Merge branch 'master' of https://github.com/aircoookie/WLED into dev
This commit is contained in:
commit
5926d396f9
16
tools/multi-update.cmd
Normal file
16
tools/multi-update.cmd
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
@echo off
|
||||||
|
SETLOCAL
|
||||||
|
SET FWPATH=c:\path\to\your\WLED\build_output\firmware
|
||||||
|
GOTO ESPS
|
||||||
|
|
||||||
|
:UPDATEONE
|
||||||
|
IF NOT EXIST %FWPATH%\%2 GOTO SKIP
|
||||||
|
ping -w 1000 -n 1 %1 | find "TTL=" || GOTO SKIP
|
||||||
|
ECHO Updating %1
|
||||||
|
curl -s -F "update=@%FWPATH%/%2" %1/update >nul
|
||||||
|
:SKIP
|
||||||
|
GOTO:EOF
|
||||||
|
|
||||||
|
:ESPS
|
||||||
|
call :UPDATEONE 192.168.x.x firmware.bin
|
||||||
|
call :UPDATEONE ....
|
19
tools/multi-update.sh
Normal file
19
tools/multi-update.sh
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
FWPATH=/path/to/your/WLED/build_output/firmware
|
||||||
|
|
||||||
|
update_one() {
|
||||||
|
if [ -f $FWPATH/$2 ]; then
|
||||||
|
ping -c 1 $1 >/dev/null
|
||||||
|
PINGRESULT=$?
|
||||||
|
if [ $PINGRESULT -eq 0 ]; then
|
||||||
|
echo Updating $1
|
||||||
|
curl -s -F "update=@${FWPATH}/$2" $1/update >/dev/null
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
update_one 192.168.x.x firmware.bin
|
||||||
|
update_one 192.168.x.x firmware.bin
|
||||||
|
# ...
|
55
usermods/battery_status_basic/readme.md
Normal file
55
usermods/battery_status_basic/readme.md
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
# :battery: Battery status/level Usermod :battery:
|
||||||
|
|
||||||
|
This Usermod allows you to monitor the battery level of your battery powered project.
|
||||||
|
|
||||||
|
You can see the battery level in the `info modal` right under the `estimated current`.
|
||||||
|
|
||||||
|
For this to work the positive side of the (18650) battery must be connected to pin `A0` of the d1mini/esp8266 with a 100k ohm resistor (see [Useful Links](#useful-links)).
|
||||||
|
|
||||||
|
If you have a esp32 board it is best to connect the positive side of the battery to ADC1 (GPIO32 - GPIO39)
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
define `USERMOD_BATTERY_STATUS_BASIC` in `my_config.h`
|
||||||
|
|
||||||
|
### Define Your Options
|
||||||
|
|
||||||
|
* `USERMOD_BATTERY_STATUS_BASIC` - define this (in `my_config.h`) to have this user mod included wled00\usermods_list.cpp
|
||||||
|
* `USERMOD_BATTERY_MEASUREMENT_PIN` - defaults to A0 on esp8266 and GPIO32 on esp32
|
||||||
|
* `USERMOD_BATTERY_MEASUREMENT_INTERVAL` - the frequency to check the battery, defaults to 30 seconds
|
||||||
|
* `USERMOD_BATTERY_MIN_VOLTAGE` - minimum voltage of the Battery used, default is 2.6 (18650 battery standard)
|
||||||
|
* `USERMOD_BATTERY_MAX_VOLTAGE` - maximum voltage of the Battery used, default is 4.2 (18650 battery standard)
|
||||||
|
|
||||||
|
All parameters can be configured at runtime using Usermods settings page.
|
||||||
|
|
||||||
|
## Important :warning:
|
||||||
|
* Make sure you know your battery specification ! not every battery is the same !
|
||||||
|
* Example:
|
||||||
|
|
||||||
|
| Your battery specification table | | Options you can define |
|
||||||
|
| :-------------------------------- |:--------------- | :---------------------------- |
|
||||||
|
| Capacity | 3500mAh 12,5 Wh | |
|
||||||
|
| Minimum capacity | 3350mAh 11,9 Wh | |
|
||||||
|
| Rated voltage | 3.6V - 3.7V | |
|
||||||
|
| **Charging end voltage** | **4,2V ± 0,05** | `USERMOD_BATTERY_MAX_VOLTAGE` |
|
||||||
|
| **Discharge voltage** | **2,5V** | `USERMOD_BATTERY_MIN_VOLTAGE` |
|
||||||
|
| Max. discharge current (constant) | 10A (10000mA) | |
|
||||||
|
| max. charging current | 1.7A (1700mA) | |
|
||||||
|
| ... | ... | ... |
|
||||||
|
| .. | .. | .. |
|
||||||
|
|
||||||
|
Specification from: [Molicel INR18650-M35A, 3500mAh 10A Lithium-ion battery, 3.6V - 3.7V](https://www.akkuteile.de/lithium-ionen-akkus/18650/molicel/molicel-inr18650-m35a-3500mah-10a-lithium-ionen-akku-3-6v-3-7v_100833)
|
||||||
|
|
||||||
|
## Useful Links
|
||||||
|
* https://lazyzero.de/elektronik/esp8266/wemos_d1_mini_a0/start
|
||||||
|
* https://arduinodiy.wordpress.com/2016/12/25/monitoring-lipo-battery-voltage-with-wemos-d1-minibattery-shield-and-thingspeak/
|
||||||
|
|
||||||
|
## Change Log
|
||||||
|
|
||||||
|
2021-08-15
|
||||||
|
* changed `USERMOD_BATTERY_MIN_VOLTAGE` to 2.6 volt as default for 18650 batteries
|
||||||
|
* Updated readme, added specification table
|
||||||
|
|
||||||
|
2021-08-10
|
||||||
|
* Created
|
||||||
|
|
346
usermods/battery_status_basic/usermod_v2_battery_status_basic.h
Normal file
346
usermods/battery_status_basic/usermod_v2_battery_status_basic.h
Normal file
@ -0,0 +1,346 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "wled.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// pin defaults
|
||||||
|
// for the esp32 it is best to use the ADC1: GPIO32 - GPIO39
|
||||||
|
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/adc.html
|
||||||
|
#ifndef USERMOD_BATTERY_MEASUREMENT_PIN
|
||||||
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
|
#define USERMOD_BATTERY_MEASUREMENT_PIN 32
|
||||||
|
#else //ESP8266 boards
|
||||||
|
#define USERMOD_BATTERY_MEASUREMENT_PIN A0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// esp32 has a 12bit adc resolution
|
||||||
|
// esp8266 only 10bit
|
||||||
|
#ifndef USERMOD_BATTERY_ADC_PRECISION
|
||||||
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
|
// 12 bits
|
||||||
|
#define USERMOD_BATTERY_ADC_PRECISION 4095.0
|
||||||
|
#else
|
||||||
|
// 10 bits
|
||||||
|
#define USERMOD_BATTERY_ADC_PRECISION 1024.0
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// the frequency to check the battery, 1 minute
|
||||||
|
#ifndef USERMOD_BATTERY_MEASUREMENT_INTERVAL
|
||||||
|
#define USERMOD_BATTERY_MEASUREMENT_INTERVAL 30000
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// default for 18650 battery
|
||||||
|
// https://batterybro.com/blogs/18650-wholesale-battery-reviews/18852515-when-to-recycle-18650-batteries-and-how-to-start-a-collection-center-in-your-vape-shop
|
||||||
|
// Discharge voltage: 2.5 volt + .1 for personal safety
|
||||||
|
#ifndef USERMOD_BATTERY_MIN_VOLTAGE
|
||||||
|
#define USERMOD_BATTERY_MIN_VOLTAGE 2.6
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef USERMOD_BATTERY_MAX_VOLTAGE
|
||||||
|
#define USERMOD_BATTERY_MAX_VOLTAGE 4.2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
class UsermodBatteryBasic : public Usermod
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
// battery pin can be defined in my_config.h
|
||||||
|
int8_t batteryPin = USERMOD_BATTERY_MEASUREMENT_PIN;
|
||||||
|
// how often to read the battery voltage
|
||||||
|
unsigned long readingInterval = USERMOD_BATTERY_MEASUREMENT_INTERVAL;
|
||||||
|
unsigned long lastTime = 0;
|
||||||
|
// battery min. voltage
|
||||||
|
float minBatteryVoltage = USERMOD_BATTERY_MIN_VOLTAGE;
|
||||||
|
// battery max. voltage
|
||||||
|
float maxBatteryVoltage = USERMOD_BATTERY_MAX_VOLTAGE;
|
||||||
|
// 0 - 1024 for esp8266 (10-bit resolution)
|
||||||
|
// 0 - 4095 for esp32 (Default is 12-bit resolution)
|
||||||
|
float adcPrecision = USERMOD_BATTERY_ADC_PRECISION;
|
||||||
|
// raw analog reading
|
||||||
|
float rawValue = 0.0;
|
||||||
|
// calculated voltage
|
||||||
|
float voltage = 0.0;
|
||||||
|
// mapped battery level based on voltage
|
||||||
|
long batteryLevel = 0;
|
||||||
|
bool initDone = false;
|
||||||
|
|
||||||
|
|
||||||
|
// strings to reduce flash memory usage (used more than twice)
|
||||||
|
static const char _name[];
|
||||||
|
static const char _readInterval[];
|
||||||
|
|
||||||
|
|
||||||
|
// custom map function
|
||||||
|
// https://forum.arduino.cc/t/floating-point-using-map-function/348113/2
|
||||||
|
double mapf(double x, double in_min, double in_max, double out_min, double out_max)
|
||||||
|
{
|
||||||
|
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
//Functions called by WLED
|
||||||
|
|
||||||
|
/*
|
||||||
|
* setup() is called once at boot. WiFi is not yet connected at this point.
|
||||||
|
* You can use it to initialize variables, sensors or similar.
|
||||||
|
*/
|
||||||
|
void setup()
|
||||||
|
{
|
||||||
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
|
DEBUG_PRINTLN(F("Allocating battery pin..."));
|
||||||
|
if (batteryPin >= 0 && pinManager.allocatePin(batteryPin, false))
|
||||||
|
{
|
||||||
|
DEBUG_PRINTLN(F("Battery pin allocation succeeded."));
|
||||||
|
} else {
|
||||||
|
if (batteryPin >= 0) DEBUG_PRINTLN(F("Battery pin allocation failed."));
|
||||||
|
batteryPin = -1; // allocation failed
|
||||||
|
}
|
||||||
|
#else //ESP8266 boards have only one analog input pin A0
|
||||||
|
|
||||||
|
pinMode(batteryPin, INPUT);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
initDone = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* connected() is called every time the WiFi is (re)connected
|
||||||
|
* Use it to initialize network interfaces
|
||||||
|
*/
|
||||||
|
void connected()
|
||||||
|
{
|
||||||
|
//Serial.println("Connected to WiFi!");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* loop() is called continuously. Here you can check for events, read sensors, etc.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
void loop()
|
||||||
|
{
|
||||||
|
if(strip.isUpdating()) return;
|
||||||
|
|
||||||
|
unsigned long now = millis();
|
||||||
|
|
||||||
|
// check the battery level every USERMOD_BATTERY_MEASUREMENT_INTERVAL (ms)
|
||||||
|
if (now - lastTime >= readingInterval) {
|
||||||
|
|
||||||
|
// read battery raw input
|
||||||
|
rawValue = analogRead(batteryPin);
|
||||||
|
|
||||||
|
// calculate the voltage
|
||||||
|
voltage = (rawValue / adcPrecision) * maxBatteryVoltage ;
|
||||||
|
|
||||||
|
// translate battery voltage into percentage
|
||||||
|
/*
|
||||||
|
the standard "map" function doesn't work
|
||||||
|
https://www.arduino.cc/reference/en/language/functions/math/map/ notes and warnings at the bottom
|
||||||
|
*/
|
||||||
|
batteryLevel = mapf(voltage, minBatteryVoltage, maxBatteryVoltage, 0, 100);
|
||||||
|
|
||||||
|
lastTime = now;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
|
||||||
|
JsonObject user = root["u"];
|
||||||
|
if (user.isNull()) user = root.createNestedObject("u");
|
||||||
|
|
||||||
|
JsonArray battery = user.createNestedArray("Battery level");
|
||||||
|
battery.add(batteryLevel);
|
||||||
|
battery.add(F(" %"));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 make your settings editable through the Usermod Settings page automatically.
|
||||||
|
*
|
||||||
|
* Usermod Settings Overview:
|
||||||
|
* - Numeric values are treated as floats in the browser.
|
||||||
|
* - If the numeric value entered into the browser contains a decimal point, it will be parsed as a C float
|
||||||
|
* before being returned to the Usermod. The float data type has only 6-7 decimal digits of precision, and
|
||||||
|
* doubles are not supported, numbers will be rounded to the nearest float value when being parsed.
|
||||||
|
* The range accepted by the input field is +/- 1.175494351e-38 to +/- 3.402823466e+38.
|
||||||
|
* - If the numeric value entered into the browser doesn't contain a decimal point, it will be parsed as a
|
||||||
|
* C int32_t (range: -2147483648 to 2147483647) before being returned to the usermod.
|
||||||
|
* Overflows or underflows are truncated to the max/min value for an int32_t, and again truncated to the type
|
||||||
|
* used in the Usermod when reading the value from ArduinoJson.
|
||||||
|
* - Pin values can be treated differently from an integer value by using the key name "pin"
|
||||||
|
* - "pin" can contain a single or array of integer values
|
||||||
|
* - On the Usermod Settings page there is simple checking for pin conflicts and warnings for special pins
|
||||||
|
* - Red color indicates a conflict. Yellow color indicates a pin with a warning (e.g. an input-only pin)
|
||||||
|
* - Tip: use int8_t to store the pin value in the Usermod, so a -1 value (pin not set) can be used
|
||||||
|
*
|
||||||
|
* See usermod_v2_auto_save.h for an example that saves Flash space by reusing ArduinoJson key name strings
|
||||||
|
*
|
||||||
|
* If you need a dedicated settings page with custom layout for your Usermod, that takes a lot more work.
|
||||||
|
* You will have to add the setting to the HTML, xml.cpp and set.cpp manually.
|
||||||
|
* See the WLED Soundreactive fork (code and wiki) for reference. https://github.com/atuline/WLED
|
||||||
|
*
|
||||||
|
* I highly recommend checking out the basics of ArduinoJson serialization and deserialization in order to use custom settings!
|
||||||
|
*/
|
||||||
|
void addToConfig(JsonObject& root)
|
||||||
|
{
|
||||||
|
// created JSON object:
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
"Battery-Level": {
|
||||||
|
"pin": "A0", <--- only when using esp32 boards
|
||||||
|
"minBatteryVoltage": 2.6,
|
||||||
|
"maxBatteryVoltage": 4.2,
|
||||||
|
"read-interval-ms": 30000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
JsonObject battery = root.createNestedObject(FPSTR(_name)); // usermodname
|
||||||
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
|
battery["pin"] = batteryPin; // usermodparam
|
||||||
|
#endif
|
||||||
|
battery["minBatteryVoltage"] = minBatteryVoltage; // usermodparam
|
||||||
|
battery["maxBatteryVoltage"] = maxBatteryVoltage; // usermodparam
|
||||||
|
battery[FPSTR(_readInterval)] = readingInterval;
|
||||||
|
|
||||||
|
DEBUG_PRINTLN(F("Battery config saved."));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 immediately after boot, or after saving on the Usermod Settings page)
|
||||||
|
*
|
||||||
|
* 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 :)
|
||||||
|
*
|
||||||
|
* Return true in case the config values returned from Usermod Settings were complete, or false if you'd like WLED to save your defaults to disk (so any missing values are editable in Usermod Settings)
|
||||||
|
*
|
||||||
|
* getJsonValue() returns false if the value is missing, or copies the value into the variable provided and returns true if the value is present
|
||||||
|
* The configComplete variable is true only if the "exampleUsermod" object and all values are present. If any values are missing, WLED will know to call addToConfig() to save them
|
||||||
|
*
|
||||||
|
* This function is guaranteed to be called on boot, but could also be called every time settings are updated
|
||||||
|
*/
|
||||||
|
bool readFromConfig(JsonObject& root)
|
||||||
|
{
|
||||||
|
// looking for JSON object:
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
"BatteryLevel": {
|
||||||
|
"pin": "A0", <--- only when using esp32 boards
|
||||||
|
"minBatteryVoltage": 2.6,
|
||||||
|
"maxBatteryVoltage": 4.2,
|
||||||
|
"read-interval-ms": 30000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
|
int8_t newBatteryPin = batteryPin;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
JsonObject battery = root[FPSTR(_name)];
|
||||||
|
if (battery.isNull())
|
||||||
|
{
|
||||||
|
DEBUG_PRINT(FPSTR(_name));
|
||||||
|
DEBUG_PRINTLN(F(": No config found. (Using defaults.)"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
|
newBatteryPin = battery["pin"] | newBatteryPin;
|
||||||
|
#endif
|
||||||
|
minBatteryVoltage = battery["minBatteryVoltage"] | minBatteryVoltage;
|
||||||
|
//minBatteryVoltage = min(12.0f, (int)readingInterval);
|
||||||
|
maxBatteryVoltage = battery["maxBatteryVoltage"] | maxBatteryVoltage;
|
||||||
|
//maxBatteryVoltage = min(14.4f, max(3.3f,(int)readingInterval));
|
||||||
|
readingInterval = battery["read-interval-ms"] | readingInterval;
|
||||||
|
readingInterval = max(3000, (int)readingInterval); // minimum repetition is >5000ms (5s)
|
||||||
|
|
||||||
|
DEBUG_PRINT(FPSTR(_name));
|
||||||
|
|
||||||
|
#ifdef ARDUINO_ARCH_ESP32
|
||||||
|
if (!initDone)
|
||||||
|
{
|
||||||
|
// first run: reading from cfg.json
|
||||||
|
newBatteryPin = batteryPin;
|
||||||
|
DEBUG_PRINTLN(F(" config loaded."));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||||
|
|
||||||
|
// changing paramters from settings page
|
||||||
|
if (newBatteryPin != batteryPin)
|
||||||
|
{
|
||||||
|
// deallocate pin
|
||||||
|
pinManager.deallocatePin(batteryPin);
|
||||||
|
batteryPin = newBatteryPin;
|
||||||
|
// initialise
|
||||||
|
setup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return !battery[FPSTR(_readInterval)].isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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()
|
||||||
|
{
|
||||||
|
return USERMOD_ID_BATTERY_STATUS_BASIC;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// strings to reduce flash memory usage (used more than twice)
|
||||||
|
const char UsermodBatteryBasic::_name[] PROGMEM = "Battery-level";
|
||||||
|
const char UsermodBatteryBasic::_readInterval[] PROGMEM = "read-interval-ms";
|
@ -301,6 +301,10 @@ bool deserializeConfig(JsonObject doc, bool fromFS) {
|
|||||||
CJSON(arlsDisableGammaCorrection, if_live[F("no-gc")]); // false
|
CJSON(arlsDisableGammaCorrection, if_live[F("no-gc")]); // false
|
||||||
CJSON(arlsOffset, if_live[F("offset")]); // 0
|
CJSON(arlsOffset, if_live[F("offset")]); // 0
|
||||||
|
|
||||||
|
CJSON(liveHSVCorrection, if_live[F("corr")]);
|
||||||
|
CJSON(liveHSVSaturation, if_live[F("hsvsat")]);
|
||||||
|
CJSON(liveHSVValue, if_live[F("hsvval")]);
|
||||||
|
|
||||||
CJSON(alexaEnabled, interfaces["va"][F("alexa")]); // false
|
CJSON(alexaEnabled, interfaces["va"][F("alexa")]); // false
|
||||||
|
|
||||||
CJSON(macroAlexaOn, interfaces["va"]["macros"][0]);
|
CJSON(macroAlexaOn, interfaces["va"]["macros"][0]);
|
||||||
@ -658,10 +662,14 @@ void serializeConfig() {
|
|||||||
if_live_dmx[F("seqskip")] = e131SkipOutOfSequence;
|
if_live_dmx[F("seqskip")] = e131SkipOutOfSequence;
|
||||||
if_live_dmx[F("addr")] = DMXAddress;
|
if_live_dmx[F("addr")] = DMXAddress;
|
||||||
if_live_dmx[F("mode")] = DMXMode;
|
if_live_dmx[F("mode")] = DMXMode;
|
||||||
|
|
||||||
if_live[F("timeout")] = realtimeTimeoutMs / 100;
|
if_live[F("timeout")] = realtimeTimeoutMs / 100;
|
||||||
if_live[F("maxbri")] = arlsForceMaxBri;
|
if_live[F("maxbri")] = arlsForceMaxBri;
|
||||||
if_live[F("no-gc")] = arlsDisableGammaCorrection;
|
if_live[F("no-gc")] = arlsDisableGammaCorrection;
|
||||||
if_live[F("offset")] = arlsOffset;
|
if_live[F("offset")] = arlsOffset;
|
||||||
|
if_live[F("corr")] = liveHSVCorrection;
|
||||||
|
if_live[F("hsvsat")] = liveHSVSaturation;
|
||||||
|
if_live[F("hsvval")] = liveHSVValue;
|
||||||
|
|
||||||
JsonObject if_va = interfaces.createNestedObject("va");
|
JsonObject if_va = interfaces.createNestedObject("va");
|
||||||
if_va[F("alexa")] = alexaEnabled;
|
if_va[F("alexa")] = alexaEnabled;
|
||||||
|
@ -47,6 +47,77 @@ void relativeChangeWhite(int8_t amount, byte lowerBoundary)
|
|||||||
col[3] = new_val;
|
col[3] = new_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void colorHSVtoRGB(float hue, float saturation, float value, byte& red, byte& green, byte& blue)
|
||||||
|
{
|
||||||
|
float r, g, b;
|
||||||
|
|
||||||
|
auto i = static_cast<int>(hue * 6);
|
||||||
|
auto f = hue * 6 - i;
|
||||||
|
auto p = value * (1 - saturation);
|
||||||
|
auto q = value * (1 - f * saturation);
|
||||||
|
auto t = value * (1 - (1 - f) * saturation);
|
||||||
|
|
||||||
|
switch (i % 6)
|
||||||
|
{
|
||||||
|
case 0: r = value, g = t, b = p;
|
||||||
|
break;
|
||||||
|
case 1: r = q, g = value, b = p;
|
||||||
|
break;
|
||||||
|
case 2: r = p, g = value, b = t;
|
||||||
|
break;
|
||||||
|
case 3: r = p, g = q, b = value;
|
||||||
|
break;
|
||||||
|
case 4: r = t, g = p, b = value;
|
||||||
|
break;
|
||||||
|
case 5: r = value, g = p, b = q;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
red = static_cast<uint8_t>(r * 255);
|
||||||
|
green = static_cast<uint8_t>(g * 255);
|
||||||
|
blue = static_cast<uint8_t>(b * 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
void colorRGBtoHSV(byte red, byte green, byte blue, float& hue, float& saturation, float& value)
|
||||||
|
{
|
||||||
|
auto rd = static_cast<float>(red) / 255;
|
||||||
|
auto gd = static_cast<float>(green) / 255;
|
||||||
|
auto bd = static_cast<float>(blue) / 255;
|
||||||
|
auto max = std::max({ rd, gd, bd }), min = std::min({ rd, gd, bd });
|
||||||
|
|
||||||
|
value = max;
|
||||||
|
|
||||||
|
auto d = max - min;
|
||||||
|
saturation = max == 0 ? 0 : d / max;
|
||||||
|
|
||||||
|
hue = 0;
|
||||||
|
if (max != min)
|
||||||
|
{
|
||||||
|
if (max == rd) hue = (gd - bd) / d + (gd < bd ? 6 : 0);
|
||||||
|
else if (max == gd) hue = (bd - rd) / d + 2;
|
||||||
|
else if (max == bd) hue = (rd - gd) / d + 4;
|
||||||
|
hue /= 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#define SATURATION_THRESHOLD 0.1
|
||||||
|
#define MAX_HSV_VALUE 1
|
||||||
|
#define MAX_HSV_SATURATION 1
|
||||||
|
|
||||||
|
//corrects the realtime colors. 10 is the unchanged saturation/value
|
||||||
|
//this feature might cause slowdowns with large LED counts
|
||||||
|
void correctColors(byte r, byte g, byte b, byte* rgb) {
|
||||||
|
float hsv[3] = { 0,0,0 };
|
||||||
|
colorRGBtoHSV(r, g,b , hsv[0], hsv[1], hsv[2]);
|
||||||
|
float saturated = hsv[1] > SATURATION_THRESHOLD ?
|
||||||
|
hsv[1] * ((float)liveHSVSaturation / 10) : hsv[1];
|
||||||
|
float saturation = saturated < MAX_HSV_SATURATION ? saturated : MAX_HSV_SATURATION;
|
||||||
|
|
||||||
|
float valued = hsv[2] * ((float)liveHSVValue/10);
|
||||||
|
float value = valued < MAX_HSV_VALUE ? valued : MAX_HSV_VALUE;
|
||||||
|
colorHSVtoRGB(hsv[0], saturation, value, rgb[0], rgb[1], rgb[2]);
|
||||||
|
}
|
||||||
|
|
||||||
void colorHStoRGB(uint16_t hue, byte sat, byte* rgb) //hue, sat to rgb
|
void colorHStoRGB(uint16_t hue, byte sat, byte* rgb) //hue, sat to rgb
|
||||||
{
|
{
|
||||||
float h = ((float)hue)/65535.0;
|
float h = ((float)hue)/65535.0;
|
||||||
|
@ -58,6 +58,7 @@
|
|||||||
#define USERMOD_ID_RTC 15 //Usermod "usermod_rtc.h"
|
#define USERMOD_ID_RTC 15 //Usermod "usermod_rtc.h"
|
||||||
#define USERMOD_ID_ELEKSTUBE_IPS 16 //Usermod "usermod_elekstube_ips.h"
|
#define USERMOD_ID_ELEKSTUBE_IPS 16 //Usermod "usermod_elekstube_ips.h"
|
||||||
#define USERMOD_ID_SN_PHOTORESISTOR 17 //Usermod "usermod_sn_photoresistor.h"
|
#define USERMOD_ID_SN_PHOTORESISTOR 17 //Usermod "usermod_sn_photoresistor.h"
|
||||||
|
#define USERMOD_ID_BATTERY_STATUS_BASIC 18 //Usermod "usermod_v2_battery_status_basic.h"
|
||||||
|
|
||||||
//Access point behavior
|
//Access point behavior
|
||||||
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
|
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot
|
||||||
|
@ -31,7 +31,7 @@ Send notifications twice: <input type="checkbox" name="S2"><br>
|
|||||||
<i>Reboot required to apply changes. </i>
|
<i>Reboot required to apply changes. </i>
|
||||||
<h3>Instance List</h3>
|
<h3>Instance List</h3>
|
||||||
Enable instance list: <input type="checkbox" name="NL"><br>
|
Enable instance list: <input type="checkbox" name="NL"><br>
|
||||||
Make this instance discoverable: <input type="checkbox" name="NB"><br>
|
Make this instance discoverable: <input type="checkbox" name="NB">
|
||||||
<h3>Realtime</h3>
|
<h3>Realtime</h3>
|
||||||
Receive UDP realtime: <input type="checkbox" name="RD"><br><br>
|
Receive UDP realtime: <input type="checkbox" name="RD"><br><br>
|
||||||
<i>Network DMX input</i><br>
|
<i>Network DMX input</i><br>
|
||||||
@ -62,7 +62,10 @@ DMX mode:
|
|||||||
Timeout: <input name="ET" type="number" min="1" max="65000" required> ms<br>
|
Timeout: <input name="ET" type="number" min="1" max="65000" required> ms<br>
|
||||||
Force max brightness: <input type="checkbox" name="FB"><br>
|
Force max brightness: <input type="checkbox" name="FB"><br>
|
||||||
Disable realtime gamma correction: <input type="checkbox" name="RG"><br>
|
Disable realtime gamma correction: <input type="checkbox" name="RG"><br>
|
||||||
Realtime LED offset: <input name="WO" type="number" min="-255" max="255" required>
|
Realtime LED offset: <input name="WO" type="number" min="-255" max="255" required><br><br>
|
||||||
|
Realtime HSV color correction: <input type="checkbox" name="HX"><br>
|
||||||
|
Saturation (1-30): <input name="HS" type="number" min="1" max="30" value="1" step="1"><br>
|
||||||
|
Value (1-60): <input name="HV" type="number" min="1" max="60" value="10" step="1">
|
||||||
<h3>Alexa Voice Assistant</h3>
|
<h3>Alexa Voice Assistant</h3>
|
||||||
Emulate Alexa device: <input type="checkbox" name="AL"><br>
|
Emulate Alexa device: <input type="checkbox" name="AL"><br>
|
||||||
Alexa invocation name: <input name="AI" maxlength="32">
|
Alexa invocation name: <input name="AI" maxlength="32">
|
||||||
|
@ -60,6 +60,9 @@ void colorFromUint32(uint32_t in, bool secondary = false);
|
|||||||
void colorFromUint24(uint32_t in, bool secondary = false);
|
void colorFromUint24(uint32_t in, bool secondary = false);
|
||||||
uint32_t colorFromRgbw(byte* rgbw);
|
uint32_t colorFromRgbw(byte* rgbw);
|
||||||
void relativeChangeWhite(int8_t amount, byte lowerBoundary = 0);
|
void relativeChangeWhite(int8_t amount, byte lowerBoundary = 0);
|
||||||
|
void colorHSVtoRGB(float hue, float saturation, float value, byte& red, byte& green, byte& blue);
|
||||||
|
void colorRGBtoHSV(byte red, byte green, byte blue, float& hue, float& saturation, float& value);
|
||||||
|
void correctColors(byte r, byte g, byte b, byte* rgb);
|
||||||
void colorHStoRGB(uint16_t hue, byte sat, byte* rgb); //hue, sat to rgb
|
void colorHStoRGB(uint16_t hue, byte sat, byte* rgb); //hue, sat to rgb
|
||||||
void colorKtoRGB(uint16_t kelvin, byte* rgb);
|
void colorKtoRGB(uint16_t kelvin, byte* rgb);
|
||||||
void colorCTtoRGB(uint16_t mired, byte* rgb); //white spectrum to rgb
|
void colorCTtoRGB(uint16_t mired, byte* rgb); //white spectrum to rgb
|
||||||
|
@ -256,8 +256,8 @@ Send Macro notifications: <input type="checkbox" name="SM"><br>
|
|||||||
Send notifications twice: <input type="checkbox" name="S2"><br><i>
|
Send notifications twice: <input type="checkbox" name="S2"><br><i>
|
||||||
Reboot required to apply changes.</i><h3>Instance List</h3>
|
Reboot required to apply changes.</i><h3>Instance List</h3>
|
||||||
Enable instance list: <input type="checkbox" name="NL"><br>
|
Enable instance list: <input type="checkbox" name="NL"><br>
|
||||||
Make this instance discoverable: <input type="checkbox" name="NB"><br><h3>
|
Make this instance discoverable: <input type="checkbox" name="NB"><h3>Realtime
|
||||||
Realtime</h3>Receive UDP realtime: <input type="checkbox" name="RD"><br><br><i>
|
</h3>Receive UDP realtime: <input type="checkbox" name="RD"><br><br><i>
|
||||||
Network DMX input</i><br>Type: <select name="DI" onchange="SP(),adj()"><option
|
Network DMX input</i><br>Type: <select name="DI" onchange="SP(),adj()"><option
|
||||||
value="5568">E1.31 (sACN)</option><option value="6454">Art-Net</option><option
|
value="5568">E1.31 (sACN)</option><option value="6454">Art-Net</option><option
|
||||||
value="4048">DDP</option><option value="0" selected="selected">Custom port
|
value="4048">DDP</option><option value="0" selected="selected">Custom port
|
||||||
@ -277,9 +277,12 @@ E1.31 info</a><br>Timeout: <input name="ET" type="number" min="1" max="65000"
|
|||||||
required> ms<br>Force max brightness: <input type="checkbox" name="FB"><br>
|
required> ms<br>Force max brightness: <input type="checkbox" name="FB"><br>
|
||||||
Disable realtime gamma correction: <input type="checkbox" name="RG"><br>
|
Disable realtime gamma correction: <input type="checkbox" name="RG"><br>
|
||||||
Realtime LED offset: <input name="WO" type="number" min="-255" max="255"
|
Realtime LED offset: <input name="WO" type="number" min="-255" max="255"
|
||||||
required><h3>Alexa Voice Assistant</h3>Emulate Alexa device: <input
|
required><br><br>Realtime HSV color correction: <input type="checkbox"
|
||||||
type="checkbox" name="AL"><br>Alexa invocation name: <input name="AI"
|
name="HX"><br>Saturation (1-30): <input name="HS" type="number" min="1"
|
||||||
maxlength="32"><h3>Blynk</h3><b>
|
max="30" value="1" step="1"><br>Value (1-60): <input name="HV" type="number"
|
||||||
|
min="1" max="60" value="10" step="1"><h3>Alexa Voice Assistant</h3>
|
||||||
|
Emulate Alexa device: <input type="checkbox" name="AL"><br>
|
||||||
|
Alexa invocation name: <input name="AI" maxlength="32"><h3>Blynk</h3><b>
|
||||||
Blynk, MQTT and Hue sync all connect to external hosts!<br>
|
Blynk, MQTT and Hue sync all connect to external hosts!<br>
|
||||||
This may impact the responsiveness of the ESP8266.</b><br>
|
This may impact the responsiveness of the ESP8266.</b><br>
|
||||||
For best results, only use one of these services at a time.<br>
|
For best results, only use one of these services at a time.<br>
|
||||||
|
@ -220,6 +220,10 @@ void handleSettingsSet(AsyncWebServerRequest *request, byte subPage)
|
|||||||
notifyMacro = request->hasArg(F("SM"));
|
notifyMacro = request->hasArg(F("SM"));
|
||||||
notifyTwice = request->hasArg(F("S2"));
|
notifyTwice = request->hasArg(F("S2"));
|
||||||
|
|
||||||
|
liveHSVCorrection = request->hasArg(F("HX"));
|
||||||
|
liveHSVSaturation = request->arg(F("HS")).toInt();
|
||||||
|
liveHSVValue = request->arg(F("HV")).toInt();
|
||||||
|
|
||||||
nodeListEnabled = request->hasArg(F("NL"));
|
nodeListEnabled = request->hasArg(F("NL"));
|
||||||
if (!nodeListEnabled) Nodes.clear();
|
if (!nodeListEnabled) Nodes.clear();
|
||||||
nodeBroadcastEnabled = request->hasArg(F("NB"));
|
nodeBroadcastEnabled = request->hasArg(F("NB"));
|
||||||
|
@ -165,7 +165,6 @@ void handleNotifications()
|
|||||||
for (uint16_t i = 0; i < packetSize -2; i += 3)
|
for (uint16_t i = 0; i < packetSize -2; i += 3)
|
||||||
{
|
{
|
||||||
setRealtimePixel(id, lbuf[i], lbuf[i+1], lbuf[i+2], 0);
|
setRealtimePixel(id, lbuf[i], lbuf[i+1], lbuf[i+2], 0);
|
||||||
|
|
||||||
id++; if (id >= ledCount) break;
|
id++; if (id >= ledCount) break;
|
||||||
}
|
}
|
||||||
strip.show();
|
strip.show();
|
||||||
@ -428,6 +427,11 @@ void setRealtimePixel(uint16_t i, byte r, byte g, byte b, byte w)
|
|||||||
uint16_t pix = i + arlsOffset;
|
uint16_t pix = i + arlsOffset;
|
||||||
if (pix < ledCount)
|
if (pix < ledCount)
|
||||||
{
|
{
|
||||||
|
if (liveHSVCorrection) {
|
||||||
|
byte correctedColors[3] = {0,0,0};
|
||||||
|
correctColors(r, g, b, correctedColors);
|
||||||
|
r = correctedColors[0]; g = correctedColors[1]; b = correctedColors[2];
|
||||||
|
}
|
||||||
if (!arlsDisableGammaCorrection && strip.gammaCorrectCol)
|
if (!arlsDisableGammaCorrection && strip.gammaCorrectCol)
|
||||||
{
|
{
|
||||||
strip.setPixelColor(pix, strip.gamma8(r), strip.gamma8(g), strip.gamma8(b), strip.gamma8(w));
|
strip.setPixelColor(pix, strip.gamma8(r), strip.gamma8(g), strip.gamma8(b), strip.gamma8(w));
|
||||||
|
@ -11,6 +11,10 @@
|
|||||||
*/
|
*/
|
||||||
//#include "../usermods/EXAMPLE_v2/usermod_v2_example.h"
|
//#include "../usermods/EXAMPLE_v2/usermod_v2_example.h"
|
||||||
|
|
||||||
|
#ifdef USERMOD_BATTERY_STATUS_BASIC
|
||||||
|
#include "../usermods/battery_status_basic/usermod_v2_battery_status_basic.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USERMOD_DALLASTEMPERATURE
|
#ifdef USERMOD_DALLASTEMPERATURE
|
||||||
#include "../usermods/Temperature/usermod_temperature.h"
|
#include "../usermods/Temperature/usermod_temperature.h"
|
||||||
#endif
|
#endif
|
||||||
@ -91,6 +95,10 @@ void registerUsermods()
|
|||||||
*/
|
*/
|
||||||
//usermods.add(new MyExampleUsermod());
|
//usermods.add(new MyExampleUsermod());
|
||||||
|
|
||||||
|
#ifdef USERMOD_BATTERY_STATUS_BASIC
|
||||||
|
usermods.add(new UsermodBatteryBasic());
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef USERMOD_DALLASTEMPERATURE
|
#ifdef USERMOD_DALLASTEMPERATURE
|
||||||
usermods.add(new UsermodTemperature());
|
usermods.add(new UsermodTemperature());
|
||||||
#endif
|
#endif
|
||||||
|
@ -297,6 +297,9 @@ WLED_GLOBAL byte irEnabled _INIT(0); // Infrared receiver
|
|||||||
WLED_GLOBAL uint16_t udpPort _INIT(21324); // WLED notifier default port
|
WLED_GLOBAL uint16_t udpPort _INIT(21324); // WLED notifier default port
|
||||||
WLED_GLOBAL uint16_t udpPort2 _INIT(65506); // WLED notifier supplemental port
|
WLED_GLOBAL uint16_t udpPort2 _INIT(65506); // WLED notifier supplemental port
|
||||||
WLED_GLOBAL uint16_t udpRgbPort _INIT(19446); // Hyperion port
|
WLED_GLOBAL uint16_t udpRgbPort _INIT(19446); // Hyperion port
|
||||||
|
WLED_GLOBAL bool liveHSVCorrection _INIT(false);
|
||||||
|
WLED_GLOBAL uint16_t liveHSVSaturation _INIT(13);
|
||||||
|
WLED_GLOBAL uint16_t liveHSVValue _INIT(10);
|
||||||
|
|
||||||
WLED_GLOBAL bool receiveNotificationBrightness _INIT(true); // apply brightness from incoming notifications
|
WLED_GLOBAL bool receiveNotificationBrightness _INIT(true); // apply brightness from incoming notifications
|
||||||
WLED_GLOBAL bool receiveNotificationColor _INIT(true); // apply color
|
WLED_GLOBAL bool receiveNotificationColor _INIT(true); // apply color
|
||||||
|
@ -429,6 +429,11 @@ void getSettingsJS(byte subPage, char* dest)
|
|||||||
{
|
{
|
||||||
sappend('v',SET_F("UP"),udpPort);
|
sappend('v',SET_F("UP"),udpPort);
|
||||||
sappend('v',SET_F("U2"),udpPort2);
|
sappend('v',SET_F("U2"),udpPort2);
|
||||||
|
|
||||||
|
sappend('c',SET_F("HX"),liveHSVCorrection);
|
||||||
|
sappend('v',SET_F("HS"),liveHSVSaturation);
|
||||||
|
sappend('v',SET_F("HV"),liveHSVValue);
|
||||||
|
|
||||||
sappend('c',SET_F("RB"),receiveNotificationBrightness);
|
sappend('c',SET_F("RB"),receiveNotificationBrightness);
|
||||||
sappend('c',SET_F("RC"),receiveNotificationColor);
|
sappend('c',SET_F("RC"),receiveNotificationColor);
|
||||||
sappend('c',SET_F("RX"),receiveNotificationEffects);
|
sappend('c',SET_F("RX"),receiveNotificationEffects);
|
||||||
|
Loading…
Reference in New Issue
Block a user