Increased time before reading temperature.

4LD modifications.
This commit is contained in:
Blaz Kristan 2021-12-19 21:14:54 +01:00
parent 6463fbee32
commit c3df9e6270
3 changed files with 191 additions and 197 deletions

View File

@ -60,7 +60,7 @@ class UsermodTemperature : public Usermod {
if (oneWire->reset()) { // if reset() fails there are no OneWire devices if (oneWire->reset()) { // if reset() fails there are no OneWire devices
oneWire->skip(); // skip ROM oneWire->skip(); // skip ROM
oneWire->write(0xBE); // read (temperature) from EEPROM oneWire->write(0xBE); // read (temperature) from EEPROM
delayMicroseconds(150); delayMicroseconds(250);
oneWire->read_bytes(data, 9); // first 2 bytes contain temperature oneWire->read_bytes(data, 9); // first 2 bytes contain temperature
#ifdef WLED_DEBUG #ifdef WLED_DEBUG
if (OneWire::crc8(data,8) != data[8]) { if (OneWire::crc8(data,8) != data[8]) {

View File

@ -131,12 +131,11 @@ class FourLineDisplayUsermod : public Usermod {
#ifndef FLD_SPI_DEFAULT #ifndef FLD_SPI_DEFAULT
int8_t ioPin[5] = {FLD_PIN_SCL, FLD_PIN_SDA, -1, -1, -1}; // I2C pins: SCL, SDA int8_t ioPin[5] = {FLD_PIN_SCL, FLD_PIN_SDA, -1, -1, -1}; // I2C pins: SCL, SDA
uint32_t ioFrequency = 400000; // in Hz (minimum is 100000, baseline is 400000 and maximum should be 3400000) uint32_t ioFrequency = 400000; // in Hz (minimum is 100000, baseline is 400000 and maximum should be 3400000)
DisplayType type = FLD_TYPE; // display type
#else #else
int8_t ioPin[5] = {FLD_PIN_CLOCKSPI, FLD_PIN_DATASPI, FLD_PIN_CS, FLD_PIN_DC, FLD_PIN_RESET}; // SPI pins: CLK, MOSI, CS, DC, RST int8_t ioPin[5] = {FLD_PIN_CLOCKSPI, FLD_PIN_DATASPI, FLD_PIN_CS, FLD_PIN_DC, FLD_PIN_RESET}; // SPI pins: CLK, MOSI, CS, DC, RST
uint32_t ioFrequency = 1000000; // in Hz (minimum is 500kHz, baseline is 1MHz and maximum should be 20MHz) uint32_t ioFrequency = 1000000; // in Hz (minimum is 500kHz, baseline is 1MHz and maximum should be 20MHz)
DisplayType type = FLD_TYPE; // display type
#endif #endif
DisplayType type = FLD_TYPE; // display type
bool flip = false; // flip display 180° bool flip = false; // flip display 180°
uint8_t contrast = 10; // screen contrast uint8_t contrast = 10; // screen contrast
uint8_t lineHeight = 1; // 1 row or 2 rows uint8_t lineHeight = 1; // 1 row or 2 rows

View File

@ -25,6 +25,10 @@
//The SCL and SDA pins are defined here. //The SCL and SDA pins are defined here.
#ifdef ARDUINO_ARCH_ESP32 #ifdef ARDUINO_ARCH_ESP32
#define HW_PIN_SCL 22
#define HW_PIN_SDA 21
#define HW_PIN_CLOCKSPI 18
#define HW_PIN_DATASPI 23
#ifndef FLD_PIN_SCL #ifndef FLD_PIN_SCL
#define FLD_PIN_SCL 22 #define FLD_PIN_SCL 22
#endif #endif
@ -47,6 +51,10 @@
#define FLD_PIN_RESET 26 #define FLD_PIN_RESET 26
#endif #endif
#else #else
#define HW_PIN_SCL 5
#define HW_PIN_SDA 4
#define HW_PIN_CLOCKSPI 14
#define HW_PIN_DATASPI 13
#ifndef FLD_PIN_SCL #ifndef FLD_PIN_SCL
#define FLD_PIN_SCL 5 #define FLD_PIN_SCL 5
#endif #endif
@ -70,6 +78,14 @@
#endif #endif
#endif #endif
#ifndef FLD_TYPE
#ifndef FLD_SPI_DEFAULT
#define FLD_TYPE SSD1306
#else
#define FLD_TYPE SSD1306_SPI
#endif
#endif
// When to time out to the clock or blank the screen // When to time out to the clock or blank the screen
// if SLEEP_MODE_ENABLED. // if SLEEP_MODE_ENABLED.
#define SCREEN_TIMEOUT_MS 60*1000 // 1 min #define SCREEN_TIMEOUT_MS 60*1000 // 1 min
@ -78,13 +94,22 @@
#define DATE_INDENT 2 #define DATE_INDENT 2
// Minimum time between redrawing screen in ms // Minimum time between redrawing screen in ms
#define USER_LOOP_REFRESH_RATE_MS 100 #define USER_LOOP_REFRESH_RATE_MS 1000
// Extra char (+1) for null // Extra char (+1) for null
#define LINE_BUFFER_SIZE 16+1 #define LINE_BUFFER_SIZE 16+1
#define MAX_JSON_CHARS 19+1 #define MAX_JSON_CHARS 19+1
#define MAX_MODE_LINE_SPACE 13+1 #define MAX_MODE_LINE_SPACE 13+1
typedef enum {
FLD_LINE_BRIGHTNESS = 0,
FLD_LINE_EFFECT_SPEED,
FLD_LINE_EFFECT_INTENSITY,
FLD_LINE_MODE,
FLD_LINE_PALETTE,
FLD_LINE_TIME
} Line4Type;
typedef enum { typedef enum {
NONE = 0, NONE = 0,
SSD1306, // U8X8_SSD1306_128X32_UNIVISION_HW_I2C SSD1306, // U8X8_SSD1306_128X32_UNIVISION_HW_I2C
@ -236,11 +261,11 @@ class FourLineDisplayUsermod : public Usermod {
#ifndef FLD_SPI_DEFAULT #ifndef FLD_SPI_DEFAULT
int8_t ioPin[5] = {FLD_PIN_SCL, FLD_PIN_SDA, -1, -1, -1}; // I2C pins: SCL, SDA int8_t ioPin[5] = {FLD_PIN_SCL, FLD_PIN_SDA, -1, -1, -1}; // I2C pins: SCL, SDA
uint32_t ioFrequency = 400000; // in Hz (minimum is 100000, baseline is 400000 and maximum should be 3400000) uint32_t ioFrequency = 400000; // in Hz (minimum is 100000, baseline is 400000 and maximum should be 3400000)
DisplayType type = SSD1306_64; // display type
#else #else
int8_t ioPin[5] = {FLD_PIN_CLOCKSPI, FLD_PIN_DATASPI, FLD_PIN_CS, FLD_PIN_DC, FLD_PIN_RESET}; // SPI pins: CLK, MOSI, CS, DC, RST int8_t ioPin[5] = {FLD_PIN_CLOCKSPI, FLD_PIN_DATASPI, FLD_PIN_CS, FLD_PIN_DC, FLD_PIN_RESET}; // SPI pins: CLK, MOSI, CS, DC, RST
DisplayType type = SSD1306_SPI; // display type uint32_t ioFrequency = 1000000; // in Hz (minimum is 500kHz, baseline is 1MHz and maximum should be 20MHz)
#endif #endif
DisplayType type = FLD_TYPE; // display type
bool flip = false; // flip display 180° bool flip = false; // flip display 180°
uint8_t contrast = 10; // screen contrast uint8_t contrast = 10; // screen contrast
uint8_t lineHeight = 1; // 1 row or 2 rows uint8_t lineHeight = 1; // 1 row or 2 rows
@ -248,6 +273,7 @@ class FourLineDisplayUsermod : public Usermod {
uint32_t screenTimeout = SCREEN_TIMEOUT_MS; // in ms uint32_t screenTimeout = SCREEN_TIMEOUT_MS; // in ms
bool sleepMode = true; // allow screen sleep? bool sleepMode = true; // allow screen sleep?
bool clockMode = false; // display clock bool clockMode = false; // display clock
bool enabled = true;
// needRedraw marks if redraw is required to prevent often redrawing. // needRedraw marks if redraw is required to prevent often redrawing.
bool needRedraw = true; bool needRedraw = true;
@ -273,12 +299,14 @@ class FourLineDisplayUsermod : public Usermod {
unsigned long lastUpdate = 0; unsigned long lastUpdate = 0;
unsigned long lastRedraw = 0; unsigned long lastRedraw = 0;
unsigned long overlayUntil = 0; unsigned long overlayUntil = 0;
Line4Type lineType = FLD_LINE_BRIGHTNESS;
// Set to 2 or 3 to mark lines 2 or 3. Other values ignored. // Set to 2 or 3 to mark lines 2 or 3. Other values ignored.
byte markLineNum = 0; byte markLineNum = 0;
byte markColNum = 0; byte markColNum = 0;
// strings to reduce flash memory usage (used more than twice) // strings to reduce flash memory usage (used more than twice)
static const char _name[]; static const char _name[];
static const char _enabled[];
static const char _contrast[]; static const char _contrast[];
static const char _refreshRate[]; static const char _refreshRate[];
static const char _screenTimeOut[]; static const char _screenTimeOut[];
@ -298,88 +326,72 @@ class FourLineDisplayUsermod : public Usermod {
// gets called once at boot. Do all initialization that doesn't depend on // gets called once at boot. Do all initialization that doesn't depend on
// network here // network here
void setup() { void setup() {
if (type == NONE) return; if (type == NONE || !enabled) return;
bool isHW;
PinOwner po = PinOwner::UM_FourLineDisplay;
if (type == SSD1306_SPI || type == SSD1306_SPI64) { if (type == SSD1306_SPI || type == SSD1306_SPI64) {
PinManagerPinType pins[5] = { { ioPin[0], true }, { ioPin[1], true}, { ioPin[2], true }, { ioPin[3], true}, { ioPin[4], true }}; isHW = (ioPin[0]==HW_PIN_CLOCKSPI && ioPin[1]==HW_PIN_DATASPI);
if (!pinManager.allocateMultiplePins(pins, 5, PinOwner::UM_FourLineDisplay)) { type=NONE; return; } PinManagerPinType pins[5] = { { ioPin[0], true }, { ioPin[1], true }, { ioPin[2], true }, { ioPin[3], true }, { ioPin[4], true }};
if (!pinManager.allocateMultiplePins(pins, 5, po)) { type=NONE; return; }
} else { } else {
PinManagerPinType pins[2] = { { ioPin[0], true }, { ioPin[1], true} }; isHW = (ioPin[0]==HW_PIN_SCL && ioPin[1]==HW_PIN_SDA);
if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::UM_FourLineDisplay)) { type=NONE; return; } PinManagerPinType pins[2] = { { ioPin[0], true }, { ioPin[1], true } };
if (ioPin[0]==HW_PIN_SCL && ioPin[1]==HW_PIN_SDA) po = PinOwner::HW_I2C; // allow multiple allocations of HW I2C bus pins
if (!pinManager.allocateMultiplePins(pins, 2, po)) { type=NONE; return; }
} }
DEBUG_PRINTLN(F("Allocating display.")); DEBUG_PRINTLN(F("Allocating display."));
switch (type) { switch (type) {
case SSD1306: case SSD1306:
#ifdef ESP8266 if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset
if (!(ioPin[0]==5 && ioPin[1]==4)) else u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA
u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset
else
#endif
u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA
lineHeight = 1; lineHeight = 1;
break; break;
case SH1106: case SH1106:
#ifdef ESP8266 if (!isHW) u8x8 = (U8X8 *) new U8X8_SH1106_128X64_WINSTAR_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset
if (!(ioPin[0]==5 && ioPin[1]==4)) else u8x8 = (U8X8 *) new U8X8_SH1106_128X64_WINSTAR_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA
u8x8 = (U8X8 *) new U8X8_SH1106_128X64_WINSTAR_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset
else
#endif
u8x8 = (U8X8 *) new U8X8_SH1106_128X64_WINSTAR_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA
lineHeight = 2; lineHeight = 2;
break; break;
case SSD1306_64: case SSD1306_64:
#ifdef ESP8266 if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset
if (!(ioPin[0]==5 && ioPin[1]==4)) else u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA
u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset
else
#endif
u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA
lineHeight = 2; lineHeight = 2;
break; break;
case SSD1305: case SSD1305:
#ifdef ESP8266 if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1305_128X32_NONAME_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset
if (!(ioPin[0]==5 && ioPin[1]==4)) else u8x8 = (U8X8 *) new U8X8_SSD1305_128X32_ADAFRUIT_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA
u8x8 = (U8X8 *) new U8X8_SSD1305_128X32_NONAME_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset
else
#endif
u8x8 = (U8X8 *) new U8X8_SSD1305_128X32_ADAFRUIT_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA
lineHeight = 1; lineHeight = 1;
break; break;
case SSD1305_64: case SSD1305_64:
#ifdef ESP8266 if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1305_128X64_ADAFRUIT_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset
if (!(ioPin[0]==5 && ioPin[1]==4)) else u8x8 = (U8X8 *) new U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA
u8x8 = (U8X8 *) new U8X8_SSD1305_128X64_ADAFRUIT_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset
else
#endif
u8x8 = (U8X8 *) new U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA
lineHeight = 2; lineHeight = 2;
break; break;
case SSD1306_SPI: case SSD1306_SPI:
if (!(ioPin[0]==FLD_PIN_CLOCKSPI && ioPin[1]==FLD_PIN_DATASPI)) // if not overridden these sould be HW accellerated if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_4W_SW_SPI(ioPin[0], ioPin[1], ioPin[2], ioPin[3], ioPin[4]);
u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_4W_SW_SPI(ioPin[0], ioPin[1], ioPin[2], ioPin[3], ioPin[4]); else u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_4W_HW_SPI(ioPin[2], ioPin[3], ioPin[4]); // Pins are cs, dc, reset
else
u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_4W_HW_SPI(ioPin[2], ioPin[3], ioPin[4]); // Pins are cs, dc, reset
lineHeight = 1; lineHeight = 1;
break; break;
case SSD1306_SPI64: case SSD1306_SPI64:
if (!(ioPin[0]==FLD_PIN_CLOCKSPI && ioPin[1]==FLD_PIN_DATASPI)) // if not overridden these sould be HW accellerated if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_4W_SW_SPI(ioPin[0], ioPin[1], ioPin[2], ioPin[3], ioPin[4]);
u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_4W_SW_SPI(ioPin[0], ioPin[1], ioPin[2], ioPin[3], ioPin[4]); else u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_4W_HW_SPI(ioPin[2], ioPin[3], ioPin[4]); // Pins are cs, dc, reset
else
u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_4W_HW_SPI(ioPin[2], ioPin[3], ioPin[4]); // Pins are cs, dc, reset
lineHeight = 2; lineHeight = 2;
break; break;
default: default:
u8x8 = nullptr; u8x8 = nullptr;
} }
if (nullptr == u8x8) { if (nullptr == u8x8) {
DEBUG_PRINTLN(F("Display init failed.")); DEBUG_PRINTLN(F("Display init failed."));
for (byte i=0; i<5 && ioPin[i]>=0; i++) pinManager.deallocatePin(ioPin[i], PinOwner::UM_FourLineDisplay); pinManager.deallocateMultiplePins((const uint8_t*)ioPin, (type == SSD1306_SPI || type == SSD1306_SPI64) ? 5 : 2, po);
type = NONE; type = NONE;
return; return;
} }
initDone = true; initDone = true;
DEBUG_PRINTLN(F("Starting display.")); DEBUG_PRINTLN(F("Starting display."));
if (!(type == SSD1306_SPI || type == SSD1306_SPI64)) u8x8->setBusClock(ioFrequency); // can be used for SPI too /*if (!(type == SSD1306_SPI || type == SSD1306_SPI64))*/ u8x8->setBusClock(ioFrequency); // can be used for SPI too
u8x8->begin(); u8x8->begin();
setFlipMode(flip); setFlipMode(flip);
setContrast(contrast); //Contrast setup will help to preserve OLED lifetime. In case OLED need to be brighter increase number up to 255 setContrast(contrast); //Contrast setup will help to preserve OLED lifetime. In case OLED need to be brighter increase number up to 255
@ -395,52 +407,50 @@ class FourLineDisplayUsermod : public Usermod {
* Da loop. * Da loop.
*/ */
void loop() { void loop() {
if (displayTurnedOff && millis() - lastUpdate < 1000) { if (!enabled || millis() - lastUpdate < (clockMode?1000:refreshRate) || strip.isUpdating()) return;
return;
}else if (millis() - lastUpdate < refreshRate){
return;}
redraw(false);
lastUpdate = millis(); lastUpdate = millis();
redraw(false);
} }
/** /**
* Wrappers for screen drawing * Wrappers for screen drawing
*/ */
void setFlipMode(uint8_t mode) { void setFlipMode(uint8_t mode) {
if (type==NONE) return; if (type == NONE || !enabled) return;
u8x8->setFlipMode(mode); u8x8->setFlipMode(mode);
} }
void setContrast(uint8_t contrast) { void setContrast(uint8_t contrast) {
if (type==NONE) return; if (type == NONE || !enabled) return;
u8x8->setContrast(contrast); u8x8->setContrast(contrast);
} }
void drawString(uint8_t col, uint8_t row, const char *string, bool ignoreLH=false) { void drawString(uint8_t col, uint8_t row, const char *string, bool ignoreLH=false) {
if (type==NONE) return; if (type == NONE || !enabled) return;
u8x8->setFont(u8x8_font_chroma48medium8_r); u8x8->setFont(u8x8_font_chroma48medium8_r);
if (!ignoreLH && lineHeight==2) u8x8->draw1x2String(col, row, string); if (!ignoreLH && lineHeight==2) u8x8->draw1x2String(col, row, string);
else u8x8->drawString(col, row, string); else u8x8->drawString(col, row, string);
} }
void draw2x2String(uint8_t col, uint8_t row, const char *string) { void draw2x2String(uint8_t col, uint8_t row, const char *string) {
if (type==NONE) return; if (type == NONE || !enabled) return;
u8x8->setFont(u8x8_font_chroma48medium8_r); u8x8->setFont(u8x8_font_chroma48medium8_r);
u8x8->draw2x2String(col, row, string); u8x8->draw2x2String(col, row, string);
} }
void drawGlyph(uint8_t col, uint8_t row, char glyph, const uint8_t *font, bool ignoreLH=false) { void drawGlyph(uint8_t col, uint8_t row, char glyph, const uint8_t *font, bool ignoreLH=false) {
if (type==NONE) return; if (type == NONE || !enabled) return;
u8x8->setFont(font); u8x8->setFont(font);
if (!ignoreLH && lineHeight==2) u8x8->draw1x2Glyph(col, row, glyph); if (!ignoreLH && lineHeight==2) u8x8->draw1x2Glyph(col, row, glyph);
else u8x8->drawGlyph(col, row, glyph); else u8x8->drawGlyph(col, row, glyph);
} }
uint8_t getCols() { uint8_t getCols() {
if (type==NONE) return 0; if (type==NONE || !enabled) return 0;
return u8x8->getCols(); return u8x8->getCols();
} }
void clear() { void clear() {
if (type==NONE) return; if (type == NONE || !enabled) return;
u8x8->clear(); u8x8->clear();
} }
void setPowerSave(uint8_t save) { void setPowerSave(uint8_t save) {
if (type==NONE) return; if (type == NONE || !enabled) return;
u8x8->setPowerSave(save); u8x8->setPowerSave(save);
} }
@ -460,9 +470,11 @@ class FourLineDisplayUsermod : public Usermod {
* or if forceRedraw). * or if forceRedraw).
*/ */
void redraw(bool forceRedraw) { void redraw(bool forceRedraw) {
if (type==NONE) return; unsigned long now = millis();
if (type == NONE || !enabled) return;
if (overlayUntil > 0) { if (overlayUntil > 0) {
if (millis() >= overlayUntil) { if (now >= overlayUntil) {
// Time to display the overlay has elapsed. // Time to display the overlay has elapsed.
overlayUntil = 0; overlayUntil = 0;
forceRedraw = true; forceRedraw = true;
@ -514,7 +526,7 @@ class FourLineDisplayUsermod : public Usermod {
if (!needRedraw) { if (!needRedraw) {
// Nothing to change. // Nothing to change.
// Turn off display after 1 minutes with no change. // Turn off display after 1 minutes with no change.
if(sleepMode && !displayTurnedOff && (millis() - lastRedraw > screenTimeout)) { if(sleepMode && !displayTurnedOff && (now - lastRedraw > screenTimeout)) {
// We will still check if there is a change in redraw() // We will still check if there is a change in redraw()
// and turn it back on if it changed. // and turn it back on if it changed.
sleepOrClock(true); sleepOrClock(true);
@ -536,7 +548,7 @@ class FourLineDisplayUsermod : public Usermod {
// Update last known values. // Update last known values.
knownSsid = apActive ? apSSID : WiFi.SSID(); //apActive ? WiFi.softAPSSID() : knownSsid = apActive ? apSSID : WiFi.SSID(); //apActive ? WiFi.softAPSSID() :
knownIp = apActive ? IPAddress(4, 3, 2, 1) : WiFi.localIP(); knownIp = apActive ? IPAddress(4, 3, 2, 1) : Network.localIP();
knownBrightness = bri; knownBrightness = bri;
knownMode = effectCurrent; knownMode = effectCurrent;
knownPalette = effectPalette; knownPalette = effectPalette;
@ -594,26 +606,25 @@ class FourLineDisplayUsermod : public Usermod {
} }
void draw2x2GlyphIcons(){ void draw2x2GlyphIcons(){
if(lineHeight == 2){ if (lineHeight == 2) {
drawGlyph(1, 0, 1, u8x8_font_benji_custom_icons_2x2, true);//brightness icon drawGlyph(1, 0, 1, u8x8_font_benji_custom_icons_2x2, true);//brightness icon
drawGlyph(5, 0, 2, u8x8_font_benji_custom_icons_2x2, true);//speed icon drawGlyph(5, 0, 2, u8x8_font_benji_custom_icons_2x2, true);//speed icon
drawGlyph(9, 0, 3, u8x8_font_benji_custom_icons_2x2, true);//intensity icon drawGlyph(9, 0, 3, u8x8_font_benji_custom_icons_2x2, true);//intensity icon
drawGlyph(14, 2*lineHeight, 4, u8x8_font_benji_custom_icons_2x2, true);//palette icon drawGlyph(14, 2*lineHeight, 4, u8x8_font_benji_custom_icons_2x2, true);//palette icon
drawGlyph(14, 3*lineHeight, 5, u8x8_font_benji_custom_icons_2x2, true);//effect icon drawGlyph(14, 3*lineHeight, 5, u8x8_font_benji_custom_icons_2x2, true);//effect icon
} } else {
else{ drawGlyph(2, 0, 69, u8x8_font_open_iconic_weather_1x1); //brightness icon
drawGlyph(2, 0, 69, u8x8_font_open_iconic_weather_1x1);//brightness icon drawGlyph(6, 0, 72, u8x8_font_open_iconic_play_1x1); //speed icon
drawGlyph(6, 0, 72, u8x8_font_open_iconic_play_1x1);//speed icon drawGlyph(10, 0, 78, u8x8_font_open_iconic_thing_1x1); //intensity icon
drawGlyph(10, 0, 78, u8x8_font_open_iconic_thing_1x1);//intensity icon drawGlyph(15, 2*lineHeight, 4, u8x8_font_benji_custom_icons_1x1); //palette icon
drawGlyph(15, 2*lineHeight, 4, u8x8_font_benji_custom_icons_1x1);//palette icon drawGlyph(15, 3*lineHeight, 70, u8x8_font_open_iconic_thing_1x1); //effect icon
drawGlyph(15, 3*lineHeight, 70, u8x8_font_open_iconic_thing_1x1);//effect icon
} }
} }
void drawStatusIcons(){ void drawStatusIcons(){
drawGlyph(14, 0, 80 + (wificonnected?0:1), u8x8_font_open_iconic_embedded_1x1, true); // wifi icon drawGlyph(14, 0, 80 + (wificonnected?0:1), u8x8_font_open_iconic_embedded_1x1, true); // wifi icon
drawGlyph(15, 0, 78 + (bri > 0 ? 0 : 3), u8x8_font_open_iconic_embedded_1x1, true); // power icon drawGlyph(15, 0, 78 + (bri > 0 ? 0 : 3), u8x8_font_open_iconic_embedded_1x1, true); // power icon
drawGlyph(13, 0, 66 + (nightlightActive?0:4), u8x8_font_open_iconic_weather_1x1, true); // moon icon for nighlight mode drawGlyph(13, 0, 66 + (nightlightActive?0:4), u8x8_font_open_iconic_weather_1x1, true); // moon icon for nighlight mode
} }
/** /**
@ -634,87 +645,62 @@ class FourLineDisplayUsermod : public Usermod {
//Display the current effect or palette (desiredEntry) //Display the current effect or palette (desiredEntry)
// on the appropriate line (row). // on the appropriate line (row).
void showCurrentEffectOrPalette(int inputEffPal, const char *qstring, uint8_t row) { void showCurrentEffectOrPalette(int inputEffPal, const char *qstring, uint8_t row) {
char lineBuffer[LINE_BUFFER_SIZE];
knownMode = effectCurrent; knownMode = effectCurrent;
knownPalette = effectPalette; knownPalette = effectPalette;
if(overlayUntil == 0){ if (overlayUntil == 0) {
char lineBuffer[MAX_JSON_CHARS]; char smallBuffer1[MAX_MODE_LINE_SPACE];
char smallBuffer1[MAX_MODE_LINE_SPACE]; char smallBuffer2[MAX_MODE_LINE_SPACE];
char smallBuffer2[MAX_MODE_LINE_SPACE]; char smallBuffer3[MAX_MODE_LINE_SPACE+1];
char smallBuffer3[MAX_MODE_LINE_SPACE+1]; bool spaceHit = false;
uint8_t qComma = 0; uint8_t printedChars = 0;
bool insideQuotes = false; uint8_t smallChars1 = 0;
bool spaceHit = false; uint8_t smallChars2 = 0;
uint8_t printedChars = 0; uint8_t smallChars3 = 0;
uint8_t smallChars1 = 0; uint8_t totalCount = 0;
uint8_t smallChars2 = 0; char singleJsonSymbol;
uint8_t smallChars3 = 0;
uint8_t totalCount = 0;
char singleJsonSymbol;
// Find the mode name in JSON // Find the mode name in JSON
for (size_t i = 0; i < strlen_P(qstring); i++) { //find and get the full text for printing printedChars = extractModeName(inputEffPal, qstring, lineBuffer, LINE_BUFFER_SIZE-1);
singleJsonSymbol = pgm_read_byte_near(qstring + i);
if (singleJsonSymbol == '\0') break; if (lineHeight == 2) { // use this code for 8 line display
switch (singleJsonSymbol) { if (printedChars < MAX_MODE_LINE_SPACE) { // use big font if the text fits
case '"': for (;printedChars < (MAX_MODE_LINE_SPACE-1); printedChars++) {lineBuffer[printedChars]=' '; }
insideQuotes = !insideQuotes; lineBuffer[printedChars] = 0;
break; drawString(1, row*lineHeight, lineBuffer);
case '[': } else { // for long names divide the text into 2 lines and print them small
case ']': for (uint8_t i = 0; i < printedChars; i++) {
break; switch (lineBuffer[i]) {
case ',': case ' ':
qComma++; if (i > 4 && !spaceHit) {
default: spaceHit = true;
if (!insideQuotes || (qComma != inputEffPal)) break;
lineBuffer[printedChars++] = singleJsonSymbol;
totalCount++;
}
if ((qComma > inputEffPal)) break;
}
if(lineHeight ==2){ // use this code for 8 line display
if(printedChars < (MAX_MODE_LINE_SPACE)){ // use big font if the text fits
for (;printedChars < (MAX_MODE_LINE_SPACE-1); printedChars++) {lineBuffer[printedChars]=' '; }
lineBuffer[printedChars] = 0;
drawString(1, row*lineHeight, lineBuffer);
lastRedraw = millis();
}else{ // for long names divide the text into 2 lines and print them small
for (uint8_t i = 0; i < printedChars; i++){
switch (lineBuffer[i]){
case ' ':
if(i > 4 && !spaceHit) {
spaceHit = true;
break;}
if(!spaceHit) smallBuffer1[smallChars1++] = lineBuffer[i];
if (spaceHit) smallBuffer2[smallChars2++] = lineBuffer[i];
break;
default:
if(!spaceHit) smallBuffer1[smallChars1++] = lineBuffer[i];
if (spaceHit) smallBuffer2[smallChars2++] = lineBuffer[i];
break; break;
} }
} if (spaceHit) smallBuffer2[smallChars2++] = lineBuffer[i];
for (; smallChars1 < (MAX_MODE_LINE_SPACE-1); smallChars1++) smallBuffer1[smallChars1]=' '; else smallBuffer1[smallChars1++] = lineBuffer[i];
smallBuffer1[smallChars1] = 0; break;
drawString(1, row*lineHeight, smallBuffer1, true); default:
for (; smallChars2 < (MAX_MODE_LINE_SPACE-1); smallChars2++) smallBuffer2[smallChars2]=' '; if (spaceHit) smallBuffer2[smallChars2++] = lineBuffer[i];
smallBuffer2[smallChars2] = 0; else smallBuffer1[smallChars1++] = lineBuffer[i];
drawString(1, row*lineHeight+1, smallBuffer2, true); break;
lastRedraw = millis(); }
} }
for (; smallChars1 < (MAX_MODE_LINE_SPACE-1); smallChars1++) smallBuffer1[smallChars1]=' ';
smallBuffer1[smallChars1] = 0;
drawString(1, row*lineHeight, smallBuffer1, true);
for (; smallChars2 < (MAX_MODE_LINE_SPACE-1); smallChars2++) smallBuffer2[smallChars2]=' ';
smallBuffer2[smallChars2] = 0;
drawString(1, row*lineHeight+1, smallBuffer2, true);
} }
else{ // use this code for 4 ling displays } else { // use this code for 4 ling displays
if (printedChars > MAX_MODE_LINE_SPACE) printedChars = MAX_MODE_LINE_SPACE; if (printedChars > MAX_MODE_LINE_SPACE) printedChars = MAX_MODE_LINE_SPACE;
for (uint8_t i = 0; i < printedChars; i++){ for (uint8_t i = 0; i < printedChars; i++) smallBuffer3[smallChars3++] = lineBuffer[i];
smallBuffer3[smallChars3++] = lineBuffer[i]; for (; smallChars3 < (MAX_MODE_LINE_SPACE); smallChars3++) smallBuffer3[smallChars3]=' ';
} smallBuffer3[smallChars3] = 0;
drawString(1, row*lineHeight, smallBuffer3, true);
for (; smallChars3 < (MAX_MODE_LINE_SPACE); smallChars3++) smallBuffer3[smallChars3]=' '; }
smallBuffer3[smallChars3] = 0; lastRedraw = millis();
drawString(1, row*lineHeight, smallBuffer3, true); }
lastRedraw = millis();
}
}
} }
/** /**
@ -724,6 +710,7 @@ class FourLineDisplayUsermod : public Usermod {
* to wake up the screen. * to wake up the screen.
*/ */
bool wakeDisplay() { bool wakeDisplay() {
if (type == NONE || !enabled) return false;
//knownHour = 99; //knownHour = 99;
if (displayTurnedOff) { if (displayTurnedOff) {
// Turn the display back on // Turn the display back on
@ -740,44 +727,44 @@ class FourLineDisplayUsermod : public Usermod {
* Clears the screen and prints. * Clears the screen and prints.
*/ */
void overlay(const char* line1, long showHowLong, byte glyphType) { void overlay(const char* line1, long showHowLong, byte glyphType) {
if (displayTurnedOff) { if (displayTurnedOff) {
// Turn the display back on // Turn the display back on
sleepOrClock(false); sleepOrClock(false);
} }
// Print the overlay // Print the overlay
clear(); clear();
if (glyphType > 0){ if (glyphType > 0) {
if ( lineHeight == 2) drawGlyph(5, 0, glyphType, u8x8_font_benji_custom_icons_6x6, true); if (lineHeight == 2) drawGlyph(5, 0, glyphType, u8x8_font_benji_custom_icons_6x6, true);
else drawGlyph(7, lineHeight, glyphType, u8x8_font_benji_custom_icons_2x2, true); else drawGlyph(7, lineHeight, glyphType, u8x8_font_benji_custom_icons_2x2, true);
} }
if (line1) drawString(0, 3*lineHeight, line1); if (line1) drawString(0, 3*lineHeight, line1);
overlayUntil = millis() + showHowLong; overlayUntil = millis() + showHowLong;
} }
void networkOverlay(const char* line1, long showHowLong) { void networkOverlay(const char* line1, long showHowLong) {
if (displayTurnedOff) { if (displayTurnedOff) {
// Turn the display back on // Turn the display back on
sleepOrClock(false); sleepOrClock(false);
} }
// Print the overlay // Print the overlay
clear(); clear();
// First row string // First row string
if (line1) drawString(0, 0, line1); if (line1) drawString(0, 0, line1);
// Second row with Wifi name // Second row with Wifi name
String ssidString = knownSsid.substring(0, getCols() > 1 ? getCols() - 2 : 0); // String ssidString = knownSsid.substring(0, getCols() > 1 ? getCols() - 2 : 0); //
drawString(0, lineHeight, ssidString.c_str()); drawString(0, lineHeight, ssidString.c_str());
// Print `~` char to indicate that SSID is longer, than our display // Print `~` char to indicate that SSID is longer, than our display
if (knownSsid.length() > getCols()) { if (knownSsid.length() > getCols()) {
drawString(getCols() - 1, 0, "~"); drawString(getCols() - 1, 0, "~");
} }
// Third row with IP and Psssword in AP Mode // Third row with IP and Psssword in AP Mode
drawString(0, lineHeight*2, (knownIp.toString()).c_str()); drawString(0, lineHeight*2, (knownIp.toString()).c_str());
if (apActive) { if (apActive) {
String appassword = apPass; String appassword = apPass;
drawString(0, lineHeight*3, appassword.c_str()); drawString(0, lineHeight*3, appassword.c_str());
} }
overlayUntil = millis() + showHowLong; overlayUntil = millis() + showHowLong;
} }
@ -805,7 +792,8 @@ class FourLineDisplayUsermod : public Usermod {
* the useAMPM configuration. * the useAMPM configuration.
*/ */
void showTime() { void showTime() {
if(knownMinute != minute(localTime)){ //only redraw clock if it has changed if (type == NONE || !enabled) return;
if (knownMinute != minute(localTime)) { //only redraw clock if it has changed
char lineBuffer[LINE_BUFFER_SIZE]; char lineBuffer[LINE_BUFFER_SIZE];
//updateLocalTime(); //updateLocalTime();
@ -873,13 +861,15 @@ class FourLineDisplayUsermod : public Usermod {
*/ */
void addToConfig(JsonObject& root) { void addToConfig(JsonObject& root) {
JsonObject top = root.createNestedObject(FPSTR(_name)); JsonObject top = root.createNestedObject(FPSTR(_name));
top[FPSTR(_enabled)] = enabled;
JsonArray io_pin = top.createNestedArray("pin"); JsonArray io_pin = top.createNestedArray("pin");
for (byte i=0; i<5; i++) io_pin.add(ioPin[i]); for (byte i=0; i<5; i++) io_pin.add(ioPin[i]);
top["help4PinTypes"] = F("Clk,Data,CS,DC,RST"); // help for Settings page top["help4Pins"] = F("Clk,Data,CS,DC,RST"); // help for Settings page
top["type"] = type; top["type"] = type;
top["help4Type"] = F("1=SSD1306,2=SH1106,3=SSD1306_128x64,4=SSD1305,5=SSD1305_128x64,6=SSD1306_SPI,7=SSD1306_SPI_128x64"); // help for Settings page
top[FPSTR(_flip)] = (bool) flip; top[FPSTR(_flip)] = (bool) flip;
top[FPSTR(_contrast)] = contrast; top[FPSTR(_contrast)] = contrast;
top[FPSTR(_refreshRate)] = refreshRate/10; top[FPSTR(_refreshRate)] = refreshRate/1000;
top[FPSTR(_screenTimeOut)] = screenTimeout/1000; top[FPSTR(_screenTimeOut)] = screenTimeout/1000;
top[FPSTR(_sleepMode)] = (bool) sleepMode; top[FPSTR(_sleepMode)] = (bool) sleepMode;
top[FPSTR(_clockMode)] = (bool) clockMode; top[FPSTR(_clockMode)] = (bool) clockMode;
@ -907,15 +897,19 @@ class FourLineDisplayUsermod : public Usermod {
return false; return false;
} }
enabled = top[FPSTR(_enabled)] | enabled;
newType = top["type"] | newType; newType = top["type"] | newType;
for (byte i=0; i<5; i++) newPin[i] = top["pin"][i] | ioPin[i]; for (byte i=0; i<5; i++) newPin[i] = top["pin"][i] | ioPin[i];
flip = top[FPSTR(_flip)] | flip; flip = top[FPSTR(_flip)] | flip;
contrast = top[FPSTR(_contrast)] | contrast; contrast = top[FPSTR(_contrast)] | contrast;
refreshRate = (top[FPSTR(_refreshRate)] | refreshRate/10) * 10; refreshRate = (top[FPSTR(_refreshRate)] | refreshRate/1000) * 1000;
screenTimeout = (top[FPSTR(_screenTimeOut)] | screenTimeout/1000) * 1000; screenTimeout = (top[FPSTR(_screenTimeOut)] | screenTimeout/1000) * 1000;
sleepMode = top[FPSTR(_sleepMode)] | sleepMode; sleepMode = top[FPSTR(_sleepMode)] | sleepMode;
clockMode = top[FPSTR(_clockMode)] | clockMode; clockMode = top[FPSTR(_clockMode)] | clockMode;
ioFrequency = min(3400, max(100, (int)(top[FPSTR(_busClkFrequency)] | ioFrequency/1000))) * 1000; // limit frequency if (newType == SSD1306_SPI || newType == SSD1306_SPI64)
ioFrequency = min(20000, max(500, (int)(top[FPSTR(_busClkFrequency)] | ioFrequency/1000))) * 1000; // limit frequency
else
ioFrequency = min(3400, max(100, (int)(top[FPSTR(_busClkFrequency)] | ioFrequency/1000))) * 1000; // limit frequency
DEBUG_PRINT(FPSTR(_name)); DEBUG_PRINT(FPSTR(_name));
if (!initDone) { if (!initDone) {
@ -930,10 +924,10 @@ class FourLineDisplayUsermod : public Usermod {
for (byte i=0; i<5; i++) if (ioPin[i] != newPin[i]) { pinsChanged = true; break; } for (byte i=0; i<5; i++) if (ioPin[i] != newPin[i]) { pinsChanged = true; break; }
if (pinsChanged || type!=newType) { if (pinsChanged || type!=newType) {
if (type != NONE) delete u8x8; if (type != NONE) delete u8x8;
for (byte i=0; i<5; i++) { PinOwner po = PinOwner::UM_FourLineDisplay;
if (ioPin[i]>=0) pinManager.deallocatePin(ioPin[i], PinOwner::UM_FourLineDisplay); if (ioPin[0]==HW_PIN_SCL && ioPin[1]==HW_PIN_SDA) po = PinOwner::HW_I2C; // allow multiple allocations of HW I2C bus pins
ioPin[i] = newPin[i]; pinManager.deallocateMultiplePins((const uint8_t *)ioPin, (type == SSD1306_SPI || type == SSD1306_SPI64) ? 5 : 2, po);
} for (byte i=0; i<5; i++) ioPin[i] = newPin[i];
if (ioPin[0]<0 || ioPin[1]<0) { // data & clock must be > -1 if (ioPin[0]<0 || ioPin[1]<0) { // data & clock must be > -1
type = NONE; type = NONE;
return true; return true;
@ -947,7 +941,7 @@ class FourLineDisplayUsermod : public Usermod {
if (needsRedraw && !wakeDisplay()) redraw(true); if (needsRedraw && !wakeDisplay()) redraw(true);
} }
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features // use "return !top["newestParameter"].isNull();" when updating Usermod with new features
return !(top[_busClkFrequency]).isNull(); return !top[FPSTR(_enabled)].isNull();
} }
/* /*
@ -960,11 +954,12 @@ class FourLineDisplayUsermod : public Usermod {
}; };
// strings to reduce flash memory usage (used more than twice) // strings to reduce flash memory usage (used more than twice)
const char FourLineDisplayUsermod::_name[] PROGMEM = "4LineDisplay"; const char FourLineDisplayUsermod::_name[] PROGMEM = "4LineDisplay";
const char FourLineDisplayUsermod::_contrast[] PROGMEM = "contrast"; const char FourLineDisplayUsermod::_enabled[] PROGMEM = "enabled";
const char FourLineDisplayUsermod::_refreshRate[] PROGMEM = "refreshRate0.01Sec"; const char FourLineDisplayUsermod::_contrast[] PROGMEM = "contrast";
const char FourLineDisplayUsermod::_screenTimeOut[] PROGMEM = "screenTimeOutSec"; const char FourLineDisplayUsermod::_refreshRate[] PROGMEM = "refreshRateSec";
const char FourLineDisplayUsermod::_flip[] PROGMEM = "flip"; const char FourLineDisplayUsermod::_screenTimeOut[] PROGMEM = "screenTimeOutSec";
const char FourLineDisplayUsermod::_sleepMode[] PROGMEM = "sleepMode"; const char FourLineDisplayUsermod::_flip[] PROGMEM = "flip";
const char FourLineDisplayUsermod::_clockMode[] PROGMEM = "clockMode"; const char FourLineDisplayUsermod::_sleepMode[] PROGMEM = "sleepMode";
const char FourLineDisplayUsermod::_clockMode[] PROGMEM = "clockMode";
const char FourLineDisplayUsermod::_busClkFrequency[] PROGMEM = "i2c-freq-kHz"; const char FourLineDisplayUsermod::_busClkFrequency[] PROGMEM = "i2c-freq-kHz";