Une fois que l'on a commencé à jouer avec un arduino, un ESP8266, un raspberry, des capteurs cela donne envie de continuer un peu plus loin au pays de la domotique. C'est à ce petit voyage que je vous convie en suivant mes premiers pas avec OpenHAB, MQTT, ESP8266, mosquitto ... and Caux !

1.  MQTT


publieurs et souscripteurs source

MQTT (MQ Telemetry Transport) permet la communication entre et avec des « objets connectés ». C'est un protocole pour les réseaux sans fil et à faible bande passante. Il repose sur un fonctionnement de type publication/abonnement hautement évolutif qui garantit la distribution. Il y a donc des publieurs (les publishers) qui envoient des données sur un canal (une chaîne d’information) appelé Topic. Ces données peuvent être lus par les souscripteurs (les subscribers) qui surveillent certains Topics. Un serveur (Broker) se charge de faire la liaison entre les publieurs et les souscripteurs. Les messages envoyés par les objets communications peuvent être de toute sortes mais ne peuvent excéder une taille de 256 Mo.

Le protocole a les propriétés suivantes :

  • la distribution de type "un à plusieurs" des messages ;
  • la fonction de publication/abonnement découple les applications ;
  • il ne dépend aucunement du contenu des messages ;
  • il fonctionne sur TCP/IP.
  • Il propose trois qualités de service pour la distribution des messages :
    1. "Au plus une fois"
    2. "Au moins une fois", les messages arrivent de façon certaine, mais ils peuvent arriver en double.
    3. "Une seule fois"
  • Il dispose de la fonction "Dernières volontés et testament" qui notifie les abonnés de la déconnexion anormale d'un client du serveur MQTT.

1.1  Mosquitto

Il existe plusieurs courtiers de message MQTT (broker), mais Mosquitto est un projet opensource que l'on peut installer sur un raspberry pi et utiliser avec un ESP, c'est donc celui-ci qui a notre préférence et que nous allons présenter et installer. La configuration par défaut de Mosquitto n'utilise pas d'authentification et accepte toutes les connexions sur le port 1883. Elle possède deux clients mosquitto_pub et mosquitto_sub. Le client mosquitto_pub est utilisé pour poster de publier des message. Le mosquitto_sub est utilisé pour s'abonner à un sujet et afficher les messages reçus.

Commençons par installer le courtier, les clients et l'api python (cette dernière n'est pas nécessaire ici). Attention il faut récupérer une version de mosquitto à jour sous peine de problème !

 % sudo bash -c 'echo "deb http://ppa.launchpad.net/mosquitto-dev/mosquitto-ppa/ubuntu trusty main" > /etc/apt/sources.list.d/mosquitto-dev-mosquitto-ppa-trusty.list'
 % sudo apt-get update
 % sudo apt-get install mosquitto mosquitto-clients python-mosquitto

Le service est normalement actif. Vous pouvez le vérifier :

 % ps aux | grep mosquitto
 mosquit+ 31101  0.0  0.0  14920  2084 ?        Ss   09:55   0:00 /usr/sbin/mosquitto -c /etc/mosquitto/mosquitto.conf
 damien   31118  0.0  0.0  15984  2224 pts/0    S+   09:58   0:00 grep --color=auto mosquitto

Si ce n'est pas le cas

 % sudo service mosquitto start
 mosquitto start/running, process 31142

La commande netstat vous confirmera que le démon écoute sur le port.

 % netstat -an | grep 1883
 tcp        0      0 0.0.0.0:1883            0.0.0.0:*               LISTEN     
 tcp        0      0 127.0.0.1:33805         127.0.0.1:1883          ESTABLISHED
 tcp        0      0 127.0.0.1:1883          127.0.0.1:33805         ESTABLISHED
 tcp6       0      0 :::1883                 :::*                    LISTEN     
 unix  2      [ ]         STREAM     CONNECTE      18830    @/tmp/dbus-RjxvT91U
 unix  3      [ ]         STREAM     CONNECTE      18831    /var/run/dbus/system_bus_socket

et si vous voulez l’arrêter

  % sudo service mosquitto stop
 mosquitto stop/waiting

