ソースを参照

add ability to trigger watering cycles via MQTT

Thomas Buck 1年前
コミット
ac92d1686c
8個のファイルの変更183行の追加25行の削除
  1. 16
    0
      README.md
  2. 2
    2
      include/Functionality.h
  3. 2
    2
      include/Statemachine.h
  4. 2
    1
      include/config.h
  5. 2
    0
      platformio.ini
  6. 2
    2
      src/Functionality.cpp
  7. 2
    2
      src/Statemachine.cpp
  8. 155
    16
      src/WifiStuff.cpp

+ 16
- 0
README.md ファイルの表示

20
 You can of course also use pio to flash your targets.
20
 You can of course also use pio to flash your targets.
21
 
21
 
22
 There is also an optional Telegram bot integration.
22
 There is also an optional Telegram bot integration.
23
+
24
+## Optional Networking Interfaces
25
+
26
+There are both a Telegram bot implementation, as well as an MQTT client implemented in Giess-o-mat.
27
+Telegram allows control even from the Internet, but unfortunately polling for new messages is very time consuming.
28
+So I would not recommend enabling it if you also want to use the I2C UI.
29
+
23
 Register a new bot with the Telegram botfather and put the token into wifi.h as TELEGRAM_TOKEN.
30
 Register a new bot with the Telegram botfather and put the token into wifi.h as TELEGRAM_TOKEN.
24
 Compile and run the project, then send a message to the bot.
31
 Compile and run the project, then send a message to the bot.
25
 Look for the chat ID in the log and put it into wifi.h in TRUSTED_IDS.
32
 Look for the chat ID in the log and put it into wifi.h in TRUSTED_IDS.
27
     echo '#define TELEGRAM_TOKEN "XXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"' >> include/wifi.h
34
     echo '#define TELEGRAM_TOKEN "XXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"' >> include/wifi.h
28
     echo '#define TRUSTED_IDS { "1234", "5678" }' >> include/wifi.h
35
     echo '#define TRUSTED_IDS { "1234", "5678" }' >> include/wifi.h
29
 
36
 
37
+MQTT is far less resource intensive, but also does not provide a bridge to the Internet.
38
+Enable it like this.
39
+The last two parameters are optional.
40
+
41
+    echo '#define MQTT_HOST "192.168.0.100"' >> include/wifi.h
42
+    echo '#define MQTT_PORT 1883' >> include/wifi.h
43
+    echo '#define MQTT_USER "USERNAME"' >> include/wifi.h
44
+    echo '#define MQTT_PASS "PASSWORD"' >> include/wifi.h
45
+
30
 ## Hardware
46
 ## Hardware
31
 
47
 
32
 In general, the project consists of two parts, the controller and the ui.
48
 In general, the project consists of two parts, the controller and the ui.

+ 2
- 2
include/Functionality.h ファイルの表示

45
 
45
 
46
 bool sm_is_idle(void);
46
 bool sm_is_idle(void);
47
 
47
 
48
-#ifdef TELEGRAM_TOKEN
48
+#if defined(TELEGRAM_TOKEN) || defined(MQTT_HOST)
49
 void sm_bot_abort(void);
49
 void sm_bot_abort(void);
50
 void sm_bot_start_auto(BoolField ferts, BoolField plants);
50
 void sm_bot_start_auto(BoolField ferts, BoolField plants);
51
-#endif // TELEGRAM_TOKEN
51
+#endif // TELEGRAM_TOKEN || MQTT_HOST
52
 
52
 
53
 #endif // FUNCTION_CONTROL
53
 #endif // FUNCTION_CONTROL
54
 
54
 

+ 2
- 2
include/Statemachine.h ファイルの表示

124
     const char *getStateName(void);
124
     const char *getStateName(void);
125
     bool isIdle(void);
125
     bool isIdle(void);
126
 
126
 
127
-#ifdef TELEGRAM_TOKEN
127
+#if defined(TELEGRAM_TOKEN) || defined(MQTT_HOST)
128
     void bot_abort(void);
128
     void bot_abort(void);
129
     void bot_start_auto(BoolField ferts, BoolField plants);
129
     void bot_start_auto(BoolField ferts, BoolField plants);
130
-#endif // TELEGRAM_TOKEN
130
+#endif // TELEGRAM_TOKEN || MQTT_HOST
131
     
131
     
132
 private:
132
 private:
133
     void switch_to(States s);
133
     void switch_to(States s);

+ 2
- 1
include/config.h ファイルの表示

53
 #define LED_CONNECT_BLINK_INTERVAL 250
53
 #define LED_CONNECT_BLINK_INTERVAL 250
54
 #define LED_ERROR_BLINK_INTERVAL 100
