mirror of
https://github.com/andvikt/mega_hacs.git
synced 2025-12-11 17:14:28 +05:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
59443989a0 | ||
|
|
5b86ceefe4 | ||
|
|
8cf000beae | ||
|
|
99317da9f6 | ||
|
|
97911d0241 | ||
|
|
d9925a2de0 |
13
.github/ISSUE_TEMPLATE/bug-report.md
vendored
13
.github/ISSUE_TEMPLATE/bug-report.md
vendored
@@ -8,19 +8,26 @@ assignees: ''
|
||||
---
|
||||
|
||||
**Описание**
|
||||
A clear and concise description of what the bug is.
|
||||
Описание проблемы
|
||||
|
||||
**Версии систем**
|
||||
Enviroment: raspberry/linux/windows/macos/docker
|
||||
HA version:
|
||||
mega_hacs version:
|
||||
megad firmware version:
|
||||
используется mqtt: true/false
|
||||
|
||||
**Ожидаемое поведение**
|
||||
A clear and concise description of what you expected to happen.
|
||||
Описание правильного поведения
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**LOG**
|
||||
Прочитайте в документации как включить подробный лог интеграции и приложите его здесь
|
||||
Просьба прикладывать детальный лог, который можно включить в конфиге так:
|
||||
```yaml
|
||||
logger:
|
||||
default: info
|
||||
logs:
|
||||
custom_components.mega: debug
|
||||
```
|
||||
|
||||
@@ -17,7 +17,7 @@ from homeassistant.components import mqtt
|
||||
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, \
|
||||
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 .config_flow import ConfigFlow
|
||||
from .http import MegaView
|
||||
@@ -65,6 +65,7 @@ async def async_setup(hass: HomeAssistant, config: dict):
|
||||
"""YAML-конфигурация содержит только кастомизации портов"""
|
||||
hass.data[DOMAIN] = {CONF_CUSTOM: 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, []))
|
||||
hass.http.register_view(view)
|
||||
hass.services.async_register(
|
||||
@@ -75,7 +76,7 @@ async def async_setup(hass: HomeAssistant, config: dict):
|
||||
hass.services.async_register(
|
||||
DOMAIN, 'get_port', partial(_get_port, hass), schema=vol.Schema({
|
||||
vol.Optional('mega_id'): str,
|
||||
vol.Optional('port'): int,
|
||||
vol.Optional('port'): vol.Any(int, [int]),
|
||||
})
|
||||
)
|
||||
hass.services.async_register(
|
||||
@@ -115,6 +116,7 @@ async def _add_mega(hass: HomeAssistant, entry: ConfigEntry):
|
||||
hub = await get_hub(hass, entry)
|
||||
hass.data[DOMAIN][id] = hass.data[DOMAIN]['__def'] = hub
|
||||
hass.data[DOMAIN][entry.data.get(CONF_HOST)] = hub
|
||||
hass.data[DOMAIN][CONF_ALL][id] = hub
|
||||
if not await hub.authenticate():
|
||||
raise Exception("not authentificated")
|
||||
mid = await hub.get_mqtt_id()
|
||||
@@ -164,6 +166,7 @@ async def async_remove_entry(hass, entry) -> None:
|
||||
_LOGGER.debug(f'remove {id}')
|
||||
_hubs.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)
|
||||
if task is not None:
|
||||
task.cancel()
|
||||
@@ -208,17 +211,23 @@ async def _get_port(hass: HomeAssistant, call: ServiceCall):
|
||||
if mega_id:
|
||||
hub: MegaD = hass.data[DOMAIN][mega_id]
|
||||
if port is None:
|
||||
await hub.get_all_ports()
|
||||
else:
|
||||
await hub.get_all_ports(check_skip=True)
|
||||
elif isinstance(port, int):
|
||||
await hub.get_port(port)
|
||||
elif isinstance(port, list):
|
||||
for x in port:
|
||||
await hub.get_port(x)
|
||||
else:
|
||||
for hub in hass.data[DOMAIN].values():
|
||||
for hub in hass.data[DOMAIN][CONF_ALL].values():
|
||||
if not isinstance(hub, MegaD):
|
||||
continue
|
||||
if port is None:
|
||||
await hub.get_all_ports()
|
||||
else:
|
||||
await hub.get_all_ports(check_skip=True)
|
||||
elif isinstance(port, int):
|
||||
await hub.get_port(port)
|
||||
elif isinstance(port, list):
|
||||
for x in port:
|
||||
await hub.get_port(x)
|
||||
|
||||
|
||||
@bind_hass
|
||||
|
||||
@@ -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.core import callback, HomeAssistant
|
||||
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 . 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_PASSWORD, default="sec"): str,
|
||||
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_MQTT_INPUTS, default=True): bool,
|
||||
vol.Optional(CONF_NPORTS, default=37): int,
|
||||
@@ -131,6 +132,7 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
|
||||
step_id="init",
|
||||
data_schema=vol.Schema({
|
||||
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_MQTT_INPUTS, default=e.get(CONF_MQTT_INPUTS, True)): bool,
|
||||
vol.Optional(CONF_NPORTS, default=e.get(CONF_NPORTS, 37)): int,
|
||||
|
||||
@@ -16,6 +16,7 @@ CONF_INVERT = 'invert'
|
||||
CONF_PORTS = 'ports'
|
||||
CONF_CUSTOM = '__custom'
|
||||
CONF_HTTP = '__http'
|
||||
CONF_ALL = '__all'
|
||||
CONF_SKIP = 'skip'
|
||||
CONF_MQTT_INPUTS = 'mqtt_inputs'
|
||||
CONF_NPORTS = 'nports'
|
||||
@@ -25,6 +26,7 @@ CONF_UPDATE_ALL = 'update_all'
|
||||
CONF_GET_VALUE = 'get_value'
|
||||
CONF_ALLOW_HOSTS = 'allow_hosts'
|
||||
CONF_CONV_TEMPLATE = 'conv_template'
|
||||
CONF_POLL_OUTS = 'poll_outs'
|
||||
PLATFORMS = [
|
||||
"light",
|
||||
"switch",
|
||||
|
||||
@@ -14,8 +14,8 @@ from homeassistant.const import DEVICE_CLASS_TEMPERATURE, DEVICE_CLASS_HUMIDITY
|
||||
from homeassistant.core import HomeAssistant
|
||||
from homeassistant.helpers.entity import Entity
|
||||
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
|
||||
from .const import TEMP, HUM, PATT_SPLIT, DOMAIN, CONF_HTTP, EVENT_BINARY_SENSOR
|
||||
from .entities import set_events_off
|
||||
from .const import TEMP, HUM, PATT_SPLIT, DOMAIN, CONF_HTTP, EVENT_BINARY_SENSOR, CONF_CUSTOM, CONF_SKIP
|
||||
from .entities import set_events_off, BaseMegaEntity
|
||||
from .exceptions import CannotConnect
|
||||
from .tools import make_ints
|
||||
|
||||
@@ -57,6 +57,7 @@ class MegaD:
|
||||
nports=38,
|
||||
inverted: typing.List[int] = None,
|
||||
update_all=True,
|
||||
poll_outs=False,
|
||||
**kwargs,
|
||||
):
|
||||
"""Initialize."""
|
||||
@@ -66,6 +67,7 @@ class MegaD:
|
||||
self.http.allowed_hosts |= {host}
|
||||
else:
|
||||
self.http = None
|
||||
self.poll_outs = poll_outs
|
||||
self.update_all = update_all if update_all is not None else True
|
||||
self.nports = nports
|
||||
self.mqtt_inputs = mqtt_inputs
|
||||
@@ -81,7 +83,7 @@ class MegaD:
|
||||
self._notif_lck = asyncio.Lock()
|
||||
self.cnd = asyncio.Condition()
|
||||
self.online = True
|
||||
self.entities: typing.List[Entity] = []
|
||||
self.entities: typing.List[BaseMegaEntity] = []
|
||||
self.poll_interval = scan_interval
|
||||
self.subs = None
|
||||
self.lg: logging.Logger = lg.getChild(self.id)
|
||||
@@ -91,6 +93,7 @@ class MegaD:
|
||||
self.last_update = datetime.now()
|
||||
self._callbacks: typing.DefaultDict[int, typing.List[typing.Callable[[dict], typing.Coroutine]]] = defaultdict(list)
|
||||
self._loop = loop
|
||||
self._customize = None
|
||||
self.values = {}
|
||||
self.last_port = None
|
||||
self.updater = DataUpdateCoordinator(
|
||||
@@ -138,6 +141,14 @@ class MegaD:
|
||||
await self.get_port(x.port, force_http=True, http_cmd=x.http_cmd)
|
||||
ports.append(x.port)
|
||||
|
||||
@property
|
||||
def customize(self):
|
||||
if self._customize is None:
|
||||
c = self.hass.data.get(DOMAIN, {}).get(CONF_CUSTOM) or {}
|
||||
c = c.get(self.id) or {}
|
||||
self._customize = c
|
||||
return self._customize
|
||||
|
||||
@property
|
||||
def is_online(self):
|
||||
return (datetime.now() - self.last_update).total_seconds() < (self.poll_interval + 10)
|
||||
@@ -168,8 +179,9 @@ class MegaD:
|
||||
if self.mqtt is None:
|
||||
await self.get_all_ports()
|
||||
await self.get_sensors(only_list=True)
|
||||
return
|
||||
if len(self.sensors) > 0:
|
||||
elif self.poll_outs:
|
||||
await self.get_all_ports(check_skip=True)
|
||||
elif len(self.sensors) > 0:
|
||||
await self.get_sensors()
|
||||
else:
|
||||
await self.get_port(self.port_to_scan)
|
||||
@@ -259,15 +271,24 @@ class MegaD:
|
||||
except asyncio.TimeoutError:
|
||||
self.lg.error(f'timeout when getting port {port}')
|
||||
|
||||
async def get_all_ports(self, only_out=False):
|
||||
@property
|
||||
def ports(self):
|
||||
return {e.port for e in self.entities}
|
||||
|
||||
async def get_all_ports(self, only_out=False, check_skip=False):
|
||||
if not self.mqtt_inputs:
|
||||
ret = await self.request(cmd='all')
|
||||
for port, x in enumerate(ret.split(';')):
|
||||
if check_skip and not port in self.ports:
|
||||
continue
|
||||
ret = self.parse_response(x)
|
||||
self.values[port] = ret
|
||||
else:
|
||||
elif not check_skip:
|
||||
for x in range(self.nports + 1):
|
||||
await self.get_port(x)
|
||||
else:
|
||||
for x in self.ports:
|
||||
await self.get_port(x)
|
||||
|
||||
async def reboot(self, save=True):
|
||||
await self.save()
|
||||
@@ -376,7 +397,7 @@ class MegaD:
|
||||
m = m.find(selected=True)['value']
|
||||
self._scanned[port] = (pty, m)
|
||||
return pty, m
|
||||
elif pty == '2':
|
||||
elif pty in ('2', '4'): # эта часть не очень проработана, тут есть i2c который может работать неправильно
|
||||
self._scanned[port] = (pty, '0')
|
||||
return pty, '0'
|
||||
|
||||
@@ -394,7 +415,7 @@ class MegaD:
|
||||
ret['binary_sensor'][port].append({})
|
||||
elif pty == "1" and (m in ['0', '1', '3'] or m is None):
|
||||
ret['light'][port].append({'dimmer': m == '1'})
|
||||
elif pty in ('3', '2'):
|
||||
elif pty in ('3', '2', '4'):
|
||||
try:
|
||||
http_cmd = 'get'
|
||||
values = await self.get_port(port, force_http=True)
|
||||
|
||||
@@ -15,5 +15,5 @@
|
||||
"@andvikt"
|
||||
],
|
||||
"issue_tracker": "https://github.com/andvikt/mega_hacs/issues",
|
||||
"version": "v0.3.12"
|
||||
"version": "v0.3.13"
|
||||
}
|
||||
@@ -15,7 +15,7 @@ get_port:
|
||||
description: ID меги, можно оставить пустым, тогда будут сохранены все зарегистрированные меги
|
||||
example: "mega"
|
||||
port:
|
||||
description: Номер порта (если не заполнять, будут запрошены все порты сразу)
|
||||
description: Номер порта или список портов (если не заполнять, будут запрошены все порты сразу)
|
||||
example: 1
|
||||
|
||||
run_cmd:
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
"invert": "[%key:common::config_flow::data::invert%]",
|
||||
"mqtt_inputs": "[%key:common::config_flow::data::mqtt_inputs%]",
|
||||
"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%]",
|
||||
"mqtt_inputs": "[%key:common::config_flow::data::mqtt_inputs%]",
|
||||
"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%]"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,8 @@
|
||||
"port_to_scan": "Port to poll aliveness (needed only if no sensors used)",
|
||||
"nports": "Number of ports",
|
||||
"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)",
|
||||
"reload": "Reload objects",
|
||||
"mqtt_inputs": "Use MQTT",
|
||||
"update_all": "Update all outs when input"
|
||||
"update_all": "Update all outs when input",
|
||||
"poll_outs": "Poll outs"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,8 @@
|
||||
"port_to_scan": "Порт, который сканируется когда нет датчиков",
|
||||
"mqtt_inputs": "Использовать MQTT",
|
||||
"nports": "Кол-во портов",
|
||||
"update_all": "Обновить все выходы когда срабатывает вход"
|
||||
"update_all": "Обновить все выходы когда срабатывает вход",
|
||||
"poll_outs": "Обновлять выходы (регулярно)"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,7 +37,8 @@
|
||||
"invert": "Список портов (через ,) с инвертированной логикой",
|
||||
"mqtt_inputs": "Использовать MQTT",
|
||||
"nports": "Кол-во портов",
|
||||
"update_all": "Обновить все выходы когда срабатывает вход"
|
||||
"update_all": "Обновить все выходы когда срабатывает вход",
|
||||
"poll_outs": "Обновлять выходы (регулярно)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,8 @@
|
||||
"port_to_scan": "Порт для сканування при відсутності датчиків",
|
||||
"mqtt_inputs": "Використовувати MQTT",
|
||||
"nports": "Кількість портів",
|
||||
"update_all": "Оновити всі виходи коли спрацьовує вхід"
|
||||
"update_all": "Оновити всі виходи коли спрацьовує вхід",
|
||||
"poll_outs": "Оновити виходи"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,7 +37,8 @@
|
||||
"invert": "Список портів з інвертованою логікою (через ,)",
|
||||
"mqtt_inputs": "Використовувати MQTT",
|
||||
"nports": "Кількість портів",
|
||||
"update_all": "Оновити всі виходи коли спрацьовує вхід"
|
||||
"update_all": "Оновити всі виходи коли спрацьовує вхід",
|
||||
"poll_outs": "Оновити виходи"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -155,12 +155,15 @@ mega:
|
||||
```
|
||||
Возможные варианты поля `type`:
|
||||
- `long`: долгое нажатие
|
||||
- `release`: размыкание (с гарантией что не было долгого нажатия)
|
||||
- `release`: размыкание (с гарантией** что не было долгого нажатия)
|
||||
- `long_release`: размыкание после долгого нажатия
|
||||
- `press`: замыкание
|
||||
- `single`: одинарный клик (в режиме кликов)
|
||||
- `double`: двойной клик
|
||||
|
||||
**гарантия есть только при использовании http-метода синхронизации, mqtt не гарантирует порядок доставки сообщений, хотя
|
||||
маловероятно, что порядок будет нарушен, но все же сам протокол не дает таких гарантий.
|
||||
|
||||
Чтобы понять, какие события происходят, лучше всего воспользоваться панелью разработчика и подписаться
|
||||
на вкладке события на событие `mega.sensor`, понажимать кнопки.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user