Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add config flow, service info & translations #96

Merged
merged 59 commits into from
Dec 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
12b6dd5
Config flow initial implementation
pnbruckner Nov 7, 2023
e08a0c1
black
pnbruckner Nov 7, 2023
9139fed
Incremental checkin
pnbruckner Nov 8, 2023
134ee7e
Move settings from config data to options
pnbruckner Nov 9, 2023
7552a4b
Add service via _attr_device_info
pnbruckner Nov 9, 2023
c0fa25b
Sort manifest.json
pnbruckner Nov 10, 2023
87c7088
Fix 2023.3 compatibility issue
pnbruckner Nov 10, 2023
c6e5a75
Use has_entity_name, sun2 config name is now location
pnbruckner Nov 11, 2023
75e1d1d
Update config entries per configuration
pnbruckner Nov 11, 2023
eb8fc15
First translation implementation
pnbruckner Nov 11, 2023
2fc9495
Add remaining translations
pnbruckner Nov 11, 2023
ab1d6d1
Simplify config entry updating
pnbruckner Nov 12, 2023
5df731e
Remove simple entity types from sun2 config
pnbruckner Nov 12, 2023
5fe55ed
Add nl.json. Thanks metbril!
pnbruckner Nov 12, 2023
ce13b92
Update info.md
pnbruckner Nov 12, 2023
eac6d41
Update README.md
pnbruckner Nov 12, 2023
9bedd11
Bump version to 3.0.0b0 & point doc to branch
pnbruckner Nov 13, 2023
df1c623
Fix config bug when no sensors listed
pnbruckner Nov 13, 2023
d6ae933
Bump version to 3.0.0b1
pnbruckner Nov 13, 2023
28a6b0c
Fix core config update handling
pnbruckner Nov 13, 2023
643bf3e
Bump version to 3.0.0b2
pnbruckner Nov 13, 2023
927c165
Move processing of HA location config to __init__
pnbruckner Nov 14, 2023
6634116
Fix time_at_elevation when config removed from YAML
pnbruckner Nov 14, 2023
b94f47c
Bump version to 3.0.0b3
pnbruckner Nov 14, 2023
19a355c
Translations require HA 2023.4.0 or newer
pnbruckner Nov 14, 2023
9a3d5b3
Move translation lookup to __init__
pnbruckner Nov 15, 2023
f36bb6d
Move config validation to config.py
pnbruckner Nov 15, 2023
ed7cdef
More translations of default entity names
pnbruckner Nov 15, 2023
28c256e
Bump version to 3.0.0b4
pnbruckner Nov 15, 2023
16c9c29
More translations, including attribute names & states
pnbruckner Nov 16, 2023
e497d26
Add PACKAGE_MERGE_HINT
pnbruckner Nov 16, 2023
e3fa933
Add _unreported_attributes
pnbruckner Nov 16, 2023
29e3c63
Make elevation binary sensor config similar to others
pnbruckner Nov 16, 2023
5234667
Add required unique_id for non-simple entity configs
pnbruckner Nov 17, 2023
d176d55
Better handle core config update
pnbruckner Nov 17, 2023
78fa138
Update README.md
pnbruckner Nov 17, 2023
de8e247
Bump version to 3.0.0b5
pnbruckner Nov 17, 2023
5cab09a
Add reload service
pnbruckner Nov 17, 2023
3fcd761
Update README.md
pnbruckner Nov 18, 2023
1628439
Bump version to 3.0.0b6
pnbruckner Nov 18, 2023
82572d2
Use placeholders in misc translations
pnbruckner Nov 18, 2023
7143890
Bump version to 3.0.0b7
pnbruckner Nov 18, 2023
75d6c5d
Add sun2 integration via UI
pnbruckner Nov 21, 2023
34b775f
Add non-simple sensors via UI
pnbruckner Nov 28, 2023
87aa5f7
Update info.md
pnbruckner Nov 28, 2023
fb9bd2c
Update README.md
pnbruckner Nov 29, 2023
94210d7
Move misc translations to satisfy hassfest
pnbruckner Nov 29, 2023
6dce3d6
Update names of additional entities when language is changed
pnbruckner Dec 1, 2023
1c21156
Update README.md
pnbruckner Dec 1, 2023
4c590f7
Bump version to 3.0.0b9
pnbruckner Dec 1, 2023
3902be5
Miscellaneous improvements
pnbruckner Dec 4, 2023
30ee800
ruff, pylint, black & mypy
pnbruckner Dec 5, 2023
4341508
Fix bug with use of abstractmethod & property decorators.
pnbruckner Dec 6, 2023
2980839
Fix bug in hours_to_hms introduced in previous commit
pnbruckner Dec 7, 2023
5a4323f
Use only new style selectors
pnbruckner Dec 8, 2023
ff14d49
Simplify unique IDs for UI added additional sensors
pnbruckner Dec 8, 2023
a30b1be
Add option to remove additional entities
pnbruckner Dec 9, 2023
11ab5c2
Bump version to 3.0.0b10
pnbruckner Dec 9, 2023
b0cd85b
Fix _unrecorded_attributes
pnbruckner Dec 11, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
388 changes: 230 additions & 158 deletions README.md

Large diffs are not rendered by default.

163 changes: 163 additions & 0 deletions custom_components/sun2/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1,164 @@
"""Sun2 integration."""
from __future__ import annotations

import asyncio
from collections.abc import Coroutine
import re
from typing import Any, cast

