falls jemand von euch Lust hat, würde ich mich über ein Code-Review freuen.
Hardware:
- ESP32
- 1,4" ST7789 Display
- BME280 Temperatur-Sensor
- 2x Led's
- mechanischer Taster (Pull-down hardwareseitig)
Gewünschte Funktion:
- Bei Stromzufuhr Ablauf einer Willkommens-Animation
- Wechsel in den Home-Bilschirm. Alle 30 Sekunden soll der aktuellste Wert des Temperatursensors angezeigt werden
- Bei Betätigung des Tasters: Wechsel des Bildschirms. Simulation eines Einschaltvorgangs einer Maschine. Die grüne LED geht an, dabei erhöhen sich 4 Werte bis der Druckwert Nr 3 (hier machen die Nummern Sinn, weil die in "echt" tatsächlich so bezeichnet werden. Da das Display so klein ist, gibt es keine 1) seinen max. Wert überschreitet. Dann wird der Maschinenlauf simuliert. Dabei nehmen zwei Werte ab, der Druckwert schwankt und Temperatur 3 erhöht sich, bis sie über ihren max. Wert ist. Zur Warnung wird der Wert gelb angezeigt, die grüne LED geht aus, die rote geht an, alle Werte fallen ab und nach kurzer Zeit wird eine Fehlermeldung angezeigt. Nach einer kurzen Wartezeit geht die rote LED aus, der Bildschirm wechselt in den Home-Bildschirm und zeigt wieder die aktuellen Werte an, bis der Taster erneut gedrückt wird.
Während der Simulation soll der Taster keinen Einfluss haben. Eine weitere Simulation soll nur ausgeführt werden, wenn aus dem Home-Bildschirm heraus der Taster gedrückt wird.
Ich habe das umgesetzt und einige Stunden problemlos laufen lassen.
Ich habe Fragen:
- Kann es aus irgendeinem Grund zu einem Überlauf des Speichers führen? Muss/soll ich den garbage collector manuell, zyklisch aufrufen? Ich sehe keinen Grund dazu, das soll aber nichts heißen
- Kann ich das `°` - Symbole, das ich mit `0xF8` darstellen kann, irgendwie in den String mit reinpacken?
Ansonsten, die Funktion, die den Maschinenlauf animiert ist etwas lang, ich sehe aber keinen sinnvollen Punkt um die aufzuteilen. Eventuell könnte man die Größe und Breite des Bildes noch abfragen, ob die Position nicht anhand festen Werten zu bestimmen. Bin über jede Kritik und Verbesserung dankbar.
Code: Alles auswählen
from time import sleep, ticks_ms, ticks_diff
from machine import Pin, SPI, I2C
from _thread import start_new_thread
from collections import deque
import st7789
import bme280
import vga2_8x16 as font
from polygone import POLYGONE
RST_PIN = 17
CS_PIN = 22
DC_PIN = 5
SCL_PIN = 32
SDA_PIN = 33
BUTTON_PIN = 25
LED_RED_PIN = 26
LED_GREEN_PIN = 27
HEIGHT = 135
WIDTH = 240
LOGO_BG = 0x5B94
#
# In milliseconds
UPDATE_CYCLE = 30 * 1e3
MAX_PRESSURE_2ND = 190
MAX_PRESSURE_3RD = 500
MAX_TEMPERATURE_2ND = 165
MAX_TEMPERATURE_3RD = 175
POLYGONE = [(int(x * 1.5), int(y * 1.2)) for x, y in POLYGONE]
class Monitor:
def __init__(self, display, led_red, led_green, sensor_value):
self.lcd = display
self.led_red = led_red
self.led_green = led_green
self.sensor_value = sensor_value
self.is_animation = False
self._temperature = None
@property
def temperature(self):
try:
_temperature = self.sensor_value.pop()
self._temperature = _temperature.split(" ")[0][:-1]
except IndexError:
pass
return self._temperature
def show_startup(self):
center = (HEIGHT - 117) // 2
self.lcd.jpg("Images/logo.jpg", 0, center, st7789.SLOW)
sleep(0.3)
for number in range(1, 6):
self.lcd.jpg(f"Images/Eng{number}.jpg", 0, center, st7789.FAST)
def show_home(self):
self.lcd.fill(LOGO_BG)
self.lcd.jpg("Images/home.jpg", 6, 0, st7789.SLOW)
self.lcd.text(font, "500 bar", 167, 83, st7789.BLACK, st7789.WHITE)
self.lcd.text(
font, f"{self.temperature} C", 167, 107, st7789.BLACK, st7789.WHITE
)
self.lcd.text(font, 0xF8, 200, 107, st7789.BLACK, st7789.WHITE)
def update_temperature(self):
self.lcd.text(
font, f"{self.temperature} C", 167, 107, st7789.BLACK, st7789.WHITE
)
self.lcd.text(font, 0xF8, 200, 107, st7789.BLACK, st7789.WHITE)
def control_animation(self, _):
if self.is_animation:
return
self.is_animation = True
def animate_machine_running(self):
self.led_green.on()
self.lcd.jpg("Images/pid.jpg", 0, 0, st7789.SLOW)
temperature_2 = temperature_3 = 20
pressure_2 = pressure_3 = 0
self.lcd.text(font, f"{pressure_2:.0f}bar", 14, 75, st7789.BLACK, st7789.WHITE)
self.lcd.text(
font, f"{temperature_2:.0f} C", 55, 112, st7789.BLACK, st7789.WHITE
)
self.lcd.text(font, 0xF8, 79, 112, st7789.BLACK, st7789.WHITE)
self.lcd.text(font, f"{pressure_3:.0f}bar", 133, 71, st7789.BLACK, st7789.WHITE)
self.lcd.text(
font, f"{temperature_3:.0f} C", 135, 105, st7789.BLACK, st7789.WHITE
)
self.lcd.text(font, 0xF8, 159, 105, st7789.BLACK, st7789.WHITE)
sleep(1)
run_up = True
while True:
if run_up:
pressure_3 += 31.5
pressure_2 += 11.7
temperature_2 += 9.3
temperature_3 += 9
else:
pressure_2 -= 1.5
temperature_2 -= 1
temperature_3 += 1
if temperature_3 > MAX_TEMPERATURE_3RD:
break
if pressure_3 > MAX_PRESSURE_3RD:
pressure_3 -= 1.5
else:
pressure_3 += 1
self.lcd.text(
font, f"{pressure_2:.0f}bar", 14, 75, st7789.BLACK, st7789.WHITE
)
self.lcd.text(
font, f"{temperature_2:.0f} C", 55, 112, st7789.BLACK, st7789.WHITE
)
self.lcd.text(font, 0xF8, 79, 112, st7789.BLACK, st7789.WHITE)
self.lcd.text(
font, f"{pressure_3:.0f}bar", 133, 71, st7789.BLACK, st7789.WHITE
)
self.lcd.text(
font, f"{temperature_3:.0f} C", 135, 105, st7789.BLACK, st7789.WHITE
)
self.lcd.text(font, 0xF8, 159, 105, st7789.BLACK, st7789.WHITE)
if pressure_3 > MAX_PRESSURE_3RD:
run_up = False
sleep(1)
self.lcd.fill_polygon(POLYGONE, 156, 111, st7789.YELLOW)
self.lcd.text(
font, f"{temperature_3 + 2:.0f} C", 135, 105, st7789.BLACK, st7789.YELLOW
)
self.led_green.off()
self.led_red.on()
for _ in range(5):
sleep(0.8)
pressure_3 -= 100
pressure_2 -= 33
temperature_2 -= 9
temperature_3 -= 8
self.lcd.text(
font, f"{pressure_2:.0f}bar", 14, 75, st7789.BLACK, st7789.WHITE
)
self.lcd.text(
font, f"{temperature_2:.0f} C", 55, 112, st7789.BLACK, st7789.WHITE
)
self.lcd.text(font, 0xF8, 79, 112, st7789.BLACK, st7789.WHITE)
self.lcd.text(
font, f"{pressure_3:.0f}bar", 133, 71, st7789.BLACK, st7789.WHITE
)
self.lcd.fill_polygon(POLYGONE, 156, 111, st7789.YELLOW)
self.lcd.text(
font, f"{temperature_3:.0f} C", 135, 105, st7789.BLACK, st7789.YELLOW
)
self.lcd.text(font, 0xF8, 159, 105, st7789.BLACK, st7789.YELLOW)
self.lcd.jpg("Images/Error.jpg", 0, 14, st7789.SLOW)
sleep(10)
self.led_red.off()
self.show_home()
self.is_animation = False
def read_temperature_sensor(bme, sensor_value):
while True:
try:
sensor_value.append(bme.temperature)
except IndexError:
# To ensure that the most up-to-date
# temperature is always available
sensor_value.pop()
sensor_value.append(bme.temperature)
sleep(30)
def main():
i2c = I2C(scl=Pin(SCL_PIN), sda=Pin(SDA_PIN), freq=10000)
bme = bme280.BME280(i2c=i2c)
sensor_value = deque((), 1)
button = Pin(BUTTON_PIN, Pin.IN)
led_green = Pin(LED_GREEN_PIN, Pin.OUT)
led_red = Pin(LED_RED_PIN, Pin.OUT)
led_green.off()
led_red.off()
spi = SPI(2, baudrate=40000000, polarity=0, phase=0)
display = st7789.ST7789(
spi,
HEIGHT,
WIDTH,
reset=Pin(RST_PIN, Pin.OUT),
cs=Pin(CS_PIN, Pin.OUT),
dc=Pin(DC_PIN, Pin.OUT),
)
display.init()
display.rotation(1)
display.fill(LOGO_BG)
start_new_thread(read_temperature_sensor, (bme, sensor_value))
monitor = Monitor(display, led_red, led_green, sensor_value)
monitor.show_startup()
sleep(2)
monitor.show_home()
button.irq(handler=monitor.control_animation, trigger=Pin.IRQ_RISING)
start = ticks_ms()
while True:
if not monitor.is_animation:
if ticks_diff(ticks_ms(), start) >= UPDATE_CYCLE:
monitor.update_temperature()
start = ticks_ms()
else:
monitor.animate_machine_running()
sleep(0.1)
if __name__ == "__main__":
main()
Dennis
