commit
670461c66f
10
CHANGELOG.md
10
CHANGELOG.md
@ -1,7 +1,15 @@
|
|||||||
## WLED changelog
|
## WLED changelog
|
||||||
|
|
||||||
#### Build 2306020
|
#### Build 2306130
|
||||||
|
- Bumped version to 0.14-b3 (beta 3)
|
||||||
|
- added pin dropdowns in LED preferences (not for LED pins) and usermods
|
||||||
|
- introduced (unused ATM) NeoGammaWLEDMethod class
|
||||||
|
- Reverse proxy support
|
||||||
|
- PCF8754 support for Rotary encoder (requires wiring INT pin to ESP GPIO)
|
||||||
|
- Rely on global I2C pins for usermods (breaking change)
|
||||||
|
- various fixes and enhancements
|
||||||
|
|
||||||
|
#### Build 2306020
|
||||||
- Support for segment sets (PR #3171)
|
- Support for segment sets (PR #3171)
|
||||||
- Reduce sound simulation modes to 2 to facilitiate segment sets
|
- Reduce sound simulation modes to 2 to facilitiate segment sets
|
||||||
- Trigger button immediately on press if all configured presets are the same (PR #3226)
|
- Trigger button immediately on press if all configured presets are the same (PR #3226)
|
||||||
|
2
package-lock.json
generated
2
package-lock.json
generated
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "wled",
|
"name": "wled",
|
||||||
"version": "0.14.0-b2",
|
"version": "0.14.0-b3",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "wled",
|
"name": "wled",
|
||||||
"version": "0.14.0-b2",
|
"version": "0.14.0-b3",
|
||||||
"description": "Tools for WLED project",
|
"description": "Tools for WLED project",
|
||||||
"main": "tools/cdata.js",
|
"main": "tools/cdata.js",
|
||||||
"directories": {
|
"directories": {
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "wled.h"
|
#include "wled.h"
|
||||||
#include <Wire.h>
|
|
||||||
#include <BH1750.h>
|
#include <BH1750.h>
|
||||||
|
|
||||||
// the max frequency to check photoresistor, 10 seconds
|
// the max frequency to check photoresistor, 10 seconds
|
||||||
@ -56,15 +55,6 @@ private:
|
|||||||
static const char _offset[];
|
static const char _offset[];
|
||||||
static const char _HomeAssistantDiscovery[];
|
static const char _HomeAssistantDiscovery[];
|
||||||
|
|
||||||
// set the default pins based on the architecture, these get overridden by Usermod menu settings
|
|
||||||
#ifdef ARDUINO_ARCH_ESP32 // ESP32 boards
|
|
||||||
#define HW_PIN_SCL 22
|
|
||||||
#define HW_PIN_SDA 21
|
|
||||||
#else // ESP8266 boards
|
|
||||||
#define HW_PIN_SCL 5
|
|
||||||
#define HW_PIN_SDA 4
|
|
||||||
#endif
|
|
||||||
int8_t ioPin[2] = {HW_PIN_SCL, HW_PIN_SDA}; // I2C pins: SCL, SDA...defaults to Arch hardware pins but overridden at setup()
|
|
||||||
bool initDone = false;
|
bool initDone = false;
|
||||||
bool sensorFound = false;
|
bool sensorFound = false;
|
||||||
|
|
||||||
@ -123,14 +113,8 @@ private:
|
|||||||
public:
|
public:
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
bool HW_Pins_Used = (ioPin[0]==HW_PIN_SCL && ioPin[1]==HW_PIN_SDA); // note whether architecture-based hardware SCL/SDA pins used
|
PinManagerPinType pins[2] = { { i2c_sda, true }, { i2c_scl, true } }; // allocate pins
|
||||||
PinOwner po = PinOwner::UM_BH1750; // defaults to being pinowner for SCL/SDA pins
|
if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) return;
|
||||||
PinManagerPinType pins[2] = { { ioPin[0], true }, { ioPin[1], true } }; // allocate pins
|
|
||||||
if (HW_Pins_Used) po = PinOwner::HW_I2C; // allow multiple allocations of HW I2C bus pins
|
|
||||||
if (!pinManager.allocateMultiplePins(pins, 2, po)) return;
|
|
||||||
|
|
||||||
Wire.begin(ioPin[1], ioPin[0]);
|
|
||||||
|
|
||||||
sensorFound = lightMeter.begin();
|
sensorFound = lightMeter.begin();
|
||||||
initDone = true;
|
initDone = true;
|
||||||
}
|
}
|
||||||
@ -216,9 +200,6 @@ public:
|
|||||||
top[FPSTR(_minReadInterval)] = minReadingInterval;
|
top[FPSTR(_minReadInterval)] = minReadingInterval;
|
||||||
top[FPSTR(_HomeAssistantDiscovery)] = HomeAssistantDiscovery;
|
top[FPSTR(_HomeAssistantDiscovery)] = HomeAssistantDiscovery;
|
||||||
top[FPSTR(_offset)] = offset;
|
top[FPSTR(_offset)] = offset;
|
||||||
JsonArray io_pin = top.createNestedArray(F("pin"));
|
|
||||||
for (byte i=0; i<2; i++) io_pin.add(ioPin[i]);
|
|
||||||
top[F("help4Pins")] = F("SCL,SDA"); // help for Settings page
|
|
||||||
|
|
||||||
DEBUG_PRINTLN(F("BH1750 config saved."));
|
DEBUG_PRINTLN(F("BH1750 config saved."));
|
||||||
}
|
}
|
||||||
@ -226,8 +207,6 @@ public:
|
|||||||
// called before setup() to populate properties from values stored in cfg.json
|
// called before setup() to populate properties from values stored in cfg.json
|
||||||
bool readFromConfig(JsonObject &root)
|
bool readFromConfig(JsonObject &root)
|
||||||
{
|
{
|
||||||
int8_t newPin[2]; for (byte i=0; i<2; i++) newPin[i] = ioPin[i]; // prepare to note changed pins
|
|
||||||
|
|
||||||
// we look for JSON object.
|
// we look for JSON object.
|
||||||
JsonObject top = root[FPSTR(_name)];
|
JsonObject top = root[FPSTR(_name)];
|
||||||
if (top.isNull())
|
if (top.isNull())
|
||||||
@ -244,27 +223,12 @@ public:
|
|||||||
configComplete &= getJsonValue(top[FPSTR(_minReadInterval)], minReadingInterval, 500); //ms
|
configComplete &= getJsonValue(top[FPSTR(_minReadInterval)], minReadingInterval, 500); //ms
|
||||||
configComplete &= getJsonValue(top[FPSTR(_HomeAssistantDiscovery)], HomeAssistantDiscovery, false);
|
configComplete &= getJsonValue(top[FPSTR(_HomeAssistantDiscovery)], HomeAssistantDiscovery, false);
|
||||||
configComplete &= getJsonValue(top[FPSTR(_offset)], offset, 1);
|
configComplete &= getJsonValue(top[FPSTR(_offset)], offset, 1);
|
||||||
for (byte i=0; i<2; i++) configComplete &= getJsonValue(top[F("pin")][i], newPin[i], ioPin[i]);
|
|
||||||
|
|
||||||
DEBUG_PRINT(FPSTR(_name));
|
DEBUG_PRINT(FPSTR(_name));
|
||||||
if (!initDone) {
|
if (!initDone) {
|
||||||
// first run: reading from cfg.json
|
|
||||||
for (byte i=0; i<2; i++) ioPin[i] = newPin[i];
|
|
||||||
DEBUG_PRINTLN(F(" config loaded."));
|
DEBUG_PRINTLN(F(" config loaded."));
|
||||||
} else {
|
} else {
|
||||||
DEBUG_PRINTLN(F(" config (re)loaded."));
|
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||||
// changing parameters from settings page
|
|
||||||
bool pinsChanged = false;
|
|
||||||
for (byte i=0; i<2; i++) if (ioPin[i] != newPin[i]) { pinsChanged = true; break; } // check if any pins changed
|
|
||||||
if (pinsChanged) { //if pins changed, deallocate old pins and allocate new ones
|
|
||||||
PinOwner po = PinOwner::UM_BH1750;
|
|
||||||
if (ioPin[0]==HW_PIN_SCL && ioPin[1]==HW_PIN_SDA) po = PinOwner::HW_I2C; // allow multiple allocations of HW I2C bus pins
|
|
||||||
pinManager.deallocateMultiplePins((const uint8_t *)ioPin, 2, po); // deallocate pins
|
|
||||||
for (byte i=0; i<2; i++) ioPin[i] = newPin[i];
|
|
||||||
setup();
|
|
||||||
}
|
|
||||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
|
||||||
return !top[F("pin")].isNull();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return configComplete;
|
return configComplete;
|
||||||
|
@ -9,7 +9,6 @@
|
|||||||
|
|
||||||
#include "wled.h"
|
#include "wled.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <Wire.h>
|
|
||||||
#include <BME280I2C.h> // BME280 sensor
|
#include <BME280I2C.h> // BME280 sensor
|
||||||
#include <EnvironmentCalculations.h> // BME280 extended measurements
|
#include <EnvironmentCalculations.h> // BME280 extended measurements
|
||||||
|
|
||||||
@ -34,7 +33,6 @@ private:
|
|||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
//uint8_t RST_PIN = 16; // Uncoment for Heltec WiFi-Kit-8
|
//uint8_t RST_PIN = 16; // Uncoment for Heltec WiFi-Kit-8
|
||||||
#endif
|
#endif
|
||||||
int8_t ioPin[2] = {i2c_scl, i2c_sda}; // I2C pins: SCL, SDA...defaults to Arch hardware pins but overridden at setup()
|
|
||||||
bool initDone = false;
|
bool initDone = false;
|
||||||
|
|
||||||
// BME280 sensor settings
|
// BME280 sensor settings
|
||||||
@ -186,13 +184,8 @@ private:
|
|||||||
public:
|
public:
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
bool HW_Pins_Used = (ioPin[0]==i2c_scl && ioPin[1]==i2c_sda); // note whether architecture-based hardware SCL/SDA pins used
|
PinManagerPinType pins[2] = { { i2c_sda, true }, { i2c_scl, true } }; // allocate pins
|
||||||
PinOwner po = PinOwner::UM_BME280; // defaults to being pinowner for SCL/SDA pins
|
if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { sensorType=0; return; }
|
||||||
PinManagerPinType pins[2] = { { ioPin[0], true }, { ioPin[1], true } }; // allocate pins
|
|
||||||
if (HW_Pins_Used) po = PinOwner::HW_I2C; // allow multiple allocations of HW I2C bus pins
|
|
||||||
if (!pinManager.allocateMultiplePins(pins, 2, po)) { sensorType=0; return; }
|
|
||||||
|
|
||||||
Wire.begin(ioPin[1], ioPin[0]);
|
|
||||||
|
|
||||||
if (!bme.begin())
|
if (!bme.begin())
|
||||||
{
|
{
|
||||||
@ -415,9 +408,6 @@ public:
|
|||||||
top[F("PublishAlways")] = PublishAlways;
|
top[F("PublishAlways")] = PublishAlways;
|
||||||
top[F("UseCelsius")] = UseCelsius;
|
top[F("UseCelsius")] = UseCelsius;
|
||||||
top[F("HomeAssistantDiscovery")] = HomeAssistantDiscovery;
|
top[F("HomeAssistantDiscovery")] = HomeAssistantDiscovery;
|
||||||
JsonArray io_pin = top.createNestedArray(F("pin"));
|
|
||||||
for (byte i=0; i<2; i++) io_pin.add(ioPin[i]);
|
|
||||||
top[F("help4Pins")] = F("SCL,SDA"); // help for Settings page
|
|
||||||
DEBUG_PRINTLN(F("BME280 config saved."));
|
DEBUG_PRINTLN(F("BME280 config saved."));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -427,8 +417,6 @@ public:
|
|||||||
// default settings values could be set here (or below using the 3-argument getJsonValue()) instead of in the class definition or constructor
|
// default settings values could be set here (or below using the 3-argument getJsonValue()) instead of in the class definition or constructor
|
||||||
// setting them inside readFromConfig() is slightly more robust, handling the rare but plausible use case of single value being missing after boot (e.g. if the cfg.json was manually edited and a value was removed)
|
// setting them inside readFromConfig() is slightly more robust, handling the rare but plausible use case of single value being missing after boot (e.g. if the cfg.json was manually edited and a value was removed)
|
||||||
|
|
||||||
int8_t newPin[2]; for (byte i=0; i<2; i++) newPin[i] = ioPin[i]; // prepare to note changed pins
|
|
||||||
|
|
||||||
JsonObject top = root[FPSTR(_name)];
|
JsonObject top = root[FPSTR(_name)];
|
||||||
if (top.isNull()) {
|
if (top.isNull()) {
|
||||||
DEBUG_PRINT(F(_name));
|
DEBUG_PRINT(F(_name));
|
||||||
@ -447,27 +435,14 @@ public:
|
|||||||
configComplete &= getJsonValue(top[F("PublishAlways")], PublishAlways, false);
|
configComplete &= getJsonValue(top[F("PublishAlways")], PublishAlways, false);
|
||||||
configComplete &= getJsonValue(top[F("UseCelsius")], UseCelsius, true);
|
configComplete &= getJsonValue(top[F("UseCelsius")], UseCelsius, true);
|
||||||
configComplete &= getJsonValue(top[F("HomeAssistantDiscovery")], HomeAssistantDiscovery, false);
|
configComplete &= getJsonValue(top[F("HomeAssistantDiscovery")], HomeAssistantDiscovery, false);
|
||||||
for (byte i=0; i<2; i++) configComplete &= getJsonValue(top[F("pin")][i], newPin[i], ioPin[i]);
|
|
||||||
|
|
||||||
DEBUG_PRINT(FPSTR(_name));
|
DEBUG_PRINT(FPSTR(_name));
|
||||||
if (!initDone) {
|
if (!initDone) {
|
||||||
// first run: reading from cfg.json
|
// first run: reading from cfg.json
|
||||||
for (byte i=0; i<2; i++) ioPin[i] = newPin[i];
|
|
||||||
DEBUG_PRINTLN(F(" config loaded."));
|
DEBUG_PRINTLN(F(" config loaded."));
|
||||||
} else {
|
} else {
|
||||||
DEBUG_PRINTLN(F(" config (re)loaded."));
|
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||||
// changing parameters from settings page
|
// changing parameters from settings page
|
||||||
bool pinsChanged = false;
|
|
||||||
for (byte i=0; i<2; i++) if (ioPin[i] != newPin[i]) { pinsChanged = true; break; } // check if any pins changed
|
|
||||||
if (pinsChanged) { //if pins changed, deallocate old pins and allocate new ones
|
|
||||||
PinOwner po = PinOwner::UM_BME280;
|
|
||||||
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); // deallocate pins
|
|
||||||
for (byte i=0; i<2; i++) ioPin[i] = newPin[i];
|
|
||||||
setup();
|
|
||||||
}
|
|
||||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
|
||||||
return !top[F("pin")].isNull();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return configComplete;
|
return configComplete;
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
* This usermod handles PIR sensor states.
|
* This usermod handles PIR sensor states.
|
||||||
* The strip will be switched on and the off timer will be resetted when the sensor goes HIGH.
|
* The strip will be switched on and the off timer will be resetted when the sensor goes HIGH.
|
||||||
* When the sensor state goes LOW, the off timer is started and when it expires, the strip is switched off.
|
* When the sensor state goes LOW, the off timer is started and when it expires, the strip is switched off.
|
||||||
*
|
* Maintained by: @blazoncek
|
||||||
*
|
*
|
||||||
* Usermods allow you to add own functionality to WLED more easily
|
* Usermods allow you to add own functionality to WLED more easily
|
||||||
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
|
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
|
||||||
@ -38,21 +38,21 @@ public:
|
|||||||
~PIRsensorSwitch() {}
|
~PIRsensorSwitch() {}
|
||||||
|
|
||||||
//Enable/Disable the PIR sensor
|
//Enable/Disable the PIR sensor
|
||||||
void EnablePIRsensor(bool en) { enabled = en; }
|
inline void EnablePIRsensor(bool en) { enabled = en; }
|
||||||
|
|
||||||
// Get PIR sensor enabled/disabled state
|
// Get PIR sensor enabled/disabled state
|
||||||
bool PIRsensorEnabled() { return enabled; }
|
inline bool PIRsensorEnabled() { return enabled; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
byte prevPreset = 0;
|
byte prevPreset = 0;
|
||||||
byte prevPlaylist = 0;
|
byte prevPlaylist = 0;
|
||||||
|
|
||||||
uint32_t offTimerStart = 0; // off timer start time
|
volatile unsigned long offTimerStart = 0; // off timer start time
|
||||||
|
volatile bool PIRtriggered = false; // did PIR trigger?
|
||||||
byte NotifyUpdateMode = CALL_MODE_NO_NOTIFY; // notification mode for stateUpdated(): CALL_MODE_NO_NOTIFY or CALL_MODE_DIRECT_CHANGE
|
byte NotifyUpdateMode = CALL_MODE_NO_NOTIFY; // notification mode for stateUpdated(): CALL_MODE_NO_NOTIFY or CALL_MODE_DIRECT_CHANGE
|
||||||
byte sensorPinState = LOW; // current PIR sensor pin state
|
byte sensorPinState = LOW; // current PIR sensor pin state
|
||||||
bool initDone = false; // status of initialization
|
bool initDone = false; // status of initialization
|
||||||
bool PIRtriggered = false;
|
|
||||||
unsigned long lastLoop = 0;
|
unsigned long lastLoop = 0;
|
||||||
|
|
||||||
// configurable parameters
|
// configurable parameters
|
||||||
@ -66,6 +66,7 @@ private:
|
|||||||
// flag to enable triggering only if WLED is initially off (LEDs are not on, preventing running effect being overwritten by PIR)
|
// flag to enable triggering only if WLED is initially off (LEDs are not on, preventing running effect being overwritten by PIR)
|
||||||
bool m_offOnly = false;
|
bool m_offOnly = false;
|
||||||
bool m_offMode = offMode;
|
bool m_offMode = offMode;
|
||||||
|
bool m_override = false;
|
||||||
|
|
||||||
// Home Assistant
|
// Home Assistant
|
||||||
bool HomeAssistantDiscovery = false; // is HA discovery turned on
|
bool HomeAssistantDiscovery = false; // is HA discovery turned on
|
||||||
@ -81,12 +82,122 @@ private:
|
|||||||
static const char _offOnly[];
|
static const char _offOnly[];
|
||||||
static const char _haDiscovery[];
|
static const char _haDiscovery[];
|
||||||
static const char _notify[];
|
static const char _notify[];
|
||||||
|
static const char _override[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* check if it is daytime
|
* check if it is daytime
|
||||||
* if sunrise/sunset is not defined (no NTP or lat/lon) default to nighttime
|
* if sunrise/sunset is not defined (no NTP or lat/lon) default to nighttime
|
||||||
*/
|
*/
|
||||||
bool isDayTime() {
|
static bool isDayTime();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* switch strip on/off
|
||||||
|
*/
|
||||||
|
void switchStrip(bool switchOn);
|
||||||
|
void publishMqtt(const char* state);
|
||||||
|
|
||||||
|
// Create an MQTT Binary Sensor for Home Assistant Discovery purposes, this includes a pointer to the topic that is published to in the Loop.
|
||||||
|
void publishHomeAssistantAutodiscovery();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read and update PIR sensor state.
|
||||||
|
* Initilize/reset switch off timer
|
||||||
|
*/
|
||||||
|
bool updatePIRsensorState();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* switch off the strip if the delay has elapsed
|
||||||
|
*/
|
||||||
|
bool handleOffTimer();
|
||||||
|
|
||||||
|
public:
|
||||||
|
//Functions called by WLED
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* connected() is called every time the WiFi is (re)connected
|
||||||
|
* Use it to initialize network interfaces
|
||||||
|
*/
|
||||||
|
//void connected();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* onMqttConnect() is called when MQTT connection is established
|
||||||
|
*/
|
||||||
|
void onMqttConnect(bool sessionPresent);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* loop() is called continuously. Here you can check for events, read sensors, etc.
|
||||||
|
*/
|
||||||
|
void loop();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
|
||||||
|
*
|
||||||
|
* Add PIR sensor state and switch off timer duration to jsoninfo
|
||||||
|
*/
|
||||||
|
void addToJsonInfo(JsonObject &root);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* onStateChanged() is used to detect WLED state change
|
||||||
|
*/
|
||||||
|
void onStateChange(uint8_t mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* provide the changeable values
|
||||||
|
*/
|
||||||
|
void addToConfig(JsonObject &root);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* provide UI information and allow extending UI options
|
||||||
|
*/
|
||||||
|
void appendConfigData();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* restore the changeable values
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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_PIRSWITCH; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// strings to reduce flash memory usage (used more than twice)
|
||||||
|
const char PIRsensorSwitch::_name[] PROGMEM = "PIRsensorSwitch";
|
||||||
|
const char PIRsensorSwitch::_enabled[] PROGMEM = "PIRenabled";
|
||||||
|
const char PIRsensorSwitch::_switchOffDelay[] PROGMEM = "PIRoffSec";
|
||||||
|
const char PIRsensorSwitch::_onPreset[] PROGMEM = "on-preset";
|
||||||
|
const char PIRsensorSwitch::_offPreset[] PROGMEM = "off-preset";
|
||||||
|
const char PIRsensorSwitch::_nightTime[] PROGMEM = "nighttime-only";
|
||||||
|
const char PIRsensorSwitch::_mqttOnly[] PROGMEM = "mqtt-only";
|
||||||
|
const char PIRsensorSwitch::_offOnly[] PROGMEM = "off-only";
|
||||||
|
const char PIRsensorSwitch::_haDiscovery[] PROGMEM = "HA-discovery";
|
||||||
|
const char PIRsensorSwitch::_notify[] PROGMEM = "notifications";
|
||||||
|
const char PIRsensorSwitch::_override[] PROGMEM = "override";
|
||||||
|
|
||||||
|
bool PIRsensorSwitch::isDayTime() {
|
||||||
updateLocalTime();
|
updateLocalTime();
|
||||||
uint8_t hr = hour(localTime);
|
uint8_t hr = hour(localTime);
|
||||||
uint8_t mi = minute(localTime);
|
uint8_t mi = minute(localTime);
|
||||||
@ -106,10 +217,7 @@ private:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void PIRsensorSwitch::switchStrip(bool switchOn)
|
||||||
* switch strip on/off
|
|
||||||
*/
|
|
||||||
void switchStrip(bool switchOn)
|
|
||||||
{
|
{
|
||||||
if (m_offOnly && bri && (switchOn || (!PIRtriggered && !switchOn))) return; //if lights on and off only, do nothing
|
if (m_offOnly && bri && (switchOn || (!PIRtriggered && !switchOn))) return; //if lights on and off only, do nothing
|
||||||
if (PIRtriggered && switchOn) return; //if already on and triggered before, do nothing
|
if (PIRtriggered && switchOn) return; //if already on and triggered before, do nothing
|
||||||
@ -158,7 +266,7 @@ private:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void publishMqtt(const char* state)
|
void PIRsensorSwitch::publishMqtt(const char* state)
|
||||||
{
|
{
|
||||||
#ifndef WLED_DISABLE_MQTT
|
#ifndef WLED_DISABLE_MQTT
|
||||||
//Check if MQTT Connected, otherwise it will crash the 8266
|
//Check if MQTT Connected, otherwise it will crash the 8266
|
||||||
@ -171,8 +279,7 @@ private:
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create an MQTT Binary Sensor for Home Assistant Discovery purposes, this includes a pointer to the topic that is published to in the Loop.
|
void PIRsensorSwitch::publishHomeAssistantAutodiscovery()
|
||||||
void publishHomeAssistantAutodiscovery()
|
|
||||||
{
|
{
|
||||||
#ifndef WLED_DISABLE_MQTT
|
#ifndef WLED_DISABLE_MQTT
|
||||||
if (WLED_MQTT_CONNECTED) {
|
if (WLED_MQTT_CONNECTED) {
|
||||||
@ -207,11 +314,7 @@ private:
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
bool PIRsensorSwitch::updatePIRsensorState()
|
||||||
* Read and update PIR sensor state.
|
|
||||||
* Initilize/reset switch off timer
|
|
||||||
*/
|
|
||||||
bool updatePIRsensorState()
|
|
||||||
{
|
{
|
||||||
bool pinState = digitalRead(PIRsensorPin);
|
bool pinState = digitalRead(PIRsensorPin);
|
||||||
if (pinState != sensorPinState) {
|
if (pinState != sensorPinState) {
|
||||||
@ -232,10 +335,7 @@ private:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
bool PIRsensorSwitch::handleOffTimer()
|
||||||
* switch off the strip if the delay has elapsed
|
|
||||||
*/
|
|
||||||
bool handleOffTimer()
|
|
||||||
{
|
{
|
||||||
if (offTimerStart > 0 && millis() - offTimerStart > m_switchOffDelay) {
|
if (offTimerStart > 0 && millis() - offTimerStart > m_switchOffDelay) {
|
||||||
offTimerStart = 0;
|
offTimerStart = 0;
|
||||||
@ -249,14 +349,9 @@ private:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
//Functions called by WLED
|
//Functions called by WLED
|
||||||
|
|
||||||
/**
|
void PIRsensorSwitch::setup()
|
||||||
* 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()
|
|
||||||
{
|
{
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
// pin retrieved from cfg.json (readFromConfig()) prior to running setup()
|
// pin retrieved from cfg.json (readFromConfig()) prior to running setup()
|
||||||
@ -275,27 +370,14 @@ public:
|
|||||||
initDone = true;
|
initDone = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void PIRsensorSwitch::onMqttConnect(bool sessionPresent)
|
||||||
* connected() is called every time the WiFi is (re)connected
|
|
||||||
* Use it to initialize network interfaces
|
|
||||||
*/
|
|
||||||
void connected()
|
|
||||||
{
|
{
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* onMqttConnect() is called when MQTT connection is established
|
|
||||||
*/
|
|
||||||
void onMqttConnect(bool sessionPresent) {
|
|
||||||
if (HomeAssistantDiscovery) {
|
if (HomeAssistantDiscovery) {
|
||||||
publishHomeAssistantAutodiscovery();
|
publishHomeAssistantAutodiscovery();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void PIRsensorSwitch::loop()
|
||||||
* loop() is called continuously. Here you can check for events, read sensors, etc.
|
|
||||||
*/
|
|
||||||
void loop()
|
|
||||||
{
|
{
|
||||||
// only check sensors 4x/s
|
// only check sensors 4x/s
|
||||||
if (!enabled || millis() - lastLoop < 250 || strip.isUpdating()) return;
|
if (!enabled || millis() - lastLoop < 250 || strip.isUpdating()) return;
|
||||||
@ -306,12 +388,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void PIRsensorSwitch::addToJsonInfo(JsonObject &root)
|
||||||
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
|
|
||||||
*
|
|
||||||
* Add PIR sensor state and switch off timer duration to jsoninfo
|
|
||||||
*/
|
|
||||||
void addToJsonInfo(JsonObject &root)
|
|
||||||
{
|
{
|
||||||
JsonObject user = root["u"];
|
JsonObject user = root["u"];
|
||||||
if (user.isNull()) user = root.createNestedObject("u");
|
if (user.isNull()) user = root.createNestedObject("u");
|
||||||
@ -371,13 +448,10 @@ public:
|
|||||||
sensor[F("motion")] = sensorPinState || offTimerStart>0 ? true : false;
|
sensor[F("motion")] = sensorPinState || offTimerStart>0 ? true : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void PIRsensorSwitch::onStateChange(uint8_t mode) {
|
||||||
* onStateChanged() is used to detect WLED state change
|
|
||||||
*/
|
|
||||||
void onStateChange(uint8_t mode) {
|
|
||||||
if (!initDone) return;
|
if (!initDone) return;
|
||||||
DEBUG_PRINT(F("PIR: offTimerStart=")); DEBUG_PRINTLN(offTimerStart);
|
DEBUG_PRINT(F("PIR: offTimerStart=")); DEBUG_PRINTLN(offTimerStart);
|
||||||
if (PIRtriggered && offTimerStart) {
|
if (m_override && PIRtriggered && offTimerStart) { // debounce
|
||||||
// checking PIRtriggered and offTimerStart will prevent cancellation upon On trigger
|
// checking PIRtriggered and offTimerStart will prevent cancellation upon On trigger
|
||||||
DEBUG_PRINTLN(F("PIR: Canceled."));
|
DEBUG_PRINTLN(F("PIR: Canceled."));
|
||||||
offTimerStart = 0;
|
offTimerStart = 0;
|
||||||
@ -385,22 +459,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void PIRsensorSwitch::readFromJsonState(JsonObject &root)
|
||||||
* 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()
|
if (!initDone) return; // prevent crash on boot applyPreset()
|
||||||
JsonObject usermod = root[FPSTR(_name)];
|
JsonObject usermod = root[FPSTR(_name)];
|
||||||
@ -411,11 +470,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PIRsensorSwitch::addToConfig(JsonObject &root)
|
||||||
/**
|
|
||||||
* provide the changeable values
|
|
||||||
*/
|
|
||||||
void addToConfig(JsonObject &root)
|
|
||||||
{
|
{
|
||||||
JsonObject top = root.createNestedObject(FPSTR(_name));
|
JsonObject top = root.createNestedObject(FPSTR(_name));
|
||||||
top[FPSTR(_enabled)] = enabled;
|
top[FPSTR(_enabled)] = enabled;
|
||||||
@ -426,24 +481,20 @@ public:
|
|||||||
top[FPSTR(_nightTime)] = m_nightTimeOnly;
|
top[FPSTR(_nightTime)] = m_nightTimeOnly;
|
||||||
top[FPSTR(_mqttOnly)] = m_mqttOnly;
|
top[FPSTR(_mqttOnly)] = m_mqttOnly;
|
||||||
top[FPSTR(_offOnly)] = m_offOnly;
|
top[FPSTR(_offOnly)] = m_offOnly;
|
||||||
|
top[FPSTR(_override)] = m_override;
|
||||||
top[FPSTR(_haDiscovery)] = HomeAssistantDiscovery;
|
top[FPSTR(_haDiscovery)] = HomeAssistantDiscovery;
|
||||||
top[FPSTR(_notify)] = (NotifyUpdateMode != CALL_MODE_NO_NOTIFY);
|
top[FPSTR(_notify)] = (NotifyUpdateMode != CALL_MODE_NO_NOTIFY);
|
||||||
DEBUG_PRINTLN(F("PIR config saved."));
|
DEBUG_PRINTLN(F("PIR config saved."));
|
||||||
}
|
}
|
||||||
|
|
||||||
void appendConfigData()
|
void PIRsensorSwitch::appendConfigData()
|
||||||
{
|
{
|
||||||
oappend(SET_F("addInfo('PIRsensorSwitch:HA-discovery',1,'HA=Home Assistant');")); // 0 is field type, 1 is actual field
|
oappend(SET_F("addInfo('PIRsensorSwitch:HA-discovery',1,'HA=Home Assistant');")); // 0 is field type, 1 is actual field
|
||||||
oappend(SET_F("addInfo('PIRsensorSwitch:notifications',1,'Periodic WS updates');")); // 0 is field type, 1 is actual field
|
oappend(SET_F("addInfo('PIRsensorSwitch:notifications',1,'Periodic WS updates');")); // 0 is field type, 1 is actual field
|
||||||
|
oappend(SET_F("addInfo('PIRsensorSwitch:override',1,'Cancel timer on change');")); // 0 is field type, 1 is actual field
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
bool PIRsensorSwitch::readFromConfig(JsonObject &root)
|
||||||
* restore the changeable values
|
|
||||||
* 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)
|
|
||||||
{
|
{
|
||||||
bool oldEnabled = enabled;
|
bool oldEnabled = enabled;
|
||||||
int8_t oldPin = PIRsensorPin;
|
int8_t oldPin = PIRsensorPin;
|
||||||
@ -469,6 +520,7 @@ public:
|
|||||||
m_nightTimeOnly = top[FPSTR(_nightTime)] | m_nightTimeOnly;
|
m_nightTimeOnly = top[FPSTR(_nightTime)] | m_nightTimeOnly;
|
||||||
m_mqttOnly = top[FPSTR(_mqttOnly)] | m_mqttOnly;
|
m_mqttOnly = top[FPSTR(_mqttOnly)] | m_mqttOnly;
|
||||||
m_offOnly = top[FPSTR(_offOnly)] | m_offOnly;
|
m_offOnly = top[FPSTR(_offOnly)] | m_offOnly;
|
||||||
|
m_override = top[FPSTR(_override)] | m_override;
|
||||||
HomeAssistantDiscovery = top[FPSTR(_haDiscovery)] | HomeAssistantDiscovery;
|
HomeAssistantDiscovery = top[FPSTR(_haDiscovery)] | HomeAssistantDiscovery;
|
||||||
|
|
||||||
NotifyUpdateMode = top[FPSTR(_notify)] ? CALL_MODE_DIRECT_CHANGE : CALL_MODE_NO_NOTIFY;
|
NotifyUpdateMode = top[FPSTR(_notify)] ? CALL_MODE_DIRECT_CHANGE : CALL_MODE_NO_NOTIFY;
|
||||||
@ -498,27 +550,5 @@ public:
|
|||||||
DEBUG_PRINTLN(F(" config (re)loaded."));
|
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||||
}
|
}
|
||||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||||
return !top[FPSTR(_haDiscovery)].isNull();
|
return !top[FPSTR(_override)].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_PIRSWITCH;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// strings to reduce flash memory usage (used more than twice)
|
|
||||||
const char PIRsensorSwitch::_name[] PROGMEM = "PIRsensorSwitch";
|
|
||||||
const char PIRsensorSwitch::_enabled[] PROGMEM = "PIRenabled";
|
|
||||||
const char PIRsensorSwitch::_switchOffDelay[] PROGMEM = "PIRoffSec";
|
|
||||||
const char PIRsensorSwitch::_onPreset[] PROGMEM = "on-preset";
|
|
||||||
const char PIRsensorSwitch::_offPreset[] PROGMEM = "off-preset";
|
|
||||||
const char PIRsensorSwitch::_nightTime[] PROGMEM = "nighttime-only";
|
|
||||||
const char PIRsensorSwitch::_mqttOnly[] PROGMEM = "mqtt-only";
|
|
||||||
const char PIRsensorSwitch::_offOnly[] PROGMEM = "off-only";
|
|
||||||
const char PIRsensorSwitch::_haDiscovery[] PROGMEM = "HA-discovery";
|
|
||||||
const char PIRsensorSwitch::_notify[] PROGMEM = "notifications";
|
|
||||||
|
@ -17,12 +17,6 @@
|
|||||||
#ifndef TFT_HEIGHT
|
#ifndef TFT_HEIGHT
|
||||||
#error Please define TFT_HEIGHT
|
#error Please define TFT_HEIGHT
|
||||||
#endif
|
#endif
|
||||||
#ifndef TFT_MOSI
|
|
||||||
#error Please define TFT_MOSI
|
|
||||||
#endif
|
|
||||||
#ifndef TFT_SCLK
|
|
||||||
#error Please define TFT_SCLK
|
|
||||||
#endif
|
|
||||||
#ifndef TFT_DC
|
#ifndef TFT_DC
|
||||||
#error Please define TFT_DC
|
#error Please define TFT_DC
|
||||||
#endif
|
#endif
|
||||||
@ -140,8 +134,14 @@ class St7789DisplayUsermod : public Usermod {
|
|||||||
*/
|
*/
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
PinManagerPinType pins[] = { { TFT_MOSI, true }, { TFT_MISO, false}, { TFT_SCLK, true }, { TFT_CS, true}, { TFT_DC, true}, { TFT_RST, true }, { TFT_BL, true } };
|
PinManagerPinType spiPins[] = { { spi_mosi, true }, { spi_miso, false}, { spi_sclk, true } };
|
||||||
if (!pinManager.allocateMultiplePins(pins, 7, PinOwner::UM_FourLineDisplay)) { enabled = false; return; }
|
if (!pinManager.allocateMultiplePins(spiPins, 3, PinOwner::HW_SPI)) { enabled = false; return; }
|
||||||
|
PinManagerPinType displayPins[] = { { TFT_CS, true}, { TFT_DC, true}, { TFT_RST, true }, { TFT_BL, true } };
|
||||||
|
if (!pinManager.allocateMultiplePins(displayPins, sizeof(displayPins)/sizeof(PinManagerPinType), PinOwner::UM_FourLineDisplay)) {
|
||||||
|
pinManager.deallocateMultiplePins(spiPins, 3, PinOwner::HW_SPI);
|
||||||
|
enabled = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
tft.init();
|
tft.init();
|
||||||
tft.setRotation(0); //Rotation here is set up for the text to be readable with the port on the left. Use 1 to flip.
|
tft.setRotation(0); //Rotation here is set up for the text to be readable with the port on the left. Use 1 to flip.
|
||||||
@ -365,9 +365,6 @@ class St7789DisplayUsermod : public Usermod {
|
|||||||
{
|
{
|
||||||
JsonObject top = root.createNestedObject("ST7789");
|
JsonObject top = root.createNestedObject("ST7789");
|
||||||
JsonArray pins = top.createNestedArray("pin");
|
JsonArray pins = top.createNestedArray("pin");
|
||||||
pins.add(TFT_MOSI);
|
|
||||||
pins.add(TFT_MISO);
|
|
||||||
pins.add(TFT_SCLK);
|
|
||||||
pins.add(TFT_CS);
|
pins.add(TFT_CS);
|
||||||
pins.add(TFT_DC);
|
pins.add(TFT_DC);
|
||||||
pins.add(TFT_RST);
|
pins.add(TFT_RST);
|
||||||
@ -376,6 +373,13 @@ class St7789DisplayUsermod : public Usermod {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void appendConfigData() {
|
||||||
|
oappend(SET_F("addInfo('ST7789:pin[]',0,'','SPI CS');"));
|
||||||
|
oappend(SET_F("addInfo('ST7789:pin[]',1,'','SPI DC');"));
|
||||||
|
oappend(SET_F("addInfo('ST7789:pin[]',2,'','SPI RST');"));
|
||||||
|
oappend(SET_F("addInfo('ST7789:pin[]',2,'','SPI BL');"));
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* readFromConfig() can be used to read back the custom settings you added with addToConfig().
|
* 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)
|
* This is called by WLED when settings are loaded (currently this only happens once immediately after boot)
|
||||||
|
@ -13,14 +13,6 @@
|
|||||||
|
|
||||||
Adafruit_Si7021 si7021;
|
Adafruit_Si7021 si7021;
|
||||||
|
|
||||||
#ifdef ARDUINO_ARCH_ESP32 //ESP32 boards
|
|
||||||
uint8_t SCL_PIN = 22;
|
|
||||||
uint8_t SDA_PIN = 21;
|
|
||||||
#else //ESP8266 boards
|
|
||||||
uint8_t SCL_PIN = 5;
|
|
||||||
uint8_t SDA_PIN = 4;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class Si7021_MQTT_HA : public Usermod
|
class Si7021_MQTT_HA : public Usermod
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
@ -184,7 +176,6 @@ class Si7021_MQTT_HA : public Usermod
|
|||||||
{
|
{
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
Serial.println("Si7021_MQTT_HA: Starting!");
|
Serial.println("Si7021_MQTT_HA: Starting!");
|
||||||
Wire.begin(SDA_PIN, SCL_PIN);
|
|
||||||
Serial.println("Si7021_MQTT_HA: Initializing sensors.. ");
|
Serial.println("Si7021_MQTT_HA: Initializing sensors.. ");
|
||||||
_initializeSensor();
|
_initializeSensor();
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,6 @@ class UsermodVL53L0XGestures : public Usermod {
|
|||||||
void setup() {
|
void setup() {
|
||||||
PinManagerPinType pins[2] = { { i2c_scl, true }, { i2c_sda, true } };
|
PinManagerPinType pins[2] = { { i2c_scl, true }, { i2c_sda, true } };
|
||||||
if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { enabled = false; return; }
|
if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { enabled = false; return; }
|
||||||
Wire.begin();
|
|
||||||
|
|
||||||
sensor.setTimeout(150);
|
sensor.setTimeout(150);
|
||||||
if (!sensor.init())
|
if (!sensor.init())
|
||||||
|
@ -569,16 +569,6 @@ class AudioReactive : public Usermod {
|
|||||||
#else
|
#else
|
||||||
int8_t i2sckPin = I2S_CKPIN;
|
int8_t i2sckPin = I2S_CKPIN;
|
||||||
#endif
|
#endif
|
||||||
#ifndef ES7243_SDAPIN
|
|
||||||
int8_t sdaPin = -1;
|
|
||||||
#else
|
|
||||||
int8_t sdaPin = ES7243_SDAPIN;
|
|
||||||
#endif
|
|
||||||
#ifndef ES7243_SCLPIN
|
|
||||||
int8_t sclPin = -1;
|
|
||||||
#else
|
|
||||||
int8_t sclPin = ES7243_SCLPIN;
|
|
||||||
#endif
|
|
||||||
#ifndef MCLK_PIN
|
#ifndef MCLK_PIN
|
||||||
int8_t mclkPin = I2S_PIN_NO_CHANGE; /* ESP32: only -1, 0, 1, 3 allowed*/
|
int8_t mclkPin = I2S_PIN_NO_CHANGE; /* ESP32: only -1, 0, 1, 3 allowed*/
|
||||||
#else
|
#else
|
||||||
@ -1136,7 +1126,7 @@ class AudioReactive : public Usermod {
|
|||||||
DEBUGSR_PRINTLN(F("AR: ES7243 Microphone (right channel only)."));
|
DEBUGSR_PRINTLN(F("AR: ES7243 Microphone (right channel only)."));
|
||||||
audioSource = new ES7243(SAMPLE_RATE, BLOCK_SIZE);
|
audioSource = new ES7243(SAMPLE_RATE, BLOCK_SIZE);
|
||||||
delay(100);
|
delay(100);
|
||||||
if (audioSource) audioSource->initialize(sdaPin, sclPin, i2swsPin, i2ssdPin, i2sckPin, mclkPin);
|
if (audioSource) audioSource->initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
DEBUGSR_PRINT(F("AR: SPH0645 Microphone - ")); DEBUGSR_PRINTLN(F(I2S_MIC_CHANNEL_TEXT));
|
DEBUGSR_PRINT(F("AR: SPH0645 Microphone - ")); DEBUGSR_PRINTLN(F(I2S_MIC_CHANNEL_TEXT));
|
||||||
@ -1657,8 +1647,6 @@ class AudioReactive : public Usermod {
|
|||||||
pinArray.add(i2swsPin);
|
pinArray.add(i2swsPin);
|
||||||
pinArray.add(i2sckPin);
|
pinArray.add(i2sckPin);
|
||||||
pinArray.add(mclkPin);
|
pinArray.add(mclkPin);
|
||||||
pinArray.add(sdaPin);
|
|
||||||
pinArray.add(sclPin);
|
|
||||||
|
|
||||||
JsonObject cfg = top.createNestedObject("config");
|
JsonObject cfg = top.createNestedObject("config");
|
||||||
cfg[F("squelch")] = soundSquelch;
|
cfg[F("squelch")] = soundSquelch;
|
||||||
@ -1719,8 +1707,6 @@ class AudioReactive : public Usermod {
|
|||||||
configComplete &= getJsonValue(top[FPSTR(_digitalmic)]["pin"][1], i2swsPin);
|
configComplete &= getJsonValue(top[FPSTR(_digitalmic)]["pin"][1], i2swsPin);
|
||||||
configComplete &= getJsonValue(top[FPSTR(_digitalmic)]["pin"][2], i2sckPin);
|
configComplete &= getJsonValue(top[FPSTR(_digitalmic)]["pin"][2], i2sckPin);
|
||||||
configComplete &= getJsonValue(top[FPSTR(_digitalmic)]["pin"][3], mclkPin);
|
configComplete &= getJsonValue(top[FPSTR(_digitalmic)]["pin"][3], mclkPin);
|
||||||
configComplete &= getJsonValue(top[FPSTR(_digitalmic)]["pin"][4], sdaPin);
|
|
||||||
configComplete &= getJsonValue(top[FPSTR(_digitalmic)]["pin"][5], sclPin);
|
|
||||||
|
|
||||||
configComplete &= getJsonValue(top["config"][F("squelch")], soundSquelch);
|
configComplete &= getJsonValue(top["config"][F("squelch")], soundSquelch);
|
||||||
configComplete &= getJsonValue(top["config"][F("gain")], sampleGain);
|
configComplete &= getJsonValue(top["config"][F("gain")], sampleGain);
|
||||||
@ -1784,8 +1770,6 @@ class AudioReactive : public Usermod {
|
|||||||
#else
|
#else
|
||||||
oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',3,'<i>master clock</i>','I2S MCLK');"));
|
oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',3,'<i>master clock</i>','I2S MCLK');"));
|
||||||
#endif
|
#endif
|
||||||
oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',4,'','I2C SDA');"));
|
|
||||||
oappend(SET_F("addInfo('AudioReactive:digitalmic:pin[]',5,'','I2C SCL');"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <Wire.h>
|
|
||||||
#include "wled.h"
|
#include "wled.h"
|
||||||
#include <driver/i2s.h>
|
#include <driver/i2s.h>
|
||||||
#include <driver/adc.h>
|
#include <driver/adc.h>
|
||||||
@ -383,21 +382,12 @@ class I2SSource : public AudioSource {
|
|||||||
*/
|
*/
|
||||||
class ES7243 : public I2SSource {
|
class ES7243 : public I2SSource {
|
||||||
private:
|
private:
|
||||||
// I2C initialization functions for ES7243
|
|
||||||
void _es7243I2cBegin() {
|
|
||||||
bool i2c_initialized = Wire.begin(pin_ES7243_SDA, pin_ES7243_SCL, 100000U);
|
|
||||||
if (i2c_initialized == false) {
|
|
||||||
DEBUGSR_PRINTLN(F("AR: ES7243 failed to initialize I2C bus driver."));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void _es7243I2cWrite(uint8_t reg, uint8_t val) {
|
void _es7243I2cWrite(uint8_t reg, uint8_t val) {
|
||||||
#ifndef ES7243_ADDR
|
#ifndef ES7243_ADDR
|
||||||
Wire.beginTransmission(0x13);
|
|
||||||
#define ES7243_ADDR 0x13 // default address
|
#define ES7243_ADDR 0x13 // default address
|
||||||
#else
|
|
||||||
Wire.beginTransmission(ES7243_ADDR);
|
|
||||||
#endif
|
#endif
|
||||||
|
Wire.beginTransmission(ES7243_ADDR);
|
||||||
Wire.write((uint8_t)reg);
|
Wire.write((uint8_t)reg);
|
||||||
Wire.write((uint8_t)val);
|
Wire.write((uint8_t)val);
|
||||||
uint8_t i2cErr = Wire.endTransmission(); // i2cErr == 0 means OK
|
uint8_t i2cErr = Wire.endTransmission(); // i2cErr == 0 means OK
|
||||||
@ -407,7 +397,6 @@ class ES7243 : public I2SSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _es7243InitAdc() {
|
void _es7243InitAdc() {
|
||||||
_es7243I2cBegin();
|
|
||||||
_es7243I2cWrite(0x00, 0x01);
|
_es7243I2cWrite(0x00, 0x01);
|
||||||
_es7243I2cWrite(0x06, 0x00);
|
_es7243I2cWrite(0x06, 0x00);
|
||||||
_es7243I2cWrite(0x05, 0x1B);
|
_es7243I2cWrite(0x05, 0x1B);
|
||||||
@ -422,44 +411,20 @@ public:
|
|||||||
_config.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT;
|
_config.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT;
|
||||||
};
|
};
|
||||||
|
|
||||||
void initialize(int8_t sdaPin, int8_t sclPin, int8_t i2swsPin, int8_t i2ssdPin, int8_t i2sckPin, int8_t mclkPin) {
|
void initialize(int8_t i2swsPin, int8_t i2ssdPin, int8_t i2sckPin, int8_t mclkPin) {
|
||||||
// check that pins are valid
|
|
||||||
if ((sdaPin < 0) || (sclPin < 0)) {
|
|
||||||
DEBUGSR_PRINTF("\nAR: invalid ES7243 I2C pins: SDA=%d, SCL=%d\n", sdaPin, sclPin);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((i2sckPin < 0) || (mclkPin < 0)) {
|
if ((i2sckPin < 0) || (mclkPin < 0)) {
|
||||||
DEBUGSR_PRINTF("\nAR: invalid I2S pin: SCK=%d, MCLK=%d\n", i2sckPin, mclkPin);
|
DEBUGSR_PRINTF("\nAR: invalid I2S pin: SCK=%d, MCLK=%d\n", i2sckPin, mclkPin);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reserve SDA and SCL pins of the I2C interface
|
|
||||||
PinManagerPinType es7243Pins[2] = { { sdaPin, true }, { sclPin, true } };
|
|
||||||
if (!pinManager.allocateMultiplePins(es7243Pins, 2, PinOwner::HW_I2C)) {
|
|
||||||
pinManager.deallocateMultiplePins(es7243Pins, 2, PinOwner::HW_I2C);
|
|
||||||
DEBUGSR_PRINTF("\nAR: Failed to allocate ES7243 I2C pins: SDA=%d, SCL=%d\n", sdaPin, sclPin);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
pin_ES7243_SDA = sdaPin;
|
|
||||||
pin_ES7243_SCL = sclPin;
|
|
||||||
|
|
||||||
// First route mclk, then configure ADC over I2C, then configure I2S
|
// First route mclk, then configure ADC over I2C, then configure I2S
|
||||||
_es7243InitAdc();
|
_es7243InitAdc();
|
||||||
I2SSource::initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin);
|
I2SSource::initialize(i2swsPin, i2ssdPin, i2sckPin, mclkPin);
|
||||||
}
|
}
|
||||||
|
|
||||||
void deinitialize() {
|
void deinitialize() {
|
||||||
// Release SDA and SCL pins of the I2C interface
|
|
||||||
PinManagerPinType es7243Pins[2] = { { pin_ES7243_SDA, true }, { pin_ES7243_SCL, true } };
|
|
||||||
pinManager.deallocateMultiplePins(es7243Pins, 2, PinOwner::HW_I2C);
|
|
||||||
I2SSource::deinitialize();
|
I2SSource::deinitialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
int8_t pin_ES7243_SDA;
|
|
||||||
int8_t pin_ES7243_SCL;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -87,10 +87,8 @@ class MPU6050Driver : public Usermod {
|
|||||||
void setup() {
|
void setup() {
|
||||||
PinManagerPinType pins[2] = { { i2c_scl, true }, { i2c_sda, true } };
|
PinManagerPinType pins[2] = { { i2c_scl, true }, { i2c_sda, true } };
|
||||||
if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { enabled = false; return; }
|
if (!pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { enabled = false; return; }
|
||||||
// join I2C bus (I2Cdev library doesn't do this automatically)
|
|
||||||
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
|
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
|
||||||
Wire.begin();
|
Wire.setClock(400000U); // 400kHz I2C clock. Comment this line if having compilation difficulties
|
||||||
Wire.setClock(400000); // 400kHz I2C clock. Comment this line if having compilation difficulties
|
|
||||||
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
|
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
|
||||||
Fastwire::setup(400, true);
|
Fastwire::setup(400, true);
|
||||||
#endif
|
#endif
|
||||||
|
@ -20,6 +20,14 @@
|
|||||||
#define ON true
|
#define ON true
|
||||||
#define OFF false
|
#define OFF false
|
||||||
|
|
||||||
|
#ifndef USERMOD_USE_PCF8574
|
||||||
|
#undef USE_PCF8574
|
||||||
|
#define USE_PCF8574 false
|
||||||
|
#else
|
||||||
|
#undef USE_PCF8574
|
||||||
|
#define USE_PCF8574 true
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef PCF8574_ADDRESS
|
#ifndef PCF8574_ADDRESS
|
||||||
#define PCF8574_ADDRESS 0x20 // some may start at 0x38
|
#define PCF8574_ADDRESS 0x20 // some may start at 0x38
|
||||||
#endif
|
#endif
|
||||||
@ -52,21 +60,15 @@ class MultiRelay : public Usermod {
|
|||||||
// array of relays
|
// array of relays
|
||||||
Relay _relay[MULTI_RELAY_MAX_RELAYS];
|
Relay _relay[MULTI_RELAY_MAX_RELAYS];
|
||||||
|
|
||||||
// switch timer start time
|
uint32_t _switchTimerStart; // switch timer start time
|
||||||
uint32_t _switchTimerStart = 0;
|
bool _oldMode; // old brightness
|
||||||
// old brightness
|
bool enabled; // usermod enabled
|
||||||
bool _oldMode;
|
bool initDone; // status of initialisation
|
||||||
|
bool usePcf8574;
|
||||||
// usermod enabled
|
uint8_t addrPcf8574;
|
||||||
bool enabled = false; // needs to be configured (no default config)
|
bool HAautodiscovery;
|
||||||
// status of initialisation
|
uint16_t periodicBroadcastSec;
|
||||||
bool initDone = false;
|
unsigned long lastBroadcast;
|
||||||
bool usePcf8574 = false;
|
|
||||||
uint8_t addrPcf8574 = PCF8574_ADDRESS;
|
|
||||||
bool HAautodiscovery = false;
|
|
||||||
|
|
||||||
uint16_t periodicBroadcastSec = 60;
|
|
||||||
unsigned long lastBroadcast = 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[];
|
||||||
@ -103,7 +105,7 @@ class MultiRelay : public Usermod {
|
|||||||
/**
|
/**
|
||||||
* desctructor
|
* desctructor
|
||||||
*/
|
*/
|
||||||
~MultiRelay() {}
|
//~MultiRelay() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable/Disable the usermod
|
* Enable/Disable the usermod
|
||||||
@ -331,7 +333,16 @@ byte MultiRelay::IOexpanderRead(int address) {
|
|||||||
|
|
||||||
// public methods
|
// public methods
|
||||||
|
|
||||||
MultiRelay::MultiRelay() {
|
MultiRelay::MultiRelay()
|
||||||
|
: _switchTimerStart(0)
|
||||||
|
, enabled(false)
|
||||||
|
, initDone(false)
|
||||||
|
, usePcf8574(USE_PCF8574)
|
||||||
|
, addrPcf8574(PCF8574_ADDRESS)
|
||||||
|
, HAautodiscovery(false)
|
||||||
|
, periodicBroadcastSec(60)
|
||||||
|
, lastBroadcast(0)
|
||||||
|
{
|
||||||
const int8_t defPins[] = {MULTI_RELAY_PINS};
|
const int8_t defPins[] = {MULTI_RELAY_PINS};
|
||||||
for (size_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
for (size_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||||
_relay[i].pin = i<sizeof(defPins) ? defPins[i] : -1;
|
_relay[i].pin = i<sizeof(defPins) ? defPins[i] : -1;
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
|
|
||||||
#include "wled.h"
|
#include "wled.h"
|
||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <Wire.h>
|
|
||||||
#include <Adafruit_Sensor.h>
|
#include <Adafruit_Sensor.h>
|
||||||
#include <Adafruit_BMP280.h>
|
#include <Adafruit_BMP280.h>
|
||||||
#include <Adafruit_CCS811.h>
|
#include <Adafruit_CCS811.h>
|
||||||
@ -16,14 +15,6 @@ Adafruit_BMP280 bmp;
|
|||||||
Adafruit_Si7021 si7021;
|
Adafruit_Si7021 si7021;
|
||||||
Adafruit_CCS811 ccs811;
|
Adafruit_CCS811 ccs811;
|
||||||
|
|
||||||
#ifdef ARDUINO_ARCH_ESP32 //ESP32 boards
|
|
||||||
uint8_t SCL_PIN = 22;
|
|
||||||
uint8_t SDA_PIN = 21;
|
|
||||||
#else //ESP8266 boards
|
|
||||||
uint8_t SCL_PIN = 5;
|
|
||||||
uint8_t SDA_PIN = 4;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class UserMod_SensorsToMQTT : public Usermod
|
class UserMod_SensorsToMQTT : public Usermod
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
@ -231,7 +222,6 @@ public:
|
|||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
Serial.println("Starting!");
|
Serial.println("Starting!");
|
||||||
Wire.begin(SDA_PIN, SCL_PIN);
|
|
||||||
Serial.println("Initializing sensors.. ");
|
Serial.println("Initializing sensors.. ");
|
||||||
_initialize();
|
_initialize();
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,24 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "wled.h"
|
#include "wled.h"
|
||||||
|
#undef U8X8_NO_HW_I2C // borrowed from WLEDMM: we do want I2C hardware drivers - if possible
|
||||||
#include <U8x8lib.h> // from https://github.com/olikraus/u8g2/
|
#include <U8x8lib.h> // from https://github.com/olikraus/u8g2/
|
||||||
#include "4LD_wled_fonts.c"
|
#include "4LD_wled_fonts.c"
|
||||||
|
|
||||||
|
#ifndef FLD_ESP32_NO_THREADS
|
||||||
|
#define FLD_ESP32_USE_THREADS // comment out to use 0.13.x behviour without parallel update task - slower, but more robust. May delay other tasks like LEDs or audioreactive!!
|
||||||
|
#endif
|
||||||
|
|
||||||
//
|
//
|
||||||
// Insired by the usermod_v2_four_line_display
|
// Inspired by the usermod_v2_four_line_display
|
||||||
//
|
//
|
||||||
// v2 usermod for using 128x32 or 128x64 i2c
|
// v2 usermod for using 128x32 or 128x64 i2c
|
||||||
// OLED displays to provide a four line display
|
// OLED displays to provide a four line display
|
||||||
// for WLED.
|
// for WLED.
|
||||||
//
|
//
|
||||||
// Dependencies
|
// Dependencies
|
||||||
// * This usermod REQURES the ModeSortUsermod
|
|
||||||
// * This Usermod works best, by far, when coupled
|
// * This Usermod works best, by far, when coupled
|
||||||
// with RotaryEncoderUIUsermod.
|
// with RotaryEncoderUI ALT Usermod.
|
||||||
//
|
//
|
||||||
// Make sure to enable NTP and set your time zone in WLED Config | Time.
|
// Make sure to enable NTP and set your time zone in WLED Config | Time.
|
||||||
//
|
//
|
||||||
@ -23,22 +27,14 @@
|
|||||||
// REQUIREMENT: * U8g2 (the version already in platformio.ini is fine)
|
// REQUIREMENT: * U8g2 (the version already in platformio.ini is fine)
|
||||||
// REQUIREMENT: * Wire
|
// REQUIREMENT: * Wire
|
||||||
//
|
//
|
||||||
|
// 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
|
||||||
|
|
||||||
//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
|
#ifndef FLD_PIN_CS
|
||||||
#define FLD_PIN_CS spi_cs
|
#define FLD_PIN_CS 15
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
@ -97,9 +93,11 @@ typedef enum {
|
|||||||
|
|
||||||
|
|
||||||
class FourLineDisplayUsermod : public Usermod {
|
class FourLineDisplayUsermod : public Usermod {
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS)
|
||||||
public:
|
public:
|
||||||
FourLineDisplayUsermod() { if (!instance) instance = this; }
|
FourLineDisplayUsermod() { if (!instance) instance = this; }
|
||||||
static FourLineDisplayUsermod* getInstance(void) { return instance; }
|
static FourLineDisplayUsermod* getInstance(void) { return instance; }
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@ -112,10 +110,10 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
U8X8 *u8x8 = nullptr; // pointer to U8X8 display object
|
U8X8 *u8x8 = nullptr; // pointer to U8X8 display object
|
||||||
|
|
||||||
#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[3] = {-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)
|
||||||
#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[3] = {FLD_PIN_CS, FLD_PIN_DC, FLD_PIN_RESET}; // custom SPI pins: 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)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -178,7 +176,194 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
// https://github.com/olikraus/u8g2/wiki/gallery
|
// https://github.com/olikraus/u8g2/wiki/gallery
|
||||||
|
|
||||||
// some displays need this to properly apply contrast
|
// some displays need this to properly apply contrast
|
||||||
void setVcomh(bool highContrast) {
|
void setVcomh(bool highContrast);
|
||||||
|
void startDisplay();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Wrappers for screen drawing
|
||||||
|
*/
|
||||||
|
void setFlipMode(uint8_t mode);
|
||||||
|
void setContrast(uint8_t contrast);
|
||||||
|
void drawString(uint8_t col, uint8_t row, const char *string, bool ignoreLH=false);
|
||||||
|
void draw2x2String(uint8_t col, uint8_t row, const char *string);
|
||||||
|
void drawGlyph(uint8_t col, uint8_t row, char glyph, const uint8_t *font, bool ignoreLH=false);
|
||||||
|
void draw2x2Glyph(uint8_t col, uint8_t row, char glyph, const uint8_t *font);
|
||||||
|
void draw2x2GlyphIcons();
|
||||||
|
uint8_t getCols();
|
||||||
|
void clear();
|
||||||
|
void setPowerSave(uint8_t save);
|
||||||
|
void center(String &line, uint8_t width);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable sleep (turn the display off) or clock mode.
|
||||||
|
*/
|
||||||
|
void sleepOrClock(bool enabled);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
// gets called once at boot. Do all initialization that doesn't depend on
|
||||||
|
// network here
|
||||||
|
void setup();
|
||||||
|
|
||||||
|
// gets called every time WiFi is (re-)connected. Initialize own network
|
||||||
|
// interfaces here
|
||||||
|
void connected();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Da loop.
|
||||||
|
*/
|
||||||
|
void loop();
|
||||||
|
|
||||||
|
//function to update lastredraw
|
||||||
|
inline void updateRedrawTime() { lastRedraw = millis(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redraw the screen (but only if things have changed
|
||||||
|
* or if forceRedraw).
|
||||||
|
*/
|
||||||
|
void redraw(bool forceRedraw);
|
||||||
|
|
||||||
|
void updateBrightness();
|
||||||
|
void updateSpeed();
|
||||||
|
void updateIntensity();
|
||||||
|
void drawStatusIcons();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* marks the position of the arrow showing
|
||||||
|
* the current setting being changed
|
||||||
|
* pass line and colum info
|
||||||
|
*/
|
||||||
|
void setMarkLine(byte newMarkLineNum, byte newMarkColNum);
|
||||||
|
|
||||||
|
//Draw the arrow for the current setting beiong changed
|
||||||
|
void drawArrow();
|
||||||
|
|
||||||
|
//Display the current effect or palette (desiredEntry)
|
||||||
|
// on the appropriate line (row).
|
||||||
|
void showCurrentEffectOrPalette(int inputEffPal, const char *qstring, uint8_t row);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows you to show one line and a glyph as overlay for a period of time.
|
||||||
|
* Clears the screen and prints.
|
||||||
|
* Used in Rotary Encoder usermod.
|
||||||
|
*/
|
||||||
|
void overlay(const char* line1, long showHowLong, byte glyphType);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows you to show Akemi WLED logo overlay for a period of time.
|
||||||
|
* Clears the screen and prints.
|
||||||
|
*/
|
||||||
|
void overlayLogo(long showHowLong);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows you to show two lines as overlay for a period of time.
|
||||||
|
* Clears the screen and prints.
|
||||||
|
* Used in Auto Save usermod
|
||||||
|
*/
|
||||||
|
void overlay(const char* line1, const char* line2, long showHowLong);
|
||||||
|
|
||||||
|
void networkOverlay(const char* line1, long showHowLong);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* handleButton() can be used to override default button behaviour. Returning true
|
||||||
|
* will prevent button working in a default way.
|
||||||
|
* Replicating button.cpp
|
||||||
|
*/
|
||||||
|
bool handleButton(uint8_t b);
|
||||||
|
|
||||||
|
void onUpdateBegin(bool init);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
void appendConfigData();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 = "refreshRate-ms";
|
||||||
|
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::_showSeconds[] PROGMEM = "showSeconds";
|
||||||
|
const char FourLineDisplayUsermod::_busClkFrequency[] PROGMEM = "i2c-freq-kHz";
|
||||||
|
const char FourLineDisplayUsermod::_contrastFix[] PROGMEM = "contrastFix";
|
||||||
|
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS)
|
||||||
|
FourLineDisplayUsermod *FourLineDisplayUsermod::instance = nullptr;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// some displays need this to properly apply contrast
|
||||||
|
void FourLineDisplayUsermod::setVcomh(bool highContrast) {
|
||||||
|
if (type == NONE || !enabled) return;
|
||||||
u8x8_t *u8x8_struct = u8x8->getU8x8();
|
u8x8_t *u8x8_struct = u8x8->getU8x8();
|
||||||
u8x8_cad_StartTransfer(u8x8_struct);
|
u8x8_cad_StartTransfer(u8x8_struct);
|
||||||
u8x8_cad_SendCmd(u8x8_struct, 0x0db); //address of value
|
u8x8_cad_SendCmd(u8x8_struct, 0x0db); //address of value
|
||||||
@ -186,18 +371,32 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
u8x8_cad_EndTransfer(u8x8_struct);
|
u8x8_cad_EndTransfer(u8x8_struct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FourLineDisplayUsermod::startDisplay() {
|
||||||
|
if (type == NONE || !enabled) return;
|
||||||
|
lineHeight = u8x8->getRows() > 4 ? 2 : 1;
|
||||||
|
DEBUG_PRINTLN(F("Starting display."));
|
||||||
|
u8x8->setBusClock(ioFrequency); // can be used for SPI too
|
||||||
|
u8x8->begin();
|
||||||
|
setFlipMode(flip);
|
||||||
|
setVcomh(contrastFix);
|
||||||
|
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...");
|
||||||
|
overlayLogo(3500);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrappers for screen drawing
|
* Wrappers for screen drawing
|
||||||
*/
|
*/
|
||||||
void setFlipMode(uint8_t mode) {
|
void FourLineDisplayUsermod::setFlipMode(uint8_t mode) {
|
||||||
if (type == NONE || !enabled) return;
|
if (type == NONE || !enabled) return;
|
||||||
u8x8->setFlipMode(mode);
|
u8x8->setFlipMode(mode);
|
||||||
}
|
}
|
||||||
void setContrast(uint8_t contrast) {
|
void FourLineDisplayUsermod::setContrast(uint8_t contrast) {
|
||||||
if (type == NONE || !enabled) 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 FourLineDisplayUsermod::drawString(uint8_t col, uint8_t row, const char *string, bool ignoreLH) {
|
||||||
if (type == NONE || !enabled) return;
|
if (type == NONE || !enabled) return;
|
||||||
drawing = true;
|
drawing = true;
|
||||||
u8x8->setFont(u8x8_font_chroma48medium8_r);
|
u8x8->setFont(u8x8_font_chroma48medium8_r);
|
||||||
@ -205,14 +404,14 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
else u8x8->drawString(col, row, string);
|
else u8x8->drawString(col, row, string);
|
||||||
drawing = false;
|
drawing = false;
|
||||||
}
|
}
|
||||||
void draw2x2String(uint8_t col, uint8_t row, const char *string) {
|
void FourLineDisplayUsermod::draw2x2String(uint8_t col, uint8_t row, const char *string) {
|
||||||
if (type == NONE || !enabled) return;
|
if (type == NONE || !enabled) return;
|
||||||
drawing = true;
|
drawing = true;
|
||||||
u8x8->setFont(u8x8_font_chroma48medium8_r);
|
u8x8->setFont(u8x8_font_chroma48medium8_r);
|
||||||
u8x8->draw2x2String(col, row, string);
|
u8x8->draw2x2String(col, row, string);
|
||||||
drawing = false;
|
drawing = false;
|
||||||
}
|
}
|
||||||
void drawGlyph(uint8_t col, uint8_t row, char glyph, const uint8_t *font, bool ignoreLH=false) {
|
void FourLineDisplayUsermod::drawGlyph(uint8_t col, uint8_t row, char glyph, const uint8_t *font, bool ignoreLH) {
|
||||||
if (type == NONE || !enabled) return;
|
if (type == NONE || !enabled) return;
|
||||||
drawing = true;
|
drawing = true;
|
||||||
u8x8->setFont(font);
|
u8x8->setFont(font);
|
||||||
@ -220,35 +419,35 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
else u8x8->drawGlyph(col, row, glyph);
|
else u8x8->drawGlyph(col, row, glyph);
|
||||||
drawing = false;
|
drawing = false;
|
||||||
}
|
}
|
||||||
void draw2x2Glyph(uint8_t col, uint8_t row, char glyph, const uint8_t *font) {
|
void FourLineDisplayUsermod::draw2x2Glyph(uint8_t col, uint8_t row, char glyph, const uint8_t *font) {
|
||||||
if (type == NONE || !enabled) return;
|
if (type == NONE || !enabled) return;
|
||||||
drawing = true;
|
drawing = true;
|
||||||
u8x8->setFont(font);
|
u8x8->setFont(font);
|
||||||
u8x8->draw2x2Glyph(col, row, glyph);
|
u8x8->draw2x2Glyph(col, row, glyph);
|
||||||
drawing = false;
|
drawing = false;
|
||||||
}
|
}
|
||||||
uint8_t getCols() {
|
uint8_t FourLineDisplayUsermod::getCols() {
|
||||||
if (type==NONE || !enabled) return 0;
|
if (type==NONE || !enabled) return 0;
|
||||||
return u8x8->getCols();
|
return u8x8->getCols();
|
||||||
}
|
}
|
||||||
void clear() {
|
void FourLineDisplayUsermod::clear() {
|
||||||
if (type == NONE || !enabled) return;
|
if (type == NONE || !enabled) return;
|
||||||
drawing = true;
|
drawing = true;
|
||||||
u8x8->clear();
|
u8x8->clear();
|
||||||
drawing = false;
|
drawing = false;
|
||||||
}
|
}
|
||||||
void setPowerSave(uint8_t save) {
|
void FourLineDisplayUsermod::setPowerSave(uint8_t save) {
|
||||||
if (type == NONE || !enabled) return;
|
if (type == NONE || !enabled) return;
|
||||||
u8x8->setPowerSave(save);
|
u8x8->setPowerSave(save);
|
||||||
}
|
}
|
||||||
|
|
||||||
void center(String &line, uint8_t width) {
|
void FourLineDisplayUsermod::center(String &line, uint8_t width) {
|
||||||
int len = line.length();
|
int len = line.length();
|
||||||
if (len<width) for (byte i=(width-len)/2; i>0; i--) line = ' ' + line;
|
if (len<width) for (byte i=(width-len)/2; i>0; i--) line = ' ' + line;
|
||||||
for (byte i=line.length(); i<width; i++) line += ' ';
|
for (byte i=line.length(); i<width; i++) line += ' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
void draw2x2GlyphIcons() {
|
void FourLineDisplayUsermod::draw2x2GlyphIcons() {
|
||||||
drawing = true;
|
drawing = true;
|
||||||
if (lineHeight == 2) {
|
if (lineHeight == 2) {
|
||||||
drawGlyph( 1, 0, 1, u8x8_4LineDisplay_WLED_icons_2x2, true); //brightness icon
|
drawGlyph( 1, 0, 1, u8x8_4LineDisplay_WLED_icons_2x2, true); //brightness icon
|
||||||
@ -271,7 +470,7 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
* on the middle rows. Based 24 or 12 hour depending on
|
* on the middle rows. Based 24 or 12 hour depending on
|
||||||
* the useAMPM configuration.
|
* the useAMPM configuration.
|
||||||
*/
|
*/
|
||||||
void showTime() {
|
void FourLineDisplayUsermod::showTime() {
|
||||||
if (type == NONE || !enabled || !displayTurnedOff) return;
|
if (type == NONE || !enabled || !displayTurnedOff) return;
|
||||||
|
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
@ -317,7 +516,7 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
/**
|
/**
|
||||||
* Enable sleep (turn the display off) or clock mode.
|
* Enable sleep (turn the display off) or clock mode.
|
||||||
*/
|
*/
|
||||||
void sleepOrClock(bool enabled) {
|
void FourLineDisplayUsermod::sleepOrClock(bool enabled) {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
displayTurnedOff = true;
|
displayTurnedOff = true;
|
||||||
if (clockMode && ntpEnabled) {
|
if (clockMode && ntpEnabled) {
|
||||||
@ -331,143 +530,66 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
// 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 FourLineDisplayUsermod::setup() {
|
||||||
if (type == NONE || !enabled) return;
|
if (type == NONE || !enabled) return;
|
||||||
|
|
||||||
bool isHW, isSPI = (type == SSD1306_SPI || type == SSD1306_SPI64);
|
bool isSPI = (type == SSD1306_SPI || type == SSD1306_SPI64);
|
||||||
PinOwner po = PinOwner::UM_FourLineDisplay;
|
|
||||||
|
// check if pins are -1 and disable usermod as PinManager::allocateMultiplePins() will accept -1 as a valid pin
|
||||||
if (isSPI) {
|
if (isSPI) {
|
||||||
uint8_t hw_sclk = spi_sclk<0 ? HW_PIN_CLOCKSPI : spi_sclk;
|
PinManagerPinType cspins[3] = { { ioPin[0], true }, { ioPin[1], true }, { ioPin[2], true } };
|
||||||
uint8_t hw_mosi = spi_mosi<0 ? HW_PIN_DATASPI : spi_mosi;
|
if (ioPin[0]==-1 || ioPin[1]==-1 || ioPin[1]==-1) { type=NONE; return; }
|
||||||
if (ioPin[0] < 0 || ioPin[1] < 0) {
|
|
||||||
ioPin[0] = hw_sclk;
|
|
||||||
ioPin[1] = hw_mosi;
|
|
||||||
}
|
|
||||||
isHW = (ioPin[0]==hw_sclk && ioPin[1]==hw_mosi);
|
|
||||||
PinManagerPinType cspins[3] = { { ioPin[2], true }, { ioPin[3], true }, { ioPin[4], true } };
|
|
||||||
if (!pinManager.allocateMultiplePins(cspins, 3, PinOwner::UM_FourLineDisplay)) { type=NONE; return; }
|
if (!pinManager.allocateMultiplePins(cspins, 3, PinOwner::UM_FourLineDisplay)) { type=NONE; return; }
|
||||||
if (isHW) po = PinOwner::HW_SPI; // allow multiple allocations of HW I2C bus pins
|
PinManagerPinType pins[2] = { { spi_sclk, true }, { spi_mosi, true } };
|
||||||
PinManagerPinType pins[2] = { { ioPin[0], true }, { ioPin[1], true } };
|
if (spi_sclk==-1 || spi_mosi==-1 || !pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_SPI)) {
|
||||||
if (!pinManager.allocateMultiplePins(pins, 2, po)) {
|
|
||||||
pinManager.deallocateMultiplePins(cspins, 3, PinOwner::UM_FourLineDisplay);
|
pinManager.deallocateMultiplePins(cspins, 3, PinOwner::UM_FourLineDisplay);
|
||||||
type = NONE;
|
type = NONE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
uint8_t hw_scl = i2c_scl<0 ? HW_PIN_SCL : i2c_scl;
|
PinManagerPinType pins[2] = { {i2c_scl, true }, { i2c_sda, true } };
|
||||||
uint8_t hw_sda = i2c_sda<0 ? HW_PIN_SDA : i2c_sda;
|
if (i2c_scl==-1 || i2c_sda==-1 || !pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { type=NONE; return; }
|
||||||
if (ioPin[0] < 0 || ioPin[1] < 0) {
|
|
||||||
ioPin[0] = hw_scl;
|
|
||||||
ioPin[1] = hw_sda;
|
|
||||||
}
|
|
||||||
isHW = (ioPin[0]==hw_scl && ioPin[1]==hw_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."));
|
DEBUG_PRINTLN(F("Allocating display."));
|
||||||
/*
|
|
||||||
// At some point it may be good to not new/delete U8X8 object but use this instead
|
|
||||||
// (does not currently work)
|
|
||||||
//-------------------------------------------------------------------------------
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case SSD1306:
|
// U8X8 uses Wire (or Wire1 with 2ND constructor) and will use existing Wire properties (calls Wire.begin() though)
|
||||||
u8x8_Setup(u8x8.getU8x8(), u8x8_d_ssd1306_128x32_univision, u8x8_cad_ssd13xx_fast_i2c, u8x8_byte_arduino_sw_i2c, u8x8_gpio_and_delay_arduino);
|
case SSD1306: u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_HW_I2C(); break;
|
||||||
break;
|
case SH1106: u8x8 = (U8X8 *) new U8X8_SH1106_128X64_WINSTAR_HW_I2C(); break;
|
||||||
case SH1106:
|
case SSD1306_64: u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_HW_I2C(); break;
|
||||||
u8x8_Setup(u8x8.getU8x8(), u8x8_d_sh1106_128x64_winstar, u8x8_cad_ssd13xx_i2c, u8x8_byte_arduino_sw_i2c, u8x8_gpio_and_delay_arduino);
|
case SSD1305: u8x8 = (U8X8 *) new U8X8_SSD1305_128X32_ADAFRUIT_HW_I2C(); break;
|
||||||
break;
|
case SSD1305_64: u8x8 = (U8X8 *) new U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C(); break;
|
||||||
case SSD1306_64:
|
// U8X8 uses global SPI variable that is attached to VSPI bus on ESP32
|
||||||
u8x8_Setup(u8x8.getU8x8(), u8x8_d_ssd1306_128x64_noname, u8x8_cad_ssd13xx_fast_i2c, u8x8_byte_arduino_sw_i2c, u8x8_gpio_and_delay_arduino);
|
case SSD1306_SPI: u8x8 = (U8X8 *) new U8X8_SSD1306_128X32_UNIVISION_4W_HW_SPI(ioPin[0], ioPin[1], ioPin[2]); break; // Pins are cs, dc, reset
|
||||||
break;
|
case SSD1306_SPI64: u8x8 = (U8X8 *) new U8X8_SSD1306_128X64_NONAME_4W_HW_SPI(ioPin[0], ioPin[1], ioPin[2]); break; // Pins are cs, dc, reset
|
||||||
case SSD1305:
|
// catchall
|
||||||
u8x8_Setup(u8x8.getU8x8(), u8x8_d_ssd1305_128x32_adafruit, u8x8_cad_ssd13xx_i2c, u8x8_byte_arduino_hw_i2c, u8x8_gpio_and_delay_arduino);
|
default: u8x8 = (U8X8 *) new U8X8_NULL(); break;
|
||||||
break;
|
|
||||||
case SSD1305_64:
|
|
||||||
u8x8_Setup(u8x8.getU8x8(), u8x8_d_ssd1305_128x64_adafruit, u8x8_cad_ssd13xx_i2c, u8x8_byte_arduino_sw_i2c, u8x8_gpio_and_delay_arduino);
|
|
||||||
break;
|
|
||||||
case SSD1306_SPI:
|
|
||||||
u8x8_Setup(u8x8.getU8x8(), u8x8_d_ssd1306_128x32_univision, u8x8_cad_001, u8x8_byte_arduino_4wire_sw_spi, u8x8_gpio_and_delay_arduino);
|
|
||||||
break;
|
|
||||||
case SSD1306_SPI64:
|
|
||||||
u8x8_Setup(u8x8.getU8x8(), u8x8_d_ssd1306_128x64_noname, u8x8_cad_001, u8x8_byte_arduino_4wire_sw_spi, u8x8_gpio_and_delay_arduino);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
type = NONE;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (isSPI) {
|
|
||||||
if (!isHW) u8x8_SetPin_4Wire_SW_SPI(u8x8.getU8x8(), ioPin[0], ioPin[1], ioPin[2], ioPin[3], ioPin[4]);
|
|
||||||
else u8x8_SetPin_4Wire_HW_SPI(u8x8.getU8x8(), ioPin[2], ioPin[3], ioPin[4]); // Pins are cs, dc, reset
|
|
||||||
} else {
|
|
||||||
if (!isHW) u8x8_SetPin_SW_I2C(u8x8.getU8x8(), ioPin[0], ioPin[1], U8X8_PIN_NONE); // SCL, SDA, reset
|
|
||||||
else u8x8_SetPin_HW_I2C(u8x8.getU8x8(), U8X8_PIN_NONE, ioPin[0], ioPin[1]); // Pins are Reset, SCL, SDA
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
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
|
|
||||||
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
|
|
||||||
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
|
|
||||||
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
|
|
||||||
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
|
|
||||||
break;
|
|
||||||
case SSD1306_SPI:
|
|
||||||
// u8x8 uses global SPI variable that is attached to VSPI bus on ESP32
|
|
||||||
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
|
|
||||||
break;
|
|
||||||
case SSD1306_SPI64:
|
|
||||||
// u8x8 uses global SPI variable that is attached to VSPI bus on ESP32
|
|
||||||
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
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
u8x8 = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (nullptr == u8x8) {
|
if (nullptr == u8x8) {
|
||||||
DEBUG_PRINTLN(F("Display init failed."));
|
DEBUG_PRINTLN(F("Display init failed."));
|
||||||
pinManager.deallocateMultiplePins((const uint8_t*)ioPin, isSPI ? 5 : 2, po);
|
if (isSPI) {
|
||||||
|
int8_t pins[] = {spi_sclk, spi_mosi};
|
||||||
|
pinManager.deallocateMultiplePins((const uint8_t*)pins, 2, PinOwner::HW_SPI);
|
||||||
|
pinManager.deallocateMultiplePins((const uint8_t*)ioPin, 3, PinOwner::UM_FourLineDisplay);
|
||||||
|
} else {
|
||||||
|
int8_t pins[] = {i2c_scl, i2c_sda};
|
||||||
|
pinManager.deallocateMultiplePins((const uint8_t*)pins, 2, PinOwner::HW_I2C);
|
||||||
|
}
|
||||||
type = NONE;
|
type = NONE;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
lineHeight = u8x8->getRows() > 4 ? 2 : 1;
|
startDisplay();
|
||||||
DEBUG_PRINTLN(F("Starting display."));
|
|
||||||
u8x8->setBusClock(ioFrequency); // can be used for SPI too
|
|
||||||
u8x8->begin();
|
|
||||||
setFlipMode(flip);
|
|
||||||
setVcomh(contrastFix);
|
|
||||||
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...");
|
|
||||||
overlayLogo(3500);
|
|
||||||
onUpdateBegin(false); // create Display task
|
onUpdateBegin(false); // create Display task
|
||||||
initDone = true;
|
initDone = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// gets called every time WiFi is (re-)connected. Initialize own network
|
// gets called every time WiFi is (re-)connected. Initialize own network
|
||||||
// interfaces here
|
// interfaces here
|
||||||
void connected() {
|
void FourLineDisplayUsermod::connected() {
|
||||||
knownSsid = WiFi.SSID(); //apActive ? apSSID : WiFi.SSID(); //apActive ? WiFi.softAPSSID() :
|
knownSsid = WiFi.SSID(); //apActive ? apSSID : WiFi.SSID(); //apActive ? WiFi.softAPSSID() :
|
||||||
knownIp = Network.localIP(); //apActive ? IPAddress(4, 3, 2, 1) : Network.localIP();
|
knownIp = Network.localIP(); //apActive ? IPAddress(4, 3, 2, 1) : Network.localIP();
|
||||||
networkOverlay(PSTR("NETWORK INFO"),7000);
|
networkOverlay(PSTR("NETWORK INFO"),7000);
|
||||||
@ -476,8 +598,8 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
/**
|
/**
|
||||||
* Da loop.
|
* Da loop.
|
||||||
*/
|
*/
|
||||||
void loop() {
|
void FourLineDisplayUsermod::loop() {
|
||||||
#ifndef ARDUINO_ARCH_ESP32
|
#if !(defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS))
|
||||||
if (!enabled || strip.isUpdating()) return;
|
if (!enabled || strip.isUpdating()) return;
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
if (now < nextUpdate) return;
|
if (now < nextUpdate) return;
|
||||||
@ -486,16 +608,11 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
//function to update lastredraw
|
|
||||||
void updateRedrawTime() {
|
|
||||||
lastRedraw = millis();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Redraw the screen (but only if things have changed
|
* Redraw the screen (but only if things have changed
|
||||||
* or if forceRedraw).
|
* or if forceRedraw).
|
||||||
*/
|
*/
|
||||||
void redraw(bool forceRedraw) {
|
void FourLineDisplayUsermod::redraw(bool forceRedraw) {
|
||||||
bool needRedraw = false;
|
bool needRedraw = false;
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
|
|
||||||
@ -607,7 +724,12 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
showCurrentEffectOrPalette(knownMode, JSON_mode_names, 3); //Effect Mode info
|
showCurrentEffectOrPalette(knownMode, JSON_mode_names, 3); //Effect Mode info
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateBrightness() {
|
void FourLineDisplayUsermod::updateBrightness() {
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS)
|
||||||
|
unsigned long now = millis();
|
||||||
|
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
||||||
|
if (drawing || lockRedraw) return;
|
||||||
|
#endif
|
||||||
knownBrightness = bri;
|
knownBrightness = bri;
|
||||||
if (overlayUntil == 0) {
|
if (overlayUntil == 0) {
|
||||||
lockRedraw = true;
|
lockRedraw = true;
|
||||||
@ -619,7 +741,12 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateSpeed() {
|
void FourLineDisplayUsermod::updateSpeed() {
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS)
|
||||||
|
unsigned long now = millis();
|
||||||
|
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
||||||
|
if (drawing || lockRedraw) return;
|
||||||
|
#endif
|
||||||
knownEffectSpeed = effectSpeed;
|
knownEffectSpeed = effectSpeed;
|
||||||
if (overlayUntil == 0) {
|
if (overlayUntil == 0) {
|
||||||
lockRedraw = true;
|
lockRedraw = true;
|
||||||
@ -631,7 +758,12 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateIntensity() {
|
void FourLineDisplayUsermod::updateIntensity() {
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS)
|
||||||
|
unsigned long now = millis();
|
||||||
|
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
||||||
|
if (drawing || lockRedraw) return;
|
||||||
|
#endif
|
||||||
knownEffectIntensity = effectIntensity;
|
knownEffectIntensity = effectIntensity;
|
||||||
if (overlayUntil == 0) {
|
if (overlayUntil == 0) {
|
||||||
lockRedraw = true;
|
lockRedraw = true;
|
||||||
@ -643,7 +775,12 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void drawStatusIcons() {
|
void FourLineDisplayUsermod::drawStatusIcons() {
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS)
|
||||||
|
unsigned long now = millis();
|
||||||
|
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
||||||
|
if (drawing || lockRedraw) return;
|
||||||
|
#endif
|
||||||
uint8_t col = 15;
|
uint8_t col = 15;
|
||||||
uint8_t row = 0;
|
uint8_t row = 0;
|
||||||
lockRedraw = true;
|
lockRedraw = true;
|
||||||
@ -660,13 +797,18 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
* the current setting being changed
|
* the current setting being changed
|
||||||
* pass line and colum info
|
* pass line and colum info
|
||||||
*/
|
*/
|
||||||
void setMarkLine(byte newMarkLineNum, byte newMarkColNum) {
|
void FourLineDisplayUsermod::setMarkLine(byte newMarkLineNum, byte newMarkColNum) {
|
||||||
markLineNum = newMarkLineNum;
|
markLineNum = newMarkLineNum;
|
||||||
markColNum = newMarkColNum;
|
markColNum = newMarkColNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Draw the arrow for the current setting beiong changed
|
//Draw the arrow for the current setting beiong changed
|
||||||
void drawArrow() {
|
void FourLineDisplayUsermod::drawArrow() {
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS)
|
||||||
|
unsigned long now = millis();
|
||||||
|
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
||||||
|
if (drawing || lockRedraw) return;
|
||||||
|
#endif
|
||||||
lockRedraw = true;
|
lockRedraw = true;
|
||||||
if (markColNum != 255 && markLineNum !=255) drawGlyph(markColNum, markLineNum*lineHeight, 21, u8x8_4LineDisplay_WLED_icons_1x1);
|
if (markColNum != 255 && markLineNum !=255) drawGlyph(markColNum, markLineNum*lineHeight, 21, u8x8_4LineDisplay_WLED_icons_1x1);
|
||||||
lockRedraw = false;
|
lockRedraw = false;
|
||||||
@ -674,7 +816,12 @@ 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 FourLineDisplayUsermod::showCurrentEffectOrPalette(int inputEffPal, const char *qstring, uint8_t row) {
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS)
|
||||||
|
unsigned long now = millis();
|
||||||
|
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
||||||
|
if (drawing || lockRedraw) return;
|
||||||
|
#endif
|
||||||
char lineBuffer[MAX_JSON_CHARS];
|
char lineBuffer[MAX_JSON_CHARS];
|
||||||
if (overlayUntil == 0) {
|
if (overlayUntil == 0) {
|
||||||
lockRedraw = true;
|
lockRedraw = true;
|
||||||
@ -740,12 +887,14 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
* the first input from the rotary encoder but
|
* the first input from the rotary encoder but
|
||||||
* to wake up the screen.
|
* to wake up the screen.
|
||||||
*/
|
*/
|
||||||
bool wakeDisplay() {
|
bool FourLineDisplayUsermod::wakeDisplay() {
|
||||||
if (type == NONE || !enabled) return false;
|
if (type == NONE || !enabled) return false;
|
||||||
if (displayTurnedOff) {
|
if (displayTurnedOff) {
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS)
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
while (drawing && millis()-now < 250) delay(1); // wait if someone else is drawing
|
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
||||||
if (drawing) return false;
|
if (drawing || lockRedraw) return false;
|
||||||
|
#endif
|
||||||
lockRedraw = true;
|
lockRedraw = true;
|
||||||
clear();
|
clear();
|
||||||
// Turn the display back on
|
// Turn the display back on
|
||||||
@ -761,10 +910,12 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
* Clears the screen and prints.
|
* Clears the screen and prints.
|
||||||
* Used in Rotary Encoder usermod.
|
* Used in Rotary Encoder usermod.
|
||||||
*/
|
*/
|
||||||
void overlay(const char* line1, long showHowLong, byte glyphType) {
|
void FourLineDisplayUsermod::overlay(const char* line1, long showHowLong, byte glyphType) {
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS)
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
||||||
if (drawing) return;
|
if (drawing || lockRedraw) return;
|
||||||
|
#endif
|
||||||
lockRedraw = true;
|
lockRedraw = true;
|
||||||
// Turn the display back on
|
// Turn the display back on
|
||||||
if (!wakeDisplay()) clear();
|
if (!wakeDisplay()) clear();
|
||||||
@ -786,10 +937,12 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
* Allows you to show Akemi WLED logo overlay for a period of time.
|
* Allows you to show Akemi WLED logo overlay for a period of time.
|
||||||
* Clears the screen and prints.
|
* Clears the screen and prints.
|
||||||
*/
|
*/
|
||||||
void overlayLogo(long showHowLong) {
|
void FourLineDisplayUsermod::overlayLogo(long showHowLong) {
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS)
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
||||||
if (drawing) return;
|
if (drawing || lockRedraw) return;
|
||||||
|
#endif
|
||||||
lockRedraw = true;
|
lockRedraw = true;
|
||||||
// Turn the display back on
|
// Turn the display back on
|
||||||
if (!wakeDisplay()) clear();
|
if (!wakeDisplay()) clear();
|
||||||
@ -848,10 +1001,12 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
* Clears the screen and prints.
|
* Clears the screen and prints.
|
||||||
* Used in Auto Save usermod
|
* Used in Auto Save usermod
|
||||||
*/
|
*/
|
||||||
void overlay(const char* line1, const char* line2, long showHowLong) {
|
void FourLineDisplayUsermod::overlay(const char* line1, const char* line2, long showHowLong) {
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS)
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
||||||
if (drawing) return;
|
if (drawing || lockRedraw) return;
|
||||||
|
#endif
|
||||||
lockRedraw = true;
|
lockRedraw = true;
|
||||||
// Turn the display back on
|
// Turn the display back on
|
||||||
if (!wakeDisplay()) clear();
|
if (!wakeDisplay()) clear();
|
||||||
@ -870,10 +1025,12 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
lockRedraw = false;
|
lockRedraw = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void networkOverlay(const char* line1, long showHowLong) {
|
void FourLineDisplayUsermod::networkOverlay(const char* line1, long showHowLong) {
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS)
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
while (drawing && millis()-now < 125) delay(1); // wait if someone else is drawing
|
||||||
if (drawing) return;
|
if (drawing || lockRedraw) return;
|
||||||
|
#endif
|
||||||
lockRedraw = true;
|
lockRedraw = true;
|
||||||
|
|
||||||
String line;
|
String line;
|
||||||
@ -915,7 +1072,7 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
* will prevent button working in a default way.
|
* will prevent button working in a default way.
|
||||||
* Replicating button.cpp
|
* Replicating button.cpp
|
||||||
*/
|
*/
|
||||||
bool handleButton(uint8_t b) {
|
bool FourLineDisplayUsermod::handleButton(uint8_t b) {
|
||||||
yield();
|
yield();
|
||||||
if (!enabled
|
if (!enabled
|
||||||
|| b // butto 0 only
|
|| b // butto 0 only
|
||||||
@ -989,8 +1146,8 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
#else
|
#else
|
||||||
#define ARDUINO_RUNNING_CORE 1
|
#define ARDUINO_RUNNING_CORE 1
|
||||||
#endif
|
#endif
|
||||||
void onUpdateBegin(bool init) {
|
void FourLineDisplayUsermod::onUpdateBegin(bool init) {
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
#if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS)
|
||||||
if (init && Display_Task) {
|
if (init && Display_Task) {
|
||||||
vTaskSuspend(Display_Task); // update is about to begin, disable task to prevent crash
|
vTaskSuspend(Display_Task); // update is about to begin, disable task to prevent crash
|
||||||
} else {
|
} else {
|
||||||
@ -1026,7 +1183,7 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
* Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI.
|
* 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
|
* Below it is shown how this could be used for e.g. a light sensor
|
||||||
*/
|
*/
|
||||||
//void addToJsonInfo(JsonObject& root) {
|
//void FourLineDisplayUsermod::addToJsonInfo(JsonObject& root) {
|
||||||
//JsonObject user = root["u"];
|
//JsonObject user = root["u"];
|
||||||
//if (user.isNull()) user = root.createNestedObject("u");
|
//if (user.isNull()) user = root.createNestedObject("u");
|
||||||
//JsonArray data = user.createNestedArray(F("4LineDisplay"));
|
//JsonArray data = user.createNestedArray(F("4LineDisplay"));
|
||||||
@ -1037,18 +1194,18 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
|
* 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
|
* Values in the state object may be modified by connected clients
|
||||||
*/
|
*/
|
||||||
//void addToJsonState(JsonObject& root) {
|
//void FourLineDisplayUsermod::addToJsonState(JsonObject& root) {
|
||||||
//}
|
//}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
|
* 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
|
* Values in the state object may be modified by connected clients
|
||||||
*/
|
*/
|
||||||
//void readFromJsonState(JsonObject& root) {
|
//void FourLineDisplayUsermod::readFromJsonState(JsonObject& root) {
|
||||||
// if (!initDone) return; // prevent crash on boot applyPreset()
|
// if (!initDone) return; // prevent crash on boot applyPreset()
|
||||||
//}
|
//}
|
||||||
|
|
||||||
void appendConfigData() {
|
void FourLineDisplayUsermod::appendConfigData() {
|
||||||
oappend(SET_F("dd=addDropdown('4LineDisplay','type');"));
|
oappend(SET_F("dd=addDropdown('4LineDisplay','type');"));
|
||||||
oappend(SET_F("addOption(dd,'None',0);"));
|
oappend(SET_F("addOption(dd,'None',0);"));
|
||||||
oappend(SET_F("addOption(dd,'SSD1306',1);"));
|
oappend(SET_F("addOption(dd,'SSD1306',1);"));
|
||||||
@ -1058,11 +1215,10 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
oappend(SET_F("addOption(dd,'SSD1305 128x64',5);"));
|
oappend(SET_F("addOption(dd,'SSD1305 128x64',5);"));
|
||||||
oappend(SET_F("addOption(dd,'SSD1306 SPI',6);"));
|
oappend(SET_F("addOption(dd,'SSD1306 SPI',6);"));
|
||||||
oappend(SET_F("addOption(dd,'SSD1306 SPI 128x64',7);"));
|
oappend(SET_F("addOption(dd,'SSD1306 SPI 128x64',7);"));
|
||||||
oappend(SET_F("addInfo('4LineDisplay:pin[]',0,'<i>-1 use global</i>','I2C/SPI CLK');"));
|
oappend(SET_F("addInfo('4LineDisplay:type',1,'<br><i class=\"warn\">Change may require reboot</i>','');"));
|
||||||
oappend(SET_F("addInfo('4LineDisplay:pin[]',1,'<i>-1 use global</i>','I2C/SPI DTA');"));
|
oappend(SET_F("addInfo('4LineDisplay:pin[]',0,'','SPI CS');"));
|
||||||
oappend(SET_F("addInfo('4LineDisplay:pin[]',2,'','SPI CS');"));
|
oappend(SET_F("addInfo('4LineDisplay:pin[]',1,'','SPI DC');"));
|
||||||
oappend(SET_F("addInfo('4LineDisplay:pin[]',3,'','SPI DC');"));
|
oappend(SET_F("addInfo('4LineDisplay:pin[]',2,'','SPI RST');"));
|
||||||
oappend(SET_F("addInfo('4LineDisplay:pin[]',4,'','SPI RST');"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1079,27 +1235,13 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
*
|
*
|
||||||
* I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings!
|
* I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings!
|
||||||
*/
|
*/
|
||||||
void addToConfig(JsonObject& root) {
|
void FourLineDisplayUsermod::addToConfig(JsonObject& root) {
|
||||||
// determine if we are using global HW pins (data & clock)
|
|
||||||
int8_t hw_dta, hw_clk;
|
|
||||||
if ((type == SSD1306_SPI || type == SSD1306_SPI64)) {
|
|
||||||
hw_clk = spi_sclk<0 ? HW_PIN_CLOCKSPI : spi_sclk;
|
|
||||||
hw_dta = spi_mosi<0 ? HW_PIN_DATASPI : spi_mosi;
|
|
||||||
} else {
|
|
||||||
hw_clk = i2c_scl<0 ? HW_PIN_SCL : i2c_scl;
|
|
||||||
hw_dta = i2c_sda<0 ? HW_PIN_SDA : i2c_sda;
|
|
||||||
}
|
|
||||||
|
|
||||||
JsonObject top = root.createNestedObject(FPSTR(_name));
|
JsonObject top = root.createNestedObject(FPSTR(_name));
|
||||||
top[FPSTR(_enabled)] = enabled;
|
top[FPSTR(_enabled)] = enabled;
|
||||||
|
|
||||||
JsonArray io_pin = top.createNestedArray("pin");
|
|
||||||
for (int i=0; i<5; i++) {
|
|
||||||
if (i==0 && ioPin[i]==hw_clk) io_pin.add(-1); // do not store global HW pin
|
|
||||||
else if (i==1 && ioPin[i]==hw_dta) io_pin.add(-1); // do not store global HW pin
|
|
||||||
else io_pin.add(ioPin[i]);
|
|
||||||
}
|
|
||||||
top["type"] = type;
|
top["type"] = type;
|
||||||
|
JsonArray io_pin = top.createNestedArray("pin");
|
||||||
|
for (int i=0; i<3; i++) io_pin.add(ioPin[i]);
|
||||||
top[FPSTR(_flip)] = (bool) flip;
|
top[FPSTR(_flip)] = (bool) flip;
|
||||||
top[FPSTR(_contrast)] = contrast;
|
top[FPSTR(_contrast)] = contrast;
|
||||||
top[FPSTR(_contrastFix)] = (bool) contrastFix;
|
top[FPSTR(_contrastFix)] = (bool) contrastFix;
|
||||||
@ -1122,10 +1264,10 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
* 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.
|
* 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 :)
|
* 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 FourLineDisplayUsermod::readFromConfig(JsonObject& root) {
|
||||||
bool needsRedraw = false;
|
bool needsRedraw = false;
|
||||||
DisplayType newType = type;
|
DisplayType newType = type;
|
||||||
int8_t oldPin[5]; for (byte i=0; i<5; i++) oldPin[i] = ioPin[i];
|
int8_t oldPin[3]; for (byte i=0; i<3; i++) oldPin[i] = ioPin[i];
|
||||||
|
|
||||||
JsonObject top = root[FPSTR(_name)];
|
JsonObject top = root[FPSTR(_name)];
|
||||||
if (top.isNull()) {
|
if (top.isNull()) {
|
||||||
@ -1136,7 +1278,7 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
|
|
||||||
enabled = top[FPSTR(_enabled)] | enabled;
|
enabled = top[FPSTR(_enabled)] | enabled;
|
||||||
newType = top["type"] | newType;
|
newType = top["type"] | newType;
|
||||||
for (byte i=0; i<5; i++) ioPin[i] = top["pin"][i] | ioPin[i];
|
for (byte i=0; i<3; i++) ioPin[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;
|
||||||
#ifndef ARDUINO_ARCH_ESP32
|
#ifndef ARDUINO_ARCH_ESP32
|
||||||
@ -1162,26 +1304,76 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
DEBUG_PRINTLN(F(" config (re)loaded."));
|
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||||
// changing parameters from settings page
|
// changing parameters from settings page
|
||||||
bool pinsChanged = false;
|
bool pinsChanged = false;
|
||||||
for (byte i=0; i<5; i++) if (ioPin[i] != oldPin[i]) { pinsChanged = true; break; }
|
for (byte i=0; i<3; i++) if (ioPin[i] != oldPin[i]) { pinsChanged = true; break; }
|
||||||
if (pinsChanged || type!=newType) {
|
if (pinsChanged || type!=newType) {
|
||||||
if (type != NONE) delete u8x8;
|
|
||||||
PinOwner po = PinOwner::UM_FourLineDisplay;
|
|
||||||
bool isSPI = (type == SSD1306_SPI || type == SSD1306_SPI64);
|
bool isSPI = (type == SSD1306_SPI || type == SSD1306_SPI64);
|
||||||
|
bool newSPI = (newType == SSD1306_SPI || newType == SSD1306_SPI64);
|
||||||
if (isSPI) {
|
if (isSPI) {
|
||||||
pinManager.deallocateMultiplePins((const uint8_t *)(&oldPin[2]), 3, po);
|
if (pinsChanged || !newSPI) pinManager.deallocateMultiplePins((const uint8_t*)oldPin, 3, PinOwner::UM_FourLineDisplay);
|
||||||
uint8_t hw_sclk = spi_sclk<0 ? HW_PIN_CLOCKSPI : spi_sclk;
|
if (!newSPI) {
|
||||||
uint8_t hw_mosi = spi_mosi<0 ? HW_PIN_DATASPI : spi_mosi;
|
// was SPI but is no longer SPI
|
||||||
bool isHW = (oldPin[0]==hw_sclk && oldPin[1]==hw_mosi);
|
int8_t oldPins[] = {spi_sclk, spi_mosi};
|
||||||
if (isHW) po = PinOwner::HW_SPI;
|
pinManager.deallocateMultiplePins((const uint8_t*)oldPins, 2, PinOwner::HW_SPI);
|
||||||
|
PinManagerPinType pins[2] = { {i2c_scl, true }, { i2c_sda, true } };
|
||||||
|
if (i2c_scl==-1 || i2c_sda==-1 || !pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_I2C)) { newType=NONE; }
|
||||||
} else {
|
} else {
|
||||||
uint8_t hw_scl = i2c_scl<0 ? HW_PIN_SCL : i2c_scl;
|
// still SPI but pins changed
|
||||||
uint8_t hw_sda = i2c_sda<0 ? HW_PIN_SDA : i2c_sda;
|
PinManagerPinType cspins[3] = { { ioPin[0], true }, { ioPin[1], true }, { ioPin[2], true } };
|
||||||
bool isHW = (oldPin[0]==hw_scl && oldPin[1]==hw_sda);
|
if (ioPin[0]==-1 || ioPin[1]==-1 || ioPin[1]==-1) { newType=NONE; }
|
||||||
if (isHW) po = PinOwner::HW_I2C;
|
else if (!pinManager.allocateMultiplePins(cspins, 3, PinOwner::UM_FourLineDisplay)) { newType=NONE; }
|
||||||
|
}
|
||||||
|
} else if (newSPI) {
|
||||||
|
// was I2C but is now SPI
|
||||||
|
int8_t oldPins[] = {i2c_scl, i2c_sda};
|
||||||
|
pinManager.deallocateMultiplePins((const uint8_t*)oldPins, 2, PinOwner::HW_I2C);
|
||||||
|
PinManagerPinType pins[3] = { { ioPin[0], true }, { ioPin[1], true }, { ioPin[2], true } };
|
||||||
|
if (ioPin[0]==-1 || ioPin[1]==-1 || ioPin[1]==-1) { newType=NONE; }
|
||||||
|
else if (!pinManager.allocateMultiplePins(pins, 3, PinOwner::UM_FourLineDisplay)) { newType=NONE; }
|
||||||
|
else {
|
||||||
|
PinManagerPinType pins[2] = { { spi_sclk, true }, { spi_mosi, true } };
|
||||||
|
if (spi_sclk==-1 || spi_mosi==-1 || !pinManager.allocateMultiplePins(pins, 2, PinOwner::HW_SPI)) {
|
||||||
|
pinManager.deallocateMultiplePins(pins, 3, PinOwner::UM_FourLineDisplay);
|
||||||
|
newType = NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// just I2C tye changed
|
||||||
}
|
}
|
||||||
pinManager.deallocateMultiplePins((const uint8_t *)oldPin, 2, po);
|
|
||||||
type = newType;
|
type = newType;
|
||||||
setup();
|
switch (type) {
|
||||||
|
case SSD1306:
|
||||||
|
u8x8_Setup(u8x8->getU8x8(), u8x8_d_ssd1306_128x32_univision, u8x8_cad_ssd13xx_fast_i2c, u8x8_byte_arduino_hw_i2c, u8x8_gpio_and_delay_arduino);
|
||||||
|
u8x8_SetPin_HW_I2C(u8x8->getU8x8(), U8X8_PIN_NONE, U8X8_PIN_NONE, U8X8_PIN_NONE);
|
||||||
|
break;
|
||||||
|
case SH1106:
|
||||||
|
u8x8_Setup(u8x8->getU8x8(), u8x8_d_sh1106_128x64_winstar, u8x8_cad_ssd13xx_fast_i2c, u8x8_byte_arduino_hw_i2c, u8x8_gpio_and_delay_arduino);
|
||||||
|
u8x8_SetPin_HW_I2C(u8x8->getU8x8(), U8X8_PIN_NONE, U8X8_PIN_NONE, U8X8_PIN_NONE);
|
||||||
|
break;
|
||||||
|
case SSD1306_64:
|
||||||
|
u8x8_Setup(u8x8->getU8x8(), u8x8_d_ssd1306_128x64_noname, u8x8_cad_ssd13xx_fast_i2c, u8x8_byte_arduino_hw_i2c, u8x8_gpio_and_delay_arduino);
|
||||||
|
u8x8_SetPin_HW_I2C(u8x8->getU8x8(), U8X8_PIN_NONE, U8X8_PIN_NONE, U8X8_PIN_NONE);
|
||||||
|
break;
|
||||||
|
case SSD1305:
|
||||||
|
u8x8_Setup(u8x8->getU8x8(), u8x8_d_ssd1305_128x32_adafruit, u8x8_cad_ssd13xx_fast_i2c, u8x8_byte_arduino_hw_i2c, u8x8_gpio_and_delay_arduino);
|
||||||
|
u8x8_SetPin_HW_I2C(u8x8->getU8x8(), U8X8_PIN_NONE, U8X8_PIN_NONE, U8X8_PIN_NONE);
|
||||||
|
break;
|
||||||
|
case SSD1305_64:
|
||||||
|
u8x8_Setup(u8x8->getU8x8(), u8x8_d_ssd1305_128x64_adafruit, u8x8_cad_ssd13xx_fast_i2c, u8x8_byte_arduino_hw_i2c, u8x8_gpio_and_delay_arduino);
|
||||||
|
u8x8_SetPin_HW_I2C(u8x8->getU8x8(), U8X8_PIN_NONE, U8X8_PIN_NONE, U8X8_PIN_NONE);
|
||||||
|
break;
|
||||||
|
case SSD1306_SPI:
|
||||||
|
u8x8_Setup(u8x8->getU8x8(), u8x8_d_ssd1306_128x32_univision, u8x8_cad_001, u8x8_byte_arduino_hw_spi, u8x8_gpio_and_delay_arduino);
|
||||||
|
u8x8_SetPin_4Wire_HW_SPI(u8x8->getU8x8(), ioPin[0], ioPin[1], ioPin[2]); // Pins are cs, dc, reset
|
||||||
|
break;
|
||||||
|
case SSD1306_SPI64:
|
||||||
|
u8x8_Setup(u8x8->getU8x8(), u8x8_d_ssd1306_128x64_noname, u8x8_cad_001, u8x8_byte_arduino_hw_spi, u8x8_gpio_and_delay_arduino);
|
||||||
|
u8x8_SetPin_4Wire_HW_SPI(u8x8->getU8x8(), ioPin[0], ioPin[1], ioPin[2]); // Pins are cs, dc, reset
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
u8x8_Setup(u8x8->getU8x8(), u8x8_d_null_cb, u8x8_cad_empty, u8x8_byte_empty, u8x8_dummy_cb);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
startDisplay();
|
||||||
needsRedraw |= true;
|
needsRedraw |= true;
|
||||||
} else {
|
} else {
|
||||||
u8x8->setBusClock(ioFrequency); // can be used for SPI too
|
u8x8->setBusClock(ioFrequency); // can be used for SPI too
|
||||||
@ -1196,27 +1388,3 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||||
return !top[FPSTR(_contrastFix)].isNull();
|
return !top[FPSTR(_contrastFix)].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 = "refreshRate-ms";
|
|
||||||
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::_showSeconds[] PROGMEM = "showSeconds";
|
|
||||||
const char FourLineDisplayUsermod::_busClkFrequency[] PROGMEM = "i2c-freq-kHz";
|
|
||||||
const char FourLineDisplayUsermod::_contrastFix[] PROGMEM = "contrastFix";
|
|
||||||
|
|
||||||
FourLineDisplayUsermod *FourLineDisplayUsermod::instance = nullptr;
|
|
||||||
|
@ -45,7 +45,23 @@
|
|||||||
#define ENCODER_SW_PIN 19
|
#define ENCODER_SW_PIN 19
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// The last UI state, remove color and saturation option if diplay not active(too many options)
|
#ifndef USERMOD_USE_PCF8574
|
||||||
|
#undef USE_PCF8574
|
||||||
|
#define USE_PCF8574 false
|
||||||
|
#else
|
||||||
|
#undef USE_PCF8574
|
||||||
|
#define USE_PCF8574 true
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PCF8574_ADDRESS
|
||||||
|
#define PCF8574_ADDRESS 0x20 // some may start at 0x38
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef PCF8574_INT_PIN
|
||||||
|
#define PCF8574_INT_PIN -1 // GPIO connected to INT pin on PCF8574
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// The last UI state, remove color and saturation option if display not active (too many options)
|
||||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||||
#define LAST_UI_STATE 11
|
#define LAST_UI_STATE 11
|
||||||
#else
|
#else
|
||||||
@ -113,62 +129,83 @@ static int re_qstringCmp(const void *ap, const void *bp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static volatile uint8_t pcfPortData = 0; // port expander port state
|
||||||
|
static volatile uint8_t addrPcf8574 = PCF8574_ADDRESS; // has to be accessible in ISR
|
||||||
|
|
||||||
|
// Interrupt routine to read I2C rotary state
|
||||||
|
// if we are to use PCF8574 port expander we will need to rely on interrupts as polling I2C every 2ms
|
||||||
|
// is a waste of resources and causes 4LD to fail.
|
||||||
|
// in such case rely on ISR to read pin values and store them into static variable
|
||||||
|
static void IRAM_ATTR i2cReadingISR() {
|
||||||
|
Wire.requestFrom(addrPcf8574, 1U);
|
||||||
|
if (Wire.available()) {
|
||||||
|
pcfPortData = Wire.read();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
class RotaryEncoderUIUsermod : public Usermod {
|
class RotaryEncoderUIUsermod : public Usermod {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int8_t fadeAmount = 5; // Amount to change every step (brightness)
|
|
||||||
|
const int8_t fadeAmount; // Amount to change every step (brightness)
|
||||||
unsigned long loopTime;
|
unsigned long loopTime;
|
||||||
|
|
||||||
unsigned long buttonPressedTime = 0;
|
unsigned long buttonPressedTime;
|
||||||
unsigned long buttonWaitTime = 0;
|
unsigned long buttonWaitTime;
|
||||||
bool buttonPressedBefore = false;
|
bool buttonPressedBefore;
|
||||||
bool buttonLongPressed = false;
|
bool buttonLongPressed;
|
||||||
|
|
||||||
int8_t pinA = ENCODER_DT_PIN; // DT from encoder
|
int8_t pinA; // DT from encoder
|
||||||
int8_t pinB = ENCODER_CLK_PIN; // CLK from encoder
|
int8_t pinB; // CLK from encoder
|
||||||
int8_t pinC = ENCODER_SW_PIN; // SW from encoder
|
int8_t pinC; // SW from encoder
|
||||||
|
|
||||||
unsigned char select_state = 0; // 0: brightness, 1: effect, 2: effect speed, ...
|
unsigned char select_state; // 0: brightness, 1: effect, 2: effect speed, ...
|
||||||
|
|
||||||
uint16_t currentHue1 = 16; // default boot color
|
uint16_t currentHue1; // default boot color
|
||||||
byte currentSat1 = 255;
|
byte currentSat1;
|
||||||
|
uint8_t currentCCT;
|
||||||
|
|
||||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||||
FourLineDisplayUsermod *display;
|
FourLineDisplayUsermod *display;
|
||||||
#else
|
#else
|
||||||
void* display = nullptr;
|
void* display;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Pointers the start of the mode names within JSON_mode_names
|
// Pointers the start of the mode names within JSON_mode_names
|
||||||
const char **modes_qstrings = nullptr;
|
const char **modes_qstrings;
|
||||||
|
|
||||||
// Array of mode indexes in alphabetical order.
|
// Array of mode indexes in alphabetical order.
|
||||||
byte *modes_alpha_indexes = nullptr;
|
byte *modes_alpha_indexes;
|
||||||
|
|
||||||
// Pointers the start of the palette names within JSON_palette_names
|
// Pointers the start of the palette names within JSON_palette_names
|
||||||
const char **palettes_qstrings = nullptr;
|
const char **palettes_qstrings;
|
||||||
|
|
||||||
// Array of palette indexes in alphabetical order.
|
// Array of palette indexes in alphabetical order.
|
||||||
byte *palettes_alpha_indexes = nullptr;
|
byte *palettes_alpha_indexes;
|
||||||
|
|
||||||
unsigned char Enc_A;
|
struct { // reduce memory footprint
|
||||||
unsigned char Enc_B;
|
bool Enc_A : 1;
|
||||||
unsigned char Enc_A_prev = 0;
|
bool Enc_B : 1;
|
||||||
|
bool Enc_A_prev : 1;
|
||||||
|
};
|
||||||
|
|
||||||
bool currentEffectAndPaletteInitialized = false;
|
bool currentEffectAndPaletteInitialized;
|
||||||
uint8_t effectCurrentIndex = 0;
|
uint8_t effectCurrentIndex;
|
||||||
uint8_t effectPaletteIndex = 0;
|
uint8_t effectPaletteIndex;
|
||||||
uint8_t knownMode = 0;
|
uint8_t knownMode;
|
||||||
uint8_t knownPalette = 0;
|
uint8_t knownPalette;
|
||||||
|
|
||||||
uint8_t currentCCT = 128;
|
byte presetHigh;
|
||||||
|
byte presetLow;
|
||||||
|
|
||||||
byte presetHigh = 0;
|
bool applyToAll;
|
||||||
byte presetLow = 0;
|
|
||||||
|
|
||||||
bool applyToAll = true;
|
bool initDone;
|
||||||
|
bool enabled;
|
||||||
|
|
||||||
bool initDone = false;
|
bool usePcf8574;
|
||||||
bool enabled = true;
|
int8_t pinIRQ;
|
||||||
|
|
||||||
// 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[];
|
||||||
@ -179,12 +216,178 @@ private:
|
|||||||
static const char _presetHigh[];
|
static const char _presetHigh[];
|
||||||
static const char _presetLow[];
|
static const char _presetLow[];
|
||||||
static const char _applyToAll[];
|
static const char _applyToAll[];
|
||||||
|
static const char _pcf8574[];
|
||||||
|
static const char _pcfAddress[];
|
||||||
|
static const char _pcfINTpin[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* readPin() - read rotary encoder pin value
|
||||||
|
*/
|
||||||
|
byte readPin(uint8_t pin);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sort the modes and palettes to the index arrays
|
* Sort the modes and palettes to the index arrays
|
||||||
* modes_alpha_indexes and palettes_alpha_indexes.
|
* modes_alpha_indexes and palettes_alpha_indexes.
|
||||||
*/
|
*/
|
||||||
void sortModesAndPalettes() {
|
void sortModesAndPalettes();
|
||||||
|
byte *re_initIndexArray(int numModes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return an array of mode or palette names from the JSON string.
|
||||||
|
* They don't end in '\0', they end in '"'.
|
||||||
|
*/
|
||||||
|
const char **re_findModeStrings(const char json[], int numModes);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort either the modes or the palettes using quicksort.
|
||||||
|
*/
|
||||||
|
void re_sortModes(const char **modeNames, byte *indexes, int count, int numSkip);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
RotaryEncoderUIUsermod()
|
||||||
|
: fadeAmount(5)
|
||||||
|
, buttonPressedTime(0)
|
||||||
|
, buttonWaitTime(0)
|
||||||
|
, buttonPressedBefore(false)
|
||||||
|
, buttonLongPressed(false)
|
||||||
|
, pinA(ENCODER_DT_PIN)
|
||||||
|
, pinB(ENCODER_CLK_PIN)
|
||||||
|
, pinC(ENCODER_SW_PIN)
|
||||||
|
, select_state(0)
|
||||||
|
, currentHue1(16)
|
||||||
|
, currentSat1(255)
|
||||||
|
, currentCCT(128)
|
||||||
|
, display(nullptr)
|
||||||
|
, modes_qstrings(nullptr)
|
||||||
|
, modes_alpha_indexes(nullptr)
|
||||||
|
, palettes_qstrings(nullptr)
|
||||||
|
, palettes_alpha_indexes(nullptr)
|
||||||
|
, currentEffectAndPaletteInitialized(false)
|
||||||
|
, effectCurrentIndex(0)
|
||||||
|
, effectPaletteIndex(0)
|
||||||
|
, knownMode(0)
|
||||||
|
, knownPalette(0)
|
||||||
|
, presetHigh(0)
|
||||||
|
, presetLow(0)
|
||||||
|
, applyToAll(true)
|
||||||
|
, initDone(false)
|
||||||
|
, enabled(true)
|
||||||
|
, usePcf8574(USE_PCF8574)
|
||||||
|
, pinIRQ(PCF8574_INT_PIN)
|
||||||
|
{}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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; }
|
||||||
|
/**
|
||||||
|
* Enable/Disable the usermod
|
||||||
|
*/
|
||||||
|
inline void enable(bool enable) { if (!(pinA<0 || pinB<0 || pinC<0)) enabled = enable; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get usermod enabled/disabled state
|
||||||
|
*/
|
||||||
|
inline bool isEnabled() { return enabled; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* connected() is called every time the WiFi is (re)connected
|
||||||
|
* Use it to initialize network interfaces
|
||||||
|
*/
|
||||||
|
//void connected();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* loop() is called continuously. Here you can check for events, read sensors, etc.
|
||||||
|
*/
|
||||||
|
void loop();
|
||||||
|
|
||||||
|
#ifndef WLED_DISABLE_MQTT
|
||||||
|
//bool onMqttMessage(char* topic, char* payload);
|
||||||
|
//void onMqttConnect(bool sessionPresent);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* handleButton() can be used to override default button behaviour. Returning true
|
||||||
|
* will prevent button working in a default way.
|
||||||
|
* Replicating button.cpp
|
||||||
|
*/
|
||||||
|
//bool handleButton(uint8_t b);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
|
||||||
|
*/
|
||||||
|
//void addToJsonInfo(JsonObject &root);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* provide the changeable values
|
||||||
|
*/
|
||||||
|
void addToConfig(JsonObject &root);
|
||||||
|
|
||||||
|
//void appendConfigData();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* restore the changeable values
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
// custom methods
|
||||||
|
void displayNetworkInfo();
|
||||||
|
void findCurrentEffectAndPalette();
|
||||||
|
bool changeState(const char *stateName, byte markedLine, byte markedCol, byte glyph);
|
||||||
|
void lampUdated();
|
||||||
|
void changeBrightness(bool increase);
|
||||||
|
void changeEffect(bool increase);
|
||||||
|
void changeEffectSpeed(bool increase);
|
||||||
|
void changeEffectIntensity(bool increase);
|
||||||
|
void changeCustom(uint8_t par, bool increase);
|
||||||
|
void changePalette(bool increase);
|
||||||
|
void changeHue(bool increase);
|
||||||
|
void changeSat(bool increase);
|
||||||
|
void changePreset(bool increase);
|
||||||
|
void changeCCT(bool increase);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* readPin() - read rotary encoder pin value
|
||||||
|
*/
|
||||||
|
byte RotaryEncoderUIUsermod::readPin(uint8_t pin) {
|
||||||
|
if (usePcf8574) {
|
||||||
|
return (pcfPortData>>pin) & 1;
|
||||||
|
} else {
|
||||||
|
return digitalRead(pin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sort the modes and palettes to the index arrays
|
||||||
|
* modes_alpha_indexes and palettes_alpha_indexes.
|
||||||
|
*/
|
||||||
|
void RotaryEncoderUIUsermod::sortModesAndPalettes() {
|
||||||
|
DEBUG_PRINTLN(F("Sorting modes and palettes."));
|
||||||
//modes_qstrings = re_findModeStrings(JSON_mode_names, strip.getModeCount());
|
//modes_qstrings = re_findModeStrings(JSON_mode_names, strip.getModeCount());
|
||||||
modes_qstrings = strip.getModeDataSrc();
|
modes_qstrings = strip.getModeDataSrc();
|
||||||
modes_alpha_indexes = re_initIndexArray(strip.getModeCount());
|
modes_alpha_indexes = re_initIndexArray(strip.getModeCount());
|
||||||
@ -200,7 +403,7 @@ private:
|
|||||||
re_sortModes(palettes_qstrings, palettes_alpha_indexes, strip.getPaletteCount(), skipPaletteCount);
|
re_sortModes(palettes_qstrings, palettes_alpha_indexes, strip.getPaletteCount(), skipPaletteCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
byte *re_initIndexArray(int numModes) {
|
byte *RotaryEncoderUIUsermod::re_initIndexArray(int numModes) {
|
||||||
byte *indexes = (byte *)malloc(sizeof(byte) * numModes);
|
byte *indexes = (byte *)malloc(sizeof(byte) * numModes);
|
||||||
for (byte i = 0; i < numModes; i++) {
|
for (byte i = 0; i < numModes; i++) {
|
||||||
indexes[i] = i;
|
indexes[i] = i;
|
||||||
@ -212,7 +415,7 @@ private:
|
|||||||
* Return an array of mode or palette names from the JSON string.
|
* Return an array of mode or palette names from the JSON string.
|
||||||
* They don't end in '\0', they end in '"'.
|
* They don't end in '\0', they end in '"'.
|
||||||
*/
|
*/
|
||||||
const char **re_findModeStrings(const char json[], int numModes) {
|
const char **RotaryEncoderUIUsermod::re_findModeStrings(const char json[], int numModes) {
|
||||||
const char **modeStrings = (const char **)malloc(sizeof(const char *) * numModes);
|
const char **modeStrings = (const char **)malloc(sizeof(const char *) * numModes);
|
||||||
uint8_t modeIndex = 0;
|
uint8_t modeIndex = 0;
|
||||||
bool insideQuotes = false;
|
bool insideQuotes = false;
|
||||||
@ -250,7 +453,7 @@ private:
|
|||||||
/**
|
/**
|
||||||
* Sort either the modes or the palettes using quicksort.
|
* Sort either the modes or the palettes using quicksort.
|
||||||
*/
|
*/
|
||||||
void re_sortModes(const char **modeNames, byte *indexes, int count, int numSkip) {
|
void RotaryEncoderUIUsermod::re_sortModes(const char **modeNames, byte *indexes, int count, int numSkip) {
|
||||||
if (!modeNames) return;
|
if (!modeNames) return;
|
||||||
listBeingSorted = modeNames;
|
listBeingSorted = modeNames;
|
||||||
qsort(indexes + numSkip, count - numSkip, sizeof(byte), re_qstringCmp);
|
qsort(indexes + numSkip, count - numSkip, sizeof(byte), re_qstringCmp);
|
||||||
@ -258,21 +461,37 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public:
|
// public methods
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* setup() is called once at boot. WiFi is not yet connected at this point.
|
* setup() is called once at boot. WiFi is not yet connected at this point.
|
||||||
* You can use it to initialize variables, sensors or similar.
|
* You can use it to initialize variables, sensors or similar.
|
||||||
*/
|
*/
|
||||||
void setup()
|
void RotaryEncoderUIUsermod::setup()
|
||||||
{
|
{
|
||||||
DEBUG_PRINTLN(F("Usermod Rotary Encoder init."));
|
DEBUG_PRINTLN(F("Usermod Rotary Encoder init."));
|
||||||
|
|
||||||
|
if (usePcf8574) {
|
||||||
|
if ((i2c_sda == i2c_scl && i2c_sda == -1) || pinA<0 || pinB<0 || pinC<0) {
|
||||||
|
DEBUG_PRINTLN(F("I2C and/or PCF8574 pins unused, disabling."));
|
||||||
|
enabled = false;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
if (pinIRQ >= 0 && pinManager.allocatePin(pinIRQ, false, PinOwner::UM_RotaryEncoderUI)) {
|
||||||
|
pinMode(pinIRQ, INPUT_PULLUP);
|
||||||
|
attachInterrupt(pinIRQ, i2cReadingISR, FALLING); // RISING, FALLING, CHANGE, ONLOW, ONHIGH
|
||||||
|
DEBUG_PRINTLN(F("Interrupt attached."));
|
||||||
|
} else {
|
||||||
|
DEBUG_PRINTLN(F("Unable to allocate interrupt pin, disabling."));
|
||||||
|
pinIRQ = -1;
|
||||||
|
enabled = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
PinManagerPinType pins[3] = { { pinA, false }, { pinB, false }, { pinC, false } };
|
PinManagerPinType pins[3] = { { pinA, false }, { pinB, false }, { pinC, false } };
|
||||||
if (!pinManager.allocateMultiplePins(pins, 3, PinOwner::UM_RotaryEncoderUI)) {
|
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;
|
pinA = pinB = pinC = -1;
|
||||||
enabled = false;
|
enabled = false;
|
||||||
return;
|
return;
|
||||||
@ -284,6 +503,7 @@ public:
|
|||||||
pinMode(pinA, USERMOD_ROTARY_ENCODER_GPIO);
|
pinMode(pinA, USERMOD_ROTARY_ENCODER_GPIO);
|
||||||
pinMode(pinB, USERMOD_ROTARY_ENCODER_GPIO);
|
pinMode(pinB, USERMOD_ROTARY_ENCODER_GPIO);
|
||||||
pinMode(pinC, USERMOD_ROTARY_ENCODER_GPIO);
|
pinMode(pinC, USERMOD_ROTARY_ENCODER_GPIO);
|
||||||
|
}
|
||||||
|
|
||||||
loopTime = millis();
|
loopTime = millis();
|
||||||
|
|
||||||
@ -301,20 +521,11 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
initDone = true;
|
initDone = true;
|
||||||
Enc_A = digitalRead(pinA); // Read encoder pins
|
Enc_A = readPin(pinA); // Read encoder pins
|
||||||
Enc_B = digitalRead(pinB);
|
Enc_B = readPin(pinB);
|
||||||
Enc_A_prev = Enc_A;
|
Enc_A_prev = Enc_A;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* 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.
|
* loop() is called continuously. Here you can check for events, read sensors, etc.
|
||||||
*
|
*
|
||||||
@ -325,7 +536,7 @@ public:
|
|||||||
* 2. Try to avoid using the delay() function. NEVER use delays longer than 10 milliseconds.
|
* 2. Try to avoid using the delay() function. NEVER use delays longer than 10 milliseconds.
|
||||||
* Instead, use a timer check as shown here.
|
* Instead, use a timer check as shown here.
|
||||||
*/
|
*/
|
||||||
void loop()
|
void RotaryEncoderUIUsermod::loop()
|
||||||
{
|
{
|
||||||
if (!enabled || strip.isUpdating()) return;
|
if (!enabled || strip.isUpdating()) return;
|
||||||
unsigned long currentTime = millis(); // get the current elapsed time
|
unsigned long currentTime = millis(); // get the current elapsed time
|
||||||
@ -339,14 +550,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (modes_alpha_indexes[effectCurrentIndex] != effectCurrent || palettes_alpha_indexes[effectPaletteIndex] != effectPalette) {
|
if (modes_alpha_indexes[effectCurrentIndex] != effectCurrent || palettes_alpha_indexes[effectPaletteIndex] != effectPalette) {
|
||||||
|
DEBUG_PRINTLN(F("Current mode or palette changed."));
|
||||||
currentEffectAndPaletteInitialized = false;
|
currentEffectAndPaletteInitialized = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentTime >= (loopTime + 2)) // 2ms since last check of encoder = 500Hz
|
if (currentTime >= (loopTime + 2)) // 2ms since last check of encoder = 500Hz
|
||||||
{
|
{
|
||||||
loopTime = currentTime; // Updates loopTime
|
bool buttonPressed = !readPin(pinC); //0=pressed, 1=released
|
||||||
|
|
||||||
bool buttonPressed = !digitalRead(pinC); //0=pressed, 1=released
|
|
||||||
if (buttonPressed) {
|
if (buttonPressed) {
|
||||||
if (!buttonPressedBefore) buttonPressedTime = currentTime;
|
if (!buttonPressedBefore) buttonPressedTime = currentTime;
|
||||||
buttonPressedBefore = true;
|
buttonPressedBefore = true;
|
||||||
@ -413,8 +623,8 @@ public:
|
|||||||
if (changedState) select_state = newState;
|
if (changedState) select_state = newState;
|
||||||
}
|
}
|
||||||
|
|
||||||
Enc_A = digitalRead(pinA); // Read encoder pins
|
Enc_A = readPin(pinA); // Read encoder pins
|
||||||
Enc_B = digitalRead(pinB);
|
Enc_B = readPin(pinB);
|
||||||
if ((Enc_A) && (!Enc_A_prev))
|
if ((Enc_A) && (!Enc_A_prev))
|
||||||
{ // A has gone from high to low
|
{ // A has gone from high to low
|
||||||
if (Enc_B == LOW) //changes to LOW so that then encoder registers a change at the very end of a pulse
|
if (Enc_B == LOW) //changes to LOW so that then encoder registers a change at the very end of a pulse
|
||||||
@ -453,16 +663,18 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Enc_A_prev = Enc_A; // Store value of A for next time
|
Enc_A_prev = Enc_A; // Store value of A for next time
|
||||||
|
loopTime = currentTime; // Updates loopTime
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void displayNetworkInfo() {
|
void RotaryEncoderUIUsermod::displayNetworkInfo() {
|
||||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||||
display->networkOverlay(PSTR("NETWORK INFO"), 10000);
|
display->networkOverlay(PSTR("NETWORK INFO"), 10000);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void findCurrentEffectAndPalette() {
|
void RotaryEncoderUIUsermod::findCurrentEffectAndPalette() {
|
||||||
|
DEBUG_PRINTLN(F("Finding current mode and palette."));
|
||||||
currentEffectAndPaletteInitialized = true;
|
currentEffectAndPaletteInitialized = true;
|
||||||
for (uint8_t i = 0; i < strip.getModeCount(); i++) {
|
for (uint8_t i = 0; i < strip.getModeCount(); i++) {
|
||||||
if (modes_alpha_indexes[i] == effectCurrent) {
|
if (modes_alpha_indexes[i] == effectCurrent) {
|
||||||
@ -470,6 +682,7 @@ public:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
DEBUG_PRINTLN(F("Found current mode."));
|
||||||
|
|
||||||
for (uint8_t i = 0; i < strip.getPaletteCount(); i++) {
|
for (uint8_t i = 0; i < strip.getPaletteCount(); i++) {
|
||||||
if (palettes_alpha_indexes[i] == effectPalette) {
|
if (palettes_alpha_indexes[i] == effectPalette) {
|
||||||
@ -477,9 +690,10 @@ public:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
DEBUG_PRINTLN(F("Found palette."));
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean changeState(const char *stateName, byte markedLine, byte markedCol, byte glyph) {
|
bool RotaryEncoderUIUsermod::changeState(const char *stateName, byte markedLine, byte markedCol, byte glyph) {
|
||||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||||
if (display != nullptr) {
|
if (display != nullptr) {
|
||||||
if (display->wakeDisplay()) {
|
if (display->wakeDisplay()) {
|
||||||
@ -494,7 +708,7 @@ public:
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void lampUdated() {
|
void RotaryEncoderUIUsermod::lampUdated() {
|
||||||
//call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification)
|
//call for notifier -> 0: init 1: direct change 2: button 3: notification 4: nightlight 5: other (No notification)
|
||||||
// 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa
|
// 6: fx changed 7: hue 8: preset cycle 9: blynk 10: alexa
|
||||||
//setValuesFromFirstSelectedSeg(); //to make transition work on main segment (should no longer be required)
|
//setValuesFromFirstSelectedSeg(); //to make transition work on main segment (should no longer be required)
|
||||||
@ -502,7 +716,7 @@ public:
|
|||||||
updateInterfaces(CALL_MODE_BUTTON);
|
updateInterfaces(CALL_MODE_BUTTON);
|
||||||
}
|
}
|
||||||
|
|
||||||
void changeBrightness(bool increase) {
|
void RotaryEncoderUIUsermod::changeBrightness(bool increase) {
|
||||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||||
if (display && display->wakeDisplay()) {
|
if (display && display->wakeDisplay()) {
|
||||||
display->redraw(true);
|
display->redraw(true);
|
||||||
@ -519,7 +733,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void changeEffect(bool increase) {
|
void RotaryEncoderUIUsermod::changeEffect(bool increase) {
|
||||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||||
if (display && display->wakeDisplay()) {
|
if (display && display->wakeDisplay()) {
|
||||||
display->redraw(true);
|
display->redraw(true);
|
||||||
@ -548,7 +762,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void changeEffectSpeed(bool increase) {
|
void RotaryEncoderUIUsermod::changeEffectSpeed(bool increase) {
|
||||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||||
if (display && display->wakeDisplay()) {
|
if (display && display->wakeDisplay()) {
|
||||||
display->redraw(true);
|
display->redraw(true);
|
||||||
@ -576,7 +790,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void changeEffectIntensity(bool increase) {
|
void RotaryEncoderUIUsermod::changeEffectIntensity(bool increase) {
|
||||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||||
if (display && display->wakeDisplay()) {
|
if (display && display->wakeDisplay()) {
|
||||||
display->redraw(true);
|
display->redraw(true);
|
||||||
@ -604,7 +818,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void changeCustom(uint8_t par, bool increase) {
|
void RotaryEncoderUIUsermod::changeCustom(uint8_t par, bool increase) {
|
||||||
uint8_t val = 0;
|
uint8_t val = 0;
|
||||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||||
if (display && display->wakeDisplay()) {
|
if (display && display->wakeDisplay()) {
|
||||||
@ -649,7 +863,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void changePalette(bool increase) {
|
void RotaryEncoderUIUsermod::changePalette(bool increase) {
|
||||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||||
if (display && display->wakeDisplay()) {
|
if (display && display->wakeDisplay()) {
|
||||||
display->redraw(true);
|
display->redraw(true);
|
||||||
@ -678,7 +892,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void changeHue(bool increase){
|
void RotaryEncoderUIUsermod::changeHue(bool increase){
|
||||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||||
if (display && display->wakeDisplay()) {
|
if (display && display->wakeDisplay()) {
|
||||||
display->redraw(true);
|
display->redraw(true);
|
||||||
@ -708,7 +922,7 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void changeSat(bool increase){
|
void RotaryEncoderUIUsermod::changeSat(bool increase){
|
||||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||||
if (display && display->wakeDisplay()) {
|
if (display && display->wakeDisplay()) {
|
||||||
display->redraw(true);
|
display->redraw(true);
|
||||||
@ -737,7 +951,7 @@ public:
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void changePreset(bool increase) {
|
void RotaryEncoderUIUsermod::changePreset(bool increase) {
|
||||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||||
if (display && display->wakeDisplay()) {
|
if (display && display->wakeDisplay()) {
|
||||||
display->redraw(true);
|
display->redraw(true);
|
||||||
@ -769,7 +983,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void changeCCT(bool increase){
|
void RotaryEncoderUIUsermod::changeCCT(bool increase){
|
||||||
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
#ifdef USERMOD_FOUR_LINE_DISPLAY
|
||||||
if (display && display->wakeDisplay()) {
|
if (display && display->wakeDisplay()) {
|
||||||
display->redraw(true);
|
display->redraw(true);
|
||||||
@ -803,7 +1017,7 @@ public:
|
|||||||
* Below it is shown how this could be used for e.g. a light sensor
|
* Below it is shown how this could be used for e.g. a light sensor
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
void addToJsonInfo(JsonObject& root)
|
void RotaryEncoderUIUsermod::addToJsonInfo(JsonObject& root)
|
||||||
{
|
{
|
||||||
int reading = 20;
|
int reading = 20;
|
||||||
//this code adds "u":{"Light":[20," lux"]} to the info object
|
//this code adds "u":{"Light":[20," lux"]} to the info object
|
||||||
@ -820,7 +1034,7 @@ public:
|
|||||||
* Values in the state object may be modified by connected clients
|
* Values in the state object may be modified by connected clients
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
void addToJsonState(JsonObject &root)
|
void RotaryEncoderUIUsermod::addToJsonState(JsonObject &root)
|
||||||
{
|
{
|
||||||
//root["user0"] = userVar0;
|
//root["user0"] = userVar0;
|
||||||
}
|
}
|
||||||
@ -831,7 +1045,7 @@ public:
|
|||||||
* Values in the state object may be modified by connected clients
|
* Values in the state object may be modified by connected clients
|
||||||
*/
|
*/
|
||||||
/*
|
/*
|
||||||
void readFromJsonState(JsonObject &root)
|
void RotaryEncoderUIUsermod::readFromJsonState(JsonObject &root)
|
||||||
{
|
{
|
||||||
//userVar0 = root["user0"] | userVar0; //if "user0" key exists in JSON, update, else keep old value
|
//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!"));
|
//if (root["bri"] == 255) Serial.println(F("Don't burn down your garage!"));
|
||||||
@ -841,7 +1055,7 @@ public:
|
|||||||
/**
|
/**
|
||||||
* addToConfig() (called from set.cpp) stores persistent properties to cfg.json
|
* addToConfig() (called from set.cpp) stores persistent properties to cfg.json
|
||||||
*/
|
*/
|
||||||
void addToConfig(JsonObject &root) {
|
void RotaryEncoderUIUsermod::addToConfig(JsonObject &root) {
|
||||||
// we add JSON object: {"Rotary-Encoder":{"DT-pin":12,"CLK-pin":14,"SW-pin":13}}
|
// we add JSON object: {"Rotary-Encoder":{"DT-pin":12,"CLK-pin":14,"SW-pin":13}}
|
||||||
JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname
|
JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname
|
||||||
top[FPSTR(_enabled)] = enabled;
|
top[FPSTR(_enabled)] = enabled;
|
||||||
@ -851,15 +1065,22 @@ public:
|
|||||||
top[FPSTR(_presetLow)] = presetLow;
|
top[FPSTR(_presetLow)] = presetLow;
|
||||||
top[FPSTR(_presetHigh)] = presetHigh;
|
top[FPSTR(_presetHigh)] = presetHigh;
|
||||||
top[FPSTR(_applyToAll)] = applyToAll;
|
top[FPSTR(_applyToAll)] = applyToAll;
|
||||||
|
top[FPSTR(_pcf8574)] = usePcf8574;
|
||||||
|
top[FPSTR(_pcfAddress)] = addrPcf8574;
|
||||||
|
top[FPSTR(_pcfINTpin)] = pinIRQ;
|
||||||
DEBUG_PRINTLN(F("Rotary Encoder config saved."));
|
DEBUG_PRINTLN(F("Rotary Encoder config saved."));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//void RotaryEncoderUIUsermod::appendConfigData() {
|
||||||
|
// oappend(SET_F("addInfo('RotaryEncoderUIUsermod:PCF8574-address',1,'<i>(not hex!)</i>');"));
|
||||||
|
//}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* readFromConfig() is called before setup() to populate properties from values stored in cfg.json
|
* 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.
|
* The function should return true if configuration was successfully loaded or false if there was no configuration.
|
||||||
*/
|
*/
|
||||||
bool readFromConfig(JsonObject &root) {
|
bool RotaryEncoderUIUsermod::readFromConfig(JsonObject &root) {
|
||||||
// we look for JSON object: {"Rotary-Encoder":{"DT-pin":12,"CLK-pin":14,"SW-pin":13}}
|
// we look for JSON object: {"Rotary-Encoder":{"DT-pin":12,"CLK-pin":14,"SW-pin":13}}
|
||||||
JsonObject top = root[FPSTR(_name)];
|
JsonObject top = root[FPSTR(_name)];
|
||||||
if (top.isNull()) {
|
if (top.isNull()) {
|
||||||
@ -870,6 +1091,8 @@ public:
|
|||||||
int8_t newDTpin = top[FPSTR(_DT_pin)] | pinA;
|
int8_t newDTpin = top[FPSTR(_DT_pin)] | pinA;
|
||||||
int8_t newCLKpin = top[FPSTR(_CLK_pin)] | pinB;
|
int8_t newCLKpin = top[FPSTR(_CLK_pin)] | pinB;
|
||||||
int8_t newSWpin = top[FPSTR(_SW_pin)] | pinC;
|
int8_t newSWpin = top[FPSTR(_SW_pin)] | pinC;
|
||||||
|
int8_t newIRQpin = top[FPSTR(_pcfINTpin)] | pinIRQ;
|
||||||
|
bool oldPcf8574 = usePcf8574;
|
||||||
|
|
||||||
presetHigh = top[FPSTR(_presetHigh)] | presetHigh;
|
presetHigh = top[FPSTR(_presetHigh)] | presetHigh;
|
||||||
presetLow = top[FPSTR(_presetLow)] | presetLow;
|
presetLow = top[FPSTR(_presetLow)] | presetLow;
|
||||||
@ -879,6 +1102,9 @@ public:
|
|||||||
enabled = top[FPSTR(_enabled)] | enabled;
|
enabled = top[FPSTR(_enabled)] | enabled;
|
||||||
applyToAll = top[FPSTR(_applyToAll)] | applyToAll;
|
applyToAll = top[FPSTR(_applyToAll)] | applyToAll;
|
||||||
|
|
||||||
|
usePcf8574 = top[FPSTR(_pcf8574)] | usePcf8574;
|
||||||
|
addrPcf8574 = top[FPSTR(_pcfAddress)] | addrPcf8574;
|
||||||
|
|
||||||
DEBUG_PRINT(FPSTR(_name));
|
DEBUG_PRINT(FPSTR(_name));
|
||||||
if (!initDone) {
|
if (!initDone) {
|
||||||
// first run: reading from cfg.json
|
// first run: reading from cfg.json
|
||||||
@ -889,10 +1115,20 @@ public:
|
|||||||
} else {
|
} else {
|
||||||
DEBUG_PRINTLN(F(" config (re)loaded."));
|
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||||
// changing parameters from settings page
|
// changing parameters from settings page
|
||||||
if (pinA!=newDTpin || pinB!=newCLKpin || pinC!=newSWpin) {
|
if (pinA!=newDTpin || pinB!=newCLKpin || pinC!=newSWpin || pinIRQ!=newIRQpin) {
|
||||||
|
if (oldPcf8574) {
|
||||||
|
if (pinIRQ >= 0) {
|
||||||
|
detachInterrupt(pinIRQ);
|
||||||
|
pinManager.deallocatePin(pinIRQ, PinOwner::UM_RotaryEncoderUI);
|
||||||
|
DEBUG_PRINTLN(F("Deallocated old IRQ pin."));
|
||||||
|
}
|
||||||
|
pinIRQ = newIRQpin;
|
||||||
|
} else {
|
||||||
pinManager.deallocatePin(pinA, PinOwner::UM_RotaryEncoderUI);
|
pinManager.deallocatePin(pinA, PinOwner::UM_RotaryEncoderUI);
|
||||||
pinManager.deallocatePin(pinB, PinOwner::UM_RotaryEncoderUI);
|
pinManager.deallocatePin(pinB, PinOwner::UM_RotaryEncoderUI);
|
||||||
pinManager.deallocatePin(pinC, PinOwner::UM_RotaryEncoderUI);
|
pinManager.deallocatePin(pinC, PinOwner::UM_RotaryEncoderUI);
|
||||||
|
DEBUG_PRINTLN(F("Deallocated old pins."));
|
||||||
|
}
|
||||||
pinA = newDTpin;
|
pinA = newDTpin;
|
||||||
pinB = newCLKpin;
|
pinB = newCLKpin;
|
||||||
pinC = newSWpin;
|
pinC = newSWpin;
|
||||||
@ -904,18 +1140,9 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||||
return !top[FPSTR(_applyToAll)].isNull();
|
return !top[FPSTR(_pcfINTpin)].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)
|
// strings to reduce flash memory usage (used more than twice)
|
||||||
const char RotaryEncoderUIUsermod::_name[] PROGMEM = "Rotary-Encoder";
|
const char RotaryEncoderUIUsermod::_name[] PROGMEM = "Rotary-Encoder";
|
||||||
@ -926,3 +1153,6 @@ const char RotaryEncoderUIUsermod::_SW_pin[] PROGMEM = "SW-pin";
|
|||||||
const char RotaryEncoderUIUsermod::_presetHigh[] PROGMEM = "preset-high";
|
const char RotaryEncoderUIUsermod::_presetHigh[] PROGMEM = "preset-high";
|
||||||
const char RotaryEncoderUIUsermod::_presetLow[] PROGMEM = "preset-low";
|
const char RotaryEncoderUIUsermod::_presetLow[] PROGMEM = "preset-low";
|
||||||
const char RotaryEncoderUIUsermod::_applyToAll[] PROGMEM = "apply-2-all-seg";
|
const char RotaryEncoderUIUsermod::_applyToAll[] PROGMEM = "apply-2-all-seg";
|
||||||
|
const char RotaryEncoderUIUsermod::_pcf8574[] PROGMEM = "use-PCF8574";
|
||||||
|
const char RotaryEncoderUIUsermod::_pcfAddress[] PROGMEM = "PCF8574-address";
|
||||||
|
const char RotaryEncoderUIUsermod::_pcfINTpin[] PROGMEM = "PCF8574-INT-pin";
|
||||||
|
@ -184,7 +184,7 @@ void Segment::deallocateData() {
|
|||||||
void Segment::resetIfRequired() {
|
void Segment::resetIfRequired() {
|
||||||
if (reset) {
|
if (reset) {
|
||||||
if (leds && !Segment::_globalLeds) { free(leds); leds = nullptr; }
|
if (leds && !Segment::_globalLeds) { free(leds); leds = nullptr; }
|
||||||
if (transitional && _t) { transitional = false; delete _t; _t = nullptr; }
|
//if (transitional && _t) { transitional = false; delete _t; _t = nullptr; }
|
||||||
deallocateData();
|
deallocateData();
|
||||||
next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0;
|
next_time = 0; step = 0; call = 0; aux0 = 0; aux1 = 0;
|
||||||
reset = false; // setOption(SEG_OPTION_RESET, false);
|
reset = false; // setOption(SEG_OPTION_RESET, false);
|
||||||
@ -367,16 +367,15 @@ CRGBPalette16 &Segment::currentPalette(CRGBPalette16 &targetPalette, uint8_t pal
|
|||||||
|
|
||||||
void Segment::handleTransition() {
|
void Segment::handleTransition() {
|
||||||
if (!transitional) return;
|
if (!transitional) return;
|
||||||
unsigned long maxWait = millis() + 20;
|
uint16_t _progress = progress();
|
||||||
if (mode == FX_MODE_STATIC && next_time > maxWait) next_time = maxWait;
|
if (_t) { // thanks to @nXm AKA https://github.com/NMeirer
|
||||||
if (progress() == 0xFFFFU) {
|
if (_progress >= 32767U && _t->_modeP != mode) markForReset();
|
||||||
if (_t) {
|
if (_progress == 0xFFFFU) {
|
||||||
if (_t->_modeP != mode) markForReset();
|
|
||||||
delete _t;
|
delete _t;
|
||||||
_t = nullptr;
|
_t = nullptr;
|
||||||
}
|
}
|
||||||
transitional = false; // finish transitioning segment
|
|
||||||
}
|
}
|
||||||
|
if (_progress == 0xFFFFU) transitional = false; // finish transitioning segment
|
||||||
}
|
}
|
||||||
|
|
||||||
void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t ofs, uint16_t i1Y, uint16_t i2Y) {
|
void Segment::setUp(uint16_t i1, uint16_t i2, uint8_t grp, uint8_t spc, uint16_t ofs, uint16_t i1Y, uint16_t i2Y) {
|
||||||
@ -1095,6 +1094,8 @@ void WS2812FX::service() {
|
|||||||
_isServicing = true;
|
_isServicing = true;
|
||||||
_segment_index = 0;
|
_segment_index = 0;
|
||||||
for (segment &seg : _segments) {
|
for (segment &seg : _segments) {
|
||||||
|
// process transition (mode changes in the middle of transition)
|
||||||
|
seg.handleTransition();
|
||||||
// reset the segment runtime data if needed
|
// reset the segment runtime data if needed
|
||||||
seg.resetIfRequired();
|
seg.resetIfRequired();
|
||||||
|
|
||||||
@ -1123,8 +1124,6 @@ void WS2812FX::service() {
|
|||||||
delay = (*_mode[seg.currentMode(seg.mode)])();
|
delay = (*_mode[seg.currentMode(seg.mode)])();
|
||||||
if (seg.mode != FX_MODE_HALLOWEEN_EYES) seg.call++;
|
if (seg.mode != FX_MODE_HALLOWEEN_EYES) seg.call++;
|
||||||
if (seg.transitional && delay > FRAMETIME) delay = FRAMETIME; // force faster updates during transition
|
if (seg.transitional && delay > FRAMETIME) delay = FRAMETIME; // force faster updates during transition
|
||||||
|
|
||||||
seg.handleTransition();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
seg.next_time = nowUp + delay;
|
seg.next_time = nowUp + delay;
|
||||||
|
@ -122,6 +122,9 @@
|
|||||||
#define I_SS_LPO_3 48
|
#define I_SS_LPO_3 48
|
||||||
|
|
||||||
|
|
||||||
|
// In the following NeoGammaNullMethod can be replaced with NeoGammaWLEDMethod to perform Gamma correction implicitly
|
||||||
|
// unfortunately that may apply Gamma correction to pre-calculated palettes which is undesired
|
||||||
|
|
||||||
/*** ESP8266 Neopixel methods ***/
|
/*** ESP8266 Neopixel methods ***/
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
//RGB
|
//RGB
|
||||||
|
@ -297,9 +297,11 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
PinManagerPinType i2c[2] = { { i2c_sda, true }, { i2c_scl, true } };
|
PinManagerPinType i2c[2] = { { i2c_sda, true }, { i2c_scl, true } };
|
||||||
if (i2c_scl >= 0 && i2c_sda >= 0 && pinManager.allocateMultiplePins(i2c, 2, PinOwner::HW_I2C)) {
|
if (i2c_scl >= 0 && i2c_sda >= 0 && pinManager.allocateMultiplePins(i2c, 2, PinOwner::HW_I2C)) {
|
||||||
#ifdef ESP32
|
#ifdef ESP32
|
||||||
Wire.setPins(i2c_sda, i2c_scl); // this will fail if Wire is initilised (Wire.begin() called prior)
|
if (!Wire.setPins(i2c_sda, i2c_scl)) { i2c_scl = i2c_sda = -1; } // this will fail if Wire is initilised (Wire.begin() called prior)
|
||||||
|
else Wire.begin();
|
||||||
|
#else
|
||||||
|
Wire.begin(i2c_sda, i2c_scl);
|
||||||
#endif
|
#endif
|
||||||
Wire.begin();
|
|
||||||
} else {
|
} else {
|
||||||
i2c_sda = -1;
|
i2c_sda = -1;
|
||||||
i2c_scl = -1;
|
i2c_scl = -1;
|
||||||
@ -336,7 +338,7 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
if (light_gc_col > 1.0f) gammaCorrectCol = true;
|
if (light_gc_col > 1.0f) gammaCorrectCol = true;
|
||||||
else gammaCorrectCol = false;
|
else gammaCorrectCol = false;
|
||||||
if (gammaCorrectVal > 1.0f && gammaCorrectVal <= 3) {
|
if (gammaCorrectVal > 1.0f && gammaCorrectVal <= 3) {
|
||||||
if (gammaCorrectVal != 2.8f) calcGammaTable(gammaCorrectVal);
|
if (gammaCorrectVal != 2.8f) NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal);
|
||||||
} else {
|
} else {
|
||||||
gammaCorrectVal = 1.0f; // no gamma correction
|
gammaCorrectVal = 1.0f; // no gamma correction
|
||||||
gammaCorrectBri = false;
|
gammaCorrectBri = false;
|
||||||
|
@ -302,7 +302,7 @@ uint16_t approximateKelvinFromRGB(uint32_t rgb) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//gamma 2.8 lookup table used for color correction
|
//gamma 2.8 lookup table used for color correction
|
||||||
static byte gammaT[] = {
|
uint8_t NeoGammaWLEDMethod::gammaT[256] = {
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1,
|
||||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
|
1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
|
||||||
@ -320,27 +320,22 @@ static byte gammaT[] = {
|
|||||||
177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213,
|
177,180,182,184,186,189,191,193,196,198,200,203,205,208,210,213,
|
||||||
215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 };
|
215,218,220,223,225,228,231,233,236,239,241,244,247,249,252,255 };
|
||||||
|
|
||||||
uint8_t gamma8_cal(uint8_t b, float gamma)
|
|
||||||
{
|
|
||||||
return (int)(powf((float)b / 255.0f, gamma) * 255.0f + 0.5f);
|
|
||||||
}
|
|
||||||
|
|
||||||
// re-calculates & fills gamma table
|
// re-calculates & fills gamma table
|
||||||
void calcGammaTable(float gamma)
|
void NeoGammaWLEDMethod::calcGammaTable(float gamma)
|
||||||
{
|
{
|
||||||
for (uint16_t i = 0; i < 256; i++) {
|
for (size_t i = 0; i < 256; i++) {
|
||||||
gammaT[i] = gamma8_cal(i, gamma);
|
gammaT[i] = (int)(powf((float)i / 255.0f, gamma) * 255.0f + 0.5f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// used for individual channel or brightness gamma correction
|
uint8_t NeoGammaWLEDMethod::Correct(uint8_t value)
|
||||||
uint8_t gamma8(uint8_t b)
|
|
||||||
{
|
{
|
||||||
return gammaT[b];
|
if (!gammaCorrectCol) return value;
|
||||||
|
return gammaT[value];
|
||||||
}
|
}
|
||||||
|
|
||||||
// used for color gamma correction
|
// used for color gamma correction
|
||||||
uint32_t gamma32(uint32_t color)
|
uint32_t NeoGammaWLEDMethod::Correct32(uint32_t color)
|
||||||
{
|
{
|
||||||
if (!gammaCorrectCol) return color;
|
if (!gammaCorrectCol) return color;
|
||||||
uint8_t w = W(color);
|
uint8_t w = W(color);
|
||||||
|
@ -320,7 +320,8 @@
|
|||||||
|
|
||||||
// WLED Error modes
|
// WLED Error modes
|
||||||
#define ERR_NONE 0 // All good :)
|
#define ERR_NONE 0 // All good :)
|
||||||
#define ERR_EEP_COMMIT 2 // Could not commit to EEPROM (wrong flash layout?)
|
#define ERR_DENIED 1 // Permission denied
|
||||||
|
#define ERR_EEP_COMMIT 2 // Could not commit to EEPROM (wrong flash layout?) OBSOLETE
|
||||||
#define ERR_NOBUF 3 // JSON buffer was not released in time, request cannot be handled at this time
|
#define ERR_NOBUF 3 // JSON buffer was not released in time, request cannot be handled at this time
|
||||||
#define ERR_JSON 9 // JSON parsing failed (input too large?)
|
#define ERR_JSON 9 // JSON parsing failed (input too large?)
|
||||||
#define ERR_FS_BEGIN 10 // Could not init filesystem (no partition?)
|
#define ERR_FS_BEGIN 10 // Could not init filesystem (no partition?)
|
||||||
|
@ -42,6 +42,6 @@
|
|||||||
<img alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAbUExURQAAAAB81gCU/zKq/////9bW1oCAgGhoaAAAAGPLX8AAAAAJdFJOU///////////AFNPeBIAAAAJcEhZcwAADsAAAA7AAWrWiQkAAACdSURBVDhPxc9bDoUgEANQebP/FUuHMjBGY/B+3EYR7RH0qC/ZBc6HwCljgHO+xZIVSI2sYgHaG7EBWh8jWoxTrCBFdDJ+BD4lbIHxAcz8APAVLTsrZE4eQD5qzt3cAFTYokC4YCN9Gybgu4yAQtBFLQXHuHABA7JMeOEC/E0W5uy9gv4vo5QHK2i7yq2C8UABM4HmL+CSTXCTF1DrCX6+Gp9zB5dsAAAAAElFTkSuQmCC">
|
<img alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAbUExURQAAAAB81gCU/zKq/////9bW1oCAgGhoaAAAAGPLX8AAAAAJdFJOU///////////AFNPeBIAAAAJcEhZcwAADsAAAA7AAWrWiQkAAACdSURBVDhPxc9bDoUgEANQebP/FUuHMjBGY/B+3EYR7RH0qC/ZBc6HwCljgHO+xZIVSI2sYgHaG7EBWh8jWoxTrCBFdDJ+BD4lbIHxAcz8APAVLTsrZE4eQD5qzt3cAFTYokC4YCN9Gybgu4yAQtBFLQXHuHABA7JMeOEC/E0W5uy9gv4vo5QHK2i7yq2C8UABM4HmL+CSTXCTF1DrCX6+Gp9zB5dsAAAAAElFTkSuQmCC">
|
||||||
<h1>404 Not Found</h1>
|
<h1>404 Not Found</h1>
|
||||||
<b>Akemi does not know where you are headed...</b><br><br>
|
<b>Akemi does not know where you are headed...</b><br><br>
|
||||||
<button onclick="window.location.href='/sliders'">Back to controls</button>
|
<button onclick="window.location.href='../sliders'">Back to controls</button>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -410,6 +410,7 @@ button {
|
|||||||
position: -webkit-sticky;
|
position: -webkit-sticky;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
|
max-width: 300px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#sliders .labels {
|
#sliders .labels {
|
||||||
@ -418,7 +419,7 @@ button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.slider {
|
.slider {
|
||||||
max-width: 300px;
|
/*max-width: 300px;*/
|
||||||
/* margin: 5px auto; add 5px; if you want some vertical space but looks ugly */
|
/* margin: 5px auto; add 5px; if you want some vertical space but looks ugly */
|
||||||
border-radius: 24px;
|
border-radius: 24px;
|
||||||
position: relative;
|
position: relative;
|
||||||
@ -434,12 +435,16 @@ button {
|
|||||||
z-index: 0;
|
z-index: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#sliders .slider {
|
||||||
|
padding-right: 64px; /* offset for bubble */
|
||||||
|
}
|
||||||
|
|
||||||
#sliders .slider, #info .slider {
|
#sliders .slider, #info .slider {
|
||||||
background-color: var(--c-2);
|
background-color: var(--c-2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#sliders .sliderwrap, .sbs .sliderwrap {
|
#sliders .sliderwrap, .sbs .sliderwrap {
|
||||||
left: 16px; /* offset for icon */
|
left: 32px; /* offset for icon */
|
||||||
}
|
}
|
||||||
|
|
||||||
.filter, .option {
|
.filter, .option {
|
||||||
@ -685,18 +690,19 @@ img {
|
|||||||
|
|
||||||
.sliderbubble {
|
.sliderbubble {
|
||||||
width: 24px;
|
width: 24px;
|
||||||
position: relative;
|
position: absolute;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
border-radius: 10px;
|
border-radius: 16px;
|
||||||
background: var(--c-3);
|
background: var(--c-3);
|
||||||
color: var(--c-f);
|
color: var(--c-f);
|
||||||
padding: 2px 4px;
|
padding: 4px;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
right: 3px;
|
right: 6px;
|
||||||
transition: visibility 0.25s ease, opacity 0.25s ease;
|
transition: visibility .25s ease,opacity .25s ease;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
left: 8px;
|
/* left: 8px; */
|
||||||
|
top: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
output.sliderbubbleshow {
|
output.sliderbubbleshow {
|
||||||
@ -1022,8 +1028,9 @@ textarea {
|
|||||||
|
|
||||||
/* segment power wrapper */
|
/* segment power wrapper */
|
||||||
.sbs {
|
.sbs {
|
||||||
padding: 1px 0 1px 20px;
|
/*padding: 1px 0 1px 20px;*/
|
||||||
display: var(--sgp);
|
display: var(--sgp);
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.pname {
|
.pname {
|
||||||
@ -1538,8 +1545,11 @@ TD .checkmark, TD .radiomark {
|
|||||||
#sliders .sliderbubble {
|
#sliders .sliderbubble {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.sliderwrap {
|
#sliders .sliderwrap, .sbs .sliderwrap {
|
||||||
width: calc(100% - 28px);
|
width: calc(100% - 42px);
|
||||||
|
}
|
||||||
|
#sliders .slider {
|
||||||
|
padding-right: 0;
|
||||||
}
|
}
|
||||||
#sliders .sliderwrap {
|
#sliders .sliderwrap {
|
||||||
left: 12px;
|
left: 12px;
|
||||||
|
@ -67,7 +67,7 @@
|
|||||||
<button id="buttonSr" onclick="toggleLiveview()"><i class="icons"></i><p class="tab-label">Peek</p></button>
|
<button id="buttonSr" onclick="toggleLiveview()"><i class="icons"></i><p class="tab-label">Peek</p></button>
|
||||||
<button id="buttonI" onclick="toggleInfo()"><i class="icons"></i><p class="tab-label">Info</p></button>
|
<button id="buttonI" onclick="toggleInfo()"><i class="icons"></i><p class="tab-label">Info</p></button>
|
||||||
<button id="buttonNodes" onclick="toggleNodes()"><i class="icons"></i><p class="tab-label">Nodes</p></button>
|
<button id="buttonNodes" onclick="toggleNodes()"><i class="icons"></i><p class="tab-label">Nodes</p></button>
|
||||||
<button onclick="window.location.href='/settings';"><i class="icons"></i><p class="tab-label">Config</p></button>
|
<button onclick="window.location.href=getURL('/settings');"><i class="icons"></i><p class="tab-label">Config</p></button>
|
||||||
<button id="buttonPcm" onclick="togglePcMode(true)"><i class="icons"></i><p class="tab-label">PC Mode</p></button>
|
<button id="buttonPcm" onclick="togglePcMode(true)"><i class="icons"></i><p class="tab-label">PC Mode</p></button>
|
||||||
</div>
|
</div>
|
||||||
<div id="briwrap">
|
<div id="briwrap">
|
||||||
@ -88,7 +88,7 @@
|
|||||||
<div class ="container">
|
<div class ="container">
|
||||||
<div id="Colors" class="tabcontent">
|
<div id="Colors" class="tabcontent">
|
||||||
<div id="picker" class="noslide"></div>
|
<div id="picker" class="noslide"></div>
|
||||||
<div id="hwrap" class="slider">
|
<div id="hwrap" class="slider" style="margin-top: 20px;">
|
||||||
<div class="sliderwrap il">
|
<div class="sliderwrap il">
|
||||||
<input id="sliderH" class="noslide" oninput="fromH()" onchange="setColor(0)" max="359" min="0" type="range" value="0" step="any">
|
<input id="sliderH" class="noslide" oninput="fromH()" onchange="setColor(0)" max="359" min="0" type="range" value="0" step="any">
|
||||||
<div class="sliderdisplay" style="background: linear-gradient(90deg, #f00 2%, #ff0 19%, #0f0 35%, #0ff 52%, #00f 68%, #f0f 85%, #f00)"></div>
|
<div class="sliderdisplay" style="background: linear-gradient(90deg, #f00 2%, #ff0 19%, #0f0 35%, #0ff 52%, #00f 68%, #f0f 85%, #f00)"></div>
|
||||||
@ -199,7 +199,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="padding-bottom: 10px;">
|
<div style="padding-bottom: 10px;">
|
||||||
<button class="btn btn-xs" type="button" onclick="window.location.href=(loc?'http://'+locip:'')+'/cpal.htm'"><i class="icons btn-icon"></i></button>
|
<button class="btn btn-xs" type="button" onclick="window.location.href=getURL('/cpal.htm')"><i class="icons btn-icon"></i></button>
|
||||||
<button class="btn btn-xs" type="button" onclick="palettesData=null;localStorage.removeItem('wledPalx');requestJson({rmcpal:true});setTimeout(loadPalettes,250,loadPalettesData);"><i class="icons btn-icon"></i></button>
|
<button class="btn btn-xs" type="button" onclick="palettesData=null;localStorage.removeItem('wledPalx');requestJson({rmcpal:true});setTimeout(loadPalettes,250,loadPalettesData);"><i class="icons btn-icon"></i></button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -363,7 +363,7 @@
|
|||||||
<div>
|
<div>
|
||||||
<button class="btn infobtn" onclick="requestJson()">Refresh</button>
|
<button class="btn infobtn" onclick="requestJson()">Refresh</button>
|
||||||
<button class="btn infobtn" onclick="toggleNodes()">Instance List</button>
|
<button class="btn infobtn" onclick="toggleNodes()">Instance List</button>
|
||||||
<button class="btn infobtn" onclick="window.open('/update','_self');">Update WLED</button>
|
<button class="btn infobtn" onclick="window.open(getURL('/update'),'_self');">Update WLED</button>
|
||||||
<button class="btn infobtn" id="resetbtn" onclick="cnfReset()">Reboot WLED</button>
|
<button class="btn infobtn" id="resetbtn" onclick="cnfReset()">Reboot WLED</button>
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//page js
|
//page js
|
||||||
var loc = false, locip;
|
var loc = false, locip, locproto = "http:";
|
||||||
var isOn = false, nlA = false, isLv = false, isInfo = false, isNodes = false, syncSend = false, syncTglRecv = true;
|
var isOn = false, nlA = false, isLv = false, isInfo = false, isNodes = false, syncSend = false, syncTglRecv = true;
|
||||||
var hasWhite = false, hasRGB = false, hasCCT = false;
|
var hasWhite = false, hasRGB = false, hasCCT = false;
|
||||||
var nlDur = 60, nlTar = 0;
|
var nlDur = 60, nlTar = 0;
|
||||||
@ -193,21 +193,38 @@ function loadSkinCSS(cId)
|
|||||||
l.id = cId;
|
l.id = cId;
|
||||||
l.rel = 'stylesheet';
|
l.rel = 'stylesheet';
|
||||||
l.type = 'text/css';
|
l.type = 'text/css';
|
||||||
l.href = (loc?`http://${locip}`:'.') + '/skin.css';
|
l.href = getURL('/skin.css');
|
||||||
l.media = 'all';
|
l.media = 'all';
|
||||||
h.appendChild(l);
|
h.appendChild(l);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getURL(path) {
|
||||||
|
return (loc ? locproto + "//" + locip : "") + path;
|
||||||
|
}
|
||||||
function onLoad()
|
function onLoad()
|
||||||
{
|
{
|
||||||
if (window.location.protocol == "file:") {
|
let l = window.location;
|
||||||
|
if (l.protocol == "file:") {
|
||||||
loc = true;
|
loc = true;
|
||||||
locip = localStorage.getItem('locIp');
|
locip = localStorage.getItem('locIp');
|
||||||
if (!locip) {
|
if (!locip) {
|
||||||
locip = prompt("File Mode. Please enter WLED IP!");
|
locip = prompt("File Mode. Please enter WLED IP!");
|
||||||
localStorage.setItem('locIp', locip);
|
localStorage.setItem('locIp', locip);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// detect reverse proxy and/or HTTPS
|
||||||
|
let pathn = l.pathname;
|
||||||
|
let paths = pathn.slice(1,pathn.endsWith('/')?-1:undefined).split("/");
|
||||||
|
//while (paths[0]==="") paths.shift();
|
||||||
|
locproto = l.protocol;
|
||||||
|
locip = l.hostname + (l.port ? ":" + l.port : "");
|
||||||
|
if (paths.length > 0 && paths[0]!=="") {
|
||||||
|
loc = true;
|
||||||
|
locip += "/" + paths[0];
|
||||||
|
} else if (locproto==="https:") {
|
||||||
|
loc = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var sett = localStorage.getItem('wledUiCfg');
|
var sett = localStorage.getItem('wledUiCfg');
|
||||||
if (sett) cfg = mergeDeep(cfg, JSON.parse(sett));
|
if (sett) cfg = mergeDeep(cfg, JSON.parse(sett));
|
||||||
@ -217,7 +234,7 @@ function onLoad()
|
|||||||
if (localStorage.getItem('pcm') == "true" || (!/Mobi/.test(navigator.userAgent) && localStorage.getItem('pcm') == null)) togglePcMode(true);
|
if (localStorage.getItem('pcm') == "true" || (!/Mobi/.test(navigator.userAgent) && localStorage.getItem('pcm') == null)) togglePcMode(true);
|
||||||
applyCfg();
|
applyCfg();
|
||||||
if (cfg.comp.hdays) { //load custom holiday list
|
if (cfg.comp.hdays) { //load custom holiday list
|
||||||
fetch((loc?`http://${locip}`:'.') + "/holidays.json", { // may be loaded from external source
|
fetch(getURL("/holidays.json"), { // may be loaded from external source
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
.then((res)=>{
|
.then((res)=>{
|
||||||
@ -433,9 +450,7 @@ function loadPresets(callback = null)
|
|||||||
// afterwards
|
// afterwards
|
||||||
if (!callback && pmt == pmtLast) return;
|
if (!callback && pmt == pmtLast) return;
|
||||||
|
|
||||||
var url = (loc?`http://${locip}`:'') + '/presets.json';
|
fetch(getURL('/presets.json'), {
|
||||||
|
|
||||||
fetch(url, {
|
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
@ -459,9 +474,7 @@ function loadPresets(callback = null)
|
|||||||
|
|
||||||
function loadPalettes(callback = null)
|
function loadPalettes(callback = null)
|
||||||
{
|
{
|
||||||
var url = (loc?`http://${locip}`:'') + '/json/palettes';
|
fetch(getURL('/json/palettes'), {
|
||||||
|
|
||||||
fetch(url, {
|
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
.then((res)=>{
|
.then((res)=>{
|
||||||
@ -483,9 +496,7 @@ function loadPalettes(callback = null)
|
|||||||
|
|
||||||
function loadFX(callback = null)
|
function loadFX(callback = null)
|
||||||
{
|
{
|
||||||
var url = (loc?`http://${locip}`:'') + '/json/effects';
|
fetch(getURL('/json/effects'), {
|
||||||
|
|
||||||
fetch(url, {
|
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
.then((res)=>{
|
.then((res)=>{
|
||||||
@ -497,6 +508,7 @@ function loadFX(callback = null)
|
|||||||
populateEffects();
|
populateEffects();
|
||||||
})
|
})
|
||||||
.catch((e)=>{
|
.catch((e)=>{
|
||||||
|
//setTimeout(loadFX, 250); // retry
|
||||||
showToast(e, true);
|
showToast(e, true);
|
||||||
})
|
})
|
||||||
.finally(()=>{
|
.finally(()=>{
|
||||||
@ -507,9 +519,7 @@ function loadFX(callback = null)
|
|||||||
|
|
||||||
function loadFXData(callback = null)
|
function loadFXData(callback = null)
|
||||||
{
|
{
|
||||||
var url = (loc?`http://${locip}`:'') + '/json/fxdata';
|
fetch(getURL('/json/fxdata'), {
|
||||||
|
|
||||||
fetch(url, {
|
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
.then((res)=>{
|
.then((res)=>{
|
||||||
@ -524,6 +534,7 @@ function loadFXData(callback = null)
|
|||||||
})
|
})
|
||||||
.catch((e)=>{
|
.catch((e)=>{
|
||||||
fxdata = [];
|
fxdata = [];
|
||||||
|
//setTimeout(loadFXData, 250); // retry
|
||||||
showToast(e, true);
|
showToast(e, true);
|
||||||
})
|
})
|
||||||
.finally(()=>{
|
.finally(()=>{
|
||||||
@ -1032,8 +1043,7 @@ function populateNodes(i,n)
|
|||||||
|
|
||||||
function loadNodes()
|
function loadNodes()
|
||||||
{
|
{
|
||||||
var url = (loc?`http://${locip}`:'') + '/json/nodes';
|
fetch(getURL('/json/nodes'), {
|
||||||
fetch(url, {
|
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
.then((res)=>{
|
.then((res)=>{
|
||||||
@ -1253,6 +1263,7 @@ function updateSelectedFx()
|
|||||||
// hide non-0D effects if segment only has 1 pixel (0D)
|
// hide non-0D effects if segment only has 1 pixel (0D)
|
||||||
var fxs = parent.querySelectorAll('.lstI');
|
var fxs = parent.querySelectorAll('.lstI');
|
||||||
for (const fx of fxs) {
|
for (const fx of fxs) {
|
||||||
|
if (!fx.dataset.opt) continue;
|
||||||
let opts = fx.dataset.opt.split(";");
|
let opts = fx.dataset.opt.split(";");
|
||||||
if (fx.dataset.id>0) {
|
if (fx.dataset.id>0) {
|
||||||
if (segLmax==0) fx.classList.add('hide'); // none of the segments selected (hide all effects)
|
if (segLmax==0) fx.classList.add('hide'); // none of the segments selected (hide all effects)
|
||||||
@ -1293,7 +1304,8 @@ function cmpP(a, b)
|
|||||||
|
|
||||||
function makeWS() {
|
function makeWS() {
|
||||||
if (ws || lastinfo.ws < 0) return;
|
if (ws || lastinfo.ws < 0) return;
|
||||||
ws = new WebSocket((window.location.protocol == "https:"?"wss":"ws")+'://'+(loc?locip:window.location.hostname)+'/ws');
|
let url = loc ? getURL('/ws').replace("http","ws") : "ws://"+window.location.hostname+"/ws";
|
||||||
|
ws = new WebSocket(url);
|
||||||
ws.binaryType = "arraybuffer";
|
ws.binaryType = "arraybuffer";
|
||||||
ws.onmessage = (e)=>{
|
ws.onmessage = (e)=>{
|
||||||
if (e.data instanceof ArrayBuffer) return; // liveview packet
|
if (e.data instanceof ArrayBuffer) return; // liveview packet
|
||||||
@ -1572,7 +1584,6 @@ function requestJson(command=null)
|
|||||||
if (command && !reqsLegal) return; // stop post requests from chrome onchange event on page restore
|
if (command && !reqsLegal) return; // stop post requests from chrome onchange event on page restore
|
||||||
if (!jsonTimeout) jsonTimeout = setTimeout(()=>{if (ws) ws.close(); ws=null; showErrorToast()}, 3000);
|
if (!jsonTimeout) jsonTimeout = setTimeout(()=>{if (ws) ws.close(); ws=null; showErrorToast()}, 3000);
|
||||||
var req = null;
|
var req = null;
|
||||||
var url = (loc?`http://${locip}`:'') + '/json/si';
|
|
||||||
var useWs = (ws && ws.readyState === WebSocket.OPEN);
|
var useWs = (ws && ws.readyState === WebSocket.OPEN);
|
||||||
var type = command ? 'post':'get';
|
var type = command ? 'post':'get';
|
||||||
if (command) {
|
if (command) {
|
||||||
@ -1593,7 +1604,7 @@ function requestJson(command=null)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fetch(url, {
|
fetch(getURL('/json/si'), {
|
||||||
method: type,
|
method: type,
|
||||||
headers: {
|
headers: {
|
||||||
"Content-type": "application/json; charset=UTF-8"
|
"Content-type": "application/json; charset=UTF-8"
|
||||||
@ -1688,7 +1699,7 @@ function toggleLiveview()
|
|||||||
}
|
}
|
||||||
|
|
||||||
gId(lvID).style.display = (isLv) ? "block":"none";
|
gId(lvID).style.display = (isLv) ? "block":"none";
|
||||||
var url = (loc?`http://${locip}`:'') + "/" + lvID;
|
var url = getURL("/" + lvID);
|
||||||
gId(lvID).src = (isLv) ? url:"about:blank";
|
gId(lvID).src = (isLv) ? url:"about:blank";
|
||||||
gId('buttonSr').className = (isLv) ? "active":"";
|
gId('buttonSr').className = (isLv) ? "active":"";
|
||||||
if (!isLv && ws && ws.readyState === WebSocket.OPEN) ws.send('{"lv":false}');
|
if (!isLv && ws && ws.readyState === WebSocket.OPEN) ws.send('{"lv":false}');
|
||||||
@ -2584,7 +2595,7 @@ function cnfReset()
|
|||||||
bt.innerHTML = "Confirm Reboot";
|
bt.innerHTML = "Confirm Reboot";
|
||||||
cnfr = true; return;
|
cnfr = true; return;
|
||||||
}
|
}
|
||||||
window.location.href = "/reset";
|
window.location.href = getURL("/reset");
|
||||||
}
|
}
|
||||||
|
|
||||||
var cnfrS = false;
|
var cnfrS = false;
|
||||||
@ -2638,9 +2649,7 @@ function loadPalettesData(callback = null)
|
|||||||
|
|
||||||
function getPalettesData(page, callback)
|
function getPalettesData(page, callback)
|
||||||
{
|
{
|
||||||
var url = (loc?`http://${locip}`:'') + `/json/palx?page=${page}`;
|
fetch(getURL(`/json/palx?page=${page}`), {
|
||||||
|
|
||||||
fetch(url, {
|
|
||||||
method: 'get',
|
method: 'get',
|
||||||
headers: {
|
headers: {
|
||||||
"Content-type": "application/json; charset=UTF-8"
|
"Content-type": "application/json; charset=UTF-8"
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
tmout = setTimeout(update, 250);
|
tmout = setTimeout(update, 250);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fetch('/json/live')
|
fetch('./json/live')
|
||||||
.then(res => {
|
.then(res => {
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
clearTimeout(tmout);
|
clearTimeout(tmout);
|
||||||
|
@ -29,8 +29,15 @@
|
|||||||
//console.info("Peek uses top WS");
|
//console.info("Peek uses top WS");
|
||||||
ws.send("{'lv':true}");
|
ws.send("{'lv':true}");
|
||||||
} else {
|
} else {
|
||||||
console.info("Peek WS opening");
|
//console.info("Peek WS opening");
|
||||||
ws = new WebSocket((window.location.protocol == "https:"?"wss":"ws")+"://"+document.location.host+"/ws");
|
let l = window.location;
|
||||||
|
let pathn = l.pathname;
|
||||||
|
let paths = pathn.slice(1,pathn.endsWith('/')?-1:undefined).split("/");
|
||||||
|
let url = l.origin.replace("http","ws");
|
||||||
|
if (paths.length > 1) {
|
||||||
|
url += "/" + paths[0];
|
||||||
|
}
|
||||||
|
ws = new WebSocket(url+"/ws");
|
||||||
ws.onopen = function () {
|
ws.onopen = function () {
|
||||||
//console.info("Peek WS open");
|
//console.info("Peek WS open");
|
||||||
ws.send("{'lv':true}");
|
ws.send("{'lv':true}");
|
||||||
|
@ -33,7 +33,14 @@
|
|||||||
if (ws && ws.readyState === WebSocket.OPEN) {
|
if (ws && ws.readyState === WebSocket.OPEN) {
|
||||||
ws.send("{'lv':true}");
|
ws.send("{'lv':true}");
|
||||||
} else {
|
} else {
|
||||||
ws = new WebSocket((window.location.protocol == "https:"?"wss":"ws")+"://"+document.location.host+"/ws");
|
let l = window.location;
|
||||||
|
let pathn = l.pathname;
|
||||||
|
let paths = pathn.slice(1,pathn.endsWith('/')?-1:undefined).split("/");
|
||||||
|
let url = l.origin.replace("http","ws");
|
||||||
|
if (paths.length > 1) {
|
||||||
|
url += "/" + paths[0];
|
||||||
|
}
|
||||||
|
ws = new WebSocket(url+"/ws");
|
||||||
ws.onopen = ()=>{
|
ws.onopen = ()=>{
|
||||||
ws.send("{'lv':true}");
|
ws.send("{'lv':true}");
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
<title>WLED Message</title>
|
<title>WLED Message</title>
|
||||||
<script>
|
<script>
|
||||||
function B() { window.history.back() };
|
function B() { window.history.back() };
|
||||||
function RS() { window.location = "/settings"; }
|
function RS() { window.location = "../settings"; }
|
||||||
function RP() { top.location.href = "/"; }
|
function RP() { top.location.href = "../"; }
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
@import url("style.css");
|
@import url("style.css");
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
<title>WLED Settings</title>
|
<title>WLED Settings</title>
|
||||||
<script>
|
<script>
|
||||||
var d=document;
|
var d=document;
|
||||||
var loc = false, locip;
|
var loc = false, locip, locproto = "http:";
|
||||||
function gId(n){return d.getElementById(n);}
|
function gId(n){return d.getElementById(n);}
|
||||||
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
||||||
function loadJS(FILE_URL, async = true) {
|
function loadJS(FILE_URL, async = true) {
|
||||||
@ -27,16 +27,28 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
function S() {
|
function S() {
|
||||||
if (window.location.protocol == "file:") {
|
let l = window.location;
|
||||||
|
if (l.protocol == "file:") {
|
||||||
loc = true;
|
loc = true;
|
||||||
locip = localStorage.getItem('locIp');
|
locip = localStorage.getItem('locIp');
|
||||||
if (!locip) {
|
if (!locip) {
|
||||||
locip = prompt("File Mode. Please enter WLED IP!");
|
locip = prompt("File Mode. Please enter WLED IP!");
|
||||||
localStorage.setItem('locIp', locip);
|
localStorage.setItem('locIp', locip);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// detect reverse proxy
|
||||||
|
let path = l.pathname;
|
||||||
|
let paths = path.slice(1,path.endsWith('/')?-1:undefined).split("/");
|
||||||
|
if (paths.length > 1) {
|
||||||
|
locproto = l.protocol;
|
||||||
|
loc = true;
|
||||||
|
locip = l.hostname + (l.port ? ":" + l.port : "") + "/" + paths[0];
|
||||||
}
|
}
|
||||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=0';
|
}
|
||||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
loadJS(getURL('/settings/s.js?p=0'), false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||||
|
}
|
||||||
|
function getURL(path) {
|
||||||
|
return (loc ? locproto + "//" + locip : "") + path;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
@ -65,15 +77,15 @@
|
|||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body onload="S()">
|
<body onload="S()">
|
||||||
<button type=submit id="b" onclick="window.location='/'">Back</button>
|
<button type=submit id="b" onclick="window.location=getURL('/')">Back</button>
|
||||||
<button type="submit" onclick="window.location='./settings/wifi'">WiFi Setup</button>
|
<button type="submit" onclick="window.location=getURL('/settings/wifi')">WiFi Setup</button>
|
||||||
<button type="submit" onclick="window.location='./settings/leds'">LED Preferences</button>
|
<button type="submit" onclick="window.location=getURL('/settings/leds')">LED Preferences</button>
|
||||||
<button id="2dbtn" style="display:none;" type="submit" onclick="window.location='./settings/2D'">2D Configuration</button>
|
<button id="2dbtn" style="display:none;" type="submit" onclick="window.location=getURL('/settings/2D')">2D Configuration</button>
|
||||||
<button type="submit" onclick="window.location='./settings/ui'">User Interface</button>
|
<button type="submit" onclick="window.location=getURL('/settings/ui')">User Interface</button>
|
||||||
<button id="dmxbtn" style="display:none;" type="submit" onclick="window.location='./settings/dmx'">DMX Output</button>
|
<button id="dmxbtn" style="display:none;" type="submit" onclick="window.location=getURL('/settings/dmx')">DMX Output</button>
|
||||||
<button type="submit" onclick="window.location='./settings/sync'">Sync Interfaces</button>
|
<button type="submit" onclick="window.location=getURL('/settings/sync')">Sync Interfaces</button>
|
||||||
<button type="submit" onclick="window.location='./settings/time'">Time & Macros</button>
|
<button type="submit" onclick="window.location=getURL('/settings/time')">Time & Macros</button>
|
||||||
<button type="submit" onclick="window.location='./settings/um'">Usermods</button>
|
<button type="submit" onclick="window.location=getURL('/settings/um')">Usermods</button>
|
||||||
<button type="submit" onclick="window.location='./settings/sec'">Security & Updates</button>
|
<button type="submit" onclick="window.location=getURL('/settings/sec')">Security & Updates</button>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -7,11 +7,11 @@
|
|||||||
<title>2D Set-up</title>
|
<title>2D Set-up</title>
|
||||||
<script>
|
<script>
|
||||||
var d=document;
|
var d=document;
|
||||||
var loc = false, locip;
|
var loc = false, locip, locproto = "http:";
|
||||||
var maxPanels=64;
|
var maxPanels=64;
|
||||||
var ctx = null; // WLEDMM
|
var ctx = null; // WLEDMM
|
||||||
function H(){window.open("https://kno.wled.ge/features/2D");}
|
function H(){window.open("https://kno.wled.ge/features/2D");}
|
||||||
function B(){window.open("/settings","_self");}
|
function B(){window.open(getURL("/settings"),"_self");}
|
||||||
function gId(n){return d.getElementById(n);}
|
function gId(n){return d.getElementById(n);}
|
||||||
function fS(){d.Sf.submit();} // <button type=submit> sometimes didn't work
|
function fS(){d.Sf.submit();} // <button type=submit> sometimes didn't work
|
||||||
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
||||||
@ -35,16 +35,29 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
function S() {
|
function S() {
|
||||||
if (window.location.protocol == "file:") {
|
let l = window.location;
|
||||||
|
if (l.protocol == "file:") {
|
||||||
loc = true;
|
loc = true;
|
||||||
locip = localStorage.getItem('locIp');
|
locip = localStorage.getItem('locIp');
|
||||||
if (!locip) {
|
if (!locip) {
|
||||||
locip = prompt("File Mode. Please enter WLED IP!");
|
locip = prompt("File Mode. Please enter WLED IP!");
|
||||||
localStorage.setItem('locIp', locip);
|
localStorage.setItem('locIp', locip);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// detect reverse proxy
|
||||||
|
let path = l.pathname;
|
||||||
|
let paths = path.slice(1,path.endsWith('/')?-1:undefined).split("/");
|
||||||
|
if (paths.length > 2) {
|
||||||
|
locproto = l.protocol;
|
||||||
|
loc = true;
|
||||||
|
locip = l.hostname + (l.port ? ":" + l.port : "") + "/" + paths[0];
|
||||||
}
|
}
|
||||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=10';
|
}
|
||||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
loadJS(getURL('/settings/s.js?p=10'), false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||||
|
if (loc) d.Sf.action = getURL('/settings/2D');
|
||||||
|
}
|
||||||
|
function getURL(path) {
|
||||||
|
return (loc ? locproto + "//" + locip : "") + path;
|
||||||
}
|
}
|
||||||
|
|
||||||
function UI() {
|
function UI() {
|
||||||
@ -322,7 +335,7 @@ Y:<input name="P${i}Y" type="number" min="0" max="255" value="0" oninput="UI()">
|
|||||||
<option value="1">Vertical</option>
|
<option value="1">Vertical</option>
|
||||||
</select><br>
|
</select><br>
|
||||||
Serpentine: <input type="checkbox" name="PS"><br>
|
Serpentine: <input type="checkbox" name="PS"><br>
|
||||||
<i style="color:#fa0;">Pressing Populate will create LED panel layout with pre-arranged matrix.<br>Values above <i>will not</i> affect final layout.<br>
|
<i class="warn">Pressing Populate will create LED panel layout with pre-arranged matrix.<br>Values above <i>will not</i> affect final layout.<br>
|
||||||
WARNING: You may need to update each panel parameters after they are generated.</i><br>
|
WARNING: You may need to update each panel parameters after they are generated.</i><br>
|
||||||
<button type="button" onclick="gen();expand(gId('expGen'),gId('mxGen'));">Populate</button>
|
<button type="button" onclick="gen();expand(gId('expGen'),gId('mxGen'));">Populate</button>
|
||||||
</div>
|
</div>
|
||||||
|
@ -7,9 +7,9 @@
|
|||||||
<title>DMX Settings</title>
|
<title>DMX Settings</title>
|
||||||
<script>
|
<script>
|
||||||
var d=document;
|
var d=document;
|
||||||
var loc = false, locip;
|
var loc = false, locip, locproto = "http:";
|
||||||
function H(){window.open("https://github.com/Aircoookie/WLED/wiki/DMX");}
|
function H(){window.open("https://github.com/Aircoookie/WLED/wiki/DMX");}
|
||||||
function B(){window.history.back();}
|
function B(){window.open(getURL("/settings"),"_self");}
|
||||||
function GCH(num) {
|
function GCH(num) {
|
||||||
d.getElementById('dmxchannels').innerHTML += "";
|
d.getElementById('dmxchannels').innerHTML += "";
|
||||||
for (i=0;i<num;i++) {
|
for (i=0;i<num;i++) {
|
||||||
@ -54,16 +54,29 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
function S(){
|
function S(){
|
||||||
if (window.location.protocol == "file:") {
|
let l = window.location;
|
||||||
|
if (l.protocol == "file:") {
|
||||||
loc = true;
|
loc = true;
|
||||||
locip = localStorage.getItem('locIp');
|
locip = localStorage.getItem('locIp');
|
||||||
if (!locip) {
|
if (!locip) {
|
||||||
locip = prompt("File Mode. Please enter WLED IP!");
|
locip = prompt("File Mode. Please enter WLED IP!");
|
||||||
localStorage.setItem('locIp', locip);
|
localStorage.setItem('locIp', locip);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// detect reverse proxy
|
||||||
|
let path = l.pathname;
|
||||||
|
let paths = path.slice(1,path.endsWith('/')?-1:undefined).split("/");
|
||||||
|
if (paths.length > 2) {
|
||||||
|
locproto = l.protocol;
|
||||||
|
loc = true;
|
||||||
|
locip = l.hostname + (l.port ? ":" + l.port : "") + "/" + paths[0];
|
||||||
}
|
}
|
||||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=7';
|
}
|
||||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
loadJS(getURL('/settings/s.js?p=7'), false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||||
|
if (loc) d.Sf.action = getURL('/settings/dmx');
|
||||||
|
}
|
||||||
|
function getURL(path) {
|
||||||
|
return (loc ? locproto + "//" + locip : "") + path;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>@import url("style.css");</style>
|
<style>@import url("style.css");</style>
|
||||||
|
@ -10,11 +10,11 @@
|
|||||||
d.um_p = [];
|
d.um_p = [];
|
||||||
d.rsvd = [];
|
d.rsvd = [];
|
||||||
d.ro_gpio = [];
|
d.ro_gpio = [];
|
||||||
d.max_gpio = 39;
|
d.max_gpio = 50;
|
||||||
var customStarts=false,startsDirty=[],maxCOOverrides=5;
|
var customStarts=false,startsDirty=[],maxCOOverrides=5;
|
||||||
var loc = false, locip;
|
var loc = false, locip, locproto = "http:";
|
||||||
function H(){window.open("https://kno.wled.ge/features/settings/#led-settings");}
|
function H(){window.open("https://kno.wled.ge/features/settings/#led-settings");}
|
||||||
function B(){window.open("/settings","_self");}
|
function B(){window.open(getURL("/settings"),"_self");}
|
||||||
function gId(n){return d.getElementById(n);}
|
function gId(n){return d.getElementById(n);}
|
||||||
function off(n){d.getElementsByName(n)[0].value = -1;}
|
function off(n){d.getElementsByName(n)[0].value = -1;}
|
||||||
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
||||||
@ -26,8 +26,12 @@
|
|||||||
d.body.appendChild(scE);
|
d.body.appendChild(scE);
|
||||||
// success event
|
// success event
|
||||||
scE.addEventListener("load", () => {
|
scE.addEventListener("load", () => {
|
||||||
GetV();checkSi();setABL();
|
GetV();
|
||||||
|
checkSi();
|
||||||
|
setABL();
|
||||||
|
d.Sf.addEventListener("submit", trySubmit);
|
||||||
if (d.um_p[0]==-1) d.um_p.shift();
|
if (d.um_p[0]==-1) d.um_p.shift();
|
||||||
|
pinDropdowns();
|
||||||
});
|
});
|
||||||
// error event
|
// error event
|
||||||
scE.addEventListener("error", (ev) => {
|
scE.addEventListener("error", (ev) => {
|
||||||
@ -49,7 +53,7 @@
|
|||||||
maxB = b; maxV = v; maxM = m; maxPB = p; maxL = l;
|
maxB = b; maxV = v; maxM = m; maxPB = p; maxL = l;
|
||||||
}
|
}
|
||||||
function pinsOK() {
|
function pinsOK() {
|
||||||
var LCs = d.getElementsByTagName("input");
|
var LCs = d.Sf.querySelectorAll("#mLC input[name^=L]"); // input fields
|
||||||
for (i=0; i<LCs.length; i++) {
|
for (i=0; i<LCs.length; i++) {
|
||||||
var nm = LCs[i].name.substring(0,2);
|
var nm = LCs[i].name.substring(0,2);
|
||||||
// ignore IP address
|
// ignore IP address
|
||||||
@ -59,23 +63,36 @@
|
|||||||
if (t>=80) continue;
|
if (t>=80) continue;
|
||||||
}
|
}
|
||||||
//check for pin conflicts
|
//check for pin conflicts
|
||||||
if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3" || nm=="L4" || nm=="RL" || nm=="BT" || nm=="IR")
|
if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3" || nm=="L4"/* || nm=="RL" || nm=="BT" || nm=="IR"*/)
|
||||||
if (LCs[i].value!="" && LCs[i].value!="-1") {
|
if (LCs[i].value!="" && LCs[i].value!="-1") {
|
||||||
var p = []; // used pin array
|
var p = d.rsvd.concat(d.um_p); // used pin array
|
||||||
for (k=0;k<d.rsvd.length;k++) p.push(d.rsvd[k]); // fill with reservations
|
d.Sf.querySelectorAll("select.pin").forEach((e)=>{if(e.value>-1)p.push(parseInt(e.value));}) // buttons, IR & relay
|
||||||
for (k=0;k<d.um_p.length;k++) p.push(d.um_p[k]); // fill with usermod pins
|
if (p.some((e)=>e==parseInt(LCs[i].value))) {
|
||||||
if (p.some((e)=>e==parseInt(LCs[i].value,10))) {alert(`Sorry, pins ${JSON.stringify(p)} can't be used.`);LCs[i].value="";LCs[i].focus();return false;}
|
alert(`Sorry, pins ${JSON.stringify(p)} can't be used.`);
|
||||||
else if (!(nm == "IR" || nm=="BT") && d.ro_gpio.some((e)=>e==parseInt(LCs[i].value,10))) {alert(`Sorry, pins ${JSON.stringify(d.ro_gpio)} are input only.`);LCs[i].value="";LCs[i].focus();return false;}
|
LCs[i].value="";
|
||||||
for (j=i+1; j<LCs.length; j++)
|
LCs[i].focus();
|
||||||
{
|
return false;
|
||||||
|
}
|
||||||
|
else if (/*!(nm == "IR" || nm=="BT") &&*/ d.ro_gpio.some((e)=>e==parseInt(LCs[i].value))) {
|
||||||
|
alert(`Sorry, pins ${JSON.stringify(d.ro_gpio)} are input only.`);
|
||||||
|
LCs[i].value="";
|
||||||
|
LCs[i].focus();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (j=i+1; j<LCs.length; j++) {
|
||||||
var n2 = LCs[j].name.substring(0,2);
|
var n2 = LCs[j].name.substring(0,2);
|
||||||
if (n2=="L0" || n2=="L1" || n2=="L2" || n2=="L3" || n2=="L4" || n2=="RL" || n2=="BT" || n2=="IR") {
|
if (n2=="L0" || n2=="L1" || n2=="L2" || n2=="L3" || n2=="L4"/* || n2=="RL" || n2=="BT" || n2=="IR"*/) {
|
||||||
if (n2.substring(0,1)==="L") {
|
if (n2.substring(0,1)==="L") {
|
||||||
var m = LCs[j].name.substring(2);
|
var m = LCs[j].name.substring(2);
|
||||||
var t2 = parseInt(d.getElementsByName("LT"+m)[0].value, 10);
|
var t2 = parseInt(d.getElementsByName("LT"+m)[0].value, 10);
|
||||||
if (t2>=80) continue;
|
if (t2>=80) continue;
|
||||||
}
|
}
|
||||||
if (LCs[j].value!="" && LCs[i].value==LCs[j].value) {alert(`Pin conflict between ${LCs[i].name}/${LCs[j].name}!`);LCs[j].value="";LCs[j].focus();return false;}
|
if (LCs[j].value!="" && LCs[i].value==LCs[j].value) {
|
||||||
|
alert(`Pin conflict between ${LCs[i].name}/${LCs[j].name}!`);
|
||||||
|
LCs[j].value="";
|
||||||
|
LCs[j].focus();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -96,6 +113,7 @@
|
|||||||
gId('abl').style.display = (en) ? 'inline':'none';
|
gId('abl').style.display = (en) ? 'inline':'none';
|
||||||
gId('psu2').style.display = (en) ? 'inline':'none';
|
gId('psu2').style.display = (en) ? 'inline':'none';
|
||||||
if (d.Sf.LA.value > 0) setABL();
|
if (d.Sf.LA.value > 0) setABL();
|
||||||
|
UI();
|
||||||
}
|
}
|
||||||
function enLA()
|
function enLA()
|
||||||
{
|
{
|
||||||
@ -117,28 +135,28 @@
|
|||||||
default: gId('LAdis').style.display = 'inline';
|
default: gId('LAdis').style.display = 'inline';
|
||||||
}
|
}
|
||||||
gId('m1').innerHTML = maxM;
|
gId('m1').innerHTML = maxM;
|
||||||
d.getElementsByName("Sf")[0].addEventListener("submit", trySubmit);
|
|
||||||
UI();
|
|
||||||
}
|
}
|
||||||
//returns mem usage
|
//returns mem usage
|
||||||
function getMem(t, n) {
|
function getMem(t, n) {
|
||||||
let len = parseInt(d.getElementsByName("LC"+n)[0].value);
|
let len = parseInt(d.getElementsByName("LC"+n)[0].value);
|
||||||
len += parseInt(d.getElementsByName("SL"+n)[0].value); // skipped LEDs are allocated too
|
len += parseInt(d.getElementsByName("SL"+n)[0].value); // skipped LEDs are allocated too
|
||||||
|
let dbl = 0;
|
||||||
|
if (d.Sf.LD.checked) dbl = len * 3; // double buffering
|
||||||
if (t < 32) {
|
if (t < 32) {
|
||||||
if (t==26 || t==29) len *= 2; // 16 bit LEDs
|
if (t==26 || t==29) len *= 2; // 16 bit LEDs
|
||||||
if (maxM < 10000 && d.getElementsByName("L0"+n)[0].value == 3) { //8266 DMA uses 5x the mem
|
if (maxM < 10000 && d.getElementsByName("L0"+n)[0].value == 3) { //8266 DMA uses 5x the mem
|
||||||
if (t > 28) return len*20; //RGBW
|
if (t > 28) return len*20 + dbl; //RGBW
|
||||||
return len*15;
|
return len*15 + dbl;
|
||||||
} else if (maxM >= 10000) //ESP32 RMT uses double buffer?
|
} else if (maxM >= 10000) //ESP32 RMT uses double buffer?
|
||||||
{
|
{
|
||||||
if (t > 28) return len*8; //RGBW
|
if (t > 28) return len*8 + dbl; //RGBW
|
||||||
return len*6;
|
return len*6 + dbl;
|
||||||
}
|
}
|
||||||
if (t > 28) return len*4; //RGBW
|
if (t > 28) return len*4 + dbl; //RGBW
|
||||||
return len*3;
|
return len*3 + dbl;
|
||||||
}
|
}
|
||||||
if (t > 31 && t < 48) return 5;
|
if (t > 31 && t < 48) return 5; // analog
|
||||||
return len*3;
|
return len*3 + dbl;
|
||||||
}
|
}
|
||||||
|
|
||||||
function UI(change=false)
|
function UI(change=false)
|
||||||
@ -151,15 +169,13 @@
|
|||||||
else if (d.Sf.LA.value > 0) laprev = d.Sf.LA.value;
|
else if (d.Sf.LA.value > 0) laprev = d.Sf.LA.value;
|
||||||
|
|
||||||
// enable/disable LED fields
|
// enable/disable LED fields
|
||||||
var s = d.getElementsByTagName("select");
|
d.Sf.querySelectorAll("#mLC select[name^=LT]").forEach((s)=>{
|
||||||
for (i=0; i<s.length; i++) {
|
|
||||||
// is the field a LED type?
|
// is the field a LED type?
|
||||||
if (s[i].name.substring(0,2)=="LT") {
|
var n = s.name.substring(2);
|
||||||
var n = s[i].name.substring(2);
|
var t = parseInt(s.value);
|
||||||
var t = parseInt(s[i].value,10);
|
|
||||||
gId("p0d"+n).innerHTML = (t>=80 && t<96) ? "IP address:" : (t > 49) ? "Data GPIO:" : (t > 41) ? "GPIOs:" : "GPIO:";
|
gId("p0d"+n).innerHTML = (t>=80 && t<96) ? "IP address:" : (t > 49) ? "Data GPIO:" : (t > 41) ? "GPIOs:" : "GPIO:";
|
||||||
gId("p1d"+n).innerHTML = (t> 49 && t<64) ? "Clk GPIO:" : "";
|
gId("p1d"+n).innerHTML = (t> 49 && t<64) ? "Clk GPIO:" : "";
|
||||||
var LK = d.getElementsByName("L1"+n)[0]; // clock pin
|
//var LK = d.getElementsByName("L1"+n)[0]; // clock pin
|
||||||
|
|
||||||
memu += getMem(t, n); // calc memory
|
memu += getMem(t, n); // calc memory
|
||||||
|
|
||||||
@ -196,8 +212,7 @@
|
|||||||
gId("dig"+n+"l").style.display = (t > 48 && t < 64) ? "inline":"none"; // bus clock speed
|
gId("dig"+n+"l").style.display = (t > 48 && t < 64) ? "inline":"none"; // bus clock speed
|
||||||
gId("rev"+n).innerHTML = (t >= 40 && t < 48) ? "Inverted output":"Reversed (rotated 180°)"; // change reverse text for analog
|
gId("rev"+n).innerHTML = (t >= 40 && t < 48) ? "Inverted output":"Reversed (rotated 180°)"; // change reverse text for analog
|
||||||
gId("psd"+n).innerHTML = (t >= 40 && t < 48) ? "Index:":"Start:"; // change analog start description
|
gId("psd"+n).innerHTML = (t >= 40 && t < 48) ? "Index:":"Start:"; // change analog start description
|
||||||
}
|
});
|
||||||
}
|
|
||||||
// display global white channel overrides
|
// display global white channel overrides
|
||||||
gId("wc").style.display = (gRGBW) ? 'inline':'none';
|
gId("wc").style.display = (gRGBW) ? 'inline':'none';
|
||||||
if (!gRGBW) {
|
if (!gRGBW) {
|
||||||
@ -205,7 +220,7 @@
|
|||||||
d.Sf.CR.checked = false;
|
d.Sf.CR.checked = false;
|
||||||
}
|
}
|
||||||
// check for pin conflicts
|
// check for pin conflicts
|
||||||
var LCs = d.getElementsByTagName("input");
|
var LCs = d.Sf.querySelectorAll("#mLC input[name^=L]"); // input fields
|
||||||
var sLC = 0, sPC = 0, maxLC = 0;
|
var sLC = 0, sPC = 0, maxLC = 0;
|
||||||
for (i=0; i<LCs.length; i++) {
|
for (i=0; i<LCs.length; i++) {
|
||||||
var nm = LCs[i].name.substring(0,2); // field name
|
var nm = LCs[i].name.substring(0,2); // field name
|
||||||
@ -243,15 +258,14 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// check for pin conflicts
|
// check for pin conflicts
|
||||||
if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3" || nm=="L4" || nm=="RL" || nm=="BT" || nm=="IR")
|
if (nm=="L0" || nm=="L1" || nm=="L2" || nm=="L3" || nm=="L4"/* || nm=="RL" || nm=="BT" || nm=="IR"*/)
|
||||||
if (LCs[i].value!="" && LCs[i].value!="-1") {
|
if (LCs[i].value!="" && LCs[i].value!="-1") {
|
||||||
var p = []; // used pin array
|
var p = d.rsvd.concat(d.um_p); // used pin array
|
||||||
for (k=0;k<d.rsvd.length;k++) p.push(d.rsvd[k]); // fill with reservations
|
d.Sf.querySelectorAll("select.pin").forEach((e)=>{if(e.value>-1)p.push(parseInt(e.value));}) // buttons, IR & relay
|
||||||
for (k=0;k<d.um_p.length;k++) p.push(d.um_p[k]); // fill with usermod pins
|
|
||||||
for (j=0; j<LCs.length; j++) {
|
for (j=0; j<LCs.length; j++) {
|
||||||
if (i==j) continue;
|
if (i==j) continue;
|
||||||
var n2 = LCs[j].name.substring(0,2);
|
var n2 = LCs[j].name.substring(0,2);
|
||||||
if (n2=="L0" || n2=="L1" || n2=="L2" || n2=="L3" || n2=="L4" || n2=="RL" || n2=="BT" || n2=="IR") {
|
if (n2=="L0" || n2=="L1" || n2=="L2" || n2=="L3" || n2=="L4"/* || n2=="RL" || n2=="BT" || n2=="IR"*/) {
|
||||||
if (n2.substring(0,1)==="L") {
|
if (n2.substring(0,1)==="L") {
|
||||||
var m = LCs[j].name.substring(2);
|
var m = LCs[j].name.substring(2);
|
||||||
var t2 = parseInt(d.getElementsByName("LT"+m)[0].value, 10);
|
var t2 = parseInt(d.getElementsByName("LT"+m)[0].value, 10);
|
||||||
@ -261,13 +275,13 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// now check for conflicts
|
// now check for conflicts
|
||||||
if (p.some((e)=>e==parseInt(LCs[i].value,10))) LCs[i].style.color="red"; else LCs[i].style.color=d.ro_gpio.some((e)=>e==parseInt(LCs[i].value,10))?"orange":"#fff";
|
if (p.some((e)=>e==parseInt(LCs[i].value))) LCs[i].style.color="red"; else LCs[i].style.color=d.ro_gpio.some((e)=>e==parseInt(LCs[i].value))?"orange":"#fff";
|
||||||
}
|
}
|
||||||
// check buttons, IR & relay
|
// check buttons, IR & relay
|
||||||
if (nm=="IR" || nm=="BT" || nm=="RL") {
|
//if (nm=="IR" || nm=="BT" || nm=="RL") {
|
||||||
LCs[i].max = d.max_gpio;
|
// LCs[i].max = d.max_gpio;
|
||||||
LCs[i].min = -1;
|
// LCs[i].min = -1;
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
// update total led count
|
// update total led count
|
||||||
gId("lc").textContent = sLC;
|
gId("lc").textContent = sLC;
|
||||||
@ -366,11 +380,11 @@ ${i+1}:
|
|||||||
<span id="psd${i}">Start:</span> <input type="number" name="LS${i}" id="ls${i}" class="l starts" min="0" max="8191" value="${lastEnd(i)}" oninput="startsDirty[${i}]=true;UI();" required />
|
<span id="psd${i}">Start:</span> <input type="number" name="LS${i}" id="ls${i}" class="l starts" min="0" max="8191" value="${lastEnd(i)}" oninput="startsDirty[${i}]=true;UI();" required />
|
||||||
<div id="dig${i}c" style="display:inline">Length: <input type="number" name="LC${i}" class="l" min="1" max="${maxPB}" value="1" required oninput="UI()" /></div><br>
|
<div id="dig${i}c" style="display:inline">Length: <input type="number" name="LC${i}" class="l" min="1" max="${maxPB}" value="1" required oninput="UI()" /></div><br>
|
||||||
</div>
|
</div>
|
||||||
<span id="p0d${i}">GPIO:</span> <input type="number" name="L0${i}" required class="s" onchange="UI()"/>
|
<span id="p0d${i}">GPIO:</span><input type="number" name="L0${i}" required class="s" onchange="UI();pinUpd(this);"/>
|
||||||
<span id="p1d${i}"></span><input type="number" name="L1${i}" class="s" onchange="UI()"/>
|
<span id="p1d${i}"></span><input type="number" name="L1${i}" class="s" onchange="UI();pinUpd(this);"/>
|
||||||
<span id="p2d${i}"></span><input type="number" name="L2${i}" class="s" onchange="UI()"/>
|
<span id="p2d${i}"></span><input type="number" name="L2${i}" class="s" onchange="UI();pinUpd(this);"/>
|
||||||
<span id="p3d${i}"></span><input type="number" name="L3${i}" class="s" onchange="UI()"/>
|
<span id="p3d${i}"></span><input type="number" name="L3${i}" class="s" onchange="UI();pinUpd(this);"/>
|
||||||
<span id="p4d${i}"></span><input type="number" name="L4${i}" class="s" onchange="UI()"/>
|
<span id="p4d${i}"></span><input type="number" name="L4${i}" class="s" onchange="UI();pinUpd(this);"/>
|
||||||
<div id="dig${i}r" style="display:inline"><br><span id="rev${i}">Reversed</span>: <input type="checkbox" name="CV${i}"></div>
|
<div id="dig${i}r" style="display:inline"><br><span id="rev${i}">Reversed</span>: <input type="checkbox" name="CV${i}"></div>
|
||||||
<div id="dig${i}s" style="display:inline"><br>Skip first LEDs: <input type="number" name="SL${i}" min="0" max="255" value="0" oninput="UI()"></div>
|
<div id="dig${i}s" style="display:inline"><br>Skip first LEDs: <input type="number" name="SL${i}" min="0" max="255" value="0" oninput="UI()"></div>
|
||||||
<div id="dig${i}f" style="display:inline"><br>Off Refresh: <input id="rf${i}" type="checkbox" name="RF${i}"></div>
|
<div id="dig${i}f" style="display:inline"><br>Off Refresh: <input id="rf${i}" type="checkbox" name="RF${i}"></div>
|
||||||
@ -546,17 +560,126 @@ Length: <input type="number" name="XC${i}" id="xc${i}" class="l" min="1" max="65
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function pinDropdowns() {
|
||||||
|
let fields = ["IR","RL"]; // IR & relay
|
||||||
|
gId("btns").querySelectorAll('input[type="number"]').forEach((e)=>{fields.push(e.name);}) // buttons
|
||||||
|
for (let i of d.Sf.elements) {
|
||||||
|
if (i.type === "number" && fields.includes(i.name)) { //select all pin select elements
|
||||||
|
let v = parseInt(i.value);
|
||||||
|
let sel = addDropdown(i.name,0);
|
||||||
|
for (var j = -1; j <= d.max_gpio; j++) {
|
||||||
|
if (d.rsvd.includes(j)) continue;
|
||||||
|
let foundPin = d.um_p.indexOf(j);
|
||||||
|
let txt = (j === -1) ? "unused" : `${j}`;
|
||||||
|
if (foundPin >= 0 && j !== v) txt += ` used`; // already reserved pin
|
||||||
|
if (d.ro_gpio.includes(j)) txt += " (R/O)";
|
||||||
|
let opt = addOption(sel, txt, j);
|
||||||
|
if (j === v) opt.selected = true; // this is "our" pin
|
||||||
|
else if (d.um_p.includes(j)) opt.disabled = true; // someone else's pin
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// update select options
|
||||||
|
d.Sf.querySelectorAll("select.pin").forEach((e)=>{pinUpd(e);});
|
||||||
|
// add dataset values for LED GPIO pins
|
||||||
|
d.Sf.querySelectorAll(".iST input.s[name^=L]").forEach((i)=>{
|
||||||
|
if (i.value!=="" && i.value>=0)
|
||||||
|
i.dataset.val = i.value;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
function pinUpd(e) {
|
||||||
|
// update changed select options across all usermods
|
||||||
|
let oldV = parseInt(e.dataset.val);
|
||||||
|
e.dataset.val = e.value;
|
||||||
|
let txt = e.name;
|
||||||
|
let pins = [];
|
||||||
|
d.Sf.querySelectorAll(".iST input.s[name^=L]").forEach((i)=>{
|
||||||
|
if (i.value!=="" && i.value>=0 && i.max<255)
|
||||||
|
pins.push(i.value);
|
||||||
|
});
|
||||||
|
let selects = d.Sf.querySelectorAll("select.pin");
|
||||||
|
for (let sel of selects) {
|
||||||
|
if (sel == e) continue
|
||||||
|
Array.from(sel.options).forEach((i)=>{
|
||||||
|
let led = pins.includes(i.value);
|
||||||
|
if (!(i.value==oldV || i.value==e.value || led)) return;
|
||||||
|
if (i.value == -1) {
|
||||||
|
i.text = "unused";
|
||||||
|
return
|
||||||
|
}
|
||||||
|
i.text = i.value;
|
||||||
|
if (i.value==oldV) {
|
||||||
|
i.disabled = false;
|
||||||
|
}
|
||||||
|
if (i.value==e.value || led) {
|
||||||
|
i.disabled = true;
|
||||||
|
i.text += ` ${led?'LED':txt}`;
|
||||||
|
}
|
||||||
|
if (d.ro_gpio.includes(parseInt(i.value))) i.text += " (R/O)";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// https://stackoverflow.com/questions/39729741/javascript-change-input-text-to-select-option
|
||||||
|
function addDropdown(field) {
|
||||||
|
let sel = d.createElement('select');
|
||||||
|
sel.classList.add("pin");
|
||||||
|
let inp = d.getElementsByName(field)[0];
|
||||||
|
if (inp && inp.tagName === "INPUT" && (inp.type === "text" || inp.type === "number")) { // may also use nodeName
|
||||||
|
let v = inp.value;
|
||||||
|
let n = inp.name;
|
||||||
|
// copy the existing input element's attributes to the new select element
|
||||||
|
for (var i = 0; i < inp.attributes.length; ++ i) {
|
||||||
|
var att = inp.attributes[i];
|
||||||
|
// type and value don't apply, so skip them
|
||||||
|
// ** you might also want to skip style, or others -- modify as needed **
|
||||||
|
if (att.name != 'type' && att.name != 'value' && att.name != 'class' && att.name != 'style') {
|
||||||
|
sel.setAttribute(att.name, att.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sel.setAttribute("data-val", v);
|
||||||
|
sel.setAttribute("onchange", "pinUpd(this)");
|
||||||
|
// finally, replace the old input element with the new select element
|
||||||
|
inp.parentElement.replaceChild(sel, inp);
|
||||||
|
return sel;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
function addOption(sel,txt,val) {
|
||||||
|
if (sel===null) return; // select object missing
|
||||||
|
let opt = d.createElement("option");
|
||||||
|
opt.value = val;
|
||||||
|
opt.text = txt;
|
||||||
|
sel.appendChild(opt);
|
||||||
|
for (let i=0; i<sel.childNodes.length; i++) {
|
||||||
|
let c = sel.childNodes[i];
|
||||||
|
if (c.value == sel.dataset.val) sel.selectedIndex = i;
|
||||||
|
}
|
||||||
|
return opt;
|
||||||
|
}
|
||||||
function S() {
|
function S() {
|
||||||
if (window.location.protocol == "file:") {
|
let l = window.location;
|
||||||
|
if (l.protocol == "file:") {
|
||||||
loc = true;
|
loc = true;
|
||||||
locip = localStorage.getItem('locIp');
|
locip = localStorage.getItem('locIp');
|
||||||
if (!locip) {
|
if (!locip) {
|
||||||
locip = prompt("File Mode. Please enter WLED IP!");
|
locip = prompt("File Mode. Please enter WLED IP!");
|
||||||
localStorage.setItem('locIp', locip);
|
localStorage.setItem('locIp', locip);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// detect reverse proxy
|
||||||
|
let path = l.pathname;
|
||||||
|
let paths = path.slice(1,path.endsWith('/')?-1:undefined).split("/");
|
||||||
|
if (paths.length > 2) {
|
||||||
|
locproto = l.protocol;
|
||||||
|
loc = true;
|
||||||
|
locip = l.hostname + (l.port ? ":" + l.port : "") + "/" + paths[0];
|
||||||
}
|
}
|
||||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=2';
|
}
|
||||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
loadJS(getURL('/settings/s.js?p=2'), false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||||
|
if (loc) d.Sf.action = getURL('/settings/leds');
|
||||||
|
}
|
||||||
|
function getURL(path) {
|
||||||
|
return (loc ? locproto + "//" + locip : "") + path;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>@import url("style.css");</style>
|
<style>@import url("style.css");</style>
|
||||||
@ -576,7 +699,7 @@ Length: <input type="number" name="XC${i}" id="xc${i}" class="l" min="1" max="65
|
|||||||
Enable automatic brightness limiter: <input type="checkbox" name="ABen" onchange="enABL()" id="able"><br>
|
Enable automatic brightness limiter: <input type="checkbox" name="ABen" onchange="enABL()" id="able"><br>
|
||||||
<div id="abl">
|
<div id="abl">
|
||||||
Maximum Current: <input name="MA" type="number" class="l" min="250" max="65000" oninput="UI()" required> mA<br>
|
Maximum Current: <input name="MA" type="number" class="l" min="250" max="65000" oninput="UI()" required> mA<br>
|
||||||
<div id="ampwarning" style="color: orange; display: none;">
|
<div id="ampwarning" class="warn" style="display: none;">
|
||||||
⚠ Your power supply provides high current.<br>
|
⚠ Your power supply provides high current.<br>
|
||||||
To improve the safety of your setup,<br>
|
To improve the safety of your setup,<br>
|
||||||
please use thick cables,<br>
|
please use thick cables,<br>
|
||||||
@ -604,14 +727,14 @@ Length: <input type="number" name="XC${i}" id="xc${i}" class="l" min="1" max="65
|
|||||||
<button type="button" id="-" onclick="addLEDs(-1,false)">-</button><br>
|
<button type="button" id="-" onclick="addLEDs(-1,false)">-</button><br>
|
||||||
LED Memory Usage: <span id="m0">0</span> / <span id="m1">?</span> B<br>
|
LED Memory Usage: <span id="m0">0</span> / <span id="m1">?</span> B<br>
|
||||||
<div id="dbar" style="display:inline-block; width: 100px; height: 10px; border-radius: 20px;"></div><br>
|
<div id="dbar" style="display:inline-block; width: 100px; height: 10px; border-radius: 20px;"></div><br>
|
||||||
<div id="ledwarning" style="color: orange; display: none;">
|
<div id="ledwarning" class="warn" style="display: none;">
|
||||||
⚠ You might run into stability or lag issues.<br>
|
⚠ You might run into stability or lag issues.<br>
|
||||||
Use less than <span id="wreason">800 LEDs per output</span> for the best experience!<br>
|
Use less than <span id="wreason">800 LEDs per output</span> for the best experience!<br>
|
||||||
</div>
|
</div>
|
||||||
<hr class="sml">
|
<hr class="sml">
|
||||||
Make a segment for each output: <input type="checkbox" name="MS"><br>
|
Make a segment for each output: <input type="checkbox" name="MS"><br>
|
||||||
Custom bus start indices: <input type="checkbox" onchange="tglSi(this.checked)" id="si"><br>
|
Custom bus start indices: <input type="checkbox" onchange="tglSi(this.checked)" id="si"><br>
|
||||||
Use global LED buffer: <input type="checkbox" name="LD"><br>
|
Use global LED buffer: <input type="checkbox" name="LD" onchange="UI()"><br>
|
||||||
<hr class="sml">
|
<hr class="sml">
|
||||||
<div id="color_order_mapping">
|
<div id="color_order_mapping">
|
||||||
Color Order Override:
|
Color Order Override:
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<title>PIN required</title>
|
<title>PIN required</title>
|
||||||
<script>
|
<script>
|
||||||
var d = document;
|
var d = document;
|
||||||
function B() { window.open("/settings","_self"); }
|
function B() { window.open("../settings","_self"); }
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
@import url("style.css");
|
@import url("style.css");
|
||||||
|
@ -7,10 +7,10 @@
|
|||||||
<title>Misc Settings</title>
|
<title>Misc Settings</title>
|
||||||
<script>
|
<script>
|
||||||
var d = document;
|
var d = document;
|
||||||
var loc = false, locip;
|
var loc = false, locip, locproto = "http:";
|
||||||
function H() { window.open("https://kno.wled.ge/features/settings/#security-settings"); }
|
function H() { window.open("https://kno.wled.ge/features/settings/#security-settings"); }
|
||||||
function B() { window.open("/settings","_self"); }
|
function B() { window.open(getURL("/settings"),"_self"); }
|
||||||
function U() { window.open("/update","_self"); }
|
function U() { window.open(getURL("/update"),"_self"); }
|
||||||
function gId(s) { return d.getElementById(s); }
|
function gId(s) { return d.getElementById(s); }
|
||||||
function isObj(o) { return (o && typeof o === 'object' && !Array.isArray(o)); }
|
function isObj(o) { return (o && typeof o === 'object' && !Array.isArray(o)); }
|
||||||
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
||||||
@ -47,7 +47,7 @@
|
|||||||
var req = new XMLHttpRequest();
|
var req = new XMLHttpRequest();
|
||||||
req.addEventListener('load', function(){showToast(this.responseText,this.status >= 400)});
|
req.addEventListener('load', function(){showToast(this.responseText,this.status >= 400)});
|
||||||
req.addEventListener('error', function(e){showToast(e.stack,true);});
|
req.addEventListener('error', function(e){showToast(e.stack,true);});
|
||||||
req.open("POST", "/upload");
|
req.open("POST", getURL("/upload"));
|
||||||
var formData = new FormData();
|
var formData = new FormData();
|
||||||
formData.append("data", fO.files[0], name);
|
formData.append("data", fO.files[0], name);
|
||||||
req.send(formData);
|
req.send(formData);
|
||||||
@ -65,16 +65,33 @@
|
|||||||
x.setAttribute("download","wled_" + x.getAttribute("download") + (sd=="WLED"?"":("_" +sd)));
|
x.setAttribute("download","wled_" + x.getAttribute("download") + (sd=="WLED"?"":("_" +sd)));
|
||||||
}
|
}
|
||||||
function S() {
|
function S() {
|
||||||
if (window.location.protocol == "file:") {
|
let l = window.location;
|
||||||
|
if (l.protocol == "file:") {
|
||||||
loc = true;
|
loc = true;
|
||||||
locip = localStorage.getItem('locIp');
|
locip = localStorage.getItem('locIp');
|
||||||
if (!locip) {
|
if (!locip) {
|
||||||
locip = prompt("File Mode. Please enter WLED IP!");
|
locip = prompt("File Mode. Please enter WLED IP!");
|
||||||
localStorage.setItem('locIp', locip);
|
localStorage.setItem('locIp', locip);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// detect reverse proxy
|
||||||
|
let path = l.pathname;
|
||||||
|
let paths = path.slice(1,path.endsWith('/')?-1:undefined).split("/");
|
||||||
|
if (paths.length > 2) {
|
||||||
|
locproto = l.protocol;
|
||||||
|
loc = true;
|
||||||
|
locip = l.hostname + (l.port ? ":" + l.port : "") + "/" + paths[0];
|
||||||
}
|
}
|
||||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=6';
|
}
|
||||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
if (loc) {
|
||||||
|
gId("bckcfg").setAttribute('href',getURL(gId("bckcfg").pathname));
|
||||||
|
gId("bckpresets").setAttribute('href',getURL(gId("bckpresets").pathname));
|
||||||
|
}
|
||||||
|
loadJS(getURL('/settings/s.js?p=6'), false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||||
|
if (loc) d.Sf.action = getURL('/settings/sec');
|
||||||
|
}
|
||||||
|
function getURL(path) {
|
||||||
|
return (loc ? locproto + "//" + locip : "") + path;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>
|
<style>
|
||||||
@ -89,7 +106,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<h2>Security & Update setup</h2>
|
<h2>Security & Update setup</h2>
|
||||||
Settings PIN: <input type="password" id="PIN" name="PIN" size="4" maxlength="4" minlength="4" onkeydown="checkNum(this)" pattern="[0-9]*" inputmode="numeric" title="Please enter a 4 digit number"><br>
|
Settings PIN: <input type="password" id="PIN" name="PIN" size="4" maxlength="4" minlength="4" onkeydown="checkNum(this)" pattern="[0-9]*" inputmode="numeric" title="Please enter a 4 digit number"><br>
|
||||||
<div style="color: #fa0;">⚠ Unencrypted transmission. Be prudent when selecting PIN, do NOT use your banking, door, SIM, etc. pin!</div><br>
|
<div class="warn">⚠ Unencrypted transmission. Be prudent when selecting PIN, do NOT use your banking, door, SIM, etc. pin!</div><br>
|
||||||
Lock wireless (OTA) software update: <input type="checkbox" name="NO"><br>
|
Lock wireless (OTA) software update: <input type="checkbox" name="NO"><br>
|
||||||
Passphrase: <input type="password" name="OP" maxlength="32"><br>
|
Passphrase: <input type="password" name="OP" maxlength="32"><br>
|
||||||
To enable OTA, for security reasons you need to also enter the correct password!<br>
|
To enable OTA, for security reasons you need to also enter the correct password!<br>
|
||||||
@ -99,7 +116,7 @@
|
|||||||
Deny access to WiFi settings if locked: <input type="checkbox" name="OW"><br><br>
|
Deny access to WiFi settings if locked: <input type="checkbox" name="OW"><br><br>
|
||||||
Factory reset: <input type="checkbox" name="RS"><br>
|
Factory reset: <input type="checkbox" name="RS"><br>
|
||||||
All settings and presets will be erased.<br><br>
|
All settings and presets will be erased.<br><br>
|
||||||
<div style="color: #fa0;">⚠ Unencrypted transmission. An attacker on the same network can intercept form data!</div>
|
<div class="warn">⚠ Unencrypted transmission. An attacker on the same network can intercept form data!</div>
|
||||||
<hr>
|
<hr>
|
||||||
<h3>Software Update</h3>
|
<h3>Software Update</h3>
|
||||||
<button type="button" onclick="U()">Manual OTA Update</button><br>
|
<button type="button" onclick="U()">Manual OTA Update</button><br>
|
||||||
@ -110,7 +127,7 @@
|
|||||||
<div>Restore presets<br><input type="file" name="data" accept=".json"> <button type="button" onclick="uploadFile(d.Sf.data,'/presets.json');">Upload</button><br></div><br>
|
<div>Restore presets<br><input type="file" name="data" accept=".json"> <button type="button" onclick="uploadFile(d.Sf.data,'/presets.json');">Upload</button><br></div><br>
|
||||||
<a class="btn lnk" id="bckpresets" href="/cfg.json" download="cfg">Backup configuration</a><br>
|
<a class="btn lnk" id="bckpresets" href="/cfg.json" download="cfg">Backup configuration</a><br>
|
||||||
<div>Restore configuration<br><input type="file" name="data2" accept=".json"> <button type="button" onclick="uploadFile(d.Sf.data2,'/cfg.json');">Upload</button><br></div>
|
<div>Restore configuration<br><input type="file" name="data2" accept=".json"> <button type="button" onclick="uploadFile(d.Sf.data2,'/cfg.json');">Upload</button><br></div>
|
||||||
<div style="color: #fa0;">⚠ Restoring presets/configuration will OVERWRITE your current presets/configuration.<br>
|
<div class="warn">⚠ Restoring presets/configuration will OVERWRITE your current presets/configuration.<br>
|
||||||
Incorrect configuration may require a factory reset or re-flashing of your ESP.</div>
|
Incorrect configuration may require a factory reset or re-flashing of your ESP.</div>
|
||||||
For security reasons, passwords are not backed up.
|
For security reasons, passwords are not backed up.
|
||||||
<hr>
|
<hr>
|
||||||
|
@ -6,11 +6,11 @@
|
|||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>Sync Settings</title>
|
<title>Sync Settings</title>
|
||||||
<script>var d=document;
|
<script>var d=document;
|
||||||
var loc = false, locip;
|
var loc = false, locip, locproto = "http:";
|
||||||
function gId(s){return d.getElementById(s);}
|
function gId(s){return d.getElementById(s);}
|
||||||
function toggle(el){gId(el).classList.toggle("hide"); gId('No'+el).classList.toggle("hide");}
|
function toggle(el){gId(el).classList.toggle("hide"); gId('No'+el).classList.toggle("hide");}
|
||||||
function H(){window.open("https://kno.wled.ge/interfaces/udp-notifier/");}
|
function H(){window.open("https://kno.wled.ge/interfaces/udp-notifier/");}
|
||||||
function B(){window.open("/settings","_self");}
|
function B(){window.open(getURL("/settings"),"_self");}
|
||||||
function adj(){if (d.Sf.DI.value == 6454) {if (d.Sf.EU.value == 1) d.Sf.EU.value = 0;}
|
function adj(){if (d.Sf.DI.value == 6454) {if (d.Sf.EU.value == 1) d.Sf.EU.value = 0;}
|
||||||
else if (d.Sf.DI.value == 5568) {if (d.Sf.DA.value == 0) d.Sf.DA.value = 1; if (d.Sf.EU.value == 0) d.Sf.EU.value = 1;} }
|
else if (d.Sf.DI.value == 5568) {if (d.Sf.DA.value == 0) d.Sf.DA.value = 1; if (d.Sf.EU.value == 0) d.Sf.EU.value = 1;} }
|
||||||
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
||||||
@ -56,16 +56,28 @@
|
|||||||
function SP(){var p = d.Sf.DI.value; gId("xp").style.display = (p > 0)?"none":"block"; if (p > 0) d.Sf.EP.value = p;}
|
function SP(){var p = d.Sf.DI.value; gId("xp").style.display = (p > 0)?"none":"block"; if (p > 0) d.Sf.EP.value = p;}
|
||||||
function SetVal(){switch(parseInt(d.Sf.EP.value)){case 5568: d.Sf.DI.value = 5568; break; case 6454: d.Sf.DI.value = 6454; break; case 4048: d.Sf.DI.value = 4048; break; }; SP();FC();}
|
function SetVal(){switch(parseInt(d.Sf.EP.value)){case 5568: d.Sf.DI.value = 5568; break; case 6454: d.Sf.DI.value = 6454; break; case 4048: d.Sf.DI.value = 4048; break; }; SP();FC();}
|
||||||
function S(){
|
function S(){
|
||||||
if (window.location.protocol == "file:") {
|
let l = window.location;
|
||||||
|
if (l.protocol == "file:") {
|
||||||
loc = true;
|
loc = true;
|
||||||
locip = localStorage.getItem('locIp');
|
locip = localStorage.getItem('locIp');
|
||||||
if (!locip) {
|
if (!locip) {
|
||||||
locip = prompt("File Mode. Please enter WLED IP!");
|
locip = prompt("File Mode. Please enter WLED IP!");
|
||||||
localStorage.setItem('locIp', locip);
|
localStorage.setItem('locIp', locip);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// detect reverse proxy
|
||||||
|
let paths = l.pathname.slice(1,l.pathname.endsWith('/')?-1:undefined).split("/");
|
||||||
|
if (paths.length > 2) {
|
||||||
|
locproto = l.protocol;
|
||||||
|
loc = true;
|
||||||
|
locip = l.hostname + (l.port ? ":" + l.port : "") + "/" + paths[0];
|
||||||
}
|
}
|
||||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=4';
|
}
|
||||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
loadJS(getURL('/settings/s.js?p=4'), false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||||
|
if (loc) d.Sf.action = getURL('/settings/sync');
|
||||||
|
}
|
||||||
|
function getURL(path) {
|
||||||
|
return (loc ? locproto + "//" + locip : "") + path;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>@import url("style.css");</style>
|
<style>@import url("style.css");</style>
|
||||||
@ -172,7 +184,7 @@ Realtime LED offset: <input name="WO" type="number" min="-255" max="255" require
|
|||||||
<hr class="sml">
|
<hr class="sml">
|
||||||
<h3>Alexa Voice Assistant</h3>
|
<h3>Alexa Voice Assistant</h3>
|
||||||
<div id="NoAlexa" class="hide">
|
<div id="NoAlexa" class="hide">
|
||||||
<em style="color:#fa0;">This firmware build does not include Alexa support.<br></em><br>
|
<i class="warn">This firmware build does not include Alexa support.<br></i><br>
|
||||||
</div>
|
</div>
|
||||||
<div id="Alexa">
|
<div id="Alexa">
|
||||||
Emulate Alexa device: <input type="checkbox" name="AL"><br>
|
Emulate Alexa device: <input type="checkbox" name="AL"><br>
|
||||||
@ -180,7 +192,7 @@ Alexa invocation name: <input type="text" name="AI" maxlength="32"><br>
|
|||||||
Also emulate devices to call the first <input name="AP" type="number" class="s" min="0" max="9" required> presets<br><br>
|
Also emulate devices to call the first <input name="AP" type="number" class="s" min="0" max="9" required> presets<br><br>
|
||||||
</div>
|
</div>
|
||||||
<hr class="sml">
|
<hr class="sml">
|
||||||
<div style="color: #fa0;">⚠ <b>MQTT and Hue sync all connect to external hosts!<br>
|
<div class="warn">⚠ <b>MQTT and Hue sync all connect to external hosts!<br>
|
||||||
This may impact the responsiveness of WLED.</b><br>
|
This may impact the responsiveness of WLED.</b><br>
|
||||||
</div>
|
</div>
|
||||||
For best results, only use one of these services at a time.<br>
|
For best results, only use one of these services at a time.<br>
|
||||||
@ -188,7 +200,7 @@ For best results, only use one of these services at a time.<br>
|
|||||||
<hr class="sml">
|
<hr class="sml">
|
||||||
<h3>MQTT</h3>
|
<h3>MQTT</h3>
|
||||||
<div id="NoMQTT" class="hide">
|
<div id="NoMQTT" class="hide">
|
||||||
<em style="color:#fa0;">This firmware build does not include MQTT support.<br></em>
|
<i class="warn">This firmware build does not include MQTT support.<br></i>
|
||||||
</div>
|
</div>
|
||||||
<div id="MQTT">
|
<div id="MQTT">
|
||||||
Enable MQTT: <input type="checkbox" name="MQ"><br>
|
Enable MQTT: <input type="checkbox" name="MQ"><br>
|
||||||
@ -207,7 +219,7 @@ Retain brightness & color messages: <input type="checkbox" name="RT"><br>
|
|||||||
</div>
|
</div>
|
||||||
<h3>Philips Hue</h3>
|
<h3>Philips Hue</h3>
|
||||||
<div id="NoHue" class="hide">
|
<div id="NoHue" class="hide">
|
||||||
<em style="color:#fa0;">This firmware build does not include Philips Hue support.<br></em>
|
<em class="warn">This firmware build does not include Philips Hue support.<br></em>
|
||||||
</div>
|
</div>
|
||||||
<div id="Hue">
|
<div id="Hue">
|
||||||
<i>You can find the bridge IP and the light number in the 'About' section of the hue app.</i><br>
|
<i>You can find the bridge IP and the light number in the 'About' section of the hue app.</i><br>
|
||||||
|
@ -7,11 +7,11 @@
|
|||||||
<title>Time Settings</title>
|
<title>Time Settings</title>
|
||||||
<script>
|
<script>
|
||||||
var d=document;
|
var d=document;
|
||||||
var loc = false, locip;
|
var loc = false, locip, locproto = "http:";
|
||||||
var el=false;
|
var el=false;
|
||||||
var ms=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
|
var ms=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];
|
||||||
function H() { window.open("https://kno.wled.ge/features/settings/#time-settings"); }
|
function H() { window.open("https://kno.wled.ge/features/settings/#time-settings"); }
|
||||||
function B() { window.open("/settings","_self"); }
|
function B() { window.open(getURL("/settings"),"_self"); }
|
||||||
function gId(s) { return d.getElementById(s); }
|
function gId(s) { return d.getElementById(s); }
|
||||||
function gN(s) { return d.getElementsByName(s)[0]; }
|
function gN(s) { return d.getElementsByName(s)[0]; }
|
||||||
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
||||||
@ -33,16 +33,29 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
function S() {
|
function S() {
|
||||||
if (window.location.protocol == "file:") {
|
let l = window.location;
|
||||||
|
if (l.protocol == "file:") {
|
||||||
loc = true;
|
loc = true;
|
||||||
locip = localStorage.getItem('locIp');
|
locip = localStorage.getItem('locIp');
|
||||||
if (!locip) {
|
if (!locip) {
|
||||||
locip = prompt("File Mode. Please enter WLED IP!");
|
locip = prompt("File Mode. Please enter WLED IP!");
|
||||||
localStorage.setItem('locIp', locip);
|
localStorage.setItem('locIp', locip);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// detect reverse proxy
|
||||||
|
let path = l.pathname;
|
||||||
|
let paths = path.slice(1,path.endsWith('/')?-1:undefined).split("/");
|
||||||
|
if (paths.length > 2) {
|
||||||
|
locproto = l.protocol;
|
||||||
|
loc = true;
|
||||||
|
locip = l.hostname + (l.port ? ":" + l.port : "") + "/" + paths[0];
|
||||||
}
|
}
|
||||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=5';
|
}
|
||||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
loadJS(getURL('/settings/s.js?p=5'), false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||||
|
if (loc) d.Sf.action = getURL('/settings/time');
|
||||||
|
}
|
||||||
|
function getURL(path) {
|
||||||
|
return (loc ? locproto + "//" + locip : "") + path;
|
||||||
}
|
}
|
||||||
function expand(o,i)
|
function expand(o,i)
|
||||||
{
|
{
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
<title>UI Settings</title>
|
<title>UI Settings</title>
|
||||||
<script>
|
<script>
|
||||||
var d = document;
|
var d = document;
|
||||||
var loc = false, locip;
|
var loc = false, locip, locproto = "http:";
|
||||||
var initial_ds, initial_st, initial_su;
|
var initial_ds, initial_st, initial_su;
|
||||||
var sett = null;
|
var sett = null;
|
||||||
var l = {
|
var l = {
|
||||||
@ -185,21 +185,33 @@
|
|||||||
alert("Loading of configuration script failed.\nIncomplete page data!");
|
alert("Loading of configuration script failed.\nIncomplete page data!");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
function S()
|
function S() {
|
||||||
{
|
let l = window.location;
|
||||||
if (window.location.protocol == "file:") {
|
if (l.protocol == "file:") {
|
||||||
loc = true;
|
loc = true;
|
||||||
locip = localStorage.getItem('locIp');
|
locip = localStorage.getItem('locIp');
|
||||||
if (!locip) {
|
if (!locip) {
|
||||||
locip = prompt("File Mode. Please enter WLED IP!");
|
locip = prompt("File Mode. Please enter WLED IP!");
|
||||||
localStorage.setItem('locIp', locip);
|
localStorage.setItem('locIp', locip);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// detect reverse proxy
|
||||||
|
let path = l.pathname;
|
||||||
|
let paths = path.slice(1,path.endsWith('/')?-1:undefined).split("/");
|
||||||
|
if (paths.length > 2) {
|
||||||
|
locproto = l.protocol;
|
||||||
|
loc = true;
|
||||||
|
locip = l.hostname + (l.port ? ":" + l.port : "") + "/" + paths[0];
|
||||||
}
|
}
|
||||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=3';
|
}
|
||||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
loadJS(getURL('/settings/s.js?p=3'), false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||||
|
if (loc) d.Sf.action = getURL('/settings/ui');
|
||||||
|
}
|
||||||
|
function getURL(path) {
|
||||||
|
return (loc ? locproto + "//" + locip : "") + path;
|
||||||
}
|
}
|
||||||
function H() { window.open("https://kno.wled.ge/features/settings/#user-interface-settings"); }
|
function H() { window.open("https://kno.wled.ge/features/settings/#user-interface-settings"); }
|
||||||
function B() { window.open("/settings","_self"); }
|
function B() { window.open(getURL("/settings"),"_self"); }
|
||||||
function UI()
|
function UI()
|
||||||
{
|
{
|
||||||
gId('idonthateyou').style.display = (gId('dm').checked) ? 'inline':'none';
|
gId('idonthateyou').style.display = (gId('dm').checked) ? 'inline':'none';
|
||||||
@ -249,7 +261,7 @@
|
|||||||
Server description: <input type="text" name="DS" maxlength="32"><br>
|
Server description: <input type="text" name="DS" maxlength="32"><br>
|
||||||
Sync button toggles both send and receive: <input type="checkbox" name="ST"><br>
|
Sync button toggles both send and receive: <input type="checkbox" name="ST"><br>
|
||||||
<div id="NoSimple" class="hide">
|
<div id="NoSimple" class="hide">
|
||||||
<em style="color:#fa0;">This firmware build does not include simplified UI support.<br></em>
|
<i class="warn">This firmware build does not include simplified UI support.<br></i>
|
||||||
</div>
|
</div>
|
||||||
<div id="Simple">Enable simplified UI: <input type="checkbox" name="SU"><br></div>
|
<div id="Simple">Enable simplified UI: <input type="checkbox" name="SU"><br></div>
|
||||||
<i>The following UI customization settings are unique both to the WLED device and this browser.<br>
|
<i>The following UI customization settings are unique both to the WLED device and this browser.<br>
|
||||||
|
@ -7,19 +7,19 @@
|
|||||||
<title>Usermod Settings</title>
|
<title>Usermod Settings</title>
|
||||||
<script>
|
<script>
|
||||||
var d = document;
|
var d = document;
|
||||||
d.max_gpio = 39;
|
d.max_gpio = 50;
|
||||||
d.um_p = [];
|
d.um_p = [];
|
||||||
d.rsvd = [];
|
d.rsvd = [];
|
||||||
d.ro_gpio = [];
|
d.ro_gpio = [];
|
||||||
var umCfg = {};
|
var umCfg = {};
|
||||||
var pins = [], pinO = [], owner;
|
var pins = [], pinO = [], owner;
|
||||||
var loc = false, locip;
|
var loc = false, locip, locproto = "http:";
|
||||||
var urows;
|
var urows;
|
||||||
var numM = 0;
|
var numM = 0;
|
||||||
function gId(s) { return d.getElementById(s); }
|
function gId(s) { return d.getElementById(s); }
|
||||||
function isO(i) { return (i && typeof i === 'object' && !Array.isArray(i)); }
|
function isO(i) { return (i && typeof i === 'object' && !Array.isArray(i)); }
|
||||||
function H() { window.open("https://github.com/Aircoookie/WLED/wiki/Settings#usermod-settings"); }
|
function H() { window.open("https://github.com/Aircoookie/WLED/wiki/Settings#usermod-settings"); }
|
||||||
function B() { window.open("/settings","_self"); }
|
function B() { window.open(getURL("/settings"),"_self"); }
|
||||||
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
// https://www.educative.io/edpresso/how-to-dynamically-load-a-js-file-in-javascript
|
||||||
function loadJS(FILE_URL, async = true) {
|
function loadJS(FILE_URL, async = true) {
|
||||||
let scE = d.createElement("script");
|
let scE = d.createElement("script");
|
||||||
@ -39,6 +39,7 @@
|
|||||||
d.Sf.MISO.max = d.max_gpio;
|
d.Sf.MISO.max = d.max_gpio;
|
||||||
let inp = d.getElementsByTagName("input");
|
let inp = d.getElementsByTagName("input");
|
||||||
for (let i of inp) if (i.type === "number" && i.name.replace("[]","").substr(-3) === "pin") i.max = d.max_gpio;
|
for (let i of inp) if (i.type === "number" && i.name.replace("[]","").substr(-3) === "pin") i.max = d.max_gpio;
|
||||||
|
pinDropdowns();
|
||||||
});
|
});
|
||||||
// error event
|
// error event
|
||||||
scE.addEventListener("error", (ev) => {
|
scE.addEventListener("error", (ev) => {
|
||||||
@ -47,16 +48,30 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
function S() {
|
function S() {
|
||||||
if (window.location.protocol == "file:") {
|
let l = window.location;
|
||||||
|
if (l.protocol == "file:") {
|
||||||
loc = true;
|
loc = true;
|
||||||
locip = localStorage.getItem('locIp');
|
locip = localStorage.getItem('locIp');
|
||||||
if (!locip) {
|
if (!locip) {
|
||||||
locip = prompt("File Mode. Please enter WLED IP!");
|
locip = prompt("File Mode. Please enter WLED IP!");
|
||||||
localStorage.setItem('locIp', locip);
|
localStorage.setItem('locIp', locip);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// detect reverse proxy
|
||||||
|
let path = l.pathname;
|
||||||
|
let paths = path.slice(1,path.endsWith('/')?-1:undefined).split("/");
|
||||||
|
if (paths.length > 2) {
|
||||||
|
locproto = l.protocol;
|
||||||
|
loc = true;
|
||||||
|
locip = l.hostname + (l.port ? ":" + l.port : "") + "/" + paths[0];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ldS();
|
ldS();
|
||||||
if (!numM) gId("um").innerHTML = "No Usermods installed.";
|
if (!numM) gId("um").innerHTML = "No Usermods installed.";
|
||||||
|
if (loc) d.Sf.action = getURL('/settings/um');
|
||||||
|
}
|
||||||
|
function getURL(path) {
|
||||||
|
return (loc ? locproto + "//" + locip : "") + path;
|
||||||
}
|
}
|
||||||
// https://stackoverflow.com/questions/3885817/how-do-i-check-that-a-number-is-float-or-integer
|
// https://stackoverflow.com/questions/3885817/how-do-i-check-that-a-number-is-float-or-integer
|
||||||
function isF(n) { return n === +n && n !== (n|0); }
|
function isF(n) { return n === +n && n !== (n|0); }
|
||||||
@ -89,8 +104,10 @@
|
|||||||
if (isO(o)) {
|
if (isO(o)) {
|
||||||
for (const [k,v] of Object.entries(o)) {
|
for (const [k,v] of Object.entries(o)) {
|
||||||
if (isO(v)) {
|
if (isO(v)) {
|
||||||
|
let oldO = owner; // keep parent name
|
||||||
owner = k;
|
owner = k;
|
||||||
getPins(v);
|
getPins(v);
|
||||||
|
owner = oldO;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (k.replace("[]","").substr(-3)=="pin") {
|
if (k.replace("[]","").substr(-3)=="pin") {
|
||||||
@ -149,11 +166,67 @@
|
|||||||
urows += `<input type="${t==="int"?"number":t}" name="${k}:${f}${a?"[]":""}" ${c} oninput="check(this,'${k.substr(k.indexOf(":")+1)}')"><br>`;
|
urows += `<input type="${t==="int"?"number":t}" name="${k}:${f}${a?"[]":""}" ${c} oninput="check(this,'${k.substr(k.indexOf(":")+1)}')"><br>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
function pinDropdowns() {
|
||||||
|
for (let i of d.Sf.elements) {
|
||||||
|
if (i.type === "number" && (i.name.includes("pin") || ["SDA","SCL","MOSI","MISO","SCLK"].includes(i.name))) { //select all pin select elements
|
||||||
|
let v = parseInt(i.value);
|
||||||
|
let sel = addDropdown(i.name,0);
|
||||||
|
for (var j = -1; j <= d.max_gpio; j++) {
|
||||||
|
if (d.rsvd.includes(j)) continue;
|
||||||
|
let foundPin = pins.indexOf(j);
|
||||||
|
let txt = (j === -1) ? "unused" : `${j}`;
|
||||||
|
if (foundPin >= 0 && j !== v) txt += ` ${pinO[foundPin]=="if"?"global":pinO[foundPin]}`; // already reserved pin
|
||||||
|
if (d.ro_gpio.includes(j)) txt += " (R/O)";
|
||||||
|
let opt = addOption(sel, txt, j);
|
||||||
|
if (j === v) opt.selected = true; // this is "our" pin
|
||||||
|
else if (pins.includes(j)) opt.disabled = true; // someone else's pin
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function UI(e) {
|
||||||
|
// update changed select options across all usermods
|
||||||
|
let oldV = parseInt(e.dataset.val);
|
||||||
|
e.dataset.val = e.value;
|
||||||
|
let txt = e.name.split(":")[e.name.split(":").length-2];
|
||||||
|
let selects = d.Sf.querySelectorAll("select[class='pin']");
|
||||||
|
for (let sel of selects) {
|
||||||
|
if (sel == e) continue
|
||||||
|
Array.from(sel.options).forEach((i)=>{
|
||||||
|
if (!(i.value==oldV || i.value==e.value)) return;
|
||||||
|
if (i.value == -1) {
|
||||||
|
i.text = "unused";
|
||||||
|
return
|
||||||
|
}
|
||||||
|
i.text = i.value;
|
||||||
|
if (i.value==oldV) {
|
||||||
|
i.disabled = false;
|
||||||
|
}
|
||||||
|
if (i.value==e.value) {
|
||||||
|
i.disabled = true;
|
||||||
|
i.text += ` ${txt}`;
|
||||||
|
}
|
||||||
|
if (d.ro_gpio.includes(parseInt(i.value))) i.text += " (R/O)";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
// https://stackoverflow.com/questions/39729741/javascript-change-input-text-to-select-option
|
// https://stackoverflow.com/questions/39729741/javascript-change-input-text-to-select-option
|
||||||
function addDropdown(um,fld) {
|
function addDropdown(um,fld) {
|
||||||
let sel = d.createElement('select');
|
let sel = d.createElement('select');
|
||||||
let arr = d.getElementsByName(um+":"+fld);
|
if (typeof(fld) === "string") { // parameter from usermod (field name)
|
||||||
let inp = arr[1]; // assume 1st field to be hidden (type)
|
if (fld.includes("pin")) sel.classList.add("pin");
|
||||||
|
um += ":"+fld;
|
||||||
|
} else if (typeof(fld) === "number") sel.classList.add("pin"); // a hack to add a class
|
||||||
|
let arr = d.getElementsByName(um);
|
||||||
|
let idx = arr[0].type==="hidden"?1:0; // ignore hidden field
|
||||||
|
if (arr.length > 2) {
|
||||||
|
// we have array of values (usually pins)
|
||||||
|
for (let i of arr) {
|
||||||
|
if (i.type === "number") break;
|
||||||
|
idx++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let inp = arr[idx];
|
||||||
if (inp && inp.tagName === "INPUT" && (inp.type === "text" || inp.type === "number")) { // may also use nodeName
|
if (inp && inp.tagName === "INPUT" && (inp.type === "text" || inp.type === "number")) { // may also use nodeName
|
||||||
let v = inp.value;
|
let v = inp.value;
|
||||||
let n = inp.name;
|
let n = inp.name;
|
||||||
@ -167,8 +240,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
sel.setAttribute("data-val", v);
|
sel.setAttribute("data-val", v);
|
||||||
|
sel.setAttribute("onchange", "UI(this)");
|
||||||
// finally, replace the old input element with the new select element
|
// finally, replace the old input element with the new select element
|
||||||
inp.parentElement.replaceChild(sel, inp);
|
inp.parentElement.replaceChild(sel, inp);
|
||||||
|
if (arr[0].type==="hidden") arr[0].parentElement.removeChild(arr[0]); // remove hidden element from DOM
|
||||||
return sel;
|
return sel;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@ -183,6 +258,7 @@
|
|||||||
let c = sel.childNodes[i];
|
let c = sel.childNodes[i];
|
||||||
if (c.value == sel.dataset.val) sel.selectedIndex = i;
|
if (c.value == sel.dataset.val) sel.selectedIndex = i;
|
||||||
}
|
}
|
||||||
|
return opt;
|
||||||
}
|
}
|
||||||
// https://stackoverflow.com/questions/26440494/insert-text-after-this-input-element-with-javascript
|
// https://stackoverflow.com/questions/26440494/insert-text-after-this-input-element-with-javascript
|
||||||
function addInfo(name,el,txt, txt2="") {
|
function addInfo(name,el,txt, txt2="") {
|
||||||
@ -194,10 +270,13 @@
|
|||||||
if (txt2!="") obj[el].insertAdjacentHTML('beforebegin', txt2 + ' '); //add pre texts
|
if (txt2!="") obj[el].insertAdjacentHTML('beforebegin', txt2 + ' '); //add pre texts
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// add Help Button
|
||||||
|
function addHB(um) {
|
||||||
|
addInfo(um + ':help',0,`<button onclick="location.href='https://kno.wled.ge/usermods/${um}'" type="button">?</button>`);
|
||||||
|
}
|
||||||
// load settings and insert values into DOM
|
// load settings and insert values into DOM
|
||||||
function ldS() {
|
function ldS() {
|
||||||
var url = (loc?`http://${locip}`:'') + '/cfg.json';
|
fetch(getURL('/cfg.json'), {
|
||||||
fetch(url, {
|
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
@ -216,8 +295,7 @@
|
|||||||
}
|
}
|
||||||
if (urows==="") urows = "Usermods configuration not found.<br>Press <i>Save</i> to initialize defaults.";
|
if (urows==="") urows = "Usermods configuration not found.<br>Press <i>Save</i> to initialize defaults.";
|
||||||
gId("um").innerHTML = urows;
|
gId("um").innerHTML = urows;
|
||||||
var url = (loc?`http://${locip}`:'') + '/settings/s.js?p=8';
|
loadJS(getURL('/settings/s.js?p=8'), false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
|
||||||
})
|
})
|
||||||
.catch((error)=>{
|
.catch((error)=>{
|
||||||
gId('lserr').style.display = "inline";
|
gId('lserr').style.display = "inline";
|
||||||
@ -242,15 +320,17 @@
|
|||||||
</div>
|
</div>
|
||||||
<h2>Usermod Setup</h2>
|
<h2>Usermod Setup</h2>
|
||||||
Global I<sup>2</sup>C GPIOs (HW)<br>
|
Global I<sup>2</sup>C GPIOs (HW)<br>
|
||||||
<i style="color: orange;">(only changable on ESP32, change requires reboot!)</i><br>
|
<i class="warn">(change requires reboot!)</i><br>
|
||||||
SDA:<input type="number" min="-1" max="48" name="SDA" onchange="check(this,'if')" class="s" placeholder="SDA">
|
SDA:<input type="number" min="-1" max="48" name="SDA" onchange="check(this,'if')" class="s" placeholder="SDA">
|
||||||
SCL:<input type="number" min="-1" max="48" name="SCL" onchange="check(this,'if')" class="s" placeholder="SCL">
|
SCL:<input type="number" min="-1" max="48" name="SCL" onchange="check(this,'if')" class="s" placeholder="SCL">
|
||||||
<hr class="sml">
|
<hr class="sml">
|
||||||
Global SPI GPIOs (HW)<br>
|
Global SPI GPIOs (HW)<br>
|
||||||
<i style="color: orange;">(only changable on ESP32, change requires reboot!)</i><br>
|
<i class="warn">(only changable on ESP32, change requires reboot!)</i><br>
|
||||||
MOSI:<input type="number" min="-1" max="48" name="MOSI" onchange="check(this,'if')" class="s" placeholder="MOSI">
|
MOSI:<input type="number" min="-1" max="48" name="MOSI" onchange="check(this,'if')" class="s" placeholder="MOSI">
|
||||||
MISO:<input type="number" min="-1" max="48" name="MISO" onchange="check(this,'if')" class="s" placeholder="MISO">
|
MISO:<input type="number" min="-1" max="48" name="MISO" onchange="check(this,'if')" class="s" placeholder="MISO">
|
||||||
SCLK:<input type="number" min="-1" max="48" name="SCLK" onchange="check(this,'if')" class="s" placeholder="SCLK">
|
SCLK:<input type="number" min="-1" max="48" name="SCLK" onchange="check(this,'if')" class="s" placeholder="SCLK">
|
||||||
|
<hr class="sml">
|
||||||
|
Reboot after save? <input type="checkbox" name="RBT"><br>
|
||||||
<div id="um">Loading settings...</div>
|
<div id="um">Loading settings...</div>
|
||||||
<hr><button type="button" onclick="B()">Back</button><button type="submit">Save</button>
|
<hr><button type="button" onclick="B()">Back</button><button type="submit">Save</button>
|
||||||
</form>
|
</form>
|
||||||
|
@ -7,21 +7,19 @@
|
|||||||
<title>WiFi Settings</title>
|
<title>WiFi Settings</title>
|
||||||
<script>
|
<script>
|
||||||
var d = document;
|
var d = document;
|
||||||
var loc = false, locip;
|
var loc = false, locip, locproto = "http:";
|
||||||
var scanLoops = 0, preScanSSID = "";
|
var scanLoops = 0, preScanSSID = "";
|
||||||
|
|
||||||
function gId(e) { return d.getElementById(e); }
|
function gId(e) { return d.getElementById(e); }
|
||||||
function cE(e) { return d.createElement(e); }
|
function cE(e) { return d.createElement(e); }
|
||||||
function H(){window.open("https://kno.wled.ge/features/settings/#wifi-settings");}
|
function H(){window.open("https://kno.wled.ge/features/settings/#wifi-settings");}
|
||||||
function B(){window.open("/settings","_self");}
|
function B(){window.open(getURL("/settings"),"_self");}
|
||||||
function N() {
|
function N() {
|
||||||
const url = (loc?`http://${locip}`:"") + "/json/net";
|
|
||||||
|
|
||||||
const button = gId("scan");
|
const button = gId("scan");
|
||||||
button.disabled = true;
|
button.disabled = true;
|
||||||
button.textContent = "Scanning...";
|
button.textContent = "Scanning...";
|
||||||
|
|
||||||
fetch(url).then((response) => {
|
fetch(getURL("/json/net")).then((response) => {
|
||||||
return response.json();
|
return response.json();
|
||||||
}).then((json) => {
|
}).then((json) => {
|
||||||
// Get the list of networks only, defaulting to an empty array.
|
// Get the list of networks only, defaulting to an empty array.
|
||||||
@ -122,16 +120,29 @@
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
function S() {
|
function S() {
|
||||||
if (window.location.protocol == "file:") {
|
let l = window.location;
|
||||||
|
if (l.protocol == "file:") {
|
||||||
loc = true;
|
loc = true;
|
||||||
locip = localStorage.getItem("locIp");
|
locip = localStorage.getItem('locIp');
|
||||||
if (!locip) {
|
if (!locip) {
|
||||||
locip = prompt("File Mode. Please enter WLED IP!");
|
locip = prompt("File Mode. Please enter WLED IP!");
|
||||||
localStorage.setItem("locIp", locip);
|
localStorage.setItem('locIp', locip);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// detect reverse proxy
|
||||||
|
let path = l.pathname;
|
||||||
|
let paths = path.slice(1,path.endsWith('/')?-1:undefined).split("/");
|
||||||
|
if (paths.length > 2) {
|
||||||
|
locproto = l.protocol;
|
||||||
|
loc = true;
|
||||||
|
locip = l.hostname + (l.port ? ":" + l.port : "") + "/" + paths[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let url = (loc?`http://${locip}`:'') + '/settings/s.js?p=1';
|
loadJS(getURL('/settings/s.js?p=1'), false); // If we set async false, file is loaded and executed, then next statement is processed
|
||||||
loadJS(url, false); // If we set async false, file is loaded and executed, then next statement is processed
|
if (loc) d.Sf.action = getURL('/settings/wifi');
|
||||||
|
}
|
||||||
|
function getURL(path) {
|
||||||
|
return (loc ? locproto + "//" + locip : "") + path;
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<style>@import url("style.css");</style>
|
<style>@import url("style.css");</style>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
//page js
|
//page js
|
||||||
var loc = false, locip;
|
var loc = false, locip, locproto = "http:";
|
||||||
var noNewSegs = false;
|
var noNewSegs = false;
|
||||||
var isOn = false, isInfo = false, isNodes = false, isRgbw = false, cct = false;
|
var isOn = false, isInfo = false, isNodes = false, isRgbw = false, cct = false;
|
||||||
var whites = [0,0,0];
|
var whites = [0,0,0];
|
||||||
@ -148,22 +148,38 @@ function loadSkinCSS(cId)
|
|||||||
l.id = cId;
|
l.id = cId;
|
||||||
l.rel = 'stylesheet';
|
l.rel = 'stylesheet';
|
||||||
l.type = 'text/css';
|
l.type = 'text/css';
|
||||||
l.href = (loc?`http://${locip}`:'.') + '/skin.css';
|
l.href = getURL('/skin.css');
|
||||||
l.media = 'all';
|
l.media = 'all';
|
||||||
h.appendChild(l);
|
h.appendChild(l);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getURL(path) {
|
||||||
|
return (loc ? locproto + "//" + locip : "") + path;
|
||||||
|
}
|
||||||
async function onLoad()
|
async function onLoad()
|
||||||
{
|
{
|
||||||
if (window.location.protocol == "file:") {
|
let l = window.location;
|
||||||
|
if (l.protocol == "file:") {
|
||||||
loc = true;
|
loc = true;
|
||||||
locip = localStorage.getItem('locIp');
|
locip = localStorage.getItem('locIp');
|
||||||
if (!locip)
|
if (!locip) {
|
||||||
{
|
|
||||||
locip = prompt("File Mode. Please enter WLED IP!");
|
locip = prompt("File Mode. Please enter WLED IP!");
|
||||||
localStorage.setItem('locIp', locip);
|
localStorage.setItem('locIp', locip);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// detect reverse proxy and/or HTTPS
|
||||||
|
let pathn = l.pathname;
|
||||||
|
let paths = pathn.slice(1,pathn.endsWith('/')?-1:undefined).split("/");
|
||||||
|
//while (paths[0]==="") paths.shift();
|
||||||
|
locproto = l.protocol;
|
||||||
|
locip = l.hostname + (l.port ? ":" + l.port : "");
|
||||||
|
if (paths.length > 0 && paths[0]!=="") {
|
||||||
|
loc = true;
|
||||||
|
locip += "/" + paths[0];
|
||||||
|
} else if (locproto==="https:") {
|
||||||
|
loc = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
var sett = localStorage.getItem('wledUiCfg');
|
var sett = localStorage.getItem('wledUiCfg');
|
||||||
if (sett) cfg = mergeDeep(cfg, JSON.parse(sett));
|
if (sett) cfg = mergeDeep(cfg, JSON.parse(sett));
|
||||||
@ -173,7 +189,7 @@ async function onLoad()
|
|||||||
applyCfg();
|
applyCfg();
|
||||||
if (cfg.theme.bg.url=="" || cfg.theme.bg.url === "https://picsum.photos/1920/1080") {
|
if (cfg.theme.bg.url=="" || cfg.theme.bg.url === "https://picsum.photos/1920/1080") {
|
||||||
var iUrl = cfg.theme.bg.url;
|
var iUrl = cfg.theme.bg.url;
|
||||||
fetch((loc?`http://${locip}`:'.') + "/holidays.json", {
|
fetch(getURL("/holidays.json"), {
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
.then((res)=>{
|
.then((res)=>{
|
||||||
@ -330,9 +346,7 @@ function loadPresets(callback = null)
|
|||||||
|
|
||||||
pmtLast = pmt;
|
pmtLast = pmt;
|
||||||
|
|
||||||
var url = (loc?`http://${locip}`:'') + '/presets.json';
|
fetch(getURL('/presets.json'), {
|
||||||
|
|
||||||
fetch(url, {
|
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
@ -355,9 +369,7 @@ function loadPresets(callback = null)
|
|||||||
|
|
||||||
function loadPalettes(callback = null)
|
function loadPalettes(callback = null)
|
||||||
{
|
{
|
||||||
var url = (loc?`http://${locip}`:'') + '/json/palettes';
|
fetch(getURL('/json/palettes'), {
|
||||||
|
|
||||||
fetch(url, {
|
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
@ -379,9 +391,7 @@ function loadPalettes(callback = null)
|
|||||||
|
|
||||||
function loadFX(callback = null)
|
function loadFX(callback = null)
|
||||||
{
|
{
|
||||||
var url = (loc?`http://${locip}`:'') + '/json/effects';
|
fetch(getURL('/json/effects'), {
|
||||||
|
|
||||||
fetch(url, {
|
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
@ -403,9 +413,7 @@ function loadFX(callback = null)
|
|||||||
|
|
||||||
function loadFXData(callback = null)
|
function loadFXData(callback = null)
|
||||||
{
|
{
|
||||||
var url = (loc?`http://${locip}`:'') + '/json/fxdata';
|
fetch(getURL('/json/fxdata'), {
|
||||||
|
|
||||||
fetch(url, {
|
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
@ -611,8 +619,7 @@ function populateNodes(i,n)
|
|||||||
|
|
||||||
function loadNodes()
|
function loadNodes()
|
||||||
{
|
{
|
||||||
var url = (loc?`http://${locip}`:'') + '/json/nodes';
|
fetch(getURL('/json/nodes'), {
|
||||||
fetch(url, {
|
|
||||||
method: 'get'
|
method: 'get'
|
||||||
})
|
})
|
||||||
.then(res => {
|
.then(res => {
|
||||||
@ -855,7 +862,8 @@ function cmpP(a, b)
|
|||||||
|
|
||||||
function makeWS() {
|
function makeWS() {
|
||||||
if (ws) return;
|
if (ws) return;
|
||||||
ws = new WebSocket('ws://'+(loc?locip:window.location.hostname)+'/ws');
|
let url = loc ? getURL('/ws').replace("http","ws") : "ws://"+window.location.hostname+"/ws";
|
||||||
|
ws = new WebSocket(url);
|
||||||
ws.onmessage = (e)=>{
|
ws.onmessage = (e)=>{
|
||||||
var json = JSON.parse(e.data);
|
var json = JSON.parse(e.data);
|
||||||
if (json.leds) return; //liveview packet
|
if (json.leds) return; //liveview packet
|
||||||
@ -974,7 +982,6 @@ function requestJson(command=null)
|
|||||||
if (command && !reqsLegal) return; //stop post requests from chrome onchange event on page restore
|
if (command && !reqsLegal) return; //stop post requests from chrome onchange event on page restore
|
||||||
if (!jsonTimeout) jsonTimeout = setTimeout(showErrorToast, 3000);
|
if (!jsonTimeout) jsonTimeout = setTimeout(showErrorToast, 3000);
|
||||||
var req = null;
|
var req = null;
|
||||||
var url = (loc?`http://${locip}`:'') + '/json/si';
|
|
||||||
var useWs = (ws && ws.readyState === WebSocket.OPEN);
|
var useWs = (ws && ws.readyState === WebSocket.OPEN);
|
||||||
var type = command ? 'post':'get';
|
var type = command ? 'post':'get';
|
||||||
if (command) {
|
if (command) {
|
||||||
@ -991,7 +998,7 @@ function requestJson(command=null)
|
|||||||
setTimeout(requestJson,200);
|
setTimeout(requestJson,200);
|
||||||
}
|
}
|
||||||
|
|
||||||
fetch(url, {
|
fetch(getURL('/json/si'), {
|
||||||
method: type,
|
method: type,
|
||||||
headers: {
|
headers: {
|
||||||
"Content-type": "application/json; charset=UTF-8"
|
"Content-type": "application/json; charset=UTF-8"
|
||||||
@ -1314,9 +1321,7 @@ function loadPalettesData(callback = null)
|
|||||||
|
|
||||||
function getPalettesData(page, callback)
|
function getPalettesData(page, callback)
|
||||||
{
|
{
|
||||||
var url = (loc?`http://${locip}`:'') + `/json/palx?page=${page}`;
|
fetch(getURL(`/json/palx?page=${page}`), {
|
||||||
|
|
||||||
fetch(url, {
|
|
||||||
method: 'get',
|
method: 'get',
|
||||||
headers: {
|
headers: {
|
||||||
"Content-type": "application/json; charset=UTF-8"
|
"Content-type": "application/json; charset=UTF-8"
|
||||||
|
@ -61,6 +61,12 @@ button.sml {
|
|||||||
.hide {
|
.hide {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
.err {
|
||||||
|
color: #f00;
|
||||||
|
}
|
||||||
|
.warn {
|
||||||
|
color: #fa0;
|
||||||
|
}
|
||||||
input {
|
input {
|
||||||
background: #333;
|
background: #333;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
@ -114,6 +120,10 @@ select {
|
|||||||
font-family: Verdana, sans-serif;
|
font-family: Verdana, sans-serif;
|
||||||
border: 0.5ch solid #333;
|
border: 0.5ch solid #333;
|
||||||
}
|
}
|
||||||
|
select.pin {
|
||||||
|
max-width: 120px;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
tr {
|
tr {
|
||||||
line-height: 100%;
|
line-height: 100%;
|
||||||
}
|
}
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
|
|
||||||
<body onload="GetV()">
|
<body onload="GetV()">
|
||||||
<h2>WLED Software Update</h2>
|
<h2>WLED Software Update</h2>
|
||||||
<form method='POST' action='/update' id='uf' enctype='multipart/form-data' onsubmit="U()">
|
<form method='POST' action='./update' id='uf' enctype='multipart/form-data' onsubmit="U()">
|
||||||
Installed version: <span class="sip">##VERSION##</span><br>
|
Installed version: <span class="sip">##VERSION##</span><br>
|
||||||
Download the latest binary: <a href="https://github.com/Aircoookie/WLED/releases" target="_blank">
|
Download the latest binary: <a href="https://github.com/Aircoookie/WLED/releases" target="_blank">
|
||||||
<img src="https://img.shields.io/github/release/Aircoookie/WLED.svg?style=flat-square"></a><br>
|
<img src="https://img.shields.io/github/release/Aircoookie/WLED.svg?style=flat-square"></a><br>
|
||||||
|
@ -55,9 +55,9 @@
|
|||||||
<h3>Thank you for installing my application!</h3>
|
<h3>Thank you for installing my application!</h3>
|
||||||
<b>Next steps:</b><br><br>
|
<b>Next steps:</b><br><br>
|
||||||
Connect the module to your local WiFi here!<br>
|
Connect the module to your local WiFi here!<br>
|
||||||
<button onclick="window.location.href='/settings/wifi'">WiFi settings</button><br>
|
<button onclick="window.location.href='./settings/wifi'">WiFi settings</button><br>
|
||||||
<i>Just trying this out in AP mode?</i><br>
|
<i>Just trying this out in AP mode?</i><br>
|
||||||
<button onclick="window.location.href='/sliders'">To the controls!</button><br>
|
<button onclick="window.location.href='./sliders'">To the controls!</button><br>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -25,7 +25,7 @@ void handleDDPPacket(e131_packet_t* p) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t ddpChannelsPerLed = (p->dataType & 0b00111000 == 0b011) ? 4 : 3; // data type 0x1B (formerly 0x1A) is RGBW (type 3, 8 bit/channel)
|
uint8_t ddpChannelsPerLed = ((p->dataType & 0b00111000)>>3 == 0b011) ? 4 : 3; // data type 0x1B (formerly 0x1A) is RGBW (type 3, 8 bit/channel)
|
||||||
|
|
||||||
uint32_t start = htonl(p->channelOffset) / ddpChannelsPerLed;
|
uint32_t start = htonl(p->channelOffset) / ddpChannelsPerLed;
|
||||||
start += DMXAddress / ddpChannelsPerLed;
|
start += DMXAddress / ddpChannelsPerLed;
|
||||||
|
@ -50,6 +50,18 @@ bool getJsonValue(const JsonVariant& element, DestType& destination, const Defau
|
|||||||
|
|
||||||
|
|
||||||
//colors.cpp
|
//colors.cpp
|
||||||
|
// similar to NeoPixelBus NeoGammaTableMethod but allows dynamic changes (superseded by NPB::NeoGammaDynamicTableMethod)
|
||||||
|
class NeoGammaWLEDMethod {
|
||||||
|
public:
|
||||||
|
static uint8_t Correct(uint8_t value); // apply Gamma to single channel
|
||||||
|
static uint32_t Correct32(uint32_t color); // apply Gamma to RGBW32 color (WLED specific, not used by NPB)
|
||||||
|
static void calcGammaTable(float gamma); // re-calculates & fills gamma table
|
||||||
|
static inline uint8_t rawGamma8(uint8_t val) { return gammaT[val]; } // get value from Gamma table (WLED specific, not used by NPB)
|
||||||
|
private:
|
||||||
|
static uint8_t gammaT[];
|
||||||
|
};
|
||||||
|
#define gamma32(c) NeoGammaWLEDMethod::Correct32(c)
|
||||||
|
#define gamma8(c) NeoGammaWLEDMethod::rawGamma8(c)
|
||||||
uint32_t color_blend(uint32_t,uint32_t,uint16_t,bool b16=false);
|
uint32_t color_blend(uint32_t,uint32_t,uint16_t,bool b16=false);
|
||||||
uint32_t color_add(uint32_t,uint32_t);
|
uint32_t color_add(uint32_t,uint32_t);
|
||||||
inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); }
|
inline uint32_t colorFromRgbw(byte* rgbw) { return uint32_t((byte(rgbw[3]) << 24) | (byte(rgbw[0]) << 16) | (byte(rgbw[1]) << 8) | (byte(rgbw[2]))); }
|
||||||
@ -63,10 +75,6 @@ bool colorFromHexString(byte* rgb, const char* in);
|
|||||||
uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb);
|
uint32_t colorBalanceFromKelvin(uint16_t kelvin, uint32_t rgb);
|
||||||
uint16_t approximateKelvinFromRGB(uint32_t rgb);
|
uint16_t approximateKelvinFromRGB(uint32_t rgb);
|
||||||
void setRandomColor(byte* rgb);
|
void setRandomColor(byte* rgb);
|
||||||
uint8_t gamma8_cal(uint8_t b, float gamma);
|
|
||||||
void calcGammaTable(float gamma);
|
|
||||||
uint8_t gamma8(uint8_t b);
|
|
||||||
uint32_t gamma32(uint32_t);
|
|
||||||
|
|
||||||
//dmx.cpp
|
//dmx.cpp
|
||||||
void initDMX();
|
void initDMX();
|
||||||
@ -99,7 +107,7 @@ void onHueData(void* arg, AsyncClient* client, void *data, size_t len);
|
|||||||
void handleImprovPacket();
|
void handleImprovPacket();
|
||||||
void sendImprovStateResponse(uint8_t state, bool error = false);
|
void sendImprovStateResponse(uint8_t state, bool error = false);
|
||||||
void sendImprovInfoResponse();
|
void sendImprovInfoResponse();
|
||||||
void sendImprovRPCResponse(uint8_t commandId);
|
void sendImprovRPCResponse(byte commandId);
|
||||||
|
|
||||||
//ir.cpp
|
//ir.cpp
|
||||||
void applyRepeatActions();
|
void applyRepeatActions();
|
||||||
@ -129,8 +137,8 @@ bool deserializeState(JsonObject root, byte callMode = CALL_MODE_DIRECT_CHANGE,
|
|||||||
void serializeSegment(JsonObject& root, Segment& seg, byte id, bool forPreset = false, bool segmentBounds = true);
|
void serializeSegment(JsonObject& root, Segment& seg, byte id, bool forPreset = false, bool segmentBounds = true);
|
||||||
void serializeState(JsonObject root, bool forPreset = false, bool includeBri = true, bool segmentBounds = true, bool selectedSegmentsOnly = false);
|
void serializeState(JsonObject root, bool forPreset = false, bool includeBri = true, bool segmentBounds = true, bool selectedSegmentsOnly = false);
|
||||||
void serializeInfo(JsonObject root);
|
void serializeInfo(JsonObject root);
|
||||||
void serializeModeNames(JsonArray arr, const char *qstring);
|
void serializeModeNames(JsonArray root);
|
||||||
void serializeModeData(JsonObject root);
|
void serializeModeData(JsonArray root);
|
||||||
void serveJson(AsyncWebServerRequest* request);
|
void serveJson(AsyncWebServerRequest* request);
|
||||||
#ifdef WLED_ENABLE_JSONLIVE
|
#ifdef WLED_ENABLE_JSONLIVE
|
||||||
bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient = 0);
|
bool serveLiveLeds(AsyncWebServerRequest* request, uint32_t wsClient = 0);
|
||||||
@ -152,9 +160,11 @@ void handleTransitions();
|
|||||||
void handleNightlight();
|
void handleNightlight();
|
||||||
byte scaledBri(byte in);
|
byte scaledBri(byte in);
|
||||||
|
|
||||||
|
#ifdef WLED_ENABLE_LOXONE
|
||||||
//lx_parser.cpp
|
//lx_parser.cpp
|
||||||
bool parseLx(int lxValue, byte* rgbw);
|
bool parseLx(int lxValue, byte* rgbw);
|
||||||
void parseLxJson(int lxValue, byte segId, bool secondary);
|
void parseLxJson(int lxValue, byte segId, bool secondary);
|
||||||
|
#endif
|
||||||
|
|
||||||
//mqtt.cpp
|
//mqtt.cpp
|
||||||
bool initMqtt();
|
bool initMqtt();
|
||||||
@ -203,7 +213,7 @@ bool handleSet(AsyncWebServerRequest *request, const String& req, bool apply=tru
|
|||||||
|
|
||||||
//udp.cpp
|
//udp.cpp
|
||||||
void notify(byte callMode, bool followUp=false);
|
void notify(byte callMode, bool followUp=false);
|
||||||
uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, byte *buffer, uint8_t bri=255, bool isRGBW=false);
|
uint8_t realtimeBroadcast(uint8_t type, IPAddress client, uint16_t length, uint8_t *buffer, uint8_t bri=255, bool isRGBW=false);
|
||||||
void realtimeLock(uint32_t timeoutMs, byte md = REALTIME_MODE_GENERIC);
|
void realtimeLock(uint32_t timeoutMs, byte md = REALTIME_MODE_GENERIC);
|
||||||
void exitRealtime();
|
void exitRealtime();
|
||||||
void handleNotifications();
|
void handleNotifications();
|
||||||
@ -372,7 +382,6 @@ void serveIndexOrWelcome(AsyncWebServerRequest *request);
|
|||||||
void serveIndex(AsyncWebServerRequest* request);
|
void serveIndex(AsyncWebServerRequest* request);
|
||||||
String msgProcessor(const String& var);
|
String msgProcessor(const String& var);
|
||||||
void serveMessage(AsyncWebServerRequest* request, uint16_t code, const String& headl, const String& subl="", byte optionT=255);
|
void serveMessage(AsyncWebServerRequest* request, uint16_t code, const String& headl, const String& subl="", byte optionT=255);
|
||||||
String settingsProcessor(const String& var);
|
|
||||||
String dmxProcessor(const String& var);
|
String dmxProcessor(const String& var);
|
||||||
void serveSettings(AsyncWebServerRequest* request, bool post = false);
|
void serveSettings(AsyncWebServerRequest* request, bool post = false);
|
||||||
void serveSettingsJS(AsyncWebServerRequest* request);
|
void serveSettingsJS(AsyncWebServerRequest* request);
|
||||||
|
@ -20,7 +20,7 @@ const uint8_t PAGE_usermod[] PROGMEM = {
|
|||||||
// Autogenerated from wled00/data/msg.htm, do not edit!!
|
// Autogenerated from wled00/data/msg.htm, do not edit!!
|
||||||
const char PAGE_msg[] PROGMEM = R"=====(<!DOCTYPE html><html><head><meta content="width=device-width" name="viewport">
|
const char PAGE_msg[] PROGMEM = R"=====(<!DOCTYPE html><html><head><meta content="width=device-width" name="viewport">
|
||||||
<title>WLED Message</title><script>
|
<title>WLED Message</title><script>
|
||||||
function B(){window.history.back()}function RS(){window.location="/settings"}function RP(){top.location.href="/"}
|
function B(){window.history.back()}function RS(){window.location="../settings"}function RP(){top.location.href="../"}
|
||||||
</script><style>@import url("style.css");</style></head><body><h2>%MSG%</body></html>)=====";
|
</script><style>@import url("style.css");</style></head><body><h2>%MSG%</body></html>)=====";
|
||||||
|
|
||||||
|
|
||||||
@ -41,52 +41,52 @@ const char PAGE_dmxmap[] PROGMEM = R"=====()=====";
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Autogenerated from wled00/data/update.htm, do not edit!!
|
// Autogenerated from wled00/data/update.htm, do not edit!!
|
||||||
const uint16_t PAGE_update_length = 615;
|
const uint16_t PAGE_update_length = 616;
|
||||||
const uint8_t PAGE_update[] PROGMEM = {
|
const uint8_t PAGE_update[] PROGMEM = {
|
||||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x13, 0x75, 0x53, 0x5d, 0x6f, 0xd4, 0x30,
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x13, 0x75, 0x53, 0x4d, 0x6f, 0xd4, 0x30,
|
||||||
0x10, 0x7c, 0xcf, 0xaf, 0x70, 0xfd, 0x74, 0x27, 0x71, 0x4e, 0xa9, 0x78, 0xa1, 0x24, 0x29, 0x1c,
|
0x10, 0xbd, 0xe7, 0x57, 0x18, 0x9f, 0x76, 0x25, 0xd6, 0x2e, 0x1f, 0x17, 0x4a, 0x92, 0x42, 0x69,
|
||||||
0xad, 0x50, 0x25, 0xa4, 0x56, 0x6a, 0x0b, 0xe2, 0x09, 0x39, 0xf6, 0xe6, 0x62, 0xce, 0xb1, 0x53,
|
0x85, 0x2a, 0x21, 0xb5, 0x52, 0x5b, 0x10, 0x27, 0xe4, 0xd8, 0x93, 0x8d, 0x59, 0xc7, 0x4e, 0xed,
|
||||||
0x7b, 0x73, 0xa7, 0xa8, 0xea, 0x7f, 0x67, 0xe3, 0xdc, 0x15, 0xc4, 0xc7, 0x4b, 0x14, 0x67, 0x67,
|
0xc9, 0xae, 0x56, 0xa8, 0xff, 0x9d, 0x89, 0xb3, 0x5b, 0x10, 0x1f, 0x97, 0x28, 0xce, 0xbc, 0x79,
|
||||||
0xc7, 0xbb, 0x33, 0x93, 0xe2, 0xe4, 0xf2, 0xe6, 0xe3, 0xfd, 0xb7, 0xdb, 0x2b, 0xd6, 0x62, 0x67,
|
0x9e, 0x79, 0xef, 0xa5, 0x7c, 0x76, 0x71, 0xfd, 0xe1, 0xee, 0xeb, 0xcd, 0x25, 0xeb, 0xb0, 0x77,
|
||||||
0xab, 0xe2, 0xf0, 0x04, 0xa9, 0xab, 0xa2, 0x03, 0x94, 0x4c, 0x79, 0x87, 0xe0, 0xb0, 0xe4, 0x7b,
|
0x75, 0x79, 0x78, 0x82, 0x32, 0x75, 0xd9, 0x03, 0x2a, 0xa6, 0x83, 0x47, 0xf0, 0x58, 0xf1, 0x9d,
|
||||||
0xa3, 0xb1, 0x2d, 0x35, 0xec, 0x8c, 0x82, 0x55, 0x3a, 0x70, 0xe6, 0x64, 0x07, 0x25, 0xdf, 0x19,
|
0x35, 0xd8, 0x55, 0x06, 0xb6, 0x56, 0xc3, 0x2a, 0x1f, 0x38, 0xf3, 0xaa, 0x87, 0x8a, 0x6f, 0x2d,
|
||||||
0xd8, 0xf7, 0x3e, 0x20, 0xaf, 0xb2, 0x02, 0x0d, 0x5a, 0xa8, 0xbe, 0x7e, 0xbe, 0xba, 0x64, 0x0f,
|
0xec, 0x86, 0x10, 0x91, 0xd7, 0x45, 0x89, 0x16, 0x1d, 0xd4, 0x5f, 0x3e, 0x5d, 0x5e, 0xb0, 0xfb,
|
||||||
0xbd, 0x96, 0x08, 0x45, 0x3e, 0x7f, 0x2a, 0xa2, 0x0a, 0xa6, 0xc7, 0x2a, 0x6b, 0x06, 0xa7, 0xd0,
|
0xc1, 0x28, 0x84, 0x52, 0xce, 0x9f, 0xca, 0xa4, 0xa3, 0x1d, 0xb0, 0x2e, 0xda, 0xd1, 0x6b, 0xb4,
|
||||||
0x78, 0xc7, 0xd6, 0x8b, 0xe5, 0xd3, 0xde, 0x38, 0xed, 0xf7, 0xa2, 0x35, 0x11, 0x7d, 0x18, 0x45,
|
0xc1, 0xb3, 0xf3, 0xc5, 0xf2, 0xc7, 0xce, 0x7a, 0x13, 0x76, 0xa2, 0xb3, 0x09, 0x43, 0xdc, 0x8b,
|
||||||
0x2d, 0xd5, 0x76, 0xb1, 0x7c, 0x7e, 0x81, 0x3c, 0x10, 0x44, 0x7b, 0x35, 0x74, 0x34, 0x81, 0xd8,
|
0x46, 0xe9, 0xcd, 0x62, 0xf9, 0xf8, 0x04, 0xb9, 0x27, 0x88, 0x09, 0x7a, 0xec, 0x69, 0x02, 0xb1,
|
||||||
0x00, 0x5e, 0x59, 0x98, 0x5e, 0xd7, 0xe3, 0xb5, 0x5e, 0xf0, 0xa1, 0xe1, 0x4b, 0x11, 0x71, 0xb4,
|
0x06, 0xbc, 0x74, 0x30, 0xbd, 0x9e, 0xef, 0xaf, 0xcc, 0x82, 0x8f, 0x2d, 0x5f, 0x8a, 0x84, 0x7b,
|
||||||
0x20, 0xb4, 0x89, 0xbd, 0x95, 0x63, 0xc9, 0x9d, 0x77, 0xc0, 0x5f, 0xfd, 0xb7, 0xa5, 0x8b, 0x9b,
|
0x07, 0xc2, 0xd8, 0x34, 0x38, 0xb5, 0xaf, 0xb8, 0x0f, 0x1e, 0xf8, 0xf3, 0xff, 0xb6, 0xf4, 0x69,
|
||||||
0xbf, 0x7b, 0x6a, 0xeb, 0xd5, 0x96, 0x3f, 0x67, 0x45, 0x7e, 0x18, 0xf1, 0x30, 0x2a, 0x8b, 0x41,
|
0xfd, 0x77, 0x4f, 0xe3, 0x82, 0xde, 0xf0, 0xc7, 0xa2, 0x94, 0x87, 0x11, 0x0f, 0xa3, 0xb2, 0x14,
|
||||||
0x95, 0x3c, 0x8f, 0x80, 0x68, 0xdc, 0x26, 0xe6, 0x51, 0xfc, 0x88, 0x17, 0x7d, 0xf9, 0x96, 0x57,
|
0x75, 0xc5, 0x65, 0x02, 0x44, 0xeb, 0xd7, 0x49, 0x26, 0xf1, 0x3d, 0x9d, 0x0d, 0xd5, 0x1b, 0x5e,
|
||||||
0xbf, 0x21, 0x27, 0xaa, 0x2a, 0x7b, 0x6f, 0xba, 0x49, 0x00, 0x36, 0x04, 0xbb, 0xe0, 0x33, 0xbd,
|
0xff, 0x86, 0x9c, 0xa8, 0xea, 0xe2, 0x9d, 0xed, 0x27, 0x01, 0xd8, 0x18, 0xdd, 0x82, 0xcf, 0xf4,
|
||||||
0x8a, 0x91, 0x2f, 0xdf, 0x11, 0x32, 0x21, 0x8a, 0x7c, 0x96, 0xb4, 0xf6, 0x7a, 0x64, 0xde, 0x59,
|
0x3a, 0x25, 0xbe, 0x7c, 0x4b, 0xc8, 0x8c, 0x28, 0xe5, 0x2c, 0x69, 0x13, 0xcc, 0x9e, 0x05, 0xef,
|
||||||
0x2f, 0x75, 0xc9, 0x3f, 0x01, 0x7e, 0x59, 0x2c, 0x89, 0xae, 0x3d, 0xab, 0xb2, 0x24, 0xd9, 0x9d,
|
0x82, 0x32, 0x15, 0xff, 0x08, 0xf8, 0x79, 0xb1, 0x24, 0xba, 0xee, 0x65, 0x5d, 0x64, 0xc9, 0x6e,
|
||||||
0x6f, 0x70, 0x2f, 0x03, 0xbc, 0x68, 0x47, 0x95, 0xa2, 0xf1, 0xa1, 0x63, 0xe4, 0x45, 0xeb, 0xa9,
|
0x43, 0x8b, 0x3b, 0x15, 0xe1, 0x49, 0x3b, 0xaa, 0x94, 0x6d, 0x88, 0x3d, 0x23, 0x2f, 0xba, 0x40,
|
||||||
0xe7, 0xf6, 0xe6, 0xee, 0x9e, 0x33, 0x99, 0xe4, 0xa1, 0xe1, 0x86, 0x84, 0xe3, 0xcc, 0x50, 0x89,
|
0x3d, 0x37, 0xd7, 0xb7, 0x77, 0x9c, 0xa9, 0x2c, 0x4f, 0xc5, 0x85, 0x1c, 0x33, 0x90, 0x33, 0x4b,
|
||||||
0xf4, 0x60, 0x19, 0x90, 0x72, 0x63, 0x4f, 0xa6, 0x74, 0x83, 0x45, 0xd3, 0xcb, 0x80, 0xf9, 0xd4,
|
0x35, 0x12, 0x84, 0x15, 0x40, 0xd2, 0xed, 0x07, 0x72, 0xa5, 0x1f, 0x1d, 0xda, 0x41, 0x45, 0x94,
|
||||||
0xbf, 0x22, 0x98, 0xe4, 0x74, 0x73, 0x1c, 0xea, 0xce, 0x90, 0x9b, 0x0f, 0xd3, 0xc5, 0xd7, 0x2e,
|
0x13, 0xc1, 0x8a, 0x60, 0x8a, 0xd3, 0xd5, 0x69, 0x6c, 0x7a, 0x4b, 0x76, 0xde, 0x4f, 0x37, 0x5f,
|
||||||
0xa2, 0xb4, 0x16, 0x34, 0xdb, 0x41, 0x88, 0xc4, 0x78, 0xce, 0x8a, 0xd8, 0x4b, 0xc7, 0x32, 0x65,
|
0xf9, 0x84, 0xca, 0x39, 0x30, 0x6c, 0x0b, 0x31, 0x11, 0xe5, 0x29, 0x2b, 0xd3, 0xa0, 0x3c, 0x2b,
|
||||||
0x65, 0x8c, 0x25, 0x8f, 0xa6, 0xe7, 0xd5, 0xa9, 0x78, 0xfd, 0x46, 0x9c, 0xae, 0xea, 0x33, 0x5a,
|
0xb4, 0x53, 0x29, 0x55, 0x3c, 0xd9, 0x81, 0xd7, 0x27, 0xe2, 0xc5, 0x6b, 0x71, 0xb2, 0x6a, 0x5e,
|
||||||
0x86, 0x8a, 0xb4, 0x44, 0xa8, 0x2e, 0xfd, 0x3e, 0x2d, 0xc1, 0xb0, 0x05, 0x66, 0x69, 0x84, 0x88,
|
0xd1, 0x36, 0x54, 0xa4, 0x2d, 0x62, 0x7d, 0x11, 0x76, 0x79, 0x0b, 0x86, 0x1d, 0x30, 0x47, 0x23,
|
||||||
0xac, 0x36, 0x4e, 0x86, 0x91, 0x28, 0x24, 0xcb, 0xda, 0x00, 0x4d, 0xc9, 0x5b, 0xc4, 0x3e, 0x9e,
|
0x24, 0x64, 0x8d, 0xf5, 0x2a, 0xee, 0x89, 0x42, 0xb1, 0xa2, 0x8b, 0xd0, 0x56, 0xbc, 0x43, 0x1c,
|
||||||
0xe7, 0xf9, 0xc6, 0x60, 0x3b, 0xd4, 0x42, 0xf9, 0x2e, 0xff, 0x60, 0x82, 0xf2, 0xde, 0x6f, 0x0d,
|
0xd2, 0xa9, 0x94, 0x6b, 0x8b, 0xdd, 0xd8, 0x08, 0x1d, 0x7a, 0xf9, 0xde, 0x46, 0x1d, 0x42, 0xd8,
|
||||||
0xe4, 0xd3, 0xc6, 0x79, 0x00, 0x0b, 0x32, 0x42, 0xe4, 0x0c, 0x65, 0x20, 0xbb, 0x4a, 0xfe, 0xbd,
|
0x58, 0x90, 0xd3, 0xca, 0x32, 0x82, 0x03, 0x95, 0x20, 0x71, 0x86, 0x2a, 0x92, 0x5f, 0x15, 0xff,
|
||||||
0xb6, 0xd2, 0x6d, 0x49, 0x15, 0xd3, 0x6d, 0x58, 0x96, 0x3c, 0x38, 0xf2, 0xd0, 0x17, 0x11, 0x5b,
|
0xd6, 0x38, 0xe5, 0x37, 0x24, 0x8b, 0xed, 0xd7, 0xac, 0xc8, 0x26, 0x1c, 0x79, 0xe8, 0x8b, 0x48,
|
||||||
0x03, 0x56, 0x47, 0x61, 0xfc, 0x81, 0xf6, 0x48, 0xf1, 0x27, 0xb5, 0x88, 0xbb, 0xcd, 0x45, 0x52,
|
0x9d, 0x05, 0x67, 0x92, 0xb0, 0xe1, 0x40, 0x7b, 0xa4, 0xf8, 0x93, 0x5a, 0xa4, 0xed, 0xfa, 0x2c,
|
||||||
0xbf, 0x6c, 0x68, 0xc2, 0x55, 0x7c, 0x1c, 0x48, 0xd9, 0x29, 0xa3, 0xb9, 0x4c, 0x3b, 0x14, 0xc6,
|
0xcb, 0x5f, 0xb5, 0x34, 0xe1, 0x2a, 0x3d, 0x8c, 0x24, 0xed, 0x14, 0x52, 0xa9, 0xf2, 0x0e, 0xa5,
|
||||||
0xf5, 0x03, 0xb2, 0x59, 0xae, 0xc6, 0x58, 0x38, 0xe6, 0xf9, 0x28, 0x6a, 0x80, 0xc7, 0xc1, 0x04,
|
0xf5, 0xc3, 0x88, 0x6c, 0x96, 0xab, 0xb5, 0x0e, 0x8e, 0x81, 0x3e, 0x8a, 0x1a, 0xe1, 0x61, 0xb4,
|
||||||
0xd0, 0x33, 0xba, 0x1e, 0x10, 0x29, 0x92, 0x33, 0x7c, 0x96, 0x91, 0xc8, 0x66, 0xa3, 0x4e, 0x8a,
|
0x11, 0xcc, 0x8c, 0x6e, 0x46, 0x44, 0xca, 0xe4, 0x0c, 0x9f, 0x65, 0x24, 0xb2, 0xd9, 0xa9, 0x67,
|
||||||
0x7c, 0x2e, 0xff, 0x03, 0x3a, 0x1f, 0x26, 0xed, 0x95, 0x35, 0x6a, 0x5b, 0xf2, 0xf5, 0x24, 0xfd,
|
0xa5, 0x9c, 0xcb, 0xff, 0x80, 0xce, 0x87, 0x49, 0x7b, 0xed, 0xac, 0xde, 0x54, 0xfc, 0x7c, 0x92,
|
||||||
0x9a, 0x92, 0xfe, 0xab, 0x29, 0x79, 0x54, 0x15, 0xda, 0xec, 0xb2, 0x64, 0xe5, 0x94, 0x53, 0xa2,
|
0xfe, 0x9c, 0xa2, 0xfe, 0xab, 0x29, 0x7b, 0x54, 0x97, 0xc6, 0x6e, 0x8b, 0x6c, 0xe5, 0x14, 0x54,
|
||||||
0xa9, 0x12, 0x3b, 0x85, 0x4f, 0x08, 0x41, 0xe0, 0x44, 0x7e, 0x9b, 0x96, 0x65, 0xda, 0x33, 0xe7,
|
0xa2, 0xa9, 0x33, 0x3b, 0xa5, 0x4f, 0x08, 0x41, 0xe0, 0x4c, 0x7e, 0x93, 0x97, 0x65, 0x26, 0x30,
|
||||||
0x91, 0x29, 0xeb, 0xe9, 0xe0, 0x03, 0xcd, 0xda, 0x04, 0x88, 0x6d, 0xf2, 0xa3, 0x97, 0x1b, 0x60,
|
0x1f, 0x90, 0x69, 0x17, 0xe8, 0x10, 0x22, 0xcd, 0xda, 0x46, 0x48, 0x5d, 0xf6, 0x63, 0x50, 0x6b,
|
||||||
0xe7, 0xcb, 0x22, 0x27, 0xbe, 0x69, 0xdd, 0x29, 0x74, 0x53, 0x02, 0xa7, 0x5f, 0xfb, 0x27, 0x3b,
|
0x60, 0xa7, 0xcb, 0x52, 0x12, 0xdf, 0xb4, 0xee, 0x94, 0xba, 0x29, 0x82, 0xd3, 0xbf, 0xfd, 0x13,
|
||||||
0x01, 0xc5, 0x54, 0xf0, 0x03, 0x00, 0x00
|
0x46, 0x22, 0xf9, 0xe1, 0xf1, 0x03, 0x00, 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Autogenerated from wled00/data/welcome.htm, do not edit!!
|
// Autogenerated from wled00/data/welcome.htm, do not edit!!
|
||||||
const uint16_t PAGE_welcome_length = 1528;
|
const uint16_t PAGE_welcome_length = 1529;
|
||||||
const uint8_t PAGE_welcome[] PROGMEM = {
|
const uint8_t PAGE_welcome[] PROGMEM = {
|
||||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x13, 0x95, 0x56, 0x5b, 0x93, 0xaa, 0x3a,
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x13, 0x95, 0x56, 0x5b, 0x93, 0xaa, 0x3a,
|
||||||
0x16, 0x7e, 0xef, 0x5f, 0xc1, 0x76, 0xea, 0xd4, 0x79, 0x70, 0x77, 0x73, 0x13, 0x51, 0xdb, 0xee,
|
0x16, 0x7e, 0xef, 0x5f, 0xc1, 0x76, 0xea, 0xd4, 0x79, 0x70, 0x77, 0x73, 0x13, 0x51, 0xdb, 0xee,
|
||||||
@ -177,18 +177,18 @@ const uint8_t PAGE_welcome[] PROGMEM = {
|
|||||||
0x72, 0xff, 0x3e, 0x19, 0x38, 0x4d, 0xa1, 0xcb, 0x04, 0x2e, 0x8e, 0x42, 0x82, 0xbd, 0x3c, 0xbe,
|
0x72, 0xff, 0x3e, 0x19, 0x38, 0x4d, 0xa1, 0xcb, 0x04, 0x2e, 0x8e, 0x42, 0x82, 0xbd, 0x3c, 0xbe,
|
||||||
0x07, 0xe3, 0x7e, 0x89, 0x10, 0x63, 0x17, 0xc4, 0xc2, 0x16, 0x0d, 0x90, 0x10, 0x42, 0xc2, 0x05,
|
0x07, 0xe3, 0x7e, 0x89, 0x10, 0x63, 0x17, 0xc4, 0xc2, 0x16, 0x0d, 0x90, 0x10, 0x42, 0xc2, 0x05,
|
||||||
0xf1, 0x6e, 0x73, 0xd7, 0x26, 0xe1, 0x09, 0xa7, 0x2e, 0x8f, 0x71, 0x7c, 0xfb, 0xf3, 0x8c, 0x52,
|
0xf1, 0x6e, 0x73, 0xd7, 0x26, 0xe1, 0x09, 0xa7, 0x2e, 0x8f, 0x71, 0x7c, 0xfb, 0xf3, 0x8c, 0x52,
|
||||||
0x0f, 0x9f, 0x5f, 0xca, 0xc5, 0x65, 0xc0, 0x97, 0x90, 0x40, 0xff, 0xad, 0x22, 0x72, 0xe1, 0x66,
|
0x0f, 0x9f, 0x5f, 0xca, 0xc5, 0x65, 0xc0, 0x97, 0x90, 0x40, 0xff, 0xad, 0xf2, 0x22, 0x72, 0xe5,
|
||||||
0x9c, 0x0e, 0x15, 0xcf, 0xc8, 0x47, 0x95, 0x3f, 0xdf, 0xef, 0x6e, 0xbe, 0x41, 0xce, 0xe0, 0xee,
|
0x66, 0x9c, 0x0f, 0x15, 0xcf, 0xc8, 0x47, 0x95, 0x3f, 0xdf, 0xef, 0x7e, 0xbe, 0x41, 0x4e, 0xe1,
|
||||||
0xe6, 0x41, 0x03, 0xbd, 0x3f, 0x8d, 0x73, 0xca, 0x29, 0x90, 0x6b, 0x99, 0x00, 0x0b, 0x11, 0x15,
|
0xee, 0xe7, 0xc1, 0x03, 0xbd, 0x3f, 0x8d, 0x73, 0xca, 0x39, 0x90, 0x6b, 0x99, 0x01, 0x0b, 0x11,
|
||||||
0xb8, 0xf6, 0xf1, 0xa4, 0x84, 0xce, 0xbc, 0x24, 0x05, 0xff, 0xdd, 0x16, 0xd1, 0xfb, 0x3f, 0x0b,
|
0x15, 0xb8, 0xf8, 0xf1, 0xac, 0x84, 0xce, 0xbc, 0x64, 0x05, 0xff, 0xdd, 0x16, 0xd1, 0xfb, 0x3f,
|
||||||
0xcf, 0x55, 0x09, 0x12, 0xca, 0x03, 0xaf, 0xf1, 0x3d, 0xb7, 0x52, 0xee, 0x09, 0x8e, 0xe9, 0x8f,
|
0x8c, 0xcf, 0x75, 0x09, 0x12, 0xca, 0x23, 0xaf, 0xf1, 0x3d, 0xbb, 0x52, 0xf0, 0x09, 0x8e, 0xe9,
|
||||||
0xbf, 0xc6, 0x16, 0xf9, 0xb6, 0xf3, 0xcd, 0x17, 0x1f, 0x65, 0x5d, 0xbc, 0xff, 0x07, 0xf9, 0x2f,
|
0x8f, 0xbf, 0x06, 0x17, 0xf9, 0xc6, 0xf3, 0xed, 0x17, 0x1f, 0x85, 0x5d, 0xbc, 0xff, 0x0b, 0xf9,
|
||||||
0xec, 0xfa, 0x82, 0xd2, 0x99, 0x08, 0x00, 0x00
|
0x2f, 0x52, 0xe7, 0x8f, 0x07, 0x9b, 0x08, 0x00, 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Autogenerated from wled00/data/liveview.htm, do not edit!!
|
// Autogenerated from wled00/data/liveview.htm, do not edit!!
|
||||||
const uint16_t PAGE_liveview_length = 547;
|
const uint16_t PAGE_liveview_length = 548;
|
||||||
const uint8_t PAGE_liveview[] PROGMEM = {
|
const uint8_t PAGE_liveview[] PROGMEM = {
|
||||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x13, 0x95, 0x53, 0x4d, 0x6f, 0xdb, 0x30,
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x13, 0x95, 0x53, 0x4d, 0x6f, 0xdb, 0x30,
|
||||||
0x0c, 0xbd, 0xe7, 0x57, 0x78, 0x2a, 0x5a, 0x48, 0x88, 0x63, 0x3b, 0xc5, 0xba, 0x8f, 0xf8, 0xe3,
|
0x0c, 0xbd, 0xe7, 0x57, 0x78, 0x2a, 0x5a, 0x48, 0x88, 0x63, 0x3b, 0xc5, 0xba, 0x8f, 0xf8, 0xe3,
|
||||||
@ -212,128 +212,133 @@ const uint8_t PAGE_liveview[] PROGMEM = {
|
|||||||
0xbc, 0x11, 0x03, 0x6f, 0x74, 0x02, 0xec, 0xd5, 0x86, 0x4a, 0x2b, 0x7c, 0x1b, 0x6a, 0x4f, 0x1a,
|
0xbc, 0x11, 0x03, 0x6f, 0x74, 0x02, 0xec, 0xd5, 0x86, 0x4a, 0x2b, 0x7c, 0x1b, 0x6a, 0x4f, 0x1a,
|
||||||
0x25, 0x25, 0x18, 0xe6, 0x00, 0xbd, 0x33, 0x91, 0xd0, 0xc0, 0xdd, 0x83, 0x6a, 0x21, 0xdc, 0xa6,
|
0x25, 0x25, 0x18, 0xe6, 0x00, 0xbd, 0x33, 0x91, 0xd0, 0xc0, 0xdd, 0x83, 0x6a, 0x21, 0xdc, 0xa6,
|
||||||
0x23, 0x07, 0x8b, 0x7b, 0xab, 0xe4, 0x64, 0x97, 0x41, 0xd5, 0x93, 0x73, 0x22, 0x8b, 0x2f, 0xaf,
|
0x23, 0x07, 0x8b, 0x7b, 0xab, 0xe4, 0x64, 0x97, 0x41, 0xd5, 0x93, 0x73, 0x22, 0x8b, 0x2f, 0xaf,
|
||||||
0x32, 0xc6, 0xf2, 0x0d, 0xa0, 0x68, 0x28, 0x49, 0x7f, 0x77, 0xd6, 0xa4, 0x3a, 0xc8, 0x46, 0x58,
|
0x32, 0xc6, 0xf2, 0x0d, 0xa0, 0x68, 0x28, 0x49, 0xd2, 0xdf, 0x9d, 0x35, 0xa9, 0x0e, 0xba, 0x11,
|
||||||
0x12, 0x94, 0x36, 0x14, 0xcb, 0x8a, 0x62, 0x62, 0x1f, 0x9f, 0x9f, 0xe9, 0xbf, 0xa8, 0xff, 0xc3,
|
0x96, 0x04, 0xa9, 0x0d, 0xc5, 0xb2, 0xa2, 0x98, 0xd8, 0xc7, 0xe7, 0x67, 0xfa, 0x2f, 0xee, 0xff,
|
||||||
0x1a, 0x68, 0x63, 0x4c, 0x06, 0x42, 0xca, 0xd8, 0x2b, 0xdb, 0x7e, 0x28, 0x2e, 0xf4, 0x51, 0x2b,
|
0xd0, 0x06, 0xde, 0x18, 0x93, 0x81, 0x90, 0x32, 0xf6, 0xca, 0xb6, 0x1f, 0xaa, 0x0b, 0x8d, 0xd4,
|
||||||
0x13, 0xe8, 0x16, 0xb5, 0xe3, 0x52, 0x85, 0x32, 0xe8, 0xe7, 0x4c, 0x42, 0x1d, 0x93, 0xd8, 0x97,
|
0xca, 0x04, 0xba, 0x45, 0xed, 0xb8, 0x54, 0xa1, 0x0e, 0xfa, 0x39, 0x93, 0x50, 0xc7, 0x24, 0xf6,
|
||||||
0x98, 0x68, 0x90, 0x5d, 0x58, 0x4c, 0x8d, 0x4d, 0xbe, 0xb1, 0x8e, 0xaa, 0x32, 0xcb, 0x55, 0xe1,
|
0x25, 0x26, 0x1a, 0x64, 0x17, 0x16, 0x53, 0x63, 0x93, 0x6f, 0xac, 0xa3, 0xaa, 0xcc, 0x72, 0x55,
|
||||||
0x73, 0x35, 0x9f, 0xb3, 0xf1, 0xbe, 0x3d, 0x82, 0x7e, 0xaa, 0x5f, 0xb9, 0x3d, 0x22, 0xab, 0x0f,
|
0xf8, 0x5c, 0xcd, 0xe7, 0x6c, 0xbc, 0x6f, 0x8f, 0xa0, 0x9f, 0xea, 0x57, 0x6e, 0x8f, 0xc8, 0xea,
|
||||||
0x17, 0x17, 0xd4, 0x96, 0x36, 0xe9, 0xfc, 0xba, 0x43, 0xa7, 0x4c, 0x4d, 0x2f, 0x43, 0x0a, 0x30,
|
0xc3, 0xc5, 0x05, 0xb5, 0xa5, 0x4d, 0x3a, 0xbf, 0xee, 0xd0, 0x29, 0x53, 0xd3, 0xcb, 0x90, 0x02,
|
||||||
0x0f, 0xd3, 0x41, 0xe6, 0x36, 0x0e, 0x04, 0x8b, 0x65, 0x80, 0x0c, 0x07, 0x31, 0x61, 0x87, 0xe1,
|
0xcc, 0xc3, 0x78, 0x90, 0xb9, 0x8d, 0x03, 0xc1, 0x62, 0x19, 0x20, 0xc3, 0x41, 0x4c, 0xd8, 0x61,
|
||||||
0xcf, 0x48, 0xfc, 0xa2, 0x63, 0x0d, 0x78, 0xa3, 0x61, 0x30, 0xbf, 0xec, 0x6e, 0x25, 0x9d, 0x9a,
|
0xf8, 0x33, 0x12, 0xbf, 0x08, 0x59, 0x03, 0xde, 0x68, 0x18, 0xcc, 0x2f, 0xbb, 0x5b, 0x49, 0xa7,
|
||||||
0xc3, 0x92, 0xb1, 0x7f, 0xc9, 0xeb, 0x64, 0x94, 0x10, 0xbf, 0x45, 0x88, 0xf7, 0x19, 0x3b, 0xb0,
|
0xee, 0xb0, 0x64, 0x6c, 0x60, 0xf2, 0x3a, 0x1a, 0x25, 0xc4, 0x6f, 0x11, 0xe2, 0x7d, 0xc6, 0x0e,
|
||||||
0x44, 0xf0, 0x41, 0x5e, 0x7a, 0x6a, 0x24, 0x45, 0xb6, 0x7f, 0xb3, 0x9a, 0x07, 0xc6, 0xc6, 0x79,
|
0x2c, 0x11, 0x7c, 0xd0, 0x97, 0x9e, 0x3a, 0x49, 0x91, 0xed, 0xdf, 0xac, 0xe6, 0x81, 0xb1, 0x71,
|
||||||
0x9a, 0x86, 0xa5, 0x48, 0xa7, 0x51, 0x4a, 0xc7, 0x17, 0xf9, 0x07, 0xe3, 0xed, 0x60, 0x85, 0xa7,
|
0xa0, 0xa6, 0x69, 0x29, 0xd2, 0x69, 0x96, 0xd2, 0xf1, 0x49, 0xfe, 0x01, 0x0f, 0xfb, 0xef, 0x75,
|
||||||
0x03, 0x00, 0x00
|
0xa8, 0x03, 0x00, 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Autogenerated from wled00/data/liveviewws.htm, do not edit!!
|
// Autogenerated from wled00/data/liveviewws.htm, do not edit!!
|
||||||
const uint16_t PAGE_liveviewws_length = 711;
|
const uint16_t PAGE_liveviewws_length = 747;
|
||||||
const uint8_t PAGE_liveviewws[] PROGMEM = {
|
const uint8_t PAGE_liveviewws[] PROGMEM = {
|
||||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x13, 0x6d, 0x54, 0x5d, 0x8f, 0x9b, 0x3a,
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x13, 0x6d, 0x54, 0x6d, 0x8f, 0x9b, 0x38,
|
||||||
0x10, 0x7d, 0xcf, 0xaf, 0xa0, 0xde, 0xdb, 0x2d, 0x56, 0x08, 0x24, 0xdb, 0xdb, 0x2f, 0xc0, 0x59,
|
0x10, 0xfe, 0x9e, 0x5f, 0x41, 0xbd, 0xd7, 0x2d, 0x28, 0x84, 0x90, 0x6d, 0xaf, 0x2f, 0x01, 0xa7,
|
||||||
0xb5, 0xb7, 0x79, 0xa8, 0xb4, 0x6a, 0x57, 0xda, 0x5e, 0xad, 0xaa, 0x55, 0xa4, 0x1a, 0x98, 0x80,
|
0xba, 0x5e, 0xf3, 0xe1, 0xa4, 0x55, 0xbb, 0xd2, 0xb6, 0x5a, 0x9d, 0x56, 0x91, 0x6a, 0x60, 0x02,
|
||||||
0xef, 0x82, 0x1d, 0xd9, 0x43, 0x50, 0x84, 0xf8, 0xef, 0x77, 0x20, 0xdb, 0xac, 0x2a, 0x95, 0x07,
|
0xbe, 0x05, 0x1b, 0xd9, 0x03, 0x28, 0x42, 0xfc, 0xf7, 0x1b, 0x93, 0x74, 0xab, 0x93, 0x8e, 0x0f,
|
||||||
0xdb, 0xc3, 0x9c, 0x99, 0x33, 0x33, 0x3e, 0x90, 0xbe, 0xf8, 0xfc, 0xed, 0x9f, 0xef, 0x3f, 0x6e,
|
0x60, 0x7b, 0xe6, 0x99, 0x97, 0x67, 0x1e, 0x93, 0xbe, 0xf8, 0xfc, 0xf5, 0xcf, 0x6f, 0x7f, 0xdf,
|
||||||
0x37, 0x5e, 0x85, 0x4d, 0xbd, 0x4e, 0x9f, 0x56, 0x90, 0xc5, 0x3a, 0x6d, 0x00, 0xa5, 0xa7, 0x65,
|
0xed, 0xbd, 0x0a, 0x9b, 0x7a, 0x97, 0x5e, 0xde, 0x20, 0x8a, 0x5d, 0xda, 0x00, 0x0a, 0x4f, 0x89,
|
||||||
0x03, 0x82, 0x1d, 0x14, 0x74, 0x7b, 0x63, 0x91, 0x79, 0xb3, 0xdc, 0x68, 0x04, 0x8d, 0x82, 0x75,
|
0x06, 0x38, 0xeb, 0x25, 0x0c, 0xad, 0x36, 0xc8, 0xbc, 0x45, 0xae, 0x15, 0x82, 0x42, 0xce, 0x06,
|
||||||
0xaa, 0xc0, 0x4a, 0x14, 0x70, 0x50, 0x39, 0x2c, 0x26, 0x23, 0x50, 0x5a, 0xa1, 0x92, 0xf5, 0xc2,
|
0x59, 0x60, 0xc5, 0x0b, 0xe8, 0x65, 0x0e, 0xab, 0x79, 0x13, 0x4a, 0x25, 0x51, 0x8a, 0x7a, 0x65,
|
||||||
0xe5, 0xb2, 0x06, 0xb1, 0x0a, 0x1a, 0x7a, 0xd1, 0xb4, 0xcd, 0x2f, 0x9b, 0x3d, 0xe5, 0x9c, 0xe5,
|
0x73, 0x51, 0x03, 0xdf, 0x84, 0x0d, 0x1d, 0x34, 0x5d, 0xf3, 0x73, 0xcf, 0x2e, 0x31, 0x17, 0x79,
|
||||||
0x95, 0xb4, 0x0e, 0x28, 0x47, 0x8b, 0xbb, 0xc5, 0x7b, 0xf6, 0x1b, 0x15, 0x56, 0xd0, 0xc0, 0x22,
|
0x25, 0x8c, 0x05, 0x8a, 0xd1, 0xe1, 0x71, 0xf5, 0x9e, 0xfd, 0x27, 0x15, 0x56, 0xd0, 0xc0, 0x2a,
|
||||||
0x37, 0xb5, 0xb1, 0xcc, 0x3b, 0x93, 0x5d, 0x5c, 0x4d, 0x0f, 0x41, 0x51, 0x61, 0x0d, 0xeb, 0xd9,
|
0xd7, 0xb5, 0x36, 0xcc, 0x7b, 0x4e, 0x76, 0x75, 0x33, 0x3f, 0xe4, 0x8a, 0x12, 0x6b, 0xd8, 0x2d,
|
||||||
0xfd, 0xcd, 0xe6, 0xb3, 0x77, 0xa3, 0x0e, 0xe0, 0xdd, 0x5a, 0x18, 0xcb, 0x4b, 0xa3, 0x93, 0x27,
|
0x1e, 0x6e, 0xf7, 0x9f, 0xbd, 0x5b, 0xd9, 0x83, 0x77, 0x67, 0xc0, 0x95, 0x97, 0xae, 0xcf, 0x96,
|
||||||
0x75, 0x78, 0x1c, 0x01, 0x99, 0x29, 0x8e, 0x7d, 0x23, 0x6d, 0xa9, 0x74, 0xbc, 0x1c, 0x2e, 0x72,
|
0xd4, 0xe2, 0xc9, 0x39, 0x64, 0xba, 0x38, 0x8d, 0x8d, 0x30, 0xa5, 0x54, 0xdb, 0x78, 0xba, 0xca,
|
||||||
0xa9, 0x0f, 0x7d, 0x26, 0xf3, 0xc7, 0xd2, 0x9a, 0x56, 0x17, 0xf1, 0xc5, 0x72, 0xb9, 0x4c, 0x76,
|
0x85, 0xea, 0xc7, 0x4c, 0xe4, 0x4f, 0xa5, 0xd1, 0x9d, 0x2a, 0xb6, 0x57, 0x71, 0x1c, 0x27, 0x47,
|
||||||
0xaa, 0x46, 0xb0, 0x71, 0x66, 0x55, 0x59, 0xa1, 0x06, 0xe7, 0xfc, 0xd5, 0xbb, 0x37, 0x2f, 0x79,
|
0x59, 0x23, 0x98, 0x6d, 0x66, 0x64, 0x59, 0xa1, 0x02, 0x6b, 0xfd, 0xcd, 0xbb, 0xdf, 0x5f, 0x06,
|
||||||
0x32, 0x75, 0x13, 0xaf, 0x96, 0xcb, 0x97, 0x49, 0x05, 0xa3, 0xef, 0x74, 0xde, 0x1b, 0x47, 0xfd,
|
0xc9, 0xdc, 0xcd, 0x76, 0x13, 0xc7, 0x2f, 0x93, 0x0a, 0x9c, 0xed, 0xbc, 0x6e, 0xb5, 0xa5, 0xfe,
|
||||||
0x19, 0x1d, 0xcb, 0xcc, 0x99, 0xba, 0x45, 0x18, 0x66, 0x69, 0x74, 0xa2, 0x4b, 0xa3, 0xd3, 0xcc,
|
0xb4, 0xda, 0x8a, 0xcc, 0xea, 0xba, 0x43, 0x98, 0x16, 0xe9, 0xfa, 0x9c, 0x2e, 0x5d, 0x9f, 0x39,
|
||||||
0x46, 0xd6, 0x75, 0x5a, 0xa8, 0x83, 0xa7, 0x0a, 0xc1, 0x46, 0x52, 0x2a, 0x39, 0x22, 0x9b, 0xea,
|
0x73, 0x59, 0x77, 0x69, 0x21, 0x7b, 0x4f, 0x16, 0x9c, 0xb9, 0xa4, 0x54, 0xf2, 0x9a, 0xf6, 0x54,
|
||||||
0xca, 0xad, 0xda, 0xe3, 0x7a, 0x76, 0x90, 0xd6, 0xeb, 0x5c, 0x82, 0xf6, 0xd8, 0x77, 0x4e, 0xa0,
|
0x57, 0x6e, 0x64, 0x8b, 0xbb, 0x45, 0x2f, 0x8c, 0x37, 0xd8, 0x04, 0xcd, 0x69, 0x1c, 0x2c, 0x47,
|
||||||
0xd9, 0x87, 0x9d, 0xd2, 0x85, 0xe9, 0xc2, 0xce, 0x0d, 0xb9, 0xc4, 0xbc, 0xf2, 0x81, 0xf7, 0x43,
|
0xdd, 0x46, 0x83, 0x54, 0x85, 0x1e, 0xa2, 0xc1, 0x4e, 0xb9, 0xc0, 0xbc, 0xf2, 0x21, 0x18, 0x27,
|
||||||
0xe7, 0x2e, 0x2f, 0x3b, 0x17, 0x5a, 0xca, 0x7a, 0xbc, 0x43, 0x89, 0x20, 0x84, 0xb8, 0x87, 0xec,
|
0x79, 0xf4, 0x07, 0x7b, 0x7d, 0x3d, 0xd8, 0xc8, 0x50, 0xe0, 0xd3, 0x3d, 0x0a, 0x04, 0xce, 0xf9,
|
||||||
0xce, 0xe4, 0x8f, 0x80, 0xe1, 0xb7, 0xdb, 0xcd, 0xd7, 0x6b, 0x72, 0x3b, 0xd0, 0x85, 0xcf, 0xfa,
|
0x03, 0x64, 0xf7, 0x3a, 0x7f, 0x02, 0x8c, 0xbe, 0xde, 0xed, 0xbf, 0x04, 0x64, 0xb6, 0xa0, 0x0a,
|
||||||
0x57, 0xf5, 0xe1, 0x55, 0x8c, 0xb6, 0x85, 0x81, 0xf1, 0xd8, 0xa7, 0xa1, 0x51, 0x79, 0x10, 0x2a,
|
0x9f, 0x8d, 0xaf, 0xea, 0xfe, 0xd5, 0x16, 0x4d, 0x07, 0x13, 0x0b, 0x12, 0xa8, 0x2d, 0x8c, 0x35,
|
||||||
0xbd, 0x33, 0x3e, 0xbb, 0x05, 0x78, 0xf4, 0xee, 0xef, 0x3c, 0xb3, 0x07, 0xad, 0x74, 0xc9, 0x78,
|
0xa0, 0x07, 0xfc, 0x12, 0xbb, 0xd6, 0x14, 0x9a, 0x4a, 0x0f, 0x91, 0x43, 0xd4, 0x0a, 0xac, 0x1c,
|
||||||
0xe0, 0x13, 0xad, 0x86, 0xce, 0x3b, 0xa7, 0xf3, 0x7d, 0x56, 0x21, 0xee, 0x5d, 0xcc, 0x84, 0x78,
|
0xd9, 0xa1, 0xe1, 0x18, 0xd9, 0x9a, 0xe6, 0xe7, 0x6f, 0x42, 0x8c, 0x28, 0x90, 0x7d, 0x90, 0x58,
|
||||||
0xaa, 0xa5, 0x36, 0x54, 0x0a, 0xb5, 0x1a, 0xee, 0xad, 0x41, 0x43, 0xb7, 0x71, 0xcd, 0x3a, 0xe7,
|
0xf9, 0x6c, 0xcd, 0x82, 0x8f, 0xab, 0xcd, 0xb6, 0xd7, 0xb2, 0xf0, 0xe2, 0x20, 0xb2, 0x6d, 0x2d,
|
||||||
0x58, 0x4c, 0x2b, 0xe3, 0x73, 0x16, 0x47, 0x11, 0x9b, 0x17, 0x26, 0x6f, 0x1b, 0xba, 0x9d, 0x67,
|
0x71, 0x3e, 0x0d, 0x15, 0xc1, 0x35, 0xd1, 0x25, 0x15, 0xd5, 0xd5, 0xd6, 0x82, 0xa0, 0xac, 0x42,
|
||||||
0x70, 0x65, 0x1c, 0xce, 0x59, 0x34, 0x62, 0x78, 0x68, 0xf4, 0x48, 0x29, 0x76, 0xad, 0xce, 0x47,
|
0x6c, 0x59, 0xc8, 0x06, 0x4b, 0x99, 0x4d, 0x54, 0x83, 0x2a, 0xb1, 0xda, 0x6d, 0xae, 0xaf, 0x7d,
|
||||||
0xa7, 0xcf, 0xfb, 0x3f, 0x17, 0x3c, 0xf0, 0x80, 0x1c, 0x99, 0xd2, 0xd2, 0x1e, 0xbf, 0x1f, 0xf7,
|
0xb5, 0xe4, 0x04, 0x5a, 0x9a, 0xc7, 0xf8, 0x10, 0x84, 0xd4, 0x0e, 0x57, 0x30, 0x78, 0xcf, 0x1d,
|
||||||
0x24, 0x01, 0x69, 0xad, 0x3c, 0x66, 0xed, 0x6e, 0x07, 0x96, 0x8d, 0x3e, 0x59, 0x14, 0x9b, 0x03,
|
0x90, 0x99, 0xad, 0x1d, 0x28, 0x88, 0xb4, 0xd2, 0x2d, 0x28, 0x7e, 0xec, 0x54, 0xee, 0x8a, 0xf4,
|
||||||
0x11, 0xdd, 0x28, 0x47, 0x6a, 0x00, 0xeb, 0xb3, 0x86, 0xee, 0x4a, 0x96, 0xc0, 0x02, 0x10, 0xeb,
|
0x83, 0xf1, 0xff, 0x1b, 0x9b, 0x26, 0x3a, 0xcf, 0xa4, 0x12, 0xe6, 0xf4, 0xed, 0xd4, 0x92, 0x58,
|
||||||
0x7e, 0x9c, 0xa4, 0xda, 0xf9, 0xec, 0xc1, 0x64, 0xff, 0x41, 0x8e, 0xde, 0xc7, 0x31, 0xfc, 0xd3,
|
0x84, 0x31, 0xe2, 0x94, 0x75, 0xc7, 0x23, 0x18, 0x16, 0x92, 0x4d, 0x14, 0xc5, 0xbe, 0x27, 0xc1,
|
||||||
0x14, 0xbe, 0xa5, 0x8e, 0x68, 0xc4, 0x77, 0x68, 0xa9, 0xf5, 0x90, 0x54, 0x58, 0xfb, 0x10, 0x16,
|
0xdc, 0x4a, 0x4b, 0xba, 0x01, 0xe3, 0xb3, 0x86, 0xa6, 0x2a, 0x4a, 0x60, 0x21, 0xf0, 0xdd, 0xe8,
|
||||||
0x12, 0x25, 0xe7, 0x7d, 0x0d, 0xe8, 0xc1, 0x34, 0x88, 0x7f, 0x95, 0xc6, 0xf7, 0x53, 0x94, 0x0f,
|
0x38, 0x27, 0x62, 0xd9, 0xa3, 0xce, 0xfe, 0x81, 0x1c, 0xbd, 0x3f, 0x1c, 0xfc, 0xd3, 0x0c, 0x3f,
|
||||||
0x23, 0xcf, 0x09, 0x91, 0x50, 0xce, 0x77, 0x6f, 0x5f, 0x08, 0x78, 0x58, 0x6e, 0xb9, 0x05, 0x6c,
|
0x30, 0x62, 0x17, 0xf5, 0x3d, 0x1a, 0xa9, 0xca, 0x88, 0xf4, 0x5a, 0xfb, 0x10, 0x15, 0x02, 0x45,
|
||||||
0xad, 0x4e, 0xc6, 0x18, 0x52, 0x63, 0xad, 0x34, 0x48, 0xbb, 0x28, 0xad, 0x2c, 0x14, 0xe1, 0xfd,
|
0x10, 0x5c, 0x98, 0x74, 0xc5, 0x7f, 0x97, 0x0a, 0xdf, 0xcf, 0x28, 0x1f, 0x5c, 0x9e, 0xb3, 0x47,
|
||||||
0x0f, 0xcb, 0x02, 0xca, 0x80, 0x05, 0x5a, 0x40, 0x58, 0x83, 0x2e, 0xe9, 0x53, 0xb0, 0xe2, 0x4a,
|
0x42, 0x31, 0xdf, 0xbd, 0x7d, 0xc1, 0xc1, 0x35, 0x6a, 0x00, 0x3b, 0xa3, 0x12, 0x87, 0x21, 0xdd,
|
||||||
0x50, 0xe8, 0x6a, 0x7b, 0xfd, 0x77, 0x7c, 0x95, 0xec, 0x8c, 0xf5, 0x95, 0xb0, 0x89, 0x4a, 0x75,
|
0xd6, 0x52, 0x81, 0x30, 0xab, 0xd2, 0x88, 0x42, 0x92, 0xbf, 0xff, 0x21, 0x2e, 0xa0, 0x0c, 0x19,
|
||||||
0xa2, 0xe6, 0xe2, 0x35, 0xc7, 0xb9, 0xf8, 0x69, 0xcb, 0xcc, 0xff, 0xab, 0x87, 0x07, 0xb5, 0x1d,
|
0x31, 0x0f, 0x17, 0xa6, 0x88, 0xd2, 0x1b, 0x4e, 0xd0, 0xcd, 0xe1, 0xe3, 0x9b, 0xed, 0x4d, 0x72,
|
||||||
0x82, 0x69, 0x9f, 0xaf, 0xce, 0xa7, 0xab, 0xed, 0xc0, 0x7f, 0x06, 0x04, 0x5f, 0xbc, 0xbe, 0xbc,
|
0xd4, 0xc6, 0x97, 0x5c, 0x25, 0x32, 0x35, 0x89, 0x5c, 0xf2, 0xd7, 0x01, 0x2e, 0xf9, 0x0f, 0x53,
|
||||||
0xf4, 0x09, 0xcd, 0x02, 0xc6, 0x93, 0x71, 0xe7, 0x2c, 0x38, 0x0f, 0xbe, 0x04, 0xdc, 0xd4, 0x30,
|
0x66, 0xfe, 0x6f, 0x23, 0x3c, 0xca, 0xc3, 0x14, 0xce, 0xdf, 0xe5, 0xe6, 0x79, 0x75, 0x73, 0x98,
|
||||||
0x1e, 0x3f, 0x1d, 0xbf, 0xd0, 0x5c, 0x27, 0xbd, 0xf1, 0x70, 0x92, 0x64, 0xf8, 0x2c, 0x76, 0x81,
|
0x82, 0x1f, 0x21, 0xb9, 0xaf, 0x5e, 0x13, 0xe5, 0xe4, 0x4d, 0xa3, 0x08, 0x12, 0xf7, 0x0d, 0x58,
|
||||||
0xc3, 0xb3, 0xb2, 0x7e, 0xa9, 0x03, 0xac, 0xa5, 0xa2, 0xce, 0xf2, 0x98, 0xcc, 0x98, 0x06, 0xca,
|
0x58, 0xe8, 0xbc, 0x6b, 0x5c, 0x9d, 0x25, 0xe0, 0xbe, 0x06, 0xb7, 0xfc, 0x74, 0xfa, 0x8b, 0x68,
|
||||||
0x87, 0x81, 0x8f, 0xb2, 0x3e, 0xa9, 0x35, 0x8d, 0x4e, 0x8a, 0x8e, 0xa6, 0x1f, 0xc3, 0xff, 0x16,
|
0x9d, 0x95, 0x49, 0x93, 0x75, 0xe2, 0x8d, 0x7e, 0x5d, 0x0b, 0x8e, 0xd3, 0x2f, 0x0d, 0xd2, 0xe5,
|
||||||
0x7e, 0x9e, 0x8e, 0x2e, 0x04, 0x00, 0x00
|
0x23, 0x99, 0x43, 0x04, 0xc6, 0x50, 0x51, 0xec, 0x0e, 0xe0, 0xc9, 0x7b, 0xb8, 0xf7, 0xe6, 0xed,
|
||||||
|
0x96, 0x08, 0xa5, 0x71, 0x04, 0xee, 0x02, 0x9c, 0x75, 0x9d, 0xae, 0xcf, 0xda, 0x5f, 0xcf, 0xbf,
|
||||||
|
0x90, 0x7f, 0x01, 0x26, 0x24, 0x5a, 0x77, 0x58, 0x04, 0x00, 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Autogenerated from wled00/data/liveviewws2D.htm, do not edit!!
|
// Autogenerated from wled00/data/liveviewws2D.htm, do not edit!!
|
||||||
const uint16_t PAGE_liveviewws2D_length = 818;
|
const uint16_t PAGE_liveviewws2D_length = 870;
|
||||||
const uint8_t PAGE_liveviewws2D[] PROGMEM = {
|
const uint8_t PAGE_liveviewws2D[] PROGMEM = {
|
||||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x13, 0x6d, 0x54, 0x6d, 0x6f, 0xdb, 0x36,
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x13, 0x6d, 0x54, 0x6d, 0x6f, 0xdb, 0x36,
|
||||||
0x10, 0xfe, 0xee, 0x5f, 0xa1, 0x70, 0x43, 0x2b, 0xda, 0xb2, 0xe4, 0xb8, 0xed, 0x96, 0xd9, 0xa2,
|
0x10, 0xfe, 0xee, 0x5f, 0xa1, 0x70, 0x43, 0x2a, 0xc6, 0xb2, 0x64, 0xbb, 0xed, 0x96, 0xc5, 0xa2,
|
||||||
0x8b, 0x36, 0x35, 0xb0, 0x02, 0xd9, 0x6a, 0xc0, 0x19, 0x82, 0x21, 0x30, 0x50, 0x5a, 0x3a, 0x5b,
|
0x87, 0x35, 0x0d, 0xb0, 0x02, 0xd9, 0x6a, 0x20, 0x19, 0x82, 0x21, 0x30, 0x50, 0x5a, 0x3a, 0x5b,
|
||||||
0x5c, 0x25, 0xd2, 0xa0, 0xce, 0x96, 0x35, 0x47, 0xff, 0x7d, 0x47, 0xc9, 0xf1, 0x32, 0x74, 0xfa,
|
0x5c, 0x25, 0xd2, 0x20, 0xcf, 0x96, 0x35, 0x47, 0xff, 0x7d, 0x47, 0xc9, 0xc9, 0x32, 0x74, 0xfe,
|
||||||
0x40, 0x91, 0xf7, 0xf2, 0xdc, 0xf1, 0xb9, 0x3b, 0xc6, 0x57, 0x9f, 0xbe, 0xdc, 0xde, 0xff, 0xb9,
|
0x20, 0x93, 0xf7, 0xf2, 0xdc, 0xdb, 0x73, 0x4c, 0xcf, 0x3e, 0x7e, 0xbe, 0xbe, 0xff, 0x73, 0x71,
|
||||||
0x98, 0x7b, 0x19, 0x16, 0xf9, 0x2c, 0x3e, 0xaf, 0x20, 0xd3, 0x59, 0x5c, 0x00, 0x4a, 0x4f, 0xcb,
|
0x13, 0x14, 0x58, 0x95, 0xf3, 0xf4, 0xf4, 0x05, 0x99, 0xcf, 0xd3, 0x0a, 0x50, 0x06, 0x5a, 0x56,
|
||||||
0x02, 0x04, 0x3b, 0x28, 0xa8, 0x76, 0xc6, 0x22, 0xf3, 0x7a, 0x89, 0xd1, 0x08, 0x1a, 0x05, 0xab,
|
0x20, 0xd8, 0x5e, 0x41, 0xbd, 0x35, 0x16, 0x59, 0x30, 0xc8, 0x8c, 0x46, 0xd0, 0x28, 0x58, 0xad,
|
||||||
0x54, 0x8a, 0x99, 0x48, 0xe1, 0xa0, 0x12, 0x18, 0xb6, 0x87, 0x40, 0x69, 0x85, 0x4a, 0xe6, 0xc3,
|
0x72, 0x2c, 0x44, 0x0e, 0x7b, 0x95, 0xc1, 0xa8, 0xbb, 0x44, 0x4a, 0x2b, 0x54, 0xb2, 0x1c, 0xb9,
|
||||||
0x32, 0x91, 0x39, 0x88, 0xeb, 0xa0, 0x20, 0x41, 0xb1, 0x2f, 0x9e, 0xcf, 0xec, 0x8c, 0xd9, 0x4b,
|
0x4c, 0x96, 0x20, 0x26, 0x51, 0x45, 0x82, 0x6a, 0x57, 0x3d, 0xdf, 0xd9, 0x09, 0x73, 0x90, 0x15,
|
||||||
0x32, 0x69, 0x4b, 0x20, 0x8c, 0x3d, 0x6e, 0x86, 0x37, 0xec, 0x3f, 0xa1, 0x30, 0x83, 0x02, 0x86,
|
0xd2, 0x3a, 0x20, 0x8c, 0x1d, 0xae, 0x47, 0x97, 0xec, 0x3f, 0xa1, 0xb0, 0x80, 0x0a, 0x46, 0x99,
|
||||||
0x89, 0xc9, 0x8d, 0x65, 0xde, 0x25, 0xd8, 0x0f, 0xe3, 0xf6, 0x23, 0x53, 0x54, 0x98, 0xc3, 0xac,
|
0x29, 0x8d, 0x65, 0xc1, 0x4b, 0xb0, 0xef, 0xa6, 0xdd, 0x8f, 0x4c, 0x51, 0x61, 0x09, 0xf3, 0xc1,
|
||||||
0xf7, 0x70, 0x37, 0xff, 0xe4, 0xdd, 0xa9, 0x03, 0x78, 0x0b, 0x0b, 0x2e, 0xbd, 0x38, 0xea, 0x34,
|
0xc3, 0xed, 0xcd, 0xc7, 0xe0, 0x56, 0xed, 0x21, 0x58, 0x58, 0xf0, 0xe9, 0xa5, 0x49, 0xaf, 0x49,
|
||||||
0x71, 0x89, 0x35, 0xfd, 0xd6, 0x26, 0xad, 0x4f, 0x85, 0xb4, 0x5b, 0xa5, 0x27, 0xa3, 0x26, 0x8e,
|
0x1d, 0x36, 0xf4, 0xb7, 0x32, 0x79, 0x73, 0xac, 0xa4, 0xdd, 0x28, 0x7d, 0x35, 0x6e, 0xd3, 0xa4,
|
||||||
0x3a, 0x69, 0x1c, 0x75, 0x57, 0x73, 0xda, 0x59, 0x9c, 0x48, 0x7d, 0x90, 0xa5, 0xd7, 0x53, 0xa9,
|
0x97, 0xa6, 0x49, 0x5f, 0x9a, 0xd7, 0xce, 0xd3, 0x4c, 0xea, 0xbd, 0x74, 0xc1, 0x40, 0xe5, 0x82,
|
||||||
0x60, 0x6e, 0x4f, 0xe8, 0x51, 0x27, 0x23, 0x94, 0xc4, 0xaa, 0x1d, 0xce, 0x7a, 0x07, 0x69, 0xbd,
|
0xf9, 0x33, 0xa1, 0x27, 0xbd, 0x8c, 0x50, 0x32, 0xab, 0xb6, 0x38, 0x1f, 0xec, 0xa5, 0x0d, 0x32,
|
||||||
0x44, 0xa4, 0x26, 0xd9, 0x17, 0x94, 0x48, 0xb8, 0x05, 0x9c, 0xe7, 0xe0, 0xb6, 0x1f, 0xeb, 0xcf,
|
0x91, 0x9b, 0x6c, 0x57, 0x51, 0x22, 0xf1, 0x06, 0xf0, 0xa6, 0x04, 0x7f, 0xfc, 0xd0, 0x7c, 0xca,
|
||||||
0xa9, 0xdf, 0xb9, 0xf1, 0x20, 0x87, 0xb4, 0x14, 0x8c, 0x05, 0x98, 0x59, 0x83, 0x94, 0x45, 0x2a,
|
0xc3, 0xde, 0x8d, 0x47, 0x25, 0xe4, 0x4e, 0x30, 0x16, 0x61, 0x61, 0x0d, 0x52, 0x16, 0xb9, 0x38,
|
||||||
0xae, 0xae, 0xa7, 0x9b, 0xbd, 0x4e, 0x50, 0x19, 0xed, 0xd1, 0x55, 0x6f, 0x5b, 0x58, 0x9f, 0x9f,
|
0x9b, 0xcc, 0xd6, 0x3b, 0x9d, 0xa1, 0x32, 0x3a, 0xa0, 0x52, 0xaf, 0x3b, 0xd8, 0x90, 0x1f, 0xb3,
|
||||||
0x92, 0xb0, 0xe3, 0x2d, 0xfc, 0xe5, 0xa6, 0x5f, 0x29, 0x9d, 0x9a, 0x2a, 0x54, 0x5a, 0x83, 0x7d,
|
0xb8, 0xef, 0x5b, 0xfc, 0xd3, 0xe5, 0x45, 0xad, 0x74, 0x6e, 0xea, 0x58, 0x69, 0x0d, 0xf6, 0xa1,
|
||||||
0x68, 0x09, 0x4c, 0xc2, 0x0c, 0xd4, 0x36, 0xc3, 0xef, 0xd4, 0xbf, 0xb6, 0xe2, 0xe6, 0x05, 0xd2,
|
0x6b, 0x60, 0x16, 0x17, 0xa0, 0x36, 0x05, 0x7e, 0xa3, 0xfe, 0xb5, 0x13, 0xb7, 0xaf, 0x90, 0x66,
|
||||||
0xb4, 0xcd, 0x0c, 0x8f, 0x22, 0x71, 0x49, 0xdd, 0x3a, 0xa2, 0x8e, 0xe8, 0xb3, 0x71, 0xca, 0xf8,
|
0x5d, 0x66, 0x78, 0x10, 0x99, 0x4f, 0xea, 0xda, 0x37, 0xea, 0x80, 0x21, 0x9b, 0xe6, 0x8c, 0xcf,
|
||||||
0x54, 0x6d, 0x7c, 0xd2, 0xf0, 0x93, 0x33, 0xa9, 0xca, 0x29, 0xda, 0xfa, 0x54, 0x95, 0x02, 0xcd,
|
0xd4, 0x3a, 0x24, 0x0d, 0x3f, 0x7a, 0x93, 0xda, 0xcd, 0xd0, 0x36, 0xc7, 0xda, 0x09, 0x34, 0xdb,
|
||||||
0x2e, 0x3c, 0x63, 0x56, 0x65, 0x93, 0x48, 0x4c, 0x32, 0x1f, 0xf9, 0xa9, 0xa9, 0xca, 0x57, 0xaf,
|
0xf8, 0x84, 0x59, 0xbb, 0x36, 0x93, 0x98, 0x15, 0x21, 0xf2, 0x63, 0x4b, 0xd6, 0xb5, 0x3b, 0x3f,
|
||||||
0xaa, 0x32, 0xb4, 0xc4, 0x4c, 0xbd, 0x44, 0x89, 0x20, 0x84, 0x78, 0x80, 0xf5, 0xd2, 0x24, 0xdf,
|
0xaf, 0x5d, 0x6c, 0xa9, 0x39, 0xcd, 0x1d, 0x4a, 0x04, 0x21, 0xc4, 0x03, 0xac, 0xee, 0x4c, 0xf6,
|
||||||
0x00, 0xc3, 0x2f, 0x8b, 0xf9, 0xef, 0xef, 0x49, 0x5d, 0x82, 0xa6, 0xfb, 0x9e, 0x5e, 0xe7, 0x87,
|
0x15, 0x30, 0xfe, 0xbc, 0xb8, 0xf9, 0x9d, 0x93, 0xda, 0x81, 0xa6, 0x92, 0x8f, 0x6f, 0xca, 0xfd,
|
||||||
0xd7, 0x13, 0xb4, 0x7b, 0x68, 0x18, 0x9f, 0xf8, 0x84, 0xaa, 0xa1, 0xf2, 0x2e, 0xd6, 0xbe, 0xcf,
|
0x9b, 0x2b, 0xb4, 0x3b, 0x68, 0x29, 0x14, 0x94, 0x0e, 0x8e, 0x25, 0x60, 0x80, 0xe2, 0x84, 0x5d,
|
||||||
0x32, 0xc4, 0x5d, 0x39, 0x61, 0x42, 0x9c, 0x43, 0xe5, 0x86, 0x22, 0x11, 0x0b, 0xe1, 0x8e, 0xa8,
|
0x1a, 0x82, 0xa6, 0xb2, 0x23, 0x10, 0x18, 0x6f, 0x25, 0x16, 0x7e, 0xae, 0x91, 0x15, 0x10, 0xbb,
|
||||||
0x31, 0x54, 0xd7, 0xf7, 0xac, 0x2a, 0x4b, 0x36, 0xa1, 0x95, 0xf1, 0x01, 0x9b, 0x44, 0x11, 0x1b,
|
0x92, 0xa8, 0x12, 0x4e, 0x22, 0x88, 0x09, 0xc8, 0x3d, 0x28, 0x2c, 0x42, 0x96, 0x30, 0xfe, 0xf3,
|
||||||
0x5c, 0xe8, 0xbd, 0x18, 0x67, 0xa6, 0xc4, 0x01, 0x8b, 0x9c, 0x0d, 0x0f, 0x8d, 0x36, 0x3b, 0xd0,
|
0x68, 0x72, 0xb5, 0x37, 0x2a, 0x0f, 0xc6, 0x3c, 0x76, 0xdb, 0x52, 0x61, 0x27, 0x8d, 0x34, 0xb9,
|
||||||
0xc2, 0xe7, 0x62, 0x76, 0xfa, 0xff, 0x4c, 0x9a, 0x80, 0xe4, 0x6b, 0xa5, 0xa5, 0xad, 0xef, 0xeb,
|
0x1b, 0xab, 0x68, 0x80, 0x94, 0xd7, 0xb6, 0x94, 0xe4, 0xca, 0x0a, 0xc4, 0x2d, 0x8b, 0x58, 0xed,
|
||||||
0x1d, 0x75, 0x91, 0xb4, 0x56, 0xd6, 0xeb, 0xfd, 0x66, 0x03, 0x96, 0x39, 0x9d, 0x4c, 0xd3, 0xf9,
|
0x28, 0xb2, 0x8d, 0x4b, 0xd0, 0x1b, 0x2c, 0xe6, 0x93, 0xf3, 0xf3, 0x50, 0x0f, 0x05, 0x39, 0x0d,
|
||||||
0x81, 0x22, 0xdc, 0xa9, 0x92, 0x1a, 0x0a, 0xac, 0xcf, 0x0a, 0x28, 0x4b, 0xb9, 0x05, 0xaa, 0x19,
|
0xed, 0xe3, 0x78, 0xc9, 0x23, 0x2a, 0x47, 0x68, 0xa8, 0x83, 0x97, 0x0a, 0x48, 0xcd, 0x12, 0xef,
|
||||||
0xa1, 0x3a, 0x86, 0x88, 0x34, 0xf6, 0x68, 0xd6, 0x7f, 0x41, 0x82, 0xde, 0x07, 0xe7, 0xfe, 0xb1,
|
0xc4, 0x63, 0xa3, 0xcd, 0x16, 0xb4, 0x08, 0xb9, 0x98, 0x1f, 0xff, 0xbf, 0xa4, 0xb6, 0x25, 0xf9,
|
||||||
0x75, 0x5f, 0xd1, 0x55, 0x88, 0xba, 0x25, 0x5a, 0xa5, 0xb7, 0x21, 0x35, 0x72, 0xee, 0x63, 0x98,
|
0x4a, 0x69, 0x69, 0x9b, 0xfb, 0x66, 0x4b, 0x8c, 0x94, 0xd6, 0xca, 0x66, 0xb5, 0x5b, 0xaf, 0xc1,
|
||||||
0x4a, 0x94, 0x9c, 0x9f, 0x72, 0x40, 0x0f, 0x5b, 0x06, 0xfe, 0x50, 0x1a, 0x6f, 0x5a, 0x2f, 0x1f,
|
0xb2, 0x88, 0x74, 0x32, 0xcf, 0x6f, 0xf6, 0xc4, 0x80, 0x5b, 0xe5, 0x88, 0x9c, 0x60, 0x43, 0x56,
|
||||||
0x5c, 0x9c, 0xce, 0xc2, 0x15, 0xe2, 0xe7, 0x9f, 0xae, 0x04, 0x3e, 0x8e, 0x56, 0x4f, 0x4f, 0x63,
|
0x81, 0x73, 0x72, 0x03, 0x34, 0x7f, 0x42, 0xf5, 0xdd, 0xa6, 0x96, 0xb2, 0x47, 0xb3, 0xfa, 0x0b,
|
||||||
0xb7, 0xb9, 0xa6, 0xcd, 0x95, 0x2b, 0x8e, 0x05, 0xdc, 0x5b, 0x3d, 0x75, 0x10, 0x96, 0xe4, 0xe3,
|
0x32, 0x0c, 0x7e, 0xf1, 0xee, 0x1f, 0x3a, 0xf7, 0x25, 0xa3, 0xbe, 0xa2, 0xb9, 0x43, 0xab, 0xf4,
|
||||||
0x55, 0xa0, 0xe9, 0xf7, 0x66, 0x15, 0x18, 0xf1, 0x9b, 0xc4, 0x2c, 0xa4, 0xd9, 0xf1, 0xcf, 0xcd,
|
0x26, 0xa6, 0xa5, 0x28, 0x43, 0x8c, 0x73, 0x89, 0x92, 0xf3, 0x53, 0x0f, 0x7d, 0xda, 0x7f, 0x28,
|
||||||
0x12, 0xd9, 0x4b, 0x63, 0x44, 0x9a, 0x07, 0xb2, 0x33, 0xd8, 0xe4, 0xc6, 0x58, 0xff, 0xd9, 0x66,
|
0x8d, 0x97, 0x9d, 0x57, 0x08, 0x3e, 0x4e, 0x6f, 0xe1, 0x87, 0xfa, 0xe3, 0x0f, 0x67, 0x02, 0xa9,
|
||||||
0x68, 0xfa, 0x96, 0x47, 0xe3, 0xae, 0x2d, 0x40, 0xbc, 0x9d, 0x6e, 0x48, 0x59, 0x8b, 0xf0, 0xdd,
|
0xc4, 0xa7, 0xa7, 0xa9, 0x3f, 0x4c, 0xe8, 0x70, 0xe6, 0x07, 0x6d, 0x01, 0x77, 0x56, 0xcf, 0x3c,
|
||||||
0xb4, 0x8e, 0xf5, 0xb4, 0x1e, 0x0c, 0xb8, 0x13, 0x1c, 0x9d, 0xe0, 0x18, 0xdb, 0xe9, 0x91, 0x04,
|
0x84, 0x25, 0xf9, 0x74, 0xe9, 0x9b, 0xf7, 0xf8, 0x76, 0x19, 0x49, 0xf1, 0x1b, 0x0d, 0x20, 0xa6,
|
||||||
0x94, 0x45, 0xb8, 0x51, 0x79, 0xbe, 0x74, 0xa3, 0x21, 0xbe, 0xda, 0xed, 0xda, 0xff, 0xf1, 0x84,
|
0x3d, 0x0c, 0x4f, 0xc4, 0x4b, 0xec, 0x0b, 0xc9, 0x12, 0xcd, 0x23, 0xd5, 0x1b, 0xac, 0x4b, 0x63,
|
||||||
0x8f, 0xb0, 0x6a, 0x82, 0xf6, 0x3f, 0xb8, 0xbe, 0xec, 0xc6, 0xab, 0x86, 0x7f, 0x0d, 0x9c, 0xc3,
|
0x6c, 0xf8, 0x6c, 0x33, 0x92, 0x17, 0x96, 0x27, 0xd3, 0x9e, 0x62, 0x20, 0xde, 0xcd, 0xd6, 0xa4,
|
||||||
0x1a, 0x68, 0xa2, 0x16, 0x14, 0xdf, 0xe7, 0xed, 0x59, 0xda, 0xc4, 0x3f, 0xf6, 0xcd, 0x40, 0x06,
|
0x6c, 0x44, 0xfc, 0x7e, 0xd6, 0xa4, 0x7a, 0xd6, 0x0c, 0x87, 0xdc, 0x0b, 0x0e, 0x5e, 0x70, 0x48,
|
||||||
0x75, 0xdf, 0x04, 0xe1, 0x5b, 0x5a, 0x46, 0xc1, 0xb8, 0xdf, 0x66, 0xb8, 0xf8, 0xdc, 0xd9, 0xb8,
|
0xed, 0xec, 0x40, 0x02, 0xca, 0x22, 0x5e, 0xab, 0xb2, 0xbc, 0xf3, 0x6b, 0x26, 0xbe, 0xd8, 0xcd,
|
||||||
0x20, 0x64, 0x0e, 0x03, 0xf1, 0xa6, 0xf9, 0xb7, 0xef, 0x68, 0xb6, 0x4b, 0x93, 0x43, 0x08, 0xd6,
|
0x2a, 0xfc, 0xfe, 0x88, 0x8f, 0xb0, 0x6c, 0xa3, 0xee, 0x7f, 0x38, 0x79, 0x39, 0x4d, 0x97, 0x2d,
|
||||||
0x52, 0x66, 0x6c, 0x01, 0xf0, 0xcd, 0x7b, 0x58, 0x7a, 0xed, 0x71, 0x42, 0x65, 0xe1, 0x4d, 0xc3,
|
0xff, 0x12, 0x79, 0x87, 0x15, 0xd0, 0x70, 0x17, 0x14, 0x3f, 0xe4, 0xdd, 0x5d, 0xda, 0x2c, 0x3c,
|
||||||
0x9b, 0x73, 0x13, 0x7d, 0x5f, 0x3e, 0x0b, 0xa5, 0xfa, 0xfb, 0xb9, 0x7a, 0xcf, 0x53, 0xf7, 0xf4,
|
0x5c, 0xc8, 0xa1, 0x8a, 0x9a, 0x0b, 0x19, 0xc5, 0xef, 0xe8, 0x33, 0x8e, 0xa6, 0x17, 0x5d, 0x86,
|
||||||
0xe4, 0xbf, 0x98, 0x90, 0x97, 0xd3, 0x38, 0x0a, 0x48, 0x71, 0xaf, 0x0a, 0x30, 0x7b, 0x6a, 0x52,
|
0x8b, 0x4f, 0xbd, 0x8d, 0x0f, 0x42, 0xe6, 0x30, 0x14, 0x6f, 0xdb, 0x7f, 0x39, 0x4c, 0xef, 0x84,
|
||||||
0xfe, 0xd2, 0x89, 0x46, 0xb5, 0x09, 0xc6, 0xef, 0x46, 0x9c, 0x37, 0xbc, 0x47, 0x0f, 0x45, 0x37,
|
0x33, 0x25, 0xf1, 0xca, 0x5a, 0xca, 0x8c, 0x2d, 0x00, 0xbe, 0x06, 0x0f, 0x77, 0x41, 0x77, 0xbd,
|
||||||
0xf8, 0x71, 0xd4, 0xbd, 0x11, 0x51, 0xfb, 0x22, 0xfe, 0x03, 0x69, 0xb3, 0xce, 0x95, 0x27, 0x05,
|
0xa2, 0xb1, 0xd0, 0x50, 0x79, 0x7b, 0xe2, 0xe7, 0xb7, 0xe3, 0xb3, 0xe0, 0xd4, 0xdf, 0xcf, 0xd3,
|
||||||
0x00, 0x00
|
0x7b, 0xde, 0xe0, 0xa7, 0xa7, 0xf0, 0xd5, 0xb6, 0xbd, 0xde, 0xec, 0x71, 0x44, 0x8a, 0x7b, 0x55,
|
||||||
|
0x81, 0xd9, 0x61, 0xd8, 0x11, 0xe9, 0xf5, 0xda, 0xb7, 0xd1, 0xf4, 0xfd, 0x98, 0xf3, 0x96, 0x0f,
|
||||||
|
0xe8, 0xd1, 0xe9, 0x1f, 0x91, 0x34, 0xe9, 0xdf, 0x9b, 0xa4, 0x7b, 0x5d, 0xff, 0x01, 0x47, 0xe8,
|
||||||
|
0xd7, 0x03, 0x73, 0x05, 0x00, 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -341,60 +346,60 @@ const uint8_t PAGE_liveviewws2D[] PROGMEM = {
|
|||||||
const uint16_t PAGE_404_length = 868;
|
const uint16_t PAGE_404_length = 868;
|
||||||
const uint8_t PAGE_404[] PROGMEM = {
|
const uint8_t PAGE_404[] PROGMEM = {
|
||||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x13, 0x65, 0x54, 0x5b, 0x73, 0xaa, 0x3a,
|
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x13, 0x65, 0x54, 0x5b, 0x73, 0xaa, 0x3a,
|
||||||
0x14, 0x7e, 0xef, 0xaf, 0xe0, 0x78, 0xe6, 0xcc, 0x7e, 0x68, 0x2d, 0xa8, 0xd8, 0x2a, 0xa2, 0x33,
|
0x14, 0x7e, 0xef, 0xaf, 0x60, 0x7b, 0x66, 0xcf, 0x7e, 0x68, 0x15, 0x54, 0xac, 0x8a, 0xe8, 0x4c,
|
||||||
0x01, 0x51, 0xec, 0xc5, 0x7a, 0xa3, 0xd6, 0xbe, 0x05, 0x12, 0x21, 0x15, 0x08, 0x4d, 0x82, 0x62,
|
0x40, 0x14, 0x7b, 0xf1, 0x4e, 0xad, 0x7d, 0x0b, 0x10, 0x21, 0x15, 0x08, 0x4d, 0x82, 0x62, 0x3b,
|
||||||
0x3b, 0xfd, 0xef, 0x3b, 0x40, 0xf7, 0x9c, 0xce, 0xec, 0x35, 0x03, 0x2b, 0xf9, 0x56, 0xd6, 0x7d,
|
0xfd, 0xef, 0x3b, 0x40, 0x3b, 0xa7, 0x33, 0x7b, 0xcd, 0xc0, 0x4a, 0xbe, 0x95, 0x75, 0x5f, 0x89,
|
||||||
0x25, 0xe6, 0x3f, 0xe3, 0x27, 0x7b, 0xb3, 0x5b, 0x38, 0x4a, 0x24, 0x92, 0x78, 0x64, 0x7e, 0xff,
|
0xfe, 0x6b, 0xbc, 0x30, 0xb7, 0xfb, 0xa5, 0x25, 0x85, 0x3c, 0x8e, 0x46, 0xfa, 0xd7, 0x1f, 0x41,
|
||||||
0x31, 0x44, 0x23, 0x33, 0xc1, 0x02, 0x2a, 0x41, 0x04, 0x19, 0xc7, 0x62, 0xd8, 0xc8, 0xc5, 0xbe,
|
0x7f, 0xa4, 0xc7, 0x88, 0x43, 0xc9, 0x0b, 0x21, 0x65, 0x88, 0x0f, 0x6b, 0x19, 0x3f, 0xd4, 0x7b,
|
||||||
0xd9, 0x6b, 0x7c, 0xa3, 0x17, 0x01, 0x4d, 0x05, 0x4e, 0x25, 0x7c, 0x22, 0x48, 0x44, 0x43, 0x84,
|
0xb5, 0x2f, 0xf4, 0xca, 0x23, 0x09, 0x47, 0x89, 0x80, 0xcf, 0xd8, 0xe7, 0xe1, 0xd0, 0x47, 0x27,
|
||||||
0x8f, 0x24, 0xc0, 0xcd, 0x6a, 0xd3, 0x50, 0x52, 0x98, 0xe0, 0x61, 0xe3, 0x48, 0xf0, 0x29, 0xa3,
|
0xec, 0xa1, 0x7a, 0xb9, 0xa9, 0x49, 0x09, 0x8c, 0xd1, 0xb0, 0x76, 0xc2, 0xe8, 0x9c, 0x12, 0xca,
|
||||||
0x4c, 0xfc, 0xd1, 0xa9, 0x51, 0x11, 0xe1, 0x04, 0x37, 0x03, 0x1a, 0x53, 0xd6, 0xf8, 0x61, 0xe6,
|
0xbf, 0x75, 0x2a, 0x94, 0x87, 0x28, 0x46, 0x75, 0x8f, 0x44, 0x84, 0xd6, 0x7e, 0x98, 0xf9, 0xaf,
|
||||||
0xdf, 0x76, 0x45, 0xf2, 0xac, 0x20, 0x22, 0xc6, 0xa3, 0x39, 0x15, 0xca, 0x9e, 0xe6, 0x29, 0x32,
|
0x55, 0x92, 0x38, 0xcb, 0x31, 0x8f, 0xd0, 0x68, 0x4e, 0xb8, 0x74, 0x20, 0x59, 0xe2, 0xeb, 0x72,
|
||||||
0xd5, 0x1a, 0x30, 0xb9, 0x38, 0x4b, 0x76, 0xe1, 0x53, 0x74, 0xfe, 0xdc, 0x4b, 0xb5, 0xe6, 0x1e,
|
0x05, 0xe8, 0x8c, 0x5f, 0x04, 0xbb, 0x72, 0x89, 0x7f, 0xf9, 0x38, 0x08, 0xb5, 0xfa, 0x01, 0xc6,
|
||||||
0x26, 0x24, 0x3e, 0x1b, 0xcf, 0x98, 0x21, 0x98, 0xc2, 0x2b, 0x17, 0xc7, 0x47, 0x2c, 0x48, 0x00,
|
0x38, 0xba, 0x68, 0x4f, 0x88, 0xfa, 0x30, 0x81, 0x37, 0x36, 0x8a, 0x4e, 0x88, 0x63, 0x0f, 0xde,
|
||||||
0xaf, 0x38, 0x4c, 0x79, 0x93, 0x63, 0x46, 0xf6, 0x03, 0x81, 0x0b, 0xd1, 0x84, 0x31, 0x09, 0x53,
|
0x30, 0x98, 0xb0, 0x3a, 0x43, 0x14, 0x1f, 0x06, 0x1c, 0xe5, 0xbc, 0x0e, 0x23, 0x1c, 0x24, 0x9a,
|
||||||
0x23, 0x90, 0x7e, 0x30, 0x1b, 0xf8, 0x30, 0x38, 0x84, 0xac, 0xb4, 0x5c, 0x07, 0x61, 0x94, 0x9e,
|
0x27, 0xfc, 0x20, 0x3a, 0x70, 0xa1, 0x77, 0x0c, 0x68, 0x61, 0xb9, 0x0a, 0x42, 0x2b, 0x3c, 0x0f,
|
||||||
0x07, 0x09, 0x64, 0x21, 0x49, 0x0d, 0x6d, 0xf0, 0x8d, 0xed, 0xf7, 0xfb, 0x2f, 0x92, 0x84, 0x9f,
|
0x62, 0x48, 0x03, 0x9c, 0x68, 0xca, 0xe0, 0x0b, 0x3b, 0x1c, 0x0e, 0x9f, 0x38, 0x0e, 0x3e, 0xca,
|
||||||
0x55, 0x42, 0x86, 0xae, 0x69, 0x59, 0x21, 0xcf, 0x14, 0x75, 0x82, 0x46, 0x57, 0xfb, 0x6f, 0x40,
|
0x84, 0x34, 0x55, 0x51, 0xd2, 0x5c, 0x9c, 0xc9, 0xab, 0x04, 0xb5, 0x8e, 0xf2, 0x7b, 0x80, 0x63,
|
||||||
0x12, 0x18, 0xe2, 0x26, 0xc3, 0x29, 0x92, 0x8e, 0xd2, 0xd0, 0xc8, 0x48, 0x81, 0x63, 0x28, 0x30,
|
0x18, 0xa0, 0x3a, 0x45, 0x89, 0x2f, 0x1c, 0x25, 0x81, 0x96, 0xe2, 0x1c, 0x45, 0x90, 0x23, 0xff,
|
||||||
0xfa, 0x4b, 0x12, 0x30, 0xc2, 0xb3, 0x26, 0x46, 0x21, 0xe6, 0x7f, 0xfc, 0xb4, 0xbb, 0x59, 0xa1,
|
0x1f, 0x89, 0x47, 0x31, 0x4b, 0xeb, 0xc8, 0x0f, 0x10, 0xfb, 0xf6, 0xd3, 0xea, 0xa4, 0xb9, 0xa4,
|
||||||
0x68, 0x4a, 0xb3, 0xa5, 0x95, 0xfc, 0xcb, 0xcf, 0x85, 0xa0, 0xe9, 0x27, 0xcd, 0x45, 0x4c, 0x52,
|
0x48, 0xf5, 0xa6, 0x52, 0xf0, 0x4f, 0x37, 0xe3, 0x9c, 0x24, 0x1f, 0x24, 0xe3, 0x11, 0x4e, 0x50,
|
||||||
0x5c, 0x46, 0x91, 0x33, 0x2e, 0xc3, 0xc8, 0x28, 0xa9, 0x62, 0xce, 0x20, 0x42, 0xa5, 0xa5, 0x5e,
|
0x11, 0x45, 0x46, 0x99, 0x08, 0x23, 0x25, 0xb8, 0x8c, 0x39, 0x85, 0xbe, 0x5f, 0x58, 0xea, 0x95,
|
||||||
0x15, 0x45, 0x65, 0xa1, 0xd4, 0x1c, 0xd4, 0xd1, 0xb4, 0x3b, 0xe5, 0xba, 0xca, 0x54, 0x30, 0x99,
|
0x51, 0x94, 0x16, 0x0a, 0xcd, 0x41, 0x15, 0x4d, 0xab, 0x5d, 0xac, 0xcb, 0x4c, 0x39, 0x15, 0xa9,
|
||||||
0xfa, 0x9e, 0xb2, 0xc4, 0xc8, 0xb3, 0x0c, 0xb3, 0x00, 0x72, 0x3c, 0xf8, 0x59, 0xab, 0xe8, 0x4f,
|
0x1f, 0x08, 0x8d, 0xb5, 0x2c, 0x4d, 0x11, 0xf5, 0x20, 0x43, 0x83, 0x9f, 0xb5, 0x0a, 0xbf, 0x6b,
|
||||||
0x8d, 0x6a, 0x94, 0x93, 0x0f, 0x6c, 0xb4, 0xfa, 0x52, 0xfb, 0xef, 0xaa, 0x74, 0x3a, 0x9d, 0x1f,
|
0x54, 0xa1, 0x0c, 0xbf, 0x23, 0xad, 0xd9, 0x17, 0xda, 0xff, 0x56, 0xa5, 0xdd, 0x6e, 0xff, 0x28,
|
||||||
0xc5, 0x18, 0xf8, 0x94, 0xc9, 0x74, 0x0c, 0x4d, 0xe1, 0x34, 0x26, 0x48, 0xf9, 0x81, 0x35, 0x19,
|
0xc6, 0xc0, 0x25, 0x54, 0xa4, 0xa3, 0x29, 0x12, 0x23, 0x11, 0xf6, 0xa5, 0x1f, 0x58, 0x9d, 0x42,
|
||||||
0x44, 0x24, 0xe7, 0x55, 0x4e, 0x5f, 0x17, 0xa6, 0x5a, 0xf7, 0xc9, 0x54, 0xeb, 0x19, 0x2a, 0xdb,
|
0x1f, 0x67, 0xac, 0xcc, 0xe9, 0xf3, 0x4a, 0x97, 0xab, 0x3e, 0xe9, 0x72, 0x35, 0x43, 0x45, 0xbb,
|
||||||
0x35, 0x32, 0x65, 0x29, 0x15, 0x18, 0xcb, 0x36, 0xcb, 0x96, 0x73, 0x16, 0x0c, 0x1b, 0x08, 0x0a,
|
0x46, 0xba, 0x28, 0xa5, 0x04, 0x23, 0xd1, 0x66, 0xd1, 0x72, 0x46, 0xbd, 0x61, 0xcd, 0x87, 0x1c,
|
||||||
0x68, 0x54, 0x85, 0x52, 0xb3, 0x34, 0x94, 0xee, 0x39, 0xbe, 0xd1, 0xaf, 0xc8, 0xb3, 0xf5, 0xb4,
|
0x6a, 0x65, 0xa1, 0xe4, 0x34, 0x09, 0x84, 0x7b, 0x86, 0x6e, 0xd5, 0x1b, 0xfc, 0x64, 0x2c, 0xd6,
|
||||||
0x3a, 0x69, 0xf7, 0xd3, 0x90, 0x02, 0x49, 0xf3, 0xb5, 0x17, 0x39, 0x5e, 0x28, 0x57, 0x76, 0xb9,
|
0x67, 0xe5, 0x7e, 0x1a, 0x10, 0x20, 0x68, 0xbe, 0x71, 0x42, 0xcb, 0x09, 0xc4, 0xca, 0x2c, 0xb6,
|
||||||
0x05, 0xa1, 0x0d, 0x1e, 0x25, 0xb3, 0x9c, 0x6c, 0xc6, 0xa6, 0x15, 0xf2, 0x32, 0x5f, 0xaf, 0xb4,
|
0x20, 0x30, 0xc1, 0xa3, 0x60, 0x86, 0x95, 0xce, 0xe8, 0xb4, 0x44, 0x9e, 0xe7, 0x9b, 0xb5, 0x32,
|
||||||
0x19, 0x60, 0x5c, 0x0f, 0x6e, 0x96, 0x25, 0xb0, 0x4a, 0x97, 0x5e, 0xcb, 0x92, 0x0a, 0xc5, 0xdb,
|
0x03, 0x94, 0xa9, 0xde, 0xed, 0xaa, 0x00, 0xd6, 0xc9, 0xca, 0x69, 0x1a, 0x42, 0x21, 0x7f, 0x3d,
|
||||||
0xe9, 0xd8, 0xdb, 0x2d, 0xbd, 0x12, 0xf4, 0x3d, 0xa7, 0xf0, 0x56, 0x95, 0xdc, 0xea, 0xb5, 0x42,
|
0x9f, 0x7a, 0xfb, 0x95, 0x53, 0x80, 0xae, 0x63, 0xe5, 0xce, 0xba, 0x94, 0x1b, 0xbd, 0x66, 0x60,
|
||||||
0xdb, 0x53, 0x3f, 0xee, 0xdf, 0xd5, 0x92, 0xfa, 0xfe, 0xb6, 0x45, 0x6d, 0x10, 0x4e, 0x23, 0x0a,
|
0x3a, 0xf2, 0xfb, 0xfd, 0x9b, 0x5c, 0x50, 0xdf, 0xdd, 0x35, 0x89, 0x09, 0x82, 0x69, 0x48, 0x60,
|
||||||
0x4b, 0xf1, 0x74, 0xf1, 0xf0, 0xd2, 0xab, 0x2c, 0xdf, 0xa1, 0xc9, 0xdd, 0x93, 0xa7, 0xfe, 0x4f,
|
0x21, 0x9e, 0x2e, 0x1f, 0x9e, 0x7b, 0xa5, 0xe5, 0x3b, 0x7f, 0x72, 0xb7, 0x70, 0xe4, 0xff, 0x09,
|
||||||
0x60, 0x32, 0x5f, 0x60, 0x6b, 0x56, 0xc9, 0x02, 0x27, 0x7a, 0x0d, 0x4e, 0x00, 0x8c, 0x79, 0xb9,
|
0x4c, 0xe6, 0x4b, 0x64, 0xcc, 0x4a, 0x99, 0x67, 0x85, 0x2f, 0xde, 0x19, 0x80, 0x31, 0x2b, 0xb6,
|
||||||
0xbd, 0x05, 0x60, 0xcb, 0xb6, 0x64, 0x79, 0x28, 0x03, 0x45, 0x6b, 0x6f, 0x65, 0x3d, 0x8f, 0xa3,
|
0x5d, 0x00, 0x76, 0x74, 0x87, 0x57, 0xc7, 0x22, 0x50, 0x7f, 0xe3, 0xac, 0x8d, 0xa7, 0x71, 0xb8,
|
||||||
0x45, 0x11, 0xf4, 0xfd, 0x31, 0xf5, 0x42, 0x07, 0xcc, 0x97, 0xd8, 0x5f, 0xa8, 0x13, 0x2f, 0x77,
|
0xcc, 0xbd, 0xbe, 0x3b, 0x26, 0x4e, 0x60, 0x81, 0xf9, 0x0a, 0xb9, 0x4b, 0x79, 0xe2, 0x64, 0xf6,
|
||||||
0x1f, 0xdf, 0xac, 0xe9, 0x4e, 0xb5, 0x2e, 0x3b, 0xce, 0x6e, 0x75, 0xbb, 0x72, 0xb5, 0x77, 0x5b,
|
0xe3, 0xab, 0x31, 0xdd, 0xcb, 0xc6, 0x75, 0xdb, 0xda, 0xaf, 0xbb, 0x6b, 0x5b, 0x79, 0x33, 0xe5,
|
||||||
0x7d, 0xb5, 0x82, 0x1b, 0xf7, 0x64, 0xc7, 0x6f, 0xa1, 0xfb, 0x74, 0x59, 0xbc, 0xce, 0x9e, 0xd7,
|
0x17, 0xc3, 0xbb, 0xb5, 0xcf, 0x66, 0xf4, 0x1a, 0xd8, 0x8b, 0xeb, 0xfc, 0x65, 0xf6, 0xb4, 0x99,
|
||||||
0xb3, 0x36, 0xdf, 0x85, 0x2e, 0x9c, 0xde, 0x3a, 0xd6, 0x36, 0xea, 0xbd, 0x6d, 0x69, 0xb1, 0x61,
|
0xb5, 0xd8, 0x3e, 0xb0, 0xe1, 0xb4, 0x6b, 0x19, 0xbb, 0xb0, 0xf7, 0xba, 0x23, 0xf9, 0x96, 0x9a,
|
||||||
0xb6, 0x35, 0x41, 0xe3, 0xbb, 0x4b, 0x6b, 0xac, 0xc7, 0xfe, 0xcc, 0x2d, 0x40, 0xf0, 0xd1, 0x03,
|
0xc6, 0xc4, 0x1f, 0xdf, 0x5d, 0x1b, 0x63, 0x35, 0x72, 0x67, 0x76, 0x0e, 0xbc, 0xf7, 0x1e, 0x58,
|
||||||
0x0b, 0xf0, 0xfc, 0xb0, 0xe1, 0xec, 0xd5, 0xd1, 0xf1, 0x72, 0xdc, 0x7d, 0xff, 0x10, 0x9d, 0x00,
|
0x82, 0xa7, 0x87, 0x2d, 0xa3, 0x2f, 0x96, 0x8a, 0x56, 0xe3, 0xce, 0xdb, 0x3b, 0x6f, 0x7b, 0x60,
|
||||||
0x4c, 0x36, 0x3b, 0x7a, 0xb0, 0xf5, 0x9d, 0x3d, 0xef, 0x4f, 0xcf, 0x7e, 0x98, 0xeb, 0x67, 0xb0,
|
0xb2, 0xdd, 0x93, 0xa3, 0xa9, 0xee, 0xcd, 0x79, 0x7f, 0x7a, 0x71, 0x83, 0x4c, 0xbd, 0x80, 0x15,
|
||||||
0x14, 0xd6, 0xe4, 0x61, 0xf9, 0xe2, 0xe6, 0x2e, 0xb0, 0xc0, 0xed, 0xdd, 0x23, 0x7e, 0x72, 0x6c,
|
0x37, 0x26, 0x0f, 0xab, 0x67, 0x3b, 0xb3, 0x81, 0x01, 0xba, 0x77, 0x8f, 0x68, 0x61, 0x99, 0xb2,
|
||||||
0xd5, 0xd1, 0xb6, 0xdd, 0xfc, 0xdc, 0x0f, 0x8f, 0xfa, 0x91, 0x76, 0x97, 0xee, 0x7d, 0x9b, 0xdc,
|
0xa5, 0xec, 0x3a, 0xd9, 0xa5, 0x1f, 0x9c, 0xd4, 0x13, 0xe9, 0xac, 0xec, 0xfb, 0x16, 0xee, 0x5e,
|
||||||
0x9e, 0xdf, 0xdb, 0x76, 0xcf, 0x03, 0xd6, 0xa3, 0xee, 0x26, 0x0f, 0x97, 0xf6, 0x7a, 0xf3, 0x62,
|
0xde, 0x5a, 0x66, 0xcf, 0x01, 0xc6, 0xa3, 0x6a, 0xc7, 0x0f, 0xd7, 0xe6, 0x66, 0xfb, 0x6c, 0x6e,
|
||||||
0x6f, 0x26, 0xad, 0x31, 0xb3, 0x5f, 0x6e, 0x2e, 0xa7, 0x59, 0xff, 0xc3, 0xea, 0xa2, 0x2a, 0x5b,
|
0x27, 0xcd, 0x31, 0x35, 0x9f, 0x6f, 0xaf, 0xa7, 0x69, 0xff, 0xdd, 0xe8, 0xf8, 0x65, 0xb6, 0xc0,
|
||||||
0xe0, 0xc4, 0x93, 0xcd, 0x61, 0x9d, 0x2f, 0x13, 0xdb, 0x6e, 0x8c, 0x2e, 0xcc, 0xa8, 0x35, 0xd2,
|
0x8a, 0x26, 0xdb, 0xe3, 0x26, 0x5b, 0xc5, 0xa6, 0x59, 0x1b, 0x5d, 0xe9, 0x61, 0x73, 0xa4, 0x2a,
|
||||||
0x35, 0x5d, 0x29, 0xef, 0xeb, 0xa4, 0xbe, 0xaf, 0x12, 0x31, 0xfd, 0x11, 0x38, 0xe0, 0x84, 0x28,
|
0xaa, 0x54, 0xdc, 0xd7, 0x49, 0x75, 0x5f, 0x05, 0xa2, 0xbb, 0x23, 0x70, 0x44, 0x31, 0x96, 0x7c,
|
||||||
0x88, 0x62, 0xae, 0xa4, 0x52, 0x76, 0x48, 0xe9, 0x49, 0x39, 0x45, 0x98, 0x61, 0xe5, 0x4c, 0x73,
|
0x82, 0x98, 0x94, 0x08, 0xd9, 0x31, 0x21, 0x67, 0xe9, 0x1c, 0x22, 0x8a, 0xa4, 0x0b, 0xc9, 0x24,
|
||||||
0x05, 0x4a, 0x5e, 0x0e, 0x08, 0x46, 0xd7, 0xd7, 0xd7, 0xa6, 0xea, 0x4b, 0x0d, 0x56, 0x7d, 0x17,
|
0x28, 0x78, 0x31, 0x20, 0xc8, 0x6f, 0x34, 0x1a, 0xba, 0xec, 0x0a, 0x0d, 0x5a, 0x7e, 0x57, 0x7a,
|
||||||
0x66, 0x7d, 0x19, 0x14, 0x9a, 0x06, 0x31, 0x09, 0x0e, 0xc3, 0x5f, 0x27, 0x92, 0x22, 0x7a, 0xba,
|
0x75, 0x19, 0x24, 0x92, 0x78, 0x11, 0xf6, 0x8e, 0xc3, 0x3f, 0x67, 0x9c, 0xf8, 0xe4, 0xdc, 0x88,
|
||||||
0x8e, 0x69, 0x00, 0x05, 0xa1, 0xe9, 0x75, 0xc4, 0xf0, 0x7e, 0xd8, 0x50, 0xb9, 0x1c, 0x43, 0xcc,
|
0x88, 0x07, 0x39, 0x26, 0x49, 0x23, 0xa4, 0xe8, 0x30, 0xac, 0x35, 0x1a, 0x32, 0x13, 0x83, 0x88,
|
||||||
0x78, 0xe3, 0xd7, 0xc8, 0x92, 0xb3, 0xab, 0x08, 0xaa, 0x94, 0x6f, 0x09, 0xa3, 0x31, 0x97, 0xe6,
|
0x28, 0xab, 0xfd, 0x19, 0x19, 0x62, 0x7a, 0x25, 0x4e, 0xa4, 0xe2, 0x35, 0xa1, 0x24, 0x62, 0xc2,
|
||||||
0x2a, 0x13, 0xd2, 0x96, 0x5a, 0x8f, 0x9f, 0x5a, 0xbd, 0x6a, 0xbf, 0x01, 0x22, 0xc8, 0xb7, 0x64,
|
0x60, 0x69, 0x44, 0x58, 0x93, 0xab, 0x01, 0x94, 0xcb, 0x77, 0xed, 0x2f, 0xa3, 0xab, 0x2b, 0xfe,
|
||||||
0xeb, 0x04, 0x00, 0x00
|
0xed, 0x04, 0x00, 0x00
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
2243
wled00/html_simple.h
2243
wled00/html_simple.h
File diff suppressed because it is too large
Load Diff
3927
wled00/html_ui.h
3927
wled00/html_ui.h
File diff suppressed because it is too large
Load Diff
@ -189,7 +189,7 @@ void sendImprovInfoResponse() {
|
|||||||
out[11] = 4; //Firmware len ("WLED")
|
out[11] = 4; //Firmware len ("WLED")
|
||||||
out[12] = 'W'; out[13] = 'L'; out[14] = 'E'; out[15] = 'D';
|
out[12] = 'W'; out[13] = 'L'; out[14] = 'E'; out[15] = 'D';
|
||||||
uint8_t lengthSum = 17;
|
uint8_t lengthSum = 17;
|
||||||
uint8_t vlen = sprintf_P(out+lengthSum,PSTR("0.14.0-b2/%i"),VERSION);
|
uint8_t vlen = sprintf_P(out+lengthSum,PSTR("0.14.0-b3/%i"),VERSION);
|
||||||
out[16] = vlen; lengthSum += vlen;
|
out[16] = vlen; lengthSum += vlen;
|
||||||
uint8_t hlen = 7;
|
uint8_t hlen = 7;
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#define JSON_PATH_PALETTES 5
|
#define JSON_PATH_PALETTES 5
|
||||||
#define JSON_PATH_FXDATA 6
|
#define JSON_PATH_FXDATA 6
|
||||||
#define JSON_PATH_NETWORKS 7
|
#define JSON_PATH_NETWORKS 7
|
||||||
|
#define JSON_PATH_EFFECTS 8
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* JSON API (De)serialization
|
* JSON API (De)serialization
|
||||||
@ -812,7 +813,7 @@ void setPaletteColors(JsonArray json, byte* tcp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void serializePalettes(JsonObject root, AsyncWebServerRequest* request)
|
void serializePalettes(JsonObject root, int page)
|
||||||
{
|
{
|
||||||
byte tcp[72];
|
byte tcp[72];
|
||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
@ -821,11 +822,6 @@ void serializePalettes(JsonObject root, AsyncWebServerRequest* request)
|
|||||||
int itemPerPage = 8;
|
int itemPerPage = 8;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int page = 0;
|
|
||||||
if (request->hasParam("page")) {
|
|
||||||
page = request->getParam("page")->value().toInt();
|
|
||||||
}
|
|
||||||
|
|
||||||
int palettesCount = strip.getPaletteCount();
|
int palettesCount = strip.getPaletteCount();
|
||||||
int customPalettes = strip.customPalettes.size();
|
int customPalettes = strip.customPalettes.size();
|
||||||
|
|
||||||
@ -1001,6 +997,7 @@ void serveJson(AsyncWebServerRequest* request)
|
|||||||
else if (url.indexOf("info") > 0) subJson = JSON_PATH_INFO;
|
else if (url.indexOf("info") > 0) subJson = JSON_PATH_INFO;
|
||||||
else if (url.indexOf("si") > 0) subJson = JSON_PATH_STATE_INFO;
|
else if (url.indexOf("si") > 0) subJson = JSON_PATH_STATE_INFO;
|
||||||
else if (url.indexOf("nodes") > 0) subJson = JSON_PATH_NODES;
|
else if (url.indexOf("nodes") > 0) subJson = JSON_PATH_NODES;
|
||||||
|
else if (url.indexOf("eff") > 0) subJson = JSON_PATH_EFFECTS;
|
||||||
else if (url.indexOf("palx") > 0) subJson = JSON_PATH_PALETTES;
|
else if (url.indexOf("palx") > 0) subJson = JSON_PATH_PALETTES;
|
||||||
else if (url.indexOf("fxda") > 0) subJson = JSON_PATH_FXDATA;
|
else if (url.indexOf("fxda") > 0) subJson = JSON_PATH_FXDATA;
|
||||||
else if (url.indexOf("net") > 0) subJson = JSON_PATH_NETWORKS;
|
else if (url.indexOf("net") > 0) subJson = JSON_PATH_NETWORKS;
|
||||||
@ -1010,20 +1007,6 @@ void serveJson(AsyncWebServerRequest* request)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
else if (url.indexOf(F("eff")) > 0) {
|
|
||||||
// this serves just effect names without FX data extensions in names
|
|
||||||
if (requestJSONBufferLock(19)) {
|
|
||||||
AsyncJsonResponse* response = new AsyncJsonResponse(&doc, true); // array document
|
|
||||||
JsonArray lDoc = response->getRoot();
|
|
||||||
serializeModeNames(lDoc); // remove WLED-SR extensions from effect names
|
|
||||||
response->setLength();
|
|
||||||
request->send(response);
|
|
||||||
releaseJSONBufferLock();
|
|
||||||
} else {
|
|
||||||
request->send(503, "application/json", F("{\"error\":3}"));
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
else if (url.indexOf("pal") > 0) {
|
else if (url.indexOf("pal") > 0) {
|
||||||
request->send_P(200, "application/json", JSON_palette_names);
|
request->send_P(200, "application/json", JSON_palette_names);
|
||||||
return;
|
return;
|
||||||
@ -1040,7 +1023,7 @@ void serveJson(AsyncWebServerRequest* request)
|
|||||||
request->send(503, "application/json", F("{\"error\":3}"));
|
request->send(503, "application/json", F("{\"error\":3}"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
AsyncJsonResponse *response = new AsyncJsonResponse(&doc, subJson==6);
|
AsyncJsonResponse *response = new AsyncJsonResponse(&doc, subJson==JSON_PATH_FXDATA || subJson==JSON_PATH_EFFECTS); // will clear and convert JsonDocument into JsonArray if necessary
|
||||||
|
|
||||||
JsonVariant lDoc = response->getRoot();
|
JsonVariant lDoc = response->getRoot();
|
||||||
|
|
||||||
@ -1053,9 +1036,11 @@ void serveJson(AsyncWebServerRequest* request)
|
|||||||
case JSON_PATH_NODES:
|
case JSON_PATH_NODES:
|
||||||
serializeNodes(lDoc); break;
|
serializeNodes(lDoc); break;
|
||||||
case JSON_PATH_PALETTES:
|
case JSON_PATH_PALETTES:
|
||||||
serializePalettes(lDoc, request); break;
|
serializePalettes(lDoc, request->hasParam("page") ? request->getParam("page")->value().toInt() : 0); break;
|
||||||
|
case JSON_PATH_EFFECTS:
|
||||||
|
serializeModeNames(lDoc); break;
|
||||||
case JSON_PATH_FXDATA:
|
case JSON_PATH_FXDATA:
|
||||||
serializeModeData(lDoc.as<JsonArray>()); break;
|
serializeModeData(lDoc); break;
|
||||||
case JSON_PATH_NETWORKS:
|
case JSON_PATH_NETWORKS:
|
||||||
serializeNetworks(lDoc); break;
|
serializeNetworks(lDoc); break;
|
||||||
default: //all
|
default: //all
|
||||||
@ -1074,7 +1059,9 @@ void serveJson(AsyncWebServerRequest* request)
|
|||||||
|
|
||||||
DEBUG_PRINTF("JSON buffer size: %u for request: %d\n", lDoc.memoryUsage(), subJson);
|
DEBUG_PRINTF("JSON buffer size: %u for request: %d\n", lDoc.memoryUsage(), subJson);
|
||||||
|
|
||||||
response->setLength();
|
size_t len = response->setLength();
|
||||||
|
DEBUG_PRINT(F("JSON content length: ")); DEBUG_PRINTLN(len);
|
||||||
|
|
||||||
request->send(response);
|
request->send(response);
|
||||||
releaseJSONBufferLock();
|
releaseJSONBufferLock();
|
||||||
}
|
}
|
||||||
|
@ -37,8 +37,8 @@ void applyValuesToSelectedSegs()
|
|||||||
|
|
||||||
if (effectSpeed != selsegPrev.speed) {seg.speed = effectSpeed; stateChanged = true;}
|
if (effectSpeed != selsegPrev.speed) {seg.speed = effectSpeed; stateChanged = true;}
|
||||||
if (effectIntensity != selsegPrev.intensity) {seg.intensity = effectIntensity; stateChanged = true;}
|
if (effectIntensity != selsegPrev.intensity) {seg.intensity = effectIntensity; stateChanged = true;}
|
||||||
if (effectPalette != selsegPrev.palette) {seg.palette = effectPalette; stateChanged = true;}
|
if (effectPalette != selsegPrev.palette) {seg.setPalette(effectPalette); stateChanged = true;}
|
||||||
if (effectCurrent != selsegPrev.mode) {strip.setMode(i, effectCurrent); stateChanged = true;}
|
if (effectCurrent != selsegPrev.mode) {seg.setMode(effectCurrent); stateChanged = true;}
|
||||||
uint32_t col0 = RGBW32( col[0], col[1], col[2], col[3]);
|
uint32_t col0 = RGBW32( col[0], col[1], col[2], col[3]);
|
||||||
uint32_t col1 = RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]);
|
uint32_t col1 = RGBW32(colSec[0], colSec[1], colSec[2], colSec[3]);
|
||||||
if (col0 != selsegPrev.colors[0]) {seg.setColor(0, col0); stateChanged = true;}
|
if (col0 != selsegPrev.colors[0]) {seg.setColor(0, col0); stateChanged = true;}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
/*
|
/*
|
||||||
* Parser for Loxone formats
|
* Parser for Loxone formats
|
||||||
*/
|
*/
|
||||||
bool parseLx(int lxValue, byte rgbw[4])
|
bool parseLx(int lxValue, byte* rgbw)
|
||||||
{
|
{
|
||||||
DEBUG_PRINT(F("LX: Lox = "));
|
DEBUG_PRINT(F("LX: Lox = "));
|
||||||
DEBUG_PRINTLN(lxValue);
|
DEBUG_PRINTLN(lxValue);
|
||||||
|
@ -167,7 +167,8 @@ void handlePresets()
|
|||||||
changePreset = true;
|
changePreset = true;
|
||||||
} else {
|
} else {
|
||||||
if (!fdo["seg"].isNull() || !fdo["on"].isNull() || !fdo["bri"].isNull() || !fdo["nl"].isNull() || !fdo["ps"].isNull() || !fdo[F("playlist")].isNull()) changePreset = true;
|
if (!fdo["seg"].isNull() || !fdo["on"].isNull() || !fdo["bri"].isNull() || !fdo["nl"].isNull() || !fdo["ps"].isNull() || !fdo[F("playlist")].isNull()) changePreset = true;
|
||||||
fdo.remove("ps"); //remove load request for presets to prevent recursive crash
|
if (!(tmpMode == CALL_MODE_BUTTON_PRESET && fdo["ps"].is<const char *>() && strchr(fdo["ps"].as<const char *>(),'~') != strrchr(fdo["ps"].as<const char *>(),'~')))
|
||||||
|
fdo.remove("ps"); // remove load request for presets to prevent recursive crash (if not called by button and contains preset cycling string "1~5~")
|
||||||
deserializeState(fdo, CALL_MODE_NO_NOTIFY, tmpPreset); // may change presetToApply by calling applyPreset()
|
deserializeState(fdo, CALL_MODE_NO_NOTIFY, tmpPreset); // may change presetToApply by calling applyPreset()
|
||||||
}
|
}
|
||||||
if (!errorFlag && tmpPreset < 255 && changePreset) presetCycCurr = currentPreset = tmpPreset;
|
if (!errorFlag && tmpPreset < 255 && changePreset) presetCycCurr = currentPreset = tmpPreset;
|
||||||
|
@ -233,7 +233,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
gammaCorrectCol = request->hasArg(F("GC"));
|
gammaCorrectCol = request->hasArg(F("GC"));
|
||||||
gammaCorrectVal = request->arg(F("GV")).toFloat();
|
gammaCorrectVal = request->arg(F("GV")).toFloat();
|
||||||
if (gammaCorrectVal > 1.0f && gammaCorrectVal <= 3)
|
if (gammaCorrectVal > 1.0f && gammaCorrectVal <= 3)
|
||||||
calcGammaTable(gammaCorrectVal);
|
NeoGammaWLEDMethod::calcGammaTable(gammaCorrectVal);
|
||||||
else {
|
else {
|
||||||
gammaCorrectVal = 1.0f; // no gamma correction
|
gammaCorrectVal = 1.0f; // no gamma correction
|
||||||
gammaCorrectBri = false;
|
gammaCorrectBri = false;
|
||||||
@ -462,7 +462,7 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
clearEEPROM();
|
clearEEPROM();
|
||||||
#endif
|
#endif
|
||||||
serveMessage(request, 200, F("All Settings erased."), F("Connect to WLED-AP to setup again"),255);
|
serveMessage(request, 200, F("All Settings erased."), F("Connect to WLED-AP to setup again"),255);
|
||||||
doReboot = true;
|
doReboot = true; // may reboot immediately on dual-core system (race condition) which is desireable in this case
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request->hasArg(F("PIN"))) {
|
if (request->hasArg(F("PIN"))) {
|
||||||
@ -539,27 +539,24 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
// global I2C & SPI pins
|
// global I2C & SPI pins
|
||||||
int8_t hw_sda_pin = !request->arg(F("SDA")).length() ? -1 : (int)request->arg(F("SDA")).toInt();
|
int8_t hw_sda_pin = !request->arg(F("SDA")).length() ? -1 : (int)request->arg(F("SDA")).toInt();
|
||||||
int8_t hw_scl_pin = !request->arg(F("SCL")).length() ? -1 : (int)request->arg(F("SCL")).toInt();
|
int8_t hw_scl_pin = !request->arg(F("SCL")).length() ? -1 : (int)request->arg(F("SCL")).toInt();
|
||||||
#ifdef ESP8266
|
if (i2c_sda != hw_sda_pin || i2c_scl != hw_scl_pin) {
|
||||||
// cannot change pins on ESP8266
|
// only if pins changed
|
||||||
if (hw_sda_pin >= 0 && hw_sda_pin != HW_PIN_SDA) hw_sda_pin = HW_PIN_SDA;
|
uint8_t old_i2c[2] = { static_cast<uint8_t>(i2c_scl), static_cast<uint8_t>(i2c_sda) };
|
||||||
if (hw_scl_pin >= 0 && hw_scl_pin != HW_PIN_SCL) hw_scl_pin = HW_PIN_SCL;
|
pinManager.deallocateMultiplePins(old_i2c, 2, PinOwner::HW_I2C); // just in case deallocation of old pins
|
||||||
#endif
|
|
||||||
PinManagerPinType i2c[2] = { { hw_sda_pin, true }, { hw_scl_pin, true } };
|
PinManagerPinType i2c[2] = { { hw_sda_pin, true }, { hw_scl_pin, true } };
|
||||||
if (hw_sda_pin >= 0 && hw_scl_pin >= 0 && pinManager.allocateMultiplePins(i2c, 2, PinOwner::HW_I2C)) {
|
if (hw_sda_pin >= 0 && hw_scl_pin >= 0 && pinManager.allocateMultiplePins(i2c, 2, PinOwner::HW_I2C)) {
|
||||||
i2c_sda = hw_sda_pin;
|
i2c_sda = hw_sda_pin;
|
||||||
i2c_scl = hw_scl_pin;
|
i2c_scl = hw_scl_pin;
|
||||||
#ifdef ESP32
|
// no bus re-initialisation as usermods do not get any notification
|
||||||
Wire.setPins(i2c_sda, i2c_scl); // this will fail if Wire is initilised (Wire.begin() called)
|
//Wire.begin(i2c_sda, i2c_scl);
|
||||||
#endif
|
|
||||||
Wire.begin();
|
|
||||||
} else {
|
} else {
|
||||||
// there is no Wire.end()
|
// there is no Wire.end()
|
||||||
DEBUG_PRINTLN(F("Could not allocate I2C pins."));
|
DEBUG_PRINTLN(F("Could not allocate I2C pins."));
|
||||||
uint8_t i2c[2] = { static_cast<uint8_t>(i2c_scl), static_cast<uint8_t>(i2c_sda) };
|
|
||||||
pinManager.deallocateMultiplePins(i2c, 2, PinOwner::HW_I2C); // just in case deallocation of old pins
|
|
||||||
i2c_sda = -1;
|
i2c_sda = -1;
|
||||||
i2c_scl = -1;
|
i2c_scl = -1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
int8_t hw_mosi_pin = !request->arg(F("MOSI")).length() ? -1 : (int)request->arg(F("MOSI")).toInt();
|
int8_t hw_mosi_pin = !request->arg(F("MOSI")).length() ? -1 : (int)request->arg(F("MOSI")).toInt();
|
||||||
int8_t hw_miso_pin = !request->arg(F("MISO")).length() ? -1 : (int)request->arg(F("MISO")).toInt();
|
int8_t hw_miso_pin = !request->arg(F("MISO")).length() ? -1 : (int)request->arg(F("MISO")).toInt();
|
||||||
int8_t hw_sclk_pin = !request->arg(F("SCLK")).length() ? -1 : (int)request->arg(F("SCLK")).toInt();
|
int8_t hw_sclk_pin = !request->arg(F("SCLK")).length() ? -1 : (int)request->arg(F("SCLK")).toInt();
|
||||||
@ -569,6 +566,10 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
if (hw_miso_pin >= 0 && hw_miso_pin != HW_PIN_MISOSPI) hw_mosi_pin = HW_PIN_MISOSPI;
|
if (hw_miso_pin >= 0 && hw_miso_pin != HW_PIN_MISOSPI) hw_mosi_pin = HW_PIN_MISOSPI;
|
||||||
if (hw_sclk_pin >= 0 && hw_sclk_pin != HW_PIN_CLOCKSPI) hw_sclk_pin = HW_PIN_CLOCKSPI;
|
if (hw_sclk_pin >= 0 && hw_sclk_pin != HW_PIN_CLOCKSPI) hw_sclk_pin = HW_PIN_CLOCKSPI;
|
||||||
#endif
|
#endif
|
||||||
|
if (spi_mosi != hw_mosi_pin || spi_miso != hw_miso_pin || spi_sclk != hw_sclk_pin) {
|
||||||
|
// only if pins changed
|
||||||
|
uint8_t old_spi[3] = { static_cast<uint8_t>(spi_mosi), static_cast<uint8_t>(spi_miso), static_cast<uint8_t>(spi_sclk) };
|
||||||
|
pinManager.deallocateMultiplePins(old_spi, 3, PinOwner::HW_SPI); // just in case deallocation of old pins
|
||||||
PinManagerPinType spi[3] = { { hw_mosi_pin, true }, { hw_miso_pin, true }, { hw_sclk_pin, true } };
|
PinManagerPinType spi[3] = { { hw_mosi_pin, true }, { hw_miso_pin, true }, { hw_sclk_pin, true } };
|
||||||
if (hw_mosi_pin >= 0 && hw_sclk_pin >= 0 && pinManager.allocateMultiplePins(spi, 3, PinOwner::HW_SPI)) {
|
if (hw_mosi_pin >= 0 && hw_sclk_pin >= 0 && pinManager.allocateMultiplePins(spi, 3, PinOwner::HW_SPI)) {
|
||||||
spi_mosi = hw_mosi_pin;
|
spi_mosi = hw_mosi_pin;
|
||||||
@ -584,12 +585,11 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
} else {
|
} else {
|
||||||
//SPI.end();
|
//SPI.end();
|
||||||
DEBUG_PRINTLN(F("Could not allocate SPI pins."));
|
DEBUG_PRINTLN(F("Could not allocate SPI pins."));
|
||||||
uint8_t spi[3] = { static_cast<uint8_t>(spi_mosi), static_cast<uint8_t>(spi_miso), static_cast<uint8_t>(spi_sclk) };
|
|
||||||
pinManager.deallocateMultiplePins(spi, 3, PinOwner::HW_SPI); // just in case deallocation of old pins
|
|
||||||
spi_mosi = -1;
|
spi_mosi = -1;
|
||||||
spi_miso = -1;
|
spi_miso = -1;
|
||||||
spi_sclk = -1;
|
spi_sclk = -1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
JsonObject um = doc.createNestedObject("um");
|
JsonObject um = doc.createNestedObject("um");
|
||||||
|
|
||||||
@ -708,7 +708,9 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
lastEditTime = millis();
|
lastEditTime = millis();
|
||||||
if (subPage != 2 && !doReboot) doSerializeConfig = true; //serializeConfig(); //do not save if factory reset or LED settings (which are saved after LED re-init)
|
// do not save if factory reset or LED settings (which are saved after LED re-init)
|
||||||
|
doSerializeConfig = subPage != 2 && !(subPage == 6 && doReboot);
|
||||||
|
if (subPage == 8) doReboot = request->hasArg(F("RBT")); // prevent race condition on dual core system (set reboot here, after doSerializeConfig has been set)
|
||||||
#ifndef WLED_DISABLE_ALEXA
|
#ifndef WLED_DISABLE_ALEXA
|
||||||
if (subPage == 4) alexaInit();
|
if (subPage == 4) alexaInit();
|
||||||
#endif
|
#endif
|
||||||
|
@ -73,13 +73,6 @@ void WLED::loop()
|
|||||||
handleAlexa();
|
handleAlexa();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
yield();
|
|
||||||
|
|
||||||
if (doSerializeConfig) serializeConfig();
|
|
||||||
|
|
||||||
if (doReboot && !doInitBusses) // if busses have to be inited & saved, wait until next iteration
|
|
||||||
reset();
|
|
||||||
|
|
||||||
if (doCloseFile) {
|
if (doCloseFile) {
|
||||||
closeFile();
|
closeFile();
|
||||||
yield();
|
yield();
|
||||||
@ -169,13 +162,14 @@ void WLED::loop()
|
|||||||
strip.finalizeInit(); // also loads default ledmap if present
|
strip.finalizeInit(); // also loads default ledmap if present
|
||||||
if (aligned) strip.makeAutoSegments();
|
if (aligned) strip.makeAutoSegments();
|
||||||
else strip.fixInvalidSegments();
|
else strip.fixInvalidSegments();
|
||||||
yield();
|
doSerializeConfig = true;
|
||||||
serializeConfig();
|
|
||||||
}
|
}
|
||||||
if (loadLedmap >= 0) {
|
if (loadLedmap >= 0) {
|
||||||
if (!strip.deserializeMap(loadLedmap) && strip.isMatrix && loadLedmap == 0) strip.setUpMatrix();
|
if (!strip.deserializeMap(loadLedmap) && strip.isMatrix && loadLedmap == 0) strip.setUpMatrix();
|
||||||
loadLedmap = -1;
|
loadLedmap = -1;
|
||||||
}
|
}
|
||||||
|
yield();
|
||||||
|
if (doSerializeConfig) serializeConfig();
|
||||||
|
|
||||||
yield();
|
yield();
|
||||||
handleWs();
|
handleWs();
|
||||||
@ -229,6 +223,9 @@ void WLED::loop()
|
|||||||
ESP.wdtFeed();
|
ESP.wdtFeed();
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (doReboot && (!doInitBusses || !doSerializeConfig)) // if busses have to be inited & saved, wait until next iteration
|
||||||
|
reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WLED::enableWatchdog() {
|
void WLED::enableWatchdog() {
|
||||||
|
@ -3,12 +3,12 @@
|
|||||||
/*
|
/*
|
||||||
Main sketch, global variable declarations
|
Main sketch, global variable declarations
|
||||||
@title WLED project sketch
|
@title WLED project sketch
|
||||||
@version 0.14.0-b2
|
@version 0.14.0-b3
|
||||||
@author Christian Schwinne
|
@author Christian Schwinne
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// version code in format yymmddb (b = daily build)
|
// version code in format yymmddb (b = daily build)
|
||||||
#define VERSION 2306020
|
#define VERSION 2306130
|
||||||
|
|
||||||
//uncomment this if you have a "my_config.h" file you'd like to use
|
//uncomment this if you have a "my_config.h" file you'd like to use
|
||||||
//#define WLED_USE_MY_CONFIG
|
//#define WLED_USE_MY_CONFIG
|
||||||
|
@ -195,7 +195,7 @@ void initServer()
|
|||||||
JsonObject root = doc.as<JsonObject>();
|
JsonObject root = doc.as<JsonObject>();
|
||||||
if (error || root.isNull()) {
|
if (error || root.isNull()) {
|
||||||
releaseJSONBufferLock();
|
releaseJSONBufferLock();
|
||||||
request->send(400, "application/json", F("{\"error\":9}"));
|
request->send(400, "application/json", F("{\"error\":9}")); // ERR_JSON
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const String& url = request->url();
|
const String& url = request->url();
|
||||||
@ -210,6 +210,11 @@ void initServer()
|
|||||||
*/
|
*/
|
||||||
verboseResponse = deserializeState(root);
|
verboseResponse = deserializeState(root);
|
||||||
} else {
|
} else {
|
||||||
|
if (!correctPIN && strlen(settingsPIN)>0) {
|
||||||
|
request->send(403, "application/json", F("{\"error\":1}")); // ERR_DENIED
|
||||||
|
releaseJSONBufferLock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
verboseResponse = deserializeConfig(root); //use verboseResponse to determine whether cfg change should be saved immediately
|
verboseResponse = deserializeConfig(root); //use verboseResponse to determine whether cfg change should be saved immediately
|
||||||
}
|
}
|
||||||
releaseJSONBufferLock();
|
releaseJSONBufferLock();
|
||||||
@ -611,7 +616,7 @@ void serveSettings(AsyncWebServerRequest* request, bool post)
|
|||||||
} else {
|
} else {
|
||||||
if (!s2[0]) strcpy_P(s2, s_redirecting);
|
if (!s2[0]) strcpy_P(s2, s_redirecting);
|
||||||
|
|
||||||
serveMessage(request, 200, s, s2, (subPage == 1 || (subPage == 6 && doReboot)) ? 129 : (correctPIN ? 1 : 3));
|
serveMessage(request, 200, s, s2, (subPage == 1 || ((subPage == 6 || subPage == 8) && doReboot)) ? 129 : (correctPIN ? 1 : 3));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,7 +78,7 @@ void wsEvent(AsyncWebSocket * server, AsyncWebSocketClient * client, AwsEventTyp
|
|||||||
if((info->index + len) == info->len){
|
if((info->index + len) == info->len){
|
||||||
if(info->final){
|
if(info->final){
|
||||||
if(info->message_opcode == WS_TEXT) {
|
if(info->message_opcode == WS_TEXT) {
|
||||||
client->text(F("{\"error\":9}")); //we do not handle split packets right now
|
client->text(F("{\"error\":9}")); // ERR_JSON we do not handle split packets right now
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -197,7 +197,7 @@ void appendGPIOinfo() {
|
|||||||
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
|
#elif defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||||
oappend(SET_F("d.rsvd=[11,12,13,14,15,16,17"));
|
oappend(SET_F("d.rsvd=[11,12,13,14,15,16,17"));
|
||||||
#elif defined(ESP32)
|
#elif defined(ESP32)
|
||||||
oappend(SET_F("d.rsvd=[6,7,8,9,10,11,24,28,29,30,31"));
|
oappend(SET_F("d.rsvd=[6,7,8,9,10,11,24,28,29,30,31,37,38"));
|
||||||
#else
|
#else
|
||||||
oappend(SET_F("d.rsvd=[6,7,8,9,10,11"));
|
oappend(SET_F("d.rsvd=[6,7,8,9,10,11"));
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user