Take Unavailable and the Activate, Run and Press words from Home Assistant's frontend too

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Max Gramser
2026-09-19 14:40:27 +02:00
parent 8fb39a52a6
commit 851c1772e5
15 changed files with 288 additions and 222 deletions
+1 -1
View File
@@ -149,7 +149,7 @@ inline const char *idle_text(const std::string &state) {
if (state == "off") return screen_text::tr(screen_text::txt::ha_off);
if (state == "standby") return screen_text::tr(screen_text::txt::ha_media_standby);
if (state == "buffering") return screen_text::tr(screen_text::txt::media_loading);
if (state == "unavailable") return screen_text::tr(screen_text::txt::tile_unavailable);
if (state == "unavailable") return screen_text::tr(screen_text::txt::ha_unavailable);
return screen_text::tr(screen_text::txt::media_not_playing);
}
inline bool playing(const std::string &state) { return state == "playing" || state == "buffering"; }
+6 -6
View File
@@ -920,7 +920,7 @@ inline std::string detail_state(const Tile &t){
if(t.state=="returning")return tr(txt::ha_vacuum_returning);
if(t.state=="idle")return tr(txt::ha_vacuum_idle);
if(t.state=="error")return tr(txt::vacuum_check_robot);
if(!t.available())return tr(txt::tile_unavailable);
if(!t.available())return tr(txt::ha_unavailable);
// Home Assistant's word where the screen has none of its own (firmware 0.2.58+).
if(!t.extra().state_word.empty())return t.extra().state_word;
return t.unit.empty()?t.state:screen_text::localize(t.state);
@@ -1131,7 +1131,7 @@ inline void render_weather_detail(const Tile &t,bool large,int width,int height,
detail_text(now,degrees(t.current),temp_x,cy+(hero-big_h)/2,temp_w,big,LV_TEXT_ALIGN_LEFT,ink);
int text_x=temp_x+temp_w+(large?4:2),text_w=width-2*pad-card_pad-text_x;
int lines_h=text_h+small_h+(large?2:0);
detail_text(now,t.available()?weather_text(t.state):tr(txt::tile_unavailable),text_x,cy+(hero-lines_h)/2,text_w,detail_font,LV_TEXT_ALIGN_LEFT,ink);
detail_text(now,t.available()?weather_text(t.state):tr(txt::ha_unavailable),text_x,cy+(hero-lines_h)/2,text_w,detail_font,LV_TEXT_ALIGN_LEFT,ink);
std::string details;
if(std::isfinite(weather.feels))details=fill(txt::weather_feels_like,"n",(int)std::lround(weather.feels));
if(std::isfinite(t.humidity)){snprintf(b,sizeof(b),"%d%%",(int)std::lround(t.humidity));details+=(details.empty()?"":" · ")+std::string(b);}
@@ -1373,7 +1373,7 @@ inline constexpr uint32_t COVER_ACCENT = theme::ha::PURPLE;
inline uint32_t cover_track(){return theme::tint(COVER_ACCENT,37);}
inline uint32_t cover_slats(){return theme::tint(COVER_ACCENT,80);}
inline lv_obj_t *cover_values[2]{};
inline std::string cover_status_line(const Tile &t){return t.available()?tile_controls::cover_card_status(t):tr(txt::tile_unavailable);}
inline std::string cover_status_line(const Tile &t){return t.available()?tile_controls::cover_card_status(t):tr(txt::ha_unavailable);}
inline void cover_slider_event(lv_event_t *e){
auto *slider=lv_event_get_target_obj(e);auto code=lv_event_get_code(e);
const bool tilt=(uintptr_t)lv_event_get_user_data(e)==1;
@@ -1570,7 +1570,7 @@ inline bool history_fits(const Tile &t){
// Home Assistant's word for the state now: from this entity's history words, else the card's own. The history can
// still be the previous card's while this one waits for its answer.
inline std::string history_words(const Tile &t){
if(!t.available())return tr(txt::tile_unavailable);
if(!t.available())return tr(txt::ha_unavailable);
if(history.entity==t.entity)for(const auto &pair:history.words)if(pair.first==t.state)return pair.second;
return detail_state(t);
}
@@ -1809,7 +1809,7 @@ inline void render_history_detail(const Tile &t,bool large,int width,int height,
if(line){
int decimals=0;const auto dot=t.state.find('.');if(dot!=std::string::npos)decimals=static_cast<int>(std::min<size_t>(4,t.state.size()-dot-1));
if(c.ready)decimals=h.decimals;
c.value_text=!t.available()?std::string(tr(txt::tile_unavailable)):numeric?history_view::number(current,decimals,t.unit):t.state;
c.value_text=!t.available()?std::string(tr(txt::ha_unavailable)):numeric?history_view::number(current,decimals,t.unit):t.state;
if(c.ready){
// The value now counts too: it can lie beyond the history (the running hour is not in the statistics yet).
if(h.has_high){c.high=h.high;c.high_at=h.high_at;}
@@ -3117,7 +3117,7 @@ inline void render_slot(size_t slot) {
// Nothing in Home Assistant stands behind the settings card, so it says the same with the link down.
if (t.is_settings()) value = tr(txt::tile_tap_to_open);
else if (t.is_page()) value = fill(txt::tile_page, "n", t.page_target());
else if (!fresh() || !t.available()) value = tr(txt::tile_unavailable);
else if (!fresh() || !t.available()) value = tr(txt::ha_unavailable);
else if (t.refused_at && esphome::millis() - t.refused_at < 4000) value = tr(txt::tile_refused);
else if (d == "light" && t.state == "on" && tile_controls::effect_running(t.extra().effect)) value = t.extra().effect;
else if (d == "light" && t.state == "on" && std::isfinite(t.brightness)) value = std::to_string(static_cast<int>(std::lround(std::clamp(t.brightness, 0.0f, 255.0f) * 100 / 255))) + " %";
+194 -194
View File
@@ -73,199 +73,199 @@ constexpr uint16_t settings_hours = 108;
constexpr uint16_t settings_hours_minutes = 109;
constexpr uint16_t tile_tap_to_open = 110;
constexpr uint16_t tile_page = 111;
constexpr uint16_t tile_unavailable = 112;
constexpr uint16_t tile_refused = 113;
constexpr uint16_t tile_command_sent = 114;
constexpr uint16_t tile_confirmed = 115;
constexpr uint16_t alert_notification = 116;
constexpr uint16_t alert_ok = 117;
constexpr uint16_t light_color = 118;
constexpr uint16_t light_color_temperature = 119;
constexpr uint16_t light_brightness = 120;
constexpr uint16_t light_waiting = 121;
constexpr uint16_t effects_effect = 122;
constexpr uint16_t effects_nothing = 123;
constexpr uint16_t effects_loading = 124;
constexpr uint16_t effects_not_connected = 125;
constexpr uint16_t climate_target = 126;
constexpr uint16_t climate_mode = 127;
constexpr uint16_t climate_fan = 128;
constexpr uint16_t climate_swing = 129;
constexpr uint16_t climate_now = 130;
constexpr uint16_t vacuum_check_robot = 131;
constexpr uint16_t vacuum_auto_suction = 132;
constexpr uint16_t vacuum_robot_chooses = 133;
constexpr uint16_t vacuum_per_room = 134;
constexpr uint16_t vacuum_speed_quiet = 135;
constexpr uint16_t vacuum_speed_balanced = 136;
constexpr uint16_t vacuum_speed_turbo = 137;
constexpr uint16_t vacuum_speed_max = 138;
constexpr uint16_t vacuum_pause_cleaning = 139;
constexpr uint16_t vacuum_pause = 140;
constexpr uint16_t vacuum_resume = 141;
constexpr uint16_t vacuum_start_cleaning = 142;
constexpr uint16_t vacuum_clean = 143;
constexpr uint16_t vacuum_dock = 144;
constexpr uint16_t cover_position = 145;
constexpr uint16_t cover_tilt = 146;
constexpr uint16_t cover_tilt_value = 147;
constexpr uint16_t weather_feels_like = 148;
constexpr uint16_t weather_no_forecast = 149;
constexpr uint16_t weather_coming_days = 150;
constexpr uint16_t history_no_data = 151;
constexpr uint16_t history_average = 152;
constexpr uint16_t history_average_of = 153;
constexpr uint16_t history_now = 154;
constexpr uint16_t history_range_hour = 155;
constexpr uint16_t history_range_day = 156;
constexpr uint16_t history_range_week = 157;
constexpr uint16_t history_high = 158;
constexpr uint16_t history_low = 159;
constexpr uint16_t history_times = 160;
constexpr uint16_t history_loading = 161;
constexpr uint16_t history_empty = 162;
constexpr uint16_t history_unavailable = 163;
constexpr uint16_t media_muted = 164;
constexpr uint16_t media_not_playing = 165;
constexpr uint16_t media_loading = 166;
constexpr uint16_t timer_running = 167;
constexpr uint16_t timer_paused = 168;
constexpr uint16_t timer_stopped = 169;
constexpr uint16_t timer_pause = 170;
constexpr uint16_t timer_start = 171;
constexpr uint16_t timer_cancel = 172;
constexpr uint16_t timer_paused_left = 173;
constexpr uint16_t sun_name = 174;
constexpr uint16_t sun_sunrise = 175;
constexpr uint16_t sun_sunset = 176;
constexpr uint16_t sun_rise = 177;
constexpr uint16_t sun_set = 178;
constexpr uint16_t script_running = 179;
constexpr uint16_t script_never_run = 180;
constexpr uint16_t script_last_time = 181;
constexpr uint16_t script_yesterday_time = 182;
constexpr uint16_t script_last_date = 183;
constexpr uint16_t camera_no_image = 184;
constexpr uint16_t camera_loading = 185;
constexpr uint16_t camera_live = 186;
constexpr uint16_t camera_recording = 187;
constexpr uint16_t camera_tap_to_view = 188;
constexpr uint16_t camera_no_image_yet = 189;
constexpr uint16_t button_activate = 190;
constexpr uint16_t button_run = 191;
constexpr uint16_t button_press = 192;
constexpr uint16_t calibration_title = 193;
constexpr uint16_t calibration_touch_check = 194;
constexpr uint16_t calibration_hold = 195;
constexpr uint16_t calibration_crosshair = 196;
constexpr uint16_t calibration_gently = 197;
constexpr uint16_t calibration_same = 198;
constexpr uint16_t calibration_rejected = 199;
constexpr uint16_t calibration_save_failed = 200;
constexpr uint16_t ha_on = 201;
constexpr uint16_t ha_off = 202;
constexpr uint16_t ha_climate_off = 203;
constexpr uint16_t ha_climate_heat = 204;
constexpr uint16_t ha_climate_cool = 205;
constexpr uint16_t ha_climate_heat_cool = 206;
constexpr uint16_t ha_climate_auto = 207;
constexpr uint16_t ha_climate_dry = 208;
constexpr uint16_t ha_climate_fan_only = 209;
constexpr uint16_t ha_hvac_action_heating = 210;
constexpr uint16_t ha_hvac_action_cooling = 211;
constexpr uint16_t ha_hvac_action_idle = 212;
constexpr uint16_t ha_hvac_action_off = 213;
constexpr uint16_t ha_hvac_action_drying = 214;
constexpr uint16_t ha_hvac_action_fan = 215;
constexpr uint16_t ha_hvac_action_preheating = 216;
constexpr uint16_t ha_hvac_action_defrosting = 217;
constexpr uint16_t ha_cover_open = 218;
constexpr uint16_t ha_cover_closed = 219;
constexpr uint16_t ha_cover_opening = 220;
constexpr uint16_t ha_cover_closing = 221;
constexpr uint16_t ha_media_playing = 222;
constexpr uint16_t ha_media_paused = 223;
constexpr uint16_t ha_media_idle = 224;
constexpr uint16_t ha_media_standby = 225;
constexpr uint16_t ha_person_home = 226;
constexpr uint16_t ha_person_not_home = 227;
constexpr uint16_t ha_sun_above_horizon = 228;
constexpr uint16_t ha_sun_below_horizon = 229;
constexpr uint16_t ha_vacuum_docked = 230;
constexpr uint16_t ha_vacuum_cleaning = 231;
constexpr uint16_t ha_vacuum_paused = 232;
constexpr uint16_t ha_vacuum_returning = 233;
constexpr uint16_t ha_vacuum_idle = 234;
constexpr uint16_t ha_weather_sunny = 235;
constexpr uint16_t ha_weather_clear_night = 236;
constexpr uint16_t ha_weather_cloudy = 237;
constexpr uint16_t ha_weather_partlycloudy = 238;
constexpr uint16_t ha_weather_rainy = 239;
constexpr uint16_t ha_weather_pouring = 240;
constexpr uint16_t ha_weather_snowy = 241;
constexpr uint16_t ha_weather_snowy_rainy = 242;
constexpr uint16_t ha_weather_fog = 243;
constexpr uint16_t ha_weather_hail = 244;
constexpr uint16_t ha_weather_lightning = 245;
constexpr uint16_t ha_weather_lightning_rainy = 246;
constexpr uint16_t ha_weather_windy = 247;
constexpr uint16_t ha_weather_exceptional = 248;
constexpr uint16_t ha_binary_battery_on = 249;
constexpr uint16_t ha_binary_battery_off = 250;
constexpr uint16_t ha_binary_battery_charging_on = 251;
constexpr uint16_t ha_binary_battery_charging_off = 252;
constexpr uint16_t ha_binary_carbon_monoxide_on = 253;
constexpr uint16_t ha_binary_carbon_monoxide_off = 254;
constexpr uint16_t ha_binary_cold_on = 255;
constexpr uint16_t ha_binary_cold_off = 256;
constexpr uint16_t ha_binary_connectivity_on = 257;
constexpr uint16_t ha_binary_connectivity_off = 258;
constexpr uint16_t ha_binary_door_on = 259;
constexpr uint16_t ha_binary_door_off = 260;
constexpr uint16_t ha_binary_garage_door_on = 261;
constexpr uint16_t ha_binary_garage_door_off = 262;
constexpr uint16_t ha_binary_gas_on = 263;
constexpr uint16_t ha_binary_gas_off = 264;
constexpr uint16_t ha_binary_heat_on = 265;
constexpr uint16_t ha_binary_heat_off = 266;
constexpr uint16_t ha_binary_light_on = 267;
constexpr uint16_t ha_binary_light_off = 268;
constexpr uint16_t ha_binary_lock_on = 269;
constexpr uint16_t ha_binary_lock_off = 270;
constexpr uint16_t ha_binary_moisture_on = 271;
constexpr uint16_t ha_binary_moisture_off = 272;
constexpr uint16_t ha_binary_motion_on = 273;
constexpr uint16_t ha_binary_motion_off = 274;
constexpr uint16_t ha_binary_moving_on = 275;
constexpr uint16_t ha_binary_moving_off = 276;
constexpr uint16_t ha_binary_occupancy_on = 277;
constexpr uint16_t ha_binary_occupancy_off = 278;
constexpr uint16_t ha_binary_opening_on = 279;
constexpr uint16_t ha_binary_opening_off = 280;
constexpr uint16_t ha_binary_plug_on = 281;
constexpr uint16_t ha_binary_plug_off = 282;
constexpr uint16_t ha_binary_power_on = 283;
constexpr uint16_t ha_binary_power_off = 284;
constexpr uint16_t ha_binary_presence_on = 285;
constexpr uint16_t ha_binary_presence_off = 286;
constexpr uint16_t ha_binary_problem_on = 287;
constexpr uint16_t ha_binary_problem_off = 288;
constexpr uint16_t ha_binary_running_on = 289;
constexpr uint16_t ha_binary_running_off = 290;
constexpr uint16_t ha_binary_safety_on = 291;
constexpr uint16_t ha_binary_safety_off = 292;
constexpr uint16_t ha_binary_smoke_on = 293;
constexpr uint16_t ha_binary_smoke_off = 294;
constexpr uint16_t ha_binary_sound_on = 295;
constexpr uint16_t ha_binary_sound_off = 296;
constexpr uint16_t ha_binary_tamper_on = 297;
constexpr uint16_t ha_binary_tamper_off = 298;
constexpr uint16_t ha_binary_update_on = 299;
constexpr uint16_t ha_binary_update_off = 300;
constexpr uint16_t ha_binary_vibration_on = 301;
constexpr uint16_t ha_binary_vibration_off = 302;
constexpr uint16_t ha_binary_window_on = 303;
constexpr uint16_t ha_binary_window_off = 304;
constexpr uint16_t tile_refused = 112;
constexpr uint16_t tile_command_sent = 113;
constexpr uint16_t tile_confirmed = 114;
constexpr uint16_t alert_notification = 115;
constexpr uint16_t alert_ok = 116;
constexpr uint16_t light_color = 117;
constexpr uint16_t light_color_temperature = 118;
constexpr uint16_t light_brightness = 119;
constexpr uint16_t light_waiting = 120;
constexpr uint16_t effects_effect = 121;
constexpr uint16_t effects_nothing = 122;
constexpr uint16_t effects_loading = 123;
constexpr uint16_t effects_not_connected = 124;
constexpr uint16_t climate_target = 125;
constexpr uint16_t climate_mode = 126;
constexpr uint16_t climate_fan = 127;
constexpr uint16_t climate_swing = 128;
constexpr uint16_t climate_now = 129;
constexpr uint16_t vacuum_check_robot = 130;
constexpr uint16_t vacuum_auto_suction = 131;
constexpr uint16_t vacuum_robot_chooses = 132;
constexpr uint16_t vacuum_per_room = 133;
constexpr uint16_t vacuum_speed_quiet = 134;
constexpr uint16_t vacuum_speed_balanced = 135;
constexpr uint16_t vacuum_speed_turbo = 136;
constexpr uint16_t vacuum_speed_max = 137;
constexpr uint16_t vacuum_pause_cleaning = 138;
constexpr uint16_t vacuum_pause = 139;
constexpr uint16_t vacuum_resume = 140;
constexpr uint16_t vacuum_start_cleaning = 141;
constexpr uint16_t vacuum_clean = 142;
constexpr uint16_t vacuum_dock = 143;
constexpr uint16_t cover_position = 144;
constexpr uint16_t cover_tilt = 145;
constexpr uint16_t cover_tilt_value = 146;
constexpr uint16_t weather_feels_like = 147;
constexpr uint16_t weather_no_forecast = 148;
constexpr uint16_t weather_coming_days = 149;
constexpr uint16_t history_no_data = 150;
constexpr uint16_t history_average = 151;
constexpr uint16_t history_average_of = 152;
constexpr uint16_t history_now = 153;
constexpr uint16_t history_range_hour = 154;
constexpr uint16_t history_range_day = 155;
constexpr uint16_t history_range_week = 156;
constexpr uint16_t history_high = 157;
constexpr uint16_t history_low = 158;
constexpr uint16_t history_times = 159;
constexpr uint16_t history_loading = 160;
constexpr uint16_t history_empty = 161;
constexpr uint16_t history_unavailable = 162;
constexpr uint16_t media_muted = 163;
constexpr uint16_t media_not_playing = 164;
constexpr uint16_t media_loading = 165;
constexpr uint16_t timer_running = 166;
constexpr uint16_t timer_paused = 167;
constexpr uint16_t timer_stopped = 168;
constexpr uint16_t timer_pause = 169;
constexpr uint16_t timer_start = 170;
constexpr uint16_t timer_cancel = 171;
constexpr uint16_t timer_paused_left = 172;
constexpr uint16_t sun_name = 173;
constexpr uint16_t sun_sunrise = 174;
constexpr uint16_t sun_sunset = 175;
constexpr uint16_t sun_rise = 176;
constexpr uint16_t sun_set = 177;
constexpr uint16_t script_running = 178;
constexpr uint16_t script_never_run = 179;
constexpr uint16_t script_last_time = 180;
constexpr uint16_t script_yesterday_time = 181;
constexpr uint16_t script_last_date = 182;
constexpr uint16_t camera_no_image = 183;
constexpr uint16_t camera_loading = 184;
constexpr uint16_t camera_live = 185;
constexpr uint16_t camera_recording = 186;
constexpr uint16_t camera_tap_to_view = 187;
constexpr uint16_t camera_no_image_yet = 188;
constexpr uint16_t calibration_title = 189;
constexpr uint16_t calibration_touch_check = 190;
constexpr uint16_t calibration_hold = 191;
constexpr uint16_t calibration_crosshair = 192;
constexpr uint16_t calibration_gently = 193;
constexpr uint16_t calibration_same = 194;
constexpr uint16_t calibration_rejected = 195;
constexpr uint16_t calibration_save_failed = 196;
constexpr uint16_t ha_on = 197;
constexpr uint16_t ha_off = 198;
constexpr uint16_t ha_unavailable = 199;
constexpr uint16_t ha_climate_off = 200;
constexpr uint16_t ha_climate_heat = 201;
constexpr uint16_t ha_climate_cool = 202;
constexpr uint16_t ha_climate_heat_cool = 203;
constexpr uint16_t ha_climate_auto = 204;
constexpr uint16_t ha_climate_dry = 205;
constexpr uint16_t ha_climate_fan_only = 206;
constexpr uint16_t ha_hvac_action_heating = 207;
constexpr uint16_t ha_hvac_action_cooling = 208;
constexpr uint16_t ha_hvac_action_idle = 209;
constexpr uint16_t ha_hvac_action_off = 210;
constexpr uint16_t ha_hvac_action_drying = 211;
constexpr uint16_t ha_hvac_action_fan = 212;
constexpr uint16_t ha_hvac_action_preheating = 213;
constexpr uint16_t ha_hvac_action_defrosting = 214;
constexpr uint16_t ha_cover_open = 215;
constexpr uint16_t ha_cover_closed = 216;
constexpr uint16_t ha_cover_opening = 217;
constexpr uint16_t ha_cover_closing = 218;
constexpr uint16_t ha_media_playing = 219;
constexpr uint16_t ha_media_paused = 220;
constexpr uint16_t ha_media_idle = 221;
constexpr uint16_t ha_media_standby = 222;
constexpr uint16_t ha_person_home = 223;
constexpr uint16_t ha_person_not_home = 224;
constexpr uint16_t ha_sun_above_horizon = 225;
constexpr uint16_t ha_sun_below_horizon = 226;
constexpr uint16_t ha_vacuum_docked = 227;
constexpr uint16_t ha_vacuum_cleaning = 228;
constexpr uint16_t ha_vacuum_paused = 229;
constexpr uint16_t ha_vacuum_returning = 230;
constexpr uint16_t ha_vacuum_idle = 231;
constexpr uint16_t ha_weather_sunny = 232;
constexpr uint16_t ha_weather_clear_night = 233;
constexpr uint16_t ha_weather_cloudy = 234;
constexpr uint16_t ha_weather_partlycloudy = 235;
constexpr uint16_t ha_weather_rainy = 236;
constexpr uint16_t ha_weather_pouring = 237;
constexpr uint16_t ha_weather_snowy = 238;
constexpr uint16_t ha_weather_snowy_rainy = 239;
constexpr uint16_t ha_weather_fog = 240;
constexpr uint16_t ha_weather_hail = 241;
constexpr uint16_t ha_weather_lightning = 242;
constexpr uint16_t ha_weather_lightning_rainy = 243;
constexpr uint16_t ha_weather_windy = 244;
constexpr uint16_t ha_weather_exceptional = 245;
constexpr uint16_t ha_binary_battery_on = 246;
constexpr uint16_t ha_binary_battery_off = 247;
constexpr uint16_t ha_binary_battery_charging_on = 248;
constexpr uint16_t ha_binary_battery_charging_off = 249;
constexpr uint16_t ha_binary_carbon_monoxide_on = 250;
constexpr uint16_t ha_binary_carbon_monoxide_off = 251;
constexpr uint16_t ha_binary_cold_on = 252;
constexpr uint16_t ha_binary_cold_off = 253;
constexpr uint16_t ha_binary_connectivity_on = 254;
constexpr uint16_t ha_binary_connectivity_off = 255;
constexpr uint16_t ha_binary_door_on = 256;
constexpr uint16_t ha_binary_door_off = 257;
constexpr uint16_t ha_binary_garage_door_on = 258;
constexpr uint16_t ha_binary_garage_door_off = 259;
constexpr uint16_t ha_binary_gas_on = 260;
constexpr uint16_t ha_binary_gas_off = 261;
constexpr uint16_t ha_binary_heat_on = 262;
constexpr uint16_t ha_binary_heat_off = 263;
constexpr uint16_t ha_binary_light_on = 264;
constexpr uint16_t ha_binary_light_off = 265;
constexpr uint16_t ha_binary_lock_on = 266;
constexpr uint16_t ha_binary_lock_off = 267;
constexpr uint16_t ha_binary_moisture_on = 268;
constexpr uint16_t ha_binary_moisture_off = 269;
constexpr uint16_t ha_binary_motion_on = 270;
constexpr uint16_t ha_binary_motion_off = 271;
constexpr uint16_t ha_binary_moving_on = 272;
constexpr uint16_t ha_binary_moving_off = 273;
constexpr uint16_t ha_binary_occupancy_on = 274;
constexpr uint16_t ha_binary_occupancy_off = 275;
constexpr uint16_t ha_binary_opening_on = 276;
constexpr uint16_t ha_binary_opening_off = 277;
constexpr uint16_t ha_binary_plug_on = 278;
constexpr uint16_t ha_binary_plug_off = 279;
constexpr uint16_t ha_binary_power_on = 280;
constexpr uint16_t ha_binary_power_off = 281;
constexpr uint16_t ha_binary_presence_on = 282;
constexpr uint16_t ha_binary_presence_off = 283;
constexpr uint16_t ha_binary_problem_on = 284;
constexpr uint16_t ha_binary_problem_off = 285;
constexpr uint16_t ha_binary_running_on = 286;
constexpr uint16_t ha_binary_running_off = 287;
constexpr uint16_t ha_binary_safety_on = 288;
constexpr uint16_t ha_binary_safety_off = 289;
constexpr uint16_t ha_binary_smoke_on = 290;
constexpr uint16_t ha_binary_smoke_off = 291;
constexpr uint16_t ha_binary_sound_on = 292;
constexpr uint16_t ha_binary_sound_off = 293;
constexpr uint16_t ha_binary_tamper_on = 294;
constexpr uint16_t ha_binary_tamper_off = 295;
constexpr uint16_t ha_binary_update_on = 296;
constexpr uint16_t ha_binary_update_off = 297;
constexpr uint16_t ha_binary_vibration_on = 298;
constexpr uint16_t ha_binary_vibration_off = 299;
constexpr uint16_t ha_binary_window_on = 300;
constexpr uint16_t ha_binary_window_off = 301;
constexpr uint16_t ha_button_activate = 302;
constexpr uint16_t ha_button_run = 303;
constexpr uint16_t ha_button_press = 304;
constexpr uint16_t date_weekdays = 17;
constexpr uint16_t date_weekdays_count = 7;
constexpr uint16_t date_weekdays_short = 24;
@@ -278,5 +278,5 @@ constexpr uint16_t date_months_short = 50;
constexpr uint16_t date_months_short_count = 12;
} // namespace txt
constexpr uint16_t KEY_COUNT = 305;
constexpr uint32_t KEYS_HASH = 0x8971C0EBu;
constexpr uint32_t KEYS_HASH = 0xC6B1A3EDu;
} // namespace screen_text
+3 -3
View File
@@ -348,9 +348,9 @@ inline std::string neighbour_option(const Tile &t, int direction) {
return options[(current + direction + count) % count];
}
inline const char *run_label(const std::string &domain) {
if (domain == "scene") return screen_text::tr(screen_text::txt::button_activate);
if (domain == "script") return screen_text::tr(screen_text::txt::button_run);
return screen_text::tr(screen_text::txt::button_press);
if (domain == "scene") return screen_text::tr(screen_text::txt::ha_button_activate);
if (domain == "script") return screen_text::tr(screen_text::txt::ha_button_run);
return screen_text::tr(screen_text::txt::ha_button_press);
}
// The Home Assistant action behind a key. STEP_* are handled locally (debounced) and return nothing.
inline Action key_action(const Tile &t, int command, const std::string &arg = "") {
+6
View File
@@ -200,6 +200,12 @@
"vibration_off": "Frei",
"window_on": "Geöffnet",
"window_off": "Geschlossen"
},
"unavailable": "Nicht verfügbar",
"button": {
"activate": "Aktivieren",
"run": "Ausführen",
"press": "Drücken"
}
}
},
+6
View File
@@ -134,6 +134,12 @@
"vibration_off": "Clear",
"window_on": "Open",
"window_off": "Closed"
},
"unavailable": "Unavailable",
"button": {
"activate": "Activate",
"run": "Run",
"press": "Press"
}
}
}
+6 -6
View File
@@ -143,7 +143,6 @@
"tile": {
"tap_to_open": "Tap to open",
"page": "Page {n}",
"unavailable": "Unavailable",
"refused": "Refused",
"command_sent": "Command sent...",
"confirmed": "Confirmed by Home Assistant"
@@ -248,11 +247,6 @@
"tap_to_view": "Tap to view",
"no_image_yet": "No image yet"
},
"button": {
"activate": "Activate",
"run": "Run",
"press": "Press"
},
"calibration": {
"title": "Follow the calibration wizard",
"touch_check": "GT911 touch check",
@@ -266,6 +260,7 @@
"ha": {
"on": "On",
"off": "Off",
"unavailable": "Unavailable",
"climate": {
"off": "Off",
"heat": "Heat",
@@ -385,6 +380,11 @@
"vibration_off": "Clear",
"window_on": "Open",
"window_off": "Closed"
},
"button": {
"activate": "Activate",
"run": "Run",
"press": "Press"
}
}
},
+6
View File
@@ -200,6 +200,12 @@
"vibration_off": "No detectado",
"window_on": "Abierto",
"window_off": "Cerrado"
},
"unavailable": "No disponible",
"button": {
"activate": "Activar",
"run": "Ejecutar",
"press": "Pulsa"
}
}
},
+6
View File
@@ -200,6 +200,12 @@
"vibration_off": "Non détectée",
"window_on": "Ouvert",
"window_off": "Fermé"
},
"unavailable": "Indisponible",
"button": {
"activate": "Activer",
"run": "Exécuter",
"press": "Appuyer"
}
}
},
+6
View File
@@ -200,6 +200,12 @@
"vibration_off": "Assente",
"window_on": "Aperto",
"window_off": "Chiuso"
},
"unavailable": "Non disponibile",
"button": {
"activate": "Attiva",
"run": "Esegui",
"press": "Premi"
}
}
},
+6 -6
View File
@@ -143,7 +143,6 @@
"tile": {
"tap_to_open": "Tik om te openen",
"page": "Pagina {n}",
"unavailable": "Niet beschikbaar",
"refused": "Geweigerd",
"command_sent": "Opdracht verstuurd...",
"confirmed": "Bevestigd door Home Assistant"
@@ -248,11 +247,6 @@
"tap_to_view": "Tik om te bekijken",
"no_image_yet": "Nog geen beeld"
},
"button": {
"activate": "Activeren",
"run": "Uitvoeren",
"press": "Indrukken"
},
"calibration": {
"title": "Volg de kalibratie",
"touch_check": "GT911-aanraaktest",
@@ -385,6 +379,12 @@
"vibration_off": "Niet gedetecteerd",
"window_on": "Open",
"window_off": "Dicht"
},
"unavailable": "Niet beschikbaar",
"button": {
"activate": "Inschakelen",
"run": "Uitvoeren",
"press": "Klik"
}
}
},
+6
View File
@@ -200,6 +200,12 @@
"vibration_off": "brak",
"window_on": "otwarto",
"window_off": "zamknięto"
},
"unavailable": "niedostępny",
"button": {
"activate": "Aktywuj",
"run": "Uruchom",
"press": "Naciśnij"
}
}
},
+6
View File
@@ -200,6 +200,12 @@
"vibration_off": "Limpo",
"window_on": "Aberto",
"window_off": "Fechada"
},
"unavailable": "Indisponível",
"button": {
"activate": "Ativar",
"run": "Executar",
"press": "Pressione"
}
}
},
+6 -6
View File
@@ -3,7 +3,7 @@
#pragma once
#include "components/smart_display/screen_text.h"
static_assert(screen_text::KEYS_HASH == 0x8971C0EBu && screen_text::KEY_COUNT == 305,
static_assert(screen_text::KEYS_HASH == 0xC6B1A3EDu && screen_text::KEY_COUNT == 305,
"screen_text_keys.h does not match screen_manager/translations/en.json: run tools/i18n.py header");
const char *const screen_text::TABLE[] = {
".",
@@ -118,7 +118,6 @@ const char *const screen_text::TABLE[] = {
"{h} h {m}",
"Tap to open",
"Page {n}",
"Unavailable",
"Refused",
"Command sent...",
"Confirmed by Home Assistant",
@@ -196,9 +195,6 @@ const char *const screen_text::TABLE[] = {
"Recording",
"Tap to view",
"No image yet",
"Activate",
"Run",
"Press",
"Follow the calibration wizard",
"GT911 touch check",
"Hold each tap for a moment",
@@ -209,6 +205,7 @@ const char *const screen_text::TABLE[] = {
"Save failed; try again",
"On",
"Off",
"Unavailable",
"Off",
"Heat",
"Cool",
@@ -310,7 +307,10 @@ const char *const screen_text::TABLE[] = {
"Detected",
"Clear",
"Open",
"Closed"
"Closed",
"Activate",
"Run",
"Press"
};
const char *const screen_text::LANGUAGE = "en";
int screen_text::plural_index(int n) { return n == 1 ? 0 : 1; }
+24
View File
@@ -200,6 +200,28 @@ def ha_sources():
return sources
# The words Home Assistant's frontend itself shows (its own translation files, not the backend's).
FRONTEND_SOURCES = {'unavailable': 'state.default.unavailable', 'button.activate': 'ui.card.scene.activate',
'button.run': 'ui.card.script.run', 'button.press': 'ui.card.button.press'}
def frontend_words(url, codes):
"""{code: {key: word}} from the translation files Home Assistant's frontend loads (their names carry a hash that the
frontend's app script lists)."""
import urllib.request
page = urllib.request.urlopen(url + '/', timeout=20).read().decode('utf-8', 'replace')
found = {}
for script in dict.fromkeys(re.findall(r'(/frontend_latest/app\.[\w.]+\.js)', page)):
text = urllib.request.urlopen(url + script, timeout=30).read().decode('utf-8', 'replace')
for code in codes:
match = re.search(r'"' + re.escape(code) + r'":\{"nativeName":"[^"]*","hash":"([0-9a-f]+)"', text)
if match and code not in found:
data = json.loads(urllib.request.urlopen(f'{url}/static/translations/{code}-{match.group(1)}.json', timeout=30).read())
flat = dict(generator().flatten(data))
found[code] = {key: flat[source] for key, source in FRONTEND_SOURCES.items() if isinstance(flat.get(source), str)}
return found
def ha_words(write):
"""screen.ha of every language from a Home Assistant (HA_URL and HA_TOKEN, or .esphome/ha_url and ha_token): its own
words for states, English included, so a screen says what Home Assistant says (Max, app 0.2.90)."""
@@ -236,6 +258,7 @@ def ha_words(write):
langs = languages()
found = asyncio.run(fetch(list(langs)))
frontend = frontend_words(url, list(langs))
status = 0
for code, data in langs.items():
words = found.get(code) or {}
@@ -245,6 +268,7 @@ def ha_words(write):
own[key] = words[source]
else:
print(f'{code}: Home Assistant has no {source}')
own.update(frontend.get(code, {}))
reference = dict(generator().flatten(data.get('screen', {}).get('ha', {})))
if code == 'en':
for key, word in own.items():