Sum Up

The aim of this project is to design a clever algorithm which rules the consumption of the room 4A020 (computer, light) based on a PV production.

When the PV production exceeds the consumption of the room, we plug all the computers to use it as an energy storage.
The light must depend on the presence of people, thanks to movement sensors.
The warmth of the room must be controlled.

In the future, weather forecast and load consumption datas would enable to plan the management system.

Context

To meet our goal, we had to create a communication between the main actors of our project. We followed this scheme :

The Raspberry 1 is the brain of the system and is installed on one of the computer.
The Raspberry 2 is the physical Raspberry and Jeedom is its comunication interface.
The automation server permits to collect information such as PV production but also it permits to set up the room light from the Raspberry 1 thanks to Web Service SOAP.

We implementated :
-A general management algorithm, located in the virtual Rapsberry 1,
-A web service REST to get the state of charge of the batteries. This Web Service is runned on every computer we want to include in our algorithm,
-A dictionnary with all the commands HTTP GET associated to the two computers.

We also connect the most smart components we could on Jeedom

TOOL BOX

Accessories

In this project, we used one type sensor, called “Wall Plug” to know the status of the computers because of many problems on the Z-wave network to connect detectors to Jeedom
This smart component returns the status of the computer (on/off) and the power consumption.

Wall Plug


It is a sophisticated and intelligent remote-controlled electrical appliance switch with a measurement of the energy consumed. This functional device in the form of an adapter connected directly to any socket outlet will prove useful wherever you want to remotely control electrical appliances comfortably and without permanent presence.

It works thanks to a Z-wave network (radio frequency)

Raspberry Pi


The Raspberry Pi is the communication nod between the controller and the smart components through Web Services installed on every system which belong to the project. It has a communication interface called Jeedom which is described below

Web Service

In our project, we used Web Services to have access to the automation server and the Raspberry.
SOAP Web Services enable to have access to the automation server and so datas about weather, PV production, lights, and movement sensors.
REST Web Services enable to have access to the Raspberry and the status of the computers.

During our project, we used Web Services REST, and we were just acquainted with SOAP Web Services.

Here we define what are Web Services SOAP and REST :

http://rest.elkstein.org/

Web Services are an architectural style using simple HTTP to make calls between machines.


• Client-Server model: user interface concerns & data storage concerns are separated.

• Stateless protocol: any request from a client contains all the information necessary to service the request HTTP

• Web cache: clients and intermediaries can cache responses.

URI (Uniform Resource Identifier) = string of characters used to identify a resource.

URL (Uniform Resource Locator) is the most common form of URI. It’s a way to access an indicated resource which locates datas on the computer network and retrieves it.

Web Service REST

A Web Service REST is runned on every computer whose characteristics are wanted.
Through the Raspberry, the controller can ask to the Web Service to get a data. The Web Service receive the command and implement it in local. It returns the local result to the controller.

http://meteo-greener.g2elab.grenoble-inp.fr/?command=DataQuery&uri=dl:_01_Hour.Ray_Global_RSR2_Avg&mode=most-recent&p1=24&format=json

Example of HTTP Get used in Web Service REST

With a Web Service, HTTP GET are used to communicate. Here is an example of a HTTP GET and its description :

Format of a WS REST answer

Web Services returns can have different display formats available :

• Request & its library

http://docs.python-requests.org/en/master/#

• Command to parse a file in JSON: json.loads()

