Compare commits

...

13 Commits

Author SHA1 Message Date
Andrey
39642700ca fix force_d 2021-02-15 19:05:00 +03:00
Andrey
07589e8e3a edit readme 2021-02-11 17:35:58 +03:00
Andrey
5a6903c67e fix config bug 2021-02-11 16:03:10 +03:00
Andrey
6758fd8d8e add server response in mqtt mode 2021-02-11 12:19:17 +03:00
Andrey
a9896c82fe add server response in mqtt mode 2021-02-11 12:00:01 +03:00
Andrey
5ed0b74eff add server response in mqtt mode 2021-02-11 11:57:17 +03:00
Andrey
4fccb23c39 remove port from command sendings 2021-02-10 14:05:16 +03:00
Andrey
03e4d3ff7e Merge remote-tracking branch 'origin/master' 2021-02-09 22:15:27 +03:00
Andrey
7907e0cd85 edit readme 2021-02-09 22:04:39 +03:00
andvikt
5211ee5330 Merge pull request #8 from r7sa/master
Улучшение поддержки I2C устройств

Спасибо большое!
2021-02-09 21:35:05 +03:00
Andrey
4e0f1dddcb add readme about srv loop 2021-02-09 21:30:26 +03:00
Sergey
742a0a9a09 - добавлены два новых класса устройства (давление, освещённость)
- улучшена поддержка I2C устройств, возвращающих только одно значение
2021-02-07 12:29:40 +03:00
Andrey
59443989a0 add poll outs 2021-02-06 09:43:10 +03:00
15 changed files with 147 additions and 57 deletions

View File

