/* * WeMos ioBroker Basis Sketch V 1.0.0 * * verbindet sich mit dem vorhandenen WLAN als Server * und schreibt die Daten in ioBroker Datenpunkte * * Auf Seite ioBroker muss der Adapter "simpleAPI" installiert und aktiv sein * * ioBroker Skript zum Anlegen der notwendigen Datenpunkte: xxxxxx.js (V1.0.0) * * Skript von ruhr70 * * Inspieriert von: * eric2905 (Anpassung seines Basis-Skripts für Weomos -> ioBroker) * http://homematic-forum.de/forum/viewtopic.php?f=31&t=29321 * http://www.renmet.com/wiki/index.php?title=Hauptseite * * Ausgabe: * - Zugriff per Browser auf die IP des Wemos * - Datenpunkte in ioBroker * - Serieller Monitor in der Arduino IDE * * Steuerung über HTTP-Befehle: * "/heartbeat?sets=" Schaltet den Heartbeat ein/aus (true/false) * * * Bedeutung der WiFi.status() Meldungen * * 3 WL_CONNECTED // assigned when connected to a WiFi network; * 255 WL_NO_SHIELD // assigned when no WiFi shield is present; * 0 WL_IDLE_STATUS // it is a temporary status assigned when WiFi.begin() is called and remains active until the number of attempts expires (resulting in WL_CONNECT_FAILED) or a connection is established (resulting in WL_CONNECTED); * 1 WL_NO_SSID_AVAIL // assigned when no SSID are available; * 2 WL_SCAN_COMPLETED // assigned when the scan networks is completed; * 4 WL_CONNECT_FAILED // assigned when the connection fails for all the attempts; * 5 WL_CONNECTION_LOST// assigned when the connection is lost; * 6 WL_DISCONNECTED * */ # define WM_IO_version "v1.0.0" // Version des Skripts (Ausgabe seriell und auf der Webseite) # define WM_IO_skriptname "ioBroker Basissketch" // Name des Skripts (Ausgabe seriell und auf der Webseite) # define WM_IO_device_name "51" // Name des Wemosgeräts (für die ioBroker Datenpunkte) # define WM_IO_WLAN_ssid "nix Verloren" // ssid des WLANs # define WM_IO_WLAN_password "********" // Passwort des WLANs # define WM_IO_iobroker_host "192.168.178.3" // IP oder FQDN von ioBroker # define WM_IO_iobroker_port 8087 // ioBroker Portnummer Simple-API-Adapter # define WM_IO_serial_speed 115200 // Geschwindigkeit der seriellen Ausgabe (serieller Monitor in der IDE) # define WM_IO_heartbead_LED D4 // LED, die für den Heartbeat verwendet wird (D4 ist mit der internen LED verbunden) # define WM_IO_heartbeat_on true // Heartbeat on (keine WLAN Verbindung wird auch bei on:false signalisiert) #include // https://github.com/ekstrand/ESP8266wifi #include // Webserver // Bibliotheken für Sensoren und Anschaltungen // #include // für Geräte, die den I2C-Bus verwenden (https://www.arduino.cc/en/Reference/Wire / http://html.szaktilla.de/arduino/6.html) // ******* Wartezeit in Sekunden zwischen 2 Messungen/Vorgängen, bitte anpassen! ******* unsigned long deltaMessungSekunden = 60; // Intervall für Messungen unsigned long deltaSysinfosSekunden = 5 * 60; // Intervall, in dem rssi und uptime an ioBroker übertragen wird unsigned long deltaHeartbeatMillisOK = 3000; // Heartbeat-Intervall bei WIFI Verbindung unsigned long deltaHeartbeatMillisError = 1000; // Heartbeat-Intervall keine WLAN Verbindung // ******* Netzwerkeinstellungen, bitte anpassen! ******* const char* ssid = WM_IO_WLAN_ssid; // SSID des vorhandenen WLANs const char* password = WM_IO_WLAN_password; // Passwort für das vorhandene WLAN // wenn nicht DHCP genutzt werden soll, sondern eine feste IP (siehe auch im Setup): //IPAddress gateway(192,168,178,1); // IP-Adresse des WLAN-Gateways //IPAddress subnet(255,255,255,0); // Subnetzmaske //IPAddress ip(192,168,178,180); // feste IP-Adresse für den WeMos // ******* ioBroker ******* // host als FQDN *ODER* IP angeben: //const char* host = "iobroker.fritz.box"; // FQDN des ioBroker-Servers const char* host = WM_IO_iobroker_host; // IP des ioBroker-Servers const int httpPort = WM_IO_iobroker_port; //Port des simpleAPI-Adapters in ioBroker ESP8266WebServer server(80); // Webserver des Wemos (ESP8266WebServer.h) initialisieren auf Port 80 // Geschwindigkeit für die serielle Ausgabe (Serieller Monitor) const unsigned int serialSpeed = WM_IO_serial_speed; // =========== Einstellungen fuer Meldungen an ioBoker, bitte anpassen! ******* // Pfad + Gerät + Datenpunkte müssen in ioBroker angelegt sein!! // das ioBroker Skript xxxx.js legt die Datenpunkte an const String ioBrokerBasisPath = "javascript.0.Wemos."; // Basispfad zum Datenpunkt in ioBroker const String ioBrokerDevice = "Device." WM_IO_device_name "."; // Gerätename in ioBroker (alle Geräte sollten mit "Device." beginnen) // Datenpunkte für die Wemos Systeminfos const String dpNameIoBrokerLastStart = "last_start"; // im Basis Pfad für alle Wemos Geräte identisch // Datenpunkte: Individuelle Wemos Systeminfos const String dpNameIoBrokerRssi = "Systeminfo.rssi"; const String dpNameIoBrokerUptime = "Systeminfo.uptime"; const String dpNameIoBrokerSsid = "Systeminfo.ssid"; const String dpNameIoBrokerWemosIp = "Systeminfo.ip"; const String dpNameIoBrokerWemosMac = "Systeminfo.mac"; // Datenpunkte für die Messwerte const String dpNameIoBrokerDemo1 = "WemosDemo1"; // Bezeichnung des ioBroker-Datenpunktes 1 für die gemessene Temperatur const String dpNameIoBrokerDemo2 = "WemosDemo2"; // Bezeichnung des ioBroker-Datenpunktes 2 für die gemessene Temperatur // Variablen alte Werte für die Messpunkte (für den Vergleich: "nur bei Änderung übermitteln) String ioBrokerDemo1ValueAlt = ""; String ioBrokerDemo2ValueAlt = ""; // ******* Heartbeat ******* boolean heartbeatOn = true; // true - Heartbeat über LED einschalten // =========== Allg. Variablen - nicht anfassen ;-) !!! ******* unsigned long intervallLastMillis[] = {0,0,0,0,0}; // max. 5 Intervalle (0-4) byte wifiLastStatus =0; // globale Variable mit der Mac-Adresse des WLAN-Moduls char MAC_char[18]; // Kommando an ioBroker und Rückantwort String ioBrokerSimpleApiCommand = ""; String ioBrokerSimpleApiAntwort = ""; // Zeitstempel (uptime) für Debug-Ausgabe berechnen // ======================================================================= // nach ca. 49,6 Tagen erfolgt ein Überlauf und der Zeitstempel fängt wieder bei 0 an String zeitstempel() { // Betriebszeit als Stunde:Minute:Sekunde char stempel[10]; int lfdStunden = millis()/3600000; int lfdMinuten = millis()/60000-lfdStunden*60; int lfdSekunden = millis()/1000-lfdStunden*3600-lfdMinuten*60; sprintf (stempel,"%03d:%02d:%02d", lfdStunden, lfdMinuten, lfdSekunden); return stempel; } // =========== IP-Adresse ermitteln ******* String myIp() { char myIpString[24]; IPAddress myIp = WiFi.localIP(); sprintf(myIpString, "%d.%d.%d.%d", myIp[0], myIp[1], myIp[2], myIp[3]); return myIpString; } // =========== MAC-Adresse ermitteln ******* // See more at: http://www.esp8266.com/viewtopic.php?f=29&t=3587#sthash.QMfjHXQH.dpuf void myMac() { uint8_t MAC_array[6]; // MAC-Adresse ermitteln und ausgeben WiFi.macAddress(MAC_array); // die 6 Byte der MAC-Adresse auselsen und in ein Array schreiben for (int i = 0; i < sizeof(MAC_array); ++i){ sprintf(MAC_char,"%s%02x:",MAC_char,MAC_array[i]); } MAC_char[strlen(MAC_char)-1] = '\0'; // letztes Zeichen ":" kürzen //MAC_char[strlen(MAC_char)-1] = 0; // letztes Zeichen ":" kürzen // MAC-Adresse steht in der globalen Variable: MAC_char } // =========== Meldestring an ioBroker beim Start - hallo hier bin ich (Last Start) ******* String lastStart() { String lastStartString = "[\"" + myIp() + "\",\"" + MAC_char + "\",\"" + zeitstempel() + "\"]"; //String lastStartString = "[\"" + myIp() + "\",\"" + myMac() + "\",\"" + zeitstempel() + "\"]"; return lastStartString; } // ===== wandelt bool in true/false String um ===== String logikBool2Str(boolean logikBool) { String logikStr = "true"; if(!logikBool) {logikStr = "false";} return logikStr; } // =========== Intervalle ******* boolean intervall(byte intervallArr, int millisekunden) { if(millis() - intervallLastMillis[intervallArr] > millisekunden) { intervallLastMillis[intervallArr] = millis(); return true; } return false; } void heartbeatIntervall() { unsigned long intervall3 = deltaHeartbeatMillisOK; if(WiFi.status() != WL_CONNECTED) { intervall3 = deltaHeartbeatMillisError; } else { if(wifiLastStatus != WiFi.status()) { delay(200); melde_ioBroker(dpNameIoBrokerLastStart, lastStart()); // Hallo ioBroker, hier bin ich. Wemos aktiv und gestartet. } } wifiLastStatus = WiFi.status(); if(intervall(3, intervall3)) { // Heartbeat if(heartbeatOn || (WiFi.status() != WL_CONNECTED)) { // Heartbeat über LED, wenn eingeschaltet ODER WLAN Verbindung verloren digitalWrite(WM_IO_heartbead_LED, 0); delay(50); digitalWrite(WM_IO_heartbead_LED, 1); if(WiFi.status() != WL_CONNECTED) { Serial.print("."); Serial.print(WiFi.status()); } } } } // =========== Webserver ******* void homepage() { // bei Aufruf des Root-Verzeichnisses String betriebszeit = zeitstempel(); String antwort = ""; int rssi = WiFi.RSSI(); antwort = "WeMos \t" WM_IO_skriptname " (" WM_IO_version ")"; antwort = antwort + "\n\n"; antwort = antwort + "\tBetriebszeit: " + betriebszeit + " (Std:Min:Sek)\n"; antwort = antwort + "\tVerbunden mit: " + ssid + "\n"; antwort = antwort + "\tSignalstaerke: " + String(rssi) + " dBm\n"; antwort = antwort + "\tIP: " + myIp() + "\n"; antwort = antwort + "\tMAC: " + MAC_char; antwort = antwort + "\n\n"; antwort = antwort + "ioBroker: \n"; antwort = antwort + "\tIP: " + host + "\tPort: " + httpPort; antwort = antwort + "\n\n"; antwort = antwort + "Systemparameter: \n"; antwort = antwort + "\tCOM-Port: "+ serialSpeed + " Baud\n"; antwort = antwort + "\tIntervall: "+ deltaMessungSekunden + " Sek.\n"; antwort = antwort + "\tHeartbeat LED: "+ logikBool2Str(heartbeatOn); antwort = antwort + "\n\n"; antwort = antwort + "HTTP-Befehlsuebersicht:\n\n"; antwort = antwort + "\thttp://"+myIp()+"/heartbeat?set=\n\t\tSchaltet den LED Heartbeat ein/aus. ( = true/false)\n"; antwort = antwort + "\n\n"; antwort = antwort + "Letzes Kommando an ioBroker:\n"; antwort = antwort + "\t" + ioBrokerSimpleApiCommand; antwort = antwort + "\n\n"; antwort = antwort + "Letzte Antwort ioBroker: \n\n" + ioBrokerSimpleApiAntwort; server.send(300, "text/plain", antwort); delay(150); Serial.println(zeitstempel() + " unspezifische HTTP-Anfrage (Root-Verzeichnis) an den Wemos"); } void webSetHeartbeat() { // bei Aufruf von ".../heartbeat" String set = server.arg("set"); if((set == "true") || (set == "1")) { heartbeatOn = true; server.send(200, "text/plain", "Heartbeat ist eingeschaltet"); delay(100); Serial.println(zeitstempel() + " Heartbeat ist eingeschaltt"); } else if((set == "false") || (set == "0")) { heartbeatOn = false; server.send(200, "text/plain", "Heartbeat ist ausgeschaltet"); delay(100); Serial.println(zeitstempel() + " Heartbeat ist ausgeschaltt"); } else { server.send(200, "text/plain", "ungueltiger Aufruf. /heartbeat?set= \t = true/false"); delay(100); Serial.println(zeitstempel() + " ungueltiger Aufruf. /heartbeat?set="); } } // Melderoutine an ioBroker // ======================================================================= // &prettyPrint sorgt für die Rückmeldung des JSON in mehren Zeilen // https://github.com/ioBroker/ioBroker.simple-api/blob/master/README.md#set void melde_ioBroker(String datenpunktName, String wert) { String dp = ioBrokerBasisPath + ioBrokerDevice + datenpunktName; if (datenpunktName == dpNameIoBrokerLastStart) { dp = ioBrokerBasisPath + datenpunktName; // "Hallo ioBroker hier bin ich" -> Datenpunkt deviceunabhängig } ioBrokerSimpleApiAntwort = ""; // globale Variale für die Rückantwort von ioBroker Serial.println("\n\n" + zeitstempel() + " <- melde_ioBroker Start\n"); WiFiClient client; // Webclient initialisieren if (!client.connect(host, httpPort)) { // mit dem CCU-Port verbinden Serial.println(zeitstempel() + " Fehler: Verbindung zum ioBroker konnte nicht aufgebaut werden (Eric2905)"); ioBrokerSimpleApiAntwort = zeitstempel() + " Fehler: Verbindung zum ioBroker konnte nicht aufgebaut werden"; delay(100); return; } String meldung = "GET /set/" + dp + "?value=" + wert + "&prettyPrint HTTP/1.1"; Serial.println(meldung); client.println(meldung); ioBrokerSimpleApiCommand = zeitstempel() + ": " + meldung; client.println(); delay(1000); Serial.println(); ioBrokerSimpleApiAntwort = "\t"+zeitstempel() + ":\n"; while(client.available()){ // Antwort des ioBrokers zeilenweise auslesen String zeile = ""; zeile = client.readStringUntil('\n'); Serial.println(zeile); ioBrokerSimpleApiAntwort = ioBrokerSimpleApiAntwort + "\t" + zeile + "\n"; } Serial.println(); Serial.println(zeitstempel() + " Werte an ioBroker gemeldet --> "); } // regelmässige Systeminfos an ioBroker (RSSI und uptime) // ======================================================================= void systeminfos() { int rssi = WiFi.RSSI(); String uptime = zeitstempel(); char tmp[10]; dtostrf(rssi, 1/*minStringWidthIncDecimalPoint*/, 0/*numVarsAfterDecimal*/, tmp); String rssiStr = tmp; melde_ioBroker(dpNameIoBrokerRssi , rssiStr); melde_ioBroker(dpNameIoBrokerUptime , uptime); } // Mess-Routine // ======================================================================= // ausgabe = 0 // Messung wird nur ausgegeben, wenn eine Änderung der Messwerte erfolgte // ausgabe = 1 // Messung wird immer ausgegeben, auch wenn die Messwerte gleich geblieben sind // alles Messwerte werden als String an ioBroker übermittelt und müssen vor dem Aufruf // der Funktion melde_ioBroker in einen String gewandelt werden. void messung(boolean ausgabe) { //Hier kommt dann der Mess-Code rein (oder die echten Messwerte) float ioBrokerDemo1Value = 123; float ioBrokerDemo2Value = 456; // Umwandlung float in String char tmp[10]; dtostrf(ioBrokerDemo1Value, 1/*minStringWidthIncDecimalPoint*/, 2/*numVarsAfterDecimal*/, tmp); String out1 = tmp; dtostrf(ioBrokerDemo2Value, 1/*minStringWidthIncDecimalPoint*/, 2/*numVarsAfterDecimal*/, tmp); String out2 = tmp; // Messwerte schreiben, wenn sich der Wert geändert hat if ((out1 != ioBrokerDemo1ValueAlt) || (ausgabe == 1)) { melde_ioBroker(dpNameIoBrokerDemo1,out1); ioBrokerDemo1ValueAlt = out1; } if ((out2 != ioBrokerDemo2ValueAlt) || (ausgabe == 1)) { melde_ioBroker(dpNameIoBrokerDemo2,out2); ioBrokerDemo2ValueAlt = out2; } } // ======================================================================= // setup() - Setup-Routine // ======================================================================= void setup() { // Heartbeat pinMode(WM_IO_heartbead_LED, OUTPUT); // Pin "WM_IO_heartbead_LED" wird als Output definiert, die interne LED ist mit D4 "fest verdrahtet" digitalWrite(WM_IO_heartbead_LED, 1); // 1 = LED aus // Seriellen Monitor für Kontrollausgaben öffnen Serial.begin(serialSpeed); // initialize serial (Geschwindigkeit in der Variable "serialSpeed") delay(10); Serial.println(""); Serial.println("WeMos - " WM_IO_skriptname " (" WM_IO_version ")"); Serial.println(""); // WLAN-Verbindung herstellen //WiFi.config(ip, gateway, subnet); // auskommentieren, falls eine dynamische IP bezogen werden soll WiFi.begin(ssid, password); Serial.println("Verbindungsaufbau zur ssid: " WM_IO_WLAN_ssid); Serial.println(""); Serial.print(zeitstempel() + " "); myMac(); // Mac-Adresse ermitteln und in die globale Variable "MAC_char" schreiben // Verbindungsaufbau abwarten while (WiFi.status() != WL_CONNECTED) { heartbeatIntervall(); //delay(500); //Serial.print("."); } wifiLastStatus = WiFi.status(); // WLAN verbunden, weiter im setup() // Ausgaben im seriellen Monitor Serial.println(""); Serial.println(zeitstempel() + " erfolgreich!"); Serial.println(""); Serial.println("Verbunden mit: " WM_IO_WLAN_ssid); //Serial.println(ssid); Serial.print("Signalstaerke: "); int rssi = WiFi.RSSI(); Serial.print(rssi); Serial.println(" dBm"); Serial.print("IP-Adresse: "); Serial.print(WiFi.localIP()); Serial.println(""); Serial.print("MAC-Adresse: "); Serial.println(MAC_char); Serial.println(""); // HTTP-Anfragen bearbeiten server.on("/" , homepage); server.on("/heartbeat", webSetHeartbeat); // HTTP-Server starten server.begin(); Serial.println(zeitstempel() + " HTTP-Server gestartet"); // WLAN-/Systeminfos an ioBroker übermitteln (Datenpunkte müssen in ioBroker angelegt sein) melde_ioBroker(dpNameIoBrokerLastStart, lastStart()); // Hallo ioBroker, hier bin ich. Wemos aktiv und gestartet. systeminfos(); // uptime und rssi melde_ioBroker(dpNameIoBrokerSsid , ssid); // ssid melde_ioBroker(dpNameIoBrokerWemosIp, myIp()); // ip melde_ioBroker(dpNameIoBrokerWemosMac, MAC_char); } // ======================================================================= // loop() - Schleife, die immer wieder durchlaufen wird // ======================================================================= void loop() { server.handleClient(); // auf HTTP-Anfragen warten // kontinuierliche Überprüfung der Messwerte, Ausgabe nur bei Änderung messung(0); // 0 = Ausgabe der Messwerte nur bei Änderung, 1 = AUsgabe des Messwerts bei jedem Aufruf (1 ist nur im Intervall sinnvoll) // Intervall 0: Messintervall - Verarbeiten wenn Zeitintervall erreicht if(intervall(0,deltaMessungSekunden * 1000)) { // alle "deltaMessungSekunden" Sekunden Serial.print("\nMess-Zeitpunkt : "); Serial.println(zeitstempel()); //messung(1); // wenn zyklisch zusätzlich immer Werte ausgegeben werden sollen -> 1 = Ausgabe der Messwerte, auch wenn die Werte sich nicht geändert haben } // Ende Zeitintervall 0 // Intervall 1: Systemmeldungen an ioBroker - Verarbeiten wenn Zeitintervall erreicht if(intervall(1, deltaSysinfosSekunden * 1000)) { systeminfos(); } // Intervall 2: Verarbeiten wenn Zeitintervall erreicht // Reserve if(intervall(2, 1 * 1000)) { // jede Sekunde Serial.print("."); // Reserve - Beispiel } // Intervall 3: Heartbeat - Verarbeiten wenn Zeitintervall erreicht heartbeatIntervall(); // Intervall 4: Reserve - Verarbeiten wenn Zeitintervall erreicht // Reserve if(intervall(4, 5 * 1000)) { Serial.print(WiFi.status()); } }