import requests\\
import json\\
r=requests.get('http://meteo-greener.g2elab.grenoble-inp.fr/?command=DataQuery&uri=dl:_01_Hour.Ray_Global_RSR2_Avg&mode=most-recent&p1=24&format=json')\\
print(r.text)\\
j=json.loads(r.text)\\
print(j)
{'head': {'fields': [{'units': 'W/m^2', 'process': 'Avg', 'type': […]

Created an object oriented String readable by python.

http://stackoverflow.com/questions/7771011/parse-json-in-python

Example of request use

import requests\\
r=requests.get('http://meteo-greener.g2elab.grenoble-inp.fr/?command=DataQuery&uri=dl:_01_Hour.Ray_Global_RSR2_Avg&mode=most-recent&p1=24&format=json')\\
print(r.text)

Web Service SOAP

SOAP protocol allows the transmission of messages between remote objects, which means that it allows an object to invoke object methods physically located on another server.

http://docs.python-zeep.org/en/master/

http://www.service-architecture.com/articles/web-services/soap.html

Initialization with WSDL language

The WSDL or Web Services Description Language is an XML grammar to describe a web service.

The WSDL is used to describe:

- The communication protocol (SOAP RPC or SOAP-oriented message)
- The message format required to communicate with this service
- Methods that the client can rely on
- The location of the service.

http://www.webservicex.net/ConvertSpeed.asmx?WSDL

Format of the answer : XML language

It’s a markup language, with distinct rules for encoding documents in a format that is both human-readable and machine-readable.

Example extracted from the Web Service SOAP which enables to get the PV production:

def GetValuesRequest( id ):
 'créer le xml de requête'
 request = \
 '<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:ns="http://www.schneider-electric.com/common/dataexchange/2011/05"> \
    <soap:Header/> \
    <soap:Body> \
       <ns:GetValuesRequest version="1.2"> \
          <ns:GetValuesIds> \
             <!--1 or more repetitions:--> \
             <ns:Id>'+id+'</ns:Id> \
          </ns:GetValuesIds> \
       </ns:GetValuesRequest> \
    </soap:Body> \
 </soap:Envelope>'
 request=request.encode('utf8') #pour faire passer les caractères spéciaux comme : '°'
 return request\\
 
 
 id is the variable.

Parse a XML document

To parse a XML document, we use the lxml library.

URL which describes where is located the web service: https://dem40.gtb.g2elab.grenoble-inp.fr/EcoStruxure/DataExchange?wsdl

Example of HTTP Post used in Web Service SOAP

POST is a request method supported by the HTTP protocol used by the World Wide Web. By design, the POST request method requests that a web server accept and store the data enclosed in the body of the request message. It is often used when uploading a file or when submitting a completed web form.

It creates a new entry in the collection. The new entry’s Uri is assigned automatically and is usually returned by the operation.

Communication protocol

We have used in our programmation different protocols : wired and radio frequency communication

Modbus

It is a non priority protocol designed for PLC with different options : RTU or TCP

→ We chose TCP (Transmission Control Protocol) to get information of the PV production.
It is based on a client-server mode. However, clients are always active and server only has a passive behaviour.

This is the ISO model of Modbus CTP :

Our automation server communicates with the PV production thanks to this type of communication

Dali (Digital Addressable Lighting Interface)

It a open protocol which permits an individual control of maximum 64 eletronic ballasts.
This communication is made of 2 wires with different polarities (speed of 1200 bit/s).
You can control precisely the intensity of light and known the facility state thanks to individual lamp status reports.

This a the type of communication we chose to create a link between the light of our room and the automation server.

Z-wave

It is a communication protocol based on radio frequency. Is is commonly used to control home automation.
It is base on low power in the frequency band of 868 MHz. This procol is done for exchanges of low bandwidth (about 20, 30 kbit/s) contrary to Wi-Fi which is done for high-speed internet services.

For example, we use this communication between our wall plugs and the raspberry

Jeedom

Jeedom is a middleware and represents the communication interface between controller and smart components such as wall plugs. It uses a Z wave to request and to collect information. Then, thanks to a web service REST, it sends theses informations to the controller.

To open JEEDOM, enter the IP address : 195.220.23.176.

Here is a screen of our room network composed of 12 wall plugs and 1 multi sensor :

Many information are available for each device :

And with the URL of each command, controller is able to send requests and can lead concret action on wall plugs :

Many options can be defined on Jeedom such as the color of light according to the consumption or the delay between each measure of consumption.

We defined our network called « Salle 4A020 » in the previous JEEDOM server .
Then, we inserted manually different captors such as multisensors (persons, light …) and wall plugs which indicate instantaneous consumption.
During this step of our project, we faced several issues like crash down of the Z-wave or detection matters from the Rasberry. So, in order to avoid losing more time on this problem, we decided to take into account 2 wall plugs for computers 4 and 5, their state of charge and the production of PV panels.

ROOM MANAGEMENT

In order to get the state of charge of each computer, we created a web service called WSSystemPowerStatus which, once downloaded, finds the percentage of charge of the computer and gives this information to the controller when it sends a request. The state of charge of each computer is available thanks to the command http://localhost:1095/getBattery. During this step, we faced an obstacle: the state of charge was available in local but the firewall seemed to block the request when the controller asked for it. So finally, we are not able to manage more than one computer.

In order to command the disconnection, reconnection or to catch up the consumption of the computers, we created a dictionary called Dictionnaire_des_commandes.txt which groups the URL of each command for each computer.

AIM OF THE ALGORITHM WE MADE
We decided to create first a simple management algorithm, whose priority is to store the energy produced by PV pannels and to consume no more than the energy dispatachable without taking into account other problematics.
The algorithm will run automatically and repeatedly, every period of time chosen.

Description of the Algorithm

  • Reconnect each of the computers in utilization. DELAY 5s

The delay is because the command to turn on the computer is not instantaneous and we must wait before the power consummed by the computers stabilizes.

  • Sum the power consumptions. Pconso
  • Get the state of charge of all the batteries,and sort them to prioritize the need in energy.
  • Sum the PV power produced and dispatchable. Pprod
  • WHILE Pconso>Pprod
  • → Disconnect the computers from the higher percentage of battery to the lowest. DELAY 5s

We delay because we wait for the disconnection of the computer and the stabilization of the power consumption.

  • → Sum the new total power consumption.
  • When Pconso⇐Pprod, we stop disconnecting the computers with the lowest state of charge of the battery.
  • DELAY 10 MINUTES if we decide that the algorithm must restart every 10 minutes.

All the algorithm belongs to a while loop which stop when we stop the general management of the system.

Appropriate Handlings to launch the algorithm

To run the algorithm in the Pycharm development environment, some settings must be done :

• To access the request library in Picharm:

Click : File → Settings → Project Interpreter → 3.5 version

• If the 3.5 version is not yet install : note that you have to follow these instructions:

File → Settings → Project Interpreter → 3.5 version → click “+” → Click Zeep → Click “Install to users…”
→ Wait for message “Package successfully installed”

• Launch the Web Service Rest wich enable to get the life percentage of the Battery on every computer of the system.

• Plug the wall plugs and check that JEEDOM recognizes them.

Override of some obstacles

Because of an firewall setting from the computer service of the school, it is impossible to run a Web Service REST on another computer from the controller.
So it was impossible to get the percentage of charge of the battery of another computer.
So in the current algorithm, some parts are to be changed the day we can request this data :

       #for key in dictionnaire_de_commandes.keys():
      #print(key)
  key='ordinateur05'
  liste=dictionnaire_de_commandes[key]
  element=liste['Charge']
  print(element)
  r=requests.get(element)
  reponse=json.loads(r.text)
  print(reponse)
  charge=reponse["BatteryLifePercent"]
  print(charge)
  vecteur[res]=charge #vecteur contenant les % de charge des batteries
  #On cree artificiellement un pourcentage de charge pour l'ordi n°4, car on ne peut pas l'obtenir avec un getBattery
  vecteur[1]=30;
  print("The load vector is",vecteur)
  

This part of the algorithm requests the Battery Pourcentage of charge.
Here we added artifically the % life battery of the external computer. But when it will be possible to access this data for an external computer, the artificial setting must be remove, and the entire procedure must be transformed into a for loop.

  while puissance_consomme>puissance_fournie_PV:
      print('Demand exceeds Production')
      res=0
      for key in dictionnaire_de_commandes.keys():
          if key!="ordinateur04": #test must be remove when it is possible to request the life percentage battery of an external computer.
          

Samely, in this part, we made sure that the diconnection doesn't happen for an external computer, because the disconnection test check the life percentage of the battery. So the programm would stop here because of the same problem. When it is possible to access the data, the procedure must be changed to be able to disconnect any of the computers.

import numpy as np

  vecteur = np.array([1,2], float)
  res=0
  

The vector created has a size 2 because we restricted the management to 2 computers. When JEEDOM easily connect to all wall plugs, it will be possible to increase the size of the vector and so request the life percentage battery of more computers.

Optimization and Prospects

Variation of Power Consumption

The power consumed by a computer depends on the state of charge of the battery.
We didn't take into account in our managemen algorithm, the fact that the power consumed must be different immediately after the reconnection of the computer.
This fact deserve to be desribed by computing the power consumption returned by Jeedom right after the reconnection of the computer.
The duration of this effect must then be taken into account in the delay before the total consumption of the room is calculated.
If the delay is too long, maybe another management system must be considered, which doesn't reconnect all the computer at the beginning of the periodic management.

Range of efficient charging mode

We measured the charging curve of a computer during an average utilization.

The results show that beyond 80%, the charging processus is slower.
So it could be taken into account that the charging mode is the more efficient before reaching 80%.
It could be implemented into the management strategy when the energy production is low : it is less interesting to charge a computer which reach 80% of Battery capacity. Morover, it can be dangerous for the computer to connect and reconnect many time the battery because it is going to use it. We didn't take into account this reflexion but with this charging curve, we see that after 80 % there is no necessity to charge the computer.
Of course, it is necessary to draw a charging curve when the computer is off and when the computer run fast.
By conducting those studies, it would be then possible to characterize precisely the behaviour of the computers in any range of utilization, during the charging process.

Toward a consumption forecast of the room

To design a smarter management system, it would be interesting to draw also a discharging curve of a computer with different range of utilization.

Then it would enable to forecast the consumption of the room, depending on the number of users in the room. The total precise forecast would then be designed depending on the number of person detected in the room with the movement detection which is supposed to join with time the managemetn project.

Input to be added to the management project

The management system would be complete when :

  • the PV production would be requested through a WS SOAP
  • the same for the weather forecast to enable to predict the PV production
  • the light status would be requested and controlled through a WS SOAP
  • the same for the warmth.

Conclusion

As a conclusion, we made an algorithm in Python which takes into account the production of PV panels and adjusts the consumption in function of this data.
However, we couldn't reach all of our expectations because of the network matter : it is not possible to catch up the state of charge of a computer if you are not in local, because of the firewall. So the listing of our consumption devices can't be done and consequently, our algorithm stops.
Without communication between our components, the management becomes quite impossible. That is why we didn't succeed in testing our algotihm whereas we have made it.

Contacts

This project was conducted by Mr Cédric Creusot and Ms Cécile Dondé under the direction of Mr DELINCHANT - benoit.delinchant@G2ELab.grenoble-inp.fr

Annexes : our codes

Web Service Battery : to catch up the state of charge of computers

  #Web service d'information d'etat de charge du pc portable.
        
  # pour la gestion de l'energie d'un PC sous Windows :  
  # http://msdn.microsoft.com/en-us/library/bb968807(v=VS.85).aspx
  # https://msdn.microsoft.com/en-us/library/windows/desktop/aa373232(v=vs.85).aspx
  # necessiste la DLL kernel32.dll
  # chargement des DLL : http://docs.python.org/library/ctypes.html
        
  import ctypes
  import ctypes.wintypes
  from flask import Flask, request
      
  #declaration de la structure definissant le STATUS (http://msdn.microsoft.com/en-us/library/aa373232(v=VS.85).aspx)
  class SYSTEM_POWER_STATUS(ctypes.Structure):
   _fields_ = [
   ("ACLineStatus", ctypes.c_byte)
   , ("BatteryFlag", ctypes.c_byte)
   , ("BatteryLifePercent", ctypes.c_byte)
   , ("Reserved1", ctypes.c_byte)
   , ("BatteryLifeTime", ctypes.wintypes.DWORD)
   , ("BatteryFullLiveTime", ctypes.wintypes.DWORD)
   ]
                       
 app = Flask(__name__)
     
 @app.route('/getBattery', methods=['GET'])
 def getBattery():
     #declaration d'un instance de type SYSTEM_POWER_STATUS
     sps = SYSTEM_POWER_STATUS()
     #appel de la fonction GetSystemPowerStatus (http://msdn.microsoft.com/en-us/library/aa372693(v=VS.85).aspx)
     #en passant en reference l'instance dont les valeurs vont etre remplie
     ctypes.windll.kernel32.GetSystemPowerStatus(ctypes.byref(sps))
         
     #declaration de la signification de la donnee : SYSTEM_POWER_STATUS.BatteryFlag
     status_constants = {0: "Not being charged - Between 33% and 66%", \
                      1: "High - More than 66%", \
                      2: "Low - Less than 33%", \
                      4: "Critical - Less than 5%", \
                      8: "Charging", \
                      128:"No system battery", \
                      255:"Unknown"}
     #declaration de la signification de la donnee : SYSTEM_POWER_STATUS.ACLineStatus
     ac_constants = {0: "Battery", 1: "AC Power", 255: "Unknown"}
     #calcul de la division entiere de BatteryLifeTime (en seconde) par 3600 pour avoir le nombre d'heures
     hours, rest = divmod(sps.BatteryLifeTime , 3600)
     #idem pour les minutes, le reste est en secondes.
     minutes, seconds = divmod(rest, 60)
          
     print("Battery charge status:", status_constants[sps.BatteryFlag & 7]) #masque des 3 premiers bits
     if (sps.BatteryFlag & 8):
         print("Battery is charging")
     print("Energy source:", ac_constants[sps.ACLineStatus])
     print("Battery life percentage: {0}%".format(sps.BatteryLifePercent))
     print("Microsoft estimation for remaining time: {0}h {1}m {2}s".format(hours, minutes, seconds))
           
     return '{"BatteryFlag": '+str(sps.BatteryFlag)+', "ACLineStatus": '+str(sps.ACLineStatus)+'}'
           
 if __name__ == '__main__':
     print('type on any web browser : http://localhost:8080/getBattery')
     print('The answer is two number, corresponding to :')
     print('Battery Flag:')
     print('    0: Not being charged - Between 33% and 66%')
     print('    1: High - More than 66%')
     print('    2: Low - Less than 33%')
     print('    4: Critical - Less than 5%')
     print('    8: Charging')
     print('    128:No system battery')
     print('    255:Unknown')
     print('ACLineStatus:')
     print('    0: Battery')
     print('    1: AC Power')
     print('    255: Unknown')
     app.run(host="0.0.0.0",port=1095,debug=False)>
     

Algorithm of room management

#bibliothèques importées
import requests
import json
import time

t=1
while t<8:
  print("Nouvelle session de management", t)
  # Ouvre le dossier txt qui contient l'ensemble des URL donnant la puissance consommée par la prise de chaque ordinateur en format json.
  with open("Dictionnaire_de_commandes.txt","r") as dictionnaire_de_commandes_json:#il est ouvert en mode read
      texte = dictionnaire_de_commandes_json.read()
      
           
  #Parse le fichier
  dictionnaire_de_commandes=json.loads(texte)
  print(dictionnaire_de_commandes)
  
  #FONCTION
  
  #PPV est la production photovoltaique donnée par le Web Service Soap
  
  # ADD départ de la procédure tous les 5 minutes
  #On créé artificiellement un vecteur contenant la production photovoltaique afin de choisir plus facilement différent cas d'études pour tester l'algorithme.
  dictionnaire_puissance_photovoltaique = {'PV 1': 10, 'PV 2': 50}
  
  
  #D'abord, on reconnecte les ordinateurs, poru principalement évaluer la pusisance consommée par chaque ordi.
  for key in dictionnaire_de_commandes.keys():
      liste=dictionnaire_de_commandes[key]
      element_ON=liste['ON']
      requests.get(element_ON)
      time.sleep(5)
      print(key, "has been reconnected")
      
  #Fonction puissance qui permet d'obtenir la puissance consommée par chaque ordi.
  #Cette fonction renvoie aussi le statut de chaque ordi.
  def puissance(dictionnaire):
      puissance_consomme=0
      for key in dictionnaire.keys():
          liste=dictionnaire[key]
          element=liste['Power'] #URL associé à la clef et permettant de trouver la puissance
          r=requests.get(element)
          puissance = float(r.text) #Renvoie la puissance associée à la clef
          print(puissance)
          print("Computer", key ,"uses", puissance, "watt")
          if puissance > 1:
              print(key, "used")
          puissance_consomme=puissance_consomme+puissance
      return puissance_consomme
      pass
      
  #Définition de la fonction SOMME
  def somme(dictionnaire):
      res=0
      for i in dictionnaire.values() :
          res=res+i
      return res
      pass
      
  puissance_fournie_PV=somme(dictionnaire_puissance_photovoltaique)
  puissance_consomme=puissance(dictionnaire_de_commandes)
  print("The total dispatchable power is",puissance_fournie_PV)
  print("The total used power is",puissance_consomme)
  
  
  import numpy as np
  vecteur = np.array([1,2], float)
  res=0
  
  #Dans le programme suivant, on accède au pourcentage de charge de chaque ordi via le Web Service WSSystemPowerStatus qui doit être lancé.
  #Il devrait y avoir une boucle permettant de lancer un Get Battery pour chacun des ordis, mais comme des pare-feu nous empêchent d'envoyer
  nos commandes via un port sur un autre ordis,
  #et donc de faire tourner le web service d'un ordi externe, on ne peut pas le faire.
  #En attendant, on utilise la commande GetBattery sur mon ordi, et on choisit artificiellement une valeur pour le deuxième ordi test.
  #J'ai choisi un petit pourcentage pour le deuxième ordi pour qu'il en soit pas déconnecté en priorité.
  
  #for key in dictionnaire_de_commandes.keys():
      #print(key)
  key='ordinateur05'
  liste=dictionnaire_de_commandes[key]
  element=liste['Charge']
  print(element)
  r=requests.get(element)
  reponse=json.loads(r.text)
  print(reponse)
  charge=reponse["BatteryLifePercent"]
  print(charge)
  vecteur[res]=charge #vecteur contenant les % de charge des batteries
  #On cree artificiellement un pourcentage de charge pour l'ordi n°4, car on ne peut pas l'obtenir avec un getBattery
  vecteur[1]=30;
  print("The load vector is",vecteur)
  
  #On classe les % de charge de batterie de chaque ordinateur pour prioriser la connexion et la déconnexion
  pourcentage_de_charge_decroissant = sorted(vecteur, reverse=True)
  print("The sorted load vector is",pourcentage_de_charge_decroissant)
  
  #Déconnexion des ordis en fonction de la production photovoltaïque
  while puissance_consomme>puissance_fournie_PV:
      print('Demand exceeds Production')
      res=0
      for key in dictionnaire_de_commandes.keys():
          if key!="ordinateur04":
              liste=dictionnaire_de_commandes[key]
              element_charge=liste['Charge']
              element_OFF=liste['OFF']
              r=requests.get(element_charge)
              reponse=json.loads(r.text)
              charge_entier=reponse["BatteryLifePercent"]
              charge=float(charge_entier)
              print(pourcentage_de_charge_decroissant[res])
              #Attention, ici, comme on avait créé artificiellement un %de charge pour l'ordinateur 4, la boucle de test ne va pas 
              fonctionner car on ne peut pas redemander le %de charge de l'ordi 4 via un get Battery.
              #Le programme s'arrête ici tant qu'on ne peut pas utiliser Get Battery sur un ordi externe.
              if pourcentage_de_charge_decroissant[res]== charge:
                  print('found')
                  requests.get(element_OFF) #déconnecte l'ordinateur
                  time.sleep(3) # wait for 3 seconds
                  print(key, "has been disconnected")
      res=res+1
      #Recalcule la somme des puissances après deconnexion
      puissance_consomme=puissance(dictionnaire_de_commandes)
      print("La puissance consomme vaut:",puissance_consomme)
      
  print('We keep on the computers to store the energy produced by the PV pannels')
  print("Management is done")
  print("The new used power is", puissance_consomme)
  print("When the dispatchable power is",puissance_fournie_PV)
  #On relance le programme toutes les 10 secondes
  time.sleep(10)
  t=t+1
     

QR Code
QR Code accueil:espaces:etudiants:etudiants:formation_initiale:module_ict_for_smart_grid:office_building_management_system (generated for current page)