Compare commits

...

23 Commits

Author SHA1 Message Date
andvikt
d7180c0477 Bump version: 1.1.4b0 → 1.1.4 2022-09-08 12:42:10 +03:00
andvikt
1ceb7e4766 Bump version: 1.1.3 → 1.1.4b0 2022-09-08 12:41:56 +03:00
andvikt
ef46ac2b2b fix 2022.9 2022-09-08 12:41:42 +03:00
andvikt
e44aef35fb Bump version: 1.1.3b0 → 1.1.3 2022-07-22 10:09:04 +03:00
andvikt
a860ba9822 Bump version: 1.1.2b0 → 1.1.3b0 2022-07-22 10:08:43 +03:00
andvikt
2463b270e5 fix asyncio.lock 2022-07-22 10:08:37 +03:00
andvikt
ce2969c1e7 Bump version: 1.1.1 → 1.1.2b0 2021-12-19 17:52:57 +03:00
andvikt
34056273f3 try to fix sht31 2021-12-19 17:52:47 +03:00
Викторов Андрей Германович
19313d3b35 Bump version: 1.1.1b1 → 1.1.1 2021-12-15 16:10:01 +03:00
Викторов Андрей Германович
cb14f9aa2a remove port in hub.binary_sesnors check when processing inbound message from controller 2021-12-15 16:08:06 +03:00
andvikt
b908068315 new config adressation 2021-12-01 18:49:37 +03:00
andvikt
c11de5c2b9 Bump version: 1.1.1b0 → 1.1.1b1 2021-11-07 12:38:18 +03:00
andvikt
679b53bbd3 new config adressation 2021-11-07 12:38:02 +03:00
Викторов Андрей Германович
2c2b3aab74 Bump version: 1.1.0 → 1.1.1b0 2021-11-03 10:24:29 +03:00
Викторов Андрей Германович
a77794dff7 fix sht31 updating issue
fix filters positive float
2021-11-03 10:24:21 +03:00
andvikt
ebb513b83d new config adressation 2021-10-29 21:14:50 +03:00
andvikt
f5519a595d Bump version: 1.1.0b0 → 1.1.0 2021-10-29 21:05:14 +03:00
andvikt
ee26759003 Bump version: 1.0.10b20 → 1.1.0b0 2021-10-29 21:04:30 +03:00
andvikt
8869ad9cee new config adressation 2021-10-29 20:14:18 +03:00
andvikt
27f1e05a3a new config adressation 2021-10-29 20:13:31 +03:00
andvikt
7fdc2fc9ff new config adressation 2021-10-29 20:12:59 +03:00
andvikt
28bf4393f0 Bump version: 1.0.10b19 → 1.0.10b20 2021-10-29 19:53:01 +03:00
andvikt
5ecb246eff fix brightness 2021-10-29 19:52:10 +03:00
14 changed files with 201 additions and 122 deletions

View File

@@ -1,5 +1,5 @@
[bumpversion] [bumpversion]
current_version = 1.0.10b19 current_version = 1.1.4
parse = (?P<major>\d+)(\.(?P<minor>\d+))(\.(?P<patch>\d+))(?P<release>[bf]*)(?P<build>\d*) parse = (?P<major>\d+)(\.(?P<minor>\d+))(\.(?P<patch>\d+))(?P<release>[bf]*)(?P<build>\d*)
commit = True commit = True
tag = True tag = True

View File

