From 0696e3f293e7e7e05cc148a0370816a9f16ea8f1 Mon Sep 17 00:00:00 2001 From: Ronald Schaten Date: Wed, 30 Mar 2016 21:08:18 +0200 Subject: [PATCH] complete rewrite, now based on homie-esp8266 --- things.ino | 569 ++++++++++++++--------------------------------------- 1 file changed, 146 insertions(+), 423 deletions(-) diff --git a/things.ino b/things.ino index a80a39b..b00b8a9 100644 --- a/things.ino +++ b/things.ino @@ -1,85 +1,86 @@ -// based on example code from the used libraries +#include // https://github.com/marvinroger/homie-esp8266 +#include // https://github.com/adafruit/DHT-sensor-library -#include // this needs to be first, or it all crashes and burns... -extern "C" { - #include -} -#include // https://github.com/esp8266/Arduino -#include -#include // https://github.com/tzapu/WiFiManager -#include -#include -#include // https://github.com/knolleary/pubsubclient -#include // https://github.com/adafruit/DHT-sensor-library -#include // https://github.com/bblanchon/ArduinoJson +#define HAS_LDR +#define HAS_LED +#undef HAS_DHT -#define HARDWARE_WITTY +// HAS_LED +#define PIN_LED_RED D8 +#define PIN_LED_GREEN D6 +#define PIN_LED_BLUE D7 +HomieNode ledNode("led", "rgb"); +int led_red = 0; +int led_green = 0; +int led_blue = 0; -// configure DHT sensor -#define DHTPIN D4 // what pin the DHT is connected to -//#define DHTTYPE DHT11 // DHT11 -//#define DHTTYPE DHT21 // DHT21 (AM2301) -#define DHTTYPE DHT22 // DHT22 (AM2302) +// HAS_LDR +#define PIN_LDR A0 +HomieNode ldrNode("ldr", "ldr"); +const int INTERVAL_LDR = 60; +unsigned long lastSentLDR = 0; +int ldr = 0; -#ifdef HARDWARE_WITTY - #define CONFIGPIN D2 // config-button is connected to this pin -#else - #define CONFIGPIN D3 // config-button is connected to this pin -#endif +// HAS_DHT +#define PIN_DHT D4 +#define TYPE_DHT DHT22 +HomieNode humidityNode("humidity", "humidity"); +HomieNode temperatureNode("temperature", "temperature"); +HomieNode heatindexNode("heatindex", "heatindex"); +const int INTERVAL_DHT = 60; +unsigned long lastSentDHT = 0; +DHT dht(PIN_DHT, TYPE_DHT); +float humidity, temperature; // raw values from the sensor +float heatindex; // computed value from the sensor -#define RGBRED D8 // red led channel on witty module -#define RGBGRN D6 // green led channel on witty module -#define RGBBLU D7 // blue led channel on witty module - -#define LDRPIN A0 // analog LDR input on witty module - -// define default values here, overwritten by values from config.json -char mqtt_server[40]; -char mqtt_port[6] = "1883"; -char mqtt_topic[34] = "OutTopic"; -bool capability_dht = true; -bool capability_ldr = true; -bool capability_rgb = true; - -// flag for saving data -bool shouldSaveConfig = false; - -// callback notifying us of the need to save config -void saveConfigCallback() { - Serial.println("Should save config"); - shouldSaveConfig = true; +void setupHandler() { + #ifdef HAS_LDR + pinMode(PIN_LDR, INPUT); + #endif + #ifdef HAS_LED + pinMode(PIN_LED_RED, OUTPUT); + pinMode(PIN_LED_GREEN, OUTPUT); + pinMode(PIN_LED_BLUE, OUTPUT); + analogWrite(PIN_LED_RED, led_red); + analogWrite(PIN_LED_GREEN, led_green); + analogWrite(PIN_LED_BLUE, led_blue); + #endif + #ifdef HAS_DHT + dht.begin(); + #endif } -// initialize modules -ESP8266WebServer http_server(80); // webserver -DHT dht(DHTPIN, DHTTYPE); // DHT sensor -Ticker ticker; // LED status +bool ledColorHandler(String message) { + DynamicJsonBuffer json_inBuffer; + JsonObject& json_in = json_inBuffer.parseObject(message); + if (json_in.success()) { + if (json_in.containsKey("red")) { + led_red = json_in["red"]; + analogWrite(PIN_LED_RED, led_red); + } + if (json_in.containsKey("green")) { + led_green = json_in["green"]; + analogWrite(PIN_LED_GREEN, led_green); + } + if (json_in.containsKey("blue")) { + led_blue = json_in["blue"]; + analogWrite(PIN_LED_BLUE, led_blue); + } + } else { + Serial.println("parsing of JSON failed"); + } -WiFiClient wifiClient; -PubSubClient mqtt_client(wifiClient); - -bool dhtvalid = false; // indicate if measurement is valid -float humidity, temperature; // raw values from the sensor -float heatindex; // computed value from the sensor -char str_humidity[10], str_temperature[10]; // rounded values as strings -char str_heatindex[10]; // rounded value as string -unsigned long previousMillis = 0; // last sensor read -const long interval = 2000; // interval between readings - -long lastMsg = 0; - -// toggle LED state -void toggle_led() { - int state = digitalRead(BUILTIN_LED); // get the current state LED - digitalWrite(BUILTIN_LED, !state); // set the opposite state -} - -// gets called when WiFiManager enters configuration mode -void configModeCallback (WiFiManager *myWiFiManager) { - Serial.println("Entered config mode"); - Serial.println(WiFi.softAPIP()); - Serial.println(myWiFiManager->getConfigPortalSSID()); - ticker.attach(0.1, toggle_led); // toggle led faster + DynamicJsonBuffer json_outBuffer; + JsonObject& json_out = json_outBuffer.createObject(); + json_out["red"] = led_red; + json_out["green"] = led_green; + json_out["blue"] = led_blue; + String response; + json_out.printTo(response); + Serial.print("led state: "); + Serial.println(response); + Homie.setNodeProperty(ledNode, "color", response); + return true; } // compare float values @@ -87,22 +88,26 @@ bool isEqual(float a, float b, float epsilon=0.001) { return fabs(a - b) <= epsilon * fabs(a); } -// concatenate MQTT topic prefix to individual topic -char* topic(const char* this_topic) { - static char topic[34]; - strcpy(topic, mqtt_topic); - strcat(topic, "/"); - strcat(topic, this_topic); - return topic; +void loopHandlerLDR() { + if (millis() - lastSentLDR >= INTERVAL_LDR * 1000UL || lastSentLDR == 0) { + int ldr_new = analogRead(PIN_LDR); + if (ldr_new != ldr) { + ldr = ldr_new; + float ldr_float = map(ldr, 0, 1023, 0, 10000) / 100.0; + Serial.print("LDR: "); + Serial.println(ldr_float); + if (!Homie.setNodeProperty(ldrNode, "value", String(ldr_float), true)) { + Serial.println("Sending failed"); + } + } else { + Serial.println("LDR value unchanged"); + } + lastSentLDR = millis(); + } } -// get values from DHT sensor -void read_sensor() { - // wait at least 2 seconds seconds between measurements - unsigned long currentMillis = millis(); - - if (currentMillis - previousMillis >= interval) { - previousMillis = currentMillis; +void loopHandlerDHT() { + if (millis() - lastSentDHT >= INTERVAL_DHT * 1000UL || lastSentDHT == 0) { float previousHumidity = humidity; float previousTemperature = temperature; float previousHeatindex = heatindex; @@ -110,356 +115,74 @@ void read_sensor() { temperature = dht.readTemperature(); // read temperature as Celsius heatindex = dht.computeHeatIndex(temperature, humidity, false); - // check if any reads failed and exit early (to try again) + // check if any reads failed and exit early if (isnan(humidity) || isnan(temperature)) { - dhtvalid = false; Serial.println("Failed to read from DHT sensor!"); - strcpy(str_humidity, "invalid"); - strcpy(str_temperature, "invalid"); - strcpy(str_heatindex, "invalid"); return; - } else { - dhtvalid = true; } - // convert the floats to strings and round to 2 decimal places - dtostrf(humidity, 1, 2, str_humidity); - dtostrf(temperature, 1, 2, str_temperature); - dtostrf(heatindex, 1, 2, str_heatindex); - if (!isEqual(humidity, previousHumidity)) { - mqtt_client.publish(topic("humidity"), str_humidity); - } - if (!isEqual(temperature, previousTemperature)) { - mqtt_client.publish(topic("temperature"), str_temperature); - } - if (!isEqual(heatindex, previousHeatindex)) { - mqtt_client.publish(topic("heatindex"), str_heatindex); - } - - Serial.print("Humidity: "); - Serial.print(str_humidity); - Serial.print(" %\t"); - Serial.print("Temperature: "); - Serial.print(str_temperature); - Serial.print(" °C\t"); - Serial.print("Heat Index: "); - Serial.print(str_heatindex); - Serial.println(" °C"); - } -} - -// callback for MQTT, gets called if we receive a message -void mqtt_callback(char* topic, byte* payload, unsigned int length) { - char inData[length+1]; - for(int i = 0; i < length; i++) { - inData[i] = (char)payload[i]; - } - inData[length] = 0; - Serial.print("Message arrived ["); - Serial.print(topic); - Serial.print("] "); - Serial.println(inData); - - StaticJsonBuffer<200> jsonBuffer; - JsonObject& json = jsonBuffer.parseObject(inData); - analogWrite(RGBRED, json["red"]); - analogWrite(RGBGRN, json["green"]); - analogWrite(RGBBLU, json["blue"]); -} - -// make sure we're connected to MQTT broker -void mqtt_reconnect() { - // loop until we're reconnected - while (!mqtt_client.connected()) { - Serial.print("Attempting MQTT connection..."); - // attempt to connect - if (mqtt_client.connect(wifi_station_get_hostname(), topic("online"), MQTTQOS1, true, "0")) { - Serial.println("connected"); - // once connected, publish an announcement... - mqtt_client.publish(topic("online"), "1", true); - // ... and resubscribe: - mqtt_client.subscribe("setrgb"); + Serial.print("humidity: "); + Serial.println(humidity); + if (!Homie.setNodeProperty(humidityNode, "value", String(humidity), true)) { + Serial.println("Sending failed"); + } } else { - Serial.print("failed, rc="); - Serial.print(mqtt_client.state()); - Serial.println(" try again in 5 seconds"); - delay(5000); + Serial.println("humidity unchanged"); } + + if (!isEqual(temperature, previousTemperature)) { + Serial.print("temperature: "); + Serial.println(temperature); + if (!Homie.setNodeProperty(temperatureNode, "value", String(temperature), true)) { + Serial.println("Sending failed"); + } + } else { + Serial.println("temperature unchanged"); + } + + if (!isEqual(heatindex, previousHeatindex)) { + Serial.print("heatindex: "); + Serial.println(heatindex); + if (!Homie.setNodeProperty(heatindexNode, "value", String(heatindex), true)) { + Serial.println("Sending failed"); + } + } else { + Serial.println("heatindex unchanged"); + } + + lastSentDHT = millis(); } } -// convert string to integer -int stringToNumber(String thisString) { - int i, value, length; - length = thisString.length(); - char blah[(length + 1)]; - for (i = 0; i < length; i++) { - blah[i] = thisString.charAt(i); - } - blah[i] = 0; - value = atoi(blah); - return value; +void loopHandler() { + #ifdef HAS_LDR + loopHandlerLDR(); + #endif + #ifdef HAS_DHT + loopHandlerDHT(); + #endif } void setup() { - // put your setup code here, to run once: - Serial.begin(9600); - - pinMode(BUILTIN_LED, OUTPUT); // set led pin as output - ticker.attach(0.5, toggle_led); // toggle led slowly during initialization - - pinMode(RGBRED, OUTPUT); - pinMode(RGBGRN, OUTPUT); - pinMode(RGBBLU, OUTPUT); - - pinMode(CONFIGPIN, INPUT); // flash-button on nodemcu - pinMode(LDRPIN, INPUT); - - // clean FS, for testing - //SPIFFS.format(); - - // read configuration from FS json - Serial.println("mounting FS..."); - - if (SPIFFS.begin()) { - Serial.println("mounted file system"); - if (SPIFFS.exists("/config.json")) { - // file exists, reading and loading - Serial.println("reading config file"); - File configFile = SPIFFS.open("/config.json", "r"); - if (configFile) { - Serial.println("opened config file"); - size_t size = configFile.size(); - // allocate a buffer to store contents of the file. - std::unique_ptr buf(new char[size]); - configFile.readBytes(buf.get(), size); - DynamicJsonBuffer jsonBuffer; - JsonObject& json = jsonBuffer.parseObject(buf.get()); - json.printTo(Serial); - if (json.success()) { - Serial.println("\nparsed json"); - strcpy(mqtt_server, json["mqtt_server"]); - strcpy(mqtt_port, json["mqtt_port"]); - strcpy(mqtt_topic, json["mqtt_topic"]); - capability_dht = json["capability_dht"]; - capability_ldr = json["capability_ldr"]; - capability_rgb = json["capability_rgb"]; - } else { - Serial.println("failed to load json config"); - } - } - } - } else { - Serial.println("failed to mount FS"); - } - - // WiFiManager - // extra parameters to be configured - WiFiManagerParameter custom_mqtt_server("server", "mqtt server", mqtt_server, 40); - WiFiManagerParameter custom_mqtt_port("port", "mqtt port", mqtt_port, 5); - WiFiManagerParameter custom_mqtt_topic("topic", "mqtt topic", mqtt_topic, 32); - WiFiManagerParameter custom_capability_dht("dht", "capability dht", capability_dht ? "true" : "false", 5); - WiFiManagerParameter custom_capability_ldr("ldr", "capability ldr", capability_ldr ? "true" : "false", 5); - WiFiManagerParameter custom_capability_rgb("rgb", "capability rgb", capability_rgb ? "true" : "false", 5); - - // local intialization - WiFiManager wifiManager; - - // reset settings if config-button is pressed - if (!digitalRead(CONFIGPIN)) { - Serial.println("config-button pressed, resetting wifi settings"); - wifiManager.resetSettings(); - } - - // set callback that gets called when connecting to previous WiFi fails, and enters Access Point mode - wifiManager.setAPCallback(configModeCallback); - - // set config save notify callback - wifiManager.setSaveConfigCallback(saveConfigCallback); - - // add all your parameters here - wifiManager.addParameter(&custom_mqtt_server); - wifiManager.addParameter(&custom_mqtt_port); - wifiManager.addParameter(&custom_mqtt_topic); - wifiManager.addParameter(&custom_capability_dht); - wifiManager.addParameter(&custom_capability_ldr); - wifiManager.addParameter(&custom_capability_rgb); - - // fetches ssid and pass and tries to connect - // if it does not connect it starts an access point - if (!wifiManager.autoConnect()) { - Serial.println("failed to connect and hit timeout"); - // reset and try again - ESP.reset(); - delay(1000); - } - - Serial.println("connected to WiFi"); - ticker.detach(); - digitalWrite(BUILTIN_LED, LOW); - - // read updated parameters - strcpy(mqtt_server, custom_mqtt_server.getValue()); - strcpy(mqtt_port, custom_mqtt_port.getValue()); - strcpy(mqtt_topic, custom_mqtt_topic.getValue()); - capability_dht = custom_capability_dht.getValue()[0] == 't'; - capability_ldr = custom_capability_ldr.getValue()[0] == 't'; - capability_rgb = custom_capability_rgb.getValue()[0] == 't'; - - // save the custom parameters to FS - if (shouldSaveConfig) { - Serial.println("saving config"); - DynamicJsonBuffer jsonBuffer; - JsonObject& json = jsonBuffer.createObject(); - json["mqtt_server"] = mqtt_server; - json["mqtt_port"] = mqtt_port; - json["mqtt_topic"] = mqtt_topic; - json["capability_dht"] = capability_dht; - json["capability_ldr"] = capability_ldr; - json["capability_rgb"] = capability_rgb; - - File configFile = SPIFFS.open("/config.json", "w"); - if (!configFile) { - Serial.println("failed to open config file for writing"); - } - - json.printTo(Serial); - json.printTo(configFile); - configFile.close(); - } - - mqtt_client.setServer(mqtt_server, stringToNumber(mqtt_port)); - mqtt_client.setCallback(mqtt_callback); - - dht.begin(); - - // initial read - read_sensor(); - mqtt_client.publish(topic("humidity"), str_humidity); - mqtt_client.publish(topic("temperature"), str_temperature); - mqtt_client.publish(topic("heatindex"), str_heatindex); - - // handle http requests - http_server.on("/", [](){ - read_sensor(); - String response = "\r\n"; - response += "\r\n"; - response += "\r\n"; - response += "\r\n"; - response += "\r\n"; - response += "Status\r\n"; - response += "\r\n"; - response += "\r\n"; - response += "\r\n"; - response += "
\r\n"; - response += "

