Skip to content

Commit a05a0cc

Browse files
authored
Merge pull request #65 from laszlojakab/develop
feat: create release 0.5.5
2 parents 1eb4ffc + 8685982 commit a05a0cc

File tree

9 files changed

+117
-121
lines changed

9 files changed

+117
-121
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
![GitHub release (latest by date)](https://img.shields.io/github/v/release/laszlojakab/homeassistant-easycontrols)
55
![GitHub](https://img.shields.io/github/license/laszlojakab/homeassistant-easycontrols)
66
![GitHub all releases](https://img.shields.io/github/downloads/laszlojakab/homeassistant-easycontrols/total)
7+
[![HA integration usage](https://img.shields.io/badge/dynamic/json?color=41BDF5&logo=home-assistant&label=integration%20usage&suffix=%20installs&cacheSeconds=15600&url=https://analytics.home-assistant.io/custom_integrations.json&query=$.easycontrols.total)](https://analytics.home-assistant.io/custom_integrations.json)
78
[![Donate](https://img.shields.io/badge/donate-Coffee-yellow.svg)](https://www.buymeacoffee.com/laszlojakab)
89

910
Helios EasyControls Modbus TCP/IP integration for [Home Assistant](https://www.home-assistant.io/)

custom_components/easycontrols/__init__.py

+13-9
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from homeassistant.helpers.typing import ConfigType, HomeAssistantType
77

88
from .const import DATA_CONTROLLER, DOMAIN
9-
from .threadsafe_controller import ThreadSafeController
9+
from .controller import Controller
1010

1111

1212
# pylint: disable=unused-argument
@@ -48,11 +48,15 @@ async def async_setup_entry(hass: HomeAssistantType, config_entry: ConfigEntry)
4848
'''
4949

5050
if not is_controller_exists(hass, config_entry.data[CONF_MAC]):
51-
set_controller(hass, ThreadSafeController(
51+
controller = Controller(
5252
config_entry.data[CONF_NAME],
5353
config_entry.data[CONF_HOST],
5454
config_entry.data[CONF_MAC]
55-
))
55+
)
56+
57+
await controller.init()
58+
59+
set_controller(hass, controller)
5660

5761
hass.async_create_task(
5862
hass.config_entries.async_forward_entry_setup(config_entry, 'fan')
@@ -68,13 +72,13 @@ async def async_setup_entry(hass: HomeAssistantType, config_entry: ConfigEntry)
6872
return True
6973

7074

71-
def get_device_info(controller: ThreadSafeController) -> DeviceInfo:
75+
def get_device_info(controller: Controller) -> DeviceInfo:
7276
'''
7377
Gets the device info based on the specified device name and the controller
7478
7579
Parameters
7680
----------
77-
controller: ThreadSafeController
81+
controller: Controller
7882
The thread safe Helios Easy Controls controller.
7983
'''
8084
return DeviceInfo(
@@ -109,13 +113,13 @@ def is_controller_exists(hass: HomeAssistantType, mac_address: str) -> bool:
109113
return mac_address in hass.data[DOMAIN][DATA_CONTROLLER]
110114

111115

112-
def set_controller(hass: HomeAssistantType, controller: ThreadSafeController) -> None:
116+
def set_controller(hass: HomeAssistantType, controller: Controller) -> None:
113117
'''
114118
Stores the specified controller in hass.data by its MAC address.
115119
116120
Parameters
117121
----------
118-
controller: ThreadSafeController
122+
controller: Controller
119123
The thread safe Helios Easy Controls instance.
120124
121125
Returns
@@ -125,7 +129,7 @@ def set_controller(hass: HomeAssistantType, controller: ThreadSafeController) ->
125129
hass.data[DOMAIN][DATA_CONTROLLER][controller.mac] = controller
126130

127131

128-
def get_controller(hass: HomeAssistantType, mac_address: str) -> ThreadSafeController:
132+
def get_controller(hass: HomeAssistantType, mac_address: str) -> Controller:
129133
'''
130134
Gets the controller for the given MAC address.
131135
@@ -136,7 +140,7 @@ def get_controller(hass: HomeAssistantType, mac_address: str) -> ThreadSafeContr
136140
137141
Returns
138142
-------
139-
ThreadSafeController
143+
Controller
140144
The thread safe controller associated to the given MAC address.
141145
'''
142146
return hass.data[DOMAIN][DATA_CONTROLLER][mac_address]

custom_components/easycontrols/binary_sensor.py

+4-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
# pylint: disable=bad-continuation
21
'''
32
The binary sensor module for Helios Easy Controls integration.
43
'''
@@ -16,7 +15,7 @@
1615
from . import get_controller, get_device_info
1716
from .const import VARIABLE_BYPASS, VARIABLE_INFO_FILTER_CHANGE
1817
from .modbus_variable import BoolModbusVariable
19-
from .threadsafe_controller import ThreadSafeController
18+
from .controller import Controller
2019

2120
_LOGGER = logging.getLogger(__name__)
2221

@@ -28,7 +27,7 @@ class EasyControlBinarySensor(BinarySensorEntity):
2827

2928
def __init__(
3029
self,
31-
controller: ThreadSafeController,
30+
controller: Controller,
3231
variable: BoolModbusVariable,
3332
description: BinarySensorEntityDescription
3433
):
@@ -37,7 +36,7 @@ def __init__(
3736
3837
Parameters
3938
----------
40-
controller: ThreadSafeController
39+
controller: Controller
4140
The thread safe Helios Easy Controls controller.
4241
variable: BoolModbusVariable
4342
The Modbus variable.
@@ -53,7 +52,7 @@ async def async_update(self):
5352
'''
5453
Updates the sensor value.
5554
'''
56-
self._attr_is_on = self._controller.get_variable(self._variable)
55+
self._attr_is_on = await self._controller.get_variable(self._variable)
5756
self._attr_available = self._attr_is_on is not None
5857

5958
@property

custom_components/easycontrols/config_flow.py

+11-11
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
''' The configuration flow for Helios Easy Controls integration. '''
22
import logging
3-
from typing import Any, Dict
3+
from typing import Any, Union
44

55
import voluptuous as vol
6-
from eazyctrl import EazyController
6+
from eazyctrl import AsyncEazyController
77
from homeassistant import config_entries
88
from homeassistant.const import CONF_HOST, CONF_MAC, CONF_NAME
99
from homeassistant.data_entry_flow import FlowResult
@@ -20,7 +20,7 @@ class EasyControlsConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
2020
'''
2121
VERSION = 1
2222

23-
async def async_step_user(self, user_info: Dict[str, Any]) -> FlowResult:
23+
async def async_step_user(self, user_input: Union[dict[str, Any], None] = None) -> FlowResult:
2424
'''
2525
Handles the step when integration added from the UI.
2626
'''
@@ -29,16 +29,16 @@ async def async_step_user(self, user_info: Dict[str, Any]) -> FlowResult:
2929
vol.Required(CONF_NAME): str
3030
})
3131

32-
if user_info is not None:
33-
await self.async_set_unique_id(user_info[CONF_NAME])
32+
if user_input is not None:
33+
await self.async_set_unique_id(user_input[CONF_NAME])
3434
self._abort_if_unique_id_configured()
3535

3636
try:
37-
controller = EazyController(user_info[CONF_HOST])
38-
device_type = controller.get_variable(
37+
controller = AsyncEazyController(user_input[CONF_HOST])
38+
device_type = await controller.get_variable(
3939
VARIABLE_ARTICLE_DESCRIPTION.name, VARIABLE_ARTICLE_DESCRIPTION.size
4040
)
41-
mac_address = controller.get_variable(
41+
mac_address = await controller.get_variable(
4242
VARIABLE_MAC_ADDRESS.name, VARIABLE_MAC_ADDRESS.size
4343
)
4444
# pylint: disable=broad-except
@@ -52,13 +52,13 @@ async def async_step_user(self, user_info: Dict[str, Any]) -> FlowResult:
5252
)
5353

5454
data = {
55-
CONF_NAME: user_info[CONF_NAME],
56-
CONF_HOST: user_info[CONF_HOST],
55+
CONF_NAME: user_input[CONF_NAME],
56+
CONF_HOST: user_input[CONF_HOST],
5757
CONF_MAC: mac_address
5858
}
5959

6060
return self.async_create_entry(
61-
title=f'Helios {device_type} ({user_info[CONF_NAME]})', data=data
61+
title=f'Helios {device_type} ({user_input[CONF_NAME]})', data=data
6262
)
6363

6464
return self.async_show_form(
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,28 @@
1-
# pylint: disable=bad-continuation
21
'''
32
The module of Helios Easy Controls thread safe controller.
43
'''
54
import logging
65
import re
7-
import threading
6+
from asyncio import Lock
87
from typing import Any
98

10-
import eazyctrl
11-
from custom_components.easycontrols.modbus_variable import ModbusVariable
9+
from eazyctrl import AsyncEazyController
1210

1311
from .const import (VARIABLE_ARTICLE_DESCRIPTION, VARIABLE_SERIAL_NUMBER,
1412
VARIABLE_SOFTWARE_VERSION)
13+
from .modbus_variable import ModbusVariable
1514

1615
_LOGGER = logging.getLogger(__name__)
1716

1817

19-
class ThreadSafeController:
18+
class Controller:
2019
'''
2120
Represents a Helios Easy Controls controller.
22-
The get_variable and set_variables methods are thread safe.
23-
For more information please visit:
24-
https://github.com/baradi09/eazyctrl#notes-on-concurrent-access-conflicts
2521
'''
2622

2723
def __init__(self, device_name: str, host: str, mac: str):
2824
'''
29-
Initialize a new instance of ThreadSafeController class.
25+
Initialize a new instance of Controller class.
3026
3127
Parameters
3228
----------
@@ -39,14 +35,27 @@ def __init__(self, device_name: str, host: str, mac: str):
3935
'''
4036
self._host = host
4137
self._device_name = device_name
42-
self._eazyctrl = eazyctrl.EazyController(host)
43-
self._lock = threading.Lock()
38+
self._eazyctrl = AsyncEazyController(host)
39+
self._lock = Lock()
4440
self._mac = mac
4541
self._model = None
4642
self._version = None
4743
self._serial_number = None
4844
self._maximum_air_flow = None
4945

46+
async def init(self):
47+
'''
48+
Initialize device specific properties:
49+
- model
50+
- version
51+
- serial_number
52+
- maximum_air_flow
53+
'''
54+
self._model = await self.get_variable(VARIABLE_ARTICLE_DESCRIPTION)
55+
self._version = await self.get_variable(VARIABLE_SOFTWARE_VERSION)
56+
self._serial_number = await self.get_variable(VARIABLE_SERIAL_NUMBER)
57+
self._maximum_air_flow = float(re.findall(r'\d+', self._model)[0])
58+
5059
@property
5160
def device_name(self) -> str:
5261
'''
@@ -60,11 +69,6 @@ def maximum_air_flow(self) -> float:
6069
Gets the maximum airflow rate of the Helios device.
6170
The value is extracted from the model name.
6271
'''
63-
if self._maximum_air_flow is None:
64-
if self.model is None:
65-
return None
66-
67-
self._maximum_air_flow = float(re.findall(r'\d+', self.model)[0])
6872
return self._maximum_air_flow
6973

7074
@property
@@ -86,43 +90,23 @@ def model(self) -> str:
8690
'''
8791
Gets the model of Helios device.
8892
'''
89-
if self._model is None:
90-
try:
91-
self._model = self.get_variable(VARIABLE_ARTICLE_DESCRIPTION)
92-
# pylint: disable=broad-except
93-
except Exception as error:
94-
_LOGGER.error('Failed to get the model of Helios device: %s', error)
9593
return self._model
9694

9795
@property
9896
def version(self) -> str:
9997
'''
10098
Gets the software version of Helios device.
10199
'''
102-
if self._version is None:
103-
try:
104-
self._version = self.get_variable(VARIABLE_SOFTWARE_VERSION)
105-
# pylint: disable=broad-except
106-
except Exception as error:
107-
_LOGGER.error('Failed to get the software version of Helios device: %s', error)
108-
109100
return self._version
110101

111102
@property
112103
def serial_number(self) -> str:
113104
'''
114105
Gets the serial number of Helios device.
115106
'''
116-
if self._serial_number is None:
117-
try:
118-
self._serial_number = self.get_variable(VARIABLE_SERIAL_NUMBER)
119-
# pylint: disable=broad-except
120-
except Exception as error:
121-
_LOGGER.error('Failed to get the serial number of Helios device: %s', error)
122-
123107
return self._serial_number
124108

125-
def get_variable(
109+
async def get_variable(
126110
self,
127111
variable: ModbusVariable,
128112
) -> Any:
@@ -134,17 +118,17 @@ def get_variable(
134118
variable: ModbusVariable
135119
The variable to get.
136120
'''
137-
with self._lock:
121+
async with self._lock:
138122
_LOGGER.debug('Getting %s.', variable.name)
139-
value = self._eazyctrl.get_variable(
123+
value = await self._eazyctrl.get_variable(
140124
variable.name,
141125
variable.size,
142126
variable.get_converter
143127
)
144128
_LOGGER.debug('%s value: %s', variable.name, value)
145129
return value
146130

147-
def set_variable(
131+
async def set_variable(
148132
self,
149133
variable: ModbusVariable,
150134
value: Any
@@ -160,9 +144,10 @@ def set_variable(
160144
The value to set on Helios device.
161145
162146
Returns
147+
-------
163148
bool
164149
True if setting of variable succeeded otherwise False.
165150
'''
166-
with self._lock:
151+
async with self._lock:
167152
_LOGGER.debug('Setting %s to %s.', variable.name, value)
168-
return self._eazyctrl.set_variable(variable.name, value, variable.set_converter)
153+
return await self._eazyctrl.set_variable(variable.name, value, variable.set_converter)

0 commit comments

Comments
 (0)