Skip to content

Commit 6beeee8

Browse files
committed
Sync with latest core - version for 2025.6 release
1 parent c4d150c commit 6beeee8

File tree

9 files changed

+79
-115
lines changed

9 files changed

+79
-115
lines changed

custom_components/zimi/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: ZimiConfigEntry) -> bool
5151
config_entry_id=entry.entry_id,
5252
identifiers={(DOMAIN, api.mac)},
5353
manufacturer=api.brand,
54-
name=f"{api.network_name}",
54+
name=api.network_name,
5555
model="Zimi Cloud Connect",
5656
sw_version=api.firmware_version,
5757
connections={(CONNECTION_NETWORK_MAC, api.mac)},

custom_components/zimi/cover.py

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,12 @@
55
import logging
66
from typing import Any
77

8-
from zcc import ControlPoint
9-
from zcc.device import ControlPointDevice
10-
118
from homeassistant.components.cover import (
129
CoverDeviceClass,
1310
CoverEntity,
1411
CoverEntityFeature,
1512
)
1613
from homeassistant.core import HomeAssistant
17-
18-
# Import the device class from the component that you want to support
1914
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
2015

2116
from . import ZimiConfigEntry
@@ -31,9 +26,9 @@ async def async_setup_entry(
3126
) -> None:
3227
"""Set up the Zimi Cover platform."""
3328

34-
api: ControlPoint = config_entry.runtime_data
29+
api = config_entry.runtime_data
3530

36-
doors: list[ZimiCover] = [ZimiCover(device, api) for device in api.doors]
31+
doors = [ZimiCover(device, api) for device in api.doors]
3732

3833
async_add_entities(doors)
3934

@@ -49,15 +44,6 @@ class ZimiCover(ZimiEntity, CoverEntity):
4944
| CoverEntityFeature.STOP
5045
)
5146

52-
def __init__(self, device: ControlPointDevice, api: ControlPoint) -> None:
53-
"""Initialize an Zimicover."""
54-
55-
super().__init__(device, api)
56-
57-
_LOGGER.debug(
58-
"Initialising ZimiCover %s in %s", self._device.name, self._device.room
59-
)
60-
6147
async def async_close_cover(self, **kwargs: Any) -> None:
6248
"""Close the cover/door."""
6349
_LOGGER.debug("Sending close_cover() for %s", self.name)

custom_components/zimi/entity.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,23 +21,26 @@ class ZimiEntity(Entity):
2121
_attr_should_poll = False
2222
_attr_has_entity_name = True
2323

24-
def __init__(self, device: ControlPointDevice, api: ControlPoint) -> None:
24+
def __init__(
25+
self, device: ControlPointDevice, api: ControlPoint, use_device_name=True
26+
) -> None:
2527
"""Initialize an HA Entity which is a ZimiDevice."""
2628

2729
self._device = device
28-
self._attr_unique_id = self._device.identifier
30+
self._attr_unique_id = device.identifier
2931
self._attr_device_info = DeviceInfo(
30-
identifiers={(DOMAIN, self._device.manufacture_info.identifier)},
31-
manufacturer=self._device.manufacture_info.manufacturer,
32-
model=self._device.manufacture_info.model,
33-
name=self._device.manufacture_info.name,
32+
identifiers={(DOMAIN, device.manufacture_info.identifier)},
33+
manufacturer=device.manufacture_info.manufacturer,
34+
model=device.manufacture_info.model,
35+
name=device.manufacture_info.name,
3436
hw_version=device.manufacture_info.hwVersion,
3537
sw_version=device.manufacture_info.firmwareVersion,
3638
suggested_area=device.room,
3739
via_device=(DOMAIN, api.mac),
3840
)
39-
self._attr_name = self._device.name.strip()
40-
self._attr_suggested_area = self._device.room
41+
if use_device_name:
42+
self._attr_name = device.name.strip()
43+
self._attr_suggested_area = device.room
4144

