ESP RGBWW Controller - Firmware v5

Begonnen von pjakobs, 01 Januar 2025, 21:14:31

Vorheriges Thema - Nächstes Thema

pjakobs

primär versteht Home Assistant wohl RGB für Leuchten, nicht HSV, und bei dieser Firmware ist einer der Vorteile ja, dass die HSV->RGB(WW/CW) Wandlung gut gelöst ist.
Home Assistant unterstützt auch ein hs_color Modell, bei dem man dann zusätzlich einen v Wert setzen muss.
Das macht's ein bisschen komplizierter, aber möglich.

Das API ist halt die andere Frage: will ich mich wie eine der erwarteten Leuchten verhalten (also die entsprechenden get/set Topics bieten plus die auto-detection Topics) oder will ich mich wie etwas anderes verhalten (also wie hue etwa) - ich hab mir beides angesehen, ich glaube, die mqtt implementation ist einfacher.

Ein Modul für Home Assistant möchte ich eher nicht schreiben, wie gesagt, meine Erfahrung mit der Community war nicht überwältigend.

https://www.home-assistant.io/integrations/light/

vbs

Ja, HA kennt wohl hue/saturation und auch brightness (verstehe ich so). Ich hoffe, damit würde man was hinbekommen. HSV muss auf jeden Fall sein.

Zitat von: pjakobs am 08 September 2025, 13:45:43Das API ist halt die andere Frage: will ich mich wie eine der erwarteten Leuchten verhalten (also die entsprechenden get/set Topics bieten plus die auto-detection Topics) oder will ich mich wie etwas anderes verhalten (also wie hue etwa) - ich hab mir beides angesehen, ich glaube, die mqtt implementation ist einfacher.
Ich hab das noch nicht so ganz verstanden, fürchte ich: Also du würdest die Controller per MQTT an HA anbinden wollen, ja? Aber mit welchem Modul/Integration dann steuern? Man will ja dann als User nicht HA selbst LowLevel-MQTT-Nachrichten bauen, um die Controller zu steuern, oder?

pjakobs

