[light] Accept the top-level white key from Home Assistant's MQTT JSO… (#19570)

This commit is contained in:
Ryan Ronnander
2026-09-24 13:11:40 +00:00
committed by GitHub
parent cbd985826c
commit fed5dd6a9d
3 changed files with 92 additions and 0 deletions
@@ -131,6 +131,13 @@ void LightJSONSchema::parse_color_json(LightState &state, LightCall &call, JsonO
call.set_white(float(root[ESPHOME_F("white_value")]) / 255.0f);
}
if (root[ESPHOME_F("white")].is<uint8_t>()) {
// White stays full because ESPHome multiplies brightness and white
call.set_color_mode_if_supported(ColorMode::WHITE);
call.set_brightness(float(root[ESPHOME_F("white")]) / 255.0f);
call.set_white(1.0f);
}
if (root[ESPHOME_F("color_temp")].is<uint16_t>()) {
call.set_color_temperature(float(root[ESPHOME_F("color_temp")]));
}
+11
View File
@@ -0,0 +1,11 @@
import esphome.codegen as cg
from tests.testing_helpers import ComponentManifestOverride
def override_manifest(manifest: ComponentManifestOverride) -> None:
# Enables light_json_schema.cpp without USE_MQTT, which pulls mqtt code into core/util.cpp
async def to_code_testing(config):
cg.add_define("USE_WEBSERVER")
manifest.to_code = to_code_testing
manifest.dependencies = manifest.dependencies + ["json"]
@@ -0,0 +1,74 @@
#include <gtest/gtest.h>
#include "esphome/components/json/json_util.h"
#include "esphome/components/light/light_call.h"
#include "esphome/components/light/light_json_schema.h"
#include "esphome/components/light/light_output.h"
#include "esphome/components/light/light_state.h"
namespace esphome::light::testing {
namespace {
// An `rgbw` light with `color_interlock: true`
class InterlockedRgbwOutput : public LightOutput {
public:
LightTraits get_traits() override {
LightTraits traits;
traits.set_supported_color_modes({ColorMode::RGB, ColorMode::WHITE});
return traits;
}
void write_state(LightState *state) override {}
};
class TestableLightCall : public LightCall {
public:
using LightCall::LightCall;
using LightCall::validate_;
};
LightColorValues parse(LightState &state, const char *payload) {
TestableLightCall call(&state);
json::parse_json(payload, [&](JsonObject root) {
LightJSONSchema::parse_json(state, call, root);
return true;
});
return call.validate_();
}
} // namespace
// HA's MQTT JSON schema selects the white color mode with a top-level `white` key
TEST(LightJSONSchema, TopLevelWhiteSelectsWhiteMode) {
InterlockedRgbwOutput output;
LightState state(&output);
state.remote_values.set_color_mode(ColorMode::RGB);
auto values = parse(state, R"({"state":"ON","white":128})");
EXPECT_EQ(values.get_color_mode(), ColorMode::WHITE);
EXPECT_FLOAT_EQ(values.get_brightness(), 128.0f / 255.0f);
EXPECT_FLOAT_EQ(values.get_white(), 1.0f);
}
TEST(LightJSONSchema, TopLevelWhiteOverridesBrightness) {
InterlockedRgbwOutput output;
LightState state(&output);
auto values = parse(state, R"({"state":"ON","brightness":255,"white":128})");
EXPECT_EQ(values.get_color_mode(), ColorMode::WHITE);
EXPECT_FLOAT_EQ(values.get_brightness(), 128.0f / 255.0f);
}
TEST(LightJSONSchema, ColorWStillSetsWhite) {
InterlockedRgbwOutput output;
LightState state(&output);
auto values = parse(state, R"({"state":"ON","color":{"w":255}})");
EXPECT_EQ(values.get_color_mode(), ColorMode::WHITE);
EXPECT_FLOAT_EQ(values.get_white(), 1.0f);
}
} // namespace esphome::light::testing