Moin Leute,
um einen kleinen Verstärker neben dem Drehencoder und TFT an der
Frontplatte auch über WEB steuern zu können, habe ich (widerwillig) die
Arduino-IDE installiert und übertrage die Slider- und anderen Werte von
der Webseite mittels websocket an einen nachgerüsteten ESP8266, der
wiederum über die serielle Schnittstelle 'Variable=Wert'-Paare ausgibt.
Der STM32-Prozessor auf dem Verstärker könnte entfallen und die Sache
allein mit dem ESP8266 geregelt werden, das ist klar. Andrerseits war
die Chronologie der Entstehung des Verstärkers anders und die Idee mit
dem Webfrontend entstand erst vor kurzem. Der STM32 soll auch aus
anderen Gründen drinbleiben.
Gelöst ist es so: Ein Javascript liest die Werte von den Slidern und
anderen Steuerelementen und überträgt sie als payload an einen
websocket, der wiederum die etwas vorgefilterte payload über die
serielle Schnittstelle des ESP (.onmessage) ausgibt. Der STM32 empfängt
diese und steuert das TFT, den Klangregler und Anderes. Das funktioniert
auch soweit und ist prinzipiell dann doch auch nicer Schice für
leidenschaftliche HTML-, Javascript- und Arduinohasser wie mich.
Es ist also möglich, Daten vom Webfrontend an den STM32 zu senden. Was
aber noch fehlt, ist der Rückkanal. Der STM32 speichert die
Einstellungen im Backup-Ram. Wenn der Websocket nun geöffnet wird (weil
die Webseite zur Steuerung aufgerufen wird, siehe angehängtes Bild),
bekommt der STM32 eine Mitteilung (.onopen) und sollte diese Daten
eigentlich an die Slider des Frontends schicken. Im günstigsten Fall
kann man dann auch die Slider der Webseite über den Drehencoder, der an
der Frontplatte sitzt, synchron bewegen - das wäre der feuchteste Traum
meiner Hoffnungen.
Das Problem ist, daß ich diesen Rückkanal vom STM32 (bzw. ESP) zum
Webfrontend nicht kenne, und beim Googeln auch nicht recht weiterkomme.
Websockets sind Vollduplex, soviel habe ich inzwischen verstanden.
'.send' funktioniert auch, aber das entsprechende Wissen über ein
'.receive' fehlt mir beim socket. Das Einzige, was ich gefunden habe,
ist ein Console.log(), aber das wird es wohl nicht sein.
Ich stochere da etwas im Nebel.
Habt ihr vielleicht ein Stichwort, wie man diesen mysteriösen Rückkanal
nennt oder seine Funktionsweise ausfindig machen kann? Den Rest mache
ich dann selba :-)
Ok, dann stoeber ich mal weiter an dem console.log-Dingsbums rum. Ist ja
schon ein Hinweis, daß man da weitersuchen kann :-)
Den Pfad zu finden, wie ich von der seriellen Schnittstelle des STM32
bis zum Slider komme, das ist die Herausforderung. Andersherum geht es
schon.
Breaking News: Wie durch ein Wunder kann ich schon einen Slider
verschieben, wenn ich ihm im Javascript einen Wert zuweise (dachte, das
geht nur andersherum). Wenn das jetzt noch vom STM32 aus geht, bin ich
glücklich g.
console.log ist nicht die Lösung, das gibt in diesem Beispiel einfach
nur die ankommende Zeichenkette in der Konsole vom Browser aus. Das
benutzt man zum debuggen. Die meisten Browser öffnen so eine Art
developer Tool mit F12 und da gibt es einen reiter "Konsole", dort sieht
man die Ausgabe.
Die Empfangene Nachricht liegt in "event.data" (im onmessage event wie
oben in meinem Beispiel), damit musst du dann weiterarbeiten.
Danke Paul, das Problem liegt/lag - glaube ich - daran, daß der Weg von
dem seriellen Port bis zum "event" im Javascript noch nicht klar war.
Prinzipiell sollen Frontplatte mit TFT und Drehencoder mit dem
Webfrontend synchronisiert sein (also jeweils die gleichen Werte für
Volume, Bass etc. haben und anzeigen).
Es bleibt spannend, aber es ist Licht am Ende des Tunnels zu sehen g
Dieses Video wird des Lötsels endgültige Räsung bringen, hoffe ich
https://www.youtube.com/watch?v=cxbXyTwOl-M
Da werden die Daten der Sensoren vom ESP über websocket zur Anzeige
gebracht, und genau da hakt es bei mir. Das bastel ich nach, und lerne
nebenbei noch was über die Vorteile der JSON-Sache.
Vermutlich werde ich dabei wieder auf die event-Methode stoßen, und dann
ist der Kreis geschlossen.
Das macht inzwischen schon Laune mit dem ESP/Arduino-Zeugs.
Wenn mal im Ansatz klar ist, wie JSON, Javascript und die Funktionen auf
der html-Seite zusammenspielen, ist schon was gewonnen. Weiß nicht, ob
es anderen auch so geht, aber die Verknotungen im Hirn beim
Nachvollziehen, wer bei diesem Server/Client-Zeug was wann wie warum und
wohin sendet, sind bei diesem Webgedöns nicht ganz ohne.
Das ist völlig normal, wenn man sich mit einer neuen Materie
beschäftigt. Man hat nur irgendwann mehr Erfahrung wie man sich
schneller solche Dinge aneignet. Mit websocket und JSON hast du auf
jeden Fall schon genau die Dinge gefunden die du brauchst.
Beispiel JSON:
Zahlen können ohne Anführungsstriche geschrieben werden, Text immer mit.
Ein einfacher JSON-String mit Key, Value pärchen sieht so aus:
{"Volume": 22, "Treble": 8, "Bass": 8}
Im onmessage event musst du den Json string als erstes in ein Objekt
parsen:
JSONobj = JSON.parse(event.data);
dann kannst du auf die Werte einfach zugreifen z.b.
var volume = JSONobj.Volume;
Als Anfänger ist es etwas tricky wie man nun auf die HTML Elemente
zugreift, weil es je nach Typ unterschiedlich ist. Wichtig ist, dass im
HTML all deine Elemente eine eindeutige id haben.
Um einen Slider zu aktualisieren zum Beispiel so:
document.getElementById("volumeslider").value = volume;
bei einer checkbox oder radio button
document.getElementById("chkbox1").checked = true;
bei einfachem Text in einem HTML Element
document.getElementById("divxyz").innerHTML = "was auch immer";
Ah gut, das mit dem JSON.parse werde ich auch noch ausprobieren.
Die Wertepaare hatte ich noch selbst gebaut, aber jetzt ist klar, daß
JSON und die entsprechenden Werkzeuge einem genau diese Dinge abnehmen.
Der Zugriff auf HTML über die IDs ist für die ".send" Richtung (also die
Sliderstellung zum STM32 übermitteln) genauso gemacht. Da gab es einige
gute Lern-Beispiele von randomnerdtutorials, tttapa und anderen.
Inzwischen ist der Knackpunkt auch gefunden: Der
"socket.broadcastTXT(x)" ist das, wonach ich gesucht habe. Der versendet
ein vorbereitetes JSON-Paket x, das aus den Daten der seriellen
Schnittstelle zusammengestellt wird. Diese Funktion/Methode kannte ich
nicht.
Soweit die Theorie. In den nächsten Tagen werde ich's testen :-). Danke
nochmal für die Unterstützung.
Jou, das geht so. Checkboxen, Slider, alles läßt sich jetzt von beiden
Seiten (Webseite und Frontplatte) steuern.
Das "JSON.parse" hat die Sache sehr vereinfacht. Ich habe auf Variablen
im Javascript verzichtet. So ungefähr sieht das Script jetzt aus
[c]
var power;
var connection = new WebSocket('ws://'+location.hostname+':81/',
['arduino']);
// -------------------------
// functions
// -------------------------
connection.onopen = function () {
connection.send('socket=true');
connection.send('Date=' + new Date()); // Wed Nov 24 2021
13:59:14 GMT+0100 (Mitteleuropäische Normalzeit)
connection.send('Unix=' + new Date().getTime()); // unixtime mit ms
(durch 1000 teilen)
};
connection.onerror = function (error) {
console.log('WebSocket Error ', error);
};
connection.onmessage = function (event) {
console.log('Server: ', event.data);
JSONobj = JSON.parse(event.data);
document.getElementById('vol').value = JSONobj.Vol;
document.getElementById("voltxt").innerHTML = JSONobj.Vol;
document.getElementById('treb').value = JSONobj.Treb;
document.getElementById("trebtxt").innerHTML = JSONobj.Treb;
document.getElementById('bass').value = JSONobj.Bass;
document.getElementById("basstxt").innerHTML = JSONobj.Bass;
//[.....]
document.getElementById('loud').checked = JSONobj.Loud;
document.getElementById('mute').checked = JSONobj.Mute;
document.getElementById('inp'+JSONobj.Input).checked = 1;
document.getElementById('gain'+JSONobj.Gain).checked = 1;
power = JSONobj.Power;
document.getElementById('power').value = power;
};
connection.onclose = function(){
connection.send('socket=false');
console.log('WebSocket connection closed');
};
// -------------------------
// functions
// -------------------------
function VolSli() {
v_vol = document.getElementById('vol').value;
connection.send('Vol=' + v_vol);
document.getElementById("voltxt").innerHTML = v_vol;
}
//[.....]
[/code]
Der broadcastTXT(), der das .onmessage-event auslöst, läuft in der
websocket.loop() in der sketch loop().
So funktioniert das also :-)
Was Lustiges: Der broadcastTXT ballert zurück, was man bei der
power-Variable merkt: Man drückt den Powerknopf auf der Webseite, das
wird zum STM32 gesendet, und weil der alternierend schaltet, wird der
Powerknopf einmal negiert, wenn das Zeug rausgeht, andrerseits merkt der
STM32, daß sich was geändert hat, und sendet alle Variablen zurück,
wobei der Knopf dann nochmal negiert wird. Äh, tja. Damit läßt sich das
Ding also erstmal nicht abschalten gg. Aber das ist ja der übliche
Mistkram, evtl. geht es auch mit sendTXT(client,str) anstatt
broadcastTXT(str) oder man nimmt halt einfach eine checkbox anstatt
einem alternierenden Schalter.
Was allerdings zu erwarten war: Wenn der Drehencoder nicht langsam genug
gedreht wird, aktualisieren sich die Daten auf der Webseite nicht und
man sieht in der Konsole, daß nur ein Teil des JSON-Strings ankommt.
Da muß man diesen Riesenstring, der ja alle Variablen beinhaltet,
nochmal irgendwie stückeln. Es wird ja auch am Drehencoder immer nur
eine Variable geändert, das ist also sinnloser Overhead jedesmal.
Das kommt dann später mal dran.
Grüße Sauer
Shit, Formatierung versaut.
v_vol ist außerdem unsichtbar viel weiter oben definiert, aber noch
experimentell und kann direkt durch
'document.getElementById('vol').value' ersetzt werden.
Die "document.getElementById("voltxt").innerHTML = JSONobj.Vol"-Elemente
beziehen sich auf Labels auf der Webseite, die über die id adressiert
werden und die Werte der Sliderstellung anzeigen. Die Zahlen sieht man
sonst nicht.
Inzwischen habe ich nach JSON.Parse mit if-Abfragen auf
JSONObj.hasOwnProperty erreicht, daß auch Teilstrings akzeptiert werden.
An der Geschwindigkeit in dieser Richtung hat sich aber nichts geändert.
Wenn man eine Variable am Drehencoder ändert, vergehen ca. 500ms, bis
der Slider auf der Webseite nachzieht. Obwohl nur ein JSON-String mit
einer payload von 8 chars übertragen wird ("vol":xx). Andere
Erfahrungsberichte jammern schon über nur 150ms.
Mal checken, ob das Synchronisieren verbessert werden kann, indem die
Daten, die vom STM32 zur Webseite gehen, quittiert werden. Wenn der
Encoder gedreht wird, müssen dann vom Javascript mit connection.send()
die Werte zurückgesendet werden - und wenn da nichts zum STM32
zurückkommt, sendet dieser halt mit geeignetem delay solange, bis die
Werte im Javascript und im STM32-Speicher übereinstimmen. Vermutlich
wird sich an der Geschwindigkeit selbst nicht viel ändern lassen.
Die umgekehrte Richtung, also vom Bewegen eines Sliders bis zur
Umsetzung im STM32 geht dagegen mit einer gefühlten Verzögerung von max.
50ms in Ordnung.
Bisher war ich auf einem anderen System mit NO_SYS=1-lwip immer mit
'GET' unterwegs, da mußte man alle Änderungen noch mit einem
submit-Button übertragen.
Bei den Beispielen für den ESP mit AJAX und asynchronem Webserver muß
zur Werteübernahme der Slider immer losgelassen werden.
Da ist diese socket-Geschichte schon besser. Da schiebt man den Slider
und die Änderung passiert ohne Absetzen fast gleichzeitig, ist ein viel
besseres 'look-and-feel'.
Moin,
also der Websocket ist für solche Sachen eigentlich recht schnell.
Vielleicht bremst bei dir schon die serielle Übertragung zwischen STM
und ESP? Hier muss man ggf. dafür sorgen das bei häufigen Änderungen
nicht alle übertragen werden.
Sascha