Compare commits

...

16 Commits

Author SHA1 Message Date
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
Andrey
a6ff177577 fix updater 2020-12-29 08:51:43 +03:00
14 changed files with 312 additions and 219 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,17 +1,15 @@
"""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
from .const import DOMAIN, CONF_INVERT from .const import DOMAIN, CONF_INVERT, CONF_RELOAD
from .hub import MegaD from .hub import MegaD
@@ -51,15 +49,34 @@ 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():
) _POLL_TASKS[id] = asyncio.create_task(hub.poll())
return True return True
@@ -73,22 +90,24 @@ async def _add_mega(hass: HomeAssistant, id, data: dict):
raise Exception("not authentificated") raise Exception("not authentificated")
mid = await hub.get_mqtt_id() mid = await hub.get_mqtt_id()
hub.mqtt_id = mid hub.mqtt_id = mid
_POLL_TASKS[id] = asyncio.create_task(hub.poll())
return hub return hub
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)
hub = await _add_mega(hass, id, dict(entry.data)) data = dict(entry.data)
data.update(entry.options or {})
hub = await _add_mega(hass, id, data)
_hubs[entry.entry_id] = hub _hubs[entry.entry_id] = hub
_subs[entry.entry_id] = entry.add_update_listener(update) _subs[entry.entry_id] = entry.add_update_listener(update)
for platform in PLATFORMS: for platform in PLATFORMS:
hass.async_create_task( hass.async_create_task(
hass.config_entries.async_forward_entry_setup( hass.config_entries.async_forward_entry_setup(
entry, platform entry, platform
) )
) )
_POLL_TASKS[id] = asyncio.create_task(hub.poll())
return True return True
@@ -96,9 +115,9 @@ async def update(hass: HomeAssistant, entry: ConfigEntry):
hub: MegaD = hass.data[DOMAIN][entry.data[CONF_ID]] hub: MegaD = hass.data[DOMAIN][entry.data[CONF_ID]]
hub.poll_interval = entry.options[CONF_SCAN_INTERVAL] hub.poll_interval = entry.options[CONF_SCAN_INTERVAL]
hub.port_to_scan = entry.options[CONF_PORT_TO_SCAN] hub.port_to_scan = entry.options[CONF_PORT_TO_SCAN]
# hub.inverted = map(lambda x: x.strip(), ( if entry.options[CONF_RELOAD]:
# entry.options.get(CONF_INVERT, '').split(',') await async_remove_entry(hass, entry)
# ) await async_setup_entry(hass, entry)
return True return True
@@ -111,16 +130,44 @@ 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()
return True
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)
async def _is_alive(cond: asyncio.Condition, msg): @bind_hass
async with cond: async def _run_cmd(hass: HomeAssistant, call: ServiceCall):
cond.notify_all() 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,6 +1,4 @@
"""Platform for light integration.""" """Platform for light integration."""
import asyncio
import json
import logging import logging
import voluptuous as vol import voluptuous as vol
@@ -18,7 +16,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,13 +60,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)
devices.append(sensor)
async_add_devices(devices)
await 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
@@ -104,8 +104,7 @@ class OptionsFlowHandler(config_entries.OptionsFlow):
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): vol.Set(), # vol.Optional(CONF_INVERT, default=''): str,
}), }),
) )
print(ret)
return ret return ret

View File

@@ -25,11 +25,12 @@ class BaseMegaEntity(RestoreEntity):
): ):
self._state: State = None self._state: State = None
self.port = port self.port = port
self._name = name
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 @property
def lg(self) -> logging.Logger: def lg(self) -> logging.Logger:

View File

@@ -1,6 +1,7 @@
import asyncio import asyncio
import json import json
import logging import logging
from datetime import datetime
from functools import wraps from functools import wraps
import aiohttp import aiohttp
@@ -22,12 +23,12 @@ class MegaD:
host: str, host: str,
password: str, password: str,
mqtt: mqtt.MQTT, mqtt: mqtt.MQTT,
lg:logging.Logger, lg: logging.Logger,
id: str, id: str,
mqtt_id: str = None, mqtt_id: str = None,
scan_interval=60, scan_interval=60,
port_to_scan=0, port_to_scan=0,
inverted:typing.List[int] = None, inverted: typing.List[int] = None,
**kwargs, **kwargs,
): ):
"""Initialize.""" """Initialize."""
@@ -47,6 +48,7 @@ class MegaD:
self.sensors = [] self.sensors = []
self.port_to_scan = port_to_scan self.port_to_scan = port_to_scan
self.inverted = inverted or [] self.inverted = inverted or []
self.last_update = datetime.now()
if not mqtt_id: if not mqtt_id:
_id = host.split(".")[-1] _id = host.split(".")[-1]
self.mqtt_id = f"megad/{_id}" self.mqtt_id = f"megad/{_id}"
@@ -59,10 +61,11 @@ class MegaD:
self.entities.append(ent) self.entities.append(ent)
async def get_sensors(self): async def get_sensors(self):
self.lg.debug(self.sensors)
_ports = {x.port for x in self.sensors} _ports = {x.port for x in self.sensors}
for x in _ports: for x in _ports:
await self.get_port(x) await self.get_port(x)
await asyncio.sleep(self.poll_interval) await asyncio.sleep(0.1)
async def poll(self): async def poll(self):
""" """
@@ -70,36 +73,37 @@ class MegaD:
offline offline
""" """
self._loop = asyncio.get_event_loop() self._loop = asyncio.get_event_loop()
if self.sensors:
await self.subscribe(self.sensors[0].port, callback=self._notify)
else:
await self.subscribe(self.port_to_scan, callback=self._notify)
while True:
async with self.is_alive:
if len(self.sensors) > 0:
await self.get_sensors()
else:
await self.get_port(self.port_to_scan)
try: while True:
await asyncio.wait_for(self.is_alive.wait(), timeout=5) if len(self.sensors) > 0:
self.hass.states.async_set( await self.get_sensors()
f'mega.{self.id}', else:
'online', await self.get_port(self.port_to_scan)
)
self.online = True await asyncio.sleep(1)
except asyncio.TimeoutError: if (datetime.now() - self.last_update).total_seconds() > self.poll_interval:
self.online = False await self.get_port(self.port_to_scan)
await asyncio.sleep(1)
if (datetime.now() - self.last_update).total_seconds() > self.poll_interval:
self.lg.warning('mega is offline')
self.hass.states.async_set( self.hass.states.async_set(
f'mega.{self.id}', f'mega.{self.id}',
'offline', 'offline',
) )
for x in self.entities: self.online = False
try: else:
await x.async_update_ha_state() self.hass.states.async_set(
except RuntimeError: f'mega.{self.id}',
pass 'online',
await asyncio.sleep(self.poll_interval) )
self.online = True
for x in self.entities:
try:
await x.async_update_ha_state()
except RuntimeError:
pass
await asyncio.sleep(self.poll_interval - 1)
async def _async_notify(self): async def _async_notify(self):
async with self.is_alive: async with self.is_alive:
@@ -136,36 +140,45 @@ 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)
unsub = await self.mqtt.async_subscribe(
topic=f'{self.mqtt_id}/{port}',
msg_callback=cb,
qos=1,
)
self.lg.debug( def cb(msg):
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:
if '"value":NA' in msg.payload.decode():
ftr.set_result(None)
return
ret = json.loads(msg.payload).get('value')
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:
try:
unsub = await self.mqtt.async_subscribe(
topic=f'{self.mqtt_id}/{port}',
msg_callback=cb,
qos=1,
)
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}')
@@ -174,7 +187,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()
@@ -187,6 +200,7 @@ class MegaD:
self.lg.debug( self.lg.debug(
'process incomming message: %s', msg 'process incomming message: %s', msg
) )
self.last_update = datetime.now()
return callback(msg) return callback(msg)
self.lg.debug( self.lg.debug(
@@ -254,7 +268,8 @@ class MegaD:
return pty, m return pty, m
async def scan_ports(self,): async def scan_ports(self,):
for x in range(37): async with self.lck:
ret = await self.scan_port(x) for x in range(38):
if ret: ret = await self.scan_port(x)
yield [x, *ret] if ret:
yield [x, *ret]

View File

@@ -1,6 +1,4 @@
"""Platform for light integration.""" """Platform for light integration."""
import asyncio
import json
import logging import logging
import voluptuous as vol import voluptuous as vol
@@ -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')
devices.append(light)
async_add_devices(devices)
await 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,5 @@
"""Platform for light integration.""" """Platform for light integration."""
import logging import logging
import typing
import voluptuous as vol import voluptuous as vol
from homeassistant.components.sensor import ( from homeassistant.components.sensor import (
@@ -87,28 +85,33 @@ 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)
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,
})
devices.append(sensor)
hub.sensors.append(sensor)
async_add_devices(devices)
await scan()
class Mega1WSensor(BaseMegaEntity): class Mega1WSensor(BaseMegaEntity):
@@ -135,11 +138,6 @@ class Mega1WSensor(BaseMegaEntity):
self._device_class = device_class self._device_class = device_class
self._unit_of_measurement = unit_of_measurement self._unit_of_measurement = unit_of_measurement
async def async_added_to_hass(self) -> None:
await super(Mega1WSensor, self).async_added_to_hass()
self.mega.sensors.append(self)
@property @property
def unit_of_measurement(self): def unit_of_measurement(self):
return self._unit_of_measurement return self._unit_of_measurement

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

130
readme.md
View File

@@ -1,100 +1,80 @@
# 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
- Поддержка температурных датчиков в режиме шины
## Зависимости
**Важно!!** Перед использованием необходимо настроить интеграцию 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
## Устройства ## Устройства
Поддерживаются устройства: light, switch, binary_sensor, sensor. light может работать как диммер Поддерживаются устройства: light, switch, binary_sensor, sensor. light может работать как диммер
## Установка
В папке config/custom_components выполнить:
```shell
git clone https://github.com/andvikt/mega.git
```
Обновление:
```shell
git pull
```
Перезагрузить HA
## Зависимости
Перед использованием необходимо настроить интеграцию mqtt в HomeAssistant
## Настройка из веб-интерфейса ## Настройка из веб-интерфейса
`Настройки` -> `Интеграции` -> `Добавить интеграцию` в поиске ищем mega `Настройки` -> `Интеграции` -> `Добавить интеграцию` в поиске ищем mega
## Пример настройки с помощью yaml:
```yaml
mega:
mega1:
host: 192.168.0.14
name: hello
password: sec
mqtt_id: mega # это id в конфиге меги
light:
- 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:
Так же каждое устройство megad опрашивается на предмет работоспособности, текущий статус description: Запросить текущий статус порта (или всех)
хранится в mega.<id> 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"
```
## Отладка ## Отладка
Если возникают проблемы, можно включить детальный лог, для этого в конфиг добавить: Интеграция находится в активной разработке, при возникновении проблем [заводите issue](https://github.com/andvikt/mega_hacs/issues/new/choose)
Просьба прикладывать детальный лог, который можно включить в конфиге так:
```yaml ```yaml
logger: logger:
default: info default: info
logs: logs:
custom_components.mega: debug custom_components.mega: debug
``` ```