@@ -1,6 +1,7 @@
"""The mega integration.""" """The mega integration."""
import asyncio import asyncio
import logging import logging
import typing
from functools import partial from functools import partial
import voluptuous as vol import voluptuous as vol
@@ -17,7 +18,8 @@ from .const import DOMAIN, CONF_INVERT, CONF_RELOAD, PLATFORMS, CONF_PORTS, CONF
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_FORCE_I2C_SCAN, CONF_HEX_TO_FLOAT, \ CONF_CONV_TEMPLATE, CONF_ALL, CONF_FORCE_D, CONF_DEF_RESPONSE, CONF_FORCE_I2C_SCAN, CONF_HEX_TO_FLOAT, \
RGB_COMBINATIONS, CONF_WS28XX, CONF_ORDER, CONF_SMOOTH, CONF_LED, CONF_WHITE_SEP, CONF_CHIP, CONF_RANGE, \ RGB_COMBINATIONS, CONF_WS28XX, CONF_ORDER, CONF_SMOOTH, CONF_LED, CONF_WHITE_SEP, CONF_CHIP, CONF_RANGE, \
CONF_FILTER_VALUES, CONF_FILTER_SCALE, CONF_FILTER_LOW, CONF_FILTER_HIGH, CONF_FILL_NA CONF_FILTER_VALUES, CONF_FILTER_SCALE, CONF_FILTER_LOW, CONF_FILTER_HIGH, CONF_FILL_NA, CONF_MEGA_ID, CONF_ADDR, \
CONF_1WBUS
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
@@ -83,10 +85,10 @@ CUSTOMIZE_PORT = {
vol.Optional(CONF_VALUE_TEMPLATE): cv.template, vol.Optional(CONF_VALUE_TEMPLATE): cv.template,
vol.Optional(CONF_FORCE_I2C_SCAN): bool, vol.Optional(CONF_FORCE_I2C_SCAN): bool,
vol.Optional(CONF_HEX_TO_FLOAT): bool, vol.Optional(CONF_HEX_TO_FLOAT): bool,
vol.Optional(CONF_FILTER_VALUES): [cv.positive_float], vol.Optional(CONF_FILTER_VALUES): [vol.Coerce(float)],
vol.Optional(CONF_FILTER_SCALE): cv.positive_float, vol.Optional(CONF_FILTER_SCALE): vol.Coerce(float),
vol.Optional(CONF_FILTER_LOW): cv.positive_float, vol.Optional(CONF_FILTER_LOW): vol.Coerce(float),
vol.Optional(CONF_FILTER_HIGH): cv.positive_float, vol.Optional(CONF_FILTER_HIGH): vol.Coerce(float),
vol.Optional(CONF_SMOOTH): cv.time_period_seconds, vol.Optional(CONF_SMOOTH): cv.time_period_seconds,
# vol.Optional(CONF_RANGE): vol.ExactSequence([int, int]), TODO: сделать отбрасывание "плохих" значений # vol.Optional(CONF_RANGE): vol.ExactSequence([int, int]), TODO: сделать отбрасывание "плохих" значений
vol.Optional(str): { vol.Optional(str): {
@@ -107,6 +109,11 @@ def extender(x):
else: else:
raise ValueError('must has "e" in port name') raise ValueError('must has "e" in port name')
OWBUS = vol.Schema({
vol.Required(CONF_PORT): vol.Any(vol.Coerce(int), vol.Coerce(str)),
vol.Required(CONF_MEGA_ID): vol.Coerce(str),
vol.Required(CONF_ADDR): [str],
})
CONFIG_SCHEMA = vol.Schema( CONFIG_SCHEMA = vol.Schema(
{ {
@@ -133,7 +140,8 @@ CONFIG_SCHEMA = vol.Schema(
vol.Optional(CONF_FILTER_SCALE): cv.positive_float, vol.Optional(CONF_FILTER_SCALE): cv.positive_float,
vol.Optional(CONF_FILTER_LOW): cv.positive_float, vol.Optional(CONF_FILTER_LOW): cv.positive_float,
vol.Optional(CONF_FILTER_HIGH): cv.positive_float, vol.Optional(CONF_FILTER_HIGH): cv.positive_float,
} },
vol.Optional(CONF_1WBUS): [OWBUS]
} }
}, },
extra=vol.ALLOW_EXTRA, extra=vol.ALLOW_EXTRA,

View File

@@ -63,7 +63,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 = 25 VERSION = 26
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):

View File

@@ -50,6 +50,8 @@ CONF_FILTER_VALUES = 'filter_values'
CONF_FILTER_SCALE = 'filter_scale' CONF_FILTER_SCALE = 'filter_scale'
CONF_FILTER_LOW = 'filter_low' CONF_FILTER_LOW = 'filter_low'
CONF_FILTER_HIGH = 'filter_high' CONF_FILTER_HIGH = 'filter_high'
CONF_1WBUS = '1wbus'
CONF_ADDR = 'addr'
PLATFORMS = [ PLATFORMS = [
"light", "light",
"switch", "switch",

View File

@@ -86,7 +86,6 @@ class BaseMegaEntity(CoordinatorEntity, RestoreEntity):
self.mega.ds2413_ports |= {self.port} self.mega.ds2413_ports |= {self.port}
super().__init__(coordinator=mega.updater) super().__init__(coordinator=mega.updater)
@property @property
def is_ws(self): def is_ws(self):
return False return False
@@ -131,9 +130,6 @@ class BaseMegaEntity(CoordinatorEntity, RestoreEntity):
return {} return {}
if self._customize is None: if self._customize is None:
c_entity_id = self.hass.data.get(DOMAIN, {}).get(CONF_CUSTOM).get('entities', {}).get(self.entity_id, {}) c_entity_id = self.hass.data.get(DOMAIN, {}).get(CONF_CUSTOM).get('entities', {}).get(self.entity_id, {})
self.lg.debug(
'customize %s with %s', self.entity_id, c_entity_id
)
c = self.hass.data.get(DOMAIN, {}).get(CONF_CUSTOM) or {} c = self.hass.data.get(DOMAIN, {}).get(CONF_CUSTOM) or {}
c = c.get(self._mega_id) or {} c = c.get(self._mega_id) or {}
c = c.get(self.port) or {} c = c.get(self.port) or {}
@@ -165,15 +161,12 @@ class BaseMegaEntity(CoordinatorEntity, RestoreEntity):
], ],
"name": f'{self._mega_id} port {pt_idx}' if not isinstance(self.port, list) else f'{self._mega_id} {pt_idx}', "name": f'{self._mega_id} port {pt_idx}' if not isinstance(self.port, list) else f'{self._mega_id} {pt_idx}',
"manufacturer": 'ab-log.ru', "manufacturer": 'ab-log.ru',
# "model": self.light.productname,
"sw_version": self.mega.fw, "sw_version": self.mega.fw,
"via_device": (DOMAIN, self._mega_id), "via_device": (DOMAIN, self._mega_id),
} }
@property @property
def lg(self) -> logging.Logger: def lg(self) -> logging.Logger:
# if self._lg is None:
# self._lg = self.mega.lg.getChild(self._name or self.unique_id)
return _LOGGER return _LOGGER
@property @property
@@ -430,6 +423,8 @@ class MegaOutPort(MegaPushEntity):
)) ))
def _calc_brightness(self, brightness): def _calc_brightness(self, brightness):
if brightness is None:
brightness = 0
pct = brightness / 255 pct = brightness / 255
pct = max((0, pct)) pct = max((0, pct))
pct = min((pct, 1)) pct = min((pct, 1))
@@ -439,6 +434,8 @@ class MegaOutPort(MegaPushEntity):
return brightness return brightness
def _cal_reverse_brightness(self, brightness): def _cal_reverse_brightness(self, brightness):
if brightness is None:
brightness = 0
l, h = self.range l, h = self.range
d = h - l d = h - l
pct = (brightness - l) / d pct = (brightness - l) / d