4245
@property
4346
def available(self) -> bool:

custom_components/zimi/fan.py

Lines changed: 12 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,8 @@
66
import math
77
from typing import Any
88

9-
from zcc import ControlPoint
10-
from zcc.device import ControlPointDevice
11-
129
from homeassistant.components.fan import FanEntity, FanEntityFeature
1310
from homeassistant.core import HomeAssistant
14-
15-
# Import the device class from the component that you want to support
1611
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
1712
from homeassistant.util.percentage import (
1813
percentage_to_ranged_value,
@@ -31,50 +26,39 @@ async def async_setup_entry(
3126
config_entry: ZimiConfigEntry,
3227
async_add_entities: AddConfigEntryEntitiesCallback,
3328
) -> None:
34-
"""Set up the Zimi Cover platform."""
29+
"""Set up the Zimi Fan platform."""
3530

36-
api: ControlPoint = config_entry.runtime_data
31+
api = config_entry.runtime_data
3732

38-
fans: list[ZimiFan] = [ZimiFan(device, api) for device in api.fans]
39-
40-
async_add_entities(fans)
33+
async_add_entities([ZimiFan(device, api) for device in api.fans])
4134

4235

4336
class ZimiFan(ZimiEntity, FanEntity):
4437
"""Representation of a Zimi fan."""
4538

39+
_attr_speed_range = (0, 7)
40+
4641
_attr_supported_features = (
4742
FanEntityFeature.SET_SPEED
4843
| FanEntityFeature.TURN_OFF
4944
| FanEntityFeature.TURN_ON
5045
)
5146

52-
def __init__(self, device: ControlPointDevice, api: ControlPoint) -> None:
53-
"""Initialize an ZimiFan."""
54-
55-
super().__init__(device, api)
56-
57-
_LOGGER.debug(
58-
"Initialising ZimiFan %s in %s", self._device.name, self._device.room
59-
)
60-
61-
self._speed = self._device.fanspeed
62-
6347
async def async_set_percentage(self, percentage: int) -> None:
6448
"""Set the desired speed for the fan."""
65-
_LOGGER.debug("Sending async_set_percentage() with percentage %s", percentage)
6649

6750
if percentage == 0:
6851
await self.async_turn_off()
6952
return
7053

7154
target_speed = math.ceil(
72-
percentage_to_ranged_value(self._speed_range, percentage)
55+
percentage_to_ranged_value(self._attr_speed_range, percentage)
7356
)
57+
7458
_LOGGER.debug(
75-
"async_set_percentage() converted percentage %s to speed %s",
59+
"Sending async_set_percentage() for %s with percentage %s",
60+
self.name,
7661
percentage,
77-
target_speed,
7862
)
7963

8064
await self._device.set_fanspeed(target_speed)
@@ -94,21 +78,17 @@ async def async_turn_off(self, **kwargs: Any) -> None:
9478
"""Instruct the fan to turn off."""
9579

9680
_LOGGER.debug("Sending turn_off() for %s", self.name)
81+
9782
await self._device.turn_off()
9883

9984
@property
10085
def percentage(self) -> int:
10186
"""Return the current speed percentage for the fan."""
10287
if not self._device.fanspeed:
10388
return 0
104-
return ranged_value_to_percentage(self._speed_range, self._device.fanspeed)
105-
106-
@property
107-
def _speed_range(self) -> tuple[int, int]:
108-
"""Return the range of speeds."""
109-
return (0, 7)
89+
return ranged_value_to_percentage(self._attr_speed_range, self._device.fanspeed)
11090

11191
@property
11292
def speed_count(self) -> int:
11393
"""Return the number of speeds the fan supports."""
114-
return int_states_in_range(self._speed_range)
94+
return int_states_in_range(self._attr_speed_range)

custom_components/zimi/light.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ async def async_setup_entry(
3232
]
3333

3434
lights.extend(
35-
[ZimiDimmer(device, api) for device in api.lights if device.type == "dimmer"]
35+
ZimiDimmer(device, api) for device in api.lights if device.type == "dimmer"
3636
)
3737

3838
async_add_entities(lights)
@@ -81,8 +81,6 @@ def __init__(self, device: ControlPointDevice, api: ControlPoint) -> None:
8181
super().__init__(device, api)
8282
self._attr_color_mode = ColorMode.BRIGHTNESS
8383
self._attr_supported_color_modes = {ColorMode.BRIGHTNESS}
84-
if self._device.type != "dimmer":
85-
raise ValueError("ZimiDimmer needs a dimmable light")
8684

8785
async def async_turn_on(self, **kwargs: Any) -> None:
8886
"""Instruct the light to turn on (with optional brightness)."""

custom_components/zimi/manifest.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@
44
"codeowners": [
55
"@markhannon"
66
],
7-
"version": "2.0.3",
7+
"version": "2.0.4",
88
"config_flow": true,
99
"documentation": "https://www.home-assistant.io/integrations/zimi",
1010
"iot_class": "local_push",
1111
"quality_scale": "bronze",
1212
"requirements": [
13-
"zcc-helper==3.5"
13+
"zcc-helper==3.5.2"
1414
]
1515
}

