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

Spring improvements #91

Merged
merged 4 commits into from
May 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
24 changes: 17 additions & 7 deletions .github/ISSUE_TEMPLATE/issue.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,30 @@ body:
validations:
required: true
attributes:
label: What version of this integration has the issue?
placeholder: 1.1.4
label: Integration version
placeholder: "2.4.0"
description: >
Can be found in the Configuration panel -> Info.
Can be found in the Configuration panel -> Integrations -> Kamstrup 403
- type: input
id: ha_version
validations:
required: true
attributes:
label: What version of Home Assistant Core has the issue?
placeholder: core-2021.12.3
label: Home Assistant version
placeholder: core-2023.4.0
description: >
Can be found in the Configuration panel -> Info.
Can be found in [![System info](https://my.home-assistant.io/badges/system_health.svg)](https://my.home-assistant.io/redirect/system_health/)
- type: input
id: py_version
validations:
required: true
attributes:
label: Python version
placeholder: "3.10"
description: >
Can be found in [![System info](https://my.home-assistant.io/badges/system_health.svg)](https://my.home-assistant.io/redirect/system_health/)
- type: markdown
attributes:
Expand All @@ -56,7 +66,7 @@ body:
id: logs
attributes:
label: Home Assistant log
description: Paste your full log here, [how to enable logs](../blob/main/README.md#collect-logs).
description: Paste your full log here, Please copy from your log file and not from the frontend, [how to enable logs](../blob/main/README.md#collect-logs)
render: shell

- type: textarea
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,9 @@ jobs:
python-version: "3.10"

- name: Install requirements
run: python3 -m pip install -r requirements_test.txt
run: |
python3 -m pip install -r requirements.txt
python3 -m pip install -r requirements_test.txt
- name: Run tests
run: |
Expand All @@ -50,6 +52,7 @@ jobs:
--durations=10 \
-n auto \
--cov custom_components.kamstrup_403 \
--cov-report=term \
--cov-report=xml \
-o console_output_style=count \
-p no:sugar \
Expand Down
8 changes: 4 additions & 4 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"version": "2.0.0",
"tasks": [
{
"label": "Run Home Assistant on port 9123",
"label": "Run Home Assistant on port 8123",
"type": "shell",
"command": "scripts/develop",
"problemMatcher": []
Expand All @@ -16,19 +16,19 @@
{
"label": "Run pytest",
"type": "shell",
"command": "pytest tests",
"command": "pytest",
"problemMatcher": []
},
{
"label": "Run pytest with coverage",
"type": "shell",
"command": "pytest --durations=10 --cov-report xml --cov=custom_components.kamstrup_403 tests",
"command": "pytest --cov-report term --cov-report xml --cov=custom_components.kamstrup_403",
"problemMatcher": []
},
{
"label": "Run black",
"type": "shell",
"command": "black . --check",
"command": "black .",
"problemMatcher": []
},
{
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ custom_components/kamstrup_403/translations/nl.json
custom_components/kamstrup_403/__init__.py
custom_components/kamstrup_403/config_flow.py
custom_components/kamstrup_403/const.py
custom_components/kamstrup_403/coordinator.py
custom_components/kamstrup_403/diagnostics.py
custom_components/kamstrup_403/manifest.json
custom_components/kamstrup_403/sensor.py
Expand Down
135 changes: 17 additions & 118 deletions custom_components/kamstrup_403/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,40 +6,36 @@
"""
from datetime import timedelta
import logging
from typing import Any, List

from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_PORT, CONF_SCAN_INTERVAL, CONF_TIMEOUT
from homeassistant.core import Config, HomeAssistant
from homeassistant.const import CONF_PORT, CONF_SCAN_INTERVAL, CONF_TIMEOUT, Platform
from homeassistant.core import HomeAssistant
from homeassistant.exceptions import ConfigEntryNotReady
from homeassistant.helpers.device_registry import DeviceEntryType
from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
import serial

from .const import (
DEFAULT_BAUDRATE,
DEFAULT_SCAN_INTERVAL,
DEFAULT_TIMEOUT,
DOMAIN,
NAME,
PLATFORMS,
VERSION,
)
from .pykamstrup.kamstrup import MULTIPLE_NBR_MAX, Kamstrup
from .coordinator import KamstrupUpdateCoordinator
from .pykamstrup.kamstrup import Kamstrup

_LOGGER: logging.Logger = logging.getLogger(__package__)


async def async_setup(_hass: HomeAssistant, _config: Config) -> bool:
"""Set up this integration using YAML is not supported."""
return True
PLATFORMS: list[Platform] = [
Platform.SENSOR,
]


async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up this integration using UI."""
if hass.data.get(DOMAIN) is None:
hass.data.setdefault(DOMAIN, {})
hass.data.setdefault(DOMAIN, {})

port = entry.data.get(CONF_PORT)
scan_interval_seconds = entry.options.get(CONF_SCAN_INTERVAL, DEFAULT_SCAN_INTERVAL)
Expand All @@ -53,9 +49,9 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
)

try:
client = Kamstrup(port, DEFAULT_BAUDRATE, timeout_seconds)
client = Kamstrup(port=port, baudrate=DEFAULT_BAUDRATE, timeout=timeout_seconds)
except Exception as exception:
_LOGGER.error("Can't establish a connection with %s", port)
_LOGGER.error("Can't establish a connection to %s", port)
raise ConfigEntryNotReady() from exception

device_info = DeviceInfo(
Expand All @@ -66,123 +62,26 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
model=VERSION,
)

coordinator = KamstrupUpdateCoordinator(
hass.data[DOMAIN][entry.entry_id] = coordinator = KamstrupUpdateCoordinator(
hass=hass, client=client, scan_interval=scan_interval, device_info=device_info
)

hass.data[DOMAIN][entry.entry_id] = coordinator

hass.data.setdefault(DOMAIN, {})[entry.entry_id] = coordinator

for platform in PLATFORMS:
if entry.options.get(platform, True):
await hass.async_add_job(
hass.config_entries.async_forward_entry_setup(entry, platform)
)

await coordinator.async_config_entry_first_refresh()

if not coordinator.last_update_success:
raise ConfigEntryNotReady
await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
entry.async_on_unload(entry.add_update_listener(async_reload_entry))

return True


async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Unload this config entry."""
unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
if unload_ok:
del hass.data[DOMAIN][entry.entry_id]
return unload_ok
"""Handle removal of an entry."""
if unloaded := await hass.config_entries.async_unload_platforms(entry, PLATFORMS):
hass.data[DOMAIN].pop(entry.entry_id)
return unloaded


async def async_reload_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
"""Reload config entry."""
await async_unload_entry(hass, entry)
await async_setup_entry(hass, entry)


class KamstrupUpdateCoordinator(DataUpdateCoordinator):
"""Class to manage fetching data from the Kamstrup serial reader."""

def __init__(
self,
hass: HomeAssistant,
client: Kamstrup,
scan_interval: int,
device_info: DeviceInfo,
) -> None:
"""Initialize."""
self.kamstrup = client
self.device_info = device_info

self._commands: List[int] = []

super().__init__(hass, _LOGGER, name=DOMAIN, update_interval=scan_interval)

def register_command(self, command: int) -> None:
"""Add a command to the commands list."""
_LOGGER.debug("Register command %s", command)
self._commands.append(command)

def unregister_command(self, command: int) -> None:
"""Remove a command from the commands list."""
_LOGGER.debug("Unregister command %s", command)
self._commands.remove(command)

@property
def commands(self) -> List[int]:
"""List of registered commands"""
return self._commands

async def _async_update_data(self) -> dict[int, Any]:
"""Update data via library."""
_LOGGER.debug("Start update")

data = {}
failed_counter = 0

# The amount of values that can request at once is limited, do it in chunks.
chunks: list[list[int]] = [
self._commands[i : i + MULTIPLE_NBR_MAX]
for i in range(0, len(self._commands), MULTIPLE_NBR_MAX)
]

for chunk in chunks:
_LOGGER.debug("Get values for %s", chunk)

try:
values = self.kamstrup.get_values(chunk)
except serial.SerialException as exception:
_LOGGER.error(
"Device disconnected or multiple access on port? \nException: %e",
exception,
)
except Exception as exception:
_LOGGER.error(
"Error reading multiple %s \nException: %s", chunk, exception
)
raise UpdateFailed() from exception

for command in chunk:
if command in values:
value, unit = values[command]
data[command] = {"value": value, "unit": unit}
_LOGGER.debug(
"New value for sensor %s, value: %s %s", command, value, unit
)

failed_counter += len(chunk) - len(values)

if failed_counter == len(data):
_LOGGER.error(
"Finished update, No readings from the meter. Please check the IR connection"
)
else:
_LOGGER.debug(
"Finished update, %s out of %s readings failed",
failed_counter,
len(data),
)

return data
Loading