Passons au test maintenant. Le plus simple est d'utiliser deux consoles. Dans la première :

 % mosquitto_sub -h localhost -t "DHT22/#" -v &

Vous vous abonnez au canal DHT22. Dans la seconde

 % mosquitto_pub -h localhost -t DHT22/temperature -m 17
 % mosquitto_pub -h localhost -t DHT22/temperature -m 17.2
 % mosquitto_pub -h localhost -t DHT22/hygrometrie -m 49.8
 % mosquitto_pub -h localhost -t DHT11/hygrometrie -m Rien

Dans la première console, on obtient :

 DHT22/temperature 17
 DHT22/temperature 17.2
 DHT22/hygrometrie 49.8

Vous pourrez remarquer que nous n'avons pas le message concernant le capteur DHT11 car nous n'y sommes pas abonné. En guise de test plutôt qu'utiliser localhost vous pouvez essayer test.mosquito.org.

1.2  MQTT pour arduino et ESP8266

PubSubClient est un client arduino et ESP MQTT. Il suffit d'installer la bibliothèque dans l'IDE arduino.

1.3  Programmation

Pour commencer en nous inspirant du programme exemple mqtt_esp8266.ino fourni avec la bibliothèque PubSub, nous allons écrire un petit exemple qui utilise l'ESP-1 et se connecte sur un broker local lancé sur une machine linux du réseau local. Le traitement consiste à se connecter au Wi-fi (ligne 54 à 74) puis au broker (ligne 100 à 116), ensuite il faut s'abonner à un fil de message serreIN (ligne 108) et on publie sur un autre fil serreOUT (lignes 98 et 107). Le fil serreIN sert à fixer le temps d’endormissement du Wi-Fi pour économiser de l'énergie. Avec un peu de soudure ou un ESP-12 par exemple on peu faire mieux, avec un sommeil plus profond ! Le code est agrémenté de nombreuses traces afin de pouvoir suivre dans la console, pour les supprimer il suffit de commenter #debug (ligne 16). Pour plus d'informations sur le montage de l'ESP, je vous conseille de vous reporter ce que j'ai expliqué ici.

  1. /*
  2.  Exemple de base ESP8266 MQTT
  3.  avec une publication de la part de l'ESP qui se connecte sur un broker MQQT (local) :
  4.  - Publie sur le fil "serreOUT" toutes les dodo minutes "[adresse Mac] Bonjour #" + numero_message
  5.  - S'abonne au fil "serreIN" lorsqu'une info est reçue cela fixe la durée d'endormissement du wifi
  6.    pour économiser l'énergie
  7.  source mqtt_esp8266.ino
  8. */
  9.  
  10. #include <ESP8266WiFi.h>
  11. #include <PubSubClient.h>
  12. extern "C" {
  13.   #include <user_interface.h>
  14. }
  15.  
  16. #define DEBUG
  17. #ifdef DEBUG
  18.  #define DEBUG_BEGIN(x)        Serial.begin(x)
  19.  #define DEBUG_PRINT(x)        Serial.print (x)
  20.  #define DEBUG_PRINTLN(x)      Serial.println (x)
  21. #else
  22.  #define DEBUG_PRINT(x)
  23.  #define DEBUG_PRINTLN(x)
  24. #endif
  25.  
  26. // Pour identifier l'ESP
  27. uint8_t MAC_array[6];
  28. char MAC_char[18];
  29.  
  30.  
  31. // Mettre à jour suivant votre réseau
  32. const char* SSID = "VotreSSID";
  33. const char* PASSWORD = "VotreMotDePasse";
  34. byte mqtt_serveur[] = {192, 168, 0, 12}; // IP du broker à modifier
  35.  
  36. WiFiClient espClient;
  37. PubSubClient client(espClient);
  38. char message[50];
  39. int numero_message = 0;
  40. int dodo = 0; // Par défaut
  41.  
  42. void setup() {
  43.   DEBUG_BEGIN(115200);
  44.   DEBUG_PRINTLN();
  45.   WiFi.macAddress(MAC_array);
  46.   for (int i = 0; i < sizeof(MAC_array); ++i){
  47.       sprintf(MAC_char,"%s%02x:",MAC_char,MAC_array[i]);
  48.   }
  49.   setup_wifi();
  50.   client.setServer(mqtt_serveur, 1883);
  51.   client.setCallback(callback);
  52. }
  53.  
  54. void setup_wifi() {
  55.   delay(10);
  56.   // Connexion au Wi-fi
  57.   DEBUG_PRINTLN();
  58.   DEBUG_PRINTLN();
  59.   DEBUG_PRINT("Connexion à : ");
  60.   DEBUG_PRINTLN(SSID);
  61.   WiFi.begin(SSID, PASSWORD);
  62.   DEBUG_PRINT("\n\r \n\rC'est en cours");
  63.  
  64.   while (WiFi.status() != WL_CONNECTED) {
  65.     delay(500);
  66.     DEBUG_PRINT(".");
  67.   }
  68.  
  69.   DEBUG_PRINTLN("");
  70.   DEBUG_PRINT("ESP connecté au Wi-fi ");
  71.   DEBUG_PRINTLN(SSID);  
  72.   DEBUG_PRINT("Adresse IP : ");
  73.   DEBUG_PRINTLN(WiFi.localIP());
  74. }
  75.  
  76. void callback(char* fil, byte* payload, unsigned int longueur) {
  77.   DEBUG_PRINT("Message arrivé [");
  78.   DEBUG_PRINT(fil);
  79.   DEBUG_PRINT("] ");
  80.   dodo = 0;
  81.   int puissance = 1;
  82.   for (int i = longueur - 1; i >= 0; i--) {
  83.     DEBUG_PRINT((char)payload[longueur - 1 - i]);
  84.     dodo = dodo + ((int)payload[i]-48) * puissance;
  85.     puissance = puissance * 10;    
  86.   }
  87.   DEBUG_PRINTLN();
  88.   DEBUG_PRINT("dodo = ");
  89.   DEBUG_PRINTLN(dodo);
  90. }
  91.  
  92. void publication()
  93. {
  94.     ++numero_message;
  95.     snprintf(message, 75, "[%s] Bonjour #%ld", MAC_char, numero_message);
  96.     DEBUG_PRINT("Message publié: ");
  97.     DEBUG_PRINTLN(message);
  98.     client.publish("serreOUT", message);
  99. }
  100. void reconnect() {
  101.   // On tente de se (re)connecter
  102.   while (!client.connected()) {
  103.     DEBUG_PRINTLN("Tentative de connexion MQTT...");
  104.     if (client.connect(MAC_char)) {
  105.       DEBUG_PRINTLN("connecté");
  106.       // Une fois connecté on le fait savoir
  107.       client.publish("serreOUT", "Connecté au MQTT");
  108.       client.subscribe("serreIN",1);
  109.     } else {
  110.       DEBUG_PRINT("echec, rc=");
  111.       DEBUG_PRINTLN(client.state());
  112.       DEBUG_PRINT(" nouvel essai dans 5 secondes");
  113.       delay(5000);
  114.     }
  115.   }
  116. }
  117. void loop() {
  118.   if (!client.connected()) {
  119.     reconnect();
  120.   }
  121.   delay(2000);
  122.   client.loop();
  123.   publication();
  124.   if (dodo >= 1)
  125.     {
  126.       DEBUG_PRINT("on couche le wifi "); DEBUG_PRINTLN(1000*60*dodo - 2000);
  127.       wifi_set_sleep_type(LIGHT_SLEEP_T);
  128.       delay(1000*60*dodo - 2000);
  129.     }
  130. }