54
 #define LED_ERROR_BLINK_INTERVAL 100
55
 #define TELEGRAM_UPDATE_INTERVAL_SLOW (10 * 1000)
55
 #define TELEGRAM_UPDATE_INTERVAL_SLOW (10 * 1000)
56
-#define TELEGRAM_UPDATE_INTERVAL_FAST (3 * 1000)
56
+#define TELEGRAM_UPDATE_INTERVAL_FAST (2 * 1000)
57
+#define MQTT_RECONNECT_INTERVAL (5 * 1000)
57
 
58
 
58
 // each attempt takes LED_CONNECT_BLINK_INTERVAL ms
59
 // each attempt takes LED_CONNECT_BLINK_INTERVAL ms
59
 #define MAX_WIFI_CONNECT_ATTEMPTS 40
60
 #define MAX_WIFI_CONNECT_ATTEMPTS 40

+ 2
- 0
platformio.ini ファイルの表示

24
     https://github.com/RobTillaart/PCF8574
24
     https://github.com/RobTillaart/PCF8574
25
     https://github.com/bblanchon/ArduinoJson
25
     https://github.com/bblanchon/ArduinoJson
26
     https://github.com/witnessmenow/Universal-Arduino-Telegram-Bot
26
     https://github.com/witnessmenow/Universal-Arduino-Telegram-Bot
27
+    https://github.com/knolleary/pubsubclient.git#2d228f2f862a95846c65a8518c79f48dfc8f188c
27
 
28
 
28
 [env:esp32_main]
29
 [env:esp32_main]
29
 platform = platformio/espressif32@3.5.0
30
 platform = platformio/espressif32@3.5.0
40
     https://github.com/RobTillaart/PCF8574
41
     https://github.com/RobTillaart/PCF8574
41
     https://github.com/bblanchon/ArduinoJson
42
     https://github.com/bblanchon/ArduinoJson
42
     https://github.com/witnessmenow/Universal-Arduino-Telegram-Bot
43
     https://github.com/witnessmenow/Universal-Arduino-Telegram-Bot
44
+    https://github.com/knolleary/pubsubclient.git#2d228f2f862a95846c65a8518c79f48dfc8f188c
43
 
45
 
44
 [env:arduino_ui]
46
 [env:arduino_ui]
45
 platform = atmelavr
47
 platform = atmelavr

+ 2
- 2
src/Functionality.cpp ファイルの表示

76
     return sm.isIdle();
76
     return sm.isIdle();
77
 }
77
 }
78
 
78
 
79
-#ifdef TELEGRAM_TOKEN
79
+#if defined(TELEGRAM_TOKEN) || defined(MQTT_HOST)
80
 
80
 
81
 void sm_bot_abort(void) {
81
 void sm_bot_abort(void) {
82
     sm.bot_abort();
82
     sm.bot_abort();
86
     sm.bot_start_auto(ferts, plants);
86
     sm.bot_start_auto(ferts, plants);
87
 }
87
 }
88
 
88
 
89
-#endif // TELEGRAM_TOKEN
89
+#endif // TELEGRAM_TOKEN || MQTT_HOST
90
 
90
 
91
 #endif // FUNCTION_CONTROL
91
 #endif // FUNCTION_CONTROL
92
 
92
 

+ 2
- 2
src/Statemachine.cpp ファイルの表示

173
     switch_to(init);
173
     switch_to(init);
174
 }
174
 }
175
 
175
 
176
-#ifdef TELEGRAM_TOKEN
176
+#if defined(TELEGRAM_TOKEN) || defined(MQTT_HOST)
177
 
177
 
178
 void Statemachine::bot_abort(void) {
178
 void Statemachine::bot_abort(void) {
179
     plants.abort();
179
     plants.abort();
244
     }
244
     }
245
 }
245
 }
246
 
246
 
247
-#endif // TELEGRAM_TOKEN
247
+#endif // TELEGRAM_TOKEN || MQTT_HOST
248
 
248
 
249
 void Statemachine::input(int n) {
249
 void Statemachine::input(int n) {
250
     if (state == init) {
250
     if (state == init) {

+ 155
- 16
src/WifiStuff.cpp ファイルの表示

62
 unsigned long last_telegram_time = 0;
62
 unsigned long last_telegram_time = 0;
63
 String trusted_chat_ids[] = TRUSTED_IDS;
63
 String trusted_chat_ids[] = TRUSTED_IDS;
64
 
64
 
65
+enum telegram_state {
66
+    BOT_IDLE,
67
+    BOT_ASKED_FERT,
68
+    BOT_ASKED_PLANTS,
69
+    BOT_ASKED_CONFIRM
70
+};
71
+
72
+enum telegram_state bot_state = BOT_IDLE;
73
+String bot_lock = "";
74
+BoolField bot_plants(VALVE_COUNT - 1);
75
+BoolField bot_ferts(PUMP_COUNT);
76
+
65
 #endif // TELEGRAM_TOKEN
77
 #endif // TELEGRAM_TOKEN
66
 
78
 
79
+#ifdef MQTT_HOST
80
+#include <PubSubClient.h>
81
+WiFiClient mqttClient;
82
+PubSubClient mqtt(mqttClient);
83
+unsigned long last_mqtt_reconnect_time = 0;
84
+BoolField mqtt_plants(VALVE_COUNT - 1);
85
+BoolField mqtt_ferts(PUMP_COUNT);
86
+#endif // MQTT_HOST
87
+
67
 UPDATE_WEB_SERVER server(80);
88
 UPDATE_WEB_SERVER server(80);
68
 WebSocketsServer socket = WebSocketsServer(81);
89
 WebSocketsServer socket = WebSocketsServer(81);
69
 SimpleUpdater updater;
90
 SimpleUpdater updater;
125
         bot.sendMessage(trusted_chat_ids[n], "New state: " + String(s), "");
146
         bot.sendMessage(trusted_chat_ids[n], "New state: " + String(s), "");
126
     }
147
     }
127
 #endif // TELEGRAM_TOKEN
148
 #endif // TELEGRAM_TOKEN
149
+
150
+#ifdef MQTT_HOST
151
+    mqtt.publish("giessomat", s);
152
+#endif // MQTT_HOST
128
 }
153
 }
129
 
154
 
130
 #ifdef TELEGRAM_TOKEN
155
 #ifdef TELEGRAM_TOKEN
131
-enum telegram_state {
132
-    BOT_IDLE,
133
-    BOT_ASKED_FERT,
134
-    BOT_ASKED_PLANTS,
135
-    BOT_ASKED_CONFIRM
136
-};
137
-
138
-enum telegram_state bot_state = BOT_IDLE;
139
-String bot_lock = "";
140
-BoolField bot_plants(VALVE_COUNT - 1);
141
-BoolField bot_ferts(PUMP_COUNT);
142
 
156
 
143
 unsigned long telegram_update_interval() {
157
 unsigned long telegram_update_interval() {
144
     if (bot_state == BOT_IDLE) {
158
     if (bot_state == BOT_IDLE) {
352
 }
366
 }
353
 #endif // TELEGRAM_TOKEN
367
 #endif // TELEGRAM_TOKEN
354
 
368
 
369
+#ifdef MQTT_HOST
370
+
371
+static void mqttCallback(char* topic, byte* payload, unsigned int length) {
372
+    String ts(topic), ps;
373
+    for (unsigned int i = 0; i < length; i++) {
374
+        char c = payload[i];
375
+        ps += c;
376
+    }
377
+
378
+    debug.println("MQTT Rx @ " + ts + ": " + ps);
379
+
380
+    if (ts != "giessomat") {
381
+        debug.println("MQTT: invalid topic");
382
+        return;
383
+    }
384
+
385
+    if (ps == "abort") {
386
+        if (sm_is_idle()) {
387
+            debug.println("MQTT: nothing to abort");
388
+        } else {
389
+            sm_bot_abort();
390
+            debug.println("MQTT: user abort");
391
+        }
392
+    } else {
393
+        if (ps.substring(0, 4) != "auto") {
394
+            debug.println("MQTT: invalid payload");
395
+            return;
396
+        }
397
+
398
+        mqtt_ferts.clear();
399
+        mqtt_plants.clear();
400
+
401
+        String buff;
402
+        bool at_plants = false;
403
+        for (int i = 5; i < ps.length() + 1; i++) {
404
+            if ((i == ps.length()) || (ps[i] == ' ') || (ps[i] == ',')) {
405
+                if (buff != "none") {
406
+                    int n = buff.toInt() - 1;
407
+                    if (!at_plants) {
408
+                        mqtt_ferts.set(n);
409
+                    } else {
410
+                        mqtt_plants.set(n);
411
+                    }
412
+                }
413
+                buff = "";
414
+
415
+                if ((i < ps.length()) && (ps[i] == ' ')) {
416
+                    at_plants = true;
417
+                }
418
+            } else {
419
+                buff += ps[i];
420
+            }
421
+        }
422
+
423
+        String s = "MQTT: fertilizers:";
424
+        for (int i = 0; i < PUMP_COUNT; i++) {
425
+            if (mqtt_ferts.isSet(i)) {
426
+                s += " " + String(i + 1);
427
+            }
428
+        }
429
+        debug.println(s);
430
+
431
+        s = "MQTT: plants:";
432
+        for (int i = 0; i < (VALVE_COUNT - 1); i++) {
433
+            if (mqtt_plants.isSet(i)) {
434
+                s += " " + String(i + 1);
435
+            }
436
+        }
437
+        debug.println(s);
438
+
439
+        if (mqtt_plants.countSet() <= 0) {
440
+            debug.println("MQTT: no plants selected");
441
+            return;
442
+        }
443
+
444
+#ifdef FULLAUTO_MIN_PLANT_COUNT
445
+        if (mqtt_plants.countSet() < FULLAUTO_MIN_PLANT_COUNT) {
446
+            debug.println("MQTT: not enough plants selected");
447
+            return;
448
+        }
449
+#endif
450
+
451
+        sm_bot_start_auto(mqtt_ferts, mqtt_plants);
452
+    }
453
+}
454
+
455
+static void mqttReconnect() {
456
+    // Create a random client ID
457
+    String clientId = F("giessomat-");
458
+    clientId += String(random(0xffff), HEX);
459
+
460
+    // Attempt to connect
461
+#if defined(MQTT_USER) && defined(MQTT_PASS)
462
+    if (mqtt.connect(clientId.c_str(), MQTT_USER, MQTT_PASS)) {
463
+#else
464
+    if (mqtt.connect(clientId.c_str())) {
465
+#endif
466
+        mqtt.subscribe("giessomat");
467
+    }
468
+}
469
+
470
+#endif // MQTT_HOST
471
+
355
 bool wifi_write_database(int duration, const char *type, int id) {
472
 bool wifi_write_database(int duration, const char *type, int id) {
356
     bool success = false;
473
     bool success = false;
357
 
474
 
874
     message += F("</p>\n");
991
     message += F("</p>\n");
875
 
992
 
876
     message += F("<p>\n");
993
     message += F("<p>\n");
994
+#ifdef MQTT_HOST
995
+    message += F("MQTT: ");
996
+    message += MQTT_HOST;
997
+    message += F(":");
998
+    message += String(MQTT_PORT);
999
+    message += F("\n");
1000
+#else
1001
+    message += F("MQTT not enabled!\n");
1002
+#endif
1003
+    message += F("</p>\n");
1004
+
1005
+    message += F("<p>\n");
877
 #ifdef ENABLE_INFLUXDB_LOGGING
1006
 #ifdef ENABLE_INFLUXDB_LOGGING
878
     message += F("InfluxDB: ");
1007
     message += F("InfluxDB: ");
879
     message += INFLUXDB_DATABASE;
1008
     message += INFLUXDB_DATABASE;
1135
     telegram_hello();
1264
     telegram_hello();
1136
 #endif // TELEGRAM_TOKEN
1265
 #endif // TELEGRAM_TOKEN
1137
 
1266
 
1267
+#ifdef MQTT_HOST
1268
+    debug.println("WiFi: initializing MQTT");
1269
+    mqtt.setServer(MQTT_HOST, MQTT_PORT);
1270
+    mqtt.setCallback(mqttCallback);
1271
+#endif // MQTT_HOST
1272
+
1138
     server.begin();
1273
     server.begin();
1139
     MDNS.addService("http", "tcp", 80);
1274
     MDNS.addService("http", "tcp", 80);
1140
     MDNS.addService("http", "tcp", 81);
1275
     MDNS.addService("http", "tcp", 81);
1146
 }
1281
 }
1147
 
1282
 
1148
 void wifi_run() {
1283
 void wifi_run() {
1149
-    // reset ESP every 6h to be safe
1150
-    if ((millis() >= (6UL * 60UL * 60UL * 1000UL)) && (sm_is_idle())) {
1151
-        ESP.restart();
1152
-    }
1153
-
1154
     if (!wifi_ok) {
1284
     if (!wifi_ok) {
1155
         // nothing to handle
1285
         // nothing to handle
1156
         return;
1286
         return;
1184
         last_telegram_time = millis();
1314
         last_telegram_time = millis();
1185
     }
1315
     }
1186
 #endif // TELEGRAM_TOKEN
1316
 #endif // TELEGRAM_TOKEN
1317
+
1318
+#ifdef MQTT_HOST
1319
+    if (!mqtt.connected() && ((millis() - last_mqtt_reconnect_time) >= MQTT_RECONNECT_INTERVAL)) {
1320
+        last_mqtt_reconnect_time = millis();
1321
+        mqttReconnect();
1322
+    }
1323
+
1324
+    mqtt.loop();
1325
+#endif // MQTT_HOST
1187
 }
1326
 }
1188
 
1327
 
1189
 #endif // PLATFORM_ESP
1328
 #endif // PLATFORM_ESP

読み込み中…
キャンセル
保存