Capteur temperature humidite wifi_arduino_jeedom

Capteur température humidité WiFi sur pile à moins de 10 euros – Arduino et Jeedom

Le matériel est prêt, le produit ressemble à un produit fini. Il ne reste plus que le fonctionnel et développer une application embarquée pour que le capteur soit enfin vivant. Je ne vous cache pas que dans la réalité, on développe en parallèle du matériel, ne serait-ce que pour tester le fonctionnement des composants du produit. En effet, entre le hardware et le software, l’un peut subvenir au besoin de l’autre…

Dans la suite de l’article, je vais vous présenter le principe du fonctionnement du capteur, de comment il vie et comment le paramétrer.

Enfin, je vous montrerai comment je l’ai intégré à ma domotique. Étant utilisateur de Jeedom, j’ai donc développé un plugin afin de recevoir les données du capteur et interagir avec.

Bien entendu tout sera disponible sur mon github. (D’ailleurs s’il manque des informations n’hésitez pas à poser un commentaire).

Principe de fonctionnement

Comme expliqué précédemment sur la partie hardware, le capteur va communiquer ses valeurs toutes les 2 heures. Pour cela :

  • le Timer va déclencher l’alimentation du capteur
  • Le capteur va récupérer sa configuration pour se connecter au WiFi
  • Le capteur fait ses mesures
  • Le capteur envoie les données en HTTP en appelant une page avec la méthode POST (Oui je sais, y a mieux en matière de communication non baveuse comme MQTT)
  • Le capteur dit au Timer de couper l’alimentation de se remettre à compter

Voici le Schéma de fonctionnement général :

schéma_principe_fonctionnement_espiot
Principe de fonctionnement du capteur

Ce diagramme d’action est assez simple et permet d’optimiser la consommation d’énergie du capteur. Dans le cas le plus défavorable, le temps d’éveil correspond à environ 6-7 secondes.

Ce diagramme ne montre que la partie en production. En réalité, toutes les fonctions du capteur (notamment pour la gestion de la configuration) ne sont pas traitées.

Entrer en mode configuration

Pour entrer en mode configuration, il faut « désactiver le timer« . Pour cela il suffit, de placer un cavalier entre le GND de la pile et le GND du MOSFET comme suit :

capteur T/H wifi mode configuration

Cavalier à placer pour le mode configuration

Une fois que le cavalier est placé, le module ne s’éteindra plus. Lorsque le capteur se connecte (ou pas) à votre borne WiFi, normalement, on demande au Timer de couper l’alimentation. Mais dans ce cas, :

  • L’alimentation n’est pas coupée.
  • On passe alors le module en mode Point d’accès
  • On monte un serveur Web contenant les pages de configuration.

Il suffit alors de:

  • Se connecter (avec un appareil WiFi) au point d’accès ESP-XXXX avec le compte admin/adminXXXX
  • Ouvrir un navigateur à l’adresse : http://192.168.4.1
  • Suivre les instructions.

espiot_ecran_de_configuration_generalespiot_ecran_de_configuration_WiFiespiot_ecran_de_configuration_update_Firmware

Liste d’écran de configuration du capteur T/H WiFi (ESPIOT)

L’apparence est encore sommaire mais totalement fonctionnel. Ca fait partie des points d’améliorations (ne serait-ce qu’une feuille de style ;)).

PS : une fois paramétrée, ne pas oublier de retiré le cavalier

Logiciel embarqué. Sketch Arduino

La suite, c’est du code pure. je vous laisse le lire, le copier ou l’analyser. Il n’est pas du tout optimisé, c’est une première version mais il a le mérite de fonctionner parfaitement. (plusieurs mois de fonctionnement sur cette version)

[pastacode lang= »c » manual= »%2F**%0A%20*%20ESPIOT%0A%20*%0A%20*%20%20Created%20on%3A%2021.10.2016%0A%20*%0A%20*%20VERSION%201.01a%0A%20*%20CHANGELOG%0A%20*%202017-01-29%0A%20*%2F%0A%23include%20%3Cstdint.h%3E%0A%23include%20%3CHardwareSerial.h%3E%0A%23include%20%3CArduino.h%3E%0A%0A%23include%20%3CESP8266WiFi.h%3E%0A%23include%20%3CESP8266HTTPClient.h%3E%0A%23include%20%3CESP8266WebServer.h%3E%0A%23include%20%3CESP8266mDNS.h%3E%0A%0A%23include%20%3CDHT.h%3E%0A%0A%23include%20%3CArduinoJson.h%3E%0A%23include%20%22FS.h%22%0A%0Aextern%20%22C%22%20%7B%0A%23include%20%3Cuser_interface.h%3E%0A%7D%0A%0A%23define%20FPM_SLEEP_MAX_TIME%200xFFFFFFF%0A%0A%2F*%20DEFINES%0A%20*%20%20%0A%20*%2F%0A%23define%20DHTTYPE%20DHT11%0A%23define%20DHTPIN%20%205%0A%23define%20DONEPIN%2014″ message= »Inclusions » highlight= » » provider= »manual »/]

