1 """Support for Harmony Hub devices."""
3 from __future__
import annotations
5 from collections.abc
import Iterable
10 import voluptuous
as vol
32 ATTR_ACTIVITY_STARTING,
36 HARMONY_OPTIONS_UPDATE,
37 PREVIOUS_ACTIVE_ACTIVITY,
38 SERVICE_CHANGE_CHANNEL,
41 from .data
import HarmonyConfigEntry, HarmonyData
42 from .entity
import HarmonyEntity
43 from .subscriber
import HarmonyCallback
45 _LOGGER = logging.getLogger(__name__)
50 ATTR_CHANNEL =
"channel"
52 HARMONY_CHANGE_CHANNEL_SCHEMA: VolDictType = {
53 vol.Required(ATTR_CHANNEL): cv.positive_int,
59 entry: HarmonyConfigEntry,
60 async_add_entities: AddEntitiesCallback,
62 """Set up the Harmony config entry."""
63 data = entry.runtime_data
65 _LOGGER.debug(
"HarmonyData : %s", data)
67 default_activity: str |
None = entry.options.get(ATTR_ACTIVITY)
68 delay_secs: float = entry.options.get(ATTR_DELAY_SECS, DEFAULT_DELAY_SECS)
70 harmony_conf_file = hass.config.path(f
"harmony_{entry.unique_id}.conf")
71 device =
HarmonyRemote(data, default_activity, delay_secs, harmony_conf_file)
74 platform = entity_platform.async_get_current_platform()
76 platform.async_register_entity_service(
81 platform.async_register_entity_service(
82 SERVICE_CHANGE_CHANNEL, HARMONY_CHANGE_CHANNEL_SCHEMA,
"change_channel"
87 """Remote representation used to control a Harmony device."""
89 _attr_supported_features = RemoteEntityFeature.ACTIVITY
93 self, data: HarmonyData, activity: str |
None, delay_secs: float, out_path: str
95 """Initialize HarmonyRemote class."""
97 self.
_state_state: bool |
None =
None
109 """Change options when the options flow does."""
110 if ATTR_DELAY_SECS
in data:
111 self.
delay_secsdelay_secs = data[ATTR_DELAY_SECS]
113 if ATTR_ACTIVITY
in data:
131 """Call for finished updated current activity."""
136 """Complete the initialization."""
139 _LOGGER.debug(
"%s: Harmony Hub added", self.
_data_data.name)
147 f
"{HARMONY_OPTIONS_UPDATE}-{self.unique_id}",
161 if ATTR_LAST_ACTIVITY
not in last_state.attributes:
166 self.
_last_activity_last_activity = last_state.attributes[ATTR_LAST_ACTIVITY]
170 """Return the current activity."""
175 """Return the available activities."""
176 return self.
_data_data.activity_names
180 """Add platform specific attributes."""
183 ATTR_DEVICES_LIST: self.
_data_data.device_names,
189 """Return False if PowerOff is the current activity, otherwise True."""
194 """Call for updating the current activity."""
195 activity_id, activity_name = activity_info
196 _LOGGER.debug(
"%s: activity reported as: %s", self.
_data_data.name, activity_name)
202 if activity_id != -1:
211 """Call for updating the current activity."""
212 _LOGGER.debug(
"%s: configuration has been updated", self.
_data_data.name)
217 """Start an activity from the Harmony device."""
218 _LOGGER.debug(
"%s: Turn On", self.
_data_data.name)
222 if not activity
or activity == PREVIOUS_ACTIVE_ACTIVITY:
225 elif all_activities := self.
_data_data.activity_names:
226 activity = all_activities[0]
229 await self.
_data_data.async_start_activity(activity)
232 "%s: No activity specified with turn_on service", self.
_data_data.name
236 """Start the PowerOff activity."""
237 await self.
_data_data.async_power_off()
240 """Send a list of commands to one device."""
241 _LOGGER.debug(
"%s: Send Command", self.
_data_data.name)
242 if (device := kwargs.get(ATTR_DEVICE))
is None:
243 _LOGGER.error(
"%s: Missing required argument: device", self.
_data_data.name)
246 num_repeats = kwargs[ATTR_NUM_REPEATS]
247 delay_secs = kwargs.get(ATTR_DELAY_SECS, self.
delay_secsdelay_secs)
248 hold_secs = kwargs[ATTR_HOLD_SECS]
250 command, device, num_repeats, delay_secs, hold_secs
254 """Change the channel using Harmony remote."""
258 """Sync the Harmony device with the web service."""
263 """Write Harmony configuration file.
265 This is a handy way for users to figure out the available commands for automations.
268 "%s: Writing hub configuration to file: %s",
269 self.
_data_data.name,
272 if (json_config := self.
_data_data.json_config)
is None:
273 _LOGGER.warning(
"%s: No configuration received from hub", self.
_data_data.name)
277 with open(self.
_config_path_config_path,
"w+", encoding=
"utf-8")
as file_out:
278 json.dump(json_config, file_out, sort_keys=
True, indent=4)
279 except OSError
as exc:
281 "%s: Unable to write HUB configuration to %s: %s",
282 self.
_data_data.name,
None _async_clear_disconnection_delay(self)
None async_got_connected(self, str|None _=None)
None async_got_disconnected(self, str|None _=None)
None __init__(self, HarmonyData data, str|None activity, float delay_secs, str out_path)
None _setup_callbacks(self)
None change_channel(self, int channel)
None write_config_file(self)
def current_activity(self)
None async_new_config(self, dict|None _=None)
None _async_update_options(self, dict[str, Any] data)
None async_turn_off(self, **Any kwargs)
None async_send_command(self, Iterable[str] command, **Any kwargs)
None async_added_to_hass(self)
None async_new_activity_finished(self, tuple activity_info)
None async_new_activity(self, tuple activity_info)
dict[str, Any] extra_state_attributes(self)
None async_turn_on(self, **Any kwargs)
None async_write_ha_state(self)
None async_on_remove(self, CALLBACK_TYPE func)
DeviceInfo|None device_info(self)
State|None async_get_last_state(self)
None async_setup_entry(HomeAssistant hass, HarmonyConfigEntry entry, AddEntitiesCallback async_add_entities)
CALLBACK_TYPE async_subscribe(HomeAssistant hass, str topic, Callable[[ReceiveMessage], Coroutine[Any, Any, None]|None] msg_callback, int qos=DEFAULT_QOS, str|None encoding=DEFAULT_ENCODING)
None open(self, **Any kwargs)
Callable[[], None] async_dispatcher_connect(HomeAssistant hass, str signal, Callable[..., Any] target)