Es werden von chinesischen Herstellern und Händlern diverse günstige AC/DC-Wandler angeboten. Die Frage ist wie es um Störspannungen auf der Netz- und Niederspannungsseite bestellt. Kürzlich bin ich auf Schaltungsvorschläge zur Entstörung dieser kleinen Netzteile gestoßen. Das habe ich mir bei Hi-Link einmal näher angesehen:

und die entsprechenden Bauteileempfehlungen:

Hi-Link schlägt für alle Modelle diese Entstörmaßnahme vor.

Wobei ich aber auch andere Vorschläge gefunden habe. So findet sich bei FEIYANG für das HKL-5M05 Modul diese asymmetrische Entstörung:

DC/DC-Wandler

Für DC/DC-Wandler habe ich sogar diesen aufwändigen Vorschlag gefunden (https://de.aliexpress.com/item/4000418841792.html?spm=a2g0o.store_pc_groupList.8148356.2.657672e6qpr5vC):

Bauteile

Das der ADC der ESP’s ziemlich umbrauchbar ist ist inzwischen hinlänglich bekannt. Allerdings benötigt man ja nicht immer eine hohe Genauigkeit. Zum Ein- und Ausschalten eines Lüfters kommt es meist ein 1, 2 Grad nicht an. Genau das ist meine Anwendung. Ich möchte einen Lüfter bei ca 45 °C ein- und bei ca. 35 °C wieder ausschalten. Dazu bedarf es keiner exakten Werte, sondern nur Schwellwerte, die ggf. per Test ermittelt werden können. Genauigkeit und Linearität des ADC spielen hier keine Rolle. Deshalb scheint mir der intere ADC des ESP32 dafür geeignet zu sein. Das möchte ich hier ausprobieren.

Hier noch ein paar interessante Infos über den ADC aus dem Programmierhandbuch von Espressif (Link unten):

Rauschen minimieren

Der ESP32 ADC kann empfindlich auf Rauschen reagieren, was zu großen Diskrepanzen in den ADC-Messwerten führen kann. Um das Rauschen zu minimieren, kann der Anwender einen 0,1uF-Kondensator an das verwendete ADC-Eingangspad anschließen. Multisampling kann auch verwendet werden, um die Auswirkungen des Rauschens weiter zu minimieren.

ADC-Kalibrierung

Die API esp_adc_cal/include/esp_adc_cal.h bietet Funktionen zur Korrektur von Unterschieden in den gemessenen Spannungen, die durch Variation der ADC-Referenzspannungen (Vref) zwischen den Chips verursacht werden. Per Design ist die ADC-Referenzspannung 1100mV, die tatsächliche Referenzspannung kann jedoch zwischen 1000mV und 1200mV bei verschiedenen ESP32 liegen.

Die Kurve von randomnerdtutorials.com zeigt auch noch eine ausgeprägte Nichtlinearität im oberen Bereich:

Test

Für den Test habe ich eine kleine Platine gebaut. Sie ist für einen M5Stack C bzw. M5Stack C Plus vorgesehen. Sie enthält eine Reihe Vorwiderstände, die mittels Jumper umgesteckt werden können, einen 3poligen Sockel für den NTC. Der parallele Sockel ermöglicht es die Spannung am NTC direkt zu messen.

Um die Temperatur am NTC zu messen habe ich ein Termoelement daran montiert.

Für den Test habe ich eine Heissluftpistole benutzt und für die Temperatureinstellung den Abstand zum NTC variiert.

Diese Schaltung habe ich angewendet:

Meine Tests haben die folgenden Werte erbracht.

  • 21,4 °C – 2850
  • 35 °C – 2200
  • 45 °C – 1750
  • 50 °C – 1500
  • 60 °C – 1150

Dabei muss man berücksichtigen, dass die Messwerte des ADC schwanken (siehe oben).

Software:

Dieses Programm ließt die Temperatur und reagiert auf das Über- und Unterschreiten der Grenzwerte, die ich hier als Raw-Werte des ADC eingesetzt habe.

Das die Abfragen in einer Interrupt-Service-Routine laufen hat mit diesem Thema hier nichts zu tun. Sie gehören üblicherweise in die Mainloop.

Links:

Schraubendreher u.ä.

Hier habe ich eine Aufstellung gemacht welche Werkzeuge für Schrauben von M2, M2,5 und M3 sinnvoll sind um alle Erfordernisse abzudecken:

  • Imbus
    • M2 => SW1,5
    • M2,5 => SW2,0
    • M3 => SW2,5
  • 6-Kant Mutter und Schraubenkopf
    • M2 SW4
    • M2,5 SW5
    • M3 SW5,5
  • Kreuzschlitz (PH)
    • M2 PH1
    • M2,5 PH1
    • M3 PH1
  • Protzi (PZ)
    • M2 PZ1
    • M2,5 PZ1
    • M3 PZ2
  • Schlitz
    • M2 0,5×3,8
    • M2,5 0,6×4,5
    • M3 0,8×5,5
  • Torx
    • M2 T6
    • M2,5 T8
    • M3 T10
  • Maul- und Ringschlüssel
    • M2 SW4
    • M2,5 SW5
    • M3 SW5,5

Zangen und Greifwerkzeuge

  • Seitenschneider
  • Kombizange
  • Spitzzange
  • Pinzetten
  • Abisolierer

Lötutensilien

Fixierungen

Als Basis für die PEL035 dient das Chinamodul XY-FZ35. Dieses Modul kann Spannungen von 1,5 V ~ 25 V und Ströme bis 5A bei einer maximalen Belastung von 35W verarbeiten. Die Einstellung des Laststromes erfolgt mittels Drehimpulsgeber an der Frontplatte oder über eine serielle Schnittstelle. Siehe: https://www.peters-bastelkiste.de/elektronische-last-xy-fz35/

Für die drahtlose Steuerung kommt ein M5ATOM Lite zum Einsatz. Eine ADC-Unit zur Messung der Spannung am Lasteingang. Das FZ-35-Modul ermittelt diese Spannung zwar auch, verwendet sie aber nur intern. Ausserhalb steht sie nicht zur Verfügung. Die Lüftersteuerung erfolgt vom M5ATOM aus. Ein Spannungsteiler aus Widerstand und NTC liefert eine der Temperatur umgekehrt proportinale Spannung die vom internen ADC des M5ATOM gemessen wird. Dieser Wert wird zur 2-Punkt-Steuerung des Lüfters herangezogen (siehe https://www.peters-bastelkiste.de/temperaturmessung-mit-esp32-und-ntc/).

Netzteil

Das Netzteil liefert 5 Volt für den M5Atom und 12 Volt für den Lüfter und das FZ-35-Modul. Es ist ganz einfach mit AC/DC-Modulen aufgebaut. Allerdings habe ich es noch um einen Tiefpassfilter zum Netz hin und Kondensatoren am Ausgang ergänzt. Diese Maßnahmen werden von einigen Anbietern vorgeschlagen. Hi-Link schlägt sogar eine stromkompensierte Drossel vor.

M5Atom Adapter

Der M5ATOM bekommt einen Adapter, der zum Einen die Befestigung an der Frontplatte ermöglicht, zum Anderen die Anschlüsse des M5ATOM auf einer 14-poligen 2,54mm Stiftleiste sammelt.

PINBedeutung
1Ground
2Ground
3+ 3,3 Volt vom M5ATOM
4+ 3,3 Volt vom M5ATOM
5+ 5 Volt – Stromversorgung für M5ATOM
6+ 5 Volt – Stromversorgung für M5ATOM
7GPIO 23
8GPIO 19
9GPIO 33 – ADC1-5
10GPIO 22
11GPIO 21 – TX
12GPIO 25 – RX
13Grove – SCL
14Grove – SDA

Platine für den Adapter

Erste Version der Platine
V. 1.1 mit Lötads für 0,1µF Kondensator am ADC Eingang unten rechts

Steuerung

Die Steuerungsplatine dient in erster Linie der Signalverteilung zwischen den verschiedenen Baugruppen. Weiterhin enthält sie den NTC zur Temperaturmessung und einen Transistor zum Schalten des Lüfters.

Die Platine

Inzwischen habe ich eine Platine entworfen und fertigen lassen.

Fehler auf der Platine

  • Eine eventuelle Pegelanpassung der RX/TX-Signale zwischen FZ35 und M5ATOM fehlt.
  • Positive Spannung für FZ35 an PIN 4 der 5-poligen Verbindung fehlt.
Die korrigierte Version 1.1

Die Geschichte von einem der auszog ein Abenteuer zu erleben.

Elementare Grundkenntnisse vom Netzwerk sind mir ja bekannt. Meine LAN-Verkabelung habe ich alleine hinbekommen. Das beschränkte sich aber überwiegend darauf Stecker in Buchsen zu stecken, Kabel zu verlegen und die Kabelenden in die richtigen Kontakte zu pressen.

Mit der Softwareseite, geschweige denn WLAN habe ich mich bisher nicht auseinander gesetzt. Nun möchte ich aber, dass die M5Stack Geräte über WLAN kommunizieren. Dafür sind sie schließlich gemacht.

Die UIFlow-IDE bietet dazu unter Blockly nur sehr begrenzte Möglichkeiten. Also wenn es über HTTP gehen soll. MQTT z.B. funktioniert gut. Die HTTP-Blöcke habe ich aber noch nicht verstanden. Micropython hingegen bietet da eine ganze Menge.

Es sind offenbar mehre Schritte erforderlich:

  • Mit dem Netzwerk verbinden
  • Ein Socket installieren
  • Ein Übertragungsprotokoll installieren

Mit einem Netzwerk verbinden.

Meistens verbindet sich ein M5Stack Gerät gleich nach dem Einschalten mit dem Netzwerk, da diese Verbindung für die Programmierung benötigt wird.

<< Ausprobieren, ob auch bei USB-Betrieb, bzw. wenn eine App läuft eine WLAN-Verbindung hergestellt wird. >>

Damit ein eine WLAN-Verbindung eingerichtet oder eine vorhandene erkannt wird ist diese der Software bekannt zu machen. Dazu dient die Library network.

# network Library importieren
>>> import network

# WLAN Interface erzeugen und aktivieren
>>> wlan = network.WLAN(network.STA_IF)
>>> wlan.active(True)

# Mit Wlan verbinden
ssid = 'REPLACE_WITH_YOUR_SSID'
password = 'REPLACE_WITH_YOUR_PASSWORD'
wlan.connect(ssid, password)

# auf bestehende Verbindung prüfen
>>> wlan.isconnected()
True
# Oder auf Verbindung warten und ausgeben
>>> while wlan.isconnected() == False:
>>>   pass
>>> print('Connection successful')
>>> print(station.ifconfig())

# WLAN Daten abfragen (Geräte-IP, Netzwerkmaske, Gateway, DNS-Server)
>>> wlan.ifconfig()
('192.168.5.89', '255.255.255.0', '192.168.5.1', '192.168.5.1')

# Eigene IP-Adresse ermitteln
>>> netzwerk = wlan.ifconfig()
>>> netzwerk
('192.168.5.89', '255.255.255.0', '192.168.5.1', '192.168.5.1')
>>> netzwerk[0]
'192.168.5.89'
# So gehts am Kürzesten
>>> wlan.ifconfig()[0]
'192.168.5.89'

# Die vorhandenen Accesspoint suchen
>>> wlan.scan()
[(b'ESP_9235A1', b'P\x02\x91\x925\xa1', 1, -50, 0, False), (b'Kapest-Fritz', b'\x94\xb9~\x8d<e', 1, -55, 3, False), (b'Kapest-Fritz', b'\x9c\xc7\xa6\x16\xe51', 1, -77, 4, False)]

# WLAN Interface beenden
>>> wlan.active(False)

# MAC Adresse ermitteln
>>> wlan.config('mac')
b'\x94\xb9~\x8b\xb9X'

Nun kennt das Netzwerk meinen M5Stack und dieser das Netzwerk zu dem er jetzt gehört.

In mehrere bekannte Netzwerke automatisch einloggen.

Die Überschrift ist etwas irreführend. Natürlich kann sich der M5Stack immer nur in ein Netzwerk zur Zeit einloggen, aber es gibt vielleicht mehrere räumlich getrennte Netzwerke in die es sich automatisch einloggen soll, so wie wir das vom Handy kennen. Z.B. ins WLAN bei mir zu Hause oder in das des Attraktor, je nachdem, wo ich mich gerade befinde.

# zuerst immer ein WLAN erzeugen sonst geht nichts.
>>> import network
>>> wlan = network.WLAN(network.STA_IF)

# nun kann ich nach WLAN-AP's suchen
>>> wlan.scan()
[(b'ESP_9235A1', b'P\x02\x91\x925\xa1', 1, -50, 0, False), (b'Kapest-Fritz', b'\x94\xb9~\x8d<e', 1, -55, 3, False), (b'Kapest-Fritz', b'\x9c\xc7\xa6\x16\xe51', 1, -77, 4, False)]

# Das sieht nicht sehr übersichtlich aus. Mal sehen ob Micropython das auch so sieht:
>>> wlans = wlan.scan()
>>> wlans
[(b'ESP_9235A1', b'P\x02\x91\x925\xa1', 1, -45, 0, False), (b'Kapest-Fritz', b'\x9c\xc7\xa6\x16\xe51', 1, -77, 4, False)]
>>> type(wlans)
<class 'list'>

# Es wird also eine Liste mit den Daten der AP's in Tupels zurückgegeben.
# Ich benötige nur den String der SSID.

# Der versuch die AP-Tupel in einer Schleife auszulesen scheitert.
>>> wlans
[(b'ESP_9235A1', b'P\x02\x91\x925\xa1', 1, -45, 0, False), (b'Kapest-Fritz', b'\x9c\xc7\xa6\x16\xe51', 1, -77, 4, False)]

# So lassen sich alle erreichbaren AP's auflisten:
>>> for i in wlan.scan():
    print(i[0].decode("utf-8"))
    
ESP_9235A1
Kapest-Fritz
WILLY.TEL-71IU1DHQNW
FRITZ!Box 7560 LY
Brian
WLAN-807195
WLAN-372270
Telekom_FON
o2-WLAN79

# Eine einfache Version für Home und Attraktor sähe dann so aus:
>>> for i in wlan.scan():
    if (i[0].decode("utf-8")) == "Kapest-Fritz":
        print("Zu Hause")
    elif (i[0].decode("utf-8")) == "attraktor":
        print("Attraktor")
WARNING:root:Unexpected echo. Expected b'\r\n', got b''
# Es wird \r\n also eine neue Zeile Schaltung vermisst. Funktioniert ansonsten aber:
Zu Hause

''' Nachdem ich mit .decode("utf-8", errors='ignore') herumgespielt habe aber weiterhin diese Warnung erhalten habe. Habe ich aufgegeben und beschlossen die Warnung zu ignorieren. Seitdem ist sie weg.
'''
# Stefan May gab den Tip es mit "ascii" anstatt "utf-8" zu versuchen. Das klappt auch:
>>> for i in wlan.scan():
    if (i[0].decode("ascii")) == "Kapest-Fritz":
        print("Zu Hause")
    elif (i[0].decode("ascii")) == "attraktor":
        print("Attraktor")
        
Zu Hause

Einen Socket einrichten.

Ein Übertragungsprotokoll installieren

Übersetzung des entsprechenden Artikels von Lukasmaximus89 auf Hackster.io aus dem Englischen mit DeepL.com.

Link zum Orginal: https://www.hackster.io/lukasmaximus89/m5stack-micropython-simple-web-server-20a4c4

Verwenden Sie MicroPython, um Ihren M5Stack mit WiFi oder ein Gerät mit AP zu verbinden und eine einfache Webseite zu erstellen, um einige Funktionen des M5Stack zu steuern.

M5Stack MicroPython Simple Web Server

In diesem Projekt verwendete Dinge

Hardware-Komponenten

M5Stack Gerät: https://www.hackster.io/m5stack/products/esp32-basic-core-iot-development-kit?ref=project-20a4c4

Software-Apps und Online-Dienste

Micropython: https://www.hackster.io/micropython/products/micropython?ref=project-20a4c4

Visual Studio Code: https://www.hackster.io/microsoft/products/vs-code?ref=project-20a4c4

Geschichte

ESP32 ist fast zum De-facto-Standard für die IoT-Entwicklung geworden und es sieht nicht so aus, als würde sich das ändern. Egal, ob wir unseren ESP32-basierten M5Stack für die Automatisierung unseres Hauses, die Überwachung unserer Haustiere oder was auch immer Sie mit Ihrem M5Stack machen möchten, wir könnten eine Art Schnittstelle verwenden, auf die wir sowohl über einen Computer als auch über ein Mobiltelefon zugreifen können.

Der einfachste Weg, dies zu tun, ist das Hosten einer einfachen Webseite auf dem M5Stack mit Schaltflächen und Textfeldern, die die Hardware des M5Stack ansteuern und auch Anzeigen seines Verhaltens anzeigen können. Dabei können wir auch einige Grundlagen über Server, Clients und andere Netzwerkterminologie lernen.

Zu Beginn benötigen wir eine MicroPython-Firmware, die wir auf unser Gerät flashen müssen. Zum Zeitpunkt des Schreibens wird die Uiflow-Version 1.3.2 empfohlen. Flashen Sie Ihr Gerät mit dem Programm M5Burner, das Sie im Download-Bereich der M5Stack-Website finden. Wenn der Brenner aus irgendeinem Grund nicht funktioniert, können Sie immer das esptool aus der Kommandozeile verwenden, um es zu flashen.

Sobald Sie die Firmware geflasht haben, müssen Sie sich entscheiden, welche IDE Sie verwenden möchten, um den M5Stack in MicroPython zu programmieren. Es gibt Uiflow, unsere Online-Plattform für die Programmierung mit Blöcken und MicroPython (in diesem Tutorial werden wir nur die Python-Seite verwenden) oder unser neues Plugin für vscode. Sehen Sie hier, wie Sie es einrichten können.

Sobald Sie sich in der MicroPython-IDE Ihrer Wahl eingerichtet haben, können wir mit dem Schreiben des Programms beginnen, aber zuerst wollen wir versuchen, ein wenig über die Server-Client-Beziehung zu verstehen.

Sie denken bei einem Server vielleicht an einen großen, sperrigen, leistungsstarken Computer, der in einem supergekühlten Rechenzentrum untergebracht ist, aber tatsächlich kann auch ein so winziges Gerät wie Ihr M5Stack ein Server sein, der eine Website hostet. Wenn wir Ihren M5Stack kurz an Ihren Router anschließen, wird ihm eine IP-Adresse zugewiesen. Sie müssen Ihre IP-Adresse kennen, um sie in den Code einzugeben und auch um sie in den Browser auf Ihrem Computer einzugeben, um auf die auf dem M5Stack gehostete Website zuzugreifen. Der M5Stack fungiert als Webserver, der HTTP (Hyper Text Transfer Protocol) verwendet, ein Protokoll zur Weiterleitung von Webseiten, das Port 80 verwendet, um eine Kopie dieser Webseite jedem anderen Gerät (dem Client) zu zeigen, das eine Anfrage an seine IP-Adresse sendet. Um mit dem Gerät zu interagieren, setzen wir einige Schaltflächen auf der Seite im html. Wenn diese Schaltflächen gedrückt werden, wird eine http-Anfrage an das Gerät gesendet, das dann die RGB-Balken ein- oder ausschaltet oder den Lautsprecher piepsen lässt. Werfen wir einen Blick auf den Code. Hier importieren wir alle notwendigen Bibliotheken.

from m5stack import *  
from uiflow import *  
from m5ui import *  
import network ##only import if you want to connect to M5Stack AP
import wifiCfg  
import socket  

Hier setzen wir eine Variable für den Zustand der RGB-LED-Balken.

state = 0

Richten Sie eine Funktion zur Anzeige der Webseite ein.

#function for displaying the html   
def web_page():  
    if state == 0:  
        led_state="Off"  
    else:  
        led_state="On"  
    
 html = """<html><head> <title>M5Stack Web Server</title> <meta name="viewport" content="width=device-width, initial-scale=1">  
 <link rel="icon" href="data:,"> <style>html{font-family: Comic Sans MS; display:inline-block; margin: 0px auto; text-align: center;}  
 h1{color: #0F3376; padding: 2vh;}p{font-size: 1.5rem;}.button{display: inline-block; background-color: #0000FF; border: none;   
 border-radius: 4px; color: white; padding: 16px 40px; text-decoration: none; font-size: 40px; margin: 2px; cursor: pointer;}  
 .button2{background-color: #ff0000;}.button3{background-color: #ff00ff</style></head><body> <h1>M5Stack Web Server</h1>   
 <p>state: <strong>""" + str(state) + """</strong></p><p><a href="/?led=on"><button class="button">ON</button></a></p>  
 <p><a href="/?btn=on"><button class="button button3">Speaker</button></a></p>  
 <p><a href="/?led=off"><button class="button button2">OFF</button></a></p>  
 </html>"""  
 return html  

Weisen Sie die ifconfig-Funktion einer Variablen zu, damit wir unsere M5Stacks IP-Adresse auf dem Bildschirm ausgeben können.

ip = wifiCfg.wlan_sta.ifconfig()  

Erstellen Sie einige Beschriftungen, um einige Statusmeldungen auf dem M5Stack-Bildschirm anzuzeigen.

label1 = M5TextBox(0, 0, "Text", lcd.FONT_Default,0xFFFFFF, rotate=0)  
label2 = M5TextBox(0, 12, "Text", lcd.FONT_Default,0xFFFFFF, rotate=0)  
label3 = M5TextBox(0, 24, "Text", lcd.FONT_Default,0xFFFFFF, rotate=0)  
label4 = M5TextBox(0, 50, "Text", lcd.FONT_Default,0xFFFFFF, rotate=0)  
label5 = M5TextBox(120, 200, "Text", lcd.FONT_Default,0xFFFFFF, rotate=0)  

Geben Sie Ihr WiFi-Netzwerk und Passwort ein und richten Sie die Steckdose ein. HINWEIS: Lassen Sie die Zeichenfolge „Geben Sie Ihre IP hier ein, sobald Sie sie kennen“ leer, führen Sie das Programm einmal aus und geben Sie dann, sobald Sie die IP-Adresse auf dem Bildschirm Ihres M5Stack sehen, diese in dieses Feld ein.

response = None  
wifiCfg.doConnect('yournetwork', 'yourpassword')  
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  
s.bind(('enter your IP here once you know it', 80))  
s.listen(5)  

Wenn Sie Ihren M5Stack nicht mit dem Internet verbinden wollen und lieber

mit dem AP des Geräts verbinden möchten, entfernen Sie die Zeile wifiCfg und ersetzen Sie sie durch

ap = network.WLAN(network.AP_IF)
ap.active(True)
ap.config(essid='ESP32')
ap.config(authmode=3, password='123456789') 

Bei Verbindung IP-Adresse anzeigen.

if wifiCfg.wlan_sta.isconnected():  
    label1.setText('wifi connected')  
    label2.setText('Your IP Address is: ' + str(ip[0]))  
else:  
    label1.setText('wifi not connected')  
    wait_ms(2)  

Hauptschleife, richten Sie die http-Anfragen und Statusmeldungen ein.

while True:  
    conn, addr = s.accept()  
    request = conn.recv(1024)  
    request = str(request)  
    label4.setText('Content = %s' % request)  
    label3.setText('Got a connection from %s' % str(addr))  
    led_on = request.find('/?led=on')  
    led_off = request.find('/?led=off')  
    btn_press = request.find('/?btn=on')  

Prüfen Sie, ob die http-Anfrage empfangen wurde, wenn ja, schalten Sie die LED oder den Lautsprecher ein/aus.

    if led_on == 6:  
        state = 1  
        label5.setText('LED ON')  
        rgb.setColorAll(0xFF0000)  
    if led_off == 6:  
        state = 0  
        label5.setText('LED OFF')  
        rgb.setColorAll(0x000000)  
    if btn_press == 6:  
        speaker.tone(400,200)  
    response = web_page()  
    conn.send('HTTP/1.1 200 OK\n')  
    conn.send('Content-Type: text/html\n')  
    conn.send('Connection: close\n\n')  
    conn.sendall(response)  
    conn.close()      

Und das ist alles, was es zu tun gibt. Sie können dieses Tutorial auch mit demjenigen kombinieren, das ich zuvor für MIT APP Inventor geschrieben habe, um Ihren M5Stack über eine App Inventor-App zu steuern, die auf http-Anfragen antwortet. Ich hoffe, dieses Tutorial hat Ihnen gefallen, bleiben Sie dran für mehr.

Code

M5Stack Webserver

MicroPython
Code, um den Webserver einzurichten, die IP des Host-Geräts anzuzeigen und einige Statusmeldungen auf dem M5Stack zu drucken

from m5stack import *
from m5ui import *
from uiflow import *
import network

try:
    import usocket as socket
except:
    import socket

def web_page():
  html = """<html><head> <title>M5Stack Web Server</title> <meta name        ="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" href="data:,"> <style>html{font-family: Comic Sans MS;    display:inline-block; margin: 0px auto; text-align: center;}
  h1{color: #0F3376; padding: 2vh;}p{font-size: 1.5rem;}.button{display:     inline-block; background-color: #0000FF; border: none; 
  border-radius: 4px; color: white; padding: 16px 40px; text-decoration:     none; font-size: 40px; margin: 2px; cursor: pointer;}
  .button2{background-color: #ff0000;}.button3{background-color: #ff00ff     </style></head><body> <h1>M5Stack Web Server</h1> 
  <p>state: <strong>""" + str(state) + """</strong></p><p><a href="/?led     =on"><button class="button">ON</button></a></p>
  <p>Button State: <strong>""" + str(btnstate) + """</strong></p><p><a href   ="/?btn=on"><button class="button button3">Speaker</button></a></p>
  <p><a href="/?led=off"><button class="button button2">OFF</button></a></p   >
  </html>"""
  return html


ap = network.WLAN(network.AP_IF)
ap.active(True)
ap.config(essid='M5Stack')
ap.config(authmode=3, password='123456789')
lcd.clear()

response = None
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('192.168.4.1',80))
s.listen(5)

while True:
    conn, addr = s.accept()
    request = conn.recv(1024)
    request = str(request)
    print ('Content = %s' % request)
    lcd.print('Content = %s' % request,0,50,0xffffff)
    if ap.isconnected() == True:
        lcd.print('connected',0,0,0xffffff)
    else:
        lcd.print('not connected',0,0,0xffffff)
    response = web_page()
    conn.send('HTTP/1.1 200 OK\n')
    conn.send('Content-Type: text/html\n')
    conn.send('Connection: close\n\n')
    conn.sendall(response)
    conn.close()

M5Stack Acess Point Webserver

MicroPython
Richten Sie Ihren M5Stack als Zugangspunkt ein und erlauben Sie Geräten den Zugriff auf eine darauf gehostete Webseite

from m5stack import *
from m5ui import *
from uiflow import *
import network

try:
    import usocket as socket
except:
    import socket

def web_page():
  html = """<html><head> <title>M5Stack Web Server</title> <meta name        ="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" href="data:,"> <style>html{font-family: Comic Sans MS;    display:inline-block; margin: 0px auto; text-align: center;}
  h1{color: #0F3376; padding: 2vh;}p{font-size: 1.5rem;}.button{display:     inline-block; background-color: #0000FF; border: none; 
  border-radius: 4px; color: white; padding: 16px 40px; text-decoration:     none; font-size: 40px; margin: 2px; cursor: pointer;}
  .button2{background-color: #ff0000;}.button3{background-color: #ff00ff     </style></head><body> <h1>M5Stack Web Server</h1> 
  <p>state: <strong>""" + str(state) + """</strong></p><p><a href="/?led     =on"><button class="button">ON</button></a></p>
  <p>Button State: <strong>""" + str(btnstate) + """</strong></p><p><a href   ="/?btn=on"><button class="button button3">Speaker</button></a></p>
  <p><a href="/?led=off"><button class="button button2">OFF</button></a></p   >
  </html>"""
  return html


ap = network.WLAN(network.AP_IF)
ap.active(True)
ap.config(essid='M5Stack')
ap.config(authmode=3, password='123456789')
lcd.clear()

response = None
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('192.168.4.1',80))
s.listen(5)

