Merge branch 'main' into usermod-libs-matrix

This commit is contained in:
Will Tatam 2025-06-14 20:17:00 +01:00
commit 7835550f1a
150 changed files with 4651 additions and 4142 deletions

View File

@ -1,5 +1,6 @@
name: Notify Discord on PR Merge
on:
workflow_dispatch:
pull_request:
types: [closed]
@ -7,10 +8,29 @@
notify:
runs-on: ubuntu-latest
steps:
- name: Get User Permission
id: checkAccess
uses: actions-cool/check-user-permission@v2
with:
require: write
username: ${{ github.triggering_actor }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Check User Permission
if: steps.checkAccess.outputs.require-result == 'false'
run: |
echo "${{ github.triggering_actor }} does not have permissions on this repo."
echo "Current permission level is ${{ steps.checkAccess.outputs.user-permission }}"
echo "Job originally triggered by ${{ github.actor }}"
exit 1
- name: Checkout code
uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.sha }} # This is dangerous without the first access check
- name: Send Discord notification
shell: bash
env:
DISCORD_WEBHOOK_BETA_TESTERS: ${{ secrets.DISCORD_WEBHOOK_BETA_TESTERS }}
if: github.event.pull_request.merged == true
# if: github.event.pull_request.merged == true
run: |
curl -H "Content-Type: application/json" -d '{"content": "Pull Request #{{ github.event.pull_request.number }} merged by {{ github.actor }}"}' $DISCORD_WEBHOOK_BETA_TESTERS
curl -H "Content-Type: application/json" -d '{"content": "Pull Request ${{ github.event.pull_request.number }} merged by ${{ github.actor }}"}' $DISCORD_WEBHOOK_BETA_TESTERS

6
package-lock.json generated
View File

@ -129,9 +129,9 @@
}
},
"node_modules/brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"version": "1.1.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
"integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0",

View File

