ESP_IOT v2.5
IOT ESP Coding
MQTTNetworking.cpp
Go to the documentation of this file.
1/**
2* \link MQTTModule \endlink
3*/
4
5/** The MQTT + WIFI part
6
7
8 Created: on Jan 1, 2022
9 Author: Scott Moody
10 test..
11 */
12
13//#define VERSION "Version 1.6a - 3.8.22" NOW defined in Defines.h
14
15#include "../../Defines.h"
16
17#ifdef USE_CAMERA_MODULE_XXX
18#include <HTTPClient.h>
19#endif //USE_CAMERA_MODULE
20
21#define DECODE_BASE64
22#ifdef DECODE_BASE64
23
24//! 9.27.23 to decode a base64 string (a Semantic Marker)
25#include <libb64/cdecode.h>
26#endif
27
28
29//!@see https://www.carletonsheets.com/assets/shared/usr/share/doc/doxygen-1.8.5/html/commands.html#cmdlink
30
31//!Ambers 22nd birthday.. 2.20.22
32
33//! 7.1.23 Dad's 92nd birthday
34#include "SMARTButton.h"
35
36/**
37 Testing:
38 1. the bootstrap of MQTT
39 1.a use a bad password and bad user
40 1.b see if it stops trying after a MAX tries
41 2. send the credentials over BLE
42 2.a use a bad password and bad user
43 2.b see if it stops trying after MAX tries
44 3. have a bad WIFI (so it won't connect)
45 3.a see if it stops trying after a bit
46 4. has valid WIFI and MQTT
47 4.1 see it connects
48 5. Using BOOTSTRAP
49 5.a see if it connects
50 5.b turn off BOOTSTRAP - re-upload script
51 5.c see if it reads the EPROM correctly
52 TODO: send status information back over BLE since iPhone has a UI to troubleshoot..
53 */
54
55#include "MQTTNetworking.h"
56
57#define ESP_EPROM_NAME "ESP32"
58
59
60//! 8.16.25 MQTT
61#include "OTAImageUpdate.h"
62
63/*******************************MQTT*************************************/
64//!added 1.1.2022 by iDogWatch.com
65//!CURRENTLY, this code below only has constant: usersP/bark as a super subscription
66//!This could be passed in via JSON later..
67
68//https://www.arduino.cc/en/Reference/BLECharacteristicConstructor
69
70//! 3.3.22 Using the new JSON library which is supposed to catch syntax errors without blowing up
71//https://arduinojson.org/?utm_source=meta&utm_medium=library.properties
72//!@see https://arduinojson.org/?utm_source=meta&utm_medium=library.properties
73//!Using 6.19.4 as of 6.10.26
74//!going to convert to 7.4.3 6.10.26
75//!see if compiles
76#include <ArduinoJson.h>
77
78//the EPROM is in preferences.h
79#include <Preferences.h>
80
81#ifdef USE_REST_MESSAGING
82#include <WiFiClientSecure.h>
83#else
84#include <WiFi.h>
85#endif
86#include <PubSubClient.h>
87
88// wifi config store. wifi配置存储的类
90
91//Can't seem to reuse this as a global .. it gets appended to, etc.
92//DynamicJsonDocument myObject(1024);
93
94//!just update the EPROM, and send that to the WIFI_AP module as well
96
97//!setup the WIFI using ssid and password
98void setupWIFI(char * arg_ssid, char * arg_password);
99
100//reset on success
102//this is the number of times to retry again, after trying WIFI again..
103#define MAXglobalMQTTAttempts 10 //2
104// the number of times to retry MQTT before trying WIFI again (then only MAXglobalMQTTAttemtt
105#define MAX_MQTT_ATTEMPTS 10 //4
106
107//max times to try the WIFI before attempting again..
108#define MAX_WIFI_CONNECT_ATTEMPTS 30
109
110//forward declarations
111//!process an MQTT message looking for keywords (barklet language)
112void processBarkletMessage(String message, String topic);
113
114//!setup the MQTT server
115void setupMQTT(char* mqttServerString, char *mqttPortString, char *mqttPasswordString, char *mqttUserString, char *deviceNameString, char *uuidString); //forward
116
117//!process the JSON message (looking for FEED, etc). Note: topic can be nil, or if not, it's an MQTT topic (so send replies if you want)
118boolean processJSONMessageMQTT(char *ascii, char *topic);
119
120//check for MQTT messages???
122
123
124//!blinks the blue light
125void blinkBlueLightMQTT();
126
127//called to setup the MQTT (which is really the _mqttClient setup). Done on it's own thread..
128void callPreSetupMQTT();
129
130//!setup the WIFI
131//void setup_WIFI(char *ssidString, char *ssidPasswordString);
132
133//!read any values from EPROM
135
136//!uptime since last reboot.
138
139//Methods: setupMQTT();
140// checkMQTTMessages_loop()
141
142#define OTA "#OTA"
143
144#define STATUS "#STATUS"
145//NOTE: the "Me" names are known and keep them..
146#define REMOTEME "#remoteMe"
147#define REMOTE2 "#REMOTE"
148#define FEED "#FEED"
149#define FEED_2 "#feedme"
150#define ACK_FEED "#actMe"
151#define ACK_FEED2 "#ackMe"
152#define CONNECTED "#connectedMe"
153#define NOT_CONNECTED "#noconnectedMe"
154#define NO_ACK_FEED "#noactMe"
155#define PLAY_ME "#playMe"
156#define DOCFOLLOW "#docFollow"
157#define DOCFOLLOW2 "#DOCFOLLOW"
158#define DOCSYNC "#docSync"
159#define NO_CAN "#NO_CAN"
160//!DOCFOLLOW syntax 8.11.22
161//! syntax: #followMe {AVM=<avm address>} .. no quotes
162#define FOLLOW_ME "#followMe"
163
164//!The WIFI client
165WiFiClient _espClient;
166
167//! 8.17.25
168//! for use by others, like RTSP
169//! return the WiFi Client
170//WiFiClient getWIFIClient()
171//{
172// return _espClient;
173//}
174
175//!The PubSub MQTT Client
177
178//! CONNECTION counters
181
182//!Decode the URL (copied from WIFI_APModule. Easier than breaking modules)
183String MQTT_urlDecode(String input);
184
185// *********************** METHODS invoked from BLE (JSON) and MQTT messages ***************
186//!perform the OTA update. This calls the OTAImageUpdate methods (via preformOTAUpdateSimple())
188//!calls the method for cleaning the SSID eprom. This calls the WIFI_APModule callback
190//!calls the FEED message via the callback (which calls the BLE code)
191void performFeedMethod(char* topic);
192
193//! the short version
195
196//! return a short version of VERSION
198{
199 return _shortVersion;
200}
201//! init short version
203{
204 int len = strlen("Version-(3.7)-3.22.24")+3;
205 strncpy(_shortVersion,VERSION, len);
206 _shortVersion[len] = '\0';
207}
208// *********************** END SPECIFICATION AND GLOBAL VARIABLES ******
209
210//!returns seconds since first booted
212{
214 return uptime;
215}
216
217//!define here as well.. NOTE: this could be passed is as well... TODO
218
219
220// NTP server to request epoch time
221const char* _ntpServer = "pool.ntp.org";
222
223// flag that the MQTT is running..
224boolean _MQTTRunning = false;
225
226#ifdef PROCESS_SMART_BUTTON_JSON
227//!define this storage once, and use everwhere..
228#define MAX_MESSAGE 2024
229#else
230#ifdef ESP_M5
231#define MAX_MESSAGE 1024
232#else
233#define MAX_MESSAGE 600
234//1235178, 63708 (600 max)
235//1235178 64980 1024
236#endif //ESP_M5
237#endif
238#define MAX_MESSAGE_DOCFOLLOW 500
239//!message received on subscription
241//! message to send out
243
244#ifdef ESP_M5
246#endif //SEP_M5
247
248//!saves the group topic .. to write back on ..
250
251//!Points to strings read from JSON (limited to 15 char key name)
252#define _preferencesJSONName "JSONPrefs"
266
267//!this is sent from the backend as a message {'guest':'guest password'} .. but lets' add to the credentials..
268//char* _mqttGuestPasswordString = NULL;
269
270/**
271 2 kinds of #remoteMe messages, one JSON the other URL query
272 For now skip the URL
273 MessageArrived: '#remoteMe {AliensOnMars} {#connectedMe} {I,F} {'T':'1706135533','dev':'AliensOnMars','user':'scott@konacurrents.com','location':'Buckley, WA','ble':'PTFeeder','v':'Version-(2.9a)-1.16.2024-ESP_32_FEEDER_GROUPS3_WIFI_AP',}', onTopic=usersP/bark/scott@konacurrents.com
274 MessageArrived: '#remoteMe {M5AtomSocket} {AVM=status?v=v7&dev=M5AtomSocket&b=100&temp=00&c=0&t=0&socket=off&W=on&M=on&B=off&C=off&A=off&T=off&S=on&bleS=PTClicker:M5AtomSocket&Z=off&G=off}', onTopic=usersP/bark/scott@konacurrents.com
275 **/
276
277//! whether message should be skipped for display and debug printouts
278//! uses _fullMessageIn global
280{
281 boolean skip = false;
285#ifdef M5CORE2_MODULE
286 //! 1.24.24 let the JSON versions of #remoteMe go to the display text..
288#else
290#endif
291 )
292 skip = true;
293 return skip;
294}
295
296
297
298//!the publishMQTTMessage is placed here as a placeholder for making the mqtt publish. If needed, this could be moved
299//!to another thread (or the next loop)
300#define TRY_MORE_ASYNC_PROCESSING
301#ifdef TRY_MORE_ASYNC_PROCESSING
302//! Wrapper of the mqttclient publish. NOTE: this might need to be in the loop as well, as the BLE could be the way the message arrived, and we are sending out over MQTT (while in the BLE thread). Don't know??
303void publishMQTTMessage(char *topic, char *message)
304{
305
306
307 SerialMin.printf("Publish message(%s): %s\n",topic, message);
309 {
310 SerialMin.println(" *** MQTT not connected .. message will queue until connected (hopefully)" );
311 }
312 //!publish on the mqttClient object
313 _mqttClient.publish(topic, message);
314
315 //!see if this pushs the publish out.. (otherwise a reply might occure .. an break our _fullMessage)
316 //_mqttClient.loop();
317
318}
319#endif
320
321
322//! Wrapper of the mqttclient publish
324{
326}
327
328
329//! send semantic /smrun
330//! 3.25.24 this is an HTTP not https
331void publishSMRunMessage(char* smrunMessage)
332{
333 SerialMin.printf("publishSMRunMessage: %s\n", smrunMessage);
334#ifdef ATOM_QRCODE_MODULE
335 // _mqttClient.publish(_mqttTopicString, buf, len);
336 //!https://randomnerdtutorials.com/esp32-http-get-post-arduino/
337 //!https://randomnerdtutorials.com/esp32-cam-post-image-photo-server/
338 //!https://raw.githubusercontent.com/RuiSantosdotme/ESP32-CAM-Arduino-IDE/master/ESP32-CAM-HTTP-POST-Image/ESP32-CAM-HTTP-POST-Image.ino
339 //! Lets do a POSt to my whats-this site..
340
341 //!create a WIFI client that talks to just our upload servlet
342 WiFiClient postClient;
343
344 String serverName = "knowledgeshark.me"; // REPLACE WITH YOUR Raspberry Pi IP ADDRESS
345 //String serverName = "example.com"; // OR REPLACE WITH YOUR DOMAIN NAME
346 String serverPath = "/examples/servlets/servlet/RequestParamExample";
347 //!tomcat server.. 8080
348 int serverPort = 8080;
349 SerialDebug.println("2. Connecting to server: " + serverName);
350
351 //!@see https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/POST
352 //! WORKS 3.25.24 !!!
353 if (postClient.connect(serverName.c_str(), serverPort))
354 {
355 String firstname = smrunMessage;
356 //! change the & to the %26
357 firstname.replace("&","%26");
358
359 //! also look for "smart" or "smflowinfo" and change to "smrun"
360 firstname.replace("smart","smrun");
361 firstname.replace("smflowinfo","smrun");
362
363 //firstname = "ScottyBoy";
364
365 SerialDebug.printf("RequstParamExample Connection successful! \n");
366 String head = "--KonaCurrents\r\nContent-Disposition: form-data; name=\"firstname\"\r\nContent-Type: image/jpeg\r\n\r\n";
367 String tail = "\r\n--KonaCurrents--\r\n";
368
369
370 head = "firstname=" + firstname;
371 tail = "";
372 uint32_t imageLen = 0;
373 uint32_t extraLen = head.length() + tail.length();
374 uint32_t totalLen = imageLen + extraLen;
375
376 postClient.println("POST " + serverPath + " HTTP/1.1");
377 postClient.println("Host: " + serverName);
378 //postClient.println("Content-Type: multipart/form-data; boundary=KonaCurrents");
379 postClient.println("Content-Type: application/x-www-form-urlencoded");
380 postClient.println("Content-Length: " + String(totalLen));
381
382 postClient.println();
383 postClient.print(head);
384 postClient.print(tail);
385 //!stop this client (it's recreated each publish)
386 postClient.stop();
387
388 //! WORKS FIRST TIME FROM M5 Camera, to tomcat on KnowledgeShark: 3.25.24 (previosuly the image was 9.17.22)
389
390
391 SerialTemp.println("POST " + serverPath + " HTTP/1.1");
392 SerialTemp.println("Host: " + serverName);
393 SerialTemp.println("Content-Type: application/x-www-form-urlencoded");
394 SerialTemp.println("Content-Length: " + String(totalLen));
395 SerialTemp.println();
396 SerialTemp.print(head);
397 SerialTemp.println(tail);
398
399 }
400 else
401 {
402 SerialDebug.printf("Connection NOT successful! ");
403 publishMQTTMessageDefaultTopic((char*)"Publish of smrun not successful");
404
405 }
406#endif //ATOM_QRCODE_MODULE
407
408}
409
410#ifdef USE_CAMERA_MODULE_XXX
411
412//! Users/scott/Library/Arduino15/packages/m5stack/hardware/esp32/2.0.3/tools/sdk
413#include "esp_camera.h"
414#include "FS.h" // SD Card ESP32
415
416#endif
417//! publish a binary file..
418//! fileExtension is .jpg, .json, .txt etc
419void publishBinaryFile(char *topic, uint8_t * buf, size_t len, String fileExtension)
420{
421 SerialMin.printf("Publish binary file(%s), len=%d\n", topic, len);
422#ifdef ESP_M5
423
424 // _mqttClient.publish(_mqttTopicString, buf, len);
425 //!https://randomnerdtutorials.com/esp32-http-get-post-arduino/
426 //!https://randomnerdtutorials.com/esp32-cam-post-image-photo-server/
427 //!https://raw.githubusercontent.com/RuiSantosdotme/ESP32-CAM-Arduino-IDE/master/ESP32-CAM-HTTP-POST-Image/ESP32-CAM-HTTP-POST-Image.ino
428 //! Lets do a POSt to my whats-this site..
429//#ifdef USE_CAMERA_MODULE
430
431
432 //!create a WIFI client that talks to just our upload servlet
433 WiFiClient postClient;
434
435 String serverName = "knowledgeshark.me"; // REPLACE WITH YOUR Raspberry Pi IP ADDRESS
436 //String serverName = "example.com"; // OR REPLACE WITH YOUR DOMAIN NAME
437 String serverPath = "/examples/servlets/UploadServlet";
438 //!tomcat server.. 8080
439 int serverPort = 8080;
440 SerialDebug.println("2. Connecting to server: " + serverName);
441
442 if (postClient.connect(serverName.c_str(), serverPort))
443 {
444 SerialDebug.printf("Connection successful! len = %d\n", len);
445 String filename = String(_mqttUserString) + "-" + String(getDeviceNameMQTT()) + "-" + String(random(0xffff), HEX) + "." + fileExtension;
446 String head = "--KonaCurrents\r\nContent-Disposition: form-data; name=\"imageFile\"; filename=\"" +
447 filename + "\"\r\nContent-Type: image/jpeg\r\n\r\n";
448 String tail = "\r\n--KonaCurrents--\r\n";
449
450 uint32_t imageLen = len;
451 uint32_t extraLen = head.length() + tail.length();
452 uint32_t totalLen = imageLen + extraLen;
453
454 postClient.println("POST " + serverPath + " HTTP/1.1");
455 postClient.println("Host: " + serverName);
456 postClient.println("Content-Length: " + String(totalLen));
457 postClient.println("Content-Type: multipart/form-data; boundary=KonaCurrents");
458 postClient.println();
459 postClient.print(head);
460
461 uint8_t *fbBuf = buf;
462 size_t fbLen = len;
463 for (size_t n=0; n<fbLen; n=n+1024)
464 {
465 if (n+1024 < fbLen)
466 {
467 postClient.write(fbBuf, 1024);
468 fbBuf += 1024;
469 }
470 else if (fbLen%1024>0)
471 {
472 size_t remainder = fbLen%1024;
473 postClient.write(fbBuf, remainder);
474 }
475 }
476 postClient.print(tail);
477 //!stop this client (it's recreated each publish)
478 postClient.stop();
479
480 //! WORKS FIRST TIME FROM M5 Camera, to tomcat on KnowledgeShark: 9.17.22
481 //!publish location of this file.
482 //String fileURL = "http://" + serverName + ":" + String(serverPort) + "/examples/uploads/" + filename;
483 //!send this out as a DOCFOLLOW message (but different syntax)
484
485 //sprintf(_semanticMarkerString,"#url {%s} {http://%s:%d/examples/uploads/%s}", getDeviceNameMQTT(), &serverName[0], serverPort, &filename[0]);
486 //! 1.20.24 There is an alias on KnowledgeShark.me that points to the http upload location
487 //! /home/ec2-user/httpd/conf/httpd.conf
488 //! Alias /uploads "/var/lib/tomcat8/webapps/examples/uploads"
489 sprintf(_semanticMarkerString,"#url {%s} {https://KnowledgeShark.me/uploads/%s}", getDeviceNameMQTT(), &filename[0]);
490
491 //sendSemanticMarkerDocFollow_mainModule(&fileURL[0]);
492 //! for now only send if it start message starts with "#"
494 //seems to be sent 2 times ...
495 }
496 else
497 {
498 SerialDebug.printf("Connection NOT successful! ");
499 publishMQTTMessageDefaultTopic((char*)"Publish of image not successful");
500
501 }
502
503#endif // ESP_M5
504
505//#endif // USE_CAMERA_MODULE
506
507}
508
509#ifdef USE_SPIFF_MODULE
510
511#include "FS.h"
512#include "SPIFFS.h"
513
514//! publish a binary file..
515//! fileExtension is .jpg, .json, .txt etc
516void publishSPIFFFile_MQTT(char *topic, char *path, int len)
517{
518 char *fileExtension = (char*)"json";
519
520 SerialMin.printf("publishSPIFFFile topic=%s, file(%s) len = %d\n", topic, path, len);
521 // _mqttClient.publish(_mqttTopicString, buf, len);
522 //!https://randomnerdtutorials.com/esp32-http-get-post-arduino/
523 //!https://randomnerdtutorials.com/esp32-cam-post-image-photo-server/
524 //!https://raw.githubusercontent.com/RuiSantosdotme/ESP32-CAM-Arduino-IDE/master/ESP32-CAM-HTTP-POST-Image/ESP32-CAM-HTTP-POST-Image.ino
525 //! Lets do a POSt to my whats-this site..
526
527 //!create a WIFI client that talks to just our upload servlet
528 WiFiClient postClient;
529
530 String serverName = "knowledgeshark.me"; // REPLACE WITH YOUR Raspberry Pi IP ADDRESS
531 //String serverName = "example.com"; // OR REPLACE WITH YOUR DOMAIN NAME
532 String serverPath = "/examples/servlets/UploadServlet";
533 //!tomcat server.. 8080
534 int serverPort = 8080;
535 SerialDebug.println("2. Connecting to server: " + serverName);
536
537 //! to make this json, need to add '[' at front and {}] on back so ..
538 char *addFront = (char*) "[";
539 char *addBack = (char*) "{}]";
540 len = len + strlen(addFront) + strlen(addBack);
541
542 if (postClient.connect(serverName.c_str(), serverPort))
543 {
544 SerialDebug.printf("Connection successful! len = %d\n", len);
545 String filename = String(_mqttUserString) + "-" + String(getDeviceNameMQTT()) + "-" + String(random(0xffff), HEX) + "." + fileExtension;
546 String head = "--KonaCurrents\r\nContent-Disposition: form-data; name=\"imageFile\"; filename=\"" +
547 filename + "\"\r\nContent-Type: file/JSON\r\n\r\n";
548 String tail = "\r\n--KonaCurrents--\r\n";
549
550 uint32_t imageLen = len;
551 uint32_t extraLen = head.length() + tail.length();
552 uint32_t totalLen = imageLen + extraLen;
553
554 postClient.println("POST " + serverPath + " HTTP/1.1");
555 postClient.println("Host: " + serverName);
556 postClient.println("Content-Length: " + String(totalLen));
557 postClient.println("Content-Type: multipart/form-data; boundary=KonaCurrents");
558 postClient.println();
559 postClient.print(head);
560
561
562 fs::FS fs = SPIFFS;
563 //char *path = path;
564
565 //! PROBLEM: if only N lines fit into buffer .. how to delete only up to those lines?
566
567 File file = fs.open(path);
568 if(!file || file.isDirectory()){
569 SerialDebug.println("- failed to open file for reading");
570 return;
571 }
572
573 // add front
574 postClient.write(addFront, strlen(addFront));
575
576 SerialDebug.println(head);
577
578 //now the rest of the lines can be sent..
579 while(file.available())
580 {
581 String line = file.readString();
582 //! 7.25.25 (rainiy TDF last mt stage.
583 //! remove any single quote with double quote
584 //! @see https://docs.arduino.cc/built-in-examples/strings/StringReplace/
585 //! stringTwo.replace("<", "</");
586 line.replace("'", "\"");
587
588 SerialDebug.println(line);
589 //char * cstr = new char [str.length()+1];
590 if (line)
591 {
592 postClient.write(line.c_str(), line.length());
593 }
594 }
595 SerialDebug.println(tail);
596
597 // add back of JSON string..
598 postClient.write(addBack, strlen(addBack));
599
600 file.close();
601
602 //! output the tail
603 postClient.print(tail);
604 //!stop this client (it's recreated each publish)
605 postClient.stop();
606
607 //! 1.20.24 There is an alias on KnowledgeShark.me that points to the http upload location
608 //! /home/ec2-user/httpd/conf/httpd.conf
609 //! Alias /uploads "/var/lib/tomcat8/webapps/examples/uploads"
610 sprintf(_semanticMarkerString,"#url {%s} {https://KnowledgeShark.me/uploads/%s}", getDeviceNameMQTT(), &filename[0]);
611
612#ifdef STOP_THIS_FOR_NOW
613 //! 7.11.26 .. seems to be sending this all over .. wonder if it's my but with SM app??
614 //! 7.25.25 print on serial monitor too..
615 SerialDebug.println(_semanticMarkerString);
616
617 //sendSemanticMarkerDocFollow_mainModule(&fileURL[0]);
618 //! for now only send if it start message starts with "#"
620 //seems to be sent 2 times ...
621#endif
622 }
623 else
624 {
625 SerialDebug.printf("Connection NOT successful! ");
626 publishMQTTMessageDefaultTopic((char*)"Publish of image not successful");
627
628 }
629
630}
631
632#endif // USE_SPIFF
633
634//! These are set by the MQTT callback..
635//! flag to let the processor know there are new messages
637//! the topic the new message came in on..
638String _topic;
639
640//!storage for the full JSON message string to send around..
642
643//! retrieve the Configuration JSON string in JSON format..
645{
646#define TRY_READING_BACK
647#ifdef TRY_READING_BACK
648 //!NEW: 2.21.22
649 //!TRY: reading back..
650 _preferencesMQTTNetworking.begin(ESP_EPROM_NAME, false); //false=read/write..
652 SerialDebug.print("Reading.12 EPROM JSON = ");
653 SerialDebug.println(_fullJSONString? _fullJSONString:"NULL");
654
655 //!check ... _fullMessageOut
656 //! Close the Preferences
658#endif
659 return _fullJSONString;
660}
661
662//!callback with the message if required (like sending the FEED message)
663//!!function pointers: https://www.cprogramming.com/tutorial/function-pointers.html
664//!define as: void callback(char* message)
665//! call processMessage(message, &callback);
666//void setMessageCallbacks(void (*callbackFunction)(char*), void (*blinkTheLED)())
667
668
669//!called for things like the advertisement
671{
672 //! 5.3.25 notset for somereason ..
674 if (!savedDeviceName)
675 savedDeviceName = NOTSET_STRING;
676
678 _deviceNameString = savedDeviceName; //NOTSET_STRING;
679 return _deviceNameString;
680 // return _chipName;
681}
682
683
684// uint32_t _chipId = 0;
685char _chipName[100];
686
687//!create a unique ID (but it needs to be stored.. otherwise it's unique each time??
689{
690 uint32_t chipId = getChipId();
691#ifdef MOVED_TO_MAIN
692 //get chip ID
693 for (int i = 0; i < 17; i = i + 8) {
694 _chipId |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i;
695 }
696#endif
698 sprintf(_chipName, "%s-%d", _deviceNameString, chipId);
699 else
700 sprintf(_chipName, "esp.%d", chipId);
701
702 Serial.printf("ESP32 Chip model = %s Rev %d\n", ESP.getChipModel(), ESP.getChipRevision());
703 Serial.printf("This chip has %d cores\n", ESP.getChipCores());
704 Serial.print("Chip ID: "); Serial.println(getChipIdString());
705 Serial.print("Chip Name: "); Serial.println(_chipName);
706
707 //chipName = "esp." + chipId;
708 //SerialInfo.println(_chipName);
709
710}
711
712#ifdef ESP_M5
713//!This uses the String (*getStatusFunc)(void)) to re-create this..
714//!used by the displayModule to call this for each new status
716{
717 //Make URL for the status..
718 char *statusString = main_currentStatusURL(true);
719
720 // sprintf(_semanticMarkerString,"%s/%s/%s/%s", "https://SemanticMarker.org/bot/sensor", _mqttUserString, _mqttGuestPasswordString, statusString);
721 //shorten..
722 sprintf(_semanticMarkerString,"%s/%s", "https://SemanticMarker.org/bot", statusString);
723
724 SerialLots.print("getDynamicStatusFunc: ");
725 SerialLots.println(_semanticMarkerString);
726
728}
729#endif
730//!examples
731//!https://SemanticMarker.org/bot/status?v=v5&dev=M5WRR&b=71&temp=59&c=0&t=8&W=on&M=on&B=on&C=off&A=off&T=off&S=on&bleS=PTClicker:M5WRR&Z=off&G=on&P=DukeGEN3&t=8
732//!https://SemanticMarker.org/bot/status?v=v5&dev=M55&b=94&temp=54&c=1&t=2&W=on&M=on&B=on&C=on&A=off&T=off&S=on&bleS=PTClicker:M55&Z=off&G=off&t=2
733
734//!storage for last doc follow semantic marker
736//! retrieves the last DocFollow SemanticMarker (from the message #DOCFOLLOW | #followMe {AVM=<SM>}
737//! Or the JSON: {'set':'semanticMarker','val','<URL>}
739{
741}
742
743//! sets the last DocFollow SemanticMarker
745{
746 strcpy(_lastDocFollowSemanticMarker, semanticMarker);
747}
748
749//! a counter to erase the last message if not changed in N calls..
751//!storage of the last message status
753
754//! Put all the storage initialization here..
756{
757 strcpy(_lastMessageStatusURL,"startup");
758 strcpy(_lastDocFollowSemanticMarker,"https://SemanticMarker.org");
759
760 //!3.22.24 add the short version
762}
763
764//! retrieves a token string.. without spaces.
765//! Currently this will be things like
766void setLastMessageStatus(char *token)
767{
768 SerialLots.print("setLastMessageStatus: ");
769 SerialLots.println(token);
771
772 //! 7.20.25
773 //!https://stackoverflow.com/questions/7352099/stdstring-to-char
774 int time = getTimeStamp_mainModule();
775
776 char *deviceName = getDeviceNameMQTT();
777 //! add just the version and device name to start, but add the msg=
778 sprintf(_lastMessageStatusURL,"status?T=%dv=%s&dev=%s&msg=",time, VERSION_SHORT, deviceName);
779
780 //! Make up a shorter version of the message
781 if (strcasecmp(token,"FEED")==0)
782 strcat(_lastMessageStatusURL,"FEED");
783 else if (strcasecmp(token,"STATUS")==0)
784 strcat(_lastMessageStatusURL,"STATUS");
785 else
786 strcat(_lastMessageStatusURL, "none");
787 //!TODO: make sure no spaces ... unless escaped
788
789 SerialTemp.println(_lastMessageStatusURL);
790}
791
792//!empty the status message
794{
796 setLastMessageStatus((char*)"none");
797}
798
799//!returns a string in in URL so: status?battery=84'&buzzon='off' } .. etc
801{
802 //!increment the count
804 //5 (counts) seconds since a change..
806 {
808 }
810}
811
812#ifdef ESP_M5
813//!used by the displayModule to call this for each new status
815{
816 //Make URL for the status..
817 char *statusString = currentMessageStatusURL();
818
819 // sprintf(_semanticMarkerString,"%s/%s/%s/%s", "https://SemanticMarker.org/bot/sensor", _mqttUserString, _mqttGuestPasswordString, statusString);
820 //shorten..
821 sprintf(_semanticMarkerString,"%s/%s", "https://SemanticMarker.org/bot", statusString);
822
823 SerialTemp.print("getDynamicMessageFunc: ");
824 SerialTemp.println(_semanticMarkerString);
825
827}
828#endif //ESP_M5
829//! 4.26.22 50 year anniverssery of Grateful Dead in Frankfurt 1972
830#define WIFI_MQTT_STATES
831#ifdef WIFI_MQTT_STATES
832
833//!the loop part of WIFI
834void setupWIFI_loop();
835//!end of WIFI loop..
836void finishWIFI_Setup();
837//!reconnects and re-subscribes
838//!NOTE: we need the host info...
839void reconnectMQTT_loop();
840
841//!state variables
843{
844 // presetup WIFI
846 //in a wait for WIFI mode
848 //called to start the mqttClient (out of this thread)
850 //in a wait for MQTT mode
852 // all connected WIFI
854 // connectged MQTT
856 //all disconnected WIFI
858 //all disconnected MQTT
861//!the state we are in..
863//!the delay in seconds for each state
865{
866 [preSetupWIFI] = 0.1,
867 [waitingForWIFI]=0.3,
868 [preSetupMQTT]=0.1,
869 [waitingForMQTT]=0.2,
870 [connectedWIFI]=0,
871 [connectedMQTT]=0,
874
875};
876
877#define USE_TIMER_DELAY_CLASS
878//! 3.29.25 RaiiiinIeeeeR Beer movie
879#ifdef USE_TIMER_DELAY_CLASS
882{
883 //! get delay in seconds
884 float seconds = _WIFI_MQTTStateDelays[_WIFI_MQTTState];
885
887}
889{
891}
893{
895}
896#else
897
898//https://www.forward.com.au/pfod/ArduinoProgramming/TimingDelaysInArduino.html
899//! the time the delay started
900unsigned long _delayStart_WIFI_MQTTState;
901//! true if still waiting for delay to finish
902boolean _delayRunning_WIFI_MQTTState = false;
903//! length of delay
904float _delaySeconds_WIFI_MQTTState;
905//!init the delay, this uses the array of delays so we can change easier..
907{
908 float seconds = _WIFI_MQTTStateDelays[_WIFI_MQTTState];
909 SerialLots.printf("startDelay_WIFI_MQTTState(%f)\n", seconds);
910 _delayStart_WIFI_MQTTState = millis(); // start delay
911 _delayRunning_WIFI_MQTTState = true; // not finished yet
912 _delaySeconds_WIFI_MQTTState = seconds;
913
914}
915//!if finished..
917{
918 if (_delayRunning_WIFI_MQTTState && ((millis() - _delayStart_WIFI_MQTTState) >= (_delaySeconds_WIFI_MQTTState * 1000)))
919 {
920 _delayRunning_WIFI_MQTTState = false;
921 return true;
922 }
923 return false;
924}
925
926//!stop the delay
928{
929 _delayRunning_WIFI_MQTTState = false;
930}
931#endif //USE_TIMER_DELAY_CLASS
932
933#endif //MQTT STATES
934
935// *********************** END METHODS invoked from BLE (JSON) and MQTT messages ***************
936
937//! send SPIFF status
938//! 4.4.24
940{
941#ifdef USE_SPIFF_MODULE
942#ifdef USE_SPIFF_MQTT_SETTING_NOT_NOW // 4.14.24 too omuch..
944 {
945 switch (_WIFI_MQTTState)
946 {
947 // presetup WIFI
948 case preSetupWIFI:
949 println_SPIFFModule_JSON((char*)"WIFI_MQTTState", (char*)"preSetupWIFI");
950 break;;
951 //in a wait for WIFI mode
952 case waitingForWIFI:
953 println_SPIFFModule_JSON((char*)"WIFI_MQTTState", (char*)"waitingForWIFI");
954 break;;
955 //called to start the mqttClient (out of this thread)
956 case preSetupMQTT:
957 println_SPIFFModule_JSON((char*)"WIFI_MQTTState", (char*)"preSetupMQTT");
958 break;;
959 //in a wait for MQTT mode
960 case waitingForMQTT:
961 println_SPIFFModule_JSON((char*)"WIFI_MQTTState", (char*)"waitingForMQTT");
962 break;;
963 // all connected WIFI
964 case connectedWIFI:
965 println_SPIFFModule_JSON((char*)"WIFI_MQTTState", (char*)"connectedWIFI");
966 break;;
967 // connectged MQTT
968 case connectedMQTT:
969 println_SPIFFModule_JSON((char*)"WIFI_MQTTState", (char*)"connectedMQTT");
970 break;;
971 //all disconnected WIFI
972 case disconnectedWIFI:
973 println_SPIFFModule_JSON((char*)"WIFI_State", (char*)"disconnectedWIFI");
974 break;;
975 //all disconnected MQTT
976 case disconnectedMQTT:
977 println_SPIFFModule_JSON((char*)"MQTTState", (char*)"disconnectedMQTT");
978 break;;
979 }
980 println_SPIFFModule_JSON((char*)"DeviceName", getDeviceNameMQTT());
981 println_SPIFFModule_JSON((char*)"ChipName", getChipIdString());
982#ifdef ESP_M5_TOO_MUCH
983 println_SPIFFModule_JSON((char*)"DynamicState", (char*)getDynamicStatusFunc());
984#endif
985 println_SPIFFModule_JSON((char*)"WIFI_MQTTState", isConnectedWIFI_MQTTState()?(char*)"connected":(char*)"disconnected");
986 println_SPIFFModule_JSON((char*)"MQTT_MQTTState", isConnectedMQTT_MQTTState()?(char*)"connected":(char*)"disconnected");
987 println_SPIFFModule_JSON((char*)"MQTTConnected", _mqttClient.connected()?(char*)"connected":(char*)"disconnected");
988 }
989#endif // USE_SPIFF_MQTT_SETTING
990#endif //USE_SPIFF_MODULE
991}
992
993//!try a flag so setupMQTTnetworking only called 1 times..
995
996//!setup the MQTT part of networking
998{
999 SerialDebug.println("setup_MQTTNetworking");
1000
1001 //make this non reentrant (only 1 time in a boot of ESP)
1003 {
1004 SerialDebug.println("setupMQTTNetworking already setup..");
1005 return;
1006 }
1007 //!init variables..
1009
1010 // initLastMessageStatusURL();
1011
1012 SerialDebug.println(" .. continue setup_MQTTNetworking");
1014
1015 // sets the _chipName
1016 getChipInfo();
1017
1018 //THIS should output the device name, user name, etc...
1019 SerialInfo.println(_chipName);
1020
1021 //read what was stored, if any..
1023
1024 SerialTemp.print("setupMQTTNetworking ssid="); SerialInfo.print(_ssidString?_ssidString:"NULL");
1025 SerialTemp.print(", password = "); SerialInfo.print(_ssidPasswordString?_ssidPasswordString:"NULL");
1026 SerialTemp.println();
1027
1028 _MQTTRunning = false;
1029
1030 //set the state, then the 'loop' will call setupWIFI(...)
1033
1034 //!starts the delay for WIFI checking, called at startup, and each time the timer finished..
1036}
1037
1038//!value of WIFI connected
1040{
1041
1042 SerialLots.printf("isConnectedWIFI_MQTTState: %s\n", _mqttClient.connected()?"connected":"not connected");
1043 if (!_mqttClient.connected())
1044 {
1045 _MQTTRunning = false;
1046
1047 SerialTemp.printf("isConnectedWIFI_MQTTState: %s\n", _mqttClient.connected()?"connected":"not connected");
1048 return false;
1049 }
1051}
1052//!value of MQTT connected
1054{
1055 return _MQTTRunning;
1056}
1057/**
1058 State:
1059 0 .
1060 1. waitingForWIFI (delaying when
1061 */
1062//!Nice writeup: https://microcontrollerslab.com/esp32-mqtt-publish-multiple-sensor-readings-node-red/
1063//!
1064//! called for the loop() of this plugin
1066{
1067//#define TRY_AGAIN1 //9.19.23
1068#ifdef TRY_AGAIN1
1069 if (!_ssidString || (_ssidString && strlen(_ssidString)==0))
1070 {
1071 SerialDebug.println("loop_MQTTNetworking .. null ssid");
1072 // setDoneWIFI_APModuleFlag(false); // this would turn off BLE server .. not good
1074 //stopDelayCheckWIFI_MQTTNetworking();
1075
1076 }
1077#endif
1078 //only check messages if MQTT is running (or want's to run.. )
1079 if (_MQTTRunning)
1080 {
1082 }
1083
1084 //!check if should try to reconnect to WIF
1086
1087 //!check if a delay was running.. for the STATE..
1089 {
1090 //SerialTemp.printf("delayFinished_WIFI_MQTTState: %d\n", _WIFI_MQTTState);
1091 //what state were we in for the delay.. continue doing that
1092 //NOTE: THese could be function pointers and just call the state we are in loop..
1093 // This is the "delay" loop
1094 switch (_WIFI_MQTTState)
1095 {
1096 case preSetupWIFI:
1097 //setup with WIFI
1099 break;
1100 //in a wait for WIFI mode
1101 case waitingForWIFI:
1103 break;
1104 //called to init the _mqttClient
1105 case preSetupMQTT:
1107 break;
1108 //in a wait for MQTT mode
1109 case waitingForMQTT:
1111 break;
1112 // all connected WIFI
1113 default:
1114 break;
1115 }
1116 }
1117}
1118
1119// ******************************MQTT + WIFI ***********************************
1120
1121//!show the status in string form (from Library/Adruino... WiFiType.h)
1123{
1124 switch (WiFi.status())
1125 {
1126 case WL_NO_SHIELD:return (char*)"WL_NO_SHIELD";
1127 case WL_IDLE_STATUS: return (char*)"WL_IDLE_STATUS";
1128 case WL_NO_SSID_AVAIL: return (char*)"WL_NO_SSID_AVAIL";
1129 case WL_SCAN_COMPLETED: return (char*)"WL_SCAN_COMPLETED";
1130 case WL_CONNECTED :return (char*)"WL_CONNECTED";
1131 case WL_CONNECT_FAILED: return (char*)"WL_CONNECT_FAILED";
1132 case WL_CONNECTION_LOST: return (char*)"WL_CONNECTION_LOST";
1133 default:
1134 case WL_DISCONNECTED: return (char*)"WL_DISCONNECTED";
1135 }
1136}
1137
1138//! a call to see if the WIFI is connected
1139//**** Delay Methods*******
1140#define SINGLE_DELAY
1141#ifdef SINGLE_DELAY
1142//https://www.forward.com.au/pfod/ArduinoProgramming/TimingDelaysInArduino.html
1143//! the time the delay started
1145//! true if still waiting for delayCheckWIFI to finish
1147//! length of delay
1149//!init the delay
1151{
1152 SerialCall.printf("startdelayCheckWIFI_MQTTNetworking: %d\n", seconds);
1153
1155 _delayCheckWIFIRunning_MQTTNetworking = true; // not finished yet
1157
1158}
1159
1160//!get the delay values
1162{
1163 //return 10; // 30 seconds .. changed back to 10 9.19.23 in testing
1164 return 30; // 30 seconds ..
1165}
1166
1167//!starts the delay for WIFI checking, called at startup, and each time the timer finished..
1169{
1171}
1172
1173//!if finished..
1175{
1177 {
1179 SerialCall.println("delayCheckWIFIFinished_MQTTNetworking..");
1180
1181 return true;
1182 }
1183 return false;
1184}
1185
1186//!stop the delay (not called)
1188{
1189 SerialCall.println("stopDelayCheckWIFI_MQTTNetworking _delayRunning=false");
1190
1192}
1193
1194//!checks delay for the WIFI connectivity
1196{
1198 {
1199 //!check and reconnect to the WIFI is not connected
1201 //!restart the timer
1203 }
1204}
1205
1206//!The setup() will call restartDelay_MQTTNetworking
1207//!Each loop will call checkDelaySinceButtonTouched_MQTTNetworking
1208#endif //SINGLE_DELAY
1209
1210//!print a SPIFF timestamp..
1211
1212//!checks if the WIFI is off (or not reachable) and tries consecting again (the 'W' command)
1214{
1215 SerialMin.printf("checkAndReconnectWIFI_MQTTState: %s\n",wifiStatus_MQTT());
1216 boolean tryReconnect = true;
1217 switch (WiFi.status())
1218 {
1219 case WL_NO_SHIELD:
1220 break;
1221 case WL_IDLE_STATUS:
1222 break;
1223 case WL_NO_SSID_AVAIL:
1224 //tryReconnect = false;
1225 break;
1226 case WL_SCAN_COMPLETED:
1227 break;;
1228 case WL_CONNECTED:
1229 //!start outputing SPIFF info
1230#ifdef TOO_MUCH
1232 println_SPIFFModule((char*)"WIFI WL_CONNECTED");
1233#endif
1234 SerialLots.printf("isConnectedWIFI = %s\n",isConnectedWIFI_MQTTState()?"connected":"not connected");
1235 //!it seems the WIFI can reconnect -- but all the MQTT isn't restarted.. So if our internal state things WIFI is off, reconnect anyway..
1237 tryReconnect = true;
1238 else
1239 tryReconnect = false;
1240 break ;
1241 case WL_CONNECT_FAILED:
1242// printTimestamp_SPIFFModule();
1243// println_SPIFFModule((char*)"WIFI WL_CONNECT_FAILED");
1244#ifdef TOO_MUCH
1245 println_SPIFFModule_JSON((char*)"WIFI", (char*)"WL_CONNECT_FAILED");
1246#endif
1247 break;
1248 case WL_CONNECTION_LOST:
1249// printTimestamp_SPIFFModule();
1250// println_SPIFFModule((char*)"WIFI WL_CONNECTION_LOST");
1251#ifdef TOO_MUCH
1252 println_SPIFFModule_JSON((char*)"WIFI", (char*)"WL_CONNECTION_LOST");
1253#endif
1254
1255 break;
1256 case WL_DISCONNECTED:
1257// printTimestamp_SPIFFModule();
1258// println_SPIFFModule((char*)"WIFI WL_DISCONNECTED");
1259#ifdef TOO_MUCH
1260
1261 println_SPIFFModule_JSON((char*)"WIFI", (char*)"WL_DISCONNECTED");
1262#endif
1263
1264 break;
1265 default:
1266 break;
1267
1268 }
1269
1270 //!try reconnecting if not connected (and ssid is available)
1271 if (tryReconnect)
1272 {
1273 //!start outputing SPIFF info
1274// printTimestamp_SPIFFModule();
1275// print_SPIFFModule((char*)"WIFI Reconnect attempt: ");
1276// println_SPIFFModule(wifiStatus_MQTT());
1277
1278#ifdef TOO_MUCH
1279
1280 println_SPIFFModule_JSON((char*)"WIFI_RECONNECT", wifiStatus_MQTT());
1281#endif
1282
1283 SerialMin.println("reconnectAttempt");
1284 //!restart the WIFI and then MQTT connection
1286 }
1287}
1288// ******************************HELPER METHODS, ***********************************
1289
1290//!https://www.arduino.cc/en/Tutorial/Foundations/DigitalPins
1292{
1293 //call method passed in..
1294 // if (_blinkTheLED)
1295 // (*_blinkTheLED)();
1296// callCallbackMain(CALLBACKS_MQTT, MQTT_CALLBACK_BLINK, strdup("blink"));
1298
1299}
1300
1301
1302//!setup the WIFI using ssid and password (called from setup_MQTTNetworking() .. the main setup for this module)
1303void setupWIFI(char * arg_ssid, char * arg_password)
1304{
1305 //state preSetupWIFI
1306 //SerialTemp.printf("setupWIFI(%d)\n", _WIFI_MQTTState);
1307
1308 // We start by connecting to a WiFi network
1309 SerialDebug.printf("1. Connecting to '%s' password = '%s'\n", arg_ssid?arg_ssid:"NULL", arg_password?arg_password:"");
1310
1311 //!save some reason we are in the AP mode
1313 appendPreference_mainModule(PREFERENCE_DEBUG_INFO_SETTING, arg_ssid?arg_ssid:"No SSID");
1314 storePreference_mainModule(PREFERENCE_DEBUG_INFO_SETTING, arg_password?arg_password:"");
1315
1316 //! 4.4.24 format as JSON
1317 //!print a time too..
1318 //!NEED a format for this to distinguish from others..
1319#ifdef TOO_MUCH
1320 println_SPIFFModule_JSON((char*)"setupWIFI", arg_ssid?arg_ssid:(char*)"empty");
1321#endif
1322
1323
1324#ifdef NOT_HELPING
1325 //! 9.19.23 if null . set max loop
1326 if (!arg_ssid || (arg_ssid && strlen(arg_ssid)==0))
1327 {
1328 SerialDebug.println(" NULL SSID in setupWIFI .. so leaving");
1329 // _maxCounterLoop = MAX_WIFI_CONNECT_ATTEMPTS + 1;
1330#define TRY_EXIT3
1331#ifdef TRY_EXIT3
1332 //! 9.19.23 before Van Morrison ..
1333 {
1334 //putting here .. time might have gone too fast..
1336 //stopDelay_WIFI_MQTTState();
1337 // return;
1338 }
1339#endif
1341 // _WIFI_MQTTState = disconnectedWIFI;
1342// return;
1343
1344 }
1345#endif
1346 //!start the WIFI mode and begin
1347 WiFi.mode(WIFI_STA);
1348 WiFi.begin(arg_ssid, arg_password?arg_password:"");
1349
1350 SerialDebug.println("WIF_STA mode..");
1351
1352 //!set the counters..
1353 _counterLoop = 0;
1354 _maxCounterLoop = 0;
1355
1356 //!reset the global attempts .. since we are trying to reconnect
1358
1359 //set the state..
1362}
1363
1364
1365//!the loop part of WIFI. Call this each time the timer is up (the delay() )
1366//! and only go to the next state if state changes to waitingForMQTT
1368{
1369 //SerialTemp.printf("setupWIFI_loop(%d)\n", _WIFI_MQTTState);
1370
1371 if (WiFi.status() == WL_CONNECTED)
1372 {
1373 SerialDebug.println("WiFi.status() == WL_CONNECTED()");
1374#ifdef STORE_DEBUG_INFO
1375 //!debug info
1376 storePreference_mainModule(PREFERENCE_DEBUG_INFO_SETTING, "WiFi.status() == WL_CONNECTED()");
1377#endif
1378 //stop the timer..
1380
1381 //try the autoReconnect (seems default was true .. so no help)
1382 WiFi.setAutoReconnect(true);
1383
1384 //finish up.. let that step change the "state"
1386 }
1388 {
1389#ifdef STORE_DEBUG_INFO
1390
1391 //!debug info
1393#endif
1394 //should still be waitingForMQTT
1395 // the is part of the loop..
1396
1397 _counterLoop++;
1398 //SerialInfo.print(".");
1399 if (_counterLoop > 10)
1400 {
1401 _counterLoop = 0;
1402 //SerialInfo.println();
1403 }
1405
1406 //the delay is set by what state we are in, and this is called back
1407 // if the timer is finished...
1409 }
1410 else //_maxCounterLoop >= MAX_WIFI_CONNECT_ATTEMPTS
1411 {
1412 SerialDebug.println("WIFI **** Cannot connect .. try bluetooth update ... ");
1413
1414#ifdef STORE_DEBUG_INFO
1415
1416 SerialTemp.println("Before storePref");
1417
1418 //!save some reason we are in the AP mode
1419// appendPreference_mainModule(PREFERENCE_DEBUG_INFO_SETTING, get_WIFIInfoString());
1420 SerialTemp.println("after 1. storePref");
1421
1422 storePreference_mainModule(PREFERENCE_DEBUG_INFO_SETTING, "MAX_WIFI_CONNECT_ATTEMPTS .. going to AP mode");
1423 SerialTemp.println("After storePref");
1424#endif
1425
1426 //blink the LED
1427 // blinkBlueLightMQTT();
1429
1430 //stop the timer..
1432#ifdef GO_BACK_TO_ORIGINAL
1433#ifdef TRY_CALLBACK
1434#define TRY_CALLBACK
1435 //NOTE: THis is taken out.. so the credentials are the same.. next time you reboot it should work if
1436 // the wifi ssid is the same.
1437 //NOTE: let's delete the 'ssid' so it goes back into AP mode. via cleadSSID_EPROM
1438 //! call the callback for cleaning the SSID eprom..
1439 callCallbackMain(CALLBACKS_MQTT, MQTT_CLEAN_SSID_EPROM, (char*)"cleanSSID_EPROM");
1440
1441 //showText_displayModule("Retry WIFI");
1442#else
1443 //!9.17.23 8.29.23 Lets just go into AP Mode
1444 //!Keep ProcessClientCmd short to let the callback run. instead change the feeder state flag
1445 //! processes a message that might save in the EPROM.. the cmd is still passed onto other (like the stepper module)
1447 showText_displayModule("AP Mode");
1448#endif
1449#endif // original
1450 }
1451} //
1452//#define TRY_GET_WIFI
1453#ifdef TRY_GET_WIFI
1454//! for getting the Debug of the WIFI info
1455String _WIFIInfoString;
1456//! retrieve the WIFIInfoString
1457String get_WIFIInfoString()
1458{
1459 long rssi = WiFi.RSSI();
1460
1461 _WIFIInfoString = "IP Address: " + WiFi.localIP();
1462 _WIFIInfoString += "\n WIFI SSID" + String(WiFi.SSID());
1463 _WIFIInfoString += "\n RSSI" + rssi;
1464 // _WIFIInfoString += "\n WIFI Status = " + String(wifiStatus_MQTT());
1465
1466 SerialDebug.println(_WIFIInfoString.c_str());
1467 return _WIFIInfoString;
1468}
1469#else
1471{
1472 char buf[50];
1473 sprintf(buf,"%s",WiFi.SSID());
1474 return "\n WIFI SSID: " + String(WiFi.SSID());
1475}
1476#endif
1477
1478//! 3.22.24 get the WIFI SSID for the status
1480{
1481 return WiFi.SSID();
1482}
1483
1484//! print the WIFI info
1486{
1487 SerialMin.println("WiFi connected");
1488 SerialMin.print("IP Address: ");
1489 SerialMin.println(WiFi.localIP());
1490 SerialMin.print("WiFi SSID:");
1491 SerialMin.println(WiFi.SSID());
1492 long rssi = WiFi.RSSI();
1493 SerialMin.print("signal strength (RSSI):");
1494 SerialMin.print(rssi);
1495 SerialMin.println(" dBm");
1496
1497
1498}
1499
1500//!end of WIFI loop..
1502{
1503 SerialMin.println("finishWIFI_Setup()");
1504
1505 //random ?? for the WIFI address?
1506 randomSeed(micros());
1507
1508 //This creates a DHCP address
1509 printWIFIInfo();
1510
1511
1512
1513 addToTextMessages_displayModule("IP ADDRESS");
1514
1515 //NOTE: this is a 192.168.0.130 kind of address. But when the outside MQTT world see it,
1516 // is like : 72.106.50.236:49205 (The address of my entry to my subdomain point ..)
1517
1518 //see if this works: took out to stop confusion..
1519 // getExternalIP();
1520
1521 //configure the time server
1522 configTime(0, 0, _ntpServer);
1523
1524 //set the time on startup
1526
1527 //blink the LED
1529
1530 SerialDebug.println("setupMQTTNetworking_WIFI done..");
1531
1533
1534 //lets kick off a delay.. this could be 0 or 1 ?? the first time
1536
1537
1538}
1539
1540//!called to setup the MQTT (which is really the _mqttClient setup). Done on it's own thread..
1542{
1543 SerialDebug.printf("callPreSetupMQTT(%d, %s)\n", _WIFI_MQTTState, _deviceNameString?_deviceNameString:"NULL");
1544
1545 //
1546 //this would use the values .. and then we save afterwards..
1548
1549 //NEW -
1550 //head to the next .. state == waitingForMQTT
1552
1553 //lets kick off a delay.. this could be 0 or 1 ?? the first time
1555
1556}
1557
1558//! break up the MQTT Handler 8.12.22 as per "My guess is that you have your data collection (from some I2C device) and data delivery intermingled. Separate them so that you have the data in hand before you make the network connection. That will reduce the possibility of timeouts and race conditions. It also makes it easier to add new collection and delivery processes. The more asynchronous you can make these steps, the more robust your application will be overall."
1559
1560
1561//! add globals for knowing the type of message.
1562//! call the check message processing
1563//!state variables
1565{
1566 // usersP/bark/<user>
1568 // usersP/dawgpack
1570 // usersP/bark
1572 // usersP/bark/groups/#
1574
1576
1577//!helper to know it's a dawgpack topic (and not process in most cases). Only support DOCFOLLOW for now..
1579{
1581}
1582//!helper to know it's a superuser topic (and not process in most cases).
1584{
1586}
1587//!helper to know it's a superuser topic (and not process in most cases).
1589{
1591}
1592//!classify a topic
1593void classifyTopic(char *topic)
1594{
1595 //!set the topic type
1596 if (strcmp(topic,"usersP/dawgpack")==0)
1598 else if (strcmp(topic,"usersP/bark") == 0)
1600 else if (containsSubstring(topic,"usersP/groups/"))
1601 {
1603 strcpy(_lastGroupTopic, topic);
1604 SerialDebug.printf("Group Topic: %s\n", topic);
1605 }
1606 else
1608}
1609
1610//!prints the topic on debug
1612{
1613 SerialDebug.print("Topic = ");
1614 switch (_MQTTMessageTopicType)
1615 {
1616 case userTopic:
1617 SerialDebug.println("userTopic");
1618 break;
1619 // usersP/dawgpack
1620 case dawgpackTopic:
1621 SerialDebug.println("dawgPackTopic");
1622 break;
1623 // usersP/bark
1624 case superTopic:
1625 SerialDebug.println("superTopic");
1626 break;
1627 // usersP/bark/groups
1628 case groupTopic:
1629 SerialDebug.println("groupTopic");
1630 break;
1631 }
1632}
1633
1634//if (_MQTTMessageTopicType == superTopic)
1635//if (_MQTTMessageTopicType == dawgpackTopic)
1636
1637
1638
1639//!called when data on the MQTT socket
1640void callbackMQTTHandler(char* topic, byte* payload, unsigned int length)
1641{
1642 SerialLots.printf("callbackMQTTHandler topic: %s\n", topic);
1643 int i = 0;
1644 for (i = 0; i < length && i < MAX_MESSAGE; i++) {
1645 _fullMessageIn[i] = (char)payload[i];
1646 }
1647 _fullMessageIn[i] = (char)NULL;
1648
1649 //note there is a strange issue where a "null" is showing up in my MQTT/Websocket path
1650 //eg: Message arrived [idogwatch/bark] Guest35: null
1651 //sow for now.. not processing if the message has a "null"
1652 if (containsSubstring(_fullMessageIn, "null"))
1653 {
1654 //don't process..
1655 return;
1656 }
1657
1658 //! too many printouts which actully slows things down.. start with actMe (or collect a count of #actme and report that??)
1659 if (!skipMessageProcessing())
1660 SerialDebug.printf("1.MessageArrived: '%s', onTopic=%s\n", _fullMessageIn, topic);
1661
1662 //!classify the topic type
1663 classifyTopic(topic);
1664
1665 //! 7.26.23 don't process if a group message and FLAG not set
1667 {
1668 // if the EPROM says not to process groups .. then skip this message..
1669 //! called to set a preference (which will be an identifier and a string, which can be converted to a number or boolean)
1671 {
1672 SerialDebug.printf("NOT PRocessing as PREFERENCE_SUPPORT_GROUPS_SETTING not set");
1673 return;
1674 }
1675 //! 8.2.24 support the not receiving message on some topics (such as a users GuestTopic)
1676 //! Idea would be some devices won't listen to the guest topic (instead only the user safe ones)
1677 else if (!topicInIncludeGroup(topic))
1678 {
1679 SerialDebug.printf("2.NOT Processing as topic not in Include Group: %s", topic);
1680 return;
1681 }
1682 }
1683
1684 //! 1.14.24 https://github.com/konacurrents/ESP_IOT/issues/297
1685 //! Only lets group messages for specific messages. For now, lets have a method() that
1686
1687
1688 //!NOTE: This assumes the callbackMQTTHandler is only called once per message processed, as the next time in the loop(), it processes this _fullMessage since the _newMQTTMessageArrived == true
1689
1690#ifdef TRY_MORE_ASYNC_PROCESSING
1691 _topic = topic;
1693 SerialLots.printf("2.MessageArrived: '%s', onTopic=%s\n", _fullMessageIn, topic);
1694
1695#else
1696 //!save some part of this message for later display by SemanticMarker 8.4.22
1697 // setLastMessageStatus(_fullMessage);
1698
1699 //process this message (We don't recognize just a JSON config yet..) That arrives on bluetooth
1701
1702 //send to the Display .. but truncate
1703 //! 11.7.22 if it's an #actMe .. don't show
1704 if (!skipMessageProcessing())
1706
1707#endif
1708 SerialLots.println(" -- DONE processsBarkletMessage ----");
1709}
1710
1711
1712
1713//!reconnects and re-subscribes
1714//!NOTE: we need the host info...
1716{
1717 //SerialTemp.println("reconnectMQTT_loop()");
1718//#define NOTNOW
1719#ifdef NOTNOW
1721 {
1722 SerialDebug.println(" *** No ssid or password");
1723 //! MQTT is not connecting .. so go to AP mode
1724 //!9.17.23, 8.29.23 Lets just go into AP Mode
1725 //!Keep ProcessClientCmd short to let the callback run. instead change the feeder state flag
1726 //! processes a message that might save in the EPROM.. the cmd is still passed onto other (like the stepper module)
1728 return;
1729
1730 }
1731#endif
1732 if (_mqttClient.connected())
1733 {
1734 SerialDebug.println("reconnectMQTT_loop: _mqttClient.connected()");
1735#ifdef STORE_DEBUG_INFO
1736 //!save some reason we are in the AP mode
1738#endif
1739
1742 }
1744 {
1745#ifdef STORE_DEBUG_INFO
1746
1747 //!save some reason we are in the AP mode
1754 storePreference_mainModule(PREFERENCE_DEBUG_INFO_SETTING, "STOPPING MQTT connection attempt > max");
1755#endif
1756 SerialDebug.printf("STOPPING MQTT connection attempts: '%s' count=%d\n", _mqttServerString?_mqttServerString:"NULL", _globalMQTTAttempts);
1757
1759
1760 //! 9.17.23 .. I think the cleaning
1761 //! call the callback for cleaning the SSID eprom..
1762 //callCallbackMain(CALLBACKS_MQTT, MQTT_CLEAN_SSID_EPROM, (char*)"cleanSSID_EPROM");
1763#ifdef NOT_IN_ORIGINAL
1764 //! MQTT is not connecting .. so go to AP mode
1765 //!9.17.23, 8.29.23 Lets just go into AP Mode
1766 //!Keep ProcessClientCmd short to let the callback run. instead change the feeder state flag
1767 //! processes a message that might save in the EPROM.. the cmd is still passed onto other (like the stepper module)
1769
1770 // TODO.. why not going into AP mode???
1771#endif
1772 }
1774 {
1775 SerialInfo.println("FAILED MQTT .. so lets try connecting to WIFI again..");
1776 SerialInfo.println("Setting WIFI from JSON parameters");
1777 //try to setup the WIFI again, seems to help.
1778#ifdef STORE_DEBUG_INFO
1779 //!save some reason we are in the AP mode
1780 storePreference_mainModule(PREFERENCE_DEBUG_INFO_SETTING, "FAILED MQTT .. so lets try connecting to WIFI again");
1781#endif
1782 //set the state back to starting WIFI..
1785 }
1786 else
1787 {
1788#ifdef USE_REST_MESSAGING
1789 //setupSecureRESTCall();
1790#endif
1791 //Lets try to connect...
1792 //reset on connection, or new BLE config info...
1794 // _WIFI_MQTTState = waitingForMQTT;
1796
1797 SerialDebug.printf("Attempting MQTT connection: '%s' '%s' '%s' count=%d\n", _mqttServerString?_mqttServerString:"NULL", _mqttUserString?_mqttUserString:"NULL", _mqttPasswordString?_mqttPasswordString:"NULL", _globalMQTTAttempts);
1798
1799 //! if NULL it keeps going, see https://github.com/konacurrents/ESP_IOT/issues/462
1800 //! 9.19.26
1801 if (!_mqttServerString)
1802 {
1803 SerialDebug.printf(" **** NULL mqttServerString .. so not attempting MQTT connect, wait until credentails change \n");
1805
1806 return;
1807 }
1808#ifdef STORE_DEBUG_INFO
1809
1810 //!save some reason we are in the AP mode
1811 appendPreference_mainModule(PREFERENCE_DEBUG_INFO_SETTING, "Attempting MQTT connection:");
1814
1815#endif
1816 // Create a random client ID
1817#ifdef ESP_M5
1818 String clientId = "espM5-";
1819#endif
1820#ifdef ESP_32
1821 String clientId = "esp32-";
1822#endif
1823 clientId += String(random(0xffff), HEX);
1824
1825 //! tack on the user name too...
1826 //! 9.19.26 so we know who ..
1827 clientId += "-";
1828 clientId += main_getUsername();
1829
1830 SerialDebug.printf("attempt _mqttClient.connect(%s)\n", clientId.c_str());
1831
1832 // Attempt to connect NOTE: this takes time...
1833 //TODO: use the argments...
1834 if (_mqttClient.connect(clientId.c_str(), _mqttUserString, _mqttPasswordString))
1835 {
1836
1837
1838
1839 //!try making a bigger packet.. 10.23.22 (seems to help)
1840 //!Looking at the PubSubClient.cpp,
1841 //! if (this->bufferSize < MQTT_MAX_HEADER_SIZE + 2+strnlen(topic, this->bufferSize) + plength) {
1842 _mqttClient.setBufferSize(MAX_MESSAGE + MQTT_MAX_HEADER_SIZE);
1843
1845#ifdef STORE_DEBUG_INFO
1846 //!save for debug
1848#endif
1849
1850 SerialInfo.println("MQTT CONNECTED");
1852
1853 //_mqttTopicString = strdup("usersP/bark/scott@konacurrents.com");
1854 //NOTE: if topic not supported ... no good error message ... it disconnects
1855 //NOTE: no wildcards allowed on statusfeed.
1856 // Once connected, publish an announcement...
1857 //NOTE: _jsonLocationString is null... sometimes.
1858 sprintf(_fullMessageOut, "%s {%s}{'mqttUser':'%s','location':'%s','uptime':'%d',%s,'v':'%s'}", REMOTEME, _deviceNameString?_deviceNameString:"NULL", _mqttUserString?_mqttUserString:"NULL", _jsonLocationString?_jsonLocationString:"somewhere", getUptime(), main_currentStatusJSON(), shortVersion());
1859
1860 SerialInfo.println(_fullMessageOut);
1861
1862#ifdef TRY_MORE_ASYNC_PROCESSING
1863 //publish back on topic
1865#else
1867#endif
1868#ifdef DONT_SEND_FROM_HERE
1869 //! 2.14.26 only request when triggered, DOCOLLOR, or startup
1870 //!TODO: see if this is TOO MUCH ... every time we publish a message we check if SMARTButtons defined?
1871 //! 2.9.26 let others know we have connected
1872 //! 2.9.26 Superbowl Win, Vonn, B1b flyover.. Eagles
1873 //! when connected .. let others get a chance to send messages out...
1875#endif
1876
1877#ifdef NOT_NOW_ONLY_DOCFOLLOW
1878#ifdef TRY_MORE_ASYNC_PROCESSING
1879 //! NOTE publish on the dawgpack as well so a single user can monitor the events..
1880
1881 publishMQTTMessage((char*)"usersP/dawgpack", _fullMessageOut);
1882#else
1883 _mqttClient.publish("usersP/dawgpack", _fullMessageOut);
1884#endif
1885#endif
1886
1887#define TRY_GROUP
1888#ifdef TRY_GROUP
1889 //!@see https://pubs.opengroup.org/onlinepubs/000095399/functions/index.html
1890 //! if the EPROM says not to process groups .. then skip this message..
1891 //! called to set a preference (which will be an identifier and a string, which can be converted to a number or boolean)
1893 {
1894 //!get the group names
1896 SerialDebug.printf("Subscribing to groups as PREFERENCE_SUPPORT_GROUPS_SETTING was set: %s\n", groupNames);
1897
1898 if (strlen(groupNames)==0 || strcmp(groupNames, "#")== 0)
1899 {
1900 //! 7.15.23 have it's own root "groups" so those that subscribe to 'bark' won't get it unless published 2 times (which it is)
1901 //! the wildcard WORKS !!!
1902 _mqttClient.subscribe((char*)"usersP/groups/#");
1903 SerialTemp.printf("Subscribe usersP/groups/#\n");
1904 }
1905 else
1906 {
1907 //!@see https://www.educative.io/answers/splitting-a-string-using-strtok-in-c
1908 //!@see https://www.geeksforgeeks.org/strtok-strtok_r-functions-c-examples/
1909 // parse the group names .. TODO..
1910 /*
1911 The strtok_r() function is a reentrant version strtok(). The saveptr argument is a pointer to a char * variable that is used internally by strtok_r() in order to maintain context between successive calls that parse the same string.
1912
1913 On the first call to strtok_r(), str should point to the string to be parsed, and the value of saveptr is ignored. In subsequent calls, str should be NULL, and saveptr should be unchanged since the previous call.
1914
1915
1916 char *strtok_r(char *str, const char *delim, char **saveptr);
1917
1918 https://linux.die.net/man/3/strtok_r
1919 */
1920 char groupSub[100];
1921 char *str = groupNames;
1922 char *rest = NULL;
1923 char *token;
1924 for (token = strtok_r(str,",",&rest); token != NULL; token = strtok_r(NULL, ",", &rest))
1925 {
1926 sprintf(groupSub,"usersP/groups/%s", token);
1927 _mqttClient.subscribe(groupSub);
1928 SerialTemp.printf("Subscribe %s\n", groupSub);
1929 }
1930
1931 }
1932 }
1933#endif
1934 // ... and resubscribe to same topic 8.3.22
1935 _mqttClient.subscribe(_mqttTopicString);
1936
1937 //add another topic ... (should be ok with usersP/bark/# )
1938
1939 //2.2.22 The root level usersP/bark for messages from the super-user
1940 // _mqttTopicString = strdup("usersP/bark");
1941 // ... and resubscribe to same topic
1942 _mqttClient.subscribe((char*)"usersP/bark");
1943
1944 //! Only subscribe if turned on.. 8.17.22
1946 {
1947 //! 8.15.22 Also subscribe to the dawgpack .. but restrict what it can effect.
1948 //! For example, start with STATUS and DOCFOLLOW
1949 _mqttClient.subscribe((char*)"usersP/dawgpack");
1950 }
1951 _MQTTRunning = true;
1952
1953 //!reset the global attempts .. since we connected
1955
1958 }
1959 else
1960 {
1961#ifdef STORE_DEBUG_INFO
1962
1963 //!save for debug
1966#endif
1967
1968 //receiving state = -2 ???
1969 //https://forum.arduino.cc/t/mqtt-esp32-nodemcu-failed-with-state-2-connecting-to-mqtt/939270
1970 SerialTemp.printf("FAILED, rc=%d, trying again in 0.2 seconds\n", _mqttClient.state());
1971 //or reset something...
1972 // Wait .2 seconds before retrying
1973 //try..
1974 //NOTE: state hasn't changed but should be waitingMQTT..
1976 }
1977 } //while not connected
1978}
1979
1980//!setup the MQTT (called after the WIFI connected)
1981void setupMQTT(char* mqttServerString, char *mqttPortString, char *mqttPasswordString, char *mqttUserString, char *deviceNameString, char *uuidString)
1982{
1983 SerialTemp.println("**** setupMQTT *****");
1984#ifdef STORE_DEBUG_INFO
1985
1987 appendPreference_mainModule(PREFERENCE_DEBUG_INFO_SETTING, mqttServerString?String(mqttServerString):"NULL");
1988 appendPreference_mainModule(PREFERENCE_DEBUG_INFO_SETTING, mqttPortString?String(mqttPortString):"NULL");
1989 appendPreference_mainModule(PREFERENCE_DEBUG_INFO_SETTING, mqttPasswordString?String(mqttPasswordString):"NULL");
1990 appendPreference_mainModule(PREFERENCE_DEBUG_INFO_SETTING, mqttUserString?String(mqttUserString):"NULL");
1991#endif
1992 // make sure the password etc are valid
1993 if (mqttServerString && mqttPortString && mqttPasswordString && mqttUserString)
1994 {
1995 //connect to server:port
1996 int port = atoi(mqttPortString);
1997 _mqttClient.setServer(mqttServerString, port);
1998 _mqttClient.setCallback(callbackMQTTHandler);
1999 _MQTTRunning = true;
2000
2001 //try to connect.. so _MQTTRUnning is not completed, just the next phase..
2002
2003 //! print the WIFI info AGAIN..
2004 printWIFIInfo();
2005
2006 //!debug
2007// storePreference_mainModule(PREFERENCE_DEBUG_INFO_SETTING, get_WIFIInfoString());
2008#ifdef BOMBS
2009 //debug
2010 appendPreference_mainModule(PREFERENCE_DEBUG_INFO_SETTING, "IP Address: " + WiFi.localIP());
2011 // appendPreference_mainModule(PREFERENCE_DEBUG_INFO_SETTING, "WIFI SSID" + WiFi.SSID);
2012
2014
2016#endif
2017 }
2018 else
2019 {
2020
2021#ifdef STORE_DEBUG_INFO
2022 //!debug
2023
2024 storePreference_mainModule(PREFERENCE_DEBUG_INFO_SETTING, "*** No MQTT Server/Port Specified ** abort");
2025#endif
2026 SerialInfo.println(" *** No MQTT Server/Port Specified ** abort");
2027 _MQTTRunning = false;
2028 }
2029
2030#ifdef STORE_DEBUG_INFO
2031
2032 SerialTemp.println("done setupMQTT");
2034#endif
2035
2036}
2037
2038//!check for MQTT messages, called from the main loop()
2040{
2041 //!don't do the loop at same time as check, do it at another time..
2043 {
2044#ifdef TRY_MORE_ASYNC_PROCESSING
2045 //!save some part of this message for later display by SemanticMarker 8.4.22
2046 // setLastMessageStatus(_fullMessageIn);
2047 if (!skipMessageProcessing())
2048 {
2049 //process this message (We don't recognize just a JSON config yet..) That arrives on bluetooth
2050 //! 11.26.25 now via BLE, WIFI or Serial Monitor
2052
2053 //send to the Display .. but truncate
2054 //! 11.7.22 if it's an #actMe .. don't show
2056 }
2057#define COLLECT_SENSOR_STATUS_turn_off_for_now
2058#ifdef COLLECT_SENSOR_STATUS
2059 //! 11.26.25 Birds in flume, Rainier sticking out with clouds around it
2060 //! look for the #remoteMe syntax that is for our paired device
2061 {
2062 char *connectedBLEDeviceName = connectedBLEDeviceName_mainModule()?connectedBLEDeviceName_mainModule():NULL;
2063 //! see if message has our device, et {DEVICE} {AVM=" ... B=on B=off
2064 //! #remoteMe {M5Atom} {AVM=status?T=1764196423&v=v1&dev=M5Atom&b=100&temp=00&c=0&t=0&k=HD&W=on&M=on&B=on&C=on&A=off&S=on&bleS=PTClicker:M5Atom&Z=on&G=off&sm=300}
2065
2066 //! 11.28.25 after nice flume, Eagles:
2067 //! this has to search for "{"<name"}" because the paired like Pair:Atom .. will show up (with B changing ..)
2068 if (connectedBLEDeviceName && containsSubstring(_fullMessageIn, "AVM="))
2069 {
2070 char nameCurly[50];
2071 sprintf(nameCurly, "{%s}", connectedBLEDeviceName);
2072 if (containsSubstring(_fullMessageIn, nameCurly) )
2073 {
2074 //! candidate look for AVM. "B" but not 'b' as that's different.
2075 boolean buzzerOn = containsSubstring(_fullMessageIn, "&B=on");
2076 SerialDebug.println(_fullMessageIn);
2077 //! should send this to the current "plugin" stored like B=on or B=off
2078 //! but only if their identity() == our connected device ??
2079 //! NO: the identity is our device - not the BLE connected device
2080 //! CANNOT send the same syntax or we would be back here again..
2081 sprintf(_fullMessageOut,"#%s Buzzer=%s", connectedBLEDeviceName, buzzerOn?"on":"off");
2082
2083 //! save the buzzer state ..
2085
2086 SerialDebug.println(_fullMessageOut);
2087 //! CANNOT seem to send the status .. as someone else is doing that... l #actMe {dev}
2088 //! 8.16.25 MQTT
2089 //!also send a #STATUS (not working)
2090 // sendMessageMQTT(_fullMessageOut);
2091 }
2092 }
2093 }
2094#endif //COLLECT_SENSOR_STATUS
2095#endif //TRY_MORE_ASYNC_PROCESSING
2096
2097 _newMQTTMessageArrived = false;
2098 }
2099 else
2100 {
2101 _newMQTTMessageArrived = false;
2102 //!call the MQTT infrastructure loop which does it's MQTT messaging
2103 _mqttClient.loop();
2104 }
2105}
2106
2107//!check if the string matches
2108bool stringMatch(String message, String substring)
2109{
2110 return strcmp(&message[0], &substring[0]) == 0;
2111}
2112
2113//!! should be a definition that the bluetooth is ONLINE
2115{
2116 return true;
2117}
2118
2119//!cleans the eprom info
2121{
2122 SerialDebug.println("cleanEPROM_MQTTNetworking");
2123 _preferencesMQTTNetworking.begin(ESP_EPROM_NAME, false); //readwrite..
2126}
2127
2128//! just send a message (let the internals to figure out topics, etc..
2129//!so the BLE can send something on the MQTT
2130//! for now only send if it start message starts with "#"
2131void sendMessageMQTT(char *message)
2132{
2134
2135#ifdef REFACTOR
2136 if (_MQTTRunning)
2137 {
2138 //Basically if we send {'cmd':'buzzon'} -- it comes back to us.. and infinite loop
2139 // for now only send if it start message starts with "#"
2140 if (containsSubstring(message, "#"))
2141 {
2142 sprintf(_fullMessageOut,"%s {%s}", message, _deviceNameString);
2143
2144 //publish this message..
2145// _mqttClient.publish(_mqttTopicString, _fullMessageOut);
2146// SerialTemp.printf("Sending message:%s %s\n",_mqttTopicString, _fullMessageOut);
2147#ifdef TRY_MORE_ASYNC_PROCESSING
2148 //publish back on topic
2150#else
2152#endif
2153 }
2154 }
2155#endif
2156}
2157
2158//! for now only send if it start message starts with "#"
2159void sendMessageMQTT_Topic(char *message, char *topic)
2160{
2161 if (_MQTTRunning)
2162 {
2163 //Basically if we send {'cmd':'buzzon'} -- it comes back to us.. and infinite loop
2164 // for now only send if it start message starts with "#"
2165 if (containsSubstring(message, "#"))
2166 {
2167 sprintf(_fullMessageOut,"%s {%s}", message, _deviceNameString);
2168
2169 //publish this message..
2170 // _mqttClient.publish(_mqttTopicString, _fullMessageOut);
2171 // SerialTemp.printf("Sending message:%s %s\n",_mqttTopicString, _fullMessageOut);
2172#ifdef TRY_MORE_ASYNC_PROCESSING
2173 //publish back on topic
2175#else
2176 _mqttClient.publish(topic, _fullMessageOut);
2177#endif
2178 }
2179 }
2180}
2181
2182//! just send a message but without any extras
2183void sendMessageNoChangeMQTT_Topic(char *message, char *topic)
2184{
2185 if (_MQTTRunning)
2186 {
2187 //Basically if we send {'cmd':'buzzon'} -- it comes back to us.. and infinite loop
2188 // for now only send if it start message starts with "#"
2189
2190 sprintf(_fullMessageOut,"%s", message);
2191
2192 //publish this message..
2193 // _mqttClient.publish(_mqttTopicString, _fullMessageOut);
2194 // SerialTemp.printf("Sending message:%s %s\n",_mqttTopicString, _fullMessageOut);
2195#ifdef TRY_MORE_ASYNC_PROCESSING
2196 //publish back on topic
2198#else
2199 _mqttClient.publish(topic, _fullMessageOut);
2200#endif
2201 }
2202}
2203
2204
2205//! just send a message but without any extras
2206void sendMessageNoChangeMQTT(char *message)
2207{
2209#ifdef REFACTORED
2210 if (_MQTTRunning)
2211 {
2212 //Basically if we send {'cmd':'buzzon'} -- it comes back to us.. and infinite loop
2213 // for now only send if it start message starts with "#"
2214
2215 sprintf(_fullMessageOut,"%s", message);
2216
2217 //publish this message..
2218// _mqttClient.publish(_mqttTopicString, _fullMessageOut);
2219// SerialTemp.printf("Sending message:%s %s\n",_mqttTopicString, _fullMessageOut);
2220#ifdef TRY_MORE_ASYNC_PROCESSING
2221 //publish back on topic
2223#else
2225#endif
2226 }
2227#endif
2228}
2229//! sends the semantic marker as a doc follow message #remoteMe (vs STATUS, as that triggers a status reply.. )
2230void sendStatusMessageMQTT_deviceName(char *deviceName, const char *semanticMarker)
2231{
2232 SerialTemp.println("sendStatusMessageMQTT..");
2233 //! don't call main_currentStatusURL .. since it was already called
2234 sprintf(_fullMessageOut, "#remoteMe {%s} {AVM=%s}", deviceName, semanticMarker);
2235 //sprintf(_fullMessageOut, "#remoteMe {%s} {AVM=%s%s}", deviceName, semanticMarker, main_currentStatusURL(false));
2236 if (_MQTTRunning)
2237 {
2238 // _mqttClient.publish(_mqttTopicString, _fullMessageOut);
2239 // SerialMin.printf("Sending message: %s\n", _fullMessageOut);
2240#ifdef TRY_MORE_ASYNC_PROCESSING
2241 //publish back on topic
2243#else
2245#endif
2246 }
2247}
2248
2249//! sends the semantic marker as a doc follow message #remoteMe (vs STATUS, as that triggers a status reply.. )
2250void sendStatusMessageMQTT(const char *semanticMarker)
2251{
2253}
2254//! sends the semantic marker as a doc follow message
2255void sendDocFollowMessageMQTT(const char *semanticMarker)
2256{
2257 SerialCall.println("sendDocFollowMessageMQTT..");
2258 if (!containsSubstring(semanticMarker,"https"))
2259 sprintf(_fullMessageOut, "#DOCFOLLOW {%s} {AVM=https://SemanticMarker.org/bot/%s}", _deviceNameString, semanticMarker);
2260 else
2261#ifdef ESP_M5_ATOM_LITE
2262 //! using the followme syntax for now..
2263 sprintf(_fullMessageOut, "#followMe {AVM=%s}", semanticMarker);
2264
2265#else
2266 sprintf(_fullMessageOut, "#DOCFOLLOW {%s} {AVM=%s}", _deviceNameString, semanticMarker);
2267#endif
2268 if (_MQTTRunning)
2269 {
2270// _mqttClient.publish(_mqttTopicString, _fullMessageOut);
2271// SerialMin.printf("Sending message: %s\n", _fullMessageOut);
2272#ifdef TRY_MORE_ASYNC_PROCESSING
2273 //publish back on topic
2275#else
2277#endif
2278 }
2279}
2280
2281//!process an MQTT message looking for keywords (this version uses the Barklet Language Grammer @c 2014)
2282//!NOTE: The processJSONMessage() is part of this (called if straight JSON).
2283//!TODO: merge these two methods..
2284void processBarkletMessage(String message, String topic)
2285{
2286 //!https://stackoverflow.com/questions/7352099/stdstring-to-char
2287 int time = getTimeStamp_mainModule();
2288
2289 //!convert String to char *
2290 char *messageString = &message[0];
2291 //!flag to send the message back on MQTT
2292 bool messageValidToSendBack = false;
2293 SerialCall.print("processBarkletMessage: ");
2294 SerialCall.print(message);
2295 SerialCall.print(" topic=");
2296 SerialCall.println(topic);
2297
2298 if (!topic)
2300
2301 //!debug printout..
2302 //printTopicType();
2303
2304 //!new 4.12.22 if this is straight JSON .. then sent to the processJSONmessage
2305 if (processJSONMessageMQTT(messageString, topic?&topic[0]:NULL))
2306 {
2307 //This was processed by the JSON processor
2308 //SerialDebug.println("** not an older Barklet message syntax, but straight JSON ***");
2309 return;
2310 }
2311
2312 //!If the dawgpack, only process the DOCFOLLOW message
2313 //!
2314 //!note: these messages are sent to MQTT. But the messages comming down originated on WebSocket barklets language
2315 //! so the 'remoteMe ..." gets up there, but not back to the rest. It's rewritten by nodered.
2316 if (containsSubstring(message, STATUS) && !isDawgpackTopic())
2317 {
2318 float temp = getTemperature_mainModule();
2319
2320 //!save some part of this message for later display by SemanticMarker 8.4.22
2321 //!set the status
2322 setLastMessageStatus((char*)"status");
2323
2324 char pairedDevice[100];
2326 {
2327 strcpy(pairedDevice,getPairedDevice_mainModule());
2328// strcat(pairedDevice,(char*)":");
2329// strcat(pairedDevice,getPairedDeviceAddress_mainModule());
2330 }
2331 else
2332 strcpy(pairedDevice,"none");
2333 //! 8.16.25 BLE CLIENT
2334 boolean isConnectedBLE = isConnectedBLEClient();
2335
2337 //! process the pair if match
2338 if (isConnectedBLE && isGateway)
2339 {
2340 //! FOR NOW , copy the code and create a _fullMessageOut that is for the Paired device...
2341
2342 sprintf(_fullMessageOut, "%s {%s} {%s} {I,F} {'T':'%d','dev':'%s','user':'%s','location':'%s','v':'%s','ble':'%s,%s}",
2343 REMOTEME,
2344 pairedDevice,
2346 time,
2347 pairedDevice,
2350 shortVersion(),
2351 //! 8.16.25 BLE SERVER
2352 //! retrieve the service name (PTFEEDER, PTFeeder:Name, PTClicker:Name, etc)
2354
2355 // if calling this.. add "%s" to sprintf above..
2357 );
2358
2359 //publish this message..
2360 SerialTemp.printf("GEN3: Sending message: %s\n", _fullMessageOut);
2361
2362 //_mqttClient.publish(_mqttTopicString, _fullMessageOut);
2363#ifdef TRY_MORE_ASYNC_PROCESSING
2364 //publish back on topic
2366#else
2368#endif
2369 //! 5.21.22 WORKS!!
2370 //!topic is the topic we can in on.. so could be super user..
2371 //if (strcmp(&topic[0],"usersP/bark")==0)
2372 if (isSuperTopic())
2373 {
2374 SerialTemp.println("Sending on DawgPack too..");
2375 //publish back on topic
2376 //_mqttClient.publish("usersP/dawgpack", _fullMessageOut);
2377#ifdef TRY_MORE_ASYNC_PROCESSING
2378 //publish back on topic
2379 publishMQTTMessage((char*)"usersP/dawgpack", _fullMessageOut);
2380#else
2381 _mqttClient.publish("usersP/dawgpack", _fullMessageOut);
2382#endif
2383 }
2384 }
2385
2386
2387 //Version-(3.7)-3.22.24-ESP_M5_ATOM_QR_SCAN_SOCKET_SMART_GROUP_CHIPID_SSID'
2388 // Need short version: "(3.7)-3.22.24"
2389 //sprintf(_fullMessageOut, "%s {%s} {%s} {I,F} {T=now}", REMOTEME, _deviceNameString, bluetoothOnline() ? CONNECTED : NOT_CONNECTED);
2390 // Once connected, publish an announcement...
2391 // sprintf(message, "#STATUS {%s} {%s}", _deviceNameString, chipName);
2392#ifdef ESP_M5
2393 sprintf(_fullMessageOut, "%s {%s} {%s} {I,F} {'T':'%d','dev':'%s','user':'%s','location':'%s','ble':'%s','v':'%s','k':'%s','chipid':'%s','ssid':'%s',%s",
2394#else
2395 sprintf(_fullMessageOut, "%s {%s} {%s} {I,F} {'T':'%d','dev':'%s','user':'%s','location':'%s','ble':'%s','v':'%s','k':'%s','chipid':'%s','ssid':'%s'}",
2396#endif
2397 REMOTEME,
2400 time,
2404 //! 8.16.25 BLE SERVER
2405 //! retrieve the service name (PTFEEDER, PTFeeder:Name, PTClicker:Name, etc)
2407
2408
2409 ,shortVersion()
2410 //k='uno':'tblr"
2411 ,(getFeederType_mainModule() == STEPPER_IS_UNO)?(char*)"uno":(char*)"tblr"
2412
2413 //! 'chipid':'%s'
2415 //! 'ssid':'%s'
2416 ,get_WIFI_SSID().c_str()
2417 //! 9.19.26 https://github.com/konacurrents/ESP_IOT/issues/463
2418 //! see if adding c_str() fixes this...
2419#ifdef ESP_M5
2420 //! last %s
2422 );
2423 //! OOPS .. the getPreference overrides the values .. remember!! so this needs to be a strcat version....
2424 //! add the sensorPlugs
2425 //! 'splug':'%s'
2426 strcat(_fullMessageOut,",'splug':'");
2428 strcat(_fullMessageOut,"'");
2429
2430 //! 8.10.25 add the Stepper Angle Kind
2431 //! #393
2432 //! 'sa':'%s
2433 strcat(_fullMessageOut,",'sa':'");
2435 strcat(_fullMessageOut,"'");
2436
2437 //! 5.21.25 add the Atom Kind and the Sensors
2438 //! 'atom':'%s
2439 strcat(_fullMessageOut,",'atom':'");
2441 strcat(_fullMessageOut,"'");
2442 //!sensors':'%s'
2443 strcat(_fullMessageOut,",'sensors':'");
2445 strcat(_fullMessageOut,"'");
2446// /'splug':'%s','atom':'%s','sensors':'%s',
2447 //! last is the dynamic main_currentStatusJSON()
2448 //! finish
2449 strcat(_fullMessageOut,"}");
2450#else
2451 );
2452#endif
2453
2454
2455 messageValidToSendBack = true;
2456
2458
2459 //On demand #STATUS send the statusURL as well (if an M5)
2460 //this queues the sending of the StatusURL over MQTT.
2461 // This is async (next loop) since sending 2 MQTT messages can be hard to do in a row ..
2463
2464 //! send SPIFF status
2465 //! 4.4.24
2467 }
2468 // else if (containsSubstring(message, "#FEED") || containsSubstring(message, "feedme"))
2469 //only use #FEED (the feedme will turn into #FEED)
2470 else if (containsSubstring(message, "#FEED") && !isDawgpackTopic())
2471 {
2472 //! flag for whether feed will occur. it won't if a device is specified and it's not our device (unless super topic)
2473 boolean performFeed = true;
2474#ifdef ESP_M5_CAMERA
2475 performFeed = false;
2476#endif
2477 //!check against the super feeder. If super feeder, then feed all devices, otherwise logic below
2478 if (!isSuperTopic())
2479 //if (!stringMatch(topic, "/usersP/bark") && !stringMatch(topic, "/usersP/dawgpack"))
2480 {
2481 //only check this if not the super feed topic "/usersP/bark" ..
2482 //TODO: not make this hardwired to /usersP/bark
2483 //TODO: 2.2.22
2484 //try 2.19.22 (but simple version..)
2485 //TODO: 7.23.22 .. look if the paired device too..
2486 if (containsSubstring(message, "deviceName"))
2487 {
2488 //since deviceName specified, then only feed if our device is specified..
2490 {
2491 // this could mean a "deviceName" was found, and our _deviceNameString was there.,
2492 // versus actually parsing for "deviceName":ourName
2493 performFeed = true;
2494 }
2496 {
2497 //broke up the if since the get paired device could overright the boolean (or visa versa). Up to the compiler to know the order these are called.. unreliable
2499 {
2500 SerialTemp.println(" *** Feeding via our gateway ***");
2501 performFeed = true;
2502 }
2503 else
2504 {
2505 SerialDebug.println(" ** Not feeding as not our paired device either ***");
2506 performFeed = false;
2507 }
2508
2509 }
2510 else
2511 {
2512 //perform feed... (knowing the message device name requires pqrsing .. so not for now since containsSubstring() suffices..
2513 SerialDebug.printf("**NOT Perform FEED as deviceName doesn't ours: %s\n", _deviceNameString );
2514
2515 performFeed = false;
2516 }
2517 }
2518 }
2519
2520 //if performFeed set, then continue..
2521 if (performFeed)
2522 {
2523 //!perform the feed
2524 performFeedMethod(&topic[0]);
2525
2526 //!message already sent ...
2527 messageValidToSendBack = false;
2528
2529 }
2530 }
2531#ifdef ESP_M5
2532 //!DOCFOLLOW .. support Dawgpack
2533 else if (containsSubstring(message, "#followMe") || containsSubstring(message,"#DOCFOLLOW"))
2534 {
2535 //! retrieves the last DocFollow SemanticMarker (from the message #DOCFOLLOW | #followMe {AVM=<SM>}
2536 //! need to parse to the AVM= grab the <SM> up to the "}"
2537 //!
2538 if (containsSubstring(message,"AVM="))
2539 {
2540 char *indexOfEqual = index(&message[0],'=');
2541 if (strlen(indexOfEqual)>2)
2542 //move past the =
2543 indexOfEqual++;
2545 // loop until the } is found
2546 while (*indexOfEqual && *indexOfEqual !='}')
2547 {
2548 //copy a character at a time until the } (or nill)
2549 strncat(_lastDocFollowSemanticMarker, indexOfEqual,1);
2550 indexOfEqual++;
2551 }
2552 strcat(_lastDocFollowSemanticMarker, "\0");
2553
2554 SerialDebug.printf("1.SemanticMarker: %s\n", _lastDocFollowSemanticMarker);
2555 //setLastDocFollowSemanticMarker(_lastDocFollowSemanticMarker);
2556
2557 //! 2.11.26 Nice day, Mountain Out, puppies gone..
2558 //! send a setval with semantic marker as the 'set'
2559 messageSetVal_mainModule((char*)"SemanticMarker", _lastDocFollowSemanticMarker, false);
2560
2561 //!parse the #followMe {AVM=<url>}
2562 sprintf(_fullMessageOut,"#ACK {%s} {doc_follow=%s}", _deviceNameString, _lastDocFollowSemanticMarker);
2563#ifdef ESP_M5
2564
2565 //! 3.23.25 parse into JSON
2566 //! Then internall process this message (only for this device)
2568 if (strlen(JSON_String) > 0)
2569 {
2570 //! now process this as JSON,
2571 char * my_argument = const_cast<char*> (topic.c_str());
2572 processJSONMessageMQTT(JSON_String, my_argument);
2573 }
2574#endif
2575 }
2576 else
2577 {
2578 sprintf(_fullMessageOut,"#ACK {%s} {bad_doc_follow syntax}", _deviceNameString);
2579
2580 }
2581 messageValidToSendBack = true;
2582 }
2583#ifdef PASS_ONTO_PLUGS
2584 //!note: this might be candidate for wider use
2585 else if (containsSubstring(message, "#CAPTURE") && !isDawgpackTopic())
2586 {
2587#ifdef ESP_M5_CAMERA_not_here
2588 // sprintf(_fullMessageOut, "#TAKING_PIC {%s} {real soon to be implemented 8.11.22}", _deviceNameString);
2589 takePicture_MainModule();
2590
2591#else
2592#ifdef M5_CAPTURE_SCREEN
2594 //sprintf(_fullMessageOut, "#M5_SCREEN {%s} {capturing screen as bmp}", _deviceNameString);
2595#else
2596 //sprintf(_fullMessageOut, "#NO_CAN_CAMERA_CAPTURE {%s} {I am just a chip without a camera}", _deviceNameString);
2597#endif // M5_CAPTURE_SCREEN
2598#endif //ESP_M5_CAMERA
2599 messageValidToSendBack = false;
2600 }
2601#endif //pass onto plugs
2602
2603#endif // ESP_M5
2604 else if (containsSubstring(message, "#TEMP") && !isDawgpackTopic())
2605 {
2606#ifdef ESP_M5
2607 float temp = getTemperature_mainModule();
2608 //SYNTAX should evolve .. backward compatable ..
2609 sprintf(_fullMessageOut,"#ACK {%s} {TEMP} %2.0f F {'temp':'%2.0f'}", _deviceNameString, temp, temp);
2610#else
2611 sprintf(_fullMessageOut, "#NO_CAN_GET_TEMP {%s} {I am just a chip without a temp sensor}", _deviceNameString);
2612#endif
2613 //call the callback specified from the caller (eg. NimBLE_PetTutor_Server .. or others)
2615
2616 messageValidToSendBack = true;
2617 }
2618 //!3.25.22 -- trying the CLEAN the ePROM SSID
2619 else if (containsSubstring(message, "#CLEAN_SSID_EPROM") && !isDawgpackTopic() && !isGroupTopic())
2620 {
2621 //! call the callback for cleaning the SSID eprom..
2622 callCallbackMain(CALLBACKS_MQTT, MQTT_CLEAN_SSID_EPROM, (char*)"cleanSSID_EPROM");
2623
2624 }
2625 //!3.8.22 -- trying the OTA. IT WORKS!!!
2626 //!NOW: 2 versions, 3.28.22, try to parse {v:'version starts with.." ) -- or just contains substring. eg. #OTA Version-1.6a ... and check against our "VERSION"
2627 else if (containsSubstring(message, "#OTA") && !isDawgpackTopic() && !isGroupTopic())
2628 {
2629 boolean performOTAUpdate = true;
2630
2631 //syntax: #OTA {v:VERSION}, or {k:ESP_32 or ESP_M5
2632 if (containsSubstring(message, "{v:"))
2633 {
2634 //does the installed "VERSION" == the string passed in eg. {v:OUR_VERSION} VERSION=OUR_VERSION
2635 // performOTAUpdate = containsSubstring(message, VERSION);
2636 performOTAUpdate = containsSubstring(message, VERSION);
2637
2638 SerialDebug.printf("#OTA version correct: %d\n", performOTAUpdate);
2639 }
2640 else if (containsSubstring(message, "{k:") && !isDawgpackTopic())
2641 {
2642 //does the installed "KIND" == the string passed in eg. {v:ESP_32} we are one or the other..
2643#ifdef ESP_M5
2644 performOTAUpdate = containsSubstring(message, "ESP_M5");
2645 SerialDebug.printf("#OTA match ESP_M5: %d\n", performOTAUpdate);
2646
2647#else
2648 performOTAUpdate = containsSubstring(message, "ESP_32");
2649 SerialDebug.printf("#OTA match ESP_32: %d\n", performOTAUpdate);
2650
2651#endif
2652
2653 }
2654
2655 //parse out the {kind, host, binfile}
2656 //SOON .. this might be a triple click?? or keep the messaging?
2657
2658 if (performOTAUpdate)
2659 {
2660 //NOTE: cannot put #OTA in message or it infinite loops..
2661 sprintf(_fullMessageOut, "over the air binary image update from version: %s", VERSION);
2662 //let clients know what's happening..
2664 SerialLots.printf("Sending message: %s\n", _fullMessageOut);
2665 //blink the light
2667
2668 //! dispatches a call to the command specified. This is run on the next loop()
2670 }
2671 else
2672 {
2673 sprintf(_fullMessageOut, "over the air NOT updating as not matching string: %s",
2674#ifdef ESP_M5
2675 "ESP_M5"
2676#else
2677 "ESP_32"
2678#endif
2679 );
2680 SerialLots.printf("Sending message: %s\n", _fullMessageOut);
2682
2683 }
2684
2685 } //#OTA
2686 else if (isDawgpackTopic())
2687 {
2688 SerialDebug.println("DAWGPACK unsupported message");
2689 }
2690
2691 if (messageValidToSendBack)
2692 {
2693 //publish this message..
2694// _mqttClient.publish(_mqttTopicString, _fullMessageOut);
2695 SerialLots.printf("1.Sending message: %s\n", _fullMessageOut);
2696#ifdef TRY_MORE_ASYNC_PROCESSING
2697 //publish back on topic
2699#else
2701#endif
2702
2703 //! 5.21.22 WORKS!!
2704 //!topic is the topic we can in on.. so could be super user..
2705 //if (strcmp(&topic[0],"usersP/bark")==0)
2706 if (isSuperTopic() || isDawgpackTopic())
2707 {
2708 SerialTemp.println("2.Sending on DawgPack too..");
2709 //publish back on topic
2710 // _mqttClient.publish("usersP/dawgpack", _fullMessageOut);
2711#ifdef TRY_MORE_ASYNC_PROCESSING
2712 //publish back on topic
2713 publishMQTTMessage((char*)"usersP/dawgpack", _fullMessageOut);
2714#else
2715 _mqttClient.publish("usersP/dawgpack", _fullMessageOut);
2716#endif
2717 }
2718
2719 //! 7.15.23 anniversery of 1799 finding Rosetta Stone in Egypt
2720 if (isGroupTopic())
2721 {
2722 SerialTemp.printf("3.Sending on %s too..\n", _lastGroupTopic);
2723#ifdef TRY_MORE_ASYNC_PROCESSING
2724 //publish back on topic
2726#else
2728#endif
2729 }
2730 }
2731}
2732
2733
2734//! *********************** METHODS invoked from BLE (JSON) and MQTT messages ***************
2735
2736//!perform the OTA update. This calls the OTAImageUpdate methods (via preformOTAUpdateSimple())
2738{
2739 //NOTE: cannot put #OTA in message or it infinite loops..
2740 sprintf(_fullMessageOut, "over the air binary image update, replacing our version: %s", VERSION);
2741 //let clients know what's happening..
2742 // _mqttClient.publish(_mqttTopicString, _fullMessageOut);
2743 SerialDebug.printf("%s\n", _fullMessageOut);
2744 //blink the light
2746 //#define REALLY_DO_IT_BOMBS
2747#ifdef REALLY_DO_IT_BOMBS
2748 //NOTE: this sync call doesn't work..
2749 //printf(" *** Bad syntax, no { } \n");
2751 //this reboots .. so the code below never runs anyway.. will work on it..
2752#else
2753 // setAsyncCallOTAUpdate(true);
2754 //! dispatches a call to the command specified. This is run on the next loop()
2756#endif
2757}
2758
2759//!calls the method for cleaning the SSID eprom. This calls the WIFI_APModule callback
2761{
2762 //! call the callback for cleaning the SSID eprom..
2763 callCallbackMain(CALLBACKS_MQTT, MQTT_CLEAN_SSID_EPROM, (char*)"cleanSSID_EPROM");
2764}
2765
2766//! //!calls the FEED message via the callback (which calls the BLE code)
2767//!NOTE: this will send a BLE command if connected via the GATEWAY to a GEN3 (or other gateway in the future)
2768//!NOTE: This sends the _full message on the topic ..
2769void performFeedMethod(char *topic)
2770{
2771 //!get the temperature
2772 float temp = getTemperature_mainModule();
2773
2774 //!get the connected status
2775 //!save some part of this message for later display by SemanticMarker 8.4.22
2776 //!set the feed
2777 setLastMessageStatus((char*)"feed");
2778
2779 //perform feed...
2780 SerialDebug.println("Perform FEED internally, calling callbackFunction.. 2");
2781 //call the callback specified from the caller (eg. NimBLE_PetTutor_Server .. or others)
2782 // (*_callbackFunction)(rxValue);
2784
2785 //! 2.21.25 add a way to change the button color (if any)
2787
2788 //ASYNC_SEND_MQTT_FEED_MESSAGE
2789 //On demand #STATUS send the statusURL as well (if an M5)
2790 //this queues the sending of the StatusURL over MQTT.
2791 // This is async (next loop) since sending 2 MQTT messages can be hard to do in a row ..
2792 //main_dispatchAsyncCommand(ASYNC_SEND_MQTT_FEED_MESSAGE);
2793
2794 //SerialTemp.println(" ** returned from ASYNC_SEND_MQTT_FEED_MESSAGE ***");
2795#define ACK_FOR_PAIR_TOO
2796 char pairedDevice[100];
2798 strcpy(pairedDevice,getPairedDevice_mainModule());
2799 else
2800 strcpy(pairedDevice,"none");
2801
2802 //! 8.16.25 BLE CLIENT
2803 boolean isConnectedBLE = isConnectedBLEClient();
2804
2806
2807 //! 7.20.25
2808 //!https://stackoverflow.com/questions/7352099/stdstring-to-char
2809 int time = getTimeStamp_mainModule();
2810
2811 if (isConnectedBLE && isGateway)
2812 {
2813 //! FOR NOW , copy the code and create a _fullMessageOut that is for the Paired device...
2814 SerialTemp.print("PairedDevice: ");
2815 SerialTemp.println(pairedDevice);
2816 sprintf(_fullMessageOut, "%s {%s} {'T':'%d','temp':'%2.0f','topic':'%s','user':'%s','v':'%s','location':'%s'}", ACK_FEED, pairedDevice, time, temp, &topic[0],_mqttUserString, VERSION_SHORT, _jsonLocationString?_jsonLocationString:"somewhere");
2817
2818 //publish this message..
2819// _mqttClient.publish(_mqttTopicString, _fullMessageOut);
2820// SerialTemp.printf("ACK: Sending message: %s\n", _fullMessageOut);
2821#ifdef TRY_MORE_ASYNC_PROCESSING
2822 //publish back on topic
2824#else
2826#endif
2827 //! 5.21.22 WORKS!!
2828 //!topic is the topic we can in on.. so could be super user..
2829 // if (strcmp(&topic[0],"usersP/bark")==0)
2830 if (isSuperTopic() || isDawgpackTopic())
2831 {
2832// SerialLots.println("Sending on DawgPack too..");
2833// //publish back on topic
2834// _mqttClient.publish("usersP/dawgpack", _fullMessageOut);
2835#ifdef TRY_MORE_ASYNC_PROCESSING
2836 //publish back on topic
2837 publishMQTTMessage((char*)"usersP/dawgpack", _fullMessageOut);
2838#else
2839 _mqttClient.publish("usersP/dawgpack", _fullMessageOut);
2840#endif
2841 }
2842
2843 //! 7.15.23 anniversery of 1799 finding Rosetta Stone in Egypt
2844 if (isGroupTopic())
2845 {
2846 SerialTemp.printf("3.Sending on %s too..\n", _lastGroupTopic);
2847#ifdef TRY_MORE_ASYNC_PROCESSING
2848 //publish back on topic
2850#else
2852#endif
2853 }
2854
2855 }
2856 //! output the main #actMe message .. but it get's nothing from the plugins - like ATOM status
2857 sprintf(_fullMessageOut, "%s {%s} {'T':'%d','temp':'%2.0f','topic':'%s','user':'%s','v':'%s','location':'%s','paired':'%s', 'ble':'%s','connected':'%s','gateway':'%s','chipid':'%s','ssid':'%s'", ACK_FEED, _deviceNameString, time, temp, &topic[0]?&topic[0]:"NULL",_mqttUserString, VERSION_SHORT, _jsonLocationString?_jsonLocationString:"somewhere",pairedDevice, isConnectedBLE?"c":"x", connectedBLEDeviceName_mainModule()?connectedBLEDeviceName_mainModule():"none", isGateway?"on":"off", getChipIdString(), get_WIFI_SSID().c_str());
2858
2859 // send the FEED to the display (if any)
2861
2862#define TRY_MORE_URL
2863#ifdef TRY_MORE_URL
2864 char *moreStatus = main_currentStatusJSON();
2865 if (moreStatus && strlen(moreStatus) > 0)
2866 {
2867 strcat(_fullMessageOut, (char*)",");
2868
2869 //Make URL for the status..
2870 strcat(_fullMessageOut, moreStatus);
2871 }
2872
2873#endif
2874 //! close the JSON message
2875 strcat(_fullMessageOut, (char*)"}");
2876
2877 //if (messageValidToSendBack)
2878 if (true)
2879 {
2880 //publish this message..
2881// _mqttClient.publish(_mqttTopicString, _fullMessageOut);
2882// SerialDebug.printf("Sending message: %s\n", _fullMessageOut);
2883#ifdef TRY_MORE_ASYNC_PROCESSING
2884 //publish back on topic
2886#else
2888#endif
2889 //! 5.21.22 WORKS!!
2890 //!topic is the topic we can in on.. so could be super user..
2891 // if (strcmp(&topic[0],"usersP/bark")==0)
2892 if (isSuperTopic() || isDawgpackTopic())
2893
2894 {
2895// SerialTemp.println("Sending on DawgPack too..");
2896// //publish back on topic
2897// _mqttClient.publish("usersP/dawgpack", _fullMessageOut);
2898#ifdef TRY_MORE_ASYNC_PROCESSING
2899 //publish back on topic
2900 publishMQTTMessage((char*)"usersP/dawgpack", _fullMessageOut);
2901#else
2902 _mqttClient.publish("usersP/dawgpack", _fullMessageOut);
2903#endif
2904 }
2905
2906 //! 7.15.23 anniversery of 1799 finding Rosetta Stone in Egypt
2907 if (isGroupTopic())
2908 {
2909 SerialTemp.printf("3.Sending on %s too..\n", _lastGroupTopic);
2910#ifdef TRY_MORE_ASYNC_PROCESSING
2911 //publish back on topic
2913#else
2915#endif
2916 }
2917 }
2918}
2919
2920
2921//! *********************** END METHODS invoked from BLE (JSON) and MQTT messages ***************
2922
2923
2924//!This is in case corruption when changing what's written.. defining BOOTSTRAP will clean up the EPROM
2925
2926//!read the eprom..
2928{
2929 SerialDebug.println("MQTT.readPreferences");
2930 //#define BOOTSTRAP
2931#ifdef BOOTSTRAP
2932 //note: this could be a 'rebootstrap' message via MQTT .. in the future..
2933 {
2934 SerialDebug.println("BOOTSTRAP device with our own WIFI and MQTT");
2935
2936 char* BOOT_mqtt_server = (char*)"iDogWatch.com";
2937
2938 //example with "test" as the user name. Change, ssid, user, pass, device name and topic
2939 char* BOOT_mqtt_port = (char*)"1883";
2940 char* BOOT_ssid = (char*)"SunnyWhiteriver";
2941 char* BOOT_ssid_password = (char*)"sunny2021";
2942 char *BOOT_mqtt_user = (char*)"test";
2943 char *BOOT_mqtt_password = (char*)"test";
2944 char *BOOT_mqtt_guestPassword = (char*)"test";
2945
2946 //new 2.2.22 (last time this century..)
2947 //change over to new MQTT Namespace: usersP/bark
2948 char *BOOT_mqtt_topic = (char*)"usersP/bark/test";
2949
2950 char *BOOT_deviceName = (char*)"name-of-feeder";
2951 char *BOOT_uuidString = (char*)"unused";
2952 char *BOOT_jsonHeaderString = (char*)"WIFI+MQTT";
2953 char *BOOT_jsonVersionString = (char*)"BOOTSTRAP 1.3";
2954 char *BOOT_jsonLocationString = (char*)"PetLand"; //enter something is you like (Seattle, WA)
2955
2956 ///note: these createCopy are to get between String and char* .. probably a better way like &BOOT[0] or something..
2957 _ssidString = createCopy(BOOT_ssid);
2958
2959 _ssidPasswordString = createCopy(BOOT_ssid_password);
2960
2961 _mqttServerString = createCopy(BOOT_mqtt_server);
2962 _mqttPortString = createCopy(BOOT_mqtt_port);
2963 _mqttPasswordString = createCopy(BOOT_mqtt_password);
2964 _mqttGuestPasswordString = createCopy(BOOT_mqtt_guestPassword);
2965 _mqttUserString = createCopy(BOOT_mqtt_user);
2966 _mqttTopicString = createCopy(BOOT_mqtt_topic);
2967 _deviceNameString = createCopy(BOOT_deviceName);
2968 _uuidString = createCopy(BOOT_uuidString);
2969 _jsonHeaderString = createCopy(BOOT_jsonHeaderString);
2970 _jsonVersionString = createCopy(BOOT_jsonVersionString);
2971 _jsonLocationString = createCopy(BOOT_jsonLocationString);
2972
2973 DynamicJsonDocument myObject(1024);
2974
2975 myObject["ssid"] = BOOT_ssid;
2976 myObject["ssidPassword"] = BOOT_ssid_password;
2977 myObject["mqtt_server"] = BOOT_mqtt_server;
2978 myObject["mqtt_port"] = BOOT_mqtt_port;
2979 myObject["mqtt_password"] = BOOT_mqtt_password;
2980 myObject["mqtt_guestPassword"] = BOOT_mqtt_guestPassword;
2981
2982 myObject["mqtt_user"] = BOOT_mqtt_user;
2983 myObject["mqtt_topic"] = BOOT_mqtt_topic;
2984 myObject["deviceName"] = BOOT_deviceName;
2985 myObject["uuid"] = BOOT_uuidString;
2986 myObject["jsonHeader"] = BOOT_jsonHeaderString;
2987 myObject["jsonVersion"] = BOOT_jsonVersionString;
2988 myObject["location"] = BOOT_jsonLocationString;
2989
2990 //open the preferences
2991
2992 _preferencesMQTTNetworking.begin(ESP_EPROM_NAME, false); //readwrite..
2994 //output our object.. myObject has a string version..
2995 SerialDebug.print("Writing EPROM JSON = ");
2996 //JSON
2997 String output1;
2998 serializeJson(myObject, output1);
2999 SerialDebug.println(output1);
3001
3002 // Close the Preferences
3004
3005 //new 2.21.22 (On bootstrap, it's nil..?? .. maybe the myObject isn't a string??
3006 //TRY: reading back..
3007 _preferencesMQTTNetworking.begin(ESP_EPROM_NAME, false); //false=read/write..
3009 SerialDebug.print("Reading.3 EPROM JSON = ");
3010 SerialDebug.println(_fullJSONString);
3011
3012 //check ... _fullMessageOut
3013 // Close the Preferences
3015
3016 //end new
3017 }
3018 return;
3019#endif //BOOTSTRAP
3020
3021#ifdef BOOTSTRAP_AP_MODE_STARTUP
3022 SerialDebug.println("*** STARTUP in AP MODE ***");
3023 _ssidString = NULL;
3024 _ssidPasswordString = NULL;
3025 return;
3026#endif
3027 //https://randomnerdtutorials.com/esp32-save-data-permanently-preferences/
3028 //https://github.com/espressif/arduino-esp32/blob/master/libraries/Preferences/src/Preferences.cpp
3029 // Open Preferences with my-app namespace. Each application module, library, etc
3030 // has to use a namespace name to prevent key name collisions. We will open storage in
3031 // RW-mode (second parameter has to be false).
3032 // Note: Namespace name is limited to 15 chars.
3033 _preferencesMQTTNetworking.begin(ESP_EPROM_NAME, false); //false=read/write..
3035 SerialDebug.print("Reading.1 EPROM JSON = ");
3036 SerialDebug.println(_fullJSONString);
3037
3038 //check ... _fullMessageOut
3039 // Close the Preferences
3041
3042 //3.29.22: ISSUE. the eprom wasn't written, but we can in from the CREDENTIALS...
3043
3044 //first time there won't be any eprom info.. THIS is a bug without this code update
3045 if (!_fullJSONString || _fullJSONString.length() == 0)
3046 {
3047 SerialDebug.println("*** no JSON in preferences, probably first time. use Bootstrap, or BLE update ***");
3048 _ssidString = NULL;
3049 _ssidPasswordString = NULL;
3050 return;
3051 }
3052
3053 DynamicJsonDocument myObject(1024);
3054 //StaticJsonDocument myObject(1024);
3055 deserializeJson(myObject, _fullJSONString);
3056 SerialDebug.print("JSON parsed.1 = ");
3057 String output1;
3058 serializeJson(myObject, output1);
3059 SerialDebug.println(output1);
3060
3061#ifdef NOT_ORIGINAL
3062 //defaults: 9.19.23 is already set don't override..
3064 _deviceNameString = (char*)"Unnamed";
3065#else
3066 //defaults:
3067 _deviceNameString = (char*)"Unnamed";
3068#endif
3069 //parse
3070 const char* a1 = myObject["ssid"];
3071#ifdef NOT_ORIGINAL
3072 if (a1 && strlen(a1)>0) /// CHANGED 9.19.23
3073#else
3074 if (a1)
3075#endif
3076 {
3077 _ssidString = const_cast<char*>(a1);
3079 SerialDebug.println(_ssidString);
3080
3081 }
3082 else
3083 {
3084 _ssidString = NULL;
3085 SerialDebug.println("ssid == NULL");
3086 }
3087 if (!_ssidString)
3088 {
3089
3090 SerialDebug.println("No SSID set, try BLE update again.. ");
3091 _ssidString = NULL;
3092 _ssidPasswordString = NULL;
3093 _mqttServerString = NULL;
3094 _mqttPortString = NULL;
3095 _mqttPasswordString = NULL;
3097 _mqttUserString = NULL;
3098 _mqttTopicString = NULL;
3099#ifdef NOT_ORIGINAL
3100 // _deviceNameString = (char*)"Unnamed"; /// CHANGED 9.19.23
3101#else
3102 _deviceNameString = (char*)"Unnamed";
3103#endif
3104 _uuidString = NULL;
3105 _jsonHeaderString = NULL;
3106 _jsonVersionString = NULL;
3107 _jsonLocationString = NULL;
3108
3109 //call the callback specified from the caller (eg. NimBLE_PetTutor_Server .. or others)
3110 // (*_callbackFunction)(rxValue);
3112
3113 return;
3114
3115 }
3116 //!seems the JSON object only returns these const char*, and not easy to just create a char *, so they are created in their own memory..
3117 {
3118 const char* a2 = myObject["ssidPassword"];
3119 if (a2)
3120 {
3121 _ssidPasswordString = const_cast<char*>(a2);
3123 SerialDebug.println(_ssidPasswordString);
3124 }
3125 else
3126 _ssidPasswordString = NULL;
3127 }
3128
3129 {
3130 //!the MQTT host/port/user/password (topic is created in this code...)
3131 const char* a3 = myObject["mqtt_server"];
3132 if (a3)
3133 {
3134 _mqttServerString = const_cast<char*>(a3);
3136 SerialDebug.println(_mqttServerString);
3137 }
3138 else
3139 _mqttServerString = NULL;
3140 }
3141
3142 {
3143 const char* a4 = myObject["mqtt_port"];
3144 if (a4)
3145 {
3146 _mqttPortString = const_cast<char*>(a4);
3148 }
3149 else
3150 _mqttPortString = NULL;
3151 }
3152
3153 {
3154 const char* a5 = myObject["mqtt_password"];
3155 if (a5)
3156 {
3157 _mqttPasswordString = const_cast<char*>(a5);
3159 SerialDebug.println(_mqttPasswordString);
3160 }
3161 else
3162 _mqttPasswordString = NULL;
3163 }
3164
3165 {
3166 const char* a6 = myObject["mqtt_user"];
3167 if (a6)
3168 {
3169 _mqttUserString = const_cast<char*>(a6);
3171 }
3172 else
3173 _mqttUserString = NULL;
3174 }
3175
3176 {
3177 const char* a7 = myObject["deviceName"];
3178 if (a7)
3179 {
3180 _deviceNameString = const_cast<char*>(a7);
3182 }
3183 else
3184 _deviceNameString = NULL;
3185 }
3186
3187 //update the chip name with the deviceName
3188 getChipInfo();
3189
3190 SerialDebug.println(_deviceNameString);
3191
3192 {
3193 const char* a8 = myObject["uuid"];
3194 if (a8)
3195 {
3196 _uuidString = const_cast<char*>(a8);
3198 SerialDebug.print("UUID: ");
3199 SerialDebug.println(_uuidString);
3200
3201 }
3202 else
3203 _uuidString = NULL;
3204 }
3205
3206 {
3207 const char* a9 = myObject["mqtt_topic"];
3208 if (a9)
3209 { _mqttTopicString = const_cast<char*>(a9);
3211 SerialDebug.println(_mqttTopicString);
3212 }
3213 else
3214 _mqttTopicString = NULL;
3215 }
3216
3217 {
3218 const char* a10 = myObject["jsonHeader"];
3219 if (a10)
3220 { _jsonHeaderString = const_cast<char*>(a10);
3222 SerialDebug.println(_jsonHeaderString);
3223 }
3224 else
3225 _jsonHeaderString = NULL;
3226 }
3227
3228 {
3229 //!Note: This is where the code could look for backward compatability, etc..
3230 const char* a11 = myObject["jsonVersion"];
3231 if (a11)
3232 { _jsonVersionString = const_cast<char*>(a11);
3234 SerialDebug.println(_jsonVersionString);
3235 }
3236 else
3237 _jsonVersionString = NULL;
3238 }
3239
3240 {
3241 const char* a12 = myObject["location"];
3242 if (a12)
3243 { _jsonLocationString = const_cast<char*>(a12);
3245 SerialDebug.println(_jsonLocationString);
3246 }
3247 else
3248 _jsonLocationString = NULL;
3249 }
3250
3251 {
3252 const char* a13 = myObject["mqtt_guestPassword"];
3253 if (a13)
3254 {
3255 _mqttGuestPasswordString = const_cast<char*>(a13);
3257 SerialDebug.println(_mqttGuestPasswordString);
3258 }
3259 else
3261 }
3262
3263 //! sets the MQTT user/password. It's up to the code to decide who needs to know (currently saves in the WIFI_APModule
3265}
3266
3267
3268
3269//!whether the string is TRUE, ON, 1
3270boolean isTrueString(String valCmdString)
3271{
3272 return valCmdString.equalsIgnoreCase("on") ||
3273 valCmdString.equalsIgnoreCase("1") ||
3274 valCmdString.equalsIgnoreCase("true");
3275}
3276#ifdef UNUSED
3277//!whether the string is FALSE, OFF, 0
3278function isFalseString(String valCmdString)
3279{
3280 return valCmdString.equalsIgnoreCase("off") ||
3281 valCmdString.equalsIgnoreCase("0") ||
3282 valCmdString.equalsIgnoreCase("false");
3283}
3284#endif //UNUSED
3285
3286//!send message to ourself to change to current specifed SM Mode
3288{
3289 //!send message to ourself to process the current mode..
3292}
3293
3294//!process the JSON message (looking for FEED, etc). Note: topic can be nil, or if not, it's an MQTT topic (so send replies if you want)
3295//!1.14.24 THIS is the main JSON processor of messages. But now that groups can send almost any message, there
3296//!needs to be a way define a subset of messages that groups can send on..
3297//!6.20.25 added Serial Monitor input,
3298//!API Manual described:
3299//!@see https://github.com/konacurrents/SemanticMarkerAPI
3300//! note: The strcasecmp() function shall compare, while ignoring differences in case, the string pointed to by s1 to the string pointed to by s2.
3301boolean processJSONMessageMQTT(char *ascii, char *topic)
3302{
3303 SerialLots.println(" *** processJSONMessageMQTT ***");
3304
3305 //! 6.16.25 Nice out, yellow field
3306 //! set below when looking at whether a command was found
3307 //! if false then continue the if/else
3308 boolean foundCommand;
3309
3310 //! use the default user topic if not specified...
3311 if (!topic)
3312 {
3313 if (!_mqttTopicString)
3314 _mqttTopicString = (char*)"usersP/bark/test";
3315 topic = _mqttTopicString;
3316 }
3317 //! sets the global so isGroupTopic() will work
3318 classifyTopic(topic);
3319
3320 if (!ascii)
3321 return false;
3322
3323 //! 7.26.23 don't process if a group message and FLAG not set
3324 if (isGroupTopic())
3325 {
3326 // if the EPROM says not to process groups .. then skip this message..
3327 //! called to set a preference (which will be an identifier and a string, which can be converted to a number or boolean)
3329 {
3330 SerialDebug.printf("NOT Processing as PREFERENCE_SUPPORT_GROUPS_SETTING not set");
3331 return false;
3332 }
3333 //! 8.2.24 support the not receiving message on some topics (such as a users GuestTopic)
3334 //! Idea would be some devices won't listen to the guest topic (instead only the user safe ones)
3335 else if (!topicInIncludeGroup(topic))
3336 {
3337 SerialDebug.printf("NOT Processing as topic not in Include Group: %s", topic);
3338 return false;
3339 }
3340 }
3341
3342 //!empty the status for the last message. Then various places the feed or status, etc are set
3343 //emptyLastMessageStatus();
3344 //cant empty here .. as the ACK gets sent .. how about after the ACK!
3345
3346 //!Basically processing as a JSON if the "{" is somewhere.. could still be invalid code
3347 if (!startsWithChar(ascii,'{'))
3348 {
3349 SerialLots.printf("processJSONMessageMQTT(%s) -> return false, not JSON\n", ascii);
3350
3351 return false;
3352 }
3353
3354 SerialLots.printf("processJSONMessageMQTT: '%s'\n", ascii);
3355
3356 // Deserialize the JSON document, then store the ascii in the EPROM (if it parses..)
3357
3358 SerialLots.printf("Ascii before deserializeJson: %s\n", ascii);
3359
3360#ifdef PROCESS_SMART_BUTTON_JSON
3361 DynamicJsonDocument myObject(2024);
3362#else
3363#ifdef ESP_m5
3364 DynamicJsonDocument myObject(1024);
3365#else
3366 DynamicJsonDocument myObject(1024); //was 600
3367#endif //ESP_M5
3368#endif
3369
3370 //! serialize into the myObject from the ascii string
3371 deserializeJson(myObject, ascii);
3372#if SERIAL_DEBUG_LOTS
3373 serializeJsonPretty(myObject, Serial);
3374#endif
3375
3376 //NOTE: the ascii is now corrupted...
3377 SerialDebug.print("\nJSON parsed = ");
3378 // String output;
3379 String output1;
3380 serializeJson(myObject, output1);
3381 SerialDebug.println(output1);
3382 SerialLots.printf("Ascii after deserializeJson: %s\n", ascii);
3383
3384 //NEW: 3.28.22 {'cmd':COMMANDS}
3385 // {'sm':<sm>}
3386 // {'guest':<passws>
3387 //{ 'set':<object>,'val':<value>}
3388 const char* cmd = myObject["cmd"];
3389 const char* semanticMarkerCmd = myObject["sm"];
3390 const char* guestCmd = myObject["guest"];
3391
3392 //! 9.18.23 add this .. so it doesnt' fall through
3393 const char *set64Cmd = myObject["set64"];
3394
3395 const char *setCmd = myObject["set"];
3396 const char *valCmd = myObject["val"];
3397 //new: 'send':<request> eg. status|temp
3398 const char *sendCmd = myObject["send"];
3399 //! devName is if a dev=<NAME> was specified, then dissregard if not our device
3400 const char *devName = myObject["dev"];
3401 //if processCommands, then do NOT process the credentials..
3402 boolean processCommands = false;
3403 if (cmd || semanticMarkerCmd || guestCmd || setCmd || sendCmd || set64Cmd)
3404 processCommands = true;
3405
3406#ifdef PROCESS_SMART_BUTTON_JSON
3407 //! 7,1.23 Dads 92'n birthday
3408//!NOT DOING THESE RIGHT NOW.. THE REST https is being done by ATOM
3409 //const char *SMARTButton = myObject["SMARTButton"];
3410 boolean processSMARTButton = containsSubstring(output1,"SMARTButton"); //myObject["SMARTButton"] != NULL;
3411 SerialTemp.printf("SMARTButton = %d\n", processSMARTButton);
3412 //! set processCommands just so it process the 'dev' argument..
3413 if (processSMARTButton)
3414 processCommands = true;
3415#endif
3416
3417
3418 //try 5.12.22 {'set':'item'},{'val':'value'}
3419 // eg. set:hightemp, val:80
3420
3421 //Find the Guest Password, and the user name - or defaults if notset
3422 String guestPassword = "pettutor";
3424 {
3425 //in case empty (but not null) - not checking for spaces only... too lazy
3426 if (strlen(_mqttGuestPasswordString)>0)
3427 guestPassword = _mqttGuestPasswordString;
3428 }
3429 // set vals to NOTSET if not set
3430 char* baseString;
3431 String title = "";
3432 if (!_mqttUserString)
3433 {
3434 _mqttUserString = NOTSET_STRING;
3435 }
3437 {
3438 _mqttPasswordString = NOTSET_STRING;
3439 }
3440
3441 //!this is to ensure that the credentials are not processed..
3442 //! there is a return 'true' after processing commands
3443 if (processCommands)
3444 {
3445 //! for dawgPack, only support the DOCFOLLOW message for now 8.19.22
3446 if (isDawgpackTopic())
3447 {
3448 char* setCmdString = const_cast<char*>(setCmd);
3449 char* valCmdString = const_cast<char*>(valCmd);
3450
3451 if (setCmd && strcasecmp(setCmd,"semanticMarker")==0)
3452 {
3453 SerialDebug.printf("DAWGPACK supported message: %s\n", setCmd);
3454 }
3455 else
3456 {
3457 SerialDebug.println("DAWGPACK unsupported message");
3458 return true;
3459 }
3460 //fall through for supported messaages..
3461 }
3462
3463 //TODO: For an M5 (with a name) .. and it's paired with a GEN3 and GATEWAY, then the feed of the GEN3 name (instead of M5 name) should be supported...
3464 //! a couple commands, like bleserveron require a device name to be specified (so everyone listening doesn't perform operation)
3465 boolean deviceNameSpecified = devName != NULL;
3466 //!if a dev:<dev> is specified, then only process if the device name is that same
3467 boolean processMessageOrGateway = true;
3468 if (deviceNameSpecified)
3469 {
3470 //default we only feed if our device or our gateway..
3471 processMessageOrGateway = false;
3472#ifdef WILDCARD_DEVICE_NAME_SUPPORT //yes
3473 //!parses a line of text, The caller then uses queryMatchesName() to see if their name matches
3474 parseQueryLine_mainModule((char*)devName);
3476 {
3477 SerialTemp.printf("Query: %s *** Matches our dev name: %s\n", devName, _deviceNameString);
3478 processMessageOrGateway = true;
3479 }
3480 //! per #314 support the chipId as well as the name..
3481 //! 3.17.24
3482 else if (stringMatch(devName, getChipIdString()))
3483 {
3484 SerialTemp.printf("ChipID: %s *** Matches our ChipID name: %s\n", devName, getChipIdString());
3485 processMessageOrGateway = true;
3486 }
3487
3488#else
3489 //!If the dev name is specified, and our device is that name .. then good
3490 if (devName && strcmp(devName,_deviceNameString) == 0)
3491 {
3492 SerialTemp.println(" .. our own device ..");
3493 processMessageOrGateway = true;
3494 }
3495#endif
3496
3497 //!we are in gateway mode, and the paired device isn't ours..
3498 if (devName
3500 {
3501#ifdef WILDCARD_DEVICE_NAME_SUPPORT
3503 {
3504 SerialTemp.printf("Query: %s *** Matches our paired dev name: %s\n", devName, getPreferenceString_mainModule(PREFERENCE_PAIRED_DEVICE_SETTING));
3505 processMessageOrGateway = true;
3506 }
3507#else
3509 {
3510 SerialTemp.println(" .. our paired device ..");
3511 processMessageOrGateway = true;
3512 }
3513#endif
3514 }
3515
3516 } //device name specified (sets up processMessageOrGateway., and sets device
3517
3518 //! basically, processMessageOrGateway is set to TRUE if the device isn't mentioned, OR
3519 //! the dev is mentioned, and the wildcard works (or is paired)
3520 //! In either case, the deviceNameSpecified will be true if "dev" was specified (even with wildcard)
3521 //! So code below that only work if "dev" specified will work and know it's their device
3522 //! For the SemanticMarker, if the onlyDevSM==true, then look for deviceNameSpecified
3523
3524#ifdef PROCESS_SMART_BUTTON_JSON //no 9.28.23
3525 //! early attempt to process a SMART buttons JSON as a stored procedure.
3526 //! But currently the JSON parser is bombing on the JSON provided..
3527 //! 7.1.23 Dads 92nd birthday
3528 if (processMessageOrGateway && processSMARTButton)
3529 {
3530 StaticJsonDocument<2024> smartButtonObject;
3531
3532 deserializeJson(smartButtonObject, myObject["SMARTButton"]);
3533 //done..
3534 return processJSONSMARTButton(smartButtonObject);
3535 }
3536#endif
3537 //! after this, if true, then ifDeviceNameSpecified .. then it's a good name..
3538 if (!processMessageOrGateway)
3539 {
3540 //Only gets here if dev set .. so the parser was run (if WILDCARD)
3541 SerialTemp.print("Disregard as Device Specified: ");
3542 SerialTemp.print(devName);
3543
3544 //! as per issue #122, if a device is in gateway mode, and paired with a device name specified, then the message can be sent
3545 SerialTemp.print(" not ours: ");
3546 SerialTemp.println(_deviceNameString);
3548 {
3549#ifdef WILDCARD_DEVICE_NAME_SUPPORT
3551#else
3553#endif
3554 {
3555 SerialTemp.print(" .. And not paired device:");
3557 }
3558 }
3559 }
3560 //! {"cmd", <cmd>)
3561 else if (cmd)
3562 {
3563 //! 1.14.24 use the isGroupTopic() where needed..
3564 //SerialDebug.printf("BLE CMD = '%s'\n", cmd);
3565 //note: we could have a mode for "testing" .. so the OTA for example does't fire.
3566 //smN
3567 //NOTE: THIS REQUIRES == 0 or no work..
3568 //NOTE: the number here has to be updated in the ButtonProcessing code too..
3569 int whichSMMode = whichSMMode_mainModule((char*)cmd);
3570 SerialTemp.printf("MQTT or BLE CMD = '%s'\n", cmd);
3571#ifdef ESP_M5
3572 // -1 if none..
3573 if (whichSMMode >= 0)
3574 {
3575 //! per #206 .. only change the page when not in doc_follow
3576 //! 1.22.24 if switching to mode 0 then it's ok..
3577 //! 11.9.22
3578 int currentSMMode = getCurrentSMMode_mainModule();
3579 SerialDebug.printf("currentSMMode = %d whichSMMode = %d\n", currentSMMode, whichSMMode);
3580 if (currentSMMode == SM_doc_follow && whichSMMode > 0)
3581 {
3582 //! Issue: #222 for #206, this sets the current mode to SM_doc_follow, but
3583 //! when at that page in the the current mode (which is now SM_doc_follow) won't let
3584 //! the page go somewhere else (except in this case we are the same page). Only but a
3585 //! physical button click.
3586 //! I THINK THE ANSWER: if current and next are the same an SM_doc_follow, then do the page change..
3587 if (currentSMMode != whichSMMode)
3588 {
3589 SerialDebug.println(" *** Not changing page as in DOCFOLLOW mode ***");
3590 return true;
3591 }
3592 else
3593 SerialDebug.println(" *** SM_doc_follow and changing to the same page ***");
3594 }
3595
3596 //set the global SMMode.. NOTE: if greater than the MAX change mode to NON MIN
3597 setCurrentSMMode_mainModule(whichSMMode);
3598
3599 boolean markerAlreadyShown = false;
3600 switch (whichSMMode)
3601 {
3602 //since the TITLE is used by the display (it doesn't use the SMMode)
3603 case SM_home_simple: //TILT
3604 {
3605 //new 7.25.22
3606 baseString = (char*)"https://iDogWatch.com/bot/guestpage2";
3607 title = "MINI CLICKER";
3608 sprintf(_semanticMarkerString,"%s/%s/%s", baseString, _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL");
3609 }
3610 break;
3611 case SM_home_simple_1: // BUZZER
3612 {
3613 //NOTE: THIS title is a binding/linking to the DisplayModule (as it looks for the title)
3614 //new 7.25.22
3615 baseString = (char*)"https://iDogWatch.com/bot/guestpage2";
3616 title = "MINI-1";
3617 sprintf(_semanticMarkerString,"%s/%s/%s", baseString, _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL");
3618 }
3619 break;
3620 case SM_home_simple_2: //FEED
3621 {
3622 //new 7.25.22
3623 baseString = (char*)"https://iDogWatch.com/bot/guestpage2";
3624 title = "MINI-2";
3625 sprintf(_semanticMarkerString,"%s/%s/%s", baseString, _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL");
3626 }
3627 break;
3628 case SM_home_simple_3: //EXPERT
3629 {
3630 //new 7.25.22
3631 baseString = (char*)"https://iDogWatch.com/bot/guestpage2";
3632 title = "MINI-3";
3633 sprintf(_semanticMarkerString,"%s/%s/%s", baseString, _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL");
3634 }
3635 break;
3636 //! the 4th page, start of smart clicker
3638 {
3639 //Make URL for the status..
3640 char *statusString = currentMessageStatusURL();
3641
3642 //!create the SemanticMarker address
3643 sprintf(_semanticMarkerString,"%s/%s/%s/%s", "https://SemanticMarker.org/bot/sensor", _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL", statusString?statusString:"NULL");
3644
3645 title = "WIFI FEED";
3646
3647 //TODO.. use the String (*getStatusFunc)(void)) to re-create this..
3648 //TODO: get the guest info.. or they send us the guest password in a message.. for next time..
3649 //SerialDebug.print("SemanticMarker: ");
3650 SerialLots.println(_semanticMarkerString);
3651 //MAYBE save the user web page.. somewhere EPROM
3652
3653 //!call the displayModuleFunc passing our dynamic status fund
3655 markerAlreadyShown = true;
3656 }
3657
3658 break;
3659 case SM_status:
3660 {
3661 //Make URL for the status..
3662 char *statusString = main_currentStatusURL(true);
3663
3664 //!create the SemanticMarker address
3665 sprintf(_semanticMarkerString,"%s/%s/%s/%s", "https://SemanticMarker.org/bot/sensor", _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL", statusString?statusString:"NULL");
3666
3667 //!tack on the device name..
3668 sprintf(_fullMessageOut,"Status %s", getDeviceNameMQTT());
3669 //title = _fullMessageOut;
3670
3671 //TODO.. use the String (*getStatusFunc)(void)) to re-create this..
3672 //TODO: get the guest info.. or they send us the guest password in a message.. for next time..
3673 //SerialDebug.print("SemanticMarker: ");
3674 SerialLots.println(_semanticMarkerString);
3675 //MAYBE save the user web page.. somewhere EPROM
3676
3677 //!call the displayModuleFunc passing our dynamic status fund
3679 markerAlreadyShown = true;
3680 }
3681 break;
3682
3683 case SM_guest_page:
3684
3685 {
3686 baseString = (char*)"https://iDogWatch.com/bot/guestpage";
3687 title = "Guest Page";
3688 sprintf(_semanticMarkerString,"%s/%s/%s", baseString, _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL");
3689 }
3690 break;
3691 case SM_guest_feed:
3692 {
3693 baseString = (char*)"https://iDogWatch.com/bot/feedguest";
3694 title = "Feed Guest";
3695 sprintf(_semanticMarkerString,"%s/%s/%s", baseString, _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL");
3696 }
3697 break;
3698 case SM_pair_dev:
3699 {
3700 baseString = (char*)"https://iDogWatch.com/bot/feedguestdevice";
3702 //!NOTE this could be "NONE" the "P:" is so the display knows this is a paired device command
3703 title = "P:";
3704 sprintf(_semanticMarkerString,"%s/%s/%s/%s", baseString, _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL", pairDev);
3705 }
3706 break;
3707 case SM_WIFI_ssid:
3708 {
3709 title = "WIFI";
3710
3711 //!#issue 136 create a SM for the WIFI syntax
3712 //!WIFI:S:<SSID>;T:<WEP|WPA|blank>;P:<PASSWORD>;H:<true|false|blank>;
3713 sprintf(_semanticMarkerString,"WIFI:S:%s;T:;P:%s;H:;", _ssidString?_ssidString:"NONE", _ssidPasswordString?_ssidPasswordString:"");
3714 }
3715 break;
3716
3717 // different SM
3718 case SM_ap_mode:
3719 {
3720 //AP mode..
3721 sprintf(_semanticMarkerString,"%s", "http://192.168.4.1");
3722 title = "AP Mode";
3723 }
3724 break;
3725
3726 case SM_help:
3727 {
3728 //HELP..
3729 //Make URL for the status..
3730 sprintf(_semanticMarkerString,"%s/%s/%s", "https://SemanticMarker.org/bot/help", _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL");
3731 title = "Help Info";
3732 }
3733 break;
3734 case SM_doc_follow: //sm12
3735 {
3736 //This is where a dynamic DOCFollow would show up..
3737 //Make URL for the status..
3739 title = "DOC FOLLOW";
3740 //call the displayModule
3741 if (SM.length()>0)
3742 sprintf(_semanticMarkerString,"%s", SM);
3743 else
3744 SM = "https://SemanticMarker.org";
3745 }
3746 break;
3747 //NOTE: each added sm, needs the ButtonProcessing.cpp to update it's list..
3748 case SM_reboot:
3749 {
3750 //REboot the device
3751 sprintf(_semanticMarkerString,"%s/%s/%s", "https://SemanticMarker.org/bot/reboot", _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL");
3752 title = "Reboot";
3753 }
3754 break;
3755 case SM_timer:
3756 {
3757 //timer the device
3758 sprintf(_semanticMarkerString,"%s/%s/%s", "https://SemanticMarker.org/bot/timer", _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL");
3759 title = "Timer";
3760 }
3761 break;
3762
3763 }
3764 //TODO: get the guest info.. or they send us the guest password in a message.. for next time..
3765 //SerialDebug.print("SemanticMarker: ");
3766 SerialLots.println(_semanticMarkerString);
3767 //MAYBE save the user web page.. somewhere EPROM
3768
3769 //!turn this OFF if it came in via a SemanticMarker command ... ???
3770 if (!markerAlreadyShown)
3771 {
3772 //only if not already shown. Status uses a dynamic function..
3774 }
3775 } //end smMode 0..n
3776 else
3777#endif //ESP_M5 display
3778 if (strcasecmp(cmd,"ota")==0 && !isGroupTopic())
3779 {
3780 SerialDebug.println("OTA via BLE");
3781 //!calls the OTA update method (this doesn't return as device is rebooted...)
3783 }
3784 //! add click to any device, and to a group
3785 //! 5.14.25 (Dead 5.14.74 3rd wall of sound)
3786 else if (strcasecmp(cmd,"click")==0)
3787 {
3788 //! click call
3790 }
3791 //! 1.2.26 add blink
3792 else if (strcasecmp(cmd,"blink")==0)
3793 {
3794 //! click call
3796 }
3797 else if (strcasecmp(cmd,"clean")==0 && !isGroupTopic())
3798 {
3799 SerialDebug.println("CLEAN via BLE");
3800 //!calls the method for cleaning the SSID eprom. This calls the WIFI_APModule callback
3802 }
3803 else if (strcasecmp(cmd,"feed")==0)
3804 {
3805 SerialDebug.printf("FEED via BLE (%s)\n",topic?topic:"NULL TOPIC!!");
3806 performFeedMethod(topic);
3807 }
3808 else if (strcasecmp(cmd,"resettimer")==0)
3809 {
3811 }
3812 else if (strcasecmp(cmd,"status")==0)
3813 {
3814 SerialDebug.println("STATUS via BLE");
3815 //!print status of the WIFI and MQTT
3816 SerialMin.printf("WIFI_MQTTState= %d\n",_WIFI_MQTTState);
3817 SerialMin.printf("DeviceName= %s\n",getDeviceNameMQTT());
3818 SerialMin.printf("ChipName= %s\n",getChipIdString());
3819#ifdef ESP_M5
3820 SerialMin.printf("DynamcState= %s\n",getDynamicStatusFunc());
3821 SerialMin.printf("WIFI connected = %d, %s\n", isConnectedWIFI_MQTTState(), wifiStatus_MQTT());
3822#endif
3823 SerialMin.printf("MQTT connected = %d, %s\n", isConnectedMQTT_MQTTState(),_mqttClient.connected()?"connected":"not connected");
3824
3825
3826 //! send SPIFF status
3827 //! 4.4.24
3829
3830
3831 //WL_NO_SSID_AVAIL .. to WL_DISCONNECTED
3832 //but never reconnects ...
3833 SerialLots.println("cmd == status");
3834 //! request a STATUS be sent.
3835 processBarkletMessage("#STATUS", topic);
3836 }
3837 else if (strcasecmp(cmd,"erase")==0 && !isGroupTopic())
3838 {
3839 SerialDebug.println("ERASE via BLE");
3841 }
3842
3843 //!TODO: duplicate and depreciate these and replace with set:buzz,val:on
3844 else if (strcasecmp(cmd,"buzzon")==0)
3845 {
3846 SerialDebug.println("BUZZON via BLE");
3848 }
3849 else if (strcasecmp(cmd,"buzzoff")==0)
3850 {
3851 SerialDebug.println("BUZZOFF via BLE");
3853 }
3854 //Gateway (which I think is obsolete if we can determin this from knowing which feeder we have)
3855 //keeping for now..
3856 else if (strcasecmp(cmd,"gatewayOn")==0)
3857 {
3858 if (deviceNameSpecified)
3859 {
3860 SerialDebug.println("ASYNC_SET_GATEWAY_ON via BLE");
3862 }
3863 }
3864 else if (strcasecmp(cmd,"gatewayOff")==0)
3865 {
3866 if (deviceNameSpecified)
3867 {
3868 SerialDebug.println("ASYNC_SET_GATEWAY_OFF via BLE");
3870 }
3871 }
3872 //!resetFirstTime
3873 else if (strcasecmp(cmd,"resetfirsttime")==0)
3874 {
3875 if (deviceNameSpecified)
3876 {
3877 SerialDebug.println("PREFERENCE_FIRST_TIME_FEATURE_SETTING ON via BLE");
3879 //!for now just reboot which will use this perference
3881 }
3882 }
3883 //BLECLient
3884 else if (strcasecmp(cmd,"bleclientOn")==0 && !isGroupTopic())
3885 {
3886 if (deviceNameSpecified)
3887 {
3888 SerialDebug.println("PREFERENCE_MAIN_BLE_CLIENT_VALUE ON via BLE");
3890 //!for now just reboot which will use this perference
3892 }
3893 }
3894 else if (strcasecmp(cmd,"bleclientOff")==0 && !isGroupTopic())
3895 {
3896 if (deviceNameSpecified)
3897 {
3898 SerialDebug.println("PREFERENCE_MAIN_BLE_CLIENT_VALUE OFF via BLE");
3900 //!for now just reboot which will use this perference
3902 }
3903 }
3904 else if (strcasecmp(cmd,"bleserverOn")==0 && !isGroupTopic())
3905 {
3906 if (deviceNameSpecified)
3907 {
3908 SerialDebug.println("PREFERENCE_MAIN_BLE_SERVER_VALUE ON via BLE");
3910 //!for now just reboot which will use this perference
3912 }
3913 }
3914 else if (strcasecmp(cmd,"bleserverOff")==0 && !isGroupTopic())
3915 {
3916 if (deviceNameSpecified)
3917 {
3918 SerialDebug.println("PREFERENCE_MAIN_BLE_SERVER_VALUE OFF via BLE");
3920 //!for now just reboot which will use this perference
3922 }
3923 }
3924 else if (strcasecmp(cmd,"reboot")==0 && !isGroupTopic())
3925 {
3926 if (deviceNameSpecified)
3927 {
3928 SerialDebug.println("REBOOT via BLE");
3929 //!for now just reboot which will use this perference
3931 }
3932 }
3933 else if (strcasecmp(cmd,"tiltOn")==0)
3934 {
3935 SerialDebug.println("PREFERENCE_SENSOR_TILT_VALUE ON via BLE");
3937 }
3938 else if (strcasecmp(cmd,"tiltOff")==0)
3939 {
3940 SerialDebug.println("PREFERENCE_SENSOR_TILT_VALUE OFF via BLE");
3942 }
3943 //!zoom == the NON semantic marker version.. so min menu is true
3944 else if (strcasecmp(cmd,"zoomSMOn")==0)
3945 {
3946
3947 //hide semantic marker.. (but only if in the max menus)
3948 //NOTE: this only hides the Semantic Marker - if on a page that has one..
3949 SerialDebug.println("PREFERENCE_SEMANTIC_MARKER_ZOOMED_VALUE ON via BLE");
3951
3952 //!zoom only if in the max menu set..
3954 {
3955 //stay on this page, but change the marker..
3957 }
3958
3959 }
3960 else if (strcasecmp(cmd,"zoomSMOff")==0)
3961 {
3962 //show semantic marker..
3963 //NOTE: this only shows the Semantic Marker - if on a page that has one..
3964 SerialDebug.println("PREFERENCE_SEMANTIC_MARKER_ZOOMED_VALUE OFF via BLE");
3967
3968 //!zoom only if in the max menu set..
3970 {
3971 //change to the status..
3973 //!send message to ourself to process the current mode..
3975 }
3976 else
3977 {
3978 //stay on this page, but change the zoom..
3980 }
3981 }
3982 else if (strcasecmp(cmd,"poweroff")==0 && !isGroupTopic())
3983 {
3984 SerialDebug.println("ASYNC_POWEROFF OFF via BLE");
3986
3987 }
3988 else if (strcasecmp(cmd,"wifi")==0)
3989 {
3990 SerialDebug.println("cmd=wifi via BLE");
3992 }
3993 else if (strcasecmp(cmd,"swapwifi")==0)
3994 {
3995 SerialDebug.println("cmd=swapwifi via BLE");
3996
3997 //NOTE: this might be where we toggle credentials?? TODO
3998 //found other one..
3999 char *credentials = main_nextJSONWIFICredential();
4000
4001 //!These are the ASYNC_CALL_PARAMETERS_MAX
4002 //!NO: just change our credentials ...
4003 //send to ourself.., recursively...
4004 int val = processJSONMessageMQTT(credentials, topic);
4005 }
4006#ifdef USE_SPIFF_MODULE
4007 //new 7.29.22 SPIFF
4008 else if (strcasecmp(cmd,"readspiff")==0)
4009 {
4010 SerialDebug.println("readspiff...");
4011
4013 }
4014 else if (strcasecmp(cmd,"sendspiff")==0)
4015 {
4017 }
4018 else if (strcasecmp(cmd,"deletespiff")==0 && !isGroupTopic())
4019 {
4021 }
4022#endif //USE_SPIFF_MODULE
4023 else if (strcasecmp(cmd,"capture")==0)
4024 {
4025 //! request a CAPTURE be sent.
4026 processBarkletMessage("#CAPTURE", topic);
4027#ifdef ESP_M5
4029#endif
4030 }
4031 //end new
4032 else if (strcasecmp(cmd,"help")==0)
4033 {
4034 //!and print any preferences to show
4036
4037 sprintf(_fullMessageOut, "Syntax {\'cmd': \'[. | ota|clean|feed|erase|status|buzzon|buzzoff| MORE..help]\'} ");
4038 //!publich back on topic
4039 //_mqttClient.publish(_mqttTopicString, _fullMessageOut);
4040#ifdef TRY_MORE_ASYNC_PROCESSING
4041 //publish back on topic
4043#else
4045#endif
4046 }
4047
4048 //! 12.27.23 pass this onto those registered (which mainModule is handling..)
4049 //! 1.14.24 .. what about groups??
4050 //! 8.16.25 Gods of War (Hawaii)
4051 //! send this .. and let the caller decide if deviceNameSpecified needed..
4052 //if (deviceNameSpecified)
4053 {
4054 char* sendCmdString = const_cast<char*>(cmd);
4055
4056 //! 12.28.23, 8.28.23 Tell Main about the set,val and if others are registered .. then get informed
4057 messageSend_mainModule(sendCmdString, deviceNameSpecified);
4058 }
4059 }
4060 //! {'guest':'guest password'}
4061 else if (guestCmd) //depreciated..
4062 {
4063 _mqttGuestPasswordString = const_cast<char*>(guestCmd);
4064 SerialDebug.printf("guestCmd = '%s'\n", _mqttGuestPasswordString);
4065 }
4066#ifdef ESP_M5
4067 // 'sm':'name/cat/uuid'
4068 else if (semanticMarkerCmd)
4069 {
4070 //char semanticMarkerString[200];
4071 char* baseString = (char*)"https://SemanticMarker.org/bot/";
4072 sprintf(_semanticMarkerString,"%s/%s", baseString, semanticMarkerCmd);
4073
4074 //! 9.28.29 devOnlySM if set, then
4075 boolean showSM = true;
4077 showSM = deviceNameSpecified;
4078
4079 if (showSM)
4080 //! use the name/cat/uuid ..
4082 else
4083 SerialDebug.println("Not showing SemanticMarker ");
4084 } //semanticMarkerCmd
4085#endif //ESP_M5
4086 //!5.12.22
4087 //!{set:<set>,"val":val, device?)
4088 else if (setCmd && valCmd)
4089 {
4090 //! options: hightemp, feedcount, timeout
4091 char* setCmdString = const_cast<char*>(setCmd);
4092 char* valCmdString = const_cast<char*>(valCmd);
4093 SerialTemp.print("Set: ");
4094 SerialTemp.print(setCmdString);
4095 SerialTemp.print(", Val: ");
4096 SerialTemp.println(valCmdString);
4097
4098 //! 12.27.23 pass this onto those registered (which mainModule is handling..)
4099 //! 8.28.23 Tell Main about the set,val and if others are registered .. then get informed
4100 //! 1.10.24 if deviceNameSpecified then this matches this device, otherwise for all.
4101 //! It's up to the receiver to decide if it has to be specified
4102 //! 1.14.24 for now, setVal in the ATOM will support GROUP commands if turned on (and if off it doesn't get here)
4103 messageSetVal_mainModule(setCmdString, valCmdString, deviceNameSpecified);
4104
4105 //!set flag (if a boolean command)
4106 boolean flag = isTrueString(valCmdString);
4107
4108 //!try 5.12.22 {'set':'item'},{'val':'value'}
4109 //! eg. set:hightemp, val:80)
4110 //! TODO: confirm valid integer values...
4111 if (strcasecmp(setCmdString,"hightemp")==0)
4112 {
4113 //!set the high temp value..
4115 }
4116 //! 9.29.22 duplicating a couple of 'set':'cmd', 'val':'feed", since the QUERY for a device is sent that way sometimes..
4117 else if (strcasecmp(setCmdString,"cmd")==0)
4118 {
4119 if (strcasecmp(valCmdString,"feed")==0)
4120 {
4121 SerialCall.printf("feed via set,cmd (%s)\n",topic?topic:"NULL TOPIC!!");
4122 performFeedMethod(topic);
4123 }
4124 else if (strcasecmp(valCmdString,"status")==0)
4125 {
4126 SerialCall.println("status via set,cmd");
4127 //! request a STATUS be sent.
4128 processBarkletMessage("#STATUS", topic);
4129 }
4130 else if (strcasecmp(valCmdString,"resettimer")==0)
4131 {
4133 }
4134
4135 else
4136 {
4137 SerialTemp.printf("1.Unknown cmd: %s\n", valCmdString);
4138 }
4139 }
4140#pragma mark COPIED FROM BELOW .. so can set without DEVICE name
4141#define USE_WITHOUT_DEVICE_NAME
4142 //! 7.31.25 copied from below .. so it doesn't need 'dev' name in message
4143 //! eg:
4144 /*
4145 {"set":"sensors","val":"BuzzerSensorClass,19,22,L9110S_DCStepperClass,21,25"}
4146 {"set":"sensors","val":"BuzzerSensorClass,21,25,ULN2003_StepperClass,23,33"}
4147 {"set":"sensorPlugs","val":"L9110S_DCStepperClass"}
4148 {"set":"M5AtomKind","val":"M5HDriver"}
4149 {"set":"stepperAngle","val":"0.25"}
4150 {"ssid":"Bob", "ssidPassword":"scott"}
4151
4152 //! 1.22.26 new year, defint eh ChainButton objects
4153 {"set":"sensors","val":"BuzzerSensorClass,19,22,L9110S_DCStepperClass,21,25"}
4154
4155 */
4156#ifdef USE_WITHOUT_DEVICE_NAME
4157 //! 7.31.25 make this without DEV to make it easier..
4158 else if (strcasecmp(setCmdString,"stepperangle")==0)
4159 {
4160 SerialDebug.printf("stepperAngle: %s\n", valCmdString);
4161 //!set the stepperangle.
4163 foundCommand = true;
4164 }
4165
4166 //!8.14.25 Dead Movie from 10.19.1974 tonight..
4167 //! issue #394 stepperRPM
4168 //! stepper RPM
4169 else if (strcasecmp(setCmdString,"stepperRPM")==0)
4170 {
4171 SerialDebug.printf("stepperRPM: %s\n", valCmdString);
4172 //!set the stepperangle.
4174 foundCommand = true;
4175 }
4176
4177 //! 9.3.25 back from LA, Horses out. Tyler on lap. Europe next week
4178 //! sets the 2feed option (go back and forth)
4179 else if (strcasecmp(setCmdString,"2feed")==0)
4180 {
4181 SerialDebug.printf("2feed: %d\n", flag);
4182 //!set the 2feed flag.
4184 foundCommand = true;
4185 }
4186
4187 //! issue #338 sensor definition (in work)
4188 //! This will be a string in JSON format with various PIN and BUS information
4189 else if (strcasecmp(setCmdString,"sensorPlugs")==0)
4190 {
4192
4193 SerialDebug.printf("sensorPlugs: %s\n", valCmdString);
4194 foundCommand = true;
4195
4196 //! reboot the device to set subscribe or not for groups
4198 }
4199
4200 //! issue #365 sensors
4201 //! 5.14.25 (Dead 5.14.74 3rd wall of sound)
4202 else if (strcasecmp(setCmdString,"sensors")==0)
4203 {
4204 //! currently not rebooting the device, but letting the user do that..
4205 //! this way multiple can be done, and a "" will reset
4206 //! 5.17.25 plowing field Mark and Bud
4207 //! this is now a full set, and resets first..
4208 setSensorsString_mainModule(valCmdString);
4209
4210 foundCommand = true;
4211
4212 }
4213 else if (strcasecmp(setCmdString,"M5AtomKind")==0)
4214 {
4215 //! new 1.4.24 setting ATOM kind (eg. M5AtomSocket, M5AtomScanner). MQTT message "set":"M5AtomKind", val=
4217
4218 foundCommand = true;
4219
4220 //!for now just reboot which will use this perference
4222 }
4223 //! sets the BLEUseDeviceName flag == the BLEServer will add the name, eg PTFeeder:ScoobyDoo
4224 else if (strcasecmp(setCmdString,"BLEUseDeviceName")==0)
4225 {
4226
4227 //! sets the bleusedevicename flag
4229
4230 foundCommand = true;
4231
4232 //!for now just reboot which will use this perference and re-create the service name..
4234 }
4235 //!NOTE: foundCommand has to be set if the above worked.. without the DEV
4236#endif //use without device name
4237
4238#pragma mark Device Name and Not Group
4239 else if (deviceNameSpecified && !isGroupTopic())
4240 {
4241 //! if not found .. keep searching
4242 foundCommand = true;
4243 //! 9.28.23 #272 devOnlySM only show a SM if sent to this device
4244 if (strcasecmp(setCmdString,"devOnlySM")==0)
4245 {
4246 //set ble+wifi transient state..
4248 }
4249
4250 //! 11.21.25 Beautiful Sunrise on Rainier
4251 //! add a 'toggle' of various boolean values
4252 //! 11.21.25 - toggle a boolean value - since you might not know the value (like 2 light switches for same light)
4253 //! "toggle" <booleanCommand>
4254 //! booleanCommand ::= "buzzer" | "socket" | "useGroups"
4255 else if (strcasecmp(setCmdString,"toggle")==0)
4256 {
4257 //! 11.25.25 this is a bridge like 'feed' to the BLE connected device
4258 if (strcasecmp(valCmdString, "buzzer")==0)
4259 {
4260 //! see if connected to a BLE device..
4261 char *connectedBLEDeviceName = connectedBLEDeviceName_mainModule()?connectedBLEDeviceName_mainModule():NULL;
4262 SerialDebug.printf("connectedBLEDeviceName = %s\n", connectedBLEDeviceName);
4263
4264 SerialDebug.printf("Call Toggle Buzzer via BLE: 'F' - dev=%s\n", connectedBLEDeviceName);
4265 if (connectedBLEDeviceName)
4266 {
4267 //! send via BLE
4268 //!send a string of 13 or less characters.
4270 }
4271 else
4272 {
4273 //! set our own buzzer ???
4274 }
4275
4276 }
4277 else if (strcasecmp(valCmdString, "socket")==0)
4278 {
4279 //! toggle the socket
4280 }
4281 }
4282
4283
4284 //! 8.2.24 to let older Tumbler NOT do the auto direction (back and forth)
4285 //! Isue #332
4286 //! it will set via message: autoMotorDirection
4287 //! {"set":"autoMotorDirection","val":"true"}
4288 else if (strcasecmp(setCmdString,"autoMotorDirection")==0)
4289 {
4291 }
4292 //! 8.20.25 configuration,
4293 //! {"set":"config","val":"PTStepper"}
4294 else if (strcasecmp(setCmdString,"config")==0)
4295 {
4296 //! 8.20.25 Horses in field last night Beautiful..
4297 setConfiguration_mainModule(valCmdString);
4298 }
4299
4300 //! 8.2.24 add includeGroups
4301 //! Isue #332
4302 //! it will set via message: includeGroups
4303 //! {"set":"includeGroups","val":"group1,group2"}
4304 else if (strcasecmp(setCmdString,"includeGroups")==0)
4305 {
4306 //! 8.2.24 set the include group (and cache it), called from MQTT
4307 setIncludeGroups(valCmdString);
4308 }
4309
4310 else if (strcasecmp(setCmdString,"ble+wifi")==0)
4311 {
4312 //set ble+wifi transient state..
4314 }
4315 else if (strcasecmp(setCmdString,"factoryreset")==0)
4316 {
4317 // factory reset .. eventually
4319
4320 }
4321 //! 11.9.22
4322 else if (strcasecmp(setCmdString,"restartmodels")==0)
4323 {
4324 //!restarts all the menu states to the first one .. useful for getting a clean start. This doesn't care if the menu is being shown
4325 if (flag)
4327 }
4328 else if (strcasecmp(setCmdString,"screentimeout")==0)
4329 {
4330 //set the screen timeout
4332 }
4333 else if (strcasecmp(setCmdString,"stepperangle")==0)
4334 {
4335 SerialDebug.printf("stepperAngle: %s\n", valCmdString);
4336 //!set the stepperangle.
4338 }
4339 //!8.14.25 Dead Movie from 10.19.1974 tonight..
4340 //! issue #394 stepperRPM
4341 //! stepper RPM
4342 else if (strcasecmp(setCmdString,"stepperRPM")==0)
4343 {
4344 SerialDebug.printf("stepperRPM: %s\n", valCmdString);
4345 //!set the stepperangle.
4347 }
4348 //! 9.3.25 back from LA, Horses out. Tyler on lap. Europe next week
4349 //! sets the 2feed option (go back and forth)
4350 else if (strcasecmp(setCmdString,"2feed")==0)
4351 {
4352 SerialDebug.printf("2feed: %d\n", flag);
4353 //!set the stepperangle.
4355 }
4356 else if (strcasecmp(setCmdString,"noclick")==0)
4357 {
4358 //!set the timeout from no click to poweroff
4360 }
4361 else if (strcasecmp(setCmdString,"gateway")==0)
4362 {
4363 //! called to set a preference (which will be an identifier and a string, which can be converted to a number or boolean)
4365 }
4366 //! 10.4.22
4367 else if (strcasecmp(setCmdString,"DiscoverM5PTClicker")==0)
4368 {
4369 //! called to set a preference (which will be an identifier and a string, which can be converted to a number or boolean)
4371 }
4372 else if (strcasecmp(setCmdString,"usespiff")==0 && !isGroupTopic())
4373 {
4374 //! called to set a preference (which will be an identifier and a string, which can be converted to a number or boolean)
4376#ifdef USE_SPIFF_MODULE
4377 if (flag)
4378 {
4379 //! the setup for this module
4381 }
4382#endif //USE_SPIFF_MODULE
4383 }
4384 //! 4.4.24
4385 else if (strcasecmp(setCmdString,"usespiff_mqtt")==0 && !isGroupTopic())
4386 {
4387 //! called to set a preference (which will be an identifier and a string, which can be converted to a number or boolean)
4389 }
4390 else if (strcasecmp(setCmdString,"usespiff_qratom")==0 && !isGroupTopic())
4391 {
4392 //! called to set a preference (which will be an identifier and a string, which can be converted to a number or boolean)
4394 }
4395#ifdef ESP_M5
4396 //!NOTE: thes PIR and ATOM settings could be done in their modules AtomSocket but the LUX is in the butto
4397 //! 1.10.24 per issue#289 support PIR calling a SM in JSON (not just the FEED)
4398 else if (strcasecmp(setCmdString,"PIR_UseSM")==0 && !isGroupTopic())
4399 {
4401 //FOR now .. use the default that is to turn on all sockets...
4402 }
4403 //! 1.12.24 AtomSocketGlobalOnOff to turn on/off global onoff
4404 else if (strcasecmp(setCmdString,"AtomSocketGlobalOnOff")==0 && !isGroupTopic())
4405 {
4406 //! set global on/off is supported..
4408 }
4409 //! 1.12.24 set the value for the LUX sepearator from light and dark
4410 else if (strcasecmp(setCmdString,"LUXdark")==0 && !isGroupTopic())
4411 {
4412 //! save temporally ..
4414 }
4415 //! 1.13.24 scannedGroup temporary setting of the group name
4416 else if (strcasecmp(setCmdString,"scannedGroup")==0 && !isGroupTopic())
4417 {
4418 //! save temporally ..
4419 main_setScannedGroupName(valCmdString);
4420
4421 }
4422 //! 1.13.24 scannedDevice temporary setting of the group name
4423 else if (strcasecmp(setCmdString,"scannedDevice")==0 && !isGroupTopic())
4424 {
4425 //! save temporally ..
4426 main_setScannedDeviceName(valCmdString);
4427 }
4428#endif //ESP_M5
4429
4430 //!MQTT: set: timerdelay, val:seconds
4431 else if (strcasecmp(setCmdString,"timerdelay")==0)
4432 {
4433 int timerdelay = atoi(valCmdString);
4434 //!set the timer delay (0 == stop).
4436 //!start or stop the timer..
4437 SerialDebug.printf("timerdelay: %d\n", timerdelay);
4438
4439 }
4440 //!MQTT: set: timerdelay, val:seconds
4441 else if (strcasecmp(setCmdString,"timerdelayMax")==0)
4442 {
4443 int timerdelay = atoi(valCmdString);
4444 //!set the timer delay (0 == stop).
4446 //!start or stop the timer..
4447 SerialDebug.printf("timerdelayMax: %d\n", timerdelay);
4448 }
4449 //! MQTT: set: starttimer, val: true/false (true == start timer, false = stop timer)
4450 else if (strcasecmp(setCmdString,"starttimer")==0)
4451 {
4452 //!start or stop the timer..
4454 //!start or stop the timer..
4455 SerialDebug.printf("startTimer: %d\n", flag);
4456
4457 }
4458 //! issue #338 sensor definition (in work)
4459 //! This will be a string in JSON format with various PIN and BUS information
4460 else if (strcasecmp(setCmdString,"sensorPlugs")==0)
4461 {
4463
4464 SerialDebug.printf("sensorPlugs: %s\n", valCmdString);
4465
4466 //! reboot the device to set subscribe or not for groups
4468 }
4469
4470 //! issue #365 sensors
4471 //! 5.14.25 (Dead 5.14.74 3rd wall of sound)
4472 else if (strcasecmp(setCmdString,"sensors")==0)
4473 {
4474 //! currently not rebooting the device, but letting the user do that..
4475 //! this way multiple can be done, and a "" will reset
4476 //! 5.17.25 plowing field Mark and Bud
4477 //! this is now a full set, and resets first..
4478 setSensorsString_mainModule(valCmdString);
4479 }
4480 //!add stepper type
4481 else if (strcasecmp(setCmdString,"stepper")==0)
4482 {
4483 //!set the stepperAngle as well for a default value
4484 //!as of 8l18.24, the stepperAngle isn't used by the MINI (only the Tumbler)
4485 float stepperAngle = 22.5;
4486 int feederType = STEPPER_IS_UNO;
4487 //!NOTE: 'mini' is deprecated
4488 if (strcasecmp(valCmdString,"mini")==0)
4489 {
4490 //! mini will be backdoor to set the angle to 45
4491 // is UNO
4492 stepperAngle = 45.0;
4493 //feederType = STEPPER_IS_MINI;
4494 }
4495 else if (strcasecmp(valCmdString,"tumbler")==0)
4496 {
4497 feederType = STEPPER_IS_TUMBLER;
4498 stepperAngle = 200.0;
4499 //! set autoRotoate as well..
4501
4502 }
4503 else
4504 {
4505 //! set autoRotoate as well..
4507 }
4508 SerialDebug.printf("stepper = %d, stepperAngle = %f\n", feederType, stepperAngle);
4509 //! called to set a preference (which will be an identifier and a string, which can be converted to a number or boolean)
4511 //!set stepperAngle default as well (int or float ok..)
4512 //!Issue #332 8.17.2024
4514 //! default to clockwise == 1
4515
4516 //! 8.18.24 setting this will check for the factory setting..
4518 } //stepper
4519 else if (strcasecmp(setCmdString,"factoryClockwiseMotor")==0)
4520 {
4521 SerialCall.println(" *** Setting factory clockwise motor");
4522 //!note since clockwise == 0 we set the opposite of the value..
4524 //! 8.18.24 setting this will check for the factory setting..
4526 }
4527 else if (strcasecmp(setCmdString,"clockwiseMotor")==0)
4528 {
4529 SerialCall.println(" *** Setting clockwise motor");
4530 //! 8.18.24 setting this will check for the factory setting..
4532 }
4533 //! 8.18.24 (back deck with Tyler - Maggie - stormy lightning last night and rain
4534 //! toggleMotor the 'Q'
4535 //! 'set':'toggleMotor':'val':'on/off"
4536 //! TODO: call the 'Q' code ..
4537 else if (strcasecmp(setCmdString,"toggleMotor")==0)
4538 {
4539 //! 9.30.23 reverse direction
4540 //else if (cmd == 'Q')
4541
4542 //! note: reboot not needed as the next time a feed happens, it reads this value
4543 // motor direction == (reverse)
4545 currentDirection = !currentDirection;
4547 }
4548 //!add stepper type
4549 else if (strcasecmp(setCmdString,"otafile")==0)
4550 {
4551 //perform the OTA via a file specified .. be careful..
4553 }
4554 //!set the location
4555 else if (strcasecmp(setCmdString,"location")==0 && !isGroupTopic())
4556 {
4557 //perform the OTA via a file specified .. be careful..
4558 _jsonLocationString = createCopy(valCmdString);
4560 }
4561
4562 //! pairnow is for invoking the pair when there isn't a user interface. Basically
4563 //! once an ESP32 gets connected, especially to a GEN3, the pairnow will make it paired
4564 //! for future. 10.24.22
4565 else if (strcasecmp(setCmdString,"pairnow")==0)
4566 {
4567 //! TRUE will pair, FALSE will unpair
4568 if (flag)
4569 //!performs the pairing.. to whatever is currently connected, this means a message could make that happen
4570 //!for a device (ESP-32) with no user interface.
4572 else
4573 //! just unpair .. don't skip
4574 //!performs the unpairing
4576 }
4577 //! paireddev the paired device (used with BLEUsePairedDeviceName and gen3Only
4578 else if (strcasecmp(setCmdString,"pairdev")==0)
4579 {
4581 if (strcasecmp(valCmdString,previousName)!=0)
4582 {
4583 //different than current..
4584
4585 //!saves the pair device name TODO: the feed device should use the pair as well.. (DONE..)
4587
4588 //! paired address is null until found..
4589 //! Keep whatever is set ...???
4590 //! 8.16.25 BLE CLIENT
4591 //!if BLE connected, then we keep the address if any and GEN3
4593 {
4594 //keep the Address (but change the use supplied device name)
4595 }
4596 else
4597 {
4598 //! erase the ADDRESS (as well as new name) .. and disconnect if connected..
4601 //! try to disconnect..
4603 }
4604
4605#ifdef NO_MORE_PREFERENCE_BLE_USE_DISCOVERED_PAIRED_DEVICE_SETTING
4606 if (strlen(valCmdString)==0)
4607 {
4608 //!turn off pairing
4610
4611 }
4612#endif
4613 }
4614 } //pairdev
4615
4616 //! sets the PREFERENCE_SUPPORT_GROUPS_SETTING
4617 else if (strcasecmp(setCmdString,"usegroups")==0)
4618 {
4619 //! sets the PREFERENCE_SUPPORT_GROUPS_SETTING flag
4621
4622 //! reboot the device to set subscribe or not for groups
4624 }
4625 //! sets the PREFERENCE_GROUP_NAMES_SETTING
4626 else if (strcasecmp(setCmdString,"groups")==0)
4627 {
4628 //! sets the PREFERENCE_GROUP_NAMES_SETTING val (eg. atlasDogs, houndDogs) or (#) or ""
4630
4631 //! reboot the device to set subscribe or not for groups
4633
4634 }
4635 else
4636 foundCommand = false;
4637 } // device but not group
4638#pragma mark END of device and not group
4639 //! if not found, continue BNF options..
4640 if (!foundCommand)
4641 {
4642 //! rename device
4643 if (strcasecmp(setCmdString,"device")==0 && !isGroupTopic())
4644 {
4645 //define the device
4646 _deviceNameString = createCopy(valCmdString);
4648
4649 //!since renaming, lets set a STATUS out..
4650 //! request a STATUS be sent.
4651 processBarkletMessage("#STATUS", topic);
4652 }
4653
4654#ifdef ESP_M5
4655 else if (strcasecmp(setCmdString,"screencolor")==0)
4656 {
4657 //!set the screen color 0..n
4658 int screenColor = atoi(valCmdString);
4659 setScreenColor_displayModule(screenColor);
4660
4661 //stay on this page, but change the marker..
4663 }
4664 //! sets the gen3only flag (only look for BLEServers that are GEN3)
4665 else if (strcasecmp(setCmdString,"gen3only")==0)
4666 {
4667 if (deviceNameSpecified && !isGroupTopic())
4668 {
4669 //! sets the gen3only flag
4671 //!for now just reboot which will use this perference
4672 // rebootDevice_mainModule();
4673 //TODO... maybe just disconnect .. or don't worry about it unless connected
4674 }
4675 }
4676 //! BLEUsePairedDeviceName (Says to only look for BLEServers with the paired name..
4677 else if (strcasecmp(setCmdString,"BLEUsePairedDeviceName")==0)
4678 {
4679 if (deviceNameSpecified && !isGroupTopic())
4680 {
4681#ifdef NO_MORE_PREFERENCE_BLE_USE_DISCOVERED_PAIRED_DEVICE_SETTING
4682 //! sets the bleusepaireddevicename flag
4684#endif
4685 }
4686 }
4687#endif //ESP_M5
4688 //! sets the BLEUseDeviceName flag == the BLEServer will add the name, eg PTFeeder:ScoobyDoo
4689 else if (strcasecmp(setCmdString,"BLEUseDeviceName")==0)
4690 {
4691 if (deviceNameSpecified && !isGroupTopic())
4692 {
4693 //! sets the bleusedevicename flag
4695
4696 //!for now just reboot which will use this perference and re-create the service name..
4698
4699 //! 8.16.25 BLE CLIENT
4700 //! try to disconnect..
4701 // disconnect_BLEClientNetworking();
4702 }
4703 }
4704#ifdef ESP_M5
4705 else if (strcasecmp(setCmdString,"minMenu")==0)
4706 {
4707 SerialDebug.println("PREFERENCE_IS_MINIMAL_MENU_SETTING via BLE");
4708 if (flag)
4709 {
4712 }
4713 else
4714 {
4715 int max = minMenuModesMax_mainModule();
4716 //set to start of after min..
4718 }
4719 //!send message to ourself to process the current mode..
4721 }
4722 else if (strcasecmp(setCmdString,"addwifi")==0)
4723 {
4724 if (deviceNameSpecified && !isGroupTopic())
4725 {
4726 //has to support "Cisco:"
4727 //parse the valCmdString: ssid:password
4728 char str[100];
4729 strcpy(str,valCmdString);
4730 char *token;
4731 char *rest = str;
4732 char* ssid = strtok_r(rest,":", &rest);
4733 char* password = strtok_r(rest,":", &rest);
4734 SerialDebug.printf("addwifi %s, %s\n", ssid?ssid:"null", password?password:"");
4735 //now save as a credential
4736 // main_addWIFICredentials(addSSID, addPassword);
4737 //!send message to ourself to process the current mode..
4738 // invokeCurrentSMModePage(topic);
4739
4740 //NOTE: there can be empty passwords..
4741 char credentials[100];
4742 //!store the JSON version of these credentials..
4743 sprintf(credentials, "{'ssid':'%s','ssidPassword':'%s'}", ssid?ssid:"NULL", password?password:"");
4744 // This works by just sending the credentials to ourself .. and process correctly.
4745 SerialMin.println(credentials);
4746 //!per #224 this will also set WIFI_CREDENTIAL_2 (even if it's also setting #1)
4747 //!NOTE: this saving has to be done before calling processJSON (since the string is goofed upand == 'ssid' not the full string
4749
4750 //!now process the credentials, which will set CREDENTIAL_1
4752
4753 //!print the preferences to SerialDebug
4755
4756 //The problem with invoking the current SMModePage is if we are on the swap WIFI page, then it will swap .. which might not be desired..
4757 }
4758 }
4759 else if (strcasecmp(setCmdString,"usedocfollow")==0)
4760 {
4761 SerialDebug.printf("PREFERENCE_USE_DOC_FOLLOW_SETTING %s\n", valCmdString);
4763
4764 }
4765#endif //ESP)_M5
4766 else if (strcasecmp(setCmdString,"semanticMarker")==0)
4767 {
4768 SerialDebug.printf("2.SemanticMarker: %s\n", valCmdString);
4770
4771 //! 9.28.29 devOnlySM if set, then
4772 boolean showSM = true;
4774 showSM = deviceNameSpecified;
4775 if (showSM)
4776 // 9.27.23 also show this ..
4777 //! use the name/cat/uuid ..
4778 showSemanticMarker_displayModule(valCmdString, "Semantic Marker");
4779 else
4780 SerialDebug.println("Not showing SemanticMarker ");
4781 }
4782#ifdef ESP_M5
4783 //blankscreen on/off
4784 else if (strcasecmp(setCmdString,"blankscreen")==0)
4785 {
4786 //!if flag then blankscreen, otherwise wake the screen..
4787 if (flag)
4788 //!blanks the screen
4790 else
4791 //!wakes up the screen
4793 }
4794#endif //ESP_M5
4795
4796 //!8.17.22 SubDawgpack
4797 else if (strcasecmp(setCmdString,"SubDawgpack")==0)
4798 {
4799 if (deviceNameSpecified && !isGroupTopic())
4800 {
4801 SerialDebug.println("PREFERENCE_SUB_DAWGPACK_SETTING via BLE");
4803 //!for now just reboot which will use this perference
4804 //rebootDevice_mainModule();
4805 if (flag)
4806 {
4807 //! start a dawgpack subscription
4808 //! 8.15.22 Also subscribe to the dawgpack .. but restrict what it can effect.
4809 //! For example, start with STATUS and DOCFOLLOW
4810 _mqttClient.subscribe((char*)"usersP/dawgpack");
4811 }
4812 else
4813 {
4814 // unsubscribe (tested and it works)
4815 _mqttClient.unsubscribe((char*)"usersP/dawgpack");
4816 }
4817 }
4818 }
4819
4820 //!TODO: duplicate and depreciate these and replace with set:buzz,val:on
4821 else if (strcasecmp(setCmdString,"buzz")==0 && !isGroupTopic())
4822 {
4823 //! this uses the ASYNC since it involves a BLE command, and has to be done outside
4824 //! of this WIFI (MQTT) operation..
4825 if (flag)
4826 {
4827 SerialDebug.println("BUZZ:ON via BLE");
4829 }
4830 else
4831 {
4832 SerialDebug.println("BUZZ:OFF via BLE");
4834 }
4835 }
4836
4837
4838 //BLECLient
4839 else if (strcasecmp(setCmdString,"bleclient")==0)
4840 {
4841 if (deviceNameSpecified && !isGroupTopic())
4842 {
4843 SerialDebug.println("PREFERENCE_MAIN_BLE_CLIENT_VALUE via BLE");
4845 , flag);
4846 //!for now just reboot which will use this perference
4848 }
4849 }
4850 // bleserver
4851 else if (strcasecmp(setCmdString,"bleserver")==0)
4852 {
4853 if (deviceNameSpecified && !isGroupTopic())
4854 {
4855 SerialDebug.println("PREFERENCE_MAIN_BLE_SERVER_VALUE via BLE");
4857 //!for now just reboot which will use this perference
4859 }
4860 }
4861 else if (strcasecmp(setCmdString,"tilt")==0)
4862 {
4863 if (deviceNameSpecified && !isGroupTopic())
4864 {
4865 SerialDebug.println("PREFERENCE_SENSOR_TILT_VALUE via BLE");
4867 }
4868 }
4869#ifdef ESP_M5
4870
4871 else if (strcasecmp(setCmdString,"zoomSm")==0)
4872 {
4873 //!zoom == the NON semantic marker version.. so min menu is true
4874 if (flag)
4875 {
4876
4877 //hide semantic marker.. (but only if in the max menus)
4878 //NOTE: this only hides the Semantic Marker - if on a page that has one..
4879 SerialDebug.println("PREFERENCE_SEMANTIC_MARKER_ZOOMED_VALUE ON via BLE");
4881
4882 //!zoom only if in the max menu set..
4884 {
4885 //stay on this page, but change the marker..
4887 }
4888
4889 }
4890 else
4891 {
4892 //show semantic marker..
4893 //NOTE: this only shows the Semantic Marker - if on a page that has one..
4894 SerialDebug.println("PREFERENCE_SEMANTIC_MARKER_ZOOMED_VALUE OFF via BLE");
4897
4898 //!zoom only if in the max menu set..
4900 {
4901 //change to the status..
4903 //!send message to ourself to process the current mode..
4905 }
4906 else
4907 {
4908 //stay on this page, but change the zoom..
4910 }
4911 }
4912 } // zoomSM
4913 //! 9.22.22 added button press from messages..
4914 else if (strcasecmp(setCmdString,"buttonA")==0)
4915 {
4916 if (strcasecmp(valCmdString,"longpress")==0)
4918 else if (strcasecmp(valCmdString,"shortpress")==0)
4920 }
4921 else if (strcasecmp(setCmdString,"buttonB")==0)
4922 {
4923 if (strcasecmp(valCmdString,"longpress")==0)
4925 else if (strcasecmp(valCmdString,"shortpress")==0)
4927 }
4928 else if (strcasecmp(setCmdString,"M5AtomKind")==0 && !isGroupTopic())
4929 {
4930 //! new 1.4.24 setting ATOM kind (eg. M5AtomSocket, M5AtomScanner). MQTT message "set":"M5AtomKind", val=
4932
4933 //!for now just reboot which will use this perference
4935 }
4936#endif //ESP_M5
4937 else if (strcasecmp(setCmdString,"disk")==0)
4938 {
4939 SerialDebug.printf("Cloud DISK space = %s\n", valCmdString);
4940 }
4941 else if (strcasecmp(setCmdString,"feedcount")==0)
4942 {
4943 SerialDebug.printf("Global feed count = %s\n", valCmdString);
4944 }
4945 else
4946 {
4947 SerialMin.printf("2.Unknown cmd: %s (isGroupTopic=%d)\n", setCmdString, isGroupTopic());
4948 }
4949
4950 } // not found
4951 } // (setCmd && valCmd)
4952 //!5.24.22 send:<request> .. Note these are for cmd without an argument..
4953 else if (sendCmd)
4954 {
4955 //!NOTE: This will be calling ourself
4956
4957 char* sendCmdString = const_cast<char*>(sendCmd);
4958 //! 8.16.25 call the main to pass onto plugs
4959 messageSend_mainModule(sendCmdString, deviceNameSpecified);
4960
4961 if (strcasecmp(sendCmdString,"temp")==0)
4962 {
4963 SerialCall.println("sendCmd == temp");
4964 //! request a TEMP be sent.
4965 processBarkletMessage("#TEMP", topic);
4966 }
4967 else if (strcasecmp(sendCmdString,"status")==0)
4968 {
4969 SerialCall.println("sendCmd == status");
4970 //! request a STATUS be sent.
4971 processBarkletMessage("#STATUS", topic);
4972 }
4973
4974 else if (strcasecmp(sendCmdString,"capture")==0)
4975 {
4976 SerialCall.println("sendCmd == capture");
4977 //! request a CAPTURE be sent.
4978 processBarkletMessage("#CAPTURE", topic);
4979 }
4980
4981#ifdef ESP_M5
4982
4983 else if (strcasecmp(sendCmdString,"volume")==0)
4984 {
4985 SerialCall.println("sendCmd == volume (not implemented)");
4986 //! request a VOLUME be sent.
4987 processBarkletMessage("#VOLUME", topic);
4988 }
4989#endif //ESP_M5
4990 else
4991 {
4992 SerialTemp.print("Unknown send request: ");
4993 SerialTemp.println(sendCmdString);
4994 }
4995
4996 } //sendCmd
4997 //! 9.18.23 set64 with a val
4998 else if (set64Cmd)
4999 {
5000#ifdef ESP_M5
5001 //! currently 9.28.23 no reason for feeder to decode base64 messages. That could change if a stored procedure..
5002 char* setCmdString = const_cast<char*>(set64Cmd);
5003 char* valCmdString = const_cast<char*>(valCmd);
5004#ifdef DECODE_BASE64
5005 char plaintext_out[200];
5006 int len = strlen(valCmdString);
5007 if (len > 200)
5008 {
5009 SerialError.println("Length too long to base64 decode: 200");
5010 }
5011 else
5012 {
5013 int status = base64_decode_chars(valCmdString, len, plaintext_out);
5014 String decoded = String(plaintext_out);
5015 decoded = MQTT_urlDecode(decoded);
5016
5017 //! 1.11.24 the decoded value might have URL encoded like %7B for '{' and %7D }
5018 //! ACTUALLY the MQTT_urlDecode is missing the 7's
5019 //! https://www.arduino.cc/reference/en/language/variables/data-types/string/functions/indexof/
5020
5021 SerialDebug.println(decoded);
5022 // not case sensitive
5023 if (strcasecmp(setCmdString,"semanticMarker")==0 && !isGroupTopic())
5024 {
5025 //! see if docFollow .. if not then don't show it
5027
5028 //! 9.28.29 devOnlySM if set, then set to whether the deviceNameSpecified (eg. dev=...)
5029 boolean showSM = true;
5031 showSM = deviceNameSpecified;
5032
5033 if (!useDocFollow)
5034 showSM = false;
5035
5036 //! 1.11.24 NOTE: this changes the page on the M5 (and I'm sending this message often
5037 //! for a demo of the watch -- SO: maybe there should be a mode to NOT accept the SM ??
5038 if (showSM)
5039 //!displays the Semantic Marker (a super QR code) on the M5 screen (title = to display)
5040 showSemanticMarker_displayModule(decoded, "SemanticMarker");
5041 else
5042 SerialDebug.println("Not showing SemanticMarker ");
5043 }
5044 else if (strcasecmp(setCmdString,"PIR_SM_JSON")==0 && !isGroupTopic())
5045 {
5046 //! 1.11.24 support setting the SM to use with the PIR (and eventually other commands)
5047 //!@see https://github.com/konacurrents/ESP_IOT/issues/289
5048 //!{"set":"PIR_UseSM", "val": "on/off"}
5049 //!{"set64":"PIR_SM_JSON", "val": "JSONbase64"}
5050 //! NOTE: this could turn on the PIR_UseSM at the same time..
5051
5054 //!let others know ??
5055 // sendMessageString_mainModule(decoded.c_str());
5056 }
5057 else if (strcasecmp(setCmdString,"PIR_OFF_SM_JSON")==0 && !isGroupTopic())
5058 {
5059 //! 1.11.24 support setting the SM to use with the PIR (and eventually other commands)
5060 //!@see https://github.com/konacurrents/ESP_IOT/issues/289
5061 //!{"set":"PIR_UseSM", "val": "on/off"}
5062 //!{"set64":"PIR_SM_JSON", "val": "JSONbase64"}
5063 //! NOTE: this could turn on the PIR_UseSM at the same time..
5064
5067 //!let others know ??
5068 // sendMessageString_mainModule(decoded.c_str());
5069 }
5070
5071 //! 3.22.25 Returned stranded from space station
5072 //! if ScannedSemanticMarker .. call the set
5073 else if (strcasecmp(setCmdString,"ScannedSemanticMarker")==0)
5074 {
5075 //! 12.27.23 pass this onto those registered (which mainModule is handling..)
5076 //! 8.28.23 Tell Main about the set,val and if others are registered .. then get informed
5077 //! 1.10.24 if deviceNameSpecified then this matches this device, otherwise for all.
5078 //! It's up to the receiver to decide if it has to be specified
5079 //! 1.14.24 for now, setVal in the ATOM will support GROUP commands if turned on (and if off it doesn't get here)
5080 char * my_argument = const_cast<char*> (decoded.c_str());
5081 messageSetVal_mainModule(setCmdString, my_argument, deviceNameSpecified);
5082 }
5083
5084 }
5085
5086#endif //DECODE_BASE64
5087#endif //ESP_M5
5088
5089 }
5090
5091 //!NOTE: if teh command isn't recognized .. then it slips through.. and is treaded like
5092 //!this return is important!!!
5093 return true;
5094 } //!end process commands..
5095
5096 //! ISSUE: when new JSON shows up that isn't process above, it's thought to be setting the credentials.
5097 //! Thus the {set64} continues below..
5098
5099
5100 //end NEW
5101 //!TRY without 1.30.22 (RAMS win) and it works..
5102 //!9.17.23 .. RAMS loose to 49rs in LA (we are in LA)
5103 //!if can talk BLE, then reboot.. 2.2.22
5104
5105 //NOTE: here is where different reasons for the info could be provided in the data>
5106 // eg. dataKind (wifi, mqtt, etc...)boot
5107 /**
5108 {
5109 "ssid" : "SunnyWhiteriver",
5110 "ssidPassword" : "sunny2021",
5111 "mqtt_topic": "usersP/bark/test",
5112 "mqtt_user" : "test",
5113 "deviceName" : "HowieFeeder",
5114 "mqtt_password" : "password..",
5115 "mqtt_guestPassword" : "password",
5116 "uuid" : "scott",
5117 "mqtt_port" : "1883",
5118 "mqtt_server" : "idogwatch.com",
5119 "mqtt_status" : "Success",
5120 "location": "whatever to reply with, GPS, state, city, etc.."
5121 }
5122
5123 //todo pass the guest password too
5124 */
5125 //TODO: parse the string...
5126 //!! Store wifi config. 存储wifi配置信息
5127 //! @see https://arduinojson.org
5128
5129//! THE CHALLENGE: if send use {ssid, ssidPassword} .. it will assume others
5130//! SO .. only null out the value if (1) there is an attributed {ssid} and empty string..
5131//#define ONLY_NULL_IF_THERE
5132#ifdef ONLY_NULL_IF_THERE
5133 SerialDebug.println(" *** processMQTT .. treat like credentials");
5134 {
5135 const char* a1 = myObject["ssid"];
5136 if (a1)
5137 {
5138 _ssidString = const_cast<char*>(a1);
5140 }
5141
5142 SerialTemp.printf("myObject[ssid] = '%s'\n", a1?a1:"EMPTY");
5143 //SerialTemp.println(a1);
5144 SerialTemp.println(_ssidString);
5145 }
5146
5147 {
5148 const char* a2 = myObject["ssidPassword"];
5149 if (a2)
5150 {
5151 _ssidPasswordString = const_cast<char*>(a2);
5153 }
5154
5155 }
5156#else
5157 SerialDebug.println(" *** processMQTT .. treat like credentials");
5158 {
5159 const char* a1 = myObject["ssid"];
5160 if (a1 && strlen(a1)>0)
5161 {
5162 _ssidString = const_cast<char*>(a1);
5164 }
5165 else
5166 _ssidString = NULL;
5167 SerialTemp.printf("myObject[ssid] = '%s'\n", a1?a1:"EMPTY");
5168 //SerialTemp.println(a1);
5169 SerialTemp.println(_ssidString);
5170 }
5171
5172 {
5173 const char* a2 = myObject["ssidPassword"];
5174 if (a2 && strlen(a2)>0)
5175 {
5176 _ssidPasswordString = const_cast<char*>(a2);
5178 }
5179 else
5180 _ssidPasswordString = NULL;
5181 }
5182#endif
5183 {
5184 //!5.25.22 (50 years since Grateful Dead London Show
5185
5186 //! To support just setting the ssid and password, a JSON
5187 //! of {ssid:s,ssidPassword:p} is supported, so don't null out if mqtt aren't provided..
5188 //! this should work (since the SSID is what's checked to go to the AP mode)
5189
5190 //!the MQTT host/port/user/password (topic is created in this code...)
5191 const char* a3 = myObject["mqtt_server"];
5192 if (a3)
5193 {
5194 _mqttServerString = const_cast<char*>(a3);
5196 }
5197 // else
5198 // _mqttServerString = NULL;
5199 }
5200 {
5201 const char* a4 = myObject["mqtt_port"];
5202 if (a4)
5203 {
5204 _mqttPortString = const_cast<char*>(a4);
5206 }
5207 // else
5208 // _mqttPortString = NULL;
5209 //
5210 }
5211 {
5212 const char* a5 = myObject["mqtt_password"];
5213 if (a5)
5214 {
5215 _mqttPasswordString = const_cast<char*>(a5);
5217 }
5218 // else
5219 // _mqttPasswordString = NULL;
5220 }
5221
5222 {
5223 const char* a6 = myObject["mqtt_user"];
5224 if (a6)
5225 {
5226 _mqttUserString = const_cast<char*>(a6);
5228 }
5229 // else
5230 // _mqttUserString = NULL;
5231 }
5232 {
5233 //! This should keep the deviceName to whatever was specified
5234 const char* a7 = myObject["deviceName"];
5235 if (a7 && strlen(a7)>0)
5236 {
5237 _deviceNameString = const_cast<char*>(a7);
5239 }
5240 // else
5241 // _deviceNameString = NULL;
5242 }
5243 {
5244 const char* a8 = myObject["uuid"];
5245#ifdef NOT_ORIGINAL
5246 if (a8 && strlen(a8)>0)
5247#else
5248 if (a8)
5249#endif
5250 {
5251 _uuidString = const_cast<char*>(a8);
5253 }
5254 // else
5255 // _uuidString = NULL;
5256 }
5257 {
5258 const char* a9 = myObject["mqtt_topic"];
5259#ifdef NOT_ORIGINAL
5260 if (a9 && strlen(a9)>0)
5261#else
5262 if (a9)
5263#endif
5264 {
5265 _mqttTopicString = const_cast<char*>(a9);
5267 }
5268 // else
5269 // _mqttTopicString = NULL;
5270
5271 }
5272 {
5273 const char* a10 = myObject["mqtt_guestPassword"];
5274#ifdef NOT_ORIGINAL
5275 if (a10 && strlen(a10)>0)
5276#else
5277 if (a10)
5278#endif
5279 {
5280 _mqttGuestPasswordString = const_cast<char*>(a10);
5282 }
5283 // else
5284 // _mqttGuestPasswordString = NULL;
5285 }
5286
5287 {
5288 const char* a11 = myObject["location"];
5289 if (a11 && strlen(a11)>0)
5290 {
5291 _jsonLocationString = const_cast<char*>(a11);
5293 }
5294 // else
5295 // _mqttGuestPasswordString = NULL;
5296 }
5297
5298 //!reset the MQTT attempts
5300
5301 boolean saveJSONPreferences = true;
5302 //!setup the WIFI if the ssid string (at least) is specified
5304 {
5305 SerialDebug.println("Setting WIFI from JSON parameters");
5306 //setupWIFI(_ssidString, _ssidPasswordString);
5307
5308 //!new: go out and let the process work...
5309 //!set the state, then the 'loop' will call setupWIF(...)
5312
5313 }
5314 else
5315 {
5316 SerialDebug.println(" ***** ERROR .. no ssidString *** ");
5317 //!call the callback specified from the caller (eg. NimBLE_PetTutor_Server .. or others)
5319
5320 saveJSONPreferences = false;
5321 }
5322
5323
5324 //!don't save the preferences, since it didn't have enough information..
5325 if (!saveJSONPreferences)
5326 {
5327 SerialDebug.println("**** Not saving JSON in preferences ***");
5328 return true;
5329 }
5330
5331 //!NOTE: this writes over entire values, since it's a string vs an JSON object
5333
5334 //!new 4.8.22 .. trying to kick out of AP mode if the credentials are good..
5336
5337 //!putting here .. time might have gone too fast..
5340
5341
5342 return true;
5343}
5344
5345//!restart the WIFI and then MQTT connection
5347{
5348 //let it know MQTT isn't running either
5349 _MQTTRunning = false;
5350
5351 SerialTemp.printf("restartWIFI_MQTTState (%s, %s)\n", _ssidString?_ssidString:"NULL", _ssidPasswordString?_ssidPasswordString:"NULL");
5352//#define TRY_EXIT2
5353#ifdef TRY_EXIT2
5354 //! 9.19.23 before Van Morrison ..
5355 if (!_ssidString || (_ssidString && strlen(_ssidString)==0))
5356 {
5357 SerialDebug.println("set disconnectedWIFI and stopDelay");
5358 //putting here .. time might have gone too fast..
5361 return;
5362 }
5363#endif
5364 //putting here .. time might have gone too fast..
5367}
5368
5369//! 9.18.23 LA (after Eagle Rock bike ride, Van Morrison tomorrow)
5371{
5372 SerialDebug.println("cleanMQTTpasswordsUpdateInEPROM");
5373 _ssidString = NULL;
5374 _mqttPasswordString = NULL;
5376
5377 //!now update the eprom with these null values
5379}
5380
5381//!just update the EPROM, and send that to the WIFI_AP module as well
5383{
5384 SerialDebug.printf("updatePreferencesInEPROM (mqtt-pass=%s)\n",_mqttPasswordString?_mqttPasswordString:"NULL");
5385
5386 DynamicJsonDocument myObject(1024);
5387
5388 //!basically if only the ssid/pass are sent, that is all that's written to EPROM
5389 //!even if the other information is available.. So recreate the JSON instead..
5390 //!seems c++ you cannot re-use output as it just appends to it.. unreal
5391 String output2;
5392#ifdef NOT_ORIGINAL
5393 myObject["ssid"] = _ssidString?_ssidString:"";
5394 myObject["ssidPassword"] = _ssidPasswordString?_ssidPasswordString:"";
5395 myObject["mqtt_server"] = _mqttServerString;
5396 myObject["mqtt_port"] = _mqttPortString;
5397 myObject["mqtt_password"] = _mqttPasswordString?_mqttPasswordString:"";
5398 myObject["mqtt_guestPassword"] = _mqttGuestPasswordString?_mqttGuestPasswordString:"";
5399#else
5400 myObject["ssid"] = _ssidString;
5401 myObject["ssidPassword"] = _ssidPasswordString;
5402 myObject["mqtt_server"] = _mqttServerString;
5403 myObject["mqtt_port"] = _mqttPortString;
5404 myObject["mqtt_password"] = _mqttPasswordString;
5405 myObject["mqtt_guestPassword"] = _mqttGuestPasswordString;
5406#endif
5407 myObject["mqtt_user"] = _mqttUserString;
5408 {
5409 char buf[100];
5410 sprintf(buf,"usersP/bark/%s", _mqttUserString?_mqttUserString:"NOTSET");
5412 }
5413 myObject["mqtt_topic"] = _mqttTopicString;
5414 myObject["deviceName"] = _deviceNameString;
5415 myObject["uuid"] = _uuidString;
5416 myObject["jsonHeader"] = _jsonHeaderString;
5417 myObject["jsonVersion"] = _jsonVersionString;
5418 myObject["location"] = _jsonLocationString;
5419
5420
5421 //!JSON
5422 serializeJson(myObject, output2);
5423
5424 //!open the preferences
5426 SerialDebug.print("MQTTNetworking.Writing EPROM JSON = '");
5427 SerialDebug.print(output2);
5428 SerialDebug.println("'");
5429
5430 //!save in EPROM
5432 //! Close the Preferences
5434
5435 //! sets the MQTT user/password. It's up to the code to decide who needs to know (currently saves in the WIFI_APModule
5437#define NO_NEED_AND_GRU_CRASH
5438#ifdef NO_NEED_AND_GRU_CRASH
5439 //!NEW: 2.21.22
5440 //!TRY: reading back..
5441 _preferencesMQTTNetworking.begin(ESP_EPROM_NAME, false); //false=read/write..
5443 SerialDebug.print("Reading.2 EPROM JSON = ");
5444 SerialDebug.println(_fullJSONString? _fullJSONString:"NULL");
5445
5446 //!check ... _fullMessageOut
5447 //! Close the Preferences
5449#endif
5450}
5451
5452
5453
5454//!Decode the URL
5455//!@see https://www.w3schools.com/tags/ref_urlencode.ASP
5456String MQTT_urlDecode(String input) {
5457 String s = input;
5458 s.replace("%20", " ");
5459 s.replace("+", " ");
5460 s.replace("%21", "!");
5461 s.replace("%22", "\"");
5462 s.replace("%23", "#");
5463 s.replace("%24", "$");
5464 s.replace("%25", "%");
5465 s.replace("%26", "&");
5466 s.replace("%27", "\'");
5467 s.replace("%28", "(");
5468 s.replace("%29", ")");
5469 s.replace("%30", "*");
5470 s.replace("%31", "+");
5471 s.replace("%2C", ",");
5472 s.replace("%2E", ".");
5473 s.replace("%2F", "/");
5474 s.replace("%2C", ",");
5475 s.replace("%3A", ":");
5476 s.replace("%3B", ";");
5477 s.replace("%3C", "<");
5478 s.replace("%3D", "=");
5479 s.replace("%3E", ">");
5480 s.replace("%3F", "?");
5481 s.replace("%40", "@");
5482 s.replace("%5B", "[");
5483 s.replace("%5C", "\\");
5484 s.replace("%5D", "]");
5485 s.replace("%5E", "^");
5486 s.replace("%5F", "-");
5487 s.replace("%60", "`");
5488 s.replace("%7B", "{");
5489 s.replace("%7D", "}");
5490
5491 return s;
5492}
5493
boolean isConnectedBLEClient()
returns whether connected over BLE as a client to a server(like a ESP feeder)
void disconnect_BLEClientNetworking()
try to disconnect..
void sendCommandBLEClient_13orLess(String cmdString)
send a string of 13 characters or less
char * getServiceName_BLEServerNetworking()
retrieve the service name (PTFEEDER, PTFeeder:Name, PTClicker:Name, etc)
void showSemanticMarkerFunc_displayModule(String semanticMarkerAddressBase, String title, const char *(*getStatusFunc)(void))
finish the address after calling the function provided, called from MQTT for STATUS
void addToTextMessages_displayModule(String text)
void wakeupScreen_displayModule()
wakes up the screen
void showText_displayModule(String text)
void redrawSemanticMarker_displayModule(boolean startNew)
redraws the image..
void setScreenColor_displayModule(int screenColor)
cache for getting the screen color 0..n. Will reset the cache as well
void showSemanticMarker_displayModule(String semanticMarkerAddress, String title)
displays the Semantic Marker (a super QR code) on the M5 screen (with an N second display)
void blankScreen_displayModule()
blanks the screen
void resetLoopTimer_displayModule()
reset the loop timer .. useful for testing,
#define START_NEW
Definition: DisplayModule.h:53
void blinkBlueLightMQTT()
blinks the blue light
void startDelayCheckWIFI_MQTTNetworking(int seconds)
init the delay
void publishBinaryFile(char *topic, uint8_t *buf, size_t len, String fileExtension)
char * _ssidString
boolean delayFinished_WIFI_MQTTState()
void sendSpiffStatus()
boolean bluetoothOnline()
! should be a definition that the bluetooth is ONLINE
#define MAXglobalMQTTAttempts
boolean isSuperTopic()
helper to know it's a superuser topic (and not process in most cases).
void emptyLastMessageStatus()
empty the status message
char _fullMessageIn[MAX_MESSAGE]
message received on subscription
void processBarkletMessage(String message, String topic)
process an MQTT message looking for keywords (barklet language)
#define NOT_CONNECTED
void publishMQTTMessageDefaultTopic(char *message)
Wrapper of the mqttclient publish.
void printTopicType()
prints the topic on debug
boolean _delayCheckWIFIRunning_MQTTNetworking
true if still waiting for delayCheckWIFI to finish
char * _ssidPasswordString
void finishWIFI_Setup()
end of WIFI loop..
void checkAndReconnectWIFI_MQTTNetworking()
print a SPIFF timestamp..
char _fullMessageOut[MAX_MESSAGE]
message to send out
int _startTimestamp
uptime since last reboot.
void updatePreferencesInEPROM()
just update the EPROM, and send that to the WIFI_AP module as well
char * _jsonVersionString
boolean _setupMQTTNetworkingAlready
try a flag so setupMQTTnetworking only called 1 times..
char * _mqttPortString
void cleanEPROM_MQTTNetworking()
cleans the eprom info
char * wifiStatus_MQTT()
show the status in string form (from Library/Adruino... WiFiType.h)
void sendStatusMessageMQTT_deviceName(char *deviceName, const char *semanticMarker)
sends the semantic marker as a doc follow message #remoteMe (vs STATUS, as that triggers a status rep...
bool stringMatch(String message, String substring)
check if the string matches
void MQTTModule_readPreferences()
setup the WIFI
int _maxCounterLoop
char * _deviceNameString
void cleanSSID_EPROM_Method()
calls the method for cleaning the SSID eprom. This calls the WIFI_APModule callback
int _globalMQTTAttempts
String get_WIFIInfoString()
retrieve the WIFIInfoString
boolean isTrueString(String valCmdString)
whether the string is TRUE, ON, 1
void publishMQTTMessage(char *topic, char *message)
Wrapper of the mqttclient publish. NOTE: this might need to be in the loop as well,...
boolean skipMessageProcessing()
this is sent from the backend as a message {'guest':'guest password'} .. but lets' add to the credent...
void sendMessageNoChangeMQTT_Topic(char *message, char *topic)
just send a message but without any extras
void publishSPIFFFile_MQTT(char *topic, char *path, int len)
int _delayCheckWIFISeconds_MQTTNetworking
length of delay
String _topic
the topic the new message came in on..
void setupWIFI_loop()
the loop part of WIFI
void sendMessageMQTT(char *message)
char _lastDocFollowSemanticMarker[MAX_MESSAGE_DOCFOLLOW]
storage for last doc follow semantic marker
char * _mqttTopicString
char * _jsonLocationString
void checkDelaySinceWIFICheck_MQTTNetworking()
checks delay for the WIFI connectivity
boolean delayCheckWIFIFinished_MQTTNetworking()
if finished..
WiFiClient _espClient
The WIFI client.
#define STATUS
#define MAX_WIFI_CONNECT_ATTEMPTS
#define MAX_MQTT_ATTEMPTS
void setupMQTT(char *mqttServerString, char *mqttPortString, char *mqttPasswordString, char *mqttUserString, char *deviceNameString, char *uuidString)
setup the MQTT server
#define ESP_EPROM_NAME
9.27.23 to decode a base64 string (a Semantic Marker)
const char * getDynamicMessageFunc()
used by the displayModule to call this for each new status
float _WIFI_MQTTStateDelays[]
the delay in seconds for each state
boolean _newMQTTMessageArrived
void callPreSetupMQTT()
called to setup the MQTT (which is really the _mqttClient setup). Done on it's own thread....
boolean _MQTTRunning
String getJSONConfigString()
retrieve the Configuration JSON string in JSON format..
void setup_MQTTNetworking()
setup the MQTT part of networking
char * _jsonHeaderString
const char * _ntpServer
define here as well.. NOTE: this could be passed is as well... TODO
void performOTAUpdateMethod()
perform the OTA update. This calls the OTAImageUpdate methods (via preformOTAUpdateSimple())
WIFI_MQTTStates
state variables
@ waitingForWIFI
@ waitingForMQTT
@ connectedWIFI
@ disconnectedMQTT
@ preSetupMQTT
@ connectedMQTT
@ disconnectedWIFI
@ preSetupWIFI
void stopDelayCheckWIFI_MQTTNetworking()
stop the delay (not called)
void sendStatusMessageMQTT(const char *semanticMarker)
sends the semantic marker as a doc follow message #remoteMe (vs STATUS, as that triggers a status rep...
void stopDelay_WIFI_MQTTState()
char * shortVersion()
return a short version of VERSION
void getChipInfo()
create a unique ID (but it needs to be stored.. otherwise it's unique each time??
boolean isGroupTopic()
helper to know it's a superuser topic (and not process in most cases).
char * _mqttPasswordString
void loop_MQTTNetworking()
called for the loop() of this plugin
char * getLastDocFollowSemanticMarker_MQTTNetworking()
char * _mqttUserString
#define MAX_MESSAGE
char _shortVersion[30]
the short version
void classifyTopic(char *topic)
classify a topic
void setLastMessageStatus(char *token)
char * currentMessageStatusURL()
returns a string in in URL so: status?battery=84'&buzzon='off' } .. etc
int _countSinceLastChangedMessageStatus
a counter to erase the last message if not changed in N calls..
const char * getDynamicStatusFunc()
void setupWIFI(char *arg_ssid, char *arg_password)
setup the WIFI using ssid and password
char _chipName[100]
void printWIFIInfo()
print the WIFI info
void startDelay_WIFI_MQTTState()
void invokeCurrentSMModePage(char *topic)
send message to ourself to change to current specifed SM Mode
enum MQTTMessageTopicType _MQTTMessageTopicType
void cleanMQTTpasswordsUpdateInEPROM()
9.18.23 LA (after Eagle Rock bike ride, Van Morrison tomorrow)
WIFI_MQTTStates _WIFI_MQTTState
the state we are in..
TimerDelayClass * _timerDelayClass_WIFI_MQTTState
3.29.25 RaiiiinIeeeeR Beer movie
int _counterLoop
CONNECTION counters.
char _lastGroupTopic[100]
saves the group topic .. to write back on ..
void initAllArrayStorage()
Put all the storage initialization here..
#define REMOTE2
boolean processJSONMessageMQTT(char *ascii, char *topic)
process the JSON message (looking for FEED, etc). Note: topic can be nil, or if not,...
char * _uuidString
PubSubClient _mqttClient(_espClient)
The PubSub MQTT Client.
String get_WIFI_SSID()
3.22.24 get the WIFI SSID for the status
char * _mqttServerString
void sendMessageMQTT_Topic(char *message, char *topic)
for now only send if it start message starts with "#"
void sendDocFollowMessageMQTT(const char *semanticMarker)
sends the semantic marker as a doc follow message
unsigned long _delayCheckWIFIStart_MQTTNetworking
the time the delay started
#define MAX_MESSAGE_DOCFOLLOW
void restartDelayCheckWIFI_MQTTNetworking()
starts the delay for WIFI checking, called at startup, and each time the timer finished....
char _semanticMarkerString[MAX_MESSAGE]
Preferences _preferencesMQTTNetworking
8.16.25 MQTT
#define ACK_FEED2
void setLastDocFollowSemanticMarker_MQTTNetworking(char *semanticMarker)
sets the last DocFollow SemanticMarker
#define REMOTEME
#define ACK_FEED
String MQTT_urlDecode(String input)
Decode the URL (copied from WIFI_APModule. Easier than breaking modules)
boolean isDawgpackTopic()
helper to know it's a dawgpack topic (and not process in most cases). Only support DOCFOLLOW for now....
void sendMessageNoChangeMQTT(char *message)
just send a message but without any extras
void callbackMQTTHandler(char *topic, byte *payload, unsigned int length)
called when data on the MQTT socket
boolean isConnectedMQTT_MQTTState()
value of MQTT connected
void checkMQTTMessages_loop()
check for MQTT messages, called from the main loop()
int getDelayCheckWIFISeconds_MQTTNetworking()
get the delay values
char _lastMessageStatusURL[MAX_MESSAGE_DOCFOLLOW]
storage of the last message status
int getUptime()
returns seconds since first booted
MQTTMessageTopicType
break up the MQTT Handler 8.12.22 as per "My guess is that you have your data collection (from some I...
@ groupTopic
@ userTopic
@ superTopic
@ dawgpackTopic
char * getDeviceNameMQTT()
called for things like the advertisement
void performFeedMethod(char *topic)
calls the FEED message via the callback (which calls the BLE code)
boolean isConnectedWIFI_MQTTState()
value of WIFI connected
void restartWIFI_MQTTState()
restart the WIFI and then MQTT connection
#define CONNECTED
char * _mqttGuestPasswordString
#define _preferencesJSONName
Points to strings read from JSON (limited to 15 char key name)
void reconnectMQTT_loop()
String _fullJSONString
storage for the full JSON message string to send around..
void publishSMRunMessage(char *smrunMessage)
void initShortVersion()
init short version
#define MQTT_CALLBACK_TEMP
#define MQTT_CLEAN_SSID_EPROM
#define MQTT_CALLBACK_BLINK
#define MQTT_CALLBACK_FEED
8.16.25 MQTT
#define MQTT_CALLBACK_SOLID_LIGHT
void messageSend_mainModule(char *sendValue, boolean deviceNameSpecified)
TODO: have a callback regist approach.
Definition: MainModule.cpp:956
#define CALLBACKS_MQTT
8.16.25 MQTT
Definition: MainModule.cpp:789
void main_updateMQTTInfo(char *ssid, char *ssid_password, char *username, char *password, char *guestPassword, char *deviceName, char *host, char *port, char *locationString)
sets the WIFI and MQTT user/password. It's up to the code (below, maybe in future a register approach...
char * charSMMode_mainModule(int whichSMMode)
returns string form whichSMMode, sg "sm0", sm1 ...
char * main_getUsername()
void main_setScannedGroupName(char *groupName)
boolean connectedBLEDeviceIsGEN3_mainModule()
whether the connected is a GEN3 (so the name isn't valid)
char * semanticMarkerToJSON_mainModule(char *semanticMarker)
char * main_currentStatusURL(boolean fullStatus)
int minMenuModesMax_mainModule()
returns the current max of the MIN menu modes (using the setting of min or expanded) to determine
void main_setScannedDeviceName(char *deviceName)
set the scanned device name
void processClientCommandChar_mainModule(char cmd)
single character version of processClientCommand (since many used that already)
void setClockwiseMotorDirection_mainModule(boolean isClockwiseFlag)
8.18.24 setting this will check for the factory setting..
void main_credentialsUpdated()
moved here 4.25.22 (entirely from ESP_IOT.ino)
void restartAllMenuStates_mainModule()
restarts all the menu states to the first one .. useful for getting a clean start....
int whichSMMode_mainModule(char *cmd)
************** SM Mode Processing ***************
void main_dispatchAsyncCommandWithString(int asyncCallCommand, char *parameter)
boolean isEmptyString(char *stringA)
informs if null or empty string
void rebootDevice_mainModule()
void setConfiguration_mainModule(char *configurationName)
void buttonB_ShortPress_mainModule()
the short press of the side button
bool containsSubstring(String message, String substring)
check if the string contains the other string. This is a poor man's grammer checker
Definition: MainModule.cpp:765
void callCallbackMain(int callbacksModuleId, int callbackType, char *message)
performs the indirect callback based on the callbackType
Definition: MainModule.cpp:900
int getCurrentSMMode_mainModule()
returns the current SM Mode
char * main_currentStatusJSON()
status in JSON format, needs to return something as a ',' is already added before calling this....
void changeButtonColor_MainModule()
2.21.25 add a way to change the button color (if any)
int getFeederType_mainModule()
get the feeder type (Sepper 1,2,3 ...)
Definition: MainModule.cpp:730
void buttonA_LongPress_mainModule()
long press on buttonA (top button)
boolean startsWithChar(char *str, char c)
a char* version of startsWith (after skipping spaces)
void setCurrentSMMode_mainModule(int whichSMMode)
sets the current screen mode .. which can be used by Button and Display processing
char * getPairedDevice_mainModule()
returns if the paired device is not NONE
void setLUXThreshold_mainModule(int thresholdKind, int luxVal)
set the threshold val
void main_dispatchAsyncCommand(int asyncCallCommand)
checks if any async commands are in 'dispatch' mode, and if so, invokes them, and sets their flag to ...
char * getChipIdString()
3.17.24 get the chip id as a string
char * connectedBLEDeviceName_mainModule()
returns the connected BLE Device name (the :NAME of advertisment, Address: 01:39:3f:33 part of name,...
uint32_t getChipId()
3.17.24 get the chip id
int getTimeStamp_mainModule()
void buttonB_LongPress_mainModule()
the long press of the side button
char * createCopy(char *stringA)
void messageSetVal_mainModule(char *setName, char *valValue, boolean deviceNameSpecified)
Definition: MainModule.cpp:929
float getTemperature_mainModule()
retrieves the temperature .
void buttonA_ShortPress_mainModule()
boolean isValidPairedDevice_mainModule()
returns if the paired device is not NONE. Note, the paired Name might be an address now (see below)
char * main_nextJSONWIFICredential()
! cycle through the next WIFI saved credential
#define SM_home_simple
Definition: MainModule.h:367
#define SM_pair_dev
guest feed device
Definition: MainModule.h:391
#define THRESHOLD_KIND_DARK
Definition: MainModule.h:78
#define SM_guest_feed
guest feed
Definition: MainModule.h:389
#define SM_guest_page
guest page
Definition: MainModule.h:382
#define SM_timer
timer .. todo
Definition: MainModule.h:398
#define SM_home_simple_1
Definition: MainModule.h:368
#define SM_home_simple_2
Definition: MainModule.h:369
#define SM_status
//status
Definition: MainModule.h:378
#define ASYNC_SET_GATEWAY_ON
sets the GATEWAY mode on
Definition: MainModule.h:218
#define SM_reboot
REboot.
Definition: MainModule.h:400
#define SM_help
HELP.
Definition: MainModule.h:393
#define ASYNC_CALL_BUZZ_ON
sends a 'B' to the BLE end of the code (assuming a feeder is connected).
Definition: MainModule.h:209
#define ASYNC_POWEROFF
sets the GATEWAY mode off
Definition: MainModule.h:225
#define ASYNC_CALL_CLEAN_EPROM
cleans the EPROM totally, and reboots
Definition: MainModule.h:205
#define ASYNC_SEND_MQTT_STATUS_URL_MESSAGE
sends the status from the main module URL
Definition: MainModule.h:215
#define SM_home_simple_3
Definition: MainModule.h:370
#define ASYNC_SET_GATEWAY_OFF
sets the GATEWAY mode off
Definition: MainModule.h:220
#define ASYNC_CALL_OTA_FILE_UPDATE_PARAMETER
these are the async with a string parameter
Definition: MainModule.h:243
#define ASYNC_CALL_OTA_UPDATE
TODO: make this a registeration approach.
Definition: MainModule.h:201
#define SM_doc_follow
docfollow
Definition: MainModule.h:396
#define SM_smart_clicker_homepage
//! homepage
Definition: MainModule.h:376
#define TOPIC_TO_SEND
Definition: MainModule.h:65
#define SM_WIFI_ssid
WIFI ssid.
Definition: MainModule.h:380
#define SM_ap_mode
AP MODE.
Definition: MainModule.h:385
#define ASYNC_CALL_BUZZ_OFF
sends a 'b' to the BLE end of the code (assuming a feeder is connected).
Definition: MainModule.h:211
#define ASYNC_CLICK_SOUND
5.15.25 add a BUZZ command (or CLICK)
Definition: MainModule.h:236
void setTimerDelaySecondsMax_mainModule(int delaySeconds)
void invokePair_ModelController()
void setTimerDelaySeconds_mainModule(int delaySeconds)
void startStopTimer_mainModule(boolean startTimer)
void invokeUnpairNoName_ModelController()
void performOTAUpdateSimple()
retrieves from constant location
void performOTAUpdate(char *hostname, char *httpAddress)
8.16.25 MQTT
void savePreferenceInt_mainModule(int preferenceID, int val)
sets an int preference
void savePreferenceBoolean_mainModule(int preferenceID, boolean flag)
save a boolean preference
void savePreferenceATOMKind_MainModule(String value)
returned from mainModule
void appendPreference_mainModule(int preferenceID, String preferenceValue)
called to append to a a preference (which will be an identifier and a string, which can be converted ...
void setDiscoverM5PTClicker(boolean flag)
void setSensorsString_mainModule(char *sensorsString)
void resetAllPreferences_mainModule()
resets preferences.. Currently only reset all, but eventually reset(groups..)
boolean getPreferenceBoolean_mainModule(int preferenceID)
called to set a preference (which will be an identifier and a string, which can be converted to a num...
void storePreference_mainModule(int preferenceID, String preferenceValue)
called to append to a a preference (which will be an identifier and a string, which can be converted ...
void savePreferenceFloat_mainModule(int preferenceID, float val)
called to set a preference (which will be an identifier and a string, which can be converted to a num...
void savePreferenceIntFromString_mainModule(int preferenceID, char *val)
sets an int, but only if a valid integer, and no signs. If bad, then a 0 is stored
void requestChainSMARTButtons()
boolean topicInIncludeGroup(char *topic)
char * getPreference_mainModule(int preferenceID)
void setIncludeGroups(char *groups)
8.2.24 set the include group (and cache it), called from MQTT
char * getPreferenceString_mainModule(int preferenceID)
returns the preference but in it's own string buffer. As long as you use it before calling getPrefere...
void printPreferenceValues_mainModule()
print the preferences to SerialDebug
void savePreference_mainModule(int preferenceID, String preferenceValue)
called to set a preference (which will be an identifier and a string, which can be converted to a num...
#define PREFERENCE_USE_SPIFF_SETTING
8.22.22 to turn on/off SPIFF use (more below..)
#define PREFERENCE_PAIRED_DEVICE_ADDRESS_SETTING
the paired device for guest device feeding (6.6.22) .. but the Address 9.3.22
#define PREFERENCE_STEPPER_KIND_VALUE
uses STEPPER type
#define PREFERENCE_SENSOR_TILT_VALUE
Sensor preferences.
#define PREFERENCE_SUB_DAWGPACK_SETTING
8.17.22 to turn on/off subscribing to the dawgpack topic
#define PREFERENCE_SM_COMMAND_PIR_OFF_SETTING
1.11.24 The Semantic Marker command is sent on PIR, and the Command to send on OFF (or opposite)
#define PREFERENCE_SENSOR_PLUGS_SETTING
#define PREFERENCE_STEPPER_FACTORY_CLOCKWISE_MOTOR_DIRECTION_SETTING
#define PREFERENCE_BLE_SERVER_USE_DEVICE_NAME_SETTING
if set, the BLE Server (like PTFeeder) will tack on the device name (or none if not defined).
#define PREFERENCE_ONLY_GEN3_CONNECT_SETTING
if true, only BLEClient connect to GEN3 feeders..
#define PREFERENCE_SENDWIFI_WITH_BLE
sends the WIFI to all except current device if set
#define PREFERENCE_NO_BUTTON_CLICK_POWEROFF_SETTING
#define PREFERENCE_SUPPORT_GROUPS_SETTING
the preference for supporting GROUPS (default true)
#define PREFERENCE_SEMANTIC_MARKER_ZOOMED_VALUE
Display preferences (SemanticMarker etc) - boolean.
#define PREFERENCE_WIFI_CREDENTIAL_2_SETTING
#define PREFERENCE_STEPPER_RPM_SETTING
#define PREFERENCE_MAIN_BLE_SERVER_VALUE
#define PREFERENCE_PAIRED_DEVICE_SETTING
the paired device for guest device feeding (6.6.22)
#define PREFERENCE_STEPPER_BUZZER_VALUE
stepper preferences
#define PREFERENCE_DEV_ONLY_SM_SETTING
adding AP_DEBUG_MODE to let others know that DEBUG eprom is available. Turn this OFF for non dev
#define STEPPER_IS_TUMBLER
#define PREFERENCE_BLE_USE_DISCOVERED_PAIRED_DEVICE_SETTING
#define PREFERENCE_USE_DOC_FOLLOW_SETTING
for
#define PREFERENCE_ATOM_SOCKET_GLOBAL_ONOFF_SETTING
1.12.24 Whether the AtomSocket accepts global on/off messages
#define PREFERENCE_USE_SPIFF_MQTT_SETTING
#define PREFERENCE_DEBUG_INFO_SETTING
a place to put some kind of Last Will of what went wrong .. for now (> max tries)
#define STEPPER_IS_UNO
#define PREFERENCE_FIRST_TIME_FEATURE_SETTING
a firsttime feature flag (only 1 per build) 7.12.22 defaulting to TRUE
#define PREFERENCE_DISPLAY_SCREEN_TIMEOUT_VALUE
sets the timeout value
#define PREFERENCE_IS_MINIMAL_MENU_SETTING
sets the max temp for a poweroff
#define PREFERENCE_USE_SPIFF_QRATOM_SETTING
For MQTT writing to the QRATOM.
#define PREFERENCE_DEVICE_NAME_SETTING
the device name itself (6.6.22)
#define PREFERENCE_HIGH_TEMP_POWEROFF_VALUE
sets the max temp for a poweroff
#define PREFERENCE_GROUP_NAMES_SETTING
the preference setting group names to subscribe (but empty or # go to wildcard, this also supports wi...
#define PREFERENCE_STEPPER_ANGLE_FLOAT_SETTING
#define PREFERENCE_STEPPER_2FEED_SETTING
#define PREFERENCE_STEPPER_AUTO_MOTOR_DIRECTION_SETTING
#define PREFERENCE_MAIN_GATEWAY_VALUE
#define PREFERENCE_STEPPER_CLOCKWISE_MOTOR_DIRECTION_SETTING
#define PREFERENCE_MAIN_BLE_CLIENT_VALUE
#define PREFERENCE_SM_ON_PIR_SETTING
1.10.24 Flag on whether a Semantic Marker command is sent on PIR, and the Command to send
#define PREFERENCE_ATOM_KIND_SETTING
1.4.24 What kind of ATOM plug (set, M5AtomKind, val= {M5AtomSocket, M5AtomScanner}
#define PREFERENCE_SM_COMMAND_PIR_SETTING
1.10.24 The Semantic Marker command is sent on PIR, and the Command to send
#define PREFERENCE_SENSORS_SETTING
void println_SPIFFModule(char *string)
The SPIFF module is for storing messages that are retrievable later as it stores on a folder area of ...
void sendStrings_SPIFFModule(int numberOfLines)
sends SPIFF module strings over MQTT, starting at the number back specified. This will use the curren...
void printTimestamp_SPIFFModule()
prints a timestamp time: <time> :
void printFile_SPIFFModule()
prints the spiff file to the SerialDebug output
void deleteFiles_SPIFFModule()
delete the spiff files..
void println_SPIFFModule_JSON(char *attribute, char *value)
4.4.24 output a line in JSON format adding timestamp as well
void setup_SPIFFModule()
the setup for this module
void saveScreen_SPIFFModule()
save the screen to a file on the SPIFF
unsigned long millis()
Definition: TinyGPS.cpp:35
boolean queryMatchesName_mainModule(char *name)
An concrete class.
void startDelay(float delayAmountSeconds)
starts delay calculation
boolean delayFinished()
whether the currently delay is finished, false if not running at all
void stopDelay()
stops delay