Implement OpenSky library (#92814)

* Implement OpenSky library

* Move function to library

* Fix feedback
This commit is contained in:
Joost Lekkerkerker 2023-05-24 12:48:55 +02:00 committed by GitHub
parent 0ca0ed3a31
commit db33aadcbb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 42 additions and 39 deletions

View File

@ -872,6 +872,7 @@ build.json @home-assistant/supervisor
/homeassistant/components/opengarage/ @danielhiversen /homeassistant/components/opengarage/ @danielhiversen
/tests/components/opengarage/ @danielhiversen /tests/components/opengarage/ @danielhiversen
/homeassistant/components/openhome/ @bazwilliams /homeassistant/components/openhome/ @bazwilliams
/homeassistant/components/opensky/ @joostlek
/homeassistant/components/opentherm_gw/ @mvn23 /homeassistant/components/opentherm_gw/ @mvn23
/tests/components/opentherm_gw/ @mvn23 /tests/components/opentherm_gw/ @mvn23
/homeassistant/components/openuv/ @bachya /homeassistant/components/openuv/ @bachya

View File

@ -1,7 +1,8 @@
{ {
"domain": "opensky", "domain": "opensky",
"name": "OpenSky Network", "name": "OpenSky Network",
"codeowners": [], "codeowners": ["@joostlek"],
"documentation": "https://www.home-assistant.io/integrations/opensky", "documentation": "https://www.home-assistant.io/integrations/opensky",
"iot_class": "cloud_polling" "iot_class": "cloud_polling",
"requirements": ["python-opensky==0.0.7"]
} }

View File

@ -3,7 +3,7 @@ from __future__ import annotations
from datetime import timedelta from datetime import timedelta
import requests from python_opensky import BoundingBox, OpenSky
import voluptuous as vol import voluptuous as vol
from homeassistant.components.sensor import PLATFORM_SCHEMA, SensorEntity from homeassistant.components.sensor import PLATFORM_SCHEMA, SensorEntity
@ -14,14 +14,12 @@ from homeassistant.const import (
CONF_LONGITUDE, CONF_LONGITUDE,
CONF_NAME, CONF_NAME,
CONF_RADIUS, CONF_RADIUS,
UnitOfLength,
) )
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
from homeassistant.helpers.aiohttp_client import async_get_clientsession
import homeassistant.helpers.config_validation as cv import homeassistant.helpers.config_validation as cv
from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType from homeassistant.helpers.typing import ConfigType, DiscoveryInfoType
from homeassistant.util import location as util_location
from homeassistant.util.unit_conversion import DistanceConverter
CONF_ALTITUDE = "altitude" CONF_ALTITUDE = "altitude"
@ -79,15 +77,18 @@ def setup_platform(
"""Set up the Open Sky platform.""" """Set up the Open Sky platform."""
latitude = config.get(CONF_LATITUDE, hass.config.latitude) latitude = config.get(CONF_LATITUDE, hass.config.latitude)
longitude = config.get(CONF_LONGITUDE, hass.config.longitude) longitude = config.get(CONF_LONGITUDE, hass.config.longitude)
radius = config.get(CONF_RADIUS, 0)
bounding_box = OpenSky.get_bounding_box(latitude, longitude, radius)
session = async_get_clientsession(hass)
opensky = OpenSky(session=session)
add_entities( add_entities(
[ [
OpenSkySensor( OpenSkySensor(
hass, hass,
config.get(CONF_NAME, DOMAIN), config.get(CONF_NAME, DOMAIN),
latitude, opensky,
longitude, bounding_box,
config.get(CONF_RADIUS), config[CONF_ALTITUDE],
config.get(CONF_ALTITUDE),
) )
], ],
True, True,
@ -101,19 +102,22 @@ class OpenSkySensor(SensorEntity):
"Information provided by the OpenSky Network (https://opensky-network.org)" "Information provided by the OpenSky Network (https://opensky-network.org)"
) )
def __init__(self, hass, name, latitude, longitude, radius, altitude): def __init__(
self,
hass: HomeAssistant,
name: str,
opensky: OpenSky,
bounding_box: BoundingBox,
altitude: float,
) -> None:
"""Initialize the sensor.""" """Initialize the sensor."""
self._session = requests.Session()
self._latitude = latitude
self._longitude = longitude
self._radius = DistanceConverter.convert(
radius, UnitOfLength.KILOMETERS, UnitOfLength.METERS
)
self._altitude = altitude self._altitude = altitude
self._state = 0 self._state = 0
self._hass = hass self._hass = hass
self._name = name self._name = name
self._previously_tracked = None self._previously_tracked: set[str] = set()
self._opensky = opensky
self._bounding_box = bounding_box
@property @property
def name(self): def name(self):
@ -129,10 +133,10 @@ class OpenSkySensor(SensorEntity):
"""Handle flights crossing region boundary.""" """Handle flights crossing region boundary."""
for flight in flights: for flight in flights:
if flight in metadata: if flight in metadata:
altitude = metadata[flight].get(ATTR_ALTITUDE) altitude = metadata[flight].barometric_altitude
longitude = metadata[flight].get(ATTR_LONGITUDE) longitude = metadata[flight].longitude
latitude = metadata[flight].get(ATTR_LATITUDE) latitude = metadata[flight].latitude
icao24 = metadata[flight].get(ATTR_ICAO24) icao24 = metadata[flight].icao24
else: else:
# Assume Flight has landed if missing. # Assume Flight has landed if missing.
altitude = 0 altitude = 0
@ -150,33 +154,27 @@ class OpenSkySensor(SensorEntity):
} }
self._hass.bus.fire(event, data) self._hass.bus.fire(event, data)
def update(self) -> None: async def async_update(self) -> None:
"""Update device state.""" """Update device state."""
currently_tracked = set() currently_tracked = set()
flight_metadata = {} flight_metadata = {}
states = self._session.get(OPENSKY_API_URL).json().get(ATTR_STATES) response = await self._opensky.get_states(bounding_box=self._bounding_box)
for state in states: for flight in response.states:
flight = dict(zip(OPENSKY_API_FIELDS, state)) if not flight.callsign:
callsign = flight[ATTR_CALLSIGN].strip() continue
callsign = flight.callsign.strip()
if callsign != "": if callsign != "":
flight_metadata[callsign] = flight flight_metadata[callsign] = flight
else: else:
continue continue
if ( if (
(longitude := flight.get(ATTR_LONGITUDE)) is None flight.longitude is None
or (latitude := flight.get(ATTR_LATITUDE)) is None or flight.latitude is None
or flight.get(ATTR_ON_GROUND) or flight.on_ground
or flight.barometric_altitude is None
): ):
continue continue
distance = util_location.distance( altitude = flight.barometric_altitude
self._latitude,
self._longitude,
latitude,
longitude,
)
if distance is None or distance > self._radius:
continue
altitude = flight.get(ATTR_ALTITUDE)
if altitude > self._altitude and self._altitude != 0: if altitude > self._altitude and self._altitude != 0:
continue continue
currently_tracked.add(callsign) currently_tracked.add(callsign)

View File

@ -2103,6 +2103,9 @@ python-mystrom==2.2.0
# homeassistant.components.nest # homeassistant.components.nest
python-nest==4.2.0 python-nest==4.2.0
# homeassistant.components.opensky
python-opensky==0.0.7
# homeassistant.components.otbr # homeassistant.components.otbr
# homeassistant.components.thread # homeassistant.components.thread
python-otbr-api==1.0.9 python-otbr-api==1.0.9