-
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
38a0785
commit 8dcd3f8
Showing
18 changed files
with
1,332 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
# The contents of this file is based on https://github.com/home-assistant/core/blob/dev/pyproject.toml | ||
|
||
target-version = "py310" | ||
|
||
select = [ | ||
"B007", # Loop control variable {name} not used within loop body | ||
"B014", # Exception handler with duplicate exception | ||
"C", # complexity | ||
"D", # docstrings | ||
"E", # pycodestyle | ||
"F", # pyflakes/autoflake | ||
"ICN001", # import concentions; {name} should be imported as {asname} | ||
"PGH004", # Use specific rule codes when using noqa | ||
"PLC0414", # Useless import alias. Import alias does not rename original package. | ||
"SIM105", # Use contextlib.suppress({exception}) instead of try-except-pass | ||
"SIM117", # Merge with-statements that use the same scope | ||
"SIM118", # Use {key} in {dict} instead of {key} in {dict}.keys() | ||
"SIM201", # Use {left} != {right} instead of not {left} == {right} | ||
"SIM212", # Use {a} if {a} else {b} instead of {b} if not {a} else {a} | ||
"SIM300", # Yoda conditions. Use 'age == 42' instead of '42 == age'. | ||
"SIM401", # Use get from dict with default instead of an if block | ||
"T20", # flake8-print | ||
"TRY004", # Prefer TypeError exception for invalid type | ||
"RUF006", # Store a reference to the return value of asyncio.create_task | ||
"UP", # pyupgrade | ||
"W", # pycodestyle | ||
] | ||
|
||
ignore = [ | ||
"D202", # No blank lines allowed after function docstring | ||
"D203", # 1 blank line required before class docstring | ||
"D213", # Multi-line docstring summary should start at the second line | ||
"D404", # First word of the docstring should not be This | ||
"D406", # Section name should end with a newline | ||
"D407", # Section name underlining | ||
"D411", # Missing blank line before section | ||
"E501", # line too long | ||
"E731", # do not assign a lambda expression, use a def | ||
] | ||
|
||
[flake8-pytest-style] | ||
fixture-parentheses = false | ||
|
||
[pyupgrade] | ||
keep-runtime-typing = true | ||
|
||
[mccabe] | ||
max-complexity = 40 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
v0.0.1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
"""Nexxtmove integration.""" | ||
from __future__ import annotations | ||
|
||
from homeassistant.config_entries import ConfigEntry | ||
from homeassistant.const import CONF_PASSWORD | ||
from homeassistant.const import CONF_USERNAME | ||
from homeassistant.core import HomeAssistant | ||
from homeassistant.helpers import device_registry as dr | ||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator | ||
from homeassistant.helpers.update_coordinator import UpdateFailed | ||
from requests.exceptions import ConnectionError | ||
|
||
from .client import NexxtmoveClient | ||
from .const import _LOGGER | ||
from .const import COORDINATOR_UPDATE_INTERVAL | ||
from .const import DOMAIN | ||
from .const import PLATFORMS | ||
from .exceptions import NexxtmoveException | ||
from .exceptions import NexxtmoveServiceException | ||
from .models import NexxtmoveItem | ||
from .utils import log_debug | ||
|
||
|
||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: | ||
"""Set up Nexxtmove from a config entry.""" | ||
hass.data.setdefault(DOMAIN, {}) | ||
|
||
client = NexxtmoveClient( | ||
username=entry.data[CONF_USERNAME], | ||
password=entry.data[CONF_PASSWORD], | ||
) | ||
|
||
dev_reg = dr.async_get(hass) | ||
hass.data[DOMAIN][entry.entry_id] = coordinator = NexxtmoveDataUpdateCoordinator( | ||
hass, | ||
config_entry_id=entry.entry_id, | ||
dev_reg=dev_reg, | ||
client=client, | ||
) | ||
|
||
await coordinator.async_config_entry_first_refresh() | ||
|
||
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.""" | ||
if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS): | ||
hass.data[DOMAIN].pop(entry.entry_id) | ||
|
||
return unload_ok | ||
|
||
|
||
class NexxtmoveDataUpdateCoordinator(DataUpdateCoordinator): | ||
"""Data update coordinator for Nexxtmove.""" | ||
|
||
data: list[NexxtmoveItem] | ||
config_entry: ConfigEntry | ||
|
||
def __init__( | ||
self, | ||
hass: HomeAssistant, | ||
config_entry_id: str, | ||
dev_reg: dr.DeviceRegistry, | ||
client: NexxtmoveClient, | ||
) -> None: | ||
"""Initialize coordinator.""" | ||
super().__init__( | ||
hass, | ||
_LOGGER, | ||
name=DOMAIN, | ||
update_interval=COORDINATOR_UPDATE_INTERVAL, | ||
) | ||
self._config_entry_id = config_entry_id | ||
self._device_registry = dev_reg | ||
self.client = client | ||
self.hass = hass | ||
|
||
async def _async_update_data(self) -> dict | None: | ||
"""Update data.""" | ||
try: | ||
items = await self.hass.async_add_executor_job( | ||
self.client.fetch_data | ||
) | ||
except ConnectionError as exception: | ||
raise UpdateFailed(f"ConnectionError {exception}") from exception | ||
except NexxtmoveServiceException as exception: | ||
raise UpdateFailed(f"NexxtmoveServiceException {exception}") from exception | ||
except NexxtmoveException as exception: | ||
raise UpdateFailed(f"NexxtmoveException {exception}") from exception | ||
except Exception as exception: | ||
raise UpdateFailed(f"Exception {exception}") from exception | ||
|
||
items: list[NexxtmoveItem] = items | ||
|
||
|
||
current_items = { | ||
list(device.identifiers)[0][1] | ||
for device in dr.async_entries_for_config_entry( | ||
self._device_registry, self._config_entry_id | ||
) | ||
} | ||
|
||
if len(items) > 0: | ||
fetched_items = { | ||
str(items[item].device_key) for item in items | ||
} | ||
log_debug( | ||
f"[init|NexxtmoveDataUpdateCoordinator|_async_update_data|fetched_items] {fetched_items}" | ||
) | ||
if stale_items := current_items - fetched_items: | ||
for device_key in stale_items: | ||
if device := self._device_registry.async_get_device( | ||
{(DOMAIN, device_key)} | ||
): | ||
log_debug( | ||
f"[init|NexxtmoveDataUpdateCoordinator|_async_update_data|async_remove_device] {device_key}", | ||
True, | ||
) | ||
self._device_registry.async_remove_device(device.id) | ||
|
||
# If there are new items, we should reload the config entry so we can | ||
# create new devices and entities. | ||
if self.data and fetched_items - { | ||
str(self.data[item].device_key) for item in self.data | ||
}: | ||
# log_debug(f"[init|NexxtmoveDataUpdateCoordinator|_async_update_data|async_reload] {product.product_name}") | ||
self.hass.async_create_task( | ||
self.hass.config_entries.async_reload(self._config_entry_id) | ||
) | ||
return None | ||
return items | ||
return [] |
Oops, something went wrong.