|
@@ -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
|
|
|
|