Refactor code into packages

This commit is contained in:
Mike Cifelli 2023-01-05 19:11:30 -05:00
parent 56d0e1f5d4
commit 627420e9cb
15 changed files with 148 additions and 144 deletions

3
.gitignore vendored
View File

@ -1,6 +1,3 @@
__pycache__/ __pycache__/
*.swp *.swp
*.tmp
chutney.cfg chutney.cfg
garage.json
weather.txt

View File

@ -1,133 +1,4 @@
import json import chutney.runner
import requests
import sys
from character_display import CharacterDisplay
from configparser import ConfigParser
from garage_display import GarageDisplay
from garage_updater import GarageUpdater
from multiprocessing import Event
from multiprocessing import Process
from multiprocessing import Queue
from queue import Empty
from signal import signal
from signal import 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
unicorn.rotation(90)
except ImportError:
from unicorn_hat_sim import unicornhathd as unicorn
unicorn.rotation(180)
WEATHER_UPDATE_INTERVAL_IN_SECONDS = 10
GARAGE_UPDATE_INTERVAL_IN_SECONDS = 30
DISPLAY_UPDATE_INTERVAL_IN_SECONDS = 0.5
CONFIG_FILE = 'chutney.cfg'
class HaltException(Exception):
pass
def main():
queue = Queue()
haltEvent = Event()
Process(target=weatherLoop, args=[haltEvent]).start()
Process(target=garageLoop, args=[queue]).start()
signal(SIGTERM, cleanExit(unicorn, haltEvent, queue))
unicorn.brightness(0.3)
characterDisplay = CharacterDisplay(unicorn)
timeDisplay = TimeDisplay(characterDisplay, topRow=15)
weatherDisplay = WeatherDisplay(characterDisplay, topRow=9)
garageDisplay = GarageDisplay(characterDisplay, topRow=3)
while True:
timeDisplay.showTime()
weatherDisplay.showWeather()
garageDisplay.showGarageState()
sleep(DISPLAY_UPDATE_INTERVAL_IN_SECONDS)
def weatherLoop(haltEvent):
weatherUpdater = WeatherUpdater(configFile=CONFIG_FILE)
while not haltEvent.is_set():
weatherUpdater.updateWeather()
haltEvent.wait(timeout=WEATHER_UPDATE_INTERVAL_IN_SECONDS)
weatherUpdater.clearWeather()
def garageLoop(queue):
garageNotify = Process(target=garageNotifyLoop, args=[queue])
garageNotify.start()
garageUpdater = GarageUpdater(configFile=CONFIG_FILE)
isRunning = True
while isRunning:
garageUpdater.updateGarageState()
try:
item = queue.get(timeout=GARAGE_UPDATE_INTERVAL_IN_SECONDS)
isRunning = item != 'halt'
except Empty:
pass
garageUpdater.clearGarageState()
garageNotify.terminate()
def garageNotifyLoop(queue):
signal(SIGTERM, raiseHaltException())
config = ConfigParser()
config.read(CONFIG_FILE)
ntfy = config['garage'].get('ntfy')
topic = config['garage'].get('topic')
try:
resp = requests.get(f'https://{ntfy}/{topic}/json', stream=True)
for line in resp.iter_lines():
if line:
data = json.loads(line.decode('utf-8'))
if (data['event'] == 'message'):
queue.put('update')
except HaltException:
pass
except Exception as e:
print(e, flush=True)
finally:
resp.close()
def cleanExit(unicorn, haltEvent, queue):
def _exit_(signum, frame):
unicorn.off()
haltEvent.set()
queue.put('halt')
queue.close()
sys.exit(0)
return _exit_
def raiseHaltException():
def _exit_(signum, frame):
raise HaltException()
return _exit_
if __name__ == '__main__': if __name__ == '__main__':
main() chutney.runner.main()

0
chutney/__init__.py Normal file
View File

View File

@ -1,4 +1,4 @@
import colors import chutney.colors as colors
class CharacterDisplay: class CharacterDisplay:

View File

@ -0,0 +1,2 @@
from .garage_display import GarageDisplay
from .garage_updater import GarageUpdater

View File

@ -1,4 +1,4 @@
import colors import chutney.colors as colors
import json import json
@ -13,7 +13,7 @@ class GarageDisplay:
self.closedFillColor = colors.RED self.closedFillColor = colors.RED
self.openOutlineColor = colors.WHITE self.openOutlineColor = colors.WHITE
self.openFillColor = colors.WHITE self.openFillColor = colors.WHITE
self.garageFile = 'garage.json' self.garageFile = 'data/garage.json'
def showGarageState(self): def showGarageState(self):
state = self.getGarageState() state = self.getGarageState()

View File

@ -10,8 +10,8 @@ class GarageUpdater:
config.read(configFile) config.read(configFile)
self.uri = config['garage'].get('uri') self.uri = config['garage'].get('uri')
self.garageTempFile = 'garage.tmp' self.garageTempFile = 'data/garage.tmp'
self.garageFile = 'garage.json' self.garageFile = 'data/garage.json'
self.persistGarageState('{"error": "init"}') self.persistGarageState('{"error": "init"}')
def updateGarageState(self): def updateGarageState(self):

129
chutney/runner.py Normal file
View File

@ -0,0 +1,129 @@
import json
import requests
import sys
from chutney.character_display import CharacterDisplay
from chutney.garage import GarageDisplay
from chutney.garage import GarageUpdater
from chutney.time import TimeDisplay
from chutney.weather import WeatherDisplay
from chutney.weather import WeatherUpdater
from configparser import ConfigParser
from multiprocessing import Event
from multiprocessing import Process
from multiprocessing import Queue
from queue import Empty
from signal import signal
from signal import SIGTERM
from time import sleep
try:
import unicornhathd as unicorn
unicorn.rotation(90)
except ImportError:
from unicorn_hat_sim import unicornhathd as unicorn
unicorn.rotation(180)
WEATHER_UPDATE_INTERVAL_IN_SECONDS = 10
GARAGE_UPDATE_INTERVAL_IN_SECONDS = 30
DISPLAY_UPDATE_INTERVAL_IN_SECONDS = 0.5
CONFIG_FILE = 'chutney.cfg'
class HaltException(Exception):
pass
def main():
queue = Queue()
haltEvent = Event()
Process(target=weatherLoop, args=[haltEvent]).start()
Process(target=garageLoop, args=[queue]).start()
signal(SIGTERM, cleanExit(unicorn, haltEvent, queue))
unicorn.brightness(0.3)
characterDisplay = CharacterDisplay(unicorn)
timeDisplay = TimeDisplay(characterDisplay, topRow=15)
weatherDisplay = WeatherDisplay(characterDisplay, topRow=9)
garageDisplay = GarageDisplay(characterDisplay, topRow=3)
while True:
timeDisplay.showTime()
weatherDisplay.showWeather()
garageDisplay.showGarageState()
sleep(DISPLAY_UPDATE_INTERVAL_IN_SECONDS)
def weatherLoop(haltEvent):
weatherUpdater = WeatherUpdater(configFile=CONFIG_FILE)
while not haltEvent.is_set():
weatherUpdater.updateWeather()
haltEvent.wait(timeout=WEATHER_UPDATE_INTERVAL_IN_SECONDS)
weatherUpdater.clearWeather()
def garageLoop(queue):
garageNotify = Process(target=garageNotifyLoop, args=[queue])
garageNotify.start()
garageUpdater = GarageUpdater(configFile=CONFIG_FILE)
isRunning = True
while isRunning:
garageUpdater.updateGarageState()
try:
item = queue.get(timeout=GARAGE_UPDATE_INTERVAL_IN_SECONDS)
isRunning = item != 'halt'
except Empty:
pass
garageUpdater.clearGarageState()
garageNotify.terminate()
def garageNotifyLoop(queue):
signal(SIGTERM, raiseHaltException())
config = ConfigParser()
config.read(CONFIG_FILE)
ntfy = config['garage'].get('ntfy')
topic = config['garage'].get('topic')
try:
resp = requests.get(f'https://{ntfy}/{topic}/json', stream=True)
for line in resp.iter_lines():
if line:
data = json.loads(line.decode('utf-8'))
if (data['event'] == 'message'):
queue.put('update')
except HaltException:
pass
except Exception as e:
print(e, flush=True)
finally:
resp.close()
def cleanExit(unicorn, haltEvent, queue):
def _exit_(signum, frame):
unicorn.off()
haltEvent.set()
queue.put('halt')
queue.close()
sys.exit(0)
return _exit_
def raiseHaltException():
def _exit_(signum, frame):
raise HaltException()
return _exit_

1
chutney/time/__init__.py Normal file
View File

@ -0,0 +1 @@
from .time_display import TimeDisplay

View File

@ -1,4 +1,4 @@
import colors import chutney.colors as colors
from datetime import datetime from datetime import datetime

View File

@ -0,0 +1,2 @@
from .weather_display import WeatherDisplay
from .weather_updater import WeatherUpdater

View File

@ -1,4 +1,4 @@
import colors import chutney.colors as colors
class WeatherDisplay: class WeatherDisplay:
@ -10,7 +10,7 @@ class WeatherDisplay:
self.digitWidth = 4 self.digitWidth = 4
self.currentTemperature = '' self.currentTemperature = ''
self.color = colors.ORANGE self.color = colors.ORANGE
self.weatherFile = 'weather.txt' self.weatherFile = 'data/weather.txt'
def showWeather(self): def showWeather(self):
temperature = self.getTemperature() temperature = self.getTemperature()

View File

@ -17,8 +17,8 @@ class WeatherUpdater:
self.uri = f'https://{host}/api/weather?lat={lat}&lon={lon}&units=metric' self.uri = f'https://{host}/api/weather?lat={lat}&lon={lon}&units=metric'
self.auth = (user, password) self.auth = (user, password)
self.weatherTempFile = 'weather.tmp' self.weatherTempFile = 'data/weather.tmp'
self.weatherFile = 'weather.txt' self.weatherFile = 'data/weather.txt'
self.persistTemperature('init') self.persistTemperature('init')
def updateWeather(self): def updateWeather(self):

2
data/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*
!.gitignore