[pastacode lang= »c » manual= »%2F*%20%0A%20*%20%20VARIABLES%20GLOBALES%0A%20*%2F%0A%20%20const%20char*%20WIFISSIDValue%3B%0A%20%20const%20char*%20WIFIpassword%3B%0A%20%20String%20urlServer%20%3B%0A%20%20const%20char*%20HTTPUser%3B%0A%20%20const%20char*%20HTTPPass%20%3B%0A%20%20const%20char*%20jsonIp%3B%0A%20%20char%20ip1%2Cip2%2Cip3%2Cip4%3B%0A%20%20char%20mask1%2Cmask2%2Cmask3%2Cmask4%3B%0A%20%20char%20gw1%2Cgw2%2Cgw3%2Cgw4%3B%0A%20%20%0A%20%20bool%20connexionOK%3Dfalse%3B%0A%20%20bool%20configOK%3Dfalse%3B%0A%0A%20%20bool%20cmdComplete%3Dfalse%3B%0A%20%20String%20SerialCMD%3B%0A%0A%20%20int%20retryConnexionOk%2CretryWifi%3B%0A%20%20int%20countConnexion%3D0%3B%0A%20%20bool%20EndCheck%3Dfalse%3B%0A%20%20bool%20ToReboot%3Dfalse%3B%0A%20%20char%20wificonfig%5B512%5D%3B%0A%20%20%0A%20%20IPAddress%20ip%2Cgateway%2Csubnet%3B%0A%20%20%0A%20%20uint8_t%20MAC_array%5B6%5D%3B%0A%20%20char%20MAC_char%5B18%5D%3B%0A%20%20%0A%20%20DHT%20dht(DHTPIN%2C%20DHTTYPE)%3B%20%0A%0A%20%20ESP8266WebServer%20server(80)%3B%0A%20%20char%20serverIndex%5B512%5D%20%3D%20%22%3Ch1%3E%3Cimg%20src%3D’%2Flogo.png’%3E%3Cbr%3EESPIOT%20Config%3C%2Fh1%3E%3Cul%3E%3Cli%3E%3Ca%20href%3D’params’%3EConfig%20ESPIOT%3C%2Fa%3E%3C%2Fli%3E%3Cli%3E%3Ca%20href%3D’update’%3EFlash%20ESPIOT%3C%2Fa%3E%3C%2Fli%3E%3C%2Ful%3E%3Cbr%3E%3Cbr%3EVersion%3A%201.0%3Cbr%3E%3Ca%20href%3D’https%3A%2F%2Fgithub.com%2Ffairecasoimeme%2F’%20target%3D’_blank’%3EDocumentation%3C%2Fa%3E%22%3B%0A%20%20char%20serverIndexUpdate%5B512%5D%20%3D%20%22%3Ch1%3EESPIOT%20Config%3C%2Fh1%3E%3Ch2%3EUpdate%20Firmware%3C%2Fh2%3E%3Cform%20method%3D’POST’%20action%3D’%2FupdateFile’%20enctype%3D’multipart%2Fform-data’%3E%3Cinput%20type%3D’file’%20name%3D’update’%3E%3Cinput%20type%3D’submit’%20value%3D’Update’%3E%3C%2Fform%3E%22%3B%0A%20%20char%20serverIndexConfig%5B4092%5D%20%3D%20%22%3Ch1%3EESPIOT%20Config%3C%2Fh1%3E%3Ch2%3EConfig%20ESPIOT%3C%2Fh2%3E%3Cform%20method%3D’POST’%20action%3D’%2Fconfig’%3ESSID%20%3A%20%3Cbr%3E%3Cinput%20type%3D’text’%20name%3D’ssid’%3E%3Cbr%3EPass%20%3A%20%3Cbr%3E%3Cinput%20type%3D’password’%20name%3D’pass’%3E%3Cbr%3E%40IP%20%3A%20%3Cbr%3E%3Cinput%20type%3D’text’%20name%3D’ip’%3E%3Cbr%3EMask%20%3A%20%3Cbr%3E%3Cinput%20type%3D’text’%20name%3D’mask’%3E%3Cbr%3E%40GW%20%3A%20%3Cbr%3E%3Cinput%20type%3D’text’%20name%3D’gw’%3E%3Cbr%3EHttp%20user%20%3A%20%3Cbr%3E%3Cinput%20type%3D’text’%20name%3D’userhttp’%3E%3Cbr%3EHttp%20pass%20%3A%20%3Cbr%3E%3Cinput%20type%3D’text’%20name%3D’passhttp’%3E%3Cbr%3EURL%20%3A%20%3Cbr%3E%3Cinput%20type%3D’text’%20name%3D’url’%3E%3Cbr%3E%3Cinput%20type%3D’submit’%20value%3D’OK’%3E%3C%2Fform%3E%22%3B%0A%20%20const%20char*%20Style%20%3D%20%22%3Cstyle%3Ebody%20%7B%20%20text-align%3A%20center%3B%20font-family%3AArial%2C%20Tahoma%3B%20%20background-color%3A%23f0f0f0%3B%7Dul%20li%20%7B%20border%3A1px%20solid%20gray%3B%20%20height%3A30px%3B%20%20padding%3A3px%3B%20%20list-style%3A%20none%3B%7Dul%20li%20a%20%7B%20text-decoration%3A%20none%3B%7Dinput%7B%20border%3A1px%20solid%20gray%3B%20%20height%3A25px%3B%7Dinput%5Btype%3Dtext%5D%20%7B%20width%3A150px%3B%20%20padding%3A5px%3B%20%20font-size%3A10px%3B%7D%23url%20%7B%20%20width%3A300px%3B%7D%3C%2Fstyle%3E%22%3B%0A » message= » » highlight= » » provider= »manual »/]

