Handle missing network on start/refactor code

This commit is contained in:
Mike Cifelli 2023-01-14 14:48:36 -05:00
parent fd1ea198fa
commit 0a212e5752
13 changed files with 83 additions and 63 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
.vscode/
__pycache__/ __pycache__/
*.swp *.swp
chutney.cfg chutney.cfg

3
chutney/exceptions.py Normal file
View File

@ -0,0 +1,3 @@
class HaltException(Exception):
pass

View File

@ -1,2 +1,3 @@
from .garage_display import GarageDisplay from .garagedisplayer import GarageDisplayer
from .garage_updater import GarageUpdater from .garagelistener import GarageListener
from .garageupdater import GarageUpdater

View File

@ -2,9 +2,9 @@ import chutney.colors as colors
import json import json
class GarageDisplay: class GarageDisplayer:
def __init__(self, symbolDisplay, topRow): def __init__(self, symbolDisplayer, topRow):
self.symbolDisplay = symbolDisplay self.symbolDisplayer = symbolDisplayer
self.topRow = topRow self.topRow = topRow
self.westDoorStartColumn = 1 self.westDoorStartColumn = 1
self.eastDoorStartColumn = 12 self.eastDoorStartColumn = 12
@ -15,7 +15,7 @@ class GarageDisplay:
self.openFillColor = colors.WHITE self.openFillColor = colors.WHITE
self.garageFile = 'data/garage.json' self.garageFile = 'data/garage.json'
self.symbolDisplay.clearRow(self.topRow, rowHeight=4) self.symbolDisplayer.clearRow(self.topRow, rowHeight=4)
def showGarageState(self): def showGarageState(self):
state = self.getGarageState() state = self.getGarageState()
@ -26,7 +26,7 @@ class GarageDisplay:
if self.isGarageStateValid(state): if self.isGarageStateValid(state):
self.showState(state) self.showState(state)
else: else:
self.symbolDisplay.clearRow(self.topRow, rowHeight=4) self.symbolDisplayer.clearRow(self.topRow, rowHeight=4)
def getGarageState(self): def getGarageState(self):
try: try:
@ -51,7 +51,7 @@ class GarageDisplay:
self.showOpenDoor(self.eastDoorStartColumn) self.showOpenDoor(self.eastDoorStartColumn)
def showOpenDoor(self, column): def showOpenDoor(self, column):
self.symbolDisplay.displaySquare( self.symbolDisplayer.displaySquare(
x=column, x=column,
y=self.topRow, y=self.topRow,
outlineColor=self.openOutlineColor, outlineColor=self.openOutlineColor,
@ -59,7 +59,7 @@ class GarageDisplay:
) )
def showClosedDoor(self, column): def showClosedDoor(self, column):
self.symbolDisplay.displaySquare( self.symbolDisplayer.displaySquare(
x=column, x=column,
y=self.topRow, y=self.topRow,
outlineColor=self.closedOutlineColor, outlineColor=self.closedOutlineColor,

View File

@ -0,0 +1,28 @@
import json
import requests
from configparser import ConfigParser
class GarageListener:
def __init__(self, configFile):
config = ConfigParser()
config.read(configFile)
ntfy = config['garage'].get('ntfy')
topic = config['garage'].get('topic')
self.ntfyUri = f'https://{ntfy}/{topic}/json'
def listenForNotifications(self, queue):
resp = requests.get(self.ntfyUri, stream=True)
try:
for line in resp.iter_lines():
if line:
data = json.loads(line.decode('utf-8'))
if (data['event'] == 'message'):
queue.put('update')
finally:
resp.close()

View File

@ -1,14 +1,13 @@
import json
import requests
import sys import sys
from .symbol_display import SymbolDisplay from .exceptions import HaltException
from .garage import GarageDisplay from .garage import GarageDisplayer
from .garage import GarageListener
from .garage import GarageUpdater from .garage import GarageUpdater
from .time import TimeDisplay from .symboldisplayer import SymbolDisplayer
from .weather import WeatherDisplay from .time import TimeDisplayer
from .weather import WeatherDisplayer
from .weather import WeatherUpdater from .weather import WeatherUpdater
from configparser import ConfigParser
from multiprocessing import Event from multiprocessing import Event
from multiprocessing import Process from multiprocessing import Process
from multiprocessing import Queue from multiprocessing import Queue
@ -27,14 +26,11 @@ except ImportError:
WEATHER_UPDATE_INTERVAL_IN_SECONDS = 60 WEATHER_UPDATE_INTERVAL_IN_SECONDS = 60
GARAGE_UPDATE_INTERVAL_IN_SECONDS = 30 GARAGE_UPDATE_INTERVAL_IN_SECONDS = 30
GARAGE_LISTENER_RETRY_INTERVAL_IN_SECONDS = 120
DISPLAY_UPDATE_INTERVAL_IN_SECONDS = 0.5 DISPLAY_UPDATE_INTERVAL_IN_SECONDS = 0.5
CONFIG_FILE = 'chutney.cfg' CONFIG_FILE = 'chutney.cfg'
class HaltException(Exception):
pass
def main(): def main():
queue = Queue() queue = Queue()
haltEvent = Event() haltEvent = Event()
@ -44,15 +40,15 @@ def main():
unicorn.brightness(0.3) unicorn.brightness(0.3)
symbolDisplay = SymbolDisplay(unicorn) symbolDisplayer = SymbolDisplayer(unicorn)
timeDisplay = TimeDisplay(symbolDisplay, topRow=15) timeDisplayer = TimeDisplayer(symbolDisplayer, topRow=15)
weatherDisplay = WeatherDisplay(symbolDisplay, topRow=9) weatherDisplayer = WeatherDisplayer(symbolDisplayer, topRow=9)
garageDisplay = GarageDisplay(symbolDisplay, topRow=3) garageDisplayer = GarageDisplayer(symbolDisplayer, topRow=3)
while True: while True:
timeDisplay.showTime() timeDisplayer.showTime()
weatherDisplay.showWeather() weatherDisplayer.showWeather()
garageDisplay.showGarageState() garageDisplayer.showGarageState()
sleep(DISPLAY_UPDATE_INTERVAL_IN_SECONDS) sleep(DISPLAY_UPDATE_INTERVAL_IN_SECONDS)
@ -88,27 +84,18 @@ def garageLoop(queue):
def garageNotifyLoop(queue): def garageNotifyLoop(queue):
signal(SIGTERM, raiseHaltException()) signal(SIGTERM, raiseHaltException())
config = ConfigParser()
config.read(CONFIG_FILE)
ntfy = config['garage'].get('ntfy') garageListener = GarageListener(configFile=CONFIG_FILE)
topic = config['garage'].get('topic') isRunning = True
try: while isRunning:
resp = requests.get(f'https://{ntfy}/{topic}/json', stream=True) try:
garageListener.listenForNotifications(queue)
for line in resp.iter_lines(): except HaltException:
if line: isRunning = False
data = json.loads(line.decode('utf-8')) except Exception as e:
print(e, flush=True)
if (data['event'] == 'message'): sleep(GARAGE_LISTENER_RETRY_INTERVAL_IN_SECONDS)
queue.put('update')
except HaltException:
pass
except Exception as e:
print(e, flush=True)
finally:
resp.close()
def cleanExit(unicorn, haltEvent, queue): def cleanExit(unicorn, haltEvent, queue):

View File

@ -1,7 +1,7 @@
import chutney.colors as colors import chutney.colors as colors
class SymbolDisplay: class SymbolDisplayer:
def __init__(self, unicorn, minX=0, maxX=15, minY=0, maxY=15): def __init__(self, unicorn, minX=0, maxX=15, minY=0, maxY=15):
self.unicorn = unicorn self.unicorn = unicorn

View File

@ -1 +1 @@
from .time_display import TimeDisplay from .timedisplayer import TimeDisplayer

View File

@ -3,10 +3,10 @@ import chutney.colors as colors
from datetime import datetime from datetime import datetime
class TimeDisplay: class TimeDisplayer:
def __init__(self, symbolDisplay, topRow): def __init__(self, symbolDisplayer, topRow):
self.symbolDisplay = symbolDisplay self.symbolDisplayer = symbolDisplayer
self.topRow = topRow self.topRow = topRow
self.currentHour = [-1, -1] self.currentHour = [-1, -1]
self.currentMinute = [-1, -1] self.currentMinute = [-1, -1]
@ -37,7 +37,7 @@ class TimeDisplay:
def showTimeDots(self): def showTimeDots(self):
if self.color != self.currentColor: if self.color != self.currentColor:
self.symbolDisplay.displayTimeDots( self.symbolDisplayer.displayTimeDots(
x=self.timeDotsColumn, x=self.timeDotsColumn,
y=self.topRow, y=self.topRow,
color=self.color color=self.color
@ -53,7 +53,7 @@ class TimeDisplay:
self.showDigit(self.minuteStartColumn + 4, minute[1]) self.showDigit(self.minuteStartColumn + 4, minute[1])
def showDigit(self, x, digit): def showDigit(self, x, digit):
self.symbolDisplay.displayDigit( self.symbolDisplayer.displayDigit(
x=x, x=x,
y=self.topRow, y=self.topRow,
digit=digit, digit=digit,
@ -61,7 +61,7 @@ class TimeDisplay:
) )
def hideDigit(self, x): def hideDigit(self, x):
self.symbolDisplay.clearDigit( self.symbolDisplayer.clearDigit(
x=x, x=x,
y=self.topRow y=self.topRow
) )

View File

@ -1,2 +1,2 @@
from .weather_display import WeatherDisplay from .weatherdisplayer import WeatherDisplayer
from .weather_updater import WeatherUpdater from .weatherupdater import WeatherUpdater

View File

@ -1,9 +1,9 @@
import chutney.colors as colors import chutney.colors as colors
class WeatherDisplay: class WeatherDisplayer:
def __init__(self, symbolDisplay, topRow): def __init__(self, symbolDisplayer, topRow):
self.symbolDisplay = symbolDisplay self.symbolDisplayer = symbolDisplayer
self.topRow = topRow self.topRow = topRow
self.twoDigitStartColumn = 5 self.twoDigitStartColumn = 5
self.oneDigitStartColumn = 7 self.oneDigitStartColumn = 7
@ -17,7 +17,7 @@ class WeatherDisplay:
if temperature != self.currentTemperature: if temperature != self.currentTemperature:
self.currentTemperature = temperature self.currentTemperature = temperature
self.symbolDisplay.clearRow(self.topRow) self.symbolDisplayer.clearRow(self.topRow)
if self.isTemperatureValid(temperature): if self.isTemperatureValid(temperature):
self.updateColor(temperature) self.updateColor(temperature)
@ -68,14 +68,14 @@ class WeatherDisplay:
return abs(int(temperature))//10 == 0 return abs(int(temperature))//10 == 0
def showNegative(self, column): def showNegative(self, column):
self.symbolDisplay.displayNegative( self.symbolDisplayer.displayNegative(
x=column, x=column,
y=self.topRow, y=self.topRow,
color=self.color color=self.color
) )
def showDigit(self, column, digit): def showDigit(self, column, digit):
self.symbolDisplay.displayDigit( self.symbolDisplayer.displayDigit(
x=column, x=column,
y=self.topRow, y=self.topRow,
digit=digit, digit=digit,
@ -83,7 +83,7 @@ class WeatherDisplay:
) )
def showDegree(self, column): def showDegree(self, column):
self.symbolDisplay.displayDegree( self.symbolDisplayer.displayDegree(
x=column, x=column,
y=self.topRow, y=self.topRow,
color=self.color color=self.color