1 """Support for Geofency."""
3 from http
import HTTPStatus
5 from aiohttp
import web
6 import voluptuous
as vol
25 from .const
import DOMAIN
27 PLATFORMS = [Platform.DEVICE_TRACKER]
29 CONF_MOBILE_BEACONS =
"mobile_beacons"
31 CONFIG_SCHEMA = vol.Schema(
33 vol.Optional(DOMAIN): vol.Schema(
35 vol.Optional(CONF_MOBILE_BEACONS, default=[]): vol.All(
36 cv.ensure_list, [cv.string]
41 extra=vol.ALLOW_EXTRA,
44 ATTR_ADDRESS =
"address"
45 ATTR_BEACON_ID =
"beaconUUID"
46 ATTR_CURRENT_LATITUDE =
"currentLatitude"
47 ATTR_CURRENT_LONGITUDE =
"currentLongitude"
48 ATTR_DEVICE =
"device"
51 BEACON_DEV_PREFIX =
"beacon"
56 TRACKER_UPDATE = f
"{DOMAIN}_tracker_update"
60 r"""Coerce address by replacing '\n' with ' '."""
61 return value.replace(
"\n",
" ")
64 WEBHOOK_SCHEMA = vol.Schema(
66 vol.Required(ATTR_ADDRESS): vol.All(cv.string, _address),
67 vol.Required(ATTR_DEVICE): vol.All(cv.string, slugify),
68 vol.Required(ATTR_ENTRY): vol.Any(LOCATION_ENTRY, LOCATION_EXIT),
69 vol.Required(ATTR_LATITUDE): cv.latitude,
70 vol.Required(ATTR_LONGITUDE): cv.longitude,
71 vol.Required(ATTR_NAME): vol.All(cv.string, slugify),
72 vol.Optional(ATTR_CURRENT_LATITUDE): cv.latitude,
73 vol.Optional(ATTR_CURRENT_LONGITUDE): cv.longitude,
74 vol.Optional(ATTR_BEACON_ID): cv.string,
76 extra=vol.ALLOW_EXTRA,
80 async
def async_setup(hass: HomeAssistant, hass_config: ConfigType) -> bool:
81 """Set up the Geofency component."""
82 config = hass_config.get(DOMAIN, {})
83 mobile_beacons = config.get(CONF_MOBILE_BEACONS, [])
85 "beacons": [
slugify(beacon)
for beacon
in mobile_beacons],
87 "unsub_device_tracker": {},
93 hass: HomeAssistant, webhook_id: str, request: web.Request
95 """Handle incoming webhook from Geofency."""
98 except vol.MultipleInvalid
as error:
100 text=error.error_message, status=HTTPStatus.UNPROCESSABLE_ENTITY
105 if data[
"entry"] == LOCATION_ENTRY:
106 location_name = data[
"name"]
108 location_name = STATE_NOT_HOME
109 if ATTR_CURRENT_LATITUDE
in data:
110 data[ATTR_LATITUDE] = data[ATTR_CURRENT_LATITUDE]
111 data[ATTR_LONGITUDE] = data[ATTR_CURRENT_LONGITUDE]
117 """Check if we have a mobile beacon."""
118 return ATTR_BEACON_ID
in data
and data[
"name"]
in mobile_beacons
122 """Return name of device tracker."""
123 if ATTR_BEACON_ID
in data:
124 return f
"{BEACON_DEV_PREFIX}_{data['name']}"
125 return data[
"device"]
129 """Fire HA event to set location."""
136 (data[ATTR_LATITUDE], data[ATTR_LONGITUDE]),
141 return web.Response(text=f
"Setting location for {device}")
145 """Configure based on config entry."""
146 webhook.async_register(
147 hass, DOMAIN,
"Geofency", entry.data[CONF_WEBHOOK_ID], handle_webhook
150 await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS)
155 """Unload a config entry."""
156 webhook.async_unregister(hass, entry.data[CONF_WEBHOOK_ID])
157 hass.data[DOMAIN][
"unsub_device_tracker"].pop(entry.entry_id)()
158 return await hass.config_entries.async_unload_platforms(entry, PLATFORMS)
161 async_remove_entry = config_entry_flow.webhook_async_remove_entry
bool async_setup(HomeAssistant hass, ConfigType hass_config)
def _set_location(hass, data, location_name)
def _is_mobile_beacon(data, mobile_beacons)
bool async_unload_entry(HomeAssistant hass, ConfigEntry entry)
bool async_setup_entry(HomeAssistant hass, ConfigEntry entry)
web.Response handle_webhook(HomeAssistant hass, str webhook_id, web.Request request)
None async_dispatcher_send(HomeAssistant hass, str signal, *Any args)
str slugify(str|None text, *str separator="_")