[pastacode lang= »c » manual= »%2F*%20FONCTION%20POUR%20CHARGER%20LA%20CONFIG%0A%20*%20%20%0A%20*%20%20%0A%20*%2F%0Abool%20loadConfig()%20%7B%0A%20%20File%20configFile%20%3D%20SPIFFS.open(%22%2Fconfig.json%22%2C%20%22r%22)%3B%0A%20%20if%20(!configFile)%20%7B%0A%20%20%20%20Serial.println(%22Failed%20to%20open%20config%20file%22)%3B%0A%20%20%20%20return%20false%3B%0A%20%20%7D%0A%0A%20%20size_t%20size%20%3D%20configFile.size()%3B%0A%20%20if%20(size%20%3E%201024)%20%7B%0A%20%20%20%20Serial.println(%22Config%20file%20size%20is%20too%20large%22)%3B%0A%20%20%20%20return%20false%3B%0A%20%20%7D%0A%0A%20%20%2F%2F%20Allocate%20a%20buffer%20to%20store%20contents%20of%20the%20file.%0A%20%20std%3A%3Aunique_ptr%3Cchar%5B%5D%3E%20buf(new%20char%5Bsize%5D)%3B%0A%0A%20%20%2F%2F%20We%20don’t%20use%20String%20here%20because%20ArduinoJson%20library%20requires%20the%20input%0A%20%20%2F%2F%20buffer%20to%20be%20mutable.%20If%20you%20don’t%20use%20ArduinoJson%2C%20you%20may%20as%20well%0A%20%20%2F%2F%20use%20configFile.readString%20instead.%0A%20%20configFile.readBytes(buf.get()%2C%20size)%3B%0A%0A%20%20StaticJsonBuffer%3C200%3E%20jsonBuffer%3B%0A%20%20JsonObject%26%20json%20%3D%20jsonBuffer.parseObject(buf.get())%3B%0A%0A%20%20if%20(!json.success())%20%7B%0A%20%20%20%20Serial.println(%22Failed%20to%20parse%20config%20file%22)%3B%0A%20%20%20%20return%20false%3B%0A%20%20%7D%0A%20%20%0A%20%20if%20(json.containsKey(%22WIFISSID%22))%20%0A%20%20%7B%0A%20%20%20%20WIFISSIDValue%20%3D%20json%5B%22WIFISSID%22%5D%3B%0A%20%20%7D%0A%20%20%0A%20%20if%20(json.containsKey(%22WIFIpass%22))%20%0A%20%20%7B%0A%20%20%20%20WIFIpassword%20%3D%20json%5B%22WIFIpass%22%5D%3B%0A%20%20%7D%0A%20%20%0A%20%20if%20(json.containsKey(%22Ip%22))%20%0A%20%20%7B%0A%20%20%20%20jsonIp%20%3D%20json%5B%22Ip%22%5D%3B%0A%20%20%20%20ip.fromString(jsonIp)%3B%0A%20%20%7D%0A%20%20%0A%20%20if%20(json.containsKey(%22Mask%22))%20%0A%20%20%7B%0A%20%20%20%20jsonIp%20%3D%20json%5B%22Mask%22%5D%3B%0A%20%20%20%20subnet.fromString(jsonIp)%3B%0A%20%20%7D%0A%20%20%0A%20%20if%20(json.containsKey(%22GW%22))%20%0A%20%20%7B%0A%20%20%20%20jsonIp%20%3D%20json%5B%22GW%22%5D%3B%0A%20%20%20%20gateway.fromString(jsonIp)%3B%0A%20%20%7D%0A%20%20%0A%20%20if%20(json.containsKey(%22urlServer%22))%20%0A%20%20%7B%0A%20%20%20%20%20urlServer%20%3D%20json%5B%22urlServer%22%5D.asString()%3B%0A%20%20%7D%0A%20%20if%20(json.containsKey(%22HTTPUser%22))%20%0A%20%20%7B%0A%20%20%20%20%20HTTPUser%20%3D%20json%5B%22HTTPUser%22%5D.asString()%3B%0A%20%20%7D%0A%20%20if%20(json.containsKey(%22HTTPPass%22))%20%0A%20%20%7B%0A%20%20%20%20%20HTTPPass%20%3D%20json%5B%22HTTPPass%22%5D.asString()%3B%0A%20%20%7D%0A%0A%20%20uint8_t%20tmp%5B6%5D%3B%0A%20%20char%20tmpMAC%5B18%5D%3B%0A%20%20WiFi.macAddress(tmp)%3B%0A%20%20for%20(int%20i%20%3D%200%3B%20i%20%3C%20sizeof(tmp)%3B%20%2B%2Bi)%7B%0A%20%20%20%20sprintf(tmpMAC%2C%22%25s%2502x%22%2CtmpMAC%2Ctmp%5Bi%5D)%3B%0A%20%20%7D%0A%20%20json%5B%22ID%22%5D%20%3D%20%20String(tmpMAC)%3B%0A%20%20json.printTo(wificonfig%2Csizeof(wificonfig))%3B%0A%0A%20%20sprintf(serverIndexConfig%2C%22%3Chtml%3E%3Chead%3E%3C%2Fhead%3E%3Cbody%3E%3Ch1%3EESPIOT%20Config%3C%2Fh1%3E%3Ch2%3E%40MAC%20%3A%20%25s%3C%2Fh2%3E%3Cform%20method%3D’POST’%20action%3D’%2Fconfig’%3ESSID%20%3A%20%3Cbr%3E%3Cinput%20type%3D’text’%20name%3D’ssid’%20value%3D’%25s’%3E%3Cbr%3EPass%20%3A%20%3Cbr%3E%3Cinput%20type%3D’password’%20name%3D’pass’%3E%3Cbr%3E%40IP%20%3A%20%3Cbr%3E%3Cinput%20type%3D’text’%20name%3D’ip’%20value%3D’%25s’%3E%3Cbr%3EMask%20%3A%20%3Cbr%3E%3Cinput%20type%3D’text’%20name%3D’mask’%20value%3D’%25s’%3E%3Cbr%3E%40GW%20%3A%20%3Cbr%3E%3Cinput%20type%3D’text’%20name%3D’gw’%20value%3D’%25s’%3E%3Cbr%3EURL%20%3A%20%3Cbr%3E%3Cinput%20type%3D’text’%20name%3D’url’%20value%3D’%25s’%20style%3D’width%3A300px%3B’%3E%3Cbr%3EHttp%20user%20%3A%20%3Cbr%3E%3Cinput%20type%3D’text’%20name%3D’userhttp’%20value%3D’%25s’%3E%3Cbr%3EHttp%20pass%20%3A%20%3Cbr%3E%3Cinput%20type%3D’text’%20name%3D’passhttp’%20value%3D’%25s’%3E%3Cbr%3E%3Cbr%3E%3Cinput%20type%3D’submit’%20value%3D’OK’%3E%3C%2Fform%3E%3C%2Fbody%3E%3C%2Fhtml%3E%22%2Cjson%5B%22ID%22%5D.asString()%2Cjson%5B%22WIFISSID%22%5D.asString()%2Cjson%5B%22Ip%22%5D.asString()%2Cjson%5B%22Mask%22%5D.asString()%2Cjson%5B%22GW%22%5D.asString()%2Cjson%5B%22urlServer%22%5D.asString()%2Cjson%5B%22HTTPUser%22%5D.asString()%2Cjson%5B%22HTTPPass%22%5D.asString())%3B%0A%20%20%20%20return%20true%3B%0A%7D » message= »Chargement de la config » highlight= » » provider= »manual »/]

