Compare commits

..

24 Commits

Author SHA1 Message Date
Andrey
ed9011a6e1 edit readme 2021-01-15 09:23:32 +03:00
Andrey
c7e8bcb83e edit readme 2021-01-15 09:20:52 +03:00
Andrey
21fd00083c edit readme 2021-01-15 09:13:12 +03:00
Andrey
c4f4510941 add device registry 2021-01-15 09:10:42 +03:00
Andrey
254015be4c edit readme 2021-01-15 08:45:27 +03:00
Andrey
adb65529a2 hotfix 2021-01-14 23:05:30 +03:00
Andrey
768d46d952 hotfix 2021-01-14 22:48:07 +03:00
Andrey
359c6b99b7 hotfix 2021-01-14 22:27:07 +03:00
Andrey
79dc46226a hotfix 2021-01-14 22:19:56 +03:00
Andrey
012d12437b hotfix 2021-01-14 21:40:19 +03:00
Andrey
7063575957 hotfix 2021-01-14 21:35:15 +03:00
Andrey
6a43198d81 hotfix 2021-01-14 21:33:44 +03:00
Andrey
242386bfe8 edit readme 2021-01-14 21:25:48 +03:00
Andrey
34d31d2879 edit readme 2021-01-14 21:07:30 +03:00
Andrey
6a02a7e98c башфикс сервисов, ускорение загрузки 2021-01-14 20:46:05 +03:00
Andrey
d6191ba46a fix services 2021-01-05 09:02:35 +03:00
Andrey
f19d3daeff add yaml deprecation 2021-01-04 09:59:44 +03:00
Andrey
d56cffa68f fix 37 port 2021-01-02 09:56:47 +03:00
Andrey
a958d56e6b fix brightness 2020-12-30 08:58:57 +03:00
Andrey
577119e41a add services 2020-12-29 12:36:48 +03:00
Andrey
db52d93ee4 add issue tracker 2020-12-29 11:30:49 +03:00
Andrey
a38de65071 add validate 2020-12-29 11:22:24 +03:00
Andrey
6d1aa47e4f fix manifest 2020-12-29 11:13:34 +03:00
Andrey
cc122cf98b add hassfest 2020-12-29 10:06:22 +03:00
14 changed files with 333 additions and 206 deletions

14
.github/workflows/hassfest.yaml vendored Normal file
View File

@@ -0,0 +1,14 @@
name: Validate with hassfest
on:
push:
pull_request:
schedule:
- cron: "0 0 * * *"
jobs:
validate:
runs-on: "ubuntu-latest"
steps:
- uses: "actions/checkout@v2"
- uses: home-assistant/actions/hassfest@master

17
.github/workflows/validate.yaml vendored Normal file
View File

@@ -0,0 +1,17 @@
name: Validate
on:
push:
pull_request:
schedule:
- cron: "0 0 * * *"
jobs:
validate:
runs-on: "ubuntu-latest"
steps:
- uses: "actions/checkout@v2"
- name: HACS validation
uses: "hacs/action@main"
with:
category: "integration"

View File

