Add garage indicators
This commit is contained in:
parent
b2e20763d9
commit
4cac468c01
|
@ -2,4 +2,5 @@ __pycache__/
|
|||
*.swp
|
||||
*.tmp
|
||||
chutney.cfg
|
||||
garage.json
|
||||
weather.txt
|
||||
|
|
|
@ -14,15 +14,15 @@
|
|||
|
||||
import colors
|
||||
|
||||
BLACK = [0, 0, 0]
|
||||
|
||||
|
||||
class CharacterDisplay:
|
||||
|
||||
def __init__(self, unicorn, minX=0, maxX=15):
|
||||
def __init__(self, unicorn, minX=0, maxX=15, minY=0, maxY=15):
|
||||
self.unicorn = unicorn
|
||||
self.minX = minX
|
||||
self.maxX = maxX
|
||||
self.minY = minY
|
||||
self.maxY = maxY
|
||||
|
||||
self.digits = {
|
||||
'0': self.displayZero,
|
||||
|
@ -49,8 +49,8 @@ class CharacterDisplay:
|
|||
|
||||
self.unicorn.show()
|
||||
|
||||
def clearRow(self, y):
|
||||
for row in range(y, y-5, -1):
|
||||
def clearRow(self, y, rowHeight=5):
|
||||
for row in range(y, y-rowHeight, -1):
|
||||
for col in range(self.minX, self.maxX + 1):
|
||||
self.setPixel(col, row, colors.BLACK)
|
||||
|
||||
|
@ -77,6 +77,22 @@ class CharacterDisplay:
|
|||
self.setPixel(x+1, y-4, colors.BLACK)
|
||||
self.unicorn.show()
|
||||
|
||||
def displaySquare(self, x, y, outlineColor, fillColor):
|
||||
self.fullLine(x, y, outlineColor)
|
||||
self.leftSide(x, y-1, outlineColor)
|
||||
self.leftSide(x, y-2, outlineColor)
|
||||
self.fullLine(x, y-3, outlineColor)
|
||||
self.rightSide(x+1, y, outlineColor)
|
||||
self.rightSide(x+1, y-1, outlineColor)
|
||||
self.rightSide(x+1, y-2, outlineColor)
|
||||
self.rightSide(x+1, y-3, outlineColor)
|
||||
|
||||
self.leftSide(x+1, y-1, fillColor)
|
||||
self.leftSide(x+1, y-2, fillColor)
|
||||
self.leftSide(x+2, y-1, fillColor)
|
||||
self.leftSide(x+2, y-2, fillColor)
|
||||
self.unicorn.show()
|
||||
|
||||
def displayZero(self, x, y, color):
|
||||
self.fullLine(x, y, color)
|
||||
self.bothSides(x, y-1, color)
|
||||
|
@ -162,5 +178,5 @@ class CharacterDisplay:
|
|||
self.setPixel(start+2, row, color)
|
||||
|
||||
def setPixel(self, x, y, color):
|
||||
if x >= self.minX and x <= self.maxX:
|
||||
if x >= self.minX and x <= self.maxX and y >= self.minY and y <= self.maxY:
|
||||
self.unicorn.set_pixel(x, y, *color)
|
||||
|
|
20
chutney.py
20
chutney.py
|
@ -1,6 +1,8 @@
|
|||
import sys
|
||||
|
||||
from character_display import CharacterDisplay
|
||||
from garage_display import GarageDisplay
|
||||
from garage_updater import GarageUpdater
|
||||
from multiprocessing import Event
|
||||
from multiprocessing import Process
|
||||
from signal import signal
|
||||
|
@ -18,7 +20,8 @@ except ImportError:
|
|||
unicorn.rotation(180)
|
||||
|
||||
|
||||
WEATHER_UPDATE_INTERVAL_IN_SECONDS = 60
|
||||
WEATHER_UPDATE_INTERVAL_IN_SECONDS = 10
|
||||
GARAGE_UPDATE_INTERVAL_IN_SECONDS = 10
|
||||
DISPLAY_UPDATE_INTERVAL_IN_SECONDS = 0.5
|
||||
CONFIG_FILE = 'chutney.cfg'
|
||||
|
||||
|
@ -31,13 +34,18 @@ def main():
|
|||
weatherThread = Process(target=weatherLoop, args=[haltEvent])
|
||||
weatherThread.start()
|
||||
|
||||
garageThread = Process(target=garageLoop, args=[haltEvent])
|
||||
garageThread.start()
|
||||
|
||||
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)
|
||||
|
||||
|
||||
|
@ -51,6 +59,16 @@ def weatherLoop(haltEvent):
|
|||
weatherUpdater.clearWeather()
|
||||
|
||||
|
||||
def garageLoop(haltEvent):
|
||||
garageUpdater = GarageUpdater(configFile=CONFIG_FILE)
|
||||
|
||||
while not haltEvent.is_set():
|
||||
garageUpdater.updateGarageState()
|
||||
haltEvent.wait(timeout=GARAGE_UPDATE_INTERVAL_IN_SECONDS)
|
||||
|
||||
garageUpdater.clearGarageState()
|
||||
|
||||
|
||||
def cleanExit(unicorn, haltEvent):
|
||||
def _exit_(signum, frame):
|
||||
unicorn.off()
|
||||
|
|
|
@ -4,3 +4,6 @@ user=user
|
|||
pass=password
|
||||
lat=lat
|
||||
lon=lon
|
||||
|
||||
[garage]
|
||||
uri=uri
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
BLACK = [0, 0, 0 ]
|
||||
WHITE = [255, 255, 255]
|
||||
GRAY = [50, 50, 50 ]
|
||||
RED = [255, 0, 0 ]
|
||||
PINK = [255, 0, 64 ]
|
||||
GREEN = [0, 255, 0 ]
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
import colors
|
||||
import json
|
||||
|
||||
|
||||
class GarageDisplay:
|
||||
def __init__(self, characterDisplay, topRow):
|
||||
self.characterDisplay = characterDisplay
|
||||
self.topRow = topRow
|
||||
self.westDoorStartColumn = 0
|
||||
self.eastDoorStartColumn = 5
|
||||
self.currentState = {}
|
||||
self.closedOutlineColor = colors.RED
|
||||
self.closedFillColor = colors.GRAY
|
||||
self.openOutlineColor = colors.WHITE
|
||||
self.openFillColor = colors.BLUE
|
||||
self.garageFile = 'garage.json'
|
||||
|
||||
def showGarageState(self):
|
||||
state = self.getGarageState()
|
||||
|
||||
if state != self.currentState:
|
||||
self.currentState = state
|
||||
self.characterDisplay.clearRow(self.topRow, rowHeight=4)
|
||||
|
||||
if self.isGarageStateValid(state):
|
||||
self.showState(state)
|
||||
|
||||
def getGarageState(self):
|
||||
try:
|
||||
with open(self.garageFile) as file:
|
||||
return json.load(file)
|
||||
except Exception as e:
|
||||
print(e, flush=True)
|
||||
return {'error': True}
|
||||
|
||||
def isGarageStateValid(self, state):
|
||||
return not 'error' in state
|
||||
|
||||
def showState(self, state):
|
||||
if state["west-door"] == "closed":
|
||||
self.characterDisplay.displaySquare(
|
||||
x=self.westDoorStartColumn,
|
||||
y=self.topRow,
|
||||
outlineColor=self.closedOutlineColor,
|
||||
fillColor=self.closedFillColor
|
||||
)
|
||||
else:
|
||||
self.characterDisplay.displaySquare(
|
||||
x=self.westDoorStartColumn,
|
||||
y=self.topRow,
|
||||
outlineColor=self.openOutlineColor,
|
||||
fillColor=self.openFillColor
|
||||
)
|
||||
|
||||
if state["east-door"] == "closed":
|
||||
self.characterDisplay.displaySquare(
|
||||
x=self.eastDoorStartColumn,
|
||||
y=self.topRow,
|
||||
outlineColor=self.closedOutlineColor,
|
||||
fillColor=self.closedFillColor
|
||||
)
|
||||
else:
|
||||
self.characterDisplay.displaySquare(
|
||||
x=self.eastDoorStartColumn,
|
||||
y=self.topRow,
|
||||
outlineColor=self.openOutlineColor,
|
||||
fillColor=self.openFillColor
|
||||
)
|
|
@ -0,0 +1,38 @@
|
|||
import os
|
||||
import requests
|
||||
|
||||
from configparser import ConfigParser
|
||||
|
||||
|
||||
class GarageUpdater:
|
||||
def __init__(self, configFile):
|
||||
config = ConfigParser()
|
||||
config.read(configFile)
|
||||
|
||||
self.uri = config['garage'].get('uri')
|
||||
self.garageTempFile = 'garage.tmp'
|
||||
self.garageFile = 'garage.json'
|
||||
self.persistGarageState('{"error": "init"}')
|
||||
|
||||
def updateGarageState(self):
|
||||
try:
|
||||
state = self.getGarageState()
|
||||
self.persistGarageState(state)
|
||||
except requests.exceptions.ConnectionError as e:
|
||||
print(e, flush=True)
|
||||
self.persistGarageState('{"error": "connection"}')
|
||||
except requests.exceptions.Timeout as e:
|
||||
print(e, flush=True)
|
||||
self.persistGarageState('{"error": "timeout"}')
|
||||
|
||||
def clearGarageState(self):
|
||||
self.persistGarageState('{"error": "halted"}')
|
||||
|
||||
def getGarageState(self):
|
||||
return requests.get(self.uri, timeout=3).text
|
||||
|
||||
def persistGarageState(self, state):
|
||||
with open(self.garageTempFile, 'w') as file:
|
||||
file.write(state)
|
||||
|
||||
os.replace(self.garageTempFile, self.garageFile)
|
|
@ -9,7 +9,7 @@ class WeatherDisplay:
|
|||
self.oneDigitStartColumn = 13
|
||||
self.digitWidth = 4
|
||||
self.currentTemperature = ''
|
||||
self.color = colors.BLUE
|
||||
self.color = colors.PINK
|
||||
self.weatherFile = 'weather.txt'
|
||||
|
||||
def showWeather(self):
|
||||
|
|
|
@ -47,7 +47,7 @@ class WeatherUpdater:
|
|||
return currentWeather[0]['intervals'][0]['values']['temperature']
|
||||
|
||||
def getWeather(self):
|
||||
return requests.get(self.uri, auth=self.auth).json()
|
||||
return requests.get(self.uri, auth=self.auth, timeout=3).json()
|
||||
|
||||
def persistTemperature(self, temperature):
|
||||
with open(self.weatherTempFile, 'w') as file:
|
||||
|
|
Loading…
Reference in New Issue