@@ -17,7 +17,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_CONV_TEMPLATE, CONF_ALL, CONF_FORCE_D
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
@@ -28,7 +28,9 @@ CONFIG_SCHEMA = vol.Schema(
{ {
DOMAIN: { DOMAIN: {
vol.Optional(CONF_ALLOW_HOSTS): [str], vol.Optional(CONF_ALLOW_HOSTS): [str],
# vol.Optional(CONF_FORCE_D, description='Принудительно слать d после срабатывания входа', default=False): bool,
vol.Required(str, description='id меги из веб-интерфейса'): { vol.Required(str, description='id меги из веб-интерфейса'): {
vol.Optional(CONF_FORCE_D, description='Принудительно слать d после срабатывания входа', default=False): bool,
vol.Optional(int, description='номер порта'): { vol.Optional(int, description='номер порта'): {
vol.Optional(CONF_SKIP, description='исключить порт из сканирования', default=False): bool, vol.Optional(CONF_SKIP, description='исключить порт из сканирования', default=False): bool,
vol.Optional(CONF_INVERT, default=False): bool, vol.Optional(CONF_INVERT, default=False): bool,
@@ -44,7 +46,7 @@ CONFIG_SCHEMA = vol.Schema(
CONF_RESPONSE_TEMPLATE, CONF_RESPONSE_TEMPLATE,
description='шаблон ответа когда на этот порт приходит' description='шаблон ответа когда на этот порт приходит'
'сообщение из меги '): cv.template, 'сообщение из меги '): cv.template,
vol.Optional(CONF_ACTION): cv.script_action, vol.Optional(CONF_ACTION): cv.script_action, # пока не реализовано
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
} }
@@ -65,6 +67,7 @@ async def async_setup(hass: HomeAssistant, config: dict):
"""YAML-конфигурация содержит только кастомизации портов""" """YAML-конфигурация содержит только кастомизации портов"""
hass.data[DOMAIN] = {CONF_CUSTOM: config.get(DOMAIN, {})} hass.data[DOMAIN] = {CONF_CUSTOM: config.get(DOMAIN, {})}
hass.data[DOMAIN][CONF_HTTP] = view = MegaView(cfg=config.get(DOMAIN, {})) hass.data[DOMAIN][CONF_HTTP] = view = MegaView(cfg=config.get(DOMAIN, {}))
hass.data[DOMAIN][CONF_ALL] = {}
view.allowed_hosts |= set(config.get(DOMAIN, {}).get(CONF_ALLOW_HOSTS, [])) view.allowed_hosts |= set(config.get(DOMAIN, {}).get(CONF_ALLOW_HOSTS, []))
hass.http.register_view(view) hass.http.register_view(view)
hass.services.async_register( hass.services.async_register(
@@ -80,7 +83,7 @@ async def async_setup(hass: HomeAssistant, config: dict):
) )
hass.services.async_register( hass.services.async_register(
DOMAIN, 'run_cmd', partial(_run_cmd, hass), schema=vol.Schema({ DOMAIN, 'run_cmd', partial(_run_cmd, hass), schema=vol.Schema({
vol.Required('port'): int, vol.Optional('port'): int,
vol.Required('cmd'): str, vol.Required('cmd'): str,
vol.Optional('mega_id'): str, vol.Optional('mega_id'): str,
}) })
@@ -115,6 +118,7 @@ async def _add_mega(hass: HomeAssistant, entry: ConfigEntry):
hub = await get_hub(hass, entry) hub = await get_hub(hass, entry)
hass.data[DOMAIN][id] = hass.data[DOMAIN]['__def'] = hub hass.data[DOMAIN][id] = hass.data[DOMAIN]['__def'] = hub
hass.data[DOMAIN][entry.data.get(CONF_HOST)] = hub hass.data[DOMAIN][entry.data.get(CONF_HOST)] = hub
hass.data[DOMAIN][CONF_ALL][id] = hub
if not await hub.authenticate(): if not await hub.authenticate():
raise Exception("not authentificated") raise Exception("not authentificated")
mid = await hub.get_mqtt_id() mid = await hub.get_mqtt_id()
@@ -164,6 +168,7 @@ async def async_remove_entry(hass, entry) -> None:
_LOGGER.debug(f'remove {id}') _LOGGER.debug(f'remove {id}')
_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)
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()
@@ -215,7 +220,7 @@ async def _get_port(hass: HomeAssistant, call: ServiceCall):
for x in port: for x in port:
await hub.get_port(x) await hub.get_port(x)
else: else:
for hub in hass.data[DOMAIN].values(): for hub in hass.data[DOMAIN][CONF_ALL].values():
if not isinstance(hub, MegaD): if not isinstance(hub, MegaD):
continue continue
if port is None: if port is None:
@@ -229,12 +234,11 @@ async def _get_port(hass: HomeAssistant, call: ServiceCall):
@bind_hass @bind_hass
async def _run_cmd(hass: HomeAssistant, call: ServiceCall): async def _run_cmd(hass: HomeAssistant, call: ServiceCall):
port = call.data.get('port')
mega_id = call.data.get('mega_id') mega_id = call.data.get('mega_id')
cmd = call.data.get('cmd') cmd = call.data.get('cmd')
if mega_id: if mega_id:
hub: MegaD = hass.data[DOMAIN][mega_id] hub: MegaD = hass.data[DOMAIN][mega_id]
await hub.send_command(port=port, cmd=cmd) await hub.request(cmd=cmd)
else: else:
for hub in hass.data[DOMAIN].values(): for hub in hass.data[DOMAIN].values():
await hub.send_command(port=port, cmd=cmd) await hub.request(cmd=cmd)

View File

@@ -16,7 +16,8 @@ from homeassistant.const import (
CONF_ENTITY_ID, CONF_ENTITY_ID,
) )
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from .const import EVENT_BINARY_SENSOR, DOMAIN, CONF_CUSTOM, CONF_SKIP, CONF_INVERT from homeassistant.helpers.template import Template
from .const import EVENT_BINARY_SENSOR, DOMAIN, CONF_CUSTOM, CONF_SKIP, CONF_INVERT, CONF_RESPONSE_TEMPLATE
from .entities import MegaPushEntity from .entities import MegaPushEntity
from .hub import MegaD from .hub import MegaD
@@ -89,4 +90,20 @@ class MegaBinarySensor(BinarySensorEntity, MegaPushEntity):
def _update(self, payload: dict): def _update(self, payload: dict):
self.mega.values[self.port] = payload self.mega.values[self.port] = payload
if not self.mega.mqtt_inputs:
return
template: Template = self.customize.get(CONF_RESPONSE_TEMPLATE, None)
if template is not None:
template.hass = self.hass
ret = template.async_render(payload)
self.mega.lg.debug(f'response: %s', ret)
self.hass.async_create_task(
self.mega.request(pt=self.port, cmd=ret)
)
elif self.mega.force_d:
self.mega.lg.debug(f'response d')
self.hass.async_create_task(
self.mega.request(pt=self.port, cmd='d')
)

View File

@@ -10,7 +10,7 @@ from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_HOST, CONF_ID, CONF_PASSWORD, CONF_SCAN_INTERVAL from homeassistant.const import CONF_HOST, CONF_ID, CONF_PASSWORD, CONF_SCAN_INTERVAL
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 # pylint:disable=unused-import CONF_NPORTS, CONF_UPDATE_ALL, CONF_POLL_OUTS # pylint:disable=unused-import
from .hub import MegaD from .hub import MegaD
from . import exceptions from . import exceptions
@@ -18,10 +18,11 @@ _LOGGER = logging.getLogger(__name__)
STEP_USER_DATA_SCHEMA = vol.Schema( STEP_USER_DATA_SCHEMA = vol.Schema(
{ {
vol.Required(CONF_ID, default='def'): str, vol.Required(CONF_ID, default='mega'): str,
vol.Required(CONF_HOST, default="192.168.0.14"): str, vol.Required(CONF_HOST, default="192.168.0.14"): str,
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_PORT_TO_SCAN, default=0): int, vol.Optional(CONF_PORT_TO_SCAN, default=0): int,
vol.Optional(CONF_MQTT_INPUTS, default=True): bool, vol.Optional(CONF_MQTT_INPUTS, default=True): bool,
vol.Optional(CONF_NPORTS, default=37): int, vol.Optional(CONF_NPORTS, default=37): int,
@@ -131,6 +132,7 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
step_id="init", step_id="init",
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_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,

View File

@@ -16,6 +16,7 @@ CONF_INVERT = 'invert'
CONF_PORTS = 'ports' CONF_PORTS = 'ports'
CONF_CUSTOM = '__custom' CONF_CUSTOM = '__custom'
CONF_HTTP = '__http' CONF_HTTP = '__http'
CONF_ALL = '__all'
CONF_SKIP = 'skip' CONF_SKIP = 'skip'
CONF_MQTT_INPUTS = 'mqtt_inputs' CONF_MQTT_INPUTS = 'mqtt_inputs'
CONF_NPORTS = 'nports' CONF_NPORTS = 'nports'
@@ -25,6 +26,8 @@ CONF_UPDATE_ALL = 'update_all'
CONF_GET_VALUE = 'get_value' CONF_GET_VALUE = 'get_value'
CONF_ALLOW_HOSTS = 'allow_hosts' CONF_ALLOW_HOSTS = 'allow_hosts'
CONF_CONV_TEMPLATE = 'conv_template' CONF_CONV_TEMPLATE = 'conv_template'
CONF_POLL_OUTS = 'poll_outs'
CONF_FORCE_D = 'force_d'
PLATFORMS = [ PLATFORMS = [
"light", "light",
"switch", "switch",
@@ -40,5 +43,6 @@ LONG = 'long'
RELEASE = 'release' RELEASE = 'release'
LONG_RELEASE = 'long_release' LONG_RELEASE = 'long_release'
PRESS = 'press' PRESS = 'press'
LUX = 'lux'
SINGLE_CLICK = 'single' SINGLE_CLICK = 'single'
DOUBLE_CLICK = 'double' DOUBLE_CLICK = 'double'

View File

@@ -246,16 +246,15 @@ class MegaOutPort(MegaPushEntity):
cmd = brightness cmd = brightness
else: else:
cmd = 1 if not self.invert else 0 cmd = 1 if not self.invert else 0
await self.mega.send_command(self.port, f"{self.port}:{cmd}") await self.mega.request(cmd=f"{self.port}:{cmd}")
self.mega.values[self.port] = {'value': cmd} self.mega.values[self.port] = {'value': cmd}
await self.get_state() await self.get_state()
async def async_turn_off(self, **kwargs) -> None: async def async_turn_off(self, **kwargs) -> None:
cmd = "0" if not self.invert else "1" cmd = "0" if not self.invert else "1"
await self.mega.send_command(self.port, f"{self.port}:{cmd}") await self.mega.request(cmd=f"{self.port}:{cmd}")
self.mega.values[self.port] = {'value': cmd} self.mega.values[self.port] = {'value': cmd}
await self.get_state() await self.get_state()

View File

@@ -15,3 +15,7 @@ class DuplicateId(exceptions.HomeAssistantError):
class InvalidAuth(exceptions.HomeAssistantError): class InvalidAuth(exceptions.HomeAssistantError):
"""Error to indicate there is invalid auth.""" """Error to indicate there is invalid auth."""
class NoPort(Exception):
pass

View File

@@ -8,16 +8,15 @@ from aiohttp.web_request import Request
from aiohttp.web_response import Response from aiohttp.web_response import Response
from homeassistant.helpers.template import Template from homeassistant.helpers.template import Template
from .const import EVENT_BINARY_SENSOR, DOMAIN, CONF_RESPONSE_TEMPLATE
from homeassistant.components.http import HomeAssistantView from homeassistant.components.http import HomeAssistantView
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from .const import EVENT_BINARY_SENSOR, DOMAIN, CONF_RESPONSE_TEMPLATE
from .tools import make_ints from .tools import make_ints
from . import hub as h from . import hub as h
_LOGGER = logging.getLogger(__name__).getChild('http') _LOGGER = logging.getLogger(__name__).getChild('http')
class MegaView(HomeAssistantView): class MegaView(HomeAssistantView):
"""Handle Yandex Smart Home unauthorized requests."""
url = '/mega' url = '/mega'
name = 'mega' name = 'mega'
@@ -31,8 +30,8 @@ class MegaView(HomeAssistantView):
mid: { mid: {
pt: cfg[mid][pt][CONF_RESPONSE_TEMPLATE] pt: cfg[mid][pt][CONF_RESPONSE_TEMPLATE]
for pt in cfg[mid] for pt in cfg[mid]
if CONF_RESPONSE_TEMPLATE in cfg[mid][pt] if isinstance(pt, int) and CONF_RESPONSE_TEMPLATE in cfg[mid][pt]
} for mid in cfg } for mid in cfg if isinstance(cfg[mid], dict)
} }
_LOGGER.debug('templates: %s', self.templates) _LOGGER.debug('templates: %s', self.templates)

View File

@@ -10,32 +10,49 @@ import json
from bs4 import BeautifulSoup from bs4 import BeautifulSoup
from homeassistant.components import mqtt from homeassistant.components import mqtt
from homeassistant.const import DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_HUMIDITY from homeassistant.const import (
DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_HUMIDITY, DEVICE_CLASS_PRESSURE,
DEVICE_CLASS_ILLUMINANCE, TEMP_CELSIUS, PERCENTAGE, LIGHT_LUX
)
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import Entity
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from .const import TEMP, HUM, PATT_SPLIT, DOMAIN, CONF_HTTP, EVENT_BINARY_SENSOR, CONF_CUSTOM, CONF_SKIP from .const import (
from .entities import set_events_off TEMP, HUM, PRESS,
from .exceptions import CannotConnect LUX, PATT_SPLIT, DOMAIN,
CONF_HTTP, EVENT_BINARY_SENSOR, CONF_CUSTOM, CONF_FORCE_D
)
from .entities import set_events_off, BaseMegaEntity
from .exceptions import CannotConnect, NoPort
from .tools import make_ints from .tools import make_ints
TEMP_PATT = re.compile(r'temp:([01234567890\.]+)') TEMP_PATT = re.compile(r'temp:([01234567890\.]+)')
HUM_PATT = re.compile(r'hum:([01234567890\.]+)') HUM_PATT = re.compile(r'hum:([01234567890\.]+)')
PRESS_PATT = re.compile(r'press:([01234567890\.]+)')
LUX_PATT = re.compile(r'lux:([01234567890\.]+)')
PATTERNS = { PATTERNS = {
TEMP: TEMP_PATT, TEMP: TEMP_PATT,
HUM: HUM_PATT, HUM: HUM_PATT,
PRESS: PRESS_PATT,
LUX: LUX_PATT
} }
UNITS = { UNITS = {
TEMP: '°C', TEMP: TEMP_CELSIUS,
HUM: '%' HUM: PERCENTAGE,
PRESS: 'mmHg',
LUX: LIGHT_LUX
} }
CLASSES = { CLASSES = {
TEMP: DEVICE_CLASS_TEMPERATURE, TEMP: DEVICE_CLASS_TEMPERATURE,
HUM: DEVICE_CLASS_HUMIDITY HUM: DEVICE_CLASS_HUMIDITY,
PRESS: DEVICE_CLASS_PRESSURE,
LUX: DEVICE_CLASS_ILLUMINANCE
}
I2C_DEVICE_TYPES = {
"2": LUX, # BH1750
"3": LUX, # TSL2591
"7": LUX, # MAX44009
"70": LUX, # OPT3001
} }
class NoPort(Exception):
pass
class MegaD: class MegaD:
@@ -57,6 +74,7 @@ class MegaD:
nports=38, nports=38,
inverted: typing.List[int] = None, inverted: typing.List[int] = None,
update_all=True, update_all=True,
poll_outs=False,
**kwargs, **kwargs,
): ):
"""Initialize.""" """Initialize."""
@@ -66,6 +84,7 @@ class MegaD:
self.http.allowed_hosts |= {host} self.http.allowed_hosts |= {host}
else: else:
self.http = None self.http = None
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
self.mqtt_inputs = mqtt_inputs self.mqtt_inputs = mqtt_inputs
@@ -81,7 +100,7 @@ class MegaD:
self._notif_lck = asyncio.Lock() self._notif_lck = asyncio.Lock()
self.cnd = asyncio.Condition() self.cnd = asyncio.Condition()
self.online = True self.online = True
self.entities: typing.List[Entity] = [] self.entities: typing.List[BaseMegaEntity] = []
self.poll_interval = scan_interval self.poll_interval = scan_interval
self.subs = None self.subs = None
self.lg: logging.Logger = lg.getChild(self.id) self.lg: logging.Logger = lg.getChild(self.id)
@@ -147,6 +166,10 @@ class MegaD:
self._customize = c self._customize = c
return self._customize return self._customize
@property
def force_d(self):
return self.customize.get(CONF_FORCE_D, False)
@property @property
def is_online(self): def is_online(self):
return (datetime.now() - self.last_update).total_seconds() < (self.poll_interval + 10) return (datetime.now() - self.last_update).total_seconds() < (self.poll_interval + 10)
@@ -170,15 +193,15 @@ class MegaD:
async def poll(self): async def poll(self):
""" """
Send get port 0 every poll_interval. When answer is received, mega.<id> becomes online else mega.<id> becomes Polling ports
offline
""" """
self.lg.debug('poll') self.lg.debug('poll')
if self.mqtt is None: if self.mqtt is None:
await self.get_all_ports() await self.get_all_ports()
await self.get_sensors(only_list=True) await self.get_sensors(only_list=True)
return elif self.poll_outs:
if len(self.sensors) > 0: await self.get_all_ports(check_skip=True)
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)
@@ -268,20 +291,23 @@ class MegaD:
except asyncio.TimeoutError: except asyncio.TimeoutError:
self.lg.error(f'timeout when getting port {port}') self.lg.error(f'timeout when getting port {port}')
@property
def ports(self):
return {e.port for e in self.entities}
async def get_all_ports(self, only_out=False, check_skip=False): async def get_all_ports(self, only_out=False, check_skip=False):
if not self.mqtt_inputs: if not self.mqtt_inputs:
ret = await self.request(cmd='all') ret = await self.request(cmd='all')
for port, x in enumerate(ret.split(';')): for port, x in enumerate(ret.split(';')):
if check_skip: if check_skip and not port in self.ports:
if self.customize.get(port, {}).get(CONF_SKIP, False): continue
continue
ret = self.parse_response(x) ret = self.parse_response(x)
self.values[port] = ret self.values[port] = ret
else: elif not check_skip:
for x in range(self.nports + 1): for x in range(self.nports + 1):
if check_skip: await self.get_port(x)
if self.customize.get(x, {}).get(CONF_SKIP, False): else:
continue for x in self.ports:
await self.get_port(x) await self.get_port(x)
async def reboot(self, save=True): async def reboot(self, save=True):
@@ -392,8 +418,11 @@ class MegaD:
self._scanned[port] = (pty, m) self._scanned[port] = (pty, m)
return pty, m return pty, m
elif pty in ('2', '4'): # эта часть не очень проработана, тут есть i2c который может работать неправильно elif pty in ('2', '4'): # эта часть не очень проработана, тут есть i2c который может работать неправильно
self._scanned[port] = (pty, '0') m = tree.find('select', attrs={'name': 'd'})
return pty, '0' 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):
@@ -428,7 +457,10 @@ class MegaD:
if isinstance(values, str) and TEMP_PATT.search(values): if isinstance(values, str) and TEMP_PATT.search(values):
values = {TEMP: values} values = {TEMP: values}
elif not isinstance(values, dict): elif not isinstance(values, dict):
values = {None: values} if pty == '4' and m in I2C_DEVICE_TYPES:
values = {I2C_DEVICE_TYPES[m]: values}
else:
values = {None: values}
for key in values: for key in values:
self.lg.debug(f'add sensor {key}') self.lg.debug(f'add sensor {key}')
ret['sensor'][port].append(dict( ret['sensor'][port].append(dict(

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": "v0.3.13" "version": "v0.3.17"
} }

View File

@@ -25,9 +25,10 @@ run_cmd:
mega_id: mega_id:
description: ID меги, можно оставить пустым, тогда будут сохранены все зарегистрированные меги description: ID меги, можно оставить пустым, тогда будут сохранены все зарегистрированные меги
example: "mega" example: "mega"
port:
description: Номер порта (это не порт, которым мы управляем, а порт с которого шлем команду)
example: 1
cmd: cmd:
description: Любая поддерживаемая мегой команда description: Любая поддерживаемая мегой команда
example: "1:0" example: "1:0"
port:
description: (Deprecated, больше не нужен) Номер порта (это не порт, которым мы управляем, а порт с которого шлем команду)
example: 1

View File

@@ -14,7 +14,8 @@
"invert": "[%key:common::config_flow::data::invert%]", "invert": "[%key:common::config_flow::data::invert%]",
"mqtt_inputs": "[%key:common::config_flow::data::mqtt_inputs%]", "mqtt_inputs": "[%key:common::config_flow::data::mqtt_inputs%]",
"nports": "[%key:common::config_flow::data::nports%]", "nports": "[%key:common::config_flow::data::nports%]",
"update_all": "[%key:common::config_flow::data::update_all%]" "update_all": "[%key:common::config_flow::data::update_all%]",
"poll_outs": "[%key:common::config_flow::data::poll_outs%]"
} }
} }
}, },
@@ -38,7 +39,8 @@
"invert": "[%key:common::config_flow::data::invert%]", "invert": "[%key:common::config_flow::data::invert%]",
"mqtt_inputs": "[%key:common::config_flow::data::mqtt_inputs%]", "mqtt_inputs": "[%key:common::config_flow::data::mqtt_inputs%]",
"nports": "[%key:common::config_flow::data::nports%]", "nports": "[%key:common::config_flow::data::nports%]",
"update_all": "[%key:common::config_flow::data::update_all%]" "update_all": "[%key:common::config_flow::data::update_all%]",
"poll_outs": "[%key:common::config_flow::data::poll_outs%]"
} }
} }
} }

