From adfcfad48886298cfe949705969dc0e62699cf98 Mon Sep 17 00:00:00 2001 From: Philip Lundrigan Date: Wed, 23 Dec 2015 03:52:52 -0700 Subject: [PATCH] Update locative functionality --- .../components/device_tracker/locative.py | 112 +++++++++++++----- 1 file changed, 80 insertions(+), 32 deletions(-) diff --git a/homeassistant/components/device_tracker/locative.py b/homeassistant/components/device_tracker/locative.py index 2d238992cc7..0ed97b6c4f8 100644 --- a/homeassistant/components/device_tracker/locative.py +++ b/homeassistant/components/device_tracker/locative.py @@ -6,12 +6,15 @@ Locative platform for the device tracker. For more details about this platform, please refer to the documentation at https://home-assistant.io/components/device_tracker.locative/ """ +import logging +from functools import partial + from homeassistant.const import ( - HTTP_UNPROCESSABLE_ENTITY, HTTP_INTERNAL_SERVER_ERROR) + HTTP_UNPROCESSABLE_ENTITY, HTTP_INTERNAL_SERVER_ERROR, STATE_NOT_HOME) -DEPENDENCIES = ['http'] +_LOGGER = logging.getLogger(__name__) -_SEE = 0 +DEPENDENCIES = ['http', 'zone'] URL_API_LOCATIVE_ENDPOINT = "/api/locative" @@ -19,52 +22,97 @@ URL_API_LOCATIVE_ENDPOINT = "/api/locative" def setup_scanner(hass, config, see): """ Set up an endpoint for the Locative app. """ - # Use a global variable to keep setup_scanner compact when using a callback - global _SEE - _SEE = see - # POST would be semantically better, but that currently does not work # since Locative sends the data as key1=value1&key2=value2 # in the request body, while Home Assistant expects json there. hass.http.register_path( - 'GET', URL_API_LOCATIVE_ENDPOINT, _handle_get_api_locative) + 'GET', URL_API_LOCATIVE_ENDPOINT, + partial(_handle_get_api_locative, hass, see)) return True -def _handle_get_api_locative(handler, path_match, data): +# TODO: What happens with HA turns off? +def _handle_get_api_locative(hass, see, handler, path_match, data): """ Locative message received. """ - if not isinstance(data, dict): - handler.write_json_message( - "Error while parsing Locative message.", - HTTP_INTERNAL_SERVER_ERROR) - return - if 'latitude' not in data or 'longitude' not in data: - handler.write_json_message( - "Location not specified.", - HTTP_UNPROCESSABLE_ENTITY) - return - if 'device' not in data or 'id' not in data: - handler.write_json_message( - "Device id or location id not specified.", - HTTP_UNPROCESSABLE_ENTITY) + if not _check_data(handler, data): return + device = data['device'].replace('-', '') + location_name = data['id'] + direction = data['trigger'] + try: gps_coords = (float(data['latitude']), float(data['longitude'])) except ValueError: - # If invalid latitude / longitude format - handler.write_json_message( - "Invalid latitude / longitude format.", - HTTP_UNPROCESSABLE_ENTITY) + handler.write_json_message("Invalid latitude / longitude format.", + HTTP_UNPROCESSABLE_ENTITY) + _LOGGER.error("Received invalid latitude / longitude format.") return - # entity id's in Home Assistant must be alphanumerical - device_uuid = data['device'] - device_entity_id = device_uuid.replace('-', '') + if direction == 'enter': + zones = [state for state in hass.states.entity_ids('zone')] + _LOGGER.info(zones) - _SEE(dev_id=device_entity_id, gps=gps_coords, location_name=data['id']) + if "zone.{}".format(location_name.lower()) in zones: + see(dev_id=device, location_name=location_name) + handler.write_json_message("Set new location to {}".format(location_name)) + else: + see(dev_id=device, gps=gps_coords) + handler.write_json_message("Set new location to {}".format(gps_coords)) + + elif direction == 'exit': + current_zone = hass.states.get("{}.{}".format("device_tracker", device)).state + + if current_zone.lower() == location_name.lower(): + see(dev_id=device, location_name=STATE_NOT_HOME) + handler.write_json_message("Set new location to not home") + else: + # 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. + handler.write_json_message("Ignoring transition to {}".format(location_name)) + + else: + handler.write_json_message("Received unidentified message: {}".format(direction)) + _LOGGER.error("Received unidentified message from Locative: %s", + direction) + + +def _check_data(handler, data): + if not isinstance(data, dict): + handler.write_json_message("Error while parsing Locative message.", + HTTP_INTERNAL_SERVER_ERROR) + _LOGGER.error("Error while parsing Locative message: " + "data is not a dict.") + return False + + if 'latitude' not in data or 'longitude' not in data: + handler.write_json_message("Latitude and longitude not specified.", + HTTP_UNPROCESSABLE_ENTITY) + _LOGGER.error("Latitude and longitude not specified.") + return False + + if 'device' not in data: + handler.write_json_message("Device id not specified.", + HTTP_UNPROCESSABLE_ENTITY) + _LOGGER.error("Device id not specified.") + return False + + if 'id' not in data: + handler.write_json_message("Location id not specified.", + HTTP_UNPROCESSABLE_ENTITY) + _LOGGER.error("Location id not specified.") + return False + + if 'trigger' not in data: + handler.write_json_message("Trigger is not specified.", + HTTP_UNPROCESSABLE_ENTITY) + _LOGGER.error("Trigger is not specified.") + return False + + return True - handler.write_json_message("Locative message processed")