Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Adds light switch platform * Addresses HoundCI warnings * Addresses Flake8 reported issues * Removes async_update call as per review
- Loading branch information
Showing
2 changed files
with
194 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
""" | ||
Light support for switch entities. | ||
For more information about this platform, please refer to the documentation at | ||
https://home-assistant.io/components/light.switch/ | ||
""" | ||
import logging | ||
import voluptuous as vol | ||
|
||
from homeassistant.core import State, callback | ||
from homeassistant.components.light import ( | ||
Light, PLATFORM_SCHEMA) | ||
from homeassistant.components import switch | ||
from homeassistant.const import ( | ||
STATE_ON, | ||
ATTR_ENTITY_ID, | ||
CONF_NAME, | ||
CONF_ENTITY_ID, | ||
STATE_UNAVAILABLE | ||
) | ||
from homeassistant.helpers.typing import HomeAssistantType, ConfigType | ||
from homeassistant.helpers.event import async_track_state_change | ||
import homeassistant.helpers.config_validation as cv | ||
|
||
_LOGGER = logging.getLogger(__name__) | ||
|
||
DEFAULT_NAME = 'Light Switch' | ||
|
||
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ | ||
vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string, | ||
vol.Required(CONF_ENTITY_ID): cv.entity_domain(switch.DOMAIN) | ||
}) | ||
|
||
|
||
async def async_setup_platform(hass: HomeAssistantType, config: ConfigType, | ||
async_add_entities, | ||
discovery_info=None) -> None: | ||
"""Initialize Light Switch platform.""" | ||
async_add_entities([LightSwitch(config.get(CONF_NAME), | ||
config[CONF_ENTITY_ID])], True) | ||
|
||
|
||
class LightSwitch(Light): | ||
"""Represents a Switch as a Light.""" | ||
|
||
def __init__(self, name: str, switch_entity_id: str) -> None: | ||
"""Initialize Light Switch.""" | ||
self._name = name # type: str | ||
self._switch_entity_id = switch_entity_id # type: str | ||
self._is_on = False # type: bool | ||
self._available = False # type: bool | ||
self._async_unsub_state_changed = None | ||
|
||
@property | ||
def name(self) -> str: | ||
"""Return the name of the entity.""" | ||
return self._name | ||
|
||
@property | ||
def is_on(self) -> bool: | ||
"""Return true if light switch is on.""" | ||
return self._is_on | ||
|
||
@property | ||
def available(self) -> bool: | ||
"""Return true if light switch is on.""" | ||
return self._available | ||
|
||
@property | ||
def should_poll(self) -> bool: | ||
"""No polling needed for a light switch.""" | ||
return False | ||
|
||
async def async_turn_on(self, **kwargs): | ||
"""Forward the turn_on command to the switch in this light switch.""" | ||
data = {ATTR_ENTITY_ID: self._switch_entity_id} | ||
await self.hass.services.async_call( | ||
switch.DOMAIN, switch.SERVICE_TURN_ON, data, blocking=True) | ||
|
||
async def async_turn_off(self, **kwargs): | ||
"""Forward the turn_off command to the switch in this light switch.""" | ||
data = {ATTR_ENTITY_ID: self._switch_entity_id} | ||
await self.hass.services.async_call( | ||
switch.DOMAIN, switch.SERVICE_TURN_OFF, data, blocking=True) | ||
|
||
async def async_update(self): | ||
"""Query the switch in this light switch and determine the state.""" | ||
switch_state = self.hass.states.get(self._switch_entity_id) | ||
|
||
if switch_state is None: | ||
self._available = False | ||
return | ||
|
||
self._is_on = switch_state.state == STATE_ON | ||
self._available = switch_state.state != STATE_UNAVAILABLE | ||
|
||
async def async_added_to_hass(self) -> None: | ||
"""Register callbacks.""" | ||
@callback | ||
def async_state_changed_listener(entity_id: str, old_state: State, | ||
new_state: State): | ||
"""Handle child updates.""" | ||
self.async_schedule_update_ha_state(True) | ||
|
||
self._async_unsub_state_changed = async_track_state_change( | ||
self.hass, self._switch_entity_id, async_state_changed_listener) | ||
|
||
async def async_will_remove_from_hass(self): | ||
"""Handle removal from Home Assistant.""" | ||
if self._async_unsub_state_changed is not None: | ||
self._async_unsub_state_changed() | ||
self._async_unsub_state_changed = None | ||
self._available = False |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
"""The tests for the Light Switch platform.""" | ||
|
||
from homeassistant.setup import async_setup_component | ||
from tests.components.light import common | ||
from tests.components.switch import common as switch_common | ||
|
||
|
||
async def test_default_state(hass): | ||
"""Test light switch default state.""" | ||
await async_setup_component(hass, 'light', {'light': { | ||
'platform': 'switch', 'entity_id': 'switch.test', | ||
'name': 'Christmas Tree Lights' | ||
}}) | ||
await hass.async_block_till_done() | ||
|
||
state = hass.states.get('light.christmas_tree_lights') | ||
assert state is not None | ||
assert state.state == 'unavailable' | ||
assert state.attributes['supported_features'] == 0 | ||
assert state.attributes.get('brightness') is None | ||
assert state.attributes.get('hs_color') is None | ||
assert state.attributes.get('color_temp') is None | ||
assert state.attributes.get('white_value') is None | ||
assert state.attributes.get('effect_list') is None | ||
assert state.attributes.get('effect') is None | ||
|
||
|
||
async def test_light_service_calls(hass): | ||
"""Test service calls to light.""" | ||
await async_setup_component(hass, 'switch', {'switch': [ | ||
{'platform': 'demo'} | ||
]}) | ||
await async_setup_component(hass, 'light', {'light': [ | ||
{'platform': 'switch', 'entity_id': 'switch.decorative_lights'} | ||
]}) | ||
await hass.async_block_till_done() | ||
|
||
assert hass.states.get('light.light_switch').state == 'on' | ||
|
||
common.async_toggle(hass, 'light.light_switch') | ||
await hass.async_block_till_done() | ||
|
||
assert hass.states.get('switch.decorative_lights').state == 'off' | ||
assert hass.states.get('light.light_switch').state == 'off' | ||
|
||
common.async_turn_on(hass, 'light.light_switch') | ||
await hass.async_block_till_done() | ||
|
||
assert hass.states.get('switch.decorative_lights').state == 'on' | ||
assert hass.states.get('light.light_switch').state == 'on' | ||
|
||
common.async_turn_off(hass, 'light.light_switch') | ||
await hass.async_block_till_done() | ||
|
||
assert hass.states.get('switch.decorative_lights').state == 'off' | ||
assert hass.states.get('light.light_switch').state == 'off' | ||
|
||
|
||
async def test_switch_service_calls(hass): | ||
"""Test service calls to switch.""" | ||
await async_setup_component(hass, 'switch', {'switch': [ | ||
{'platform': 'demo'} | ||
]}) | ||
await async_setup_component(hass, 'light', {'light': [ | ||
{'platform': 'switch', 'entity_id': 'switch.decorative_lights'} | ||
]}) | ||
await hass.async_block_till_done() | ||
|
||
assert hass.states.get('light.light_switch').state == 'on' | ||
|
||
switch_common.async_turn_off(hass, 'switch.decorative_lights') | ||
await hass.async_block_till_done() | ||
|
||
assert hass.states.get('switch.decorative_lights').state == 'off' | ||
assert hass.states.get('light.light_switch').state == 'off' | ||
|
||
switch_common.async_turn_on(hass, 'switch.decorative_lights') | ||
await hass.async_block_till_done() | ||
|
||
assert hass.states.get('switch.decorative_lights').state == 'on' | ||
assert hass.states.get('light.light_switch').state == 'on' |