Merge pull request #4623 from willmmiles/more-usermod-fixes

More usermod fixes
This commit is contained in:
netmindz 2025-04-30 18:55:36 +00:00 committed by GitHub
commit d10714d1c1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
79 changed files with 877 additions and 833 deletions

View File

@ -1,5 +1,5 @@
{
"name:": "ADS1115_v2",
"name": "ADS1115_v2",
"dependencies": {
"Adafruit BusIO": "https://github.com/adafruit/Adafruit_BusIO#1.13.2",
"Adafruit ADS1X15": "https://github.com/adafruit/Adafruit_ADS1X15#2.4.0"

View File

@ -1,5 +1,5 @@
{
"name:": "AHT10_v2",
"name": "AHT10_v2",
"dependencies": {
"enjoyneering/AHT10":"~1.1.0"
}

View File

@ -1,3 +1,3 @@
{
"name:": "Analog_Clock"
"name": "Analog_Clock"
}

View File

@ -1,3 +1,3 @@
{
"name:": "Animated_Staircase"
"name": "Animated_Staircase"
}

View File

@ -2,244 +2,176 @@
#warning **** Included USERMOD_BH1750 ****
#include "wled.h"
#include <BH1750.h>
#include "BH1750_v2.h"
#ifdef WLED_DISABLE_MQTT
#error "This user mod requires MQTT to be enabled."
#endif
// the max frequency to check photoresistor, 10 seconds
#ifndef USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL
#define USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL 10000
#endif
// the min frequency to check photoresistor, 500 ms
#ifndef USERMOD_BH1750_MIN_MEASUREMENT_INTERVAL
#define USERMOD_BH1750_MIN_MEASUREMENT_INTERVAL 500
#endif
// how many seconds after boot to take first measurement, 10 seconds
#ifndef USERMOD_BH1750_FIRST_MEASUREMENT_AT
#define USERMOD_BH1750_FIRST_MEASUREMENT_AT 10000
#endif
// only report if difference grater than offset value
#ifndef USERMOD_BH1750_OFFSET_VALUE
#define USERMOD_BH1750_OFFSET_VALUE 1
#endif
class Usermod_BH1750 : public Usermod
static bool checkBoundSensor(float newValue, float prevValue, float maxDiff)
{
private:
int8_t offset = USERMOD_BH1750_OFFSET_VALUE;
return isnan(prevValue) || newValue <= prevValue - maxDiff || newValue >= prevValue + maxDiff || (newValue == 0.0 && prevValue > 0.0);
}
unsigned long maxReadingInterval = USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL;
unsigned long minReadingInterval = USERMOD_BH1750_MIN_MEASUREMENT_INTERVAL;
unsigned long lastMeasurement = UINT32_MAX - (USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL - USERMOD_BH1750_FIRST_MEASUREMENT_AT);
unsigned long lastSend = UINT32_MAX - (USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL - USERMOD_BH1750_FIRST_MEASUREMENT_AT);
// flag to indicate we have finished the first readLightLevel call
// allows this library to report to the user how long until the first
// measurement
bool getLuminanceComplete = false;
void Usermod_BH1750::_mqttInitialize()
{
mqttLuminanceTopic = String(mqttDeviceTopic) + F("/brightness");
// flag set at startup
bool enabled = true;
if (HomeAssistantDiscovery) _createMqttSensor(F("Brightness"), mqttLuminanceTopic, F("Illuminance"), F(" lx"));
}
// strings to reduce flash memory usage (used more than twice)
static const char _name[];
static const char _enabled[];
static const char _maxReadInterval[];
static const char _minReadInterval[];
static const char _offset[];
static const char _HomeAssistantDiscovery[];
bool initDone = false;
bool sensorFound = false;
// Home Assistant and MQTT
String mqttLuminanceTopic;
bool mqttInitialized = false;
bool HomeAssistantDiscovery = true; // Publish Home Assistant Discovery messages
BH1750 lightMeter;
float lastLux = -1000;
bool checkBoundSensor(float newValue, float prevValue, float maxDiff)
{
return isnan(prevValue) || newValue <= prevValue - maxDiff || newValue >= prevValue + maxDiff || (newValue == 0.0 && prevValue > 0.0);
}
// Create an MQTT Sensor for Home Assistant Discovery purposes, this includes a pointer to the topic that is published to in the Loop.
void Usermod_BH1750::_createMqttSensor(const String &name, const String &topic, const String &deviceClass, const String &unitOfMeasurement)
{
String t = String(F("homeassistant/sensor/")) + mqttClientID + F("/") + name + F("/config");
// set up Home Assistant discovery entries
void _mqttInitialize()
{
mqttLuminanceTopic = String(mqttDeviceTopic) + F("/brightness");
StaticJsonDocument<600> doc;
doc[F("name")] = String(serverDescription) + " " + name;
doc[F("state_topic")] = topic;
doc[F("unique_id")] = String(mqttClientID) + name;
if (unitOfMeasurement != "")
doc[F("unit_of_measurement")] = unitOfMeasurement;
if (deviceClass != "")
doc[F("device_class")] = deviceClass;
doc[F("expire_after")] = 1800;
if (HomeAssistantDiscovery) _createMqttSensor(F("Brightness"), mqttLuminanceTopic, F("Illuminance"), F(" lx"));
JsonObject device = doc.createNestedObject(F("device")); // attach the sensor to the same device
device[F("name")] = serverDescription;
device[F("identifiers")] = "wled-sensor-" + String(mqttClientID);
device[F("manufacturer")] = F(WLED_BRAND);
device[F("model")] = F(WLED_PRODUCT_NAME);
device[F("sw_version")] = versionString;
String temp;
serializeJson(doc, temp);
DEBUG_PRINTLN(t);
DEBUG_PRINTLN(temp);
mqtt->publish(t.c_str(), 0, true, temp.c_str());
}
void Usermod_BH1750::setup()
{
if (i2c_scl<0 || i2c_sda<0) { enabled = false; return; }
sensorFound = lightMeter.begin();
initDone = true;
}
void Usermod_BH1750::loop()
{
if ((!enabled) || strip.isUpdating())
return;
unsigned long now = millis();
// check to see if we are due for taking a measurement
// lastMeasurement will not be updated until the conversion
// is complete the the reading is finished
if (now - lastMeasurement < minReadingInterval)
{
return;
}
// Create an MQTT Sensor for Home Assistant Discovery purposes, this includes a pointer to the topic that is published to in the Loop.
void _createMqttSensor(const String &name, const String &topic, const String &deviceClass, const String &unitOfMeasurement)
bool shouldUpdate = now - lastSend > maxReadingInterval;
float lux = lightMeter.readLightLevel();
lastMeasurement = millis();
getLuminanceComplete = true;
if (shouldUpdate || checkBoundSensor(lux, lastLux, offset))
{
String t = String(F("homeassistant/sensor/")) + mqttClientID + F("/") + name + F("/config");
StaticJsonDocument<600> doc;
doc[F("name")] = String(serverDescription) + " " + name;
doc[F("state_topic")] = topic;
doc[F("unique_id")] = String(mqttClientID) + name;
if (unitOfMeasurement != "")
doc[F("unit_of_measurement")] = unitOfMeasurement;
if (deviceClass != "")
doc[F("device_class")] = deviceClass;
doc[F("expire_after")] = 1800;
lastLux = lux;
lastSend = millis();
JsonObject device = doc.createNestedObject(F("device")); // attach the sensor to the same device
device[F("name")] = serverDescription;
device[F("identifiers")] = "wled-sensor-" + String(mqttClientID);
device[F("manufacturer")] = F(WLED_BRAND);
device[F("model")] = F(WLED_PRODUCT_NAME);
device[F("sw_version")] = versionString;
String temp;
serializeJson(doc, temp);
DEBUG_PRINTLN(t);
DEBUG_PRINTLN(temp);
mqtt->publish(t.c_str(), 0, true, temp.c_str());
if (WLED_MQTT_CONNECTED)
{
if (!mqttInitialized)
{
_mqttInitialize();
mqttInitialized = true;
}
mqtt->publish(mqttLuminanceTopic.c_str(), 0, true, String(lux).c_str());
DEBUG_PRINTLN(F("Brightness: ") + String(lux) + F("lx"));
}
else
{
DEBUG_PRINTLN(F("Missing MQTT connection. Not publishing data"));
}
}
}
public:
void setup()
{
if (i2c_scl<0 || i2c_sda<0) { enabled = false; return; }
sensorFound = lightMeter.begin();
initDone = true;
}
void loop()
{
if ((!enabled) || strip.isUpdating())
void Usermod_BH1750::addToJsonInfo(JsonObject &root)
{
JsonObject user = root[F("u")];
if (user.isNull())
user = root.createNestedObject(F("u"));
JsonArray lux_json = user.createNestedArray(F("Luminance"));
if (!enabled) {
lux_json.add(F("disabled"));
} else if (!sensorFound) {
// if no sensor
lux_json.add(F("BH1750 "));
lux_json.add(F("Not Found"));
} else if (!getLuminanceComplete) {
// if we haven't read the sensor yet, let the user know
// that we are still waiting for the first measurement
lux_json.add((USERMOD_BH1750_FIRST_MEASUREMENT_AT - millis()) / 1000);
lux_json.add(F(" sec until read"));
return;
unsigned long now = millis();
// check to see if we are due for taking a measurement
// lastMeasurement will not be updated until the conversion
// is complete the the reading is finished
if (now - lastMeasurement < minReadingInterval)
{
return;
}
bool shouldUpdate = now - lastSend > maxReadingInterval;
float lux = lightMeter.readLightLevel();
lastMeasurement = millis();
getLuminanceComplete = true;
if (shouldUpdate || checkBoundSensor(lux, lastLux, offset))
{
lastLux = lux;
lastSend = millis();
#ifndef WLED_DISABLE_MQTT
if (WLED_MQTT_CONNECTED)
{
if (!mqttInitialized)
{
_mqttInitialize();
mqttInitialized = true;
}
mqtt->publish(mqttLuminanceTopic.c_str(), 0, true, String(lux).c_str());
DEBUG_PRINTLN(F("Brightness: ") + String(lux) + F("lx"));
}
else
{
DEBUG_PRINTLN(F("Missing MQTT connection. Not publishing data"));
}
#endif
}
} else {
lux_json.add(lastLux);
lux_json.add(F(" lx"));
}
}
inline float getIlluminance() {
return (float)lastLux;
}
// (called from set.cpp) stores persistent properties to cfg.json
void Usermod_BH1750::addToConfig(JsonObject &root)
{
// we add JSON object.
JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname
top[FPSTR(_enabled)] = enabled;
top[FPSTR(_maxReadInterval)] = maxReadingInterval;
top[FPSTR(_minReadInterval)] = minReadingInterval;
top[FPSTR(_HomeAssistantDiscovery)] = HomeAssistantDiscovery;
top[FPSTR(_offset)] = offset;
void addToJsonInfo(JsonObject &root)
DEBUG_PRINTLN(F("BH1750 config saved."));
}
// called before setup() to populate properties from values stored in cfg.json
bool Usermod_BH1750::readFromConfig(JsonObject &root)
{
// we look for JSON object.
JsonObject top = root[FPSTR(_name)];
if (top.isNull())
{
JsonObject user = root[F("u")];
if (user.isNull())
user = root.createNestedObject(F("u"));
JsonArray lux_json = user.createNestedArray(F("Luminance"));
if (!enabled) {
lux_json.add(F("disabled"));
} else if (!sensorFound) {
// if no sensor
lux_json.add(F("BH1750 "));
lux_json.add(F("Not Found"));
} else if (!getLuminanceComplete) {
// if we haven't read the sensor yet, let the user know
// that we are still waiting for the first measurement
lux_json.add((USERMOD_BH1750_FIRST_MEASUREMENT_AT - millis()) / 1000);
lux_json.add(F(" sec until read"));
return;
} else {
lux_json.add(lastLux);
lux_json.add(F(" lx"));
}
}
// (called from set.cpp) stores persistent properties to cfg.json
void addToConfig(JsonObject &root)
{
// we add JSON object.
JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname
top[FPSTR(_enabled)] = enabled;
top[FPSTR(_maxReadInterval)] = maxReadingInterval;
top[FPSTR(_minReadInterval)] = minReadingInterval;
top[FPSTR(_HomeAssistantDiscovery)] = HomeAssistantDiscovery;
top[FPSTR(_offset)] = offset;
DEBUG_PRINTLN(F("BH1750 config saved."));
}
// called before setup() to populate properties from values stored in cfg.json
bool readFromConfig(JsonObject &root)
{
// we look for JSON object.
JsonObject top = root[FPSTR(_name)];
if (top.isNull())
{
DEBUG_PRINT(FPSTR(_name));
DEBUG_PRINT(F("BH1750"));
DEBUG_PRINTLN(F(": No config found. (Using defaults.)"));
return false;
}
bool configComplete = !top.isNull();
configComplete &= getJsonValue(top[FPSTR(_enabled)], enabled, false);
configComplete &= getJsonValue(top[FPSTR(_maxReadInterval)], maxReadingInterval, 10000); //ms
configComplete &= getJsonValue(top[FPSTR(_minReadInterval)], minReadingInterval, 500); //ms
configComplete &= getJsonValue(top[FPSTR(_HomeAssistantDiscovery)], HomeAssistantDiscovery, false);
configComplete &= getJsonValue(top[FPSTR(_offset)], offset, 1);
DEBUG_PRINT(FPSTR(_name));
if (!initDone) {
DEBUG_PRINTLN(F(" config loaded."));
} else {
DEBUG_PRINTLN(F(" config (re)loaded."));
}
DEBUG_PRINT(F("BH1750"));
DEBUG_PRINTLN(F(": No config found. (Using defaults.)"));
return false;
}
bool configComplete = !top.isNull();
return configComplete;
configComplete &= getJsonValue(top[FPSTR(_enabled)], enabled, false);
configComplete &= getJsonValue(top[FPSTR(_maxReadInterval)], maxReadingInterval, 10000); //ms
configComplete &= getJsonValue(top[FPSTR(_minReadInterval)], minReadingInterval, 500); //ms
configComplete &= getJsonValue(top[FPSTR(_HomeAssistantDiscovery)], HomeAssistantDiscovery, false);
configComplete &= getJsonValue(top[FPSTR(_offset)], offset, 1);
DEBUG_PRINT(FPSTR(_name));
if (!initDone) {
DEBUG_PRINTLN(F(" config loaded."));
} else {
DEBUG_PRINTLN(F(" config (re)loaded."));
}
uint16_t getId()
{
return USERMOD_ID_BH1750;
}
return configComplete;
}
};
// strings to reduce flash memory usage (used more than twice)
const char Usermod_BH1750::_name[] PROGMEM = "BH1750";

View File

@ -0,0 +1,92 @@
#pragma once
#include "wled.h"
#include <BH1750.h>
#ifdef WLED_DISABLE_MQTT
#error "This user mod requires MQTT to be enabled."
#endif
// the max frequency to check photoresistor, 10 seconds
#ifndef USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL
#define USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL 10000
#endif
// the min frequency to check photoresistor, 500 ms
#ifndef USERMOD_BH1750_MIN_MEASUREMENT_INTERVAL
#define USERMOD_BH1750_MIN_MEASUREMENT_INTERVAL 500
#endif
// how many seconds after boot to take first measurement, 10 seconds
#ifndef USERMOD_BH1750_FIRST_MEASUREMENT_AT
#define USERMOD_BH1750_FIRST_MEASUREMENT_AT 10000
#endif
// only report if difference grater than offset value
#ifndef USERMOD_BH1750_OFFSET_VALUE
#define USERMOD_BH1750_OFFSET_VALUE 1
#endif
class Usermod_BH1750 : public Usermod
{
private:
int8_t offset = USERMOD_BH1750_OFFSET_VALUE;
unsigned long maxReadingInterval = USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL;
unsigned long minReadingInterval = USERMOD_BH1750_MIN_MEASUREMENT_INTERVAL;
unsigned long lastMeasurement = UINT32_MAX - (USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL - USERMOD_BH1750_FIRST_MEASUREMENT_AT);
unsigned long lastSend = UINT32_MAX - (USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL - USERMOD_BH1750_FIRST_MEASUREMENT_AT);
// flag to indicate we have finished the first readLightLevel call
// allows this library to report to the user how long until the first
// measurement
bool getLuminanceComplete = false;
// flag set at startup
bool enabled = true;
// strings to reduce flash memory usage (used more than twice)
static const char _name[];
static const char _enabled[];
static const char _maxReadInterval[];
static const char _minReadInterval[];
static const char _offset[];
static const char _HomeAssistantDiscovery[];
bool initDone = false;
bool sensorFound = false;
// Home Assistant and MQTT
String mqttLuminanceTopic;
bool mqttInitialized = false;
bool HomeAssistantDiscovery = true; // Publish Home Assistant Discovery messages
BH1750 lightMeter;
float lastLux = -1000;
// set up Home Assistant discovery entries
void _mqttInitialize();
// Create an MQTT Sensor for Home Assistant Discovery purposes, this includes a pointer to the topic that is published to in the Loop.
void _createMqttSensor(const String &name, const String &topic, const String &deviceClass, const String &unitOfMeasurement);
public:
void setup();
void loop();
inline float getIlluminance() {
return (float)lastLux;
}
void addToJsonInfo(JsonObject &root);
// (called from set.cpp) stores persistent properties to cfg.json
void addToConfig(JsonObject &root);
// called before setup() to populate properties from values stored in cfg.json
bool readFromConfig(JsonObject &root);
inline uint16_t getId()
{
return USERMOD_ID_BH1750;
}
};

View File

@ -1,5 +1,5 @@
{
"name:": "BH1750_v2",
"name": "BH1750_v2",
"dependencies": {
"claws/BH1750":"^1.2.0"
}

View File

@ -1,5 +1,5 @@
{
"name:": "BME280_v2",
"name": "BME280_v2",
"dependencies": {
"finitespace/BME280":"~3.0.0"
}

View File

@ -1,5 +1,5 @@
/**
* @file usermod_BMW68X.h
* @file usermod_BMW68X.cpp
* @author Gabriel A. Sieben (GeoGab)
* @brief Usermod for WLED to implement the BME680/BME688 sensor
* @version 1.0.2

View File

@ -1,5 +1,5 @@
{
"name:": "BME68X",
"name": "BME68X",
"dependencies": {
"boschsensortec/BSEC Software Library":"^1.8.1492"
}

View File

@ -1,3 +1,3 @@
{
"name:": "Battery"
"name": "Battery"
}

View File

@ -1,3 +1,3 @@
{
"name:": "Cronixie"
"name": "Cronixie"
}

View File

@ -1,5 +1,5 @@
{
"name:": "DHT",
"name": "DHT",
"build": { "libArchive": false},
"dependencies": {
"DHT_nonblocking":"https://github.com/alwynallan/DHT_nonblocking"

View File

@ -1,4 +1,4 @@
{
"name:": "EXAMPLE",
"name": "EXAMPLE",
"dependencies": {}
}

View File

@ -1,4 +1,4 @@
{
"name:": "Fix_unreachable_netservices_v2",
"name": "Fix_unreachable_netservices_v2",
"platforms": ["espressif8266"]
}

View File

@ -1,5 +1,5 @@
{
"name:": "INA226_v2",
"name": "INA226_v2",
"dependencies": {
"wollewald/INA226_WE":"~1.2.9"
}

View File

@ -1,3 +1,3 @@
{
"name:": "Internal_Temperature_v2"
"name": "Internal_Temperature_v2"
}

View File

@ -1,5 +1,5 @@
{
"name:": "LD2410_v2",
"name": "LD2410_v2",
"dependencies": {
"ncmreynolds/ld2410":"^0.1.3"
}

View File

@ -1,3 +1,3 @@
{
"name:": "LDR_Dusk_Dawn_v2"
"name": "LDR_Dusk_Dawn_v2"
}

View File

@ -35,8 +35,8 @@ class Usermod_MAX17048 : public Usermod {
unsigned long lastSend = UINT32_MAX - (USERMOD_MAX17048_MAX_MONITOR_INTERVAL - USERMOD_MAX17048_FIRST_MONITOR_AT);
uint8_t VoltageDecimals = 3; // Number of decimal places in published voltage values
uint8_t PercentDecimals = 1; // Number of decimal places in published percent values
unsigned VoltageDecimals = 3; // Number of decimal places in published voltage values
unsigned PercentDecimals = 1; // Number of decimal places in published percent values
// string that are used multiple time (this will save some flash memory)
static const char _name[];

View File

@ -1,5 +1,5 @@
{
"name:": "MAX17048_v2",
"name": "MAX17048_v2",
"build": { "libArchive": false},
"dependencies": {
"Adafruit_MAX1704X":"https://github.com/adafruit/Adafruit_MAX1704X#1.0.2"

View File

@ -5,26 +5,16 @@ This usermod reads information from an Adafruit MAX17048 and outputs the follow
## Dependencies
Libraries:
- `Adafruit_BusIO@~1.14.5` (by [adafruit](https://github.com/adafruit/Adafruit_BusIO))
- `Adafruit_MAX1704X@~1.0.2` (by [adafruit](https://github.com/adafruit/Adafruit_MAX1704X))
These must be added under `lib_deps` in your `platform.ini` (or `platform_override.ini`).
Data is published over MQTT - make sure you've enabled the MQTT sync interface.
## Compilation
Add "MAX17048_v2" to your platformio.ini environment's custom_usermods and build.
To enable, compile with `USERMOD_MAX17048` define in the build_flags (e.g. in `platformio.ini` or `platformio_override.ini`) such as in the example below:
```ini
[env:usermod_max17048_d1_mini]
extends = env:d1_mini
build_flags =
${common.build_flags_esp8266}
-D USERMOD_MAX17048
lib_deps =
${esp8266.lib_deps}
https://github.com/adafruit/Adafruit_BusIO @ 1.14.5
https://github.com/adafruit/Adafruit_MAX1704X @ 1.0.2
custom_usermods = ${env:d1_mini.custom_usermods} MAX17048_v2
```
### Configuration Options

View File

@ -1,4 +1,4 @@
{
"name:": "MY9291",
"name": "MY9291",
"platforms": ["espressif8266"]
}

View File

@ -1,3 +1,3 @@
{
"name:": "PIR_sensor_switch"
"name": "PIR_sensor_switch"
}

View File

@ -1,5 +1,5 @@
{
"name:": "PWM_fan",
"name": "PWM_fan",
"build": {
"extraScript": "setup_deps.py"
}

View File

@ -7,6 +7,5 @@ if "Temperature" in usermods:
env.Append(CPPDEFINES=[("USERMOD_DALLASTEMPERATURE")])
elif "sht" in usermods:
env.Append(CPPDEFINES=[("USERMOD_SHT")])
else:
elif "PWM_fan" in usermods: # The script can be run if this module was previously selected
raise RuntimeError("PWM_fan usermod requires Temperature or sht to be enabled")

View File

@ -1,3 +1,3 @@
{
"name:": "RTC"
"name": "RTC"
}

View File

@ -1,204 +1,137 @@
#include "wled.h"
#include "SN_Photoresistor.h"
//Pin defaults for QuinLed Dig-Uno (A0)
#ifndef PHOTORESISTOR_PIN
#define PHOTORESISTOR_PIN A0
#endif
// the frequency to check photoresistor, 10 seconds
#ifndef USERMOD_SN_PHOTORESISTOR_MEASUREMENT_INTERVAL
#define USERMOD_SN_PHOTORESISTOR_MEASUREMENT_INTERVAL 10000
#endif
// how many seconds after boot to take first measurement, 10 seconds
#ifndef USERMOD_SN_PHOTORESISTOR_FIRST_MEASUREMENT_AT
#define USERMOD_SN_PHOTORESISTOR_FIRST_MEASUREMENT_AT 10000
#endif
// supplied voltage
#ifndef USERMOD_SN_PHOTORESISTOR_REFERENCE_VOLTAGE
#define USERMOD_SN_PHOTORESISTOR_REFERENCE_VOLTAGE 5
#endif
// 10 bits
#ifndef USERMOD_SN_PHOTORESISTOR_ADC_PRECISION
#define USERMOD_SN_PHOTORESISTOR_ADC_PRECISION 1024.0f
#endif
// resistor size 10K hms
#ifndef USERMOD_SN_PHOTORESISTOR_RESISTOR_VALUE
#define USERMOD_SN_PHOTORESISTOR_RESISTOR_VALUE 10000.0f
#endif
// only report if difference grater than offset value
#ifndef USERMOD_SN_PHOTORESISTOR_OFFSET_VALUE
#define USERMOD_SN_PHOTORESISTOR_OFFSET_VALUE 5
#endif
class Usermod_SN_Photoresistor : public Usermod
static bool checkBoundSensor(float newValue, float prevValue, float maxDiff)
{
private:
float referenceVoltage = USERMOD_SN_PHOTORESISTOR_REFERENCE_VOLTAGE;
float resistorValue = USERMOD_SN_PHOTORESISTOR_RESISTOR_VALUE;
float adcPrecision = USERMOD_SN_PHOTORESISTOR_ADC_PRECISION;
int8_t offset = USERMOD_SN_PHOTORESISTOR_OFFSET_VALUE;
return isnan(prevValue) || newValue <= prevValue - maxDiff || newValue >= prevValue + maxDiff;
}
unsigned long readingInterval = USERMOD_SN_PHOTORESISTOR_MEASUREMENT_INTERVAL;
// set last reading as "40 sec before boot", so first reading is taken after 20 sec
unsigned long lastMeasurement = UINT32_MAX - (USERMOD_SN_PHOTORESISTOR_MEASUREMENT_INTERVAL - USERMOD_SN_PHOTORESISTOR_FIRST_MEASUREMENT_AT);
// flag to indicate we have finished the first getTemperature call
// allows this library to report to the user how long until the first
// measurement
bool getLuminanceComplete = false;
uint16_t lastLDRValue = -1000;
uint16_t Usermod_SN_Photoresistor::getLuminance()
{
// http://forum.arduino.cc/index.php?topic=37555.0
// https://forum.arduino.cc/index.php?topic=185158.0
float volts = analogRead(PHOTORESISTOR_PIN) * (referenceVoltage / adcPrecision);
float amps = volts / resistorValue;
float lux = amps * 1000000 * 2.0;
// flag set at startup
bool disabled = false;
lastMeasurement = millis();
getLuminanceComplete = true;
return uint16_t(lux);
}
// strings to reduce flash memory usage (used more than twice)
static const char _name[];
static const char _enabled[];
static const char _readInterval[];
static const char _referenceVoltage[];
static const char _resistorValue[];
static const char _adcPrecision[];
static const char _offset[];
void Usermod_SN_Photoresistor::setup()
{
// set pinmode
pinMode(PHOTORESISTOR_PIN, INPUT);
}
bool checkBoundSensor(float newValue, float prevValue, float maxDiff)
void Usermod_SN_Photoresistor::loop()
{
if (disabled || strip.isUpdating())
return;
unsigned long now = millis();
// check to see if we are due for taking a measurement
// lastMeasurement will not be updated until the conversion
// is complete the the reading is finished
if (now - lastMeasurement < readingInterval)
{
return isnan(prevValue) || newValue <= prevValue - maxDiff || newValue >= prevValue + maxDiff;
return;
}
uint16_t getLuminance()
uint16_t currentLDRValue = getLuminance();
if (checkBoundSensor(currentLDRValue, lastLDRValue, offset))
{
// http://forum.arduino.cc/index.php?topic=37555.0
// https://forum.arduino.cc/index.php?topic=185158.0
float volts = analogRead(PHOTORESISTOR_PIN) * (referenceVoltage / adcPrecision);
float amps = volts / resistorValue;
float lux = amps * 1000000 * 2.0;
lastMeasurement = millis();
getLuminanceComplete = true;
return uint16_t(lux);
}
public:
void setup()
{
// set pinmode
pinMode(PHOTORESISTOR_PIN, INPUT);
}
void loop()
{
if (disabled || strip.isUpdating())
return;
unsigned long now = millis();
// check to see if we are due for taking a measurement
// lastMeasurement will not be updated until the conversion
// is complete the the reading is finished
if (now - lastMeasurement < readingInterval)
{
return;
}
uint16_t currentLDRValue = getLuminance();
if (checkBoundSensor(currentLDRValue, lastLDRValue, offset))
{
lastLDRValue = currentLDRValue;
lastLDRValue = currentLDRValue;
#ifndef WLED_DISABLE_MQTT
if (WLED_MQTT_CONNECTED)
{
char subuf[45];
strcpy(subuf, mqttDeviceTopic);
strcat_P(subuf, PSTR("/luminance"));
mqtt->publish(subuf, 0, true, String(lastLDRValue).c_str());
}
else
{
DEBUG_PRINTLN(F("Missing MQTT connection. Not publishing data"));
}
}
#endif
}
uint16_t getLastLDRValue()
{
return lastLDRValue;
}
void addToJsonInfo(JsonObject &root)
{
JsonObject user = root[F("u")];
if (user.isNull())
user = root.createNestedObject(F("u"));
JsonArray lux = user.createNestedArray(F("Luminance"));
if (!getLuminanceComplete)
if (WLED_MQTT_CONNECTED)
{
// if we haven't read the sensor yet, let the user know
// that we are still waiting for the first measurement
lux.add((USERMOD_SN_PHOTORESISTOR_FIRST_MEASUREMENT_AT - millis()) / 1000);
lux.add(F(" sec until read"));
return;
char subuf[45];
strcpy(subuf, mqttDeviceTopic);
strcat_P(subuf, PSTR("/luminance"));
mqtt->publish(subuf, 0, true, String(lastLDRValue).c_str());
}
lux.add(lastLDRValue);
lux.add(F(" lux"));
}
uint16_t getId()
{
return USERMOD_ID_SN_PHOTORESISTOR;
}
/**
* addToConfig() (called from set.cpp) stores persistent properties to cfg.json
*/
void addToConfig(JsonObject &root)
{
// we add JSON object.
JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname
top[FPSTR(_enabled)] = !disabled;
top[FPSTR(_readInterval)] = readingInterval / 1000;
top[FPSTR(_referenceVoltage)] = referenceVoltage;
top[FPSTR(_resistorValue)] = resistorValue;
top[FPSTR(_adcPrecision)] = adcPrecision;
top[FPSTR(_offset)] = offset;
DEBUG_PRINTLN(F("Photoresistor config saved."));
}
/**
* readFromConfig() is called before setup() to populate properties from values stored in cfg.json
*/
bool readFromConfig(JsonObject &root)
{
// we look for JSON object.
JsonObject top = root[FPSTR(_name)];
if (top.isNull()) {
DEBUG_PRINT(FPSTR(_name));
DEBUG_PRINTLN(F(": No config found. (Using defaults.)"));
return false;
else
{
DEBUG_PRINTLN(F("Missing MQTT connection. Not publishing data"));
}
}
#endif
}
disabled = !(top[FPSTR(_enabled)] | !disabled);
readingInterval = (top[FPSTR(_readInterval)] | readingInterval/1000) * 1000; // convert to ms
referenceVoltage = top[FPSTR(_referenceVoltage)] | referenceVoltage;
resistorValue = top[FPSTR(_resistorValue)] | resistorValue;
adcPrecision = top[FPSTR(_adcPrecision)] | adcPrecision;
offset = top[FPSTR(_offset)] | offset;
void Usermod_SN_Photoresistor::addToJsonInfo(JsonObject &root)
{
JsonObject user = root[F("u")];
if (user.isNull())
user = root.createNestedObject(F("u"));
JsonArray lux = user.createNestedArray(F("Luminance"));
if (!getLuminanceComplete)
{
// if we haven't read the sensor yet, let the user know
// that we are still waiting for the first measurement
lux.add((USERMOD_SN_PHOTORESISTOR_FIRST_MEASUREMENT_AT - millis()) / 1000);
lux.add(F(" sec until read"));
return;
}
lux.add(lastLDRValue);
lux.add(F(" lux"));
}
/**
* addToConfig() (called from set.cpp) stores persistent properties to cfg.json
*/
void Usermod_SN_Photoresistor::addToConfig(JsonObject &root)
{
// we add JSON object.
JsonObject top = root.createNestedObject(FPSTR(_name)); // usermodname
top[FPSTR(_enabled)] = !disabled;
top[FPSTR(_readInterval)] = readingInterval / 1000;
top[FPSTR(_referenceVoltage)] = referenceVoltage;
top[FPSTR(_resistorValue)] = resistorValue;
top[FPSTR(_adcPrecision)] = adcPrecision;
top[FPSTR(_offset)] = offset;
DEBUG_PRINTLN(F("Photoresistor config saved."));
}
/**
* readFromConfig() is called before setup() to populate properties from values stored in cfg.json
*/
bool Usermod_SN_Photoresistor::readFromConfig(JsonObject &root)
{
// we look for JSON object.
JsonObject top = root[FPSTR(_name)];
if (top.isNull()) {
DEBUG_PRINT(FPSTR(_name));
DEBUG_PRINTLN(F(" config (re)loaded."));
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
return true;
DEBUG_PRINTLN(F(": No config found. (Using defaults.)"));
return false;
}
};
disabled = !(top[FPSTR(_enabled)] | !disabled);
readingInterval = (top[FPSTR(_readInterval)] | readingInterval/1000) * 1000; // convert to ms
referenceVoltage = top[FPSTR(_referenceVoltage)] | referenceVoltage;
resistorValue = top[FPSTR(_resistorValue)] | resistorValue;
adcPrecision = top[FPSTR(_adcPrecision)] | adcPrecision;
offset = top[FPSTR(_offset)] | offset;
DEBUG_PRINT(FPSTR(_name));
DEBUG_PRINTLN(F(" config (re)loaded."));
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
return true;
}
// strings to reduce flash memory usage (used more than twice)
const char Usermod_SN_Photoresistor::_name[] PROGMEM = "Photoresistor";
@ -209,6 +142,5 @@ const char Usermod_SN_Photoresistor::_resistorValue[] PROGMEM = "resistor-value"
const char Usermod_SN_Photoresistor::_adcPrecision[] PROGMEM = "adc-precision";
const char Usermod_SN_Photoresistor::_offset[] PROGMEM = "offset";
static Usermod_SN_Photoresistor sn_photoresistor;
REGISTER_USERMOD(sn_photoresistor);

View File

@ -0,0 +1,90 @@
#pragma once
#include "wled.h"
// the frequency to check photoresistor, 10 seconds
#ifndef USERMOD_SN_PHOTORESISTOR_MEASUREMENT_INTERVAL
#define USERMOD_SN_PHOTORESISTOR_MEASUREMENT_INTERVAL 10000
#endif
// how many seconds after boot to take first measurement, 10 seconds
#ifndef USERMOD_SN_PHOTORESISTOR_FIRST_MEASUREMENT_AT
#define USERMOD_SN_PHOTORESISTOR_FIRST_MEASUREMENT_AT 10000
#endif
// supplied voltage
#ifndef USERMOD_SN_PHOTORESISTOR_REFERENCE_VOLTAGE
#define USERMOD_SN_PHOTORESISTOR_REFERENCE_VOLTAGE 5
#endif
// 10 bits
#ifndef USERMOD_SN_PHOTORESISTOR_ADC_PRECISION
#define USERMOD_SN_PHOTORESISTOR_ADC_PRECISION 1024.0f
#endif
// resistor size 10K hms
#ifndef USERMOD_SN_PHOTORESISTOR_RESISTOR_VALUE
#define USERMOD_SN_PHOTORESISTOR_RESISTOR_VALUE 10000.0f
#endif
// only report if difference grater than offset value
#ifndef USERMOD_SN_PHOTORESISTOR_OFFSET_VALUE
#define USERMOD_SN_PHOTORESISTOR_OFFSET_VALUE 5
#endif
class Usermod_SN_Photoresistor : public Usermod
{
private:
float referenceVoltage = USERMOD_SN_PHOTORESISTOR_REFERENCE_VOLTAGE;
float resistorValue = USERMOD_SN_PHOTORESISTOR_RESISTOR_VALUE;
float adcPrecision = USERMOD_SN_PHOTORESISTOR_ADC_PRECISION;
int8_t offset = USERMOD_SN_PHOTORESISTOR_OFFSET_VALUE;
unsigned long readingInterval = USERMOD_SN_PHOTORESISTOR_MEASUREMENT_INTERVAL;
// set last reading as "40 sec before boot", so first reading is taken after 20 sec
unsigned long lastMeasurement = UINT32_MAX - (USERMOD_SN_PHOTORESISTOR_MEASUREMENT_INTERVAL - USERMOD_SN_PHOTORESISTOR_FIRST_MEASUREMENT_AT);
// flag to indicate we have finished the first getTemperature call
// allows this library to report to the user how long until the first
// measurement
bool getLuminanceComplete = false;
uint16_t lastLDRValue = 65535;
// flag set at startup
bool disabled = false;
// strings to reduce flash memory usage (used more than twice)
static const char _name[];
static const char _enabled[];
static const char _readInterval[];
static const char _referenceVoltage[];
static const char _resistorValue[];
static const char _adcPrecision[];
static const char _offset[];
uint16_t getLuminance();
public:
void setup();
void loop();
uint16_t getLastLDRValue()
{
return lastLDRValue;
}
void addToJsonInfo(JsonObject &root);
uint16_t getId()
{
return USERMOD_ID_SN_PHOTORESISTOR;
}
/**
* addToConfig() (called from set.cpp) stores persistent properties to cfg.json
*/
void addToConfig(JsonObject &root);
/**
* readFromConfig() is called before setup() to populate properties from values stored in cfg.json
*/
bool readFromConfig(JsonObject &root);
};

View File

@ -1,3 +1,3 @@
{
"name:": "SN_Photoresistor"
"name": "SN_Photoresistor"
}

View File

@ -1,14 +0,0 @@
#include "wled.h"
/*
* Register your v2 usermods here!
*/
#ifdef USERMOD_SN_PHOTORESISTOR
#include "../usermods/SN_Photoresistor/usermod_sn_photoresistor.h"
#endif
void registerUsermods()
{
#ifdef USERMOD_SN_PHOTORESISTOR
UsermodManager::add(new Usermod_SN_Photoresistor());
#endif
}

View File

@ -1,5 +1,5 @@
{
"name:": "Si7021_MQTT_HA",
"name": "Si7021_MQTT_HA",
"dependencies": {
"finitespace/BME280":"3.0.0",
"adafruit/Adafruit Si7021 Library" : "1.5.3"

View File

@ -1,5 +1,5 @@
{
"name:": "Temperature",
"name": "Temperature",
"build": { "libArchive": false},
"dependencies": {
"paulstoffregen/OneWire":"~2.3.8"

View File

@ -1,3 +1,3 @@
{
"name:": "TetrisAI_v2"
"name": "TetrisAI_v2"
}

View File

@ -1,5 +1,5 @@
{
"name:": "VL53L0X_gestures",
"name": "VL53L0X_gestures",
"build": { "libArchive": false},
"dependencies": {
"pololu/VL53L0X" : "^1.3.0"

View File

@ -1,3 +1,3 @@
{
"name:": "boblight"
"name": "boblight"
}

View File

@ -1,3 +1,3 @@
{
"name:": "buzzer"
"name": "buzzer"
}

View File

@ -1,3 +1,3 @@
{
"name:": "deep_sleep"
"name": "deep_sleep"
}

View File

@ -1,5 +1,5 @@
{
"name:": "mpu6050_imu",
"name": "mpu6050_imu",
"build": { "libArchive": false},
"dependencies": {
"electroniccats/MPU6050":"1.0.1"

View File

@ -1,3 +1,3 @@
{
"name:": "multi_relay"
"name": "multi_relay"
}

View File

@ -1,5 +1,5 @@
{
"name:": "pixels_dice_tray",
"name": "pixels_dice_tray",
"build": { "libArchive": false},
"dependencies": {
"arduino-pixels-dice":"https://github.com/axlan/arduino-pixels-dice.git",

View File

@ -1,3 +1,3 @@
{
"name:": "pwm_outputs"
"name": "pwm_outputs"
}

View File

@ -1,5 +1,5 @@
{
"name:": "quinled-an-penta",
"name": "quinled-an-penta",
"build": { "libArchive": false},
"dependencies": {
"olikraus/U8g2":"~2.28.8",

View File

@ -1,5 +1,5 @@
{
"name:": "rgb-rotary-encoder",
"name": "rgb-rotary-encoder",
"build": { "libArchive": false},
"dependencies": {
"lennarthennigs/ESP Rotary":"^2.1.1"

View File

@ -1,3 +1,3 @@
{
"name:": "sd_card"
"name": "sd_card"
}

View File

@ -1,5 +1,5 @@
{
"name:": "sensors_to_mqtt",
"name": "sensors_to_mqtt",
"build": { "libArchive": false},
"dependencies": {
"adafruit/Adafruit BMP280 Library":"2.6.8",

View File

@ -1,3 +1,3 @@
{
"name:": "seven_segment_display"
"name": "seven_segment_display"
}

View File

@ -1,3 +1,6 @@
{
"name:": "seven_segment_display_reloaded"
"name": "seven_segment_display_reloaded",
"build": {
"extraScript": "setup_deps.py"
}
}

View File

@ -0,0 +1,9 @@
Import('env')
usermods = env.GetProjectOption("custom_usermods","").split()
# Check for partner usermods
if "SN_Photoresistor" in usermods:
env.Append(CPPDEFINES=[("USERMOD_SN_PHOTORESISTOR")])
if any(mod in ("BH1750_v2", "BH1750") for mod in usermods):
env.Append(CPPDEFINES=[("USERMOD_BH1750")])

View File

@ -1,4 +1,10 @@
#include "wled.h"
#ifdef USERMOD_SN_PHOTORESISTOR
#include "SN_Photoresistor.h"
#endif
#ifdef USERMOD_BH1750
#include "BH1750_v2.h"
#endif
#ifdef WLED_DISABLE_MQTT
#error "This user mod requires MQTT to be enabled."

View File

@ -1,5 +1,5 @@
{
"name:": "sht",
"name": "sht",
"dependencies": {
"robtillaart/SHT85": "~0.3.3"
}

View File

@ -1,3 +1,3 @@
{
"name:": "smartnest"
"name": "smartnest"
}

View File

@ -1,3 +1,3 @@
{
"name:": "stairway_wipe_basic"
"name": "stairway_wipe_basic"
}

View File

@ -1,3 +1,3 @@
{
"name:": "usermod_rotary_brightness_color"
"name": "usermod_rotary_brightness_color"
}

View File

@ -0,0 +1,3 @@
{
"name": "usermod_v2_HttpPullLightControl"
}

View File

@ -1,3 +0,0 @@
{
"name:": "usermod_v2_HttpPullLightControl"
}

View File

@ -297,10 +297,10 @@ void HttpPullLightControl::handleResponse(String& responseStr) {
// Check for valid JSON, otherwise we brick the program runtime
if (jsonStr[0] == '{' || jsonStr[0] == '[') {
// Attempt to deserialize the JSON response
DeserializationError error = deserializeJson(doc, jsonStr);
DeserializationError error = deserializeJson(*pDoc, jsonStr);
if (error == DeserializationError::Ok) {
// Get JSON object from th doc
JsonObject obj = doc.as<JsonObject>();
JsonObject obj = pDoc->as<JsonObject>();
// Parse the object throuhg deserializeState (use CALL_MODE_NO_NOTIFY or OR CALL_MODE_DIRECT_CHANGE)
deserializeState(obj, CALL_MODE_NO_NOTIFY);
} else {

View File

@ -1,5 +1,5 @@
{
"name:": "usermod_v2_RF433",
"name": "usermod_v2_RF433",
"dependencies": {
"sui77/rc-switch":"2.6.4"
}

View File

@ -0,0 +1,3 @@
{
"name": "brightness_follow_sun"
}

View File

@ -1,5 +1,3 @@
#pragma once
#include "wled.h"
//v2 usermod that allows to change brightness and color using a rotary encoder,
@ -128,3 +126,6 @@ const char UsermodBrightnessFollowSun::_update_interval[] PROGMEM = "Update
const char UsermodBrightnessFollowSun::_min_bri[] PROGMEM = "Min Brightness";
const char UsermodBrightnessFollowSun::_max_bri[] PROGMEM = "Max Brightness";
const char UsermodBrightnessFollowSun::_relax_hour[] PROGMEM = "Relax Hour";
static UsermodBrightnessFollowSun usermod_brightness_follow_sun;
REGISTER_USERMOD(usermod_brightness_follow_sun);

View File

@ -1,7 +1,5 @@
#pragma once
//WLED custom fonts, curtesy of @Benji (https://github.com/Proto-molecule)
#pragma once
/*
Fontname: wled_logo_akemi_4x4

View File

@ -0,0 +1,7 @@
{
"name": "four_line_display_ALT",
"dependencies": {
"U8g2": "~2.34.4",
"Wire": ""
}
}

View File

@ -1,3 +0,0 @@
{
"name:": "usermod_v2_four_line_display_ALT"
}

View File

@ -1,18 +1,11 @@
[platformio]
default_envs = esp32dev
default_envs = esp32dev_fld
[env:esp32dev]
board = esp32dev
platform = ${esp32.platform}
build_unflags = ${common.build_unflags}
[env:esp32dev_fld]
extends = env:esp32dev_V4
custom_usermods = ${env:esp32dev_V4.custom_usermods} four_line_display_ALT
build_flags =
${common.build_flags_esp32}
-D USERMOD_FOUR_LINE_DISPLAY
${env:esp32dev_V4.build_flags}
-D FLD_TYPE=SH1106
-D I2CSCLPIN=27
-D I2CSDAPIN=26
lib_deps =
${esp32.lib_deps}
U8g2@~2.34.4
Wire

View File

@ -0,0 +1,315 @@
#include "wled.h"
#undef U8X8_NO_HW_I2C // borrowed from WLEDMM: we do want I2C hardware drivers - if possible
#include <U8x8lib.h> // from https://github.com/olikraus/u8g2/
#pragma once
#ifndef FLD_ESP32_NO_THREADS
#define FLD_ESP32_USE_THREADS // comment out to use 0.13.x behaviour without parallel update task - slower, but more robust. May delay other tasks like LEDs or audioreactive!!
#endif
#ifndef FLD_PIN_CS
#define FLD_PIN_CS 15
#endif
#ifdef ARDUINO_ARCH_ESP32
#ifndef FLD_PIN_DC
#define FLD_PIN_DC 19
#endif
#ifndef FLD_PIN_RESET
#define FLD_PIN_RESET 26
#endif
#else
#ifndef FLD_PIN_DC
#define FLD_PIN_DC 12
#endif
#ifndef FLD_PIN_RESET
#define FLD_PIN_RESET 16
#endif
#endif
#ifndef FLD_TYPE
#ifndef FLD_SPI_DEFAULT
#define FLD_TYPE SSD1306
#else
#define FLD_TYPE SSD1306_SPI
#endif
#endif
// When to time out to the clock or blank the screen
// if SLEEP_MODE_ENABLED.
#define SCREEN_TIMEOUT_MS 60*1000 // 1 min
// Minimum time between redrawing screen in ms
#define REFRESH_RATE_MS 1000
// Extra char (+1) for null
#define LINE_BUFFER_SIZE 16+1
#define MAX_JSON_CHARS 19+1
#define MAX_MODE_LINE_SPACE 13+1
typedef enum {
NONE = 0,
SSD1306, // U8X8_SSD1306_128X32_UNIVISION_HW_I2C
SH1106, // U8X8_SH1106_128X64_WINSTAR_HW_I2C
SSD1306_64, // U8X8_SSD1306_128X64_NONAME_HW_I2C
SSD1305, // U8X8_SSD1305_128X32_ADAFRUIT_HW_I2C
SSD1305_64, // U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C
SSD1306_SPI, // U8X8_SSD1306_128X32_NONAME_HW_SPI
SSD1306_SPI64, // U8X8_SSD1306_128X64_NONAME_HW_SPI
SSD1309_SPI64, // U8X8_SSD1309_128X64_NONAME0_4W_HW_SPI
SSD1309_64 // U8X8_SSD1309_128X64_NONAME0_HW_I2C
} DisplayType;
class FourLineDisplayUsermod : public Usermod {
#if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS)
public:
FourLineDisplayUsermod() { if (!instance) instance = this; }
static FourLineDisplayUsermod* getInstance(void) { return instance; }
#endif
private:
static FourLineDisplayUsermod *instance;
bool initDone = false;
volatile bool drawing = false;
volatile bool lockRedraw = false;
// HW interface & configuration
U8X8 *u8x8 = nullptr; // pointer to U8X8 display object
#ifndef FLD_SPI_DEFAULT
int8_t ioPin[3] = {-1, -1, -1}; // I2C pins: SCL, SDA
uint32_t ioFrequency = 400000; // in Hz (minimum is 100000, baseline is 400000 and maximum should be 3400000)
#else
int8_t ioPin[3] = {FLD_PIN_CS, FLD_PIN_DC, FLD_PIN_RESET}; // custom SPI pins: CS, DC, RST
uint32_t ioFrequency = 1000000; // in Hz (minimum is 500kHz, baseline is 1MHz and maximum should be 20MHz)
#endif
DisplayType type = FLD_TYPE; // display type
bool flip = false; // flip display 180°
uint8_t contrast = 10; // screen contrast
uint8_t lineHeight = 1; // 1 row or 2 rows
uint16_t refreshRate = REFRESH_RATE_MS; // in ms
uint32_t screenTimeout = SCREEN_TIMEOUT_MS; // in ms
bool sleepMode = true; // allow screen sleep?
bool clockMode = false; // display clock
bool showSeconds = true; // display clock with seconds
bool enabled = true;
bool contrastFix = false;
// Next variables hold the previous known values to determine if redraw is
// required.
String knownSsid = apSSID;
IPAddress knownIp = IPAddress(4, 3, 2, 1);
uint8_t knownBrightness = 0;
uint8_t knownEffectSpeed = 0;
uint8_t knownEffectIntensity = 0;
uint8_t knownMode = 0;
uint8_t knownPalette = 0;
uint8_t knownMinute = 99;
uint8_t knownHour = 99;
byte brightness100;
byte fxspeed100;
byte fxintensity100;
bool knownnightlight = nightlightActive;
bool wificonnected = interfacesInited;
bool powerON = true;
bool displayTurnedOff = false;
unsigned long nextUpdate = 0;
unsigned long lastRedraw = 0;
unsigned long overlayUntil = 0;
// Set to 2 or 3 to mark lines 2 or 3. Other values ignored.
byte markLineNum = 255;
byte markColNum = 255;
// strings to reduce flash memory usage (used more than twice)
static const char _name[];
static const char _enabled[];
static const char _contrast[];
static const char _refreshRate[];
static const char _screenTimeOut[];
static const char _flip[];
static const char _sleepMode[];
static const char _clockMode[];
static const char _showSeconds[];
static const char _busClkFrequency[];
static const char _contrastFix[];
// If display does not work or looks corrupted check the
// constructor reference:
// https://github.com/olikraus/u8g2/wiki/u8x8setupcpp
// or check the gallery:
// https://github.com/olikraus/u8g2/wiki/gallery
// some displays need this to properly apply contrast
void setVcomh(bool highContrast);
void startDisplay();
/**
* Wrappers for screen drawing
*/
void setFlipMode(uint8_t mode);
void setContrast(uint8_t contrast);
void drawString(uint8_t col, uint8_t row, const char *string, bool ignoreLH=false);
void draw2x2String(uint8_t col, uint8_t row, const char *string);
void drawGlyph(uint8_t col, uint8_t row, char glyph, const uint8_t *font, bool ignoreLH=false);
void draw2x2Glyph(uint8_t col, uint8_t row, char glyph, const uint8_t *font);
void draw2x2GlyphIcons();
uint8_t getCols();
void clear();
void setPowerSave(uint8_t save);
void center(String &line, uint8_t width);
/**
* Display the current date and time in large characters
* on the middle rows. Based 24 or 12 hour depending on
* the useAMPM configuration.
*/
void showTime();
/**
* Enable sleep (turn the display off) or clock mode.
*/
void sleepOrClock(bool enabled);
public:
// gets called once at boot. Do all initialization that doesn't depend on
// network here
void setup() override;
// gets called every time WiFi is (re-)connected. Initialize own network
// interfaces here
void connected() override;
/**
* Da loop.
*/
void loop() override;
//function to update lastredraw
inline void updateRedrawTime() { lastRedraw = millis(); }
/**
* Redraw the screen (but only if things have changed
* or if forceRedraw).
*/
void redraw(bool forceRedraw);
void updateBrightness();
void updateSpeed();
void updateIntensity();
void drawStatusIcons();
/**
* marks the position of the arrow showing
* the current setting being changed
* pass line and colum info
*/
void setMarkLine(byte newMarkLineNum, byte newMarkColNum);
//Draw the arrow for the current setting being changed
void drawArrow();
//Display the current effect or palette (desiredEntry)
// on the appropriate line (row).
void showCurrentEffectOrPalette(int inputEffPal, const char *qstring, uint8_t row);
/**
* If there screen is off or in clock is displayed,
* this will return true. This allows us to throw away
* the first input from the rotary encoder but
* to wake up the screen.
*/
bool wakeDisplay();
/**
* Allows you to show one line and a glyph as overlay for a period of time.
* Clears the screen and prints.
* Used in Rotary Encoder usermod.
*/
void overlay(const char* line1, long showHowLong, byte glyphType);
/**
* Allows you to show Akemi WLED logo overlay for a period of time.
* Clears the screen and prints.
*/
void overlayLogo(long showHowLong);
/**
* Allows you to show two lines as overlay for a period of time.
* Clears the screen and prints.
* Used in Auto Save usermod
*/
void overlay(const char* line1, const char* line2, long showHowLong);
void networkOverlay(const char* line1, long showHowLong);
/**
* handleButton() can be used to override default button behaviour. Returning true
* will prevent button working in a default way.
* Replicating button.cpp
*/
bool handleButton(uint8_t b);
void onUpdateBegin(bool init) override;
/*
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
* Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI.
* Below it is shown how this could be used for e.g. a light sensor
*/
//void addToJsonInfo(JsonObject& root) override;
/*
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
* Values in the state object may be modified by connected clients
*/
//void addToJsonState(JsonObject& root) override;
/*
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
* Values in the state object may be modified by connected clients
*/
//void readFromJsonState(JsonObject& root) override;
void appendConfigData() override;
/*
* addToConfig() can be used to add custom persistent settings to the cfg.json file in the "um" (usermod) object.
* It will be called by WLED when settings are actually saved (for example, LED settings are saved)
* If you want to force saving the current state, use serializeConfig() in your loop().
*
* CAUTION: serializeConfig() will initiate a filesystem write operation.
* It might cause the LEDs to stutter and will cause flash wear if called too often.
* Use it sparingly and always in the loop, never in network callbacks!
*
* addToConfig() will also not yet add your setting to one of the settings pages automatically.
* To make that work you still have to add the setting to the HTML, xml.cpp and set.cpp manually.
*
* I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings!
*/
void addToConfig(JsonObject& root) override;
/*
* readFromConfig() can be used to read back the custom settings you added with addToConfig().
* This is called by WLED when settings are loaded (currently this only happens once immediately after boot)
*
* readFromConfig() is called BEFORE setup(). This means you can use your persistent values in setup() (e.g. pin assignments, buffer sizes),
* but also that if you want to write persistent values to a dynamic buffer, you'd need to allocate it here instead of in setup.
* If you don't know what that is, don't fret. It most likely doesn't affect your use case :)
*/
bool readFromConfig(JsonObject& root) override;
/*
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
* This could be used in the future for the system to determine whether your usermod is installed.
*/
uint16_t getId() override {
return USERMOD_ID_FOUR_LINE_DISP;
}
};

View File

@ -1,11 +1,5 @@
#include "wled.h"
#undef U8X8_NO_HW_I2C // borrowed from WLEDMM: we do want I2C hardware drivers - if possible
#include <U8x8lib.h> // from https://github.com/olikraus/u8g2/
#include "4LD_wled_fonts.c"
#ifndef FLD_ESP32_NO_THREADS
#define FLD_ESP32_USE_THREADS // comment out to use 0.13.x behaviour without parallel update task - slower, but more robust. May delay other tasks like LEDs or audioreactive!!
#endif
#include "usermod_v2_four_line_display.h"
#include "4LD_wled_fonts.h"
//
// Inspired by the usermod_v2_four_line_display
@ -20,330 +14,18 @@
//
// Make sure to enable NTP and set your time zone in WLED Config | Time.
//
// REQUIREMENT: You must add the following requirements to
// REQUIREMENT: "lib_deps" within platformio.ini / platformio_override.ini
// REQUIREMENT: * U8g2 (the version already in platformio.ini is fine)
// REQUIREMENT: * Wire
//
// If display does not work or looks corrupted check the
// constructor reference:
// https://github.com/olikraus/u8g2/wiki/u8x8setupcpp
// or check the gallery:
// https://github.com/olikraus/u8g2/wiki/gallery
#ifndef FLD_PIN_CS
#define FLD_PIN_CS 15
#endif
#ifdef ARDUINO_ARCH_ESP32
#ifndef FLD_PIN_DC
#define FLD_PIN_DC 19
#endif
#ifndef FLD_PIN_RESET
#define FLD_PIN_RESET 26
#endif
#else
#ifndef FLD_PIN_DC
#define FLD_PIN_DC 12
#endif
#ifndef FLD_PIN_RESET
#define FLD_PIN_RESET 16
#endif
#endif
#ifndef FLD_TYPE
#ifndef FLD_SPI_DEFAULT
#define FLD_TYPE SSD1306
#else
#define FLD_TYPE SSD1306_SPI
#endif
#endif
// When to time out to the clock or blank the screen
// if SLEEP_MODE_ENABLED.
#define SCREEN_TIMEOUT_MS 60*1000 // 1 min
// Minimum time between redrawing screen in ms
#define REFRESH_RATE_MS 1000
// Extra char (+1) for null
#define LINE_BUFFER_SIZE 16+1
#define MAX_JSON_CHARS 19+1
#define MAX_MODE_LINE_SPACE 13+1
#ifdef ARDUINO_ARCH_ESP32
static TaskHandle_t Display_Task = nullptr;
void DisplayTaskCode(void * parameter);
#endif
typedef enum {
NONE = 0,
SSD1306, // U8X8_SSD1306_128X32_UNIVISION_HW_I2C
SH1106, // U8X8_SH1106_128X64_WINSTAR_HW_I2C
SSD1306_64, // U8X8_SSD1306_128X64_NONAME_HW_I2C
SSD1305, // U8X8_SSD1305_128X32_ADAFRUIT_HW_I2C
SSD1305_64, // U8X8_SSD1305_128X64_ADAFRUIT_HW_I2C
SSD1306_SPI, // U8X8_SSD1306_128X32_NONAME_HW_SPI
SSD1306_SPI64, // U8X8_SSD1306_128X64_NONAME_HW_SPI
SSD1309_SPI64, // U8X8_SSD1309_128X64_NONAME0_4W_HW_SPI
SSD1309_64 // U8X8_SSD1309_128X64_NONAME0_HW_I2C
} DisplayType;
class FourLineDisplayUsermod : public Usermod {
#if defined(ARDUINO_ARCH_ESP32) && defined(FLD_ESP32_USE_THREADS)
public:
FourLineDisplayUsermod() { if (!instance) instance = this; }
static FourLineDisplayUsermod* getInstance(void) { return instance; }
#endif
private:
static FourLineDisplayUsermod *instance;
bool initDone = false;
volatile bool drawing = false;
volatile bool lockRedraw = false;
// HW interface & configuration
U8X8 *u8x8 = nullptr; // pointer to U8X8 display object
#ifndef FLD_SPI_DEFAULT
int8_t ioPin[3] = {-1, -1, -1}; // I2C pins: SCL, SDA
uint32_t ioFrequency = 400000; // in Hz (minimum is 100000, baseline is 400000 and maximum should be 3400000)
#else
int8_t ioPin[3] = {FLD_PIN_CS, FLD_PIN_DC, FLD_PIN_RESET}; // custom SPI pins: CS, DC, RST
uint32_t ioFrequency = 1000000; // in Hz (minimum is 500kHz, baseline is 1MHz and maximum should be 20MHz)
#endif
DisplayType type = FLD_TYPE; // display type
bool flip = false; // flip display 180°
uint8_t contrast = 10; // screen contrast
uint8_t lineHeight = 1; // 1 row or 2 rows
uint16_t refreshRate = REFRESH_RATE_MS; // in ms
uint32_t screenTimeout = SCREEN_TIMEOUT_MS; // in ms
bool sleepMode = true; // allow screen sleep?
bool clockMode = false; // display clock
bool showSeconds = true; // display clock with seconds
bool enabled = true;
bool contrastFix = false;
// Next variables hold the previous known values to determine if redraw is
// required.
String knownSsid = apSSID;
IPAddress knownIp = IPAddress(4, 3, 2, 1);
uint8_t knownBrightness = 0;
uint8_t knownEffectSpeed = 0;
uint8_t knownEffectIntensity = 0;
uint8_t knownMode = 0;
uint8_t knownPalette = 0;
uint8_t knownMinute = 99;
uint8_t knownHour = 99;
byte brightness100;
byte fxspeed100;
byte fxintensity100;
bool knownnightlight = nightlightActive;
bool wificonnected = interfacesInited;
bool powerON = true;
bool displayTurnedOff = false;
unsigned long nextUpdate = 0;
unsigned long lastRedraw = 0;
unsigned long overlayUntil = 0;
// Set to 2 or 3 to mark lines 2 or 3. Other values ignored.
byte markLineNum = 255;
byte markColNum = 255;
// strings to reduce flash memory usage (used more than twice)
static const char _name[];
static const char _enabled[];
static const char _contrast[];
static const char _refreshRate[];
static const char _screenTimeOut[];
static const char _flip[];
static const char _sleepMode[];
static const char _clockMode[];
static const char _showSeconds[];
static const char _busClkFrequency[];
static const char _contrastFix[];
// If display does not work or looks corrupted check the
// constructor reference:
// https://github.com/olikraus/u8g2/wiki/u8x8setupcpp
// or check the gallery:
// https://github.com/olikraus/u8g2/wiki/gallery
// some displays need this to properly apply contrast
void setVcomh(bool highContrast);
void startDisplay();
/**
* Wrappers for screen drawing
*/
void setFlipMode(uint8_t mode);
void setContrast(uint8_t contrast);
void drawString(uint8_t col, uint8_t row, const char *string, bool ignoreLH=false);
void draw2x2String(uint8_t col, uint8_t row, const char *string);
void drawGlyph(uint8_t col, uint8_t row, char glyph, const uint8_t *font, bool ignoreLH=false);
void draw2x2Glyph(uint8_t col, uint8_t row, char glyph, const uint8_t *font);
void draw2x2GlyphIcons();
uint8_t getCols();
void clear();
void setPowerSave(uint8_t save);
void center(String &line, uint8_t width);
/**
* Display the current date and time in large characters
* on the middle rows. Based 24 or 12 hour depending on
* the useAMPM configuration.
*/
void showTime();
/**
* Enable sleep (turn the display off) or clock mode.
*/
void sleepOrClock(bool enabled);
public:
// gets called once at boot. Do all initialization that doesn't depend on
// network here
void setup() override;
// gets called every time WiFi is (re-)connected. Initialize own network
// interfaces here
void connected() override;
/**
* Da loop.
*/
void loop() override;
//function to update lastredraw
inline void updateRedrawTime() { lastRedraw = millis(); }
/**
* Redraw the screen (but only if things have changed
* or if forceRedraw).
*/
void redraw(bool forceRedraw);
void updateBrightness();
void updateSpeed();
void updateIntensity();
void drawStatusIcons();
/**
* marks the position of the arrow showing
* the current setting being changed
* pass line and colum info
*/
void setMarkLine(byte newMarkLineNum, byte newMarkColNum);
//Draw the arrow for the current setting being changed
void drawArrow();
//Display the current effect or palette (desiredEntry)
// on the appropriate line (row).
void showCurrentEffectOrPalette(int inputEffPal, const char *qstring, uint8_t row);
/**
* If there screen is off or in clock is displayed,
* this will return true. This allows us to throw away
* the first input from the rotary encoder but
* to wake up the screen.
*/
bool wakeDisplay();
/**
* Allows you to show one line and a glyph as overlay for a period of time.
* Clears the screen and prints.
* Used in Rotary Encoder usermod.
*/
void overlay(const char* line1, long showHowLong, byte glyphType);
/**
* Allows you to show Akemi WLED logo overlay for a period of time.
* Clears the screen and prints.
*/
void overlayLogo(long showHowLong);
/**
* Allows you to show two lines as overlay for a period of time.
* Clears the screen and prints.
* Used in Auto Save usermod
*/
void overlay(const char* line1, const char* line2, long showHowLong);
void networkOverlay(const char* line1, long showHowLong);
/**
* handleButton() can be used to override default button behaviour. Returning true
* will prevent button working in a default way.
* Replicating button.cpp
*/
bool handleButton(uint8_t b);
void onUpdateBegin(bool init) override;
/*
* addToJsonInfo() can be used to add custom entries to the /json/info part of the JSON API.
* Creating an "u" object allows you to add custom key/value pairs to the Info section of the WLED web UI.
* Below it is shown how this could be used for e.g. a light sensor
*/
//void addToJsonInfo(JsonObject& root) override;
/*
* addToJsonState() can be used to add custom entries to the /json/state part of the JSON API (state object).
* Values in the state object may be modified by connected clients
*/
//void addToJsonState(JsonObject& root) override;
/*
* readFromJsonState() can be used to receive data clients send to the /json/state part of the JSON API (state object).
* Values in the state object may be modified by connected clients
*/
//void readFromJsonState(JsonObject& root) override;
void appendConfigData() override;
/*
* addToConfig() can be used to add custom persistent settings to the cfg.json file in the "um" (usermod) object.
* It will be called by WLED when settings are actually saved (for example, LED settings are saved)
* If you want to force saving the current state, use serializeConfig() in your loop().
*
* CAUTION: serializeConfig() will initiate a filesystem write operation.
* It might cause the LEDs to stutter and will cause flash wear if called too often.
* Use it sparingly and always in the loop, never in network callbacks!
*
* addToConfig() will also not yet add your setting to one of the settings pages automatically.
* To make that work you still have to add the setting to the HTML, xml.cpp and set.cpp manually.
*
* I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings!
*/
void addToConfig(JsonObject& root) override;
/*
* readFromConfig() can be used to read back the custom settings you added with addToConfig().
* This is called by WLED when settings are loaded (currently this only happens once immediately after boot)
*
* readFromConfig() is called BEFORE setup(). This means you can use your persistent values in setup() (e.g. pin assignments, buffer sizes),
* but also that if you want to write persistent values to a dynamic buffer, you'd need to allocate it here instead of in setup.
* If you don't know what that is, don't fret. It most likely doesn't affect your use case :)
*/
bool readFromConfig(JsonObject& root) override;
/*
* getId() allows you to optionally give your V2 usermod an unique ID (please define it in const.h!).
* This could be used in the future for the system to determine whether your usermod is installed.
*/
uint16_t getId() override {
return USERMOD_ID_FOUR_LINE_DISP;
}
};
// strings to reduce flash memory usage (used more than twice)
const char FourLineDisplayUsermod::_name[] PROGMEM = "4LineDisplay";
const char FourLineDisplayUsermod::_enabled[] PROGMEM = "enabled";
@ -1387,4 +1069,4 @@ bool FourLineDisplayUsermod::readFromConfig(JsonObject& root) {
static FourLineDisplayUsermod usermod_v2_four_line_display_alt;
REGISTER_USERMOD(usermod_v2_four_line_display_alt);
REGISTER_USERMOD(usermod_v2_four_line_display_alt);

View File

@ -1,3 +1,3 @@
{
"name:": "usermod_v2_klipper_percentage"
"name": "usermod_v2_klipper_percentage"
}

View File

@ -1,3 +1,3 @@
{
"name:": "usermod_v2_ping_pong_clock"
"name": "usermod_v2_ping_pong_clock"
}

View File

@ -1,3 +1,6 @@
{
"name:": "usermod_v2_rotary_encoder_ui_ALT"
"name": "rotary_encoder_ui_ALT",
"build": {
"extraScript": "setup_deps.py"
}
}

View File

@ -1,13 +1,11 @@
[platformio]
default_envs = esp32dev
default_envs = esp32dev_re
[env:esp32dev]
board = esp32dev
platform = ${esp32.platform}
build_unflags = ${common.build_unflags}
[env:esp32dev_re]
extends = env:esp32dev_V4
custom_usermods = ${env:esp32dev_V4.custom_usermods} rotary_encoder_ui_ALT
build_flags =
${common.build_flags_esp32}
-D USERMOD_ROTARY_ENCODER_UI
${env:esp32dev_V4.build_flags}
-D USERMOD_ROTARY_ENCODER_GPIO=INPUT
-D ENCODER_DT_PIN=21
-D ENCODER_CLK_PIN=23

View File

@ -25,10 +25,6 @@ Copy the example `platformio_override.sample.ini` to the root directory of your
### Define Your Options
* `USERMOD_ROTARY_ENCODER_UI` - define this to have this user mod included wled00\usermods_list.cpp
* `USERMOD_FOUR_LINE_DISPLAY` - define this to have this the Four Line Display mod included wled00\usermods_list.cpp
also tells this usermod that the display is available
(see the Four Line Display usermod `readme.md` for more details)
* `ENCODER_DT_PIN` - defaults to 18
* `ENCODER_CLK_PIN` - defaults to 5
* `ENCODER_SW_PIN` - defaults to 19

View File

@ -0,0 +1,8 @@
Import('env')
usermods = env.GetProjectOption("custom_usermods","").split()
# Check for partner usermod
# Allow both "usermod_v2" and unqualified syntax
if any(mod in ("four_line_display_ALT", "usermod_v2_four_line_display_ALT") for mod in usermods):
env.Append(CPPDEFINES=[("USERMOD_FOUR_LINE_DISPLAY")])

View File

@ -27,6 +27,10 @@
// * display network (long press buttion)
//
#ifdef USERMOD_FOUR_LINE_DISPLAY
#include "usermod_v2_four_line_display.h"
#endif
#ifdef USERMOD_MODE_SORT
#error "Usermod Mode Sort is no longer required. Remove -D USERMOD_MODE_SORT from platformio.ini"
#endif

View File

@ -1,3 +1,3 @@
{
"name:": "usermod_v2_word_clock"
"name": "usermod_v2_word_clock"
}

View File

@ -1,5 +1,5 @@
{
"name:": "wireguard",
"name": "wireguard",
"build": { "libArchive": false},
"dependencies": {
"WireGuard-ESP32-Arduino":"https://github.com/kienvu58/WireGuard-ESP32-Arduino.git"

View File

@ -1,3 +1,3 @@
{
"name:": "wizlights"
"name": "wizlights"
}

View File

@ -0,0 +1,3 @@
{
"name": "word-clock-matrix"
}

View File

@ -1,3 +0,0 @@
{
"name:": "word-clock-matrix"
}

View File

@ -36,8 +36,8 @@ public:
//other segments are text
for (int i = 1; i < 10; i++)
{
Segment &seg = strip.getSegment(i);
seg.colors[0] = ((0 << 24) | ((0 & 0xFF) << 16) | ((190 & 0xFF) << 8) | ((180 & 0xFF)));
Segment &text_seg = strip.getSegment(i);
text_seg.colors[0] = ((0 << 24) | ((0 & 0xFF) << 16) | ((190 & 0xFF) << 8) | ((180 & 0xFF)));
strip.getSegment(i).setOption(0, true);
strip.setBrightness(64);
}
@ -67,7 +67,7 @@ public:
//strip.resetSegments();
selectWordSegments(true);
colorUpdated(CALL_MODE_FX_CHANGED);
savePreset(13, false);
savePreset(13);
selectWordSegments(false);
//strip.getSegment(0).setOption(0, true);
strip.getSegment(0).setOption(2, true);
@ -329,7 +329,7 @@ public:
uint16_t getId()
{
return USERMOD_ID_WORD_CLOCK_MATRIX;
return 500;
}