while True:
    conn, addr = s.accept()
    request = conn.recv(1024)
    request = str(request)
    print ('Content = %s' % request)
    lcd.print('Content = %s' % request,0,50,0xffffff)
    if ap.isconnected() == True:
        lcd.print('connected',0,0,0xffffff)
    else:
        lcd.print('not connected',0,0,0xffffff)
    response = web_page()
    conn.send('HTTP/1.1 200 OK\n')
    conn.send('Content-Type: text/html\n')
    conn.send('Connection: close\n\n')
    conn.sendall(response)
    conn.close()
So ähnlich soll das Systemgehäuse aussehen.

Das Gehäuse soll aus 3mm MDF/HDF oder Plexiglas gefertigt werden. Die möglichen Größen sollen in einem Raster liegen. Dadurch werden die Gehäuse stapelbar. Die Gehäuse sind so gestaltet, dass die Kühlluft von unten oder vorne ins Gehäuse strömt und nach hinten abgegeben wird. Die Gestaltung des Gehäuses verhindert, dass warme Luft von hinten in die Kühlluftzufuhr gelangen kann.

Material:

  • MDF/HDF 3mm
  • Pexiglas 3mm
  • andere Kunststoffe 3mm – sofern sie mit dem Lasercutter geschnitten werden können.

