123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517 |
- #define VERSION "0.1.1"
- #include <ESP8266WiFi.h> //ESP8266 Core WiFi Library (you most likely already have this in your sketch)
- #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 <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;
- float setTemp;
- 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
- 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";
- const char* mqtt_topic_settemp = "Test/Thermostat/SetTemp";
- //const char* mqtt_topic_setmode = "Test/Thermostat/SetMode";
- const char* mqtt_topic_hum = "Test/Thermostat/Hum";
- const char* mqtt_topic_lux = "Test/Thermostat/Lux";
- 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";
- DHT dht(PIN_DHTSENSOR, DHTTYPE);
- // global variables from other modules
- extern bool displayActive;
- //AS_BH1750 lightMeter; // Lichtstärkemessung mit BH1750
- 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);
- /////
- WiFi.begin(ssid, password);
- while (WiFi.status() != WL_CONNECTED) {
- delay(500);
- Serial.print(".");
- }
- randomSeed(micros());
- Serial.println("");
- Serial.println("WiFi connected");
- Serial.println("IP address: ");
- Serial.println(WiFi.localIP());
- }
- void callback(char* topic, byte* payload, unsigned int length) {
- Serial.print("Message arrived [");
- Serial.print(topic);
- Serial.print("] ");
- for (int i = 0; i < length; i++) {
- Serial.print((char)payload[i]);
- }
- 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] == ' ' ) {
- char inValue[length - 9 + 1];
- for (int i = 0; i < length; i++) {
- inValue[i] = (char)payload[i + 9];
- }
- inValue[sizeof(inValue) - 1] = '\0';
- Serial.print(inValue);
- Serial.println();
- float invalueFloat = round(atof(inValue) * 2.0) / 2.0;
- Serial.print(invalueFloat);
- if (invalueFloat >= setTempMin && invalueFloat <= setTempMax) {
- setTempDay = invalueFloat;
- lastMsg = 0; // reset var lastMsg to speed up lcd update
- }
- else if (invalueFloat > setTempMax) {
- setTempDay = setTempMax;
- lastMsg = 0; // reset var lastMsg to speed up lcd update
- }
- else if (invalueFloat < setTempMin) {
- setTempDay = setTempMin;
- lastMsg = 0; // reset var lastMsg to speed up lcd update
- }
- }
- else if ((char)payload[4] == 't' && \
- (char)payload[5] == 'l' && \
- (char)payload[6] == 'o' && \
- (char)payload[7] == 'w' && \
- (char)payload[8] == ' ' ) {
- char inValue[length - 9 + 1];
- for (int i = 0; i < length; i++) {
- inValue[i] = (char)payload[i + 9];
- }
- inValue[sizeof(inValue) - 1] = '\0';
- Serial.print(inValue);
- Serial.println();
- float invalueFloat = round(atof(inValue) * 2.0) / 2.0;
- Serial.print(invalueFloat);
- if (invalueFloat >= setTempMinLow && invalueFloat <= setTempMaxLow) {
- setTempNight = invalueFloat;
- lastMsg = 0; // reset var lastMsg to speed up lcd update
- }
- else if (invalueFloat > setTempMaxLow) {
- setTempNight = setTempMaxLow;
- lastMsg = 0; // reset var lastMsg to speed up lcd update
- }
- else if (invalueFloat < setTempMinLow) {
- setTempNight = setTempMinLow;
- lastMsg = 0; // reset var lastMsg to speed up lcd update
- }
- }
- else if ((char)payload[4] == 'm' && \
- (char)payload[5] == 'o' && \
- (char)payload[6] == 'd' && \
- (char)payload[7] == 'e' && \
- (char)payload[8] == ' ' ) {
- if ((char)payload[9] == '1') {
- // switch to mode default/day
- heatingMode = 1;
- lastMsg = 0; // reset var lastMsg to speed up lcd update
- }
- else if ((char)payload[9] == '2') {
- // switch to mode night/reduction
- heatingMode = 2;
- lastMsg = 0; // reset var lastMsg to speed up lcd update
- }
- }
- else if ((char)payload[4] == 'e' && \
- (char)payload[5] == 'n' && \
- (char)payload[6] == 'a' && \
- (char)payload[7] == 'b' && \
- (char)payload[8] == ' ' ) {
- if ((char)payload[9] == '0') {
- // switch heating off
- heatingEnabled = false;
- lastMsg = 0; // reset var lastMsg to speed up lcd update
- }
- else if ((char)payload[9] == '1') {
- // switch heating on
- heatingEnabled = true;
- lastMsg = 0; // reset var lastMsg to speed up lcd update
- }
- }
- }
- }
- 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);
- }
- }
- }
- void setup() {
- //WiFiManager wifiManager;
- //wifiManager.autoConnect("Thermostat", "configesp");
- //wifiManager.setConfigPortalTimeout(180);
- Serial.begin(115200);
- delay(300);
- Serial.print("WiFi Thermostat v");
- Serial.print(VERSION);
- Serial.println(" by Flo Kra");
- Serial.println("starting...");
- pinMode(PIN_RELAIS, OUTPUT);
- digitalWrite(PIN_RELAIS, HIGH);
- pinMode(PIN_BUTTON_PLUS, INPUT_PULLUP);
- pinMode(PIN_BUTTON_MINUS, INPUT_PULLUP);
- pinMode(PIN_BUTTON_MODE, INPUT_PULLUP);
- // DHT11/22 Temp/Hum-Sensor initialisieren
- 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);
- 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);
- initDisplay();
- }
- void loop() {
- httpServer.handleClient();
- if (!client.connected()) {
- reconnect();
- }
- client.loop();
- checkButtonStates();
- handleDisplayTimeout();
- if ( (millis() - lastMsg) > measureinterval) {
- lastMsg = millis();
- humidity = dht.readHumidity();
- temperature = dht.readTemperature(); // Read temperature as Celsius (the default)
- unsigned long heatingOnTime, heatingOffTime;
- if (heatingEnabled && turnHeatingOn) {
- heatingOnTime = (millis() - heatingLastOffMillis) / 1000;
- Serial.print("heatingOnTime: ");
- Serial.print(heatingOnTime);
- Serial.println();
- }
- else if (heatingEnabled && !turnHeatingOn) {
- heatingOffTime = (millis() - heatingLastOnMillis) / 1000;
- Serial.print("heatingOffTime: ");
- Serial.print(heatingOffTime);
- 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();
- client.publish(mqtt_topic_heating, "off");
- //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");
- Serial.print("last offTime: ");
- Serial.print(heatingOffTime);
- Serial.println();
- client.publish(mqtt_topic_heating, "on");
- //client.publish(mqtt_topic_heating_lastofftime, heatingOffTime);
- }
- // 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;
- }
- // 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);
- // client.publish(mqtt_topic_lux, lux_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...
- 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 );
- 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);
- 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("%");
- // display current mode on LCD
- lcd.setCursor(13, 0); // to char 15, line 1
- if (heatingEnabled) {
- if ( heatingMode == 1 ) { // day/normal mode
- lcd.print(" ");
- lcd.write((uint8_t)1); // sun symbol if mode is day/normal
- lcd.print(" ");
- }
- else if ( heatingMode == 2 ) { // night/reduction mode
- lcd.print(" ");
- lcd.write((uint8_t)0); // moon symbol if mode is night/reduction
- lcd.print(" ");
- }
- }
- else lcd.print(" "); // mode is heating off
- // display target temperature to line 2, 8 chars length incl space at the end
- lcd.setCursor(0, 1);
- // when the heating mode is OFF, do not display target temp - instead show "Heating off" info in line 2
- if ( !heatingEnabled ) {
- // 1234567890123456
- lcd.print(" Heizung aus ");
- }
- else {
- lcd.write((uint8_t)2); // Pfeil rechts
- lcd.print(" ");
- lcd.print(setTemp_chararr);
- lcd.write(0xDF); // degree symbol
- lcd.print(" ");
- // display status info to line 2 from char 9 -> 8 chars length
- lcd.setCursor(8, 1);
- if (turnHeatingOn) {
- // 12345678
- lcd.print("heizen..");
- }
- else if ( heatingMode == 1 ) { // day/normal mode
- // 12345678
- lcd.print(" ");
- }
- else if ( heatingMode == 2 ) { // night/reduction mode
- // 12345678
- lcd.print("N-Absenk");
- }
- else lcd.print(" ");
- }
- }
- // 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;
- //}
- }
|