Skip to content

Commit

Permalink
Merge pull request #171 from krahabb/dev
Browse files Browse the repository at this point in the history
Release Dare
  • Loading branch information
krahabb authored Feb 20, 2022
2 parents e428a9d + 156b8fe commit 72cdb72
Show file tree
Hide file tree
Showing 38 changed files with 2,963 additions and 1,589 deletions.
84 changes: 50 additions & 34 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -1,35 +1,51 @@
{
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
// Example of attaching to local debug server
"name": "Python: Attach Local",
"type": "python",
"request": "attach",
"port": 5678,
"host": "localhost",
"justMyCode": false,
"pathMappings": [
{
"localRoot": "${workspaceFolder}",
"remoteRoot": "."
}
]
},
{
// Example of attaching to my production server
"name": "Python: Attach Remote",
"type": "python",
"request": "attach",
"port": 5678,
"host": "homeassistant.local",
"pathMappings": [
{
"localRoot": "${workspaceFolder}",
"remoteRoot": "/usr/src/homeassistant"
}
]
}
]
}
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Emulator",
"type": "python",
"request": "launch",
"module": "aiohttp.web",
"args": [
"-H",
"127.0.0.1",
"-P",
"40000",
"custom_components.meross_lan.emulator:run",
"custom_components/meross_lan/traces/emulator",
"-K pippo",
"-U 01234567890123456789012345678901"
]
},
{
// Example of attaching to local debug server
"name": "Python: Attach Local",
"type": "python",
"request": "attach",
"port": 5678,
"host": "localhost",
"justMyCode": false,
"pathMappings": [
{
"localRoot": "${workspaceFolder}",
"remoteRoot": "."
}
]
},
{
// Example of attaching to my production server
"name": "Python: Attach Remote",
"type": "python",
"request": "attach",
"port": 5678,
"host": "homeassistant.local",
"pathMappings": [
{
"localRoot": "${workspaceFolder}",
"remoteRoot": "/usr/src/homeassistant"
}
]
}
]
}
47 changes: 28 additions & 19 deletions README.md

Large diffs are not rendered by default.

91 changes: 69 additions & 22 deletions custom_components/meross_lan/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,31 +2,27 @@
from typing import Callable, Dict, Optional, Union
from time import time
from datetime import datetime, timedelta
from logging import WARNING, INFO
from json import (
dumps as json_dumps,
loads as json_loads,
)
from aiohttp.client_exceptions import ClientConnectionError
from homeassistant.config_entries import ConfigEntry, SOURCE_DISCOVERY
from homeassistant.core import HomeAssistant, callback
from homeassistant.components.mqtt.const import MQTT_DISCONNECTED
from homeassistant.helpers import device_registry
from homeassistant.helpers.aiohttp_client import async_get_clientsession
from homeassistant.helpers.dispatcher import async_dispatcher_connect
from homeassistant.helpers.event import async_track_point_in_utc_time
from homeassistant.helpers.update_coordinator import (
DataUpdateCoordinator,
)
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from homeassistant.exceptions import ConfigEntryNotReady