Il faut maintenant se pencher sur mosquitto. On utilise la configuration par défaut sans authentification et certificat pour le moment afin de ne pas multiplier les sources d'erreurs. On ajoute néanmoins le mécanisme de persistance afin de pouvoir avoir des capteurs qui s'endorment. J'ai ajouté un fichier mosquitto.conf dans le repertoire /etc/mosquitto/conf.d avec les paramètres nécessaires, enfin si j'ai bien compris ! Vous pouvez vous en inspirer. Pour une utilisation plus stable, il faut modifier le répertoire de la base par exemple. Je me suis battu également avec la lecture du fichier de configuration aussi je vous conseille d’arrêter le courtier s'il tourne.

 % sudo /etc/init.d/mosquitto stop

et lancer le "votre".

 % mosquitto -c /etc/mosquitto/conf.d/mosquitto.conf -d -v

Il ne vous reste plus qu'à vous abonner et publier.

L'abonnement et c'est gratuit :

 % mosquitto_sub -h armille -t serreOUT -v

et pour publier

 % mosquitto_pub -h localhost -t serreIN -m 10 -r

TODO ! Trace d'exécution

2.  OpenHAB

OpenHab est un logiciel opensource en Java de domotique interopérable basé sur un bus d’événement. Lorsque l'un de ces derniers se produit un scénario est alors exécuté.

