-
Notifications
You must be signed in to change notification settings - Fork 3
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
Showing
25 changed files
with
1,358 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,8 @@ | ||
default_config: | ||
|
||
logger: | ||
default: info | ||
logs: | ||
custom_components.elro_connects: debug | ||
# If you need to debug uncomment the line below (doc: https://www.home-assistant.io/integrations/debugpy/) | ||
# debugpy: |
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,30 @@ | ||
// See https://aka.ms/vscode-remote/devcontainer.json for format details. | ||
{ | ||
"image": "ludeeus/container:integration-debian", | ||
"name": "Elro Connects development", | ||
"context": "..", | ||
"appPort": [ | ||
"9123:8123" | ||
], | ||
"postCreateCommand": "container install", | ||
"extensions": [ | ||
"ms-python.python", | ||
"github.vscode-pull-request-github", | ||
"ryanluker.vscode-coverage-gutters", | ||
"ms-python.vscode-pylance" | ||
], | ||
"settings": { | ||
"files.eol": "\n", | ||
"editor.tabSize": 4, | ||
"terminal.integrated.shell.linux": "/bin/bash", | ||
"python.pythonPath": "/usr/bin/python3", | ||
"python.analysis.autoSearchPaths": false, | ||
"python.linting.pylintEnabled": true, | ||
"python.linting.enabled": true, | ||
"python.formatting.provider": "black", | ||
"editor.formatOnPaste": false, | ||
"editor.formatOnSave": true, | ||
"editor.formatOnType": true, | ||
"files.trimTrailingWhitespace": true | ||
} | ||
} |
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,6 @@ | ||
__pycache__ | ||
pythonenv* | ||
venv | ||
.venv | ||
.coverage | ||
.idea |
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 |
---|---|---|
@@ -1,2 +1,64 @@ | ||
# ha-elro-connects | ||
Elro Connects for Home Assistant via HACS | ||
|
||
[![GitHub Release][releases-shield]][releases] | ||
[![GitHub Activity][commits-shield]][commits] | ||
[![License][license-shield]](LICENSE) | ||
|
||
[![hacs][hacsbadge]][hacs] | ||
![Project Maintenance][maintenance-shield] | ||
|
||
[![Community Forum][forum-shield]][forum] | ||
|
||
**This component will set up the following platforms.** | ||
|
||
Platform | Description | ||
-- | -- | ||
`siren` | Represents Elro Connects alarms as a siren. Turn the siren `ON` to test it. Turn it `OFF` to silence the (test) alarm. | ||
|
||
Other platforms (sensor e.g. sensor for battery level and signal strength are to be added later) | ||
|
||
## Installation | ||
|
||
1. Using the tool of choice open the directory (folder) for your HA configuration (where you find `configuration.yaml`). | ||
2. If you do not have a `custom_components` directory (folder) there, you need to create it. | ||
3. In the `custom_components` directory (folder) create a new folder called `elro_connects`. | ||
4. Download _all_ the files from the `custom_components/elro_connects/` directory (folder) in this repository. | ||
5. Place the files you downloaded in the new directory (folder) you created. | ||
6. Restart Home Assistant | ||
7. In the HA UI go to "Configuration" -> "Integrations" click "+" and search for "Elro Connects" | ||
|
||
Using your HA configuration directory (folder) as a starting point you should now also have something like this: | ||
|
||
```text | ||
custom_components/elro_connects/translations/en.json | ||
custom_components/elro_connects/translations/nl.json | ||
custom_components/elro_connects/__init__.py | ||
custom_components/elro_connects/api.py | ||
custom_components/elro_connects/siren.py | ||
custom_components/elro_connects/config_flow.py | ||
custom_components/elro_connects/const.py | ||
custom_components/elro_connects/manifest.json | ||
... | ||
``` | ||
|
||
## Configuration is done in the UI | ||
|
||
<!----> | ||
|
||
## Contributions are welcome | ||
|
||
If you want to contribute to this please read the [Contribution guidelines](CONTRIBUTING.md) | ||
|
||
*** | ||
|
||
[elro_connects]: https://github.com/jbouwh/ha-elro-connects | ||
[buymecoffeebadge]: https://img.shields.io/badge/buy%20me%20a%20coffee-donate-yellow.svg?style=for-the-badge | ||
[commits]: https://github.com/jbouwh/ha-elro-connects/commits/main | ||
[hacs]: https://github.com/custom-components/hacs | ||
[hacsbadge]: https://img.shields.io/badge/HACS-Custom-orange.svg?style=for-the-badge | ||
[forum-shield]: https://img.shields.io/badge/community-forum-brightgreen.svg?style=for-the-badge | ||
[forum]: https://community.home-assistant.io/ | ||
[license-shield]: https://img.shields.io/github/license/custom-components/blueprint.svg?style=for-the-badge | ||
[maintenance-shield]: https://img.shields.io/badge/maintainer-Joakim%20Sørensen%20%40ludeeus-blue.svg?style=for-the-badge | ||
[releases-shield]: https://img.shields.io/github/release/elro_connects/blueprint.svg?style=for-the-badge | ||
[releases]: https://github.com/jbouwh/ha-elro-connects/releases |
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,91 @@ | ||
"""The Elro Connects integration.""" | ||
from __future__ import annotations | ||
|
||
from datetime import timedelta | ||
import logging | ||
|
||
from elro.api import K1 | ||
|
||
from homeassistant.config_entries import ConfigEntry | ||
from homeassistant.const import CONF_HOST, CONF_PORT, SERVICE_RELOAD, Platform | ||
from homeassistant.core import HomeAssistant, ServiceCall | ||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed | ||
|
||
from .const import CONF_CONNECTOR_ID, DEFAULT_INTERVAL, DOMAIN | ||
from .device import ElroConnectsK1 | ||
|
||
_LOGGER = logging.getLogger(__name__) | ||
|
||
PLATFORMS: list[Platform] = [Platform.SIREN] | ||
|
||
|
||
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: | ||
"""Set up Elro Connects from a config entry.""" | ||
|
||
current_device_set: set | None = None | ||
|
||
async def _async_update_data() -> dict[int, dict]: | ||
"""Update data via API.""" | ||
nonlocal current_device_set | ||
try: | ||
await elro_connects_api.async_update() | ||
except K1.K1ConnectionError as err: | ||
raise UpdateFailed(err) from err | ||
new_set = set(elro_connects_api.data.keys()) | ||
if current_device_set is None: | ||
current_device_set = new_set | ||
if new_set - current_device_set: | ||
current_device_set = new_set | ||
# New devices discovered, trigger a reload | ||
await hass.services.async_call( | ||
DOMAIN, | ||
SERVICE_RELOAD, | ||
{}, | ||
blocking=False, | ||
) | ||
return elro_connects_api.data | ||
|
||
async def async_reload(call: ServiceCall) -> None: | ||
"""Reload the integration.""" | ||
await async_unload_entry(hass, entry) | ||
await async_setup_entry(hass, entry) | ||
|
||
coordinator = DataUpdateCoordinator( | ||
hass, | ||
_LOGGER, | ||
name=DOMAIN.title(), | ||
update_method=_async_update_data, | ||
update_interval=timedelta(seconds=DEFAULT_INTERVAL), | ||
) | ||
elro_connects_api = ElroConnectsK1( | ||
coordinator, | ||
entry.data[CONF_HOST], | ||
entry.data[CONF_CONNECTOR_ID], | ||
entry.data[CONF_PORT], | ||
) | ||
|
||
await coordinator.async_config_entry_first_refresh() | ||
|
||
hass.data[DOMAIN] = {} | ||
hass.data[DOMAIN][entry.entry_id] = elro_connects_api | ||
|
||
hass.config_entries.async_setup_platforms(entry, PLATFORMS) | ||
|
||
entry.async_on_unload( | ||
entry.add_update_listener(elro_connects_api.async_update_settings) | ||
) | ||
hass.helpers.service.async_register_admin_service( | ||
DOMAIN, SERVICE_RELOAD, async_reload | ||
) | ||
|
||
return True | ||
|
||
|
||
async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: | ||
"""Unload a config entry.""" | ||
elro_connects_api: ElroConnectsK1 = hass.data[DOMAIN][entry.entry_id] | ||
if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS): | ||
await elro_connects_api.async_disconnect() | ||
hass.data[DOMAIN].pop(entry.entry_id) | ||
|
||
return unload_ok |
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,145 @@ | ||
"""Config flow for Elro Connects integration.""" | ||
from __future__ import annotations | ||
|
||
import logging | ||
from typing import Any | ||
|
||
from elro.api import K1 | ||
import voluptuous as vol | ||
|
||
from homeassistant import config_entries | ||
from homeassistant.config_entries import ConfigEntry | ||
from homeassistant.const import CONF_HOST, CONF_PORT | ||
from homeassistant.core import HomeAssistant, callback | ||
from homeassistant.data_entry_flow import FlowResult | ||
from homeassistant.exceptions import HomeAssistantError | ||
import homeassistant.helpers.config_validation as cv | ||
|
||
from .const import CONF_CONNECTOR_ID, DEFAULT_PORT, DOMAIN | ||
|
||
_LOGGER = logging.getLogger(__name__) | ||
|
||
ELRO_CONNECTS_DATA_SCHEMA = vol.Schema( | ||
{ | ||
vol.Required(CONF_CONNECTOR_ID): str, | ||
vol.Required(CONF_HOST): str, | ||
vol.Required(CONF_PORT, default=DEFAULT_PORT): cv.port, | ||
} | ||
) | ||
|
||
|
||
class K1ConnectionTest: | ||
"""Elro Connects K1 connection test.""" | ||
|
||
def __init__(self, host: str) -> None: | ||
"""Initialize.""" | ||
self.host = host | ||
|
||
async def async_try_connection(self, connector_id: str, port: int) -> bool: | ||
"""Test if we can authenticate with the host.""" | ||
connector = K1(self.host, connector_id, port) | ||
try: | ||
await connector.async_connect() | ||
except K1.K1ConnectionError: | ||
return False | ||
finally: | ||
await connector.async_disconnect() | ||
return True | ||
|
||
|
||
async def async_validate_input( | ||
hass: HomeAssistant, data: dict[str, Any] | ||
) -> dict[str, Any]: | ||
"""Validate the user input allows us to connect.""" | ||
|
||
hub = K1ConnectionTest(data["host"]) | ||
|
||
if not await hub.async_try_connection(data["connector_id"], data["port"]): | ||
raise CannotConnect | ||
|
||
return {"title": "Elro Connects K1 Connector"} | ||
|
||
|
||
class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): | ||
"""Handle a config flow for Elro Connects.""" | ||
|
||
VERSION = 1 | ||
|
||
@staticmethod | ||
@callback | ||
def async_get_options_flow(config_entry): | ||
"""Handle configuring options.""" | ||
return OptionsFlowHandler(config_entry) | ||
|
||
async def async_step_user( | ||
self, user_input: dict[str, Any] | None = None | ||
) -> FlowResult: | ||
"""Handle the initial step.""" | ||
if user_input is None: | ||
return self.async_show_form( | ||
step_id="user", data_schema=ELRO_CONNECTS_DATA_SCHEMA | ||
) | ||
|
||
errors = {} | ||
|
||
try: | ||
info = await async_validate_input(self.hass, user_input) | ||
except CannotConnect: | ||
errors["base"] = "cannot_connect" | ||
except Exception: # pylint: disable=broad-except | ||
_LOGGER.exception("Unexpected exception") | ||
errors["base"] = "unknown" | ||
else: | ||
await self.async_set_unique_id(user_input[CONF_CONNECTOR_ID]) | ||
self._abort_if_unique_id_configured() | ||
return self.async_create_entry(title=info["title"], data=user_input) | ||
|
||
return self.async_show_form( | ||
step_id="user", data_schema=ELRO_CONNECTS_DATA_SCHEMA, errors=errors | ||
) | ||
|
||
|
||
class OptionsFlowHandler(config_entries.OptionsFlow): | ||
"""Manage the options.""" | ||
|
||
def __init__(self, config_entry: ConfigEntry) -> None: | ||
"""Initialize options flow.""" | ||
self.config_entry = config_entry | ||
|
||
async def async_step_init( | ||
self, user_input: dict[str, Any] | None = None | ||
) -> FlowResult: | ||
"""Manage configuration options.""" | ||
errors = {} | ||
entry_data = self.config_entry.data | ||
if user_input is not None: | ||
changed_input = {} | ||
changed_input.update(user_input) | ||
changed_input[CONF_CONNECTOR_ID] = entry_data.get(CONF_CONNECTOR_ID) | ||
try: | ||
await async_validate_input(self.hass, changed_input) | ||
except CannotConnect: | ||
errors["base"] = "cannot_connect" | ||
except Exception: # pylint: disable=broad-except | ||
_LOGGER.exception("Unexpected exception") | ||
errors["base"] = "unknown" | ||
else: | ||
self.hass.config_entries.async_update_entry( | ||
self.config_entry, data=changed_input | ||
) | ||
return self.async_create_entry(title="", data=user_input) | ||
|
||
return self.async_show_form( | ||
step_id="init", | ||
errors=errors, | ||
data_schema=vol.Schema( | ||
{ | ||
vol.Required(CONF_HOST, default=entry_data.get(CONF_HOST)): str, | ||
vol.Required(CONF_PORT, default=entry_data.get(CONF_PORT)): cv.port, | ||
} | ||
), | ||
) | ||
|
||
|
||
class CannotConnect(HomeAssistantError): | ||
"""Error to indicate we cannot connect.""" |
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,8 @@ | ||
"""Constants for the Elro Connects integration.""" | ||
|
||
DOMAIN = "elro_connects" | ||
|
||
DEFAULT_INTERVAL = 15 | ||
DEFAULT_PORT = 1025 | ||
|
||
CONF_CONNECTOR_ID = "connector_id" |
Oops, something went wrong.