55
66
77class SevenSegmentDisplay : public Usermod {
8+
9+ #define WLED_SS_BUFFLEN 6
810 private:
911 // Private class members. You can declare variables and functions only accessible to your usermod here
10- unsigned long lastTime = 0 ;
12+ unsigned long lastRefresh = 0 ;
13+ char ssDisplayBuffer[WLED_SS_BUFFLEN+1 ]; // Runtime buffer of what should be displayed.
14+ char ssCharacterMask[36 ] = {0x77 ,0x11 ,0x6B ,0x3B ,0x1D ,0x3E ,0x7E ,0x13 ,0x7F ,0x1F ,0x5F ,0x7B ,0x66 ,0x79 ,0x6E ,0x4E ,0x76 ,0x5D ,0x44 ,0x71 ,0x5E ,0x64 ,0x27 ,0x58 ,0x77 ,0x4F ,0x1F ,0x48 ,0x3E ,0x6C ,0x75 ,0x25 ,0x7D ,0x2A ,0x3D ,0x6B };
15+ int ssDisplayMessageIdx = 0 ; // Position of the start of the message to be physically displayed.
16+
1117
1218 // set your config variables to their boot default value (this can also be done in readFromConfig() or a constructor if you prefer)
13- bool testBool = false ;
14- unsigned long testULong = 42424242 ;
15- float testFloat = 42.42 ;
16- String testString = " Forty-Two" ;
19+ unsigned long resfreshTime = 497 ;
20+ byte ssLEDPerSegment = 1 ; // The number of LEDs in each segment of the 7 seg (total per digit is 7 * ssLedPerSegment)
21+ byte ssLEDPerPeriod = 1 ; // A Period will have 1x and a Colon will have 2x
22+ int ssStartLED = 0 ; // The pixel that the display starts at.
23+ // HH - 0-23. hh - 1-12, kk - 1-24 hours
24+ // MM or mm - 0-59 minutes
25+ // SS or ss = 0-59 seconds
26+ // : for a colon
27+ // All others for alpha numeric, (will be blank when displaying time)
28+ char ssDisplayMask[WLED_SS_BUFFLEN+1 ] = " HHMMSS" ; // Physical Display Mask, this should reflect physical equipment.
29+ // ssDisplayConfig
30+ // -------
31+ // / A / 0 - EDCGFAB
32+ // / F / B 1 - EDCBAFG
33+ // / / 2 - GCDEFAB
34+ // ------- 3 - GBAFEDC
35+ // / G / 4 - FABGEDC
36+ // / E / C 5 - FABCDEG
37+ // / /
38+ // -------
39+ // D
40+ byte ssDisplayConfig = 5 ; // Physical configuration of the Seven segment display
41+ char ssDisplayMessage[50 ] = " ABCDEF" ;// Message that can scroll across the display
42+ bool ssDoDisplayMessage = 1 ; // If not, display time.
43+ int ssDisplayMessageTime = 10 ; // Length of time to display message before returning to time, in seconds. <0 would be indefinite. High Select of ssDisplayMessageTime and time to finish current scroll
44+ int ssScrollSpeed = 500 ; // Time between advancement of extended message scrolling, in milliseconds.
45+
46+
47+
48+ void _overlaySevenSegmentProcess ()
49+ {
50+ // Do time for now.
51+ if (!ssDoDisplayMessage)
52+ {
53+ // Format the ssDisplayBuffer based on ssDisplayMask
54+ for (int index = 0 ; index < WLED_SS_BUFFLEN; index++)
55+ {
56+ // Only look for time formatting if there are at least 2 characters left in the buffer.
57+ if ((index < WLED_SS_BUFFLEN - 1 ) && (ssDisplayMask[index] == ssDisplayMask[index + 1 ]))
58+ {
59+ int timeVar = 0 ;
60+ switch (ssDisplayMask[index])
61+ {
62+ case ' h' :
63+ timeVar = hourFormat12 (localTime);
64+ break ;
65+ case ' H' :
66+ timeVar = hour (localTime);
67+ break ;
68+ case ' k' :
69+ timeVar = hour (localTime) + 1 ;
70+ break ;
71+ case ' M' :
72+ case ' m' :
73+ timeVar = minute (localTime);
74+ break ;
75+ case ' S' :
76+ case ' s' :
77+ timeVar = second (localTime);
78+ break ;
79+
80+ }
81+
82+ // Only want to leave a blank in the hour formatting.
83+ if ((ssDisplayMask[index] == ' h' || ssDisplayMask[index] == ' H' || ssDisplayMask[index] == ' k' ) && timeVar < 10 )
84+ ssDisplayBuffer[index] = ' ' ;
85+ else
86+ ssDisplayBuffer[index] = 0x30 + (timeVar / 10 );
87+ ssDisplayBuffer[index + 1 ] = 0x30 + (timeVar % 10 );
88+
89+ // Need to increment the index because of the second digit.
90+ index++;
91+ }
92+ else
93+ {
94+ ssDisplayBuffer[index] = (ssDisplayMask[index] == ' :' ? ' :' : ' ' );
95+ }
96+ }
97+ }
98+ else
99+ {
100+ /* This will handle displaying a message and the scrolling of the message if its longer than the buffer length */
101+ // TODO: Progress message starting point depending on display length, message length, display time, etc...
102+
103+ // Display message
104+ for (int index = 0 ; index < WLED_SS_BUFFLEN; index++){
105+ ssDisplayBuffer[index] = ssDisplayMessage[ssDisplayMessageIdx+index];
106+ }
107+ }
108+ }
109+
110+ void _overlaySevenSegmentDraw ()
111+ {
112+
113+ // Start pixels at ssStartLED, Use ssLEDPerSegment, ssLEDPerPeriod, ssDisplayBuffer
114+ int indexLED = 0 ;
115+ for (int indexBuffer = 0 ; indexBuffer < WLED_SS_BUFFLEN; indexBuffer++)
116+ {
117+ if (ssDisplayBuffer[indexBuffer] == 0 ) break ;
118+ else if (ssDisplayBuffer[indexBuffer] == ' .' )
119+ {
120+ // Won't ever turn off LED lights for a period. (or will we?)
121+ indexLED += ssLEDPerPeriod;
122+ continue ;
123+ }
124+ else if (ssDisplayBuffer[indexBuffer] == ' :' )
125+ {
126+ // Turn off colon if odd second?
127+ indexLED += ssLEDPerPeriod * 2 ;
128+ }
129+ else if (ssDisplayBuffer[indexBuffer] == ' ' )
130+ {
131+ // Turn off all 7 segments.
132+ _overlaySevenSegmentLEDOutput (0 , indexLED);
133+ indexLED += ssLEDPerSegment * 7 ;
134+ }
135+ else
136+ {
137+ // Turn off correct segments.
138+ _overlaySevenSegmentLEDOutput (_overlaySevenSegmentGetCharMask (ssDisplayBuffer[indexBuffer]), indexLED);
139+ indexLED += ssLEDPerSegment * 7 ;
140+ }
141+
142+ }
17143
18- // These config variables have defaults set inside readFromConfig()
19- int testInt;
20- long testLong;
21- int8_t testPins[2 ];
144+ }
145+
146+ void _overlaySevenSegmentLEDOutput (char mask, int indexLED)
147+ {
148+ for (char index = 0 ; index < 7 ; index++)
149+ {
150+ if ((mask & (0x40 >> index)) != (0x40 >> index))
151+ {
152+ for (int numPerSeg = 0 ; numPerSeg < ssLEDPerSegment; numPerSeg++)
153+ {
154+ strip.setPixelColor (indexLED, 0x000000 );
155+ }
156+ }
157+ indexLED += ssLEDPerSegment;
158+ }
159+ }
160+
161+ char _overlaySevenSegmentGetCharMask (char var)
162+ {
163+ // ssCharacterMask
164+ if (var > 0x60 ) // Essentially a "toLower" call.
165+ var -= 0x20 ;
166+ if (var > 0x9 ) // Meaning it is a non-numeric
167+ var -= 0x07 ;
168+ var -= 0x30 ; // Shift ascii down to start numeric 0 at index 0.
169+
170+ char mask = ssCharacterMask[var];
171+ /*
172+ 0 - EDCGFAB
173+ 1 - EDCBAFG
174+ 2 - GCDEFAB
175+ 3 - GBAFEDC
176+ 4 - FABGEDC
177+ 5 - FABCDEG
178+ */
179+ switch (ssDisplayConfig)
180+ {
181+ case 1 :
182+ mask = _overlaySevenSegmentSwapBits (mask, 0 , 3 , 1 );
183+ mask = _overlaySevenSegmentSwapBits (mask, 1 , 2 , 1 );
184+ break ;
185+ case 2 :
186+ mask = _overlaySevenSegmentSwapBits (mask, 3 , 6 , 1 );
187+ mask = _overlaySevenSegmentSwapBits (mask, 4 , 5 , 1 );
188+ break ;
189+ case 3 :
190+ mask = _overlaySevenSegmentSwapBits (mask, 0 , 4 , 3 );
191+ mask = _overlaySevenSegmentSwapBits (mask, 3 , 6 , 1 );
192+ mask = _overlaySevenSegmentSwapBits (mask, 4 , 5 , 1 );
193+ break ;
194+ case 4 :
195+ mask = _overlaySevenSegmentSwapBits (mask, 0 , 4 , 3 );
196+ break ;
197+ case 5 :
198+ mask = _overlaySevenSegmentSwapBits (mask, 0 , 4 , 3 );
199+ mask = _overlaySevenSegmentSwapBits (mask, 0 , 3 , 1 );
200+ mask = _overlaySevenSegmentSwapBits (mask, 1 , 2 , 1 );
201+ break ;
202+ }
203+ return mask;
204+ }
205+
206+ char _overlaySevenSegmentSwapBits (char x, char p1, char p2, char n)
207+ {
208+ /* Move all bits of first set to rightmost side */
209+ char set1 = (x >> p1) & ((1U << n) - 1 );
210+
211+ /* Move all bits of second set to rightmost side */
212+ char set2 = (x >> p2) & ((1U << n) - 1 );
213+
214+ /* Xor the two sets */
215+ char Xor = (set1 ^ set2);
216+
217+ /* Put the Xor bits back to their original positions */
218+ Xor = (Xor << p1) | (Xor << p2);
219+
220+ /* Xor the 'Xor' with the original number so that the
221+ two sets are swapped */
222+ char result = x ^ Xor;
223+
224+ return result;
225+ }
22226
23227 public:
24228 // Functions called by WLED
@@ -42,12 +246,16 @@ class SevenSegmentDisplay : public Usermod {
42246 * Instead, use a timer check as shown here.
43247 */
44248 void loop () {
45- if (millis () - lastTime > 1000 ) {
46- // Serial.println("I'm alive!" );
47- lastTime = millis ();
249+ if (millis () - lastRefresh > resfreshTime ) {
250+ _overlaySevenSegmentProcess ( );
251+ lastRefresh = millis ();
48252 }
49253 }
50254
255+ void handleOverlayDraw (){
256+ _overlaySevenSegmentDraw ();
257+ }
258+
51259void onMqttConnect (bool sessionPresent)
52260{
53261 if (mqttDeviceTopic[0 ] == 0 )
@@ -242,6 +450,5 @@ bool onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties
242450 return USERMOD_ID_SEVEN_SEGMENT_DISPLAY;
243451 }
244452
245- // More methods can be added in the future, this example will then be extended.
246- // Your usermod will remain compatible as it does not need to implement all methods from the Usermod base class!
453+
247454};
0 commit comments