Преглед изворни кода

Code nach Funktionen in mehrere source-files aufgeteilt, diverse Verbesserungen und Features hinzugekommen wie Web-Interface, OTA-Update usw.
benutzte libs mit eingecheckt

FloKra пре 6 година
родитељ
комит
78dd5fd3b8

+ 180 - 0
src/WiFiThermostat/Buttonhandling.ino

@@ -0,0 +1,180 @@
+bool plusButtonCurrentState = HIGH;
+bool plusButtonLastState = HIGH;
+unsigned long plusButtonDownMillis = 0;
+unsigned long plusButtonRepeatMillis = 0;
+unsigned long plusButtonHoldTime = 0;
+bool plusButtonFired = false;
+
+bool minusButtonCurrentState = HIGH;
+bool minusButtonLastState = HIGH;
+unsigned long minusButtonDownMillis = 0;
+unsigned long minusButtonRepeatMillis = 0;
+unsigned long minusButtonHoldTime = 0;
+bool minusButtonFired = false;
+
+bool modeButtonCurrentState = HIGH;
+bool modeButtonLastState = HIGH;
+unsigned long modeButtonDownMillis = 0;
+unsigned long modeButtonHoldTime = 0;
+bool modeButtonFired = false;
+bool modeButtonHoldFired = false;
+
+//extern bool displayActive;
+//extern void extendDisplayTimeout();
+//extern void updateDisplay();
+
+void plusButtonAction() {
+  if(heatingMode == 1 && heatingEnabled) {
+    Serial.println("+");
+    if ( setTempDay <= (setTempMax - 0.5)) setTempDay += 0.5;
+  }
+  extendDisplayTimeout();
+  updateDisplay();
+}
+
+void minusButtonAction() {
+  if(heatingMode == 1 && heatingEnabled) {
+    Serial.println("-");
+    if ( setTempDay >= (setTempMin + 0.5)) setTempDay -= 0.5;
+  }
+  extendDisplayTimeout();
+  updateDisplay();
+}
+
+void modeButtonAction() {
+  extendDisplayTimeout();
+  if (heatingEnabled) {
+    Serial.print("switch mode to ");
+    if (heatingMode == 1) heatingMode = 2;
+    else if (heatingMode == 2) heatingMode = 1;
+    Serial.println(heatingMode);
+    updateDisplay();
+  }
+}
+
+void modeButtonHoldAction() {
+  Serial.println("switch off/on");
+  extendDisplayTimeout();
+  if (heatingEnabled) heatingEnabled = false;
+  else heatingEnabled = true;
+  updateDisplay();
+}
+
+void checkButtonStates() {
+  
+  // Buttons einlesen
+
+  // plus button
+  plusButtonCurrentState = digitalRead(PIN_BUTTON_PLUS);
+  if (plusButtonCurrentState == LOW && plusButtonLastState == HIGH) { // button was unpressed and is millis() pressed
+    plusButtonDownMillis = millis();
+    plusButtonLastState = plusButtonCurrentState;
+  }
+  else if (plusButtonCurrentState == LOW && plusButtonLastState == LOW) { // button is held
+    plusButtonHoldTime = millis() - plusButtonDownMillis;
+    if ( plusButtonHoldTime > 50 ) {
+      plusButtonLastState = plusButtonCurrentState;
+            if (!displayActive && !plusButtonFired ) {
+              enableDisplay();
+              plusButtonFired = true;
+            }
+      //      else if (displayActive && !plusButtonFired ) {
+      //        plusButtonAction();
+      //        plusButtonFired = true;
+      //      }
+    }
+    if ( plusButtonHoldTime > 1250 ) {
+      // button is held longer - repeating
+      if ( (millis() - plusButtonRepeatMillis) > 300 ) {
+        plusButtonAction();
+        plusButtonRepeatMillis = millis();
+      }
+    }
+  }
+  else if (plusButtonCurrentState == HIGH && plusButtonLastState == LOW) { // button is released again
+    plusButtonLastState = plusButtonCurrentState;
+    
+    if (displayActive && !plusButtonFired) {
+      plusButtonAction();
+    }
+    plusButtonFired = false;
+  }
+
+
+
+
+  // minus button
+  minusButtonCurrentState = digitalRead(PIN_BUTTON_MINUS);
+  if (minusButtonCurrentState == LOW && minusButtonLastState == HIGH) { // button was unpressed and is millis() pressed
+    minusButtonDownMillis = millis();
+    minusButtonLastState = minusButtonCurrentState;
+  }
+  else if (minusButtonCurrentState == LOW && minusButtonLastState == LOW) { // button is held
+    minusButtonHoldTime = millis() - minusButtonDownMillis;
+    if ( minusButtonHoldTime > 50 ) {
+      minusButtonLastState = minusButtonCurrentState;
+            if (!displayActive && !minusButtonFired ) {
+              enableDisplay();
+              minusButtonFired = true;
+            }
+      //      else if (displayActive && !minusButtonFired ) {
+      //        minusButtonAction();
+      //        minusButtonFired = true;
+      //      }
+    }
+    if ( minusButtonHoldTime > 1250 ) {
+      // button is held longer - repeating
+      if ( (millis() - minusButtonRepeatMillis) > 300 ) {
+        minusButtonAction();
+        minusButtonRepeatMillis = millis();
+      }
+    }
+  }
+  else if (minusButtonCurrentState == HIGH && minusButtonLastState == LOW) { // button is released again
+    minusButtonLastState = minusButtonCurrentState;
+    
+    if (displayActive && !minusButtonFired) {
+      minusButtonAction();
+    }
+    minusButtonFired = false;
+  }
+
+
+
+
+  // mode button
+  modeButtonCurrentState = digitalRead(PIN_BUTTON_MODE);
+  if (modeButtonCurrentState == LOW && modeButtonLastState == HIGH) { // button was unpressed and is millis() pressed
+    modeButtonDownMillis = millis();
+    modeButtonLastState = modeButtonCurrentState;
+  }
+  else if (modeButtonCurrentState == LOW && modeButtonLastState == LOW) { // button is held
+    modeButtonHoldTime = millis() - modeButtonDownMillis;
+    if ( modeButtonHoldTime > 50 ) {
+      modeButtonLastState = modeButtonCurrentState;
+            if (!displayActive && !modeButtonFired ) {
+              enableDisplay();
+              modeButtonFired = true;
+            }
+      //      else if (displayActive && !modeButtonFired ) {
+      //        modeButtonAction();
+      //        modeButtonFired = true;
+      //      }
+    }
+    if ( modeButtonHoldTime > 2000 && !modeButtonHoldFired ) {
+      // button is held longer
+      modeButtonHoldAction();
+      modeButtonHoldFired = true;
+    }
+  }
+  else if (modeButtonCurrentState == HIGH && modeButtonLastState == LOW) { // button is released again
+    modeButtonLastState = modeButtonCurrentState;
+    if (displayActive && !modeButtonHoldFired && !modeButtonFired) {
+      modeButtonAction();
+    }
+    modeButtonFired = false;
+    modeButtonHoldFired = false;
+  }
+
+}
+

+ 50 - 1
src/WiFiThermostat/DHT.cpp

@@ -61,6 +61,36 @@ float DHT::readTemperature(bool S, bool force) {
   return f;
 }
 
+//boolean S == Scale.  True == Fahrenheit; False == Celcius
+int DHT::readTemperatureInt(bool S, bool force) {
+  int f = NAN;
+
+  if (read(force)) {
+    switch (_type) {
+    case DHT11:
+      f = data[2];
+      if(S) {
+        f = convertCtoF(f);
+      }
+      break;
+    case DHT22:
+    case DHT21:
+      f = data[2] & 0x7F;
+      f *= 256;
+      f += data[3];
+      //f *= 0.1;
+      if (data[2] & 0x80) {
+        f *= -1;
+      }
+      if(S) {
+        f = convertCtoF(f);
+      }
+      break;
+    }
+  }
+  return f;
+}
+
 float DHT::convertCtoF(float c) {
   return c * 1.8 + 32;
 }
@@ -88,6 +118,25 @@ float DHT::readHumidity(bool force) {
   return f;
 }
 
+int DHT::readHumidityInt(bool force) {
+  int f = NAN;
+  if (read()) {
+    switch (_type) {
+    case DHT11:
+      f = data[0];
+      break;
+    case DHT22:
+    case DHT21:
+      f = data[0];
+      f *= 256;
+      f += data[1];
+      //f *= 0.1;
+      break;
+    }
+  }
+  return f;
+}
+
 //boolean isFahrenheit: True == Fahrenheit; False == Celcius
 float DHT::computeHeatIndex(float temperature, float percentHumidity, bool isFahrenheit) {
   // Using both Rothfusz and Steadman's equations
@@ -256,4 +305,4 @@ uint32_t DHT::expectPulse(bool level) {
   #endif
 
   return count;
-}
+}

+ 3 - 1
src/WiFiThermostat/DHT.h

