diff --git a/README.md b/README.md index 0456e7e..749f559 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Flightradar24 integration for Home Assistant -Flightradar24 integration allows one to track overhead flights in a given region or particular planes. It will also fire Home Assistant events when flights enter and exit the defined region. +Flightradar24 integration allows one to track overhead flights in a given region or particular planes. It will also fire Home Assistant events when flights enter/exit/landed/took off. IMPORTANT: No need FlightRadar24 subscription! @@ -19,6 +19,10 @@ It allows you: - flightradar24_entry: Fired when a flight enters the region. - flightradar24_exit: Fired when a flight exits the region. - flightradar24_most_tracked_new: Fired when a new flight appears in top 10 most tracked flights on FlightRadar24 + - flightradar24_area_landed: Fired when a flight lands in your area. + - flightradar24_area_took_off: Fired when a flight takes off in your area. + - flightradar24_tracked_landed: Fired when a tracked flight lands. + - flightradar24_tracked_took_off: Fired when a tracked flight takes off. ### Sensors - Current in area diff --git a/custom_components/flightradar24/const.py b/custom_components/flightradar24/const.py index 19e94e4..8cf9edc 100644 --- a/custom_components/flightradar24/const.py +++ b/custom_components/flightradar24/const.py @@ -7,9 +7,13 @@ CONF_MOST_TRACKED = "most_tracked" CONF_MOST_TRACKED_DEFAULT = True -EVENT_FLIGHTRADAR24_ENTRY = f"{DOMAIN}_entry" -EVENT_FLIGHTRADAR24_EXIT = f"{DOMAIN}_exit" -EVENT_FLIGHTRADAR24_MOST_TRACKED_NEW = f"{DOMAIN}_most_tracked_new" +EVENT_ENTRY = f"{DOMAIN}_entry" +EVENT_EXIT = f"{DOMAIN}_exit" +EVENT_AREA_LANDED = f"{DOMAIN}_area_landed" +EVENT_AREA_TOOK_OFF = f"{DOMAIN}_area_took_off" +EVENT_TRACKED_LANDED = f"{DOMAIN}_tracked_landed" +EVENT_TRACKED_TOOK_OFF = f"{DOMAIN}_tracked_took_off" +EVENT_MOST_TRACKED_NEW = f"{DOMAIN}_most_tracked_new" MIN_ALTITUDE = -1 MAX_ALTITUDE = 100000 diff --git a/custom_components/flightradar24/coordinator.py b/custom_components/flightradar24/coordinator.py index 66d0862..d6c581c 100644 --- a/custom_components/flightradar24/coordinator.py +++ b/custom_components/flightradar24/coordinator.py @@ -1,5 +1,6 @@ from __future__ import annotations from typing import Any +from enum import Enum from datetime import timedelta from homeassistant.core import HomeAssistant from homeassistant.helpers.update_coordinator import DataUpdateCoordinator @@ -9,14 +10,23 @@ DOMAIN, URL, DEFAULT_NAME, - EVENT_FLIGHTRADAR24_ENTRY, - EVENT_FLIGHTRADAR24_EXIT, - EVENT_FLIGHTRADAR24_MOST_TRACKED_NEW, + EVENT_ENTRY, + EVENT_EXIT, + EVENT_MOST_TRACKED_NEW, + EVENT_AREA_LANDED, + EVENT_AREA_TOOK_OFF, + EVENT_TRACKED_LANDED, + EVENT_TRACKED_TOOK_OFF, ) from logging import Logger from FlightRadar24 import FlightRadar24API, Flight, Entity +class SensorType(Enum): + TRACKED = 1 + IN_AREA = 2 + + class FlightRadar24Coordinator(DataUpdateCoordinator[int]): def __init__( @@ -105,15 +115,15 @@ async def _update_flights_in_area(self) -> None: for obj in flights: if not self.min_altitude <= obj.altitude <= self.max_altitude: continue - await self._update_flights_data(obj, current, self.in_area) + await self._update_flights_data(obj, current, self.in_area, SensorType.IN_AREA) if self.in_area is not None: entries = current.keys() - self.in_area.keys() self.entered = [current[x] for x in entries] exits = self.in_area.keys() - current.keys() self.exited = [self.in_area[x] for x in exits] - self._handle_boundary(EVENT_FLIGHTRADAR24_ENTRY, self.entered) - self._handle_boundary(EVENT_FLIGHTRADAR24_EXIT, self.exited) + self._handle_boundary(EVENT_ENTRY, self.entered) + self._handle_boundary(EVENT_EXIT, self.exited) self.in_area = current async def _update_flights_tracked(self) -> None: @@ -126,7 +136,7 @@ async def _update_flights_tracked(self) -> None: ) current: dict[int, dict[str, Any]] = {} for obj in flights: - await self._update_flights_data(obj, current, self.tracked) + await self._update_flights_data(obj, current, self.tracked, SensorType.TRACKED) self.tracked = current async def _update_most_tracked(self) -> None: @@ -151,15 +161,18 @@ async def _update_most_tracked(self) -> None: } entries = self.entered = [current[x] for x in (current.keys() - self.most_tracked.keys())] self.most_tracked = current - self._handle_boundary(EVENT_FLIGHTRADAR24_MOST_TRACKED_NEW, entries) + self._handle_boundary(EVENT_MOST_TRACKED_NEW, entries) async def _update_flights_data(self, obj: Flight, current: dict[int, dict[str, Any]], - area: dict[str, dict[str, Any]], + tracked: dict[str, dict[str, Any]], + sensor_type: SensorType | None = None, ) -> None: - if area is not None and obj.id in area and self._is_valid(area[obj.id]): - flight = area[obj.id] + altitude = None + if tracked is not None and obj.id in tracked and self._is_valid(tracked[obj.id]): + flight = tracked[obj.id] + altitude = flight.get('altitude') else: data = await self.hass.async_add_executor_job( self._client.get_flight_details, obj @@ -175,11 +188,27 @@ async def _update_flights_data(self, flight['squawk'] = obj.squawk flight['vertical_speed'] = obj.vertical_speed flight['distance'] = obj.get_distance_from(self.point) + self._takeoff_and_landing(flight, altitude, obj.altitude, sensor_type) def _handle_boundary(self, event: str, flights: list[dict[str, Any]]) -> None: for flight in flights: - flight['tracked_by_device'] = self.config_entry.title - self.hass.bus.fire(event, flight) + self._fire_event(event, flight) + + def _fire_event(self, event: str, flight: dict[str, Any]) -> None: + flight['tracked_by_device'] = self.config_entry.title + self.hass.bus.fire(event, flight) + + def _takeoff_and_landing(self, + flight: dict[str, Any], + altitude_old, altitude_new, + sensor_type: SensorType | None) -> None: + if sensor_type is None or altitude_old is None: + return + if altitude_old < 10 and altitude_new >= 10: + self._fire_event(EVENT_AREA_TOOK_OFF if SensorType.IN_AREA == sensor_type else EVENT_TRACKED_TOOK_OFF, + flight) + elif altitude_old > 0 and altitude_new <= 0: + self._fire_event(EVENT_AREA_LANDED if SensorType.IN_AREA == sensor_type else EVENT_TRACKED_LANDED, flight) @staticmethod def _is_valid(flight: dict) -> bool: diff --git a/custom_components/flightradar24/manifest.json b/custom_components/flightradar24/manifest.json index d905cf5..ff77da6 100644 --- a/custom_components/flightradar24/manifest.json +++ b/custom_components/flightradar24/manifest.json @@ -7,5 +7,5 @@ "iot_class": "cloud_polling", "issue_tracker": "https://github.com/AlexandrErohin/home-assistant-flightradar24/issues", "requirements": ["FlightRadarAPI==1.3.25", "pycountry==23.12.11"], - "version": "1.13.0" + "version": "1.14.0" } \ No newline at end of file