135 lines
4.6 KiB
Python
135 lines
4.6 KiB
Python
"""Demo platform for the geolocation component."""
|
|
from datetime import timedelta
|
|
import logging
|
|
from math import cos, pi, radians, sin
|
|
import random
|
|
from typing import Optional
|
|
|
|
from homeassistant.helpers.event import track_time_interval
|
|
|
|
from homeassistant.components.geo_location import GeolocationEvent
|
|
|
|
_LOGGER = logging.getLogger(__name__)
|
|
|
|
AVG_KM_PER_DEGREE = 111.0
|
|
DEFAULT_UNIT_OF_MEASUREMENT = 'km'
|
|
DEFAULT_UPDATE_INTERVAL = timedelta(minutes=1)
|
|
MAX_RADIUS_IN_KM = 50
|
|
NUMBER_OF_DEMO_DEVICES = 5
|
|
|
|
EVENT_NAMES = ["Bushfire", "Hazard Reduction", "Grass Fire", "Burn off",
|
|
"Structure Fire", "Fire Alarm", "Thunderstorm", "Tornado",
|
|
"Cyclone", "Waterspout", "Dust Storm", "Blizzard", "Ice Storm",
|
|
"Earthquake", "Tsunami"]
|
|
|
|
SOURCE = 'demo'
|
|
|
|
|
|
def setup_platform(hass, config, add_entities, discovery_info=None):
|
|
"""Set up the Demo geolocations."""
|
|
DemoManager(hass, add_entities)
|
|
|
|
|
|
class DemoManager:
|
|
"""Device manager for demo geolocation events."""
|
|
|
|
def __init__(self, hass, add_entities):
|
|
"""Initialise the demo geolocation event manager."""
|
|
self._hass = hass
|
|
self._add_entities = add_entities
|
|
self._managed_devices = []
|
|
self._update(count=NUMBER_OF_DEMO_DEVICES)
|
|
self._init_regular_updates()
|
|
|
|
def _generate_random_event(self):
|
|
"""Generate a random event in vicinity of this HA instance."""
|
|
home_latitude = self._hass.config.latitude
|
|
home_longitude = self._hass.config.longitude
|
|
|
|
# Approx. 111km per degree (north-south).
|
|
radius_in_degrees = random.random() * MAX_RADIUS_IN_KM / \
|
|
AVG_KM_PER_DEGREE
|
|
radius_in_km = radius_in_degrees * AVG_KM_PER_DEGREE
|
|
angle = random.random() * 2 * pi
|
|
# Compute coordinates based on radius and angle. Adjust longitude value
|
|
# based on HA's latitude.
|
|
latitude = home_latitude + radius_in_degrees * sin(angle)
|
|
longitude = home_longitude + radius_in_degrees * cos(angle) / \
|
|
cos(radians(home_latitude))
|
|
|
|
event_name = random.choice(EVENT_NAMES)
|
|
return DemoGeolocationEvent(event_name, radius_in_km, latitude,
|
|
longitude, DEFAULT_UNIT_OF_MEASUREMENT)
|
|
|
|
def _init_regular_updates(self):
|
|
"""Schedule regular updates based on configured time interval."""
|
|
track_time_interval(self._hass, lambda now: self._update(),
|
|
DEFAULT_UPDATE_INTERVAL)
|
|
|
|
def _update(self, count=1):
|
|
"""Remove events and add new random events."""
|
|
# Remove devices.
|
|
for _ in range(1, count + 1):
|
|
if self._managed_devices:
|
|
device = random.choice(self._managed_devices)
|
|
if device:
|
|
_LOGGER.debug("Removing %s", device)
|
|
self._managed_devices.remove(device)
|
|
self._hass.add_job(device.async_remove())
|
|
# Generate new devices from events.
|
|
new_devices = []
|
|
for _ in range(1, count + 1):
|
|
new_device = self._generate_random_event()
|
|
_LOGGER.debug("Adding %s", new_device)
|
|
new_devices.append(new_device)
|
|
self._managed_devices.append(new_device)
|
|
self._add_entities(new_devices)
|
|
|
|
|
|
class DemoGeolocationEvent(GeolocationEvent):
|
|
"""This represents a demo geolocation event."""
|
|
|
|
def __init__(self, name, distance, latitude, longitude,
|
|
unit_of_measurement):
|
|
"""Initialize entity with data provided."""
|
|
self._name = name
|
|
self._distance = distance
|
|
self._latitude = latitude
|
|
self._longitude = longitude
|
|
self._unit_of_measurement = unit_of_measurement
|
|
|
|
@property
|
|
def source(self) -> str:
|
|
"""Return source value of this external event."""
|
|
return SOURCE
|
|
|
|
@property
|
|
def name(self) -> Optional[str]:
|
|
"""Return the name of the event."""
|
|
return self._name
|
|
|
|
@property
|
|
def should_poll(self):
|
|
"""No polling needed for a demo geolocation event."""
|
|
return False
|
|
|
|
@property
|
|
def distance(self) -> Optional[float]:
|
|
"""Return distance value of this external event."""
|
|
return self._distance
|
|
|
|
@property
|
|
def latitude(self) -> Optional[float]:
|
|
"""Return latitude value of this external event."""
|
|
return self._latitude
|
|
|
|
@property
|
|
def longitude(self) -> Optional[float]:
|
|
"""Return longitude value of this external event."""
|
|
return self._longitude
|
|
|
|
@property
|
|
def unit_of_measurement(self):
|
|
"""Return the unit of measurement."""
|
|
return self._unit_of_measurement
|