OpenHAB met à disposition :

  • Un moteur d’événements, il faut une machine virtuelle Java ;
  • Un portail Web mobile configurable ;
  • Une API REST.
  • Des plugins pour "tout" matériel (module z-wave, bluetooth ...) ou service sur Internet (Twitter, Dropbox ...) leur permettant de communiquer avec le bus d’événement ;
  • Un éditeur de règles permettant de définir des déclenchements d'action ;
  • Des applications mobiles iOS et Android pour visualiser et déclencher des événements à distance.

2.1  Installation sous ubuntu 14.04

Ajouter tout d'abord la clef et le dépôt :

 sudo apt-get update

 % wget -qO - 'https://bintray.com /user/downloadSubjectPublicKey?username=openhab' | sudo apt-key add -
 % echo "deb http://dl.bintray.com/openhab/apt-repo stable main" | sudo tee /etc/apt/sources.list.d/openhab.list
 % sudo apt-get update

C'est parti, on installe openHAB et quelques addons qui pourront être nécessaires.

 % sudo apt-get install openhab-runtime openhab-addon-binding-mqtt openhab-addon-action-mail openhab-addon-binding-bluetooth openhab-addon-binding-serial openhab-addon-binding-weather openhab-addon-binding-ntp openhab-addon-persistence-rrd4j

2.2  Configuration

La première chose à faire est de localiser le fichier openhab_default.cfg. Un petit locate ou find vous aideront.

 % cd /etc/openhab/configurations
 % sudo cp openhab_default.cfg openhab.cfg

Il faut maintenant modifier avec votre éditeur favori openhab.cfg en ajoutant au niveau de MQTT Transport mqtt:mosquitto.url=tcp://localhost:1883 ou si vous préférez le nom de la machine/ip sur laquelle tourne votre courtier. Relancer ensuite openhab.

 % sudo /etc/init.d/openhab restart

L'étape suivante consiste à creer un fichier d'items. Dans ce dernier vous indiquez quels sont les différents capteurs que vous suivez et comment vous les organisez en groupe. Sur le site github d'openHab vous trouverez des explications plus détaillées et claires. Nous allons créer un groupe principal ElevageDeK avec un Jardin et une Serre.

 % sudo nano /etc/openhab/configurations/items/default.items



 Group ElevageDeK
 Group Jardin (ElevageDeK)

 Group 	Serre 	"Serre" 	<greenhouse> 	(Jardin)

 Number Temp 		"Température : [%.2f °C]" 	<temperature>	(Serre)	{mqtt="<[mosquitto:ElevageDeK/Jardin/Serre/1/OUT/temperature:state:default]"}
 Number Humidite         "Humidité : [%.2f ]" 		<bath> 		(Serre) {mqtt="<[mosquitto:ElevageDeK/Jardin/Serre/1/OUT/humidite:state:default]"}
  • Number : le type de la valeur ;
  • Temperature : nom de l'item ;
  • "Température [%.2f]°C" : affichage de l'information et définition de son format (flottant 2 chiffres après la virgule) ;
  • <temperature> : le nom de l’icône ;
  • (Serre) : groupe auquel l'item appartient ;
  • {mqtt="<[mosquitto:ElevageDeK/Jardin/Serre/1/OUT/humidite:state:default]"} : comment récupérer la valeur. On demande à OpenHAB d'utiliser "mosquitto" et de lire le fil ElevageDeK/Jardin/Serre/1/OUT/humidite. state défini le type et default la transformation. < indique que l'on lit le fil.

