[core] Add PROGMEM macros and move web_server JSON keys to flash (#12214)
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
#include "light_json_schema.h"
|
||||
#include "light_output.h"
|
||||
#include "esphome/core/progmem.h"
|
||||
|
||||
#ifdef USE_JSON
|
||||
|
||||
@@ -35,9 +36,9 @@ static const char *get_color_mode_json_str(ColorMode mode) {
|
||||
void LightJSONSchema::dump_json(LightState &state, JsonObject root) {
|
||||
// NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks) false positive with ArduinoJson
|
||||
if (state.supports_effects()) {
|
||||
root["effect"] = state.get_effect_name();
|
||||
root["effect_index"] = state.get_current_effect_index();
|
||||
root["effect_count"] = state.get_effect_count();
|
||||
root[ESPHOME_F("effect")] = state.get_effect_name();
|
||||
root[ESPHOME_F("effect_index")] = state.get_current_effect_index();
|
||||
root[ESPHOME_F("effect_count")] = state.get_effect_count();
|
||||
}
|
||||
|
||||
auto values = state.remote_values;
|
||||
@@ -45,39 +46,39 @@ void LightJSONSchema::dump_json(LightState &state, JsonObject root) {
|
||||
const auto color_mode = values.get_color_mode();
|
||||
const char *mode_str = get_color_mode_json_str(color_mode);
|
||||
if (mode_str != nullptr) {
|
||||
root["color_mode"] = mode_str;
|
||||
root[ESPHOME_F("color_mode")] = mode_str;
|
||||
}
|
||||
|
||||
if (color_mode & ColorCapability::ON_OFF)
|
||||
root["state"] = (values.get_state() != 0.0f) ? "ON" : "OFF";
|
||||
root[ESPHOME_F("state")] = (values.get_state() != 0.0f) ? "ON" : "OFF";
|
||||
if (color_mode & ColorCapability::BRIGHTNESS)
|
||||
root["brightness"] = to_uint8_scale(values.get_brightness());
|
||||
root[ESPHOME_F("brightness")] = to_uint8_scale(values.get_brightness());
|
||||
|
||||
JsonObject color = root["color"].to<JsonObject>();
|
||||
JsonObject color = root[ESPHOME_F("color")].to<JsonObject>();
|
||||
if (color_mode & ColorCapability::RGB) {
|
||||
float color_brightness = values.get_color_brightness();
|
||||
color["r"] = to_uint8_scale(color_brightness * values.get_red());
|
||||
color["g"] = to_uint8_scale(color_brightness * values.get_green());
|
||||
color["b"] = to_uint8_scale(color_brightness * values.get_blue());
|
||||
color[ESPHOME_F("r")] = to_uint8_scale(color_brightness * values.get_red());
|
||||
color[ESPHOME_F("g")] = to_uint8_scale(color_brightness * values.get_green());
|
||||
color[ESPHOME_F("b")] = to_uint8_scale(color_brightness * values.get_blue());
|
||||
}
|
||||
if (color_mode & ColorCapability::WHITE) {
|
||||
uint8_t white_val = to_uint8_scale(values.get_white());
|
||||
color["w"] = white_val;
|
||||
root["white_value"] = white_val; // legacy API
|
||||
color[ESPHOME_F("w")] = white_val;
|
||||
root[ESPHOME_F("white_value")] = white_val; // legacy API
|
||||
}
|
||||
if (color_mode & ColorCapability::COLOR_TEMPERATURE) {
|
||||
// this one isn't under the color subkey for some reason
|
||||
root["color_temp"] = uint32_t(values.get_color_temperature());
|
||||
root[ESPHOME_F("color_temp")] = uint32_t(values.get_color_temperature());
|
||||
}
|
||||
if (color_mode & ColorCapability::COLD_WARM_WHITE) {
|
||||
color["c"] = to_uint8_scale(values.get_cold_white());
|
||||
color["w"] = to_uint8_scale(values.get_warm_white());
|
||||
color[ESPHOME_F("c")] = to_uint8_scale(values.get_cold_white());
|
||||
color[ESPHOME_F("w")] = to_uint8_scale(values.get_warm_white());
|
||||
}
|
||||
}
|
||||
|
||||
void LightJSONSchema::parse_color_json(LightState &state, LightCall &call, JsonObject root) {
|
||||
if (root["state"].is<const char *>()) {
|
||||
auto val = parse_on_off(root["state"]);
|
||||
if (root[ESPHOME_F("state")].is<const char *>()) {
|
||||
auto val = parse_on_off(root[ESPHOME_F("state")]);
|
||||
switch (val) {
|
||||
case PARSE_ON:
|
||||
call.set_state(true);
|
||||
@@ -93,76 +94,77 @@ void LightJSONSchema::parse_color_json(LightState &state, LightCall &call, JsonO
|
||||
}
|
||||
}
|
||||
|
||||
if (root["brightness"].is<uint8_t>()) {
|
||||
call.set_brightness(float(root["brightness"]) / 255.0f);
|
||||
if (root[ESPHOME_F("brightness")].is<uint8_t>()) {
|
||||
call.set_brightness(float(root[ESPHOME_F("brightness")]) / 255.0f);
|
||||
}
|
||||
|
||||
if (root["color"].is<JsonObject>()) {
|
||||
JsonObject color = root["color"];
|
||||
if (root[ESPHOME_F("color")].is<JsonObject>()) {
|
||||
JsonObject color = root[ESPHOME_F("color")];
|
||||
// HA also encodes brightness information in the r, g, b values, so extract that and set it as color brightness.
|
||||
float max_rgb = 0.0f;
|
||||
if (color["r"].is<uint8_t>()) {
|
||||
float r = float(color["r"]) / 255.0f;
|
||||
if (color[ESPHOME_F("r")].is<uint8_t>()) {
|
||||
float r = float(color[ESPHOME_F("r")]) / 255.0f;
|
||||
max_rgb = fmaxf(max_rgb, r);
|
||||
call.set_red(r);
|
||||
}
|
||||
if (color["g"].is<uint8_t>()) {
|
||||
float g = float(color["g"]) / 255.0f;
|
||||
if (color[ESPHOME_F("g")].is<uint8_t>()) {
|
||||
float g = float(color[ESPHOME_F("g")]) / 255.0f;
|
||||
max_rgb = fmaxf(max_rgb, g);
|
||||
call.set_green(g);
|
||||
}
|
||||
if (color["b"].is<uint8_t>()) {
|
||||
float b = float(color["b"]) / 255.0f;
|
||||
if (color[ESPHOME_F("b")].is<uint8_t>()) {
|
||||
float b = float(color[ESPHOME_F("b")]) / 255.0f;
|
||||
max_rgb = fmaxf(max_rgb, b);
|
||||
call.set_blue(b);
|
||||
}
|
||||
if (color["r"].is<uint8_t>() || color["g"].is<uint8_t>() || color["b"].is<uint8_t>()) {
|
||||
if (color[ESPHOME_F("r")].is<uint8_t>() || color[ESPHOME_F("g")].is<uint8_t>() ||
|
||||
color[ESPHOME_F("b")].is<uint8_t>()) {
|
||||
call.set_color_brightness(max_rgb);
|
||||
}
|
||||
|
||||
if (color["c"].is<uint8_t>()) {
|
||||
call.set_cold_white(float(color["c"]) / 255.0f);
|
||||
if (color[ESPHOME_F("c")].is<uint8_t>()) {
|
||||
call.set_cold_white(float(color[ESPHOME_F("c")]) / 255.0f);
|
||||
}
|
||||
if (color["w"].is<uint8_t>()) {
|
||||
if (color[ESPHOME_F("w")].is<uint8_t>()) {
|
||||
// the HA scheme is ambiguous here, the same key is used for white channel in RGBW and warm
|
||||
// white channel in RGBWW.
|
||||
if (color["c"].is<uint8_t>()) {
|
||||
call.set_warm_white(float(color["w"]) / 255.0f);
|
||||
if (color[ESPHOME_F("c")].is<uint8_t>()) {
|
||||
call.set_warm_white(float(color[ESPHOME_F("w")]) / 255.0f);
|
||||
} else {
|
||||
call.set_white(float(color["w"]) / 255.0f);
|
||||
call.set_white(float(color[ESPHOME_F("w")]) / 255.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (root["white_value"].is<uint8_t>()) { // legacy API
|
||||
call.set_white(float(root["white_value"]) / 255.0f);
|
||||
if (root[ESPHOME_F("white_value")].is<uint8_t>()) { // legacy API
|
||||
call.set_white(float(root[ESPHOME_F("white_value")]) / 255.0f);
|
||||
}
|
||||
|
||||
if (root["color_temp"].is<uint16_t>()) {
|
||||
call.set_color_temperature(float(root["color_temp"]));
|
||||
if (root[ESPHOME_F("color_temp")].is<uint16_t>()) {
|
||||
call.set_color_temperature(float(root[ESPHOME_F("color_temp")]));
|
||||
}
|
||||
}
|
||||
|
||||
void LightJSONSchema::parse_json(LightState &state, LightCall &call, JsonObject root) {
|
||||
LightJSONSchema::parse_color_json(state, call, root);
|
||||
|
||||
if (root["flash"].is<uint32_t>()) {
|
||||
auto length = uint32_t(float(root["flash"]) * 1000);
|
||||
if (root[ESPHOME_F("flash")].is<uint32_t>()) {
|
||||
auto length = uint32_t(float(root[ESPHOME_F("flash")]) * 1000);
|
||||
call.set_flash_length(length);
|
||||
}
|
||||
|
||||
if (root["transition"].is<uint16_t>()) {
|
||||
auto length = uint32_t(float(root["transition"]) * 1000);
|
||||
if (root[ESPHOME_F("transition")].is<uint16_t>()) {
|
||||
auto length = uint32_t(float(root[ESPHOME_F("transition")]) * 1000);
|
||||
call.set_transition_length(length);
|
||||
}
|
||||
|
||||
if (root["effect"].is<const char *>()) {
|
||||
const char *effect = root["effect"];
|
||||
if (root[ESPHOME_F("effect")].is<const char *>()) {
|
||||
const char *effect = root[ESPHOME_F("effect")];
|
||||
call.set_effect(effect);
|
||||
}
|
||||
|
||||
if (root["effect_index"].is<uint32_t>()) {
|
||||
uint32_t effect_index = root["effect_index"];
|
||||
if (root[ESPHOME_F("effect_index")].is<uint32_t>()) {
|
||||
uint32_t effect_index = root[ESPHOME_F("effect_index")];
|
||||
call.set_effect(effect_index);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -244,8 +244,8 @@ void DeferredUpdateEventSourceList::on_client_connect_(DeferredUpdateEventSource
|
||||
for (auto &group : ws->sorting_groups_) {
|
||||
json::JsonBuilder builder;
|
||||
JsonObject root = builder.root();
|
||||
root["name"] = group.second.name;
|
||||
root["sorting_weight"] = group.second.weight;
|
||||
root[ESPHOME_F("name")] = group.second.name;
|
||||
root[ESPHOME_F("sorting_weight")] = group.second.weight;
|
||||
message = builder.serialize();
|
||||
|
||||
// up to 31 groups should be able to be queued initially without defer
|
||||
@@ -286,15 +286,15 @@ std::string WebServer::get_config_json() {
|
||||
json::JsonBuilder builder;
|
||||
JsonObject root = builder.root();
|
||||
|
||||
root["title"] = App.get_friendly_name().empty() ? App.get_name() : App.get_friendly_name();
|
||||
root["comment"] = App.get_comment();
|
||||
root[ESPHOME_F("title")] = App.get_friendly_name().empty() ? App.get_name() : App.get_friendly_name();
|
||||
root[ESPHOME_F("comment")] = App.get_comment();
|
||||
#if defined(USE_WEBSERVER_OTA_DISABLED) || !defined(USE_WEBSERVER_OTA)
|
||||
root["ota"] = false; // Note: USE_WEBSERVER_OTA_DISABLED only affects web_server, not captive_portal
|
||||
root[ESPHOME_F("ota")] = false; // Note: USE_WEBSERVER_OTA_DISABLED only affects web_server, not captive_portal
|
||||
#else
|
||||
root["ota"] = true;
|
||||
root[ESPHOME_F("ota")] = true;
|
||||
#endif
|
||||
root["log"] = this->expose_log_;
|
||||
root["lang"] = "en";
|
||||
root[ESPHOME_F("log")] = this->expose_log_;
|
||||
root[ESPHOME_F("lang")] = "en";
|
||||
|
||||
return builder.serialize();
|
||||
}
|
||||
@@ -407,14 +407,14 @@ static void set_json_id(JsonObject &root, EntityBase *obj, const char *prefix, J
|
||||
char id_buf[160]; // object_id can be up to 128 chars + prefix + dash + null
|
||||
const auto &object_id = obj->get_object_id();
|
||||
snprintf(id_buf, sizeof(id_buf), "%s-%s", prefix, object_id.c_str());
|
||||
root["id"] = id_buf;
|
||||
root[ESPHOME_F("id")] = id_buf;
|
||||
if (start_config == DETAIL_ALL) {
|
||||
root["name"] = obj->get_name();
|
||||
root["icon"] = obj->get_icon_ref();
|
||||
root["entity_category"] = obj->get_entity_category();
|
||||
root[ESPHOME_F("name")] = obj->get_name();
|
||||
root[ESPHOME_F("icon")] = obj->get_icon_ref();
|
||||
root[ESPHOME_F("entity_category")] = obj->get_entity_category();
|
||||
bool is_disabled = obj->is_disabled_by_default();
|
||||
if (is_disabled)
|
||||
root["is_disabled_by_default"] = is_disabled;
|
||||
root[ESPHOME_F("is_disabled_by_default")] = is_disabled;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -424,14 +424,14 @@ template<typename T>
|
||||
static void set_json_value(JsonObject &root, EntityBase *obj, const char *prefix, const T &value,
|
||||
JsonDetail start_config) {
|
||||
set_json_id(root, obj, prefix, start_config);
|
||||
root["value"] = value;
|
||||
root[ESPHOME_F("value")] = value;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static void set_json_icon_state_value(JsonObject &root, EntityBase *obj, const char *prefix, const std::string &state,
|
||||
const T &value, JsonDetail start_config) {
|
||||
set_json_value(root, obj, prefix, value, start_config);
|
||||
root["state"] = state;
|
||||
root[ESPHOME_F("state")] = state;
|
||||
}
|
||||
|
||||
// Helper to get request detail parameter
|
||||
@@ -478,7 +478,7 @@ std::string WebServer::sensor_json(sensor::Sensor *obj, float value, JsonDetail
|
||||
if (start_config == DETAIL_ALL) {
|
||||
this->add_sorting_info_(root, obj);
|
||||
if (!uom_ref.empty())
|
||||
root["uom"] = uom_ref;
|
||||
root[ESPHOME_F("uom")] = uom_ref;
|
||||
}
|
||||
|
||||
return builder.serialize();
|
||||
@@ -593,7 +593,7 @@ std::string WebServer::switch_json(switch_::Switch *obj, bool value, JsonDetail
|
||||
|
||||
set_json_icon_state_value(root, obj, "switch", value ? "ON" : "OFF", value, start_config);
|
||||
if (start_config == DETAIL_ALL) {
|
||||
root["assumed_state"] = obj->assumed_state();
|
||||
root[ESPHOME_F("assumed_state")] = obj->assumed_state();
|
||||
this->add_sorting_info_(root, obj);
|
||||
}
|
||||
|
||||
@@ -748,11 +748,11 @@ std::string WebServer::fan_json(fan::Fan *obj, JsonDetail start_config) {
|
||||
set_json_icon_state_value(root, obj, "fan", obj->state ? "ON" : "OFF", obj->state, start_config);
|
||||
const auto traits = obj->get_traits();
|
||||
if (traits.supports_speed()) {
|
||||
root["speed_level"] = obj->speed;
|
||||
root["speed_count"] = traits.supported_speed_count();
|
||||
root[ESPHOME_F("speed_level")] = obj->speed;
|
||||
root[ESPHOME_F("speed_count")] = traits.supported_speed_count();
|
||||
}
|
||||
if (obj->get_traits().supports_oscillation())
|
||||
root["oscillation"] = obj->oscillating;
|
||||
root[ESPHOME_F("oscillation")] = obj->oscillating;
|
||||
if (start_config == DETAIL_ALL) {
|
||||
this->add_sorting_info_(root, obj);
|
||||
}
|
||||
@@ -827,7 +827,7 @@ std::string WebServer::light_json(light::LightState *obj, JsonDetail start_confi
|
||||
|
||||
light::LightJSONSchema::dump_json(*obj, root);
|
||||
if (start_config == DETAIL_ALL) {
|
||||
JsonArray opt = root["effects"].to<JsonArray>();
|
||||
JsonArray opt = root[ESPHOME_F("effects")].to<JsonArray>();
|
||||
opt.add("None");
|
||||
for (auto const &option : obj->get_effects()) {
|
||||
opt.add(option->get_name());
|
||||
@@ -913,12 +913,12 @@ std::string WebServer::cover_json(cover::Cover *obj, JsonDetail start_config) {
|
||||
set_json_icon_state_value(root, obj, "cover", obj->is_fully_closed() ? "CLOSED" : "OPEN", obj->position,
|
||||
start_config);
|
||||
char buf[PSTR_LOCAL_SIZE];
|
||||
root["current_operation"] = PSTR_LOCAL(cover::cover_operation_to_str(obj->current_operation));
|
||||
root[ESPHOME_F("current_operation")] = PSTR_LOCAL(cover::cover_operation_to_str(obj->current_operation));
|
||||
|
||||
if (obj->get_traits().get_supports_position())
|
||||
root["position"] = obj->position;
|
||||
root[ESPHOME_F("position")] = obj->position;
|
||||
if (obj->get_traits().get_supports_tilt())
|
||||
root["tilt"] = obj->tilt;
|
||||
root[ESPHOME_F("tilt")] = obj->tilt;
|
||||
if (start_config == DETAIL_ALL) {
|
||||
this->add_sorting_info_(root, obj);
|
||||
}
|
||||
@@ -979,14 +979,15 @@ std::string WebServer::number_json(number::Number *obj, float value, JsonDetail
|
||||
value, step_to_accuracy_decimals(obj->traits.get_step()), uom_ref);
|
||||
set_json_icon_state_value(root, obj, "number", state_str, val_str, start_config);
|
||||
if (start_config == DETAIL_ALL) {
|
||||
root["min_value"] =
|
||||
root[ESPHOME_F("min_value")] =
|
||||
value_accuracy_to_string(obj->traits.get_min_value(), step_to_accuracy_decimals(obj->traits.get_step()));
|
||||
root["max_value"] =
|
||||
root[ESPHOME_F("max_value")] =
|
||||
value_accuracy_to_string(obj->traits.get_max_value(), step_to_accuracy_decimals(obj->traits.get_step()));
|
||||
root["step"] = value_accuracy_to_string(obj->traits.get_step(), step_to_accuracy_decimals(obj->traits.get_step()));
|
||||
root["mode"] = (int) obj->traits.get_mode();
|
||||
root[ESPHOME_F("step")] =
|
||||
value_accuracy_to_string(obj->traits.get_step(), step_to_accuracy_decimals(obj->traits.get_step()));
|
||||
root[ESPHOME_F("mode")] = (int) obj->traits.get_mode();
|
||||
if (!uom_ref.empty())
|
||||
root["uom"] = uom_ref;
|
||||
root[ESPHOME_F("uom")] = uom_ref;
|
||||
this->add_sorting_info_(root, obj);
|
||||
}
|
||||
|
||||
@@ -1208,11 +1209,11 @@ std::string WebServer::text_json(text::Text *obj, const std::string &value, Json
|
||||
|
||||
std::string state = obj->traits.get_mode() == text::TextMode::TEXT_MODE_PASSWORD ? "********" : value;
|
||||
set_json_icon_state_value(root, obj, "text", state, value, start_config);
|
||||
root["min_length"] = obj->traits.get_min_length();
|
||||
root["max_length"] = obj->traits.get_max_length();
|
||||
root["pattern"] = obj->traits.get_pattern();
|
||||
root[ESPHOME_F("min_length")] = obj->traits.get_min_length();
|
||||
root[ESPHOME_F("max_length")] = obj->traits.get_max_length();
|
||||
root[ESPHOME_F("pattern")] = obj->traits.get_pattern();
|
||||
if (start_config == DETAIL_ALL) {
|
||||
root["mode"] = (int) obj->traits.get_mode();
|
||||
root[ESPHOME_F("mode")] = (int) obj->traits.get_mode();
|
||||
this->add_sorting_info_(root, obj);
|
||||
}
|
||||
|
||||
@@ -1266,7 +1267,7 @@ std::string WebServer::select_json(select::Select *obj, const char *value, JsonD
|
||||
|
||||
set_json_icon_state_value(root, obj, "select", value, value, start_config);
|
||||
if (start_config == DETAIL_ALL) {
|
||||
JsonArray opt = root["option"].to<JsonArray>();
|
||||
JsonArray opt = root[ESPHOME_F("option")].to<JsonArray>();
|
||||
for (auto &option : obj->traits.get_options()) {
|
||||
opt.add(option);
|
||||
}
|
||||
@@ -1337,32 +1338,32 @@ std::string WebServer::climate_json(climate::Climate *obj, JsonDetail start_conf
|
||||
char buf[PSTR_LOCAL_SIZE];
|
||||
|
||||
if (start_config == DETAIL_ALL) {
|
||||
JsonArray opt = root["modes"].to<JsonArray>();
|
||||
JsonArray opt = root[ESPHOME_F("modes")].to<JsonArray>();
|
||||
for (climate::ClimateMode m : traits.get_supported_modes())
|
||||
opt.add(PSTR_LOCAL(climate::climate_mode_to_string(m)));
|
||||
if (!traits.get_supported_custom_fan_modes().empty()) {
|
||||
JsonArray opt = root["fan_modes"].to<JsonArray>();
|
||||
JsonArray opt = root[ESPHOME_F("fan_modes")].to<JsonArray>();
|
||||
for (climate::ClimateFanMode m : traits.get_supported_fan_modes())
|
||||
opt.add(PSTR_LOCAL(climate::climate_fan_mode_to_string(m)));
|
||||
}
|
||||
|
||||
if (!traits.get_supported_custom_fan_modes().empty()) {
|
||||
JsonArray opt = root["custom_fan_modes"].to<JsonArray>();
|
||||
JsonArray opt = root[ESPHOME_F("custom_fan_modes")].to<JsonArray>();
|
||||
for (auto const &custom_fan_mode : traits.get_supported_custom_fan_modes())
|
||||
opt.add(custom_fan_mode);
|
||||
}
|
||||
if (traits.get_supports_swing_modes()) {
|
||||
JsonArray opt = root["swing_modes"].to<JsonArray>();
|
||||
JsonArray opt = root[ESPHOME_F("swing_modes")].to<JsonArray>();
|
||||
for (auto swing_mode : traits.get_supported_swing_modes())
|
||||
opt.add(PSTR_LOCAL(climate::climate_swing_mode_to_string(swing_mode)));
|
||||
}
|
||||
if (traits.get_supports_presets() && obj->preset.has_value()) {
|
||||
JsonArray opt = root["presets"].to<JsonArray>();
|
||||
JsonArray opt = root[ESPHOME_F("presets")].to<JsonArray>();
|
||||
for (climate::ClimatePreset m : traits.get_supported_presets())
|
||||
opt.add(PSTR_LOCAL(climate::climate_preset_to_string(m)));
|
||||
}
|
||||
if (!traits.get_supported_custom_presets().empty() && obj->has_custom_preset()) {
|
||||
JsonArray opt = root["custom_presets"].to<JsonArray>();
|
||||
JsonArray opt = root[ESPHOME_F("custom_presets")].to<JsonArray>();
|
||||
for (auto const &custom_preset : traits.get_supported_custom_presets())
|
||||
opt.add(custom_preset);
|
||||
}
|
||||
@@ -1370,49 +1371,50 @@ std::string WebServer::climate_json(climate::Climate *obj, JsonDetail start_conf
|
||||
}
|
||||
|
||||
bool has_state = false;
|
||||
root["mode"] = PSTR_LOCAL(climate_mode_to_string(obj->mode));
|
||||
root["max_temp"] = value_accuracy_to_string(traits.get_visual_max_temperature(), target_accuracy);
|
||||
root["min_temp"] = value_accuracy_to_string(traits.get_visual_min_temperature(), target_accuracy);
|
||||
root["step"] = traits.get_visual_target_temperature_step();
|
||||
root[ESPHOME_F("mode")] = PSTR_LOCAL(climate_mode_to_string(obj->mode));
|
||||
root[ESPHOME_F("max_temp")] = value_accuracy_to_string(traits.get_visual_max_temperature(), target_accuracy);
|
||||
root[ESPHOME_F("min_temp")] = value_accuracy_to_string(traits.get_visual_min_temperature(), target_accuracy);
|
||||
root[ESPHOME_F("step")] = traits.get_visual_target_temperature_step();
|
||||
if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_ACTION)) {
|
||||
root["action"] = PSTR_LOCAL(climate_action_to_string(obj->action));
|
||||
root["state"] = root["action"];
|
||||
root[ESPHOME_F("action")] = PSTR_LOCAL(climate_action_to_string(obj->action));
|
||||
root[ESPHOME_F("state")] = root[ESPHOME_F("action")];
|
||||
has_state = true;
|
||||
}
|
||||
if (traits.get_supports_fan_modes() && obj->fan_mode.has_value()) {
|
||||
root["fan_mode"] = PSTR_LOCAL(climate_fan_mode_to_string(obj->fan_mode.value()));
|
||||
root[ESPHOME_F("fan_mode")] = PSTR_LOCAL(climate_fan_mode_to_string(obj->fan_mode.value()));
|
||||
}
|
||||
if (!traits.get_supported_custom_fan_modes().empty() && obj->has_custom_fan_mode()) {
|
||||
root["custom_fan_mode"] = obj->get_custom_fan_mode();
|
||||
root[ESPHOME_F("custom_fan_mode")] = obj->get_custom_fan_mode();
|
||||
}
|
||||
if (traits.get_supports_presets() && obj->preset.has_value()) {
|
||||
root["preset"] = PSTR_LOCAL(climate_preset_to_string(obj->preset.value()));
|
||||
root[ESPHOME_F("preset")] = PSTR_LOCAL(climate_preset_to_string(obj->preset.value()));
|
||||
}
|
||||
if (!traits.get_supported_custom_presets().empty() && obj->has_custom_preset()) {
|
||||
root["custom_preset"] = obj->get_custom_preset();
|
||||
root[ESPHOME_F("custom_preset")] = obj->get_custom_preset();
|
||||
}
|
||||
if (traits.get_supports_swing_modes()) {
|
||||
root["swing_mode"] = PSTR_LOCAL(climate_swing_mode_to_string(obj->swing_mode));
|
||||
root[ESPHOME_F("swing_mode")] = PSTR_LOCAL(climate_swing_mode_to_string(obj->swing_mode));
|
||||
}
|
||||
if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_CURRENT_TEMPERATURE)) {
|
||||
if (!std::isnan(obj->current_temperature)) {
|
||||
root["current_temperature"] = value_accuracy_to_string(obj->current_temperature, current_accuracy);
|
||||
root[ESPHOME_F("current_temperature")] = value_accuracy_to_string(obj->current_temperature, current_accuracy);
|
||||
} else {
|
||||
root["current_temperature"] = "NA";
|
||||
root[ESPHOME_F("current_temperature")] = "NA";
|
||||
}
|
||||
}
|
||||
if (traits.has_feature_flags(climate::CLIMATE_SUPPORTS_TWO_POINT_TARGET_TEMPERATURE |
|
||||
climate::CLIMATE_REQUIRES_TWO_POINT_TARGET_TEMPERATURE)) {
|
||||
root["target_temperature_low"] = value_accuracy_to_string(obj->target_temperature_low, target_accuracy);
|
||||
root["target_temperature_high"] = value_accuracy_to_string(obj->target_temperature_high, target_accuracy);
|
||||
root[ESPHOME_F("target_temperature_low")] = value_accuracy_to_string(obj->target_temperature_low, target_accuracy);
|
||||
root[ESPHOME_F("target_temperature_high")] =
|
||||
value_accuracy_to_string(obj->target_temperature_high, target_accuracy);
|
||||
if (!has_state) {
|
||||
root["state"] = value_accuracy_to_string((obj->target_temperature_high + obj->target_temperature_low) / 2.0f,
|
||||
target_accuracy);
|
||||
root[ESPHOME_F("state")] = value_accuracy_to_string(
|
||||
(obj->target_temperature_high + obj->target_temperature_low) / 2.0f, target_accuracy);
|
||||
}
|
||||
} else {
|
||||
root["target_temperature"] = value_accuracy_to_string(obj->target_temperature, target_accuracy);
|
||||
root[ESPHOME_F("target_temperature")] = value_accuracy_to_string(obj->target_temperature, target_accuracy);
|
||||
if (!has_state)
|
||||
root["state"] = root["target_temperature"];
|
||||
root[ESPHOME_F("state")] = root[ESPHOME_F("target_temperature")];
|
||||
}
|
||||
|
||||
return builder.serialize();
|
||||
@@ -1566,10 +1568,10 @@ std::string WebServer::valve_json(valve::Valve *obj, JsonDetail start_config) {
|
||||
set_json_icon_state_value(root, obj, "valve", obj->is_fully_closed() ? "CLOSED" : "OPEN", obj->position,
|
||||
start_config);
|
||||
char buf[PSTR_LOCAL_SIZE];
|
||||
root["current_operation"] = PSTR_LOCAL(valve::valve_operation_to_str(obj->current_operation));
|
||||
root[ESPHOME_F("current_operation")] = PSTR_LOCAL(valve::valve_operation_to_str(obj->current_operation));
|
||||
|
||||
if (obj->get_traits().get_supports_position())
|
||||
root["position"] = obj->position;
|
||||
root[ESPHOME_F("position")] = obj->position;
|
||||
if (start_config == DETAIL_ALL) {
|
||||
this->add_sorting_info_(root, obj);
|
||||
}
|
||||
@@ -1701,14 +1703,14 @@ std::string WebServer::event_json(event::Event *obj, const std::string &event_ty
|
||||
|
||||
set_json_id(root, obj, "event", start_config);
|
||||
if (!event_type.empty()) {
|
||||
root["event_type"] = event_type;
|
||||
root[ESPHOME_F("event_type")] = event_type;
|
||||
}
|
||||
if (start_config == DETAIL_ALL) {
|
||||
JsonArray event_types = root["event_types"].to<JsonArray>();
|
||||
JsonArray event_types = root[ESPHOME_F("event_types")].to<JsonArray>();
|
||||
for (const char *event_type : obj->get_event_types()) {
|
||||
event_types.add(event_type);
|
||||
}
|
||||
root["device_class"] = obj->get_device_class_ref();
|
||||
root[ESPHOME_F("device_class")] = obj->get_device_class_ref();
|
||||
this->add_sorting_info_(root, obj);
|
||||
}
|
||||
|
||||
@@ -1774,10 +1776,10 @@ std::string WebServer::update_json(update::UpdateEntity *obj, JsonDetail start_c
|
||||
set_json_icon_state_value(root, obj, "update", PSTR_LOCAL(update_state_to_string(obj->state)),
|
||||
obj->update_info.latest_version, start_config);
|
||||
if (start_config == DETAIL_ALL) {
|
||||
root["current_version"] = obj->update_info.current_version;
|
||||
root["title"] = obj->update_info.title;
|
||||
root["summary"] = obj->update_info.summary;
|
||||
root["release_url"] = obj->update_info.release_url;
|
||||
root[ESPHOME_F("current_version")] = obj->update_info.current_version;
|
||||
root[ESPHOME_F("title")] = obj->update_info.title;
|
||||
root[ESPHOME_F("summary")] = obj->update_info.summary;
|
||||
root[ESPHOME_F("release_url")] = obj->update_info.release_url;
|
||||
this->add_sorting_info_(root, obj);
|
||||
}
|
||||
|
||||
@@ -2063,9 +2065,9 @@ bool WebServer::isRequestHandlerTrivial() const { return false; }
|
||||
void WebServer::add_sorting_info_(JsonObject &root, EntityBase *entity) {
|
||||
#ifdef USE_WEBSERVER_SORTING
|
||||
if (this->sorting_entitys_.find(entity) != this->sorting_entitys_.end()) {
|
||||
root["sorting_weight"] = this->sorting_entitys_[entity].weight;
|
||||
root[ESPHOME_F("sorting_weight")] = this->sorting_entitys_[entity].weight;
|
||||
if (this->sorting_groups_.find(this->sorting_entitys_[entity].group_id) != this->sorting_groups_.end()) {
|
||||
root["sorting_group"] = this->sorting_groups_[this->sorting_entitys_[entity].group_id].name;
|
||||
root[ESPHOME_F("sorting_group")] = this->sorting_groups_[this->sorting_entitys_[entity].group_id].name;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -6,20 +6,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
|
||||
// Platform-agnostic macros for web server components
|
||||
// On ESP32 (both Arduino and IDF): Use plain strings (no PROGMEM)
|
||||
// On ESP8266: Use Arduino's F() macro for PROGMEM strings
|
||||
#ifdef USE_ESP32
|
||||
#define ESPHOME_F(string_literal) (string_literal)
|
||||
#define ESPHOME_PGM_P const char *
|
||||
#define ESPHOME_strncpy_P strncpy
|
||||
#else
|
||||
// ESP8266 uses Arduino macros
|
||||
#define ESPHOME_F(string_literal) F(string_literal)
|
||||
#define ESPHOME_PGM_P PGM_P
|
||||
#define ESPHOME_strncpy_P strncpy_P
|
||||
#endif
|
||||
#include "esphome/core/progmem.h"
|
||||
|
||||
#if USE_ESP32
|
||||
#include "esphome/core/hal.h"
|
||||
|
||||
16
esphome/core/progmem.h
Normal file
16
esphome/core/progmem.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
// Platform-agnostic macros for PROGMEM string handling
|
||||
// On ESP32 (both Arduino and IDF): Use plain strings (no PROGMEM)
|
||||
// On ESP8266/Arduino: Use Arduino's F() macro for PROGMEM strings
|
||||
|
||||
#ifdef USE_ESP32
|
||||
#define ESPHOME_F(string_literal) (string_literal)
|
||||
#define ESPHOME_PGM_P const char *
|
||||
#define ESPHOME_strncpy_P strncpy
|
||||
#else
|
||||
// ESP8266 and other Arduino platforms use Arduino macros
|
||||
#define ESPHOME_F(string_literal) F(string_literal)
|
||||
#define ESPHOME_PGM_P PGM_P
|
||||
#define ESPHOME_strncpy_P strncpy_P
|
||||
#endif
|
||||
Reference in New Issue
Block a user