In der c't 18/2018 wurde als Bastelobjekt zum Thema Hausautomation eine über MQTT adressierte Statusanzeige mit Neopixeln (für Arduino + ESP8266) vorgestellt. Das ist eine gute Idee, wie man mit Hilfe eines einzelnen freien Pins den Status diverser Sensoren optisch signaliseren kann. Da ich alle notwendigen Bauteile in der Bastellkiste hatte, habe das Projekt nachgebaut. Was mir nicht wirklich gefallen wollte, das war die Implementierung. Zum einen fügte sie sich nicht in mein eigenes Konzept der MQTT-Clients, zum anderen werden die Neopixel mit schwerem Geschütz zum Blinken genötigt: Scheduler, JsonObjekt und reichlich Stringobjekte und Stringmanipulationen werden resourcenverschwendend bemüht. Darum habe ich das Programm komplett umgekrempelt, mich dabei auf die klassischen Char-Arrays beschränkt, Scheduler und Json werden überflüssig. Die wesentlichen Funktionen sind in "neopixel.ino" zusammengefasst: - neopixel() wertet die eingehende MQTT-Message aus, schaltet die Neopixel auf die übergebenen Farbwerte und speichert ggf. die Blinkwerte. - check_blink() muss in regelmäßigen Abständen aufgerufen werden und kümmert sich um das selbstständige Blinken. "mqtt-neopixel.ino" führt lediglich die Initialisierung sowie setup() und loop() aus. "mqtt_client.ino" reicht eingehende MQTT-Messages an die zuständigen Behandlungsroutinen durch. Die Parameterübergabe: Per MQTT-Message/Payload kann man entweder eine Komma-separierte-Liste im ASCII-Format - oder die Daten in hexadezimaler Form kompakt übermitteln. Die Reihenfolge der 6 Felder ist in beiden Fällen gleich: Erste-LED, Rot, Grün, Blau, letzte-LED, Blinkmodus (alle Werte zwingend numerisch !) Die Bedeutung des Teils "Erste-LED, Rot, Grün, Blau" ist selbsterklärend. Wenn "letzte-LED" > "erste-LED", dann wird der gesamte Bereich von "erste-LED" bis "letzte-LED" geschaltet. Die Blinkmodi sind: 0 -> Dauerlicht [default] 1 -> 1Hz, 2 -> 2Hz, 3 -> 4Hz, 4 -> 1Hz unsymmetrische 1:7 (125ms an, 875ms aus)) Beispiele: "0,255,0,0,2,0" -> Erste-LED = 0, Rot = 255, Grün = 0, Blau = 0, Letzte-LED = 2, Blinken = 0 Die LED's 0, 1, 2 werden auf Rot geschaltet bei Dauerlicht. Bei der Übertragung im ASCII-Format können alle "0" entfallen, fehlende Parameter werden intern auf "0" gesetzt. Die Alternative Eingabe ist also: ",255,,,2" Die kürzestmögliche Message bestehend aus einem Zeichen - etwa die Payload "6" wird erweitert zu "6,0,0,0,0,0", die LED 6 wird ausgeschaltet. Und "," schaltet die LED 0 aus. Eine hexadezimale Payload muss genau 6 Byte lang sein und im letzten Byte muss das Bit.7 gesetzt sein. 0500FF000781 -> LED 5 bis 7 werden auf Grün gesetzt und Blinken auf 1 Hz. Viel Spaß beim Blinken, Michael S.
Michael S. schrieb: > Darum habe ich das Programm komplett umgekrempelt, mich dabei auf die > klassischen Char-Arrays beschränkt, Scheduler und Json werden > überflüssig. Damit führst du die normale Funktionsweise von MQTT ad absurdum. Sowas kann man sich nur erlauben, wenn man sicher sein kann, daß alle MQTT-Nachrichten tatsäclich ohne JSON auskommen, und das ist in der realen Welt nicht der Fall. In meinem Umfeld (mit einer Menge MQTT-Publisher/Subscriber) wäre sowas komplett unbrauchbar Wieso man unbedingt Resourcen sparen muß, die anderweitig nicht benötigt werden, erschließt sich mir sowieso nicht.
Harry L. schrieb: > Damit führst du die normale Funktionsweise von MQTT ad absurdum. > Sowas kann man sich nur erlauben, wenn man sicher sein kann, daß alle > MQTT-Nachrichten tatsäclich ohne JSON auskommen, und das ist in der > realen Welt nicht der Fall. ich glaube, wir reden über verschiedene Dinge. Wenn ich Nachrichten im JSON-Format empfange oder sende, dann kann ich auf die entsprechenden Bibiotheken nicht verzichten. Aber das JSON-Format wird im konkreten Fall nicht zur Datenübertragung benutzt. JSON wird benutzt, um die RGB-Werte für blinkende LED's in JSON-Objekten zu speichern. Ein Array mit uint8_t kann diesen Zweck mit deutlich weniger Overhead erfüllen. Aber selbstverständlich - viele Wege führen nach Rom. > Wieso man unbedingt Resourcen sparen muß, die anderweitig nicht benötigt > werden, erschließt sich mir sowieso nicht. Zum Thema "ressourcenschonen". Wenn man mit ATtinys und ATmegas arbeitet, dann ist man schon gezwungen, möglichst kompakten Code zu schreiben. In den Beispielen zu ArduinoJson finde ich folgenden Hinweis: // Use String objects sparingly, because ArduinoJson duplicates them in the // JsonBuffer. Prefer plain old char[], as they are more efficient in term of // code size, speed, and memory usage. Auf dem ESP8266 kann man entspannter vorgehen, da kann man sich dann schon mal ein "sprintf()" erlauben. Übrigens habe ich auf die Verwendung von C++String / C-Strings komplett verzichten können (Ausnahme zum Debugggen), indem ich die Payload direkt als uint8_t ablege. Eine sprachliche Korrektur zu meinem ersten Beitrag: Wenn ich von "Hexadezimaler Payload" schreibe, dann ist eine Payload im binären / Byte-Format gemeint (bytearray[] in Python) . mfg Michael S.
Ich sehe auch einen grossen Vorteil darin das man Menschenlesbare Nachriten per MQTT verschickt. Es gibt viele Clients die sich an den Broker anhängen können, selbst auf dem Smartphone kann ich die Meldungen mitlesen. Da machen kryptische Hexcodes keinen Spass. Auch zur Weiterverarbeitung in NodeRed z.B. ist das mit JSON Objekten viel angenehmer. Das man sich den Anachronismus mit Tinys für solche Aufgaben noch antut... In gleicher Größe und für nahezu gleiches Geld bekomme ich 32 Bitter mit ausreichend Flash und RAM um auch da schon mit lesbaren Daten arbeiten zu können. Wie heisst der blöde Spruch nochmal? Für nicht benutzten Flash gibts kein Geld zurück?
MQTT auf einem 8bit-AVR ist ohnehin eine Illusion.
Harry L. schrieb: > MQTT auf einem 8bit-AVR ist ohnehin eine Illusion. Es ist immer noch ein Unterschied, ob es sich um einen Client oder Server handelt.
Wolfgang schrieb: > Es ist immer noch ein Unterschied, ob es sich um einen Client oder > Server handelt. Hä? Kann es sein, daß du MQTT nicht verstanden hast? Da gibts nur Broker(Server) und Publisher/Subscriber(Client) Ein 8bit-AVR ist für jede dieser Komponenten mindestens 3 Nummern zu klein.
:
Bearbeitet durch User
Harry L. schrieb: > MQTT auf einem 8bit-AVR ist ohnehin eine Illusion. Eine Menge Bla-Bla gemischt mit heißer Luft, die du in diesem Thread produzierst. Wäre es nicht besser du nimmst dein Eimerchen und dein Schauffelchen und gehst spielen? Das Prinzip und die Idee hinter MQTT wirst du verstehen, wenn du erwachsen bist.
Zur allgemeinen Beruhigung der Gemüter: Wenn man einige Zeit mit den ATtinys und ATmegas gearbeitet hat, dann geht einem schlankes Programmieren (zumindest der Versuch dazu) in Fleisch und Blut über. Selbstverständlich läuft der MQTT-Client auf einem größeren Controller, nämlich dem ESP8266. Michael S.
Warum sollte das nicht gehen? Vorausgesetzt man lagert das TCP/IP auf Hardware aus. Wo ist das Problem bei einem String?
Ein kleiner Nachtrag: Damit der MQTT-Client angeschlossenen Neopixels auch ohne den Umweg über den MQTT-Server direkt ansteuern kann, ist eine zusätzliche Schnittstelle in der "neopixel.ino" eingefügt: void set_mypixel(uint8_t* pixel); ein Array mit 6 Byte wird zur Übergabe der Parameter benötigt: uint8_t pixel[] = {0,0,0,0,0,0}; die Bedeutung der Bytes: pixel[0] = Start-LED pixel[1] = rot pixel[2] = grün pixel[3] = blau pixel[4] = End-LED pixel[5] = Blinkmode [0...4] Die Farbwerte einzelner Neopixel können natürlich auch mit einer Methode des neopixel-Objektes geändert werden: pixels.setPixelColor(pixelnr, pixels.Color(rot, grün, blau)); Allerdings kann man auf diesem Wege keine Reihe von LED's setzen und auch den Blinkmodus nicht nutzen. Viel Spaß beim Blinken, Michael S.
Was soll daran Ressourcen sparend sein ? Also die Möglichkeiten des RTOS nutzt du nicht. Warum ? Dein Code beschäftigt die CPU zu 100% .. Das hat folgen.. früher ka... die WIFI Verbindung ab.... Unter RTOS kann man das besser lösen das eine Thread nach x wieder aufwacht ;)
:
Bearbeitet durch User
Hallo, interessante Diskussion... Muß ich jetzt meinen AVR Mega328 mit ENC28J60 und BME280 und MQTT-Client wegwerfen? Dabei schickt der doch artig die Daten zum MQTT-Broker. Harry L. schrieb: > Damit führst du die normale Funktionsweise von MQTT ad absurdum. > Sowas kann man sich nur erlauben, wenn man sicher sein kann, daß alle > MQTT-Nachrichten tatsäclich ohne JSON auskommen, und das ist in der > realen Welt nicht der Fall. Ein MQTT-Client bekommt nur die Daten, die er auch abboniert hat. Ich bin mir auch sicher, daß ich keine JSON-Messages bekomme, da ich meinem Broker keine schicke. Michael S. schrieb: > Auf dem ESP8266 kann man entspannter vorgehen, da kann man sich dann > schon mal ein "sprintf()" erlauben. > > Übrigens habe ich auf die Verwendung von C++String / C-Strings komplett > verzichten können (Ausnahme zum Debugggen), indem ich die Payload direkt > als uint8_t ablege. Warum soll ich Flash sparen wenn alle gewünschten Funktionen auch mit der String-Klasse bequem reinpassen? Der Ram-Verbrauch kann bei großen Strings und bearbeiten mit den String-Funktionen temporär knapp werden. Allerdings habe ich selten Strings mit knapp 6kB Größe, auf die ich z.B. String.replace() loslasse. Gruß aus Berlin Michael Gruß aus Berlin Michael
Nunja mit Strings muss der MQTT Stack ja sowie so umgehen können und ich meine damit nicht die payload. Alles andere im Protokoll sind strings.. Da kommt es auf die Payload auch nicht mehr an und jeder kann lesen was gemeint ist.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.