ESP_IOT v2.5
IOT ESP Coding
DisplayModule.cpp
Go to the documentation of this file.
1#include "DisplayModule.h"
2#ifdef USE_DISPLAY_MODULE
3//! \link DisplayModule
4//!@see https://www.carletonsheets.com/assets/shared/usr/share/doc/doxygen-1.8.5/html/commands.html#cmdlink
5
6//!@see https://docs.m5stack.com/en/api/stickc/lcd_m5stickc
7//!@see https://github.com/m5stack/M5StickC-Plus
8//!@see https://docs.m5stack.com/en/core/m5stickc_plus
9//!@see https://docs.m5stack.com/en/api/core2/lcd_api (for the Core2)
10/**
11 * System:
12 * M5.begin();
13 *
14 * LCD:
15 * M5.Lcd.drawPixel(int16_t x, int16_t y, uint16_t color);
16* M5.Lcd.drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color);
17* M5.Lcd.fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color);
18* M5.Lcd.fillScreen(uint16_t color);
19* M5.Lcd.drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color);
20* M5.Lcd.drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername,uint16_t color);
21* M5.Lcd.fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color);
22* M5.Lcd.fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername,int16_t delta, uint16_t color);
23* M5.Lcd.drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color);
24* M5.Lcd.fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color);
25* M5.Lcd.drawRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, int16_t radius, uint16_t color);
26* M5.Lcd.fillRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, int16_t radius, uint16_t color);
27* M5.Lcd.drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color);
28* M5.Lcd.drawRGBBitmap(int16_t x, int16_t y, const uint16_t bitmap[], int16_t w, int16_t h),
29* M5.Lcd.drawChar(uint16_t x, uint16_t y, char c, uint16_t color, uint16_t bg, uint8_t size);
30* M5.Lcd.setCursor(uint16_t x0, uint16_t y0);
31* M5.Lcd.setTextColor(uint16_t color);
32* M5.Lcd.setTextColor(uint16_t color, uint16_t backgroundcolor);
33* M5.Lcd.setTextSize(uint8_t size);
34* M5.Lcd.setTextWrap(boolean w);
35* M5.Lcd.printf();
36* M5.Lcd.print();
37* M5.Lcd.println();
38* M5.Lcd.drawCentreString(const char *string, int dX, int poY, int font);
39* M5.Lcd.drawRightString(const char *string, int dX, int poY, int font);
40 //M5.Lcd.drawJpg(const uint8_t *jpg_data, size_t jpg_len, uint16_t x, uint16_t y);
41 //M5.Lcd.drawJpgFile(fs::FS &fs, const char *path, uint16_t x, uint16_t y);
42 //M5.Lcd.drawBmpFile(fs::FS &fs, const char *path, uint16_t x, uint16_t y);
43 *
44 */
45/***************************************************************************************
46 ** Function name: setRotation In
47 ** Description: rotate the screen orientation m = 0-3 or 4-7 for BMP drawing
48 ***************************************************************************************/
49/*
50 void TFT_eSPI::setRotation(uint8_t m)
51 */
52#ifdef ESP_M5_LATER
53
54//!new design for the pairing and dynamic discovery and pairing..
55
56//!defined in icon.c
57//extern const unsigned char bitmap[13424];
58//! draws the bitmap .. for testing
59void drawBitmapIcon()
60{
61 // M5.Lcd.drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color);
62 // M5.Lcd.drawRGBBitmap(int16_t x, int16_t y, const uint16_t bitmap[], int16_t w, int16_t h),
63
64 M5.Lcd.drawRGBBitmap(0,0, (uint16_t *)bitmap, 135,100);
65}
66#endif //later..
67
68#ifdef M5CORE2_MODULE
69boolean _showScrollingTextWindow = false;
70
71#define SHOW_BIG_BUTTON
72//! the BIG BUTTON is green and says Feed
73/**
74 1.24.24 First attempt at using the M5Core2 display to show something other than the M5 display
75 1. scrolling text
76 */
77#endif
78
79//! 1.24.24 as alternate display windows are introducted,
80//! let others know and don't overright stuff..
81boolean inAlternateDisplay_displayModule()
82{
83#ifdef M5CORE2_MODULE
84 //! if showing the scrolling window .. don't do the rest ..
85 return _showScrollingTextWindow;
86#else
87 return false;
88#endif
89}
90
91//!prints the text up to the maxLen (the setup of position, etc is already done)
92void printText(String text, int maxLen);
93
94//!default semantic marker (or the current one)
95String _currentSemanticMarkerAddress="https://iDogWatch.com";
96/**
97* \image html IMG_4616.PNG "AR + Semantic Marker"
98*/
99//!returns the current semantic marker (eg. guest page)
101{
102 return _currentSemanticMarkerAddress.c_str();
103}
104String _lastSemanticMarkerAddress = "";
105//!default semantic title
106String _semanticTitle = "M5 Clicker";
107//!base http address of semantic markers
108String _currentSemanticMarkerAddressBase = "https://iDogWatch.com";
109//!stores the statusFunc (it's a pointer to a function)
110const char* (*_getStatusFunc)(void) = NULL;
111
112//!if blank, then only show something after a click (not a message)
113boolean _semanticMarkerShown = false;
114
115//! 1.26.24 10 seems to be working..
116#define SEMANTIC_MARKER_QR_VERSION 10
117
118//!The type of screen (not the SM_home, etc, but using the SemanticTitle)
119//!NORMAL for normal display .. we can use NORMAL for the first page..
120#define SCREEN_TYPE_NORMAL 0
121//! for home screen
122#define SCREEN_TYPE_HOME 1
123#define SCREEN_TYPE_STATUS 2
124#define SCREEN_TYPE_HELP 3
125#define SCREEN_TYPE_WIFI 4
126#define SCREEN_TYPE_TILT 5
127#define SCREEN_TYPE_BUZZ 6
128#define SCREEN_TYPE_AP 7
129#define SCREEN_TYPE_GUEST_PAGE 8
130#define SCREEN_TYPE_FEED_GUEST 9
131#define SCREEN_TYPE_PAIRED_DEV 10
132#define SCREEN_TYPE_RESET 11
133#define SCREEN_TYPE_REBOOT 12
134//!try simple menu
135#define SCREEN_TYPE_HOME_SIMPLE 13 //tilt
136#define SCREEN_TYPE_HOME_SIMPLE_1 14 //buzz
137#define SCREEN_TYPE_HOME_SIMPLE_2 15 //feed
138#define SCREEN_TYPE_HOME_SIMPLE_3 16 //advanced
139#define SCREEN_TYPE_DOC_FOLLOW 17 //docFollow
140#define SCREEN_TYPE_TIMER 18 //timer
141
142//!the current screen type (a side effect of asking for it)
143int _currentScreenType = SCREEN_TYPE_NORMAL;
144
145//!returns the screen type (f0..n) for the title (such as HOME) NOTE: if the name changes .. ramifications
146//! So they match the MQTTNetwork title strings..
147int screenTypeForTitle_displayModule(String title)
148{
149 //!NOTE: All the comparisons are ALL CAPS ...
150 title.toUpperCase();
151 int screenType = SCREEN_TYPE_NORMAL;
152 if (title.compareTo("MINI CLICKER")==0)
153 {
154 screenType = SCREEN_TYPE_HOME_SIMPLE;
155 }
156 else if (title.compareTo("MINI-1")==0)
157 {
158 screenType = SCREEN_TYPE_HOME_SIMPLE_1;
159 }
160 else if (title.compareTo("MINI-2")==0)
161 {
162 screenType = SCREEN_TYPE_HOME_SIMPLE_2;
163 }
164 //!ADD SCREEN_TYPE_HOME
165
166 else if (title.compareTo("MINI-3")==0)
167 {
168 screenType = SCREEN_TYPE_HOME_SIMPLE_3;
169 }
170 //rest are normal
171 else if (title.compareTo("WIFI FEED")==0)
172 {
173 screenType = SCREEN_TYPE_HOME;
174 }
175 else if (title.startsWith("HELP"))
176 {
177 screenType = SCREEN_TYPE_HELP;
178 }
179 else if (title.startsWith("WIFI"))
180 {
181 screenType = SCREEN_TYPE_WIFI;
182 }
183 else if (title.startsWith("TILT"))
184 {
185 screenType = SCREEN_TYPE_TILT;
186 }
187 else if (title.startsWith("BUZZ"))
188 {
189 screenType = SCREEN_TYPE_BUZZ;
190 }
191 else if (title.startsWith("AP"))
192 {
193 screenType = SCREEN_TYPE_AP;
194 }
195 else if (title.startsWith("GUEST PAGE"))
196 {
197 screenType = SCREEN_TYPE_GUEST_PAGE;
198 }
199 else if (title.startsWith("FEED GUEST"))
200 {
201 screenType = SCREEN_TYPE_FEED_GUEST;
202 }
203 else if (title.startsWith("STATUS"))
204 {
205 screenType = SCREEN_TYPE_STATUS;
206 }
207 else if (title.startsWith("RESET"))
208 {
209 screenType = SCREEN_TYPE_RESET;
210 }
211 else if (title.startsWith("DOC FOLLOW"))
212 {
213 screenType = SCREEN_TYPE_DOC_FOLLOW;
214 }
215 else if (title.startsWith("REBOOT"))
216 {
217 screenType = SCREEN_TYPE_REBOOT;
218 }
219 else if (title.startsWith("TIMER"))
220 {
221 screenType = SCREEN_TYPE_TIMER;
222 }
223 //! the "P:" is a special token from the MQTT that denotes this is a pairing feed. The P: is replaced with the paired device
224 else if (title.startsWith("P:"))
225 {
226 screenType = SCREEN_TYPE_PAIRED_DEV;
227 }
228 //set global used by callers of addToTextMessages_displayModule
229 _currentScreenType = screenType;
230 return screenType;
231}
232
233
234
235//!These are when the ESP_M5 isn't used, so the code below compiles..
236#ifdef ESP_M5
237#else
238//!unused .. for now since no display
239#define BLACK 100
240#define WHITE 101
241#define YELLOW 102
242#define BLUE 103
243#define RED 104
244#define ORANGE 105
245
246#endif
247#ifdef M5CORE2_MODULE
248#define WIDTH 320
249#else
250#define WIDTH 135
251#endif
252
253#define HEIGHT_3 20
254#define HEIGHT_3_2LINE 60
255
256#define HEIGHT_4 40
257
258#define HEIGHT_2 10
259#define HEIGHT_1 10
260
261#define ROTATE_0 0
262#define FONT_3 3
263#define FONT_2 2
264#define FONT_1 1
265
266//!defines the position constants
267//!Note some uses below just use the text color and size attributes, (Too much work to make a variable struct)
268//! eg. ORANGE,WHITE,BLACK
269typedef struct TextPosition
270{
271 uint16_t x,y;
272 uint16_t width, height;
273 uint16_t textSize;
274 uint16_t textColor;
275 uint16_t textColorBackground;
276 uint16_t blankColor;
277
278 uint16_t rotation; // 0
279 uint16_t maxLen; // 0
280
281} TextPositionStruct;
282
283//!EG: #actMe (M5) { ksjdfkdsjfk
284//! Feed Guest
285//!based on text size 3
286TextPositionStruct _actionTextPosition = {0,2,WIDTH,HEIGHT_2,FONT_2,BLUE,WHITE,BLACK,ROTATE_0,11};
287TextPositionStruct _actionTextPositionZoomed = {0,2,WIDTH,HEIGHT_3_2LINE,FONT_3,BLUE,WHITE,BLACK,ROTATE_0,14};
288TextPositionStruct _actionTextHomePositionZoomed= {0,2,WIDTH,HEIGHT_3_2LINE,FONT_3,ORANGE,BLACK,BLACK,ROTATE_0,14}; //28};
289// the simple title (MINI CLICKER)
290TextPositionStruct _actionTextHomeSimplePositionZoomed = {0,2,WIDTH,HEIGHT_3_2LINE,FONT_3,YELLOW,BLUE,BLACK,ROTATE_0,15}; //28};
291TextPositionStruct _actionTextHomeSimplePositionZoomed_1= {0,2,WIDTH,HEIGHT_3_2LINE,FONT_3,BLUE,YELLOW,BLACK,ROTATE_0,15}; //28};
292TextPositionStruct _actionTextHomeSimplePositionZoomed_2= {0,2,WIDTH,HEIGHT_3_2LINE,FONT_3,BLACK,GREEN,BLACK,ROTATE_0,15}; //28};
293TextPositionStruct _actionTextHomeSimplePositionZoomed_3= {0,2,WIDTH,HEIGHT_3_2LINE,FONT_3,BLACK,WHITE,BLACK,ROTATE_0,15}; //28};
294TextPositionStruct _actionTextHomeSimplePositionZoomed_4= {0,2,WIDTH,HEIGHT_3_2LINE,FONT_3,WHITE,RED,BLACK,ROTATE_0,15}; //28};
295
296//! these are grouped in an array for the color index to use. If index > max then use max.. (-1)
297#define MAX_ACTION_TEXT_HOME_COLORS 5
298TextPositionStruct _actionTextHomeSimpleColor[MAX_ACTION_TEXT_HOME_COLORS] =
299{
300 _actionTextHomeSimplePositionZoomed,
301 _actionTextHomeSimplePositionZoomed_1,
302 _actionTextHomeSimplePositionZoomed_2,
303 _actionTextHomeSimplePositionZoomed_3,
304 _actionTextHomeSimplePositionZoomed_4,
305};
306
307//! mode is the status of sensors .
308TextPositionStruct _sensorStatusTextPosition = {0,27,WIDTH,HEIGHT_2,FONT_2,WHITE,BLACK,BLACK,ROTATE_0,22};
309TextPositionStruct _sensorStatusTextPositionZoomed = {0,65,WIDTH,HEIGHT_3,FONT_2,WHITE,BLACK,BLACK,ROTATE_0,22};
310
311TextPositionStruct _helpStatusTextPosition =
312 {0,65,WIDTH,HEIGHT_3,FONT_2,ORANGE,BLACK,BLACK,ROTATE_0,22};
313//! Help
314TextPositionStruct _multilineStatusTextPosition = {0,27,WIDTH,HEIGHT_4,FONT_2,WHITE,BLACK,BLACK,ROTATE_0,40};
315TextPositionStruct _multilineStatusTextPositionZoomed = {0,65,WIDTH,HEIGHT_4,FONT_2,WHITE,BLACK,BLACK,ROTATE_0,40};
316
317#ifdef M5CORE2_MODULE
318//! 2.10.24 on M5Core2 there is a line under "MINI CLICKER" that can show the Device name and pair=
319TextPositionStruct _moduleDeviceNameTextPosition = {0,40,WIDTH,HEIGHT_3,FONT_3,YELLOW,BLUE,BLACK,ROTATE_0,30};
320#endif
321//!status are the state modules (WIFI ON/off, etc)
322TextPositionStruct _moduleStatusTextPosition = {0,67,WIDTH,HEIGHT_3,FONT_3,YELLOW,BLUE,BLACK,ROTATE_0,7};
323TextPositionStruct _moduleStatusTextPositionZoomed = {0,105,WIDTH,HEIGHT_3,FONT_3,YELLOW,BLUE,BLACK,ROTATE_0,7};
324
325//! new for the SM_HOME_SIMPLE
326TextPositionStruct _homeSimpleStatusTextPositionZoomed = {0,105,WIDTH,HEIGHT_3,FONT_3,ORANGE,BLACK,BLACK,ROTATE_0,7};
327//! new for the SM_HOME_SIMPLE - draws FEED as red if over 13 feeds..
328TextPositionStruct _homeSimpleStatusTextPositionZoomedRED = {0,105,WIDTH,HEIGHT_3,FONT_3,RED,BLACK,BLACK,ROTATE_0,7};
329
330//! the position of "connected" at the bottom on the first 3 screens..
331TextPositionStruct _connectedStatusTextPositionZoomed = {0,213,WIDTH,HEIGHT_2,FONT_2,WHITE,BLACK,BLACK,ROTATE_0,11};
332
333//!new Menu selection (if 4 ..)
334TextPositionStruct _menuTextPositionZoomed_4less = {0,105,WIDTH,HEIGHT_3,FONT_3,ORANGE,BLACK,BLACK,ROTATE_0,7};
335TextPositionStruct _menuTextPositionZoomed_4plus = {0,105,WIDTH,HEIGHT_2,FONT_2,ORANGE,BLACK,BLACK,ROTATE_0,22};
336
337
338//top == feed, bottom = semantic marker (or the action of it)..{
339#define BIG_ACTION 0
340#define SM_ACTION 1
341#define SM_ACTION_SMALL 2
342#define QRAVATAR_ACTION 3
343
344#define MAX_ACTIONS 4
345
346#define TRY_SWAPPED_COLORS
347#ifdef TRY_SWAPPED_COLORS
348TextPositionStruct _zoomedTextPositions[MAX_ACTIONS] = {
349 {0,145,WIDTH,HEIGHT_3,FONT_3,ORANGE,BLACK,BLACK,ROTATE_0,7},
350 {0,180,WIDTH,HEIGHT_3,FONT_3,WHITE,BLUE,BLACK,ROTATE_0,7},
351
352 //the smaller WIFI words (without feed..)
353 {0,145,WIDTH,HEIGHT_2,FONT_2,WHITE,BLACK,BLACK,ROTATE_0,40},
354 //the avatar character.. not perfect Blue on Yellow -- how about Red
355 {50,150,1,HEIGHT_3,FONT_3,RED,YELLOW,BLACK,ROTATE_0,2}
356};
357#else
358TextPositionStruct _zoomedTextPositions[MAX_ACTIONS] = {
359 {0,145,WIDTH,HEIGHT_3,FONT_3,WHITE,BLUE,BLACK,ROTATE_0,7},
360 {0,180,WIDTH,HEIGHT_3,FONT_3,WHITE,BLACK,BLACK,ROTATE_0,7},
361 //!home screens bottom action
362 {0,180,WIDTH,HEIGHT_3,FONT_3,ORANGE,BLACK,BLACK,ROTATE_0,7},
363
364 //the smaller WIFI words (without feed..)
365 {0,145,WIDTH,HEIGHT_2,FONT_2,WHITE,BLACK,BLACK,ROTATE_0,40},
366 //the avatar character.. not perfect Blue on Yellow -- how about Red
367 {50,150,1,HEIGHT_3,FONT_3,RED,YELLOW,BLACK,ROTATE_0,2}
368};
369#endif
370
371//! init the text - but override the text color (stil using the textP.blankCOlor
372void setupTextPositionOverrideTextColor(TextPositionStruct textP, TextPositionStruct textColor)
373{
374 //SerialTemp.printf("setupText(%d,%d,w=%d,h=%d)\n", textP.x, textP.y, textP.width, textP.height);
375#ifdef ESP_M5
376#ifdef M5CORE2_MODULE
377 //! DON"T rotate -- for the M5Core2 display
378#else
379 M5.Lcd.setRotation(textP.rotation);
380#endif
381 M5.Lcd.fillRect(textP.x, textP.y, textP.width, textP.height, textColor.blankColor );
382 M5.Lcd.setTextColor(textColor.textColor, textColor.textColorBackground);
383 M5.Lcd.setCursor(textP.x + 2, textP.y);
384 M5.Lcd.setTextSize(textP.textSize);
385#endif
386}
387
388//!show an OTA message..
390{
391#ifdef ESP_M5
392 // blank the area
393 M5.Lcd.fillRect(0, 60, 135, 140, ORANGE);
394 M5.Lcd.setTextColor(WHITE, BLACK);
395 M5.Lcd.setCursor(10, 90);
396 M5.Lcd.setTextSize(2);
397 M5.Lcd.println("\nStarting \nOTA Update \nPlease Wait\n2-5 minutes");
398#endif
399}
400
401//! set so it can be erased on next loop
402boolean _fullScreenMessageDisplayed = false;
403
404//! 4.3.24 show text in big letters
405//!@see https://github.com/konacurrents/ESP_IOT/issues/323
406//!show full screen message..
407void displayFullscreenMessage(String text, boolean turnOn)
408{
409#ifdef ESP_M5
410 if (turnOn)
411 {
412 _fullScreenMessageDisplayed = true;
413 // M5.Lcd.fillScreen(BLUE);
414
415 // blank the area
416 M5.Lcd.fillRect(0, 0, 135, 240, BLUE);
417 M5.Lcd.setTextColor(WHITE, BLACK);
418 M5.Lcd.setCursor(10, 90);
419 M5.Lcd.setTextSize(3);
420 M5.Lcd.print(text);
421
422 // delay then clear
423 // delay(50);
424 // redrawSemanticMarker_displayModule(false);
425 //wakeupScreen_displayModule();
426 }
427 else
428 {
429 _fullScreenMessageDisplayed = false;
430
432
433 // M5.blankscreen();
434 }
435#endif
436}
437
438//! init the text
439void setupTextPosition(TextPositionStruct textP)
440{
441 //use same color
442 setupTextPositionOverrideTextColor(textP, textP);
443
444}
445
446//!use the textPositionStruct - but override the text color
447void printTextAtTextPositionOverrideTextColor(String text, TextPositionStruct textPosition, TextPositionStruct textColor)
448{
449 setupTextPositionOverrideTextColor(textPosition, textColor);
450 //SerialDebug.printf("'%s'\n", text);
451#ifdef ESP_M5
452 M5.Lcd.print(text);
453#endif
454}
455
456//!use the textPositionStruct
457void printTextAtTextPosition(String text, TextPositionStruct textPosition)
458{
459 setupTextPosition(textPosition);
460#ifdef ESP_M5
461 M5.Lcd.print(text);
462#endif
463}
464
465
466//! SCREEN COLOR
467//!Increment the screen color 0..n cache for getting the screen color 0..max (max provided by sender)
468//!This is implemented by incrementScreenColor_mainModule() since it knows the MAX value of colors
470{
472 screenColor++;
473 if (screenColor >= MAX_ACTION_TEXT_HOME_COLORS)
474 {
475 // change color and store
476 screenColor = 0;
477 }
479
480 SerialCall.printf("incrementScreenColor_displayModule = %d\n", screenColor);
481}
482
483//!cache for getting the screen color 0..n. Will reset the cache as well
484int getScreenColor_displayModule()
485{
486 //normalize
488 if (screenColor < 0 || screenColor >= MAX_ACTION_TEXT_HOME_COLORS)
489 {
490 // normalize the number, and store it..
491 screenColor = screenColor % MAX_ACTION_TEXT_HOME_COLORS;
493 }
494 SerialLots.printf("getScreenColor_displayModule = %d\n", screenColor);
495
496 return screenColor;
497}
498
499//!cache for getting the screen color 0..n. Will reset the cache as well
500void setScreenColor_displayModule(int screenColor)
501{
502 //normalize
503 if (screenColor < 0 || screenColor >= MAX_ACTION_TEXT_HOME_COLORS)
504 {
505 // normalize the number, and store it..
506 screenColor = screenColor % MAX_ACTION_TEXT_HOME_COLORS;
507 }
509 SerialCall.printf("setScreenColor_displayModule = %d\n", screenColor);
510
511}
512
513
514
515//!markerTimer is a semi timer for the number of times before doing anything. Kinda a kludge.
516int _markerTimer = 0;
517//! ticks.. when it rest? (show to blank screen)
518int _loopTimer = 0;
519//!increment the loop timer
520void incrementLoopTimer()
521{
522 _loopTimer = (_loopTimer+1) % 100;
523}
524//!stop the loop timer
525void stopLoopTimer()
526{
527 _loopTimer = 0;
528}
529//!returns the loop timer (just a timer..)
531{
532 return _loopTimer;
533}
534
535//!reset the loop timer .. useful for testing,
537{
538 _loopTimer = 0;
539}
540/**
541* \image html SMStatus1.PNG "Semantic Marker"
542*/
543//!NOTE: need to add dev:deviceName
544//!creates semantic address, and if _getStatusFunc is non nil, call it to add to the address SemanticMarker&trade;
545String createSemanticAddress()
546{
547 //!if there is a status function to call, call it and add to the address (and tack on the _loopTimer)
548 //!Otherwise, just use the provided address (not a status like address)
549 if (_getStatusFunc)
550 {
551 SerialTemp.print("createDynamicSemanticAddress: ");
552
553 //check if this is right (the base)
554 // _currentSemanticMarkerAddress = _currentSemanticMarkerAddressBase + "/" + String((*_getStatusFunc)()) + "&t=" + String(_loopTimer);
555 _currentSemanticMarkerAddress = String((*_getStatusFunc)()) + "&t=" + String(_loopTimer);
556
557 }
558 else
559 {
560 SerialCall.print("createSemanticAddress: ");
561 _currentSemanticMarkerAddress = _currentSemanticMarkerAddressBase;
562 }
563
564
565 int maxLenForIphone = 250;
566
567 // strip down to 155 .. yanking off each parameter?? or just chop it.. for not just chop it..
568 if (_currentSemanticMarkerAddress.length() > maxLenForIphone)
569 {
570 SerialTemp.printf("1. Truncating chartacters to: %d\n", maxLenForIphone);
571 SerialTemp.println(_currentSemanticMarkerAddress);
572 _currentSemanticMarkerAddress = _currentSemanticMarkerAddress.substring(0,maxLenForIphone);
573 }
574
575 SerialTemp.println(_currentSemanticMarkerAddress);
576 return _currentSemanticMarkerAddress;
577}
578
579
580#define USE_TIMER_DELAY_CLASS
581//! 3.29.25 RaiiiinIeeeeR Beer movie
582#ifdef USE_TIMER_DELAY_CLASS
583TimerDelayClass* _timerDelayClass_DisplayModule = new TimerDelayClass(1.0);
584void startDelay(int seconds)
585{
586 _timerDelayClass_DisplayModule->startDelay((float)seconds);
587}
588boolean delayFinished()
589{
590 return _timerDelayClass_DisplayModule->delayFinished();
591}
592void stopDelay()
593{
594 _timerDelayClass_DisplayModule->stopDelay();
595}
596#else
597//**** Delay Methods*******
598#define SINGLE_DELAY
599#ifdef SINGLE_DELAY
600//https://www.forward.com.au/pfod/ArduinoProgramming/TimingDelaysInArduino.html
601//! the time the delay started
602unsigned long _delayStart;
603//! true if still waiting for delay to finish
604boolean _delayRunning = false;
605//! length of delay
606int _delaySeconds;
607//!init the delay starting
608void startDelay(int seconds)
609{
610 SerialCall.printf("startDelay_displayModule: %d\n", seconds);
611
612 _delayStart = millis(); // start delay
613 _delayRunning = true; // not finished yet
614 _delaySeconds = seconds;
615
616}
617//!if finished..
618boolean delayFinished()
619{
620 if (_delayRunning && ((millis() - _delayStart) >= (_delaySeconds * 1000)))
621 {
622 _delayRunning = false;
623 SerialCall.println("delayFinished..");
624 return true;
625 }
626 return false;
627}
628
629//!stop the delay
630void stopDelay()
631{
632 SerialCall.println("stopDelay _delayRunning=false");
633
634 _delayRunning = false;
635}
636#endif //SINGLE_DELAY
637#endif // USE_TIMER_DELAY_CLASS
638
639//****** SCREEN DISPLAY ************
640//!new 12.29.22
641//!
642//! //! https://github.com/Bodmer/TFT_eSPI/issues/226
643//! TRY THIS:
644#define BLK_PWM_CHANNEL 7 // LEDC_CHANNEL_7
645void setBrightness_displayModule(int brightness)
646{
647#ifdef LATER
648 ledcWrite(BLK_PWM_CHANNEL, brightness);
649#endif
650}
651
652//!blanks the screen
654{
655 SerialCall.println("blankScreen_displayModule");
656 stopLoopTimer();
657
658 //!stop the delay which says delay finished .. so don't show anything.. 8.9.22
659 stopDelay();
660
661 //nothing displayed
662 _semanticMarkerShown = false;
663
664#ifdef ESP_M5
665 M5.Lcd.fillScreen(BLACK);
666 //not available.. without M5Stack.h ???
667 // M5.Lcd.setBrightness(0);
668 // M5.Lcd.setBrightness(200);
669
670 //M5.Lcd.sleep();
671
672 // M5.Lcd.fillScreen(ORANGE);
673
674 //get out of all modes..
675 // #issue #144 show something to let know its screen saver not OFF
676
677 printTextAtTextPosition(" CLICKER",_connectedStatusTextPositionZoomed);
678
679
680
681#define TRY_DEVICES_AND_PAIRED
682#ifdef TRY_DEVICES_AND_PAIRED
683 {
684 char infoString[150];
685 boolean multilineScreenType;
686
687 //!update the model for those drawing Dev and Connected Dev
689
690 multilineScreenType = true;
691 //! just ask the deviceState...
693 switch (model->pairedDeviceStateEnum)
694 {
695 //paired to a device, but BLE NOT connected right now
697 sprintf(infoString,"%s\n+%.*s",deviceName_mainModule(),10,getPairedDeviceOrAddress_mainModule() );
698 break;
699 //paired to a device, and BLE connected right now
701 sprintf(infoString,"%s\n%.*s",deviceName_mainModule(),10,getPairedDeviceOrAddress_mainModule() );
702 break;
703 //not paired (but could be paired as it's a named device])
705 sprintf(infoString,"%s\n-%.*s",deviceName_mainModule(),9,connectedBLEDeviceName_mainModule());
706 break;
707 //!factory default but not connecte to anything..
708 case notConnectedEnum:
709 //sprintf(infoString,"%s\n%s",deviceName_mainModule(),(char*)"scanning..");
710 sprintf(infoString,"%s\n",deviceName_mainModule());
711
712 break;
713 }
714 SerialCall.println(infoString);
715
716 //!use the zoomed amount
717 setupTextPosition(multilineScreenType?_multilineStatusTextPositionZoomed:_sensorStatusTextPositionZoomed);
718
719 //!draw the text
720 printText(infoString,multilineScreenType?_multilineStatusTextPosition.maxLen:_sensorStatusTextPosition.maxLen);
721 }
722#else
723 //! also show the device name..
724 //! at same location as before.. the small text below the top..
725 //!use the zoomed amount
726 setupTextPosition(_sensorStatusTextPositionZoomed);
727
728 //!draw the device name (not including the parired or not paired .. as it can change dynaically...
729 printTextAtTextPosition(deviceName_mainModule(),_sensorStatusTextPosition);
730#endif
731#endif
732}
733
734//!wakes up the screen
736{
737
738 //clear screen first.. since the KEEP_SAME won't clear the screen..
740
741 // _semanticMarkerShown = true;
742 SerialCall.println("wakeupScreen_displayModule");
743
744 //!see if this works .. vs too flickering.. (if so we have to slow it down..)
746
747}
748
749//!clears the screen (but not a blank screen) and stops the timer..
751{
752 SerialCall.println("clearScreen_displayModule");
753
754 //reset the timer.. NEW!! 8.9.22 (a mini blankScreen)
755 //??
756 stopLoopTimer();
757
758#ifdef ESP_M5
759#ifdef M5CORE2_MODULE
760 //! DON"T rotate -- for the M5Core2 display
761#else
762 M5.Lcd.setRotation(0);
763#endif
764 M5.Lcd.fillScreen(BLACK);
765#endif
766}
767
768//!whether screen is blank (so the button can be a wake, vs action..)
770{
771 SerialLots.print("isBlankScreen_displayModule:");
772#ifdef USE_TIMER_DELAY_CLASS
773 boolean delayRunning = !_timerDelayClass_DisplayModule->delayFinished();
774
775#else
776 boolean delayRunning = _delayRunning;
777#endif
778 SerialLots.println(!delayRunning?"BLANK":"NOT BLANK");
779
780 //! if the delay is running, then not blanked
781 return !delayRunning;
782}
783
784//! whether to display on a blank screen
785boolean displayOnBlankScreen()
786{
788}
789
790//! current screen timeout
791int currentScreenTimeout()
792{
794 return val;
795}
796
797#ifdef ESP_M5
798//!setup the Lcd, etc..
799void setupESP_M5()
800{
801 SerialMin.println("setupESP_M5");
802
803#ifdef M5STICKCPLUS2
804//! 4.20.24 add config
805 M5.config();
806#endif
807#ifdef M5CORE2_MODULE
808 /*
809 https://arduino.stackexchange.com/questions/9092/how-do-you-call-a-class-method-with-named-parameters
810 begin(bool LCDEnable = true, bool SDEnable = true, bool SerialEnable = true,
811 bool I2CEnable = false, mbus_mode_t mode = kMBusModeOutput,
812 bool SpeakerEnable = true);
813
814 M5.begin(true, true, true, false);
815 */
816 M5.begin( /*LCDEnable*/true, /*SDEnable*/true, /*SerialEnable*/ true,
817 /*I2CEnable*/ false, /*mode*/ kMBusModeOutput,
818 /*SpeakerEnable*/ true);
819
820 //! see if this lets battery work on M5 Core2 v1.1
821 //! 2.11.24 Super Bowl day
822 //! STILL NOT WORKING on the v1.1 device
823 /*
824 M5.Axp.SetLcdVoltage(3300);
825 M5.Axp.SetBusPowerMode(0);
826 M5.Axp.SetCHGCurrent(AXP192::kCHG_190mA);
827 */
828 /*
829 M5.Power.setPowerBoostOnOff(false); //Change the power on / off method. The power does not turn off when connected via USB. true=Press and hold to turn on / off. false=Turn on / off with two short presses.
830 M5.Power.setPowerBoostSet(false); //Change the power on / off method true=ON / OFF in one short press. false=same as above
831 M5.Power.setPowerVin(true); //When the power supply from USB etc. is cut off, Decide whether to turn on the power again.
832 M5.Power.setPowerBtnEn(true); //Set whether to accept the power button.
833 M5.Power.setPowerBoostKeepOn(false); //Always output power. True= Always output power. False=not Always output power.
834 M5.Power.setAutoBootOnLoad(true); //Set whether to automatically start when power consumption occurs
835 */
836#else
837 //!Init M5StickC Plus. 初始化 M5StickC Plus
838 M5.begin();
839#endif
840
841 //!Set font size.
842 //!Set the font color to yellow. 设置字体颜色为黄色
843 M5.Lcd.setTextColor(WHITE);
844 //!rotate to landscape (vs vertical)
845 //!M5.Lcd.setRotation(3);
846#ifdef M5CORE2_MODULE
847 //! DON"T rotate -- for the M5Core2 display
848 SerialMin.println("M5CORE2_MODULE");
849 M5.Lcd.drawCircle(65,220, 10, WHITE);
850 M5.Lcd.drawCircle(155,220, 10, WHITE);
851 M5.Lcd.drawCircle(255,220, 10, WHITE);
852
853 //! * M5.Lcd.drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color);
854
855#else
856 //!Rotate the screen. 将屏幕旋转
857 M5.Lcd.setRotation(0);
858#endif
859 //!set the cursor location. 设置光标位置
860
861 //!Set font size.
862
863 M5.Lcd.setTextSize(2);
864 // M5.Lcd.printf("Click Controller v1.0");
865
866 //! STARTUP SCREEN showing VERSION
867 M5.Lcd.printf("%s", VERSION);
868
869 //!Draws a SemanticMarker&trade; (using QR code)
870 //!Create a QR code with a width of 135 QR code at (0, 100). 在(0,0)处创建一个宽为135二维码
871 //!Please select the appropriate QR code version according to the number of characters. 请根据字符数量选择合适的二维码版本
872 M5.Lcd.qrcode("https://iDogWatch.com/bot/help",0,100,135,SEMANTIC_MARKER_QR_VERSION);
873 //try to draw a character in the middle ...
874 printTextAtTextPosition("SM",_zoomedTextPositions[QRAVATAR_ACTION]);
875 //delay so they can read it a little bit..
876 delay(550);
877
878 //blank screen is on..
879}
880#endif //ESP_M5
881
882//!THIS IS the setup() and loop() but using the "component" name, eg MQTTNetworking()
883//!This will perform preference initializtion as well
884//! called from the setup()
886{
887#ifdef ESP_M5
888 setupESP_M5();
889#endif
890
891 //this is supposed to say it's not in blank screen...
892 //stopDelay();
893 startDelay(60);
894
895}
896
897//! used to create a mini
898int _fullscreenLoopCount = 0;
899
900//! called for the loop() of this plugin
902{
903 //! set so it can be erased on next loop
904 if (_fullScreenMessageDisplayed)
905 {
906 _fullscreenLoopCount ++;
907 if (_fullscreenLoopCount > 10)
908 {
909 displayFullscreenMessage("", false);
910 _fullscreenLoopCount = 0;
911 }
912 else
913 return;
914
915 }
916#ifdef M5CORE2_MODULE
917 //! 1.24.24 if alternate display then return ..
918 if (inAlternateDisplay_displayModule())
919 {
920
921 loop_Alternate_displayModule();
922 return;
923 }
924#endif
925
926 //!check if a delay was running..
927 if (delayFinished())
928 {
929 SerialCall.println("loop_displayModule: delayFinished");
931 }
932
933 //TODO:
934 // change sensors, and change any SemanticMarkers using said sensors..
935 // or every second update SM (whatever is shown - and only change if sensors are showing (parms), eg. status
936//either delay or redraw right now.. from loop()
937
938 //4.20.22 (9 pm .. listening to Mike Campbell with drummer talking story about Tom Petty
939 // lets use a counter vs time .. simplier??
940 _markerTimer++;
941//#define LOOP_COUNTER_MICROSECONDS 30
942#define LOOP_COUNTER_MICROSECONDS 20 // 2 seconds it seems.. 11.7.22
943
944 if (_markerTimer > LOOP_COUNTER_MICROSECONDS) //10 was working .. got to 20 how fast it loop across all the modules (their loop() ..
945 {
946
947 //! 9.2.22 new .. update the timer. This is on blank screen as well .. so don't check _semanticMarkerShown
949#define TRY_BLANKSCREEN_IN_LOOP
950#ifdef TRY_BLANKSCREEN_IN_LOOP
951 //!check if a delay was running..
953 {
954 SerialCall.println("loop_displayModule: isBlankScreen");
956 }
957#endif
958 _markerTimer = 0;
959 if (_semanticMarkerShown)
960 {
961 SerialCall.println("loop_displayModule: redrawSemanticMarker(KEEP_SAME)");
962
963 //!see if this works .. vs too flickering.. (if so we have to slow it down..)
965 }
966 }
967
968#ifdef M5CORE2_MODULE
969 //! try to show where the 3 buttons are below the following box..
970 M5.Lcd.drawRect(50, 235, 10, 3, WHITE);
971 M5.Lcd.drawRect(155,235, 10, 3, WHITE);
972 M5.Lcd.drawRect(258,235, 10, 3, WHITE);
973 //! 240 too low..
974#endif
975}
976
977// ************ Drawing of the Action, Mode and Status ***************
978
979//!prints the text up to the maxLen (the setup of position, etc is already done)
980void printText(String text, int maxLen)
981{
982#ifdef ESP_M5
983 if (text.length() < maxLen)
984 {
985 M5.Lcd.print(text);
986 }
987 else
988 {
989 M5.Lcd.print(text.substring(0,maxLen));
990 }
991#endif
992}
993
994//! print the text, but pad with background color spaces..
995void printTextPadSpaces(String text, TextPositionStruct textColor)
996{
997#ifdef ESP_M5
998
999 int maxLen = textColor.maxLen;
1000 printText(text, maxLen);
1001
1002 // now pad with spaces .. using the color provided..
1003 // pad with spaces .., but in the background color..
1004 M5.Lcd.setTextColor(textColor.textColor, textColor.textColorBackground);
1005 for (int i=text.length(); i< maxLen; i++)
1006 {
1007 M5.Lcd.print(" ");
1008 }
1009#endif
1010}
1011
1012//!sets the "ACTION" -- The TOP line
1013void drawAction(String title, int screenType)
1014{
1015
1016 SerialCall.print("drawAction: ");
1017 SerialCall.print(title);
1018 SerialCall.printf(" screenType=%d\n",screenType);
1019
1020 //!setup the position for the Action text
1022 && (screenType != SCREEN_TYPE_HELP))
1023 {
1024 //!only add the CR on the zoomed
1025 title.replace(" ","\r\n");
1026
1027 //!get the color index .. 0..MAX-1, if outside range, pick 0. Use 'mod' == % syntax.
1028 //!This is because the set from the web (MQTT) doesn't know the size.. or have it done here..
1029 int colorIndex = getScreenColor_displayModule();
1030
1031 //!different for home screen
1032 switch (screenType)
1033 {
1034 case SCREEN_TYPE_HOME_SIMPLE:
1035 //!print preferences
1036 //printPreferenceValues_mainModule();
1037 //fall through to same as simple_1/2
1038 case SCREEN_TYPE_HOME_SIMPLE_1:
1039 case SCREEN_TYPE_HOME_SIMPLE_2:
1040 case SCREEN_TYPE_AP:
1041
1042 {
1043 //Hard wire back to "MINI CLICKER" since the MQTT code used a name to bind to this code, eg. MINI-2
1044 setupTextPosition(_actionTextHomeSimpleColor[colorIndex]);
1045 printText(" MINI CLICKER", _actionTextHomeSimplePositionZoomed.maxLen);
1046#ifdef M5CORE2_MODULE
1047 setupTextPosition(_moduleDeviceNameTextPosition);
1048 //sprintf(infoString,"%s, %.*s",deviceName_mainModule(),getPairedDeviceOrAddress_mainModule() );
1049 printTextAtTextPosition(deviceName_mainModule(), _moduleDeviceNameTextPosition);
1050#endif
1051 }
1052 break;
1053 case SCREEN_TYPE_HOME_SIMPLE_3:
1054 {
1055 //Hard wire back to "MINI CLICKER" since the MQTT code used a name to bind to this code, eg. MINI-2
1056 setupTextPosition(_actionTextHomeSimpleColor[colorIndex]);
1057 printText("CLICKER MENU ", _actionTextHomeSimplePositionZoomed.maxLen);
1058 }
1059 break;
1060 //rest are the next set of screens.
1061 case SCREEN_TYPE_HOME:
1062 {
1063 // This now comes in as "FEED ALL" .. so change to SMART CLICKER
1064 setupTextPosition(_actionTextHomeSimpleColor[colorIndex]);
1065 printText(" SMART CLICKER", _actionTextHomeSimplePositionZoomed.maxLen); }
1066 break;
1067 //same title.. for now..
1068 case SCREEN_TYPE_PAIRED_DEV:
1069 {
1070 // the title == P: so replace with the paired name..
1071 setupTextPosition(_actionTextHomeSimpleColor[colorIndex]);
1072
1073 //!use the zoomed amount
1074 printText("PAIR DEVICE ", _actionTextPositionZoomed.maxLen);
1075 }
1076 break;
1077 default:
1078 //!use the zoomed amount
1079 //setupTextPosition(_actionTextPositionZoomed);
1080 setupTextPosition(_actionTextHomeSimpleColor[colorIndex]);
1081 printText(title, _actionTextPositionZoomed.maxLen);
1082 }
1083 }
1084 else
1085 {
1086 //don't show the P: but rather the paired device name
1087 if (screenType == SCREEN_TYPE_PAIRED_DEV)
1088 {
1089 // the title == P: so replace with the paired name..
1090 setupTextPosition(_actionTextPosition);
1091 //!use the zoomed amount
1092 printTextPadSpaces("PAIRDEV", _actionTextPosition);
1093
1094 }
1095 else
1096 {
1097 setupTextPosition(_actionTextPosition);
1098 //printText(title, _actionTextPosition.maxLen);
1099
1100 printTextPadSpaces(title, _actionTextPosition);
1101
1102 }
1103 }
1104}
1105
1106//!sets the "Sensor Status"
1107void drawSensorStatus(int screenType)
1108{
1109 char infoString[150];
1110 boolean multilineScreenType = false;
1111
1112#ifdef ESP_M5
1113
1114 //!The "INFO"
1115 //float batVoltage = M5.Axp.GetBatVoltage();
1116 float batPercentage = getBatPercentage_mainModule();
1120 boolean isConnectedBLE =
1121 //! 8.16.25 BLE CLIENT
1123
1124
1125 //!add the Gateway status.. Now, if the preference is only GEN3 and not connected, then show a Gx, but if connected then G3, and g if any kind but not connected
1126 String gStatus = "g";
1127 String gStatusHome = "";
1128 if (isConnectedBLE && gatewayOn)
1129 {
1130 gStatus = "G3";
1131 gStatusHome = "G3";
1132 }
1134 {
1135 gStatus = "Gx";
1136 gStatusHome = "Gx";
1137 }
1138 //!Special layout for HELP screen type
1139 switch (screenType)
1140 {
1141
1142 case SCREEN_TYPE_HELP:
1143 multilineScreenType = true;
1144 // sprintf(infoString,inMinMenu?"Show All\nmenus":"Minimize\nmenus");
1145 sprintf(infoString,"Scan Image\nFor Help");
1146
1147 break;
1148 case SCREEN_TYPE_WIFI:
1149 multilineScreenType = true;
1151 {
1152 //! 8.16.25 MQTT
1153
1155 sprintf(infoString,"Swap WIFI");
1156 else
1157 sprintf(infoString,"Swap/Retry\nWIFI");
1158 }
1159 else
1160 {
1161 //! #issue 136 show the WIFI in the semantic marker, and label for scanning
1162 sprintf(infoString,"Scan to\nShare WIFI");
1163 }
1164 break;
1165 case SCREEN_TYPE_AP:
1166 multilineScreenType = true;
1167 //! 8.16.25 WIFI AP
1169 sprintf(infoString,"Enter AP\n192.168.4.1");
1170 else
1171 sprintf(infoString,"In AP\n192.168.4.1");
1172 break;
1173 case SCREEN_TYPE_GUEST_PAGE:
1174 multilineScreenType = true;
1175 sprintf(infoString,"Share WIFI with Feeder");
1176 break;
1177#ifdef NOMORE
1178 case SCREEN_TYPE_TIMER: //will be it's own with the time values...
1179 {
1180 //printf(infoString,"TIMER...");
1183 sprintf(infoString,"Seconds=%d", model->delaySeconds);
1184
1185 }
1186#endif
1187 break;
1188 case SCREEN_TYPE_TIMER:
1189 case SCREEN_TYPE_DOC_FOLLOW:
1190 //case SCREEN_TYPE_HOME_SIMPLE:
1191 case SCREEN_TYPE_HOME_SIMPLE_2:
1192 case SCREEN_TYPE_HOME_SIMPLE_3:
1193 case SCREEN_TYPE_PAIRED_DEV:
1194 case SCREEN_TYPE_REBOOT:
1195 {
1196 //!update the model for those drawing Dev and Connected Dev
1198
1199 multilineScreenType = true;
1200 //! just ask the deviceState...
1202 switch (model->pairedDeviceStateEnum)
1203 {
1204 //paired to a device, but BLE NOT connected right now
1206 sprintf(infoString,"%s\n+%.*s",deviceName_mainModule(),10,getPairedDeviceOrAddress_mainModule() );
1207 break;
1208 //paired to a device, and BLE connected right now
1210 sprintf(infoString,"%s\n%.*s",deviceName_mainModule(),10,getPairedDeviceOrAddress_mainModule() );
1211 break;
1212 //not paired (but could be paired as it's a named device])
1214 sprintf(infoString,"%s\n-%.*s",deviceName_mainModule(),9,connectedBLEDeviceName_mainModule());
1215 break;
1216 //!factory default but not connecte to anything..
1217 case notConnectedEnum:
1218 sprintf(infoString,"%s\n%s",deviceName_mainModule(),(char*)"scanning..");
1219 break;
1220 }
1221
1222 }
1223 break;
1224
1225 case SCREEN_TYPE_FEED_GUEST:
1226 multilineScreenType = true;
1227 sprintf(infoString,"Feed Guest");
1228 break;
1229
1230
1231 case SCREEN_TYPE_HOME:
1232 case SCREEN_TYPE_HOME_SIMPLE:
1233 case SCREEN_TYPE_HOME_SIMPLE_1:
1234
1235 sprintf(infoString,"Feed=%0d(%0d) Bat=%2.0f%% %s", getFeedCount_mainModule(), feedCountMax_mainModule(), batPercentage,gStatusHome);
1236 //!could add BUZZER (but it's a distributed issue - it can be sent elsewhere..
1237 break;
1238
1239 case SCREEN_TYPE_STATUS:
1240 // case SCREEN_TYPE_REBOOT:
1241 default:
1242 sprintf(infoString,"%s|%2.0f%%|%2.0ff c%0d|%c|%s|t%0d",VERSION_SHORT, batPercentage, getTemperature_mainModule(), getFeedCount_mainModule(), buzzerOn?'B':'b', gStatus,_loopTimer);
1243 //!could add BUZZER (but it's a distributed issue - it can be sent elsewhere..
1244 break;
1245 }
1246
1247 //!setup the position for the SensorStatus .. HELP is always not-zoomed (show semantic marker)
1249 && !(screenType == SCREEN_TYPE_HELP))
1250 {
1251 //!use the zoomed amount
1252 setupTextPosition(multilineScreenType?_multilineStatusTextPositionZoomed:_sensorStatusTextPositionZoomed);
1253 }
1254 else
1255 {
1256 setupTextPosition(multilineScreenType?_multilineStatusTextPosition:_sensorStatusTextPosition);
1257 }
1258
1259 //!draw the text
1260 printText(infoString,multilineScreenType?_multilineStatusTextPosition.maxLen:_sensorStatusTextPosition.maxLen);
1261#endif //m5
1262}
1263//!draws the text and differeent if ON or OFF
1264void drawStatusText(String text, boolean isOn)
1265{
1266#ifdef ESP_M5
1267 if (isOn)
1268 M5.Lcd.setTextColor(BLUE, YELLOW);
1269 else
1270 M5.Lcd.setTextColor(WHITE, BLACK);
1271 M5.Lcd.print(text);
1272#endif
1273}
1274
1275//! returns if the modesDesired contains a mode character, but also true if modesDesired in null
1276boolean containsMode(char *modesDesired, char mode)
1277{
1278 if (!modesDesired)
1279 return true;
1280 else return index(modesDesired,mode) != NULL;
1281}
1282
1283//!sets the "Module Status", will show only the modesDesired if non null
1284void drawModuleStatus(char *modesDesired)
1285{
1286 //!setup the position for the SensorStatus
1288 {
1289 //!Zoomed .. setup the position for the ModuleStatus
1290 setupTextPosition(_moduleStatusTextPositionZoomed);
1291 }
1292 else
1293 {
1294 //!setup the position for the ModuleStatus
1295 setupTextPosition(_moduleStatusTextPosition);
1296 }
1297 // would be nice to get the device name.. of our connected BLE..
1298 //!value of WIFI connected
1299 //! 8.16.25 MQTT
1300 if (containsMode(modesDesired,'W'))
1301 drawStatusText("W", isConnectedWIFI_MQTTState());
1302 if (containsMode(modesDesired,'M'))
1303 drawStatusText("M", isConnectedMQTT_MQTTState());
1304 //! 8.16.25 BLE CLIENT
1305 //!useBLECLient == it's linked in and running (vs not running)
1306 if (containsMode(modesDesired,'B'))
1307 drawStatusText("B", useBLEClient());
1308 //! connected == we are connected to another BLEServer
1309 if (containsMode(modesDesired,'C'))
1310 drawStatusText("C", isConnectedBLEClient());
1311 //! 8.16.25 WIFI AP
1312 //!not done is what we look for ..
1313 if (containsMode(modesDesired,'A'))
1314 drawStatusText("A", !doneWIFI_APModule_Credentials());
1315 if (containsMode(modesDesired,'T'))
1317
1318 //! 8.16.25 BLE SERVER
1319 if (containsMode(modesDesired,'S'))
1320 {
1321 //maybe only show if ON..
1323 drawStatusText("S",true);
1324 }
1325 //Buzzer (but only sometimes)
1326 if (containsMode(modesDesired,'Z'))
1328
1329 //! Reset
1330 if (containsMode(modesDesired,'R'))
1331 drawStatusText("R",true);
1332 //! Reboot
1333 if (containsMode(modesDesired,'X'))
1334 drawStatusText("X",true);
1335 //! Help
1336 if (containsMode(modesDesired,'H'))
1337 drawStatusText("H",true);
1338
1339 //! Paired
1340 if (containsMode(modesDesired,'P'))
1341 {
1342 //if the paired device is NONE then
1343 drawStatusText("P",isValidPairedDevice_mainModule());
1344 }
1345}
1346
1347//!just draw the simple status at bottom
1348void displaySimpleStatus()
1349{
1350 //!show the BLE connected status at the bottom (G3 if gen3), WIFI, and AP if APmode
1351 boolean isConnectedBLE =
1352 //! 8.16.25 BLE CLIENT
1354
1355 // whether the gateway is on.. this isn't using the Gx just BLE or GE3
1357 //WIFI means the MQTT is working (not just WIFI)
1358 boolean isConnectedWIFI =
1359 //! 8.16.25 MQTT
1361
1362 char label[30];
1363 String gStatus = " "; //3 characters
1364 if (isConnectedBLE && gatewayOn)
1365 {
1366 gStatus = "GE3";
1367 }
1368 else if (isConnectedBLE)
1369 {
1370 gStatus = "BLE";
1371 }
1372
1373 //! 8.16.25 WIFI AP
1374 sprintf(label,"%s %s %s", gStatus, isConnectedWIFI?"WIFI":" ",!doneWIFI_APModule_Credentials()?"AP":" ");
1375 printTextAtTextPosition(label,_connectedStatusTextPositionZoomed);
1376}
1377
1378//!perform a zoom .. of the semantic marker - or it might be something else..
1379void displayZoomedSemanticMarker(int screenType)
1380{
1381 SerialCall.print("displayZoomedSemanticMarker: ");
1382 SerialCall.println(_semanticTitle);
1383 // use _currentSemanticMarkerAddress
1384
1385 //!used in the new model versions below..
1386 ModelKindEnum modelKind;
1387
1388
1389 //2nd line..
1390 switch (screenType)
1391 {
1392 case SCREEN_TYPE_WIFI:
1393 {
1394 //show the current WIFI..
1395 //TODO: pull out the SSID only...
1396 // {'ssid':<name we want>,'ssidPassword':p}
1397 //try JSON.. NOT WORKING ...
1398 //https://linux.die.net/man/3/strstr
1399 //I'm cheeting, for now .. and grabbing both 1 * 3
1400 char wifi1[100];
1402 char wifi2[100];
1404 char *json = main_JSONStringForWIFICredentials();
1405
1406 SerialTemp.println(wifi1);
1407 SerialTemp.println(wifi2);
1408 boolean wifi1Current = strcmp(json,wifi1)==0;
1409
1410 SerialTemp.printf("wifi1Current == %d\n", wifi1Current);
1411
1412 char buffer[100];
1413
1414 char *json1 = strstr(wifi1,":");
1415 int json1Len = 1;
1416 if (json1 && strlen(json1) > 3)
1417 {
1418 json1 += 2; //move past the ':'"
1419 }
1420 else
1421 json1 = wifi1;
1422 {
1423 //find the '
1424 char *comma = strchr(json1,'\'');
1425 json1Len = comma?((int)(comma - json1)):strlen(json1);
1426 }
1427 SerialTemp.println(json1);
1428
1429 char *json2 = strstr(wifi2,":");
1430 int json2Len = 1;
1431 if (json2 && strlen(json2) > 3)
1432 {
1433 json2 += 2; //move past the ':'"
1434 }
1435 else
1436 json2 = wifi2;
1437 {
1438 //find the '
1439 char *comma = strchr(json2,'\'');
1440 json2Len = comma?((int)(comma - json2)):strlen(json2);
1441 }
1442 SerialTemp.println(json2);
1443
1444 strcpy(buffer,"+");
1445 strncat(buffer, wifi1Current?json1:json2, wifi1Current?json1Len:json2Len );
1446 strcat(buffer,"\n\r");
1447 printTextAtTextPosition(buffer,_zoomedTextPositions[SM_ACTION_SMALL]);
1448
1449 strcpy(buffer,"-");
1450 strncat(buffer, !wifi1Current?json1:json2, !wifi1Current?json1Len:json2Len );
1451 //make it blue..
1452 M5.Lcd.setTextColor(WHITE, BLUE);
1453 M5.Lcd.print(buffer);
1454
1455 SerialCall.println(buffer);
1456 }
1457 break;
1458
1459 //!ADD SCREEN_TYPE_HOME
1460 case SCREEN_TYPE_HOME_SIMPLE:
1461 {
1462 //Draw the tilt normal, and the buzz as
1463 // new 7.25.22 per issue #126
1464 // This is for the TILT
1465 //THE BIG ACTION == first, but that color is ORANGE, so wap to the SM_ACTION colors
1467 printTextAtTextPositionOverrideTextColor("TiltOn",_zoomedTextPositions[BIG_ACTION],_zoomedTextPositions[SM_ACTION] );
1468 else
1469 printTextAtTextPositionOverrideTextColor("TiltOff",_zoomedTextPositions[BIG_ACTION], _zoomedTextPositions[SM_ACTION]);
1470
1471 //THE BIG ACTION == first, but that color is ORANGE
1473 printTextAtTextPositionOverrideTextColor("BuzzOn",_zoomedTextPositions[SM_ACTION],_zoomedTextPositions[BIG_ACTION] );
1474 else
1475 printTextAtTextPositionOverrideTextColor("BuzzOff",_zoomedTextPositions[SM_ACTION], _zoomedTextPositions[BIG_ACTION]);
1476 // show the BLE connected status at the bottom
1477 displaySimpleStatus();
1478 }
1479 break;
1480 case SCREEN_TYPE_HOME_SIMPLE_1:
1481 {
1482 // This is for the BUZZ
1483 // new 7.25.22 per issue #126
1484 //swap them .. for now .. or TODO: change the zoomText to be swapped colors..
1485 //DRAFT ...
1486 //swap colors, passing the _zoomedTextPositions of the opposite
1488 printTextAtTextPosition("TiltOn",_zoomedTextPositions[BIG_ACTION]);
1489 else
1490 printTextAtTextPosition("TiltOff",_zoomedTextPositions[BIG_ACTION]);
1491
1493 printTextAtTextPosition("BuzzOn",_zoomedTextPositions[SM_ACTION]);
1494 else
1495 printTextAtTextPosition("BuzzOff",_zoomedTextPositions[SM_ACTION]);
1496 // show the BLE connected status at the bottom
1497 displaySimpleStatus();
1498 }
1499 break;
1500 case SCREEN_TYPE_HOME_SIMPLE_2:
1501 {
1502 // new 7.25.22 per issue #126, special feeding page
1503 // Feeds left:
1504
1505 char tmpString[30];
1506 //blue as this is an option (for reset counter)
1507 sprintf(tmpString,"%0d(%0d)", getFeedCount_mainModule(), feedCountMax_mainModule());
1508 printTextAtTextPositionOverrideTextColor(tmpString,_zoomedTextPositions[BIG_ACTION], _zoomedTextPositions[SM_ACTION]);
1509 // battery percent, but orange not selected ..
1510 sprintf(tmpString,"B:%2.0f%%", getBatPercentage_mainModule());
1511 printTextAtTextPositionOverrideTextColor(tmpString,_zoomedTextPositions[SM_ACTION],_zoomedTextPositions[BIG_ACTION]);
1512 // show the BLE connected status at the bottom
1513 displaySimpleStatus();
1514 }
1515 break;
1516
1517 case SCREEN_TYPE_AP:
1518 {
1519 //TODO: change the top simple line .. to a messaging
1520 // new 7.25.22 per issue #126
1521 printTextAtTextPositionOverrideTextColor("AP",_zoomedTextPositions[BIG_ACTION], _zoomedTextPositions[SM_ACTION]);
1522 printTextAtTextPositionOverrideTextColor("Mode...",_zoomedTextPositions[SM_ACTION],_zoomedTextPositions[SM_ACTION]);
1523 // show the BLE connected status at the bottom
1524 displaySimpleStatus();
1525 }
1526 break;
1527 case SCREEN_TYPE_TIMER:
1528 case SCREEN_TYPE_HOME_SIMPLE_3:
1529 case SCREEN_TYPE_PAIRED_DEV:
1530 case SCREEN_TYPE_REBOOT:
1531 {
1532
1533 if (screenType == SCREEN_TYPE_REBOOT)
1534 modelKind = rebootModel;
1535 else if (screenType == SCREEN_TYPE_PAIRED_DEV)
1536 modelKind = pairedDeviceModel;
1537 else if (screenType == SCREEN_TYPE_HOME_SIMPLE_3)
1538 modelKind = menusModel;
1539 else if (screenType == SCREEN_TYPE_TIMER)
1540 modelKind = timerModel;
1541 else
1542 SerialMin.println(" *** INVALID screenType ***");
1543
1544 char buffer[50];
1545
1546 //!upate the model (done at beginning of loop()
1547 //updateMenuState(modelKind);
1548 //!grab this model.
1549 ModelStateStruct *model = getModel(modelKind);
1550
1551 // empty the 4 lines.. with black characters..
1552 //4 lines max
1553
1554 // blank the area
1555 M5.Lcd.fillRect(0, 80, 135, 130, BLACK);
1556
1557 // start over..
1558 strcpy(buffer,"");
1559 int windowSize = 6;
1560 int textLength = 10;
1561 if (model->perfersBigText)
1562 {
1563 windowSize = 4;
1564 textLength = 6;
1565 }
1566
1567 if (model->maxItems < windowSize)
1568 windowSize = model->maxItems;
1569
1570 printTextAtTextPosition(buffer, (windowSize <= 4)?_menuTextPositionZoomed_4less:_menuTextPositionZoomed_4plus);
1571
1572 //SerialDebug.printf("current = %d, max = %d\n",model->currentItem, model->maxItems);
1573 //get the menu items to draw..
1574 //!try a rolling window..
1575 // current 3 1..8
1576 // if there maxItems > 6 .. then when hit end .. it scrolls to next one..
1577 int startItem = 0;
1578 int maxItems = model->maxItems;
1579 int currentItem = model->currentItem;
1580 if (currentItem >= windowSize)
1581 {
1582 // scrolling time..
1583 // move start the number past maxWindow
1584 // 0..5, 1..6, 2..7 3..8 (and current always last item on scrolling)
1585 //say it's 8: current = 8, start = 8 - windowSize
1586 startItem = currentItem - windowSize + 1;
1587 }
1588 maxItems = startItem + windowSize;
1589 for (int i=startItem; i < maxItems; i++)
1590 {
1591 char *menu = menuForState(modelKind, i);
1592 if (i == model->currentItem)
1593 {
1594 // use blue...
1595 M5.Lcd.setTextColor(WHITE, BLUE);
1596 }
1597 else
1598 {
1599 M5.Lcd.setTextColor(ORANGE, BLACK);
1600 }
1601
1602 sprintf(buffer,"-%.*s\n\r", textLength, menu);
1603 M5.Lcd.print(buffer);
1604 }
1605
1606 // show the BLE connected status at the bottom
1607 // in this case, it's not connected so BLE should be off..
1608 displaySimpleStatus();
1609 }
1610 break;
1611
1612 default:
1613 {
1614 // FEED ..
1615 printTextAtTextPosition("+FEED",_zoomedTextPositions[BIG_ACTION]);
1616
1617 String title = "-" + _semanticTitle;
1618 title.replace(" ","\r\n");
1619
1620 switch (screenType)
1621 {
1622 case SCREEN_TYPE_HOME:
1623 printTextAtTextPosition(title,_zoomedTextPositions[SM_ACTION]);
1624 break;
1625
1626 //wont get here... the case is above..
1627 case SCREEN_TYPE_PAIRED_DEV:
1628 break;
1629 case SCREEN_TYPE_HELP:
1630 {
1631 // Instead of "Help Info" show the "MINI CLICKER"
1632 String title = "-MINI\r\nCLICKER";
1633 printTextAtTextPosition(title,_zoomedTextPositions[SM_ACTION]);
1634 }
1635 break;
1636 case SCREEN_TYPE_GUEST_PAGE:
1637 {
1638 //!This sends the M5's WIFI credentials down to the paired device over BLE
1639 // Instead of "Help Info" show the "MINI CLICKER"
1640 String title = "-SHARE\r\nWIFI";
1641 printTextAtTextPosition(title,_zoomedTextPositions[SM_ACTION]);
1642 }
1643 break;
1644 default:
1645 printTextAtTextPosition(title,_zoomedTextPositions[SM_ACTION]);
1646 }
1647 }
1648 break;
1649 } //switch
1650}
1651
1652//!redraws the image..
1653void redrawSemanticMarker_displayModule(boolean startNew)
1654{
1655 int screenType = screenTypeForTitle_displayModule(_semanticTitle);
1656
1657 SerialCall.printf("redrawSemanticMarker_displayModule(startNew:%d, ScreenType = %d)\n", startNew, screenType);;
1658 if (startNew)
1659 {
1660 //! resets the preferences so the mini menu is running, and resets other preferences
1661 switch (screenType)
1662 {
1663 //!ADD SCREEN_TYPE_HOME
1664 case SCREEN_TYPE_HOME_SIMPLE:
1665 {
1666 //!set some defaults on boot - that override EPROM this can be called on the HOME screen to set back to normal mode..
1668 }
1669 break;
1670 case SCREEN_TYPE_HOME_SIMPLE_1:
1671 case SCREEN_TYPE_HOME_SIMPLE_2:
1672 case SCREEN_TYPE_HOME_SIMPLE_3:
1673 //DO THIS HERE TOO.. just check if simple_3 lets things still happen..
1674 // setOnboot sets min menu and the zoomedSM
1675 {
1676 //!set some defaults on boot - that override EPROM this can be called on the HOME screen to set back to normal mode..
1678 }
1679 break;
1680 }
1681
1682#define TRY_CLEAR_WITH_RESET_TIMER
1683
1684#ifdef TRY_CLEAR_WITH_RESET_TIMER
1685 //! clears the screen, and resets timer
1687#else
1688 //also resets the loop timer
1690#endif
1691 //empty the lastSM
1692 _lastSemanticMarkerAddress = String("");
1693
1694 }
1695 else
1696 {
1697 incrementLoopTimer();
1698 }
1699
1700
1701 //!update the model (ModelController.h) for the type of screen displayed (what model)
1702 if (screenType == SCREEN_TYPE_REBOOT)
1703 //!upate the model -- each loop, before drawing stuff (obviously)
1705 else if (screenType == SCREEN_TYPE_PAIRED_DEV)
1707 else if (screenType == SCREEN_TYPE_HOME_SIMPLE_3)
1709 else if (screenType == SCREEN_TYPE_TIMER)
1711
1712 //!sets flag that being shown..
1713 _semanticMarkerShown = true;
1714
1715 //!this re-creates the address (maybe dynamically if the func() callback is defined)
1716 _currentSemanticMarkerAddress = createSemanticAddress();
1717
1718 // ** NOTE the zoom is a way to figure out what else to show..
1720 && (screenType != SCREEN_TYPE_HELP))
1721 {
1722 displayZoomedSemanticMarker(screenType);
1723 }
1724 else if (screenType == SCREEN_TYPE_DOC_FOLLOW)
1725 {
1726 //! this draws QR but using the lastDocFollowSemanticMarker
1727#define QRAVATAR
1728#ifdef ESP_M5
1729#ifdef M5CORE2_MODULE
1730 //! DON"T rotate -- for the M5Core2 display
1731#else
1732 M5.Lcd.setRotation(0);
1733#endif
1734 //!Draws a SemanticMarker&trade; (using QR code)
1735 //!Create a QR code with a width of 135 QR code at (0, 100). 在(0,0)处创建一个宽为135二维码
1736 //!Please select the appropriate QR code version according to the number of characters. 请根据字符数量选择合适的二维码版本
1737 //try brightness
1738 setBrightness_displayModule(0);
1739 M5.Lcd.qrcode(getLastDocFollowSemanticMarker_MQTTNetworking(),0,100,135, SEMANTIC_MARKER_QR_VERSION);
1740
1741#ifdef QRAVATAR
1742 //try to draw a character in the middle ... (D, etc)
1743 printTextAtTextPosition("SM",_zoomedTextPositions[QRAVATAR_ACTION]);
1744#endif
1745#endif //ESP_M5
1746 }
1747 else
1748 {
1749#ifdef ESP_M5
1750#ifdef M5CORE2_MODULE
1751 //! DON"T rotate -- for the M5Core2 display
1752#else
1753 M5.Lcd.setRotation(0);
1754#endif
1755 SerialLots.print("last vs current: ");
1756 SerialLots.print(_lastSemanticMarkerAddress);
1757 SerialLots.println(" vs ");
1758 SerialLots.println(_currentSemanticMarkerAddress);
1759 //!only redraw if changed ...
1760 if (!_lastSemanticMarkerAddress.compareTo(_currentSemanticMarkerAddress)==0)
1761 {
1762 SerialLots.println(_currentSemanticMarkerAddress);
1763 //try brightness
1764 setBrightness_displayModule(0);
1765
1766 //!Draws a SemanticMarker&trade; (using QR code)
1767 //!Create a QR code with a width of 135 QR code at (0, 100). 在(0,0)处创建一个宽为135二维码
1768 //!Please select the appropriate QR code version according to the number of characters. 请根据字符数量选择合适的二维码版本
1769 M5.Lcd.qrcode(_currentSemanticMarkerAddress,0,100,135, SEMANTIC_MARKER_QR_VERSION);
1770#ifdef QRAVATAR
1771 //try to draw a character in the middle ... (D, etc)
1772 String smChar = _semanticTitle.substring(0,1);
1773 printTextAtTextPosition(smChar,_zoomedTextPositions[QRAVATAR_ACTION]);
1774#endif
1775 }
1776
1777#endif
1778
1779 _lastSemanticMarkerAddress = _currentSemanticMarkerAddress;
1780 }
1781
1782 //!The "ACTION"
1783 drawAction(_semanticTitle, screenType);
1784
1785 //!The "SensorStatus", which uses current info..
1786 drawSensorStatus(screenType);
1787
1788 //!then which modules to draw for the different screens
1789 switch (screenType)
1790 {
1791 case SCREEN_TYPE_HOME_SIMPLE_3:
1792 //advanced is now ModelController..
1793 break;
1794 //!ADD SCREEN_TYPE_HOME
1795 case SCREEN_TYPE_HOME_SIMPLE:
1796 case SCREEN_TYPE_HOME_SIMPLE_1:
1797 case SCREEN_TYPE_HOME_SIMPLE_2:
1798 case SCREEN_TYPE_AP:
1799 {
1800 // 7.25.22
1801 //!Draw FEED in red if the feed count is > 13
1802 if (getFeedCount_mainModule() > 13)
1803 setupTextPosition(_homeSimpleStatusTextPositionZoomedRED);
1804 else
1805 setupTextPosition(_homeSimpleStatusTextPositionZoomed);
1806 // if count > 13 make it red
1807 M5.Lcd.print("+FEED ");
1808 // 1234567
1809 }
1810 break;
1811 //REST are previous..
1812 //NOTE: that the HELP long press also goes home..
1813 case SCREEN_TYPE_HOME:
1814 //!The " ModuleStats"
1815 drawModuleStatus((char*)"WMCTZAS");
1816 break;
1817 case SCREEN_TYPE_TILT:
1818 //!The " ModuleStats"
1819 drawModuleStatus((char*)"T");
1820 break;
1821 case SCREEN_TYPE_BUZZ:
1822 //! module status with BUZZ
1823 drawModuleStatus((char*)"Z");
1824 break;
1825 case SCREEN_TYPE_WIFI:
1826 drawModuleStatus((char*)"WM");
1827 break;
1828// case SCREEN_TYPE_AP:
1829// drawModuleStatus((char*)"WMA");
1830// break;
1831 case SCREEN_TYPE_HELP:
1832 // drawModuleStatus((char*)"H");
1833 // maybe draw text: iDogWatch.com/bot/help
1834 setupTextPosition(_helpStatusTextPosition);
1835
1836 //!draw the text
1837 printText((char*)"iDogWatch.com/bot/help",_helpStatusTextPosition.maxLen);
1838 break;
1839
1840 case SCREEN_TYPE_RESET:
1841 drawModuleStatus((char*)"R");
1842 break;
1843 case SCREEN_TYPE_TIMER:
1844 break;
1845 case SCREEN_TYPE_REBOOT:
1846 break;
1847 case SCREEN_TYPE_PAIRED_DEV:
1848 break;
1849
1850 case SCREEN_TYPE_GUEST_PAGE:
1851 drawModuleStatus((char*)"WMC");
1852 break;
1853 case SCREEN_TYPE_FEED_GUEST:
1854 drawModuleStatus((char*)"WMC");
1855 break;
1856
1857 case SCREEN_TYPE_STATUS:
1858 default:
1859 //!The " ModuleStats"
1860 //drawModuleStatus((char*)"WMBCATZ");
1861 drawModuleStatus((char*)"WMBCATS");
1862
1863 }
1864 //!startNew is that the screen needs new timeout
1865 if (startNew)
1866 {
1867 // boolean zoomed = getPreferenceBoolean_mainModule( PREFERENCE_SEMANTIC_MARKER_ZOOMED_VALUE);
1868 //if the SemanticMarker is show, delay 50
1869 //!startDelay(zoomed?25: currentScreenTimeout());
1870 startDelay(currentScreenTimeout());
1871
1872 //! called by the feed operation to say the device is still running.. and count it as a button click.
1873 //! Issue #145 8.8.22
1875
1876 //!NOTE: this gets called 2 times if buttonB short press .. but not othertimes..
1877
1878 }
1879
1880}
1881
1882
1883//! ISSUE: need to re-generate the SemanticAddress but only for "Status".
1884//! could kluge and use the Title?? == "Status"
1885
1886//**** Specific Methods*******
1887//!displays the Semantic Marker (a super QR code) on the M5 screen (with an N second display)
1888void showSemanticMarker_displayModule(String semanticMarkerAddress, String title)
1889{
1890
1891 SerialTemp.print("showSemanticMarker(nulls func) ");
1892 SerialTemp.print(title);
1893 SerialTemp.print(" SM=");
1894 SerialTemp.println(semanticMarkerAddress);
1895
1896 //!NOTE: issue #134 shows that the 'buttonProcessing _currentSMMode isn't getting updated .. Which is only an issue if the message is comming in from outside -- versus a button clik..
1897 //!cache for the redraw()
1898 _semanticTitle = title;
1899 //!no function, the addresss is the address provided
1900 //!NOTE: we could add our own function .. TODO .. less of a kluge..
1901 _getStatusFunc = NULL;
1902
1903 _currentSemanticMarkerAddressBase = semanticMarkerAddress;
1904 //!save the marker..
1905 _lastSemanticMarkerAddress = String("");
1906
1907 // clearScreen_displayModule();
1908
1909 //!draw a semantic marker (zoomed or not)
1911
1912 //startDelay(20);
1913//issue is another display can show up while this is being shown. like FEED , etc
1914}
1915
1916
1917//UNUSED SO FAR..
1918
1919//!finish the address after calling the function provided, called from MQTT for STATUS
1920void showSemanticMarkerFunc_displayModule(String semanticMarkerAddressBase, String title, const char* (*getStatusFunc)(void))
1921{
1922 SerialCall.print("showSemanticMarkerFunc: ");
1923 SerialCall.print(title);
1924 SerialCall.print(" SM=");
1925 SerialCall.println(semanticMarkerAddressBase);
1926
1927 //!save for use on redraw..
1928 _getStatusFunc = getStatusFunc;
1929 _currentSemanticMarkerAddressBase = semanticMarkerAddressBase;
1930 _semanticTitle = title;
1931 _lastSemanticMarkerAddress = String("");
1932
1933 // clearScreen_displayModule();
1934
1936
1937 //startDelay(20);
1938
1939}
1940
1941
1942//!
1943//! shows a FEED (or whatever) then blanks the screen after N seconds
1944void showText_displayModule(String text)
1945{
1946 drawAction(text, _currentScreenType);
1947 // startDelay(10);
1948}
1949
1950
1951
1952
1953
1954//! adds messages that aren't shown unless in message window mode.
1955//! NOTE: This will be a scrolling text as sometime ..
1956void addToTextMessages_displayModule(String text)
1957{
1958 SerialLots.printf("addToTextMessages_displayModule:(%d)",displayOnBlankScreen());
1959 SerialLots.println(text);
1960
1961#ifdef M5CORE2_MODULE
1962 //! FOR now .. isBlankScreen isn't cared about ..
1963 //! if showing the scrolling window .. don't do the rest ..
1964 if (_showScrollingTextWindow)
1965 {
1966#ifdef SHOW_BIG_BUTTON
1967#else
1968 //! 1.24.24 Adding scrolling text (if that window on the M5Core2 is shown)
1969 addToScrollingText_displayModule(text);
1970#endif
1971 return;
1972 }
1973#endif
1974
1975 //!whether screen is blank (so the button can be a wake, vs action..)
1976 if (isBlankScreen_displayModule() and !displayOnBlankScreen())
1977 {
1978 SerialLots.println("Not displaying since blank screen");
1979 return;
1980 }
1981
1982
1983 //!different for home screen
1984 switch (_currentScreenType)
1985 {
1986 //!ADD SCREEN_TYPE_HOME
1987 case SCREEN_TYPE_HOME_SIMPLE:
1988 case SCREEN_TYPE_HOME_SIMPLE_1:
1989 case SCREEN_TYPE_HOME_SIMPLE_2:
1990 case SCREEN_TYPE_AP:
1991 //don't show anything over the SMART CLICKER at the top
1992 break;
1993 case SCREEN_TYPE_HOME_SIMPLE_3:
1994 //TODO.. for now..
1995 // draw the title but on the 2nd smaller line
1996 //!use the zoomed amount
1997 setupTextPosition(_sensorStatusTextPositionZoomed);
1998
1999 //!draw the text
2000 printText(text,_sensorStatusTextPosition.maxLen);
2001 break;
2002 default:
2003 drawAction(text, _currentScreenType);
2004
2005
2006 }
2007
2008 //! testing 4.3.24 for large text
2009 if (text.compareTo("FEED")==0)
2010 {
2011 displayFullscreenMessage(text, true);
2012 }
2013}
2014
2015#ifdef M5CORE2_MODULE
2016//! add a loop for the alternate display
2017void loop_Alternate_displayModule()
2018{
2019 //no op for now..
2020}
2021/**
2022 First attempt at using the M5Core2 display to show something other than the M5 display
2023 1. scrolling text
2024 */
2025//! 1.24.24 Adding scrolling text (if that window on the M5Core2 is shown)
2026void addToScrollingText_displayModule(String textString)
2027{
2028 if (_showScrollingTextWindow)
2029 {
2030 M5.Lcd.setTextSize(1);
2031 M5.Lcd.println(textString);
2032 M5.Lcd.println();
2033 int X = M5.Lcd.getCursorX();
2034 int Y = M5.Lcd.getCursorY();
2035 SerialDebug.printf("cursor(%d,%d)\n", X, Y);
2036
2037 if (Y > 213)
2038 M5.Lcd.setCursor(0,0);
2039 }
2040}
2041
2042//! 1.24.24 Goto the scrolling text mode ..
2043void toggleShowingScrollingTextMode_displayModule()
2044{
2045 boolean flag = !_showScrollingTextWindow;
2046 setShowingScrollingTextMode_displayModule(flag);
2047 //! now change perminately ...
2048 //_showScrollingTextWindow = !_showScrollingTextWindow;
2049
2050}
2051
2052//! 2.29.24 Leap Year day
2053//! Returns whether the Scrolling Text window is shown
2054boolean scrollingTextWindowVisible_displayModule()
2055{
2056 return _showScrollingTextWindow;
2057}
2058
2059//! 2.27.24 make the button seem to be touched, if being shown
2060void showButtonTouched_displayModule()
2061{
2062#ifdef SHOW_BIG_BUTTON
2063 //! but only if _showScrollingTextWindow
2064 if (_showScrollingTextWindow)
2065 {
2066 SerialDebug.println("showButtonTouched_displayModule");
2067 delay(200);
2068 //try a blink..
2069 M5.Lcd.fillCircle(150,120,118, BLACK);
2070 M5.Lcd.drawCircle(150,120,118, WHITE);
2071 M5.Lcd.setTextColor(WHITE);
2072 M5.Lcd.setTextSize(5);
2073 M5.Lcd.setCursor(100, 110);
2074 M5.Lcd.print("Feed");
2075
2076 delay(500);
2077 M5.Lcd.fillCircle(150,120,118, GREEN);
2078 M5.Lcd.drawCircle(150,120,118, WHITE);
2079 M5.Lcd.setTextColor(BLACK);
2080 M5.Lcd.setTextSize(5);
2081 M5.Lcd.setCursor(100, 110);
2082 M5.Lcd.print("Feed");
2083 }
2084#endif
2085}
2086
2087//! 1.24.24 Goto the scrolling text mode .. if flag
2088void setShowingScrollingTextMode_displayModule(boolean flag)
2089{
2090 SerialDebug.printf("setShowingScrollingTextMode_displayModule(%d, s=%d)\n", flag,_showScrollingTextWindow );
2091
2092 //! now change perminately ...
2093 _showScrollingTextWindow = flag;
2094
2095 //! only do something if changed state
2096// if (flag == _showScrollingTextWindow)
2097// return;
2098
2099 if (_showScrollingTextWindow)
2100 {
2101 //! stop timers, etc
2102 //!stop the delay which says delay finished .. so don't show anything.. 8.9.22
2104
2105#ifdef SHOW_BIG_BUTTON
2106 // draw big green button.. for the heck of it..
2107 M5.Lcd.fillCircle(150,120,118, GREEN);
2108 M5.Lcd.drawCircle(150,120,118, WHITE);
2109
2110 M5.Lcd.setTextColor(BLACK);
2111 M5.Lcd.setTextSize(5);
2112 M5.Lcd.setCursor(100, 110);
2113 M5.Lcd.print("Feed");
2114
2115 //M5.Lcd.setCursor(0,0);
2116#else
2117 // blank the area
2118 // M5.Lcd.fillRect(0, 60, 135, 140, WHITE);
2119 M5.Lcd.setTextColor(WHITE, BLACK);
2120 M5.Lcd.setCursor(0, 0);
2121 M5.Lcd.setTextSize(1);
2122 M5.Lcd.println("Messages from the Network");
2123 //M5.Lcd.setTextWrap(true);
2124#endif
2125 }
2126 else
2127 {
2128 //! GO back to a normal screen..
2129 //M5.Lcd.setTextWrap(false);
2130
2131 //!wakes up the screen
2132 M5.Lcd.fillScreen(BLACK);
2134
2135 }
2136}
2137
2138//! scrolls the displayed text NOT YET ...
2139void scrollText_displayModule()
2140{
2141 if (_showScrollingTextWindow)
2142 {
2143 //!TODO..
2144 //!for now just clear the text...
2145 M5.Lcd.fillScreen(BLACK);
2146 M5.Lcd.setCursor(0, 0);
2147 //! maybe the text keeps going ... can we ask the cursor location??
2148 }
2149
2150}
2151#endif //M5CORE2_MODULE
2152
2153#else // not DISPLAY_MODULE
2154
2155//!Increment the screen color 0..n cache for getting the screen color 0..max (max provided by sender)
2156//!This is implemented by incrementScreenColor_mainModule() since it knows the MAX value of colors
2158{
2159
2160}
2161
2162
2163//!cache for getting the screen color 0..n. Will reset the cache as well
2164void setScreenColor_displayModule(int screenColor)
2165{
2166
2167}
2168
2169//!THIS IS the setup() and loop() but using the "component" name, eg MQTTNetworking()
2170//!This will perform preference initializtion as well
2171//! called from the setup()
2173{
2174
2175}
2176
2177//! called for the loop() of this plugin
2179{
2180
2181}
2182
2183//! shows a FEED (or whatever) then blanks the screen after N seconds
2184//! NOTE: This will be a scrolling text as sometime ..
2185void showText_displayModule(String text)
2186{
2187
2188}
2189
2190//! adds messages that aren't shown unless in message window mode.
2191//! NOTE: This will be a scrolling text as sometime ..
2193{
2194
2195}
2196
2197//!blanks the screen
2199{
2200
2201}
2202
2203//!wakes up the screen
2205{
2206
2207}
2208
2209//!whether screen is blank (so the button can be a wake, vs action..)
2211{
2212 return true;
2213}
2214
2215//!clears the screen
2217{
2218
2219}
2220
2221//!displays the Semantic Marker (a super QR code) on the M5 screen (title = to display)
2222void showSemanticMarker_displayModule(String semanticMarkerAddress, String title)
2223{
2224
2225}
2226
2227//!returns the current semantic marker (eg. guest page)
2229{
2230 return (char*)"unused";
2231}
2232
2233//!the function to call to get the 'status', return char*
2234//char* (*getStatusFunc)(void)
2235//typedef String (*getStatusFunc)(void);
2236
2237//!displays the Semantic Marker (a super QR code) on the M5 screen (title = to display)
2238void showSemanticMarkerFunc_displayModule(String semanticMarkerAddressBase, String title, const char* (*getStatusFunc)(void))
2239{
2240
2241}
2242
2243//!redraws the Semantic Marker image..
2245{
2246
2247}
2248
2250//!returns the loop timer (just a timer..)
2252{
2254}
2255
2256//!reset the loop timer .. useful for testing,
2258{
2260}
2261#endif
boolean isConnectedBLEClient()
returns whether connected over BLE as a client to a server(like a ESP feeder)
boolean useBLEClient()
returns if the BLEClient is turned on.. note, if connected to a BLE device, then disconnect
void loop_displayModule()
called for the loop() of this plugin
void showSemanticMarkerFunc_displayModule(String semanticMarkerAddressBase, String title, const char *(*getStatusFunc)(void))
the function to call to get the 'status', return char*
void addToTextMessages_displayModule(String text)
void wakeupScreen_displayModule()
wakes up the screen
int _loopCounter_displayModule
void setup_displayModule()
for types: String, boolean ..
void clearScreen_displayModule()
clears the screen
void incrementScreenColor_displayModule()
boolean isBlankScreen_displayModule()
whether screen is blank (so the button can be a wake, vs action..)
void showText_displayModule(String text)
void redrawSemanticMarker_displayModule(boolean startNew)
redraws the Semantic Marker image..
void setScreenColor_displayModule(int screenColor)
cache for getting the screen color 0..n. Will reset the cache as well
void showSemanticMarker_displayModule(String semanticMarkerAddress, String title)
displays the Semantic Marker (a super QR code) on the M5 screen (title = to display)
void blankScreen_displayModule()
blanks the screen
const char * currentSemanticMarkerAddress_displayModule()
returns the current semantic marker (eg. guest page)
int getLoopTimer_displayModule()
returns the loop timer (just a timer..)
void resetLoopTimer_displayModule()
reset the loop timer .. useful for testing,
void showOTAUpdatingMessage()
show an OTA message..
#define START_NEW
Definition: DisplayModule.h:53
#define KEEP_SAME
Definition: DisplayModule.h:54
char * getLastDocFollowSemanticMarker_MQTTNetworking()
boolean isConnectedMQTT_MQTTState()
value of MQTT connected
boolean isConnectedWIFI_MQTTState()
value of WIFI connected
char * deviceName_mainModule()
gets the device name
Definition: MainModule.cpp:844
int getFeedCount_mainModule()
feedcount info..
Definition: MainModule.cpp:355
char * main_JSONStringForWIFICredentials()
retrieve a JSON string for the ssid and ssid_password: {'ssid':<ssid>,'ssidPassword':<pass>"}
Definition: MainModule.cpp:904
int feedCountMax_mainModule()
returns the max for this feeder
Definition: MainModule.cpp:337
char * getPairedDeviceOrAddress_mainModule()
returns if the paired device is not NONE .. returns address or device
Definition: MainModule.cpp:825
void refreshDelayButtonTouched_MainModule()
called by the feed operation to say the device is still running.. and count it as a button click.
Definition: MainModule.cpp:773
char * connectedBLEDeviceName_mainModule()
returns the connected BLE Device name (the :NAME of advertisment, Address: 01:39:3f:33 part of name,...
float getTemperature_mainModule()
retrieves the temperature .
boolean isValidPairedDevice_mainModule()
returns if the paired device is not NONE. Note, the paired Name might be an address now (see below)
Definition: MainModule.cpp:806
float getBatPercentage_mainModule()
start of the sensor updates ... TODO: tie these to the MQTT messaging as well..
void updateMenuState(ModelKindEnum modelKind)
updates the model for the menu state, this sets max etc
char * menuForState(ModelKindEnum modelKind, int item)
returns the menu string for the deviceState's item number (use woudl go 0..maxItems -1
ModelStateStruct * getModel(ModelKindEnum modelKind)
retrieves the state model for the modelKind
ModelKindEnum
a pseudo Class
@ menusModel
@ pairedDeviceModel
@ timerModel
@ rebootModel
@ pairedButNotConnectedEnum
@ notConnectedEnum
factory default but not connecte to anything..
@ pairableAndConnectedEnum
@ pairedAndConnectedEnum
void savePreferenceInt_mainModule(int preferenceID, int val)
sets an int preference
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 setOnBootPreferences_mainModule()
set some defaults on boot - that override EPROM this can be called on the HOME screen to set back to ...
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 * getPreferenceString_mainModule(int preferenceID)
returns the preference but in it's own string buffer. As long as you use it before calling getPrefere...
#define PREFERENCE_SENSOR_TILT_VALUE
Sensor preferences.
#define PREFERENCE_ONLY_GEN3_CONNECT_SETTING
if true, only BLEClient connect to GEN3 feeders..
#define PREFERENCE_SEMANTIC_MARKER_ZOOMED_VALUE
Display preferences (SemanticMarker etc) - boolean.
#define PREFERENCE_WIFI_CREDENTIAL_2_SETTING
#define PREFERENCE_MAIN_BLE_SERVER_VALUE
#define PREFERENCE_STEPPER_BUZZER_VALUE
stepper preferences
#define PREFERENCE_WIFI_CREDENTIAL_1_SETTING
#define PREFERENCE_DISPLAY_SCREEN_TIMEOUT_VALUE
sets the timeout value
#define PREFERENCE_DISPLAY_ON_BLANK_SCREEN_VALUE
Display preferences - show messages on blank screen- boolean.
#define PREFERENCE_IS_MINIMAL_MENU_SETTING
sets the max temp for a poweroff
#define PREFERENCE_SCREEN_COLOR_SETTING
ithe color of the screen 0..n
#define PREFERENCE_MAIN_GATEWAY_VALUE
unsigned long millis()
Definition: TinyGPS.cpp:35
boolean doneWIFI_APModule_Credentials()
called to see if the WIFIModule has finished bootstrapping..
An concrete class.
void startDelay(float delayAmountSeconds)
starts delay calculation
boolean delayFinished()
whether the currently delay is finished, false if not running at all
void stopDelay()
stops delay
the struct for the models. Since this isn't straight OO, we are overlaying information....
int currentItem
the current item
boolean perfersBigText
a preference to the View that big text is desired
PairedDeviceStateEnum pairedDeviceStateEnum
int delaySeconds
length of delay (changable..)
int maxItems
the number of items in the model