mirror of
https://github.com/home-assistant/core.git
synced 2025-07-18 18:57:06 +00:00
Convert switch to AsnycIO (#4382)
* Convert switch to AsnycIO * Move update entity to service * use time better for faster handling * Change to suggestion from paulus * Use new shedule_update_ha_state * fix lint * minimize executor calls
This commit is contained in:
parent
5d8a465c18
commit
41aaeb715a
@ -4,6 +4,7 @@ Component to interface with various switches that can be controlled remotely.
|
||||
For more details about this component, please refer to the documentation
|
||||
at https://home-assistant.io/components/switch/
|
||||
"""
|
||||
import asyncio
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
import os
|
||||
@ -69,38 +70,50 @@ def toggle(hass, entity_id=None):
|
||||
hass.services.call(DOMAIN, SERVICE_TOGGLE, data)
|
||||
|
||||
|
||||
def setup(hass, config):
|
||||
@asyncio.coroutine
|
||||
def async_setup(hass, config):
|
||||
"""Track states and offer events for switches."""
|
||||
component = EntityComponent(
|
||||
_LOGGER, DOMAIN, hass, SCAN_INTERVAL, GROUP_NAME_ALL_SWITCHES)
|
||||
component.setup(config)
|
||||
yield from component.async_setup(config)
|
||||
|
||||
def handle_switch_service(service):
|
||||
@asyncio.coroutine
|
||||
def async_handle_switch_service(service):
|
||||
"""Handle calls to the switch services."""
|
||||
target_switches = component.extract_from_service(service)
|
||||
target_switches = component.async_extract_from_service(service)
|
||||
|
||||
update_tasks = []
|
||||
for switch in target_switches:
|
||||
if service.service == SERVICE_TURN_ON:
|
||||
switch.turn_on()
|
||||
yield from switch.async_turn_on()
|
||||
elif service.service == SERVICE_TOGGLE:
|
||||
switch.toggle()
|
||||
yield from switch.async_toggle()
|
||||
else:
|
||||
switch.turn_off()
|
||||
yield from switch.async_turn_off()
|
||||
|
||||
if switch.should_poll:
|
||||
switch.update_ha_state(True)
|
||||
update_coro = switch.async_update_ha_state(True)
|
||||
if hasattr(switch, 'async_update'):
|
||||
update_tasks.append(hass.loop.create_task(update_coro))
|
||||
else:
|
||||
yield from update_coro
|
||||
|
||||
descriptions = load_yaml_config_file(
|
||||
os.path.join(os.path.dirname(__file__), 'services.yaml'))
|
||||
hass.services.register(DOMAIN, SERVICE_TURN_OFF, handle_switch_service,
|
||||
descriptions.get(SERVICE_TURN_OFF),
|
||||
schema=SWITCH_SERVICE_SCHEMA)
|
||||
hass.services.register(DOMAIN, SERVICE_TURN_ON, handle_switch_service,
|
||||
descriptions.get(SERVICE_TURN_ON),
|
||||
schema=SWITCH_SERVICE_SCHEMA)
|
||||
hass.services.register(DOMAIN, SERVICE_TOGGLE, handle_switch_service,
|
||||
descriptions.get(SERVICE_TOGGLE),
|
||||
schema=SWITCH_SERVICE_SCHEMA)
|
||||
if update_tasks:
|
||||
yield from asyncio.wait(update_tasks, loop=hass.loop)
|
||||
|
||||
descriptions = yield from hass.loop.run_in_executor(
|
||||
None, load_yaml_config_file, os.path.join(
|
||||
os.path.dirname(__file__), 'services.yaml'))
|
||||
|
||||
hass.services.async_register(
|
||||
DOMAIN, SERVICE_TURN_OFF, async_handle_switch_service,
|
||||
descriptions.get(SERVICE_TURN_OFF), schema=SWITCH_SERVICE_SCHEMA)
|
||||
hass.services.async_register(
|
||||
DOMAIN, SERVICE_TURN_ON, async_handle_switch_service,
|
||||
descriptions.get(SERVICE_TURN_ON), schema=SWITCH_SERVICE_SCHEMA)
|
||||
hass.services.async_register(
|
||||
DOMAIN, SERVICE_TOGGLE, async_handle_switch_service,
|
||||
descriptions.get(SERVICE_TOGGLE), schema=SWITCH_SERVICE_SCHEMA)
|
||||
|
||||
return True
|
||||
|
||||
|
@ -149,11 +149,11 @@ class CommandSwitch(SwitchDevice):
|
||||
if (CommandSwitch._switch(self._command_on) and
|
||||
not self._command_state):
|
||||
self._state = True
|
||||
self.update_ha_state()
|
||||
self.shedule_update_ha_state()
|
||||
|
||||
def turn_off(self, **kwargs):
|
||||
"""Turn the device off."""
|
||||
if (CommandSwitch._switch(self._command_off) and
|
||||
not self._command_state):
|
||||
self._state = False
|
||||
self.update_ha_state()
|
||||
self.shedule_update_ha_state()
|
||||
|
@ -66,9 +66,9 @@ class DemoSwitch(SwitchDevice):
|
||||
def turn_on(self, **kwargs):
|
||||
"""Turn the switch on."""
|
||||
self._state = True
|
||||
self.update_ha_state()
|
||||
self.shedule_update_ha_state()
|
||||
|
||||
def turn_off(self, **kwargs):
|
||||
"""Turn the device off."""
|
||||
self._state = False
|
||||
self.update_ha_state()
|
||||
self.shedule_update_ha_state()
|
||||
|
@ -79,4 +79,4 @@ class EnOceanSwitch(enocean.EnOceanDevice, ToggleEntity):
|
||||
def value_changed(self, val):
|
||||
"""Update the internal state of the switch."""
|
||||
self._on_state = val
|
||||
self.update_ha_state()
|
||||
self.shedule_update_ha_state()
|
||||
|
@ -137,7 +137,7 @@ class FluxSwitch(SwitchDevice):
|
||||
self._state = True
|
||||
self.unsub_tracker = track_utc_time_change(self.hass, self.flux_update,
|
||||
second=[0, 30])
|
||||
self.update_ha_state()
|
||||
self.shedule_update_ha_state()
|
||||
|
||||
def turn_off(self, **kwargs):
|
||||
"""Turn off flux."""
|
||||
@ -146,7 +146,7 @@ class FluxSwitch(SwitchDevice):
|
||||
self.unsub_tracker = None
|
||||
|
||||
self._state = False
|
||||
self.update_ha_state()
|
||||
self.shedule_update_ha_state()
|
||||
|
||||
def flux_update(self, now=None):
|
||||
"""Update all the lights using flux."""
|
||||
|
@ -40,7 +40,7 @@ class KNXSwitch(KNXGroupAddress, SwitchDevice):
|
||||
self.group_write(1)
|
||||
self._state = [1]
|
||||
if not self.should_poll:
|
||||
self.update_ha_state()
|
||||
self.shedule_update_ha_state()
|
||||
|
||||
def turn_off(self, **kwargs):
|
||||
"""Turn the switch off.
|
||||
@ -50,4 +50,4 @@ class KNXSwitch(KNXGroupAddress, SwitchDevice):
|
||||
self.group_write(0)
|
||||
self._state = [0]
|
||||
if not self.should_poll:
|
||||
self.update_ha_state()
|
||||
self.shedule_update_ha_state()
|
||||
|
@ -117,7 +117,7 @@ class MqttSwitch(SwitchDevice):
|
||||
if self._optimistic:
|
||||
# Optimistically assume that switch has changed state.
|
||||
self._state = True
|
||||
self.update_ha_state()
|
||||
self.shedule_update_ha_state()
|
||||
|
||||
def turn_off(self, **kwargs):
|
||||
"""Turn the device off."""
|
||||
@ -126,4 +126,4 @@ class MqttSwitch(SwitchDevice):
|
||||
if self._optimistic:
|
||||
# Optimistically assume that switch has changed state.
|
||||
self._state = False
|
||||
self.update_ha_state()
|
||||
self.shedule_update_ha_state()
|
||||
|
@ -137,7 +137,7 @@ class MySensorsSwitch(mysensors.MySensorsDeviceEntity, SwitchDevice):
|
||||
if self.gateway.optimistic:
|
||||
# optimistically assume that switch has changed state
|
||||
self._values[self.value_type] = STATE_ON
|
||||
self.update_ha_state()
|
||||
self.shedule_update_ha_state()
|
||||
|
||||
def turn_off(self):
|
||||
"""Turn the switch off."""
|
||||
@ -146,7 +146,7 @@ class MySensorsSwitch(mysensors.MySensorsDeviceEntity, SwitchDevice):
|
||||
if self.gateway.optimistic:
|
||||
# optimistically assume that switch has changed state
|
||||
self._values[self.value_type] = STATE_OFF
|
||||
self.update_ha_state()
|
||||
self.shedule_update_ha_state()
|
||||
|
||||
|
||||
class MySensorsIRSwitch(MySensorsSwitch):
|
||||
@ -182,7 +182,7 @@ class MySensorsIRSwitch(MySensorsSwitch):
|
||||
# optimistically assume that switch has changed state
|
||||
self._values[self.value_type] = self._ir_code
|
||||
self._values[set_req.V_LIGHT] = STATE_ON
|
||||
self.update_ha_state()
|
||||
self.shedule_update_ha_state()
|
||||
# turn off switch after switch was turned on
|
||||
self.turn_off()
|
||||
|
||||
@ -198,7 +198,7 @@ class MySensorsIRSwitch(MySensorsSwitch):
|
||||
if self.gateway.optimistic:
|
||||
# optimistically assume that switch has changed state
|
||||
self._values[set_req.V_LIGHT] = STATE_OFF
|
||||
self.update_ha_state()
|
||||
self.shedule_update_ha_state()
|
||||
|
||||
def update(self):
|
||||
"""Update the controller with the latest value from a sensor."""
|
||||
|
@ -156,7 +156,7 @@ class NetioSwitch(SwitchDevice):
|
||||
val[self.outlet - 1] = '1' if value else '0'
|
||||
self.netio.get('port list %s' % ''.join(val))
|
||||
self.netio.states[self.outlet - 1] = value
|
||||
self.update_ha_state()
|
||||
self.shedule_update_ha_state()
|
||||
|
||||
@property
|
||||
def is_on(self):
|
||||
|
@ -127,11 +127,11 @@ class PilightSwitch(SwitchDevice):
|
||||
self._hass.services.call(pilight.DOMAIN, pilight.SERVICE_NAME,
|
||||
self._code_on, blocking=True)
|
||||
self._state = True
|
||||
self.update_ha_state()
|
||||
self.shedule_update_ha_state()
|
||||
|
||||
def turn_off(self):
|
||||
"""Turn the switch on by calling pilight.send service with off code."""
|
||||
self._hass.services.call(pilight.DOMAIN, pilight.SERVICE_NAME,
|
||||
self._code_off, blocking=True)
|
||||
self._state = False
|
||||
self.update_ha_state()
|
||||
self.shedule_update_ha_state()
|
||||
|
@ -170,7 +170,7 @@ class PALoopbackSwitch(SwitchDevice):
|
||||
self._pa_svr.update_module_state(no_throttle=True)
|
||||
self._module_idx = self._pa_svr.get_module_idx(
|
||||
self._sink_name, self._source_name)
|
||||
self.update_ha_state()
|
||||
self.shedule_update_ha_state()
|
||||
else:
|
||||
_LOGGER.warning(IGNORED_SWITCH_WARN)
|
||||
|
||||
@ -181,7 +181,7 @@ class PALoopbackSwitch(SwitchDevice):
|
||||
self._pa_svr.update_module_state(no_throttle=True)
|
||||
self._module_idx = self._pa_svr.get_module_idx(
|
||||
self._sink_name, self._source_name)
|
||||
self.update_ha_state()
|
||||
self.shedule_update_ha_state()
|
||||
else:
|
||||
_LOGGER.warning(IGNORED_SWITCH_WARN)
|
||||
|
||||
|
@ -77,10 +77,10 @@ class RPiGPIOSwitch(ToggleEntity):
|
||||
"""Turn the device on."""
|
||||
rpi_gpio.write_output(self._port, 0 if self._invert_logic else 1)
|
||||
self._state = True
|
||||
self.update_ha_state()
|
||||
self.shedule_update_ha_state()
|
||||
|
||||
def turn_off(self):
|
||||
"""Turn the device off."""
|
||||
rpi_gpio.write_output(self._port, 1 if self._invert_logic else 0)
|
||||
self._state = False
|
||||
self.update_ha_state()
|
||||
self.shedule_update_ha_state()
|
||||
|
@ -119,7 +119,7 @@ class SCSGateSwitch(SwitchDevice):
|
||||
ToggleStatusTask(target=self._scs_id, toggled=True))
|
||||
|
||||
self._toggled = True
|
||||
self.update_ha_state()
|
||||
self.shedule_update_ha_state()
|
||||
|
||||
def turn_off(self, **kwargs):
|
||||
"""Turn the device off."""
|
||||
@ -129,7 +129,7 @@ class SCSGateSwitch(SwitchDevice):
|
||||
ToggleStatusTask(target=self._scs_id, toggled=False))
|
||||
|
||||
self._toggled = False
|
||||
self.update_ha_state()
|
||||
self.shedule_update_ha_state()
|
||||
|
||||
def process_event(self, message):
|
||||
"""Handle a SCSGate message related with this switch."""
|
||||
|
@ -92,7 +92,7 @@ class SwitchTemplate(SwitchDevice):
|
||||
@callback
|
||||
def template_switch_state_listener(entity, old_state, new_state):
|
||||
"""Called when the target device changes state."""
|
||||
hass.async_add_job(self.async_update_ha_state, True)
|
||||
hass.async_add_job(self.async_update_ha_state(True))
|
||||
|
||||
async_track_state_change(
|
||||
hass, entity_ids, template_switch_state_listener)
|
||||
|
@ -36,13 +36,13 @@ class VeraSwitch(VeraDevice, SwitchDevice):
|
||||
"""Turn device on."""
|
||||
self.vera_device.switch_on()
|
||||
self._state = STATE_ON
|
||||
self.update_ha_state()
|
||||
self.shedule_update_ha_state()
|
||||
|
||||
def turn_off(self, **kwargs):
|
||||
"""Turn device off."""
|
||||
self.vera_device.switch_off()
|
||||
self._state = STATE_OFF
|
||||
self.update_ha_state()
|
||||
self.shedule_update_ha_state()
|
||||
|
||||
@property
|
||||
def current_power_mwh(self):
|
||||
|
@ -76,13 +76,11 @@ class WOLSwitch(SwitchDevice):
|
||||
def turn_on(self):
|
||||
"""Turn the device on."""
|
||||
self._wol.send_magic_packet(self._mac_address)
|
||||
self.update_ha_state()
|
||||
|
||||
def turn_off(self):
|
||||
"""Turn the device off if an off action is present."""
|
||||
if self._off_script is not None:
|
||||
self._off_script.run()
|
||||
self.update_ha_state()
|
||||
|
||||
def update(self):
|
||||
"""Check if device is on and update the state."""
|
||||
|
@ -150,14 +150,14 @@ class WemoSwitch(SwitchDevice):
|
||||
def turn_on(self, **kwargs):
|
||||
"""Turn the switch on."""
|
||||
self._state = WEMO_ON
|
||||
self.update_ha_state()
|
||||
self.wemo.on()
|
||||
self.shedule_update_ha_state()
|
||||
|
||||
def turn_off(self):
|
||||
"""Turn the switch off."""
|
||||
self._state = WEMO_OFF
|
||||
self.update_ha_state()
|
||||
self.wemo.off()
|
||||
self.shedule_update_ha_state()
|
||||
|
||||
def update(self):
|
||||
"""Update WeMo state."""
|
||||
|
@ -1,6 +1,7 @@
|
||||
"""An abstract class for entities."""
|
||||
import asyncio
|
||||
import logging
|
||||
import functools as ft
|
||||
from timeit import default_timer as timer
|
||||
|
||||
from typing import Any, Optional, List, Dict
|
||||
@ -269,6 +270,18 @@ class Entity(object):
|
||||
self.hass.states.async_set(
|
||||
self.entity_id, state, attr, self.force_update)
|
||||
|
||||
def shedule_update_ha_state(self, force_refresh=False):
|
||||
"""Shedule a update ha state change task.
|
||||
|
||||
That is only needed on executor to not block.
|
||||
"""
|
||||
# We're already in a thread, do the force refresh here.
|
||||
if force_refresh and not hasattr(self, 'async_update'):
|
||||
self.update()
|
||||
force_refresh = False
|
||||
|
||||
self.hass.add_job(self.async_update_ha_state(force_refresh))
|
||||
|
||||
def remove(self) -> None:
|
||||
"""Remove entitiy from HASS."""
|
||||
run_coroutine_threadsafe(
|
||||
@ -324,23 +337,23 @@ class ToggleEntity(Entity):
|
||||
|
||||
def turn_on(self, **kwargs) -> None:
|
||||
"""Turn the entity on."""
|
||||
run_coroutine_threadsafe(self.async_turn_on(**kwargs),
|
||||
self.hass.loop).result()
|
||||
raise NotImplementedError()
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_turn_on(self, **kwargs):
|
||||
"""Turn the entity on."""
|
||||
raise NotImplementedError()
|
||||
yield from self.hass.loop.run_in_executor(
|
||||
None, ft.partial(self.turn_on, **kwargs))
|
||||
|
||||
def turn_off(self, **kwargs) -> None:
|
||||
"""Turn the entity off."""
|
||||
run_coroutine_threadsafe(self.async_turn_off(**kwargs),
|
||||
self.hass.loop).result()
|
||||
raise NotImplementedError()
|
||||
|
||||
@asyncio.coroutine
|
||||
def async_turn_off(self, **kwargs):
|
||||
"""Turn the entity off."""
|
||||
raise NotImplementedError()
|
||||
yield from self.hass.loop.run_in_executor(
|
||||
None, ft.partial(self.turn_off, **kwargs))
|
||||
|
||||
def toggle(self) -> None:
|
||||
"""Toggle the entity."""
|
||||
|
Loading…
x
Reference in New Issue
Block a user