mirror of
https://github.com/wled/WLED.git
synced 2025-07-09 20:06:33 +00:00
Multi PIR usermod
This commit is contained in:
parent
00038453e1
commit
246746a82e
@ -15,6 +15,9 @@
|
|||||||
#define PIR_SENSOR_OFF_SEC 600
|
#define PIR_SENSOR_OFF_SEC 600
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef PIR_SENSOR_MAX_SENSORS
|
||||||
|
#define PIR_SENSOR_MAX_SENSORS 1
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This usermod handles PIR sensor states.
|
* This usermod handles PIR sensor states.
|
||||||
@ -50,13 +53,13 @@ private:
|
|||||||
|
|
||||||
volatile unsigned long offTimerStart = 0; // off timer start time
|
volatile unsigned long offTimerStart = 0; // off timer start time
|
||||||
volatile bool PIRtriggered = false; // did PIR trigger?
|
volatile bool PIRtriggered = false; // did PIR trigger?
|
||||||
bool sensorPinState = LOW; // current PIR sensor pin state
|
bool initDone = false; // status of initialization
|
||||||
bool initDone = false; // status of initialization
|
unsigned long lastLoop = 0;
|
||||||
unsigned long lastLoop = 0;
|
bool sensorPinState[PIR_SENSOR_MAX_SENSORS] = {LOW}; // current PIR sensor pin state
|
||||||
|
|
||||||
// configurable parameters
|
// configurable parameters
|
||||||
bool enabled = true; // PIR sensor enabled
|
bool enabled = true; // PIR sensor enabled
|
||||||
int8_t PIRsensorPin = PIR_SENSOR_PIN; // PIR sensor pin
|
int8_t PIRsensorPin[PIR_SENSOR_MAX_SENSORS] = {PIR_SENSOR_PIN}; // PIR sensor pin
|
||||||
uint32_t m_switchOffDelay = PIR_SENSOR_OFF_SEC*1000; // delay before switch off after the sensor state goes LOW (10min)
|
uint32_t m_switchOffDelay = PIR_SENSOR_OFF_SEC*1000; // delay before switch off after the sensor state goes LOW (10min)
|
||||||
uint8_t m_onPreset = 0; // on preset
|
uint8_t m_onPreset = 0; // on preset
|
||||||
uint8_t m_offPreset = 0; // off preset
|
uint8_t m_offPreset = 0; // off preset
|
||||||
@ -325,21 +328,29 @@ void PIRsensorSwitch::publishHomeAssistantAutodiscovery()
|
|||||||
|
|
||||||
bool PIRsensorSwitch::updatePIRsensorState()
|
bool PIRsensorSwitch::updatePIRsensorState()
|
||||||
{
|
{
|
||||||
bool pinState = digitalRead(PIRsensorPin);
|
bool stateChanged = false;
|
||||||
if (pinState != sensorPinState) {
|
bool allOff = true;
|
||||||
sensorPinState = pinState; // change previous state
|
for (int i = 0; i < PIR_SENSOR_MAX_SENSORS; i++) {
|
||||||
|
if (PIRsensorPin[i] < 0) continue;
|
||||||
|
|
||||||
if (sensorPinState == HIGH) {
|
bool pinState = digitalRead(PIRsensorPin[i]);
|
||||||
offTimerStart = 0;
|
if (pinState != sensorPinState[i]) {
|
||||||
if (!m_mqttOnly && (!m_nightTimeOnly || (m_nightTimeOnly && !isDayTime()))) switchStrip(true);
|
sensorPinState[i] = pinState; // change previous state
|
||||||
} else {
|
stateChanged = true;
|
||||||
// start switch off timer
|
|
||||||
offTimerStart = millis();
|
if (sensorPinState[i] == HIGH) {
|
||||||
|
offTimerStart = 0;
|
||||||
|
allOff = false;
|
||||||
|
if (!m_mqttOnly && (!m_nightTimeOnly || (m_nightTimeOnly && !isDayTime()))) switchStrip(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
publishMqtt(sensorPinState == HIGH);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
return false;
|
if (stateChanged) {
|
||||||
|
publishMqtt(!allOff);
|
||||||
|
// start switch off timer
|
||||||
|
if (allOff) offTimerStart = millis();
|
||||||
|
}
|
||||||
|
return stateChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PIRsensorSwitch::handleOffTimer()
|
bool PIRsensorSwitch::handleOffTimer()
|
||||||
@ -356,18 +367,21 @@ bool PIRsensorSwitch::handleOffTimer()
|
|||||||
|
|
||||||
void PIRsensorSwitch::setup()
|
void PIRsensorSwitch::setup()
|
||||||
{
|
{
|
||||||
if (enabled) {
|
for (int i = 0; i < PIR_SENSOR_MAX_SENSORS; i++) {
|
||||||
|
sensorPinState[i] = LOW;
|
||||||
|
if (PIRsensorPin[i] < 0) continue;
|
||||||
// pin retrieved from cfg.json (readFromConfig()) prior to running setup()
|
// pin retrieved from cfg.json (readFromConfig()) prior to running setup()
|
||||||
if (PIRsensorPin >= 0 && pinManager.allocatePin(PIRsensorPin, false, PinOwner::UM_PIR)) {
|
if (pinManager.allocatePin(PIRsensorPin[i], false, PinOwner::UM_PIR)) {
|
||||||
// PIR Sensor mode INPUT_PULLUP
|
// PIR Sensor mode INPUT_PULLDOWN
|
||||||
pinMode(PIRsensorPin, INPUT_PULLUP);
|
#ifdef ESP8266
|
||||||
sensorPinState = digitalRead(PIRsensorPin);
|
pinMode(PIRsensorPin[i], PIRsensorPin[i]==16 ? INPUT_PULLDOWN : INPUT_PULLUP); // ESP8266 has INPUT_PULLDOWN on GPIO16 only
|
||||||
|
#else
|
||||||
|
pinMode(PIRsensorPin[i], INPUT_PULLDOWN);
|
||||||
|
#endif
|
||||||
|
sensorPinState[i] = digitalRead(PIRsensorPin[i]);
|
||||||
} else {
|
} else {
|
||||||
if (PIRsensorPin >= 0) {
|
DEBUG_PRINT(F("PIRSensorSwitch pin ")); DEBUG_PRINTLN(i); DEBUG_PRINTLN(F(" allocation failed."));
|
||||||
DEBUG_PRINTLN(F("PIRSensorSwitch pin allocation failed."));
|
PIRsensorPin[i] = -1; // allocation failed
|
||||||
}
|
|
||||||
PIRsensorPin = -1; // allocation failed
|
|
||||||
enabled = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
initDone = true;
|
initDone = true;
|
||||||
@ -382,8 +396,8 @@ void PIRsensorSwitch::onMqttConnect(bool sessionPresent)
|
|||||||
|
|
||||||
void PIRsensorSwitch::loop()
|
void PIRsensorSwitch::loop()
|
||||||
{
|
{
|
||||||
// only check sensors 4x/s
|
// only check sensors 5x/s
|
||||||
if (!enabled || millis() - lastLoop < 250 || strip.isUpdating()) return;
|
if (!enabled || millis() - lastLoop < 200) return;
|
||||||
lastLoop = millis();
|
lastLoop = millis();
|
||||||
|
|
||||||
if (!updatePIRsensorState()) {
|
if (!updatePIRsensorState()) {
|
||||||
@ -396,37 +410,35 @@ void PIRsensorSwitch::addToJsonInfo(JsonObject &root)
|
|||||||
JsonObject user = root["u"];
|
JsonObject user = root["u"];
|
||||||
if (user.isNull()) user = root.createNestedObject("u");
|
if (user.isNull()) user = root.createNestedObject("u");
|
||||||
|
|
||||||
|
bool state = LOW;
|
||||||
|
for (int i = 0; i < PIR_SENSOR_MAX_SENSORS; i++)
|
||||||
|
if (PIRsensorPin[i] >= 0) state |= sensorPinState[i];
|
||||||
|
|
||||||
JsonArray infoArr = user.createNestedArray(FPSTR(_name));
|
JsonArray infoArr = user.createNestedArray(FPSTR(_name));
|
||||||
|
|
||||||
String uiDomString;
|
String uiDomString;
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
if (offTimerStart > 0)
|
if (offTimerStart > 0) {
|
||||||
{
|
|
||||||
uiDomString = "";
|
uiDomString = "";
|
||||||
unsigned int offSeconds = (m_switchOffDelay - (millis() - offTimerStart)) / 1000;
|
unsigned int offSeconds = (m_switchOffDelay - (millis() - offTimerStart)) / 1000;
|
||||||
if (offSeconds >= 3600)
|
if (offSeconds >= 3600) {
|
||||||
{
|
|
||||||
uiDomString += (offSeconds / 3600);
|
uiDomString += (offSeconds / 3600);
|
||||||
uiDomString += F("h ");
|
uiDomString += F("h ");
|
||||||
offSeconds %= 3600;
|
offSeconds %= 3600;
|
||||||
}
|
}
|
||||||
if (offSeconds >= 60)
|
if (offSeconds >= 60) {
|
||||||
{
|
|
||||||
uiDomString += (offSeconds / 60);
|
uiDomString += (offSeconds / 60);
|
||||||
offSeconds %= 60;
|
offSeconds %= 60;
|
||||||
}
|
} else if (uiDomString.length() > 0) {
|
||||||
else if (uiDomString.length() > 0)
|
|
||||||
{
|
|
||||||
uiDomString += 0;
|
uiDomString += 0;
|
||||||
}
|
}
|
||||||
if (uiDomString.length() > 0)
|
if (uiDomString.length() > 0) {
|
||||||
{
|
|
||||||
uiDomString += F("min ");
|
uiDomString += F("min ");
|
||||||
}
|
}
|
||||||
uiDomString += (offSeconds);
|
uiDomString += (offSeconds);
|
||||||
infoArr.add(uiDomString + F("s"));
|
infoArr.add(uiDomString + F("s"));
|
||||||
} else {
|
} else {
|
||||||
infoArr.add(sensorPinState ? F("sensor on") : F("inactive"));
|
infoArr.add(state ? F("sensor on") : F("inactive"));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
infoArr.add(F("disabled"));
|
infoArr.add(F("disabled"));
|
||||||
@ -446,9 +458,11 @@ void PIRsensorSwitch::addToJsonInfo(JsonObject &root)
|
|||||||
uiDomString += F("</button>");
|
uiDomString += F("</button>");
|
||||||
infoArr.add(uiDomString);
|
infoArr.add(uiDomString);
|
||||||
|
|
||||||
JsonObject sensor = root[F("sensor")];
|
if (enabled) {
|
||||||
if (sensor.isNull()) sensor = root.createNestedObject(F("sensor"));
|
JsonObject sensor = root[F("sensor")];
|
||||||
sensor[F("motion")] = sensorPinState || offTimerStart>0 ? true : false;
|
if (sensor.isNull()) sensor = root.createNestedObject(F("sensor"));
|
||||||
|
sensor[F("motion")] = state || offTimerStart>0 ? true : false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PIRsensorSwitch::onStateChange(uint8_t mode) {
|
void PIRsensorSwitch::onStateChange(uint8_t mode) {
|
||||||
@ -478,7 +492,8 @@ void PIRsensorSwitch::addToConfig(JsonObject &root)
|
|||||||
JsonObject top = root.createNestedObject(FPSTR(_name));
|
JsonObject top = root.createNestedObject(FPSTR(_name));
|
||||||
top[FPSTR(_enabled)] = enabled;
|
top[FPSTR(_enabled)] = enabled;
|
||||||
top[FPSTR(_switchOffDelay)] = m_switchOffDelay / 1000;
|
top[FPSTR(_switchOffDelay)] = m_switchOffDelay / 1000;
|
||||||
top["pin"] = PIRsensorPin;
|
JsonArray pinArray = top.createNestedArray("pin");
|
||||||
|
for (int i = 0; i < PIR_SENSOR_MAX_SENSORS; i++) pinArray.add(PIRsensorPin[i]);
|
||||||
top[FPSTR(_onPreset)] = m_onPreset;
|
top[FPSTR(_onPreset)] = m_onPreset;
|
||||||
top[FPSTR(_offPreset)] = m_offPreset;
|
top[FPSTR(_offPreset)] = m_offPreset;
|
||||||
top[FPSTR(_nightTime)] = m_nightTimeOnly;
|
top[FPSTR(_nightTime)] = m_nightTimeOnly;
|
||||||
@ -494,12 +509,20 @@ void PIRsensorSwitch::appendConfigData()
|
|||||||
{
|
{
|
||||||
oappend(SET_F("addInfo('PIRsensorSwitch:HA-discovery',1,'HA=Home Assistant');")); // 0 is field type, 1 is actual field
|
oappend(SET_F("addInfo('PIRsensorSwitch:HA-discovery',1,'HA=Home Assistant');")); // 0 is field type, 1 is actual field
|
||||||
oappend(SET_F("addInfo('PIRsensorSwitch:override',1,'Cancel timer on change');")); // 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
|
||||||
|
for (int i = 0; i < PIR_SENSOR_MAX_SENSORS; i++) {
|
||||||
|
char str[128];
|
||||||
|
sprintf_P(str, PSTR("addInfo('PIRsensorSwitch:pin[]',%d,'','#%d');"), i, i);
|
||||||
|
oappend(str);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PIRsensorSwitch::readFromConfig(JsonObject &root)
|
bool PIRsensorSwitch::readFromConfig(JsonObject &root)
|
||||||
{
|
{
|
||||||
bool oldEnabled = enabled;
|
int8_t oldPin[PIR_SENSOR_MAX_SENSORS];
|
||||||
int8_t oldPin = PIRsensorPin;
|
for (int i = 0; i < PIR_SENSOR_MAX_SENSORS; i++) {
|
||||||
|
oldPin[i] = PIRsensorPin[i];
|
||||||
|
PIRsensorPin[i] = -1;
|
||||||
|
}
|
||||||
|
|
||||||
DEBUG_PRINT(FPSTR(_name));
|
DEBUG_PRINT(FPSTR(_name));
|
||||||
JsonObject top = root[FPSTR(_name)];
|
JsonObject top = root[FPSTR(_name)];
|
||||||
@ -508,7 +531,13 @@ bool PIRsensorSwitch::readFromConfig(JsonObject &root)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
PIRsensorPin = top["pin"] | PIRsensorPin;
|
JsonArray pins = top["pin"];
|
||||||
|
if (!pins.isNull()) {
|
||||||
|
for (int i = 0; i < PIR_SENSOR_MAX_SENSORS; i++)
|
||||||
|
if (i < pins.size()) PIRsensorPin[i] = pins[i] | PIRsensorPin[i];
|
||||||
|
} else {
|
||||||
|
PIRsensorPin[0] = top["pin"] | oldPin[0];
|
||||||
|
}
|
||||||
|
|
||||||
enabled = top[FPSTR(_enabled)] | enabled;
|
enabled = top[FPSTR(_enabled)] | enabled;
|
||||||
|
|
||||||
@ -530,26 +559,11 @@ bool PIRsensorSwitch::readFromConfig(JsonObject &root)
|
|||||||
// reading config prior to setup()
|
// reading config prior to setup()
|
||||||
DEBUG_PRINTLN(F(" config loaded."));
|
DEBUG_PRINTLN(F(" config loaded."));
|
||||||
} else {
|
} else {
|
||||||
if (oldPin != PIRsensorPin || oldEnabled != enabled) {
|
for (int i = 0; i < PIR_SENSOR_MAX_SENSORS; i++)
|
||||||
// check if pin is OK
|
if (oldPin[i] >= 0) pinManager.deallocatePin(oldPin[i], PinOwner::UM_PIR);
|
||||||
if (oldPin != PIRsensorPin && oldPin >= 0) {
|
setup();
|
||||||
// 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."));
|
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||||
}
|
}
|
||||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||||
return !top[FPSTR(_domoticzIDX)].isNull();
|
return !(pins.isNull() || pins.size() != PIR_SENSOR_MAX_SENSORS);
|
||||||
}
|
}
|
||||||
|
@ -426,7 +426,7 @@
|
|||||||
#ifdef ESP8266
|
#ifdef ESP8266
|
||||||
#define SETTINGS_STACK_BUF_SIZE 2048
|
#define SETTINGS_STACK_BUF_SIZE 2048
|
||||||
#else
|
#else
|
||||||
#define SETTINGS_STACK_BUF_SIZE 3608 // warning: quite a large value for stack
|
#define SETTINGS_STACK_BUF_SIZE 3840 // warning: quite a large value for stack (640 * WLED_MAX_USERMODS)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef WLED_USE_ETHERNET
|
#ifdef WLED_USE_ETHERNET
|
||||||
|
@ -227,10 +227,10 @@
|
|||||||
} else if (typeof(fld) === "number") sel.classList.add("pin"); // a hack to add a class
|
} else if (typeof(fld) === "number") sel.classList.add("pin"); // a hack to add a class
|
||||||
let arr = d.getElementsByName(um);
|
let arr = d.getElementsByName(um);
|
||||||
let idx = arr[0].type==="hidden"?1:0; // ignore hidden field
|
let idx = arr[0].type==="hidden"?1:0; // ignore hidden field
|
||||||
if (arr.length > 2) {
|
if (arr.length > 1+idx) {
|
||||||
// we have array of values (usually pins)
|
// we have array of values (usually pins)
|
||||||
for (let i of arr) {
|
for (let i of arr) {
|
||||||
if (i.type === "number") break;
|
if (i.nodeName === "INPUT" && i.type === "number") break;
|
||||||
idx++;
|
idx++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user