Make mysensors component async (#13641)
* Make mysensors component async * Use async dispatcher and discovery. * Run I/O in executor. * Make mysensors actuator methods async. * Upgrade pymysensors to 0.13.0. * Use async serial gateway. * Use async TCP gateway. * Use async mqtt gateway. * Start gateway before hass start event * Make sure gateway is started after discovery of persistent devices and after corresponding platforms have been loaded. * Don't wait to start gateway until after hass start. * Bump pymysensors to 0.14.0
This commit is contained in:
parent
ef8fc1f201
commit
be3b227a87
7 changed files with 110 additions and 80 deletions
|
@ -115,7 +115,7 @@ class MySensorsHVAC(mysensors.MySensorsEntity, ClimateDevice):
|
||||||
"""List of available fan modes."""
|
"""List of available fan modes."""
|
||||||
return ['Auto', 'Min', 'Normal', 'Max']
|
return ['Auto', 'Min', 'Normal', 'Max']
|
||||||
|
|
||||||
def set_temperature(self, **kwargs):
|
async def async_set_temperature(self, **kwargs):
|
||||||
"""Set new target temperature."""
|
"""Set new target temperature."""
|
||||||
set_req = self.gateway.const.SetReq
|
set_req = self.gateway.const.SetReq
|
||||||
temp = kwargs.get(ATTR_TEMPERATURE)
|
temp = kwargs.get(ATTR_TEMPERATURE)
|
||||||
|
@ -143,9 +143,9 @@ class MySensorsHVAC(mysensors.MySensorsEntity, ClimateDevice):
|
||||||
if self.gateway.optimistic:
|
if self.gateway.optimistic:
|
||||||
# Optimistically assume that device has changed state
|
# Optimistically assume that device has changed state
|
||||||
self._values[value_type] = value
|
self._values[value_type] = value
|
||||||
self.schedule_update_ha_state()
|
self.async_schedule_update_ha_state()
|
||||||
|
|
||||||
def set_fan_mode(self, fan_mode):
|
async def async_set_fan_mode(self, fan_mode):
|
||||||
"""Set new target temperature."""
|
"""Set new target temperature."""
|
||||||
set_req = self.gateway.const.SetReq
|
set_req = self.gateway.const.SetReq
|
||||||
self.gateway.set_child_value(
|
self.gateway.set_child_value(
|
||||||
|
@ -153,9 +153,9 @@ class MySensorsHVAC(mysensors.MySensorsEntity, ClimateDevice):
|
||||||
if self.gateway.optimistic:
|
if self.gateway.optimistic:
|
||||||
# Optimistically assume that device has changed state
|
# Optimistically assume that device has changed state
|
||||||
self._values[set_req.V_HVAC_SPEED] = fan_mode
|
self._values[set_req.V_HVAC_SPEED] = fan_mode
|
||||||
self.schedule_update_ha_state()
|
self.async_schedule_update_ha_state()
|
||||||
|
|
||||||
def set_operation_mode(self, operation_mode):
|
async def async_set_operation_mode(self, operation_mode):
|
||||||
"""Set new target temperature."""
|
"""Set new target temperature."""
|
||||||
self.gateway.set_child_value(
|
self.gateway.set_child_value(
|
||||||
self.node_id, self.child_id, self.value_type,
|
self.node_id, self.child_id, self.value_type,
|
||||||
|
@ -163,7 +163,7 @@ class MySensorsHVAC(mysensors.MySensorsEntity, ClimateDevice):
|
||||||
if self.gateway.optimistic:
|
if self.gateway.optimistic:
|
||||||
# Optimistically assume that device has changed state
|
# Optimistically assume that device has changed state
|
||||||
self._values[self.value_type] = operation_mode
|
self._values[self.value_type] = operation_mode
|
||||||
self.schedule_update_ha_state()
|
self.async_schedule_update_ha_state()
|
||||||
|
|
||||||
async def async_update(self):
|
async def async_update(self):
|
||||||
"""Update the controller with the latest value from a sensor."""
|
"""Update the controller with the latest value from a sensor."""
|
||||||
|
|
|
@ -42,7 +42,7 @@ class MySensorsCover(mysensors.MySensorsEntity, CoverDevice):
|
||||||
set_req = self.gateway.const.SetReq
|
set_req = self.gateway.const.SetReq
|
||||||
return self._values.get(set_req.V_DIMMER)
|
return self._values.get(set_req.V_DIMMER)
|
||||||
|
|
||||||
def open_cover(self, **kwargs):
|
async def async_open_cover(self, **kwargs):
|
||||||
"""Move the cover up."""
|
"""Move the cover up."""
|
||||||
set_req = self.gateway.const.SetReq
|
set_req = self.gateway.const.SetReq
|
||||||
self.gateway.set_child_value(
|
self.gateway.set_child_value(
|
||||||
|
@ -53,9 +53,9 @@ class MySensorsCover(mysensors.MySensorsEntity, CoverDevice):
|
||||||
self._values[set_req.V_DIMMER] = 100
|
self._values[set_req.V_DIMMER] = 100
|
||||||
else:
|
else:
|
||||||
self._values[set_req.V_LIGHT] = STATE_ON
|
self._values[set_req.V_LIGHT] = STATE_ON
|
||||||
self.schedule_update_ha_state()
|
self.async_schedule_update_ha_state()
|
||||||
|
|
||||||
def close_cover(self, **kwargs):
|
async def async_close_cover(self, **kwargs):
|
||||||
"""Move the cover down."""
|
"""Move the cover down."""
|
||||||
set_req = self.gateway.const.SetReq
|
set_req = self.gateway.const.SetReq
|
||||||
self.gateway.set_child_value(
|
self.gateway.set_child_value(
|
||||||
|
@ -66,9 +66,9 @@ class MySensorsCover(mysensors.MySensorsEntity, CoverDevice):
|
||||||
self._values[set_req.V_DIMMER] = 0
|
self._values[set_req.V_DIMMER] = 0
|
||||||
else:
|
else:
|
||||||
self._values[set_req.V_LIGHT] = STATE_OFF
|
self._values[set_req.V_LIGHT] = STATE_OFF
|
||||||
self.schedule_update_ha_state()
|
self.async_schedule_update_ha_state()
|
||||||
|
|
||||||
def set_cover_position(self, **kwargs):
|
async def async_set_cover_position(self, **kwargs):
|
||||||
"""Move the cover to a specific position."""
|
"""Move the cover to a specific position."""
|
||||||
position = kwargs.get(ATTR_POSITION)
|
position = kwargs.get(ATTR_POSITION)
|
||||||
set_req = self.gateway.const.SetReq
|
set_req = self.gateway.const.SetReq
|
||||||
|
@ -77,9 +77,9 @@ class MySensorsCover(mysensors.MySensorsEntity, CoverDevice):
|
||||||
if self.gateway.optimistic:
|
if self.gateway.optimistic:
|
||||||
# Optimistically assume that cover has changed state.
|
# Optimistically assume that cover has changed state.
|
||||||
self._values[set_req.V_DIMMER] = position
|
self._values[set_req.V_DIMMER] = position
|
||||||
self.schedule_update_ha_state()
|
self.async_schedule_update_ha_state()
|
||||||
|
|
||||||
def stop_cover(self, **kwargs):
|
async def async_stop_cover(self, **kwargs):
|
||||||
"""Stop the device."""
|
"""Stop the device."""
|
||||||
set_req = self.gateway.const.SetReq
|
set_req = self.gateway.const.SetReq
|
||||||
self.gateway.set_child_value(
|
self.gateway.set_child_value(
|
||||||
|
|
|
@ -130,7 +130,7 @@ class MySensorsLight(mysensors.MySensorsEntity, Light):
|
||||||
self._white = white
|
self._white = white
|
||||||
self._values[self.value_type] = hex_color
|
self._values[self.value_type] = hex_color
|
||||||
|
|
||||||
def turn_off(self, **kwargs):
|
async def async_turn_off(self, **kwargs):
|
||||||
"""Turn the device off."""
|
"""Turn the device off."""
|
||||||
value_type = self.gateway.const.SetReq.V_LIGHT
|
value_type = self.gateway.const.SetReq.V_LIGHT
|
||||||
self.gateway.set_child_value(
|
self.gateway.set_child_value(
|
||||||
|
@ -139,7 +139,7 @@ class MySensorsLight(mysensors.MySensorsEntity, Light):
|
||||||
# optimistically assume that light has changed state
|
# optimistically assume that light has changed state
|
||||||
self._state = False
|
self._state = False
|
||||||
self._values[value_type] = STATE_OFF
|
self._values[value_type] = STATE_OFF
|
||||||
self.schedule_update_ha_state()
|
self.async_schedule_update_ha_state()
|
||||||
|
|
||||||
def _async_update_light(self):
|
def _async_update_light(self):
|
||||||
"""Update the controller with values from light child."""
|
"""Update the controller with values from light child."""
|
||||||
|
@ -171,12 +171,12 @@ class MySensorsLightDimmer(MySensorsLight):
|
||||||
"""Flag supported features."""
|
"""Flag supported features."""
|
||||||
return SUPPORT_BRIGHTNESS
|
return SUPPORT_BRIGHTNESS
|
||||||
|
|
||||||
def turn_on(self, **kwargs):
|
async def async_turn_on(self, **kwargs):
|
||||||
"""Turn the device on."""
|
"""Turn the device on."""
|
||||||
self._turn_on_light()
|
self._turn_on_light()
|
||||||
self._turn_on_dimmer(**kwargs)
|
self._turn_on_dimmer(**kwargs)
|
||||||
if self.gateway.optimistic:
|
if self.gateway.optimistic:
|
||||||
self.schedule_update_ha_state()
|
self.async_schedule_update_ha_state()
|
||||||
|
|
||||||
async def async_update(self):
|
async def async_update(self):
|
||||||
"""Update the controller with the latest value from a sensor."""
|
"""Update the controller with the latest value from a sensor."""
|
||||||
|
@ -196,13 +196,13 @@ class MySensorsLightRGB(MySensorsLight):
|
||||||
return SUPPORT_BRIGHTNESS | SUPPORT_COLOR
|
return SUPPORT_BRIGHTNESS | SUPPORT_COLOR
|
||||||
return SUPPORT_COLOR
|
return SUPPORT_COLOR
|
||||||
|
|
||||||
def turn_on(self, **kwargs):
|
async def async_turn_on(self, **kwargs):
|
||||||
"""Turn the device on."""
|
"""Turn the device on."""
|
||||||
self._turn_on_light()
|
self._turn_on_light()
|
||||||
self._turn_on_dimmer(**kwargs)
|
self._turn_on_dimmer(**kwargs)
|
||||||
self._turn_on_rgb_and_w('%02x%02x%02x', **kwargs)
|
self._turn_on_rgb_and_w('%02x%02x%02x', **kwargs)
|
||||||
if self.gateway.optimistic:
|
if self.gateway.optimistic:
|
||||||
self.schedule_update_ha_state()
|
self.async_schedule_update_ha_state()
|
||||||
|
|
||||||
async def async_update(self):
|
async def async_update(self):
|
||||||
"""Update the controller with the latest value from a sensor."""
|
"""Update the controller with the latest value from a sensor."""
|
||||||
|
@ -225,10 +225,10 @@ class MySensorsLightRGBW(MySensorsLightRGB):
|
||||||
return SUPPORT_BRIGHTNESS | SUPPORT_MYSENSORS_RGBW
|
return SUPPORT_BRIGHTNESS | SUPPORT_MYSENSORS_RGBW
|
||||||
return SUPPORT_MYSENSORS_RGBW
|
return SUPPORT_MYSENSORS_RGBW
|
||||||
|
|
||||||
def turn_on(self, **kwargs):
|
async def async_turn_on(self, **kwargs):
|
||||||
"""Turn the device on."""
|
"""Turn the device on."""
|
||||||
self._turn_on_light()
|
self._turn_on_light()
|
||||||
self._turn_on_dimmer(**kwargs)
|
self._turn_on_dimmer(**kwargs)
|
||||||
self._turn_on_rgb_and_w('%02x%02x%02x%02x', **kwargs)
|
self._turn_on_rgb_and_w('%02x%02x%02x%02x', **kwargs)
|
||||||
if self.gateway.optimistic:
|
if self.gateway.optimistic:
|
||||||
self.schedule_update_ha_state()
|
self.async_schedule_update_ha_state()
|
||||||
|
|
|
@ -4,6 +4,7 @@ Connect to a MySensors gateway via pymysensors API.
|
||||||
For more details about this component, please refer to the documentation at
|
For more details about this component, please refer to the documentation at
|
||||||
https://home-assistant.io/components/mysensors/
|
https://home-assistant.io/components/mysensors/
|
||||||
"""
|
"""
|
||||||
|
import asyncio
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
@ -16,17 +17,17 @@ import voluptuous as vol
|
||||||
from homeassistant.components.mqtt import (
|
from homeassistant.components.mqtt import (
|
||||||
valid_publish_topic, valid_subscribe_topic)
|
valid_publish_topic, valid_subscribe_topic)
|
||||||
from homeassistant.const import (
|
from homeassistant.const import (
|
||||||
ATTR_BATTERY_LEVEL, CONF_NAME, CONF_OPTIMISTIC, EVENT_HOMEASSISTANT_START,
|
ATTR_BATTERY_LEVEL, CONF_NAME, CONF_OPTIMISTIC,
|
||||||
EVENT_HOMEASSISTANT_STOP, STATE_OFF, STATE_ON)
|
EVENT_HOMEASSISTANT_STOP, STATE_OFF, STATE_ON)
|
||||||
from homeassistant.core import callback
|
from homeassistant.core import callback
|
||||||
from homeassistant.helpers import discovery
|
from homeassistant.helpers import discovery
|
||||||
import homeassistant.helpers.config_validation as cv
|
import homeassistant.helpers.config_validation as cv
|
||||||
from homeassistant.helpers.dispatcher import (
|
from homeassistant.helpers.dispatcher import (
|
||||||
async_dispatcher_connect, dispatcher_send)
|
async_dispatcher_connect, async_dispatcher_send)
|
||||||
from homeassistant.helpers.entity import Entity
|
from homeassistant.helpers.entity import Entity
|
||||||
from homeassistant.setup import setup_component
|
from homeassistant.setup import async_setup_component
|
||||||
|
|
||||||
REQUIREMENTS = ['pymysensors==0.11.1']
|
REQUIREMENTS = ['pymysensors==0.14.0']
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -280,67 +281,62 @@ MYSENSORS_CONST_SCHEMA = {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def setup(hass, config):
|
async def async_setup(hass, config):
|
||||||
"""Set up the MySensors component."""
|
"""Set up the MySensors component."""
|
||||||
import mysensors.mysensors as mysensors
|
import mysensors.mysensors as mysensors
|
||||||
|
|
||||||
version = config[DOMAIN].get(CONF_VERSION)
|
version = config[DOMAIN].get(CONF_VERSION)
|
||||||
persistence = config[DOMAIN].get(CONF_PERSISTENCE)
|
persistence = config[DOMAIN].get(CONF_PERSISTENCE)
|
||||||
|
|
||||||
def setup_gateway(device, persistence_file, baud_rate, tcp_port, in_prefix,
|
async def setup_gateway(
|
||||||
out_prefix):
|
device, persistence_file, baud_rate, tcp_port, in_prefix,
|
||||||
|
out_prefix):
|
||||||
"""Return gateway after setup of the gateway."""
|
"""Return gateway after setup of the gateway."""
|
||||||
if device == MQTT_COMPONENT:
|
if device == MQTT_COMPONENT:
|
||||||
if not setup_component(hass, MQTT_COMPONENT, config):
|
if not await async_setup_component(hass, MQTT_COMPONENT, config):
|
||||||
return
|
return None
|
||||||
mqtt = hass.components.mqtt
|
mqtt = hass.components.mqtt
|
||||||
retain = config[DOMAIN].get(CONF_RETAIN)
|
retain = config[DOMAIN].get(CONF_RETAIN)
|
||||||
|
|
||||||
def pub_callback(topic, payload, qos, retain):
|
def pub_callback(topic, payload, qos, retain):
|
||||||
"""Call MQTT publish function."""
|
"""Call MQTT publish function."""
|
||||||
mqtt.publish(topic, payload, qos, retain)
|
mqtt.async_publish(topic, payload, qos, retain)
|
||||||
|
|
||||||
def sub_callback(topic, sub_cb, qos):
|
def sub_callback(topic, sub_cb, qos):
|
||||||
"""Call MQTT subscribe function."""
|
"""Call MQTT subscribe function."""
|
||||||
mqtt.subscribe(topic, sub_cb, qos)
|
@callback
|
||||||
gateway = mysensors.MQTTGateway(
|
def internal_callback(*args):
|
||||||
pub_callback, sub_callback,
|
"""Call callback."""
|
||||||
|
sub_cb(*args)
|
||||||
|
|
||||||
|
hass.async_add_job(
|
||||||
|
mqtt.async_subscribe(topic, internal_callback, qos))
|
||||||
|
|
||||||
|
gateway = mysensors.AsyncMQTTGateway(
|
||||||
|
pub_callback, sub_callback, in_prefix=in_prefix,
|
||||||
|
out_prefix=out_prefix, retain=retain, loop=hass.loop,
|
||||||
event_callback=None, persistence=persistence,
|
event_callback=None, persistence=persistence,
|
||||||
persistence_file=persistence_file,
|
persistence_file=persistence_file,
|
||||||
protocol_version=version, in_prefix=in_prefix,
|
protocol_version=version)
|
||||||
out_prefix=out_prefix, retain=retain)
|
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
is_serial_port(device)
|
await hass.async_add_job(is_serial_port, device)
|
||||||
gateway = mysensors.SerialGateway(
|
gateway = mysensors.AsyncSerialGateway(
|
||||||
device, event_callback=None, persistence=persistence,
|
device, baud=baud_rate, loop=hass.loop,
|
||||||
|
event_callback=None, persistence=persistence,
|
||||||
persistence_file=persistence_file,
|
persistence_file=persistence_file,
|
||||||
protocol_version=version, baud=baud_rate)
|
protocol_version=version)
|
||||||
except vol.Invalid:
|
except vol.Invalid:
|
||||||
try:
|
gateway = mysensors.AsyncTCPGateway(
|
||||||
socket.getaddrinfo(device, None)
|
device, port=tcp_port, loop=hass.loop, event_callback=None,
|
||||||
# valid ip address
|
persistence=persistence, persistence_file=persistence_file,
|
||||||
gateway = mysensors.TCPGateway(
|
protocol_version=version)
|
||||||
device, event_callback=None, persistence=persistence,
|
|
||||||
persistence_file=persistence_file,
|
|
||||||
protocol_version=version, port=tcp_port)
|
|
||||||
except OSError:
|
|
||||||
# invalid ip address
|
|
||||||
return
|
|
||||||
gateway.metric = hass.config.units.is_metric
|
gateway.metric = hass.config.units.is_metric
|
||||||
gateway.optimistic = config[DOMAIN].get(CONF_OPTIMISTIC)
|
gateway.optimistic = config[DOMAIN].get(CONF_OPTIMISTIC)
|
||||||
gateway.device = device
|
gateway.device = device
|
||||||
gateway.event_callback = gw_callback_factory(hass)
|
gateway.event_callback = gw_callback_factory(hass)
|
||||||
|
if persistence:
|
||||||
def gw_start(event):
|
await gateway.start_persistence()
|
||||||
"""Trigger to start of the gateway and any persistence."""
|
|
||||||
if persistence:
|
|
||||||
discover_persistent_devices(hass, gateway)
|
|
||||||
gateway.start()
|
|
||||||
hass.bus.listen_once(EVENT_HOMEASSISTANT_STOP,
|
|
||||||
lambda event: gateway.stop())
|
|
||||||
|
|
||||||
hass.bus.listen_once(EVENT_HOMEASSISTANT_START, gw_start)
|
|
||||||
|
|
||||||
return gateway
|
return gateway
|
||||||
|
|
||||||
|
@ -357,7 +353,7 @@ def setup(hass, config):
|
||||||
tcp_port = gway.get(CONF_TCP_PORT)
|
tcp_port = gway.get(CONF_TCP_PORT)
|
||||||
in_prefix = gway.get(CONF_TOPIC_IN_PREFIX, '')
|
in_prefix = gway.get(CONF_TOPIC_IN_PREFIX, '')
|
||||||
out_prefix = gway.get(CONF_TOPIC_OUT_PREFIX, '')
|
out_prefix = gway.get(CONF_TOPIC_OUT_PREFIX, '')
|
||||||
ready_gateway = setup_gateway(
|
ready_gateway = await setup_gateway(
|
||||||
device, persistence_file, baud_rate, tcp_port, in_prefix,
|
device, persistence_file, baud_rate, tcp_port, in_prefix,
|
||||||
out_prefix)
|
out_prefix)
|
||||||
if ready_gateway is not None:
|
if ready_gateway is not None:
|
||||||
|
@ -371,9 +367,36 @@ def setup(hass, config):
|
||||||
|
|
||||||
hass.data[MYSENSORS_GATEWAYS] = gateways
|
hass.data[MYSENSORS_GATEWAYS] = gateways
|
||||||
|
|
||||||
|
hass.async_add_job(finish_setup(hass, gateways))
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
async def finish_setup(hass, gateways):
|
||||||
|
"""Load any persistent devices and platforms and start gateway."""
|
||||||
|
discover_tasks = []
|
||||||
|
start_tasks = []
|
||||||
|
for gateway in gateways.values():
|
||||||
|
discover_tasks.append(discover_persistent_devices(hass, gateway))
|
||||||
|
start_tasks.append(gw_start(hass, gateway))
|
||||||
|
if discover_tasks:
|
||||||
|
# Make sure all devices and platforms are loaded before gateway start.
|
||||||
|
await asyncio.wait(discover_tasks, loop=hass.loop)
|
||||||
|
if start_tasks:
|
||||||
|
await asyncio.wait(start_tasks, loop=hass.loop)
|
||||||
|
|
||||||
|
|
||||||
|
async def gw_start(hass, gateway):
|
||||||
|
"""Start the gateway."""
|
||||||
|
@callback
|
||||||
|
def gw_stop(event):
|
||||||
|
"""Trigger to stop the gateway."""
|
||||||
|
hass.async_add_job(gateway.stop())
|
||||||
|
|
||||||
|
await gateway.start()
|
||||||
|
hass.bus.async_listen_once(EVENT_HOMEASSISTANT_STOP, gw_stop)
|
||||||
|
|
||||||
|
|
||||||
def validate_child(gateway, node_id, child):
|
def validate_child(gateway, node_id, child):
|
||||||
"""Validate that a child has the correct values according to schema.
|
"""Validate that a child has the correct values according to schema.
|
||||||
|
|
||||||
|
@ -431,14 +454,18 @@ def validate_child(gateway, node_id, child):
|
||||||
return validated
|
return validated
|
||||||
|
|
||||||
|
|
||||||
|
@callback
|
||||||
def discover_mysensors_platform(hass, platform, new_devices):
|
def discover_mysensors_platform(hass, platform, new_devices):
|
||||||
"""Discover a MySensors platform."""
|
"""Discover a MySensors platform."""
|
||||||
discovery.load_platform(
|
task = hass.async_add_job(discovery.async_load_platform(
|
||||||
hass, platform, DOMAIN, {ATTR_DEVICES: new_devices, CONF_NAME: DOMAIN})
|
hass, platform, DOMAIN,
|
||||||
|
{ATTR_DEVICES: new_devices, CONF_NAME: DOMAIN}))
|
||||||
|
return task
|
||||||
|
|
||||||
|
|
||||||
def discover_persistent_devices(hass, gateway):
|
async def discover_persistent_devices(hass, gateway):
|
||||||
"""Discover platforms for devices loaded via persistence file."""
|
"""Discover platforms for devices loaded via persistence file."""
|
||||||
|
tasks = []
|
||||||
new_devices = defaultdict(list)
|
new_devices = defaultdict(list)
|
||||||
for node_id in gateway.sensors:
|
for node_id in gateway.sensors:
|
||||||
node = gateway.sensors[node_id]
|
node = gateway.sensors[node_id]
|
||||||
|
@ -447,7 +474,9 @@ def discover_persistent_devices(hass, gateway):
|
||||||
for platform, dev_ids in validated.items():
|
for platform, dev_ids in validated.items():
|
||||||
new_devices[platform].extend(dev_ids)
|
new_devices[platform].extend(dev_ids)
|
||||||
for platform, dev_ids in new_devices.items():
|
for platform, dev_ids in new_devices.items():
|
||||||
discover_mysensors_platform(hass, platform, dev_ids)
|
tasks.append(discover_mysensors_platform(hass, platform, dev_ids))
|
||||||
|
if tasks:
|
||||||
|
await asyncio.wait(tasks, loop=hass.loop)
|
||||||
|
|
||||||
|
|
||||||
def get_mysensors_devices(hass, domain):
|
def get_mysensors_devices(hass, domain):
|
||||||
|
@ -459,6 +488,7 @@ def get_mysensors_devices(hass, domain):
|
||||||
|
|
||||||
def gw_callback_factory(hass):
|
def gw_callback_factory(hass):
|
||||||
"""Return a new callback for the gateway."""
|
"""Return a new callback for the gateway."""
|
||||||
|
@callback
|
||||||
def mysensors_callback(msg):
|
def mysensors_callback(msg):
|
||||||
"""Handle messages from a MySensors gateway."""
|
"""Handle messages from a MySensors gateway."""
|
||||||
start = timer()
|
start = timer()
|
||||||
|
@ -489,7 +519,7 @@ def gw_callback_factory(hass):
|
||||||
# Only one signal per device is needed.
|
# Only one signal per device is needed.
|
||||||
# A device can have multiple platforms, ie multiple schemas.
|
# A device can have multiple platforms, ie multiple schemas.
|
||||||
# FOR LATER: Add timer to not signal if another update comes in.
|
# FOR LATER: Add timer to not signal if another update comes in.
|
||||||
dispatcher_send(hass, signal)
|
async_dispatcher_send(hass, signal)
|
||||||
end = timer()
|
end = timer()
|
||||||
if end - start > 0.1:
|
if end - start > 0.1:
|
||||||
_LOGGER.debug(
|
_LOGGER.debug(
|
||||||
|
|
|
@ -42,7 +42,7 @@ class MySensorsNotificationService(BaseNotificationService):
|
||||||
"""Initialize the service."""
|
"""Initialize the service."""
|
||||||
self.devices = mysensors.get_mysensors_devices(hass, DOMAIN)
|
self.devices = mysensors.get_mysensors_devices(hass, DOMAIN)
|
||||||
|
|
||||||
def send_message(self, message="", **kwargs):
|
async def async_send_message(self, message="", **kwargs):
|
||||||
"""Send a message to a user."""
|
"""Send a message to a user."""
|
||||||
target_devices = kwargs.get(ATTR_TARGET)
|
target_devices = kwargs.get(ATTR_TARGET)
|
||||||
devices = [device for device in self.devices.values()
|
devices = [device for device in self.devices.values()
|
||||||
|
|
|
@ -42,7 +42,7 @@ async def async_setup_platform(
|
||||||
hass, DOMAIN, discovery_info, device_class_map,
|
hass, DOMAIN, discovery_info, device_class_map,
|
||||||
async_add_devices=async_add_devices)
|
async_add_devices=async_add_devices)
|
||||||
|
|
||||||
def send_ir_code_service(service):
|
async def async_send_ir_code_service(service):
|
||||||
"""Set IR code as device state attribute."""
|
"""Set IR code as device state attribute."""
|
||||||
entity_ids = service.data.get(ATTR_ENTITY_ID)
|
entity_ids = service.data.get(ATTR_ENTITY_ID)
|
||||||
ir_code = service.data.get(ATTR_IR_CODE)
|
ir_code = service.data.get(ATTR_IR_CODE)
|
||||||
|
@ -58,10 +58,10 @@ async def async_setup_platform(
|
||||||
|
|
||||||
kwargs = {ATTR_IR_CODE: ir_code}
|
kwargs = {ATTR_IR_CODE: ir_code}
|
||||||
for device in _devices:
|
for device in _devices:
|
||||||
device.turn_on(**kwargs)
|
await device.async_turn_on(**kwargs)
|
||||||
|
|
||||||
hass.services.async_register(
|
hass.services.async_register(
|
||||||
DOMAIN, SERVICE_SEND_IR_CODE, send_ir_code_service,
|
DOMAIN, SERVICE_SEND_IR_CODE, async_send_ir_code_service,
|
||||||
schema=SEND_IR_CODE_SERVICE_SCHEMA)
|
schema=SEND_IR_CODE_SERVICE_SCHEMA)
|
||||||
|
|
||||||
|
|
||||||
|
@ -84,23 +84,23 @@ class MySensorsSwitch(mysensors.MySensorsEntity, SwitchDevice):
|
||||||
"""Return True if switch is on."""
|
"""Return True if switch is on."""
|
||||||
return self._values.get(self.value_type) == STATE_ON
|
return self._values.get(self.value_type) == STATE_ON
|
||||||
|
|
||||||
def turn_on(self, **kwargs):
|
async def async_turn_on(self, **kwargs):
|
||||||
"""Turn the switch on."""
|
"""Turn the switch on."""
|
||||||
self.gateway.set_child_value(
|
self.gateway.set_child_value(
|
||||||
self.node_id, self.child_id, self.value_type, 1)
|
self.node_id, self.child_id, self.value_type, 1)
|
||||||
if self.gateway.optimistic:
|
if self.gateway.optimistic:
|
||||||
# optimistically assume that switch has changed state
|
# optimistically assume that switch has changed state
|
||||||
self._values[self.value_type] = STATE_ON
|
self._values[self.value_type] = STATE_ON
|
||||||
self.schedule_update_ha_state()
|
self.async_schedule_update_ha_state()
|
||||||
|
|
||||||
def turn_off(self, **kwargs):
|
async def async_turn_off(self, **kwargs):
|
||||||
"""Turn the switch off."""
|
"""Turn the switch off."""
|
||||||
self.gateway.set_child_value(
|
self.gateway.set_child_value(
|
||||||
self.node_id, self.child_id, self.value_type, 0)
|
self.node_id, self.child_id, self.value_type, 0)
|
||||||
if self.gateway.optimistic:
|
if self.gateway.optimistic:
|
||||||
# optimistically assume that switch has changed state
|
# optimistically assume that switch has changed state
|
||||||
self._values[self.value_type] = STATE_OFF
|
self._values[self.value_type] = STATE_OFF
|
||||||
self.schedule_update_ha_state()
|
self.async_schedule_update_ha_state()
|
||||||
|
|
||||||
|
|
||||||
class MySensorsIRSwitch(MySensorsSwitch):
|
class MySensorsIRSwitch(MySensorsSwitch):
|
||||||
|
@ -117,7 +117,7 @@ class MySensorsIRSwitch(MySensorsSwitch):
|
||||||
set_req = self.gateway.const.SetReq
|
set_req = self.gateway.const.SetReq
|
||||||
return self._values.get(set_req.V_LIGHT) == STATE_ON
|
return self._values.get(set_req.V_LIGHT) == STATE_ON
|
||||||
|
|
||||||
def turn_on(self, **kwargs):
|
async def async_turn_on(self, **kwargs):
|
||||||
"""Turn the IR switch on."""
|
"""Turn the IR switch on."""
|
||||||
set_req = self.gateway.const.SetReq
|
set_req = self.gateway.const.SetReq
|
||||||
if ATTR_IR_CODE in kwargs:
|
if ATTR_IR_CODE in kwargs:
|
||||||
|
@ -130,11 +130,11 @@ class MySensorsIRSwitch(MySensorsSwitch):
|
||||||
# optimistically assume that switch has changed state
|
# optimistically assume that switch has changed state
|
||||||
self._values[self.value_type] = self._ir_code
|
self._values[self.value_type] = self._ir_code
|
||||||
self._values[set_req.V_LIGHT] = STATE_ON
|
self._values[set_req.V_LIGHT] = STATE_ON
|
||||||
self.schedule_update_ha_state()
|
self.async_schedule_update_ha_state()
|
||||||
# turn off switch after switch was turned on
|
# turn off switch after switch was turned on
|
||||||
self.turn_off()
|
await self.async_turn_off()
|
||||||
|
|
||||||
def turn_off(self, **kwargs):
|
async def async_turn_off(self, **kwargs):
|
||||||
"""Turn the IR switch off."""
|
"""Turn the IR switch off."""
|
||||||
set_req = self.gateway.const.SetReq
|
set_req = self.gateway.const.SetReq
|
||||||
self.gateway.set_child_value(
|
self.gateway.set_child_value(
|
||||||
|
@ -142,7 +142,7 @@ class MySensorsIRSwitch(MySensorsSwitch):
|
||||||
if self.gateway.optimistic:
|
if self.gateway.optimistic:
|
||||||
# optimistically assume that switch has changed state
|
# optimistically assume that switch has changed state
|
||||||
self._values[set_req.V_LIGHT] = STATE_OFF
|
self._values[set_req.V_LIGHT] = STATE_OFF
|
||||||
self.schedule_update_ha_state()
|
self.async_schedule_update_ha_state()
|
||||||
|
|
||||||
async def async_update(self):
|
async def async_update(self):
|
||||||
"""Update the controller with the latest value from a sensor."""
|
"""Update the controller with the latest value from a sensor."""
|
||||||
|
|
|
@ -869,7 +869,7 @@ pymusiccast==0.1.6
|
||||||
pymyq==0.0.8
|
pymyq==0.0.8
|
||||||
|
|
||||||
# homeassistant.components.mysensors
|
# homeassistant.components.mysensors
|
||||||
pymysensors==0.11.1
|
pymysensors==0.14.0
|
||||||
|
|
||||||
# homeassistant.components.lock.nello
|
# homeassistant.components.lock.nello
|
||||||
pynello==1.5.1
|
pynello==1.5.1
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue