186 lines
7.1 KiB
C++
186 lines
7.1 KiB
C++
#include <ArduinoJson.h>
|
|
#include "light.h"
|
|
#include "mqtt.h"
|
|
|
|
constexpr uint16_t CONFIG_MSG_SIZE = 1024;
|
|
constexpr uint16_t STATUS_MSG_SIZE = 128;
|
|
|
|
const struct {
|
|
String available = "online";
|
|
String notAvailable = "offline";
|
|
} Availability;
|
|
|
|
|
|
Light::Light(Pin* pinR, Pin* pinG, Pin* pinB, Mqtt* mqttClient, std::string uniqueId)
|
|
: pinR(pinR), pinG(pinG), pinB(pinB), pinCW(nullptr), pinWW(nullptr), mqttClient(mqttClient) {
|
|
lightInfo.uniqueId = uniqueId;
|
|
lightType = LightType::rgb;
|
|
publishInitialState();
|
|
subscribeToMqttTopics();
|
|
}
|
|
|
|
void Light::publishInitialState() {
|
|
// Publish the initial state of the light
|
|
JsonDocument configInfo;
|
|
JsonObject deviceInfo = configInfo["device"].to<JsonObject>();
|
|
deviceInfo["name"] = this->deviceInfo.name;
|
|
deviceInfo["model"] = this->deviceInfo.model;
|
|
JsonArray identifiers = deviceInfo["identifiers"].to<JsonArray>();
|
|
identifiers.add(this->deviceInfo.identifier + this->lightInfo.uniqueId);
|
|
deviceInfo["sw_version"] = this->deviceInfo.swVersion;
|
|
deviceInfo["manufacturer"] = this->deviceInfo.manufacturer;
|
|
|
|
configInfo["unique_id"] = this->lightInfo.uniqueId;
|
|
configInfo["name"] = this->lightInfo.name;
|
|
configInfo["schema"] = "json";
|
|
// configInfo["json_attributes_topic"] = this->lightInfo.statusTopic;
|
|
configInfo["command_topic"] = this->lightInfo.commandTopic;
|
|
JsonArray availabilityInfo = configInfo["availability"].to<JsonArray>();
|
|
JsonObject availabilityItem = availabilityInfo.add<JsonObject>();
|
|
availabilityItem["topic"] = this->lightInfo.availabilityTopic;
|
|
availabilityItem["value_template"] = this->lightInfo.availabilityTemplate;
|
|
JsonArray supportedColorModes = configInfo["supported_color_modes"].to<JsonArray>();
|
|
if (lightType == LightType::rgb) {
|
|
supportedColorModes.add("rgb");
|
|
} else if (lightType == LightType::rgbw) {
|
|
supportedColorModes.add("rgbw");
|
|
} else if (lightType == LightType::rgbww) {
|
|
supportedColorModes.add("rgbww");
|
|
supportedColorModes.add("color_temp");
|
|
} else if (lightType == LightType::colorTemperature) {
|
|
supportedColorModes.add("color_temp");
|
|
} else if (lightType == LightType::brightness) {
|
|
supportedColorModes.add("brightness");
|
|
} else {
|
|
supportedColorModes.add("onoff");
|
|
}
|
|
configInfo["state_topic"] = this->lightInfo.stateTopic;
|
|
// configInfo["state_value_template"] = this->lightInfo.stateValueTemplate;
|
|
|
|
std::string configJson;
|
|
serializeJson(configInfo, configJson);
|
|
mqttClient->publish(lightInfo.discoveryTopic, configJson);
|
|
|
|
std::string stateJson;
|
|
JsonDocument stateInfo;
|
|
stateInfo["state"] = "OFF"; // Initial state is OFF
|
|
// stateInfo["availability"] = Availability.available; // Initial availability
|
|
stateInfo["brightness"] = 0; // Initial brightness
|
|
JsonObject rgbValue = stateInfo["rgb_value"].to<JsonObject>();
|
|
rgbValue["r"] = 255;
|
|
rgbValue["g"] = 255;
|
|
rgbValue["b"] = 255;
|
|
serializeJson(stateInfo, stateJson);
|
|
std::string availabilityJson;
|
|
JsonDocument availabilityInfoDoc;
|
|
availabilityInfoDoc["availability"] = Availability.available; // Initial availability
|
|
serializeJson(availabilityInfoDoc, availabilityJson);
|
|
mqttClient->publish(lightInfo.stateTopic, stateJson);
|
|
mqttClient->publish(lightInfo.availabilityTopic, availabilityJson);
|
|
}
|
|
|
|
void Light::operatePin() {
|
|
uint32_t rSetpoint = r;
|
|
uint32_t gSetpoint = g;
|
|
uint32_t bSetpoint = b;
|
|
if (!isOn) {
|
|
turnOff();
|
|
return;
|
|
}
|
|
float brightnessFactor = brightness / 255.0f;
|
|
rSetpoint = static_cast<uint32_t>(r * brightnessFactor);
|
|
gSetpoint = static_cast<uint32_t>(g * brightnessFactor);
|
|
bSetpoint = static_cast<uint32_t>(b * brightnessFactor);
|
|
Serial.printf("Setting RGB: R=%d, G=%d, B=%d with brightness factor: %.2f\n", rSetpoint, gSetpoint, bSetpoint, brightnessFactor);
|
|
pinR->setLedLevel(rSetpoint);
|
|
pinG->setLedLevel(gSetpoint);
|
|
pinB->setLedLevel(bSetpoint);
|
|
Serial.printf("Set RGB: R=%d, G=%d, B=%d\n", r, g, b);
|
|
}
|
|
|
|
void Light::subscribeToMqttTopics() {
|
|
mqttClient->subscribe(lightInfo.commandTopic, [this](uint8_t* payload, int length) {
|
|
std::string command(reinterpret_cast<char*>(payload), length);
|
|
handleCommand(command);
|
|
});
|
|
}
|
|
|
|
void Light::handleCommand(const std::string& command) {
|
|
Serial.println("Received command: " + String(command.c_str()));
|
|
JsonDocument commandJson;
|
|
deserializeJson(commandJson, command);
|
|
if (commandJson.isNull()) {
|
|
Serial.println("Invalid command JSON");
|
|
return;
|
|
}
|
|
if (commandJson["state"].is<String>()) {
|
|
std::string state = commandJson["state"].as<std::string>();
|
|
if (state == "ON") {
|
|
isOn = true;
|
|
} else if (state == "OFF") {
|
|
isOn = false;
|
|
}
|
|
}
|
|
if (commandJson["brightness"].is<int>()) {
|
|
brightness = commandJson["brightness"].as<int>();
|
|
}
|
|
if (commandJson["color"].is<JsonObject>()) {
|
|
JsonObject color = commandJson["color"];
|
|
r = color["r"] | 255; // Default to 255 if not provided
|
|
g = color["g"] | 255; // Default to 255 if not provided
|
|
b = color["b"] | 255; // Default to 255 if not provided
|
|
}
|
|
if (lightType == LightType::rgb)
|
|
{
|
|
operatePin();
|
|
}
|
|
publishCurrentState();
|
|
}
|
|
|
|
void Light::turnOn() {
|
|
isOn = true;
|
|
if (pinR != nullptr) pinR->setLedLevel(r);
|
|
if (pinG != nullptr) pinG->setLedLevel(g);
|
|
if (pinB != nullptr) pinB->setLedLevel(b);
|
|
if (pinCW != nullptr) pinCW->setLedLevel(cw);
|
|
if (pinWW != nullptr) pinWW->setLedLevel(ww);
|
|
}
|
|
|
|
void Light::turnOff() {
|
|
isOn = false;
|
|
if (pinR != nullptr) pinR->setLedLevel(0);
|
|
if (pinG != nullptr) pinG->setLedLevel(0);
|
|
if (pinB != nullptr) pinB->setLedLevel(0);
|
|
if (pinCW != nullptr) pinCW->setLedLevel(0);
|
|
if (pinWW != nullptr) pinWW->setLedLevel(0);
|
|
}
|
|
|
|
void Light::publishCurrentState() {
|
|
// Publish the current state of the light
|
|
JsonDocument stateInfo;
|
|
stateInfo["state"] = isOn ? "ON" : "OFF";
|
|
stateInfo["availability"] = Availability.available; // Current availability
|
|
stateInfo["brightness"] = brightness;
|
|
if (lightType == LightType::rgb || lightType == LightType::rgbw || lightType == LightType::rgbww) {
|
|
JsonObject rgbValue = stateInfo["color"].to<JsonObject>();
|
|
rgbValue["r"] = r;
|
|
rgbValue["g"] = g;
|
|
rgbValue["b"] = b;
|
|
if (lightType == LightType::rgb) {
|
|
stateInfo["color_mode"] = "rgb";
|
|
}
|
|
if (lightType == LightType::rgbw) {
|
|
stateInfo["color_mode"] = "rgbw";
|
|
rgbValue["w"] = ww;
|
|
} else if (lightType == LightType::rgbww) {
|
|
stateInfo["color_mode"] = "rgbww";
|
|
rgbValue["cw"] = cw;
|
|
rgbValue["ww"] = ww;
|
|
}
|
|
}
|
|
|
|
std::string stateJson;
|
|
serializeJson(stateInfo, stateJson);
|
|
Serial.println("Publishing current state: " + String(stateJson.c_str()));
|
|
mqttClient->publish(lightInfo.stateTopic, stateJson);
|
|
} |