@@ -1,13 +1,11 @@
"""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
from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_PLATFORM, CONF_SCAN_INTERVAL, CONF_ID from homeassistant.const import CONF_HOST, CONF_PASSWORD, CONF_SCAN_INTERVAL, CONF_ID
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant, ServiceCall
from homeassistant.helpers.entity_component import EntityComponent
from homeassistant.helpers.service import bind_hass from homeassistant.helpers.service import bind_hass
from homeassistant.components import mqtt from homeassistant.components import mqtt
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
@@ -51,16 +49,33 @@ async def async_setup(hass: HomeAssistant, config: dict):
"""Set up the mega component.""" """Set up the mega component."""
conf = config.get(DOMAIN) conf = config.get(DOMAIN)
hass.data[DOMAIN] = {} hass.data[DOMAIN] = {}
hass.services.async_register(
DOMAIN, 'save', partial(_save_service, hass), schema=vol.Schema({
vol.Optional('mega_id'): str
})
)
hass.services.async_register(
DOMAIN, 'get_port', partial(_get_port, hass), schema=vol.Schema({
vol.Optional('mega_id'): str,
vol.Optional('port'): int,
})
)
hass.services.async_register(
DOMAIN, 'run_cmd', partial(_run_cmd, hass), schema=vol.Schema({
vol.Required('port'): int,
vol.Required('cmd'): str,
vol.Optional('mega_id'): str,
})
)
if conf is None: if conf is None:
return True return True
if CONF_HOST in conf: if CONF_HOST in conf:
conf = {DEF_ID: conf} conf = {DEF_ID: conf}
for id, data in conf.items(): for id, data in conf.items():
_LOGGER.warning('YAML configuration is deprecated, please use web-interface')
await _add_mega(hass, id, data) await _add_mega(hass, id, data)
hass.services.async_register(
DOMAIN, 'save', _save_service, for id, hub in hass.data[DOMAIN].items():
)
for id, hub in hass.data[DOMAIN].__items__():
_POLL_TASKS[id] = asyncio.create_task(hub.poll()) _POLL_TASKS[id] = asyncio.create_task(hub.poll())
return True return True
@@ -79,7 +94,6 @@ async def _add_mega(hass: HomeAssistant, id, data: dict):
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry): async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry):
print(entry.entry_id)
id = entry.data.get('id', entry.entry_id) id = entry.data.get('id', entry.entry_id)
data = dict(entry.data) data = dict(entry.data)
data.update(entry.options or {}) data.update(entry.options or {})
@@ -116,10 +130,45 @@ async def async_remove_entry(hass, entry) -> None:
_hubs.pop(entry.entry_id) _hubs.pop(entry.entry_id)
unsub = _subs.pop(entry.entry_id) unsub = _subs.pop(entry.entry_id)
unsub() unsub()
hass.data[DOMAIN].pop(id)
async def _save_service(hass: HomeAssistant, call: ServiceCall):
mega_id = call.data.get('mega_id')
if mega_id:
hub: MegaD = hass.data[DOMAIN][mega_id]
await hub.save()
else:
for hub in hass.data[DOMAIN].values():
await hub.save()
@bind_hass @bind_hass
async def _save_service(hass: HomeAssistant, mega_id='def'): async def _get_port(hass: HomeAssistant, call: ServiceCall):
hub: MegaD = hass.data[DOMAIN][mega_id] port = call.data.get('port')
await hub.save() mega_id = call.data.get('mega_id')
if mega_id:
hub: MegaD = hass.data[DOMAIN][mega_id]
if port is None:
await hub.get_all_ports()
else:
await hub.get_port(port)
else:
for hub in hass.data[DOMAIN].values():
if port is None:
await hub.get_all_ports()
else:
await hub.get_port(port)
@bind_hass
async def _run_cmd(hass: HomeAssistant, call: ServiceCall):
port = call.data.get('port')
mega_id = call.data.get('mega_id')
cmd = call.data.get('cmd')
if mega_id:
hub: MegaD = hass.data[DOMAIN][mega_id]
await hub.send_command(port=port, cmd=cmd)
else:
for hub in hass.data[DOMAIN].values():
await hub.send_command(port=port, cmd=cmd)

View File

@@ -1,7 +1,6 @@
"""Platform for light integration.""" """Platform for light integration."""
import asyncio
import json
import logging import logging
import asyncio
import voluptuous as vol import voluptuous as vol
@@ -18,7 +17,6 @@ from homeassistant.const import (
CONF_ID CONF_ID
) )
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.restore_state import RestoreEntity
from .entities import BaseMegaEntity from .entities import BaseMegaEntity
from .hub import MegaD from .hub import MegaD
@@ -63,12 +61,16 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, asyn
mid = config_entry.data[CONF_ID] mid = config_entry.data[CONF_ID]
hub: MegaD = hass.data['mega'][mid] hub: MegaD = hass.data['mega'][mid]
devices = [] devices = []
async for port, pty, m in hub.scan_ports():
if pty == "0":
sensor = MegaBinarySensor(mega_id=mid, port=port)
devices.append(sensor)
async_add_devices(devices) async def scan():
async for port, pty, m in hub.scan_ports():
if pty == "0":
sensor = MegaBinarySensor(mega_id=mid, port=port, config_entry=config_entry)
devices.append(sensor)
async_add_devices(devices)
asyncio.create_task(scan())
class MegaBinarySensor(BinarySensorEntity, BaseMegaEntity): class MegaBinarySensor(BinarySensorEntity, BaseMegaEntity):

View File

@@ -9,7 +9,7 @@ from homeassistant.components import mqtt
from homeassistant.config_entries import ConfigEntry 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 from homeassistant.core import callback
from .const import DOMAIN, CONF_PORT_TO_SCAN, CONF_RELOAD, CONF_INVERT # pylint:disable=unused-import from .const import DOMAIN, CONF_PORT_TO_SCAN, CONF_RELOAD # pylint:disable=unused-import
from .hub import MegaD from .hub import MegaD
from . import exceptions from . import exceptions
@@ -103,7 +103,7 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
data_schema=vol.Schema({ data_schema=vol.Schema({
vol.Optional(CONF_SCAN_INTERVAL, default=e[CONF_SCAN_INTERVAL]): int, vol.Optional(CONF_SCAN_INTERVAL, default=e[CONF_SCAN_INTERVAL]): int,
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_RELOAD, default=False): bool, # vol.Optional(CONF_RELOAD, default=False): bool,
# vol.Optional(CONF_INVERT, default=''): str, # vol.Optional(CONF_INVERT, default=''): str,
}), }),
) )

View File

@@ -3,6 +3,7 @@ import asyncio
import json import json
import logging import logging
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import State from homeassistant.core import State
from .hub import MegaD from .hub import MegaD
from homeassistant.helpers.restore_state import RestoreEntity from homeassistant.helpers.restore_state import RestoreEntity
@@ -19,17 +20,37 @@ class BaseMegaEntity(RestoreEntity):
self, self,
mega_id: str, mega_id: str,
port: int, port: int,
config_entry: ConfigEntry = None,
id_suffix=None, id_suffix=None,
name=None, name=None,
unique_id=None unique_id=None,
): ):
self._state: State = None self._state: State = None
self.port = port self.port = port
self._name = name self.config_entry = config_entry
self._mega_id = mega_id self._mega_id = mega_id
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}" + \
(f"_{id_suffix}" if id_suffix else "")
@property
def device_info(self):
return {
"identifiers": {
# Serial numbers are unique identifiers within a specific domain
(DOMAIN, f'{self._mega_id}', self.port),
},
"config_entries": [
self.config_entry,
],
"name": f'port {self.port}',
"manufacturer": 'ab-log.ru',
# "model": self.light.productname,
# "sw_version": self.light.swversion,
"via_device": (DOMAIN, self._mega_id),
}
@property @property
def lg(self) -> logging.Logger: def lg(self) -> logging.Logger:

View File

@@ -140,36 +140,47 @@ class MegaD:
async def save(self): async def save(self):
await self.send_command(cmd='s') await self.send_command(cmd='s')
async def get_port(self, port, get_value=False): async def get_port(self, port):
if get_value: """
ftr = asyncio.get_event_loop().create_future() Опрашивает порт с помощью mqtt. Ждет ответ, возвращает ответ.
def cb(msg): :param port:
try: :return:
ftr.set_result(json.loads(msg.payload).get('value')) """
except Exception as exc: ftr = asyncio.get_event_loop().create_future()
self.lg.warning(f'could not parse {msg.payload}: {exc}')
ftr.set_result(None) def cb(msg):
try:
if '"value":NA' in msg.payload.decode():
if not ftr.done():
ftr.set_result(None)
return
ret = json.loads(msg.payload).get('value')
if not ftr.done():
ftr.set_result(ret)
except Exception as exc:
ret = None
self.lg.exception(f'while parsing response from port {port}: {msg.payload}')
ftr.set_result(None)
self.lg.debug(
f'port: %s response: %s', port, ret
)
async with self.lck:
unsub = await self.mqtt.async_subscribe( unsub = await self.mqtt.async_subscribe(
topic=f'{self.mqtt_id}/{port}', topic=f'{self.mqtt_id}/{port}',
msg_callback=cb, msg_callback=cb,
qos=1, qos=1,
) )
self.lg.debug(
f'get port: %s', port
)
async with self.lck:
await self.mqtt.async_publish(
topic=f'{self.mqtt_id}/cmd',
payload=f'get:{port}',
qos=0,
retain=False,
)
await asyncio.sleep(0.1)
if get_value:
try: try:
await self.mqtt.async_publish(
topic=f'{self.mqtt_id}/cmd',
payload=f'get:{port}',
qos=1,
retain=False,
)
return await asyncio.wait_for(ftr, timeout=2) return await asyncio.wait_for(ftr, timeout=2)
except asyncio.TimeoutError: except asyncio.TimeoutError:
self.lg.warning(f'timeout on port {port}') self.lg.warning(f'timeout on port {port}')
@@ -178,7 +189,7 @@ class MegaD:
async def get_all_ports(self): async def get_all_ports(self):
for x in range(37): for x in range(37):
await self.get_port(x) asyncio.create_task(self.get_port(x))
async def reboot(self, save=True): async def reboot(self, save=True):
await self.save() await self.save()
@@ -227,39 +238,40 @@ class MegaD:
return await req.text() return await req.text()
async def scan_port(self, port): async def scan_port(self, port):
if port in self._scanned: async with self.lck:
return self._scanned[port] if port in self._scanned:
url = f'http://{self.host}/{self.sec}/?pt={port}' return self._scanned[port]
self.lg.debug( url = f'http://{self.host}/{self.sec}/?pt={port}'
f'scan port %s: %s', port, url self.lg.debug(
) f'scan port %s: %s', port, url
async with aiohttp.request('get', url) as req: )
html = await req.text() async with aiohttp.request('get', url) as req:
tree = BeautifulSoup(html, features="lxml") html = await req.text()
pty = tree.find('select', attrs={'name': 'pty'}) tree = BeautifulSoup(html, features="lxml")
if pty is None: pty = tree.find('select', attrs={'name': 'pty'})
return if pty is None:
else:
pty = pty.find(selected=True)
if pty:
pty = pty['value']
else:
return return
if pty in ['0', '1']: else:
m = tree.find('select', attrs={'name': 'm'}) pty = pty.find(selected=True)
if m: if pty:
m = m.find(selected=True)['value'] pty = pty['value']
self._scanned[port] = (pty, m) else:
return pty, m return
elif pty == '3': if pty in ['0', '1']:
m = tree.find('select', attrs={'name': 'd'}) m = tree.find('select', attrs={'name': 'm'})
if m: if m:
m = m.find(selected=True)['value'] m = m.find(selected=True)['value']
self._scanned[port] = (pty, m) self._scanned[port] = (pty, m)
return 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
async def scan_ports(self,): async def scan_ports(self,):
for x in range(37): for x in range(38):
ret = await self.scan_port(x) ret = await self.scan_port(x)
if ret: if ret:
yield [x, *ret] yield [x, *ret]

View File

@@ -1,8 +1,6 @@
"""Platform for light integration.""" """Platform for light integration."""
import asyncio
import json
import logging import logging
import asyncio
import voluptuous as vol import voluptuous as vol
from homeassistant.components.light import ( from homeassistant.components.light import (
@@ -19,7 +17,6 @@ from homeassistant.const import (
CONF_ID CONF_ID
) )
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.restore_state import RestoreEntity
from .entities import BaseMegaEntity from .entities import BaseMegaEntity
from .hub import MegaD from .hub import MegaD
@@ -80,11 +77,15 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, asyn
mid = config_entry.data[CONF_ID] mid = config_entry.data[CONF_ID]
hub: MegaD = hass.data['mega'][mid] hub: MegaD = hass.data['mega'][mid]
devices = [] devices = []
async for port, pty, m in hub.scan_ports():
if pty == "1" and m in ['0', '1']: async def scan_ports():
light = MegaLight(mega_id=mid, port=port, dimmer=m == '1') async for port, pty, m in hub.scan_ports():
devices.append(light) if pty == "1" and m in ['0', '1']:
async_add_devices(devices) light = MegaLight(mega_id=mid, port=port, dimmer=m == '1', config_entry=config_entry)
devices.append(light)
async_add_devices(devices)
asyncio.create_task(scan_ports())
class MegaLight(LightEntity, BaseMegaEntity): class MegaLight(LightEntity, BaseMegaEntity):
@@ -119,7 +120,7 @@ class MegaLight(LightEntity, BaseMegaEntity):
return self._state == 'ON' return self._state == 'ON'
async def async_turn_on(self, brightness=None, **kwargs) -> None: async def async_turn_on(self, brightness=None, **kwargs) -> None:
brightness = brightness or self.brightness brightness = brightness or self.brightness or 255
if self.dimmer and brightness == 0: if self.dimmer and brightness == 0:
cmd = 255 cmd = 255
elif self.dimmer: elif self.dimmer:

View File

@@ -2,7 +2,7 @@
"domain": "mega", "domain": "mega",
"name": "mega", "name": "mega",
"config_flow": true, "config_flow": true,
"documentation": "https://www.home-assistant.io/integrations/mega", "documentation": "https://www.home-assistant.io/integrations/mega_hacs",
"requirements": [ "requirements": [
"beautifulsoup4", "beautifulsoup4",
"lxml" "lxml"
@@ -15,5 +15,6 @@
], ],
"codeowners": [ "codeowners": [
"@andvikt" "@andvikt"
] ],
"issue_tracker": "https://github.com/andvikt/mega_hacs/issues"
} }

View File

@@ -1,7 +1,6 @@
"""Platform for light integration.""" """Platform for light integration."""
import asyncio
import logging import logging
import typing
import voluptuous as vol import voluptuous as vol
from homeassistant.components.sensor import ( from homeassistant.components.sensor import (
@@ -70,7 +69,7 @@ async def async_setup_platform(hass, config, add_entities, discovery_info=None):
return True return True
def _make_entity(mid: str, port: int, conf: dict): def _make_entity(config_entry, mid: str, port: int, conf: dict):
key = conf[CONF_KEY] key = conf[CONF_KEY]
return Mega1WSensor( return Mega1WSensor(
key=key, key=key,
@@ -79,7 +78,8 @@ def _make_entity(mid: str, port: int, conf: dict):
patt=PATTERNS.get(key), patt=PATTERNS.get(key),
unit_of_measurement=UNITS.get(key, UNITS[TEMP]), # TODO: make other units, make options in config flow unit_of_measurement=UNITS.get(key, UNITS[TEMP]), # TODO: make other units, make options in config flow
device_class=CLASSES.get(key, CLASSES[TEMP]), device_class=CLASSES.get(key, CLASSES[TEMP]),
id_suffix=key id_suffix=key,
config_entry=config_entry
) )
@@ -87,29 +87,35 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry, asyn
mid = config_entry.data[CONF_ID] mid = config_entry.data[CONF_ID]
hub: MegaD = hass.data['mega'][mid] hub: MegaD = hass.data['mega'][mid]
devices = [] devices = []
async for port, pty, m in hub.scan_ports():
if pty == "3":
values = await hub.get_port(port, get_value=True)
lg.debug(f'values: %s', values)
if values is None:
continue
if isinstance(values, str) and TEMP_PATT.search(values):
values = {TEMP: values}
elif not isinstance(values, dict):
values = {None: values}
for key in values:
hub.lg.debug(f'add sensor {W1}:{key}')
sensor = _make_entity(
mid=mid,
port=port,
conf={
CONF_TYPE: W1,
CONF_KEY: key,
})
devices.append(sensor)
hub.sensors.append(sensor)
async_add_devices(devices) async def scan():
async for port, pty, m in hub.scan_ports():
if pty == "3":
values = await hub.get_port(port)
lg.debug(f'values: %s', values)
if values is None:
continue
if isinstance(values, str) and TEMP_PATT.search(values):
values = {TEMP: values}
elif not isinstance(values, dict):
values = {None: values}
for key in values:
hub.lg.debug(f'add sensor {W1}:{key}')
sensor = _make_entity(
mid=mid,
port=port,
conf={
CONF_TYPE: W1,
CONF_KEY: key,
},
config_entry=config_entry,
)
devices.append(sensor)
hub.sensors.append(sensor)
async_add_devices(devices)
asyncio.create_task(scan())
class Mega1WSensor(BaseMegaEntity): class Mega1WSensor(BaseMegaEntity):

View File

@@ -1,13 +1,33 @@
save: save:
# Description of the service
description: Сохраняет текущее состояние портов (?cmd=s) description: Сохраняет текущее состояние портов (?cmd=s)
# Different fields that your service accepts
fields: fields:
# Key of the field
mega_id: mega_id:
# Description of the field description: ID меги, можно оставить пустым, тогда будут сохранены все зарегистрированные меги
description: ID меги example: "mega"
# Example value that can be passed for this field
example: "def" get_port:
description: Запросить текущий статус порта (или всех)
fields:
mega_id:
description: ID меги, можно оставить пустым, тогда будут сохранены все зарегистрированные меги
example: "mega"
port:
description: Номер порта (если не заполнять, будут запрошены все порты сразу)
example: 1
run_cmd:
description: Выполнить любую произвольную команду
fields:
mega_id:
description: ID меги, можно оставить пустым, тогда будут сохранены все зарегистрированные меги
example: "mega"
port:
description: Номер порта (это не порт, которым мы управляем, а порт с которого шлем команду)
example: 1
cmd:
description: Любая поддерживаемая мегой команда
example: "1:0"

View File

@@ -1,5 +1,4 @@
"""Platform for light integration.""" """Platform for light integration."""
import json
import logging import logging
import voluptuous as vol import voluptuous as vol
@@ -13,11 +12,7 @@ from homeassistant.const import (
CONF_PLATFORM, CONF_PLATFORM,
CONF_PORT, CONF_PORT,
) )
from homeassistant.core import HomeAssistant
from homeassistant.helpers.restore_state import RestoreEntity
from .entities import BaseMegaEntity from .entities import BaseMegaEntity
from .hub import MegaD
from .const import CONF_DIMMER, CONF_SWITCH from .const import CONF_DIMMER, CONF_SWITCH
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)

5
install.sh Normal file
View File

@@ -0,0 +1,5 @@
#!/bin/bash
git clone https://github.com/andvikt/mega_hacs.git
mkdir custom_components
cp mega_hacs/custom_components/mega custom_components/mega
rm -fR mega_hacs

138
readme.md
View File

@@ -1,97 +1,81 @@
# MegaD HomeAssistant custom component # MegaD HomeAssistant integration
Интеграция с [MegaD-2561](https://www.ab-log.ru/smart-house/ethernet/megad-2561) Интеграция с [MegaD-2561](https://www.ab-log.ru/smart-house/ethernet/megad-2561)
## Основные особенности: ## Основные особенности:
- Настройка как из yaml так и из веб-интерфейса - Настройка в веб-интерфейсе
- При настройки из веба все порты автоматически добавляются как устройства (для обычных релейных выходов создается - Все порты автоматически добавляются как устройства (для обычных релейных выходов создается
`light`, для шим - `light` с поддержкой яркости, для цифровых входов `binary_sensor`, для температурных датчиков `light`, для шим - `light` с поддержкой яркости, для цифровых входов `binary_sensor`, для датчиков
`sensor`) `sensor`)
- Возможность работы с несколькими megad - Возможность работы с несколькими megad
- Обратная связь по mqtt - Обратная связь по mqtt
- Команды выполняются друг за другом без конкурентного доступа к ресурсам megad - Команды выполняются друг за другом без конкурентного доступа к ресурсам megad, это дает гарантии надежного исполнения
## Устройства большого кол-ва команд (например в сценах). Каждая следующая команда отправляется только после получения ответа о
Поддерживаются устройства: light, switch, binary_sensor, sensor. light может работать как диммер выполнении предыдущей.
## Установка
В папке config/custom_components выполнить:
```shell
git clone https://github.com/andvikt/mega.git
```
Обновление:
```shell
git pull
```
Перезагрузить HA
## Зависимости
Перед использованием необходимо настроить интеграцию mqtt в HomeAssistant
## Настройка из веб-интерфейса ## Зависимости
**Важно!!** Перед использованием необходимо настроить интеграцию mqtt в HomeAssistant
Для максимальной совместимости необходимо обновить ваш контроллер до последней версии, тк были важные обновления в части
mqtt
## Установка
Рекомендованный способ с поддержкой обновлений - [HACS](https://hacs.xyz/docs/installation/installation):
HACS - Integrations - Explore, в поиске ищем MegaD.
Альтернативный способ установки:
```shell
# из папки с конфигом
wget -q -O - https://raw.githubusercontent.com/andvikt/mega_hacs/master/install.sh | bash -
```
Не забываем перезагрузить HA
## Настройка
`Настройки` -> `Интеграции` -> `Добавить интеграцию` в поиске ищем mega `Настройки` -> `Интеграции` -> `Добавить интеграцию` в поиске ищем mega
## Пример настройки с помощью yaml: Все имеющиеся у вас порты будут настроены автоматически.
```yaml
mega:
mega1:
host: 192.168.0.14
name: hello
password: sec
mqtt_id: mega # это id в конфиге меги
light: Вы можете менять названия, иконки и entity_id так же из интерфейса.
- platform: mega
mega1:
switch:
- 1 # можно просто перечислить порты
- 2
- 3
dimmer:
- port: 7
name: hello # можно использовать расширенный вариант с названиями
- 9
- 10
binary_sensor:
- platform: mega
mega1:
- port: 16
name: sensor1
- port: 18
name: sensor2
sensor:
- platform: mega
mega1:
- port: 10
name: some temp
type: w1
key: temp
- port: 10
name: some hum
type: w1
key: hum
switch:
- platform: mega
mega1:
- 11
```
## Сервисы ## Сервисы
Интеграция предоставляет сервис сохранения состояния портов: `mega.save` Все сервисы доступны в меню разработчика с описанием и примерами использования
```yaml ```yaml
action: mega.save:
service: mega.save description: Сохраняет текущее состояние портов (?cmd=s)
data: fields:
mega_id: def mega_id:
description: ID меги, можно оставить пустым, тогда будут сохранены все зарегистрированные меги
example: "mega"
mega.get_port:
description: Запросить текущий статус порта (или всех)
fields:
mega_id:
description: ID меги, можно оставить пустым, тогда будут порты всех зарегистрированных мег
example: "mega"
port:
description: Номер порта (если не заполнять, будут запрошены все порты сразу)
example: 1
mega.run_cmd:
description: Выполнить любую произвольную команду
fields:
mega_id:
description: ID меги
example: "mega"
port:
description: Номер порта (это не порт, которым мы управляем, а порт с которого шлем команду)
example: 1
cmd:
description: Любая поддерживаемая мегой команда
example: "1:0"
``` ```
## Состояния
Так же каждое устройство megad опрашивается на предмет работоспособности, текущий статус
хранится в mega.<id>
## Отладка ## Отладка
Если возникают проблемы, можно включить детальный лог, для этого в конфиг добавить: Интеграция находится в активной разработке, при возникновении проблем [заводите issue](https://github.com/andvikt/mega_hacs/issues/new/choose)
Просьба прикладывать детальный лог, который можно включить в конфиге так:
```yaml ```yaml
logger: logger:
default: info default: info