123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189 |
- #!/usr/bin/env python
-
- import uasyncio as asyncio
- import io
- import sys
- import machine
- import os
- import gc
- import time
-
- # https://github.com/pimoroni/pimoroni-pico/blob/main/micropython/examples/pico_lipo_shim/battery_pico.py
- # https://github.com/pimoroni/enviro/pull/146
- # TODO https://github.com/micropython/micropython/issues/11185
-
- full_battery = 4.2
- empty_battery = 3.2
-
- charging = machine.Pin("WL_GPIO2", machine.Pin.IN)
- conversion_factor = 3 * 3.3 / 65535
- cachedVoltage = None
- lastCaching = time.time()
-
- def set_pad(gpio, value):
- machine.mem32[0x4001c000 | (4 + (4 * gpio))] = value
-
- def get_pad(gpio):
- return machine.mem32[0x4001c000 | (4 + (4 * gpio))]
-
- def batteryVoltageRead():
- vsys = machine.ADC(3)
- voltage = vsys.read_u16() * conversion_factor
- return voltage
-
- def batteryVoltageAverage():
- old_pad = get_pad(29)
- set_pad(29, 128) # no pulls, no output, no input
-
- sample_count = 10
- voltage = 0
- for i in range(0, sample_count):
- voltage += batteryVoltageRead()
- voltage /= sample_count
-
- set_pad(29, old_pad)
- return voltage
-
- def batteryVoltage():
- global cachedVoltage, lastCaching
-
- if ((time.time() - lastCaching) >= 2) or (cachedVoltage == None):
- lastCaching = time.time()
- cachedVoltage = batteryVoltageAverage()
-
- percentage = 100.0 * ((cachedVoltage - empty_battery) / (full_battery - empty_battery))
- if percentage > 100.0:
- percentage = 100.0
-
- return cachedVoltage, percentage
-
- class States:
- def __init__(self, lcd):
- self.lcd = lcd
- self.states = []
- self.current = None
-
- def add(self, s):
- self.states.append(s)
-
- async def draw(self):
- self.lcd.fill(self.lcd.black)
- self.lcd.text("Volcano Remote Control App", 0, 0, self.lcd.green)
-
- r = await self.states[self.current].draw()
-
- voltage, percentage = batteryVoltage()
- s = "Charging ({:.2f}V)".format(voltage)
- c = self.lcd.green
- if charging.value() != 1:
- s = "{:.0f}% ({:.2f}V)".format(percentage, voltage)
- c = self.lcd.white
- if percentage <= 20:
- c = self.lcd.red
- self.lcd.text("Battery: {}".format(s), 0, self.lcd.height - 10, c)
-
- self.lcd.show()
- return r
-
- def run(self):
- if self.current == None:
- self.current = 0
- self.states[self.current].enter()
-
- next = asyncio.run(self.draw())
- if next >= 0:
- val = self.states[self.current].exit()
- self.current = next
- self.states[self.current].enter(val)
-
- def state_machine(lcd):
- states = States(lcd)
-
- # 0 - Scan
- from state_scan import StateScan
- scan = StateScan(lcd)
- states.add(scan)
-
- # 1 - Connect
- from state_connect import StateConnect
- conn = StateConnect(lcd, True)
- states.add(conn)
-
- # 2 - Select
- from state_select import StateSelect
- select = StateSelect(lcd)
- states.add(select)
-
- # 3 - Heater On
- from state_heat import StateHeat
- heatOn = StateHeat(lcd, True)
- states.add(heatOn)
-
- # 4 - Heater Off
- heatOff = StateHeat(lcd, False)
- states.add(heatOff)
-
- # 5 - Disconnect
- disconn = StateConnect(lcd, False)
- states.add(disconn)
-
- # 6 - Wait for temperature
- from state_wait_temp import StateWaitTemp
- waitTemp = StateWaitTemp(lcd)
- states.add(waitTemp)
-
- # 7 - Wait for time
- from state_wait_time import StateWaitTime
- waitTime = StateWaitTime(lcd)
- states.add(waitTime)
-
- # 8 - Pump
- from state_pump import StatePump
- pump = StatePump(lcd)
- states.add(pump)
-
- # 9 - Notify
- from state_notify import StateNotify
- notify = StateNotify(lcd)
- states.add(notify)
-
- while True:
- states.run()
-
- from lcd import LCD
- lcd = LCD()
-
- # splash screen
- lcd.fill(lcd.black)
- lcd.textC("S&B Volcano Remote", int(lcd.width / 2), 10, lcd.green)
- lcd.textC("by xythobuz", int(lcd.width / 2), 20, lcd.yellow)
- lcd.textC("Initializing...", int(lcd.width / 2), 30, lcd.white)
- lcd.textC(os.uname()[0][ 0 : 30], int(lcd.width / 2), lcd.height - 50, lcd.green)
- lcd.textC(os.uname()[3][ 0 : 30], int(lcd.width / 2), lcd.height - 40, lcd.yellow)
- lcd.textC(os.uname()[3][30 : 60], int(lcd.width / 2), lcd.height - 30, lcd.yellow)
- lcd.textC(os.uname()[4][ 0 : 30], int(lcd.width / 2), lcd.height - 20, lcd.white)
- lcd.textC(os.uname()[4][30 : 60], int(lcd.width / 2), lcd.height - 10, lcd.white)
- lcd.show()
- lcd.brightness(1.0)
-
- # bootloader access with face buttons
- keys = lcd.buttons()
- if keys.once("a") and keys.once("b"):
- machine.bootloader()
-
- try:
- state_machine(lcd)
- except Exception as e:
- sys.print_exception(e)
-
- gc.collect()
- os = io.StringIO()
- sys.print_exception(e, os)
- s = os.getvalue()
- os.close()
-
- lcd.fill(lcd.black)
- lcd.textBlock(s, lcd.white)
- lcd.show()
-
- raise e
|