[pastacode lang= »c » manual= »void%20PowerDown()%0A%7B%0A%20%20digitalWrite(DONEPIN%2CHIGH)%3B%0A%20%20delay(1)%3B%0A%20%20digitalWrite(DONEPIN%2CLOW)%3B%0A%20%20Serial.print(%22%20power%20down%20%22)%3B%0A%0A%7D%0A » message= »Fonction qui permet de couper l’alimentation par le Timer » highlight= » » provider= »manual »/]

[pastacode lang= »c » manual= »float%20readADC_avg()%0A%7B%0A%20%20int%20battery%3D0%3B%0A%20%20for%20(int%20i%3D0%3Bi%3C10%3Bi%2B%2B)%0A%20%20%7B%0A%20%20%20%20%20%20battery%20%3D%20battery%20%2B%20analogRead(A0)%3B%0A%20%20%7D%0A%20%20return%20(((battery%2F10)*4.2)%2F1024)%3B%0A%20%20%0A%7D » message= »Fonction de lecture de la tension de pile » highlight= » » provider= »manual »/]

[pastacode lang= »c » manual= »void%20setupWifiAP()%0A%7B%0A%20%20WiFi.mode(WIFI_AP)%3B%0A%0A%20%20uint8_t%20mac%5BWL_MAC_ADDR_LENGTH%5D%3B%0A%20%20WiFi.softAPmacAddress(mac)%3B%0A%20%20String%20macID%20%3D%20String(mac%5BWL_MAC_ADDR_LENGTH%20-%202%5D%2C%20HEX)%20%2B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20String(mac%5BWL_MAC_ADDR_LENGTH%20-%201%5D%2C%20HEX)%3B%0A%20%20macID.toUpperCase()%3B%0A%20%20String%20AP_NameString%20%3D%20%22ESPIOT-%22%20%2B%20macID%3B%0A%0A%20%20char%20AP_NameChar%5BAP_NameString.length()%20%2B%201%5D%3B%0A%20%20memset(AP_NameChar%2C%200%2C%20AP_NameString.length()%20%2B%201)%3B%0A%0A%20%20for%20(int%20i%3D0%3B%20i%3CAP_NameString.length()%3B%20i%2B%2B)%0A%20%20%20%20AP_NameChar%5Bi%5D%20%3D%20AP_NameString.charAt(i)%3B%0A%0A%20%20String%20WIFIPASSSTR%20%3D%20%22admin%22%2BmacID%3B%0A%20%20char%20WIFIPASS%5BWIFIPASSSTR.length()%2B1%5D%3B%0A%20%20memset(WIFIPASS%2C0%2CWIFIPASSSTR.length()%2B1)%3B%0A%20%20for%20(int%20i%3D0%3B%20i%3CWIFIPASSSTR.length()%3B%20i%2B%2B)%0A%20%20%20%20WIFIPASS%5Bi%5D%20%3D%20WIFIPASSSTR.charAt(i)%3B%0A%0A%20%20WiFi.softAP(AP_NameChar%2CWIFIPASS%20)%3B%0A%7D » message= »Configuration du module en mode point d’accès » highlight= » » provider= »manual »/]