Mindestabmaße für ein Raster.

Damit mehrere Gehäuse über- und nebeneinander angeordnet werden können ist es erforderlich ihre Größen durch ein Raster festzulegen. Die Rastergrößen machen mir z.Z. noch Probleme. Für das Tiefenraster habe ich mich auf 200 mm, 250 mm und 300 mm festgelegt. Für das Breiten- und Höhenraster tue ich mich noch schwer ein Maß zu finden. Es gibt Lösungen für eher flache und breite Gehäuse oder hohe und schmale Gehäuse. Die goldene Mitte habe ich bisher noch nicht gefunden.

Rasterentschluß: Breite 100/50 mm, Höhe 135 mm

100 mm, 150 mm, 200 mm, 250 mm, 300 mm, 400 mm, 500 mm (passt für 19″ Baugruppenträger – 482,6 x 133,35 mm)

Höhenraster:

Das Höhenraster sollte auf der einen Seite flache Gehäuse ermöglichen, auf der anderen Seite aber auch nicht zu sehr hohen Gehäusen führen.

Wahrscheinlich werden Höhen von 2/3 – 1 – 4/3 angemessen sein.

  • 1 – 2/3 – 4/3 – 1/2 – 1,5 – 5/3 – 2
  • 100: 66,7(50,7) – 133,3(117,3)
  • 125: 83,3(67,3) – 166,7(150,7)
  • 135: 90(74) – 180(164) – 67,5(51,5) – 209(193) – 225(209) – 270(254)
  • 67,5(51,5) – 90(74) – 135(119) – 180(164) – 209(193) – 225(209) – 270(254)

