Use attributes in mochad (#76032)

This commit is contained in:
epenet 2022-08-30 21:49:28 +02:00 committed by GitHub
parent 46affe5c82
commit 7f883b7ff3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 47 additions and 70 deletions

View File

@ -4,7 +4,7 @@ from __future__ import annotations
import logging import logging
from typing import Any from typing import Any
from pymochad import device from pymochad import controller, device
from pymochad.exceptions import MochadException from pymochad.exceptions import MochadException
import voluptuous as vol import voluptuous as vol
@ -20,7 +20,7 @@ from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import CONF_COMM_TYPE, DOMAIN, REQ_LOCK from . import CONF_COMM_TYPE, DOMAIN, REQ_LOCK, MochadCtrl
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
CONF_BRIGHTNESS_LEVELS = "brightness_levels" CONF_BRIGHTNESS_LEVELS = "brightness_levels"
@ -49,66 +49,50 @@ def setup_platform(
discovery_info: DiscoveryInfoType | None = None, discovery_info: DiscoveryInfoType | None = None,
) -> None: ) -> None:
"""Set up X10 dimmers over a mochad controller.""" """Set up X10 dimmers over a mochad controller."""
mochad_controller = hass.data[DOMAIN] mochad_controller: MochadCtrl = hass.data[DOMAIN]
devs = config[CONF_DEVICES] devs: list[dict[str, Any]] = config[CONF_DEVICES]
add_entities([MochadLight(hass, mochad_controller.ctrl, dev) for dev in devs]) add_entities([MochadLight(hass, mochad_controller.ctrl, dev) for dev in devs])
class MochadLight(LightEntity): class MochadLight(LightEntity):
"""Representation of a X10 dimmer over Mochad.""" """Representation of a X10 dimmer over Mochad."""
_attr_assumed_state = True # X10 devices are normally 1-way
_attr_color_mode = ColorMode.BRIGHTNESS _attr_color_mode = ColorMode.BRIGHTNESS
_attr_supported_color_modes = {ColorMode.BRIGHTNESS} _attr_supported_color_modes = {ColorMode.BRIGHTNESS}
def __init__(self, hass, ctrl, dev): def __init__(
self, hass: HomeAssistant, ctrl: controller.PyMochad, dev: dict[str, Any]
) -> None:
"""Initialize a Mochad Light Device.""" """Initialize a Mochad Light Device."""
self._controller = ctrl self._controller = ctrl
self._address = dev[CONF_ADDRESS] self._address: str = dev[CONF_ADDRESS]
self._name = dev.get(CONF_NAME, f"x10_light_dev_{self._address}") self._attr_name: str = dev.get(CONF_NAME, f"x10_light_dev_{self._address}")
self._comm_type = dev.get(CONF_COMM_TYPE, "pl") self._comm_type: str = dev.get(CONF_COMM_TYPE, "pl")
self.light = device.Device(ctrl, self._address, comm_type=self._comm_type) self.light = device.Device(ctrl, self._address, comm_type=self._comm_type)
self._brightness = 0 self._attr_brightness = 0
self._state = self._get_device_status() self._attr_is_on = self._get_device_status()
self._brightness_levels = dev.get(CONF_BRIGHTNESS_LEVELS) - 1 self._brightness_levels: int = dev[CONF_BRIGHTNESS_LEVELS] - 1
@property def _get_device_status(self) -> bool:
def brightness(self):
"""Return the brightness of this light between 0..255."""
return self._brightness
def _get_device_status(self):
"""Get the status of the light from mochad.""" """Get the status of the light from mochad."""
with REQ_LOCK: with REQ_LOCK:
status = self.light.get_status().rstrip() status = self.light.get_status().rstrip()
return status == "on" return status == "on"
@property def _calculate_brightness_value(self, value: int) -> int:
def name(self):
"""Return the display name of this light."""
return self._name
@property
def is_on(self):
"""Return true if the light is on."""
return self._state
@property
def assumed_state(self):
"""X10 devices are normally 1-way so we have to assume the state."""
return True
def _calculate_brightness_value(self, value):
return int(value * (float(self._brightness_levels) / 255.0)) return int(value * (float(self._brightness_levels) / 255.0))
def _adjust_brightness(self, brightness): def _adjust_brightness(self, brightness: int) -> None:
if self._brightness > brightness: assert self.brightness is not None
bdelta = self._brightness - brightness if self.brightness > brightness:
bdelta = self.brightness - brightness
mochad_brightness = self._calculate_brightness_value(bdelta) mochad_brightness = self._calculate_brightness_value(bdelta)
self.light.send_cmd(f"dim {mochad_brightness}") self.light.send_cmd(f"dim {mochad_brightness}")
self._controller.read_data() self._controller.read_data()
elif self._brightness < brightness: elif self.brightness < brightness:
bdelta = brightness - self._brightness bdelta = brightness - self.brightness
mochad_brightness = self._calculate_brightness_value(bdelta) mochad_brightness = self._calculate_brightness_value(bdelta)
self.light.send_cmd(f"bright {mochad_brightness}") self.light.send_cmd(f"bright {mochad_brightness}")
self._controller.read_data() self._controller.read_data()
@ -116,7 +100,7 @@ class MochadLight(LightEntity):
def turn_on(self, **kwargs: Any) -> None: def turn_on(self, **kwargs: Any) -> None:
"""Send the command to turn the light on.""" """Send the command to turn the light on."""
_LOGGER.debug("Reconnect %s:%s", self._controller.server, self._controller.port) _LOGGER.debug("Reconnect %s:%s", self._controller.server, self._controller.port)
brightness = kwargs.get(ATTR_BRIGHTNESS, 255) brightness: int = kwargs.get(ATTR_BRIGHTNESS, 255)
with REQ_LOCK: with REQ_LOCK:
try: try:
# Recycle socket on new command to recover mochad connection # Recycle socket on new command to recover mochad connection
@ -130,11 +114,11 @@ class MochadLight(LightEntity):
self._controller.read_data() self._controller.read_data()
# There is no persistence for X10 modules so a fresh on command # There is no persistence for X10 modules so a fresh on command
# will be full brightness # will be full brightness
if self._brightness == 0: if self.brightness == 0:
self._brightness = 255 self._attr_brightness = 255
self._adjust_brightness(brightness) self._adjust_brightness(brightness)
self._brightness = brightness self._attr_brightness = brightness
self._state = True self._attr_is_on = True
except (MochadException, OSError) as exc: except (MochadException, OSError) as exc:
_LOGGER.error("Error with mochad communication: %s", exc) _LOGGER.error("Error with mochad communication: %s", exc)
@ -150,7 +134,7 @@ class MochadLight(LightEntity):
# There is no persistence for X10 modules so we need to prepare # There is no persistence for X10 modules so we need to prepare
# to track a fresh on command will full brightness # to track a fresh on command will full brightness
if self._brightness_levels == 31: if self._brightness_levels == 31:
self._brightness = 0 self._attr_brightness = 0
self._state = False self._attr_is_on = False
except (MochadException, OSError) as exc: except (MochadException, OSError) as exc:
_LOGGER.error("Error with mochad communication: %s", exc) _LOGGER.error("Error with mochad communication: %s", exc)

