diff --git a/src/common/entity/compute_attribute_display.ts b/src/common/entity/compute_attribute_display.ts new file mode 100644 index 0000000000..f969646265 --- /dev/null +++ b/src/common/entity/compute_attribute_display.ts @@ -0,0 +1,52 @@ +import { HassEntity } from "home-assistant-js-websocket"; +import { EntityRegistryEntry } from "../../data/entity_registry"; +import { HomeAssistant } from "../../types"; +import { LocalizeFunc } from "../translations/localize"; +import { computeDomain } from "./compute_domain"; + +export const computeAttributeValueDisplay = ( + localize: LocalizeFunc, + stateObj: HassEntity, + entities: HomeAssistant["entities"], + attribute: string, + value?: any +): string => { + const entityId = stateObj.entity_id; + const attributeValue = + value !== undefined ? value : stateObj.attributes[attribute]; + const domain = computeDomain(entityId); + const entity = entities[entityId] as EntityRegistryEntry | undefined; + const translationKey = entity?.translation_key; + + return ( + (translationKey && + localize( + `component.${entity.platform}.entity.${domain}.${translationKey}.state_attributes.${attribute}.state.${attributeValue}` + )) || + localize( + `component.${domain}.state_attributes._.${attribute}.state.${attributeValue}` + ) || + attributeValue + ); +}; + +export const computeAttributeNameDisplay = ( + localize: LocalizeFunc, + stateObj: HassEntity, + entities: HomeAssistant["entities"], + attribute: string +): string => { + const entityId = stateObj.entity_id; + const domain = computeDomain(entityId); + const entity = entities[entityId] as EntityRegistryEntry | undefined; + const translationKey = entity?.translation_key; + + return ( + (translationKey && + localize( + `component.${entity.platform}.entity.${domain}.${translationKey}.state_attributes.${attribute}.name` + )) || + localize(`component.${domain}.state_attributes._.${attribute}.name`) || + attribute + ); +}; diff --git a/src/components/ha-climate-state.ts b/src/components/ha-climate-state.ts index 8b9f170b00..9443352fb5 100644 --- a/src/components/ha-climate-state.ts +++ b/src/components/ha-climate-state.ts @@ -1,5 +1,7 @@ import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import { customElement, property } from "lit/decorators"; +import { computeAttributeValueDisplay } from "../common/entity/compute_attribute_display"; +import { computeStateDisplay } from "../common/entity/compute_state_display"; import { formatNumber } from "../common/number/format_number"; import { ClimateEntity, CLIMATE_PRESET_NONE } from "../data/climate"; import { isUnavailableState } from "../data/entity"; @@ -21,9 +23,12 @@ class HaClimateState extends LitElement { ${this.stateObj.attributes.preset_mode && this.stateObj.attributes.preset_mode !== CLIMATE_PRESET_NONE ? html`- - ${this.hass.localize( - `state_attributes.climate.preset_mode.${this.stateObj.attributes.preset_mode}` - ) || this.stateObj.attributes.preset_mode}` + ${computeAttributeValueDisplay( + this.hass.localize, + this.stateObj, + this.hass.entities, + "preset_mode" + )}` : ""}
${this._computeTarget()}
` @@ -112,13 +117,19 @@ class HaClimateState extends LitElement { return this.hass.localize(`state.default.${this.stateObj.state}`); } - const stateString = this.hass.localize( - `component.climate.state._.${this.stateObj.state}` + const stateString = computeStateDisplay( + this.hass.localize, + this.stateObj, + this.hass.locale, + this.hass.entities ); return this.stateObj.attributes.hvac_action - ? `${this.hass.localize( - `state_attributes.climate.hvac_action.${this.stateObj.attributes.hvac_action}` + ? `${computeAttributeValueDisplay( + this.hass.localize, + this.stateObj, + this.hass.entities, + "hvac_action" )} (${stateString})` : stateString; } diff --git a/src/data/climate.ts b/src/data/climate.ts index 064fb32c98..6ed6fa7523 100644 --- a/src/data/climate.ts +++ b/src/data/climate.ts @@ -2,7 +2,6 @@ import { HassEntityAttributeBase, HassEntityBase, } from "home-assistant-js-websocket"; -import { TranslationDict } from "../types"; export type HvacMode = | "off" @@ -15,12 +14,13 @@ export type HvacMode = export const CLIMATE_PRESET_NONE = "none"; -type ClimateAttributes = TranslationDict["state_attributes"]["climate"]; -export type HvacAction = keyof ClimateAttributes["hvac_action"]; -export type FanMode = keyof ClimateAttributes["fan_mode"]; -export type PresetMode = - | keyof ClimateAttributes["preset_mode"] - | typeof CLIMATE_PRESET_NONE; +export type HvacAction = + | "off" + | "heating" + | "cooling" + | "drying" + | "idle" + | "fan"; export type ClimateEntity = HassEntityBase & { attributes: HassEntityAttributeBase & { @@ -40,23 +40,25 @@ export type ClimateEntity = HassEntityBase & { target_humidity_high?: number; min_humidity?: number; max_humidity?: number; - fan_mode?: FanMode; - fan_modes?: FanMode[]; - preset_mode?: PresetMode; - preset_modes?: PresetMode[]; + fan_mode?: string; + fan_modes?: string[]; + preset_mode?: string; + preset_modes?: string[]; swing_mode?: string; swing_modes?: string[]; aux_heat?: "on" | "off"; }; }; -export const CLIMATE_SUPPORT_TARGET_TEMPERATURE = 1; -export const CLIMATE_SUPPORT_TARGET_TEMPERATURE_RANGE = 2; -export const CLIMATE_SUPPORT_TARGET_HUMIDITY = 4; -export const CLIMATE_SUPPORT_FAN_MODE = 8; -export const CLIMATE_SUPPORT_PRESET_MODE = 16; -export const CLIMATE_SUPPORT_SWING_MODE = 32; -export const CLIMATE_SUPPORT_AUX_HEAT = 64; +export const enum ClimateEntityFeature { + TARGET_TEMPERATURE = 1, + TARGET_TEMPERATURE_RANGE = 2, + TARGET_HUMIDITY = 4, + FAN_MODE = 8, + PRESET_MODE = 16, + SWING_MODE = 32, + AUX_HEAT = 64, +} const hvacModeOrdering: { [key in HvacMode]: number } = { auto: 1, diff --git a/src/data/translation.ts b/src/data/translation.ts index 56764f922a..1d3f5c2d71 100644 --- a/src/data/translation.ts +++ b/src/data/translation.ts @@ -44,6 +44,7 @@ declare global { export type TranslationCategory = | "title" | "state" + | "state_attributes" | "entity" | "config" | "config_panel" diff --git a/src/dialogs/more-info/controls/more-info-climate.ts b/src/dialogs/more-info/controls/more-info-climate.ts index 03b94c3827..559b9bfbef 100644 --- a/src/dialogs/more-info/controls/more-info-climate.ts +++ b/src/dialogs/more-info/controls/more-info-climate.ts @@ -11,6 +11,11 @@ import { property } from "lit/decorators"; import { classMap } from "lit/directives/class-map"; import { fireEvent } from "../../../common/dom/fire_event"; import { stopPropagation } from "../../../common/dom/stop_propagation"; +import { + computeAttributeNameDisplay, + computeAttributeValueDisplay, +} from "../../../common/entity/compute_attribute_display"; +import { computeStateDisplay } from "../../../common/entity/compute_state_display"; import { supportsFeature } from "../../../common/entity/supports-feature"; import { computeRTLDirection } from "../../../common/util/compute_rtl"; import "../../../components/ha-climate-control"; @@ -19,13 +24,7 @@ import "../../../components/ha-slider"; import "../../../components/ha-switch"; import { ClimateEntity, - CLIMATE_SUPPORT_AUX_HEAT, - CLIMATE_SUPPORT_FAN_MODE, - CLIMATE_SUPPORT_PRESET_MODE, - CLIMATE_SUPPORT_SWING_MODE, - CLIMATE_SUPPORT_TARGET_HUMIDITY, - CLIMATE_SUPPORT_TARGET_TEMPERATURE, - CLIMATE_SUPPORT_TARGET_TEMPERATURE_RANGE, + ClimateEntityFeature, compareClimateHvacModes, } from "../../../data/climate"; import { HomeAssistant } from "../../../types"; @@ -47,26 +46,32 @@ class MoreInfoClimate extends LitElement { const supportTargetTemperature = supportsFeature( stateObj, - CLIMATE_SUPPORT_TARGET_TEMPERATURE + ClimateEntityFeature.TARGET_TEMPERATURE ); const supportTargetTemperatureRange = supportsFeature( stateObj, - CLIMATE_SUPPORT_TARGET_TEMPERATURE_RANGE + ClimateEntityFeature.TARGET_TEMPERATURE_RANGE ); const supportTargetHumidity = supportsFeature( stateObj, - CLIMATE_SUPPORT_TARGET_HUMIDITY + ClimateEntityFeature.TARGET_HUMIDITY + ); + const supportFanMode = supportsFeature( + stateObj, + ClimateEntityFeature.FAN_MODE ); - const supportFanMode = supportsFeature(stateObj, CLIMATE_SUPPORT_FAN_MODE); const supportPresetMode = supportsFeature( stateObj, - CLIMATE_SUPPORT_PRESET_MODE + ClimateEntityFeature.PRESET_MODE ); const supportSwingMode = supportsFeature( stateObj, - CLIMATE_SUPPORT_SWING_MODE + ClimateEntityFeature.SWING_MODE + ); + const supportAuxHeat = supportsFeature( + stateObj, + ClimateEntityFeature.AUX_HEAT ); - const supportAuxHeat = supportsFeature(stateObj, CLIMATE_SUPPORT_AUX_HEAT); const temperatureStepSize = stateObj.attributes.target_temp_step || @@ -94,7 +99,12 @@ class MoreInfoClimate extends LitElement { ${supportTargetTemperature || supportTargetTemperatureRange ? html`
- ${hass.localize("ui.card.climate.target_temperature")} + ${computeAttributeNameDisplay( + hass.localize, + stateObj, + hass.entities, + "temperature" + )}
` : ""} @@ -145,7 +155,14 @@ class MoreInfoClimate extends LitElement { ${supportTargetHumidity ? html`
-
${hass.localize("ui.card.climate.target_humidity")}
+
+ ${computeAttributeNameDisplay( + hass.localize, + stateObj, + hass.entities, + "humidity" + )} +
${stateObj.attributes.humidity} % @@ -182,7 +199,13 @@ class MoreInfoClimate extends LitElement { .map( (mode) => html` - ${hass.localize(`component.climate.state._.${mode}`)} + ${computeStateDisplay( + hass.localize, + stateObj, + hass.locale, + hass.entities, + mode + )} ` )} @@ -194,7 +217,12 @@ class MoreInfoClimate extends LitElement { ? html`
html` - ${hass.localize( - `state_attributes.climate.preset_mode.${mode}` - ) || mode} + ${computeAttributeValueDisplay( + hass.localize, + stateObj, + hass.entities, + "preset_mode", + mode + )} ` )} @@ -218,7 +250,12 @@ class MoreInfoClimate extends LitElement { ? html`
html` - ${hass.localize( - `state_attributes.climate.fan_mode.${mode}` - ) || mode} + ${computeAttributeValueDisplay( + hass.localize, + stateObj, + hass.entities, + "fan_mode", + mode + )} ` )} @@ -242,7 +283,12 @@ class MoreInfoClimate extends LitElement { ? html`
${stateObj.attributes.swing_modes!.map( (mode) => html` - ${mode} + + ${computeAttributeValueDisplay( + hass.localize, + stateObj, + hass.entities, + "swing_mode", + mode + )} + ` )} @@ -263,7 +317,12 @@ class MoreInfoClimate extends LitElement {
- ${hass.localize("ui.card.climate.aux_heat")} + ${computeAttributeNameDisplay( + hass.localize, + stateObj, + hass.entities, + "aux_heat" + )}
${ stateObj.attributes.hvac_action - ? this.hass!.localize( - `state_attributes.climate.hvac_action.${stateObj.attributes.hvac_action}` + ? computeAttributeValueDisplay( + this.hass.localize, + stateObj, + this.hass.entities, + "hvac_action" ) - : this.hass!.localize( - `component.climate.state._.${stateObj.state}` + : computeStateDisplay( + this.hass.localize, + stateObj, + this.hass.locale, + this.hass.entities ) } ${ @@ -225,9 +233,12 @@ export class HuiThermostatCard extends LitElement implements LovelaceCard { stateObj.attributes.preset_mode !== CLIMATE_PRESET_NONE ? html` - - ${this.hass!.localize( - `state_attributes.climate.preset_mode.${stateObj.attributes.preset_mode}` - ) || stateObj.attributes.preset_mode} + ${computeAttributeValueDisplay( + this.hass.localize, + stateObj, + this.hass.entities, + "preset_mode" + )} ` : "" } diff --git a/src/translations/en.json b/src/translations/en.json index b8bebcaf5f..f8415ad180 100755 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -22,31 +22,6 @@ } }, "state_attributes": { - "climate": { - "fan_mode": { - "off": "Off", - "on": "On", - "auto": "Auto" - }, - "preset_mode": { - "none": "None", - "eco": "Eco", - "away": "Away", - "boost": "Boost", - "comfort": "Comfort", - "home": "Home", - "sleep": "Sleep", - "activity": "Activity" - }, - "hvac_action": { - "off": "Off", - "heating": "Heating", - "cooling": "Cooling", - "drying": "Drying", - "idle": "Idle", - "fan": "Fan" - } - }, "humidifier": { "mode": { "normal": "Normal", @@ -140,7 +115,6 @@ "climate": { "currently": "Currently", "on_off": "On / off", - "target_temperature": "Target temperature", "target_temperature_entity": "{name} target temperature", "target_temperature_mode": "{name} target temperature {mode}", "current_temperature": "{name} current temperature", @@ -148,13 +122,8 @@ "cooling": "{name} cooling", "high": "high", "low": "low", - "target_humidity": "Target humidity", "operation": "Operation", - "fan_mode": "Fan mode", - "swing_mode": "Swing mode", - "preset_mode": "Preset", - "away_mode": "Away mode", - "aux_heat": "Aux heat" + "away_mode": "Away mode" }, "counter": { "actions": {