View File

@@ -134,7 +134,8 @@ class MegaView(HomeAssistantView):
if ret == 'd' and act: if ret == 'd' and act:
await hub.request(cmd=act.replace(':3', f':{v}')) await hub.request(cmd=act.replace(':3', f':{v}'))
ret = 'd' if hub.force_d else '' ret = 'd' if hub.force_d else ''
elif port in hub.binary_sensors: else:
# elif port in hub.binary_sensors:
hub.values[port] = data hub.values[port] = data
for cb in self.callbacks[hub.id][port]: for cb in self.callbacks[hub.id][port]:
cb(data) cb(data)

View File

@@ -427,7 +427,7 @@ class MegaD:
def subscribe(self, port, callback): def subscribe(self, port, callback):
port = int_ignore(port) port = int_ignore(port)
self.lg.debug( self.lg.debug(
f'subscribe %s %s', port, str(callback) f'subscribe %s', port,
) )
self.http.callbacks[self.id][port].append(callback) self.http.callbacks[self.id][port].append(callback)

View File

@@ -1,4 +1,5 @@
from dataclasses import dataclass, field import typing
from dataclasses import dataclass, field, astuple
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 (
@@ -15,7 +16,15 @@ from homeassistant.const import (
) )
from collections import namedtuple from collections import namedtuple
DeviceType = namedtuple('DeviceType', 'device_class,unit_of_measurement,suffix') # DeviceType = namedtuple('DeviceType', 'device_class,unit_of_measurement,suffix')
@dataclass
class DeviceType:
device_class: typing.Optional[str] = None
unit_of_measurement: typing.Optional[str] = None
suffix: typing.Optional[str] = None
delay: typing.Optional[float] = None
def parse_scan_page(page: str): def parse_scan_page(page: str):
@@ -32,39 +41,40 @@ def parse_scan_page(page: str):
continue continue
classes = i2c_classes.get(dev, []) classes = i2c_classes.get(dev, [])
for i, c in enumerate(classes): for i, c in enumerate(classes):
_params = params.copy()
if c is Skip: if c is Skip:
continue continue
elif c is Request: elif c is Request:
req.append(params) req.append(_params)
continue continue
elif isinstance(c, Request): elif isinstance(c, Request):
if c.delay: if c.delay:
params = params.copy() _params['delay'] = c.delay
params['delay'] = c.delay req.append(_params)
req.append(params)
continue continue
elif isinstance(c, DeviceType): elif isinstance(c, DeviceType):
c, m, suffix = c c, m, suffix, delay = astuple(c)
if delay is not None:
_params['delay'] = delay
else: else:
continue continue
suffix = suffix or c suffix = suffix or c
if 'addr' in params: if 'addr' in _params:
suffix += f"_{params['addr']}" if suffix else str(params['addr']) suffix += f"_{_params['addr']}" if suffix else str(_params['addr'])
if suffix: if suffix:
_dev = f'{dev}_{suffix}' _dev = f'{dev}_{suffix}'
else: else:
_dev = dev _dev = dev
params = params.copy()
if i > 0: if i > 0:
params['i2c_par'] = i _params['i2c_par'] = i
ret.append({ ret.append({
'id_suffix': _dev, 'id_suffix': _dev,
'device_class': c, 'device_class': c,
'params': params, 'params': _params,
'unit_of_measurement': m, 'unit_of_measurement': m,
}) })
req.append(params) req.append(_params)
return req, ret return req, ret
@@ -83,7 +93,7 @@ i2c_classes = {
DeviceType(DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS, None), DeviceType(DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS, None),
], ],
'sht31': [ 'sht31': [
DeviceType(DEVICE_CLASS_HUMIDITY, PERCENTAGE, None), DeviceType(DEVICE_CLASS_HUMIDITY, PERCENTAGE, None, delay=1.5),
DeviceType(DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS, None), DeviceType(DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS, None),
], ],
'max44009': [ 'max44009': [
@@ -115,7 +125,7 @@ i2c_classes = {
], ],
'ptsensor': [ 'ptsensor': [
Skip, Skip,
Request(delay=1), # запрос на измерение Request(delay=3), # запрос на измерение
DeviceType(DEVICE_CLASS_PRESSURE, PRESSURE_BAR, None), DeviceType(DEVICE_CLASS_PRESSURE, PRESSURE_BAR, None),
DeviceType(DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS, None), DeviceType(DEVICE_CLASS_TEMPERATURE, TEMP_CELSIUS, None),
], ],

View File

@@ -1,4 +1,6 @@
"""Platform for light integration.""" """Platform for light integration."""
from __future__ import annotations
import asyncio import asyncio
import logging import logging
import typing import typing
@@ -14,8 +16,8 @@ from homeassistant.components.light import (
SUPPORT_BRIGHTNESS, SUPPORT_BRIGHTNESS,
LightEntity, LightEntity,
SUPPORT_TRANSITION, SUPPORT_TRANSITION,
SUPPORT_COLOR, SUPPORT_COLOR, ColorMode, LightEntityFeature,
SUPPORT_WHITE_VALUE # SUPPORT_WHITE_VALUE
) )
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ( from homeassistant.const import (
@@ -116,6 +118,7 @@ class MegaRGBW(LightEntity, BaseMegaEntity):
self._is_on = None self._is_on = None
self._brightness = None self._brightness = None
self._hs_color = None self._hs_color = None
self._rgb_color: tuple[int, int, int] | None = None
self._white_value = None self._white_value = None
self._task: asyncio.Task = None self._task: asyncio.Task = None
self._restore = None self._restore = None
@@ -143,10 +146,34 @@ class MegaRGBW(LightEntity, BaseMegaEntity):
def is_ws(self): def is_ws(self):
return self.customize.get(CONF_WS28XX) return self.customize.get(CONF_WS28XX)
@property
def supported_color_modes(self) -> set[ColorMode] | set[str] | None:
return {
ColorMode.BRIGHTNESS,
ColorMode.RGB if len(self.port) != 4 else ColorMode.RGBW
}
@property
def color_mode(self) -> ColorMode | str | None:
if len(self.port) == 4:
return ColorMode.RGBW
else:
return ColorMode.RGB
@property @property
def white_value(self): def white_value(self):
if self.supported_features & SUPPORT_WHITE_VALUE: # if self.supported_features & SUPPORT_WHITE_VALUE:
return float(self.get_attribute('white_value', 0)) return float(self.get_attribute('white_value', 0))
@property
def rgb_color(self) -> tuple[int, int, int] | None:
return self._rgb_color
@property
def rgbw_color(self) -> tuple[int, int, int, int] | None:
if self._white_value is not None and self._rgb_color is not None:
return (*self._rgb_color, self._white_value)
@property @property
def brightness(self): def brightness(self):
@@ -162,12 +189,7 @@ class MegaRGBW(LightEntity, BaseMegaEntity):
@property @property
def supported_features(self): def supported_features(self):
return ( return LightEntityFeature.TRANSITION
SUPPORT_BRIGHTNESS |
SUPPORT_TRANSITION |
SUPPORT_COLOR |
(SUPPORT_WHITE_VALUE if len(self.port) == 4 else 0)
)
def get_rgbw(self): def get_rgbw(self):
if not self.is_on: if not self.is_on:
@@ -225,6 +247,7 @@ class MegaRGBW(LightEntity, BaseMegaEntity):
for item, value in kwargs.items(): for item, value in kwargs.items():
setattr(self, f'_{item}', value) setattr(self, f'_{item}', value)
_after = self.get_rgbw() _after = self.get_rgbw()
self._rgb_color = tuple(_after[:3])
if transition is None: if transition is None:
transition = self.smooth.total_seconds() transition = self.smooth.total_seconds()
ratio = self.calc_speed_ratio(_before, _after) ratio = self.calc_speed_ratio(_before, _after)

View File

@@ -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": "v1.0.10b19" "version": "v1.1.4"
} }