Ich hab mich da nur mal reingelesen und es nicht getestet, aber wenn ich Home Assistant richtig verstehe, dann bringt es ein mqtt-light Modul mit (https://www.home-assistant.io/integrations/light.mqtt/) das relativ flexibel Lichter ansprechen kann - allerdings nicht, wie es die rgbww firmware macht, mit rpc messages, sondern mit state messages.
Ich hab ein paar experimentelle Sachen im mqtthandler in HAIntegration Branch, da fehlt aber noch einiges.

ich glaube, das sind max zwei Tage Arbeit, wenn man ein funktionierendes Home Assistant hat.

void AppMqttClient::initHomeAssistant() {
    AppConfig::Network network(*app.cfg);
    _haEnabled = network.mqtt.homeassistant.getEnable();
   
    if (!_haEnabled) {
        return;
    }
   
    _haDiscoveryPrefix = network.mqtt.homeassistant.getDiscoveryPrefix();
    _haNodeId = network.mqtt.homeassistant.getNodeId();
   
    // If node_id is empty, use the device ID
    if (_haNodeId.length() == 0) {
        _haNodeId = _id;
    }
   
    // Subscribe to the HA command topic
    if (mqtt && mqtt->getConnectionState() == TcpClientState::eTCS_Connected) {
        mqtt->subscribe(buildHATopic("light", _haNodeId, "set"));
    }
}

void AppMqttClient::publishHomeAssistantConfig() {
    if (!_haEnabled || _haConfigPublished) {
        return;
    }
   
    AppConfig::General general(*app.cfg);
    String deviceName = general.getDeviceName();
   
    // Create config document
    StaticJsonDocument<512> doc;
   
    // Basic configuration
    doc["name"] = deviceName;
    doc["unique_id"] = _haNodeId;
    doc["state_topic"] = buildHATopic("light", _haNodeId, "state");
    doc["command_topic"] = buildHATopic("light", _haNodeId, "set");
    doc["schema"] = "json";
   
    // Light features
    doc["brightness"] = true;
    doc["brightness_scale"] = 255;  // Standard HA scale
    doc["color_mode"] = true;
    doc["supported_color_modes"] = JsonArray().add("hs");
   
    // Optimization
    doc["optimistic"] = false;
    doc["retain"] = true;
   
    // Device info
    JsonObject device = doc.createNestedObject("device");
    device["identifiers"] = JsonArray().add(_id);
    device["name"] = deviceName;
    device["model"] = "RGBWW Controller";
    device["manufacturer"] = "ESP RGBWW Firmware";
    device["sw_version"] = GITVERSION;
   
    // Publish discovery message
    String configTopic = _haDiscoveryPrefix + "/light/" + _haNodeId + "/config";
    publish(configTopic, Json::serialize(doc), true);
   
    _haConfigPublished = true;
   
    // Publish initial state
    publishCurrentHsv(app.rgbwwctrl.getCurrentColor());
}

String AppMqttClient::buildHATopic(const String& component, const String& entityId, const String& suffix) {
    return component + "/" + entityId + "/" + suffix;
}

void AppMqttClient::publishHAState(const ChannelOutput& raw, const HSVCT* pHsv) {
    if (!_haEnabled) {
        return;
    }
   
    StaticJsonDocument<256> doc;
   
    // Get HSV values
    HSVCT color = pHsv ? *pHsv : app.rgbwwctrl.getCurrentColor();
    float h, s, v;
    int ct;
    color.asRadian(h, s, v, ct);
   
    // Convert to HA format
    doc["state"] = v > 0 ? "ON" : "OFF";
    doc["brightness"] = (uint8_t)(v * 2.55f);  // Scale 0-100 to 0-255
   
    // Only include color if light is on
    if (v > 0) {
        JsonObject color_obj = doc.createNestedObject("color");
        color_obj["h"] = h;
        color_obj["s"] = s * 100;  // HA expects 0-100%
    }
   
    publish(buildHATopic("light", _haNodeId, "state"), Json::serialize(doc), true);
}

void AppMqttClient::handleHomeAssistantCommand(const String& message) {
    if (!_haEnabled) {
        return;
    }
   
    StaticJsonDocument<256> doc;
    deserializeJson(doc, message);
   
    String state = doc["state"];
   
    // Create a JSON command that works with your existing system
    StaticJsonDocument<256> cmdDoc;
    JsonObject root = cmdDoc.to<JsonObject>();
    JsonObject hsv = root.createNestedObject("hsv");
   
    if (state == "ON") {
        // Handle brightness
        float brightness = 100.0f;  // Default to 100%
        if (doc.containsKey("brightness")) {
            brightness = (doc["brightness"].as<float>() / 255.0f) * 100.0f;  // Convert 0-255 to 0-100
        }
       
        // Handle color
        if (doc.containsKey("color")) {
            hsv["h"] = doc["color"]["h"];
            hsv["s"] = doc["color"]["s"];
            hsv["v"] = brightness;
        } else {
            // Just brightness change
            hsv["v"] = brightness;
        }
    } else {
        // Turn off
        hsv["v"] = 0;
    }
   
    root["cmd"] = "fade";
    root["t"] = 500;  // 500ms transition
   
    // Process the command through your existing system
    String error;
    app.jsonproc.onColor(Json::serialize(root), error, false);
}

vbs

Ach, das ist interessant, danke.

Es gibt ja auch "command templates", wo man offenbar sich template-basiert MQTT-Befehlsnachrichten zusammenbauen kann:
https://www.home-assistant.io/docs/configuration/templating/#using-command-templates-with-mqtt

Kriegt man damit vielleicht sogar eine Steuerung hin, ohne Anpassung der aktuelle Controller-FW?

pjakobs

hatte ich mir angesehen, schien mir aber unnötig kompliziert.

pjakobs

ach so, grundsätzlich bietet Sming auch noch eine Hue Bridge Library mit. Ich überlege noch, ob ich die auch noch mit einbaue, aber das ist eher langfristig.

vbs

Wenn man die Standard-MQTT-light-Sachen benutzt, könnte man dann trotzdem die Custom-Funktionen des Controllers wie konfigurierbare Animationen nutzen?

pjakobs

das json format definiert einen "effect" und das Gerät kann auch eine Liste der Effekte liefern. Damit könnte man vermutlich was anfangen:

https://www.home-assistant.io/integrations/light.mqtt/#json-schema

vbs

Ja, das hab ich mir auch angesehen, aber ich würde sagen, damit kriegt man nur die "trivialen" Kommandos wie "pause" und "stop" abgedeckt, wenn man die dann als Effekt bezeichnen will (die dann sofort enden). Hätte aber erstmal keine Idee, wie/ob man damit komplexere Animationen abbilden könnte.

pjakobs

ich hab ja im UI die Möglichkeit, komplexere Animationen zu definieren und auf dem Controller zu speichern. Im Moment werden die nur vom Frontend ausgewertet, aber im Grunde könnte ich die auch direkt auf dem Controller "abspielen" - die liegen einfach als json String in der ConfigDB. Über das mqtt interface könnte man HomeAssistant die Namen liefern und dann lokal abspielen.
Ich müsste mir allerdings überlegen, wie ich mit Animationen für Gruppen umgehe - im Grunde könnte ein Controller auch einem anderen Kommandos schicken - dann idealerweise über websocket