From 0b6f2f5b9133d946f1ae50a085f612858c729c34 Mon Sep 17 00:00:00 2001 From: Ioan Loosley Date: Tue, 31 Jul 2018 20:45:18 +0100 Subject: [PATCH] Opensky altitude (#15273) * Added Altitude to opensky * decided to take all metadata * Final Tidy * More formatting * moving CONF_ALTITUDE to platform * Moved CONF_ALTITUDE to platform --- homeassistant/components/sensor/opensky.py | 59 +++++++++++++++------- 1 file changed, 40 insertions(+), 19 deletions(-) diff --git a/homeassistant/components/sensor/opensky.py b/homeassistant/components/sensor/opensky.py index af0491cc26c..9178b46c488 100644 --- a/homeassistant/components/sensor/opensky.py +++ b/homeassistant/components/sensor/opensky.py @@ -13,22 +13,27 @@ import voluptuous as vol import homeassistant.helpers.config_validation as cv from homeassistant.components.sensor import PLATFORM_SCHEMA from homeassistant.const import ( - CONF_NAME, CONF_LATITUDE, CONF_LONGITUDE, CONF_RADIUS, - ATTR_ATTRIBUTION, ATTR_LATITUDE, ATTR_LONGITUDE, - LENGTH_KILOMETERS, LENGTH_METERS) + CONF_NAME, CONF_LATITUDE, CONF_LONGITUDE, + CONF_RADIUS, ATTR_ATTRIBUTION, ATTR_LATITUDE, + ATTR_LONGITUDE, LENGTH_KILOMETERS, LENGTH_METERS) from homeassistant.helpers.entity import Entity from homeassistant.util import distance as util_distance from homeassistant.util import location as util_location _LOGGER = logging.getLogger(__name__) +CONF_ALTITUDE = 'altitude' + ATTR_CALLSIGN = 'callsign' +ATTR_ALTITUDE = 'altitude' ATTR_ON_GROUND = 'on_ground' ATTR_SENSOR = 'sensor' ATTR_STATES = 'states' DOMAIN = 'opensky' +DEFAULT_ALTITUDE = 0 + EVENT_OPENSKY_ENTRY = '{}_entry'.format(DOMAIN) EVENT_OPENSKY_EXIT = '{}_exit'.format(DOMAIN) SCAN_INTERVAL = timedelta(seconds=12) # opensky public limit is 10 seconds @@ -38,7 +43,7 @@ OPENSKY_ATTRIBUTION = "Information provided by the OpenSky Network "\ OPENSKY_API_URL = 'https://opensky-network.org/api/states/all' OPENSKY_API_FIELDS = [ 'icao24', ATTR_CALLSIGN, 'origin_country', 'time_position', - 'time_velocity', ATTR_LONGITUDE, ATTR_LATITUDE, 'altitude', + 'time_velocity', ATTR_LONGITUDE, ATTR_LATITUDE, ATTR_ALTITUDE, ATTR_ON_GROUND, 'velocity', 'heading', 'vertical_rate', 'sensors'] @@ -46,7 +51,8 @@ PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({ vol.Required(CONF_RADIUS): vol.Coerce(float), vol.Optional(CONF_NAME): cv.string, vol.Inclusive(CONF_LATITUDE, 'coordinates'): cv.latitude, - vol.Inclusive(CONF_LONGITUDE, 'coordinates'): cv.longitude + vol.Inclusive(CONF_LONGITUDE, 'coordinates'): cv.longitude, + vol.Optional(CONF_ALTITUDE, default=DEFAULT_ALTITUDE): vol.Coerce(float) }) @@ -56,19 +62,20 @@ def setup_platform(hass, config, add_devices, discovery_info=None): longitude = config.get(CONF_LONGITUDE, hass.config.longitude) add_devices([OpenSkySensor( hass, config.get(CONF_NAME, DOMAIN), latitude, longitude, - config.get(CONF_RADIUS))], True) + config.get(CONF_RADIUS), config.get(CONF_ALTITUDE))], True) class OpenSkySensor(Entity): """Open Sky Network Sensor.""" - def __init__(self, hass, name, latitude, longitude, radius): + def __init__(self, hass, name, latitude, longitude, radius, altitude): """Initialize the sensor.""" self._session = requests.Session() self._latitude = latitude self._longitude = longitude self._radius = util_distance.convert( radius, LENGTH_KILOMETERS, LENGTH_METERS) + self._altitude = altitude self._state = 0 self._hass = hass self._name = name @@ -84,11 +91,18 @@ class OpenSkySensor(Entity): """Return the state of the sensor.""" return self._state - def _handle_boundary(self, callsigns, event): + def _handle_boundary(self, flights, event, metadata): """Handle flights crossing region boundary.""" - for callsign in callsigns: + for flight in flights: + if flight in metadata: + altitude = metadata[flight].get(ATTR_ALTITUDE) + else: + # Assume Flight has landed if missing. + altitude = 0 + data = { - ATTR_CALLSIGN: callsign, + ATTR_CALLSIGN: flight, + ATTR_ALTITUDE: altitude, ATTR_SENSOR: self._name, } self._hass.bus.fire(event, data) @@ -96,30 +110,37 @@ class OpenSkySensor(Entity): def update(self): """Update device state.""" currently_tracked = set() + flight_metadata = {} states = self._session.get(OPENSKY_API_URL).json().get(ATTR_STATES) for state in states: - data = dict(zip(OPENSKY_API_FIELDS, state)) + flight = dict(zip(OPENSKY_API_FIELDS, state)) + callsign = flight[ATTR_CALLSIGN].strip() + if callsign != '': + flight_metadata[callsign] = flight + else: + continue missing_location = ( - data.get(ATTR_LONGITUDE) is None or - data.get(ATTR_LATITUDE) is None) + flight.get(ATTR_LONGITUDE) is None or + flight.get(ATTR_LATITUDE) is None) if missing_location: continue - if data.get(ATTR_ON_GROUND): + if flight.get(ATTR_ON_GROUND): continue distance = util_location.distance( self._latitude, self._longitude, - data.get(ATTR_LATITUDE), data.get(ATTR_LONGITUDE)) + flight.get(ATTR_LATITUDE), flight.get(ATTR_LONGITUDE)) if distance is None or distance > self._radius: continue - callsign = data[ATTR_CALLSIGN].strip() - if callsign == '': + altitude = flight.get(ATTR_ALTITUDE) + if altitude > self._altitude and self._altitude != 0: continue currently_tracked.add(callsign) if self._previously_tracked is not None: entries = currently_tracked - self._previously_tracked exits = self._previously_tracked - currently_tracked - self._handle_boundary(entries, EVENT_OPENSKY_ENTRY) - self._handle_boundary(exits, EVENT_OPENSKY_EXIT) + self._handle_boundary(entries, EVENT_OPENSKY_ENTRY, + flight_metadata) + self._handle_boundary(exits, EVENT_OPENSKY_EXIT, flight_metadata) self._state = len(currently_tracked) self._previously_tracked = currently_tracked