Update usermods: FixUnreachableNetServices and PIRsensorSwitch (#1448)
* Removed usermod Fix_unreachable_webserver * Changed README. Added a compiler warning for ESP32 * Fix ESP32 compiling issue. Add instance ptr API. * Updated usermods. Store config values. ESP32 fix. * Store analog clock settings * Rename JSON values bring them visually more in line with the other settings Co-authored-by: cschwinne <dev.aircoookie@gmail.com>
This commit is contained in:
parent
6b4bbe625b
commit
7a7f34746e
@ -1,17 +1,32 @@
|
|||||||
# Fix unreachable net services V2
|
# Fix unreachable net services V2
|
||||||
|
|
||||||
|
**Attention: This usermod compiles only for ESP8266**
|
||||||
|
|
||||||
This usermod-v2 modification performs a ping request to the local IP address every 60 seconds. By this procedure the net services of WLED remains accessible in some problematic WLAN environments.
|
This usermod-v2 modification performs a ping request to the local IP address every 60 seconds. By this procedure the net services of WLED remains accessible in some problematic WLAN environments.
|
||||||
|
|
||||||
The modification works with static or DHCP IP address configuration.
|
The modification works with static or DHCP IP address configuration.
|
||||||
|
|
||||||
**Webinterface**: The number of pings and reconnects is displayed on the info page in the web interface.
|
|
||||||
|
|
||||||
_Story:_
|
_Story:_
|
||||||
|
|
||||||
Unfortunately, with all ESP projects where a web server or other network services are running, I have the problem that after some time the web server is no longer accessible. Now I found out that the connection is at least reestablished when a ping request is executed by the device.
|
Unfortunately, with all ESP projects where a web server or other network services are running, I have the problem that after some time the web server is no longer accessible. Now I found out that the connection is at least reestablished when a ping request is executed by the device.
|
||||||
|
|
||||||
With this modification, in the worst case, the network functions are not available for 60 seconds until the next ping request.
|
With this modification, in the worst case, the network functions are not available for 60 seconds until the next ping request.
|
||||||
|
|
||||||
|
## Webinterface
|
||||||
|
|
||||||
|
The number of pings and reconnects is displayed on the info page in the web interface.
|
||||||
|
The ping delay can be changed. Changes persist after a reboot.
|
||||||
|
|
||||||
|
## JSON API
|
||||||
|
|
||||||
|
The usermod supports the following state changes:
|
||||||
|
|
||||||
|
| JSON key | Value range | Description |
|
||||||
|
|-------------|------------------|---------------------------------|
|
||||||
|
| PingDelayMs | 5000 to 18000000 | Deactivdate/activate the sensor |
|
||||||
|
|
||||||
|
Changes also persist after a reboot.
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
1. Copy the file `usermod_Fix_unreachable_netservices.h` to the `wled00` directory.
|
1. Copy the file `usermod_Fix_unreachable_netservices.h` to the `wled00` directory.
|
||||||
|
@ -1,6 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "wled.h"
|
#include "wled.h"
|
||||||
|
#if defined(ESP32)
|
||||||
|
#warning "Usermod FixUnreachableNetServices works only with ESP8266 builds"
|
||||||
|
class FixUnreachableNetServices : public Usermod
|
||||||
|
{
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(ESP8266)
|
||||||
#include <ping.h>
|
#include <ping.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -23,34 +31,37 @@
|
|||||||
* 2. Register the usermod by adding #include "usermod_filename.h" in the top and registerUsermod(new MyUsermodClass()) in the bottom of usermods_list.cpp
|
* 2. Register the usermod by adding #include "usermod_filename.h" in the top and registerUsermod(new MyUsermodClass()) in the bottom of usermods_list.cpp
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class FixUnreachableNetServices : public Usermod {
|
class FixUnreachableNetServices : public Usermod
|
||||||
|
{
|
||||||
private:
|
private:
|
||||||
//Private class members. You can declare variables and functions only accessible to your usermod here
|
//Private class members. You can declare variables and functions only accessible to your usermod here
|
||||||
unsigned long m_lastTime = 0;
|
unsigned long m_lastTime = 0;
|
||||||
|
|
||||||
// desclare required variables
|
// declare required variables
|
||||||
const unsigned int PingDelayMs = 60000;
|
unsigned long m_pingDelayMs = 60000;
|
||||||
unsigned long m_connectedWiFi = 0;
|
unsigned long m_connectedWiFi = 0;
|
||||||
ping_option m_pingOpt;
|
ping_option m_pingOpt;
|
||||||
unsigned int m_pingCount = 0;
|
unsigned int m_pingCount = 0;
|
||||||
|
bool m_updateConfig = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
//Functions called by WLED
|
//Functions called by WLED
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* 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()
|
||||||
|
{
|
||||||
//Serial.println("Hello from my usermod!");
|
//Serial.println("Hello from my usermod!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
/*
|
|
||||||
* 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()
|
||||||
|
{
|
||||||
//Serial.println("Connected to WiFi!");
|
//Serial.println("Connected to WiFi!");
|
||||||
|
|
||||||
++m_connectedWiFi;
|
++m_connectedWiFi;
|
||||||
@ -59,31 +70,27 @@ class FixUnreachableNetServices : public Usermod {
|
|||||||
memset(&m_pingOpt, 0, sizeof(struct ping_option));
|
memset(&m_pingOpt, 0, sizeof(struct ping_option));
|
||||||
m_pingOpt.count = 1;
|
m_pingOpt.count = 1;
|
||||||
m_pingOpt.ip = WiFi.localIP();
|
m_pingOpt.ip = WiFi.localIP();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
/*
|
* loop
|
||||||
* loop() is called continuously. Here you can check for events, read sensors, etc.
|
|
||||||
*
|
|
||||||
* Tips:
|
|
||||||
* 1. You can use "if (WLED_CONNECTED)" to check for a successful network connection.
|
|
||||||
* Additionally, "if (WLED_MQTT_CONNECTED)" is available to check for a connection to an MQTT broker.
|
|
||||||
*
|
|
||||||
* 2. Try to avoid using the delay() function. NEVER use delays longer than 10 milliseconds.
|
|
||||||
* Instead, use a timer check as shown here.
|
|
||||||
*/
|
*/
|
||||||
void loop() {
|
void loop()
|
||||||
if (m_connectedWiFi > 0 && millis()-m_lastTime > PingDelayMs)
|
{
|
||||||
|
if (m_connectedWiFi > 0 && millis() - m_lastTime > m_pingDelayMs)
|
||||||
{
|
{
|
||||||
ping_start(&m_pingOpt);
|
ping_start(&m_pingOpt);
|
||||||
m_lastTime = millis();
|
m_lastTime = millis();
|
||||||
++m_pingCount;
|
++m_pingCount;
|
||||||
}
|
}
|
||||||
|
if (m_updateConfig)
|
||||||
|
{
|
||||||
|
serializeConfig();
|
||||||
|
m_updateConfig = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
/*
|
|
||||||
* 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.
|
||||||
* Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI.
|
* Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI.
|
||||||
* Below it is shown how this could be used for e.g. a light sensor
|
* Below it is shown how this could be used for e.g. a light sensor
|
||||||
@ -92,9 +99,15 @@ class FixUnreachableNetServices : public Usermod {
|
|||||||
{
|
{
|
||||||
//this code adds "u":{"⚡ Ping fix pings": m_pingCount} to the info object
|
//this code adds "u":{"⚡ Ping fix pings": m_pingCount} to the info object
|
||||||
JsonObject user = root["u"];
|
JsonObject user = root["u"];
|
||||||
if (user.isNull()) user = root.createNestedObject("u");
|
if (user.isNull())
|
||||||
|
user = root.createNestedObject("u");
|
||||||
|
|
||||||
JsonArray infoArr = user.createNestedArray("⚡ Ping fix pings"); //name
|
String uiDomString = "⚡ Ping fix pings<span style=\"display:block;padding-left:25px;\">\
|
||||||
|
Delay <input type=\"number\" min=\"5\" max=\"300\" value=\"";
|
||||||
|
uiDomString += (unsigned long)(m_pingDelayMs / 1000);
|
||||||
|
uiDomString += "\" onchange=\"requestJson({PingDelay:parseInt(this.value)});\">sec</span>";
|
||||||
|
|
||||||
|
JsonArray infoArr = user.createNestedArray(uiDomString); //name
|
||||||
infoArr.add(m_pingCount); //value
|
infoArr.add(m_pingCount); //value
|
||||||
|
|
||||||
//this code adds "u":{"⚡ Reconnects": m_connectedWiFi - 1} to the info object
|
//this code adds "u":{"⚡ Reconnects": m_connectedWiFi - 1} to the info object
|
||||||
@ -102,29 +115,48 @@ class FixUnreachableNetServices : public Usermod {
|
|||||||
infoArr.add(m_connectedWiFi - 1); //value
|
infoArr.add(m_connectedWiFi - 1); //value
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
/*
|
|
||||||
* 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)
|
||||||
{
|
{
|
||||||
//root["user0"] = userVar0;
|
root["PingDelay"] = (m_pingDelayMs/1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
/*
|
|
||||||
* 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)
|
||||||
{
|
{
|
||||||
//userVar0 = root["user0"] | userVar0; //if "user0" key exists in JSON, update, else keep old value
|
if (root["PingDelay"] != nullptr)
|
||||||
//if (root["bri"] == 255) Serial.println(F("Don't burn down your garage!"));
|
{
|
||||||
|
m_pingDelayMs = (1000 * max(1UL, min(300UL, root["PingDelay"].as<unsigned long>())));
|
||||||
|
m_updateConfig = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* provide the changeable values
|
||||||
|
*/
|
||||||
|
void addToConfig(JsonObject &root)
|
||||||
|
{
|
||||||
|
JsonObject top = root.createNestedObject("FixUnreachableNetServices");
|
||||||
|
top["PingDelayMs"] = m_pingDelayMs;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|
* restore the changeable values
|
||||||
|
*/
|
||||||
|
void readFromConfig(JsonObject &root)
|
||||||
|
{
|
||||||
|
JsonObject top = root["FixUnreachableNetServices"];
|
||||||
|
m_pingDelayMs = top["PingDelayMs"] | m_pingDelayMs;
|
||||||
|
m_pingDelayMs = max(5000UL, min(18000000UL, m_pingDelayMs));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
* 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.
|
||||||
*/
|
*/
|
||||||
@ -132,7 +164,5 @@ class FixUnreachableNetServices : public Usermod {
|
|||||||
{
|
{
|
||||||
return USERMOD_ID_FIXNETSERVICES;
|
return USERMOD_ID_FIXNETSERVICES;
|
||||||
}
|
}
|
||||||
|
|
||||||
//More methods can be added in the future, this example will then be extended.
|
|
||||||
//Your usermod will remain compatible as it does not need to implement all methods from the Usermod base class!
|
|
||||||
};
|
};
|
||||||
|
#endif
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
# Fix unreachable Webserver
|
|
||||||
|
|
||||||
This modification performs a ping request to the local IP address every 60 seconds. By this procedure the web server remains accessible in some problematic WLAN environments.
|
|
||||||
|
|
||||||
The modification works with static or DHCP IP address configuration
|
|
||||||
|
|
||||||
_Story:_
|
|
||||||
|
|
||||||
Unfortunately, with all ESP projects where a web server or other network services are running, I have the problem that after some time the web server is no longer accessible. Now I found out that the connection is at least reestablished when a ping request is executed by the device.
|
|
||||||
|
|
||||||
With this modification, in the worst case, the network functions are not available for 60 seconds until the next ping request.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
Copy and replace the file `usermod.cpp` in wled00 directory.
|
|
||||||
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
|||||||
#include "wled.h"
|
|
||||||
/*
|
|
||||||
* This file allows you to add own functionality to WLED more easily
|
|
||||||
* See: https://github.com/Aircoookie/WLED/wiki/Add-own-functionality
|
|
||||||
* EEPROM bytes 2750+ are reserved for your custom use case. (if you extend #define EEPSIZE in const.h)
|
|
||||||
* bytes 2400+ are currently ununsed, but might be used for future wled features
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <ping.h>
|
|
||||||
|
|
||||||
const int PingDelayMs = 60000;
|
|
||||||
long lastCheckTime = 0;
|
|
||||||
bool connectedWiFi = false;
|
|
||||||
ping_option pingOpt;
|
|
||||||
|
|
||||||
//Use userVar0 and userVar1 (API calls &U0=,&U1=, uint16_t)
|
|
||||||
|
|
||||||
//gets called once at boot. Do all initialization that doesn't depend on network here
|
|
||||||
void userSetup()
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//gets called every time WiFi is (re-)connected. Initialize own network interfaces here
|
|
||||||
void userConnected()
|
|
||||||
{
|
|
||||||
connectedWiFi = true;
|
|
||||||
// initialize ping_options structure
|
|
||||||
memset(&pingOpt, 0, sizeof(struct ping_option));
|
|
||||||
pingOpt.count = 1;
|
|
||||||
pingOpt.ip = WiFi.localIP();
|
|
||||||
}
|
|
||||||
|
|
||||||
//loop. You can use "if (WLED_CONNECTED)" to check for successful connection
|
|
||||||
void userLoop()
|
|
||||||
{
|
|
||||||
if (connectedWiFi && millis()-lastCheckTime > PingDelayMs)
|
|
||||||
{
|
|
||||||
ping_start(&pingOpt);
|
|
||||||
lastCheckTime = millis();
|
|
||||||
}
|
|
||||||
}
|
|
@ -11,8 +11,8 @@ The LED strip is switched [using a relay](https://github.com/Aircoookie/WLED/wik
|
|||||||
|
|
||||||
The info page in the web interface shows the items below
|
The info page in the web interface shows the items below
|
||||||
|
|
||||||
- the state of the sensor. By clicking on the state the sensor can be deactivated/activated.
|
- the state of the sensor. By clicking on the state the sensor can be deactivated/activated. Changes persist after a reboot.
|
||||||
**I recommend to deactivate the sensor before installing an OTA update**.
|
**I recommend to deactivate the sensor before an OTA update and activate it again afterwards**.
|
||||||
- the remaining time of the off timer.
|
- the remaining time of the off timer.
|
||||||
|
|
||||||
## JSON API
|
## JSON API
|
||||||
@ -24,6 +24,8 @@ The usermod supports the following state changes:
|
|||||||
| PIRenabled | bool | Deactivdate/activate the sensor |
|
| PIRenabled | bool | Deactivdate/activate the sensor |
|
||||||
| PIRoffSec | 60 to 43200 | Off timer seconds |
|
| PIRoffSec | 60 to 43200 | Off timer seconds |
|
||||||
|
|
||||||
|
Changes also persist after a reboot.
|
||||||
|
|
||||||
## Sensor connection
|
## Sensor connection
|
||||||
|
|
||||||
My setup uses an HC-SR501 sensor, a HC-SR505 should also work.
|
My setup uses an HC-SR501 sensor, a HC-SR505 should also work.
|
||||||
@ -72,26 +74,36 @@ void registerUsermods()
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usermod installation (advanced mode)
|
## API to enable/disable the PIR sensor from outside. For example from another usermod.
|
||||||
|
|
||||||
In this mode IR sensor will disable PIR when light ON by remote controller and enable PIR when light OFF.
|
The class provides the static method `PIRsensorSwitch* PIRsensorSwitch::GetInstance()` to get a pointer to the usermod object.
|
||||||
|
|
||||||
1. Copy the file `usermod_PIR_sensor_switch.h` to the `wled00` directory.
|
To query or change the PIR sensor state the methods `bool PIRsensorEnabled()` and `void EnablePIRsensor(bool enable)` are available.
|
||||||
2. Register the usermod by adding `#include "usermod_PIR_sensor_switch.h"` in the top and `registerUsermod(new PIRsensorSwitch());` in the bottom of `usermods_list.cpp`.
|
|
||||||
3. Add to the line 237, on `wled.h` in the `wled00` directory:
|
|
||||||
|
|
||||||
`WLED_GLOBAL bool m_PIRenabled _INIT(true); // enable PIR sensor`
|
### There are two options to get access to the usermod instance:
|
||||||
|
|
||||||
4. On `ir.cpp` in the `wled00` directory, add to the IR controller's mapping (beyond line 200):
|
1. Include `usermod_PIR_sensor_switch.h` **before** you include the other usermod in `usermods_list.cpp'
|
||||||
|
|
||||||
- To the off button:
|
or
|
||||||
`m_PIRenabled = true;`
|
|
||||||
|
|
||||||
- To the on button:
|
2. Use `#include "usermod_PIR_sensor_switch.h"` at the top of the `usermod.h` where you need it.
|
||||||
`m_PIRenabled = false;`
|
|
||||||
|
|
||||||
5. Edit line 40, on `usermod_PIR_sensor_switch.h` in the `wled00` directory:
|
**Example usermod.h :**
|
||||||
|
```cpp
|
||||||
|
#include "wled.h"
|
||||||
|
|
||||||
`\\bool m_PIRenabled = true;`
|
#include "usermod_PIR_sensor_switch.h"
|
||||||
|
|
||||||
|
class MyUsermod : public Usermod {
|
||||||
|
//...
|
||||||
|
|
||||||
|
void togglePIRSensor() {
|
||||||
|
if (PIRsensorSwitch::GetInstance() != nullptr) {
|
||||||
|
PIRsensorSwitch::GetInstance()->EnablePIRsensor(!PIRsensorSwitch::GetInstance()->PIRsensorEnabled());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//...
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
Have fun - @gegu
|
Have fun - @gegu
|
||||||
|
@ -24,7 +24,40 @@
|
|||||||
* 2. Register the usermod by adding #include "usermod_filename.h" in the top and registerUsermod(new MyUsermodClass()) in the bottom of usermods_list.cpp
|
* 2. Register the usermod by adding #include "usermod_filename.h" in the top and registerUsermod(new MyUsermodClass()) in the bottom of usermods_list.cpp
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class PIRsensorSwitch : public Usermod {
|
class PIRsensorSwitch : public Usermod
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* constructor
|
||||||
|
*/
|
||||||
|
PIRsensorSwitch()
|
||||||
|
{
|
||||||
|
// set static instance pointer
|
||||||
|
PIRsensorSwitchInstance(this);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* desctructor
|
||||||
|
*/
|
||||||
|
~PIRsensorSwitch()
|
||||||
|
{
|
||||||
|
PIRsensorSwitchInstance(nullptr, true);
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* return the instance pointer of the class
|
||||||
|
*/
|
||||||
|
static PIRsensorSwitch *GetInstance() { return PIRsensorSwitchInstance(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable/Disable the PIR sensor
|
||||||
|
*/
|
||||||
|
void EnablePIRsensor(bool enable) { m_PIRenabled = enable; }
|
||||||
|
/**
|
||||||
|
* Get PIR sensor enabled/disabled state
|
||||||
|
*/
|
||||||
|
bool PIRsensorEnabled() { return m_PIRenabled; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// PIR sensor pin
|
// PIR sensor pin
|
||||||
const uint8_t PIRsensorPin = 13; // D7 on D1 mini
|
const uint8_t PIRsensorPin = 13; // D7 on D1 mini
|
||||||
@ -38,53 +71,59 @@ class PIRsensorSwitch : public Usermod {
|
|||||||
byte m_PIRsensorPinState = LOW;
|
byte m_PIRsensorPinState = LOW;
|
||||||
// PIR sensor enabled - ISR attached
|
// PIR sensor enabled - ISR attached
|
||||||
bool m_PIRenabled = true;
|
bool m_PIRenabled = true;
|
||||||
|
// state if serializeConfig() should be called
|
||||||
|
bool m_updateConfig = false;
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* return or change if new PIR sensor state is available
|
* return or change if new PIR sensor state is available
|
||||||
*/
|
*/
|
||||||
static volatile bool newPIRsensorState(bool changeState = false, bool newState = false) {
|
static volatile bool newPIRsensorState(bool changeState = false, bool newState = false);
|
||||||
static volatile bool s_PIRsensorState = false;
|
|
||||||
if (changeState) {
|
|
||||||
s_PIRsensorState = newState;
|
|
||||||
}
|
|
||||||
return s_PIRsensorState;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* PIR sensor state has changed
|
* PIR sensor state has changed
|
||||||
*/
|
*/
|
||||||
static void IRAM_ATTR ISR_PIRstateChange() {
|
static void IRAM_ATTR ISR_PIRstateChange();
|
||||||
newPIRsensorState(true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|
* Set/get instance pointer
|
||||||
|
*/
|
||||||
|
static PIRsensorSwitch *PIRsensorSwitchInstance(PIRsensorSwitch *pInstance = nullptr, bool bRemoveInstance = false);
|
||||||
|
|
||||||
|
/**
|
||||||
* switch strip on/off
|
* switch strip on/off
|
||||||
*/
|
*/
|
||||||
void switchStrip(bool switchOn) {
|
void switchStrip(bool switchOn)
|
||||||
if (switchOn && bri == 0) {
|
{
|
||||||
|
if (switchOn && bri == 0)
|
||||||
|
{
|
||||||
bri = briLast;
|
bri = briLast;
|
||||||
colorUpdated(NotifyUpdateMode);
|
colorUpdated(NotifyUpdateMode);
|
||||||
}
|
}
|
||||||
else if (!switchOn && bri != 0) {
|
else if (!switchOn && bri != 0)
|
||||||
|
{
|
||||||
briLast = bri;
|
briLast = bri;
|
||||||
bri = 0;
|
bri = 0;
|
||||||
colorUpdated(NotifyUpdateMode);
|
colorUpdated(NotifyUpdateMode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* 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()
|
||||||
if (newPIRsensorState()) {
|
{
|
||||||
|
if (newPIRsensorState())
|
||||||
|
{
|
||||||
m_PIRsensorPinState = digitalRead(PIRsensorPin);
|
m_PIRsensorPinState = digitalRead(PIRsensorPin);
|
||||||
|
|
||||||
if (m_PIRsensorPinState == HIGH) {
|
if (m_PIRsensorPinState == HIGH)
|
||||||
|
{
|
||||||
m_offTimerStart = 0;
|
m_offTimerStart = 0;
|
||||||
switchStrip(true);
|
switchStrip(true);
|
||||||
}
|
}
|
||||||
else if (bri != 0) {
|
else if (bri != 0)
|
||||||
|
{
|
||||||
// start switch off timer
|
// start switch off timer
|
||||||
m_offTimerStart = millis();
|
m_offTimerStart = millis();
|
||||||
}
|
}
|
||||||
@ -94,12 +133,15 @@ class PIRsensorSwitch : public Usermod {
|
|||||||
return false;
|
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 (m_offTimerStart > 0 && millis() - m_offTimerStart > m_switchOffDelay) {
|
{
|
||||||
if (m_PIRenabled == true){
|
if (m_offTimerStart > 0 && millis() - m_offTimerStart > m_switchOffDelay)
|
||||||
|
{
|
||||||
|
if (m_PIRenabled == true)
|
||||||
|
{
|
||||||
switchStrip(false);
|
switchStrip(false);
|
||||||
}
|
}
|
||||||
m_offTimerStart = 0;
|
m_offTimerStart = 0;
|
||||||
@ -111,37 +153,46 @@ class PIRsensorSwitch : public Usermod {
|
|||||||
public:
|
public:
|
||||||
//Functions called by WLED
|
//Functions called by WLED
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* 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()
|
||||||
|
{
|
||||||
// PIR Sensor mode INPUT_PULLUP
|
// PIR Sensor mode INPUT_PULLUP
|
||||||
pinMode(PIRsensorPin, INPUT_PULLUP);
|
pinMode(PIRsensorPin, INPUT_PULLUP);
|
||||||
|
if (m_PIRenabled)
|
||||||
|
{
|
||||||
// assign interrupt function and set CHANGE mode
|
// assign interrupt function and set CHANGE mode
|
||||||
attachInterrupt(digitalPinToInterrupt(PIRsensorPin), ISR_PIRstateChange, CHANGE);
|
attachInterrupt(digitalPinToInterrupt(PIRsensorPin), ISR_PIRstateChange, CHANGE);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
/*
|
|
||||||
* 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()
|
||||||
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
/*
|
|
||||||
* 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()
|
||||||
if (!updatePIRsensorState()) {
|
{
|
||||||
|
if (!updatePIRsensorState())
|
||||||
|
{
|
||||||
handleOffTimer();
|
handleOffTimer();
|
||||||
|
if (m_updateConfig)
|
||||||
|
{
|
||||||
|
serializeConfig();
|
||||||
|
m_updateConfig = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* 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
|
||||||
@ -151,17 +202,21 @@ class PIRsensorSwitch : public Usermod {
|
|||||||
//this code adds "u":{"⏲ PIR sensor state":uiDomString} to the info object
|
//this code adds "u":{"⏲ PIR sensor state":uiDomString} to the info object
|
||||||
// the value contains a button to toggle the sensor enabled/disabled
|
// the value contains a button to toggle the sensor enabled/disabled
|
||||||
JsonObject user = root["u"];
|
JsonObject user = root["u"];
|
||||||
if (user.isNull()) user = root.createNestedObject("u");
|
if (user.isNull())
|
||||||
|
user = root.createNestedObject("u");
|
||||||
|
|
||||||
JsonArray infoArr = user.createNestedArray("⏲ PIR sensor state"); //name
|
JsonArray infoArr = user.createNestedArray("⏲ PIR sensor state"); //name
|
||||||
String uiDomString = "<button class=\"btn infobtn\" onclick=\"requestJson({PIRenabled:";
|
String uiDomString = "<button class=\"btn infobtn\" onclick=\"requestJson({PIRenabled:";
|
||||||
String sensorStateInfo;
|
String sensorStateInfo;
|
||||||
|
|
||||||
// PIR sensor state
|
// PIR sensor state
|
||||||
if (m_PIRenabled) {
|
if (m_PIRenabled)
|
||||||
|
{
|
||||||
uiDomString += "false";
|
uiDomString += "false";
|
||||||
sensorStateInfo = (m_PIRsensorPinState != LOW ? "active" : "inactive"); //value
|
sensorStateInfo = (m_PIRsensorPinState != LOW ? "active" : "inactive"); //value
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
uiDomString += "true";
|
uiDomString += "true";
|
||||||
sensorStateInfo = "Disabled !";
|
sensorStateInfo = "Disabled !";
|
||||||
}
|
}
|
||||||
@ -171,35 +226,46 @@ class PIRsensorSwitch : public Usermod {
|
|||||||
infoArr.add(uiDomString); //value
|
infoArr.add(uiDomString); //value
|
||||||
|
|
||||||
//this code adds "u":{"⏲ switch off timer":uiDomString} to the info object
|
//this code adds "u":{"⏲ switch off timer":uiDomString} to the info object
|
||||||
infoArr = user.createNestedArray("⏲ switch off timer"); //name
|
uiDomString = "⏲ switch off timer<span style=\"display:block;padding-left:25px;\">\
|
||||||
|
after <input type=\"number\" min=\"1\" max=\"720\" value=\"";
|
||||||
|
uiDomString += (m_switchOffDelay / 60000);
|
||||||
|
uiDomString += "\" onchange=\"requestJson({PIRoffSec:parseInt(this.value)*60});\">min</span>";
|
||||||
|
infoArr = user.createNestedArray(uiDomString); //name
|
||||||
|
|
||||||
// off timer
|
// off timer
|
||||||
if (m_offTimerStart > 0) {
|
if (m_offTimerStart > 0)
|
||||||
|
{
|
||||||
uiDomString = "";
|
uiDomString = "";
|
||||||
unsigned int offSeconds = (m_switchOffDelay - (millis() - m_offTimerStart)) / 1000;
|
unsigned int offSeconds = (m_switchOffDelay - (millis() - m_offTimerStart)) / 1000;
|
||||||
if (offSeconds >= 3600) {
|
if (offSeconds >= 3600)
|
||||||
|
{
|
||||||
uiDomString += (offSeconds / 3600);
|
uiDomString += (offSeconds / 3600);
|
||||||
uiDomString += " hours ";
|
uiDomString += " hours ";
|
||||||
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 += " min ";
|
uiDomString += " min ";
|
||||||
}
|
}
|
||||||
uiDomString += (offSeconds);
|
uiDomString += (offSeconds);
|
||||||
infoArr.add(uiDomString + " sec");
|
infoArr.add(uiDomString + " sec");
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
infoArr.add("inactive");
|
infoArr.add("inactive");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
/*
|
|
||||||
* 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
|
||||||
* Add "PIRenabled" to json state. This can be used to disable/enable the sensor.
|
* Add "PIRenabled" to json state. This can be used to disable/enable the sensor.
|
||||||
@ -211,8 +277,7 @@ class PIRsensorSwitch : public Usermod {
|
|||||||
root["PIRoffSec"] = (m_switchOffDelay / 1000);
|
root["PIRoffSec"] = (m_switchOffDelay / 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
/*
|
|
||||||
* 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
|
||||||
* Read "PIRenabled" from json state and switch enable/disable the PIR sensor.
|
* Read "PIRenabled" from json state and switch enable/disable the PIR sensor.
|
||||||
@ -220,24 +285,49 @@ class PIRsensorSwitch : public Usermod {
|
|||||||
*/
|
*/
|
||||||
void readFromJsonState(JsonObject &root)
|
void readFromJsonState(JsonObject &root)
|
||||||
{
|
{
|
||||||
if (root["PIRoffSec"] != nullptr) {
|
if (root["PIRoffSec"] != nullptr)
|
||||||
|
{
|
||||||
m_switchOffDelay = (1000 * max(60UL, min(43200UL, root["PIRoffSec"].as<unsigned long>())));
|
m_switchOffDelay = (1000 * max(60UL, min(43200UL, root["PIRoffSec"].as<unsigned long>())));
|
||||||
|
m_updateConfig = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (root["PIRenabled"] != nullptr) {
|
if (root["PIRenabled"] != nullptr)
|
||||||
if (root["PIRenabled"] && !m_PIRenabled) {
|
{
|
||||||
|
if (root["PIRenabled"] && !m_PIRenabled)
|
||||||
|
{
|
||||||
attachInterrupt(digitalPinToInterrupt(PIRsensorPin), ISR_PIRstateChange, CHANGE);
|
attachInterrupt(digitalPinToInterrupt(PIRsensorPin), ISR_PIRstateChange, CHANGE);
|
||||||
newPIRsensorState(true, true);
|
newPIRsensorState(true, true);
|
||||||
}
|
}
|
||||||
else if(m_PIRenabled) {
|
else if (m_PIRenabled)
|
||||||
|
{
|
||||||
detachInterrupt(PIRsensorPin);
|
detachInterrupt(PIRsensorPin);
|
||||||
}
|
}
|
||||||
m_PIRenabled = root["PIRenabled"];
|
m_PIRenabled = root["PIRenabled"];
|
||||||
|
m_updateConfig = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* provide the changeable values
|
||||||
|
*/
|
||||||
|
void addToConfig(JsonObject &root)
|
||||||
|
{
|
||||||
|
JsonObject top = root.createNestedObject("PIRsensorSwitch");
|
||||||
|
top["PIRenabled"] = m_PIRenabled;
|
||||||
|
top["PIRoffSec"] = m_switchOffDelay;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
|
* restore the changeable values
|
||||||
|
*/
|
||||||
|
void readFromConfig(JsonObject &root)
|
||||||
|
{
|
||||||
|
JsonObject top = root["PIRsensorSwitch"];
|
||||||
|
m_PIRenabled = (top["PIRenabled"] != nullptr ? top["PIRenabled"] : true);
|
||||||
|
m_switchOffDelay = top["PIRoffSec"] | m_switchOffDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
* 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.
|
||||||
*/
|
*/
|
||||||
@ -245,7 +335,32 @@ class PIRsensorSwitch : public Usermod {
|
|||||||
{
|
{
|
||||||
return USERMOD_ID_PIRSWITCH;
|
return USERMOD_ID_PIRSWITCH;
|
||||||
}
|
}
|
||||||
|
|
||||||
//More methods can be added in the future, this example will then be extended.
|
|
||||||
//Your usermod will remain compatible as it does not need to implement all methods from the Usermod base class!
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////
|
||||||
|
// PIRsensorSwitch static method implementations
|
||||||
|
|
||||||
|
volatile bool PIRsensorSwitch::newPIRsensorState(bool changeState, bool newState)
|
||||||
|
{
|
||||||
|
static volatile bool s_PIRsensorState = false;
|
||||||
|
if (changeState)
|
||||||
|
{
|
||||||
|
s_PIRsensorState = newState;
|
||||||
|
}
|
||||||
|
return s_PIRsensorState;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRAM_ATTR PIRsensorSwitch::ISR_PIRstateChange()
|
||||||
|
{
|
||||||
|
newPIRsensorState(true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
PIRsensorSwitch *PIRsensorSwitch::PIRsensorSwitchInstance(PIRsensorSwitch *pInstance, bool bRemoveInstance)
|
||||||
|
{
|
||||||
|
static PIRsensorSwitch *s_pPIRsensorSwitch = nullptr;
|
||||||
|
if (pInstance != nullptr || bRemoveInstance)
|
||||||
|
{
|
||||||
|
s_pPIRsensorSwitch = pInstance;
|
||||||
|
}
|
||||||
|
return s_pPIRsensorSwitch;
|
||||||
|
}
|
||||||
|
@ -251,7 +251,11 @@ void deserializeConfig() {
|
|||||||
CJSON(countdownMode, ol[F("cntdwn")]);
|
CJSON(countdownMode, ol[F("cntdwn")]);
|
||||||
overlayCurrent = overlayDefault;
|
overlayCurrent = overlayDefault;
|
||||||
|
|
||||||
JsonArray ol_cntdwn = ol[F("cntdwn")]; //[20,12,31,23,59,59]
|
CJSON(overlayMin, ol[F("min")]);
|
||||||
|
CJSON(overlayMax, ol[F("max")]);
|
||||||
|
CJSON(analogClock12pixel, ol[F("o12pix")]);
|
||||||
|
CJSON(analogClock5MinuteMarks, ol[F("o5m")]);
|
||||||
|
CJSON(analogClockSecondsTrail, ol[F("osec")]);
|
||||||
|
|
||||||
//timed macro rules
|
//timed macro rules
|
||||||
JsonObject tm = doc[F("timers")];
|
JsonObject tm = doc[F("timers")];
|
||||||
@ -562,6 +566,12 @@ void serializeConfig() {
|
|||||||
ol[F("clock")] = overlayDefault;
|
ol[F("clock")] = overlayDefault;
|
||||||
ol[F("cntdwn")] = countdownMode;
|
ol[F("cntdwn")] = countdownMode;
|
||||||
|
|
||||||
|
ol[F("min")] = overlayMin;
|
||||||
|
ol[F("max")] = overlayMax;
|
||||||
|
ol[F("o12pix")] = analogClock12pixel;
|
||||||
|
ol[F("o5m")] = analogClock5MinuteMarks;
|
||||||
|
ol[F("osec")] = analogClockSecondsTrail;
|
||||||
|
|
||||||
JsonObject timers = doc.createNestedObject("timers");
|
JsonObject timers = doc.createNestedObject("timers");
|
||||||
|
|
||||||
JsonObject cntdwn = timers.createNestedObject("cntdwn");
|
JsonObject cntdwn = timers.createNestedObject("cntdwn");
|
||||||
|
Loading…
Reference in New Issue
Block a user