View File

@@ -6,7 +6,7 @@ import struct
from homeassistant.components.sensor import ( from homeassistant.components.sensor import (
PLATFORM_SCHEMA as SENSOR_SCHEMA, PLATFORM_SCHEMA as SENSOR_SCHEMA,
DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_TEMPERATURE,
DEVICE_CLASS_HUMIDITY DEVICE_CLASS_HUMIDITY, SensorEntity
) )
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ( from homeassistant.const import (
@@ -108,30 +108,34 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, asyn
async_add_devices(devices) async_add_devices(devices)
class FilterBadValues(MegaPushEntity): class FilterBadValues(MegaPushEntity, SensorEntity):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self._prev_value = None self._prev_value = None
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
def filter_value(self, value): def filter_value(self, value):
if value \ try:
in self.filter_values \ if value \
or (self.filter_low is not None and value < self.filter_low) \ in self.filter_values \
or (self.filter_high is not None and value > self.filter_high) \ or (self.filter_low is not None and value < self.filter_low) \
or ( or (self.filter_high is not None and value > self.filter_high) \
self._prev_value is not None or (
and self.filter_scale is not None self._prev_value is not None
and ( and self.filter_scale is not None
abs(value - self._prev_value) / self._prev_value > self.filter_scale and (
) abs(value - self._prev_value) / self._prev_value > self.filter_scale
): )
if self.fill_na == 'last': ):
value = self._prev_value if self.fill_na == 'last':
else: value = self._prev_value
value = None else:
self._prev_value = value value = None
return value self._prev_value = value
return value
except Exception as exc:
lg.exception(f'while parsing value')
return None
@property @property
def filter_values(self): def filter_values(self):
@@ -191,28 +195,32 @@ class MegaI2C(FilterBadValues):
return self._device_class return self._device_class
@property @property
def unit_of_measurement(self): def native_unit_of_measurement(self):
return self._unit_of_measurement return self._unit_of_measurement
@property @property
def state(self): def native_value(self):
ret = self.mega.values.get(self._params)
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))
try: try:
ret = float(ret) ret = self.mega.values.get(self._params)
if tmpl is not None and self.hass is not None: if self.customize.get(CONF_HEX_TO_FLOAT):
tmpl.hass = self.hass try:
ret = tmpl.async_render({'value': ret}) ret = struct.unpack('!f', bytes.fromhex(ret))[0]
except: except:
ret = ret self.lg.warning(f'could not convert {ret} form hex to float')
ret = self.filter_value(ret) tmpl: Template = self.customize.get(CONF_CONV_TEMPLATE, self.customize.get(CONF_VALUE_TEMPLATE))
if ret is not None: try:
return str(ret) ret = float(ret)
if tmpl is not None and self.hass is not None:
tmpl.hass = self.hass
ret = tmpl.async_render({'value': ret})
except:
ret = ret
ret = self.filter_value(ret)
if ret is not None:
return str(ret)
except Exception:
lg.exception('while getting value')
return None
@property @property
def device_class(self): def device_class(self):
@@ -244,7 +252,7 @@ class Mega1WSensor(FilterBadValues):
self.prev_value = None self.prev_value = None
@property @property
def unit_of_measurement(self): def native_unit_of_measurement(self):
_u = self.customize.get(CONF_UNIT_OF_MEASUREMENT, None) _u = self.customize.get(CONF_UNIT_OF_MEASUREMENT, None)
if _u is None: if _u is None:
return self._unit_of_measurement return self._unit_of_measurement
@@ -275,49 +283,53 @@ class Mega1WSensor(FilterBadValues):
return self._device_class return self._device_class
@property @property
def state(self): def native_value(self):
ret = None try:
if not hasattr(self, 'key'): ret = None
return None if not hasattr(self, 'key'):
if self.key: return None
try: if self.key:
ret = self.mega.values.get(self.port, {}) try:
if isinstance(ret, dict): ret = self.mega.values.get(self.port, {})
ret = ret.get('value', {})
if isinstance(ret, dict): if isinstance(ret, dict):
ret = ret.get(self.key) ret = ret.get('value', {})
except: if isinstance(ret, dict):
self.lg.error(self.mega.values.get(self.port, {}).get('value', {})) ret = ret.get(self.key)
return except:
else: self.lg.error(self.mega.values.get(self.port, {}).get('value', {}))
ret = self.mega.values.get(self.port, {}).get('value') return
if ret is None and self.fill_na == 'fill_na' and self.prev_value is not None: else:
ret = self.prev_value ret = self.mega.values.get(self.port, {}).get('value')
elif ret is None and self.fill_na == 'fill_na' and self._state is not None: if ret is None and self.fill_na == 'fill_na' and self.prev_value is not None:
ret = self._state.state ret = self.prev_value
try: elif ret is None and self.fill_na == 'fill_na' and self._state is not None:
ret = float(ret) ret = self._state.state
ret = str(ret)
except:
self.lg.debug(f'could not convert to float "{ret}"')
ret = self.prev_value
if self.customize.get(CONF_HEX_TO_FLOAT):
try: try:
ret = struct.unpack('!f', bytes.fromhex(ret))[0] ret = float(ret)
ret = str(ret)
except: except:
self.lg.warning(f'could not convert {ret} form hex to float') self.lg.debug(f'could not convert to float "{ret}"')
tmpl: Template = self.customize.get(CONF_CONV_TEMPLATE, self.customize.get(CONF_VALUE_TEMPLATE)) ret = self.prev_value
try: if self.customize.get(CONF_HEX_TO_FLOAT):
ret = float(ret) try:
if tmpl is not None and self.hass is not None: ret = struct.unpack('!f', bytes.fromhex(ret))[0]
tmpl.hass = self.hass except:
ret = tmpl.async_render({'value': ret}) self.lg.warning(f'could not convert {ret} form hex to float')
except: tmpl: Template = self.customize.get(CONF_CONV_TEMPLATE, self.customize.get(CONF_VALUE_TEMPLATE))
pass try:
ret = self.filter_value(ret) ret = float(ret)
self.prev_value = ret if tmpl is not None and self.hass is not None:
if ret is not None: tmpl.hass = self.hass
return str(ret) ret = tmpl.async_render({'value': ret})
except:
pass
ret = self.filter_value(ret)
self.prev_value = ret
if ret is not None:
return str(ret)
except Exception:
lg.exception('while parsing state')
return None
@property @property
def name(self): def name(self):

