Beta-3 changes
- remove I2C init from usermods - PCF8574 (&co) port expander support - refactor PIR & Rotary encoder & 4LD - reboot race condition - optimisations
This commit is contained in:
parent
680afe972e
commit
82e448de7c
@ -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,14 +184,9 @@ 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())
|
||||||
{
|
{
|
||||||
sensorType = 0;
|
sensorType = 0;
|
||||||
@ -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,173 +82,33 @@ 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();
|
||||||
updateLocalTime();
|
|
||||||
uint8_t hr = hour(localTime);
|
|
||||||
uint8_t mi = minute(localTime);
|
|
||||||
|
|
||||||
if (sunrise && sunset) {
|
|
||||||
if (hour(sunrise)<hr && hour(sunset)>hr) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
if (hour(sunrise)==hr && minute(sunrise)<mi) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (hour(sunset)==hr && minute(sunset)>mi) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* switch strip on/off
|
* switch strip on/off
|
||||||
*/
|
*/
|
||||||
void switchStrip(bool switchOn)
|
void switchStrip(bool switchOn);
|
||||||
{
|
void publishMqtt(const char* state);
|
||||||
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
|
|
||||||
PIRtriggered = switchOn;
|
|
||||||
DEBUG_PRINT(F("PIR: strip=")); DEBUG_PRINTLN(switchOn?"on":"off");
|
|
||||||
if (switchOn) {
|
|
||||||
if (m_onPreset) {
|
|
||||||
if (currentPlaylist>0 && !offMode) {
|
|
||||||
prevPlaylist = currentPlaylist;
|
|
||||||
unloadPlaylist();
|
|
||||||
} else if (currentPreset>0 && !offMode) {
|
|
||||||
prevPreset = currentPreset;
|
|
||||||
} else {
|
|
||||||
saveTemporaryPreset();
|
|
||||||
prevPlaylist = 0;
|
|
||||||
prevPreset = 255;
|
|
||||||
}
|
|
||||||
applyPreset(m_onPreset, NotifyUpdateMode);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// preset not assigned
|
|
||||||
if (bri == 0) {
|
|
||||||
bri = briLast;
|
|
||||||
stateUpdated(NotifyUpdateMode);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (m_offPreset) {
|
|
||||||
applyPreset(m_offPreset, NotifyUpdateMode);
|
|
||||||
return;
|
|
||||||
} else if (prevPlaylist) {
|
|
||||||
if (currentPreset==m_onPreset || currentPlaylist==m_onPreset) applyPreset(prevPlaylist, NotifyUpdateMode);
|
|
||||||
prevPlaylist = 0;
|
|
||||||
return;
|
|
||||||
} else if (prevPreset) {
|
|
||||||
if (prevPreset<255) { if (currentPreset==m_onPreset || currentPlaylist==m_onPreset) applyPreset(prevPreset, NotifyUpdateMode); }
|
|
||||||
else { if (currentPreset==m_onPreset || currentPlaylist==m_onPreset) applyTemporaryPreset(); }
|
|
||||||
prevPreset = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// preset not assigned
|
|
||||||
if (bri != 0) {
|
|
||||||
briLast = bri;
|
|
||||||
bri = 0;
|
|
||||||
stateUpdated(NotifyUpdateMode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void publishMqtt(const char* state)
|
|
||||||
{
|
|
||||||
#ifndef WLED_DISABLE_MQTT
|
|
||||||
//Check if MQTT Connected, otherwise it will crash the 8266
|
|
||||||
if (WLED_MQTT_CONNECTED) {
|
|
||||||
char subuf[64];
|
|
||||||
strcpy(subuf, mqttDeviceTopic);
|
|
||||||
strcat_P(subuf, PSTR("/motion"));
|
|
||||||
mqtt->publish(subuf, 0, false, state);
|
|
||||||
}
|
|
||||||
#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.
|
// 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()
|
void publishHomeAssistantAutodiscovery();
|
||||||
{
|
|
||||||
#ifndef WLED_DISABLE_MQTT
|
|
||||||
if (WLED_MQTT_CONNECTED) {
|
|
||||||
StaticJsonDocument<600> doc;
|
|
||||||
char uid[24], json_str[1024], buf[128];
|
|
||||||
|
|
||||||
sprintf_P(buf, PSTR("%s Motion"), serverDescription); //max length: 33 + 7 = 40
|
|
||||||
doc[F("name")] = buf;
|
|
||||||
sprintf_P(buf, PSTR("%s/motion"), mqttDeviceTopic); //max length: 33 + 7 = 40
|
|
||||||
doc[F("stat_t")] = buf;
|
|
||||||
doc[F("pl_on")] = "on";
|
|
||||||
doc[F("pl_off")] = "off";
|
|
||||||
sprintf_P(uid, PSTR("%s_motion"), escapedMac.c_str());
|
|
||||||
doc[F("uniq_id")] = uid;
|
|
||||||
doc[F("dev_cla")] = F("motion");
|
|
||||||
doc[F("exp_aft")] = 1800;
|
|
||||||
|
|
||||||
JsonObject device = doc.createNestedObject(F("device")); // attach the sensor to the same device
|
|
||||||
device[F("name")] = serverDescription;
|
|
||||||
device[F("ids")] = String(F("wled-sensor-")) + mqttClientID;
|
|
||||||
device[F("mf")] = "WLED";
|
|
||||||
device[F("mdl")] = F("FOSS");
|
|
||||||
device[F("sw")] = versionString;
|
|
||||||
|
|
||||||
sprintf_P(buf, PSTR("homeassistant/binary_sensor/%s/config"), uid);
|
|
||||||
DEBUG_PRINTLN(buf);
|
|
||||||
size_t payload_size = serializeJson(doc, json_str);
|
|
||||||
DEBUG_PRINTLN(json_str);
|
|
||||||
|
|
||||||
mqtt->publish(buf, 0, true, json_str, payload_size); // do we really need to retain?
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read and update PIR sensor state.
|
* Read and update PIR sensor state.
|
||||||
* Initilize/reset switch off timer
|
* Initilize/reset switch off timer
|
||||||
*/
|
*/
|
||||||
bool updatePIRsensorState()
|
bool updatePIRsensorState();
|
||||||
{
|
|
||||||
bool pinState = digitalRead(PIRsensorPin);
|
|
||||||
if (pinState != sensorPinState) {
|
|
||||||
sensorPinState = pinState; // change previous state
|
|
||||||
|
|
||||||
if (sensorPinState == HIGH) {
|
|
||||||
offTimerStart = 0;
|
|
||||||
if (!m_mqttOnly && (!m_nightTimeOnly || (m_nightTimeOnly && !isDayTime()))) switchStrip(true);
|
|
||||||
else if (NotifyUpdateMode != CALL_MODE_NO_NOTIFY) updateInterfaces(CALL_MODE_WS_SEND);
|
|
||||||
publishMqtt("on");
|
|
||||||
} else {
|
|
||||||
// start switch off timer
|
|
||||||
offTimerStart = millis();
|
|
||||||
if (NotifyUpdateMode != CALL_MODE_NO_NOTIFY) updateInterfaces(CALL_MODE_WS_SEND);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* switch off the strip if the delay has elapsed
|
* switch off the strip if the delay has elapsed
|
||||||
*/
|
*/
|
||||||
bool handleOffTimer()
|
bool handleOffTimer();
|
||||||
{
|
|
||||||
if (offTimerStart > 0 && millis() - offTimerStart > m_switchOffDelay) {
|
|
||||||
offTimerStart = 0;
|
|
||||||
if (enabled == true) {
|
|
||||||
if (!m_mqttOnly && (!m_nightTimeOnly || (m_nightTimeOnly && !isDayTime()) || PIRtriggered)) switchStrip(false);
|
|
||||||
else if (NotifyUpdateMode != CALL_MODE_NO_NOTIFY) updateInterfaces(CALL_MODE_WS_SEND);
|
|
||||||
publishMqtt("off");
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
//Functions called by WLED
|
//Functions called by WLED
|
||||||
@ -256,186 +117,57 @@ public:
|
|||||||
* 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 setup();
|
||||||
{
|
|
||||||
if (enabled) {
|
|
||||||
// pin retrieved from cfg.json (readFromConfig()) prior to running setup()
|
|
||||||
if (PIRsensorPin >= 0 && pinManager.allocatePin(PIRsensorPin, false, PinOwner::UM_PIR)) {
|
|
||||||
// PIR Sensor mode INPUT_PULLUP
|
|
||||||
pinMode(PIRsensorPin, INPUT_PULLUP);
|
|
||||||
sensorPinState = digitalRead(PIRsensorPin);
|
|
||||||
} else {
|
|
||||||
if (PIRsensorPin >= 0) {
|
|
||||||
DEBUG_PRINTLN(F("PIRSensorSwitch pin allocation failed."));
|
|
||||||
}
|
|
||||||
PIRsensorPin = -1; // allocation failed
|
|
||||||
enabled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
initDone = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* connected() is called every time the WiFi is (re)connected
|
* connected() is called every time the WiFi is (re)connected
|
||||||
* Use it to initialize network interfaces
|
* Use it to initialize network interfaces
|
||||||
*/
|
*/
|
||||||
void connected()
|
//void connected();
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* onMqttConnect() is called when MQTT connection is established
|
* onMqttConnect() is called when MQTT connection is established
|
||||||
*/
|
*/
|
||||||
void onMqttConnect(bool sessionPresent) {
|
void onMqttConnect(bool sessionPresent);
|
||||||
if (HomeAssistantDiscovery) {
|
|
||||||
publishHomeAssistantAutodiscovery();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
*/
|
*/
|
||||||
void loop()
|
void loop();
|
||||||
{
|
|
||||||
// only check sensors 4x/s
|
|
||||||
if (!enabled || millis() - lastLoop < 250 || strip.isUpdating()) return;
|
|
||||||
lastLoop = millis();
|
|
||||||
|
|
||||||
if (!updatePIRsensorState()) {
|
|
||||||
handleOffTimer();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
|
* 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
|
* Add PIR sensor state and switch off timer duration to jsoninfo
|
||||||
*/
|
*/
|
||||||
void addToJsonInfo(JsonObject &root)
|
void addToJsonInfo(JsonObject &root);
|
||||||
{
|
|
||||||
JsonObject user = root["u"];
|
|
||||||
if (user.isNull()) user = root.createNestedObject("u");
|
|
||||||
|
|
||||||
JsonArray infoArr = user.createNestedArray(FPSTR(_name));
|
|
||||||
|
|
||||||
String uiDomString;
|
|
||||||
if (enabled) {
|
|
||||||
if (offTimerStart > 0)
|
|
||||||
{
|
|
||||||
uiDomString = "";
|
|
||||||
unsigned int offSeconds = (m_switchOffDelay - (millis() - offTimerStart)) / 1000;
|
|
||||||
if (offSeconds >= 3600)
|
|
||||||
{
|
|
||||||
uiDomString += (offSeconds / 3600);
|
|
||||||
uiDomString += F("h ");
|
|
||||||
offSeconds %= 3600;
|
|
||||||
}
|
|
||||||
if (offSeconds >= 60)
|
|
||||||
{
|
|
||||||
uiDomString += (offSeconds / 60);
|
|
||||||
offSeconds %= 60;
|
|
||||||
}
|
|
||||||
else if (uiDomString.length() > 0)
|
|
||||||
{
|
|
||||||
uiDomString += 0;
|
|
||||||
}
|
|
||||||
if (uiDomString.length() > 0)
|
|
||||||
{
|
|
||||||
uiDomString += F("min ");
|
|
||||||
}
|
|
||||||
uiDomString += (offSeconds);
|
|
||||||
infoArr.add(uiDomString + F("s"));
|
|
||||||
} else {
|
|
||||||
infoArr.add(sensorPinState ? F("sensor on") : F("inactive"));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
infoArr.add(F("disabled"));
|
|
||||||
}
|
|
||||||
|
|
||||||
uiDomString = F(" <button class=\"btn btn-xs\" onclick=\"requestJson({");
|
|
||||||
uiDomString += FPSTR(_name);
|
|
||||||
uiDomString += F(":{");
|
|
||||||
uiDomString += FPSTR(_enabled);
|
|
||||||
if (enabled) {
|
|
||||||
uiDomString += F(":false}});\">");
|
|
||||||
uiDomString += F("<i class=\"icons on\"></i>");
|
|
||||||
} else {
|
|
||||||
uiDomString += F(":true}});\">");
|
|
||||||
uiDomString += F("<i class=\"icons off\"></i>");
|
|
||||||
}
|
|
||||||
uiDomString += F("</button>");
|
|
||||||
infoArr.add(uiDomString);
|
|
||||||
|
|
||||||
JsonObject sensor = root[F("sensor")];
|
|
||||||
if (sensor.isNull()) sensor = root.createNestedObject(F("sensor"));
|
|
||||||
sensor[F("motion")] = sensorPinState || offTimerStart>0 ? true : false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* onStateChanged() is used to detect WLED state change
|
* onStateChanged() is used to detect WLED state change
|
||||||
*/
|
*/
|
||||||
void onStateChange(uint8_t mode) {
|
void onStateChange(uint8_t mode);
|
||||||
if (!initDone) return;
|
|
||||||
DEBUG_PRINT(F("PIR: offTimerStart=")); DEBUG_PRINTLN(offTimerStart);
|
|
||||||
if (PIRtriggered && offTimerStart) {
|
|
||||||
// checking PIRtriggered and offTimerStart will prevent cancellation upon On trigger
|
|
||||||
DEBUG_PRINTLN(F("PIR: Canceled."));
|
|
||||||
offTimerStart = 0;
|
|
||||||
PIRtriggered = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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 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 readFromJsonState(JsonObject &root)
|
|
||||||
{
|
|
||||||
if (!initDone) return; // prevent crash on boot applyPreset()
|
|
||||||
JsonObject usermod = root[FPSTR(_name)];
|
|
||||||
if (!usermod.isNull()) {
|
|
||||||
if (usermod[FPSTR(_enabled)].is<bool>()) {
|
|
||||||
enabled = usermod[FPSTR(_enabled)].as<bool>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* provide the changeable values
|
* provide the changeable values
|
||||||
*/
|
*/
|
||||||
void addToConfig(JsonObject &root)
|
void addToConfig(JsonObject &root);
|
||||||
{
|
|
||||||
JsonObject top = root.createNestedObject(FPSTR(_name));
|
|
||||||
top[FPSTR(_enabled)] = enabled;
|
|
||||||
top[FPSTR(_switchOffDelay)] = m_switchOffDelay / 1000;
|
|
||||||
top["pin"] = PIRsensorPin;
|
|
||||||
top[FPSTR(_onPreset)] = m_onPreset;
|
|
||||||
top[FPSTR(_offPreset)] = m_offPreset;
|
|
||||||
top[FPSTR(_nightTime)] = m_nightTimeOnly;
|
|
||||||
top[FPSTR(_mqttOnly)] = m_mqttOnly;
|
|
||||||
top[FPSTR(_offOnly)] = m_offOnly;
|
|
||||||
top[FPSTR(_haDiscovery)] = HomeAssistantDiscovery;
|
|
||||||
top[FPSTR(_notify)] = (NotifyUpdateMode != CALL_MODE_NO_NOTIFY);
|
|
||||||
DEBUG_PRINTLN(F("PIR config saved."));
|
|
||||||
}
|
|
||||||
|
|
||||||
void appendConfigData()
|
/**
|
||||||
{
|
* provide UI information and allow extending UI options
|
||||||
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
|
void appendConfigData();
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* restore the changeable values
|
* restore the changeable values
|
||||||
@ -443,72 +175,13 @@ public:
|
|||||||
*
|
*
|
||||||
* 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 readFromConfig(JsonObject &root);
|
||||||
{
|
|
||||||
bool oldEnabled = enabled;
|
|
||||||
int8_t oldPin = PIRsensorPin;
|
|
||||||
|
|
||||||
DEBUG_PRINT(FPSTR(_name));
|
|
||||||
JsonObject top = root[FPSTR(_name)];
|
|
||||||
if (top.isNull()) {
|
|
||||||
DEBUG_PRINTLN(F(": No config found. (Using defaults.)"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
PIRsensorPin = top["pin"] | PIRsensorPin;
|
|
||||||
|
|
||||||
enabled = top[FPSTR(_enabled)] | enabled;
|
|
||||||
|
|
||||||
m_switchOffDelay = (top[FPSTR(_switchOffDelay)] | m_switchOffDelay/1000) * 1000;
|
|
||||||
|
|
||||||
m_onPreset = top[FPSTR(_onPreset)] | m_onPreset;
|
|
||||||
m_onPreset = max(0,min(250,(int)m_onPreset));
|
|
||||||
m_offPreset = top[FPSTR(_offPreset)] | m_offPreset;
|
|
||||||
m_offPreset = max(0,min(250,(int)m_offPreset));
|
|
||||||
|
|
||||||
m_nightTimeOnly = top[FPSTR(_nightTime)] | m_nightTimeOnly;
|
|
||||||
m_mqttOnly = top[FPSTR(_mqttOnly)] | m_mqttOnly;
|
|
||||||
m_offOnly = top[FPSTR(_offOnly)] | m_offOnly;
|
|
||||||
HomeAssistantDiscovery = top[FPSTR(_haDiscovery)] | HomeAssistantDiscovery;
|
|
||||||
|
|
||||||
NotifyUpdateMode = top[FPSTR(_notify)] ? CALL_MODE_DIRECT_CHANGE : CALL_MODE_NO_NOTIFY;
|
|
||||||
|
|
||||||
if (!initDone) {
|
|
||||||
// reading config prior to setup()
|
|
||||||
DEBUG_PRINTLN(F(" config loaded."));
|
|
||||||
} else {
|
|
||||||
if (oldPin != PIRsensorPin || oldEnabled != enabled) {
|
|
||||||
// check if pin is OK
|
|
||||||
if (oldPin != PIRsensorPin && oldPin >= 0) {
|
|
||||||
// if we are changing pin in settings page
|
|
||||||
// deallocate old pin
|
|
||||||
pinManager.deallocatePin(oldPin, PinOwner::UM_PIR);
|
|
||||||
if (pinManager.allocatePin(PIRsensorPin, false, PinOwner::UM_PIR)) {
|
|
||||||
pinMode(PIRsensorPin, INPUT_PULLUP);
|
|
||||||
} else {
|
|
||||||
// allocation failed
|
|
||||||
PIRsensorPin = -1;
|
|
||||||
enabled = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (enabled) {
|
|
||||||
sensorPinState = digitalRead(PIRsensorPin);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
DEBUG_PRINTLN(F(" config (re)loaded."));
|
|
||||||
}
|
|
||||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
|
||||||
return !top[FPSTR(_haDiscovery)].isNull();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
|
* 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.
|
* This could be used in the future for the system to determine whether your usermod is installed.
|
||||||
*/
|
*/
|
||||||
uint16_t getId()
|
uint16_t getId() { return USERMOD_ID_PIRSWITCH; }
|
||||||
{
|
|
||||||
return USERMOD_ID_PIRSWITCH;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// strings to reduce flash memory usage (used more than twice)
|
// strings to reduce flash memory usage (used more than twice)
|
||||||
@ -522,3 +195,360 @@ const char PIRsensorSwitch::_mqttOnly[] PROGMEM = "mqtt-only";
|
|||||||
const char PIRsensorSwitch::_offOnly[] PROGMEM = "off-only";
|
const char PIRsensorSwitch::_offOnly[] PROGMEM = "off-only";
|
||||||
const char PIRsensorSwitch::_haDiscovery[] PROGMEM = "HA-discovery";
|
const char PIRsensorSwitch::_haDiscovery[] PROGMEM = "HA-discovery";
|
||||||
const char PIRsensorSwitch::_notify[] PROGMEM = "notifications";
|
const char PIRsensorSwitch::_notify[] PROGMEM = "notifications";
|
||||||
|
const char PIRsensorSwitch::_override[] PROGMEM = "override";
|
||||||
|
|
||||||
|
bool PIRsensorSwitch::isDayTime() {
|
||||||
|
updateLocalTime();
|
||||||
|
uint8_t hr = hour(localTime);
|
||||||
|
uint8_t mi = minute(localTime);
|
||||||
|
|
||||||
|
if (sunrise && sunset) {
|
||||||
|
if (hour(sunrise)<hr && hour(sunset)>hr) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
if (hour(sunrise)==hr && minute(sunrise)<mi) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (hour(sunset)==hr && minute(sunset)>mi) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PIRsensorSwitch::switchStrip(bool switchOn)
|
||||||
|
{
|
||||||
|
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
|
||||||
|
PIRtriggered = switchOn;
|
||||||
|
DEBUG_PRINT(F("PIR: strip=")); DEBUG_PRINTLN(switchOn?"on":"off");
|
||||||
|
if (switchOn) {
|
||||||
|
if (m_onPreset) {
|
||||||
|
if (currentPlaylist>0 && !offMode) {
|
||||||
|
prevPlaylist = currentPlaylist;
|
||||||
|
unloadPlaylist();
|
||||||
|
} else if (currentPreset>0 && !offMode) {
|
||||||
|
prevPreset = currentPreset;
|
||||||
|
} else {
|
||||||
|
saveTemporaryPreset();
|
||||||
|
prevPlaylist = 0;
|
||||||
|
prevPreset = 255;
|
||||||
|
}
|
||||||
|
applyPreset(m_onPreset, NotifyUpdateMode);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// preset not assigned
|
||||||
|
if (bri == 0) {
|
||||||
|
bri = briLast;
|
||||||
|
stateUpdated(NotifyUpdateMode);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (m_offPreset) {
|
||||||
|
applyPreset(m_offPreset, NotifyUpdateMode);
|
||||||
|
return;
|
||||||
|
} else if (prevPlaylist) {
|
||||||
|
if (currentPreset==m_onPreset || currentPlaylist==m_onPreset) applyPreset(prevPlaylist, NotifyUpdateMode);
|
||||||
|
prevPlaylist = 0;
|
||||||
|
return;
|
||||||
|
} else if (prevPreset) {
|
||||||
|
if (prevPreset<255) { if (currentPreset==m_onPreset || currentPlaylist==m_onPreset) applyPreset(prevPreset, NotifyUpdateMode); }
|
||||||
|
else { if (currentPreset==m_onPreset || currentPlaylist==m_onPreset) applyTemporaryPreset(); }
|
||||||
|
prevPreset = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// preset not assigned
|
||||||
|
if (bri != 0) {
|
||||||
|
briLast = bri;
|
||||||
|
bri = 0;
|
||||||
|
stateUpdated(NotifyUpdateMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PIRsensorSwitch::publishMqtt(const char* state)
|
||||||
|
{
|
||||||
|
#ifndef WLED_DISABLE_MQTT
|
||||||
|
//Check if MQTT Connected, otherwise it will crash the 8266
|
||||||
|
if (WLED_MQTT_CONNECTED) {
|
||||||
|
char subuf[64];
|
||||||
|
strcpy(subuf, mqttDeviceTopic);
|
||||||
|
strcat_P(subuf, PSTR("/motion"));
|
||||||
|
mqtt->publish(subuf, 0, false, state);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void PIRsensorSwitch::publishHomeAssistantAutodiscovery()
|
||||||
|
{
|
||||||
|
#ifndef WLED_DISABLE_MQTT
|
||||||
|
if (WLED_MQTT_CONNECTED) {
|
||||||
|
StaticJsonDocument<600> doc;
|
||||||
|
char uid[24], json_str[1024], buf[128];
|
||||||
|
|
||||||
|
sprintf_P(buf, PSTR("%s Motion"), serverDescription); //max length: 33 + 7 = 40
|
||||||
|
doc[F("name")] = buf;
|
||||||
|
sprintf_P(buf, PSTR("%s/motion"), mqttDeviceTopic); //max length: 33 + 7 = 40
|
||||||
|
doc[F("stat_t")] = buf;
|
||||||
|
doc[F("pl_on")] = "on";
|
||||||
|
doc[F("pl_off")] = "off";
|
||||||
|
sprintf_P(uid, PSTR("%s_motion"), escapedMac.c_str());
|
||||||
|
doc[F("uniq_id")] = uid;
|
||||||
|
doc[F("dev_cla")] = F("motion");
|
||||||
|
doc[F("exp_aft")] = 1800;
|
||||||
|
|
||||||
|
JsonObject device = doc.createNestedObject(F("device")); // attach the sensor to the same device
|
||||||
|
device[F("name")] = serverDescription;
|
||||||
|
device[F("ids")] = String(F("wled-sensor-")) + mqttClientID;
|
||||||
|
device[F("mf")] = "WLED";
|
||||||
|
device[F("mdl")] = F("FOSS");
|
||||||
|
device[F("sw")] = versionString;
|
||||||
|
|
||||||
|
sprintf_P(buf, PSTR("homeassistant/binary_sensor/%s/config"), uid);
|
||||||
|
DEBUG_PRINTLN(buf);
|
||||||
|
size_t payload_size = serializeJson(doc, json_str);
|
||||||
|
DEBUG_PRINTLN(json_str);
|
||||||
|
|
||||||
|
mqtt->publish(buf, 0, true, json_str, payload_size); // do we really need to retain?
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PIRsensorSwitch::updatePIRsensorState()
|
||||||
|
{
|
||||||
|
bool pinState = digitalRead(PIRsensorPin);
|
||||||
|
if (pinState != sensorPinState) {
|
||||||
|
sensorPinState = pinState; // change previous state
|
||||||
|
|
||||||
|
if (sensorPinState == HIGH) {
|
||||||
|
offTimerStart = 0;
|
||||||
|
if (!m_mqttOnly && (!m_nightTimeOnly || (m_nightTimeOnly && !isDayTime()))) switchStrip(true);
|
||||||
|
else if (NotifyUpdateMode != CALL_MODE_NO_NOTIFY) updateInterfaces(CALL_MODE_WS_SEND);
|
||||||
|
publishMqtt("on");
|
||||||
|
} else {
|
||||||
|
// start switch off timer
|
||||||
|
offTimerStart = millis();
|
||||||
|
if (NotifyUpdateMode != CALL_MODE_NO_NOTIFY) updateInterfaces(CALL_MODE_WS_SEND);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PIRsensorSwitch::handleOffTimer()
|
||||||
|
{
|
||||||
|
if (offTimerStart > 0 && millis() - offTimerStart > m_switchOffDelay) {
|
||||||
|
offTimerStart = 0;
|
||||||
|
if (enabled == true) {
|
||||||
|
if (!m_mqttOnly && (!m_nightTimeOnly || (m_nightTimeOnly && !isDayTime()) || PIRtriggered)) switchStrip(false);
|
||||||
|
else if (NotifyUpdateMode != CALL_MODE_NO_NOTIFY) updateInterfaces(CALL_MODE_WS_SEND);
|
||||||
|
publishMqtt("off");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Functions called by WLED
|
||||||
|
|
||||||
|
void PIRsensorSwitch::setup()
|
||||||
|
{
|
||||||
|
if (enabled) {
|
||||||
|
// pin retrieved from cfg.json (readFromConfig()) prior to running setup()
|
||||||
|
if (PIRsensorPin >= 0 && pinManager.allocatePin(PIRsensorPin, false, PinOwner::UM_PIR)) {
|
||||||
|
// PIR Sensor mode INPUT_PULLUP
|
||||||
|
pinMode(PIRsensorPin, INPUT_PULLUP);
|
||||||
|
sensorPinState = digitalRead(PIRsensorPin);
|
||||||
|
} else {
|
||||||
|
if (PIRsensorPin >= 0) {
|
||||||
|
DEBUG_PRINTLN(F("PIRSensorSwitch pin allocation failed."));
|
||||||
|
}
|
||||||
|
PIRsensorPin = -1; // allocation failed
|
||||||
|
enabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
initDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PIRsensorSwitch::onMqttConnect(bool sessionPresent)
|
||||||
|
{
|
||||||
|
if (HomeAssistantDiscovery) {
|
||||||
|
publishHomeAssistantAutodiscovery();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PIRsensorSwitch::loop()
|
||||||
|
{
|
||||||
|
// only check sensors 4x/s
|
||||||
|
if (!enabled || millis() - lastLoop < 250 || strip.isUpdating()) return;
|
||||||
|
lastLoop = millis();
|
||||||
|
|
||||||
|
if (!updatePIRsensorState()) {
|
||||||
|
handleOffTimer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PIRsensorSwitch::addToJsonInfo(JsonObject &root)
|
||||||
|
{
|
||||||
|
JsonObject user = root["u"];
|
||||||
|
if (user.isNull()) user = root.createNestedObject("u");
|
||||||
|
|
||||||
|
JsonArray infoArr = user.createNestedArray(FPSTR(_name));
|
||||||
|
|
||||||
|
String uiDomString;
|
||||||
|
if (enabled) {
|
||||||
|
if (offTimerStart > 0)
|
||||||
|
{
|
||||||
|
uiDomString = "";
|
||||||
|
unsigned int offSeconds = (m_switchOffDelay - (millis() - offTimerStart)) / 1000;
|
||||||
|
if (offSeconds >= 3600)
|
||||||
|
{
|
||||||
|
uiDomString += (offSeconds / 3600);
|
||||||
|
uiDomString += F("h ");
|
||||||
|
offSeconds %= 3600;
|
||||||
|
}
|
||||||
|
if (offSeconds >= 60)
|
||||||
|
{
|
||||||
|
uiDomString += (offSeconds / 60);
|
||||||
|
offSeconds %= 60;
|
||||||
|
}
|
||||||
|
else if (uiDomString.length() > 0)
|
||||||
|
{
|
||||||
|
uiDomString += 0;
|
||||||
|
}
|
||||||
|
if (uiDomString.length() > 0)
|
||||||
|
{
|
||||||
|
uiDomString += F("min ");
|
||||||
|
}
|
||||||
|
uiDomString += (offSeconds);
|
||||||
|
infoArr.add(uiDomString + F("s"));
|
||||||
|
} else {
|
||||||
|
infoArr.add(sensorPinState ? F("sensor on") : F("inactive"));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
infoArr.add(F("disabled"));
|
||||||
|
}
|
||||||
|
|
||||||
|
uiDomString = F(" <button class=\"btn btn-xs\" onclick=\"requestJson({");
|
||||||
|
uiDomString += FPSTR(_name);
|
||||||
|
uiDomString += F(":{");
|
||||||
|
uiDomString += FPSTR(_enabled);
|
||||||
|
if (enabled) {
|
||||||
|
uiDomString += F(":false}});\">");
|
||||||
|
uiDomString += F("<i class=\"icons on\"></i>");
|
||||||
|
} else {
|
||||||
|
uiDomString += F(":true}});\">");
|
||||||
|
uiDomString += F("<i class=\"icons off\"></i>");
|
||||||
|
}
|
||||||
|
uiDomString += F("</button>");
|
||||||
|
infoArr.add(uiDomString);
|
||||||
|
|
||||||
|
JsonObject sensor = root[F("sensor")];
|
||||||
|
if (sensor.isNull()) sensor = root.createNestedObject(F("sensor"));
|
||||||
|
sensor[F("motion")] = sensorPinState || offTimerStart>0 ? true : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PIRsensorSwitch::onStateChange(uint8_t mode) {
|
||||||
|
if (!initDone) return;
|
||||||
|
DEBUG_PRINT(F("PIR: offTimerStart=")); DEBUG_PRINTLN(offTimerStart);
|
||||||
|
if (m_override && PIRtriggered && offTimerStart) { // debounce
|
||||||
|
// checking PIRtriggered and offTimerStart will prevent cancellation upon On trigger
|
||||||
|
DEBUG_PRINTLN(F("PIR: Canceled."));
|
||||||
|
offTimerStart = 0;
|
||||||
|
PIRtriggered = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PIRsensorSwitch::readFromJsonState(JsonObject &root)
|
||||||
|
{
|
||||||
|
if (!initDone) return; // prevent crash on boot applyPreset()
|
||||||
|
JsonObject usermod = root[FPSTR(_name)];
|
||||||
|
if (!usermod.isNull()) {
|
||||||
|
if (usermod[FPSTR(_enabled)].is<bool>()) {
|
||||||
|
enabled = usermod[FPSTR(_enabled)].as<bool>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PIRsensorSwitch::addToConfig(JsonObject &root)
|
||||||
|
{
|
||||||
|
JsonObject top = root.createNestedObject(FPSTR(_name));
|
||||||
|
top[FPSTR(_enabled)] = enabled;
|
||||||
|
top[FPSTR(_switchOffDelay)] = m_switchOffDelay / 1000;
|
||||||
|
top["pin"] = PIRsensorPin;
|
||||||
|
top[FPSTR(_onPreset)] = m_onPreset;
|
||||||
|
top[FPSTR(_offPreset)] = m_offPreset;
|
||||||
|
top[FPSTR(_nightTime)] = m_nightTimeOnly;
|
||||||
|
top[FPSTR(_mqttOnly)] = m_mqttOnly;
|
||||||
|
top[FPSTR(_offOnly)] = m_offOnly;
|
||||||
|
top[FPSTR(_override)] = m_override;
|
||||||
|
top[FPSTR(_haDiscovery)] = HomeAssistantDiscovery;
|
||||||
|
top[FPSTR(_notify)] = (NotifyUpdateMode != CALL_MODE_NO_NOTIFY);
|
||||||
|
DEBUG_PRINTLN(F("PIR config saved."));
|
||||||
|
}
|
||||||
|
|
||||||
|
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: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)
|
||||||
|
{
|
||||||
|
bool oldEnabled = enabled;
|
||||||
|
int8_t oldPin = PIRsensorPin;
|
||||||
|
|
||||||
|
DEBUG_PRINT(FPSTR(_name));
|
||||||
|
JsonObject top = root[FPSTR(_name)];
|
||||||
|
if (top.isNull()) {
|
||||||
|
DEBUG_PRINTLN(F(": No config found. (Using defaults.)"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PIRsensorPin = top["pin"] | PIRsensorPin;
|
||||||
|
|
||||||
|
enabled = top[FPSTR(_enabled)] | enabled;
|
||||||
|
|
||||||
|
m_switchOffDelay = (top[FPSTR(_switchOffDelay)] | m_switchOffDelay/1000) * 1000;
|
||||||
|
|
||||||
|
m_onPreset = top[FPSTR(_onPreset)] | m_onPreset;
|
||||||
|
m_onPreset = max(0,min(250,(int)m_onPreset));
|
||||||
|
m_offPreset = top[FPSTR(_offPreset)] | m_offPreset;
|
||||||
|
m_offPreset = max(0,min(250,(int)m_offPreset));
|
||||||
|
|
||||||
|
m_nightTimeOnly = top[FPSTR(_nightTime)] | m_nightTimeOnly;
|
||||||
|
m_mqttOnly = top[FPSTR(_mqttOnly)] | m_mqttOnly;
|
||||||
|
m_offOnly = top[FPSTR(_offOnly)] | m_offOnly;
|
||||||
|
m_override = top[FPSTR(_override)] | m_override;
|
||||||
|
HomeAssistantDiscovery = top[FPSTR(_haDiscovery)] | HomeAssistantDiscovery;
|
||||||
|
|
||||||
|
NotifyUpdateMode = top[FPSTR(_notify)] ? CALL_MODE_DIRECT_CHANGE : CALL_MODE_NO_NOTIFY;
|
||||||
|
|
||||||
|
if (!initDone) {
|
||||||
|
// reading config prior to setup()
|
||||||
|
DEBUG_PRINTLN(F(" config loaded."));
|
||||||
|
} else {
|
||||||
|
if (oldPin != PIRsensorPin || oldEnabled != enabled) {
|
||||||
|
// check if pin is OK
|
||||||
|
if (oldPin != PIRsensorPin && oldPin >= 0) {
|
||||||
|
// if we are changing pin in settings page
|
||||||
|
// deallocate old pin
|
||||||
|
pinManager.deallocatePin(oldPin, PinOwner::UM_PIR);
|
||||||
|
if (pinManager.allocatePin(PIRsensorPin, false, PinOwner::UM_PIR)) {
|
||||||
|
pinMode(PIRsensorPin, INPUT_PULLUP);
|
||||||
|
} else {
|
||||||
|
// allocation failed
|
||||||
|
PIRsensorPin = -1;
|
||||||
|
enabled = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (enabled) {
|
||||||
|
sensorPinState = digitalRead(PIRsensorPin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||||
|
}
|
||||||
|
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||||
|
return !top[FPSTR(_override)].isNull();
|
||||||
|
}
|
||||||
|
@ -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
|
#endif
|
||||||
#else
|
|
||||||
Wire.beginTransmission(ES7243_ADDR);
|
Wire.beginTransmission(ES7243_ADDR);
|
||||||
#endif
|
|
||||||
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
|
||||||
@ -50,23 +58,17 @@ class MultiRelay : public Usermod {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
// 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();
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -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;
|
||||||
|
@ -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;
|
||||||
|
@ -497,6 +497,7 @@ function loadFX(callback = null)
|
|||||||
populateEffects();
|
populateEffects();
|
||||||
})
|
})
|
||||||
.catch((e)=>{
|
.catch((e)=>{
|
||||||
|
//setTimeout(loadFX, 250); // retry
|
||||||
showToast(e, true);
|
showToast(e, true);
|
||||||
})
|
})
|
||||||
.finally(()=>{
|
.finally(()=>{
|
||||||
@ -524,6 +525,7 @@ function loadFXData(callback = null)
|
|||||||
})
|
})
|
||||||
.catch((e)=>{
|
.catch((e)=>{
|
||||||
fxdata = [];
|
fxdata = [];
|
||||||
|
//setTimeout(loadFXData, 250); // retry
|
||||||
showToast(e, true);
|
showToast(e, true);
|
||||||
})
|
})
|
||||||
.finally(()=>{
|
.finally(()=>{
|
||||||
@ -1253,6 +1255,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)
|
||||||
|
@ -322,7 +322,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>
|
||||||
|
@ -576,7 +576,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,7 +604,7 @@ 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>
|
||||||
|
@ -89,7 +89,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 +99,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 +110,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>
|
||||||
|
@ -172,7 +172,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 +180,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 +188,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 +207,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>
|
||||||
|
@ -249,7 +249,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>
|
||||||
|
@ -242,15 +242,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>
|
||||||
|
@ -61,6 +61,9 @@ button.sml {
|
|||||||
.hide {
|
.hide {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
.warn {
|
||||||
|
color: #fa0;
|
||||||
|
}
|
||||||
input {
|
input {
|
||||||
background: #333;
|
background: #333;
|
||||||
color: #fff;
|
color: #fff;
|
||||||
|
@ -99,7 +99,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 +129,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 +152,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 +205,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 +374,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);
|
||||||
|
File diff suppressed because it is too large
Load Diff
3933
wled00/html_ui.h
3933
wled00/html_ui.h
File diff suppressed because it is too large
Load Diff
@ -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,29 +997,16 @@ 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;
|
||||||
#ifdef WLED_ENABLE_JSONLIVE
|
#ifdef WLED_ENABLE_JSONLIVE
|
||||||
else if (url.indexOf("live") > 0) {
|
else if (url.indexOf("live") > 0) {
|
||||||
serveLiveLeds(request);
|
serveLiveLeds(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();
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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,26 +539,23 @@ 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
|
} else {
|
||||||
Wire.begin();
|
// there is no Wire.end()
|
||||||
} else {
|
DEBUG_PRINTLN(F("Could not allocate I2C pins."));
|
||||||
// there is no Wire.end()
|
i2c_sda = -1;
|
||||||
DEBUG_PRINTLN(F("Could not allocate I2C pins."));
|
i2c_scl = -1;
|
||||||
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_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();
|
||||||
@ -569,26 +566,29 @@ 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
|
||||||
PinManagerPinType spi[3] = { { hw_mosi_pin, true }, { hw_miso_pin, true }, { hw_sclk_pin, true } };
|
if (spi_mosi != hw_mosi_pin || spi_miso != hw_miso_pin || spi_sclk != hw_sclk_pin) {
|
||||||
if (hw_mosi_pin >= 0 && hw_sclk_pin >= 0 && pinManager.allocateMultiplePins(spi, 3, PinOwner::HW_SPI)) {
|
// only if pins changed
|
||||||
spi_mosi = hw_mosi_pin;
|
uint8_t old_spi[3] = { static_cast<uint8_t>(spi_mosi), static_cast<uint8_t>(spi_miso), static_cast<uint8_t>(spi_sclk) };
|
||||||
spi_miso = hw_miso_pin;
|
pinManager.deallocateMultiplePins(old_spi, 3, PinOwner::HW_SPI); // just in case deallocation of old pins
|
||||||
spi_sclk = hw_sclk_pin;
|
PinManagerPinType spi[3] = { { hw_mosi_pin, true }, { hw_miso_pin, true }, { hw_sclk_pin, true } };
|
||||||
// no bus re-initialisation as usermods do not get any notification
|
if (hw_mosi_pin >= 0 && hw_sclk_pin >= 0 && pinManager.allocateMultiplePins(spi, 3, PinOwner::HW_SPI)) {
|
||||||
//SPI.end();
|
spi_mosi = hw_mosi_pin;
|
||||||
#ifdef ESP32
|
spi_miso = hw_miso_pin;
|
||||||
//SPI.begin(spi_sclk, spi_miso, spi_mosi);
|
spi_sclk = hw_sclk_pin;
|
||||||
#else
|
// no bus re-initialisation as usermods do not get any notification
|
||||||
//SPI.begin();
|
//SPI.end();
|
||||||
#endif
|
#ifdef ESP32
|
||||||
} else {
|
//SPI.begin(spi_sclk, spi_miso, spi_mosi);
|
||||||
//SPI.end();
|
#else
|
||||||
DEBUG_PRINTLN(F("Could not allocate SPI pins."));
|
//SPI.begin();
|
||||||
uint8_t spi[3] = { static_cast<uint8_t>(spi_mosi), static_cast<uint8_t>(spi_miso), static_cast<uint8_t>(spi_sclk) };
|
#endif
|
||||||
pinManager.deallocateMultiplePins(spi, 3, PinOwner::HW_SPI); // just in case deallocation of old pins
|
} else {
|
||||||
spi_mosi = -1;
|
//SPI.end();
|
||||||
spi_miso = -1;
|
DEBUG_PRINTLN(F("Could not allocate SPI pins."));
|
||||||
spi_sclk = -1;
|
spi_mosi = -1;
|
||||||
|
spi_miso = -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() {
|
||||||
|
@ -611,7 +611,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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user