Bezugsgrößen:

  • 4×4 Folientastatur – 75mm
  • M5Stick C – 50mm / mit USB-C-Winkeladapter 70mm
  • 1-3 Zellen 18650 USB-Stromversorgungsplatine (5V und 3,3V) –

Daraus ergibt sich eine lichte Höhe von mindestens 80 mm.

Flaches Gehäuse:

  • Lichte Höhe ca. 50 mm
  • => Systemhöhe = 50 mm + 2 * 3 mm + 10 mm = 66 mm
  • => Standarthöhe = 2 * 66 mm = 132 mm

Standardgehäuse:

  • Lichte Höhe 80 – 120 mm
  • => Systemhöhe = 80 mm + 16 mm = 96 mm
  • => Systemhöhe = 120 mm + 16 mm = 136 mm

Hohes Gehäuse:

  • Lichte Höhe ab 150 mm
  • => Systemhöhe = 150 mm + 16 mm = 166 mm

Breitenraster:

  • M5Stack Core – 55mm
  • M5Sick C + 4×4 Folientastatur = 25 + 70 = 95mm

Daraus ergibt sich eine lichte Breite von mindestens 100 mm. In 50 mm Schritten.

Tieferaster:

Für die Tiefe habe ich 3 Abmaße überlegt:

  • 200 mm
  • 250 mm
  • 300 mm