Pour l'icone greenhouse je l'ai récupérée sur le web et copiée dans /usr/share/openhab/webapps/images/ On fixe maintenant l'interface utilisateur en créant un fichier sitemap.

 % sudo nano /opt/openhab/configurations/sitemaps/default.sitemap


 sitemap default label="ElevageDesK"
 {
	Frame {
		Group item=Jardin icon="garden" 
	      }
 } 

Vous pouvez tester maintenant :

 % mosquitto_pub -h localhost -t ElevageDeK/Jardin/Serre/1/OUT/humidite -m 97

et dans votre navigateur http://localhost:8080/openhab.app

3.  Pour aller plus loin

Je vous propose de maintenant construire une application plus complète où nous n'allons pas nous contenter de simuler un capteur et son contrôle mais réellement le réaliser. Cette application peut être une base de départ pour réaliser un suivi et un contrôle de chez vous.

3.1  Éléments nécessaires

Cette liste n'est pas complète, mais donne les éléments essentiels :

  • Le broker mosquitto installé ;
  • Le serveur openhab installé ;
  • Un montage esp8266 avec un DHT22 opérationnel.

3.2  Objectif

Nous allons donc chercher à récupérer la date à partir d'un serveur ntp, la température locale extérieure grâce à openWeatherMap et la température et le pourcentage d'humidité dans la serre avec un ESP8266-1 et un capteur DHT22. On doit pouvoir également configurer la durée entre deux acquisitions de la mesure par l'ESP dans la serre avec un "endormissement" de celui-ci afin de limiter la consommation d'énergie. Cette application est largement inspirée de la démo d'openhab.

3.3  Configuration des extensions

On utilise différentes extensions, qu'il faut alors configurer.

Liaison avec un serveur ntp

Vérifiez que vous avez bien le fichier /usr/share/openhab/addons/org.openhab.binding.ntp-1.8.2.jar (remplacez 1.8.2 par votre noméro de version) sinon installez le. Il faut ensuite modifier le fichier /etc/openhab/configurations/openhab.cfg en ajoutant le serveur ntp et le rafraîchissement de l'information.

 # refresh interval in milliseconds (optional, defaults to 900000 [15 minutes])
 ntp:refresh=60000
 # the hostname of the timeserver
 ntp:hostname=ntp-p1.obspm.fr

Liaison avec le broker mosquitto

Comme pour ntp assurez vous que vous avez bien le fichier /usr/share/openhab/addons/org.openhab.binding.mqtt-1.8.2.jar (remplacez 1.8.2 par votre noméro de version) sinon installez le. Il Il faut ensuite modifier le fichier /etc/openhab/configurations/openhab.cfg en indiquant le nom de la machine et le port sur lequel le broker tourne et écoute.

 # URL to the MQTT broker, e.g. tcp://localhost:1883 or ssl://localhost:8883
 mqtt:mosquitto.url=tcp://localhost:1883

Récupération de la météo

Vous commencez à connaître l'histoire, il faut vérifier que vous avez bien le fichier /usr/share/openhab/addons/org.openhab.binding.weather-1.8.2.jar. (remplacez 1.8.2 par votre noméro de version) sinon installez le. Il Il faut ensuite modifier le fichier /etc/openhab/configurations/openhab.cfg, mais avant cela commencez par créer un compte sur OpenWeatherMap et demandez pour récupérer une clef qui vous permettra d'utiliser l'Api.

et notez votre clef.

Au niveau d'openhab.cf

 weather:apikey.OpenWeatherMap=votreClef
 weather:location.maison.latitude=votreLatitude
 weather:location.maison.longitude=votreLongitude
 weather:location.maison.provider=OpenWeatherMap
 weather:location.maison.language=en
 weather:location.maison.updateInterval=10

Si vous voulez d'autres lieux, il suffit d'ajouter d'autres identifiants (maison) qui permettront de récupérer les informations.

3.4  Configuration des fichiers xx.items

Attention à ne pas avoir des items qui ont les mêmes labels dans plusieurs fichiers cela crée des problèmes sur les charts.