from . import merossclient
from .merossclient import (
const as mc, KeyType,
MerossDeviceDescriptor, MerossHttpClient,
build_default_payload_get,
build_payload, build_default_payload_get, get_replykey,
)
from .meross_device import MerossDevice
from logging import WARNING, INFO
from .helpers import (
LOGGER, LOGGER_trap,
mqtt_publish, mqtt_is_connected,
Expand Down Expand Up @@ -119,6 +115,7 @@ async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
device.unsub_updatecoordinator_listener()
device.unsub_updatecoordinator_listener = None
api.devices.pop(device_id)
device.shutdown()

#when removing the last configentry do a complete cleanup
if (not api.devices) and (len(hass.config_entries.async_entries(DOMAIN)) == 1):
Expand Down Expand Up @@ -148,6 +145,7 @@ def __init__(self, hass: HomeAssistant):
self.hass = hass
self.key = None
self.cloud_key = None
self.deviceclasses: Dict[str, object] = {}
self.devices: Dict[str, MerossDevice] = {}
self.discovering: Dict[str, dict] = {}
self.mqtt_subscribing = False # guard for asynchronous mqtt sub registration
Expand Down Expand Up @@ -223,7 +221,7 @@ async def mqtt_receive(msg):
LOGGER_trap(INFO, 14400, "Ignoring discovery for device_id: %s (ConfigEntry is in progress)", device_id)
return

replykey = merossclient.get_replykey(header, self.key)
replykey = get_replykey(header, self.key)
if replykey != self.key:
LOGGER_trap(WARNING, 300, "Meross discovery key error for device_id: %s", device_id)
if self.key is not None:# we're using a fixed key in discovery so ignore this device
Expand Down Expand Up @@ -310,22 +308,71 @@ def build_device(self, device_id: str, entry: ConfigEntry) -> MerossDevice:
but some devices (i.e. Hub) need a (radically?) different behaviour
"""
descriptor = MerossDeviceDescriptor(entry.data.get(CONF_PAYLOAD, {}))
if (mc.KEY_HUB in descriptor.digest):
ability = descriptor.ability
digest = descriptor.digest

if (mc.KEY_HUB in digest):
from .meross_device_hub import MerossDeviceHub
device = MerossDeviceHub(self, descriptor, entry)
elif (mc.KEY_LIGHT in descriptor.digest):
from .meross_device_bulb import MerossDeviceBulb
device = MerossDeviceBulb(self, descriptor, entry)
elif (mc.KEY_GARAGEDOOR in descriptor.digest):
from .meross_device_cover import MerossDeviceGarage
device = MerossDeviceGarage(self, descriptor, entry)
elif (mc.NS_APPLIANCE_ROLLERSHUTTER_STATE in descriptor.ability):
from .meross_device_cover import MerossDeviceShutter
device = MerossDeviceShutter(self, descriptor, entry)
class_base = MerossDeviceHub
else:
class_base = MerossDevice

mixin_classes = list()
# put Toggle(X) mixin at the top of the class hierarchy
# since the toggle feature could be related to a more
# specialized entity than switch (see light for example)
# this way the __init__ for toggle entity will be called
# later and could check if a more specialized entity is
# already in place for the very same channel
if mc.NS_APPLIANCE_CONTROL_TOGGLEX in ability:
from .switch import ToggleXMixin
mixin_classes.append(ToggleXMixin)
elif mc.NS_APPLIANCE_CONTROL_TOGGLE in ability:
# toggle is older and superseded by togglex
# so no need to handle it in case
from .switch import ToggleMixin
mixin_classes.append(ToggleMixin)
if mc.KEY_LIGHT in digest:
from .light import LightMixin
mixin_classes.append(LightMixin)
if mc.NS_APPLIANCE_CONTROL_ELECTRICITY in ability:
from .sensor import ElectricityMixin
mixin_classes.append(ElectricityMixin)
if mc.NS_APPLIANCE_CONTROL_CONSUMPTIONX in ability:
from .sensor import ConsumptionMixin
mixin_classes.append(ConsumptionMixin)
if mc.KEY_SPRAY in digest:
from .select import SprayMixin
mixin_classes.append(SprayMixin)
if mc.KEY_GARAGEDOOR in digest:
from .cover import GarageMixin
mixin_classes.append(GarageMixin)
if mc.NS_APPLIANCE_ROLLERSHUTTER_STATE in ability:
from .cover import RollerShutterMixin
mixin_classes.append(RollerShutterMixin)
if mc.KEY_THERMOSTAT in digest:
from .devices.mts200 import ThermostatMixin
mixin_classes.append(ThermostatMixin)
if mc.KEY_DIFFUSER in digest:
from .devices.mod100 import DiffuserMixin
mixin_classes.append(DiffuserMixin)


# We must be careful when ordering the mixin and leave MerossDevice as last class.
# Messing up with that will cause MRO to not resolve inheritance correctly.
# see https://github.com/albertogeniola/MerossIot/blob/0.4.X.X/meross_iot/device_factory.py
mixin_classes.append(class_base)
# build a label to cache the set
class_name = ''
for m in mixin_classes:
class_name = class_name + m.__name__
if class_name in self.deviceclasses:
class_type = self.deviceclasses[class_name]
else:
from .meross_device_switch import MerossDeviceSwitch
device = MerossDeviceSwitch(self, descriptor, entry)
class_type = type(class_name, tuple(mixin_classes), {})
self.deviceclasses[class_name] = class_type

device = class_type(self, descriptor, entry)
self.devices[device_id] = device
self.update_polling_period()

Expand Down Expand Up @@ -358,7 +405,7 @@ def mqtt_publish(self,
mqtt_publish(
self.hass,
mc.TOPIC_REQUEST.format(device_id),
json_dumps(merossclient.build_payload(
json_dumps(build_payload(
namespace, method, payload, key,
mc.TOPIC_RESPONSE.format(device_id), messageid))
)
Expand Down
12 changes: 4 additions & 8 deletions custom_components/meross_lan/binary_sensor.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@

from homeassistant.components.binary_sensor import (
DOMAIN as PLATFORM_BINARY_SENSOR,
BinarySensorEntity
BinarySensorEntity,
DEVICE_CLASS_WINDOW,
)

from .meross_entity import _MerossEntity, platform_setup_entry, platform_unload_entry
Expand All @@ -14,15 +15,10 @@ async def async_unload_entry(hass: object, config_entry: object) -> bool:
return platform_unload_entry(hass, config_entry, PLATFORM_BINARY_SENSOR)


class MerossLanBinarySensor(_MerossEntity, BinarySensorEntity):
class MLBinarySensor(_MerossEntity, BinarySensorEntity):

PLATFORM = PLATFORM_BINARY_SENSOR

"""
def __init__(self, device: 'MerossDevice', _id: object, device_class: str, subdevice: 'MerossSubDevice'):
super().__init__(device, _id, device_class, subdevice)
"""

@staticmethod
def build_for_subdevice(subdevice: "MerossSubDevice", device_class: str):
return MerossLanBinarySensor(subdevice.hub, f"{subdevice.id}_{device_class}", device_class, subdevice)
return MLBinarySensor(subdevice.hub, subdevice.id, device_class, device_class, subdevice)
Loading

0 comments on commit 72cdb72

Please sign in to comment.