View File

@@ -22,7 +22,8 @@
"port_to_scan": "Port to poll aliveness (needed only if no sensors used)", "port_to_scan": "Port to poll aliveness (needed only if no sensors used)",
"nports": "Number of ports", "nports": "Number of ports",
"update_all": "Update all outs when input", "update_all": "Update all outs when input",
"mqtt_inputs": "Use MQTT" "mqtt_inputs": "Use MQTT",
"poll_outs": "Poll outs"
} }
} }
} }
@@ -35,7 +36,8 @@
"port_to_scan": "Port to poll aliveness (needed only if no sensors used)", "port_to_scan": "Port to poll aliveness (needed only if no sensors used)",
"reload": "Reload objects", "reload": "Reload objects",
"mqtt_inputs": "Use MQTT", "mqtt_inputs": "Use MQTT",
"update_all": "Update all outs when input" "update_all": "Update all outs when input",
"poll_outs": "Poll outs"
} }
} }
} }

View File

@@ -21,7 +21,8 @@
"port_to_scan": "Порт, который сканируется когда нет датчиков", "port_to_scan": "Порт, который сканируется когда нет датчиков",
"mqtt_inputs": "Использовать MQTT", "mqtt_inputs": "Использовать MQTT",
"nports": "Кол-во портов", "nports": "Кол-во портов",
"update_all": "Обновить все выходы когда срабатывает вход" "update_all": "Обновить все выходы когда срабатывает вход",
"poll_outs": "Обновлять выходы (регулярно)"
} }
} }
} }
@@ -36,7 +37,8 @@
"invert": "Список портов (через ,) с инвертированной логикой", "invert": "Список портов (через ,) с инвертированной логикой",
"mqtt_inputs": "Использовать MQTT", "mqtt_inputs": "Использовать MQTT",
"nports": "Кол-во портов", "nports": "Кол-во портов",
"update_all": "Обновить все выходы когда срабатывает вход" "update_all": "Обновить все выходы когда срабатывает вход",
"poll_outs": "Обновлять выходы (регулярно)"
} }
} }
} }

