Skip to content

Commit f72e43e

Browse files
authored
Merge branch 'main' into config_flow_explicit_deprecated
2 parents 24e6eb2 + 76e26e8 commit f72e43e

26 files changed

+2046
-766
lines changed

.github/workflows/hacs.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,4 @@ jobs:
1515
- name: HACS validation
1616
uses: "hacs/action@main"
1717
with:
18-
category: "integration"
18+
category: "integration"

.pre-commit-config.yaml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Adapted from https://github.com/home-assistant/core/blob/dev/.pre-commit-config.yaml
2+
repos:
3+
- repo: https://github.com/astral-sh/ruff-pre-commit
4+
rev: v0.7.3
5+
hooks:
6+
- id: ruff
7+
args: [--fix, --select, I]
8+
- id: ruff-format
9+
files: ^((custom_components)/.+)?[^/]+\.(py|pyi)$
10+
- repo: https://github.com/codespell-project/codespell
11+
rev: v2.3.0
12+
hooks:
13+
- id: codespell
14+
args:
15+
- --ignore-words-list=astroid,checkin,currenty,hass,iif,incomfort,lookin,nam,NotIn
16+
- --skip="./.*,*.csv,*.json,*.ambr,*.md"
17+
- --quiet-level=2
18+
exclude_types: [csv, json, html, markdown]
19+
exclude: ^serialserver/|res/
20+
- repo: https://github.com/pre-commit/mirrors-prettier
21+
rev: v3.0.3
22+
hooks:
23+
- id: prettier
24+
- repo: local
25+
hooks:
26+
# Run mypy through our wrapper script in order to get the possible
27+
# pyenv and/or virtualenv activated; it may not have been e.g. if
28+
# committing from a GUI tool that was not launched from an activated
29+
# shell.
30+
- id: mypy
31+
name: mypy
32+
entry: mypy
33+
language: python
34+
types_or: [python, pyi]
35+
args:
36+
- --ignore-missing-imports
37+
require_serial: true
38+
files: ^(custom_components)/.+\.(py|pyi)$

README.md

Lines changed: 76 additions & 70 deletions
Large diffs are not rendered by default.

custom_components/linkytic/__init__.py

Lines changed: 79 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,25 @@
11
"""The linkytic integration."""
2+
23
from __future__ import annotations
34

5+
import asyncio
46
import logging
57

8+
from homeassistant.components import usb
69
from homeassistant.config_entries import ConfigEntry
710
from homeassistant.const import EVENT_HOMEASSISTANT_STOP, Platform
811
from homeassistant.core import HomeAssistant
12+
from homeassistant.exceptions import ConfigEntryNotReady
913

1014
from .const import (
1115
DOMAIN,
16+
LINKY_IO_ERRORS,
1217
OPTIONS_REALTIME,
18+
SETUP_PRODUCER,
1319
SETUP_SERIAL,
1420
SETUP_THREEPHASE,
15-
TICMODE_HISTORIC,
21+
SETUP_TICMODE,
22+
TICMODE_STANDARD,
1623
)
1724
from .serial_reader import LinkyTICReader
1825

@@ -24,14 +31,42 @@
2431
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
2532
"""Set up linkytic from a config entry."""
2633
# Create the serial reader thread and start it
27-
serial_reader = LinkyTICReader(
28-
title=entry.title,
29-
port=entry.data.get(SETUP_SERIAL),
30-
std_mode=entry.data.get(TICMODE_HISTORIC),
31-
three_phase=entry.data.get(SETUP_THREEPHASE),
32-
real_time=entry.options.get(OPTIONS_REALTIME),
33-
)
34-
serial_reader.start()
34+
port = entry.data.get(SETUP_SERIAL)
35+
try:
36+
serial_reader = LinkyTICReader(
37+
title=entry.title,
38+
port=port,
39+
std_mode=entry.data.get(SETUP_TICMODE) == TICMODE_STANDARD,
40+
producer_mode=entry.data.get(SETUP_PRODUCER),
41+
three_phase=entry.data.get(SETUP_THREEPHASE),
42+
real_time=entry.options.get(OPTIONS_REALTIME),
43+
)
44+
serial_reader.start()
45+
46+
async def read_serial_number(serial: LinkyTICReader):
47+
while serial.serial_number is None:
48+
await asyncio.sleep(1)
49+
# Check for any serial error that occurred in the serial thread context
50+
if serial.setup_error:
51+
raise serial.setup_error
52+
return serial.serial_number
53+
54+
s_n = await asyncio.wait_for(read_serial_number(serial_reader), timeout=5)
55+
# TODO: check if S/N is the one saved in config entry, if not this is a different meter!
56+
57+
# Error when opening serial port.
58+
except LINKY_IO_ERRORS as e:
59+
raise ConfigEntryNotReady(f"Couldn't open serial port {port}: {e}") from e
60+
61+
# Timeout waiting for S/N to be read.
62+
except TimeoutError as e:
63+
serial_reader.signalstop("linkytic_timeout")
64+
raise ConfigEntryNotReady(
65+
"Connected to serial port but coulnd't read serial number before timeout: check if TIC is connected and active."
66+
) from e
67+
68+
_LOGGER.info(f"Device connected with serial number: {s_n}")
69+
3570
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, serial_reader.signalstop)
3671
# Add options callback
3772
entry.async_on_unload(entry.add_update_listener(update_listener))
@@ -68,3 +103,38 @@ async def update_listener(hass: HomeAssistant, entry: ConfigEntry):
68103
return
69104
# Update its options
70105
serial_reader.update_options(entry.options.get(OPTIONS_REALTIME))
106+
107+
108+
async def async_migrate_entry(hass: HomeAssistant, config_entry: ConfigEntry):
109+
"""Migrate old entry."""
110+
_LOGGER.info(
111+
"Migrating from version %d.%d", config_entry.version, config_entry.minor_version
112+
)
113+
114+
if config_entry.version == 1:
115+
new = {**config_entry.data}
116+
117+
if config_entry.minor_version < 2:
118+
# Migrate to serial by-id.
119+
serial_by_id = await hass.async_add_executor_job(
120+
usb.get_serial_by_id, new[SETUP_SERIAL]
121+
)
122+
if serial_by_id == new[SETUP_SERIAL]:
123+
_LOGGER.warning(
124+
f"Couldn't find a persistent /dev/serial/by-id alias for {serial_by_id}. "
125+
"Problems might occur at startup if device names are not persistent."
126+
)
127+
else:
128+
new[SETUP_SERIAL] = serial_by_id
129+
130+
# config_entry.minor_version = 2
131+
hass.config_entries.async_update_entry(
132+
config_entry, data=new, minor_version=2, version=1
133+
) # type: ignore
134+
135+
_LOGGER.info(
136+
"Migration to version %d.%d successful",
137+
config_entry.version,
138+
config_entry.minor_version,
139+
)
140+
return True

0 commit comments

Comments
 (0)