[pastacode lang= »c » manual= »void%20serverWebCfg()%0A%7B%0A%20%20char*%20host%20%3D%20%22espiot%22%3B%0A%20%20Serial.println(%22HTTP%20server%20started%22)%3B%0A%20%20%20%20MDNS.begin(host)%3B%0A%0A%0A%20%20%20%20server.on(%22%2Flist%22%2C%20HTTP_GET%2C%20handleFileList)%3B%0A%20%20%20%20server.on(%22%2Flogo.png%22%2C%20handleLogo)%3B%20%0A%20%20%20%20server.on(%22%2F%22%2C%20HTTP_GET%2C%20%5B%5D()%7B%0A%20%20%20%20%20%20server.sendHeader(%22Connection%22%2C%20%22close%22)%3B%0A%20%20%20%20%20%20server.send(200%2C%20%22text%2Fhtml%22%2C%20strcat(serverIndex%2CStyle))%3B%0A%20%20%20%20%7D)%3B%0A%20%20%20%20server.on(%22%2Fupdate%22%2C%20HTTP_GET%2C%20%5B%5D()%7B%0A%20%20%20%20%20%20server.sendHeader(%22Connection%22%2C%20%22close%22)%3B%0A%20%20%20%20%20%20server.send(200%2C%20%22text%2Fhtml%22%2C%20strcat(serverIndexUpdate%2CStyle))%3B%0A%20%20%20%20%7D)%3B%0A%20%20%20%20server.on(%22%2Fparams%22%2C%20HTTP_GET%2C%20%5B%5D()%7B%0A%20%20%20%20%20%20server.sendHeader(%22Connection%22%2C%20%22close%22)%3B%0A%20%20%20%20%20%20server.send(200%2C%20%22text%2Fhtml%22%2C%20strcat(serverIndexConfig%2CStyle))%3B%0A%20%20%20%20%7D)%3B%0A%20%20%20%20%20server.on(%22%2Fconfig%22%2C%20HTTP_POST%2C%20%5B%5D()%7B%0A%20%20%20%20%20%20%0A%20%20%20%20%20%20%20String%20StringConfig%3B%0A%20%20%20%20%20%20%20String%20ssid%3Dserver.arg(%22ssid%22)%3B%0A%20%20%20%20%20%20%20String%20pass%3Dserver.arg(%22pass%22)%3B%0A%20%20%20%20%20%20%20String%20ip%3Dserver.arg(%22ip%22)%3B%0A%0A%20%20%20%20%20%20%20String%20mask%3Dserver.arg(%22mask%22)%3B%0A%0A%20%20%20%20%20%20%20String%20gw%3Dserver.arg(%22gw%22)%3B%0A%0A%20%20%20%20%20%20%20String%20userhttp%3Dserver.arg(%22userhttp%22)%3B%0A%20%20%20%20%20%20%20String%20passhttp%3Dserver.arg(%22passhttp%22)%3B%0A%20%20%20%20%20%20%20String%20url%3Dserver.arg(%22url%22)%3B%0A%20%20%20%20%20%20%20uint8_t%20tmp%5B6%5D%3B%0A%20%20%20%20%20%20%20char%20tmpMAC%5B18%5D%3B%0A%20%20%20%20%20%20%20WiFi.macAddress(tmp)%3B%0A%20%20%20%20%20%20%20for%20(int%20i%20%3D%201%3B%20i%20%3C%20sizeof(tmp)%3B%20%2B%2Bi)%7B%0A%20%20%20%20%20%20%20%20sprintf(tmpMAC%2C%22%25s%2502x%3A%22%2CtmpMAC%2Ctmp%5Bi%5D)%3B%0A%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20%20%20%20StringConfig%20%3D%20%22%7B%5C%22ID%5C%22%3A%5C%22%22%2BString(tmpMAC)%2B%22%5C%22%2C%5C%22WIFISSID%5C%22%3A%5C%22%22%2Bssid%2B%22%5C%22%2C%5C%22WIFIpass%5C%22%3A%5C%22%22%2Bpass%2B%22%5C%22%2C%5C%22Ip%5C%22%3A%5C%22%22%2Bip%2B%22%5C%22%2C%5C%22Mask%5C%22%3A%5C%22%22%2Bmask%2B%22%5C%22%2C%5C%22GW%5C%22%3A%5C%22%22%2Bgw%2B%22%5C%22%2C%5C%22urlServer%5C%22%3A%5C%22%22%2Burl%2B%22%5C%22%2C%5C%22HTTPUser%5C%22%3A%5C%22%22%2Buserhttp%2B%22%5C%22%2C%5C%22HTTPPass%5C%22%3A%5C%22%22%2Bpasshttp%2B%22%5C%22%7D%22%3B%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20StaticJsonBuffer%3C512%3E%20jsonBuffer%3B%0A%20%20%20%20%20%20%20JsonObject%26%20json%20%3D%20jsonBuffer.parseObject(StringConfig)%3B%0A%20%20%20%20%20%20%20File%20configFile%20%3D%20SPIFFS.open(%22%2Fconfig.json%22%2C%20%22w%22)%3B%0A%20%20%20%20%20%20%20if%20(!configFile)%20%7B%0A%20%20%20%20%20%20%20%20Serial.println(%22Failed%20to%20open%20config%20file%20for%20writing%22)%3B%0A%20%20%20%20%20%20%20%7Delse%7B%0A%20%20%20%20%20%20%20%20%20json.printTo(configFile)%3B%0A%20%20%20%20%20%20%20%20%20delay(5000)%3B%0A%20%20%20%20%20%20%20%20%20ToReboot%3Dtrue%3B%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%0A%20%20%20%20%20%20server.send(200%2C%20%22text%2Fplain%22%2C%20%22OK%22)%3B%0A%20%20%20%20%7D)%3B%0A%20%20%20%0A%20%20%20%20server.on(%22%2FupdateFile%22%2C%20HTTP_POST%2C%20%5B%5D()%7B%0A%20%20%20%20%20%20server.sendHeader(%22Connection%22%2C%20%22close%22)%3B%0A%20%20%20%20%20%20server.send(200%2C%20%22text%2Fplain%22%2C%20(Update.hasError())%3F%22FAIL%22%3A%22OK%22)%3B%0A%20%20%20%20%20%20ESP.restart()%3B%0A%20%20%20%20%7D%2C%5B%5D()%7B%0A%20%20%20%20%20%20HTTPUpload%26%20upload%20%3D%20server.upload()%3B%0A%20%20%20%20%20%20if(upload.status%20%3D%3D%20UPLOAD_FILE_START)%7B%0A%20%20%20%20%20%20%20%20Serial.setDebugOutput(true)%3B%0A%20%20%20%20%20%20%20%20WiFiUDP%3A%3AstopAll()%3B%0A%20%20%20%20%20%20%20%20Serial.printf(%22Update%3A%20%25s%5Cn%22%2C%20upload.filename.c_str())%3B%0A%20%20%20%20%20%20%20%20uint32_t%20maxSketchSpace%20%3D%20(ESP.getFreeSketchSpace()%20-%200×1000)%20%26%200xFFFFF000%3B%0A%20%20%20%20%20%20%20%20if(!Update.begin(maxSketchSpace))%7B%2F%2Fstart%20with%20max%20available%20size%0A%20%20%20%20%20%20%20%20%20%20Update.printError(Serial)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%7D%20else%20if(upload.status%20%3D%3D%20UPLOAD_FILE_WRITE)%7B%0A%20%20%20%20%20%20%20%20if(Update.write(upload.buf%2C%20upload.currentSize)%20!%3D%20upload.currentSize)%7B%0A%20%20%20%20%20%20%20%20%20%20Update.printError(Serial)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%7D%20else%20if(upload.status%20%3D%3D%20UPLOAD_FILE_END)%7B%0A%20%20%20%20%20%20%20%20if(Update.end(true))%7B%20%2F%2Ftrue%20to%20set%20the%20size%20to%20the%20current%20progress%0A%20%20%20%20%20%20%20%20%20%20Serial.printf(%22Update%20Success%3A%20%25u%5CnRebooting…%5Cn%22%2C%20upload.totalSize)%3B%0A%20%20%20%20%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20Update.printError(Serial)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20Serial.setDebugOutput(false)%3B%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20yield()%3B%0A%20%20%20%20%7D)%3B%0A%20%20%20%20server.begin()%3B%0A%20%20%20%20MDNS.addService(%22http%22%2C%20%22tcp%22%2C%2080)%3B%0A%0A%7D%0A » message= »Gestion du serveur Web » highlight= » » provider= »manual »/]

