ESP_IOT v2.5
IOT ESP Coding
MainModule.cpp
Go to the documentation of this file.
1//! \link MainModule
2#include "../../Defines.h"
3//#include "MainModule.h"
4
5#define USE_NEW_M5ATOMCLASS
6//! 5.6.25 use the M5Atom ClassType
7#ifdef USE_NEW_M5ATOMCLASS
8//! @see https://www.cs.fsu.edu/~myers/cop3330/notes/dma.html
9#include "../M5AtomClassModule/M5AtomClassType.h"
10
11#include "../M5AtomClassModule/M5Atom_SocketModuleClass.h"
12#include "../M5AtomClassModule/M5Atom_QRCodeModuleClass.h"
13#include "../M5AtomClassModule/M5Atom_HDriverModuleClass.h"
14//! 5.9.25 -- Dead 77
15#include "../M5AtomClassModule/M5Atom_Core2ModuleClass.h"
16//! 7.17.25 - Adding GPS
17#include "../M5AtomClassModule/M5Atom_TinyGPSModuleClass.h"
18//! 8.16.25 bring in the CameraModule from 2022
19#include "../M5AtomClassModule/M5Atom_CameraModuleClass.h"
20//! 10.26.25 Power Out .. Wind Storm. Generator Running
21//! add a NoModule class
22#include "../M5AtomClassModule/M5Atom_NoModuleClass.h"
23
24//! 7.24.25 Hot Day, Ballon last night, Mt Out
25//! for the 'C' option of atom color
26#ifdef USE_FAST_LED
27#include "../ATOM_LED_Module/M5Display.h"
28#endif
29
30#pragma mark BUTTON Processing of M5
31//! 10.16.25 add buttons
32boolean _shortPress_MainModule = false;
33boolean _longPress_MainModule = false;
35//!big button on front of M5StickC Plus
38
39//! instances of the M5AtomClassType
40#pragma mark M5AtomClassType
41
42//1
44//2
46//3
48//4
50//! 7.17.25 - Adding GPS
51//! 5
53//! 8.16.25 bring in the CameraModule from 2022
54//! 6
56//! 10.26.25 Power Out .. Wind Storm. Generator Running
57//! add a NoModule class
59
60//! make sure this is updated.
61//! 8.16.25 == 6
62//! 10.26.25 == 7
63#define NUM_M5ATOM_CLASS 7
64
65//! 3.31.25 create array of plugs
67
68//! use this one...
70
71#endif //USE_NEW_M5ATOMCLASS
72
73#pragma mark SensorClassType
74
75#define USE_SENSOR_CLASS
76#ifdef USE_SENSOR_CLASS
77//! 5.14.25
78#include "../SensorClass/SensorClassType.h"
79#include "../SensorClass/BuzzerSensorClass.h"
80#include "../SensorClass/KeyUnitSensorClass.h"
81//! 11.27.25 add PIRSensor
82#include "../SensorClass/PIRSensorClass.h"
83//! 12.19.25 48 hrs no power, high wind storm, flooding in lowlands - bad
84//! this will be the ChainButtonClass
85#include "../SensorClass/ChainButtonClassType.h"
86
87#define NUM_SENSOR_CLASS_TYPES 4
88//!
90//2
92//3
94//4
96
97//! 11.28.25 Clear day, M5 Out
98//! create array of instances POSSIBLE (the Sensors, pin1,pin2 -- will instantiate them)
100
101//! 11.27.25 Turkey Day, loop
103{
104 //return; //! 11.28.25 inifinite loop when using a sensor is defined, but no instance created, eg StepperMotor ..
105
106 //! return the sensor specified or null
108 //SerialDebug.printf(" *** loopSensorClassTypeArray (%ld) ***\n", sensorsStruct?sensorsStruct->count:-1);
109#define SERIAL_LOTS_
110#ifdef SERIAL_LOTS
111 //! try a debug print..
113#endif
114
115 if (sensorsStruct)
116 {
117 //! all the sensors defined
118 //! sensors is an array of sensor
120 int count = sensorsStruct->count;
121
122 //! go through the defined sensorName and call loop on those classes
123 for (int i=0; i< count; i++)
124 {
125 //! this only works if there is an instance there of value .. the NULL doesn't work
126 //! as this is a memory location somethwere.
127 //! so the instantiator will now create a DUMMY SensorClass object .. so this works.
128 //! The issue is there can be a sensor that doesn't exist so that slot is empty .. but the &sensors[i] BLOWS up
129 SensorStruct* sensor = &sensors[i];
130
131 //! 11.28.25 KLUDGE .. for now only this sensor has a loop
132 // if (strcmp(sensor->sensorName, (char*)"PIRSensorClass")==0)
133 //! check sensor exists ..
134 if (sensor)
135 {
136 //check this??? PIR HAT only one so far that needs this ...
137 sensor->sensorClassType->loop();
138 }
139 }
140
141 }
142}
143
144//! 1.24.26 send the setval of the MQTT message ..TODO
145//! 11.27.25 Turkey Day, loop
146void messageSetVal_SensorClassTypeArray(char *setName, char* valValue, boolean deviceNameSpecified)
147{
148 //return; //! 11.28.25 inifinite loop when using a sensor is defined, but no instance created, eg StepperMotor ..
149
150 //! return the sensor specified or null
152 if (sensorsStruct)
153 {
154 //! all the sensors defined
155 //! sensors is an array of sensor
157 int count = sensorsStruct->count;
158
159 //! go through the defined sensorName and call loop on those classes
160 for (int i=0; i< count; i++)
161 {
162 //! this only works if there is an instance there of value .. the NULL doesn't work
163 //! as this is a memory location somethwere.
164 //! so the instantiator will now create a DUMMY SensorClass object .. so this works.
165 //! The issue is there can be a sensor that doesn't exist so that slot is empty .. but the &sensors[i] BLOWS up
166 SensorStruct* sensor = &sensors[i];
167
168 //! check sensor exists ..
169 if (sensor)
170 {
171 SensorClassType *sensorClassType = sensor->sensorClassType;
172 if (sensorClassType)
173 //! forward the message
174 sensorClassType->messageSetVal_SensorClassType(setName, valValue, deviceNameSpecified);
175 }
176 }
177 }
178}
179
180//! init will look at those SensorClass known above, and look
181//! to see which ones are defined by the user in the SensorsStruct
182//! A report will show which ones were not found
184{
185 SerialDebug.println(" *** initSensorClassTypeArray ***");
186
187 //! create possible Sensor class instan ces
188 //! 11.28.25
189 //! use the class name as identity()
190 _BuzzerSensorClass = new BuzzerSensorClass((char*)"BuzzerSensorClass");
191 _KeyUnitSensorClass = new KeyUnitSensorClass((char*)"KeyUnitSensorClass");
192 _PIRSensorClass = new PIRSensorClass((char*)"PIRSensorClass");
193 //! 12.19.25 add Class type for Chain
194 _ChainButtonClass = new ChainButtonClass((char*)"ChainButtonClass");
195
196 //! 11.28.25 Clear day, M5 Out
197 //! create array of instances POSSIBLE (the Sensors, pin1,pin2 -- will instantiate them)
199
200 int whichSensorClassIndex = 0;
201 SerialDebug.println("setup_SensorClassIypes");
202
203 //! 11.28.25 create array of Sensors
204 _SensorClassTypes[whichSensorClassIndex++] = _BuzzerSensorClass;
205 _SensorClassTypes[whichSensorClassIndex++] = _KeyUnitSensorClass;
206 _SensorClassTypes[whichSensorClassIndex++] = _PIRSensorClass;
207 //! 12.19.25 add ChainButtonClass
208 _SensorClassTypes[whichSensorClassIndex++] = _ChainButtonClass;
209
210 //! add check..
211 if (whichSensorClassIndex > NUM_SENSOR_CLASS_TYPES)
212 {
213 SerialDebug.printf("**** sensors are more than max .. FIX CODE");
214 }
215 SerialDebug.printf("Created %d SensorClassTypes\n", whichSensorClassIndex);
216
217
218 //! return the sensor specified or null
220 if (sensorsStruct)
221 {
222 //! all the sensors defined
223 //! sensors is an array of sensor
225 int count = sensorsStruct->count;
226
227 //! 11.28.25 use the SensorClassType (like the M5AtomClassType pattern)
228 //! go through the defined sensorName and instantiate those classes
229 for (int i=0; i< count; i++)
230 {
231 SensorStruct* sensor = &sensors[i];
232 SerialDebug.printf("Looking for sensor: %s, %ld, %ld\n", sensor->sensorName, sensor->pin1, sensor->pin2);
233 //! find matching sensor instantiated
234 SensorClassType *whichSensorClassType = NULL;
235 boolean foundMatchingClassType = false;
236 for (int whichSensor=0; whichSensor<NUM_SENSOR_CLASS_TYPES; whichSensor++)
237 {
238 //! look for ths sensor mentioned..
239 whichSensorClassType = _SensorClassTypes[whichSensor];
240 char *sensorIdentity = whichSensorClassType->classIdentity();
241 if (strcmp(sensor->sensorName, sensorIdentity)==0)
242 {
243 //! set the running sensor type for this instnce (currently only 1 per sensor type)
244 sensor->sensorClassType = whichSensorClassType;
245
246#ifdef ALL_ARE_SENSOR_CLASS
247 //! 12.20.25 Winter Solstice party, do some polymorphsm if different sub-class (ChainButtonClassType)
248 //! @see https://forum.arduino.cc/t/casting-from-base-class-to-derived-class/849723/9
249 //! not allowed ....
250 //! @see https://stackoverflow.com/questions/307765/how-do-i-check-if-an-objects-type-is-a-particular-subclass-in-c
251 //! 12.21.25 Eagles 2
252 //! no static, no dynamic (now try typeid)
253 //if (dynamic_cast<ChainButtonClass*>(whichSensorClassType) != nullptr)
254 //if (static_cast<ChainButtonClass>(whichSensorClassType) != nullptr)
255 switch (whichSensorClassType->type())
256 {
258
259 //! this is a ChainButton .. do something different..
260 SerialDebug.printf("whichSensorClass == ChainButtonClassType\n");
261 //! SET the other sensors
262 //! TODO .. set it's values differently (no Pins)
263 //! 1.22.26 2026
264 //! set the messages and button definition..
265 //! NOTE: the button number will have to be set as well.
266 //! Actually there will be a lot of info for the button configuration
267 //! already read into the SensorStruct
268 break;
270
271 //! this is a ChainButton .. do something different..
272 SerialDebug.printf("whichSensorClass == SensorClassType\n");
273 //! call this setup and pin sets
274 //! setup and then setPins..
275 whichSensorClassType->setPinValues(sensor->pin1, sensor->pin2);
276 //! TODO .. set it's values differently (no Pins)
277 break;
278 }
279#else
280 //! call this setup and pin sets
281 //! setup and then setPins..
282 whichSensorClassType->setPinValues(sensor->pin1, sensor->pin2);
283 //! 1.22.26 the Chain will read the button definitions at setup time and loop time
284#endif
285
286
287 //! call setup
288 whichSensorClassType->setup();
289 //! exit loop
290 foundMatchingClassType = true;
291 break;
292 }
293 }
294#ifdef NOT_OO_ENOUGH
295 if (strcmp(sensor->sensorName, "BuzzerSensorClass")==0)
296 {
297 //! init this class
298 _BuzzerSensorClass = new BuzzerSensorClass((char*)"BuzzerSensorClass");
299 //! store the class type instance
301 //! setup and then setPins..
302 _BuzzerSensorClass->setPinValues(sensor->pin1, sensor->pin2);
303
304 //! call setup
306 }
307 //! 11.27.25 Turkey Day, Mt Out nice
308 //! adding the PIRSensorClass
309 else if (strcmp(sensor->sensorName, "PIRSensorClass")==0)
310 {
311 //! init this class
312 _PIRSensorClass = new PIRSensorClass((char*)"PIRSensorClass");
313 //! store the class type instance
315 //! setup and then setPins..
316 _PIRSensorClass->setPinValues(sensor->pin1, sensor->pin2);
317
318 //! call setup
320 }
321#endif
322 if (!foundMatchingClassType)
323 {
324 SerialDebug.printf("Missing SensorClass definition: %s\n", sensor->sensorName);
325 sensor->sensorClassType = NULL;
326 }
327 }
328 //! find missing sensors
329 //! go throug the defined sensorName and instantiate those classes
330 for (int i=0; i< count; i++)
331 {
332 SensorStruct* sensor = &sensors[i];
333 if (!sensor->sensorClassType)
334 {
335 //! missing instance
336 SerialDebug.printf("Missing class definition: %s\n", sensor->sensorName);
338 }
339 }
340 }
341 SerialDebug.println("Finish initSensorClassTypeArray");
342}
343#endif
344
345//! 6.7.25 hot air balloons over house..
346//! stops the motor
348{
351}
352
353//! gets if PTFeeder a surrogate for the M5Atom class
355{
358 else
359 //!Defines the name of the service of the server, which for M5 will be PTClicker
360 {
361 return containsSubstring(MAIN_BLE_SERVER_SERVICE_NAME, "PTFeeder");
362 }
363 /*
364#ifdef ESP_M5
365#define MAIN_BLE_SERVER_SERVICE_NAME (char*)"PTClicker"
366#else
367#define MAIN_BLE_SERVER_SERVICE_NAME (char*)"PTFeeder"
368#endif
369 */
370}
371
372//! 10.10.25 #405 #406
373//! see if the device is a PTClicker if the M5Atom class is one..
374//! return the service name: PTClicker or PTFeeder
376{
378 return MAIN_BLE_SERVER_SERVICE_NAME_PTFeeder;
379 else
380 return MAIN_BLE_SERVER_SERVICE_NAME_PTClicker;
381}
382//! reads the preferences. Save is everytime the savePreference is called
384//!testing..
385boolean _stopAllProcessing = false;
386//!stop all loops... while OTA working..
388{
389 _stopAllProcessing = true;
390}
391//!restart all loops... while OTA working..
393{
394 _stopAllProcessing = false;
395}
396//! if stopped
398{
399 //! try to disconnect..
400 //disconnect_BLEClientNetworking();
401 // return false; //
402 return _stopAllProcessing;
403}
404
405//****** GLOBALS (shows how much memory is allocated.. )
406//!the parameter being sent to those commands passing an argument
408//!global to store credentials when ever they are stored..
410//!global for others to use..
411#define MESSAGE_STORAGE_MAX 500
413//!status string (URL query format)
415//! current smMode
417//! saved deviceName storage..
419
420//!store a big message #MSG_START .. #MSG_END
422char _bigMessage[500];
423//!saved BLE connected name 8.26.22
425//!full: ""Name: PTFeeder:HowieFeeder, Address: 7c:9e:bd:48:af:92, serviceUUID: 0xdead"
427//!full: ""Address: 7c:9e:bd:48:af:92, serviceUUID: 0xdead"
429
430//!init globals strings
432{
433 //!NOTE: this is definitely needed, as grabbing strings willy nilly can bomb or corrupt stuff..
434 strcpy(_connectedBLEDeviceName,(char*)"");
435 strcpy(_bigMessage,(char*)"");
436 strcpy(_deviceNameSave,(char*)"");
437 strcpy(_smMode_MainModule,(char*)"");
438 strcpy(_fullStatusString,(char*)"");
439 strcpy(_messageStorage,(char*)"");
440 strcpy(_JSONStringForWIFICredentials,(char*)"");
441 strcpy(_asyncParameter,(char*)"");
442 strcpy(_fullBLEDeviceName,(char*)"");
443
444 main_setScannedDeviceName((char*)"");
445 //! 1.7.24
446 main_setScannedGroupName((char*)"");
447}
448
449//THIS IS the setup() and loop() but using the "component" name, eg MQTTNetworking()
450//! called from the setup()
452{
453 SerialMin.println("setup_mainModule");
454#ifdef BOOTSTRAP_CLEAN
455 //!cleans the EPROM .. if things are really not working..
457#endif
458#define TEMP_FIX_LOOP_NO
459#ifdef TEMP_FIX_LOOP
460 setSensorsString_mainModule((char*)"BuzzerSensorClass,21,25");
461#endif
462
463 //test...
464 //! setup for the token parser (really just for testing) -- an
466
467 //!init globals like strings (but nothing that needs preferences)
469
470 //!read the preferences from EPROM
472
473 //!must initialize the structs NOTE: this has to ber AFTER the preferences are read in..
475
476 //!a first time feature .. to get EPROM changed to a different default
478 {
479
480 //!7.12.22
481 //! {'dev':'m5",'cmd':'bleserveron'} or bleserveroff will work later..
482 //!#issue 116 .. turn off the BLE_Server for the M5
483 SerialMin.println("FIRST TIME TURNING off the BLE_SERVER for the M5");
484#ifdef ESP_M5
485
486#ifdef M5_ATOM
487 //! 5.6.25 use object version
489
490#else // not M5_ATOM
491
492 // 8.28.23 .. not doing this anymore..
494
495 //! not ESP_M5
496#endif // M5_ATOM
497#else // NOT ESP_M5
499#endif
500 //! all ..
502 }
503
504#define NEW_SENSORS
505 //! 5.14.25 use the Sensor types
506 //! first we have N sensors
507 //! then we get which ones the user wants (the SENSORS_SETTING)
508 //! then we instantiate, and provide ping, etc.
510
511#define TRY_DUPLICATES_works
512#ifdef TRY_DUPLICATES
513 {
514 //! 8.32.25 added a test .. the '.' needs to run.. to see the error
515 registerPinUse_mainModule(22, "TestPin22", "MainModule", false);
516 registerPinUse_mainModule(27, "TestPin27", "MainModule", false);
517 }
518#endif
519
520 SerialDebug.println("END setup_mainModule");
521}
522
523#if defined(ESP_M5_CAMERA) || defined(ESP_32)
524//!a couinter to slow down the loop doing things..
525int _mainLoopCounter = 0;
526#endif
527
528//! storage for reading from the serial buffer
529//! 6.20.25 (Sam Sprague grad Western party)
531
532//! called for the loop() of this plugin
534{
535 //no op..
536
537
538
539#if defined(ESP_M5_CAMERA) || defined(ESP_32)
540 //!only do this menu update if there is no DisplayModule running the MVC loop
541
542 if (_mainLoopCounter++ > 30)
543 {
544 //! 9.2.22 new .. update the timer. This is on blank screen as well .. so don't check _semanticMarkerShown
546
547 _mainLoopCounter = 0;
548 }
549
550#endif
551
552#pragma mark Serial Input Processor
553 //! 6.20.25 works with full code (JSON, or single commands - with '.' as help)
554 //! 6.19.25 Mt Peak finally (kept to 124 bpm)
555 //! Per ##373 let the serial monitor get some input, and let us set a few features
556 //! see if data on the serial input
557 //! Re-indexed and now command completion works!!!!!! 3 years later.
558 //!@see https://developer.apple.com/documentation/corespotlight/regenerating-your-app-s-indexes-on-demand?language=objc
559 if (Serial.available())
560 {
561 // read string until meet newline character
562 String command = Serial.readStringUntil('\n');
563
564 SerialDebug.println(command);
565 //! save globally for the callback below..
566 strcpy(_serialBuffer, command.c_str());
567
568 if (command == "help")
569 {
570 SerialDebug.println("Enter any Single Char or JSON msg, type '.' for commands");
571 SerialDebug.println("r -- reboot");
572 SerialDebug.println(". -- shows single char commands");
573 SerialDebug.println("Example JSON to change WIFI (copy and modify with your values)");
574 SerialDebug.println(" supports single quotes for values");
575 SerialDebug.println("{'ssid':'Bob', 'ssidPassword':'scott'}");
576
577 }
578 else if (command == "r")
579 {
581 }
582 else
583 {
584 //!call the callback specified from the caller (eg. NimBLE_PetTutor_Server .. or others)
586 }
587 }
588
589#pragma mark button processing
590#ifdef USE_BUTTON_MODULE
591#else
592 //! 10.16.25 add the M5.update here...
593 M5.update();
594
595 //! 10.16.25 Mt out .. looks like storm comming
596 //! implement the buttonA here..
597 //!big button on front of M5StickC Plus
599 //! 10.16.25 seems the big button on M5ATOM is Button B ..
602 {
604 }
605 else if (_longPress_MainModule)
606 {
608 }
610 {
611 //! 11.25.25 Cold 30's
612 //! call the long long
614 }
615#endif
616
617 //! 11.27.25 Turkey Day, loop
619}
620
621
622//! 5.3.22 added a feed count approach.. (NOTE: there is a _feedCount in Dispence.cpp ... and no linker error!!! )
624//!returns the max for this feeder
626{
627 int max = 16;
628 switch (getFeederType_mainModule())
629 {
630 case STEPPER_IS_UNO:
631 max = 16;
632 break;
633 case STEPPER_IS_MINI:
634 max = 55;
635 break;
637 max = 50;
638 break;
639 }
640 return max;
641}
642//!feedcount info..
644{
646}
647
648//!get the feeder type (Sepper 1,2,3 ...)
650{
652 return kind;
653}
654
655//!increments .. and if MAX goes to 0 -- and sends a message on MQTT
657{
658 SerialTemp.println("incrementFeedCount_mainModule");
659
662 {
663 // send a message.
664 //! 8.16.25 MQTT
665 //note needs # or won't send..
666 //!NOTE: don't send "feed" as it might trigger a FEED ...
667 sendMessageMQTT((char*)"#count reached .. resetting");
668
670 }
671
672 //! called by the feed operation to say the device is still running.. and count it as a button click.
673 //! Issue #145 8.8.22
675
676}
677//! sets the feed count max
679{
681}
682
683//!check if the string contains the other string. This is a poor man's grammer checker
684bool containsSubstring(String message, String substring)
685{
686 if (substring.length() == 0 )
687 return false;
688 bool found = strstr(&message[0], &substring[0]);
689 SerialLots.printf("containsSubstring-%d - %s in: %s\n", found, &substring[0], &message[0]);
690 return found;
691}
692
693//! 8.16.25 MQTT
694#include "../MQTTModule/MQTTNetworking.h"
695
696//! 8.16.25 BLE SERVER
697#include "../BLEServerModule/BLEServerNetworking.h"
698
699//! 8.16.25 BLE CLIENT
700#include "../BLEClientModule/BLEClientNetworking.h"
701#ifdef USE_BUTTON_MODULE
702#include "../ButtonModule/ButtonProcessing.h"
703#endif
704
705//! New RegisterCallback that works across a number of callback modules
706//!
707//! callbacksModuleId
708#define CALLBACKS_MQTT 0
709#define CALLBACKS_BUTTON_MODULE 1
710#define CALLBACKS_BLE_CLIENT 2
711#define CALLBACKS_BLE_SERVER 3
712
713
714//!register the callback based on the callbackType. use the callbacksModuleId for which one..
715void registerCallbackMain(int callbacksModuleId, int callbackType, void (*callback)(char*));
716//!performs the indirect callback based on the callbackType
717void callCallbackMain(int callbacksModuleId, int callbackType, char *message);
718
719
720//!make sure these are the number of callbacks.. 0..n
721//! These values are from the respective .h of the modules
722#define CALLBACKS_MAX_MQTT MQTT_MAX_CALLBACKS
723#define CALLBACKS_MAX_BUTTON_MODULE MAX_CALLBACKS_BM
724#define CALLBACKS_MAX_BLE_CLIENT BLE_CLIENT_MAX_CALLBACKS
725#define CALLBACKS_MAX_BLE_SERVER BLE_SERVER_MAX_CALLBACKS
726
727
728//!example callback
729void dummyCallbackMain(char *message)
730{
731 SerialLots.printf("No callback defined .. %s\n", message);
732}
733
734//tricky getting array of arrays (or pointers to arrays), without dynamic memory.. we are going to use calloc()
735//https://www.geeksforgeeks.org/dynamic-memory-allocation-in-c-using-malloc-calloc-free-and-realloc/
736//https://www.tutorialspoint.com/cprogramming/c_pointer_to_pointer.htm
737//https://stackoverflow.com/questions/5573302/pointer-to-an-array-of-function-pointers
738//!the array of callback functions
739//* this means there are arrays of N pointers to functions that take 1 parameter (char*).
740
741
742//! the max of each module .. hard coded (or 0 if module not there)
744
745//!flag for initializing if not yes
747
748//a pointer to a callback function that takes (char*) and returns void
749typedef void (*callbackSignature)(char *);
750//callbackSignature fpar[2] = {&dummyCallbackMain, &dummyCallbackMain};
751
752//!return dyamically created array of max
754{
755 SerialLots.printf("creatingCallbacks %d size: %d\n", max, sizeof(callbackSignature *));
756 callbackSignature *callbackArray = (callbackSignature *)calloc(max,sizeof(callbackSignature *));
757 for (int i=0; i< max; i++)
758 {
759 callbackArray[i] = &dummyCallbackMain;
760 }
761 return callbackArray;
762}
763//!array of known size (CALLBACKS_MODULE_MAX) of callbackSignatures
765
766//!init the callbacks to dummy callbacks
768{
770 {
772
773 // default to 0 callbacks.. in case module not there..
774 for (int i = 0; i < CALLBACKS_MODULE_MAX; i++)
775 {
777 }
778 //! only place for #ifdef (NOTE some can be 0 based on the #ifdef module not being included..
779 //! 8.16.25 MQTT
781 //! 8.16.25 BLE SERVER
783 //! 8.16.25 BLE CLIENT
785#ifdef USE_BUTTON_MODULE
787#endif
788 // initialize the dummy callbacks
789 for (int i = 0; i < CALLBACKS_MODULE_MAX; i++)
790 {
791 //first determine how many are in the array..
792 int max = _callbacksFunctionsMAXS[i];
793 //then create the space which are (void *) pointers
794 _allCallbacks[i] = createMemory(max);
795 }
796 }
797}
798
799//!register the callback based on the callbackType. use the callbacksModuleId for which one..
800void registerCallbackMain(int callbacksModuleId, int callbackType, void (*callback)(char*))
801{
802 SerialLots.printf("registerCallbackMain %d, %d\n", callbacksModuleId, callbackType);
803
804 //init if not already..
806 int max = _callbacksFunctionsMAXS[callbacksModuleId];
807
808 if (callbackType < 0 || callbackType >= max)
809 {
810 SerialError.printf("#### Error outside callback range - 1, %d\n", callbackType);
811 }
812 else
813 {
814 // array of arrays (or array of pointer to another array)
815 _allCallbacks[callbacksModuleId][callbackType] = callback;
816 }
817}
818//!performs the indirect callback based on the callbackType
819void callCallbackMain(int callbacksModuleId, int callbackType, char *message)
820{
821 //init if not already..
823 int max = _callbacksFunctionsMAXS[callbacksModuleId];
824
825 if (callbackType < 0 || callbackType >= max)
826 {
827 SerialError.printf("#### Error outside callback range - 2, %d\n", callbackType);
828
829 }
830 else {
831 void (*callbackFunction)(char *) = _allCallbacks[callbacksModuleId][callbackType];
832 (*callbackFunction)(message);
833 }
834}
835
836//!whether the string is TRUE, ON, 1
837boolean isTrueString_mainModule(String valCmdString)
838{
839 return valCmdString.equalsIgnoreCase("on") ||
840 valCmdString.equalsIgnoreCase("1") ||
841 valCmdString.equalsIgnoreCase("true");
842};
843
844//! 8.28.23 Adding a way for others to get informed on messages that arrive
845//! for the set,val
846//! 1.10.24 if deviceNameSpecified then this matches this device, otherwise for all.
847//! It's up to the receiver to decide if it has to be specified
848void messageSetVal_mainModule(char *setName, char* valValue, boolean deviceNameSpecified)
849{
850 SerialCall.printf("messageSetVal(%s,%s)\n", setName, valValue);
851 // THE IDEA WOULD be a callback is avaialble..
852 //FOR now.. just ifdef
853#ifdef M5_ATOM
854 //! 5.6.25 use object version
856 _whichM5AtomClassType->messageSetVal_M5AtomClassType(setName, valValue, deviceNameSpecified);
857
858 //! 1.24.26 call the same on the SensorClassType
859 messageSetVal_SensorClassTypeArray(setName, valValue, deviceNameSpecified);
860
861#endif //M5_ATOM
862
863#ifdef M5CORE2_MODULE
864 //! TODO fix this
865 messageSetVal_M5Core2Module(setName, valValue, deviceNameSpecified);
866#endif
867}
868//!TODO: have a callback regist approach
869
870//! 12.28.23, 8.28.23 Adding a way for others to get informed on messages that arrive
871//! for the set,val
872//! 5.21.25 SEND and CMD will be treated the same and put to "send"
873void messageSend_mainModule(char *sendValue, boolean deviceNameSpecified)
874{
875//! 5.21.25 this will overlap with the "cmd" .. so send == cmd
876#ifdef M5_ATOM
877#pragma mark USE_NEW_M5ATOMCLASS
878
879 //! 5.6.25 use object version
881 _whichM5AtomClassType->messageSend_M5AtomClassType(sendValue, deviceNameSpecified);
882
883#endif //M5_ATOM
884
885#ifdef M5CORE2_MODULE
886 //! TODO FIX THIS
887 messageSend_M5Core2Module(sendValue);
888#endif
889}
890
891//! 8.16.25 MQTT
892//!example callback: but the scope would have the pCharacteristic defined, etc..
893//!This is passed just before the setupMQTTNetworking() is called..
894void feedMessageCallback(char *message)
895{
896 SerialTemp.print("feedMessageCallback_main: ");
897 SerialTemp.println(message);
898 char * rxValue = (char*)"c"; //feed (s and 0 work too) MIGHT NOT BE WORKING IF MESSAGE ARRIVES VIA MQTT (and we want to use BLE)
899 //!sends this single character to the StepperModule
901
902 //!increment the feed count .. TODO .. see if this is good place..
903// incrementFeedCount_mainModule();
904
905 //!the FEED was send over MQTT, now what to do?
906 //! WIth the StepperModule -- it just performs the feeding internalls
907 //! if using the BLE_CLIENT then we have the potential to send to over BLE
908 //! to the server (another feeder, GEN3 or ESP32).
909 //! The issue is that ESP32 feeders are receiving the same MQTT message (usually unless MQTT turned off
910 //! So the gatewayMode can be set (or in the EPROM) using {'cmd':'gatewayOn'}
912 {
913 //! 8.16.25 BLE CLIENT
914
915 SerialTemp.print("Paired Device: ");
917
918 SerialTemp.printf("Gateway: Feeding over the BLE CLIENT network .. if connected: %d\n",isConnectedBLEClient());
920 {
921 //!send the feed over the BLE client (if connected)
923 }
924 SerialLots.println("after send feed via ble");
925 }
926
927 //! 11.26.25 try the #STATUS on every feed
928 SerialDebug.println("FEED now send STATUS");
929 sendMessageMQTT((char*)"#STATUS");
930}
931
932//!moved here 4.25.22 (entirely from ESP_IOT.ino)
933
934//! April 8, 2022
935//! set that the credentials are set. Called from the MQTT after processJSONMessage() found things were good..
937{
938 // set the done in the WI
939 SerialDebug.println(" *** main_credentialsUpdated .. setDoneWIFI_APModuleFlag **");
940 //! 8.16.25 WIFI AP
942}
943//NOTE: #else not there so this won't link.. on purpose
944
945/*******************************BLE Server*************************************/
946//!The callback for "onWrite" of the bluetooth "onWrite'
947void onBLEServerCallback(char *message)
948{
949 SerialCall.print("onWriteBLEServerCallback: ");
950 SerialCall.println(message);
951
952}
953//! The callback for "status messages" of the bluetooth
955{
956 SerialCall.print("onStatusMessageBLEServerCallback");
957 SerialCall.print(message);
958 //! 2.2.22 send this over bluetooth.. TODO.
959 //
960}
961
962//! The FINISH of callback for "onWrite" of the bluetooth "onWrite'
964{
965
966 SerialDebug.print("onWriteBLEServerCallback_main: ");
967 SerialDebug.println(message);
968
969 //!client never sends these wrapped messages of length 1, so process normally..
970 //!gets us out of potential infinite wait
971 if (strlen(message) == 1)
973
974 if (strcmp(message, "#MSG_START")==0)
975 {
977 strcpy(_bigMessage,"");
978 return;
979 }
981 {
982 if (strcmp(message, "#MSG_END")==0)
983 {
985 //! we are done.. send big message to ourself..
987 }
988 else
989 {
990 strcat(_bigMessage,message);
991 return;
992 }
993 }
995
996 //!Issue: the message is arriving via BLE, but if we call the MQTT process, it might call us back to send
997 //!the message over BLE. This hangs things up!
998 //!So short optimization for 'feed' will be to look for cmd and feed in message {cmd:feed}
999 //!8.19.22 issue #162
1000 if (containsSubstring(message,"cmd"))
1001 {
1002 if (containsSubstring(message,"feed"))
1003 {
1004 message = (char*)"s";
1005 }
1006 else if (containsSubstring(message,"buzzOn"))
1007 {
1008 message = (char*)"B";
1009 }
1010 else if (containsSubstring(message,"buzzOff"))
1011 {
1012 message = (char*)"b";
1013 }
1014
1015 }
1016
1017 //! 8.16.25 MQTT
1018 //This should be a 'register' command..
1019
1020 //!the MQTTNetwork.processJSONMessage()
1021 //!will return true if the message was JSON and was processes, false otherwise.
1022 if (processJSONMessageMQTT(message, NULL))
1023 {
1024 //!processed by the MQTTNetworking code..
1025 //! 8.16.25 BLE SERVER
1027 //pCharacteristic->setValue(0x01); //?? This is the acknowlege(ACK) back to client. Later this should be contigent on a feed completed
1028 }
1029 else
1030 {
1031 //!perform feed...
1032 SerialDebug.printf("Perform BLE Command '%s'\n", message);
1033
1034 char cmd = message[0];
1035
1036 //OOOPS.. we need the ProcessClientCmd .. for other than just step..
1037 // for sensors..
1038
1039 //!look for ** sensor commands..
1041
1042 //! 8.16.25 BLE SERVER
1044
1045 }
1046 SerialDebug.println("*********");
1047
1048} //onWriteBLEServerCallback
1049
1050//! The callback for "onWrite" of the bluetooth "onWrite'
1051void onWriteBLEServerCallback(char *message)
1052{
1053 //TEST:
1054#define TRY_ASYNC_BLE_PROCESSING
1055#ifdef TRY_ASYNC_BLE_PROCESSING
1056
1057 //!send an async call with a string parameter. This will set store the value and then async call the command (passing the parameter)
1058 //!These are the ASYNC_CALL_PARAMETERS_MAX
1060#else
1061
1062 //! The callback for "onWrite" of the bluetooth "onWrite'
1063 onWriteBLEServerCallbackFinish(char *message);
1064#endif
1065}
1066
1067//! called by the feed operation to say the device is still running.. and count it as a button click.
1069{
1070#ifdef USE_BUTTON_MODULE
1071 //!calls the button processing control
1072 refreshDelayButtonTouched_ButtonProcessing();
1073#endif
1074}
1075//! 3.28.22 .. implemented in ESP_IOT.ino
1077//!performs an async OTA update
1079{
1081}
1082//!sets the async OTA flag (for next loop)
1084{
1086}
1087
1088//!returns if the paired device is not NONE
1090{
1092}
1093
1094//!returns if the paired device is not NONE
1096{
1098
1099}
1100//!returns if the paired device is not NONE. Note, the paired Name might be an address now (see below)
1102{
1103 char *pairedDevice = getPairedDevice_mainModule();
1104 //new: now if non ""
1105 //return strcmp(pairedDevice,"NONE")!= 0;
1106 boolean isValid = pairedDevice && strlen(pairedDevice)>0 && strcmp(pairedDevice,"NONE")!= 0;
1107 if (!isValid)
1108 {
1109 char *pairedDeviceAddress = getPairedDeviceAddress_mainModule();
1110 isValid = pairedDeviceAddress && strlen(pairedDeviceAddress)>0 && strcmp(pairedDeviceAddress,"NONE")!= 0;
1111 SerialLots.printf("isValidDeviceAddress(%s,%d)\n", pairedDeviceAddress?pairedDeviceAddress:(char*)"NULL", isValid);
1112 }
1113 SerialLots.printf("isValidPairedDevice_mainModule(%s,%d)\n", pairedDevice?pairedDevice:(char*)"NULL", isValid);
1114 return isValid;
1115}
1116
1117//**** dang.. the getPreference reuses the same storage!! ****
1118
1119//!returns if the paired device is not NONE .. returns address or device
1121{
1122 char *pairedDevice = getPairedDevice_mainModule();
1123 if (pairedDevice && strlen(pairedDevice)>0 && strcmp(pairedDevice,"NONE")!= 0)
1124 {
1125 SerialLots.printf("getPairedDeviceOrAddress_mainModule(%s)\n", pairedDevice);
1126 return pairedDevice;
1127 }
1128 char *pairedDeviceAddress = getPairedDeviceAddress_mainModule();
1129 if (pairedDeviceAddress && strlen(pairedDeviceAddress)>0 && strcmp(pairedDeviceAddress,"NONE")!= 0)
1130 {
1131 SerialLots.printf("getPairedDeviceOrAddress_mainModule(%s)\n", pairedDeviceAddress);
1132 return pairedDeviceAddress;
1133 }
1134 else
1135 return (char*)"";
1136}
1137
1138//!gets the device name
1140{
1142 strcpy(_deviceNameSave,deviceName);
1143 return _deviceNameSave;
1144}
1145
1146//!power of devices
1147//!reboot
1149{
1150 //reboot
1151 ESP.restart();
1152}
1153
1154//!power off
1156{
1157#ifdef ESP_M5
1158 //SerialTemp.println(" **** THIS WOULD BE A POWEROFF ***");
1159 SerialTemp.println(" **** POWEROFF ***");
1160
1161#ifndef ESP_M5_CAMERA
1162#ifndef M5STICKCPLUS2
1163
1164#ifndef ESP_M5_ATOM_S3
1165 M5.Axp.PowerOff();
1166#endif
1167#endif
1168#endif
1169
1170#endif
1171}
1172// ******************* Preference Cleaning ************
1173
1174//!cleans the EPROM
1176{
1177 SerialDebug.println("CLEANING EPROM PREFERENCES");
1178
1179 //4.17.22
1181
1182 //! 8.16.25 MQTT
1184
1185 //! 8.16.25 WIFI AP
1187 //! 7.29.25 set the FIRST time ..
1189
1190 SerialDebug.println("REBOOTING...");
1191
1192 //!reboot
1194
1195}
1196
1197
1198//!retrieve a JSON string for the ssid and ssid_password: {'ssid':<ssid>,'ssidPassword':<pass>"}
1200{
1202}
1203
1204//!! cycle through the next WIFI saved credential
1206{
1207
1208 SerialTemp.printf("WIFI_CREDENTIAL_1: %s\n", getPreference_mainModule(PREFERENCE_WIFI_CREDENTIAL_1_SETTING));
1209 SerialTemp.printf("WIFI_CREDENTIAL_2: %s\n", getPreference_mainModule(PREFERENCE_WIFI_CREDENTIAL_2_SETTING));
1210
1211 //! WIFI_CREDENTIALS_MAX
1213 {
1214 char* credential = getPreference_mainModule(i);
1215 //!jump out of loop if no match.. so index is valid
1216 if (strcmp(credential,"NONE")==0)
1217 continue;
1218 if (strcmp(credential,_JSONStringForWIFICredentials)!= 0)
1219 {
1220 SerialTemp.print("main_nextJSONWIFICredential:");
1221 SerialTemp.println(credential);
1222 return credential;
1223
1224 }
1225 }
1226 SerialTemp.print("main_nextJSONWIFICredential:");
1227 SerialTemp.println(main_JSONStringForWIFICredentials());
1229}
1230
1231//!save the WIFI credential
1232void main_saveWIFICredentials(char *ssid, char *ssid_password)
1233{
1234 //!store the JSON version of these credentials..
1235 sprintf(_JSONStringForWIFICredentials, "{'ssid':'%s','ssidPassword':'%s'}", ssid?ssid:"NULL", ssid_password?ssid_password:"");
1236 SerialMin.print("main_saveWIFICredentials");
1237 SerialMin.println(_JSONStringForWIFICredentials);
1238
1239 //!look for an non matching slot.. if none, then use the first
1242 {
1243 char* credential = getPreference_mainModule(index);
1244 //!jump out of loop if no match.. so index is valid, or NONE (which is the placeholder)
1245 if (strcmp(credential,"NONE")==0)
1246 break;;
1247 if (strcmp(credential,_JSONStringForWIFICredentials)== 0)
1248 {
1249 break;
1250 }
1251 }
1252
1255
1256 SerialDebug.println(_JSONStringForWIFICredentials);
1257 //!save in chosen index
1259}
1260
1261//!clean the saved WIFI credential, otherwise the AP mode doesn't work (6.3.22)
1263{
1264 SerialMin.println("main_cleanSavedWIFICredentials");
1265
1266 //!go through the saved WIFI credentials and empty them with "" (vs null)
1269 {
1270 //!cannot null but can make stringlen=0
1271 savePreference_mainModule(index,"");
1272 }
1273}
1274
1275//! 12.14.23
1276char *_MQTT_Password = (char*)"";
1277char *_MQTT_Username = (char*)"";
1280
1281//! return the username and password
1282//! 12.14.23 to support calling the SMART buttons (smrun) with parameters
1284{
1285 return _MQTT_Username;
1286}
1287
1288//! return password
1290{
1291 return _MQTT_Password;
1292}
1293
1294//! return devicename
1296{
1297 SerialDebug.printf("main_getScannedDeviceName(%s)\n", _scannedDeviceName);
1298
1299 return _scannedDeviceName;
1300}
1301//! set the scanned device name
1302void main_setScannedDeviceName(char *deviceName)
1303{
1304 strcpy(_scannedDeviceName, deviceName);
1305 SerialDebug.printf("main_setScannedDeviceName(%s)\n", deviceName);
1306}
1307
1308//! set the scanned group name
1309//! 1.7.24
1310void main_setScannedGroupName(char *groupName)
1311{
1312 SerialDebug.printf("main_setScannedGroupName(%s)\n", groupName);
1313
1314 if (groupName && strlen(groupName)>0)
1315 {
1316 char *groupTopic = groupTopicFullName(groupName);
1318 }
1319 else
1320 strcpy(_scannedGroupTopicName, "");
1321}
1322//! return groupname -- returns "" or nil if not set,
1323//! or the FULL group name topic, or nil
1325{
1327 {
1328 SerialDebug.printf("main_getScannedGroupNameTopic(%s)\n", _scannedGroupTopicName);
1330
1331 }
1332 return NULL;
1333}
1334
1335//! sets the WIFI and MQTT user/password. It's up to the code (below, maybe in future a register approach) to decide who needs to know
1336void main_updateMQTTInfo(char *ssid, char *ssid_password, char *username, char *password, char *guestPassword, char *deviceName, char * host, char * port, char *locationString)
1337{
1338 SerialMin.printf("main_updateMQTTInfo(%s,%s,%s,%s,%s, %s, d=%s)\n", ssid?ssid:"NULL", ssid_password?ssid_password:"", username?username:"NULL", password?password:"NULL", guestPassword?guestPassword:"NULL", locationString?locationString:"NULL", deviceName?deviceName:"NULL");
1339
1340 _MQTT_Password = password;
1341 _MQTT_Username = username;
1342
1343 //!store the device name
1345
1346 //!store the JSON version of these credentials..
1347 main_saveWIFICredentials(ssid,ssid_password);
1348
1349 //! 8.16.25 WIFI AP
1350 WIFI_APModule_updateMQTTInfo(ssid, ssid_password, username, password, guestPassword, deviceName, host, port, locationString);
1351}
1352
1353//! 5.16.25 Fountainhead, Raining cold weekend
1354//! start SYNC calls starting with the SYNC_CLICK_SOUND
1355//#define SYNC_CLICK_SOUND 0
1356//#define SYNC_CALL_MAX 1
1357//! the main sync command (no parameters yet)
1358void main_dispatchSyncCommand(int syncCallCommand)
1359{
1360 switch (syncCallCommand)
1361 {
1362 case SYNC_CLICK_SOUND:
1363 {
1365 {
1366 //! 5.15.25 see if the Buzzer class is defined .. if so, then call local message
1367 SensorStruct* buzzerSensor = getSensor_mainModule((char*)"BuzzerSensorClass");
1368
1369 //!perform the click sound..
1370 //!this will be the sensors...
1371 if (buzzerSensor)
1372 {
1373 buzzerSensor->sensorClassType->messageLocal_SensorClassType((char*)"click");
1374 }
1375 else
1376 SerialDebug.println("NO BuzzerSensorClass defined");
1377 }
1378 }
1379 break;
1380 }
1381}
1382
1383//! 3.21.22 these are to setup for the next time the main loop() runs to call these commands..
1384//! The implementation is hard coded in the ESP_IO.ino
1385//! TODO: make this a registeration approach
1386//#define ASYNC_CALL_OTA_UPDATE 0
1387//#define ASYNC_CALL_CLEAN_CREDENTIALS 1
1388//#define ASYNC_CALL_MAX 2
1389
1390//!storage for asyncCallCommands
1392//!array of async flags for the different ASYNC_CALl values
1394
1395//!initialize the async call flags (with and without parameters)
1397{
1398 for (int i = 0; i < ASYNC_CALL_MAX; i++)
1399 {
1400 _asyncCallFlags[i] = false;
1401 }
1402 for (int i = 0; i < ASYNC_CALL_PARAMETERS_MAX; i++)
1403 {
1404 _asyncCallFlagsParameters[i] = false;
1405 }
1406}
1407
1408// ******************* Async Dispatch Processing ************
1409
1410//!checks if any async commands are in 'dispatch' mode, and if so, invokes them, and sets their flag to false
1411
1412//! dispatches a call to the command specified. This is run on the next loop()
1413void main_dispatchAsyncCommand(int asyncCallCommand)
1414{
1415 //! this just sets the flag, it's the next loop that makes the call
1416#ifdef ERROR_CHECKS
1417 if (asyncCallCommand < 0 || asyncCallCommand >= ASYNC_CALL_MAX)
1418 {
1419 SerialError.printf("ERROR: async call out of range: %d\n", asyncCallCommand);
1420 }
1421 else
1422#endif
1423 {
1424 SerialTemp.printf("1.main_dispatchAsyncCommand: %d\n", asyncCallCommand);
1425 _asyncCallFlags[asyncCallCommand] = true;
1426 }
1427}
1428
1429//!send an async call with a string parameter. This will set store the value and then async call the command (passing the parameter)
1430//!These are the ASYNC_CALL_PARAMETERS_MAX
1431void main_dispatchAsyncCommandWithString(int asyncCallCommand, char *parameter)
1432{
1433 //!store in the parameter mailbox
1434 strcpy(_asyncParameter,parameter);
1435 //! this just sets the flag, it's the next loop that makes the call
1436#ifdef ERROR_CHECKS
1437 if (asyncCallCommand < 0 || asyncCallCommand >= ASYNC_CALL_PARAMETERS_MAX)
1438 {
1439 SerialError.printf("ERROR: async call out of range: %d\n", asyncCallCommand);
1440 }
1441 else
1442#endif
1443 {
1444 SerialTemp.print("2.main_dispatchAsyncCommandWithString:");
1445 SerialTemp.print(asyncCallCommand);
1446 SerialTemp.print(": ");
1447 SerialTemp.println(_asyncParameter);
1448 _asyncCallFlagsParameters[asyncCallCommand] = true;
1449
1450 //! 6.15.25 Fathers Day
1451 //! seems issue when a GROVE or other sensor plugged in the main loop isn't working.
1452 //! SO for now, if the command is "r" then do an actual reboot..
1453 if (strlen(_asyncParameter)>1 && _asyncParameter[0] == 'r')
1454 {
1455 SerialDebug.println("SYNC_REBOOT");
1457 }
1458 }
1459}
1460
1461//!checks if any async commands are in 'dispatch' mode, and if so, invokes them, and sets their flag to false
1463{
1464 SerialCall.printf("invokeAsyncCommands(%d)\n", ASYNC_CALL_PARAMETERS_MAX);
1465
1466 for (int i = 0; i < ASYNC_CALL_PARAMETERS_MAX; i++)
1467 {
1468 boolean asyncCallFlag = _asyncCallFlagsParameters[i];
1469 if (asyncCallFlag)
1470 {
1471 SerialCall.printf("invokeAsyncCommands(%d)\n", i);
1472 _asyncCallFlagsParameters[i] = false;
1473 switch (i)
1474 {
1476 SerialTemp.print("ASYNC_CALL_BLE_CLIENT_PARAMETER: ");
1477 SerialTemp.println(_asyncParameter);
1478 //! 8.16.25 BLE CLIENT
1479 if (strlen(_asyncParameter)<=13)
1481 else
1483
1484 break;
1486 SerialTemp.print("ASYNC_CALL_OTA_FILE_UPDATE_PARAMETER: ");
1487 SerialTemp.println(_asyncParameter);
1488 //! 8.16.25 MQTT
1489 {
1490 //look for the host: http://<name>/
1491 // httpAddress is everything after the /
1492 //hostname is without http://
1493 char hostname[100];
1494 char httpAddress[100];
1495 int thirdSlash = 0;
1496 for (int i=0; i< strlen(_asyncParameter);i++)
1497 {
1498 if (_asyncParameter[i] == '/')
1499 {
1500 thirdSlash++;
1501 }
1502 if (thirdSlash == 3)
1503 {
1504 // i == point to 3rd slash
1505 strncpy(hostname,_asyncParameter,i);
1506 //add null
1507 hostname[i] = (char)0;
1508 char *a = &_asyncParameter[i+1];
1509 strcpy(httpAddress,a);
1510 break;
1511 }
1512 }
1513 //todo..
1514 SerialTemp.print("will performOTAUpdate: ");
1515 SerialTemp.print(hostname);
1516 SerialTemp.print(" with httpAddress: ");
1517 SerialTemp.println(httpAddress);
1518 performOTAUpdate(hostname, httpAddress);
1519 }
1520 break;
1522 {
1523 //process the message
1524 SerialDebug.print("ASYNC_JSON_MESSAGE_PARAMETER: ");
1525 SerialDebug.println(_asyncParameter);
1526
1527 //! The FINISH of callback for "onWrite" of the bluetooth "onWrite'
1529 }
1530 break;
1531
1532 //! 1.10.24 add ability to send a MQTT Semantic Marker message
1534 {
1535 //process the message
1536 SerialDebug.print("ASYNC_JSON_MQTT_MESSAGE_PARAMETER: ");
1537 SerialDebug.println(_asyncParameter);
1538
1539 //! This sends a MQTT message. Currently GROUP not supported
1540 //! TODO: add GROUP
1541 char *groupTopic = NULL;
1542 if (groupTopic)
1544 else
1546 }
1547 break;
1548
1549 //! 3.9.24 REST call
1551 {
1552 //process the message
1553 SerialDebug.print("ASYNC_REST_CALL_MESSAGE_PARAMETER: ");
1554 SerialDebug.println(_asyncParameter);
1555#ifdef USE_REST_MESSAGING
1556 sendSecureRESTCall(_asyncParameter);
1557#endif
1558 }
1559 break;
1560 }
1561
1562 }
1563 }
1564
1565 //!now process those that don't have a string parameter
1566 for (int i = 0; i < ASYNC_CALL_MAX; i++)
1567 {
1568 boolean asyncCallFlag = _asyncCallFlags[i];
1569 if (asyncCallFlag)
1570 {
1571 _asyncCallFlags[i] = false;
1572 switch (i)
1573 {
1575 SerialLots.println("ASYNC_CALL_OTA_UPDATE");
1576 //! 8.16.25 MQTT
1578 break;
1580 SerialTemp.println("ASYNC_CALL_CLEAN_CREDENTIALS");
1581 //! 8.16.25 WIFI AP
1583 //this reboots ..
1584 break;
1586 SerialTemp.println("ASYNC_CALL_CLEAN_EPROM");
1588 break;
1590 SerialLots.println("ASYNC_CALL_FEED_COMMAND");
1592 //! 8.16.25 MQTT
1593 //!register the 2 callbacks for now..
1595 break;
1596 //!this is a sending of the message
1598 SerialTemp.println("ASYNC_SEND_MQTT_FEED_MESSAGE");
1599 //incrementFeedCount_mainModule();
1600 SerialCall.println("async_send_feed.1");
1601
1602 //! 8.16.25 MQTT
1603 //! 8.16.25 BLE CLIENT
1604 //!9.30.22 IF SET .. send a feed but to all devices except ours and our pair (if any)
1605 //! uses new wildcard syntax either ! OUR NAME [ & ! OUR_CONNECTED_NAME
1607 {
1608 char pubString[100];
1610 boolean isPaired = paired && strlen(paired)>0;
1611 // cannot save it.. so refresh below.. (Preferences are reused)
1612 SerialTemp.printf("Paired = %s\n", paired?paired:(char*)"none");
1613 SerialTemp.printf("Connected = %s\n", connectedBLEDeviceName_mainModule()?connectedBLEDeviceName_mainModule():(char*)"none");
1614
1616 sprintf(pubString,"{'dev':'!%s & !%s'",deviceName_mainModule(),connectedBLEDeviceName_mainModule());
1617 else if (isPaired)
1618 sprintf(pubString,"{'dev':'!%s & !%s'",deviceName_mainModule(),getPreference_mainModule(PREFERENCE_PAIRED_DEVICE_SETTING));
1619 else
1620 sprintf(pubString,"{'dev':'!%s'",deviceName_mainModule());
1621 strcat(pubString,",'cmd':'feed'}");
1623 //! if not paired, then feed everyone except out device...
1624 }
1625 //! if not BLE connected .. send wifi fee to all below...
1626 //SerialTemp.println("async_send_feed.3");
1627 //TODO: 7.26.22 .. decide if this logic makes sense:
1628 //NO BLECLient, and a message arrives for this device to #FEED. So previously it would sned that onto the network .. but I don't think that's right. (And we weren't in that mode yet).
1629 //sendMessageMQTT((char *)"#FEED");
1630 //! 8.16.25 BLE CLIENT
1631 //! returns whether connected over BLE as a client to a server(like a ESP feeder)
1632 if (!isConnectedBLEClient())
1633 {
1634 //! If not connected over BLE -- then send the MQTT feed message.. ??? WHY??
1635 //! 8.16.25 MQTT
1636
1637 //!only if not WIFI with BLE
1638 //! 8.20.24 put back to MQTT feed to all .. for now..
1639 //! SerialCall.println("async_send_feed.1");
1640 sendMessageMQTT((char *)"#FEED");
1641 SerialTemp.println(" *** NO BLE connected so send wifi ASYNC_SEND_MQTT_FEED_MESSAGE");
1642
1643 }
1644 else
1645 {
1646 SerialCall.println("async_send_feed.2");
1648
1649 //!send a BLE feed command as we are connected
1651
1652 //!perform ACK too
1653 //! 8.16.25 MQTT
1654 //ack is sent by the caller of this message..??
1655 //! 11.26.25 send Status instead
1656 //sendMessageMQTT((char *)"#ackMe");
1657 sendMessageMQTT((char*)"#STATUS");
1658 }
1659#ifdef NOT_NOW
1660 //! 8.24.22 (This will redraw the screen - and turn off the blank screen (but not let anyone know)
1661 //! SO: now only the buttons will unlock the blank screen..
1662
1663 //!redraws the Semantic Marker image..
1665#endif //not_now
1666 break;
1667
1668 //!this is a sending of the message
1669 //!5.15.25 Sodbuster Rod plowing/disking in minutes with Mark and Bud
1670 case ASYNC_CLICK_SOUND:
1671 {
1672 SerialTemp.println("ASYNC_CLICK_SOUND");
1674 }
1675 break;
1676
1677 case ASYNC_CALL_BUZZ_ON:
1679 {
1680 boolean isBuzzOn = (i == ASYNC_CALL_BUZZ_ON);
1681 //! set the persistence (Note, this is locally saved. If sending elsewhere .. then they have to set their value)
1683
1684 SerialDebug.printf("ASYNC_CALL_BUZZ %d\n",isBuzzOn);
1685 String cmdToSend;
1686 if (isBuzzOn)
1687 {
1688 cmdToSend = "{'cmd':'buzzon'}";
1689 //! click call synchronously ...
1691 }
1692 else
1693 cmdToSend = "{'cmd':'buzzoff'}";
1694
1695 //!OK: issue.
1696 //! if we are an ESP feeder, the STEPPER is on .. so we're good,
1697 //! if an M5 - then either send over BLE or MQTT
1698#ifdef ESP_M5
1699 //!send via BLE or MQTT ..
1700 //! 8.16.25 BLE CLIENT
1701 //! returns whether connected over BLE as a client to a server(like a ESP feeder)
1702 if (!isConnectedBLEClient())
1703 {
1704 SerialLots.println("async_call_buzz_on/off -- not BLE connected.. send MQTT");
1705 //! If not connected over BLE -- then send the MQTT buzzon message..
1706 //! 8.16.25 MQTT
1707 sendMessageMQTT((char*)cmdToSend.c_str());
1708 }
1709 else
1710 {
1711 //!send over BLE...
1712 sendCommandBLEClient(cmdToSend);
1713 }
1714#else //not M5
1715
1716 //! 8.16.25 BLE CLIENT
1717 //! returns whether connected over BLE as a client to a server(like a ESP feeder)
1718 if (!isConnectedBLEClient())
1719 {
1720 SerialLots.println("async_call_buzz_on -- not BLE connected.. send MQTT");
1721 //! If not connected over BLE -- then send the MQTT buzzon message..
1722 //! 8.16.25 MQTT
1723 sendMessageMQTT((char *)cmdToSend.c_str());
1724 }
1725 else
1726 {
1727 SerialLots.println("async_call_buzz_on -- YES BLE connected.. send BLE");
1728 processClientCommandChar_mainModule(isBuzzOn?'B':'b');
1729
1730 }
1731
1732#endif // ESP_M5
1733 }
1734 break;
1735
1736 //!setGatewayOn/Off called from the processJSON message in MQTT
1737 //! or via the EPROM setting (TODO)
1739 SerialLots.println("ASYNC_SET_GATEWAY_ON");
1741
1742 break;
1743
1745 SerialLots.println("ASYNC_SET_GATEWAY_OFF");
1747
1748 break;
1749
1750 case ASYNC_REBOOT:
1751 SerialDebug.println("ASYNC_REBOOT");
1753
1754 break;
1755
1756 case ASYNC_POWEROFF:
1757 SerialDebug.println("ASYNC_POWEROFF");
1759
1760 break;
1761 case ASYNC_BLANKSCREEN:
1762 SerialDebug.println("ASYNC_BLANKSCREEN");
1764 break;
1766 //!sends the status from the main module URL
1767 //! 8.16.25 MQTT
1768 {
1769#ifdef ESP_M5_CAMERA
1770 char *statusURL = main_currentStatusURL(false);
1771#else
1772 char *statusURL = main_currentStatusURL(true);
1773#endif
1774 SerialDebug.print(" ASYNC_SEND_MQTT_STATUS_URL: ");
1775 SerialDebug.println(statusURL);
1776 /// NO MORE: sendDocFollowMessageMQTT(statusURL);
1777 sendStatusMessageMQTT(statusURL);
1778 }
1779#ifdef M5BUTTON_MODULE
1780 //! 1.23.24 call the status which re-evaluates the sensor ALIVE
1781 //! this status will be called and let the ALIVE re-evaluate
1782 //! Only do this on the STATUS since it might be slow for the LUX
1783 statusM5ButtonModule();
1784#endif
1785 break;
1786
1787 case ASYNC_SWAP_WIFI:
1788 case ASYNC_NEXT_WIFI:
1789 {
1790 //NOTE: this might be where we toggle credentials?? TODO
1791 //found other one..
1792 char *credentials = main_nextJSONWIFICredential();
1793 //! 8.16.25 MQTT
1794
1795 //!These are the ASYNC_CALL_PARAMETERS_MAX
1796 //!NO: just change our credentials ...
1797 //send to
1798 //main_dispatchAsyncCommandWithString(ASYNC_CALL_BLE_CLIENT_PARAMETER, credentials);
1800 }
1801 break;
1803 //! 8.16.25 MQTT
1804 //!Restarts (or attempts) a restart of the WIFI using the existing credentials -- vs the 'n' command
1806 break;
1807 default:
1808 SerialLots.printf("NO COMMAND: %s", i);
1809 }
1810 }
1811 }
1812}
1813//! 2.21.25 add a way to change the button color (if any)
1815{
1816#ifdef M5BUTTON_MODULE
1817 SerialDebug.println("changeButtonColor_MainModule");
1818 // changeButtonColor_M5ButtonModule()
1819#endif
1820}
1821
1822//!3.17.24 the unqiue chip id
1824//! string like: 10311304
1826
1827//! 3.17.24 get the chip id
1828uint32_t getChipId()
1829{
1830 if (_chipID_MainModule == 0)
1831 {
1832 //get chip ID
1833 for (int i = 0; i < 17; i = i + 8) {
1834 _chipID_MainModule |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i;
1835 }
1837 }
1838 return _chipID_MainModule;
1839
1840}
1841
1842//! 3.17.24 get the chip id as a string
1844{
1845 getChipId();
1847}
1848
1849//! 1.12.24 add a temporary LUX dark
1850//! threshholdKind = 0 (LIGHT), 1=(DARK) .. others might be 2=super dark
1851//#define THRESHOLD_KIND_LIGHT 0
1852//#define THRESHOLD_KIND_DARK 1
1855//! set the threshold val
1856void setLUXThreshold_mainModule(int thresholdKind, int luxVal)
1857{
1858 switch (thresholdKind)
1859 {
1861 _thresholdLUXLight = luxVal;
1862 break;
1864 _thresholdLUXDark = luxVal;
1865 break;
1866 }
1867}
1868//! get the threshold val
1869int getLUXThreshold_mainModule(int thresholdKind)
1870{
1871 switch (thresholdKind)
1872 {
1874 return _thresholdLUXLight;
1875 break;
1877 return _thresholdLUXDark;
1878 break;
1879 }
1880 return 80;
1881}
1882
1883//!storage for the group topic name
1884//!Note NO "/" in the front of the path only "usersP"
1886#define GROUP_TOPIC_TO_SEND (char*)"usersP/groups"
1887//!returns a groupTopic to use as a topic
1888char *groupTopicFullName(char *groupName)
1889{
1890 sprintf(_groupTopicName, "%s/%s",GROUP_TOPIC_TO_SEND, groupName);
1891 return _groupTopicName;
1892}
1893
1894//define a couple lights .. maybe move somewhere else..
1895char* _ON_LIGHT = (char*)"ON";
1896char* _OFF_LIGHT = (char*)"OFF";
1897
1898//!callback for blinking led
1899void blinkMessageCallback(char *message)
1900{
1901 //! 12.19.25 Power back on, Snowing in mountains
1902 //! support the blink but using the plugin class
1903 //! 5.15.25 try the async CLICK
1904 //! click call 5.26.25 SYNC version
1906
1907#ifdef ESP_M5
1908
1909 //call the already defined blink led
1910 // devined in Dispense.cpp
1911// digitalWrite(LED, HIGH);
1912// delay(150);
1913// digitalWrite(LED, LOW);
1914
1915#else //not M5
1916 //call the already defined blink led
1917 // defined in Dispense.cpp
1918 // stepperModule_BlinkLED();
1920#endif //ESP_M5
1921}
1922
1923//!callback for SOLID blinking led
1924void solidLightMessageCallback(char *message)
1925{
1926 SerialLots.println("solidLightMessageCallback..");
1927#ifdef ESP_M5
1928#else
1929 //!call the already defined solid led
1930 //! defined in Dispense.cpp
1931 boolean lightOn = true;
1932 lightOn = strstr(&message[0], _ON_LIGHT);
1933 solidLightOnOff_UIModule(lightOn);
1934#endif
1935}
1936
1937//!clean the SSID eprom (MQTT_CLEAN_SSID_EPROM)
1939{
1940 //!call the already defined solid led
1941 //! defined in Dispense.cpp
1942 //! 8.16.25 WIFI AP
1943 //!clean_SSID_WIFICredentials();
1944 //!now register an async call..
1946
1947}
1948
1949//!called on single click
1950//!NOTE: with BLE_CLIENT_NETWORKING, the right button and top button send a BLE command for feeding..
1951void singleClickTouched(char *whichButton)
1952{
1953 //! 8.16.25 WIFI AP
1954 //!for now, only send the FEED command via BLE_CLIENT if turned on. No reboot to AP mode yet..
1955 //! 8.16.25 BLE CLIENT
1956 //!send the async FEED
1957
1958 //! dispatches a call to the command specified. This is run on the next loop()
1960}
1961
1962//! shows a FEED (or whatever) then blanks the screen after N seconds
1963//! NOTE: This will be a scrolling text as sometime ..
1964void showText_mainModule(String text)
1965{
1966 //showText_displayModule(text);
1968
1969}
1970
1971//!callback for SOLID blinking led
1972void solidLightOnOff(boolean onOff)
1973{
1974#ifdef ESP_M5
1975#else
1976 SerialLots.println("solidLight..");
1977 //!call the already defined solid led
1978 //! defined in Dispense.cpp
1979 boolean lightOn = onOff;
1980 solidLightOnOff_UIModule(lightOn);
1981#endif
1982}
1983
1984//!prints the module configuration by looking at #defines
1985//! Eventually this might be an object returned letting the code
1986//!know a capability is included for runtime (vs compile time) decisions
1988{
1989 //!Module Configuration
1990 SerialDebug.println(" ** #define Module Configuration **");
1991 SerialDebug.println(PARTITION_SCHEME);
1992 SerialDebug.printf("M5Stack Version = %s\n", (char*)M5STACK_VERSION);
1993
1994 SerialDebug.println(" ** BUILDS **");
1995
1996#ifdef ESP_M5
1997 //![x] ESP_M5
1998 SerialMin.println("[x] ESP_M5");
1999#else
2000 SerialMin.println("[ ] ESP_M5");
2001#endif
2002#ifdef ESP_M5_CAMERA
2003 //![x] ESP_M5
2004 SerialMin.println("[x] ESP_M5_CAMERA");
2005#else
2006 SerialMin.println("[ ] ESP_M5_CAMERA");
2007#endif
2008#ifdef ESP_32
2009 //! [x] ESP_32
2010 SerialMin.println("[x] ESP_32");
2011#else
2012 SerialMin.println("[ ] ESP_32");
2013#endif
2014#ifdef M5CORE2_MODULE
2015 //![x] M5CORE2_MODULE
2016 SerialMin.println(F("[x] M5CORE2_MODULE"));
2017#else
2018 SerialMin.println(F("[ ] M5CORE2_MODULE"));
2019#endif
2020 //Set this if the SMART clicker build is used.
2021#ifdef ESP_M5_SMART_CLICKER_CONFIGURATION
2022 SerialMin.println(F("[x] ESP_M5_SMART_CLICKER_CONFIGURATION"));
2023#else
2024 SerialMin.println(F("[ ] ESP_M5_SMART_CLICKER_CONFIGURATION"));
2025#endif
2026#ifdef ESP_M5_ATOM_LITE
2027 SerialMin.println(F("[x] ESP_M5_ATOM_LITE"));
2028#else
2029 SerialMin.println(F("[ ] ESP_M5_ATOM_LITE"));
2030#endif
2031
2032 SerialDebug.println(F(" ** MQTT BLE NETWORKING **"));
2033
2034 //! 8.16.25 MQTT
2035 //! [x] USE_MQTT_NETWORKING
2036 SerialMin.println("[x] USE_MQTT_NETWORKING");
2037
2038 //! 8.16.25 BLE SERVER
2039 //! [x] USE_BLE_SERVER_NETWORKING
2040 SerialMin.println("[x] USE_BLE_SERVER_NETWORKING");
2041
2042 //! 8.16.25 BLE CLIENT
2043 //! [x] USE_BLE_CLIENT_NETWORKING
2044 SerialMin.println(F("[x] USE_BLE_CLIENT_NETWORKING"));
2045
2046 //! 8.16.25 WIFI AP
2047 //! [x] USE_WIFI_AP_MODULE
2048
2049 SerialMin.println(F("[x] USE_WIFI_AP_MODULE"));
2050
2051
2052#ifdef USE_BUTTON_MODULE
2053 // [x] USE_BUTTON_MODULE
2054 SerialMin.println("[x] USE_BUTTON_MODULE");
2055#else
2056 SerialMin.println("[ ] USE_BUTTON_MODULE");
2057#endif
2058
2059#ifdef M5BUTTON_MODULE
2060 // [x] M5BUTTON_MODULE
2061 SerialMin.println("[x] M5BUTTON_MODULE");
2062#else
2063 SerialMin.println("[ ] M5BUTTON_MODULE");
2064
2065#endif
2066
2067#ifdef USE_STEPPER_MODULE
2068 SerialMin.println("[x] USE_STEPPER_MODULE");
2069#else
2070 SerialMin.println("[ ] USE_STEPPER_MODULE");
2071
2072#endif
2073#ifdef USE_UI_MODULE
2074 SerialMin.println("[x] USE_UI_MODULE");
2075#else
2076 SerialMin.println("[ ] USE_UI_MODULE");
2077
2078#endif
2079#ifdef USE_DISPLAY_MODULE
2080 SerialMin.println("[x] USE_DISPLAY_MODULE");
2081#else
2082 SerialMin.println("[ ] USE_DISPLAY_MODULE");
2083
2084#endif
2085#ifdef BOARD
2086 SerialMin.println(F("[x] BOARD"));
2087#else
2088 SerialMin.println(F("[ ] BOARD"));
2089#endif
2090#ifdef USE_SPIFF_MODULE
2091 SerialMin.printf("[%d] USE_SPIFF_MODULE/_SETTING\n", getPreferenceBoolean_mainModule(PREFERENCE_USE_SPIFF_SETTING));
2092#else
2093 SerialMin.println("[ ] USE_SPIFF_MODULE");
2094#endif
2095#ifdef USE_SPIFF_MQTT_SETTING
2096 SerialMin.printf("[%d] USE_SPIFF_MQTT_SETTING\n",getPreferenceBoolean_mainModule(PREFERENCE_USE_SPIFF_MQTT_SETTING));
2097#endif
2098#ifdef USE_SPIFF_QRATOM_SETTING
2099 SerialMin.printf("[%d] USE_SPIFF_QRATOM_SETTING\n", getPreferenceBoolean_mainModule(PREFERENCE_USE_SPIFF_QRATOM_SETTING));
2100#endif
2101
2102#ifdef USE_FAST_LED
2103 SerialMin.println(F("[x] USE_FAST_LED"));
2104#else
2105 SerialMin.println(F("[ ] USE_FAST_LED"));
2106#endif
2107#ifdef KEY_UNIT_SENSOR_CLASS
2108 SerialMin.println(F("[x] KEY_UNIT_SENSOR_CLASS"));
2109#else
2110 SerialMin.println(F("[ ] KEY_UNIT_SENSOR_CLASS"));
2111#endif
2112#ifdef USE_LED_BREATH
2113 SerialMin.println(F("[x] USE_LED_BREATH"));
2114#else
2115 SerialMin.println(F("[ ] USE_LED_BREATH"));
2116#endif
2117
2118#if (SERIAL_DEBUG_ERROR)
2119 SerialMin.println(F("[x] SERIAL_DEBUG_ERROR"));
2120#endif
2121#if (SERIAL_DEBUG_DEBUG)
2122 SerialMin.println(F("[x] SERIAL_DEBUG_DEBUG"));
2123#endif
2124#if (SERIAL_DEBUG_INFO)
2125 SerialMin.println(F("[x] SERIAL_DEBUG_INFO"));
2126#endif
2127#if (SERIAL_DEBUG_MINIMAL)
2128 SerialMin.println(F("[x] SERIAL_DEBUG_MINIMAL"));
2129#endif
2130
2131 //!and print any preferences to show
2133}
2134
2135//!If nil it create one with just the null, so strlen = 0
2136//!NOTE: the strdup() might be used later..
2137char* createCopy(char * stringA)
2138{
2139 if (stringA)
2140 return strdup(stringA);
2141 else
2142 return strdup("");
2143}
2144
2145//!If nil it create one with just the null, so strlen = 0
2146//!NOTE: the strdup() might be used later..
2147char* createCopy2(const char * stringA)
2148{
2149 if (stringA)
2150 return strdup(stringA);
2151 else
2152 return strdup("");
2153}
2154
2155//!informs if null or empty string
2156boolean isEmptyString(char *stringA)
2157{
2158 if (!stringA)
2159 {
2160 return true;
2161 }
2162 else if (strlen(stringA) == 0)
2163 {
2164 return true;
2165 }
2166 else
2167 return false;
2168}
2169
2170//!a char* version of startsWith (after skipping spaces)
2171boolean startsWithChar(char *str, char c)
2172{
2173 if (!str) return false;
2174 //!find first non space character, and if not '{' then return false
2175 int i = 0;
2176 while (i < strlen(str))
2177 {
2178 //!jump out if not a space, and 'i' will be the thing to look for
2179 if (str[i] != ' ')
2180 break;
2181 i++;
2182 }
2183
2184 if (str[i] == c)
2185 return true;
2186
2187 return false;
2188}
2189
2190//!start of the sensor updates ... TODO: tie these to the MQTT messaging as well..
2192{
2193 float batVoltage = 1;
2194 float batPercentage = 100; //plugged in
2195#ifdef ESP_M5
2196#ifndef M5STICKCPLUS2
2197
2198#ifdef M5_ATOM
2199 //! the M5.Axp.GetBatVoltage() is VERY slow on the M5 (as there isn't one..)
2200#elif defined(M5CORE2_MODULE)
2201 //!see https://forum.arduino.cc/t/elseif-not-working/565646/12
2202 batVoltage = M5.Axp.GetBatVoltage();
2203 batPercentage = (batVoltage < 3.2) ? 0 : ( batVoltage - 3.2 ) * 100;
2204#else
2205 batVoltage = M5.Axp.GetBatVoltage();
2206 batPercentage = (batVoltage < 3.2) ? 0 : ( batVoltage - 3.2 ) * 100;
2207 //!#Issue 117
2208 //!from: https://community.m5stack.com/topic/1361/ischarging-and-getbatterylevel/9
2209 //!GetVbatdata() is currently depreciated
2210 uint16_t vbatData = M5.Axp.GetVbatData();
2211 double vbat = vbatData * 1.1 / 1000;
2212 batPercentage = 100.0 * ((vbat - 3.0) / (4.07 - 3.0));
2213#endif
2214#endif // M5STICKCPLUS2
2215#endif
2216
2217 if (batPercentage > 100.0)
2218 batPercentage = 100.0;
2219 return batPercentage;
2220}
2221
2222//!adding a synchronous call to send a message over the network (assuming MQTT but not specified), this tacks on {device} and {t:time}
2223void sendMessageString_mainModule(char *messageString)
2224{
2226}
2227
2228
2229//!adding a synchronous call to send a message over the network (assuming MQTT but not specified), this tacks on {device} and {t:time}
2230void sendMessageStringTopic_mainModule(char *messageString, char*topicString)
2231{
2232 //! 8.16.25 MQTT
2233 SerialDebug.printf("sendMessageStringTopic_mainModule(%s) - topic=%s\n", messageString, topicString);
2234 if (strlen(messageString) > 0 && messageString[0] == '{')
2235 {
2236 // JSON Message
2237 //! 12.19.23 Amber in air from Iceland. 50 years since Dead 12.19.73
2238 sendMessageNoChangeMQTT_Topic(messageString, topicString);
2239 }
2240 else if (strlen(messageString) < MESSAGE_STORAGE_MAX)
2241 {
2242 //!NOTE: the # has to be there, otherwise the sendMessageMQTT ignores it..
2243 sprintf(_messageStorage,"#%s {%s} {t:%d}", messageString, getDeviceNameMQTT(), getTimeStamp_mainModule());
2244 //!send this message over MQTT
2246 }
2247}
2248
2249//!retrieves the temperature .
2251{
2252#ifdef ESP_M5
2253 //!return celcius
2254 //!float temperature = M5.Axp.GetTempInAXP192();
2255 float temperature;
2256#ifdef M5_ATOM
2257#else
2258#ifndef M5STICKCPLUS2
2259 M5.IMU.getTempData(&temperature);
2260#endif
2261#endif
2262
2263#ifdef USER_THE_MAX_TEMP_FEATURE
2265 if (temperature > maxtemp)
2266 {
2267 //! turn off the device after sending a message..
2268 //! let others know we are powering off..
2269 //! then poweroff
2270 //! 8.16.25 MQTT
2271 sprintf(_messageStorage,"#Temp %f too high > %d - powering off {%s}", temperature, maxtemp, getDeviceNameMQTT());
2272 //!send this message over MQTT
2274 //! now poweroff
2275 SerialTemp.println(" *** This would poweroff .. but you can send message");
2276 //!poweroff_mainModule();
2277
2278 }
2279#endif
2280
2281#else
2282 float temperature = 10.0;
2283#endif
2284 return temperature ;//* 9/5 + 32;
2285}
2286//!NEW: 4.30.22
2287//!returns a string in JSON format, such that {'battery':'84'}, {'buzzon':'off'} .. etc
2288//!as a URL: SemanticMarker.org/bot/sample/scott@name/password/status?BLE:on&numfeeds=8&WIFI:on&AP:off
2289/** Sample format:
2290{"status": [
2291 {
2292 "BLE": "on"
2293 },
2294 {
2295 "numfeeds": "8",
2296 "maxfeeds": "16"
2297 },
2298 {
2299 "battery": "87"
2300 },
2301 {
2302 "buzzon": "on"
2303 },
2304 {
2305 "MQTT": "on"
2306 },
2307 {
2308 "WIFI": "on"
2309 },
2310 {
2311 "AP": "off"
2312 },
2313 {
2314 "tilt": "55"
2315 }
2316]
2317}
2318*/
2319//!status in JSON format, needs to return something as a ',' is already added before calling this..
2321{
2322 //returns a JSON string..
2323// String b = String(getBatPercentage(),0);
2324// return "{'status':[{'BLE':'on'},{'bat':'" + b + "'}]}";
2325 // return (char*)"";
2326
2327 //! 1.4.24 work on ATOM kinds without IFDEF (except to bring in the code)
2328#pragma mark USE_NEW_M5ATOMCLASS
2329
2330 //! 5.6.25 use object version
2333
2334#ifdef M5CORE2_MODULE
2335 //!returns a string in in JSON so: status&battery=84'&buzzon='off' } .. etc
2336 //!starts with "&"*
2338#endif
2339
2340 return (char*)"'tbd':'x'";
2341}
2342
2343//! TODO: fix syntax. If just sensor sensor status: ....
2344//!https://SemanticMarker.org/bot/sensor/scott@konacurrents.com/doggy/status?v=v2&dev=M5Ski&b=68&temp=66&c=0&t=8&W=on&M=on&B=on&C=on&A=off&T=on&S=on&Z=off&t=8
2345//!not working just added Z=on/off length = 157
2346//! going to remove the username/password to shorten..
2347
2348//!adds a query string "&key=value"
2349void addStatusStringFlag(const char *key, char * val)
2350{
2351 char buf[50];
2352 sprintf(buf,"&%s=%s", key, val);
2353 strcat(_fullStatusString, buf);
2354}
2355//!adds to _fullStatusString a query string "&key=value"
2356void addStatusBooleanFlag(const char *key, boolean flag)
2357{
2358 addStatusStringFlag(key, flag?(char*)"on":(char*)"off");
2359
2360}
2361//!sets the "Module Status"
2362//!in queryString == name=val&name=val ...
2364{
2365 //!value of WIFI connected
2366 //! 8.16.25 MQTT
2369 //! 8.16.25 BLE CLIENT
2370 //useBLECLient == it's linked in and running (vs not running)
2372 //! connected == we are connected to another BLEServer
2374
2375 //! 8.16.25 WIFI AP
2376 //!not done is what we look for ..
2378
2379#pragma mark reused
2380#ifdef OVERLOADS_TIME_T
2381 //! 7.20.25 this breaks the T:<time> since there is a dublicate in the URL .. with no error
2383#endif
2384
2385 //! 8.16.25 BLE SERVER
2387 {
2388 //! add a bleS=PTFeeder:name
2389 char *serverBLEName = getServiceName_BLEServerNetworking();
2390 addStatusStringFlag((char*)"bleS",serverBLEName);
2391 }
2392
2393 //!show Z for buZZ
2395
2396 //!show G for gateway
2398
2399 //! 8.10.25
2400 //! #393 add stepper angle
2401 //!show SA for stepper angle float ..
2403
2404
2405 //!P = paired
2408#ifdef NO_MORE_PREFERENCE_BLE_USE_DISCOVERED_PAIRED_DEVICE_SETTING
2409
2412#endif
2413 {
2414 addStatusStringFlag("P", pairedDeviceName);
2415 }
2416
2417 //! add the canister and stepper angle per #278
2418#ifdef ESP_32
2423
2424#endif
2425}
2426
2427//!returns a string in in URL so: status?battery=84'&buzzon='off' } .. etc
2428//!if fullStatus, return everything, else just the ATOM stuff
2429char* main_currentStatusURL(boolean fullStatus)
2430{
2431 //!7.20.25 add T too
2432 int time = getTimeStamp_mainModule();
2433 if (fullStatus)
2434 {
2435 //! 8.16.25 MQTT
2436 char *deviceName = getDeviceNameMQTT();
2437 //!TODO: make sure no spaces ... unless escaped
2438
2439 sprintf(_fullStatusString,"status?T=%d&v=%s&dev=%s&b=%02.0f&temp=%02.0f&c=%0d&t=%0d",time, VERSION_SHORT, deviceName, getBatPercentage_mainModule(), getTemperature_mainModule(), getFeedCount_mainModule(), getLoopTimer_displayModule());
2440
2441 }
2442 else
2443 {
2444 //_fullStatusString[0] = '\0';
2445 //! 8.16.25 MQTT
2446 char *deviceName = getDeviceNameMQTT();
2447 //!TODO: make sure no spaces ... unless escaped
2448 sprintf(_fullStatusString,"status?T=%d&v=%s&dev=%s",time, VERSION_SHORT, deviceName);
2449
2450 }
2451#pragma mark USE_NEW_M5ATOMCLASS
2452 //! 5.6.25 use object version
2455
2456 //add to _fullStatusString
2458
2459// //NOTE: any new query from somewhere starts with & (they put it in)
2460
2461 SerialCall.println( _fullStatusString );
2462
2463 //!TODO: put these somewhere somehow (expandable easily..architecturally. eg. setStatus("battery","87") key,val
2464 //!the JSON DB supports db["battery"]=87 like syntax..
2465
2466 //return "status?buzzon=off&AP=off&MQTT=on&WIFI=on&BLE=on&battery=" + String(getBatPercentage(),0);
2467 return _fullStatusString;
2468}
2469
2470#ifdef UNDEFINED
2471//!sets status parts cia a a string in JSON format, such that {'battery':'84'}, {'buzzon':'off'} .. etc
2472void main_setStatusJSON(const char* JSONString)
2473{
2474 //would set the JSON string
2475}
2476//!sets status parts cia a a string in JSON format, such that {'battery':'84'}, {'buzzon':'off'} .. etc
2477void main_setStatusKeyValue(const char* key, const char* value)
2478{
2479 //todo..
2480}
2481#endif
2482
2483//!SemanticMarker events
2484//!This would see a DOCFollow message, and set the value.. then SM10 can display it..
2486//!sed the address to follow
2487void setSemanticMarkerDocFollow_mainModule(char* SMDocFollowAddress)
2488{
2489 _lastSemanticMarkerDocFollow = SMDocFollowAddress;
2492}
2493
2494//!gets the semanticAddress SemanticMarker&trade;
2496{
2498}
2499
2500//!sends the SM on the DOCFOLLOW channel (publish it..)
2501void sendSemanticMarkerDocFollow_mainModule(const char* SMDocFollowAddress)
2502{
2503 //! 8.16.25 MQTT
2504 sendDocFollowMessageMQTT(SMDocFollowAddress);
2505}
2506
2507//! 8.18.24 setting this will check for the factory setting..
2508void setClockwiseMotorDirection_mainModule(boolean isClockwiseFlag)
2509{
2511 SerialDebug.printf("factoryMotorClockwise = %d, isClockwiseFlag = %d\n",factoryMotorClockwise, isClockwiseFlag);
2512
2513 if (factoryMotorClockwise && isClockwiseFlag)
2514 {
2515 SerialDebug.println("setClockwiseMotorDirection -- same so no change");
2516 }
2517 else if (factoryMotorClockwise && !isClockwiseFlag)
2518 {
2519 //!toggle flag and save as that mode..
2520 isClockwiseFlag = !isClockwiseFlag;
2521 //! this says: factory is CW and we want to turn CCW
2522 //! so we have to go the opposite direction (!CW)
2523 }
2524 else if (!factoryMotorClockwise && isClockwiseFlag)
2525 {
2526 //! toggle flag as well,
2527 isClockwiseFlag = !isClockwiseFlag;
2528 //! this says: factory is CCW and we want to turn CW
2529 //! so we have to go the opposite direction (!CW)
2530 }
2531 else if (!factoryMotorClockwise && !isClockwiseFlag)
2532 {
2533 SerialDebug.println("setClockwiseMotorDirection -- same so no change");
2534 }
2535 //! set to what it thinks it is...
2537}
2538
2539//!Keep ProcessClientCmd short to let the callback run. instead change the feeder state flag
2540//! processes a message that might save in the EPROM.. the cmd is still passed onto other (like the stepper module)
2542{
2543 //!the sentToStepper is only needed if there are 'actions' on the command, versus just
2544 //! setting persistent EPROM data. Like feed, buzzer, etc..
2545 //!Thus we don't need to know much of their implementation.. or we just pass anyway!
2546 boolean sendToStepperModule = false;
2547 SerialDebug.printf("***** processClientCommand_mainModule(%c) from client*****\n", cmd);
2548
2549 //char cmd = message[0];
2550 //!only process things that are stored persistently..
2551 //!7.20.25 6 months T
2552 //!Using switch to guarentee unique case of single characters
2553 switch (cmd)
2554 {
2555 case 0x00:
2556 case 's':
2557 case 'c':
2558 {
2559 sendToStepperModule = true;
2560 } break;
2561 case 'a':
2562 {
2563
2564 SerialDebug.println("cmd=a startTimer");
2565 //!start timer..
2567
2568 } break;
2569 case 'A':
2570 {
2571
2572 SerialDebug.println("cmd=A stopTimer");
2573
2574 //!start timer..
2576
2577 } break;
2578 case 'j':
2579 {
2580 sendToStepperModule = true;
2581 SerialLots.println("Setting FeedState = JACKPOT_FEED");
2583
2584 } break;
2585 case 'u':
2586 {
2587 SerialDebug.println("Setting feederType = UNO");
2589
2590 //!Issue #332 8.17.2024
2592 //! set autoRotoate as well..
2594 //! default to clockwise == 0
2595 //! 8.18.24 setting this will check for the factory setting..
2597 } break;
2598 case 'm':
2599 {
2600 SerialDebug.println("Setting feederType = MINI");
2601 //save preference
2603 //!Issue #332 8.17.2024
2605 // turn clockwise..
2606 //! 8.18.24 setting this will check for the factory setting..
2608 } break;
2609 case 'L':
2610 {
2611 SerialDebug.println("Setting feederType = Tumbler");
2612 //save preference
2614 //!Issue #332 8.17.2024
2616 //! set autoRotoate as well..
2618 //! set autoRotoate as well..
2619 //! 8.18.24 setting this will check for the factory setting..
2620 //setClockwiseMotorDirection_mainModule(true);
2621 } break;
2622 //! 11.25.25 toggle the buzzer, THIS is local already, but the toggle:buzzer will be ONLY be to a BLE device
2623 //! that way it sends 'F'
2624 case 'F':
2625 {
2626 SerialDebug.println("Toggle Buzzer via BLE: 'F'");
2627 //! then toggle value
2629
2630 //! will be turned on so make sound..
2631 //! the main sync command (no parameters yet)
2633#ifdef LOCAL_NOT_REMOTE
2634 if (buzzerOn)
2636 else
2638#endif
2639 } break;
2640 //! this is a call to the connected device
2641 case 'f':
2642 {
2643 //! this will be a BLE message to the connectd device sending a 'F"
2644 SerialDebug.println("Toggle remove Buzzer via BLE: 'f'");
2645 //! then toggle value
2646 //! see if connected to a BLE device..
2647 char *connectedBLEDeviceName = connectedBLEDeviceName_mainModule()?connectedBLEDeviceName_mainModule():NULL;
2648 SerialDebug.printf("connectedBLEDeviceName = %s\n", connectedBLEDeviceName);
2649
2650 if (connectedBLEDeviceName)
2651 {
2652 SerialDebug.printf("Call Toggle Buzzer via BLE: 'F' - dev=%s\n", connectedBLEDeviceName);
2653
2654 //! send via BLE
2655 //!send a string of 13 or less characters.
2657 }
2658 } break;
2659 case 'B':
2660 {
2661 sendToStepperModule = true;
2662 SerialDebug.println("Setting buzzStatus = BUZZON");
2663 //save pref
2665
2666 //! 11.27.25 Turkey Day, Nice day Mt Out.
2667 //! Also make the Buzzer sound
2668
2669 //! will be turned on so make sound..
2670 //! the main sync command (no parameters yet)
2672 } break;
2673 case 'b':
2674 {
2675 sendToStepperModule = true;
2676
2677 SerialDebug.println("Setting buzzStatus = BUZZOFF");
2679 } break;
2680 case 'T':
2681 {
2682 SerialDebug.println("*** Setting tilt = ON");
2684 } break;
2685 case 't':
2686 {
2687 SerialDebug.println("Setting tilt = OFF");
2689 } break;
2690 case 'R':
2691 {
2692 SerialDebug.println("Clean Credentials");
2693 //! dispatches a call to the command specified. This is run on the next loop()
2695 } break;
2696 //!6.20.25
2697#ifdef NOT_SUPPORTED_RIGHT_NOW
2698 case 'O':
2699 {
2700 SerialDebug.println("OTA Update.. ");
2701 //! dispatches a call to the command specified. This is run on the next loop()
2703 } break;
2704#endif
2705 case 'X':
2706 {
2707 SerialDebug.println("Clean EPROM.. ");
2708 //! dispatches a call to the command specified. This is run on the next loop()
2710 } break;
2711 case 'x':
2712 {
2713 SerialDebug.println("Clean SSID from EPROM.. ");
2714 char cleanWIFI[100];
2715 strcpy(cleanWIFI,"{'ssid':'','ssidPassword':''}");
2716 SerialDebug.println(cleanWIFI);
2717 //! 8.16.25 MQTT
2718 //! send to ourself
2719 sendMessageNoChangeMQTT((char*)cleanWIFI);
2720
2721 } break;
2722
2723 //!NOTE: the gateway is auto selected for now. A future version might manually set it in other situations (eg. my iPhone app should have a flag to not be a gateway at time)
2724 case 'G':
2725 {
2726 SerialDebug.println("Setting Gateway = ON");
2728 } break;
2729 case 'g':
2730 {
2731 SerialDebug.println("Setting Gateway = OFF");
2733 } break;
2734 case '_':
2735 {
2736 //This is from the handshake like "_BLEClient_ESP_M5"
2737 SerialDebug.println("unused cmd '_'");
2738 } break;
2739#ifdef OLD_FOR_M5_DISPLAY
2740 case 'Z':
2741 {
2742 sendToStepperModule = false;
2743
2744 SerialDebug.println("Setting SM Zoom = zoomed");
2746 } break;
2747 case 'z':
2748 {
2749 sendToStepperModule = false;
2750
2751 SerialDebug.println("Setting SM Zoom = full SM");
2753 } break;
2754#else
2755 //! 7.25.25 chilly morning, Mt starting to come out.
2756 //! SPIFF
2757 case 'Z':
2758 {
2759 //! clean SPIFF file"
2760
2761 SerialDebug.println("clean SPIFF file");
2763 } break;
2764 case 'z':
2765 {
2766 //! upload SPIFF to web
2767
2768 SerialDebug.println("upload SPIFF to web");
2769 //! number of lines to send
2770 //! TODO: configure thie number of lines to save..
2772 } break;
2773#endif
2774 case 'P':
2775 {
2776 //printout the spiff.. to the serial debug monitor
2777 //!Restarts (or attempts) a restart of the WIFI using the existing credentials -- vs the 'n' command
2779 } break;
2780 //! 7.24.25 use SPIFF
2781 case 'S':
2782 {
2783 //! toggle spiff on/off
2785 spiffFlag = !spiffFlag;
2786
2787 SerialDebug.printf("Changing current USE_SPIFF = %s\n", spiffFlag?"NOYES":"NO");
2789
2790 // reboot
2792
2793 }
2794 //! WIFI credential changes...
2795 case 'N':
2796 {
2797 //NOTE: this might be where we toggle credentials?? TODO
2798 //found other one..
2799 char *credentials = main_JSONStringForWIFICredentials();
2800
2801 //!These are the ASYNC_CALL_PARAMETERS_MAX
2803 } break;
2804 case 'n':
2805 {
2806 //!NOTE: this is almost the same as 'w' except there might be more WIFI than 2 (so swap is different).
2808 } break;
2809 case 'W':
2810 {
2812 } break;
2813 case 'w':
2814 {
2815 SerialDebug.println("w for swapWifi");
2816
2818 } break;
2819
2820 //! 8.16.24 per #332
2821 case 'H':
2822 {
2823 SerialDebug.printf("PREFERENCE_STEPPER_AUTO_MOTOR_DIRECTION_SETTING true");
2824
2825 // autoMotorDirection ON
2827
2828 } break;
2829 //! 8.16.24 per #332
2830
2831 case 'h':
2832 {
2833 SerialDebug.printf("PREFERENCE_STEPPER_AUTO_MOTOR_DIRECTION_SETTING false");
2834
2835 // autoMotorDirection off
2837 } break;
2838 case 'D':
2839 {
2840 SerialDebug.printf("PREFERENCE_STEPPER_CLOCKWISE_MOTOR_DIRECTION_SETTING counter clockwise");
2841
2842 //!NOTE: no current mode to specify CCW or CW dynamically (non factory reset)
2843 // motor direction = counterclockwise
2845 } break;
2846 case 'd':
2847 {
2848 SerialDebug.printf("PREFERENCE_STEPPER_CLOCKWISE_MOTOR_DIRECTION_SETTING clockwise");
2849
2850 // motor direction == (clockwise)
2852 } break;
2853 //! 9.30.23 reverse direction
2854 case 'Q':
2855 {
2856 SerialDebug.printf("PREFERENCE_STEPPER_CLOCKWISE_MOTOR_DIRECTION_SETTING reverse direction");
2857
2858 //! note: reboot not needed as the next time a feed happens, it reads this value
2859 // motor direction == (reverse)
2861 currentDirection = !currentDirection;
2863
2864 } break;
2865 case 'E':
2866 {
2867 SerialDebug.printf("PREFERENCE_BLE_SERVER_USE_DEVICE_NAME_SETTING false");
2868
2869 //!if set, the BLE Server (like PTFeeder) will tack on the device name (or none if not defined).
2871 // reboot
2873 } break;
2874 case 'e':
2875 {
2876 SerialDebug.printf("PREFERENCE_BLE_SERVER_USE_DEVICE_NAME_SETTING true");
2877
2878 //!if set, the BLE Server (like PTFeeder) will tack on the device name (or none if not defined).
2880 // reboot
2882 } break;
2883 case 'r':
2884 {
2885 // reboot
2886 SerialDebug.println("REBOOT ...");
2888 } break;
2889
2890 case 'p':
2891 {
2892 //! poweroff
2893 SerialDebug.printf("(%c) POWEROFF ...", cmd);
2895 } break;
2896 //! 7.12.25
2897 //! 0 == Clear SENSOR definitions
2898 case 'k':
2899 {
2900 //! poweroff
2901 SerialDebug.println("Clearing Sensors");
2902 setSensorsString_mainModule((char*)"");
2903
2904 //! reboot .. so the sensors are set..
2906 } break;
2907 //! 7.9.25
2908 //! 1 == Init SENSOR definitions
2909 case '1':
2910 {
2911 setConfiguration_mainModule((char*)"L9110S_DCStepperClass");
2912 } break;
2913#ifdef NOT_ANYMORE
2914 //! 7.12.25
2915 //! 2 == default for SMART Button
2916 case '2':
2917 {
2918 setConfiguration_mainModule((char*)"ULN2003_StepperClass");
2919 } break;
2920#endif
2921 //! 12.21.25 Winter Solstice, Eagles,
2922 //! support the new Chain Buttons
2923 case '2':
2924 {
2925 setConfiguration_mainModule((char*)"ChainButtonClass");
2926 } break;
2927 //! 7.19.25 add Clear Sensors
2928 case '3':
2929 {
2930 setConfiguration_mainModule((char*)"PTStepper");
2931 } break;
2932 case '4':
2933 {
2934 setConfiguration_mainModule((char*)"M5AtomCamera");
2935 } break;
2936 //! 7.9.25 grabbed from BOOTSTRAP let someone update the atom to the recent OTA
2937 case '5':
2938 {
2939 SerialDebug.println(" *** performing m5atom OTA Update");
2940 //! 8.16.25 MQTT
2941 //!retrieves from constant location
2942 performOTAUpdate((char*)"http://KnowledgeShark.org", (char*)"OTA/TEST/M5Atom/ESP_IOT.ino.m5stick_c_plus.bin");
2943 } break;
2944 //! 7.9.25 grabbed from BOOTSTRAP let someone update the atom to the recent OTA
2945 case '6':
2946 {
2947 SerialDebug.println(" *** performing m5atom OTA Update - DAILY");
2948 //! 8.16.25 MQTT
2949 //!retrieves from constant location
2950 performOTAUpdate((char*)"http://KnowledgeShark.org", (char*)"OTA/TEST/M5Atom/daily/ESP_IOT.ino.m5stick_c_plus.bin");
2951 } break;
2952 case '7':
2953 {
2954 SerialDebug.println(" *** performing m5atom OTA Update - BOOTSTRAP");
2955 //! 8.16.25 MQTT
2956 //!retrieves from constant location
2957 performOTAUpdate((char*)"http://KnowledgeShark.org", (char*)"OTA/Bootstrap/ESP_M5_BOOTSTRAP.ino.m5stack_stickc_plus.bin");
2958 } break;
2959 //! 8.18.25
2960 case '8':
2961 {
2962 setConfiguration_mainModule((char*)"M5NoModule");
2963 } break;
2964 case '9':
2965 {
2966 setConfiguration_mainModule((char*)"M5TinyGPS");
2967 } break;
2968 case '0': //m5atom_qrode
2969 {
2970 setConfiguration_mainModule((char*)"M5AtomScanner");
2971 } break;
2972#ifdef USE_6
2973 case '9':
2974 {
2975 //! 8.18.25 M5Clicker
2976 SerialDebug.println(" *** performing m5atom OTA Update - M5Clicker");
2977 //! 8.16.25 MQTT
2978 //!retrieves from constant location
2979 performOTAUpdate((char*)"http://KnowledgeShark.org", (char*)"OTA/Bootstrap/ESP_M5_BOOTSTRAP.ino.m5stack_stickc_plus.bin");
2980 } break;
2981#endif
2982 case 'C':
2983 {
2984 SerialDebug.println("'C' change color touched");
2985#ifdef USE_FAST_LED
2986 CRGB randomColor = getRandomColor();
2987 fillpix(randomColor);
2988 delay(50);
2989#endif
2990 }
2991 break;
2992 case 'i':
2993 {
2994 char sendCapture[100];
2995 strcpy(sendCapture,"{'send':'capture'}");
2996 SerialDebug.println(sendCapture);
2997 //! 8.16.25 MQTT
2998 //! send to ourself
2999 sendMessageNoChangeMQTT((char*)sendCapture);
3000
3001 }
3002 break;
3003 case '.':
3004 {
3005
3006 //! returns if the BLEClient is turned on.. note, if connected to a BLE device, then disconnect
3007
3009 //! toggle spiff on/off
3011
3012 SerialMin.println("Valid Commands: ");
3013 SerialMin.println(" . = help, this message");
3014 SerialMin.println(" p = poweroff if can");
3015 SerialMin.println(" 0x0, s, c == Single Feed - via BLE to connected device");
3016 SerialMin.println(" a == AutoFeed On");
3017 SerialMin.println(" A == AutoFeed Off");
3018 SerialMin.println(" u == UNO ");
3019 SerialMin.println(" m == MINI ");
3020 SerialMin.println(" L == tumbler");
3021 SerialMin.println(" H == autoMotorDirection on");
3022 SerialMin.println(" h == autoMotorDirection off");
3023 SerialMin.println(" D == FACTORY counter clockwise motor direction");
3024 SerialMin.println(" d == FACTORY clockwise motor direction");
3025 SerialMin.println(" Q == change motor direction opposite of current");
3026
3027 //! this is local buzzer on/off calling the current Atom Class
3028 SerialMin.println(" F == Toggle Buzzer on/off");
3029 //! this will be a BLE message to the connectd device sending a 'F"
3030 SerialMin.println(" f == Toggle Buzzer on/off on BLE connected device");
3031
3032 SerialMin.println(" B == Buzzer On");
3033 SerialMin.println(" b == Buzzer Off");
3034 SerialMin.println(" G == Gateway On");
3035 SerialMin.println(" g == Gateway Off");
3036 SerialMin.println(" R == clean credentials");
3037 SerialMin.println(" X == clean EPROM");
3038 SerialMin.println(" x == clean SSID from EPROM");
3039 SerialMin.println(" r == reboot ");
3040 //!6.20.25
3041
3042 SerialMin.println(" T == tiltOn");
3043 SerialMin.println(" t == tiltOff");
3044 SerialMin.println(" N == send WIFI Credential to BLEServer");
3045 SerialMin.println(" n == next WIFI Credential");
3046 SerialMin.println(" W == retry WIFI");
3047 SerialMin.println(" w == swap WIFI");
3048 SerialMin.println(" C == change m5 atom to random color");
3049 SerialMin.println(" i == take pic, {send:capture}");
3050
3051 SerialMin.println(" SPIFF internal memory ");
3052#ifndef OLD_FOR_M5_DISPLAY
3053 SerialMin.println(" Z == clean SPIFF file");
3054 SerialMin.println(" z == upload SPIFF to web");
3055#endif
3056 SerialMin.println(" P == print SPIFF");
3057 SerialMin.printf (" S == toggle SPIFF %s\n", spiffFlag?"OFF":"ON");
3058
3059 SerialMin.println(" BLE Naming ");
3060
3061 SerialMin.println(" E == use only PTFeeder naming");
3062 SerialMin.println(" e == use naming PTFeeder:name");
3063#ifdef OLD_FOR_M5_DISPLAY
3064 SerialMin.println(" Z == Setting SM Zoom = zoomed");
3065 SerialMin.println(" z == Setting SM Zoom = full SM");
3066#endif
3067 SerialMin.println(" Configurations of M5Atom ");
3068
3069 SerialMin.println(" k == no sensors");
3070 SerialMin.println(" 1 == L9100S_DCStepper (current main)");
3071 //SerialMin.println(" 2 == ULN2002 Stepper (new test 8.13.25)");
3072 SerialMin.println(" 2 == ChainSensors (12.21.25))");
3073 SerialMin.println(" 3 == *** PTStepperClass (original code - with M5");
3074 SerialMin.printf (" 4 == M5AtomCamera\n");
3075 SerialMin.println(" 8 == SMART Button, Clicker");
3076 SerialMin.println(" 9 == M5TinyGPS, Clicker");
3077 SerialMin.println(" 0 == M5AtomScanner, Clicker");
3078
3079
3080#ifdef NOT_SUPPORTED_RIGHT_NOW
3081 SerialMin.println(" O == OTA update");
3082#else
3083 SerialMin.println(" OTA Updates of M5Atom ");
3084 SerialMin.println(" 5 == m5atom DEV OTA update");
3085 SerialMin.println(" 6 == m5atom DAILY TEST DEV OTA update");
3086 SerialMin.println(" 7 == go back to m5atom BOOTSTRAP");
3087
3088#endif
3089 SerialMin.println();
3090 SerialMin.println("Full API at: https://github.com/konacurrents/SemanticMarkerAPI");
3091 SerialMin.println();
3092
3093 //!print out stuff
3095
3096 } break;
3097 break;
3098 default:
3099
3100 {
3101 SerialMin.printf("*****invalid command '%c' from client (use '.' for help) *****\n", cmd);
3102 }
3103 }
3104
3105#ifdef USE_STEPPER_MODULE
3106 if (sendToStepperModule)
3107 {
3109 }
3110#endif
3111}
3112
3113//! 8.20.25 Horses grazing if field first time for Mark and Bud
3114//! add set/config
3115//! PTStepper
3116//! M5AtomCamera
3117void setConfiguration_mainModule(char* configurationName)
3118{
3119 SerialDebug.printf("setConfiguration: %s\n", configurationName);
3120
3121 if (strcmp(configurationName, "PTStepper")==0)
3122 {
3123 //! poweroff
3124 SerialDebug.println("Default PTStepperClass");
3125 //resetSensorToDefault_mainModule();
3126 //! 7.30.25 changing to the HDriver's board
3127 //! savePreference_mainModule(PREFERENCE_SENSORS_SETTING, _sensorsEPROM);
3128#ifdef DONT_ADD_TO_SENSORS
3129 setSensorsString_mainModule((char*)"BuzzerSensorClass,21,25,PTStepperClass,23,33");
3130#else
3131 setSensorsString_mainModule((char*)"BuzzerSensorClass,21,25");
3132
3133#endif
3134 //! 7.31.25 if Scanner or QR then pin 22 used .. so make M5HDriver (basically don't have a sensor)
3136 //! also specify the sensor plug
3138 //! for Tumbler .. use 200
3140 //! @see #390 this is the RPM of the stepper
3141 //savePreferenceFloat_mainModule(PREFERENCE_STEPPER_RPM_SETTING, 15.0);
3142 //! set autoRotoate as well..
3144 //! tumbler
3146
3147 //! 9.5.25 set the 2step OFF for now
3149
3150 //! 10.24.25 also set BLE client and serve on,
3151 //! RAIN .. atosmopheric river
3152 //savePreferenceBoolean_mainModule(PREFERENCE_MAIN_BLE_CLIENT_VALUE, true);
3154
3155 //!if set, the BLE Server (like PTFeeder) will tack on the device name (or none if not defined).
3157
3158 //! reboot .. so the sensors are set..
3160 }
3161#pragma mark CHAIN BUTTON
3162 //! 12.21.25 Winter Solstice, Eagles,
3163 //! Chain Button
3164 else if (strcmp(configurationName, "ChainButtonClass")==0)
3165 {
3166 //! poweroff
3167 SerialDebug.println("Default ChainButtonClass **** NEED WORK ****");
3168 //resetSensorToDefault_mainModule();
3169 //! 7.30.25 changing to the HDriver's board
3170 setSensorsString_mainModule((char*)"ChainButtonClass,19,22");
3171
3172 //! 7.31.25 if Scanner or QR then pin 22 used .. so make M5HDriver (basically don't have a sensor)
3174 //! also specify the sensor plug (non for now..
3176
3177
3178 //!TODO.. Chain
3179 //!presskind = 0, short, 1, long, 2, longlong
3180 //!ButtonKind, number_1based, pressKind, setString, valString, device
3181 //!if localhost then internal message, otherwise external MQTT message
3182 savePreference_mainModule(PREFERENCE_CHAIN_SENSORS_SETTING, "ChainButtonClass,1,0,SM_MatrixCell,8,$all,ButtonClass,1,1,feed,,$pair,JoystickClass,2,0,feed,,$localhost");
3183
3185
3186 //! idea is you define the button and the press kind
3187 //! MatrixCell is Column Major 1,4, 7 // 2,5,8 // 3,6,9
3188 registerChain_mainModule("ButtonClass", 1, BUTTON_SHORT_PRESS, "SM_MatrixCell", "15", "$dev" );
3189 registerChain_mainModule("ButtonClass", 1, BUTTON_LONG_PRESS, "SM_MatrixCell", "6", "$dev");
3190 registerChain_mainModule("JoystickClass", 2, BUTTON_SHORT_PRESS, "feed", "", "localhost" );
3191
3192
3193 //! 10.24.25 also set BLE client and serve on,
3194 //! RAIN .. atosmopheric river
3197
3198 //!if set, the BLE Server (like PTFeeder) will tack on the device name (or none if not defined).
3200
3202
3203 //! reboot .. so the sensors are set..
3204 // FOR NOW until parser workign .. don't reboot ...
3206 }
3207 else if (strcmp(configurationName, "ULN2003_StepperClass")==0)
3208 {
3209 /*
3210 #define IN1 22
3211 #define IN2 19
3212 #define IN3 23
3213 #define IN4 33
3214 */
3215 //! poweroff
3216 SerialDebug.println("Default ULN2003_StepperClass");
3217 //resetSensorToDefault_mainModule();
3218 //! 7.30.25 changing to the HDriver's board
3219 setSensorsString_mainModule((char*)"BuzzerSensorClass,21,25");
3220 //! 7.31.25 if Scanner or QR then pin 22 used .. so make M5HDriver (basically don't have a sensor)
3222 //! also specify the sensor plug
3224 //! 1 second motor (overloads "angle" field)
3225 //! This is the RPM speed
3227 //! @see #390 this is the RPM of the stepper
3229 //! set autoRotoate as well..
3231 //! tumbler
3233
3234 //!if set, the BLE Server (like PTFeeder) will tack on the device name (or none if not defined).
3236
3237 //! reboot .. so the sensors are set..
3239 }
3240 else if (strcmp(configurationName, "M5AtomCamera")==0)
3241 {
3242 //! poweroff
3243 SerialDebug.println("Default M5AtomCamera");
3244 //resetSensorToDefault_mainModule();
3245 //! 7.30.25 changing to the HDriver's board
3246 setSensorsString_mainModule((char*)"");
3247 //! 7.31.25 if Scanner or QR then pin 22 used .. so make M5HDriver (basically don't have a sensor)
3249 //! also specify the sensor plug
3251
3252 //! 10.24.25 also set BLE client and serve on,
3253 //! RAIN .. atosmopheric river
3256
3257 //!if set, the BLE Server (like PTFeeder) will tack on the device name (or none if not defined).
3259
3260 //! reboot .. so the sensors are set..
3262 }
3263 else if (strcmp(configurationName, "M5TinyGPS")==0)
3264 {
3265 //!
3266 SerialDebug.println("Default M5AtomTinyGPS");
3267 //resetSensorToDefault_mainModule();
3268 //! 7.30.25 changing to the HDriver's board
3269 setSensorsString_mainModule((char*)"");
3270 //! 7.31.25 if Scanner or QR then pin 22 used .. so make M5HDriver (basically don't have a sensor)
3272 //! also specify the sensor plug (non for now..
3274
3275 //! 10.24.25 also set BLE client and serve on,
3276 //! RAIN .. atosmopheric river
3279
3280 //!if set, the BLE Server (like PTFeeder) will tack on the device name (or none if not defined).
3282
3283 //! reboot .. so the sensors are set..
3285 }
3286 else if (strcmp(configurationName, "M5AtomScanner")==0)
3287 {
3288 //!
3289 SerialDebug.println("Default M5AtomScanner");
3290 //resetSensorToDefault_mainModule();
3291 //! 7.30.25 changing to the HDriver's board
3292 setSensorsString_mainModule((char*)"");
3293 //! 7.31.25 if Scanner or QR then pin 22 used .. so make M5HDriver (basically don't have a sensor)
3295 //! also specify the sensor plug (non for now..
3297
3298 //! 10.24.25 also set BLE client and serve on,
3299 //! RAIN .. atosmopheric river
3302
3303 //!if set, the BLE Server (like PTFeeder) will tack on the device name (or none if not defined).
3305
3306 //! reboot .. so the sensors are set..
3308 }
3309 else if (strcmp(configurationName, "M5NoModule")==0)
3310 {
3311 //!
3312 SerialDebug.println("Default M5AtomNoModule");
3313 //resetSensorToDefault_mainModule();
3314 //! 7.30.25 changing to the HDriver's board
3315 setSensorsString_mainModule((char*)"");
3316 //! 7.31.25 if Scanner or QR then pin 22 used .. so make M5HDriver (basically don't have a sensor)
3318 //! also specify the sensor plug (non for now..
3320
3321 //! 10.24.25 also set BLE client and serve on,
3322 //! RAIN .. atosmopheric river
3325
3326 //!if set, the BLE Server (like PTFeeder) will tack on the device name (or none if not defined).
3328
3329 //! reboot .. so the sensors are set..
3331 }
3332 else
3333 {
3334 SerialDebug.printf(" **** Unknown Configuration: %s\n", configurationName);
3335 }
3336}
3337
3338
3339//!On the esp32, sec is all we can handle. We can return as a double if milisecond resolution is needed.
3340//!This is the time since app started..
3341//!https://randomnerdtutorials.com/epoch-unix-time-esp32-arduino/
3343{
3344
3345 time_t now;
3346 struct tm timeinfo;
3347 time(&now);
3348 //! 7.27.25
3349 //! miliseconds .. convert to seconds
3350 //now = now * 1000;
3351 SerialMin.printf("Unix Time: %d\n", now);
3352 return now;
3353}
3354
3355//! ************** SM Mode Processing ***************
3356
3357
3358//!returns an index from 0..max of SM matching cmd, or -1 if none
3360{
3361#ifdef ESP_M5
3362 //https://www.cplusplus.com/reference/cstring
3363 if (strncmp(cmd,"sm",2) == 0)
3364 {
3365 //point to the 'm' in 'sm'
3366 char *p = strchr(cmd,'m');
3367 //then increment
3368 p++;
3369 //convert to a number
3370 int num = atoi(p);
3371 //convert to integer..
3372 SerialLots.print("whichSMMode: ");
3373 SerialLots.print(cmd);
3374 SerialLots.print(" => " );
3375 SerialLots.println(num);
3376 return num;
3377 }
3378 else
3379#endif //ESP_M5
3380 {
3381 return -1;
3382 }
3383}
3384//!returns if a match the mode. whichSMMode is 0..12 and == sm0 .. smn
3385boolean matchesSMMode_mainModule(char *cmd, int whichSMMode)
3386{
3387 char *mode = charSMMode_mainModule(whichSMMode);
3388 return (strcasecmp(cmd,mode)==0);
3389}
3390//!returns string form whichSMMode, sg "sm0", sm1 ...
3391//!This can (and is) called by multiple places (like ButtonProcessing and MainModule
3392char* charSMMode_mainModule(int whichSMMode)
3393{
3394 SerialLots.printf("charSMMode_mainModule: %d\n", whichSMMode);
3395
3396 sprintf(_smMode_MainModule,"sm%0d",whichSMMode);
3397 SerialCall.println(_smMode_MainModule);
3398 return _smMode_MainModule;
3399}
3400
3401//!returns which mode in (min or expanded)
3403{
3405}
3406
3407//!toggles the menu mode
3409{
3411}
3412
3413//! returns the current max of the MIN menu modes (using the setting of min or expanded) to determine
3415{
3416 return MAX_SM_MIN_MODES;
3417}
3418
3419//! returns the current max of the menu modes (using the setting of min or expanded) to determine
3421{
3422 SerialLots.printf("maxMenuModes_mainModule: %s, %d, %d\n", isMinimalMenuMode_mainModule?"1":"0", MAX_SM_MIN_MODES, MAX_SM_EXPANDED_MODES);
3424 return MAX_SM_MIN_MODES;
3425 else
3426 return MAX_SM_EXPANDED_MODES;
3427}
3428
3429//!the saved SMMode
3431//!sets the current screen mode .. which can be used by Button and Display processing
3432void setCurrentSMMode_mainModule(int whichSMMode)
3433{
3434 SerialLots.print("setCurrentSMMode_mainModule:");
3435 SerialLots.println(whichSMMode);
3436
3437 // This version sets the MIN OR MAX
3438 if (whichSMMode >= MAX_SM_MIN_MODES)
3439 {
3440 // change to EXPANDED MODES
3442 }
3443 _saveWhichSMMode = whichSMMode;
3444}
3445//!returns the current SM Mode
3447{
3448 return _saveWhichSMMode;
3449}
3450
3451//!increment the currentSMMode, wrapping and using the max menu
3453{
3455 int max = maxMenuModes_mainModule();
3456 if (_saveWhichSMMode >= max)
3457 {
3458 _saveWhichSMMode = 0;
3459 }
3460 SerialTemp.print("incrementSMMode_mainModule:");
3461 SerialTemp.println(_saveWhichSMMode);
3462}
3463//!increment the currentSMMode, wrapping and using the max menu
3465{
3466 if (_saveWhichSMMode > 0)
3467 {
3469 }
3470}
3471
3472//!full: ""Name: PTFeeder:HowieFeeder, Address: 7c:9e:bd:48:af:92, serviceUUID: 0xdead"
3474{
3475 //! 8.16.25 BLE CLIENT
3477 return _fullBLEDeviceName;
3478 else
3479 {
3480 return (char*)"";
3481 }
3482}
3483
3484//!whether connected GEN3
3485boolean _connecteBLEisGEN3 = false;
3486//!whether the connected is a GEN3 (so the name isn't valid)
3488{
3489 return _connecteBLEisGEN3;
3490}
3491
3492//! BLE Discovery Methods
3493//! Connected to a BLE device with the advertised name. The syntax can include (PTFeeder:NAME) or just PTFeeder
3494//! Being disconnected is already a flag isConnectedBLE ...
3495void setConnectedBLEDevice_mainModule(char *deviceName, boolean isGEN3)
3496{
3497 //!set the isGEN3 flag
3498 _connecteBLEisGEN3 = isGEN3;
3499 //!now set the gateway based on if GEN3
3500 SerialTemp.printf("auto-settingGateway(%d)\n", isGEN3);
3502
3503 strcpy(_fullBLEDeviceName, deviceName);
3504
3505 //!seems device name = "Name: PTFeeder:HowieFeeder, Address: 7c:9e:bd:48:af:92, serviceUUID: 0xdead
3506 //!Note: the Address, eg "7c:9e:bd:48:af:92" is unique somehow.. lets use that to skip one..
3507 SerialCall.printf("setConnectedBLEDevice_mainModule: %s\n", deviceName);
3508 strcpy(_connectedBLEDeviceName,"");
3509
3510 if (containsSubstring(deviceName,"PTFeeder:") || containsSubstring(deviceName,"PTClicker:"))
3511 {
3512 //!parse out the 2nd half of name
3513 char *colon = index(deviceName,':');
3514 colon++;
3515 colon = index(colon,':');
3516 //! go past the :
3517 colon++;
3518
3519 while (*colon && *colon != ',')
3520 {
3521 int len = strlen(_connectedBLEDeviceName);
3522 _connectedBLEDeviceName[len] = colon[0];
3523 _connectedBLEDeviceName[len+1] = '\0';
3524 colon++;
3525 }
3526 }
3527 else
3528 {
3529 //! empty name (just PTFeeder)
3530 strcpy(_connectedBLEDeviceName,(char*)"");
3531 }
3532 SerialTemp.print("connectedBLEName= ");
3533 SerialTemp.println(_connectedBLEDeviceName);
3534
3535 //! 8.29.23 send a message saying we connected..
3536#ifdef LATER
3537 seems to be crashing..
3538 {
3539 char connectMessage[300];
3540 sprintf(connectMessage,"#connectedBLE {%s to %s}", getDeviceNameMQTT(), _connectedBLEDeviceName);
3541 SerialTemp.println(connectMessage);
3542 //sendSemanticMarkerDocFollow_mainModule(&fileURL[0]);
3543 //! for now only send if it start message starts with "#"
3544 publishMQTTMessageDefaultTopic(connectMessage);
3545 }
3546#endif
3547 //!parse for the address too..
3548 //! strcpy(_fullBLEDeviceName, deviceName);
3549
3550 //!seems device name = "Name: PTFeeder:HowieFeeder, Address: 7c:9e:bd:48:af:92, serviceUUID: 0xdead
3551 //!Note: the Address, eg "7c:9e:bd:48:af:92" is unique somehow.. lets use that to skip one..
3552 strcpy(_connectedBLEDeviceAddress,"");
3553 if (containsSubstring(_fullBLEDeviceName,"Address:"))
3554 {
3555 //!parse out the 2nd half of name
3556 char *colon = strstr(_fullBLEDeviceName,"Address:");
3557 colon += strlen("Address:");
3558 //strip spaces
3559 while (*colon && *colon == ' ')
3560 {
3561 colon++;
3562 }
3563 //now until the , is the address
3564 while (*colon && *colon != ',')
3565 {
3566 int len = strlen(_connectedBLEDeviceAddress);
3567 _connectedBLEDeviceAddress[len] = colon[0];
3568 _connectedBLEDeviceAddress[len+1] = '\0';
3569 colon++;
3570 }
3571 }
3572 else
3573 {
3574 //! empty name (just PTFeeder)
3575 strcpy(_connectedBLEDeviceAddress,(char*)"");
3576 }
3577 SerialTemp.print("_connectedBLEDeviceAddress= ");
3578 SerialTemp.println(_connectedBLEDeviceAddress);
3579}
3580
3581//!ISSUE: if BLE, can only return the address.. it's up to the caller to know it might not match the Paired Name (eg DukeGEN3)
3582//! returns the connected BLE Device name (the :NAME of advertisment, Address: 01:39:3f:33 part of name
3584{
3585 char *nameToUse;
3586 if (strlen(_connectedBLEDeviceName)!= 0)
3587 nameToUse = _connectedBLEDeviceName;
3588 else if (strlen(_connectedBLEDeviceAddress)!= 0)
3589 nameToUse =_connectedBLEDeviceAddress;
3590 else
3591 nameToUse = (char*)"";
3592
3593 //! 8.16.25 BLE CLIENT
3594
3595 //! if connected, return the connected name, otherwise return empty string
3597 {
3598 return nameToUse;
3599 }
3600 else
3601 {
3602 return (char*)"";
3603 }
3604}
3605
3606//!returns address part of name.
3608{
3609 //! 8.16.25 BLE CLIENT
3610
3611 //! if connected, return the connected name, otherwise return empty string
3613 {
3615 }
3616 else
3617 {
3618 return (char*)"";
3619 }
3620}
3621
3622//! 6.6.25 get the current M5AtomClassType
3624{
3625 return _whichM5AtomClassType;
3626}
3627
3628//! 1.22.24 add setup and loop at main so it can call appropriate plugs
3630{
3631#ifdef USE_BUTTON_MODULE
3632 //! the model part of the MVC for buttons
3633 loop_ButtonProcessing();
3634#endif
3635
3636 //! these are the plugin modules .. and only 1 active at a time except for ATOM
3637#ifdef M5CORE2_MODULE
3639#elif defined(M5_ATOM)
3640
3641#pragma mark USE_NEW_M5ATOMCLASS
3642 //! 5.6.25 use object version
3644 {
3645 SerialCall.printf("*** _whichM5AtomClassType %s\n",_whichM5AtomClassType->classIdentity() );
3647 }
3648 else
3649 {
3650 SerialDebug.println("*** _whichM5AtomClassType NULL ***");
3651
3652 }
3653
3654 // end atom
3655
3656#elif defined(M5BUTTON_MODULE)
3657 loop_M5ButtonModule();
3658#endif
3659}
3660
3661//! 1.22.24 setup of buttons
3663{
3664 SerialDebug.println("setup_Sensors_mainModule");
3665#ifdef USE_BUTTON_MODULE
3666 //! the model part of the MVC for buttons
3667 setup_ButtonProcessing();
3668#endif
3669 //! these are the plugin modules .. and only 1 active at a time except for ATOM
3670#ifdef M5_ATOM
3671 SerialDebug.println(" ***** M5_ATOM define ****");
3672#endif
3673#ifdef M5CORE2_MODULE
3675#endif
3676
3677#ifdef M5_ATOM
3678
3679#pragma mark M5AtomClassType
3680
3681 //! 5.6.25 use the M5Atom ClassType
3682#ifdef USE_NEW_M5ATOMCLASS
3683 //! @see https://www.cs.fsu.edu/~myers/cop3330/notes/dma.html
3684 _M5Atom_SocketModuleClass = new M5Atom_SocketModuleClass((char*)"M5AtomSocket");
3685 _M5Atom_QRCodeModuleClass = new M5Atom_QRCodeModuleClass((char*)"M5AtomScanner");
3686 _M5Atom_HDriverModuleClass = new M5Atom_HDriverModuleClass((char*)"M5HDriver");
3687 //! 7.17.25
3688 _M5Atom_TinyGPSModuleClass = new M5Atom_TinyGPSModuleClass((char*)"M5AtomTinyGPS");
3689 //! 8.16.25 bring in the Camera
3690 _M5Atom_CameraModuleClass = new M5Atom_CameraModuleClass((char*)"M5AtomCamera");
3691 //! 10.26.25 Power Out .. Wind Storm. Generator Running
3692 //! add a NoModule class
3693 _M5Atom_NoModuleClass = new M5Atom_NoModuleClass((char*)"M5AtomNoModule");
3694
3695 int whichM5AtomIndex = 0;
3696 SerialDebug.println("setup_M5Atoms");
3697
3698 //! 3.31.25 create array of plugs
3699 _M5AtomClassTypes[whichM5AtomIndex++] = _M5Atom_SocketModuleClass;
3700 _M5AtomClassTypes[whichM5AtomIndex++] = _M5Atom_QRCodeModuleClass;
3701 _M5AtomClassTypes[whichM5AtomIndex++] = _M5Atom_HDriverModuleClass;
3702 //! 7.17.25
3703 _M5AtomClassTypes[whichM5AtomIndex++] = _M5Atom_TinyGPSModuleClass;
3704 //! 8.16.25 bring in the Camera
3705 _M5AtomClassTypes[whichM5AtomIndex++] = _M5Atom_CameraModuleClass;
3706 //! 10.26.25 Power Out .. Wind Storm. Generator Running
3707 //! add a NoModule class
3708 _M5AtomClassTypes[whichM5AtomIndex++] = _M5Atom_NoModuleClass;
3709
3710 //! add check..
3711 if (whichM5AtomIndex > NUM_M5ATOM_CLASS)
3712 {
3713 SerialDebug.printf("**** sensors are more than max .. FIX CODE");
3714 }
3715 SerialDebug.printf("Created %d M5AtomClassTypes\n", whichM5AtomIndex);
3716
3717 //! use this one...
3718 _whichM5AtomClassType = NULL;
3719 //! find the current atomKind. which is a string
3720 char *atomKind = getPreferenceATOMKind_MainModule();
3721
3722 //! find which one..
3723 for (int i=0; i<NUM_M5ATOM_CLASS; i++)
3724 {
3725 if (!_M5AtomClassTypes[i])
3726 {
3727 SerialDebug.println("NULL M5AtomClassType");
3728 continue;
3729 }
3730 //! check against the identity.. (or make this part of that method?)
3731 if (strcmp(_M5AtomClassTypes[i]->classIdentity(), atomKind) == 0)
3732 {
3733 //! Matched..
3735 break;
3736 }
3737 }
3739 {
3740 SerialDebug.printf("** Found M5AtomClass = %s\n", atomKind);
3741 }
3742 else
3743 {
3744 SerialDebug.printf("****^^^ Cannot find M5AtomClass = %s\n", atomKind);
3745
3746 SerialDebug.println("Defaulting to _M5Atom_HDriverModuleClass");
3748 }
3749#else
3750 SerialDebug.printf("M5AtomKind = %d\n", getM5ATOMKind_MainModule());
3751#endif
3752
3753 //! now the setup() call
3754#pragma mark USE_NEW_M5ATOMCLASS
3755 //! 5.6.25 use object version
3758
3759 // end atom
3760
3761#elif defined(M5BUTTON_MODULE)
3762 setup_M5ButtonModule();
3763#endif
3764}
3765//! BUTTON PROCESSING abstraction
3766//!short press on buttonA (top button)
3768{
3769#ifdef USE_BUTTON_MODULE
3770 buttonA_ShortPress();
3771#endif
3772#ifdef M5CORE2_MODULE
3774#elif defined(M5_ATOM)
3775#pragma mark USE_NEW_M5ATOMCLASS
3776 //! 5.6.25 use object version
3778 {
3779 SerialDebug.println("buttonA_ShortPress_mainModule");
3781 }
3782
3783#elif defined(M5BUTTON_MODULE)
3784 buttonA_ShortPress_M5ButtonModule();
3785#endif
3786
3787}
3788
3789//!long press on buttonA (top button)
3791{
3792#ifdef USE_BUTTON_MODULE
3793 buttonA_LongPress();
3794#endif
3795#ifdef M5CORE2_MODULE
3797#elif defined(M5_ATOM)
3798
3799#pragma mark USE_NEW_M5ATOMCLASS
3800 //! 5.6.25 use object version
3802 {
3803 SerialDebug.println("buttonA_LongPress_mainModule");
3805 }
3806
3807#elif defined(M5BUTTON_MODULE)
3808 buttonA_LongPress_M5ButtonModule();
3809#endif
3810}
3811
3812//! 11.25.25 add long long
3813//!long press on buttonA (top button)
3815{
3816#ifdef USE_BUTTON_MODULE
3817 buttonA_LongLongPress();
3818#endif
3819#ifdef M5CORE2_MODULE
3820 buttonA_LongLongPress_M5Core2Module();
3821#elif defined(M5_ATOM)
3822
3823#pragma mark USE_NEW_M5ATOMCLASS
3824 //! 5.6.25 use object version
3826 {
3827 SerialDebug.println("buttonA_LongLongPress_mainModule");
3829 }
3830
3831#elif defined(M5BUTTON_MODULE)
3832 buttonA_LongLongPress_M5ButtonModule();
3833#endif
3834}
3835
3836
3837//!the long press of the side button
3839{
3840#ifdef USE_BUTTON_MODULE
3841 buttonB_LongPress();
3842#endif
3843#ifdef M5BUTTON_MODULE
3844 //!the long press of the side button
3845 buttonB_LongPress_M5ButtonModule();
3846#endif
3847}
3848//!the short press of the side button
3850{
3851#ifdef USE_BUTTON_MODULE
3852 buttonB_ShortPress();
3853#endif
3854
3855#ifdef M5BUTTON_MODULE
3856 //!the long press of the side button
3857 buttonB_ShortPress_M5ButtonModule();
3858#endif
3859}
3860#pragma mark BUTTON Processing of M5
3861
3862//!big button on front of M5StickC Plus
3864{
3865 _shortPress_MainModule = false;
3866 _longPress_MainModule = false;
3868#ifdef ESP_M5
3869
3870 //!NOTE: ths issue is the timer is interruped by the scanner.. so make long-long very long..
3871 //was 1000 (from 500)
3872 if (M5.BtnA.wasReleasefor(4500))
3873 {
3874 // buttonA_longPress_MainModule();
3875 SerialDebug.println("MainModule **** LONG LONG PRESS ***");
3877 }
3878 else if (M5.BtnA.wasReleasefor(1000))
3879 {
3880 // buttonA_longPress_MainModule();
3881 SerialDebug.println("MainModule **** LONG PRESS ***");
3882 _longPress_MainModule = true;
3883 }
3884 else if (M5.BtnA.wasReleased())
3885 {
3886 // buttonA_shortPress_MainModule();
3887 SerialDebug.println("MainModule **** SHORT PRESS ***");
3889 }
3890#endif
3891}
3892//!big button on front of M5StickC Plus
3894{
3895 _shortPress_MainModule = false;
3896 _longPress_MainModule = false;
3898#ifdef ESP_M5
3899
3900 //!NOTE: ths issue is the timer is interruped by the scanner.. so make long-long very long..
3901 //was 1000 (from 500)
3902 if (M5.BtnB.wasReleasefor(4500))
3903 {
3904 // buttonA_longPress_MainModule();
3905 SerialDebug.println("MainModule **** LONG LONG PRESS ***");
3907 }
3908 else if (M5.BtnB.wasReleasefor(1000))
3909 {
3910 // buttonA_longPress_MainModule();
3911 SerialDebug.println("MainModule **** LONG PRESS ***");
3912 _longPress_MainModule = true;
3913 }
3914 else if (M5.BtnB.wasReleased())
3915 {
3916 // buttonA_shortPress_MainModule();
3917 SerialDebug.println("MainModule **** SHORT PRESS ***");
3919 }
3920#endif
3921}
3922
3923#pragma mark Models
3924//!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
3926{
3927 //!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
3929}
3930
3931//! 1.1.24 send status of this device after events..
3933{
3934 //On demand #STATUS send the statusURL as well (if an M5)
3935 //this queues the sending of the StatusURL over MQTT.
3936 // This is async (next loop) since sending 2 MQTT messages can be hard to do in a row ..
3938}
3939
3940//! 3.23.25 rainy weekend
3941//! create a JSON string from the SemanticMarker
3942//! https://semanticmarker.org/bot/setdevice/scott@konacurrents.com/PASS/M5AtomSocket/socket/on}
3943//! Create a JSON knowing the "bot" syntax, eg. setdevice/USER/PASS/device/<set>/<flag>
3944//! defined in TokenParser.h
3945char *semanticMarkerToJSON_mainModule(char* semanticMarker)
3946{
3947 return semanticMarkerToJSON_TokenParser(semanticMarker);
3948}
3949
3950#pragma mark PIN_USE_STRUCT
3951#pragma mark PIN USE to see if overlaps.
3952//! 7.31.25 add this for a status, saw that QRCode was using 22 also .. so buzer didn't work.
3953/**
3954#define PIN_USE_MAX 10
3955struct pinUseStruct {
3956 int pinUseCount;
3957 //! string describing the module, etc
3958 char *pinUseArray[PIN_USE_MAX];
3959 //! each pin
3960 long pinNumArray[PIN_USE_MAX];
3961} _pinUseStruct;
3962*/
3963
3964//! global for use. This is an object (not a pointer) and has all the storage created statically
3966//! get the pin use array
3968{
3969 return &_pinUseStruct;
3970}
3971
3972
3973//! 7.31.25 store this information.. for STATUS
3974//! 5.3.25 add a central clearing house for defining PIN use
3975//! @see issue #365
3976//! central clearing house for all pins used to we can analyze if there are overlaps
3977//! pin is the actual number, pinName is the local name (eg. IN1_PIN or VIN_PIN).
3978//! moduleName is the module in the code,
3979//! isI2C is whether this is a I2C bus (which we aren't using much yet)
3980void registerPinUse_mainModule(long pin, String pinName, String moduleName, boolean isI2C)
3981{
3982 char pinUseSample[100];
3983 sprintf(pinUseSample,"PIN_USE: %2d = %s, %s %s", pin, pinName.c_str(), moduleName.c_str(), isI2C?"(I2C)":"");
3984 //! 5.3.25 create storage here
3985 char *pinUse = (char*)calloc(strlen(pinUseSample)+1, sizeof(char));
3986 strcpy(pinUse, pinUseSample);
3987 //!store globally
3989 //! 8.30.25 add the pin
3991
3992 //! increment
3994
3996 {
3997 SerialError.printf("*** ERROR .. too many PINS defined ***");
3999
4000 }
4001
4002 SerialDebug.printf("** PIN_USE: %s = %d, module=%s %s\n", pinName.c_str(), pin, moduleName.c_str(), isI2C?"(I2C)":"");
4003}
4004
4005
4006
4007
void sendCommandBLEClient(String cmdString)
boolean isConnectedBLEClient()
returns whether connected over BLE as a client to a server(like a ESP feeder)
void sendFeedCommandBLEClient()
sends the "feed" command over bluetooth to the connected device..
boolean useBLEClient()
returns if the BLEClient is turned on.. note, if connected to a BLE device, then disconnect
void sendCommandBLEClient_13orLess(String cmdString)
send a string of 13 characters or less
void sendBLEMessageACKMessage()
send ACK over bluetooth, this right now is 0x01
char * getServiceName_BLEServerNetworking()
retrieve the service name (PTFEEDER, PTFeeder:Name, PTClicker:Name, etc)
#define BLE_SERVER_CALLBACK_ONWRITE
void addToTextMessages_displayModule(String text)
void redrawSemanticMarker_displayModule(boolean startNew)
redraws the Semantic Marker image..
void blankScreen_displayModule()
blanks the screen
int getLoopTimer_displayModule()
returns the loop timer (just a timer..)
#define KEEP_SAME
Definition: DisplayModule.h:54
void setup_M5Core2Module()
void loop_M5Core2Module()
called for the loop() of this plugin
char * currentStatusJSON_M5Core2Module()
void messageSend_M5Core2Module(char *sendValue)
void messageSetVal_M5Core2Module(char *setName, char *valValue, boolean deviceNameSpecified)
void buttonA_ShortPress_M5Core2Module()
CRGB getRandomColor()
7.24.25 return a (semi) random color
Definition: M5Display.cpp:80
void fillpix(CRGB Color)
color the button light
Definition: M5Display.cpp:67
void publishMQTTMessageDefaultTopic(char *message)
Wrapper of the mqttclient publish.
void cleanEPROM_MQTTNetworking()
cleans the eprom info
void sendMessageNoChangeMQTT_Topic(char *message, char *topic)
just send a message but without any extras
void sendMessageMQTT(char *message)
void sendStatusMessageMQTT(const char *semanticMarker)
sends the semantic marker as a doc follow message #remoteMe (vs STATUS, as that triggers a status rep...
boolean processJSONMessageMQTT(char *ascii, char *topic)
process the JSON message (looking for FEED, etc). Note: topic can be nil, or if not,...
void sendMessageMQTT_Topic(char *message, char *topic)
for now only send if it start message starts with "#"
void sendDocFollowMessageMQTT(const char *semanticMarker)
sends the semantic marker as a doc follow message
void sendMessageNoChangeMQTT(char *message)
just send a message but without any extras
boolean isConnectedMQTT_MQTTState()
value of MQTT connected
@ groupTopic
char * getDeviceNameMQTT()
called for things like the advertisement
boolean isConnectedWIFI_MQTTState()
value of WIFI connected
void restartWIFI_MQTTState()
restart the WIFI and then MQTT connection
#define MQTT_CALLBACK_FEED
8.16.25 MQTT
void cleanEpromPreferences()
cleans the EPROM
void sendSemanticMarkerDocFollow_mainModule(const char *SMDocFollowAddress)
sends the SM on the DOCFOLLOW channel (publish it..)
M5Atom_NoModuleClass * _M5Atom_NoModuleClass
Definition: MainModule.cpp:58
void initCallbacksMain()
init the callbacks to dummy callbacks
Definition: MainModule.cpp:767
#define MESSAGE_STORAGE_MAX
global for others to use..
Definition: MainModule.cpp:411
char * _MQTT_Username
boolean _connecteBLEisGEN3
whether connected GEN3
void setAsyncCallOTAUpdate(bool flag)
sets the async OTA flag (for next loop)
void main_cleanSavedWIFICredentials()
clean the saved WIFI credential, otherwise the AP mode doesn't work (6.3.22)
void messageSend_mainModule(char *sendValue, boolean deviceNameSpecified)
TODO: have a callback regist approach.
Definition: MainModule.cpp:873
boolean _asyncCallOTAUpdateFlag
3.28.22 .. implemented in ESP_IOT.ino
boolean _stopAllProcessing
testing..
Definition: MainModule.cpp:385
M5Atom_Core2ModuleClass * _M5Atom_Core2ModuleClass
Definition: MainModule.cpp:49
char * createCopy2(const char *stringA)
#define CALLBACKS_MQTT
8.16.25 MQTT
Definition: MainModule.cpp:708
void main_updateMQTTInfo(char *ssid, char *ssid_password, char *username, char *password, char *guestPassword, char *deviceName, char *host, char *port, char *locationString)
sets the WIFI and MQTT user/password. It's up to the code (below, maybe in future a register approach...
ChainButtonClass * _ChainButtonClass
Definition: MainModule.cpp:95
void setConnectedBLEDevice_mainModule(char *deviceName, boolean isGEN3)
char _fullBLEDeviceName[100]
full: ""Name: PTFeeder:HowieFeeder, Address: 7c:9e:bd:48:af:92, serviceUUID: 0xdead"
Definition: MainModule.cpp:426
SensorClassType * _SensorClassTypes[NUM_SENSOR_CLASS_TYPES]
Definition: MainModule.cpp:99
#define CALLBACKS_MAX_BLE_SERVER
Definition: MainModule.cpp:725
KeyUnitSensorClass * _KeyUnitSensorClass
Definition: MainModule.cpp:91
char * connectedBLEDeviceNameAddress_mainModule()
returns address part of name.
void cleanSSID_EPROM_MessageCallback(char *message)
clean the SSID eprom (MQTT_CLEAN_SSID_EPROM)
callbackSignature * createMemory(int max)
return dyamically created array of max
Definition: MainModule.cpp:753
void toggleMinimalMenuMode_mainModule()
toggles the menu mode
char * charSMMode_mainModule(int whichSMMode)
returns string form whichSMMode, sg "sm0", sm1 ...
int _thresholdLUXDark
char * main_getUsername()
#define NUM_SENSOR_CLASS_TYPES
5.14.25
Definition: MainModule.cpp:87
char * groupTopicFullName(char *groupName)
returns a groupTopic to use as a topic
char * _OFF_LIGHT
char _smMode_MainModule[10]
current smMode
Definition: MainModule.cpp:416
void loop_mainModule()
called for the loop() of this plugin
Definition: MainModule.cpp:533
char * getSemanticMarkerDocFollow_mainModule()
gets the semanticAddress SemanticMarkerâ„¢
void main_setScannedGroupName(char *groupName)
void registerCallbackMain(int callbacksModuleId, int callbackType, void(*callback)(char *))
register the callback based on the callbackType. use the callbacksModuleId for which one....
Definition: MainModule.cpp:800
#define NUM_M5ATOM_CLASS
Definition: MainModule.cpp:63
M5Atom_HDriverModuleClass * _M5Atom_HDriverModuleClass
Definition: MainModule.cpp:47
char * deviceName_mainModule()
gets the device name
int getLUXThreshold_mainModule(int thresholdKind)
get the threshold val
void dummyCallbackMain(char *message)
example callback
Definition: MainModule.cpp:729
#define CALLBACKS_MAX_MQTT
Definition: MainModule.cpp:722
void initGlobals_mainModule()
init globals strings
Definition: MainModule.cpp:431
void sendStatusMQTT_mainModule()
1.1.24 send status of this device after events..
PinUseStruct _pinUseStruct
7.31.25 add this for a status, saw that QRCode was using 22 also .. so buzer didn't work.
char _deviceNameSave[50]
saved deviceName storage..
Definition: MainModule.cpp:418
void initSensorClassTypeArray()
Definition: MainModule.cpp:183
boolean connectedBLEDeviceIsGEN3_mainModule()
whether the connected is a GEN3 (so the name isn't valid)
boolean _shortPress_MainModule
5.6.25 use the M5Atom ClassType
Definition: MainModule.cpp:32
char * semanticMarkerToJSON_mainModule(char *semanticMarker)
char * main_currentStatusURL(boolean fullStatus)
int minMenuModesMax_mainModule()
returns the current max of the MIN menu modes (using the setting of min or expanded) to determine
int _thresholdLUXLight
#define CALLBACKS_BLE_SERVER
Definition: MainModule.cpp:711
boolean _asyncCallFlags[ASYNC_CALL_MAX]
storage for asyncCallCommands
void main_setScannedDeviceName(char *deviceName)
set the scanned device name
void processClientCommandChar_mainModule(char cmd)
single character version of processClientCommand (since many used that already)
boolean _longLongPress_MainModule
Definition: MainModule.cpp:34
char _scannedDeviceName[100]
int getFeedCount_mainModule()
feedcount info..
Definition: MainModule.cpp:643
void onStatusMessageBLEServerCallback(char *message)
The callback for "status messages" of the bluetooth.
Definition: MainModule.cpp:954
char * main_JSONStringForWIFICredentials()
retrieve a JSON string for the ssid and ssid_password: {'ssid':<ssid>,'ssidPassword':<pass>"}
int feedCountMax_mainModule()
returns the max for this feeder
Definition: MainModule.cpp:625
char _scannedGroupTopicName[100]
M5Atom_CameraModuleClass * _M5Atom_CameraModuleClass
Definition: MainModule.cpp:55
void setClockwiseMotorDirection_mainModule(boolean isClockwiseFlag)
8.18.24 setting this will check for the factory setting..
void solidLightOnOff(boolean onOff)
callback for SOLID blinking led
void sendMessageStringTopic_mainModule(char *messageString, char *topicString)
adding a synchronous call to send a message over the network (assuming MQTT but not specified),...
char * main_getScannedGroupNameTopic()
void checkButtonB_MainModule()
big button on front of M5StickC Plus
uint32_t _chipID_MainModule
3.17.24 the unqiue chip id
void main_credentialsUpdated()
moved here 4.25.22 (entirely from ESP_IOT.ino)
Definition: MainModule.cpp:936
void setup_mainModule()
called from the setup()
Definition: MainModule.cpp:451
void loopSensorClassTypeArray()
11.27.25 Turkey Day, loop
Definition: MainModule.cpp:102
void main_dispatchSyncCommand(int syncCallCommand)
the main sync command (no parameters yet)
boolean stopAllProcesses_mainModule()
if stopped
Definition: MainModule.cpp:397
void restartAllMenuStates_mainModule()
restarts all the menu states to the first one .. useful for getting a clean start....
void setSemanticMarkerDocFollow_mainModule(char *SMDocFollowAddress)
sed the address to follow
PIRSensorClass * _PIRSensorClass
Definition: MainModule.cpp:93
boolean isTrueString_mainModule(String valCmdString)
whether the string is TRUE, ON, 1
Definition: MainModule.cpp:837
char * main_getPassword()
return password
int whichSMMode_mainModule(char *cmd)
************** SM Mode Processing ***************
M5Atom_SocketModuleClass * _M5Atom_SocketModuleClass
instances of the M5AtomClassType
Definition: MainModule.cpp:43
void main_dispatchAsyncCommandWithString(int asyncCallCommand, char *parameter)
char _bigMessage[500]
Definition: MainModule.cpp:422
void initAsyncCallFlags()
initialize the async call flags (with and without parameters)
void registerPinUse_mainModule(long pin, String pinName, String moduleName, boolean isI2C)
void solidLightMessageCallback(char *message)
callback for SOLID blinking led
M5AtomClassType * _M5AtomClassTypes[NUM_M5ATOM_CLASS]
3.31.25 create array of plugs
Definition: MainModule.cpp:66
M5AtomClassType * _whichM5AtomClassType
use this one...
Definition: MainModule.cpp:69
boolean isEmptyString(char *stringA)
informs if null or empty string
void rebootDevice_mainModule()
void setConfiguration_mainModule(char *configurationName)
void poweroff_mainModule()
power off
int maxMenuModes_mainModule()
returns the current max of the menu modes (using the setting of min or expanded) to determine
void buttonB_ShortPress_mainModule()
the short press of the side button
#define GROUP_TOPIC_TO_SEND
boolean isPTFeeder_mainModule()
gets if PTFeeder a surrogate for the M5Atom class
Definition: MainModule.cpp:354
bool containsSubstring(String message, String substring)
check if the string contains the other string. This is a poor man's grammer checker
Definition: MainModule.cpp:684
void decrementSMMode_mainModule()
increment the currentSMMode, wrapping and using the max menu
M5Atom_QRCodeModuleClass * _M5Atom_QRCodeModuleClass
Definition: MainModule.cpp:45
void onWriteBLEServerCallbackFinish(char *message)
The FINISH of callback for "onWrite" of the bluetooth "onWrite'.
Definition: MainModule.cpp:963
char _serialBuffer[300]
Definition: MainModule.cpp:530
void callCallbackMain(int callbacksModuleId, int callbackType, char *message)
performs the indirect callback based on the callbackType
Definition: MainModule.cpp:819
int getCurrentSMMode_mainModule()
returns the current SM Mode
boolean _longPress_MainModule
Definition: MainModule.cpp:33
boolean _waitingForBigMessageEnd
store a big message #MSG_START .. #MSG_END
Definition: MainModule.cpp:421
void buttonA_LongLongPress_mainModule()
long long press on buttonA (top button)
void stopMotor_mainModule()
added 9.29.22 to support wildcards #196
Definition: MainModule.cpp:347
void stopProcessesForOTAUpdate_mainModule()
stop all loops... while OTA working..
Definition: MainModule.cpp:387
void feedMessageCallback(char *message)
Definition: MainModule.cpp:894
void resetFeedCount_mainModule()
sets the feed count max
Definition: MainModule.cpp:678
boolean asyncCallOTAUpdate()
performs an async OTA update
void sendMessageString_mainModule(char *messageString)
adding a synchronous call to send a message over the network (assuming MQTT but not specified),...
char * main_currentStatusJSON()
status in JSON format, needs to return something as a ',' is already added before calling this....
M5AtomClassType * whichM5AtomClassType()
6.6.25 get the current M5AtomClassType
void(* callbackSignature)(char *)
Definition: MainModule.cpp:749
void changeButtonColor_MainModule()
2.21.25 add a way to change the button color (if any)
void setup_Sensors_mainModule()
1.22.24 setup of buttons
char * getFullBLEDeviceName_mainModule()
full: ""Name: PTFeeder:HowieFeeder, Address: 7c:9e:bd:48:af:92, serviceUUID: 0xdead"
void checkButtonA_MainModule()
big button on front of M5StickC Plus
char _groupTopicName[100]
int getFeederType_mainModule()
get the feeder type (Sepper 1,2,3 ...)
Definition: MainModule.cpp:649
char _connectedBLEDeviceName[50]
saved BLE connected name 8.26.22
Definition: MainModule.cpp:424
char * _lastSemanticMarkerDocFollow
char _connectedBLEDeviceAddress[50]
full: ""Address: 7c:9e:bd:48:af:92, serviceUUID: 0xdead"
Definition: MainModule.cpp:428
void addMoreStatusQueryString()
void buttonA_LongPress_mainModule()
long press on buttonA (top button)
void addStatusBooleanFlag(const char *key, boolean flag)
adds to _fullStatusString a query string "&key=value"
void invokeAsyncCommands()
checks if any async commands are in 'dispatch' mode, and if so, invokes them, and sets their flag to ...
#define CALLBACKS_MAX_BLE_CLIENT
Definition: MainModule.cpp:724
boolean startsWithChar(char *str, char c)
a char* version of startsWith (after skipping spaces)
void showText_mainModule(String text)
callbackSignature * _allCallbacks[CALLBACKS_MODULE_MAX]
array of known size (CALLBACKS_MODULE_MAX) of callbackSignatures
Definition: MainModule.cpp:764
void setCurrentSMMode_mainModule(int whichSMMode)
sets the current screen mode .. which can be used by Button and Display processing
char * getPairedDeviceOrAddress_mainModule()
returns if the paired device is not NONE .. returns address or device
char _chipIdString_MainModule[15]
string like: 10311304
char * getPairedDevice_mainModule()
returns if the paired device is not NONE
void onWriteBLEServerCallback(char *message)
The callback for "onWrite" of the bluetooth "onWrite'.
char * _MQTT_Password
12.14.23
char * getServerServiceName_mainModule()
Definition: MainModule.cpp:375
void setLUXThreshold_mainModule(int thresholdKind, int luxVal)
set the threshold val
boolean _callbacksInitializedMain
flag for initializing if not yes
Definition: MainModule.cpp:746
#define CALLBACKS_BLE_CLIENT
Definition: MainModule.cpp:710
void main_dispatchAsyncCommand(int asyncCallCommand)
checks if any async commands are in 'dispatch' mode, and if so, invokes them, and sets their flag to ...
char _JSONStringForWIFICredentials[200]
global to store credentials when ever they are stored..
Definition: MainModule.cpp:409
boolean matchesSMMode_mainModule(char *cmd, int whichSMMode)
returns if a match the mode. whichSMMode is 0..12 and == sm0 .. smn
int _feedCount_mainModule
5.3.22 added a feed count approach.. (NOTE: there is a _feedCount in Dispence.cpp ....
Definition: MainModule.cpp:623
BuzzerSensorClass * _BuzzerSensorClass
Definition: MainModule.cpp:89
int _saveWhichSMMode
the saved SMMode
PinUseStruct * getPinUseStruct_mainModule()
get the pin use array
char * getChipIdString()
3.17.24 get the chip id as a string
void refreshDelayButtonTouched_MainModule()
called by the feed operation to say the device is still running.. and count it as a button click.
char * connectedBLEDeviceName_mainModule()
returns the connected BLE Device name (the :NAME of advertisment, Address: 01:39:3f:33 part of name,...
uint32_t getChipId()
3.17.24 get the chip id
boolean isMinimalMenuMode_mainModule()
returns which mode in (min or expanded)
char _asyncParameter[500]
the parameter being sent to those commands passing an argument
Definition: MainModule.cpp:407
void loop_Sensors_mainModule()
1.22.24 add setup and loop at main so it can call appropriate plugs
int getTimeStamp_mainModule()
void buttonB_LongPress_mainModule()
the long press of the side button
void blinkMessageCallback(char *message)
callback for blinking led
void restartProcessesForOTAUpdate_mainModule()
restart all loops... while OTA working..
Definition: MainModule.cpp:392
char * main_getScannedDeviceName()
return devicename
char * createCopy(char *stringA)
#define CALLBACKS_MAX_BUTTON_MODULE
Definition: MainModule.cpp:723
boolean _asyncCallFlagsParameters[ASYNC_CALL_PARAMETERS_MAX]
array of async flags for the different ASYNC_CALl values
char _fullStatusString[500]
status string (URL query format)
Definition: MainModule.cpp:414
void main_printModuleConfiguration()
M5Atom_TinyGPSModuleClass * _M5Atom_TinyGPSModuleClass
Definition: MainModule.cpp:52
void messageSetVal_mainModule(char *setName, char *valValue, boolean deviceNameSpecified)
Definition: MainModule.cpp:848
void singleClickTouched(char *whichButton)
float getTemperature_mainModule()
retrieves the temperature .
void buttonA_ShortPress_mainModule()
boolean isValidPairedDevice_mainModule()
returns if the paired device is not NONE. Note, the paired Name might be an address now (see below)
char * main_nextJSONWIFICredential()
! cycle through the next WIFI saved credential
void onBLEServerCallback(char *message)
The callback for "onWrite" of the bluetooth "onWrite'.
Definition: MainModule.cpp:947
void addStatusStringFlag(const char *key, char *val)
adds a query string "&key=value"
void incrementSMMode_mainModule()
increment the currentSMMode, wrapping and using the max menu
char * _ON_LIGHT
#define CALLBACKS_BUTTON_MODULE
Definition: MainModule.cpp:709
char _messageStorage[MESSAGE_STORAGE_MAX]
Definition: MainModule.cpp:412
void incrementFeedCount_mainModule()
increments .. and if MAX goes to 0 – and sends a message on MQTT
Definition: MainModule.cpp:656
void messageSetVal_SensorClassTypeArray(char *setName, char *valValue, boolean deviceNameSpecified)
Definition: MainModule.cpp:146
void main_saveWIFICredentials(char *ssid, char *ssid_password)
save the WIFI credential
void readPreferences_mainModule()
reads the preferences. Save is everytime the savePreference is called
char * getPairedDeviceAddress_mainModule()
returns if the paired device is not NONE
float getBatPercentage_mainModule()
start of the sensor updates ... TODO: tie these to the MQTT messaging as well..
int _callbacksFunctionsMAXS[CALLBACKS_MODULE_MAX]
the array of callback functions
Definition: MainModule.cpp:743
#define ASYNC_CALL_FEED_COMMAND
sends a 'c' to the BLE end of the code (assuming a feeder is connected). Need to morph if a real feed...
Definition: MainModule.h:201
#define MAX_SM_MIN_MODES
note for now, heep the max the same – so only goes through zoom or not zoom
Definition: MainModule.h:399
void cleanEPROM_mainModule()
cleans the main module EPROM
#define ASYNC_CALL_MAX
the max one greater than last one
Definition: MainModule.h:232
#define THRESHOLD_KIND_DARK
Definition: MainModule.h:78
#define ASYNC_REBOOT
sets the GATEWAY mode off
Definition: MainModule.h:217
#define ASYNC_CALL_BLE_CLIENT_PARAMETER
these are the async with a string parameter. This sends a BLE command unless MQTT
Definition: MainModule.h:235
#define ASYNC_REST_CALL_MESSAGE_PARAMETER
send REST call
Definition: MainModule.h:243
#define ASYNC_SEND_MQTT_FEED_MESSAGE
sends a message (like FEED) on the users topic
Definition: MainModule.h:207
#define CALLBACKS_MODULE_MAX
Definition: MainModule.h:94
#define ASYNC_JSON_MQTT_MESSAGE_PARAMETER
these are the async with a string parameter
Definition: MainModule.h:241
#define ASYNC_CALL_CLEAN_CREDENTIALS
cleans out the credentials and restarts in AP (Access Point) mode.
Definition: MainModule.h:197
#define ASYNC_SWAP_WIFI
swaps WIFI 'w'
Definition: MainModule.h:224
#define ASYNC_SET_GATEWAY_ON
sets the GATEWAY mode on
Definition: MainModule.h:212
#define MAX_SM_EXPANDED_MODES
Definition: MainModule.h:400
#define ASYNC_RESTART_WIFI_MQTT
restarts the WIFI (after BLE interrupt over)
Definition: MainModule.h:228
#define THRESHOLD_KIND_LIGHT
Definition: MainModule.h:77
#define SYNC_CLICK_SOUND
Definition: MainModule.h:262
#define PIN_USE_MAX
Definition: MainModule.h:501
#define ASYNC_CALL_BUZZ_ON
sends a 'B' to the BLE end of the code (assuming a feeder is connected).
Definition: MainModule.h:203
#define ASYNC_POWEROFF
sets the GATEWAY mode off
Definition: MainModule.h:219
#define ASYNC_CALL_CLEAN_EPROM
cleans the EPROM totally, and reboots
Definition: MainModule.h:199
#define ASYNC_BLANKSCREEN
blank the screen
Definition: MainModule.h:221
#define ASYNC_CALL_PARAMETERS_MAX
the max one greater than last one
Definition: MainModule.h:245
#define ASYNC_SEND_MQTT_STATUS_URL_MESSAGE
sends the status from the main module URL
Definition: MainModule.h:209
#define ASYNC_SET_GATEWAY_OFF
sets the GATEWAY mode off
Definition: MainModule.h:214
#define ASYNC_CALL_OTA_FILE_UPDATE_PARAMETER
these are the async with a string parameter
Definition: MainModule.h:237
#define ASYNC_CALL_OTA_UPDATE
TODO: make this a registeration approach.
Definition: MainModule.h:195
#define TOPIC_TO_SEND
Definition: MainModule.h:65
#define ASYNC_NEXT_WIFI
next WIFI 'n'
Definition: MainModule.h:226
#define ASYNC_CALL_BUZZ_OFF
sends a 'b' to the BLE end of the code (assuming a feeder is connected).
Definition: MainModule.h:205
#define ASYNC_CLICK_SOUND
5.15.25 add a BUZZ command (or CLICK)
Definition: MainModule.h:230
#define ASYNC_JSON_MESSAGE_PARAMETER
these are the async with a string parameter
Definition: MainModule.h:239
void updateMenuState(ModelKindEnum modelKind)
updates the model for the menu state, this sets max etc
void startStopTimer_mainModule(boolean startTimer)
void initModelStructs_ModelController()
initialize the objects
void restartAllMenuStates_ModelController()
restarts all the menu states to the first one .. useful for getting a clean start....
@ timerModel
void performOTAUpdateSimple()
retrieves from constant location
void performOTAUpdate(char *hostname, char *httpAddress)
8.16.25 MQTT
void savePreferenceInt_mainModule(int preferenceID, int val)
sets an int preference
void savePreferenceBoolean_mainModule(int preferenceID, boolean flag)
save a boolean preference
void printSensors_mainModule(SensorsStruct *sensors)
print sensors, passing in a struct
SensorsStruct * getSensors_mainModule()
return the sensors defined
void initChainSensorStringsFromEPROM_mainModule()
void setSensorsString_mainModule(char *sensorsString)
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 registerChain_mainModule(String classType, int buttonNumber, int pressKind, String setString, String valString, String deviceString)
void togglePreferenceBoolean_mainModule(int preferenceID)
toggles a preference boolean
char * getPreferenceATOMKind_MainModule()
new 1.4.24 setting ATOM kind (eg. M5AtomSocket, M5AtomScanner)
void savePreferenceFloat_mainModule(int preferenceID, float val)
called to set a preference (which will be an identifier and a string, which can be converted to a num...
int getM5ATOMKind_MainModule()
new 1.4.24 setting ATOM kind (eg. ATOM_KIND_M5_SCANNER, ATOM_KIND_M5_SOCKET)
int getPreferenceInt_mainModule(int preferenceID)
called to set a preference (which will be an identifier and a string, which can be converted to a num...
char * getPreference_mainModule(int preferenceID)
SensorStruct * getSensor_mainModule(char *sensorName)
return the sensor specified or null
char * getPreferenceString_mainModule(int preferenceID)
returns the preference but in it's own string buffer. As long as you use it before calling getPrefere...
void printPreferenceValues_mainModule()
print the preferences to SerialDebug
void savePreference_mainModule(int preferenceID, String preferenceValue)
called to set a preference (which will be an identifier and a string, which can be converted to a num...
#define PREFERENCE_USE_SPIFF_SETTING
8.22.22 to turn on/off SPIFF use (more below..)
#define PREFERENCE_PAIRED_DEVICE_ADDRESS_SETTING
the paired device for guest device feeding (6.6.22) .. but the Address 9.3.22
#define PREFERENCE_STEPPER_KIND_VALUE
uses STEPPER type
#define PREFERENCE_SENSOR_TILT_VALUE
Sensor preferences.
#define PREFERENCE_SENSOR_PLUGS_SETTING
#define PREFERENCE_STEPPER_FACTORY_CLOCKWISE_MOTOR_DIRECTION_SETTING
#define PREFERENCE_BLE_SERVER_USE_DEVICE_NAME_SETTING
if set, the BLE Server (like PTFeeder) will tack on the device name (or none if not defined).
#define PREFERENCE_ONLY_GEN3_CONNECT_SETTING
if true, only BLEClient connect to GEN3 feeders..
#define PREFERENCE_SENDWIFI_WITH_BLE
sends the WIFI to all except current device if set
#define PREFERENCE_SEMANTIC_MARKER_ZOOMED_VALUE
Display preferences (SemanticMarker etc) - boolean.
#define PREFERENCE_STEPPER_JACKPOT_FEED_VALUE
#define PREFERENCE_WIFI_CREDENTIAL_2_SETTING
#define PREFERENCE_STEPPER_RPM_SETTING
#define PREFERENCE_MAIN_BLE_SERVER_VALUE
#define PREFERENCE_PAIRED_DEVICE_SETTING
the paired device for guest device feeding (6.6.22)
#define PREFERENCE_STEPPER_BUZZER_VALUE
stepper preferences
#define STEPPER_IS_TUMBLER
#define PREFERENCE_BLE_USE_DISCOVERED_PAIRED_DEVICE_SETTING
#define PREFERENCE_WIFI_CREDENTIAL_1_SETTING
#define PREFERENCE_USE_SPIFF_MQTT_SETTING
#define PREFERENCE_CHAIN_SENSORS_SETTING
#define STEPPER_IS_UNO
#define WIFI_CREDENTIALS_MAX
for now, save 2 WIFI Credentials
#define BUTTON_SHORT_PRESS
#define PREFERENCE_FIRST_TIME_FEATURE_SETTING
a firsttime feature flag (only 1 per build) 7.12.22 defaulting to TRUE
#define PREFERENCE_IS_MINIMAL_MENU_SETTING
sets the max temp for a poweroff
#define STEPPER_IS_MINI
#define PREFERENCE_USE_SPIFF_QRATOM_SETTING
For MQTT writing to the QRATOM.
#define PREFERENCE_DEVICE_NAME_SETTING
the device name itself (6.6.22)
#define PREFERENCE_HIGH_TEMP_POWEROFF_VALUE
sets the max temp for a poweroff
#define PREFERENCE_STEPPER_ANGLE_FLOAT_SETTING
#define BUTTON_LONG_PRESS
#define PREFERENCE_STEPPER_2FEED_SETTING
#define PREFERENCE_STEPPER_AUTO_MOTOR_DIRECTION_SETTING
#define PREFERENCE_MAIN_GATEWAY_VALUE
#define PREFERENCE_STEPPER_CLOCKWISE_MOTOR_DIRECTION_SETTING
#define PREFERENCE_MAIN_BLE_CLIENT_VALUE
#define PREFERENCE_ATOM_KIND_SETTING
1.4.24 What kind of ATOM plug (set, M5AtomKind, val= {M5AtomSocket, M5AtomScanner}
void sendStrings_SPIFFModule(int numberOfLines)
sends SPIFF module strings over MQTT, starting at the number back specified. This will use the curren...
void printFile_SPIFFModule()
prints the spiff file to the SerialDebug output
void deleteFiles_SPIFFModule()
delete the spiff files..
@ SensorClassType
@ ChainButtonClassType
void stepperModule_ProcessClientCmdFinal(char cmd)
the Blink the LED - and it will use the latest BUZZER status (so MQTT could set buzzer on....
void setup_tokenParser_mainModule()
setup a test ..
char * semanticMarkerToJSON_TokenParser(char *semanticMarker)
void blinkLED_UIModule()
blink the LED
Definition: UI.cpp:23
void solidLightOnOff_UIModule(boolean onOff)
turns on/off a solid light
Definition: UI.cpp:20
void clean_SSID_WIFICredentials()
returns true if the SSID is set, false otherwise. If set, then just exit..
void WIFI_APModule_updateMQTTInfo(char *ssid, char *ssid_password, char *username, char *password, char *guestPassword, char *deviceName, char *host, char *port, char *locationString)
sets the MQTT user/password. It's up to the code to decide who needs to know
boolean doneWIFI_APModule_Credentials()
called to see if the WIFIModule has finished bootstrapping..
void cleanEPROM_WIFI_APModule()
cleans the eprom info
void setDoneWIFI_APModuleFlag(boolean flag)
called to set the done flag
void setup()
Pure Virtual Function.
An concrete class.
An mostly virtual class.
virtual void messageSend_M5AtomClassType(char *sendValue, boolean deviceNameSpecified)=0
virtual void loop_M5AtomClassType()=0
loop the PTStepper (so timer can run)
virtual boolean isPTFeeder_M5AtomClassType()
virtual void buttonA_ShortPress_M5AtomClassType()=0
virtual char * currentStatusJSON_M5AtomClassType()=0
virtual void buttonA_LongPress_M5AtomClassType()=0
long press on buttonA (top button)
virtual void messageSetVal_M5AtomClassType(char *setName, char *valValue, boolean deviceNameSpecified)=0
these are from the ATOM
virtual void setup_M5AtomClassType()=0
setup the PTStepper
virtual void stop_M5AtomClassType()=0
stop the motor
virtual char * currentStatusURL_M5AtomClassType()=0
virtual void buttonA_LongLongPress_M5AtomClassType()
11.25.25 Add LONG LONG press for the AP mode
void setup()
Pure Virtual Function.
virtual void loop()=0
Pure Virtual Function.
virtual Type type() const
void setPinValues(int pin1, int pin2)
virtual void messageSetVal_SensorClassType(char *setName, char *valValue, boolean deviceNameSpecified)
virtual void setup()=0
Pure Virtual Function.
virtual void messageLocal_SensorClassType(char *message)
5.15.25 try a special command local to this class
long pinNumArray[PIN_USE_MAX]
each pin
Definition: MainModule.h:507
char * pinUseArray[PIN_USE_MAX]
string describing the module, etc
Definition: MainModule.h:505
SensorClassType * sensorClassType
and the pointer to matching SensorClassType
SensorStruct * sensors
array of sensorStruct