Design:

Das Gehäuse ist in der DIY-üblichen Art mit ineinandergreifenden Fingern gestaltet. Rückwand, Bodenplatte und Front werden zu einer U-förmigen Grundstruktur verleimt. Der Deckel wird von oben, ebenfalls mit Fingern eingesetzt. Die Stabilität erhält das Gehäuse durch die Seitenwände. Diese haben Aussparungen für die seitlichen Finger der anderen Teile. Im Boden und im Deckel sind M3-Gewindebuchsen eingearbeitet. Durch die Seitenwände geführte M3-Senkschrauben wird das Gehäuse verschraubt.

Seitenteile:

Für die beiden Seitenteile wird eine gemeinsame Zeichnung erstellt. Sie liegt auf der rechten ansicht auf der Symmetrieachse des Gehäuses. Es ist jeweils eine Zeichnung zur Erstellung der Füsse und für die Durchbrüche erforderlich.

Die Seitenteile unterscheiden sich je nach Tiefe des Gehäuses erheblich. Die Zeichnungen müssen für jede Gehäusetiefe erstellt werden.

Kontur für 200 mm Tiefe.

Aussparrungen für 200 mm Tiefe.

Boden:

Boden und Deckel sind von der Geometrie identisch. Während der Boden die Befestigungslöcher für zu Montierenden Baugruppen bekommt, bleibt der Deckel unbearbeitet. Warme Luft soll nach Hinten und nicht nach Oben entweichen.