Les fichiers items contiennent les définitions des variables pour échanger des informations au sein d'openhab ou avec d'autres programmes, systèmes, serveurs, courtiers .... Ils précisent également comment les afficher. Ils sont localisés dans le répertoire /etc/openhab/configurations/items. Ainsi nous allons pouvoir définir une variable Temperature_exterieure qui va permettre de stocker l'information issue d'OpenWeatherMap, nous allons également pouvoir préciser que l'affichage se fera sous la forme d'un nombre flottant avec deux décimales après la virgule [%.2f °C]. Le plus simple est de regarder l'exemple ci-dessous.

 Group ElevageDeK
 Group Jardin 					(ElevageDeK)
 Group Serre 		"Serre" 	<greenhouse> 	(Jardin)
 Group Meteo 		"Meteo" 	<sun> 		(ElevageDeK)
 Group Reglage 					(ElevageDeK)
 Group SerreReglage 	"Réglage des paramètres pour la serre" <settings> (Reglage)
 Group Serre_Courbes
 Group Initialiser

 Number 	Serre_Temp 		"Température serre [%.2f]" 	<temperature>	(Serre, Serre_Courbes)	{mqtt="<[mosquitto:ElevageDeK/Jardin/Serre/1/OUT/temperature:state:default]"}
 Number 	Serre_Humidite         "Humidité : [%.2f ]" 	<dht11_2> 	(Serre, Serre_Courbes) 	{mqtt="<[mosquitto:ElevageDeK/Jardin/Serre/1/OUT/humidite:state:default]"}


 DateTime	Date	"Date [%1$tA, %1$td.%1$tm.%1$tY,%1$tH:%1$tM ]"	<calendar>		{ ntp="Europe/Paris:fr_FR" }


 Group Meteo_Courbes								
 Number Meteo_Temperature    "Température [%.2f °C]" <temperature>      (Meteo, Meteo_Courbes) {weather="locationId=maison, type=temperature, property=current"}
 Number Meteo_Humidite       "Humidité extérieure [%.1f ]" <dht11_2> 	(Meteo, Meteo_Courbes) {weather="locationId=maison, type=atmosphere, property=humidity"}
 Number Meteo_Temp_Max       "Maximum aujourd'hui [%.1f °C]" <temperature> (Meteo) {weather="locationId=maison, type=temperature, property=max"}
 Number Meteo_Temp_Min       "Minimum aujourd'hui [%.1f °C]" <temperature> (Meteo) {weather="locationId=oudalle, type=temperature, property=min"}
 Number Meteo_Courbes_Periode "Durée"
 DateTime Meteo_LastUpdate  "Dernière maj. [%1$ta %1$tR]" (Initialiser) <clock>
 Number FrequenceAcq "Réglage fréquence [%.0f  mn]" <myslider> (SerreReglage, Initialiser)
 Number FrequenceTrans {mqtt=">[mosquitto:ElevageDeK/Jardin/Serre/1/IN/frequence:state:*:default]"}
 Switch Endormissement "Envoi consigne"

La syntaxe est la suivante (ce qui est entre crochet est facultatif) :

 itemtype itemname ["labeltext"] [<iconname>] [(group1, group2, ...)] [{bindingconfig}]

Vous fournissez le type de l'item (Number, DateTime, Switch, Dimmer, String ....) puis le nom de l'item et le texte qui sera associé et le format de représentation, puis l'icone le représentant et les groupes auxquels il appartient et pour finir l'appel éventuel à un service extérieur (ntp, mosquitto ...). Prenons un exemple Number Meteo_Temperature "Température [%.2f °C]" <temperature> (Meteo, Meteo_Courbes) {weather="locationId=maison, type=temperature, property=current"}. On déclare donc un item Meteo_Temperature de type Number qui a pour affichage "Température [%.2f °C]", [%.2f °C] indique comment la valeur de la variable sera affichée. Cette variable appartient à deux groupes d'item qui sont (Meteo, Meteo_Courbes). Les Group servent à associer des items entre-eux que ce soient des variables ou des groupes. Ils se déclarent comme des items. Pour en savoir plus je vous conseille de vous reporter à la documentation.

