From 991e292d7e73593d8456cc48bcdd5132c5e5b505 Mon Sep 17 00:00:00 2001 From: Robbie Trencheny Date: Mon, 8 Aug 2016 17:34:29 -0700 Subject: [PATCH] Foursquare Component (#2723) * Add a Foursquare component which accepts push notifications from Foursquare and provides a user checkin service * @balloob requested fixes * Sort .coveragerc list of components by name * Revert "Sort .coveragerc list of components by name" This reverts commit 997ae225769c31979183fecba39033d69ea3e6f2. * Only sort Foursquare since I get conflicts otherwise * Add Foursquare checkin service to services.yaml --- .coveragerc | 1 + homeassistant/components/foursquare.py | 99 ++++++++++++++++++++++++++ homeassistant/components/services.yaml | 41 +++++++++++ 3 files changed, 141 insertions(+) create mode 100644 homeassistant/components/foursquare.py diff --git a/.coveragerc b/.coveragerc index d1db30522e9..dd270beb5d7 100644 --- a/.coveragerc +++ b/.coveragerc @@ -123,6 +123,7 @@ omit = homeassistant/components/discovery.py homeassistant/components/downloader.py homeassistant/components/feedreader.py + homeassistant/components/foursquare.py homeassistant/components/garage_door/wink.py homeassistant/components/garage_door/rpi_gpio.py homeassistant/components/hdmi_cec.py diff --git a/homeassistant/components/foursquare.py b/homeassistant/components/foursquare.py new file mode 100644 index 00000000000..57fa441774c --- /dev/null +++ b/homeassistant/components/foursquare.py @@ -0,0 +1,99 @@ +""" +Allows utilizing the Foursquare (Swarm) API. + +For more details about this component, please refer to the documentation at +https://home-assistant.io/components/foursquare/ +""" +import logging +import os +import json +import requests + +import voluptuous as vol + +from homeassistant.config import load_yaml_config_file +import homeassistant.helpers.config_validation as cv +from homeassistant.components.http import HomeAssistantView + +DOMAIN = "foursquare" + +SERVICE_CHECKIN = "checkin" + +EVENT_PUSH = "foursquare.push" +EVENT_CHECKIN = "foursquare.checkin" + +CHECKIN_SERVICE_SCHEMA = vol.Schema({ + vol.Required("venueId"): cv.string, + vol.Optional("eventId"): cv.string, + vol.Optional("shout"): cv.string, + vol.Optional("mentions"): cv.string, + vol.Optional("broadcast"): cv.string, + vol.Optional("ll"): cv.string, + vol.Optional("llAcc"): cv.string, + vol.Optional("alt"): cv.string, + vol.Optional("altAcc"): cv.string, +}) + +_LOGGER = logging.getLogger(__name__) + +DEPENDENCIES = ["http"] + + +def setup(hass, config): + """Setup the notify services.""" + descriptions = load_yaml_config_file( + os.path.join(os.path.dirname(__file__), "services.yaml")) + + config = config[DOMAIN] + + def checkin_user(call): + """Check a user in on Swarm.""" + url = ("https://api.foursquare.com/v2/checkins/add" + "?oauth_token={}" + "&v=20160802" + "&m=swarm").format(config["access_token"]) + response = requests.post(url, data=call.data, timeout=10) + + if response.status_code not in (200, 201): + _LOGGER.exception( + "Error checking in user. Response %d: %s:", + response.status_code, response.reason) + + hass.bus.fire(EVENT_CHECKIN, response.text) + + # Register our service with Home Assistant. + hass.services.register(DOMAIN, "checkin", checkin_user, + descriptions[DOMAIN][SERVICE_CHECKIN], + schema=CHECKIN_SERVICE_SCHEMA) + + hass.wsgi.register_view(FoursquarePushReceiver(hass, + config["push_secret"])) + + return True + + +class FoursquarePushReceiver(HomeAssistantView): + """Handle pushes from the Foursquare API.""" + + requires_auth = False + url = "/api/foursquare" + name = "foursquare" + + def __init__(self, hass, push_secret): + """Initialize the OAuth callback view.""" + super().__init__(hass) + self.push_secret = push_secret + + def post(self, request): + """Accept the POST from Foursquare.""" + raw_data = request.form + _LOGGER.debug("Received Foursquare push: %s", raw_data) + if self.push_secret != raw_data["secret"]: + _LOGGER.error("Received Foursquare push with invalid" + "push secret! Data: %s", raw_data) + return + parsed_payload = { + key: json.loads(val) for key, val in raw_data.items() + if key != "secret" + } + self.hass.bus.fire(EVENT_PUSH, parsed_payload) diff --git a/homeassistant/components/services.yaml b/homeassistant/components/services.yaml index b42e661de1f..901a00a72ef 100644 --- a/homeassistant/components/services.yaml +++ b/homeassistant/components/services.yaml @@ -1,3 +1,44 @@ +foursquare: + checkin: + description: Check a user into a Foursquare venue + + fields: + venueId: + description: The Foursquare venue where the user is checking in. [Required] + example: IHR8THISVNU + + eventId: + description: The event the user is checking in to. [Optional] + example: UHR8THISVNT + + shout: + description: A message about your check-in. The maximum length of this field is 140 characters. [Optional] + example: There are crayons! Crayons! + + mentions: + description: Mentions in your check-in. This parameter is a semicolon-delimited list of mentions. A single mention is of the form "start,end,userid", where start is the index of the first character in the shout representing the mention, end is the index of the first character in the shout after the mention, and userid is the userid of the user being mentioned. If userid is prefixed with "fbu-", this indicates a Facebook userid that is being mention. Character indices in shouts are 0-based. [Optional] + example: 5,10,HZXXY3Y;15,20,GZYYZ3Z;25,30,fbu-GZXY13Y + + broadcast: + description: "Who to broadcast this check-in to. Accepts a comma-delimited list of values: private (off the grid) or public (share with friends), facebook share on facebook, twitter share on twitter, followers share with followers (celebrity mode users only), If no valid value is found, the default is public. [Optional]" + example: public,twitter + + ll: + description: Latitude and longitude of the user's location. Only specify this field if you have a GPS or other device reported location for the user at the time of check-in. [Optional] + example: 33.7,44.2 + + llAcc: + description: Accuracy of the user's latitude and longitude, in meters. [Optional] + example: 1 + + alt: + description: Altitude of the user's location, in meters. [Optional] + example: 0 + + altAcc: + description: Vertical accuracy of the user's location, in meters. + example: 1 + persistent_notification: create: description: Show a notification in the frontend