View File

@ -2,8 +2,9 @@
from __future__ import annotations from __future__ import annotations
import logging import logging
from typing import Any
from pymochad import device from pymochad import controller, device
from pymochad.exceptions import MochadException from pymochad.exceptions import MochadException
import voluptuous as vol import voluptuous as vol
@ -14,7 +15,7 @@ from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from . import CONF_COMM_TYPE, DOMAIN, REQ_LOCK from . import CONF_COMM_TYPE, DOMAIN, REQ_LOCK, MochadCtrl
_LOGGER = logging.getLogger(__name__) _LOGGER = logging.getLogger(__name__)
@ -40,35 +41,32 @@ def setup_platform(
discovery_info: DiscoveryInfoType | None = None, discovery_info: DiscoveryInfoType | None = None,
) -> None: ) -> None:
"""Set up X10 switches over a mochad controller.""" """Set up X10 switches over a mochad controller."""
mochad_controller = hass.data[DOMAIN] mochad_controller: MochadCtrl = hass.data[DOMAIN]
devs = config[CONF_DEVICES] devs: list[dict[str, str]] = config[CONF_DEVICES]
add_entities([MochadSwitch(hass, mochad_controller.ctrl, dev) for dev in devs]) add_entities([MochadSwitch(hass, mochad_controller.ctrl, dev) for dev in devs])
class MochadSwitch(SwitchEntity): class MochadSwitch(SwitchEntity):
"""Representation of a X10 switch over Mochad.""" """Representation of a X10 switch over Mochad."""
def __init__(self, hass, ctrl, dev): def __init__(
self, hass: HomeAssistant, ctrl: controller.PyMochad, dev: dict[str, str]
) -> None:
"""Initialize a Mochad Switch Device.""" """Initialize a Mochad Switch Device."""
self._controller = ctrl self._controller = ctrl
self._address = dev[CONF_ADDRESS] self._address: str = dev[CONF_ADDRESS]
self._name = dev.get(CONF_NAME, f"x10_switch_dev_{self._address}") self._attr_name: str = dev.get(CONF_NAME, f"x10_switch_dev_{self._address}")
self._comm_type = dev.get(CONF_COMM_TYPE, "pl") self._comm_type: str = dev.get(CONF_COMM_TYPE, "pl")
self.switch = device.Device(ctrl, self._address, comm_type=self._comm_type) self.switch = device.Device(ctrl, self._address, comm_type=self._comm_type)
# Init with false to avoid locking HA for long on CM19A (goes from rf # Init with false to avoid locking HA for long on CM19A (goes from rf
# to pl via TM751, but not other way around) # to pl via TM751, but not other way around)
if self._comm_type == "pl": if self._comm_type == "pl":
self._state = self._get_device_status() self._attr_is_on = self._get_device_status()
else: else:
self._state = False self._attr_is_on = False
@property def turn_on(self, **kwargs: Any) -> None:
def name(self):
"""Get the name of the switch."""
return self._name
def turn_on(self, **kwargs):
"""Turn the switch on.""" """Turn the switch on."""
_LOGGER.debug("Reconnect %s:%s", self._controller.server, self._controller.port) _LOGGER.debug("Reconnect %s:%s", self._controller.server, self._controller.port)
@ -80,11 +78,11 @@ class MochadSwitch(SwitchEntity):
# No read data on CM19A which is rf only # No read data on CM19A which is rf only
if self._comm_type == "pl": if self._comm_type == "pl":
self._controller.read_data() self._controller.read_data()
self._state = True self._attr_is_on = True
except (MochadException, OSError) as exc: except (MochadException, OSError) as exc:
_LOGGER.error("Error with mochad communication: %s", exc) _LOGGER.error("Error with mochad communication: %s", exc)
def turn_off(self, **kwargs): def turn_off(self, **kwargs: Any) -> None:
"""Turn the switch off.""" """Turn the switch off."""
_LOGGER.debug("Reconnect %s:%s", self._controller.server, self._controller.port) _LOGGER.debug("Reconnect %s:%s", self._controller.server, self._controller.port)
@ -96,17 +94,12 @@ class MochadSwitch(SwitchEntity):
# No read data on CM19A which is rf only # No read data on CM19A which is rf only
if self._comm_type == "pl": if self._comm_type == "pl":
self._controller.read_data() self._controller.read_data()
self._state = False self._attr_is_on = False
except (MochadException, OSError) as exc: except (MochadException, OSError) as exc:
_LOGGER.error("Error with mochad communication: %s", exc) _LOGGER.error("Error with mochad communication: %s", exc)
def _get_device_status(self): def _get_device_status(self) -> bool:
"""Get the status of the switch from mochad.""" """Get the status of the switch from mochad."""
with REQ_LOCK: with REQ_LOCK:
status = self.switch.get_status().rstrip() status = self.switch.get_status().rstrip()
return status == "on" return status == "on"
@property
def is_on(self):
"""Return true if switch is on."""
return self._state