custom_components/zimi/sensor.py

Lines changed: 36 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
from __future__ import annotations
44

5+
from collections.abc import Callable
6+
from dataclasses import dataclass
57
import logging
68

79
from zcc import ControlPoint
@@ -15,40 +17,45 @@
1517
from homeassistant.const import PERCENTAGE, EntityCategory, UnitOfTemperature
1618
from homeassistant.core import HomeAssistant
1719
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
20+
from homeassistant.helpers.typing import StateType
1821

1922
from . import ZimiConfigEntry
2023
from .entity import ZimiEntity
2124

22-
SENSOR_KEY_DOOR_TEMP = "door_temperature"
23-
SENSOR_KEY_GARAGE_BATTERY = "garage_battery"
24-
SENSOR_KEY_GARAGE_HUMDITY = "garage_humidty"
25-
SENSOR_KEY_GARAGE_TEMP = "garage_temperature"
2625

27-
GARAGE_SENSOR_DESCRIPTIONS = (
28-
SensorEntityDescription(
29-
key=SENSOR_KEY_DOOR_TEMP,
30-
name="Outside temperature",
26+
@dataclass(frozen=True, kw_only=True)
27+
class ZimiSensorEntityDescription(SensorEntityDescription):
28+
"""Class describing Zimi sensor entities."""
29+
30+
value_fn: Callable[[ControlPointDevice], StateType]
31+
32+
33+
GARAGE_SENSOR_DESCRIPTIONS: tuple[ZimiSensorEntityDescription, ...] = (
34+
ZimiSensorEntityDescription(
35+
key="door_temperature",
36+
translation_key="door_temperature",
3137
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
3238
device_class=SensorDeviceClass.TEMPERATURE,
39+
value_fn=lambda device: device.door_temp,
3340
),
34-
SensorEntityDescription(
35-
key=SENSOR_KEY_GARAGE_BATTERY,
36-
name="Battery Level",
41+
ZimiSensorEntityDescription(
42+
key="garage_battery",
3743
native_unit_of_measurement=PERCENTAGE,
3844
entity_category=EntityCategory.DIAGNOSTIC,
3945
device_class=SensorDeviceClass.BATTERY,
46+
value_fn=lambda device: device.battery_level,
4047
),
41-
SensorEntityDescription(
42-
key=SENSOR_KEY_GARAGE_TEMP,
43-
name="Garage temperature",
48+
ZimiSensorEntityDescription(
49+
key="garage_temperature",
4450
native_unit_of_measurement=UnitOfTemperature.CELSIUS,
4551
device_class=SensorDeviceClass.TEMPERATURE,
52+
value_fn=lambda device: device.garage_temp,
4653
),
47-
SensorEntityDescription(
48-
key=SENSOR_KEY_GARAGE_HUMDITY,
49-
name="Garage humidity",
54+
ZimiSensorEntityDescription(
55+
key="garage_humidty",
5056
native_unit_of_measurement=PERCENTAGE,
5157
device_class=SensorDeviceClass.HUMIDITY,
58+
value_fn=lambda device: device.garage_humidity,
5259
),
5360
)
5461

@@ -62,50 +69,35 @@ async def async_setup_entry(
6269
) -> None:
6370
"""Set up the Zimi Sensor platform."""
6471

65-
api: ControlPoint = config_entry.runtime_data
72+
api = config_entry.runtime_data
6673

67-
for description in GARAGE_SENSOR_DESCRIPTIONS:
68-
sensors: list[ZimiSensor] = [
69-
ZimiSensor(device, description, api) for device in api.sensors
70-
]
71-
72-
async_add_entities(sensors)
74+
async_add_entities(
75+
ZimiSensor(device, description, api)
76+
for device in api.sensors
77+
for description in GARAGE_SENSOR_DESCRIPTIONS
78+
)
7379

7480

7581
class ZimiSensor(ZimiEntity, SensorEntity):
7682
"""Representation of a Zimi sensor."""
7783

84+
entity_description: ZimiSensorEntityDescription
85+
7886
def __init__(
7987
self,
8088
device: ControlPointDevice,
81-
description: SensorEntityDescription,
89+
description: ZimiSensorEntityDescription,
8290
api: ControlPoint,
8391
) -> None:
8492
"""Initialize an ZimiSensor with specified type."""
8593

86-
super().__init__(device, api)
94+
super().__init__(device, api, use_device_name=False)
8795

8896
self.entity_description = description
8997
self._attr_unique_id = device.identifier + "." + self.entity_description.key
9098

91-
_LOGGER.debug(
92-
"Initialising ZimiSensor %s in %s", self._device.name, self._device.room
93-
)
94-
9599
@property
96-
def native_value(self) -> float | None:
100+
def native_value(self) -> StateType:
97101
"""Return the state of the sensor."""
98102

99-
if self.entity_description.key == SENSOR_KEY_DOOR_TEMP:
100-
return self._device.door_temp
101-
102-
if self.entity_description.key == SENSOR_KEY_GARAGE_BATTERY:
103-
return self._device.battery_level
104-
105-
if self.entity_description.key == SENSOR_KEY_GARAGE_HUMDITY:
106-
return self._device.garage_humidity
107-
108-
if self.entity_description.key == SENSOR_KEY_GARAGE_TEMP:
109-
return self._device.garage_temp
110-
111-
return None
103+
return self.entity_description.value_fn(self._device)

custom_components/zimi/strings.json

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,27 @@
2727
"port": "[%key:common::config_flow::data::port%]"
2828
},
2929
"data_description": {
30-
"host": "Mandatory - ZCC IP address.",
31-
"port": "Mandatory - ZCC port number (default=5003)."
30+
"host": "[%key:component::zimi::config::step::selection::data_description::host%]",
31+
"port": "[%key:component::zimi::config::step::selection::data_description::port%]"
3232
}
3333
}
3434
},
3535
"error": {
3636
"cannot_connect": "[%key:common::config_flow::error::cannot_connect%]",
3737
"unknown": "[%key:common::config_flow::error::unknown%]",
38-
"timeout": "Connection timed out",
39-
"invalid_host": "Invalid hostname",
38+
"timeout": "[%key:common::config_flow::error::timeout_connect%]",
39+
"invalid_host": "[%key:common::config_flow::error::invalid_host%]",
4040
"connection_refused": "Connection refused"
4141
},
4242
"abort": {
4343
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]"
4444
}
45+
},
46+
"entity": {
47+
"sensor": {
48+
"door_temperature": {
49+
"name": "Outside temperature"
50+
}
51+
}
4552
}
4653
}

0 commit comments

Comments
 (0)