Nous continuons aujourd’hui le tutoriel consacré à l’échange de données entre Domoticz et un ESP8266 par requête HTTP (TCP/IP) et plus particulièrement comment piloter le GPIO depuis Domoticz. Dans l’article précédent, nous avons mis en place l’envoi de données depuis un ESP8266 vers Domoticz. Dans cet article, nous allons mettre en place la communication dans l’autre sens.
L’API JSON de Domoticz est une porte d’entrée polyvalente qui permet de mettre à jour des appareils, récupérer des données et réaliser des opérations sur le système domotique. Par contre, cette interface n’est pas bi-directionnelle. On va devoir utiliser un système de requêtes HTTP classique. qui seront récupérées par un petit serveur Web qui fonctionne sur l’ESP8266.
Matériel utilisé
Nous allons reprendre le même montage que le tutoriel précédent. Cette fois, ce montage va permettre d’intégrer un ESP8266. Pour la partie sonde, vous pouvez utiliser un DHT11 ou un DHT22. Rapide à mettre en oeuvre grâce à la librairie DHT.h d’Adafruit. On pourra également ajouter un BMP180 qui permettra de créer un baromètre sur Domoticz. Pour le pilotage du GPIO, vous pouvez utiliser une simple LED ou un relai.
Module ESP8266 ESP-12. Par exemple Wemos D1 Mini | |
Alimentation 5V/3A micro-usb | |
Capteur de pression atmosphérique | |
Capteur de température et d’humidité
DHT11 ou DHT22 |
|
Shield DHT22 ou DHT11 pour Wemos D1 Mini
Le capteur est connecté à la broche D4 (GPIO2) |
|
Shield relai (250VAC/10A ou 30VDC/10A) pour Wemos D1 Mini.
Le relai est accessible depuis la broche D1 (GPIO5) |
|
Led (visualiser l’activation / désactivation du GPIO ) | |
Résistance 220Ω | |
Jumper Dupont | |
Breadboard |
Circuit
Composant | Broches | Broche ESP8266 (Wemos D1 mini) |
DHT22 (shield Wemos D1 Mini) | VCC | 3V3 |
GND | G | |
Data | D4 | |
BMP180 | VCC | 3V3 |
GND | G | |
SDA | D2 | |
SCK | D3 | |
Led GPIO D7 | Pole + | D7 |
Pole – | G | |
Shield relai Wemos D1 Mini | D1 |
Changer les broches du bus I2C de l’ESP8266
Avant d’aller plus loin, vous avez du remarquer que la carte relai de Wemos utilise la broche D1. La broche D1 est partagée avec le broche SCK du bus I2C. Il va donc falloir déplacer la broche du bus I2C pour pouvoir utiliser le shield relai en même temps. Pour cela, on utilise la librairie Wire.h
Déclarez la librairie en début de programme
#include <Wire.h>
Dans le setup() ; mais avant le d’initialiser l’objet BMP180 avec la commande bmp.begin() ; on déclare la initialise le bus I2C en indiquant les nouvelles broches. Comme d’habitude, inutile de chercher les broches équivalentes de l’Arduino, on indique directement les broches de l’ESP8266, la conversion se ferra automatiquement. Ici, j’ai déplacé par broche D1 (SCK) sur la broche D3, ce qui donne
Wire.begin(D2,D3);
C’est tout, vous pouvez maintenant déplacer le bus I2C sur les broches que vous voulez.
Piloter le GPIO de l’ESP8266 depuis Domoticz
Nous allons maintenant piloter le GPIO de l’ESP8266 depuis Domoticz. Vous pouvez également faire des demandes complexes en intégrant des requêtes HTTP dans vos scripts Lua. Ici, nous allons simplement activer le relai du shield relai pour Wemos D1 mini. Pour moins de 8€, vous pouvez réaliser une lampe connectée ou un simulateur de présence à l’aide d’un scénario.
Code Arduino / ESP8266
Pour recevoir des commandes depuis Domoticz, on va ajouter une partie serveur au code Arduino précédent. Ajoutez la librairie ESP8266WebServer au code précédent et créer un server écoutant sur le port 80.
#include <ESP8266WebServer.h> ESP8266WebServer server ( 80 );
Dans le startup ajouter une route sur /gpio après que la connexion au réseau Wi-Fi. Ce serveur sera simplement à l’écoute des appels sur une page /gpio. Chaque appel sur cette page déclenchera l’execution de la fonction updateGpio().
server.on("/gpio", updateGpio); server.begin();
La fonction updateGpio() décode l’URL et met à jour l’état du GPIO correspondant. La fonction server.arg(“id”) permet de récupérer l’identifiant du GPIO etserver.arg(“etat”), l’état de ce dernier.
void updateGpio(){ Serial.println("Update GPIO command from DOMOTICZ : "); for ( int i = 0 ; i < server.args(); i++ ) { Serial.print(server.argName(i)); Serial.println(server.arg(i)); } String gpio = server.arg("id"); int etat = server.arg("etat").toInt(); int pin = D1; if ( gpio == "D1" ) { pin = D1; } else if ( gpio == "D7" ) { pin = D7; } else if ( gpio == "D8" ) { pin = D8; } else { pin = D1; } Serial.print("Update GPIO "); Serial.println(pin); if ( etat == 1 ) { digitalWrite(pin, HIGH); Serial.println("GPIO updated : On"); } else if ( etat == 0 ) { digitalWrite(pin, LOW); Serial.println("GPIO updated : Off"); } else { Serial.println("Bad Led Value !"); } }
Voici le code Arduino complet qu’il vous suffit de téléverser après avoir modifié vos paramètres :
- ssid et mot de passe WiFi
- Adresse IP du serveur Domoticz (host) et le port s’il est différent de 8080
#include <ESP8266WebServer.h> #include <ESP8266WiFi.h> #include <ESP8266HTTPClient.h> #include <DHT.h> #include <Adafruit_BMP085.h> #include <Wire.h> #define DHTTYPE DHT22 // DHT type (DHT11, DHT22) #define DHTPIN D4 // Broche du DHT / DHT Pin const char* ssid = "XXXXXXXX"; const char* password = "XXXXXXXX"; const char* host = "XXX.XXX.XXX.XXX"; const int port = 8080; const int watchdog = 60000; // Fréquence d'envoi des données à Domoticz - Frequency of sending data to Domoticz unsigned long previousMillis = millis(); const uint8_t GPIOPIN[5] = {D1,D5,D6,D7,D8}; // Led DHT dht(DHTPIN, DHTTYPE); Adafruit_BMP085 bmp; ESP8266WebServer server ( 80 ); HTTPClient http; void updateGpio(){ Serial.println("Update GPIO command from DOMOTICZ : "); for ( int i = 0 ; i < server.args(); i++ ) { Serial.print(server.argName(i)); Serial.println(server.arg(i)); } String gpio = server.arg("id"); String token = server.arg("token"); if ( token != "123abCde" ) { Serial.println("Not authentified "); return; } int etat = server.arg("etat").toInt(); int pin = D1; if ( gpio == "D1" ) { pin = D1; } else if ( gpio == "D7" ) { pin = D7; } else if ( gpio == "D8" ) { pin = D8; } else { pin = D1; } Serial.print("Update GPIO "); Serial.println(pin); if ( etat == 1 ) { digitalWrite(pin, HIGH); Serial.println("GPIO updated : On"); } else if ( etat == 0 ) { digitalWrite(pin, LOW); Serial.println("GPIO updated : Off"); } else { Serial.println("Bad Led Value !"); } } void setup() { Serial.begin(115200); delay(10); Wire.begin(D2,D3); if ( !bmp.begin() ) { Serial.println("BMP180 KO!"); while (1); } else { Serial.println("BMP180 OK"); } Serial.setDebugOutput(true); Serial.println("Connecting Wifi..."); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } for ( int x = 0 ; x < 5 ; x++ ) { pinMode(GPIOPIN[x], OUTPUT); } Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.print(WiFi.localIP()); server.on("/gpio", updateGpio); server.begin(); } int value = 0; void loop() { server.handleClient(); unsigned long currentMillis = millis(); if ( currentMillis - previousMillis > watchdog ) { previousMillis = currentMillis; if(WiFi.status() != WL_CONNECTED) { Serial.println("WiFi not connected !"); } else { Serial.println("Send data to Domoticz"); float t = dht.readTemperature(); float h = dht.readHumidity(); float pa = bmp.readPressure() / 100.0F; if ( isnan(t) || isnan(h) ) { Serial.println("DHT KO"); } else { int hum_stat; int bar_for = 0; if ( h > 70 ) { hum_stat = 3; } else if ( h < 30 ) { hum_stat = 2; } else if ( h >= 30 & h <= 45 ) { hum_stat = 0; } else if ( h > 45 & h <= 70 ) { hum_stat = 1; } if ( pa > 1030 ) { bar_for = 1; } else if ( pa > 1010 & pa <= 1030 ) { bar_for = 2; } else if ( pa > 990 & pa <= 1010 ) { bar_for = 3; } else if ( pa > 970 & pa < 990 ) { bar_for = 4; } String url = "/json.htm?type=command¶m=udevice&idx=12&nvalue=0&svalue="; url += String(t); url += ";"; url += String(h); url += ";"; url += String(hum_stat); url += ";"; url += String(pa);url += ";"; url += String(bar_for); sendToDomoticz(url); } } } } void sendToDomoticz(String url){ Serial.print("connecting to "); Serial.println(host); Serial.print("Requesting URL: "); Serial.println(url); http.begin(host,port,url); int httpCode = http.GET(); if (httpCode) { if (httpCode == 200) { String payload = http.getString(); Serial.println("Domoticz response "); Serial.println(payload); } } Serial.println("closing connection"); http.end(); }
Configuration Domoticz : créer un interrupteur virtuel
Retournez dans le matériel pour ajouter un nouveau capteur virtuel.
Piloter le GPIO à l’aide d’une action
Pour allumer, éteindre une lampe sans aucune autre condition, le plus facile et le plus rapide est de configurer une action en fonction de l’état de l’interrupteur. Allez à l’onglet Interrupteurs et ouvrez l’appareil en édition.
Dans le champ Action On, collez l’URL suivante en remplaçant IP_ESP8266 par la votre
http://IP_ESP8266/gpio?id=D1&etat=1&token=123abCde
Pour l’état Off, on mettra donc simplement l’état à 0.
http://IP_ESP8266/gpio?id=D1&etat=0&token=123abCde
Enregistrez.
Piloter le GPIO à l’aide d’un script Lua
L’autre manière de procéder et de créer un script Lua. C’est un peu plus long à mettre en place, mais on a toute la puissance du language à notre disposition. Si vous ne connaissez pas les scripts Lua, vous pouvez commencer par ce tutoriel.
Connectez-vous à votre serveur Domoticz en SSH et placez vous dans le répertoire des scripts Lua
cd ~/domoticz/scripts/lua
On va créer u script qui se déclenche à chaque changement d’état de l’interrupteur. Par convention, le fichier devra donc porter le nom script_device_nomDuDevice.lua, ce qui donne
sudo nano script_device_GPIO_D1.lua
Collez ce code Lua. Modifiez l’adresse IP de votre ESP8266 dans la variable baseurlESP8266. Le script test la valeur de l’appareil RelayD1. Si elle est égale à On, on complète l’url en indiquant l’id=D1 avec l’état à 1, 0 dans le cas contraire. Vous pouvez mettre l’état à On, ON, ALLUME…il faudra simplement tester la valeur de la variable dans le code Arduino.
baseurlESP8266 = "http://192.168.1.22/gpio?" commandArray = {} print ("Update Wemos D1 Mini Relay shield (Pin D1)") if (otherdevices['RelayD1'] == 'On') then commandArray['OpenURL'] = baseurlESP8266..'id=D1&etat=1&token=123abCd' else commandArray['OpenURL'] = baseurlESP8266..'id=D1&etat=0&token=123abCd' end return commandArray
Sécuriser la communication
Il est possible d’améliorer la sécurité des échanges entre Domoticz et l’ESP8266. Vous avez certainement remarqué que l’envoi de données à Domoticz se fait sans la moindre authentification. Si on considère que le serveur domotique n’est jamais exposé à internet et que le réseau Wi-Fi est bien sécurisé, cela ne pose pas trop de problème. Par contre si vous voulez rendre accessible Domoticz depuis internet, il va falloir améliorer ça. Ici, nous n’irons pas jusqu’à chiffrer les échanges, c’est possible mais sort du cadre de ce tutoriel.
Réseaux locaux (pas d’identifiant ni mot de passe)
Dans la majorité des cas, vos objets connectés à base d’ESP8266 devrait se trouver sur le même réseau que le serveur Domoticz. Dans ce cas, le plus facile est d’ajouter les adresses IP de vos objets connectés à la liste des appareils autorisés à utiliser l’API dans autorisation. Pour cela, allez dans les réglages puis Paramètres et complétez le champ Réseaux.
Authentification par utilisateur et mot de passe (code Arduino)
Si vous avez protégé l’accès de votre Domoticz par un identifiant et un mot de passe, il vous suffit de modifier la variable host
La variable host prendra alors la forme
username:password@domoticz-ip
Ajouter un token (jeton) dans la requête HTTP
Ces deux méthodes de sécurisation ne fonctionnent que dans le sens ESP8266 vers Domoticz. Il n’est pas (encore) possible de crypter le serveur web de l’ESP8266. Pour sécuriser les commandes, le plus simple est d’ajouter un clé publique ou un jeton qu’il suffira de tester dans le code Arduino. C’est une sécurisation assez basique mais c’est toujours mieux que rien.
String token = server.arg("token"); if ( token != "123abCde" ) { Serial.println("Not authentified "); return; }
Voilà, vous pouvez maintenant envoyer des données, l’états de capteurs et piloter le GPIO de l’ESP8266 depuis un serveur Domoticz. La prochaine fois, nous verrons comment faire pour Jeedom.
- Domoticz. Installation et prise en main sur un Raspberry Pi OS (Buster)
- Intégrer un module ESP32-CAM à Domoticz (firmware modifié)
- Installer Domoticz sur NAS Synology DS718+ sous Docker ou machine virtuelle
- Test de cloudMQTT, broker MQTT en ligne gratuit. Piloter Domoticz avec l’API JSON
- Sécuriser Domoticz avec un certificat Let’s Encrypt HTTPS
- Utiliser les plugins sur Domoticz. Installation manuelle ou via Python Plugin Manager
Bonjour et merci pour l’ensembles des tuto qui nous aident bien.
Je me casse les dents sur celui-ci que je n’arrive pas à faire fonctionner.
Quand téléverse j’ai ce message:
09:37:46.461 -> sp: 3fff02f0 end: 3fff04e0 offset: 01b0
09:37:46.461 ->
09:37:46.461 -> >>>stack>>>
09:37:46.461 -> 3fff04a0: 3fffdad0 3ffef488 3ffef488 40202784
09:37:46.461 -> 3fff04b0: feefeffe feefeffe feefeffe feefeffe
09:37:46.461 -> 3fff04c0: 3fffdad0 00000000 3ffef4ac 4020824c
09:37:46.461 -> 3fff04d0: feefeffe feefeffe 3ffef4c0 40100718
09:37:46.461 -> <<<stack<<
09:37:46.496 -> ets Jan 8 2013,rst cause:2, boot mode:(1,7)
09:37:46.496 ->
09:37:51.644 ->
09:37:51.644 -> ets Jan 8 2013,rst cause:4, boot mode:(1,7)
09:37:51.644 ->
09:37:51.644 -> wdt reset
qui apparaît mais je ne comprends pas ce que ça signifie.
pouvez-vous m’expliquer ?
Merci
bonjour. Ce n’est pas un problème au niveau du téléversement. Le problème viens du code. Par contre impossible d’en dire plus sans voir le code ou au moins connaitre les librairies utilisées
Bonjour,
quand je compile ça me dit ça, je ne comprend pas
sketch_dec01a:17:29: error: ‘D1’ was not declared in this scope
const uint8_t GPIOPIN[5] = {D1,D5,D6,D7,D8}; // Led
^
sketch_dec01a:17:32: error: ‘D5’ was not declared in this scope
const uint8_t GPIOPIN[5] = {D1,D5,D6,D7,D8}; // Led
^
sketch_dec01a:17:35: error: ‘D6’ was not declared in this scope
const uint8_t GPIOPIN[5] = {D1,D5,D6,D7,D8}; // Led
^
sketch_dec01a:17:38: error: ‘D7’ was not declared in this scope
const uint8_t GPIOPIN[5] = {D1,D5,D6,D7,D8}; // Led
^
sketch_dec01a:17:41: error: ‘D8’ was not declared in this scope
const uint8_t GPIOPIN[5] = {D1,D5,D6,D7,D8}; // Led
^
sketch_dec01a:9:19: error: ‘D4’ was not declared in this scope
#define DHTPIN D4 // Broche du DHT / DHT Pin
^
C:UsersmarsfDocumentsArduinosketch_dec01asketch_dec01a.ino:19:9: note: in expansion of macro ‘DHTPIN’
DHT dht(DHTPIN, DHTTYPE);
^
C:UsersmarsfDocumentsArduinosketch_dec01asketch_dec01a.ino: In function ‘void updateGpio()’:
sketch_dec01a:36:13: error: ‘D1’ was not declared in this scope
int pin = D1;
^
sketch_dec01a:40:11: error: ‘D7’ was not declared in this scope
pin = D7;
^
sketch_dec01a:42:11: error: ‘D8’ was not declared in this scope
pin = D8;
^
C:UsersmarsfDocumentsArduinosketch_dec01asketch_dec01a.ino: In function ‘void setup()’:
sketch_dec01a:61:14: error: ‘D2’ was not declared in this scope
Wire.begin(D2,D3);
^
sketch_dec01a:61:17: error: ‘D3’ was not declared in this scope
Wire.begin(D2,D3);
^
exit status 1
‘D1’ was not declared in this scope
Bonjour Marsflow. Avez vous choisi la bonne carte (à priori ESP8266). Si c’est l’Arduino/Genuino qui est sélectionné, c’est normal d’avoir ces erreurs.
Oups, j’ai oublié de te remercier vivement pour tous tes posts qui me sont bien utiles !
Merci à vous tous !
Dans la partie “Changer les broches du bus I2C”
Au lieu de “Wire.begin(D2,D3);” ce n’est pas plutôt “Wire.begin(D1,D3);” ?
Bonjour Steph. On peut passer les broches que l’on souhaite au moment de l’appel Wire.begin. C’est pratique sur la Wemos par exemple car les shields se marchent un peu sur les pieds comme il y a moins de broches que sur un Arduino (vivement l’ESP32 !)
Oups, j’ai oublié ceci :
3) l’idée étant, dans la mesure du possible et après calcul des consummation, d’alimenter ce Dual board avec une batterie solaire place à la fenêtre (parce que mes quatre fenêtres disposent d’un ensoleillement dès le matin jusqu’à 16 hr).
Je me dis qu’en utilisant le fameux “Deep sleep”, peut-être pourrais-je le faire :
a) ouvrir les stores le matin dès 6 hr
b) lire toutes les heures (ou à convenir) la T° et H° sur la journée pour ne fermer les stores qu’à la demande du bouton ou à l’heure souhaitée le soir (que ce soit dès allumage des lampes intérieures – tiens faudrait rajouter un senseur de lumière).
A bon entendeur 😉
Bonjour,
sujet intéressant puisque j’aimerais bien aboutir à ceci :
1) un Wemos D1 Mini (merci de mentionner si il serait alors preferable de prendre le 16M plutôt que le 4M)
2) il serait place sur un “Dual board” pour avoir
a) d’un côté avoir le Wemos D1 Mini avec un SHT30 (T° et H° plutôt qu’un DHT22) et un senseur de CO2 (https://www.aliexpress.com/item/MQ-9-combustible-gas-sensor-detects-carbon-monoxide-alarm-module-sensor-for-arduino-Compatible-1pcs/32794413364.html?spm=2114.01010208.3.319.GahB8Q&ws_ab_test=searchweb0_0,searchweb201602_6_10065_10068_433_434_10136_10137_1)
b) de l’autre côté, un “Motor Shield Dual motor driver” (https://www.aliexpress.com/store/product/Motor-Shield-For-WeMos-D1-mini-I2C-Dual-Motor-Driver-TB6612FNG-1A-V1-0-0/1331105_32700182142.html?spm=2114.12010608.0.0.KpkN6A) en vue de commander en meme temps deux store (Rideau enrouleur), d’un bouton pour pouvoir le commander manuellement sans devoir passer par l’interface domotique (https://www.aliexpress.com/store/product/1-Button-Shield-for-WeMos-D1-mini-button/1331105_32575988167.html?spm=2114.12010615.0.0.yyPmKd) et pourquoi pas, avec un détecteur de presence pour peaufiner (seulement si nécessaire) (https://www.aliexpress.com/item/HC-SR04-Ultrasonic-Ranging-Module-Module-ultrasonic-sensors-for-arduino-Compatible-1pcs/2033580925.html?spm=2114.01010208.3.116.GahB8Q&ws_ab_test=searchweb0_0,searchweb201602_6_10065_10068_433_434_10136_10137_10138_10060_10)
Ce dual board serait alors place sur chaque fenêtre (qui est compose de deux battants) donnant ainsi la T° et H° de la pièce, la possibilité de monter/descendre ensemble les deux stores sur les deux battants de fenêtres, mais également et surtout, de prévenir (le Banana Pi M2+ étant pairé en Bluetooth sur une baffle (speaker) centralisé) de toute accumaltion risquée de CO2 (indépendamment) pour chaque pièce (permettant alors d’enclencher les extracteurs d’humiditié ou VMC pour éviter les accidents).
Merci, dans la mesure du possible, d’orienter le present article vers une solution cumulée comme présentée ci-dessus.
Au plaisir de vous lire,
Miguipda 😉
Bonjour Migui. Très beau projet ! Pour moi, c’est tout à fait possible. Pour le moment j’ai toutefois quelques réserves coté matériel. Je m’explique. Les capteurs de la série MQ sont des capteurs photochimiques. Ils doivent atteindre une température de fonctionner…donc il faut le laisser en permanence alimentée, c’est qui peut être problématique avec une alimentation sur batterie (même solaire). Il faut compter 15 minutes pour que la mesure soit correcte. Ensuite ce sont des capteurs sensibles à plusieurs polluants, on récupère un signal mais il faut procéder à un étalonnage pour connaître la teneur pour le gaz recherché. Comme personne n’est équipé, il faut s’en remettre à internet et là y a vraiment de tout ! J’ai mis en pose les articles sur le sujet (je n’aime pas écrire un article sans avoir vérifié/testé). J’ai commandé un autre MQ135 pour corréler mes mesures. Je pense qu’il vaudrait mieux partir sur des capteurs CO2 pré-calibré. Ils sont 10x plus couteux mais la mesure devrait être plus fiable. On trouve des exemples de code pour le MH-Z19 par exemple (http://s.click.aliexpress.com/e/yb6aiEm). Concernant le shield Motor, je viens de commander mon 3ème, les 2 premiers ne fonctionnent pas ! Il semble que le microcontroleur I2C STM32F030 des clones du shield Wemos ne sont pas programmés ! Et c’est pas très facile à faire : https://hackaday.io/project/18439-motor-shield-reprogramming. En attendant, il y a toujours le L293D ou L298N (http://s.click.aliexpress.com/e/I2zVjAA). Concernant la Wemos Pro 16M, les 16M ne sont pas encore (facilement) pris en charge. Pour moi l’intérêt réside dans la possibilité d’ajouter une antenne externe.Pratique si la wemos est dans une boite au lettre par exemple. Par contre, il faut au moins 5dBi pour commencer à voir la différence. Bon, c’est pas très positif comme réponse mais on devrait finir par trouver le matériel pour le faire. Bon week end