from astral import SunDirection

from homeassistant.config_entries import SOURCE_IMPORT, ConfigEntry
from homeassistant.const import (
CONF_BINARY_SENSORS,
CONF_LATITUDE,
CONF_SENSORS,
CONF_UNIQUE_ID,
EVENT_CORE_CONFIG_UPDATE,
SERVICE_RELOAD,
Platform,
)
from homeassistant.core import Event, HomeAssistant, ServiceCall
from homeassistant.helpers import entity_registry as er
from homeassistant.helpers.dispatcher import dispatcher_send
from homeassistant.helpers.reload import async_integration_yaml_config
from homeassistant.helpers.service import async_register_admin_service
from homeassistant.helpers.typing import ConfigType

from .const import CONF_DIRECTION, CONF_TIME_AT_ELEVATION, DOMAIN, SIG_HA_LOC_UPDATED
from .helpers import LocData, LocParams, Sun2Data

PLATFORMS = [Platform.BINARY_SENSOR, Platform.SENSOR]
_OLD_UNIQUE_ID = re.compile(r"[0-9a-f]{32}-([0-9a-f]{32})")
_UUID_UNIQUE_ID = re.compile(r"[0-9a-f]{32}")


async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up composite integration."""

def update_local_loc_data() -> LocData:
"""Update local location data from HA's config."""
cast(Sun2Data, hass.data[DOMAIN]).locations[None] = loc_data = LocData(
LocParams(
hass.config.elevation,
hass.config.latitude,
hass.config.longitude,
str(hass.config.time_zone),
)
)
return loc_data

async def process_config(
config: ConfigType | None, run_immediately: bool = True
) -> None:
"""Process sun2 config."""
if not config or not (configs := config.get(DOMAIN)):
configs = []
unique_ids = [config[CONF_UNIQUE_ID] for config in configs]
tasks: list[Coroutine[Any, Any, Any]] = []

for entry in hass.config_entries.async_entries(DOMAIN):
if entry.source != SOURCE_IMPORT:
continue
if entry.unique_id not in unique_ids:
tasks.append(hass.config_entries.async_remove(entry.entry_id))

for conf in configs:
tasks.append(
hass.config_entries.flow.async_init(
DOMAIN, context={"source": SOURCE_IMPORT}, data=conf.copy()
)
)

if not tasks:
return

if run_immediately:
await asyncio.gather(*tasks)
else:
for task in tasks:
hass.async_create_task(task)

async def reload_config(call: ServiceCall | None = None) -> None:
"""Reload configuration."""
await process_config(await async_integration_yaml_config(hass, DOMAIN))

async def handle_core_config_update(event: Event) -> None:
"""Handle core config update."""
if not event.data:
return

loc_data = update_local_loc_data()

if not any(key in event.data for key in ("location_name", "language")):
# Signal all instances that location data has changed.
dispatcher_send(hass, SIG_HA_LOC_UPDATED, loc_data)
return

await reload_config()
for entry in hass.config_entries.async_entries(DOMAIN):
if entry.source == SOURCE_IMPORT:
continue
if CONF_LATITUDE not in entry.options:
reload = not hass.config_entries.async_update_entry(
entry, title=hass.config.location_name
)
else:
reload = True
if reload:
await hass.config_entries.async_reload(entry.entry_id)

update_local_loc_data()
await process_config(config, run_immediately=False)
async_register_admin_service(hass, DOMAIN, SERVICE_RELOAD, reload_config)
hass.bus.async_listen(EVENT_CORE_CONFIG_UPDATE, handle_core_config_update)

return True


async def entry_updated(hass: HomeAssistant, entry: ConfigEntry) -> None:
"""Handle config entry update."""
# Remove entity registry entries for additional sensors that were deleted.
unqiue_ids = [
sensor[CONF_UNIQUE_ID]
for sensor_type in (CONF_BINARY_SENSORS, CONF_SENSORS)
for sensor in entry.options.get(sensor_type, [])
]
ent_reg = er.async_get(hass)
for entity in er.async_entries_for_config_entry(ent_reg, entry.entry_id):
unique_id = entity.unique_id
# Only sensors that were added via the UI have UUID type unique IDs.
if _UUID_UNIQUE_ID.fullmatch(unique_id) and unique_id not in unqiue_ids:
ent_reg.async_remove(entity.entity_id)
await hass.config_entries.async_reload(entry.entry_id)


async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up config entry."""
# From 3.0.0b8 or older: Convert config direction from -1, 1 -> "setting", "rising"
options = dict(entry.options)
for sensor in options.get(CONF_SENSORS, []):
if CONF_TIME_AT_ELEVATION not in sensor:
continue
if isinstance(direction := sensor[CONF_DIRECTION], str):
continue
sensor[CONF_DIRECTION] = SunDirection(direction).name.lower()
if options != entry.options:
hass.config_entries.async_update_entry(entry, options=options)

# From 3.0.0b9 or older: Convert unique_id from entry.entry_id-unique_id -> unique_id
ent_reg = er.async_get(hass)
for entity in ent_reg.entities.values():
if entity.platform != DOMAIN:
continue
if m := _OLD_UNIQUE_ID.fullmatch(entity.unique_id):
ent_reg.async_update_entity(entity.entity_id, new_unique_id=m.group(1))

entry.async_on_unload(entry.add_update_listener(entry_updated))
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
return True


async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload a config entry."""
return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
Loading