View File

@@ -21,7 +21,8 @@
"port_to_scan": "Порт для сканування при відсутності датчиків", "port_to_scan": "Порт для сканування при відсутності датчиків",
"mqtt_inputs": "Використовувати MQTT", "mqtt_inputs": "Використовувати MQTT",
"nports": "Кількість портів", "nports": "Кількість портів",
"update_all": "Оновити всі виходи коли спрацьовує вхід" "update_all": "Оновити всі виходи коли спрацьовує вхід",
"poll_outs": "Оновити виходи"
} }
} }
} }
@@ -36,7 +37,8 @@
"invert": "Список портів з інвертованою логікою (через ,)", "invert": "Список портів з інвертованою логікою (через ,)",
"mqtt_inputs": "Використовувати MQTT", "mqtt_inputs": "Використовувати MQTT",
"nports": "Кількість портів", "nports": "Кількість портів",
"update_all": "Оновити всі виходи коли спрацьовує вхід" "update_all": "Оновити всі виходи коли спрацьовує вхід",
"poll_outs": "Оновити виходи"
} }
} }
} }

View File

@@ -4,7 +4,7 @@
[![hacs_badge](https://img.shields.io/badge/HACS-Custom-orange.svg)](https://github.com/custom-components/hacs) [![hacs_badge](https://img.shields.io/badge/HACS-Custom-orange.svg)](https://github.com/custom-components/hacs)
[![Donate](https://img.shields.io/badge/donate-Yandex-red.svg)](https://yoomoney.ru/to/410013955329136) [![Donate](https://img.shields.io/badge/donate-Yandex-red.svg)](https://yoomoney.ru/to/410013955329136)
Интеграция с [MegaD-2561](https://www.ab-log.ru/smart-house/ethernet/megad-2561) Интеграция с [MegaD-2561, MegaD-328](https://www.ab-log.ru/smart-house/ethernet/megad-2561)
## Основные особенности: ## Основные особенности:
- Настройка в веб-интерфейсе + yaml - Настройка в веб-интерфейсе + yaml
@@ -73,6 +73,9 @@ mega:
Начиная с версии `0.3.1` интеграция стала поддерживать обратную связь без mqtt, используя http-сервер. Для этого в настройках Начиная с версии `0.3.1` интеграция стала поддерживать обратную связь без mqtt, используя http-сервер. Для этого в настройках
интеграции необходимо снять галку с `использовать mqtt` интеграции необходимо снять галку с `использовать mqtt`
**Внимание!** Не используйте srv loop на контроллере, это может приводить к ложным срабатываниям входов. Вместо srv loop
интеграция будет сама обновлять все состояния портов с заданным интервалом
В самой меге необходимо прописать настройки: В самой меге необходимо прописать настройки:
```yaml ```yaml
srv: "192.168.1.4:8123" # ip:port вашего HA srv: "192.168.1.4:8123" # ip:port вашего HA
@@ -107,9 +110,26 @@ mega:
# эти параметры можно использовать в условиях или непосредственно в шаблоне в виде {{pt}} # эти параметры можно использовать в условиях или непосредственно в шаблоне в виде {{pt}}
response_template: >- response_template: >-
{% if m==2 %}1:0{% else %}d{% endif %} {% if m==2 %}1:0{% else %}d{% endif %}
``` ```
Начиная с версии v0.3.17 ответ можно слать так же и в режиме MQTT. Аналогично, темплейт должен возвращать готовую команду
такую же как требует команда cmd, так же можно использовать d, но d не отправляется по умолчанию, это сделано чтобы не
сломать текущую логику у пользователей предыдущих версий. Чтобы включить для всех входов в режиме mqtt отправку команды
d необходимо в конфиге прописать следующее:
```yaml
mega:
mega1:
force_d: true
```
**Внимание!** Нельзя использовать чекбокс напротив поля act если планируется использовать ответ сервера - у вас и
сработает act и команда от сервера, а вслучае ответа d сработает act два раза.
Так же следует понимать, что это не "ответ" в нормальном понимании - это вызов следом за полученным mqtt-сообщением
http команды такого вида `http://megaurl/?pt=port&cmd=rendered_template`, где `port` - это номер порта сработавшего входа,
а `cmd` - текст команды, который получен из темплейта. Те это имитация ответа. У этого подхода есть минус - задержка в
исполнении будет значительно выше чем при ответе в режиме http, но тем не менее эта задержка скорее всего не будет
сильно заметна.
## binary_sensor и события ## binary_sensor и события
Входы будут доступны как binary_sensor, а так же в виде событий `mega.sensor` и `mega.binary`. Входы будут доступны как binary_sensor, а так же в виде событий `mega.sensor` и `mega.binary`.