@ -1,17 +1,14 @@
Import('env')
import os.path
from collections import deque
from pathlib import Path # For OS-agnostic path manipulation
from platformio.package.manager.library import LibraryPackageManager
from click import secho
from SCons.Script import Exit
from platformio.builder.tools.piolib import LibBuilderBase
usermod_dir = Path(env["PROJECT_DIR"]) / "usermods"
all_usermods = [f for f in usermod_dir.iterdir() if f.is_dir() and f.joinpath('library.json').exists()]
usermod_dir = Path(env["PROJECT_DIR"]).resolve() / "usermods"
if env['PIOENV'] == "usermods":
# Add all usermods
env.GetProjectConfig().set(f"env:usermods", 'custom_usermods', " ".join([f.name for f in all_usermods]))
def find_usermod(mod: str):
# Utility functions
def find_usermod(mod: str) -> Path:
"""Locate this library in the usermods folder.
We do this to avoid needing to rename a bunch of folders;
this could be removed later
@ -22,51 +19,36 @@ def find_usermod(mod: str):
return mp
mp = usermod_dir / f"{mod}_v2"
if mp.exists():
return mp
return mp
mp = usermod_dir / f"usermod_v2_{mod}"
if mp.exists():
return mp
raise RuntimeError(f"Couldn't locate module {mod} in usermods directory!")
def is_wled_module(dep: LibBuilderBase) -> bool:
"""Returns true if the specified library is a wled module
"""
return usermod_dir in Path(dep.src_dir).parents or str(dep.name).startswith("wled-")
## Script starts here
# Process usermod option
usermods = env.GetProjectOption("custom_usermods","")
# Handle "all usermods" case
if usermods == '*':
usermods = [f.name for f in usermod_dir.iterdir() if f.is_dir() and f.joinpath('library.json').exists()]
else:
usermods = usermods.split()
if usermods:
# Inject usermods in to project lib_deps
proj = env.GetProjectConfig()
deps = env.GetProjectOption('lib_deps')
src_dir = proj.get("platformio", "src_dir")
src_dir = src_dir.replace('\\','/')
mod_paths = {mod: find_usermod(mod) for mod in usermods.split()}
usermods = [f"{mod} = symlink://{path}" for mod, path in mod_paths.items()]
proj.set("env:" + env['PIOENV'], 'lib_deps', deps + usermods)
# Force usermods to be installed in to the environment build state before the LDF runs
# Otherwise we won't be able to see them until it's too late to change their paths for LDF
# Logic is largely borrowed from PlaformIO internals
not_found_specs = []
for spec in usermods:
found = False
for storage_dir in env.GetLibSourceDirs():
#print(f"Checking {storage_dir} for {spec}")
lm = LibraryPackageManager(storage_dir)
if lm.get_package(spec):
#print("Found!")
found = True
break
if not found:
#print("Missing!")
not_found_specs.append(spec)
if not_found_specs:
lm = LibraryPackageManager(
env.subst(os.path.join("$PROJECT_LIBDEPS_DIR", "$PIOENV"))
)
for spec in not_found_specs:
#print(f"LU: forcing install of {spec}")
lm.install(spec)
symlinks = [f"symlink://{find_usermod(mod).resolve()}" for mod in usermods]
env.GetProjectConfig().set("env:" + env['PIOENV'], 'lib_deps', env.GetProjectOption('lib_deps') + symlinks)
# Utility function for assembling usermod include paths
def cached_add_includes(dep, dep_cache: set, includes: deque):
""" Add dep's include paths to includes if it's not in the cache """
if dep not in dep_cache:
if dep not in dep_cache:
dep_cache.add(dep)
for include in dep.get_include_dirs():
if include not in includes:
@ -82,13 +64,6 @@ old_ConfigureProjectLibBuilder = env.ConfigureProjectLibBuilder
# Our new wrapper
def wrapped_ConfigureProjectLibBuilder(xenv):
# Update usermod properties
# Set libArchive before build actions are added
for um in (um for um in xenv.GetLibBuilders() if usermod_dir in Path(um.src_dir).parents):
build = um._manifest.get("build", {})
build["libArchive"] = False
um._manifest["build"] = build
# Call the wrapped function
result = old_ConfigureProjectLibBuilder.clone(xenv)()
@ -102,12 +77,25 @@ def wrapped_ConfigureProjectLibBuilder(xenv):
for dep in result.depbuilders:
cached_add_includes(dep, processed_deps, extra_include_dirs)
for um in [dep for dep in result.depbuilders if usermod_dir in Path(dep.src_dir).parents]:
# Add the wled folder to the include path
um.env.PrependUnique(CPPPATH=wled_dir)
# Add WLED's own dependencies
for dir in extra_include_dirs:
um.env.PrependUnique(CPPPATH=dir)
broken_usermods = []
for dep in result.depbuilders:
if is_wled_module(dep):
# Add the wled folder to the include path
dep.env.PrependUnique(CPPPATH=str(wled_dir))
# Add WLED's own dependencies
for dir in extra_include_dirs:
dep.env.PrependUnique(CPPPATH=str(dir))
# Enforce that libArchive is not set; we must link them directly to the executable
if dep.lib_archive:
broken_usermods.append(dep)
if broken_usermods:
broken_usermods = [usermod.name for usermod in broken_usermods]
secho(
f"ERROR: libArchive=false is missing on usermod(s) {' '.join(broken_usermods)} -- modules will not compile in correctly",
fg="red",
err=True)
Exit(1)
return result

View File

@ -0,0 +1,92 @@
import re
from pathlib import Path # For OS-agnostic path manipulation
from typing import Iterable
from click import secho
from SCons.Script import Action, Exit
from platformio.builder.tools.piolib import LibBuilderBase
def is_wled_module(env, dep: LibBuilderBase) -> bool:
"""Returns true if the specified library is a wled module
"""
usermod_dir = Path(env["PROJECT_DIR"]).resolve() / "usermods"
return usermod_dir in Path(dep.src_dir).parents or str(dep.name).startswith("wled-")
def read_lines(p: Path):
""" Read in the contents of a file for analysis """
with p.open("r", encoding="utf-8", errors="ignore") as f:
return f.readlines()
def check_map_file_objects(map_file: list[str], dirs: Iterable[str]) -> set[str]:
""" Identify which dirs contributed to the final build
Returns the (sub)set of dirs that are found in the output ELF
"""
# Pattern to match symbols in object directories
# Join directories into alternation
usermod_dir_regex = "|".join([re.escape(dir) for dir in dirs])
# Matches nonzero address, any size, and any path in a matching directory
object_path_regex = re.compile(r"0x0*[1-9a-f][0-9a-f]*\s+0x[0-9a-f]+\s+\S+[/\\](" + usermod_dir_regex + r")[/\\]\S+\.o")
found = set()
for line in map_file:
matches = object_path_regex.findall(line)
for m in matches:
found.add(m)
return found
def count_usermod_objects(map_file: list[str]) -> int:
""" Returns the number of usermod objects in the usermod list """
# Count the number of entries in the usermods table section
return len([x for x in map_file if ".dtors.tbl.usermods.1" in x])
def validate_map_file(source, target, env):
""" Validate that all modules appear in the output build """
build_dir = Path(env.subst("$BUILD_DIR"))
map_file_path = build_dir / env.subst("${PROGNAME}.map")
if not map_file_path.exists():
secho(f"ERROR: Map file not found: {map_file_path}", fg="red", err=True)
Exit(1)
# Identify the WLED module source directories
module_lib_builders = [builder for builder in env.GetLibBuilders() if is_wled_module(env, builder)]
if env.GetProjectOption("custom_usermods","") == "*":
# All usermods build; filter non-platform-OK modules
module_lib_builders = [builder for builder in module_lib_builders if env.IsCompatibleLibBuilder(builder)]
else:
incompatible_builders = [builder for builder in module_lib_builders if not env.IsCompatibleLibBuilder(builder)]
if incompatible_builders:
secho(
f"ERROR: Modules {[b.name for b in incompatible_builders]} are not compatible with this platform!",
fg="red",
err=True)
Exit(1)
# Extract the values we care about
modules = {Path(builder.build_dir).name: builder.name for builder in module_lib_builders}
secho(f"INFO: {len(modules)} libraries linked as WLED optional/user modules")
# Now parse the map file
map_file_contents = read_lines(map_file_path)
usermod_object_count = count_usermod_objects(map_file_contents)
secho(f"INFO: {usermod_object_count} usermod object entries")
confirmed_modules = check_map_file_objects(map_file_contents, modules.keys())
missing_modules = [modname for mdir, modname in modules.items() if mdir not in confirmed_modules]
if missing_modules:
secho(
f"ERROR: No object files from {missing_modules} found in linked output!",
fg="red",
err=True)
Exit(1)
return None
Import("env")
env.Append(LINKFLAGS=[env.subst("-Wl,--Map=${BUILD_DIR}/${PROGNAME}.map")])
env.AddPostAction("$BUILD_DIR/${PROGNAME}.elf", Action(validate_map_file, cmdstr='Checking linked optional modules (usermods) in map file'))

View File

@ -116,6 +116,7 @@ extra_scripts =
pre:pio-scripts/user_config_copy.py
pre:pio-scripts/load_usermods.py
pre:pio-scripts/build_ui.py
post:pio-scripts/validate_modules.py ;; double-check the build output usermods
; post:pio-scripts/obj-dump.py ;; convenience script to create a disassembly dump of the firmware (hardcore debugging)
# ------------------------------------------------------------------------------
@ -659,5 +660,5 @@ build_flags = ${common.build_flags} ${esp32_idf_V4.build_flags} -D WLED_RELEASE_
lib_deps = ${esp32_idf_V4.lib_deps}
monitor_filters = esp32_exception_decoder
board_build.flash_mode = dio
; custom_usermods = *every folder with library.json* -- injected by pio-scripts/load_usermods.py
custom_usermods = * ; Expands to all usermods in usermods folder
board_build.partitions = ${esp32.extreme_partitions} ; We're gonna need a bigger boat

View File

@ -38,7 +38,7 @@ pyelftools==0.32
# via platformio
pyserial==3.5
# via platformio
requests==2.32.3
requests==2.32.4
# via platformio
semantic-version==2.10.0
# via platformio

View File

@ -1,5 +1,6 @@
{
"name:": "ADS1115_v2",
"name": "ADS1115_v2",
"build": { "libArchive": false },
"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,6 @@
{
"name:": "AHT10_v2",
"name": "AHT10_v2",
"build": { "libArchive": false },
"dependencies": {
"enjoyneering/AHT10":"~1.1.0"
}

View File

@ -102,9 +102,9 @@ private:
void secondsEffectSineFade(int16_t secondLed, Toki::Time const& time) {
uint32_t ms = time.ms % 1000;
uint8_t b0 = (cos8_t(ms * 64 / 1000) - 128) * 2;
setPixelColor(secondLed, gamma32(scale32(secondColor, b0)));
setPixelColor(secondLed, scale32(secondColor, b0));
uint8_t b1 = (sin8_t(ms * 64 / 1000) - 128) * 2;
setPixelColor(inc(secondLed, 1, secondsSegment), gamma32(scale32(secondColor, b1)));
setPixelColor(inc(secondLed, 1, secondsSegment), scale32(secondColor, b1));
}
static inline uint32_t qadd32(uint32_t c1, uint32_t c2) {
@ -191,7 +191,7 @@ public:
// for (uint16_t i = 1; i < secondsTrail + 1; ++i) {
// uint16_t trailLed = dec(secondLed, i, secondsSegment);
// uint8_t trailBright = 255 / (secondsTrail + 1) * (secondsTrail - i + 1);
// setPixelColor(trailLed, gamma32(scale32(secondColor, trailBright)));
// setPixelColor(trailLed, scale32(secondColor, trailBright));
// }
}

View File

@ -1,3 +1,4 @@
{
"name:": "Analog_Clock"
"name": "Analog_Clock",
"build": { "libArchive": false }
}

View File

@ -1,4 +1,5 @@
# Usermod Animated Staircase
This usermod makes your staircase look cool by illuminating it with an animation. It uses
PIR or ultrasonic sensors at the top and bottom of your stairs to:
@ -11,11 +12,13 @@ The Animated Staircase can be controlled by the WLED API. Change settings such a
speed, on/off time and distance by sending an HTTP request, see below.
## WLED integration
To include this usermod in your WLED setup, you have to be able to [compile WLED from source](https://kno.wled.ge/advanced/compiling-wled/).
Before compiling, you have to make the following modifications:
Edit your environment in `platformio_override.ini`
1. Open `platformio_override.ini`
2. add `Animated_Staircase` to the `custom_usermods` line for your environment
@ -25,10 +28,10 @@ If you use PIR sensor enter -1 for echo pin.
Maximum distance for ultrasonic sensor can be configured as the time needed for an echo (see below).
## Hardware installation
1. Attach the LED strip to each step of the stairs.
2. Connect the ESP8266 pin D4 or ESP32 pin D2 to the first LED data pin at the bottom step.
3. Connect the data-out pin at the end of each strip per step to the data-in pin on the
next step, creating one large virtual LED strip.
3. Connect the data-out pin at the end of each strip per step to the data-in pin on the next step, creating one large virtual LED strip.
4. Mount sensors of choice at the bottom and top of the stairs and connect them to the ESP.
5. To make sure all LEDs get enough power and have your staircase lighted evenly, power each
step from one side, using at least AWG14 or 2.5mm^2 cable. Don't connect them serial as you
@ -37,24 +40,23 @@ Maximum distance for ultrasonic sensor can be configured as the time needed for
You _may_ need to use 10k pull-down resistors on the selected PIR pins, depending on the sensor.
## WLED configuration
1. In the WLED UI, configure a segment for each step. The lowest step of the stairs is the
lowest segment id.
2. Save your segments into a preset.
3. Ideally, add the preset in the config > LED setup menu to the "apply
preset **n** at boot" setting.
1. In the WLED UI, configure a segment for each step. The lowest step of the stairs is the lowest segment id.
2. Save your segments into a preset.
3. Ideally, add the preset in the config > LED setup menu to the "apply preset **n** at boot" setting.
## Changing behavior through API
The Staircase settings can be changed through the WLED JSON api.
**NOTE:** We are using [curl](https://curl.se/) to send HTTP POSTs to the WLED API.
If you're using Windows and want to use the curl commands, replace the `\` with a `^`
or remove them and put everything on one line.
| Setting | Description | Default |
|------------------|---------------------------------------------------------------|---------|
| enabled | Enable or disable the usermod | true |
| bottom-sensor | Manually trigger a down to up animation via API | false |
| bottom-sensor | Manually trigger a down to up animation via API | false |
| top-sensor | Manually trigger an up to down animation via API | false |
@ -74,6 +76,7 @@ The staircase settings and sensor states are inside the WLED "state" element:
```
### Enable/disable the usermod
By disabling the usermod you will be able to keep the LED's on, independent from the sensor
activity. This enables you to play with the lights without the usermod switching them on or off.
@ -90,6 +93,7 @@ To enable the usermod again, use `"enabled":true`.
Alternatively you can use _Usermod_ Settings page where you can change other parameters as well.
### Changing animation parameters and detection range of the ultrasonic HC-SR04 sensor
Using _Usermod_ Settings page you can define different usermod parameters, including sensor pins, delay between segment activation etc.
When an ultrasonic sensor is enabled you can enter maximum detection distance in centimeters separately for top and bottom sensors.
@ -99,6 +103,7 @@ distances creates delays in the WLED software, _might_ introduce timing hiccups
a less responsive web interface. It is therefore advised to keep the detection distance as short as possible.
### Animation triggering through the API
In addition to activation by one of the stair sensors, you can also trigger the animation manually
via the API. To simulate triggering the bottom sensor, use:
@ -115,15 +120,19 @@ curl -X POST -H "Content-Type: application/json" \
-d '{"staircase":{"top-sensor":true}}' \
xxx.xxx.xxx.xxx/json/state
```
**MQTT**
You can publish a message with either `up` or `down` on topic `/swipe` to trigger animation.
You can also use `on` or `off` for enabling or disabling the usermod.
Have fun with this usermod.<br/>
www.rolfje.com
Have fun with this usermod
`www.rolfje.com`
Modifications @blazoncek
## Change log
2021-04
* Adaptation for runtime configuration.
- Adaptation for runtime configuration.

View File

@ -1,3 +1,4 @@
{
"name:": "Animated_Staircase"
"name": "Animated_Staircase",
"build": { "libArchive": false }
}

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,6 @@
{
"name:": "BH1750_v2",
"name": "BH1750_v2",
"build": { "libArchive": false },
"dependencies": {
"claws/BH1750":"^1.2.0"
}

View File

@ -4,6 +4,7 @@ This usermod will read from an ambient light sensor like the BH1750.
The luminance is displayed in both the Info section of the web UI, as well as published to the `/luminance` MQTT topic if enabled.
## Dependencies
- Libraries
- `claws/BH1750 @^1.2.0`
- Data is published over MQTT - make sure you've enabled the MQTT sync interface.
@ -13,23 +14,30 @@ The luminance is displayed in both the Info section of the web UI, as well as pu
To enable, compile with `BH1750` in `custom_usermods` (e.g. in `platformio_override.ini`)
### Configuration Options
The following settings can be set at compile-time but are configurable on the usermod menu (except First Measurement time):
* `USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL` - the max number of milliseconds between measurements, defaults to 10000ms
* `USERMOD_BH1750_MIN_MEASUREMENT_INTERVAL` - the min number of milliseconds between measurements, defaults to 500ms
* `USERMOD_BH1750_OFFSET_VALUE` - the offset value to report on, defaults to 1
* `USERMOD_BH1750_FIRST_MEASUREMENT_AT` - the number of milliseconds after boot to take first measurement, defaults to 10000 ms
- `USERMOD_BH1750_MAX_MEASUREMENT_INTERVAL` - the max number of milliseconds between measurements, defaults to 10000ms
- `USERMOD_BH1750_MIN_MEASUREMENT_INTERVAL` - the min number of milliseconds between measurements, defaults to 500ms
- `USERMOD_BH1750_OFFSET_VALUE` - the offset value to report on, defaults to 1
- `USERMOD_BH1750_FIRST_MEASUREMENT_AT` - the number of milliseconds after boot to take first measurement, defaults to 10000 ms
In addition, the Usermod screen allows you to:
- enable/disable the usermod
- Enable Home Assistant Discovery of usermod
- Configure the SCL/SDA pins
## API
The following method is available to interact with the usermod from other code modules:
- `getIlluminance` read the brightness from the sensor
## Change Log
Jul 2022
- Added Home Assistant Discovery
- Implemented PinManager to register pins
- Made pins configurable in usermod menu

View File

@ -1,5 +1,6 @@
{
"name:": "BME280_v2",
"name": "BME280_v2",
"build": { "libArchive": false },
"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,6 @@
{
"name:": "BME68X",
"name": "BME68X",
"build": { "libArchive": false },
"dependencies": {
"boschsensortec/BSEC Software Library":"^1.8.1492"
}

View File

@ -1,3 +1,4 @@
{
"name:": "Battery"
"name": "Battery",
"build": { "libArchive": false }
}

View File

@ -247,7 +247,7 @@ class UsermodCronixie : public Usermod {
if (backlight && _digitOut[i] <11)
{
uint32_t col = gamma32(strip.getSegment(0).colors[1]);
uint32_t col = strip.getSegment(0).colors[1];
for (uint16_t j=o; j< o+10; j++) {
if (j != excl) strip.setPixelColor(j, col);
}

View File

@ -1,3 +1,4 @@
{
"name:": "Cronixie"
"name": "Cronixie",
"build": { "libArchive": false }
}

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,5 @@
{
"name:": "EXAMPLE",
"name": "EXAMPLE",
"build": { "libArchive": false },
"dependencies": {}
}

View File

@ -1,5 +1,6 @@
{
"name:": "EleksTube_IPS",
"build": { "libArchive": false },
"dependencies": {
"TFT_eSPI" : "2.5.33"
}

View File

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

View File

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

View File

@ -1,3 +1,4 @@
{
"name:": "Internal_Temperature_v2"
"name": "Internal_Temperature_v2",
"build": { "libArchive": false }
}

View File

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

View File

@ -1,3 +1,4 @@
{
"name:": "LDR_Dusk_Dawn_v2"
"name": "LDR_Dusk_Dawn_v2",
"build": { "libArchive": false }
}

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,5 @@
{
"name:": "MY9291",
"name": "MY9291",
"build": { "libArchive": false },
"platforms": ["espressif8266"]
}

View File

@ -1,3 +1,4 @@
{
"name:": "PIR_sensor_switch"
"name": "PIR_sensor_switch",
"build": { "libArchive": false }
}

View File

@ -25,7 +25,7 @@ You can also use usermod's off timer instead of sensor's. In such case rotate th
**NOTE:** Usermod has been included in master branch of WLED so it can be compiled in directly just by defining `-D USERMOD_PIRSWITCH` and optionally `-D PIR_SENSOR_PIN=16` to override default pin. You can also change the default off time by adding `-D PIR_SENSOR_OFF_SEC=30`.
## API to enable/disable the PIR sensor from outside. For example from another usermod:
## API to enable/disable the PIR sensor from outside. For example from another usermod
To query or change the PIR sensor state the methods `bool PIRsensorEnabled()` and `void EnablePIRsensor(bool enable)` are available.
@ -33,15 +33,16 @@ When the PIR sensor state changes an MQTT message is broadcasted with topic `wle
Usermod can also be configured to send just the MQTT message but not change WLED state using settings page as well as responding to motion only at night
(assuming NTP and latitude/longitude are set to determine sunrise/sunset times).
### There are two options to get access to the usermod instance:
### There are two options to get access to the usermod instance
1. Include `usermod_PIR_sensor_switch.h` **before** you include other usermods in `usermods_list.cpp'
_1._ Include `usermod_PIR_sensor_switch.h` **before** you include other usermods in `usermods_list.cpp'
or
2. Use `#include "usermod_PIR_sensor_switch.h"` at the top of the `usermod.h` where you need it.
_2._ Use `#include "usermod_PIR_sensor_switch.h"` at the top of the `usermod.h` where you need it.
**Example usermod.h :**
```cpp
#include "wled.h"
@ -79,25 +80,30 @@ Usermod can be configured via the Usermods settings page.
* `override` - override PIR input when WLED state is changed using UI
* `domoticz-idx` - Domoticz virtual switch ID (used with MQTT `domoticz/in`)
Have fun - @gegu & @blazoncek
## Change log
2021-04
* Adaptation for runtime configuration.
2021-11
* Added information about dynamic configuration options
* Added option to temporary enable/disable usermod from WLED UI (Info dialog)
2022-11
* Added compile time option for off timer.
* Added Home Assistant autodiscovery MQTT broadcast.
* Updated info on compiling.
2023-??
* Override option
* Domoticz virtual switch ID (used with MQTT `domoticz/in`)
2024-02
* Added compile time option to expand number of PIR sensors (they are logically ORed) `-D PIR_SENSOR_MAX_SENSORS=3`
* Added compile time option to expand number of PIR sensors (they are logically ORed) `-D PIR_SENSOR_MAX_SENSORS=3`

View File

@ -1,6 +1,7 @@
{
"name:": "PWM_fan",
"name": "PWM_fan",
"build": {
"libArchive": false,
"extraScript": "setup_deps.py"
}
}

View File

@ -40,6 +40,9 @@ If the fan speed is unlocked, it will revert to temperature controlled speed on
## Change Log
2021-10
* First public release
2022-05
* Added JSON API call to allow changing of speed

View File

@ -1,12 +1,12 @@
from platformio.package.meta import PackageSpec
Import('env')
usermods = env.GetProjectOption("custom_usermods","").split()
libs = [PackageSpec(lib).name for lib in env.GetProjectOption("lib_deps",[])]
# Check for dependencies
if "Temperature" in usermods:
if "Temperature" in libs:
env.Append(CPPDEFINES=[("USERMOD_DALLASTEMPERATURE")])
elif "sht" in usermods:
elif "sht" in libs:
env.Append(CPPDEFINES=[("USERMOD_SHT")])
else:
elif "PWM_fan" in libs: # 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,4 @@
{
"name:": "RTC"
"name": "RTC",
"build": { "libArchive": false }
}

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,4 @@
{
"name:": "SN_Photoresistor"
"name": "SN_Photoresistor",
"build": { "libArchive": false }
}

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,3 +1,4 @@
{
"name:": "ST7789_display"
"name:": "ST7789_display",
"build": { "libArchive": false }
}

View File

@ -1,5 +1,6 @@
{
"name:": "Si7021_MQTT_HA",
"name": "Si7021_MQTT_HA",
"build": { "libArchive": false },
"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

@ -35,19 +35,23 @@ All parameters can be configured at runtime via the Usermods settings page, incl
## Change Log
2020-09-12
2020-09-12
* Changed to use async non-blocking implementation
* Do not report erroneous low temperatures to MQTT
* Disable plugin if temperature sensor not detected
* Report the number of seconds until the first read in the info screen instead of sensor error
2021-04
* Adaptation for runtime configuration.
2023-05
* Rewrite to conform to newer recommendations.
* Recommended @blazoncek fork of OneWire for ESP32 to avoid Sensor error
2024-09
* Update OneWire to version 2.3.8, which includes stickbreaker's and garyd9's ESP32 fixes:
blazoncek's fork is no longer needed
blazoncek's fork is no longer needed

View File

@ -1,3 +1,4 @@
{
"name:": "TetrisAI_v2"
"name": "TetrisAI_v2",
"build": { "libArchive": false }
}

View File

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

View File

@ -1736,7 +1736,7 @@ class AudioReactive : public Usermod {
}
void onStateChange(uint8_t callMode) override {
if (initDone && enabled && addPalettes && palettes==0 && strip.customPalettes.size()<10) {
if (initDone && enabled && addPalettes && palettes==0 && customPalettes.size()<10) {
// if palettes were removed during JSON call re-add them
createAudioPalettes();
}
@ -1966,20 +1966,20 @@ class AudioReactive : public Usermod {
void AudioReactive::removeAudioPalettes(void) {
DEBUG_PRINTLN(F("Removing audio palettes."));
while (palettes>0) {
strip.customPalettes.pop_back();
customPalettes.pop_back();
DEBUG_PRINTLN(palettes);
palettes--;
}
DEBUG_PRINT(F("Total # of palettes: ")); DEBUG_PRINTLN(strip.customPalettes.size());
DEBUG_PRINT(F("Total # of palettes: ")); DEBUG_PRINTLN(customPalettes.size());
}
void AudioReactive::createAudioPalettes(void) {
DEBUG_PRINT(F("Total # of palettes: ")); DEBUG_PRINTLN(strip.customPalettes.size());
DEBUG_PRINT(F("Total # of palettes: ")); DEBUG_PRINTLN(customPalettes.size());
if (palettes) return;
DEBUG_PRINTLN(F("Adding audio palettes."));
for (int i=0; i<MAX_PALETTES; i++)
if (strip.customPalettes.size() < 10) {
strip.customPalettes.push_back(CRGBPalette16(CRGB(BLACK)));
if (customPalettes.size() < 10) {
customPalettes.push_back(CRGBPalette16(CRGB(BLACK)));
palettes++;
DEBUG_PRINTLN(palettes);
} else break;
@ -2016,7 +2016,7 @@ CRGB AudioReactive::getCRGBForBand(int x, int pal) {
void AudioReactive::fillAudioPalettes() {
if (!palettes) return;
size_t lastCustPalette = strip.customPalettes.size();
size_t lastCustPalette = customPalettes.size();
if (int(lastCustPalette) >= palettes) lastCustPalette -= palettes;
for (int pal=0; pal<palettes; pal++) {
uint8_t tcp[16]; // Needs to be 4 times however many colors are being used.
@ -2045,7 +2045,7 @@ void AudioReactive::fillAudioPalettes() {
tcp[14] = rgb.g;
tcp[15] = rgb.b;
strip.customPalettes[lastCustPalette+pal].loadDynamicGradientPalette(tcp);
customPalettes[lastCustPalette+pal].loadDynamicGradientPalette(tcp);
}
}

View File

@ -8,24 +8,27 @@ Does audio processing and provides data structure that specially written effects
**does not** provide effects or draw anything to an LED strip/matrix.
## Additional Documentation
This usermod is an evolution of [SR-WLED](https://github.com/atuline/WLED), and a lot of documentation and information can be found in the [SR-WLED wiki](https://github.com/atuline/WLED/wiki):
* [getting started with audio](https://github.com/atuline/WLED/wiki/First-Time-Setup#sound)
* [Sound settings](https://github.com/atuline/WLED/wiki/Sound-Settings) - similar to options on the usemod settings page in WLED.
* [Digital Audio](https://github.com/atuline/WLED/wiki/Digital-Microphone-Hookup)
* [Analog Audio](https://github.com/atuline/WLED/wiki/Analog-Audio-Input-Options)
* [UDP Sound sync](https://github.com/atuline/WLED/wiki/UDP-Sound-Sync)
## Supported MCUs
This audioreactive usermod works best on "classic ESP32" (dual core), and on ESP32-S3 which also has dual core and hardware floating point support.
It will compile successfully for ESP32-S2 and ESP32-C3, however might not work well, as other WLED functions will become slow. Audio processing requires a lot of computing power, which can be problematic on smaller MCUs like -S2 and -C3.
This audioreactive usermod works best on "classic ESP32" (dual core), and on ESP32-S3 which also has dual core and hardware floating point support.
It will compile successfully for ESP32-S2 and ESP32-C3, however might not work well, as other WLED functions will become slow. Audio processing requires a lot of computing power, which can be problematic on smaller MCUs like -S2 and -C3.
Analog audio is only possible on "classic" ESP32, but not on other MCUs like ESP32-S3.
Currently ESP8266 is not supported, due to low speed and small RAM of this chip.
Currently ESP8266 is not supported, due to low speed and small RAM of this chip.
There are however plans to create a lightweight audioreactive for the 8266, with reduced features.
## Installation
## Installation
Add 'ADS1115_v2' to `custom_usermods` in your platformio environment.
@ -35,29 +38,31 @@ All parameters are runtime configurable. Some may require a hard reset after cha
If you want to define default GPIOs during compile time, use the following (default values in parentheses):
- `-D SR_DMTYPE=x` : defines digital microphone type: 0=analog, 1=generic I2S (default), 2=ES7243 I2S, 3=SPH0645 I2S, 4=generic I2S with master clock, 5=PDM I2S
- `-D AUDIOPIN=x` : GPIO for analog microphone/AUX-in (36)
- `-D I2S_SDPIN=x` : GPIO for SD pin on digital microphone (32)
- `-D I2S_WSPIN=x` : GPIO for WS pin on digital microphone (15)
- `-D I2S_CKPIN=x` : GPIO for SCK pin on digital microphone (14)
- `-D MCLK_PIN=x` : GPIO for master clock pin on digital Line-In boards (-1)
- `-D ES7243_SDAPIN` : GPIO for I2C SDA pin on ES7243 microphone (-1)
- `-D ES7243_SCLPIN` : GPIO for I2C SCL pin on ES7243 microphone (-1)
* `-D SR_DMTYPE=x` : defines digital microphone type: 0=analog, 1=generic I2S (default), 2=ES7243 I2S, 3=SPH0645 I2S, 4=generic I2S with master clock, 5=PDM I2S
* `-D AUDIOPIN=x` : GPIO for analog microphone/AUX-in (36)
* `-D I2S_SDPIN=x` : GPIO for SD pin on digital microphone (32)
* `-D I2S_WSPIN=x` : GPIO for WS pin on digital microphone (15)
* `-D I2S_CKPIN=x` : GPIO for SCK pin on digital microphone (14)
* `-D MCLK_PIN=x` : GPIO for master clock pin on digital Line-In boards (-1)
* `-D ES7243_SDAPIN` : GPIO for I2C SDA pin on ES7243 microphone (-1)
* `-D ES7243_SCLPIN` : GPIO for I2C SCL pin on ES7243 microphone (-1)
Other options:
- `-D UM_AUDIOREACTIVE_ENABLE` : makes usermod default enabled (not the same as include into build option!)
- `-D UM_AUDIOREACTIVE_DYNAMICS_LIMITER_OFF` : disables rise/fall limiter default
* `-D UM_AUDIOREACTIVE_ENABLE` : makes usermod default enabled (not the same as include into build option!)
* `-D UM_AUDIOREACTIVE_DYNAMICS_LIMITER_OFF` : disables rise/fall limiter default
**NOTE** I2S is used for analog audio sampling. Hence, the analog *buttons* (i.e. potentiometers) are disabled when running this usermod with an analog microphone.
### Advanced Compile-Time Options
You can use the following additional flags in your `build_flags`
* `-D SR_SQUELCH=x` : Default "squelch" setting (10)
* `-D SR_GAIN=x` : Default "gain" setting (60)
* `-D I2S_USE_RIGHT_CHANNEL`: Use RIGHT instead of LEFT channel (not recommended unless you strictly need this).
* `-D I2S_USE_16BIT_SAMPLES`: Use 16bit instead of 32bit for internal sample buffers. Reduces sampling quality, but frees some RAM ressources (not recommended unless you absolutely need this).
* `-D I2S_GRAB_ADC1_COMPLETELY`: Experimental: continuously sample analog ADC microphone. Only effective on ESP32. WARNING this _will_ cause conflicts(lock-up) with any analogRead() call.
* `-D I2S_GRAB_ADC1_COMPLETELY`: Experimental: continuously sample analog ADC microphone. Only effective on ESP32. WARNING this *will* cause conflicts(lock-up) with any analogRead() call.
* `-D MIC_LOGGER` : (debugging) Logs samples from the microphone to serial USB. Use with serial plotter (Arduino IDE)
* `-D SR_DEBUG` : (debugging) Additional error diagnostics and debug info on serial USB.

View File

@ -1,3 +1,4 @@
{
"name:": "boblight"
"name": "boblight",
"build": { "libArchive": false }
}

View File

@ -1,3 +1,4 @@
{
"name:": "buzzer"
"name": "buzzer",
"build": { "libArchive": false }
}

View File

@ -1,3 +1,4 @@
{
"name:": "deep_sleep"
"name": "deep_sleep",
"build": { "libArchive": false }
}

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,4 @@
{
"name:": "multi_relay"
"name": "multi_relay",
"build": { "libArchive": false }
}

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,11 +1,11 @@
### Shift Light for Project Cars
# Shift Light for Project Cars
Turn your WLED lights into a rev light and shift indicator for Project Cars.
It's easy to use.
1. Make sure your WLED device and your PC/console are on the same network and can talk to each other
_1._ Make sure your WLED device and your PC/console are on the same network and can talk to each other
2. Go to the gameplay settings menu in PCARS and enable UDP. There are 9 numbers you can choose from. This is the refresh rate. The lower the number, the better. However, you might run into problems at faster rates.
_2._ Go to the gameplay settings menu in PCARS and enable UDP. There are 9 numbers you can choose from. This is the refresh rate. The lower the number, the better. However, you might run into problems at faster rates.
| Number | Updates/Second |
| ------ | -------------- |
@ -19,5 +19,5 @@ It's easy to use.
| 8 | 05 |
| 9 | 1 |
3. Once you enter a race, WLED should automatically shift to PCARS mode.
4. Done.
_3._ Once you enter a race, WLED should automatically shift to PCARS mode.
_4._ Done.

View File

@ -1,3 +1,4 @@
{
"name:": "pwm_outputs"
"name": "pwm_outputs",
"build": { "libArchive": false }
}

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,4 +1,4 @@
### Usermods
# Usermods
This folder serves as a repository for usermods (custom `usermod.cpp` files)!
@ -6,11 +6,11 @@ If you have created a usermod you believe is useful (for example to support a pa
In order for other people to be able to have fun with your usermod, please keep these points in mind:
- Create a folder in this folder with a descriptive name (for example `usermod_ds18b20_temp_sensor_mqtt`)
- Include your custom files
- If your usermod requires changes to other WLED files, please write a `readme.md` outlining the steps one needs to take
- Create a pull request!
- If your feature is useful for the majority of WLED users, I will consider adding it to the base code!
* Create a folder in this folder with a descriptive name (for example `usermod_ds18b20_temp_sensor_mqtt`)
* Include your custom files
* If your usermod requires changes to other WLED files, please write a `readme.md` outlining the steps one needs to take
* Create a pull request!
* If your feature is useful for the majority of WLED users, I will consider adding it to the base code!
While I do my best to not break too much, keep in mind that as WLED is updated, usermods might break.
I am not actively maintaining any usermod in this directory, that is your responsibility as the creator of the usermod.

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,4 @@
{
"name:": "sd_card"
"name": "sd_card",
"build": { "libArchive": false }
}

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,4 @@
{
"name:": "seven_segment_display"
"name": "seven_segment_display",
"build": { "libArchive": false }
}

View File

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

View File

@ -0,0 +1,10 @@
from platformio.package.meta import PackageSpec
Import('env')
libs = [PackageSpec(lib).name for lib in env.GetProjectOption("lib_deps",[])]
# Check for partner usermods
if "SN_Photoresistor" in libs:
env.Append(CPPDEFINES=[("USERMOD_SN_PHOTORESISTOR")])
if any(mod in ("BH1750_v2", "BH1750") for mod in libs):
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,6 @@
{
"name:": "sht",
"name": "sht",
"build": { "libArchive": false },
"dependencies": {
"robtillaart/SHT85": "~0.3.3"
}

View File

@ -1,35 +1,43 @@
# SHT
Usermod to support various SHT i2c sensors like the SHT30, SHT31, SHT35 and SHT85
## Requirements
* "SHT85" by Rob Tillaart, v0.2 or higher: https://github.com/RobTillaart/SHT85
* "SHT85" by Rob Tillaart, v0.2 or higher: <https://github.com/RobTillaart/SHT85>
## Usermod installation
Simply copy the below block (build task) to your `platformio_override.ini` and compile WLED using this new build task. Or use an existing one, add the custom_usermod `sht`.
ESP32:
```
```ini
[env:custom_esp32dev_usermod_sht]
extends = env:esp32dev
custom_usermods = ${env:esp32dev.custom_usermods} sht
```
ESP8266:
```
```ini
[env:custom_d1_mini_usermod_sht]
extends = env:d1_mini
custom_usermods = ${env:d1_mini.custom_usermods} sht
```
## MQTT Discovery for Home Assistant
If you're using Home Assistant and want to have the temperature and humidity available as entities in HA, you can tick the "Add-To-Home-Assistant-MQTT-Discovery" option in the usermod settings. If you have an MQTT broker configured under "Sync Settings" and it is connected, the mod will publish the auto discovery message to your broker and HA will instantly find it and create an entity each for the temperature and humidity.
### Publishing readings via MQTT
Regardless of having MQTT discovery ticked or not, the mod will always report temperature and humidity to the WLED MQTT topic of that instance, if you have a broker configured and it's connected.
## Configuration
Navigate to the "Config" and then to the "Usermods" section. If you compiled WLED with `-D USERMOD_SHT`, you will see the config for it there:
* SHT-Type:
* What it does: Select the SHT sensor type you want to use
* Possible values: SHT30, SHT31, SHT35, SHT85
@ -44,8 +52,11 @@ Navigate to the "Config" and then to the "Usermods" section. If you compiled WLE
* Default: Disabled
## Change log
2022-12
* First implementation.
## Credits
ezcGman | Andy: Find me on the Intermit.Tech (QuinLED) Discord server: https://discord.gg/WdbAauG
ezcGman | Andy: Find me on the Intermit.Tech (QuinLED) Discord server: <https://discord.gg/WdbAauG>

View File

@ -1,3 +1,4 @@
{
"name:": "smartnest"
"name": "smartnest",
"build": { "libArchive": false }
}

View File

@ -1,3 +1,4 @@
{
"name:": "stairway_wipe_basic"
"name": "stairway_wipe_basic",
"build": { "libArchive": false }
}

View File

@ -0,0 +1,4 @@
# Usermod user FX
This Usermod is a common place to put various user's LED effects.

View File

@ -0,0 +1,4 @@
{
"name": "user_fx",
"build": { "libArchive": false }
}

View File

@ -0,0 +1,116 @@
#include "wled.h"
// for information how FX metadata strings work see https://kno.wled.ge/interfaces/json-api/#effect-metadata
// static effect, used if an effect fails to initialize
static uint16_t mode_static(void) {
SEGMENT.fill(SEGCOLOR(0));
return strip.isOffRefreshRequired() ? FRAMETIME : 350;
}
/////////////////////////
// User FX functions //
/////////////////////////
// Diffusion Fire: fire effect intended for 2D setups smaller than 16x16
static uint16_t mode_diffusionfire(void) {
if (!strip.isMatrix || !SEGMENT.is2D())
return mode_static(); // not a 2D set-up
const int cols = SEG_W;
const int rows = SEG_H;
const auto XY = [&](int x, int y) { return x + y * cols; };
const uint8_t refresh_hz = map(SEGMENT.speed, 0, 255, 20, 80);
const unsigned refresh_ms = 1000 / refresh_hz;
const int16_t diffusion = map(SEGMENT.custom1, 0, 255, 0, 100);
const uint8_t spark_rate = SEGMENT.intensity;
const uint8_t turbulence = SEGMENT.custom2;
unsigned dataSize = SEGMENT.length(); // allocate persistent data for heat value for each pixel
if (!SEGENV.allocateData(dataSize))
return mode_static(); // allocation failed
if (SEGENV.call == 0) {
SEGMENT.fill(BLACK);
SEGENV.step = 0;
}
if ((strip.now - SEGENV.step) >= refresh_ms) {
uint8_t tmp_row[cols];
SEGENV.step = strip.now;
// scroll up
for (unsigned y = 1; y < rows; y++)
for (unsigned x = 0; x < cols; x++) {
unsigned src = XY(x, y);
unsigned dst = XY(x, y - 1);
SEGMENT.data[dst] = SEGMENT.data[src];
}
if (hw_random8() > turbulence) {
// create new sparks at bottom row
for (unsigned x = 0; x < cols; x++) {
uint8_t p = hw_random8();
if (p < spark_rate) {
unsigned dst = XY(x, rows - 1);
SEGMENT.data[dst] = 255;
}
}
}
// diffuse
for (unsigned y = 0; y < rows; y++) {
for (unsigned x = 0; x < cols; x++) {
unsigned v = SEGMENT.data[XY(x, y)];
if (x > 0) {
v += SEGMENT.data[XY(x - 1, y)];
}
if (x < (cols - 1)) {
v += SEGMENT.data[XY(x + 1, y)];
}
tmp_row[x] = min(255, (int)(v * 100 / (300 + diffusion)));
}
for (unsigned x = 0; x < cols; x++) {
SEGMENT.data[XY(x, y)] = tmp_row[x];
if (SEGMENT.check1) {
uint32_t color = ColorFromPalette(SEGPALETTE, tmp_row[x], 255, LINEARBLEND_NOWRAP);
SEGMENT.setPixelColorXY(x, y, color);
} else {
uint32_t color = SEGCOLOR(0);
SEGMENT.setPixelColorXY(x, y, color_fade(color, tmp_row[x]));
}
}
}
}
return FRAMETIME;
}
static const char _data_FX_MODE_DIFFUSIONFIRE[] PROGMEM = "Diffusion Fire@!,Spark rate,Diffusion Speed,Turbulence,,Use palette;;Color;;2;pal=35";
/////////////////////
// UserMod Class //
/////////////////////
class UserFxUsermod : public Usermod {
private:
public:
void setup() override {
strip.addEffect(255, &mode_diffusionfire, _data_FX_MODE_DIFFUSIONFIRE);
////////////////////////////////////////
// add your effect function(s) here //
////////////////////////////////////////
// use id=255 for all custom user FX (the final id is assigned when adding the effect)
// strip.addEffect(255, &mode_your_effect, _data_FX_MODE_YOUR_EFFECT);
// strip.addEffect(255, &mode_your_effect2, _data_FX_MODE_YOUR_EFFECT2);
// strip.addEffect(255, &mode_your_effect3, _data_FX_MODE_YOUR_EFFECT3);
}
void loop() override {} // nothing to do in the loop
uint16_t getId() override { return USERMOD_ID_USER_FX; }
};
static UserFxUsermod user_fx;
REGISTER_USERMOD(user_fx);

View File

@ -1,3 +1,4 @@
{
"name:": "usermod_rotary_brightness_color"
"name": "usermod_rotary_brightness_color",
"build": { "libArchive": false }
}

View File

@ -0,0 +1,4 @@
{
"name": "usermod_v2_HttpPullLightControl",
"build": { "libArchive": false }
}

View File

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

View File

@ -5,7 +5,7 @@ The `usermod_v2_HttpPullLightControl` is a custom user module for WLED that enab
## Features
* Configure the URL endpoint (only support HTTP for now, no HTTPS) and polling interval via the WLED user interface.
* All options from the JSON API are supported (since v0.0.3). See: https://kno.wled.ge/interfaces/json-api/
* All options from the JSON API are supported (since v0.0.3). See: [https://kno.wled.ge/interfaces/json-api/](https://kno.wled.ge/interfaces/json-api/)
* The ability to control the brightness of all lights and the state (on/off) and color of individual lights remotely.
* Start or stop an effect and when you run the same effect when its's already running, it won't restart.
* The ability to control all these settings per segment.
@ -13,13 +13,15 @@ The `usermod_v2_HttpPullLightControl` is a custom user module for WLED that enab
* Unique ID generation based on the device's MAC address and a configurable salt value, appended to the request URL for identification.
## Configuration
* Enable the `usermod_v2_HttpPullLightControl` via the WLED user interface.
* Specify the URL endpoint and polling interval.
## JSON Format and examples
* The module sends a GET request to the configured URL, appending a unique identifier as a query parameter: `https://www.example.com/mycustompage.php?id=xxxxxxxx` where xxxxxxx is a 40 character long SHA1 hash of the MAC address combined with a given salt.
* Response Format (since v0.0.3) it is eactly the same as the WLED JSON API, see: https://kno.wled.ge/interfaces/json-api/
* Response Format (since v0.0.3) it is eactly the same as the WLED JSON API, see: [https://kno.wled.ge/interfaces/json-api/](https://kno.wled.ge/interfaces/json-api/)
After getting the URL (it can be a static file like static.json or a mylogic.php which gives a dynamic response), the response is read and parsed to WLED.
* An example of a response to set the individual lights: 0 to RED, 12 to Green and 14 to BLUE. Remember that is will SET lights, you might want to set all the others to black.
@ -58,48 +60,51 @@ After getting the URL (it can be a static file like static.json or a mylogic.php
}`
* Or use the following example to start an effect, but first we UNFREEZE (frz=false) the segment because it was frozen by individual light control in the previous examples (28=Chase effect, Speed=180m Intensity=128). The three color slots are the slots you see under the color wheel and used by the effect. RED, Black, White in this case.
```json
`{
"seg":
{
"frz": false,
"fx": 28,
"sx": 200,
"ix": 128,
"col": [
"FF0000",
"000000",
"FFFFFF"
]
}
"frz": false,
"fx": 28,
"sx": 200,
"ix": 128,
"col": [
"FF0000",
"000000",
"FFFFFF"
]
}
}`
```
## Installation
1. Add `usermod_v2_HttpPullLightControl` to your WLED project following the instructions provided in the WLED documentation.
2. Compile by setting the build_flag: -D USERMOD_HTTP_PULL_LIGHT_CONTROL and upload to your ESP32/ESP8266!
3. There are several compile options which you can put in your platformio.ini or platformio_override.ini:
- -DUSERMOD_HTTP_PULL_LIGHT_CONTROL ;To Enable the usermod
- -DHTTP_PULL_LIGHT_CONTROL_URL="\"http://mydomain.com/json-response.php\"" ; The URL which will be requested all the time to set the lights/effects
- -DHTTP_PULL_LIGHT_CONTROL_SALT="\"my_very-S3cret_C0de\"" ; A secret SALT which will help by making the ID more safe
- -DHTTP_PULL_LIGHT_CONTROL_INTERVAL=30 ; The interval at which the URL is requested in seconds
- -DHTTP_PULL_LIGHT_CONTROL_HIDE_SALT ; Do you want to Hide the SALT in the User Interface? If yes, Set this flag. Note that the salt can now only be set via the above -DHTTP_PULL_LIGHT_CONTROL_SALT= setting
- -DWLED_AP_SSID="\"Christmas Card\"" ; These flags are not just for my Usermod but you probably want to set them
- -DWLED_AP_PASS="\"christmas\""
- -DWLED_OTA_PASS="\"otapw-secret\""
- -DMDNS_NAME="\"christmascard\""
- -DSERVERNAME="\"CHRISTMASCARD\""
- -D ABL_MILLIAMPS_DEFAULT=450
- -D DEFAULT_LED_COUNT=60 ; For a LED Ring of 60 LEDs
- -D BTNPIN=41 ; The M5Stack Atom S3 Lite has a button on GPIO41
- -D DATA_PINS=2 ; The M5Stack Atom S3 Lite has a Grove connector on the front, we use this GPIO2
- -D STATUSLED=35 ; The M5Stack Atom S3 Lite has a Multi-Color LED on GPIO35, although I didnt managed to control it
- -D IRPIN=4 ; The M5Stack Atom S3 Lite has a IR LED on GPIO4
* -DUSERMOD_HTTP_PULL_LIGHT_CONTROL ;To Enable the usermod
* -DHTTP_PULL_LIGHT_CONTROL_URL="\"`http://mydomain.com/json-response.php`\"" ; The URL which will be requested all the time to set the lights/effects
* -DHTTP_PULL_LIGHT_CONTROL_SALT="\"my_very-S3cret_C0de\"" ; A secret SALT which will help by making the ID more safe
* -DHTTP_PULL_LIGHT_CONTROL_INTERVAL=30 ; The interval at which the URL is requested in seconds
* -DHTTP_PULL_LIGHT_CONTROL_HIDE_SALT ; Do you want to Hide the SALT in the User Interface? If yes, Set this flag. Note that the salt can now only be set via the above -DHTTP_PULL_LIGHT_CONTROL_SALT= setting
- -D DEBUG=1 ; Set these DEBUG flags ONLY if you want to debug and read out Serial (using Visual Studio Code - Serial Monitor)
- -DDEBUG_LEVEL=5
- -DWLED_DEBUG
* -DWLED_AP_SSID="\"Christmas Card\"" ; These flags are not just for my Usermod but you probably want to set them
* -DWLED_AP_PASS="\"christmas\""
* -DWLED_OTA_PASS="\"otapw-secret\""
* -DMDNS_NAME="\"christmascard\""
* -DSERVERNAME="\"CHRISTMASCARD\""
* -D ABL_MILLIAMPS_DEFAULT=450
* -D DEFAULT_LED_COUNT=60 ; For a LED Ring of 60 LEDs
* -D BTNPIN=41 ; The M5Stack Atom S3 Lite has a button on GPIO41
* -D DATA_PINS=2 ; The M5Stack Atom S3 Lite has a Grove connector on the front, we use this GPIO2
* -D STATUSLED=35 ; The M5Stack Atom S3 Lite has a Multi-Color LED on GPIO35, although I didnt managed to control it
* -D IRPIN=4 ; The M5Stack Atom S3 Lite has a IR LED on GPIO4
* -D DEBUG=1 ; Set these DEBUG flags ONLY if you want to debug and read out Serial (using Visual Studio Code - Serial Monitor)
* -DDEBUG_LEVEL=5
* -DWLED_DEBUG
## Use Case: Interactive Christmas Cards
@ -107,4 +112,4 @@ Imagine distributing interactive Christmas cards embedded with a tiny ESP32 and
Your server keeps track of how many cards are active at any given time. If all 20 cards are active, your server instructs each card to light up all of its LEDs. However, if only 4 cards are active, your server instructs each card to light up only 4 LEDs. This creates a real-time interactive experience, symbolizing the collective spirit of the holiday season. Each lit LED represents a friend who's thinking about the others, and the visual feedback creates a sense of connection among the group, despite the physical distance.
This setup demonstrates a unique way to blend traditional holiday sentiments with modern technology, offering an engaging and memorable experience.
This setup demonstrates a unique way to blend traditional holiday sentiments with modern technology, offering an engaging and memorable experience.

View File

@ -4,6 +4,9 @@
const char HttpPullLightControl::_name[] PROGMEM = "HttpPullLightControl";
const char HttpPullLightControl::_enabled[] PROGMEM = "Enable";
static HttpPullLightControl http_pull_usermod;
REGISTER_USERMOD(http_pull_usermod);
void HttpPullLightControl::setup() {
//Serial.begin(115200);
@ -297,10 +300,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,6 @@
{
"name:": "usermod_v2_RF433",
"name": "usermod_v2_RF433",
"build": { "libArchive": false },
"dependencies": {
"sui77/rc-switch":"2.6.4"
}

View File

@ -1,5 +1,6 @@
{
"name": "animartrix",
"build": { "libArchive": false },
"dependencies": {
"Animartrix": "https://github.com/netmindz/animartrix.git#b172586"
}

View File

@ -1,3 +1,4 @@
{
"name": "auto_save"
"name": "auto_save",
"build": { "libArchive": false }
}

View File

@ -2,6 +2,7 @@
v2 Usermod to automatically save settings
to preset number AUTOSAVE_PRESET_NUM after a change to any of:
* brightness
* effect speed
* effect intensity
@ -19,7 +20,7 @@ Note: WLED doesn't respect the brightness of the preset being auto loaded, so th
## Installation
Copy and update the example `platformio_override.ini.sample`
Copy and update the example `platformio_override.ini.sample`
from the Rotary Encoder UI usermode folder to the root directory of your particular build.
This file should be placed in the same directory as `platformio.ini`.
@ -50,6 +51,9 @@ Note: the Four Line Display usermod requires the libraries `U8g2` and `Wire`.
## Change Log
2021-02
* First public release
2021-04
* Adaptation for runtime configuration.

View File

@ -10,8 +10,8 @@ define `USERMOD_BRIGHTNESS_FOLLOW_SUN` e.g. `#define USERMOD_BRIGHTNESS_FOLLOW_S
or add `-D USERMOD_BRIGHTNESS_FOLLOW_SUN` to `build_flags` in platformio_override.ini
### Options
Open Usermod Settings in WLED to change settings:
`Enable` - When checked `Enable`, turn on the `Brightness Follow Sun` Usermod, which will automatically turn on the lights, adjust the brightness, and turn off the lights. If you need to completely turn off the lights, please unchecked `Enable`.
@ -24,12 +24,12 @@ Open Usermod Settings in WLED to change settings:
`Relax Hour` - The unit is in hours, with an effective range of 0-6. According to the settings, maintain the lowest brightness for 0-6 hours before sunrise and after sunset.
### PlatformIO requirements
No special requirements.
## Change Log
### Change Log
2025-01-02
* init

View File

@ -0,0 +1,4 @@
{
"name": "brightness_follow_sun",
"build": { "libArchive": false }
}

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,8 @@
{
"name": "four_line_display_ALT",
"build": { "libArchive": false },
"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

@ -5,6 +5,7 @@ This usermod could be used in compination with `usermod_v2_rotary_encoder_ui_ALT
## Functionalities
Press the encoder to cycle through the options:
* Brightness
* Speed
* Intensity
@ -35,15 +36,15 @@ These options are configurable in Config > Usermods
* `enabled` - enable/disable usermod
* `type` - display type in numeric format
* 1 = I2C SSD1306 128x32
* 2 = I2C SH1106 128x32
* 3 = I2C SSD1306 128x64 (4 double-height lines)
* 4 = I2C SSD1305 128x32
* 5 = I2C SSD1305 128x64 (4 double-height lines)
* 6 = SPI SSD1306 128x32
* 7 = SPI SSD1306 128x64 (4 double-height lines)
* 8 = SPI SSD1309 128x64 (4 double-height lines)
* 9 = I2C SSD1309 128x64 (4 double-height lines)
* 1 = I2C SSD1306 128x32
* 2 = I2C SH1106 128x32
* 3 = I2C SSD1306 128x64 (4 double-height lines)
* 4 = I2C SSD1305 128x32
* 5 = I2C SSD1305 128x64 (4 double-height lines)
* 6 = SPI SSD1306 128x32
* 7 = SPI SSD1306 128x64 (4 double-height lines)
* 8 = SPI SSD1309 128x64 (4 double-height lines)
* 9 = I2C SSD1309 128x64 (4 double-height lines)
* `pin` - GPIO pins used for display; SPI displays can use SCK, MOSI, CS, DC & RST
* `flip` - flip/rotate display 180°
* `contrast` - set display contrast (higher contrast may reduce display lifetime)
@ -53,7 +54,6 @@ These options are configurable in Config > Usermods
* `showSeconds` - Show seconds on the clock display
* `i2c-freq-kHz` - I2C clock frequency in kHz (may help reduce dropped frames, range: 400-3400)
### PlatformIO requirements
Note: the Four Line Display usermod requires the libraries `U8g2` and `Wire`.
@ -61,4 +61,5 @@ Note: the Four Line Display usermod requires the libraries `U8g2` and `Wire`.
## Change Log
2021-10
* First public release

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,4 @@
{
"name:": "usermod_v2_klipper_percentage"
"name": "usermod_v2_klipper_percentage",
"build": { "libArchive": false }
}

View File

@ -1,3 +1,4 @@
{
"name:": "usermod_v2_ping_pong_clock"
"name": "usermod_v2_ping_pong_clock",
"build": { "libArchive": false }
}

View File

@ -1,3 +1,7 @@
{
"name:": "usermod_v2_rotary_encoder_ui_ALT"
"name": "rotary_encoder_ui_ALT",
"build": {
"libArchive": false,
"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

@ -5,6 +5,7 @@ This usermod supports the UI of the `usermod_v2_rotary_encoder_ui_ALT`.
## Functionalities
Press the encoder to cycle through the options:
* Brightness
* Speed
* Intensity
@ -25,10 +26,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
@ -43,4 +40,5 @@ No special requirements.
## Change Log
2021-10
* First public release

Some files were not shown because too many files have changed in this diff Show More