1 """Integrates Native Apps to Home Assistant."""
3 from contextlib
import suppress
4 from functools
import partial
10 async_register
as webhook_register,
11 async_unregister
as webhook_unregister,
17 config_validation
as cv,
18 device_registry
as dr,
28 binary_sensor
as binary_sensor_pre_import,
29 device_tracker
as device_tracker_pre_import,
30 notify
as notify_pre_import,
31 sensor
as sensor_pre_import,
50 from .helpers
import savable_state
51 from .http_api
import RegistrationsView
52 from .timers
import async_handle_timer_event
53 from .util
import async_create_cloud_hook, supports_push
54 from .webhook
import handle_webhook
56 PLATFORMS = [Platform.BINARY_SENSOR, Platform.DEVICE_TRACKER, Platform.SENSOR]
58 CONFIG_SCHEMA = cv.empty_config_schema(DOMAIN)
61 async
def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
62 """Set up the mobile app component."""
63 store = Store[dict[str, Any]](hass, STORAGE_VERSION, STORAGE_KEY)
64 if (app_config := await store.async_load())
is None or not isinstance(
68 DATA_CONFIG_ENTRIES: {},
73 DATA_CONFIG_ENTRIES: {},
74 DATA_DELETED_IDS: app_config.get(DATA_DELETED_IDS, []),
76 DATA_PUSH_CHANNEL: {},
82 for deleted_id
in hass.data[DOMAIN][DATA_DELETED_IDS]:
83 with suppress(ValueError):
85 hass, DOMAIN,
"Deleted Webhook", deleted_id, handle_webhook
88 hass.async_create_task(
89 discovery.async_load_platform(hass, Platform.NOTIFY, DOMAIN, {}, config),
93 websocket_api.async_setup_commands(hass)
95 async
def _handle_user_removed(event: Event) ->
None:
96 """Remove an entry when the user is removed."""
97 user_id = event.data[
"user_id"]
98 for entry
in hass.config_entries.async_entries(DOMAIN):
99 if entry.data[CONF_USER_ID] == user_id:
100 await hass.config_entries.async_remove(entry.entry_id)
102 hass.bus.async_listen(EVENT_USER_REMOVED, _handle_user_removed)
108 """Set up a mobile_app entry."""
109 registration = entry.data
111 webhook_id = registration[CONF_WEBHOOK_ID]
113 hass.data[DOMAIN][DATA_CONFIG_ENTRIES][webhook_id] = entry
115 device_registry = dr.async_get(hass)
117 device = device_registry.async_get_or_create(
118 config_entry_id=entry.entry_id,
119 identifiers={(DOMAIN, registration[ATTR_DEVICE_ID])},
120 manufacturer=registration[ATTR_MANUFACTURER],
121 model=registration[ATTR_MODEL],
122 name=registration[ATTR_DEVICE_NAME],
123 sw_version=registration[ATTR_OS_VERSION],
126 hass.data[DOMAIN][DATA_DEVICES][webhook_id] = device
128 registration_name = f
"Mobile App: {registration[ATTR_DEVICE_NAME]}"
129 webhook_register(hass, DOMAIN, registration_name, webhook_id, handle_webhook)
131 async
def manage_cloudhook(state: cloud.CloudConnectionState) ->
None:
133 state
is cloud.CloudConnectionState.CLOUD_CONNECTED
134 and CONF_CLOUDHOOK_URL
not in entry.data
138 if cloud.async_is_logged_in(hass):
140 CONF_CLOUDHOOK_URL
not in entry.data
141 and cloud.async_active_subscription(hass)
142 and cloud.async_is_connected(hass)
145 elif CONF_CLOUDHOOK_URL
in entry.data:
147 data =
dict(entry.data)
148 data.pop(CONF_CLOUDHOOK_URL)
149 hass.config_entries.async_update_entry(entry, data=data)
151 entry.async_on_unload(cloud.async_listen_connection_change(hass, manage_cloudhook))
153 await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
156 entry.async_on_unload(
157 intent.async_register_timer_handler(
158 hass, device.id, partial(async_handle_timer_event, hass, entry)
162 await hass_notify.async_reload(hass, DOMAIN)
168 """Unload a mobile app entry."""
169 unload_ok = await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
173 webhook_id = entry.data[CONF_WEBHOOK_ID]
175 webhook_unregister(hass, webhook_id)
176 del hass.data[DOMAIN][DATA_CONFIG_ENTRIES][webhook_id]
177 del hass.data[DOMAIN][DATA_DEVICES][webhook_id]
178 await hass_notify.async_reload(hass, DOMAIN)
184 """Cleanup when entry is removed."""
185 hass.data[DOMAIN][DATA_DELETED_IDS].append(entry.data[CONF_WEBHOOK_ID])
186 store = hass.data[DOMAIN][DATA_STORE]
189 if CONF_CLOUDHOOK_URL
in entry.data:
191 await cloud.async_delete_cloudhook(hass, entry.data[CONF_WEBHOOK_ID])
dict savable_state(HomeAssistant hass)
bool supports_push(HomeAssistant hass, str webhook_id)
str async_create_cloud_hook(HomeAssistant hass, str webhook_id, ConfigEntry|None entry)
bool async_unload_entry(HomeAssistant hass, ConfigEntry entry)
bool async_setup_entry(HomeAssistant hass, ConfigEntry entry)
None async_remove_entry(HomeAssistant hass, ConfigEntry entry)
bool async_setup(HomeAssistant hass, ConfigType config)