mirror of
https://github.com/andvikt/mega_hacs.git
synced 2025-12-12 01:24:29 +05:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
149d30e921 | ||
|
|
84f677656a | ||
|
|
a0900052dc | ||
|
|
b8d355f412 | ||
|
|
d3f76a88df | ||
|
|
fa2bb2674e | ||
|
|
a1ae4e294b | ||
|
|
81d85ba1ed | ||
|
|
7135bb273e | ||
|
|
7d8554a7aa | ||
|
|
40dcadc109 | ||
|
|
35f99877ca | ||
|
|
6c50b81bff | ||
|
|
c810693ba5 | ||
|
|
1fd321d4c1 | ||
|
|
6732e1b7a2 |
122
.experiment.py
122
.experiment.py
@@ -1,121 +1,3 @@
|
|||||||
from urllib.parse import urlparse, parse_qsl
|
import struct
|
||||||
|
|
||||||
from bs4 import BeautifulSoup
|
print(struct.unpack('!f', bytes.fromhex('435c028f'))[0])
|
||||||
|
|
||||||
page = '''
|
|
||||||
<html><head></head><body><a href="/sec/?pt=33">Back</a><br>0x15 - <a href="/sec/?pt=33&scl=32&i2c_dev=t67xx">T67XX</a><br>0x40 - <a href="/sec/?pt=33&scl=32&i2c_dev=htu21d">HTU21D</a>/PCA9685/HM3301<br>0x4a - <a href="/sec/?pt=33&scl=32&i2c_dev=max44009">MAX44009</a><br>
|
|
||||||
</body></html>
|
|
||||||
'''
|
|
||||||
|
|
||||||
from urllib.parse import parse_qsl, urlparse
|
|
||||||
|
|
||||||
from bs4 import BeautifulSoup
|
|
||||||
|
|
||||||
from homeassistant.const import (
|
|
||||||
DEVICE_CLASS_HUMIDITY,
|
|
||||||
DEVICE_CLASS_TEMPERATURE,
|
|
||||||
DEVICE_CLASS_ILLUMINANCE,
|
|
||||||
DEVICE_CLASS_PRESSURE,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_scan_page(page: str):
|
|
||||||
ret = []
|
|
||||||
req = []
|
|
||||||
page = BeautifulSoup(page, features="lxml")
|
|
||||||
for x in page.find_all('a'):
|
|
||||||
params = x.get('href')
|
|
||||||
if params is None:
|
|
||||||
continue
|
|
||||||
params = dict(parse_qsl(urlparse(params).query))
|
|
||||||
if 'i2c_dev' in params:
|
|
||||||
dev = params['i2c_dev']
|
|
||||||
classes = i2c_classes.get(dev, [])
|
|
||||||
for i, c in enumerate(classes):
|
|
||||||
if c is Skip:
|
|
||||||
continue
|
|
||||||
elif c is Request:
|
|
||||||
req.append(params)
|
|
||||||
continue
|
|
||||||
elif isinstance(c, tuple):
|
|
||||||
suffix, c = c
|
|
||||||
elif isinstance(c, str):
|
|
||||||
suffix = c
|
|
||||||
else:
|
|
||||||
suffix = ''
|
|
||||||
if 'addr' in params:
|
|
||||||
suffix += f"_{params['addr']}" if suffix else str(params['addr'])
|
|
||||||
if suffix:
|
|
||||||
_dev = f'{dev}_{suffix}'
|
|
||||||
else:
|
|
||||||
_dev = dev
|
|
||||||
params = params.copy()
|
|
||||||
if i > 0:
|
|
||||||
params['i2c_par'] = i
|
|
||||||
ret.append({
|
|
||||||
'id_suffix': _dev,
|
|
||||||
'device_class': c,
|
|
||||||
'params': params,
|
|
||||||
})
|
|
||||||
req.append(params)
|
|
||||||
return req, ret
|
|
||||||
|
|
||||||
|
|
||||||
class Skip:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class Request:
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
i2c_classes = {
|
|
||||||
'htu21d': [
|
|
||||||
DEVICE_CLASS_HUMIDITY,
|
|
||||||
DEVICE_CLASS_TEMPERATURE,
|
|
||||||
],
|
|
||||||
'sht31': [
|
|
||||||
DEVICE_CLASS_HUMIDITY,
|
|
||||||
DEVICE_CLASS_TEMPERATURE,
|
|
||||||
],
|
|
||||||
'max44009': [
|
|
||||||
DEVICE_CLASS_ILLUMINANCE
|
|
||||||
],
|
|
||||||
'bh1750': [
|
|
||||||
DEVICE_CLASS_ILLUMINANCE
|
|
||||||
],
|
|
||||||
'tsl2591': [
|
|
||||||
DEVICE_CLASS_ILLUMINANCE
|
|
||||||
],
|
|
||||||
'bmp180': [
|
|
||||||
DEVICE_CLASS_PRESSURE,
|
|
||||||
DEVICE_CLASS_TEMPERATURE,
|
|
||||||
],
|
|
||||||
'bmx280': [
|
|
||||||
DEVICE_CLASS_PRESSURE,
|
|
||||||
DEVICE_CLASS_TEMPERATURE,
|
|
||||||
DEVICE_CLASS_HUMIDITY
|
|
||||||
],
|
|
||||||
'mlx90614': [
|
|
||||||
Skip,
|
|
||||||
('temp', DEVICE_CLASS_TEMPERATURE),
|
|
||||||
('object', DEVICE_CLASS_TEMPERATURE),
|
|
||||||
],
|
|
||||||
'ptsensor': [
|
|
||||||
Request, # запрос на измерение
|
|
||||||
DEVICE_CLASS_PRESSURE,
|
|
||||||
DEVICE_CLASS_TEMPERATURE,
|
|
||||||
],
|
|
||||||
'mcp9600': [
|
|
||||||
DEVICE_CLASS_TEMPERATURE, # термопара
|
|
||||||
DEVICE_CLASS_TEMPERATURE, # сенсор встроенный в микросхему
|
|
||||||
],
|
|
||||||
't67xx': [
|
|
||||||
None # для co2 нет класса в HA
|
|
||||||
],
|
|
||||||
'tmp117': [
|
|
||||||
DEVICE_CLASS_TEMPERATURE,
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
print(parse_scan_page(page))
|
|
||||||
@@ -16,7 +16,7 @@ from homeassistant.components import mqtt
|
|||||||
from homeassistant.config_entries import ConfigEntry
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from .const import DOMAIN, CONF_INVERT, CONF_RELOAD, PLATFORMS, CONF_PORTS, CONF_CUSTOM, CONF_SKIP, CONF_PORT_TO_SCAN, \
|
from .const import DOMAIN, CONF_INVERT, CONF_RELOAD, PLATFORMS, CONF_PORTS, CONF_CUSTOM, CONF_SKIP, CONF_PORT_TO_SCAN, \
|
||||||
CONF_MQTT_INPUTS, CONF_HTTP, CONF_RESPONSE_TEMPLATE, CONF_ACTION, CONF_GET_VALUE, CONF_ALLOW_HOSTS, \
|
CONF_MQTT_INPUTS, CONF_HTTP, CONF_RESPONSE_TEMPLATE, CONF_ACTION, CONF_GET_VALUE, CONF_ALLOW_HOSTS, \
|
||||||
CONF_CONV_TEMPLATE, CONF_ALL, CONF_FORCE_D, CONF_DEF_RESPONSE
|
CONF_CONV_TEMPLATE, CONF_ALL, CONF_FORCE_D, CONF_DEF_RESPONSE, CONF_FORCE_I2C_SCAN, CONF_HEX_TO_FLOAT
|
||||||
from .hub import MegaD
|
from .hub import MegaD
|
||||||
from .config_flow import ConfigFlow
|
from .config_flow import ConfigFlow
|
||||||
from .http import MegaView
|
from .http import MegaView
|
||||||
@@ -46,6 +46,8 @@ CUSTOMIZE_PORT = {
|
|||||||
vol.Optional(CONF_GET_VALUE, default=True): bool,
|
vol.Optional(CONF_GET_VALUE, default=True): bool,
|
||||||
vol.Optional(CONF_CONV_TEMPLATE): cv.template,
|
vol.Optional(CONF_CONV_TEMPLATE): cv.template,
|
||||||
vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
|
vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
|
||||||
|
vol.Optional(CONF_FORCE_I2C_SCAN): bool,
|
||||||
|
vol.Optional(CONF_HEX_TO_FLOAT): bool,
|
||||||
}
|
}
|
||||||
CUSTOMIZE_DS2413 = {
|
CUSTOMIZE_DS2413 = {
|
||||||
vol.Optional(str.lower, description='адрес и индекс устройства'): CUSTOMIZE_PORT
|
vol.Optional(str.lower, description='адрес и индекс устройства'): CUSTOMIZE_PORT
|
||||||
@@ -132,7 +134,7 @@ async def get_hub(hass, entry):
|
|||||||
break
|
break
|
||||||
if _mqtt is None:
|
if _mqtt is None:
|
||||||
raise Exception('mqtt not configured, please configure mqtt first')
|
raise Exception('mqtt not configured, please configure mqtt first')
|
||||||
hub = MegaD(hass, **data, mqtt=_mqtt, lg=_LOGGER, loop=asyncio.get_event_loop())
|
hub = MegaD(hass, config=entry, **data, mqtt=_mqtt, lg=_LOGGER, loop=asyncio.get_event_loop())
|
||||||
hub.mqtt_id = await hub.get_mqtt_id()
|
hub.mqtt_id = await hub.get_mqtt_id()
|
||||||
return hub
|
return hub
|
||||||
|
|
||||||
@@ -172,18 +174,14 @@ async def updater(hass: HomeAssistant, entry: ConfigEntry):
|
|||||||
:param entry:
|
:param entry:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
hub: MegaD = hass.data[DOMAIN][entry.data[CONF_ID]]
|
# hub: MegaD = hass.data[DOMAIN][entry.data[CONF_ID]]
|
||||||
hub.poll_interval = entry.options[CONF_SCAN_INTERVAL]
|
# hub.poll_interval = entry.options[CONF_SCAN_INTERVAL]
|
||||||
hub.port_to_scan = entry.options.get(CONF_PORT_TO_SCAN, 0)
|
# hub.port_to_scan = entry.options.get(CONF_PORT_TO_SCAN, 0)
|
||||||
entry.data = entry.options
|
await hass.config_entries.async_reload(entry.entry_id)
|
||||||
for platform in PLATFORMS:
|
|
||||||
await hass.config_entries.async_forward_entry_unload(entry, platform)
|
|
||||||
await async_remove_entry(hass, entry)
|
|
||||||
await async_setup_entry(hass, entry)
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
async def async_remove_entry(hass, entry) -> None:
|
async def async_remove_entry(hass: HomeAssistant, entry: ConfigEntry) -> None:
|
||||||
"""Handle removal of an entry."""
|
"""Handle removal of an entry."""
|
||||||
id = entry.data.get('id', entry.entry_id)
|
id = entry.data.get('id', entry.entry_id)
|
||||||
hub: MegaD = hass.data[DOMAIN].get(id)
|
hub: MegaD = hass.data[DOMAIN].get(id)
|
||||||
@@ -193,12 +191,17 @@ async def async_remove_entry(hass, entry) -> None:
|
|||||||
_hubs.pop(id, None)
|
_hubs.pop(id, None)
|
||||||
hass.data[DOMAIN].pop(id, None)
|
hass.data[DOMAIN].pop(id, None)
|
||||||
hass.data[DOMAIN][CONF_ALL].pop(id, None)
|
hass.data[DOMAIN][CONF_ALL].pop(id, None)
|
||||||
|
for platform in PLATFORMS:
|
||||||
|
await hass.config_entries.async_forward_entry_unload(entry, platform)
|
||||||
task: asyncio.Task = _POLL_TASKS.pop(id, None)
|
task: asyncio.Task = _POLL_TASKS.pop(id, None)
|
||||||
if task is not None:
|
if task is not None:
|
||||||
task.cancel()
|
task.cancel()
|
||||||
if hub is None:
|
if hub is None:
|
||||||
return
|
return
|
||||||
await hub.stop()
|
await hub.stop()
|
||||||
|
return True
|
||||||
|
|
||||||
|
async_unload_entry = async_remove_entry
|
||||||
|
|
||||||
|
|
||||||
async def async_migrate_entry(hass, config_entry: ConfigEntry):
|
async def async_migrate_entry(hass, config_entry: ConfigEntry):
|
||||||
|
|||||||
@@ -57,6 +57,8 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, asyn
|
|||||||
continue
|
continue
|
||||||
hub.lg.debug(f'add binary_sensor on port %s', port)
|
hub.lg.debug(f'add binary_sensor on port %s', port)
|
||||||
sensor = MegaBinarySensor(mega=hub, port=port, config_entry=config_entry)
|
sensor = MegaBinarySensor(mega=hub, port=port, config_entry=config_entry)
|
||||||
|
if '<' in sensor.name:
|
||||||
|
continue
|
||||||
devices.append(sensor)
|
devices.append(sensor)
|
||||||
async_add_devices(devices)
|
async_add_devices(devices)
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ from homeassistant.const import CONF_HOST, CONF_ID, CONF_PASSWORD, CONF_SCAN_INT
|
|||||||
from homeassistant.core import callback, HomeAssistant
|
from homeassistant.core import callback, HomeAssistant
|
||||||
from .const import DOMAIN, CONF_PORT_TO_SCAN, CONF_RELOAD, PLATFORMS, CONF_MQTT_INPUTS, \
|
from .const import DOMAIN, CONF_PORT_TO_SCAN, CONF_RELOAD, PLATFORMS, CONF_MQTT_INPUTS, \
|
||||||
CONF_NPORTS, CONF_UPDATE_ALL, CONF_POLL_OUTS, CONF_FAKE_RESPONSE, CONF_FORCE_D, \
|
CONF_NPORTS, CONF_UPDATE_ALL, CONF_POLL_OUTS, CONF_FAKE_RESPONSE, CONF_FORCE_D, \
|
||||||
CONF_ALLOW_HOSTS, CONF_PROTECTED, CONF_RESTORE_ON_RESTART # pylint:disable=unused-import
|
CONF_ALLOW_HOSTS, CONF_PROTECTED, CONF_RESTORE_ON_RESTART, CONF_UPDATE_TIME, \
|
||||||
|
REMOVE_CONFIG # pylint:disable=unused-import
|
||||||
from .hub import MegaD
|
from .hub import MegaD
|
||||||
from . import exceptions
|
from . import exceptions
|
||||||
|
|
||||||
@@ -24,7 +25,7 @@ STEP_USER_DATA_SCHEMA = vol.Schema(
|
|||||||
vol.Required(CONF_PASSWORD, default="sec"): str,
|
vol.Required(CONF_PASSWORD, default="sec"): str,
|
||||||
vol.Optional(CONF_SCAN_INTERVAL, default=0): int,
|
vol.Optional(CONF_SCAN_INTERVAL, default=0): int,
|
||||||
vol.Optional(CONF_POLL_OUTS, default=False): bool,
|
vol.Optional(CONF_POLL_OUTS, default=False): bool,
|
||||||
vol.Optional(CONF_PORT_TO_SCAN, default=0): int,
|
# vol.Optional(CONF_PORT_TO_SCAN, default=0): int,
|
||||||
vol.Optional(CONF_MQTT_INPUTS, default=False): bool,
|
vol.Optional(CONF_MQTT_INPUTS, default=False): bool,
|
||||||
vol.Optional(CONF_NPORTS, default=37): int,
|
vol.Optional(CONF_NPORTS, default=37): int,
|
||||||
vol.Optional(CONF_UPDATE_ALL, default=True): bool,
|
vol.Optional(CONF_UPDATE_ALL, default=True): bool,
|
||||||
@@ -33,6 +34,7 @@ STEP_USER_DATA_SCHEMA = vol.Schema(
|
|||||||
vol.Optional(CONF_RESTORE_ON_RESTART, default=True): bool,
|
vol.Optional(CONF_RESTORE_ON_RESTART, default=True): bool,
|
||||||
vol.Optional(CONF_PROTECTED, default=True): bool,
|
vol.Optional(CONF_PROTECTED, default=True): bool,
|
||||||
vol.Optional(CONF_ALLOW_HOSTS, default='::1;127.0.0.1'): str,
|
vol.Optional(CONF_ALLOW_HOSTS, default='::1;127.0.0.1'): str,
|
||||||
|
vol.Optional(CONF_UPDATE_TIME, default=True): bool,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -63,7 +65,7 @@ async def validate_input(hass: core.HomeAssistant, data):
|
|||||||
class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
||||||
"""Handle a config flow for mega."""
|
"""Handle a config flow for mega."""
|
||||||
|
|
||||||
VERSION = 19
|
VERSION = 23
|
||||||
CONNECTION_CLASS = config_entries.CONN_CLASS_ASSUMED
|
CONNECTION_CLASS = config_entries.CONN_CLASS_ASSUMED
|
||||||
|
|
||||||
async def async_step_user(self, user_input=None):
|
async def async_step_user(self, user_input=None):
|
||||||
@@ -82,6 +84,7 @@ class ConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
|
|||||||
await hub.stop()
|
await hub.stop()
|
||||||
hub.lg.debug(f'config loaded: %s', config)
|
hub.lg.debug(f'config loaded: %s', config)
|
||||||
config.update(user_input)
|
config.update(user_input)
|
||||||
|
config['new_naming'] = True
|
||||||
return self.async_create_entry(
|
return self.async_create_entry(
|
||||||
title=user_input.get(CONF_ID, user_input[CONF_HOST]),
|
title=user_input.get(CONF_ID, user_input[CONF_HOST]),
|
||||||
data=config,
|
data=config,
|
||||||
@@ -113,22 +116,20 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
|||||||
|
|
||||||
async def async_step_init(self, user_input=None):
|
async def async_step_init(self, user_input=None):
|
||||||
"""Manage the options."""
|
"""Manage the options."""
|
||||||
hub = await get_hub(self.hass, self.config_entry.data)
|
new_naming = self.config_entry.data.get('new_naming', False)
|
||||||
if user_input is not None:
|
if user_input is not None:
|
||||||
reload = user_input.pop(CONF_RELOAD)
|
reload = user_input.pop(CONF_RELOAD)
|
||||||
cfg = dict(self.config_entry.data)
|
cfg = dict(self.config_entry.data)
|
||||||
cfg.update(user_input)
|
cfg.update(user_input)
|
||||||
hub = await get_hub(self.hass, cfg)
|
cfg['new_naming'] = new_naming
|
||||||
if reload:
|
self.config_entry.data = cfg
|
||||||
await hub.start()
|
await get_hub(self.hass, cfg)
|
||||||
new = await hub.get_config(nports=user_input.get(CONF_NPORTS, 37))
|
|
||||||
await hub.stop()
|
if reload:
|
||||||
|
id = self.config_entry.data.get('id', self.config_entry.entry_id)
|
||||||
|
hub: MegaD = self.hass.data[DOMAIN].get(id)
|
||||||
|
await hub.reload(reload_entry=False)
|
||||||
|
|
||||||
_LOGGER.debug(f'new config: %s', new)
|
|
||||||
cfg = dict(self.config_entry.data)
|
|
||||||
for x in PLATFORMS:
|
|
||||||
cfg.pop(x, None)
|
|
||||||
cfg.update(new)
|
|
||||||
return self.async_create_entry(
|
return self.async_create_entry(
|
||||||
title='',
|
title='',
|
||||||
data=cfg,
|
data=cfg,
|
||||||
@@ -139,7 +140,7 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
|||||||
data_schema=vol.Schema({
|
data_schema=vol.Schema({
|
||||||
vol.Optional(CONF_SCAN_INTERVAL, default=e.get(CONF_SCAN_INTERVAL, 0)): int,
|
vol.Optional(CONF_SCAN_INTERVAL, default=e.get(CONF_SCAN_INTERVAL, 0)): int,
|
||||||
vol.Optional(CONF_POLL_OUTS, default=e.get(CONF_POLL_OUTS, False)): bool,
|
vol.Optional(CONF_POLL_OUTS, default=e.get(CONF_POLL_OUTS, False)): bool,
|
||||||
vol.Optional(CONF_PORT_TO_SCAN, default=e.get(CONF_PORT_TO_SCAN, 0)): int,
|
# vol.Optional(CONF_PORT_TO_SCAN, default=e.get(CONF_PORT_TO_SCAN, 0)): int,
|
||||||
vol.Optional(CONF_MQTT_INPUTS, default=e.get(CONF_MQTT_INPUTS, True)): bool,
|
vol.Optional(CONF_MQTT_INPUTS, default=e.get(CONF_MQTT_INPUTS, True)): bool,
|
||||||
vol.Optional(CONF_NPORTS, default=e.get(CONF_NPORTS, 37)): int,
|
vol.Optional(CONF_NPORTS, default=e.get(CONF_NPORTS, 37)): int,
|
||||||
vol.Optional(CONF_RELOAD, default=False): bool,
|
vol.Optional(CONF_RELOAD, default=False): bool,
|
||||||
@@ -149,6 +150,7 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
|||||||
vol.Optional(CONF_RESTORE_ON_RESTART, default=e.get(CONF_RESTORE_ON_RESTART, False)): bool,
|
vol.Optional(CONF_RESTORE_ON_RESTART, default=e.get(CONF_RESTORE_ON_RESTART, False)): bool,
|
||||||
vol.Optional(CONF_PROTECTED, default=e.get(CONF_PROTECTED, True)): bool,
|
vol.Optional(CONF_PROTECTED, default=e.get(CONF_PROTECTED, True)): bool,
|
||||||
vol.Optional(CONF_ALLOW_HOSTS, default='::1;127.0.0.1'): str,
|
vol.Optional(CONF_ALLOW_HOSTS, default='::1;127.0.0.1'): str,
|
||||||
|
vol.Optional(CONF_UPDATE_TIME, default=e.get(CONF_UPDATE_TIME, False)): bool,
|
||||||
# vol.Optional(CONF_INVERT, default=''): str,
|
# vol.Optional(CONF_INVERT, default=''): str,
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -34,6 +34,9 @@ CONF_DEF_RESPONSE = 'def_response'
|
|||||||
CONF_RESTORE_ON_RESTART = 'restore_on_restart'
|
CONF_RESTORE_ON_RESTART = 'restore_on_restart'
|
||||||
CONF_CLICK_TIME = 'click_time'
|
CONF_CLICK_TIME = 'click_time'
|
||||||
CONF_LONG_TIME = 'long_time'
|
CONF_LONG_TIME = 'long_time'
|
||||||
|
CONF_FORCE_I2C_SCAN = 'force_i2c_scan'
|
||||||
|
CONF_UPDATE_TIME = 'update_time'
|
||||||
|
CONF_HEX_TO_FLOAT = 'hex_to_float'
|
||||||
PLATFORMS = [
|
PLATFORMS = [
|
||||||
"light",
|
"light",
|
||||||
"switch",
|
"switch",
|
||||||
@@ -54,3 +57,14 @@ SINGLE_CLICK = 'single'
|
|||||||
DOUBLE_CLICK = 'double'
|
DOUBLE_CLICK = 'double'
|
||||||
|
|
||||||
PATT_FW = re.compile(r'fw:\s(.+)\)')
|
PATT_FW = re.compile(r'fw:\s(.+)\)')
|
||||||
|
|
||||||
|
REMOVE_CONFIG = [
|
||||||
|
'extenders',
|
||||||
|
'ext_in',
|
||||||
|
'ext_acts',
|
||||||
|
'i2c_sensors',
|
||||||
|
'binary_sensor',
|
||||||
|
'light',
|
||||||
|
'i2c',
|
||||||
|
'sensor',
|
||||||
|
]
|
||||||
@@ -60,7 +60,8 @@ class BaseMegaEntity(CoordinatorEntity, RestoreEntity):
|
|||||||
self._lg = None
|
self._lg = None
|
||||||
self._unique_id = unique_id or f"mega_{mega.id}_{port}" + \
|
self._unique_id = unique_id or f"mega_{mega.id}_{port}" + \
|
||||||
(f"_{id_suffix}" if id_suffix else "")
|
(f"_{id_suffix}" if id_suffix else "")
|
||||||
self._name = name or f"{mega.id}_{port}" + \
|
_pt = port if not mega.new_naming else f'{port:02}' if isinstance(port, int) else port
|
||||||
|
self._name = name or f"{mega.id}_{_pt}" + \
|
||||||
(f"_{id_suffix}" if id_suffix else "")
|
(f"_{id_suffix}" if id_suffix else "")
|
||||||
self._customize: dict = None
|
self._customize: dict = None
|
||||||
self.index = index
|
self.index = index
|
||||||
@@ -68,6 +69,13 @@ class BaseMegaEntity(CoordinatorEntity, RestoreEntity):
|
|||||||
if self.http_cmd == 'ds2413':
|
if self.http_cmd == 'ds2413':
|
||||||
self.mega.ds2413_ports |= {self.port}
|
self.mega.ds2413_ports |= {self.port}
|
||||||
|
|
||||||
|
@property
|
||||||
|
def enabled(self):
|
||||||
|
if '<' in self.name:
|
||||||
|
return False
|
||||||
|
else:
|
||||||
|
return super().enabled
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def customize(self):
|
def customize(self):
|
||||||
if self.hass is None:
|
if self.hass is None:
|
||||||
@@ -85,6 +93,7 @@ class BaseMegaEntity(CoordinatorEntity, RestoreEntity):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def device_info(self):
|
def device_info(self):
|
||||||
|
_pt = self.port if not self.mega.new_naming else f'{self.port:02}' if isinstance(self.port, int) else self.port
|
||||||
return {
|
return {
|
||||||
"identifiers": {
|
"identifiers": {
|
||||||
# Serial numbers are unique identifiers within a specific domain
|
# Serial numbers are unique identifiers within a specific domain
|
||||||
@@ -93,7 +102,7 @@ class BaseMegaEntity(CoordinatorEntity, RestoreEntity):
|
|||||||
"config_entries": [
|
"config_entries": [
|
||||||
self.config_entry,
|
self.config_entry,
|
||||||
],
|
],
|
||||||
"name": f'{self._mega_id} port {self.port}',
|
"name": f'{self._mega_id} port {_pt}',
|
||||||
"manufacturer": 'ab-log.ru',
|
"manufacturer": 'ab-log.ru',
|
||||||
# "model": self.light.productname,
|
# "model": self.light.productname,
|
||||||
"sw_version": self.mega.fw,
|
"sw_version": self.mega.fw,
|
||||||
@@ -114,7 +123,8 @@ class BaseMegaEntity(CoordinatorEntity, RestoreEntity):
|
|||||||
def name(self):
|
def name(self):
|
||||||
c = self.customize.get(CONF_NAME)
|
c = self.customize.get(CONF_NAME)
|
||||||
if not isinstance(c, str):
|
if not isinstance(c, str):
|
||||||
c = self._name or f"{self.mega.id}_p{self.port}"
|
_pt = self.port if not self.mega.new_naming else f'{self.port:02}' if isinstance(self.port, int) else self.port
|
||||||
|
c = self._name or f"{self.mega.id}_p{_pt}"
|
||||||
return c
|
return c
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@@ -147,6 +157,8 @@ class MegaPushEntity(BaseMegaEntity):
|
|||||||
|
|
||||||
def __update(self, value: dict):
|
def __update(self, value: dict):
|
||||||
self._update(value)
|
self._update(value)
|
||||||
|
if self.hass is None:
|
||||||
|
return
|
||||||
self.async_write_ha_state()
|
self.async_write_ha_state()
|
||||||
self.lg.debug(f'state after update %s', self.state)
|
self.lg.debug(f'state after update %s', self.state)
|
||||||
if self.mega.mqtt_inputs and not _events_on:
|
if self.mega.mqtt_inputs and not _events_on:
|
||||||
|
|||||||
@@ -77,7 +77,11 @@ class MegaView(HomeAssistantView):
|
|||||||
if hub is None:
|
if hub is None:
|
||||||
_LOGGER.warning(f'can not find mdid={request.query["mdid"]} in {list(self.hubs)}')
|
_LOGGER.warning(f'can not find mdid={request.query["mdid"]} in {list(self.hubs)}')
|
||||||
if hub is None and request.remote in ['::1', '127.0.0.1']:
|
if hub is None and request.remote in ['::1', '127.0.0.1']:
|
||||||
hub = self.hubs.get('__def')
|
try:
|
||||||
|
hub = list(self.hubs.values())[0]
|
||||||
|
except IndexError:
|
||||||
|
_LOGGER.warning(f'can not find mdid={request.query["mdid"]} in {list(self.hubs)}')
|
||||||
|
return Response(status=400)
|
||||||
elif hub is None:
|
elif hub is None:
|
||||||
return Response(status=400)
|
return Response(status=400)
|
||||||
data = dict(request.query)
|
data = dict(request.query)
|
||||||
@@ -87,8 +91,10 @@ class MegaView(HomeAssistantView):
|
|||||||
)
|
)
|
||||||
_LOGGER.debug(f"Request: %s from '%s'", data, request.remote)
|
_LOGGER.debug(f"Request: %s from '%s'", data, request.remote)
|
||||||
make_ints(data)
|
make_ints(data)
|
||||||
if data.get('st') == '1' and hub.restore_on_restart:
|
if data.get('st') == '1':
|
||||||
asyncio.create_task(self.later_restore(hub))
|
hass.async_create_task(hub.reload())
|
||||||
|
if hub.restore_on_restart:
|
||||||
|
hass.async_create_task(self.later_restore(hub))
|
||||||
return Response(status=200)
|
return Response(status=200)
|
||||||
port = data.get('pt')
|
port = data.get('pt')
|
||||||
data = data.copy()
|
data = data.copy()
|
||||||
@@ -164,4 +170,3 @@ class MegaView(HomeAssistantView):
|
|||||||
await asyncio.sleep(1)
|
await asyncio.sleep(1)
|
||||||
_LOGGER.debug('force update')
|
_LOGGER.debug('force update')
|
||||||
await hub.updater.async_refresh()
|
await hub.updater.async_refresh()
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import json
|
|||||||
|
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
from homeassistant.components import mqtt
|
from homeassistant.components import mqtt
|
||||||
|
from homeassistant.config_entries import ConfigEntry
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_PRESSURE,
|
DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_PRESSURE,
|
||||||
DEVICE_CLASS_ILLUMINANCE, TEMP_CELSIUS, PERCENTAGE, LIGHT_LUX
|
DEVICE_CLASS_ILLUMINANCE, TEMP_CELSIUS, PERCENTAGE, LIGHT_LUX
|
||||||
@@ -20,7 +21,8 @@ from .config_parser import parse_config, DS2413, MCP230, MCP230_OUT, MCP230_IN,
|
|||||||
from .const import (
|
from .const import (
|
||||||
TEMP, HUM, PRESS,
|
TEMP, HUM, PRESS,
|
||||||
LUX, PATT_SPLIT, DOMAIN,
|
LUX, PATT_SPLIT, DOMAIN,
|
||||||
CONF_HTTP, EVENT_BINARY_SENSOR, CONF_CUSTOM, CONF_FORCE_D, CONF_DEF_RESPONSE, PATT_FW
|
CONF_HTTP, EVENT_BINARY_SENSOR, CONF_CUSTOM, CONF_FORCE_D, CONF_DEF_RESPONSE, PATT_FW, CONF_FORCE_I2C_SCAN,
|
||||||
|
REMOVE_CONFIG
|
||||||
)
|
)
|
||||||
from .entities import set_events_off, BaseMegaEntity, MegaOutPort
|
from .entities import set_events_off, BaseMegaEntity, MegaOutPort
|
||||||
from .exceptions import CannotConnect, NoPort
|
from .exceptions import CannotConnect, NoPort
|
||||||
@@ -69,6 +71,7 @@ class MegaD:
|
|||||||
mqtt: mqtt.MQTT,
|
mqtt: mqtt.MQTT,
|
||||||
lg: logging.Logger,
|
lg: logging.Logger,
|
||||||
id: str,
|
id: str,
|
||||||
|
config: ConfigEntry = None,
|
||||||
mqtt_inputs: bool = True,
|
mqtt_inputs: bool = True,
|
||||||
mqtt_id: str = None,
|
mqtt_id: str = None,
|
||||||
scan_interval=60,
|
scan_interval=60,
|
||||||
@@ -85,9 +88,12 @@ class MegaD:
|
|||||||
ext_in=None,
|
ext_in=None,
|
||||||
ext_acts=None,
|
ext_acts=None,
|
||||||
i2c_sensors=None,
|
i2c_sensors=None,
|
||||||
|
new_naming=False,
|
||||||
|
update_time=False,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
):
|
):
|
||||||
"""Initialize."""
|
"""Initialize."""
|
||||||
|
self.config = config
|
||||||
if mqtt_inputs is None or mqtt_inputs == 'None' or mqtt_inputs is False:
|
if mqtt_inputs is None or mqtt_inputs == 'None' or mqtt_inputs is False:
|
||||||
self.http = hass.data.get(DOMAIN, {}).get(CONF_HTTP)
|
self.http = hass.data.get(DOMAIN, {}).get(CONF_HTTP)
|
||||||
if not self.http is None:
|
if not self.http is None:
|
||||||
@@ -99,10 +105,12 @@ class MegaD:
|
|||||||
self.http.hubs[mqtt_id] = self
|
self.http.hubs[mqtt_id] = self
|
||||||
else:
|
else:
|
||||||
self.http = None
|
self.http = None
|
||||||
|
self.new_naming = new_naming
|
||||||
self.extenders = extenders or []
|
self.extenders = extenders or []
|
||||||
self.ext_in = ext_in or {}
|
self.ext_in = ext_in or {}
|
||||||
self.ext_act = ext_acts or {}
|
self.ext_act = ext_acts or {}
|
||||||
self.i2c_sensors = i2c_sensors or []
|
self.i2c_sensors = i2c_sensors or []
|
||||||
|
self._update_time = update_time
|
||||||
self.poll_outs = poll_outs
|
self.poll_outs = poll_outs
|
||||||
self.update_all = update_all if update_all is not None else True
|
self.update_all = update_all if update_all is not None else True
|
||||||
self.nports = nports
|
self.nports = nports
|
||||||
@@ -248,6 +256,8 @@ class MegaD:
|
|||||||
Polling ports
|
Polling ports
|
||||||
"""
|
"""
|
||||||
self.lg.debug('poll')
|
self.lg.debug('poll')
|
||||||
|
if self._update_time:
|
||||||
|
await self.update_time()
|
||||||
for x in self.i2c_sensors:
|
for x in self.i2c_sensors:
|
||||||
if not isinstance(x, dict):
|
if not isinstance(x, dict):
|
||||||
continue
|
continue
|
||||||
@@ -267,8 +277,8 @@ class MegaD:
|
|||||||
await self.get_all_ports(check_skip=True)
|
await self.get_all_ports(check_skip=True)
|
||||||
elif len(self.sensors) > 0:
|
elif len(self.sensors) > 0:
|
||||||
await self.get_sensors()
|
await self.get_sensors()
|
||||||
else:
|
# else:
|
||||||
await self.get_port(self.port_to_scan)
|
# await self.get_port(self.port_to_scan)
|
||||||
await self._get_ds2413()
|
await self._get_ds2413()
|
||||||
return self.values
|
return self.values
|
||||||
|
|
||||||
@@ -464,45 +474,6 @@ class MegaD:
|
|||||||
async def scan_port(self, port):
|
async def scan_port(self, port):
|
||||||
data = await self.request(pt=port)
|
data = await self.request(pt=port)
|
||||||
return parse_config(data)
|
return parse_config(data)
|
||||||
# async with self.lck:
|
|
||||||
# if port in self._scanned:
|
|
||||||
# return self._scanned[port]
|
|
||||||
# url = f'http://{self.host}/{self.sec}/?pt={port}'
|
|
||||||
# self.lg.debug(
|
|
||||||
# f'scan port %s: %s', port, url
|
|
||||||
# )
|
|
||||||
# async with aiohttp.request('get', url) as req:
|
|
||||||
# html = await req.text()
|
|
||||||
# if req.status != 200:
|
|
||||||
# return
|
|
||||||
# tree = BeautifulSoup(html, features="lxml")
|
|
||||||
# pty = tree.find('select', attrs={'name': 'pty'})
|
|
||||||
# if pty is None:
|
|
||||||
# return
|
|
||||||
# else:
|
|
||||||
# pty = pty.find(selected=True)
|
|
||||||
# if pty:
|
|
||||||
# pty = pty['value']
|
|
||||||
# else:
|
|
||||||
# return
|
|
||||||
# if pty in ['0', '1']:
|
|
||||||
# m = tree.find('select', attrs={'name': 'm'})
|
|
||||||
# if m:
|
|
||||||
# m = m.find(selected=True)['value']
|
|
||||||
# self._scanned[port] = (pty, m)
|
|
||||||
# return pty, m
|
|
||||||
# elif pty == '3':
|
|
||||||
# m = tree.find('select', attrs={'name': 'd'})
|
|
||||||
# if m:
|
|
||||||
# m = m.find(selected=True)['value']
|
|
||||||
# self._scanned[port] = (pty, m)
|
|
||||||
# return pty, m
|
|
||||||
# elif pty in ('2', '4'): # эта часть не очень проработана, тут есть i2c который может работать неправильно
|
|
||||||
# m = tree.find('select', attrs={'name': 'd'})
|
|
||||||
# if m:
|
|
||||||
# m = m.find(selected=True)['value']
|
|
||||||
# self._scanned[port] = (pty, m or '0')
|
|
||||||
# return pty, m or '0'
|
|
||||||
|
|
||||||
async def scan_ports(self, nports=37):
|
async def scan_ports(self, nports=37):
|
||||||
for x in range(0, nports+1):
|
for x in range(0, nports+1):
|
||||||
@@ -530,9 +501,17 @@ class MegaD:
|
|||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
_params = tuple(params.items())
|
_params = tuple(params.items())
|
||||||
return {
|
delay = None
|
||||||
|
if 'delay' in params:
|
||||||
|
delay = params.pop('delay')
|
||||||
|
ret = {
|
||||||
_params: await self.request(**params)
|
_params: await self.request(**params)
|
||||||
}
|
}
|
||||||
|
self.lg.debug('i2c response: %s', ret)
|
||||||
|
if delay:
|
||||||
|
self.lg.debug('delay %s', delay)
|
||||||
|
await asyncio.sleep(delay)
|
||||||
|
return ret
|
||||||
|
|
||||||
async def get_config(self, nports=37):
|
async def get_config(self, nports=37):
|
||||||
ret = defaultdict(lambda: defaultdict(list))
|
ret = defaultdict(lambda: defaultdict(list))
|
||||||
@@ -542,6 +521,9 @@ class MegaD:
|
|||||||
ret['ext_acts'] = ext_acts = {}
|
ret['ext_acts'] = ext_acts = {}
|
||||||
ret['i2c_sensors'] = i2c_sensors = []
|
ret['i2c_sensors'] = i2c_sensors = []
|
||||||
async for port, cfg in self.scan_ports(nports):
|
async for port, cfg in self.scan_ports(nports):
|
||||||
|
_cust = self.customize.get(port)
|
||||||
|
if not isinstance(_cust, dict):
|
||||||
|
_cust = {}
|
||||||
if cfg.pty == "0":
|
if cfg.pty == "0":
|
||||||
ret['binary_sensor'][port].append({})
|
ret['binary_sensor'][port].append({})
|
||||||
elif cfg.pty == "1" and (cfg.m in ['0', '1', '3'] or cfg.m is None):
|
elif cfg.pty == "1" and (cfg.m in ['0', '1', '3'] or cfg.m is None):
|
||||||
@@ -567,7 +549,7 @@ class MegaD:
|
|||||||
for n in range(len(values)):
|
for n in range(len(values)):
|
||||||
ext_page = await self.request(pt=port, ext=n)
|
ext_page = await self.request(pt=port, ext=n)
|
||||||
ext_cfg = parse_config(ext_page)
|
ext_cfg = parse_config(ext_page)
|
||||||
pt = f'{port}e{n}'
|
pt = f'{port}e{n}' if not self.new_naming else f'{port:02}e{n:02}'
|
||||||
if ext_cfg.ety == '1':
|
if ext_cfg.ety == '1':
|
||||||
ret['light'][pt].append({})
|
ret['light'][pt].append({})
|
||||||
elif ext_cfg.ety == '0':
|
elif ext_cfg.ety == '0':
|
||||||
@@ -579,8 +561,9 @@ class MegaD:
|
|||||||
values = await self.request(pt=port, cmd='get')
|
values = await self.request(pt=port, cmd='get')
|
||||||
values = values.split(';')
|
values = values.split(';')
|
||||||
for n in range(len(values)):
|
for n in range(len(values)):
|
||||||
ret['light'][f'{port}e{n}'].append({'dimmer': True, 'dimmer_scale': 16})
|
pt = f'{port}e{n}' if not self.new_naming else f'{port:02}e{n:02}'
|
||||||
elif cfg.pty == '4' and cfg.gr == '0':
|
ret['light'][pt].append({'dimmer': True, 'dimmer_scale': 16})
|
||||||
|
elif cfg.pty == '4' and (cfg.gr == '0' or _cust.get(CONF_FORCE_I2C_SCAN)):
|
||||||
# i2c в режиме ANY
|
# i2c в режиме ANY
|
||||||
scan = cfg.src.find('a', text='I2C Scan')
|
scan = cfg.src.find('a', text='I2C Scan')
|
||||||
self.lg.debug(f'find scan link: %s', scan)
|
self.lg.debug(f'find scan link: %s', scan)
|
||||||
@@ -590,6 +573,9 @@ class MegaD:
|
|||||||
self.lg.debug(f'scan results: %s', (req, parsed))
|
self.lg.debug(f'scan results: %s', (req, parsed))
|
||||||
ret['i2c'][port].extend(parsed)
|
ret['i2c'][port].extend(parsed)
|
||||||
i2c_sensors.extend(req)
|
i2c_sensors.extend(req)
|
||||||
|
elif cfg.pty == '4' and cfg.m == '2':
|
||||||
|
# scl исключаем из сканирования
|
||||||
|
continue
|
||||||
elif cfg.pty in ('3', '2', '4'):
|
elif cfg.pty in ('3', '2', '4'):
|
||||||
http_cmd = 'get'
|
http_cmd = 'get'
|
||||||
if cfg.d == '5' and cfg.pty == '3':
|
if cfg.d == '5' and cfg.pty == '3':
|
||||||
@@ -633,4 +619,19 @@ class MegaD:
|
|||||||
else:
|
else:
|
||||||
await x.async_turn_off()
|
await x.async_turn_off()
|
||||||
|
|
||||||
|
async def update_time(self):
|
||||||
|
await self.request(
|
||||||
|
cf=7,
|
||||||
|
stime=datetime.now().strftime('%H:%M:%S')
|
||||||
|
)
|
||||||
|
|
||||||
|
async def reload(self, reload_entry=True):
|
||||||
|
new = await self.get_config(nports=self.nports)
|
||||||
|
self.lg.debug(f'new config: %s', new)
|
||||||
|
cfg = dict(self.config.data)
|
||||||
|
for x in REMOVE_CONFIG:
|
||||||
|
cfg.pop(x, None)
|
||||||
|
cfg.update(new)
|
||||||
|
self.config.data = cfg
|
||||||
|
if reload_entry:
|
||||||
|
await self.hass.config_entries.async_reload(self.config.entry_id)
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
from dataclasses import dataclass, field
|
||||||
from urllib.parse import parse_qsl, urlparse
|
from urllib.parse import parse_qsl, urlparse
|
||||||
from bs4 import BeautifulSoup
|
from bs4 import BeautifulSoup
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
@@ -27,6 +28,12 @@ def parse_scan_page(page: str):
|
|||||||
elif c is Request:
|
elif c is Request:
|
||||||
req.append(params)
|
req.append(params)
|
||||||
continue
|
continue
|
||||||
|
elif isinstance(c, Request):
|
||||||
|
if c.delay:
|
||||||
|
params = params.copy()
|
||||||
|
params['delay'] = c.delay
|
||||||
|
req.append(params)
|
||||||
|
continue
|
||||||
elif isinstance(c, tuple):
|
elif isinstance(c, tuple):
|
||||||
suffix, c = c
|
suffix, c = c
|
||||||
elif isinstance(c, str):
|
elif isinstance(c, str):
|
||||||
@@ -55,8 +62,9 @@ class Skip:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
class Request:
|
class Request:
|
||||||
pass
|
delay: float = None
|
||||||
|
|
||||||
|
|
||||||
i2c_classes = {
|
i2c_classes = {
|
||||||
@@ -92,7 +100,8 @@ i2c_classes = {
|
|||||||
('object', DEVICE_CLASS_TEMPERATURE),
|
('object', DEVICE_CLASS_TEMPERATURE),
|
||||||
],
|
],
|
||||||
'ptsensor': [
|
'ptsensor': [
|
||||||
Request, # запрос на измерение
|
Skip,
|
||||||
|
Request(delay=1), # запрос на измерение
|
||||||
DEVICE_CLASS_PRESSURE,
|
DEVICE_CLASS_PRESSURE,
|
||||||
DEVICE_CLASS_TEMPERATURE,
|
DEVICE_CLASS_TEMPERATURE,
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -69,6 +69,8 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, asyn
|
|||||||
for data in cfg:
|
for data in cfg:
|
||||||
hub.lg.debug(f'add light on port %s with data %s', port, data)
|
hub.lg.debug(f'add light on port %s with data %s', port, data)
|
||||||
light = MegaLight(mega=hub, port=port, config_entry=config_entry, **data)
|
light = MegaLight(mega=hub, port=port, config_entry=config_entry, **data)
|
||||||
|
if '<' in light.name:
|
||||||
|
continue
|
||||||
devices.append(light)
|
devices.append(light)
|
||||||
async_add_devices(devices)
|
async_add_devices(devices)
|
||||||
|
|
||||||
|
|||||||
@@ -15,5 +15,5 @@
|
|||||||
"@andvikt"
|
"@andvikt"
|
||||||
],
|
],
|
||||||
"issue_tracker": "https://github.com/andvikt/mega_hacs/issues",
|
"issue_tracker": "https://github.com/andvikt/mega_hacs/issues",
|
||||||
"version": "v0.6.1b1"
|
"version": "v0.6.3b1"
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
"""Platform for light integration."""
|
"""Platform for light integration."""
|
||||||
import logging
|
import logging
|
||||||
import voluptuous as vol
|
import voluptuous as vol
|
||||||
|
import struct
|
||||||
|
|
||||||
from homeassistant.components.sensor import (
|
from homeassistant.components.sensor import (
|
||||||
PLATFORM_SCHEMA as SENSOR_SCHEMA,
|
PLATFORM_SCHEMA as SENSOR_SCHEMA,
|
||||||
@@ -19,7 +20,7 @@ from homeassistant.const import (
|
|||||||
from homeassistant.core import HomeAssistant
|
from homeassistant.core import HomeAssistant
|
||||||
from homeassistant.helpers.template import Template
|
from homeassistant.helpers.template import Template
|
||||||
from .entities import MegaPushEntity
|
from .entities import MegaPushEntity
|
||||||
from .const import CONF_KEY, TEMP, HUM, W1, W1BUS, CONF_CONV_TEMPLATE
|
from .const import CONF_KEY, TEMP, HUM, W1, W1BUS, CONF_CONV_TEMPLATE, CONF_HEX_TO_FLOAT
|
||||||
from .hub import MegaD
|
from .hub import MegaD
|
||||||
import re
|
import re
|
||||||
|
|
||||||
@@ -94,6 +95,8 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, asyn
|
|||||||
config_entry=config_entry,
|
config_entry=config_entry,
|
||||||
**data,
|
**data,
|
||||||
)
|
)
|
||||||
|
if '<' in sensor.name:
|
||||||
|
continue
|
||||||
devices.append(sensor)
|
devices.append(sensor)
|
||||||
|
|
||||||
async_add_devices(devices)
|
async_add_devices(devices)
|
||||||
@@ -109,8 +112,20 @@ class MegaI2C(MegaPushEntity):
|
|||||||
def device_class(self):
|
def device_class(self):
|
||||||
return self._device_class
|
return self._device_class
|
||||||
|
|
||||||
|
@property
|
||||||
def state(self):
|
def state(self):
|
||||||
return self.mega.values[self._params]
|
# self.lg.debug(f'get % all states: %', self._params, self.mega.values)
|
||||||
|
ret = self.mega.values.get(self._params)
|
||||||
|
if self.customize.get(CONF_HEX_TO_FLOAT):
|
||||||
|
try:
|
||||||
|
ret = struct.unpack('!f', bytes.fromhex('41973333'))[0]
|
||||||
|
except:
|
||||||
|
self.lg.warning(f'could not convert {ret} form hex to float')
|
||||||
|
tmpl: Template = self.customize.get(CONF_CONV_TEMPLATE, self.customize.get(CONF_VALUE_TEMPLATE))
|
||||||
|
if tmpl is not None and self.hass is not None:
|
||||||
|
tmpl.hass = self.hass
|
||||||
|
ret = tmpl.async_render({'value': ret})
|
||||||
|
return ret
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def device_class(self):
|
def device_class(self):
|
||||||
@@ -193,6 +208,11 @@ class Mega1WSensor(MegaPushEntity):
|
|||||||
ret = str(ret)
|
ret = str(ret)
|
||||||
except:
|
except:
|
||||||
ret = None
|
ret = None
|
||||||
|
if self.customize.get(CONF_HEX_TO_FLOAT):
|
||||||
|
try:
|
||||||
|
ret = struct.unpack('!f', bytes.fromhex(ret))[0]
|
||||||
|
except:
|
||||||
|
self.lg.warning(f'could not convert {ret} form hex to float')
|
||||||
tmpl: Template = self.customize.get(CONF_CONV_TEMPLATE, self.customize.get(CONF_VALUE_TEMPLATE))
|
tmpl: Template = self.customize.get(CONF_CONV_TEMPLATE, self.customize.get(CONF_VALUE_TEMPLATE))
|
||||||
if tmpl is not None and self.hass is not None:
|
if tmpl is not None and self.hass is not None:
|
||||||
tmpl.hass = self.hass
|
tmpl.hass = self.hass
|
||||||
|
|||||||
@@ -20,7 +20,9 @@
|
|||||||
"protected": "[%key:common::config_flow::data::protected%]",
|
"protected": "[%key:common::config_flow::data::protected%]",
|
||||||
"allow_hosts": "[%key:common::config_flow::data::allow_hosts%]",
|
"allow_hosts": "[%key:common::config_flow::data::allow_hosts%]",
|
||||||
"restore_on_restart": "[%key:common::config_flow::data::restore_on_restart%]",
|
"restore_on_restart": "[%key:common::config_flow::data::restore_on_restart%]",
|
||||||
"poll_outs": "[%key:common::config_flow::data::poll_outs%]"
|
"poll_outs": "[%key:common::config_flow::data::poll_outs%]",
|
||||||
|
"update_time": "[%key:common::config_flow::data::update_time%]"
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -58,6 +58,8 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, asyn
|
|||||||
for data in cfg:
|
for data in cfg:
|
||||||
hub.lg.debug(f'add switch on port %s with data %s', port, data)
|
hub.lg.debug(f'add switch on port %s with data %s', port, data)
|
||||||
light = MegaSwitch(mega=hub, port=port, config_entry=config_entry, **data)
|
light = MegaSwitch(mega=hub, port=port, config_entry=config_entry, **data)
|
||||||
|
if '<' in light.name:
|
||||||
|
continue
|
||||||
devices.append(light)
|
devices.append(light)
|
||||||
async_add_devices(devices)
|
async_add_devices(devices)
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ class PriorityLock(asyncio.Lock):
|
|||||||
locked and returns True.
|
locked and returns True.
|
||||||
"""
|
"""
|
||||||
if (not self._locked and (self._waiters is None or
|
if (not self._locked and (self._waiters is None or
|
||||||
all(w.cancelled() for _, w in self._waiters))):
|
all(w.cancelled() for _, _, w in self._waiters))):
|
||||||
self._locked = True
|
self._locked = True
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|||||||
@@ -28,7 +28,8 @@
|
|||||||
"protected": "Protected",
|
"protected": "Protected",
|
||||||
"allow_hosts": "Allowed hosts",
|
"allow_hosts": "Allowed hosts",
|
||||||
"restore_on_restart": "Restore outs on restart",
|
"restore_on_restart": "Restore outs on restart",
|
||||||
"poll_outs": "Poll outs"
|
"poll_outs": "Poll outs",
|
||||||
|
"update_time": "Sync time"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -47,7 +48,8 @@
|
|||||||
"protected": "Protected",
|
"protected": "Protected",
|
||||||
"allow_hosts": "Allowed hosts",
|
"allow_hosts": "Allowed hosts",
|
||||||
"restore_on_restart": "Restore outs on restart",
|
"restore_on_restart": "Restore outs on restart",
|
||||||
"poll_outs": "Poll outs"
|
"poll_outs": "Poll outs",
|
||||||
|
"update_time": "Sync time"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,8 @@
|
|||||||
"protected": "Блокировать неразрешенные соединения",
|
"protected": "Блокировать неразрешенные соединения",
|
||||||
"restore_on_restart": "Восстанавливать выходы при перезагрузке",
|
"restore_on_restart": "Восстанавливать выходы при перезагрузке",
|
||||||
"allow_hosts": "Разрешенные ip (через ;)",
|
"allow_hosts": "Разрешенные ip (через ;)",
|
||||||
"poll_outs": "Обновлять выходы (регулярно)"
|
"poll_outs": "Обновлять выходы (регулярно)",
|
||||||
|
"update_time": "Синхронизировать время"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -48,7 +49,8 @@
|
|||||||
"protected": "Блокировать неразрешенные соединения",
|
"protected": "Блокировать неразрешенные соединения",
|
||||||
"allow_hosts": "Разрешенные ip (через ;)",
|
"allow_hosts": "Разрешенные ip (через ;)",
|
||||||
"restore_on_restart": "Восстанавливать выходы при перезагрузке",
|
"restore_on_restart": "Восстанавливать выходы при перезагрузке",
|
||||||
"poll_outs": "Обновлять выходы (регулярно)"
|
"poll_outs": "Обновлять выходы (регулярно)",
|
||||||
|
"update_time": "Синхронизировать время"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,8 @@
|
|||||||
"protected": "Блокувати недозволені з'єднання",
|
"protected": "Блокувати недозволені з'єднання",
|
||||||
"allow_hosts": "Дозволені ip (через ;)",
|
"allow_hosts": "Дозволені ip (через ;)",
|
||||||
"restore_on_restart": "Відновлювати виходи при перезавантаженні",
|
"restore_on_restart": "Відновлювати виходи при перезавантаженні",
|
||||||
"poll_outs": "Оновити виходи"
|
"poll_outs": "Оновити виходи",
|
||||||
|
"update_time": "Осинхронізувати час"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user