From b8bf2a707c48c3d8fd8d065696e79fa5d722bbff Mon Sep 17 00:00:00 2001 From: Blaz Kristan Date: Thu, 1 Feb 2024 18:53:55 +0100 Subject: [PATCH] Remove obsolete usermods - mode sort - 4LD (non ALT) - Rotary encoder (non ALT) --- .../usermod_v2_four_line_display/readme.md | 63 -- .../usermod_v2_four_line_display.h | 742 ------------------ usermods/usermod_v2_mode_sort/readme.md | 33 - .../usermod_v2_mode_sort.h | 244 ------ .../platformio_override.ini.sample | 48 -- .../usermod_v2_rotary_encoder_ui/readme.md | 39 - .../usermod_v2_rotary_encoder_ui.h | 496 ------------ wled00/usermods_list.cpp | 20 +- 8 files changed, 2 insertions(+), 1683 deletions(-) delete mode 100644 usermods/usermod_v2_four_line_display/readme.md delete mode 100644 usermods/usermod_v2_four_line_display/usermod_v2_four_line_display.h delete mode 100644 usermods/usermod_v2_mode_sort/readme.md delete mode 100644 usermods/usermod_v2_mode_sort/usermod_v2_mode_sort.h delete mode 100644 usermods/usermod_v2_rotary_encoder_ui/platformio_override.ini.sample delete mode 100644 usermods/usermod_v2_rotary_encoder_ui/readme.md delete mode 100644 usermods/usermod_v2_rotary_encoder_ui/usermod_v2_rotary_encoder_ui.h diff --git a/usermods/usermod_v2_four_line_display/readme.md b/usermods/usermod_v2_four_line_display/readme.md deleted file mode 100644 index 26250cb5c5..0000000000 --- a/usermods/usermod_v2_four_line_display/readme.md +++ /dev/null @@ -1,63 +0,0 @@ -# I2C 4 Line Display Usermod - -First, thanks to the authors of the ssd11306_i2c_oled_u8g2 mod. - -Provides a four line display using either -128x32 or 128x64 OLED displays. -It can operate independently, but starts to provide -a relatively complete on-device UI when paired with the -Rotary Encoder UI usermod. I strongly encourage you to use -them together. - -[See the pair of usermods in action](https://www.youtube.com/watch?v=tITQY80rIOA) - -## Installation - -Copy and update the example `platformio_override.ini.sample` -from the Rotary Encoder UI usermode folder to the root directory of your particular build. -This file should be placed in the same directory as `platformio.ini`. - -### Define Your Options - -* `USERMOD_FOUR_LINE_DISPLAY` - define this to have this mod included wled00\usermods_list.cpp - also tells Rotary Encoder usermod, if installed, the display is available -* `FLD_PIN_SCL` - The display SCL pin, defaults to 5 -* `FLD_PIN_SDA` - The display SDA pin, defaults to 4 - -All of the parameters can be configured via the Usermods settings page, inluding GPIO pins. - -### PlatformIO requirements - -This usermod requires the `U8g2` and `Wire` libraries. See the -`platformio_override.ini.sample` found in the Rotary Encoder -UI usermod folder for how to include these using `platformio_override.ini`. - -## Configuration - -* `enabled` - enable/disable usermod -* `pin` - GPIO pins used for display; I2C displays use Clk & Data; SPI displays can use SCK, MOSI, CS, DC & RST -* `type` - display type in numeric format - * 1 = I2C SSD1306 128x32 - * 2 = I2C SH1106 128x32 - * 3 = I2C SSD1306 128x64 (4 double-height lines) - * 4 = I2C SSD1305 128x32 - * 5 = I2C SSD1305 128x64 (4 double-height lines) - * 6 = SPI SSD1306 128x32 - * 7 = SPI SSD1306 128x64 (4 double-height lines) -* `contrast` - set display contrast (higher contrast may reduce display lifetime) -* `refreshRateSec` - display refresh time in seconds -* `screenTimeOutSec` - screen saver time-out in seconds -* `flip` - flip/rotate display 180° -* `sleepMode` - enable/disable screen saver -* `clockMode` - enable/disable clock display in screen saver mode -* `i2c-freq-kHz` - I2C clock frequency in kHz (may help reduce dropped frames, range: 400-3400) - -## Change Log - -2021-02 -* First public release - -2021-04 -* Adaptation for runtime configuration. - -2021-11 -* Added configuration option description. diff --git a/usermods/usermod_v2_four_line_display/usermod_v2_four_line_display.h b/usermods/usermod_v2_four_line_display/usermod_v2_four_line_display.h deleted file mode 100644 index 3fcf661289..0000000000 --- a/usermods/usermod_v2_four_line_display/usermod_v2_four_line_display.h +++ /dev/null @@ -1,742 +0,0 @@ -#pragma once - -#include "wled.h" -#include // from https://github.com/olikraus/u8g2/ - -// -// Insired by the v1 usermod: ssd1306_i2c_oled_u8g2 -// -// v2 usermod for using 128x32 or 128x64 i2c -// OLED displays to provide a four line display -// for WLED. -// -// Dependencies -// * This usermod REQURES the ModeSortUsermod -// * This Usermod works best, by far, when coupled -// with RotaryEncoderUIUsermod. -// -// Make sure to enable NTP and set your time zone in WLED Config | Time. -// -// REQUIREMENT: You must add the following requirements to -// REQUIREMENT: "lib_deps" within platformio.ini / platformio_override.ini -// REQUIREMENT: * U8g2 (the version already in platformio.ini is fine) -// REQUIREMENT: * Wire -// - -//The SCL and SDA pins are defined here. -#ifndef FLD_PIN_SCL - #define FLD_PIN_SCL i2c_scl -#endif -#ifndef FLD_PIN_SDA - #define FLD_PIN_SDA i2c_sda -#endif -#ifndef FLD_PIN_CLOCKSPI - #define FLD_PIN_CLOCKSPI spi_sclk -#endif - #ifndef FLD_PIN_DATASPI - #define FLD_PIN_DATASPI spi_mosi -#endif -#ifndef FLD_PIN_CS - #define FLD_PIN_CS spi_cs -#endif -#ifdef ARDUINO_ARCH_ESP32 - #ifndef FLD_PIN_DC - #define FLD_PIN_DC 19 - #endif - #ifndef FLD_PIN_RESET - #define FLD_PIN_RESET 26 - #endif -#else - #ifndef FLD_PIN_DC - #define FLD_PIN_DC 12 - #endif - #ifndef FLD_PIN_RESET - #define FLD_PIN_RESET 16 - #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 -// if SLEEP_MODE_ENABLED. -#define SCREEN_TIMEOUT_MS 60*1000 // 1 min - -#define TIME_INDENT 0 -#define DATE_INDENT 2 - -// Minimum time between redrawing screen in ms -#define USER_LOOP_REFRESH_RATE_MS 1000 - -// Extra char (+1) for null -#define LINE_BUFFER_SIZE 16+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 { - NONE = 0, - SSD1306, // U8X8_SSD1306_128X32_UNIVISION_HW_I2C - SH1106, // U8X8_SH1106_128X64_WINSTAR_HW_I2C - SSD1306_64, // U8X8_SSD1306_128X64_NONAME_HW_I2C - SSD1305, // U8X8_SSD1305_128X32_ADAFRUIT_HW_I2C - SSD1305_64, // U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C - SSD1306_SPI, // U8X8_SSD1306_128X32_NONAME_HW_SPI - SSD1306_SPI64 // U8X8_SSD1306_128X64_NONAME_HW_SPI -} DisplayType; - -class FourLineDisplayUsermod : public Usermod { - - private: - - bool initDone = false; - unsigned long lastTime = 0; - - // HW interface & configuration - U8X8 *u8x8 = nullptr; // pointer to U8X8 display object - #ifndef FLD_SPI_DEFAULT - 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) - #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 - uint32_t ioFrequency = 1000000; // in Hz (minimum is 500kHz, baseline is 1MHz and maximum should be 20MHz) - #endif - DisplayType type = FLD_TYPE; // display type - bool flip = false; // flip display 180° - uint8_t contrast = 10; // screen contrast - uint8_t lineHeight = 1; // 1 row or 2 rows - uint32_t refreshRate = USER_LOOP_REFRESH_RATE_MS; // in ms - uint32_t screenTimeout = SCREEN_TIMEOUT_MS; // in ms - bool sleepMode = true; // allow screen sleep? - bool clockMode = false; // display clock - bool enabled = true; - - // Next variables hold the previous known values to determine if redraw is - // required. - String knownSsid = ""; - IPAddress knownIp; - uint8_t knownBrightness = 0; - uint8_t knownEffectSpeed = 0; - uint8_t knownEffectIntensity = 0; - uint8_t knownMode = 0; - uint8_t knownPalette = 0; - uint8_t knownMinute = 99; - uint8_t knownHour = 99; - - bool displayTurnedOff = false; - unsigned long lastUpdate = 0; - unsigned long lastRedraw = 0; - unsigned long overlayUntil = 0; - Line4Type lineType = FLD_LINE_BRIGHTNESS; - // Set to 2 or 3 to mark lines 2 or 3. Other values ignored. - byte markLineNum = 0; - - // strings to reduce flash memory usage (used more than twice) - static const char _name[]; - static const char _enabled[]; - static const char _contrast[]; - static const char _refreshRate[]; - static const char _screenTimeOut[]; - static const char _flip[]; - static const char _sleepMode[]; - static const char _clockMode[]; - static const char _busClkFrequency[]; - - // If display does not work or looks corrupted check the - // constructor reference: - // https://github.com/olikraus/u8g2/wiki/u8x8setupcpp - // or check the gallery: - // https://github.com/olikraus/u8g2/wiki/gallery - - public: - - // gets called once at boot. Do all initialization that doesn't depend on - // network here - void setup() { - if (type == NONE || !enabled) return; - - bool isHW; - PinOwner po = PinOwner::UM_FourLineDisplay; - if (type == SSD1306_SPI || type == SSD1306_SPI64) { - isHW = (ioPin[0]==spi_sclk && ioPin[1]==spi_mosi); - if (isHW) po = PinOwner::HW_SPI; // allow multiple allocations of HW I2C bus pins - 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 { - isHW = (ioPin[0]==i2c_scl && ioPin[1]==i2c_sda); - if (isHW) po = PinOwner::HW_I2C; // allow multiple allocations of HW I2C bus pins - PinManagerPinType pins[2] = { { ioPin[0], true }, { ioPin[1], true } }; - if (!pinManager.allocateMultiplePins(pins, 2, po)) { type=NONE; return; } - } - - DEBUG_PRINTLN(F("Allocating display.")); - switch (type) { - case SSD1306: - if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset - else u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA - lineHeight = 1; - break; - case SH1106: - if (!isHW) u8x8 = (U8X8 *) new U8X8_SH1106_128X64_WINSTAR_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset - else u8x8 = (U8X8 *) new U8X8_SH1106_128X64_WINSTAR_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA - lineHeight = 2; - break; - case SSD1306_64: - if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset - else u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA - lineHeight = 2; - break; - case SSD1305: - if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1305_128X32_NONAME_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset - else u8x8 = (U8X8 *) new U8X8_SSD1305_128X32_ADAFRUIT_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA - lineHeight = 1; - break; - case SSD1305_64: - if (!isHW) u8x8 = (U8X8 *) new U8X8_SSD1305_128X64_ADAFRUIT_SW_I2C(ioPin[0], ioPin[1]); // SCL, SDA, reset - else u8x8 = (U8X8 *) new U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C(U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA - lineHeight = 2; - break; - case SSD1306_SPI: - if (!isHW) 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 - lineHeight = 1; - break; - case SSD1306_SPI64: - if (!isHW) 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 - lineHeight = 2; - break; - default: - u8x8 = nullptr; - } - - if (nullptr == u8x8) { - DEBUG_PRINTLN(F("Display init failed.")); - pinManager.deallocateMultiplePins((const uint8_t*)ioPin, (type == SSD1306_SPI || type == SSD1306_SPI64) ? 5 : 2, po); - type = NONE; - return; - } - - initDone = true; - DEBUG_PRINTLN(F("Starting display.")); - /*if (!(type == SSD1306_SPI || type == SSD1306_SPI64))*/ u8x8->setBusClock(ioFrequency); // can be used for SPI too - u8x8->begin(); - setFlipMode(flip); - setContrast(contrast); //Contrast setup will help to preserve OLED lifetime. In case OLED need to be brighter increase number up to 255 - setPowerSave(0); - drawString(0, 0, "Loading..."); - } - - // gets called every time WiFi is (re-)connected. Initialize own network - // interfaces here - void connected() {} - - /** - * Da loop. - */ - void loop() { - if (!enabled || millis() - lastUpdate < (clockMode?1000:refreshRate) || strip.isUpdating()) return; - lastUpdate = millis(); - - redraw(false); - } - - /** - * Wrappers for screen drawing - */ - void setFlipMode(uint8_t mode) { - if (type == NONE || !enabled) return; - u8x8->setFlipMode(mode); - } - void setContrast(uint8_t contrast) { - if (type == NONE || !enabled) return; - u8x8->setContrast(contrast); - } - void drawString(uint8_t col, uint8_t row, const char *string, bool ignoreLH=false) { - if (type == NONE || !enabled) return; - u8x8->setFont(u8x8_font_chroma48medium8_r); - if (!ignoreLH && lineHeight==2) u8x8->draw1x2String(col, row, string); - else u8x8->drawString(col, row, string); - } - void draw2x2String(uint8_t col, uint8_t row, const char *string) { - if (type == NONE || !enabled) return; - u8x8->setFont(u8x8_font_chroma48medium8_r); - u8x8->draw2x2String(col, row, string); - } - void drawGlyph(uint8_t col, uint8_t row, char glyph, const uint8_t *font, bool ignoreLH=false) { - if (type == NONE || !enabled) return; - u8x8->setFont(font); - if (!ignoreLH && lineHeight==2) u8x8->draw1x2Glyph(col, row, glyph); - else u8x8->drawGlyph(col, row, glyph); - } - uint8_t getCols() { - if (type==NONE || !enabled) return 0; - return u8x8->getCols(); - } - void clear() { - if (type == NONE || !enabled) return; - u8x8->clear(); - } - void setPowerSave(uint8_t save) { - if (type == NONE || !enabled) return; - u8x8->setPowerSave(save); - } - - void center(String &line, uint8_t width) { - int len = line.length(); - if (len0; i--) line = ' ' + line; - for (byte i=line.length(); i 0) { - if (now >= overlayUntil) { - // Time to display the overlay has elapsed. - overlayUntil = 0; - forceRedraw = true; - } else { - // We are still displaying the overlay - // Don't redraw. - return; - } - } - - // Check if values which are shown on display changed from the last time. - if (forceRedraw || - (((apActive) ? String(apSSID) : WiFi.SSID()) != knownSsid) || - (knownIp != (apActive ? IPAddress(4, 3, 2, 1) : Network.localIP())) || - (knownBrightness != bri) || - (knownEffectSpeed != effectSpeed) || - (knownEffectIntensity != effectIntensity) || - (knownMode != strip.getMainSegment().mode) || - (knownPalette != strip.getMainSegment().palette)) { - knownHour = 99; // force time update - lastRedraw = now; // update lastRedraw marker - } else if (sleepMode && !displayTurnedOff && ((now - lastRedraw)/1000)%5 == 0) { - // change line every 5s - showName = !showName; - switch (lineType) { - case FLD_LINE_BRIGHTNESS: - lineType = FLD_LINE_EFFECT_SPEED; - break; - case FLD_LINE_MODE: - lineType = FLD_LINE_BRIGHTNESS; - break; - case FLD_LINE_PALETTE: - lineType = clockMode ? FLD_LINE_MODE : FLD_LINE_BRIGHTNESS; - break; - case FLD_LINE_EFFECT_SPEED: - lineType = FLD_LINE_EFFECT_INTENSITY; - break; - case FLD_LINE_EFFECT_INTENSITY: - lineType = FLD_LINE_PALETTE; - break; - default: - lineType = FLD_LINE_MODE; - break; - } - knownHour = 99; // force time update - // do not update lastRedraw marker if just switching row contenet - } else { - // Nothing to change. - // Turn off display after 3 minutes with no change. - if(sleepMode && !displayTurnedOff && (millis() - lastRedraw > screenTimeout)) { - // We will still check if there is a change in redraw() - // and turn it back on if it changed. - sleepOrClock(true); - } else if (displayTurnedOff && clockMode) { - showTime(); - } - return; - } - - // Turn the display back on - if (displayTurnedOff) sleepOrClock(false); - - // Update last known values. - knownSsid = apActive ? WiFi.softAPSSID() : WiFi.SSID(); - knownIp = apActive ? IPAddress(4, 3, 2, 1) : Network.localIP(); - knownBrightness = bri; - knownMode = strip.getMainSegment().mode; - knownPalette = strip.getMainSegment().palette; - knownEffectSpeed = effectSpeed; - knownEffectIntensity = effectIntensity; - - // Do the actual drawing - String line; - // First row with Wifi name - drawGlyph(0, 0, 80, u8x8_font_open_iconic_embedded_1x1); // home icon - line = knownSsid.substring(0, getCols() > 1 ? getCols() - 2 : 0); - center(line, getCols()-2); - drawString(1, 0, line.c_str()); - // Print `~` char to indicate that SSID is longer, than our display - if (knownSsid.length() > (int)getCols()-1) { - drawString(getCols() - 1, 0, "~"); - } - - // Second row with IP or Psssword - drawGlyph(0, lineHeight, 68, u8x8_font_open_iconic_embedded_1x1); // wifi icon - // Print password in AP mode and if led is OFF. - if (apActive && bri == 0) { - drawString(1, lineHeight, apPass); - } else { - // alternate IP address and server name - line = knownIp.toString(); - if (showName && strcmp(serverDescription, "WLED") != 0) { - line = serverDescription; - } - center(line, getCols()-1); - drawString(1, lineHeight, line.c_str()); - } - - // draw third and fourth row - drawLine(2, clockMode ? lineType : FLD_LINE_MODE); - drawLine(3, clockMode ? FLD_LINE_TIME : lineType); - - drawGlyph(0, 2*lineHeight, 66 + (bri > 0 ? 3 : 0), u8x8_font_open_iconic_weather_2x2); // sun/moon icon - //if (markLineNum>1) drawGlyph(2, markLineNum*lineHeight, 66, u8x8_font_open_iconic_arrow_1x1); // arrow icon - } - - void drawLine(uint8_t line, Line4Type lineType) { - char lineBuffer[LINE_BUFFER_SIZE]; - uint8_t printedChars; - switch(lineType) { - case FLD_LINE_BRIGHTNESS: - sprintf_P(lineBuffer, PSTR("Brightness %3d"), bri); - drawString(2, line*lineHeight, lineBuffer); - break; - case FLD_LINE_EFFECT_SPEED: - sprintf_P(lineBuffer, PSTR("FX Speed %3d"), effectSpeed); - drawString(2, line*lineHeight, lineBuffer); - break; - case FLD_LINE_EFFECT_INTENSITY: - sprintf_P(lineBuffer, PSTR("FX Intens. %3d"), effectIntensity); - drawString(2, line*lineHeight, lineBuffer); - break; - case FLD_LINE_MODE: - printedChars = extractModeName(knownMode, JSON_mode_names, lineBuffer, LINE_BUFFER_SIZE-1); - for (;printedChars < getCols()-2 && printedChars < LINE_BUFFER_SIZE-3; printedChars++) lineBuffer[printedChars]=' '; - lineBuffer[printedChars] = 0; - drawString(2, line*lineHeight, lineBuffer); - break; - case FLD_LINE_PALETTE: - printedChars = extractModeName(knownPalette, JSON_palette_names, lineBuffer, LINE_BUFFER_SIZE-1); - for (;printedChars < getCols()-2 && printedChars < LINE_BUFFER_SIZE-3; printedChars++) lineBuffer[printedChars]=' '; - lineBuffer[printedChars] = 0; - drawString(2, line*lineHeight, lineBuffer); - break; - case FLD_LINE_TIME: - default: - showTime(false); - break; - } - } - - /** - * If there screen is off or in clock is displayed, - * this will return true. This allows us to throw away - * the first input from the rotary encoder but - * to wake up the screen. - */ - bool wakeDisplay() { - if (type == NONE || !enabled) return false; - knownHour = 99; - if (displayTurnedOff) { - // Turn the display back on - sleepOrClock(false); - redraw(true); - return true; - } - return false; - } - - /** - * Allows you to show up to two lines as overlay for a - * period of time. - * Clears the screen and prints on the middle two lines. - */ - void overlay(const char* line1, const char *line2, long showHowLong) { - if (type == NONE || !enabled) return; - - if (displayTurnedOff) { - // Turn the display back on (includes clear()) - sleepOrClock(false); - } else { - clear(); - } - - // Print the overlay - if (line1) { - String buf = line1; - center(buf, getCols()); - drawString(0, 1*lineHeight, buf.c_str()); - } - if (line2) { - String buf = line2; - center(buf, getCols()); - drawString(0, 2*lineHeight, buf.c_str()); - } - overlayUntil = millis() + showHowLong; - } - - void setLineType(byte lT) { - lineType = (Line4Type) lT; - } - - /** - * Line 3 or 4 (last two lines) can be marked with an - * arrow in the first column. Pass 2 or 3 to this to - * specify which line to mark with an arrow. - * Any other values are ignored. - */ - void setMarkLine(byte newMarkLineNum) { - if (newMarkLineNum == 2 || newMarkLineNum == 3) { - markLineNum = newMarkLineNum; - } - else { - markLineNum = 0; - } - } - - /** - * Enable sleep (turn the display off) or clock mode. - */ - void sleepOrClock(bool enabled) { - clear(); - if (enabled) { - if (clockMode) showTime(); - else setPowerSave(1); - displayTurnedOff = true; - } else { - setPowerSave(0); - displayTurnedOff = false; - } - } - - /** - * Display the current date and time in large characters - * on the middle rows. Based 24 or 12 hour depending on - * the useAMPM configuration. - */ - void showTime(bool fullScreen = true) { - if (type == NONE || !enabled) return; - char lineBuffer[LINE_BUFFER_SIZE]; - - updateLocalTime(); - byte minuteCurrent = minute(localTime); - byte hourCurrent = hour(localTime); - byte secondCurrent = second(localTime); - if (knownMinute == minuteCurrent && knownHour == hourCurrent) { - // Time hasn't changed. - if (!fullScreen) return; - } - knownMinute = minuteCurrent; - knownHour = hourCurrent; - - byte currentMonth = month(localTime); - sprintf_P(lineBuffer, PSTR("%s %2d "), monthShortStr(currentMonth), day(localTime)); - if (fullScreen) - draw2x2String(DATE_INDENT, lineHeight==1 ? 0 : lineHeight, lineBuffer); // adjust for 8 line displays - else - drawString(2, lineHeight*3, lineBuffer); - - byte showHour = hourCurrent; - boolean isAM = false; - if (useAMPM) { - if (showHour == 0) { - showHour = 12; - isAM = true; - } - else if (showHour > 12) { - showHour -= 12; - isAM = false; - } - else { - isAM = true; - } - } - - sprintf_P(lineBuffer, (secondCurrent%2 || !fullScreen) ? PSTR("%2d:%02d") : PSTR("%2d %02d"), (useAMPM ? showHour : hourCurrent), minuteCurrent); - // For time, we always use LINE_HEIGHT of 2 since - // we are printing it big. - if (fullScreen) { - draw2x2String(TIME_INDENT+2, lineHeight*2, lineBuffer); - sprintf_P(lineBuffer, PSTR("%02d"), secondCurrent); - if (useAMPM) drawString(12+(fullScreen?0:2), lineHeight*2, (isAM ? "AM" : "PM"), true); - else drawString(12, lineHeight*2+1, lineBuffer, true); // even with double sized rows print seconds in 1 line - } else { - drawString(9+(useAMPM?0:2), lineHeight*3, lineBuffer); - if (useAMPM) drawString(12+(fullScreen?0:2), lineHeight*3, (isAM ? "AM" : "PM"), true); - } - } - - /* - * addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API. - * Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI. - * Below it is shown how this could be used for e.g. a light sensor - */ - //void addToJsonInfo(JsonObject& root) { - //JsonObject user = root["u"]; - //if (user.isNull()) user = root.createNestedObject("u"); - //JsonArray data = user.createNestedArray(F("4LineDisplay")); - //data.add(F("Loaded.")); - //} - - /* - * addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object). - * Values in the state object may be modified by connected clients - */ - //void addToJsonState(JsonObject& root) { - //} - - /* - * readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object). - * Values in the state object may be modified by connected clients - */ - //void readFromJsonState(JsonObject& root) { - // if (!initDone) return; // prevent crash on boot applyPreset() - //} - - /* - * addToConfig() can be used to add custom persistent settings to the cfg.json file in the "um" (usermod) object. - * It will be called by WLED when settings are actually saved (for example, LED settings are saved) - * If you want to force saving the current state, use serializeConfig() in your loop(). - * - * CAUTION: serializeConfig() will initiate a filesystem write operation. - * It might cause the LEDs to stutter and will cause flash wear if called too often. - * Use it sparingly and always in the loop, never in network callbacks! - * - * addToConfig() will also not yet add your setting to one of the settings pages automatically. - * To make that work you still have to add the setting to the HTML, xml.cpp and set.cpp manually. - * - * I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings! - */ - void addToConfig(JsonObject& root) { - JsonObject top = root.createNestedObject(FPSTR(_name)); - top[FPSTR(_enabled)] = enabled; - JsonArray io_pin = top.createNestedArray("pin"); - for (byte i=0; i<5; i++) io_pin.add(ioPin[i]); - top["help4Pins"] = F("Clk,Data,CS,DC,RST"); // help for Settings page - 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(_contrast)] = contrast; - top[FPSTR(_refreshRate)] = refreshRate/1000; - top[FPSTR(_screenTimeOut)] = screenTimeout/1000; - top[FPSTR(_sleepMode)] = (bool) sleepMode; - top[FPSTR(_clockMode)] = (bool) clockMode; - top[FPSTR(_busClkFrequency)] = ioFrequency/1000; - DEBUG_PRINTLN(F("4 Line Display config saved.")); - } - - /* - * readFromConfig() can be used to read back the custom settings you added with addToConfig(). - * This is called by WLED when settings are loaded (currently this only happens once immediately after boot) - * - * readFromConfig() is called BEFORE setup(). This means you can use your persistent values in setup() (e.g. pin assignments, buffer sizes), - * but also that if you want to write persistent values to a dynamic buffer, you'd need to allocate it here instead of in setup. - * If you don't know what that is, don't fret. It most likely doesn't affect your use case :) - */ - bool readFromConfig(JsonObject& root) { - bool needsRedraw = false; - DisplayType newType = type; - int8_t newPin[5]; for (byte i=0; i<5; i++) newPin[i] = ioPin[i]; - - JsonObject top = root[FPSTR(_name)]; - if (top.isNull()) { - DEBUG_PRINT(FPSTR(_name)); - DEBUG_PRINTLN(F(": No config found. (Using defaults.)")); - return false; - } - - enabled = top[FPSTR(_enabled)] | enabled; - newType = top["type"] | newType; - for (byte i=0; i<5; i++) newPin[i] = top["pin"][i] | ioPin[i]; - flip = top[FPSTR(_flip)] | flip; - contrast = top[FPSTR(_contrast)] | contrast; - refreshRate = (top[FPSTR(_refreshRate)] | refreshRate/1000) * 1000; - screenTimeout = (top[FPSTR(_screenTimeOut)] | screenTimeout/1000) * 1000; - sleepMode = top[FPSTR(_sleepMode)] | sleepMode; - clockMode = top[FPSTR(_clockMode)] | clockMode; - 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)); - if (!initDone) { - // first run: reading from cfg.json - for (byte i=0; i<5; i++) ioPin[i] = newPin[i]; - type = newType; - DEBUG_PRINTLN(F(" config loaded.")); - } else { - DEBUG_PRINTLN(F(" config (re)loaded.")); - // changing parameters from settings page - bool pinsChanged = false; - for (byte i=0; i<5; i++) if (ioPin[i] != newPin[i]) { pinsChanged = true; break; } - if (pinsChanged || type!=newType) { - if (type != NONE) delete u8x8; - PinOwner po = PinOwner::UM_FourLineDisplay; - bool isSPI = (type == SSD1306_SPI || type == SSD1306_SPI64); - if (isSPI) { - if (ioPin[0]==spi_sclk && ioPin[1]==spi_mosi) po = PinOwner::HW_SPI; // allow multiple allocations of HW SPI bus pins - pinManager.deallocateMultiplePins((const uint8_t *)ioPin, 5, po); - } else { - if (ioPin[0]==i2c_scl && ioPin[1]==i2c_sda) po = PinOwner::HW_I2C; // allow multiple allocations of HW I2C bus pins - pinManager.deallocateMultiplePins((const uint8_t *)ioPin, 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 - type = NONE; - return true; - } else type = newType; - setup(); - needsRedraw |= true; - } - if (!(type == SSD1306_SPI || type == SSD1306_SPI64)) u8x8->setBusClock(ioFrequency); // can be used for SPI too - setContrast(contrast); - setFlipMode(flip); - if (needsRedraw && !wakeDisplay()) redraw(true); - } - // use "return !top["newestParameter"].isNull();" when updating Usermod with new features - return !top[FPSTR(_enabled)].isNull(); - } - - /* - * getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!). - * This could be used in the future for the system to determine whether your usermod is installed. - */ - uint16_t getId() { - return USERMOD_ID_FOUR_LINE_DISP; - } -}; - -// strings to reduce flash memory usage (used more than twice) -const char FourLineDisplayUsermod::_name[] PROGMEM = "4LineDisplay"; -const char FourLineDisplayUsermod::_enabled[] PROGMEM = "enabled"; -const char FourLineDisplayUsermod::_contrast[] PROGMEM = "contrast"; -const char FourLineDisplayUsermod::_refreshRate[] PROGMEM = "refreshRateSec"; -const char FourLineDisplayUsermod::_screenTimeOut[] PROGMEM = "screenTimeOutSec"; -const char FourLineDisplayUsermod::_flip[] PROGMEM = "flip"; -const char FourLineDisplayUsermod::_sleepMode[] PROGMEM = "sleepMode"; -const char FourLineDisplayUsermod::_clockMode[] PROGMEM = "clockMode"; -const char FourLineDisplayUsermod::_busClkFrequency[] PROGMEM = "i2c-freq-kHz"; diff --git a/usermods/usermod_v2_mode_sort/readme.md b/usermods/usermod_v2_mode_sort/readme.md deleted file mode 100644 index c24322f32e..0000000000 --- a/usermods/usermod_v2_mode_sort/readme.md +++ /dev/null @@ -1,33 +0,0 @@ -# Mode Sort - -v2 usermod that provides data about modes and -palettes to other usermods. Notably it provides: -* A direct method for a mode or palette name -* Ability to retrieve mode and palette names in - alphabetical order - -```char **getModesQStrings()``` - -Provides a char* array (pointers) to the names of the -palettes contained in JSON_mode_names, in the same order as -JSON_mode_names. These strings end in double quote (") -(or \0 if there is a problem). - -```byte *getModesAlphaIndexes()``` - -A byte array designating the indexes of names of the -modes in alphabetical order. "Solid" will always remain -at the top of the list. - -```char **getPalettesQStrings()``` - -Provides a char* array (pointers) to the names of the -palettes contained in JSON_palette_names, in the same order as -JSON_palette_names. These strings end in double quote (") -(or \0 if there is a problem). - -```byte *getPalettesAlphaIndexes()``` - -A byte array designating the indexes of names of the -palettes in alphabetical order. "Default" and those -starting with "(" will always remain at the top of the list. diff --git a/usermods/usermod_v2_mode_sort/usermod_v2_mode_sort.h b/usermods/usermod_v2_mode_sort/usermod_v2_mode_sort.h deleted file mode 100644 index 092206bb6d..0000000000 --- a/usermods/usermod_v2_mode_sort/usermod_v2_mode_sort.h +++ /dev/null @@ -1,244 +0,0 @@ -#pragma once - -#include "wled.h" - -// -// v2 usermod that provides data about modes and -// palettes to other usermods. Notably it provides: -// * A direct method for a mode or palette name -// * Ability to retrieve mode and palette names in -// alphabetical order -// -// char **getModesQStrings() -// Provides an array of char* (pointers) to the names of the -// palettes within JSON_mode_names, in the same order as -// JSON_mode_names. These strings end in double quote (") -// (or \0 if there is a problem). -// -// byte *getModesAlphaIndexes() -// An array of byte designating the indexes of names of the -// modes in alphabetical order. "Solid" will always remain -// at the front of the list. -// -// char **getPalettesQStrings() -// Provides an array of char* (pointers) to the names of the -// palettes within JSON_palette_names, in the same order as -// JSON_palette_names. These strings end in double quote (") -// (or \0 if there is a problem). -// -// byte *getPalettesAlphaIndexes() -// An array of byte designating the indexes of names of the -// palettes in alphabetical order. "Default" and those -// starting with "(" will always remain at the front of the list. -// - -// Number of modes at the start of the list to not sort -#define MODE_SORT_SKIP_COUNT 1 - -// Which list is being sorted -char **listBeingSorted = nullptr; - -/** - * Modes and palettes are stored as strings that - * end in a quote character. Compare two of them. - * We are comparing directly within either - * JSON_mode_names or JSON_palette_names. - */ -int re_qstringCmp(const void *ap, const void *bp) { - char *a = listBeingSorted[*((byte *)ap)]; - char *b = listBeingSorted[*((byte *)bp)]; - int i = 0; - do { - char aVal = pgm_read_byte_near(a + i); - if (aVal >= 97 && aVal <= 122) { - // Lowercase - aVal -= 32; - } - char bVal = pgm_read_byte_near(b + i); - if (bVal >= 97 && bVal <= 122) { - // Lowercase - bVal -= 32; - } - // Relly we shouldn't ever get to '\0' - if (aVal == '"' || bVal == '"' || aVal == '\0' || bVal == '\0') { - // We're done. one is a substring of the other - // or something happenend and the quote didn't stop us. - if (aVal == bVal) { - // Same value, probably shouldn't happen - // with this dataset - return 0; - } - else if (aVal == '"' || aVal == '\0') { - return -1; - } - else { - return 1; - } - } - if (aVal == bVal) { - // Same characters. Move to the next. - i++; - continue; - } - // We're done - if (aVal < bVal) { - return -1; - } - else { - return 1; - } - } while (true); - // We shouldn't get here. - return 0; -} - -class ModeSortUsermod : public Usermod { -private: - - // Pointers the start of the mode names within JSON_mode_names - char **modes_qstrings = nullptr; - - // Array of mode indexes in alphabetical order. - byte *modes_alpha_indexes = nullptr; - - // Pointers the start of the palette names within JSON_palette_names - char **palettes_qstrings = nullptr; - - // Array of palette indexes in alphabetical order. - byte *palettes_alpha_indexes = nullptr; - -public: - /** - * setup() is called once at boot. WiFi is not yet connected at this point. - * You can use it to initialize variables, sensors or similar. - */ - void setup() { - // Sort the modes and palettes on startup - // as they are guarantted to change. - sortModesAndPalettes(); - } - - char **getModesQStrings() { - return modes_qstrings; - } - - byte *getModesAlphaIndexes() { - return modes_alpha_indexes; - } - - char **getPalettesQStrings() { - return palettes_qstrings; - } - - byte *getPalettesAlphaIndexes() { - return palettes_alpha_indexes; - } - - /** - * This Usermod doesn't have anything for loop. - */ - void loop() {} - - /** - * Sort the modes and palettes to the index arrays - * modes_alpha_indexes and palettes_alpha_indexes. - */ - void sortModesAndPalettes() { - modes_qstrings = re_findModeStrings(JSON_mode_names, strip.getModeCount()); - modes_alpha_indexes = re_initIndexArray(strip.getModeCount()); - re_sortModes(modes_qstrings, modes_alpha_indexes, strip.getModeCount(), MODE_SORT_SKIP_COUNT); - - palettes_qstrings = re_findModeStrings(JSON_palette_names, strip.getPaletteCount()); - palettes_alpha_indexes = re_initIndexArray(strip.getPaletteCount()); - - int skipPaletteCount = 1; - while (true) { - // How many palette names start with '*' and should not be sorted? - // (Also skipping the first one, 'Default'). - if (pgm_read_byte_near(palettes_qstrings[skipPaletteCount]) == '*') { - skipPaletteCount++; - } - else { - break; - } - } - re_sortModes(palettes_qstrings, palettes_alpha_indexes, strip.getPaletteCount(), skipPaletteCount); - } - - byte *re_initIndexArray(int numModes) { - byte *indexes = (byte *)malloc(sizeof(byte) * numModes); - for (byte i = 0; i < numModes; i++) { - indexes[i] = i; - } - return indexes; - } - - /** - * Return an array of mode or palette names from the JSON string. - * They don't end in '\0', they end in '"'. - */ - char **re_findModeStrings(const char json[], int numModes) { - char **modeStrings = (char **)malloc(sizeof(char *) * numModes); - uint8_t modeIndex = 0; - bool insideQuotes = false; - // advance past the mark for markLineNum that may exist. - char singleJsonSymbol; - - // Find the mode name in JSON - bool complete = false; - for (size_t i = 0; i < strlen_P(json); i++) { - singleJsonSymbol = pgm_read_byte_near(json + i); - if (singleJsonSymbol == '\0') break; - switch (singleJsonSymbol) { - case '"': - insideQuotes = !insideQuotes; - if (insideQuotes) { - // We have a new mode or palette - modeStrings[modeIndex] = (char *)(json + i + 1); - } - break; - case '[': - break; - case ']': - if (!insideQuotes) complete = true; - break; - case ',': - if (!insideQuotes) modeIndex++; - default: - if (!insideQuotes) break; - } - if (complete) break; - } - return modeStrings; - } - - /** - * Sort either the modes or the palettes using quicksort. - */ - void re_sortModes(char **modeNames, byte *indexes, int count, int numSkip) { - listBeingSorted = modeNames; - qsort(indexes + numSkip, count - numSkip, sizeof(byte), re_qstringCmp); - listBeingSorted = nullptr; - } - - /* - * addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object). - * Values in the state object may be modified by connected clients - */ - void addToJsonState(JsonObject &root) {} - - /* - * readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object). - * Values in the state object may be modified by connected clients - */ - void readFromJsonState(JsonObject &root) {} - - /* - * getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!). - * This could be used in the future for the system to determine whether your usermod is installed. - */ - uint16_t getId() - { - return USERMOD_ID_MODE_SORT; - } -}; diff --git a/usermods/usermod_v2_rotary_encoder_ui/platformio_override.ini.sample b/usermods/usermod_v2_rotary_encoder_ui/platformio_override.ini.sample deleted file mode 100644 index 4b537a8f7c..0000000000 --- a/usermods/usermod_v2_rotary_encoder_ui/platformio_override.ini.sample +++ /dev/null @@ -1,48 +0,0 @@ -[platformio] -default_envs = d1_mini -; default_envs = esp32dev - -[env:esp32dev] -board = esp32dev -platform = espressif32@3.2 -build_unflags = ${common.build_unflags} -build_flags = - ${common.build_flags_esp32} - -D USERMOD_MODE_SORT - -D USERMOD_FOUR_LINE_DISPLAY -D FLD_PIN_SCL=22 -D FLD_PIN_SDA=21 - -D USERMOD_ROTARY_ENCODER_UI -D ENCODER_DT_PIN=18 -D ENCODER_CLK_PIN=5 -D ENCODER_SW_PIN=19 - -D USERMOD_AUTO_SAVE -D AUTOSAVE_PRESET_NUM=1 - -D LEDPIN=16 -D BTNPIN=13 -upload_speed = 460800 -lib_ignore = - ESPAsyncTCP - ESPAsyncUDP - -[env:d1_mini] -board = d1_mini -platform = ${common.platform_wled_default} -platform_packages = ${common.platform_packages} -upload_speed = 460800 -board_build.ldscript = ${common.ldscript_4m1m} -build_unflags = ${common.build_unflags} -build_flags = - ${common.build_flags_esp8266} - -D USERMOD_MODE_SORT - -D USERMOD_FOUR_LINE_DISPLAY -D FLD_PIN_SCL=5 -D FLD_PIN_SDA=4 - -D USERMOD_ROTARY_ENCODER_UI -D ENCODER_DT_PIN=12 -D ENCODER_CLK_PIN=14 -D ENCODER_SW_PIN=13 - -D USERMOD_AUTO_SAVE -D AUTOSAVE_PRESET_NUM=1 - -D LEDPIN=3 -D BTNPIN=0 -monitor_filters = esp8266_exception_decoder - -[env] -lib_deps = - fastled/FastLED @ 3.3.2 - NeoPixelBus @ 2.6.0 - ESPAsyncTCP @ 1.2.0 - ESPAsyncUDP - AsyncTCP @ 1.0.3 - IRremoteESP8266 @ 2.7.3 - https://github.com/lorol/LITTLEFS.git - https://github.com/Aircoookie/ESPAsyncWebServer.git @ ~2.0.0 - U8g2@~2.27.2 - Wire diff --git a/usermods/usermod_v2_rotary_encoder_ui/readme.md b/usermods/usermod_v2_rotary_encoder_ui/readme.md deleted file mode 100644 index 5e4f3cff63..0000000000 --- a/usermods/usermod_v2_rotary_encoder_ui/readme.md +++ /dev/null @@ -1,39 +0,0 @@ -# Rotary Encoder UI Usermod - -First, thanks to the authors of other Rotary Encoder usermods. - -This usermod starts to provide a relatively complete on-device -UI when paired with the Four Line Display usermod. I strongly -encourage you to try them together. - -[See the pair of usermods in action](https://www.youtube.com/watch?v=tITQY80rIOA) - -## Installation - -Copy and update the example `platformio_override.ini.sample` to the root directory of your particular build. -This file should be placed in the same directory as `platformio.ini`. - -### Define Your Options - -* `USERMOD_ROTARY_ENCODER_UI` - define this to have this user mod included wled00\usermods_list.cpp -* `USERMOD_ROTARY_ENCODER_GPIO` - define the GPIO function (INPUT, INPUT_PULLUP, etc...) -* `USERMOD_FOUR_LINE_DISPLAY` - define this to have this the Four Line Display mod included wled00\usermods_list.cpp - also tells this usermod that the display is available - (see the Four Line Display usermod `readme.md` for more details) -* `ENCODER_DT_PIN`   - defaults to 12 -* `ENCODER_CLK_PIN` - defaults to 14 -* `ENCODER_SW_PIN`   - defaults to 13 -* `USERMOD_ROTARY_ENCODER_GPIO` - GPIO functionality: - `INPUT_PULLUP` to use internal pull-up - `INPUT` to use pull-up on the PCB - -### PlatformIO requirements - -No special requirements. - -Note: the Four Line Display usermod requires the libraries `U8g2` and `Wire`. - -## Change Log - -2021-02 -* First public release diff --git a/usermods/usermod_v2_rotary_encoder_ui/usermod_v2_rotary_encoder_ui.h b/usermods/usermod_v2_rotary_encoder_ui/usermod_v2_rotary_encoder_ui.h deleted file mode 100644 index 02bc0ccdaa..0000000000 --- a/usermods/usermod_v2_rotary_encoder_ui/usermod_v2_rotary_encoder_ui.h +++ /dev/null @@ -1,496 +0,0 @@ -#pragma once - -#include "wled.h" - -// -// Inspired by the v1 usermods -// * rotary_encoder_change_brightness -// * rotary_encoder_change_effect -// -// v2 usermod that provides a rotary encoder-based UI. -// -// This usermod allows you to control: -// -// * Brightness -// * Selected Effect -// * Effect Speed -// * Effect Intensity -// * Palette -// -// Change between modes by pressing a button. -// -// Dependencies -// * This usermod REQURES the ModeSortUsermod -// * This Usermod works best coupled with -// FourLineDisplayUsermod. -// - -#ifndef ENCODER_DT_PIN -#define ENCODER_DT_PIN 12 -#endif - -#ifndef ENCODER_CLK_PIN -#define ENCODER_CLK_PIN 14 -#endif - -#ifndef ENCODER_SW_PIN -#define ENCODER_SW_PIN 13 -#endif - -#ifndef USERMOD_FOUR_LINE_DISPLAY -// These constants won't be defined if we aren't using FourLineDisplay. -#define FLD_LINE_BRIGHTNESS 0 -#define FLD_LINE_MODE 0 -#define FLD_LINE_EFFECT_SPEED 0 -#define FLD_LINE_EFFECT_INTENSITY 0 -#define FLD_LINE_PALETTE 0 -#endif - - -// The last UI state -#define LAST_UI_STATE 4 - - -class RotaryEncoderUIUsermod : public Usermod { -private: - int fadeAmount = 10; // Amount to change every step (brightness) - unsigned long currentTime; - unsigned long loopTime; - int8_t pinA = ENCODER_DT_PIN; // DT from encoder - int8_t pinB = ENCODER_CLK_PIN; // CLK from encoder - int8_t pinC = ENCODER_SW_PIN; // SW from encoder - unsigned char select_state = 0; // 0: brightness, 1: effect, 2: effect speed - unsigned char button_state = HIGH; - unsigned char prev_button_state = HIGH; - -#ifdef USERMOD_FOUR_LINE_DISPLAY - FourLineDisplayUsermod *display; -#else - void* display = nullptr; -#endif - - byte *modes_alpha_indexes = nullptr; - byte *palettes_alpha_indexes = nullptr; - - unsigned char Enc_A; - unsigned char Enc_B; - unsigned char Enc_A_prev = 0; - - bool currentEffectAndPaletteInitialized = false; - uint8_t effectCurrentIndex = 0; - uint8_t effectPaletteIndex = 0; - - bool initDone = false; - bool enabled = true; - - // strings to reduce flash memory usage (used more than twice) - static const char _name[]; - static const char _enabled[]; - static const char _DT_pin[]; - static const char _CLK_pin[]; - static const char _SW_pin[]; - -public: - /* - * setup() is called once at boot. WiFi is not yet connected at this point. - * You can use it to initialize variables, sensors or similar. - */ - void setup() - { - DEBUG_PRINTLN(F("Usermod Rotary Encoder init.")); - PinManagerPinType pins[3] = { { pinA, false }, { pinB, false }, { pinC, false } }; - if (!pinManager.allocateMultiplePins(pins, 3, PinOwner::UM_RotaryEncoderUI)) { - // BUG: configuring this usermod with conflicting pins - // will cause it to de-allocate pins it does not own - // (at second config) - // This is the exact type of bug solved by pinManager - // tracking the owner tags.... - pinA = pinB = pinC = -1; - enabled = false; - return; - } - - #ifndef USERMOD_ROTARY_ENCODER_GPIO - #define USERMOD_ROTARY_ENCODER_GPIO INPUT_PULLUP - #endif - pinMode(pinA, USERMOD_ROTARY_ENCODER_GPIO); - pinMode(pinB, USERMOD_ROTARY_ENCODER_GPIO); - pinMode(pinC, USERMOD_ROTARY_ENCODER_GPIO); - - currentTime = millis(); - loopTime = currentTime; - - ModeSortUsermod *modeSortUsermod = (ModeSortUsermod*) usermods.lookup(USERMOD_ID_MODE_SORT); - modes_alpha_indexes = modeSortUsermod->getModesAlphaIndexes(); - palettes_alpha_indexes = modeSortUsermod->getPalettesAlphaIndexes(); - -#ifdef USERMOD_FOUR_LINE_DISPLAY - // This Usermod uses FourLineDisplayUsermod for the best experience. - // But it's optional. But you want it. - display = (FourLineDisplayUsermod*) usermods.lookup(USERMOD_ID_FOUR_LINE_DISP); - if (display != nullptr) { - display->setLineType(FLD_LINE_BRIGHTNESS); - display->setMarkLine(3); - } -#endif - - initDone = true; - } - - /* - * connected() is called every time the WiFi is (re)connected - * Use it to initialize network interfaces - */ - void connected() - { - //Serial.println("Connected to WiFi!"); - } - - /* - * loop() is called continuously. Here you can check for events, read sensors, etc. - * - * Tips: - * 1. You can use "if (WLED_CONNECTED)" to check for a successful network connection. - * Additionally, "if (WLED_MQTT_CONNECTED)" is available to check for a connection to an MQTT broker. - * - * 2. Try to avoid using the delay() function. NEVER use delays longer than 10 milliseconds. - * Instead, use a timer check as shown here. - */ - void loop() - { - if (!enabled) return; - - currentTime = millis(); // get the current elapsed time - - // Initialize effectCurrentIndex and effectPaletteIndex to - // current state. We do it here as (at least) effectCurrent - // is not yet initialized when setup is called. - if (!currentEffectAndPaletteInitialized) { - findCurrentEffectAndPalette(); - } - - if (currentTime >= (loopTime + 2)) // 2ms since last check of encoder = 500Hz - { - button_state = digitalRead(pinC); - if (prev_button_state != button_state) - { - if (button_state == LOW) - { - prev_button_state = button_state; - - char newState = select_state + 1; - if (newState > LAST_UI_STATE) newState = 0; - - bool changedState = true; - if (display != nullptr) { - switch(newState) { - case 0: - changedState = changeState("Brightness", FLD_LINE_BRIGHTNESS, 3); - break; - case 1: - changedState = changeState("Select FX", FLD_LINE_MODE, 2); - break; - case 2: - changedState = changeState("FX Speed", FLD_LINE_EFFECT_SPEED, 3); - break; - case 3: - changedState = changeState("FX Intensity", FLD_LINE_EFFECT_INTENSITY, 3); - break; - case 4: - changedState = changeState("Palette", FLD_LINE_PALETTE, 3); - break; - } - } - if (changedState) { - select_state = newState; - } - } - else - { - prev_button_state = button_state; - } - } - int Enc_A = digitalRead(pinA); // Read encoder pins - int Enc_B = digitalRead(pinB); - if ((!Enc_A) && (Enc_A_prev)) - { // A has gone from high to low - if (Enc_B == HIGH) - { // B is high so clockwise - switch(select_state) { - case 0: - changeBrightness(true); - break; - case 1: - changeEffect(true); - break; - case 2: - changeEffectSpeed(true); - break; - case 3: - changeEffectIntensity(true); - break; - case 4: - changePalette(true); - break; - } - } - else if (Enc_B == LOW) - { // B is low so counter-clockwise - switch(select_state) { - case 0: - changeBrightness(false); - break; - case 1: - changeEffect(false); - break; - case 2: - changeEffectSpeed(false); - break; - case 3: - changeEffectIntensity(false); - break; - case 4: - changePalette(false); - break; - } - } - } - Enc_A_prev = Enc_A; // Store value of A for next time - loopTime = currentTime; // Updates loopTime - } - } - - void findCurrentEffectAndPalette() { - currentEffectAndPaletteInitialized = true; - for (uint8_t i = 0; i < strip.getModeCount(); i++) { - //byte value = modes_alpha_indexes[i]; - if (modes_alpha_indexes[i] == effectCurrent) { - effectCurrentIndex = i; - break; - } - } - - for (uint8_t i = 0; i < strip.getPaletteCount(); i++) { - //byte value = palettes_alpha_indexes[i]; - if (palettes_alpha_indexes[i] == strip.getSegment(0).palette) { - effectPaletteIndex = i; - break; - } - } - } - - boolean changeState(const char *stateName, byte lineThreeMode, byte markedLine) { -#ifdef USERMOD_FOUR_LINE_DISPLAY - if (display != nullptr) { - if (display->wakeDisplay()) { - // Throw away wake up input - return false; - } - display->overlay("Mode change", stateName, 1500); - display->setLineType(lineThreeMode); - display->setMarkLine(markedLine); - } - #endif - return true; - } - - void lampUdated() { - colorUpdated(CALL_MODE_BUTTON); - updateInterfaces(CALL_MODE_BUTTON); - } - - void changeBrightness(bool increase) { -#ifdef USERMOD_FOUR_LINE_DISPLAY - if (display && display->wakeDisplay()) { - // Throw away wake up input - return; - } -#endif - if (increase) { - bri = (bri + fadeAmount <= 255) ? (bri + fadeAmount) : 255; - } - else { - bri = (bri - fadeAmount >= 0) ? (bri - fadeAmount) : 0; - } - lampUdated(); - } - - void changeEffect(bool increase) { -#ifdef USERMOD_FOUR_LINE_DISPLAY - if (display && display->wakeDisplay()) { - // Throw away wake up input - return; - } -#endif - if (increase) { - effectCurrentIndex = (effectCurrentIndex + 1 >= strip.getModeCount()) ? 0 : (effectCurrentIndex + 1); - } - else { - effectCurrentIndex = (effectCurrentIndex - 1 < 0) ? (strip.getModeCount() - 1) : (effectCurrentIndex - 1); - } - effectCurrent = modes_alpha_indexes[effectCurrentIndex]; - lampUdated(); - } - - void changeEffectSpeed(bool increase) { -#ifdef USERMOD_FOUR_LINE_DISPLAY - if (display && display->wakeDisplay()) { - // Throw away wake up input - return; - } -#endif - if (increase) { - effectSpeed = (effectSpeed + fadeAmount <= 255) ? (effectSpeed + fadeAmount) : 255; - } - else { - effectSpeed = (effectSpeed - fadeAmount >= 0) ? (effectSpeed - fadeAmount) : 0; - } - lampUdated(); - } - - void changeEffectIntensity(bool increase) { -#ifdef USERMOD_FOUR_LINE_DISPLAY - if (display && display->wakeDisplay()) { - // Throw away wake up input - return; - } -#endif - if (increase) { - effectIntensity = (effectIntensity + fadeAmount <= 255) ? (effectIntensity + fadeAmount) : 255; - } - else { - effectIntensity = (effectIntensity - fadeAmount >= 0) ? (effectIntensity - fadeAmount) : 0; - } - lampUdated(); - } - - void changePalette(bool increase) { -#ifdef USERMOD_FOUR_LINE_DISPLAY - if (display && display->wakeDisplay()) { - // Throw away wake up input - return; - } -#endif - if (increase) { - effectPaletteIndex = (effectPaletteIndex + 1 >= strip.getPaletteCount()) ? 0 : (effectPaletteIndex + 1); - } - else { - effectPaletteIndex = (effectPaletteIndex - 1 < 0) ? (strip.getPaletteCount() - 1) : (effectPaletteIndex - 1); - } - effectPalette = palettes_alpha_indexes[effectPaletteIndex]; - lampUdated(); - } - - /* - * addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API. - * Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI. - * Below it is shown how this could be used for e.g. a light sensor - */ - /* - void addToJsonInfo(JsonObject& root) - { - int reading = 20; - //this code adds "u":{"Light":[20," lux"]} to the info object - JsonObject user = root["u"]; - if (user.isNull()) user = root.createNestedObject("u"); - JsonArray lightArr = user.createNestedArray("Light"); //name - lightArr.add(reading); //value - lightArr.add(" lux"); //unit - } - */ - - /* - * addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object). - * Values in the state object may be modified by connected clients - */ - void addToJsonState(JsonObject &root) - { - //root["user0"] = userVar0; - } - - /* - * readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object). - * Values in the state object may be modified by connected clients - */ - void readFromJsonState(JsonObject &root) - { - //userVar0 = root["user0"] | userVar0; //if "user0" key exists in JSON, update, else keep old value - //if (root["bri"] == 255) Serial.println(F("Don't burn down your garage!")); - } - - /** - * addToConfig() (called from set.cpp) stores persistent properties to cfg.json - */ - void addToConfig(JsonObject &root) { - // we add JSON object: {"Rotary-Encoder":{"DT-pin":12,"CLK-pin":14,"SW-pin":13}} - JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname - top[FPSTR(_enabled)] = enabled; - top[FPSTR(_DT_pin)] = pinA; - top[FPSTR(_CLK_pin)] = pinB; - top[FPSTR(_SW_pin)] = pinC; - DEBUG_PRINTLN(F("Rotary Encoder config saved.")); - } - - /** - * readFromConfig() is called before setup() to populate properties from values stored in cfg.json - * - * The function should return true if configuration was successfully loaded or false if there was no configuration. - */ - bool readFromConfig(JsonObject &root) { - // we look for JSON object: {"Rotary-Encoder":{"DT-pin":12,"CLK-pin":14,"SW-pin":13}} - JsonObject top = root[FPSTR(_name)]; - if (top.isNull()) { - DEBUG_PRINT(FPSTR(_name)); - DEBUG_PRINTLN(F(": No config found. (Using defaults.)")); - return false; - } - int8_t newDTpin = top[FPSTR(_DT_pin)] | pinA; - int8_t newCLKpin = top[FPSTR(_CLK_pin)] | pinB; - int8_t newSWpin = top[FPSTR(_SW_pin)] | pinC; - - enabled = top[FPSTR(_enabled)] | enabled; - - DEBUG_PRINT(FPSTR(_name)); - if (!initDone) { - // first run: reading from cfg.json - pinA = newDTpin; - pinB = newCLKpin; - pinC = newSWpin; - DEBUG_PRINTLN(F(" config loaded.")); - } else { - DEBUG_PRINTLN(F(" config (re)loaded.")); - // changing parameters from settings page - if (pinA!=newDTpin || pinB!=newCLKpin || pinC!=newSWpin) { - pinManager.deallocatePin(pinA, PinOwner::UM_RotaryEncoderUI); - pinManager.deallocatePin(pinB, PinOwner::UM_RotaryEncoderUI); - pinManager.deallocatePin(pinC, PinOwner::UM_RotaryEncoderUI); - pinA = newDTpin; - pinB = newCLKpin; - pinC = newSWpin; - if (pinA<0 || pinB<0 || pinC<0) { - enabled = false; - return true; - } - setup(); - } - } - // use "return !top["newestParameter"].isNull();" when updating Usermod with new features - return !top[FPSTR(_enabled)].isNull(); - } - - /* - * getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!). - * This could be used in the future for the system to determine whether your usermod is installed. - */ - uint16_t getId() - { - return USERMOD_ID_ROTARY_ENC_UI; - } -}; - -// strings to reduce flash memory usage (used more than twice) -const char RotaryEncoderUIUsermod::_name[] PROGMEM = "Rotary-Encoder"; -const char RotaryEncoderUIUsermod::_enabled[] PROGMEM = "enabled"; -const char RotaryEncoderUIUsermod::_DT_pin[] PROGMEM = "DT-pin"; -const char RotaryEncoderUIUsermod::_CLK_pin[] PROGMEM = "CLK-pin"; -const char RotaryEncoderUIUsermod::_SW_pin[] PROGMEM = "SW-pin"; diff --git a/wled00/usermods_list.cpp b/wled00/usermods_list.cpp index 4a03d48472..b9132d9a40 100644 --- a/wled00/usermods_list.cpp +++ b/wled00/usermods_list.cpp @@ -44,10 +44,6 @@ #include "../usermods/PIR_sensor_switch/usermod_PIR_sensor_switch.h" #endif -#ifdef USERMOD_MODE_SORT - #include "../usermods/usermod_v2_mode_sort/usermod_v2_mode_sort.h" -#endif - #ifdef USERMOD_BH1750 #include "../usermods/BH1750_v2/usermod_BH1750.h" #endif @@ -58,19 +54,11 @@ #endif #ifdef USERMOD_FOUR_LINE_DISPLAY - #ifdef USE_ALT_DISPlAY - #include "../usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h" - #else - #include "../usermods/usermod_v2_four_line_display/usermod_v2_four_line_display.h" - #endif + #include "../usermods/usermod_v2_four_line_display_ALT/usermod_v2_four_line_display_ALT.h" #endif #ifdef USERMOD_ROTARY_ENCODER_UI - #ifdef USE_ALT_DISPlAY - #include "../usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h" - #else - #include "../usermods/usermod_v2_rotary_encoder_ui/usermod_v2_rotary_encoder_ui.h" - #endif + #include "../usermods/usermod_v2_rotary_encoder_ui_ALT/usermod_v2_rotary_encoder_ui_ALT.h" #endif #ifdef USERMOD_AUTO_SAVE @@ -254,10 +242,6 @@ void registerUsermods() usermods.add(new PIRsensorSwitch()); #endif - #ifdef USERMOD_MODE_SORT - usermods.add(new ModeSortUsermod()); - #endif - #ifdef USERMOD_FOUR_LINE_DISPLAY usermods.add(new FourLineDisplayUsermod()); #endif