Run weather updates in a separate thread
This commit is contained in:
parent
5d1caff78c
commit
fc77feedb2
|
@ -1,3 +1,4 @@
|
|||
__pycache__/
|
||||
*.swp
|
||||
chutney.cfg
|
||||
weather.txt
|
||||
|
|
38
chutney.py
38
chutney.py
|
@ -1,10 +1,12 @@
|
|||
import sys
|
||||
import threading
|
||||
|
||||
from character_display import CharacterDisplay
|
||||
from signal import signal, SIGTERM
|
||||
from time import sleep
|
||||
from time_display import TimeDisplay
|
||||
from weather_display import WeatherDisplay
|
||||
from weather_updater import WeatherUpdater
|
||||
|
||||
try:
|
||||
import unicornhathd as unicorn
|
||||
|
@ -14,34 +16,44 @@ except ImportError:
|
|||
unicorn.rotation(180)
|
||||
|
||||
|
||||
def cleanExit(unicorn):
|
||||
WEATHER_UPDATE_INTERVAL_IN_SECONDS = 10
|
||||
DISPLAY_UPDATE_INTERVAL_IN_SECONDS = 0.5
|
||||
CONFIG_FILE = 'chutney.cfg'
|
||||
|
||||
|
||||
def cleanExit(unicorn, haltEvent):
|
||||
def _exit_(signum, frame):
|
||||
unicorn.off()
|
||||
haltEvent.set()
|
||||
sys.exit(0)
|
||||
|
||||
return _exit_
|
||||
|
||||
|
||||
def weatherLoop(haltEvent):
|
||||
weatherUpdater = WeatherUpdater(configFile=CONFIG_FILE)
|
||||
|
||||
while not haltEvent.is_set():
|
||||
weatherUpdater.updateWeather()
|
||||
sleep(WEATHER_UPDATE_INTERVAL_IN_SECONDS)
|
||||
|
||||
|
||||
def main():
|
||||
signal(SIGTERM, cleanExit(unicorn))
|
||||
haltEvent = threading.Event()
|
||||
signal(SIGTERM, cleanExit(unicorn, haltEvent))
|
||||
unicorn.brightness(0.3)
|
||||
|
||||
weatherThread = threading.Thread(target=weatherLoop, args=[haltEvent])
|
||||
weatherThread.start()
|
||||
|
||||
characterDisplay = CharacterDisplay(unicorn)
|
||||
timeDisplay = TimeDisplay(characterDisplay, topRow=15)
|
||||
weatherDisplay = WeatherDisplay(characterDisplay, topRow=9, configFile='chutney.cfg')
|
||||
|
||||
x = 0
|
||||
weatherDisplay = WeatherDisplay(characterDisplay, topRow=9)
|
||||
|
||||
while True:
|
||||
timeDisplay.showTime()
|
||||
|
||||
if (x == 0):
|
||||
weatherDisplay.showWeather()
|
||||
|
||||
x = x + 1
|
||||
x = x % 120
|
||||
|
||||
sleep(1)
|
||||
weatherDisplay.showWeather()
|
||||
sleep(DISPLAY_UPDATE_INTERVAL_IN_SECONDS)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
|
|
@ -16,15 +16,11 @@ class TimeDisplay:
|
|||
self.timeDotsColumn = 7
|
||||
self.minuteStartColumn = 9
|
||||
|
||||
self.characterDisplay.displayTimeDots(
|
||||
x=self.timeDotsColumn,
|
||||
y=self.topRow,
|
||||
color=self.color
|
||||
)
|
||||
|
||||
def showTime(self):
|
||||
self.showHour(self.getHourDigits())
|
||||
self.showTimeDots()
|
||||
self.showMinute(self.getMinuteDigits())
|
||||
self.currentColor = self.color
|
||||
|
||||
def showHour(self, hour):
|
||||
if hour[0] != self.currentHour[0]:
|
||||
|
@ -39,6 +35,14 @@ class TimeDisplay:
|
|||
self.currentHour[1] = hour[1]
|
||||
self.showDigit(self.hourStartColumn + 4, hour[1])
|
||||
|
||||
def showTimeDots(self):
|
||||
if self.color != self.currentColor:
|
||||
self.characterDisplay.displayTimeDots(
|
||||
x=self.timeDotsColumn,
|
||||
y=self.topRow,
|
||||
color=self.color
|
||||
)
|
||||
|
||||
def showMinute(self, minute):
|
||||
if minute[0] != self.currentMinute[0]:
|
||||
self.currentMinute[0] = minute[0]
|
||||
|
|
|
@ -1,37 +1,24 @@
|
|||
import colors
|
||||
import requests
|
||||
|
||||
from configparser import ConfigParser
|
||||
|
||||
|
||||
class WeatherDisplay:
|
||||
def __init__(self, characterDisplay, topRow, configFile):
|
||||
def __init__(self, characterDisplay, topRow):
|
||||
self.characterDisplay = characterDisplay
|
||||
self.topRow = topRow
|
||||
self.currentTemperature = [9, 9]
|
||||
self.color = colors.BLUE
|
||||
|
||||
config = ConfigParser()
|
||||
config.read(configFile)
|
||||
|
||||
host = config['weather'].get('host')
|
||||
user = config['weather'].get('user')
|
||||
password = config['weather'].get('pass')
|
||||
lat = config['weather'].get('lat')
|
||||
lon = config['weather'].get('lon')
|
||||
|
||||
self.uri = f'https://{host}/api/weather?lat={lat}&lon={lon}&units=metric'
|
||||
self.auth = (user, password)
|
||||
self.weatherFile = 'weather.txt'
|
||||
|
||||
def showWeather(self):
|
||||
try:
|
||||
self.showTemperature(
|
||||
self.getTemperatureCharacters(self.getTemperature()))
|
||||
except requests.exceptions.ConnectionError:
|
||||
print("connection error", flush=True)
|
||||
print('connection error', flush=True)
|
||||
self.characterDisplay.clearRow(self.topRow)
|
||||
except requests.exceptions.Timeout:
|
||||
print("timeout", flush=True)
|
||||
print('timeout', flush=True)
|
||||
self.characterDisplay.clearRow(self.topRow)
|
||||
|
||||
def showTemperature(self, temperature):
|
||||
|
@ -53,7 +40,14 @@ class WeatherDisplay:
|
|||
self.currentTemperature = temperature
|
||||
|
||||
def getTemperature(self):
|
||||
return list(filter(lambda t: t["timestep"] == 'current', requests.get(self.uri, auth=self.auth, timeout=2).json()["tomorrow"]["data"]['timelines']))[0]["intervals"][0]["values"]["temperature"]
|
||||
# TODO - don't use a file left around from a previous run
|
||||
# TODO - clear temp on errors from updater
|
||||
try:
|
||||
with open(self.weatherFile) as file:
|
||||
return int(file.readline().strip())
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return 0
|
||||
|
||||
def getTemperatureCharacters(self, temperature):
|
||||
return list(str(round(temperature)))
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
import os
|
||||
import requests
|
||||
|
||||
from configparser import ConfigParser
|
||||
|
||||
|
||||
class WeatherUpdater:
|
||||
def __init__(self, configFile):
|
||||
config = ConfigParser()
|
||||
config.read(configFile)
|
||||
|
||||
host = config['weather'].get('host')
|
||||
user = config['weather'].get('user')
|
||||
password = config['weather'].get('pass')
|
||||
lat = config['weather'].get('lat')
|
||||
lon = config['weather'].get('lon')
|
||||
|
||||
self.uri = f'https://{host}/api/weather?lat={lat}&lon={lon}&units=metric'
|
||||
self.auth = (user, password)
|
||||
self.weatherTempFile = 'weather.tmp'
|
||||
self.weatherFile = 'weather.txt'
|
||||
|
||||
# TODO - clear weather file on init and on failure
|
||||
|
||||
def updateWeather(self):
|
||||
try:
|
||||
temperature = round(self.getTemperature())
|
||||
self.persistTemperature(temperature)
|
||||
except requests.exceptions.ConnectionError:
|
||||
print('connection error', flush=True)
|
||||
self.characterDisplay.clearRow(self.topRow)
|
||||
except requests.exceptions.Timeout:
|
||||
print('timeout', flush=True)
|
||||
self.characterDisplay.clearRow(self.topRow)
|
||||
|
||||
def getTemperature(self):
|
||||
weather = self.getWeather()
|
||||
currentWeather = list(
|
||||
filter(
|
||||
lambda t: t['timestep'] == 'current',
|
||||
weather['tomorrow']['data']['timelines']
|
||||
)
|
||||
)
|
||||
|
||||
return currentWeather[0]['intervals'][0]['values']['temperature']
|
||||
|
||||
def getWeather(self):
|
||||
return requests.get(self.uri, auth=self.auth).json()
|
||||
|
||||
def persistTemperature(self, temperature):
|
||||
with open(self.weatherTempFile, 'w') as file:
|
||||
file.write(str(temperature))
|
||||
|
||||
os.replace(self.weatherTempFile, self.weatherFile)
|
Loading…
Reference in New Issue