From cd65be7a0799aebc177977b66a4e5d165aacc28e Mon Sep 17 00:00:00 2001 From: Home Assistant Version Control Date: Mon, 28 Sep 2026 14:45:59 +0000 Subject: [PATCH] 35 files --- .storage/lovelace_resources | 2 +- custom_components/midea_ac_lan/__init__.py | 14 +- custom_components/midea_ac_lan/climate.py | 129 +- custom_components/midea_ac_lan/manifest.json | 7 +- .../midea_ac_lan/midea_devices.py | 1182 ++++++++++++++++- .../midea_ac_lan/midea_entity.py | 14 + .../midea_ac_lan/translations/de.json | 396 +++++- .../midea_ac_lan/translations/en.json | 396 +++++- .../midea_ac_lan/translations/es.json | 396 +++++- .../midea_ac_lan/translations/fr.json | 396 +++++- .../midea_ac_lan/translations/hu.json | 396 +++++- .../midea_ac_lan/translations/it.json | 396 +++++- .../midea_ac_lan/translations/ru.json | 396 +++++- .../midea_ac_lan/translations/sk.json | 396 +++++- .../midea_ac_lan/translations/zh-Hans.json | 398 +++++- custom_components/spook/__init__.py | 8 + .../repairs/unknown_entity_references.py | 1 + .../group/repairs/unknown_members.py | 1 + .../repairs/unknown_entity_references.py | 1 + .../repairs/unknown_ignored_zones.py | 1 + .../repairs/unknown_tracked_entities.py | 1 + .../proximity/repairs/unknown_zone.py | 1 + .../repairs/unknown_entity_references.py | 1 + .../repairs/unknown_entity_references.py | 26 +- custom_components/spook/entity_filtering.py | 101 +- .../integrations/spook_inverse/manifest.json | 2 +- .../spook_inverse/translations/sr_Latn.json | 2 +- custom_components/spook/manifest.json | 2 +- custom_components/spook/repairs.py | 193 ++- custom_components/spook/translations/de.json | 8 +- custom_components/spook/translations/en.json | 32 +- .../spook/translations/sr-Latn.json | 4 +- .../multiple-entity-row.js | 2 +- .../multiple-entity-row.js.gz | Bin 27261 -> 27566 bytes zigbee2mqtt/state.json | 44 +- 35 files changed, 5212 insertions(+), 133 deletions(-) diff --git a/.storage/lovelace_resources b/.storage/lovelace_resources index 3471513c..a4b1908a 100644 --- a/.storage/lovelace_resources +++ b/.storage/lovelace_resources @@ -196,7 +196,7 @@ }, { "id": "e92ef0caff41454e9f49ea966ed99e41", - "url": "/hacsfiles/lovelace-multiple-entity-row/multiple-entity-row.js?hacstag=1789210374111", + "url": "/hacsfiles/lovelace-multiple-entity-row/multiple-entity-row.js?hacstag=1789210374120", "type": "module" }, { diff --git a/custom_components/midea_ac_lan/__init__.py b/custom_components/midea_ac_lan/__init__.py index 72e5e54c..e66f29a0 100644 --- a/custom_components/midea_ac_lan/__init__.py +++ b/custom_components/midea_ac_lan/__init__.py @@ -159,14 +159,12 @@ async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool: # ruff: item = None if dev_ := MIDEA_DEVICES.get(dev.device_type): item = cast("dict", dev_["entities"]).get(attr) - if ( - item - and (item.get("type") in EXTRA_SWITCH) - or ( - dev.device_type == DeviceType.AC - and attr == "fan_speed" - and value in range(103) - ) + if item is not None and item.get("type") in EXTRA_SWITCH: + dev.set_attribute(attr=item.get("attribute", attr), value=value) + elif ( + dev.device_type == DeviceType.AC + and attr == "fan_speed" + and value in range(103) ): dev.set_attribute(attr=attr, value=value) else: diff --git a/custom_components/midea_ac_lan/climate.py b/custom_components/midea_ac_lan/climate.py index 49538b27..189e6143 100644 --- a/custom_components/midea_ac_lan/climate.py +++ b/custom_components/midea_ac_lan/climate.py @@ -44,6 +44,8 @@ from homeassistant.helpers.entity_platform import AddEntitiesCallback from midealan.device import DeviceType from midealan.devices.ac import DeviceAttributes as ACAttributes from midealan.devices.ac import MideaACDevice +from midealan.devices.c1 import DeviceAttributes as C1Attributes +from midealan.devices.c1 import MideaC1Device from midealan.devices.c3 import DeviceAttributes as C3Attributes from midealan.devices.c3 import MideaC3Device from midealan.devices.cc import DeviceAttributes as CCAttributes @@ -83,6 +85,7 @@ async def async_setup_entry( | MideaCCClimate | MideaCFClimate | MideaC3Climate + | MideaC1Climate | MideaFBClimate | MideaEDTeaBarClimate ] = [] @@ -104,6 +107,8 @@ async def async_setup_entry( devs.append(MideaCFClimate(device, entity_key)) elif device.device_type == DeviceType.C3: devs.append(MideaC3Climate(device, entity_key, config["zone"])) + elif device.device_type == DeviceType.C1: + devs.append(MideaC1Climate(device, entity_key)) elif device.device_type == DeviceType.FB: devs.append(MideaFBClimate(device, entity_key)) elif device.device_type == DeviceType.ED: @@ -111,9 +116,10 @@ async def async_setup_entry( async_add_entities(devs) -type MideaClimateDevice = ( +type MideaSetTemperatureDevice = ( MideaACDevice | MideaCCDevice | MideaCFDevice | MideaC3Device | MideaFBDevice ) +type MideaClimateDevice = MideaSetTemperatureDevice | MideaC1Device class MideaClimate(MideaEntity, ClimateEntity): @@ -211,7 +217,8 @@ class MideaClimate(MideaEntity, ClimateEntity): else: try: mode = self.hvac_modes.index(hvac_mode.lower()) if hvac_mode else None - self._device.set_target_temperature( + target_device = cast("MideaSetTemperatureDevice", self._device) + target_device.set_target_temperature( target_temperature=temperature, mode=mode, zone=None, @@ -1019,6 +1026,124 @@ class MideaC3Climate(MideaClimate): self._device.set_mode(self._zone, self.hvac_modes.index(hvac_mode)) +class MideaC1Climate(MideaClimate): + """Midea C1 electric wall-hung boiler (space heating as climate).""" + + _device: MideaC1Device + + _attr_max_temp: float = 60 + _attr_min_temp: float = 30 + _attr_target_temperature_high: float | None = 60 + _attr_target_temperature_low: float | None = 30 + _attr_target_temperature_step: float | None = PRECISION_WHOLE + + def __init__(self, device: MideaC1Device, entity_key: str) -> None: + """Midea C1 climate entity init.""" + super().__init__(device, entity_key) + self._attr_hvac_modes = [HVACMode.OFF, HVACMode.HEAT] + self._attr_preset_modes: list[str] = self._device.heating_modes + + @property + def supported_features(self) -> ClimateEntityFeature: + """Midea C1 climate supported features.""" + features = ( + ClimateEntityFeature.TARGET_TEMPERATURE | ClimateEntityFeature.PRESET_MODE + ) + if (MAJOR_VERSION, MINOR_VERSION) >= (2024, 2): + features |= ClimateEntityFeature.TURN_OFF | ClimateEntityFeature.TURN_ON + return features + + @property + def hvac_mode(self) -> HVACMode: + """Midea C1 climate hvac mode.""" + return ( + HVACMode.HEAT + if self._device.get_attribute(C1Attributes.power) + else HVACMode.OFF + ) + + @property + def preset_mode(self) -> str: + """Midea C1 climate preset mode (comfort / activity / sleep).""" + mode = cast("str", self._device.get_attribute(C1Attributes.heating_mode)) + if mode == "unknown" and self._attr_preset_modes: + return self._attr_preset_modes[0] + return mode + + @property + def current_temperature(self) -> float | None: + """Midea C1 climate current temperature.""" + raw = self._device.get_attribute(C1Attributes.current_temperature) + if isinstance(raw, int | float): + return float(raw) + return None + + @property + def target_temperature(self) -> float: + """Midea C1 climate heating target setpoint.""" + raw = self._device.get_attribute(C1Attributes.heating_target_temperature) + if isinstance(raw, int | float): + return float(raw) + return float(self.min_temp) + + def set_temperature(self, **kwargs: Any) -> None: # ruff:ignore[any-type] + """Midea C1 climate set heating target temperature.""" + if ATTR_TEMPERATURE not in kwargs: + return + temperature = float(round(float(kwargs[ATTR_TEMPERATURE]))) + hvac_mode = kwargs.get(ATTR_HVAC_MODE) + if hvac_mode == HVACMode.OFF: + self.turn_off() + return + # Writing heating_target_temperature only sends MessageSetHeating, not a + # power-on command. When the service call carries an explicit non-OFF + # mode, turn the boiler on first so a combined change on an off device + # actually starts heating instead of silently staying off. + if hvac_mode is not None: + self.turn_on() + self._device.set_attribute( + attr=C1Attributes.heating_target_temperature, + value=temperature, + ) + + def set_hvac_mode(self, hvac_mode: HVACMode) -> None: + """Midea C1 climate set hvac mode.""" + if hvac_mode == HVACMode.OFF: + self.turn_off() + else: + self.turn_on() + + def set_preset_mode(self, preset_mode: str) -> None: + """Midea C1 climate set heating schedule mode. + + Send the requested preset's own stored setpoint together with the mode + change. The device library's plain ``heating_mode`` setter re-applies + the cached general ``heating_target_temperature`` under the new mode, so + switching presets would otherwise carry over the previous mode's target + instead of that preset's per-mode setpoint. Fall back to the plain mode + change when the per-mode setpoint has not been reported yet. + """ + # Lua mode codes: user=1, activity=2, sleep=3 (see midealan c1.message). + per_mode = { + "user": (1, C1Attributes.user_mode_target_temperature), + "activity": (2, C1Attributes.activity_mode_target_temperature), + "sleep": (3, C1Attributes.sleep_mode_target_temperature), + }.get(preset_mode) + if per_mode is not None: + mode_code, per_mode_attr = per_mode + raw = self._device.get_attribute(per_mode_attr) + if isinstance(raw, int | float): + self._device.set_heating_target_temperature( + float(raw), + heating_mode=mode_code, + ) + return + self._device.set_attribute( + attr=C1Attributes.heating_mode, + value=preset_mode, + ) + + class MideaFBClimate(MideaClimate): """Midea FB Climate Entries.""" diff --git a/custom_components/midea_ac_lan/manifest.json b/custom_components/midea_ac_lan/manifest.json index cc73b01e..3a40a002 100644 --- a/custom_components/midea_ac_lan/manifest.json +++ b/custom_components/midea_ac_lan/manifest.json @@ -2,8 +2,7 @@ "domain": "midea_ac_lan", "name": "Midea AC LAN", "codeowners": [ - "@wuwentao", - "@caibinqing" + "@wuwentao" ], "config_flow": true, "dependencies": [], @@ -15,7 +14,7 @@ "midealan" ], "requirements": [ - "midea-lan==2026.9.1" + "midea-lan==2026.9.2" ], - "version": "2026.9.1" + "version": "2026.9.2" } diff --git a/custom_components/midea_ac_lan/midea_devices.py b/custom_components/midea_ac_lan/midea_devices.py index 5d52fb3b..9f1dfd81 100644 --- a/custom_components/midea_ac_lan/midea_devices.py +++ b/custom_components/midea_ac_lan/midea_devices.py @@ -20,7 +20,9 @@ from homeassistant.const import ( UnitOfTemperature, UnitOfTime, UnitOfVolume, + UnitOfVolumeFlowRate, ) +from homeassistant.helpers.entity import EntityCategory # HA 2026.7 added UnitOfDensity/UnitOfRatio, and HA 2026.8 started deprecating # CONCENTRATION_MICROGRAMS_PER_CUBIC_METER / CONCENTRATION_PARTS_PER_MILLION in favor of @@ -53,6 +55,7 @@ from midealan.devices.b6 import DeviceAttributes as B6Attributes from midealan.devices.bf import WORK_MODE_MAP as BF_WORK_MODE_MAP from midealan.devices.bf import DeviceAttributes as BFAttributes from midealan.devices.bf import FirePower as BFFirePower +from midealan.devices.c1 import DeviceAttributes as C1Attributes from midealan.devices.c2 import DeviceAttributes as C2Attributes from midealan.devices.c3 import DeviceAttributes as C3Attributes from midealan.devices.ca import DeviceAttributes as CAAttributes @@ -90,7 +93,6 @@ ED_SOFT_WATER_SUBTYPES = [703] BF_WORK_MODES = list(BF_WORK_MODE_MAP) BF_FIRE_POWERS = list(BFFirePower.__members__) BF_TEMPERATURES = list(range(251)) - # C3 outdoor-unit telemetry attributes. Referenced by string so the entity # table still imports on a midea-lan release that predates the parser support; # the matching sensors carry a required_attribute guard and are skipped there. @@ -595,6 +597,12 @@ MIDEA_DEVICES: dict[int, dict[str, dict[str, Any] | str]] = { "name": "Self Clean", "icon": "mdi:air-filter", }, + ACAttributes.degerming: { + "type": Platform.SWITCH, + "translation_key": "degerming", + "name": "Degerming", + "icon": "mdi:bacteria-outline", + }, ACAttributes.ieco: { "type": Platform.SWITCH, "translation_key": "ieco", @@ -638,7 +646,7 @@ MIDEA_DEVICES: dict[int, dict[str, dict[str, Any] | str]] = { "name": "Total Energy Consumption", "device_class": SensorDeviceClass.ENERGY, "unit": UnitOfEnergy.KILO_WATT_HOUR, - "state_class": SensorStateClass.TOTAL_INCREASING, + "state_class": SensorStateClass.TOTAL, }, ACAttributes.current_energy_consumption: { "type": Platform.SENSOR, @@ -646,7 +654,7 @@ MIDEA_DEVICES: dict[int, dict[str, dict[str, Any] | str]] = { "name": "Current Energy Consumption", "device_class": SensorDeviceClass.ENERGY, "unit": UnitOfEnergy.KILO_WATT_HOUR, - "state_class": SensorStateClass.TOTAL_INCREASING, + "state_class": SensorStateClass.TOTAL, }, ACAttributes.realtime_power: { "type": Platform.SENSOR, @@ -1076,6 +1084,20 @@ MIDEA_DEVICES: dict[int, dict[str, dict[str, Any] | str]] = { "unit": UnitOfTime.SECONDS, "state_class": SensorStateClass.MEASUREMENT, }, + B1Attributes.mode: { + "type": Platform.SENSOR, + "translation_key": "mode", + "name": "Mode", + "icon": "mdi:chef-hat", + }, + B1Attributes.target_temperature: { + "type": Platform.SENSOR, + "translation_key": "target_temperature", + "name": "Target Temperature", + "device_class": SensorDeviceClass.TEMPERATURE, + "unit": UnitOfTemperature.CELSIUS, + "state_class": SensorStateClass.MEASUREMENT, + }, }, }, 0xB3: { @@ -1305,6 +1327,227 @@ MIDEA_DEVICES: dict[int, dict[str, dict[str, Any] | str]] = { }, }, }, + 0xB8: { + "name": "Robot Vacuum", + "entities": { + "work_status": { + "type": Platform.SENSOR, + "name": "Work Status", + "icon": "mdi:robot-vacuum", + }, + "function_type": { + "type": Platform.SENSOR, + "name": "Function Type", + "icon": "mdi:function", + }, + "control_type": { + "type": Platform.SENSOR, + "name": "Control Type", + "icon": "mdi:remote", + }, + "area": { + "type": Platform.SENSOR, + "name": "Cleaned Area", + "icon": "mdi:floor-plan", + "state_class": SensorStateClass.MEASUREMENT, + }, + "battery_percent": { + "type": Platform.SENSOR, + "name": "Battery", + "device_class": SensorDeviceClass.BATTERY, + "unit": PERCENTAGE, + "state_class": SensorStateClass.MEASUREMENT, + }, + "work_time": { + "type": Platform.SENSOR, + "name": "Work Time", + "icon": "mdi:timer-outline", + "unit": UnitOfTime.MINUTES, + "state_class": SensorStateClass.MEASUREMENT, + }, + "mop": { + "type": Platform.SENSOR, + "name": "Mop State", + "icon": "mdi:water", + }, + "speed": { + "type": Platform.SENSOR, + "name": "Speed", + "icon": "mdi:speedometer", + }, + "error_type": { + "type": Platform.SENSOR, + "name": "Error Type", + "icon": "mdi:alert-circle", + }, + "error_desc": { + "type": Platform.SENSOR, + "name": "Error Description", + "icon": "mdi:alert", + }, + "disturb_start_time": { + "type": Platform.SENSOR, + "name": "Do Not Disturb Start Time", + "icon": "mdi:weather-night", + "required_attribute": "disturb_start_time", + }, + "disturb_end_time": { + "type": Platform.SENSOR, + "name": "Do Not Disturb End Time", + "icon": "mdi:weather-sunny", + "required_attribute": "disturb_end_time", + }, + "side_brush_rest_time": { + "type": Platform.SENSOR, + "name": "Side Brush Remaining Time", + "icon": "mdi:broom", + "state_class": SensorStateClass.MEASUREMENT, + "required_attribute": "side_brush_rest_time", + }, + "side_brush_life_time": { + "type": Platform.SENSOR, + "name": "Side Brush Life Time", + "icon": "mdi:broom", + "state_class": SensorStateClass.MEASUREMENT, + "required_attribute": "side_brush_life_time", + }, + "filter_net_rest_time": { + "type": Platform.SENSOR, + "name": "Filter Remaining Time", + "icon": "mdi:air-filter", + "state_class": SensorStateClass.MEASUREMENT, + "required_attribute": "filter_net_rest_time", + }, + "filter_net_life_time": { + "type": Platform.SENSOR, + "name": "Filter Life Time", + "icon": "mdi:air-filter", + "state_class": SensorStateClass.MEASUREMENT, + "required_attribute": "filter_net_life_time", + }, + "roll_brush_rest_time": { + "type": Platform.SENSOR, + "name": "Roll Brush Remaining Time", + "icon": "mdi:brush", + "state_class": SensorStateClass.MEASUREMENT, + "required_attribute": "roll_brush_rest_time", + }, + "roll_brush_life_time": { + "type": Platform.SENSOR, + "name": "Roll Brush Life Time", + "icon": "mdi:brush", + "state_class": SensorStateClass.MEASUREMENT, + "required_attribute": "roll_brush_life_time", + }, + "have_reserve_task": { + "type": Platform.BINARY_SENSOR, + "name": "Reserve Task", + "icon": "mdi:calendar-clock", + }, + "uv_switch": { + "type": Platform.BINARY_SENSOR, + "name": "UV Light", + "icon": "mdi:lightbulb-on-outline", + }, + "wifi_switch": { + "type": Platform.BINARY_SENSOR, + "name": "Wi-Fi Light", + "icon": "mdi:wifi", + }, + "voice_switch": { + "type": Platform.BINARY_SENSOR, + "name": "Voice Prompt", + "icon": "mdi:volume-high", + }, + "command_source": { + "type": Platform.BINARY_SENSOR, + "name": "Command Source", + "icon": "mdi:flash", + }, + "device_error": { + "type": Platform.BINARY_SENSOR, + "name": "Device Error", + "icon": "mdi:alert-circle", + "device_class": BinarySensorDeviceClass.PROBLEM, + }, + "carpet_switch": { + "type": Platform.BINARY_SENSOR, + "name": "Carpet Detection", + "icon": "mdi:rug", + }, + "board_communication_error": { + "type": Platform.BINARY_SENSOR, + "name": "Board Communication Error", + "icon": "mdi:alert-circle", + "device_class": BinarySensorDeviceClass.PROBLEM, + }, + "laser_sensor_shelter": { + "type": Platform.BINARY_SENSOR, + "name": "Laser Sensor Shelter", + "icon": "mdi:alert-circle", + "device_class": BinarySensorDeviceClass.PROBLEM, + }, + "laser_sensor_error": { + "type": Platform.BINARY_SENSOR, + "name": "Laser Sensor Error", + "icon": "mdi:alert-circle", + "device_class": BinarySensorDeviceClass.PROBLEM, + }, + "disturb_switch": { + "type": Platform.BINARY_SENSOR, + "name": "Do Not Disturb", + "icon": "mdi:minus-circle", + "required_attribute": "disturb_switch", + }, + "clean_mode": { + "type": Platform.SELECT, + "name": "Clean Mode", + "options": "clean_modes", + "icon": "mdi:robot-vacuum", + }, + "fan_level": { + "type": Platform.SELECT, + "name": "Fan Level", + "options": "fan_levels", + "icon": "mdi:fan", + }, + "water_level": { + "type": Platform.SELECT, + "name": "Water Level", + "options": "water_levels", + "icon": "mdi:water", + }, + "speak_level": { + "type": Platform.SELECT, + "name": "Speak Level", + "options": "speak_levels", + "icon": "mdi:volume-high", + "required_attribute": "speak_level", + }, + "move_direction": { + "type": Platform.SELECT, + "name": "Move Direction", + "options": "move_directions", + "icon": "mdi:arrow-decision", + }, + "work_status_control": { + "type": Platform.SELECT, + "name": "Work Status Control", + "attribute": "work_status", + "options": "work_status_controls", + "icon": "mdi:robot-vacuum", + }, + "voice_volume": { + "type": Platform.NUMBER, + "name": "Voice Volume", + "icon": "mdi:volume-high", + "min": 0, + "max": 100, + "step": 1, + "unit": PERCENTAGE, + }, + }, + }, 0xBF: { "name": "Microwave Steam Oven", "entities": { @@ -1619,6 +1862,189 @@ MIDEA_DEVICES: dict[int, dict[str, dict[str, Any] | str]] = { }, }, }, + 0xC1: { + "name": "Electric Wall-hung Boiler", + "entities": { + "climate": { + "type": Platform.CLIMATE, + "icon": "mdi:radiator", + "default": True, + }, + C1Attributes.power: { + "type": Platform.SWITCH, + "translation_key": "power", + "name": "Power", + "icon": "mdi:power", + "default": True, + }, + C1Attributes.heating_target_temperature: { + "type": Platform.NUMBER, + "translation_key": "heating_target_temperature", + "name": "Heating Target Temperature", + "icon": "mdi:thermometer-lines", + "device_class": NumberDeviceClass.TEMPERATURE, + "unit": UnitOfTemperature.CELSIUS, + "min": 30, + "max": 60, + "step": "temperature_step", + "default": True, + }, + C1Attributes.heating_mode: { + "type": Platform.SELECT, + "translation_key": "heating_mode", + "name": "Heating Mode", + "icon": "mdi:radiator", + "options": "heating_modes", + "default": True, + }, + C1Attributes.status: { + "type": Platform.SENSOR, + "translation_key": "status", + "name": "Status", + "icon": "mdi:radiator", + }, + C1Attributes.error_code: { + "type": Platform.SENSOR, + "translation_key": "error_code", + "name": "Error Code", + "icon": "mdi:alert-circle", + }, + C1Attributes.three_way_mode: { + "type": Platform.SENSOR, + "translation_key": "three_way_mode", + "name": "Three-way Mode", + "icon": "mdi:valve", + }, + C1Attributes.heating_unit_type: { + "type": Platform.SENSOR, + "translation_key": "heating_unit_type", + "name": "Heating Unit Type", + "icon": "mdi:heating-coil", + }, + C1Attributes.return_temperature: { + "type": Platform.SENSOR, + "translation_key": "return_temperature", + "name": "Return Temperature", + "device_class": SensorDeviceClass.TEMPERATURE, + "unit": UnitOfTemperature.CELSIUS, + "state_class": SensorStateClass.MEASUREMENT, + }, + C1Attributes.current_temperature: { + "type": Platform.SENSOR, + "name": "Current Temperature", + "device_class": SensorDeviceClass.TEMPERATURE, + "unit": UnitOfTemperature.CELSIUS, + "state_class": SensorStateClass.MEASUREMENT, + }, + C1Attributes.heating_temperature: { + "type": Platform.SENSOR, + "translation_key": "heating_temperature", + "name": "Heating Temperature", + "device_class": SensorDeviceClass.TEMPERATURE, + "unit": UnitOfTemperature.CELSIUS, + "state_class": SensorStateClass.MEASUREMENT, + }, + C1Attributes.heating_gap_temperature: { + "type": Platform.SENSOR, + "translation_key": "heating_gap_temperature", + "name": "Heating Gap Temperature", + "icon": "mdi:thermometer-lines", + "device_class": SensorDeviceClass.TEMPERATURE, + "unit": UnitOfTemperature.CELSIUS, + "state_class": SensorStateClass.MEASUREMENT, + }, + C1Attributes.user_mode_target_temperature: { + "type": Platform.SENSOR, + "translation_key": "user_mode_target_temperature", + "name": "User Mode Target Temperature", + "device_class": SensorDeviceClass.TEMPERATURE, + "unit": UnitOfTemperature.CELSIUS, + "state_class": SensorStateClass.MEASUREMENT, + }, + C1Attributes.activity_mode_target_temperature: { + "type": Platform.SENSOR, + "translation_key": "activity_mode_target_temperature", + "name": "Activity Mode Target Temperature", + "device_class": SensorDeviceClass.TEMPERATURE, + "unit": UnitOfTemperature.CELSIUS, + "state_class": SensorStateClass.MEASUREMENT, + }, + C1Attributes.sleep_mode_target_temperature: { + "type": Platform.SENSOR, + "translation_key": "sleep_mode_target_temperature", + "name": "Sleep Mode Target Temperature", + "device_class": SensorDeviceClass.TEMPERATURE, + "unit": UnitOfTemperature.CELSIUS, + "state_class": SensorStateClass.MEASUREMENT, + }, + C1Attributes.last_time: { + "type": Platform.SENSOR, + "translation_key": "last_time", + "name": "Last Time", + "icon": "mdi:timer-outline", + "unit": UnitOfTime.MINUTES, + "state_class": SensorStateClass.MEASUREMENT, + }, + C1Attributes.flow_volume: { + "type": Platform.SENSOR, + "translation_key": "flow_volume", + "name": "Flow Rate", + "icon": "mdi:water", + "device_class": SensorDeviceClass.VOLUME_FLOW_RATE, + "unit": UnitOfVolumeFlowRate.LITERS_PER_MINUTE, + "state_class": SensorStateClass.MEASUREMENT, + }, + C1Attributes.standby: { + "type": Platform.BINARY_SENSOR, + "translation_key": "standby", + "name": "Standby", + "icon": "mdi:power-standby", + "device_class": BinarySensorDeviceClass.RUNNING, + }, + C1Attributes.heating: { + "type": Platform.BINARY_SENSOR, + "translation_key": "heating", + "name": "Heating", + "icon": "mdi:heat-wave", + "device_class": BinarySensorDeviceClass.RUNNING, + }, + C1Attributes.warm_power: { + "type": Platform.BINARY_SENSOR, + "translation_key": "warm_power", + "name": "Warm Power", + "icon": "mdi:radiator", + "device_class": BinarySensorDeviceClass.RUNNING, + }, + C1Attributes.cold_power: { + "type": Platform.BINARY_SENSOR, + "translation_key": "cold_power", + "name": "Cold Power", + "icon": "mdi:snowflake", + "device_class": BinarySensorDeviceClass.RUNNING, + }, + C1Attributes.sleep_power: { + "type": Platform.BINARY_SENSOR, + "translation_key": "sleep_power", + "name": "Sleep Power", + "icon": "mdi:sleep", + "device_class": BinarySensorDeviceClass.RUNNING, + }, + C1Attributes.pump_on: { + "type": Platform.BINARY_SENSOR, + "translation_key": "pump_on", + "name": "Pump On", + "icon": "mdi:pump", + "device_class": BinarySensorDeviceClass.RUNNING, + }, + C1Attributes.fault: { + "type": Platform.BINARY_SENSOR, + "translation_key": "fault", + "name": "Fault", + "icon": "mdi:alert", + "device_class": BinarySensorDeviceClass.PROBLEM, + }, + }, + }, 0xC2: { "name": "Toilet", "entities": { @@ -1744,8 +2170,8 @@ MIDEA_DEVICES: dict[int, dict[str, dict[str, Any] | str]] = { }, C3Attributes.disinfect: { "type": Platform.SWITCH, - "translation_key": "disinfect", - "name": "Disinfect", + "translation_key": "dhw_disinfect", + "name": "DHW - Disinfect", "icon": "mdi:water-plus-outline", }, C3Attributes.dhw_power: { @@ -1784,6 +2210,7 @@ MIDEA_DEVICES: dict[int, dict[str, dict[str, Any] | str]] = { "translation_key": "tbh", "name": "TBH", "icon": "mdi:water-boiler", + "default": False, }, C3Attributes.zone1_curve: { "type": Platform.SWITCH, @@ -1905,6 +2332,7 @@ MIDEA_DEVICES: dict[int, dict[str, dict[str, Any] | str]] = { }, C3Attributes.temp_tw_in: { "type": Platform.SENSOR, + "translation_key": "temp_tw_in", "name": "Water Inlet Temperature", "device_class": SensorDeviceClass.TEMPERATURE, "unit": UnitOfTemperature.CELSIUS, @@ -1912,18 +2340,451 @@ MIDEA_DEVICES: dict[int, dict[str, dict[str, Any] | str]] = { }, C3Attributes.temp_tw_out: { "type": Platform.SENSOR, + "translation_key": "temp_tw_out", "name": "Water Outlet Temperature", "device_class": SensorDeviceClass.TEMPERATURE, "unit": UnitOfTemperature.CELSIUS, "state_class": SensorStateClass.MEASUREMENT, }, + # ---- Newly exposed C3 attributes (device capability + telemetry) ---- + C3Attributes.holiday_on: { + "type": Platform.SWITCH, + "translation_key": "holiday_on", + "name": "Holiday Mode", + "icon": "mdi:palm-tree", + }, + C3Attributes.status_cool: { + "type": Platform.BINARY_SENSOR, + "translation_key": "status_cool", + "name": "Cooling status", + "icon": "mdi:snowflake", + "device_class": BinarySensorDeviceClass.RUNNING, + }, + C3Attributes.eco_function_state: { + "type": Platform.BINARY_SENSOR, + "translation_key": "eco_function_state", + "name": "ECO Function", + "icon": "mdi:leaf", + "device_class": BinarySensorDeviceClass.RUNNING, + }, + C3Attributes.eco_timer_state: { + "type": Platform.BINARY_SENSOR, + "translation_key": "eco_timer_state", + "name": "ECO Timer", + "icon": "mdi:leaf-clock", + "device_class": BinarySensorDeviceClass.RUNNING, + }, + C3Attributes.heat: { + "type": Platform.BINARY_SENSOR, + "translation_key": "heat_capability", + "name": "Heat Capability", + "icon": "mdi:fire", + }, + C3Attributes.cool: { + "type": Platform.BINARY_SENSOR, + "translation_key": "cool_capability", + "name": "Cool Capability", + "icon": "mdi:snowflake", + }, + C3Attributes.dhw: { + "type": Platform.BINARY_SENSOR, + "translation_key": "dhw_capability", + "name": "DHW Capability", + "icon": "mdi:water-boiler", + }, + C3Attributes.double_zone: { + "type": Platform.BINARY_SENSOR, + "translation_key": "double_zone", + "name": "Double Zone Enabled", + "icon": "mdi:home-floor-2", + }, + C3Attributes.room_thermal_support: { + "type": Platform.BINARY_SENSOR, + "translation_key": "room_thermal_support", + "name": "Room Thermostat Support", + "icon": "mdi:thermostat", + }, + C3Attributes.room_thermal_state: { + "type": Platform.BINARY_SENSOR, + "translation_key": "room_thermal_state", + "name": "Room Thermostat State", + "icon": "mdi:thermostat", + "device_class": BinarySensorDeviceClass.RUNNING, + }, + C3Attributes.time_set: { + "type": Platform.BINARY_SENSOR, + "translation_key": "time_set", + "name": "Time Set", + "icon": "mdi:clock-check", + }, + C3Attributes.disinfect_run: { + "type": Platform.BINARY_SENSOR, + "translation_key": "disinfect_run", + "name": "Disinfect Running", + "icon": "mdi:water-plus", + "device_class": BinarySensorDeviceClass.RUNNING, + }, + C3Attributes.remote_onoff: { + "type": Platform.BINARY_SENSOR, + "translation_key": "remote_onoff", + "name": "Remote On/Off", + "icon": "mdi:remote", + }, + C3Attributes.tbh_control: { + "type": Platform.BINARY_SENSOR, + "translation_key": "tbh_control", + "name": "TBH Control", + "icon": "mdi:water-boiler", + }, + C3Attributes.sys_energy_ana_en: { + "type": Platform.BINARY_SENSOR, + "translation_key": "sys_energy_ana_en", + "name": "System Energy Analysis Enabled", + "icon": "mdi:chart-line", + }, + C3Attributes.hmi_energy_ana_set_en: { + "type": Platform.BINARY_SENSOR, + "translation_key": "hmi_energy_ana_set_en", + "name": "HMI Energy Analysis Set Enabled", + "icon": "mdi:chart-line", + }, + # NOTE: comp_run_freq, fan_speed, unit_mode_run, temp_t1, temp_t2, + # temp_t2b and temp_t3 are provided by upstream's required_attribute + # -guarded telemetry block further below (from midea_ac_lan main), + # which also fixes unit_mode_run's options (int-keyed, matching the + # library's actual int return type) - do not re-add direct + # C3Attributes references for them here. + C3Attributes.temp_t4: { + "type": Platform.SENSOR, + "translation_key": "temp_t4", + "name": "Outdoor Ambient Temperature (T4)", + "device_class": SensorDeviceClass.TEMPERATURE, + "unit": UnitOfTemperature.CELSIUS, + "state_class": SensorStateClass.MEASUREMENT, + }, + C3Attributes.temp_t5: { + "type": Platform.SENSOR, + "translation_key": "temp_t5", + "name": "Water Tank Temperature (T5)", + "device_class": SensorDeviceClass.TEMPERATURE, + "unit": UnitOfTemperature.CELSIUS, + "state_class": SensorStateClass.MEASUREMENT, + }, + C3Attributes.temp_ta: { + "type": Platform.SENSOR, + "translation_key": "temp_ta", + "name": "Room Ambient Temperature (Ta)", + "device_class": SensorDeviceClass.TEMPERATURE, + "unit": UnitOfTemperature.CELSIUS, + "state_class": SensorStateClass.MEASUREMENT, + }, + # NOTE: temp_tp and temp_th also come from upstream's guarded block. + C3Attributes.temp_tw2: { + "type": Platform.SENSOR, + "translation_key": "temp_tw2", + "name": "Zone 2 Outlet Water Temperature (Tw2)", + "device_class": SensorDeviceClass.TEMPERATURE, + "unit": UnitOfTemperature.CELSIUS, + "state_class": SensorStateClass.MEASUREMENT, + }, + C3Attributes.temp_tb_t1: { + "type": Platform.SENSOR, + "translation_key": "temp_tb_t1", + "name": "Buffer Tank Upper Temperature (Tbt1)", + "device_class": SensorDeviceClass.TEMPERATURE, + "unit": UnitOfTemperature.CELSIUS, + "state_class": SensorStateClass.MEASUREMENT, + }, + C3Attributes.temp_tb_t2: { + "type": Platform.SENSOR, + "translation_key": "temp_tb_t2", + "name": "Buffer Tank Lower Temperature (Tbt2)", + "device_class": SensorDeviceClass.TEMPERATURE, + "unit": UnitOfTemperature.CELSIUS, + "state_class": SensorStateClass.MEASUREMENT, + }, + C3Attributes.temp_tsolar: { + "type": Platform.SENSOR, + "translation_key": "temp_tsolar", + "name": "Solar Temperature (Tsolar)", + "device_class": SensorDeviceClass.TEMPERATURE, + "unit": UnitOfTemperature.CELSIUS, + "state_class": SensorStateClass.MEASUREMENT, + }, + # NOTE: pressure_high and pressure_low also come from upstream's + # guarded block. + # midea-lan attribute name has an upstream typo (water_flower) + C3Attributes.water_flower: { + "type": Platform.SENSOR, + "translation_key": "water_flow", + "name": "Water Flow Rate", + "icon": "mdi:water-pump", + "device_class": SensorDeviceClass.VOLUME_FLOW_RATE, + # parser scales to m3/h (raw/100); verified against wired HMI + "unit": UnitOfVolumeFlowRate.CUBIC_METERS_PER_HOUR, + "state_class": SensorStateClass.MEASUREMENT, + }, + C3Attributes.water_pressure: { + "type": Platform.SENSOR, + "translation_key": "water_pressure", + "name": "Water Pressure", + "device_class": SensorDeviceClass.PRESSURE, + "unit": UnitOfPressure.KPA, + "state_class": SensorStateClass.MEASUREMENT, + }, + # NOTE: exv_current (translation_key "exv_current" upstream, was + # "exv_opening") and odu_voltage also come from upstream's guarded + # block. + C3Attributes.dc_current: { + "type": Platform.SENSOR, + "translation_key": "dc_current", + "name": "DC Current", + "device_class": SensorDeviceClass.CURRENT, + "unit": UnitOfElectricCurrent.AMPERE, + "state_class": SensorStateClass.MEASUREMENT, + }, + C3Attributes.dc_bus_voltage: { + "type": Platform.SENSOR, + "translation_key": "dc_bus_voltage", + "name": "DC Bus Voltage", + "device_class": SensorDeviceClass.VOLTAGE, + "unit": UnitOfElectricPotential.VOLT, + "state_class": SensorStateClass.MEASUREMENT, + }, + # NOTE: instant_power (kW, /100 scaled) never made it into + # midea-lan; main exposes the same two raw bytes unscaled as + # current_unit_capacity. Surfaced as a raw diagnostic until a + # future lib PR adds the /100 scaling. + C3Attributes.current_unit_capacity: { + "type": Platform.SENSOR, + "translation_key": "current_unit_capacity", + "name": "Current Unit Capacity (raw)", + "icon": "mdi:heat-wave", + "entity_category": EntityCategory.DIAGNOSTIC, + "state_class": SensorStateClass.MEASUREMENT, + }, C3Attributes.instant_power0: { "type": Platform.SENSOR, - "name": "Current Power", + "translation_key": "instant_power0", + "name": "Power Consumption", + "device_class": SensorDeviceClass.POWER, + # midea-lan returns the raw 16-bit value in watts (unscaled) + "unit": UnitOfPower.WATT, + "state_class": SensorStateClass.MEASUREMENT, + }, + C3Attributes.instant_renew_power0: { + "type": Platform.SENSOR, + "translation_key": "instant_renew_power0", + "name": "Renewable Heating Capacity", "device_class": SensorDeviceClass.POWER, "unit": UnitOfPower.WATT, "state_class": SensorStateClass.MEASUREMENT, }, + # instant_cop (thermal capacity / electrical draw) is not computed + # by midea-lan yet - deferred until a future lib PR adds it. + # --- Pump / valve statuses (LOAD_OUTPUT bitmap, X10 byte[33]) --- + C3Attributes.pump_i_running: { + "type": Platform.BINARY_SENSOR, + "translation_key": "pump_i_running", + "name": "Pump Interior (Pump_I)", + "icon": "mdi:pump", + "device_class": BinarySensorDeviceClass.RUNNING, + }, + C3Attributes.pump_o_running: { + "type": Platform.BINARY_SENSOR, + "translation_key": "pump_o_running", + "name": "Pump Outdoor (Pump_O)", + "icon": "mdi:pump", + "device_class": BinarySensorDeviceClass.RUNNING, + }, + C3Attributes.pump_d_running: { + "type": Platform.BINARY_SENSOR, + "translation_key": "pump_d_running", + "name": "Pump D (Pump_D)", + "icon": "mdi:pump", + "device_class": BinarySensorDeviceClass.RUNNING, + }, + C3Attributes.pump_c_running: { + "type": Platform.BINARY_SENSOR, + "translation_key": "pump_c_running", + "name": "Pump C - Zone 2 (Pump_C, reg129 BIT8)", + "icon": "mdi:pump", + "device_class": BinarySensorDeviceClass.RUNNING, + }, + C3Attributes.pump_s_running: { + "type": Platform.BINARY_SENSOR, + "translation_key": "pump_s_running", + "name": "Pump S - Solar (Pump_S, reg129 BIT11)", + "icon": "mdi:pump", + "device_class": BinarySensorDeviceClass.RUNNING, + "entity_category": EntityCategory.DIAGNOSTIC, + "entity_registry_enabled_default": False, + }, + C3Attributes.sv1_open: { + "type": Platform.BINARY_SENSOR, + "translation_key": "sv1_open", + "name": "3-way Valve DHW (SV1)", + "icon": "mdi:valve", + "device_class": BinarySensorDeviceClass.OPENING, + }, + C3Attributes.sv2_open: { + "type": Platform.BINARY_SENSOR, + "translation_key": "sv2_open", + "name": "Heating Valve (SV2)", + "icon": "mdi:valve", + "device_class": BinarySensorDeviceClass.OPENING, + }, + C3Attributes.load_output_tbh: { + "type": Platform.BINARY_SENSOR, + "translation_key": "load_output_tbh", + "name": "Tank Backup Heater (TBH)", + "icon": "mdi:radiator", + "device_class": BinarySensorDeviceClass.RUNNING, + }, + C3Attributes.ibh1_on: { + "type": Platform.BINARY_SENSOR, + "translation_key": "ibh1_on", + "name": "Electric Heater IBH1", + "icon": "mdi:radiator", + "device_class": BinarySensorDeviceClass.RUNNING, + }, + C3Attributes.ibh2_on: { + "type": Platform.BINARY_SENSOR, + "translation_key": "ibh2_on", + "name": "Electric Heater IBH2", + "icon": "mdi:radiator", + "device_class": BinarySensorDeviceClass.RUNNING, + }, + C3Attributes.sv3_open: { + "type": Platform.BINARY_SENSOR, + "translation_key": "sv3_open", + "name": "3-way Valve SV3", + "icon": "mdi:valve", + "device_class": BinarySensorDeviceClass.OPENING, + "entity_category": EntityCategory.DIAGNOSTIC, + "entity_registry_enabled_default": False, + }, + C3Attributes.crankcase_heater_on: { + "type": Platform.BINARY_SENSOR, + "translation_key": "crankcase_heater_on", + "name": "Crankcase Heater", + "icon": "mdi:heating-coil", + "device_class": BinarySensorDeviceClass.RUNNING, + "entity_category": EntityCategory.DIAGNOSTIC, + "entity_registry_enabled_default": False, + }, + C3Attributes.alarm_on: { + "type": Platform.BINARY_SENSOR, + "translation_key": "alarm_on", + "name": "Alarm (Reg 129 BIT12)", + "icon": "mdi:alert", + "device_class": BinarySensorDeviceClass.PROBLEM, + "entity_category": EntityCategory.DIAGNOSTIC, + "entity_registry_enabled_default": False, + }, + C3Attributes.aux_heat_on: { + "type": Platform.BINARY_SENSOR, + "translation_key": "aux_heat_on", + "name": "Auxiliary Heat Source", + "icon": "mdi:fire", + "device_class": BinarySensorDeviceClass.RUNNING, + "entity_category": EntityCategory.DIAGNOSTIC, + "entity_registry_enabled_default": False, + }, + # ---- New (Aug-18): compressor telemetry ---- + C3Attributes.compressor_on: { + "type": Platform.BINARY_SENSOR, + "translation_key": "compressor_on", + "name": "Compressor Running", + "icon": "mdi:engine", + "device_class": BinarySensorDeviceClass.RUNNING, + }, + # compressor_status_raw superseded by the verified compressor_on + # binary sensor above; no raw diagnostic needed. + # raw_b31, water_circuit_active (b31 bit6) and unit_demand (b31 + # bit5) were this PR's own unverified guesses at the run-state + # byte. midea-lan#83 decoded that byte against the Modbus doc and + # real hardware instead, replacing it with named, verified flags + # (cool_run, heat_run, dhw_run, fact_req_solar_on, + # fact_req_ther_cool_on, fact_req_ther_heat_on, edge_version_type). + # None of those guesses survived, so nothing to alias here; the + # verified flags can be added as their own entities in a follow-up. + # raw_b65 has no Modbus register match and was dropped from the + # library entirely (midea-lan#46 discussion) - no replacement. + # odu_comp_current is provided by upstream's required_attribute + # -guarded telemetry block below. + C3Attributes.room_rel_hum: { + "type": Platform.SENSOR, + "translation_key": "room_rel_hum", + "name": "Room Relative Humidity", + "device_class": SensorDeviceClass.HUMIDITY, + "unit": PERCENTAGE, + "state_class": SensorStateClass.MEASUREMENT, + }, + C3Attributes.comp_total_run_time: { + "type": Platform.SENSOR, + "translation_key": "comp_total_run_time", + "name": "Compressor Total Run Time", + "icon": "mdi:timer-outline", + "device_class": SensorDeviceClass.DURATION, + "unit": UnitOfTime.HOURS, + "state_class": SensorStateClass.TOTAL_INCREASING, + }, + C3Attributes.error_code_description: { + "type": Platform.SENSOR, + "translation_key": "error_code_description", + "name": "Error Description", + "icon": "mdi:alert-circle-outline", + }, + # renamed upstream in midea-lan#81 (HMI serial, not Wi-Fi module's) + C3Attributes.hmi_sn_code: { + "type": Platform.SENSOR, + "translation_key": "hmi_sn_code", + "name": "HMI Serial", + "icon": "mdi:identifier", + }, + # --- Additional low-level diagnostic sensors --- + C3Attributes.hydbox_subtype: { + "type": Platform.SENSOR, + "translation_key": "hydbox_subtype", + "name": "Hydrobox Subtype", + "icon": "mdi:identifier", + }, + C3Attributes.hydrobox_capacity: { + "type": Platform.SENSOR, + "translation_key": "hydrobox_capacity", + "name": "Hydrobox Capacity", + "icon": "mdi:heat-pump-outline", + }, + # IDU / ODU firmware versions - parsed from X10 telemetry + # bytes 94/95 (verified against wired HMI: V14 / V64). + # SW version strings including build date (parsed from X10 tail). + C3Attributes.idu_software_version_str: { + "type": Platform.SENSOR, + "translation_key": "idu_software_version_str", + "name": "IDU Software Version (with date)", + "icon": "mdi:chip", + }, + C3Attributes.odu_software_version_str: { + "type": Platform.SENSOR, + "translation_key": "odu_software_version_str", + "name": "ODU Software Version (with date)", + "icon": "mdi:chip", + }, + C3Attributes.machine_type: { + "type": Platform.SENSOR, + "translation_key": "machine_type", + "name": "Machine Type", + "icon": "mdi:identifier", + }, + C3Attributes.odu_model: { + "type": Platform.SENSOR, + "translation_key": "odu_model", + "name": "Outdoor Unit Model", + "icon": "mdi:identifier", + }, + # odu_target_fre is provided by upstream's required_attribute + # -guarded telemetry block below. # Outdoor-unit runtime telemetry. Parsed by midea-lan since the # MSG_TYPE_UP_UNITPARA / X10 UnitPara work; older library releases # omit these keys, so each carries a required_attribute guard. @@ -1936,6 +2797,8 @@ MIDEA_DEVICES: dict[int, dict[str, dict[str, Any] | str]] = { "unit": UnitOfFrequency.HERTZ, "state_class": SensorStateClass.MEASUREMENT, }, + # fg_capacity_need and temp_tf are provided by upstream's + # required_attribute-guarded telemetry block below. C3_FAN_SPEED: { "type": Platform.SENSOR, "required_attribute": C3_FAN_SPEED, @@ -2080,6 +2943,72 @@ MIDEA_DEVICES: dict[int, dict[str, dict[str, Any] | str]] = { "unit": UnitOfTemperature.CELSIUS, "state_class": SensorStateClass.MEASUREMENT, }, + C3Attributes.t5s: { + "type": Platform.SENSOR, + "translation_key": "t5s", + "name": "Tank Setpoint (T5s)", + "device_class": SensorDeviceClass.TEMPERATURE, + "unit": UnitOfTemperature.CELSIUS, + "state_class": SensorStateClass.MEASUREMENT, + }, + C3Attributes.tas: { + "type": Platform.SENSOR, + "translation_key": "tas", + "name": "Room Ambient Setpoint (Tas)", + "device_class": SensorDeviceClass.TEMPERATURE, + "unit": UnitOfTemperature.CELSIUS, + "state_class": SensorStateClass.MEASUREMENT, + }, + C3Attributes.idu_t1s1: { + "type": Platform.SENSOR, + "translation_key": "idu_t1s1", + "name": "Indoor Unit T1 Setpoint 1", + "device_class": SensorDeviceClass.TEMPERATURE, + "unit": UnitOfTemperature.CELSIUS, + "state_class": SensorStateClass.MEASUREMENT, + }, + C3Attributes.idu_t1s2: { + "type": Platform.SENSOR, + "translation_key": "idu_t1s2", + "name": "Indoor Unit T1 Setpoint 2", + "device_class": SensorDeviceClass.TEMPERATURE, + "unit": UnitOfTemperature.CELSIUS, + "state_class": SensorStateClass.MEASUREMENT, + }, + C3Attributes.zone1_temp_set: { + "type": Platform.SENSOR, + "translation_key": "zone1_temp_set", + "name": "Zone 1 Temperature Setpoint (echo)", + "device_class": SensorDeviceClass.TEMPERATURE, + "unit": UnitOfTemperature.CELSIUS, + "state_class": SensorStateClass.MEASUREMENT, + }, + C3Attributes.zone2_temp_set: { + "type": Platform.SENSOR, + "translation_key": "zone2_temp_set", + "name": "Zone 2 Temperature Setpoint (echo)", + "device_class": SensorDeviceClass.TEMPERATURE, + "unit": UnitOfTemperature.CELSIUS, + "state_class": SensorStateClass.MEASUREMENT, + }, + C3Attributes.disinfect_set_weekday: { + "type": Platform.SENSOR, + "translation_key": "disinfect_set_weekday", + "name": "Disinfect Scheduled Weekday", + "icon": "mdi:calendar-week", + }, + C3Attributes.disinfect_start_hour: { + "type": Platform.SENSOR, + "translation_key": "disinfect_start_hour", + "name": "DHW - Disinfect Start Hour", + "icon": "mdi:clock-outline", + }, + C3Attributes.disinfect_start_minutes: { + "type": Platform.SENSOR, + "translation_key": "disinfect_start_minutes", + "name": "DHW - Disinfect Start Minute", + "icon": "mdi:clock-outline", + }, }, }, 0xCA: { @@ -3460,6 +4389,14 @@ MIDEA_DEVICES: dict[int, dict[str, dict[str, Any] | str]] = { "unit": UnitOfTemperature.CELSIUS, "state_class": SensorStateClass.MEASUREMENT, }, + E2Attributes.top_temp: { + "type": Platform.SENSOR, + "translation_key": "top_temperature", + "name": "Top Temperature", + "device_class": SensorDeviceClass.TEMPERATURE, + "unit": UnitOfTemperature.CELSIUS, + "state_class": SensorStateClass.MEASUREMENT, + }, E2Attributes.heating_time_remaining: { "type": Platform.SENSOR, "translation_key": "heating_time_remaining", @@ -4353,6 +5290,153 @@ MIDEA_DEVICES: dict[int, dict[str, dict[str, Any] | str]] = { 231: "e7_chlorine_sterilization_fault", }, }, + # Water purifier attributes for FF body + EDAttributes.life4: { + "type": Platform.SENSOR, + "translation_key": "filter4_life", + "name": "Filter4 Life Level", + "icon": "mdi:percent", + "unit": PERCENTAGE, + "state_class": SensorStateClass.MEASUREMENT, + }, + EDAttributes.life5: { + "type": Platform.SENSOR, + "translation_key": "filter5_life", + "name": "Filter5 Life Level", + "icon": "mdi:percent", + "unit": PERCENTAGE, + "state_class": SensorStateClass.MEASUREMENT, + }, + EDAttributes.maxlife1: { + "type": Platform.SENSOR, + "translation_key": "filter1_maxlife", + "name": "Filter1 Lifetime Limit", + "icon": "mdi:air-filter", + "unit": UnitOfTime.MONTHS, + "state_class": SensorStateClass.MEASUREMENT, + }, + EDAttributes.maxlife2: { + "type": Platform.SENSOR, + "translation_key": "filter2_maxlife", + "name": "Filter2 Lifetime Limit", + "icon": "mdi:air-filter", + "unit": UnitOfTime.MONTHS, + "state_class": SensorStateClass.MEASUREMENT, + }, + EDAttributes.maxlife3: { + "type": Platform.SENSOR, + "translation_key": "filter3_maxlife", + "name": "Filter3 Lifetime Limit", + "icon": "mdi:air-filter", + "unit": UnitOfTime.MONTHS, + "state_class": SensorStateClass.MEASUREMENT, + }, + EDAttributes.maxlife4: { + "type": Platform.SENSOR, + "translation_key": "filter4_maxlife", + "name": "Filter4 Lifetime Limit", + "icon": "mdi:air-filter", + "unit": UnitOfTime.MONTHS, + "state_class": SensorStateClass.MEASUREMENT, + }, + EDAttributes.maxlife5: { + "type": Platform.SENSOR, + "translation_key": "filter5_maxlife", + "name": "Filter5 Lifetime Limit", + "icon": "mdi:air-filter", + "unit": UnitOfTime.MONTHS, + "state_class": SensorStateClass.MEASUREMENT, + }, + EDAttributes.hot_pot_temperature: { + "type": Platform.SENSOR, + "translation_key": "hot_pot_temperature", + "name": "Hot Pot Temperature", + "device_class": SensorDeviceClass.TEMPERATURE, + "unit": UnitOfTemperature.CELSIUS, + "state_class": SensorStateClass.MEASUREMENT, + }, + EDAttributes.water_kind: { + "type": Platform.SENSOR, + "translation_key": "water_kind", + "name": "Water Kind", + "icon": "mdi:water", + "device_class": SensorDeviceClass.ENUM, + "options": { + 0: "idle", + 2: "warm", + 3: "cold", + }, + }, + EDAttributes.heat_start: { + "type": Platform.SENSOR, + "translation_key": "heat_start", + "name": "Heat Start", + "icon": "mdi:kettle-steam", + "device_class": SensorDeviceClass.ENUM, + "options": { + 1: "heating", + 2: "keep_warm", + }, + }, + EDAttributes.ice_gall_status: { + "type": Platform.SENSOR, + "translation_key": "ice_gall_status", + "name": "Ice Gall Status", + "icon": "mdi:snowflake", + "state_class": SensorStateClass.MEASUREMENT, + }, + EDAttributes.filter: { + "type": Platform.BINARY_SENSOR, + "translation_key": "filter_status", + "name": "Filter Alarm", + "icon": "mdi:air-filter", + "device_class": BinarySensorDeviceClass.PROBLEM, + }, + EDAttributes.standby_status: { + "type": Platform.BINARY_SENSOR, + "translation_key": "standby_status", + "name": "Standby Status", + "icon": "mdi:power-standby", + }, + EDAttributes.out_water: { + "type": Platform.BINARY_SENSOR, + "translation_key": "out_water", + "name": "Out Water", + "icon": "mdi:water-pump", + "device_class": BinarySensorDeviceClass.RUNNING, + }, + EDAttributes.out_hot_water: { + "type": Platform.BINARY_SENSOR, + "translation_key": "out_hot_water", + "name": "Out Hot Water", + "icon": "mdi:water-thermometer", + "device_class": BinarySensorDeviceClass.RUNNING, + }, + EDAttributes.backflow: { + "type": Platform.BINARY_SENSOR, + "translation_key": "backflow", + "name": "Backflow", + "icon": "mdi:water-sync", + "device_class": BinarySensorDeviceClass.RUNNING, + }, + EDAttributes.sleep_status: { + "type": Platform.BINARY_SENSOR, + "translation_key": "sleep_status", + "name": "Sleep Status", + "icon": "mdi:sleep", + }, + EDAttributes.wash: { + "type": Platform.SWITCH, + "translation_key": "wash", + "name": "Filter Wash", + "icon": "mdi:washing-machine", + }, + EDAttributes.antifreeze: { + "type": Platform.SWITCH, + "translation_key": "antifreeze", + "name": "Antifreeze", + "icon": "mdi:snowflake-melt", + }, }, }, 0xFA: { @@ -4401,6 +5485,92 @@ MIDEA_DEVICES: dict[int, dict[str, dict[str, Any] | str]] = { "name": "Power", "icon": "mdi:power", }, + FAAttributes.humidify: { + "type": Platform.SWITCH, + "translation_key": "humidify", + "name": "Humidify", + "icon": "mdi:water-percent", + }, + FAAttributes.waterions: { + "type": Platform.SWITCH, + "translation_key": "waterions", + "name": "Water Ions", + "icon": "mdi:atom-variant", + }, + FAAttributes.anion: { + "type": Platform.SWITCH, + "translation_key": "anion", + "name": "Anion", + "icon": "mdi:atom", + }, + FAAttributes.anophelifuge: { + "type": Platform.SWITCH, + "translation_key": "anophelifuge", + "name": "Anti-Mosquito", + "icon": "mdi:mosquito-off", + }, + FAAttributes.display_on_off: { + "type": Platform.SWITCH, + "translation_key": "display_on_off", + "name": "Display", + "icon": "mdi:television", + }, + FAAttributes.auto_power_off: { + "type": Platform.SWITCH, + "translation_key": "auto_power_off", + "name": "Auto Power Off", + "icon": "mdi:timer-off", + }, + FAAttributes.body_feeling_scan: { + "type": Platform.SWITCH, + "translation_key": "body_feeling_scan", + "name": "Body Feeling Scan", + "icon": "mdi:motion-sensor", + }, + FAAttributes.humidity: { + "type": Platform.SENSOR, + "translation_key": "humidity", + "name": "Humidity", + "device_class": SensorDeviceClass.HUMIDITY, + "unit": PERCENTAGE, + "state_class": SensorStateClass.MEASUREMENT, + }, + FAAttributes.target_temperature: { + "type": Platform.SENSOR, + "translation_key": "target_temperature", + "name": "Target Temperature", + "device_class": SensorDeviceClass.TEMPERATURE, + "unit": UnitOfTemperature.CELSIUS, + "state_class": SensorStateClass.MEASUREMENT, + }, + FAAttributes.humidify_feedback: { + "type": Platform.SENSOR, + "translation_key": "humidify_feedback", + "name": "Humidity Feedback", + "device_class": SensorDeviceClass.HUMIDITY, + "unit": PERCENTAGE, + "state_class": SensorStateClass.MEASUREMENT, + }, + FAAttributes.temperature_feedback: { + "type": Platform.SENSOR, + "translation_key": "temperature_feedback", + "name": "Temperature Feedback", + "device_class": SensorDeviceClass.TEMPERATURE, + "unit": UnitOfTemperature.CELSIUS, + "state_class": SensorStateClass.MEASUREMENT, + }, + FAAttributes.humidify_mode: { + "type": Platform.SENSOR, + "translation_key": "humidify_mode", + "name": "Humidify Mode", + "icon": "mdi:water-percent", + }, + FAAttributes.error_code: { + "type": Platform.SENSOR, + "translation_key": "error_code", + "name": "Error Code", + "icon": "mdi:alert-circle", + }, }, }, 0xFB: { diff --git a/custom_components/midea_ac_lan/midea_entity.py b/custom_components/midea_ac_lan/midea_entity.py index a51f6394..0e4a2442 100644 --- a/custom_components/midea_ac_lan/midea_entity.py +++ b/custom_components/midea_ac_lan/midea_entity.py @@ -89,6 +89,20 @@ class MideaEntity(Entity): else: self._attr_name = None + # Optional entity registry hints from the device config: + # - entity_category: mark an entity as CONFIG/DIAGNOSTIC so HA groups it + # away from the main controls. + # - entity_registry_enabled_default: hide noisy/raw entities by default; + # users can still opt in from the entity registry. + entity_category = self._config.get("entity_category") + if entity_category is not None: + self._attr_entity_category = entity_category + registry_enabled_default = self._config.get( + "entity_registry_enabled_default", + ) + if registry_enabled_default is not None: + self._attr_entity_registry_enabled_default = registry_enabled_default + @property def device(self) -> MideaDevice: """Underlying Midea device instance.""" diff --git a/custom_components/midea_ac_lan/translations/de.json b/custom_components/midea_ac_lan/translations/de.json index 9bbcc754..e6feaad5 100644 --- a/custom_components/midea_ac_lan/translations/de.json +++ b/custom_components/midea_ac_lan/translations/de.json @@ -63,6 +63,18 @@ }, "entity": { "binary_sensor": { + "warm_power": { + "name": "Heizbetrieb" + }, + "cold_power": { + "name": "Kühlbetrieb" + }, + "sleep_power": { + "name": "Schlafbetrieb" + }, + "pump_on": { + "name": "Pumpe Ein" + }, "bar_door": { "name": "Bar-Tür" }, @@ -363,6 +375,114 @@ }, "water_pump_running": { "name": "Wasserpumpe läuft" + }, + "filter_status": { + "name": "Filteralarm" + }, + "standby_status": { + "name": "Standby-Status" + }, + "out_water": { + "name": "Wasserausgabe" + }, + "out_hot_water": { + "name": "Heißwasserausgabe" + }, + "backflow": { + "name": "Rückfluss" + }, + "sleep_status": { + "name": "Schlafstatus" + }, + "alarm_on": { + "name": "Fehler - Alarm" + }, + "aux_heat_on": { + "name": "Heizstab - Zusatzwärmequelle" + }, + "compressor_on": { + "name": "Kompressor - Läuft" + }, + "cool_capability": { + "name": "Funktion - Kühlen" + }, + "crankcase_heater_on": { + "name": "Heizstab - Kurbelgehäuse" + }, + "dhw_capability": { + "name": "Funktion - Warmwasser" + }, + "disinfect_run": { + "name": "WW - Desinfektion läuft" + }, + "double_zone": { + "name": "Funktion - Zwei Zonen" + }, + "eco_function_state": { + "name": "Modus - ECO-Funktion" + }, + "eco_timer_state": { + "name": "Modus - ECO-Zeitschaltung" + }, + "heat_capability": { + "name": "Funktion - Heizen" + }, + "hmi_energy_ana_set_en": { + "name": "Funktion - Energieanalyse (HMI)" + }, + "ibh1_on": { + "name": "Heizstab - IBH1" + }, + "ibh2_on": { + "name": "Heizstab - IBH2" + }, + "load_output_tbh": { + "name": "Heizstab - Speicher (TBH)" + }, + "pump_c_running": { + "name": "Pump_C - Mischkreis Zone 2" + }, + "pump_d_running": { + "name": "Pump_D - Warmwasser" + }, + "pump_i_running": { + "name": "Pump_I - Intern" + }, + "pump_o_running": { + "name": "Pump_O - Extern" + }, + "pump_s_running": { + "name": "Pump_S - Solar" + }, + "remote_onoff": { + "name": "Funktion - Fernein/-aus" + }, + "room_thermal_state": { + "name": "Status - Raumthermostat" + }, + "room_thermal_support": { + "name": "Funktion - Raumthermostat" + }, + "status_cool": { + "name": "Status - Kühlen" + }, + "sv1_open": { + "name": "SV1 - Ventil (Warmwasser)" + }, + "sv2_open": { + "name": "SV2 - Ventil (Heizen)" + }, + "sv3_open": { + "name": "SV3 - Ventil" + }, + "sys_energy_ana_en": { + "name": "Funktion - Energieanalyse (System)" + }, + "tbh_control": { + "name": "Funktion - TBH-Steuerung" + }, + "time_set": { + "name": "Funktion - Zeit gesetzt" } }, "button": { @@ -402,6 +522,9 @@ } }, "number": { + "heating_target_temperature": { + "name": "Heizungs-Solltemperatur" + }, "dry_level": { "name": "Trocken-Level" }, @@ -446,14 +569,38 @@ } }, "select": { + "heating_mode": { + "name": "Heizmodus", + "state": { + "user": "Benutzer", + "activity": "Aktivität", + "sleep": "Schlaf", + "unknown": "Unbekannt" + } + }, "detect_mode": { - "name": "Detektions-Modus" + "name": "Detektions-Modus", + "state": { + "off": "Aus", + "pm_2_5": "PM 2.5", + "methanal": "Methanal" + } }, "direction": { - "name": "Richtung" + "name": "Richtung", + "state": { + "oscillate": "Oszillieren" + } }, "fan_speed": { - "name": "Lüftergeschwindigkeit" + "name": "Lüftergeschwindigkeit", + "state": { + "auto": "Auto", + "standby": "Standby", + "low": "Niedrig", + "medium": "Mittel", + "high": "Hoch" + } }, "fresh_air_exhaust_mode": { "name": "Frischluft-Abluftgeschwindigkeit", @@ -475,7 +622,22 @@ } }, "mode": { - "name": "Modus" + "name": "Modus", + "state": { + "standby": "Standby", + "auto": "Auto", + "manual": "Manuell", + "sleep": "Schlaf", + "fast": "Schnell", + "smoke": "Rauch", + "off": "Aus", + "heat_high": "Heizen (hoch)", + "heat_low": "Heizen (niedrig)", + "bath": "Baden", + "blow": "Blasen", + "ventilation": "Lüftung", + "dry": "Trocknen" + } }, "oscillation_angle": { "name": "Oszillationswinkel" @@ -487,7 +649,12 @@ "name": "Leistungslimit" }, "screen_display": { - "name": "Bildschirmanzeige" + "name": "Bildschirmanzeige", + "state": { + "bright": "Hell", + "dim": "Gedimmt", + "off": "Aus" + } }, "silent_level": { "name": "Silent-Stufe" @@ -530,6 +697,36 @@ } }, "sensor": { + "three_way_mode": { + "name": "Dreiwegemodus" + }, + "heating_unit_type": { + "name": "Heizkörpertyp" + }, + "return_temperature": { + "name": "Rücklauftemperatur" + }, + "heating_temperature": { + "name": "Heiztemperatur" + }, + "heating_gap_temperature": { + "name": "Heizungs-Hysteresetemperatur" + }, + "user_mode_target_temperature": { + "name": "Solltemperatur Benutzermodus" + }, + "activity_mode_target_temperature": { + "name": "Solltemperatur Aktivitätsmodus" + }, + "sleep_mode_target_temperature": { + "name": "Solltemperatur Schlafmodus" + }, + "last_time": { + "name": "Laufzeit" + }, + "flow_volume": { + "name": "Durchfluss" + }, "bathing_leaving_temperature": { "name": "Bathing Leaving Water Temperature" }, @@ -659,6 +856,15 @@ "error_code": { "name": "Fehlercode" }, + "humidify_feedback": { + "name": "Luftfeuchtigkeit-Rückmeldung" + }, + "temperature_feedback": { + "name": "Temperatur-Rückmeldung" + }, + "humidify_mode": { + "name": "Befeuchtungsmodus" + }, "estimated_energy_consumption": { "name": "Geschätzter Energieverbrauch" }, @@ -1218,12 +1424,177 @@ }, "velocity": { "name": "Durchflussgeschwindigkeit" + }, + "filter4_life": { + "name": "Filter4 Lebensdauer" + }, + "filter5_life": { + "name": "Filter5 Lebensdauer" + }, + "filter1_maxlife": { + "name": "Filter1 Lebensdauergrenze" + }, + "filter2_maxlife": { + "name": "Filter2 Lebensdauergrenze" + }, + "filter3_maxlife": { + "name": "Filter3 Lebensdauergrenze" + }, + "filter4_maxlife": { + "name": "Filter4 Lebensdauergrenze" + }, + "filter5_maxlife": { + "name": "Filter5 Lebensdauergrenze" + }, + "hot_pot_temperature": { + "name": "Heißwassertopf-Temperatur" + }, + "ice_gall_status": { + "name": "Eisbehälterstatus" + }, + "water_kind": { + "name": "Wasserart", + "state": { + "idle": "Leerlauf", + "warm": "Warm", + "cold": "Kalt" + } + }, + "heat_start": { + "name": "Heizstart", + "state": { + "heating": "Heizen", + "keep_warm": "Warmhalten" + } + }, + "comp_total_run_time": { + "name": "Energie - Kompressor-Laufzeit" + }, + "dc_bus_voltage": { + "name": "Außengerät - DC-Zwischenkreisspannung" + }, + "dc_current": { + "name": "Außengerät - DC-Zwischenkreisstrom" + }, + "disinfect_set_weekday": { + "name": "WW - Desinfektion Wochentag" + }, + "disinfect_start_hour": { + "name": "WW - Desinfektion Startstunde" + }, + "disinfect_start_minutes": { + "name": "WW - Desinfektion Startminute" + }, + "error_code_description": { + "name": "Fehler - Beschreibung" + }, + "hydbox_subtype": { + "name": "Info - Hydraulikmodul-Subtyp" + }, + "hydrobox_capacity": { + "name": "Info - Hydraulikmodul-Leistung" + }, + "idu_software_version_str": { + "name": "Info - Software-Version Inneneinheit" + }, + "idu_t1s1": { + "name": "Temperatur - Zone 1 berechnet (T1s)" + }, + "idu_t1s2": { + "name": "Temperatur - Zone 2 berechnet (T1s)" + }, + "current_unit_capacity": { + "name": "Aktuelle Geräteleistung (roh)" + }, + "instant_power0": { + "name": "Leistung - Heiz-Stromaufnahme" + }, + "instant_renew_power0": { + "name": "Leistung - Erneuerbarer Heizanteil" + }, + "machine_type": { + "name": "Info - Maschinentyp" + }, + "odu_model": { + "name": "Info - Außengerät-Modellcode" + }, + "odu_software_version_str": { + "name": "Info - Software-Version Außengerät" + }, + "room_rel_hum": { + "name": "Relative Raumfeuchte" + }, + "t5s": { + "name": "Temperatur T5s - Warmwasser-Sollwert" + }, + "tas": { + "name": "Temperatur Tas - Luft-Sollwert" + }, + "temp_t4": { + "name": "Temperatur T4 - Außenluft" + }, + "temp_t5": { + "name": "Temperatur T5 - Warmwasserspeicher" + }, + "temp_ta": { + "name": "Temperatur Ta - Raumluft" + }, + "temp_tb_t1": { + "name": "Temperatur TB-T1 - Pufferspeicher oben" + }, + "temp_tb_t2": { + "name": "Temperatur TB-T2 - Pufferspeicher unten" + }, + "temp_tsolar": { + "name": "Temperatur Tsolar - Solarkollektor" + }, + "temp_tw2": { + "name": "Temperatur Tw2 - Wasser Zone 2" + }, + "temp_tw_in": { + "name": "Temperatur Tw_in - Wasser Eintritt" + }, + "temp_tw_out": { + "name": "Temperatur Tw_out - Wasser Austritt" + }, + "water_flow": { + "name": "Wasser - Durchfluss" + }, + "water_pressure": { + "name": "Wasser - Druck" + }, + "hmi_sn_code": { + "name": "Info - HMI-Seriennummer" + }, + "zone1_temp_set": { + "name": "Temperatur - Sollwert Zone 1" + }, + "zone2_temp_set": { + "name": "Temperatur - Sollwert Zone 2" } }, "switch": { "anion": { "name": "Anion" }, + "humidify": { + "name": "Befeuchten" + }, + "waterions": { + "name": "Wasserionen" + }, + "anophelifuge": { + "name": "Mückenschutz" + }, + "display_on_off": { + "name": "Anzeige" + }, + "auto_power_off": { + "name": "Automatische Abschaltung" + }, + "body_feeling_scan": { + "name": "Körpererkennung" + }, "aux_heating": { "name": "Aux Heating" }, @@ -1242,6 +1613,9 @@ "comfort_mode": { "name": "Comfort-Modus" }, + "degerming": { + "name": "Entkeimung" + }, "dhw_power": { "name": "DHW Power" }, @@ -1445,6 +1819,18 @@ }, "screen_off": { "name": "Bildschirm aus" + }, + "wash": { + "name": "Filterspülung" + }, + "antifreeze": { + "name": "Frostschutz" + }, + "dhw_disinfect": { + "name": "WW - Desinfektion" + }, + "holiday_on": { + "name": "Modus - Urlaub" } }, "water_heater": { diff --git a/custom_components/midea_ac_lan/translations/en.json b/custom_components/midea_ac_lan/translations/en.json index 70334259..c84e265f 100644 --- a/custom_components/midea_ac_lan/translations/en.json +++ b/custom_components/midea_ac_lan/translations/en.json @@ -63,6 +63,18 @@ }, "entity": { "binary_sensor": { + "warm_power": { + "name": "Warm Power" + }, + "cold_power": { + "name": "Cold Power" + }, + "sleep_power": { + "name": "Sleep Power" + }, + "pump_on": { + "name": "Pump On" + }, "bar_door": { "name": "Bar Door" }, @@ -330,6 +342,114 @@ }, "water_pump_running": { "name": "Water Pump Running" + }, + "filter_status": { + "name": "Filter Alarm" + }, + "standby_status": { + "name": "Standby Status" + }, + "out_water": { + "name": "Out Water" + }, + "out_hot_water": { + "name": "Out Hot Water" + }, + "backflow": { + "name": "Backflow" + }, + "sleep_status": { + "name": "Sleep Status" + }, + "status_cool": { + "name": "Status - Cooling" + }, + "eco_function_state": { + "name": "Mode - ECO Function" + }, + "eco_timer_state": { + "name": "Mode - ECO Timer" + }, + "double_zone": { + "name": "Capability - Double Zone" + }, + "room_thermal_support": { + "name": "Capability - Room Thermostat" + }, + "room_thermal_state": { + "name": "Status - Room Thermostat" + }, + "time_set": { + "name": "Capability - Time Set" + }, + "disinfect_run": { + "name": "DHW - Disinfect Running" + }, + "remote_onoff": { + "name": "Capability - Remote On/Off" + }, + "tbh_control": { + "name": "Capability - TBH Control" + }, + "heat_capability": { + "name": "Capability - Heating" + }, + "cool_capability": { + "name": "Capability - Cooling" + }, + "dhw_capability": { + "name": "Capability - DHW" + }, + "sys_energy_ana_en": { + "name": "Capability - Energy Analysis (System)" + }, + "hmi_energy_ana_set_en": { + "name": "Capability - Energy Analysis (HMI)" + }, + "pump_i_running": { + "name": "Pump_I - Internal" + }, + "pump_o_running": { + "name": "Pump_O - External" + }, + "pump_d_running": { + "name": "Pump_D - DHW" + }, + "pump_c_running": { + "name": "Pump_C - Mixed Water Loop Zone 2" + }, + "pump_s_running": { + "name": "Pump_S - Solar" + }, + "sv1_open": { + "name": "SV1 - Valve (DHW)" + }, + "sv2_open": { + "name": "SV2 - Valve (Heating)" + }, + "load_output_tbh": { + "name": "Heater - Tank Backup (TBH)" + }, + "compressor_on": { + "name": "Compressor - Running" + }, + "ibh1_on": { + "name": "Heater - IBH1" + }, + "ibh2_on": { + "name": "Heater - IBH2" + }, + "sv3_open": { + "name": "SV3 - Valve" + }, + "crankcase_heater_on": { + "name": "Heater - Crankcase" + }, + "alarm_on": { + "name": "Error - Alarm" + }, + "aux_heat_on": { + "name": "Heater - Auxiliary Source" } }, "button": { @@ -369,6 +489,9 @@ } }, "number": { + "heating_target_temperature": { + "name": "Heating Target Temperature" + }, "dry_level": { "name": "Dry Level" }, @@ -407,14 +530,38 @@ } }, "select": { + "heating_mode": { + "name": "Heating Mode", + "state": { + "user": "User", + "activity": "Activity", + "sleep": "Sleep", + "unknown": "Unknown" + } + }, "detect_mode": { - "name": "Detect Mode" + "name": "Detect Mode", + "state": { + "off": "Off", + "pm_2_5": "PM 2.5", + "methanal": "Methanal" + } }, "direction": { - "name": "Direction" + "name": "Direction", + "state": { + "oscillate": "Oscillate" + } }, "fan_speed": { - "name": "Fan Speed" + "name": "Fan Speed", + "state": { + "auto": "Auto", + "standby": "Standby", + "low": "Low", + "medium": "Medium", + "high": "High" + } }, "fresh_air_exhaust_mode": { "name": "Fresh Air Exhaust Speed", @@ -436,7 +583,22 @@ } }, "mode": { - "name": "Mode" + "name": "Mode", + "state": { + "standby": "Standby", + "auto": "Auto", + "manual": "Manual", + "sleep": "Sleep", + "fast": "Fast", + "smoke": "Smoke", + "off": "Off", + "heat_high": "Heat (High)", + "heat_low": "Heat (Low)", + "bath": "Bath", + "blow": "Blow", + "ventilation": "Ventilation", + "dry": "Dry" + } }, "oscillation_angle": { "name": "Oscillation Angle" @@ -448,7 +610,12 @@ "name": "Power Rate Limit" }, "screen_display": { - "name": "Screen Display" + "name": "Screen Display", + "state": { + "bright": "Bright", + "dim": "Dim", + "off": "Off" + } }, "silent_level": { "name": "Silent Level" @@ -491,6 +658,36 @@ } }, "sensor": { + "three_way_mode": { + "name": "Three-way Mode" + }, + "heating_unit_type": { + "name": "Heating Unit Type" + }, + "return_temperature": { + "name": "Return Temperature" + }, + "heating_temperature": { + "name": "Heating Temperature" + }, + "heating_gap_temperature": { + "name": "Heating Gap Temperature" + }, + "user_mode_target_temperature": { + "name": "User Mode Target Temperature" + }, + "activity_mode_target_temperature": { + "name": "Activity Mode Target Temperature" + }, + "sleep_mode_target_temperature": { + "name": "Sleep Mode Target Temperature" + }, + "last_time": { + "name": "Last Time" + }, + "flow_volume": { + "name": "Flow Rate" + }, "bathing_leaving_temperature": { "name": "Bathing Leaving Water Temperature" }, @@ -670,6 +867,15 @@ "error_code": { "name": "Error Code" }, + "humidify_feedback": { + "name": "Humidity Feedback" + }, + "temperature_feedback": { + "name": "Temperature Feedback" + }, + "humidify_mode": { + "name": "Humidify Mode" + }, "estimated_energy_consumption": { "name": "Estimated Energy Consumption" }, @@ -1166,12 +1372,177 @@ }, "velocity": { "name": "Velocity" + }, + "filter4_life": { + "name": "Filter4 Life Level" + }, + "filter5_life": { + "name": "Filter5 Life Level" + }, + "filter1_maxlife": { + "name": "Filter1 Lifetime Limit" + }, + "filter2_maxlife": { + "name": "Filter2 Lifetime Limit" + }, + "filter3_maxlife": { + "name": "Filter3 Lifetime Limit" + }, + "filter4_maxlife": { + "name": "Filter4 Lifetime Limit" + }, + "filter5_maxlife": { + "name": "Filter5 Lifetime Limit" + }, + "hot_pot_temperature": { + "name": "Hot Pot Temperature" + }, + "ice_gall_status": { + "name": "Ice Gall Status" + }, + "water_kind": { + "name": "Water Kind", + "state": { + "idle": "Idle", + "warm": "Warm", + "cold": "Cold" + } + }, + "heat_start": { + "name": "Heat Start", + "state": { + "heating": "Heating", + "keep_warm": "Keeping Warm" + } + }, + "temp_ta": { + "name": "Temperature Ta - Room Ambient" + }, + "water_flow": { + "name": "Water - Flow Rate" + }, + "water_pressure": { + "name": "Water - Pressure" + }, + "temp_t4": { + "name": "Temperature T4 - Outdoor Ambient" + }, + "temp_t5": { + "name": "Temperature T5 - Water Tank" + }, + "temp_tb_t1": { + "name": "Temperature TB-T1 - Buffer Tank Top" + }, + "temp_tb_t2": { + "name": "Temperature TB-T2 - Buffer Tank Bottom" + }, + "temp_tsolar": { + "name": "Temperature Tsolar - Solar Panel" + }, + "temp_tw2": { + "name": "Temperature Tw2 - Zone 2 Water" + }, + "dc_current": { + "name": "ODU - DC Bus Current" + }, + "dc_bus_voltage": { + "name": "ODU - DC Bus Voltage" + }, + "current_unit_capacity": { + "name": "Current Unit Capacity (raw)" + }, + "instant_power0": { + "name": "Power - Heating Consumption" + }, + "instant_renew_power0": { + "name": "Power - Renewable Heating Capacity" + }, + "room_rel_hum": { + "name": "Room Relative Humidity" + }, + "hydbox_subtype": { + "name": "Info - Hydraulic Box Subtype" + }, + "machine_type": { + "name": "Info - Machine Type" + }, + "odu_model": { + "name": "Info - ODU Model Code" + }, + "hydrobox_capacity": { + "name": "Info - Hydraulic Box Capacity" + }, + "idu_t1s1": { + "name": "Temperature - Zone 1 Calculated (T1s)" + }, + "idu_t1s2": { + "name": "Temperature - Zone 2 Calculated (T1s)" + }, + "t5s": { + "name": "Temperature T5s - DHW Setpoint" + }, + "tas": { + "name": "Temperature Tas - Air Setpoint" + }, + "zone1_temp_set": { + "name": "Temperature - Zone 1 Setpoint" + }, + "zone2_temp_set": { + "name": "Temperature - Zone 2 Setpoint" + }, + "disinfect_set_weekday": { + "name": "DHW - Disinfect Weekday" + }, + "disinfect_start_hour": { + "name": "DHW - Disinfect Start Hour" + }, + "disinfect_start_minutes": { + "name": "DHW - Disinfect Start Minute" + }, + "error_code_description": { + "name": "Error - Description" + }, + "hmi_sn_code": { + "name": "HMI Serial" + }, + "temp_tw_in": { + "name": "Temperature Tw_in - Water Inlet" + }, + "temp_tw_out": { + "name": "Temperature Tw_out - Water Outlet" + }, + "comp_total_run_time": { + "name": "Energy - Compressor Run Time" + }, + "idu_software_version_str": { + "name": "Info - IDU Software Version" + }, + "odu_software_version_str": { + "name": "Info - ODU Software Version" } }, "switch": { "anion": { "name": "Anion" }, + "humidify": { + "name": "Humidify" + }, + "waterions": { + "name": "Water Ions" + }, + "anophelifuge": { + "name": "Anti-Mosquito" + }, + "display_on_off": { + "name": "Display" + }, + "auto_power_off": { + "name": "Auto Power Off" + }, + "body_feeling_scan": { + "name": "Body Feeling Scan" + }, "aux_heating": { "name": "Aux Heating" }, @@ -1190,6 +1561,9 @@ "comfort_mode": { "name": "Comfort Mode" }, + "degerming": { + "name": "Degerming" + }, "dhw_power": { "name": "DHW Power" }, @@ -1391,6 +1765,18 @@ }, "screen_off": { "name": "Screen Off" + }, + "wash": { + "name": "Filter Wash" + }, + "antifreeze": { + "name": "Antifreeze" + }, + "holiday_on": { + "name": "Mode - Holiday" + }, + "dhw_disinfect": { + "name": "DHW - Disinfect" } }, "water_heater": { diff --git a/custom_components/midea_ac_lan/translations/es.json b/custom_components/midea_ac_lan/translations/es.json index c3ee94ab..1e19d559 100644 --- a/custom_components/midea_ac_lan/translations/es.json +++ b/custom_components/midea_ac_lan/translations/es.json @@ -63,6 +63,18 @@ }, "entity": { "binary_sensor": { + "warm_power": { + "name": "Funcionamiento de calefacción" + }, + "cold_power": { + "name": "Funcionamiento de refrigeración" + }, + "sleep_power": { + "name": "Funcionamiento nocturno" + }, + "pump_on": { + "name": "Bomba encendida" + }, "bar_door": { "name": "Puerta del bar" }, @@ -363,6 +375,114 @@ }, "water_pump_running": { "name": "Bomba de agua en funcionamiento" + }, + "filter_status": { + "name": "Alarma de filtro" + }, + "standby_status": { + "name": "Estado de espera" + }, + "out_water": { + "name": "Salida de agua" + }, + "out_hot_water": { + "name": "Salida de agua caliente" + }, + "backflow": { + "name": "Reflujo" + }, + "sleep_status": { + "name": "Estado de reposo" + }, + "alarm_on": { + "name": "Error - Alarma" + }, + "aux_heat_on": { + "name": "Resistencia - Fuente auxiliar" + }, + "compressor_on": { + "name": "Compresor - En marcha" + }, + "cool_capability": { + "name": "Capacidad - Refrigeración" + }, + "crankcase_heater_on": { + "name": "Resistencia - Cárter" + }, + "dhw_capability": { + "name": "Capacidad - ACS" + }, + "disinfect_run": { + "name": "ACS - Desinfección en curso" + }, + "double_zone": { + "name": "Capacidad - Zona doble" + }, + "eco_function_state": { + "name": "Modo - Función ECO" + }, + "eco_timer_state": { + "name": "Modo - Temporizador ECO" + }, + "heat_capability": { + "name": "Capacidad - Calefacción" + }, + "hmi_energy_ana_set_en": { + "name": "Capacidad - Análisis energético (HMI)" + }, + "ibh1_on": { + "name": "Resistencia - IBH1" + }, + "ibh2_on": { + "name": "Resistencia - IBH2" + }, + "load_output_tbh": { + "name": "Resistencia - Acumulador (TBH)" + }, + "pump_c_running": { + "name": "Pump_C - Circuito mezcla zona 2" + }, + "pump_d_running": { + "name": "Pump_D - ACS" + }, + "pump_i_running": { + "name": "Pump_I - Interna" + }, + "pump_o_running": { + "name": "Pump_O - Externa" + }, + "pump_s_running": { + "name": "Pump_S - Solar" + }, + "remote_onoff": { + "name": "Capacidad - Encendido remoto" + }, + "room_thermal_state": { + "name": "Estado - Termostato de ambiente" + }, + "room_thermal_support": { + "name": "Capacidad - Termostato de ambiente" + }, + "status_cool": { + "name": "Estado - Refrigeración" + }, + "sv1_open": { + "name": "SV1 - Válvula (ACS)" + }, + "sv2_open": { + "name": "SV2 - Válvula (Calefacción)" + }, + "sv3_open": { + "name": "SV3 - Válvula" + }, + "sys_energy_ana_en": { + "name": "Capacidad - Análisis energético (Sistema)" + }, + "tbh_control": { + "name": "Capacidad - Control TBH" + }, + "time_set": { + "name": "Capacidad - Hora configurada" } }, "button": { @@ -402,6 +522,9 @@ } }, "number": { + "heating_target_temperature": { + "name": "Temperatura objetivo de calefacción" + }, "dry_level": { "name": "Nivel de secado" }, @@ -446,14 +569,38 @@ } }, "select": { + "heating_mode": { + "name": "Modo de calefacción", + "state": { + "user": "Usuario", + "activity": "Actividad", + "sleep": "Reposo", + "unknown": "Desconocido" + } + }, "detect_mode": { - "name": "Modo de detección" + "name": "Modo de detección", + "state": { + "off": "Apagado", + "pm_2_5": "PM 2.5", + "methanal": "Formaldehído" + } }, "direction": { - "name": "Dirección" + "name": "Dirección", + "state": { + "oscillate": "Oscilar" + } }, "fan_speed": { - "name": "Velocidad del ventilador" + "name": "Velocidad del ventilador", + "state": { + "auto": "Automático", + "standby": "En espera", + "low": "Baja", + "medium": "Media", + "high": "Alta" + } }, "fresh_air_exhaust_mode": { "name": "Velocidad de extracción de aire fresco", @@ -475,7 +622,22 @@ } }, "mode": { - "name": "Modo" + "name": "Modo", + "state": { + "standby": "En espera", + "auto": "Automático", + "manual": "Manual", + "sleep": "Sueño", + "fast": "Rápido", + "smoke": "Humo", + "off": "Apagado", + "heat_high": "Calor (alto)", + "heat_low": "Calor (bajo)", + "bath": "Baño", + "blow": "Soplado", + "ventilation": "Ventilación", + "dry": "Secado" + } }, "oscillation_angle": { "name": "Ángulo de oscilación" @@ -487,7 +649,12 @@ "name": "Límite de tasa de potencia" }, "screen_display": { - "name": "Visualización de pantalla" + "name": "Visualización de pantalla", + "state": { + "bright": "Brillante", + "dim": "Atenuado", + "off": "Apagado" + } }, "silent_level": { "name": "Nivel de silencio" @@ -530,6 +697,36 @@ } }, "sensor": { + "three_way_mode": { + "name": "Modo de tres vías" + }, + "heating_unit_type": { + "name": "Tipo de unidad de calefacción" + }, + "return_temperature": { + "name": "Temperatura de retorno" + }, + "heating_temperature": { + "name": "Temperatura de calefacción" + }, + "heating_gap_temperature": { + "name": "Temperatura de histéresis de calefacción" + }, + "user_mode_target_temperature": { + "name": "Temperatura objetivo modo usuario" + }, + "activity_mode_target_temperature": { + "name": "Temperatura objetivo modo actividad" + }, + "sleep_mode_target_temperature": { + "name": "Temperatura objetivo modo reposo" + }, + "last_time": { + "name": "Tiempo de funcionamiento" + }, + "flow_volume": { + "name": "Caudal" + }, "bathing_leaving_temperature": { "name": "Temperatura de salida del agua de baño" }, @@ -712,6 +909,15 @@ "error_code": { "name": "Código de error" }, + "humidify_feedback": { + "name": "Retroalimentación de humedad" + }, + "temperature_feedback": { + "name": "Retroalimentación de temperatura" + }, + "humidify_mode": { + "name": "Modo de humidificación" + }, "estimated_energy_consumption": { "name": "Consumo estimado de energía" }, @@ -1218,12 +1424,177 @@ }, "velocity": { "name": "Velocidad" + }, + "filter4_life": { + "name": "Vida del filtro 4" + }, + "filter5_life": { + "name": "Vida del filtro 5" + }, + "filter1_maxlife": { + "name": "Límite de vida del filtro 1" + }, + "filter2_maxlife": { + "name": "Límite de vida del filtro 2" + }, + "filter3_maxlife": { + "name": "Límite de vida del filtro 3" + }, + "filter4_maxlife": { + "name": "Límite de vida del filtro 4" + }, + "filter5_maxlife": { + "name": "Límite de vida del filtro 5" + }, + "hot_pot_temperature": { + "name": "Temperatura de agua caliente" + }, + "ice_gall_status": { + "name": "Estado del depósito de hielo" + }, + "water_kind": { + "name": "Tipo de agua", + "state": { + "idle": "Inactivo", + "warm": "Templada", + "cold": "Fría" + } + }, + "heat_start": { + "name": "Inicio de calentamiento", + "state": { + "heating": "Calentando", + "keep_warm": "Manteniendo caliente" + } + }, + "comp_total_run_time": { + "name": "Energía - Tiempo de marcha del compresor" + }, + "dc_bus_voltage": { + "name": "Unidad exterior - Tensión del bus CC" + }, + "dc_current": { + "name": "Unidad exterior - Corriente del bus CC" + }, + "disinfect_set_weekday": { + "name": "ACS - Día de desinfección" + }, + "disinfect_start_hour": { + "name": "ACS - Hora de inicio de desinfección" + }, + "disinfect_start_minutes": { + "name": "ACS - Minuto de inicio de desinfección" + }, + "error_code_description": { + "name": "Error - Descripción" + }, + "hydbox_subtype": { + "name": "Info - Subtipo del hidrokit" + }, + "hydrobox_capacity": { + "name": "Info - Potencia del hidrokit" + }, + "idu_software_version_str": { + "name": "Info - Versión de software de la unidad interior" + }, + "idu_t1s1": { + "name": "Temperatura - Zona 1 calculada (T1s)" + }, + "idu_t1s2": { + "name": "Temperatura - Zona 2 calculada (T1s)" + }, + "current_unit_capacity": { + "name": "Capacidad actual de la unidad (sin procesar)" + }, + "instant_power0": { + "name": "Potencia - Consumo de calefacción" + }, + "instant_renew_power0": { + "name": "Potencia - Capacidad renovable de calefacción" + }, + "machine_type": { + "name": "Info - Tipo de máquina" + }, + "odu_model": { + "name": "Info - Código de modelo de la unidad exterior" + }, + "odu_software_version_str": { + "name": "Info - Versión de software de la unidad exterior" + }, + "room_rel_hum": { + "name": "Humedad relativa de la sala" + }, + "t5s": { + "name": "Temperatura T5s - Consigna de ACS" + }, + "tas": { + "name": "Temperatura Tas - Consigna de aire" + }, + "temp_t4": { + "name": "Temperatura T4 - Aire exterior" + }, + "temp_t5": { + "name": "Temperatura T5 - Acumulador de ACS" + }, + "temp_ta": { + "name": "Temperatura Ta - Ambiente interior" + }, + "temp_tb_t1": { + "name": "Temperatura TB-T1 - Depósito de inercia superior" + }, + "temp_tb_t2": { + "name": "Temperatura TB-T2 - Depósito de inercia inferior" + }, + "temp_tsolar": { + "name": "Temperatura Tsolar - Panel solar" + }, + "temp_tw2": { + "name": "Temperatura Tw2 - Agua zona 2" + }, + "temp_tw_in": { + "name": "Temperatura Tw_in - Entrada de agua" + }, + "temp_tw_out": { + "name": "Temperatura Tw_out - Salida de agua" + }, + "water_flow": { + "name": "Agua - Caudal" + }, + "water_pressure": { + "name": "Agua - Presión" + }, + "hmi_sn_code": { + "name": "Info - Número de serie HMI" + }, + "zone1_temp_set": { + "name": "Temperatura - Consigna zona 1" + }, + "zone2_temp_set": { + "name": "Temperatura - Consigna zona 2" } }, "switch": { "anion": { "name": "Anión" }, + "humidify": { + "name": "Humidificar" + }, + "waterions": { + "name": "Iones de agua" + }, + "anophelifuge": { + "name": "Antimosquitos" + }, + "display_on_off": { + "name": "Pantalla" + }, + "auto_power_off": { + "name": "Apagado automático" + }, + "body_feeling_scan": { + "name": "Detección corporal" + }, "aux_heating": { "name": "Calefacción auxiliar" }, @@ -1242,6 +1613,9 @@ "comfort_mode": { "name": "Modo confort" }, + "degerming": { + "name": "Desinfección" + }, "dhw_power": { "name": "Potencia ACS" }, @@ -1445,6 +1819,18 @@ }, "screen_off": { "name": "Pantalla apagada" + }, + "wash": { + "name": "Lavado de filtro" + }, + "antifreeze": { + "name": "Anticongelante" + }, + "dhw_disinfect": { + "name": "ACS - Desinfección" + }, + "holiday_on": { + "name": "Modo - Vacaciones" } }, "water_heater": { diff --git a/custom_components/midea_ac_lan/translations/fr.json b/custom_components/midea_ac_lan/translations/fr.json index 2cdc1983..25d3f08d 100644 --- a/custom_components/midea_ac_lan/translations/fr.json +++ b/custom_components/midea_ac_lan/translations/fr.json @@ -63,6 +63,18 @@ }, "entity": { "binary_sensor": { + "warm_power": { + "name": "Fonctionnement chauffage" + }, + "cold_power": { + "name": "Fonctionnement refroidissement" + }, + "sleep_power": { + "name": "Fonctionnement nuit" + }, + "pump_on": { + "name": "Pompe en marche" + }, "bar_door": { "name": "Bar Door" }, @@ -363,6 +375,114 @@ }, "water_pump_running": { "name": "Pompe à eau en marche" + }, + "filter_status": { + "name": "Alarme filtre" + }, + "standby_status": { + "name": "État de veille" + }, + "out_water": { + "name": "Sortie d'eau" + }, + "out_hot_water": { + "name": "Sortie d'eau chaude" + }, + "backflow": { + "name": "Reflux" + }, + "sleep_status": { + "name": "État de veille prolongée" + }, + "alarm_on": { + "name": "Erreur - Alarme" + }, + "aux_heat_on": { + "name": "Résistance - Source auxiliaire" + }, + "compressor_on": { + "name": "Compresseur - En marche" + }, + "cool_capability": { + "name": "Fonction - Refroidissement" + }, + "crankcase_heater_on": { + "name": "Résistance - Carter" + }, + "dhw_capability": { + "name": "Fonction - ECS" + }, + "disinfect_run": { + "name": "ECS - Désinfection en cours" + }, + "double_zone": { + "name": "Fonction - Double zone" + }, + "eco_function_state": { + "name": "Mode - Fonction ECO" + }, + "eco_timer_state": { + "name": "Mode - Minuterie ECO" + }, + "heat_capability": { + "name": "Fonction - Chauffage" + }, + "hmi_energy_ana_set_en": { + "name": "Fonction - Analyse énergétique (IHM)" + }, + "ibh1_on": { + "name": "Résistance - IBH1" + }, + "ibh2_on": { + "name": "Résistance - IBH2" + }, + "load_output_tbh": { + "name": "Résistance - Ballon (TBH)" + }, + "pump_c_running": { + "name": "Pump_C - Circuit mélangé zone 2" + }, + "pump_d_running": { + "name": "Pump_D - ECS" + }, + "pump_i_running": { + "name": "Pump_I - Interne" + }, + "pump_o_running": { + "name": "Pump_O - Externe" + }, + "pump_s_running": { + "name": "Pump_S - Solaire" + }, + "remote_onoff": { + "name": "Fonction - Marche/arrêt à distance" + }, + "room_thermal_state": { + "name": "État - Thermostat d'ambiance" + }, + "room_thermal_support": { + "name": "Fonction - Thermostat d'ambiance" + }, + "status_cool": { + "name": "État - Refroidissement" + }, + "sv1_open": { + "name": "SV1 - Vanne (ECS)" + }, + "sv2_open": { + "name": "SV2 - Vanne (Chauffage)" + }, + "sv3_open": { + "name": "SV3 - Vanne" + }, + "sys_energy_ana_en": { + "name": "Fonction - Analyse énergétique (Système)" + }, + "tbh_control": { + "name": "Fonction - Commande TBH" + }, + "time_set": { + "name": "Fonction - Heure réglée" } }, "button": { @@ -402,6 +522,9 @@ } }, "number": { + "heating_target_temperature": { + "name": "Température cible de chauffage" + }, "dry_level": { "name": "Dry Level" }, @@ -446,14 +569,38 @@ } }, "select": { + "heating_mode": { + "name": "Mode de chauffage", + "state": { + "user": "Utilisateur", + "activity": "Activité", + "sleep": "Nuit", + "unknown": "Inconnu" + } + }, "detect_mode": { - "name": "Detect Mode" + "name": "Detect Mode", + "state": { + "off": "Arrêt", + "pm_2_5": "PM 2.5", + "methanal": "Methanal" + } }, "direction": { - "name": "Direction" + "name": "Direction", + "state": { + "oscillate": "Oscillation" + } }, "fan_speed": { - "name": "Fan Speed" + "name": "Fan Speed", + "state": { + "auto": "Auto", + "standby": "Veille", + "low": "Faible", + "medium": "Moyenne", + "high": "Élevée" + } }, "fresh_air_exhaust_mode": { "name": "Vitesse d'extraction d'air frais", @@ -475,7 +622,22 @@ } }, "mode": { - "name": "Mode" + "name": "Mode", + "state": { + "standby": "Veille", + "auto": "Auto", + "manual": "Manuel", + "sleep": "Sommeil", + "fast": "Rapide", + "smoke": "Fumée", + "off": "Arrêt", + "heat_high": "Chauffage (fort)", + "heat_low": "Chauffage (faible)", + "bath": "Bain", + "blow": "Soufflage", + "ventilation": "Ventilation", + "dry": "Séchage" + } }, "oscillation_angle": { "name": "Oscillation Angle" @@ -487,7 +649,12 @@ "name": "Power Rate Limit" }, "screen_display": { - "name": "Screen Display" + "name": "Screen Display", + "state": { + "bright": "Lumineux", + "dim": "Atténué", + "off": "Arrêt" + } }, "silent_level": { "name": "Silent Level" @@ -530,6 +697,36 @@ } }, "sensor": { + "three_way_mode": { + "name": "Mode trois voies" + }, + "heating_unit_type": { + "name": "Type d'émetteur" + }, + "return_temperature": { + "name": "Température de retour" + }, + "heating_temperature": { + "name": "Température de chauffage" + }, + "heating_gap_temperature": { + "name": "Température d'hystérésis de chauffage" + }, + "user_mode_target_temperature": { + "name": "Température cible mode utilisateur" + }, + "activity_mode_target_temperature": { + "name": "Température cible mode activité" + }, + "sleep_mode_target_temperature": { + "name": "Température cible mode nuit" + }, + "last_time": { + "name": "Durée de fonctionnement" + }, + "flow_volume": { + "name": "Débit" + }, "bathing_leaving_temperature": { "name": "Bathing Leaving Water Temperature" }, @@ -659,6 +856,15 @@ "error_code": { "name": "Error Code" }, + "humidify_feedback": { + "name": "Retour d'humidité" + }, + "temperature_feedback": { + "name": "Retour de température" + }, + "humidify_mode": { + "name": "Mode d'humidification" + }, "estimated_energy_consumption": { "name": "Consommation d'énergie estimée" }, @@ -1218,12 +1424,177 @@ }, "velocity": { "name": "Vitesse" + }, + "filter4_life": { + "name": "Durée de vie du filtre 4" + }, + "filter5_life": { + "name": "Durée de vie du filtre 5" + }, + "filter1_maxlife": { + "name": "Limite de vie du filtre 1" + }, + "filter2_maxlife": { + "name": "Limite de vie du filtre 2" + }, + "filter3_maxlife": { + "name": "Limite de vie du filtre 3" + }, + "filter4_maxlife": { + "name": "Limite de vie du filtre 4" + }, + "filter5_maxlife": { + "name": "Limite de vie du filtre 5" + }, + "hot_pot_temperature": { + "name": "Température d'eau chaude" + }, + "ice_gall_status": { + "name": "État du réservoir à glace" + }, + "water_kind": { + "name": "Type d'eau", + "state": { + "idle": "Inactif", + "warm": "Tiède", + "cold": "Froide" + } + }, + "heat_start": { + "name": "Démarrage du chauffage", + "state": { + "heating": "Chauffage", + "keep_warm": "Maintien au chaud" + } + }, + "comp_total_run_time": { + "name": "Énergie - Temps de fonctionnement du compresseur" + }, + "dc_bus_voltage": { + "name": "Unité extérieure - Tension du bus CC" + }, + "dc_current": { + "name": "Unité extérieure - Courant du bus CC" + }, + "disinfect_set_weekday": { + "name": "ECS - Jour de désinfection" + }, + "disinfect_start_hour": { + "name": "ECS - Heure de début de désinfection" + }, + "disinfect_start_minutes": { + "name": "ECS - Minute de début de désinfection" + }, + "error_code_description": { + "name": "Erreur - Description" + }, + "hydbox_subtype": { + "name": "Info - Sous-type du module hydraulique" + }, + "hydrobox_capacity": { + "name": "Info - Puissance du module hydraulique" + }, + "idu_software_version_str": { + "name": "Info - Version logicielle unité intérieure" + }, + "idu_t1s1": { + "name": "Température - Zone 1 calculée (T1s)" + }, + "idu_t1s2": { + "name": "Température - Zone 2 calculée (T1s)" + }, + "current_unit_capacity": { + "name": "Capacité actuelle de l'unité (brut)" + }, + "instant_power0": { + "name": "Puissance - Consommation de chauffage" + }, + "instant_renew_power0": { + "name": "Puissance - Capacité renouvelable de chauffage" + }, + "machine_type": { + "name": "Info - Type de machine" + }, + "odu_model": { + "name": "Info - Code modèle unité extérieure" + }, + "odu_software_version_str": { + "name": "Info - Version logicielle unité extérieure" + }, + "room_rel_hum": { + "name": "Humidité relative de la pièce" + }, + "t5s": { + "name": "Température T5s - Consigne ECS" + }, + "tas": { + "name": "Température Tas - Consigne d'air" + }, + "temp_t4": { + "name": "Température T4 - Air extérieur" + }, + "temp_t5": { + "name": "Température T5 - Ballon d'eau chaude" + }, + "temp_ta": { + "name": "Température Ta - Air ambiant" + }, + "temp_tb_t1": { + "name": "Température TB-T1 - Ballon tampon haut" + }, + "temp_tb_t2": { + "name": "Température TB-T2 - Ballon tampon bas" + }, + "temp_tsolar": { + "name": "Température Tsolar - Panneau solaire" + }, + "temp_tw2": { + "name": "Température Tw2 - Eau zone 2" + }, + "temp_tw_in": { + "name": "Température Tw_in - Entrée d'eau" + }, + "temp_tw_out": { + "name": "Température Tw_out - Sortie d'eau" + }, + "water_flow": { + "name": "Eau - Débit" + }, + "water_pressure": { + "name": "Eau - Pression" + }, + "hmi_sn_code": { + "name": "Info - Numéro de série HMI" + }, + "zone1_temp_set": { + "name": "Température - Consigne zone 1" + }, + "zone2_temp_set": { + "name": "Température - Consigne zone 2" } }, "switch": { "anion": { "name": "Anion" }, + "humidify": { + "name": "Humidifier" + }, + "waterions": { + "name": "Ions d'eau" + }, + "anophelifuge": { + "name": "Anti-moustique" + }, + "display_on_off": { + "name": "Affichage" + }, + "auto_power_off": { + "name": "Arrêt automatique" + }, + "body_feeling_scan": { + "name": "Détection corporelle" + }, "aux_heating": { "name": "Aux Heating" }, @@ -1242,6 +1613,9 @@ "comfort_mode": { "name": "Comfort Mode" }, + "degerming": { + "name": "Stérilisation" + }, "dhw_power": { "name": "DHW Power" }, @@ -1442,6 +1816,18 @@ }, "screen_off": { "name": "Écran éteint" + }, + "wash": { + "name": "Lavage du filtre" + }, + "antifreeze": { + "name": "Antigel" + }, + "dhw_disinfect": { + "name": "ECS - Désinfection" + }, + "holiday_on": { + "name": "Mode - Vacances" } }, "water_heater": { diff --git a/custom_components/midea_ac_lan/translations/hu.json b/custom_components/midea_ac_lan/translations/hu.json index f2016a33..37060eeb 100644 --- a/custom_components/midea_ac_lan/translations/hu.json +++ b/custom_components/midea_ac_lan/translations/hu.json @@ -63,6 +63,18 @@ }, "entity": { "binary_sensor": { + "warm_power": { + "name": "Fűtés üzem" + }, + "cold_power": { + "name": "Hűtés üzem" + }, + "sleep_power": { + "name": "Alvó üzem" + }, + "pump_on": { + "name": "Szivattyú be" + }, "bar_door": { "name": "Bar Door" }, @@ -363,6 +375,114 @@ }, "water_pump_running": { "name": "Vízszivattyú működik" + }, + "filter_status": { + "name": "Szűrő riasztás" + }, + "standby_status": { + "name": "Készenléti állapot" + }, + "out_water": { + "name": "Vízkiadás" + }, + "out_hot_water": { + "name": "Melegvíz-kiadás" + }, + "backflow": { + "name": "Visszafolyás" + }, + "sleep_status": { + "name": "Alvó állapot" + }, + "alarm_on": { + "name": "Hiba - Riasztás" + }, + "aux_heat_on": { + "name": "Fűtőbetét - Kiegészítő hőforrás" + }, + "compressor_on": { + "name": "Kompresszor - Működik" + }, + "cool_capability": { + "name": "Képesség - Hűtés" + }, + "crankcase_heater_on": { + "name": "Fűtőbetét - Forgattyúház" + }, + "dhw_capability": { + "name": "Képesség - HMV" + }, + "disinfect_run": { + "name": "HMV - Fertőtlenítés fut" + }, + "double_zone": { + "name": "Képesség - Két zóna" + }, + "eco_function_state": { + "name": "Üzemmód - ECO funkció" + }, + "eco_timer_state": { + "name": "Üzemmód - ECO időzítő" + }, + "heat_capability": { + "name": "Képesség - Fűtés" + }, + "hmi_energy_ana_set_en": { + "name": "Képesség - Energiaelemzés (HMI)" + }, + "ibh1_on": { + "name": "Fűtőbetét - IBH1" + }, + "ibh2_on": { + "name": "Fűtőbetét - IBH2" + }, + "load_output_tbh": { + "name": "Fűtőbetét - Tároló (TBH)" + }, + "pump_c_running": { + "name": "Pump_C - Kevert kör 2. zóna" + }, + "pump_d_running": { + "name": "Pump_D - HMV" + }, + "pump_i_running": { + "name": "Pump_I - Belső" + }, + "pump_o_running": { + "name": "Pump_O - Külső" + }, + "pump_s_running": { + "name": "Pump_S - Napkollektor" + }, + "remote_onoff": { + "name": "Képesség - Távoli be/ki" + }, + "room_thermal_state": { + "name": "Állapot - Szobatermosztát" + }, + "room_thermal_support": { + "name": "Képesség - Szobatermosztát" + }, + "status_cool": { + "name": "Állapot - Hűtés" + }, + "sv1_open": { + "name": "SV1 - Szelep (HMV)" + }, + "sv2_open": { + "name": "SV2 - Szelep (Fűtés)" + }, + "sv3_open": { + "name": "SV3 - Szelep" + }, + "sys_energy_ana_en": { + "name": "Képesség - Energiaelemzés (Rendszer)" + }, + "tbh_control": { + "name": "Képesség - TBH vezérlés" + }, + "time_set": { + "name": "Képesség - Idő beállítva" } }, "button": { @@ -402,6 +522,9 @@ } }, "number": { + "heating_target_temperature": { + "name": "Fűtés célhőmérséklet" + }, "dry_level": { "name": "Dry Level" }, @@ -446,14 +569,38 @@ } }, "select": { + "heating_mode": { + "name": "Fűtési mód", + "state": { + "user": "Felhasználó", + "activity": "Aktivitás", + "sleep": "Alvás", + "unknown": "Ismeretlen" + } + }, "detect_mode": { - "name": "Detect Mode" + "name": "Detect Mode", + "state": { + "off": "Ki", + "pm_2_5": "PM 2.5", + "methanal": "Methanal" + } }, "direction": { - "name": "Direction" + "name": "Direction", + "state": { + "oscillate": "Oszcillálás" + } }, "fan_speed": { - "name": "Fan Speed" + "name": "Fan Speed", + "state": { + "auto": "Automatikus", + "standby": "Készenlét", + "low": "Alacsony", + "medium": "Közepes", + "high": "Magas" + } }, "fresh_air_exhaust_mode": { "name": "Frisslevegő elszívás sebessége", @@ -475,7 +622,22 @@ } }, "mode": { - "name": "Mode" + "name": "Mode", + "state": { + "standby": "Készenlét", + "auto": "Automatikus", + "manual": "Manuális", + "sleep": "Alvó", + "fast": "Gyors", + "smoke": "Füst", + "off": "Ki", + "heat_high": "Fűtés (magas)", + "heat_low": "Fűtés (alacsony)", + "bath": "Fürdés", + "blow": "Fújás", + "ventilation": "Szellőztetés", + "dry": "Szárítás" + } }, "oscillation_angle": { "name": "Oscillation Angle" @@ -487,7 +649,12 @@ "name": "Power Rate Limit" }, "screen_display": { - "name": "Screen Display" + "name": "Screen Display", + "state": { + "bright": "Világos", + "dim": "Halvány", + "off": "Ki" + } }, "silent_level": { "name": "Silent Level" @@ -530,6 +697,36 @@ } }, "sensor": { + "three_way_mode": { + "name": "Háromjáratú mód" + }, + "heating_unit_type": { + "name": "Fűtőegység típusa" + }, + "return_temperature": { + "name": "Visszatérő hőmérséklet" + }, + "heating_temperature": { + "name": "Fűtési hőmérséklet" + }, + "heating_gap_temperature": { + "name": "Fűtési hiszterézis hőmérséklet" + }, + "user_mode_target_temperature": { + "name": "Felhasználói mód célhőmérséklet" + }, + "activity_mode_target_temperature": { + "name": "Aktivitás mód célhőmérséklet" + }, + "sleep_mode_target_temperature": { + "name": "Alvó mód célhőmérséklet" + }, + "last_time": { + "name": "Üzemidő" + }, + "flow_volume": { + "name": "Térfogatáram" + }, "bathing_leaving_temperature": { "name": "Bathing Leaving Water Temperature" }, @@ -659,6 +856,15 @@ "error_code": { "name": "Error Code" }, + "humidify_feedback": { + "name": "Páratartalom visszajelzés" + }, + "temperature_feedback": { + "name": "Hőmérséklet visszajelzés" + }, + "humidify_mode": { + "name": "Párásítási mód" + }, "estimated_energy_consumption": { "name": "Becsült energiafogyasztás" }, @@ -1218,12 +1424,177 @@ }, "velocity": { "name": "Sebesség" + }, + "filter4_life": { + "name": "4. szűrő élettartama" + }, + "filter5_life": { + "name": "5. szűrő élettartama" + }, + "filter1_maxlife": { + "name": "1. szűrő élettartam-korlát" + }, + "filter2_maxlife": { + "name": "2. szűrő élettartam-korlát" + }, + "filter3_maxlife": { + "name": "3. szűrő élettartam-korlát" + }, + "filter4_maxlife": { + "name": "4. szűrő élettartam-korlát" + }, + "filter5_maxlife": { + "name": "5. szűrő élettartam-korlát" + }, + "hot_pot_temperature": { + "name": "Forróvíz hőmérséklet" + }, + "ice_gall_status": { + "name": "Jégtartály állapota" + }, + "water_kind": { + "name": "Víz típusa", + "state": { + "idle": "Tétlen", + "warm": "Meleg", + "cold": "Hideg" + } + }, + "heat_start": { + "name": "Fűtés indítás", + "state": { + "heating": "Fűtés", + "keep_warm": "Melegen tartás" + } + }, + "comp_total_run_time": { + "name": "Energia - Kompresszor üzemidő" + }, + "dc_bus_voltage": { + "name": "Kültéri egység - DC busz feszültség" + }, + "dc_current": { + "name": "Kültéri egység - DC busz áram" + }, + "disinfect_set_weekday": { + "name": "HMV - Fertőtlenítés napja" + }, + "disinfect_start_hour": { + "name": "HMV - Fertőtlenítés kezdő óra" + }, + "disinfect_start_minutes": { + "name": "HMV - Fertőtlenítés kezdő perc" + }, + "error_code_description": { + "name": "Hiba - Leírás" + }, + "hydbox_subtype": { + "name": "Info - Hidraulikus modul altípus" + }, + "hydrobox_capacity": { + "name": "Info - Hidraulikus modul teljesítmény" + }, + "idu_software_version_str": { + "name": "Info - Beltéri egység szoftververzió" + }, + "idu_t1s1": { + "name": "Hőmérséklet - 1. zóna számított (T1s)" + }, + "idu_t1s2": { + "name": "Hőmérséklet - 2. zóna számított (T1s)" + }, + "current_unit_capacity": { + "name": "Aktuális egységteljesítmény (nyers)" + }, + "instant_power0": { + "name": "Teljesítmény - Fűtési fogyasztás" + }, + "instant_renew_power0": { + "name": "Teljesítmény - Megújuló fűtési teljesítmény" + }, + "machine_type": { + "name": "Info - Gép típusa" + }, + "odu_model": { + "name": "Info - Kültéri egység modellkód" + }, + "odu_software_version_str": { + "name": "Info - Kültéri egység szoftververzió" + }, + "room_rel_hum": { + "name": "Relatív páratartalom" + }, + "t5s": { + "name": "Hőmérséklet T5s - HMV alapjel" + }, + "tas": { + "name": "Hőmérséklet Tas - Levegő alapjel" + }, + "temp_t4": { + "name": "Hőmérséklet T4 - Külső levegő" + }, + "temp_t5": { + "name": "Hőmérséklet T5 - HMV tároló" + }, + "temp_ta": { + "name": "Hőmérséklet Ta - Szobalevegő" + }, + "temp_tb_t1": { + "name": "Hőmérséklet TB-T1 - Puffertartály felső" + }, + "temp_tb_t2": { + "name": "Hőmérséklet TB-T2 - Puffertartály alsó" + }, + "temp_tsolar": { + "name": "Hőmérséklet Tsolar - Napkollektor" + }, + "temp_tw2": { + "name": "Hőmérséklet Tw2 - 2. zóna víz" + }, + "temp_tw_in": { + "name": "Hőmérséklet Tw_in - Vízbemenet" + }, + "temp_tw_out": { + "name": "Hőmérséklet Tw_out - Vízkimenet" + }, + "water_flow": { + "name": "Víz - Térfogatáram" + }, + "water_pressure": { + "name": "Víz - Nyomás" + }, + "hmi_sn_code": { + "name": "Info - HMI sorozatszám" + }, + "zone1_temp_set": { + "name": "Hőmérséklet - 1. zóna alapjel" + }, + "zone2_temp_set": { + "name": "Hőmérséklet - 2. zóna alapjel" } }, "switch": { "anion": { "name": "Anion" }, + "humidify": { + "name": "Párásítás" + }, + "waterions": { + "name": "Vízionok" + }, + "anophelifuge": { + "name": "Szúnyogriasztó" + }, + "display_on_off": { + "name": "Kijelző" + }, + "auto_power_off": { + "name": "Automatikus kikapcsolás" + }, + "body_feeling_scan": { + "name": "Testérzékelés" + }, "aux_heating": { "name": "Aux Heating" }, @@ -1242,6 +1613,9 @@ "comfort_mode": { "name": "Comfort Mode" }, + "degerming": { + "name": "Csírátlanítás" + }, "dhw_power": { "name": "DHW Power" }, @@ -1442,6 +1816,18 @@ }, "screen_off": { "name": "Kijelző kikapcsolása" + }, + "wash": { + "name": "Szűrő mosás" + }, + "antifreeze": { + "name": "Fagyvédelem" + }, + "dhw_disinfect": { + "name": "HMV - Fertőtlenítés" + }, + "holiday_on": { + "name": "Üzemmód - Nyaralás" } }, "water_heater": { diff --git a/custom_components/midea_ac_lan/translations/it.json b/custom_components/midea_ac_lan/translations/it.json index 700c8ef8..a49c5738 100644 --- a/custom_components/midea_ac_lan/translations/it.json +++ b/custom_components/midea_ac_lan/translations/it.json @@ -63,6 +63,18 @@ }, "entity": { "binary_sensor": { + "warm_power": { + "name": "Funzionamento riscaldamento" + }, + "cold_power": { + "name": "Funzionamento raffreddamento" + }, + "sleep_power": { + "name": "Funzionamento notturno" + }, + "pump_on": { + "name": "Pompa accesa" + }, "bar_door": { "name": "Porta Bar" }, @@ -326,6 +338,114 @@ }, "water_pump_running": { "name": "Pompa Acqua in Funzione" + }, + "filter_status": { + "name": "Allarme filtro" + }, + "standby_status": { + "name": "Stato di standby" + }, + "out_water": { + "name": "Erogazione acqua" + }, + "out_hot_water": { + "name": "Erogazione acqua calda" + }, + "backflow": { + "name": "Riflusso" + }, + "sleep_status": { + "name": "Stato di sospensione" + }, + "alarm_on": { + "name": "Errore - Allarme" + }, + "aux_heat_on": { + "name": "Resistenza - Fonte ausiliaria" + }, + "compressor_on": { + "name": "Compressore - In funzione" + }, + "cool_capability": { + "name": "Capacità - Raffrescamento" + }, + "crankcase_heater_on": { + "name": "Resistenza - Carter" + }, + "dhw_capability": { + "name": "Capacità - ACS" + }, + "disinfect_run": { + "name": "ACS - Disinfezione in corso" + }, + "double_zone": { + "name": "Capacità - Doppia zona" + }, + "eco_function_state": { + "name": "Modalità - Funzione ECO" + }, + "eco_timer_state": { + "name": "Modalità - Timer ECO" + }, + "heat_capability": { + "name": "Capacità - Riscaldamento" + }, + "hmi_energy_ana_set_en": { + "name": "Capacità - Analisi energetica (HMI)" + }, + "ibh1_on": { + "name": "Resistenza - IBH1" + }, + "ibh2_on": { + "name": "Resistenza - IBH2" + }, + "load_output_tbh": { + "name": "Resistenza - Accumulo (TBH)" + }, + "pump_c_running": { + "name": "Pump_C - Circuito miscelato zona 2" + }, + "pump_d_running": { + "name": "Pump_D - ACS" + }, + "pump_i_running": { + "name": "Pump_I - Interna" + }, + "pump_o_running": { + "name": "Pump_O - Esterna" + }, + "pump_s_running": { + "name": "Pump_S - Solare" + }, + "remote_onoff": { + "name": "Capacità - Accensione remota" + }, + "room_thermal_state": { + "name": "Stato - Termostato ambiente" + }, + "room_thermal_support": { + "name": "Capacità - Termostato ambiente" + }, + "status_cool": { + "name": "Stato - Raffrescamento" + }, + "sv1_open": { + "name": "SV1 - Valvola (ACS)" + }, + "sv2_open": { + "name": "SV2 - Valvola (Riscaldamento)" + }, + "sv3_open": { + "name": "SV3 - Valvola" + }, + "sys_energy_ana_en": { + "name": "Capacità - Analisi energetica (Sistema)" + }, + "tbh_control": { + "name": "Capacità - Controllo TBH" + }, + "time_set": { + "name": "Capacità - Ora impostata" } }, "button": { @@ -365,6 +485,9 @@ } }, "number": { + "heating_target_temperature": { + "name": "Temperatura target riscaldamento" + }, "dry_level": { "name": "Livello Asciugatura" }, @@ -403,14 +526,38 @@ } }, "select": { + "heating_mode": { + "name": "Modalità riscaldamento", + "state": { + "user": "Utente", + "activity": "Attività", + "sleep": "Notte", + "unknown": "Sconosciuto" + } + }, "detect_mode": { - "name": "Modalità Rilevamento" + "name": "Modalità Rilevamento", + "state": { + "off": "Spento", + "pm_2_5": "PM 2.5", + "methanal": "Metanale" + } }, "direction": { - "name": "Direzione" + "name": "Direzione", + "state": { + "oscillate": "Oscillazione" + } }, "fan_speed": { - "name": "Velocità Ventola" + "name": "Velocità Ventola", + "state": { + "auto": "Auto", + "standby": "Standby", + "low": "Bassa", + "medium": "Media", + "high": "Alta" + } }, "fresh_air_exhaust_mode": { "name": "Velocità Estrazione Aria Fresca", @@ -432,7 +579,22 @@ } }, "mode": { - "name": "Modalità" + "name": "Modalità", + "state": { + "standby": "Standby", + "auto": "Auto", + "manual": "Manuale", + "sleep": "Sleep", + "fast": "Veloce", + "smoke": "Fumo", + "off": "Spento", + "heat_high": "Riscaldamento (alto)", + "heat_low": "Riscaldamento (basso)", + "bath": "Bagno", + "blow": "Soffio", + "ventilation": "Ventilazione", + "dry": "Asciugatura" + } }, "oscillation_angle": { "name": "Angolo Oscillazione" @@ -444,7 +606,12 @@ "name": "Limite Potenza" }, "screen_display": { - "name": "Display Schermo" + "name": "Display Schermo", + "state": { + "bright": "Luminoso", + "dim": "Attenuato", + "off": "Spento" + } }, "silent_level": { "name": "Livello Silenzioso" @@ -487,6 +654,36 @@ } }, "sensor": { + "three_way_mode": { + "name": "Modalità a tre vie" + }, + "heating_unit_type": { + "name": "Tipo di unità di riscaldamento" + }, + "return_temperature": { + "name": "Temperatura di ritorno" + }, + "heating_temperature": { + "name": "Temperatura di riscaldamento" + }, + "heating_gap_temperature": { + "name": "Temperatura di isteresi riscaldamento" + }, + "user_mode_target_temperature": { + "name": "Temperatura target modalità utente" + }, + "activity_mode_target_temperature": { + "name": "Temperatura target modalità attività" + }, + "sleep_mode_target_temperature": { + "name": "Temperatura target modalità notte" + }, + "last_time": { + "name": "Tempo di funzionamento" + }, + "flow_volume": { + "name": "Portata" + }, "bathing_leaving_temperature": { "name": "Temperatura Acqua in Uscita Bagno" }, @@ -660,6 +857,15 @@ "error_code": { "name": "Codice Errore" }, + "humidify_feedback": { + "name": "Feedback umidità" + }, + "temperature_feedback": { + "name": "Feedback temperatura" + }, + "humidify_mode": { + "name": "Modalità umidificazione" + }, "estimated_energy_consumption": { "name": "Consumo Energetico Stimato" }, @@ -1156,12 +1362,177 @@ }, "velocity": { "name": "Velocità" + }, + "filter4_life": { + "name": "Durata filtro 4" + }, + "filter5_life": { + "name": "Durata filtro 5" + }, + "filter1_maxlife": { + "name": "Limite durata filtro 1" + }, + "filter2_maxlife": { + "name": "Limite durata filtro 2" + }, + "filter3_maxlife": { + "name": "Limite durata filtro 3" + }, + "filter4_maxlife": { + "name": "Limite durata filtro 4" + }, + "filter5_maxlife": { + "name": "Limite durata filtro 5" + }, + "hot_pot_temperature": { + "name": "Temperatura acqua calda" + }, + "ice_gall_status": { + "name": "Stato serbatoio ghiaccio" + }, + "water_kind": { + "name": "Tipo di acqua", + "state": { + "idle": "Inattivo", + "warm": "Tiepida", + "cold": "Fredda" + } + }, + "heat_start": { + "name": "Avvio riscaldamento", + "state": { + "heating": "Riscaldamento", + "keep_warm": "Mantenimento in caldo" + } + }, + "comp_total_run_time": { + "name": "Energia - Ore di funzionamento compressore" + }, + "dc_bus_voltage": { + "name": "Unità esterna - Tensione bus CC" + }, + "dc_current": { + "name": "Unità esterna - Corrente bus CC" + }, + "disinfect_set_weekday": { + "name": "ACS - Giorno disinfezione" + }, + "disinfect_start_hour": { + "name": "ACS - Ora di inizio disinfezione" + }, + "disinfect_start_minutes": { + "name": "ACS - Minuto di inizio disinfezione" + }, + "error_code_description": { + "name": "Errore - Descrizione" + }, + "hydbox_subtype": { + "name": "Info - Sottotipo modulo idraulico" + }, + "hydrobox_capacity": { + "name": "Info - Potenza modulo idraulico" + }, + "idu_software_version_str": { + "name": "Info - Versione software unità interna" + }, + "idu_t1s1": { + "name": "Temperatura - Zona 1 calcolata (T1s)" + }, + "idu_t1s2": { + "name": "Temperatura - Zona 2 calcolata (T1s)" + }, + "current_unit_capacity": { + "name": "Capacità attuale dell'unità (grezzo)" + }, + "instant_power0": { + "name": "Potenza - Consumo di riscaldamento" + }, + "instant_renew_power0": { + "name": "Potenza - Capacità rinnovabile di riscaldamento" + }, + "machine_type": { + "name": "Info - Tipo di macchina" + }, + "odu_model": { + "name": "Info - Codice modello unità esterna" + }, + "odu_software_version_str": { + "name": "Info - Versione software unità esterna" + }, + "room_rel_hum": { + "name": "Umidità relativa ambiente" + }, + "t5s": { + "name": "Temperatura T5s - Setpoint ACS" + }, + "tas": { + "name": "Temperatura Tas - Setpoint aria" + }, + "temp_t4": { + "name": "Temperatura T4 - Aria esterna" + }, + "temp_t5": { + "name": "Temperatura T5 - Serbatoio ACS" + }, + "temp_ta": { + "name": "Temperatura Ta - Ambiente interno" + }, + "temp_tb_t1": { + "name": "Temperatura TB-T1 - Puffer alto" + }, + "temp_tb_t2": { + "name": "Temperatura TB-T2 - Puffer basso" + }, + "temp_tsolar": { + "name": "Temperatura Tsolar - Pannello solare" + }, + "temp_tw2": { + "name": "Temperatura Tw2 - Acqua zona 2" + }, + "temp_tw_in": { + "name": "Temperatura Tw_in - Ingresso acqua" + }, + "temp_tw_out": { + "name": "Temperatura Tw_out - Uscita acqua" + }, + "water_flow": { + "name": "Acqua - Portata" + }, + "water_pressure": { + "name": "Acqua - Pressione" + }, + "hmi_sn_code": { + "name": "Info - Numero di serie HMI" + }, + "zone1_temp_set": { + "name": "Temperatura - Setpoint zona 1" + }, + "zone2_temp_set": { + "name": "Temperatura - Setpoint zona 2" } }, "switch": { "anion": { "name": "Anioni" }, + "humidify": { + "name": "Umidifica" + }, + "waterions": { + "name": "Ioni d'acqua" + }, + "anophelifuge": { + "name": "Antizanzare" + }, + "display_on_off": { + "name": "Display" + }, + "auto_power_off": { + "name": "Spegnimento automatico" + }, + "body_feeling_scan": { + "name": "Rilevamento corporeo" + }, "aux_heating": { "name": "Riscaldamento Ausiliario" }, @@ -1180,6 +1551,9 @@ "comfort_mode": { "name": "Modalità Comfort" }, + "degerming": { + "name": "Sterilizzazione" + }, "dhw_power": { "name": "Potenza ACS" }, @@ -1378,6 +1752,18 @@ }, "screen_off": { "name": "Spegnimento schermo" + }, + "wash": { + "name": "Lavaggio filtro" + }, + "antifreeze": { + "name": "Antigelo" + }, + "dhw_disinfect": { + "name": "ACS - Disinfezione" + }, + "holiday_on": { + "name": "Modalità - Vacanza" } }, "water_heater": { diff --git a/custom_components/midea_ac_lan/translations/ru.json b/custom_components/midea_ac_lan/translations/ru.json index d7f23b4d..9afd46b6 100644 --- a/custom_components/midea_ac_lan/translations/ru.json +++ b/custom_components/midea_ac_lan/translations/ru.json @@ -63,6 +63,18 @@ }, "entity": { "binary_sensor": { + "warm_power": { + "name": "Режим обогрева" + }, + "cold_power": { + "name": "Режим охлаждения" + }, + "sleep_power": { + "name": "Ночной режим" + }, + "pump_on": { + "name": "Насос включен" + }, "bar_door": { "name": "Bar Door" }, @@ -363,6 +375,114 @@ }, "water_pump_running": { "name": "Работа водяного насоса" + }, + "filter_status": { + "name": "Тревога фильтра" + }, + "standby_status": { + "name": "Состояние ожидания" + }, + "out_water": { + "name": "Подача воды" + }, + "out_hot_water": { + "name": "Подача горячей воды" + }, + "backflow": { + "name": "Обратный поток" + }, + "sleep_status": { + "name": "Спящий режим" + }, + "alarm_on": { + "name": "Ошибка - Авария" + }, + "aux_heat_on": { + "name": "ТЭН - Дополнительный источник" + }, + "compressor_on": { + "name": "Компрессор - Работает" + }, + "cool_capability": { + "name": "Возможность - Охлаждение" + }, + "crankcase_heater_on": { + "name": "ТЭН - Картер компрессора" + }, + "dhw_capability": { + "name": "Возможность - ГВС" + }, + "disinfect_run": { + "name": "ГВС - Дезинфекция идёт" + }, + "double_zone": { + "name": "Возможность - Две зоны" + }, + "eco_function_state": { + "name": "Режим - Функция ECO" + }, + "eco_timer_state": { + "name": "Режим - Таймер ECO" + }, + "heat_capability": { + "name": "Возможность - Отопление" + }, + "hmi_energy_ana_set_en": { + "name": "Возможность - Анализ энергии (HMI)" + }, + "ibh1_on": { + "name": "ТЭН - IBH1" + }, + "ibh2_on": { + "name": "ТЭН - IBH2" + }, + "load_output_tbh": { + "name": "ТЭН - Бак (TBH)" + }, + "pump_c_running": { + "name": "Pump_C - Смесительный контур зоны 2" + }, + "pump_d_running": { + "name": "Pump_D - ГВС" + }, + "pump_i_running": { + "name": "Pump_I - Внутренний" + }, + "pump_o_running": { + "name": "Pump_O - Внешний" + }, + "pump_s_running": { + "name": "Pump_S - Солнечный контур" + }, + "remote_onoff": { + "name": "Возможность - Удалённое вкл/выкл" + }, + "room_thermal_state": { + "name": "Состояние - Комнатный термостат" + }, + "room_thermal_support": { + "name": "Возможность - Комнатный термостат" + }, + "status_cool": { + "name": "Состояние - Охлаждение" + }, + "sv1_open": { + "name": "SV1 - Клапан (ГВС)" + }, + "sv2_open": { + "name": "SV2 - Клапан (Отопление)" + }, + "sv3_open": { + "name": "SV3 - Клапан" + }, + "sys_energy_ana_en": { + "name": "Возможность - Анализ энергии (Система)" + }, + "tbh_control": { + "name": "Возможность - Управление TBH" + }, + "time_set": { + "name": "Возможность - Время установлено" } }, "button": { @@ -402,6 +522,9 @@ } }, "number": { + "heating_target_temperature": { + "name": "Целевая температура отопления" + }, "dry_level": { "name": "Dry Level" }, @@ -446,14 +569,38 @@ } }, "select": { + "heating_mode": { + "name": "Режим отопления", + "state": { + "user": "Пользовательский", + "activity": "Активность", + "sleep": "Сон", + "unknown": "Неизвестно" + } + }, "detect_mode": { - "name": "Detect Mode" + "name": "Detect Mode", + "state": { + "off": "Выкл", + "pm_2_5": "PM 2.5", + "methanal": "Формальдегид" + } }, "direction": { - "name": "Направление" + "name": "Направление", + "state": { + "oscillate": "Колебание" + } }, "fan_speed": { - "name": "Скорость" + "name": "Скорость", + "state": { + "auto": "Авто", + "standby": "Режим ожидания", + "low": "Низкая", + "medium": "Средняя", + "high": "Высокая" + } }, "fresh_air_exhaust_mode": { "name": "Скорость вытяжки свежего воздуха", @@ -475,7 +622,22 @@ } }, "mode": { - "name": "Режим" + "name": "Режим", + "state": { + "standby": "Режим ожидания", + "auto": "Авто", + "manual": "Ручной", + "sleep": "Сон", + "fast": "Быстрый", + "smoke": "Дым", + "off": "Выкл", + "heat_high": "Нагрев (высокий)", + "heat_low": "Нагрев (низкий)", + "bath": "Ванна", + "blow": "Обдув", + "ventilation": "Вентиляция", + "dry": "Сушка" + } }, "oscillation_angle": { "name": "Oscillation Angle" @@ -487,7 +649,12 @@ "name": "Ограничение мощности" }, "screen_display": { - "name": "Screen Display" + "name": "Screen Display", + "state": { + "bright": "Яркий", + "dim": "Тусклый", + "off": "Выкл" + } }, "silent_level": { "name": "Silent Level" @@ -530,6 +697,36 @@ } }, "sensor": { + "three_way_mode": { + "name": "Трёхходовой режим" + }, + "heating_unit_type": { + "name": "Тип отопительного прибора" + }, + "return_temperature": { + "name": "Температура обратной линии" + }, + "heating_temperature": { + "name": "Температура отопления" + }, + "heating_gap_temperature": { + "name": "Температура гистерезиса отопления" + }, + "user_mode_target_temperature": { + "name": "Целевая температура пользовательского режима" + }, + "activity_mode_target_temperature": { + "name": "Целевая температура режима активности" + }, + "sleep_mode_target_temperature": { + "name": "Целевая температура ночного режима" + }, + "last_time": { + "name": "Время работы" + }, + "flow_volume": { + "name": "Расход" + }, "bathing_leaving_temperature": { "name": "Bathing Leaving Water Temperature" }, @@ -712,6 +909,15 @@ "error_code": { "name": "Код ошибки" }, + "humidify_feedback": { + "name": "Обратная связь по влажности" + }, + "temperature_feedback": { + "name": "Обратная связь по температуре" + }, + "humidify_mode": { + "name": "Режим увлажнения" + }, "estimated_energy_consumption": { "name": "Расчётное энергопотребление" }, @@ -1218,12 +1424,177 @@ }, "velocity": { "name": "Скорость" + }, + "filter4_life": { + "name": "Ресурс фильтра 4" + }, + "filter5_life": { + "name": "Ресурс фильтра 5" + }, + "filter1_maxlife": { + "name": "Предел ресурса фильтра 1" + }, + "filter2_maxlife": { + "name": "Предел ресурса фильтра 2" + }, + "filter3_maxlife": { + "name": "Предел ресурса фильтра 3" + }, + "filter4_maxlife": { + "name": "Предел ресурса фильтра 4" + }, + "filter5_maxlife": { + "name": "Предел ресурса фильтра 5" + }, + "hot_pot_temperature": { + "name": "Температура горячей воды" + }, + "ice_gall_status": { + "name": "Состояние резервуара для льда" + }, + "water_kind": { + "name": "Тип воды", + "state": { + "idle": "Простой", + "warm": "Тёплая", + "cold": "Холодная" + } + }, + "heat_start": { + "name": "Запуск нагрева", + "state": { + "heating": "Нагрев", + "keep_warm": "Поддержание тепла" + } + }, + "comp_total_run_time": { + "name": "Энергия - Наработка компрессора" + }, + "dc_bus_voltage": { + "name": "Наружный блок - Напряжение шины постоянного тока" + }, + "dc_current": { + "name": "Наружный блок - Ток шины постоянного тока" + }, + "disinfect_set_weekday": { + "name": "ГВС - День дезинфекции" + }, + "disinfect_start_hour": { + "name": "ГВС - Час начала дезинфекции" + }, + "disinfect_start_minutes": { + "name": "ГВС - Минута начала дезинфекции" + }, + "error_code_description": { + "name": "Ошибка - Описание" + }, + "hydbox_subtype": { + "name": "Инфо - Подтип гидромодуля" + }, + "hydrobox_capacity": { + "name": "Инфо - Мощность гидромодуля" + }, + "idu_software_version_str": { + "name": "Инфо - Версия ПО внутреннего блока" + }, + "idu_t1s1": { + "name": "Температура - Зона 1 расчётная (T1s)" + }, + "idu_t1s2": { + "name": "Температура - Зона 2 расчётная (T1s)" + }, + "current_unit_capacity": { + "name": "Текущая мощность агрегата (сырое значение)" + }, + "instant_power0": { + "name": "Мощность - Потребление на отопление" + }, + "instant_renew_power0": { + "name": "Мощность - Возобновляемая тепловая мощность" + }, + "machine_type": { + "name": "Инфо - Тип машины" + }, + "odu_model": { + "name": "Инфо - Код модели наружного блока" + }, + "odu_software_version_str": { + "name": "Инфо - Версия ПО наружного блока" + }, + "room_rel_hum": { + "name": "Относительная влажность в помещении" + }, + "t5s": { + "name": "Температура T5s - Уставка ГВС" + }, + "tas": { + "name": "Температура Tas - Уставка воздуха" + }, + "temp_t4": { + "name": "Температура T4 - Наружный воздух" + }, + "temp_t5": { + "name": "Температура T5 - Бак ГВС" + }, + "temp_ta": { + "name": "Температура Ta - Комнатный воздух" + }, + "temp_tb_t1": { + "name": "Температура TB-T1 - Буферная ёмкость, верх" + }, + "temp_tb_t2": { + "name": "Температура TB-T2 - Буферная ёмкость, низ" + }, + "temp_tsolar": { + "name": "Температура Tsolar - Солнечный коллектор" + }, + "temp_tw2": { + "name": "Температура Tw2 - Вода зоны 2" + }, + "temp_tw_in": { + "name": "Температура Tw_in - Вход воды" + }, + "temp_tw_out": { + "name": "Температура Tw_out - Выход воды" + }, + "water_flow": { + "name": "Вода - Расход" + }, + "water_pressure": { + "name": "Вода - Давление" + }, + "hmi_sn_code": { + "name": "Инфо - Серийный номер HMI" + }, + "zone1_temp_set": { + "name": "Температура - Уставка зоны 1" + }, + "zone2_temp_set": { + "name": "Температура - Уставка зоны 2" } }, "switch": { "anion": { "name": "Anion" }, + "humidify": { + "name": "Увлажнение" + }, + "waterions": { + "name": "Ионы воды" + }, + "anophelifuge": { + "name": "Отпугивание комаров" + }, + "display_on_off": { + "name": "Дисплей" + }, + "auto_power_off": { + "name": "Автовыключение" + }, + "body_feeling_scan": { + "name": "Сканирование присутствия" + }, "aux_heating": { "name": "Aux Heating" }, @@ -1242,6 +1613,9 @@ "comfort_mode": { "name": "Comfort Mode" }, + "degerming": { + "name": "Обеззараживание" + }, "dhw_power": { "name": "DHW Power" }, @@ -1442,6 +1816,18 @@ }, "screen_off": { "name": "Выключение экрана" + }, + "wash": { + "name": "Промывка фильтра" + }, + "antifreeze": { + "name": "Защита от замерзания" + }, + "dhw_disinfect": { + "name": "ГВС - Дезинфекция" + }, + "holiday_on": { + "name": "Режим - Отпуск" } }, "water_heater": { diff --git a/custom_components/midea_ac_lan/translations/sk.json b/custom_components/midea_ac_lan/translations/sk.json index 6476d292..bab5f220 100644 --- a/custom_components/midea_ac_lan/translations/sk.json +++ b/custom_components/midea_ac_lan/translations/sk.json @@ -63,6 +63,18 @@ }, "entity": { "binary_sensor": { + "warm_power": { + "name": "Prevádzka kúrenia" + }, + "cold_power": { + "name": "Prevádzka chladenia" + }, + "sleep_power": { + "name": "Nočná prevádzka" + }, + "pump_on": { + "name": "Čerpadlo zapnuté" + }, "bar_door": { "name": "Bar Door" }, @@ -363,6 +375,114 @@ }, "water_pump_running": { "name": "Vodné čerpadlo beží" + }, + "filter_status": { + "name": "Alarm filtra" + }, + "standby_status": { + "name": "Pohotovostný stav" + }, + "out_water": { + "name": "Výdaj vody" + }, + "out_hot_water": { + "name": "Výdaj horúcej vody" + }, + "backflow": { + "name": "Spätný tok" + }, + "sleep_status": { + "name": "Režim spánku" + }, + "alarm_on": { + "name": "Chyba - Alarm" + }, + "aux_heat_on": { + "name": "Ohrievač - Pomocný zdroj" + }, + "compressor_on": { + "name": "Kompresor - Beží" + }, + "cool_capability": { + "name": "Funkcia - Chladenie" + }, + "crankcase_heater_on": { + "name": "Ohrievač - Kľuková skriňa" + }, + "dhw_capability": { + "name": "Funkcia - TÚV" + }, + "disinfect_run": { + "name": "TÚV - Dezinfekcia prebieha" + }, + "double_zone": { + "name": "Funkcia - Dve zóny" + }, + "eco_function_state": { + "name": "Režim - Funkcia ECO" + }, + "eco_timer_state": { + "name": "Režim - Časovač ECO" + }, + "heat_capability": { + "name": "Funkcia - Kúrenie" + }, + "hmi_energy_ana_set_en": { + "name": "Funkcia - Energetická analýza (HMI)" + }, + "ibh1_on": { + "name": "Ohrievač - IBH1" + }, + "ibh2_on": { + "name": "Ohrievač - IBH2" + }, + "load_output_tbh": { + "name": "Ohrievač - Zásobník (TBH)" + }, + "pump_c_running": { + "name": "Pump_C - Zmiešavací okruh zóny 2" + }, + "pump_d_running": { + "name": "Pump_D - TÚV" + }, + "pump_i_running": { + "name": "Pump_I - Vnútorné" + }, + "pump_o_running": { + "name": "Pump_O - Vonkajšie" + }, + "pump_s_running": { + "name": "Pump_S - Solár" + }, + "remote_onoff": { + "name": "Funkcia - Diaľkové zap/vyp" + }, + "room_thermal_state": { + "name": "Stav - Izbový termostat" + }, + "room_thermal_support": { + "name": "Funkcia - Izbový termostat" + }, + "status_cool": { + "name": "Stav - Chladenie" + }, + "sv1_open": { + "name": "SV1 - Ventil (TÚV)" + }, + "sv2_open": { + "name": "SV2 - Ventil (Kúrenie)" + }, + "sv3_open": { + "name": "SV3 - Ventil" + }, + "sys_energy_ana_en": { + "name": "Funkcia - Energetická analýza (Systém)" + }, + "tbh_control": { + "name": "Funkcia - Riadenie TBH" + }, + "time_set": { + "name": "Funkcia - Čas nastavený" } }, "button": { @@ -402,6 +522,9 @@ } }, "number": { + "heating_target_temperature": { + "name": "Cieľová teplota kúrenia" + }, "dry_level": { "name": "Dry Level" }, @@ -446,14 +569,38 @@ } }, "select": { + "heating_mode": { + "name": "Režim kúrenia", + "state": { + "user": "Používateľ", + "activity": "Aktivita", + "sleep": "Spánok", + "unknown": "Neznáme" + } + }, "detect_mode": { - "name": "Detect Mode" + "name": "Detect Mode", + "state": { + "off": "Vypnuté", + "pm_2_5": "PM 2.5", + "methanal": "Methanal" + } }, "direction": { - "name": "Direction" + "name": "Direction", + "state": { + "oscillate": "Oscilovať" + } }, "fan_speed": { - "name": "Fan Speed" + "name": "Fan Speed", + "state": { + "auto": "Automatická", + "standby": "Pohotovostný režim", + "low": "Nízka", + "medium": "Stredná", + "high": "Vysoká" + } }, "fresh_air_exhaust_mode": { "name": "Rýchlosť odvodu čerstvého vzduchu", @@ -475,7 +622,22 @@ } }, "mode": { - "name": "Mode" + "name": "Mode", + "state": { + "standby": "Pohotovostný režim", + "auto": "Automatický", + "manual": "Manuálny", + "sleep": "Spánok", + "fast": "Rýchly", + "smoke": "Dym", + "off": "Vypnuté", + "heat_high": "Kúrenie (vysoké)", + "heat_low": "Kúrenie (nízke)", + "bath": "Kúpanie", + "blow": "Fúkanie", + "ventilation": "Vetranie", + "dry": "Sušenie" + } }, "oscillation_angle": { "name": "Oscillation Angle" @@ -487,7 +649,12 @@ "name": "Power Rate Limit" }, "screen_display": { - "name": "Screen Display" + "name": "Screen Display", + "state": { + "bright": "Jasný", + "dim": "Tlmený", + "off": "Vypnuté" + } }, "silent_level": { "name": "Silent Level" @@ -530,6 +697,36 @@ } }, "sensor": { + "three_way_mode": { + "name": "Trojcestný režim" + }, + "heating_unit_type": { + "name": "Typ vykurovacieho telesa" + }, + "return_temperature": { + "name": "Teplota spiatočky" + }, + "heating_temperature": { + "name": "Teplota kúrenia" + }, + "heating_gap_temperature": { + "name": "Teplota hysterézie kúrenia" + }, + "user_mode_target_temperature": { + "name": "Cieľová teplota používateľského režimu" + }, + "activity_mode_target_temperature": { + "name": "Cieľová teplota režimu aktivity" + }, + "sleep_mode_target_temperature": { + "name": "Cieľová teplota nočného režimu" + }, + "last_time": { + "name": "Doba prevádzky" + }, + "flow_volume": { + "name": "Prietok" + }, "bathing_leaving_temperature": { "name": "Bathing Leaving Water Temperature" }, @@ -659,6 +856,15 @@ "error_code": { "name": "Error Code" }, + "humidify_feedback": { + "name": "Spätná väzba vlhkosti" + }, + "temperature_feedback": { + "name": "Spätná väzba teploty" + }, + "humidify_mode": { + "name": "Režim zvlhčovania" + }, "estimated_energy_consumption": { "name": "Odhadovaná spotreba energie" }, @@ -1218,12 +1424,177 @@ }, "velocity": { "name": "Rýchlosť" + }, + "filter4_life": { + "name": "Životnosť filtra 4" + }, + "filter5_life": { + "name": "Životnosť filtra 5" + }, + "filter1_maxlife": { + "name": "Limit životnosti filtra 1" + }, + "filter2_maxlife": { + "name": "Limit životnosti filtra 2" + }, + "filter3_maxlife": { + "name": "Limit životnosti filtra 3" + }, + "filter4_maxlife": { + "name": "Limit životnosti filtra 4" + }, + "filter5_maxlife": { + "name": "Limit životnosti filtra 5" + }, + "hot_pot_temperature": { + "name": "Teplota horúcej vody" + }, + "ice_gall_status": { + "name": "Stav zásobníka ľadu" + }, + "water_kind": { + "name": "Druh vody", + "state": { + "idle": "Nečinné", + "warm": "Teplá", + "cold": "Studená" + } + }, + "heat_start": { + "name": "Spustenie ohrevu", + "state": { + "heating": "Ohrev", + "keep_warm": "Udržiavanie teploty" + } + }, + "comp_total_run_time": { + "name": "Energia - Doba chodu kompresora" + }, + "dc_bus_voltage": { + "name": "Vonkajšia jednotka - Napätie DC zbernice" + }, + "dc_current": { + "name": "Vonkajšia jednotka - Prúd DC zbernice" + }, + "disinfect_set_weekday": { + "name": "TÚV - Deň dezinfekcie" + }, + "disinfect_start_hour": { + "name": "TÚV - Hodina začiatku dezinfekcie" + }, + "disinfect_start_minutes": { + "name": "TÚV - Minúta začiatku dezinfekcie" + }, + "error_code_description": { + "name": "Chyba - Popis" + }, + "hydbox_subtype": { + "name": "Info - Podtyp hydraulického modulu" + }, + "hydrobox_capacity": { + "name": "Info - Výkon hydraulického modulu" + }, + "idu_software_version_str": { + "name": "Info - Verzia softvéru vnútornej jednotky" + }, + "idu_t1s1": { + "name": "Teplota - Zóna 1 vypočítaná (T1s)" + }, + "idu_t1s2": { + "name": "Teplota - Zóna 2 vypočítaná (T1s)" + }, + "current_unit_capacity": { + "name": "Aktuálny výkon jednotky (surové)" + }, + "instant_power0": { + "name": "Výkon - Spotreba vykurovania" + }, + "instant_renew_power0": { + "name": "Výkon - Obnoviteľný vykurovací výkon" + }, + "machine_type": { + "name": "Info - Typ stroja" + }, + "odu_model": { + "name": "Info - Kód modelu vonkajšej jednotky" + }, + "odu_software_version_str": { + "name": "Info - Verzia softvéru vonkajšej jednotky" + }, + "room_rel_hum": { + "name": "Relatívna vlhkosť v miestnosti" + }, + "t5s": { + "name": "Teplota T5s - Žiadaná hodnota TÚV" + }, + "tas": { + "name": "Teplota Tas - Žiadaná hodnota vzduchu" + }, + "temp_t4": { + "name": "Teplota T4 - Vonkajší vzduch" + }, + "temp_t5": { + "name": "Teplota T5 - Zásobník TÚV" + }, + "temp_ta": { + "name": "Teplota Ta - Vzduch v miestnosti" + }, + "temp_tb_t1": { + "name": "Teplota TB-T1 - Akumulačná nádrž hore" + }, + "temp_tb_t2": { + "name": "Teplota TB-T2 - Akumulačná nádrž dole" + }, + "temp_tsolar": { + "name": "Teplota Tsolar - Solárny panel" + }, + "temp_tw2": { + "name": "Teplota Tw2 - Voda zóny 2" + }, + "temp_tw_in": { + "name": "Teplota Tw_in - Vstup vody" + }, + "temp_tw_out": { + "name": "Teplota Tw_out - Výstup vody" + }, + "water_flow": { + "name": "Voda - Prietok" + }, + "water_pressure": { + "name": "Voda - Tlak" + }, + "hmi_sn_code": { + "name": "Info - Sériové číslo HMI" + }, + "zone1_temp_set": { + "name": "Teplota - Žiadaná hodnota zóny 1" + }, + "zone2_temp_set": { + "name": "Teplota - Žiadaná hodnota zóny 2" } }, "switch": { "anion": { "name": "Anion" }, + "humidify": { + "name": "Zvlhčovanie" + }, + "waterions": { + "name": "Vodné ióny" + }, + "anophelifuge": { + "name": "Odpudzovač komárov" + }, + "display_on_off": { + "name": "Displej" + }, + "auto_power_off": { + "name": "Automatické vypnutie" + }, + "body_feeling_scan": { + "name": "Detekcia prítomnosti" + }, "aux_heating": { "name": "Aux Heating" }, @@ -1242,6 +1613,9 @@ "comfort_mode": { "name": "Comfort Mode" }, + "degerming": { + "name": "Sterilizácia" + }, "dhw_power": { "name": "DHW Power" }, @@ -1445,6 +1819,18 @@ }, "screen_off": { "name": "Vypnutie obrazovky" + }, + "wash": { + "name": "Preplach filtra" + }, + "antifreeze": { + "name": "Ochrana proti zamrznutiu" + }, + "dhw_disinfect": { + "name": "TÚV - Dezinfekcia" + }, + "holiday_on": { + "name": "Režim - Dovolenka" } }, "water_heater": { diff --git a/custom_components/midea_ac_lan/translations/zh-Hans.json b/custom_components/midea_ac_lan/translations/zh-Hans.json index b26d9248..fcceeb11 100644 --- a/custom_components/midea_ac_lan/translations/zh-Hans.json +++ b/custom_components/midea_ac_lan/translations/zh-Hans.json @@ -63,6 +63,18 @@ }, "entity": { "binary_sensor": { + "warm_power": { + "name": "制热运行" + }, + "cold_power": { + "name": "制冷运行" + }, + "sleep_power": { + "name": "睡眠运行" + }, + "pump_on": { + "name": "水泵运行" + }, "bar_door": { "name": "吧台门状态" }, @@ -368,6 +380,114 @@ }, "water_pump_running": { "name": "水泵运行" + }, + "filter_status": { + "name": "滤芯报警" + }, + "standby_status": { + "name": "待机状态" + }, + "out_water": { + "name": "出水" + }, + "out_hot_water": { + "name": "出热水" + }, + "backflow": { + "name": "回流" + }, + "sleep_status": { + "name": "睡眠状态" + }, + "alarm_on": { + "name": "故障 - 报警" + }, + "aux_heat_on": { + "name": "电加热 - 辅助热源" + }, + "compressor_on": { + "name": "压缩机 - 运行中" + }, + "cool_capability": { + "name": "功能 - 制冷" + }, + "crankcase_heater_on": { + "name": "电加热 - 曲轴箱" + }, + "dhw_capability": { + "name": "功能 - 生活热水" + }, + "disinfect_run": { + "name": "生活热水 - 杀菌运行中" + }, + "double_zone": { + "name": "功能 - 双区" + }, + "eco_function_state": { + "name": "模式 - ECO 功能" + }, + "eco_timer_state": { + "name": "模式 - ECO 定时" + }, + "heat_capability": { + "name": "功能 - 制热" + }, + "hmi_energy_ana_set_en": { + "name": "功能 - 能耗分析 (HMI)" + }, + "ibh1_on": { + "name": "电加热 - IBH1" + }, + "ibh2_on": { + "name": "电加热 - IBH2" + }, + "load_output_tbh": { + "name": "电加热 - 水箱 (TBH)" + }, + "pump_c_running": { + "name": "Pump_C - 二区混水回路" + }, + "pump_d_running": { + "name": "Pump_D - 生活热水" + }, + "pump_i_running": { + "name": "Pump_I - 内置" + }, + "pump_o_running": { + "name": "Pump_O - 外置" + }, + "pump_s_running": { + "name": "Pump_S - 太阳能" + }, + "remote_onoff": { + "name": "功能 - 远程开关" + }, + "room_thermal_state": { + "name": "状态 - 室内温控器" + }, + "room_thermal_support": { + "name": "功能 - 室内温控器" + }, + "status_cool": { + "name": "状态 - 制冷" + }, + "sv1_open": { + "name": "SV1 - 阀门 (生活热水)" + }, + "sv2_open": { + "name": "SV2 - 阀门 (制热)" + }, + "sv3_open": { + "name": "SV3 - 阀门" + }, + "sys_energy_ana_en": { + "name": "功能 - 能耗分析 (系统)" + }, + "tbh_control": { + "name": "功能 - TBH 控制" + }, + "time_set": { + "name": "功能 - 时间已设置" } }, "button": { @@ -407,6 +527,9 @@ } }, "number": { + "heating_target_temperature": { + "name": "采暖目标温度" + }, "dry_level": { "name": "烘干档位" }, @@ -451,14 +574,38 @@ } }, "select": { + "heating_mode": { + "name": "采暖模式", + "state": { + "user": "用户", + "activity": "活动", + "sleep": "睡眠", + "unknown": "未知" + } + }, "detect_mode": { - "name": "检测模式" + "name": "检测模式", + "state": { + "off": "关闭", + "pm_2_5": "PM 2.5", + "methanal": "甲醛" + } }, "direction": { - "name": "摇摆方向" + "name": "摇摆方向", + "state": { + "oscillate": "摆动" + } }, "fan_speed": { - "name": "风速设定" + "name": "风速设定", + "state": { + "auto": "自动", + "standby": "待机", + "low": "低速", + "medium": "中速", + "high": "高速" + } }, "fresh_air_exhaust_mode": { "name": "排风风速", @@ -480,7 +627,22 @@ } }, "mode": { - "name": "模式" + "name": "模式", + "state": { + "standby": "待机", + "auto": "自动", + "manual": "手动", + "sleep": "睡眠", + "fast": "快速", + "smoke": "烟雾", + "off": "关闭", + "heat_high": "高温加热", + "heat_low": "低温加热", + "bath": "洗浴", + "blow": "吹风", + "ventilation": "换气", + "dry": "干燥" + } }, "oscillation_angle": { "name": "水平摆头角度" @@ -492,7 +654,12 @@ "name": "功率限制" }, "screen_display": { - "name": "屏幕显示" + "name": "屏幕显示", + "state": { + "bright": "明亮", + "dim": "暗淡", + "off": "关闭" + } }, "silent_level": { "name": "静音级别" @@ -535,6 +702,36 @@ } }, "sensor": { + "three_way_mode": { + "name": "三通模式" + }, + "heating_unit_type": { + "name": "末端类型" + }, + "return_temperature": { + "name": "回水温度" + }, + "heating_temperature": { + "name": "采暖温度" + }, + "heating_gap_temperature": { + "name": "采暖回差温度" + }, + "user_mode_target_temperature": { + "name": "用户模式目标温度" + }, + "activity_mode_target_temperature": { + "name": "活动模式目标温度" + }, + "sleep_mode_target_temperature": { + "name": "睡眠模式目标温度" + }, + "last_time": { + "name": "持续时间" + }, + "flow_volume": { + "name": "水流量" + }, "bathing_leaving_temperature": { "name": "淋浴出水温度" }, @@ -714,6 +911,15 @@ "error_code": { "name": "错误码" }, + "humidify_feedback": { + "name": "湿度反馈" + }, + "temperature_feedback": { + "name": "温度反馈" + }, + "humidify_mode": { + "name": "加湿模式" + }, "estimated_energy_consumption": { "name": "预估能耗" }, @@ -1222,12 +1428,177 @@ }, "velocity": { "name": "流速" + }, + "filter4_life": { + "name": "滤芯4寿命" + }, + "filter5_life": { + "name": "滤芯5寿命" + }, + "filter1_maxlife": { + "name": "滤芯1寿命上限" + }, + "filter2_maxlife": { + "name": "滤芯2寿命上限" + }, + "filter3_maxlife": { + "name": "滤芯3寿命上限" + }, + "filter4_maxlife": { + "name": "滤芯4寿命上限" + }, + "filter5_maxlife": { + "name": "滤芯5寿命上限" + }, + "hot_pot_temperature": { + "name": "热罐温度" + }, + "ice_gall_status": { + "name": "制冰仓状态" + }, + "water_kind": { + "name": "出水类型", + "state": { + "idle": "空闲", + "warm": "温水", + "cold": "冷水" + } + }, + "heat_start": { + "name": "加热启动", + "state": { + "heating": "加热中", + "keep_warm": "保温中" + } + }, + "comp_total_run_time": { + "name": "能耗 - 压缩机累计运行时间" + }, + "dc_bus_voltage": { + "name": "室外机 - 直流母线电压" + }, + "dc_current": { + "name": "室外机 - 直流母线电流" + }, + "disinfect_set_weekday": { + "name": "生活热水 - 杀菌星期" + }, + "disinfect_start_hour": { + "name": "生活热水 - 杀菌开始小时" + }, + "disinfect_start_minutes": { + "name": "生活热水 - 杀菌开始分钟" + }, + "error_code_description": { + "name": "故障 - 说明" + }, + "hydbox_subtype": { + "name": "信息 - 水力模块子类型" + }, + "hydrobox_capacity": { + "name": "信息 - 水力模块容量" + }, + "idu_software_version_str": { + "name": "信息 - 室内机软件版本" + }, + "idu_t1s1": { + "name": "温度 - 一区计算值 (T1s)" + }, + "idu_t1s2": { + "name": "温度 - 二区计算值 (T1s)" + }, + "current_unit_capacity": { + "name": "当前机组能力(原始值)" + }, + "instant_power0": { + "name": "功率 - 制热耗电" + }, + "instant_renew_power0": { + "name": "功率 - 可再生制热能力" + }, + "machine_type": { + "name": "信息 - 机型" + }, + "odu_model": { + "name": "信息 - 室外机型号代码" + }, + "odu_software_version_str": { + "name": "信息 - 室外机软件版本" + }, + "room_rel_hum": { + "name": "室内相对湿度" + }, + "t5s": { + "name": "温度 T5s - 生活热水设定值" + }, + "tas": { + "name": "温度 Tas - 空气设定值" + }, + "temp_t4": { + "name": "温度 T4 - 室外环境" + }, + "temp_t5": { + "name": "温度 T5 - 水箱" + }, + "temp_ta": { + "name": "温度 Ta - 室内环境" + }, + "temp_tb_t1": { + "name": "温度 TB-T1 - 缓冲水箱上部" + }, + "temp_tb_t2": { + "name": "温度 TB-T2 - 缓冲水箱下部" + }, + "temp_tsolar": { + "name": "温度 Tsolar - 太阳能板" + }, + "temp_tw2": { + "name": "温度 Tw2 - 二区水温" + }, + "temp_tw_in": { + "name": "温度 Tw_in - 进水" + }, + "temp_tw_out": { + "name": "温度 Tw_out - 出水" + }, + "water_flow": { + "name": "水 - 流量" + }, + "water_pressure": { + "name": "水 - 压力" + }, + "hmi_sn_code": { + "name": "信息 - 线控器序列号" + }, + "zone1_temp_set": { + "name": "温度 - 一区设定值" + }, + "zone2_temp_set": { + "name": "温度 - 二区设定值" } }, "switch": { "anion": { "name": "负离子开关" }, + "humidify": { + "name": "加湿" + }, + "waterions": { + "name": "水离子" + }, + "anophelifuge": { + "name": "驱蚊" + }, + "display_on_off": { + "name": "显示屏" + }, + "auto_power_off": { + "name": "自动关机" + }, + "body_feeling_scan": { + "name": "体感扫描" + }, "aux_heating": { "name": "电辅热" }, @@ -1246,6 +1617,9 @@ "comfort_mode": { "name": "舒省模式" }, + "degerming": { + "name": "除菌" + }, "dhw_power": { "name": "生活热水电源开关" }, @@ -1394,7 +1768,7 @@ "name": "垂直摆风" }, "self_clean": { - "name": "Self Clean" + "name": "智清洁" }, "ieco": { "name": "iECO 节能" @@ -1449,6 +1823,18 @@ }, "screen_off": { "name": "熄屏" + }, + "wash": { + "name": "滤芯冲洗" + }, + "antifreeze": { + "name": "防冻" + }, + "dhw_disinfect": { + "name": "生活热水 - 杀菌" + }, + "holiday_on": { + "name": "模式 - 假期" } }, "water_heater": { diff --git a/custom_components/spook/__init__.py b/custom_components/spook/__init__.py index 4b5d2e64..a7ee82fe 100644 --- a/custom_components/spook/__init__.py +++ b/custom_components/spook/__init__.py @@ -25,6 +25,7 @@ from .repairs import SpookRepairManager from .run_history import async_setup_run_history from .services import SpookServiceManager from .setup_helpers import async_forward_setup_entry +from .statistics_sources import async_setup_abandoned_statistics_watching from .timed_states import async_setup_timed_states if TYPE_CHECKING: @@ -94,6 +95,13 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: await services.async_setup() entry.async_on_unload(services.async_on_unload) + # Watching before anything can start a wait it has to observe. A repair + # can put a statistic on the clock the first time it looks, and on the + # reload path that happens below rather than at some later event, so a + # watcher registered afterwards would already have missed the beginning + # of what it is meant to be watching. + entry.async_on_unload(async_setup_abandoned_statistics_watching(hass)) + # Who you gonna call? SpookRepairManager! repairs = SpookRepairManager(hass) diff --git a/custom_components/spook/ectoplasms/automation/repairs/unknown_entity_references.py b/custom_components/spook/ectoplasms/automation/repairs/unknown_entity_references.py index 093dec78..e3c22ea5 100644 --- a/custom_components/spook/ectoplasms/automation/repairs/unknown_entity_references.py +++ b/custom_components/spook/ectoplasms/automation/repairs/unknown_entity_references.py @@ -349,4 +349,5 @@ class SpookRepair(AbstractSpookEntityComponentUnknownReferencesRepair): self.hass, entity_ids=all_entities, known_entity_ids=self._known_entity_ids, + known_services=self._known_services, ) diff --git a/custom_components/spook/ectoplasms/group/repairs/unknown_members.py b/custom_components/spook/ectoplasms/group/repairs/unknown_members.py index 86cd1872..94990c12 100644 --- a/custom_components/spook/ectoplasms/group/repairs/unknown_members.py +++ b/custom_components/spook/ectoplasms/group/repairs/unknown_members.py @@ -61,6 +61,7 @@ class SpookRepair(AbstractSpookRepair): ) self.async_create_issue( issue_id=entity.entity_id, + references=unknown_entities, is_fixable=True, data={ "group_entity_id": entity.entity_id, diff --git a/custom_components/spook/ectoplasms/lovelace/repairs/unknown_entity_references.py b/custom_components/spook/ectoplasms/lovelace/repairs/unknown_entity_references.py index 43265121..fc5b2368 100644 --- a/custom_components/spook/ectoplasms/lovelace/repairs/unknown_entity_references.py +++ b/custom_components/spook/ectoplasms/lovelace/repairs/unknown_entity_references.py @@ -103,6 +103,7 @@ class SpookRepair(AbstractSpookRepair): title = dashboard.config.get("title", url_path) self.async_create_issue( issue_id=url_path, + references=unknown_entities, translation_placeholders={ "entities": async_describe_unknown_entities( self.hass, sorted(unknown_entities) diff --git a/custom_components/spook/ectoplasms/proximity/repairs/unknown_ignored_zones.py b/custom_components/spook/ectoplasms/proximity/repairs/unknown_ignored_zones.py index fa3324f4..ed452c7a 100644 --- a/custom_components/spook/ectoplasms/proximity/repairs/unknown_ignored_zones.py +++ b/custom_components/spook/ectoplasms/proximity/repairs/unknown_ignored_zones.py @@ -51,6 +51,7 @@ class SpookRepair(AbstractSpookRepair): ): self.async_create_issue( issue_id=entry.entry_id, + references=unknown_entities, translation_placeholders={ "name": coordinator.name, "zones": async_describe_unknown_entities( diff --git a/custom_components/spook/ectoplasms/proximity/repairs/unknown_tracked_entities.py b/custom_components/spook/ectoplasms/proximity/repairs/unknown_tracked_entities.py index 12bee7bf..796ff054 100644 --- a/custom_components/spook/ectoplasms/proximity/repairs/unknown_tracked_entities.py +++ b/custom_components/spook/ectoplasms/proximity/repairs/unknown_tracked_entities.py @@ -51,6 +51,7 @@ class SpookRepair(AbstractSpookRepair): ): self.async_create_issue( issue_id=entry.entry_id, + references=unknown_entities, translation_placeholders={ "name": coordinator.name, "entities": async_describe_unknown_entities( diff --git a/custom_components/spook/ectoplasms/proximity/repairs/unknown_zone.py b/custom_components/spook/ectoplasms/proximity/repairs/unknown_zone.py index d9fcce19..0d51bc91 100644 --- a/custom_components/spook/ectoplasms/proximity/repairs/unknown_zone.py +++ b/custom_components/spook/ectoplasms/proximity/repairs/unknown_zone.py @@ -45,6 +45,7 @@ class SpookRepair(AbstractSpookRepair): if coordinator.proximity_zone_id not in known_entity_ids: self.async_create_issue( issue_id=entry.entry_id, + references=[coordinator.proximity_zone_id], translation_placeholders={ "name": coordinator.name, "zone": coordinator.proximity_zone_id, diff --git a/custom_components/spook/ectoplasms/scene/repairs/unknown_entity_references.py b/custom_components/spook/ectoplasms/scene/repairs/unknown_entity_references.py index 9b8bce94..f9d8d149 100644 --- a/custom_components/spook/ectoplasms/scene/repairs/unknown_entity_references.py +++ b/custom_components/spook/ectoplasms/scene/repairs/unknown_entity_references.py @@ -60,6 +60,7 @@ class SpookRepair(AbstractSpookRepair): ) self.async_create_issue( issue_id=entity.entity_id, + references=unknown_entities, translation_placeholders={ "entities": async_describe_unknown_entities( self.hass, sorted(unknown_entities) diff --git a/custom_components/spook/ectoplasms/script/repairs/unknown_entity_references.py b/custom_components/spook/ectoplasms/script/repairs/unknown_entity_references.py index 64f1dc31..1d879401 100644 --- a/custom_components/spook/ectoplasms/script/repairs/unknown_entity_references.py +++ b/custom_components/spook/ectoplasms/script/repairs/unknown_entity_references.py @@ -8,7 +8,7 @@ from homeassistant.components import script from homeassistant.const import EVENT_COMPONENT_LOADED from homeassistant.helpers import entity_registry as er -from ....entity_filtering import async_get_all_entity_ids +from ....entity_filtering import async_get_all_entity_ids, async_get_all_services from ....repairs import AbstractSpookEntityComponentUnknownReferencesRepair from ....template_extraction import ( async_extract_entities_from_config, @@ -61,13 +61,19 @@ def extract_referenced_entities_from_script(entity: script.ScriptEntity) -> set[ async def extract_template_entities_from_script_entity( - hass: HomeAssistant, entity: Any + hass: HomeAssistant, + entity: Any, + known_services: set[str] | None = None, ) -> set[str]: """Extract entities from script configuration using Template analysis. This function finds template strings in script configuration and creates Template objects to extract entity references using Template.async_render_to_info(). This provides more comprehensive entity detection than regex-based parsing alone. + + ``known_services`` is built once per inspection and handed down, because + building it flattens every service Home Assistant has and every script + with a template in it needs the same answer. """ # Get the script configuration config = None @@ -82,7 +88,7 @@ async def extract_template_entities_from_script_entity( if not config: return set() - return await async_extract_entities_from_config(hass, config) + return await async_extract_entities_from_config(hass, config, known_services) class SpookRepair(AbstractSpookEntityComponentUnknownReferencesRepair): @@ -104,6 +110,7 @@ class SpookRepair(AbstractSpookEntityComponentUnknownReferencesRepair): edit_url_pattern = "/config/script/edit/{unique_id}" _known_entity_ids: set[str] + _known_services: set[str] def _get_blueprint_trigger_entities(self, entity: script.ScriptEntity) -> set[str]: """Extract entity references from blueprint trigger inputs.""" @@ -134,10 +141,16 @@ class SpookRepair(AbstractSpookEntityComponentUnknownReferencesRepair): return entities async def _async_setup_inspection(self) -> None: - """Cache known entity IDs (including ALL/NONE) for this inspection cycle.""" + """Cache what every script in this cycle needs looked up. + + The service set is in here for the same reason as the entity ids: + building it flattens every service Home Assistant has, and it is the + same answer for every script in one pass. + """ self._known_entity_ids = async_get_all_entity_ids( self.hass, include_all_none=True ) + self._known_services = async_get_all_services(self.hass) async def _async_compute_unknown_references(self, entity: Any) -> set[str]: """Return unknown entity IDs referenced by ``entity`` (incl. templates).""" @@ -149,11 +162,14 @@ class SpookRepair(AbstractSpookEntityComponentUnknownReferencesRepair): # Extract entities from Template objects within the script entity all_entities.update( - await extract_template_entities_from_script_entity(self.hass, entity) + await extract_template_entities_from_script_entity( + self.hass, entity, self._known_services + ) ) return await async_filter_known_entity_ids_with_templates( self.hass, entity_ids=all_entities, known_entity_ids=self._known_entity_ids, + known_services=self._known_services, ) diff --git a/custom_components/spook/entity_filtering.py b/custom_components/spook/entity_filtering.py index 5d464930..757e3f1c 100644 --- a/custom_components/spook/entity_filtering.py +++ b/custom_components/spook/entity_filtering.py @@ -48,7 +48,7 @@ from .listeners import async_listen_once_tracked if TYPE_CHECKING: from collections.abc import Callable, Iterable, Mapping, Sequence - from homeassistant.core import HomeAssistant + from homeassistant.core import Event, HomeAssistant # Entity domains to ignore when filtering unknown entities. These can be @@ -98,6 +98,7 @@ class EntityIDsCache: entity_ids_by_domain: dict[str, list[str]] | None = None created_scene_ids: set[str] | None = None rename_suggestions: dict[str, str | None] | None = None + deleted_entities: dict[str, er.DeletedRegistryEntry] | None = None unsubscribe: Callable[[], None] | None = None @@ -138,7 +139,20 @@ def async_setup_all_entity_ids_cache_invalidation( cache.entity_ids = None cache.entity_ids_by_domain = None cache.created_scene_ids = None + + @callback + def _clear_cache_and_suggestions(*_args: Any) -> None: + """Clear the entity IDs and the rename suggestions worked out from them. + + Kept apart from `_clear_cache` because the two cost wildly different + amounts to rebuild. The entity IDs are a couple of set unions. A + suggestion is a fuzzy comparison against every entity in its domain, + and there is one per broken reference in the house, so throwing them + away is tens of seconds of solid work on a large installation. #1667. + """ + _clear_cache() cache.rename_suggestions = None + cache.deleted_entities = None @callback def _state_entity_changed(event_data: Mapping[str, Any]) -> bool: @@ -147,17 +161,41 @@ def async_setup_all_entity_ids_cache_invalidation( event_data.get("old_state") is None or event_data.get("new_state") is None ) + @callback + def _registry_updated(event: Event[er.EventEntityRegistryUpdatedData]) -> None: + """Handle a registry entry being created, removed or changed. + + The suggestions only go when the pool they were drawn from moves: + an entity registered, unregistered, or renamed. Registry entries are + written for plenty of other reasons (an icon, a category, a device + being reassigned), and none of those change what an entity is called. + """ + data = event.data + pool_moved = data["action"] != "update" or "entity_id" in data["changes"] + + if pool_moved: + _clear_cache_and_suggestions() + return + + _clear_cache() + # Listen for entity registry updates unsub_registry_update = hass.bus.async_listen( - er.EVENT_ENTITY_REGISTRY_UPDATED, _clear_cache + er.EVENT_ENTITY_REGISTRY_UPDATED, _registry_updated ) # Listen for Home Assistant start to ensure cache is clear then unsub_hass_start = async_listen_once_tracked( - hass, EVENT_HOMEASSISTANT_START, _clear_cache + hass, EVENT_HOMEASSISTANT_START, _clear_cache_and_suggestions ) # Listen for components loading - unsub_component_loaded = hass.bus.async_listen(EVENT_COMPONENT_LOADED, _clear_cache) - # Listen for state-only entities being added or removed. + unsub_component_loaded = hass.bus.async_listen( + EVENT_COMPONENT_LOADED, _clear_cache_and_suggestions + ) + # Listen for state-only entities being added or removed. The suggestions + # are left standing here: an entity arriving or leaving the state machine + # without touching the registry is the noisiest event in the house, and a + # suggestion that is a few minutes out of date is a sentence in an issue + # description, not a wrong answer about what is missing. unsub_state_changed = hass.bus.async_listen( EVENT_STATE_CHANGED, _clear_cache, @@ -165,7 +203,7 @@ def async_setup_all_entity_ids_cache_invalidation( ) # Perform an initial clear, just in case. - _clear_cache() + _clear_cache_and_suggestions() def _unsubscribe_listeners() -> None: LOGGER.debug( @@ -175,10 +213,7 @@ def async_setup_all_entity_ids_cache_invalidation( unsub_hass_start() unsub_component_loaded() unsub_state_changed() - cache.entity_ids = None - cache.entity_ids_by_domain = None - cache.created_scene_ids = None - cache.rename_suggestions = None + _clear_cache_and_suggestions() cache.unsubscribe = None # Mark as unsubscribed cache.unsubscribe = _unsubscribe_listeners @@ -341,6 +376,52 @@ def async_get_rename_suggestion_cache(hass: HomeAssistant) -> dict[str, str | No return cache.rename_suggestions +@callback +def async_name_helper_in_the_registry(hass: HomeAssistant, entry_id: str) -> str: + """Return how to find the helper behind a config entry, by ID. + + A helper is reported by its title, which is the only name anybody gave + it, and a title is not something Home Assistant can be searched by. When + the helper has gone strange the title is all somebody has, and it takes + them to a Helpers page that does not show it. #1633. + + So: the entity IDs it registered, which is what they were looking for. + Failing that the config entry ID, because a helper with nothing in the + entity registry is exactly the one that cannot be found by looking, and + that ID is the handle it is stored under. + """ + registry = er.async_get(hass) + entity_ids = sorted( + entity.entity_id + for entity in er.async_entries_for_config_entry(registry, entry_id) + ) + + return ", ".join(entity_ids) if entity_ids else entry_id + + +@callback +def async_get_deleted_entities( + hass: HomeAssistant, +) -> dict[str, er.DeletedRegistryEntry]: + """Return the deleted entity registry entries, keyed by entity ID. + + Cached, because the description of one broken reference is built per + reference and every one of them wants this same map. Home Assistant keeps + deleted entries around for a long while, so on an old installation there + are thousands of them to walk. + """ + cache = _async_get_cache(hass) + + if cache.deleted_entities is None: + entity_registry = er.async_get(hass) + cache.deleted_entities = { + deleted.entity_id: deleted + for deleted in entity_registry.deleted_entities.values() + } + + return cache.deleted_entities + + @callback def async_get_all_area_ids(hass: HomeAssistant) -> set[str]: """Return all area IDs, known to Home Assistant.""" diff --git a/custom_components/spook/integrations/spook_inverse/manifest.json b/custom_components/spook/integrations/spook_inverse/manifest.json index 55ffe8aa..fe708188 100644 --- a/custom_components/spook/integrations/spook_inverse/manifest.json +++ b/custom_components/spook/integrations/spook_inverse/manifest.json @@ -10,5 +10,5 @@ "iot_class": "calculated", "issue_tracker": "https://github.com/frenck/spook/issues", "requirements": [], - "version": "5.5.1" + "version": "5.6.0" } diff --git a/custom_components/spook/integrations/spook_inverse/translations/sr_Latn.json b/custom_components/spook/integrations/spook_inverse/translations/sr_Latn.json index d7b4fa27..d3b3cbb4 100644 --- a/custom_components/spook/integrations/spook_inverse/translations/sr_Latn.json +++ b/custom_components/spook/integrations/spook_inverse/translations/sr_Latn.json @@ -18,7 +18,7 @@ "title": "Invertuj 👻" }, "user": { - "description": "Ovaj pomoćnik omogućava da obrnete ponašanje entiteta. Na primer, preokreće stanja otvoreno/zatvoreno ili uključeno/isključeno za binarne senzore i prekidače.", + "description": "Ovaj pomoćnik ti omogućava da preokreneš ponašanje entiteta. Na primer, da obrneš stanja otvoreno/zatvoreno ili uključeno/isključeno za binarne senzore i prekidače.", "menu_options": { "binary_sensor": "Invertuj binarni senzor", "switch": "Invertuj prekidač" diff --git a/custom_components/spook/manifest.json b/custom_components/spook/manifest.json index 516025f7..f54b1632 100644 --- a/custom_components/spook/manifest.json +++ b/custom_components/spook/manifest.json @@ -36,5 +36,5 @@ "requirements": [ "cronsim==2.7" ], - "version": "5.5.1" + "version": "5.6.0" } diff --git a/custom_components/spook/repairs.py b/custom_components/spook/repairs.py index 77842c00..1d9ab90a 100644 --- a/custom_components/spook/repairs.py +++ b/custom_components/spook/repairs.py @@ -6,6 +6,7 @@ from abc import ABC, abstractmethod import asyncio from contextlib import suppress from dataclasses import dataclass, field +import hashlib import importlib from pathlib import Path from typing import TYPE_CHECKING, Any, final @@ -36,15 +37,24 @@ from homeassistant.helpers.debounce import Debouncer from homeassistant.helpers.dispatcher import async_dispatcher_connect from homeassistant.helpers.entity_component import DATA_INSTANCES from homeassistant.helpers.event import async_track_time_interval +from homeassistant.helpers.recorder import get_instance from homeassistant.util.async_ import create_eager_task from .const import DOMAIN, LOGGER from .dashboard_resources import is_yaml_managed, redundant_item_ids -from .entity_filtering import async_filter_known_entity_ids, async_get_all_entity_ids -from .entity_suggestions import async_describe_unknown_entities +from .entity_filtering import ( + async_filter_known_entity_ids, + async_get_all_entity_ids, + async_name_helper_in_the_registry, +) +from .entity_suggestions import ( + async_describe_unknown_entities, + async_warm_rename_suggestions, +) +from .statistics_sources import async_settled_orphaned_statistic_ids if TYPE_CHECKING: - from collections.abc import Callable, Coroutine, Mapping, Sized + from collections.abc import Callable, Coroutine, Iterable, Mapping, Sized from datetime import datetime, timedelta from types import ModuleType @@ -57,6 +67,18 @@ if TYPE_CHECKING: # large installations. INSPECTION_YIELD_INTERVAL = 50 +# How long to give the recorder to say it has cleared what it was asked to. +# The same as Home Assistant allows its own Statistics page, which asks the +# recorder the same question the same way. +_CLEARING_TAKES_AT_MOST = 10 + +# Enough of a digest to tell two sets of findings apart. A collision would +# mean one dismissal covering a different finding in the same place, which is +# the thing this exists to prevent, and eight hex characters make that four +# billion to one. +_FINGERPRINT_LENGTH = 8 + + # A min/max helper needs at least this many members to function; Spook must # not prune it below this. _MIN_MAX_MINIMUM_MEMBERS = 2 @@ -67,6 +89,34 @@ def _plural(items: Sized) -> str: return "" if len(items) == 1 else "s" +def _bulleted(items: Iterable[str]) -> str: + """Return the markdown list a repair puts its findings in.""" + return "\n".join(f"- `{item}`" for item in items) + + +def _fingerprint(references: Iterable[str]) -> str: + r"""Return a short digest of what a finding is about. + + Sorted first, because the same findings in a different order are the same + findings, and an ID that moved would resurface an issue somebody had + already dealt with. + + Each one is written down with its length in front of it, so that the + digest reads two different sets two different ways. Joining them with a + separator does not: a reference holding that separator borrows the one + next to it, and `{"a\nb", "c"}` and `{"a", "b\nc"}` come out identical. + Entity IDs cannot do that, but resource URLs, notifier names and + customize keys are whatever somebody typed. + """ + digest = hashlib.sha256() + for reference in sorted(references): + encoded = reference.encode() + digest.update(f"{len(encoded)}:".encode()) + digest.update(encoded) + + return digest.hexdigest()[:_FINGERPRINT_LENGTH] + + class AbstractSpookRepairBase(ABC): """Abstract base class to hold a Spook repairs.""" @@ -103,6 +153,7 @@ class AbstractSpookRepairBase(ABC): issue_domain: str | None = None, issue_id: str, learn_more_url: str | None = None, + references: Iterable[str] | None = None, severity: ir.IssueSeverity = ir.IssueSeverity.WARNING, translation_key: str | None = None, translation_placeholders: dict[str, str] | None = None, @@ -114,7 +165,18 @@ class AbstractSpookRepairBase(ABC): worded differently depending on what the house looks like, so that the alternative is a translated string of its own rather than a sentence smuggled in through a placeholder. + + `references` is what the issue is reporting, when that is a list of + things rather than the one place they were found in. Pass it and the + ID follows the findings, so that pressing "ignore" means "not these" + rather than "nothing here, ever". Without it an issue keyed to a + script keeps its dismissal while its text is quietly rewritten + underneath, and the next genuinely broken thing in that script is + hidden by a decision somebody made about something else. #1395. """ + if references is not None: + issue_id = f"{issue_id}_{_fingerprint(references)}" + self.issue_ids.add(issue_id) ir.async_create_issue( self.hass, @@ -356,10 +418,9 @@ class AbstractSpookEntityComponentUnknownReferencesRepair(AbstractSpookRepair, A automatically_clean_up_issues = True #: Entity class representing an unavailable/broken instance. Entities of - #: this type are still tracked in ``possible_issue_ids`` but skipped during - #: issue creation. ``None`` inspects every entity, including unavailable - #: ones; repairs that diagnose *why* an entity is broken need exactly - #: those. + #: this type are skipped during issue creation. ``None`` inspects every + #: entity, including unavailable ones; repairs that diagnose *why* an + #: entity is broken need exactly those. unavailable_entity_class: type | None = None #: Translation placeholder key holding the entity's display name (e.g. @@ -415,9 +476,14 @@ class AbstractSpookEntityComponentUnknownReferencesRepair(AbstractSpookRepair, A return self.edit_url_pattern.format(unique_id=entity.unique_id) async def async_inspect(self) -> None: - """Trigger an inspection.""" - self.possible_issue_ids.clear() + """Trigger an inspection. + Nothing goes into ``possible_issue_ids`` here. An issue raised by this + repair is keyed to its findings rather than to the entity they were + found in, so a list of inspected entities no longer names anything + that could be in the registry. What this repair left behind is read + back out of the registry instead, which finds all of it. + """ if self.domain not in (instances := self.hass.data.get(DATA_INSTANCES, {})): return @@ -439,14 +505,19 @@ class AbstractSpookEntityComponentUnknownReferencesRepair(AbstractSpookRepair, A # after the round finished. entities = list(entity_component.entities) + # Collected first and reported afterwards, rather than an issue raised + # the moment one is found. Describing a broken entity reference means + # working out what it was probably meant to say, which is the most + # expensive thing in the whole inspection, and gathering the round's + # findings first lets all of that happen in one go. #1667. + findings: list[tuple[Any, list[str]]] = [] + for index, entity in enumerate(entities): if index and index % INSPECTION_YIELD_INTERVAL == 0: # Inspections are CPU-bound; periodically yield to the event # loop so large installations do not stall it. await asyncio.sleep(0) - self.possible_issue_ids.add(entity.entity_id) - unavailable_class = self.unavailable_entity_class # pylint: disable-next=isinstance-second-argument-not-valid-type if unavailable_class is not None and isinstance(entity, unavailable_class): @@ -459,10 +530,18 @@ class AbstractSpookEntityComponentUnknownReferencesRepair(AbstractSpookRepair, A if not unknown: continue - sorted_unknown = sorted(unknown) + findings.append((entity, sorted(unknown))) + if self.references_are_entities and findings: + await async_warm_rename_suggestions( + self.hass, + {reference for _, references in findings for reference in references}, + ) + + for entity, sorted_unknown in findings: self.async_create_issue( issue_id=entity.entity_id, + references=sorted_unknown, translation_placeholders={ self.reference_label: self._format_references(sorted_unknown), self.entity_label: entity.name, @@ -982,6 +1061,9 @@ class MinMaxUnknownSourcesFixFlow(_RemoveOrIgnoreFixFlow): data = self.data or {} return { "helper": str(data.get("helper", "")), + "entity_id": async_name_helper_in_the_registry( + self.hass, str(data.get(self._id_key, "")) + ), "sources": str(data.get("sources", "")), } @@ -1040,6 +1122,9 @@ class HelperUnknownSourcesFixFlow(_RemoveOrIgnoreFixFlow): return { "helper": str(data.get("helper", "")), "domain": str(data.get("domain", "")), + "entity_id": async_name_helper_in_the_registry( + self.hass, str(data.get(self._id_key, "")) + ), "sources": str(data.get("sources", "")), "usage": self._usage_text(str(data.get("helper_config_entry_id", ""))), } @@ -1078,6 +1163,89 @@ class HelperUnknownSourcesFixFlow(_RemoveOrIgnoreFixFlow): return self.async_create_entry(data={}) +class OrphanedStatisticsFixFlow(_RemoveOrIgnoreFixFlow): + """Handler for long-term statistics with no entity left behind them. + + Clearing them is a websocket command the Statistics page calls and no + action anybody can reach, so without this the only way to act on the + report is to open that page and work through it by hand, which on a list + of a couple of hundred is not really an offer at all. #1613. + """ + + _key = "statistics" + _id_key = "orphaned_statistic_ids" + + def _menu_placeholders(self) -> dict[str, str]: + """List what the report named, the way the report listed it.""" + return {"statistics": _bulleted(self._offered())} + + def _offered(self) -> list[str]: + """Return the statistic IDs the report put in front of somebody.""" + written = str((self.data or {}).get(self._id_key, "")) + return [statistic_id for statistic_id in written.split(",") if statistic_id] + + async def async_step_remove( + self, + _: dict[str, str] | None = None, + ) -> FlowResult: + """Clear the statistics, after looking again to see if they still go. + + Looked up again rather than taken from the issue, and then kept in + common with it. An issue sits there until somebody opens it, which + may be days, and this deletes history: nothing goes that was not on + the list they read, and nothing goes that has come back since. + + Asked the same way the report asked it, settling time and all. A + glance would say yes to a sensor that came back long ago and happens + to be between two brief windows right now, which is the case the + wait exists for. + """ + offered = set(self._offered()) + if not offered: + return self.async_abort(reason="nothing_to_clear") + + still_gone = await async_settled_orphaned_statistic_ids(self.hass) + clearing = sorted(offered & still_gone) + if not clearing: + # Nothing on the list still needs clearing. They may have an + # entity behind them again, or somebody may have cleared them by + # hand while the issue sat there. Either way there is nothing to + # do, and which of the two it was is not worth guessing at. + return self.async_abort(reason="nothing_to_clear") + + # Queued rather than done: the recorder takes the work on its own + # thread and says when it has landed. Answering before that would + # close the issue on the strength of having asked, and a recorder + # that is wedged would look like a job well done. Home Assistant's + # own Statistics page waits on exactly this, for exactly this long. + cleared = asyncio.Event() + + def _done() -> None: + """Say so from the recorder's thread.""" + self.hass.loop.call_soon_threadsafe(cleared.set) + + get_instance(self.hass).async_clear_statistics(clearing, on_done=_done) + + try: + async with asyncio.timeout(_CLEARING_TAKES_AT_MOST): + await cleared.wait() + except TimeoutError: + # The work is still queued and will most likely land. Saying it + # is done would be a guess, and leaving the issue up costs + # nothing: the next round clears it if the statistics went, and + # reports them again if they did not. + LOGGER.debug( + "Spook asked for %s to be cleared and the recorder has not " + "said it is done", + ", ".join(clearing), + ) + return self.async_abort(reason="clearing_took_too_long") + + LOGGER.debug("Spook cleared orphaned statistics: %s", ", ".join(clearing)) + + return self.async_create_entry(data={}) + + # Remove-or-ignore fix flows, keyed by the data field that identifies their # leftover registry thing. _REMOVE_OR_IGNORE_FLOWS: dict[str, type[_RemoveOrIgnoreFixFlow]] = { @@ -1090,6 +1258,7 @@ _REMOVE_OR_IGNORE_FLOWS: dict[str, type[_RemoveOrIgnoreFixFlow]] = { "group_entity_id": GroupUnknownMembersFixFlow, "min_max_config_entry_id": MinMaxUnknownSourcesFixFlow, "helper_config_entry_id": HelperUnknownSourcesFixFlow, + "orphaned_statistic_ids": OrphanedStatisticsFixFlow, } diff --git a/custom_components/spook/translations/de.json b/custom_components/spook/translations/de.json index 0787c413..7543cc88 100644 --- a/custom_components/spook/translations/de.json +++ b/custom_components/spook/translations/de.json @@ -7,7 +7,7 @@ }, "step": { "user": { - "description": "Hast du die Readme gelesen? Hast du die Lizenz gelesen? Bist du dir ganz sicher?" + "description": "Hast du die README gelesen? Hast du die Lizenz gelesen? Bist du dir wirklich sicher?" }, "choice_restart": { "description": "Damit Spook die Einrichtung abschließen kann, muss Home Assistant neu gestartet werden.\n\nMöchtest du Home Assistant jetzt neu starten?", @@ -401,7 +401,7 @@ } }, "lovelace_missing_resources": { - "description": "Spook hat einen Geist in deinen Dashboards gefunden 👻\n\nDieses Dashboard verweist auf Dateien, die die nicht mehr existieren:\n\n{resources}\n\n\n\nDies tritt in der Regel auf, wenn eine benutzerdefinierte Karte oder deren Dateien gelöscht wurden, die Ressource jedoch noch vorhanden ist. Um diesen Fehler zu beheben, öffnen Sie „Einstellungen“ > „Dashboards“ > „Ressourcen“ und entfernen oder korrigieren Sie diese Ressourcen.\n\nSpook 👻 Dein Kumpel.", + "description": "Spook hat einen Geist in deinen Dashboards gefunden 👻\n\nDieses Dashboard verweist auf Dateien, die die nicht mehr existieren:\n\n{resources}\n\n\n\nDies passiert normalerweise, wenn eine benutzerdefinierte Karte oder deren Dateien entfernt wurden, die Ressource jedoch zurückgeblieben ist. Um diesen Fehler zu beheben, öffne die [Resources page](/config/lovelace/resources) und entferne oder korrigiere diese Ressourcen. Sie hat keinen eigenen Tab: Auf der Dashboards-Seite befindet sie sich oben rechts hinter den drei Punkten.\n\nSpook 👻 Dein Kumpel.", "title": "Die Ressourcen im Dashboard verweisen auf fehlende Dateien" }, "lovelace_unknown_area_references": { @@ -483,7 +483,7 @@ }, "orphaned_statistics": { "title": "Verwaiste Langzeitstatistik gefunden", - "description": "Spook hat einen Geist in deinem Recorder gefunden 👻\n\nHome Assistant bewahrt Langzeitstatistiken für Folgendes auf, aber es gibt keine passende Entität mehr dazu:\n\n{statistics}\n\n\n\nDas passiert meist, wenn ein Sensor entfernt wurde, während seine Statistiken erhalten blieben. Um diesen Fehler zu beheben, öffne Einstellungen > Werkzeuge > Statistiken und bringe sie dort in Ordnung.\n\nSpook 👻 Dein Kumpel." + "description": "Spook hat einen Geist in deinem Recorder gefunden 👻\n\nHome Assistant speichert Langzeitstatistiken für Folgendes, aber es gibt dafür keine passende Entität mehr:\n\n{statistics}\n\n\n\nDies passiert normalerweise, wenn ein Sensor entfernt wurde, während seine Statistiken aufbewahrt wurden. Um diesen Fehler zu beheben, öffne Einstellungen > Werkzeuge > Statistiken und behebe ihn dort.\n\nSpook 👻 Dein Kumpel." }, "person_unknown_device_trackers": { "fix_flow": { @@ -649,7 +649,7 @@ }, "homeassistant_delete_all_orphaned_entities": { "name": "Alle verwaisten Entitäten löschen", - "description": "Löscht alle verwaisten Entitäten die keiner Integration mehr zugeordnet/bereitgestellt sind. Beachte, falls die Integration erst vor Kurzem gelöscht wurde, ist gegebenenfalls ein Neustart von Home Assistant nötigt, damit diese als verwaist angezeigt werden.\n**WARNUNG** Entitäten könnten auch als verwaist markiert sein, falls eine Integration offline ist oder nach einem Neustart von Home Assistant noch nicht funktioniert. Der Aufruf dieser Aktion löscht auch diese Entitäten." + "description": "Löscht alle verwaisten Entitäten, für die keine Integration mehr zuständig ist (oder die von keiner mehr bereitgestellt werden). Bitte beachten: Falls die Integration gerade erst entfernt wurde, ist möglicherweise ein Neustart erforderlich, damit Home Assistant erkennt, dass sie verwaist sind.\n**WARNUNG** Entitäten könnten als verwaist markiert worden sein, weil eine Integration offline ist oder seit dem Start von Home Assistant nicht funktioniert. Das Ausführen dieser Aktion löscht auch diese Entitäten." }, "homeassistant_create_area": { "fields": { diff --git a/custom_components/spook/translations/en.json b/custom_components/spook/translations/en.json index 5602268c..a86c952b 100644 --- a/custom_components/spook/translations/en.json +++ b/custom_components/spook/translations/en.json @@ -615,7 +615,7 @@ "step": { "init": { "title": "Dashboard resource listed more than once: {resource}", - "description": "Spook has found a ghost in your dashboards \ud83d\udc7b\n\nThis dashboard resource is listed {count} times:\n\n{resources}\n\nThis usually happens when a custom card was updated by adding a resource for the new version instead of editing the one already there. The browser loads both, the card tries to register itself twice, and the second attempt fails, which looks like a broken card rather than a duplicated resource.\n\nSpook can clear the extra copies and keep the most recently added one.\n\nSpook \ud83d\udc7b Your homie.", + "description": "Spook has found a ghost in your dashboards 👻\n\nThis dashboard resource is listed {count} times:\n\n{resources}\n\nThis usually happens when a custom card was updated by adding a resource for the new version instead of editing the one already there. The browser loads both, the card tries to register itself twice, and the second attempt fails, which looks like a broken card rather than a duplicated resource.\n\nSpook can clear the extra copies and keep the most recently added one.\n\nSpook 👻 Your homie.", "menu_options": { "remove": "Clear the extra copies, keep the most recent", "ignore": "Leave them, stop telling me", @@ -644,7 +644,7 @@ "step": { "init": { "title": "Unknown members used in min/max helper: {helper}", - "description": "Spook has found a ghost in your helpers 👻\n\nThe min/max helper {helper} combines the following members, which are unknown to Home Assistant:\n\n{sources}\n\nRemove them so the helper carries on with the members that remain, or keep them and Spook will stop pointing them out.\n\nSpook 👻 Your homie.", + "description": "Spook has found a ghost in your helpers 👻\n\nThe min/max helper {helper} (`{entity_id}`) combines the following members, which are unknown to Home Assistant:\n\n{sources}\n\nRemove them so the helper carries on with the members that remain, or keep them and Spook will stop pointing them out.\n\nSpook 👻 Your homie.", "menu_options": { "remove": "Remove these members", "manage": "Let me fix it myself", @@ -664,8 +664,26 @@ "title": "Unknown members in notify group: {group}" }, "orphaned_statistics": { - "description": "Spook has found a ghost in your recorder 👻\n\nHome Assistant is keeping long-term statistics for the following, but there is no matching entity for them anymore:\n\n{statistics}\n\n\n\nThis usually happens when a sensor was removed while its statistics were kept. To fix this error, open Settings > Tools > Statistics and fix them there.\n\nSpook 👻 Your homie.", - "title": "Orphaned long-term statistics found" + "title": "Orphaned long-term statistics found", + "fix_flow": { + "step": { + "init": { + "title": "Orphaned long-term statistics found", + "description": "Spook has found a ghost in your recorder 👻\n\nHome Assistant is keeping long-term statistics for the following, but there is no matching entity for them anymore:\n\n{statistics}\n\nThis usually happens when a sensor was removed while its statistics were kept. Clearing them throws that history away for good, so Spook looks again before it does, and leaves alone anything that has come back in the meantime.\n\nSpook 👻 Your homie.", + "menu_options": { + "remove": "Clear these statistics", + "manage": "Let me do it myself", + "ignore": "Keep them, stop telling me" + } + } + }, + "abort": { + "issue_ignored": "Spook will keep quiet about these statistics from now on.", + "manage": "You can clear these yourself on the [Statistics page](/config/tools/statistics).", + "nothing_to_clear": "Nothing on that list still needs clearing, so nothing has been thrown away. Either the statistics have an entity behind them again, or they are already gone.", + "clearing_took_too_long": "Spook asked for the statistics to be cleared and the recorder has not said it is done. The work is queued and will most likely land, so this repair stays up until Spook has looked again." + } + } }, "person_unknown_device_trackers": { "title": "Unknown device trackers tracked by: {person}", @@ -748,11 +766,11 @@ "title": "Unknown triggers used in: {script}" }, "template_unknown_entity_references": { - "description": "Spook has found a ghost in your template helpers 👻\n\nWhile floating around, Spook crossed path with the following template helper:\n\n[{helper}]({edit})\n\nIts configuration references the following entities, which are unknown to Home Assistant:\n\n{entities}\n\n\n\nThis often happens when an entity was renamed or removed. To fix this error, reconfigure the template helper to reference existing entities.\n\nSpook 👻 Your homie.", + "description": "Spook has found a ghost in your template helpers 👻\n\nWhile floating around, Spook crossed path with the following template helper:\n\n[{helper}]({edit}) (`{entity_id}`)\n\nIts configuration references the following entities, which are unknown to Home Assistant:\n\n{entities}\n\n\n\nThis often happens when an entity was renamed or removed. To fix this error, reconfigure the template helper to reference existing entities.\n\nSpook 👻 Your homie.", "title": "Unknown entities used in template helper: {helper}" }, "template_unknown_service_references": { - "description": "Spook has found a ghost in your template helpers \ud83d\udc7b\n\nWhile floating around, Spook crossed path with the following template helper:\n\n[{helper}]({edit})\n\nIt references the following actions, which are unknown to Home Assistant:\n\n{services}\n\n\n\nThis often happens when an action provider was removed, or a script was renamed or deleted. To fix this error, reconfigure the template helper to use existing actions.\n\nSpook \ud83d\udc7b Your homie.", + "description": "Spook has found a ghost in your template helpers 👻\n\nWhile floating around, Spook crossed path with the following template helper:\n\n[{helper}]({edit}) (`{entity_id}`)\n\nIt references the following actions, which are unknown to Home Assistant:\n\n{services}\n\n\n\nThis often happens when an action provider was removed, or a script was renamed or deleted. To fix this error, reconfigure the template helper to use existing actions.\n\nSpook 👻 Your homie.", "title": "Unknown actions used in template helper: {helper}" }, "unknown_customized_entities": { @@ -765,7 +783,7 @@ "step": { "init": { "title": "Unknown source entities used in helper: {helper}", - "description": "Spook has found a ghost in your helpers 👻\n\nThe helper {helper} (`{domain}`) references the following source entities, which are unknown to Home Assistant:\n\n{sources}\n\nWithout its sources this helper cannot work. {usage}\n\nRemove the helper, or keep it and Spook will stop pointing it out.\n\nSpook 👻 Your homie.", + "description": "Spook has found a ghost in your helpers 👻\n\nThe helper {helper} (`{domain}`, `{entity_id}`) references the following source entities, which are unknown to Home Assistant:\n\n{sources}\n\nWithout its sources this helper cannot work. {usage}\n\nRemove the helper, or keep it and Spook will stop pointing it out.\n\nSpook 👻 Your homie.", "menu_options": { "remove": "Remove this helper", "manage": "Let me fix it myself", diff --git a/custom_components/spook/translations/sr-Latn.json b/custom_components/spook/translations/sr-Latn.json index 27e4c8a0..5f34d746 100644 --- a/custom_components/spook/translations/sr-Latn.json +++ b/custom_components/spook/translations/sr-Latn.json @@ -7,7 +7,7 @@ }, "step": { "user": { - "description": "Da li ste pročitali README? Da li ste pročitali licencu? Da li ste stvarno sigurni?" + "description": "Da li ste pročitali readme? Da li ste pročitali licencu? Da li ste stvarno sigurni?" }, "choice_restart": { "description": "Da bi Spook završio podešavanje, Home Assistant mora biti restartovan.\n\nDa li želite da restartujete Home Assistant sada?", @@ -1220,7 +1220,7 @@ "description": "ID prostorije sa koje treba ukloniti sprat." } }, - "name": "Ukloni pseudonim iz prostorije", + "name": "Ukloni prostoriju sa sprata", "description": "Uklanjanje prostorije sa sprata. Pošto prostorija može biti samo na jednom spratu, ovaj poziv ne mora da navodi sprat." }, "input_number_decrement": { diff --git a/www/community/lovelace-multiple-entity-row/multiple-entity-row.js b/www/community/lovelace-multiple-entity-row/multiple-entity-row.js index 903e98b1..ad08773e 100644 --- a/www/community/lovelace-multiple-entity-row/multiple-entity-row.js +++ b/www/community/lovelace-multiple-entity-row/multiple-entity-row.js @@ -1,2 +1,2 @@ /*! For license information please see multiple-entity-row.js.LICENSE.txt */ -(()=>{"use strict";const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,n=Symbol(),i=new WeakMap;class r{constructor(t,e,i){if(this._$cssResult$=!0,i!==n)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=t,this.t=e}get styleSheet(){let t=this.o;const n=this.t;if(e&&void 0===t){const e=void 0!==n&&1===n.length;e&&(t=i.get(n)),void 0===t&&((this.o=t=new CSSStyleSheet).replaceSync(this.cssText),e&&i.set(n,t))}return t}toString(){return this.cssText}}const o=(t,...e)=>{const i=1===t.length?t[0]:e.reduce((e,n,i)=>e+(t=>{if(!0===t._$cssResult$)return t.cssText;if("number"==typeof t)return t;throw Error("Value passed to 'css' function must be a 'css' function result: "+t+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(n)+t[i+1],t[0]);return new r(i,t,n)},a=(n,i)=>{if(e)n.adoptedStyleSheets=i.map(t=>t instanceof CSSStyleSheet?t:t.styleSheet);else for(const e of i){const i=document.createElement("style"),r=t.litNonce;void 0!==r&&i.setAttribute("nonce",r),i.textContent=e.cssText,n.appendChild(i)}},s=e?t=>t:t=>t instanceof CSSStyleSheet?(t=>{let e="";for(const n of t.cssRules)e+=n.cssText;return(t=>new r("string"==typeof t?t:t+"",void 0,n))(e)})(t):t,{is:c,defineProperty:l,getOwnPropertyDescriptor:u,getOwnPropertyNames:f,getOwnPropertySymbols:d,getPrototypeOf:h}=Object,p=globalThis,m=p.trustedTypes,y=m?m.emptyScript:"",v=p.reactiveElementPolyfillSupport,b=(t,e)=>t,g={toAttribute(t,e){switch(e){case Boolean:t=t?y:null;break;case Object:case Array:t=null==t?t:JSON.stringify(t)}return t},fromAttribute(t,e){let n=t;switch(e){case Boolean:n=null!==t;break;case Number:n=null===t?null:Number(t);break;case Object:case Array:try{n=JSON.parse(t)}catch(t){n=null}}return n}},_=(t,e)=>!c(t,e),w={attribute:!0,type:String,converter:g,reflect:!1,useDefault:!1,hasChanged:_};Symbol.metadata??=Symbol("metadata"),p.litPropertyMetadata??=new WeakMap;class O extends HTMLElement{static addInitializer(t){this._$Ei(),(this.l??=[]).push(t)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(t,e=w){if(e.state&&(e.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(t)&&((e=Object.create(e)).wrapped=!0),this.elementProperties.set(t,e),!e.noAccessor){const n=Symbol(),i=this.getPropertyDescriptor(t,n,e);void 0!==i&&l(this.prototype,t,i)}}static getPropertyDescriptor(t,e,n){const{get:i,set:r}=u(this.prototype,t)??{get(){return this[e]},set(t){this[e]=t}};return{get:i,set(e){const o=i?.call(this);r?.call(this,e),this.requestUpdate(t,o,n)},configurable:!0,enumerable:!0}}static getPropertyOptions(t){return this.elementProperties.get(t)??w}static _$Ei(){if(this.hasOwnProperty(b("elementProperties")))return;const t=h(this);t.finalize(),void 0!==t.l&&(this.l=[...t.l]),this.elementProperties=new Map(t.elementProperties)}static finalize(){if(this.hasOwnProperty(b("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(b("properties"))){const t=this.properties,e=[...f(t),...d(t)];for(const n of e)this.createProperty(n,t[n])}const t=this[Symbol.metadata];if(null!==t){const e=litPropertyMetadata.get(t);if(void 0!==e)for(const[t,n]of e)this.elementProperties.set(t,n)}this._$Eh=new Map;for(const[t,e]of this.elementProperties){const n=this._$Eu(t,e);void 0!==n&&this._$Eh.set(n,t)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(t){const e=[];if(Array.isArray(t)){const n=new Set(t.flat(1/0).reverse());for(const t of n)e.unshift(s(t))}else void 0!==t&&e.push(s(t));return e}static _$Eu(t,e){const n=e.attribute;return!1===n?void 0:"string"==typeof n?n:"string"==typeof t?t.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(t=>this.enableUpdating=t),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(t=>t(this))}addController(t){(this._$EO??=new Set).add(t),void 0!==this.renderRoot&&this.isConnected&&t.hostConnected?.()}removeController(t){this._$EO?.delete(t)}_$E_(){const t=new Map,e=this.constructor.elementProperties;for(const n of e.keys())this.hasOwnProperty(n)&&(t.set(n,this[n]),delete this[n]);t.size>0&&(this._$Ep=t)}createRenderRoot(){const t=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return a(t,this.constructor.elementStyles),t}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(t=>t.hostConnected?.())}enableUpdating(t){}disconnectedCallback(){this._$EO?.forEach(t=>t.hostDisconnected?.())}attributeChangedCallback(t,e,n){this._$AK(t,n)}_$ET(t,e){const n=this.constructor.elementProperties.get(t),i=this.constructor._$Eu(t,n);if(void 0!==i&&!0===n.reflect){const r=(void 0!==n.converter?.toAttribute?n.converter:g).toAttribute(e,n.type);this._$Em=t,null==r?this.removeAttribute(i):this.setAttribute(i,r),this._$Em=null}}_$AK(t,e){const n=this.constructor,i=n._$Eh.get(t);if(void 0!==i&&this._$Em!==i){const t=n.getPropertyOptions(i),r="function"==typeof t.converter?{fromAttribute:t.converter}:void 0!==t.converter?.fromAttribute?t.converter:g;this._$Em=i;const o=r.fromAttribute(e,t.type);this[i]=o??this._$Ej?.get(i)??o,this._$Em=null}}requestUpdate(t,e,n,i=!1,r){if(void 0!==t){const o=this.constructor;if(!1===i&&(r=this[t]),n??=o.getPropertyOptions(t),!((n.hasChanged??_)(r,e)||n.useDefault&&n.reflect&&r===this._$Ej?.get(t)&&!this.hasAttribute(o._$Eu(t,n))))return;this.C(t,e,n)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(t,e,{useDefault:n,reflect:i,wrapped:r},o){n&&!(this._$Ej??=new Map).has(t)&&(this._$Ej.set(t,o??e??this[t]),!0!==r||void 0!==o)||(this._$AL.has(t)||(this.hasUpdated||n||(e=void 0),this._$AL.set(t,e)),!0===i&&this._$Em!==t&&(this._$Eq??=new Set).add(t))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(t){Promise.reject(t)}const t=this.scheduleUpdate();return null!=t&&await t,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[t,e]of this._$Ep)this[t]=e;this._$Ep=void 0}const t=this.constructor.elementProperties;if(t.size>0)for(const[e,n]of t){const{wrapped:t}=n,i=this[e];!0!==t||this._$AL.has(e)||void 0===i||this.C(e,void 0,n,i)}}let t=!1;const e=this._$AL;try{t=this.shouldUpdate(e),t?(this.willUpdate(e),this._$EO?.forEach(t=>t.hostUpdate?.()),this.update(e)):this._$EM()}catch(e){throw t=!1,this._$EM(),e}t&&this._$AE(e)}willUpdate(t){}_$AE(t){this._$EO?.forEach(t=>t.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(t)),this.updated(t)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(t){return!0}update(t){this._$Eq&&=this._$Eq.forEach(t=>this._$ET(t,this[t])),this._$EM()}updated(t){}firstUpdated(t){}}O.elementStyles=[],O.shadowRootOptions={mode:"open"},O[b("elementProperties")]=new Map,O[b("finalized")]=new Map,v?.({ReactiveElement:O}),(p.reactiveElementVersions??=[]).push("2.1.2");const S=globalThis,A=t=>t,j=S.trustedTypes,$=j?j.createPolicy("lit-html",{createHTML:t=>t}):void 0,x="$lit$",k=`lit$${Math.random().toFixed(9).slice(2)}$`,E="?"+k,C=`<${E}>`,P=document,T=()=>P.createComment(""),M=t=>null===t||"object"!=typeof t&&"function"!=typeof t,I=Array.isArray,R=t=>I(t)||"function"==typeof t?.[Symbol.iterator],H="[ \t\n\f\r]",D=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,F=/-->/g,N=/>/g,U=RegExp(`>|${H}(?:([^\\s"'>=/]+)(${H}*=${H}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),L=/'/g,V=/"/g,z=/^(?:script|style|textarea|title)$/i,B=t=>(e,...n)=>({_$litType$:t,strings:e,values:n}),W=B(1),q=(B(2),B(3),Symbol.for("lit-noChange")),Z=Symbol.for("lit-nothing"),G=new WeakMap,J=P.createTreeWalker(P,129);function K(t,e){if(!I(t)||!t.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==$?$.createHTML(e):e}const Y=(t,e)=>{const n=t.length-1,i=[];let r,o=2===e?"":3===e?"":"",a=D;for(let e=0;e"===c[0]?(a=r??D,l=-1):void 0===c[1]?l=-2:(l=a.lastIndex-c[2].length,s=c[1],a=void 0===c[3]?U:'"'===c[3]?V:L):a===V||a===L?a=U:a===F||a===N?a=D:(a=U,r=void 0);const f=a===U&&t[e+1].startsWith("/>")?" ":"";o+=a===D?n+C:l>=0?(i.push(s),n.slice(0,l)+x+n.slice(l)+k+f):n+k+(-2===l?e:f)}return[K(t,o+(t[n]||"")+(2===e?"":3===e?"":"")),i]};class Q{constructor({strings:t,_$litType$:e},n){let i;this.parts=[];let r=0,o=0;const a=t.length-1,s=this.parts,[c,l]=Y(t,e);if(this.el=Q.createElement(c,n),J.currentNode=this.el.content,2===e||3===e){const t=this.el.content.firstChild;t.replaceWith(...t.childNodes)}for(;null!==(i=J.nextNode())&&s.length0){i.textContent=j?j.emptyScript:"";for(let n=0;n2||""!==n[0]||""!==n[1]?(this._$AH=Array(n.length-1).fill(new String),this.strings=n):this._$AH=Z}_$AI(t,e=this,n,i){const r=this.strings;let o=!1;if(void 0===r)t=X(this,t,e,0),o=!M(t)||t!==this._$AH&&t!==q,o&&(this._$AH=t);else{const i=t;let a,s;for(t=r[0],a=0;a{const i=n?.renderBefore??e;let r=i._$litPart$;if(void 0===r){const t=n?.renderBefore??null;i._$litPart$=r=new et(e.insertBefore(T(),t),t,void 0,n??{})}return r._$AI(t),r})(e,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return q}}ut._$litElement$=!0,ut.finalized=!0,lt.litElementHydrateSupport?.({LitElement:ut});const ft=lt.litElementPolyfillSupport;ft?.({LitElement:ut}),(lt.litElementVersions??=[]).push("4.2.2");var dt=["unavailable","unknown"],ht="last-changed",pt="last-updated",mt=["relative","total","date","time","datetime"],yt=["entity-id","last-changed","last-updated","last-triggered","position","tilt-position","brightness"];function vt(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var n=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=n){var i,r,o,a,s=[],c=!0,l=!1;try{if(o=(n=n.call(t)).next,0===e){if(Object(n)!==n)return;c=!1}else for(;!(c=(i=o.call(n)).done)&&(s.push(i.value),s.length!==e);c=!0);}catch(t){l=!0,r=t}finally{try{if(!c&&null!=n.return&&(a=n.return(),Object(a)!==a))return}finally{if(l)throw r}}return s}}(t,e)||bt(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function bt(t,e){if(t){if("string"==typeof t)return gt(t,e);var n={}.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?gt(t,e):void 0}}function gt(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,i=Array(e);n=t.length?{done:!0}:{done:!1,value:t[n++]}},e:function(t){throw t},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var r,o=!0,a=!1;return{s:function(){e=e.call(t)},n:function(){var t=e.next();return o=t.done,t},e:function(t){a=!0,r=t},f:function(){try{o||null==e.return||e.return()}finally{if(a)throw r}}}}(wt);try{for(i.s();!(e=i.n()).done;){var r=vt(e.value,2),o=r[0],a=r[1];if(customElements.get(o))wt.delete(o);else try{customElements.define(o,a),n.push(o),wt.delete(o)}catch(t){console.warn("multiple-entity-row: re-defining ".concat(o," after registry swap failed"),t)}}}catch(t){i.e(t)}finally{i.f()}n.length&&console.info("multiple-entity-row: re-defined ".concat(n.join(", ")," after customElements registry swap, caught by ").concat(t," (frontend#52960)"))}catch(t){console.warn("multiple-entity-row: customElements registry check failed",t)}},jt=function(){wt.size&&(Ot>=30?wt.clear():(Ot+=1,setTimeout(function(){At("fallback poll"),jt()},1e3)))},$t=function(t,e){try{if(_t.get(t))return void console.warn("multiple-entity-row: ".concat(t," is already defined - a duplicate resource entry or stale cached copy loaded first"));_t.define(t,e)}catch(e){return void console.warn("multiple-entity-row: defining ".concat(t," failed"),e)}wt.set(t,e),St||(St=!0,_t.whenDefined("home-assistant").then(function(){return At("ha-boot signal")}).catch(function(){}),jt())};function xt(t){return xt="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},xt(t)}var kt=function(t){return"object"===xt(t)&&!Array.isArray(t)&&!!t},Et=function(t,e){if(kt(t)&&void 0!==e&&Object.prototype.hasOwnProperty.call(t,e)){var n=t[e];return null==n||""===n?void 0:n}},Ct=function(t,e,n){var i=new Event(e,{bubbles:!0,composed:!0});i.detail=n,t.dispatchEvent(i)},Pt=function(t){return!t||dt.includes(t.state)},Tt=function(t,e,n){if(function(t,e){return e.hide_unavailable&&(Pt(t)||e.attribute&&![ht,pt].includes(e.attribute)&&void 0===t.attributes[e.attribute])}(t,e))return!0;if(void 0===e.hide_if)return!1;if("boolean"==typeof e.hide_if)return e.hide_if;var i;if(kt(e.hide_if)&&(e.hide_if.entity||e.hide_if.attribute)){var r=e.hide_if.entity?null==n?void 0:n.states[e.hide_if.entity]:t;i=e.hide_if.attribute?null==r?void 0:r.attributes[e.hide_if.attribute]:null==r?void 0:r.state}else i=e.attribute?t.attributes[e.attribute]:t.state;var o=[];if(kt(e.hide_if)){if(e.hide_if.below&&ie.hide_if.above)return!0;e.hide_if.value&&(o=o.concat(e.hide_if.value))}else o=o.concat(e.hide_if);return o.some(function(t){return"number"==typeof t?t===+i:t===i})},Mt=["formatEntityName","formatEntityState","formatEntityAttributeValue"],It=new Set(["primary","accent","red","pink","purple","deep-purple","indigo","blue","light-blue","cyan","teal","green","light-green","lime","yellow","amber","orange","deep-orange","brown","light-grey","grey","dark-grey","blue-grey","black","white","primary-text","secondary-text","disabled"]),Rt=function(t){return It.has(t)?"var(--".concat(t,"-color)"):t},Ht=function(t,e){var n=Et(t.state_color,e);return void 0===n?void 0:Rt(String(n))},Dt=function(t){var e;return null!==(e=t.color)&&void 0!==e?e:"boolean"==typeof t.state_color?t.state_color?"state":"none":void 0},Ft=function(t,e,n){var i;if(void 0!==Ht(t,n))return{stateColor:!1};var r=null!==(i=Dt(t))&&void 0!==i?i:t.icon_color||!e?void 0:Dt(e);return void 0===r?t.icon_color?{stateColor:!1}:{stateColor:!0}:"state"===r?{stateColor:!0}:"none"===r?{stateColor:!1}:{cssColor:Rt(r)}},Nt=function(t){return t<10?"0".concat(t):t};function Ut(t){var e=Math.floor(t/3600),n=Math.floor(t%3600/60),i=Math.floor(t%3600%60);return e>0?"".concat(e,":").concat(Nt(n),":").concat(Nt(i)):n>0?"".concat(n,":").concat(Nt(i)):i>0?""+i:null}function Lt(t){return Lt="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},Lt(t)}function Vt(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);e&&(i=i.filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})),n.push.apply(n,i)}return n}function zt(t,e,n){return(e=function(t){var e=function(t){if("object"!=Lt(t)||!t)return t;var e=t[Symbol.toPrimitive];if(void 0!==e){var n=e.call(t,"string");if("object"!=Lt(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(t)}(t);return"symbol"==Lt(e)?e:e+""}(e))in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}var Bt=function(t,e,n){var i=e?function(t){switch(t.number_format){case"comma_decimal":return["en-US","en"];case"decimal_comma":return["de","es","it"];case"space_comma":return["fr","sv","cs"];case"system":return;default:return t.language}}(e):void 0;if(Number.isNaN=Number.isNaN||function t(e){return"number"==typeof e&&t(e)},"none"!==(null==e?void 0:e.number_format)&&!Number.isNaN(Number(t))&&Intl)try{return new Intl.NumberFormat(i,Wt(t,n)).format(Number(t))}catch(e){return console.error(e),new Intl.NumberFormat(void 0,Wt(t,n)).format(Number(t))}return"string"==typeof t?t:"".concat(function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:2;return Math.round(t*Math.pow(10,e))/Math.pow(10,e)}(t,null==n?void 0:n.maximumFractionDigits).toString()).concat("currency"===(null==n?void 0:n.style)?" ".concat(n.currency):"")},Wt=function(t,e){var n=function(t){for(var e=1;e-1?t.split(".")[1].length:0;n.minimumFractionDigits=i,n.maximumFractionDigits=i}return n};function qt(t,e){var n="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(!n){if(Array.isArray(t)||(n=Xt(t))||e&&t&&"number"==typeof t.length){n&&(t=n);var i=0,r=function(){};return{s:r,n:function(){return i>=t.length?{done:!0}:{done:!1,value:t[i++]}},e:function(t){throw t},f:r}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o,a=!0,s=!1;return{s:function(){n=n.call(t)},n:function(){var t=n.next();return a=t.done,t},e:function(t){s=!0,o=t},f:function(){try{a||null==n.return||n.return()}finally{if(s)throw o}}}}function Zt(t,e){for(var n=0;nt.length)&&(e=t.length);for(var n=0,i=Array(e);n2&&void 0!==arguments[2]?arguments[2]:"";ne(t)&&n.push({template:i+t,entity:e})},r=function(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"";i(t.name,e,n),i(t.icon,e,n),i(t.icon_color,e,n),i(t.color,e,n),i(t.template,e,n),i(re(t),e,n),kt(t.styles)&&fe(t.styles,function(t){return i(t,e,n)}),ue.forEach(function(r){return fe(t[r],function(t){return i(t,e,n)})})},o=t.entity;if(r(t,o,le(de(t))),"string"==typeof t.secondary_info)i(t.secondary_info,o,le(de(t)));else if(kt(t.secondary_info)){var a,s=t.secondary_info;r(s,null!==(a=s.entity)&&void 0!==a?a:o,le(de(t,s)))}return null===(e=t.entities)||void 0===e||e.forEach(function(e){if(kt(e)){var n,i=e;r(i,null!==(n=i.entity)&&void 0!==n?n:o,le(de(t,i)))}}),n}(t).map(function(t){return[se(t.template,t.entity),t]})),this.sync()}},{key:"setHass",value:function(t){var e,n=!(null===(e=this.hass)||void 0===e||!e.connection);this.hass=t,!n&&null!=t&&t.connection&&this.sync()}},{key:"connect",value:function(){this.connected=!0,this.sync()}},{key:"disconnect",value:function(){this.connected=!1,this.sync()}},{key:"sync",value:function(){var t,e,n=qt(this.unsubs);try{for(n.s();!(e=n.n()).done;){var i=Qt(e.value,2),r=i[0],o=i[1];this.connected&&this.requests.has(r)||(this.unsubs.delete(r),this.requests.has(r)||(this.results.delete(r),this.errors.delete(r)),o.then(function(t){return null==t?void 0:t()}).catch(function(){}))}}catch(t){n.e(t)}finally{n.f()}if(this.connected&&null!==(t=this.hass)&&void 0!==t&&t.connection){var a,s=qt(this.requests);try{for(s.s();!(a=s.n()).done;){var c=Qt(a.value,2),l=c[0],u=c[1];this.unsubs.has(l)||this.unsubs.set(l,this.subscribe(l,u))}}catch(t){s.e(t)}finally{s.f()}}}},{key:"subscribe",value:function(t,e){var n=this;return this.hass.connection.subscribeMessage(function(e){return n.onMessage(t,e)},{type:"render_template",template:e.template,variables:{entity:e.entity},report_errors:!0}).catch(function(t){return console.warn("multiple-entity-row: template subscription failed:",e.template,t),null})}},{key:"onMessage",value:function(t,e){this.unsubs.has(t)&&(void 0!==e.error?(this.errors.get(t)!==e.error&&(this.errors.set(t,e.error),console.warn("multiple-entity-row: template error:",e.error)),this.results.set(t,"")):(this.errors.delete(t),this.results.set(t,e.result)),this.notify(new Map(this.results)))}}])}();function me(t){return me="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},me(t)}function ye(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);e&&(i=i.filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})),n.push.apply(n,i)}return n}function ve(t){for(var e=1;et.length)&&(e=t.length);for(var n=0,i=Array(e);n1&&a.every(function(t){return xe.test(t)})){var s=r??0;return!isNaN(parseFloat(s))&&isFinite(s)?function(t,e,n,i){var r,o,a=parseFloat(e),s=Se(e),c=!1,l=function(t){c||(s=void 0,r=t)},u=function(t){var e="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(!e){if(Array.isArray(t)||(e=ge(t))){e&&(t=e);var n=0,i=function(){};return{s:i,n:function(){return n>=t.length?{done:!0}:{done:!1,value:t[n++]}},e:function(t){throw t},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var r,o=!0,a=!1;return{s:function(){e=e.call(t)},n:function(){var t=e.next();return o=t.done,t},e:function(t){a=!0,r=t},f:function(){try{o||null==e.return||e.return()}finally{if(a)throw r}}}}(t);try{for(u.s();!(o=u.n()).done;){var f=o.value,d=je.exec(f);if(d&&"precision"===d[1])s=parseInt(d[2],10),r=void 0,c=!0;else if(d)a/={kilo:1e3,mega:1e6,milli:.001}[d[1]],void 0!==d[2]?(s=parseInt(d[2],10),r=void 0,c=!0):l(2);else switch(f){case"brightness":a=Math.round(a/255*100),n="%",l(0);break;case"percent":a*=100,n="%",l(2);break;case"invert":a=-a;break;case"position":a=100-a;break;case"celsius_to_fahrenheit":a=1.8*a+32,l(0);break;case"fahrenheit_to_celsius":a=5*(a-32)/9,l(1)}}}catch(t){u.e(t)}finally{u.f()}return"".concat(Bt(a,i,void 0!==s?{minimumFractionDigits:s,maximumFractionDigits:s}:void 0!==r?{maximumFractionDigits:r}:void 0)).concat(n?" ".concat(n):"")}(a,s,o,t.locale):"".concat(s).concat(o?" ".concat(o):"")}if(n.format&&!function(t){return Ae.some(function(e){return null==t?void 0:t.startsWith(e)})&&!$e(t)}(n.format)){if(null==r&&(r=ke.includes(n.format)?"":0),ke.includes(n.format))return"".concat(function(t,e){switch(t){case"upper":return e.toUpperCase();case"lower":return e.toLowerCase();case"capitalize":return e.charAt(0).toUpperCase()+e.slice(1);case"title":return e.split(/(\s+)/).map(function(t){return t.charAt(0).toUpperCase()+t.slice(1)}).join("")}}(n.format,String(r))).concat(o?" ".concat(o):"");if(isNaN(parseFloat(r))||!isFinite(r));else if("brightness"===n.format)r=Math.round(r/255*100),o="%";else if("percent"===n.format)r=Bt(100*r,t.locale,{maximumFractionDigits:2}),o="%";else if("duration"===n.format){var c;r=null!==(c=Ut(r))&&void 0!==c?c:"0",o=void 0}else if("duration-m"===n.format){var l;r=null!==(l=Ut(r/1e3))&&void 0!==l?l:"0",o=void 0}else if("duration-h"===n.format){var u;r=null!==(u=Ut(3600*r))&&void 0!==u?u:"0",o=void 0}else if($e(n.format)){var f=function(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var n=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=n){var i,r,o,a,s=[],c=!0,l=!1;try{if(o=(n=n.call(t)).next,0===e){if(Object(n)!==n)return;c=!1}else for(;!(c=(i=o.call(n)).done)&&(s.push(i.value),s.length!==e);c=!0);}catch(t){l=!0,r=t}finally{try{if(!c&&null!=n.return&&(a=n.return(),Object(a)!==a))return}finally{if(l)throw r}}return s}}(t,e)||ge(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}($e(n.format),3),d=f[1],h=f[2];if("precision"===d){var p=parseInt(h,10);r=Bt(parseFloat(r),t.locale,{minimumFractionDigits:p,maximumFractionDigits:p})}else r=function(t,e,n,i){if(void 0===n)return Bt(t/e,i,{maximumFractionDigits:2});var r=parseInt(n,10);return Bt(t/e,i,{minimumFractionDigits:r,maximumFractionDigits:r})}(r,{kilo:1e3,mega:1e6,milli:.001}[d],h,t.locale)}else if("invert"===n.format){var m=Se(r);r=Bt(r-2*r,t.locale,void 0!==m?{minimumFractionDigits:m,maximumFractionDigits:m}:void 0)}else if("position"===n.format){var y=Se(r);r=Bt(100-r,t.locale,void 0!==y?{minimumFractionDigits:y,maximumFractionDigits:y}:void 0)}else"celsius_to_fahrenheit"===n.format?r=Bt(1.8*r+32,t.locale,{maximumFractionDigits:0}):"fahrenheit_to_celsius"===n.format&&(r=Bt(5*(r-32)/9,t.locale,{maximumFractionDigits:1}));return"".concat(r).concat(o?" ".concat(o):"")}var v=ve(ve({},e),{},{attributes:ve(ve({},e.attributes),{},{unit_of_measurement:o})});if(void 0!==n.unit&&!n.attribute){if(!isNaN(parseFloat(r))&&isFinite(r)){var b,g=null===(b=t.entities)||void 0===b||null===(b=b[e.entity_id])||void 0===b?void 0:b.display_precision,_=Bt(r,t.locale,null!=g?{minimumFractionDigits:g,maximumFractionDigits:g}:void 0);return"".concat(_).concat(o?" ".concat(o):"")}return"".concat(t.formatEntityState(e)).concat(o?" ".concat(o):"")}if(n.attribute){if(void 0!==n.unit){var w=null==r?"":isNaN(r)?r:Bt(r,t.locale);return"".concat(w).concat(o?" ".concat(o):"")}return Me(t.formatEntityAttributeValue(v,n.attribute))}return Me(t.formatEntityState(v))},Re=function(t){return kt(null==t?void 0:t.styles)?Object.keys(t.styles).filter(function(e){return""!==t.styles[e]&&null!=t.styles[e]}).map(function(e){return"".concat(e,": ").concat(t.styles[e],";")}).join(""):""};class He{constructor(t){}get _$AU(){return this._$AM._$AU}_$AT(t,e,n){this._$Ct=t,this._$AM=e,this._$Ci=n}_$AS(t,e){return this.update(t,e)}update(t,e){return this.render(...e)}}const{I:De}=st,Fe={},Ne=(t=>(...e)=>({_$litDirective$:t,values:e}))(class extends He{constructor(){super(...arguments),this.key=Z}render(t,e){return this.key=t,e}update(t,[e,n]){return e!==this.key&&(((t,e=Fe)=>{t._$AH=e})(t),this.key=e),n}});var Ue,Le,Ve,ze,Be,We,qe,Ze,Ge,Je,Ke,Ye,Qe,Xe,tn,en,nn,rn="__custom__",on=[{value:"",label:"No format"},{value:"brightness",label:"Brightness (0-255 → %)"},{value:"percent",label:"Percent (value × 100 → x %)"},{value:"duration",label:"Duration (seconds → h:mm:ss)"},{value:"duration-m",label:"Duration (milliseconds)"},{value:"duration-h",label:"Duration (hours)"},{value:"precision0",label:"Precision 0 decimals"},{value:"precision1",label:"Precision 1 decimal"},{value:"precision2",label:"Precision 2 decimals"},{value:"precision3",label:"Precision 3 decimals"},{value:"kilo",label:"Kilo (value / 1,000)"},{value:"mega",label:"Mega (value / 1,000,000)"},{value:"milli",label:"Milli (value × 1,000)"},{value:"invert",label:"Invert (value × -1)"},{value:"position",label:"Position (100 - value)"},{value:"celsius_to_fahrenheit",label:"°C → °F"},{value:"fahrenheit_to_celsius",label:"°F → °C"},{value:"upper",label:"Text: UPPERCASE"},{value:"lower",label:"Text: lowercase"},{value:"capitalize",label:"Text: Capitalize first letter"},{value:"title",label:"Text: Title Case"},{value:"relative",label:"Timestamp: relative"},{value:"total",label:"Timestamp: total"},{value:"date",label:"Timestamp: date"},{value:"time",label:"Timestamp: time"},{value:"datetime",label:"Timestamp: date + time"},{value:rn,label:"Custom…"}],an=new Set(on.map(function(t){return t.value}).filter(function(t){return t&&t!==rn})),sn=[{name:"entity",required:!0,selector:{entity:{}}},{type:"grid",schema:[{name:"name",selector:{text:{}}},{name:"attribute",selector:{text:{}}}]},{type:"grid",schema:[{name:"unit",selector:{text:{}}},{name:"icon",selector:{icon:{}}}]},{name:"icon_color",selector:{text:{}}},{name:"name_gap",selector:{text:{}}},{type:"grid",schema:[{name:"show_state",default:!0,selector:{boolean:{}}},{name:"color",selector:{ui_color:{include_state:!0,include_none:!0}}}]},{type:"grid",schema:[{name:"toggle",selector:{boolean:{}}},{name:"column",selector:{boolean:{}}}]},{type:"grid",schema:[{name:"show_state_first",selector:{boolean:{}}},{name:"hide_unavailable",selector:{boolean:{}}},{name:"wrap",selector:{boolean:{}}}]},{name:"state_header",selector:{text:{}}},{name:"image",selector:{text:{}}},{name:"format",selector:{select:{mode:"dropdown",options:on}}}],cn=[{name:"tap_action",selector:{ui_action:{default_action:"more-info"}}},{name:"hold_action",selector:{ui_action:{default_action:"none"}}},{name:"double_tap_action",selector:{ui_action:{default_action:"none"}}}],ln=[{name:"entity",selector:{entity:{}}},{type:"grid",schema:[{name:"name",selector:{text:{}}},{name:"attribute",selector:{text:{}}}]},{type:"grid",schema:[{name:"unit",selector:{text:{}}},{name:"icon",selector:{icon:{}}}]},{name:"icon_color",selector:{text:{}}},{type:"grid",schema:[{name:"color",selector:{ui_color:{include_state:!0,include_none:!0}}},{name:"toggle",selector:{boolean:{}}}]},{name:"hide_unavailable",selector:{boolean:{}}},{name:"format",selector:{select:{mode:"dropdown",options:on}}}],un={entity:"Entity",attribute:"Attribute",name:"Name override (or false to hide)",unit:"Unit (or false to hide)",icon:"Icon",icon_color:"Icon color (CSS value, e.g. red, #ff0000, var(--my-color))",name_gap:"Icon → name gap (CSS length, e.g. 8px; default 16px)",image:"Image URL",format:"Format",show_state:"Show main entity state",show_state_first:"State before entities",state_header:"State header label",color:"Icon color",state_color:"State color",column:"Column layout",wrap:"Wrap instead of overflowing",toggle:"Show as toggle",hide_unavailable:"Hide if unavailable",tap_action:"Tap action",hold_action:"Hold action",double_tap_action:"Double-tap action"};function fn(t,e){return e||(e=t.slice(0)),Object.freeze(Object.defineProperties(t,{raw:{value:Object.freeze(e)}}))}function dn(t){return function(t){if(Array.isArray(t))return An(t)}(t)||function(t){if("undefined"!=typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}(t)||Sn(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function hn(t,e){for(var n=0;n=t.length?{done:!0}:{done:!1,value:t[i++]}},e:function(t){throw t},f:r}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o,a=!0,s=!1;return{s:function(){n=n.call(t)},n:function(){var t=n.next();return a=t.done,t},e:function(t){s=!0,o=t},f:function(){try{a||null==n.return||n.return()}finally{if(s)throw o}}}}function On(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var n=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=n){var i,r,o,a,s=[],c=!0,l=!1;try{if(o=(n=n.call(t)).next,0===e){if(Object(n)!==n)return;c=!1}else for(;!(c=(i=o.call(n)).done)&&(s.push(i.value),s.length!==e);c=!0);}catch(t){l=!0,r=t}finally{try{if(!c&&null!=n.return&&(a=n.return(),Object(a)!==a))return}finally{if(l)throw r}}return s}}(t,e)||Sn(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Sn(t,e){if(t){if("string"==typeof t)return An(t,e);var n={}.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?An(t,e):void 0}}function An(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,i=Array(e);ni.length&&(t._selectedTab=i.length),t._keys.clear(),t._updateConfig({entities:i.length?i:void 0})}}),gn(t,"_moveAdditional",function(e,n){var i;if(t._config){var r=dn(null!==(i=t._config.entities)&&void 0!==i?i:[]),o=e+n;if(!(o<0||o>=r.length)){var a=[r[o],r[e]];r[e]=a[0],r[o]=a[1],t._selectedTab=o+1,t._keys.clear(),t._updateConfig({entities:r})}}}),gn(t,"_copyAdditional",function(e){var n,i=null===(n=t._config)||void 0===n||null===(n=n.entities)||void 0===n?void 0:n[e];null!=i&&t._writeClipboard("string"==typeof i?{entity:i}:bn({},i))}),gn(t,"_cutAdditional",function(e){t._copyAdditional(e),t._deleteAdditional(e)}),gn(t,"_copyMainAsTemplate",function(){if(t._config){var e,n={},i=wn(Nn);try{for(i.s();!(e=i.n()).done;){var r=e.value,o=t._config[r];void 0!==o&&(n[r]=o)}}catch(t){i.e(t)}finally{i.f()}t._writeClipboard(n)}}),gn(t,"_pasteEntity",function(){var e;if(t._config){var n=t._readClipboard();if(n){var i=[].concat(dn(null!==(e=t._config.entities)&&void 0!==e?e:[]),[n]);t._selectedTab=i.length,t._keys.clear(),t._updateConfig({entities:i})}}}),gn(t,"_secondaryModeChanged",function(e){if(t._config){var n=e.detail.value.mode;if(n!==t._secondaryInfoMode()){var i;switch(n){case"none":i=void 0;break;case"text":i="";break;case"generic":i="last-changed";break;case"entity":i={entity:t._config.entity}}t._updateConfig({secondary_info:i})}}}),gn(t,"_secondaryTextChanged",function(e){t._updateConfig({secondary_info:e.detail.value.text})}),gn(t,"_secondaryTokenChanged",function(e){t._updateConfig({secondary_info:e.detail.value.token})}),gn(t,"_secondaryEntityChanged",function(e){var n,i=kt(null===(n=t._config)||void 0===n?void 0:n.secondary_info)?t._config.secondary_info.format:void 0;t._updateConfig({secondary_info:t._formatFromForm("secondary",Dn(e.detail.value),i)})}),t._selectedTab=0,t._entitiesExpanded=!0,t._stateIconRowsMain=[],t._stateIconRowsAdditional=new Map,t._customFormatScopes=new Set,t}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),Object.defineProperty(t,"prototype",{writable:!1}),e&&yn(t,e)}(e,t),function(t,e,n){return e&&hn(t.prototype,e),n&&hn(t,n),Object.defineProperty(t,"prototype",{writable:!1}),t}(e,[{key:"setConfig",value:function(t){var e,n,i,r=this;if(ie(t))throw new Error("This row uses templates - edit it in the code (YAML) editor.");this._config=t;var o,a=null!==(e=null===(n=t.entities)||void 0===n?void 0:n.length)&&void 0!==e?e:0;this._selectedTab>a&&(this._selectedTab=a),this._clipboardEntity=this._readClipboard(),this._stateIconRowsMatch(this._stateIconRowsMain,t.state_icon)||(this._stateIconRowsMain=Object.entries(null!==(o=t.state_icon)&&void 0!==o?o:{}));var s=new Map;null===(i=t.entities)||void 0===i||i.forEach(function(t,e){var n=kt(t)?t.state_icon:void 0,i=r._stateIconRowsAdditional.get(e);i&&r._stateIconRowsMatch(i,n)?s.set(e,i):n&&s.set(e,Object.entries(n))}),this._stateIconRowsAdditional=s}},{key:"_stateIconRowsMatch",value:function(t,e){var n,i={},r=wn(t);try{for(r.s();!(n=r.n()).done;){var o=On(n.value,2),a=o[0],s=o[1];a.trim()&&s.trim()&&(i[a.trim()]=s.trim())}}catch(t){r.e(t)}finally{r.f()}var c=null!=e?e:{},l=Object.keys(i);return l.length===Object.keys(c).length&&l.every(function(t){return i[t]===c[t]})}},{key:"_readClipboard",value:function(){try{var t=sessionStorage.getItem(Fn);if(!t)return;var e=JSON.parse(t);if(e&&"object"===jn(e))return e}catch(t){}}},{key:"_writeClipboard",value:function(t){try{sessionStorage.setItem(Fn,JSON.stringify(t)),this._clipboardEntity=t}catch(t){}}},{key:"_hasNativeTabs",get:function(){return!!customElements.get("ha-tab-group")&&!!customElements.get("ha-tab-group-tab")}},{key:"render",value:function(){return this.hass&&this._config?W(Ue||(Ue=fn(["\n \n ",'\n \n\n \n "])),"Entities",this._entitiesExpanded,this._onEntitiesExpandedChanged,this._renderEntitiesPanel(),"4.11.1","2026-09-02T21:15:15.588Z"):Z}},{key:"_isCustomFormat",value:function(t,e){return this._customFormatScopes.has(t)||!!e&&!an.has(e)}},{key:"_setCustomFormatScope",value:function(t,e){if(e!==this._customFormatScopes.has(t)){var n=new Set(this._customFormatScopes);e?n.add(t):n.delete(t),this._customFormatScopes=n}}},{key:"_formatToForm",value:function(t,e){return this._isCustomFormat(t,e.format)?bn(bn({},e),{},{format:rn}):e}},{key:"_formatFromForm",value:function(t,e,n){if(e.format===rn){this._setCustomFormatScope(t,!0);var i=bn({},e);return void 0!==n?i.format=n:delete i.format,i}return this._setCustomFormatScope(t,!1),e}},{key:"_renderCustomFormatField",value:function(t,e,n){return this._isCustomFormat(t,e)?W(Le||(Le=fn(["\n \n "])),this.hass,{custom_format:null!=e?e:""},[{name:"custom_format",selector:{text:{}}}],function(){return"Custom format (e.g. invert, precision3)"},function(t){var e,i=(null!==(e=t.detail.value.custom_format)&&void 0!==e?e:"").trim();n(i||void 0)}):Z}},{key:"_keyFor",value:function(t){return this._keys.has(t)||this._keys.set(t,"".concat(t,"-").concat(Math.random().toString(36).slice(2,10))),this._keys.get(t)}},{key:"_renderEntitiesPanel",value:function(){var t,e,n=this,i=null!==(t=null===(e=this._config)||void 0===e?void 0:e.entities)&&void 0!==t?t:[],r=Math.min(this._selectedTab,i.length);return W(Ve||(Ve=fn(['\n
\n
\n ','\n \n
\n\n
\n ',"\n
\n
\n "])),this._hasNativeTabs?W(ze||(ze=fn(['\n \n \n \n \n \n
\n
\n \n \n ','\n \n ','\n \n ',"\n \n "])),"Copy main as template",xn,this._copyMainAsTemplate,"Paste as new entity",kn,!this._clipboardEntity,this._pasteEntity,this.hass,this._mainFormData(),sn,this._computeLabel,this._mainValueChanged,this._renderCustomFormatField("main",null===(t=this._config)||void 0===t?void 0:t.format,function(t){return n._updateConfig({format:t})}),this.hass,this._mainFormData(),cn,this._computeLabel,this._mainValueChanged,this._renderSecondaryInfoBlock(),this._renderStateIconRows("main"),this._renderStylesBlock(null===(e=this._config)||void 0===e?void 0:e.styles,function(t){return n._mainStylesChanged(t)}))}},{key:"_renderStylesBlock",value:function(t,e){return W(Ge||(Ge=fn(['\n \n ','\n \n \n \n \n
\n
\n \n \n ','\n \n ',"\n \n "])),"Move before","M15.41,16.58L10.83,12L15.41,7.41L14,6L8,12L14,18L15.41,16.58Z",0===t,function(){return i._moveAdditional(t,-1)},"Move after","M8.59,16.58L13.17,12L8.59,7.41L10,6L16,12L10,18L8.59,16.58Z",t===a,function(){return i._moveAdditional(t,1)},"Copy entity",xn,function(){return i._copyAdditional(t)},"Cut entity","M19,3L13,9L15,11L22,4V3M12,12.5A0.5,0.5 0 0,1 11.5,12A0.5,0.5 0 0,1 12,11.5A0.5,0.5 0 0,1 12.5,12A0.5,0.5 0 0,1 12,12.5M6,20A2,2 0 0,1 4,18C4,16.89 4.9,16 6,16A2,2 0 0,1 8,18C8,19.11 7.1,20 6,20M6,8A2,2 0 0,1 4,6C4,4.89 4.9,4 6,4A2,2 0 0,1 8,6C8,7.11 7.1,8 6,8M9.64,7.64C9.87,7.14 10,6.59 10,6A4,4 0 0,0 6,2A4,4 0 0,0 2,6A4,4 0 0,0 6,10C6.59,10 7.14,9.87 7.64,9.64L10,12L7.64,14.36C7.14,14.13 6.59,14 6,14A4,4 0 0,0 2,18A4,4 0 0,0 6,22A4,4 0 0,0 10,18C10,17.41 9.87,16.86 9.64,16.36L12,14L19,21H22V20L9.64,7.64Z",function(){return i._cutAdditional(t)},"Paste from clipboard",kn,!this._clipboardEntity,this._pasteEntity,"Delete entity",$n,function(){return i._deleteAdditional(t)},this.hass,this._formatToForm("sub-".concat(t),Hn(o)),ln,this._computeLabel,function(e){return i._additionalValueChanged(e,t)},this._renderCustomFormatField("sub-".concat(t),o.format,function(e){return i._setAdditionalFormat(t,e)}),this.hass,this._formatToForm("sub-".concat(t),Hn(o)),cn,this._computeLabel,function(e){return i._additionalValueChanged(e,t)},this._renderStateIconRows(t),this._renderStylesBlock(o.styles,function(e){return i._additionalStylesChanged(e,t)}))}},{key:"_mainFormData",value:function(){return this._formatToForm("main",Hn(bn({show_state:!0},this._config)))}},{key:"_setAdditionalFormat",value:function(t,e){var n;if(this._config){var i=dn(null!==(n=this._config.entities)&&void 0!==n?n:[]),r=i[t],o="string"==typeof r?{entity:r}:bn({},r);e?o.format=e:delete o.format,i[t]=o,this._updateConfig({entities:i})}}},{key:"_secondaryInfoMode",value:function(){var t,e=null===(t=this._config)||void 0===t?void 0:t.secondary_info;return null==e?"none":"object"===jn(e)?"entity":yt.includes(e)?"generic":"text"}},{key:"_renderSecondaryInfoBlock",value:function(){var t,e=this,n=this._secondaryInfoMode(),i=null===(t=this._config)||void 0===t?void 0:t.secondary_info;return W(Qe||(Qe=fn(["\n
\n \n ","\n ","\n ","\n
\n "])),this.hass,{mode:n},En,function(){return"Mode"},this._secondaryModeChanged,"text"===n?W(Xe||(Xe=fn(['
\n \n \n 3?(r=p===i)&&(c=o[(s=o[4])?5:(s=3,3)],o[4]=o[5]=t):o[0]<=h&&((r=n<2&&hi||i>p)&&(o[4]=n,o[5]=i,d.n=p,s=0))}if(r||n>1)return a;throw f=!0,i}return function(r,u,p){if(l>1)throw TypeError("Generator is already running");for(f&&1===u&&h(u,p),s=u,c=p;(e=s<2?t:c)||!f;){o||(s?s<3?(s>1&&(d.n=-1),h(s,c)):d.n=c:d.v=c);try{if(l=2,o){if(s||(r="next"),e=o[r]){if(!(e=e.call(o,c)))throw TypeError("iterator result is not an object");if(!e.done)return e;c=e.value,s<2&&(s=0)}else 1===s&&(e=o.return)&&e.call(o),s<2&&(c=TypeError("The iterator does not provide a '"+r+"' method"),s=1);o=t}else if((e=(f=d.n<0)?c:n.call(i,d))!==a)break}catch(e){o=t,s=1,c=e}finally{l=1}}return{value:e,done:f}}}(n,r,o),!0),l}var a={};function s(){}function c(){}function l(){}e=Object.getPrototypeOf;var u=[][i]?e(e([][i]())):(gi(e={},i,function(){return this}),e),f=l.prototype=s.prototype=Object.create(u);function d(t){return Object.setPrototypeOf?Object.setPrototypeOf(t,l):(t.__proto__=l,gi(t,r,"GeneratorFunction")),t.prototype=Object.create(f),t}return c.prototype=l,gi(f,"constructor",l),gi(l,"constructor",c),c.displayName="GeneratorFunction",gi(l,r,"GeneratorFunction"),gi(f),gi(f,r,"Generator"),gi(f,i,function(){return this}),gi(f,"toString",function(){return"[object Generator]"}),(bi=function(){return{w:o,m:d}})()}function gi(t,e,n,i){var r=Object.defineProperty;try{r({},"",{})}catch(t){r=0}gi=function(t,e,n,i){function o(e,n){gi(t,e,function(t){return this._invoke(e,n,t)})}e?r?r(t,e,{value:n,enumerable:!i,configurable:!i,writable:!i}):t[e]=n:(o("next",0),o("throw",1),o("return",2))},gi(t,e,n,i)}function _i(t,e,n,i,r,o,a){try{var s=t[o](a),c=s.value}catch(t){return void n(t)}s.done?e(c):Promise.resolve(c).then(i,r)}function wi(t,e){return e||(e=t.slice(0)),Object.freeze(Object.defineProperties(t,{raw:{value:Object.freeze(e)}}))}function Oi(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);e&&(i=i.filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})),n.push.apply(n,i)}return n}function Si(t){for(var e=1;e\n \n ',"\n
\n "])),u?"main-icon-painted":"",(s=u)?"--multiple-entity-row-main-icon-color: ".concat(s,";"):"",Ce(i.name_gap),this._hass,c,this.renderSecondaryInfo(),l,!1,[this.config.column?"entities-column":"entities-row",!this.config.column&&this.config.wrap?"wrap":"",null!==(e=Ri[this.config.align])&&void 0!==e?e:"",l?"no-name":""].filter(Boolean).join(" "),this.config.show_state_first?W(ei||(ei=wi(["","",""])),this.renderMainEntity(),this.entities.map(function(t,e){return n.renderEntity(t.stateObj,t,e)})):W(ni||(ni=wi(["","",""])),this.entities.map(function(t,e){return n.renderEntity(t.stateObj,t,e)}),this.renderMainEntity()))}},{key:"updated",value:function(t){var n;null===(n=ki(e,"updated",this,3))||void 0===n||n([t]),this.syncRowStyles()}},{key:"syncRowStyles",value:function(){var t,e,n=Ce(null===(t=this.config)||void 0===t?void 0:t.name_gap);if(n||this._mainPainted){var i=null===(e=this.renderRoot)||void 0===e?void 0:e.querySelector("hui-generic-entity-row");i&&(n&&this.injectRowStyle(i,"data-mer-name-gap",":host .info{padding-inline-start:var(--multiple-entity-row-name-gap,16px)}"),i.classList.contains("main-icon-painted")&&this.injectRowStyle(i,"data-mer-main-icon",Mi))}}},{key:"injectRowStyle",value:(n=function(t){return function(){var e=this,n=arguments;return new Promise(function(i,r){var o=t.apply(e,n);function a(t){_i(o,i,r,a,s,"next",t)}function s(t){_i(o,i,r,a,s,"throw",t)}a(void 0)})}}(bi().m(function t(e,n,i){var r,o,a;return bi().w(function(t){for(;;)switch(t.p=t.n){case 0:if(null===(r=e.shadowRoot)||void 0===r||!r.querySelector("style[".concat(n,"]"))){t.n=1;break}return t.a(2);case 1:return t.p=1,t.n=2,e.updateComplete;case 2:t.n=4;break;case 3:return t.p=3,t.v,t.a(2);case 4:if(o=e.shadowRoot){t.n=5;break}return t.a(2);case 5:o.querySelector("style[".concat(n,"]"))||((a=document.createElement("style")).setAttribute(n,""),a.textContent=i,o.appendChild(a));case 6:return t.a(2)}},t,null,[[1,3]])})),function(t,e,i){return n.apply(this,arguments)})},{key:"renderSecondaryInfo",value:function(){var t=this.config.secondary_info;if(!t||function(t){return"string"==typeof t&&yt.includes(t)}(t))return null;if("string"==typeof t)return ne(t)?he(this._templateResults,t,this.config.entity,de(this.config))||" ":t;var e=this._resolved(t);if(Tt(this.info,e,this._hass))return null;var n=Te(this.info,e);return W(ii||(ii=wi([''," ",""])),Re(e),n,this.renderValue(this.info,e))}},{key:"renderMainEntity",value:function(){var t;if(!1===this.config.show_state)return null;var e=null!==(t=this._rowScope)&&void 0!==t?t:this._resolved(this.config);if(Tt(this.stateObj,e,this._hass))return this.config.default?W(ri||(ri=wi(['
\n ',"\n
","
\n
"])),Re(e),this.renderMainHeader(),this.config.default):null;var n=this.getGestureHandlers("main",this.config.entity,this.config);return W(oi||(oi=wi(['\n ',"\n
","
\n "])),Re(e),null==n?void 0:n.onDown,null==n?void 0:n.onUp,null==n?void 0:n.onCancel,Ti,Ti,Ti,Ti,Ti,Ti,this.renderMainHeader(),this.renderValue(this.stateObj,e))}},{key:"renderEntity",value:function(t,e,n){var i,r,o;if(e=this._resolved(e),!t||Tt(t,e,this._hass))return e.default?W(ai||(ai=wi(['
\n ',"\n
","
\n
"])),Re(e),null!==(r=Ii(t?Te(t,e):e.name))&&void 0!==r?r:this.headerPlaceholder(),e.default):t||e.hide_unavailable?null:W(si||(si=wi(['\n ','\n
\n '])),Re(e),this._hass.localize("ui.panel.lovelace.warning.entity_not_found","entity",null!==(o=e.entity)&&void 0!==o?o:""),Ii(e.name));var a=this.getGestureHandlers("sub-".concat(n),t.entity_id,e);return W(ci||(ci=wi(['\n ',"\n
\n ","\n
\n "])),Re(e),null==a?void 0:a.onDown,null==a?void 0:a.onUp,null==a?void 0:a.onCancel,Ti,Ti,Ti,Ti,Ti,Ti,null!==(i=Ii(Te(t,e)))&&void 0!==i?i:function(t){return!0===t.toggle||!!t.icon||kt(t.state_icon)}(e)?null:this.headerPlaceholder(),e.icon||kt(e.state_icon)?this.renderIcon(t,e):this.renderValue(t,e))}},{key:"renderMainHeader",value:function(){var t,e=null!==(t=Ii(this.config.state_header))&&void 0!==t?t:!0===this.config.toggle?null:this.headerPlaceholder();return e?W(li||(li=wi(["",""])),e):null}},{key:"headerPlaceholder",value:function(){return null!=Ii(this.config.state_header)||this.entities.some(function(t){return!1!==(e=t).name&&null!==Ii(e.name)&&!(!e.name&&!e.entity);var e})?" ":null}},{key:"renderValue",value:function(t,e){var n;if(!0===e.toggle)return this.renderToggle(t,e);if(void 0!==e.template){var i=ne(e.template)?"":e.template;return"".concat(i).concat(e.unit?" ".concat(e.unit):"")}if(!e.attribute&&null!==(n=t.entity_id)&&void 0!==n&&n.startsWith("timer."))return W(ui||(ui=wi([""])),this._hass,t);var r=e.attribute&&[ht,pt].includes(e.attribute);if(e.format&&mt.includes(e.format)){var o,a=r?t[e.attribute.replace("-","_")]:e.attribute?null!==(o=t.attributes[e.attribute])&&void 0!==o?o:t[e.attribute]:t.state,s=new Date(a);return s instanceof Date&&!isNaN(s.getTime())?W(fi||(fi=wi([""])),this._hass,s,e.format):a}return r?W(di||(di=wi([""])),this._hass,t[e.attribute.replace("-","_")]):Ie(this._hass,t,e)}},{key:"renderToggle",value:function(t,e){var n,i=this,r=null===(n=e.tap_action)||void 0===n?void 0:n.confirmation,o=r?{handleEvent:function(n){var o,a,s;n.stopPropagation(),n.preventDefault();var c=kt(r)&&(null===(o=r.exemptions)||void 0===o?void 0:o.some(function(t){var e;return t.user===(null===(e=i._hass.user)||void 0===e?void 0:e.id)})),l=kt(r)&&r.text,u=ne(l)?he(i._templateResults,l,null!==(a=e.entity)&&void 0!==a?a:i.config.entity,de(i.config,e)):l||"Are you sure you want to toggle ".concat(null!==(s=Te(t,e))&&void 0!==s?s:t.entity_id,"?");(c||confirm(u))&&i._hass.callService("homeassistant","toggle",{entity_id:t.entity_id})},capture:!0}:void 0;return W(hi||(hi=wi(["\n '])),Ti,Ti,Ti,o,t,this._hass)}},{key:"renderIcon",value:function(t,e){var n,i,r,o,a=null!==(n=Pe(t,e))&&void 0!==n?n:!0===e.icon?t.attributes.icon||null:e.icon,s=null!==(i=this._rowScope)&&void 0!==i?i:this._resolved(this.config),c="cssColor"in(o=Ft(e,s,t.state))?{color:o.cssColor}:{stateColor:o.stateColor},l=c.stateColor,u=c.color,f=!(a||!t.attributes.entity_picture&&!t.attributes.entity_picture_local);return W(pi||(pi=wi([''])),f?" has-picture":"",Ee(null!==(r=Ht(e,t.state))&&void 0!==r?r:e.icon_color),this._hass,t,a,l,u)}},{key:"renderWarning",value:function(){return W(mi||(mi=wi(["\n ","\n "])),this._hass.localize("ui.panel.lovelace.warning.entity_not_found","entity",this.config.entity))}},{key:"getGestureHandlers",value:function(t,e,n){var i,r,o,a,s,c,l,u=this;return this._actionHandlers.has(t)||this._actionHandlers.set(t,(i=function(t,i){return u.dispatchAction(e,n,t,i)},r={hasHold:!!n.hold_action,hasDoubleTap:!!n.double_tap_action},s=r.hasHold,c=r.hasDoubleTap,l=!1,{onDown:function(){l=!1,s&&(o=setTimeout(function(){l=!0},500))},onUp:function(){if(clearTimeout(o),l)return l=!1,void i(!0,!1);c?a?(clearTimeout(a),a=void 0,i(!1,!0)):a=setTimeout(function(){a=void 0,i(!1,!1)},250):i(!1,!1)},onCancel:function(){clearTimeout(o)}})),this._actionHandlers.get(t)}},{key:"dispatchAction",value:function(t,e,n,i){var r,o,a=i?e.double_tap_action:n?e.hold_action:null!==(r=e.tap_action)&&void 0!==r?r:{action:"more-info"};if(a&&"none"!==a.action){var s,c,l,u,f,d,h=(s=a,c=this._templateResults,l=null!==(o=e.entity)&&void 0!==o?o:this.config.entity,u=de(this.config,e),f=le(u),d=function(t){if(ne(t)){var e=c.get(se(f+t,l));return void 0===e?"":e}return Array.isArray(t)?t.map(d):kt(t)?Object.fromEntries(Object.entries(t).map(function(t){var e=Qt(t,2),n=e[0],i=e[1];return[n,d(i)]})):t},d(s)),p=i?"double_tap":n?"hold":"tap";Ct(this,"hass-action",{config:Ai({entity:h.entity||t},"".concat(p,"_action"),h),action:p})}}}],[{key:"getConfigElement",value:function(){return document.createElement("multiple-entity-row-editor")}},{key:"getStubConfig",value:function(t,e){var n,i,r=null!==(n=null!==(i=null==e?void 0:e.find(function(t){return t.startsWith("sensor.")}))&&void 0!==i?i:null==e?void 0:e[0])&&void 0!==n?n:"";return{entity:r}}},{key:"properties",get:function(){return{_hass:Object,config:Object,stateObj:Object,_templateResults:Object}}},{key:"styles",get:function(){return o(we||(we=function(t,e){return e||(e=t.slice(0)),Object.freeze(Object.defineProperties(t,{raw:{value:Object.freeze(e)}}))}(["\n /* state-badge is a fixed 40px box, which leaves an odd gap under a headered icon - let it\n shrink to the icon's natural size instead (see #425). */\n .icon-small {\n width: auto;\n height: auto;\n }\n /* ...except when it is showing a picture: state-badge then hides the icon and paints the\n image as a background, so the host has no in-flow content and would collapse to nothing.\n The class is set in renderIcon rather than reusing state-badge's own has-image. */\n .icon-small.has-picture {\n width: 40px;\n height: 40px;\n }\n .entity {\n text-align: center;\n cursor: pointer;\n }\n /* Marker for an entity id that resolves to nothing (see #364). */\n .entity .missing {\n color: var(--error-color, #db4437);\n }\n .entity span {\n font-size: 10px;\n color: var(--multiple-entity-row-header-color, var(--secondary-text-color));\n }\n .entities-row {\n flex-direction: row;\n display: inline-flex;\n justify-content: space-between;\n align-items: center;\n }\n /* HA's name box is what pushes the entities to the right: it grows at flex: 1 1 30%. Hiding\n it removes that push too, leaving them against the icon, so take over the job here - the\n point of hiding the name is more room, not a different alignment (see #341, #365). */\n .entities-row.no-name,\n .entities-column.no-name {\n margin-left: auto;\n }\n /* The 'styles' option reaches one entity's div, which is a flex item - so vertical-align\n there does nothing and alignment has to be set on the container instead (see #261). */\n .entities-row.align-top,\n .entities-column.align-top {\n align-items: flex-start;\n }\n .entities-row.align-bottom,\n .entities-column.align-bottom {\n align-items: flex-end;\n }\n /* The 16px gap must be margin, not padding: users tune spacing with their own margins in\n the 'styles' option, which replace this margin but would stack on top of a padding - 4.10.1 did\n padding and widened every tuned row into overflowing on phones (see #432). The gap still\n has to be clickable though: the row's cursor:pointer inherits into it, but HA stops\n slotted clicks at the bare slot (catchInteraction=false), so bare margin is dead space\n that looks clickable. The ::after extension puts the gap inside the entity's hit area\n without affecting layout. position:relative on every entity keeps hit-testing fair: a\n positioned later sibling beats its neighbor's ::after wherever a user's zero/negative\n margin makes them overlap, so no entity steals its neighbor's clicks. */\n .entities-row .entity {\n margin-right: 16px;\n position: relative;\n }\n .entities-row .entity:last-of-type {\n margin-right: 0;\n }\n .entities-row .entity:not(:last-of-type)::after {\n content: '';\n position: absolute;\n top: 0;\n bottom: 0;\n right: -16px;\n width: 16px;\n }\n /* HA's ha-entity-toggle host is display:flex with no horizontal alignment, so in a slot\n wider than the switch it hugs the left edge while everything else centers. Outer styles\n out-rank :host rules, so it can be centered from here; keeping the host's flex box (vs\n display:contents) preserves the full-width tap strip and HA's box assumptions (#436). */\n .entity ha-entity-toggle {\n justify-content: center;\n }\n /* Opt-in, because it trades a taller row for not overflowing: nothing between HA's .row and\n our entities can shrink, so a row needing more width than the card has just spills past\n the edge (worst on narrow phone screens - see #411). Wrapping reflows instead. */\n .entities-row.wrap {\n flex-wrap: wrap;\n justify-content: flex-end;\n row-gap: 4px;\n }\n .entities-column {\n flex-direction: column;\n display: flex;\n align-items: flex-end;\n justify-content: space-evenly;\n }\n .entities-column .entity div {\n display: inline-block;\n vertical-align: middle;\n }\n"])))}}]);var n}(ut);$t("multiple-entity-row",Hi),window.customCards=window.customCards||[],window.customCards.some(function(t){return"multiple-entity-row"===t.type})||window.customCards.push({type:"multiple-entity-row",name:"Multiple Entity Row",description:"Show multiple entity states and attributes on a single entity row"})})(); \ No newline at end of file +(()=>{"use strict";const t=globalThis,e=t.ShadowRoot&&(void 0===t.ShadyCSS||t.ShadyCSS.nativeShadow)&&"adoptedStyleSheets"in Document.prototype&&"replace"in CSSStyleSheet.prototype,n=Symbol(),i=new WeakMap;class r{constructor(t,e,i){if(this._$cssResult$=!0,i!==n)throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");this.cssText=t,this.t=e}get styleSheet(){let t=this.o;const n=this.t;if(e&&void 0===t){const e=void 0!==n&&1===n.length;e&&(t=i.get(n)),void 0===t&&((this.o=t=new CSSStyleSheet).replaceSync(this.cssText),e&&i.set(n,t))}return t}toString(){return this.cssText}}const o=(t,...e)=>{const i=1===t.length?t[0]:e.reduce((e,n,i)=>e+(t=>{if(!0===t._$cssResult$)return t.cssText;if("number"==typeof t)return t;throw Error("Value passed to 'css' function must be a 'css' function result: "+t+". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.")})(n)+t[i+1],t[0]);return new r(i,t,n)},a=(n,i)=>{if(e)n.adoptedStyleSheets=i.map(t=>t instanceof CSSStyleSheet?t:t.styleSheet);else for(const e of i){const i=document.createElement("style"),r=t.litNonce;void 0!==r&&i.setAttribute("nonce",r),i.textContent=e.cssText,n.appendChild(i)}},s=e?t=>t:t=>t instanceof CSSStyleSheet?(t=>{let e="";for(const n of t.cssRules)e+=n.cssText;return(t=>new r("string"==typeof t?t:t+"",void 0,n))(e)})(t):t,{is:c,defineProperty:l,getOwnPropertyDescriptor:u,getOwnPropertyNames:f,getOwnPropertySymbols:d,getPrototypeOf:h}=Object,p=globalThis,m=p.trustedTypes,y=m?m.emptyScript:"",v=p.reactiveElementPolyfillSupport,b=(t,e)=>t,g={toAttribute(t,e){switch(e){case Boolean:t=t?y:null;break;case Object:case Array:t=null==t?t:JSON.stringify(t)}return t},fromAttribute(t,e){let n=t;switch(e){case Boolean:n=null!==t;break;case Number:n=null===t?null:Number(t);break;case Object:case Array:try{n=JSON.parse(t)}catch(t){n=null}}return n}},_=(t,e)=>!c(t,e),w={attribute:!0,type:String,converter:g,reflect:!1,useDefault:!1,hasChanged:_};Symbol.metadata??=Symbol("metadata"),p.litPropertyMetadata??=new WeakMap;class O extends HTMLElement{static addInitializer(t){this._$Ei(),(this.l??=[]).push(t)}static get observedAttributes(){return this.finalize(),this._$Eh&&[...this._$Eh.keys()]}static createProperty(t,e=w){if(e.state&&(e.attribute=!1),this._$Ei(),this.prototype.hasOwnProperty(t)&&((e=Object.create(e)).wrapped=!0),this.elementProperties.set(t,e),!e.noAccessor){const n=Symbol(),i=this.getPropertyDescriptor(t,n,e);void 0!==i&&l(this.prototype,t,i)}}static getPropertyDescriptor(t,e,n){const{get:i,set:r}=u(this.prototype,t)??{get(){return this[e]},set(t){this[e]=t}};return{get:i,set(e){const o=i?.call(this);r?.call(this,e),this.requestUpdate(t,o,n)},configurable:!0,enumerable:!0}}static getPropertyOptions(t){return this.elementProperties.get(t)??w}static _$Ei(){if(this.hasOwnProperty(b("elementProperties")))return;const t=h(this);t.finalize(),void 0!==t.l&&(this.l=[...t.l]),this.elementProperties=new Map(t.elementProperties)}static finalize(){if(this.hasOwnProperty(b("finalized")))return;if(this.finalized=!0,this._$Ei(),this.hasOwnProperty(b("properties"))){const t=this.properties,e=[...f(t),...d(t)];for(const n of e)this.createProperty(n,t[n])}const t=this[Symbol.metadata];if(null!==t){const e=litPropertyMetadata.get(t);if(void 0!==e)for(const[t,n]of e)this.elementProperties.set(t,n)}this._$Eh=new Map;for(const[t,e]of this.elementProperties){const n=this._$Eu(t,e);void 0!==n&&this._$Eh.set(n,t)}this.elementStyles=this.finalizeStyles(this.styles)}static finalizeStyles(t){const e=[];if(Array.isArray(t)){const n=new Set(t.flat(1/0).reverse());for(const t of n)e.unshift(s(t))}else void 0!==t&&e.push(s(t));return e}static _$Eu(t,e){const n=e.attribute;return!1===n?void 0:"string"==typeof n?n:"string"==typeof t?t.toLowerCase():void 0}constructor(){super(),this._$Ep=void 0,this.isUpdatePending=!1,this.hasUpdated=!1,this._$Em=null,this._$Ev()}_$Ev(){this._$ES=new Promise(t=>this.enableUpdating=t),this._$AL=new Map,this._$E_(),this.requestUpdate(),this.constructor.l?.forEach(t=>t(this))}addController(t){(this._$EO??=new Set).add(t),void 0!==this.renderRoot&&this.isConnected&&t.hostConnected?.()}removeController(t){this._$EO?.delete(t)}_$E_(){const t=new Map,e=this.constructor.elementProperties;for(const n of e.keys())this.hasOwnProperty(n)&&(t.set(n,this[n]),delete this[n]);t.size>0&&(this._$Ep=t)}createRenderRoot(){const t=this.shadowRoot??this.attachShadow(this.constructor.shadowRootOptions);return a(t,this.constructor.elementStyles),t}connectedCallback(){this.renderRoot??=this.createRenderRoot(),this.enableUpdating(!0),this._$EO?.forEach(t=>t.hostConnected?.())}enableUpdating(t){}disconnectedCallback(){this._$EO?.forEach(t=>t.hostDisconnected?.())}attributeChangedCallback(t,e,n){this._$AK(t,n)}_$ET(t,e){const n=this.constructor.elementProperties.get(t),i=this.constructor._$Eu(t,n);if(void 0!==i&&!0===n.reflect){const r=(void 0!==n.converter?.toAttribute?n.converter:g).toAttribute(e,n.type);this._$Em=t,null==r?this.removeAttribute(i):this.setAttribute(i,r),this._$Em=null}}_$AK(t,e){const n=this.constructor,i=n._$Eh.get(t);if(void 0!==i&&this._$Em!==i){const t=n.getPropertyOptions(i),r="function"==typeof t.converter?{fromAttribute:t.converter}:void 0!==t.converter?.fromAttribute?t.converter:g;this._$Em=i;const o=r.fromAttribute(e,t.type);this[i]=o??this._$Ej?.get(i)??o,this._$Em=null}}requestUpdate(t,e,n,i=!1,r){if(void 0!==t){const o=this.constructor;if(!1===i&&(r=this[t]),n??=o.getPropertyOptions(t),!((n.hasChanged??_)(r,e)||n.useDefault&&n.reflect&&r===this._$Ej?.get(t)&&!this.hasAttribute(o._$Eu(t,n))))return;this.C(t,e,n)}!1===this.isUpdatePending&&(this._$ES=this._$EP())}C(t,e,{useDefault:n,reflect:i,wrapped:r},o){n&&!(this._$Ej??=new Map).has(t)&&(this._$Ej.set(t,o??e??this[t]),!0!==r||void 0!==o)||(this._$AL.has(t)||(this.hasUpdated||n||(e=void 0),this._$AL.set(t,e)),!0===i&&this._$Em!==t&&(this._$Eq??=new Set).add(t))}async _$EP(){this.isUpdatePending=!0;try{await this._$ES}catch(t){Promise.reject(t)}const t=this.scheduleUpdate();return null!=t&&await t,!this.isUpdatePending}scheduleUpdate(){return this.performUpdate()}performUpdate(){if(!this.isUpdatePending)return;if(!this.hasUpdated){if(this.renderRoot??=this.createRenderRoot(),this._$Ep){for(const[t,e]of this._$Ep)this[t]=e;this._$Ep=void 0}const t=this.constructor.elementProperties;if(t.size>0)for(const[e,n]of t){const{wrapped:t}=n,i=this[e];!0!==t||this._$AL.has(e)||void 0===i||this.C(e,void 0,n,i)}}let t=!1;const e=this._$AL;try{t=this.shouldUpdate(e),t?(this.willUpdate(e),this._$EO?.forEach(t=>t.hostUpdate?.()),this.update(e)):this._$EM()}catch(e){throw t=!1,this._$EM(),e}t&&this._$AE(e)}willUpdate(t){}_$AE(t){this._$EO?.forEach(t=>t.hostUpdated?.()),this.hasUpdated||(this.hasUpdated=!0,this.firstUpdated(t)),this.updated(t)}_$EM(){this._$AL=new Map,this.isUpdatePending=!1}get updateComplete(){return this.getUpdateComplete()}getUpdateComplete(){return this._$ES}shouldUpdate(t){return!0}update(t){this._$Eq&&=this._$Eq.forEach(t=>this._$ET(t,this[t])),this._$EM()}updated(t){}firstUpdated(t){}}O.elementStyles=[],O.shadowRootOptions={mode:"open"},O[b("elementProperties")]=new Map,O[b("finalized")]=new Map,v?.({ReactiveElement:O}),(p.reactiveElementVersions??=[]).push("2.1.2");const A=globalThis,S=t=>t,j=A.trustedTypes,$=j?j.createPolicy("lit-html",{createHTML:t=>t}):void 0,x="$lit$",k=`lit$${Math.random().toFixed(9).slice(2)}$`,E="?"+k,C=`<${E}>`,P=document,T=()=>P.createComment(""),M=t=>null===t||"object"!=typeof t&&"function"!=typeof t,I=Array.isArray,R=t=>I(t)||"function"==typeof t?.[Symbol.iterator],H="[ \t\n\f\r]",D=/<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g,F=/-->/g,N=/>/g,L=RegExp(`>|${H}(?:([^\\s"'>=/]+)(${H}*=${H}*(?:[^ \t\n\f\r"'\`<>=]|("|')|))|$)`,"g"),U=/'/g,V=/"/g,z=/^(?:script|style|textarea|title)$/i,B=t=>(e,...n)=>({_$litType$:t,strings:e,values:n}),W=B(1),q=(B(2),B(3),Symbol.for("lit-noChange")),Z=Symbol.for("lit-nothing"),G=new WeakMap,J=P.createTreeWalker(P,129);function K(t,e){if(!I(t)||!t.hasOwnProperty("raw"))throw Error("invalid template strings array");return void 0!==$?$.createHTML(e):e}const Y=(t,e)=>{const n=t.length-1,i=[];let r,o=2===e?"":3===e?"":"",a=D;for(let e=0;e"===c[0]?(a=r??D,l=-1):void 0===c[1]?l=-2:(l=a.lastIndex-c[2].length,s=c[1],a=void 0===c[3]?L:'"'===c[3]?V:U):a===V||a===U?a=L:a===F||a===N?a=D:(a=L,r=void 0);const f=a===L&&t[e+1].startsWith("/>")?" ":"";o+=a===D?n+C:l>=0?(i.push(s),n.slice(0,l)+x+n.slice(l)+k+f):n+k+(-2===l?e:f)}return[K(t,o+(t[n]||"")+(2===e?"":3===e?"":"")),i]};class Q{constructor({strings:t,_$litType$:e},n){let i;this.parts=[];let r=0,o=0;const a=t.length-1,s=this.parts,[c,l]=Y(t,e);if(this.el=Q.createElement(c,n),J.currentNode=this.el.content,2===e||3===e){const t=this.el.content.firstChild;t.replaceWith(...t.childNodes)}for(;null!==(i=J.nextNode())&&s.length0){i.textContent=j?j.emptyScript:"";for(let n=0;n2||""!==n[0]||""!==n[1]?(this._$AH=Array(n.length-1).fill(new String),this.strings=n):this._$AH=Z}_$AI(t,e=this,n,i){const r=this.strings;let o=!1;if(void 0===r)t=X(this,t,e,0),o=!M(t)||t!==this._$AH&&t!==q,o&&(this._$AH=t);else{const i=t;let a,s;for(t=r[0],a=0;a{const i=n?.renderBefore??e;let r=i._$litPart$;if(void 0===r){const t=n?.renderBefore??null;i._$litPart$=r=new et(e.insertBefore(T(),t),t,void 0,n??{})}return r._$AI(t),r})(e,this.renderRoot,this.renderOptions)}connectedCallback(){super.connectedCallback(),this._$Do?.setConnected(!0)}disconnectedCallback(){super.disconnectedCallback(),this._$Do?.setConnected(!1)}render(){return q}}ut._$litElement$=!0,ut.finalized=!0,lt.litElementHydrateSupport?.({LitElement:ut});const ft=lt.litElementPolyfillSupport;ft?.({LitElement:ut}),(lt.litElementVersions??=[]).push("4.2.2");var dt=["unavailable","unknown"],ht="last-changed",pt="last-updated",mt=["relative","total","date","time","datetime"],yt=["entity-id","last-changed","last-updated","last-triggered","position","tilt-position","brightness"];function vt(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var n=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=n){var i,r,o,a,s=[],c=!0,l=!1;try{if(o=(n=n.call(t)).next,0===e){if(Object(n)!==n)return;c=!1}else for(;!(c=(i=o.call(n)).done)&&(s.push(i.value),s.length!==e);c=!0);}catch(t){l=!0,r=t}finally{try{if(!c&&null!=n.return&&(a=n.return(),Object(a)!==a))return}finally{if(l)throw r}}return s}}(t,e)||bt(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function bt(t,e){if(t){if("string"==typeof t)return gt(t,e);var n={}.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?gt(t,e):void 0}}function gt(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,i=Array(e);n=t.length?{done:!0}:{done:!1,value:t[n++]}},e:function(t){throw t},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var r,o=!0,a=!1;return{s:function(){e=e.call(t)},n:function(){var t=e.next();return o=t.done,t},e:function(t){a=!0,r=t},f:function(){try{o||null==e.return||e.return()}finally{if(a)throw r}}}}(wt);try{for(i.s();!(e=i.n()).done;){var r=vt(e.value,2),o=r[0],a=r[1];if(customElements.get(o))wt.delete(o);else try{customElements.define(o,a),n.push(o),wt.delete(o)}catch(t){console.warn("multiple-entity-row: re-defining ".concat(o," after registry swap failed"),t)}}}catch(t){i.e(t)}finally{i.f()}n.length&&console.info("multiple-entity-row: re-defined ".concat(n.join(", ")," after customElements registry swap, caught by ").concat(t," (frontend#52960)"))}catch(t){console.warn("multiple-entity-row: customElements registry check failed",t)}},jt=function(){wt.size&&(Ot>=30?wt.clear():(Ot+=1,setTimeout(function(){St("fallback poll"),jt()},1e3)))},$t=function(t,e){try{if(_t.get(t))return void console.warn("multiple-entity-row: ".concat(t," is already defined - a duplicate resource entry or stale cached copy loaded first"));_t.define(t,e)}catch(e){return void console.warn("multiple-entity-row: defining ".concat(t," failed"),e)}wt.set(t,e),At||(At=!0,_t.whenDefined("home-assistant").then(function(){return St("ha-boot signal")}).catch(function(){}),jt())};function xt(t){return xt="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},xt(t)}var kt=function(t){return"object"===xt(t)&&!Array.isArray(t)&&!!t},Et=function(t,e){if(kt(t)&&void 0!==e&&Object.prototype.hasOwnProperty.call(t,e)){var n=t[e];return null==n||""===n?void 0:n}},Ct=function(t,e,n){var i=new Event(e,{bubbles:!0,composed:!0});i.detail=n,t.dispatchEvent(i)},Pt=function(t){return!t||dt.includes(t.state)},Tt=function(t,e,n){if(function(t,e){return e.hide_unavailable&&(Pt(t)||e.attribute&&![ht,pt].includes(e.attribute)&&void 0===t.attributes[e.attribute])}(t,e))return!0;if(void 0===e.hide_if)return!1;if("boolean"==typeof e.hide_if)return e.hide_if;var i;if(kt(e.hide_if)&&(e.hide_if.entity||e.hide_if.attribute)){var r=e.hide_if.entity?null==n?void 0:n.states[e.hide_if.entity]:t;i=e.hide_if.attribute?null==r?void 0:r.attributes[e.hide_if.attribute]:null==r?void 0:r.state}else i=e.attribute?t.attributes[e.attribute]:t.state;var o=[];if(kt(e.hide_if)){if(e.hide_if.below&&ie.hide_if.above)return!0;e.hide_if.value&&(o=o.concat(e.hide_if.value))}else o=o.concat(e.hide_if);return o.some(function(t){return"number"==typeof t?t===+i:t===i})},Mt=function(t){return"string"==typeof t&&yt.includes(t)},It=["formatEntityName","formatEntityState","formatEntityAttributeValue","entities","devices","areas","floors"],Rt=new Set(["primary","accent","red","pink","purple","deep-purple","indigo","blue","light-blue","cyan","teal","green","light-green","lime","yellow","amber","orange","deep-orange","brown","light-grey","grey","dark-grey","blue-grey","black","white","primary-text","secondary-text","disabled"]),Ht=function(t){return Rt.has(t)?"var(--".concat(t,"-color)"):t},Dt=function(t,e){var n=Et(t.state_color,e);return void 0===n?void 0:Ht(String(n))},Ft=function(t){var e;return null!==(e=t.color)&&void 0!==e?e:"boolean"==typeof t.state_color?t.state_color?"state":"none":void 0},Nt=function(t,e,n){var i;if(void 0!==Dt(t,n))return{stateColor:!1};var r=null!==(i=Ft(t))&&void 0!==i?i:t.icon_color||!e?void 0:Ft(e);return void 0===r?t.icon_color?{stateColor:!1}:{stateColor:!0}:"state"===r?{stateColor:!0}:"none"===r?{stateColor:!1}:{cssColor:Ht(r)}},Lt=function(t){return t<10?"0".concat(t):t};function Ut(t){var e=Math.floor(t/3600),n=Math.floor(t%3600/60),i=Math.floor(t%3600%60);return e>0?"".concat(e,":").concat(Lt(n),":").concat(Lt(i)):n>0?"".concat(n,":").concat(Lt(i)):i>0?""+i:null}function Vt(t){return Vt="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},Vt(t)}function zt(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);e&&(i=i.filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})),n.push.apply(n,i)}return n}function Bt(t,e,n){return(e=function(t){var e=function(t){if("object"!=Vt(t)||!t)return t;var e=t[Symbol.toPrimitive];if(void 0!==e){var n=e.call(t,"string");if("object"!=Vt(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(t)}(t);return"symbol"==Vt(e)?e:e+""}(e))in t?Object.defineProperty(t,e,{value:n,enumerable:!0,configurable:!0,writable:!0}):t[e]=n,t}var Wt=function(t,e,n){var i=e?function(t){switch(t.number_format){case"comma_decimal":return["en-US","en"];case"decimal_comma":return["de","es","it"];case"space_comma":return["fr","sv","cs"];case"system":return;default:return t.language}}(e):void 0;if(Number.isNaN=Number.isNaN||function t(e){return"number"==typeof e&&t(e)},"none"!==(null==e?void 0:e.number_format)&&!Number.isNaN(Number(t))&&Intl)try{return new Intl.NumberFormat(i,qt(t,n)).format(Number(t))}catch(e){return console.error(e),new Intl.NumberFormat(void 0,qt(t,n)).format(Number(t))}return"string"==typeof t?t:"".concat(function(t){var e=arguments.length>1&&void 0!==arguments[1]?arguments[1]:2;return Math.round(t*Math.pow(10,e))/Math.pow(10,e)}(t,null==n?void 0:n.maximumFractionDigits).toString()).concat("currency"===(null==n?void 0:n.style)?" ".concat(n.currency):"")},qt=function(t,e){var n=function(t){for(var e=1;e-1?t.split(".")[1].length:0;n.minimumFractionDigits=i,n.maximumFractionDigits=i}return n};function Zt(t,e){var n="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(!n){if(Array.isArray(t)||(n=te(t))||e&&t&&"number"==typeof t.length){n&&(t=n);var i=0,r=function(){};return{s:r,n:function(){return i>=t.length?{done:!0}:{done:!1,value:t[i++]}},e:function(t){throw t},f:r}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o,a=!0,s=!1;return{s:function(){n=n.call(t)},n:function(){var t=n.next();return a=t.done,t},e:function(t){s=!0,o=t},f:function(){try{a||null==n.return||n.return()}finally{if(s)throw o}}}}function Gt(t,e){for(var n=0;nt.length)&&(e=t.length);for(var n=0,i=Array(e);n2&&void 0!==arguments[2]?arguments[2]:"";ie(t)&&n.push({template:i+t,entity:e})},r=function(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"";i(t.name,e,n),i(t.icon,e,n),i(t.icon_color,e,n),i(t.color,e,n),i(t.template,e,n),i(ae(t),e,n),kt(t.styles)&&he(t.styles,function(t){return i(t,e,n)}),de.forEach(function(r){return he(t[r],function(t){return i(t,e,n)})})},o=t.entity;if(r(t,o,fe(pe(t))),"string"==typeof t.secondary_info)i(t.secondary_info,o,fe(pe(t)));else if(kt(t.secondary_info)){var a,s=t.secondary_info;r(s,null!==(a=s.entity)&&void 0!==a?a:o,fe(pe(t,s)))}return null===(e=t.entities)||void 0===e||e.forEach(function(e){if(kt(e)){var n,i=e;r(i,null!==(n=i.entity)&&void 0!==n?n:o,fe(pe(t,i)))}}),n}(t).map(function(t){return[le(t.template,t.entity),t]})),this.sync()}},{key:"setHass",value:function(t){var e,n=!(null===(e=this.hass)||void 0===e||!e.connection);this.hass=t,!n&&null!=t&&t.connection&&this.sync()}},{key:"connect",value:function(){this.connected=!0,this.sync()}},{key:"disconnect",value:function(){this.connected=!1,this.sync()}},{key:"sync",value:function(){var t,e,n=Zt(this.unsubs);try{for(n.s();!(e=n.n()).done;){var i=Xt(e.value,2),r=i[0],o=i[1];this.connected&&this.requests.has(r)||(this.unsubs.delete(r),this.requests.has(r)||(this.results.delete(r),this.errors.delete(r)),o.then(function(t){return null==t?void 0:t()}).catch(function(){}))}}catch(t){n.e(t)}finally{n.f()}if(this.connected&&null!==(t=this.hass)&&void 0!==t&&t.connection){var a,s=Zt(this.requests);try{for(s.s();!(a=s.n()).done;){var c=Xt(a.value,2),l=c[0],u=c[1];this.unsubs.has(l)||this.unsubs.set(l,this.subscribe(l,u))}}catch(t){s.e(t)}finally{s.f()}}}},{key:"subscribe",value:function(t,e){var n=this;return this.hass.connection.subscribeMessage(function(e){return n.onMessage(t,e)},{type:"render_template",template:e.template,variables:{entity:e.entity},report_errors:!0}).catch(function(t){return console.warn("multiple-entity-row: template subscription failed:",e.template,t),null})}},{key:"onMessage",value:function(t,e){this.unsubs.has(t)&&(void 0!==e.error?(this.errors.get(t)!==e.error&&(this.errors.set(t,e.error),console.warn("multiple-entity-row: template error:",e.error)),this.results.set(t,"")):(this.errors.delete(t),this.results.set(t,e.result)),this.notify(new Map(this.results)))}}])}();function ve(t){return ve="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t},ve(t)}function be(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);e&&(i=i.filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})),n.push.apply(n,i)}return n}function ge(t){for(var e=1;et.length)&&(e=t.length);for(var n=0,i=Array(e);n2026||2026===Number(n)&&Number(i)>=4}(t)?t.formatEntityName(e,n.name||void 0)||$e(e.entity_id)||null:e.attributes.friendly_name||$e(e.entity_id)||null:n.name||null},De=function(t){return"string"==typeof t?t.replace(/(\d)%/,"$1​%"):t},Fe=function(t,e,n){if(Pt(e))return t.formatEntityState(e);var i,r=n.attribute?e.attributes[n.attribute]:e.state,o=!1===n.unit?void 0:void 0!==n.attribute?n.unit:n.unit||e.attributes.unit_of_measurement,a="string"==typeof(i=n.format)?i.split(",").map(function(t){return t.trim()}).filter(Boolean):[];if(a.length>1&&a.every(function(t){return Pe.test(t)})){var s=r??0;return!isNaN(parseFloat(s))&&isFinite(s)?function(t,e,n,i){var r,o,a=parseFloat(e),s=xe(e),c=!1,l=function(t){c||(s=void 0,r=t)},u=function(t){var e="undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(!e){if(Array.isArray(t)||(e=Oe(t))){e&&(t=e);var n=0,i=function(){};return{s:i,n:function(){return n>=t.length?{done:!0}:{done:!1,value:t[n++]}},e:function(t){throw t},f:i}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var r,o=!0,a=!1;return{s:function(){e=e.call(t)},n:function(){var t=e.next();return o=t.done,t},e:function(t){a=!0,r=t},f:function(){try{o||null==e.return||e.return()}finally{if(a)throw r}}}}(t);try{for(u.s();!(o=u.n()).done;){var f=o.value,d=Ee.exec(f);if(d&&"precision"===d[1])s=parseInt(d[2],10),r=void 0,c=!0;else if(d)a/={kilo:1e3,mega:1e6,milli:.001}[d[1]],void 0!==d[2]?(s=parseInt(d[2],10),r=void 0,c=!0):l(2);else switch(f){case"brightness":a=Math.round(a/255*100),n="%",l(0);break;case"percent":a*=100,n="%",l(2);break;case"invert":a=-a;break;case"position":a=100-a;break;case"celsius_to_fahrenheit":a=1.8*a+32,l(0);break;case"fahrenheit_to_celsius":a=5*(a-32)/9,l(1)}}}catch(t){u.e(t)}finally{u.f()}return"".concat(Wt(a,i,void 0!==s?{minimumFractionDigits:s,maximumFractionDigits:s}:void 0!==r?{maximumFractionDigits:r}:void 0)).concat(n?" ".concat(n):"")}(a,s,o,t.locale):"".concat(s).concat(o?" ".concat(o):"")}if(n.format&&!function(t){return ke.some(function(e){return null==t?void 0:t.startsWith(e)})&&!Ce(t)}(n.format)){if(null==r&&(r=Te.includes(n.format)?"":0),Te.includes(n.format))return"".concat(function(t,e){switch(t){case"upper":return e.toUpperCase();case"lower":return e.toLowerCase();case"capitalize":return e.charAt(0).toUpperCase()+e.slice(1);case"title":return e.split(/(\s+)/).map(function(t){return t.charAt(0).toUpperCase()+t.slice(1)}).join("")}}(n.format,String(r))).concat(o?" ".concat(o):"");if(isNaN(parseFloat(r))||!isFinite(r));else if("brightness"===n.format)r=Math.round(r/255*100),o="%";else if("percent"===n.format)r=Wt(100*r,t.locale,{maximumFractionDigits:2}),o="%";else if("duration"===n.format){var c;r=null!==(c=Ut(r))&&void 0!==c?c:"0",o=void 0}else if("duration-m"===n.format){var l;r=null!==(l=Ut(r/1e3))&&void 0!==l?l:"0",o=void 0}else if("duration-h"===n.format){var u;r=null!==(u=Ut(3600*r))&&void 0!==u?u:"0",o=void 0}else if(Ce(n.format)){var f=we(Ce(n.format),3),d=f[1],h=f[2];if("precision"===d){var p=parseInt(h,10);r=Wt(parseFloat(r),t.locale,{minimumFractionDigits:p,maximumFractionDigits:p})}else r=function(t,e,n,i){if(void 0===n)return Wt(t/e,i,{maximumFractionDigits:2});var r=parseInt(n,10);return Wt(t/e,i,{minimumFractionDigits:r,maximumFractionDigits:r})}(r,{kilo:1e3,mega:1e6,milli:.001}[d],h,t.locale)}else if("invert"===n.format){var m=xe(r);r=Wt(r-2*r,t.locale,void 0!==m?{minimumFractionDigits:m,maximumFractionDigits:m}:void 0)}else if("position"===n.format){var y=xe(r);r=Wt(100-r,t.locale,void 0!==y?{minimumFractionDigits:y,maximumFractionDigits:y}:void 0)}else"celsius_to_fahrenheit"===n.format?r=Wt(1.8*r+32,t.locale,{maximumFractionDigits:0}):"fahrenheit_to_celsius"===n.format&&(r=Wt(5*(r-32)/9,t.locale,{maximumFractionDigits:1}));return"".concat(r).concat(o?" ".concat(o):"")}var v=ge(ge({},e),{},{attributes:ge(ge({},e.attributes),{},{unit_of_measurement:o})});if(void 0!==n.unit&&!n.attribute){if(!isNaN(parseFloat(r))&&isFinite(r)){var b,g=null===(b=t.entities)||void 0===b||null===(b=b[e.entity_id])||void 0===b?void 0:b.display_precision,_=Wt(r,t.locale,null!=g?{minimumFractionDigits:g,maximumFractionDigits:g}:void 0);return"".concat(_).concat(o?" ".concat(o):"")}return"".concat(t.formatEntityState(e)).concat(o?" ".concat(o):"")}if(n.attribute){if(void 0!==n.unit){var w=null==r?"":isNaN(r)?r:Wt(r,t.locale);return"".concat(w).concat(o?" ".concat(o):"")}return De(t.formatEntityAttributeValue(v,n.attribute))}return De(t.formatEntityState(v))},Ne=function(t){return kt(null==t?void 0:t.styles)?Object.keys(t.styles).filter(function(e){return""!==t.styles[e]&&null!=t.styles[e]}).map(function(e){return"".concat(e,": ").concat(t.styles[e],";")}).join(""):""};class Le{constructor(t){}get _$AU(){return this._$AM._$AU}_$AT(t,e,n){this._$Ct=t,this._$AM=e,this._$Ci=n}_$AS(t,e){return this.update(t,e)}update(t,e){return this.render(...e)}}const{I:Ue}=st,Ve={},ze=(t=>(...e)=>({_$litDirective$:t,values:e}))(class extends Le{constructor(){super(...arguments),this.key=Z}render(t,e){return this.key=t,e}update(t,[e,n]){return e!==this.key&&(((t,e=Ve)=>{t._$AH=e})(t),this.key=e),n}});var Be,We,qe,Ze,Ge,Je,Ke,Ye,Qe,Xe,tn,en,nn,rn,on,an,sn,cn="__custom__",ln=[{value:"",label:"No format"},{value:"brightness",label:"Brightness (0-255 → %)"},{value:"percent",label:"Percent (value × 100 → x %)"},{value:"duration",label:"Duration (seconds → h:mm:ss)"},{value:"duration-m",label:"Duration (milliseconds)"},{value:"duration-h",label:"Duration (hours)"},{value:"precision0",label:"Precision 0 decimals"},{value:"precision1",label:"Precision 1 decimal"},{value:"precision2",label:"Precision 2 decimals"},{value:"precision3",label:"Precision 3 decimals"},{value:"kilo",label:"Kilo (value / 1,000)"},{value:"mega",label:"Mega (value / 1,000,000)"},{value:"milli",label:"Milli (value × 1,000)"},{value:"invert",label:"Invert (value × -1)"},{value:"position",label:"Position (100 - value)"},{value:"celsius_to_fahrenheit",label:"°C → °F"},{value:"fahrenheit_to_celsius",label:"°F → °C"},{value:"upper",label:"Text: UPPERCASE"},{value:"lower",label:"Text: lowercase"},{value:"capitalize",label:"Text: Capitalize first letter"},{value:"title",label:"Text: Title Case"},{value:"relative",label:"Timestamp: relative"},{value:"total",label:"Timestamp: total"},{value:"date",label:"Timestamp: date"},{value:"time",label:"Timestamp: time"},{value:"datetime",label:"Timestamp: date + time"},{value:cn,label:"Custom…"}],un=new Set(ln.map(function(t){return t.value}).filter(function(t){return t&&t!==cn})),fn=[{name:"entity",required:!0,selector:{entity:{}}},{type:"grid",schema:[{name:"name",selector:{text:{}}},{name:"attribute",selector:{text:{}}}]},{type:"grid",schema:[{name:"unit",selector:{text:{}}},{name:"icon",selector:{icon:{}}}]},{name:"icon_color",selector:{text:{}}},{name:"name_gap",selector:{text:{}}},{type:"grid",schema:[{name:"show_state",default:!0,selector:{boolean:{}}},{name:"color",selector:{ui_color:{include_state:!0,include_none:!0}}}]},{type:"grid",schema:[{name:"toggle",selector:{boolean:{}}},{name:"column",selector:{boolean:{}}}]},{type:"grid",schema:[{name:"show_state_first",selector:{boolean:{}}},{name:"hide_unavailable",selector:{boolean:{}}},{name:"wrap",selector:{boolean:{}}}]},{name:"state_header",selector:{text:{}}},{name:"image",selector:{text:{}}},{name:"format",selector:{select:{mode:"dropdown",options:ln}}}],dn=[{name:"tap_action",selector:{ui_action:{default_action:"more-info"}}},{name:"hold_action",selector:{ui_action:{default_action:"none"}}},{name:"double_tap_action",selector:{ui_action:{default_action:"none"}}}],hn=[{name:"entity",selector:{entity:{}}},{type:"grid",schema:[{name:"name",selector:{text:{}}},{name:"attribute",selector:{text:{}}}]},{type:"grid",schema:[{name:"unit",selector:{text:{}}},{name:"icon",selector:{icon:{}}}]},{name:"icon_color",selector:{text:{}}},{type:"grid",schema:[{name:"color",selector:{ui_color:{include_state:!0,include_none:!0}}},{name:"toggle",selector:{boolean:{}}}]},{name:"hide_unavailable",selector:{boolean:{}}},{name:"format",selector:{select:{mode:"dropdown",options:ln}}}],pn={entity:"Entity",attribute:"Attribute",name:"Name override (or false to hide)",unit:"Unit (or false to hide)",icon:"Icon",icon_color:"Icon color (CSS value, e.g. red, #ff0000, var(--my-color))",name_gap:"Icon → name gap (CSS length, e.g. 8px; default 16px)",image:"Image URL",format:"Format",show_state:"Show main entity state",show_state_first:"State before entities",state_header:"State header label",color:"Color",state_color:"State color",column:"Column layout",wrap:"Wrap instead of overflowing",toggle:"Show as toggle",hide_unavailable:"Hide if unavailable",tap_action:"Tap action",hold_action:"Hold action",double_tap_action:"Double-tap action"};function mn(t,e){return e||(e=t.slice(0)),Object.freeze(Object.defineProperties(t,{raw:{value:Object.freeze(e)}}))}function yn(t){return function(t){if(Array.isArray(t))return kn(t)}(t)||function(t){if("undefined"!=typeof Symbol&&null!=t[Symbol.iterator]||null!=t["@@iterator"])return Array.from(t)}(t)||xn(t)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function vn(t,e){for(var n=0;n=t.length?{done:!0}:{done:!1,value:t[i++]}},e:function(t){throw t},f:r}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var o,a=!0,s=!1;return{s:function(){n=n.call(t)},n:function(){var t=n.next();return a=t.done,t},e:function(t){s=!0,o=t},f:function(){try{a||null==n.return||n.return()}finally{if(s)throw o}}}}function $n(t,e){return function(t){if(Array.isArray(t))return t}(t)||function(t,e){var n=null==t?null:"undefined"!=typeof Symbol&&t[Symbol.iterator]||t["@@iterator"];if(null!=n){var i,r,o,a,s=[],c=!0,l=!1;try{if(o=(n=n.call(t)).next,0===e){if(Object(n)!==n)return;c=!1}else for(;!(c=(i=o.call(n)).done)&&(s.push(i.value),s.length!==e);c=!0);}catch(t){l=!0,r=t}finally{try{if(!c&&null!=n.return&&(a=n.return(),Object(a)!==a))return}finally{if(l)throw r}}return s}}(t,e)||xn(t,e)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function xn(t,e){if(t){if("string"==typeof t)return kn(t,e);var n={}.toString.call(t).slice(8,-1);return"Object"===n&&t.constructor&&(n=t.constructor.name),"Map"===n||"Set"===n?Array.from(t):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?kn(t,e):void 0}}function kn(t,e){(null==e||e>t.length)&&(e=t.length);for(var n=0,i=Array(e);ni.length&&(t._selectedTab=i.length),t._keys.clear(),t._updateConfig({entities:i.length?i:void 0})}}),An(t,"_moveAdditional",function(e,n){var i;if(t._config){var r=yn(null!==(i=t._config.entities)&&void 0!==i?i:[]),o=e+n;if(!(o<0||o>=r.length)){var a=[r[o],r[e]];r[e]=a[0],r[o]=a[1],t._selectedTab=o+1,t._keys.clear(),t._updateConfig({entities:r})}}}),An(t,"_copyAdditional",function(e){var n,i=null===(n=t._config)||void 0===n||null===(n=n.entities)||void 0===n?void 0:n[e];null!=i&&t._writeClipboard("string"==typeof i?{entity:i}:On({},i))}),An(t,"_cutAdditional",function(e){t._copyAdditional(e),t._deleteAdditional(e)}),An(t,"_copyMainAsTemplate",function(){if(t._config){var e,n={},i=jn(zn);try{for(i.s();!(e=i.n()).done;){var r=e.value,o=t._config[r];void 0!==o&&(n[r]=o)}}catch(t){i.e(t)}finally{i.f()}t._writeClipboard(n)}}),An(t,"_pasteEntity",function(){var e;if(t._config){var n=t._readClipboard();if(n){var i=[].concat(yn(null!==(e=t._config.entities)&&void 0!==e?e:[]),[n]);t._selectedTab=i.length,t._keys.clear(),t._updateConfig({entities:i})}}}),An(t,"_secondaryModeChanged",function(e){if(t._config){var n=e.detail.value.mode;if(n!==t._secondaryInfoMode()){var i;switch(n){case"none":i=void 0;break;case"text":i="";break;case"generic":i="last-changed";break;case"entity":i={entity:t._config.entity}}t._updateConfig({secondary_info:i})}}}),An(t,"_secondaryTextChanged",function(e){t._updateConfig({secondary_info:e.detail.value.text})}),An(t,"_secondaryTokenChanged",function(e){t._updateConfig({secondary_info:e.detail.value.token})}),An(t,"_secondaryEntityChanged",function(e){var n,i=kt(null===(n=t._config)||void 0===n?void 0:n.secondary_info)?t._config.secondary_info.format:void 0;t._updateConfig({secondary_info:t._formatFromForm("secondary",Un(e.detail.value),i)})}),t._selectedTab=0,t._entitiesExpanded=!0,t._stateIconRowsMain=[],t._stateIconRowsAdditional=new Map,t._customFormatScopes=new Set,t}return function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),Object.defineProperty(t,"prototype",{writable:!1}),e&&_n(t,e)}(e,t),function(t,e,n){return e&&vn(t.prototype,e),n&&vn(t,n),Object.defineProperty(t,"prototype",{writable:!1}),t}(e,[{key:"setConfig",value:function(t){var e,n,i,r=this;if(oe(t))throw new Error("This row uses templates - edit it in the code (YAML) editor.");if(function(t){return re(t.name)||kt(t.secondary_info)&&re(t.secondary_info.name)||Array.isArray(t.entities)&&t.entities.some(function(t){return kt(t)&&re(t.name)})}(t))throw new Error("This row uses a composed name - edit it in the code (YAML) editor.");this._config=t;var o,a=null!==(e=null===(n=t.entities)||void 0===n?void 0:n.length)&&void 0!==e?e:0;this._selectedTab>a&&(this._selectedTab=a),this._clipboardEntity=this._readClipboard(),this._stateIconRowsMatch(this._stateIconRowsMain,t.state_icon)||(this._stateIconRowsMain=Object.entries(null!==(o=t.state_icon)&&void 0!==o?o:{}));var s=new Map;null===(i=t.entities)||void 0===i||i.forEach(function(t,e){var n=kt(t)?t.state_icon:void 0,i=r._stateIconRowsAdditional.get(e);i&&r._stateIconRowsMatch(i,n)?s.set(e,i):n&&s.set(e,Object.entries(n))}),this._stateIconRowsAdditional=s}},{key:"_stateIconRowsMatch",value:function(t,e){var n,i={},r=jn(t);try{for(r.s();!(n=r.n()).done;){var o=$n(n.value,2),a=o[0],s=o[1];a.trim()&&s.trim()&&(i[a.trim()]=s.trim())}}catch(t){r.e(t)}finally{r.f()}var c=null!=e?e:{},l=Object.keys(i);return l.length===Object.keys(c).length&&l.every(function(t){return i[t]===c[t]})}},{key:"_readClipboard",value:function(){try{var t=sessionStorage.getItem(Vn);if(!t)return;var e=JSON.parse(t);if(e&&"object"===En(e))return e}catch(t){}}},{key:"_writeClipboard",value:function(t){try{sessionStorage.setItem(Vn,JSON.stringify(t)),this._clipboardEntity=t}catch(t){}}},{key:"_hasNativeTabs",get:function(){return!!customElements.get("ha-tab-group")&&!!customElements.get("ha-tab-group-tab")}},{key:"render",value:function(){return this.hass&&this._config?W(Be||(Be=mn(["\n \n ",'\n \n\n \n "])),"Entities",this._entitiesExpanded,this._onEntitiesExpandedChanged,this._renderEntitiesPanel(),"4.12.0","2026-09-27T17:51:53.225Z"):Z}},{key:"_isCustomFormat",value:function(t,e){return this._customFormatScopes.has(t)||!!e&&!un.has(e)}},{key:"_setCustomFormatScope",value:function(t,e){if(e!==this._customFormatScopes.has(t)){var n=new Set(this._customFormatScopes);e?n.add(t):n.delete(t),this._customFormatScopes=n}}},{key:"_formatToForm",value:function(t,e){return this._isCustomFormat(t,e.format)?On(On({},e),{},{format:cn}):e}},{key:"_formatFromForm",value:function(t,e,n){if(e.format===cn){this._setCustomFormatScope(t,!0);var i=On({},e);return void 0!==n?i.format=n:delete i.format,i}return this._setCustomFormatScope(t,!1),e}},{key:"_renderCustomFormatField",value:function(t,e,n){return this._isCustomFormat(t,e)?W(We||(We=mn(["\n \n "])),this.hass,{custom_format:null!=e?e:""},[{name:"custom_format",selector:{text:{}}}],function(){return"Custom format (e.g. invert, precision3)"},function(t){var e,i=(null!==(e=t.detail.value.custom_format)&&void 0!==e?e:"").trim();n(i||void 0)}):Z}},{key:"_keyFor",value:function(t){return this._keys.has(t)||this._keys.set(t,"".concat(t,"-").concat(Math.random().toString(36).slice(2,10))),this._keys.get(t)}},{key:"_renderEntitiesPanel",value:function(){var t,e,n=this,i=null!==(t=null===(e=this._config)||void 0===e?void 0:e.entities)&&void 0!==t?t:[],r=Math.min(this._selectedTab,i.length);return W(qe||(qe=mn(['\n
\n
\n ','\n \n
\n\n
\n ',"\n
\n
\n "])),this._hasNativeTabs?W(Ze||(Ze=mn(['\n \n \n \n \n \n
\n
\n \n \n ','\n \n ','\n \n ',"\n \n "])),"Copy main as template",Pn,this._copyMainAsTemplate,"Paste as new entity",Tn,!this._clipboardEntity,this._pasteEntity,this.hass,this._mainFormData(),fn,this._computeLabel,this._mainValueChanged,this._renderCustomFormatField("main",null===(t=this._config)||void 0===t?void 0:t.format,function(t){return n._updateConfig({format:t})}),this.hass,this._mainFormData(),dn,this._computeLabel,this._mainValueChanged,this._renderSecondaryInfoBlock(),this._renderStateIconRows("main"),this._renderStylesBlock(null===(e=this._config)||void 0===e?void 0:e.styles,function(t){return n._mainStylesChanged(t)}))}},{key:"_renderStylesBlock",value:function(t,e){return W(Qe||(Qe=mn(['\n \n ','\n \n \n \n \n
\n
\n \n \n ','\n \n ',"\n \n "])),"Move before","M15.41,16.58L10.83,12L15.41,7.41L14,6L8,12L14,18L15.41,16.58Z",0===t,function(){return i._moveAdditional(t,-1)},"Move after","M8.59,16.58L13.17,12L8.59,7.41L10,6L16,12L10,18L8.59,16.58Z",t===a,function(){return i._moveAdditional(t,1)},"Copy entity",Pn,function(){return i._copyAdditional(t)},"Cut entity","M19,3L13,9L15,11L22,4V3M12,12.5A0.5,0.5 0 0,1 11.5,12A0.5,0.5 0 0,1 12,11.5A0.5,0.5 0 0,1 12.5,12A0.5,0.5 0 0,1 12,12.5M6,20A2,2 0 0,1 4,18C4,16.89 4.9,16 6,16A2,2 0 0,1 8,18C8,19.11 7.1,20 6,20M6,8A2,2 0 0,1 4,6C4,4.89 4.9,4 6,4A2,2 0 0,1 8,6C8,7.11 7.1,8 6,8M9.64,7.64C9.87,7.14 10,6.59 10,6A4,4 0 0,0 6,2A4,4 0 0,0 2,6A4,4 0 0,0 6,10C6.59,10 7.14,9.87 7.64,9.64L10,12L7.64,14.36C7.14,14.13 6.59,14 6,14A4,4 0 0,0 2,18A4,4 0 0,0 6,22A4,4 0 0,0 10,18C10,17.41 9.87,16.86 9.64,16.36L12,14L19,21H22V20L9.64,7.64Z",function(){return i._cutAdditional(t)},"Paste from clipboard",Tn,!this._clipboardEntity,this._pasteEntity,"Delete entity",Cn,function(){return i._deleteAdditional(t)},this.hass,this._formatToForm("sub-".concat(t),Ln(o)),hn,this._computeLabel,function(e){return i._additionalValueChanged(e,t)},this._renderCustomFormatField("sub-".concat(t),o.format,function(e){return i._setAdditionalFormat(t,e)}),this.hass,this._formatToForm("sub-".concat(t),Ln(o)),dn,this._computeLabel,function(e){return i._additionalValueChanged(e,t)},this._renderStateIconRows(t),this._renderStylesBlock(o.styles,function(e){return i._additionalStylesChanged(e,t)}))}},{key:"_mainFormData",value:function(){return this._formatToForm("main",Ln(On({show_state:!0},this._config)))}},{key:"_setAdditionalFormat",value:function(t,e){var n;if(this._config){var i=yn(null!==(n=this._config.entities)&&void 0!==n?n:[]),r=i[t],o="string"==typeof r?{entity:r}:On({},r);e?o.format=e:delete o.format,i[t]=o,this._updateConfig({entities:i})}}},{key:"_secondaryInfoMode",value:function(){var t,e=null===(t=this._config)||void 0===t?void 0:t.secondary_info;return null==e?"none":"object"===En(e)?"entity":yt.includes(e)?"generic":"text"}},{key:"_renderSecondaryInfoBlock",value:function(){var t,e=this,n=this._secondaryInfoMode(),i=null===(t=this._config)||void 0===t?void 0:t.secondary_info;return W(nn||(nn=mn(["\n
\n \n ","\n ","\n ","\n
\n "])),this.hass,{mode:n},Mn,function(){return"Mode"},this._secondaryModeChanged,"text"===n?W(rn||(rn=mn(['
\n \n \n 3?(r=p===i)&&(c=o[(s=o[4])?5:(s=3,3)],o[4]=o[5]=t):o[0]<=h&&((r=n<2&&hi||i>p)&&(o[4]=n,o[5]=i,d.n=p,s=0))}if(r||n>1)return a;throw f=!0,i}return function(r,u,p){if(l>1)throw TypeError("Generator is already running");for(f&&1===u&&h(u,p),s=u,c=p;(e=s<2?t:c)||!f;){o||(s?s<3?(s>1&&(d.n=-1),h(s,c)):d.n=c:d.v=c);try{if(l=2,o){if(s||(r="next"),e=o[r]){if(!(e=e.call(o,c)))throw TypeError("iterator result is not an object");if(!e.done)return e;c=e.value,s<2&&(s=0)}else 1===s&&(e=o.return)&&e.call(o),s<2&&(c=TypeError("The iterator does not provide a '"+r+"' method"),s=1);o=t}else if((e=(f=d.n<0)?c:n.call(i,d))!==a)break}catch(e){o=t,s=1,c=e}finally{l=1}}return{value:e,done:f}}}(n,r,o),!0),l}var a={};function s(){}function c(){}function l(){}e=Object.getPrototypeOf;var u=[][i]?e(e([][i]())):(Ai(e={},i,function(){return this}),e),f=l.prototype=s.prototype=Object.create(u);function d(t){return Object.setPrototypeOf?Object.setPrototypeOf(t,l):(t.__proto__=l,Ai(t,r,"GeneratorFunction")),t.prototype=Object.create(f),t}return c.prototype=l,Ai(f,"constructor",l),Ai(l,"constructor",c),c.displayName="GeneratorFunction",Ai(l,r,"GeneratorFunction"),Ai(f),Ai(f,r,"Generator"),Ai(f,i,function(){return this}),Ai(f,"toString",function(){return"[object Generator]"}),(Oi=function(){return{w:o,m:d}})()}function Ai(t,e,n,i){var r=Object.defineProperty;try{r({},"",{})}catch(t){r=0}Ai=function(t,e,n,i){function o(e,n){Ai(t,e,function(t){return this._invoke(e,n,t)})}e?r?r(t,e,{value:n,enumerable:!i,configurable:!i,writable:!i}):t[e]=n:(o("next",0),o("throw",1),o("return",2))},Ai(t,e,n,i)}function Si(t,e,n,i,r,o,a){try{var s=t[o](a),c=s.value}catch(t){return void n(t)}s.done?e(c):Promise.resolve(c).then(i,r)}function ji(t,e){return e||(e=t.slice(0)),Object.freeze(Object.defineProperties(t,{raw:{value:Object.freeze(e)}}))}function $i(t,e){var n=Object.keys(t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(t);e&&(i=i.filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable})),n.push.apply(n,i)}return n}function xi(t){for(var e=1;e\n \n ',"\n
\n "])),u?"main-icon-painted":"",(s=u)?"--multiple-entity-row-main-icon-color: ".concat(s,";"):"",Ie(i.name_gap),this._hass,c,this.renderSecondaryInfo(),l,!1,[this.config.column?"entities-column":"entities-row",!this.config.column&&this.config.wrap?"wrap":"",null!==(e=Ui[this.config.align])&&void 0!==e?e:"",l?"no-name":""].filter(Boolean).join(" "),this.config.show_state_first?W(oi||(oi=ji(["","",""])),this.renderMainEntity(),this.entities.map(function(t,e){return n.renderEntity(t.stateObj,t,e)})):W(ai||(ai=ji(["","",""])),this.entities.map(function(t,e){return n.renderEntity(t.stateObj,t,e)}),this.renderMainEntity()))}},{key:"updated",value:function(t){var n;null===(n=Ti(e,"updated",this,3))||void 0===n||n([t]),this.syncRowStyles()}},{key:"syncRowStyles",value:function(){var t,e,n=Ie(null===(t=this.config)||void 0===t?void 0:t.name_gap);if(n||this._mainPainted){var i=null===(e=this.renderRoot)||void 0===e?void 0:e.querySelector("hui-generic-entity-row");i&&(n&&this.injectRowStyle(i,"data-mer-name-gap",":host .info{padding-inline-start:var(--multiple-entity-row-name-gap,16px)}"),i.classList.contains("main-icon-painted")&&this.injectRowStyle(i,"data-mer-main-icon",Di))}}},{key:"injectRowStyle",value:(n=function(t){return function(){var e=this,n=arguments;return new Promise(function(i,r){var o=t.apply(e,n);function a(t){Si(o,i,r,a,s,"next",t)}function s(t){Si(o,i,r,a,s,"throw",t)}a(void 0)})}}(Oi().m(function t(e,n,i){var r,o,a;return Oi().w(function(t){for(;;)switch(t.p=t.n){case 0:if(null===(r=e.shadowRoot)||void 0===r||!r.querySelector("style[".concat(n,"]"))){t.n=1;break}return t.a(2);case 1:return t.p=1,t.n=2,e.updateComplete;case 2:t.n=4;break;case 3:return t.p=3,t.v,t.a(2);case 4:if(o=e.shadowRoot){t.n=5;break}return t.a(2);case 5:o.querySelector("style[".concat(n,"]"))||((a=document.createElement("style")).setAttribute(n,""),a.textContent=i,o.prepend(a));case 6:return t.a(2)}},t,null,[[1,3]])})),function(t,e,i){return n.apply(this,arguments)})},{key:"renderSecondaryInfo",value:function(){var t=this.config.secondary_info;if(!t||Mt(t))return null;if("string"==typeof t)return ie(t)?me(this._templateResults,t,this.config.entity,pe(this.config))||" ":t;var e=this._resolved(t);if(Tt(this.info,e,this._hass))return null;var n=He(this._hass,this.info,e);return W(si||(si=ji([''," ",""])),Ne(e),n,this.renderValue(this.info,e))}},{key:"renderMainEntity",value:function(){var t;if(!1===this.config.show_state)return null;var e=null!==(t=this._rowScope)&&void 0!==t?t:this._resolved(this.config);if(Tt(this.stateObj,e,this._hass))return this.config.default?W(ci||(ci=ji(['
\n ',"\n
","
\n
"])),Ne(e),this.renderMainHeader(),this.config.default):null;var n=this.getGestureHandlers("main",this.config.entity,this.config);return W(li||(li=ji(['\n ',"\n
","
\n "])),Ne(e),null==n?void 0:n.onDown,null==n?void 0:n.onUp,null==n?void 0:n.onCancel,Hi,Hi,Hi,Hi,Hi,Hi,this.renderMainHeader(),this.renderValue(this.stateObj,e))}},{key:"renderEntity",value:function(t,e,n){var i,r,o;if(e=this._resolved(e),!t||Tt(t,e,this._hass))return e.default?W(ui||(ui=ji(['
\n ',"\n
","
\n
"])),Li(e,null==t?void 0:t.state),Ne(e),null!==(r=Fi(t?He(this._hass,t,e):e.name))&&void 0!==r?r:this.headerPlaceholder(),e.default):t||e.hide_unavailable?null:W(fi||(fi=ji(['\n ','\n
\n '])),Ne(e),this._hass.localize("ui.panel.lovelace.warning.entity_not_found","entity",null!==(o=e.entity)&&void 0!==o?o:""),Fi(e.name));var a=this.getGestureHandlers("sub-".concat(n),t.entity_id,e);return W(di||(di=ji(['\n ',"\n
\n ","\n
\n "])),Li(e,t.state),Ne(e),null==a?void 0:a.onDown,null==a?void 0:a.onUp,null==a?void 0:a.onCancel,Hi,Hi,Hi,Hi,Hi,Hi,null!==(i=Fi(He(this._hass,t,e)))&&void 0!==i?i:Ni(e)?null:this.headerPlaceholder(),e.icon||kt(e.state_icon)?this.renderIcon(t,e):this.renderValue(t,e))}},{key:"renderMainHeader",value:function(){var t,e=null!==(t=Fi(this.config.state_header))&&void 0!==t?t:!0===this.config.toggle?null:this.headerPlaceholder();return e?W(hi||(hi=ji(["",""])),e):null}},{key:"headerPlaceholder",value:function(){return null!=Fi(this.config.state_header)||this.entities.some(function(t){return!1!==(e=t).name&&null!==Fi(e.name)&&!(!e.name&&!e.entity);var e})?" ":null}},{key:"renderValue",value:function(t,e){var n;if(!0===e.toggle)return this.renderToggle(t,e);if(void 0!==e.template){var i=ie(e.template)?"":e.template;return"".concat(i).concat(e.unit?" ".concat(e.unit):"")}if(!e.attribute&&null!==(n=t.entity_id)&&void 0!==n&&n.startsWith("timer."))return W(pi||(pi=ji([""])),this._hass,t);var r=e.attribute&&[ht,pt].includes(e.attribute);if(e.format&&mt.includes(e.format)){var o,a=r?t[e.attribute.replace("-","_")]:e.attribute?null!==(o=t.attributes[e.attribute])&&void 0!==o?o:t[e.attribute]:t.state,s=new Date(a);return s instanceof Date&&!isNaN(s.getTime())?W(mi||(mi=ji([""])),this._hass,s,e.format):a}return r?W(yi||(yi=ji([""])),this._hass,t[e.attribute.replace("-","_")]):Fe(this._hass,t,e)}},{key:"renderToggle",value:function(t,e){var n,i=this,r=null===(n=e.tap_action)||void 0===n?void 0:n.confirmation,o=r?{handleEvent:function(n){var o,a,s;n.stopPropagation(),n.preventDefault();var c=kt(r)&&(null===(o=r.exemptions)||void 0===o?void 0:o.some(function(t){var e;return t.user===(null===(e=i._hass.user)||void 0===e?void 0:e.id)})),l=kt(r)&&r.text,u=ie(l)?me(i._templateResults,l,null!==(a=e.entity)&&void 0!==a?a:i.config.entity,pe(i.config,e)):l||"Are you sure you want to toggle ".concat(null!==(s=He(i._hass,t,e))&&void 0!==s?s:t.entity_id,"?");(c||confirm(u))&&i._hass.callService("homeassistant","toggle",{entity_id:t.entity_id})},capture:!0}:void 0;return W(vi||(vi=ji(["\n '])),Hi,Hi,Hi,o,t,this._hass)}},{key:"renderIcon",value:function(t,e){var n,i,r,o,a=null!==(n=Re(t,e))&&void 0!==n?n:!0===e.icon?t.attributes.icon||null:e.icon,s=null!==(i=this._rowScope)&&void 0!==i?i:this._resolved(this.config),c="cssColor"in(o=Nt(e,s,t.state))?{color:o.cssColor}:{stateColor:o.stateColor},l=c.stateColor,u=c.color,f=!(a||!t.attributes.entity_picture&&!t.attributes.entity_picture_local);return W(bi||(bi=ji([''])),f?" has-picture":"",Me(null!==(r=Dt(e,t.state))&&void 0!==r?r:e.icon_color),this._hass,t,a,l,u)}},{key:"renderWarning",value:function(){return W(gi||(gi=ji(["\n ","\n "])),this._hass.localize("ui.panel.lovelace.warning.entity_not_found","entity",this.config.entity))}},{key:"getGestureHandlers",value:function(t,e,n){var i,r,o,a,s,c,l,u=this;return this._actionHandlers.has(t)||this._actionHandlers.set(t,(i=function(t,i){return u.dispatchAction(e,n,t,i)},r={hasHold:!!n.hold_action,hasDoubleTap:!!n.double_tap_action},s=r.hasHold,c=r.hasDoubleTap,l=!1,{onDown:function(){l=!1,s&&(o=setTimeout(function(){l=!0},500))},onUp:function(){if(clearTimeout(o),l)return l=!1,void i(!0,!1);c?a?(clearTimeout(a),a=void 0,i(!1,!0)):a=setTimeout(function(){a=void 0,i(!1,!1)},250):i(!1,!1)},onCancel:function(){clearTimeout(o)}})),this._actionHandlers.get(t)}},{key:"dispatchAction",value:function(t,e,n,i){var r,o,a=i?e.double_tap_action:n?e.hold_action:null!==(r=e.tap_action)&&void 0!==r?r:{action:"more-info"};if(a&&"none"!==a.action){var s,c,l,u,f,d,h=(s=a,c=this._templateResults,l=null!==(o=e.entity)&&void 0!==o?o:this.config.entity,u=pe(this.config,e),f=fe(u),d=function(t){if(ie(t)){var e=c.get(le(f+t,l));return void 0===e?"":e}return Array.isArray(t)?t.map(d):kt(t)?Object.fromEntries(Object.entries(t).map(function(t){var e=Xt(t,2),n=e[0],i=e[1];return[n,d(i)]})):t},d(s)),p=i?"double_tap":n?"hold":"tap";Ct(this,"hass-action",{config:ki({entity:h.entity||t},"".concat(p,"_action"),h),action:p})}}}],[{key:"getConfigElement",value:function(){return document.createElement("multiple-entity-row-editor")}},{key:"getStubConfig",value:function(t,e){var n,i,r=null!==(n=null!==(i=null==e?void 0:e.find(function(t){return t.startsWith("sensor.")}))&&void 0!==i?i:null==e?void 0:e[0])&&void 0!==n?n:"";return{entity:r}}},{key:"properties",get:function(){return{_hass:Object,config:Object,stateObj:Object,_templateResults:Object}}},{key:"styles",get:function(){return o(Se||(Se=function(t,e){return e||(e=t.slice(0)),Object.freeze(Object.defineProperties(t,{raw:{value:Object.freeze(e)}}))}(["\n /* state-badge is a fixed 40px box, which leaves an odd gap under a headered icon - let it\n shrink to the icon's natural size instead (see #425). */\n .icon-small {\n width: auto;\n height: auto;\n }\n /* ...except when it is showing a picture: state-badge then hides the icon and paints the\n image as a background, so the host has no in-flow content and would collapse to nothing.\n The class is set in renderIcon rather than reusing state-badge's own has-image. */\n .icon-small.has-picture {\n width: 40px;\n height: 40px;\n }\n .entity {\n text-align: center;\n cursor: pointer;\n }\n /* Marker for an entity id that resolves to nothing (see #364). */\n .entity .missing {\n color: var(--error-color, #db4437);\n }\n .entity span {\n font-size: 10px;\n color: var(--multiple-entity-row-header-color, var(--secondary-text-color));\n }\n .entities-row {\n flex-direction: row;\n display: inline-flex;\n justify-content: space-between;\n align-items: center;\n }\n /* HA's name box is what pushes the entities to the right: it grows at flex: 1 1 30%. Hiding\n it removes that push too, leaving them against the icon, so take over the job here - the\n point of hiding the name is more room, not a different alignment (see #341, #365). */\n .entities-row.no-name,\n .entities-column.no-name {\n margin-left: auto;\n }\n /* The 'styles' option reaches one entity's div, which is a flex item - so vertical-align\n there does nothing and alignment has to be set on the container instead (see #261). */\n .entities-row.align-top,\n .entities-column.align-top {\n align-items: flex-start;\n }\n .entities-row.align-bottom,\n .entities-column.align-bottom {\n align-items: flex-end;\n }\n /* The 16px gap must be margin, not padding: users tune spacing with their own margins in\n the 'styles' option, which replace this margin but would stack on top of a padding - 4.10.1 did\n padding and widened every tuned row into overflowing on phones (see #432). The gap still\n has to be clickable though: the row's cursor:pointer inherits into it, but HA stops\n slotted clicks at the bare slot (catchInteraction=false), so bare margin is dead space\n that looks clickable. The ::after extension puts the gap inside the entity's hit area\n without affecting layout. position:relative on every entity keeps hit-testing fair: a\n positioned later sibling beats its neighbor's ::after wherever a user's zero/negative\n margin makes them overlap, so no entity steals its neighbor's clicks. */\n .entities-row .entity {\n margin-right: 16px;\n position: relative;\n }\n .entities-row .entity:last-of-type {\n margin-right: 0;\n }\n .entities-row .entity:not(:last-of-type)::after {\n content: '';\n position: absolute;\n top: 0;\n bottom: 0;\n right: -16px;\n width: 16px;\n }\n /* HA's ha-entity-toggle host is display:flex with no horizontal alignment, so in a slot\n wider than the switch it hugs the left edge while everything else centers. Outer styles\n out-rank :host rules, so it can be centered from here; keeping the host's flex box (vs\n display:contents) preserves the full-width tap strip and HA's box assumptions (#436). */\n .entity ha-entity-toggle {\n justify-content: center;\n }\n /* Opt-in, because it trades a taller row for not overflowing: nothing between HA's .row and\n our entities can shrink, so a row needing more width than the card has just spills past\n the edge (worst on narrow phone screens - see #411). Wrapping reflows instead. */\n .entities-row.wrap {\n flex-wrap: wrap;\n justify-content: flex-end;\n row-gap: 4px;\n }\n .entities-column {\n flex-direction: column;\n display: flex;\n align-items: flex-end;\n justify-content: space-evenly;\n }\n .entities-column .entity div {\n display: inline-block;\n vertical-align: middle;\n }\n"])))}}]);var n}(ut);$t("multiple-entity-row",Vi),window.customCards=window.customCards||[],window.customCards.some(function(t){return"multiple-entity-row"===t.type})||window.customCards.push({type:"multiple-entity-row",name:"Multiple Entity Row",description:"Show multiple entity states and attributes on a single entity row"})})(); \ No newline at end of file diff --git a/www/community/lovelace-multiple-entity-row/multiple-entity-row.js.gz b/www/community/lovelace-multiple-entity-row/multiple-entity-row.js.gz index eb76dda90f3dccd47a009789eebd667fb1125c18..0cbc9da095f79664c9d32e2f0aaa5615d5fc813b 100644 GIT binary patch literal 27566 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 diff --git a/zigbee2mqtt/state.json b/zigbee2mqtt/state.json index 5c15b210..81a7dd3f 100644 --- a/zigbee2mqtt/state.json +++ b/zigbee2mqtt/state.json @@ -4,7 +4,7 @@ "state": "ON", "led_brightness": 100, "countdown_to_turn_off": 0, - "voltage": 118.8, + "voltage": 118.6, "countdown_to_turn_on": 0, "ac_frequency": 60, "power_factor": 0.11, @@ -22,15 +22,15 @@ }, "0xffffb40e0607af27": { "state": "ON", - "voltage": 121, + "voltage": 118.1, "ac_frequency": 60, "led_brightness": 100, "countdown_to_turn_off": 0, "countdown_to_turn_on": 0, - "power": 1.9, + "power": 2, "current": 0.09, "energy": 49.19, - "power_factor": 0.16, + "power_factor": 0.18, "update": { "state": "idle", "installed_version": 268513381, @@ -47,8 +47,8 @@ "countdown_to_turn_off": 0, "voltage": 118.4, "countdown_to_turn_on": 0, - "energy": 93.73, - "power_factor": 0.9, + "energy": 93.77, + "power_factor": 0.31, "ac_frequency": 60, "update": { "state": "idle", @@ -58,8 +58,8 @@ "latest_release_notes": null }, "linkquality": 120, - "power": 83.6, - "current": 0.82, + "power": 0.2, + "current": 0.01, "power_on_behavior": "on" }, "0xb40e060fffe031e3": { @@ -74,13 +74,13 @@ "led_brightness": 100, "countdown_to_turn_off": 0, "countdown_to_turn_on": 0, - "voltage": 118, + "voltage": 117.2, "state": "ON", "ac_frequency": 60, - "energy": 192.46, - "power": 0.8, - "current": 0.05, - "power_factor": 0.34, + "energy": 192.56, + "power": 96.7, + "current": 0.89, + "power_factor": 0.94, "update": { "state": "idle", "installed_version": 268513381, @@ -95,11 +95,11 @@ "led_brightness": 100, "countdown_to_turn_off": 0, "countdown_to_turn_on": 0, - "voltage": 118.7, - "energy": 95.08, + "voltage": 118.3, + "energy": 95.11, "state": "ON", - "power": 18.4, - "current": 0.26, + "power": 17.2, + "current": 0.28, "ac_frequency": 60, "power_factor": 0.54, "update": { @@ -114,12 +114,12 @@ }, "0xffffb40e060895b3": { "state": "ON", - "voltage": 118.6, + "voltage": 118.7, "ac_frequency": 60, - "energy": 12.9, + "energy": 12.91, "current": 0.01, "power": 0.1, - "power_factor": 0.11, + "power_factor": 0.22, "linkquality": 87, "update": { "state": "idle", @@ -136,7 +136,7 @@ "0xffffb40e0608864e": { "led_brightness": 100, "countdown_to_turn_off": 0, - "voltage": 119.3, + "voltage": 119, "energy": 29.67, "countdown_to_turn_on": 0, "state": "ON", @@ -224,7 +224,7 @@ }, "0xb40e060fffe717c5": { "battery": 100, - "occupancy": false, + "occupancy": true, "tamper": false, "battery_low": false, "linkquality": 116,