Die blauen Linien kennzeichnen die maximale Größe der Boden-/Deckelplatte. Die Zinken gehen nach Innen.

Zinken für 80 mm Rasterbreite.
Zinken für 100 mm Rasterbreite.
Zinken vorne und hinten für Rasterbreite 125 mm
Änderung für 160 mm Rasterbreite.
Zinken bei 187,5 mm Rasterbreite.
Zinen bei 200 mm Rasterbreite.
Zinken bei 240 mm Rasterbreite.
Zinken links und rechts für Tiefe 200 mm

Frontplatte:

Deckel:

S. Boden.

Rückwand:

Die Rückwand ist bis zur Oberkante eines ggf. darunter stehenden Gehäuses herunter gezogen. So wird verhindert, das warme Luft von hinten in die Kühlluftzufuhr gerät.

Einpressmuttern:

Das Maß für die Einpressmuttern ist recht kritisch.

  • Bei 5,3 mm waren die Muttern locker.
  • 5,2 mm hielte sich gerade so.
  • 5,1 mm gingen nur mit Kraft in den Schlitz. Ging aber noch.
  • 5,15 mm als Kompromis.
  • Die Werte dürften auch von der Leistung und Geschwindigkeit des Lasers abhängen.
Das Zen von Python, von Tim Peters

