platypush/platypush/plugins/sun/__init__.py

87 lines
3 KiB
Python

import datetime
import time
from typing import Optional
import requests
from dateutil.tz import gettz, tzutc
from platypush.message.event.sun import SunriseEvent, SunsetEvent
from platypush.plugins import RunnablePlugin, action
from platypush.schemas.sun import SunEventsSchema
class SunPlugin(RunnablePlugin):
"""
Plugin to get sunset/sunrise events and info for a certain location.
Triggers:
* :class:`platypush.message.event.sun.SunriseEvent` on sunrise.
* :class:`platypush.message.event.sun.SunsetEvent` on sunset.
"""
_base_url = 'https://api.sunrise-sunset.org/json'
_attr_to_event_class = {
'sunrise': SunriseEvent,
'sunset': SunsetEvent,
}
def __init__(self, latitude: float, longitude: float, **kwargs):
"""
:param latitude: Default latitude.
:param longitude: Default longitude.
"""
super().__init__(**kwargs)
self.latitude = latitude
self.longitude = longitude
def main(self):
while not self.should_stop():
# noinspection PyUnresolvedReferences
next_events = self.get_events().output
next_events = sorted([
event_class(latitude=self.latitude, longitude=self.longitude, time=next_events[attr])
for attr, event_class in self._attr_to_event_class.items()
if next_events.get(attr)
], key=lambda t: t.time)
for event in next_events:
# noinspection PyTypeChecker
dt = datetime.datetime.fromisoformat(event.time)
while (not self.should_stop()) and (dt > datetime.datetime.now(tz=gettz())):
time.sleep(1)
if dt <= datetime.datetime.now(tz=gettz()):
self.bus.post(event)
@staticmethod
def _convert_time(t: str) -> datetime.datetime:
now = datetime.datetime.now().replace(tzinfo=gettz()) # lgtm [py/call-to-non-callable]
dt = datetime.datetime.strptime(t, '%H:%M:%S %p')
dt = datetime.datetime(year=now.year, month=now.month, day=now.day,
hour=dt.hour, minute=dt.minute, second=dt.second, tzinfo=tzutc())
if dt < now:
dt += datetime.timedelta(days=1)
return datetime.datetime.fromtimestamp(dt.timestamp(), tz=gettz())
@action
def get_events(self, latitude: Optional[float] = None, longitude: Optional[float] = None) -> dict:
"""
Return the next sun events.
:param latitude: Default latitude override.
:param longitude: Default longitude override.
:return: .. schema:: sun.SunEventsSchema
"""
response = requests.get(self._base_url, params={
'lat': latitude or self.latitude,
'lng': longitude or self.longitude,
}).json().get('results', {})
schema = SunEventsSchema()
return schema.dump({
attr: self._convert_time(t)
for attr, t in response.items()
if attr in schema.declared_fields.keys()
})