v.0.7.0 WeatherResponse
This commit is contained in:
@@ -1,4 +1,8 @@
|
|||||||
from .weather import Weather, AirQuality, Condition, CurrentCondition
|
from .weather import Weather, AirQuality, Condition, CurrentCondition
|
||||||
from .location import Location
|
from .location import Location
|
||||||
|
from .response_status import ResponseStatus
|
||||||
|
from .weather_response import WeatherResponse
|
||||||
|
|
||||||
__all__ = ["Weather","AirQuality","Condition","CurrentCondition","Location"]
|
__all__ = ["Weather",
|
||||||
|
"AirQuality","Condition","CurrentCondition","Location",
|
||||||
|
"ResponseStatus","WeatherResponse"]
|
||||||
46
app/classes/response_status.py
Normal file
46
app/classes/response_status.py
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
class ResponseStatus:
|
||||||
|
|
||||||
|
def __init__(self, code: int=0, message:str="", error_text:str=""):
|
||||||
|
self._code = code
|
||||||
|
self._message = message
|
||||||
|
self._error_text = error_text
|
||||||
|
|
||||||
|
@property
|
||||||
|
def error_text(self):
|
||||||
|
"""Get the status code"""
|
||||||
|
return self._error_text
|
||||||
|
|
||||||
|
@error_text.setter
|
||||||
|
def error_text(self, value):
|
||||||
|
self._error_text = value
|
||||||
|
|
||||||
|
# Status Code property with validation
|
||||||
|
@property
|
||||||
|
def code(self):
|
||||||
|
"""Get the status code"""
|
||||||
|
return self._code
|
||||||
|
|
||||||
|
@code.setter
|
||||||
|
def code(self, value):
|
||||||
|
"""Set the status code with validation"""
|
||||||
|
if not isinstance(value, int):
|
||||||
|
raise TypeError("code must be an integer")
|
||||||
|
if value < 0 or value > 599:
|
||||||
|
raise ValueError("code must be between 0 and 599")
|
||||||
|
self._code = value
|
||||||
|
|
||||||
|
# Status Message property with validation
|
||||||
|
@property
|
||||||
|
def message(self):
|
||||||
|
"""Get the status message"""
|
||||||
|
return self._message
|
||||||
|
|
||||||
|
@message.setter
|
||||||
|
def message(self, value):
|
||||||
|
"""Set the status message with validation"""
|
||||||
|
if not isinstance(value, str):
|
||||||
|
raise TypeError("message must be a string")
|
||||||
|
self._message = value
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return f'ResponseStatus(code={self.code}, message={self.message})'
|
||||||
48
app/classes/weather_response.py
Normal file
48
app/classes/weather_response.py
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
from app.classes import Weather
|
||||||
|
from app.classes import ResponseStatus
|
||||||
|
|
||||||
|
class WeatherResponse:
|
||||||
|
_response_status: ResponseStatus
|
||||||
|
_weather: Weather
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._weather = None
|
||||||
|
self._response_status = None
|
||||||
|
|
||||||
|
# Weather property with getter and setter
|
||||||
|
@property
|
||||||
|
def weather(self)->Weather:
|
||||||
|
"""Get the weather data"""
|
||||||
|
return self._weather
|
||||||
|
|
||||||
|
@weather.setter
|
||||||
|
def weather(self, value:Weather)->None:
|
||||||
|
"""Set the weather data with validation"""
|
||||||
|
if value is not None and not isinstance(value, Weather):
|
||||||
|
raise TypeError("weather must be an instance of Weather class")
|
||||||
|
self._weather = value
|
||||||
|
|
||||||
|
# ResponseStatus property with getter and setter
|
||||||
|
@property
|
||||||
|
def response_status(self)->ResponseStatus:
|
||||||
|
"""Get the response status"""
|
||||||
|
return self._response_status
|
||||||
|
|
||||||
|
@response_status.setter
|
||||||
|
def response_status(self, value:ResponseStatus)->None:
|
||||||
|
"""Set the response status with validation"""
|
||||||
|
if value is not None and not isinstance(value, ResponseStatus):
|
||||||
|
raise TypeError("response_status must be an instance of ResponseStatus class")
|
||||||
|
self._response_status = value
|
||||||
|
|
||||||
|
# Additional utility methods
|
||||||
|
def is_successful(self)->bool:
|
||||||
|
"""Check if the response was successful"""
|
||||||
|
return self._response_status is not None
|
||||||
|
|
||||||
|
def has_weather_data(self)->bool:
|
||||||
|
"""Check if weather data is available"""
|
||||||
|
return self._weather is not None
|
||||||
|
|
||||||
|
def __str__(self)->str:
|
||||||
|
return f"WeatherResponse(weather={self._weather}, status={self._response_status})"
|
||||||
@@ -45,7 +45,6 @@ class NeoPixel_64x64(NeoPixel):
|
|||||||
# wir holen den ersten Wert des Fonts
|
# wir holen den ersten Wert des Fonts
|
||||||
first_char = next(iter(self.selected_font))
|
first_char = next(iter(self.selected_font))
|
||||||
self.font_height = len(self.selected_font[first_char])
|
self.font_height = len(self.selected_font[first_char])
|
||||||
print(f'Font set: width: per char; height: {self.font_height}')
|
|
||||||
|
|
||||||
def set_pixel(self, x, y, color):
|
def set_pixel(self, x, y, color):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
import urequests # type: ignore
|
import urequests # type: ignore
|
||||||
import json
|
import json
|
||||||
|
|
||||||
from app.classes import Weather, Location, CurrentCondition
|
from app.classes import Weather, Location, CurrentCondition, WeatherResponse, ResponseStatus
|
||||||
from app.display import NeoPixel_64x64
|
from app.display import NeoPixel_64x64
|
||||||
import app.utils.colors as colors
|
import app.utils.colors as colors
|
||||||
from app.utils import URLEncoder
|
from app.utils import URLEncoder, http_message
|
||||||
|
|
||||||
|
|
||||||
API_KEY = '3545ce42d0ba436e8dc164532250410'
|
API_KEY = '3545ce42d0ba436e8dc164532250410'
|
||||||
ACTUAL_WEATHER_URL = 'http://api.weatherapi.com/v1/current.json?key={API_KEY}&q={city}&aqi=yes&lang={lang}'
|
ACTUAL_WEATHER_URL = 'http://api.weatherapi.com/v1/current.json?key={API_KEY}&q={city}&aqi=yes&lang={lang}'
|
||||||
@@ -30,54 +29,78 @@ class Weather_Checker():
|
|||||||
print(f"Error: Invalid JSON in '{filepath}': {e}")
|
print(f"Error: Invalid JSON in '{filepath}': {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def _build_weather(self, json_resp) -> Weather:
|
||||||
|
loc = Location(**json_resp['location'])
|
||||||
|
cc = CurrentCondition(**json_resp['current'])
|
||||||
|
|
||||||
def actual_weather(self, city, lang, test_mode=False) -> Weather:
|
weather = Weather(location=loc, current=cc)
|
||||||
|
return weather
|
||||||
|
|
||||||
|
def actual_weather(self, city, lang, test_mode=False) -> WeatherResponse:
|
||||||
|
wr : WeatherResponse = WeatherResponse()
|
||||||
weather_url = ACTUAL_WEATHER_URL.format(API_KEY=API_KEY, city=city, lang=lang)
|
weather_url = ACTUAL_WEATHER_URL.format(API_KEY=API_KEY, city=city, lang=lang)
|
||||||
|
|
||||||
|
|
||||||
if not test_mode:
|
if not test_mode:
|
||||||
|
response_status: ResponseStatus = ResponseStatus()
|
||||||
|
|
||||||
print(f'query: {weather_url}')
|
print(f'query: {weather_url}')
|
||||||
r = urequests.get(weather_url)
|
r = urequests.get(weather_url)
|
||||||
|
|
||||||
print('Status-Code:', r.status_code)
|
print('Status-Code:', r.status_code)
|
||||||
json_resp = r.json()
|
json_resp = r.json()
|
||||||
|
print('json_resp:', json_resp)
|
||||||
|
|
||||||
|
response_status.code = r.status_code
|
||||||
|
response_status.message = http_message[r.status_code]
|
||||||
|
|
||||||
|
if r.status_code == 200:
|
||||||
|
wr.weather = self._build_weather(json_resp)
|
||||||
|
else:
|
||||||
|
response_status.error_text = json_resp['error']['message']
|
||||||
|
|
||||||
|
wr.response_status = response_status
|
||||||
|
|
||||||
r.close()
|
r.close()
|
||||||
else:
|
else:
|
||||||
print('Status-Code: test_mode')
|
print('Status-Code: test_mode')
|
||||||
# json_resp = WEATHER_QUERY_MOCK
|
# json_resp = WEATHER_QUERY_MOCK
|
||||||
json_resp = self.mock_weather_data()
|
json_resp = self.mock_weather_data()
|
||||||
|
wr.weather = self._build_weather(json_resp)
|
||||||
|
wr.response_status = ResponseStatus( code=200, message="OK (Test-Mode)")
|
||||||
|
|
||||||
loc = Location(**json_resp['location'])
|
return wr
|
||||||
cc = CurrentCondition(**json_resp['current'])
|
|
||||||
|
|
||||||
weather = Weather(location=loc, current=cc)
|
|
||||||
|
|
||||||
return weather
|
|
||||||
|
|
||||||
|
|
||||||
def check(self, city:str, lang:str, test_mode: bool = False):
|
def check(self, city:str, lang:str, test_mode: bool = False):
|
||||||
try:
|
try:
|
||||||
self.display.clear()
|
self.display.clear()
|
||||||
|
|
||||||
city = URLEncoder.encode_utf8(city) # url_encode
|
city_encoded = URLEncoder.encode_utf8(city) # url_encode
|
||||||
w_resp: Weather = self.actual_weather(city=city, lang=lang, test_mode=test_mode)
|
w_resp: WeatherResponse = self.actual_weather(city=city_encoded, lang=lang, test_mode=test_mode)
|
||||||
|
|
||||||
|
if w_resp.response_status.code == 200:
|
||||||
ypos = 0
|
ypos = 0
|
||||||
self.display.write_text(f'{str(w_resp.location.name)}', 0, ypos, color=colors.RAINBOW[0])
|
self.display.write_text(f'{str(w_resp.weather.location.name)}', 0, ypos, color=colors.RAINBOW[0])
|
||||||
ypos += self.display.font_height + 1
|
ypos += self.display.font_height + 1
|
||||||
self.display.write_text(f'{str(w_resp.location.region)}', 0, ypos, color=colors.RAINBOW[0])
|
self.display.write_text(f'{str(w_resp.weather.location.region)}', 0, ypos, color=colors.RAINBOW[0])
|
||||||
ypos += self.display.font_height + 1
|
ypos += self.display.font_height + 1
|
||||||
self.display.write_text(f'{str(w_resp.location.localtime)[:10]}', 0, ypos, color=colors.RAINBOW[3])
|
self.display.write_text(f'{str(w_resp.weather.location.localtime)[:10]}', 0, ypos, color=colors.RAINBOW[3])
|
||||||
ypos += self.display.font_height + 1
|
ypos += self.display.font_height + 1
|
||||||
|
|
||||||
self.display.write_text(f'{str(w_resp.current.temp_c)}°C', 0, ypos, color=colors.RAINBOW[1])
|
self.display.write_text(f'{str(w_resp.weather.current.temp_c)}°C', 0, ypos, color=colors.RAINBOW[1])
|
||||||
ypos += self.display.font_height + 1
|
ypos += self.display.font_height + 1
|
||||||
self.display.write_text(f'{str(w_resp.current.condition.text)}', 0, ypos, color=colors.RAINBOW[2])
|
self.display.write_text(f'{str(w_resp.weather.current.condition.text)}', 0, ypos, color=colors.RAINBOW[2])
|
||||||
ypos += self.display.font_height + 1
|
ypos += self.display.font_height + 1
|
||||||
self.display.write_text(f'upd:{str(w_resp.current.last_updated)[-5:]}', 0, ypos, color=colors.RAINBOW[3])
|
self.display.write_text(f'upd:{str(w_resp.weather.current.last_updated)[-5:]}', 0, ypos, color=colors.RAINBOW[3])
|
||||||
ypos += self.display.font_height + 1
|
ypos += self.display.font_height + 1
|
||||||
self.display.write_text(f'cur:{str(w_resp.location.localtime)[-5:]}', 0, ypos, color=colors.RAINBOW[4])
|
self.display.write_text(f'cur:{str(w_resp.weather.location.localtime)[-5:]}', 0, ypos, color=colors.RAINBOW[4])
|
||||||
|
else:
|
||||||
|
ypos = 0
|
||||||
|
self.display.write_text(f'Code:{w_resp.response_status.code}', 0, ypos, color=colors.RAINBOW[0])
|
||||||
|
ypos += self.display.font_height + 1
|
||||||
|
self.display.write_text(f'{w_resp.response_status.message}', 0, ypos, color=colors.RAINBOW[1])
|
||||||
|
ypos += self.display.font_height + 1
|
||||||
|
self.display.write_text(f'{w_resp.response_status.error_text}', 0, ypos, color=colors.RAINBOW[2])
|
||||||
|
|
||||||
# unten rechts in die Ecke
|
# unten rechts in die Ecke
|
||||||
ypos = self.display.MATRIX_HEIGHT - self.display.font_height - 1
|
ypos = self.display.MATRIX_HEIGHT - self.display.font_height - 1
|
||||||
|
|||||||
@@ -4,3 +4,4 @@ from .time_utils import *
|
|||||||
from .font_utils import *
|
from .font_utils import *
|
||||||
from .math_utils import *
|
from .math_utils import *
|
||||||
from .url_encode import URLEncoder
|
from .url_encode import URLEncoder
|
||||||
|
from .http_utils import http_message
|
||||||
6
app/utils/http_utils.py
Normal file
6
app/utils/http_utils.py
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
http_message = {
|
||||||
|
# Jedes Zeichen ist genau 3 Pixel breit, 5 Pixel hoch
|
||||||
|
200: "OK",
|
||||||
|
400: "Bad Request",
|
||||||
|
401: "Unauthorized",
|
||||||
|
}
|
||||||
2
main.py
2
main.py
@@ -19,6 +19,6 @@ if __name__ == '__main__':
|
|||||||
# tryout.weather_check(display, test_mode=False)
|
# tryout.weather_check(display, test_mode=False)
|
||||||
display.set_font(font_5x7)
|
display.set_font(font_5x7)
|
||||||
weather_checker: Weather_Checker = Weather_Checker( display=display)
|
weather_checker: Weather_Checker = Weather_Checker( display=display)
|
||||||
weather_checker.check(city="ahrensburg", lang="de", test_mode=False)
|
weather_checker.check(city="Columbus", lang="de", test_mode=False)
|
||||||
|
|
||||||
# show_system_load()
|
# show_system_load()
|
||||||
|
|||||||
Reference in New Issue
Block a user