diff options
Diffstat (limited to 'oliver/lr_stripes')
| -rw-r--r-- | oliver/lr_stripes/platformio.ini | 1 | ||||
| -rw-r--r-- | oliver/lr_stripes/src/main.cpp | 208 |
2 files changed, 113 insertions, 96 deletions
diff --git a/oliver/lr_stripes/platformio.ini b/oliver/lr_stripes/platformio.ini index c6d35d4..06b3430 100644 --- a/oliver/lr_stripes/platformio.ini +++ b/oliver/lr_stripes/platformio.ini | |||
| @@ -13,6 +13,7 @@ default_envs = nodemcuv2 | |||
| 13 | [env:nodemcuv2] | 13 | [env:nodemcuv2] |
| 14 | platform = espressif8266 | 14 | platform = espressif8266 |
| 15 | board = nodemcuv2 | 15 | board = nodemcuv2 |
| 16 | lib_deps = WiFiManager, PubSubClient, Bounce2 | ||
| 16 | framework = arduino | 17 | framework = arduino |
| 17 | monitor_speed = 115200 | 18 | monitor_speed = 115200 |
| 18 | upload_speed = 115200 | 19 | upload_speed = 115200 |
diff --git a/oliver/lr_stripes/src/main.cpp b/oliver/lr_stripes/src/main.cpp index b55a198..3fe2238 100644 --- a/oliver/lr_stripes/src/main.cpp +++ b/oliver/lr_stripes/src/main.cpp | |||
| @@ -1,21 +1,18 @@ | |||
| 1 | #include <Arduino.h> | 1 | #include <Arduino.h> |
| 2 | #include <ESP8266mDNS.h> | 2 | #include <ESP8266mDNS.h> |
| 3 | #include <PubSubClient.h> | ||
| 4 | #include <WiFiManager.h> | 3 | #include <WiFiManager.h> |
| 5 | #include <Bounce2.h> | 4 | #include <Bounce2.h> |
| 5 | #include <PubSubClient.h> | ||
| 6 | #include <ESP8266httpUpdate.h> | 6 | #include <ESP8266httpUpdate.h> |
| 7 | 7 | ||
| 8 | #define _STR(s) #s | 8 | #include "secrets.h" |
| 9 | #define STR(s) _STR(s) | ||
| 10 | 9 | ||
| 11 | const char* mqtt_server = "192.168.1.2"; //MQTT Server IP, your home MQTT server eg Mosquitto on RPi, or some public MQTT | 10 | #define MQTT_BROKER "192.168.1.5" |
| 12 | const int mqtt_port = 1883; //MQTT Server PORT, default is 1883 but can be anything. | 11 | #define MQTT_BROKER_PORT 1883 |
| 12 | //#define MQTT_USERNAME "" | ||
| 13 | //#define MQTT_PASSWORD "" | ||
| 14 | #define MQTT_BASE "home/livingroom/ledstripe" | ||
| 13 | 15 | ||
| 14 | const char* mqtt_pingall_sub = "home/pingall"; | ||
| 15 | const char* mqtt_pingall_pub = "home/pingall/response"; | ||
| 16 | |||
| 17 | #define MQTT_BASE "home/livingroom/ledstripe" | ||
| 18 | const char* mqtt_device_boot = MQTT_BASE "/device"; | ||
| 19 | 16 | ||
| 20 | enum sensor_type : uint8_t | 17 | enum sensor_type : uint8_t |
| 21 | { | 18 | { |
| @@ -77,19 +74,37 @@ struct sensor_t sensors[] = { | |||
| 77 | 74 | ||
| 78 | #define DIMMER_FADE_DELAY 40 // Delay in ms for each percentage fade up/down (10ms = 1s full-range dim) | 75 | #define DIMMER_FADE_DELAY 40 // Delay in ms for each percentage fade up/down (10ms = 1s full-range dim) |
| 79 | 76 | ||
| 80 | WiFiClient espClient; | 77 | // fw update |
| 81 | PubSubClient client(espClient); | 78 | // - increment number + build |
| 82 | char convBuffer[10]; | 79 | // - scp .pio/build/$ENV/firmware.bin manuel@mausz.at:public_html/coding/.firmware/olilrstripes.bin |
| 80 | // - reboot device or send "fwupdate" to mqtt_topic_cmd | ||
| 81 | // - fw update state is published in mqtt_topic_state | ||
| 82 | #define FIRMWARE_VERSION 1 | ||
| 83 | //#define FIRMWARE_URL "" | ||
| 84 | |||
| 85 | #define _STR(s) #s | ||
| 86 | #define STR(s) _STR(s) | ||
| 87 | |||
| 88 | const String mqtt_clientId = "LrStripes-" + String(ESP.getChipId()) | ||
| 89 | + "/v" + STR(FIRMWARE_VERSION); | ||
| 90 | const char* mqtt_topic_ping = MQTT_BASE "/ping"; | ||
| 91 | const char* mqtt_topic_cmd = MQTT_BASE "/command"; | ||
| 92 | const String mqtt_topic_state = String(MQTT_BASE) + "/" + String(ESP.getChipId()); | ||
| 93 | |||
| 94 | bool mqttLoop(); | ||
| 95 | void mqttCallback(char *topic, byte *payload, unsigned int length); | ||
| 96 | void checkFirmwareUpdate(); | ||
| 83 | 97 | ||
| 84 | void callback(char* topic, byte* payload, unsigned int length); | ||
| 85 | void blink(); | ||
| 86 | bool relayRead(struct sensor_t *sensor); | 98 | bool relayRead(struct sensor_t *sensor); |
| 87 | void relayWrite(struct sensor_t *sensor, bool state, bool send_update=false); | 99 | void relayWrite(struct sensor_t *sensor, bool state, bool send_update=false); |
| 88 | void flipRelay(struct sensor_t *sensor, bool send_update=false); | 100 | void flipRelay(struct sensor_t *sensor, bool send_update=false); |
| 89 | void checkButtons(void); | 101 | void checkButtons(void); |
| 90 | inline uint8_t pwmValue(uint8_t level); | 102 | inline uint8_t pwmValue(uint8_t level); |
| 91 | void fadeDimmer(struct sensor_t *sensor, uint8_t level, bool send_update=false); | 103 | void fadeDimmer(struct sensor_t *sensor, uint8_t level, bool send_update=false); |
| 92 | void checkFirmwareUpdate(); | 104 | |
| 105 | WiFiClient wifi_client; | ||
| 106 | PubSubClient mqtt(wifi_client); | ||
| 107 | char convBuffer[10]; | ||
| 93 | 108 | ||
| 94 | void setup() | 109 | void setup() |
| 95 | { | 110 | { |
| @@ -134,7 +149,9 @@ void setup() | |||
| 134 | WiFiManager wifiManager; | 149 | WiFiManager wifiManager; |
| 135 | wifiManager.setConfigPortalTimeout(600); | 150 | wifiManager.setConfigPortalTimeout(600); |
| 136 | Serial.printf_P(PSTR("Setting up WiFi\n")); | 151 | Serial.printf_P(PSTR("Setting up WiFi\n")); |
| 137 | if (!wifiManager.autoConnect("ESP8266_LR_STRIPES")) { | 152 | WiFi.hostname("lrstripes"); |
| 153 | if (!wifiManager.autoConnect("ESP8266_LR_STRIPES")) | ||
| 154 | { | ||
| 138 | Serial.printf_P(PSTR("Failed to connect and hit timeout\n")); | 155 | Serial.printf_P(PSTR("Failed to connect and hit timeout\n")); |
| 139 | delay(5000); | 156 | delay(5000); |
| 140 | ESP.restart(); | 157 | ESP.restart(); |
| @@ -144,110 +161,101 @@ void setup() | |||
| 144 | checkFirmwareUpdate(); | 161 | checkFirmwareUpdate(); |
| 145 | yield(); | 162 | yield(); |
| 146 | 163 | ||
| 147 | client.setServer(mqtt_server, mqtt_port); | 164 | mqtt.setServer(MQTT_BROKER, MQTT_BROKER_PORT); |
| 148 | client.setCallback(callback); | 165 | mqtt.setCallback(mqttCallback); |
| 149 | 166 | ||
| 150 | digitalWrite(LED_BUILTIN, HIGH); //Turn off led as default | 167 | digitalWrite(LED_BUILTIN, HIGH); //Turn off led as default |
| 151 | } | 168 | } |
| 152 | 169 | ||
| 153 | void reconnect() | 170 | bool mqttLoop() |
| 154 | { | 171 | { |
| 155 | // Loop until we're reconnected | 172 | if (!mqtt.connected()) |
| 156 | while (!client.connected()) | ||
| 157 | { | 173 | { |
| 158 | // Create a random client ID | 174 | Serial.printf_P(PSTR("Connecting to MQTT\n")); |
| 159 | String clientId = "ESP8266Client-"; | 175 | if (!mqtt.connect(mqtt_clientId.c_str(), MQTT_USERNAME, MQTT_PASSWORD)) |
| 160 | clientId += String(random(0xffff), HEX); | 176 | return false; |
| 161 | 177 | ||
| 162 | // Attempt to connect | 178 | Serial.printf_P(PSTR("MQTT connected\n")); |
| 163 | if (client.connect(clientId.c_str())) | 179 | mqtt.publish(mqtt_topic_ping, mqtt_clientId.c_str()); |
| 180 | mqtt.subscribe(mqtt_topic_ping); | ||
| 181 | mqtt.subscribe(mqtt_topic_cmd); | ||
| 182 | |||
| 183 | // publish states | ||
| 184 | for (uint8_t i = 0; i < NUM(sensors); i++) | ||
| 164 | { | 185 | { |
| 165 | // Once connected, publish an announcement... | 186 | struct sensor_t *sensor = &sensors[i]; |
| 166 | client.publish(mqtt_device_boot, "connected"); | 187 | if (sensor->type & SENSOR_RELAY) |
| 167 | // ... and resubscribe | 188 | { |
| 168 | client.subscribe(mqtt_pingall_sub); | 189 | Serial.println(sensor->relay.mqtt_sub); |
| 190 | mqtt.subscribe(sensor->relay.mqtt_sub); | ||
| 191 | mqtt.publish(sensor->relay.mqtt_pub, relayRead(sensor) ? "1" : "0", | ||
| 192 | true); | ||
| 193 | } | ||
| 169 | 194 | ||
| 170 | // publish states | 195 | if (sensor->type & SENSOR_DIMMER) |
| 171 | for (uint8_t i = 0; i < NUM(sensors); i++) | ||
| 172 | { | 196 | { |
| 173 | struct sensor_t *sensor = &sensors[i]; | 197 | Serial.println(sensor->dimmer.mqtt_sub); |
| 174 | if (sensor->type & SENSOR_RELAY) | 198 | mqtt.subscribe(sensor->dimmer.mqtt_sub); |
| 175 | { | 199 | itoa(sensor->dimmer.level, convBuffer, 10); |
| 176 | Serial.println(sensor->relay.mqtt_sub); | 200 | mqtt.publish(sensor->dimmer.mqtt_pub, convBuffer, true); |
| 177 | client.subscribe(sensor->relay.mqtt_sub); | ||
| 178 | client.publish(sensor->relay.mqtt_pub, relayRead(sensor) ? "1" : "0", | ||
| 179 | true); | ||
| 180 | } | ||
| 181 | |||
| 182 | if (sensor->type & SENSOR_DIMMER) | ||
| 183 | { | ||
| 184 | Serial.println(sensor->dimmer.mqtt_sub); | ||
| 185 | client.subscribe(sensor->dimmer.mqtt_sub); | ||
| 186 | itoa(sensor->dimmer.level, convBuffer, 10); | ||
| 187 | client.publish(sensor->dimmer.mqtt_pub, convBuffer, true); | ||
| 188 | } | ||
| 189 | } | 201 | } |
| 190 | } | 202 | } |
| 191 | else | ||
| 192 | { | ||
| 193 | // Wait 5 seconds before retrying | ||
| 194 | delay(5000); | ||
| 195 | } | ||
| 196 | } | 203 | } |
| 204 | |||
| 205 | yield(); | ||
| 206 | mqtt.loop(); | ||
| 207 | return true; | ||
| 197 | } | 208 | } |
| 198 | 209 | ||
| 199 | void callback(char* topic, byte* payload, unsigned int length) | 210 | void mqttCallback(char *topic, byte *payload, unsigned int length) |
| 200 | { | 211 | { |
| 201 | char c_payload[length]; | 212 | char c_payload[length + 1]; |
| 202 | memcpy(c_payload, payload, length); | 213 | memcpy(c_payload, payload, length); |
| 203 | c_payload[length] = '\0'; | 214 | c_payload[length] = '\0'; |
| 204 | 215 | ||
| 205 | if (strcmp(topic, mqtt_pingall_sub) == 0) | 216 | if (!strcmp(topic, mqtt_topic_ping)) |
| 206 | { | 217 | { |
| 207 | blink(); | 218 | if (!strcmp(c_payload, "ping")) |
| 208 | client.publish(mqtt_pingall_pub, | 219 | mqtt.publish(mqtt_topic_ping, mqtt_clientId.c_str()); |
| 209 | "{\"livingroom_ledstrip\":\"connected\"}"); | ||
| 210 | return; | 220 | return; |
| 211 | } | 221 | } |
| 212 | 222 | else if (!strcmp(topic, mqtt_topic_cmd)) | |
| 213 | for (uint8_t i = 0; i < NUM(sensors); i++) | ||
| 214 | { | 223 | { |
| 215 | struct sensor_t *sensor = &sensors[i]; | 224 | if (!strcmp(c_payload, "fwupdate")) |
| 216 | if (sensor->type & SENSOR_RELAY | ||
| 217 | && length > 0 | ||
| 218 | && strcmp(topic, sensor->relay.mqtt_sub) == 0) | ||
| 219 | { | 225 | { |
| 220 | blink(); | 226 | checkFirmwareUpdate(); |
| 221 | relayWrite(sensor, payload[0] == '1', true); | ||
| 222 | return; | 227 | return; |
| 223 | } | 228 | } |
| 224 | 229 | else if (!strcmp(c_payload, "reset")) | |
| 225 | if (sensor->type & SENSOR_DIMMER | ||
| 226 | && length > 0 | ||
| 227 | && strcmp(topic, sensor->dimmer.mqtt_sub) == 0) | ||
| 228 | { | 230 | { |
| 229 | blink(); | 231 | Serial.printf_P(PSTR("Resetting\n")); |
| 230 | uint8_t level = atoi((char *)payload); | 232 | ESP.reset(); |
| 231 | fadeDimmer(sensor, (level > 100) ? 100 : level, true); | ||
| 232 | return; | 233 | return; |
| 233 | } | 234 | } |
| 234 | } | 235 | } |
| 235 | } | 236 | else |
| 236 | 237 | { | |
| 237 | void blink() | 238 | for (uint8_t i = 0; i < NUM(sensors); i++) |
| 238 | { | 239 | { |
| 239 | //Blink on received MQTT message | 240 | struct sensor_t *sensor = &sensors[i]; |
| 240 | digitalWrite(LED_BUILTIN, LOW); | 241 | if (sensor->type & SENSOR_RELAY |
| 241 | delay(25); | 242 | && length > 0 |
| 242 | digitalWrite(LED_BUILTIN, HIGH); | 243 | && strcmp(topic, sensor->relay.mqtt_sub) == 0) |
| 243 | } | 244 | { |
| 245 | relayWrite(sensor, payload[0] == '1', true); | ||
| 246 | return; | ||
| 247 | } | ||
| 244 | 248 | ||
| 245 | void loop() | 249 | if (sensor->type & SENSOR_DIMMER |
| 246 | { | 250 | && length > 0 |
| 247 | if (!client.connected()) | 251 | && strcmp(topic, sensor->dimmer.mqtt_sub) == 0) |
| 248 | reconnect(); | 252 | { |
| 249 | client.loop(); | 253 | uint8_t level = atoi((char *)payload); |
| 250 | checkButtons(); | 254 | fadeDimmer(sensor, (level > 100) ? 100 : level, true); |
| 255 | return; | ||
| 256 | } | ||
| 257 | } | ||
| 258 | } | ||
| 251 | } | 259 | } |
| 252 | 260 | ||
| 253 | bool relayRead(struct sensor_t *sensor) | 261 | bool relayRead(struct sensor_t *sensor) |
| @@ -277,7 +285,7 @@ void relayWrite(struct sensor_t *sensor, bool state, bool send_update) | |||
| 277 | #endif | 285 | #endif |
| 278 | 286 | ||
| 279 | if (send_update) | 287 | if (send_update) |
| 280 | client.publish(sensor->relay.mqtt_pub, state ? "1" : "0", true); | 288 | mqtt.publish(sensor->relay.mqtt_pub, state ? "1" : "0", true); |
| 281 | } | 289 | } |
| 282 | 290 | ||
| 283 | void flipRelay(struct sensor_t *sensor, bool send_update) | 291 | void flipRelay(struct sensor_t *sensor, bool send_update) |
| @@ -356,7 +364,7 @@ void fadeDimmer(struct sensor_t *sensor, uint8_t level, bool send_update) | |||
| 356 | if (send_update) | 364 | if (send_update) |
| 357 | { | 365 | { |
| 358 | itoa(level, convBuffer, 10); | 366 | itoa(level, convBuffer, 10); |
| 359 | client.publish(sensor->dimmer.mqtt_pub, convBuffer, true); | 367 | mqtt.publish(sensor->dimmer.mqtt_pub, convBuffer, true); |
| 360 | } | 368 | } |
| 361 | } | 369 | } |
| 362 | 370 | ||
| @@ -365,7 +373,7 @@ void checkFirmwareUpdate() | |||
| 365 | BearSSL::WiFiClientSecure update_client; | 373 | BearSSL::WiFiClientSecure update_client; |
| 366 | update_client.setInsecure(); | 374 | update_client.setInsecure(); |
| 367 | 375 | ||
| 368 | client.publish(mqtt_device_boot, "fwupdate running"); | 376 | mqtt.publish(mqtt_topic_state.c_str(), "fwupdate running"); |
| 369 | ESPhttpUpdate.setLedPin(LED_BUILTIN, HIGH); | 377 | ESPhttpUpdate.setLedPin(LED_BUILTIN, HIGH); |
| 370 | ESPhttpUpdate.rebootOnUpdate(true); | 378 | ESPhttpUpdate.rebootOnUpdate(true); |
| 371 | t_httpUpdate_return ret = ESPhttpUpdate.update(update_client, FIRMWARE_URL, STR(FIRMWARE_VERSION)); | 379 | t_httpUpdate_return ret = ESPhttpUpdate.update(update_client, FIRMWARE_URL, STR(FIRMWARE_VERSION)); |
| @@ -376,18 +384,26 @@ void checkFirmwareUpdate() | |||
| 376 | Serial.printf_P(PSTR("HTTP_UPDATE_FAILED Error (%d): %s\n"), | 384 | Serial.printf_P(PSTR("HTTP_UPDATE_FAILED Error (%d): %s\n"), |
| 377 | ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str()); | 385 | ESPhttpUpdate.getLastError(), ESPhttpUpdate.getLastErrorString().c_str()); |
| 378 | String tmp = String("fwupdate error: ") + ESPhttpUpdate.getLastErrorString(); | 386 | String tmp = String("fwupdate error: ") + ESPhttpUpdate.getLastErrorString(); |
| 379 | client.publish(mqtt_device_boot, tmp.c_str()); | 387 | mqtt.publish(mqtt_topic_state.c_str(), tmp.c_str()); |
| 380 | } | 388 | } |
| 381 | break; | 389 | break; |
| 382 | 390 | ||
| 383 | case HTTP_UPDATE_NO_UPDATES: | 391 | case HTTP_UPDATE_NO_UPDATES: |
| 384 | Serial.printf_P(PSTR("HTTP_UPDATE_NO_UPDATES\n")); | 392 | Serial.printf_P(PSTR("HTTP_UPDATE_NO_UPDATES\n")); |
| 385 | client.publish(mqtt_device_boot, "fwupdate noupdates"); | 393 | mqtt.publish(mqtt_topic_state.c_str(), "fwupdate noupdates"); |
| 386 | break; | 394 | break; |
| 387 | 395 | ||
| 388 | case HTTP_UPDATE_OK: | 396 | case HTTP_UPDATE_OK: |
| 389 | Serial.printf_P(PSTR("HTTP_UPDATE_OK\n")); | 397 | Serial.printf_P(PSTR("HTTP_UPDATE_OK\n")); |
| 390 | client.publish(mqtt_device_boot, "fwupdate ok"); | 398 | mqtt.publish(mqtt_topic_state.c_str(), "fwupdate ok"); |
| 391 | break; | 399 | break; |
| 392 | } | 400 | } |
| 393 | } | 401 | } |
| 402 | |||
| 403 | void loop() | ||
| 404 | { | ||
| 405 | if (!mqttLoop()) | ||
| 406 | delay(5000); | ||
| 407 | |||
| 408 | checkButtons(); | ||
| 409 | } | ||
