Refactor code into packages
This commit is contained in:
parent
56d0e1f5d4
commit
627420e9cb
|
@ -1,6 +1,3 @@
|
||||||
__pycache__/
|
__pycache__/
|
||||||
*.swp
|
*.swp
|
||||||
*.tmp
|
|
||||||
chutney.cfg
|
chutney.cfg
|
||||||
garage.json
|
|
||||||
weather.txt
|
|
||||||
|
|
133
chutney.py
133
chutney.py
|
@ -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()
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import colors
|
import chutney.colors as colors
|
||||||
|
|
||||||
|
|
||||||
class CharacterDisplay:
|
class CharacterDisplay:
|
|
@ -0,0 +1,2 @@
|
||||||
|
from .garage_display import GarageDisplay
|
||||||
|
from .garage_updater import GarageUpdater
|
|
@ -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()
|
|
@ -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):
|
|
@ -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_
|
|
@ -0,0 +1 @@
|
||||||
|
from .time_display import TimeDisplay
|
|
@ -1,4 +1,4 @@
|
||||||
import colors
|
import chutney.colors as colors
|
||||||
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
from .weather_display import WeatherDisplay
|
||||||
|
from .weather_updater import WeatherUpdater
|
|
@ -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()
|
|
@ -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):
|
|
@ -0,0 +1,2 @@
|
||||||
|
*
|
||||||
|
!.gitignore
|
Loading…
Reference in New Issue