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