Schön ist besser als hässlich.
Explizit ist besser als implizit.
Einfach ist besser als komplex.
Komplex ist besser als kompliziert.
Flach ist besser als verschachtelt.
Spärlich ist besser als dicht.
Lesbarkeit zählt.
Spezialfälle sind nicht speziell genug, um die Regeln zu brechen.
Obwohl Praktikabilität die Reinheit schlägt.
Fehler sollten niemals stillschweigend passieren.
Es sei denn, sie werden explizit zum Schweigen gebracht.
Im Angesicht von Mehrdeutigkeit, widerstehen Sie der Versuchung zu raten.
Es sollte einen - und vorzugsweise nur einen - offensichtlichen Weg geben, es zu tun.
Auch wenn dieser Weg anfangs vielleicht nicht offensichtlich ist, es sei denn, Sie sind Niederländer.
Jetzt ist besser als nie.
Obwohl "nie" oft besser ist als "jetzt".
Wenn die Implementierung schwer zu erklären ist, ist es eine schlechte Idee.
Wenn die Implementierung einfach zu erklären ist, kann es eine gute Idee sein.
Namensräume sind eine verdammt gute Idee - lasst uns mehr davon machen!

Übersetzt mit www.DeepL.com/Translator (kostenlose Version)

Ich wollte mal JSON ausprobieren und lernen wozu es zu gebrauchen ist. Die Erklärungen im Internet waren mir alle zu abstrakt. Also habe ich dieses Prgramm geschrieben;

https://www.peters-bastelkiste.de/ein-eigenes-uebertragungsprotokoll/

Zuerst sah es noch etwas anders aus. Das ist die funtionsfähige Version.

Zuerst wird ein Dictionary (in Micropython Map) erstellt. Diese Map wird in ein JSON-Objekt umgewandelt und schließlich wird dieses Objekt wieder in eine Map zurückverwandelt.

Der große Unterschied der Map-Objekte und des JSON-Objektes besteht darin, dass das JSON-Objekt direkt mit print ausgedruckt werden kann – also ein Stream ist – wohingegen bei den Maps erst die Werte einzeln herausgeholt werden müssen. Sonst erscheint nur ?@.

D.h. eine komplexe Datenstruktur wird in eine einfache verwandelt und zurück.

Ob mir das für mein Messdatenprotokoll von Vorteil sein kann?

Das wäre der Fall, wenn ich Texte und Zahlen gemeinsam um- und wieder zurückwandeln kann.

Mit diesem Programm habe ich es ausprobiert.

Es sah nicht gleich so aus. Da eine Liste hier nicht mit dem Print-Befehl ausgegeben werden kann habe ich erst die Schleife zum Auslesen der Liste einbauen müssen. Das ist der Beweiß, dass tatsächlich wieder eine Liste entsteht.

Das Ergebnis zeigt, dass JSON für meine Zwecke sehr nützlich ist.

Mein Traum seit vielen Jahren ist es ein drahtloses Multimeter aufzubauen. Mit den M5Stack Geräten ist dieser Traum der Wirklichkeit sehr viel näher gerückt und mit dem Erscheinen der isolierten Units VMeter und AMeter steht der Realisierung nun nichts mehr im Wege.

Erster Testaufbau – ein chaotisches Gewusel

Auf dem Bild seht Ihr den ersten Testaufbau. Dank der Steckmöglichkeiten war es schnell zusammengesteckt und getestet und funktionierte. Die Spannungswerte sind zwar nicht real aber die Grundsätzliche Funktion ist gegeben. Die Spannungseingänge sind offen und fangen sich offenbar alle möglichen Störsignale ein. Die Stormaufnahme von 500mA enthält den Ladestrom für den Akku des M5Stick Cplus. Mit geladenem Akku sind es immerhin noch 460mA.

Ganz einfach war es nicht diese Kombination zu realisieren, weil die UIFlow-IDE es nicht ermöglichte ohne weiteres die Units am PaHUB zu betreiben. Erst der in diesem Beitrag beschriebene Trick brachte den Durchbruch:

Der Workaround ist nun nicht mehr erforderlich.

Die Units können inzwischen auch direkt in der UIFlow-IDE hinter einem PaHUB benutzt werden.

Das erste Testprogramm

Das erste Testprogramm – Die GUI wurde mit dem UI-Simulator von UIFlow erstellt.
Das an die neuen Möglichkeiten der UIFlow-IDE angepasste Programm (MVA033-010.m5f).

Messgenauigkeit

VMeter Unit

Um überhaupt etwas messen zu können habe ich eine LiIon-Zelle an alle drei VMeter angeschlossen. Eine davon invers gepolt. Das geht Dank galvanischer Trennung der Messteile problemlos. Die Anzeige schwankt zwischen 3,463 und 3,475 Volt. Als eine Unsicherheit von 12 mV. Die Spannungsänderungen springen in 4 mV Schritten. Mein Rigol DM3068 zeigt 3,4629 Volt an. Das entspricht -0% … +0,35% Abweichung. Für allgemeine DIY-Messungen völlig in Ordnung.

AMeter Unit

Zum testen der AMeter habe ich alle drei und das Rigol in Reihe geschaltet und an ein Hameg HM8040 Netzgerät angeschlossen. Mit dem Stromegrenzungspoti habe ich den Stron eingestellt. Da ich die Stromanzeige auf ganze mA eingestellt habe gibt es bei den kleineren Strömen ungenauigkeiten. dazu werden ich anschließend eine Weitere Messreihe durchführen.

DM3068AMeter
10,0776 mA10 mA
20,461 mA20/21 mA
50,76251/50 mA
99,315100/99 mA
201,025201/202 mA
301,47301/302/304 mA
404,92405/406/407 mA
mehr geht nicht beim HM8040

Auch diese Werte können sich sehen lassen. Alle Abweichungen <1%.

Maximal können Ströme bis ±4 A gemessen werden. Die höheren Ströme werde ich später testen. Genauso wie Ströme <1 mA.

Drahtlose Kommunikation

Ein großer Vorteil des ESP32 ist es, dass die Messwerte drahtlos übertragen werden können. Dafür stehen die WLAN-Einheit oder die Bluetooth-Einheit des ESP32 zur Verfügung.

Ein eigenes Übertragungsprotokoll

Im Prinzip ermöglichen die unten aufgeführten drahtlosen Übertragungsprotokolle schon Alles. Warum also noch ein eigenes Protokoll darauf setzen?