"; - response += mqtt_topic; - response += "

\r\n"; - response += "

Sensor Status

\r\n"; - response += "\r\n"; - response += "\r\n"; - response += "\r\n"; - response += "\r\n"; - } - response += "
MQTT Server"; - response += mqtt_server; - response += ":"; - response += mqtt_port; - if (capability_dht) { - response += "
Temperature"; - response += str_temperature; - response += "°C
Humidity"; - response += str_humidity; - response += "%RH
Heat Index"; - response += str_heatindex; - response += "°C
\r\n"; - response += "
\r\n"; - response += "
\r\n"; - response += "\r\n"; - response += "\n"; - http_server.send(200, "text/html", response); - delay(100); - }); - - http_server.on("/values", [](){ - read_sensor(); - String response = "updatetime\t"; - response += previousMillis; - response += "\n"; - response += "temperature\t"; - response += str_temperature; - response += "\n"; - response += "humidity\t"; - response += str_humidity; - response += "\n"; - response += "heatindex\t"; - response += str_heatindex; - response += "\n"; - http_server.send(200, "text/plain", response); - delay(100); - }); - - http_server.on("/json", [](){ - read_sensor(); - DynamicJsonBuffer jsonBuffer; - JsonObject& json = jsonBuffer.createObject(); - JsonObject& mqtt = json.createNestedObject("mqtt"); - mqtt["server"] = mqtt_server; - mqtt["port"] = mqtt_port; - mqtt["topic"] = mqtt_topic; - if (capability_dht) { - JsonObject& dht = json.createNestedObject("dht"); - dht["temperature"] = str_temperature; - dht["humidity"] = str_humidity; - dht["heatindex"] = str_heatindex; - } - String response; - json.printTo(response); - http_server.send(200, "text/plain", response); - delay(100); - }); - - http_server.on("/config", [](){ - read_sensor(); - DynamicJsonBuffer jsonBuffer; - JsonObject& json = jsonBuffer.createObject(); - JsonObject& mqtt = json.createNestedObject("mqtt"); - mqtt["server"] = mqtt_server; - mqtt["port"] = mqtt_port; - mqtt["topic"] = mqtt_topic; - JsonObject& capability = json.createNestedObject("capability"); - capability["dht"] = capability_dht; - capability["ldr"] = capability_ldr; - capability["rgb"] = capability_rgb; - String response; - json.printTo(response); - http_server.send(200, "text/plain", response); - delay(100); - }); - - // start the web server - http_server.begin(); - Serial.println("HTTP server started"); + Homie.setFirmware("things", "1.0.0"); + #ifdef HAS_LDR + Homie.registerNode(ldrNode); + #endif + #ifdef HAS_LED + ledNode.subscribe("color", ledColorHandler); + Homie.registerNode(ledNode); + #endif + #ifdef HAS_DHT + Homie.registerNode(humidityNode); + Homie.registerNode(temperatureNode); + Homie.registerNode(heatindexNode); + #endif + Homie.setSetupFunction(setupHandler); + Homie.setLoopFunction(loopHandler); + Homie.setup(); } void loop() { - // listen for http requests - http_server.handleClient(); - - if (!mqtt_client.connected()) { - mqtt_reconnect(); - } - mqtt_client.loop(); - - long now = millis(); - if (now - lastMsg > 10000) { - lastMsg = now; - read_sensor(); - } + Homie.loop(); }