View File

@@ -50,6 +50,10 @@ class PriorityLock(asyncio.Lock):
finally: finally:
self.release() self.release()
@property
def _loop(self):
return asyncio.get_event_loop()
async def acquire(self, priority=0) -> bool: async def acquire(self, priority=0) -> bool:
"""Acquire a lock. """Acquire a lock.

View File

@@ -1,6 +1,25 @@
С помощью yaml-конфигурации можно кастомизировать ваши устройства. С помощью yaml-конфигурации можно кастомизировать ваши устройства.
## Основное ## Основное
!!! note "Альтернативная адресация"
Начиная с v1.1.0 большинство параметров объектов можно записывать в более простой и понятной форме:
```yaml
mega: # название интеграции
entities:
sensor.some_sensor: #entity_id как в интерфейсе HA
filter_low: 20
filter_high: 40
```
Рекомендуется пользоваться именно этим способом, тк он более логичный и простой.
Некоторые параметры по своей логике (влияют на entity_id) не могут быть записаны таким образом, среди них:
- domain
- skip
- name
Остальные параметры можно записывать используя новый entities
Конфиг записывается стандартным образом в файл `configuration.yaml`, начинаем с Конфиг записывается стандартным образом в файл `configuration.yaml`, начинаем с
указания названия интеграции: указания названия интеграции:
```yaml hl_lines="1" ```yaml hl_lines="1"
@@ -64,6 +83,9 @@ mega:
диммера набирает от 0 до 100% диммера набирает от 0 до 100%
- **range** (list[int, int], [0, 255]), *начиная с версии 1.1.0*: границы диммирования в абсолютных единицах 0..255. При диммировании 1% - **range** (list[int, int], [0, 255]), *начиная с версии 1.1.0*: границы диммирования в абсолютных единицах 0..255. При диммировании 1%
будет равен левой границе, 100% - правой. будет равен левой границе, 100% - правой.
```yaml
range: [20, 200]
```
[Подробнее про плавное диммирование](smooth.md) [Подробнее про плавное диммирование](smooth.md)
### MegaD-16R-XT, MegaD-16PWM ### MegaD-16R-XT, MegaD-16PWM
Порты расширителей MegaD-16R-XT, MegaD-16PWM конфигурируются аналогично обычным реле и диммерам, но адресация порта Порты расширителей MegaD-16R-XT, MegaD-16PWM конфигурируются аналогично обычным реле и диммерам, но адресация порта

View File

@@ -22,7 +22,7 @@ nav:
- Конфигурация: - Конфигурация:
- В интерфейсе: settings.md - В интерфейсе: settings.md
- Настройка обратной связи: http.md - Настройка обратной связи: http.md
- YAML-конфиг: yaml.md - Кастомизация: yaml.md
- i2c: i2c.md - i2c: i2c.md
- Плавные переходы: smooth.md - Плавные переходы: smooth.md
- Автоматизация: - Автоматизация: