Browse Source

Add Universal-Arduino-Telegram-Bot library and implement simple bot.

Thomas Buck 2 years ago
parent
commit
274197f83f
9 changed files with 428 additions and 7 deletions
  1. 8
    0
      README.md
  2. 8
    2
      include/Functionality.h
  3. 5
    0
      include/Statemachine.h
  4. 1
    0
      include/WifiStuff.h
  5. 5
    3
      include/config.h
  6. 4
    0
      platformio.ini
  7. 13
    0
      src/Functionality.cpp
  8. 78
    0
      src/Statemachine.cpp
  9. 306
    2
      src/WifiStuff.cpp

+ 8
- 0
README.md View File

19
 
19
 
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.
23
+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.
25
+Look for the chat ID in the log and put it into wifi.h in TRUSTED_IDS.
26
+
27
+    echo '#define TELEGRAM_TOKEN "XXXXXXXXX:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"' >> include/wifi.h
28
+    echo '#define TRUSTED_IDS { "1234", "5678" }' >> include/wifi.h
29
+
22
 ## Hardware
30
 ## Hardware
23
 
31
 
24
 In general, the project consists of two parts, the controller and the ui.
32
 In general, the project consists of two parts, the controller and the ui.

+ 8
- 2
include/Functionality.h View File

32
 #ifdef FUNCTION_CONTROL
32
 #ifdef FUNCTION_CONTROL
33
 
33
 
34
 #include "Plants.h"
34
 #include "Plants.h"
35
+#include "BoolField.h"
35
 
36
 
36
 void control_setup(void);
37
 void control_setup(void);
37
 void control_begin(void);
38
 void control_begin(void);
42
 
43
 
43
 Plants *get_plants(void);
44
 Plants *get_plants(void);
44
 
45
 
46
+bool sm_is_idle(void);
47
+
48
+#ifdef TELEGRAM_TOKEN
49
+void sm_bot_abort(void);
50
+void sm_bot_start_auto(BoolField ferts, BoolField plants);
51
+#endif // TELEGRAM_TOKEN
52
+
45
 #endif // FUNCTION_CONTROL
53
 #endif // FUNCTION_CONTROL
46
 
54
 
47
 // ----------------------------------------------------------------------------
55
 // ----------------------------------------------------------------------------
51
                   const char *c, const char *d, int num_input);
59
                   const char *c, const char *d, int num_input);
52
 void backspace(void);
60
 void backspace(void);
53
 
61
 
54
-bool sm_is_idle(void);
55
-
56
 #endif // _FUNCTIONALITY_H_
62
 #endif // _FUNCTIONALITY_H_

+ 5
- 0
include/Statemachine.h View File

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

+ 1
- 0
include/WifiStuff.h View File

28
 void wifi_set_message_buffer(String a, String b, String c, String d);
28
 void wifi_set_message_buffer(String a, String b, String c, String d);
29
 void wifi_schedule_websocket(void);
29
 void wifi_schedule_websocket(void);
30
 void wifi_send_status_broadcast(void);
30
 void wifi_send_status_broadcast(void);
31
+void wifi_broadcast_state_change(const char *s);
31
 
32
 
32
 void wifi_send_websocket(String s);
33
 void wifi_send_websocket(String s);
33
 
34
 

+ 5
- 3
include/config.h View File

36
 #define MAX_PUMP_RUNTIME 30
36
 #define MAX_PUMP_RUNTIME 30
37
 #define MAX_VALVE_RUNTIME (45 * 60)
37
 #define MAX_VALVE_RUNTIME (45 * 60)
38
 #define MAX_AUX_RUNTIME (5 * 60)
38
 #define MAX_AUX_RUNTIME (5 * 60)
39
-#define KICKSTART_RUNTIME 45
39
+#define KICKSTART_RUNTIME 60
40
 #define OVERRUN_RUNTIME 75
40
 #define OVERRUN_RUNTIME 75
41
 #define PURGE_FILL_RUNTIME 20
41
 #define PURGE_FILL_RUNTIME 20
42
 #define FULLAUTO_MIN_PLANT_COUNT 2
42
 #define FULLAUTO_MIN_PLANT_COUNT 2
43
 #define FULLAUTO_END_PUMP_TIME 30
43
 #define FULLAUTO_END_PUMP_TIME 30
44
 
44
 
45
 // Sketch version
45
 // Sketch version
46
-#define FIRMWARE_VERSION "0.6"
46
+#define FIRMWARE_VERSION "0.7"
47
 
47
 
48
 // all given in milliseconds
48
 // all given in milliseconds
49
-#define SERVER_HANDLE_INTERVAL 10
49
+#define SERVER_HANDLE_INTERVAL 0
50
 #define WEBSOCKET_UPDATE_INTERVAL 500
50
 #define WEBSOCKET_UPDATE_INTERVAL 500
51
 #define LED_BLINK_INTERVAL 500
51
 #define LED_BLINK_INTERVAL 500
52
 #define LED_INIT_BLINK_INTERVAL 500
52
 #define LED_INIT_BLINK_INTERVAL 500
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)
56
+#define TELEGRAM_UPDATE_INTERVAL_FAST (3 * 1000)
55
 
57
 
56
 // each attempt takes LED_CONNECT_BLINK_INTERVAL ms
58
 // each attempt takes LED_CONNECT_BLINK_INTERVAL ms
57
 #define MAX_WIFI_CONNECT_ATTEMPTS 40
59
 #define MAX_WIFI_CONNECT_ATTEMPTS 40

+ 4
- 0
platformio.ini View File

22
     https://github.com/rlogiacco/CircularBuffer
22
     https://github.com/rlogiacco/CircularBuffer
23
     https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino.git
23
     https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino.git
24
     https://github.com/RobTillaart/PCF8574
24
     https://github.com/RobTillaart/PCF8574
25
+    https://github.com/bblanchon/ArduinoJson
26
+    https://github.com/witnessmenow/Universal-Arduino-Telegram-Bot
25
 
27
 
26
 [env:esp32_main]
28
 [env:esp32_main]
27
 platform = platformio/espressif32@3.5.0
29
 platform = platformio/espressif32@3.5.0
36
     https://github.com/rlogiacco/CircularBuffer
38
     https://github.com/rlogiacco/CircularBuffer
37
     https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino.git
39
     https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino.git
38
     https://github.com/RobTillaart/PCF8574
40
     https://github.com/RobTillaart/PCF8574
41
+    https://github.com/bblanchon/ArduinoJson
42
+    https://github.com/witnessmenow/Universal-Arduino-Telegram-Bot
39
 
43
 
40
 [env:arduino_ui]
44
 [env:arduino_ui]
41
 platform = atmelavr
45
 platform = atmelavr

+ 13
- 0
src/Functionality.cpp View File

19
 
19
 
20
 #include <Arduino.h>
20
 #include <Arduino.h>
21
 
21
 
22
+#include "wifi.h"
22
 #include "config.h"
23
 #include "config.h"
23
 #include "config_pins.h"
24
 #include "config_pins.h"
24
 #include "DebugLog.h"
25
 #include "DebugLog.h"
75
     return sm.isIdle();
76
     return sm.isIdle();
76
 }
77
 }
77
 
78
 
79
+#ifdef TELEGRAM_TOKEN
80
+
81
+void sm_bot_abort(void) {
82
+    sm.bot_abort();
83
+}
84
+
85
+void sm_bot_start_auto(BoolField ferts, BoolField plants) {
86
+    sm.bot_start_auto(ferts, plants);
87
+}
88
+
89
+#endif // TELEGRAM_TOKEN
90
+
78
 #endif // FUNCTION_CONTROL
91
 #endif // FUNCTION_CONTROL
79
 
92
 
80
 // ----------------------------------------------------------------------------
93
 // ----------------------------------------------------------------------------

+ 78
- 0
src/Statemachine.cpp View File

17
  * along with Giess-o-mat.  If not, see <https://www.gnu.org/licenses/>.
17
  * along with Giess-o-mat.  If not, see <https://www.gnu.org/licenses/>.
18
  */
18
  */
19
 
19
 
20
+#include "wifi.h"
20
 #include "Plants.h"
21
 #include "Plants.h"
21
 #include "DebugLog.h"
22
 #include "DebugLog.h"
22
 #include "WifiStuff.h"
23
 #include "WifiStuff.h"
172
     switch_to(init);
173
     switch_to(init);
173
 }
174
 }
174
 
175
 
