In diesem Teil erfährst du:
Okay, wir brauchen zusätzlich zum Display noch eine Möglichkeit, Eingaben zu machen. Wir wollen ja nicht immer nur einen Wert angezeigt bekommen, sondern uns aussuchen, was wir angezeigt bekommen wollen. Ich habe mich hier für einen Rotary Encoder entschieden. Damit kann man durch das Menü navigieren. Der, den ich ausgesucht habe, hat sogar noch einen Schalter mit eingebaut. Das Display, was ich nutze, hat gleich noch eine I2C-Adapterplatine mit angelötet. So können wir sogar noch einige Pins sparen (obwohl wir das in diesem Projekt nicht müssten).
Hier mein Schaltplan:
Für das Display und den Rotary Encoder braucht ihr noch weitere Bibliotheken, die ich aus Urheberrechtsgründen nicht bei mir hochladen möchte. Ihr könnt sie hier downloaden:
rotary_irq_esp.py
und rotary.py
esp8266_i2c_lcd.py
, lcd_api.py
Kopiert sie bei euch auf den ESP32 in das Verzeichnis /pyboard/lib
. Anschließend könnt ihr mit upip.install("micropython-eydam-prototyping-lcd-menu")
mein Modul installieren.
Danach könnt ihr einmal kurz probieren, ob alles funktioniert hat:
>>> import machine
>>> from esp8266_i2c_lcd import I2cLcd
>>> from rotary_irq_esp import RotaryIRQ
>>> i2c = machine.I2C(0, scl=machine.Pin(22), sda=machine.Pin(21))
>>> lcd = I2cLcd(i2c, 39, 2, 16)
>>> lcd.clear()
>>> lcd.putstr("Hello World") # "Hello World" should be displayed
>>> r = RotaryIRQ(18,19,0,10,False)
>>> r.value() # turn rotary
0
>>> r.value()
16
Okay. Um jetzt ein Menü auf dem Display darzustellen, müssen wir uns erst einmal eine Struktur überlegen. Ich habe mir folgendes ausgedacht (ich mache es mal auf Englisch, damit es später in den Dateien genau so aussieht. Ihr könnt es aber direkt auf Deutsch machen, wenn ihr wollt. Achtet aber darauf, dass, je nach Display, Umlaute eventuell nicht funktionieren). In der ersten Zeile steht immer der Menüeintrag, in der zweiten steht das, was in Klammern steht:
Um das darzustellen, erstellen wir uns die Datei menu.json
(siehe github) und kopieren sie auf den ESP32. Dann brauchen wir noch ein bisschen Code, um das Menü auch anzuzeigen. Legt euch dafür die Datei menu.py
mit folgendem Inhalt an:
import machine
import ep_lcd_menu
from rotary_irq_esp import RotaryIRQ
from esp8266_i2c_lcd import I2cLcd
def setup(temps, sm):
i2c = machine.I2C(0, scl=machine.Pin(22), sda=machine.Pin(21))
lcd = I2cLcd(i2c, 39, 2, 16)
lcd.clear()
r = RotaryIRQ(18, 19, 0, 10, False)
menu = ep_lcd_menu.menu_rot_enc(
menu_config_file="menu.json", display_type="1602", display=lcd, rotary=r, button_pin=5)
menu.load()
menu.render()
return menu
In der main.py
müsst ihr folgendes ergänzen:
import ep_logging
import ep_wifi
import ep_config
import heater_http
import onewire
import ds18x20
import machine
import ubinascii
import statemachine
import menu
import gc
wifi = ep_wifi.wifi("./network_config.json", max_time_wait_for_connect=10)
wlan, ssid, bssid = wifi.connect()
ip = wlan.ifconfig()[0]
logger = ep_logging.colored_logger(appname="main")
logger.notice("WiFi connected")
logger_http = ep_logging.colored_logger(appname="http")
ow = onewire.OneWire(machine.Pin(4))
ds = ds18x20.DS18X20(ow)
ht_config = ep_config.config("ht_config.json")
ht_config.load()
thresh = ht_config.get("")
ds_config = ep_config.config("ds_config.json")
ds_config.load()
temps = ds_config.get("")
get_temp = lambda name: temps[name]["value"] if (name in temps) and ("value" in temps[name]) else 0
sm = statemachine.setup(
get_temp,
lambda name: thresh.get(name, 0)
)
sm.init()
sm.step_until_stationary()
def read_temps(timer, ds, temps, sm):
ds.convert_temp()
for key in temps:
temps[key]["value"] = ds.read_temp(ubinascii.unhexlify(temps[key]["id"]))
sm.step()
gc.collect()
tim_ds = machine.Timer(0)
tim_ds.init(mode=machine.Timer.PERIODIC, period=5000, callback=lambda timer: read_temps(timer, ds, temps, sm))
http_server = heater_http.setup(wlan, logger_http, ds)
http_server.start()
m = menu.setup()
Wenn ihr den ESP32 jetzt neu startet, sollte auf dem Display das Menü angezeigt werden. Mit dem Rotaty Encoder könnt ihr durch das Menü navigieren und mit einem Klick auf den Drehknopf könnt ihr den Menüpunkt betreten. Es werden aber noch keine Werte angezeigt. In der menu.json
haben wir definiert, welche Funktionen aufgerufen werden sollen, um in der zweiten Zeile etwas anzuzeigen:
Wir müssen die Funktion print_T_Oven
(und alle anderen Funktionen) noch registrieren. Ergänzt dazu folgendes:
import ep_logging
import ep_wifi
import ep_config
import heater_http
import onewire
import ds18x20
import machine
import ubinascii
import statemachine
import menu
import gc
wifi = ep_wifi.wifi("./network_config.json", max_time_wait_for_connect=10)
wlan, ssid, bssid = wifi.connect()
ip = wlan.ifconfig()[0]
logger = ep_logging.colored_logger(appname="main")
logger.notice("WiFi connected")
logger_http = ep_logging.colored_logger(appname="http")
ow = onewire.OneWire(machine.Pin(4))
ds = ds18x20.DS18X20(ow)
ht_config = ep_config.config("ht_config.json")
ht_config.load()
thresh = ht_config.get("")
ds_config = ep_config.config("ds_config.json")
ds_config.load()
temps = ds_config.get("")
get_temp = lambda name: temps[name]["value"] if (name in temps) and ("value" in temps[name]) else 0
sm = statemachine.setup(
get_temp,
lambda name: thresh.get(name, 0)
)
sm.init()
sm.step_until_stationary()
def read_temps(timer, ds, temps, sm):
ds.convert_temp()
for key in temps:
temps[key]["value"] = ds.read_temp(ubinascii.unhexlify(temps[key]["id"]))
sm.step()
gc.collect()
tim_ds = machine.Timer(0)
tim_ds.init(mode=machine.Timer.PERIODIC, period=5000, callback=lambda timer: read_temps(timer, ds, temps, sm))
http_server = heater_http.setup(wlan, logger_http, ds)
http_server.start()
m = menu.setup(get_temp, sm)
m.display_funcs["print_ssid"] = lambda: "{}".format(ssid)
m.display_funcs["print_ip"] = lambda: "{}".format(ip)
m.display_funcs["print_rssi"] = lambda: "{} db".format(wlan.status("rssi")) if wlan.isconnected() else "---"
Bzw.:
import machine
import ep_lcd_menu
from rotary_irq_esp import RotaryIRQ
from esp8266_i2c_lcd import I2cLcd
import esp32
import gc
def setup(temps, sm):
i2c = machine.I2C(0, scl=machine.Pin(22), sda=machine.Pin(21))
lcd = I2cLcd(i2c, 39, 2, 16)
lcd.clear()
r = RotaryIRQ(18, 19, 0, 10, False)
menu = ep_lcd_menu.menu_rot_enc(
menu_config_file="menu.json", display_type="1602", display=lcd, rotary=r, button_pin=5)
menu.display_funcs = {
"print_T_Oven": lambda: "{:.2f} C".format(temps("T_Oven")),
"print_T_TankU": lambda: "{:.2f} C".format(temps("T_TankU")),
"print_T_TankL": lambda: "{:.2f} C".format(temps("T_TankL")),
"print_state": lambda: "{}".format(sm.state),
"print_cpu_temp": lambda: "{:.2f} C".format((esp32.raw_temperature()-32)*5/9),
"print_ram": lambda: "{:.1f}/{:.1f}kB".format(gc.mem_free()/1024, (gc.mem_alloc()+gc.mem_free())/1024),
}
menu.load()
menu.render()
return menu
Wir könnten auch alles in die main.py
schreiben, ich packe aber so viel wie möglich in die menu.py
, damit die main.py
möglichst übersichtlich bleibt.
Damit ist unser Menü erstmal fertig. Du kannst es gern noch erweitern, wenn du willst. Im nächsten Kapitel erfährst du, wie du die Daten per MQTT an einen MQTT-Broker sendest.
Eydam-Prototyping
Saccasner Straße 19
03096 Schmogrow-Fehrow
Germany