2015-10-11 22:14:05 +00:00
|
|
|
"""
|
2016-03-07 17:12:06 +00:00
|
|
|
Support for the Locative platform.
|
2015-10-11 22:14:05 +00:00
|
|
|
|
2015-10-13 18:50:15 +00:00
|
|
|
For more details about this platform, please refer to the documentation at
|
2015-12-21 15:54:14 +00:00
|
|
|
https://home-assistant.io/components/device_tracker.locative/
|
2015-10-11 22:14:05 +00:00
|
|
|
"""
|
2015-12-23 10:52:52 +00:00
|
|
|
import logging
|
|
|
|
from functools import partial
|
|
|
|
|
2015-12-31 19:02:50 +00:00
|
|
|
from homeassistant.components.device_tracker import DOMAIN
|
2016-02-19 05:27:50 +00:00
|
|
|
from homeassistant.const import HTTP_UNPROCESSABLE_ENTITY, STATE_NOT_HOME
|
2015-10-11 22:14:05 +00:00
|
|
|
|
2015-12-23 10:52:52 +00:00
|
|
|
_LOGGER = logging.getLogger(__name__)
|
2015-10-11 22:14:05 +00:00
|
|
|
|
2015-12-31 19:02:50 +00:00
|
|
|
DEPENDENCIES = ['http']
|
2015-10-11 22:14:05 +00:00
|
|
|
|
2015-12-21 15:54:14 +00:00
|
|
|
URL_API_LOCATIVE_ENDPOINT = "/api/locative"
|
2015-10-12 18:58:24 +00:00
|
|
|
|
2015-10-11 22:14:05 +00:00
|
|
|
|
|
|
|
def setup_scanner(hass, config, see):
|
2016-03-07 17:12:06 +00:00
|
|
|
"""Setup an endpoint for the Locative application."""
|
2015-10-11 22:28:39 +00:00
|
|
|
# POST would be semantically better, but that currently does not work
|
2015-12-21 15:54:14 +00:00
|
|
|
# since Locative sends the data as key1=value1&key2=value2
|
2015-10-11 22:28:39 +00:00
|
|
|
# in the request body, while Home Assistant expects json there.
|
2015-10-11 22:14:05 +00:00
|
|
|
hass.http.register_path(
|
2015-12-23 10:52:52 +00:00
|
|
|
'GET', URL_API_LOCATIVE_ENDPOINT,
|
|
|
|
partial(_handle_get_api_locative, hass, see))
|
2015-10-11 22:14:05 +00:00
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
2015-12-23 10:52:52 +00:00
|
|
|
def _handle_get_api_locative(hass, see, handler, path_match, data):
|
2016-03-07 17:12:06 +00:00
|
|
|
"""Locative message received."""
|
2015-12-23 10:52:52 +00:00
|
|
|
if not _check_data(handler, data):
|
2015-10-11 22:14:05 +00:00
|
|
|
return
|
|
|
|
|
2015-12-23 10:52:52 +00:00
|
|
|
device = data['device'].replace('-', '')
|
2015-12-31 07:34:06 +00:00
|
|
|
location_name = data['id'].lower()
|
2015-12-23 10:52:52 +00:00
|
|
|
direction = data['trigger']
|
|
|
|
|
|
|
|
if direction == 'enter':
|
2015-12-31 19:02:50 +00:00
|
|
|
see(dev_id=device, location_name=location_name)
|
|
|
|
handler.write_text("Setting location to {}".format(location_name))
|
2015-12-23 10:52:52 +00:00
|
|
|
|
|
|
|
elif direction == 'exit':
|
2016-01-15 20:07:26 +00:00
|
|
|
current_state = hass.states.get("{}.{}".format(DOMAIN, device))
|
2015-12-23 10:52:52 +00:00
|
|
|
|
2016-01-15 20:07:26 +00:00
|
|
|
if current_state is None or current_state.state == location_name:
|
2015-12-23 10:52:52 +00:00
|
|
|
see(dev_id=device, location_name=STATE_NOT_HOME)
|
2015-12-31 08:43:18 +00:00
|
|
|
handler.write_text("Setting location to not home")
|
2015-12-23 10:52:52 +00:00
|
|
|
else:
|
2015-12-30 19:30:49 +00:00
|
|
|
# Ignore the message if it is telling us to exit a zone that we
|
|
|
|
# aren't currently in. This occurs when a zone is entered before
|
|
|
|
# the previous zone was exited. The enter message will be sent
|
|
|
|
# first, then the exit message will be sent second.
|
2015-12-31 05:43:00 +00:00
|
|
|
handler.write_text(
|
2015-12-31 08:43:18 +00:00
|
|
|
'Ignoring exit from {} (already in {})'.format(
|
2015-12-31 19:02:50 +00:00
|
|
|
location_name, current_state))
|
2015-12-31 00:30:20 +00:00
|
|
|
|
|
|
|
elif direction == 'test':
|
|
|
|
# In the app, a test message can be sent. Just return something to
|
|
|
|
# the user to let them know that it works.
|
|
|
|
handler.write_text("Received test message.")
|
2015-12-23 10:52:52 +00:00
|
|
|
|
|
|
|
else:
|
2015-12-31 05:43:00 +00:00
|
|
|
handler.write_text(
|
2015-12-31 07:34:06 +00:00
|
|
|
"Received unidentified message: {}".format(direction),
|
|
|
|
HTTP_UNPROCESSABLE_ENTITY)
|
2015-12-23 10:52:52 +00:00
|
|
|
_LOGGER.error("Received unidentified message from Locative: %s",
|
|
|
|
direction)
|
|
|
|
|
|
|
|
|
|
|
|
def _check_data(handler, data):
|
2016-03-07 17:12:06 +00:00
|
|
|
"""Check the data."""
|
2015-12-23 10:52:52 +00:00
|
|
|
if 'latitude' not in data or 'longitude' not in data:
|
2015-12-31 05:43:00 +00:00
|
|
|
handler.write_text("Latitude and longitude not specified.",
|
|
|
|
HTTP_UNPROCESSABLE_ENTITY)
|
2015-12-23 10:52:52 +00:00
|
|
|
_LOGGER.error("Latitude and longitude not specified.")
|
|
|
|
return False
|
|
|
|
|
|
|
|
if 'device' not in data:
|
2015-12-31 05:43:00 +00:00
|
|
|
handler.write_text("Device id not specified.",
|
|
|
|
HTTP_UNPROCESSABLE_ENTITY)
|
2015-12-23 10:52:52 +00:00
|
|
|
_LOGGER.error("Device id not specified.")
|
|
|
|
return False
|
|
|
|
|
|
|
|
if 'id' not in data:
|
2015-12-31 05:43:00 +00:00
|
|
|
handler.write_text("Location id not specified.",
|
|
|
|
HTTP_UNPROCESSABLE_ENTITY)
|
2015-12-23 10:52:52 +00:00
|
|
|
_LOGGER.error("Location id not specified.")
|
|
|
|
return False
|
|
|
|
|
|
|
|
if 'trigger' not in data:
|
2015-12-31 05:43:00 +00:00
|
|
|
handler.write_text("Trigger is not specified.",
|
|
|
|
HTTP_UNPROCESSABLE_ENTITY)
|
2015-12-23 10:52:52 +00:00
|
|
|
_LOGGER.error("Trigger is not specified.")
|
|
|
|
return False
|
|
|
|
|
|
|
|
return True
|