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;
36
37//! 8.11.26 have B (the top of the display button on M5AtomS3
38//! 10.16.25 add buttons
40boolean _longPressB_MainModule = false;
43
44//!big button on front of M5StickC Plus
46//! buttonB will set the _shortPressB .. fields
48
49//! instances of the M5AtomClassType
50#pragma mark M5AtomClassType
51
52//1
54//2
56//3
58//4
60//! 7.17.25 - Adding GPS
61//! 5
63//! 8.16.25 bring in the CameraModule from 2022
64//! 6
66//! 10.26.25 Power Out .. Wind Storm. Generator Running
67//! add a NoModule class
69
70//! make sure this is updated.
71//! 8.16.25 == 6
72//! 10.26.25 == 7
73#define NUM_M5ATOM_CLASS 7
74
75//! 3.31.25 create array of plugs
77
78//! use this one...
80
81#endif //USE_NEW_M5ATOMCLASS
82
83#pragma mark SensorClassType
84
85#ifdef ESP_M5_ATOM_S3
86//! 7.12.26 Ashton's 12th birthday in Hawaii
87//! M5AtomS3 working .. now add more ...
88#define USE_SENSOR_CLASS
89// blowing up at ChainButtonClass::setup(19.22) ... PINS are now:
90// blowing up at ChainButtonClass::setup(6,5) BLOWING STILL ... PINS are now:
91
92#else
93#define USE_SENSOR_CLASS
94#endif
95#ifdef USE_SENSOR_CLASS
96//! 5.14.25
97#include "../SensorClass/SensorClassType.h"
98#include "../SensorClass/BuzzerSensorClass.h"
99#include "../SensorClass/KeyUnitSensorClass.h"
100//! 11.27.25 add PIRSensor
101#include "../SensorClass/PIRSensorClass.h"
102//! 12.19.25 48 hrs no power, high wind storm, flooding in lowlands - bad
103//! this will be the ChainButtonClass
104#include "../SensorClass/ChainButtonClassType.h"
105
106#define NUM_SENSOR_CLASS_TYPES 4
107//!
109//2
111//3
113//4
115
116//! 11.28.25 Clear day, M5 Out
117//! create array of instances POSSIBLE (the Sensors, pin1,pin2 -- will instantiate them)
119
120//! 11.27.25 Turkey Day, loop
122{
123 //return; //! 11.28.25 inifinite loop when using a sensor is defined, but no instance created, eg StepperMotor ..
124
125 //! return the sensor specified or null
127 //SerialDebug.printf(" *** loopSensorClassTypeArray (%ld) ***\n", sensorsStruct?sensorsStruct->count:-1);
128#define SERIAL_LOTS_
129#ifdef SERIAL_LOTS
130 //! try a debug print..
132#endif
133
134 if (sensorsStruct)
135 {
136 //printSensors_mainModule(sensorsStruct);
137
138 //! all the sensors defined
139 //! sensors is an array of sensor
141 int count = sensorsStruct->count;
142
143 //! go through the defined sensorName and call loop on those classes
144 for (int i=0; i< count; i++)
145 {
146 //! this only works if there is an instance there of value .. the NULL doesn't work
147 //! as this is a memory location somethwere.
148 //! so the instantiator will now create a DUMMY SensorClass object .. so this works.
149 //! The issue is there can be a sensor that doesn't exist so that slot is empty .. but the &sensors[i] BLOWS up
150 SensorStruct* sensor = &sensors[i];
151 //SerialTemp.printf("sensor = %d\n", sensor);
152
153 //! 11.28.25 KLUDGE .. for now only this sensor has a loop
154 // if (strcmp(sensor->sensorName, (char*)"PIRSensorClass")==0)
155 //! check sensor exists ..
156 if (sensor)
157 {
158 //check this??? PIR HAT only one so far that needs this ...
159 sensor->sensorClassType->loop();
160 }
161 }
162
163 }
164}
165
166//! 1.24.26 send the setval of the MQTT message ..TODO
167//! 11.27.25 Turkey Day, loop
168void messageSetVal_SensorClassTypeArray(char *setName, char* valValue, boolean deviceNameSpecified)
169{
170 //return; //! 11.28.25 inifinite loop when using a sensor is defined, but no instance created, eg StepperMotor ..
171
172 //! return the sensor specified or null
174 if (sensorsStruct)
175 {
176 //! all the sensors defined
177 //! sensors is an array of sensor
179 int count = sensorsStruct->count;
180
181 //! go through the defined sensorName and call loop on those classes
182 for (int i=0; i< count; i++)
183 {
184 //! this only works if there is an instance there of value .. the NULL doesn't work
185 //! as this is a memory location somethwere.
186 //! so the instantiator will now create a DUMMY SensorClass object .. so this works.
187 //! The issue is there can be a sensor that doesn't exist so that slot is empty .. but the &sensors[i] BLOWS up
188 SensorStruct* sensor = &sensors[i];
189
190 //! check sensor exists ..
191 if (sensor)
192 {
193 SensorClassType *sensorClassType = sensor->sensorClassType;
194 if (sensorClassType)
195 //! forward the message
196 sensorClassType->messageSetVal_SensorClassType(setName, valValue, deviceNameSpecified);
197 }
198 }
199 }
200}
201
202//! init will look at those SensorClass known above, and look
203//! to see which ones are defined by the user in the SensorsStruct
204//! A report will show which ones were not found
206{
207 SerialDebug.println(" *** initSensorClassTypeArray ***");
208
209 //! create possible Sensor class instan ces
210 //! 11.28.25
211 //! use the class name as identity()
212 _BuzzerSensorClass = new BuzzerSensorClass((char*)"BuzzerSensorClass");
213 _KeyUnitSensorClass = new KeyUnitSensorClass((char*)"KeyUnitSensorClass");
214 _PIRSensorClass = new PIRSensorClass((char*)"PIRSensorClass");
215 //! 12.19.25 add Class type for Chain
216 _ChainButtonClass = new ChainButtonClass((char*)"ChainButtonClass");
217
218 //! 11.28.25 Clear day, M5 Out
219 //! create array of instances POSSIBLE (the Sensors, pin1,pin2 -- will instantiate them)
221
222 int whichSensorClassIndex = 0;
223 SerialDebug.println("setup_SensorClassIypes");
224
225 //! 11.28.25 create array of Sensors
226 _SensorClassTypes[whichSensorClassIndex++] = _BuzzerSensorClass;
227 _SensorClassTypes[whichSensorClassIndex++] = _KeyUnitSensorClass;
228 _SensorClassTypes[whichSensorClassIndex++] = _PIRSensorClass;
229 //! 12.19.25 add ChainButtonClass
230 _SensorClassTypes[whichSensorClassIndex++] = _ChainButtonClass;
231
232 //! add check..
233 if (whichSensorClassIndex > NUM_SENSOR_CLASS_TYPES)
234 {
235 SerialDebug.printf("**** sensors are more than max .. FIX CODE");
236 }
237 SerialDebug.printf("Created %d SensorClassTypes\n", whichSensorClassIndex);
238
239
240 //! return the sensor specified or null
242 if (sensorsStruct)
243 {
244 //! all the sensors defined
245 //! sensors is an array of sensor
247 int count = sensorsStruct->count;
248
249 //! 11.28.25 use the SensorClassType (like the M5AtomClassType pattern)
250 //! go through the defined sensorName and instantiate those classes
251 for (int i=0; i< count; i++)
252 {
253 SensorStruct* sensor = &sensors[i];
254 SerialDebug.printf("Looking for sensor: %s, %ld, %ld\n", sensor->sensorName, sensor->pin1, sensor->pin2);
255 //! find matching sensor instantiated
256 SensorClassType *whichSensorClassType = NULL;
257 boolean foundMatchingClassType = false;
258 for (int whichSensor=0; whichSensor<NUM_SENSOR_CLASS_TYPES; whichSensor++)
259 {
260 //! look for ths sensor mentioned..
261 whichSensorClassType = _SensorClassTypes[whichSensor];
262 char *sensorIdentity = whichSensorClassType->classIdentity();
263 if (strcmp(sensor->sensorName, sensorIdentity)==0)
264 {
265 //! set the running sensor type for this instnce (currently only 1 per sensor type)
266 sensor->sensorClassType = whichSensorClassType;
267
268 //! call this setup and pin sets
269 //! setup and then setPins..
270 whichSensorClassType->setPinValues(sensor->pin1, sensor->pin2);
271 //! 1.22.26 the Chain will read the button definitions at setup time and loop time
272
273 SerialTemp.printf("sensor.setup(%s) = %d\n", whichSensorClassType->classIdentity(), whichSensorClassType);
274
275 //! call setup
276 whichSensorClassType->setup();
277 //! exit loop
278 foundMatchingClassType = true;
279 break;
280 }
281 }
282
283 if (!foundMatchingClassType)
284 {
285 SerialDebug.printf("Missing SensorClass definition: %s\n", sensor->sensorName);
286 sensor->sensorClassType = NULL;
287 }
288 }
289 //! find missing sensors
290 //! go throug the defined sensorName and instantiate those classes
291 for (int i=0; i< count; i++)
292 {
293 SensorStruct* sensor = &sensors[i];
294 if (!sensor->sensorClassType)
295 {
296 //! missing instance
297 SerialDebug.printf("Missing class definition: %s\n", sensor->sensorName);
299 }
300 }
301 }
302 SerialDebug.println("Finish initSensorClassTypeArray");
303}
304#endif
305
306//! 6.7.25 hot air balloons over house..
307//! stops the motor
309{
312}
313
314//! gets if PTFeeder a surrogate for the M5Atom class
316{
319 else
320 //!Defines the name of the service of the server, which for M5 will be PTClicker
321 {
322 return containsSubstring(MAIN_BLE_SERVER_SERVICE_NAME, "PTFeeder");
323 }
324 /*
325#ifdef ESP_M5
326#define MAIN_BLE_SERVER_SERVICE_NAME (char*)"PTClicker"
327#else
328#define MAIN_BLE_SERVER_SERVICE_NAME (char*)"PTFeeder"
329#endif
330 */
331}
332
333//! 10.10.25 #405 #406
334//! see if the device is a PTClicker if the M5Atom class is one..
335//! return the service name: PTClicker or PTFeeder
337{
339 return MAIN_BLE_SERVER_SERVICE_NAME_PTFeeder;
340 else
341 return MAIN_BLE_SERVER_SERVICE_NAME_PTClicker;
342}
343//! reads the preferences. Save is everytime the savePreference is called
345//!testing..
346boolean _stopAllProcessing = false;
347//!stop all loops... while OTA working..
349{
350 _stopAllProcessing = true;
351}
352//!restart all loops... while OTA working..
354{
355 _stopAllProcessing = false;
356}
357//! if stopped
359{
360 //! try to disconnect..
361 //disconnect_BLEClientNetworking();
362 // return false; //
363 return _stopAllProcessing;
364}
365
366//****** GLOBALS (shows how much memory is allocated.. )
367//!the parameter being sent to those commands passing an argument
369//!global to store credentials when ever they are stored..
371//!global for others to use..
372#define MESSAGE_STORAGE_MAX 500
374//!status string (URL query format)
376//! current smMode
378//! saved deviceName storage..
380
381//!store a big message #MSG_START .. #MSG_END
383char _bigMessage[500];
384//!saved BLE connected name 8.26.22
386//!full: ""Name: PTFeeder:HowieFeeder, Address: 7c:9e:bd:48:af:92, serviceUUID: 0xdead"
388//!full: ""Address: 7c:9e:bd:48:af:92, serviceUUID: 0xdead"
390
391//!init globals strings
393{
394 //!NOTE: this is definitely needed, as grabbing strings willy nilly can bomb or corrupt stuff..
395 strcpy(_connectedBLEDeviceName,(char*)"");
396 strcpy(_bigMessage,(char*)"");
397 strcpy(_deviceNameSave,(char*)"");
398 strcpy(_smMode_MainModule,(char*)"");
399 strcpy(_fullStatusString,(char*)"");
400 strcpy(_messageStorage,(char*)"");
401 strcpy(_JSONStringForWIFICredentials,(char*)"");
402 strcpy(_asyncParameter,(char*)"");
403 strcpy(_fullBLEDeviceName,(char*)"");
404
405 main_setScannedDeviceName((char*)"");
406 //! 1.7.24
407 main_setScannedGroupName((char*)"");
408}
409
410//THIS IS the setup() and loop() but using the "component" name, eg MQTTNetworking()
411//! called from the setup()
413{
414 SerialMin.println("setup_mainModule");
415
416 //! change LED
418
419#ifdef DONE_IN_INO
420 //! 7.9.26 add this. 20 mile bike ride .. felt good
421#ifdef ESP_M5_ATOM_S3
422 espBegin_mainModule(0); //7.26.26 //M5.Begin();
423#else
424 // Init Atom-Matrix(Initialize serial port, LED).
425 //M5.begin(true, false, true);
426 espBegin_mainModule(0); //7.26.26 //M5.Begin();
427#endif
428#endif
429
430#ifdef BOOTSTRAP_CLEAN
431 //!cleans the EPROM .. if things are really not working..
433#endif
434#define TEMP_FIX_LOOP_NO
435#ifdef TEMP_FIX_LOOP
436 setSensorsString_mainModule((char*)"BuzzerSensorClass,21,25");
437#endif
438
439 //test...
440 //! setup for the token parser (really just for testing) -- an
442
443 //!init globals like strings (but nothing that needs preferences)
445
446 //!read the preferences from EPROM
448
449 //!must initialize the structs NOTE: this has to ber AFTER the preferences are read in..
451
452 //!a first time feature .. to get EPROM changed to a different default
454 {
455
456 //!7.12.22
457 //! {'dev':'m5",'cmd':'bleserveron'} or bleserveroff will work later..
458 //!#issue 116 .. turn off the BLE_Server for the M5
459 SerialMin.println("FIRST TIME TURNING off the BLE_SERVER for the M5");
460#ifdef ESP_M5
461
462#ifdef M5_ATOM
463 //! 5.6.25 use object version
465
466#else // not M5_ATOM
467
468 // 8.28.23 .. not doing this anymore..
470
471 //! not ESP_M5
472#endif // M5_ATOM
473#else // NOT ESP_M5
475#endif
476 //! all ..
478 }
479
480#define NEW_SENSORS
481#ifdef USE_SENSOR_CLASS
482 //! 5.14.25 use the Sensor types
483 //! first we have N sensors
484 //! then we get which ones the user wants (the SENSORS_SETTING)
485 //! then we instantiate, and provide ping, etc.
487#endif
488
489#define TRY_DUPLICATES_works //uncomment to try again..
490#ifdef TRY_DUPLICATES
491 {
492 //! 8.32.25 added a test .. the '.' needs to run.. to see the error
493 boolean pinValid = registerPinUse_mainModule(22, "TestPin22", "MainModule", false);
494 pinValid = pinValid && registerPinUse_mainModule(27, "TestPin27", "MainModule", false);
495 if (!pinValid)
496 {
497 SerialError.println("*** invalidPins testing..");
498 }
499 }
500#endif
501
502 SerialDebug.println("END setup_mainModule");
503}
504
505//! main BEGIN and UPDATE .. everyone calls this .. and we can see if dont too many times
506//! 7.26.26
507//! the Beging aggregate
509{
510 SerialDebug.print(" **** ESP BEGIN: ");
511 SerialDebug.println(num);
512
513#ifdef ESP_ATOM_S3
514 Atom.begin();
515#else
516 M5.begin();
517#endif
518 SerialDebug.println(" *** DONE M5.begin");
519}
520//! the Update aggrgate
522{
523 SerialLots.printf("***ESP UPDATE(%d)\n",num);
524#ifdef ESP_ATOM_S3
525 Atom.update();
526#else
527 M5.update();
528#endif
529}
530
531#if defined(ESP_M5_CAMERA) || defined(ESP_32)
532//!a couinter to slow down the loop doing things..
533int _mainLoopCounter = 0;
534#endif
535
536//! storage for reading from the serial buffer
537//! 6.20.25 (Sam Sprague grad Western party)
539
540//! called for the loop() of this plugin
542{
543
544 //! 7.9.26 add this. 20 mile bike ride .. felt good
545#ifdef ESP_M5_ATOM_S3
546 espUpdate_mainModule(0); //AtomS3.update();
547#else
548 espUpdate_mainModule(0); //M5.update();
549#endif
550
551
552#if defined(ESP_M5_CAMERA) || defined(ESP_32)
553 //!only do this menu update if there is no DisplayModule running the MVC loop
554
555 if (_mainLoopCounter++ > 30)
556 {
557 //! 9.2.22 new .. update the timer. This is on blank screen as well .. so don't check _semanticMarkerShown
559
560 _mainLoopCounter = 0;
561 }
562
563#endif
564
565#pragma mark Serial Input Processor
566 //! 6.20.25 works with full code (JSON, or single commands - with '.' as help)
567 //! 6.19.25 Mt Peak finally (kept to 124 bpm)
568 //! Per ##373 let the serial monitor get some input, and let us set a few features
569 //! see if data on the serial input
570 //! Re-indexed and now command completion works!!!!!! 3 years later.
571 //!@see https://developer.apple.com/documentation/corespotlight/regenerating-your-app-s-indexes-on-demand?language=objc
572 if (Serial.available())
573 {
574 // read string until meet newline character
575 String command = Serial.readStringUntil('\n');
576
577 SerialDebug.printf("** SerialCommand: '%s'\n", command);
578 //! save globally for the callback below..
579 strcpy(_serialBuffer, command.c_str());
580
581 if (command == "help")
582 {
583 SerialTemp.println(VERSION);
584
585 SerialDebug.println("Enter any Single Char or JSON msg, type '.' for commands");
586 SerialDebug.println("r -- reboot");
587 SerialDebug.println(". -- shows single char commands");
588 SerialDebug.println("Example JSON to change WIFI (copy and modify with your values)");
589 SerialDebug.println(" supports single quotes for values");
590 SerialDebug.println(" Use to set your WIFI");
591 SerialDebug.println("{'ssid':'SunnyWhiteriver', 'ssidPassword':'sunny2021'}");
592 SerialDebug.println("{'ssid':'wes', 'ssidPassword':'wes'}");
593 SerialDebug.println();
594
595
596 //! 7.23.26 this callback only gets called if the BLE_Server is on.. so let's call it anyway without the callback.
597 //processClientCommandChar_mainModule('.');
598 }
599 else if (command == "r")
600 {
602 }
603 //! 8.10.26 Nice boat trip to Fox Island and Tanglewood
604 //! work on the TEST ideas
605 else if (command == "test1")
606 {
607 // do an ota of test1 ... ???
608 SerialDebug.println(" **** TODO: OTA for test1");
609 }
610 //! 8.11.26 reate test user
611 else if (command == "test")
612 {
613 SerialDebug.println("create TEST user");
614 SerialDebug.println("{'ssid':'SunnyWhiteriver', 'ssidPassword':'sunny2021'}");
615 SerialDebug.println("{'ssid':'wes', 'ssidPassword':'wes'}");
616 /*
617 {
618 "ssid" : "SunnyWhiteriver",
619 "ssidPassword" : "sunny2021",
620 "mqtt_topic": "usersP/bark/test",
621 "mqtt_user" : "test",
622 "deviceName" : "M5AtomTest",
623 "mqtt_password" : "test",
624 "mqtt_guestPassword" : "test",
625 "uuid" : "test",
626 "mqtt_port" : "1883",
627 "mqtt_server" : "idogwatch.com",
628 "mqtt_status" : "Success",
629 "location": "seattle, wa"
630 }
631 */
632 char credentials[400];
633 sprintf(credentials,
634 "{'ssid':'SSID','ssidPassword':'PASS','mqtt_topic':'usersP/bar/test','mqtt_user':'test','deviceName':'M5Atomtest','mqtt_password':'test','mqtt_guestPassword':'test','uuid':'test','mqtt_port':'1883','mqtt_server':'idogwatch.com','location':'Seattle,Wa'}");
635
636
637 //!These are the ASYNC_CALL_PARAMETERS_MAX
638 //!NO: just change our credentials ...
639 //send to ourself.., recursively...
640 int val = processJSONMessageMQTT(credentials, TOPIC_TO_SEND);
641 }
642 else
643 {
644 //! 8.7.26 w laura babe,
645 //! Tyler, if BLEServer is on .. send the serial buffer ..
646 //! if not serial server .. then accept single commands .. and go right there .. basically to turn on the server
648 {
649 //!call the callback specified from the caller (eg. NimBLE_PetTutor_Server .. or others)
651 }
652 else
653 {
654 SerialDebug.println(" *** only single character supported since BLE_Server off, type '#' to turn on");
655 //! 7.23.26 this callback only gets called if the BLE_Server is on.. so let's call it anyway without the callback.
657 }
658
659 }
660 }
661
662#pragma mark button processing
663#ifdef USE_BUTTON_MODULE
664 //! duplicate here for now...
666
667#else
668 //! 10.16.25 add the M5.update here...
669 //! 7.14.26 THIS no-work, cannot do update 2 times.. the butotns won't work.
670 // M5.update();
671
672 //! 10.16.25 Mt out .. looks like storm comming
673 //! implement the buttonA here..
674 //!big button on front of M5StickC Plus
676 //! 10.16.25 seems the big button on M5ATOM is Button B ..
677 //! the LED push button... (WE HAVE TO SUPPORT A,B,C buttons .. )
679 //! now process single button .. merged
681 {
683 }
684 else if (_longPress_MainModule)
685 {
687 }
689 {
690 //! 11.25.25 Cold 30's
691 //! call the long long
693 }
694#endif
695
696#ifdef USE_SENSOR_CLASS
697 //! 11.27.25 Turkey Day, loop
699#endif
700}
701
702
703//! 5.3.22 added a feed count approach.. (NOTE: there is a _feedCount in Dispence.cpp ... and no linker error!!! )
705//!returns the max for this feeder
707{
708 int max = 16;
709 switch (getFeederType_mainModule())
710 {
711 case STEPPER_IS_UNO:
712 max = 16;
713 break;
714 case STEPPER_IS_MINI:
715 max = 55;
716 break;
718 max = 50;
719 break;
720 }
721 return max;
722}
723//!feedcount info..
725{
727}
728
729//!get the feeder type (Sepper 1,2,3 ...)
731{
733 return kind;
734}
735
736//!increments .. and if MAX goes to 0 -- and sends a message on MQTT
738{
739 SerialTemp.println("incrementFeedCount_mainModule");
740
743 {
744 // send a message.
745 //! 8.16.25 MQTT
746 //note needs # or won't send..
747 //!NOTE: don't send "feed" as it might trigger a FEED ...
748 sendMessageMQTT((char*)"#count reached .. resetting");
749
751 }
752
753 //! called by the feed operation to say the device is still running.. and count it as a button click.
754 //! Issue #145 8.8.22
756
757}
758//! sets the feed count max
760{
762}
763
764//!check if the string contains the other string. This is a poor man's grammer checker
765bool containsSubstring(String message, String substring)
766{
767 if (substring.length() == 0 )
768 return false;
769 bool found = strstr(&message[0], &substring[0]);
770 SerialLots.printf("containsSubstring-%d - %s in: %s\n", found, &substring[0], &message[0]);
771 return found;
772}
773
774//! 8.16.25 MQTT
775#include "../MQTTModule/MQTTNetworking.h"
776
777//! 8.16.25 BLE SERVER
778#include "../BLEServerModule/BLEServerNetworking.h"
779
780//! 8.16.25 BLE CLIENT
781#include "../BLEClientModule/BLEClientNetworking.h"
782#ifdef USE_BUTTON_MODULE
783#include "../ButtonModule/ButtonProcessing.h"
784#endif
785
786//! New RegisterCallback that works across a number of callback modules
787//!
788//! callbacksModuleId
789#define CALLBACKS_MQTT 0
790#define CALLBACKS_BUTTON_MODULE 1
791#define CALLBACKS_BLE_CLIENT 2
792#define CALLBACKS_BLE_SERVER 3
793
794
795//!register the callback based on the callbackType. use the callbacksModuleId for which one..
796void registerCallbackMain(int callbacksModuleId, int callbackType, void (*callback)(char*));
797//!performs the indirect callback based on the callbackType
798void callCallbackMain(int callbacksModuleId, int callbackType, char *message);
799
800
801//!make sure these are the number of callbacks.. 0..n
802//! These values are from the respective .h of the modules
803#define CALLBACKS_MAX_MQTT MQTT_MAX_CALLBACKS
804#define CALLBACKS_MAX_BUTTON_MODULE MAX_CALLBACKS_BM
805#define CALLBACKS_MAX_BLE_CLIENT BLE_CLIENT_MAX_CALLBACKS
806#define CALLBACKS_MAX_BLE_SERVER BLE_SERVER_MAX_CALLBACKS
807
808
809//!example callback
810void dummyCallbackMain(char *message)
811{
812 SerialLots.printf("No callback defined .. %s\n", message);
813}
814
815//tricky getting array of arrays (or pointers to arrays), without dynamic memory.. we are going to use calloc()
816//https://www.geeksforgeeks.org/dynamic-memory-allocation-in-c-using-malloc-calloc-free-and-realloc/
817//https://www.tutorialspoint.com/cprogramming/c_pointer_to_pointer.htm
818//https://stackoverflow.com/questions/5573302/pointer-to-an-array-of-function-pointers
819//!the array of callback functions
820//* this means there are arrays of N pointers to functions that take 1 parameter (char*).
821
822
823//! the max of each module .. hard coded (or 0 if module not there)
825
826//!flag for initializing if not yes
828
829//a pointer to a callback function that takes (char*) and returns void
830typedef void (*callbackSignature)(char *);
831//callbackSignature fpar[2] = {&dummyCallbackMain, &dummyCallbackMain};
832
833//!return dyamically created array of max
835{
836 SerialLots.printf("creatingCallbacks %d size: %d\n", max, sizeof(callbackSignature *));
837 callbackSignature *callbackArray = (callbackSignature *)calloc(max,sizeof(callbackSignature *));
838 for (int i=0; i< max; i++)
839 {
840 callbackArray[i] = &dummyCallbackMain;
841 }
842 return callbackArray;
843}
844//!array of known size (CALLBACKS_MODULE_MAX) of callbackSignatures
846
847//!init the callbacks to dummy callbacks
849{
851 {
853
854 // default to 0 callbacks.. in case module not there..
855 for (int i = 0; i < CALLBACKS_MODULE_MAX; i++)
856 {
858 }
859 //! only place for #ifdef (NOTE some can be 0 based on the #ifdef module not being included..
860 //! 8.16.25 MQTT
862 //! 8.16.25 BLE SERVER
864 //! 8.16.25 BLE CLIENT
866#ifdef USE_BUTTON_MODULE
868#endif
869 // initialize the dummy callbacks
870 for (int i = 0; i < CALLBACKS_MODULE_MAX; i++)
871 {
872 //first determine how many are in the array..
873 int max = _callbacksFunctionsMAXS[i];
874 //then create the space which are (void *) pointers
875 _allCallbacks[i] = createMemory(max);
876 }
877 }
878}
879
880//!register the callback based on the callbackType. use the callbacksModuleId for which one..
881void registerCallbackMain(int callbacksModuleId, int callbackType, void (*callback)(char*))
882{
883 SerialLots.printf("registerCallbackMain %d, %d\n", callbacksModuleId, callbackType);
884
885 //init if not already..
887 int max = _callbacksFunctionsMAXS[callbacksModuleId];
888
889 if (callbackType < 0 || callbackType >= max)
890 {
891 SerialError.printf("#### Error outside callback range - 1, %d\n", callbackType);
892 }
893 else
894 {
895 // array of arrays (or array of pointer to another array)
896 _allCallbacks[callbacksModuleId][callbackType] = callback;
897 }
898}
899//!performs the indirect callback based on the callbackType
900void callCallbackMain(int callbacksModuleId, int callbackType, char *message)
901{
902 //init if not already..
904 int max = _callbacksFunctionsMAXS[callbacksModuleId];
905
906 if (callbackType < 0 || callbackType >= max)
907 {
908 SerialError.printf("#### Error outside callback range - 2, %d\n", callbackType);
909
910 }
911 else {
912 void (*callbackFunction)(char *) = _allCallbacks[callbacksModuleId][callbackType];
913 (*callbackFunction)(message);
914 }
915}
916
917//!whether the string is TRUE, ON, 1
918boolean isTrueString_mainModule(String valCmdString)
919{
920 return valCmdString.equalsIgnoreCase("on") ||
921 valCmdString.equalsIgnoreCase("1") ||
922 valCmdString.equalsIgnoreCase("true");
923};
924
925//! 8.28.23 Adding a way for others to get informed on messages that arrive
926//! for the set,val
927//! 1.10.24 if deviceNameSpecified then this matches this device, otherwise for all.
928//! It's up to the receiver to decide if it has to be specified
929void messageSetVal_mainModule(char *setName, char* valValue, boolean deviceNameSpecified)
930{
931 SerialTemp.printf("messageSetVal(%s,%s)\n", setName, valValue);
932 // THE IDEA WOULD be a callback is avaialble..
933 //FOR now.. just ifdef
934#ifdef M5_ATOM
935 //! 5.6.25 use object version
937 _whichM5AtomClassType->messageSetVal_M5AtomClassType(setName, valValue, deviceNameSpecified);
938
939#ifdef USE_SENSOR_CLASS
940 //! 1.24.26 call the same on the SensorClassType
941 messageSetVal_SensorClassTypeArray(setName, valValue, deviceNameSpecified);
942#endif
943
944#endif //M5_ATOM
945
946#ifdef M5CORE2_MODULE
947 //! TODO fix this
948 messageSetVal_M5Core2Module(setName, valValue, deviceNameSpecified);
949#endif
950}
951//!TODO: have a callback regist approach
952
953//! 12.28.23, 8.28.23 Adding a way for others to get informed on messages that arrive
954//! for the set,val
955//! 5.21.25 SEND and CMD will be treated the same and put to "send"
956void messageSend_mainModule(char *sendValue, boolean deviceNameSpecified)
957{
958//! 5.21.25 this will overlap with the "cmd" .. so send == cmd
959#ifdef M5_ATOM
960#pragma mark USE_NEW_M5ATOMCLASS
961
962 //! 5.6.25 use object version
964 _whichM5AtomClassType->messageSend_M5AtomClassType(sendValue, deviceNameSpecified);
965
966#endif //M5_ATOM
967
968#ifdef M5CORE2_MODULE
969 //! TODO FIX THIS
970 messageSend_M5Core2Module(sendValue);
971#endif
972}
973
974//! 8.16.25 MQTT
975//!example callback: but the scope would have the pCharacteristic defined, etc..
976//!This is passed just before the setupMQTTNetworking() is called..
977void feedMessageCallback(char *message)
978{
979 SerialTemp.print("feedMessageCallback_main: ");
980 SerialTemp.println(message);
981 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)
982 //!sends this single character to the StepperModule
984
985 //!increment the feed count .. TODO .. see if this is good place..
986// incrementFeedCount_mainModule();
987
988 //!the FEED was send over MQTT, now what to do?
989 //! WIth the StepperModule -- it just performs the feeding internalls
990 //! if using the BLE_CLIENT then we have the potential to send to over BLE
991 //! to the server (another feeder, GEN3 or ESP32).
992 //! The issue is that ESP32 feeders are receiving the same MQTT message (usually unless MQTT turned off
993 //! So the gatewayMode can be set (or in the EPROM) using {'cmd':'gatewayOn'}
995 {
996 //! 8.16.25 BLE CLIENT
997
998 SerialTemp.print("Paired Device: ");
1000
1001 SerialTemp.printf("Gateway: Feeding over the BLE CLIENT network .. if connected: %d\n",isConnectedBLEClient());
1003 {
1004 //!send the feed over the BLE client (if connected)
1006 }
1007 SerialLots.println("after send feed via ble");
1008 }
1009
1010#ifdef TOO_MUCH_7_10_26
1011 //! 11.26.25 try the #STATUS on every feed
1012 SerialDebug.println("FEED now send STATUS");
1013 sendMessageMQTT((char*)"#STATUS");
1014#endif
1015}
1016
1017//!moved here 4.25.22 (entirely from ESP_IOT.ino)
1018
1019//! April 8, 2022
1020//! set that the credentials are set. Called from the MQTT after processJSONMessage() found things were good..
1022{
1023 // set the done in the WI
1024 SerialDebug.println(" *** main_credentialsUpdated .. setDoneWIFI_APModuleFlag **");
1025 //! 8.16.25 WIFI AP
1027}
1028//NOTE: #else not there so this won't link.. on purpose
1029
1030/*******************************BLE Server*************************************/
1031//!The callback for "onWrite" of the bluetooth "onWrite'
1032void onBLEServerCallback(char *message)
1033{
1034 SerialCall.print("onWriteBLEServerCallback: ");
1035 SerialCall.println(message);
1036
1037}
1038//! The callback for "status messages" of the bluetooth
1040{
1041 SerialCall.print("onStatusMessageBLEServerCallback");
1042 SerialCall.print(message);
1043 //! 2.2.22 send this over bluetooth.. TODO.
1044 //
1045}
1046
1047//! The FINISH of callback for "onWrite" of the bluetooth "onWrite'
1049{
1050
1051 SerialDebug.print("onWriteBLEServerCallback_main: ");
1052 SerialDebug.println(message);
1053
1054 //!client never sends these wrapped messages of length 1, so process normally..
1055 //!gets us out of potential infinite wait
1056 if (strlen(message) == 1)
1058
1059 if (strcmp(message, "#MSG_START")==0)
1060 {
1062 strcpy(_bigMessage,"");
1063 return;
1064 }
1065 else if (_waitingForBigMessageEnd)
1066 {
1067 if (strcmp(message, "#MSG_END")==0)
1068 {
1070 //! we are done.. send big message to ourself..
1072 }
1073 else
1074 {
1075 strcat(_bigMessage,message);
1076 return;
1077 }
1078 }
1080
1081 //!Issue: the message is arriving via BLE, but if we call the MQTT process, it might call us back to send
1082 //!the message over BLE. This hangs things up!
1083 //!So short optimization for 'feed' will be to look for cmd and feed in message {cmd:feed}
1084 //!8.19.22 issue #162
1085 if (containsSubstring(message,"cmd"))
1086 {
1087 if (containsSubstring(message,"feed"))
1088 {
1089 message = (char*)"s";
1090 }
1091 else if (containsSubstring(message,"buzzOn"))
1092 {
1093 message = (char*)"B";
1094 }
1095 else if (containsSubstring(message,"buzzOff"))
1096 {
1097 message = (char*)"b";
1098 }
1099
1100 }
1101
1102 //! 8.16.25 MQTT
1103 //This should be a 'register' command..
1104
1105 //!the MQTTNetwork.processJSONMessage()
1106 //!will return true if the message was JSON and was processes, false otherwise.
1107 if (processJSONMessageMQTT(message, NULL))
1108 {
1109 //!processed by the MQTTNetworking code..
1110 //! 8.16.25 BLE SERVER
1112 //pCharacteristic->setValue(0x01); //?? This is the acknowlege(ACK) back to client. Later this should be contigent on a feed completed
1113 }
1114 else
1115 {
1116 //!perform feed...
1117 SerialDebug.printf("Perform BLE Command '%s'\n", message);
1118
1119 char cmd = message[0];
1120
1121 //OOOPS.. we need the ProcessClientCmd .. for other than just step..
1122 // for sensors..
1123
1124 //!look for ** sensor commands..
1126
1127 //! 8.16.25 BLE SERVER
1129
1130 }
1131 SerialDebug.println("*********");
1132
1133} //onWriteBLEServerCallback
1134
1135//! The callback for "onWrite" of the bluetooth "onWrite'
1136void onWriteBLEServerCallback(char *message)
1137{
1138 //TEST:
1139#define TRY_ASYNC_BLE_PROCESSING
1140#ifdef TRY_ASYNC_BLE_PROCESSING
1141
1142 //!send an async call with a string parameter. This will set store the value and then async call the command (passing the parameter)
1143 //!These are the ASYNC_CALL_PARAMETERS_MAX
1145#else
1146
1147 //! The callback for "onWrite" of the bluetooth "onWrite'
1148 onWriteBLEServerCallbackFinish(char *message);
1149#endif
1150}
1151
1152//! called by the feed operation to say the device is still running.. and count it as a button click.
1154{
1155#ifdef USE_BUTTON_MODULE
1156 //!calls the button processing control
1157 refreshDelayButtonTouched_ButtonProcessing();
1158#endif
1159}
1160//! 3.28.22 .. implemented in ESP_IOT.ino
1162//!performs an async OTA update
1164{
1166}
1167//!sets the async OTA flag (for next loop)
1169{
1171}
1172
1173//!returns if the paired device is not NONE
1175{
1177}
1178
1179//!returns if the paired device is not NONE
1181{
1183
1184}
1185//!returns if the paired device is not NONE. Note, the paired Name might be an address now (see below)
1187{
1188 char *pairedDevice = getPairedDevice_mainModule();
1189 //new: now if non ""
1190 //return strcmp(pairedDevice,"NONE")!= 0;
1191 boolean isValid = pairedDevice && strlen(pairedDevice)>0 && strcmp(pairedDevice,"NONE")!= 0;
1192 if (!isValid)
1193 {
1194 char *pairedDeviceAddress = getPairedDeviceAddress_mainModule();
1195 isValid = pairedDeviceAddress && strlen(pairedDeviceAddress)>0 && strcmp(pairedDeviceAddress,"NONE")!= 0;
1196 SerialLots.printf("isValidDeviceAddress(%s,%d)\n", pairedDeviceAddress?pairedDeviceAddress:(char*)"NULL", isValid);
1197 }
1198 SerialLots.printf("isValidPairedDevice_mainModule(%s,%d)\n", pairedDevice?pairedDevice:(char*)"NULL", isValid);
1199 return isValid;
1200}
1201
1202//**** dang.. the getPreference reuses the same storage!! ****
1203
1204//!returns if the paired device is not NONE .. returns address or device
1206{
1207 char *pairedDevice = getPairedDevice_mainModule();
1208 if (pairedDevice && strlen(pairedDevice)>0 && strcmp(pairedDevice,"NONE")!= 0)
1209 {
1210 SerialLots.printf("getPairedDeviceOrAddress_mainModule(%s)\n", pairedDevice);
1211 return pairedDevice;
1212 }
1213 char *pairedDeviceAddress = getPairedDeviceAddress_mainModule();
1214 if (pairedDeviceAddress && strlen(pairedDeviceAddress)>0 && strcmp(pairedDeviceAddress,"NONE")!= 0)
1215 {
1216 SerialLots.printf("getPairedDeviceOrAddress_mainModule(%s)\n", pairedDeviceAddress);
1217 return pairedDeviceAddress;
1218 }
1219 else
1220 return (char*)"";
1221}
1222
1223//!gets the device name
1225{
1227 strcpy(_deviceNameSave,deviceName);
1228 return _deviceNameSave;
1229}
1230
1231//!power of devices
1232//!reboot
1234{
1235 //reboot
1236 ESP.restart();
1237}
1238
1239//!power off
1241{
1242#ifdef ESP_M5
1243 //SerialTemp.println(" **** THIS WOULD BE A POWEROFF ***");
1244 SerialTemp.println(" **** POWEROFF ***");
1245
1246#ifndef ESP_M5_CAMERA
1247#ifndef M5STICKCPLUS2
1248
1249#ifndef ESP_M5_ATOM_S3
1250
1251#ifdef M5UNIFIED
1252 //! 6.5.26
1253#else
1254 M5.Axp.PowerOff();
1255#endif
1256#endif
1257#endif
1258#endif
1259
1260#endif
1261}
1262// ******************* Preference Cleaning ************
1263
1264//!cleans the EPROM
1266{
1267 SerialDebug.println("CLEANING EPROM PREFERENCES");
1268
1269 //4.17.22
1271
1272 //! 8.16.25 MQTT
1274
1275 //! 8.16.25 WIFI AP
1277 //! 7.29.25 set the FIRST time ..
1279
1280 SerialDebug.println("REBOOTING...");
1281
1282 //!reboot
1284
1285}
1286
1287
1288//!retrieve a JSON string for the ssid and ssid_password: {'ssid':<ssid>,'ssidPassword':<pass>"}
1290{
1292}
1293
1294//!! cycle through the next WIFI saved credential
1296{
1297
1298 SerialTemp.printf("WIFI_CREDENTIAL_1: %s\n", getPreference_mainModule(PREFERENCE_WIFI_CREDENTIAL_1_SETTING));
1299 SerialTemp.printf("WIFI_CREDENTIAL_2: %s\n", getPreference_mainModule(PREFERENCE_WIFI_CREDENTIAL_2_SETTING));
1300
1301 //! WIFI_CREDENTIALS_MAX
1303 {
1304 char* credential = getPreference_mainModule(i);
1305 //!jump out of loop if no match.. so index is valid
1306 if (strcmp(credential,"NONE")==0)
1307 continue;
1308 if (strcmp(credential,_JSONStringForWIFICredentials)!= 0)
1309 {
1310 SerialTemp.print("main_nextJSONWIFICredential:");
1311 SerialTemp.println(credential);
1312 return credential;
1313
1314 }
1315 }
1316 SerialTemp.print("main_nextJSONWIFICredential:");
1317 SerialTemp.println(main_JSONStringForWIFICredentials());
1319}
1320
1321//!save the WIFI credential
1322void main_saveWIFICredentials(char *ssid, char *ssid_password)
1323{
1324 //!store the JSON version of these credentials..
1325 sprintf(_JSONStringForWIFICredentials, "{'ssid':'%s','ssidPassword':'%s'}", ssid?ssid:"NULL", ssid_password?ssid_password:"");
1326 SerialMin.print("main_saveWIFICredentials");
1327 SerialMin.println(_JSONStringForWIFICredentials);
1328
1329 //!look for an non matching slot.. if none, then use the first
1332 {
1333 char* credential = getPreference_mainModule(index);
1334 //!jump out of loop if no match.. so index is valid, or NONE (which is the placeholder)
1335 if (strcmp(credential,"NONE")==0)
1336 break;;
1337 if (strcmp(credential,_JSONStringForWIFICredentials)== 0)
1338 {
1339 break;
1340 }
1341 }
1342
1345
1346 SerialDebug.println(_JSONStringForWIFICredentials);
1347 //!save in chosen index
1349}
1350
1351//!clean the saved WIFI credential, otherwise the AP mode doesn't work (6.3.22)
1353{
1354 SerialMin.println("main_cleanSavedWIFICredentials");
1355
1356 //!go through the saved WIFI credentials and empty them with "" (vs null)
1359 {
1360 //!cannot null but can make stringlen=0
1361 savePreference_mainModule(index,"");
1362 }
1363}
1364
1365//! 12.14.23
1366char *_MQTT_Password = (char*)"";
1367char *_MQTT_Username = (char*)"";
1370
1371//! return the username and password
1372//! 12.14.23 to support calling the SMART buttons (smrun) with parameters
1374{
1375 return _MQTT_Username;
1376}
1377
1378//! return password
1380{
1381 return _MQTT_Password;
1382}
1383
1384//! return devicename
1386{
1387 SerialDebug.printf("main_getScannedDeviceName(%s)\n", _scannedDeviceName);
1388
1389 return _scannedDeviceName;
1390}
1391//! set the scanned device name
1392void main_setScannedDeviceName(char *deviceName)
1393{
1394 strcpy(_scannedDeviceName, deviceName);
1395 SerialDebug.printf("main_setScannedDeviceName(%s)\n", deviceName);
1396}
1397
1398//! set the scanned group name
1399//! 1.7.24
1400void main_setScannedGroupName(char *groupName)
1401{
1402 SerialDebug.printf("main_setScannedGroupName(%s)\n", groupName);
1403
1404 if (groupName && strlen(groupName)>0)
1405 {
1406 char *groupTopic = groupTopicFullName(groupName);
1408 }
1409 else
1410 strcpy(_scannedGroupTopicName, "");
1411}
1412//! return groupname -- returns "" or nil if not set,
1413//! or the FULL group name topic, or nil
1415{
1417 {
1418 SerialDebug.printf("main_getScannedGroupNameTopic(%s)\n", _scannedGroupTopicName);
1420
1421 }
1422 return NULL;
1423}
1424
1425//! 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
1426void main_updateMQTTInfo(char *ssid, char *ssid_password, char *username, char *password, char *guestPassword, char *deviceName, char * host, char * port, char *locationString)
1427{
1428 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");
1429
1430 _MQTT_Password = password;
1431 _MQTT_Username = username;
1432
1433 //!store the device name
1435
1436 //!store the JSON version of these credentials..
1437 main_saveWIFICredentials(ssid,ssid_password);
1438
1439 //! 8.16.25 WIFI AP
1440 WIFI_APModule_updateMQTTInfo(ssid, ssid_password, username, password, guestPassword, deviceName, host, port, locationString);
1441}
1442
1443//! 5.16.25 Fountainhead, Raining cold weekend
1444//! start SYNC calls starting with the SYNC_CLICK_SOUND
1445//#define SYNC_CLICK_SOUND 0
1446//#define SYNC_CALL_MAX 1
1447//! the main sync command (no parameters yet)
1448void main_dispatchSyncCommand(int syncCallCommand)
1449{
1450 switch (syncCallCommand)
1451 {
1452 case SYNC_CLICK_SOUND:
1453 {
1455 {
1456 //! 5.15.25 see if the Buzzer class is defined .. if so, then call local message
1457 SensorStruct* buzzerSensor = getSensor_mainModule((char*)"BuzzerSensorClass");
1458
1459 //!perform the click sound..
1460 //!this will be the sensors...
1461 if (buzzerSensor)
1462 {
1463 buzzerSensor->sensorClassType->messageLocal_SensorClassType((char*)"click");
1464 }
1465 else
1466 {
1467 SerialDebug.println("NO BuzzerSensorClass defined ..turn off");
1469 }
1470 }
1471 }
1472 break;
1473 }
1474}
1475
1476//! 3.21.22 these are to setup for the next time the main loop() runs to call these commands..
1477//! The implementation is hard coded in the ESP_IO.ino
1478//! TODO: make this a registeration approach
1479//#define ASYNC_CALL_OTA_UPDATE 0
1480//#define ASYNC_CALL_CLEAN_CREDENTIALS 1
1481//#define ASYNC_CALL_MAX 2
1482
1483//!storage for asyncCallCommands
1485//!array of async flags for the different ASYNC_CALl values
1487
1488//!initialize the async call flags (with and without parameters)
1490{
1491 SerialTemp.printf("initAsyncCallFlags(%d,%d)\n", ASYNC_CALL_MAX, ASYNC_CALL_PARAMETERS_MAX);
1492 for (int i = 0; i < ASYNC_CALL_MAX; i++)
1493 {
1494 _asyncCallFlags[i] = false;
1495 }
1496 for (int i = 0; i < ASYNC_CALL_PARAMETERS_MAX; i++)
1497 {
1498 _asyncCallFlagsParameters[i] = false;
1499 }
1500}
1501
1502// ******************* Async Dispatch Processing ************
1503
1504//!checks if any async commands are in 'dispatch' mode, and if so, invokes them, and sets their flag to false
1505
1506//! dispatches a call to the command specified. This is run on the next loop()
1507void main_dispatchAsyncCommand(int asyncCallCommand)
1508{
1509 //! this just sets the flag, it's the next loop that makes the call
1510#ifdef ERROR_CHECKS
1511 if (asyncCallCommand < 0 || asyncCallCommand >= ASYNC_CALL_MAX)
1512 {
1513 SerialError.printf("ERROR: async call out of range: %d\n", asyncCallCommand);
1514 }
1515 else
1516#endif
1517 {
1518 SerialTemp.printf("1.main_dispatchAsyncCommand: %d\n", asyncCallCommand);
1519 _asyncCallFlags[asyncCallCommand] = true;
1520 }
1521}
1522
1523//!send an async call with a string parameter. This will set store the value and then async call the command (passing the parameter)
1524//!These are the ASYNC_CALL_PARAMETERS_MAX
1525void main_dispatchAsyncCommandWithString(int asyncCallCommand, char *parameter)
1526{
1527 //!store in the parameter mailbox
1528 strcpy(_asyncParameter,parameter);
1529 //! this just sets the flag, it's the next loop that makes the call
1530#ifdef ERROR_CHECKS
1531 if (asyncCallCommand < 0 || asyncCallCommand >= ASYNC_CALL_PARAMETERS_MAX)
1532 {
1533 SerialError.printf("ERROR: async call out of range: %d\n", asyncCallCommand);
1534 }
1535 else
1536#endif
1537 {
1538 SerialTemp.print("2.main_dispatchAsyncCommandWithString:");
1539 SerialTemp.print(asyncCallCommand);
1540 SerialTemp.print(": ");
1541 SerialTemp.println(_asyncParameter);
1542 _asyncCallFlagsParameters[asyncCallCommand] = true;
1543
1544 //! 6.15.25 Fathers Day
1545 //! seems issue when a GROVE or other sensor plugged in the main loop isn't working.
1546 //! SO for now, if the command is "r" then do an actual reboot..
1547 if (strlen(_asyncParameter)>1 && _asyncParameter[0] == 'r')
1548 {
1549 SerialDebug.println("SYNC_REBOOT");
1551 }
1552 }
1553}
1554
1555//!checks if any async commands are in 'dispatch' mode, and if so, invokes them, and sets their flag to false
1557{
1558 SerialCall.printf("invokeAsyncCommands(%d)\n", ASYNC_CALL_PARAMETERS_MAX);
1559
1560 for (int i = 0; i < ASYNC_CALL_PARAMETERS_MAX; i++)
1561 {
1562 boolean asyncCallFlag = _asyncCallFlagsParameters[i];
1563 if (asyncCallFlag)
1564 {
1565 SerialTemp.printf("invokeAsyncCommands(%d)\n", i);
1566 _asyncCallFlagsParameters[i] = false;
1567 switch (i)
1568 {
1570 SerialTemp.print("ASYNC_CALL_BLE_CLIENT_PARAMETER: ");
1571 SerialTemp.println(_asyncParameter);
1572 //! 8.16.25 BLE CLIENT
1573 if (strlen(_asyncParameter)<=13)
1575 else
1577
1578 break;
1580 SerialTemp.print("ASYNC_CALL_OTA_FILE_UPDATE_PARAMETER: ");
1581 SerialTemp.println(_asyncParameter);
1582 //! 8.16.25 MQTT
1583 {
1584 //look for the host: http://<name>/
1585 // httpAddress is everything after the /
1586 //hostname is without http://
1587 char hostname[100];
1588 char httpAddress[100];
1589 int thirdSlash = 0;
1590 for (int i=0; i< strlen(_asyncParameter);i++)
1591 {
1592 if (_asyncParameter[i] == '/')
1593 {
1594 thirdSlash++;
1595 }
1596 if (thirdSlash == 3)
1597 {
1598 // i == point to 3rd slash
1599 strncpy(hostname,_asyncParameter,i);
1600 //add null
1601 hostname[i] = (char)0;
1602 char *a = &_asyncParameter[i+1];
1603 strcpy(httpAddress,a);
1604 break;
1605 }
1606 }
1607 //todo..
1608 SerialTemp.print("will performOTAUpdate: ");
1609 SerialTemp.print(hostname);
1610 SerialTemp.print(" with httpAddress: ");
1611 SerialTemp.println(httpAddress);
1612 performOTAUpdate(hostname, httpAddress);
1613 }
1614 break;
1616 {
1617 //process the message
1618 SerialDebug.print("ASYNC_JSON_MESSAGE_PARAMETER: ");
1619 SerialDebug.println(_asyncParameter);
1620
1621 //! The FINISH of callback for "onWrite" of the bluetooth "onWrite'
1623 }
1624 break;
1625
1626 //! 1.10.24 add ability to send a MQTT Semantic Marker message
1628 {
1629 //process the message
1630 SerialDebug.print("ASYNC_JSON_MQTT_MESSAGE_PARAMETER: ");
1631 SerialDebug.println(_asyncParameter);
1632
1633 //! This sends a MQTT message. Currently GROUP not supported
1634 //! TODO: add GROUP
1635 char *groupTopic = NULL;
1636 if (groupTopic)
1638 else
1640 }
1641 break;
1642
1643 //! 3.9.24 REST call
1645 {
1646 //process the message
1647 SerialDebug.print("ASYNC_REST_CALL_MESSAGE_PARAMETER: ");
1648 SerialDebug.println(_asyncParameter);
1649#ifdef USE_REST_MESSAGING
1650 sendSecureRESTCall(_asyncParameter);
1651#endif
1652 }
1653 break;
1654 }
1655
1656 }
1657 }
1658
1659 //!now process those that don't have a string parameter
1660 for (int i = 0; i < ASYNC_CALL_MAX; i++)
1661 {
1662 boolean asyncCallFlag = _asyncCallFlags[i];
1663 if (asyncCallFlag)
1664 {
1665 _asyncCallFlags[i] = false;
1666 switch (i)
1667 {
1669 SerialLots.println("ASYNC_CALL_OTA_UPDATE");
1670 //! 8.16.25 MQTT
1672 break;
1674 SerialTemp.println("ASYNC_CALL_CLEAN_CREDENTIALS");
1675 //! 8.16.25 WIFI AP
1677 //this reboots ..
1678 break;
1680 SerialTemp.println("ASYNC_CALL_CLEAN_EPROM");
1682 break;
1684 SerialLots.println("ASYNC_CALL_FEED_COMMAND");
1686 //! 8.16.25 MQTT
1687 //!register the 2 callbacks for now..
1689 break;
1690 //!this is a sending of the message
1692 SerialTemp.println("ASYNC_SEND_MQTT_FEED_MESSAGE");
1693 //incrementFeedCount_mainModule();
1694 SerialCall.println("async_send_feed.1");
1695
1696 //! 8.16.25 MQTT
1697 //! 8.16.25 BLE CLIENT
1698 //!9.30.22 IF SET .. send a feed but to all devices except ours and our pair (if any)
1699 //! uses new wildcard syntax either ! OUR NAME [ & ! OUR_CONNECTED_NAME
1701 {
1702 char pubString[100];
1704 boolean isPaired = paired && strlen(paired)>0;
1705 // cannot save it.. so refresh below.. (Preferences are reused)
1706 SerialTemp.printf("Paired = %s\n", paired?paired:(char*)"none");
1707 SerialTemp.printf("Connected = %s\n", connectedBLEDeviceName_mainModule()?connectedBLEDeviceName_mainModule():(char*)"none");
1708
1710 sprintf(pubString,"{'dev':'!%s & !%s'",deviceName_mainModule(),connectedBLEDeviceName_mainModule());
1711 else if (isPaired)
1712 sprintf(pubString,"{'dev':'!%s & !%s'",deviceName_mainModule(),getPreference_mainModule(PREFERENCE_PAIRED_DEVICE_SETTING));
1713 else
1714 sprintf(pubString,"{'dev':'!%s'",deviceName_mainModule());
1715 strcat(pubString,",'cmd':'feed'}");
1717 //! if not paired, then feed everyone except out device...
1718 }
1719 //! if not BLE connected .. send wifi fee to all below...
1720 //SerialTemp.println("async_send_feed.3");
1721 //TODO: 7.26.22 .. decide if this logic makes sense:
1722 //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).
1723 //sendMessageMQTT((char *)"#FEED");
1724 //! 8.16.25 BLE CLIENT
1725 //! returns whether connected over BLE as a client to a server(like a ESP feeder)
1726 if (!isConnectedBLEClient())
1727 {
1728 //! If not connected over BLE -- then send the MQTT feed message.. ??? WHY??
1729 //! 8.16.25 MQTT
1730
1731 //!only if not WIFI with BLE
1732 //! 8.20.24 put back to MQTT feed to all .. for now..
1733 //! SerialCall.println("async_send_feed.1");
1734 sendMessageMQTT((char *)"#FEED");
1735 SerialTemp.println(" *** NO BLE connected so send wifi ASYNC_SEND_MQTT_FEED_MESSAGE");
1736
1737 }
1738 else
1739 {
1740 SerialCall.println("async_send_feed.2");
1742
1743 //!send a BLE feed command as we are connected
1745
1746 //!perform ACK too
1747 //! 8.16.25 MQTT
1748 //ack is sent by the caller of this message..??
1749 //! 11.26.25 send Status instead
1750 //sendMessageMQTT((char *)"#ackMe");
1751 sendMessageMQTT((char*)"#STATUS");
1752 }
1753#ifdef NOT_NOW
1754 //! 8.24.22 (This will redraw the screen - and turn off the blank screen (but not let anyone know)
1755 //! SO: now only the buttons will unlock the blank screen..
1756
1757 //!redraws the Semantic Marker image..
1759#endif //not_now
1760 break;
1761
1762 //!this is a sending of the message
1763 //!5.15.25 Sodbuster Rod plowing/disking in minutes with Mark and Bud
1764 case ASYNC_CLICK_SOUND:
1765 {
1766 SerialTemp.println("ASYNC_CLICK_SOUND");
1768 }
1769 break;
1770
1771 case ASYNC_CALL_BUZZ_ON:
1773 {
1774 boolean isBuzzOn = (i == ASYNC_CALL_BUZZ_ON);
1775 //! set the persistence (Note, this is locally saved. If sending elsewhere .. then they have to set their value)
1777
1778 SerialDebug.printf("ASYNC_CALL_BUZZ %d\n",isBuzzOn);
1779 String cmdToSend;
1780 if (isBuzzOn)
1781 {
1782 cmdToSend = "{'cmd':'buzzon'}";
1783 //! click call synchronously ...
1785 }
1786 else
1787 cmdToSend = "{'cmd':'buzzoff'}";
1788
1789 //!OK: issue.
1790 //! if we are an ESP feeder, the STEPPER is on .. so we're good,
1791 //! if an M5 - then either send over BLE or MQTT
1792#ifdef ESP_M5
1793 //!send via BLE or MQTT ..
1794 //! 8.16.25 BLE CLIENT
1795 //! returns whether connected over BLE as a client to a server(like a ESP feeder)
1796 if (!isConnectedBLEClient())
1797 {
1798 SerialLots.println("async_call_buzz_on/off -- not BLE connected.. send MQTT");
1799 //! If not connected over BLE -- then send the MQTT buzzon message..
1800 //! 8.16.25 MQTT
1801 sendMessageMQTT((char*)cmdToSend.c_str());
1802 }
1803 else
1804 {
1805 //!send over BLE...
1806 sendCommandBLEClient(cmdToSend);
1807 }
1808#else //not M5
1809
1810 //! 8.16.25 BLE CLIENT
1811 //! returns whether connected over BLE as a client to a server(like a ESP feeder)
1812 if (!isConnectedBLEClient())
1813 {
1814 SerialLots.println("async_call_buzz_on -- not BLE connected.. send MQTT");
1815 //! If not connected over BLE -- then send the MQTT buzzon message..
1816 //! 8.16.25 MQTT
1817 sendMessageMQTT((char *)cmdToSend.c_str());
1818 }
1819 else
1820 {
1821 SerialLots.println("async_call_buzz_on -- YES BLE connected.. send BLE");
1822 processClientCommandChar_mainModule(isBuzzOn?'B':'b');
1823
1824 }
1825
1826#endif // ESP_M5
1827 }
1828 break;
1829
1830 //!setGatewayOn/Off called from the processJSON message in MQTT
1831 //! or via the EPROM setting (TODO)
1833 SerialLots.println("ASYNC_SET_GATEWAY_ON");
1835
1836 break;
1837
1839 SerialLots.println("ASYNC_SET_GATEWAY_OFF");
1841
1842 break;
1843
1844 case ASYNC_REBOOT:
1845 SerialDebug.println("ASYNC_REBOOT");
1847
1848 break;
1849
1850 case ASYNC_POWEROFF:
1851 SerialDebug.println("ASYNC_POWEROFF");
1853
1854 break;
1855 case ASYNC_BLANKSCREEN:
1856 SerialDebug.println("ASYNC_BLANKSCREEN");
1858 break;
1860 //!sends the status from the main module URL
1861 //! 8.16.25 MQTT
1862 {
1863#ifdef ESP_M5_CAMERA
1864 char *statusURL = main_currentStatusURL(false);
1865#else
1866 char *statusURL = main_currentStatusURL(true);
1867#endif
1868 SerialDebug.print(" ASYNC_SEND_MQTT_STATUS_URL: ");
1869 SerialDebug.println(statusURL);
1870 /// NO MORE: sendDocFollowMessageMQTT(statusURL);
1871 sendStatusMessageMQTT(statusURL);
1872 }
1873#ifdef M5BUTTON_MODULE
1874 //! 1.23.24 call the status which re-evaluates the sensor ALIVE
1875 //! this status will be called and let the ALIVE re-evaluate
1876 //! Only do this on the STATUS since it might be slow for the LUX
1877 statusM5ButtonModule();
1878#endif
1879 break;
1880
1881 case ASYNC_SWAP_WIFI:
1882 case ASYNC_NEXT_WIFI:
1883 {
1884 //NOTE: this might be where we toggle credentials?? TODO
1885 //found other one..
1886 char *credentials = main_nextJSONWIFICredential();
1887 //! 8.16.25 MQTT
1888
1889 //!These are the ASYNC_CALL_PARAMETERS_MAX
1890 //!NO: just change our credentials ...
1891 //send to
1892 //main_dispatchAsyncCommandWithString(ASYNC_CALL_BLE_CLIENT_PARAMETER, credentials);
1894 }
1895 break;
1897 //! 8.16.25 MQTT
1898 //!Restarts (or attempts) a restart of the WIFI using the existing credentials -- vs the 'n' command
1900 break;
1901 default:
1902 SerialLots.printf("NO COMMAND: %s", i);
1903 }
1904 }
1905 }
1906}
1907//! 2.21.25 add a way to change the button color (if any)
1909{
1910#ifdef M5BUTTON_MODULE
1911 SerialDebug.println("changeButtonColor_MainModule");
1912 // changeButtonColor_M5ButtonModule()
1913#endif
1914}
1915
1916//!3.17.24 the unqiue chip id
1918//! string like: 10311304
1920
1921//! 3.17.24 get the chip id
1922uint32_t getChipId()
1923{
1924 if (_chipID_MainModule == 0)
1925 {
1926 //get chip ID
1927 for (int i = 0; i < 17; i = i + 8) {
1928 _chipID_MainModule |= ((ESP.getEfuseMac() >> (40 - i)) & 0xff) << i;
1929 }
1931 }
1932 return _chipID_MainModule;
1933
1934}
1935
1936//! 3.17.24 get the chip id as a string
1938{
1939 getChipId();
1941}
1942
1943//! 1.12.24 add a temporary LUX dark
1944//! threshholdKind = 0 (LIGHT), 1=(DARK) .. others might be 2=super dark
1945//#define THRESHOLD_KIND_LIGHT 0
1946//#define THRESHOLD_KIND_DARK 1
1949//! set the threshold val
1950void setLUXThreshold_mainModule(int thresholdKind, int luxVal)
1951{
1952 switch (thresholdKind)
1953 {
1955 _thresholdLUXLight = luxVal;
1956 break;
1958 _thresholdLUXDark = luxVal;
1959 break;
1960 }
1961}
1962//! get the threshold val
1963int getLUXThreshold_mainModule(int thresholdKind)
1964{
1965 switch (thresholdKind)
1966 {
1968 return _thresholdLUXLight;
1969 break;
1971 return _thresholdLUXDark;
1972 break;
1973 }
1974 return 80;
1975}
1976
1977//!storage for the group topic name
1978//!Note NO "/" in the front of the path only "usersP"
1980#define GROUP_TOPIC_TO_SEND (char*)"usersP/groups"
1981//!returns a groupTopic to use as a topic
1982char *groupTopicFullName(char *groupName)
1983{
1984 sprintf(_groupTopicName, "%s/%s",GROUP_TOPIC_TO_SEND, groupName);
1985 return _groupTopicName;
1986}
1987
1988//define a couple lights .. maybe move somewhere else..
1989char* _ON_LIGHT = (char*)"ON";
1990char* _OFF_LIGHT = (char*)"OFF";
1991
1992//!callback for blinking led
1993void blinkMessageCallback(char *message)
1994{
1995 //! 12.19.25 Power back on, Snowing in mountains
1996 //! support the blink but using the plugin class
1997 //! 5.15.25 try the async CLICK
1998 //! click call 5.26.25 SYNC version
2000
2001#ifdef ESP_M5
2002
2003 //call the already defined blink led
2004 // devined in Dispense.cpp
2005// digitalWrite(LED, HIGH);
2006// delay(150);
2007// digitalWrite(LED, LOW);
2008
2009#else //not M5
2010 //call the already defined blink led
2011 // defined in Dispense.cpp
2012 // stepperModule_BlinkLED();
2014#endif //ESP_M5
2015}
2016
2017//!callback for SOLID blinking led
2018void solidLightMessageCallback(char *message)
2019{
2020 SerialLots.println("solidLightMessageCallback..");
2021#ifdef ESP_M5
2022#else
2023 //!call the already defined solid led
2024 //! defined in Dispense.cpp
2025 boolean lightOn = true;
2026 lightOn = strstr(&message[0], _ON_LIGHT);
2027 solidLightOnOff_UIModule(lightOn);
2028#endif
2029}
2030
2031//!clean the SSID eprom (MQTT_CLEAN_SSID_EPROM)
2033{
2034 //!call the already defined solid led
2035 //! defined in Dispense.cpp
2036 //! 8.16.25 WIFI AP
2037 //!clean_SSID_WIFICredentials();
2038 //!now register an async call..
2040
2041}
2042
2043//!called on single click
2044//!NOTE: with BLE_CLIENT_NETWORKING, the right button and top button send a BLE command for feeding..
2045void singleClickTouched(char *whichButton)
2046{
2047 //! 8.16.25 WIFI AP
2048 //!for now, only send the FEED command via BLE_CLIENT if turned on. No reboot to AP mode yet..
2049 //! 8.16.25 BLE CLIENT
2050 //!send the async FEED
2051
2052 //! dispatches a call to the command specified. This is run on the next loop()
2054}
2055
2056//! shows a FEED (or whatever) then blanks the screen after N seconds
2057//! NOTE: This will be a scrolling text as sometime ..
2058void showText_mainModule(String text)
2059{
2060 //showText_displayModule(text);
2062
2063}
2064
2065//!callback for SOLID blinking led
2066void solidLightOnOff(boolean onOff)
2067{
2068#ifdef ESP_M5
2069#else
2070 SerialLots.println("solidLight..");
2071 //!call the already defined solid led
2072 //! defined in Dispense.cpp
2073 boolean lightOn = onOff;
2074 solidLightOnOff_UIModule(lightOn);
2075#endif
2076}
2077
2078//!prints the module configuration by looking at #defines
2079//! Eventually this might be an object returned letting the code
2080//!know a capability is included for runtime (vs compile time) decisions
2082{
2083 //!Module Configuration
2084 SerialDebug.println(" ** #define Module Configuration **");
2085 SerialDebug.println(PARTITION_SCHEME);
2086 SerialDebug.printf("M5Stack Version = %s\n", (char*)M5STACK_VERSION);
2087
2088 SerialDebug.println(" ** BUILDS **");
2089
2090#ifdef ESP_M5
2091 //![x] ESP_M5
2092 SerialMin.println("[x] ESP_M5");
2093#else
2094 SerialMin.println("[ ] ESP_M5");
2095#endif
2096#ifdef ESP_M5_CAMERA
2097 //![x] ESP_M5
2098 SerialMin.println("[x] ESP_M5_CAMERA");
2099#else
2100 SerialMin.println("[ ] ESP_M5_CAMERA");
2101#endif
2102#ifdef ESP_32
2103 //! [x] ESP_32
2104 SerialMin.println("[x] ESP_32");
2105#else
2106 SerialMin.println("[ ] ESP_32");
2107#endif
2108#ifdef M5CORE2_MODULE
2109 //![x] M5CORE2_MODULE
2110 SerialMin.println(F("[x] M5CORE2_MODULE"));
2111#else
2112 SerialMin.println(F("[ ] M5CORE2_MODULE"));
2113#endif
2114 //Set this if the SMART clicker build is used.
2115#ifdef ESP_M5_SMART_CLICKER_CONFIGURATION
2116 SerialMin.println(F("[x] ESP_M5_SMART_CLICKER_CONFIGURATION"));
2117#else
2118 SerialMin.println(F("[ ] ESP_M5_SMART_CLICKER_CONFIGURATION"));
2119#endif
2120 //! 7.9.26 Nice summer.. up and dow, 20 mile bike today..
2121#ifdef ESP_M5_ATOM_S3
2122 SerialMin.println(F("[x] ESP_M5_ATOM_S3"));
2123#endif
2124#ifdef ESP_M5_ATOM_LITE
2125 SerialMin.println(F("[x] ESP_M5_ATOM_LITE"));
2126#else
2127 SerialMin.println(F("[ ] ESP_M5_ATOM_LITE"));
2128#endif
2129
2130 SerialDebug.println(F(" ** MQTT BLE NETWORKING **"));
2131
2132 //! 8.16.25 MQTT
2133 //! [x] USE_MQTT_NETWORKING
2134 SerialMin.println("[x] USE_MQTT_NETWORKING");
2135
2136 //! 8.16.25 BLE SERVER
2137 //! [x] USE_BLE_SERVER_NETWORKING
2138 SerialMin.println("[x] USE_BLE_SERVER_NETWORKING");
2139
2140 //! 8.16.25 BLE CLIENT
2141 //! [x] USE_BLE_CLIENT_NETWORKING
2142 SerialMin.println(F("[x] USE_BLE_CLIENT_NETWORKING"));
2143
2144 //! 8.16.25 WIFI AP
2145 //! [x] USE_WIFI_AP_MODULE
2146
2147 SerialMin.println(F("[x] USE_WIFI_AP_MODULE"));
2148
2149
2150#ifdef USE_BUTTON_MODULE
2151 // [x] USE_BUTTON_MODULE
2152 SerialMin.println("[x] USE_BUTTON_MODULE");
2153#else
2154 SerialMin.println("[ ] USE_BUTTON_MODULE");
2155#endif
2156
2157#ifdef M5BUTTON_MODULE
2158 // [x] M5BUTTON_MODULE
2159 SerialMin.println("[x] M5BUTTON_MODULE");
2160#else
2161 SerialMin.println("[ ] M5BUTTON_MODULE");
2162
2163#endif
2164
2165#ifdef USE_STEPPER_MODULE
2166 SerialMin.println("[x] USE_STEPPER_MODULE");
2167#else
2168 SerialMin.println("[ ] USE_STEPPER_MODULE");
2169
2170#endif
2171#ifdef USE_UI_MODULE
2172 SerialMin.println("[x] USE_UI_MODULE");
2173#else
2174 SerialMin.println("[ ] USE_UI_MODULE");
2175
2176#endif
2177#ifdef USE_DISPLAY_MODULE
2178 SerialMin.println("[x] USE_DISPLAY_MODULE");
2179#else
2180 SerialMin.println("[ ] USE_DISPLAY_MODULE");
2181
2182#endif
2183#ifdef BOARD
2184 SerialMin.println(F("[x] BOARD"));
2185#else
2186 SerialMin.println(F("[ ] BOARD"));
2187#endif
2188#ifdef USE_SPIFF_MODULE
2189 SerialMin.printf("[x] USE_SPIFF_MODULE/_SETTING on=%d\n", getPreferenceBoolean_mainModule(PREFERENCE_USE_SPIFF_SETTING));
2190#else
2191 SerialMin.println("[ ] USE_SPIFF_MODULE");
2192#endif
2193#ifdef USE_SPIFF_MQTT_SETTING
2194 SerialMin.printf("[%d] USE_SPIFF_MQTT_SETTING\n",getPreferenceBoolean_mainModule(PREFERENCE_USE_SPIFF_MQTT_SETTING));
2195#endif
2196#ifdef USE_SPIFF_QRATOM_SETTING
2197 SerialMin.printf("[%d] USE_SPIFF_QRATOM_SETTING\n", getPreferenceBoolean_mainModule(PREFERENCE_USE_SPIFF_QRATOM_SETTING));
2198#endif
2199
2200#ifdef USE_FAST_LED
2201 SerialMin.println(F("[x] USE_FAST_LED"));
2202#else
2203 SerialMin.println(F("[ ] USE_FAST_LED"));
2204#endif
2205#ifdef KEY_UNIT_SENSOR_CLASS
2206 SerialMin.println(F("[x] KEY_UNIT_SENSOR_CLASS"));
2207#else
2208 SerialMin.println(F("[ ] KEY_UNIT_SENSOR_CLASS"));
2209#endif
2210#ifdef USE_LED_BREATH
2211 SerialMin.println(F("[x] USE_LED_BREATH"));
2212#else
2213 SerialMin.println(F("[ ] USE_LED_BREATH"));
2214#endif
2215
2216#if (SERIAL_DEBUG_ERROR)
2217 SerialMin.println(F("[x] SERIAL_DEBUG_ERROR"));
2218#endif
2219#if (SERIAL_DEBUG_DEBUG)
2220 SerialMin.println(F("[x] SERIAL_DEBUG_DEBUG"));
2221#endif
2222#if (SERIAL_DEBUG_INFO)
2223 SerialMin.println(F("[x] SERIAL_DEBUG_INFO"));
2224#endif
2225#if (SERIAL_DEBUG_MINIMAL)
2226 SerialMin.println(F("[x] SERIAL_DEBUG_MINIMAL"));
2227#endif
2228#ifdef USE_LIB_WEBSERVER
2229 SerialMin.println("[x] USE_LIB_WEBSERVER");
2230#else
2231 SerialMin.println("[ ] USE_LIB_WEBSERVER");
2232#endif
2233 //!and print any preferences to show
2235}
2236
2237//!If nil it create one with just the null, so strlen = 0
2238//!NOTE: the strdup() might be used later..
2239char* createCopy(char * stringA)
2240{
2241 if (stringA)
2242 return strdup(stringA);
2243 else
2244 return strdup("");
2245}
2246
2247//!If nil it create one with just the null, so strlen = 0
2248//!NOTE: the strdup() might be used later..
2249char* createCopy2(const char * stringA)
2250{
2251 if (stringA)
2252 return strdup(stringA);
2253 else
2254 return strdup("");
2255}
2256
2257//!informs if null or empty string
2258boolean isEmptyString(char *stringA)
2259{
2260 if (!stringA)
2261 {
2262 return true;
2263 }
2264 else if (strlen(stringA) == 0)
2265 {
2266 return true;
2267 }
2268 else
2269 return false;
2270}
2271
2272//!a char* version of startsWith (after skipping spaces)
2273boolean startsWithChar(char *str, char c)
2274{
2275 if (!str) return false;
2276 //!find first non space character, and if not '{' then return false
2277 int i = 0;
2278 while (i < strlen(str))
2279 {
2280 //!jump out if not a space, and 'i' will be the thing to look for
2281 if (str[i] != ' ')
2282 break;
2283 i++;
2284 }
2285
2286 if (str[i] == c)
2287 return true;
2288
2289 return false;
2290}
2291
2292//!start of the sensor updates ... TODO: tie these to the MQTT messaging as well..
2294{
2295 float batVoltage = 1;
2296 float batPercentage = 100; //plugged in
2297#ifdef ESP_M5
2298#ifndef M5STICKCPLUS2
2299
2300#ifdef M5_ATOM
2301 //! the M5.Axp.GetBatVoltage() is VERY slow on the M5 (as there isn't one..)
2302#elif defined(M5CORE2_MODULE)
2303 //!see https://forum.arduino.cc/t/elseif-not-working/565646/12
2304 batVoltage = M5.Axp.GetBatVoltage();
2305 batPercentage = (batVoltage < 3.2) ? 0 : ( batVoltage - 3.2 ) * 100;
2306#else
2307 batVoltage = M5.Axp.GetBatVoltage();
2308 batPercentage = (batVoltage < 3.2) ? 0 : ( batVoltage - 3.2 ) * 100;
2309 //!#Issue 117
2310 //!from: https://community.m5stack.com/topic/1361/ischarging-and-getbatterylevel/9
2311 //!GetVbatdata() is currently depreciated
2312 uint16_t vbatData = M5.Axp.GetVbatData();
2313 double vbat = vbatData * 1.1 / 1000;
2314 batPercentage = 100.0 * ((vbat - 3.0) / (4.07 - 3.0));
2315#endif
2316#endif // M5STICKCPLUS2
2317#endif
2318
2319 if (batPercentage > 100.0)
2320 batPercentage = 100.0;
2321 return batPercentage;
2322}
2323
2324//!adding a synchronous call to send a message over the network (assuming MQTT but not specified), this tacks on {device} and {t:time}
2325void sendMessageString_mainModule(char *messageString)
2326{
2328}
2329
2330
2331//!adding a synchronous call to send a message over the network (assuming MQTT but not specified), this tacks on {device} and {t:time}
2332void sendMessageStringTopic_mainModule(char *messageString, char*topicString)
2333{
2334 //! 8.16.25 MQTT
2335 SerialDebug.printf("sendMessageStringTopic_mainModule(%s) - topic=%s\n", messageString, topicString);
2336 if (strlen(messageString) > 0 && messageString[0] == '{')
2337 {
2338 // JSON Message
2339 //! 12.19.23 Amber in air from Iceland. 50 years since Dead 12.19.73
2340 sendMessageNoChangeMQTT_Topic(messageString, topicString);
2341 }
2342 else if (strlen(messageString) < MESSAGE_STORAGE_MAX)
2343 {
2344 //!NOTE: the # has to be there, otherwise the sendMessageMQTT ignores it..
2345 sprintf(_messageStorage,"#%s {%s} {t:%d}", messageString, getDeviceNameMQTT(), getTimeStamp_mainModule());
2346 //!send this message over MQTT
2348 }
2349}
2350
2351//!retrieves the temperature .
2353{
2354#ifdef ESP_M5
2355 //!return celcius
2356 //!float temperature = M5.Axp.GetTempInAXP192();
2357 float temperature;
2358#ifdef M5_ATOM
2359#else
2360#ifndef M5STICKCPLUS2
2361 M5.IMU.getTempData(&temperature);
2362#endif
2363#endif
2364
2365#ifdef USER_THE_MAX_TEMP_FEATURE
2367 if (temperature > maxtemp)
2368 {
2369 //! turn off the device after sending a message..
2370 //! let others know we are powering off..
2371 //! then poweroff
2372 //! 8.16.25 MQTT
2373 sprintf(_messageStorage,"#Temp %f too high > %d - powering off {%s}", temperature, maxtemp, getDeviceNameMQTT());
2374 //!send this message over MQTT
2376 //! now poweroff
2377 SerialTemp.println(" *** This would poweroff .. but you can send message");
2378 //!poweroff_mainModule();
2379
2380 }
2381#endif
2382
2383#else
2384 float temperature = 10.0;
2385#endif
2386 return temperature ;//* 9/5 + 32;
2387}
2388//!NEW: 4.30.22
2389//!returns a string in JSON format, such that {'battery':'84'}, {'buzzon':'off'} .. etc
2390//!as a URL: SemanticMarker.org/bot/sample/scott@name/password/status?BLE:on&numfeeds=8&WIFI:on&AP:off
2391/** Sample format:
2392{"status": [
2393 {
2394 "BLE": "on"
2395 },
2396 {
2397 "numfeeds": "8",
2398 "maxfeeds": "16"
2399 },
2400 {
2401 "battery": "87"
2402 },
2403 {
2404 "buzzon": "on"
2405 },
2406 {
2407 "MQTT": "on"
2408 },
2409 {
2410 "WIFI": "on"
2411 },
2412 {
2413 "AP": "off"
2414 },
2415 {
2416 "tilt": "55"
2417 }
2418]
2419}
2420*/
2421//!status in JSON format, needs to return something as a ',' is already added before calling this..
2423{
2424 //returns a JSON string..
2425// String b = String(getBatPercentage(),0);
2426// return "{'status':[{'BLE':'on'},{'bat':'" + b + "'}]}";
2427 // return (char*)"";
2428
2429 //! 1.4.24 work on ATOM kinds without IFDEF (except to bring in the code)
2430#pragma mark USE_NEW_M5ATOMCLASS
2431
2432 //! 5.6.25 use object version
2435
2436#ifdef M5CORE2_MODULE
2437 //!returns a string in in JSON so: status&battery=84'&buzzon='off' } .. etc
2438 //!starts with "&"*
2440#endif
2441
2442 return (char*)"'tbd':'x'";
2443}
2444
2445//! TODO: fix syntax. If just sensor sensor status: ....
2446//!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
2447//!not working just added Z=on/off length = 157
2448//! going to remove the username/password to shorten..
2449
2450//!adds a query string "&key=value"
2451void addStatusStringFlag(const char *key, char * val)
2452{
2453 char buf[50];
2454 sprintf(buf,"&%s=%s", key, val);
2455 strcat(_fullStatusString, buf);
2456}
2457//!adds to _fullStatusString a query string "&key=value"
2458void addStatusBooleanFlag(const char *key, boolean flag)
2459{
2460 addStatusStringFlag(key, flag?(char*)"on":(char*)"off");
2461
2462}
2463//!sets the "Module Status"
2464//!in queryString == name=val&name=val ...
2466{
2467 //!value of WIFI connected
2468 //! 8.16.25 MQTT
2471 //! 8.16.25 BLE CLIENT
2472 //useBLECLient == it's linked in and running (vs not running)
2474 //! connected == we are connected to another BLEServer
2476
2477 //! 8.16.25 WIFI AP
2478 //!not done is what we look for ..
2480
2481#pragma mark reused
2482#ifdef OVERLOADS_TIME_T
2483 //! 7.20.25 this breaks the T:<time> since there is a dublicate in the URL .. with no error
2485#endif
2486
2487 //! 8.16.25 BLE SERVER
2489 {
2490 //! add a bleS=PTFeeder:name
2491 char *serverBLEName = getServiceName_BLEServerNetworking();
2492 addStatusStringFlag((char*)"bleS",serverBLEName);
2493 }
2494
2495 //!show Z for buZZ
2497
2498 //!show G for gateway
2500
2501 //! 8.10.25
2502 //! #393 add stepper angle
2503 //!show SA for stepper angle float ..
2505
2506
2507 //!P = paired
2510#ifdef NO_MORE_PREFERENCE_BLE_USE_DISCOVERED_PAIRED_DEVICE_SETTING
2511
2514#endif
2515 {
2516 addStatusStringFlag("P", pairedDeviceName);
2517 }
2518
2519 //! add the canister and stepper angle per #278
2520#ifdef ESP_32
2525
2526#endif
2527}
2528
2529//!returns a string in in URL so: status?battery=84'&buzzon='off' } .. etc
2530//!if fullStatus, return everything, else just the ATOM stuff
2531char* main_currentStatusURL(boolean fullStatus)
2532{
2533 //!7.20.25 add T too
2534 int time = getTimeStamp_mainModule();
2535 if (fullStatus)
2536 {
2537 //! 8.16.25 MQTT
2538 char *deviceName = getDeviceNameMQTT();
2539 //!TODO: make sure no spaces ... unless escaped
2540
2541 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());
2542
2543 }
2544 else
2545 {
2546 //_fullStatusString[0] = '\0';
2547 //! 8.16.25 MQTT
2548 char *deviceName = getDeviceNameMQTT();
2549 //!TODO: make sure no spaces ... unless escaped
2550 sprintf(_fullStatusString,"status?T=%d&v=%s&dev=%s",time, VERSION_SHORT, deviceName);
2551
2552 }
2553#pragma mark USE_NEW_M5ATOMCLASS
2554 //! 5.6.25 use object version
2557
2558 //add to _fullStatusString
2560
2561// //NOTE: any new query from somewhere starts with & (they put it in)
2562
2563 SerialCall.println( _fullStatusString );
2564
2565 //!TODO: put these somewhere somehow (expandable easily..architecturally. eg. setStatus("battery","87") key,val
2566 //!the JSON DB supports db["battery"]=87 like syntax..
2567
2568 //return "status?buzzon=off&AP=off&MQTT=on&WIFI=on&BLE=on&battery=" + String(getBatPercentage(),0);
2569 return _fullStatusString;
2570}
2571
2572#ifdef UNDEFINED
2573//!sets status parts cia a a string in JSON format, such that {'battery':'84'}, {'buzzon':'off'} .. etc
2574void main_setStatusJSON(const char* JSONString)
2575{
2576 //would set the JSON string
2577}
2578//!sets status parts cia a a string in JSON format, such that {'battery':'84'}, {'buzzon':'off'} .. etc
2579void main_setStatusKeyValue(const char* key, const char* value)
2580{
2581 //todo..
2582}
2583#endif
2584
2585//!SemanticMarker events
2586//!This would see a DOCFollow message, and set the value.. then SM10 can display it..
2588//!sed the address to follow
2589void setSemanticMarkerDocFollow_mainModule(char* SMDocFollowAddress)
2590{
2591 _lastSemanticMarkerDocFollow = SMDocFollowAddress;
2594}
2595
2596//!gets the semanticAddress SemanticMarker&trade;
2598{
2600}
2601
2602//!sends the SM on the DOCFOLLOW channel (publish it..)
2603void sendSemanticMarkerDocFollow_mainModule(const char* SMDocFollowAddress)
2604{
2605 //! 8.16.25 MQTT
2606 sendDocFollowMessageMQTT(SMDocFollowAddress);
2607}
2608
2609//! 8.18.24 setting this will check for the factory setting..
2610void setClockwiseMotorDirection_mainModule(boolean isClockwiseFlag)
2611{
2613 SerialDebug.printf("factoryMotorClockwise = %d, isClockwiseFlag = %d\n",factoryMotorClockwise, isClockwiseFlag);
2614
2615 if (factoryMotorClockwise && isClockwiseFlag)
2616 {
2617 SerialDebug.println("setClockwiseMotorDirection -- same so no change");
2618 }
2619 else if (factoryMotorClockwise && !isClockwiseFlag)
2620 {
2621 //!toggle flag and save as that mode..
2622 isClockwiseFlag = !isClockwiseFlag;
2623 //! this says: factory is CW and we want to turn CCW
2624 //! so we have to go the opposite direction (!CW)
2625 }
2626 else if (!factoryMotorClockwise && isClockwiseFlag)
2627 {
2628 //! toggle flag as well,
2629 isClockwiseFlag = !isClockwiseFlag;
2630 //! this says: factory is CCW and we want to turn CW
2631 //! so we have to go the opposite direction (!CW)
2632 }
2633 else if (!factoryMotorClockwise && !isClockwiseFlag)
2634 {
2635 SerialDebug.println("setClockwiseMotorDirection -- same so no change");
2636 }
2637 //! set to what it thinks it is...
2639}
2640
2641//!Keep ProcessClientCmd short to let the callback run. instead change the feeder state flag
2642//! processes a message that might save in the EPROM.. the cmd is still passed onto other (like the stepper module)
2644{
2645 //!the sentToStepper is only needed if there are 'actions' on the command, versus just
2646 //! setting persistent EPROM data. Like feed, buzzer, etc..
2647 //!Thus we don't need to know much of their implementation.. or we just pass anyway!
2648 boolean sendToStepperModule = false;
2649 SerialDebug.printf("***** processClientCommand_mainModule(%c) from client*****\n", cmd);
2650
2651 //char cmd = message[0];
2652 //!only process things that are stored persistently..
2653 //!7.20.25 6 months T
2654 //!Using switch to guarentee unique case of single characters
2655 switch (cmd)
2656 {
2657 case 0x00:
2658 case 's':
2659 case 'c':
2660 {
2661 sendToStepperModule = true;
2662 } break;
2663 case 'a':
2664 {
2665
2666 SerialDebug.println("cmd=a startTimer");
2667 //!start timer..
2669
2670 } break;
2671 case 'A':
2672 {
2673
2674 SerialDebug.println("cmd=A stopTimer");
2675
2676 //!start timer..
2678
2679 } break;
2680 case 'j':
2681 {
2682 sendToStepperModule = true;
2683 SerialLots.println("Setting FeedState = JACKPOT_FEED");
2685
2686 } break;
2687 case 'u':
2688 {
2689 SerialDebug.println("Setting feederType = UNO");
2691
2692 //!Issue #332 8.17.2024
2694 //! set autoRotoate as well..
2696 //! default to clockwise == 0
2697 //! 8.18.24 setting this will check for the factory setting..
2699 } break;
2700 case 'm':
2701 {
2702 SerialDebug.println("Setting feederType = MINI");
2703 //save preference
2705 //!Issue #332 8.17.2024
2707 // turn clockwise..
2708 //! 8.18.24 setting this will check for the factory setting..
2710 } break;
2711 case 'L':
2712 {
2713 SerialDebug.println("Setting feederType = Tumbler");
2714 //save preference
2716 //!Issue #332 8.17.2024
2718 //! set autoRotoate as well..
2720 //! set autoRotoate as well..
2721 //! 8.18.24 setting this will check for the factory setting..
2722 //setClockwiseMotorDirection_mainModule(true);
2723 } break;
2724 //! 11.25.25 toggle the buzzer, THIS is local already, but the toggle:buzzer will be ONLY be to a BLE device
2725 //! that way it sends 'F'
2726 case 'F':
2727 {
2728 SerialDebug.println("Toggle Buzzer via BLE: 'F'");
2729 //! then toggle value
2731
2732 //! will be turned on so make sound..
2733 //! the main sync command (no parameters yet)
2735#ifdef LOCAL_NOT_REMOTE
2736 if (buzzerOn)
2738 else
2740#endif
2741 } break;
2742 //! this is a call to the connected device
2743 case 'f':
2744 {
2745 //! this will be a BLE message to the connectd device sending a 'F"
2746 SerialDebug.println("Toggle remove Buzzer via BLE: 'f'");
2747 //! then toggle value
2748 //! see if connected to a BLE device..
2749 char *connectedBLEDeviceName = connectedBLEDeviceName_mainModule()?connectedBLEDeviceName_mainModule():NULL;
2750 SerialDebug.printf("connectedBLEDeviceName = %s\n", connectedBLEDeviceName);
2751
2752 if (connectedBLEDeviceName)
2753 {
2754 SerialDebug.printf("Call Toggle Buzzer via BLE: 'F' - dev=%s\n", connectedBLEDeviceName);
2755
2756 //! send via BLE
2757 //!send a string of 13 or less characters.
2759 }
2760 } break;
2761 case 'B':
2762 {
2763 sendToStepperModule = true;
2764 SerialDebug.println("Setting buzzStatus = BUZZON");
2765 //save pref
2767
2768 //! 11.27.25 Turkey Day, Nice day Mt Out.
2769 //! Also make the Buzzer sound
2770
2771 //! will be turned on so make sound..
2772 //! the main sync command (no parameters yet)
2774 } break;
2775 case 'b':
2776 {
2777 sendToStepperModule = true;
2778
2779 SerialDebug.println("Setting buzzStatus = BUZZOFF");
2781 } break;
2782 case 'T':
2783 {
2784 SerialDebug.println("*** Setting tilt = ON");
2786 } break;
2787 case 't':
2788 {
2789 SerialDebug.println("Setting tilt = OFF");
2791 } break;
2792
2793 //!6.20.25
2794#ifdef NOT_SUPPORTED_RIGHT_NOW
2795 case 'O':
2796 {
2797 SerialDebug.println("OTA Update.. ");
2798 //! dispatches a call to the command specified. This is run on the next loop()
2800 } break;
2801#endif
2802#define SUPPORT_MINI_CLEAN
2803#ifdef SUPPORT_MINI_CLEAN
2804 //! 7.16.26 SpaceX 1 sec stoppage
2805 //! only suport Clean Credentials
2806 case 'X':
2807 {
2808 SerialDebug.println("Clean EPROM.. so it's first time again");
2809 //! dispatches a call to the command specified. This is run on the next loop()
2811 } break;
2812 case 'x':
2813 {
2814 SerialDebug.println("Clean SSID from EPROM.. ");
2815 char cleanWIFI[100];
2816 strcpy(cleanWIFI,"{'ssid':'','ssidPassword':''}");
2817 SerialDebug.println(cleanWIFI);
2818 //! 8.16.25 MQTT
2819 //! send to ourself
2820 sendMessageNoChangeMQTT((char*)cleanWIFI);
2821
2822 } break;
2823#else
2824 case 'X':
2825 case 'x':
2826#endif
2827 case 'R':
2828 {
2829 SerialDebug.println("Clean Credentials");
2830 //! dispatches a call to the command specified. This is run on the next loop()
2832 } break;
2833
2834 //!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)
2835 case 'G':
2836 {
2837 SerialDebug.println("Setting Gateway = ON");
2839 } break;
2840 case 'g':
2841 {
2842 SerialDebug.println("Setting Gateway = OFF");
2844 } break;
2845 case '_':
2846 {
2847 //This is from the handshake like "_BLEClient_ESP_M5"
2848 SerialDebug.println("unused cmd '_'");
2849 } break;
2850#ifdef OLD_FOR_M5_DISPLAY
2851 case 'Z':
2852 {
2853 sendToStepperModule = false;
2854
2855 SerialDebug.println("Setting SM Zoom = zoomed");
2857 } break;
2858 case 'z':
2859 {
2860 sendToStepperModule = false;
2861
2862 SerialDebug.println("Setting SM Zoom = full SM");
2864 } break;
2865#else
2866 //! 7.25.25 chilly morning, Mt starting to come out.
2867 //! SPIFF
2868 case 'Z':
2869 {
2870 //! clean SPIFF file"
2871
2872 SerialDebug.println("clean SPIFF file");
2874 } break;
2875 case 'z':
2876 {
2877 //! upload SPIFF to web
2878
2879 SerialDebug.println("upload SPIFF to web");
2880 //! number of lines to send
2881 //! TODO: configure thie number of lines to save..
2883 } break;
2884#endif
2885 case 'P':
2886 {
2887 //printout the spiff.. to the serial debug monitor
2888 //!Restarts (or attempts) a restart of the WIFI using the existing credentials -- vs the 'n' command
2890 } break;
2891 //! 7.24.25 use SPIFF
2892 case 'S':
2893 {
2894 //! toggle spiff on/off
2896 spiffFlag = !spiffFlag;
2897
2898 SerialDebug.printf("Changing current USE_SPIFF = %s\n", spiffFlag?"NOYES":"NO");
2900
2901 // reboot
2903
2904 }
2905 //! WIFI credential changes...
2906 case 'N':
2907 {
2908 //NOTE: this might be where we toggle credentials?? TODO
2909 //found other one..
2910 char *credentials = main_JSONStringForWIFICredentials();
2911
2912 //!These are the ASYNC_CALL_PARAMETERS_MAX
2914 } break;
2915 case 'n':
2916 {
2917 //!NOTE: this is almost the same as 'w' except there might be more WIFI than 2 (so swap is different).
2919 } break;
2920 case 'W':
2921 {
2923 } break;
2924 case 'w':
2925 {
2926 SerialDebug.println("w for swapWifi");
2927
2929 } break;
2930
2931 //! 8.16.24 per #332
2932 case 'H':
2933 {
2934 SerialDebug.printf("PREFERENCE_STEPPER_AUTO_MOTOR_DIRECTION_SETTING true");
2935
2936 // autoMotorDirection ON
2938
2939 } break;
2940 //! 8.16.24 per #332
2941
2942 case 'h':
2943 {
2944 SerialDebug.printf("PREFERENCE_STEPPER_AUTO_MOTOR_DIRECTION_SETTING false");
2945
2946 // autoMotorDirection off
2948 } break;
2949 case 'D':
2950 {
2951 SerialDebug.printf("PREFERENCE_STEPPER_CLOCKWISE_MOTOR_DIRECTION_SETTING counter clockwise");
2952
2953 //!NOTE: no current mode to specify CCW or CW dynamically (non factory reset)
2954 // motor direction = counterclockwise
2956 } break;
2957 case 'd':
2958 {
2959 SerialDebug.printf("PREFERENCE_STEPPER_CLOCKWISE_MOTOR_DIRECTION_SETTING clockwise");
2960
2961 // motor direction == (clockwise)
2963 } break;
2964 //! 9.30.23 reverse direction
2965 case 'Q':
2966 {
2967 SerialDebug.printf("PREFERENCE_STEPPER_CLOCKWISE_MOTOR_DIRECTION_SETTING reverse direction");
2968
2969 //! note: reboot not needed as the next time a feed happens, it reads this value
2970 // motor direction == (reverse)
2972 currentDirection = !currentDirection;
2974
2975 } break;
2976 case 'E':
2977 {
2978 SerialDebug.printf("PREFERENCE_BLE_SERVER_USE_DEVICE_NAME_SETTING false");
2979
2980 //!if set, the BLE Server (like PTFeeder) will tack on the device name (or none if not defined).
2982 // reboot
2984 } break;
2985 case 'e':
2986 {
2987 SerialDebug.printf("PREFERENCE_BLE_SERVER_USE_DEVICE_NAME_SETTING true");
2988
2989 //!if set, the BLE Server (like PTFeeder) will tack on the device name (or none if not defined).
2991 // reboot
2993 } break;
2994 case 'r':
2995 {
2996 // reboot
2997 SerialDebug.println("REBOOT ...");
2999 } break;
3000
3001 case 'p':
3002 {
3003 //! poweroff
3004 SerialDebug.printf("(%c) POWEROFF ...", cmd);
3006 } break;
3007 //! 7.12.25
3008 //! 0 == Clear SENSOR definitions
3009 case 'k':
3010 {
3011 //! poweroff
3012 SerialDebug.println("Clearing Sensors");
3013 setSensorsString_mainModule((char*)"");
3014
3015 //! reboot .. so the sensors are set..
3017 } break;
3018 //! 7.9.25
3019 //! 1 == Init SENSOR definitions
3020 case '1':
3021 {
3022 setConfiguration_mainModule((char*)"L9110S_DCStepperClass");
3023 } break;
3024#ifdef NOT_ANYMORE
3025 //! 7.12.25
3026 //! 2 == default for SMART Button
3027 case '2':
3028 {
3029 setConfiguration_mainModule((char*)"ULN2003_StepperClass");
3030 } break;
3031#endif
3032 //! 12.21.25 Winter Solstice, Eagles,
3033 //! support the new Chain Buttons
3034 case '2':
3035 {
3036 setConfiguration_mainModule((char*)"ChainButtonClass");
3037 } break;
3038 //! 7.19.25 add Clear Sensors
3039 case '3':
3040 {
3041 setConfiguration_mainModule((char*)"PTStepper");
3042 } break;
3043 //! 8.18.26 use this for the mode of a released PTStepper
3044 case '=':
3045 {
3046 SerialDebug.println("Setting modes for (a) PTStepper with (b) E mode 8.18.26");
3047 //! E mode first . don't use the DEVICE_NAME
3049
3050 //! do the PTStepper but first set the E mode
3051 setConfiguration_mainModule((char*)"PTStepper");
3052
3053 //! cannot do anything else, as the line above reoots the computer
3054 }
3055 break;
3056 case '4':
3057 {
3058 setConfiguration_mainModule((char*)"M5AtomCamera");
3059 } break;
3060 //! 7.9.25 grabbed from BOOTSTRAP let someone update the atom to the recent OTA
3061 case '5':
3062 {
3063 SerialDebug.println(" *** performing m5atom OTA Update");
3064 //! 8.16.25 MQTT
3065 //!retrieves from constant location
3066 performOTAUpdate((char*)"http://KnowledgeShark.org", (char*)"OTA/TEST/M5Atom/ESP_IOT.ino.m5stick_c_plus.bin");
3067 } break;
3068 //! 7.9.25 grabbed from BOOTSTRAP let someone update the atom to the recent OTA
3069 case '6':
3070 {
3071 SerialDebug.println(" *** performing m5atom OTA Update - DAILY");
3072 //! 8.16.25 MQTT
3073 //!retrieves from constant location
3074 performOTAUpdate((char*)"http://KnowledgeShark.org", (char*)"OTA/TEST/M5Atom/daily/ESP_IOT.ino.m5stick_c_plus.bin");
3075 } break;
3076 case '7':
3077 {
3078 SerialDebug.println(" *** performing m5atom OTA Update - BOOTSTRAP");
3079 //! 8.16.25 MQTT
3080 //!retrieves from constant location
3081 performOTAUpdate((char*)"http://KnowledgeShark.org", (char*)"OTA/Bootstrap/ESP_M5_BOOTSTRAP.ino.m5stack_stickc_plus.bin");
3082 } break;
3083#pragma mark M5AtomS3 OTA
3084 //! 7.10.26 M5AtomS3 (without display)
3085 // SerialDebug.println(" y - _m5atomS3");
3086 // SerialDebug.println(" Y - _mm5atomS3Daily");
3087 //! must be first..
3088 case 'y':
3089 {
3090 SerialDebug.println(" *** performing m5atomS3 OTA Update");
3091
3092 //!retrieves from constant location
3093 performOTAUpdate((char*)"http://KnowledgeShark.org", (char*)"OTA/TEST/M5AtomS3/ESP_IOT.ino.m5stick_c_plus.bin");
3094 }break;
3095 case 'Y':
3096 {
3097 SerialDebug.println(" *** performing m5atomS3 OTA Update - DAILY");
3098
3099 //!retrieves from constant location
3100 performOTAUpdate((char*)"http://KnowledgeShark.org", (char*)"OTA/TEST/M5AtomS3/daily/ESP_IOT.ino.m5stick_c_plus.bin");
3101 }break;
3102 //! 8.11.26 added the platform.io bin (which Wes creates)
3103 case '+':
3104 {
3105 SerialDebug.println(" *** performing m5atomS3_platform.io OTA Update - DAILY");
3106
3107 //!retrieves from constant location
3108 performOTAUpdate((char*)"http://KnowledgeShark.org", (char*)"OTA/TEST/M5AtomS3/platform.io/daily/ESP_IOT.ino.m5stick_c_plus.bin");
3109 }break;
3110 //! 8.15.26 add - for the released version
3111 case '-':
3112 {
3113 SerialDebug.println(" *** performing m5atomS3_platform.io OTA Update - RELEASED");
3114
3115 //!retrieves from constant location
3116 performOTAUpdate((char*)"http://KnowledgeShark.org", (char*)"OTA/TEST/M5AtomS3/platform.io/ESP_IOT.ino.m5stick_c_plus.bin");
3117 }break;
3118 //! 8.18.25
3119 case '8':
3120 {
3121 setConfiguration_mainModule((char*)"M5NoModule");
3122 } break;
3123 case '9':
3124 {
3125 setConfiguration_mainModule((char*)"M5TinyGPS");
3126 } break;
3127 case '0': //m5atom_qrode
3128 {
3129 setConfiguration_mainModule((char*)"M5AtomScanner");
3130 } break;
3131#ifdef USE_6
3132 case '9':
3133 {
3134 //! 8.18.25 M5Clicker
3135 SerialDebug.println(" *** performing m5atom OTA Update - M5Clicker");
3136 //! 8.16.25 MQTT
3137 //!retrieves from constant location
3138 performOTAUpdate((char*)"http://KnowledgeShark.org", (char*)"OTA/Bootstrap/ESP_M5_BOOTSTRAP.ino.m5stack_stickc_plus.bin");
3139 } break;
3140#endif
3141 case 'C':
3142 {
3143 SerialDebug.println("'C' change color touched");
3144#ifdef USE_FAST_LED
3145 CRGB randomColor = getRandomColor();
3146 fillpix(randomColor);
3147 delay(50);
3148#else
3149 //! 8.2.26 random LED color
3151#endif
3152 }
3153 break;
3154 case 'i':
3155 {
3156 char sendCapture[100];
3157 strcpy(sendCapture,"{'send':'capture'}");
3158 SerialDebug.println(sendCapture);
3159 //! 8.16.25 MQTT
3160 //! send to ourself
3161 sendMessageNoChangeMQTT((char*)sendCapture);
3162
3163 }
3164 break;
3165#pragma mark BLE_SETTINGS
3166 //! 8.11.26 BLE Server and Client on/off
3167 case '!':
3168 {
3169 SerialDebug.println(" ! - BLE_Client on");
3171 //! reboot .. so the sensors are set..
3173 }
3174 break;
3175 case '@':
3176 {
3177 SerialDebug.println(" @ - BLE_Client off");
3179 //! reboot .. so the sensors are set..
3181 }
3182 break;
3183 case '#':
3184 {
3185 SerialDebug.println(" # - BLE_Server on");
3187 //! reboot .. so the sensors are set..
3189 }
3190 break;
3191 case '$':
3192 {
3193 SerialDebug.println(" $ - BLE_Server off");
3195 //! reboot .. so the sensors are set..
3197 }
3198 break;
3199
3200#pragma mark HELP
3201 case '.':
3202 {
3203
3204 //! returns if the BLEClient is turned on.. note, if connected to a BLE device, then disconnect
3205
3207 //! toggle spiff on/off
3209 SerialTemp.println(VERSION);
3210 SerialMin.println("Valid Commands: ");
3211 SerialMin.println(" . = help, this message");
3212 SerialMin.println(" p = poweroff if can");
3213 SerialMin.println(" 0x0, s, c == Single Feed - via BLE to connected device");
3214 SerialMin.println(" a == AutoFeed On");
3215 SerialMin.println(" A == AutoFeed Off");
3216 SerialMin.println(" u == UNO ");
3217 SerialMin.println(" m == MINI ");
3218 SerialMin.println(" L == tumbler");
3219 SerialMin.println(" H == autoMotorDirection on");
3220 SerialMin.println(" h == autoMotorDirection off");
3221 SerialMin.println(" D == FACTORY counter clockwise motor direction");
3222 SerialMin.println(" d == FACTORY clockwise motor direction");
3223 SerialMin.println(" Q == change motor direction opposite of current");
3224
3225 //! this is local buzzer on/off calling the current Atom Class
3226 SerialMin.println(" F == Toggle Buzzer on/off");
3227 //! this will be a BLE message to the connectd device sending a 'F"
3228 SerialMin.println(" f == Toggle Buzzer on/off on BLE connected device");
3229
3230 SerialMin.println(" B == Buzzer On");
3231 SerialMin.println(" b == Buzzer Off");
3232 SerialMin.println(" G == Gateway On");
3233 SerialMin.println(" g == Gateway Off");
3234 SerialMin.println(" R == clean credentials");
3235 SerialMin.println(" X == clean EPROM <<<< FIRST TIME DO THIS <<<< 7.26.26");
3236 SerialMin.println(" x == clean SSID from EPROM");
3237 SerialMin.println(" r == reboot ");
3238 //!6.20.25
3239
3240 SerialMin.println(" T == tiltOn");
3241 SerialMin.println(" t == tiltOff");
3242 SerialMin.println(" N == send WIFI Credential to BLEServer");
3243 SerialMin.println(" n == next WIFI Credential");
3244 SerialMin.println(" W == retry WIFI");
3245 SerialMin.println(" w == swap WIFI");
3246 SerialMin.println(" C == change m5 atom to random color");
3247 SerialMin.println(" i == take pic, {send:capture}");
3248
3249 SerialMin.println(" SPIFF internal memory ");
3250#ifndef OLD_FOR_M5_DISPLAY
3251 SerialMin.println(" Z == clean SPIFF file");
3252 SerialMin.println(" z == upload SPIFF to web");
3253#endif
3254 SerialMin.println(" P == print SPIFF");
3255 SerialMin.printf (" S == toggle SPIFF %s\n", spiffFlag?"OFF":"ON");
3256
3257 SerialMin.println(" BLE Naming ");
3258
3259 SerialMin.println(" E == use only PTFeeder naming");
3260 SerialMin.println(" e == use naming PTFeeder:name");
3261#ifdef OLD_FOR_M5_DISPLAY
3262 SerialMin.println(" Z == Setting SM Zoom = zoomed");
3263 SerialMin.println(" z == Setting SM Zoom = full SM");
3264#endif
3265 SerialMin.println(" Configurations of M5Atom ");
3266
3267 SerialMin.println(" k == no sensors");
3268 SerialMin.println(" 1 == L9100S_DCStepper (current main)");
3269 //SerialMin.println(" 2 == ULN2002 Stepper (new test 8.13.25)");
3270 SerialMin.println(" 2 == ChainSensors (12.21.25))");
3271 SerialMin.println(" 3 == *** PTStepperClass (original code - with M5");
3272 SerialMin.printf (" 4 == M5AtomCamera\n");
3273 SerialMin.println(" 8 == SMART Button, Clicker");
3274 SerialMin.println(" 9 == M5TinyGPS, Clicker");
3275 SerialMin.println(" 0 == M5AtomScanner, Clicker");
3276 SerialMin.println(" = == E mode, then PTStepper (3)");
3277
3278
3279#ifdef NOT_SUPPORTED_RIGHT_NOW
3280 SerialMin.println(" O == OTA update");
3281#else
3282 SerialMin.println(" OTA Updates of M5AtomLite -board M5StickCPlus ");
3283 SerialMin.println(" 5 == m5atom DEV OTA update");
3284 SerialMin.println(" 6 == m5atom DAILY TEST DEV OTA update");
3285 SerialMin.println(" 7 == go back to m5atom BOOTSTRAP");
3286
3287 //! 7.10.26 M5AtomS3 (without display)
3288 SerialDebug.println(" OTA updates for M5AtomS3 - board M5AtomS3");
3289 SerialDebug.println(" y - _m5atomS3");
3290 SerialDebug.println(" Y - _mm5atomS3Daily");
3291 SerialDebug.println();
3292 //! 8.11.26 M5AtomS3_platformIO
3293 SerialDebug.println(" OTA updates for M5AtomS3 - board M5AtomS3 - platform.io");
3294 SerialDebug.println(" + _mm5atomS3 Daily_platform.io");
3295 SerialDebug.println(" - _mm5atomS3 Released _platform.io");
3296
3297 SerialDebug.println();
3298#endif
3299 //! 8.11.26 BLE Server and Client on/off
3300 SerialDebug.println(" Turn On/Off BLE Server and Client");
3301 SerialDebug.println(" ! - BLE_Client on");
3302 SerialDebug.println(" @ - BLE_Client off");
3303 SerialDebug.println(" # - BLE_Server on");
3304 SerialDebug.println(" $ - BLE_Server off");
3305 SerialDebug.println(" test -- create test user ");
3306
3307 SerialDebug.println();
3308
3309 SerialMin.println();
3310 SerialMin.println("Full API at: https://github.com/konacurrents/SemanticMarkerAPI");
3311 SerialMin.println();
3312
3313 //!print out stuff
3315
3316 } break;
3317 break;
3318 default:
3319
3320 {
3321 SerialMin.printf("*****invalid command '%c' from client (use '.' for help) *****\n", cmd);
3322 }
3323 }
3324
3325#ifdef USE_STEPPER_MODULE
3326 if (sendToStepperModule)
3327 {
3329 }
3330#endif
3331}
3332
3333//! 8.20.25 Horses grazing if field first time for Mark and Bud
3334//! add set/config
3335//! PTStepper
3336//! M5AtomCamera
3337void setConfiguration_mainModule(char* configurationName)
3338{
3339 SerialDebug.printf("setConfiguration: %s\n", configurationName);
3340
3341 if (strcmp(configurationName, "PTStepper")==0)
3342 {
3343 //! poweroff
3344 SerialDebug.println("Default PTStepperClass");
3345 //resetSensorToDefault_mainModule();
3346 //! 7.30.25 changing to the HDriver's board
3347 //! savePreference_mainModule(PREFERENCE_SENSORS_SETTING, _sensorsEPROM);
3348#ifdef DONT_ADD_TO_SENSORS
3349 setSensorsString_mainModule((char*)"BuzzerSensorClass,21,25,PTStepperClass,23,33");
3350#else
3351#ifdef ESP_M5_ATOM_S3
3352 //! 7.12.26 Ashton's 12th birtyday, Bike ride 20
3353 //! seems the AtomS3 blows UP with 19,22
3354 //! now they are 39, 38
3355 //! now -1, 39
3356 setSensorsString_mainModule((char*)"BuzzerSensorClass,-1,39");
3357
3358#else
3359 // setSensorsString_mainModule((char*)"BuzzerSensorClass,21,25");
3360 //! try -1 and 21 ...
3361 //! 7.14.26 warm day, fluffing up hay in field
3362
3363 setSensorsString_mainModule((char*)"BuzzerSensorClass,-1,21");
3364
3365#endif
3366
3367#endif
3368 //! 7.31.25 if Scanner or QR then pin 22 used .. so make M5HDriver (basically don't have a sensor)
3370 //! also specify the sensor plug
3372 //! for Tumbler .. use 200
3374 //! @see #390 this is the RPM of the stepper
3375 //savePreferenceFloat_mainModule(PREFERENCE_STEPPER_RPM_SETTING, 15.0);
3376 //! set autoRotoate as well..
3378 //! tumbler
3380
3381 //! 8.18.26 default buzzer OFF
3383
3384 //! 9.5.25 set the 2step OFF for now
3386
3387 //! 10.24.25 also set BLE client and serve on,
3388 //! RAIN .. atosmopheric river
3390
3391 //!if set, the BLE Server (like PTFeeder) will tack on the device name (or none if not defined).
3392 //!8.18.26 don't set it either way, use E if want other..
3393 //savePreferenceBoolean_mainModule(PREFERENCE_BLE_SERVER_USE_DEVICE_NAME_SETTING,true);
3394
3395 //!if set, the BLE client OFF 8.18.26
3397
3398 //! reboot .. so the sensors are set..
3400 }
3401#pragma mark CHAIN BUTTON
3402 //! 12.21.25 Winter Solstice, Eagles,
3403 //! Chain Button
3404 else if (strcmp(configurationName, "ChainButtonClass")==0)
3405 {
3406 //! poweroff
3407 SerialDebug.println("Default ChainButtonClass **** hardcoded button messages ****");
3408 //resetSensorToDefault_mainModule();
3409#ifdef ESP_M5_ATOM_S3
3410 //! 7.12.26 Ashton's 12th birtyday, Bike ride 20
3411 //! seems the AtomS3 blows UP with 19,22
3412 //! now they are G6 and G5
3413 //setSensorsString_mainModule((char*)"ChainButtonClass,6,5");
3414 //! 8.7.26 w Laura, swap pins .. RXD, TXD
3415 //! 8.8.26 Row Jimmy, Bike warm nice. less smoke, put back the 6,5 pins..
3416 setSensorsString_mainModule((char*)"ChainButtonClass,6,5");
3417
3418#else
3419 //! 7.30.25 changing to the HDriver's board
3420 setSensorsString_mainModule((char*)"ChainButtonClass,19,22");
3421#endif
3422
3423 //! 7.31.25 if Scanner or QR then pin 22 used .. so make M5HDriver (basically don't have a sensor)
3425 //! also specify the sensor plug (non for now..
3427
3428 //! 4.3.26 Off to the Moon
3429 //! This will send WIFI along with BLE (if double click). or WIFI if not BLE connected
3431
3432
3433 //!TODO.. Chain
3434 //!presskind = 0, short, 1, long, 2, longlong
3435 //!ButtonKind, number_1based, pressKind, setString, valString, device
3436 //!if localhost then internal message, otherwise external MQTT message
3437 savePreference_mainModule(PREFERENCE_CHAIN_SENSORS_SETTING, "ChainButtonClass,1,0,SM_MatrixCell,8,$all,ButtonClass,1,1,feed,,$pair,JoystickClass,2,0,feed,,$localhost");
3438
3439 //! iniitlize from the string ..
3441
3442 //! idea is you define the button and the press kind
3443 //! MatrixCell is Column Major 1,4, 7 // 2,5,8 // 3,6,9
3444 registerChain_mainModule("ButtonClass", 1, BUTTON_SHORT_PRESS, "SM_MatrixCell", "15", "$dev" );
3445 registerChain_mainModule("ButtonClass", 1, BUTTON_LONG_PRESS, "SM_MatrixCell", "6", "$dev");
3446 registerChain_mainModule("JoystickClass", 2, BUTTON_SHORT_PRESS, "feed", "", "localhost" );
3447
3448
3449 //! 10.24.25 also set BLE client and serve on,
3450 //! RAIN .. atosmopheric river
3453
3454 //!if set, the BLE Server (like PTFeeder) will tack on the device name (or none if not defined).
3456
3457 //! this initializes as well as prints (I think) 8.8.26
3459
3460 //! reboot .. so the sensors are set..
3461 // FOR NOW until parser workign .. don't reboot ...
3463 }
3464 else if (strcmp(configurationName, "ULN2003_StepperClass")==0)
3465 {
3466 /*
3467 #define IN1 22
3468 #define IN2 19
3469 #define IN3 23
3470 #define IN4 33
3471 */
3472 //! poweroff
3473 SerialDebug.println("Default ULN2003_StepperClass");
3474 //resetSensorToDefault_mainModule();
3475 //! 7.30.25 changing to the HDriver's board
3476 setSensorsString_mainModule((char*)"BuzzerSensorClass,21,25");
3477 //! 7.31.25 if Scanner or QR then pin 22 used .. so make M5HDriver (basically don't have a sensor)
3479 //! also specify the sensor plug
3481 //! 1 second motor (overloads "angle" field)
3482 //! This is the RPM speed
3484 //! @see #390 this is the RPM of the stepper
3486 //! set autoRotoate as well..
3488 //! tumbler
3490
3491 //!if set, the BLE Server (like PTFeeder) will tack on the device name (or none if not defined).
3493
3494 //! reboot .. so the sensors are set..
3496 }
3497 else if (strcmp(configurationName, "M5AtomCamera")==0)
3498 {
3499 //! poweroff
3500 SerialDebug.println("Default M5AtomCamera");
3501 //resetSensorToDefault_mainModule();
3502 //! 7.30.25 changing to the HDriver's board
3503 setSensorsString_mainModule((char*)"");
3504 //! 7.31.25 if Scanner or QR then pin 22 used .. so make M5HDriver (basically don't have a sensor)
3506 //! also specify the sensor plug
3508
3509 //! 10.24.25 also set BLE client and serve on,
3510 //! RAIN .. atosmopheric river
3513
3514 //!if set, the BLE Server (like PTFeeder) will tack on the device name (or none if not defined).
3516
3517 //! reboot .. so the sensors are set..
3519 }
3520 else if (strcmp(configurationName, "M5TinyGPS")==0)
3521 {
3522 //!
3523 SerialDebug.println("Default M5AtomTinyGPS");
3524 //resetSensorToDefault_mainModule();
3525 //! 7.30.25 changing to the HDriver's board
3526 setSensorsString_mainModule((char*)"");
3527 //! 7.31.25 if Scanner or QR then pin 22 used .. so make M5HDriver (basically don't have a sensor)
3529 //! also specify the sensor plug (non for now..
3531
3532 //! 10.24.25 also set BLE client and serve on,
3533 //! RAIN .. atosmopheric river
3536
3537 //!if set, the BLE Server (like PTFeeder) will tack on the device name (or none if not defined).
3539
3540 //! reboot .. so the sensors are set..
3542 }
3543 else if (strcmp(configurationName, "M5AtomScanner")==0)
3544 {
3545 //!
3546 SerialDebug.println("Default M5AtomScanner");
3547 //resetSensorToDefault_mainModule();
3548 //! 7.30.25 changing to the HDriver's board
3549 setSensorsString_mainModule((char*)"");
3550 //! 7.31.25 if Scanner or QR then pin 22 used .. so make M5HDriver (basically don't have a sensor)
3552 //! also specify the sensor plug (non for now..
3554
3555 //! 10.24.25 also set BLE client and serve on,
3556 //! RAIN .. atosmopheric river
3559
3560 //!if set, the BLE Server (like PTFeeder) will tack on the device name (or none if not defined).
3562
3563 //! reboot .. so the sensors are set..
3565 }
3566 else if (strcmp(configurationName, "M5NoModule")==0)
3567 {
3568 //!
3569 SerialDebug.println("Default M5AtomNoModule");
3570 //resetSensorToDefault_mainModule();
3571 //! 7.30.25 changing to the HDriver's board
3572 setSensorsString_mainModule((char*)"");
3573 //! 7.31.25 if Scanner or QR then pin 22 used .. so make M5HDriver (basically don't have a sensor)
3575 //! also specify the sensor plug (non for now..
3577
3578 //! 10.24.25 also set BLE client and serve on,
3579 //! RAIN .. atosmopheric river
3582
3583 //!if set, the BLE Server (like PTFeeder) will tack on the device name (or none if not defined).
3585
3586 //! reboot .. so the sensors are set..
3588 }
3589 else
3590 {
3591 SerialDebug.printf(" **** Unknown Configuration: %s\n", configurationName);
3592 }
3593}
3594
3595
3596//!On the esp32, sec is all we can handle. We can return as a double if milisecond resolution is needed.
3597//!This is the time since app started..
3598//!https://randomnerdtutorials.com/epoch-unix-time-esp32-arduino/
3600{
3601
3602 time_t now;
3603 struct tm timeinfo;
3604 time(&now);
3605 //! 7.27.25
3606 //! miliseconds .. convert to seconds
3607 //now = now * 1000;
3608 SerialLots.printf("Unix Time: %d\n", now);
3609 return now;
3610}
3611
3612//! ************** SM Mode Processing ***************
3613
3614
3615//!returns an index from 0..max of SM matching cmd, or -1 if none
3617{
3618#ifdef ESP_M5
3619 //https://www.cplusplus.com/reference/cstring
3620 if (strncmp(cmd,"sm",2) == 0)
3621 {
3622 //point to the 'm' in 'sm'
3623 char *p = strchr(cmd,'m');
3624 //then increment
3625 p++;
3626 //convert to a number
3627 int num = atoi(p);
3628 //convert to integer..
3629 SerialLots.print("whichSMMode: ");
3630 SerialLots.print(cmd);
3631 SerialLots.print(" => " );
3632 SerialLots.println(num);
3633 return num;
3634 }
3635 else
3636#endif //ESP_M5
3637 {
3638 return -1;
3639 }
3640}
3641//!returns if a match the mode. whichSMMode is 0..12 and == sm0 .. smn
3642boolean matchesSMMode_mainModule(char *cmd, int whichSMMode)
3643{
3644 char *mode = charSMMode_mainModule(whichSMMode);
3645 return (strcasecmp(cmd,mode)==0);
3646}
3647//!returns string form whichSMMode, sg "sm0", sm1 ...
3648//!This can (and is) called by multiple places (like ButtonProcessing and MainModule
3649char* charSMMode_mainModule(int whichSMMode)
3650{
3651 SerialLots.printf("charSMMode_mainModule: %d\n", whichSMMode);
3652
3653 sprintf(_smMode_MainModule,"sm%0d",whichSMMode);
3654 SerialCall.println(_smMode_MainModule);
3655 return _smMode_MainModule;
3656}
3657
3658//!returns which mode in (min or expanded)
3660{
3662}
3663
3664//!toggles the menu mode
3666{
3668}
3669
3670//! returns the current max of the MIN menu modes (using the setting of min or expanded) to determine
3672{
3673 return MAX_SM_MIN_MODES;
3674}
3675
3676//! returns the current max of the menu modes (using the setting of min or expanded) to determine
3678{
3679 SerialLots.printf("maxMenuModes_mainModule: %s, %d, %d\n", isMinimalMenuMode_mainModule?"1":"0", MAX_SM_MIN_MODES, MAX_SM_EXPANDED_MODES);
3681 return MAX_SM_MIN_MODES;
3682 else
3683 return MAX_SM_EXPANDED_MODES;
3684}
3685
3686//!the saved SMMode
3688//!sets the current screen mode .. which can be used by Button and Display processing
3689void setCurrentSMMode_mainModule(int whichSMMode)
3690{
3691 SerialLots.print("setCurrentSMMode_mainModule:");
3692 SerialLots.println(whichSMMode);
3693
3694 // This version sets the MIN OR MAX
3695 if (whichSMMode >= MAX_SM_MIN_MODES)
3696 {
3697 // change to EXPANDED MODES
3699 }
3700 _saveWhichSMMode = whichSMMode;
3701}
3702//!returns the current SM Mode
3704{
3705 return _saveWhichSMMode;
3706}
3707
3708//!increment the currentSMMode, wrapping and using the max menu
3710{
3712 int max = maxMenuModes_mainModule();
3713 if (_saveWhichSMMode >= max)
3714 {
3715 _saveWhichSMMode = 0;
3716 }
3717 SerialTemp.print("incrementSMMode_mainModule:");
3718 SerialTemp.println(_saveWhichSMMode);
3719}
3720//!increment the currentSMMode, wrapping and using the max menu
3722{
3723 if (_saveWhichSMMode > 0)
3724 {
3726 }
3727}
3728
3729//!full: ""Name: PTFeeder:HowieFeeder, Address: 7c:9e:bd:48:af:92, serviceUUID: 0xdead"
3731{
3732 //! 8.16.25 BLE CLIENT
3734 return _fullBLEDeviceName;
3735 else
3736 {
3737 return (char*)"";
3738 }
3739}
3740
3741//!whether connected GEN3
3742boolean _connecteBLEisGEN3 = false;
3743//!whether the connected is a GEN3 (so the name isn't valid)
3745{
3746 return _connecteBLEisGEN3;
3747}
3748
3749//! BLE Discovery Methods
3750//! Connected to a BLE device with the advertised name. The syntax can include (PTFeeder:NAME) or just PTFeeder
3751//! Being disconnected is already a flag isConnectedBLE ...
3752void setConnectedBLEDevice_mainModule(char *deviceName, boolean isGEN3)
3753{
3754 //!set the isGEN3 flag
3755 _connecteBLEisGEN3 = isGEN3;
3756 //!now set the gateway based on if GEN3
3757 SerialTemp.printf("auto-settingGateway(%d)\n", isGEN3);
3759
3760 strcpy(_fullBLEDeviceName, deviceName);
3761
3762 //!seems device name = "Name: PTFeeder:HowieFeeder, Address: 7c:9e:bd:48:af:92, serviceUUID: 0xdead
3763 //!Note: the Address, eg "7c:9e:bd:48:af:92" is unique somehow.. lets use that to skip one..
3764 SerialCall.printf("setConnectedBLEDevice_mainModule: %s\n", deviceName);
3765 strcpy(_connectedBLEDeviceName,"");
3766
3767 if (containsSubstring(deviceName,"PTFeeder:") || containsSubstring(deviceName,"PTClicker:"))
3768 {
3769 //!parse out the 2nd half of name
3770 char *colon = index(deviceName,':');
3771 colon++;
3772 colon = index(colon,':');
3773 //! go past the :
3774 colon++;
3775
3776 while (*colon && *colon != ',')
3777 {
3778 int len = strlen(_connectedBLEDeviceName);
3779 _connectedBLEDeviceName[len] = colon[0];
3780 _connectedBLEDeviceName[len+1] = '\0';
3781 colon++;
3782 }
3783 }
3784 else
3785 {
3786 //! empty name (just PTFeeder)
3787 strcpy(_connectedBLEDeviceName,(char*)"");
3788 }
3789 SerialTemp.print("connectedBLEName= ");
3790 SerialTemp.println(_connectedBLEDeviceName);
3791
3792 //! 8.29.23 send a message saying we connected..
3793#ifdef LATER
3794 seems to be crashing..
3795 {
3796 char connectMessage[300];
3797 sprintf(connectMessage,"#connectedBLE {%s to %s}", getDeviceNameMQTT(), _connectedBLEDeviceName);
3798 SerialTemp.println(connectMessage);
3799 //sendSemanticMarkerDocFollow_mainModule(&fileURL[0]);
3800 //! for now only send if it start message starts with "#"
3801 publishMQTTMessageDefaultTopic(connectMessage);
3802 }
3803#endif
3804 //!parse for the address too..
3805 //! strcpy(_fullBLEDeviceName, deviceName);
3806
3807 //!seems device name = "Name: PTFeeder:HowieFeeder, Address: 7c:9e:bd:48:af:92, serviceUUID: 0xdead
3808 //!Note: the Address, eg "7c:9e:bd:48:af:92" is unique somehow.. lets use that to skip one..
3809 strcpy(_connectedBLEDeviceAddress,"");
3810 if (containsSubstring(_fullBLEDeviceName,"Address:"))
3811 {
3812 //!parse out the 2nd half of name
3813 char *colon = strstr(_fullBLEDeviceName,"Address:");
3814 colon += strlen("Address:");
3815 //strip spaces
3816 while (*colon && *colon == ' ')
3817 {
3818 colon++;
3819 }
3820 //now until the , is the address
3821 while (*colon && *colon != ',')
3822 {
3823 int len = strlen(_connectedBLEDeviceAddress);
3824 _connectedBLEDeviceAddress[len] = colon[0];
3825 _connectedBLEDeviceAddress[len+1] = '\0';
3826 colon++;
3827 }
3828 }
3829 else
3830 {
3831 //! empty name (just PTFeeder)
3832 strcpy(_connectedBLEDeviceAddress,(char*)"");
3833 }
3834 SerialTemp.print("_connectedBLEDeviceAddress= ");
3835 SerialTemp.println(_connectedBLEDeviceAddress);
3836}
3837
3838//!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)
3839//! returns the connected BLE Device name (the :NAME of advertisment, Address: 01:39:3f:33 part of name
3841{
3842 char *nameToUse;
3843 if (strlen(_connectedBLEDeviceName)!= 0)
3844 nameToUse = _connectedBLEDeviceName;
3845 else if (strlen(_connectedBLEDeviceAddress)!= 0)
3846 nameToUse =_connectedBLEDeviceAddress;
3847 else
3848 nameToUse = (char*)"";
3849
3850 //! 8.16.25 BLE CLIENT
3851
3852 //! if connected, return the connected name, otherwise return empty string
3854 {
3855 return nameToUse;
3856 }
3857 else
3858 {
3859 return (char*)"";
3860 }
3861}
3862
3863//!returns address part of name.
3865{
3866 //! 8.16.25 BLE CLIENT
3867
3868 //! if connected, return the connected name, otherwise return empty string
3870 {
3872 }
3873 else
3874 {
3875 return (char*)"";
3876 }
3877}
3878
3879//! 6.6.25 get the current M5AtomClassType
3881{
3882 return _whichM5AtomClassType;
3883}
3884
3885//! 1.22.24 add setup and loop at main so it can call appropriate plugs
3887{
3888#ifdef USE_BUTTON_MODULE
3889 //! the model part of the MVC for buttons
3890 loop_ButtonProcessing();
3891#endif
3892
3893 //! these are the plugin modules .. and only 1 active at a time except for ATOM
3894#ifdef M5CORE2_MODULE
3896#elif defined(M5_ATOM)
3897
3898#pragma mark USE_NEW_M5ATOMCLASS
3899 //! 5.6.25 use object version
3901 {
3902 SerialCall.printf("*** _whichM5AtomClassType %s\n",_whichM5AtomClassType->classIdentity() );
3904 }
3905 else
3906 {
3907 SerialDebug.println("*** _whichM5AtomClassType NULL ***");
3908
3909 }
3910
3911 // end atom
3912
3913#elif defined(M5BUTTON_MODULE)
3914 loop_M5ButtonModule();
3915#endif
3916}
3917
3918//! 1.22.24 setup of buttons
3920{
3921 SerialDebug.println("setup_Sensors_mainModule");
3922#ifdef USE_BUTTON_MODULE
3923 //! the model part of the MVC for buttons
3924 setup_ButtonProcessing();
3925#endif
3926 //! these are the plugin modules .. and only 1 active at a time except for ATOM
3927#ifdef M5_ATOM
3928 SerialDebug.println(" ***** M5_ATOM define ****");
3929#endif
3930#ifdef M5CORE2_MODULE
3932#endif
3933
3934#ifdef M5_ATOM
3935
3936#pragma mark M5AtomClassType
3937
3938 //! 5.6.25 use the M5Atom ClassType
3939#ifdef USE_NEW_M5ATOMCLASS
3940 //! @see https://www.cs.fsu.edu/~myers/cop3330/notes/dma.html
3941 _M5Atom_SocketModuleClass = new M5Atom_SocketModuleClass((char*)"M5AtomSocket");
3942 _M5Atom_QRCodeModuleClass = new M5Atom_QRCodeModuleClass((char*)"M5AtomScanner");
3943 _M5Atom_HDriverModuleClass = new M5Atom_HDriverModuleClass((char*)"M5HDriver");
3944 //! 7.17.25
3945 _M5Atom_TinyGPSModuleClass = new M5Atom_TinyGPSModuleClass((char*)"M5AtomTinyGPS");
3946 //! 8.16.25 bring in the Camera
3947 _M5Atom_CameraModuleClass = new M5Atom_CameraModuleClass((char*)"M5AtomCamera");
3948 //! 10.26.25 Power Out .. Wind Storm. Generator Running
3949 //! add a NoModule class
3950 _M5Atom_NoModuleClass = new M5Atom_NoModuleClass((char*)"M5AtomNoModule");
3951
3952 int whichM5AtomIndex = 0;
3953 SerialDebug.println("setup_M5Atoms");
3954
3955 //! 3.31.25 create array of plugs
3956 _M5AtomClassTypes[whichM5AtomIndex++] = _M5Atom_SocketModuleClass;
3957 _M5AtomClassTypes[whichM5AtomIndex++] = _M5Atom_QRCodeModuleClass;
3958 _M5AtomClassTypes[whichM5AtomIndex++] = _M5Atom_HDriverModuleClass;
3959 //! 7.17.25
3960 _M5AtomClassTypes[whichM5AtomIndex++] = _M5Atom_TinyGPSModuleClass;
3961 //! 8.16.25 bring in the Camera
3962 _M5AtomClassTypes[whichM5AtomIndex++] = _M5Atom_CameraModuleClass;
3963 //! 10.26.25 Power Out .. Wind Storm. Generator Running
3964 //! add a NoModule class
3965 _M5AtomClassTypes[whichM5AtomIndex++] = _M5Atom_NoModuleClass;
3966
3967 //! add check..
3968 if (whichM5AtomIndex > NUM_M5ATOM_CLASS)
3969 {
3970 SerialDebug.printf("**** sensors are more than max .. FIX CODE");
3971 }
3972 SerialDebug.printf("Created %d M5AtomClassTypes\n", whichM5AtomIndex);
3973
3974 //! use this one...
3975 _whichM5AtomClassType = NULL;
3976 //! find the current atomKind. which is a string
3977 char *atomKind = getPreferenceATOMKind_MainModule();
3978
3979#pragma mark DEBUG_7_9_26
3980 {
3981 if (!atomKind || strlen(atomKind) ==0)
3982 {
3983 SerialDebug.println(" **** no atomKind set .. use M5AtomNoModule");
3984 atomKind = (char*)"M5AtomNoModule";
3985 }
3986 SerialDebug.printf("**** setting M5AtomNoModule %s\n", atomKind);
3987 // still don't get it.. but for motor lets change this...
3988// atomKind = "M5AtomNoModule";
3989// processClientCommandChar_mainModule('3');
3990 }
3991// SerialDebug.println(" **** no atomKind set .. use M5AtomNoModule");
3992// atomKind = "M5AtomNoModule";
3993// SerialDebug.println(" **** no atomKind set .. use M5AtomNoModule");
3994#pragma mark endDebug
3995
3996 //! find which one..
3997 for (int i=0; i<NUM_M5ATOM_CLASS; i++)
3998 {
3999 if (!_M5AtomClassTypes[i])
4000 {
4001 SerialDebug.println("NULL M5AtomClassType");
4002 continue;
4003 }
4004 //! check against the identity.. (or make this part of that method?)
4005 if (strcmp(_M5AtomClassTypes[i]->classIdentity(), atomKind) == 0)
4006 {
4007 //! Matched..
4009 break;
4010 }
4011 }
4013 {
4014 SerialDebug.printf("** Found M5AtomClass = %s\n", atomKind);
4015 }
4016 else
4017 {
4018 SerialDebug.printf("****^^^ Cannot find M5AtomClass = %s\n", atomKind);
4019
4020 SerialDebug.println("Defaulting to _M5Atom_HDriverModuleClass");
4022 }
4023#else
4024 SerialDebug.printf("M5AtomKind = %d\n", getM5ATOMKind_MainModule());
4025#endif
4026
4027 //! now the setup() call
4028#pragma mark USE_NEW_M5ATOMCLASS
4029 //! 5.6.25 use object version
4032
4033 // end atom
4034#pragma mark DEBUG_7_9_26
4035 //SerialDebug.println("** DEBUG: xxx");
4036
4037#elif defined(M5BUTTON_MODULE)
4038 setup_M5ButtonModule();
4039#endif
4040}
4041//! BUTTON PROCESSING abstraction
4042//!short press on buttonA (top button)
4044{
4045#ifdef USE_BUTTON_MODULE
4047#endif
4048#ifdef M5CORE2_MODULE
4050#elif defined(M5_ATOM)
4051#pragma mark USE_NEW_M5ATOMCLASS
4052 //! 5.6.25 use object version
4054 {
4055 SerialDebug.println("buttonA_ShortPress_mainModule");
4057 }
4058
4059#elif defined(M5BUTTON_MODULE)
4060 buttonA_ShortPress_M5ButtonModule();
4061#endif
4062
4063}
4064
4065//!long press on buttonA (top button)
4067{
4068#ifdef USE_BUTTON_MODULE
4070#endif
4071#ifdef M5CORE2_MODULE
4073#elif defined(M5_ATOM)
4074
4075#pragma mark USE_NEW_M5ATOMCLASS
4076 //! 5.6.25 use object version
4078 {
4079 SerialDebug.println("buttonA_LongPress_mainModule");
4081 }
4082
4083#elif defined(M5BUTTON_MODULE)
4084 buttonA_LongPress_M5ButtonModule();
4085#endif
4086}
4087
4088//! 11.25.25 add long long
4089//!long press on buttonA (top button)
4091{
4092#ifdef USE_BUTTON_MODULE
4093 //buttonA_LongLongPress();
4094 //! 7.11.26 nedw M5AtomS3a NOT: let's turn off USE_BUTTON for now
4095 //buttonA_LongLongPress_mainModule();
4096
4097#endif
4098#ifdef M5CORE2_MODULE
4100#elif defined(M5_ATOM)
4101
4102#pragma mark USE_NEW_M5ATOMCLASS
4103 //! 5.6.25 use object version
4105 {
4106 SerialDebug.println("buttonA_LongLongPress_mainModule");
4108 }
4109 else
4110 {
4111 SerialDebug.println(" *** buttonA_LongLongPress undefined ****");
4112 }
4113
4114#elif defined(M5BUTTON_MODULE)
4115 buttonA_LongLongPress_M5ButtonModule();
4116#endif
4117}
4118
4119
4120//!the long press of the side button
4122{
4123#ifdef USE_BUTTON_MODULE
4125#endif
4126#ifdef M5BUTTON_MODULE
4127 //!the long press of the side button
4128 buttonB_LongPress_M5ButtonModule();
4129#endif
4130}
4131//!the short press of the side button
4133{
4134#ifdef USE_BUTTON_MODULE
4136#endif
4137
4138#ifdef M5BUTTON_MODULE
4139 //!the long press of the side button
4140 buttonB_ShortPress_M5ButtonModule();
4141#endif
4142}
4143#pragma mark BUTTON Processing of M5
4144
4145//!big button on front of M5StickC Plus
4147{
4148 _shortPress_MainModule = false;
4149 _longPress_MainModule = false;
4151#ifdef M5UNIFIED
4152 //!NOTE: ths issue is the timer is interruped by the scanner.. so make long-long very long..
4153 //was 1000 (from 500)
4154 if (M5.BtnA.wasPressed())
4155 {
4156 // buttonA_longPress_MainModule();
4157 SerialDebug.println("MainModule M5.BtnA **** wasPressed ***");
4159 }
4160 else if (M5.BtnA.wasReleasefor(4500))
4161 {
4162 // buttonA_longPress_MainModule();
4163 SerialDebug.println("MainModule M5.BtnA **** LONG LONG PRESS ***");
4165 }
4166 else if (M5.BtnA.wasReleasefor(1000))
4167 {
4168 // buttonA_longPress_MainModule();
4169 SerialDebug.println("MainModule M5.BtnA **** LONG PRESS ***");
4170 _longPress_MainModule = true;
4171 }
4172 else if (M5.BtnA.wasReleased())
4173 {
4174 // buttonA_shortPress_MainModule();
4175 SerialDebug.println("MainModule M5.BtnA **** wasReleased ***");
4177 }
4178#elif defined(ESP_M5_ATOM_S3)
4179 //!NOTE: ths issue is the timer is interruped by the scanner.. so make long-long very long..
4180 //was 1000 (from 500)
4181 if (AtomS3.BtnA.wasPressed())
4182 {
4183 // buttonA_longPress_MainModule();
4184 SerialDebug.println("MainModule M5.BtnA **** wasPressed ***");
4186 }
4187 else if (AtomS3.BtnA.wasReleasefor(4500))
4188 {
4189 // buttonA_longPress_MainModule();
4190 SerialDebug.println("MainModule M5.BtnA **** LONG LONG PRESS ***");
4192 }
4193 else if (AtomS3.BtnA.wasReleasefor(1000))
4194 {
4195 // buttonA_longPress_MainModule();
4196 SerialDebug.println("MainModule M5.BtnA **** LONG PRESS ***");
4197 _longPress_MainModule = true;
4198 }
4199 else if (AtomS3.BtnA.wasReleased())
4200 {
4201 // buttonA_shortPress_MainModule();
4202 SerialDebug.println("MainModule M5.BtnA **** wasReleased ***");
4204 }
4205#else
4206 //!NOTE: ths issue is the timer is interruped by the scanner.. so make long-long very long..
4207 //was 1000 (from 500)
4208 if (M5.BtnA.wasPressed())
4209 {
4210 // buttonA_longPress_MainModule();
4211 SerialDebug.println("MainModule M5.BtnA **** wasPressed ***");
4213 }
4214 else if (M5.BtnA.wasReleasefor(4500))
4215 {
4216 // buttonA_longPress_MainModule();
4217 SerialDebug.println("MainModule M5.BtnA **** LONG LONG PRESS ***");
4219 }
4220 else if (M5.BtnA.wasReleasefor(1000))
4221 {
4222 // buttonA_longPress_MainModule();
4223 SerialDebug.println("MainModule M5.BtnA **** LONG PRESS ***");
4224 _longPress_MainModule = true;
4225 }
4226 else if (M5.BtnA.wasReleased())
4227 {
4228 // buttonA_shortPress_MainModule();
4229 SerialDebug.println("MainModule M5.BtnA **** wasReleased ***");
4231 }
4232#endif
4233}
4234//!big button on front of M5StickC Plus
4236{
4237 //! OOPS:: these override the A_versions....
4238 //! just ADD to the state..
4239 if (true)
4240 {
4242 _longPressB_MainModule = false;
4245
4246 }
4247#ifdef ESP_M5
4248
4249 //!NOTE: ths issue is the timer is interruped by the scanner.. so make long-long very long..
4250 //was 1000 (from 500)
4251 if (M5.BtnB.wasReleasefor(4500))
4252 {
4253 // buttonA_longPress_MainModule();
4254 SerialDebug.println("MainModule M5.BtnB **** LONG LONG PRESS ***");
4256 }
4257 else if (M5.BtnB.wasReleasefor(1000))
4258 {
4259 // buttonA_longPress_MainModule();
4260 SerialDebug.println("MainModule M5.BtnB **** LONG PRESS ***");
4261 _longPress_MainModule = true;
4262 }
4263 else if (M5.BtnB.wasReleased())
4264 {
4265 // buttonA_shortPress_MainModule();
4266 SerialDebug.println("MainModule M5.BtnB **** SHORT PRESS ***");
4268 }
4269 /// Returns true when some time has passed since the button was double clicked.
4270 //!@see bool wasDoubleClicked(void) const { return _currentState == state_decide_click_count && _clickCount == 2; }
4271
4272 else if (M5.BtnB.wasDoubleClicked())
4273 {
4274 //! one idea: double press is like single press. then long preess is A's long press? But need B to more through menues of display
4275 SerialDebug.println("MainModule M5.BtnB **** DOUBLE PRESS ***");
4277 }
4278#endif
4279}
4280
4281#pragma mark Models
4282//!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
4284{
4285 //!restarts all the menu states to the first one .. useful for getting a clean start. This doesn't care if the menu is being shown
4287}
4288
4289//! 1.1.24 send status of this device after events..
4291{
4292 //On demand #STATUS send the statusURL as well (if an M5)
4293 //this queues the sending of the StatusURL over MQTT.
4294 // This is async (next loop) since sending 2 MQTT messages can be hard to do in a row ..
4296}
4297
4298//! 3.23.25 rainy weekend
4299//! create a JSON string from the SemanticMarker
4300//! https://semanticmarker.org/bot/setdevice/scott@konacurrents.com/PASS/M5AtomSocket/socket/on}
4301//! Create a JSON knowing the "bot" syntax, eg. setdevice/USER/PASS/device/<set>/<flag>
4302//! defined in TokenParser.h
4303char *semanticMarkerToJSON_mainModule(char* semanticMarker)
4304{
4305 return semanticMarkerToJSON_TokenParser(semanticMarker);
4306}
4307
4308#pragma mark PIN_USE_STRUCT
4309#pragma mark PIN USE to see if overlaps.
4310//! 7.31.25 add this for a status, saw that QRCode was using 22 also .. so buzer didn't work.
4311/**
4312#define PIN_USE_MAX 10
4313struct pinUseStruct {
4314 int pinUseCount;
4315 //! string describing the module, etc
4316 char *pinUseArray[PIN_USE_MAX];
4317 //! each pin
4318 long pinNumArray[PIN_USE_MAX];
4319} _pinUseStruct;
4320*/
4321
4322//! global for use. This is an object (not a pointer) and has all the storage created statically
4324//! get the pin use array
4326{
4327 return &_pinUseStruct;
4328}
4329
4330
4331//! 7.31.25 store this information.. for STATUS
4332//! 5.3.25 add a central clearing house for defining PIN use
4333//! @see issue #365
4334//! central clearing house for all pins used to we can analyze if there are overlaps
4335//! pin is the actual number, pinName is the local name (eg. IN1_PIN or VIN_PIN).
4336//! moduleName is the module in the code,
4337//! isI2C is whether this is a I2C bus (which we aren't using much yet)
4338//! //! 7.13.26 Ballon morning .. field haying
4339//! return Boolean saying the pin was Valid of Invalie
4340boolean registerPinUse_mainModule(long pin, String pinName, String moduleName, boolean isI2C)
4341{
4342 char pinUseSample[100];
4343 sprintf(pinUseSample,"PIN_USE: %2d = %s, %s %s", pin, pinName.c_str(), moduleName.c_str(), isI2C?"(I2C)":"");
4344
4345 //! check if pins are valid ..
4346 boolean validPins = true;
4347#ifdef ESP_M5_ATOM_S3
4348 switch (pin)
4349 {
4350 case -1: // support this as a power
4351 case 0: //main button hod 2s
4352 case 1: //Port.A
4353 case 2: //Port.A
4354 case 4: //IR
4355 case 5:
4356 case 6:
4357 case 7:
4358 case 8:
4359 case 39:
4360 case 38:
4361 case 41: //BTN
4362 case 34: //LCD-RST
4363 case 21: //MOSI
4364 case 17: //SCK
4365 case 15: //CS
4366 case 33: //RS
4367 case 16: //BL
4368 case 35: //RGB ??
4369 validPins = true;
4370 break;
4371 default:
4372 validPins = false;
4373 break;
4374 }
4375#else
4376 switch (pin)
4377 {
4378 case -1: // support this as a power
4379 case 0: //Main button hod 2s ???
4380 case 26: //Port.A
4381 case 32: //Port.A
4382 case 12: //IR
4383 case 22:
4384 case 19:
4385 case 23:
4386 case 25:
4387 case 39: //BTN
4388 // don't know these ...
4389 case 34: //LCD-RST ??
4390 case 21: //MOSI
4391 case 17: //SCK
4392 case 15: //CS
4393 case 33: //RS
4394 case 16: //BL
4395 case 27: //LED ??
4396 // case 2: //?? added 7.25.26
4397 validPins = true;
4398 break;
4399 default:
4400 validPins = false;
4401 }
4402#endif
4403 if (!validPins)
4404 {
4405 SerialError.printf("**** Invalid pin: %d, %s\n", pin, pinUseSample);
4406 return false;
4407 }
4408 //! 5.3.25 create storage here
4409 char *pinUse = (char*)calloc(strlen(pinUseSample)+1, sizeof(char));
4410 strcpy(pinUse, pinUseSample);
4411 //!store globally
4413 //! 8.30.25 add the pin
4415
4416 //! increment
4418
4420 {
4421 SerialError.printf("*** ERROR .. too many PINS defined ***");
4423
4424 }
4425
4426 SerialDebug.printf("** PIN_USE: %s = %d, module=%s %s\n", pinName.c_str(), pin, moduleName.c_str(), isI2C?"(I2C)":"");
4427
4428 return true;
4429}
4430
4431#pragma mark LED Buttons
4432#ifdef M5UNIFIED
4433
4434//! these are the constanst for the colors
4435// TFT_WHITE, TFT_CYAN, TFT_RED, TFT_YELLOW, TFT_BLUE, TFT_GREEN
4436
4437
4439#define MAX_COLORS 6
4440//! 7.24.25 return a (semi) random color
4443 int color = TFT_BLUE;
4444 switch (_randomColorIndex) {
4445 case 0:
4446 color = TFT_WHITE;
4447 break;
4448 case 1:
4449 color = TFT_CYAN;
4450 break;
4451 case 2:
4452 color = TFT_RED;
4453 break;
4454 case 3:
4455 color = TFT_YELLOW;
4456 break;
4457 case 4:
4458 color = TFT_BLUE;
4459 break;
4460
4461 default:
4462 case 5:
4463 color = TFT_GREEN;
4464 break;
4465 }
4466 return color;
4467}
4468//! returns a string for the color int
4469String getColorStringUnified(int color)
4470{
4471 String colorString = "TFT_RED";
4472 switch (color) {
4473 case TFT_WHITE: colorString = "TFT_WHITE"; break;
4474 case TFT_CYAN: colorString = "TFT_CYAN"; break;
4475 case TFT_RED: colorString = "TFT_RED"; break;
4476 case TFT_YELLOW: colorString = "TFT_YELLOW"; break;
4477 case TFT_BLUE: colorString = "TFT_BLUE"; break;
4478
4479 default:
4480 case TFT_GREEN: colorString = "TFT_GREEN"; break;
4481 }
4482 return colorString;
4483}
4484//!this is the M5UNIFIED version ...
4485//! uses the color numbers TFT_GREEN, etc
4486void setLEDColorUnified(int color)
4487{
4488 SerialLots.printf("setLEDColorUnified%s)\n", getColorStringUnified(color));
4489 M5.Led.setAllColor(color);
4490}
4491#endif
4492
4493//! 7.24.25 return a (semi) random color
4495{
4497 ColorsUnified color = RED_LED;
4498 switch (_randomColorIndex) {
4499 case 0:
4500 color = WHITE_LED;
4501 break;
4502 case 1:
4503 color = CYAN_LED;
4504 break;
4505 case 2:
4506 color = RED_LED;
4507 break;
4508 case 3:
4509 color = YELLOW_LED;
4510 break;
4511 case 4:
4512 color = BLUE_LED;
4513 break;
4514 default:
4515 case 5:
4516 color = GREEN_LED;
4517 break;
4518 }
4519 return color;
4520}
4521//! returns a string for the color int
4523{
4524 String colorString = "RED_LED";
4525 switch (color) {
4526 case RED_LED: colorString = "RED_LED"; break;
4527 case BLUE_LED: colorString = "BLUE_LED"; break;
4528 case GREEN_LED: colorString = "GREEN_LED"; break;
4529 case YELLOW_LED: colorString = "YELLOW_LED"; break;
4530 case CYAN_LED: colorString = "CYAN_LED"; break;
4531
4532 default:
4533 case WHITE_LED: colorString = "WHITE_LED"; break;
4534 }
4535 return colorString;
4536}
4537
4538//! uses colors.. _GREEN to be typed values
4540{
4541 SerialDebug.printf("setLEDColor(%s)\n", getColorString(color));
4542#ifdef M5UNIFIED
4543 // M5.Led.setAllColor(color);
4544 setLEDColorUnified((int)color);
4545#else
4546 //! Anyone?
4547 SerialDebug.printf("setLEDColor(%s) NOT IMPLEMENTED\n", getColorString(color));
4548#endif
4549
4550}
4551
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 buttonB_ShortPress()
the short press of the side button
void buttonA_LongPress()
long press on buttonA (top button)
void buttonB_LongPress()
the long press of the side button
void buttonA_ShortPress()
ButtonProcessing
void addToTextMessages_displayModule(String text)
void redrawSemanticMarker_displayModule(boolean startNew)
redraws the 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 buttonA_LongLongPress_M5Core2Module()
long press on buttonA (top button)
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()
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:68
void initCallbacksMain()
init the callbacks to dummy callbacks
Definition: MainModule.cpp:848
boolean _longPressB_MainModule
Definition: MainModule.cpp:40
#define MESSAGE_STORAGE_MAX
global for others to use..
Definition: MainModule.cpp:372
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:956
boolean _asyncCallOTAUpdateFlag
3.28.22 .. implemented in ESP_IOT.ino
boolean _stopAllProcessing
testing..
Definition: MainModule.cpp:346
M5Atom_Core2ModuleClass * _M5Atom_Core2ModuleClass
Definition: MainModule.cpp:59
char * createCopy2(const char *stringA)
#define CALLBACKS_MQTT
8.16.25 MQTT
Definition: MainModule.cpp:789
void main_updateMQTTInfo(char *ssid, char *ssid_password, char *username, char *password, char *guestPassword, char *deviceName, char *host, char *port, char *locationString)
sets the WIFI and MQTT user/password. It's up to the code (below, maybe in future a register approach...
ChainButtonClass * _ChainButtonClass
Definition: MainModule.cpp:114
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:387
boolean registerPinUse_mainModule(long pin, String pinName, String moduleName, boolean isI2C)
SensorClassType * _SensorClassTypes[NUM_SENSOR_CLASS_TYPES]
Definition: MainModule.cpp:118
#define CALLBACKS_MAX_BLE_SERVER
Definition: MainModule.cpp:806
KeyUnitSensorClass * _KeyUnitSensorClass
Definition: MainModule.cpp:110
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:834
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:106
char * groupTopicFullName(char *groupName)
returns a groupTopic to use as a topic
char * _OFF_LIGHT
char _smMode_MainModule[10]
current smMode
Definition: MainModule.cpp:377
void loop_mainModule()
called for the loop() of this plugin
Definition: MainModule.cpp:541
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:881
#define NUM_M5ATOM_CLASS
Definition: MainModule.cpp:73
M5Atom_HDriverModuleClass * _M5Atom_HDriverModuleClass
Definition: MainModule.cpp:57
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:810
boolean _longLongPressB_MainModule
Definition: MainModule.cpp:41
#define CALLBACKS_MAX_MQTT
Definition: MainModule.cpp:803
void initGlobals_mainModule()
init globals strings
Definition: MainModule.cpp:392
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:379
void initSensorClassTypeArray()
Definition: MainModule.cpp:205
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
void setLEDColorUnified(int color)
int _thresholdLUXLight
#define CALLBACKS_BLE_SERVER
Definition: MainModule.cpp:792
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:724
void onStatusMessageBLEServerCallback(char *message)
The callback for "status messages" of the bluetooth.
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:706
char _scannedGroupTopicName[100]
M5Atom_CameraModuleClass * _M5Atom_CameraModuleClass
Definition: MainModule.cpp:65
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()
buttonB will set the _shortPressB .. fields
uint32_t _chipID_MainModule
3.17.24 the unqiue chip id
void main_credentialsUpdated()
moved here 4.25.22 (entirely from ESP_IOT.ino)
void setup_mainModule()
called from the setup()
Definition: MainModule.cpp:412
void loopSensorClassTypeArray()
11.27.25 Turkey Day, loop
Definition: MainModule.cpp:121
void main_dispatchSyncCommand(int syncCallCommand)
the main sync command (no parameters yet)
boolean stopAllProcesses_mainModule()
if stopped
Definition: MainModule.cpp:358
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:112
boolean isTrueString_mainModule(String valCmdString)
whether the string is TRUE, ON, 1
Definition: MainModule.cpp:918
char * main_getPassword()
return password
boolean _shortPressB_MainModule
Definition: MainModule.cpp:39
int whichSMMode_mainModule(char *cmd)
************** SM Mode Processing ***************
M5Atom_SocketModuleClass * _M5Atom_SocketModuleClass
instances of the M5AtomClassType
Definition: MainModule.cpp:53
void main_dispatchAsyncCommandWithString(int asyncCallCommand, char *parameter)
char _bigMessage[500]
Definition: MainModule.cpp:383
void initAsyncCallFlags()
initialize the async call flags (with and without parameters)
boolean _doublePressB_MainModule
Definition: MainModule.cpp:42
String getColorStringUnified(int color)
returns a string for the color int
void solidLightMessageCallback(char *message)
callback for SOLID blinking led
M5AtomClassType * _M5AtomClassTypes[NUM_M5ATOM_CLASS]
3.31.25 create array of plugs
Definition: MainModule.cpp:76
M5AtomClassType * _whichM5AtomClassType
use this one...
Definition: MainModule.cpp:79
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:315
bool containsSubstring(String message, String substring)
check if the string contains the other string. This is a poor man's grammer checker
Definition: MainModule.cpp:765
void decrementSMMode_mainModule()
increment the currentSMMode, wrapping and using the max menu
M5Atom_QRCodeModuleClass * _M5Atom_QRCodeModuleClass
Definition: MainModule.cpp:55
void onWriteBLEServerCallbackFinish(char *message)
The FINISH of callback for "onWrite" of the bluetooth "onWrite'.
char _serialBuffer[300]
Definition: MainModule.cpp:538
void callCallbackMain(int callbacksModuleId, int callbackType, char *message)
performs the indirect callback based on the callbackType
Definition: MainModule.cpp:900
int getCurrentSMMode_mainModule()
returns the current SM Mode
boolean _longPress_MainModule
Definition: MainModule.cpp:33
boolean _waitingForBigMessageEnd
store a big message #MSG_START .. #MSG_END
Definition: MainModule.cpp:382
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:308
void stopProcessesForOTAUpdate_mainModule()
stop all loops... while OTA working..
Definition: MainModule.cpp:348
void feedMessageCallback(char *message)
Definition: MainModule.cpp:977
void resetFeedCount_mainModule()
sets the feed count max
Definition: MainModule.cpp:759
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:830
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:730
char _connectedBLEDeviceName[50]
saved BLE connected name 8.26.22
Definition: MainModule.cpp:385
char * _lastSemanticMarkerDocFollow
char _connectedBLEDeviceAddress[50]
full: ""Address: 7c:9e:bd:48:af:92, serviceUUID: 0xdead"
Definition: MainModule.cpp:389
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:805
String getColorString(ColorsUnified color)
returns a string for the color int
int getRandomColorUnified()
7.24.25 return a (semi) random color
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:845
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
long _randomColorIndex
these are the constanst for the colors
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:336
void setLUXThreshold_mainModule(int thresholdKind, int luxVal)
set the threshold val
boolean _callbacksInitializedMain
flag for initializing if not yes
Definition: MainModule.cpp:827
#define CALLBACKS_BLE_CLIENT
Definition: MainModule.cpp:791
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:370
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:704
BuzzerSensorClass * _BuzzerSensorClass
Definition: MainModule.cpp:108
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:368
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:353
char * main_getScannedDeviceName()
return devicename
char * createCopy(char *stringA)
#define CALLBACKS_MAX_BUTTON_MODULE
Definition: MainModule.cpp:804
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:375
void main_printModuleConfiguration()
M5Atom_TinyGPSModuleClass * _M5Atom_TinyGPSModuleClass
Definition: MainModule.cpp:62
void messageSetVal_mainModule(char *setName, char *valValue, boolean deviceNameSpecified)
Definition: MainModule.cpp:929
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)
boolean _doublePress_MainModule
Definition: MainModule.cpp:35
char * main_nextJSONWIFICredential()
! cycle through the next WIFI saved credential
void onBLEServerCallback(char *message)
The callback for "onWrite" of the bluetooth "onWrite'.
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:790
char _messageStorage[MESSAGE_STORAGE_MAX]
Definition: MainModule.cpp:373
void incrementFeedCount_mainModule()
increments .. and if MAX goes to 0 – and sends a message on MQTT
Definition: MainModule.cpp:737
void messageSetVal_SensorClassTypeArray(char *setName, char *valValue, boolean deviceNameSpecified)
Definition: MainModule.cpp:168
void espUpdate_mainModule(int num)
the Update aggrgate
Definition: MainModule.cpp:521
void main_saveWIFICredentials(char *ssid, char *ssid_password)
save the WIFI credential
#define MAX_COLORS
ColorsUnified getRandomColor()
7.24.25 return a (semi) random color
void espBegin_mainModule(int num)
Definition: MainModule.cpp:508
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..
void setLEDColor(ColorsUnified color)
uses colors.. _GREEN to be typed values
int _callbacksFunctionsMAXS[CALLBACKS_MODULE_MAX]
the array of callback functions
Definition: MainModule.cpp:824
#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:207
#define MAX_SM_MIN_MODES
note for now, heep the max the same – so only goes through zoom or not zoom
Definition: MainModule.h:405
void cleanEPROM_mainModule()
cleans the main module EPROM
#define ASYNC_CALL_MAX
the max one greater than last one
Definition: MainModule.h:238
#define THRESHOLD_KIND_DARK
Definition: MainModule.h:78
#define ASYNC_REBOOT
sets the GATEWAY mode off
Definition: MainModule.h:223
#define ASYNC_CALL_BLE_CLIENT_PARAMETER
these are the async with a string parameter. This sends a BLE command unless MQTT
Definition: MainModule.h:241
#define ASYNC_REST_CALL_MESSAGE_PARAMETER
send REST call
Definition: MainModule.h:249
#define ASYNC_SEND_MQTT_FEED_MESSAGE
sends a message (like FEED) on the users topic
Definition: MainModule.h:213
#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:247
#define ASYNC_CALL_CLEAN_CREDENTIALS
cleans out the credentials and restarts in AP (Access Point) mode.
Definition: MainModule.h:203
#define ASYNC_SWAP_WIFI
swaps WIFI 'w'
Definition: MainModule.h:230
#define ASYNC_SET_GATEWAY_ON
sets the GATEWAY mode on
Definition: MainModule.h:218
#define MAX_SM_EXPANDED_MODES
Definition: MainModule.h:406
#define ASYNC_RESTART_WIFI_MQTT
restarts the WIFI (after BLE interrupt over)
Definition: MainModule.h:234
#define THRESHOLD_KIND_LIGHT
Definition: MainModule.h:77
#define SYNC_CLICK_SOUND
Definition: MainModule.h:268
#define PIN_USE_MAX
Definition: MainModule.h:509
#define ASYNC_CALL_BUZZ_ON
sends a 'B' to the BLE end of the code (assuming a feeder is connected).
Definition: MainModule.h:209
#define ASYNC_POWEROFF
sets the GATEWAY mode off
Definition: MainModule.h:225
#define ASYNC_CALL_CLEAN_EPROM
cleans the EPROM totally, and reboots
Definition: MainModule.h:205
#define ASYNC_BLANKSCREEN
blank the screen
Definition: MainModule.h:227
#define ASYNC_CALL_PARAMETERS_MAX
the max one greater than last one
Definition: MainModule.h:251
#define ASYNC_SEND_MQTT_STATUS_URL_MESSAGE
sends the status from the main module URL
Definition: MainModule.h:215
#define ASYNC_SET_GATEWAY_OFF
sets the GATEWAY mode off
Definition: MainModule.h:220
#define ASYNC_CALL_OTA_FILE_UPDATE_PARAMETER
these are the async with a string parameter
Definition: MainModule.h:243
#define ASYNC_CALL_OTA_UPDATE
TODO: make this a registeration approach.
Definition: MainModule.h:201
#define TOPIC_TO_SEND
Definition: MainModule.h:65
ColorsUnified
Definition: MainModule.h:535
@ CYAN_LED
Definition: MainModule.h:539
@ WHITE_LED
Definition: MainModule.h:541
@ BLUE_LED
Definition: MainModule.h:537
@ YELLOW_LED
Definition: MainModule.h:540
@ GREEN_LED
Definition: MainModule.h:538
@ RED_LED
Definition: MainModule.h:536
#define ASYNC_NEXT_WIFI
next WIFI 'n'
Definition: MainModule.h:232
#define ASYNC_CALL_BUZZ_OFF
sends a 'b' to the BLE end of the code (assuming a feeder is connected).
Definition: MainModule.h:211
#define ASYNC_CLICK_SOUND
5.15.25 add a BUZZ command (or CLICK)
Definition: MainModule.h:236
#define ASYNC_JSON_MESSAGE_PARAMETER
these are the async with a string parameter
Definition: MainModule.h:245
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..
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
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
virtual void loop()=0
Pure Virtual Function.
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:515
char * pinUseArray[PIN_USE_MAX]
string describing the module, etc
Definition: MainModule.h:513
SensorClassType * sensorClassType
and the pointer to matching SensorClassType
SensorStruct * sensors
array of sensorStruct