[pastacode lang= »c » manual= »void%20setup()%20%7B%0A%0A%20%20%20%20pinMode(DONEPIN%2COUTPUT)%3B%0A%20%20%20%20digitalWrite(DONEPIN%2CLOW)%3B%0A%0A%20%20%20%20Serial.begin(9600)%3B%0A%20%20%20%20Serial.setDebugOutput(true)%3B%0A%20%20%20%20%20%20%0A%20%20%20%20if%20(!SPIFFS.begin())%20%7B%0A%20%20%20%20%20%20Serial.println(%22Failed%20to%20mount%20file%20system%22)%3B%0A%20%20%20%20%20%20return%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20if%20(!loadConfig())%20%7B%0A%20%20%20%20%20%20Serial.println(%22Failed%20to%20load%20config%22)%3B%0A%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20configOK%3Dtrue%3B%0A%20%20%20%20%20%20Serial.println(%22Config%20loaded%22)%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20%0A%20%20%20%20if%20(configOK)%0A%20%20%20%20%7B%0A%0A%20%20%20%20%20%20if%20(WiFi.status()%20!%3D%20WL_CONNECTED)%20%7B%0A%20%20%20%20%20%20%20%20WiFi.begin(WIFISSIDValue%2C%20WIFIpassword)%3B%0A%20%20%20%20%20%20%20%2F%2F%20%20WiFi.config(ip%2C%20gateway%2C%20subnet)%3B%20%2F%2FSI%20ON%20UTILISE%20LA%20CONFIG%20POUR%20ETRE%20EN%20IP%20FIXE%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%20%0A%20%20%20%20%20%20WiFi.macAddress(MAC_array)%3B%0A%20%20%20%20%20%20for%20(int%20i%20%3D%200%3B%20i%20%3C%20sizeof(MAC_array)%3B%20%2B%2Bi)%7B%0A%20%20%20%20%20%20%20%20sprintf(MAC_char%2C%22%25s%2502x%3A%22%2CMAC_char%2CMAC_array%5Bi%5D)%3B%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20Serial.println(WiFi.localIP())%3B%0A%20%20%20%20%20%20dht.begin()%3B%20%0A%20%20%20%20%20%20delay(1000)%3B%20%20%20%20%0A%20%20%20%20%7Delse%7B%0A%20%20%20%20%20%20setupWifiAP()%3B%0A%20%20%20%20%20%20Serial.println(%22Config%20not%20ok%22)%3B%0A%20%20%20%20%20%20%0A%20%20%20%20%7D%0A%20%20%0A%20%20%20%20%20retryWifi%3D0%3B%20%20%0A%20%20%20%20%20retryConnexionOk%3D0%3B%0A%20%20%20%20%20countConnexion%3D0%3B%0A%20%20%20%20%20EndCheck%3Dfalse%3B%0A%20%20%20%20%20ToReboot%3Dfalse%3B%0A%0A%7D » message= »La fonction de configuration » highlight= » » provider= »manual »/]

