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:"NULL");
1303
1304 //!save some reason we are in the AP mode
1306 appendPreference_mainModule(PREFERENCE_DEBUG_INFO_SETTING, arg_ssid?arg_ssid:"No SSID");
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);
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
2021
2022 //send to the Display .. but truncate
2023 //! 11.7.22 if it's an #actMe .. don't show
2025 }
2026#endif
2027 _newMQTTMessageArrived = false;
2028 }
2029 else
2030 {
2031 _newMQTTMessageArrived = false;
2032 //!call the MQTT infrastructure loop which does it's MQTT messaging
2033 _mqttClient.loop();
2034 }
2035}
2036
2037//!check if the string matches
2038bool stringMatch(String message, String substring)
2039{
2040 return strcmp(&message[0], &substring[0]) == 0;
2041}
2042
2043//!! should be a definition that the bluetooth is ONLINE
2045{
2046 return true;
2047}
2048
2049//!cleans the eprom info
2051{
2052 SerialDebug.println("cleanEPROM_MQTTNetworking");
2053 _preferencesMQTTNetworking.begin(ESP_EPROM_NAME, false); //readwrite..
2056}
2057
2058//! just send a message (let the internals to figure out topics, etc..
2059//!so the BLE can send something on the MQTT
2060//! for now only send if it start message starts with "#"
2061void sendMessageMQTT(char *message)
2062{
2064
2065#ifdef REFACTOR
2066 if (_MQTTRunning)
2067 {
2068 //Basically if we send {'cmd':'buzzon'} -- it comes back to us.. and infinite loop
2069 // for now only send if it start message starts with "#"
2070 if (containsSubstring(message, "#"))
2071 {
2072 sprintf(_fullMessageOut,"%s {%s}", message, _deviceNameString);
2073
2074 //publish this message..
2075// _mqttClient.publish(_mqttTopicString, _fullMessageOut);
2076// SerialTemp.printf("Sending message:%s %s\n",_mqttTopicString, _fullMessageOut);
2077#ifdef TRY_MORE_ASYNC_PROCESSING
2078 //publish back on topic
2080#else
2082#endif
2083 }
2084 }
2085#endif
2086}
2087
2088//! for now only send if it start message starts with "#"
2089void sendMessageMQTT_Topic(char *message, char *topic)
2090{
2091 if (_MQTTRunning)
2092 {
2093 //Basically if we send {'cmd':'buzzon'} -- it comes back to us.. and infinite loop
2094 // for now only send if it start message starts with "#"
2095 if (containsSubstring(message, "#"))
2096 {
2097 sprintf(_fullMessageOut,"%s {%s}", message, _deviceNameString);
2098
2099 //publish this message..
2100 // _mqttClient.publish(_mqttTopicString, _fullMessageOut);
2101 // SerialTemp.printf("Sending message:%s %s\n",_mqttTopicString, _fullMessageOut);
2102#ifdef TRY_MORE_ASYNC_PROCESSING
2103 //publish back on topic
2105#else
2106 _mqttClient.publish(topic, _fullMessageOut);
2107#endif
2108 }
2109 }
2110}
2111
2112//! just send a message but without any extras
2113void sendMessageNoChangeMQTT_Topic(char *message, char *topic)
2114{
2115 if (_MQTTRunning)
2116 {
2117 //Basically if we send {'cmd':'buzzon'} -- it comes back to us.. and infinite loop
2118 // for now only send if it start message starts with "#"
2119
2120 sprintf(_fullMessageOut,"%s", message);
2121
2122 //publish this message..
2123 // _mqttClient.publish(_mqttTopicString, _fullMessageOut);
2124 // SerialTemp.printf("Sending message:%s %s\n",_mqttTopicString, _fullMessageOut);
2125#ifdef TRY_MORE_ASYNC_PROCESSING
2126 //publish back on topic
2128#else
2129 _mqttClient.publish(topic, _fullMessageOut);
2130#endif
2131 }
2132}
2133
2134
2135//! just send a message but without any extras
2136void sendMessageNoChangeMQTT(char *message)
2137{
2139#ifdef REFACTORED
2140 if (_MQTTRunning)
2141 {
2142 //Basically if we send {'cmd':'buzzon'} -- it comes back to us.. and infinite loop
2143 // for now only send if it start message starts with "#"
2144
2145 sprintf(_fullMessageOut,"%s", message);
2146
2147 //publish this message..
2148// _mqttClient.publish(_mqttTopicString, _fullMessageOut);
2149// SerialTemp.printf("Sending message:%s %s\n",_mqttTopicString, _fullMessageOut);
2150#ifdef TRY_MORE_ASYNC_PROCESSING
2151 //publish back on topic
2153#else
2155#endif
2156 }
2157#endif
2158}
2159//! sends the semantic marker as a doc follow message #remoteMe (vs STATUS, as that triggers a status reply.. )
2160void sendStatusMessageMQTT_deviceName(char *deviceName, const char *semanticMarker)
2161{
2162 SerialTemp.println("sendStatusMessageMQTT..");
2163 //! don't call main_currentStatusURL .. since it was already called
2164 sprintf(_fullMessageOut, "#remoteMe {%s} {AVM=%s}", deviceName, semanticMarker);
2165 //sprintf(_fullMessageOut, "#remoteMe {%s} {AVM=%s%s}", deviceName, semanticMarker, main_currentStatusURL(false));
2166 if (_MQTTRunning)
2167 {
2168 // _mqttClient.publish(_mqttTopicString, _fullMessageOut);
2169 // SerialMin.printf("Sending message: %s\n", _fullMessageOut);
2170#ifdef TRY_MORE_ASYNC_PROCESSING
2171 //publish back on topic
2173#else
2175#endif
2176 }
2177}
2178
2179//! sends the semantic marker as a doc follow message #remoteMe (vs STATUS, as that triggers a status reply.. )
2180void sendStatusMessageMQTT(const char *semanticMarker)
2181{
2183}
2184//! sends the semantic marker as a doc follow message
2185void sendDocFollowMessageMQTT(const char *semanticMarker)
2186{
2187 SerialCall.println("sendDocFollowMessageMQTT..");
2188 if (!containsSubstring(semanticMarker,"https"))
2189 sprintf(_fullMessageOut, "#DOCFOLLOW {%s} {AVM=https://SemanticMarker.org/bot/%s}", _deviceNameString, semanticMarker);
2190 else
2191#ifdef ESP_M5_ATOM_LITE
2192 //! using the followme syntax for now..
2193 sprintf(_fullMessageOut, "#followMe {AVM=%s}", semanticMarker);
2194
2195#else
2196 sprintf(_fullMessageOut, "#DOCFOLLOW {%s} {AVM=%s}", _deviceNameString, semanticMarker);
2197#endif
2198 if (_MQTTRunning)
2199 {
2200// _mqttClient.publish(_mqttTopicString, _fullMessageOut);
2201// SerialMin.printf("Sending message: %s\n", _fullMessageOut);
2202#ifdef TRY_MORE_ASYNC_PROCESSING
2203 //publish back on topic
2205#else
2207#endif
2208 }
2209}
2210
2211//!process an MQTT message looking for keywords (this version uses the Barklet Language Grammer @c 2014)
2212//!NOTE: The processJSONMessage() is part of this (called if straight JSON).
2213//!TODO: merge these two methods..
2214void processBarkletMessage(String message, String topic)
2215{
2216 //!https://stackoverflow.com/questions/7352099/stdstring-to-char
2217 int time = getTimeStamp_mainModule();
2218
2219 //!convert String to char *
2220 char *messageString = &message[0];
2221 //!flag to send the message back on MQTT
2222 bool messageValidToSendBack = false;
2223 SerialCall.print("processBarkletMessage: ");
2224 SerialCall.print(message);
2225 SerialCall.print(" topic=");
2226 SerialCall.println(topic);
2227
2228 if (!topic)
2230
2231 //!debug printout..
2232 //printTopicType();
2233
2234 //!new 4.12.22 if this is straight JSON .. then sent to the processJSONmessage
2235 if (processJSONMessageMQTT(messageString, topic?&topic[0]:NULL))
2236 {
2237 //This was processed by the JSON processor
2238 //SerialDebug.println("** not an older Barklet message syntax, but straight JSON ***");
2239 return;
2240 }
2241
2242 //!If the dawgpack, only process the DOCFOLLOW message
2243 //!
2244 //!note: these messages are sent to MQTT. But the messages comming down originated on WebSocket barklets language
2245 //! so the 'remoteMe ..." gets up there, but not back to the rest. It's rewritten by nodered.
2246 if (containsSubstring(message, STATUS) && !isDawgpackTopic())
2247 {
2248 float temp = getTemperature_mainModule();
2249
2250 //!save some part of this message for later display by SemanticMarker 8.4.22
2251 //!set the status
2252 setLastMessageStatus((char*)"status");
2253
2254 char pairedDevice[100];
2256 {
2257 strcpy(pairedDevice,getPairedDevice_mainModule());
2258// strcat(pairedDevice,(char*)":");
2259// strcat(pairedDevice,getPairedDeviceAddress_mainModule());
2260 }
2261 else
2262 strcpy(pairedDevice,"none");
2263 //! 8.16.25 BLE CLIENT
2264 boolean isConnectedBLE = isConnectedBLEClient();
2265
2267 //! process the pair if match
2268 if (isConnectedBLE && isGateway)
2269 {
2270 //! FOR NOW , copy the code and create a _fullMessageOut that is for the Paired device...
2271
2272 sprintf(_fullMessageOut, "%s {%s} {%s} {I,F} {'T':'%d','dev':'%s','user':'%s','location':'%s','v':'%s','ble':'%s,%s}",
2273 REMOTEME,
2274 pairedDevice,
2276 time,
2277 pairedDevice,
2280 shortVersion(),
2281 //! 8.16.25 BLE SERVER
2282 //! retrieve the service name (PTFEEDER, PTFeeder:Name, PTClicker:Name, etc)
2284
2285 // if calling this.. add "%s" to sprintf above..
2287 );
2288
2289 //publish this message..
2290 SerialTemp.printf("GEN3: Sending message: %s\n", _fullMessageOut);
2291
2292 //_mqttClient.publish(_mqttTopicString, _fullMessageOut);
2293#ifdef TRY_MORE_ASYNC_PROCESSING
2294 //publish back on topic
2296#else
2298#endif
2299 //! 5.21.22 WORKS!!
2300 //!topic is the topic we can in on.. so could be super user..
2301 //if (strcmp(&topic[0],"usersP/bark")==0)
2302 if (isSuperTopic())
2303 {
2304 SerialTemp.println("Sending on DawgPack too..");
2305 //publish back on topic
2306 //_mqttClient.publish("usersP/dawgpack", _fullMessageOut);
2307#ifdef TRY_MORE_ASYNC_PROCESSING
2308 //publish back on topic
2309 publishMQTTMessage((char*)"usersP/dawgpack", _fullMessageOut);
2310#else
2311 _mqttClient.publish("usersP/dawgpack", _fullMessageOut);
2312#endif
2313 }
2314 }
2315
2316
2317 //Version-(3.7)-3.22.24-ESP_M5_ATOM_QR_SCAN_SOCKET_SMART_GROUP_CHIPID_SSID'
2318 // Need short version: "(3.7)-3.22.24"
2319 //sprintf(_fullMessageOut, "%s {%s} {%s} {I,F} {T=now}", REMOTEME, _deviceNameString, bluetoothOnline() ? CONNECTED : NOT_CONNECTED);
2320 // Once connected, publish an announcement...
2321 // sprintf(message, "#STATUS {%s} {%s}", _deviceNameString, chipName);
2322#ifdef ESP_M5
2323 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",
2324#else
2325 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'}",
2326#endif
2327 REMOTEME,
2330 time,
2334 //! 8.16.25 BLE SERVER
2335 //! retrieve the service name (PTFEEDER, PTFeeder:Name, PTClicker:Name, etc)
2337
2338
2339 ,shortVersion()
2340 //k='uno':'tblr"
2341 ,(getFeederType_mainModule() == STEPPER_IS_UNO)?(char*)"uno":(char*)"tblr"
2342
2343 //! 'chipid':'%s'
2345 //! 'ssid':'%s'
2346 ,get_WIFI_SSID()
2347
2348#ifdef ESP_M5
2349 //! last %s
2351 );
2352 //! OOPS .. the getPreference overrides the values .. remember!! so this needs to be a strcat version....
2353 //! add the sensorPlugs
2354 //! 'splug':'%s'
2355 strcat(_fullMessageOut,",'splug':'");
2357 strcat(_fullMessageOut,"'");
2358
2359 //! 8.10.25 add the Stepper Angle Kind
2360 //! #393
2361 //! 'sa':'%s
2362 strcat(_fullMessageOut,",'sa':'");
2364 strcat(_fullMessageOut,"'");
2365
2366 //! 5.21.25 add the Atom Kind and the Sensors
2367 //! 'atom':'%s
2368 strcat(_fullMessageOut,",'atom':'");
2370 strcat(_fullMessageOut,"'");
2371 //!sensors':'%s'
2372 strcat(_fullMessageOut,",'sensors':'");
2374 strcat(_fullMessageOut,"'");
2375// /'splug':'%s','atom':'%s','sensors':'%s',
2376 //! last is the dynamic main_currentStatusJSON()
2377 //! finish
2378 strcat(_fullMessageOut,"}");
2379#else
2380 );
2381#endif
2382
2383
2384 messageValidToSendBack = true;
2385
2387
2388 //On demand #STATUS send the statusURL as well (if an M5)
2389 //this queues the sending of the StatusURL over MQTT.
2390 // This is async (next loop) since sending 2 MQTT messages can be hard to do in a row ..
2392
2393 //! send SPIFF status
2394 //! 4.4.24
2396 }
2397 // else if (containsSubstring(message, "#FEED") || containsSubstring(message, "feedme"))
2398 //only use #FEED (the feedme will turn into #FEED)
2399 else if (containsSubstring(message, "#FEED") && !isDawgpackTopic())
2400 {
2401 //! flag for whether feed will occur. it won't if a device is specified and it's not our device (unless super topic)
2402 boolean performFeed = true;
2403#ifdef ESP_M5_CAMERA
2404 performFeed = false;
2405#endif
2406 //!check against the super feeder. If super feeder, then feed all devices, otherwise logic below
2407 if (!isSuperTopic())
2408 //if (!stringMatch(topic, "/usersP/bark") && !stringMatch(topic, "/usersP/dawgpack"))
2409 {
2410 //only check this if not the super feed topic "/usersP/bark" ..
2411 //TODO: not make this hardwired to /usersP/bark
2412 //TODO: 2.2.22
2413 //try 2.19.22 (but simple version..)
2414 //TODO: 7.23.22 .. look if the paired device too..
2415 if (containsSubstring(message, "deviceName"))
2416 {
2417 //since deviceName specified, then only feed if our device is specified..
2419 {
2420 // this could mean a "deviceName" was found, and our _deviceNameString was there.,
2421 // versus actually parsing for "deviceName":ourName
2422 performFeed = true;
2423 }
2425 {
2426 //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
2428 {
2429 SerialTemp.println(" *** Feeding via our gateway ***");
2430 performFeed = true;
2431 }
2432 else
2433 {
2434 SerialDebug.println(" ** Not feeding as not our paired device either ***");
2435 performFeed = false;
2436 }
2437
2438 }
2439 else
2440 {
2441 //perform feed... (knowing the message device name requires pqrsing .. so not for now since containsSubstring() suffices..
2442 SerialDebug.printf("**NOT Perform FEED as deviceName doesn't ours: %s\n", _deviceNameString );
2443
2444 performFeed = false;
2445 }
2446 }
2447 }
2448
2449 //if performFeed set, then continue..
2450 if (performFeed)
2451 {
2452 //!perform the feed
2453 performFeedMethod(&topic[0]);
2454
2455 //!message already sent ...
2456 messageValidToSendBack = false;
2457
2458 }
2459 }
2460#ifdef ESP_M5
2461 //!DOCFOLLOW .. support Dawgpack
2462 else if (containsSubstring(message, "#followMe") || containsSubstring(message,"#DOCFOLLOW"))
2463 {
2464 //! retrieves the last DocFollow SemanticMarker (from the message #DOCFOLLOW | #followMe {AVM=<SM>}
2465 //! need to parse to the AVM= grab the <SM> up to the "}"
2466 //!
2467 if (containsSubstring(message,"AVM="))
2468 {
2469 char *indexOfEqual = index(&message[0],'=');
2470 if (strlen(indexOfEqual)>2)
2471 //move past the =
2472 indexOfEqual++;
2474 // loop until the } is found
2475 while (*indexOfEqual && *indexOfEqual !='}')
2476 {
2477 //copy a character at a time until the } (or nill)
2478 strncat(_lastDocFollowSemanticMarker, indexOfEqual,1);
2479 indexOfEqual++;
2480 }
2481 strcat(_lastDocFollowSemanticMarker, "\0");
2482
2483 SerialDebug.printf("SemanticMarker: %s\n", _lastDocFollowSemanticMarker);
2484 //setLastDocFollowSemanticMarker(_lastDocFollowSemanticMarker);
2485
2486 //!parse the #followMe {AVM=<url>}
2487 sprintf(_fullMessageOut,"#ACK {%s} {doc_follow=%s}", _deviceNameString, _lastDocFollowSemanticMarker);
2488#ifdef ESP_M5
2489
2490 //! 3.23.25 parse into JSON
2491 //! Then internall process this message (only for this device)
2493 if (strlen(JSON_String) > 0)
2494 {
2495 //! now process this as JSON,
2496 char * my_argument = const_cast<char*> (topic.c_str());
2497 processJSONMessageMQTT(JSON_String, my_argument);
2498 }
2499#endif
2500 }
2501 else
2502 {
2503 sprintf(_fullMessageOut,"#ACK {%s} {bad_doc_follow syntax}", _deviceNameString);
2504
2505 }
2506 messageValidToSendBack = true;
2507 }
2508#ifdef PASS_ONTO_PLUGS
2509 //!note: this might be candidate for wider use
2510 else if (containsSubstring(message, "#CAPTURE") && !isDawgpackTopic())
2511 {
2512#ifdef ESP_M5_CAMERA_not_here
2513 // sprintf(_fullMessageOut, "#TAKING_PIC {%s} {real soon to be implemented 8.11.22}", _deviceNameString);
2514 takePicture_MainModule();
2515
2516#else
2517#ifdef M5_CAPTURE_SCREEN
2519 //sprintf(_fullMessageOut, "#M5_SCREEN {%s} {capturing screen as bmp}", _deviceNameString);
2520#else
2521 //sprintf(_fullMessageOut, "#NO_CAN_CAMERA_CAPTURE {%s} {I am just a chip without a camera}", _deviceNameString);
2522#endif // M5_CAPTURE_SCREEN
2523#endif //ESP_M5_CAMERA
2524 messageValidToSendBack = false;
2525 }
2526#endif //pass onto plugs
2527
2528#endif // ESP_M5
2529 else if (containsSubstring(message, "#TEMP") && !isDawgpackTopic())
2530 {
2531#ifdef ESP_M5
2532 float temp = getTemperature_mainModule();
2533 //SYNTAX should evolve .. backward compatable ..
2534 sprintf(_fullMessageOut,"#ACK {%s} {TEMP} %2.0f F {'temp':'%2.0f'}", _deviceNameString, temp, temp);
2535#else
2536 sprintf(_fullMessageOut, "#NO_CAN_GET_TEMP {%s} {I am just a chip without a temp sensor}", _deviceNameString);
2537#endif
2538 //call the callback specified from the caller (eg. NimBLE_PetTutor_Server .. or others)
2540
2541 messageValidToSendBack = true;
2542 }
2543 //!3.25.22 -- trying the CLEAN the ePROM SSID
2544 else if (containsSubstring(message, "#CLEAN_SSID_EPROM") && !isDawgpackTopic() && !isGroupTopic())
2545 {
2546 //! call the callback for cleaning the SSID eprom..
2547 callCallbackMain(CALLBACKS_MQTT, MQTT_CLEAN_SSID_EPROM, (char*)"cleanSSID_EPROM");
2548
2549 }
2550 //!3.8.22 -- trying the OTA. IT WORKS!!!
2551 //!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"
2552 else if (containsSubstring(message, "#OTA") && !isDawgpackTopic() && !isGroupTopic())
2553 {
2554 boolean performOTAUpdate = true;
2555
2556 //syntax: #OTA {v:VERSION}, or {k:ESP_32 or ESP_M5
2557 if (containsSubstring(message, "{v:"))
2558 {
2559 //does the installed "VERSION" == the string passed in eg. {v:OUR_VERSION} VERSION=OUR_VERSION
2560 // performOTAUpdate = containsSubstring(message, VERSION);
2561 performOTAUpdate = containsSubstring(message, VERSION);
2562
2563 SerialDebug.printf("#OTA version correct: %d\n", performOTAUpdate);
2564 }
2565 else if (containsSubstring(message, "{k:") && !isDawgpackTopic())
2566 {
2567 //does the installed "KIND" == the string passed in eg. {v:ESP_32} we are one or the other..
2568#ifdef ESP_M5
2569 performOTAUpdate = containsSubstring(message, "ESP_M5");
2570 SerialDebug.printf("#OTA match ESP_M5: %d\n", performOTAUpdate);
2571
2572#else
2573 performOTAUpdate = containsSubstring(message, "ESP_32");
2574 SerialDebug.printf("#OTA match ESP_32: %d\n", performOTAUpdate);
2575
2576#endif
2577
2578 }
2579
2580 //parse out the {kind, host, binfile}
2581 //SOON .. this might be a triple click?? or keep the messaging?
2582
2583 if (performOTAUpdate)
2584 {
2585 //NOTE: cannot put #OTA in message or it infinite loops..
2586 sprintf(_fullMessageOut, "over the air binary image update from version: %s", VERSION);
2587 //let clients know what's happening..
2589 SerialLots.printf("Sending message: %s\n", _fullMessageOut);
2590 //blink the light
2592
2593 //! dispatches a call to the command specified. This is run on the next loop()
2595 }
2596 else
2597 {
2598 sprintf(_fullMessageOut, "over the air NOT updating as not matching string: %s",
2599#ifdef ESP_M5
2600 "ESP_M5"
2601#else
2602 "ESP_32"
2603#endif
2604 );
2605 SerialLots.printf("Sending message: %s\n", _fullMessageOut);
2607
2608 }
2609
2610 } //#OTA
2611 else if (isDawgpackTopic())
2612 {
2613 SerialDebug.println("DAWGPACK unsupported message");
2614 }
2615
2616 if (messageValidToSendBack)
2617 {
2618 //publish this message..
2619// _mqttClient.publish(_mqttTopicString, _fullMessageOut);
2620 SerialLots.printf("1.Sending message: %s\n", _fullMessageOut);
2621#ifdef TRY_MORE_ASYNC_PROCESSING
2622 //publish back on topic
2624#else
2626#endif
2627
2628 //! 5.21.22 WORKS!!
2629 //!topic is the topic we can in on.. so could be super user..
2630 //if (strcmp(&topic[0],"usersP/bark")==0)
2631 if (isSuperTopic() || isDawgpackTopic())
2632 {
2633 SerialTemp.println("2.Sending on DawgPack too..");
2634 //publish back on topic
2635 // _mqttClient.publish("usersP/dawgpack", _fullMessageOut);
2636#ifdef TRY_MORE_ASYNC_PROCESSING
2637 //publish back on topic
2638 publishMQTTMessage((char*)"usersP/dawgpack", _fullMessageOut);
2639#else
2640 _mqttClient.publish("usersP/dawgpack", _fullMessageOut);
2641#endif
2642 }
2643
2644 //! 7.15.23 anniversery of 1799 finding Rosetta Stone in Egypt
2645 if (isGroupTopic())
2646 {
2647 SerialTemp.printf("3.Sending on %s too..\n", _lastGroupTopic);
2648#ifdef TRY_MORE_ASYNC_PROCESSING
2649 //publish back on topic
2651#else
2653#endif
2654 }
2655 }
2656}
2657
2658
2659//! *********************** METHODS invoked from BLE (JSON) and MQTT messages ***************
2660
2661//!perform the OTA update. This calls the OTAImageUpdate methods (via preformOTAUpdateSimple())
2663{
2664 //NOTE: cannot put #OTA in message or it infinite loops..
2665 sprintf(_fullMessageOut, "over the air binary image update, replacing our version: %s", VERSION);
2666 //let clients know what's happening..
2667 // _mqttClient.publish(_mqttTopicString, _fullMessageOut);
2668 SerialDebug.printf("%s\n", _fullMessageOut);
2669 //blink the light
2671 //#define REALLY_DO_IT_BOMBS
2672#ifdef REALLY_DO_IT_BOMBS
2673 //NOTE: this sync call doesn't work..
2674 //printf(" *** Bad syntax, no { } \n");
2676 //this reboots .. so the code below never runs anyway.. will work on it..
2677#else
2678 // setAsyncCallOTAUpdate(true);
2679 //! dispatches a call to the command specified. This is run on the next loop()
2681#endif
2682}
2683
2684//!calls the method for cleaning the SSID eprom. This calls the WIFI_APModule callback
2686{
2687 //! call the callback for cleaning the SSID eprom..
2688 callCallbackMain(CALLBACKS_MQTT, MQTT_CLEAN_SSID_EPROM, (char*)"cleanSSID_EPROM");
2689}
2690
2691//! //!calls the FEED message via the callback (which calls the BLE code)
2692//!NOTE: this will send a BLE command if connected via the GATEWAY to a GEN3 (or other gateway in the future)
2693//!NOTE: This sends the _full message on the topic ..
2694void performFeedMethod(char *topic)
2695{
2696 //!get the temperature
2697 float temp = getTemperature_mainModule();
2698
2699 //!get the connected status
2700 //!save some part of this message for later display by SemanticMarker 8.4.22
2701 //!set the feed
2702 setLastMessageStatus((char*)"feed");
2703
2704 //perform feed...
2705 SerialDebug.println("Perform FEED internally, calling callbackFunction.. 2");
2706 //call the callback specified from the caller (eg. NimBLE_PetTutor_Server .. or others)
2707 // (*_callbackFunction)(rxValue);
2709
2710 //! 2.21.25 add a way to change the button color (if any)
2712
2713 //ASYNC_SEND_MQTT_FEED_MESSAGE
2714 //On demand #STATUS send the statusURL as well (if an M5)
2715 //this queues the sending of the StatusURL over MQTT.
2716 // This is async (next loop) since sending 2 MQTT messages can be hard to do in a row ..
2717 //main_dispatchAsyncCommand(ASYNC_SEND_MQTT_FEED_MESSAGE);
2718
2719 //SerialTemp.println(" ** returned from ASYNC_SEND_MQTT_FEED_MESSAGE ***");
2720#define ACK_FOR_PAIR_TOO
2721 char pairedDevice[100];
2723 strcpy(pairedDevice,getPairedDevice_mainModule());
2724 else
2725 strcpy(pairedDevice,"none");
2726
2727 //! 8.16.25 BLE CLIENT
2728 boolean isConnectedBLE = isConnectedBLEClient();
2729
2731
2732 //! 7.20.25
2733 //!https://stackoverflow.com/questions/7352099/stdstring-to-char
2734 int time = getTimeStamp_mainModule();
2735
2736 if (isConnectedBLE && isGateway)
2737 {
2738 //! FOR NOW , copy the code and create a _fullMessageOut that is for the Paired device...
2739 SerialTemp.print("PairedDevice: ");
2740 SerialTemp.println(pairedDevice);
2741 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");
2742
2743 //publish this message..
2744// _mqttClient.publish(_mqttTopicString, _fullMessageOut);
2745// SerialTemp.printf("ACK: Sending message: %s\n", _fullMessageOut);
2746#ifdef TRY_MORE_ASYNC_PROCESSING
2747 //publish back on topic
2749#else
2751#endif
2752 //! 5.21.22 WORKS!!
2753 //!topic is the topic we can in on.. so could be super user..
2754 // if (strcmp(&topic[0],"usersP/bark")==0)
2755 if (isSuperTopic() || isDawgpackTopic())
2756 {
2757// SerialLots.println("Sending on DawgPack too..");
2758// //publish back on topic
2759// _mqttClient.publish("usersP/dawgpack", _fullMessageOut);
2760#ifdef TRY_MORE_ASYNC_PROCESSING
2761 //publish back on topic
2762 publishMQTTMessage((char*)"usersP/dawgpack", _fullMessageOut);
2763#else
2764 _mqttClient.publish("usersP/dawgpack", _fullMessageOut);
2765#endif
2766 }
2767
2768 //! 7.15.23 anniversery of 1799 finding Rosetta Stone in Egypt
2769 if (isGroupTopic())
2770 {
2771 SerialTemp.printf("3.Sending on %s too..\n", _lastGroupTopic);
2772#ifdef TRY_MORE_ASYNC_PROCESSING
2773 //publish back on topic
2775#else
2777#endif
2778 }
2779
2780 }
2781 //! output the main #actMe message .. but it get's nothing from the plugins - like ATOM status
2782 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());
2783
2784 // send the FEED to the display (if any)
2786
2787#define TRY_MORE_URL
2788#ifdef TRY_MORE_URL
2789 char *moreStatus = main_currentStatusJSON();
2790 if (moreStatus && strlen(moreStatus) > 0)
2791 {
2792 strcat(_fullMessageOut, (char*)",");
2793
2794 //Make URL for the status..
2795 strcat(_fullMessageOut, moreStatus);
2796 }
2797
2798#endif
2799 //! close the JSON message
2800 strcat(_fullMessageOut, (char*)"}");
2801
2802 //if (messageValidToSendBack)
2803 if (true)
2804 {
2805 //publish this message..
2806// _mqttClient.publish(_mqttTopicString, _fullMessageOut);
2807// SerialDebug.printf("Sending message: %s\n", _fullMessageOut);
2808#ifdef TRY_MORE_ASYNC_PROCESSING
2809 //publish back on topic
2811#else
2813#endif
2814 //! 5.21.22 WORKS!!
2815 //!topic is the topic we can in on.. so could be super user..
2816 // if (strcmp(&topic[0],"usersP/bark")==0)
2817 if (isSuperTopic() || isDawgpackTopic())
2818
2819 {
2820// SerialTemp.println("Sending on DawgPack too..");
2821// //publish back on topic
2822// _mqttClient.publish("usersP/dawgpack", _fullMessageOut);
2823#ifdef TRY_MORE_ASYNC_PROCESSING
2824 //publish back on topic
2825 publishMQTTMessage((char*)"usersP/dawgpack", _fullMessageOut);
2826#else
2827 _mqttClient.publish("usersP/dawgpack", _fullMessageOut);
2828#endif
2829 }
2830
2831 //! 7.15.23 anniversery of 1799 finding Rosetta Stone in Egypt
2832 if (isGroupTopic())
2833 {
2834 SerialTemp.printf("3.Sending on %s too..\n", _lastGroupTopic);
2835#ifdef TRY_MORE_ASYNC_PROCESSING
2836 //publish back on topic
2838#else
2840#endif
2841 }
2842 }
2843}
2844
2845
2846//! *********************** END METHODS invoked from BLE (JSON) and MQTT messages ***************
2847
2848
2849//!This is in case corruption when changing what's written.. defining BOOTSTRAP will clean up the EPROM
2850
2851//!read the eprom..
2853{
2854 SerialDebug.println("MQTT.readPreferences");
2855 //#define BOOTSTRAP
2856#ifdef BOOTSTRAP
2857 //note: this could be a 'rebootstrap' message via MQTT .. in the future..
2858 {
2859 SerialDebug.println("BOOTSTRAP device with our own WIFI and MQTT");
2860
2861 char* BOOT_mqtt_server = (char*)"iDogWatch.com";
2862
2863 //example with "test" as the user name. Change, ssid, user, pass, device name and topic
2864 char* BOOT_mqtt_port = (char*)"1883";
2865 char* BOOT_ssid = (char*)"SunnyWhiteriver";
2866 char* BOOT_ssid_password = (char*)"sunny2021";
2867 char *BOOT_mqtt_user = (char*)"test";
2868 char *BOOT_mqtt_password = (char*)"test";
2869 char *BOOT_mqtt_guestPassword = (char*)"test";
2870
2871 //new 2.2.22 (last time this century..)
2872 //change over to new MQTT Namespace: usersP/bark
2873 char *BOOT_mqtt_topic = (char*)"usersP/bark/test";
2874
2875 char *BOOT_deviceName = (char*)"name-of-feeder";
2876 char *BOOT_uuidString = (char*)"unused";
2877 char *BOOT_jsonHeaderString = (char*)"WIFI+MQTT";
2878 char *BOOT_jsonVersionString = (char*)"BOOTSTRAP 1.3";
2879 char *BOOT_jsonLocationString = (char*)"PetLand"; //enter something is you like (Seattle, WA)
2880
2881 ///note: these createCopy are to get between String and char* .. probably a better way like &BOOT[0] or something..
2882 _ssidString = createCopy(BOOT_ssid);
2883
2884 _ssidPasswordString = createCopy(BOOT_ssid_password);
2885
2886 _mqttServerString = createCopy(BOOT_mqtt_server);
2887 _mqttPortString = createCopy(BOOT_mqtt_port);
2888 _mqttPasswordString = createCopy(BOOT_mqtt_password);
2889 _mqttGuestPasswordString = createCopy(BOOT_mqtt_guestPassword);
2890 _mqttUserString = createCopy(BOOT_mqtt_user);
2891 _mqttTopicString = createCopy(BOOT_mqtt_topic);
2892 _deviceNameString = createCopy(BOOT_deviceName);
2893 _uuidString = createCopy(BOOT_uuidString);
2894 _jsonHeaderString = createCopy(BOOT_jsonHeaderString);
2895 _jsonVersionString = createCopy(BOOT_jsonVersionString);
2896 _jsonLocationString = createCopy(BOOT_jsonLocationString);
2897
2898 DynamicJsonDocument myObject(1024);
2899
2900 myObject["ssid"] = BOOT_ssid;
2901 myObject["ssidPassword"] = BOOT_ssid_password;
2902 myObject["mqtt_server"] = BOOT_mqtt_server;
2903 myObject["mqtt_port"] = BOOT_mqtt_port;
2904 myObject["mqtt_password"] = BOOT_mqtt_password;
2905 myObject["mqtt_guestPassword"] = BOOT_mqtt_guestPassword;
2906
2907 myObject["mqtt_user"] = BOOT_mqtt_user;
2908 myObject["mqtt_topic"] = BOOT_mqtt_topic;
2909 myObject["deviceName"] = BOOT_deviceName;
2910 myObject["uuid"] = BOOT_uuidString;
2911 myObject["jsonHeader"] = BOOT_jsonHeaderString;
2912 myObject["jsonVersion"] = BOOT_jsonVersionString;
2913 myObject["location"] = BOOT_jsonLocationString;
2914
2915 //open the preferences
2916
2917 _preferencesMQTTNetworking.begin(ESP_EPROM_NAME, false); //readwrite..
2919 //output our object.. myObject has a string version..
2920 SerialDebug.print("Writing EPROM JSON = ");
2921 //JSON
2922 String output1;
2923 serializeJson(myObject, output1);
2924 SerialDebug.println(output1);
2926
2927 // Close the Preferences
2929
2930 //new 2.21.22 (On bootstrap, it's nil..?? .. maybe the myObject isn't a string??
2931 //TRY: reading back..
2932 _preferencesMQTTNetworking.begin(ESP_EPROM_NAME, false); //false=read/write..
2934 SerialDebug.print("Reading.3 EPROM JSON = ");
2935 SerialDebug.println(_fullJSONString);
2936
2937 //check ... _fullMessageOut
2938 // Close the Preferences
2940
2941 //end new
2942 }
2943 return;
2944#endif //BOOTSTRAP
2945
2946#ifdef BOOTSTRAP_AP_MODE_STARTUP
2947 SerialDebug.println("*** STARTUP in AP MODE ***");
2948 _ssidString = NULL;
2949 _ssidPasswordString = NULL;
2950 return;
2951#endif
2952 //https://randomnerdtutorials.com/esp32-save-data-permanently-preferences/
2953 //https://github.com/espressif/arduino-esp32/blob/master/libraries/Preferences/src/Preferences.cpp
2954 // Open Preferences with my-app namespace. Each application module, library, etc
2955 // has to use a namespace name to prevent key name collisions. We will open storage in
2956 // RW-mode (second parameter has to be false).
2957 // Note: Namespace name is limited to 15 chars.
2958 _preferencesMQTTNetworking.begin(ESP_EPROM_NAME, false); //false=read/write..
2960 SerialDebug.print("Reading.1 EPROM JSON = ");
2961 SerialDebug.println(_fullJSONString);
2962
2963 //check ... _fullMessageOut
2964 // Close the Preferences
2966
2967 //3.29.22: ISSUE. the eprom wasn't written, but we can in from the CREDENTIALS...
2968
2969 //first time there won't be any eprom info.. THIS is a bug without this code update
2970 if (!_fullJSONString || _fullJSONString.length() == 0)
2971 {
2972 SerialDebug.println("*** no JSON in preferences, probably first time. use Bootstrap, or BLE update ***");
2973 _ssidString = NULL;
2974 _ssidPasswordString = NULL;
2975 return;
2976 }
2977
2978 DynamicJsonDocument myObject(1024);
2979 //StaticJsonDocument myObject(1024);
2980 deserializeJson(myObject, _fullJSONString);
2981 SerialDebug.print("JSON parsed.1 = ");
2982 String output1;
2983 serializeJson(myObject, output1);
2984 SerialDebug.println(output1);
2985
2986#ifdef NOT_ORIGINAL
2987 //defaults: 9.19.23 is already set don't override..
2989 _deviceNameString = (char*)"Unnamed";
2990#else
2991 //defaults:
2992 _deviceNameString = (char*)"Unnamed";
2993#endif
2994 //parse
2995 const char* a1 = myObject["ssid"];
2996#ifdef NOT_ORIGINAL
2997 if (a1 && strlen(a1)>0) /// CHANGED 9.19.23
2998#else
2999 if (a1)
3000#endif
3001 {
3002 _ssidString = const_cast<char*>(a1);
3004 SerialDebug.println(_ssidString);
3005
3006 }
3007 else
3008 {
3009 _ssidString = NULL;
3010 SerialDebug.println("ssid == NULL");
3011 }
3012 if (!_ssidString)
3013 {
3014
3015 SerialDebug.println("No SSID set, try BLE update again.. ");
3016 _ssidString = NULL;
3017 _ssidPasswordString = NULL;
3018 _mqttServerString = NULL;
3019 _mqttPortString = NULL;
3020 _mqttPasswordString = NULL;
3022 _mqttUserString = NULL;
3023 _mqttTopicString = NULL;
3024#ifdef NOT_ORIGINAL
3025 // _deviceNameString = (char*)"Unnamed"; /// CHANGED 9.19.23
3026#else
3027 _deviceNameString = (char*)"Unnamed";
3028#endif
3029 _uuidString = NULL;
3030 _jsonHeaderString = NULL;
3031 _jsonVersionString = NULL;
3032 _jsonLocationString = NULL;
3033
3034 //call the callback specified from the caller (eg. NimBLE_PetTutor_Server .. or others)
3035 // (*_callbackFunction)(rxValue);
3037
3038 return;
3039
3040 }
3041 //!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..
3042 {
3043 const char* a2 = myObject["ssidPassword"];
3044 if (a2)
3045 {
3046 _ssidPasswordString = const_cast<char*>(a2);
3048 SerialDebug.println(_ssidPasswordString);
3049 }
3050 else
3051 _ssidPasswordString = NULL;
3052 }
3053
3054 {
3055 //!the MQTT host/port/user/password (topic is created in this code...)
3056 const char* a3 = myObject["mqtt_server"];
3057 if (a3)
3058 {
3059 _mqttServerString = const_cast<char*>(a3);
3061 SerialDebug.println(_mqttServerString);
3062 }
3063 else
3064 _mqttServerString = NULL;
3065 }
3066
3067 {
3068 const char* a4 = myObject["mqtt_port"];
3069 if (a4)
3070 {
3071 _mqttPortString = const_cast<char*>(a4);
3073 }
3074 else
3075 _mqttPortString = NULL;
3076 }
3077
3078 {
3079 const char* a5 = myObject["mqtt_password"];
3080 if (a5)
3081 {
3082 _mqttPasswordString = const_cast<char*>(a5);
3084 SerialDebug.println(_mqttPasswordString);
3085 }
3086 else
3087 _mqttPasswordString = NULL;
3088 }
3089
3090 {
3091 const char* a6 = myObject["mqtt_user"];
3092 if (a6)
3093 {
3094 _mqttUserString = const_cast<char*>(a6);
3096 }
3097 else
3098 _mqttUserString = NULL;
3099 }
3100
3101 {
3102 const char* a7 = myObject["deviceName"];
3103 if (a7)
3104 {
3105 _deviceNameString = const_cast<char*>(a7);
3107 }
3108 else
3109 _deviceNameString = NULL;
3110 }
3111
3112 //update the chip name with the deviceName
3113 getChipInfo();
3114
3115 SerialDebug.println(_deviceNameString);
3116
3117 {
3118 const char* a8 = myObject["uuid"];
3119 if (a8)
3120 {
3121 _uuidString = const_cast<char*>(a8);
3123 SerialDebug.print("UUID: ");
3124 SerialDebug.println(_uuidString);
3125
3126 }
3127 else
3128 _uuidString = NULL;
3129 }
3130
3131 {
3132 const char* a9 = myObject["mqtt_topic"];
3133 if (a9)
3134 { _mqttTopicString = const_cast<char*>(a9);
3136 SerialDebug.println(_mqttTopicString);
3137 }
3138 else
3139 _mqttTopicString = NULL;
3140 }
3141
3142 {
3143 const char* a10 = myObject["jsonHeader"];
3144 if (a10)
3145 { _jsonHeaderString = const_cast<char*>(a10);
3147 SerialDebug.println(_jsonHeaderString);
3148 }
3149 else
3150 _jsonHeaderString = NULL;
3151 }
3152
3153 {
3154 //!Note: This is where the code could look for backward compatability, etc..
3155 const char* a11 = myObject["jsonVersion"];
3156 if (a11)
3157 { _jsonVersionString = const_cast<char*>(a11);
3159 SerialDebug.println(_jsonVersionString);
3160 }
3161 else
3162 _jsonVersionString = NULL;
3163 }
3164
3165 {
3166 const char* a12 = myObject["location"];
3167 if (a12)
3168 { _jsonLocationString = const_cast<char*>(a12);
3170 SerialDebug.println(_jsonLocationString);
3171 }
3172 else
3173 _jsonLocationString = NULL;
3174 }
3175
3176 {
3177 const char* a13 = myObject["mqtt_guestPassword"];
3178 if (a13)
3179 {
3180 _mqttGuestPasswordString = const_cast<char*>(a13);
3182 SerialDebug.println(_mqttGuestPasswordString);
3183 }
3184 else
3186 }
3187
3188 //! sets the MQTT user/password. It's up to the code to decide who needs to know (currently saves in the WIFI_APModule
3190}
3191
3192
3193
3194//!whether the string is TRUE, ON, 1
3195boolean isTrueString(String valCmdString)
3196{
3197 return valCmdString.equalsIgnoreCase("on") ||
3198 valCmdString.equalsIgnoreCase("1") ||
3199 valCmdString.equalsIgnoreCase("true");
3200}
3201#ifdef UNUSED
3202//!whether the string is FALSE, OFF, 0
3203function isFalseString(String valCmdString)
3204{
3205 return valCmdString.equalsIgnoreCase("off") ||
3206 valCmdString.equalsIgnoreCase("0") ||
3207 valCmdString.equalsIgnoreCase("false");
3208}
3209#endif //UNUSED
3210
3211//!send message to ourself to change to current specifed SM Mode
3213{
3214 //!send message to ourself to process the current mode..
3217}
3218
3219//!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)
3220//!1.14.24 THIS is the main JSON processor of messages. But now that groups can send almost any message, there
3221//!needs to be a way define a subset of messages that groups can send on..
3222//!6.20.25 added Serial Monitor input,
3223//!API Manual described:
3224//!@see https://github.com/konacurrents/SemanticMarkerAPI
3225//! note: The strcasecmp() function shall compare, while ignoring differences in case, the string pointed to by s1 to the string pointed to by s2.
3226boolean processJSONMessageMQTT(char *ascii, char *topic)
3227{
3228 SerialTemp.println(" *** processJSONMessageMQTT ***");
3229
3230 //! 6.16.25 Nice out, yellow field
3231 //! set below when looking at whether a command was found
3232 //! if false then continue the if/else
3233 boolean foundCommand;
3234
3235 //! use the default user topic if not specified...
3236 if (!topic)
3237 {
3238 if (!_mqttTopicString)
3239 _mqttTopicString = (char*)"usersP/bark/test";
3240 topic = _mqttTopicString;
3241 }
3242 //! sets the global so isGroupTopic() will work
3243 classifyTopic(topic);
3244
3245 if (!ascii)
3246 return false;
3247
3248 //! 7.26.23 don't process if a group message and FLAG not set
3249 if (isGroupTopic())
3250 {
3251 // if the EPROM says not to process groups .. then skip this message..
3252 //! called to set a preference (which will be an identifier and a string, which can be converted to a number or boolean)
3254 {
3255 SerialDebug.printf("NOT Processing as PREFERENCE_SUPPORT_GROUPS_SETTING not set");
3256 return false;
3257 }
3258 //! 8.2.24 support the not receiving message on some topics (such as a users GuestTopic)
3259 //! Idea would be some devices won't listen to the guest topic (instead only the user safe ones)
3260 else if (!topicInIncludeGroup(topic))
3261 {
3262 SerialDebug.printf("NOT Processing as topic not in Include Group: %s", topic);
3263 return false;
3264 }
3265 }
3266
3267 //!empty the status for the last message. Then various places the feed or status, etc are set
3268 //emptyLastMessageStatus();
3269 //cant empty here .. as the ACK gets sent .. how about after the ACK!
3270
3271 //!Basically processing as a JSON if the "{" is somewhere.. could still be invalid code
3272 if (!startsWithChar(ascii,'{'))
3273 {
3274 SerialLots.printf("processJSONMessageMQTT(%s) -> return false, not JSON\n", ascii);
3275
3276 return false;
3277 }
3278
3279 SerialDebug.printf("processJSONMessageMQTT: '%s'\n", ascii);
3280
3281 // Deserialize the JSON document, then store the ascii in the EPROM (if it parses..)
3282
3283 SerialLots.printf("Ascii before deserializeJson: %s\n", ascii);
3284
3285#ifdef PROCESS_SMART_BUTTON_JSON
3286 DynamicJsonDocument myObject(2024);
3287#else
3288#ifdef ESP_m5
3289 DynamicJsonDocument myObject(1024);
3290#else
3291 DynamicJsonDocument myObject(1024); //was 600
3292#endif //ESP_M5
3293#endif
3294
3295 deserializeJson(myObject, ascii);
3296 serializeJsonPretty(myObject, Serial);
3297
3298 //NOTE: the ascii is now corrupted...
3299 SerialDebug.print("\nJSON parsed = ");
3300 // String output;
3301 String output1;
3302 serializeJson(myObject, output1);
3303 SerialDebug.println(output1);
3304 SerialLots.printf("Ascii after deserializeJson: %s\n", ascii);
3305
3306 //NEW: 3.28.22 {'cmd':COMMANDS}
3307 // {'sm':<sm>}
3308 // {'guest':<passws>
3309 //{ 'set':<object>,'val':<value>}
3310 const char* cmd = myObject["cmd"];
3311 const char* semanticMarkerCmd = myObject["sm"];
3312 const char* guestCmd = myObject["guest"];
3313
3314 //! 9.18.23 add this .. so it doesnt' fall through
3315 const char *set64Cmd = myObject["set64"];
3316
3317 const char *setCmd = myObject["set"];
3318 const char *valCmd = myObject["val"];
3319 //new: 'send':<request> eg. status|temp
3320 const char *sendCmd = myObject["send"];
3321 //! devName is if a dev=<NAME> was specified, then dissregard if not our device
3322 const char *devName = myObject["dev"];
3323 //if processCommands, then do NOT process the credentials..
3324 boolean processCommands = false;
3325 if (cmd || semanticMarkerCmd || guestCmd || setCmd || sendCmd || set64Cmd)
3326 processCommands = true;
3327
3328#ifdef PROCESS_SMART_BUTTON_JSON
3329 //! 7,1.23 Dads 92'n birthday
3330//!NOT DOING THESE RIGHT NOW.. THE REST https is being done by ATOM
3331 //const char *SMARTButton = myObject["SMARTButton"];
3332 boolean processSMARTButton = containsSubstring(output1,"SMARTButton"); //myObject["SMARTButton"] != NULL;
3333 SerialTemp.printf("SMARTButton = %d\n", processSMARTButton);
3334 //! set processCommands just so it process the 'dev' argument..
3335 if (processSMARTButton)
3336 processCommands = true;
3337#endif
3338
3339
3340 //try 5.12.22 {'set':'item'},{'val':'value'}
3341 // eg. set:hightemp, val:80
3342
3343 //Find the Guest Password, and the user name - or defaults if notset
3344 String guestPassword = "pettutor";
3346 {
3347 //in case empty (but not null) - not checking for spaces only... too lazy
3348 if (strlen(_mqttGuestPasswordString)>0)
3349 guestPassword = _mqttGuestPasswordString;
3350 }
3351 // set vals to NOTSET if not set
3352 char* baseString;
3353 String title = "";
3354 if (!_mqttUserString)
3355 {
3356 _mqttUserString = NOTSET_STRING;
3357 }
3359 {
3360 _mqttPasswordString = NOTSET_STRING;
3361 }
3362
3363 //!this is to ensure that the credentials are not processed..
3364 //! there is a return 'true' after processing commands
3365 if (processCommands)
3366 {
3367 //! for dawgPack, only support the DOCFOLLOW message for now 8.19.22
3368 if (isDawgpackTopic())
3369 {
3370 char* setCmdString = const_cast<char*>(setCmd);
3371 char* valCmdString = const_cast<char*>(valCmd);
3372
3373 if (setCmd && strcasecmp(setCmd,"semanticMarker")==0)
3374 {
3375 SerialDebug.printf("DAWGPACK supported message: %s\n", setCmd);
3376 }
3377 else
3378 {
3379 SerialDebug.println("DAWGPACK unsupported message");
3380 return true;
3381 }
3382 //fall through for supported messaages..
3383 }
3384
3385 //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...
3386 //! a couple commands, like bleserveron require a device name to be specified (so everyone listening doesn't perform operation)
3387 boolean deviceNameSpecified = devName != NULL;
3388 //!if a dev:<dev> is specified, then only process if the device name is that same
3389 boolean processMessageOrGateway = true;
3390 if (deviceNameSpecified)
3391 {
3392 //default we only feed if our device or our gateway..
3393 processMessageOrGateway = false;
3394#ifdef WILDCARD_DEVICE_NAME_SUPPORT //yes
3395 //!parses a line of text, The caller then uses queryMatchesName() to see if their name matches
3396 parseQueryLine_mainModule((char*)devName);
3398 {
3399 SerialTemp.printf("Query: %s *** Matches our dev name: %s\n", devName, _deviceNameString);
3400 processMessageOrGateway = true;
3401 }
3402 //! per #314 support the chipId as well as the name..
3403 //! 3.17.24
3404 else if (stringMatch(devName, getChipIdString()))
3405 {
3406 SerialTemp.printf("ChipID: %s *** Matches our ChipID name: %s\n", devName, getChipIdString());
3407 processMessageOrGateway = true;
3408 }
3409
3410#else
3411 //!If the dev name is specified, and our device is that name .. then good
3412 if (devName && strcmp(devName,_deviceNameString) == 0)
3413 {
3414 SerialTemp.println(" .. our own device ..");
3415 processMessageOrGateway = true;
3416 }
3417#endif
3418
3419 //!we are in gateway mode, and the paired device isn't ours..
3420 if (devName
3422 {
3423#ifdef WILDCARD_DEVICE_NAME_SUPPORT
3425 {
3426 SerialTemp.printf("Query: %s *** Matches our paired dev name: %s\n", devName, getPreferenceString_mainModule(PREFERENCE_PAIRED_DEVICE_SETTING));
3427 processMessageOrGateway = true;
3428 }
3429#else
3431 {
3432 SerialTemp.println(" .. our paired device ..");
3433 processMessageOrGateway = true;
3434 }
3435#endif
3436 }
3437
3438 } //device name specified (sets up processMessageOrGateway., and sets device
3439
3440 //! basically, processMessageOrGateway is set to TRUE if the device isn't mentioned, OR
3441 //! the dev is mentioned, and the wildcard works (or is paired)
3442 //! In either case, the deviceNameSpecified will be true if "dev" was specified (even with wildcard)
3443 //! So code below that only work if "dev" specified will work and know it's their device
3444 //! For the SemanticMarker, if the onlyDevSM==true, then look for deviceNameSpecified
3445
3446#ifdef PROCESS_SMART_BUTTON_JSON //no 9.28.23
3447 //! early attempt to process a SMART buttons JSON as a stored procedure.
3448 //! But currently the JSON parser is bombing on the JSON provided..
3449 //! 7.1.23 Dads 92nd birthday
3450 if (processMessageOrGateway && processSMARTButton)
3451 {
3452 StaticJsonDocument<2024> smartButtonObject;
3453
3454 deserializeJson(smartButtonObject, myObject["SMARTButton"]);
3455 //done..
3456 return processJSONSMARTButton(smartButtonObject);
3457 }
3458#endif
3459 //! after this, if true, then ifDeviceNameSpecified .. then it's a good name..
3460 if (!processMessageOrGateway)
3461 {
3462 //Only gets here if dev set .. so the parser was run (if WILDCARD)
3463 SerialTemp.print("Disregard as Device Specified: ");
3464 SerialTemp.print(devName);
3465
3466 //! as per issue #122, if a device is in gateway mode, and paired with a device name specified, then the message can be sent
3467 SerialTemp.print(" not ours: ");
3468 SerialTemp.println(_deviceNameString);
3470 {
3471#ifdef WILDCARD_DEVICE_NAME_SUPPORT
3473#else
3475#endif
3476 {
3477 SerialTemp.print(" .. And not paired device:");
3479 }
3480 }
3481 }
3482 //! {"cmd", <cmd>)
3483 else if (cmd)
3484 {
3485 //! 1.14.24 use the isGroupTopic() where needed..
3486 //SerialDebug.printf("BLE CMD = '%s'\n", cmd);
3487 //note: we could have a mode for "testing" .. so the OTA for example does't fire.
3488 //smN
3489 //NOTE: THIS REQUIRES == 0 or no work..
3490 //NOTE: the number here has to be updated in the ButtonProcessing code too..
3491 int whichSMMode = whichSMMode_mainModule((char*)cmd);
3492 SerialTemp.printf("MQTT or BLE CMD = '%s'\n", cmd);
3493#ifdef ESP_M5
3494 // -1 if none..
3495 if (whichSMMode >= 0)
3496 {
3497 //! per #206 .. only change the page when not in doc_follow
3498 //! 1.22.24 if switching to mode 0 then it's ok..
3499 //! 11.9.22
3500 int currentSMMode = getCurrentSMMode_mainModule();
3501 SerialDebug.printf("currentSMMode = %d whichSMMode = %d\n", currentSMMode, whichSMMode);
3502 if (currentSMMode == SM_doc_follow && whichSMMode > 0)
3503 {
3504 //! Issue: #222 for #206, this sets the current mode to SM_doc_follow, but
3505 //! when at that page in the the current mode (which is now SM_doc_follow) won't let
3506 //! the page go somewhere else (except in this case we are the same page). Only but a
3507 //! physical button click.
3508 //! I THINK THE ANSWER: if current and next are the same an SM_doc_follow, then do the page change..
3509 if (currentSMMode != whichSMMode)
3510 {
3511 SerialDebug.println(" *** Not changing page as in DOCFOLLOW mode ***");
3512 return true;
3513 }
3514 else
3515 SerialDebug.println(" *** SM_doc_follow and changing to the same page ***");
3516 }
3517
3518 //set the global SMMode.. NOTE: if greater than the MAX change mode to NON MIN
3519 setCurrentSMMode_mainModule(whichSMMode);
3520
3521 boolean markerAlreadyShown = false;
3522 switch (whichSMMode)
3523 {
3524 //since the TITLE is used by the display (it doesn't use the SMMode)
3525 case SM_home_simple: //TILT
3526 {
3527 //new 7.25.22
3528 baseString = (char*)"https://iDogWatch.com/bot/guestpage2";
3529 title = "MINI CLICKER";
3530 sprintf(_semanticMarkerString,"%s/%s/%s", baseString, _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL");
3531 }
3532 break;
3533 case SM_home_simple_1: // BUZZER
3534 {
3535 //NOTE: THIS title is a binding/linking to the DisplayModule (as it looks for the title)
3536 //new 7.25.22
3537 baseString = (char*)"https://iDogWatch.com/bot/guestpage2";
3538 title = "MINI-1";
3539 sprintf(_semanticMarkerString,"%s/%s/%s", baseString, _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL");
3540 }
3541 break;
3542 case SM_home_simple_2: //FEED
3543 {
3544 //new 7.25.22
3545 baseString = (char*)"https://iDogWatch.com/bot/guestpage2";
3546 title = "MINI-2";
3547 sprintf(_semanticMarkerString,"%s/%s/%s", baseString, _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL");
3548 }
3549 break;
3550 case SM_home_simple_3: //EXPERT
3551 {
3552 //new 7.25.22
3553 baseString = (char*)"https://iDogWatch.com/bot/guestpage2";
3554 title = "MINI-3";
3555 sprintf(_semanticMarkerString,"%s/%s/%s", baseString, _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL");
3556 }
3557 break;
3558 //! the 4th page, start of smart clicker
3560 {
3561 //Make URL for the status..
3562 char *statusString = currentMessageStatusURL();
3563
3564 //!create the SemanticMarker address
3565 sprintf(_semanticMarkerString,"%s/%s/%s/%s", "https://SemanticMarker.org/bot/sensor", _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL", statusString?statusString:"NULL");
3566
3567 title = "WIFI FEED";
3568
3569 //TODO.. use the String (*getStatusFunc)(void)) to re-create this..
3570 //TODO: get the guest info.. or they send us the guest password in a message.. for next time..
3571 //SerialDebug.print("SemanticMarker: ");
3572 SerialLots.println(_semanticMarkerString);
3573 //MAYBE save the user web page.. somewhere EPROM
3574
3575 //!call the displayModuleFunc passing our dynamic status fund
3577 markerAlreadyShown = true;
3578 }
3579
3580 break;
3581 case SM_status:
3582 {
3583 //Make URL for the status..
3584 char *statusString = main_currentStatusURL(true);
3585
3586 //!create the SemanticMarker address
3587 sprintf(_semanticMarkerString,"%s/%s/%s/%s", "https://SemanticMarker.org/bot/sensor", _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL", statusString?statusString:"NULL");
3588
3589 //!tack on the device name..
3590 sprintf(_fullMessageOut,"Status %s", getDeviceNameMQTT());
3591 //title = _fullMessageOut;
3592
3593 //TODO.. use the String (*getStatusFunc)(void)) to re-create this..
3594 //TODO: get the guest info.. or they send us the guest password in a message.. for next time..
3595 //SerialDebug.print("SemanticMarker: ");
3596 SerialLots.println(_semanticMarkerString);
3597 //MAYBE save the user web page.. somewhere EPROM
3598
3599 //!call the displayModuleFunc passing our dynamic status fund
3601 markerAlreadyShown = true;
3602 }
3603 break;
3604
3605 case SM_guest_page:
3606
3607 {
3608 baseString = (char*)"https://iDogWatch.com/bot/guestpage";
3609 title = "Guest Page";
3610 sprintf(_semanticMarkerString,"%s/%s/%s", baseString, _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL");
3611 }
3612 break;
3613 case SM_guest_feed:
3614 {
3615 baseString = (char*)"https://iDogWatch.com/bot/feedguest";
3616 title = "Feed Guest";
3617 sprintf(_semanticMarkerString,"%s/%s/%s", baseString, _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL");
3618 }
3619 break;
3620 case SM_pair_dev:
3621 {
3622 baseString = (char*)"https://iDogWatch.com/bot/feedguestdevice";
3624 //!NOTE this could be "NONE" the "P:" is so the display knows this is a paired device command
3625 title = "P:";
3626 sprintf(_semanticMarkerString,"%s/%s/%s/%s", baseString, _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL", pairDev);
3627 }
3628 break;
3629 case SM_WIFI_ssid:
3630 {
3631 title = "WIFI";
3632
3633 //!#issue 136 create a SM for the WIFI syntax
3634 //!WIFI:S:<SSID>;T:<WEP|WPA|blank>;P:<PASSWORD>;H:<true|false|blank>;
3635 sprintf(_semanticMarkerString,"WIFI:S:%s;T:;P:%s;H:;", _ssidString?_ssidString:"NONE", _ssidPasswordString?_ssidPasswordString:"");
3636 }
3637 break;
3638
3639 // different SM
3640 case SM_ap_mode:
3641 {
3642 //AP mode..
3643 sprintf(_semanticMarkerString,"%s", "http://192.168.4.1");
3644 title = "AP Mode";
3645 }
3646 break;
3647
3648 case SM_help:
3649 {
3650 //HELP..
3651 //Make URL for the status..
3652 sprintf(_semanticMarkerString,"%s/%s/%s", "https://SemanticMarker.org/bot/help", _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL");
3653 title = "Help Info";
3654 }
3655 break;
3656 case SM_doc_follow: //sm12
3657 {
3658 //This is where a dynamic DOCFollow would show up..
3659 //Make URL for the status..
3661 title = "DOC FOLLOW";
3662 //call the displayModule
3663 if (SM.length()>0)
3664 sprintf(_semanticMarkerString,"%s", SM);
3665 else
3666 SM = "https://SemanticMarker.org";
3667 }
3668 break;
3669 //NOTE: each added sm, needs the ButtonProcessing.cpp to update it's list..
3670 case SM_reboot:
3671 {
3672 //REboot the device
3673 sprintf(_semanticMarkerString,"%s/%s/%s", "https://SemanticMarker.org/bot/reboot", _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL");
3674 title = "Reboot";
3675 }
3676 break;
3677 case SM_timer:
3678 {
3679 //timer the device
3680 sprintf(_semanticMarkerString,"%s/%s/%s", "https://SemanticMarker.org/bot/timer", _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL");
3681 title = "Timer";
3682 }
3683 break;
3684
3685 }
3686 //TODO: get the guest info.. or they send us the guest password in a message.. for next time..
3687 //SerialDebug.print("SemanticMarker: ");
3688 SerialLots.println(_semanticMarkerString);
3689 //MAYBE save the user web page.. somewhere EPROM
3690
3691 //!turn this OFF if it came in via a SemanticMarker command ... ???
3692 if (!markerAlreadyShown)
3693 {
3694 //only if not already shown. Status uses a dynamic function..
3696 }
3697 } //end smMode 0..n
3698 else
3699#endif //ESP_M5 display
3700 if (strcasecmp(cmd,"ota")==0 && !isGroupTopic())
3701 {
3702 SerialDebug.println("OTA via BLE");
3703 //!calls the OTA update method (this doesn't return as device is rebooted...)
3705 }
3706 //! add click to any device, and to a group
3707 //! 5.14.25 (Dead 5.14.74 3rd wall of sound)
3708 else if (strcasecmp(cmd,"click")==0)
3709 {
3710 //! click call
3712 }
3713 else if (strcasecmp(cmd,"clean")==0 && !isGroupTopic())
3714 {
3715 SerialDebug.println("CLEAN via BLE");
3716 //!calls the method for cleaning the SSID eprom. This calls the WIFI_APModule callback
3718 }
3719 else if (strcasecmp(cmd,"feed")==0)
3720 {
3721 SerialDebug.printf("FEED via BLE (%s)\n",topic?topic:"NULL TOPIC!!");
3722 performFeedMethod(topic);
3723 }
3724 else if (strcasecmp(cmd,"resettimer")==0)
3725 {
3727 }
3728 else if (strcasecmp(cmd,"status")==0)
3729 {
3730 SerialDebug.println("STATUS via BLE");
3731 //!print status of the WIFI and MQTT
3732 SerialMin.printf("WIFI_MQTTState= %d\n",_WIFI_MQTTState);
3733 SerialMin.printf("DeviceName= %s\n",getDeviceNameMQTT());
3734 SerialMin.printf("ChipName= %s\n",getChipIdString());
3735#ifdef ESP_M5
3736 SerialMin.printf("DynamcState= %s\n",getDynamicStatusFunc());
3737 SerialMin.printf("WIFI connected = %d, %s\n", isConnectedWIFI_MQTTState(), wifiStatus_MQTT());
3738#endif
3739 SerialMin.printf("MQTT connected = %d, %s\n", isConnectedMQTT_MQTTState(),_mqttClient.connected()?"connected":"not connected");
3740
3741
3742 //! send SPIFF status
3743 //! 4.4.24
3745
3746
3747 //WL_NO_SSID_AVAIL .. to WL_DISCONNECTED
3748 //but never reconnects ...
3749 SerialLots.println("cmd == status");
3750 //! request a STATUS be sent.
3751 processBarkletMessage("#STATUS", topic);
3752 }
3753 else if (strcasecmp(cmd,"erase")==0 && !isGroupTopic())
3754 {
3755 SerialDebug.println("ERASE via BLE");
3757 }
3758
3759 //!TODO: duplicate and depreciate these and replace with set:buzz,val:on
3760 else if (strcasecmp(cmd,"buzzon")==0)
3761 {
3762 SerialDebug.println("BUZZON via BLE");
3764 }
3765 else if (strcasecmp(cmd,"buzzoff")==0)
3766 {
3767 SerialDebug.println("BUZZOFF via BLE");
3769 }
3770 //Gateway (which I think is obsolete if we can determin this from knowing which feeder we have)
3771 //keeping for now..
3772 else if (strcasecmp(cmd,"gatewayOn")==0)
3773 {
3774 if (deviceNameSpecified)
3775 {
3776 SerialDebug.println("ASYNC_SET_GATEWAY_ON via BLE");
3778 }
3779 }
3780 else if (strcasecmp(cmd,"gatewayOff")==0)
3781 {
3782 if (deviceNameSpecified)
3783 {
3784 SerialDebug.println("ASYNC_SET_GATEWAY_OFF via BLE");
3786 }
3787 }
3788 //!resetFirstTime
3789 else if (strcasecmp(cmd,"resetfirsttime")==0)
3790 {
3791 if (deviceNameSpecified)
3792 {
3793 SerialDebug.println("PREFERENCE_FIRST_TIME_FEATURE_SETTING ON via BLE");
3795 //!for now just reboot which will use this perference
3797 }
3798 }
3799 //BLECLient
3800 else if (strcasecmp(cmd,"bleclientOn")==0 && !isGroupTopic())
3801 {
3802 if (deviceNameSpecified)
3803 {
3804 SerialDebug.println("PREFERENCE_MAIN_BLE_CLIENT_VALUE ON via BLE");
3806 //!for now just reboot which will use this perference
3808 }
3809 }
3810 else if (strcasecmp(cmd,"bleclientOff")==0 && !isGroupTopic())
3811 {
3812 if (deviceNameSpecified)
3813 {
3814 SerialDebug.println("PREFERENCE_MAIN_BLE_CLIENT_VALUE OFF via BLE");
3816 //!for now just reboot which will use this perference
3818 }
3819 }
3820 else if (strcasecmp(cmd,"bleserverOn")==0 && !isGroupTopic())
3821 {
3822 if (deviceNameSpecified)
3823 {
3824 SerialDebug.println("PREFERENCE_MAIN_BLE_SERVER_VALUE ON via BLE");
3826 //!for now just reboot which will use this perference
3828 }
3829 }
3830 else if (strcasecmp(cmd,"bleserverOff")==0 && !isGroupTopic())
3831 {
3832 if (deviceNameSpecified)
3833 {
3834 SerialDebug.println("PREFERENCE_MAIN_BLE_SERVER_VALUE OFF via BLE");
3836 //!for now just reboot which will use this perference
3838 }
3839 }
3840 else if (strcasecmp(cmd,"reboot")==0 && !isGroupTopic())
3841 {
3842 if (deviceNameSpecified)
3843 {
3844 SerialDebug.println("REBOOT via BLE");
3845 //!for now just reboot which will use this perference
3847 }
3848 }
3849 else if (strcasecmp(cmd,"tiltOn")==0)
3850 {
3851 SerialDebug.println("PREFERENCE_SENSOR_TILT_VALUE ON via BLE");
3853 }
3854 else if (strcasecmp(cmd,"tiltOff")==0)
3855 {
3856 SerialDebug.println("PREFERENCE_SENSOR_TILT_VALUE OFF via BLE");
3858 }
3859 //!zoom == the NON semantic marker version.. so min menu is true
3860 else if (strcasecmp(cmd,"zoomSMOn")==0)
3861 {
3862
3863 //hide semantic marker.. (but only if in the max menus)
3864 //NOTE: this only hides the Semantic Marker - if on a page that has one..
3865 SerialDebug.println("PREFERENCE_SEMANTIC_MARKER_ZOOMED_VALUE ON via BLE");
3867
3868 //!zoom only if in the max menu set..
3870 {
3871 //stay on this page, but change the marker..
3873 }
3874
3875 }
3876 else if (strcasecmp(cmd,"zoomSMOff")==0)
3877 {
3878 //show semantic marker..
3879 //NOTE: this only shows the Semantic Marker - if on a page that has one..
3880 SerialDebug.println("PREFERENCE_SEMANTIC_MARKER_ZOOMED_VALUE OFF via BLE");
3883
3884 //!zoom only if in the max menu set..
3886 {
3887 //change to the status..
3889 //!send message to ourself to process the current mode..
3891 }
3892 else
3893 {
3894 //stay on this page, but change the zoom..
3896 }
3897 }
3898 else if (strcasecmp(cmd,"poweroff")==0 && !isGroupTopic())
3899 {
3900 SerialDebug.println("ASYNC_POWEROFF OFF via BLE");
3902
3903 }
3904 else if (strcasecmp(cmd,"wifi")==0)
3905 {
3906 SerialDebug.println("cmd=wifi via BLE");
3908 }
3909 else if (strcasecmp(cmd,"swapwifi")==0)
3910 {
3911 SerialDebug.println("cmd=swapwifi via BLE");
3912
3913 //NOTE: this might be where we toggle credentials?? TODO
3914 //found other one..
3915 char *credentials = main_nextJSONWIFICredential();
3916
3917 //!These are the ASYNC_CALL_PARAMETERS_MAX
3918 //!NO: just change our credentials ...
3919 //send to ourself.., recursively...
3920 int val = processJSONMessageMQTT(credentials, topic);
3921 }
3922#ifdef USE_SPIFF_MODULE
3923 //new 7.29.22 SPIFF
3924 else if (strcasecmp(cmd,"readspiff")==0)
3925 {
3926 SerialDebug.println("readspiff...");
3927
3929 }
3930 else if (strcasecmp(cmd,"sendspiff")==0)
3931 {
3933 }
3934 else if (strcasecmp(cmd,"deletespiff")==0 && !isGroupTopic())
3935 {
3937 }
3938#endif //USE_SPIFF_MODULE
3939 else if (strcasecmp(cmd,"capture")==0)
3940 {
3941 //! request a CAPTURE be sent.
3942 processBarkletMessage("#CAPTURE", topic);
3943#ifdef ESP_M5
3945#endif
3946 }
3947 //end new
3948 else if (strcasecmp(cmd,"help")==0)
3949 {
3950 //!and print any preferences to show
3952
3953 sprintf(_fullMessageOut, "Syntax {\'cmd': \'[ota|clean|feed|erase|status|buzzon|buzzoff| MORE..help]\'} ");
3954 //!publich back on topic
3955 //_mqttClient.publish(_mqttTopicString, _fullMessageOut);
3956#ifdef TRY_MORE_ASYNC_PROCESSING
3957 //publish back on topic
3959#else
3961#endif
3962 }
3963
3964 //! 12.27.23 pass this onto those registered (which mainModule is handling..)
3965 //! 1.14.24 .. what about groups??
3966 //! 8.16.25 Gods of War (Hawaii)
3967 //! send this .. and let the caller decide if deviceNameSpecified needed..
3968 //if (deviceNameSpecified)
3969 {
3970 char* sendCmdString = const_cast<char*>(cmd);
3971
3972 //! 12.28.23, 8.28.23 Tell Main about the set,val and if others are registered .. then get informed
3973 messageSend_mainModule(sendCmdString, deviceNameSpecified);
3974 }
3975 }
3976 //! {'guest':'guest password'}
3977 else if (guestCmd) //depreciated..
3978 {
3979 _mqttGuestPasswordString = const_cast<char*>(guestCmd);
3980 SerialDebug.printf("guestCmd = '%s'\n", _mqttGuestPasswordString);
3981 }
3982#ifdef ESP_M5
3983 // 'sm':'name/cat/uuid'
3984 else if (semanticMarkerCmd)
3985 {
3986 //char semanticMarkerString[200];
3987 char* baseString = (char*)"https://SemanticMarker.org/bot/";
3988 sprintf(_semanticMarkerString,"%s/%s", baseString, semanticMarkerCmd);
3989
3990 //! 9.28.29 devOnlySM if set, then
3991 boolean showSM = true;
3993 showSM = deviceNameSpecified;
3994
3995 if (showSM)
3996 //! use the name/cat/uuid ..
3998 else
3999 SerialDebug.println("Not showing SemanticMarker ");
4000 } //semanticMarkerCmd
4001#endif //ESP_M5
4002 //!5.12.22
4003 //!{set:<set>,"val":val, device?)
4004 else if (setCmd && valCmd)
4005 {
4006 //! options: hightemp, feedcount, timeout
4007 char* setCmdString = const_cast<char*>(setCmd);
4008 char* valCmdString = const_cast<char*>(valCmd);
4009 SerialTemp.print("Set: ");
4010 SerialTemp.print(setCmdString);
4011 SerialTemp.print(", Val: ");
4012 SerialTemp.println(valCmdString);
4013
4014 //! 12.27.23 pass this onto those registered (which mainModule is handling..)
4015 //! 8.28.23 Tell Main about the set,val and if others are registered .. then get informed
4016 //! 1.10.24 if deviceNameSpecified then this matches this device, otherwise for all.
4017 //! It's up to the receiver to decide if it has to be specified
4018 //! 1.14.24 for now, setVal in the ATOM will support GROUP commands if turned on (and if off it doesn't get here)
4019 messageSetVal_mainModule(setCmdString, valCmdString, deviceNameSpecified);
4020
4021 //!set flag (if a boolean command)
4022 boolean flag = isTrueString(valCmdString);
4023
4024 //!try 5.12.22 {'set':'item'},{'val':'value'}
4025 //! eg. set:hightemp, val:80)
4026 //! TODO: confirm valid integer values...
4027 if (strcasecmp(setCmdString,"hightemp")==0)
4028 {
4029 //!set the high temp value..
4031 }
4032 //! 9.29.22 duplicating a couple of 'set':'cmd', 'val':'feed", since the QUERY for a device is sent that way sometimes..
4033 else if (strcasecmp(setCmdString,"cmd")==0)
4034 {
4035 if (strcasecmp(valCmdString,"feed")==0)
4036 {
4037 SerialCall.printf("feed via set,cmd (%s)\n",topic?topic:"NULL TOPIC!!");
4038 performFeedMethod(topic);
4039 }
4040 else if (strcasecmp(valCmdString,"status")==0)
4041 {
4042 SerialCall.println("status via set,cmd");
4043 //! request a STATUS be sent.
4044 processBarkletMessage("#STATUS", topic);
4045 }
4046 else if (strcasecmp(valCmdString,"resettimer")==0)
4047 {
4049 }
4050
4051 else
4052 {
4053 SerialTemp.printf("1.Unknown cmd: %s\n", valCmdString);
4054 }
4055 }
4056#pragma mark COPIED FROM BELOW .. so can set without DEVICE name
4057#define USE_WITHOUT_DEVICE_NAME
4058 //! 7.31.25 copied from below .. so it doesn't need 'dev' name in message
4059 //! eg:
4060 /*
4061 {"set":"sensors","val":"BuzzerSensorClass,19,22,L9110S_DCStepperClass,21,25"}
4062 {"set":"sensors","val":"BuzzerSensorClass,21,25,ULN2003_StepperClass,23,33"}
4063 {"set":"sensorPlugs","val":"L9110S_DCStepperClass"}
4064 {"set":"M5AtomKind","val":"M5HDriver"}
4065 {"set":"stepperAngle","val":"0.25"}
4066 {"ssid":"Bob", "ssidPassword":"scott"}
4067 */
4068#ifdef USE_WITHOUT_DEVICE_NAME
4069 //! 7.31.25 make this without DEV to make it easier..
4070 else if (strcasecmp(setCmdString,"stepperangle")==0)
4071 {
4072 SerialDebug.printf("stepperAngle: %s\n", valCmdString);
4073 //!set the stepperangle.
4075 foundCommand = true;
4076 }
4077
4078 //!8.14.25 Dead Movie from 10.19.1974 tonight..
4079 //! issue #394 stepperRPM
4080 //! stepper RPM
4081 else if (strcasecmp(setCmdString,"stepperRPM")==0)
4082 {
4083 SerialDebug.printf("stepperRPM: %s\n", valCmdString);
4084 //!set the stepperangle.
4086 foundCommand = true;
4087 }
4088
4089 //! issue #338 sensor definition (in work)
4090 //! This will be a string in JSON format with various PIN and BUS information
4091 else if (strcasecmp(setCmdString,"sensorPlugs")==0)
4092 {
4094
4095 SerialDebug.printf("sensorPlugs: %s\n", valCmdString);
4096 foundCommand = true;
4097
4098 //! reboot the device to set subscribe or not for groups
4100 }
4101
4102 //! issue #365 sensors
4103 //! 5.14.25 (Dead 5.14.74 3rd wall of sound)
4104 else if (strcasecmp(setCmdString,"sensors")==0)
4105 {
4106 //! currently not rebooting the device, but letting the user do that..
4107 //! this way multiple can be done, and a "" will reset
4108 //! 5.17.25 plowing field Mark and Bud
4109 //! this is now a full set, and resets first..
4110 setSensorsString_mainModule(valCmdString);
4111
4112 foundCommand = true;
4113
4114 }
4115 else if (strcasecmp(setCmdString,"M5AtomKind")==0)
4116 {
4117 //! new 1.4.24 setting ATOM kind (eg. M5AtomSocket, M5AtomScanner). MQTT message "set":"M5AtomKind", val=
4119
4120 foundCommand = true;
4121
4122 //!for now just reboot which will use this perference
4124 }
4125#endif
4126
4127#pragma mark Device Name and Not Group
4128 else if (deviceNameSpecified && !isGroupTopic())
4129 {
4130 //! if not found .. keep searching
4131 foundCommand = true;
4132 //! 9.28.23 #272 devOnlySM only show a SM if sent to this device
4133 if (strcasecmp(setCmdString,"devOnlySM")==0)
4134 {
4135 //set ble+wifi transient state..
4137 }
4138
4139 //! 8.2.24 to let older Tumbler NOT do the auto direction (back and forth)
4140 //! Isue #332
4141 //! it will set via message: autoMotorDirection
4142 //! {"set":"autoMotorDirection","val":"true"}
4143 else if (strcasecmp(setCmdString,"autoMotorDirection")==0)
4144 {
4146 }
4147
4148 //! 8.2.24 add includeGroups
4149 //! Isue #332
4150 //! it will set via message: includeGroups
4151 //! {"set":"includeGroups","val":"group1,group2"}
4152 else if (strcasecmp(setCmdString,"includeGroups")==0)
4153 {
4154 //! 8.2.24 set the include group (and cache it), called from MQTT
4155 setIncludeGroups(valCmdString);
4156 }
4157
4158 else if (strcasecmp(setCmdString,"ble+wifi")==0)
4159 {
4160 //set ble+wifi transient state..
4162 }
4163 else if (strcasecmp(setCmdString,"factoryreset")==0)
4164 {
4165 // factory reset .. eventually
4167
4168 }
4169 //! 11.9.22
4170 else if (strcasecmp(setCmdString,"restartmodels")==0)
4171 {
4172 //!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
4173 if (flag)
4175 }
4176 else if (strcasecmp(setCmdString,"screentimeout")==0)
4177 {
4178 //set the screen timeout
4180 }
4181 else if (strcasecmp(setCmdString,"stepperangle")==0)
4182 {
4183 SerialDebug.printf("stepperAngle: %s\n", valCmdString);
4184 //!set the stepperangle.
4186 }
4187 //!8.14.25 Dead Movie from 10.19.1974 tonight..
4188 //! issue #394 stepperRPM
4189 //! stepper RPM
4190 else if (strcasecmp(setCmdString,"stepperRPM")==0)
4191 {
4192 SerialDebug.printf("stepperRPM: %s\n", valCmdString);
4193 //!set the stepperangle.
4195 }
4196
4197 else if (strcasecmp(setCmdString,"noclick")==0)
4198 {
4199 //!set the timeout from no click to poweroff
4201 }
4202 else if (strcasecmp(setCmdString,"gateway")==0)
4203 {
4204 //! called to set a preference (which will be an identifier and a string, which can be converted to a number or boolean)
4206 }
4207 //! 10.4.22
4208 else if (strcasecmp(setCmdString,"DiscoverM5PTClicker")==0)
4209 {
4210 //! called to set a preference (which will be an identifier and a string, which can be converted to a number or boolean)
4212 }
4213 else if (strcasecmp(setCmdString,"usespiff")==0 && !isGroupTopic())
4214 {
4215 //! called to set a preference (which will be an identifier and a string, which can be converted to a number or boolean)
4217#ifdef USE_SPIFF_MODULE
4218 if (flag)
4219 {
4220 //! the setup for this module
4222 }
4223#endif //USE_SPIFF_MODULE
4224 }
4225 //! 4.4.24
4226 else if (strcasecmp(setCmdString,"usespiff_mqtt")==0 && !isGroupTopic())
4227 {
4228 //! called to set a preference (which will be an identifier and a string, which can be converted to a number or boolean)
4230 }
4231 else if (strcasecmp(setCmdString,"usespiff_qratom")==0 && !isGroupTopic())
4232 {
4233 //! called to set a preference (which will be an identifier and a string, which can be converted to a number or boolean)
4235 }
4236#ifdef ESP_M5
4237 //!NOTE: thes PIR and ATOM settings could be done in their modules AtomSocket but the LUX is in the butto
4238 //! 1.10.24 per issue#289 support PIR calling a SM in JSON (not just the FEED)
4239 else if (strcasecmp(setCmdString,"PIR_UseSM")==0 && !isGroupTopic())
4240 {
4242 //FOR now .. use the default that is to turn on all sockets...
4243 }
4244 //! 1.12.24 AtomSocketGlobalOnOff to turn on/off global onoff
4245 else if (strcasecmp(setCmdString,"AtomSocketGlobalOnOff")==0 && !isGroupTopic())
4246 {
4247 //! set global on/off is supported..
4249 }
4250 //! 1.12.24 set the value for the LUX sepearator from light and dark
4251 else if (strcasecmp(setCmdString,"LUXdark")==0 && !isGroupTopic())
4252 {
4253 //! save temporally ..
4255 }
4256 //! 1.13.24 scannedGroup temporary setting of the group name
4257 else if (strcasecmp(setCmdString,"scannedGroup")==0 && !isGroupTopic())
4258 {
4259 //! save temporally ..
4260 main_setScannedGroupName(valCmdString);
4261
4262 }
4263 //! 1.13.24 scannedDevice temporary setting of the group name
4264 else if (strcasecmp(setCmdString,"scannedDevice")==0 && !isGroupTopic())
4265 {
4266 //! save temporally ..
4267 main_setScannedDeviceName(valCmdString);
4268 }
4269#endif //ESP_M5
4270
4271 //!MQTT: set: timerdelay, val:seconds
4272 else if (strcasecmp(setCmdString,"timerdelay")==0)
4273 {
4274 int timerdelay = atoi(valCmdString);
4275 //!set the timer delay (0 == stop).
4277 //!start or stop the timer..
4278 SerialDebug.printf("timerdelay: %d\n", timerdelay);
4279
4280 }
4281 //!MQTT: set: timerdelay, val:seconds
4282 else if (strcasecmp(setCmdString,"timerdelayMax")==0)
4283 {
4284 int timerdelay = atoi(valCmdString);
4285 //!set the timer delay (0 == stop).
4287 //!start or stop the timer..
4288 SerialDebug.printf("timerdelayMax: %d\n", timerdelay);
4289 }
4290 //! MQTT: set: starttimer, val: true/false (true == start timer, false = stop timer)
4291 else if (strcasecmp(setCmdString,"starttimer")==0)
4292 {
4293 //!start or stop the timer..
4295 //!start or stop the timer..
4296 SerialDebug.printf("startTimer: %d\n", flag);
4297
4298 }
4299 //! issue #338 sensor definition (in work)
4300 //! This will be a string in JSON format with various PIN and BUS information
4301 else if (strcasecmp(setCmdString,"sensorPlugs")==0)
4302 {
4304
4305 SerialDebug.printf("sensorPlugs: %s\n", valCmdString);
4306
4307 //! reboot the device to set subscribe or not for groups
4309 }
4310
4311 //! issue #365 sensors
4312 //! 5.14.25 (Dead 5.14.74 3rd wall of sound)
4313 else if (strcasecmp(setCmdString,"sensors")==0)
4314 {
4315 //! currently not rebooting the device, but letting the user do that..
4316 //! this way multiple can be done, and a "" will reset
4317 //! 5.17.25 plowing field Mark and Bud
4318 //! this is now a full set, and resets first..
4319 setSensorsString_mainModule(valCmdString);
4320 }
4321 //!add stepper type
4322 else if (strcasecmp(setCmdString,"stepper")==0)
4323 {
4324 //!set the stepperAngle as well for a default value
4325 //!as of 8l18.24, the stepperAngle isn't used by the MINI (only the Tumbler)
4326 float stepperAngle = 22.5;
4327 int feederType = STEPPER_IS_UNO;
4328 //!NOTE: 'mini' is deprecated
4329 if (strcasecmp(valCmdString,"mini")==0)
4330 {
4331 //! mini will be backdoor to set the angle to 45
4332 // is UNO
4333 stepperAngle = 45.0;
4334 //feederType = STEPPER_IS_MINI;
4335 }
4336 else if (strcasecmp(valCmdString,"tumbler")==0)
4337 {
4338 feederType = STEPPER_IS_TUMBLER;
4339 stepperAngle = 200.0;
4340 //! set autoRotoate as well..
4342
4343 }
4344 else
4345 {
4346 //! set autoRotoate as well..
4348 }
4349 SerialDebug.printf("stepper = %d, stepperAngle = %f\n", feederType, stepperAngle);
4350 //! called to set a preference (which will be an identifier and a string, which can be converted to a number or boolean)
4352 //!set stepperAngle default as well (int or float ok..)
4353 //!Issue #332 8.17.2024
4355 //! default to clockwise == 1
4356
4357 //! 8.18.24 setting this will check for the factory setting..
4359 } //stepper
4360 else if (strcasecmp(setCmdString,"factoryClockwiseMotor")==0)
4361 {
4362 SerialCall.println(" *** Setting factory clockwise motor");
4363 //!note since clockwise == 0 we set the opposite of the value..
4365 //! 8.18.24 setting this will check for the factory setting..
4367 }
4368 else if (strcasecmp(setCmdString,"clockwiseMotor")==0)
4369 {
4370 SerialCall.println(" *** Setting clockwise motor");
4371 //! 8.18.24 setting this will check for the factory setting..
4373 }
4374 //! 8.18.24 (back deck with Tyler - Maggie - stormy lightning last night and rain
4375 //! toggleMotor the 'Q'
4376 //! 'set':'toggleMotor':'val':'on/off"
4377 //! TODO: call the 'Q' code ..
4378 else if (strcasecmp(setCmdString,"toggleMotor")==0)
4379 {
4380 //! 9.30.23 reverse direction
4381 //else if (cmd == 'Q')
4382
4383 //! note: reboot not needed as the next time a feed happens, it reads this value
4384 // motor direction == (reverse)
4386 currentDirection = !currentDirection;
4388 }
4389 //!add stepper type
4390 else if (strcasecmp(setCmdString,"otafile")==0)
4391 {
4392 //perform the OTA via a file specified .. be careful..
4394 }
4395 //!set the location
4396 else if (strcasecmp(setCmdString,"location")==0 && !isGroupTopic())
4397 {
4398 //perform the OTA via a file specified .. be careful..
4399 _jsonLocationString = createCopy(valCmdString);
4401 }
4402
4403 //! pairnow is for invoking the pair when there isn't a user interface. Basically
4404 //! once an ESP32 gets connected, especially to a GEN3, the pairnow will make it paired
4405 //! for future. 10.24.22
4406 else if (strcasecmp(setCmdString,"pairnow")==0)
4407 {
4408 //! TRUE will pair, FALSE will unpair
4409 if (flag)
4410 //!performs the pairing.. to whatever is currently connected, this means a message could make that happen
4411 //!for a device (ESP-32) with no user interface.
4413 else
4414 //! just unpair .. don't skip
4415 //!performs the unpairing
4417 }
4418 //! paireddev the paired device (used with BLEUsePairedDeviceName and gen3Only
4419 else if (strcasecmp(setCmdString,"pairdev")==0)
4420 {
4422 if (strcasecmp(valCmdString,previousName)!=0)
4423 {
4424 //different than current..
4425
4426 //!saves the pair device name TODO: the feed device should use the pair as well.. (DONE..)
4428
4429 //! paired address is null until found..
4430 //! Keep whatever is set ...???
4431 //! 8.16.25 BLE CLIENT
4432 //!if BLE connected, then we keep the address if any and GEN3
4434 {
4435 //keep the Address (but change the use supplied device name)
4436 }
4437 else
4438 {
4439 //! erase the ADDRESS (as well as new name) .. and disconnect if connected..
4442 //! try to disconnect..
4444 }
4445
4446#ifdef NO_MORE_PREFERENCE_BLE_USE_DISCOVERED_PAIRED_DEVICE_SETTING
4447 if (strlen(valCmdString)==0)
4448 {
4449 //!turn off pairing
4451
4452 }
4453#endif
4454 }
4455 } //pairdev
4456
4457 //! sets the PREFERENCE_SUPPORT_GROUPS_SETTING
4458 else if (strcasecmp(setCmdString,"usegroups")==0)
4459 {
4460 //! sets the PREFERENCE_SUPPORT_GROUPS_SETTING flag
4462
4463 //! reboot the device to set subscribe or not for groups
4465 }
4466 //! sets the PREFERENCE_GROUP_NAMES_SETTING
4467 else if (strcasecmp(setCmdString,"groups")==0)
4468 {
4469 //! sets the PREFERENCE_GROUP_NAMES_SETTING val (eg. atlasDogs, houndDogs) or (#) or ""
4471
4472 //! reboot the device to set subscribe or not for groups
4474
4475 }
4476 else
4477 foundCommand = false;
4478 } // device but not group
4479#pragma mark END of device and not group
4480 //! if not found, continue BNF options..
4481 if (!foundCommand)
4482 {
4483 //! rename device
4484 if (strcasecmp(setCmdString,"device")==0 && !isGroupTopic())
4485 {
4486 //define the device
4487 _deviceNameString = createCopy(valCmdString);
4489
4490 //!since renaming, lets set a STATUS out..
4491 //! request a STATUS be sent.
4492 processBarkletMessage("#STATUS", topic);
4493 }
4494
4495#ifdef ESP_M5
4496 else if (strcasecmp(setCmdString,"screencolor")==0)
4497 {
4498 //!set the screen color 0..n
4499 int screenColor = atoi(valCmdString);
4500 setScreenColor_displayModule(screenColor);
4501
4502 //stay on this page, but change the marker..
4504 }
4505 //! sets the gen3only flag (only look for BLEServers that are GEN3)
4506 else if (strcasecmp(setCmdString,"gen3only")==0)
4507 {
4508 if (deviceNameSpecified && !isGroupTopic())
4509 {
4510 //! sets the gen3only flag
4512 //!for now just reboot which will use this perference
4513 // rebootDevice_mainModule();
4514 //TODO... maybe just disconnect .. or don't worry about it unless connected
4515 }
4516 }
4517 //! BLEUsePairedDeviceName (Says to only look for BLEServers with the paired name..
4518 else if (strcasecmp(setCmdString,"BLEUsePairedDeviceName")==0)
4519 {
4520 if (deviceNameSpecified && !isGroupTopic())
4521 {
4522#ifdef NO_MORE_PREFERENCE_BLE_USE_DISCOVERED_PAIRED_DEVICE_SETTING
4523 //! sets the bleusepaireddevicename flag
4525#endif
4526 }
4527 }
4528#endif //ESP_M5
4529 //! sets the BLEUseDeviceName flag == the BLEServer will add the name, eg PTFeeder:ScoobyDoo
4530 else if (strcasecmp(setCmdString,"BLEUseDeviceName")==0)
4531 {
4532 if (deviceNameSpecified && !isGroupTopic())
4533 {
4534 //! sets the bleusedevicename flag
4536
4537 //!for now just reboot which will use this perference and re-create the service name..
4539
4540 //! 8.16.25 BLE CLIENT
4541 //! try to disconnect..
4542 // disconnect_BLEClientNetworking();
4543 }
4544 }
4545#ifdef ESP_M5
4546 else if (strcasecmp(setCmdString,"minMenu")==0)
4547 {
4548 SerialDebug.println("PREFERENCE_IS_MINIMAL_MENU_SETTING via BLE");
4549 if (flag)
4550 {
4553 }
4554 else
4555 {
4556 int max = minMenuModesMax_mainModule();
4557 //set to start of after min..
4559 }
4560 //!send message to ourself to process the current mode..
4562 }
4563 else if (strcasecmp(setCmdString,"addwifi")==0)
4564 {
4565 if (deviceNameSpecified && !isGroupTopic())
4566 {
4567 //has to support "Cisco:"
4568 //parse the valCmdString: ssid:password
4569 char str[100];
4570 strcpy(str,valCmdString);
4571 char *token;
4572 char *rest = str;
4573 char* ssid = strtok_r(rest,":", &rest);
4574 char* password = strtok_r(rest,":", &rest);
4575 SerialDebug.printf("addwifi %s, %s\n", ssid?ssid:"null", password?password:"");
4576 //now save as a credential
4577 // main_addWIFICredentials(addSSID, addPassword);
4578 //!send message to ourself to process the current mode..
4579 // invokeCurrentSMModePage(topic);
4580
4581 //NOTE: there can be empty passwords..
4582 char credentials[100];
4583 //!store the JSON version of these credentials..
4584 sprintf(credentials, "{'ssid':'%s','ssidPassword':'%s'}", ssid?ssid:"NULL", password?password:"");
4585 // This works by just sending the credentials to ourself .. and process correctly.
4586 SerialMin.println(credentials);
4587 //!per #224 this will also set WIFI_CREDENTIAL_2 (even if it's also setting #1)
4588 //!NOTE: this saving has to be done before calling processJSON (since the string is goofed upand == 'ssid' not the full string
4590
4591 //!now process the credentials, which will set CREDENTIAL_1
4593
4594 //!print the preferences to SerialDebug
4596
4597 //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..
4598 }
4599 }
4600 else if (strcasecmp(setCmdString,"usedocfollow")==0)
4601 {
4602 SerialDebug.printf("PREFERENCE_USE_DOC_FOLLOW_SETTING %s\n", valCmdString);
4604
4605 }
4606#endif //ESP)_M5
4607 else if (strcasecmp(setCmdString,"semanticMarker")==0)
4608 {
4609 SerialDebug.printf("SemanticMarker: %s\n", valCmdString);
4611
4612 //! 9.28.29 devOnlySM if set, then
4613 boolean showSM = true;
4615 showSM = deviceNameSpecified;
4616 if (showSM)
4617 // 9.27.23 also show this ..
4618 //! use the name/cat/uuid ..
4619 showSemanticMarker_displayModule(valCmdString, "Semantic Marker");
4620 else
4621 SerialDebug.println("Not showing SemanticMarker ");
4622 }
4623#ifdef ESP_M5
4624 //blankscreen on/off
4625 else if (strcasecmp(setCmdString,"blankscreen")==0)
4626 {
4627 //!if flag then blankscreen, otherwise wake the screen..
4628 if (flag)
4629 //!blanks the screen
4631 else
4632 //!wakes up the screen
4634 }
4635#endif //ESP_M5
4636
4637 //!8.17.22 SubDawgpack
4638 else if (strcasecmp(setCmdString,"SubDawgpack")==0)
4639 {
4640 if (deviceNameSpecified && !isGroupTopic())
4641 {
4642 SerialDebug.println("PREFERENCE_SUB_DAWGPACK_SETTING via BLE");
4644 //!for now just reboot which will use this perference
4645 //rebootDevice_mainModule();
4646 if (flag)
4647 {
4648 //! start a dawgpack subscription
4649 //! 8.15.22 Also subscribe to the dawgpack .. but restrict what it can effect.
4650 //! For example, start with STATUS and DOCFOLLOW
4651 _mqttClient.subscribe((char*)"usersP/dawgpack");
4652 }
4653 else
4654 {
4655 // unsubscribe (tested and it works)
4656 _mqttClient.unsubscribe((char*)"usersP/dawgpack");
4657 }
4658 }
4659 }
4660
4661 //!TODO: duplicate and depreciate these and replace with set:buzz,val:on
4662 else if (strcasecmp(setCmdString,"buzz")==0 && !isGroupTopic())
4663 {
4664 //! this uses the ASYNC since it involves a BLE command, and has to be done outside
4665 //! of this WIFI (MQTT) operation..
4666 if (flag)
4667 {
4668 SerialDebug.println("BUZZ:ON via BLE");
4670 }
4671 else
4672 {
4673 SerialDebug.println("BUZZ:OFF via BLE");
4675 }
4676 }
4677
4678
4679 //BLECLient
4680 else if (strcasecmp(setCmdString,"bleclient")==0)
4681 {
4682 if (deviceNameSpecified && !isGroupTopic())
4683 {
4684 SerialDebug.println("PREFERENCE_MAIN_BLE_CLIENT_VALUE via BLE");
4686 , flag);
4687 //!for now just reboot which will use this perference
4689 }
4690 }
4691 // bleserver
4692 else if (strcasecmp(setCmdString,"bleserver")==0)
4693 {
4694 if (deviceNameSpecified && !isGroupTopic())
4695 {
4696 SerialDebug.println("PREFERENCE_MAIN_BLE_SERVER_VALUE via BLE");
4698 //!for now just reboot which will use this perference
4700 }
4701 }
4702 else if (strcasecmp(setCmdString,"tilt")==0)
4703 {
4704 if (deviceNameSpecified && !isGroupTopic())
4705 {
4706 SerialDebug.println("PREFERENCE_SENSOR_TILT_VALUE via BLE");
4708 }
4709 }
4710#ifdef ESP_M5
4711
4712 else if (strcasecmp(setCmdString,"zoomSm")==0)
4713 {
4714 //!zoom == the NON semantic marker version.. so min menu is true
4715 if (flag)
4716 {
4717
4718 //hide semantic marker.. (but only if in the max menus)
4719 //NOTE: this only hides the Semantic Marker - if on a page that has one..
4720 SerialDebug.println("PREFERENCE_SEMANTIC_MARKER_ZOOMED_VALUE ON via BLE");
4722
4723 //!zoom only if in the max menu set..
4725 {
4726 //stay on this page, but change the marker..
4728 }
4729
4730 }
4731 else
4732 {
4733 //show semantic marker..
4734 //NOTE: this only shows the Semantic Marker - if on a page that has one..
4735 SerialDebug.println("PREFERENCE_SEMANTIC_MARKER_ZOOMED_VALUE OFF via BLE");
4738
4739 //!zoom only if in the max menu set..
4741 {
4742 //change to the status..
4744 //!send message to ourself to process the current mode..
4746 }
4747 else
4748 {
4749 //stay on this page, but change the zoom..
4751 }
4752 }
4753 } // zoomSM
4754 //! 9.22.22 added button press from messages..
4755 else if (strcasecmp(setCmdString,"buttonA")==0)
4756 {
4757 if (strcasecmp(valCmdString,"longpress")==0)
4759 else if (strcasecmp(valCmdString,"shortpress")==0)
4761 }
4762 else if (strcasecmp(setCmdString,"buttonB")==0)
4763 {
4764 if (strcasecmp(valCmdString,"longpress")==0)
4766 else if (strcasecmp(valCmdString,"shortpress")==0)
4768 }
4769 else if (strcasecmp(setCmdString,"M5AtomKind")==0 && !isGroupTopic())
4770 {
4771 //! new 1.4.24 setting ATOM kind (eg. M5AtomSocket, M5AtomScanner). MQTT message "set":"M5AtomKind", val=
4773
4774 //!for now just reboot which will use this perference
4776 }
4777#endif //ESP_M5
4778 else if (strcasecmp(setCmdString,"disk")==0)
4779 {
4780 SerialDebug.printf("Cloud DISK space = %s\n", valCmdString);
4781 }
4782 else if (strcasecmp(setCmdString,"feedcount")==0)
4783 {
4784 SerialDebug.printf("Global feed count = %s\n", valCmdString);
4785 }
4786 else
4787 {
4788 SerialMin.printf("2.Unknown cmd: %s (isGroupTopic=%d)\n", setCmdString, isGroupTopic());
4789 }
4790
4791 } // not found
4792 } // (setCmd && valCmd)
4793 //!5.24.22 send:<request> .. Note these are for cmd without an argument..
4794 else if (sendCmd)
4795 {
4796 //!NOTE: This will be calling ourself
4797
4798 char* sendCmdString = const_cast<char*>(sendCmd);
4799 //! 8.16.25 call the main to pass onto plugs
4800 messageSend_mainModule(sendCmdString, deviceNameSpecified);
4801
4802 if (strcasecmp(sendCmdString,"temp")==0)
4803 {
4804 SerialCall.println("sendCmd == temp");
4805 //! request a TEMP be sent.
4806 processBarkletMessage("#TEMP", topic);
4807 }
4808 else if (strcasecmp(sendCmdString,"status")==0)
4809 {
4810 SerialCall.println("sendCmd == status");
4811 //! request a STATUS be sent.
4812 processBarkletMessage("#STATUS", topic);
4813 }
4814
4815 else if (strcasecmp(sendCmdString,"capture")==0)
4816 {
4817 SerialCall.println("sendCmd == capture");
4818 //! request a CAPTURE be sent.
4819 processBarkletMessage("#CAPTURE", topic);
4820 }
4821
4822#ifdef ESP_M5
4823
4824 else if (strcasecmp(sendCmdString,"volume")==0)
4825 {
4826 SerialCall.println("sendCmd == volume (not implemented)");
4827 //! request a VOLUME be sent.
4828 processBarkletMessage("#VOLUME", topic);
4829 }
4830#endif //ESP_M5
4831 else
4832 {
4833 SerialTemp.print("Unknown send request: ");
4834 SerialTemp.println(sendCmdString);
4835 }
4836
4837 } //sendCmd
4838 //! 9.18.23 set64 with a val
4839 else if (set64Cmd)
4840 {
4841#ifdef ESP_M5
4842 //! currently 9.28.23 no reason for feeder to decode base64 messages. That could change if a stored procedure..
4843 char* setCmdString = const_cast<char*>(set64Cmd);
4844 char* valCmdString = const_cast<char*>(valCmd);
4845#ifdef DECODE_BASE64
4846 char plaintext_out[200];
4847 int len = strlen(valCmdString);
4848 if (len > 200)
4849 {
4850 SerialError.println("Length too long to base64 decode: 200");
4851 }
4852 else
4853 {
4854 int status = base64_decode_chars(valCmdString, len, plaintext_out);
4855 String decoded = String(plaintext_out);
4856 decoded = MQTT_urlDecode(decoded);
4857
4858 //! 1.11.24 the decoded value might have URL encoded like %7B for '{' and %7D }
4859 //! ACTUALLY the MQTT_urlDecode is missing the 7's
4860 //! https://www.arduino.cc/reference/en/language/variables/data-types/string/functions/indexof/
4861
4862 SerialDebug.println(decoded);
4863 // not case sensitive
4864 if (strcasecmp(setCmdString,"semanticMarker")==0 && !isGroupTopic())
4865 {
4866 //! see if docFollow .. if not then don't show it
4868
4869 //! 9.28.29 devOnlySM if set, then set to whether the deviceNameSpecified (eg. dev=...)
4870 boolean showSM = true;
4872 showSM = deviceNameSpecified;
4873
4874 if (!useDocFollow)
4875 showSM = false;
4876
4877 //! 1.11.24 NOTE: this changes the page on the M5 (and I'm sending this message often
4878 //! for a demo of the watch -- SO: maybe there should be a mode to NOT accept the SM ??
4879 if (showSM)
4880 //!displays the Semantic Marker (a super QR code) on the M5 screen (title = to display)
4881 showSemanticMarker_displayModule(decoded, "SemanticMarker");
4882 else
4883 SerialDebug.println("Not showing SemanticMarker ");
4884 }
4885 else if (strcasecmp(setCmdString,"PIR_SM_JSON")==0 && !isGroupTopic())
4886 {
4887 //! 1.11.24 support setting the SM to use with the PIR (and eventually other commands)
4888 //!@see https://github.com/konacurrents/ESP_IOT/issues/289
4889 //!{"set":"PIR_UseSM", "val": "on/off"}
4890 //!{"set64":"PIR_SM_JSON", "val": "JSONbase64"}
4891 //! NOTE: this could turn on the PIR_UseSM at the same time..
4892
4895 //!let others know ??
4896 // sendMessageString_mainModule(decoded.c_str());
4897 }
4898 else if (strcasecmp(setCmdString,"PIR_OFF_SM_JSON")==0 && !isGroupTopic())
4899 {
4900 //! 1.11.24 support setting the SM to use with the PIR (and eventually other commands)
4901 //!@see https://github.com/konacurrents/ESP_IOT/issues/289
4902 //!{"set":"PIR_UseSM", "val": "on/off"}
4903 //!{"set64":"PIR_SM_JSON", "val": "JSONbase64"}
4904 //! NOTE: this could turn on the PIR_UseSM at the same time..
4905
4908 //!let others know ??
4909 // sendMessageString_mainModule(decoded.c_str());
4910 }
4911
4912 //! 3.22.25 Returned stranded from space station
4913 //! if ScannedSemanticMarker .. call the set
4914 else if (strcasecmp(setCmdString,"ScannedSemanticMarker")==0)
4915 {
4916 //! 12.27.23 pass this onto those registered (which mainModule is handling..)
4917 //! 8.28.23 Tell Main about the set,val and if others are registered .. then get informed
4918 //! 1.10.24 if deviceNameSpecified then this matches this device, otherwise for all.
4919 //! It's up to the receiver to decide if it has to be specified
4920 //! 1.14.24 for now, setVal in the ATOM will support GROUP commands if turned on (and if off it doesn't get here)
4921 char * my_argument = const_cast<char*> (decoded.c_str());
4922 messageSetVal_mainModule(setCmdString, my_argument, deviceNameSpecified);
4923 }
4924
4925 }
4926
4927#endif //DECODE_BASE64
4928#endif //ESP_M5
4929
4930 }
4931
4932 //!NOTE: if teh command isn't recognized .. then it slips through.. and is treaded like
4933 //!this return is important!!!
4934 return true;
4935 } //!end process commands..
4936
4937 //! ISSUE: when new JSON shows up that isn't process above, it's thought to be setting the credentials.
4938 //! Thus the {set64} continues below..
4939
4940
4941 //end NEW
4942 //!TRY without 1.30.22 (RAMS win) and it works..
4943 //!9.17.23 .. RAMS loose to 49rs in LA (we are in LA)
4944 //!if can talk BLE, then reboot.. 2.2.22
4945
4946 //NOTE: here is where different reasons for the info could be provided in the data>
4947 // eg. dataKind (wifi, mqtt, etc...)boot
4948 /**
4949 {
4950 "ssid" : "SunnyWhiteriver",
4951 "ssidPassword" : "sunny2021",
4952 "mqtt_topic": "usersP/bark/test",
4953 "mqtt_user" : "test",
4954 "deviceName" : "HowieFeeder",
4955 "mqtt_password" : "password..",
4956 "mqtt_guestPassword" : "password",
4957 "uuid" : "scott",
4958 "mqtt_port" : "1883",
4959 "mqtt_server" : "idogwatch.com",
4960 "mqtt_status" : "Success",
4961 "location": "whatever to reply with, GPS, state, city, etc.."
4962 }
4963
4964 //todo pass the guest password too
4965 */
4966 //TODO: parse the string...
4967 //!! Store wifi config. 存储wifi配置信息
4968 //! @see https://arduinojson.org
4969
4970//! THE CHALLENGE: if send use {ssid, ssidPassword} .. it will assume others
4971//! SO .. only null out the value if (1) there is an attributed {ssid} and empty string..
4972//#define ONLY_NULL_IF_THERE
4973#ifdef ONLY_NULL_IF_THERE
4974 SerialDebug.println(" *** processMQTT .. treat like credentials");
4975 {
4976 const char* a1 = myObject["ssid"];
4977 if (a1)
4978 {
4979 _ssidString = const_cast<char*>(a1);
4981 }
4982
4983 SerialTemp.printf("myObject[ssid] = '%s'\n", a1?a1:"EMPTY");
4984 //SerialTemp.println(a1);
4985 SerialTemp.println(_ssidString);
4986 }
4987
4988 {
4989 const char* a2 = myObject["ssidPassword"];
4990 if (a2)
4991 {
4992 _ssidPasswordString = const_cast<char*>(a2);
4994 }
4995
4996 }
4997#else
4998 SerialDebug.println(" *** processMQTT .. treat like credentials");
4999 {
5000 const char* a1 = myObject["ssid"];
5001 if (a1 && strlen(a1)>0)
5002 {
5003 _ssidString = const_cast<char*>(a1);
5005 }
5006 else
5007 _ssidString = NULL;
5008 SerialTemp.printf("myObject[ssid] = '%s'\n", a1?a1:"EMPTY");
5009 //SerialTemp.println(a1);
5010 SerialTemp.println(_ssidString);
5011 }
5012
5013 {
5014 const char* a2 = myObject["ssidPassword"];
5015 if (a2 && strlen(a2)>0)
5016 {
5017 _ssidPasswordString = const_cast<char*>(a2);
5019 }
5020 else
5021 _ssidPasswordString = NULL;
5022 }
5023#endif
5024 {
5025 //!5.25.22 (50 years since Grateful Dead London Show
5026
5027 //! To support just setting the ssid and password, a JSON
5028 //! of {ssid:s,ssidPassword:p} is supported, so don't null out if mqtt aren't provided..
5029 //! this should work (since the SSID is what's checked to go to the AP mode)
5030
5031 //!the MQTT host/port/user/password (topic is created in this code...)
5032 const char* a3 = myObject["mqtt_server"];
5033 if (a3)
5034 {
5035 _mqttServerString = const_cast<char*>(a3);
5037 }
5038 // else
5039 // _mqttServerString = NULL;
5040 }
5041 {
5042 const char* a4 = myObject["mqtt_port"];
5043 if (a4)
5044 {
5045 _mqttPortString = const_cast<char*>(a4);
5047 }
5048 // else
5049 // _mqttPortString = NULL;
5050 //
5051 }
5052 {
5053 const char* a5 = myObject["mqtt_password"];
5054 if (a5)
5055 {
5056 _mqttPasswordString = const_cast<char*>(a5);
5058 }
5059 // else
5060 // _mqttPasswordString = NULL;
5061 }
5062
5063 {
5064 const char* a6 = myObject["mqtt_user"];
5065 if (a6)
5066 {
5067 _mqttUserString = const_cast<char*>(a6);
5069 }
5070 // else
5071 // _mqttUserString = NULL;
5072 }
5073 {
5074 //! This should keep the deviceName to whatever was specified
5075 const char* a7 = myObject["deviceName"];
5076 if (a7 && strlen(a7)>0)
5077 {
5078 _deviceNameString = const_cast<char*>(a7);
5080 }
5081 // else
5082 // _deviceNameString = NULL;
5083 }
5084 {
5085 const char* a8 = myObject["uuid"];
5086#ifdef NOT_ORIGINAL
5087 if (a8 && strlen(a8)>0)
5088#else
5089 if (a8)
5090#endif
5091 {
5092 _uuidString = const_cast<char*>(a8);
5094 }
5095 // else
5096 // _uuidString = NULL;
5097 }
5098 {
5099 const char* a9 = myObject["mqtt_topic"];
5100#ifdef NOT_ORIGINAL
5101 if (a9 && strlen(a9)>0)
5102#else
5103 if (a9)
5104#endif
5105 {
5106 _mqttTopicString = const_cast<char*>(a9);
5108 }
5109 // else
5110 // _mqttTopicString = NULL;
5111
5112 }
5113 {
5114 const char* a10 = myObject["mqtt_guestPassword"];
5115#ifdef NOT_ORIGINAL
5116 if (a10 && strlen(a10)>0)
5117#else
5118 if (a10)
5119#endif
5120 {
5121 _mqttGuestPasswordString = const_cast<char*>(a10);
5123 }
5124 // else
5125 // _mqttGuestPasswordString = NULL;
5126 }
5127
5128 {
5129 const char* a11 = myObject["location"];
5130 if (a11 && strlen(a11)>0)
5131 {
5132 _jsonLocationString = const_cast<char*>(a11);
5134 }
5135 // else
5136 // _mqttGuestPasswordString = NULL;
5137 }
5138
5139 //!reset the MQTT attempts
5141
5142 boolean saveJSONPreferences = true;
5143 //!setup the WIFI if the ssid string (at least) is specified
5145 {
5146 SerialDebug.println("Setting WIFI from JSON parameters");
5147 //setupWIFI(_ssidString, _ssidPasswordString);
5148
5149 //!new: go out and let the process work...
5150 //!set the state, then the 'loop' will call setupWIF(...)
5153
5154 }
5155 else
5156 {
5157 SerialDebug.println(" ***** ERROR .. no ssidString *** ");
5158 //!call the callback specified from the caller (eg. NimBLE_PetTutor_Server .. or others)
5160
5161 saveJSONPreferences = false;
5162 }
5163
5164
5165 //!don't save the preferences, since it didn't have enough information..
5166 if (!saveJSONPreferences)
5167 {
5168 SerialDebug.println("**** Not saving JSON in preferences ***");
5169 return true;
5170 }
5171
5172 //!NOTE: this writes over entire values, since it's a string vs an JSON object
5174
5175 //!new 4.8.22 .. trying to kick out of AP mode if the credentials are good..
5177
5178 //!putting here .. time might have gone too fast..
5181
5182
5183 return true;
5184}
5185
5186//!restart the WIFI and then MQTT connection
5188{
5189 //let it know MQTT isn't running either
5190 _MQTTRunning = false;
5191
5192 SerialTemp.printf("restartWIFI_MQTTState (%s, %s)\n", _ssidString?_ssidString:"NULL", _ssidPasswordString?_ssidPasswordString:"NULL");
5193//#define TRY_EXIT2
5194#ifdef TRY_EXIT2
5195 //! 9.19.23 before Van Morrison ..
5196 if (!_ssidString || (_ssidString && strlen(_ssidString)==0))
5197 {
5198 SerialDebug.println("set disconnectedWIFI and stopDelay");
5199 //putting here .. time might have gone too fast..
5202 return;
5203 }
5204#endif
5205 //putting here .. time might have gone too fast..
5208}
5209
5210//! 9.18.23 LA (after Eagle Rock bike ride, Van Morrison tomorrow)
5212{
5213 SerialDebug.println("cleanMQTTpasswordsUpdateInEPROM");
5214 _ssidString = NULL;
5215 _mqttPasswordString = NULL;
5217
5218 //!now update the eprom with these null values
5220}
5221
5222//!just update the EPROM, and send that to the WIFI_AP module as well
5224{
5225 SerialDebug.printf("updatePreferencesInEPROM (mqtt-pass=%s)\n",_mqttPasswordString?_mqttPasswordString:"NULL");
5226
5227 DynamicJsonDocument myObject(1024);
5228
5229 //!basically if only the ssid/pass are sent, that is all that's written to EPROM
5230 //!even if the other information is available.. So recreate the JSON instead..
5231 //!seems c++ you cannot re-use output as it just appends to it.. unreal
5232 String output2;
5233#ifdef NOT_ORIGINAL
5234 myObject["ssid"] = _ssidString?_ssidString:"";
5235 myObject["ssidPassword"] = _ssidPasswordString?_ssidPasswordString:"";
5236 myObject["mqtt_server"] = _mqttServerString;
5237 myObject["mqtt_port"] = _mqttPortString;
5238 myObject["mqtt_password"] = _mqttPasswordString?_mqttPasswordString:"";
5239 myObject["mqtt_guestPassword"] = _mqttGuestPasswordString?_mqttGuestPasswordString:"";
5240#else
5241 myObject["ssid"] = _ssidString;
5242 myObject["ssidPassword"] = _ssidPasswordString;
5243 myObject["mqtt_server"] = _mqttServerString;
5244 myObject["mqtt_port"] = _mqttPortString;
5245 myObject["mqtt_password"] = _mqttPasswordString;
5246 myObject["mqtt_guestPassword"] = _mqttGuestPasswordString;
5247#endif
5248 myObject["mqtt_user"] = _mqttUserString;
5249 {
5250 char buf[100];
5251 sprintf(buf,"usersP/bark/%s", _mqttUserString?_mqttUserString:"NOTSET");
5253 }
5254 myObject["mqtt_topic"] = _mqttTopicString;
5255 myObject["deviceName"] = _deviceNameString;
5256 myObject["uuid"] = _uuidString;
5257 myObject["jsonHeader"] = _jsonHeaderString;
5258 myObject["jsonVersion"] = _jsonVersionString;
5259 myObject["location"] = _jsonLocationString;
5260
5261
5262 //!JSON
5263 serializeJson(myObject, output2);
5264
5265 //!open the preferences
5267 SerialDebug.print("MQTTNetworking.Writing EPROM JSON = '");
5268 SerialDebug.print(output2);
5269 SerialDebug.println("'");
5270
5271 //!save in EPROM
5273 //! Close the Preferences
5275
5276 //! sets the MQTT user/password. It's up to the code to decide who needs to know (currently saves in the WIFI_APModule
5278#define NO_NEED_AND_GRU_CRASH
5279#ifdef NO_NEED_AND_GRU_CRASH
5280 //!NEW: 2.21.22
5281 //!TRY: reading back..
5282 _preferencesMQTTNetworking.begin(ESP_EPROM_NAME, false); //false=read/write..
5284 SerialDebug.print("Reading.2 EPROM JSON = ");
5285 SerialDebug.println(_fullJSONString? _fullJSONString:"NULL");
5286
5287 //!check ... _fullMessageOut
5288 //! Close the Preferences
5290#endif
5291}
5292
5293
5294
5295//!Decode the URL
5296//!@see https://www.w3schools.com/tags/ref_urlencode.ASP
5297String MQTT_urlDecode(String input) {
5298 String s = input;
5299 s.replace("%20", " ");
5300 s.replace("+", " ");
5301 s.replace("%21", "!");
5302 s.replace("%22", "\"");
5303 s.replace("%23", "#");
5304 s.replace("%24", "$");
5305 s.replace("%25", "%");
5306 s.replace("%26", "&");
5307 s.replace("%27", "\'");
5308 s.replace("%28", "(");
5309 s.replace("%29", ")");
5310 s.replace("%30", "*");
5311 s.replace("%31", "+");
5312 s.replace("%2C", ",");
5313 s.replace("%2E", ".");
5314 s.replace("%2F", "/");
5315 s.replace("%2C", ",");
5316 s.replace("%3A", ":");
5317 s.replace("%3B", ";");
5318 s.replace("%3C", "<");
5319 s.replace("%3D", "=");
5320 s.replace("%3E", ">");
5321 s.replace("%3F", "?");
5322 s.replace("%40", "@");
5323 s.replace("%5B", "[");
5324 s.replace("%5C", "\\");
5325 s.replace("%5D", "]");
5326 s.replace("%5E", "^");
5327 s.replace("%5F", "-");
5328 s.replace("%60", "`");
5329 s.replace("%7B", "{");
5330 s.replace("%7D", "}");
5331
5332 return s;
5333}
5334
boolean isConnectedBLEClient()
returns whether connected over BLE as a client to a server(like a ESP feeder)
void disconnect_BLEClientNetworking()
try to disconnect..
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:582
#define CALLBACKS_MQTT
8.16.25 MQTT
Definition: MainModule.cpp:420
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:641
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()
Definition: MainModule.cpp:853
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:396
void callCallbackMain(int callbacksModuleId, int callbackType, char *message)
performs the indirect callback based on the callbackType
Definition: MainModule.cpp:531
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:361
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
Definition: MainModule.cpp:794
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:560
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)
Definition: MainModule.cpp:806
char * main_nextJSONWIFICredential()
! cycle through the next WIFI saved credential
Definition: MainModule.cpp:910
#define SM_home_simple
Definition: MainModule.h:357
#define SM_pair_dev
guest feed device
Definition: MainModule.h:381
#define THRESHOLD_KIND_DARK
Definition: MainModule.h:74
#define SM_guest_feed
guest feed
Definition: MainModule.h:379
#define SM_guest_page
guest page
Definition: MainModule.h:372
#define SM_timer
timer .. todo
Definition: MainModule.h:388
#define SM_home_simple_1
Definition: MainModule.h:358
#define SM_home_simple_2
Definition: MainModule.h:359
#define SM_status
//status
Definition: MainModule.h:368
#define ASYNC_SET_GATEWAY_ON
sets the GATEWAY mode on
Definition: MainModule.h:208
#define SM_reboot
REboot.
Definition: MainModule.h:390
#define SM_help
HELP.
Definition: MainModule.h:383
#define ASYNC_CALL_BUZZ_ON
sends a 'B' to the BLE end of the code (assuming a feeder is connected).
Definition: MainModule.h:199
#define ASYNC_POWEROFF
sets the GATEWAY mode off
Definition: MainModule.h:215
#define ASYNC_CALL_CLEAN_EPROM
cleans the EPROM totally, and reboots
Definition: MainModule.h:195
#define ASYNC_SEND_MQTT_STATUS_URL_MESSAGE
sends the status from the main module URL
Definition: MainModule.h:205
#define SM_home_simple_3
Definition: MainModule.h:360
#define ASYNC_SET_GATEWAY_OFF
sets the GATEWAY mode off
Definition: MainModule.h:210
#define ASYNC_CALL_OTA_FILE_UPDATE_PARAMETER
these are the async with a string parameter
Definition: MainModule.h:233
#define ASYNC_CALL_OTA_UPDATE
TODO: make this a registeration approach.
Definition: MainModule.h:191
#define SM_doc_follow
docfollow
Definition: MainModule.h:386
#define SM_smart_clicker_homepage
//! homepage
Definition: MainModule.h:366
#define TOPIC_TO_SEND
Definition: MainModule.h:61
#define SM_WIFI_ssid
WIFI ssid.
Definition: MainModule.h:370
#define SM_ap_mode
AP MODE.
Definition: MainModule.h:375
#define ASYNC_CALL_BUZZ_OFF
sends a 'b' to the BLE end of the code (assuming a feeder is connected).
Definition: MainModule.h:201
#define ASYNC_CLICK_SOUND
5.15.25 add a BUZZ command (or CLICK)
Definition: MainModule.h:226
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_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_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