{weather="locationId=maison, type=temperature, property=current"} est donc la liaison à un service, ici la météo. On fournit la localisation souhaitée en lien avec le fichier openhab.cfg ainsi que le type. La documentation d'openHab détaille cela. Dans l'exemple ci-dessus vous trouverez également une liaison avec un serveur de temps ntp : { ntp="Europe/Paris:fr_FR" }.

Je vous propose de nous attarder maintenant sur deux items : Serre_Temp et FrequenceTrans. Ces deux items utilisent mosquitto que nous avons déjà présenté.

 Number Serre_Temp "Température serre [%.2f]" <temperature> (Serre, Serre_Courbes) {mqtt="<[mosquitto:ElevageDeK/Jardin/Serre/1/OUT/temperature:state:default]"}
 Number FrequenceTrans {mqtt=">[mosquitto:ElevageDeK/Jardin/Serre/1/IN/frequence:state:*:default]"}

mosquitto précise l'alias du courtier, > l'envoi de données, < la réception de données, ElevageDeK/Jardin/Serre/1/OUT/temperature indique le fil sur lequel la lecture s'effectue, ElevageDeK/Jardin/Serre/1/IN/frequence le fil sur lequel l'écriture se fait, state:default le type d'informations.

Les trois items FrequenceTrans, FrequenceAcq et Endormissemnt sont "liés". FrequenceAcq est fournie par l'utilisateur, FrequenceTrans est transmis au courtier lorsque Endormissement est basculé. Cela évite de transmettre de façon systématique les modifications de FrequenceAcq. Cela se fait par l'intermédiaire d'une règle, que je présente plus loin.

3.5  Configuration des fichiers xx.sitemap

Ces fichiers sont utilisés pour définir le contenu et la structure de l'interface utilisateur.

 sitemap default label="ElevageDeK"
 {
 	Frame label="Date" {
 		Text item=Date
 	}
 	Frame label="Météo" {
 		Text item=Meteo_Temperature valuecolor=[Meteo_LastUpdate=="NonInitialise"="lightgray",Meteo_LastUpdate>90="lightgray",>25="orange",>15="green",>5="orange",<=5="blue"] {
 			Frame {
				Text item=Meteo_Temp_Max valuecolor=[>25="orange",>15="green",>5="orange",<=5="blue"]
				Text item=Meteo_Temp_Min valuecolor=[>25="orange",>15="green",>5="orange",<=5="blue"]
				Text item=Meteo_Humidite
				Text item=Meteo_LastUpdate
				}
			Frame label="Courbes" {	
				Switch item=Meteo_Courbes_Periode label="Choix" mappings=[0="Heure", 1="Jour", 2="Semaine"]
				Chart item=Meteo_Courbes period=h label="Essai1" refresh=6000 visibility=[Meteo_Courbes_Periode==0, Meteo_Courbes_Periode=="Uninitialized"]
				Chart item=Meteo_Courbes period=D label="Essai2" refresh=30000 visibility=[Meteo_Courbes_Periode==1]
				Chart item=Meteo_Courbes period=W label="Essai3" refresh=30000 visibility=[Meteo_Courbes_Periode==2]
				} 	
		}
	}
	Frame label="Extérieur" {
		Group item=Jardin icon="garden" {
			Text item=Serre {
			     Frame {
				Text item=Serre_Temp
				Text item=Serre_Humidite
			     }
			     Chart item=Serre_Temp period=h refresh=6000
			} 
		} 
	}
	Frame label="Réglages" {
		Group item=SerreReglage {
                             Frame {
                                Setpoint item=FrequenceAcq minValue=0 maxValue=3600 step=4
       				Switch item=Endormissement
                             }
                }

	}
 }

On reconnaît (?) la structure de l'interface présentée précédemment avec par exemple le label Météo ou encore Température. Ce dernier conduit à une autre page dans laquelle on trouvera les températures maximales et minimales du jour, l'humidité ainsi que l'heure de la dernière mise à jour. En dessous figure une courbe traçant l'évolution de la température et de l'humidité.

