Merge remote-tracking branch 'origin/segment-api' into segment-api
This commit is contained in:
commit
d3e9f51d6b
6
package-lock.json
generated
6
package-lock.json
generated
@ -2067,9 +2067,9 @@
|
|||||||
"integrity": "sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw=="
|
"integrity": "sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw=="
|
||||||
},
|
},
|
||||||
"terser": {
|
"terser": {
|
||||||
"version": "4.8.0",
|
"version": "4.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/terser/-/terser-4.8.1.tgz",
|
||||||
"integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==",
|
"integrity": "sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"commander": "^2.20.0",
|
"commander": "^2.20.0",
|
||||||
"source-map": "~0.6.1",
|
"source-map": "~0.6.1",
|
||||||
|
@ -1,36 +1,60 @@
|
|||||||
Hello! I have written a v2 usermod for the BME280/BMP280 sensor based on the [existing v1 usermod](https://github.com/Aircoookie/WLED/blob/master/usermods/Wemos_D1_mini%2BWemos32_mini_shield/usermod_bme280.cpp). It is not just a refactor, there are many changes which I made to fit my use case, and I hope they will fit the use cases of others as well! Most notably, this usermod is *just* for the BME280 and does not control a display like in the v1 usermod designed for the WeMos shield.
|
# Usermod BME280
|
||||||
|
This Usermod is designed to read a `BME280` or `BMP280` sensor and output the following:
|
||||||
|
- Temperature
|
||||||
|
- Humidity (`BME280` only)
|
||||||
|
- Pressure
|
||||||
|
- Heat Index (`BME280` only)
|
||||||
|
- Dew Point (`BME280` only)
|
||||||
|
|
||||||
- Requires libraries `BME280@~3.0.0` (by [finitespace](https://github.com/finitespace/BME280)) and `Wire`. Please add these under `lib_deps` in your `platform.ini` (or `platform_override.ini`).
|
Configuration is all completed via the Usermod menu. There are no settings to set in code! The following settings can be configured in the Usermod Menu:
|
||||||
- Data is published over MQTT so make sure you've enabled the MQTT sync interface.
|
- Temperature Decimals (number of decimal places to output)
|
||||||
|
- Humidity Decimals
|
||||||
|
- Pressure Decimals
|
||||||
|
- Temperature Interval (how many seconds between reads of temperature and humidity)
|
||||||
|
- Pressure Interval
|
||||||
|
- Publish Always (turn off to only publish changes, on to publish whether or not value changed)
|
||||||
|
- Use Celsius (turn off to use Farenheit)
|
||||||
|
- Home Assistant Discovery (turn on to sent MQTT Discovery entries for Home Assistant)
|
||||||
|
- SCL/SDA GPIO Pins
|
||||||
|
|
||||||
|
Dependencies
|
||||||
|
- Libraries
|
||||||
|
- `BME280@~3.0.0` (by [finitespace](https://github.com/finitespace/BME280))
|
||||||
|
- `Wire`
|
||||||
|
- 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.
|
||||||
- This usermod also writes to serial (GPIO1 on ESP8266). Please make sure nothing else listening on the serial TX pin of your board will get confused by log messages!
|
- This usermod also writes to serial (GPIO1 on ESP8266). Please make sure nothing else listening on the serial TX pin of your board will get confused by log messages!
|
||||||
|
|
||||||
To enable, compile with `USERMOD_BME280` defined (i.e. `platformio_override.ini`)
|
In addition to outputting via MQTT, you can read the values from the Info Screen on the dashboard page of the device's web interface.
|
||||||
|
|
||||||
|
Methods also exist to read the read/calculated values from other WLED modules through code.
|
||||||
|
- `getTemperatureC()`
|
||||||
|
- `getTemperatureF()`
|
||||||
|
- `getHumidity()`
|
||||||
|
- `getPressure()`
|
||||||
|
- `getDewPointC()`
|
||||||
|
- `getDewPointF()`
|
||||||
|
- `getHeatIndexC()`
|
||||||
|
- `getHeatIndexF()`
|
||||||
|
|
||||||
|
# Complilation
|
||||||
|
|
||||||
|
To enable, compile with `USERMOD_BME280` defined (e.g. in `platformio_override.ini`)
|
||||||
```ini
|
```ini
|
||||||
|
[env:usermod_bme280_d1_mini]
|
||||||
|
extends = env:d1_mini
|
||||||
build_flags =
|
build_flags =
|
||||||
${common.build_flags_esp8266}
|
${common.build_flags_esp8266}
|
||||||
-D USERMOD_BME280
|
-D USERMOD_BME280
|
||||||
```
|
lib_deps =
|
||||||
or define `USERMOD_BME280` in `my_config.h`
|
${esp8266.lib_deps}
|
||||||
```c++
|
BME280@~3.0.0
|
||||||
#define USERMOD_BME280
|
Wire
|
||||||
```
|
```
|
||||||
|
|
||||||
Changes include:
|
|
||||||
- Adjustable measure intervals
|
|
||||||
- Temperature and pressure have separate intervals due to pressure not frequently changing at any constant altitude
|
|
||||||
- Adjustment of number of decimal places in published sensor values
|
|
||||||
- Separate adjustment for temperature, humidity and pressure values
|
|
||||||
- Values are rounded to the specified number of decimal places
|
|
||||||
- Pressure measured in units of hPa instead of Pa
|
|
||||||
- Calculation of heat index (apparent temperature) and dew point
|
|
||||||
- These, along with humidity measurements, are disabled if the sensor is a BMP280
|
|
||||||
- 16x oversampling of sensor during measurement
|
|
||||||
- Values are only published if they are different from the previous value
|
|
||||||
- Values are published on startup (continually until the MQTT broker acknowledges a successful publication)
|
|
||||||
|
|
||||||
Adjustments are made through preprocessor definitions at the start of the class definition.
|
# MQTT
|
||||||
|
MQTT topics are as follows (`<deviceTopic>` is set in MQTT section of Sync Setup menu):
|
||||||
MQTT topics are as follows:
|
|
||||||
Measurement type | MQTT topic
|
Measurement type | MQTT topic
|
||||||
--- | ---
|
--- | ---
|
||||||
Temperature | `<deviceTopic>/temperature`
|
Temperature | `<deviceTopic>/temperature`
|
||||||
@ -38,3 +62,29 @@ Humidity | `<deviceTopic>/humidity`
|
|||||||
Pressure | `<deviceTopic>/pressure`
|
Pressure | `<deviceTopic>/pressure`
|
||||||
Heat index | `<deviceTopic>/heat_index`
|
Heat index | `<deviceTopic>/heat_index`
|
||||||
Dew point | `<deviceTopic>/dew_point`
|
Dew point | `<deviceTopic>/dew_point`
|
||||||
|
|
||||||
|
If you are using Home Assistant, and `Home Assistant Discovery` is turned on, Home Assistant should automatically detect a new device, provided you have the MQTT integration installed. The device is seperate from the main WLED device and will contain sensors for Pressure, Humidity, Temperature, Dew Point and Heat Index.
|
||||||
|
|
||||||
|
# Revision History
|
||||||
|
Jul 2022
|
||||||
|
- Added Home Assistant Discovery
|
||||||
|
- Added API interface to output data
|
||||||
|
- Removed compile-time variables
|
||||||
|
- Added usermod menu interface
|
||||||
|
- Added value outputs to info screen
|
||||||
|
- Updated `readme.md`
|
||||||
|
- Registered usermod
|
||||||
|
- Implemented PinManager for usermod
|
||||||
|
- Implemented reallocation of pins without reboot
|
||||||
|
|
||||||
|
Apr 2021
|
||||||
|
- Added `Publish Always` option
|
||||||
|
|
||||||
|
Dec 2020
|
||||||
|
- Ported to V2 Usermod format
|
||||||
|
- Customisable `measure intervals`
|
||||||
|
- Customisable number of `decimal places` in published sensor values
|
||||||
|
- Pressure measured in units of hPa instead of Pa
|
||||||
|
- Calculation of heat index (apparent temperature) and dew point
|
||||||
|
- `16x oversampling` of sensor during measurement
|
||||||
|
- Values only published if they are different from the previous value
|
@ -1,3 +1,6 @@
|
|||||||
|
// force the compiler to show a warning to confirm that this file is included
|
||||||
|
#warning **** Included USERMOD_BME280 version 2.0 ****
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "wled.h"
|
#include "wled.h"
|
||||||
@ -9,43 +12,30 @@
|
|||||||
class UsermodBME280 : public Usermod
|
class UsermodBME280 : public Usermod
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
// User-defined configuration
|
|
||||||
#define Celsius // Show temperature mesaurement in Celcius. Comment out for Fahrenheit
|
|
||||||
#define TemperatureDecimals 1 // Number of decimal places in published temperaure values
|
|
||||||
#define HumidityDecimals 2 // Number of decimal places in published humidity values
|
|
||||||
#define PressureDecimals 2 // Number of decimal places in published pressure values
|
|
||||||
#define TemperatureInterval 5 // Interval to measure temperature (and humidity, dew point if available) in seconds
|
|
||||||
#define PressureInterval 300 // Interval to measure pressure in seconds
|
|
||||||
#define PublishAlways 0 // Publish values even when they have not changed
|
|
||||||
|
|
||||||
// Sanity checks
|
// NOTE: Do not implement any compile-time variables, anything the user needs to configure
|
||||||
#if !defined(TemperatureDecimals) || TemperatureDecimals < 0
|
// should be configurable from the Usermod menu using the methods below
|
||||||
#define TemperatureDecimals 0
|
// key settings set via usermod menu
|
||||||
#endif
|
unsigned long TemperatureDecimals = 0; // Number of decimal places in published temperaure values
|
||||||
#if !defined(HumidityDecimals) || HumidityDecimals < 0
|
unsigned long HumidityDecimals = 0; // Number of decimal places in published humidity values
|
||||||
#define HumidityDecimals 0
|
unsigned long PressureDecimals = 0; // Number of decimal places in published pressure values
|
||||||
#endif
|
unsigned long TemperatureInterval = 5; // Interval to measure temperature (and humidity, dew point if available) in seconds
|
||||||
#if !defined(PressureDecimals) || PressureDecimals < 0
|
unsigned long PressureInterval = 300; // Interval to measure pressure in seconds
|
||||||
#define PressureDecimals 0
|
bool PublishAlways = false; // Publish values even when they have not changed
|
||||||
#endif
|
bool UseCelsius = true; // Use Celsius for Reporting
|
||||||
#if !defined(TemperatureInterval) || TemperatureInterval < 0
|
bool HomeAssistantDiscovery = false; // Publish Home Assistant Device Information
|
||||||
#define TemperatureInterval 1
|
|
||||||
#endif
|
|
||||||
#if !defined(PressureInterval) || PressureInterval < 0
|
|
||||||
#define PressureInterval TemperatureInterval
|
|
||||||
#endif
|
|
||||||
#if !defined(PublishAlways)
|
|
||||||
#define PublishAlways 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef ARDUINO_ARCH_ESP32 // ESP32 boards
|
// set the default pins based on the architecture, these get overridden by Usermod menu settings
|
||||||
uint8_t SCL_PIN = 22;
|
#ifdef ARDUINO_ARCH_ESP32 // ESP32 boards
|
||||||
uint8_t SDA_PIN = 21;
|
#define HW_PIN_SCL 22
|
||||||
#else // ESP8266 boards
|
#define HW_PIN_SDA 21
|
||||||
uint8_t SCL_PIN = 5;
|
#else // ESP8266 boards
|
||||||
uint8_t SDA_PIN = 4;
|
#define HW_PIN_SCL 5
|
||||||
//uint8_t RST_PIN = 16; // Uncoment for Heltec WiFi-Kit-8
|
#define HW_PIN_SDA 4
|
||||||
#endif
|
//uint8_t RST_PIN = 16; // Uncoment for Heltec WiFi-Kit-8
|
||||||
|
#endif
|
||||||
|
int8_t ioPin[2] = {HW_PIN_SCL, HW_PIN_SDA}; // I2C pins: SCL, SDA...defaults to Arch hardware pins but overridden at setup()
|
||||||
|
bool initDone = false;
|
||||||
|
|
||||||
// BME280 sensor settings
|
// BME280 sensor settings
|
||||||
BME280I2C::Settings settings{
|
BME280I2C::Settings settings{
|
||||||
@ -75,6 +65,7 @@ private:
|
|||||||
float sensorHeatIndex;
|
float sensorHeatIndex;
|
||||||
float sensorDewPoint;
|
float sensorDewPoint;
|
||||||
float sensorPressure;
|
float sensorPressure;
|
||||||
|
String tempScale;
|
||||||
// Track previous sensor values
|
// Track previous sensor values
|
||||||
float lastTemperature;
|
float lastTemperature;
|
||||||
float lastHumidity;
|
float lastHumidity;
|
||||||
@ -82,43 +73,122 @@ private:
|
|||||||
float lastDewPoint;
|
float lastDewPoint;
|
||||||
float lastPressure;
|
float lastPressure;
|
||||||
|
|
||||||
|
// MQTT topic strings for publishing Home Assistant discovery topics
|
||||||
|
bool mqttInitialized = false;
|
||||||
|
String mqttTemperatureTopic = "";
|
||||||
|
String mqttHumidityTopic = "";
|
||||||
|
String mqttPressureTopic = "";
|
||||||
|
String mqttHeatIndexTopic = "";
|
||||||
|
String mqttDewPointTopic = "";
|
||||||
|
|
||||||
// Store packet IDs of MQTT publications
|
// Store packet IDs of MQTT publications
|
||||||
uint16_t mqttTemperaturePub = 0;
|
uint16_t mqttTemperaturePub = 0;
|
||||||
uint16_t mqttPressurePub = 0;
|
uint16_t mqttPressurePub = 0;
|
||||||
|
|
||||||
|
// Read the BME280/BMP280 Sensor (which one runs depends on whether Celsius or Farenheit being set in Usermod Menu)
|
||||||
void UpdateBME280Data(int SensorType)
|
void UpdateBME280Data(int SensorType)
|
||||||
{
|
{
|
||||||
float _temperature, _humidity, _pressure;
|
float _temperature, _humidity, _pressure;
|
||||||
#ifdef Celsius
|
|
||||||
|
if (UseCelsius) {
|
||||||
BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
|
BME280::TempUnit tempUnit(BME280::TempUnit_Celsius);
|
||||||
EnvironmentCalculations::TempUnit envTempUnit(EnvironmentCalculations::TempUnit_Celsius);
|
EnvironmentCalculations::TempUnit envTempUnit(EnvironmentCalculations::TempUnit_Celsius);
|
||||||
#else
|
BME280::PresUnit presUnit(BME280::PresUnit_hPa);
|
||||||
|
|
||||||
|
bme.read(_pressure, _temperature, _humidity, tempUnit, presUnit);
|
||||||
|
|
||||||
|
sensorTemperature = _temperature;
|
||||||
|
sensorHumidity = _humidity;
|
||||||
|
sensorPressure = _pressure;
|
||||||
|
tempScale = "°C";
|
||||||
|
if (sensorType == 1)
|
||||||
|
{
|
||||||
|
sensorHeatIndex = EnvironmentCalculations::HeatIndex(_temperature, _humidity, envTempUnit);
|
||||||
|
sensorDewPoint = EnvironmentCalculations::DewPoint(_temperature, _humidity, envTempUnit);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
BME280::TempUnit tempUnit(BME280::TempUnit_Fahrenheit);
|
BME280::TempUnit tempUnit(BME280::TempUnit_Fahrenheit);
|
||||||
EnvironmentCalculations::TempUnit envTempUnit(EnvironmentCalculations::TempUnit_Fahrenheit);
|
EnvironmentCalculations::TempUnit envTempUnit(EnvironmentCalculations::TempUnit_Fahrenheit);
|
||||||
#endif
|
BME280::PresUnit presUnit(BME280::PresUnit_hPa);
|
||||||
BME280::PresUnit presUnit(BME280::PresUnit_hPa);
|
|
||||||
|
|
||||||
bme.read(_pressure, _temperature, _humidity, tempUnit, presUnit);
|
bme.read(_pressure, _temperature, _humidity, tempUnit, presUnit);
|
||||||
|
|
||||||
sensorTemperature = _temperature;
|
sensorTemperature = _temperature;
|
||||||
sensorHumidity = _humidity;
|
sensorHumidity = _humidity;
|
||||||
sensorPressure = _pressure;
|
sensorPressure = _pressure;
|
||||||
if (sensorType == 1)
|
tempScale = "°F";
|
||||||
{
|
if (sensorType == 1)
|
||||||
sensorHeatIndex = EnvironmentCalculations::HeatIndex(_temperature, _humidity, envTempUnit);
|
{
|
||||||
sensorDewPoint = EnvironmentCalculations::DewPoint(_temperature, _humidity, envTempUnit);
|
sensorHeatIndex = EnvironmentCalculations::HeatIndex(_temperature, _humidity, envTempUnit);
|
||||||
|
sensorDewPoint = EnvironmentCalculations::DewPoint(_temperature, _humidity, envTempUnit);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Procedure to define all MQTT discovery Topics
|
||||||
|
void _mqttInitialize()
|
||||||
|
{
|
||||||
|
mqttTemperatureTopic = String(mqttDeviceTopic) + F("/temperature");
|
||||||
|
mqttPressureTopic = String(mqttDeviceTopic) + F("/pressure");
|
||||||
|
mqttHumidityTopic = String(mqttDeviceTopic) + F("/humidity");
|
||||||
|
mqttHeatIndexTopic = String(mqttDeviceTopic) + F("/heat_index");
|
||||||
|
mqttDewPointTopic = String(mqttDeviceTopic) + F("/dew_point");
|
||||||
|
|
||||||
|
if (HomeAssistantDiscovery) {
|
||||||
|
_createMqttSensor(F("Temperature"), mqttTemperatureTopic, F("temperature"), tempScale);
|
||||||
|
_createMqttSensor(F("Pressure"), mqttPressureTopic, F("pressure"), F("hPa"));
|
||||||
|
_createMqttSensor(F("Humidity"), mqttHumidityTopic, F("humidity"), F("%"));
|
||||||
|
_createMqttSensor(F("HeatIndex"), mqttHeatIndexTopic, F("temperature"), tempScale);
|
||||||
|
_createMqttSensor(F("DewPoint"), mqttDewPointTopic, F("temperature"), tempScale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
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");
|
||||||
|
device[F("model")] = F("FOSS");
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
Wire.begin(SDA_PIN, SCL_PIN);
|
bool HW_Pins_Used = (ioPin[0]==HW_PIN_SCL && ioPin[1]==HW_PIN_SDA); // note whether architecture-based hardware SCL/SDA pins used
|
||||||
|
PinOwner po = PinOwner::UM_BME280; // defaults to being pinowner for SCL/SDA pins
|
||||||
|
PinManagerPinType pins[2] = { { ioPin[0], true }, { ioPin[1], true } }; // allocate pins
|
||||||
|
if (HW_Pins_Used) po = PinOwner::HW_I2C; // allow multiple allocations of HW I2C bus pins
|
||||||
|
if (!pinManager.allocateMultiplePins(pins, 2, po)) { sensorType=0; return; }
|
||||||
|
|
||||||
|
Wire.begin(ioPin[1], ioPin[0]);
|
||||||
|
|
||||||
if (!bme.begin())
|
if (!bme.begin())
|
||||||
{
|
{
|
||||||
sensorType = 0;
|
sensorType = 0;
|
||||||
Serial.println("Could not find BME280I2C sensor!");
|
DEBUG_PRINTLN(F("Could not find BME280I2C sensor!"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -126,24 +196,25 @@ public:
|
|||||||
{
|
{
|
||||||
case BME280::ChipModel_BME280:
|
case BME280::ChipModel_BME280:
|
||||||
sensorType = 1;
|
sensorType = 1;
|
||||||
Serial.println("Found BME280 sensor! Success.");
|
DEBUG_PRINTLN(F("Found BME280 sensor! Success."));
|
||||||
break;
|
break;
|
||||||
case BME280::ChipModel_BMP280:
|
case BME280::ChipModel_BMP280:
|
||||||
sensorType = 2;
|
sensorType = 2;
|
||||||
Serial.println("Found BMP280 sensor! No Humidity available.");
|
DEBUG_PRINTLN(F("Found BMP280 sensor! No Humidity available."));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
sensorType = 0;
|
sensorType = 0;
|
||||||
Serial.println("Found UNKNOWN sensor! Error!");
|
DEBUG_PRINTLN(F("Found UNKNOWN sensor! Error!"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
initDone=true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop()
|
void loop()
|
||||||
{
|
{
|
||||||
// BME280 sensor MQTT publishing
|
// BME280 sensor MQTT publishing
|
||||||
// Check if sensor present and MQTT Connected, otherwise it will crash the MCU
|
// Check if sensor present and MQTT Connected, otherwise it will crash the MCU
|
||||||
if (sensorType != 0 && mqtt != nullptr)
|
if (sensorType != 0 && WLED_MQTT_CONNECTED)
|
||||||
{
|
{
|
||||||
// Timer to fetch new temperature, humidity and pressure data at intervals
|
// Timer to fetch new temperature, humidity and pressure data at intervals
|
||||||
timer = millis();
|
timer = millis();
|
||||||
@ -154,9 +225,15 @@ public:
|
|||||||
|
|
||||||
UpdateBME280Data(sensorType);
|
UpdateBME280Data(sensorType);
|
||||||
|
|
||||||
float temperature = roundf(sensorTemperature * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals);
|
float temperature = roundf(sensorTemperature * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals);
|
||||||
float humidity, heatIndex, dewPoint;
|
float humidity, heatIndex, dewPoint;
|
||||||
|
|
||||||
|
if (WLED_MQTT_CONNECTED && !mqttInitialized)
|
||||||
|
{
|
||||||
|
_mqttInitialize();
|
||||||
|
mqttInitialized = true;
|
||||||
|
}
|
||||||
|
|
||||||
// If temperature has changed since last measure, create string populated with device topic
|
// If temperature has changed since last measure, create string populated with device topic
|
||||||
// from the UI and values read from sensor, then publish to broker
|
// from the UI and values read from sensor, then publish to broker
|
||||||
if (temperature != lastTemperature || PublishAlways)
|
if (temperature != lastTemperature || PublishAlways)
|
||||||
@ -169,25 +246,25 @@ public:
|
|||||||
|
|
||||||
if (sensorType == 1) // Only if sensor is a BME280
|
if (sensorType == 1) // Only if sensor is a BME280
|
||||||
{
|
{
|
||||||
humidity = roundf(sensorHumidity * pow(10, HumidityDecimals)) / pow(10, HumidityDecimals);
|
humidity = roundf(sensorHumidity * powf(10, HumidityDecimals)) / powf(10, HumidityDecimals);
|
||||||
heatIndex = roundf(sensorHeatIndex * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals);
|
heatIndex = roundf(sensorHeatIndex * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals);
|
||||||
dewPoint = roundf(sensorDewPoint * pow(10, TemperatureDecimals)) / pow(10, TemperatureDecimals);
|
dewPoint = roundf(sensorDewPoint * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals);
|
||||||
|
|
||||||
if (humidity != lastHumidity || PublishAlways)
|
if (humidity != lastHumidity || PublishAlways)
|
||||||
{
|
{
|
||||||
String topic = String(mqttDeviceTopic) + "/humidity";
|
String topic = String(mqttDeviceTopic) + F("/humidity");
|
||||||
mqtt->publish(topic.c_str(), 0, false, String(humidity, HumidityDecimals).c_str());
|
mqtt->publish(topic.c_str(), 0, false, String(humidity, HumidityDecimals).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (heatIndex != lastHeatIndex || PublishAlways)
|
if (heatIndex != lastHeatIndex || PublishAlways)
|
||||||
{
|
{
|
||||||
String topic = String(mqttDeviceTopic) + "/heat_index";
|
String topic = String(mqttDeviceTopic) + F("/heat_index");
|
||||||
mqtt->publish(topic.c_str(), 0, false, String(heatIndex, TemperatureDecimals).c_str());
|
mqtt->publish(topic.c_str(), 0, false, String(heatIndex, TemperatureDecimals).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dewPoint != lastDewPoint || PublishAlways)
|
if (dewPoint != lastDewPoint || PublishAlways)
|
||||||
{
|
{
|
||||||
String topic = String(mqttDeviceTopic) + "/dew_point";
|
String topic = String(mqttDeviceTopic) + F("/dew_point");
|
||||||
mqtt->publish(topic.c_str(), 0, false, String(dewPoint, TemperatureDecimals).c_str());
|
mqtt->publish(topic.c_str(), 0, false, String(dewPoint, TemperatureDecimals).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,11 +278,11 @@ public:
|
|||||||
{
|
{
|
||||||
lastPressureMeasure = timer;
|
lastPressureMeasure = timer;
|
||||||
|
|
||||||
float pressure = roundf(sensorPressure * pow(10, PressureDecimals)) / pow(10, PressureDecimals);
|
float pressure = roundf(sensorPressure * powf(10, PressureDecimals)) / powf(10, PressureDecimals);
|
||||||
|
|
||||||
if (pressure != lastPressure || PublishAlways)
|
if (pressure != lastPressure || PublishAlways)
|
||||||
{
|
{
|
||||||
String topic = String(mqttDeviceTopic) + "/pressure";
|
String topic = String(mqttDeviceTopic) + F("/pressure");
|
||||||
mqttPressurePub = mqtt->publish(topic.c_str(), 0, true, String(pressure, PressureDecimals).c_str());
|
mqttPressurePub = mqtt->publish(topic.c_str(), 0, true, String(pressure, PressureDecimals).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,4 +290,173 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* API calls te enable data exchange between WLED modules
|
||||||
|
*/
|
||||||
|
inline float getTemperatureC() {
|
||||||
|
if (UseCelsius) {
|
||||||
|
return (float)roundf(sensorTemperature * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals);
|
||||||
|
} else {
|
||||||
|
return (float)roundf(sensorTemperature * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals) * 1.8f + 32;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
inline float getTemperatureF() {
|
||||||
|
if (UseCelsius) {
|
||||||
|
return ((float)roundf(sensorTemperature * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals) -32) * 0.56f;
|
||||||
|
} else {
|
||||||
|
return (float)roundf(sensorTemperature * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inline float getHumidity() {
|
||||||
|
return (float)roundf(sensorHumidity * powf(10, HumidityDecimals));
|
||||||
|
}
|
||||||
|
inline float getPressure() {
|
||||||
|
return (float)roundf(sensorPressure * powf(10, PressureDecimals));
|
||||||
|
}
|
||||||
|
inline float getDewPointC() {
|
||||||
|
if (UseCelsius) {
|
||||||
|
return (float)roundf(sensorDewPoint * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals);
|
||||||
|
} else {
|
||||||
|
return (float)roundf(sensorDewPoint * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals) * 1.8f + 32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inline float getDewPointF() {
|
||||||
|
if (UseCelsius) {
|
||||||
|
return ((float)roundf(sensorDewPoint * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals) -32) * 0.56f;
|
||||||
|
} else {
|
||||||
|
return (float)roundf(sensorDewPoint * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inline float getHeatIndexC() {
|
||||||
|
if (UseCelsius) {
|
||||||
|
return (float)roundf(sensorHeatIndex * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals);
|
||||||
|
} else {
|
||||||
|
return (float)roundf(sensorHeatIndex * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals) * 1.8f + 32;
|
||||||
|
}
|
||||||
|
}inline float getHeatIndexF() {
|
||||||
|
if (UseCelsius) {
|
||||||
|
return ((float)roundf(sensorHeatIndex * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals) -32) * 0.56f;
|
||||||
|
} else {
|
||||||
|
return (float)roundf(sensorHeatIndex * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Publish Sensor Information to Info Page
|
||||||
|
void addToJsonInfo(JsonObject &root)
|
||||||
|
{
|
||||||
|
JsonObject user = root[F("u")];
|
||||||
|
if (user.isNull()) user = root.createNestedObject(F("u"));
|
||||||
|
|
||||||
|
if (sensorType==0) //No Sensor
|
||||||
|
{
|
||||||
|
// if we sensor not detected, let the user know
|
||||||
|
JsonArray temperature_json = user.createNestedArray(F("BME/BMP280 Sensor"));
|
||||||
|
temperature_json.add(F("Not Found"));
|
||||||
|
}
|
||||||
|
else if (sensorType==2) //BMP280
|
||||||
|
{
|
||||||
|
|
||||||
|
JsonArray temperature_json = user.createNestedArray(F("Temperature"));
|
||||||
|
JsonArray pressure_json = user.createNestedArray(F("Pressure"));
|
||||||
|
temperature_json.add(roundf(sensorTemperature * powf(10, TemperatureDecimals)));
|
||||||
|
temperature_json.add(tempScale);
|
||||||
|
pressure_json.add(roundf(sensorPressure * powf(10, PressureDecimals)));
|
||||||
|
pressure_json.add(F("hPa"));
|
||||||
|
}
|
||||||
|
else if (sensorType==1) //BME280
|
||||||
|
{
|
||||||
|
JsonArray temperature_json = user.createNestedArray(F("Temperature"));
|
||||||
|
JsonArray humidity_json = user.createNestedArray(F("Humidity"));
|
||||||
|
JsonArray pressure_json = user.createNestedArray(F("Pressure"));
|
||||||
|
JsonArray heatindex_json = user.createNestedArray(F("Heat Index"));
|
||||||
|
JsonArray dewpoint_json = user.createNestedArray(F("Dew Point"));
|
||||||
|
temperature_json.add(roundf(sensorTemperature * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals));
|
||||||
|
temperature_json.add(tempScale);
|
||||||
|
humidity_json.add(roundf(sensorHumidity * powf(10, HumidityDecimals)));
|
||||||
|
humidity_json.add(F("%"));
|
||||||
|
pressure_json.add(roundf(sensorPressure * powf(10, PressureDecimals)));
|
||||||
|
pressure_json.add(F("hPa"));
|
||||||
|
heatindex_json.add(roundf(sensorHeatIndex * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals));
|
||||||
|
heatindex_json.add(tempScale);
|
||||||
|
dewpoint_json.add(roundf(sensorDewPoint * powf(10, TemperatureDecimals)) / powf(10, TemperatureDecimals));
|
||||||
|
dewpoint_json.add(tempScale);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save Usermod Config Settings
|
||||||
|
void addToConfig(JsonObject& root)
|
||||||
|
{
|
||||||
|
JsonObject top = root.createNestedObject(F("BME280/BMP280"));
|
||||||
|
top[F("TemperatureDecimals")] = TemperatureDecimals;
|
||||||
|
top[F("HumidityDecimals")] = HumidityDecimals;
|
||||||
|
top[F("PressureDecimals")] = PressureDecimals;
|
||||||
|
top[F("TemperatureInterval")] = TemperatureInterval;
|
||||||
|
top[F("PressureInterval")] = PressureInterval;
|
||||||
|
top[F("PublishAlways")] = PublishAlways;
|
||||||
|
top[F("UseCelsius")] = UseCelsius;
|
||||||
|
top[F("HomeAssistantDiscovery")] = HomeAssistantDiscovery;
|
||||||
|
JsonArray io_pin = top.createNestedArray(F("pin"));
|
||||||
|
for (byte i=0; i<2; i++) io_pin.add(ioPin[i]);
|
||||||
|
top[F("help4Pins")] = F("SCL,SDA"); // help for Settings page
|
||||||
|
DEBUG_PRINTLN(F("BME280 config saved."));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read Usermod Config Settings
|
||||||
|
bool readFromConfig(JsonObject& root)
|
||||||
|
{
|
||||||
|
// default settings values could be set here (or below using the 3-argument getJsonValue()) instead of in the class definition or constructor
|
||||||
|
// setting them inside readFromConfig() is slightly more robust, handling the rare but plausible use case of single value being missing after boot (e.g. if the cfg.json was manually edited and a value was removed)
|
||||||
|
|
||||||
|
|
||||||
|
int8_t newPin[2]; for (byte i=0; i<2; i++) newPin[i] = ioPin[i]; // prepare to note changed pins
|
||||||
|
|
||||||
|
JsonObject top = root[F("BME280/BMP280")];
|
||||||
|
if (top.isNull()) {
|
||||||
|
DEBUG_PRINT(F("BME280/BMP280"));
|
||||||
|
DEBUG_PRINTLN(F(": No config found. (Using defaults.)"));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
bool configComplete = !top.isNull();
|
||||||
|
|
||||||
|
// A 3-argument getJsonValue() assigns the 3rd argument as a default value if the Json value is missing
|
||||||
|
configComplete &= getJsonValue(top[F("TemperatureDecimals")], TemperatureDecimals, 1);
|
||||||
|
configComplete &= getJsonValue(top[F("HumidityDecimals")], HumidityDecimals, 0);
|
||||||
|
configComplete &= getJsonValue(top[F("PressureDecimals")], PressureDecimals, 0);
|
||||||
|
configComplete &= getJsonValue(top[F("TemperatureInterval")], TemperatureInterval, 30);
|
||||||
|
configComplete &= getJsonValue(top[F("PressureInterval")], PressureInterval, 30);
|
||||||
|
configComplete &= getJsonValue(top[F("PublishAlways")], PublishAlways, false);
|
||||||
|
configComplete &= getJsonValue(top[F("UseCelsius")], UseCelsius, true);
|
||||||
|
configComplete &= getJsonValue(top[F("HomeAssistantDiscovery")], HomeAssistantDiscovery, false);
|
||||||
|
for (byte i=0; i<2; i++) configComplete &= getJsonValue(top[F("pin")][i], newPin[i], ioPin[i]);
|
||||||
|
|
||||||
|
DEBUG_PRINT(FPSTR(F("BME280/BMP280")));
|
||||||
|
if (!initDone) {
|
||||||
|
// first run: reading from cfg.json
|
||||||
|
for (byte i=0; i<2; i++) ioPin[i] = newPin[i];
|
||||||
|
DEBUG_PRINTLN(F(" config loaded."));
|
||||||
|
} else {
|
||||||
|
DEBUG_PRINTLN(F(" config (re)loaded."));
|
||||||
|
// changing parameters from settings page
|
||||||
|
bool pinsChanged = false;
|
||||||
|
for (byte i=0; i<2; i++) if (ioPin[i] != newPin[i]) { pinsChanged = true; break; } // check if any pins changed
|
||||||
|
if (pinsChanged) { //if pins changed, deallocate old pins and allocate new ones
|
||||||
|
PinOwner po = PinOwner::UM_BME280;
|
||||||
|
if (ioPin[0]==HW_PIN_SCL && ioPin[1]==HW_PIN_SDA) po = PinOwner::HW_I2C; // allow multiple allocations of HW I2C bus pins
|
||||||
|
pinManager.deallocateMultiplePins((const uint8_t *)ioPin, 2, po); // deallocate pins
|
||||||
|
for (byte i=0; i<2; i++) ioPin[i] = newPin[i];
|
||||||
|
setup();
|
||||||
|
}
|
||||||
|
// use "return !top["newestParameter"].isNull();" when updating Usermod with new features
|
||||||
|
return !top[F("pin")].isNull();
|
||||||
|
}
|
||||||
|
|
||||||
|
return configComplete;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t getId() {
|
||||||
|
return USERMOD_ID_BME280;
|
||||||
|
}
|
||||||
};
|
};
|
@ -3241,7 +3241,7 @@ uint16_t mode_starburst(void) {
|
|||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
#undef STARBURST_MAX_FRAG
|
#undef STARBURST_MAX_FRAG
|
||||||
static const char *_data_FX_MODE_STARBURST PROGMEM = "Fireworks Starburst;;;mp12=0"; //pixels
|
static const char *_data_FX_MODE_STARBURST PROGMEM = "Fireworks Starburst@Chance,Fragments;,!,;!=11;mp12=0";
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -3377,7 +3377,7 @@ uint16_t mode_exploding_fireworks(void)
|
|||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
#undef MAX_SPARKS
|
#undef MAX_SPARKS
|
||||||
static const char *_data_FX_MODE_EXPLODING_FIREWORKS PROGMEM = "Fireworks 1D@Gravity,Firing side;!,!,;!";
|
static const char *_data_FX_MODE_EXPLODING_FIREWORKS PROGMEM = "Fireworks 1D@Gravity,Firing side=128;!,!,;!=11";
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -5917,7 +5917,7 @@ uint16_t mode_2Dscrollingtext(void) {
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
}
|
}
|
||||||
static const char *_data_FX_MODE_2DSCROLLTEXT PROGMEM = "2D Scrolling Text@!,Y Offset,Trail=0,Font size;!,!;!";
|
static const char *_data_FX_MODE_2DSCROLLTEXT PROGMEM = "2D Scrolling Text@!,Y Offset=128,Trail=0,Font size;!,!;!;rev=0,mi=0,rY=0,mY=0";
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////
|
////////////////////////////
|
||||||
@ -6257,7 +6257,7 @@ uint16_t mode_ripplepeak(void) { // * Ripple peak. By Andrew Tuli
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
} // mode_ripplepeak()
|
} // mode_ripplepeak()
|
||||||
static const char *_data_FX_MODE_RIPPLEPEAK PROGMEM = " ♪ Ripple Peak@Fade rate,Max # of ripples,,Select bin,Volume (minimum)=0;!,!;!;mp12=0;ssim=1"; // Pixel, Beatsin
|
static const char *_data_FX_MODE_RIPPLEPEAK PROGMEM = " ♪ Ripple Peak@Fade rate,Max # of ripples,,Select bin,Volume (minimum)=0;!,!;!;mp12=0,ssim=1"; // Pixel, Beatsin
|
||||||
|
|
||||||
|
|
||||||
#ifndef WLED_DISABLE_2D
|
#ifndef WLED_DISABLE_2D
|
||||||
@ -6426,7 +6426,7 @@ uint16_t mode_gravcenter(void) { // Gravcenter. By Andrew Tuline.
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
} // mode_gravcenter()
|
} // mode_gravcenter()
|
||||||
static const char *_data_FX_MODE_GRAVCENTER PROGMEM = " ♪ Gravcenter@Rate of fall,Sensitivity=128;,!;!;mp12=2;ssim=1"; // Circle, Beatsin
|
static const char *_data_FX_MODE_GRAVCENTER PROGMEM = " ♪ Gravcenter@Rate of fall,Sensitivity=128;,!;!;mp12=2,ssim=1"; // Circle, Beatsin
|
||||||
|
|
||||||
|
|
||||||
///////////////////////
|
///////////////////////
|
||||||
@ -6480,7 +6480,7 @@ uint16_t mode_gravcentric(void) { // Gravcentric. By Andrew
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
} // mode_gravcentric()
|
} // mode_gravcentric()
|
||||||
static const char *_data_FX_MODE_GRAVCENTRIC PROGMEM = " ♪ Gravcentric@Rate of fall,Sensitivity=128;!;!;mp12=2;ssim=1"; // Circle, Beatsin
|
static const char *_data_FX_MODE_GRAVCENTRIC PROGMEM = " ♪ Gravcentric@Rate of fall,Sensitivity=128;!;!;mp12=2,ssim=1"; // Circle, Beatsin
|
||||||
|
|
||||||
|
|
||||||
///////////////////////
|
///////////////////////
|
||||||
@ -6530,7 +6530,7 @@ uint16_t mode_gravimeter(void) { // Gravmeter. By Andrew Tuline.
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
} // mode_gravimeter()
|
} // mode_gravimeter()
|
||||||
static const char *_data_FX_MODE_GRAVIMETER PROGMEM = " ♪ Gravimeter@Rate of fall,Sensitivity=128;,!;!;mp12=2;ssim=1"; // Circle, Beatsin
|
static const char *_data_FX_MODE_GRAVIMETER PROGMEM = " ♪ Gravimeter@Rate of fall,Sensitivity=128;,!;!;mp12=2,ssim=1"; // Circle, Beatsin
|
||||||
#else
|
#else
|
||||||
// This an abuse of the gravimeter effect for AGC debugging
|
// This an abuse of the gravimeter effect for AGC debugging
|
||||||
// instead of sound volume, it uses the AGC gain multiplier as input
|
// instead of sound volume, it uses the AGC gain multiplier as input
|
||||||
@ -6596,7 +6596,7 @@ uint16_t mode_gravimeter(void) { // Gravmeter. By Andrew Tuline.
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
} // mode_gravimeter()
|
} // mode_gravimeter()
|
||||||
static const char *_data_FX_MODE_GRAVIMETER PROGMEM = " ♪ Gravimeter@Rate of fall,Sensitivity=128,Input level=128;,!;!;mp12=2;ssim=1"; // Circle, Beatsin
|
static const char *_data_FX_MODE_GRAVIMETER PROGMEM = " ♪ Gravimeter@Rate of fall,Sensitivity=128,Input level=128;,!;!;mp12=2,ssim=1"; // Circle, Beatsin
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@ -6620,7 +6620,7 @@ uint16_t mode_juggles(void) { // Juggles. By Andrew Tuline.
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
} // mode_juggles()
|
} // mode_juggles()
|
||||||
static const char *_data_FX_MODE_JUGGLES PROGMEM = " ♪ Juggles@!,# of balls;,!;!;mp12=0;ssim=1"; // Pixels, Beatsin
|
static const char *_data_FX_MODE_JUGGLES PROGMEM = " ♪ Juggles@!,# of balls;,!;!;mp12=0,ssim=1"; // Pixels, Beatsin
|
||||||
|
|
||||||
|
|
||||||
//////////////////////
|
//////////////////////
|
||||||
@ -6650,7 +6650,7 @@ uint16_t mode_matripix(void) { // Matripix. By Andrew Tuline.
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
} // mode_matripix()
|
} // mode_matripix()
|
||||||
static const char *_data_FX_MODE_MATRIPIX PROGMEM = " ♪ Matripix@!,Brightness=64;,!;!;mp12=2;ssim=2;rev=1"; // Circle, WeWillRockYou, reverseX
|
static const char *_data_FX_MODE_MATRIPIX PROGMEM = " ♪ Matripix@!,Brightness=64;!,!;!;mp12=2,ssim=2,rev=1,mi=1,rY=1,mY=1"; // Circle, WeWillRockYou, reverseX
|
||||||
|
|
||||||
|
|
||||||
//////////////////////
|
//////////////////////
|
||||||
@ -6688,7 +6688,7 @@ uint16_t mode_midnoise(void) { // Midnoise. By Andrew Tuline.
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
} // mode_midnoise()
|
} // mode_midnoise()
|
||||||
static const char *_data_FX_MODE_MIDNOISE PROGMEM = " ♪ Midnoise@Fade rate,Maximum length=128;,!;!;mp12=2;ssim=1"; // Circle, Beatsin
|
static const char *_data_FX_MODE_MIDNOISE PROGMEM = " ♪ Midnoise@Fade rate,Maximum length=128;,!;!;mp12=2,ssim=1"; // Circle, Beatsin
|
||||||
|
|
||||||
|
|
||||||
//////////////////////
|
//////////////////////
|
||||||
@ -6722,7 +6722,7 @@ uint16_t mode_noisefire(void) { // Noisefire. By Andrew Tuline.
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
} // mode_noisefire()
|
} // mode_noisefire()
|
||||||
static const char *_data_FX_MODE_NOISEFIRE PROGMEM = " ♪ Noisefire@!,!;;;mp12=2;ssim=1"; // Circle, Beatsin
|
static const char *_data_FX_MODE_NOISEFIRE PROGMEM = " ♪ Noisefire@!,!;;;mp12=2,ssim=1"; // Circle, Beatsin
|
||||||
|
|
||||||
|
|
||||||
///////////////////////
|
///////////////////////
|
||||||
@ -6760,7 +6760,7 @@ uint16_t mode_noisemeter(void) { // Noisemeter. By Andrew Tuline.
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
} // mode_noisemeter()
|
} // mode_noisemeter()
|
||||||
static const char *_data_FX_MODE_NOISEMETER PROGMEM = " ♪ Noisemeter@Fade rate,Width=128;!,!;!;mp12=2;ssim=1"; // Circle, Beatsin
|
static const char *_data_FX_MODE_NOISEMETER PROGMEM = " ♪ Noisemeter@Fade rate,Width=128;!,!;!;mp12=2,ssim=1"; // Circle, Beatsin
|
||||||
|
|
||||||
|
|
||||||
//////////////////////
|
//////////////////////
|
||||||
@ -6793,7 +6793,7 @@ uint16_t mode_pixelwave(void) { // Pixelwave. By Andrew Tuline.
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
} // mode_pixelwave()
|
} // mode_pixelwave()
|
||||||
static const char *_data_FX_MODE_PIXELWAVE PROGMEM = " ♪ Pixelwave@!,Sensitivity=64;!,!;!;mp12=2;ssim=1"; // Circle, Beatsin
|
static const char *_data_FX_MODE_PIXELWAVE PROGMEM = " ♪ Pixelwave@!,Sensitivity=64;!,!;!;mp12=2,ssim=1"; // Circle, Beatsin
|
||||||
|
|
||||||
|
|
||||||
//////////////////////
|
//////////////////////
|
||||||
@ -6837,7 +6837,7 @@ uint16_t mode_plasmoid(void) { // Plasmoid. By Andrew Tuline.
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
} // mode_plasmoid()
|
} // mode_plasmoid()
|
||||||
static const char *_data_FX_MODE_PLASMOID PROGMEM = " ♪ Plasmoid@Phase=128,# of pixels=128;,!;!;mp12=0;ssim=1"; // Pixels, Beatsin
|
static const char *_data_FX_MODE_PLASMOID PROGMEM = " ♪ Plasmoid@Phase=128,# of pixels=128;,!;!;mp12=0,ssim=1"; // Pixels, Beatsin
|
||||||
|
|
||||||
|
|
||||||
///////////////////////
|
///////////////////////
|
||||||
@ -6881,7 +6881,7 @@ uint16_t mode_puddlepeak(void) { // Puddlepeak. By Andrew Tuline.
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
} // mode_puddlepeak()
|
} // mode_puddlepeak()
|
||||||
static const char *_data_FX_MODE_PUDDLEPEAK PROGMEM = " ♪ Puddlepeak@Fade rate,Puddle size,,Select bin,Volume (minimum)=0;!,!;!;mp12=0;ssim=1"; // Pixels, Beatsin
|
static const char *_data_FX_MODE_PUDDLEPEAK PROGMEM = " ♪ Puddlepeak@Fade rate,Puddle size,,Select bin,Volume (minimum)=0;!,!;!;mp12=0,ssim=1"; // Pixels, Beatsin
|
||||||
|
|
||||||
|
|
||||||
//////////////////////
|
//////////////////////
|
||||||
@ -6916,7 +6916,7 @@ uint16_t mode_puddles(void) { // Puddles. By Andrew Tuline.
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
} // mode_puddles()
|
} // mode_puddles()
|
||||||
static const char *_data_FX_MODE_PUDDLES PROGMEM = " ♪ Puddles@Fade rate,Puddle size;!,!;!;mp12=0;ssim=1"; // Pixels, Beatsin
|
static const char *_data_FX_MODE_PUDDLES PROGMEM = " ♪ Puddles@Fade rate,Puddle size;!,!;!;mp12=0,ssim=1"; // Pixels, Beatsin
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
@ -6946,7 +6946,7 @@ uint16_t mode_pixels(void) { // Pixels. By Andrew Tuline.
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
} // mode_pixels()
|
} // mode_pixels()
|
||||||
static const char *_data_FX_MODE_PIXELS PROGMEM = " ♪ Pixels@Fade rate,# of pixels;,!;!;mp12=0;ssim=1"; // Pixels, Beatsin
|
static const char *_data_FX_MODE_PIXELS PROGMEM = " ♪ Pixels@Fade rate,# of pixels;,!;!;mp12=0,ssim=1"; // Pixels, Beatsin
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////
|
///////////////////////////////
|
||||||
@ -7028,9 +7028,9 @@ uint16_t mode_binmap(void) {
|
|||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
} // mode_binmap()
|
} // mode_binmap()
|
||||||
#ifdef SR_DEBUG
|
#ifdef SR_DEBUG
|
||||||
static const char *_data_FX_MODE_BINMAP PROGMEM = " ♫ Binmap@,,Input level=128,,Max vol;!,!;!;mp12=0;ssim=1;rY=true"; // Pixels, Beatsin, ReverseY
|
static const char *_data_FX_MODE_BINMAP PROGMEM = " ♫ Binmap@,,Input level=128,,Max vol;!,!;!;mp12=0,ssim=1,rY=1"; // Pixels, Beatsin, ReverseY
|
||||||
#else
|
#else
|
||||||
static const char *_data_FX_MODE_BINMAP PROGMEM = " ♫ Binmap@,,Input level=128;!,!;!;mp12=0;ssim=1;rY=true"; // Pixels, Beatsin, ReverseY
|
static const char *_data_FX_MODE_BINMAP PROGMEM = " ♫ Binmap@,,Input level=128;!,!;!;mp12=0,ssim=1,rY=1"; // Pixels, Beatsin, ReverseY
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//////////////////////
|
//////////////////////
|
||||||
@ -7060,7 +7060,7 @@ uint16_t mode_blurz(void) { // Blurz. By Andrew Tuline.
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
} // mode_blurz()
|
} // mode_blurz()
|
||||||
static const char *_data_FX_MODE_BLURZ PROGMEM = " ♫ Blurz@Fade rate,Blur amount;!,Color mix;!;mp12=0;ssim=1"; // Pixels, Beatsin
|
static const char *_data_FX_MODE_BLURZ PROGMEM = " ♫ Blurz@Fade rate,Blur amount;!,Color mix;!;mp12=0,ssim=1"; // Pixels, Beatsin
|
||||||
|
|
||||||
|
|
||||||
/////////////////////////
|
/////////////////////////
|
||||||
@ -7097,7 +7097,7 @@ uint16_t mode_DJLight(void) { // Written by ??? Adapted by Wil
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
} // mode_DJLight()
|
} // mode_DJLight()
|
||||||
static const char *_data_FX_MODE_DJLIGHT PROGMEM = " ♫ DJ Light@Speed;;;mp12=2;ssim=1"; // Circle, Beatsin
|
static const char *_data_FX_MODE_DJLIGHT PROGMEM = " ♫ DJ Light@Speed;;;mp12=2,ssim=1"; // Circle, Beatsin
|
||||||
|
|
||||||
|
|
||||||
////////////////////
|
////////////////////
|
||||||
@ -7134,7 +7134,7 @@ uint16_t mode_freqmap(void) { // Map FFT_MajorPeak to SEGLEN.
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
} // mode_freqmap()
|
} // mode_freqmap()
|
||||||
static const char *_data_FX_MODE_FREQMAP PROGMEM = " ♫ Freqmap@Fade rate,Starting color;,!;!;mp12=2;ssim=1"; // Circle, Beatsin
|
static const char *_data_FX_MODE_FREQMAP PROGMEM = " ♫ Freqmap@Fade rate,Starting color;,!;!;mp12=2,ssim=1"; // Circle, Beatsin
|
||||||
|
|
||||||
|
|
||||||
///////////////////////
|
///////////////////////
|
||||||
@ -7184,7 +7184,7 @@ uint16_t mode_freqmatrix(void) { // Freqmatrix. By Andreas Plesch
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
} // mode_freqmatrix()
|
} // mode_freqmatrix()
|
||||||
static const char *_data_FX_MODE_FREQMATRIX PROGMEM = " ♫ Freqmatrix@Time delay,Sound effect,Low bin,High bin,Sensivity;;;mp12=0;ssim=1"; // Pixels, Beatsin
|
static const char *_data_FX_MODE_FREQMATRIX PROGMEM = " ♫ Freqmatrix@Time delay,Sound effect,Low bin,High bin,Sensivity;;;mp12=0,ssim=1"; // Pixels, Beatsin
|
||||||
|
|
||||||
|
|
||||||
//////////////////////
|
//////////////////////
|
||||||
@ -7220,7 +7220,7 @@ uint16_t mode_freqpixels(void) { // Freqpixel. By Andrew Tuline.
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
} // mode_freqpixels()
|
} // mode_freqpixels()
|
||||||
static const char *_data_FX_MODE_FREQPIXELS PROGMEM = " ♫ Freqpixels@Fade rate,Starting colour and # of pixels;;;mp12=0;ssim=1"; // Pixels, Beatsin
|
static const char *_data_FX_MODE_FREQPIXELS PROGMEM = " ♫ Freqpixels@Fade rate,Starting colour and # of pixels;;;mp12=0,ssim=1"; // Pixels, Beatsin
|
||||||
|
|
||||||
|
|
||||||
//////////////////////
|
//////////////////////
|
||||||
@ -7291,7 +7291,7 @@ uint16_t mode_freqwave(void) { // Freqwave. By Andreas Pleschun
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
} // mode_freqwave()
|
} // mode_freqwave()
|
||||||
static const char *_data_FX_MODE_FREQWAVE PROGMEM = " ♫ Freqwave@Time delay,Sound effect,Low bin,High bin,Pre-amp;;;mp12=2;ssim=1"; // Circle, Beatsin
|
static const char *_data_FX_MODE_FREQWAVE PROGMEM = " ♫ Freqwave@Time delay,Sound effect,Low bin,High bin,Pre-amp;;;mp12=2,ssim=1"; // Circle, Beatsin
|
||||||
|
|
||||||
|
|
||||||
///////////////////////
|
///////////////////////
|
||||||
@ -7344,7 +7344,7 @@ uint16_t mode_gravfreq(void) { // Gravfreq. By Andrew Tuline.
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
} // mode_gravfreq()
|
} // mode_gravfreq()
|
||||||
static const char *_data_FX_MODE_GRAVFREQ PROGMEM = " ♫ Gravfreq@Rate of fall,Sensivity=128;,!;!;mp12=2;ssim=1"; // Circle, Beatsin
|
static const char *_data_FX_MODE_GRAVFREQ PROGMEM = " ♫ Gravfreq@Rate of fall,Sensivity=128;,!;!;mp12=2,ssim=1"; // Circle, Beatsin
|
||||||
|
|
||||||
|
|
||||||
//////////////////////
|
//////////////////////
|
||||||
@ -7370,7 +7370,7 @@ uint16_t mode_noisemove(void) { // Noisemove. By: Andrew Tuli
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
} // mode_noisemove()
|
} // mode_noisemove()
|
||||||
static const char *_data_FX_MODE_NOISEMOVE PROGMEM = " ♫ Noisemove@Speed of perlin movement,Fade rate;,!;!;mp12=0;ssim=1"; // Pixels, Beatsin
|
static const char *_data_FX_MODE_NOISEMOVE PROGMEM = " ♫ Noisemove@Speed of perlin movement,Fade rate;,!;!;mp12=0,ssim=1"; // Pixels, Beatsin
|
||||||
|
|
||||||
|
|
||||||
//////////////////////
|
//////////////////////
|
||||||
@ -7414,7 +7414,7 @@ uint16_t mode_rocktaves(void) { // Rocktaves. Same note from eac
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
} // mode_rocktaves()
|
} // mode_rocktaves()
|
||||||
static const char *_data_FX_MODE_ROCKTAVES PROGMEM = " ♫ Rocktaves@;,!;!;mp12=0;ssim=1"; // Pixels, Beatsin
|
static const char *_data_FX_MODE_ROCKTAVES PROGMEM = " ♫ Rocktaves@;,!;!;mp12=0,ssim=1"; // Pixels, Beatsin
|
||||||
|
|
||||||
|
|
||||||
///////////////////////
|
///////////////////////
|
||||||
@ -7467,7 +7467,7 @@ uint16_t mode_waterfall(void) { // Waterfall. By: Andrew Tulin
|
|||||||
|
|
||||||
return FRAMETIME;
|
return FRAMETIME;
|
||||||
} // mode_waterfall()
|
} // mode_waterfall()
|
||||||
static const char *_data_FX_MODE_WATERFALL PROGMEM = " ♫ Waterfall@!,Adjust color,,Select bin, Volume (minimum)=0;!,!;!;mp12=2;ssim=1"; // Circles, Beatsin
|
static const char *_data_FX_MODE_WATERFALL PROGMEM = " ♫ Waterfall@!,Adjust color,,Select bin, Volume (minimum)=0;!,!;!;mp12=2,ssim=1"; // Circles, Beatsin
|
||||||
|
|
||||||
|
|
||||||
#ifndef WLED_DISABLE_2D
|
#ifndef WLED_DISABLE_2D
|
||||||
|
@ -4535,10 +4535,10 @@ static const unsigned char console_font_5x8[] PROGMEM = {
|
|||||||
0x00, /* 00000 */
|
0x00, /* 00000 */
|
||||||
0x00, /* 00000 */
|
0x00, /* 00000 */
|
||||||
0x90, /* 10010 */
|
0x90, /* 10010 */
|
||||||
0x90, /* 10010 */
|
|
||||||
0xF0, /* 11110 */
|
0xF0, /* 11110 */
|
||||||
0x90, /* 10010 */
|
0x90, /* 10010 */
|
||||||
0x90, /* 10010 */
|
0x90, /* 10010 */
|
||||||
|
0x90, /* 10010 */
|
||||||
0x00, /* 00000 */
|
0x00, /* 00000 */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -405,7 +405,7 @@ uint32_t Segment::getPixelColor(uint16_t i)
|
|||||||
{
|
{
|
||||||
#ifndef WLED_DISABLE_2D
|
#ifndef WLED_DISABLE_2D
|
||||||
if (height() > 1) { // if this does not work use strip.isMatrix
|
if (height() > 1) { // if this does not work use strip.isMatrix
|
||||||
uint16_t vH = virtualHeight(); // segment height in logical pixels
|
//uint16_t vH = virtualHeight(); // segment height in logical pixels
|
||||||
uint16_t vW = virtualWidth();
|
uint16_t vW = virtualWidth();
|
||||||
switch (map1D2D) {
|
switch (map1D2D) {
|
||||||
case M12_Pixels:
|
case M12_Pixels:
|
||||||
|
@ -78,7 +78,8 @@
|
|||||||
#define USERMOD_ID_WORDCLOCK 27 //Usermod "usermod_v2_word_clock.h"
|
#define USERMOD_ID_WORDCLOCK 27 //Usermod "usermod_v2_word_clock.h"
|
||||||
#define USERMOD_ID_MY9291 28 //Usermod "usermod_MY9291.h"
|
#define USERMOD_ID_MY9291 28 //Usermod "usermod_MY9291.h"
|
||||||
#define USERMOD_ID_SI7021_MQTT_HA 29 //Usermod "usermod_si7021_mqtt_ha.h"
|
#define USERMOD_ID_SI7021_MQTT_HA 29 //Usermod "usermod_si7021_mqtt_ha.h"
|
||||||
#define USERMOD_ID_AUDIOREACTIVE 30 //Usermod "audioreactive.h"
|
#define USERMOD_ID_BME280 30 //Usermod "usermod_bme280.h
|
||||||
|
#define USERMOD_ID_AUDIOREACTIVE 31 //Usermod "audioreactive.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
|
||||||
|
@ -377,7 +377,7 @@ button {
|
|||||||
|
|
||||||
#sliders {
|
#sliders {
|
||||||
width: 300px;
|
width: 300px;
|
||||||
margin: 0 auto;
|
margin: 32px auto 0;
|
||||||
position: sticky;
|
position: sticky;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
}
|
}
|
||||||
@ -835,17 +835,19 @@ input[type=range]::-moz-range-thumb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
select {
|
select {
|
||||||
padding: 4px;
|
padding: 4px 0 4px 8px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 19px;
|
font-size: 19px;
|
||||||
background-color: var(--c-3);
|
background-color: var(--c-3);
|
||||||
color: var(--c-d);
|
color: var(--c-d);
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
border: 1px solid var(--c-2);
|
border: 1px solid var(--c-2);
|
||||||
border-radius: 5px;
|
border-radius: 20px;
|
||||||
transition-duration: 0.5s;
|
transition-duration: 0.5s;
|
||||||
-webkit-backface-visibility: hidden;
|
-webkit-backface-visibility: hidden;
|
||||||
-webkit-transform:translate3d(0,0,0);
|
-webkit-transform:translate3d(0,0,0);
|
||||||
|
-webkit-appearance: none;
|
||||||
|
-moz-appearance: none;
|
||||||
backface-visibility: hidden;
|
backface-visibility: hidden;
|
||||||
transform:translate3d(0,0,0);
|
transform:translate3d(0,0,0);
|
||||||
}
|
}
|
||||||
@ -855,16 +857,26 @@ select {
|
|||||||
.cl {
|
.cl {
|
||||||
background-color: #000;
|
background-color: #000;
|
||||||
}
|
}
|
||||||
.sel-p {
|
select.sel-p, select.sel-pl, select.sel-ple {
|
||||||
margin: 5px 0 10px;
|
margin: 5px 0;
|
||||||
width: 5em;
|
|
||||||
}
|
|
||||||
.sel-pl {
|
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-position: 141px 16px;
|
height: 40px;
|
||||||
}
|
}
|
||||||
.sel-ple {
|
div.sel-p {
|
||||||
width: 100%;
|
position: relative;
|
||||||
|
}
|
||||||
|
div.sel-p:after {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
right: 10px;
|
||||||
|
top: 22px;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
border-left: 8px solid transparent;
|
||||||
|
border-right: 8px solid transparent;
|
||||||
|
border-top: 8px solid var(--c-f);
|
||||||
|
}
|
||||||
|
select.sel-ple {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
option {
|
option {
|
||||||
@ -1183,8 +1195,10 @@ TD .checkmark, TD .radiomark {
|
|||||||
|
|
||||||
.lbl-s {
|
.lbl-s {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin: 10px 4px 0 0;
|
/* margin: 10px 4px 0 0; */
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
|
width: 48%;
|
||||||
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* list wrapper */
|
/* list wrapper */
|
||||||
|
@ -5,10 +5,10 @@ var isOn = false, nlA = false, isLv = false, isInfo = false, isNodes = false, sy
|
|||||||
var hasWhite = false, hasRGB = false, hasCCT = false;
|
var hasWhite = false, hasRGB = false, hasCCT = false;
|
||||||
var nlDur = 60, nlTar = 0;
|
var nlDur = 60, nlTar = 0;
|
||||||
var nlMode = false;
|
var nlMode = false;
|
||||||
var selectedFx = 0, prevFx = -1;
|
var selectedFx = 0;
|
||||||
var selectedPal = 0;
|
var selectedPal = 0;
|
||||||
var csel = 0; // selected color slot (0-2)
|
var csel = 0; // selected color slot (0-2)
|
||||||
var currentPreset = -1, prevPS = -1;
|
var currentPreset = -1;
|
||||||
var lastUpdate = 0;
|
var lastUpdate = 0;
|
||||||
var segCount = 0, ledCount = 0, lowestUnused = 0, maxSeg = 0, lSeg = 0;
|
var segCount = 0, ledCount = 0, lowestUnused = 0, maxSeg = 0, lSeg = 0;
|
||||||
var pcMode = false, pcModeA = false, lastw = 0, wW;
|
var pcMode = false, pcModeA = false, lastw = 0, wW;
|
||||||
@ -697,22 +697,22 @@ function populateSegments(s)
|
|||||||
rvYck = `<label class="check revchkl">Reverse<input type="checkbox" id="seg${i}rY" onchange="setRevY(${i})" ${inst.rY?"checked":""}><span class="checkmark schk"></span></label>`;
|
rvYck = `<label class="check revchkl">Reverse<input type="checkbox" id="seg${i}rY" onchange="setRevY(${i})" ${inst.rY?"checked":""}><span class="checkmark schk"></span></label>`;
|
||||||
miYck = `<label class="check revchkl">Mirror<input type="checkbox" id="seg${i}mY" onchange="setMiY(${i})" ${inst.mY?"checked":""}><span class="checkmark schk"></span></label>`;
|
miYck = `<label class="check revchkl">Mirror<input type="checkbox" id="seg${i}mY" onchange="setMiY(${i})" ${inst.mY?"checked":""}><span class="checkmark schk"></span></label>`;
|
||||||
}
|
}
|
||||||
let map2D = `<div id="seg${i}map2D" data-map="map2D" class="lbl-s hide">Expand 1D FX:<br>
|
let map2D = `<div id="seg${i}map2D" data-map="map2D" class="lbl-s hide">Expand 1D FX<br>
|
||||||
<select class="sel-p" id="seg${i}mp12" onchange="setMp12(${i})">
|
<div class="sel-p"><select class="sel-p" id="seg${i}mp12" onchange="setMp12(${i})">
|
||||||
<option value="0" ${inst.mp12==0?' selected':''}>None</option>
|
<option value="0" ${inst.mp12==0?' selected':''}>None</option>
|
||||||
<option value="1" ${inst.mp12==1?' selected':''}>Vertical</option>
|
<option value="1" ${inst.mp12==1?' selected':''}>Bar</option>
|
||||||
<option value="2" ${inst.mp12==2?' selected':''}>Circle</option>
|
<option value="2" ${inst.mp12==2?' selected':''}>Arc</option>
|
||||||
<option value="3" ${inst.mp12==3?' selected':''}>Block</option>
|
<option value="3" ${inst.mp12==3?' selected':''}>Corner</option>
|
||||||
</select>
|
</select></div>
|
||||||
</div>`;
|
</div>`;
|
||||||
let sndSim = `<div data-snd="ssim" class="lbl-s hide">Sound sim:<br>
|
let sndSim = `<div data-snd="ssim" class="lbl-s hide">Sound sim<br>
|
||||||
<select class="sel-p" id="seg${i}ssim" onchange="setSSim(${i})">
|
<div class="sel-p"><select class="sel-p" id="seg${i}ssim" onchange="setSSim(${i})">
|
||||||
<option value="0" ${inst.ssim==0?' selected':''}>Off</option>
|
<option value="0" ${inst.ssim==0?' selected':''}>Off</option>
|
||||||
<option value="1" ${inst.ssim==1?' selected':''}>BeatSin</option>
|
<option value="1" ${inst.ssim==1?' selected':''}>BeatSin</option>
|
||||||
<option value="2" ${inst.ssim==2?' selected':''}>WeWillRockYou</option>
|
<option value="2" ${inst.ssim==2?' selected':''}>WeWillRockYou</option>
|
||||||
<option value="3" ${inst.ssim==3?' selected':''}>U10_3</option>
|
<option value="3" ${inst.ssim==3?' selected':''}>U10_3</option>
|
||||||
<option value="4" ${inst.ssim==4?' selected':''}>U14_3</option>
|
<option value="4" ${inst.ssim==4?' selected':''}>U14_3</option>
|
||||||
</select>
|
</select></div>
|
||||||
</div>`;
|
</div>`;
|
||||||
cn += `<div class="seg lstI ${i==s.mainseg ? 'selected' : ''} ${exp ? "expanded":""}" id="seg${i}">
|
cn += `<div class="seg lstI ${i==s.mainseg ? 'selected' : ''} ${exp ? "expanded":""}" id="seg${i}">
|
||||||
<label class="check schkl">
|
<label class="check schkl">
|
||||||
@ -1129,15 +1129,15 @@ function updateSelectedFx()
|
|||||||
if (selEffectInput) selEffectInput.checked = true;
|
if (selEffectInput) selEffectInput.checked = true;
|
||||||
|
|
||||||
var selElement = parent.querySelector('.selected');
|
var selElement = parent.querySelector('.selected');
|
||||||
if (selElement) selElement.classList.remove('selected');
|
if (selElement) {
|
||||||
|
selElement.classList.remove('selected');
|
||||||
|
selElement.style.bottom = null; // remove element style added in slider handling
|
||||||
|
}
|
||||||
|
|
||||||
var selectedEffect = parent.querySelector(`.lstI[data-id="${selectedFx}"]`);
|
var selectedEffect = parent.querySelector(`.lstI[data-id="${selectedFx}"]`);
|
||||||
if (selectedEffect) {
|
if (selectedEffect) {
|
||||||
selectedEffect.classList.add('selected');
|
selectedEffect.classList.add('selected');
|
||||||
var fx = (selectedFx != prevFx) && currentPreset==-1; // effect changed & preset==none
|
setEffectParameters(selectedFx);
|
||||||
var ps = (prevPS != currentPreset) && currentPreset==-1; // preset changed & preset==none
|
|
||||||
// WLEDSR: extract the Slider and color control string from the HTML element and set it.
|
|
||||||
setEffectParameters(selectedFx, (fx || ps));
|
|
||||||
|
|
||||||
var selectedName = selectedEffect.querySelector(".lstIname").innerText;
|
var selectedName = selectedEffect.querySelector(".lstIname").innerText;
|
||||||
var segs = gId("segcont").querySelectorAll(`div[data-map="map2D"]`);
|
var segs = gId("segcont").querySelectorAll(`div[data-map="map2D"]`);
|
||||||
@ -1215,7 +1215,6 @@ function readState(s,command=false)
|
|||||||
nlTar = s.nl.tbri;
|
nlTar = s.nl.tbri;
|
||||||
nlFade = s.nl.fade;
|
nlFade = s.nl.fade;
|
||||||
syncSend = s.udpn.send;
|
syncSend = s.udpn.send;
|
||||||
prevPS = currentPreset;
|
|
||||||
if (s.pl<0) currentPreset = s.ps;
|
if (s.pl<0) currentPreset = s.ps;
|
||||||
else currentPreset = s.pl;
|
else currentPreset = s.pl;
|
||||||
|
|
||||||
@ -1293,7 +1292,6 @@ function readState(s,command=false)
|
|||||||
showToast('Error ' + s.error + ": " + errstr, true);
|
showToast('Error ' + s.error + ": " + errstr, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
prevFx = selectedFx;
|
|
||||||
selectedPal = i.pal;
|
selectedPal = i.pal;
|
||||||
selectedFx = i.fx;
|
selectedFx = i.fx;
|
||||||
redrawPalPrev(); // if any color changed (random palette did at least)
|
redrawPalPrev(); // if any color changed (random palette did at least)
|
||||||
@ -1322,7 +1320,7 @@ function readState(s,command=false)
|
|||||||
// Note: Effects can override default pattern behaviour
|
// Note: Effects can override default pattern behaviour
|
||||||
// - FadeToBlack can override the background setting
|
// - FadeToBlack can override the background setting
|
||||||
// - Defining SEGCOL(<i>) can override a specific palette using these values (e.g. Color Gradient)
|
// - Defining SEGCOL(<i>) can override a specific palette using these values (e.g. Color Gradient)
|
||||||
function setEffectParameters(idx, applyDef=false)
|
function setEffectParameters(idx)
|
||||||
{
|
{
|
||||||
if (!(Array.isArray(fxdata) && fxdata.length>idx)) return;
|
if (!(Array.isArray(fxdata) && fxdata.length>idx)) return;
|
||||||
var controlDefined = (fxdata[idx].substr(0,1) == "@");
|
var controlDefined = (fxdata[idx].substr(0,1) == "@");
|
||||||
@ -1331,14 +1329,6 @@ function setEffectParameters(idx, applyDef=false)
|
|||||||
var slOnOff = (effectPars.length==0 || effectPars[0]=='')?[]:effectPars[0].split(",");
|
var slOnOff = (effectPars.length==0 || effectPars[0]=='')?[]:effectPars[0].split(",");
|
||||||
var coOnOff = (effectPars.length<2 || effectPars[1]=='')?[]:effectPars[1].split(",");
|
var coOnOff = (effectPars.length<2 || effectPars[1]=='')?[]:effectPars[1].split(",");
|
||||||
var paOnOff = (effectPars.length<3 || effectPars[2]=='')?[]:effectPars[2].split(",");
|
var paOnOff = (effectPars.length<3 || effectPars[2]=='')?[]:effectPars[2].split(",");
|
||||||
var obj = {"seg":{}};
|
|
||||||
// var obj = {"seg": {"rev": false, "rY": false}};
|
|
||||||
|
|
||||||
//assign extra parameters to segment
|
|
||||||
for (let i=3;i<effectPars.length;i++) {
|
|
||||||
let keyval = effectPars[i].split("=");
|
|
||||||
obj.seg[keyval[0]] = keyval[1]=="true"?true:keyval[1]=="false"?false:keyval[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
// set html slider items on/off
|
// set html slider items on/off
|
||||||
var nSliders = Math.min(5,Math.floor(gId("sliders").children.length)); // div for each slider
|
var nSliders = Math.min(5,Math.floor(gId("sliders").children.length)); // div for each slider
|
||||||
@ -1351,10 +1341,6 @@ function setEffectParameters(idx, applyDef=false)
|
|||||||
if (slOnOff.length>i && slOnOff[i].indexOf("=")>0) {
|
if (slOnOff.length>i && slOnOff[i].indexOf("=")>0) {
|
||||||
// embeded default values
|
// embeded default values
|
||||||
var dPos = slOnOff[i].indexOf("=");
|
var dPos = slOnOff[i].indexOf("=");
|
||||||
var v = Math.max(0,Math.min(255,parseInt(slOnOff[i].substr(dPos+1))));
|
|
||||||
if (i==0) { if (applyDef) gId("sliderSpeed").value = v; obj.seg.sx = v; }
|
|
||||||
else if (i==1) { if (applyDef) gId("sliderIntensity").value = v; obj.seg.ix = v; }
|
|
||||||
else { if (applyDef) gId("sliderC"+(i-1)).value = v; obj.seg["c"+(i-1)] = v}
|
|
||||||
slOnOff[i] = slOnOff[i].substring(0,dPos);
|
slOnOff[i] = slOnOff[i].substring(0,dPos);
|
||||||
}
|
}
|
||||||
if (slOnOff.length>i && slOnOff[i]!="!") label.innerHTML = slOnOff[i];
|
if (slOnOff.length>i && slOnOff[i]!="!") label.innerHTML = slOnOff[i];
|
||||||
@ -1362,18 +1348,15 @@ function setEffectParameters(idx, applyDef=false)
|
|||||||
else if (i==1) label.innerHTML = "Effect intensity";
|
else if (i==1) label.innerHTML = "Effect intensity";
|
||||||
else label.innerHTML = "Custom" + (i-1);
|
else label.innerHTML = "Custom" + (i-1);
|
||||||
sldCnt++;
|
sldCnt++;
|
||||||
//if (sldCnt++===0) slider.classList.add("top");
|
|
||||||
slider.classList.remove("hide");
|
slider.classList.remove("hide");
|
||||||
//slider.setAttribute('title',label.innerHTML);
|
|
||||||
} else {
|
} else {
|
||||||
slider.classList.add("hide");
|
slider.classList.add("hide");
|
||||||
//slider.classList.remove("top");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// set the bottom position of selected effect (sticky) as the top of sliders div
|
// set the bottom position of selected effect (sticky) as the top of sliders div
|
||||||
let top = parseInt(getComputedStyle(gId("sliders")).height);
|
let top = parseInt(getComputedStyle(gId("sliders")).height);
|
||||||
/*if (sldCnt===1)*/ top += 28; // size of tooltip
|
top += 28; // size of tooltip
|
||||||
let sel = d.querySelector('#fxlist .selected');
|
let sel = d.querySelector('#fxlist .selected');
|
||||||
if (sel) sel.style.bottom = top + "px"; // we will need to remove this when unselected (in setX())
|
if (sel) sel.style.bottom = top + "px"; // we will need to remove this when unselected (in setX())
|
||||||
|
|
||||||
@ -1423,11 +1406,6 @@ function setEffectParameters(idx, applyDef=false)
|
|||||||
// embeded default values
|
// embeded default values
|
||||||
var dPos = paOnOff[0].indexOf("=");
|
var dPos = paOnOff[0].indexOf("=");
|
||||||
var v = Math.max(0,Math.min(255,parseInt(paOnOff[0].substr(dPos+1))));
|
var v = Math.max(0,Math.min(255,parseInt(paOnOff[0].substr(dPos+1))));
|
||||||
var p = d.querySelector(`#pallist input[name="palette"][value="${v}"]`);
|
|
||||||
if (applyDef && p) {
|
|
||||||
p.checked = true;
|
|
||||||
obj.seg.pal = v;
|
|
||||||
}
|
|
||||||
paOnOff[0] = paOnOff[0].substring(0,dPos);
|
paOnOff[0] = paOnOff[0].substring(0,dPos);
|
||||||
}
|
}
|
||||||
if (paOnOff.length>0 && paOnOff[0] != "!") pall.innerHTML = paOnOff[0];
|
if (paOnOff.length>0 && paOnOff[0] != "!") pall.innerHTML = paOnOff[0];
|
||||||
@ -1436,14 +1414,11 @@ function setEffectParameters(idx, applyDef=false)
|
|||||||
// disable palett list
|
// disable palett list
|
||||||
pall.innerHTML = '<i class="icons sel-icon" onclick="tglHex()"></i> Color palette not used';
|
pall.innerHTML = '<i class="icons sel-icon" onclick="tglHex()"></i> Color palette not used';
|
||||||
palw.style.display = "none";
|
palw.style.display = "none";
|
||||||
// if numeric set as selected palette
|
|
||||||
if (paOnOff.length>0 && paOnOff[0]!="" && !isNaN(paOnOff[0]) && parseInt(paOnOff[0])!=selectedPal) obj.seg.pal = parseInt(paOnOff[0]);
|
|
||||||
}
|
}
|
||||||
// not all color selectors shown, hide palettes created from color selectors
|
// not all color selectors shown, hide palettes created from color selectors
|
||||||
for (let e of (gId('pallist').querySelectorAll('.lstI')||[])) {
|
for (let e of (gId('pallist').querySelectorAll('.lstI')||[])) {
|
||||||
if (cslCnt < 3 && e.querySelector('.lstIname').innerText.indexOf("* C")>=0) e.classList.add('hide'); else e.classList.remove('hide');
|
if (cslCnt < 3 && e.querySelector('.lstIname').innerText.indexOf("* C")>=0) e.classList.add('hide'); else e.classList.remove('hide');
|
||||||
}
|
}
|
||||||
if (!isEmpty(obj.seg) && applyDef) requestJson(obj); // update default values (may need throttling on ESP8266)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var jsonTimeout;
|
var jsonTimeout;
|
||||||
@ -1658,14 +1633,14 @@ var plJson = {"0":{
|
|||||||
"end": 0
|
"end": 0
|
||||||
}};
|
}};
|
||||||
|
|
||||||
function makePlSel(incPl=false) {
|
function makePlSel(el, incPl=false) {
|
||||||
var plSelContent = "";
|
var plSelContent = "";
|
||||||
delete pJson["0"]; // remove filler preset
|
delete pJson["0"]; // remove filler preset
|
||||||
var arr = Object.entries(pJson);
|
var arr = Object.entries(pJson);
|
||||||
for (var i = 0; i < arr.length; i++) {
|
for (var i = 0; i < arr.length; i++) {
|
||||||
var n = arr[i][1].n ? arr[i][1].n : "Preset " + arr[i][0];
|
var n = arr[i][1].n ? arr[i][1].n : "Preset " + arr[i][0];
|
||||||
if (!incPl && arr[i][1].playlist && arr[i][1].playlist.ps) continue; // remove playlists, sub-playlists not yet supported
|
if (!incPl && arr[i][1].playlist && arr[i][1].playlist.ps) continue; // remove playlists, sub-playlists not yet supported
|
||||||
plSelContent += `<option value="${arr[i][0]}">${n}</option>`
|
plSelContent += `<option value="${arr[i][0]}" ${arr[i][0]==el?"selected":""}>${n}</option>`
|
||||||
}
|
}
|
||||||
return plSelContent;
|
return plSelContent;
|
||||||
}
|
}
|
||||||
@ -1751,11 +1726,11 @@ function makeP(i,pl) {
|
|||||||
<div id="pl${i}o1" style="display:${rep>0?"block":"none"}">
|
<div id="pl${i}o1" style="display:${rep>0?"block":"none"}">
|
||||||
<div class="c">Repeat <input class="noslide" type="number" id="pl${i}rp" oninput="plR(${i})" max=127 min=0 value=${rep>0?rep:1}> times</div>
|
<div class="c">Repeat <input class="noslide" type="number" id="pl${i}rp" oninput="plR(${i})" max=127 min=0 value=${rep>0?rep:1}> times</div>
|
||||||
<div class="sel">End preset:<br>
|
<div class="sel">End preset:<br>
|
||||||
<select class="sel-ple" id="pl${i}selEnd" onchange="plR(${i})" data-val=${plJson[i].end?plJson[i].end:0}>
|
<div class="sel-p"><select class="sel-ple" id="pl${i}selEnd" onchange="plR(${i})" data-val=${plJson[i].end?plJson[i].end:0}>
|
||||||
<option value="0">None</option>
|
<option value="0">None</option>
|
||||||
<option value="255">Restore preset</option>
|
<option value="255">Restore preset</option>
|
||||||
${makePlSel(true)}
|
${makePlSel(plJson[i].end?plJson[i].end:0, true)}
|
||||||
</select></div>
|
</select></div></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="c"><button class="btn btn-p" onclick="testPl(${i}, this)"><i class='icons btn-icon'></i>Test</button></div>`;
|
<div class="c"><button class="btn btn-p" onclick="testPl(${i}, this)"><i class='icons btn-icon'></i>Test</button></div>`;
|
||||||
} else {
|
} else {
|
||||||
@ -1835,9 +1810,9 @@ function makePlEntry(p,i) {
|
|||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td width="80%" colspan=2>
|
<td width="80%" colspan=2>
|
||||||
<select class="sel-pl" onchange="plePs(${p},${i},this)" data-val="${plJson[p].ps[i]}" data-index="${i}">
|
<div class="sel-p"><select class="sel-pl" onchange="plePs(${p},${i},this)" data-val="${plJson[p].ps[i]}" data-index="${i}">
|
||||||
${makePlSel()}
|
${makePlSel(plJson[p].ps[i])}
|
||||||
</select>
|
</select></div>
|
||||||
</td>
|
</td>
|
||||||
<td class="c"><button class="btn btn-pl-add" onclick="addPl(${p},${i})"><i class="icons btn-icon"></i></button></td>
|
<td class="c"><button class="btn btn-pl-add" onclick="addPl(${p},${i})"><i class="icons btn-icon"></i></button></td>
|
||||||
</tr>
|
</tr>
|
||||||
@ -2061,6 +2036,8 @@ function setX(ind = null)
|
|||||||
} else {
|
} else {
|
||||||
d.querySelector(`#fxlist input[name="fx"][value="${ind}"]`).checked = true;
|
d.querySelector(`#fxlist input[name="fx"][value="${ind}"]`).checked = true;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
// this code also in updateSelectedFx
|
||||||
var selElement = d.querySelector('#fxlist .selected');
|
var selElement = d.querySelector('#fxlist .selected');
|
||||||
if (selElement) {
|
if (selElement) {
|
||||||
selElement.classList.remove('selected');
|
selElement.classList.remove('selected');
|
||||||
@ -2068,7 +2045,7 @@ function setX(ind = null)
|
|||||||
}
|
}
|
||||||
|
|
||||||
d.querySelector(`#fxlist .lstI[data-id="${ind}"]`).classList.add('selected');
|
d.querySelector(`#fxlist .lstI[data-id="${ind}"]`).classList.add('selected');
|
||||||
|
*/
|
||||||
var obj = {"seg": {"fx": parseInt(ind)}};
|
var obj = {"seg": {"fx": parseInt(ind)}};
|
||||||
requestJson(obj);
|
requestJson(obj);
|
||||||
}
|
}
|
||||||
@ -2080,11 +2057,13 @@ function setPalette(paletteId = null)
|
|||||||
} else {
|
} else {
|
||||||
d.querySelector(`#pallist input[name="palette"][value="${paletteId}"]`).checked = true;
|
d.querySelector(`#pallist input[name="palette"][value="${paletteId}"]`).checked = true;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
var selElement = d.querySelector('#pallist .selected');
|
var selElement = d.querySelector('#pallist .selected');
|
||||||
if (selElement) {
|
if (selElement) {
|
||||||
selElement.classList.remove('selected')
|
selElement.classList.remove('selected')
|
||||||
}
|
}
|
||||||
d.querySelector(`#pallist .lstI[data-id="${paletteId}"]`).classList.add('selected');
|
d.querySelector(`#pallist .lstI[data-id="${paletteId}"]`).classList.add('selected');
|
||||||
|
*/
|
||||||
var obj = {"seg": {"pal": paletteId}};
|
var obj = {"seg": {"pal": paletteId}};
|
||||||
requestJson(obj);
|
requestJson(obj);
|
||||||
}
|
}
|
||||||
|
@ -299,7 +299,7 @@ class UsermodManager {
|
|||||||
void onUpdateBegin(bool);
|
void onUpdateBegin(bool);
|
||||||
bool add(Usermod* um);
|
bool add(Usermod* um);
|
||||||
Usermod* lookup(uint16_t mod_id);
|
Usermod* lookup(uint16_t mod_id);
|
||||||
byte getModCount();
|
byte getModCount() {return numMods;};
|
||||||
};
|
};
|
||||||
|
|
||||||
//usermods_list.cpp
|
//usermods_list.cpp
|
||||||
@ -324,7 +324,8 @@ bool isAsterisksOnly(const char* str, byte maxLen);
|
|||||||
bool requestJSONBufferLock(uint8_t module=255);
|
bool requestJSONBufferLock(uint8_t module=255);
|
||||||
void releaseJSONBufferLock();
|
void releaseJSONBufferLock();
|
||||||
uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLen);
|
uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLen);
|
||||||
uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxLen);
|
uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxLen, uint8_t *var = nullptr);
|
||||||
|
int16_t extractModeDefaults(uint8_t mode, const char *segVar);
|
||||||
uint16_t crc16(const unsigned char* data_p, size_t length);
|
uint16_t crc16(const unsigned char* data_p, size_t length);
|
||||||
|
|
||||||
//wled_eeprom.cpp
|
//wled_eeprom.cpp
|
||||||
|
1799
wled00/html_ui.h
1799
wled00/html_ui.h
File diff suppressed because it is too large
Load Diff
@ -162,11 +162,10 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
seg.setOption(SEG_OPTION_SELECTED, elem[F("sel")] | seg.getOption(SEG_OPTION_SELECTED));
|
seg.setOption(SEG_OPTION_SELECTED, elem["sel"] | seg.getOption(SEG_OPTION_SELECTED));
|
||||||
seg.setOption(SEG_OPTION_REVERSED, elem["rev"] | seg.getOption(SEG_OPTION_REVERSED));
|
seg.setOption(SEG_OPTION_REVERSED, elem["rev"] | seg.getOption(SEG_OPTION_REVERSED));
|
||||||
seg.setOption(SEG_OPTION_MIRROR , elem[F("mi")] | seg.getOption(SEG_OPTION_MIRROR ));
|
seg.setOption(SEG_OPTION_MIRROR , elem[F("mi")] | seg.getOption(SEG_OPTION_MIRROR ));
|
||||||
#ifndef WLED_DISABLE_2D
|
#ifndef WLED_DISABLE_2D
|
||||||
// 2D options
|
|
||||||
seg.setOption(SEG_OPTION_REVERSED_Y, elem[F("rY")] | seg.getOption(SEG_OPTION_REVERSED_Y));
|
seg.setOption(SEG_OPTION_REVERSED_Y, elem[F("rY")] | seg.getOption(SEG_OPTION_REVERSED_Y));
|
||||||
seg.setOption(SEG_OPTION_MIRROR_Y , elem[F("mY")] | seg.getOption(SEG_OPTION_MIRROR_Y ));
|
seg.setOption(SEG_OPTION_MIRROR_Y , elem[F("mY")] | seg.getOption(SEG_OPTION_MIRROR_Y ));
|
||||||
seg.setOption(SEG_OPTION_TRANSPOSED, elem[F("tp")] | seg.getOption(SEG_OPTION_TRANSPOSED));
|
seg.setOption(SEG_OPTION_TRANSPOSED, elem[F("tp")] | seg.getOption(SEG_OPTION_TRANSPOSED));
|
||||||
@ -178,10 +177,41 @@ void deserializeSegment(JsonObject elem, byte it, byte presetId)
|
|||||||
strip.setMode(id, fx);
|
strip.setMode(id, fx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// load default values from effect string if effect is selected without
|
||||||
|
// any other effect parameter (i.e. effect clicked in UI)
|
||||||
|
if (elem[F("sx")].isNull() && elem[F("ix")].isNull() && elem["pal"].isNull() && elem[F("c1")].isNull() && elem[F("c2")].isNull() && elem[F("c3")].isNull()) {
|
||||||
|
char buf[5]; // dummy buffer
|
||||||
|
for (int i=0; i<5; i++) {
|
||||||
|
uint8_t *var;
|
||||||
|
switch (i) {
|
||||||
|
case 0: var = &seg.speed; break;
|
||||||
|
case 1: var = &seg.intensity; break;
|
||||||
|
case 2: var = &seg.custom1; break;
|
||||||
|
case 3: var = &seg.custom2; break;
|
||||||
|
case 4: var = &seg.custom3; break;
|
||||||
|
}
|
||||||
|
extractModeSlider(fx, i, buf, 4, var);
|
||||||
|
}
|
||||||
|
extractModeSlider(fx, 255, buf, 4, &seg.palette);
|
||||||
|
int16_t sOpt;
|
||||||
|
sOpt = extractModeDefaults(fx, SET_F("sx")); if (sOpt >= 0) seg.speed = sOpt;
|
||||||
|
sOpt = extractModeDefaults(fx, SET_F("ix")); if (sOpt >= 0) seg.intensity = sOpt;
|
||||||
|
sOpt = extractModeDefaults(fx, SET_F("c1")); if (sOpt >= 0) seg.custom1 = sOpt;
|
||||||
|
sOpt = extractModeDefaults(fx, SET_F("c2")); if (sOpt >= 0) seg.custom2 = sOpt;
|
||||||
|
sOpt = extractModeDefaults(fx, SET_F("c3")); if (sOpt >= 0) seg.custom3 = sOpt;
|
||||||
|
sOpt = extractModeDefaults(fx, "pal"); if (sOpt >= 0) seg.palette = sOpt;
|
||||||
|
sOpt = extractModeDefaults(fx, SET_F("mp12")); if (sOpt >= 0) seg.map1D2D = sOpt & 0x03;
|
||||||
|
sOpt = extractModeDefaults(fx, SET_F("ssim")); if (sOpt >= 0) seg.soundSim = sOpt & 0x07;
|
||||||
|
sOpt = extractModeDefaults(fx, "rev"); if (sOpt >= 0) seg.setOption(SEG_OPTION_REVERSED, (bool)sOpt);
|
||||||
|
sOpt = extractModeDefaults(fx, SET_F("mi")); if (sOpt >= 0) seg.setOption(SEG_OPTION_MIRROR, (bool)sOpt);
|
||||||
|
sOpt = extractModeDefaults(fx, SET_F("rY")); if (sOpt >= 0) seg.setOption(SEG_OPTION_REVERSED_Y, (bool)sOpt);
|
||||||
|
sOpt = extractModeDefaults(fx, SET_F("mY")); if (sOpt >= 0) seg.setOption(SEG_OPTION_MIRROR_Y, (bool)sOpt);
|
||||||
|
}
|
||||||
|
|
||||||
//getVal also supports inc/decrementing and random
|
//getVal also supports inc/decrementing and random
|
||||||
getVal(elem[F("sx")], &seg.speed);
|
getVal(elem[F("sx")], &seg.speed);
|
||||||
getVal(elem[F("ix")], &seg.intensity);
|
getVal(elem[F("ix")], &seg.intensity);
|
||||||
getVal(elem["pal"], &seg.palette, 1, strip.getPaletteCount());
|
getVal(elem["pal"], &seg.palette, 1, strip.getPaletteCount());
|
||||||
getVal(elem[F("c1")], &seg.custom1);
|
getVal(elem[F("c1")], &seg.custom1);
|
||||||
getVal(elem[F("c2")], &seg.custom2);
|
getVal(elem[F("c2")], &seg.custom2);
|
||||||
getVal(elem[F("c3")], &seg.custom3);
|
getVal(elem[F("c3")], &seg.custom3);
|
||||||
|
@ -56,7 +56,8 @@ enum struct PinOwner : uint8_t {
|
|||||||
// #define USERMOD_ID_SN_PHOTORESISTOR // 0x11 // Usermod "usermod_sn_photoresistor.h" -- Uses hard-coded pin (PHOTORESISTOR_PIN == A0), but could be easily updated to use pinManager
|
// #define USERMOD_ID_SN_PHOTORESISTOR // 0x11 // Usermod "usermod_sn_photoresistor.h" -- Uses hard-coded pin (PHOTORESISTOR_PIN == A0), but could be easily updated to use pinManager
|
||||||
UM_RGBRotaryEncoder = USERMOD_RGB_ROTARY_ENCODER, // 0x16 // Usermod "rgb-rotary-encoder.h"
|
UM_RGBRotaryEncoder = USERMOD_RGB_ROTARY_ENCODER, // 0x16 // Usermod "rgb-rotary-encoder.h"
|
||||||
UM_QuinLEDAnPenta = USERMOD_ID_QUINLED_AN_PENTA, // 0x17 // Usermod "quinled-an-penta.h"
|
UM_QuinLEDAnPenta = USERMOD_ID_QUINLED_AN_PENTA, // 0x17 // Usermod "quinled-an-penta.h"
|
||||||
UM_Audioreactive = USERMOD_ID_AUDIOREACTIVE // 0x1E // Usermod: "audio_reactive.h"
|
UM_BME280 = USERMOD_ID_BME280, // 0x18 // Usermod "usermod_bme280.h -- Uses "standard" HW_I2C pins
|
||||||
|
UM_Audioreactive = USERMOD_ID_AUDIOREACTIVE // 0x1E // Usermod "audio_reactive.h"
|
||||||
};
|
};
|
||||||
static_assert(0u == static_cast<uint8_t>(PinOwner::None), "PinOwner::None must be zero, so default array initialization works as expected");
|
static_assert(0u == static_cast<uint8_t>(PinOwner::None), "PinOwner::None must be zero, so default array initialization works as expected");
|
||||||
|
|
||||||
|
@ -59,5 +59,3 @@ bool UsermodManager::add(Usermod* um)
|
|||||||
ums[numMods++] = um;
|
ums[numMods++] = um;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
byte UsermodManager::getModCount() {return numMods;}
|
|
@ -281,7 +281,7 @@ uint8_t extractModeName(uint8_t mode, const char *src, char *dest, uint8_t maxLe
|
|||||||
|
|
||||||
|
|
||||||
// extracts effect slider data (1st group after @)
|
// extracts effect slider data (1st group after @)
|
||||||
uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxLen)
|
uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxLen, uint8_t *var)
|
||||||
{
|
{
|
||||||
dest[0] = '\0'; // start by clearing buffer
|
dest[0] = '\0'; // start by clearing buffer
|
||||||
|
|
||||||
@ -291,30 +291,50 @@ uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxL
|
|||||||
int16_t start = lineBuffer.indexOf('@');
|
int16_t start = lineBuffer.indexOf('@');
|
||||||
int16_t stop = lineBuffer.indexOf(';', start);
|
int16_t stop = lineBuffer.indexOf(';', start);
|
||||||
if (start>0 && stop>0) {
|
if (start>0 && stop>0) {
|
||||||
String names = lineBuffer.substring(start+1, stop);
|
String names = lineBuffer.substring(start, stop); // include @
|
||||||
int16_t nameBegin = 0, nameEnd;
|
int16_t nameBegin = 1, nameEnd, nameDefault;
|
||||||
for (size_t i=0; i<=slider; i++) {
|
if (slider < 10) {
|
||||||
const char *tmpstr;
|
for (size_t i=0; i<=slider; i++) {
|
||||||
dest[0] = '\0'; //clear dest buffer
|
const char *tmpstr;
|
||||||
if (i > 0 && nameBegin == 0) break; // there are no more names
|
dest[0] = '\0'; //clear dest buffer
|
||||||
nameEnd = names.indexOf(',', nameBegin);
|
if (nameBegin == 0) break; // there are no more names
|
||||||
if (names.charAt(nameBegin) == '!') {
|
nameEnd = names.indexOf(',', nameBegin);
|
||||||
switch (i) {
|
if (i == slider) {
|
||||||
case 0: tmpstr = PSTR("FX Speed"); break;
|
nameDefault = names.indexOf('=', nameBegin); // find default value
|
||||||
case 1: tmpstr = PSTR("FX Intensity"); break;
|
if (nameDefault > 0 && var && ((nameEnd>0 && nameDefault<nameEnd) || nameEnd<0)) {
|
||||||
case 2: tmpstr = PSTR("FX Custom 1"); break;
|
*var = (uint8_t)atoi(names.substring(nameDefault+1).c_str());
|
||||||
case 3: tmpstr = PSTR("FX Custom 2"); break;
|
}
|
||||||
case 4: tmpstr = PSTR("FX Custom 3"); break;
|
if (names.charAt(nameBegin) == '!') {
|
||||||
default: tmpstr = PSTR("FX Custom"); break;
|
switch (slider) {
|
||||||
|
case 0: tmpstr = PSTR("FX Speed"); break;
|
||||||
|
case 1: tmpstr = PSTR("FX Intensity"); break;
|
||||||
|
case 2: tmpstr = PSTR("FX Custom 1"); break;
|
||||||
|
case 3: tmpstr = PSTR("FX Custom 2"); break;
|
||||||
|
case 4: tmpstr = PSTR("FX Custom 3"); break;
|
||||||
|
default: tmpstr = PSTR("FX Custom"); break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (nameEnd<0) tmpstr = names.substring(nameBegin).c_str(); // did not find ",", last name?
|
||||||
|
else tmpstr = names.substring(nameBegin, nameEnd).c_str();
|
||||||
|
}
|
||||||
|
strlcpy(dest, tmpstr, maxLen); // copy the name into buffer (replacing previous)
|
||||||
|
}
|
||||||
|
nameBegin = nameEnd+1; // next name (if "," is not found it will be 0)
|
||||||
|
} // next slider
|
||||||
|
} else if (slider == 255) {
|
||||||
|
// palette
|
||||||
|
strlcpy(dest, "pal", maxLen);
|
||||||
|
names = lineBuffer.substring(stop+1); // stop has index of color slot names
|
||||||
|
nameBegin = names.indexOf(';'); // look for palette
|
||||||
|
if (nameBegin >= 0) {
|
||||||
|
nameEnd = names.indexOf(';', nameBegin+1);
|
||||||
|
if (!isdigit(names[nameBegin+1])) nameBegin = names.indexOf('=', nameBegin+1); // look for default value
|
||||||
|
if (nameEnd >= 0 && nameBegin > nameEnd) nameBegin = -1;
|
||||||
|
if (nameBegin >= 0 && var) {
|
||||||
|
*var = (uint8_t)atoi(names.substring(nameBegin+1).c_str());
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (nameEnd<0) tmpstr = names.substring(nameBegin).c_str(); // did not find ",", last name?
|
|
||||||
else tmpstr = names.substring(nameBegin, nameEnd).c_str();
|
|
||||||
}
|
}
|
||||||
strncpy(dest, tmpstr, maxLen); // copy the name into buffer (replacing previous)
|
}
|
||||||
nameBegin = nameEnd+1; // next name (if "," is not found it will be 0)
|
|
||||||
} // next slider
|
|
||||||
|
|
||||||
// we have slider name (including default value) in the dest buffer
|
// we have slider name (including default value) in the dest buffer
|
||||||
for (size_t i=0; i<strlen(dest); i++) if (dest[i]=='=') { dest[i]='\0'; break; } // truncate default value
|
for (size_t i=0; i<strlen(dest); i++) if (dest[i]=='=') { dest[i]='\0'; break; } // truncate default value
|
||||||
|
|
||||||
@ -324,6 +344,7 @@ uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxL
|
|||||||
case 0: strncpy_P(dest, PSTR("FX Speed"), maxLen); break;
|
case 0: strncpy_P(dest, PSTR("FX Speed"), maxLen); break;
|
||||||
case 1: strncpy_P(dest, PSTR("FX Intensity"), maxLen); break;
|
case 1: strncpy_P(dest, PSTR("FX Intensity"), maxLen); break;
|
||||||
}
|
}
|
||||||
|
dest[maxLen] = '\0'; // strncpy does not necessarily null terminate string
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return strlen(dest);
|
return strlen(dest);
|
||||||
@ -332,6 +353,23 @@ uint8_t extractModeSlider(uint8_t mode, uint8_t slider, char *dest, uint8_t maxL
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int16_t extractModeDefaults(uint8_t mode, const char *segVar)
|
||||||
|
{
|
||||||
|
if (mode < strip.getModeCount()) {
|
||||||
|
String lineBuffer = strip.getModeData(mode);
|
||||||
|
if (lineBuffer.length() > 0) {
|
||||||
|
int16_t start = lineBuffer.lastIndexOf(';');
|
||||||
|
if (start<0) return -1;
|
||||||
|
|
||||||
|
int16_t stop = lineBuffer.indexOf(segVar, start+1);
|
||||||
|
if (stop<0) return -1;
|
||||||
|
return atoi(lineBuffer.substring(stop+strlen(segVar)+1).c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
uint16_t crc16(const unsigned char* data_p, size_t length) {
|
uint16_t crc16(const unsigned char* data_p, size_t length) {
|
||||||
uint8_t x;
|
uint8_t x;
|
||||||
uint16_t crc = 0xFFFF;
|
uint16_t crc = 0xFFFF;
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// version code in format yymmddb (b = daily build)
|
// version code in format yymmddb (b = daily build)
|
||||||
#define VERSION 2207211
|
#define VERSION 2207241
|
||||||
|
|
||||||
//uncomment this if you have a "my_config.h" file you'd like to use
|
//uncomment this if you have a "my_config.h" file you'd like to use
|
||||||
//#define WLED_USE_MY_CONFIG
|
//#define WLED_USE_MY_CONFIG
|
||||||
|
@ -305,8 +305,8 @@ void initServer()
|
|||||||
DEBUG_PRINTLN(F("Update Success"));
|
DEBUG_PRINTLN(F("Update Success"));
|
||||||
} else {
|
} else {
|
||||||
DEBUG_PRINTLN(F("Update Failed"));
|
DEBUG_PRINTLN(F("Update Failed"));
|
||||||
WLED::instance().enableWatchdog();
|
|
||||||
usermods.onUpdateBegin(false); // notify usermods that update has failed (some may require task init)
|
usermods.onUpdateBegin(false); // notify usermods that update has failed (some may require task init)
|
||||||
|
WLED::instance().enableWatchdog();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -308,9 +308,15 @@ void getSettingsJS(byte subPage, char* dest)
|
|||||||
|
|
||||||
// set limits
|
// set limits
|
||||||
oappend(SET_F("bLimits("));
|
oappend(SET_F("bLimits("));
|
||||||
|
#ifdef ESP32
|
||||||
|
// requested by @softhack007 https://github.com/blazoncek/WLED/issues/33
|
||||||
|
if (usermods.lookup(USERMOD_ID_AUDIOREACTIVE))
|
||||||
|
oappend(itoa(WLED_MAX_BUSSES-2,nS,10)); // prevent use of I2S buses if audio installed
|
||||||
|
else
|
||||||
|
#endif
|
||||||
oappend(itoa(WLED_MAX_BUSSES,nS,10)); oappend(",");
|
oappend(itoa(WLED_MAX_BUSSES,nS,10)); oappend(",");
|
||||||
oappend(itoa(MAX_LEDS_PER_BUS,nS,10)); oappend(",");
|
oappend(itoa(MAX_LEDS_PER_BUS,nS,10)); oappend(",");
|
||||||
oappend(itoa(MAX_LED_MEMORY,nS,10)); oappend(",");
|
oappend(itoa(MAX_LED_MEMORY,nS,10)); oappend(",");
|
||||||
oappend(itoa(MAX_LEDS,nS,10));
|
oappend(itoa(MAX_LEDS,nS,10));
|
||||||
oappend(SET_F(");"));
|
oappend(SET_F(");"));
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user