Compare commits

...

4 Commits

Author SHA1 Message Date
Andrey
59443989a0 add poll outs 2021-02-06 09:43:10 +03:00
Andrey
5b86ceefe4 Merge remote-tracking branch 'origin/master' 2021-02-05 21:06:40 +03:00
Andrey
8cf000beae fix get_port 2021-02-05 21:06:27 +03:00
andvikt
99317da9f6 Update bug-report.md 2021-02-05 20:47:58 +03:00
10 changed files with 62 additions and 28 deletions

View File

@@ -8,19 +8,26 @@ assignees: ''
--- ---
**Описание** **Описание**
A clear and concise description of what the bug is. Описание проблемы
**Версии систем** **Версии систем**
Enviroment: raspberry/linux/windows/macos/docker Enviroment: raspberry/linux/windows/macos/docker
HA version: HA version:
mega_hacs version: mega_hacs version:
megad firmware version: megad firmware version:
используется mqtt: true/false
**Ожидаемое поведение** **Ожидаемое поведение**
A clear and concise description of what you expected to happen. Описание правильного поведения
**Screenshots** **Screenshots**
If applicable, add screenshots to help explain your problem. If applicable, add screenshots to help explain your problem.
**LOG** **LOG**
Прочитайте в документации как включить подробный лог интеграции и приложите его здесь Просьба прикладывать детальный лог, который можно включить в конфиге так:
```yaml
logger:
default: info
logs:
custom_components.mega: debug
```

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
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
@@ -65,6 +65,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(
@@ -115,6 +116,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 +166,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,13 +218,16 @@ 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:
await hub.get_all_ports() await hub.get_all_ports(check_skip=True)
else: elif isinstance(port, int):
await hub.get_port(port) await hub.get_port(port)
elif isinstance(port, list):
for x in port:
await hub.get_port(x)
@bind_hass @bind_hass

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
@@ -22,6 +22,7 @@ STEP_USER_DATA_SCHEMA = vol.Schema(
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,7 @@ 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'
PLATFORMS = [ PLATFORMS = [
"light", "light",
"switch", "switch",

View File

@@ -15,7 +15,7 @@ from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity import Entity 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 TEMP, HUM, PATT_SPLIT, DOMAIN, CONF_HTTP, EVENT_BINARY_SENSOR, CONF_CUSTOM, CONF_SKIP
from .entities import set_events_off from .entities import set_events_off, BaseMegaEntity
from .exceptions import CannotConnect from .exceptions import CannotConnect
from .tools import make_ints from .tools import make_ints
@@ -57,6 +57,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 +67,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 +83,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)
@@ -177,8 +179,9 @@ class MegaD:
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 +271,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):

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

@@ -155,12 +155,15 @@ mega:
``` ```
Возможные варианты поля `type`: Возможные варианты поля `type`:
- `long`: долгое нажатие - `long`: долгое нажатие
- `release`: размыкание (с гарантией что не было долгого нажатия) - `release`: размыкание (с гарантией** что не было долгого нажатия)
- `long_release`: размыкание после долгого нажатия - `long_release`: размыкание после долгого нажатия
- `press`: замыкание - `press`: замыкание
- `single`: одинарный клик (в режиме кликов) - `single`: одинарный клик (в режиме кликов)
- `double`: двойной клик - `double`: двойной клик
**гарантия есть только при использовании http-метода синхронизации, mqtt не гарантирует порядок доставки сообщений, хотя
маловероятно, что порядок будет нарушен, но все же сам протокол не дает таких гарантий.
Чтобы понять, какие события происходят, лучше всего воспользоваться панелью разработчика и подписаться Чтобы понять, какие события происходят, лучше всего воспользоваться панелью разработчика и подписаться
на вкладке события на событие `mega.sensor`, понажимать кнопки. на вкладке события на событие `mega.sensor`, понажимать кнопки.