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
18#include <HTTPClient.h>
19#endif //USE_CAMERA_MODULE
20
21//!@see https://www.carletonsheets.com/assets/shared/usr/share/doc/doxygen-1.8.5/html/commands.html#cmdlink
22
23//!Ambers 22nd birthday.. 2.20.22
24
25/**
26 Testing:
27 1. the bootstrap of MQTT
28 1.a use a bad password and bad user
29 1.b see if it stops trying after a MAX tries
30 2. send the credentials over BLE
31 2.a use a bad password and bad user
32 2.b see if it stops trying after MAX tries
33 3. have a bad WIFI (so it won't connect)
34 3.a see if it stops trying after a bit
35 4. has valid WIFI and MQTT
36 4.1 see it connects
37 5. Using BOOTSTRAP
38 5.a see if it connects
39 5.b turn off BOOTSTRAP - re-upload script
40 5.c see if it reads the EPROM correctly
41 TODO: send status information back over BLE since iPhone has a UI to troubleshoot..
42 */
43
44#include "MQTTNetworking.h"
45
46#define ESP_EPROM_NAME "ESP32"
47
48
49#ifdef USE_MQTT_NETWORKING
50#include "OTAImageUpdate.h"
51
52/*******************************MQTT*************************************/
53//!added 1.1.2022 by iDogWatch.com
54//!CURRENTLY, this code below only has constant: usersP/bark as a super subscription
55//!This could be passed in via JSON later..
56
57//https://www.arduino.cc/en/Reference/BLECharacteristicConstructor
58
59//! 3.3.22 Using the new JSON library which is supposed to catch syntax errors without blowing up
60//https://arduinojson.org/?utm_source=meta&utm_medium=library.properties
61#include <ArduinoJson.h>
62
63//the EPROM is in preferences.h
64#include <Preferences.h>
65
66#include <WiFi.h>
67#include <PubSubClient.h>
68
69// wifi config store. wifi配置存储的类
71
72//Can't seem to reuse this as a global .. it gets appended to, etc.
73//DynamicJsonDocument myObject(1024);
74
75//!just update the EPROM, and send that to the WIFI_AP module as well
77
78//!setup the WIFI using ssid and password
79void setupWIFI(char * arg_ssid, char * arg_password);
80
81//reset on success
83//this is the number of times to retry again, after trying WIFI again..
84#define MAXglobalMQTTAttempts 10 //2
85// the number of times to retry MQTT before trying WIFI again (then only MAXglobalMQTTAttemtt
86#define MAX_MQTT_ATTEMPTS 10 //4
87
88//max times to try the WIFI before attempting again..
89#define MAX_WIFI_CONNECT_ATTEMPTS 30
90
91//forward declarations
92//!process an MQTT message looking for keywords (barklet language)
93void processBarkletMessage(String message, String topic);
94
95//!setup the MQTT server
96void setupMQTT(char* mqttServerString, char *mqttPortString, char *mqttPasswordString, char *mqttUserString, char *deviceNameString, char *uuidString); //forward
97
98//!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)
99boolean processJSONMessageMQTT(char *ascii, char *topic);
100
101//check for MQTT messages???
103
104
105//!blinks the blue light
106void blinkBlueLightMQTT();
107
108//called to setup the MQTT (which is really the _mqttClient setup). Done on it's own thread..
109void callPreSetupMQTT();
110
111//!setup the WIFI
112//void setup_WIFI(char *ssidString, char *ssidPasswordString);
113
114//!read any values from EPROM
116
117//!uptime since last reboot.
119
120//Methods: setupMQTT();
121// checkMQTTMessages_loop()
122
123#define OTA "#OTA"
124
125#define STATUS "#STATUS"
126//NOTE: the "Me" names are known and keep them..
127#define REMOTE "#remoteMe"
128#define REMOTE2 "#REMOTE"
129#define FEED "#FEED"
130#define FEED_2 "#feedme"
131#define ACK_FEED "#actMe"
132#define ACK_FEED2 "#ackMe"
133#define CONNECTED "#connectedMe"
134#define NOT_CONNECTED "#noconnectedMe"
135#define NO_ACK_FEED "#noactMe"
136#define PLAY_ME "#playMe"
137#define DOCFOLLOW "#docFollow"
138#define DOCFOLLOW2 "#DOCFOLLOW"
139#define DOCSYNC "#docSync"
140#define NO_CAN "#NO_CAN"
141//!DOCFOLLOW syntax 8.11.22
142//! syntax: #followMe {AVM=<avm address>} .. no quotes
143#define FOLLOW_ME "#followMe"
144
145//!The WIFI client
146WiFiClient _espClient;
147
148//!The PubSub MQTT Client
150
153
154
155// *********************** METHODS invoked from BLE (JSON) and MQTT messages ***************
156//!perform the OTA update. This calls the OTAImageUpdate methods (via preformOTAUpdateSimple())
158//!calls the method for cleaning the SSID eprom. This calls the WIFI_APModule callback
160//!calls the FEED message via the callback (which calls the BLE code)
161void performFeedMethod(char* topic);
162
163// *********************** END SPECIFICATION AND GLOBAL VARIABLES ******
164
165//!returns seconds since first booted
167{
169 return uptime;
170}
171
172//!define here as well.. NOTE: this could be passed is as well... TODO
173
174
175// NTP server to request epoch time
176const char* _ntpServer = "pool.ntp.org";
177
178// flag that the MQTT is running..
179boolean _MQTTRunning = false;
180
181//!define this storage once, and use everwhere..
182#define MAX_MESSAGE 600
183//!message received on subscription
185//! message to send out
187
189
190//!Points to strings read from JSON (limited to 15 char key name)
191#define _preferencesJSONName "JSONPrefs"
205
206//!this is sent from the backend as a message {'guest':'guest password'} .. but lets' add to the credentials..
207//char* _mqttGuestPasswordString = NULL;
208
209
210//! whether message should be skipped for display and debug printouts
211//! uses _fullMessageIn global
213{
214 boolean skip = false;
219 skip = true;
220 return skip;
221}
222
223//!the publishMQTTMessage is placed here as a placeholder for making the mqtt publish. If needed, this could be moved
224//!to another thread (or the next loop)
225#define TRY_MORE_ASYNC_PROCESSING
226#ifdef TRY_MORE_ASYNC_PROCESSING
227//! 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??
228void publishMQTTMessage(char *topic, char *message)
229{
230
231
232 SerialMin.printf("Publish message(%s): %s\n",topic, message);
234 {
235 SerialMin.println(" *** MQTT not connected .. message will queue until connected (hopefully)" );
236 }
237 //!publish on the mqttClient object
238 _mqttClient.publish(topic, message);
239
240 //!see if this pushs the publish out.. (otherwise a reply might occure .. an break our _fullMessage)
241 //_mqttClient.loop();
242
243}
244#endif
245
246
247//! Wrapper of the mqttclient publish
249{
251}
252
253#ifdef USE_CAMERA_MODULE
254
255//! Users/scott/Library/Arduino15/packages/m5stack/hardware/esp32/2.0.3/tools/sdk
256#include "esp_camera.h"
257#include "FS.h" // SD Card ESP32
258
259#endif
260//! publish a binary file..
261void publishBinaryFile(char *topic, uint8_t * buf, size_t len)
262{
263 SerialMin.printf("Publish binary file(%s), len=%d\n", topic, len);
264 // _mqttClient.publish(_mqttTopicString, buf, len);
265 //!https://randomnerdtutorials.com/esp32-http-get-post-arduino/
266 //!https://randomnerdtutorials.com/esp32-cam-post-image-photo-server/
267 //!https://raw.githubusercontent.com/RuiSantosdotme/ESP32-CAM-Arduino-IDE/master/ESP32-CAM-HTTP-POST-Image/ESP32-CAM-HTTP-POST-Image.ino
268 //! Lets do a POSt to my whats-this site..
269#ifdef USE_CAMERA_MODULE
270
271#define NEW_WAY
272#ifdef NEW_WAY
273 //!create a WIFI client that talks to just our upload servlet
274 WiFiClient postClient;
275
276 String serverName = "knowledgeshark.me"; // REPLACE WITH YOUR Raspberry Pi IP ADDRESS
277 //String serverName = "example.com"; // OR REPLACE WITH YOUR DOMAIN NAME
278 String serverPath = "/examples/servlets/UploadServlet";
279 //!tomcat server.. 8080
280 int serverPort = 8080;
281 SerialDebug.println("Connecting to server: " + serverName);
282
283 if (postClient.connect(serverName.c_str(), serverPort))
284 {
285 SerialDebug.printf("Connection successful! len = %d\n", len);
286 String filename = "esp32-cam-" + String(getDeviceNameMQTT()) + "-" + String(random(0xffff), HEX) + ".jpg";
287 String head = "--KonaCurrents\r\nContent-Disposition: form-data; name=\"imageFile\"; filename=\"" +
288 filename + "\"\r\nContent-Type: image/jpeg\r\n\r\n";
289 String tail = "\r\n--KonaCurrents--\r\n";
290
291 uint32_t imageLen = len;
292 uint32_t extraLen = head.length() + tail.length();
293 uint32_t totalLen = imageLen + extraLen;
294
295 postClient.println("POST " + serverPath + " HTTP/1.1");
296 postClient.println("Host: " + serverName);
297 postClient.println("Content-Length: " + String(totalLen));
298 postClient.println("Content-Type: multipart/form-data; boundary=KonaCurrents");
299 postClient.println();
300 postClient.print(head);
301
302 uint8_t *fbBuf = buf;
303 size_t fbLen = len;
304 for (size_t n=0; n<fbLen; n=n+1024)
305 {
306 if (n+1024 < fbLen)
307 {
308 postClient.write(fbBuf, 1024);
309 fbBuf += 1024;
310 }
311 else if (fbLen%1024>0)
312 {
313 size_t remainder = fbLen%1024;
314 postClient.write(fbBuf, remainder);
315 }
316 }
317 postClient.print(tail);
318 //!stop this client (it's recreated each publish)
319 postClient.stop();
320
321 //! WORKS FIRST TIME FROM M5 Camera, to tomcat on KnowledgeShark: 9.17.22
322 //!publish location of this file.
323 //String fileURL = "http://" + serverName + ":" + String(serverPort) + "/examples/uploads/" + filename;
324 //!send this out as a DOCFOLLOW message (but different syntax)
325
326 sprintf(_semanticMarkerString,"#url {%s} {http://%s:%d/examples/uploads/%s}", getDeviceNameMQTT(), &serverName[0], serverPort, &filename[0]);
327 //sendSemanticMarkerDocFollow_mainModule(&fileURL[0]);
328 //! for now only send if it start message starts with "#"
330 //seems to be sent 2 times ...
331 }
332 else
333 {
334 SerialDebug.printf("Connection NOT successful! ");
335 }
336
337
338#endif //newway
339
340#endif
341}
342
343//! These are set by the MQTT callback..
344//! flag to let the processor know there are new messages
346//! the topic the new message came in on..
347String _topic;
348
349//!storage for the full JSON message string to send around..
351
352//! retrieve the Configuration JSON string in JSON format..
354{
355 return _fullJSONString;
356}
357
358//!callback with the message if required (like sending the FEED message)
359//!!function pointers: https://www.cprogramming.com/tutorial/function-pointers.html
360//!define as: void callback(char* message)
361//! call processMessage(message, &callback);
362//void setMessageCallbacks(void (*callbackFunction)(char*), void (*blinkTheLED)())
363
364
365//!called for things like the advertisement
367{
369 _deviceNameString = NOTSET_STRING;
370 return _deviceNameString;
371 // return _chipName;
372}
373
374
375uint32_t _chipId = 0;
376char _chipName[50];
377
378//!create a unique ID (but it needs to be stored.. otherwise it's unique each time??
380{
381
382 //get chip ID
383 for (int i = 0; i < 17; i = i + 8) {
384 _chipId |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i;
385 }
386
388 sprintf(_chipName, "%s-%d", _deviceNameString, _chipId);
389 else
390 sprintf(_chipName, "esp.%d", _chipId);
391
392 //chipName = "esp." + chipId;
393 SerialInfo.println(_chipName);
394
395}
396
397//!This uses the String (*getStatusFunc)(void)) to re-create this..
398//!used by the displayModule to call this for each new status
400{
401 //Make URL for the status..
402 char *statusString = main_currentStatusURL();
403
404 // sprintf(_semanticMarkerString,"%s/%s/%s/%s", "https://SemanticMarker.org/bot/sensor", _mqttUserString, _mqttGuestPasswordString, statusString);
405 //shorten..
406 sprintf(_semanticMarkerString,"%s/%s", "https://SemanticMarker.org/bot", statusString);
407
408 SerialLots.print("getDynamicStatusFunc: ");
409 SerialLots.println(_semanticMarkerString);
410
412}
413//!examples
414//!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
415//!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
416
417//!storage for last doc follow semantic marker
419//! retrieves the last DocFollow SemanticMarker (from the message #DOCFOLLOW | #followMe {AVM=<SM>}
420//! Or the JSON: {'set':'semanticMarker','val','<URL>}
422{
424}
425
426//! sets the last DocFollow SemanticMarker
428{
429 strcpy(_lastDocFollowSemanticMarker, semanticMarker);
430}
431
432//! a counter to erase the last message if not changed in N calls..
434//!storage of the last message status
436
437//! Put all the storage initialization here..
439{
440 strcpy(_lastMessageStatusURL,"startup");
441 strcpy(_lastDocFollowSemanticMarker,"https://SemanticMarker.org");
442}
443
444//! retrieves a token string.. without spaces.
445//! Currently this will be things like
446void setLastMessageStatus(char *token)
447{
448 SerialLots.print("setLastMessageStatus: ");
449 SerialLots.println(token);
451
452 char *deviceName = getDeviceNameMQTT();
453 //! add just the version and device name to start, but add the msg=
454 sprintf(_lastMessageStatusURL,"status?v=%s&dev=%s&msg=",VERSION_SHORT, deviceName);
455
456 //! Make up a shorter version of the message
457 if (strcasecmp(token,"FEED")==0)
458 strcat(_lastMessageStatusURL,"FEED");
459 else if (strcasecmp(token,"STATUS")==0)
460 strcat(_lastMessageStatusURL,"STATUS");
461 else
462 strcat(_lastMessageStatusURL, "none");
463 //!TODO: make sure no spaces ... unless escaped
464
465 SerialTemp.println(_lastMessageStatusURL);
466}
467
468//!empty the status message
470{
472 setLastMessageStatus((char*)"none");
473}
474
475//!returns a string in in URL so: status?battery=84'&buzzon='off' } .. etc
477{
478 //!increment the count
480 //5 (counts) seconds since a change..
482 {
484 }
486}
487
488//!used by the displayModule to call this for each new status
490{
491 //Make URL for the status..
492 char *statusString = currentMessageStatusURL();
493
494 // sprintf(_semanticMarkerString,"%s/%s/%s/%s", "https://SemanticMarker.org/bot/sensor", _mqttUserString, _mqttGuestPasswordString, statusString);
495 //shorten..
496 sprintf(_semanticMarkerString,"%s/%s", "https://SemanticMarker.org/bot", statusString);
497
498 SerialTemp.print("getDynamicMessageFunc: ");
499 SerialTemp.println(_semanticMarkerString);
500
502}
503
504//! 4.26.22 50 year anniverssery of Grateful Dead in Frankfurt 1972
505#define WIFI_MQTT_STATES
506#ifdef WIFI_MQTT_STATES
507
508//!the loop part of WIFI
509void setupWIFI_loop();
510//!end of WIFI loop..
511void finishWIFI_Setup();
512//!reconnects and re-subscribes
513//!NOTE: we need the host info...
514void reconnectMQTT_loop();
515
516//!state variables
518{
519 // presetup WIFI
521 //in a wait for WIFI mode
523 //called to start the mqttClient (out of this thread)
525 //in a wait for MQTT mode
527 // all connected WIFI
529 // connectged MQTT
531 //all disconnected WIFI
533 //all disconnected MQTT
536//!the state we are in..
538//!the delay in seconds for each state
540{
541 [preSetupWIFI] = 0.1,
542 [waitingForWIFI]=0.3,
543 [preSetupMQTT]=0.1,
544 [waitingForMQTT]=0.2,
545 [connectedWIFI]=0,
546 [connectedMQTT]=0,
549
550};
551
552
553//https://www.forward.com.au/pfod/ArduinoProgramming/TimingDelaysInArduino.html
554//! the time the delay started
556//! true if still waiting for delay to finish
558//! length of delay
560//!init the delay, this uses the array of delays so we can change easier..
562{
563 float seconds = _WIFI_MQTTStateDelays[_WIFI_MQTTState];
564 SerialLots.printf("startDelay_WIFI_MQTTState(%f)\n", seconds);
565 _delayStart_WIFI_MQTTState = millis(); // start delay
566 _delayRunning_WIFI_MQTTState = true; // not finished yet
568
569}
570//!if finished..
572{
574 {
576 return true;
577 }
578 return false;
579}
580
581//!stop the delay
583{
585}
586
587#endif //MQTT STATES
588
589// *********************** END METHODS invoked from BLE (JSON) and MQTT messages ***************
590
591//!try a flag so setupMQTTnetworking only called 1 times..
593
594//!setup the MQTT part of networking
596{
597 SerialDebug.println("setup_MQTTNetworking");
598
599 //make this non reentrant (only 1 time in a boot of ESP)
601 {
602 SerialDebug.println("setupMQTTNetworking already setup..");
603 return;
604 }
605 //!init variables..
607
608 // initLastMessageStatusURL();
609
610 SerialDebug.println(" .. continue setup_MQTTNetworking");
612
613 // sets the _chipName
614 getChipInfo();
615
616 //THIS should output the device name, user name, etc...
617 SerialInfo.println(_chipName);
618
619 //read what was stored, if any..
621
622 SerialTemp.print("setupMQTTNetworking ssid="); SerialInfo.print(_ssidString?_ssidString:"NULL");
623 SerialTemp.print(", password = "); SerialInfo.print(_ssidPasswordString?_ssidPasswordString:"NULL");
624 SerialTemp.println();
625
626 _MQTTRunning = false;
627
628 //set the state, then the 'loop' will call setupWIFI(...)
631
632 //!starts the delay for WIFI checking, called at startup, and each time the timer finished..
634}
635
636//!value of WIFI connected
638{
639
640 SerialLots.printf("isConnectedWIFI_MQTTState: %s\n", _mqttClient.connected()?"connected":"not connected");
641 if (!_mqttClient.connected())
642 {
643 _MQTTRunning = false;
644
645 SerialTemp.printf("isConnectedWIFI_MQTTState: %s\n", _mqttClient.connected()?"connected":"not connected");
646 return false;
647 }
649}
650//!value of MQTT connected
652{
653 return _MQTTRunning;
654}
655/**
656 State:
657 0 .
658 1. waitingForWIFI (delaying when
659 */
660//!Nice writeup: https://microcontrollerslab.com/esp32-mqtt-publish-multiple-sensor-readings-node-red/
661//!
662//! called for the loop() of this plugin
664{
665 //only check messages if MQTT is running (or want's to run.. )
666 if (_MQTTRunning)
667 {
669 }
670
671 //!check if should try to reconnect to WIF
673
674 //!check if a delay was running.. for the STATE..
676 {
677 //SerialTemp.printf("delayFinished_WIFI_MQTTState: %d\n", _WIFI_MQTTState);
678 //what state were we in for the delay.. continue doing that
679 //NOTE: THese could be function pointers and just call the state we are in loop..
680 // This is the "delay" loop
681 switch (_WIFI_MQTTState)
682 {
683 case preSetupWIFI:
684 //setup with WIFI
686 break;
687 //in a wait for WIFI mode
688 case waitingForWIFI:
690 break;
691 //called to init the _mqttClient
692 case preSetupMQTT:
694 break;
695 //in a wait for MQTT mode
696 case waitingForMQTT:
698 break;
699 // all connected WIFI
700 default:
701 break;
702 }
703 }
704}
705
706// ******************************MQTT + WIFI ***********************************
707
708//!show the status in string form (from Library/Adruino... WiFiType.h)
710{
711 switch (WiFi.status())
712 {
713 case WL_NO_SHIELD:return (char*)"WL_NO_SHIELD";
714 case WL_IDLE_STATUS: return (char*)"WL_IDLE_STATUS";
715 case WL_NO_SSID_AVAIL: return (char*)"WL_NO_SSID_AVAIL";
716 case WL_SCAN_COMPLETED: return (char*)"WL_SCAN_COMPLETED";
717 case WL_CONNECTED :return (char*)"WL_CONNECTED";
718 case WL_CONNECT_FAILED: return (char*)"WL_CONNECT_FAILED";
719 case WL_CONNECTION_LOST: return (char*)"WL_CONNECTION_LOST";
720 default:
721 case WL_DISCONNECTED: return (char*)"WL_DISCONNECTED";
722 }
723}
724
725//! a call to see if the WIFI is connected
726//**** Delay Methods*******
727#define SINGLE_DELAY
728#ifdef SINGLE_DELAY
729//https://www.forward.com.au/pfod/ArduinoProgramming/TimingDelaysInArduino.html
730//! the time the delay started
732//! true if still waiting for delayCheckWIFI to finish
734//! length of delay
736//!init the delay
738{
739 SerialCall.printf("startdelayCheckWIFI_MQTTNetworking: %d\n", seconds);
740
741 _delayCheckWIFIStart_MQTTNetworking = millis(); // start delay
742 _delayCheckWIFIRunning_MQTTNetworking = true; // not finished yet
744
745}
746
747//!get the delay values
749{
750 return 30; // 30 seconds ..
751}
752
753//!starts the delay for WIFI checking, called at startup, and each time the timer finished..
755{
757}
758
759//!if finished..
761{
763 {
765 SerialCall.println("delayCheckWIFIFinished_MQTTNetworking..");
766
767 return true;
768 }
769 return false;
770}
771
772//!stop the delay (not called)
774{
775 SerialCall.println("stopDelayCheckWIFI_MQTTNetworking _delayRunning=false");
776
778}
779
780//!checks delay for the WIFI connectivity
782{
784 {
785 //!check and reconnect to the WIFI is not connected
787 //!restart the timer
789 }
790}
791
792//!The setup() will call restartDelay_MQTTNetworking
793//!Each loop will call checkDelaySinceButtonTouched_MQTTNetworking
794#endif //SINGLE_DELAY
795
796//!print a SPIFF timestamp..
797
798//!checks if the WIFI is off (or not reachable) and tries consecting again (the 'W' command)
800{
801 SerialMin.printf("checkAndReconnectWIFI_MQTTState: %s\n",wifiStatus_MQTT());
802 boolean tryReconnect = true;
803 switch (WiFi.status())
804 {
805 case WL_NO_SHIELD:
806 break;
807 case WL_IDLE_STATUS:
808 break;
809 case WL_NO_SSID_AVAIL:
810 //tryReconnect = false;
811 break;
812 case WL_SCAN_COMPLETED:
813 break;;
814 case WL_CONNECTED:
815 //!start outputing SPIFF info
816#ifdef TOO_MUCH
818 println_SPIFFModule((char*)"WIFI WL_CONNECTED");
819#endif
820 SerialLots.printf("isConnectedWIFI = %s\n",isConnectedWIFI_MQTTState()?"connected":"not connected");
821 //!it seems the WIFI can reconnect -- but all the MQTT isn't restarted.. So if our internal state things WIFI is off, reconnect anyway..
823 tryReconnect = true;
824 else
825 tryReconnect = false;
826 break ;
827 case WL_CONNECT_FAILED:
829 println_SPIFFModule((char*)"WIFI WL_CONNECT_FAILED");
830 break;
831 case WL_CONNECTION_LOST:
833 println_SPIFFModule((char*)"WIFI WL_CONNECTION_LOST");
834 break;
835 case WL_DISCONNECTED:
837 println_SPIFFModule((char*)"WIFI WL_DISCONNECTED");
838 break;
839 default:
840 break;
841
842 }
843
844 //!try reconnecting if not connected (and ssid is available)
845 if (tryReconnect)
846 {
847 //!start outputing SPIFF info
849 print_SPIFFModule((char*)"WIFI Reconnect attempt: ");
851 SerialMin.println("reconnectAttempt");
852 //!restart the WIFI and then MQTT connection
854 }
855}
856// ******************************HELPER METHODS, ***********************************
857
858//!https://www.arduino.cc/en/Tutorial/Foundations/DigitalPins
860{
861 //call method passed in..
862 // if (_blinkTheLED)
863 // (*_blinkTheLED)();
864// callCallbackMain(CALLBACKS_MQTT, MQTT_CALLBACK_BLINK, strdup("blink"));
866
867}
868
869
870//!setup the WIFI using ssid and password (called from setup_MQTTNetworking() .. the main setup for this module)
871void setupWIFI(char * arg_ssid, char * arg_password)
872{
873 //state preSetupWIFI
874 //SerialTemp.printf("setupWIFI(%d)\n", _WIFI_MQTTState);
875
876 // We start by connecting to a WiFi network
877 SerialInfo.printf("\nConnecting to '%s' password = '%s'\n", arg_ssid?arg_ssid:"NULL", arg_password?arg_password:"NULL");
878
880 print_SPIFFModule((char*)"setupWIFI: ");
881 println_SPIFFModule(arg_ssid?arg_ssid:(char*)"empty");
882
883 //!start the WIFI mode and begin
884 WiFi.mode(WIFI_STA);
885 WiFi.begin(arg_ssid, arg_password);
886
887 //!set the counters..
888 _counterLoop = 0;
889 _maxCounterLoop = 0;
890
891 //!reset the global attempts .. since we are trying to reconnect
893
894 //set the state..
897}
898
899
900//!the loop part of WIFI. Call this each time the timer is up (the delay() )
901//! and only go to the next state if state changes to waitingForMQTT
903{
904 //SerialTemp.printf("setupWIFI_loop(%d)\n", _WIFI_MQTTState);
905
906 if (WiFi.status() == WL_CONNECTED)
907 {
908 SerialDebug.println("WiFi.status() == WL_CONNECTED()");
909
910 //stop the timer..
912
913 //try the autoReconnect (seems default was true .. so no help)
914 WiFi.setAutoReconnect(true);
915
916 //finish up.. let that step change the "state"
918 }
920 {
921 //should still be waitingForMQTT
922 // the is part of the loop..
923
924 _counterLoop++;
925 //SerialInfo.print(".");
926 if (_counterLoop > 10)
927 {
928 _counterLoop = 0;
929 //SerialInfo.println();
930 }
932
933 //the delay is set by what state we are in, and this is called back
934 // if the timer is finished...
936 }
937 else //_maxCounterLoop >= MAX_WIFI_CONNECT_ATTEMPTS
938 {
939 SerialInfo.println("WIFI **** Cannot connect .. try bluetooth update ... ");
940 //blink the LED
941 // blinkBlueLightMQTT();
943
944 //stop the timer..
946
947 //NOTE: THis is taken out.. so the credentials are the same.. next time you reboot it should work if
948 // the wifi ssid is the same.
949 //NOTE: let's delete the 'ssid' so it goes back into AP mode. via cleadSSID_EPROM
950 //! call the callback for cleaning the SSID eprom..
951 //callCallbackMain(CALLBACKS_MQTT, MQTT_CLEAN_SSID_EPROM, (char*)"cleanSSID_EPROM");
952
953 showText_displayModule("Retry WIFI");
954
955 }
956} //
957
958//! print the WIFI info
960{
961 SerialMin.println("WiFi connected");
962 SerialMin.print("IP Address: ");
963 SerialMin.println(WiFi.localIP());
964 SerialMin.print("WiFi SSID:");
965 SerialMin.println(WiFi.SSID());
966 long rssi = WiFi.RSSI();
967 SerialMin.print("signal strength (RSSI):");
968 SerialMin.print(rssi);
969 SerialMin.println(" dBm");
970}
971
972//!end of WIFI loop..
974{
975 SerialMin.println("finishWIFI_Setup()");
976
977 //random ?? for the WIFI address?
978 randomSeed(micros());
979
980 //This creates a DHCP address
982
984
985 //NOTE: this is a 192.168.0.130 kind of address. But when the outside MQTT world see it,
986 // is like : 72.106.50.236:49205 (The address of my entry to my subdomain point ..)
987
988 //see if this works: took out to stop confusion..
989 // getExternalIP();
990
991 //configure the time server
992 configTime(0, 0, _ntpServer);
993
994 //set the time on startup
996
997 //blink the LED
999
1000 SerialDebug.println("setupMQTTNetworking_WIFI done..");
1001
1003
1004 //lets kick off a delay.. this could be 0 or 1 ?? the first time
1006
1007
1008}
1009
1010//!called to setup the MQTT (which is really the _mqttClient setup). Done on it's own thread..
1012{
1013 SerialDebug.printf("callPreSetupMQTT(%d)\n", _WIFI_MQTTState);
1014
1015 //
1016 //this would use the values .. and then we save afterwards..
1018
1019 //NEW -
1020 //head to the next .. state == waitingForMQTT
1022
1023 //lets kick off a delay.. this could be 0 or 1 ?? the first time
1025
1026}
1027
1028//! 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."
1029
1030
1031//! add globals for knowing the type of message.
1032//! call the check message processing
1033//!state variables
1035{
1036 // usersP/bark/<user>
1038 // usersP/dawgpack
1040 // usersP/bark
1043
1044//!helper to know it's a dawgpack topic (and not process in most cases). Only support DOCFOLLOW for now..
1046{
1048}
1049//!helper to know it's a superuser topic (and not process in most cases).
1051{
1053}
1054//!classify a topic
1055void classifyTopic(char *topic)
1056{
1057 //!set the topic type
1058 if (strcmp(topic,"usersP/dawgpack")==0)
1060 else if (strcmp(topic,"usersP/bark") == 0)
1062 else
1064}
1065
1066//!prints the topic on debug
1068{
1069 SerialDebug.print("Topic = ");
1070 switch (_MQTTMessageTopicType)
1071 {
1072 case userTopic:
1073 SerialDebug.println("userTopic");
1074 break;
1075 // usersP/dawgpack
1076 case dawgpackTopic:
1077 SerialDebug.println("dawgPackTopic");
1078 break;
1079 // usersP/bark
1080 case superTopic:
1081 SerialDebug.println("superTopic");
1082 break;
1083 }
1084}
1085
1086//if (_MQTTMessageTopicType == superTopic)
1087//if (_MQTTMessageTopicType == dawgpackTopic)
1088
1089
1090
1091//!called when data on the MQTT socket
1092void callbackMQTTHandler(char* topic, byte* payload, unsigned int length)
1093{
1094 SerialLots.printf("callbackMQTTHandler topic: %s\n", topic);
1095 int i = 0;
1096 for (i = 0; i < length && i < MAX_MESSAGE; i++) {
1097 _fullMessageIn[i] = (char)payload[i];
1098 }
1099 _fullMessageIn[i] = (char)NULL;
1100
1101 //note there is a strange issue where a "null" is showing up in my MQTT/Websocket path
1102 //eg: Message arrived [idogwatch/bark] Guest35: null
1103 //sow for now.. not processing if the message has a "null"
1104 if (containsSubstring(_fullMessageIn, "null"))
1105 {
1106 //don't process..
1107 return;
1108 }
1109
1110 //! too many printouts which actully slows things down.. start with actMe (or collect a count of #actme and report that??)
1111 if (!skipMessageProcessing())
1112 SerialDebug.printf("MessageArrived: '%s', onTopic=%s\n", _fullMessageIn, topic);
1113
1114 //!classify the topic type
1115 classifyTopic(topic);
1116
1117
1118 //!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
1119
1120#ifdef TRY_MORE_ASYNC_PROCESSING
1121 _topic = topic;
1123 SerialLots.printf("MessageArrived: '%s', onTopic=%s\n", _fullMessageIn, topic);
1124
1125#else
1126 //!save some part of this message for later display by SemanticMarker 8.4.22
1127 // setLastMessageStatus(_fullMessage);
1128
1129 //process this message (We don't recognize just a JSON config yet..) That arrives on bluetooth
1131
1132 //send to the Display .. but truncate
1133 //! 11.7.22 if it's an #actMe .. don't show
1134 if (!skipMessageProcessing())
1136
1137#endif
1138 SerialLots.println(" -- DONE processsBarkletMessage ----");
1139}
1140
1141
1142
1143//!reconnects and re-subscribes
1144//!NOTE: we need the host info...
1146{
1147 //SerialTemp.println("reconnectMQTT_loop()");
1148
1149 if (_mqttClient.connected())
1150 {
1151 SerialDebug.println("reconnectMQTT_loop: _mqttClient.connected()");
1152
1155 }
1157 {
1158
1159 SerialDebug.printf("STOPPING MQTT connection attempts: '%s' count=%d\n", _mqttServerString?_mqttServerString:"NULL", _globalMQTTAttempts);
1160
1162
1163 //! call the callback for cleaning the SSID eprom..
1164 //callCallbackMain(CALLBACKS_MQTT, MQTT_CLEAN_SSID_EPROM, (char*)"cleanSSID_EPROM");
1165
1166 }
1168 {
1169 SerialInfo.println("FAILED MQTT .. so lets try connecting to WIFI again..");
1170 SerialInfo.println("Setting WIFI from JSON parameters");
1171 //try to setup the WIFI again, seems to help.
1172
1173 //set the state back to starting WIFI..
1176 }
1177 else
1178 {
1179 //Lets try to connect...
1180 //reset on connection, or new BLE config info...
1182 // _WIFI_MQTTState = waitingForMQTT;
1184
1185 SerialDebug.printf("Attempting MQTT connection: '%s' '%s' '%s' count=%d\n", _mqttServerString?_mqttServerString:"NULL", _mqttUserString?_mqttUserString:"NULL", _mqttPasswordString?_mqttPasswordString:"NULL", _globalMQTTAttempts);
1186
1187 // Create a random client ID
1188#ifdef ESP_M5
1189 String clientId = "espM5-";
1190#endif
1191#ifdef ESP_32
1192 String clientId = "esp32-";
1193#endif
1194 clientId += String(random(0xffff), HEX);
1195
1196 SerialDebug.printf("attempt _mqttClient.connect(%s)\n", clientId);
1197
1198 // Attempt to connect NOTE: this takes time...
1199 //TODO: use the argments...
1200 if (_mqttClient.connect(clientId.c_str(), _mqttUserString, _mqttPasswordString))
1201 {
1202
1203
1204
1205 //!try making a bigger packet.. 10.23.22 (seems to help)
1206 //!Looking at the PubSubClient.cpp,
1207 //! if (this->bufferSize < MQTT_MAX_HEADER_SIZE + 2+strnlen(topic, this->bufferSize) + plength) {
1208 _mqttClient.setBufferSize(MAX_MESSAGE + MQTT_MAX_HEADER_SIZE);
1209
1211
1212 SerialInfo.println("MQTT CONNECTED");
1214
1215 //_mqttTopicString = strdup("usersP/bark/scott@konacurrents.com");
1216 //NOTE: if topic not supported ... no good error message ... it disconnects
1217 //NOTE: no wildcards allowed on statusfeed.
1218 // Once connected, publish an announcement...
1219 //NOTE: _jsonLocationString is null... sometimes.
1220 sprintf(_fullMessageOut, "%s {%s}{'mqttUser':'%s','location':'%s','uptime':'%d','v':'%s'}", REMOTE, _deviceNameString?_deviceNameString:"NULL", _mqttUserString?_mqttUserString:"NULL", _jsonLocationString?_jsonLocationString:"somewhere", getUptime(), VERSION);
1221
1222 SerialInfo.println(_fullMessageOut);
1223
1224#ifdef TRY_MORE_ASYNC_PROCESSING
1225 //publish back on topic
1227#else
1229#endif
1230
1231#ifdef NOT_NOW_ONLY_DOCFOLLOW
1232#ifdef TRY_MORE_ASYNC_PROCESSING
1233 //! NOTE publish on the dawgpack as well so a single user can monitor the events..
1234
1235 publishMQTTMessage((char*)"usersP/dawgpack", _fullMessageOut);
1236#else
1237 _mqttClient.publish("usersP/dawgpack", _fullMessageOut);
1238#endif
1239#endif
1240
1241 // ... and resubscribe to same topic 8.3.22
1242 _mqttClient.subscribe(_mqttTopicString);
1243
1244 //add another topic ... (should be ok with usersP/bark/# )
1245
1246 //2.2.22 The root level usersP/bark for messages from the super-user
1247 // _mqttTopicString = strdup("usersP/bark");
1248 // ... and resubscribe to same topic
1249 _mqttClient.subscribe((char*)"usersP/bark");
1250
1251 //! Only subscribe if turned on.. 8.17.22
1253 {
1254 //! 8.15.22 Also subscribe to the dawgpack .. but restrict what it can effect.
1255 //! For example, start with STATUS and DOCFOLLOW
1256 _mqttClient.subscribe((char*)"usersP/dawgpack");
1257 }
1258 _MQTTRunning = true;
1259
1260 //!reset the global attempts .. since we connected
1262
1265 }
1266 else
1267 {
1268 //receiving state = -2 ???
1269 //https://forum.arduino.cc/t/mqtt-esp32-nodemcu-failed-with-state-2-connecting-to-mqtt/939270
1270 SerialInfo.printf("FAILED, rc=%d, trying again in 0.2 seconds\n", _mqttClient.state());
1271 //or reset something...
1272 // Wait .2 seconds before retrying
1273 //try..
1274 //NOTE: state hasn't changed but should be waitingMQTT..
1276 }
1277 } //while not connected
1278}
1279
1280//!setup the MQTT (called after the WIFI connected)
1281void setupMQTT(char* mqttServerString, char *mqttPortString, char *mqttPasswordString, char *mqttUserString, char *deviceNameString, char *uuidString)
1282{
1283 SerialTemp.println("**** setupMQTT *****");
1284 // make sure the password etc are valid
1285 if (mqttServerString && mqttPortString && mqttPasswordString && mqttUserString)
1286 {
1287 //connect to server:port
1288 int port = atoi(mqttPortString);
1289 _mqttClient.setServer(mqttServerString, port);
1290 _mqttClient.setCallback(callbackMQTTHandler);
1291 _MQTTRunning = true;
1292
1293 //try to connect.. so _MQTTRUnning is not completed, just the next phase..
1294
1295 //! print the WIFI info AGAIN..
1296 printWIFIInfo();
1297
1298 }
1299 else
1300 {
1301 SerialInfo.println(" *** No MQTT Server/Port Specified ** abort");
1302 _MQTTRunning = false;
1303 }
1304}
1305
1306//!check for MQTT messages, called from the main loop()
1308{
1309 //!don't do the loop at same time as check, do it at another time..
1311 {
1312#ifdef TRY_MORE_ASYNC_PROCESSING
1313 //!save some part of this message for later display by SemanticMarker 8.4.22
1314 // setLastMessageStatus(_fullMessageIn);
1315 if (!skipMessageProcessing())
1316 {
1317 //process this message (We don't recognize just a JSON config yet..) That arrives on bluetooth
1319
1320 //send to the Display .. but truncate
1321 //! 11.7.22 if it's an #actMe .. don't show
1323 }
1324#endif
1325 _newMQTTMessageArrived = false;
1326 }
1327 else
1328 {
1329 _newMQTTMessageArrived = false;
1330 //!call the MQTT infrastructure loop which does it's MQTT messaging
1331 _mqttClient.loop();
1332 }
1333}
1334
1335//!check if the string matches
1336bool stringMatch(String message, String substring)
1337{
1338 return strcmp(&message[0], &substring[0]) == 0;
1339}
1340
1341//!! should be a definition that the bluetooth is ONLINE
1343{
1344 return true;
1345}
1346
1347//!cleans the eprom info
1349{
1350 SerialDebug.println("cleanEPROM_MQTTNetworking");
1351 _preferencesMQTTNetworking.begin(ESP_EPROM_NAME, false); //readwrite..
1354}
1355
1356//! just send a message (let the internals to figure out topics, etc..
1357//!so the BLE can send something on the MQTT
1358//! for now only send if it start message starts with "#"
1359void sendMessageMQTT(char *message)
1360{
1361 if (_MQTTRunning)
1362 {
1363 //Basically if we send {'cmd':'buzzon'} -- it comes back to us.. and infinite loop
1364 // for now only send if it start message starts with "#"
1365 if (containsSubstring(message, "#"))
1366 {
1367 sprintf(_fullMessageOut,"%s {%s}", message, _deviceNameString);
1368
1369 //publish this message..
1370// _mqttClient.publish(_mqttTopicString, _fullMessageOut);
1371// SerialTemp.printf("Sending message:%s %s\n",_mqttTopicString, _fullMessageOut);
1372#ifdef TRY_MORE_ASYNC_PROCESSING
1373 //publish back on topic
1375#else
1377#endif
1378 }
1379 }
1380}
1381
1382//! just send a message but without any extras
1383void sendMessageNoChangeMQTT(char *message)
1384{
1385 if (_MQTTRunning)
1386 {
1387 //Basically if we send {'cmd':'buzzon'} -- it comes back to us.. and infinite loop
1388 // for now only send if it start message starts with "#"
1389
1390 sprintf(_fullMessageOut,"%s", message);
1391
1392 //publish this message..
1393// _mqttClient.publish(_mqttTopicString, _fullMessageOut);
1394// SerialTemp.printf("Sending message:%s %s\n",_mqttTopicString, _fullMessageOut);
1395#ifdef TRY_MORE_ASYNC_PROCESSING
1396 //publish back on topic
1398#else
1400#endif
1401 }
1402}
1403
1404//! sends the semantic marker as a doc follow message #remoteMe (vs STATUS, as that triggers a status reply.. )
1405void sendStatusMessageMQTT_deviceName(char *deviceName, const char *semanticMarker)
1406{
1407 SerialTemp.println("sendStatusMessageMQTT..");
1408 sprintf(_fullMessageOut, "#remoteMe {%s} {AVM=%s}", deviceName, semanticMarker);
1409 if (_MQTTRunning)
1410 {
1411 // _mqttClient.publish(_mqttTopicString, _fullMessageOut);
1412 // SerialMin.printf("Sending message: %s\n", _fullMessageOut);
1413#ifdef TRY_MORE_ASYNC_PROCESSING
1414 //publish back on topic
1416#else
1418#endif
1419 }
1420}
1421
1422//! sends the semantic marker as a doc follow message #remoteMe (vs STATUS, as that triggers a status reply.. )
1423void sendStatusMessageMQTT(const char *semanticMarker)
1424{
1426}
1427//! sends the semantic marker as a doc follow message
1428void sendDocFollowMessageMQTT(const char *semanticMarker)
1429{
1430 SerialTemp.println("sendDocFollowMessageMQTT..");
1431 if (!containsSubstring(semanticMarker,"https"))
1432 sprintf(_fullMessageOut, "#DOCFOLLOW {%s} {AVM=https://SemanticMarker.org/bot/%s}", _deviceNameString, semanticMarker);
1433 else
1434 sprintf(_fullMessageOut, "#DOCFOLLOW {%s} {AVM=%s}", _deviceNameString, semanticMarker);
1435 if (_MQTTRunning)
1436 {
1437// _mqttClient.publish(_mqttTopicString, _fullMessageOut);
1438// SerialMin.printf("Sending message: %s\n", _fullMessageOut);
1439#ifdef TRY_MORE_ASYNC_PROCESSING
1440 //publish back on topic
1442#else
1444#endif
1445 }
1446}
1447
1448//!process an MQTT message looking for keywords (this version uses the Barklet Language Grammer @c 2014)
1449//!NOTE: The processJSONMessage() is part of this (called if straight JSON).
1450//!TODO: merge these two methods..
1451void processBarkletMessage(String message, String topic)
1452{
1453 //!https://stackoverflow.com/questions/7352099/stdstring-to-char
1454 int time = getTimeStamp_mainModule();
1455
1456 //!convert String to char *
1457 char *messageString = &message[0];
1458 //!flag to send the message back on MQTT
1459 bool messageValidToSendBack = false;
1460 SerialCall.print("processBarkletMessage: ");
1461 SerialCall.print(message);
1462 SerialCall.print(" topic=");
1463 SerialCall.println(topic);
1464
1465 if (!topic)
1467
1468 //!debug printout..
1469 //printTopicType();
1470
1471 //!new 4.12.22 if this is straight JSON .. then sent to the processJSONmessage
1472 if (processJSONMessageMQTT(messageString, topic?&topic[0]:NULL))
1473 {
1474 //This was processed by the JSON processor
1475 //SerialDebug.println("** not an older Barklet message syntax, but straight JSON ***");
1476 return;
1477 }
1478
1479 //!If the dawgpack, only process the DOCFOLLOW message
1480 //!
1481 //!note: these messages are sent to MQTT. But the messages comming down originated on WebSocket barklets language
1482 //! so the 'remoteMe ..." gets up there, but not back to the rest. It's rewritten by nodered.
1483 if (containsSubstring(message, STATUS) && !isDawgpackTopic())
1484 {
1485 float temp = getTemperature_mainModule();
1486
1487 //!save some part of this message for later display by SemanticMarker 8.4.22
1488 //!set the status
1489 setLastMessageStatus((char*)"status");
1490
1491 char pairedDevice[100];
1493 {
1494 strcpy(pairedDevice,getPairedDevice_mainModule());
1495// strcat(pairedDevice,(char*)":");
1496// strcat(pairedDevice,getPairedDeviceAddress_mainModule());
1497 }
1498 else
1499 strcpy(pairedDevice,"none");
1500#ifdef USE_BLE_CLIENT_NETWORKING
1501 boolean isConnectedBLE = isConnectedBLEClient();
1502#else
1503 boolean isConnectedBLE = false;
1504#endif
1506 //! process the pair if match
1507 if (isConnectedBLE && isGateway)
1508 {
1509 //! FOR NOW , copy the code and create a _fullMessageOut that is for the Paired device...
1510
1511 sprintf(_fullMessageOut, "%s {%s} {%s} {I,F} {'T':'%d','dev':'%s','user':'%s','location':'%s','v':'%s','ble':'%s'}",
1512 REMOTE,
1513 pairedDevice,
1515 time,
1516 pairedDevice,
1519 VERSION,
1520#ifdef USE_BLE_SERVER_NETWORKING
1521 //! retrieve the service name (PTFEEDER, PTFeeder:Name, PTClicker:Name, etc)
1523#else
1524 "none"
1525#endif
1526 );
1527
1528 //publish this message..
1529 SerialTemp.printf("GEN3: Sending message: %s\n", _fullMessageOut);
1530
1531 //_mqttClient.publish(_mqttTopicString, _fullMessageOut);
1532#ifdef TRY_MORE_ASYNC_PROCESSING
1533 //publish back on topic
1535#else
1537#endif
1538 //! 5.21.22 WORKS!!
1539 //!topic is the topic we can in on.. so could be super user..
1540 //if (strcmp(&topic[0],"usersP/bark")==0)
1541 if (isSuperTopic())
1542 {
1543 SerialTemp.println("Sending on DawgPack too..");
1544 //publish back on topic
1545 //_mqttClient.publish("usersP/dawgpack", _fullMessageOut);
1546#ifdef TRY_MORE_ASYNC_PROCESSING
1547 //publish back on topic
1548 publishMQTTMessage((char*)"usersP/dawgpack", _fullMessageOut);
1549#else
1550 _mqttClient.publish("usersP/dawgpack", _fullMessageOut);
1551#endif
1552 }
1553 }
1554
1555 //sprintf(_fullMessageOut, "%s {%s} {%s} {I,F} {T=now}", REMOTE, _deviceNameString, bluetoothOnline() ? CONNECTED : NOT_CONNECTED);
1556 // Once connected, publish an announcement...
1557 // sprintf(message, "#STATUS {%s} {%s}", _deviceNameString, chipName);
1558 sprintf(_fullMessageOut, "%s {%s} {%s} {I,F} {'T':'%d','dev':'%s','user':'%s','location':'%s','ble':'%s','v':'%s'}",
1559 REMOTE,
1562 time,
1566#ifdef USE_BLE_SERVER_NETWORKING
1567 //! retrieve the service name (PTFEEDER, PTFeeder:Name, PTClicker:Name, etc)
1569#else
1570 "none",
1571#endif
1572 VERSION);
1573
1574 messageValidToSendBack = true;
1575
1577
1578 //On demand #STATUS send the statusURL as well (if an M5)
1579 //this queues the sending of the StatusURL over MQTT.
1580 // This is async (next loop) since sending 2 MQTT messages can be hard to do in a row ..
1582 }
1583 // else if (containsSubstring(message, "#FEED") || containsSubstring(message, "feedme"))
1584 //only use #FEED (the feedme will turn into #FEED)
1585 else if (containsSubstring(message, "#FEED") && !isDawgpackTopic())
1586 {
1587 //! flag for whether feed will occur. it won't if a device is specified and it's not our device (unless super topic)
1588 boolean performFeed = true;
1589 //!check against the super feeder. If super feeder, then feed all devices, otherwise logic below
1590 if (!isSuperTopic())
1591 //if (!stringMatch(topic, "/usersP/bark") && !stringMatch(topic, "/usersP/dawgpack"))
1592 {
1593 //only check this if not the super feed topic "/usersP/bark" ..
1594 //TODO: not make this hardwired to /usersP/bark
1595 //TODO: 2.2.22
1596 //try 2.19.22 (but simple version..)
1597 //TODO: 7.23.22 .. look if the paired device too..
1598 if (containsSubstring(message, "deviceName"))
1599 {
1600 //since deviceName specified, then only feed if our device is specified..
1602 {
1603 // this could mean a "deviceName" was found, and our _deviceNameString was there.,
1604 // versus actually parsing for "deviceName":ourName
1605 performFeed = true;
1606 }
1608 {
1609 //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
1611 {
1612 SerialTemp.println(" *** Feeding via our gateway ***");
1613 performFeed = true;
1614 }
1615 else
1616 {
1617 SerialDebug.println(" ** Not feeding as not our paired device either ***");
1618 performFeed = false;
1619 }
1620
1621 }
1622 else
1623 {
1624 //perform feed... (knowing the message device name requires pqrsing .. so not for now since containsSubstring() suffices..
1625 SerialDebug.printf("**NOT Perform FEED as deviceName doesn't ours: %s\n", _deviceNameString );
1626
1627 performFeed = false;
1628 }
1629 }
1630 }
1631
1632 //if performFeed set, then continue..
1633 if (performFeed)
1634 {
1635 //!perform the feed
1636 performFeedMethod(&topic[0]);
1637
1638 //!message already sent ...
1639 messageValidToSendBack = false;
1640 }
1641 }
1642#ifdef ESP_M5
1643 //!DOCFOLLOW .. support Dawgpack
1644 else if (containsSubstring(message, "#followMe") || containsSubstring(message,"#DOCFOLLOW"))
1645 {
1646 //! retrieves the last DocFollow SemanticMarker (from the message #DOCFOLLOW | #followMe {AVM=<SM>}
1647 //! need to parse to the AVM= grab the <SM> up to the "}"
1648 //!
1649 if (containsSubstring(message,"AVM="))
1650 {
1651 char *indexOfEqual = index(&message[0],'=');
1652 if (strlen(indexOfEqual)>2)
1653 //move past the =
1654 indexOfEqual++;
1656 // loop until the } is found
1657 while (*indexOfEqual && *indexOfEqual !='}')
1658 {
1659 //copy a character at a time until the } (or nill)
1660 strncat(_lastDocFollowSemanticMarker, indexOfEqual,1);
1661 indexOfEqual++;
1662 }
1663 strcat(_lastDocFollowSemanticMarker, "\0");
1664
1665 SerialDebug.printf("SemanticMarker: %s\n", _lastDocFollowSemanticMarker);
1666 //setLastDocFollowSemanticMarker(_lastDocFollowSemanticMarker);
1667
1668 //!parse the #followMe {AVM=<url>}
1669 sprintf(_fullMessageOut,"#ACK {%s} {doc_follow=%s}", _deviceNameString, _lastDocFollowSemanticMarker);
1670 }
1671 else
1672 {
1673 sprintf(_fullMessageOut,"#ACK {%s} {bad_doc_follow syntax}", _deviceNameString);
1674
1675 }
1676 messageValidToSendBack = true;
1677 }
1678 //!note: this might be candidate for wider use
1679 else if (containsSubstring(message, "#CAPTURE") && !isDawgpackTopic())
1680 {
1681#ifdef ESP_M5_CAMERA
1682 // sprintf(_fullMessageOut, "#TAKING_PIC {%s} {real soon to be implemented 8.11.22}", _deviceNameString);
1684
1685#else
1686#ifdef M5_CAPTURE_SCREEN
1688 //sprintf(_fullMessageOut, "#M5_SCREEN {%s} {capturing screen as bmp}", _deviceNameString);
1689#else
1690 //sprintf(_fullMessageOut, "#NO_CAN_CAMERA_CAPTURE {%s} {I am just a chip without a camera}", _deviceNameString);
1691#endif // ESP_M5
1692#endif //ESP_M5_CAMERA
1693 messageValidToSendBack = false;
1694 }
1695#endif // M5
1696 else if (containsSubstring(message, "#TEMP") && !isDawgpackTopic())
1697 {
1698#ifdef ESP_M5
1699 float temp = getTemperature_mainModule();
1700 //SYNTAX should evolve .. backward compatable ..
1701 sprintf(_fullMessageOut,"#ACK {%s} {TEMP} %2.0f F {'temp':'%2.0f'}", _deviceNameString, temp, temp);
1702#else
1703 sprintf(_fullMessageOut, "#NO_CAN_GET_TEMP {%s} {I am just a chip without a temp sensor}", _deviceNameString);
1704#endif
1705 //call the callback specified from the caller (eg. NimBLE_PetTutor_Server .. or others)
1707
1708 messageValidToSendBack = true;
1709 }
1710 //!3.25.22 -- trying the CLEAN the ePROM SSID
1711 else if (containsSubstring(message, "#CLEAN_SSID_EPROM") && !isDawgpackTopic())
1712 {
1713 //! call the callback for cleaning the SSID eprom..
1714 callCallbackMain(CALLBACKS_MQTT, MQTT_CLEAN_SSID_EPROM, (char*)"cleanSSID_EPROM");
1715
1716 }
1717 //!3.8.22 -- trying the OTA. IT WORKS!!!
1718 //!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"
1719 else if (containsSubstring(message, "#OTA") && !isDawgpackTopic())
1720 {
1721 boolean performOTAUpdate = true;
1722
1723 //syntax: #OTA {v:VERSION}, or {k:ESP_32 or ESP_M5
1724 if (containsSubstring(message, "{v:"))
1725 {
1726 //does the installed "VERSION" == the string passed in eg. {v:OUR_VERSION} VERSION=OUR_VERSION
1727 // performOTAUpdate = containsSubstring(message, VERSION);
1728 performOTAUpdate = containsSubstring(message, VERSION);
1729
1730 SerialDebug.printf("#OTA version correct: %d\n", performOTAUpdate);
1731 }
1732 else if (containsSubstring(message, "{k:") && !isDawgpackTopic())
1733 {
1734 //does the installed "KIND" == the string passed in eg. {v:ESP_32} we are one or the other..
1735#ifdef ESP_M5
1736 performOTAUpdate = containsSubstring(message, "ESP_M5");
1737 SerialDebug.printf("#OTA match ESP_M5: %d\n", performOTAUpdate);
1738
1739#else
1740 performOTAUpdate = containsSubstring(message, "ESP_32");
1741 SerialDebug.printf("#OTA match ESP_32: %d\n", performOTAUpdate);
1742
1743#endif
1744
1745 }
1746
1747
1748 //parse out the {kind, host, binfile}
1749 //SOON .. this might be a triple click?? or keep the messaging?
1750
1751
1752 if (performOTAUpdate)
1753 {
1754 //NOTE: cannot put #OTA in message or it infinite loops..
1755 sprintf(_fullMessageOut, "over the air binary image update from version: %s", VERSION);
1756 //let clients know what's happening..
1758 SerialLots.printf("Sending message: %s\n", _fullMessageOut);
1759 //blink the light
1761
1762 //! dispatches a call to the command specified. This is run on the next loop()
1764 }
1765 else
1766 {
1767 sprintf(_fullMessageOut, "over the air NOT updating as not matching string: %s",
1768#ifdef ESP_M5
1769 "ESP_M5"
1770#else
1771 "ESP_32"
1772#endif
1773 );
1774 SerialLots.printf("Sending message: %s\n", _fullMessageOut);
1776
1777 }
1778
1779 } //#OTA
1780 else if (isDawgpackTopic())
1781 {
1782 SerialDebug.println("DAWGPACK unsupported message");
1783 }
1784
1785 if (messageValidToSendBack)
1786 {
1787 //publish this message..
1788// _mqttClient.publish(_mqttTopicString, _fullMessageOut);
1789 SerialLots.printf("1.Sending message: %s\n", _fullMessageOut);
1790#ifdef TRY_MORE_ASYNC_PROCESSING
1791 //publish back on topic
1793#else
1795#endif
1796
1797 //! 5.21.22 WORKS!!
1798 //!topic is the topic we can in on.. so could be super user..
1799 //if (strcmp(&topic[0],"usersP/bark")==0)
1800 if (isSuperTopic() || isDawgpackTopic())
1801 {
1802 SerialTemp.println("2.Sending on DawgPack too..");
1803 //publish back on topic
1804 // _mqttClient.publish("usersP/dawgpack", _fullMessageOut);
1805#ifdef TRY_MORE_ASYNC_PROCESSING
1806 //publish back on topic
1807 publishMQTTMessage((char*)"usersP/dawgpack", _fullMessageOut);
1808#else
1809 _mqttClient.publish("usersP/dawgpack", _fullMessageOut);
1810#endif
1811 }
1812 }
1813}
1814
1815
1816//! *********************** METHODS invoked from BLE (JSON) and MQTT messages ***************
1817
1818//!perform the OTA update. This calls the OTAImageUpdate methods (via preformOTAUpdateSimple())
1820{
1821 //NOTE: cannot put #OTA in message or it infinite loops..
1822 sprintf(_fullMessageOut, "over the air binary image update, replacing our version: %s", VERSION);
1823 //let clients know what's happening..
1824 // _mqttClient.publish(_mqttTopicString, _fullMessageOut);
1825 SerialDebug.printf("%s\n", _fullMessageOut);
1826 //blink the light
1828 //#define REALLY_DO_IT_BOMBS
1829#ifdef REALLY_DO_IT_BOMBS
1830 //NOTE: this sync call doesn't work..
1831 //printf(" *** Bad syntax, no { } \n");
1833 //this reboots .. so the code below never runs anyway.. will work on it..
1834#else
1835 // setAsyncCallOTAUpdate(true);
1836 //! dispatches a call to the command specified. This is run on the next loop()
1838#endif
1839}
1840
1841//!calls the method for cleaning the SSID eprom. This calls the WIFI_APModule callback
1843{
1844 //! call the callback for cleaning the SSID eprom..
1845 callCallbackMain(CALLBACKS_MQTT, MQTT_CLEAN_SSID_EPROM, (char*)"cleanSSID_EPROM");
1846}
1847
1848//! //!calls the FEED message via the callback (which calls the BLE code)
1849//!NOTE: this will send a BLE command if connected via the GATEWAY to a GEN3 (or other gateway in the future)
1850//!NOTE: This sends the _full message on the topic ..
1851void performFeedMethod(char *topic)
1852{
1853 //!get the temperature
1854 float temp = getTemperature_mainModule();
1855
1856 //!get the connected status
1857 //!save some part of this message for later display by SemanticMarker 8.4.22
1858 //!set the feed
1859 setLastMessageStatus((char*)"feed");
1860
1861 //perform feed...
1862 SerialDebug.println("Perform FEED internally, calling callbackFunction.. 2");
1863 //call the callback specified from the caller (eg. NimBLE_PetTutor_Server .. or others)
1864 // (*_callbackFunction)(rxValue);
1866
1867 //ASYNC_SEND_MQTT_FEED_MESSAGE
1868 //On demand #STATUS send the statusURL as well (if an M5)
1869 //this queues the sending of the StatusURL over MQTT.
1870 // This is async (next loop) since sending 2 MQTT messages can be hard to do in a row ..
1871 //main_dispatchAsyncCommand(ASYNC_SEND_MQTT_FEED_MESSAGE);
1872
1873 //SerialTemp.println(" ** returned from ASYNC_SEND_MQTT_FEED_MESSAGE ***");
1874#define ACK_FOR_PAIR_TOO
1875 char pairedDevice[100];
1877 strcpy(pairedDevice,getPairedDevice_mainModule());
1878 else
1879 strcpy(pairedDevice,"none");
1880
1881#ifdef USE_BLE_CLIENT_NETWORKING
1882 boolean isConnectedBLE = isConnectedBLEClient();
1883#else
1884 boolean isConnectedBLE = false;
1885#endif
1887
1888 if (isConnectedBLE && isGateway)
1889 {
1890 //! FOR NOW , copy the code and create a _fullMessageOut that is for the Paired device...
1891 SerialTemp.print("PairedDevice: ");
1892 SerialTemp.println(pairedDevice);
1893 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");
1894
1895 //publish this message..
1896// _mqttClient.publish(_mqttTopicString, _fullMessageOut);
1897// SerialTemp.printf("ACK: Sending message: %s\n", _fullMessageOut);
1898#ifdef TRY_MORE_ASYNC_PROCESSING
1899 //publish back on topic
1901#else
1903#endif
1904 //! 5.21.22 WORKS!!
1905 //!topic is the topic we can in on.. so could be super user..
1906 // if (strcmp(&topic[0],"usersP/bark")==0)
1907 if (isSuperTopic() || isDawgpackTopic())
1908 {
1909// SerialLots.println("Sending on DawgPack too..");
1910// //publish back on topic
1911// _mqttClient.publish("usersP/dawgpack", _fullMessageOut);
1912#ifdef TRY_MORE_ASYNC_PROCESSING
1913 //publish back on topic
1914 publishMQTTMessage((char*)"usersP/dawgpack", _fullMessageOut);
1915#else
1916 _mqttClient.publish("usersP/dawgpack", _fullMessageOut);
1917#endif
1918 }
1919 }
1920 sprintf(_fullMessageOut, "%s {%s} {'T':'%d','temp':'%2.0f','topic':'%s','user':'%s','v':'%s','location':'%s','paired':'%s', 'ble':'%s','gateway':'%s'}", ACK_FEED, _deviceNameString, time, temp, &topic[0]?&topic[0]:"NULL",_mqttUserString, VERSION_SHORT, _jsonLocationString?_jsonLocationString:"somewhere",pairedDevice, isConnectedBLE?"c":"x", isGateway?"on":"off");
1921
1922 // send the FEED to the display (if any)
1924
1925 //if (messageValidToSendBack)
1926 if (true)
1927 {
1928 //publish this message..
1929// _mqttClient.publish(_mqttTopicString, _fullMessageOut);
1930// SerialDebug.printf("Sending message: %s\n", _fullMessageOut);
1931#ifdef TRY_MORE_ASYNC_PROCESSING
1932 //publish back on topic
1934#else
1936#endif
1937 //! 5.21.22 WORKS!!
1938 //!topic is the topic we can in on.. so could be super user..
1939 // if (strcmp(&topic[0],"usersP/bark")==0)
1940 if (isSuperTopic() || isDawgpackTopic())
1941
1942 {
1943// SerialTemp.println("Sending on DawgPack too..");
1944// //publish back on topic
1945// _mqttClient.publish("usersP/dawgpack", _fullMessageOut);
1946#ifdef TRY_MORE_ASYNC_PROCESSING
1947 //publish back on topic
1948 publishMQTTMessage((char*)"usersP/dawgpack", _fullMessageOut);
1949#else
1950 _mqttClient.publish("usersP/dawgpack", _fullMessageOut);
1951#endif
1952 }
1953 }
1954}
1955
1956
1957//! *********************** END METHODS invoked from BLE (JSON) and MQTT messages ***************
1958
1959
1960//!This is in case corruption when changing what's written.. defining BOOTSTRAP will clean up the EPROM
1961
1962//!read the eprom..
1964{
1965 SerialDebug.println("MQTT.readPreferences");
1966 //#define BOOTSTRAP
1967#ifdef BOOTSTRAP
1968 //note: this could be a 'rebootstrap' message via MQTT .. in the future..
1969 {
1970 SerialDebug.println("BOOTSTRAP device with our own WIFI and MQTT");
1971
1972 char* BOOT_mqtt_server = (char*)"iDogWatch.com";
1973
1974 //example with "test" as the user name. Change, ssid, user, pass, device name and topic
1975 char* BOOT_mqtt_port = (char*)"1883";
1976 char* BOOT_ssid = (char*)"SunnyWhiteriver";
1977 char* BOOT_ssid_password = (char*)"sunny2021";
1978 char *BOOT_mqtt_user = (char*)"test";
1979 char *BOOT_mqtt_password = (char*)"test";
1980 char *BOOT_mqtt_guestPassword = (char*)"test";
1981
1982 //new 2.2.22 (last time this century..)
1983 //change over to new MQTT Namespace: usersP/bark
1984 char *BOOT_mqtt_topic = (char*)"usersP/bark/test";
1985
1986 char *BOOT_deviceName = (char*)"name-of-feeder";
1987 char *BOOT_uuidString = (char*)"unused";
1988 char *BOOT_jsonHeaderString = (char*)"WIFI+MQTT";
1989 char *BOOT_jsonVersionString = (char*)"BOOTSTRAP 1.3";
1990 char *BOOT_jsonLocationString = (char*)"PetLand"; //enter something is you like (Seattle, WA)
1991
1992 ///note: these createCopy are to get between String and char* .. probably a better way like &BOOT[0] or something..
1993 _ssidString = createCopy(BOOT_ssid);
1994
1995 _ssidPasswordString = createCopy(BOOT_ssid_password);
1996
1997 _mqttServerString = createCopy(BOOT_mqtt_server);
1998 _mqttPortString = createCopy(BOOT_mqtt_port);
1999 _mqttPasswordString = createCopy(BOOT_mqtt_password);
2000 _mqttGuestPasswordString = createCopy(BOOT_mqtt_guestPassword);
2001 _mqttUserString = createCopy(BOOT_mqtt_user);
2002 _mqttTopicString = createCopy(BOOT_mqtt_topic);
2003 _deviceNameString = createCopy(BOOT_deviceName);
2004 _uuidString = createCopy(BOOT_uuidString);
2005 _jsonHeaderString = createCopy(BOOT_jsonHeaderString);
2006 _jsonVersionString = createCopy(BOOT_jsonVersionString);
2007 _jsonLocationString = createCopy(BOOT_jsonLocationString);
2008
2009 DynamicJsonDocument myObject(1024);
2010
2011 myObject["ssid"] = BOOT_ssid;
2012 myObject["ssidPassword"] = BOOT_ssid_password;
2013 myObject["mqtt_server"] = BOOT_mqtt_server;
2014 myObject["mqtt_port"] = BOOT_mqtt_port;
2015 myObject["mqtt_password"] = BOOT_mqtt_password;
2016 myObject["mqtt_guestPassword"] = BOOT_mqtt_guestPassword;
2017
2018 myObject["mqtt_user"] = BOOT_mqtt_user;
2019 myObject["mqtt_topic"] = BOOT_mqtt_topic;
2020 myObject["deviceName"] = BOOT_deviceName;
2021 myObject["uuid"] = BOOT_uuidString;
2022 myObject["jsonHeader"] = BOOT_jsonHeaderString;
2023 myObject["jsonVersion"] = BOOT_jsonVersionString;
2024 myObject["location"] = BOOT_jsonLocationString;
2025
2026 //open the preferences
2027
2028 _preferencesMQTTNetworking.begin(ESP_EPROM_NAME, false); //readwrite..
2030 //output our object.. myObject has a string version..
2031 SerialDebug.print("Writing EPROM JSON = ");
2032 //JSON
2033 String output1;
2034 serializeJson(myObject, output1);
2035 SerialDebug.println(output1);
2037
2038 // Close the Preferences
2040
2041 //new 2.21.22 (On bootstrap, it's nil..?? .. maybe the myObject isn't a string??
2042 //TRY: reading back..
2043 _preferencesMQTTNetworking.begin(ESP_EPROM_NAME, false); //false=read/write..
2045 SerialDebug.print("Reading.3 EPROM JSON = ");
2046 SerialDebug.println(_fullJSONString);
2047
2048 //check ... _fullMessageOut
2049 // Close the Preferences
2051
2052 //end new
2053 }
2054 return;
2055#endif //BOOTSTRAP
2056
2057 //https://randomnerdtutorials.com/esp32-save-data-permanently-preferences/
2058 //https://github.com/espressif/arduino-esp32/blob/master/libraries/Preferences/src/Preferences.cpp
2059 // Open Preferences with my-app namespace. Each application module, library, etc
2060 // has to use a namespace name to prevent key name collisions. We will open storage in
2061 // RW-mode (second parameter has to be false).
2062 // Note: Namespace name is limited to 15 chars.
2063 _preferencesMQTTNetworking.begin(ESP_EPROM_NAME, false); //false=read/write..
2065 SerialDebug.print("Reading.1 EPROM JSON = ");
2066 SerialDebug.println(_fullJSONString);
2067
2068 //check ... _fullMessageOut
2069 // Close the Preferences
2071
2072 //3.29.22: ISSUE. the eprom wasn't written, but we can in from the CREDENTIALS...
2073
2074 //first time there won't be any eprom info.. THIS is a bug without this code update
2075 if (!_fullJSONString || _fullJSONString.length() == 0)
2076 {
2077 SerialDebug.println("*** no JSON in preferences, probably first time. use Bootstrap, or BLE update ***");
2078 _ssidString = NULL;
2079 _ssidPasswordString = NULL;
2080 return;
2081 }
2082
2083 DynamicJsonDocument myObject(1024);
2084 //StaticJsonDocument myObject(1024);
2085 deserializeJson(myObject, _fullJSONString);
2086 SerialDebug.print("JSON parsed.1 = ");
2087 String output1;
2088 serializeJson(myObject, output1);
2089 SerialDebug.println(output1);
2090
2091 //defaults:
2092 _deviceNameString = (char*)"Unnamed";
2093
2094 //parse
2095 const char* a1 = myObject["ssid"];
2096 if (a1)
2097 {
2098 _ssidString = const_cast<char*>(a1);
2100 SerialDebug.println(_ssidString);
2101
2102 }
2103 else
2104 {
2105 _ssidString = NULL;
2106 SerialDebug.println("ssid == NULL");
2107 }
2108 if (!_ssidString)
2109 {
2110
2111 SerialDebug.println("No SSID set, try BLE update again.. ");
2112 _ssidString = NULL;
2113 _ssidPasswordString = NULL;
2114 _mqttServerString = NULL;
2115 _mqttPortString = NULL;
2116 _mqttPasswordString = NULL;
2118 _mqttUserString = NULL;
2119 _mqttTopicString = NULL;
2120 _deviceNameString = (char*)"Unnamed";
2121 _uuidString = NULL;
2122 _jsonHeaderString = NULL;
2123 _jsonVersionString = NULL;
2124 _jsonLocationString = NULL;
2125
2126 //call the callback specified from the caller (eg. NimBLE_PetTutor_Server .. or others)
2127 // (*_callbackFunction)(rxValue);
2129
2130 return;
2131
2132 }
2133 //!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..
2134 {
2135 const char* a2 = myObject["ssidPassword"];
2136 if (a2)
2137 {
2138 _ssidPasswordString = const_cast<char*>(a2);
2140 SerialDebug.println(_ssidPasswordString);
2141 }
2142 else
2143 _ssidPasswordString = NULL;
2144 }
2145
2146 {
2147 //!the MQTT host/port/user/password (topic is created in this code...)
2148 const char* a3 = myObject["mqtt_server"];
2149 if (a3)
2150 {
2151 _mqttServerString = const_cast<char*>(a3);
2153 SerialDebug.println(_mqttServerString);
2154 }
2155 else
2156 _mqttServerString = NULL;
2157 }
2158
2159 {
2160 const char* a4 = myObject["mqtt_port"];
2161 if (a4)
2162 {
2163 _mqttPortString = const_cast<char*>(a4);
2165 }
2166 else
2167 _mqttPortString = NULL;
2168 }
2169
2170 {
2171 const char* a5 = myObject["mqtt_password"];
2172 if (a5)
2173 {
2174 _mqttPasswordString = const_cast<char*>(a5);
2176 SerialDebug.println(_mqttPasswordString);
2177 }
2178 else
2179 _mqttPasswordString = NULL;
2180 }
2181
2182 {
2183 const char* a6 = myObject["mqtt_user"];
2184 if (a6)
2185 {
2186 _mqttUserString = const_cast<char*>(a6);
2188 }
2189 else
2190 _mqttUserString = NULL;
2191 }
2192
2193 {
2194 const char* a7 = myObject["deviceName"];
2195 if (a7)
2196 {
2197 _deviceNameString = const_cast<char*>(a7);
2199 }
2200 else
2201 _deviceNameString = NULL;
2202 }
2203
2204 //update the chip name with the deviceName
2205 getChipInfo();
2206
2207 SerialDebug.println(_deviceNameString);
2208
2209 {
2210 const char* a8 = myObject["uuid"];
2211 if (a8)
2212 {
2213 _uuidString = const_cast<char*>(a8);
2215 SerialDebug.print("UUID: ");
2216 SerialDebug.println(_uuidString);
2217
2218 }
2219 else
2220 _uuidString = NULL;
2221 }
2222
2223 {
2224 const char* a9 = myObject["mqtt_topic"];
2225 if (a9)
2226 { _mqttTopicString = const_cast<char*>(a9);
2228 SerialDebug.println(_mqttTopicString);
2229 }
2230 else
2231 _mqttTopicString = NULL;
2232 }
2233
2234 {
2235 const char* a10 = myObject["jsonHeader"];
2236 if (a10)
2237 { _jsonHeaderString = const_cast<char*>(a10);
2239 SerialDebug.println(_jsonHeaderString);
2240 }
2241 else
2242 _jsonHeaderString = NULL;
2243 }
2244
2245 {
2246 //!Note: This is where the code could look for backward compatability, etc..
2247 const char* a11 = myObject["jsonVersion"];
2248 if (a11)
2249 { _jsonVersionString = const_cast<char*>(a11);
2251 SerialDebug.println(_jsonVersionString);
2252 }
2253 else
2254 _jsonVersionString = NULL;
2255 }
2256
2257 {
2258 const char* a12 = myObject["location"];
2259 if (a12)
2260 { _jsonLocationString = const_cast<char*>(a12);
2262 SerialDebug.println(_jsonLocationString);
2263 }
2264 else
2265 _jsonLocationString = NULL;
2266 }
2267
2268 {
2269 const char* a13 = myObject["mqtt_guestPassword"];
2270 if (a13)
2271 {
2272 _mqttGuestPasswordString = const_cast<char*>(a13);
2274 SerialDebug.println(_mqttGuestPasswordString);
2275 }
2276 else
2278 }
2279
2280 //! sets the MQTT user/password. It's up to the code to decide who needs to know (currently saves in the WIFI_APModule
2282}
2283
2284
2285
2286//!whether the string is TRUE, ON, 1
2287boolean isTrueString(String valCmdString)
2288{
2289 return valCmdString.equalsIgnoreCase("on") ||
2290 valCmdString.equalsIgnoreCase("1") ||
2291 valCmdString.equalsIgnoreCase("true");
2292}
2293#ifdef UNUSED
2294//!whether the string is FALSE, OFF, 0
2295function isFalseString(String valCmdString)
2296{
2297 return valCmdString.equalsIgnoreCase("off") ||
2298 valCmdString.equalsIgnoreCase("0") ||
2299 valCmdString.equalsIgnoreCase("false");
2300}
2301#endif
2302
2303//!send message to ourself to change to current specifed SM Mode
2305{
2306 //!send message to ourself to process the current mode..
2309}
2310
2311//!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)
2312boolean processJSONMessageMQTT(char *ascii, char *topic)
2313{
2314 SerialLots.println(" *** processJSONMessageMQTT ***");
2315 //! use the default user topic if not specified...
2316 if (!topic)
2317 {
2318 if (!_mqttTopicString)
2319 _mqttTopicString = (char*)"usersP/bark/test";
2320 topic = _mqttTopicString;
2321 }
2322 classifyTopic(topic);
2323
2324 if (!ascii)
2325 return false;
2326
2327 //!empty the status for the last message. Then various places the feed or status, etc are set
2328 //emptyLastMessageStatus();
2329 //cant empty here .. as the ACK gets sent .. how about after the ACK!
2330
2331 //!Basically processing as a JSON if the "{" is somewhere.. could still be invalid code
2332 if (!startsWithChar(ascii,'{'))
2333 {
2334 SerialLots.printf("processJSONMessageMQTT(%s) -> return false, not JSON\n", ascii);
2335
2336 return false;
2337 }
2338
2339 SerialDebug.printf("processJSONMessageMQTT: '%s'\n", ascii);
2340
2341 // Deserialize the JSON document, then store the ascii in the EPROM (if it parses..)
2342
2343 SerialLots.printf("Ascii before deserializeJson: %s\n", ascii);
2344
2345 DynamicJsonDocument myObject(1024);
2346 deserializeJson(myObject, ascii);
2347 //NOTE: the ascii is now corrupted...
2348 SerialDebug.print("JSON parsed = ");
2349 // String output;
2350 String output1;
2351 serializeJson(myObject, output1);
2352 SerialDebug.println(output1);
2353 SerialLots.printf("Ascii after deserializeJson: %s\n", ascii);
2354
2355 //NEW: 3.28.22 {'cmd':COMMANDS}
2356 // {'sm':<sm>}
2357 // {'guest':<passws>
2358 //{ 'set':<object>,'val':<value>}
2359 const char* cmd = myObject["cmd"];
2360 const char* semanticMarkerCmd = myObject["sm"];
2361 const char* guestCmd = myObject["guest"];
2362
2363 const char *setCmd = myObject["set"];
2364 const char *valCmd = myObject["val"];
2365 //new: 'send':<request> eg. status|temp
2366 const char *sendCmd = myObject["send"];
2367 //! devName is if a dev=<NAME> was specified, then dissregard if not our device
2368 const char *devName = myObject["dev"];
2369 //if processCommands, then do NOT process the credentials..
2370 boolean processCommands = false;
2371 if (cmd || semanticMarkerCmd || guestCmd || setCmd || sendCmd)
2372 processCommands = true;
2373
2374 //try 5.12.22 {'set':'item'},{'val':'value'}
2375 // eg. set:hightemp, val:80
2376
2377 //Find the Guest Password, and the user name - or defaults if notset
2378 String guestPassword = "pettutor";
2380 {
2381 //in case empty (but not null) - not checking for spaces only... too lazy
2382 if (strlen(_mqttGuestPasswordString)>0)
2383 guestPassword = _mqttGuestPasswordString;
2384 }
2385 // set vals to NOTSET if not set
2386 char* baseString;
2387 String title = "";
2388 if (!_mqttUserString)
2389 {
2390 _mqttUserString = NOTSET_STRING;
2391 }
2393 {
2394 _mqttPasswordString = NOTSET_STRING;
2395 }
2396
2397 //!this is to ensure that the credentials are not processed..
2398 //! there is a return 'true' after processing commands
2399 if (processCommands)
2400 {
2401 //! for dawgPack, only support the DOCFOLLOW message for now 8.19.22
2402 if (isDawgpackTopic())
2403 {
2404 char* setCmdString = const_cast<char*>(setCmd);
2405 char* valCmdString = const_cast<char*>(valCmd);
2406
2407 if (setCmd && strcasecmp(setCmd,"semanticMarker")==0)
2408 {
2409 SerialDebug.printf("DAWGPACK supported message: %s\n", setCmd);
2410 }
2411 else
2412 {
2413 SerialDebug.println("DAWGPACK unsupported message");
2414 return true;
2415 }
2416 //fall through for supported messaages..
2417 }
2418
2419 //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...
2420 //! a couple commands, like bleserveron require a device name to be specified (so everyone listening doesn't perform operation)
2421 boolean deviceNameSpecified = devName != NULL;
2422 //!if a dev:<dev> is specified, then only process if the device name is that same
2423 boolean processMessageOrGateway = true;
2424 if (deviceNameSpecified)
2425 {
2426 //default we only feed if our device or our gateway..
2427 processMessageOrGateway = false;
2428#ifdef WILDCARD_DEVICE_NAME_SUPPORT
2429 //!parses a line of text, The caller then uses queryMatchesName() to see if their name matches
2430 parseQueryLine_mainModule((char*)devName);
2432 {
2433 SerialTemp.printf("Query: %s *** Matches our dev name: %s\n", devName, _deviceNameString);
2434#else
2435 //!If the dev name is specified, and our device is that name .. then good
2436 if (devName && strcmp(devName,_deviceNameString) == 0)
2437 {
2438#endif
2439 SerialTemp.println(" .. our own device ..");
2440 processMessageOrGateway = true;
2441 }
2442 //!we are in gateway mode, and the paired device isn't ours..
2443 if (devName
2445 {
2446#ifdef WILDCARD_DEVICE_NAME_SUPPORT
2448 {
2449 SerialTemp.printf("Query: %s *** Matches our paired dev name: %s\n", devName, getPreferenceString_mainModule(PREFERENCE_PAIRED_DEVICE_SETTING));
2450
2451#else
2453 {
2454#endif
2455 SerialTemp.println(" .. our paired device ..");
2456 processMessageOrGateway = true;
2457 }
2458 }
2459
2460 }
2461 //! after this, if true, then ifDeviceNameSpecified .. then it's a good name..
2462 if (!processMessageOrGateway)
2463 {
2464 //Only gets here if dev set .. so the parser was run (if WILDCARD)
2465 SerialTemp.print("Disregard as Device Specified: ");
2466 SerialTemp.print(devName);
2467
2468 //! as per issue #122, if a device is in gateway mode, and paired with a device name specified, then the message can be sent
2469 SerialTemp.print(" not ours: ");
2470 SerialTemp.println(_deviceNameString);
2472 {
2473#ifdef WILDCARD_DEVICE_NAME_SUPPORT
2475 {
2476#else
2478 {
2479#endif
2480 SerialTemp.print(" .. And not paired device:");
2482 }
2483 }
2484 }
2485 else if (cmd)
2486 {
2487
2488 //SerialDebug.printf("BLE CMD = '%s'\n", cmd);
2489 //note: we could have a mode for "testing" .. so the OTA for example does't fire.
2490 //smN
2491 //NOTE: THIS REQUIRES == 0 or no work..
2492 //NOTE: the number here has to be updated in the ButtonProcessing code too..
2493 int whichSMMode = whichSMMode_mainModule((char*)cmd);
2494 SerialTemp.printf("BLE CMD = '%s'\n", cmd);
2495
2496 // -1 if none..
2497 if (whichSMMode >= 0)
2498 {
2499 //! per #206 .. only change the page when not in doc_follow
2500 //! 11.9.22
2501 int currentSMMode = getCurrentSMMode_mainModule();
2502 SerialDebug.printf("currentSMMode = %d whichSMMode = %d\n", currentSMMode, whichSMMode);
2503 if (currentSMMode == SM_doc_follow)
2504 {
2505 //! Issue: #222 for #206, this sets the current mode to SM_doc_follow, but
2506 //! when at that page in the the current mode (which is now SM_doc_follow) won't let
2507 //! the page go somewhere else (except in this case we are the same page). Only but a
2508 //! physical button click.
2509 //! I THINK THE ANSWER: if current and next are the same an SM_doc_follow, then do the page change..
2510 if (currentSMMode != whichSMMode)
2511 {
2512 SerialDebug.println(" *** Not changing page as in DOCFOLLOW mode ***");
2513 return true;
2514 }
2515 else
2516 SerialDebug.println(" *** SM_doc_follow and changing to the same page ***");
2517 }
2518
2519 //set the global SMMode.. NOTE: if greater than the MAX change mode to NON MIN
2520 setCurrentSMMode_mainModule(whichSMMode);
2521
2522 boolean markerAlreadyShown = false;
2523 switch (whichSMMode)
2524 {
2525 //since the TITLE is used by the display (it doesn't use the SMMode)
2526 case SM_home_simple: //TILT
2527 {
2528 //new 7.25.22
2529 baseString = (char*)"https://iDogWatch.com/bot/guestpage2";
2530 title = "MINI CLICKER";
2531 sprintf(_semanticMarkerString,"%s/%s/%s", baseString, _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL");
2532 }
2533 break;
2534 case SM_home_simple_1: // BUZZER
2535 {
2536 //NOTE: THIS title is a binding/linking to the DisplayModule (as it looks for the title)
2537 //new 7.25.22
2538 baseString = (char*)"https://iDogWatch.com/bot/guestpage2";
2539 title = "MINI-1";
2540 sprintf(_semanticMarkerString,"%s/%s/%s", baseString, _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL");
2541 }
2542 break;
2543 case SM_home_simple_2: //FEED
2544 {
2545 //new 7.25.22
2546 baseString = (char*)"https://iDogWatch.com/bot/guestpage2";
2547 title = "MINI-2";
2548 sprintf(_semanticMarkerString,"%s/%s/%s", baseString, _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL");
2549 }
2550 break;
2551 case SM_home_simple_3: //EXPERT
2552 {
2553 //new 7.25.22
2554 baseString = (char*)"https://iDogWatch.com/bot/guestpage2";
2555 title = "MINI-3";
2556 sprintf(_semanticMarkerString,"%s/%s/%s", baseString, _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL");
2557 }
2558 break;
2559 //! the 4th page, start of smart clicker
2561 {
2562 //Make URL for the status..
2563 char *statusString = currentMessageStatusURL();
2564
2565 //!create the SemanticMarker address
2566 sprintf(_semanticMarkerString,"%s/%s/%s/%s", "https://SemanticMarker.org/bot/sensor", _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL", statusString?statusString:"NULL");
2567
2568 title = "WIFI FEED";
2569
2570 //TODO.. use the String (*getStatusFunc)(void)) to re-create this..
2571 //TODO: get the guest info.. or they send us the guest password in a message.. for next time..
2572 //SerialDebug.print("SemanticMarker: ");
2573 SerialLots.println(_semanticMarkerString);
2574 //MAYBE save the user web page.. somewhere EPROM
2575
2576 //!call the displayModuleFunc passing our dynamic status fund
2578 markerAlreadyShown = true;
2579 }
2580
2581 break;
2582 case SM_status:
2583 {
2584 //Make URL for the status..
2585 char *statusString = main_currentStatusURL();
2586
2587 //!create the SemanticMarker address
2588 sprintf(_semanticMarkerString,"%s/%s/%s/%s", "https://SemanticMarker.org/bot/sensor", _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL", statusString?statusString:"NULL");
2589
2590 //!tack on the device name..
2591 sprintf(_fullMessageOut,"Status %s", getDeviceNameMQTT());
2592 //title = _fullMessageOut;
2593
2594 //TODO.. use the String (*getStatusFunc)(void)) to re-create this..
2595 //TODO: get the guest info.. or they send us the guest password in a message.. for next time..
2596 //SerialDebug.print("SemanticMarker: ");
2597 SerialLots.println(_semanticMarkerString);
2598 //MAYBE save the user web page.. somewhere EPROM
2599
2600 //!call the displayModuleFunc passing our dynamic status fund
2602 markerAlreadyShown = true;
2603 }
2604 break;
2605
2606 case SM_guest_page:
2607
2608 {
2609 baseString = (char*)"https://iDogWatch.com/bot/guestpage";
2610 title = "Guest Page";
2611 sprintf(_semanticMarkerString,"%s/%s/%s", baseString, _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL");
2612 }
2613 break;
2614 case SM_guest_feed:
2615 {
2616 baseString = (char*)"https://iDogWatch.com/bot/feedguest";
2617 title = "Feed Guest";
2618 sprintf(_semanticMarkerString,"%s/%s/%s", baseString, _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL");
2619 }
2620 break;
2621 case SM_pair_dev:
2622 {
2623 baseString = (char*)"https://iDogWatch.com/bot/feedguestdevice";
2625 //!NOTE this could be "NONE" the "P:" is so the display knows this is a paired device command
2626 title = "P:";
2627 sprintf(_semanticMarkerString,"%s/%s/%s/%s", baseString, _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL", pairDev);
2628 }
2629 break;
2630 case SM_WIFI_ssid:
2631 {
2632 title = "WIFI";
2633
2634 //!#issue 136 create a SM for the WIFI syntax
2635 //!WIFI:S:<SSID>;T:<WEP|WPA|blank>;P:<PASSWORD>;H:<true|false|blank>;
2636 sprintf(_semanticMarkerString,"WIFI:S:%s;T:;P:%s;H:;", _ssidString?_ssidString:"NONE", _ssidPasswordString?_ssidPasswordString:"");
2637 }
2638 break;
2639
2640 // different SM
2641 case SM_ap_mode:
2642 {
2643 //AP mode..
2644 sprintf(_semanticMarkerString,"%s", "http://192.168.4.1");
2645 title = "AP Mode";
2646 }
2647 break;
2648
2649 case SM_help:
2650 {
2651 //HELP..
2652 //Make URL for the status..
2653 sprintf(_semanticMarkerString,"%s/%s/%s", "https://SemanticMarker.org/bot/help", _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL");
2654 title = "Help Info";
2655 }
2656 break;
2657 case SM_doc_follow:
2658 {
2659 //This is where a dynamic DOCFollow would show up..
2660 //Make URL for the status..
2662 title = "DOC FOLLOW";
2663 //call the displayModule
2664 if (SM.length()>0)
2665 sprintf(_semanticMarkerString,"%s", SM);
2666 else
2667 SM = "https://SemanticMarker.org";
2668 }
2669 break;
2670 //NOTE: each added sm, needs the ButtonProcessing.cpp to update it's list..
2671 case SM_reboot:
2672 {
2673 //REboot the device
2674 sprintf(_semanticMarkerString,"%s/%s/%s", "https://SemanticMarker.org/bot/reboot", _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL");
2675 title = "Reboot";
2676 }
2677 break;
2678 case SM_timer:
2679 {
2680 //timer the device
2681 sprintf(_semanticMarkerString,"%s/%s/%s", "https://SemanticMarker.org/bot/timer", _mqttUserString?_mqttUserString:"NULL", guestPassword?guestPassword:"NULL");
2682 title = "Timer";
2683 }
2684 break;
2685
2686 }
2687 //TODO: get the guest info.. or they send us the guest password in a message.. for next time..
2688 //SerialDebug.print("SemanticMarker: ");
2689 SerialLots.println(_semanticMarkerString);
2690 //MAYBE save the user web page.. somewhere EPROM
2691
2692 if (!markerAlreadyShown)
2693 {
2694 //only if not already shown. Status uses a dynamic function..
2696 }
2697 } //end smMode 0..n
2698 else if (strcasecmp(cmd,"ota")==0)
2699 {
2700 SerialDebug.println("OTA via BLE");
2701 //!calls the OTA update method (this doesn't return as device is rebooted...)
2703 }
2704 else if (strcasecmp(cmd,"clean")==0)
2705 {
2706 SerialDebug.println("CLEAN via BLE");
2707 //!calls the method for cleaning the SSID eprom. This calls the WIFI_APModule callback
2709 }
2710 else if (strcasecmp(cmd,"feed")==0)
2711 {
2712 SerialDebug.printf("FEED via BLE (%s)\n",topic?topic:"NULL TOPIC!!");
2713 performFeedMethod(topic);
2714 }
2715 else if (strcasecmp(cmd,"resettimer")==0)
2716 {
2718 }
2719 else if (strcasecmp(cmd,"status")==0)
2720 {
2721 SerialDebug.println("STATUS via BLE");
2722 //!print status of the WIFI and MQTT
2723 SerialMin.printf("WIFI_MQTTState= %d\n",_WIFI_MQTTState);
2724 SerialMin.printf("DeviceName= %s\n",getDeviceNameMQTT());
2725 SerialMin.printf("DynamcState= %s\n",getDynamicStatusFunc());
2726 SerialMin.printf("WIFI connected = %d, %s\n", isConnectedWIFI_MQTTState(), wifiStatus_MQTT());
2727 SerialMin.printf("MQTT connected = %d, %s\n", isConnectedMQTT_MQTTState(),_mqttClient.connected()?"connected":"not connected");
2728
2730 {
2733 println_SPIFFModule((char*)"=WIFI_MQTTState");
2734
2736 println_SPIFFModule((char*)"=DynamcState");
2737
2739 println_SPIFFModule((char*)"=WIFIConnected");
2740
2742 println_SPIFFModule((char*)"=WIFI Status");
2743
2745 println_SPIFFModule((char*)"=MQTTConnected");
2746
2747 printInt_SPIFFModule(_mqttClient.connected());
2748 println_SPIFFModule((char*)"=MQTTConnected");
2749
2750 }
2751
2752
2753 //WL_NO_SSID_AVAIL .. to WL_DISCONNECTED
2754 //but never reconnects ...
2755 SerialLots.println("cmd == status");
2756 //! request a STATUS be sent.
2757 processBarkletMessage("#STATUS", topic);
2758 }
2759 else if (strcasecmp(cmd,"erase")==0)
2760 {
2761 SerialDebug.println("ERASE via BLE");
2763 }
2764
2765 //!TODO: duplicate and depreciate these and replace with set:buzz,val:on
2766 else if (strcasecmp(cmd,"buzzon")==0)
2767 {
2768 SerialDebug.println("BUZZON via BLE");
2770 }
2771 else if (strcasecmp(cmd,"buzzoff")==0)
2772 {
2773 SerialDebug.println("BUZZOFF via BLE");
2775 }
2776 //Gateway (which I think is obsolete if we can determin this from knowing which feeder we have)
2777 //keeping for now..
2778 else if (strcasecmp(cmd,"gatewayOn")==0)
2779 {
2780 if (deviceNameSpecified)
2781 {
2782 SerialDebug.println("ASYNC_SET_GATEWAY_ON via BLE");
2784 }
2785 }
2786 else if (strcasecmp(cmd,"gatewayOff")==0)
2787 {
2788 if (deviceNameSpecified)
2789 {
2790 SerialDebug.println("ASYNC_SET_GATEWAY_OFF via BLE");
2792 }
2793 }
2794 //!resetFirstTime
2795 else if (strcasecmp(cmd,"resetfirsttime")==0)
2796 {
2797 if (deviceNameSpecified)
2798 {
2799 SerialDebug.println("PREFERENCE_FIRST_TIME_FEATURE_SETTING ON via BLE");
2801 //!for now just reboot which will use this perference
2803 }
2804 }
2805 //BLECLient
2806 else if (strcasecmp(cmd,"bleclientOn")==0)
2807 {
2808 if (deviceNameSpecified)
2809 {
2810 SerialDebug.println("PREFERENCE_MAIN_BLE_CLIENT_VALUE ON via BLE");
2812 //!for now just reboot which will use this perference
2814 }
2815 }
2816 else if (strcasecmp(cmd,"bleclientOff")==0)
2817 {
2818 if (deviceNameSpecified)
2819 {
2820 SerialDebug.println("PREFERENCE_MAIN_BLE_CLIENT_VALUE OFF via BLE");
2822 //!for now just reboot which will use this perference
2824 }
2825 }
2826 else if (strcasecmp(cmd,"bleserverOn")==0)
2827 {
2828 if (deviceNameSpecified)
2829 {
2830 SerialDebug.println("PREFERENCE_MAIN_BLE_SERVER_VALUE ON via BLE");
2832 //!for now just reboot which will use this perference
2834 }
2835 }
2836 else if (strcasecmp(cmd,"bleserverOff")==0)
2837 {
2838 if (deviceNameSpecified)
2839 {
2840 SerialDebug.println("PREFERENCE_MAIN_BLE_SERVER_VALUE OFF via BLE");
2842 //!for now just reboot which will use this perference
2844 }
2845 }
2846 else if (strcasecmp(cmd,"reboot")==0)
2847 {
2848 if (deviceNameSpecified)
2849 {
2850 SerialDebug.println("REBOOT via BLE");
2851 //!for now just reboot which will use this perference
2853 }
2854 }
2855 else if (strcasecmp(cmd,"tiltOn")==0)
2856 {
2857 SerialDebug.println("PREFERENCE_SENSOR_TILT_VALUE ON via BLE");
2859 }
2860 else if (strcasecmp(cmd,"tiltOff")==0)
2861 {
2862 SerialDebug.println("PREFERENCE_SENSOR_TILT_VALUE OFF via BLE");
2864 }
2865 //!zoom == the NON semantic marker version.. so min menu is true
2866 else if (strcasecmp(cmd,"zoomSMOn")==0)
2867 {
2868
2869 //hide semantic marker.. (but only if in the max menus)
2870 //NOTE: this only hides the Semantic Marker - if on a page that has one..
2871 SerialDebug.println("PREFERENCE_SEMANTIC_MARKER_ZOOMED_VALUE ON via BLE");
2873
2874 //!zoom only if in the max menu set..
2876 {
2877 //stay on this page, but change the marker..
2879 }
2880
2881 }
2882 else if (strcasecmp(cmd,"zoomSMOff")==0)
2883 {
2884 //show semantic marker..
2885 //NOTE: this only shows the Semantic Marker - if on a page that has one..
2886 SerialDebug.println("PREFERENCE_SEMANTIC_MARKER_ZOOMED_VALUE OFF via BLE");
2889
2890 //!zoom only if in the max menu set..
2892 {
2893 //change to the status..
2895 //!send message to ourself to process the current mode..
2897 }
2898 else
2899 {
2900 //stay on this page, but change the zoom..
2902 }
2903 }
2904 else if (strcasecmp(cmd,"poweroff")==0)
2905 {
2906 SerialDebug.println("ASYNC_POWEROFF OFF via BLE");
2908
2909 }
2910 else if (strcasecmp(cmd,"wifi")==0)
2911 {
2912 SerialDebug.println("cmd=wifi via BLE");
2914 }
2915 else if (strcasecmp(cmd,"swapwifi")==0)
2916 {
2917 SerialDebug.println("cmd=swapwifi via BLE");
2918
2919 //NOTE: this might be where we toggle credentials?? TODO
2920 //found other one..
2921 char *credentials = main_nextJSONWIFICredential();
2922
2923 //!These are the ASYNC_CALL_PARAMETERS_MAX
2924 //!NO: just change our credentials ...
2925 //send to ourself.., recursively...
2926 int val = processJSONMessageMQTT(credentials, topic);
2927 }
2928
2929 //new 7.29.22 SPIFF
2930 else if (strcasecmp(cmd,"readspiff")==0)
2931 {
2932 SerialDebug.println("readspiff...");
2933
2935 }
2936 else if (strcasecmp(cmd,"sendspiff")==0)
2937 {
2939 }
2940 else if (strcasecmp(cmd,"deletespiff")==0)
2941 {
2943 }
2944 else if (strcasecmp(cmd,"capture")==0)
2945 {
2946 //! request a CAPTURE be sent.
2947 processBarkletMessage("#CAPTURE", topic);
2948#ifdef ESP_M5
2950#endif
2951 }
2952 //end new
2953 else if (strcasecmp(cmd,"help")==0)
2954 {
2955 //!and print any preferences to show
2957
2958 sprintf(_fullMessageOut, "Syntax {\'cmd': \'[ota|clean|feed|erase|status|buzzon|buzzoff| MORE..help]\'} ");
2959 //!publich back on topic
2960 //_mqttClient.publish(_mqttTopicString, _fullMessageOut);
2961#ifdef TRY_MORE_ASYNC_PROCESSING
2962 //publish back on topic
2964#else
2966#endif
2967 }
2968 }
2969 //! {'guest':'guest password'}
2970 else if (guestCmd) //depreciated..
2971 {
2972 _mqttGuestPasswordString = const_cast<char*>(guestCmd);
2973 SerialDebug.printf("guestCmd = '%s'\n", _mqttGuestPasswordString);
2974 }
2975 // {'sm':'name/cat/uuid'}
2976 else if (semanticMarkerCmd)
2977 {
2978 //char semanticMarkerString[200];
2979 char* baseString = (char*)"https://SemanticMarker.org/bot/";
2980 sprintf(_semanticMarkerString,"%s/%s", baseString, semanticMarkerCmd);
2981
2982 //! use the name/cat/uuid ..
2984
2985 }
2986 //!5.12.22
2987 else if (setCmd && valCmd)
2988 {
2989 //! options: hightemp, feedcount, timeout
2990 char* setCmdString = const_cast<char*>(setCmd);
2991 char* valCmdString = const_cast<char*>(valCmd);
2992 SerialTemp.print("Set: ");
2993 SerialTemp.print(setCmdString);
2994 SerialTemp.print(", Val: ");
2995 SerialTemp.println(valCmdString);
2996
2997 //!set flag (if a boolean command)
2998 boolean flag = isTrueString(valCmdString);
2999
3000 //!try 5.12.22 {'set':'item'},{'val':'value'}
3001 //! eg. set:hightemp, val:80)
3002 //! TODO: confirm valid integer values...
3003 if (strcasecmp(setCmdString,"hightemp")==0)
3004 {
3005 //!set the high temp value..
3007 }
3008 //! 9.29.22 duplicating a couple of 'set':'cmd', 'val':'feed", since the QUERY for a device is sent that way sometimes..
3009 else if (strcasecmp(setCmdString,"cmd")==0)
3010 {
3011 if (strcasecmp(valCmdString,"feed")==0)
3012 {
3013 SerialCall.printf("feed via set,cmd (%s)\n",topic?topic:"NULL TOPIC!!");
3014 performFeedMethod(topic);
3015 }
3016 else if (strcasecmp(valCmdString,"status")==0)
3017 {
3018 SerialCall.println("status via set,cmd");
3019 //! request a STATUS be sent.
3020 processBarkletMessage("#STATUS", topic);
3021 }
3022 else if (strcasecmp(valCmdString,"resettimer")==0)
3023 {
3025 }
3026 else
3027 {
3028 SerialTemp.printf("Unknown cmd: %s\n", valCmdString);
3029 }
3030 }
3031 else if (strcasecmp(setCmdString,"ble+wifi")==0)
3032 {
3033 if (deviceNameSpecified)
3034 {
3035 //set ble+wifi transient state..
3037 }
3038 }
3039 else if (strcasecmp(setCmdString,"factoryreset")==0)
3040 {
3041 if (deviceNameSpecified)
3042 {
3043 // factory reset .. eventually
3045 }
3046 }
3047 //! 11.9.22
3048 else if (strcasecmp(setCmdString,"restartmodels")==0)
3049 {
3050 //!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
3051 if (flag)
3053 }
3054 else if (strcasecmp(setCmdString,"screentimeout")==0)
3055 {
3056 //set the screen timeout
3058 }
3059 else if (strcasecmp(setCmdString,"stepperangle")==0)
3060 {
3061 //!set the stepperangle.
3063 }
3064 else if (strcasecmp(setCmdString,"noclick")==0)
3065 {
3066 //!set the timeout from no click to poweroff
3068 }
3069 else if (strcasecmp(setCmdString,"gateway")==0)
3070 {
3071 if (deviceNameSpecified)
3072 {
3073 //! called to set a preference (which will be an identifier and a string, which can be converted to a number or boolean)
3075 }
3076 }
3077 //! 10.4.22
3078 else if (strcasecmp(setCmdString,"DiscoverM5PTClicker")==0)
3079 {
3080 //! called to set a preference (which will be an identifier and a string, which can be converted to a number or boolean)
3082 }
3083 else if (strcasecmp(setCmdString,"usespiff")==0)
3084 {
3085 //! called to set a preference (which will be an identifier and a string, which can be converted to a number or boolean)
3087 if (flag)
3088 {
3089 //! the setup for this module
3091
3092 }
3093 }
3094
3095 //!MQTT: set: timerdelay, val:seconds
3096 else if (strcasecmp(setCmdString,"timerdelay")==0)
3097 {
3098 if (deviceNameSpecified)
3099 {
3100 int timerdelay = atoi(valCmdString);
3101 //!set the timer delay (0 == stop).
3103 //!start or stop the timer..
3104 SerialDebug.printf("timerdelay: %d\n", timerdelay);
3105 }
3106 }
3107 //! MQTT: set: starttimer, val: true/false (true == start timer, false = stop timer)
3108 else if (strcasecmp(setCmdString,"starttimer")==0)
3109 {
3110 if (deviceNameSpecified)
3111 {
3112 //!start or stop the timer..
3114 //!start or stop the timer..
3115 SerialDebug.printf("startTimer: %d\n", flag);
3116 }
3117 }
3118
3119 //!add stepper type
3120 else if (strcasecmp(setCmdString,"stepper")==0)
3121 {
3122 int feederType = STEPPER_IS_UNO;
3123 if (strcasecmp(valCmdString,"mini")==0)
3124 feederType = STEPPER_IS_MINI;
3125 else if (strcasecmp(valCmdString,"tumbler")==0)
3126 feederType = STEPPER_IS_TUMBLER;
3127 //! called to set a preference (which will be an identifier and a string, which can be converted to a number or boolean)
3129 }
3130 else if (strcasecmp(setCmdString,"clockwiseMotor")==0)
3131 {
3132 SerialCall.println(" *** Setting clockwise motor");
3133 //!note since clockwise == 0 we set the opposite of the value..
3135 }
3136 //!add stepper type
3137 else if (strcasecmp(setCmdString,"otafile")==0)
3138 {
3139 //perform the OTA via a file specified .. be careful..
3141 }
3142 //!set the location
3143 else if (strcasecmp(setCmdString,"location")==0)
3144 {
3145 //perform the OTA via a file specified .. be careful..
3146 _jsonLocationString = createCopy(valCmdString);
3148 }
3149 //! rename device
3150 else if (strcasecmp(setCmdString,"device")==0)
3151 {
3152 //define the device
3153 _deviceNameString = createCopy(valCmdString);
3155
3156 //!since renaming, lets set a STATUS out..
3157 //! request a STATUS be sent.
3158 processBarkletMessage("#STATUS", topic);
3159 }
3160 //! pairnow is for invoking the pair when there isn't a user interface. Basically
3161 //! once an ESP32 gets connected, especially to a GEN3, the pairnow will make it paired
3162 //! for future. 10.24.22
3163 else if (strcasecmp(setCmdString,"pairnow")==0)
3164 {
3165 if (deviceNameSpecified)
3166 {
3167 //! TRUE will pair, FALSE will unpair
3168 if (flag)
3169 //!performs the pairing.. to whatever is currently connected, this means a message could make that happen
3170 //!for a device (ESP-32) with no user interface.
3172 else
3173 //! just unpair .. don't skip
3174 //!performs the unpairing
3176 }
3177 }
3178 //! paireddev the paired device (used with BLEUsePairedDeviceName and gen3Only
3179 else if (strcasecmp(setCmdString,"pairdev")==0)
3180 {
3181 if (deviceNameSpecified)
3182 {
3184 if (strcasecmp(valCmdString,previousName)!=0)
3185 {
3186 //different than current..
3187
3188 //!saves the pair device name TODO: the feed device should use the pair as well.. (DONE..)
3190
3191 //! paired address is null until found..
3192 //! Keep whatever is set ...???
3193#ifdef USE_BLE_CLIENT_NETWORKING
3194 //!if BLE connected, then we keep the address if any and GEN3
3196 {
3197 //keep the Address (but change the use supplied device name)
3198 }
3199 else
3200 {
3201 //! erase the ADDRESS (as well as new name) .. and disconnect if connected..
3204 //! try to disconnect..
3206 }
3207#endif
3208
3209#ifdef NO_MORE_PREFERENCE_BLE_USE_DISCOVERED_PAIRED_DEVICE_SETTING
3210 if (strlen(valCmdString)==0)
3211 {
3212 //!turn off pairing
3214
3215 }
3216#endif
3217 }
3218 }
3219 }
3220
3221 else if (strcasecmp(setCmdString,"screencolor")==0)
3222 {
3223 //!set the screen color 0..n
3224 int screenColor = atoi(valCmdString);
3225 setScreenColor_displayModule(screenColor);
3226
3227 //stay on this page, but change the marker..
3229 }
3230 //! sets the gen3only flag (only look for BLEServers that are GEN3)
3231 else if (strcasecmp(setCmdString,"gen3only")==0)
3232 {
3233 //! sets the gen3only flag
3235 //!for now just reboot which will use this perference
3236 // rebootDevice_mainModule();
3237 //TODO... maybe just disconnect .. or don't worry about it unless connected
3238 }
3239 //! BLEUsePairedDeviceName (Says to only look for BLEServers with the paired name..
3240 else if (strcasecmp(setCmdString,"BLEUsePairedDeviceName")==0)
3241 {
3242 if (deviceNameSpecified)
3243 {
3244#ifdef NO_MORE_PREFERENCE_BLE_USE_DISCOVERED_PAIRED_DEVICE_SETTING
3245 //! sets the bleusepaireddevicename flag
3247#endif
3248 }
3249 }
3250 //! sets the BLEUseDeviceName flag == the BLEServer will add the name, eg PTFeeder:ScoobyDoo
3251 else if (strcasecmp(setCmdString,"BLEUseDeviceName")==0)
3252 {
3253 if (deviceNameSpecified)
3254 {
3255 //! sets the bleusedevicename flag
3257
3258 //!for now just reboot which will use this perference and re-create the service name..
3260
3261#ifdef USE_BLE_CLIENT_NETWORKING
3262 //! try to disconnect..
3263 // disconnect_BLEClientNetworking();
3264#endif
3265 }
3266 }
3267 else if (strcasecmp(setCmdString,"minMenu")==0)
3268 {
3269 SerialDebug.println("PREFERENCE_IS_MINIMAL_MENU_SETTING via BLE");
3270 if (flag)
3271 {
3274 }
3275 else
3276 {
3277 int max = minMenuModesMax_mainModule();
3278 //set to start of after min..
3280 }
3281 //!send message to ourself to process the current mode..
3283 }
3284 else if (strcasecmp(setCmdString,"addwifi")==0)
3285 {
3286 if (deviceNameSpecified)
3287 {
3288 //has to support "Cisco:"
3289 //parse the valCmdString: ssid:password
3290 char str[100];
3291 strcpy(str,valCmdString);
3292 char *token;
3293 char *rest = str;
3294 char* ssid = strtok_r(rest,":", &rest);
3295 char* password = strtok_r(rest,":", &rest);
3296 SerialDebug.printf("addwifi %s, %s\n", ssid?ssid:"null", password?password:"");
3297 //now save as a credential
3298 // main_addWIFICredentials(addSSID, addPassword);
3299 //!send message to ourself to process the current mode..
3300 // invokeCurrentSMModePage(topic);
3301
3302 //NOTE: there can be empty passwords..
3303 char credentials[100];
3304 //!store the JSON version of these credentials..
3305 sprintf(credentials, "{'ssid':'%s','ssidPassword':'%s'}", ssid?ssid:"NULL", password?password:"");
3306 // This works by just sending the credentials to ourself .. and process correctly.
3307 SerialMin.println(credentials);
3308 //!per #224 this will also set WIFI_CREDENTIAL_2 (even if it's also setting #1)
3309 //!NOTE: this saving has to be done before calling processJSON (since the string is goofed upand == 'ssid' not the full string
3311
3312 //!now process the credentials, which will set CREDENTIAL_1
3314
3315 //!print the preferences to SerialDebug
3317
3318 //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..
3319 }
3320 }
3321 else if (strcasecmp(setCmdString,"usedocfollow")==0)
3322 {
3323 SerialDebug.printf("PREFERENCE_USE_DOC_FOLLOW_SETTING %s\n", valCmdString);
3325
3326 }
3327 else if (strcasecmp(setCmdString,"semanticMarker")==0)
3328 {
3329 SerialDebug.printf("SemanticMarker: %s\n", valCmdString);
3331 }
3332 //blankscreen on/off
3333 else if (strcasecmp(setCmdString,"blankscreen")==0)
3334 {
3335 //!if flag then blankscreen, otherwise wake the screen..
3336 if (flag)
3337 //!blanks the screen
3339 else
3340 //!wakes up the screen
3342 }
3343
3344 //!8.17.22 SubDawgpack
3345 else if (strcasecmp(setCmdString,"SubDawgpack")==0)
3346 {
3347 if (deviceNameSpecified)
3348 {
3349 SerialDebug.println("PREFERENCE_SUB_DAWGPACK_SETTING via BLE");
3351 //!for now just reboot which will use this perference
3352 //rebootDevice_mainModule();
3353 if (flag)
3354 {
3355 //! start a dawgpack subscription
3356 //! 8.15.22 Also subscribe to the dawgpack .. but restrict what it can effect.
3357 //! For example, start with STATUS and DOCFOLLOW
3358 _mqttClient.subscribe((char*)"usersP/dawgpack");
3359 }
3360 else
3361 {
3362 // unsubscribe (tested and it works)
3363 _mqttClient.unsubscribe((char*)"usersP/dawgpack");
3364 }
3365 }
3366 }
3367
3368 //!TODO: duplicate and depreciate these and replace with set:buzz,val:on
3369 else if (strcasecmp(setCmdString,"buzz")==0)
3370 {
3371 //! this uses the ASYNC since it involves a BLE command, and has to be done outside
3372 //! of this WIFI (MQTT) operation..
3373 if (flag)
3374 {
3375 SerialDebug.println("BUZZ:ON via BLE");
3377 }
3378 else
3379 {
3380 SerialDebug.println("BUZZ:OFF via BLE");
3382 }
3383 }
3384
3385
3386 //BLECLient
3387 else if (strcasecmp(setCmdString,"bleclient")==0)
3388 {
3389 if (deviceNameSpecified)
3390 {
3391 SerialDebug.println("PREFERENCE_MAIN_BLE_CLIENT_VALUE via BLE");
3393 , flag);
3394 //!for now just reboot which will use this perference
3396 }
3397 }
3398 // bleserver
3399 else if (strcasecmp(setCmdString,"bleserver")==0)
3400 {
3401 if (deviceNameSpecified)
3402 {
3403 SerialDebug.println("PREFERENCE_MAIN_BLE_SERVER_VALUE via BLE");
3405 //!for now just reboot which will use this perference
3407 }
3408 }
3409 else if (strcasecmp(setCmdString,"tilt")==0)
3410 {
3411 if (deviceNameSpecified)
3412 {
3413 SerialDebug.println("PREFERENCE_SENSOR_TILT_VALUE via BLE");
3415 }
3416 }
3417 else if (strcasecmp(setCmdString,"zoomSm")==0)
3418 {
3419 //!zoom == the NON semantic marker version.. so min menu is true
3420 if (flag)
3421 {
3422
3423 //hide semantic marker.. (but only if in the max menus)
3424 //NOTE: this only hides the Semantic Marker - if on a page that has one..
3425 SerialDebug.println("PREFERENCE_SEMANTIC_MARKER_ZOOMED_VALUE ON via BLE");
3427
3428 //!zoom only if in the max menu set..
3430 {
3431 //stay on this page, but change the marker..
3433 }
3434
3435 }
3436 else
3437 {
3438 //show semantic marker..
3439 //NOTE: this only shows the Semantic Marker - if on a page that has one..
3440 SerialDebug.println("PREFERENCE_SEMANTIC_MARKER_ZOOMED_VALUE OFF via BLE");
3443
3444 //!zoom only if in the max menu set..
3446 {
3447 //change to the status..
3449 //!send message to ourself to process the current mode..
3451 }
3452 else
3453 {
3454 //stay on this page, but change the zoom..
3456 }
3457 }
3458 } // zoomSM
3459 //! 9.22.22 added button press from messages..
3460 else if (strcasecmp(setCmdString,"buttonA")==0)
3461 {
3462 if (strcasecmp(valCmdString,"longpress")==0)
3464 else if (strcasecmp(valCmdString,"shortpress")==0)
3466 }
3467 else if (strcasecmp(setCmdString,"buttonB")==0)
3468 {
3469 if (strcasecmp(valCmdString,"longpress")==0)
3471 else if (strcasecmp(valCmdString,"shortpress")==0)
3473 }
3474 else
3475 {
3476 SerialMin.printf("Unknown cmd: %s\n", setCmdString);
3477 }
3478
3479 }
3480 //!5.24.22 send:<request> .. Note these are for cmd without an argument..
3481 else if (sendCmd)
3482 {
3483 //!NOTE: This will be calling ourself
3484
3485 char* sendCmdString = const_cast<char*>(sendCmd);
3486 if (strcasecmp(sendCmdString,"temp")==0)
3487 {
3488 SerialCall.println("sendCmd == temp");
3489 //! request a TEMP be sent.
3490 processBarkletMessage("#TEMP", topic);
3491 }
3492 else if (strcasecmp(sendCmdString,"status")==0)
3493 {
3494 SerialCall.println("sendCmd == status");
3495 //! request a STATUS be sent.
3496 processBarkletMessage("#STATUS", topic);
3497 }
3498 else if (strcasecmp(sendCmdString,"capture")==0)
3499 {
3500 SerialCall.println("sendCmd == capture");
3501 //! request a CAPTURE be sent.
3502 processBarkletMessage("#CAPTURE", topic);
3503 }
3504 else if (strcasecmp(sendCmdString,"volume")==0)
3505 {
3506 SerialCall.println("sendCmd == volume (not implemented)");
3507 //! request a VOLUME be sent.
3508 processBarkletMessage("#VOLUME", topic);
3509 }
3510 else
3511 {
3512 SerialTemp.print("Unknown send request: ");
3513 SerialTemp.println(sendCmdString);
3514 }
3515
3516 }
3517
3518 //!this return is important!!!
3519 return true;
3520 } //!end process commands..
3521
3522 //end NEW
3523 //!TRY without 1.30.22 (RAMS win) and it works..
3524 //!if can talk BLE, then reboot.. 2.2.22
3525
3526 //NOTE: here is where different reasons for the info could be provided in the data>
3527 // eg. dataKind (wifi, mqtt, etc...)boot
3528 /**
3529 {
3530 "ssid" : "SunnyWhiteriver",
3531 "ssidPassword" : "sunny2021",
3532 "mqtt_topic": "usersP/bark/test",
3533 "mqtt_user" : "test",
3534 "deviceName" : "HowieFeeder",
3535 "mqtt_password" : "password..",
3536 "mqtt_guestPassword" : "password",
3537 "uuid" : "scott",
3538 "mqtt_port" : "1883",
3539 "mqtt_server" : "idogwatch.com",
3540 "mqtt_status" : "Success",
3541 "location": "whatever to reply with, GPS, state, city, etc.."
3542 }
3543
3544 //todo pass the guest password too
3545 */
3546 //TODO: parse the string...
3547 //!! Store wifi config. 存储wifi配置信息
3548 //! @see https://arduinojson.org
3549
3550 {
3551 const char* a1 = myObject["ssid"];
3552 if (a1 && strlen(a1)>0)
3553 {
3554 _ssidString = const_cast<char*>(a1);
3556 }
3557 else
3558 _ssidString = NULL;
3559
3560 SerialTemp.println(a1);
3561 SerialTemp.println(_ssidString);
3562 }
3563
3564 {
3565 const char* a2 = myObject["ssidPassword"];
3566 if (a2 && strlen(a2)>0)
3567 {
3568 _ssidPasswordString = const_cast<char*>(a2);
3570 }
3571 else
3572 _ssidPasswordString = NULL;
3573 }
3574
3575 {
3576 //!5.25.22 (50 years since Grateful Dead London Show
3577
3578 //! To support just setting the ssid and password, a JSON
3579 //! of {ssid:s,ssidPassword:p} is supported, so don't null out if mqtt aren't provided..
3580 //! this should work (since the SSID is what's checked to go to the AP mode)
3581
3582 //!the MQTT host/port/user/password (topic is created in this code...)
3583 const char* a3 = myObject["mqtt_server"];
3584 if (a3)
3585 {
3586 _mqttServerString = const_cast<char*>(a3);
3588 }
3589 // else
3590 // _mqttServerString = NULL;
3591 }
3592 {
3593 const char* a4 = myObject["mqtt_port"];
3594 if (a4)
3595 {
3596 _mqttPortString = const_cast<char*>(a4);
3598 }
3599 // else
3600 // _mqttPortString = NULL;
3601 //
3602 }
3603 {
3604 const char* a5 = myObject["mqtt_password"];
3605 if (a5)
3606 {
3607 _mqttPasswordString = const_cast<char*>(a5);
3609 }
3610 // else
3611 // _mqttPasswordString = NULL;
3612 }
3613
3614 {
3615 const char* a6 = myObject["mqtt_user"];
3616 if (a6)
3617 {
3618 _mqttUserString = const_cast<char*>(a6);
3620 }
3621 // else
3622 // _mqttUserString = NULL;
3623 }
3624 {
3625 const char* a7 = myObject["deviceName"];
3626 if (a7 && strlen(a7)>0)
3627 {
3628 _deviceNameString = const_cast<char*>(a7);
3630 }
3631 // else
3632 // _deviceNameString = NULL;
3633 }
3634 {
3635 const char* a8 = myObject["uuid"];
3636 if (a8)
3637 {
3638 _uuidString = const_cast<char*>(a8);
3640 }
3641 // else
3642 // _uuidString = NULL;
3643 }
3644 {
3645 const char* a9 = myObject["mqtt_topic"];
3646 if (a9)
3647 {
3648 _mqttTopicString = const_cast<char*>(a9);
3650 }
3651 // else
3652 // _mqttTopicString = NULL;
3653
3654 }
3655 {
3656 const char* a10 = myObject["mqtt_guestPassword"];
3657 if (a10)
3658 {
3659 _mqttGuestPasswordString = const_cast<char*>(a10);
3661 }
3662 // else
3663 // _mqttGuestPasswordString = NULL;
3664 }
3665
3666 {
3667 const char* a11 = myObject["location"];
3668 if (a11 && strlen(a11)>0)
3669 {
3670 _jsonLocationString = const_cast<char*>(a11);
3672 }
3673 // else
3674 // _mqttGuestPasswordString = NULL;
3675 }
3676
3677 //!reset the MQTT attempts
3679
3680 boolean saveJSONPreferences = true;
3681 //!setup the WIFI if the ssid string (at least) is specified
3683 {
3684 SerialDebug.println("Setting WIFI from JSON parameters");
3685 //setupWIFI(_ssidString, _ssidPasswordString);
3686
3687 //!new: go out and let the process work...
3688 //!set the state, then the 'loop' will call setupWIF(...)
3691
3692 }
3693 else
3694 {
3695 SerialDebug.println(" ***** ERROR .. no ssidString *** ");
3696 //!call the callback specified from the caller (eg. NimBLE_PetTutor_Server .. or others)
3698
3699 saveJSONPreferences = false;
3700 }
3701
3702
3703 //!don't save the preferences, since it didn't have enough information..
3705 {
3706 SerialDebug.println("**** Not saving JSON in preferences ***");
3707 return true;
3708 }
3709
3710 //!NOTE: this writes over entire values, since it's a string vs an JSON object
3712
3713 //!new 4.8.22 .. trying to kick out of AP mode if the credentials are good..
3715
3716 //!putting here .. time might have gone too fast..
3719
3720
3721 return true;
3722}
3723
3724//!restart the WIFI and then MQTT connection
3726{
3727 //let it know MQTT isn't running either
3728 _MQTTRunning = false;
3729
3730 SerialTemp.printf("restartWIFI_MQTTState (%s, %s)\n", _ssidString, _ssidPasswordString);
3731 //putting here .. time might have gone too fast..
3734
3735}
3736
3737//!just update the EPROM, and send that to the WIFI_AP module as well
3739{
3740 DynamicJsonDocument myObject(1024);
3741
3742 //!basically if only the ssid/pass are sent, that is all that's written to EPROM
3743 //!even if the other information is available.. So recreate the JSON instead..
3744 //!seems c++ you cannot re-use output as it just appends to it.. unreal
3745 String output2;
3746 myObject["ssid"] = _ssidString;
3747 myObject["ssidPassword"] = _ssidPasswordString;
3748 myObject["mqtt_server"] = _mqttServerString;
3749 myObject["mqtt_port"] = _mqttPortString;
3750 myObject["mqtt_password"] = _mqttPasswordString;
3751 myObject["mqtt_guestPassword"] = _mqttGuestPasswordString;
3752
3753 myObject["mqtt_user"] = _mqttUserString;
3754 {
3755 char buf[100];
3756 sprintf(buf,"usersP/bark/%s", _mqttUserString?_mqttUserString:"NOTSET");
3758 }
3759 myObject["mqtt_topic"] = _mqttTopicString;
3760 myObject["deviceName"] = _deviceNameString;
3761 myObject["uuid"] = _uuidString;
3762 myObject["jsonHeader"] = _jsonHeaderString;
3763 myObject["jsonVersion"] = _jsonVersionString;
3764 myObject["location"] = _jsonLocationString;
3765
3766
3767 //!JSON
3768 serializeJson(myObject, output2);
3769
3770 //!open the preferences
3772 SerialDebug.print("MQTTNetworking.Writing EPROM JSON = '");
3773 SerialDebug.print(output2);
3774 SerialDebug.println("'");
3775
3776 //!save in EPROM
3778 //! Close the Preferences
3780
3781 //! sets the MQTT user/password. It's up to the code to decide who needs to know (currently saves in the WIFI_APModule
3783#define NO_NEED_AND_GRU_CRASH
3784#ifdef NO_NEED_AND_GRU_CRASH
3785 //!NEW: 2.21.22
3786 //!TRY: reading back..
3787 _preferencesMQTTNetworking.begin(ESP_EPROM_NAME, false); //false=read/write..
3789 SerialDebug.print("Reading.2 EPROM JSON = ");
3790 SerialDebug.println(_fullJSONString? _fullJSONString:"NULL");
3791
3792 //!check ... _fullMessageOut
3793 //! Close the Preferences
3795#endif
3796}
3797
3798#endif //USE_MQTT_NETWORKING
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
char * _ssidString
unsigned long _delayStart_WIFI_MQTTState
the time the delay started
boolean delayFinished_WIFI_MQTTState()
if finished..
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 _delayRunning_WIFI_MQTTState
true if still waiting for delay to finish
boolean _setupMQTTNetworkingAlready
try a flag so setupMQTTnetworking only called 1 times..
char * _mqttPortString
void cleanEPROM_MQTTNetworking()
cleans the eprom info
char _lastDocFollowSemanticMarker[200]
storage for last doc follow semantic marker
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
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...
int _delayCheckWIFISeconds_MQTTNetworking
length of delay
String _topic
the topic the new message came in on..
char _lastMessageStatusURL[100]
storage of the last message status
void setupWIFI_loop()
the loop part of WIFI
void sendMessageMQTT(char *message)
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
Ambers 22nd birthday.. 2.20.22.
const char * getDynamicMessageFunc()
used by the displayModule to call this for each new status
#define REMOTE
float _delaySeconds_WIFI_MQTTState
length of delay
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()
stop the delay
void getChipInfo()
create a unique ID (but it needs to be stored.. otherwise it's unique each time??
char * _mqttPasswordString
void loop_MQTTNetworking()
called for the loop() of this plugin
char * getLastDocFollowSemanticMarker_MQTTNetworking()
char * _mqttUserString
#define MAX_MESSAGE
define this storage once, and use everwhere..
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
void publishBinaryFile(char *topic, uint8_t *buf, size_t len)
publish a binary file..
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
void printWIFIInfo()
print the WIFI info
void startDelay_WIFI_MQTTState()
init the delay, this uses the array of delays so we can change easier..
void invokeCurrentSMModePage(char *topic)
send message to ourself to change to current specifed SM Mode
enum MQTTMessageTopicType _MQTTMessageTopicType
WIFI_MQTTStates _WIFI_MQTTState
the state we are in..
int _counterLoop
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.
char _chipName[50]
char * _mqttServerString
void sendDocFollowMessageMQTT(const char *semanticMarker)
sends the semantic marker as a doc follow message
unsigned long _delayCheckWIFIStart_MQTTNetworking
the time the delay started
void restartDelayCheckWIFI_MQTTNetworking()
starts the delay for WIFI checking, called at startup, and each time the timer finished....
char _semanticMarkerString[MAX_MESSAGE]
Preferences _preferencesMQTTNetworking
3.3.22 Using the new JSON library which is supposed to catch syntax errors without blowing up
#define ACK_FEED2
void setLastDocFollowSemanticMarker_MQTTNetworking(char *semanticMarker)
sets the last DocFollow SemanticMarker
#define ACK_FEED
boolean isDawgpackTopic()
helper to know it's a dawgpack topic (and not process in most cases). Only support DOCFOLLOW for now....
uint32_t _chipId
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
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...
@ 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..
#define MQTT_CALLBACK_TEMP
#define MQTT_CLEAN_SSID_EPROM
#define MQTT_CALLBACK_BLINK
#define MQTT_CALLBACK_FEED
#define MQTT_CALLBACK_SOLID_LIGHT
void takePicture_MainModule()
take a picture (calls the camera module).. what to do with picture??? TODO
Definition: MainModule.cpp:528
#define CALLBACKS_MQTT
Definition: MainModule.cpp:221
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...
Definition: MainModule.cpp:741
char * charSMMode_mainModule(int whichSMMode)
returns string form whichSMMode, sg "sm0", sm1 ...
boolean connectedBLEDeviceIsGEN3_mainModule()
whether the connected is a GEN3 (so the name isn't valid)
int minMenuModesMax_mainModule()
returns the current max of the MIN menu modes (using the setting of min or expanded) to determine
char * main_currentStatusURL()
returns a string in in URL so: status?battery=84'&buzzon='off' } .. etc
void main_credentialsUpdated()
moved here 4.25.22 (entirely from ESP_IOT.ino)
Definition: MainModule.cpp:392
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)
Definition: MainModule.cpp:807
boolean isEmptyString(char *stringA)
informs if null or empty string
void rebootDevice_mainModule()
Definition: MainModule.cpp:616
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:196
void callCallbackMain(int callbacksModuleId, int callbackType, char *message)
performs the indirect callback based on the callbackType
Definition: MainModule.cpp:333
int getCurrentSMMode_mainModule()
returns the current SM Mode
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:557
void main_dispatchAsyncCommand(int asyncCallCommand)
checks if any async commands are in 'dispatch' mode, and if so, invokes them, and sets their flag to ...
Definition: MainModule.cpp:789
int getTimeStamp_mainModule()
void buttonB_LongPress_mainModule()
the long press of the side button
char * createCopy(char *stringA)
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:569
char * main_nextJSONWIFICredential()
! cycle through the next WIFI saved credential
Definition: MainModule.cpp:669
#define SM_home_simple
Definition: MainModule.h:284
#define SM_pair_dev
guest feed device
Definition: MainModule.h:308
#define SM_guest_feed
guest feed
Definition: MainModule.h:306
#define SM_guest_page
guest page
Definition: MainModule.h:299
#define SM_timer
timer .. todo
Definition: MainModule.h:315
#define SM_home_simple_1
Definition: MainModule.h:285
#define SM_home_simple_2
Definition: MainModule.h:286
#define SM_status
//status
Definition: MainModule.h:295
#define ASYNC_SET_GATEWAY_ON
sets the GATEWAY mode on
Definition: MainModule.h:158
#define SM_reboot
REboot.
Definition: MainModule.h:317
#define SM_help
HELP.
Definition: MainModule.h:310
#define ASYNC_CALL_BUZZ_ON
sends a 'B' to the BLE end of the code (assuming a feeder is connected).
Definition: MainModule.h:149
#define ASYNC_POWEROFF
sets the GATEWAY mode off
Definition: MainModule.h:165
#define ASYNC_CALL_CLEAN_EPROM
cleans the EPROM totally, and reboots
Definition: MainModule.h:145
#define ASYNC_SEND_MQTT_STATUS_URL_MESSAGE
sends the status from the main module URL
Definition: MainModule.h:155
#define SM_home_simple_3
Definition: MainModule.h:287
#define ASYNC_SET_GATEWAY_OFF
sets the GATEWAY mode off
Definition: MainModule.h:160
#define ASYNC_CALL_OTA_FILE_UPDATE_PARAMETER
these are the async with a string parameter
Definition: MainModule.h:181
#define ASYNC_CALL_OTA_UPDATE
TODO: make this a registeration approach.
Definition: MainModule.h:141
#define SM_doc_follow
docfollow
Definition: MainModule.h:313
#define SM_smart_clicker_homepage
//! homepage
Definition: MainModule.h:293
#define TOPIC_TO_SEND
Definition: MainModule.h:41
#define SM_WIFI_ssid
WIFI ssid.
Definition: MainModule.h:297
#define SM_ap_mode
AP MODE.
Definition: MainModule.h:302
#define ASYNC_CALL_BUZZ_OFF
sends a 'b' to the BLE end of the code (assuming a feeder is connected).
Definition: MainModule.h:151
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)
connects to host and grabs the http file and tries to update the binary (OTA)
void savePreferenceInt_mainModule(int preferenceID, int val)
sets an int preference
void savePreferenceBoolean_mainModule(int preferenceID, boolean flag)
save a boolean preference
void setDiscoverM5PTClicker(boolean flag)
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 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
char * getPreference_mainModule(int preferenceID)
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
#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_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_SEMANTIC_MARKER_ZOOMED_VALUE
Display preferences (SemanticMarker etc) - boolean.
#define PREFERENCE_WIFI_CREDENTIAL_2_SETTING
#define PREFERENCE_MAIN_BLE_SERVER_VALUE
#define PREFERENCE_PAIRED_DEVICE_SETTING
the paired device for guest device feeding (6.6.22)
#define STEPPER_IS_TUMBLER
#define PREFERENCE_BLE_USE_DISCOVERED_PAIRED_DEVICE_SETTING
#define PREFERENCE_USE_DOC_FOLLOW_SETTING
for
#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 STEPPER_IS_MINI
#define PREFERENCE_HIGH_TEMP_POWEROFF_VALUE
sets the max temp for a poweroff
#define PREFERENCE_STEPPER_ANGLE_FLOAT_SETTING
#define PREFERENCE_MAIN_GATEWAY_VALUE
#define PREFERENCE_STEPPER_CLOCKWISE_MOTOR_DIRECTION_SETTING
#define PREFERENCE_MAIN_BLE_CLIENT_VALUE
boolean saveJSONPreferences
Definition: REFAcTOR.c:525
void println_SPIFFModule(char *string)
print a string to spiff (a new line is added)
void printInt_SPIFFModule(int val)
print a int to spiff (NO new line is added)
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
void printFile_SPIFFModule()
prints the spiff file to the SerialDebug output
void print_SPIFFModule(char *string)
print a string to spiff (NO new line is added)
void deleteFiles_SPIFFModule()
delete the spiff files..
void setup_SPIFFModule()
the setup for this module
void saveScreen_SPIFFModule()
save the screen to a file on the SPIFF
boolean queryMatchesName_mainModule(char *name)
void parseQueryLine_mainModule(char *line)
parses a line of text, returning the number of tokens..