Skip to content

Commit 22fc58d

Browse files
author
Gregory Schmidt
committed
Add seven segment overlay usermod
1 parent ccd3152 commit 22fc58d

File tree

1 file changed

+221
-14
lines changed

1 file changed

+221
-14
lines changed

usermods/seven_segment_display/usermod_v2_seven_segment_display.h

Lines changed: 221 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,224 @@
55

66

77
class 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+
51259
void 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

Comments
 (0)