diff --git a/src/logic/Helpers.py b/src/logic/Helpers.py index a497f4b0cc0f8f0039e19af5d4ca6be2b3f58d1e..2eee764531f5c68c4f1ca1177c75c1e6312f0120 100644 --- a/src/logic/Helpers.py +++ b/src/logic/Helpers.py @@ -1,3 +1,5 @@ +from datetime import datetime + from logic import Constants @@ -29,7 +31,7 @@ def determine_color_for_wind(windSpeed: float) -> str: return Constants.RED.to_rgba() -def determine_color_for_weather_icon(iconId: int): +def determine_color_for_weather_icon(iconId: int, isDayTime: bool): if 200 <= iconId < 300: # thunderstorm return Constants.RED.to_rgba() elif 300 <= iconId < 400: # drizzle @@ -40,7 +42,20 @@ def determine_color_for_weather_icon(iconId: int): return Constants.WHITE.to_rgba() elif 700 <= iconId < 800: # fog return Constants.WHITE.to_rgba() - elif 800 <= iconId < 802: # clear of partly cloudy (up to 25%) - return Constants.ORANGE.to_rgba() + elif 800 <= iconId < 802: # clear or partly cloudy (up to 25%) + if isDayTime: + return Constants.ORANGE.to_rgba() + return Constants.WHITE.to_rgba() elif 802 <= iconId < 805: # clouds > 25% return Constants.WHITE.to_rgba() + + +def is_dayTime(sunrise: int, sunset: int, currentTimestamp: int = None) -> bool: + if not currentTimestamp: + currentTimestamp = int(datetime.now().timestamp()) + return sunrise < currentTimestamp < sunset + + +def timestamp_to_timezone(timestamp: int, timeZone: datetime.tzinfo): + timestamp = datetime.utcfromtimestamp(timestamp) + return timeZone.fromutc(timestamp) diff --git a/src/logic/tile/tiles/CurrentWeatherTile.html b/src/logic/tile/tiles/CurrentWeatherTile.html index 8363486f5c1a6b94aca3f3d5ed976b9c6fe7f232..71adec40c4735ca77ccedee01089395f45059274 100644 --- a/src/logic/tile/tiles/CurrentWeatherTile.html +++ b/src/logic/tile/tiles/CurrentWeatherTile.html @@ -63,7 +63,13 @@ <div class="currentTemperatureTile"> <div class="content"> - <i class="wi wi-owm-{{ data['icon'] }} icon" style="color: {{ data['iconColor'] }};"></i> + {% if data['isDayTime'] %} + {% set iconPrefix = 'wi-owm-day-' %} + {% else %} + {% set iconPrefix = 'wi-owm-night-' %} + {% endif %} + + <i class="wi {{ iconPrefix }}{{ data['icon'] }} icon" style="color: {{ data['iconColor'] }};"></i> <div class="entries"> <div class="temperatures"> <div class="temperature-entry"> diff --git a/src/logic/tile/tiles/CurrentWeatherTile.py b/src/logic/tile/tiles/CurrentWeatherTile.py index 237fde0b97c9b3b5658295883836c461ff8afd6b..3fd7910701b66d43c134965e8f20231eb7923028 100644 --- a/src/logic/tile/tiles/CurrentWeatherTile.py +++ b/src/logic/tile/tiles/CurrentWeatherTile.py @@ -1,6 +1,8 @@ import os +from datetime import datetime from typing import Dict +import pytz from flask import Blueprint from logic import Helpers @@ -12,7 +14,8 @@ class CurrentWeatherTile(Tile): EXAMPLE_SETTINGS = { "lat": "51.012825", "lon": "13.666365", - "apiKey": "myApiKey" + "apiKey": "myApiKey", + "timeZone": "Europe/Berlin" } def __init__(self, uniqueName: str, settings: Dict, intervalInSeconds: int): @@ -23,6 +26,8 @@ class CurrentWeatherTile(Tile): fetchIntervalInSeconds = 60 * 10 # query api less often + timeZone = pytz.timezone(self._settings['timeZone']) + # cache key will be determined in service weatherData = weatherService.get_data('', fetchIntervalInSeconds, self._settings) currentWeather = weatherData['current'] @@ -30,6 +35,9 @@ class CurrentWeatherTile(Tile): feelsLike = currentWeather['feels_like'] windSpeed = currentWeather['wind_speed'] * 3.6 icon = currentWeather['weather'][0]['id'] + sunrise = Helpers.timestamp_to_timezone(currentWeather['sunrise'], timeZone).timestamp() + sunset = Helpers.timestamp_to_timezone(currentWeather['sunset'], timeZone).timestamp() + isDayTime = Helpers.is_dayTime(sunrise, sunset) return { 'temperature': Helpers.round_to_decimals(currentTemperature, 1), @@ -37,10 +45,11 @@ class CurrentWeatherTile(Tile): 'feelsLike': Helpers.round_to_decimals(feelsLike, 1), 'feelsLikeColor': Helpers.determine_color_for_temperature(feelsLike), 'icon': icon, - 'iconColor': Helpers.determine_color_for_weather_icon(icon), + 'iconColor': Helpers.determine_color_for_weather_icon(icon, isDayTime), 'windDegrees': currentWeather['wind_deg'], 'windSpeed': f'{Helpers.round_to_decimals(windSpeed, 1)} km/h', - 'windSpeedColor': Helpers.determine_color_for_wind(windSpeed) + 'windSpeedColor': Helpers.determine_color_for_wind(windSpeed), + 'isDayTime': isDayTime } def render(self, data: Dict) -> str: diff --git a/src/logic/tile/tiles/HourlyForecastTile.html b/src/logic/tile/tiles/HourlyForecastTile.html index 9fc2159b6d9fbb3867ed3f8e2214ee3f77f696bf..515bf1e40bc9687c04835972ca94fda737fd91d0 100644 --- a/src/logic/tile/tiles/HourlyForecastTile.html +++ b/src/logic/tile/tiles/HourlyForecastTile.html @@ -64,9 +64,15 @@ <div class="hourlyForecastTile"> <div class="content"> {% for item in data %} + {% if data['isDayTime'] %} + {% set iconPrefix = 'wi-owm-day-' %} + {% else %} + {% set iconPrefix = 'wi-owm-night-' %} + {% endif %} + <div class="entry"> <div class="hour">{{ item['hour'] }} Uhr</div> - <i class="wi wi-owm-{{ item['icon'] }} icon" style="color: {{ item['iconColor'] }};"></i> + <i class="wi {{ iconPrefix }}{{ item['icon'] }} icon" style="color: {{ item['iconColor'] }};"></i> <div class="temperature" style="color: {{ item['temperatureColor'] }}">{{ item['temperature'] }}°C</div> <div class="rain"> <i class="wi wi-raindrops"></i> diff --git a/src/logic/tile/tiles/HourlyForecastTile.py b/src/logic/tile/tiles/HourlyForecastTile.py index 8747edea951d1d3d58174b8591a2a9d4027e28f9..92caa7885b5e15f096c9e31b005db011d220afcd 100644 --- a/src/logic/tile/tiles/HourlyForecastTile.py +++ b/src/logic/tile/tiles/HourlyForecastTile.py @@ -31,27 +31,31 @@ class HourlyForecastTile(Tile): # cache key will be determined in service weatherData = weatherService.get_data('', fetchIntervalInSeconds, self._settings) + sunrise = Helpers.timestamp_to_timezone(weatherData['current']['sunrise'], timeZone).timestamp() + sunset = Helpers.timestamp_to_timezone(weatherData['current']['sunset'], timeZone).timestamp() + hourData = [] hourlyForecast = weatherData['hourly'] for entry in hourlyForecast[:12]: - timestamp = entry['dt'] - timestamp = datetime.utcfromtimestamp(timestamp) - timestamp = timeZone.fromutc(timestamp) + timestamp = Helpers.timestamp_to_timezone(entry['dt'], timeZone) temperature = entry['temp'] icon = entry['weather'][0]['id'] rainProbability = round(entry['pop'] * 100, -1) # -1 rounds to the next ten windSpeed = entry['wind_speed'] * 3.6 + isDayTime = Helpers.is_dayTime(sunrise, sunset, currentTimestamp=timestamp.timestamp()) + hourData.append({ 'hour': timestamp.strftime('%H'), 'temperature': Helpers.round_to_decimals(temperature, 0), 'temperatureColor': Helpers.determine_color_for_temperature(temperature), 'icon': icon, - 'iconColor': Helpers.determine_color_for_weather_icon(icon), + 'iconColor': Helpers.determine_color_for_weather_icon(icon, isDayTime), 'windSpeed': f'{Helpers.round_to_decimals(windSpeed, 0)} km/h', 'windSpeedColor': Helpers.determine_color_for_wind(windSpeed), - 'rainProbability': f'{Helpers.round_to_decimals(rainProbability, 0)} %' + 'rainProbability': f'{Helpers.round_to_decimals(rainProbability, 0)} %', + 'isDayTime': isDayTime }) return { diff --git a/src/logic/tile/tiles/SevenDaysForecastTile.py b/src/logic/tile/tiles/SevenDaysForecastTile.py index d518eafc9f7473d9c50e5f9d862f4d67d1e91b53..25576833209c6427819d28c8f24bb20d8957b96d 100644 --- a/src/logic/tile/tiles/SevenDaysForecastTile.py +++ b/src/logic/tile/tiles/SevenDaysForecastTile.py @@ -39,7 +39,7 @@ class SevenDaysForecastTile(Tile): date = datetime.fromtimestamp(date) date = datetime.strftime(date, self.DATE_FORMAT) icon = day['weather'][0]['id'] - iconColor = Helpers.determine_color_for_weather_icon(icon) + iconColor = Helpers.determine_color_for_weather_icon(icon, True) icons.append((icon, iconColor)) forecastData[date] = (int(day['temp']['min']), int(day['temp']['max'])) diff --git a/test/__init__.py b/test/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/test/logic/HelpersTest.py b/test/logic/HelpersTest.py new file mode 100644 index 0000000000000000000000000000000000000000..7b76e78f7def541f4214e31c2927c249a9848b98 --- /dev/null +++ b/test/logic/HelpersTest.py @@ -0,0 +1,39 @@ +import unittest +from datetime import datetime + +from logic import Helpers + + +class HelpersTest(unittest.TestCase): + def test_join_url_parts(self): + self.assertEqual('https://myWebsite/eimer/0815', Helpers.join_url_parts('https://myWebsite', 'eimer', '0815')) + + def test_round_to_decimals_one(self): + self.assertEqual('0.4', Helpers.round_to_decimals(0.428, 1)) + + def test_round_to_decimals_zero(self): + self.assertEqual('0', Helpers.round_to_decimals(0.428, 0)) + + def test_is_dayTime_true(self): + sunrise = datetime(year=2020, month=11, day=1, hour=8, minute=0, second=0).timestamp() + sunset = datetime(year=2020, month=11, day=1, hour=17, minute=0, second=0).timestamp() + + currentTimestamp = datetime(year=2020, month=11, day=1, hour=12, minute=0, second=0).timestamp() + + self.assertTrue(Helpers.is_dayTime(sunrise, sunset, currentTimestamp)) + + def test_is_dayTime_false_before(self): + sunrise = datetime(year=2020, month=11, day=1, hour=8, minute=0, second=0).timestamp() + sunset = datetime(year=2020, month=11, day=1, hour=17, minute=0, second=0).timestamp() + + currentTimestamp = datetime(year=2020, month=11, day=1, hour=4, minute=0, second=0).timestamp() + + self.assertFalse(Helpers.is_dayTime(sunrise, sunset, currentTimestamp)) + + def test_is_dayTime_false_after(self): + sunrise = datetime(year=2020, month=11, day=1, hour=8, minute=0, second=0).timestamp() + sunset = datetime(year=2020, month=11, day=1, hour=17, minute=0, second=0).timestamp() + + currentTimestamp = datetime(year=2020, month=11, day=1, hour=18, minute=0, second=0).timestamp() + + self.assertFalse(Helpers.is_dayTime(sunrise, sunset, currentTimestamp)) diff --git a/test/logic/__init__.py b/test/logic/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391