Der wesentliche Grund ist, dass es mir beim ESP Now – das ich bevorzugt einsetzen möchte – noch nicht gelungen ist mit der UIFlow-IDE im laufenden Betrieb neue Peers in ein Netzwerk aufzunehmen. Die MAC-Adresse muss zur Programmierzeit bekannt und fest im Programm vorgegeben sein. Damit lässt sich aber kein flexibles zur Laufzeit zusammenstellbares Mess-Netzwerk aufbauen.

https://www.peters-bastelkiste.de/wp-admin/post.php?post=694&action=edit

ESP Now

ESP Now ist ein Protokoll von Espressif, dass die UIFlow-IDE unterstützt. Damit ist recht einfach ein kleines Netzwerk aufgebaut, dass keinen Accesspoint benötigt. Die einzelnen ESP32 Geräte kommuniziernen direkt miteinander. Der Nachteil ist, das bei der Programmierung mit der UIFlow-IDE die MAC-Adressen aller Mitglieder eines solchen Netzwerkes bekann sein müssen. Ob das bei ESP Now grundsätzlich so ist glaube ich nicht. Es ist mir bisher aber nicht gelungen einen Workaround für Micropython und damit für Blockly zu finden. Man kann mit ESP Now aber auch Broadcast Packete aussenden, so dass jedes andere Gerät die Informationen empfangen kann. Das ist zwar nichts für reale Anwendungen, aber zum Ausprobieren ist es zu gebrauchen.

Ein einfaches Programm, dass alle 6 Messwerte ermittelt und anzeigt. U1 wird als Broadcast mit ESP Now gesendet.
Hier das dazugehörige Empfangsprogramm

Die beiden oben abgebildeten Programme zeigen die Möglichkeit der Übertragung mit ESP Now.

Eine Schwierigkeit bei ESP Now ist, dass die Daten als String übertragen werden. Wenn Die Daten in eine Liste gepackt werden und diese Liste übertragen wird sieht der String nach dem Empfang so aus: „[ Wert1, Wert2, Wert3, Wert4, Wert5 Wert6] „. Die Werte daraus zu entpacken ist etwas umständlich. Zuerst müssen die eckigen Klammern entfernt werden:

Aus dem von den eckigen Klammern befreiten String kann nun wieder eine Liste erstellt werden:

Nun ist tmp_date eine Liste die die Messwerte enthält.

In einer Schleife lassen sich nun die Messwerte auslesen. Hier ein kleines Programm, dass die Messwerte untereinander im Display darstellt, zurechtgestutzt auf ganze mV und mA.

Ein universelles Empfangprogramm. Es wird eine Liste mit Daten erwartet und dargestellt.

Hier kann das Programm heruntergeladen werden:

Das dazugehörige Sendeprogramm sieht so aus:

Ein einfaches Sendeprogramm, dass die Daten der 6 Messstellen in eine Liste verpackt überträgt.

Damit kann man schon erste Versuche anstellen.

MQTT

MQTT ist ein Protokoll, dass für den Zweck der Messwerverteilung sicher gut geeignet ist. Es benötigt im WLAN aber einen Brocker, der die Daten entgegen nimmt und weiterverteilt an die Geräte die diese abonniert habe.

WLAN

Das Gerät mit einem Webserver auszurüsten und die Daten dort abzuholen oder vom Server zuschicken zu lassen ist wohl die Königsklasse der drahtlosen Übertragung. Dazu fehlt mir aber noch einiges an Wissen, so dass dieser vorläufig nicht von mir beschritten werden wird.

Grenzwertüberwachung

Die integration einer Grenzwertüberwachung erweitert den Einsatzbereich des Gerätes. Dazu ist eine Tastatur zur Eingabe der Grenzwerte und eine Ausgabe durch Logiksignale, ggf. eine Darstellung auf dem Display.

Für die Grenzwertüberwachung ist wie schon erwähnt eine Tastatur erforderlich, die 5, 7 oder 8 Leitungen benötigt, je nach Anzahl der Tasten. Ausserdem sollte eine Grenzwertüberschreitung auch nach
Außen gemeldet werden. Dazu sind weitere 6 oder 12 Leitungen erforderlich. Je nach dem ob Über- und Unterschreitung oder nur eine einfache Meldung erfolgen soll.

Nun wird es eng auf dem I2C-Bus. Es werden weitere 2 bis 3 I/O-Expander benötigt. Das funktioniert nicht weil deren Adresse nicht umgestellt werden kann (in der UIFlow IDE). Ein weiterer PaHUB kan auch nicht eingesetzt werden, aus dem selben Grund. Der Versuch einen I/O-Expander und einen PbHUB zu kombinieren schlug auch fehl, weil ein I2C-Error gemeldet wurde. Der PbHUB belastet den I2C-Bus offenbar zu stark. Eine M5Stack inherente Lösung gibt es offenbar nicht. Deshalb habe ich I2C-Bus -Expander-IC’s bestllt. Ich hoffe damit lässt sich das Problem lösen.

Ich habe das Proglem mit den fixen Adressen in der UIFlow-IDE und damit auch in Micropython zwar an M5Stack weitergegeben, aber aufgrund meiner bisherigen Erfahrungen rechne ich mit großer Resonanz.

Alternativ könnte das Problem mit den Adressen mit der Arduino-IDE gelöst werden. Soweit ich weiß, kann man dort die I2C-Adresse eines Bausteins angeben. Aber ich wollte doch bei Blockly und Micropython bleiben.

Eingabe Tastatur

Als Eingabetastatur käme eine 4×4-Matrix-Tastatur in Frage. Diese ist aber relativ groß. Alternativ könnten auch Touchkeys zum Einsatz kommen. Deren Eignung muss aber noch untersucht werden.

Software

Die Software muss zum Einen die Eingabe des Grenzwertes für jeden Messkanal ermöglichen. Während des Messens müssen die Werte überprüft und ggf. Aktionen ausgeführt werden.

Darstellung im Display

Im Display kann ein Wert normal grün, in der Nähe des Grenzwerte gelb und bei überschreiten des Grenzwertes rot angezeigt werden.

Ausgabe

Die Ausgabe könnte durch Darlingten-Treiber-IC z.B. ULN2008 realisiert werden. Das ist universal einsetzbar und kann ggf. auch Relais treiben.