Vous aurez noté que les courbes se trace avec Chart, il faut bien sur activer la persistance des données dans le fichier de configuration.

 # The name of the default persistence service to use
 persistence:default=db4o 

J'utilise db4o (data base for object) qui n'est pas celui par défaut d'openHab mais j'ai rencontré des problèmes avec rr4j.

 Chart item=Meteo_Courbes period=h label="Essai1" refresh=6000 visibility=[Meteo_Courbes_Periode==0, Meteo_Courbes_Periode=="Uninitialized"]

On définit un tracé de courbe (Chart) en liaison avec le group (Meteo_Courbes) défini dans le fichier d'items. La période affichée est horaire (period=h) les données sont rafraichies toutes les minutes (refresh=6000), la courbe est affichée en fonction de la valeur du sélecteur Meteo_Courbes_Periode==0 qui est affiché auparavant (Switch item=Meteo_Courbes_Periode label="Choix" mappings=[0="Heure", 1="Jour", 2="Semaine"]).

 Frame label="Réglages" {
		Group item=SerreReglage {
                             Frame {
                                Setpoint item=FrequenceAcq minValue=0 maxValue=3600 step=4
       				Switch item=Endormissement
                             }
                }

 }

Ce bloc d'affichage permet d'envoyer des consignes à l'ESP Setpoint est un slider qui permet de fixer une valeur entre 0 et 3600 secondes par pas de 4. La valeur sera réellement envoyée que lorsque le switch Endormissement aura été basculé. La valeur est transmisse grâce à l'item FrequenceTrans qui n’apparaît pas au niveau de l'interface mais dont la valeur est fixée par une règle.

3.6  Configuration de la persistance

Le fichier de configuration est /etc/openhab/configurations/persistence/db4o.persist, si vous utiliser rrd4j remplacer db4o par ce dernier. Vous devez définir les stratégies que vous souhaitez mettre en œuvre. Le format correspond à ce que l'on fait avec les tables de planification sous Unix/Linux (crontab). Trois stratégies sont préexistantes : everyChange, everyUpdate et restoreOnStartup.

 Strategies {
	everyMinute 	: "0 * * * * ?"
	everyHour 	: "0 0 * * * ?"
	everyDay	: "0 0 0 * * ?"
	default = everyChange
 }
 Items {
   	* : strategy = everyChange, restoreOnStartup
	 Meteo_Courbes* : strategy = everyMinute, restoreOnStartup
	 Temp : strategy = everyMinute, restoreOnStartup
 }

L'* est un caractère joker, et représente l'ensemble des items limités au groupe Meteo_Courbes lorsqu'elle est associée à ce dernier, où à la totalité des items pour la première utilisation.

3.7  Configuration des règles

Le langage utilisé a des faux airs de Java, c'est en fait du xtend

 import org.openhab.core.library.types.*

 rule "Initialise les items appartenant au groupe Initialiser"
 when
    System started
 then
    logInfo("Initialiser", "45s pour le démarrage ...")
    createTimer(now.plusSeconds(45)) [|
        logInfo("Initialiser", "... initialisation en cours")
        Initialiser.members.filter( x | x.state == Uninitialized).forEach[ item |
            postUpdate(item, 0)
        ]
    ]
 end

 rule "MAJ des données météo"
 when
  Item Meteo_Temperature received update 
 then
  postUpdate(Meteo_LastUpdate, new DateTimeType())
 end

 rule "Envoi Frequence"
    when
        Item Endormissement received command
    then
	if (receivedCommand==ON)
	{
        	postUpdate(Endormissement, OFF) 
		var int valeur = 0
        	if (FrequenceAcq.state instanceof DecimalType)
            	valeur = (FrequenceAcq.state as DecimalType).intValue
		postUpdate(FrequenceTrans, valeur);
	}
 end

La première règle initialise les items non encore initialisés appartenant au groupe Initialiser. La troisième règle permet de fixer la valeur de l'item FrequenceTrans qui sera transmis à l'ESP lorsque le switch Endormissement a basculé. Cette valeur est celle de l'item FrequenceAcq.

3.8  Programmation de l'ESP

Il nous reste à programmer l'ESP on repart du code présenté pour l' ESP et du code écrit précédemment.

4.  Sources