1 """Support for Locative."""
3 from __future__
import annotations
5 from http
import HTTPStatus
8 from aiohttp
import web
9 import voluptuous
as vol
26 _LOGGER = logging.getLogger(__name__)
29 TRACKER_UPDATE = f
"{DOMAIN}_tracker_update"
31 PLATFORMS = [Platform.DEVICE_TRACKER]
33 ATTR_DEVICE_ID =
"device"
34 ATTR_TRIGGER =
"trigger"
37 def _id(value: str) -> str:
38 """Coerce id by removing '-'."""
39 return value.replace(
"-",
"")
43 """Validate that id is provided outside of test mode."""
44 if ATTR_ID
not in obj
and obj[ATTR_TRIGGER] !=
"test":
45 raise vol.Invalid(
"Location id not specified")
49 WEBHOOK_SCHEMA = vol.All(
52 vol.Required(ATTR_LATITUDE): cv.latitude,
53 vol.Required(ATTR_LONGITUDE): cv.longitude,
54 vol.Required(ATTR_DEVICE_ID): cv.string,
55 vol.Required(ATTR_TRIGGER): cv.string,
56 vol.Optional(ATTR_ID): vol.All(cv.string, _id),
58 extra=vol.ALLOW_EXTRA,
65 hass: HomeAssistant, webhook_id: str, request: web.Request
67 """Handle incoming webhook from Locative."""
70 except vol.MultipleInvalid
as error:
72 text=error.error_message, status=HTTPStatus.UNPROCESSABLE_ENTITY
75 device = data[ATTR_DEVICE_ID]
76 location_name = data.get(ATTR_ID, data[ATTR_TRIGGER]).lower()
77 direction = data[ATTR_TRIGGER]
78 gps_location = (data[ATTR_LATITUDE], data[ATTR_LONGITUDE])
80 if direction ==
"enter":
82 return web.Response(text=f
"Setting location to {location_name}")
84 if direction ==
"exit":
85 current_state = hass.states.get(f
"{Platform.DEVICE_TRACKER}.{device}")
87 if current_state
is None or current_state.state == location_name:
88 location_name = STATE_NOT_HOME
90 hass, TRACKER_UPDATE, device, gps_location, location_name
92 return web.Response(text=
"Setting location to not home")
99 text=f
"Ignoring exit from {location_name} (already in {current_state})",
102 if direction ==
"test":
105 return web.Response(text=
"Received test message.")
107 _LOGGER.error(
"Received unidentified message from Locative: %s", direction)
109 text=f
"Received unidentified message: {direction}",
110 status=HTTPStatus.UNPROCESSABLE_ENTITY,
115 """Configure based on config entry."""
116 if DOMAIN
not in hass.data:
117 hass.data[DOMAIN] = {
"devices": set(),
"unsub_device_tracker": {}}
118 webhook.async_register(
119 hass, DOMAIN,
"Locative", entry.data[CONF_WEBHOOK_ID], handle_webhook
122 await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
127 """Unload a config entry."""
128 webhook.async_unregister(hass, entry.data[CONF_WEBHOOK_ID])
129 hass.data[DOMAIN][
"unsub_device_tracker"].pop(entry.entry_id)()
130 return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
133 async_remove_entry = config_entry_flow.webhook_async_remove_entry
dict _validate_test_mode(dict obj)
web.Response handle_webhook(HomeAssistant hass, str webhook_id, web.Request request)
bool async_unload_entry(HomeAssistant hass, ConfigEntry entry)
bool async_setup_entry(HomeAssistant hass, ConfigEntry entry)
None async_dispatcher_send(HomeAssistant hass, str signal, *Any args)