From d0f781919d603cc8b65250dc982344bf1542ac2f Mon Sep 17 00:00:00 2001 From: Fabio Manganiello Date: Mon, 20 May 2024 02:01:40 +0200 Subject: [PATCH] [#345] Rewritten `sun` plugin. Closes: #345 --- platypush/plugins/sun/__init__.py | 109 +++++++++++++++--------------- 1 file changed, 55 insertions(+), 54 deletions(-) diff --git a/platypush/plugins/sun/__init__.py b/platypush/plugins/sun/__init__.py index e01e643d3f..9519d326d3 100644 --- a/platypush/plugins/sun/__init__.py +++ b/platypush/plugins/sun/__init__.py @@ -1,9 +1,8 @@ import datetime -import time -from typing import Optional +from typing import Dict, Optional import requests -from dateutil.tz import gettz, tzutc +from dateutil.tz import gettz from platypush.message.event.sun import SunriseEvent, SunsetEvent from platypush.plugins import RunnablePlugin, action @@ -16,6 +15,7 @@ class SunPlugin(RunnablePlugin): """ _base_url = 'https://api.sunrise-sunset.org/json' + _schema = SunEventsSchema() _attr_to_event_class = { 'sunrise': SunriseEvent, 'sunset': SunsetEvent, @@ -32,66 +32,54 @@ class SunPlugin(RunnablePlugin): 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], + next_events = self._get_events() + next_event = next( + iter( + 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 attr, event_class in self._attr_to_event_class.items() - if next_events.get(attr) - ], - key=lambda t: t.time, + ), + None, ) - 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) + assert next_event is not None, 'No next event found' + wait_secs = max( + 0, (next_event.time - datetime.datetime.now(tz=gettz())).seconds + ) + self.wait_stop(wait_secs) - if dt <= datetime.datetime.now(tz=gettz()): - self.bus.post(event) + if not self.should_stop(): + self._bus.post(next_event) + self.wait_stop(2) @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(), - ) + now = datetime.datetime.now(datetime.UTC).replace(microsecond=0) + dt = datetime.datetime.strptime( + f'{now.year}-{now.month:02d}-{now.day:02d} {t}', + '%Y-%m-%d %I:%M:%S %p', + ).replace(tzinfo=datetime.UTC) if dt < now: dt += datetime.timedelta(days=1) - return datetime.datetime.fromtimestamp(dt.timestamp(), tz=gettz()) + return dt - @action - def get_events( + 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 - """ + ) -> Dict[str, datetime.datetime]: response = ( requests.get( self._base_url, + timeout=10, params={ 'lat': latitude or self.latitude, 'lng': longitude or self.longitude, @@ -101,11 +89,24 @@ class SunPlugin(RunnablePlugin): .get('results', {}) ) + return { + attr: self._convert_time(t) + for attr, t in response.items() + if attr in self._schema.declared_fields + } + + @action + def get_events( + self, latitude: Optional[float] = None, longitude: Optional[float] = None + ) -> dict: + """ + Return the next sun events. + + :param latitude: Override the default latitude. + :param longitude: Override the default longitude. + :return: .. schema:: sun.SunEventsSchema + """ schema = SunEventsSchema() - return schema.dump( - { - attr: self._convert_time(t) - for attr, t in response.items() - if attr in schema.declared_fields - } + return dict( + schema.dump(self._get_events(latitude=latitude, longitude=longitude)) )