hass-core/homeassistant/components/harmony/switch.py
Mike Keesey 60a1948ab0
Generate switches for harmony activities automatically (#42331)
* Adding switch code for harmony activities

* Working on-off

* Removing poll code for now

* Async updates for current activity

* Update our state based on events

* Notifications we got connected or disconnected

* Remove unncessary constructor arg

* Initial switch tests

* Additional tests for switch transitions

* Test transitions for availability

* Testing switch state changes

* Tests passing

* Final tests

* Updating manifest.

* Correctly mock the return value from a call to the library

* Adding new subscriber classes

* Update class name and location

* Got the refactor working locally.

* Tests passing

* Tracking state changes

* Remove write_to_config_file - this appears to never be read.

It was added far back in the past to account for a harmony library
change, but nothing ever reads that path.

Removing that side effect from tests is a pain - avoid the side effect
completely.

* Connection changes tested

* Clean up temporary code

* Update .coveragerc for harmony component

Specifically exclude untested files instead of the whole module

* Fix linting

* test sending activity change commands by id

* Improving coverage

* Testing channel change commands

* Splitting subscriber logic into it's own class

* Improve coverage and tighten up .coveragerc

* Test cleanups.

* re-add config file writing for harmony remote

* Create fixture for the mock harmonyclient

* Reduce duplication in subscription callbacks

* use async_run_job to call callbacks

* Adding some tests for async behaviors with subscribers.

* async_call_later for delay in marking remote unavailable

* Test disconnection handling in harmony remote

* Early exit if activity not specified

* Use connection state mixin

* Lint fix after rebase

* Fix isort

* super init for ConnectionStateMixin

* Adding @mkeesey to harmony CODEOWNERS
2021-01-04 13:21:14 -10:00

87 lines
2.6 KiB
Python

"""Support for Harmony Hub activities."""
import logging
from homeassistant.components.switch import SwitchEntity
from homeassistant.const import CONF_NAME
from .connection_state import ConnectionStateMixin
from .const import DOMAIN
from .data import HarmonyData
from .subscriber import HarmonyCallback
_LOGGER = logging.getLogger(__name__)
async def async_setup_entry(hass, entry, async_add_entities):
"""Set up harmony activity switches."""
data = hass.data[DOMAIN][entry.entry_id]
activities = data.activity_names
switches = []
for activity in activities:
_LOGGER.debug("creating switch for activity: %s", activity)
name = f"{entry.data[CONF_NAME]} {activity}"
switches.append(HarmonyActivitySwitch(name, activity, data))
async_add_entities(switches, True)
class HarmonyActivitySwitch(ConnectionStateMixin, SwitchEntity):
"""Switch representation of a Harmony activity."""
def __init__(self, name: str, activity: str, data: HarmonyData):
"""Initialize HarmonyActivitySwitch class."""
super().__init__()
self._name = name
self._activity = activity
self._data = data
@property
def name(self):
"""Return the Harmony activity's name."""
return self._name
@property
def unique_id(self):
"""Return the unique id."""
return f"{self._data.unique_id}-{self._activity}"
@property
def is_on(self):
"""Return if the current activity is the one for this switch."""
_, activity_name = self._data.current_activity
return activity_name == self._activity
@property
def should_poll(self):
"""Return that we shouldn't be polled."""
return False
@property
def available(self):
"""Return True if we're connected to the Hub, otherwise False."""
return self._data.available
async def async_turn_on(self, **kwargs):
"""Start this activity."""
await self._data.async_start_activity(self._activity)
async def async_turn_off(self, **kwargs):
"""Stop this activity."""
await self._data.async_power_off()
async def async_added_to_hass(self):
"""Call when entity is added to hass."""
callbacks = {
"connected": self.got_connected,
"disconnected": self.got_disconnected,
"activity_starting": self._activity_update,
"activity_started": self._activity_update,
"config_updated": None,
}
self.async_on_remove(self._data.async_subscribe(HarmonyCallback(**callbacks)))
def _activity_update(self, activity_info: tuple):
self.async_write_ha_state()