stepper-clock/Screens.py

430 lines
17 KiB
Python

import Clock
import uasyncio as asyncio
import Buzzer
import Settings
import Hardware as HW
import math
import network
import time
import ntptime
class ClockScreen():
def __await__(self):
self.running = True
self.init()
while self.running:
if Settings.alarmOn:
minutesNow = (time.localtime()[3]*60+time.localtime()[4])%(24*60)
minutesAlarm = (Settings.alarmTime[0]*60+Settings.alarmTime[1])%(24*60)
if not self.alarmTrunedOff:
self.alarmPlaying = self.alarmPlaying or (minutesNow >= minutesAlarm and ((minutesNow-minutesAlarm)%(24*60) <=5 ))
if self.alarmPlaying and not HW.buzzer.isPlaying():
HW.housingLEDs.fill((255,0,0))
for l in HW.leds:
l.setOffState(blinkRate=4,pwmDuty=1023)
HW.buzzer.playSound(HW.Buzzer.ALARMTONES[Settings.selectedSound])
else:
pass
elif minutesNow < minutesAlarm:
self.alarmTrunedOff = False
await asyncio.sleep_ms(200)
HW.housingLEDs.fill((0,0,0))
self.cleanup()
__iter__ = __await__ # https://github.com/micropython/micropython/issues/2678
def finish(self):
self.running = False
for b in HW.buttons:
b.setCallbacks()#Clear Callbacks
def __init__(self):
self.running = False
self.light = False
self.clock = Clock.Clock()
self.alarmTrunedOff = False
self.alarmPlaying = False
COLORS = ((255,0,0),(255,0,127),(127,0,255),(0,0,255),(0,127,255),(140,70,255),(0,255,127),(0,255,0),(127,255,0),(255,127,0))
BRIGHTNESS = (5,10,50,100,160,255)
def onButtonPressed(self,button):
HW.leds[button].on()
def onButtonReleased(self,button,pushDownTime):
HW.leds[button].off()
if self.alarmPlaying:
HW.buzzer.stop()
self.alarmTrunedOff = True
self.alarmPlaying = False
HW.housingLEDs.fill((0,0,0))
HW.leds[0].setOffState()
HW.leds[1].setOffState()
HW.leds[2].setOffState(pwmDuty=200 if Settings.alarmOn else 0)
HW.housingLEDs.fill([int(c/255*ClockScreen.BRIGHTNESS[Settings.selectedBrightness]) for c in ClockScreen.COLORS[Settings.selectedColor]] if self.light else (0,0,0))
else:
if button == 0:
Settings.selectedBrightness=(Settings.selectedBrightness+1)%len(ClockScreen.BRIGHTNESS)
elif button == 1:
if pushDownTime > 700:
self.finish()
return
self.light = not self.light
elif button == 2:
if pushDownTime < 700:
Settings.selectedColor=(Settings.selectedColor+1)%len(ClockScreen.COLORS)
else:
Settings.alarmOn = not Settings.alarmOn
HW.leds[2].setOffState(pwmDuty=200 if Settings.alarmOn else 0)
Settings.save()
HW.housingLEDs.fill([int(c/255*ClockScreen.BRIGHTNESS[Settings.selectedBrightness]) for c in ClockScreen.COLORS[Settings.selectedColor]] if self.light else (0,0,0))
def init(self):
HW.leds[2].setOffState(pwmDuty=200 if Settings.alarmOn else 0)
HW.housingLEDs.fill([int(c/255*ClockScreen.BRIGHTNESS[Settings.selectedBrightness]) for c in ClockScreen.COLORS[Settings.selectedColor]] if self.light else (0,0,0))
for i,b in enumerate(HW.buttons):
b.setCallbacks(onPushDown=lambda i=i:self.onButtonPressed(i),onPushUp=lambda pushDownTime,button=i:self.onButtonReleased(button,pushDownTime))
self.clock.start()
def cleanup(self):
HW.leds[2].setOffState()
self.clock.stop()
class InitHandsScreen():
def __iter__(self):
HW.motorHour.rotateTo(0)
HW.motorMinu.rotateTo(0)
HW.housingLEDs.upper((50,50,50))
HW.leds[1].setOffState(pwmDuty=500,blinkRate=1.2)
timeScreen = Get2PositionsScreen(\
startTime=(0,0),\
onStart=lambda _: HW.buzzer.playSound(HW.Buzzer.BEEP),\
onSelectedTimeChange=None,\
onPicked=lambda _: Settings.save())
await timeScreen
HW.motorHour.reset() # Set the new Zero
HW.motorMinu.reset()
HW.housingLEDs.fill((0,0,0))
HW.leds[1].setOffState()
class SetAlarmTimeScreen():
def setAlarmTime(self,selectedTime):
Settings.alarmTime = selectedTime
Settings.save()
def __iter__(self):
HW.housingLEDs.fill((255,0,0))
timeScreen = GetTimeScreen(\
startTime=Settings.alarmTime,\
onStart=lambda _: HW.buzzer.playSound(HW.Buzzer.BEEP),\
onSelectedTimeChange=None,\
onPicked=self.setAlarmTime)
await timeScreen
HW.housingLEDs.fill((0,0,0))
class SetTimeScreen():
def __init__(self):
self.timeScreen = None
def onShortMiddle(self):
try:
ntptime.settime()
if self.timeScreen != None:
ti = HW.rtc.datetime()[4:6]
self.timeScreen.pickedTime = ti[0]*60 + ti[1]
HW.buzzer.playSound(HW.Buzzer.BEEPBEEP)
except Exception as e:
HW.buzzer.playSound(HW.Buzzer.BOOP)
print("Failed to get NTP Time\n",e)
def setTime(self,selectedTime):
#TODO if (HW.rtc != None):
ti = list(HW.rtc.datetime()[:-1])
ti[4:6] = selectedTime
HW.rtc.datetime(ti + [0])
HW.dsRtc.DateTime(ti)
def __iter__(self):
HW.housingLEDs.fill((255,0,0))
self.timeScreen = GetTimeScreen(\
startTime=HW.rtc.datetime()[4:6],\
onStart=lambda _: HW.buzzer.playSound(HW.Buzzer.BEEP),\
onSelectedTimeChange=None,\
onPicked=self.setTime,
onShortMiddle=self.onShortMiddle)
await self.timeScreen
HW.housingLEDs.fill((0,0,0))
class RingtoneSettingsScreen():
def playAndSetSound(self,number):
Settings.selectedSound = number
HW.buzzer.playSound(HW.Buzzer.ALARMTONES[number])
def __iter__(self):
numberScreen = GetNumberScreen([i for i in range(len(HW.Buzzer.ALARMTONES))],\
startNumber=Settings.selectedSound,\
onStart=self.playAndSetSound,\
onNumberChange=self.playAndSetSound,\
onPicked=lambda _:Settings.save())
await numberScreen
HW.buzzer.stop()
class HumidityScreen():
def __iter__(self):
HW.housingLEDs.fill((0,50,200))
numberScreen = ShowNumberScreen(HW.sensorBme.humidity,numberGetter=lambda : HW.sensorBme.humidity)
await numberScreen
class TemperatureScreen():
def __iter__(self):
HW.housingLEDs.fill((0,50,200))
numberScreen = ShowNumberScreen(HW.sensorBme.temperature,numberGetter=lambda : HW.sensorBme.temperature)
await numberScreen
class ShowIpScreen():
def __init__(self):
self.IP = "0"
async def beepAndWaitIP(self,digitShown):
HW.housingLEDs.fill(HW.HousingLEDs.WHITE)
ipdigit = digitShown+self.IP[:digitShown].count(".")
if (ipdigit >= len(self.IP) or self.IP[ipdigit] == "."):
HW.buzzer.playSound(HW.Buzzer.BEEPBEEP)
await asyncio.sleep_ms(1800)
else:
HW.buzzer.playSound(HW.Buzzer.BEEP)
await asyncio.sleep_ms(1100)
HW.housingLEDs.fill((0,0,0))
def __iter__(self):
sta_if = network.WLAN(network.STA_IF)
if sta_if.status() != network.STAT_GOT_IP:
HW.housingLEDs.fill((255,0,0))
HW.buzzer.playSound(HW.Buzzer.BEEP)
await asyncio.sleep_ms(1000)
else:
self.IP = sta_if.ifconfig()[0]
showNumberScreen = ShowLongNumberScreen(number=[int(i) for i in self.IP.replace(".","")],onDigitShown=self.beepAndWaitIP)
await showNumberScreen
HW.housingLEDs.fill((0,0,0))
class ShowLongNumberScreen():
def __init__(self,number,onDigitShown):
self.number = number
self.digit_shown = 0
self.onDigitShown = onDigitShown
self.running = False
def onButtonReleased(self,pushDownTime):
HW.leds[1].off()
if pushDownTime > 700:
self.running = False
def __await__(self):
self.running = True
HW.buttons[1].setCallbacks(onPushUp=self.onButtonReleased,onPushDown=lambda :HW.leds[1].on())
HW.motorMinu.rotateTo(0)
HW.motorHour.rotateTo(0)
self.digit_shown = 0
await self.onDigitShown(self.digit_shown)
while self.digit_shown < len(self.number):
HW.motorMinu.rotateTo(-((self.number[self.digit_shown]%10)/12))
while self.running and (not HW.motorMinu.isAtTarget() or not HW.motorHour.isAtTarget()):
await asyncio.sleep_ms(200)
if not self.running:
return
self.digit_shown=self.digit_shown+1
await self.onDigitShown(self.digit_shown)
HW.buttons[1].setCallbacks()
__iter__ = __await__ # https://github.com/micropython/micropython/issues/2678
class ShowNumberScreen():
def __init__(self,number,numberGetter=None):
self.number = number
self.running = False
self.update = numberGetter
def onButtonReleased(self,pushDownTime):
HW.leds[1].off()
if pushDownTime > 700:
self.running = False
def __await__(self):
self.running = True
HW.buttons[1].setCallbacks(onPushUp=self.onButtonReleased,onPushDown=lambda :HW.leds[1].on())
while self.running:
if self.update != None:
self.number = self.update()
while (not HW.motorMinu.isAtTarget() or not HW.motorHour.isAtTarget()):
await asyncio.sleep_ms(200)
HW.motorMinu.rotateTo(-((self.number%10)/12))
HW.motorrHou.rotateTo(-((self.number//10)/12))
await asyncio.sleep_ms(500)
HW.buttons[1].setCallbacks()
__iter__ = __await__ # https://github.com/micropython/micropython/issues/2678
class GetNumberScreen():
def __init__(self,acceptedInputNumbers,startNumber = None,onStart=None,onNumberChange = None,onPicked = None):
self.acceptedInputNumbers = acceptedInputNumbers
self.onStart = onStart
self.onNumberChange = onNumberChange
self.onPicked = onPicked
self.running = False
if startNumber:
self.number = startNumber
else:
self.number = acceptedInputNumbers[0]
def __await__(self):
self.running = True
for i,b in enumerate(HW.buttons):
b.setCallbacks(onPushDown=lambda i=i:self.onButtonPressed(i),onPushUp=lambda pushDownTime,button=i:self.onButtonReleased(button,pushDownTime))
HW.motorMinu.rotateTo(-(self.number/12))
HW.motorHour.rotateTo(0)
while not HW.motorHour.isAtTarget() or not HW.motorMinu.isAtTarget():
await asyncio.sleep_ms(200)
if self.onStart:
self.onStart(self.number)
while self.running:
await asyncio.sleep_ms(200)
if self.onPicked:
self.onPicked(self.number)
return self.number
__iter__ = __await__ # https://github.com/micropython/micropython/issues/2678
def onButtonPressed(self,button):
HW.leds[button].on()
def onButtonReleased(self,button,pushDownTime):
HW.leds[button].off()
if button == 1:
if pushDownTime > 700:
self.finish()
return
else:
if pushDownTime < 500:
self.number=self.acceptedInputNumbers[(self.acceptedInputNumbers.index(self.number) + (1 if button == 2 else -1)) % len(self.acceptedInputNumbers)]
HW.motorMinu.rotateTo(-(self.number/12))
if self.onNumberChange:
self.onNumberChange(self.number)
def finish(self):
self.running = False
for b in HW.buttons:
b.setCallbacks()#Clear Callbacks
class Get2PositionsScreen():
def __init__(self,startTime = (0,0),onStart=None,onSelectedTimeChange = None,onPicked = None):
self.onStart = onStart
self.onSelectedTimeChange = onSelectedTimeChange
self.onPicked = onPicked
self.running = False
self.pickedTime = startTime
self.mode = 0
def __await__(self):
self.running = True
self.mode=0 # 0: Minutes, 1: Hours
HW.motorMinu.rotateTo(-(self.pickedTime[1])/12)
HW.motorHour.rotateTo(-(self.pickedTime[0])/12)
for number,button in enumerate(HW.buttons):
button.setCallbacks(\
onPushDown=lambda i=number:self.onButtonPressed(i),\
onPushUp=lambda pushDownTime,button=number:self.onButtonReleased(button,pushDownTime))
# Wait for the Hands to move up
while not HW.motorMinu.isAtTarget() or not HW.motorHour.isAtTarget():
await asyncio.sleep_ms(200)
if self.onStart:
self.onStart(self.pickedTime)
while self.running:
await asyncio.sleep_ms(200)
if self.onPicked:
self.onPicked(self.pickedTime)
__iter__ = __await__ # https://github.com/micropython/micropython/issues/2678
def finish(self):
self.running = False
for b in HW.buttons:
b.setCallbacks()#Clear Callbacks
for l in HW.leds:
l.off()
l.setOffState()
def onButtonPressed(self,button):
HW.leds[button].on()
if button != 1:
if self.mode == 0:
HW.motorMinu.rotateTo(direction=(1 if button == 0 else -1))
elif self.mode == 1:
HW.motorHour.rotateTo(direction=(1 if button == 0 else -1))
def onButtonReleased(self,button,time):
HW.leds[button].off()
if button == 1:
self.mode=(1+self.mode )% 2
if time > 700:
self.finish()
else:
if self.mode == 0:
HW.motorMinu.stop()
else:
HW.motorHour.stop()
if self.onSelectedTimeChange:
# TODO This is probably not save as its super unstable around the hour-increments
minutes = (60-HW.motorMinu.getOrientation()*60)
hours = (12-HW.motorMinu.getOrientation()*12)
self.pickedTime = (hours,minutes)
self.onSelectedTimeChange(self.pickedTime)
class GetTimeScreen():
def __init__(self,startTime = (0,0),onStart=None,onSelectedTimeChange = None,onPicked = None,onShortMiddle = None):
self.onShortMiddle = onShortMiddle
self.onStart = onStart
self.onSelectedTimeChange = onSelectedTimeChange
self.onPicked = onPicked
self.running = False
self.pickedTime = (startTime[0]*60 + startTime[1])%(24*60)
self.AM = (self.pickedTime < 12*60)
self.direction = 0
def calcTupleTime(self):
return (int(self.pickedTime/60)%24,self.pickedTime%60)
def __await__(self):
self.running = True
HW.leds[1].setOffState(blinkRate=1.2)
HW.housingLEDs.upper(HW.HousingLEDs.BLUE if self.AM else HW.HousingLEDs.YELLOW)
for number,button in enumerate(HW.buttons):
button.setCallbacks(\
onPushDown=lambda i=number:self.onButtonPressed(i),\
onPushUp=lambda pushDownTime,button=number:self.onButtonReleased(button,pushDownTime))
# Wait for the Hands to move up
while not HW.motorMinu.isAtTarget() or not HW.motorHour.isAtTarget():
await asyncio.sleep_ms(200)
if self.onStart:
self.onStart(self.calcTupleTime())
while self.running:
HW.motorMinu.rotateTo(-(self.pickedTime/60))
HW.motorHour.rotateTo(-(self.pickedTime/60/12))
# Color the Top LED to indikate AM or PM
self.AM = (self.pickedTime < 12*60)
HW.housingLEDs.upper(HW.HousingLEDs.BLUE if self.AM else HW.HousingLEDs.YELLOW)
await asyncio.sleep_ms(100)
self.pickedTime = (self.pickedTime+self.direction)%(24*60)
if self.onSelectedTimeChange:
self.onSelectedTimeChange(self.calcTupleTime())
if self.onPicked:
self.onPicked(self.calcTupleTime())
__iter__ = __await__ # https://github.com/micropython/micropython/issues/2678
def finish(self):
self.running = False
for b in HW.buttons:
b.setCallbacks()#Clear Callbacks
for l in HW.leds:
l.off()
l.setOffState()
def onButtonPressed(self,button):
HW.leds[button].on()
if button != 1:
self.direction = (-1 if button == 0 else 1)
def onButtonReleased(self,button,time):
HW.leds[button].off()
if button == 1:
if time > 700:
self.finish()
else:
if self.onShortMiddle != None:
self.onShortMiddle()
else:
self.direction = 0