Fixed pin reservations. (#2214)
* Fixed pin reservations. Added ethernet pin reservations. Minor tweaks in usermods. * Optional ADA compile (not default, free GPIO3 use) * Move ethernet definitions Remove pin 3 used check Co-authored-by: cschwinne <dev.aircoookie@gmail.com>
This commit is contained in:
parent
7d929dcde6
commit
dc9dedf220
@ -1,33 +1,33 @@
|
|||||||
# JSON IR remote
|
# JSON IR remote
|
||||||
|
|
||||||
## Purpose
|
## Purpose
|
||||||
|
|
||||||
The JSON IR remote allows users to customize IR remote behavior without writing custom code and compiling.
|
The JSON IR remote allows users to customize IR remote behavior without writing custom code and compiling.
|
||||||
It also enables using any remote that is compatible with your IR receiver. Using the JSON IR remote, you can
|
It also enables using any remote that is compatible with your IR receiver. Using the JSON IR remote, you can
|
||||||
map buttons from any remote to any HTTP request API or JSON API command.
|
map buttons from any remote to any HTTP request API or JSON API command.
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
* Upload the IR config file, named _ir.json_ to your board using the [ip address]/edit url. Pick from one of the included files or create your own.
|
* Upload the IR config file, named _ir.json_ to your board using the [ip address]/edit url. Pick from one of the included files or create your own.
|
||||||
* On the config > LED settings page, set the correct IR pin.
|
* On the config > LED settings page, set the correct IR pin.
|
||||||
* On the config > Sync Interfaces page, select "JSON Remote" as the Infrared remote.
|
* On the config > Sync Interfaces page, select "JSON Remote" as the Infrared remote.
|
||||||
|
|
||||||
## Modification
|
## Modification
|
||||||
|
|
||||||
* See if there is a json file with the same number of buttons as your remote. Many remotes will have the same internals and emit the same codes but have different labels.
|
* See if there is a json file with the same number of buttons as your remote. Many remotes will have the same internals and emit the same codes but have different labels.
|
||||||
* In the ir.json file, each key will be the hex encoded IR code.
|
* In the ir.json file, each key will be the hex encoded IR code.
|
||||||
* The "cmd" property will be the HTTP Request API or JSON API to execute when that button is pressed.
|
* The "cmd" property will be the HTTP Request API or JSON API to execute when that button is pressed.
|
||||||
* A limited number of c functions are supported (!incBrightness, !decBrightness, !presetFallback)
|
* A limited number of c functions are supported (!incBrightness, !decBrightness, !presetFallback)
|
||||||
* When using !presetFallback, include properties PL (preset to load), FX (effect to fall back to) and FP (palette to fall back to)
|
* When using !presetFallback, include properties PL (preset to load), FX (effect to fall back to) and FP (palette to fall back to)
|
||||||
* If the command is _repeatable_ and does not contain the "~" character, add a "rpt": true property.
|
* If the command is _repeatable_ and does not contain the "~" character, add a "rpt": true property.
|
||||||
* Other properties are ignored, but having a label property may help when editing.
|
* Other properties are ignored, but having a label property may help when editing.
|
||||||
|
|
||||||
|
|
||||||
Sample:
|
Sample:
|
||||||
{
|
{
|
||||||
"0xFF629D": {"cmd": "T=2", "rpt": true, "label": "Toggle on/off"}, // HTTP command
|
"0xFF629D": {"cmd": "T=2", "rpt": true, "label": "Toggle on/off"}, // HTTP command
|
||||||
"0xFF9867": {"cmd": "A=~16", "label": "Inc brightness"}, // HTTP command with incrementing
|
"0xFF9867": {"cmd": "A=~16", "label": "Inc brightness"}, // HTTP command with incrementing
|
||||||
"0xFF38C7": {"cmd": {"bri": 10}, "label": "Dim to 10"}, // JSON command
|
"0xFF38C7": {"cmd": {"bri": 10}, "label": "Dim to 10"}, // JSON command
|
||||||
"0xFF22DD": {"cmd": "!presetFallback", "PL": 1, "FX": 16, "FP": 6,
|
"0xFF22DD": {"cmd": "!presetFallback", "PL": 1, "FX": 16, "FP": 6,
|
||||||
"label": "Preset 1 or fallback to Saw - Party"}, // c function
|
"label": "Preset 1 or fallback to Saw - Party"}, // c function
|
||||||
}
|
}
|
||||||
|
@ -1,409 +1,409 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "wled.h"
|
#include "wled.h"
|
||||||
|
|
||||||
#ifndef PIR_SENSOR_PIN
|
#ifndef PIR_SENSOR_PIN
|
||||||
// compatible with QuinLED-Dig-Uno
|
// compatible with QuinLED-Dig-Uno
|
||||||
#ifdef ARDUINO_ARCH_ESP32
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
#define PIR_SENSOR_PIN 23 // Q4
|
#define PIR_SENSOR_PIN 23 // Q4
|
||||||
#else //ESP8266 boards
|
#else //ESP8266 boards
|
||||||
#define PIR_SENSOR_PIN 13 // Q4 (D7 on D1 mini)
|
#define PIR_SENSOR_PIN 13 // Q4 (D7 on D1 mini)
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 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.
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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
|
||||||
*
|
*
|
||||||
* v2 usermods are class inheritance based and can (but don't have to) implement more functions, each of them is shown in this example.
|
* v2 usermods are class inheritance based and can (but don't have to) implement more functions, each of them is shown in this example.
|
||||||
* Multiple v2 usermods can be added to one compilation easily.
|
* Multiple v2 usermods can be added to one compilation easily.
|
||||||
*
|
*
|
||||||
* Creating a usermod:
|
* Creating a usermod:
|
||||||
* This file serves as an example. If you want to create a usermod, it is recommended to use usermod_v2_empty.h from the usermods folder as a template.
|
* This file serves as an example. If you want to create a usermod, it is recommended to use usermod_v2_empty.h from the usermods folder as a template.
|
||||||
* Please remember to rename the class and file to a descriptive name.
|
* Please remember to rename the class and file to a descriptive name.
|
||||||
* You may also use multiple .h and .cpp files.
|
* You may also use multiple .h and .cpp files.
|
||||||
*
|
*
|
||||||
* Using a usermod:
|
* Using a usermod:
|
||||||
* 1. Copy the usermod into the sketch folder (same folder as wled00.ino)
|
* 1. Copy the usermod into the sketch folder (same folder as wled00.ino)
|
||||||
* 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:
|
public:
|
||||||
/**
|
/**
|
||||||
* constructor
|
* constructor
|
||||||
*/
|
*/
|
||||||
PIRsensorSwitch() {}
|
PIRsensorSwitch() {}
|
||||||
/**
|
/**
|
||||||
* desctructor
|
* desctructor
|
||||||
*/
|
*/
|
||||||
~PIRsensorSwitch() {}
|
~PIRsensorSwitch() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable/Disable the PIR sensor
|
* Enable/Disable the PIR sensor
|
||||||
*/
|
*/
|
||||||
void EnablePIRsensor(bool en) { enabled = en; }
|
void EnablePIRsensor(bool en) { enabled = en; }
|
||||||
/**
|
/**
|
||||||
* Get PIR sensor enabled/disabled state
|
* Get PIR sensor enabled/disabled state
|
||||||
*/
|
*/
|
||||||
bool PIRsensorEnabled() { return enabled; }
|
bool PIRsensorEnabled() { return enabled; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// PIR sensor pin
|
// PIR sensor pin
|
||||||
int8_t PIRsensorPin = PIR_SENSOR_PIN;
|
int8_t PIRsensorPin = PIR_SENSOR_PIN;
|
||||||
// notification mode for colorUpdated()
|
// notification mode for colorUpdated()
|
||||||
const byte NotifyUpdateMode = CALL_MODE_NO_NOTIFY; // CALL_MODE_DIRECT_CHANGE
|
const byte NotifyUpdateMode = CALL_MODE_NO_NOTIFY; // CALL_MODE_DIRECT_CHANGE
|
||||||
// delay before switch off after the sensor state goes LOW
|
// delay before switch off after the sensor state goes LOW
|
||||||
uint32_t m_switchOffDelay = 600000; // 10min
|
uint32_t m_switchOffDelay = 600000; // 10min
|
||||||
// off timer start time
|
// off timer start time
|
||||||
uint32_t m_offTimerStart = 0;
|
uint32_t m_offTimerStart = 0;
|
||||||
// current PIR sensor pin state
|
// current PIR sensor pin state
|
||||||
byte sensorPinState = LOW;
|
byte sensorPinState = LOW;
|
||||||
// PIR sensor enabled
|
// PIR sensor enabled
|
||||||
bool enabled = true;
|
bool enabled = true;
|
||||||
// status of initialisation
|
// status of initialisation
|
||||||
bool initDone = false;
|
bool initDone = false;
|
||||||
// on and off presets
|
// on and off presets
|
||||||
uint8_t m_onPreset = 0;
|
uint8_t m_onPreset = 0;
|
||||||
uint8_t m_offPreset = 0;
|
uint8_t m_offPreset = 0;
|
||||||
// flag to indicate that PIR sensor should activate WLED during nighttime only
|
// flag to indicate that PIR sensor should activate WLED during nighttime only
|
||||||
bool m_nightTimeOnly = false;
|
bool m_nightTimeOnly = false;
|
||||||
// flag to send MQTT message only (assuming it is enabled)
|
// flag to send MQTT message only (assuming it is enabled)
|
||||||
bool m_mqttOnly = false;
|
bool m_mqttOnly = false;
|
||||||
// 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 PIRtriggered = false;
|
bool PIRtriggered = false;
|
||||||
|
|
||||||
unsigned long lastLoop = 0;
|
unsigned long lastLoop = 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[];
|
||||||
static const char _switchOffDelay[];
|
static const char _switchOffDelay[];
|
||||||
static const char _enabled[];
|
static const char _enabled[];
|
||||||
static const char _onPreset[];
|
static const char _onPreset[];
|
||||||
static const char _offPreset[];
|
static const char _offPreset[];
|
||||||
static const char _nightTime[];
|
static const char _nightTime[];
|
||||||
static const char _mqttOnly[];
|
static const char _mqttOnly[];
|
||||||
static const char _offOnly[];
|
static const char _offOnly[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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() {
|
bool isDayTime() {
|
||||||
bool isDayTime = false;
|
bool isDayTime = false;
|
||||||
updateLocalTime();
|
updateLocalTime();
|
||||||
uint8_t hr = hour(localTime);
|
uint8_t hr = hour(localTime);
|
||||||
uint8_t mi = minute(localTime);
|
uint8_t mi = minute(localTime);
|
||||||
|
|
||||||
if (sunrise && sunset) {
|
if (sunrise && sunset) {
|
||||||
if (hour(sunrise)<hr && hour(sunset)>hr) {
|
if (hour(sunrise)<hr && hour(sunset)>hr) {
|
||||||
isDayTime = true;
|
isDayTime = true;
|
||||||
} else {
|
} else {
|
||||||
if (hour(sunrise)==hr && minute(sunrise)<mi) {
|
if (hour(sunrise)==hr && minute(sunrise)<mi) {
|
||||||
isDayTime = true;
|
isDayTime = true;
|
||||||
}
|
}
|
||||||
if (hour(sunset)==hr && minute(sunset)>mi) {
|
if (hour(sunset)==hr && minute(sunset)>mi) {
|
||||||
isDayTime = true;
|
isDayTime = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return isDayTime;
|
return isDayTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* switch strip on/off
|
* switch strip on/off
|
||||||
*/
|
*/
|
||||||
void switchStrip(bool switchOn)
|
void switchStrip(bool switchOn)
|
||||||
{
|
{
|
||||||
if (m_offOnly && bri && (switchOn || (!PIRtriggered && !switchOn))) return;
|
if (m_offOnly && bri && (switchOn || (!PIRtriggered && !switchOn))) return;
|
||||||
PIRtriggered = switchOn;
|
PIRtriggered = switchOn;
|
||||||
if (switchOn && m_onPreset) {
|
if (switchOn && m_onPreset) {
|
||||||
applyPreset(m_onPreset);
|
applyPreset(m_onPreset);
|
||||||
} else if (!switchOn && m_offPreset) {
|
} else if (!switchOn && m_offPreset) {
|
||||||
applyPreset(m_offPreset);
|
applyPreset(m_offPreset);
|
||||||
} else if (switchOn && bri == 0) {
|
} else 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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void publishMqtt(const char* state)
|
void publishMqtt(const char* state)
|
||||||
{
|
{
|
||||||
//Check if MQTT Connected, otherwise it will crash the 8266
|
//Check if MQTT Connected, otherwise it will crash the 8266
|
||||||
if (WLED_MQTT_CONNECTED){
|
if (WLED_MQTT_CONNECTED){
|
||||||
char subuf[64];
|
char subuf[64];
|
||||||
strcpy(subuf, mqttDeviceTopic);
|
strcpy(subuf, mqttDeviceTopic);
|
||||||
strcat_P(subuf, PSTR("/motion"));
|
strcat_P(subuf, PSTR("/motion"));
|
||||||
mqtt->publish(subuf, 0, false, state);
|
mqtt->publish(subuf, 0, false, state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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);
|
bool pinState = digitalRead(PIRsensorPin);
|
||||||
if (pinState != sensorPinState) {
|
if (pinState != sensorPinState) {
|
||||||
sensorPinState = pinState; // change previous state
|
sensorPinState = pinState; // change previous state
|
||||||
|
|
||||||
if (sensorPinState == HIGH) {
|
if (sensorPinState == HIGH) {
|
||||||
m_offTimerStart = 0;
|
m_offTimerStart = 0;
|
||||||
if (!m_mqttOnly && (!m_nightTimeOnly || (m_nightTimeOnly && !isDayTime()))) switchStrip(true);
|
if (!m_mqttOnly && (!m_nightTimeOnly || (m_nightTimeOnly && !isDayTime()))) switchStrip(true);
|
||||||
publishMqtt("on");
|
publishMqtt("on");
|
||||||
} else /*if (bri != 0)*/ {
|
} else /*if (bri != 0)*/ {
|
||||||
// start switch off timer
|
// start switch off timer
|
||||||
m_offTimerStart = millis();
|
m_offTimerStart = millis();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
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_offTimerStart > 0 && millis() - m_offTimerStart > m_switchOffDelay)
|
||||||
{
|
{
|
||||||
if (enabled == true)
|
if (enabled == true)
|
||||||
{
|
{
|
||||||
if (!m_mqttOnly && (!m_nightTimeOnly || (m_nightTimeOnly && !isDayTime()))) switchStrip(false);
|
if (!m_mqttOnly && (!m_nightTimeOnly || (m_nightTimeOnly && !isDayTime()))) switchStrip(false);
|
||||||
publishMqtt("off");
|
publishMqtt("off");
|
||||||
}
|
}
|
||||||
m_offTimerStart = 0;
|
m_offTimerStart = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return 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()
|
||||||
{
|
{
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
// 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 (PIRsensorPin >= 0 && pinManager.allocatePin(PIRsensorPin, false, PinOwner::UM_PIR)) {
|
||||||
// PIR Sensor mode INPUT_PULLUP
|
// PIR Sensor mode INPUT_PULLUP
|
||||||
pinMode(PIRsensorPin, INPUT_PULLUP);
|
pinMode(PIRsensorPin, INPUT_PULLUP);
|
||||||
sensorPinState = digitalRead(PIRsensorPin);
|
sensorPinState = digitalRead(PIRsensorPin);
|
||||||
} else {
|
} else {
|
||||||
if (PIRsensorPin >= 0) {
|
if (PIRsensorPin >= 0) {
|
||||||
DEBUG_PRINTLN(F("PIRSensorSwitch pin allocation failed."));
|
DEBUG_PRINTLN(F("PIRSensorSwitch pin allocation failed."));
|
||||||
}
|
}
|
||||||
PIRsensorPin = -1; // allocation failed
|
PIRsensorPin = -1; // allocation failed
|
||||||
enabled = false;
|
enabled = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
initDone = true;
|
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()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
// only check sensors 4x/s
|
||||||
if (!enabled || millis() - lastLoop < 250 || strip.isUpdating()) return;
|
if (!enabled || millis() - lastLoop < 250 || strip.isUpdating()) return;
|
||||||
lastLoop = millis();
|
lastLoop = millis();
|
||||||
|
|
||||||
if (!updatePIRsensorState()) {
|
if (!updatePIRsensorState()) {
|
||||||
handleOffTimer();
|
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"];
|
JsonObject user = root["u"];
|
||||||
if (user.isNull()) user = root.createNestedObject("u");
|
if (user.isNull()) user = root.createNestedObject("u");
|
||||||
|
|
||||||
if (enabled)
|
if (enabled)
|
||||||
{
|
{
|
||||||
// off timer
|
// off timer
|
||||||
String uiDomString = F("PIR <i class=\"icons\"></i>");
|
String uiDomString = F("PIR <i class=\"icons\"></i>");
|
||||||
JsonArray infoArr = user.createNestedArray(uiDomString); // timer value
|
JsonArray infoArr = user.createNestedArray(uiDomString); // timer value
|
||||||
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 += 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(sensorPinState ? F("sensor on") : F("inactive"));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
String uiDomString = F("PIR sensor");
|
String uiDomString = F("PIR sensor");
|
||||||
JsonArray infoArr = user.createNestedArray(uiDomString);
|
JsonArray infoArr = user.createNestedArray(uiDomString);
|
||||||
infoArr.add(F("disabled"));
|
infoArr.add(F("disabled"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* provide the changeable values
|
* provide the changeable values
|
||||||
*/
|
*/
|
||||||
void addToConfig(JsonObject &root)
|
void 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;
|
top["pin"] = PIRsensorPin;
|
||||||
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;
|
||||||
top[FPSTR(_mqttOnly)] = m_mqttOnly;
|
top[FPSTR(_mqttOnly)] = m_mqttOnly;
|
||||||
top[FPSTR(_offOnly)] = m_offOnly;
|
top[FPSTR(_offOnly)] = m_offOnly;
|
||||||
DEBUG_PRINTLN(F("PIR config saved."));
|
DEBUG_PRINTLN(F("PIR config saved."));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* restore the changeable values
|
* restore the changeable values
|
||||||
* readFromConfig() is called before setup() to populate properties from values stored in cfg.json
|
* readFromConfig() is called before setup() to populate properties from values stored in cfg.json
|
||||||
*
|
*
|
||||||
* The function should return true if configuration was successfully loaded or false if there was no configuration.
|
* The function should return true if configuration was successfully loaded or false if there was no configuration.
|
||||||
*/
|
*/
|
||||||
bool readFromConfig(JsonObject &root)
|
bool readFromConfig(JsonObject &root)
|
||||||
{
|
{
|
||||||
bool oldEnabled = enabled;
|
bool oldEnabled = enabled;
|
||||||
int8_t oldPin = PIRsensorPin;
|
int8_t oldPin = PIRsensorPin;
|
||||||
|
|
||||||
JsonObject top = root[FPSTR(_name)];
|
JsonObject top = root[FPSTR(_name)];
|
||||||
if (top.isNull()) {
|
if (top.isNull()) {
|
||||||
DEBUG_PRINT(FPSTR(_name));
|
DEBUG_PRINT(FPSTR(_name));
|
||||||
DEBUG_PRINTLN(F(": No config found. (Using defaults.)"));
|
DEBUG_PRINTLN(F(": No config found. (Using defaults.)"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
PIRsensorPin = top["pin"] | PIRsensorPin;
|
PIRsensorPin = top["pin"] | PIRsensorPin;
|
||||||
|
|
||||||
enabled = top[FPSTR(_enabled)] | enabled;
|
enabled = top[FPSTR(_enabled)] | enabled;
|
||||||
|
|
||||||
m_switchOffDelay = (top[FPSTR(_switchOffDelay)] | m_switchOffDelay/1000) * 1000;
|
m_switchOffDelay = (top[FPSTR(_switchOffDelay)] | m_switchOffDelay/1000) * 1000;
|
||||||
|
|
||||||
m_onPreset = top[FPSTR(_onPreset)] | m_onPreset;
|
m_onPreset = top[FPSTR(_onPreset)] | m_onPreset;
|
||||||
m_onPreset = max(0,min(250,(int)m_onPreset));
|
m_onPreset = max(0,min(250,(int)m_onPreset));
|
||||||
|
|
||||||
m_offPreset = top[FPSTR(_offPreset)] | m_offPreset;
|
m_offPreset = top[FPSTR(_offPreset)] | m_offPreset;
|
||||||
m_offPreset = max(0,min(250,(int)m_offPreset));
|
m_offPreset = max(0,min(250,(int)m_offPreset));
|
||||||
|
|
||||||
m_nightTimeOnly = top[FPSTR(_nightTime)] | m_nightTimeOnly;
|
m_nightTimeOnly = top[FPSTR(_nightTime)] | m_nightTimeOnly;
|
||||||
m_mqttOnly = top[FPSTR(_mqttOnly)] | m_mqttOnly;
|
m_mqttOnly = top[FPSTR(_mqttOnly)] | m_mqttOnly;
|
||||||
m_offOnly = top[FPSTR(_offOnly)] | m_offOnly;
|
m_offOnly = top[FPSTR(_offOnly)] | m_offOnly;
|
||||||
|
|
||||||
DEBUG_PRINT(FPSTR(_name));
|
DEBUG_PRINT(FPSTR(_name));
|
||||||
if (!initDone) {
|
if (!initDone) {
|
||||||
// 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) {
|
if (oldPin != PIRsensorPin || oldEnabled != enabled) {
|
||||||
// check if pin is OK
|
// check if pin is OK
|
||||||
if (oldPin != PIRsensorPin && oldPin >= 0) {
|
if (oldPin != PIRsensorPin && oldPin >= 0) {
|
||||||
// if we are changing pin in settings page
|
// if we are changing pin in settings page
|
||||||
// deallocate old pin
|
// deallocate old pin
|
||||||
pinManager.deallocatePin(oldPin, PinOwner::UM_PIR);
|
pinManager.deallocatePin(oldPin, PinOwner::UM_PIR);
|
||||||
if (pinManager.allocatePin(PIRsensorPin, false, PinOwner::UM_PIR)) {
|
if (pinManager.allocatePin(PIRsensorPin, false, PinOwner::UM_PIR)) {
|
||||||
pinMode(PIRsensorPin, INPUT_PULLUP);
|
pinMode(PIRsensorPin, INPUT_PULLUP);
|
||||||
} else {
|
} else {
|
||||||
// allocation failed
|
// allocation failed
|
||||||
PIRsensorPin = -1;
|
PIRsensorPin = -1;
|
||||||
enabled = false;
|
enabled = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
sensorPinState = digitalRead(PIRsensorPin);
|
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(_offOnly)].isNull();
|
return !top[FPSTR(_offOnly)].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)
|
||||||
const char PIRsensorSwitch::_name[] PROGMEM = "PIRsensorSwitch";
|
const char PIRsensorSwitch::_name[] PROGMEM = "PIRsensorSwitch";
|
||||||
const char PIRsensorSwitch::_enabled[] PROGMEM = "PIRenabled";
|
const char PIRsensorSwitch::_enabled[] PROGMEM = "PIRenabled";
|
||||||
const char PIRsensorSwitch::_switchOffDelay[] PROGMEM = "PIRoffSec";
|
const char PIRsensorSwitch::_switchOffDelay[] PROGMEM = "PIRoffSec";
|
||||||
const char PIRsensorSwitch::_onPreset[] PROGMEM = "on-preset";
|
const char PIRsensorSwitch::_onPreset[] PROGMEM = "on-preset";
|
||||||
const char PIRsensorSwitch::_offPreset[] PROGMEM = "off-preset";
|
const char PIRsensorSwitch::_offPreset[] PROGMEM = "off-preset";
|
||||||
const char PIRsensorSwitch::_nightTime[] PROGMEM = "nighttime-only";
|
const char PIRsensorSwitch::_nightTime[] PROGMEM = "nighttime-only";
|
||||||
const char PIRsensorSwitch::_mqttOnly[] PROGMEM = "mqtt-only";
|
const char PIRsensorSwitch::_mqttOnly[] PROGMEM = "mqtt-only";
|
||||||
const char PIRsensorSwitch::_offOnly[] PROGMEM = "off-only";
|
const char PIRsensorSwitch::_offOnly[] PROGMEM = "off-only";
|
||||||
|
@ -81,7 +81,9 @@ class UsermodTemperature : public Usermod {
|
|||||||
temperature = readDallas();
|
temperature = readDallas();
|
||||||
lastMeasurement = millis();
|
lastMeasurement = millis();
|
||||||
waitingForConversion = false;
|
waitingForConversion = false;
|
||||||
DEBUG_PRINTF("Read temperature %2.1f.\n", temperature);
|
//DEBUG_PRINTF("Read temperature %2.1f.\n", temperature); // does not work properly on 8266
|
||||||
|
DEBUG_PRINT(F("Read temperature "));
|
||||||
|
DEBUG_PRINTLN(temperature);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool findSensor() {
|
bool findSensor() {
|
||||||
|
@ -317,15 +317,15 @@ class MultiRelay : public Usermod {
|
|||||||
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
|
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
|
||||||
* Values in the state object may be modified by connected clients
|
* Values in the state object may be modified by connected clients
|
||||||
*/
|
*/
|
||||||
void addToJsonState(JsonObject &root) {
|
//void 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) {
|
||||||
}
|
//}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* provide the changeable values
|
* provide the changeable values
|
||||||
@ -335,11 +335,12 @@ class MultiRelay : public Usermod {
|
|||||||
|
|
||||||
top[FPSTR(_enabled)] = enabled;
|
top[FPSTR(_enabled)] = enabled;
|
||||||
for (uint8_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
for (uint8_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||||
String parName = FPSTR(_relay_str); parName += "-"; parName += i; parName += "-";
|
String parName = FPSTR(_relay_str); parName += '-'; parName += i;
|
||||||
top[parName+"pin"] = _relay[i].pin;
|
JsonObject relay = top.createNestedObject(parName);
|
||||||
top[parName+FPSTR(_activeHigh)] = _relay[i].mode;
|
relay["pin"] = _relay[i].pin;
|
||||||
top[parName+FPSTR(_delay_str)] = _relay[i].delay;
|
relay[FPSTR(_activeHigh)] = _relay[i].mode;
|
||||||
top[parName+FPSTR(_external)] = _relay[i].external;
|
relay[FPSTR(_delay_str)] = _relay[i].delay;
|
||||||
|
relay[FPSTR(_external)] = _relay[i].external;
|
||||||
}
|
}
|
||||||
DEBUG_PRINTLN(F("MultiRelay config saved."));
|
DEBUG_PRINTLN(F("MultiRelay config saved."));
|
||||||
}
|
}
|
||||||
@ -363,12 +364,19 @@ class MultiRelay : public Usermod {
|
|||||||
enabled = top[FPSTR(_enabled)] | enabled;
|
enabled = top[FPSTR(_enabled)] | enabled;
|
||||||
|
|
||||||
for (uint8_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
for (uint8_t i=0; i<MULTI_RELAY_MAX_RELAYS; i++) {
|
||||||
String parName = FPSTR(_relay_str); parName += "-"; parName += i; parName += "-";
|
String parName = FPSTR(_relay_str); parName += '-'; parName += i;
|
||||||
oldPin[i] = _relay[i].pin;
|
oldPin[i] = _relay[i].pin;
|
||||||
|
_relay[i].pin = top[parName]["pin"] | _relay[i].pin;
|
||||||
|
_relay[i].mode = top[parName][FPSTR(_activeHigh)] | _relay[i].mode;
|
||||||
|
_relay[i].external = top[parName][FPSTR(_external)] | _relay[i].external;
|
||||||
|
_relay[i].delay = top[parName][FPSTR(_delay_str)] | _relay[i].delay;
|
||||||
|
// begin backwards compatibility (beta) remove when 0.13 is released
|
||||||
|
parName += '-';
|
||||||
_relay[i].pin = top[parName+"pin"] | _relay[i].pin;
|
_relay[i].pin = top[parName+"pin"] | _relay[i].pin;
|
||||||
_relay[i].mode = top[parName+FPSTR(_activeHigh)] | _relay[i].mode;
|
_relay[i].mode = top[parName+FPSTR(_activeHigh)] | _relay[i].mode;
|
||||||
_relay[i].external = top[parName+FPSTR(_external)] | _relay[i].external;
|
_relay[i].external = top[parName+FPSTR(_external)] | _relay[i].external;
|
||||||
_relay[i].delay = top[parName+FPSTR(_delay_str)] | _relay[i].delay;
|
_relay[i].delay = top[parName+FPSTR(_delay_str)] | _relay[i].delay;
|
||||||
|
// end compatibility
|
||||||
_relay[i].delay = min(600,max(0,abs((int)_relay[i].delay))); // bounds checking max 10min
|
_relay[i].delay = min(600,max(0,abs((int)_relay[i].delay))); // bounds checking max 10min
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -396,7 +404,7 @@ class MultiRelay : public Usermod {
|
|||||||
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 true;
|
return !top[F("relay-0")]["pin"].isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -114,6 +114,7 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
U8X8 *u8x8 = nullptr; // pointer to U8X8 display object
|
U8X8 *u8x8 = nullptr; // pointer to U8X8 display object
|
||||||
#ifndef FLD_SPI_DEFAULT
|
#ifndef FLD_SPI_DEFAULT
|
||||||
int8_t ioPin[5] = {FLD_PIN_SCL, FLD_PIN_SDA, -1, -1, -1}; // I2C pins: SCL, SDA
|
int8_t ioPin[5] = {FLD_PIN_SCL, FLD_PIN_SDA, -1, -1, -1}; // I2C pins: SCL, SDA
|
||||||
|
uint32_t ioFrequency = 400000; // in Hz (minimum is 100000, baseline is 400000 and maximum should be 3400000)
|
||||||
DisplayType type = SSD1306; // display type
|
DisplayType type = SSD1306; // display type
|
||||||
#else
|
#else
|
||||||
int8_t ioPin[5] = {FLD_PIN_CLOCKSPI, FLD_PIN_DATASPI, FLD_PIN_CS, FLD_PIN_DC, FLD_PIN_RESET}; // SPI pins: CLK, MOSI, CS, DC, RST
|
int8_t ioPin[5] = {FLD_PIN_CLOCKSPI, FLD_PIN_DATASPI, FLD_PIN_CS, FLD_PIN_DC, FLD_PIN_RESET}; // SPI pins: CLK, MOSI, CS, DC, RST
|
||||||
@ -155,6 +156,7 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
static const char _flip[];
|
static const char _flip[];
|
||||||
static const char _sleepMode[];
|
static const char _sleepMode[];
|
||||||
static const char _clockMode[];
|
static const char _clockMode[];
|
||||||
|
static const char _busClkFrequency[];
|
||||||
|
|
||||||
// If display does not work or looks corrupted check the
|
// If display does not work or looks corrupted check the
|
||||||
// constructor reference:
|
// constructor reference:
|
||||||
@ -248,6 +250,7 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
|
|
||||||
initDone = true;
|
initDone = true;
|
||||||
DEBUG_PRINTLN(F("Starting display."));
|
DEBUG_PRINTLN(F("Starting display."));
|
||||||
|
if (!(type == SSD1306_SPI || type == SSD1306_SPI64)) u8x8->setBusClock(ioFrequency); // can be used for SPI too
|
||||||
u8x8->begin();
|
u8x8->begin();
|
||||||
setFlipMode(flip);
|
setFlipMode(flip);
|
||||||
setContrast(contrast); //Contrast setup will help to preserve OLED lifetime. In case OLED need to be brighter increase number up to 255
|
setContrast(contrast); //Contrast setup will help to preserve OLED lifetime. In case OLED need to be brighter increase number up to 255
|
||||||
@ -683,6 +686,7 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
top[FPSTR(_screenTimeOut)] = screenTimeout/1000;
|
top[FPSTR(_screenTimeOut)] = screenTimeout/1000;
|
||||||
top[FPSTR(_sleepMode)] = (bool) sleepMode;
|
top[FPSTR(_sleepMode)] = (bool) sleepMode;
|
||||||
top[FPSTR(_clockMode)] = (bool) clockMode;
|
top[FPSTR(_clockMode)] = (bool) clockMode;
|
||||||
|
top[FPSTR(_busClkFrequency)] = ioFrequency/1000;
|
||||||
DEBUG_PRINTLN(F("4 Line Display config saved."));
|
DEBUG_PRINTLN(F("4 Line Display config saved."));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -714,6 +718,7 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
screenTimeout = (top[FPSTR(_screenTimeOut)] | screenTimeout/1000) * 1000;
|
screenTimeout = (top[FPSTR(_screenTimeOut)] | screenTimeout/1000) * 1000;
|
||||||
sleepMode = top[FPSTR(_sleepMode)] | sleepMode;
|
sleepMode = top[FPSTR(_sleepMode)] | sleepMode;
|
||||||
clockMode = top[FPSTR(_clockMode)] | clockMode;
|
clockMode = top[FPSTR(_clockMode)] | clockMode;
|
||||||
|
ioFrequency = min(3400, max(100, (int)(top[FPSTR(_busClkFrequency)] | ioFrequency/1000))) * 1000; // limit frequency
|
||||||
|
|
||||||
DEBUG_PRINT(FPSTR(_name));
|
DEBUG_PRINT(FPSTR(_name));
|
||||||
if (!initDone) {
|
if (!initDone) {
|
||||||
@ -739,12 +744,13 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
setup();
|
setup();
|
||||||
needsRedraw |= true;
|
needsRedraw |= true;
|
||||||
}
|
}
|
||||||
|
if (!(type == SSD1306_SPI || type == SSD1306_SPI64)) u8x8->setBusClock(ioFrequency); // can be used for SPI too
|
||||||
setContrast(contrast);
|
setContrast(contrast);
|
||||||
setFlipMode(flip);
|
setFlipMode(flip);
|
||||||
if (needsRedraw && !wakeDisplay()) redraw(true);
|
if (needsRedraw && !wakeDisplay()) redraw(true);
|
||||||
}
|
}
|
||||||
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||||
return !(top["pin"][2]).isNull();
|
return !(top[_busClkFrequency]).isNull();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -757,10 +763,11 @@ class FourLineDisplayUsermod : public Usermod {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// strings to reduce flash memory usage (used more than twice)
|
// strings to reduce flash memory usage (used more than twice)
|
||||||
const char FourLineDisplayUsermod::_name[] PROGMEM = "4LineDisplay";
|
const char FourLineDisplayUsermod::_name[] PROGMEM = "4LineDisplay";
|
||||||
const char FourLineDisplayUsermod::_contrast[] PROGMEM = "contrast";
|
const char FourLineDisplayUsermod::_contrast[] PROGMEM = "contrast";
|
||||||
const char FourLineDisplayUsermod::_refreshRate[] PROGMEM = "refreshRateSec";
|
const char FourLineDisplayUsermod::_refreshRate[] PROGMEM = "refreshRateSec";
|
||||||
const char FourLineDisplayUsermod::_screenTimeOut[] PROGMEM = "screenTimeOutSec";
|
const char FourLineDisplayUsermod::_screenTimeOut[] PROGMEM = "screenTimeOutSec";
|
||||||
const char FourLineDisplayUsermod::_flip[] PROGMEM = "flip";
|
const char FourLineDisplayUsermod::_flip[] PROGMEM = "flip";
|
||||||
const char FourLineDisplayUsermod::_sleepMode[] PROGMEM = "sleepMode";
|
const char FourLineDisplayUsermod::_sleepMode[] PROGMEM = "sleepMode";
|
||||||
const char FourLineDisplayUsermod::_clockMode[] PROGMEM = "clockMode";
|
const char FourLineDisplayUsermod::_clockMode[] PROGMEM = "clockMode";
|
||||||
|
const char FourLineDisplayUsermod::_busClkFrequency[] PROGMEM = "i2c-freq-kHz";
|
||||||
|
@ -4,18 +4,6 @@
|
|||||||
#ifdef WLED_USE_ETHERNET
|
#ifdef WLED_USE_ETHERNET
|
||||||
#include "pin_manager.h"
|
#include "pin_manager.h"
|
||||||
|
|
||||||
// The following six pins are neither configurable nor
|
|
||||||
// can they be re-assigned through IOMUX / GPIO matrix.
|
|
||||||
// See https://docs.espressif.com/projects/esp-idf/en/latest/esp32/hw-reference/esp32/get-started-ethernet-kit-v1.1.html#ip101gri-phy-interface
|
|
||||||
const managed_pin_type esp32_nonconfigurable_ethernet_pins[6] = {
|
|
||||||
{ 21, true }, // RMII EMAC TX EN == When high, clocks the data on TXD0 and TXD1 to transmitter
|
|
||||||
{ 19, true }, // RMII EMAC TXD0 == First bit of transmitted data
|
|
||||||
{ 22, true }, // RMII EMAC TXD1 == Second bit of transmitted data
|
|
||||||
{ 25, false }, // RMII EMAC RXD0 == First bit of received data
|
|
||||||
{ 26, false }, // RMII EMAC RXD1 == Second bit of received data
|
|
||||||
{ 27, true }, // RMII EMAC CRS_DV == Carrier Sense and RX Data Valid
|
|
||||||
};
|
|
||||||
|
|
||||||
// For ESP32, the remaining five pins are at least somewhat configurable.
|
// For ESP32, the remaining five pins are at least somewhat configurable.
|
||||||
// eth_address is in range [0..31], indicates which PHY (MAC?) address should be allocated to the interface
|
// eth_address is in range [0..31], indicates which PHY (MAC?) address should be allocated to the interface
|
||||||
// eth_power is an output GPIO pin used to enable/disable the ethernet port (and/or external oscillator)
|
// eth_power is an output GPIO pin used to enable/disable the ethernet port (and/or external oscillator)
|
||||||
@ -37,15 +25,16 @@ typedef struct EthernetSettings {
|
|||||||
eth_clock_mode_t eth_clk_mode;
|
eth_clock_mode_t eth_clk_mode;
|
||||||
} ethernet_settings;
|
} ethernet_settings;
|
||||||
|
|
||||||
ethernet_settings ethernetBoards[] = {
|
const ethernet_settings ethernetBoards[] = {
|
||||||
// None
|
// None
|
||||||
{
|
{
|
||||||
},
|
},
|
||||||
|
|
||||||
// WT32-EHT01
|
// WT32-EHT01
|
||||||
// (*) NOTE: silkscreen on board revision v1.2 may be wrong:
|
// Please note, from my testing only these pins work for LED outputs:
|
||||||
// silkscreen on v1.2 says IO35, but appears to be IO5
|
// IO2, IO4, IO12, IO14, IO15
|
||||||
// silkscreen on v1.2 says RXD, and appears to be IO35
|
// These pins do not appear to work from my testing:
|
||||||
|
// IO35, IO36, IO39
|
||||||
{
|
{
|
||||||
1, // eth_address,
|
1, // eth_address,
|
||||||
16, // eth_power,
|
16, // eth_power,
|
||||||
@ -97,14 +86,27 @@ ethernet_settings ethernetBoards[] = {
|
|||||||
|
|
||||||
// ESP3DEUXQuattro
|
// ESP3DEUXQuattro
|
||||||
{
|
{
|
||||||
1, // eth_address,
|
1, // eth_address,
|
||||||
-1, // eth_power,
|
-1, // eth_power,
|
||||||
23, // eth_mdc,
|
23, // eth_mdc,
|
||||||
18, // eth_mdio,
|
18, // eth_mdio,
|
||||||
ETH_PHY_LAN8720, // eth_type,
|
ETH_PHY_LAN8720, // eth_type,
|
||||||
ETH_CLOCK_GPIO17_OUT // eth_clk_mode
|
ETH_CLOCK_GPIO17_OUT // eth_clk_mode
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define WLED_ETH_RSVD_PINS_COUNT 6
|
||||||
|
// The following six pins are neither configurable nor
|
||||||
|
// can they be re-assigned through IOMUX / GPIO matrix.
|
||||||
|
// See https://docs.espressif.com/projects/esp-idf/en/latest/esp32/hw-reference/esp32/get-started-ethernet-kit-v1.1.html#ip101gri-phy-interface
|
||||||
|
const managed_pin_type esp32_nonconfigurable_ethernet_pins[WLED_ETH_RSVD_PINS_COUNT] = {
|
||||||
|
{ 21, true }, // RMII EMAC TX EN == When high, clocks the data on TXD0 and TXD1 to transmitter
|
||||||
|
{ 19, true }, // RMII EMAC TXD0 == First bit of transmitted data
|
||||||
|
{ 22, true }, // RMII EMAC TXD1 == Second bit of transmitted data
|
||||||
|
{ 25, false }, // RMII EMAC RXD0 == First bit of received data
|
||||||
|
{ 26, false }, // RMII EMAC RXD1 == Second bit of received data
|
||||||
|
{ 27, true }, // RMII EMAC CRS_DV == Carrier Sense and RX Data Valid
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
129
wled00/xml.cpp
129
wled00/xml.cpp
@ -1,4 +1,5 @@
|
|||||||
#include "wled.h"
|
#include "wled.h"
|
||||||
|
#include "wled_ethernet.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Sending XML status files to client
|
* Sending XML status files to client
|
||||||
@ -186,6 +187,52 @@ void sappends(char stype, const char* key, char* val)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void extractPin(JsonObject &obj, const char *key) {
|
||||||
|
if (obj[key].is<JsonArray>()) {
|
||||||
|
JsonArray pins = obj[key].as<JsonArray>();
|
||||||
|
for (JsonVariant pv : pins) {
|
||||||
|
if (pv.as<int>() > -1) { oappend(","); oappendi(pv.as<int>()); }
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (obj[key].as<int>() > -1) { oappend(","); oappendi(obj[key].as<int>()); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// oappens used pins by scanning JsonObject (1 level deep)
|
||||||
|
void fillUMPins(JsonObject &mods)
|
||||||
|
{
|
||||||
|
for (JsonPair kv : mods) {
|
||||||
|
// kv.key() is usermod name or subobject key
|
||||||
|
// kv.value() is object itself
|
||||||
|
JsonObject obj = kv.value();
|
||||||
|
if (!obj.isNull()) {
|
||||||
|
// element is an JsonObject
|
||||||
|
if (!obj["pin"].isNull()) {
|
||||||
|
extractPin(obj, "pin");
|
||||||
|
} else {
|
||||||
|
// scan keys (just one level deep as is possible with usermods)
|
||||||
|
for (JsonPair so : obj) {
|
||||||
|
const char *key = so.key().c_str();
|
||||||
|
if (strstr(key, "pin")) {
|
||||||
|
// we found a key containing "pin" substring
|
||||||
|
if (strlen(strstr(key, "pin")) == 3) {
|
||||||
|
// and it is at the end, we found another pin
|
||||||
|
extractPin(obj, key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!obj[so.key()].is<JsonObject>()) continue;
|
||||||
|
JsonObject subObj = obj[so.key()];
|
||||||
|
if (!subObj["pin"].isNull()) {
|
||||||
|
// get pins from subobject
|
||||||
|
extractPin(subObj, "pin");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//get values for settings form in javascript
|
//get values for settings form in javascript
|
||||||
void getSettingsJS(byte subPage, char* dest)
|
void getSettingsJS(byte subPage, char* dest)
|
||||||
@ -198,7 +245,8 @@ void getSettingsJS(byte subPage, char* dest)
|
|||||||
|
|
||||||
if (subPage <1 || subPage >8) return;
|
if (subPage <1 || subPage >8) return;
|
||||||
|
|
||||||
if (subPage == 1) {
|
if (subPage == 1)
|
||||||
|
{
|
||||||
sappends('s',SET_F("CS"),clientSSID);
|
sappends('s',SET_F("CS"),clientSSID);
|
||||||
|
|
||||||
byte l = strlen(clientPass);
|
byte l = strlen(clientPass);
|
||||||
@ -264,50 +312,53 @@ void getSettingsJS(byte subPage, char* dest)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (subPage == 2) {
|
if (subPage == 2)
|
||||||
|
{
|
||||||
char nS[8];
|
char nS[8];
|
||||||
|
|
||||||
// add reserved and usermod pins as d.um_p array
|
// add reserved and usermod pins as d.um_p array
|
||||||
|
oappend(SET_F("d.um_p=[6,7,8,9,10,11"));
|
||||||
|
|
||||||
DynamicJsonDocument doc(JSON_BUFFER_SIZE/2);
|
DynamicJsonDocument doc(JSON_BUFFER_SIZE/2);
|
||||||
JsonObject mods = doc.createNestedObject(F("um"));
|
JsonObject mods = doc.createNestedObject(F("um"));
|
||||||
usermods.addToConfig(mods);
|
usermods.addToConfig(mods);
|
||||||
oappend(SET_F("d.um_p=["));
|
if (!mods.isNull()) fillUMPins(mods);
|
||||||
if (!mods.isNull()) {
|
|
||||||
uint8_t i=0;
|
#ifdef WLED_ENABLE_DMX
|
||||||
for (JsonPair kv : mods) {
|
oappend(SET_F(",2")); // DMX hardcoded pin
|
||||||
if (!kv.value().isNull()) {
|
#endif
|
||||||
// element is an JsonObject
|
|
||||||
JsonObject obj = kv.value();
|
//Note: Using pin 3 (RX) disables Adalight / Serial JSON
|
||||||
if (obj["pin"] != nullptr) {
|
|
||||||
if (obj["pin"].is<JsonArray>()) {
|
#ifdef WLED_DEBUG
|
||||||
JsonArray pins = obj["pin"].as<JsonArray>();
|
oappend(SET_F(",1")); // debug output (TX) pin
|
||||||
for (JsonVariant pv : pins) {
|
#endif
|
||||||
if (i++) oappend(SET_F(","));
|
|
||||||
oappendi(pv.as<int>());
|
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
|
||||||
}
|
if (psramFound()) oappend(SET_F(",16,17")); // GPIO16 & GPIO17 reserved for SPI RAM
|
||||||
} else {
|
#endif
|
||||||
if (i++) oappend(SET_F(","));
|
|
||||||
oappendi(obj["pin"].as<int>());
|
#ifdef WLED_USE_ETHERNET
|
||||||
}
|
if (ethernetType != WLED_ETH_NONE && ethernetType < WLED_NUM_ETH_TYPES) {
|
||||||
}
|
for (uint8_t p=0; p<WLED_ETH_RSVD_PINS_COUNT; p++) { oappend(","); oappend(itoa(esp32_nonconfigurable_ethernet_pins[p].pin,nS,10)); }
|
||||||
}
|
if (ethernetBoards[ethernetType].eth_power>=0) { oappend(","); oappend(itoa(ethernetBoards[ethernetType].eth_power,nS,10)); }
|
||||||
|
if (ethernetBoards[ethernetType].eth_mdc>=0) { oappend(","); oappend(itoa(ethernetBoards[ethernetType].eth_mdc,nS,10)); }
|
||||||
|
if (ethernetBoards[ethernetType].eth_mdio>=0) { oappend(","); oappend(itoa(ethernetBoards[ethernetType].eth_mdio,nS,10)); }
|
||||||
|
switch (ethernetBoards[ethernetType].eth_clk_mode) {
|
||||||
|
case ETH_CLOCK_GPIO0_IN:
|
||||||
|
case ETH_CLOCK_GPIO0_OUT:
|
||||||
|
oappend(SET_F(",0"));
|
||||||
|
break;
|
||||||
|
case ETH_CLOCK_GPIO16_OUT:
|
||||||
|
oappend(SET_F(",16"));
|
||||||
|
break;
|
||||||
|
case ETH_CLOCK_GPIO17_OUT:
|
||||||
|
oappend(SET_F(",17"));
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (i) oappend(SET_F(","));
|
|
||||||
oappend(SET_F("6,7,8,9,10,11")); // flash memory pins
|
|
||||||
#ifdef WLED_ENABLE_DMX
|
|
||||||
oappend(SET_F(",2")); // DMX hardcoded pin
|
|
||||||
#endif
|
|
||||||
//Adalight / Serial in requires pin 3 to be unused. However, Serial input can not be prevented by WLED
|
|
||||||
#ifdef WLED_DEBUG
|
|
||||||
oappend(SET_F(",1")); // debug output (TX) pin
|
|
||||||
#endif
|
|
||||||
#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_PSRAM)
|
|
||||||
if (psramFound()) oappend(SET_F(",16,17")); // GPIO16 & GPIO17 reserved for SPI RAM
|
|
||||||
#endif
|
|
||||||
//TODO: add reservations for Ethernet shield pins
|
|
||||||
#ifdef WLED_USE_ETHERNET
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
oappend(SET_F("];"));
|
oappend(SET_F("];"));
|
||||||
|
|
||||||
// set limits
|
// set limits
|
||||||
@ -338,9 +389,9 @@ void getSettingsJS(byte subPage, char* dest)
|
|||||||
uint8_t nPins = bus->getPins(pins);
|
uint8_t nPins = bus->getPins(pins);
|
||||||
for (uint8_t i = 0; i < nPins; i++) {
|
for (uint8_t i = 0; i < nPins; i++) {
|
||||||
lp[1] = 48+i;
|
lp[1] = 48+i;
|
||||||
if (pinManager.isPinOk(pins[i])) sappend('v', lp, pins[i]);
|
if (pinManager.isPinOk(pins[i])) sappend('v',lp,pins[i]);
|
||||||
}
|
}
|
||||||
sappend('v', lc, bus->getLength());
|
sappend('v',lc,bus->getLength());
|
||||||
sappend('v',lt,bus->getType());
|
sappend('v',lt,bus->getType());
|
||||||
sappend('v',co,bus->getColorOrder());
|
sappend('v',co,bus->getColorOrder());
|
||||||
sappend('v',ls,bus->getStart());
|
sappend('v',ls,bus->getStart());
|
||||||
|
Loading…
Reference in New Issue
Block a user