@@ -40,10 +40,12 @@ class DHT {
    DHT(uint8_t pin, uint8_t type, uint8_t count=6);
    void begin(void);
    float readTemperature(bool S=false, bool force=false);
+   int readTemperatureInt(bool S=false, bool force=false);
    float convertCtoF(float);
    float convertFtoC(float);
    float computeHeatIndex(float temperature, float percentHumidity, bool isFahrenheit=true);
    float readHumidity(bool force=false);
+   int readHumidityInt(bool force=false);
    boolean read(bool force=false);
 
  private:
@@ -72,4 +74,4 @@ class InterruptLock {
 
 };
 
-#endif
+#endif

+ 59 - 0
src/WiFiThermostat/Display.ino

@@ -0,0 +1,59 @@
+// LCD
+byte customCharSun[8] = {0b00100, 0b10001, 0b01110, 0b11111, 0b11111, 0b01110, 0b10001, 0b00100};
+byte customCharMoon[8] = {0b11000, 0b01110, 0b00110, 0b00111, 0b00111, 0b00110, 0b01110, 0b11000};
+byte customCharArrowRight[8] = {0b00000, 0b00100, 0b00110, 0b11111, 0b11111, 0b00110, 0b00100, 0b00000};
+//bool displayActive = false;
+unsigned long displayLastOnMillis = 0;
+
+//extern long lastDisplayUpdate;
+
+void enableDisplay() {
+  lcd.backlight();
+  displayActive = true;
+  displayLastOnMillis = millis();
+}
+
+void disableDisplay() {
+  lcd.noBacklight();
+  displayActive = false;
+}
+
+void extendDisplayTimeout() {
+  displayLastOnMillis = millis();
+}
+
+void handleDisplayTimeout() {
+  if (displayActive && (millis() - displayLastOnMillis) > displayTimeout) {
+    disableDisplay();
+  }
+}
+
+void updateDisplay() {
+  lastDisplayUpdate = 0;
+}
+
+void initDisplay() {
+  lcd.init();
+  lcd.createChar(0, customCharMoon);
+  lcd.createChar(1, customCharSun);
+  lcd.createChar(2, customCharArrowRight);
+
+  lcd.setCursor(0, 0);
+
+  lcd.print("WiFi-Thermostat ");
+  lcd.setCursor(0, 1);
+  lcd.print("      by Flo Kra");
+
+  //  for ( int i = 0; i < 3; i++) {
+  //    lcd.backlight();
+  //    delay(200);
+  //    lcd.noBacklight();
+  //    delay(200);
+  //  }
+  lcd.backlight();
+  delay(1000);
+  ///lcd.clear();
+  displayActive = true;
+  displayLastOnMillis = millis();
+}
+

+ 158 - 0
src/WiFiThermostat/PersWiFiManager.cpp

@@ -0,0 +1,158 @@
+/* PersWiFiManager
+   version 3.0.1
+   https://r-downing.github.io/PersWiFiManager/
+*/
+
+#include "PersWiFiManager.h"
+
+//#ifdef WIFI_HTM_PROGMEM
+const char wifi_htm[] PROGMEM = R"=====(<!DOCTYPE html><html><head><meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no"/><title>ESP WiFi</title><script>function g(i){return document.getElementById(i);};function p(t,l){if(confirm(t)) window.location=l;};function E(s){return document.createElement(s)};var S="setAttribute",A="appendChild",H="innerHTML",X,wl;function scan(){if(X) return;X=new XMLHttpRequest(),wl=document.getElementById('wl');wl[H]="Scanning...";X.onreadystatechange=function(){if (this.readyState==4&&this.status==200){X=0;wl[H]="";this.responseText.split("\n").forEach(function (e){let t=e.split(","), s=t.slice(2).join(',');var d=E('div'),i=E('a'),c=E('a');i[S]('class','s'); c[S]('class','q');i.onclick=function(){g('s').value=s;g('p').focus();};i[A](document.createTextNode(s));c[H]=t[0]+"%"+(parseInt(t[1])?"\uD83D\uDD12":"\u26A0");wl[A](i); wl[A](c);wl[A](document.createElement('br'));});}};X.open("GET","wifi/list",true);X.send();};</script><style>input{padding:5px;font-size:1em;width:95%;}body{text-align:center;font-family:verdana;background-color:black;color:white;}a{color:#1fa3ec;}button{border:0;border-radius:0.3em;background-color:#1fa3ec;color:#fff;line-height:2.4em;font-size:1.2em;width:100%;display:block;}.q{float:right;}.s{display:inline-block;width:14em;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}#wl{line-height:1.5em;}</style></head><body><div style='text-align:left;display:inline-block;width:320px;padding:5px'><button onclick="scan()">&#x21bb; Scan</button><p id='wl'></p><form method='post' action='/wifi/connect'><input id='s' name='n' length=32 placeholder='SSID'><br><input id='p' name='p' length=64 type='password' placeholder='password'><br><br><button type='submit'>Connect</button></form><br><br><button onclick="p('Start WPS?','/wifi/wps')">WPS Setup</button><br><button onclick="p('Reboot device?','/wifi/rst')">Reboot</button><br><a href="/">Home</a></div></body></html>)=====";
+//#endif
+
+PersWiFiManager::PersWiFiManager(ESP8266WebServer& s, DNSServer& d) {
+  _server = &s;
+  _dnsServer = &d;
+  _apPass = "";
+} //PersWiFiManager
+
+bool PersWiFiManager::attemptConnection(const String& ssid, const String& pass) {
+  //attempt to connect to wifi
+  WiFi.mode(WIFI_STA);
+  if (ssid.length()) {
+    if (pass.length()) WiFi.begin(ssid.c_str(), pass.c_str());
+    else WiFi.begin(ssid.c_str());
+  } else {
+    WiFi.begin();
+  }
+
+  //if in nonblock mode, skip this loop
+  _connectStartTime = millis();// + 1;
+  while (!_connectNonBlock && _connectStartTime) {
+    handleWiFi();
+    delay(10);
+  }
+
+  return (WiFi.status() == WL_CONNECTED);
+
+} //attemptConnection
+
+void PersWiFiManager::handleWiFi() {
+  if (!_connectStartTime) return;
+
+  if (WiFi.status() == WL_CONNECTED) {
+    _connectStartTime = 0;
+    if (_connectHandler) _connectHandler();
+    return;
+  }
+
+  //if failed or not connected and time is up
+  if ((WiFi.status() == WL_CONNECT_FAILED) || ((WiFi.status() != WL_CONNECTED) && ((millis() - _connectStartTime) > (1000 * WIFI_CONNECT_TIMEOUT)))) {
+    startApMode();
+    _connectStartTime = 0; //reset connect start time
+  }
+
+} //handleWiFi
+
+void PersWiFiManager::startApMode(){
+  //start AP mode
+  IPAddress apIP(192, 168, 1, 1);
+  WiFi.mode(WIFI_AP);
+  WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
+  _apPass.length() ? WiFi.softAP(getApSsid().c_str(), _apPass.c_str()) : WiFi.softAP(getApSsid().c_str());
+  if (_apHandler) _apHandler();  
+}//startApMode
+
+void PersWiFiManager::setConnectNonBlock(bool b) {
+  _connectNonBlock = b;
+} //setConnectNonBlock
+
+void PersWiFiManager::setupWiFiHandlers() {
+  IPAddress apIP(192, 168, 1, 1);
+  _dnsServer->setErrorReplyCode(DNSReplyCode::NoError);
+  _dnsServer->start((byte)53, "*", apIP); //used for captive portal in AP mode
+
+  _server->on("/wifi/list", [&] () {
+    //scan for wifi networks
+    int n = WiFi.scanNetworks();
+
+    //build array of indices
+    int ix[n];
+    for (int i = 0; i < n; i++) ix[i] = i;
+
+    //sort by signal strength
+    for (int i = 0; i < n; i++) for (int j = 1; j < n - i; j++) if (WiFi.RSSI(ix[j]) > WiFi.RSSI(ix[j - 1])) std::swap(ix[j], ix[j - 1]);
+    //remove duplicates
+    for (int i = 0; i < n; i++) for (int j = i + 1; j < n; j++) if (WiFi.SSID(ix[i]).equals(WiFi.SSID(ix[j])) && WiFi.encryptionType(ix[i]) == WiFi.encryptionType(ix[j])) ix[j] = -1;
+
+    //build plain text string of wifi info
+    //format [signal%]:[encrypted 0 or 1]:SSID
+    String s = "";
+    s.reserve(2050);
+    for (int i = 0; i < n && s.length() < 2000; i++) { //check s.length to limit memory usage
+      if (ix[i] != -1) {
+        s += String(i ? "\n" : "") + ((constrain(WiFi.RSSI(ix[i]), -100, -50) + 100) * 2) + ","
+             + ((WiFi.encryptionType(ix[i]) == ENC_TYPE_NONE) ? 0 : 1) + "," + WiFi.SSID(ix[i]);
+      }
+    }
+
+    //send string to client
+    _server->send(200, "text/plain", s);
+  }); //_server->on /wifi/list
+
+  _server->on("/wifi/wps", [&]() {
+    _server->send(200, "text/html", "attempting WPS");
+    WiFi.mode(WIFI_STA);
+    WiFi.beginWPSConfig();
+    delay(100);
+    if (WiFi.status() != WL_CONNECTED) {
+      attemptConnection("", "");
+    }
+  }); //_server->on /wifi/wps
+
+  _server->on("/wifi/connect", [&]() {
+    _server->send(200, "text/html", "connecting...");
+    attemptConnection(_server->arg("n"), _server->arg("p"));
+  }); //_server->on /wifi/connect
+
+  _server->on("/wifi/ap", [&](){
+    _server->send(200, "text/html", "access point: "+getApSsid());
+    startApMode();
+  }); //_server->on /wifi/ap
+
+  _server->on("/wifi/rst", [&]() {
+    _server->send(200, "text/html", "Rebooting...");
+    delay(100);
+    ESP.restart();
+  });
+
+//#ifdef WIFI_HTM_PROGMEM
+  _server->on("/wifi.htm", [&]() {
+    _server->send(200, "text/html", wifi_htm);
+  });
+//#endif
+
+}//setupWiFiHandlers
+
+bool PersWiFiManager::begin(const String& ssid, const String& pass) {
+  setupWiFiHandlers();
+  return attemptConnection(ssid, pass); //switched order of these two for return
+} //begin
+
+String PersWiFiManager::getApSsid() {
+  return _apSsid.length() ? _apSsid : "ESP8266";
+} //getApSsid
+
+void PersWiFiManager::setApCredentials(const String& apSsid, const String& apPass) {
+  if (apSsid.length()) _apSsid = apSsid;
+  if (apPass.length() >= 8) _apPass = apPass;
+} //setApCredentials
+
+void PersWiFiManager::onConnect(WiFiChangeHandlerFunction fn) {
+  _connectHandler = fn;
+}
+
+void PersWiFiManager::onAp(WiFiChangeHandlerFunction fn) {
+  _apHandler = fn;
+}
+
+

+ 52 - 0
src/WiFiThermostat/PersWiFiManager.h

@@ -0,0 +1,52 @@
+#ifndef PERSWIFIMANAGER_H
+#define PERSWIFIMANAGER_H
+
+#include <ESP8266WiFi.h>
+#include <ESP8266WebServer.h>
+#include <DNSServer.h>
+
+#define WIFI_CONNECT_TIMEOUT 30
+
+class PersWiFiManager {
+
+  public:
+
+    typedef std::function<void(void)> WiFiChangeHandlerFunction;
+
+    PersWiFiManager(ESP8266WebServer& s, DNSServer& d);
+
+    bool attemptConnection(const String& ssid = "", const String& pass = "");
+
+    void setupWiFiHandlers();
+
+    bool begin(const String& ssid = "", const String& pass = "");
+
+    String getApSsid();
+
+    void setApCredentials(const String& apSsid, const String& apPass = "");
+
+    void setConnectNonBlock(bool b);
+
+    void handleWiFi();
+
+    void startApMode();
+
+    void onConnect(WiFiChangeHandlerFunction fn);
+
+    void onAp(WiFiChangeHandlerFunction fn);
+
+  private:
+    ESP8266WebServer * _server;
+    DNSServer * _dnsServer;
+    String _apSsid, _apPass;
+
+    bool _connectNonBlock;
+    unsigned long _connectStartTime;
+
+    WiFiChangeHandlerFunction _connectHandler;
+    WiFiChangeHandlerFunction _apHandler;
+
+};//class
+
+#endif
+

+ 480 - 267
src/WiFiThermostat/WiFiThermostat.ino

@@ -1,83 +1,111 @@
 
-#define VERSION "0.1.1"
+// pre compiletime config
+#define VERSION "0.1.2"
 
-#include <ESP8266WiFi.h>          //ESP8266 Core WiFi Library (you most likely already have this in your sketch)
+#define DEVICE_NAME "WIFI-THERMOSTAT"
+
+#define PIN_DHTSENSOR 13
+#define PIN_RELAIS 16
+#define PIN_BUTTON_PLUS 0
+#define PIN_BUTTON_MINUS 2
+#define PIN_BUTTON_MODE 14
+#define PIN_PIRSENSOR 12
+
+#define RELAISONSTATE LOW
+#define BUTTONONSTATE LOW
+
+#define DHTTYPE DHT22 // DHT sensor type
+#define LCDADDR 0x27  // I2C address LCD
+
+
+#define DEBUG_SERIAL //uncomment for Serial debugging statements
+
+#ifdef DEBUG_SERIAL
+#define DEBUG_BEGIN Serial.begin(115200)
+#define DEBUG_PRINT(x) Serial.println(x)
+#else
+#define DEBUG_PRINT(x)
+#define DEBUG_BEGIN
+#endif
+
+#include "PersWiFiManager.h"
+
+#include <ArduinoJson.h>
+#include <ESP8266WiFi.h>
 #include <WiFiClient.h>
 #include <ESP8266WebServer.h>
 #include <ESP8266mDNS.h>
 #include <ESP8266HTTPUpdateServer.h>
 #include <PubSubClient.h>
 
-ESP8266WebServer httpServer(80);
-ESP8266HTTPUpdateServer httpUpdater;
-
 #include <Wire.h>
 #include "LiquidCrystal_I2C.h"
 
-//#include <DNSServer.h>            //Local DNS Server used for redirecting all requests to the configuration portal
-//#include <ESP8266WebServer.h>     //Local WebServer used to serve the configuration portal
-//#include <WiFiManager.h>          //https://github.com/tzapu/WiFiManager WiFi Configuration Magic
+#include <DNSServer.h>
+#include <FS.h>
 
-#include <AS_BH1750.h> // BH1750 lux sensor
+//#include <AS_BH1750.h> // BH1750 lux sensor
 #include "DHT.h"
 
-#define DHTTYPE DHT22
-#define LCDADDR 0x27
-#define LUXSENSORADDR 0x23
 
-#define PIN_DHTSENSOR 13
-#define PIN_RELAIS 16
-#define PIN_BUTTON_PLUS 0
-#define PIN_BUTTON_MINUS 2
-#define PIN_BUTTON_MODE 14
-#define PIN_PIRSENSOR 12
-
-/*const int PIN_DHTSENSOR = 13;
-  const int PIN_RELAIS = 16;
-  const int PIN_BUTTON_PLUS = 0;
-  const int PIN_BUTTON_MINUS = 2;
-  const int PIN_BUTTON_MODE = 14;
-  const int PIN_PIRSENSOR = 12;*/
 
-const bool RelaisOnState = LOW;
-const bool ButtonOnState = LOW;
+// global variables
+float humidity, temperature;
+bool turnHeatingOn = false;
+bool heatingEnabled = true;
+byte heatingMode = 1; // 0 = off, 1 = default/day, 2 = night/reduction
 
 float setTemp;
+long heatingLastOnMillis;
+long heatingLastOffMillis;
+
+float aTemp, aHum;
+long aTempHumLastUpdate;
+byte whichTempToDisplay; // 1=temp inside (from DHT sensor), 2= temp outside (via MQTT)
+
+long lastMeasure = 0;
+long lastDisplayUpdate = 0;
+long lastDisplayToggle = 0;
+long lastTempUpdate = 0;
+char msg[50];   // buffer MQTT in payload
+char topic[50]; // buffer MQTT in topic
+
+// global variables from other modules
+//extern bool displayActive;
+bool displayActive = false;
+
+// functions from other modules/files
+//extern void httpServerHandleNotFound();
+//extern void httpServerHandleRoot();
+//extern void enableDisplay();
+//extern void disableDisplay();
+//extern void extendDisplayTimeout();
+//extern void handleDisplayTimeout();
+//extern void updateDisplay();
+//extern void initDisplay();
+//extern void plusButtonAction();
+//extern void minusButtonAction();
+//extern void modeButtonAction();
+//extern void modeButtonHoldAction();
+//extern void checkButtonStates();
+
+// config variables
+
+const char* mqtt_server = "10.1.1.11";
+const int mqtt_port = 1883;
+long minOffTime = 10; // s
+
 float setTempDay = 21.5;
 float setTempNight = 18.0;
-
 float setTempMin = 14.0;
 float setTempMax = 29.0;
 float setTempMinLow = 10.0;
 float setTempMaxLow = 19.0;
 float hysteresis = 0.5;
-
-long heatingLastOnMillis;
-long heatingLastOffMillis;
-long minOffTime = 10; // s
-//uint16_t lux;
-//int lux;
-//float lux;
-
 int measureinterval = 60000; // ms
+int displayinterval = 5000;
+int displayTimeout = 60000;
 
-bool heatingEnabled = true;
-byte heatingMode = 1;
-///// 0 = off
-// 1 = default/day
-// 2 = night/reduction
-
-bool turnHeatingOn = false;
-
-float humidity, temperature;
-//int humidity, temperature;
-
-const char* host = "espthermostat";
-const char* ssid = "KS61T5SH";  // WiFi SSID
-const char* password = "Gurken651salat";  // WiFi PWD
-
-const char* mqtt_server = "10.1.1.11";
-const int mqtt_port = 1883;
 
 //const char* mqtt_topic_prefix = "Test/Thermostat/";
 const char* mqtt_topic_temp = "Test/Thermostat/Temp";
@@ -89,59 +117,27 @@ const char* mqtt_topic_heating = "Test/Thermostat/Heating";
 const char* mqtt_topic_heating_lastofftime = "Test/Thermostat/HeatingLastOffTime";
 const char* mqtt_topic_heating_lastontime = "Test/Thermostat/HeatingLastOnTime";
 
-// subscribe topic
-const char* mqtt_topic_in = "Test/Thermostat/in";
+const char* mqtt_topic_in = "Test/Thermostat/in";   // subscribe topic
 
-DHT dht(PIN_DHTSENSOR, DHTTYPE);
-
-// global variables from other modules
-extern bool displayActive;
 
 
 
-//AS_BH1750 lightMeter; // Lichtstärkemessung mit BH1750
 
+DHT dht(PIN_DHTSENSOR, DHTTYPE);
 LiquidCrystal_I2C lcd(0x27, 16, 2); // set the LCD address to 0x27 for a 16 chars and 2 line display
 
 WiFiClient espClient;
-PubSubClient client(espClient);
-
-long lastMsg = 0;
-char msg[50];
-
-char topic[50];
-
-int displayTimeout = 10000;
-
-//bool lightMeter_present;
-
-void setup_wifi() {
-  delay(10);
-  // We start by connecting to a WiFi network
-  Serial.println();
-  Serial.print("Connecting to ");
-  Serial.println(ssid);
-
-  /////
-  WiFi.mode(WIFI_STA);
-  /////
+PubSubClient mqttclient(espClient);
 
-  WiFi.begin(ssid, password);
-
-  while (WiFi.status() != WL_CONNECTED) {
-    delay(500);
-    Serial.print(".");
-  }
+ESP8266WebServer httpServer(80);
+DNSServer dnsServer;
+PersWiFiManager persWM(httpServer, dnsServer);
 
-  randomSeed(micros());
+ESP8266HTTPUpdateServer httpUpdater;
 
-  Serial.println("");
-  Serial.println("WiFi connected");
-  Serial.println("IP address: ");
-  Serial.println(WiFi.localIP());
-}
 
-void callback(char* topic, byte* payload, unsigned int length) {
+// MQTT callback
+void mqttCallback(char* topic, byte* payload, unsigned int length) {
   Serial.print("Message arrived [");
   Serial.print(topic);
   Serial.print("] ");
@@ -150,15 +146,19 @@ void callback(char* topic, byte* payload, unsigned int length) {
   }
   Serial.println();
 
-  if ((char)payload[0] == 's' && \
-      (char)payload[1] == 'e' && \
-      (char)payload[2] == 't' && \
-      (char)payload[3] == ' ' ) {
-    if ((char)payload[4] == 't' && \
-        (char)payload[5] == 'e' && \
-        (char)payload[6] == 'm' && \
-        (char)payload[7] == 'p' && \
-        (char)payload[8] == ' ' ) {
+  if (strcmp(topic, mqtt_topic_in) == 0) { //if topic = mqtt_topic_in
+    Serial.println("TOPIC!!");
+
+    char tmpPayload[length + 1];
+    for (int i = 0; i < length; i++) {
+      tmpPayload[i] = (char)payload[i];
+    }
+    tmpPayload[sizeof(tmpPayload) - 1] = '\0';
+
+    Serial.print("tmpPayload:");
+    Serial.println(tmpPayload);
+
+    if (strncmp(tmpPayload, "set temp ", 9) == 0) {
       char inValue[length - 9 + 1];
       for (int i = 0; i < length; i++) {
         inValue[i] = (char)payload[i + 9];
@@ -171,22 +171,19 @@ void callback(char* topic, byte* payload, unsigned int length) {
       Serial.print(invalueFloat);
       if (invalueFloat >= setTempMin && invalueFloat <= setTempMax) {
         setTempDay = invalueFloat;
-        lastMsg = 0; // reset var lastMsg to speed up lcd update
+        updateDisplay();
       }
       else if (invalueFloat > setTempMax) {
         setTempDay = setTempMax;
-        lastMsg = 0; // reset var lastMsg to speed up lcd update
+        updateDisplay();
       }
       else if (invalueFloat < setTempMin) {
         setTempDay = setTempMin;
-        lastMsg = 0; // reset var lastMsg to speed up lcd update
+        updateDisplay();
       }
-    }
-    else if ((char)payload[4] == 't' && \
-             (char)payload[5] == 'l' && \
-             (char)payload[6] == 'o' && \
-             (char)payload[7] == 'w' && \
-             (char)payload[8] == ' ' ) {
+    }// if payload=="set temp "
+
+    else if (strncmp(tmpPayload, "set tlow ", 9) == 0) {
       char inValue[length - 9 + 1];
       for (int i = 0; i < length; i++) {
         inValue[i] = (char)payload[i + 9];
@@ -199,84 +196,104 @@ void callback(char* topic, byte* payload, unsigned int length) {
       Serial.print(invalueFloat);
       if (invalueFloat >= setTempMinLow && invalueFloat <= setTempMaxLow) {
         setTempNight = invalueFloat;
-        lastMsg = 0; // reset var lastMsg to speed up lcd update
+        updateDisplay();
       }
       else if (invalueFloat > setTempMaxLow) {
         setTempNight = setTempMaxLow;
-        lastMsg = 0; // reset var lastMsg to speed up lcd update
+        updateDisplay();
       }
       else if (invalueFloat < setTempMinLow) {
         setTempNight = setTempMinLow;
-        lastMsg = 0; // reset var lastMsg to speed up lcd update
+        updateDisplay();
       }
     }
-    else if ((char)payload[4] == 'm' && \
-             (char)payload[5] == 'o' && \
-             (char)payload[6] == 'd' && \
-             (char)payload[7] == 'e' && \
-             (char)payload[8] == ' ' ) {
+
+    else if (strncmp(tmpPayload, "set mode ", 9) == 0) {
       if ((char)payload[9] == '1') {
         // switch to mode default/day
         heatingMode = 1;
-        lastMsg = 0; // reset var lastMsg to speed up lcd update
+        updateDisplay();
       }
       else if ((char)payload[9] == '2') {
         // switch to mode night/reduction
         heatingMode = 2;
-        lastMsg = 0; // reset var lastMsg to speed up lcd update
+        updateDisplay();
       }
     }
 
-    else if ((char)payload[4] == 'e' && \
-             (char)payload[5] == 'n' && \
-             (char)payload[6] == 'a' && \
-             (char)payload[7] == 'b' && \
-             (char)payload[8] == ' ' ) {
+    else if (strncmp(tmpPayload, "set enab ", 9) == 0) {
       if ((char)payload[9] == '0') {
         // switch heating off
         heatingEnabled = false;
-        lastMsg = 0; // reset var lastMsg to speed up lcd update
+        updateDisplay();
       }
       else if ((char)payload[9] == '1') {
         // switch heating on
         heatingEnabled = true;
-        lastMsg = 0; // reset var lastMsg to speed up lcd update
+        updateDisplay();
       }
     }
+  }//if topic = mqtt_topic_in
 
-  }
-}
-
-void reconnect() {
-  // Loop until we're reconnected
-  while (!client.connected()) {
-    Serial.print("Attempting MQTT connection...");
-    // Create a random client ID
-    String clientId = "ESP8266Client-";
-    clientId += String(random(0xffff), HEX);
-    // Attempt to connect
-    if (client.connect(clientId.c_str())) {
-      Serial.println("connected");
-      // Once connected, publish an announcement...
-      //client.publish("TestoutTopic", "hello world");
-      // ... and resubscribe
-      client.subscribe(mqtt_topic_in);
-    } else {
-      Serial.print("failed, rc=");
-      Serial.print(client.state());
-      Serial.println(" try again in 5 seconds");
-      // Wait 5 seconds before retrying
-      delay(5000);
+  if (strcmp(topic, "wetter/atemp") == 0) { //if topic = "wetter/atemp"
+    char inValue[length + 1];
+    for (int i = 0; i < length; i++) {
+      inValue[i] = (char)payload[i];
+    }
+    inValue[sizeof(inValue) - 1] = '\0';
+    //Serial.print(inValue);
+    //Serial.println();
+    float invalueFloat = atof(inValue);
+    aTemp = invalueFloat;
+    aTempHumLastUpdate = millis();
+    //Serial.print("atemp=");
+    //Serial.println(invalueFloat);
+  }//if topic = "wetter/atemp"
+
+  if (strcmp(topic, "wetter/ahum") == 0) { //if topic = "wetter/atemp"
+    char inValue[length + 1];
+    for (int i = 0; i < length; i++) {
+      inValue[i] = (char)payload[i];
     }
+    inValue[sizeof(inValue) - 1] = '\0';
+    //Serial.print(inValue);
+    //Serial.println();
+    float invalueFloat = atof(inValue);
+    aHum = invalueFloat;
+    aTempHumLastUpdate = millis();
+    //Serial.println("ahum=");
+    //Serial.println(invalueFloat);
+  }//if topic = "wetter/ahum"
+
+}//mqttCallback
+
+
+
+long mqttLastReconnectAttempt = 0;
+
+boolean mqttReconnect() {
+  // Create a random MQTT client ID
+  String mqttClientId = "ESP8266Client-";
+  mqttClientId += String(random(0xffff), HEX);
+  if (mqttclient.connect(mqttClientId.c_str())) {
+    Serial.println("connected");
+    // Once connected, publish an announcement...
+    //mqttclient.publish("TestoutTopic", "hello world");
+    // ... and resubscribe
+    mqttclient.subscribe(mqtt_topic_in);
+    mqttclient.subscribe("wetter/atemp");
+    mqttclient.subscribe("wetter/ahum");
   }
-}
+  return mqttclient.connected();
+} //mqttReconnect
+
 
 void setup() {
-  //WiFiManager wifiManager;
-  //wifiManager.autoConnect("Thermostat", "configesp");
-  //wifiManager.setConfigPortalTimeout(180);
-  Serial.begin(115200);
-  delay(300);
+  DEBUG_BEGIN; //for terminal debugging
+  DEBUG_PRINT();
+
+
+
   Serial.print("WiFi Thermostat v");
   Serial.print(VERSION);
   Serial.println(" by Flo Kra");
@@ -288,64 +305,162 @@ void setup() {
   pinMode(PIN_BUTTON_MINUS, INPUT_PULLUP);
   pinMode(PIN_BUTTON_MODE, INPUT_PULLUP);
 
-  // DHT11/22 Temp/Hum-Sensor initialisieren
+  // initialize DHT11/22 temp/hum sensor
   dht.begin();
 
-  //  // lightMeter BH1750
-  //  //if (! lightMeter.begin(BH1750_CONTINUOUS_HIGH_RES_MODE_2)) {
-  //  if (! lightMeter.begin(RESOLUTION_AUTO_HIGH)) {
-  //    lightMeter_present = false;
-  //    delay(50);
-  //    Serial.println(F("ERROR: no BH1750 light meter found"));
-  //  }
-  //  else {
-  //    lightMeter_present = true;
-  //    delay(50);
-  //    Serial.println(F("BH1750 light meter found"));
-  //  }
-
-  setup_wifi();
-
-  MDNS.begin(host);
 
+  //optional code handlers to run everytime wifi is connected...
+  persWM.onConnect([]() {
+    DEBUG_PRINT("wifi connected");
+    DEBUG_PRINT(WiFi.SSID());
+    DEBUG_PRINT(WiFi.localIP());
+  });
+  //...or AP mode is started
+  persWM.onAp([]() {
+    DEBUG_PRINT("AP MODE");
+    DEBUG_PRINT(persWM.getApSsid());
+  });
+
+  //allows serving of files from SPIFFS
+  //SPIFFS.begin();
+  //SPIFFS.format();
+  //sets network name for AP mode
+  persWM.setApCredentials(DEVICE_NAME);
+  //persWM.setApCredentials(DEVICE_NAME, "password"); optional password
+
+  //make connecting/disconnecting non-blocking
+  persWM.setConnectNonBlock(true);
+
+  //in non-blocking mode, program will continue past this point without waiting
+  persWM.begin();
+
+  //handles commands from webpage, sends live data in JSON format
+  httpServer.on("/api", []() {
+    DEBUG_PRINT("httpServer.on /api");
+    if (httpServer.hasArg("plusBtn")) {
+      plusButtonAction();
+      DEBUG_PRINT(P("web plusBtn"));
+    } //if
+    if (httpServer.hasArg("minusBtn")) {
+      minusButtonAction();
+      DEBUG_PRINT(P("web minusBtn"));
+    } //if
+    if (httpServer.hasArg("modeBtn")) {
+      modeButtonAction();
+      DEBUG_PRINT(P("web modeBtn"));
+    } //if
+    if (httpServer.hasArg("onoffBtn")) {
+      modeButtonHoldAction();
+      DEBUG_PRINT(P("web onoffBtn"));
+    } //if
+
+    //build json object of program data
+    StaticJsonBuffer<200> jsonBuffer;
+    JsonObject &json = jsonBuffer.createObject();
+    json["ssid"] = WiFi.SSID();
+    json["setTemp"] = setTempDay;
+    json["temp"] = temperature;
+    json["hum"] = int(humidity);
+    json["mode"] = heatingMode;
+    json["heatingEnabled"] = heatingEnabled;
+    json["heating"] = turnHeatingOn;
+
+    char jsonchar[200];
+    json.printTo(jsonchar); //print to char array, takes more memory but sends in one piece
+    httpServer.send(200, "application/json", jsonchar);
+
+  }); //httpServer.on /api
+
+  //get heap status, analog input value and all GPIO statuses in one json call
+  httpServer.on("/info", HTTP_GET, []() {
+    String json = "{";
+    json += "\"wifissid\":\"" + WiFi.SSID() + "\"";
+    json += "\"heap\":" + String(ESP.getFreeHeap());
+    //json += ", \"analog\":" + String(analogRead(A0));
+    //json += ", \"gpio\":" + String((uint32_t)(((GPI | GPO) & 0xFFFF) | ((GP16I & 0x01) << 16)));
+    json += "}";
+    httpServer.send(200, "text/json", json);
+    json = String();
+  }); //httpServer.on /info
+
+  httpServer.on("/", []() {
+    httpServerHandleRoot();
+  });
+
+  httpServer.onNotFound([]() {
+    httpServerHandleNotFound();
+  }); //httpServer.onNotFound
+
+  // HTTP Updater at /update
   httpUpdater.setup(&httpServer);
 
-  httpServer.on("/", handleRoot);
-  httpServer.onNotFound(handleNotFound);
-  
+
   httpServer.begin();
 
-  MDNS.addService("http", "tcp", 80);
-  Serial.printf("HTTPUpdateServer ready! Open http://%s.local/update in your browser\n", host);
-  
-  client.setServer(mqtt_server, mqtt_port);
-  client.setCallback(callback);
+  DEBUG_PRINT("setup complete.");
+
+  mqttclient.setServer(mqtt_server, mqtt_port);
+  mqttclient.setCallback(mqttCallback);
+  mqttLastReconnectAttempt = 0;
 
   initDisplay();
-}
 
+} //void setup
 
 void loop() {
-  httpServer.handleClient();
+  persWM.handleWiFi(); //in non-blocking mode, handleWiFi must be called in the main loop
 
+  dnsServer.processNextRequest();
+  httpServer.handleClient();
 
-  if (!client.connected()) {
-    reconnect();
-  }
-  client.loop();
+  // MQTT reconnect if not connected (nonblocking)
+  if (!mqttclient.connected()) {
+    long now = millis();
 
+    if (now - mqttLastReconnectAttempt > 5000) {
+      mqttLastReconnectAttempt = now;
+      // Attempt to reconnect
+      if (mqttReconnect()) {
+        mqttLastReconnectAttempt = 0;
+      }
+    }
+  } else {
+    // Client connected
+    mqttclient.loop();
+  }//else
 
   checkButtonStates();
   handleDisplayTimeout();
 
-  if ( (millis() - lastMsg) > measureinterval) {
-    lastMsg = millis();
 
-    humidity = dht.readHumidity();
-    temperature = dht.readTemperature();  // Read temperature as Celsius (the default)
+  // set target temp for heating mode
+  if (heatingMode == 1) { // heating on - default/day mode
+    setTemp = setTempDay;
+  }
+  else if (heatingMode == 2) { // heating of - night/reduction mode
+    setTemp = setTempNight;
+  }
 
-    unsigned long heatingOnTime, heatingOffTime;
 
+  if ( (millis() - lastMeasure) > measureinterval) {
+    lastMeasure = millis();
+
+    float tmpHum = round(dht.readHumidity());
+    float tmpTemp = dht.readTemperature();  // Read temperature as Celsius (the default)
+
+    // Check if any reads failed
+    if (isnan(tmpHum) || isnan(tmpTemp)) {
+      Serial.println("Failed to read from DHT sensor!");
+    }
+    else {
+      if (tmpTemp < 50.0 && tmpTemp > -20.0) {
+        temperature = tmpTemp;
+        humidity = tmpHum;
+        lastTempUpdate = millis();
+      }
+    }
+
+    unsigned long heatingOnTime, heatingOffTime;
     if (heatingEnabled && turnHeatingOn) {
       heatingOnTime = (millis() - heatingLastOffMillis) / 1000;
       Serial.print("heatingOnTime: ");
@@ -359,97 +474,204 @@ void loop() {
       Serial.println();
     }
 
-    if ( temperature >= setTemp ) {
-      turnHeatingOn = false;
-      heatingLastOnMillis = millis();
-      digitalWrite(PIN_RELAIS, !RelaisOnState);
-      Serial.println("heating off");
 
-      Serial.print("last onTime: ");
-      Serial.print(heatingOnTime);
-      Serial.println();
+    Serial.print("lastTempUpdate: ");
+    Serial.println(lastTempUpdate);
 
-      client.publish(mqtt_topic_heating, "off");
+    long test1 = millis() - lastTempUpdate;
+    Serial.print("lastTempUpdate test1: ");
+    Serial.println(test1);
 
-      //client.publish(mqtt_topic_heating_lastontime, heatingOnTime);
-    }
-    else if ( heatingEnabled && ( temperature < (setTemp - hysteresis) ) && ( heatingOffTime > minOffTime ) ) {
-      turnHeatingOn = true;
-      digitalWrite(PIN_RELAIS, RelaisOnState);
-      Serial.println("heating on");
+    
+    if ( (millis() - lastTempUpdate) < 120000 ) {
+      // thermostat - only active if measured temperature is < 2 min old
 
-      Serial.print("last offTime: ");
-      Serial.print(heatingOffTime);
-      Serial.println();
+      // thermostat with hysteresis
+      if ( temperature >= setTemp ) {
+        turnHeatingOn = false;
+        heatingLastOnMillis = millis();
+        digitalWrite(PIN_RELAIS, !RELAISONSTATE);
+        updateDisplay();
+        Serial.println("heating off");
 
-      client.publish(mqtt_topic_heating, "on");
+        Serial.print("last onTime: ");
+        Serial.print(heatingOnTime);
+        Serial.println();
 
-      //client.publish(mqtt_topic_heating_lastofftime, heatingOffTime);
-    }
+        mqttclient.publish(mqtt_topic_heating, "off");
+
+        //mqttclient.publish(mqtt_topic_heating_lastontime, heatingOnTime);
+      }
+      else if ( heatingEnabled && ( temperature < (setTemp - hysteresis) ) && ( heatingOffTime > minOffTime ) ) {
+        turnHeatingOn = true;
+        digitalWrite(PIN_RELAIS, RELAISONSTATE);
+        updateDisplay();
+        Serial.println("heating on");
+
+        Serial.print("last offTime: ");
+        Serial.print(heatingOffTime);
+        Serial.println();
 
-    // set target temp for heating mode
-    if (heatingMode == 1) { // heating on - default/day mode
-      setTemp = setTempDay;
+        mqttclient.publish(mqtt_topic_heating, "on");
+
+        //mqttclient.publish(mqtt_topic_heating_lastofftime, heatingOffTime);
+      }
     }
-    else if (heatingMode == 2) { // heating of - night/reduction mode
-      setTemp = setTempNight;
+    else {
+      turnHeatingOn = false;
+      digitalWrite(PIN_RELAIS, !RELAISONSTATE);
+      Serial.println("heating off");
+      mqttclient.publish(mqtt_topic_heating, "off");
     }
 
 
 
-    //    if (lightMeter_present) {
-    //      delay(50);
-    //      lux = lightMeter.readLightLevel();
+  }
+
+
+
+
+  //    if (lightMeter_present) {
+  //      delay(50);
+  //      lux = lightMeter.readLightLevel();
+  //
+  //      String lux_str = String(lux, 1); //converting humidity (the float variable above) to a string with 0 decimals
+  //      char lux_chararr[lux_str.length() + 1];
+  //      lux_str.toCharArray(lux_chararr, lux_str.length() + 1); //packaging up the data to publish to mqtt whoa...
+  //
+  //      Serial.print("Lux: ");
+  //      Serial.println(lux_str);
+  //      mqttclient.publish(mqtt_topic_lux, lux_chararr);
+  //    }
+
+
+  long now = millis();
+  if ( ((now - aTempHumLastUpdate) < 300000) && whichTempToDisplay == 1 && ((now - lastDisplayToggle) > displayinterval) ) {
+    // A-temp has been updated < 5 min ago, last displayed temp was I and display interval is overdue
+    whichTempToDisplay = 2; // 1= I, 2= A
+    lastDisplayToggle = now;
+  }
+  else if ( whichTempToDisplay != 1 && ((now - lastDisplayToggle) > displayinterval) ) {
+    whichTempToDisplay = 1; // 1= I, 2= A
+    lastDisplayToggle = now;
+  }
+
+  // update display?
+  if ( (now - lastDisplayUpdate) > displayinterval) {
+    lastDisplayUpdate = now;
+
+    //    char temp_chararr[6];
+    //    char hum_chararr[3];
+    //    if ( (millis() - lastTempUpdate) < 120000) {
+    //      String temp_str = String(temperature, 1); //converting Temperature (the float variable above) to a string with 1 decimal
+    //      //char temp_chararr[temp_str.length() + 1];
+    //      temp_str.toCharArray(temp_chararr, temp_str.length() + 1); //packaging up the data to publish to mqtt whoa...
     //
-    //      String lux_str = String(lux, 1); //converting humidity (the float variable above) to a string with 0 decimals
-    //      char lux_chararr[lux_str.length() + 1];
-    //      lux_str.toCharArray(lux_chararr, lux_str.length() + 1); //packaging up the data to publish to mqtt whoa...
+    //      String hum_str = String(humidity, 0); //converting humidity (the float variable above) to a string with 0 decimals
+    //      //char hum_chararr[hum_str.length() + 1];
+    //      hum_str.toCharArray(hum_chararr, hum_str.length() + 1); //packaging up the data to publish to mqtt whoa...
     //
-    //      Serial.print("Lux: ");
-    //      Serial.println(lux_str);
-    //      client.publish(mqtt_topic_lux, lux_chararr);
+    //      mqttclient.publish(mqtt_topic_temp, temp_chararr);
+    //      mqttclient.publish(mqtt_topic_hum, hum_chararr);
+    //    }
+    //    else {
+    //      char temp_chararr[] = {'-', '-', ',', '-', '\0'};
+    //      char hum_chararr[] = {'-', '-', '\0'};
     //    }
 
-    String hum_str = String(humidity, 0); //converting humidity (the float variable above) to a string with 0 decimals
-    char hum_chararr[hum_str.length() + 1];
-    hum_str.toCharArray(hum_chararr, hum_str.length() + 1); //packaging up the data to publish to mqtt whoa...
+
 
     String temp_str = String(temperature, 1); //converting Temperature (the float variable above) to a string with 1 decimal
     char temp_chararr[temp_str.length() + 1];
     temp_str.toCharArray(temp_chararr, temp_str.length() + 1); //packaging up the data to publish to mqtt whoa...
 
-    char setTemp_chararr[5];     //result string 4 positions + \0 at the end
-    // convert float to fprintf type string format 2 positions with 1 decimal place
-    dtostrf(setTemp, 2, 1, setTemp_chararr );
+    String hum_str = String(humidity, 0); //converting humidity (the float variable above) to a string with 0 decimals
+    char hum_chararr[hum_str.length() + 1];
+    hum_str.toCharArray(hum_chararr, hum_str.length() + 1); //packaging up the data to publish to mqtt whoa...
+
+    if ( (now - lastTempUpdate) < 120000 ) {
+      mqttclient.publish(mqtt_topic_temp, temp_chararr);
+      mqttclient.publish(mqtt_topic_hum, hum_chararr);
+    }
+    else {
+      temp_str = "--.-";
+      hum_str = "--";
+    }
 
-    Serial.println("Publish messages temp/hum ");
 
-    client.publish(mqtt_topic_temp, temp_chararr);
-    client.publish(mqtt_topic_hum, hum_chararr);
-    client.publish(mqtt_topic_settemp, setTemp_chararr);
+    String atemp_str = String(aTemp, 1); //converting Temperature (the float variable above) to a string with 1 decimal
+    char atemp_chararr[atemp_str.length() + 1];
+    atemp_str.toCharArray(atemp_chararr, atemp_str.length() + 1); //packaging up the data to publish to mqtt whoa...
 
+    String ahum_str = String(aHum, 0); //converting humidity (the float variable above) to a string with 0 decimals
+    char ahum_chararr[ahum_str.length() + 1];
+    ahum_str.toCharArray(ahum_chararr, ahum_str.length() + 1); //packaging up the data to publish to mqtt whoa...
+
+
+
+    char setTemp_chararr[5];     //result string 4 positions + \0 at the end
+    // convert float to fprintf type string format 2 positions with 1 decimal place
+    dtostrf(setTemp, 2, 1, setTemp_chararr );
 
     Serial.print("set temp: ");
     Serial.println(setTemp_chararr);
     Serial.print("current temp: ");
-    Serial.println(temp_str);
-
-    // print is-temperature incl = and ° symbol + humidity to lcd, line 1, first 11 chars
-    lcd.setCursor(0, 0);
-    lcd.write(0x3D); // = Zeichen
-    lcd.print(" ");
-    //if (temperature < -9) lcd.print(" ");
-    //else if (temperature < 0) lcd.print("");
-    //else if (temperature < 10) lcd.print("  ");
-    //else lcd.print(" ");
-    //lcd.print(tempstr2);
-    lcd.print(temp_str); // inside temperature should hopefully always be 2.1 chars, so no special formatting necessary
-    lcd.write(0xDF); // degree symbol
-    lcd.print(" ");
-
-    //lcd.print(humstr2);
-    lcd.print(hum_str); // always 2 chars
-    lcd.print("%");
+    Serial.println(temp_chararr);
+
+
+    mqttclient.publish(mqtt_topic_settemp, setTemp_chararr);
+
+
+    if (whichTempToDisplay == 2) {
+      // print inside temperature incl = and ° symbol + humidity to lcd, line 1, first 11 chars
+      lcd.setCursor(0, 0);
+      //lcd.write(0x3D); // = Zeichen
+      lcd.print("A");
+
+      if (aTemp <= -10);
+      else if (aTemp < 0) lcd.print(" ");
+      else if (aTemp < 10) lcd.print("  ");
+      else lcd.print(" ");
+
+      lcd.print(atemp_str); // inside temperature should hopefully always be 2.1 chars, so no special formatting necessary
+      lcd.write(0xDF); // degree symbol
+      lcd.print(" ");
+
+      //lcd.print(humstr2);
+      lcd.print(ahum_str); // always 2 chars
+      lcd.print("%");
+      lcd.print("  ");
+    }
+    else {
+      // print outside temperature incl = and ° symbol + humidity to lcd, line 1, first 11 chars
+      lcd.setCursor(0, 0);
+      //lcd.write(0x3D); // = Zeichen
+      lcd.print("I");
+
+      //lcd.print(" "); // inside temperature should hopefully always be 2.1 chars, so no special formatting/spaces handling necessary
+
+      if (temperature <= -10);
+      else if (temperature < 0) lcd.print(" ");
+      else if (temperature < 10) lcd.print("  ");
+      else lcd.print(" ");
+
+      //if (temperature < -9) lcd.print(" ");
+      //else if (temperature < 0) lcd.print("");
+      //else if (temperature < 10) lcd.print("  ");
+      //else lcd.print(" ");
+      //lcd.print(tempstr2);
+      //lcd.print(temp_str);
+      lcd.print(temp_chararr);
+      lcd.write(0xDF); // degree symbol
+      lcd.print(" ");
+
+      //lcd.print(humstr2);
+      //lcd.print(hum_str); // always 2 chars
+      lcd.print(hum_chararr); // always 2 chars
+      lcd.print("%");
+      lcd.print("  ");
+    }
+
 
 
     // display current mode on LCD
@@ -504,14 +726,5 @@ void loop() {
 
   }
 
-
-  // Check if any reads failed and exit early (to try again).
-  //if (isnan(hum) || isnan(temp)) {
-  //  Serial.println("Failed to read from DHT sensor!");
-  //  return;
-  //}
-
-}
-
-
+} //void loop
 

+ 4 - 0
src/WiFiThermostat/commands.ino

@@ -0,0 +1,4 @@
+/*void evalCmd(char payload[50]) {
+ 
+}
+*/

+ 62 - 0
src/WiFiThermostat/data/conf.htm

@@ -0,0 +1,62 @@
+<h3>Configuration</h3>
+MQTT Server:
+<span id="mqtthost"></span>
+<br/> MQTT Port:
+<span id="mqttport"></span>
+<br/> MQTT User:
+<span id="mqttuser"></span>
+<br/> MQTT Password:
+<span id="mqttpass"></span>
+
+<h6>Last updated
+	<span id="ut"></span> seconds ago.
+	<span id="status"></span>
+</h6>
+
+<h3>Update Data</h3>
+<form id="xform" onsubmit="return transmit(this)">
+	x:
+	<input type="number" name="x" />
+	<input type="submit" />
+</form>
+<form id="yform" onsubmit="return transmit(this)">
+	y:
+	<input type="text" name="y" />
+	<input type="submit" />
+</form>
+<form id="zform" onsubmit="return transmit(this)">
+	z:
+	<input type="text" name="z" />
+	<input type="submit" />
+</form>
+
+<a href="wifi.htm">WiFi settings</a>
+
+<script>
+	function g(i) { return document.getElementById(i) };
+	var xhttp, updateTime;
+
+	function transmit(f) {
+		if (!xhttp) { //prevent simultaneous requests
+			g("status").innerHTML = "updating...";
+			xhttp = new XMLHttpRequest();
+			xhttp.open("POST", "/api");
+			xhttp.send(f ? (new FormData(f)) : "");
+			xhttp.onreadystatechange = function () {
+				if (xhttp.readyState === XMLHttpRequest.DONE && xhttp.status === 200) {
+					var data = JSON.parse(xhttp.responseText);
+					g("x").innerHTML = data.x;
+					g("y").innerHTML = data.y;
+					g("z").innerHTML = data.z;
+					xhttp = null;
+					g("status").innerHTML = "";
+					updateTime = 0;
+				}
+			}
+		}
+		return false; //prevent form redirect
+	}
+	transmit();
+	setInterval(function () { g("ut").innerHTML = ++updateTime; }, 1000);
+	setInterval(transmit, 5000); //autoupdate display every 5s
+</script>

+ 54 - 0
src/WiFiThermostat/data/index.htm

@@ -0,0 +1,54 @@
+<h3>Current Data</h3>
+Temp:
+<span id="temp"></span>
+<br/> set Temp:
+<span id="setTemp"></span>
+<br/> current WiFi SSID:
+<span id="ssid"></span>
+
+<h6>Last updated
+	<span id="ut"></span> seconds ago.
+	<span id="status"></span>
+</h6>
+
+<h3>Update Data</h3>
+<form id="yform" onsubmit="return transmit(this)">
+	set temp:
+	<input type="text" name="setTemp" />
+	<input type="submit" />
+</form>
+
+<a href="wifi.htm">WiFi settings</a><br/>
+<a href="/update">Firmware Update</a>
+
+<script>
+	function g(i) { return document.getElementById(i) };
+	var xhttp, updateTime;
+
+	function transmit(f) {
+		if (!xhttp) { //prevent simultaneous requests
+			g("status").innerHTML = "updating...";
+			xhttp = new XMLHttpRequest();
+			xhttp.open("POST", "/api");
+			xhttp.send(f ? (new FormData(f)) : "");
+			xhttp.onreadystatechange = function () {
+				if (xhttp.readyState === XMLHttpRequest.DONE && xhttp.status === 200) {
+					var data = JSON.parse(xhttp.responseText);
+					g("x").innerHTML = data.x;
+					g("y").innerHTML = data.y;
+					g("z").innerHTML = data.z;
+					g("ssid").innerHTML = data.ssid;
+					g("temp").innerHTML = data.temp;
+					g("setTemp").innerHTML = data.setTemp;
+					xhttp = null;
+					g("status").innerHTML = "";
+					updateTime = 0;
+				}
+			}
+		}
+		return false; //prevent form redirect
+	}
+	transmit();
+	setInterval(function () { g("ut").innerHTML = ++updateTime; }, 1000);
+	setInterval(transmit, 5000); //autoupdate display every 5s
+</script>

+ 108 - 0
src/WiFiThermostat/data/wifi.htm

@@ -0,0 +1,108 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+	<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
+	<title>ESP WiFi</title>
+	<script>
+		function g(i){return document.getElementById(i);};
+		function p(t,l){if(confirm(t)) window.location=l;};
+		function E(s){return document.createElement(s)};
+		var S="setAttribute",A="appendChild",H="innerHTML",X,wl;
+		function scan(){
+			if(X) return;
+			X=new XMLHttpRequest(),wl=document.getElementById('wl');
+			wl[H]="Scanning...";
+			X.onreadystatechange=function(){
+				if (this.readyState==4&&this.status==200) {
+					X=0;
+					wl[H]="";
+					this.responseText.split("\n").forEach(function (e) {
+						let t=e.split(","), s=t.slice(2).join(',');
+						var d=E('div'),i=E('a'),c=E('a');
+						i[S]('class','s'); c[S]('class','q');
+						i.onclick=function(){g('s').value=s;g('p').focus();};
+						i[A](document.createTextNode(s));
+						c[H]=t[0]+"%"+(parseInt(t[1])?"\uD83D\uDD12":"\u26A0");
+						wl[A](i); wl[A](c);
+						wl[A](document.createElement('br'));
+					});
+				}
+			};
+			X.open("GET","wifi/list",true);
+			X.send();
+		};
+	</script>
+	<style>
+		input {
+			padding:5px;
+			font-size:1em;
+			width:95%;
+			filter:invert(100%);
+		}
+
+		body {
+			text-align:center;
+			font-family:verdana;
+			background-color:black;
+			color:white;
+		}
+
+		a {
+			color:#1fa3ec;
+		}
+
+		button {
+			border:0;
+			border-radius:0.3em;
+			background-color:#1fa3ec;
+			color:#fff;
+			line-height:2.4em;
+			font-size:1.2em;
+			width:100%;
+			display:block;
+		}
+
+		.q {
+			float:right;
+		}
+
+		.s {
+			display:inline-block;
+			width:14em;
+			overflow:hidden;
+			text-overflow:ellipsis;
+			white-space:nowrap;
+		}
+		#wl{
+			line-height:1.5em;
+		}
+	</style>
+</head>
+
+<body>
+	<div style='text-align:left;display:inline-block;width:320px;padding:5px'>
+		<button onclick="scan()">&#x21bb; Scan</button>
+		<p id='wl'></p>
+		<form method='post' action='/wifi/connect'>
+			<input id='s' name='n' length=32 placeholder='SSID'>
+			<br>
+			<input id='p' name='p' length=64 type='password' placeholder='password'>
+			<br>
+			<br>
+			<button type='submit'>Connect</button>
+		</form>
+		<br>
+		<br>
+		<button onclick="p('Start WPS?','/wifi/wps')">WPS Setup</button>
+		<br>
+		<button onclick="p('Start AP mode?','/wifi/ap')">AP Mode</button>
+		<br>
+		<button onclick="p('Reboot device?','/wifi/rst')">Reboot</button>
+		<br>
+		<a href="javascript:history.back()">Back</a> | 
+		<a href="/">Home</a>
+	</div>
+</body>
+
+</html>

+ 64 - 0
src/WiFiThermostat/html/index - Copy.htm

@@ -0,0 +1,64 @@
+<html><body>
+  <h1>WiFi Thermostat</h1>
+  
+  <form id='minusBtn' onsubmit='return transmit(this)'>
+	<input type='hidden' name='minusBtn' value='1'>
+	<input type='submit' value='-'/>
+  </form>
+  <span id='setTemp'>22.5</span><br>
+  <form id='plusBtn' onsubmit='return transmit(this)'>
+    <input type='hidden' name='plusBtn' value='1'>
+	<input type='submit' value='+'/>
+  </form>
+  
+  Betriebsmodus: <span id='mode'></span><br>
+  <br>
+  Aktuell: <span id='temp'></span> °C&nbsp;&nbsp;&nbsp;<span id='hum'></span> %<br>  
+  <br>
+  WiFi verbunden mit: <span id='ssid'></span><br>
+  <h6>Letztes Update vor
+  <span id='ut'></span> Sekunden.
+  <span id='status'></span>
+  </h6>
+  <br><a href='/wifi.htm'>WiFi-Einstellungen</a><br>
+  <a href='/update'>Firmware Update</a>
+  <script>
+  function g(i) { return document.getElementById(i) };
+  var xhttp, updateTime;
+  function transmit(f) {
+    if (!xhttp) { 
+      g('status').innerHTML = 'lade...';
+      xhttp = new XMLHttpRequest();
+      xhttp.open('POST', '/api');
+      xhttp.send(f ? (new FormData(f)) : '');
+      xhttp.onreadystatechange = function () {
+        if (xhttp.readyState === XMLHttpRequest.DONE && xhttp.status === 200) {
+          var data = JSON.parse(xhttp.responseText);
+          g('temp').innerHTML = data.temp;
+		  g('hum').innerHTML = data.hum;
+          g('setTemp').innerHTML = data.setTemp;          
+          g('ssid').innerHTML = data.ssid;
+		  
+		  if(data.mode == '0') {
+		    g('mode').innerHTML = 'AUS';
+		  }
+		  else if(data.mode == '1') {
+			g('mode').innerHTML = 'Normalbetrieb';
+		  }
+		  else if(data.mode == '2') {
+			g('mode').innerHTML = 'Nachtabsenkung';
+		  }
+
+          xhttp = null;
+          g('status').innerHTML = '';
+          updateTime = 0;
+        }
+      }
+    }
+    return false;
+  }
+  transmit();
+  setInterval(function () { g('ut').innerHTML = ++updateTime; }, 1000);
+  setInterval(transmit, 5000);
+</script>
+  </body></html>

+ 72 - 0
src/WiFiThermostat/html/index.htm

@@ -0,0 +1,72 @@
+<html><body>
+  <h1>WiFi Thermostat</h1>
+  
+  <!--<form id='tempbtns'>
+  <input type='text' id='tempbtn' name='tempbtn' value='xx'>
+  </form>-->
+  <span id='setTemp'>22.5</span> &#8451;
+	<input type='button' onclick='return sendBtn("min")' value='-'/>
+	<input type='button' onclick='return sendBtn("pls")' value='+'/>
+  
+  <br><br>
+  Betriebsmodus: <span id='mode'></span><br>
+  <br>
+  Aktuell: <span id='temp'></span> &#8451;&nbsp;&nbsp;&nbsp;<span id='hum'></span> %<br>  
+  <br>
+  WiFi verbunden mit: <span id='ssid'></span><br>
+  <h6>Letztes Update vor
+  <span id='ut'></span> Sekunden.
+  <span id='status'></span>
+  </h6>
+  <br><a href='/wifi.htm'>WiFi-Einstellungen</a><br>
+  <a href='/update'>Firmware Update</a>
+  <script>
+  function g(i) { return document.getElementById(i) };
+  var xhttp, updateTime;
+  
+  function sendBtn(btn) {
+  //var form = document.getElementById('tempbtns');
+  //var act=document.getElementById('tempbtn')
+  //act.value = btn;
+  var fd = new FormData();
+  fd.append('tempbtn', btn);
+  return transmit(fd);
+  }
+  
+  function transmit(f) {
+    if (!xhttp) { 
+      g('status').innerHTML = 'lade...';
+      xhttp = new XMLHttpRequest();
+      xhttp.open('POST', 'api.php');
+      xhttp.send(f ? (new FormData(f)) : '');
+      xhttp.onreadystatechange = function () {
+        if (xhttp.readyState === XMLHttpRequest.DONE && xhttp.status === 200) {
+          var data = JSON.parse(xhttp.responseText);
+          g('temp').innerHTML = data.temp;
+		  g('hum').innerHTML = data.hum;
+          g('setTemp').innerHTML = data.setTemp;          
+          g('ssid').innerHTML = data.ssid;
+		  
+		  if(data.mode == '0') {
+		    g('mode').innerHTML = 'AUS';
+		  }
+		  else if(data.mode == '1') {
+			g('mode').innerHTML = 'Normalbetrieb';
+		  }
+		  else if(data.mode == '2') {
+			g('mode').innerHTML = 'Nachtabsenkung';
+		  }
+
+          xhttp = null;
+          g('status').innerHTML = '';
+          updateTime = 0;
+        }
+      }
+    }
+    return false;
+  }
+  transmit();
+  setInterval(function () { g('ut').innerHTML = ++updateTime; }, 1000);
+  setInterval(transmit, 5000);
+</script>
+  </body></html>

+ 127 - 0
src/WiFiThermostat/httpServer.ino

@@ -0,0 +1,127 @@
+//extern ESP8266WebServer httpServer;
+
+static const char httpRoot[] PROGMEM =
+  R"(<html><body>
+  <h1>WiFi Thermostat</h1>
+  
+  <form id='minusBtnFrm'>
+  <input type='hidden' name='minusBtn' value='1'>
+  </form>
+  <form id='plusBtnFrm'>
+  <input type='hidden' name='plusBtn' value='1'>
+  </form>
+  <form id='modeBtnFrm'>
+  <input type='hidden' name='modeBtn' value='1'>
+  </form>
+  <form id='onoffBtnFrm'>
+  <input type='hidden' name='onoffBtn' value='1'>
+  </form>  
+  <span style="font-size:xx-large" id='setTemp'></span> &#8451;<br>
+  <span id='mode'></span><br>
+ <input type='button' onclick='return sendMinusBtn()' value='-'/>
+  <input type='button' onclick='return sendPlusBtn()' value='+'/>
+  <input type='button' onclick='return sendModeBtn()' value='MODE'/>
+  <br>  
+  <br>  
+  <input type='button' onclick='return sendOnOffBtn()' value='EIN/AUS'/><br>
+  <span id='onoff'></span><br>
+  <br>
+  <br>
+  
+  Aktuell: <span id='temp'></span> &#8451;&nbsp;&nbsp;&nbsp;<span id='hum'></span> %<br>
+  Heizung <span id='heating'></span><br>
+  <br>
+  WiFi verbunden mit <i><span id='ssid'></span></i>.<br>
+  <h6>Letztes Update vor
+  <span id='ut'></span> Sekunden.
+  <span id='status'></span>
+  </h6>
+  <br><a href='/wifi.htm'>WiFi-Einstellungen</a><br>
+  <a href='/update'>Firmware Update</a>
+  <script>
+  function g(i) { return document.getElementById(i) };
+  var xhttp, updateTime;
+  
+  function sendMinusBtn() {
+  var form = document.getElementById('minusBtnFrm');
+  return transmit(form);
+  }
+  function sendPlusBtn() {
+  var form = document.getElementById('plusBtnFrm');
+  return transmit(form);
+  }
+  function sendModeBtn() {
+  var form = document.getElementById('modeBtnFrm');
+  return transmit(form);
+  }
+  function sendOnOffBtn() {
+  var form = document.getElementById('onoffBtnFrm');
+  return transmit(form);
+  }
+  
+  function transmit(f) {
+    if (!xhttp) { 
+      g('status').innerHTML = 'lädt...';
+      xhttp = new XMLHttpRequest();
+      xhttp.open('POST', 'api');
+      xhttp.send(f ? (new FormData(f)) : '');
+      xhttp.onreadystatechange = function () {
+        if (xhttp.readyState === XMLHttpRequest.DONE && xhttp.status === 200) {
+          var data = JSON.parse(xhttp.responseText);
+          g('temp').innerHTML = data.temp.toFixed(1);
+      g('hum').innerHTML = data.hum;
+          g('setTemp').innerHTML = data.setTemp.toFixed(1);
+          g('ssid').innerHTML = data.ssid;
+      
+      if(!data.heatingEnabled) {
+      g('mode').innerHTML = '-';
+      g('onoff').innerHTML = 'AUS';
+      }
+      else {
+      g('onoff').innerHTML = 'EIN';
+      if(data.mode == '1') {
+        g('mode').innerHTML = 'Normalbetrieb';
+      }
+      else if(data.mode == '2') {
+        g('mode').innerHTML = 'Nachtabsenkung';
+      }
+      }
+      
+      if(data.heating == '1') g('heating').innerHTML = 'aktiv';
+      else if(data.heating == '0') g('heating').innerHTML = 'nicht aktiv';
+
+          xhttp = null;
+          g('status').innerHTML = '';
+          updateTime = 0;
+        }
+      }
+    }
+    return false;
+  }
+  transmit();
+  setInterval(function () { g('ut').innerHTML = ++updateTime; }, 1000);
+  setInterval(transmit, 5000);
+</script>
+  </body></html>)";
+
+void httpServerHandleRoot() {
+  httpServer.send_P(200, "text/html", httpRoot);
+}
+
+void httpServerHandleNotFound() {
+  String message = "File Not Found\n\n";
+  message += "URI: ";
+  message += httpServer.uri();
+  message += "\nMethod: ";
+  message += (httpServer.method() == HTTP_GET) ? "GET" : "POST";
+  message += "\nArguments: ";
+  message += httpServer.args();
+  message += "\n";
+  for (uint8_t i = 0; i < httpServer.args(); i++) {
+    message += " " + httpServer.argName(i) + ": " + httpServer.arg(i) + "\n";
+  }
+  httpServer.send(404, "text/plain", message);
+}
+
+
+

BIN
src/WiFiThermostat/lib/Arduino-DHT22-master.zip


BIN
src/WiFiThermostat/lib/DHT.7z


BIN
src/WiFiThermostat/lib/esp8266-dht22-master.zip


+ 21 - 0
src/WiFiThermostat/lib/esp8266-dht22-master/LICENSE

@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2016 iotpipe
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 74 - 0
src/WiFiThermostat/lib/esp8266-dht22-master/README.md

@@ -0,0 +1,74 @@
+# esp8266-dht22
+A DHT library for the ESP8266
+
+This library builds on top of the ESP8266 SDK to support the DHTXX family of humidity and temperature sensors.  
+Supported models are:
+-DHT11
+-DHT21 (AM2301) 
+-DHT22 (AM2302)
+
+It is a port of the DHT Sensor library for the arduino created by @adafruit , which you can find [here](https://github.com/adafruit/DHT-sensor-library).
+
+Additional information about the DTHXX can be found in this [spec sheet](https://www.adafruit.com/datasheets/Digital%20humidity%20and%20temperature%20sensor%20AM2302.pdf).
+
+## Usage
+The library is comprised of a single header and source code file.  Simply include dht.h at the top of your program to get started.
+
+There are only 4 functions you'll need to read temperature and humidity data.
+```C
+/*Initializes the DHT.  User must specify which GPIO on the ESP8266 is connected to the DHT and which member of the DHTXX family is being used.  Options are DHT11, DHT21, AM2301, DHT22, AM2302.  This must be called before reading the DHT*/
+void DHT_init(uint8_t pin, uint8_t type);
+
+/*Prepare ESP8266 for reading the DHT.  This must be called before reading the DHT.*/
+void DHT_begin(void);
+
+/*Returns a floating point value of the temperature, or -1 if failed.  User can specify if they want value in Celsius or Fahrenheight*/
+float readTemperature(bool isFahrenheit);
+
+/*Returns a floating point value of the humidity, or -1 if failed.*/
+float readHumidity();
+```
+
+A a quick example, here is a sample user_main.c file which prints out the humidity and temperature every 3 seconds.
+```C
+#include "dht22.h"
+#define baud_rate 115200
+
+volatile os_timer_t read_humidity_timer;
+void read_humidity_timerfunc(void);
+
+void user_init(void)
+{
+        uart_div_modify(0, UART_CLK_FREQ / baud_rate); 
+        os_delay_us(10);
+
+        //Setup a timer to read DHT every 3 seconds, on repeat.
+        os_timer_setfn(&read_humidity_timer, (os_timer_func_t *)read_humidity_timerfunc, NULL);
+        os_timer_arm(&read_humidity_timer, 3000, 1);
+
+        //Declare we are using a DHT22 on Pin 14
+        DHT_init(14,DHT22);
+        DHT_begin();
+}
+
+
+void read_humidity_timerfunc(void)
+{
+        float t = readTemperature(false);
+        float h = readHumidity();
+        
+        os_printf("Temperature (C): %d\r\n", (int)t);
+        os_printf("Humidity (C): %d\r\n", (int)h);
+}
+```
+
+##What's been tested
+-DHT22 with an Adafruit Huzzah
+
+##Known issues
+The 1 wire communication bus relays on very exact timing.  During the signal reading process any interrupts will corrupt the result.  In Adafruit's Arduino implementation they disable all interrupts during the reading process.  The ESP8266 cannot disable all interrupts so if an interrupt does occur expect a bad result.  Luckily, bad results are returned as -1, so you have a way to verify.
+
+On the Adafruit Huzzah using certain pins will result in failure to read the signal if you don't power cycle your ESP8266 after flashing and after hitting the reset button.  So far, this has happened on Pins #2 and #4.  Pin #14, however, does not have this issue.  When in doubt, power cycle!
+
+##Contact the author
+Reach out on twitter [@iotpipe](https://twitter.com/iot_pipe)

+ 289 - 0
src/WiFiThermostat/lib/esp8266-dht22-master/dht22.c

@@ -0,0 +1,289 @@
+
+
+ 
+//DHT library for the ESP8266, a port from the Adafruit library for the Arduino
+//MIT license
+//written by IoT Pipe
+
+
+#include "dht22.h"
+
+#define MIN_INTERVAL 2000
+#define NUM_VALID_INPUT_PINS 8
+const uint32_t pin_mux[NUM_VALID_INPUT_PINS] = {PERIPHS_IO_MUX_GPIO0_U,PERIPHS_IO_MUX_GPIO2_U,PERIPHS_IO_MUX_GPIO4_U,PERIPHS_IO_MUX_GPIO5_U,PERIPHS_IO_MUX_MTDI_U,PERIPHS_IO_MUX_MTCK_U,PERIPHS_IO_MUX_MTMS_U,PERIPHS_IO_MUX_MTDO_U}; 
+const uint8_t pin_num[NUM_VALID_INPUT_PINS] = {0,2,4,5,12,13,14,15};
+const uint8_t pin_func[NUM_VALID_INPUT_PINS] = {FUNC_GPIO0, FUNC_GPIO2,FUNC_GPIO4,FUNC_GPIO5,FUNC_GPIO12,FUNC_GPIO13,FUNC_GPIO14,FUNC_GPIO15};
+
+
+float ICACHE_FLASH_ATTR convertCtoF(float c) {
+	return c * 1.8 + 32;
+}
+
+float ICACHE_FLASH_ATTR convertFtoC(float f) {
+	return (f - 32) * 0.55555;
+}
+
+static int ICACHE_FLASH_ATTR get_index(int pin)
+{
+	int i = 0;
+	for(i = 0; i < NUM_VALID_INPUT_PINS; i++)
+	{
+		if(pin==pin_num[i])
+		{
+			return i;
+		}
+	}
+	return -1;
+}
+
+void ICACHE_FLASH_ATTR DHT_begin(void) 
+{
+	LOG_DEBUG("DHT BEGIN");
+
+	// set up the pins!
+	int index = get_index(_pin);
+
+	gpio_init();
+	PIN_FUNC_SELECT(pin_mux[index],pin_func[index]); 
+	//GPIO_OUTPUT_SET(_pin,1);
+	GPIO_DIS_OUTPUT(_pin);
+	PIN_PULLUP_EN(pin_mux[index]);
+
+	// Using this value makes sure that millis() - lastreadtime will be >= MIN_INTERVAL right away. Note that this assignment wraps around, but so will the subtraction.
+	_lastreadtime = -MIN_INTERVAL;
+}
+
+static bool read() {
+
+	int index = get_index(_pin);
+
+	// Check if sensor was read less than two seconds ago and return early to use last reading. 
+	//This is todo.  The force argument overrides this logic.  We can implement in ESP8266 with a timer.
+	uint32 current =  system_get_time();
+	if ( current - _lastreadtime < 2000000 )
+	{	
+		LOG_DEBUG_ARGS("2 seconds is required between polls,  Its only been %d (ms)",(current-_lastreadtime) / 1000);
+		return _lastresult;
+	}
+	_lastreadtime=current;
+
+
+	// Reset 40 bits of received data to zero.
+	data[0] = data[1] = data[2] = data[3] = data[4] = 0;
+
+	// Send start signal.  See DHT datasheet for full signal diagram:
+	//   http://www.adafruit.com/datasheets/Digital%20humidity%20and%20temperature%20sensor%20AM2302.pdf
+
+	// Go into high impedence state to let pull-up raise data line level and
+	// start the reading process.
+	GPIO_OUTPUT_SET(_pin,1);
+	os_delay_us(250*1000);
+
+
+	// First set data line low for 10 milliseconds.
+	GPIO_OUTPUT_SET(_pin,0);
+	os_delay_us(10*1000);
+
+	uint32_t cycles[80];
+	{
+		// Turn off interrupts temporarily because the next sections are timing critical
+		// and we don't want any interruptions.
+		//TODO: We've disabled GPIO interrupts, but we haven't done anything about timers
+		ETS_GPIO_INTR_DISABLE();
+
+		// End the start signal by setting data line high for 40 microseconds.
+		GPIO_OUTPUT_SET(_pin,1);
+		os_delay_us(40);
+
+		// Now start reading the data line to get the value from the DHT sensor.
+		GPIO_DIS_OUTPUT(_pin);
+		PIN_PULLUP_EN(pin_mux[index]);
+
+		//os_delay_us(100);  // Delay a bit to let sensor pull data line low.
+
+		// First expect a low signal for ~80 microseconds followed by a high signal
+		// for ~80 microseconds again.
+		if (expectPulse(0) == 0) 
+		{
+			LOG_DEBUG("Timeout waiting for start signal low pulse.");
+			_lastresult = false;
+			return _lastresult;
+		}
+		if (expectPulse(1) == 0) 
+		{
+			LOG_DEBUG("Timeout waiting for start signal high pulse.");
+			_lastresult = false;
+			return _lastresult;
+		}
+
+		// Now read the 40 bits sent by the sensor.  Each bit is sent as a 50
+		// microsecond low pulse followed by a variable length high pulse.  If the
+		// high pulse is ~28 microseconds then it's a 0 and if it's ~70 microseconds
+		// then it's a 1.  We measure the cycle count of the initial 50us low pulse
+		// and use that to compare to the cycle count of the high pulse to determine
+		// if the bit is a 0 (high state cycle count < low state cycle count), or a
+		// 1 (high state cycle count > low state cycle count). Note that for speed all
+		// the pulses are read into a array and then examined in a later step.
+		int i = 0;
+		for (i=0; i<80; i+=2) 
+		{
+			cycles[i]   = expectPulse(0);
+			cycles[i+1] = expectPulse(1);
+		}
+	} // Timing critical code is now complete.
+	ETS_GPIO_INTR_ENABLE();
+
+	// Inspect pulses and determine which ones are 0 (high state cycle count < low
+	// state cycle count), or 1 (high state cycle count > low state cycle count).
+	int i = 0;
+	for (i=0; i<40; ++i) 
+	{
+		uint32_t lowCycles  = cycles[2*i];
+		uint32_t highCycles = cycles[2*i+1];
+		if ((lowCycles == 0) || (highCycles == 0)) 
+		{
+			LOG_DEBUG("Timeout waiting for pulse.");
+			_lastresult = false;
+			return _lastresult;
+		}
+		data[i/8] <<= 1;
+		// Now compare the low and high cycle times to see if the bit is a 0 or 1.
+		if (highCycles > lowCycles) 
+		{
+			// High cycles are greater than 50us low cycle count, must be a 1.
+			data[i/8] |= 1;
+		}
+		// Else high cycles are less than (or equal to, a weird case) the 50us low
+		// cycle count so this must be a zero.  Nothing needs to be changed in the
+		// stored data.
+	}
+
+	LOG_DEBUG_ARGS("Received: %d,%d,%d,%d,%d ?= %d",data[0],data[1],data[2],data[3],data[4],(data[0] + data[1] + data[2] + data[3]) & 0xFF );
+
+
+
+	// Check we read 40 bits and that the checksum matches.
+	if (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) 
+	{
+		_lastresult = true;
+	
+		float f = data[0];
+		f *= 256;
+		f += data[1];
+		f *= 0.1;
+
+		f = data[2] & 0x7F;
+	      	f *= 256;
+	      	f += data[3];
+	      	f *= 0.1;
+	      	if (data[2] & 0x80) {
+        		f *= -1;
+      		}
+		return _lastresult;
+	}
+	else 
+	{
+		LOG_DEBUG("Checksum failure!");
+		_lastresult = false;
+		return _lastresult;
+	}
+}
+
+// Expect the signal line to be at the specified level for a period of time and
+// return a count of loop cycles spent at that level (this cycle count can be
+// used to compare the relative time of two pulses).  If more than a millisecond
+// ellapses without the level changing then the call fails with a 0 response.
+// This is adapted from Arduino's pulseInLong function (which is only available
+// in the very latest IDE versions):
+//   https://github.com/arduino/Arduino/blob/master/hardware/arduino/avr/cores/arduino/wiring_pulse.c
+uint32_t expectPulse(bool level) 
+{
+	uint32_t count = 0;
+	while (GPIO_INPUT_GET(_pin) == level) 
+	{
+		if (count++ >= _maxcycles) 
+		{
+			LOG_DEBUG_ARGS("Max cycles reached: %d",count);
+			return 0; // Exceeded timeout, fail.
+      		}
+    	}
+	return count;
+}
+
+void DHT_init(uint8_t pin, uint8_t type, uint8_t count) 
+{
+	LOG_DEBUG("DHT_INIT");
+	_pin = pin;
+	_type = type;
+
+	//_maxcycles gives thenumber of cycles in a millisecond. this is used as a timeout in other functions.
+
+	//bit11~bit0 are decimal part
+	uint32_t cal = system_rtc_clock_cali_proc();
+	uint32_t int_part = ((cal*1000) >> 12) / 1000;// + ( (float)(((cal*1000)>>12)%1000 ) / 1000.0f);
+	uint32_t dec_part = ((cal * 1000) >> 12) % 1000; 
+
+	float result = int_part + (float)dec_part/1000.0f;
+
+	_maxcycles = 1000.0f / result;
+	LOG_DEBUG_ARGS("max cycles: %d",(int)_maxcycles);
+}
+
+
+float readHumidity()
+{
+	float f = -1;
+	if (read()) 
+	{
+		switch (_type) 
+		{
+			case DHT11:
+				f = data[0];
+				break;
+			case DHT22:
+			case DHT21:
+				f = data[0];
+				f *= 256;
+				f += data[1];
+				f *= 0.1;
+				break;
+		}
+	}
+	return f;
+}
+
+//boolean S == Scale.  True == Fahrenheit; False == Celcius
+float readTemperature(bool S) {
+	float f = -1;
+
+	if (read()) 
+	{
+		switch (_type) 
+		{
+			case DHT11:
+				f = data[2];
+				if(S) 
+				{
+					f = convertCtoF(f);
+				}
+			break;
+			case DHT22:
+			case DHT21:
+				f = data[2] & 0x7F;
+				f *= 256;
+				f += data[3];
+				f *= 0.1;
+				if (data[2] & 0x80) 
+				{
+					f *= -1;
+				}
+				if(S) 
+				{
+					f = convertCtoF(f);
+				}
+				break;
+		}
+	}
+	return f;
+}
+

+ 54 - 0
src/WiFiThermostat/lib/esp8266-dht22-master/dht22.h

@@ -0,0 +1,54 @@
+/* 
+DHT library for the ESP8266, a port from the Adafruit library for the Arduino
+MIT license
+written by IoT Pipe
+*/
+
+#ifndef DHT22_H
+#define DHT22_H
+
+#include "ets_sys.h"
+#include "osapi.h"
+#include "os_type.h"
+#include "user_config.h"
+#include "mem.h"
+#include "user_interface.h"
+
+#include "gpio.h"
+// Uncomment to enable printing out nice debug messages.
+//#define DHT_DEBUG
+
+// Setup debug printing macros.
+#ifdef DHT_DEBUG
+	#define LOG_DEBUG(message)		do {os_printf("[DHT-DEBUG] %s", message); os_printf("\r\n");} while (0)
+	#define LOG_DEBUG_ARGS(message, args...)		do {os_printf("[DHT-DEBUG] "); os_printf(message, args); os_printf("\r\n");} while (0)
+#else
+	#define LOG_DEBUG(message) do {} while(0)
+	#define LOG_DEBUG_ARGS(message, args...) do {} while(0)
+#endif
+
+// Define types of sensors.
+#define DHT11 11
+#define DHT22 22
+#define DHT21 21
+#define AM2301 21
+
+
+static uint8_t data[5];
+static uint8_t _pin, _type, _bit, _type;
+static uint32_t _lastreadtime, _maxcycles;
+static bool _lastresult;
+static uint32_t expectPulse(bool level);
+static int ICACHE_FLASH_ATTR get_index(int pin);
+static bool read();
+
+
+
+void DHT_init(uint8_t pin, uint8_t type, uint8_t count);
+void DHT_begin(void);
+float readTemperature(bool S);
+float readHumidity();
+float ICACHE_FLASH_ATTR convertCtoF(float);
+float ICACHE_FLASH_ATTR convertFtoC(float);
+
+#endif