[pastacode lang= »c » manual= »%0Avoid%20loop()%20%0A%7B%0A%20%20%20server.handleClient()%3B%0A%20%20%20if%20(ToReboot)%0A%20%20%20%7B%0A%20%20%20%20%20ESP.restart()%3B%0A%20%20%20%7D%0A%0A%20%20%20if%20(!EndCheck)%0A%20%20%20%7B%0A%20%20%20%20%20if%20(WiFi.status()%20!%3D%20WL_CONNECTED)%20%0A%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20countConnexion%3D0%3B%0A%20%20%20%20%20%20%20%20if%20(retryWifi%20%3C40)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20delay(500)%3B%0A%20%20%20%20%20%20%20%20%20%20retryWifi%2B%2B%3B%0A%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%7Delse%7B%0A%20%20%20%20%20%20%20%20%20%20EndCheck%3Dtrue%3B%0A%20%20%20%20%20%20%20%20%20%20PowerDown()%3B%0A%20%20%20%20%20%20%20%20%20%20setupWifiAP()%3B%0A%20%20%20%20%20%20%20%20%20%20serverWebCfg()%3B%0A%20%20%20%20%20%20%20%20%20%20Serial.println(%22d%C3%A9lai%20d%C3%A9pass%C3%A9%22)%3B%20%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%7Delse%7B%0A%20%20%20%20%20%20%20%20%20connexionOK%3Dtrue%3B%0A%20%20%20%20%20%20%20%20%20EndCheck%3Dtrue%3B%0A%20%20%20%20%20%20%20%20%20serverWebCfg()%3B%0A%20%20%20%20%20%20%20%20Serial.println(%22Connexion%20OK%22)%3B%20%0A%20%20%20%20%20%20%7D%0A%20%20%20%7D%0A%20%20%20%20%20%0A%20%20%20%20%0A%20%20%20if%20((connexionOK)%20%26%26%20(countConnexion%3D%3D0))%0A%20%20%20%7B%0A%0A%20%20%20%20%20%20%20float%20humidity%2C%20temp%2C%20tension%3B%20%20%20%0A%20%20%20%20%20%20%20%20for%20(int%20i%20%3D%200%3B%20i%20%3C%203%3B%20%2B%2Bi)%7B%0A%20%20%20%20%20%20%20%20%20%20humidity%20%3D%20dht.readHumidity()%3B%20%20%20%20%20%20%20%20%20%20%2F%2F%20Read%20humidity%20(percent)%0A%20%20%20%20%20%20%20%20%20%20temp%20%3D%20dht.readTemperature()%3B%20%20%0A%20%20%20%20%20%20%20%20%20%20tension%3DreadADC_avg()%3B%0A%20%20%20%20%20%20%20%20%20%20Serial.print(%22temp%3A%22)%3B%0A%20%20%20%20%20%20%20%20%20%20Serial.print(temp)%3B%0A%20%20%20%20%20%20%20%20%20%20Serial.print(%22hum%3A%22)%3B%0A%20%20%20%20%20%20%20%20%20%20Serial.print(humidity)%3B%0A%20%20%20%20%20%20%20%20%20%20if%20(String(temp)!%3D%22nan%22)%0A%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20break%3B%20%20%0A%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20delay(1000)%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20if%20(retryConnexionOk%3C3)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20connexionOK%3Dfalse%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20HTTPClient%20http%3B%0A%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20configure%20traged%20server%20and%20url%0A%20%20%20%20%20%20%20%20%20%20%20%20http.begin(urlServer)%3B%20%2F%2FHTTP%0A%20%20%20%20%20%20%20%20%20%20%20%20Serial.print(%22%5BHTTP%5D%20begin…%5Cn%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2FSerial.print(urlServer)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20if%20((HTTPUser%20!%3D%20%22%22)%20%7C%7C%20(HTTPPass%20!%3D%20%22%22))%0A%20%20%20%20%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20http.setAuthorization(HTTPUser%2C%20HTTPPass)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20Serial.print(%22%5BHTTP%5D%20GET…%5Cn%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20start%20connection%20and%20send%20HTTP%20header%0A%20%20%20%20%20%20%20%20%20%20%20%20http.addHeader(%22Content-Type%22%2C%20%22application%2Fx-www-form-urlencoded%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20int%20httpCode%20%3D%20http.POST(%22id%3D%22%2BString(MAC_char)%2B%22%26temp%3D%22%2BString(temp)%2B%22%26hum%3D%22%2BString(humidity)%2B%22%26v%3D%22%2BString(tension))%3B%0A%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20httpCode%20will%20be%20negative%20on%20error%0A%20%20%20%20%20%20%20%20%20%20%20%20if(httpCode%20%3E%200)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20if(httpCode%20%3D%3D%20HTTP_CODE_OK)%20%7B%0A%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20Serial.println(%22HTTP%20OK%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20PowerDown()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%20else%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20Serial.println(%22HTTP%20NOK%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20PowerDown()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%2F%2F%20Serial.printf(%22%5BHTTP%5D%20GET…%20failed%2C%20error%3A%20%25s%5Cn%22%2C%20http.errorToString(httpCode).c_str())%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%20%20http.end()%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20retryConnexionOk%2B%2B%3B%0A%20%20%20%20%20%20%20%20%7Delse%7B%0A%20%20%20%20%20%20%20%20%20%20PowerDown()%3B%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20countConnexion%2B%2B%3B%0A%20%20%20%20%7D%0A%0A%20%20%20%20cmdComplete%3Dfalse%3B%0A%20%20%20%20while%20(Serial.available()%3E0%20%26%26%20cmdComplete%20%3D%3Dfalse)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20%20char%20car%3B%0A%20%20%20%20%20%20%20%20car%3DSerial.read()%3B%0A%20%20%20%20%20%20%20%20if%20(car%3D%3D0x02)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20SerialCMD%3D%22%22%3B%0A%20%20%20%20%20%20%20%20%7Delse%20if%20(car%3D%3D0x03)%0A%20%20%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20%20cmdComplete%3Dtrue%3B%0A%20%20%20%20%20%20%20%20%7Delse%7B%0A%20%20%20%20%20%20%20%20%20%20%20SerialCMD%20%2B%3Dcar%3B%0A%20%20%20%20%20%20%20%20%7D%20%20%20%20%20%0A%20%20%20%20%7D%0A%0A%20%20%20%20if%20(cmdComplete)%0A%20%20%20%20%7B%0A%20%20%20%20%20%20cmdComplete%3Dfalse%3B%0A%20%20%20%20%20%20if%20(SerialCMD%3D%3D%22reset%22)%0A%20%20%20%20%20%20%7B%0A%20%20%20%20%20%20%20%20%20ESP.restart()%3B%0A%20%20%20%20%20%20%7Delse%20if%20(SerialCMD%3D%3D%22loadconfig%22)%0A%20%20%20%20%20%20%7B%20%20%0A%20%20%20%20%20%20%20%20Serial.print(wificonfig)%3B%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20else%7B%0A%20%20%20%20%20%20%20%20StaticJsonBuffer%3C512%3E%20jsonBuffer%3B%0A%20%20%20%20%20%20%20%20JsonObject%26%20json%20%3D%20jsonBuffer.parseObject(SerialCMD)%3B%0A%20%20%20%20%20%20%20%20if%20(!json.success())%20%7B%0A%20%20%20%20%20%20%20%20%20%20Serial.println(%22Failed%20to%20parse%20config%20file%22)%3B%0A%20%20%20%20%20%20%20%20%7Delse%7B%0A%20%20%20%20%20%20%20%20%20%20Serial.println(%22OK%22)%3B%0A%20%20%20%20%20%20%20%20%20%20File%20configFile%20%3D%20SPIFFS.open(%22%2Fconfig.json%22%2C%20%22w%22)%3B%0A%20%20%20%20%20%20%20%20%20%20if%20(!configFile)%20%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20Serial.println(%22Failed%20to%20open%20config%20file%20for%20writing%22)%3B%0A%20%20%20%20%20%20%20%20%20%20%7Delse%7B%0A%20%20%20%20%20%20%20%20%20%20%20%20json.printTo(configFile)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20delay(2000)%3B%0A%20%20%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%20%20%20%20%0A%20%20%20%20%20%20%20%20%7D%0A%20%20%20%20%20%20%7D%0A%20%20%20%20%7D%0A%7D » message= »Boucle principale » highlight= » » provider= »manual »/]

Le code précédent est destiné au capteur de type DHTXX. il est encore en mode debug (crade) mais il va évoluer rapidement quand j’aurai fini tous les tests fonctionnels. D’ailleurs en enlevant les écritures sur la COM à 9600bauds, je risque de gagner du temps en mode éveillé et d’économiser de la batterie.

Vous pourrez retrouver toutes les nouvelles versions sur :

Télécharger le code Arduino

Plugin Jeedom

Ça y est, mon capteur communique. Il ne reste plus qu’à développer un petit plugin Jeedom pour l’intégrer à ma domotique. Comme pour le plugin sur la domobase et parce que j’aime bien apprendre par l’exemple, je suis parti d’un plugin déjà existant. Celui du capteur virtuel.

Dans un premier temps, j’ai développé le plugin en mode synchronisé. C’est à dire que dès que le capteur envoie ses données, je traite les informations directement à réception. Mais je me suis rendu compte que le temps de traitement rallongeait de quelques secondes « l’état éveillé » de mon capteur. (du coup, une consommation plus importante). Je suis donc passé à une autre méthode.

J’ai corrigé mon code pour passer en mode désynchronisé. Désormais, lorsque mon capteur envoie les données, je les stocke dans un fichier (un fichier par capteur) sous format JSON. Jeedom viendra analyser les données dans un second temps pour les enregistrer.

Exemple de données en JSON collectées:

{"Temperature":"2.90","Humidity":"77.42","Pression":"998.33","Tension":"2.86"}

Le traitement des données est plus rapide (simple écriture dans un fichier), le capteur se rendort plus rapidement et je gagne en consommation d’énergie.

Ne maitrisant pas encore tous les rouages de Jeedom, n’hésitez pas à me donner des conseils sur une meilleure utilisation des plugins. Je dois dire que la documentation est assez restreinte ou alors je ne sais pas chercher où il faut …

Voici à quoi ressemble l’affichage des capteurs dans Jeedom :

Affichage des mesures de capteurs ESPIOT dans Jeedom

jeedom_pluginsListe des plugins dans mon Jeedom

jeedom_plugin_espiotListe de mes capteurs ESPIOT

jeedom_plugin_espiot_generaljeedom_plugin_espiot_commandesConfiguration d’un capteur ESPIOT

La configuration d’un capteur est très simple : il suffit de donner un nom au capteur puis de rentrer son adresse MAC. Les commandes sont normalement créées. Si ce n’est pas le cas, les noms de commandes sont:

  • Temperature
  • Humidity
  • Tension
  • Pression (uniquement pour le BME280)

Téléchargement du plugin Jeedom

Conclusion

Enfin, cette partie signe la fin du projet de mon capteur température/humidité/(pression) sur pile communiquant en WiFi. J’avais vraiment à cœur de réussir un objet abouti. Ce projet m’a permis de jouer avec plein de concept, allant de l’électronique jusqu’à de la mécanique en passant par du logiciel embarqué et du logiciel  » haut niveau ».

J’ai déjà en tête plein de points d’amélioration, mais je vais laisser vivre pendant un petit moment le projet pour me consacrer à d’autres projets tout aussi intéressant. J’espère obtenir de votre part des retours sur mon travail, des critiques (constructives), des remarques…. bref avoir une interaction avec vous. C’est ce que j’attends de ce genre de projet partagé sur le web. Je pense que c’est le meilleur moyen de progresser.

Une fois toutes les remarques synthétisée, j’appliquerai certaines modifications pour que le capteur soit optimisé. Je mettrai, bien entendu, les modifications sur mon Github.

Les tests que j’ai effectué sont déjà prometteurs sur la durée :

jeedom_espiot_stats

Historiques des mesures de température

Cela fait déjà un peu plus de 3mois que le capteur envoie des données sans interruption. La consommation d’énergie suit les prédictions théoriques. La tension des piles est de 3.99v. Y a encore plein d’énergies !!!

Vous avez été nombreux à visiter et parcourir ce projet et je vous en remercie. Voici le fil d’Ariane de tout le projet :

Lien github

 

Click to rate this post!
[Total: 16 Average: 3.5]

4 comments

  1. Bonjorur,

    je suis stupéfait de votre développement. Pourquoi ne pas avoir utilisé le logiciel ESP easy?
    Est-ce que vous vendez ce capteur ?
    Si oui, je suis intéressé.

    Merci

  2. Bonjour

    J’adore votre capteur, c’est exactement ce que je recherche mais je pense que je n’ai pas les compétences et le matériels pour le fabriquer.
    Est ce que vous en vendez?

    Cordialement et bravo

  3. Bonjour,
    Joli boulot, que ce soit sur ce projet ou les autres !

    J’avais réalisé un projet un peu similaire, bien que moins bien abouti (réalisé sur des breadboard), et j’ai commencé à regarder pour le rendre 100% autonome, notamment en essayant de recharger la pile via des petites cellules photovoltaïques (on en trouve pour pas trop cher). Est-ce un sujet sur lequel vous avez déjà travaillé ? Je me pose des questions sur la viabilité de la chose…
    Merci et encore bravo

  4. bonsoir,
    j’ai 70 ans et ne vais pas reinventer la poudre.
    Vous avez fait un travail magnifique.
    comme les messages precedents, peut-on acheter ces capteurs?
    cordialement

Leave a Reply

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.