Skip to content

Commit aa5b970

Browse files
authored
Beta firmware update switch for Connect integrations (#155370)
1 parent 8091204 commit aa5b970

File tree

28 files changed

+1124
-139
lines changed

28 files changed

+1124
-139
lines changed

homeassistant/components/homeassistant_connect_zbt2/__init__.py

Lines changed: 34 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,35 @@
22

33
from __future__ import annotations
44

5+
from dataclasses import dataclass
56
import logging
67
import os.path
78

9+
from homeassistant.components.homeassistant_hardware.coordinator import (
10+
FirmwareUpdateCoordinator,
11+
)
812
from homeassistant.components.usb import USBDevice, async_register_port_event_callback
913
from homeassistant.config_entries import ConfigEntry
1014
from homeassistant.core import HomeAssistant, callback
1115
from homeassistant.exceptions import ConfigEntryNotReady
1216
from homeassistant.helpers import config_validation as cv
17+
from homeassistant.helpers.aiohttp_client import async_get_clientsession
1318
from homeassistant.helpers.typing import ConfigType
1419

15-
from .const import DEVICE, DOMAIN
20+
from .const import DEVICE, DOMAIN, NABU_CASA_FIRMWARE_RELEASES_URL
1621

1722
_LOGGER = logging.getLogger(__name__)
1823

24+
type HomeAssistantConnectZBT2ConfigEntry = ConfigEntry[HomeAssistantConnectZBT2Data]
25+
26+
27+
@dataclass
28+
class HomeAssistantConnectZBT2Data:
29+
"""Runtime data definition."""
30+
31+
coordinator: FirmwareUpdateCoordinator
32+
33+
1934
CONFIG_SCHEMA = cv.empty_config_schema(DOMAIN)
2035

2136

@@ -49,7 +64,9 @@ def async_port_event_callback(
4964
return True
5065

5166

52-
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
67+
async def async_setup_entry(
68+
hass: HomeAssistant, entry: HomeAssistantConnectZBT2ConfigEntry
69+
) -> bool:
5370
"""Set up a Home Assistant Connect ZBT-2 config entry."""
5471

5572
# Postpone loading the config entry if the device is missing
@@ -60,12 +77,23 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
6077
translation_key="device_disconnected",
6178
)
6279

63-
await hass.config_entries.async_forward_entry_setups(entry, ["update"])
80+
# Create and store the firmware update coordinator in runtime_data
81+
session = async_get_clientsession(hass)
82+
coordinator = FirmwareUpdateCoordinator(
83+
hass,
84+
entry,
85+
session,
86+
NABU_CASA_FIRMWARE_RELEASES_URL,
87+
)
88+
entry.runtime_data = HomeAssistantConnectZBT2Data(coordinator)
89+
90+
await hass.config_entries.async_forward_entry_setups(entry, ["switch", "update"])
6491

6592
return True
6693

6794

68-
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
95+
async def async_unload_entry(
96+
hass: HomeAssistant, entry: HomeAssistantConnectZBT2ConfigEntry
97+
) -> bool:
6998
"""Unload a config entry."""
70-
await hass.config_entries.async_unload_platforms(entry, ["update"])
71-
return True
99+
return await hass.config_entries.async_unload_platforms(entry, ["switch", "update"])

homeassistant/components/homeassistant_connect_zbt2/const.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
DOMAIN = "homeassistant_connect_zbt2"
44

55
NABU_CASA_FIRMWARE_RELEASES_URL = (
6-
"https://api.github.com/repos/NabuCasa/silabs-firmware-builder/releases/latest"
6+
"https://api.github.com/repos/NabuCasa/silabs-firmware-builder/releases"
77
)
88

99
FIRMWARE = "firmware"
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"entity": {
3+
"switch": {
4+
"beta_firmware": {
5+
"default": "mdi:test-tube"
6+
}
7+
}
8+
}
9+
}

