Add usermode to control Wiz lights (#2595)

* Add usermode to control Wiz lights (#1)

* Fix inclusion in usermods list

Co-authored-by: Christian Schwinne <dev.aircoookie@gmail.com>
This commit is contained in:
Eduardo Ibanez 2022-03-23 10:20:18 -05:00 committed by GitHub
parent a517f0df1d
commit 22c3ac5be3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 164 additions and 0 deletions

View File

@ -0,0 +1,13 @@
# Controlling Wiz lights
This usermod allows the control of [WiZ](https://www.wizconnected.com/en/consumer/) lights that are in the same network as the WLED controller.
The mod takes the colors from the first few pixels and sends them to the lights.
## Configuration
First, enter how often the data will be sent to the lights (in ms).
Then enter the IPs for the lights to be controlled, in order. There is currently a limit of 10 devices that can be controled, but that number
can be easily changed by updating _MAX_WIZ_LIGHTS_.

View File

@ -0,0 +1,142 @@
#pragma once
#include "wled.h"
#include <WiFiUdp.h>
// Maximum number of lights supported
#define MAX_WIZ_LIGHTS 10
// UDP object, to send messages
WiFiUDP UDP;
// Function to send a color to a light
void sendColor(IPAddress ip, uint32_t color) {
UDP.beginPacket(ip, 38899);
if (color == 0) {
UDP.print("{\"method\":\"setPilot\",\"params\":{\"state\":false}}");
} else {
UDP.print("{\"method\":\"setPilot\",\"params\":{\"state\":true, \"r\":");
UDP.print(R(color));
UDP.print(",\"g\":");
UDP.print(G(color));
UDP.print(",\"b\":");
UDP.print(B(color));
UDP.print("}}");
}
UDP.endPacket();
}
// Create label for the usermode page (I cannot make it work with JSON arrays...)
String getJsonLabel(uint8_t i) {
return "ip_light_" + String(i);
}
class WizLightsUsermod : public Usermod {
private:
// Keep track of the last time the lights were updated
unsigned long lastTime = 0;
// Specify how often WLED sends data to the Wiz lights
long updateInterval;
// Save the IP of the lights
IPAddress lightsIP[MAX_WIZ_LIGHTS];
bool lightsValid[MAX_WIZ_LIGHTS];
// Variable that keeps track of RBG values for the lights
uint32_t colorsSent[MAX_WIZ_LIGHTS];
public:
//Functions called by WLED
/*
* loop() is called continuously. Here you can check for events, read sensors, etc.
*/
void loop() {
// Calculate how long since the last update
unsigned long ellapsedTime = millis() - lastTime;
if (ellapsedTime > updateInterval) {
// Keep track of whether we are updating any of the lights
bool update = false;
// Loop through the lights
for (uint8_t i = 0; i < MAX_WIZ_LIGHTS; i++) {
// Check if we have a valid IP
if (!lightsValid[i]) { continue; }
// Get the first colors in the strip
uint32_t new_color = strip.getPixelColor(i);
// Check if the color has changed from the last one sent
// Force an update every 5 minutes, in case the colors don't change
// (the lights could have been reset by turning off and on)
if ((new_color != colorsSent[i]) | (ellapsedTime > 5*60000)) {
// It has changed, send the new color to the light
update = true;
sendColor(lightsIP[i], new_color);
colorsSent[i] = new_color;
}
}
// We sent an update, wait until we do this again
if (update) {
lastTime = millis();
}
}
}
/*
* 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().
*/
void addToConfig(JsonObject& root)
{
JsonObject top = root.createNestedObject("wizLightsUsermod");
top["interval_ms"] = updateInterval;
for (uint8_t i = 0; i < MAX_WIZ_LIGHTS; i++) {
top[getJsonLabel(i)] = lightsIP[i].toString();
}
}
/*
* 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)
*/
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)
JsonObject top = root["wizLightsUsermod"];
bool configComplete = !top.isNull();
// Read interval to update the lights
configComplete &= getJsonValue(top["interval_ms"], updateInterval, 1000);
// Read list of IPs
String tempIp;
for (uint8_t i = 0; i < MAX_WIZ_LIGHTS; i++) {
configComplete &= getJsonValue(top[getJsonLabel(i)], tempIp, "0.0.0.0");
lightsValid[i] = lightsIP[i].fromString(tempIp);
// If the IP is not valid, force the value to be empty
if (!lightsValid[i]) {
lightsIP[i].fromString("0.0.0.0");
}
}
return configComplete;
}
/*
* 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_WIZLIGHTS;
}
};

View File

@ -72,6 +72,7 @@
#define USERMOD_ID_QUINLED_AN_PENTA 23 //Usermod "quinled-an-penta.h"
#define USERMOD_ID_SSDR 24 //Usermod "usermod_v2_seven_segment_display_reloaded.h"
#define USERMOD_ID_CRONIXIE 25 //Usermod "usermod_cronixie.h"
#define USERMOD_ID_WIZLIGHTS 26 //Usermod "wizlights.h"
//Access point behavior
#define AP_BEHAVIOR_BOOT_NO_CONN 0 //Open AP when no connection after boot

View File

@ -112,6 +112,10 @@
#include "../usermods/quinled-an-penta/quinled-an-penta.h"
#endif
#ifdef USERMOD_WIZLIGHTS
#include "../usermods/wizlights/wizlights.h"
#endif
void registerUsermods()
{
/*
@ -211,4 +215,8 @@ void registerUsermods()
#ifdef QUINLED_AN_PENTA
usermods.add(new QuinLEDAnPentaUsermod());
#endif
#ifdef USERMOD_WIZLIGHTS
usermods.add(new WizLightsUsermod());
#endif
}