Add seven segment overlay usermod
This commit is contained in:
parent
ccd3152b24
commit
22fc58d93b
@ -5,20 +5,224 @@
|
|||||||
|
|
||||||
|
|
||||||
class SevenSegmentDisplay : public Usermod {
|
class SevenSegmentDisplay : public Usermod {
|
||||||
|
|
||||||
|
#define WLED_SS_BUFFLEN 6
|
||||||
private:
|
private:
|
||||||
//Private class members. You can declare variables and functions only accessible to your usermod here
|
//Private class members. You can declare variables and functions only accessible to your usermod here
|
||||||
unsigned long lastTime = 0;
|
unsigned long lastRefresh = 0;
|
||||||
|
char ssDisplayBuffer[WLED_SS_BUFFLEN+1]; //Runtime buffer of what should be displayed.
|
||||||
|
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};
|
||||||
|
int ssDisplayMessageIdx = 0; //Position of the start of the message to be physically displayed.
|
||||||
|
|
||||||
|
|
||||||
// set your config variables to their boot default value (this can also be done in readFromConfig() or a constructor if you prefer)
|
// set your config variables to their boot default value (this can also be done in readFromConfig() or a constructor if you prefer)
|
||||||
bool testBool = false;
|
unsigned long resfreshTime = 497;
|
||||||
unsigned long testULong = 42424242;
|
byte ssLEDPerSegment = 1; //The number of LEDs in each segment of the 7 seg (total per digit is 7 * ssLedPerSegment)
|
||||||
float testFloat = 42.42;
|
byte ssLEDPerPeriod = 1; //A Period will have 1x and a Colon will have 2x
|
||||||
String testString = "Forty-Two";
|
int ssStartLED = 0; //The pixel that the display starts at.
|
||||||
|
// HH - 0-23. hh - 1-12, kk - 1-24 hours
|
||||||
|
// MM or mm - 0-59 minutes
|
||||||
|
// SS or ss = 0-59 seconds
|
||||||
|
// : for a colon
|
||||||
|
// All others for alpha numeric, (will be blank when displaying time)
|
||||||
|
char ssDisplayMask[WLED_SS_BUFFLEN+1] = "HHMMSS"; //Physical Display Mask, this should reflect physical equipment.
|
||||||
|
// ssDisplayConfig
|
||||||
|
// -------
|
||||||
|
// / A / 0 - EDCGFAB
|
||||||
|
// / F / B 1 - EDCBAFG
|
||||||
|
// / / 2 - GCDEFAB
|
||||||
|
// ------- 3 - GBAFEDC
|
||||||
|
// / G / 4 - FABGEDC
|
||||||
|
// / E / C 5 - FABCDEG
|
||||||
|
// / /
|
||||||
|
// -------
|
||||||
|
// D
|
||||||
|
byte ssDisplayConfig = 5; //Physical configuration of the Seven segment display
|
||||||
|
char ssDisplayMessage[50] = "ABCDEF";//Message that can scroll across the display
|
||||||
|
bool ssDoDisplayMessage = 1; //If not, display time.
|
||||||
|
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
|
||||||
|
int ssScrollSpeed = 500; //Time between advancement of extended message scrolling, in milliseconds.
|
||||||
|
|
||||||
// These config variables have defaults set inside readFromConfig()
|
|
||||||
int testInt;
|
|
||||||
long testLong;
|
void _overlaySevenSegmentProcess()
|
||||||
int8_t testPins[2];
|
{
|
||||||
|
//Do time for now.
|
||||||
|
if(!ssDoDisplayMessage)
|
||||||
|
{
|
||||||
|
//Format the ssDisplayBuffer based on ssDisplayMask
|
||||||
|
for(int index = 0; index < WLED_SS_BUFFLEN; index++)
|
||||||
|
{
|
||||||
|
//Only look for time formatting if there are at least 2 characters left in the buffer.
|
||||||
|
if((index < WLED_SS_BUFFLEN - 1) && (ssDisplayMask[index] == ssDisplayMask[index + 1]))
|
||||||
|
{
|
||||||
|
int timeVar = 0;
|
||||||
|
switch(ssDisplayMask[index])
|
||||||
|
{
|
||||||
|
case 'h':
|
||||||
|
timeVar = hourFormat12(localTime);
|
||||||
|
break;
|
||||||
|
case 'H':
|
||||||
|
timeVar = hour(localTime);
|
||||||
|
break;
|
||||||
|
case 'k':
|
||||||
|
timeVar = hour(localTime) + 1;
|
||||||
|
break;
|
||||||
|
case 'M':
|
||||||
|
case 'm':
|
||||||
|
timeVar = minute(localTime);
|
||||||
|
break;
|
||||||
|
case 'S':
|
||||||
|
case 's':
|
||||||
|
timeVar = second(localTime);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//Only want to leave a blank in the hour formatting.
|
||||||
|
if((ssDisplayMask[index] == 'h' || ssDisplayMask[index] == 'H' || ssDisplayMask[index] == 'k') && timeVar < 10)
|
||||||
|
ssDisplayBuffer[index] = ' ';
|
||||||
|
else
|
||||||
|
ssDisplayBuffer[index] = 0x30 + (timeVar / 10);
|
||||||
|
ssDisplayBuffer[index + 1] = 0x30 + (timeVar % 10);
|
||||||
|
|
||||||
|
//Need to increment the index because of the second digit.
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ssDisplayBuffer[index] = (ssDisplayMask[index] == ':' ? ':' : ' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* This will handle displaying a message and the scrolling of the message if its longer than the buffer length */
|
||||||
|
//TODO: Progress message starting point depending on display length, message length, display time, etc...
|
||||||
|
|
||||||
|
//Display message
|
||||||
|
for(int index = 0; index < WLED_SS_BUFFLEN; index++){
|
||||||
|
ssDisplayBuffer[index] = ssDisplayMessage[ssDisplayMessageIdx+index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _overlaySevenSegmentDraw()
|
||||||
|
{
|
||||||
|
|
||||||
|
//Start pixels at ssStartLED, Use ssLEDPerSegment, ssLEDPerPeriod, ssDisplayBuffer
|
||||||
|
int indexLED = 0;
|
||||||
|
for(int indexBuffer = 0; indexBuffer < WLED_SS_BUFFLEN; indexBuffer++)
|
||||||
|
{
|
||||||
|
if(ssDisplayBuffer[indexBuffer] == 0) break;
|
||||||
|
else if(ssDisplayBuffer[indexBuffer] == '.')
|
||||||
|
{
|
||||||
|
//Won't ever turn off LED lights for a period. (or will we?)
|
||||||
|
indexLED += ssLEDPerPeriod;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if(ssDisplayBuffer[indexBuffer] == ':')
|
||||||
|
{
|
||||||
|
//Turn off colon if odd second?
|
||||||
|
indexLED += ssLEDPerPeriod * 2;
|
||||||
|
}
|
||||||
|
else if(ssDisplayBuffer[indexBuffer] == ' ')
|
||||||
|
{
|
||||||
|
//Turn off all 7 segments.
|
||||||
|
_overlaySevenSegmentLEDOutput(0, indexLED);
|
||||||
|
indexLED += ssLEDPerSegment * 7;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Turn off correct segments.
|
||||||
|
_overlaySevenSegmentLEDOutput(_overlaySevenSegmentGetCharMask(ssDisplayBuffer[indexBuffer]), indexLED);
|
||||||
|
indexLED += ssLEDPerSegment * 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void _overlaySevenSegmentLEDOutput(char mask, int indexLED)
|
||||||
|
{
|
||||||
|
for(char index = 0; index < 7; index++)
|
||||||
|
{
|
||||||
|
if((mask & (0x40 >> index)) != (0x40 >> index))
|
||||||
|
{
|
||||||
|
for(int numPerSeg = 0; numPerSeg < ssLEDPerSegment; numPerSeg++)
|
||||||
|
{
|
||||||
|
strip.setPixelColor(indexLED, 0x000000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
indexLED += ssLEDPerSegment;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char _overlaySevenSegmentGetCharMask(char var)
|
||||||
|
{
|
||||||
|
//ssCharacterMask
|
||||||
|
if(var > 0x60) //Essentially a "toLower" call.
|
||||||
|
var -= 0x20;
|
||||||
|
if(var > 0x9) //Meaning it is a non-numeric
|
||||||
|
var -= 0x07;
|
||||||
|
var -= 0x30; //Shift ascii down to start numeric 0 at index 0.
|
||||||
|
|
||||||
|
char mask = ssCharacterMask[var];
|
||||||
|
/*
|
||||||
|
0 - EDCGFAB
|
||||||
|
1 - EDCBAFG
|
||||||
|
2 - GCDEFAB
|
||||||
|
3 - GBAFEDC
|
||||||
|
4 - FABGEDC
|
||||||
|
5 - FABCDEG
|
||||||
|
*/
|
||||||
|
switch(ssDisplayConfig)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
mask = _overlaySevenSegmentSwapBits(mask, 0, 3, 1);
|
||||||
|
mask = _overlaySevenSegmentSwapBits(mask, 1, 2, 1);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
mask = _overlaySevenSegmentSwapBits(mask, 3, 6, 1);
|
||||||
|
mask = _overlaySevenSegmentSwapBits(mask, 4, 5, 1);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
mask = _overlaySevenSegmentSwapBits(mask, 0, 4, 3);
|
||||||
|
mask = _overlaySevenSegmentSwapBits(mask, 3, 6, 1);
|
||||||
|
mask = _overlaySevenSegmentSwapBits(mask, 4, 5, 1);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
mask = _overlaySevenSegmentSwapBits(mask, 0, 4, 3);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
mask = _overlaySevenSegmentSwapBits(mask, 0, 4, 3);
|
||||||
|
mask = _overlaySevenSegmentSwapBits(mask, 0, 3, 1);
|
||||||
|
mask = _overlaySevenSegmentSwapBits(mask, 1, 2, 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
char _overlaySevenSegmentSwapBits(char x, char p1, char p2, char n)
|
||||||
|
{
|
||||||
|
/* Move all bits of first set to rightmost side */
|
||||||
|
char set1 = (x >> p1) & ((1U << n) - 1);
|
||||||
|
|
||||||
|
/* Move all bits of second set to rightmost side */
|
||||||
|
char set2 = (x >> p2) & ((1U << n) - 1);
|
||||||
|
|
||||||
|
/* Xor the two sets */
|
||||||
|
char Xor = (set1 ^ set2);
|
||||||
|
|
||||||
|
/* Put the Xor bits back to their original positions */
|
||||||
|
Xor = (Xor << p1) | (Xor << p2);
|
||||||
|
|
||||||
|
/* Xor the 'Xor' with the original number so that the
|
||||||
|
two sets are swapped */
|
||||||
|
char result = x ^ Xor;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
//Functions called by WLED
|
//Functions called by WLED
|
||||||
@ -42,12 +246,16 @@ class SevenSegmentDisplay : public Usermod {
|
|||||||
* Instead, use a timer check as shown here.
|
* Instead, use a timer check as shown here.
|
||||||
*/
|
*/
|
||||||
void loop() {
|
void loop() {
|
||||||
if (millis() - lastTime > 1000) {
|
if (millis() - lastRefresh > resfreshTime) {
|
||||||
//Serial.println("I'm alive!");
|
_overlaySevenSegmentProcess();
|
||||||
lastTime = millis();
|
lastRefresh = millis();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void handleOverlayDraw(){
|
||||||
|
_overlaySevenSegmentDraw();
|
||||||
|
}
|
||||||
|
|
||||||
void onMqttConnect(bool sessionPresent)
|
void onMqttConnect(bool sessionPresent)
|
||||||
{
|
{
|
||||||
if (mqttDeviceTopic[0] == 0)
|
if (mqttDeviceTopic[0] == 0)
|
||||||
@ -242,6 +450,5 @@ bool onMqttMessage(char *topic, char *payload, AsyncMqttClientMessageProperties
|
|||||||
return USERMOD_ID_SEVEN_SEGMENT_DISPLAY;
|
return USERMOD_ID_SEVEN_SEGMENT_DISPLAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
//More methods can be added in the future, this example will then be extended.
|
|
||||||
//Your usermod will remain compatible as it does not need to implement all methods from the Usermod base class!
|
|
||||||
};
|
};
|
Loading…
Reference in New Issue
Block a user