homeassistant/components/homeassistant_connect_zbt2/strings.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,13 @@
9090
}
9191
}
9292
},
93+
"entity": {
94+
"switch": {
95+
"beta_firmware": {
96+
"name": "Beta firmware updates"
97+
}
98+
}
99+
},
93100
"exceptions": {
94101
"device_disconnected": {
95102
"message": "The device is not plugged in"
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
"""Home Assistant Connect ZBT-2 switch entities."""
2+
3+
from __future__ import annotations
4+
5+
import logging
6+
7+
from homeassistant.components.homeassistant_hardware.coordinator import (
8+
FirmwareUpdateCoordinator,
9+
)
10+
from homeassistant.components.homeassistant_hardware.switch import (
11+
BaseBetaFirmwareSwitch,
12+
)
13+
from homeassistant.core import HomeAssistant
14+
from homeassistant.helpers.device_registry import DeviceInfo
15+
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
16+
17+
from . import HomeAssistantConnectZBT2ConfigEntry
18+
from .const import DOMAIN, HARDWARE_NAME, SERIAL_NUMBER
19+
20+
_LOGGER = logging.getLogger(__name__)
21+
22+
23+
async def async_setup_entry(
24+
hass: HomeAssistant,
25+
config_entry: HomeAssistantConnectZBT2ConfigEntry,
26+
async_add_entities: AddConfigEntryEntitiesCallback,
27+
) -> None:
28+
"""Set up the switch platform for Home Assistant Connect ZBT-2."""
29+
async_add_entities(
30+
[BetaFirmwareSwitch(config_entry.runtime_data.coordinator, config_entry)]
31+
)
32+
33+
34+
class BetaFirmwareSwitch(BaseBetaFirmwareSwitch):
35+
"""Home Assistant Connect ZBT-2 beta firmware switch."""
36+
37+
def __init__(
38+
self,
39+
coordinator: FirmwareUpdateCoordinator,
40+
config_entry: HomeAssistantConnectZBT2ConfigEntry,
41+
) -> None:
42+
"""Initialize the beta firmware switch."""
43+
super().__init__(coordinator, config_entry)
44+
45+
serial_number = self._config_entry.data[SERIAL_NUMBER]
46+
47+
self._attr_unique_id = f"{serial_number}_beta_firmware"
48+
self._attr_device_info = DeviceInfo(
49+
identifiers={(DOMAIN, serial_number)},
50+
name=f"{HARDWARE_NAME} ({serial_number})",
51+
model=HARDWARE_NAME,
52+
manufacturer="Nabu Casa",
53+
serial_number=serial_number,
54+
)

homeassistant/components/homeassistant_connect_zbt2/update.py

Lines changed: 8 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44

55
import logging
66

7-
import aiohttp
8-
97
from homeassistant.components.homeassistant_hardware.coordinator import (
108
FirmwareUpdateCoordinator,
119
)
@@ -19,22 +17,14 @@
1917
ResetTarget,
2018
)
2119
from homeassistant.components.update import UpdateDeviceClass
22-
from homeassistant.config_entries import ConfigEntry
2320
from homeassistant.const import EntityCategory
2421
from homeassistant.core import HomeAssistant, callback
2522
from homeassistant.helpers import device_registry as dr, entity_registry as er
26-
from homeassistant.helpers.aiohttp_client import async_get_clientsession
2723
from homeassistant.helpers.device_registry import DeviceInfo
2824
from homeassistant.helpers.entity_platform import AddConfigEntryEntitiesCallback
2925

30-
from .const import (
31-
DOMAIN,
32-
FIRMWARE,
33-
FIRMWARE_VERSION,
34-
HARDWARE_NAME,
35-
NABU_CASA_FIRMWARE_RELEASES_URL,
36-
SERIAL_NUMBER,
37-
)
26+
from . import HomeAssistantConnectZBT2ConfigEntry
27+
from .const import DOMAIN, FIRMWARE, FIRMWARE_VERSION, HARDWARE_NAME, SERIAL_NUMBER
3828

3929
_LOGGER = logging.getLogger(__name__)
4030

@@ -91,8 +81,7 @@
9181

9282
def _async_create_update_entity(
9383
hass: HomeAssistant,
94-
config_entry: ConfigEntry,
95-
session: aiohttp.ClientSession,
84+
config_entry: HomeAssistantConnectZBT2ConfigEntry,
9685
async_add_entities: AddConfigEntryEntitiesCallback,
9786
) -> FirmwareUpdateEntity:
9887
"""Create an update entity that handles firmware type changes."""
@@ -111,12 +100,7 @@ def _async_create_update_entity(
111100
entity = FirmwareUpdateEntity(
112101
device=config_entry.data["device"],
113102
config_entry=config_entry,
114-
update_coordinator=FirmwareUpdateCoordinator(
115-
hass,
116-
config_entry,
117-
session,
118-
NABU_CASA_FIRMWARE_RELEASES_URL,
119-
),
103+
update_coordinator=config_entry.runtime_data.coordinator,
120104
entity_description=entity_description,
121105
)
122106

@@ -126,11 +110,7 @@ def firmware_type_changed(
126110
"""Replace the current entity when the firmware type changes."""
127111
er.async_get(hass).async_remove(entity.entity_id)
128112
async_add_entities(
129-
[
130-
_async_create_update_entity(
131-
hass, config_entry, session, async_add_entities
132-
)
133-
]
113+
[_async_create_update_entity(hass, config_entry, async_add_entities)]
134114
)
135115

136116
entity.async_on_remove(
@@ -142,14 +122,11 @@ def firmware_type_changed(
142122

143123
async def async_setup_entry(
144124
hass: HomeAssistant,
145-
config_entry: ConfigEntry,
125+
config_entry: HomeAssistantConnectZBT2ConfigEntry,
146126
async_add_entities: AddConfigEntryEntitiesCallback,
147127
) -> None:
148128
"""Set up the firmware update config entry."""
149-
session = async_get_clientsession(hass)
150-
entity = _async_create_update_entity(
151-
hass, config_entry, session, async_add_entities
152-
)
129+
entity = _async_create_update_entity(hass, config_entry, async_add_entities)
153130

154131
async_add_entities([entity])
155132

@@ -162,7 +139,7 @@ class FirmwareUpdateEntity(BaseFirmwareUpdateEntity):
162139
def __init__(
163140
self,
164141
device: str,
165-
config_entry: ConfigEntry,
142+
config_entry: HomeAssistantConnectZBT2ConfigEntry,
166143
update_coordinator: FirmwareUpdateCoordinator,
167144
entity_description: FirmwareUpdateEntityDescription,
168145
) -> None:

homeassistant/components/homeassistant_hardware/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,6 @@
88
"integration_type": "system",
99
"requirements": [
1010
"universal-silabs-flasher==0.0.35",
11-
"ha-silabs-firmware-client==0.2.0"
11+
"ha-silabs-firmware-client==0.3.0"
1212
]
1313
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
"""Home Assistant Hardware base beta firmware switch entity."""
2+
3+
from __future__ import annotations
4+
5+
import logging
6+
from typing import Any
7+
8+
from homeassistant.components.switch import SwitchEntity
9+
from homeassistant.config_entries import ConfigEntry
10+
from homeassistant.const import EntityCategory
11+
from homeassistant.helpers.restore_state import RestoreEntity
12+
13+
from .coordinator import FirmwareUpdateCoordinator
14+
15+
_LOGGER = logging.getLogger(__name__)
16+
17+
18+
class BaseBetaFirmwareSwitch(SwitchEntity, RestoreEntity):
19+
"""Base switch to enable beta firmware updates."""
20+
21+
_attr_has_entity_name = True
22+
_attr_entity_category = EntityCategory.CONFIG
23+
_attr_entity_registry_enabled_default = False
24+
_attr_translation_key = "beta_firmware"
25+
26+
def __init__(
27+
self,
28+
coordinator: FirmwareUpdateCoordinator,
29+
config_entry: ConfigEntry,
30+
) -> None:
31+
"""Initialize the beta firmware switch."""
32+
self._coordinator = coordinator
33+
self._config_entry = config_entry
34+
35+
async def async_added_to_hass(self) -> None:
36+
"""Handle entity which will be added to hass."""
37+
await super().async_added_to_hass()
38+
39+
# Restore the last state
40+
last_state = await self.async_get_last_state()
41+
if last_state is not None:
42+
self._attr_is_on = last_state.state == "on"
43+
else:
44+
self._attr_is_on = False
45+
46+
# Apply the restored state to the coordinator
47+
await self._update_coordinator_prerelease()
48+
49+
async def async_turn_on(self, **kwargs: Any) -> None:
50+
"""Turn on beta firmware updates."""
51+
self._attr_is_on = True
52+
self.async_write_ha_state()
53+
await self._update_coordinator_prerelease()
54+
55+
async def async_turn_off(self, **kwargs: Any) -> None:
56+
"""Turn off beta firmware updates."""
57+
self._attr_is_on = False
58+
self.async_write_ha_state()
59+
await self._update_coordinator_prerelease()
60+
61+
async def _update_coordinator_prerelease(self) -> None:
62+
"""Update the coordinator with the current prerelease setting."""
63+
self._coordinator.client.update_prerelease(bool(self._attr_is_on))
64+
await self._coordinator.async_refresh()

0 commit comments

Comments
 (0)