Skip to content

Commit 05843fb

Browse files
authored
Support Home Assistant 2024.8.3 or newer (#82)
Drop support for HA versions before 2024.8.3. Drop platform config support. Fix Broken help link on adding new integration #81.
1 parent d72ad0e commit 05843fb

File tree

12 files changed

+71
-91
lines changed

12 files changed

+71
-91
lines changed

README.md

Lines changed: 1 addition & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ After it has been downloaded you will need to restart Home Assistant.
7676

7777
### Versions
7878

79-
This custom integration supports HomeAssistant versions 2023.4.0 or newer.
79+
This custom integration supports HomeAssistant versions 2024.8.3 or newer.
8080

8181
## Services
8282

@@ -99,38 +99,5 @@ Key | Optional | Description
9999
`name` | yes | Name of the sensor. Default is `Illuminance`.
100100
`scan_interval` | yes | Update interval. Minimum is 30 seconds. Default is 5 minutes.
101101

102-
## Converting from `platform` configuration
103-
104-
In previous versions, configuration was done under `sensor`.
105-
This is now deprecated and will generate a warning at startup.
106-
It should be converted to the new `illuminance` format as described above.
107-
Or simply remove it and add the sensor(s) via the UI.
108-
109-
Here is an example of the old format:
110-
111-
```yaml
112-
sensor:
113-
- platform: illuminance
114-
entity_id: weather.home_forecast
115-
fallback: 5
116-
mode: normal
117-
name: Weather-Based Sun Illuminance
118-
scan_interval:
119-
minutes: 10
120-
```
121-
122-
This is the equivalent configuration in the new format:
123-
124-
```yaml
125-
illuminance:
126-
- unique_id: 1
127-
entity_id: weather.home_forecast
128-
fallback: 5
129-
mode: normal
130-
name: Weather-Based Sun Illuminance
131-
scan_interval:
132-
minutes: 10
133-
```
134-
135102
## Releases Before 2.1.0
136103
See https://github.com/pnbruckner/homeassistant-config/blob/master/docs/illuminance.md.

custom_components/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""Illuminance Sensor."""

custom_components/illuminance/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from homeassistant.helpers.typing import ConfigType
2323

2424
from .const import DOMAIN
25-
from .sensor import ILLUMINANCE_SCHEMA
25+
from .sensor import ILLUMINANCE_SCHEMA, LOC_ELEV
2626

2727
_ILLUMINANCE_SCHEMA = vol.Schema(
2828
ILLUMINANCE_SCHEMA
@@ -64,7 +64,7 @@ def get_loc_elev() -> None:
6464
"""
6565
loc, elv = get_astral_location(hass)
6666
loc.tzinfo # noqa: B018
67-
hass.data[DOMAIN] = loc, elv
67+
hass.data[LOC_ELEV] = loc, elv
6868

6969
await hass.async_add_executor_job(get_loc_elev)
7070

@@ -84,7 +84,7 @@ async def process_config(
8484
tasks.append(hass.config_entries.async_remove(entry.entry_id))
8585

8686
for conf in configs:
87-
tasks.append(
87+
tasks.append( # noqa: PERF401
8888
hass.config_entries.flow.async_init(
8989
DOMAIN, context={"source": SOURCE_IMPORT}, data=conf.copy()
9090
)

custom_components/illuminance/config_flow.py

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,9 @@
1010
from homeassistant.config_entries import (
1111
SOURCE_IMPORT,
1212
ConfigEntry,
13+
ConfigEntryBaseFlow,
1314
ConfigFlow,
15+
ConfigFlowResult,
1416
OptionsFlowWithConfigEntry,
1517
)
1618
from homeassistant.const import (
@@ -21,7 +23,6 @@
2123
CONF_UNIQUE_ID,
2224
)
2325
from homeassistant.core import callback
24-
from homeassistant.data_entry_flow import FlowHandler, FlowResult
2526
from homeassistant.helpers.selector import (
2627
EntitySelector,
2728
EntitySelectorConfig,
@@ -43,7 +44,7 @@
4344
from .sensor import MODES
4445

4546

46-
class IlluminanceFlow(FlowHandler):
47+
class IlluminanceFlow(ConfigEntryBaseFlow):
4748
"""Illuminance flow mixin."""
4849

4950
@property
@@ -53,7 +54,7 @@ def options(self) -> dict[str, Any]:
5354

5455
async def async_step_options(
5556
self, user_input: dict[str, Any] | None = None
56-
) -> FlowResult:
57+
) -> ConfigFlowResult:
5758
"""Get sensor options."""
5859
if user_input is not None:
5960
self.options.clear()
@@ -100,7 +101,9 @@ async def async_step_options(
100101
return self.async_show_form(step_id="options", data_schema=data_schema)
101102

102103
@abstractmethod
103-
async def async_step_done(self, _: dict[str, Any] | None = None) -> FlowResult:
104+
async def async_step_done(
105+
self, _: dict[str, Any] | None = None
106+
) -> ConfigFlowResult:
104107
"""Finish the flow."""
105108

106109

@@ -136,7 +139,7 @@ def options(self) -> dict[str, Any]:
136139
"""Return mutable copy of options."""
137140
return self._options
138141

139-
async def async_step_import(self, data: dict[str, Any]) -> FlowResult:
142+
async def async_step_import(self, data: dict[str, Any]) -> ConfigFlowResult:
140143
"""Import config entry from configuration."""
141144
title = data.pop(CONF_NAME)
142145
# Convert from timedelta to float in minutes.
@@ -151,13 +154,15 @@ async def async_step_import(self, data: dict[str, Any]) -> FlowResult:
151154

152155
return self.async_create_entry(title=title, data={}, options=data)
153156

154-
async def async_step_user(self, _: dict[str, Any] | None = None) -> FlowResult:
157+
async def async_step_user(
158+
self, _: dict[str, Any] | None = None
159+
) -> ConfigFlowResult:
155160
"""Start user config flow."""
156161
return await self.async_step_name()
157162

158163
async def async_step_name(
159164
self, user_input: dict[str, Any] | None = None
160-
) -> FlowResult:
165+
) -> ConfigFlowResult:
161166
"""Get name."""
162167
if user_input is not None:
163168
self._name = user_input[CONF_NAME]
@@ -168,14 +173,18 @@ async def async_step_name(
168173
step_id="name", data_schema=vol.Schema(schema), last_step=False
169174
)
170175

171-
async def async_step_done(self, _: dict[str, Any] | None = None) -> FlowResult:
176+
async def async_step_done(
177+
self, _: dict[str, Any] | None = None
178+
) -> ConfigFlowResult:
172179
"""Finish the flow."""
173180
return self.async_create_entry(title=self._name, data={}, options=self.options)
174181

175182

176183
class IlluminanceOptionsFlow(OptionsFlowWithConfigEntry, IlluminanceFlow):
177184
"""Sun2 integration options flow."""
178185

179-
async def async_step_done(self, _: dict[str, Any] | None = None) -> FlowResult:
186+
async def async_step_done(
187+
self, _: dict[str, Any] | None = None
188+
) -> ConfigFlowResult:
180189
"""Finish the flow."""
181190
return self.async_create_entry(title="", data=self.options or {})

custom_components/illuminance/manifest.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44
"codeowners": ["@pnbruckner"],
55
"config_flow": true,
66
"dependencies": [],
7-
"documentation": "https://github.com/pnbruckner/ha-illuminance/5.6.1/master/README.md",
7+
"documentation": "https://github.com/pnbruckner/ha-illuminance/blob/5.7.0b0/README.md",
88
"iot_class": "calculated",
99
"issue_tracker": "https://github.com/pnbruckner/ha-illuminance/issues",
1010
"requirements": [],
11-
"version": "5.6.1"
11+
"version": "5.7.0b0"
1212
}

custom_components/illuminance/sensor.py

Lines changed: 20 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from dataclasses import dataclass
1010
from datetime import date, datetime, timedelta
1111
from enum import Enum, IntEnum, auto
12-
from functools import cached_property
12+
from functools import cached_property # pylint: disable=hass-deprecated-import
1313
import logging
1414
from math import asin, cos, exp, radians, sin
1515
import re
@@ -20,8 +20,7 @@
2020
import voluptuous as vol
2121

2222
from homeassistant.components.sensor import (
23-
DOMAIN as SENSOR_DOMAIN,
24-
PLATFORM_SCHEMA,
23+
PLATFORM_SCHEMA as SENSOR_PLATFORM_SCHEMA,
2524
SensorDeviceClass,
2625
SensorEntity,
2726
SensorEntityDescription,
@@ -50,28 +49,27 @@
5049
CONF_ENTITY_ID,
5150
CONF_MODE,
5251
CONF_NAME,
53-
CONF_PLATFORM,
5452
CONF_SCAN_INTERVAL,
5553
LIGHT_LUX,
5654
STATE_UNAVAILABLE,
5755
STATE_UNKNOWN,
5856
UnitOfIrradiance,
5957
)
60-
from homeassistant.core import Event, HomeAssistant, State, callback
58+
from homeassistant.core import (
59+
Event,
60+
EventStateChangedData,
61+
HomeAssistant,
62+
State,
63+
callback,
64+
)
6165
import homeassistant.helpers.config_validation as cv
62-
from homeassistant.helpers.device_registry import DeviceEntryType
63-
64-
# Device Info moved to device_registry in 2023.9
65-
try:
66-
from homeassistant.helpers.device_registry import DeviceInfo
67-
except ImportError:
68-
from homeassistant.helpers.entity import DeviceInfo # type: ignore[attr-defined]
69-
66+
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
7067
from homeassistant.helpers.entity import Entity
7168
from homeassistant.helpers.entity_platform import AddEntitiesCallback, EntityPlatform
7269
from homeassistant.helpers.event import async_track_state_change_event
73-
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
70+
from homeassistant.helpers.typing import ConfigType
7471
import homeassistant.util.dt as dt_util
72+
from homeassistant.util.hass_dict import HassKey
7573

7674
from .const import (
7775
CONF_FALLBACK,
@@ -124,6 +122,8 @@
124122

125123
ADDITIONAL_MAPPINGS = ((AW_PATTERN, AW_MAPPING), (ECOBEE_PATTERN, ECOBEE_MAPPING))
126124

125+
LOC_ELEV: HassKey[tuple[Location, Elevation]] = HassKey(DOMAIN)
126+
127127
_LOGGER = logging.getLogger(__name__)
128128

129129

@@ -146,7 +146,7 @@ class Mode(Enum):
146146
vol.Optional(CONF_MODE, default=MODES[0]): vol.In(MODES),
147147
vol.Optional(CONF_FALLBACK): vol.All(vol.Coerce(float), vol.Range(1, 10)),
148148
}
149-
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(ILLUMINANCE_SCHEMA)
149+
PLATFORM_SCHEMA = SENSOR_PLATFORM_SCHEMA.extend(ILLUMINANCE_SCHEMA)
150150

151151
_20_MIN = timedelta(minutes=20)
152152
_40_MIN = timedelta(minutes=40)
@@ -165,19 +165,15 @@ class IlluminanceSensorEntityDescription(SensorEntityDescription): # type: igno
165165
scan_interval: timedelta | None = None
166166

167167

168-
def _sensor(
169-
config: ConfigType,
170-
unique_id: str | None = None,
171-
scan_interval: timedelta | None = None,
172-
) -> Entity:
168+
def _sensor(config: ConfigType, unique_id: str, scan_interval: timedelta) -> Entity:
173169
"""Create entity to add."""
174170
weather_entity = config.get(CONF_ENTITY_ID)
175171
fallback = cast(
176172
float, config.get(CONF_FALLBACK, DEFAULT_FALLBACK if weather_entity else 1)
177173
)
178174
if (mode := Mode.__getitem__(cast(str, config[CONF_MODE]))) is Mode.irradiance:
179175
device_class = SensorDeviceClass.IRRADIANCE
180-
native_unit_of_measurement = UnitOfIrradiance.WATTS_PER_SQUARE_METER
176+
native_unit_of_measurement: str = UnitOfIrradiance.WATTS_PER_SQUARE_METER
181177
suggested_display_precision = 1
182178
else:
183179
device_class = SensorDeviceClass.ILLUMINANCE
@@ -200,24 +196,6 @@ def _sensor(
200196
return IlluminanceSensor(entity_description)
201197

202198

203-
async def async_setup_platform(
204-
hass: HomeAssistant,
205-
config: ConfigType,
206-
async_add_entities: AddEntitiesCallback,
207-
discovery_info: DiscoveryInfoType | None = None,
208-
) -> None:
209-
"""Set up sensors."""
210-
_LOGGER.warning(
211-
"%s: %s under %s is deprecated. Move to %s:",
212-
CONF_PLATFORM,
213-
DOMAIN,
214-
SENSOR_DOMAIN,
215-
DOMAIN,
216-
)
217-
218-
async_add_entities([_sensor(config)], True)
219-
220-
221199
async def async_setup_entry(
222200
hass: HomeAssistant,
223201
entry: ConfigEntry,
@@ -264,7 +242,7 @@ class IlluminanceSensor(SensorEntity):
264242
_attr_device_info = DeviceInfo(
265243
entry_type=DeviceEntryType.SERVICE,
266244
identifiers={(DOMAIN, DOMAIN)},
267-
name=DOMAIN.title(),
245+
translation_key="service",
268246
)
269247
_entity_status = EntityStatus.NOT_SEEN
270248
_sk_mapping: Sequence[tuple[Num, Sequence[str]]] | None = None
@@ -321,7 +299,7 @@ def add_to_platform_start(
321299
return
322300

323301
@callback
324-
def sensor_state_listener(event: Event) -> None:
302+
def sensor_state_listener(event: Event[EventStateChangedData]) -> None:
325303
"""Process input entity state update."""
326304
new_state: State | None = event.data["new_state"]
327305
old_state: State | None = event.data["old_state"]
@@ -491,7 +469,7 @@ def _calculate_illuminance(self, now: datetime) -> Num:
491469

492470
def _astral_event(self, event: str, date_or_dt: date | datetime) -> Any:
493471
"""Get astral event."""
494-
loc, elev = cast(tuple[Location, Elevation], self.hass.data[DOMAIN])
472+
loc, elev = self.hass.data[LOC_ELEV]
495473
if event == "solar_elevation":
496474
return getattr(loc, event)(date_or_dt, observer_elevation=elev)
497475
return getattr(loc, event)(date_or_dt, local=False, observer_elevation=elev)

custom_components/illuminance/translations/en.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@
2020
}
2121
}
2222
},
23+
"device": {
24+
"service": {
25+
"name": "Illuminance"
26+
}
27+
},
2328
"options": {
2429
"step": {
2530
"options": {

custom_components/illuminance/translations/it.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@
1919
}
2020
}
2121
},
22+
"device": {
23+
"service": {
24+
"name": "Illuminazione"
25+
}
26+
},
2227
"options": {
2328
"step": {
2429
"options": {

custom_components/illuminance/translations/nl.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@
1919
}
2020
}
2121
},
22+
"device": {
23+
"service": {
24+
"name": "Verlichtingssterkte"
25+
}
26+
},
2227
"options": {
2328
"step": {
2429
"options": {

custom_components/illuminance/translations/pl.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@
1919
}
2020
}
2121
},
22+
"device": {
23+
"service": {
24+
"name": "Natężenie oświetlenia"
25+
}
26+
},
2227
"options": {
2328
"step": {
2429
"options": {

0 commit comments

Comments
 (0)