176
+#ifdef TELEGRAM_TOKEN
177
+
178
+void Statemachine::bot_abort(void) {
179
+    plants.abort();
180
+    stop_time = millis();
181
+    switch_to(auto_done);
182
+}
183
+
184
+void Statemachine::bot_start_auto(BoolField _ferts, BoolField _plants) {
185
+    selected_ferts = _ferts;
186
+    selected_plants = _plants;
187
+
188
+    // check if we need to run fertilizers
189
+    if (selected_ferts.countSet() > 0) {
190
+        // stirr before pumping fertilizers
191
+        for (int i = 0; i < STIRRER_COUNT; i++) {
192
+            plants.startAux(i);
193
+        }
194
+        selected_id = 1;
195
+        selected_time = AUTO_STIRR_RUNTIME;
196
+        start_time = millis();
197
+        switch_to(fullauto_stirr_run);
198
+    } else {
199
+        // immediately continue with filling tank
200
+        auto wl = plants.getWaterlevel();
201
+        if ((wl != Plants::full) && (wl != Plants::invalid)) {
202
+            // if the waterlevel is currently empty, we
203
+            // set a flag to record the time to fill
204
+            filling_started_empty = (wl == Plants::empty);
205
+
206
+            plants.openWaterInlet();
207
+            selected_id = plants.countPlants() + 1;
208
+            selected_time = MAX_TANK_FILL_TIME;
209
+            start_time = millis();
210
+            switch_to(fullauto_tank_run);
211
+        } else if (wl == Plants::full) {
212
+            // check if kickstart is required for this
213
+            bool need_kickstart = false;
214
+            for (int i = 0; i < plants.countPlants(); i++) {
215
+                if (selected_plants.isSet(i)) {
216
+                    if (plants.getKickstart()->getPinNumber(i) >= 0) {
217
+                        need_kickstart = true;
218
+                    }
219
+                }
220
+            }
221
+
222
+            // start kickstart/valve as needed
223
+            for (int i = 0; i < plants.countPlants(); i++) {
224
+                if (selected_plants.isSet(i)) {
225
+                    plants.startPlant(i, need_kickstart);
226
+                }
227
+            }
228
+
229
+            // for recording the flowrate
230
+            watering_started_full = (wl == Plants::full);
231
+
232
+            selected_time = MAX_AUTO_PLANT_RUNTIME;
233
+            start_time = millis();
234
+            if (need_kickstart) {
235
+                switch_to(fullauto_kickstart_run);
236
+            } else {
237
+                switch_to(fullauto_plant_run);
238
+            }
239
+        } else if (wl == Plants::invalid) {
240
+            error_condition = F("Invalid sensor state");
241
+            state = auto_mode_a;
242
+            switch_to(error);
243
+        }
244
+    }
245
+}
246
+
247
+#endif // TELEGRAM_TOKEN
248
+
175
 void Statemachine::input(int n) {
249
 void Statemachine::input(int n) {
176
     if (state == init) {
250
     if (state == init) {
177
 #if (LOCK_COUNT > 0) && defined(DOOR_LOCK_PIN)
251
 #if (LOCK_COUNT > 0) && defined(DOOR_LOCK_PIN)
1729
         debug.println(state_names[state]);
1803
         debug.println(state_names[state]);
1730
 
1804
 
1731
         menu_entered_digits = "";
1805
         menu_entered_digits = "";
1806
+
1807
+#ifdef PLATFORM_ESP
1808
+        wifi_broadcast_state_change(state_names[state]);
1809
+#endif
1732
     }
1810
     }
1733
     
1811
     
1734
     if (s == init) {
1812
     if (s == init) {

+ 306
- 2
src/WifiStuff.cpp View File

43
 #include "Functionality.h"
43
 #include "Functionality.h"
44
 #include "SimpleUpdater.h"
44
 #include "SimpleUpdater.h"
45
 #include "DebugLog.h"
45
 #include "DebugLog.h"
46
+#include "BoolField.h"
46
 #include "WifiStuff.h"
47
 #include "WifiStuff.h"
47
 
48
 
49
+#ifdef TELEGRAM_TOKEN
50
+
51
+#include <WiFiClientSecure.h>
52
+#include <UniversalTelegramBot.h>
53
+
54
+//#define TELEGRAM_LOG_TIMINGS
55
+
56
+#if defined(ARDUINO_ARCH_ESP8266)
57
+X509List cert(TELEGRAM_CERTIFICATE_ROOT);
58
+#endif
59
+
60
+WiFiClientSecure secured_client;
61
+UniversalTelegramBot bot(TELEGRAM_TOKEN, secured_client);
62
+unsigned long last_telegram_time = 0;
63
+String trusted_chat_ids[] = TRUSTED_IDS;
64
+
65
+#endif // TELEGRAM_TOKEN
66
+
48
 UPDATE_WEB_SERVER server(80);
67
 UPDATE_WEB_SERVER server(80);
49
 WebSocketsServer socket = WebSocketsServer(81);
68
 WebSocketsServer socket = WebSocketsServer(81);
50
 SimpleUpdater updater;
69
 SimpleUpdater updater;
100
 
119
 
101
 #endif // ENABLE_GPIO_TEST
120
 #endif // ENABLE_GPIO_TEST
102
 
121
 
122
+void wifi_broadcast_state_change(const char *s) {
123
+#ifdef TELEGRAM_TOKEN
124
+    for (int n = 0; n < (sizeof(trusted_chat_ids) / sizeof(trusted_chat_ids[0])); n++) {
125
+        bot.sendMessage(trusted_chat_ids[n], "New state: " + String(s), "");
126
+    }
127
+#endif // TELEGRAM_TOKEN
128
+}
129
+
130
+#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
+
143
+unsigned long telegram_update_interval() {
144
+    if (bot_state == BOT_IDLE) {
145
+        return TELEGRAM_UPDATE_INTERVAL_SLOW;
146
+    } else {
147
+        return TELEGRAM_UPDATE_INTERVAL_FAST;
148
+    }
149
+}
150
+
151
+String telegram_help() {
152
+    String s = "Usage:\n";
153
+    s += "Send /auto and follow prompts.\n";
154
+    s += "Send /abort to cancel menus.\n";
155
+    s += "Send /none to skip menus.\n";
156
+    s += "Send /begin to confirm menus.";
157
+    return s;
158
+}
159
+
160
+void telegram_handle_message(int message_id) {
161
+    if (!sm_is_idle()) {
162
+        debug.println("Telegram: message while machine in use");
163
+
164
+        if (bot.messages[message_id].text == "/abort") {
165
+            sm_bot_abort();
166
+            bot.sendMessage(bot.messages[message_id].chat_id, "Aborted current cycle!", "");
167
+        } else {
168
+            bot.sendMessage(bot.messages[message_id].chat_id, "Machine is already in use.\nPlease try again later.", "");
169
+        }
170
+
171
+        return;
172
+    }
173
+
174
+    if ((bot_state == BOT_IDLE) && (bot_lock == "")) {
175
+        bot_lock = bot.messages[message_id].chat_id;
176
+        debug.println("Telegram: locked to " + bot_lock);
177
+    }
178
+
179
+    if (bot_lock != bot.messages[message_id].chat_id) {
180
+        debug.println("Telegram: bot locked. abort for chat " + bot.messages[message_id].chat_id);
181
+        bot.sendMessage(bot.messages[message_id].chat_id, "Bot is already in use.\nPlease try again later.", "");
182
+        return;
183
+    }
184
+
185
+    if (bot_state == BOT_IDLE) {
186
+        if (bot.messages[message_id].text == "/auto") {
187
+            String s = "Please enter fertilizer numbers.\n";
188
+            s += "Valid numbers: 1 to " + String(PUMP_COUNT) + "\n";
189
+            s += "Send /none to skip.\n";
190
+            s += "Send /abort to cancel.";
191
+            bot_ferts.clear();
192
+            bot_state = BOT_ASKED_FERT;
193
+            bot.sendMessage(bot.messages[message_id].chat_id, s, "");
194
+        } else if (bot.messages[message_id].text == "/abort") {
195
+            bot_lock = "";
196
+            bot.sendMessage(bot.messages[message_id].chat_id, "Nothing to abort.", "");
197
+        } else {
198
+            bot_lock = "";
199
+            bot.sendMessage(bot.messages[message_id].chat_id, telegram_help(), "");
200
+        }
201
+    } else if (bot_state == BOT_ASKED_FERT) {
202
+        if (bot.messages[message_id].text == "/abort") {
203
+            bot_state = BOT_IDLE;
204
+            bot_lock = "";
205
+            bot.sendMessage(bot.messages[message_id].chat_id, "Aborted.", "");
206
+            return;
207
+        } else if (bot.messages[message_id].text != "/none") {
208
+            String buff;
209
+            for (int i = 0; i < bot.messages[message_id].text.length() + 1; i++) {
210
+                if ((i == bot.messages[message_id].text.length()) || (bot.messages[message_id].text[i] == ' ')) {
211
+                    if (buff.length() > 0) {
212
+                        int n = buff.toInt() - 1;
213
+                        buff = "";
214
+                        bot_ferts.set(n);
215
+                    }
216
+                } else if ((bot.messages[message_id].text[i] >= '0') && (bot.messages[message_id].text[i] <= '9')) {
217
+                    buff += bot.messages[message_id].text[i];
218
+                } else {
219
+                    bot_state = BOT_IDLE;
220
+                    bot_lock = "";
221
+                    bot.sendMessage(bot.messages[message_id].chat_id, "Invalid input.\nAborted.", "");
222
+                    return;
223
+                }
224
+            }
225
+        }
226
+
227
+        String s = "Please enter plant numbers.\n";
228
+        s += "Valid numbers: 1 to " + String(VALVE_COUNT - 1) + "\n";
229
+        s += "Send /abort to cancel.";
230
+        bot_plants.clear();
231
+        bot_state = BOT_ASKED_PLANTS;
232
+        bot.sendMessage(bot.messages[message_id].chat_id, s, "");
233
+    } else if (bot_state == BOT_ASKED_PLANTS) {
234
+        if (bot.messages[message_id].text == "/abort") {
235
+            bot_state = BOT_IDLE;
236
+            bot_lock = "";
237
+            bot.sendMessage(bot.messages[message_id].chat_id, "Aborted.", "");
238
+            return;
239
+        }
240
+
241
+        String buff;
242
+        for (int i = 0; i < bot.messages[message_id].text.length() + 1; i++) {
243
+            if ((i == bot.messages[message_id].text.length()) || (bot.messages[message_id].text[i] == ' ')) {
244
+                if (buff.length() > 0) {
245
+                    int n = buff.toInt() - 1;
246
+                    buff = "";
247
+                    bot_plants.set(n);
248
+                }
249
+            } else if ((bot.messages[message_id].text[i] >= '0') && (bot.messages[message_id].text[i] <= '9')) {
250
+                buff += bot.messages[message_id].text[i];
251
+            } else {
252
+                bot_state = BOT_IDLE;
253
+                bot_lock = "";
254
+                bot.sendMessage(bot.messages[message_id].chat_id, "Invalid input.\nAborted.", "");
255
+                return;
256
+            }
257
+        }
258
+
259
+        if (bot_plants.countSet() <= 0) {
260
+            bot_state = BOT_IDLE;
261
+            bot_lock = "";
262
+            bot.sendMessage(bot.messages[message_id].chat_id, "No plants selected.\nAborted.", "");
263
+            return;
264
+        }
265
+
266
+#ifdef FULLAUTO_MIN_PLANT_COUNT
267
+        if (bot_plants.countSet() < FULLAUTO_MIN_PLANT_COUNT) {
268
+            bot_state = BOT_IDLE;
269
+            bot_lock = "";
270
+            bot.sendMessage(bot.messages[message_id].chat_id, "Select at least " + String(FULLAUTO_MIN_PLANT_COUNT) + " plants.\nAborted.", "");
271
+            return;
272
+        }
273
+#endif
274
+
275
+        String s = "Input accepted.\nFertilizers:";
276
+        for (int i = 0; i < PUMP_COUNT; i++) {
277
+            if (bot_ferts.isSet(i)) {
278
+                s += " " + String(i + 1);
279
+            }
280
+        }
281
+        s += "\nPlants:";
282
+        for (int i = 0; i < (VALVE_COUNT - 1); i++) {
283
+            if (bot_plants.isSet(i)) {
284
+                s += " " + String(i + 1);
285
+            }
286
+        }
287
+        s += "\nOk? Send /begin to start or /abort to cancel.";
288
+        bot_state = BOT_ASKED_CONFIRM;
289
+        bot.sendMessage(bot.messages[message_id].chat_id, s, "");
290
+    } else if (bot_state == BOT_ASKED_CONFIRM) {
291
+        if (bot.messages[message_id].text == "/abort") {
292
+            bot_state = BOT_IDLE;
293
+            bot_lock = "";
294
+            bot.sendMessage(bot.messages[message_id].chat_id, "Aborted.", "");
295
+        } else if (bot.messages[message_id].text == "/begin") {
296
+            bot_state = BOT_IDLE;
297
+            bot_lock = "";
298
+            bot.sendMessage(bot.messages[message_id].chat_id, "Auto watering cycle started.", "");
299
+            sm_bot_start_auto(bot_ferts, bot_plants);
300
+        } else {
301
+            bot_state = BOT_IDLE;
302
+            bot_lock = "";
303
+            bot.sendMessage(bot.messages[message_id].chat_id, "Unknown message.\nAborted.", "");
304
+        }
305
+    } else {
306
+        debug.println("Telegram: invalid state");
307
+        bot_state = BOT_IDLE;
308
+        bot_lock = "";
309
+        bot.sendMessage(bot.messages[message_id].chat_id, "Internal error.\nPlease try again.", "");
310
+    }
311
+}
312
+
313
+void telegram_handler(int message_id) {
314
+    debug.println("Telegram: rx " + bot.messages[message_id].chat_id + " \"" + bot.messages[message_id].text + "\"");
315
+
316
+    bool found = false;
317
+    for (int n = 0; n < (sizeof(trusted_chat_ids) / sizeof(trusted_chat_ids[0])); n++) {
318
+        if (trusted_chat_ids[n] == bot.messages[message_id].chat_id) {
319
+            found = true;
320
+            break;
321
+        }
322
+    }
323
+    if (!found) {
324
+        bot.sendMessage(bot.messages[message_id].chat_id, "Sorry, not authorized!", "");
325
+        return;
326
+    }
327
+
328
+    telegram_handle_message(message_id);
329
+}
330
+
331
+void telegram_poll() {
332
+#ifdef TELEGRAM_LOG_TIMINGS
333
+    unsigned long start = millis();
334
+#endif // TELEGRAM_LOG_TIMINGS
335
+
336
+    while (int count = bot.getUpdates(bot.last_message_received + 1)) {
337
+        for (int i = 0; i < count; i++) {
338
+            telegram_handler(i);
339
+        }
340
+    }
341
+
342
+#ifdef TELEGRAM_LOG_TIMINGS
343
+    unsigned long end = millis();
344
+    debug.println("Telegram: took " + String(end - start) + "ms");
345
+#endif // TELEGRAM_LOG_TIMINGS
346
+}
347
+
348
+void telegram_hello() {
349
+    for (int n = 0; n < (sizeof(trusted_chat_ids) / sizeof(trusted_chat_ids[0])); n++) {
350
+        bot.sendMessage(trusted_chat_ids[n], "Giess-o-mat v" FIRMWARE_VERSION " initialized.\nSend /auto to begin.", "");
351
+    }
352
+}
353
+#endif // TELEGRAM_TOKEN
354
+
103
 bool wifi_write_database(int duration, const char *type, int id) {
355
 bool wifi_write_database(int duration, const char *type, int id) {
104
     bool success = false;
356
     bool success = false;
105
 
357
 
610
 #endif
862
 #endif
611
 
863
 
612
     message += F("<p>\n");
864
     message += F("<p>\n");
865
+#ifdef TELEGRAM_TOKEN
866
+    message += F("Telegram: ");
867
+    message += TELEGRAM_UPDATE_INTERVAL_SLOW;
868
+    message += F("ms / ");
869
+    message += TELEGRAM_UPDATE_INTERVAL_FAST;
870
+    message += F("ms\n");
871
+#else
872
+    message += F("Telegram bot not enabled!\n");
873
+#endif
874
+    message += F("</p>\n");
875
+
876
+    message += F("<p>\n");
613
 #ifdef ENABLE_INFLUXDB_LOGGING
877
 #ifdef ENABLE_INFLUXDB_LOGGING
614
     message += F("InfluxDB: ");
878
     message += F("InfluxDB: ");
615
     message += INFLUXDB_DATABASE;
879
     message += INFLUXDB_DATABASE;
735
 
999
 
736
 void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t length) {
1000
 void webSocketEvent(uint8_t num, WStype_t type, uint8_t *payload, size_t length) {
737
     if ((type != WStype_TEXT) || (length != 1)) {
1001
     if ((type != WStype_TEXT) || (length != 1)) {
1002
+        debug.println("Websocket: invalid type=" + String(type) + " len=" + String(length) + " data=" + String((char *)payload));
738
         return;
1003
         return;
739
     }
1004
     }
740
     
1005
     
764
     debug.print("WiFi: connecting");
1029
     debug.print("WiFi: connecting");
765
     WiFi.begin(WIFI_SSID, WIFI_PW);
1030
     WiFi.begin(WIFI_SSID, WIFI_PW);
766
 
1031
 
1032
+#ifdef TELEGRAM_TOKEN
1033
+    secured_client.setTrustAnchors(&cert);
1034
+#endif // TELEGRAM_TOKEN
1035
+
767
     while (((ws = WiFi.status()) != WL_CONNECTED) && (connect_attempts < MAX_WIFI_CONNECT_ATTEMPTS)) {
1036
     while (((ws = WiFi.status()) != WL_CONNECTED) && (connect_attempts < MAX_WIFI_CONNECT_ATTEMPTS)) {
768
         connect_attempts++;
1037
         connect_attempts++;
769
         debug.print(String(" ") + String(ws));
1038
         debug.print(String(" ") + String(ws));
797
     WiFi.mode(WIFI_STA);
1066
     WiFi.mode(WIFI_STA);
798
     WiFi.begin(WIFI_SSID, WIFI_PW);
1067
     WiFi.begin(WIFI_SSID, WIFI_PW);
799
 
1068
 
1069
+#ifdef TELEGRAM_TOKEN
1070
+    secured_client.setCACert(TELEGRAM_CERTIFICATE_ROOT);
1071
+#endif // TELEGRAM_TOKEN
1072
+
800
     while (((ws = WiFi.status()) != WL_CONNECTED) && (connect_attempts < MAX_WIFI_CONNECT_ATTEMPTS)) {
1073
     while (((ws = WiFi.status()) != WL_CONNECTED) && (connect_attempts < MAX_WIFI_CONNECT_ATTEMPTS)) {
801
         connect_attempts++;
1074
         connect_attempts++;
802
         debug.print(String(" ") + String(ws));
1075
         debug.print(String(" ") + String(ws));
838
 #ifdef ENABLE_GPIO_TEST
1111
 #ifdef ENABLE_GPIO_TEST
839
     server.on("/gpiotest", handleGpioTest);
1112
     server.on("/gpiotest", handleGpioTest);
840
 #endif // ENABLE_GPIO_TEST
1113
 #endif // ENABLE_GPIO_TEST
841
-    
1114
+
1115
+#ifdef TELEGRAM_TOKEN
1116
+    debug.print("WiFi: getting NTP time");
1117
+    configTime(0, 0, "pool.ntp.org");
1118
+    time_t now = time(nullptr);
1119
+    while (now < 24 * 60 * 60) {
1120
+        debug.print(".");
1121
+        delay(100);
1122
+        now = time(nullptr);
1123
+    }
1124
+    debug.println(" done!");
1125
+    debug.println("WiFi: time is " + String(now));
1126
+
1127
+    debug.println("WiFi: initializing Telegram");
1128
+    const String commands = F("["
1129
+        "{\"command\":\"auto\", \"description\":\"Start automatic watering cycle\"},"
1130
+        "{\"command\":\"confirm\", \"description\":\"Proceed with any menu inputs\"},"
1131
+        "{\"command\":\"none\", \"description\":\"Proceed without menu input\"},"
1132
+        "{\"command\":\"abort\", \"description\":\"Cancel any menu inputs\"}"
1133
+    "]");
1134
+    bot.setMyCommands(commands);
1135
+    telegram_hello();
1136
+#endif // TELEGRAM_TOKEN
1137
+
842
     server.begin();
1138
     server.begin();
843
     MDNS.addService("http", "tcp", 80);
1139
     MDNS.addService("http", "tcp", 80);
844
-    
1140
+    MDNS.addService("http", "tcp", 81);
1141
+
845
     socket.begin();
1142
     socket.begin();
846
     socket.onEvent(webSocketEvent);
1143
     socket.onEvent(webSocketEvent);
847
     
1144
     
880
         runGpioTest(gpioTestState);
1177
         runGpioTest(gpioTestState);
881
     }
1178
     }
882
 #endif // ENABLE_GPIO_TEST
1179
 #endif // ENABLE_GPIO_TEST
1180
+
1181
+#ifdef TELEGRAM_TOKEN
1182
+    if ((millis() - last_telegram_time) >= telegram_update_interval()) {
1183
+        telegram_poll();
1184
+        last_telegram_time = millis();
1185
+    }
1186
+#endif // TELEGRAM_TOKEN
883
 }
1187
 }
884
 
1188
 
885
 #endif // PLATFORM_ESP
1189
 #endif // PLATFORM_ESP

Loading…
Cancel
Save