PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : html-Code für virtuelles website-Button-Pad



HaWe
30.10.2019, 20:15
Das ist nicht ganz so einfach. Das nodeMCU ist etwas langsam. Ich hatte schon mal gelesen, dass die keine sher hohe Datenübertragungsrate per WiFi haben, aber mich stellt das so nicht ganz zufrieden. Einen Anfang habe ich gemacht, bis ich jetzt gesehen habe, wie lang das mit der Übertragung der Seite dauert.

Hier mal der vorläufige Code:


#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>

const char* ssid = "....";
const char* password = "....";

ESP8266WebServer server(80); //instantiate server at port 80 (http port)

String page = "";
//the HTML of the web page
String s1="<div style='display:block;overflow:visible;'><div role='presentation' style='display:table'>";
String s2="<div style='display:table-row;'>";
String s3="<div style='display:table-cell;position:relative;vertical-align:top;width:1.5em;padding:0.1em;'><form style='height:0.65em;'><input type='text' name='but' value='";
String s31="' maxlength='1' style='visibility:hidden;width:0;height:0;'><input id='but#0' type='submit' value='*' style='margin:0;height:1.5em;width:1.6em;font-family:monospace;font-style:normal;font-size:133%;color:#000000;font-weight:700;text-align:center;line-height:170%;border-radius:0.375em;border-width:1px;'></form></div>";
String s4="</div>";


int tableWidth=7;
int tableHeight=7;




void setup(void){
Serial.begin(115200);
delay(10);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password); //begin WiFi connection
WiFi.config(IPAddress(xxx,xxx,x,xx), IPAddress(xxx,xxx,x,xx), IPAddress(255,255,255,0), IPAddress(xxx,xxx,x,xxx));



Serial.println("");

// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());

server.on("/", [](){
page = s1;
int but = 0;
for(int x=0; x < tableHeight; x++){
page += s2;
for(int j=0; j < tableWidth; j++){
page += s3 + String(but) + s31;
but++;
}
page += s4;
}
page += s4;
server.send(200, "text/html", page);
});
server.begin();
Serial.println("Web server started!");
}

void loop(void){
server.handleClient();
yield();
}




Es wäre in der Größe, per CSS, noch optimierbar, aber besser wär's mit JavaScript auf der Seite zu arbeiten und einem unsichtbaren Frame, zwecks Datenübertragung.


MfG

die Eingabe per Buttons ist nicht zeitkritisch, das dauert eh bis man ein Muster mit etwa 10-20 Buttons gedrückt hat.
Dann muss es per Sende-Button ("Fertig") übertragen weden,
und dann beginnt der Trainings- und Lernalgorithmus, der dann eh nicht mehr auf das Netzt per html zugreift und (je nach Netzstruktur und Musterzahl) durchaus mehrere Stunden dauern kann.

Im "Erinnerungsmodus" kann man dann dem Netz verschiedene Muster präsentieren (dauert so lange wie oben)
und dann legt es die gelernten Perzeptronwerte an (Netz-Matrix),
das dauert dann erfahrungsgemäß nur wenige Sekunden bis zur Auswertung.



Update:
dein html-Buttonpad sieht schon sehr schön aus, jetzt müssten die Buttons noch Zahlen tragen (0-63, zeilenweise hochgezählt),
Farbwechsel sobald gedrückt (grau->gelb o.ä.)
und dann müsste das Gesamt-Muster mit allen Nullen und Einsen für alle 64 Buttons als Block per Extra-Button an den esp gesendet werden, zur Weiterverarbeitung als net-inputs.

Anm.: WiFi.config() hat subnet 255,255,255,0 am Schluss!

WiFi.config(IPAddress(192,168,2,99), IPAddress(192,168,2,1), IPAddress(192,168,2,1), IPAddress(255,255,255,0));

Moppi
30.10.2019, 20:20
Vergiss es wieder, ist schon überholt. Nicht mit dem alten Krempel den Server belasten.

Hier mal ein Bild, ob das so dann ok ist. In den Feldern stehen nachher 0, 1 oder Leer und X (oder was anderes). Zum Aussuchen. Beim reinklicken würde sich der Inhalt ändern. Wenn alles fertig gesetzt ist, würde es ein Mal übertragen. Das ist dann aber vom Code her schon wesentlich kürzer so.


34433



MfG

HaWe
30.10.2019, 20:31
zusätzlich zu
[Senden/OK]

bräuchte man zum Umschalten der Betriebsmodi noch einen Button
[Training]

und einen Button
[Erkennen],

aber das ginge zur Not auch über 2 echte Buttons an je einem GPIO Pin

- - - Aktualisiert - - -

edit, hat sich überschnitten:

ja, sieht top aus!
da ginge sogar auch ' ' für 0 und 'X' für 1, wenn kein Farbwechsel stattfindet und keine Zahlen in den Feldern stehen
(Zahlen in den Feldern würden das Debuggen vereinfachen, muss aber nicht sein)

- - - Aktualisiert - - -

man würde dann

1. entscheiden per Buttonclick, ob trainiert oder erkannt werden soll (evtl. auch Radio-Buttons)
und
2. "Senden/OK" würde dann das Muster für den gewählten Modus übertragen ans Netz.

Moppi
30.10.2019, 20:54
Man kann rein schreiben, was man möchte. Es wäre auch die Hintergrundfarbe zu ändern, was ich dann persönlich für besser fände, wenn das Feld ein Muster abbilden soll.

Das mit den "Betriebsmodi" verstehe ich noch nicht.
Das mit dem Muster trainieren kann ich mir vorstellen, aber dann fehlt die Zielvorgabe, was am Ende erkannt werden soll.

Jetzt ist es so nur ein Eingabefeld. Man könnte durch anklicken der Felder ein Muster erstellen / eingeben und abschicken.

Mal sehen ...



MfG

HaWe
31.10.2019, 06:55
man trainiert mehrere Eingabemuster gemeinam mit enem jew. Ausgabemuster (Ziel), z.B
000
0
(training)

010
0
(training)

100
0
(training)

110
1
(training)


dadurch lernt das Netz, die verschiedenen Eingabemuster zuzuordnen.
Dabei werden nicht die Einzelmuster gespeichert, sondern die Neuronen verändern ihre innere Struktur für alle Muster gemeinsam:
sie bilden eine interne Variablen-Matrix aus internen Gewichten und Thresholds, die auf alles gemeinam passt.

gibt man nun ein
011
drückt man auf
(erkennen)
dann wurde dieses Muster bisher nicht trainiert, trotzdem wendet das Netz seine Matrix auf dieses Muster an und erzeugt ein Ergebnis, das irgendwie zu den bisherigen Mustern passt, möglicherweise wird es auch eine 1 sein, aber das muss man ausprobieren: es lässt sich nicht vorhersagen.

Als Inputschicht könnte man die obersten 9 Zeilen des html-Buttonpads verwenden, als Ausgabeschicht die unterste, 10.

Ich bin aber gestern abend/nacht auf eine Sache gestoßen, als ich ein einfaches meiner alten Netze auf den esp8266 portieren wollte:

alle meine bisherigen MCUs konnten Multithreading (Lego NXT und Arduino Due), und beiden machte es nichts aus, wenn eine Funktion für eine Berechnung sehr lange gebraucht hat (Minuten bis Stunden).

Der esp8266 kann aber überhaupt kein Multithreading, und er stürzt ab und rebootet, wenn eine Funktion den Prozessor länger als wenige (1-2) Sekunden komplett mit einer Berechnung belegt. Training aber kann mehrere Stunden dauern, und auch Auswertungen (Erkennen) zumindest mehrere Sekunden

Das zweite Problem lässt sich vielleicht (!) durch etliche delay(1) in der Trainingsfunktion kaschieren (weiß ich noch nicht),
aber Mutithreading ist unverzichtbar, wenn man im Betrieb das Gehirn (ich nenne es HAL) simultan Muster bearbeiten als auch Inputs, Steuerbuttons und das Display bedienen soll.
Würde man das alles Spagetticodemäßig hintereinander schreiben, wird es nicht nur unübersichtlich, sondern auch extrem langsam, weil dadurch die sehr schnellen Gehirnroutinen im Mikrosekunden-Bereich ausgebremst werden durch TFT-Anzeige- oder GPIO- und html-Abfrageroutinen, die man nur 1x pro Sekunde aktualisieren muss.
Ein dritter Grund, was gegen den esp8266 spricht: er hat zu wenie GPIOs, um auch zusätzlich neben lokalen Pin-Buttons eine SD-Karte per SPI anzusprechen.

Der esp8266 macht daher keinen Sinn als Basis für ein NN, zumindest bei meinen NN-Pogrammen, die ich bereits geschrieben habe.
Es müsste ein Arduino Due sein wie früher, der kann aber keinen Webserver aufbauen,
oder ein esp32 ,
denn nur diese beiden können derzeit Multithreading (Due Scheduler bzw. std::thread).

Da der Due wegen mangelndem html aber komplett rausfällt und wir auch kein Hardware-Buttonpad haben, bleibt nur mein ESP32 als einzige Basis (meiner hat ein Adafruit Feather HX8367 Display) , für die ich die NNs neu programmieren könnte.
Allerdings verwendet der ESP32 auch etwas andere wifi- und webserver libs als der esp8266.

Mir ist daher jetzt noch nicht klar, wie es weitergehen kann, und ob es Sinn macht, zunächst mit den esp8266-html-Buttons zweigleisig zu fahren, mit absolut ungewissem Ausgang...

Moppi
31.10.2019, 08:03
alle meine bisherigen MCUs konnten Multithreading (Lego NXT und Arduino Due), und beiden machte es nichts aus, wenn eine Funktion für eine Berechnung sehr lange gebraucht hat (Minuten bis Stunden).

Macht es dem nodeMCU auch nicht, wenn man im Programmcode mitteilt, dass man beschäftigt aber aktiv ist. Der Befehl dafür ist: yield();


Ich habe das mal, so weit es bis jetzt mit den Infos möglich war, erstellt und etwas beschrieben. Datei hier zum Herunterladen.

34434

MfG

Ceos
31.10.2019, 08:23
und einem unsichtbaren Frame, zwecks Datenübertragung.

https://www.html5rocks.com/en/tutorials/websockets/basics/

geht auch etwas eleganter als ständig http requests zu schicken :)

Und weil ichs persönlich liebe hole ich nochmal die Python Keule raus und sag mal

https://github.com/pallets/flask

Da fällt das parsen etwas leichter und man kann die Webseiten als richtige HTMl Files schreiben und muss dann wie bei PHP in den Patzhaltern nur den PyCode packen der dann aus Daten die Lücken des HTML Dokuments an der entsprechenden Stelle ergänzt.

Finde ich persönlich eleganter als den HTML code als String mit ein zu compilen (und man kann auch die files on-the-fly updaten wenn was nicht stimmt und muss nicht immer erst alles compilen und hochladen

Moppi
31.10.2019, 08:42
https://www.html5rocks.com/en/tutorials/websockets/basics/

geht auch etwas eleganter als ständig http requests zu schicken :)



Wenn Du es kannst: super! Mach bitte ein Beispiel für nodeMCU.

Ceos
31.10.2019, 09:10
Wenn Du es kannst: super! Mach bitte ein Beispiel für nodeMCU.

Netter Beißreflex ... war als Denkanstoß zu verstehen und um etwas Last aus der Verbindung zu nehmen, aber wenn man sich zu fein ist mal damit zu beschäftigen ... bitte ... daher nur eine vereinfachte Antwort und viel Glück

https://www.tutorialspoint.com/html5/html5_websocket.htm

für die NodeMCU Seite braucht man allerdings ein klein wenig mehr Einrichtungsarbeit

https://github.com/micropython/micropython (Als Grundlage)
https://github.com/pfalcon/picoweb (Die Flask Version für den kleinen Speicher)
https://github.com/hiway/micropython-uasyncio-uwebsockets-modules (Die Websocket Anbindung)

Allerdings habe ich damals den richtigen Flask genommen und etwas angepasst damit er auf µPy läuft. Hab sogar mal Owncloud drauf laufen lassen, aber die Datenrate war eher bescheiden :P

HaWe
31.10.2019, 09:12
Wenn Du es kannst: super! Mach bitte ein Beispiel für nodeMCU.
schließe ich mich an, in Arduinisch!
Python ist hier völlig OT, denn dann müsste ja auch das NN in Python geschrieben werden, und das ist völlig illusorisch für meine Zwecke.

yield() ist aber nichts anderes als delay(1) in Arduinsch, das hatte ich ja schon angesprochen und damit müsste ich es ausprobieren.

Dennoch nützt es nichts, wenn die cpu kein MT kann.

Moppi
31.10.2019, 09:18
Wir haben in diesem Forum keine Beispiele für die Programmierung von NN in C
für Arduino z.B.
Aus diesem Grund hatte ich dieses in einem andern Thread nochmals geäußert.


Wenn man sich zu weit von der Basis entfernt, die ich hier bei Arduino und nodeMCU
sehe, entfernt man sich zu weit von der Mehrzahl der User in diesem Forum.


Ich hatte diesbezüglich schon woanders zum Nachdenken anregen wollen, als ich
sinngemäß schrieb, dass man sich überlegen soll eine Art Supercomputer zu verwenden.
Also irgendwas leistungsstarkes mit mehreren GHz Taktrate, mehreren Gigabyte RAM
und Festplattenspeicher, wenn man auf diesen Komfort dieser Geräte zurückgreifen
möchte: Schnelligkeit, Multitasking, Webfähigkeit. Dort hätte man dann alle Möglichkeiten,
wie Webserver mit PHP, man kann Javaprogramme drauf laufen lassen, man kann
Webanwendungen drauf laufen lassen, die ihre Datentransfer auch anders abwickeln,
Stichwort: AJAX.


Wenn ich hier jetzt anfange, mich in Neuronale Netze einzuarbeiten und dies in einem Thread
darzustellen, weiß ich genau was passiert. Nämlich dasselbe, was soeben auch hier passiert ist:
dann - und genau dann, nicht vorher - kommen die Leute die "Ahnung" davon haben und
den Thread so richtig aufmischen, mit diversen, nicht zielführenden Bemerkungen oder
"gut gemeinten Ratschlägen".
Deshalb wünschte ich mir etwas zum Thema Neuronale Netze, um die User hier zu wecken, die
etwas davon verstehen und sich der Sache annehmen, damit wir alle hier etwas davon haben und
es nicht in einem Zerreden des Themas endet.


Ich habe schon vieles gemacht und auch eine Webanwendung die mittels Sockets / AJAX-like,
Daten mit einem Webserver austauscht. Die Anwendung ist toll geworden, hier aber nicht brauchbar!

Ich sehe mein Projekt zuhause momentan als bestes Beispiel, wie weit man sich von einer allgemein handhabbaren Basis,
für viele Menschen / User - entfernen kann. Deshalb bin ich dafür, ganz klein anzufangen und es für jeden
verständlich zu machen. Hier jetzt besonders das Thema neuronales Netz.








MfG

HaWe
31.10.2019, 09:34
Hinzu kommt, dass die html-Steuertasten (Senden, Lernmode, Erkennmode, ggf. auch weitere für ResetInputs, SD_Speichern und Pause) ständig während aller HAL-Modi parallel zu Steuerzwecken abgefragt werden müssen, d.h. wenigstens 1-2x pro Sekunde gepollt werden müssten.

Der Due wäre eine gute Basis, wegen MT, und billig ist er auch, man braucht aber Dutzende GPIO-Switches, die einrasten.
Der ESP32 wäre eben die andere Alternative, mit der ich es u.U. umsetzen könnte, aber die komplette html-Sache müsste ich aus der Hand geben.

Auch der Raspi kann ja MT (und ist ja vergleichsweise schon ein kleiner "Supercomputer"), aber auch für ihn gibt es kein Hardware-Buttonpad und dafür kann ich auch keinen html-webserver schreiben, und daher bräuchte ich auch für ihn jemanden, der die html-Seite schreibt und im Programm händelt - eigentlich zu schwierig, wenn man es richtig überlegt.

PS,
Ich will aber gerne anfangen, den html-Code für die Key- und Steuer-Buttons zu testen, wie weit ich damit komme, ohne Garantie aber, dass es nicht bereits ein paar Stunden später doch nicht weiter komme.

Moppi
31.10.2019, 09:38
Hinzu kommt, dass die html-Steuertasten (Senden, Lernmode, Erkennmode, ggf. auch weitere für ResetInputs und Pause) ständig während aller HAL-Modi parallel zu Steuerzwecken abgefragt werden müssen, d.h. wenigstens 1-2x pro Sekunde gepollt werden müssten.

So was in der Richtung hatte ich auch vermutet.
Das macht es dann eigentlich unmöglich. Da der Browser immer erst eine Anfrage senden muss. Wie man das, mit einem ndeMCU, anders hinbekommen könnte, ist mir bislang nicht bekannt. Möglichkeiten gibt es theoretisch. Früher hat man die verwendet um, per PHP, ein Webchat zu bauen. Dazu kann man die Verbindung bestehen lassen, Daten an den Browser schicken (der ständig lauscht) und der verarbeitet sie, sobald sie angekommen sind. Das geht dann ohne ständige Serveranfragen.

Wenn Du aus einem Programm heraus z.B. das Feld dauernd aktualisieren wolltest, ohne dass der User dauernd klicken muss, ist das in einer erträglichen Geschwindigkeit nicht möglich, weil ständig der Netzwerkverkehr dazwischen ist, der ausbremst. Eine LED am µC kannst Du in Bruchteilen einer Sekunde hunderte Male ein- und ausschalten.

Allerdings wäre das, dies per HTML-Seite zu realisieren, die eleganteste Lösung, wenn jemand das dann ausprobieren möchte (dagegen stehen ca. 25,- für so ein beleuchtetes Originalpad in Größe 4x4 und das muss noch zusammengebaut werden, LEDs eingelötet werden).

MfG

HaWe
31.10.2019, 09:44
ja, stimmt, und daher sind zumindest unabhängige Threads für Gehirn (HAL-Schicht) und Steuerungs-Interface (Website, Display, Buttons) unerlässlich.

Ceos
31.10.2019, 09:46
Wenns nur Arduino sein soll, kann ich leider nicht direkt helfen

aber hier ein paar Links die vielversprechend aussehen für die "Server" Seite der Websockets auf Arduino Basis (sind aber ESP spezifisch):

https://tttapa.github.io/ESP8266/Chap14%20-%20WebSocket.html (Doku)
https://github.com/gilmaimon/ArduinoWebsockets (Quelle)

Ich habe es nur in Python und Flask gelöst, weil mir das persönlich einfacher fiel aber es war defintiv effektiver als ständiges Refresh eines versteckten div/frame

HaWe
31.10.2019, 09:55
Der ESP8266 scheidet doch aus, wie schon oben erklärt, da er kein MT kann. Man könnte dafür höchsten html-Seiten testen (d.h. zu reinen html-Testzwecken), aber kein NN aufbauen und steuern.
Ich programmiere aber nur in der Arduino-IDE, daher der ESP32 als Vorschlag, aber selbst das ist schon sehr aufwändig ohne Hardware-Keypad, und den kompletten html Teil müsste wer anders entwickeln und einbinden nach meinen Vorgaben, das macht es doppelt schwierig.

Und das heißt @Ceos:
echten Arduino-Code schreiben, den ich direkt kopieren+pasten kann, samt aller weiteren Änderungswünche.

PS,
Zeitkritisch sind hier allerdings v.a. die genannten Steuertasten (Senden, Lernmode, Erkennmode, ggf. auch weitere für ResetInputs, SD_Speichern und Pause) , nicht die 10x10 keypad-Matrix.

Weitere html-Funktionen kommen aber noch hinzu, wenn man kein gemeinsames TFT Display für Menüs hat und auch das über html laufen muss:

überschreiben? ja/nein
nicht gefunden: wiederholen/Abbruch
Netz-Ausgabewert: 123.4567
Wert korrekt? ja/nein/Abbruch

etc.

das kann ich zwar einfach über mein HX8357 TFT ausgeben, aber nur für dieses, denn es ist fest an meinem ESP32 angeschlossen.
A-Bär: man kann sich ja langsam Schritt für Schritt an diese Probleme herantasten.

Ceos
31.10.2019, 09:58
Ich habe die letzten Antworten noch nicht alle aufgeholt, ihr tippt schneller als man Beispiele suchen kann!


Und das heißt @Ceos:
echten Arduino-Code schreiben, den ich direkt kopieren+pasten kann, samt aller weiteren Änderungswünche.

deinen Anforderungen kann man ja nicht gerecht werden, dafür brauchte ich schon Bezahlung ....

so um jetzt hier einen Punkt damit zu machen nurnoch eine Sache:

Wenn ihr beide nicht immer so schnippisch Antworten würdet und euren Beißreflex mal im Zaum halten könntet, würdet ihr nicht ständig Gegenkommentare bekommen die das Topic "zerreden" oder Beispiele die das Thema "verwässern"

Packt euch mal an der eigenen Nase und bleibt bei euren Antworten einfach mal sachlich und nehmt einen Denkanstoss hin ohne dieses ständige "mach mal vor" hinten dran zu packen, das löst nämlich meinen Beißreflex aus, weil ich sowas einfach unverschämt finde (warum habe ich auch schon mehrfach erklärt)


NACHTRAG:


@Ceos,
das ist nicht schnippisch, hier hilft nur echter Code, und den zu schreiben macht zweifelsfrei eine Menge Arbeit, und anders geht es nicht.

Bis hierher geh ich konform und sehe dass du verstehst was ich meine.


Aso wenn du etwas postest:
bitte gerne echte Code, ansonsten bitte eher nichts.

Aber den hättest du einfach weglassen sollen, das ist GENAU das was ich unverschämt finde, LASS ES einfach

erneuter NACHTRAG:


das nichts auch noch nachträglich FETT zu machen setzt dem ganzen noch das Sahnehäubchen auf, du bist und bleibst unverbesserlich

HaWe
31.10.2019, 10:09
@Ceos,
das ist nicht schnippisch, hier hilft nur echter Code, und den zu schreiben macht zweifelsfrei eine Menge Arbeit, und anders geht es nicht.
Also wenn du etwas postest:
bitte gerne echten Arduino-C++-Code, ansonsten bitte eher nichts.

- - - Aktualisiert - - -

@Moppi:
könntest du denn auch auf einem ESP32 arbeiten?

Moppi
31.10.2019, 10:12
Wenn für Deine Software ein Multitasking notwendig ist, weil das aus Gründen der schnellen und einfachen Handhabung verschiedener Codeschnipsel für Dich unabdingbar ist, dann bist Du - für meine Begriffe - zu weit weg.
Es gibt auch tolle Neuronale Netze, die mit PC erstellt werden können, schnell anzulernen sind und praktisch toll sind (Stichwort NVIDIA). Das kann man hier auch vorstellen, aber nicht erwarten, dass dies jemand "Nachbauen" will oder auch nur ausprobieren.

Daher, weil Du auch sagst, dass wir so nicht weiter kommen, ohne hardwaretechnisch immens aufzurüsten, wende ich mich dem Thema Arduino zu und beschäftige mich etwas damit. Einen guten Link dazu gab es ja. Mal schauen, wie weit man damit kommt. Leider gibts hier offenbar keinen, der in der Lage wäre, das Thema Neuronales Netz für Bastler verständlich darzustellen und Projekte, angefangen vom Arduino UNO, über schnellere nodeMCUs mit mehr Speicherplatz und schließlich darüber hinaus verständlich darzustellen und zu beschreiben. Wenn man im Laufe der Entwicklung ableitet, dass man noch schnellere und noch mehr Speicherplatz und noch andere Technik (wie Multitasking) benötigt, ist das durchaus sinvoll und hat seine Berechtigung und macht dann auch Sinn.


Also gut. Das war ein Exkurs in die Richtung, scheitert bei mir aber am Multitasking.



MfG

- - - Aktualisiert - - -

Einen ESP32 habe ich _noch_ nicht. Der ist mir noch zu neu. Die meisten Leute haben wohl noch nodeMCUs der alten Generation im Schubfach. Ich meine mit 80MHz (?) und 1 MB Programmspeicher, sowie 3 MB für SPIFF müsste schon was machbar sein.

HaWe
31.10.2019, 10:34
ja, das stimmt leider, das NN (HAL-Module für isoliertes Muster-Training und -Auswerten) läuft zwar ohne MT, aber für die Steuerung (User-Interface, Dashboard) ist bei mir zusätzlich MT notwendig.

Moppi
31.10.2019, 11:24
... deinen Anforderungen kann man ja nicht gerecht werden, dafür brauchte ich schon Bezahlung ....

Meinst Du nicht, ceos, Du bist hier damit an der falschen Adresse?

Das hier sind Hobbybastler und mehr, in diesem Forum. Gerade versucht HaWe - aus seiner eignen Quellcodesammlung - was zur Verfügung zu stellen, was man nachvollziehen kann. Ich versuche ihn zu unterstützen und tue das praktisch, indem ich mich auch Stunden hinsetze und etwas zusammenbaue, was - eventuell - nützlich ist. Ich habe das kostenlos erledigt, damit wir hier voran kommen, in diesem Forum. Solche Threads sind wohl nicht geeignet, seine Fähigkeiten zu presentieren, indem man Links in die Runde wirft, die keine direkte Problemlösung bringen, um dann zu werben, dass man Geld haben möchte, wenn man sich hier beteiligt.




MfG

HaWe
31.10.2019, 11:59
danke, moppi!
aber bitte jetzt keine OT-Diskussionen darüber,
Code zum testen und Experimentieren aber immer gerne!

Ceos
31.10.2019, 12:08
Meinst Du nicht, ceos, Du bist hier damit an der falschen Adresse?

Das hier sind Hobbybastler und mehr, in diesem Forum. Gerade versucht HaWe - aus seiner eignen Quellcodesammlung - was zur Verfügung zu stellen, was man nachvollziehen kann. Ich versuche ihn zu unterstützen und tue das praktisch, indem ich mich auch Stunden hinsetze und etwas zusammenbaue, was - eventuell - nützlich ist. Ich habe das kostenlos erledigt, damit wir hier voran kommen, in diesem Forum. Solche Threads sind wohl nicht geeignet, seine Fähigkeiten zu presentieren, indem man Links in die Runde wirft, die keine direkte Problemlösung bringen, um dann zu werben, dass man Geld haben möchte, wenn man sich hier beteiligt.


Sich darüber aufregen dass Themen verwässert/zerredet werden und selber immer wieder Antworten provozieren ist aber auch nicht hilfreich. Für mich war das Thema eigentlich geklärt.

Ich habe bereits ewähnt es war ein Denkanstoß (aufgrund der von dir selbst erwähnten Leistungsproblematik und dem in meinen Augen sehr schlechten Vorschlag einen hidden Frame für Datentransfer zu nutzen) eine alternative Methode zu betrachten.

Einen eigenen Code aufbauen nur der Demo wegen wenn man es für den eigenen Ansatz selber erforschen und gleich anwenden könnte halte ich nicht unbedingt für Zielführend(vor allem wenn du mehr zeit damit verbringst den code aufgrund mangelnder Praxis in Arduino lauffähig zu bekommen als die eigentliche Funktion zu demonstrieren .... Wenn ich HaWe einen Teilcode schicke reicht es ihm nie aus, es muss auf seiner Hardware laufen, wobei ich nicht die identische habe und es immer deutlich mehr Zeit kostet etwas universal lauffähig zu machen als den funktionalen Code zu schreiben der die Anwendung demonstriert).

Ich war zwar schon dabei den Python Part aus meinem Fundus zu suchen aber es war scheinbar einfacher etwas (in herablassenden Ton) zu verlangen


Wenn Du es kannst: super! Mach bitte ein Beispiel für nodeMCU.

statt mal nachzusehen was das ist und ob man das anwenden kann. Und dann hatte ich auch keine Lust mehr und hab die Projekte zum nachlesen verlinkt. Auf die Aussage dass man für die NN Arduino braucht habe ich dann noch die passenden Arduino Referenzen für WebsocketsServer rausgesucht.

Du darfst gerne eine Seite zurück gehen und die Historie meines letzten Beitrages nachverfolgen. Es geht um die Art der Kommentierung und vor allem auch die wie nacheditiert wird um der dem eignen Gegenkommentar noch Nachdruck zu verleihen.

Mein Finaler Kommentar dazu ist nur, wenn du eine Idee gezeigt bekommst, erstmal reinsehen, bewerten und ignorieren oder sich damit befassen und ggf. Anwendungsbeispiele in höflichem Ton erfragen.

Aber schön dass wieder am Text vorbei gelobt wird.

HaWe
31.10.2019, 12:13
und jetzt bitte Schluss mit OT und zurück zum Topic!

Moppi
31.10.2019, 16:36
Um nochmal zurückzukommen:

Der Code ist momentan so gestaltet, dass man ein Bitfeld / Array / Matrix mit Nullen und Einsen beschickt oder daraus liest. Das entspricht dem Muster, das über den Browser eingegeben wurde. Klickt der User auf "ok" wird das Muster übertragen und kann dann also jederzeit verarbeitet werden. Wenn der Browser (per Refresh z.B. oder wenn der User einen Button klickt) die Seite neu lädt, wird das Muster im Browser ausgegeben.
Das Bitfeld kann also stets aktualisiert werden, unabhängig von der Darstellung. Die Darstellung im Browser ist dann nur nicht in Echtzeit möglich.

Ob das brauchbar ist, kannst nur Du entscheiden.



MfG

HaWe
31.10.2019, 16:47
dankeschön, ich teste es gerne noch mal !

was mir noch nicht klar ist:
wir haben ja insg. 10x10=100 keypad-Felder auf der html-Website.
Im Programm hätte ich einen array-buffer
float/buffArray[100];
zum temporären Speichen.

wo und wie kann ich die html-keypad-Werte auf diesen buffer-array übertragen zur Weiterverarbeitung,
und wie merkt meine loop(), ob per [ok/Senden] tatsächlich soeben neue keypad-Werte übertargen wurden?

Moppi
31.10.2019, 17:12
Guck mal in die ZIP-Datei aus Beitrag #6. Ich habe dort so gut erklärt, wie ich dachte, dass es notwendig ist.
Es fehlen, nach Deinen Angaben, sicherlich noch Buttons. Aber das wusste ich noch nicht, welche genau. Wenn das so nun doch nicht wirklich zu gebrauchen ist, müssen wir die auch nicht einbauen - logisch.
Wann was passiert, liegt an Deinem Programm. server.handleClient() sorgt für die Abwicklung auf Seite des Webservers, von allein passiert dort nichts. Wird das nicht immer wieder aufgerufen, gibt es
irgendwann einen Time-Out-Fehler im Webbrowser. Da der Bitpuffer / Array ... global zugänglich ist, solltest Du von überall her dort rein schreiben oder dort heraus lesen können. Besonderheit nur: Datentyp ist boolean



MfG

HaWe
31.10.2019, 18:01
hmm - danke, aber wie ich weiß, wann [ok/Senden] gedrückt wurde und wie ich dann die Daten auf meinen buffer übertrage, weiß ich dadurch immer noch nicht.

Wie schon gesagt, html- und webserver Code und was man wie damit anstellt ist nicht meine Welt...

der Buffer muss bei mir strenggenommen eigentlich float sein, aber das kann man ja umwandeln): (editiert)

float buffArray[100];

Moppi
31.10.2019, 18:10
wenn keine neuen Daten verfügbar sind, muss ich ja keine Daten von der website pollen, und die loop kann diesen Schritt überspringen.

Wenn es notwendig ist, kann das eingebaut werden.


der Buffer muss bei mir allerdings signed char sein

Das weiß ich nicht, ob Du die Daten von einem in das andere Array überträgst. Dachte ich mir so. Sonst kann man den auch auf char ändern, belegt dann aber ein Vielfaches mehr Speicherplatz.




MfG

HaWe
31.10.2019, 19:38
das mit bool oder char ist egal, wenn es sich um die Daten auf dem Server handelt.
Übertragen auf andere float-Arrays oder Matrizen muss ich es eh, weil nur die ersten 9 Zeilen (90 Werte) vom html-keypad für die Inputs sind und die 10. Zeile (10 Werte) für Ziel-Outputs, das muss man evtl auch flexibel anpassen (ggf. 8 Zeilen + 2 Zeilen etc.).
Ein NN rechnet aber grundsätzlich mit floats, nicht mit int, char oder bit.

Ich muss es nur zunächst übertragen auf lineare Arrays, aber nur dann, wenn Daten auch neu verfügbar sind (OK/senden-Button auf der website frisch gedrückt).

Ein bool Datentyp benötigt ja übrigens auch denselben Speicherplatz bei C/C++ ( stdbool.h ) wie ein char oder byte.
http://www.mrknowing.com/2013/10/08/datentypen-in-c-wertebereich-und-speichergroesse/

Moppi
31.10.2019, 20:00
Ein bool Datentyp benötigt ja übrigens auch denselben Speicherplatz bei C/C++ ( stdbool.h ) wie ein char oder byte.
Habe ich nicht mit gerechnet. Dann sag noch mal, was Du für einen Datentyp brauchst, dann sparen wir die Umwandlung.


Ich muss es nur zunächst übertragen auf lineare Arrays, aber nur dann, wenn Daten auch neu verfügbar sind (OK/senden-Button auf der website frisch gedrückt).
Ich habe eine Variable (bool isChange) eingebaut, zum Abfragen nach server.handleClient();

34435

MfG

HaWe
31.10.2019, 20:38
Auf der website fürs 10x10 keypad ist signed char oder bool ok.

(float oder double wäre hier übertrieben und wirklich ein Speicherfresser)

Die 100 website-keys müssen zeilenweise als Array durchgezählt sein von 0...99, nicht Reihe/Spalte.


0 1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
...


Die Übertragung muss dann zunächst so erfolgen (verkürzt, die echte Umwandlung ist etwas komplizierter und die mache ich später selber):

float bufferArray[100]; // global
//...
// Kopieren sobald neue Daten verfügbar:
for (int i=0; i<100; i++} { bufferArray[i]=(float)websiteKey[i]; }

ich komme aber mit dem Reinkopieren des neuen Schnipsels nicht klar.
Kannst du bitte den vollständigen, kompletten Code posten?
Am besten als Code in Code-Tags, kein zip-Anhang

Moppi
31.10.2019, 21:02
Die 100 website-keys müssen zeilenweise als Array durchgezählt sein von 0...99, nicht Reihe/Spalte.


Sind sie.




ich komme aber mit dem Reinkopieren des neuen Schnipsels nicht klar.
Kannst du bitte den vollständigen, kompletten Code posten?



:!: 34436



Auf neue Daten prüfen
if (isChange) ...


Kopieren sobald neue Daten verfügbar
for (int i=0; i<100; i++} { bufferArray[i]=(float)matrix[i]; }






MfG


PS:
Benutze lieber ZIPs, weil der Thread so leserlicher bleibt.
Ich habe im Thread nochmal etwas gelesen, ob noch irgendwas in den Code eingebaut werden soll, was ich übersehen habe.
Für das nodeMCU hatte ich ein kleines Projekt geplant. Aus diesem Grund kam ich überhaupt auf das Tastenfeld per HTML.
Du musst schauen, ob es so praktikabel ist, wenn nicht, dann nicht. Alle meine Projekte beginnen so, dass ich mit unbekannten
Dingen beginne oder mit denen, die am schwierigsten sein könnten; um frühzeitig ein Scheitern zu erkennen und dann abzubrechen.
Wenn Du das lieber anders lösen möchtest, als mit einer HTML-Seite, habe ich damit also keinerlei Problem. Alles i.O.

HaWe
01.11.2019, 10:42
zip Anhänge bringebn nichts, besser man kann es dirket lesen, um sich darüber zu verständigen.


float bufferArray[100];

uint32_t timestamp=0, sec=0;


void loop(void) {
server.handleClient();
// Kopieren sobald neue Daten verfügbar:
if (isChange) {
Serial.println("new data:");
for (int i = 0; i < 100; i++) {
bufferArray[i] = (float)matrix[i];
Serial.println((String)i + ": " + bufferArray[i]);
}
isChange=0;
}
if(millis()-timestamp >= 1000) {
sec++;
timestamp=millis();
Serial.println(sec);
}
}

OK in Change:OK umbenannt.

wie kann man jetzt (edit: ) 5 weitere Buttons hinzufügen, in dieser Reihenfolge
Clear

Learn
Detect

(Change:OK)

Reset
Save

wenn einer gedrückt wurde, soll er ebenfalls seinen Status senden, wie Change:OK:

isClear
isLearn
isDetect
(isChange)
isReset
isSave

das will ich dann versuchen für eine Statemachine zu nutzen.

- - - Aktualisiert - - -

edit, 5 weitere Buttons

Moppi
01.11.2019, 10:43
Du hattest das mit den Radio-Buttons schon mal angeführt. Das wäre eine Möglichkeit.

Das Feld könnte man so gestalten, nur am Ende einen Senden-Button, um die Daten der Form zu übertragen:

[ ] Learn
[ ] Detect
[ ] Reset

Change
[ ] Save

( Senden )


Leider ist mir die Bedeutung von der Bezeichnung "Change:Ok" nicht klar, also was das genau ausdrücken soll.




MfG

HaWe
01.11.2019, 11:50
Change:OK ist nur der neue Name des Buttons für (bisher) OK
s5 = "<input type="submit" value="Change: OK" style="width:14.9em;height:2em"></form>";

Clear

Detect <-> Learn

(Change:OK)

Reset
Save

"Change: OK" ist nur ein Arbeits-Name, könnte man auch "submit" oder "Change: submit" nennen.

Radio Buttons gehen nur für Learn/Detect
die anderen müssten eigene Buttons sein, die man wahlweise drücken kann.

späterer Zweck:
Clear soll einfach nur alle Keypad Felder der Website auf 0 zurücksetzen (so als hätte man die einzelnen X nochmal angeklickt) , ohne dass es neu gelernt oder erkannt wird (löschen aller bisherigen X)
Reset soll später alle bisherigen Lernschritte komplett löschen (mit Sicherheitsabfrage)
Save soll das bisher gelernte auf SD speichern (mit Sicherheitsabfrage)
(Load automatisch bei Programm-Neustart von SD)

- - - Aktualisiert - - -

PS, edit:
Radiobuttons für Detect/Learn könnten bei Umschalten z.B. entweder isLearn=1 oder isDetect=1 zurückliefern
(default wird sein: isLearn=0 und isDetect=1)
Learn schaltet in Lern-Mode
Detect in den Erkennungs-Mode
(evt. kann man das auch anders lösen, wie Radiobuttons funktionieren und was sie zurückgeben weiß ich ja auch noch gar nicht)

Moppi
01.11.2019, 12:57
Das nodeMCU mit seinen Bibliotheken hat mir einige Schwierigkeiten bereitet.
Die Radio-Buttons wollten nicht funktionieren; obwohl das HTML im Browser schon funktionierte,
nur nicht, nachdem das mit dem nodeMCU verschickt wurde. Hat mich den ganzen Vormittag gekostet :(

Also bin ich doch auf Buttons umgestiegen, Quelltext hier:
:!: 34437


Neu hinzugekommen sind:

bool isLearn
bool isDetect
bool isReset
bool isSave


In der Browserzeile kann man noch sehen, welche Parameter an das nodeMCU verschickt wurden.
Habe das so gelassen, weil man dann bei der Entwicklung etwas zum Kontrollieren hat.
Kann später geändert werden.


MfG

HaWe
01.11.2019, 14:57
danke, aber wie geagt:
zip Anhänge bringebn nichts, besser man kann es dirket lesen, um sich darüber zu verständigen.

Habe es getestet und noch etwas geändert + ergänzt, die Buttons werden jetzt richtig erkannt:



#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>


// Version 0.0.2

const char* ssid = "WLAN";
const char* password = "0.0.2";

ESP8266WebServer server(80);

//-----------------------------------------------------
//HTML und Daten für das Eingabe-/Ausgabefeld
//einfügen im globalen Scope
//-----------------------------------------------------
//erstellt von (c): Moppi @roboternetz.de
//-----------------------------------------------------
//Hintergrundfarbe Buttons, wenn aktiv
const String bColorActiv = "red";
//Breite und Höhe des ges. Feldes
const int tableWidth = 10;
const int tableHeight = 10;
//Füllzeichen für Felder
const String fillChar = "X";
//Parameter-Array enthält den Status aller Felder
//der Ein-/Ausgabematrix (0= AUS, 1= AN)
bool matrix[tableHeight*tableWidth]={0};
//Status, ob Änderungen vorliegen
bool toChange = 0;
bool toLearn = 0;
bool toDetect = 1;
bool toReset = 0;
bool toSave = 0;
bool toClear = 0;
//HTML
String body = "";
String s1="<style>\nform{margin:0}\n#un{width:0;height:0;visibility: hidden}\n#bu{width:10em;height:2em;}\n#rw{display: table-row;}\n#ce{display:table-cell;}\n#ip{width:1.5em;text-align:center;font-weight:bold}\n</style>\n<script>dge=document.getElementById; function oc(ob){if(ob.value=='')ob.value='"+fillChar+"';else ob.value='';}</script>\n<div role=\"presentation\" style=\"display:table\"><div id='rw'><div id='ce' style=\"padding-right:1em\"><form method=\"get\"><div role=\"presentation\" style=\"margin-bottom:1em;display:table\">";
String s2="<div id=\"rw\">";
String s3="<div id=\"ce\"><input onclick=\"oc(this);\" type=\"text\" name=\"b";
String s3_1="\" value=\"";
String s3_2="\" maxlength=\"1\" id=\"ip\"></div>";
String s4="</div>";
String s5="</div><div id='ce'><input id=\"bu\" type=\"submit\" value=\"Change:Ok\"><p></form>";
String s5_0="<form method=\"get\"><input id=\"bu\" type=\"submit\" value=\"Clear\"><input id=\"un\" type=\"text\" name=\"bn\" value=\"clear\"></form>";
String s5_1="<form method=\"get\"><input id=\"bu\" style=\"background-color:";
String s5_1n="\" type=\"submit\" value=\"Learn\"><input id=\"un\" type=\"text\" name=\"bn\" value=\"learn\"></form>";
String s5_2="<form method=\"get\"><input id=\"bu\" style=\"background-color:";
String s5_2n="\" type=\"submit\" value=\"Detect\"><input id=\"un\" type=\"text\" name=\"bn\" value=\"detect\"></form>";
String s5_3="<form method=\"get\"><input id=\"bu\" type=\"submit\" value=\"Reset\"><input id=\"un\" type=\"text\" name=\"bn\" value=\"reset\"></form>";
String s5_4="<form method=\"get\"><input id=\"bu\" type=\"submit\" value=\"Save\"><input id=\"un\" type=\"text\" name=\"bn\" value=\"save\"></form></div></div></div>";

String par="b";
//-----------------------------------------------------


float bufferArray[100];



//-----------------------------------------------------
//-----------------------------------------------------
void setup() {

Serial.begin(115200);
delay(1000);
Serial.println();

//-----------------------------------------------------
//Anmeldung am Netzwerk
//-----------------------------------------------------
Serial.println("connecting by IPAddress(192,168,2,99)");
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password); //begin WiFi connection
WiFi.config(IPAddress(192, 168, 2, 99), IPAddress(192, 168, 2, 1), IPAddress(192, 168, 2, 1), IPAddress(255, 255, 255, 0));

Serial.println("");

// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());


//-----------------------------------------------------
//Auswertung und Erstellung des Ein-/Ausgabefeldes
//-----------------------------------------------------
//Einbinden in setup() und in loop() nutzen durch
//Aufruf von "server.handleClient();"
//benötigt Objekt "server", erstellt im globalen Scope
//mittels: ESP8266WebServer server(80);
//benötigt auch: #include <ESP8266WebServer.h>
//-----------------------------------------------------
//erstellt von (c): Moppi @roboternetz.de
//-----------------------------------------------------
server.on("/",[]()
{
//Auswerten des Query-String vom Browser
int n = 0;
if(server.hasArg("bn")){
if(server.arg("bn") == "clear") toClear=1; else {toClear=0; toChange=0; for(int i=0; i<(tableWidth*tableHeight); i++) matrix[n] = 0;}
if(server.arg("bn") == "save") toSave=1; else toSave=0;
if(server.arg("bn") == "reset") toReset=1; else toReset=0;
if(server.arg("bn") == "detect") toDetect=1; else toDetect=0;
if(server.arg("bn") == "learn") toLearn=1; else toLearn=0;
}
for(int x=0; x < tableHeight; x++){
for(int j=0; j < tableWidth; j++){
if(server.hasArg(par+String(n))){
String a = server.arg(par+String(n));
bool ic = matrix[n];
if (a == "") matrix[n] = 0; else matrix[n] = 1;
if (ic != matrix[n]) toChange = 1;
n++;
}
if(toChange){
toClear = 0;
toSave = 0;
toReset = 0;
toDetect = 0;
toLearn = 0;
}
}
}
//Aufbau des Feldes
String v; body = s1; n = 0;
for(int x=0; x < tableHeight; x++){
body += s2;
for(int j=0; j < tableWidth; j++){
if (matrix[n]) v = fillChar; else v = "";
body += s3 + String(n) + s3_1 + v + s3_2;
n++;
}
body += s4;
}
body += s4+s5+s5_0+s5_1;
if (toLearn) body += bColorActiv;
body += s5_1n+s5_2;
if (toDetect) body += bColorActiv;
body += s5_2n+s5_3+s5_4;
//Senden der Seite an den Browser
server.send(200, "text/html", body);
}
);
//-----------------------------------------------------



//-----------------------------------------------------
//Webserver starten
//-----------------------------------------------------
server.begin();
Serial.println("Web server started!");

}


uint32_t timestamp=0, sec=0;
uint8_t modeLearn=0, modeDetect=0;

//-----------------------------------------------------
//-----------------------------------------------------
void loop() {
server.handleClient();
// Aktionen nach ButtonClick:
/*
if(toClear) {
Serial.println((String)"toClear="+toClear);
memset(matrix , 0, sizeof(matrix));
toClear=0;
}
*/
if (toChange) {
Serial.println("new data:");
for (int i = 0; i < 100; i++) {
bufferArray[i] = (float)matrix[i];
Serial.println((String)i + ": " + bufferArray[i]);
}
toChange=0;
}
if(toLearn){
modeLearn=1;
modeDetect=0;
Serial.println((String)"modeLearn="+modeLearn);
toLearn=0;
}
else
if(toDetect) {
modeLearn=0;
modeDetect=1;
Serial.println((String)"modeDetect="+modeDetect);
toDetect=0;
}
if(toReset) {
toLearn=0;
toDetect=1;
Serial.println((String)"toReset="+toReset);
toReset=0;
}
if(toSave) {
toLearn=0;
toDetect=1;
Serial.println((String)"toSave="+toSave);
toSave=0;
}
if(millis()-timestamp >= 1000) {
sec++;
timestamp +=1000;
Serial.println(sec);
}
}


jetzt will ich mal nach dem WE versuchen, das als Eingabe-Panel für ein NN zu nutzen!

- - - Aktualisiert - - -

PS,
auch
clear
funktioniert, es löscht alle X bei BtnClick,
nur wenn man kurz vorher OK gedrückt hat, muss man 2x clear drücken, damit man den Löschvorgang im Panel sieht.

- - - Aktualisiert - - -

noch eine Frage:
kann man in der Website erkennbar machen, ob gerade Lern-Mode oder Detect-Mode gewählt ist (vlt über die Änderung der entspr. Button-Farbe auf rot?)

Moppi
01.11.2019, 15:30
nur wenn man kurz vorher OK gedrückt hat, muss man 2x clear drücken, damit man den Löschvorgang im Panel sieht.

was soll bei clear passieren, der Puffer geleert? Dann machen wir das so, wusste ich ja nicht.


kann man in der Website erkennbar machen, ob gerade Lern-Mode oder Detect-Mode gewählt ist (vlt über die Änderung der entspr. Button-Farbe auf rot?)

Die Buttonfarbe kann geändert werden. Allerdings würde sie beim zweiten Klick zurückwechseln.



MfG

HaWe
01.11.2019, 15:54
ja, ich hatte es selber mit memset probiert, aber wie gesagt, manchmal braucht es einen 2.Klick



if(toClear) {
Serial.println((String)"toClear="+toClear);
memset(matrix , 0, sizeof(matrix));
toClear=0;
}


die Buttonfarbe müsste bei Learn und Detect konstant bleiben, ggf. abhängig von den beiden anderen Variablen
modeLearn
modeDetect
die nach den Buttonclicks entspr. gesetzt werden



// SNIP
if(toDetect) {
modeLearn=0;
modeDetect=1;
Serial.println((String)"modeDetect="+modeDetect);
toDetect=0;
}
if(toReset) {
toLearn=0;
toDetect=1;
Serial.println((String)"toReset="+toReset);
toReset=0;
}
// SNIP

Moppi
01.11.2019, 16:16
Probier mal diesen Code:


:!: 34441


Buttons färben sich, Puffer wird bei Clear gelöscht und der Status für die Buttons wird zurückgesetzt, wenn das Muster geändert wird.




MfG

HaWe
01.11.2019, 16:40
nochmal:
zip Anhänge bringebn nichts, besser man kann es dirket lesen, um sich darüber zu verständigen.

und: nein, es soll sich der Status von
Learn
Detect
nur dann ändern, wenn eine von beiden Tasten geclickt wurde, und dann dauerhaft so bleiben.
Wenn es vom Programm intern geändert wird, soll es sich entsprechend anpassen, damit man immer sieht, welcher Mode aktiv ist.
Der jeweilge Status wird gespeichert in den Variablen
modeLearn
modeDetect


wenn man frisch OK geklickt hat, muss man aber auch immer noch 2x Clear clicken, bis das Keypad gelöscht wird.


verwende jetzt mal bitte original meinen Code als Basis, weil ich mittlerweile schon ein aar Dinge abgewandelt habe, u.a. Variablennamen und auch void setup(void).



#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>

// Version 0.0.3


const char* ssid = "WLAN";
const char* password = "0.0.3";

ESP8266WebServer server(80);

//-----------------------------------------------------
//HTML und Daten für das Eingabe-/Ausgabefeld
//einfügen im globalen Scope
//-----------------------------------------------------
//erstellt von (c): Moppi @roboternetz.de
//-----------------------------------------------------
//Hintergrundfarbe Buttons, wenn aktiv
const String bColorActiv = "red";
//Breite und Höhe des ges. Feldes
const int tableWidth = 10;
const int tableHeight = 10;
//Füllzeichen für Felder
const String fillChar = "X";
//Parameter-Array enthält den Status aller Felder
//der Ein-/Ausgabematrix (0= AUS, 1= AN)
bool matrix[tableHeight*tableWidth]={0};
//Status, ob Änderungen vorliegen
bool toChange = 0;
bool toLearn = 0;
bool toDetect = 1;
bool toReset = 0;
bool toSave = 0;
bool toClear = 0;
//HTML
String body = "";
String s1="<style>\nform{margin:0}\n#un{width:0;height:0;visibility: hidden}\n#bu{width:10em;height:2em;}\n#rw{display: table-row;}\n#ce{display:table-cell;}\n#ip{width:1.5em;text-align:center;font-weight:bold}\n</style>\n<script>dge=document.getElementById; function oc(ob){if(ob.value=='')ob.value='"+fillChar+"';else ob.value='';}</script>\n<div role=\"presentation\" style=\"display:table\"><div id='rw'><div id='ce' style=\"padding-right:1em\"><form method=\"get\"><div role=\"presentation\" style=\"margin-bottom:1em;display:table\">";
String s2="<div id=\"rw\">";
String s3="<div id=\"ce\"><input onclick=\"oc(this);\" type=\"text\" name=\"b";
String s3_1="\" value=\"";
String s3_2="\" maxlength=\"1\" id=\"ip\"></div>";
String s4="</div>";
String s5="</div><div id='ce'><input id=\"bu\" type=\"submit\" value=\"Change:Ok\"><p></form>";
String s5_0="<form method=\"get\"><input id=\"bu\" type=\"submit\" value=\"Clear\"><input id=\"un\" type=\"text\" name=\"bn\" value=\"clear\"></form>";
String s5_1="<form method=\"get\"><input id=\"bu\" style=\"background-color:";
String s5_1n="\" type=\"submit\" value=\"Learn\"><input id=\"un\" type=\"text\" name=\"bn\" value=\"learn\"></form>";
String s5_2="<form method=\"get\"><input id=\"bu\" style=\"background-color:";
String s5_2n="\" type=\"submit\" value=\"Detect\"><input id=\"un\" type=\"text\" name=\"bn\" value=\"detect\"></form>";
String s5_3="<form method=\"get\"><input id=\"bu\" type=\"submit\" value=\"Reset\"><input id=\"un\" type=\"text\" name=\"bn\" value=\"reset\"></form>";
String s5_4="<form method=\"get\"><input id=\"bu\" type=\"submit\" value=\"Save\"><input id=\"un\" type=\"text\" name=\"bn\" value=\"save\"></form></div></div></div>";

String par="b";
//-----------------------------------------------------


float bufferArray[100];

void setup() {

Serial.begin(115200);
delay(1000);
Serial.println();

//-----------------------------------------------------
//Anmeldung am Netzwerk
//-----------------------------------------------------
Serial.println("connecting by IPAddress(192,168,2,99)");
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password); //begin WiFi connection
WiFi.config(IPAddress(192, 168, 2, 99), IPAddress(192, 168, 2, 1), IPAddress(192, 168, 2, 1), IPAddress(255, 255, 255, 0));

Serial.println("");

// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());


//-----------------------------------------------------
//Auswertung und Erstellung des Ein-/Ausgabefeldes
//-----------------------------------------------------
//Einbinden in setup() und in loop() nutzen durch
//Aufruf von "server.handleClient();"
//benötigt Objekt "server", erstellt im globalen Scope
//mittels: ESP8266WebServer server(80);
//benötigt auch: #include <ESP8266WebServer.h>
//-----------------------------------------------------
//erstellt von (c): Moppi @roboternetz.de
//-----------------------------------------------------
server.on("/",[]()
{
//Auswerten des Query-String vom Browser
int n = 0;
if(server.hasArg("bn")){
if(server.arg("bn") == "clear") toClear=1; else {toClear=0; toChange=0; for(int i=0; i<(tableWidth*tableHeight); i++) matrix[n] = 0;}
if(server.arg("bn") == "save") toSave=1; else toSave=0;
if(server.arg("bn") == "reset") toReset=1; else toReset=0;
if(server.arg("bn") == "detect") toDetect=1; else toDetect=0;
if(server.arg("bn") == "learn") toLearn=1; else toLearn=0;
}
for(int x=0; x < tableHeight; x++){
for(int j=0; j < tableWidth; j++){
if(server.hasArg(par+String(n))){
String a = server.arg(par+String(n));
bool ic = matrix[n];
if (a == "") matrix[n] = 0; else matrix[n] = 1;
if (ic != matrix[n]) toChange = 1;
n++;
}
if(toChange){
toClear = 0;
toSave = 0;
toReset = 0;
toDetect = 0;
toLearn = 0;
}
}
}
//Aufbau des Feldes
String v; body = s1; n = 0;
for(int x=0; x < tableHeight; x++){
body += s2;
for(int j=0; j < tableWidth; j++){
if (matrix[n]) v = fillChar; else v = "";
body += s3 + String(n) + s3_1 + v + s3_2;
n++;
}
body += s4;
}
body += s4+s5+s5_0+s5_1;
if (toLearn) body += bColorActiv;
body += s5_1n+s5_2;
if (toDetect) body += bColorActiv;
body += s5_2n+s5_3+s5_4;
//Senden der Seite an den Browser
server.send(200, "text/html", body);
}
);
//-----------------------------------------------------



//-----------------------------------------------------
//Webserver starten
//-----------------------------------------------------
server.begin();
Serial.println("Web server started!");

}


uint32_t timestamp=0, sec=0;
uint8_t modeLearn=0, modeDetect=0;

void loop() {
server.handleClient();
// Aktionen nach ButtonClick:
/*
if(toClear) {
Serial.println((String)"toClear="+toClear);
memset(matrix , 0, sizeof(matrix));
toClear=0;
}
*/
if (toChange) {
Serial.println("new data:");
for (int i = 0; i < 100; i++) {
bufferArray[i] = (float)matrix[i];
Serial.println((String)i + ": " + bufferArray[i]);
}
toChange=0;
}
if(toLearn){
modeLearn=1;
modeDetect=0;
Serial.println((String)"modeLearn="+modeLearn);
toLearn=0;
}
if(toDetect) {
modeLearn=0;
modeDetect=1;
Serial.println((String)"modeDetect="+modeDetect);
toDetect=0;
}
if(toReset) {
toLearn=0;
toDetect=1;
Serial.println((String)"toReset="+toReset);
toReset=0;
}
if(toSave) {
toLearn=0;
toDetect=1;
Serial.println((String)"toSave="+toSave);
toSave=0;
}
if(millis()-timestamp >= 1000) {
sec++;
timestamp +=1000;
Serial.println(sec);
}
}

Moppi
01.11.2019, 16:50
Irgendwas ist schief gegangen. Muss noch mal gucken.

Noch mal:

Wenn das Muster geändert wird und es wird mit Change:Ok übertragen, dann werden die Farben der Buttons zurückgesetzt.
Wenn das Muster gelöscht wird, passiert das, was bei Änderung geschieht, Learn und Detect müssen dann neu aktiviert werden.
Nicht so?

Soll der Status immer stehen bleiben, für isLearn, isDetect und isSave, sowie isReset?
Dann musst Du Dich um den Status dieser Buttons selber kümmern, denn irgendwann muss der wieder zurückgesetzt werden (wenn irgendein Button geklickt wird, werden die andern auch zurückgesetzt).

HaWe
01.11.2019, 17:08
Status muss nur für Detect und Learn gesetzt bleiben, je nachdem, was zuletzt geklickt wurde und wie es auch vom Programm selber geändert wurde (z.B. bei Save erfolgt immer zuerst ein Wechsel zu modeDetect, das selbe bei Reset)

Auch automatisierte NN-Routinen können später den Learn/Detect-Mode zwischendurch ändern.

Jede Änderung wird aber immer bei
modeDetect
modeLearn
im Programm aktualisiert.

Von sich aus dürfen andere Button-Clicks den Detect/Learn-Status nicht ändern, also auch nicht die Farbe der Learn/Detect-Buttons.


die Farbe aller anderen Buttons ist unwichtig, hier bleibt nichts gespeichert, sie sollen also immer grau bleiben.

- - - Aktualisiert - - -

die Variablen heißen jetzt auch anders:

toSave,
toDetect,
toClear,
...


daher bitte jetzt bei meinem eigenen Code verbessern!

Moppi
01.11.2019, 17:19
Ich habe Deinen Code geändert, aber nicht ausprobiert:



#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>


// Version 0.0.3




const char* ssid = "WLAN";
const char* password = "0.0.3";


ESP8266WebServer server(80);


//-----------------------------------------------------
//HTML und Daten für das Eingabe-/Ausgabefeld
//einfügen im globalen Scope
//-----------------------------------------------------
//erstellt von (c): Moppi @roboternetz.de
//-----------------------------------------------------
//Hintergrundfarbe Buttons, wenn aktiv
const String bColorActiv = "red";
//Breite und Höhe des ges. Feldes
const int tableWidth = 10;
const int tableHeight = 10;
//Füllzeichen für Felder
const String fillChar = "X";
//Parameter-Array enthält den Status aller Felder
//der Ein-/Ausgabematrix (0= AUS, 1= AN)
bool matrix[tableHeight*tableWidth]={0};
//Status, ob Änderungen vorliegen
bool toChange = 0;
bool toLearn = 0;
bool toDetect = 0;
bool toReset = 0;
bool toSave = 0;
bool toClear = 0;
//HTML
String body = "";
String s1="<style>\nform{margin:0}\n#un{width:0;height:0;visibility: hidden}\n#bu{width:10em;height:2em;}\n#rw{display: table-row;}\n#ce{display:table-cell;}\n#ip{width:1.5em;text-align:center;font-weight:bold}\n</style>\n<script>dge=document.getElementById; function oc(ob){if(ob.value=='')ob.value='"+fillChar+"';else ob.value='';}</script>\n<div role=\"presentation\" style=\"display:table\"><div id='rw'><div id='ce' style=\"padding-right:1em\"><form method=\"get\"><div role=\"presentation\" style=\"margin-bottom:1em;display:table\">";
String s2="<div id=\"rw\">";
String s3="<div id=\"ce\"><input onclick=\"oc(this);\" type=\"text\" name=\"b";
String s3_1="\" value=\"";
String s3_2="\" maxlength=\"1\" id=\"ip\"></div>";
String s4="</div>";
String s5="</div><div id='ce'><input id=\"bu\" type=\"submit\" value=\"Change:Ok\"><p></form>";
String s5_0="<form method=\"get\"><input id=\"bu\" type=\"submit\" value=\"Clear\"><input id=\"un\" type=\"text\" name=\"bn\" value=\"clear\"></form>";
String s5_1="<form method=\"get\"><input id=\"bu\" style=\"background-color:";
String s5_1n="\" type=\"submit\" value=\"Learn\"><input id=\"un\" type=\"text\" name=\"bn\" value=\"learn\"></form>";
String s5_2="<form method=\"get\"><input id=\"bu\" style=\"background-color:";
String s5_2n="\" type=\"submit\" value=\"Detect\"><input id=\"un\" type=\"text\" name=\"bn\" value=\"detect\"></form>";
String s5_3="<form method=\"get\"><input id=\"bu\" type=\"submit\" value=\"Reset\"><input id=\"un\" type=\"text\" name=\"bn\" value=\"reset\"></form>";
String s5_4="<form method=\"get\"><input id=\"bu\" type=\"submit\" value=\"Save\"><input id=\"un\" type=\"text\" name=\"bn\" value=\"save\"></form></div></div></div>";

String par="b";
//-----------------------------------------------------




float bufferArray[100];


void setup(void) {


Serial.begin(115200);
delay(1000);
Serial.println();


//-----------------------------------------------------
//Anmeldung am Netzwerk
//-----------------------------------------------------
Serial.println("connecting by IPAddress(192,168,2,99)");
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password); //begin WiFi connection
WiFi.config(IPAddress(192, 168, 2, 99), IPAddress(192, 168, 2, 1), IPAddress(192, 168, 2, 1), IPAddress(255, 255, 255, 0));


Serial.println("");


// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());




//-----------------------------------------------------
//Auswertung und Erstellung des Ein-/Ausgabefeldes
//-----------------------------------------------------
//Einbinden in setup() und in loop() nutzen durch
//Aufruf von "server.handleClient();"
//benötigt Objekt "server", erstellt im globalen Scope
//mittels: ESP8266WebServer server(80);
//benötigt auch: #include <ESP8266WebServer.h>
//-----------------------------------------------------
//erstellt von (c): Moppi @roboternetz.de
//-----------------------------------------------------
server.on("/",[]()
{
//Auswerten des Query-String vom Browser
int n = 0;
if(server.hasArg("bn")){
if(server.arg("bn") == "clear") {toClear=1; for(int i=0; i<(tableWidth*tableHeight); i++) matrix[i] = 0;} else {toClear=0; toChange=0;}
if(server.arg("bn") == "save") toSave=1; else toSave=0;
if(server.arg("bn") == "reset") toReset=1; else toReset=0;
if(server.arg("bn") == "detect") toDetect=1; // else toDetect=0;
if(server.arg("bn") == "learn") toLearn=1; // else toLearn=0;
}
for(int x=0; x < tableHeight; x++){
for(int j=0; j < tableWidth; j++){
if(server.hasArg(par+String(n))){
String a = server.arg(par+String(n));
bool ic = matrix[n];
if (a == "") matrix[n] = 0; else matrix[n] = 1;
if (ic != matrix[n]) toChange = 1;
n++;
}
/* //Status aller Buttons zurücksetzen, wenn das Muster mit Change:Ok geändert wurde
if(toChange){
toClear = 0;
toSave = 0;
toReset = 0;
toDetect = 0;
toLearn = 0;
}
*/
}
}
//Aufbau des Feldes
String v; body = s1; n = 0;
for(int x=0; x < tableHeight; x++){
body += s2;
for(int j=0; j < tableWidth; j++){
if (matrix[n]) v = fillChar; else v = "";
body += s3 + String(n) + s3_1 + v + s3_2;
n++;
}
body += s4;
}
body += s4+s5+s5_0+s5_1;
if (toLearn) body += bColorActiv;
body += s5_1n+s5_2;
if (toDetect) body += bColorActiv;
body += s5_2n+s5_3+s5_4;
//Senden der Seite an den Browser
server.send(200, "text/html", body);
}
);
//-----------------------------------------------------






//-----------------------------------------------------
//Webserver starten
//-----------------------------------------------------
server.begin();
Serial.println("Web server started!");


}




uint32_t timestamp=0, sec=0;
uint8_t modeLearn=0, modeDetect=0;


void loop(void) {
server.handleClient();
// Aktionen nach ButtonClick:
/*
if(toClear) {
Serial.println((String)"toClear="+toClear);
memset(matrix , 0, sizeof(matrix));
toClear=0;
}
*/
if (toChange) {
Serial.println("new data:");
for (int i = 0; i < 100; i++) {
bufferArray[i] = (float)matrix[i];
Serial.println((String)i + ": " + bufferArray[i]);
}
toChange=0;
}
if(toLearn){
modeLearn=1;
modeDetect=0;
Serial.println((String)"modeLearn="+modeLearn);
toLearn=0;
}
else
if(toDetect) {
modeLearn=0;
modeDetect=1;
Serial.println((String)"modeDetect="+modeDetect);
toDetect=0;
}
if(toReset) {
toLearn=0;
toDetect=1;
Serial.println((String)"toReset="+toReset);
toReset=0;
}
if(toSave) {
toLearn=0;
toDetect=1;
Serial.println((String)"toSave="+toSave);
toSave=0;
}
if(millis()-timestamp >= 1000) {
sec++;
timestamp +=1000;
Serial.println(sec);
}
}

Ich habe das hier nochmal, wie es bei mir funktionierte:
:!: 34442


Teile des Programms sind auskommentiert, also nicht entfernt, falls man die Funktion doch wieder ändern will.
Ich habe weitestgehend Verständnis, für die Änderungen. Aber irgendwann blicke ich dann durch meinen eigenen Code nicht mehr durch,
weil Du Änderungen drin vornimmst.



MfG

HaWe
01.11.2019, 17:51
leider nein,
wenn das Programm den mode ändert (z.B. bei Reset), dann wird dir Learn-/Detect-Buttonfarbe nicht aktualisiert, sondern grau gemacht.
und wenn man Clear drückt, und dann auf OK, dann wird das komplett gelöschte Feld nicht übertragen, sondern das alte, vorherige.

Aber auch nach OK wird immer noch die Farbe von Detect/Learn auf grau zurückgesetzt, das darf auch nicht sein, denn hier werden Learn/Detect-Status ja überhaupt nicht geändert.

Und bitte keine zip-Anhänge!!

Teste es mal selber aus!
Man erkennt es am einfachsten, wenn man die letzten untersten Felder verändert.

Im Serial Monitor werden die Buttonclicks auch angezeigt,
dann das aktuell übertragene Keypad-Feld
und ebenfalls der jew. aktuelle, neu gesetzte Learn/Detect-Mode.


mein ursprünglicher Button-Clear Code ist übrigens inzwischen auskommentiert., daher wird Button Clear-Click nicht mehr seriell angezeigt
- vlt kannst du es für deine Änderungen wider mit verwenden:


/*
if(toClear) {
Serial.println((String)"toClear="+toClear);
memset(matrix , 0, sizeof(matrix));
toClear=0;
}
*/



- - - Aktualisiert - - -
Deine Version im Anhang hat nicht meine Änderungen mit übernommen, ich kann es jetzt nicht mehr genau so laufen lassen.
Bitte verwende immer meine Änderungen mit und verändere bitte immer nur meinen geposteten Code samt Versions-Nummer, sonst kommt alles durcheinander!

Insb. die loop solltest du immer mit verwenden, denn hier läuft der Serial Monitor zum Debuggen, aber auch in setup ist was geändert, und zusätzlich gibt es weitere Variablen.

Der Code wächst ja immer weiter...

Wenn du nicht mehr durchblickst, starte nochmal bei Version 0.0.2
https://www.roboternetz.de/community/threads/74178-html-Code-f%C3%BCr-virtuelles-website-Button-Pad?p=655984&viewfull=1#post655984

Moppi
01.11.2019, 18:43
Wenn du nicht mehr durchblickst, starte nochmal bei Version 0.0.2
https://www.roboternetz.de/community/threads/74178-html-Code-f%C3%BCr-virtuelles-website-Button-Pad?p=655984&viewfull=1#post655984


Neeee, das ist keine gute Idee! *lol*

Also ich programmier ja quasi ein Modul, das hat eine Schnittstelle.
Die kannst Du gerne benutzen, aber nicht den internen Code des Moduls umschreiben! :)

Für mich ist im Modul wichtig, dass isChange auch isChange bedeutet. Das kann ich zwar toChange ändern, aber nach dieser definition dürfte sich dann in meinem Modul der Pufferinhalt (matrix) nicht ändern.
Ich spiegele den Status wieder, nicht das, was außerhalb des Moduls damit mal passieren soll.
Aber ich wollte diesmal nicht so sein, drum hab ich es so geändert, wie Du es Dir vorstellst, obwohl Du den Modulcode nicht schreibst - sonst brauch ich das ja nicht machen.

Ich schau nochmal rein....

Ich orientiere mich jetzt mal daran, was Du geschrieben hast:

wenn das Programm den mode ändert (z.B. bei Reset), dann wird dir Learn-/Detect-Buttonfarbe nicht aktualisiert, sondern grau gemacht.
und wenn man Clear drückt, und dann auf OK, dann wird das komplett gelöschte Feld nicht übertragen, sondern das alte, vorherige.

Aber auch nach OK wird immer noch die Farbe von Detect/Learn auf grau zurückgesetzt, das darf auch nicht sein, denn hier werden Learn/Detect-Status ja überhaupt nicht geändert.



wenn das Programm den mode ändert (z.B. bei Reset), dann wird dir Learn-/Detect-Buttonfarbe nicht aktualisiert, sondern grau gemacht

aktueller Status bei mir:
LEARN und DETECT bleiben immer Rot, egal, was passiert / gedrückt wird
.
.
.
und wenn man Clear drückt, und dann auf OK, dann wird das komplett gelöschte Feld nicht übertragen, sondern das alte, vorherige

aktueller Status bei mir:
Das Feld wird gelöscht und bleibt gelöscht.





Falls es da Mißverständnisse gibt, kann ich ein Video machen (zwar schwierig alleine, aber vielleicht bekomme ich es hin) zum Anschauen.

Hat geklappt, hier das Video
https://youtu.be/yWqrUk5nDK4


MfG

.

HaWe
01.11.2019, 19:04
ich habe ja dein Modul verwendet, aber auch mein Code außen rum ändert sich mit, nachdem du dein Modul angepasst hast.
es muss also immer alles per Handshake gehen:
deine Änderungen
meine neuen Änderungen
deine Änderungen meiner neuen Änderungen
....
usw.

auch setup und loop samt Variablen und Zusatzfunktionen werden ja ebenfalls weiterentwickelt.
Nur eine Kleinigkeit: aber z.B. in setup() sollte Serial als erstes gestartet werden, danach delay(1000), damit man auch WLAN und webserver seriell debuggen kann.

Am besten, du passt bei deinen Änderungen dann auch die Versionsnummer an.

- - - Aktualisiert - - -

PS,
bitte ändere nicht deine oberen Posts, wenn ich bereits darauf geantwortet habe, denn ich lese normalerweise oben nicht mehr nach.

das mit den zip Files macht auch keinen Sinn, bitte immer "Klartext"-Code.
der letzte Klartext-Code, den ich verwenden konnte, war der hier
https://www.roboternetz.de/community/threads/74178-html-Code-f%C3%BCr-virtuelles-website-Button-Pad?p=656003&viewfull=1#post656003

allerdings sollte er Versionsnummer 0.0.4 tragen nach deinen Änderungen.
Er war aber noch fehlerhaft, wie beschrieben.

Videos bringen nichts, das kann ich nicht recht erkennen.

- - - Aktualisiert - - -



PPS,
Ergänzung, nach deiner Änderung:






mein Programm ändert (auch) intern den Lern/Detect-Modus, ohne dass ein Button gedrückt wurde.
Auch dann muss es das Panel erkennen und den neuen Modus rot kennzeichnen.

Moppi
01.11.2019, 19:16
Ich sehe nicht, ob Du schon geantwortet hast. Kannst ja auch mal 15min warten, ob sich mein Beitrag noch ändert.
Leider fallen immer wieder noch mehr Sachen ein, wenn ich eigentlich schon fertig geschrieben habe. ;)




MfG

- - - Aktualisiert - - -

Bevor wir jetzt weiter machen, warte ich, bis das Video hoch geladen ist, dauert noch ca. 25min.
Dann kannst Du mal schauen, und wir können uns verständigen. Gerne auch dann mit Angabe der Position (mm:sec) im Video.




MfG

- - - Aktualisiert - - -

Was die Änderungen und das Weiterentwickeln angeht:
Ich habe den Code extra optisch gekapselt, dass man die Module erkennt und einfach austauschen kann.
Ich wollte mir das Drama jetzt mit den LIBs "*.h" etc. ersparen, weil ich darin noch ungeübt bin.
Daher sollte es einfach sein, auch in einem riesigen Quelltext, diese beiden Sachen zu finden und auszutauschen.
Da muss man nicht jedesmal den gesamten Quelltext über's Forum schicken - dachte ich mir so.

HaWe
01.11.2019, 19:42
ich kann nicht deine Änderungen in meinen Code einarbeiten, wenn du meine vorherigen Änderungen nicht ebenfalls mit übernommen hast.
Es sind oft vielfältige Änderungen, hier und da.

bitte auch nicht einen Post nachträglich ändern, sondern zusätzlich antworten.

- - - Aktualisiert - - -

drücke mal die "Learn" Taste: Learn wird rot, das stimmt;
und dann die "Save" Taste
und schau, ob sich die Farbe von Learn und Detect Button ändern
Das müssen sie nämlich (Detect->rot und Learn->grau)

das selbe bei Reset.


guck bitte auch warum: nämlich was da in loop() und im Serial Monitor passiert.

- - - Aktualisiert - - -


ich beziehe mich auf Klartext-Code in https://www.roboternetz.de/community...l=1#post656003
(bei dir Version 0.0.3, eigentlich aber Version 0.0.4)

Moppi
01.11.2019, 19:51
Da Du oben/vorher nicht mehr liest, schreibe ich es nochmals hier, dass das Video hochgeladen ist:

https://youtu.be/yWqrUk5nDK4



MfG

- - - Aktualisiert - - -


ich kann nicht deine Änderungen in meinen Code einarbeiten, wenn du meine vorherigen Änderungen nicht ebenfalls mit übernommen hast.


Ich brauche Deine Änderungen nicht übernehmen. Du sollst nichts an meinem Code ändern. Machst Du das nicht, muss ich es auch nicht übernehmen.
Das erschwert die Zusammenarbeit ... leider ... ich suche mir das auch nicht aus.
In einer Firma mit 30 Programmierern wäre das auch nicht anders möglich. Da verlässt Du Dich auf den Code des andern Kollegen und benutzt die Schnittstelle,
dafür heißen die Teile so (gut, jetzt haben wir hier keine Eindeutige, aber ich habe mich sehr bemüht, die Variablen, die nach außen hin zu interessieren haben,
ganz nach oben zu stellen und habe sie kommentiert (damit wir es einfacher haben, in Deutsch). Und wenn was an dem Modul des Kollegen funktionell nicht passend
ist, teilt man das dem mit und er ändert das demnächst. Aber man nimmt nicht seinen Code, ändert den, gibt ihm den zurück und sagt: übernimm diese, meine Änderungen,
die ich angebracht habe.

Ich schaue gleich weiter ...


MfG
.

HaWe
01.11.2019, 20:08
um es nochmal zu verdeutlichen:
der Farbwechsel darf nicht stattfinden, weil ein Button im Formular gedrückt wurde,
sondern einzig und allein, weil im Code steht
modeDetect=1/0
oder
modeLearn=1/0.


Ich muss deinen Code ändern können, denn dein Code muss auf meinen Code passen und reagieren.

Ich brauche deinen Code auch nicht als unveränderliche Schnittstelle, sondern als integralen Bestandteil MEINES Codes.

- - - Aktualisiert - - -

zum Video:
man sieht nach Druck auf Clear nicht, was im Serial Monitor passiert, da wird der Fehler nämlich offensichtlich!
markiere die beiden letzten Felder,
drücke OK,
kontrolliere im Serial Monitor.

drücke Clear, drücke OK,
kontrolliere im Serial Monitor:
hier sind immer noch die letzten 2 Felder markiert.

es dürfen auch nicht sowohl Learn als auch Detect Button gleichzeitg beide rot oder beide grau sein, bedingt durch die Variablen
modeLearn und modeDetect.

GGf. poste bitte deinen neuen Code samt meiner Ergänzungen (Version 0.0.5)

Moppi
01.11.2019, 20:10
drücke mal die "Learn" Taste: Learn wird rot, das stimmt;
und dann die "Save" Taste
und schau, ob sich die Farbe von Learn und Detect Button ändern
Das müssen sie nämlich (Detect->rot und Learn->grau)


Das weiß ich nicht, warum das passiert.

Fakt ist: Du kannst NICHTS eigenständig zum Browser schicken, der das dann ausführt.
Du bist immer drauf angewiesen, dass der User eine Aktion im Browser ausführt, worauf reagiert werden kann.

Du musst wissen, welche Funktionalität da sein soll. Das meiste davon werde ich in meinem Modul einbauen können.
Dass also bestimmte Buttons bestimmte Farben bekommen. Habe ich gemacht.
Irgendwo hast Du doch geschrieben, der Status der Buttons darf sich nicht ändern. Oder so ähnlich.
Wie soll das dann jetzt gemacht werden?

Da musst Du jetzt eine Wahrheitstabelle erstellen, wo die Abhängigkeit der Buttons draus hervorgeht.
Das so wild dort rein zu programmieren, führt ins Chaos und zu nicht funktionierendem Code. Da jagt dann ein
Problem das andere und die Katze beißt sich am Ende in den Schwanz ... und es vergehen Stunden um Stunden dabei.

Und deswegen werde ich dann auch die Variablen zurückändern, weil sonst die Logik in meinem Code hinten und vorne
irgendwann nicht mehr stimmt und ich nicht mehr weiß, was an welcher Stelle mit welcher Variable gemeint ist.


ok .... so weit



MfG

HaWe
01.11.2019, 20:22
Du scheinst nicht zu verstehen, wann sich ein modeStatus ändert und wann nicht und wann und wie darauf die Button-Farbe zu reagieren hat.
Auch scheint dein Code nach Clear und OK die falschen Were zu übertragen (wie beschrieben).

Aber ok, wenn das so ist, dass der Browser nicht Aktionen des eigenständigen, automatischen Codes ebenfalls anzeigen kann, dann macht das ganze keinen Sinn.
Und wenn du meine Änderungen nicht übernimmst und passend weiter verarbeitest, auch nicht.
Dann kann ich aber dein jetziges html ButtonPad auch nicht fürs NN verwenden.

Moppi
01.11.2019, 22:01
Du scheinst nicht zu verstehen, wann sich ein modeStatus ändert und wann nicht und wann und wie darauf die Button-Farbe zu reagieren hat.

Antwort: nein



Um dem Wirrwarr zu entgehen, habe ich mich nun noch einige Zeit
hingesetzt und es etwas durchsichtiger gemacht, sowie geändert.
Wenn das sinnvoll weiter verfolgt werden soll, ist das notwendig.


Ich habe das alles in eine Datei gepackt:
:!: 34446

und in noch eine:

:!: 34447





MfG

- - - Aktualisiert - - -


Und wenn du meine Änderungen nicht übernimmst und passend weiter verarbeitest, auch nicht.
Dann kann ich aber dein jetziges html ButtonPad auch nicht fürs NN verwenden.


Du wolltest, dass ich etwas in HTML mache. Habe ich getan. Zudem gebe ich mir alle Mühe und mache mir viele Gedanken,
wie wir das in den Griff bekommen, dass einerseits auf die User-Aktionen reagiert und die HTML-Datei entsprechend versendet wird
und andererseits Du aber in die Lage versetzt wirst, darauf Einfluss zu nehmen.

Worauf Du keinen Einfluss nehmen kannst: auf den Status, ob und was für einen Button der User angeklickt hat.
Deshalb auch auf diese Variablen nicht. Du kannst sie auslesen, aber nicht deren Namen ändern. Du kannst sie auch
überschreiben, was aber keinen Sinn macht. Sie sollen nur dazu dienen, dass Du in Erfahrung bringen kannst, ob und was der User
will.

Ich habe weitere Variablen eingeführt, die Dir Kontrolle und Einfluss erlauben. Du kannst nun Einfluss nehmen, ob der Inhalt der
neuen Variablen stateLearn und stateDetect - abhängig von der Nutzeraktion -geändert wird oder nicht und kannst
diese Variablen selbst ändern, darüber wird auch die Farbe der Buttons bestimmt, damit der Status dieser Variablen (Buttons)
für den Nutzer optisch ersichtlich ist.

Ich hoffe, dass wir damit ein gutes Stück besser voran kommen!



MfG

- - - Aktualisiert - - -

Wenn Du sonst für Buttons noch einen festen Status brauchst, der eben nicht abhängig vom User-Klick geändert wird, sondern für Deinen weiteren Programmablauf erhalten bleibt, solltest Du diese Variableninhalte in für Dich brauchbare Variablen, deren Namen Du dann selbst in Deinem Code bestimmen kannst, kopieren/übernehmen.

HaWe
02.11.2019, 10:19
zip Anhänge bringebn nichts, besser man kann es dirket lesen, um sich darüber zu verständigen!!
Und es muss vollständiger Code sein!! (Komplettes Program!!)

ich will versuchen, dir noch mal den Grund zu erklären:

als reines Keypad ist die Website grundsätzlich OK,
und Zusatzbuttons zur Steuerung funktionieren grundsätzlich auch.
Was die Buttons für die Zustands-Modi angeht, so müssen die allerdings angezeigt werden, und hier kommen zu
Detect, Training
noch mindestens 2 weitere dazu: Upload und Pause,
und zwischen diesen Zuständen wird hin- und her geschaltet (immer nur 1 davon ist aktiv).

Diese Zustandsmodi werden allerdings auch vom laufenden Programm selbstständig, automatisch gesetzt und geändert, nicht nur vom User auf der Website, und wenn man neue Daten eingibt, muss man wissen, in welchem Zustand das Programm gerade ist (Zustandsautomat).
Wenn das über die Website nicht geht (Farbänderung der entspr. Buttons ,oder ggf eine Meldezeile), dann muss dies auf einem Display erfolgen und über GPIO-LEDs.

Mein M3 Due früher hatte viel RAM (mehr als der esp8266), genügend GPIOS (70), ein 2,8"" Farb-Display und konnte MT, darüber ging es, war aber per Menüsteuerung trotzdem sehr verschachtelt.
Mein ESP8266 hat nicht genügend freie Pins, eine SD-Karte braucht 4, und mein i2c-OLED 2 weitere, außerdem ist dieses eigentlich zu mickrig zur autonomen Steuerung: Hier bleiben also dann schon gar keine GPIOs mehr übrig für LEDs und Taster.
Fazit:
wenn man eine html-Website nicht auch als Dashboard zur Programmstatusanzeige verwenden kann, braucht man einen anderen Prozessor mit WiFi, mehr GPIOs, zusätzlichen GPIO-Tastern und einem großen TFT, und das kann dann nur ein ESP32 oder ein Raspi sein, und beide können ja auch MT.

Darüberhinaus muss ich in der Lage sein, Variablennamen zu ändern, wenn es nötig ist.
isSave ist missverständlich, da es nichts "ist", sondern nur einen btn-press signalisiert, wodurch etwas getan werden soll.
eigentlich wäre dann sogar etwas anderes wie btn_Save_press besser, analog auch btn_Clear_press usw., damit der Code später unmissverständlich bleibt.
Zusätzlich muss ich die Reihenfolge und Anordnung der Buttons samt ihrer Variablen für die Zwecke der NN-Steuerung ändern können, und das muss dann so bleiben.

Dein letzter zip Anhang ist wie geesagt nicht nutzbar für mich, da er nicht meinen eigenen Code samt Test- und Debugroutinen mit eingearbeitet hat und noch nicht einmal lauffähig ist. Auch hast du die Variablennamen zurück-geändert, wodurch sie jetzt nicht mehr zu meinem Testcode passen.

Ich werde daher wschl auf Version 0.0.2a zurückgehen, ohne Farbänderung der Buttons (denn das geht ja eh nicht programmseitig) und muss sehen, ob ich Teile der Buttons auf ein TFT/OLED-Display-Menü übertrage, samt Zustandsanzeige.

Am WE jetzt bin ich viel unterwegs, höchstens zwischenzeitlich mal am PC (aber dann ohne ESP8266) wschl also erst im Lauf der kommen den Woche.

Ob ich das ganze also hinkriege, dass auch du das NN am esp8266 benutzen kannst, ist ziemlich unsicher, vermutlich vlt eher nicht, ich selber würde meinem Adafruit Feather ESP32 mit 3,5" TFT bessere Chancen einräumen, und selbst das wird viele Wochen Arbeit bedeuten.

- - - Aktualisiert - - -

was allerdings schön wäre: ein Bugfix für Version 0.0.2a, sodass ein Clear-Press nach Daten-OK/submit sofort das Keypad leert, nicht erst nach 2x, und es auch nicht nur scheinbar leert wie bei Version 0.0.3/4:
sondern nach XXX Daten OK/submit, dann Clear-Press und dann unmittelbarem Click auf OK/submit dann auch wirklich sofort ein leeres Feld übertragen wird und nicht doch noch mal der vorher ungelöschte Inhalt.


#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>


// Version 0.0.2a

const char* ssid = "WLAN";
const char* password = "1234567";

ESP8266WebServer server(80);

//-----------------------------------------------------
//HTML und Daten für das Eingabe-/Ausgabefeld
//einfügen im globalen Scope
//-----------------------------------------------------
//erstellt von (c): Moppi @roboternetz.de
//-----------------------------------------------------
//Breite und Höhe des ges. Feldes
const int tableWidth = 10;
const int tableHeight = 10;
//Füllzeichen für Felder
const String fillChar = "X";
//Parameter-Array enthält den Status aller Felder
//der Ein-/Ausgabematrix (0= AUS, 1= AN)
bool matrix[tableHeight*tableWidth]={0};
//Status, ob Änderungen vorliegen
volatile static bool toChange = 0;
volatile static bool toLearn = 1;
volatile static bool toDetect = 0;
volatile static bool toReset = 0;
volatile static bool toSave = 0;
volatile static bool toClear = 0;
//HTML
String body = "";
String s1="<style>\nform{margin:0}\n#un{width:0;height:0;visibility: hidden}\n#bu{width:10em;height:2em;}\n#rw{display: table-row;}\n#ce{display:table-cell;}\n#ip{width:1.5em;text-align:center;font-weight:bold}\n</style>\n<script>dge=document.getElementById; function oc(ob){if(ob.value=='')ob.value='"+fillChar+"';else ob.value='';}</script>\n<div role=\"presentation\" style=\"display:table\"><div id='rw'><div id='ce' style=\"padding-right:1em\"><form method=\"get\"><div role=\"presentation\" style=\"margin-bottom:1em;display:table\">";
String s2="<div id=\"rw\">";
String s3="<div id=\"ce\"><input onclick=\"oc(this);\" type=\"text\" name=\"b";
String s3_1="\" value=\"";
String s3_2="\" maxlength=\"1\" id=\"ip\"></div>";
String s4="</div>";
String s5="</div><div id='ce'><input id=\"bu\" type=\"submit\" value=\"Change:Ok\"><p></form>";
String s5_0="<form method=\"get\"><input id=\"bu\" type=\"submit\" value=\"Clear\"><input id=\"un\" type=\"text\" name=\"bn\" value=\"clear\"></form>";
String s5_1="<form method=\"get\"><input id=\"bu\" type=\"submit\" value=\"Learn\"><input id=\"un\" type=\"text\" name=\"bn\" value=\"learn\"></form>";
String s5_2="<form method=\"get\"><input id=\"bu\" type=\"submit\" value=\"Detect\"><input id=\"un\" type=\"text\" name=\"bn\" value=\"detect\"></form>";
String s5_3="<form method=\"get\"><input id=\"bu\" type=\"submit\" value=\"Reset\"><input id=\"un\" type=\"text\" name=\"bn\" value=\"reset\"></form>";
String s5_4="<form method=\"get\"><input id=\"bu\" type=\"submit\" value=\"Save\"><input id=\"un\" type=\"text\" name=\"bn\" value=\"save\"></form></div></div></div>";
String par="b";
//-----------------------------------------------------


float bufferArray[100];


//-----------------------------------------------------
//-----------------------------------------------------
void setup() {

Serial.begin(115200);
delay(1000);
Serial.println();

//-----------------------------------------------------
//Anmeldung am Netzwerk
//-----------------------------------------------------
Serial.println("connecting by IPAddress(192,168,2,99)");
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password); //begin WiFi connection
WiFi.config(IPAddress(192, 168, 2, 99), IPAddress(192, 168, 2, 1), IPAddress(192, 168, 2, 1), IPAddress(255, 255, 255, 0));

Serial.println("");

// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());


//-----------------------------------------------------
//Auswertung und Erstellung des Ein-/Ausgabefeldes
//-----------------------------------------------------
//Einbinden in setup() und in loop() nutzen durch
//Aufruf von "server.handleClient();"
//benötigt Objekt "server", erstellt im globalen Scope
//mittels: ESP8266WebServer server(80);
//benötigt auch: #include <ESP8266WebServer.h>
//-----------------------------------------------------
//erstellt von (c): Moppi @roboternetz.de
//-----------------------------------------------------

memset(matrix , 0, sizeof(matrix));
server.on("/",[]()
{
//Auswerten des Query-String vom Browser
int n = 0;
if(server.hasArg("bn")){
if(server.arg("bn") == "clear") toClear=1; else toClear=0;
if(server.arg("bn") == "save") toSave=1; else toSave=0;
if(server.arg("bn") == "reset") toReset=1; else toReset=0;
if(server.arg("bn") == "detect") toDetect=1; else toDetect=0;
if(server.arg("bn") == "learn") toLearn=1; else toLearn=0;
}
for(int x=0; x < tableHeight; x++){
for(int j=0; j < tableWidth; j++){
if(server.hasArg(par+String(n))){
String a = server.arg(par+String(n));
bool ic = matrix[n];
if (a == "") matrix[n] = 0; else matrix[n] = 1;
if (ic != matrix[n]) toChange = 1;
n++;
}
}
}
//Aufbau des Feldes
String v; body = s1; n = 0;
for(int x=0; x < tableHeight; x++){
body += s2;
for(int j=0; j < tableWidth; j++){
if (matrix[n]) v = fillChar; else v = "";
body += s3 + String(n) + s3_1 + v + s3_2;
n++;
}
body += s4;
}
body += s4+s5+s5_0+s5_1+s5_2+s5_3+s5_4;
//Senden der Seite an den Browser
server.send(200, "text/html", body);
}
);
//-----------------------------------------------------



//-----------------------------------------------------
//Webserver starten
//-----------------------------------------------------
server.begin();
Serial.println("Web server started!");

}


uint32_t timestamp=0, sec=0;
uint8_t modeLearn=0, modeDetect=0;

//-----------------------------------------------------
//-----------------------------------------------------
void loop() {
server.handleClient();
// Aktionen nach ButtonClick:
if(toClear) {
Serial.println((String)"toClear="+toClear);
memset(matrix , 0, sizeof(matrix));
toClear=0;
}
if (toChange) {
Serial.println("new data:");
for (int i = 0; i < 100; i++) {
bufferArray[i] = (float)matrix[i];
Serial.println((String)i + ": " + bufferArray[i]);
}
toChange=0;
}
if(toLearn){
modeLearn=1;
modeDetect=0;
Serial.println((String)"modeLearn="+modeLearn);
toLearn=0;
}
else
if(toDetect) {
modeLearn=0;
modeDetect=1;
Serial.println((String)"modeDetect="+modeDetect);
toDetect=0;
}
if(toReset) {
toLearn=0;
toDetect=1;
Serial.println((String)"toReset="+toReset);
toReset=0;
}
if(toSave) {
toLearn=0;
toDetect=1;
Serial.println((String)"toSave="+toSave);
toSave=0;
}
if(millis()-timestamp >= 1000) {
sec++;
timestamp +=1000;
Serial.println(sec);
}
}

Moppi
02.11.2019, 14:03
Wie schon früher erwähnt, kann noch ein Reload
der Seite vom Browser aus veranlasst werden.
Eine Möglichkeit habe ich zunächst eingebaut.
So, wie ich jetzt lese, geht es ohne wohl nicht.

Die neue Version ist: 20191102.1

Zwei neue Variablen sind hinzugekommen:



Variable: bool ifRefresh = 1;
Beschreibung: Refresh der Seite ausführen 0 = nein, 1 = ja
Ändern: darf geändert werden
Wirkrichtung: unidirektional, Programm -> Browser
---------------------------------------------------------------------
Variable: const int RefreshTime = 4;
Beschreibung: Zeit, nach der die Seite erneut abgerufen wird
Ändern: darf bei Programmerstellung geändert werden
Wirkrichtung: unidirektional, Programm -> Browser



:!: 34448


Ich weiß, Softwareentwicklung ist keine einfache Sache. Ablaufpläne haben wir hier noch gar nicht erwähnt,
aber eine Wahrheitstabelle für die Buttons wäre gut gewesen, dann hätte ich früher einen Überblick gehabt,
wie die wann reagieren sollen; hätte vlt. das ein oder andere mit einbauen können.


Falls Du das ausprobierst, bitte dran denken, dass die Steuerung des Seiten-Reload von Dir aktiviert oder
deaktiviert werden kann/soll/muss.





MfG

HaWe
02.11.2019, 14:39
danke, aber mit dem zip kan ich nichts anfangen - ich weiß nicht was wo hin soll und was stattdessen raus muss.
Außerdem stimmen die Variablen-Namen nicht mit 0.0.2a überein.
Bitte kopiere es in meinen Sketch ver 0.0.2a hinein und poste es neu!
Danke!

ich teste den lauffähigen Code dann ASAP!

Moppi
03.11.2019, 12:12
Meine Hilfestellung habe ich darin gesehen, bezüglich dieser Button-Pad-Geschichte
(ausgehend von Buttons mit LEDs) in möglichst kurzer Zeit, etwas zu erstellen,
das platzsparend im Quelltext unterzubringen und einfach dort austauschbar ist.
Letzteres, um die gute Wartbarkeit des Codes zu gewährleisten.
Dass das Produkt hier nicht das Ende der Weiterentwicklung darstellen muss,
sollte bewusst sein. Das betrifft auch die eingesetzten Techniken zur Datenübertragung,
seitens des Webbrowsers.


Modular und strukturiert vorzugehen, ist bei Teamarbeit unerlässlich, weil es
viel Zeit spart und das Projekt somit schnell voran bringt.


Der von mir vorgelegte Aufbau des Quelltextes ist zunächst experimentell, aber auch so
gewählt, damit das später in eine externe Bibliothek umgewandelt werden kann, wo aus
der Sache dann ein Objekt mit Methoden werden könnte.


Angesichts der Schwierigkeiten der Akzeptanz eines solchen Aufbaus / Vorgehens
sehe ich es aber als zu zeitraubend, zwei Quellcodes / Module zweier "Programmierer"
miteinander zu verquicken / ineinander zu verschachteln, so dass dann nur noch ein
größerer Quellcode da ist, mit vielen Bestandteilen, die mit der eigentlichen
Ausgangsaufgabe nichts zu tun haben. Wer soll den dann warten?


Der Quellecode liegt vor, ist einfach für Dich zu verstehen und daher steht es Dir frei,
das irgndwie anders in Deinem Programm umzusetzen oder zu integrieren.


Ob Du so eine Lösung aus technischer Sicht verwenden kannst, war von Anfang an fraglich
und muss(te) sich mit der Zeit herausstellen. Wissen kannst nur Du das, was Du dann für
Dein Vorhaben benötigst.


Ich werde an diesem Punkt nicht weiter daran arbeiten, sondern mich dann wieder anderen
Sachen zuwenden.




MfG
Moppi

HaWe
03.11.2019, 13:00
es kann bei so speziellen Anforderungen wie für ein Dashborad samt User-Control und Monitor für ein NN IMO nur funktionieren, wenn der komplette lauffähige Code ständig überarbeitet wird, schrittweise und komplett -
erst wenn er komplett reibungslos funktioniert und alle Funktionen perfekt aufeinander abgestimmt sind und fehlerfrei und schnell genug miteinander funktionieren, kann man den html-Part auskoppeln und in eine eigenständige Lib auslagern.
Trotzdem vielen Dank bis hier hin, die Version 0.0.2b ist ja auch immerhin ein guter Anfang!

HaWe
09.11.2019, 09:28
ich habe trotz alledem noch eine Verständnisfrage:

Wozu dient hier



#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>

// Version 0.0.2b

const char* ssid = "WLAN";
const char* password = "59467";

ESP8266WebServer server(80);

//-----------------------------------------------------
//HTML und Daten für das Eingabe-/Ausgabefeld
//einfügen im globalen Scope
//-----------------------------------------------------
//erstellt von (c): Moppi @roboternetz.de
//-----------------------------------------------------
//Breite und Höhe des ges. Feldes
const int tableWidth = 10;
const int tableHeight = 10;
//Füllzeichen für Felder
const String fillChar = "X";
//Parameter-Array enthält den Status aller Felder
//der Ein-/Ausgabematrix (0= AUS, 1= AN)
bool matrix[tableHeight*tableWidth]={0};
//Status, ob Änderungen vorliegen
volatile static bool toChange = 0;
volatile static bool toLearn = 1;
volatile static bool toDetect = 0;
volatile static bool toReset = 0;
volatile static bool toSave = 0;
volatile static bool toClear = 0;
//HTML
String body = "";
String s1="<style>\nform{margin:0}\n#un{width:0;height:0;visibility: hidden}\n#bu{width:10em;height:2em;}\n#rw{display: table-row;}\n#ce{display:table-cell;}\n#ip{width:1.5em;text-align:center;font-weight:bold}\n</style>\n<script>dge=document.getElementById; function oc(ob){if(ob.value=='')ob.value='"+fillChar+"';else ob.value='';}</script>\n<div role=\"presentation\" style=\"display:table\"><div id='rw'><div id='ce' style=\"padding-right:1em\"><form method=\"get\"><div role=\"presentation\" style=\"margin-bottom:1em;display:table\">";
String s2="<div id=\"rw\">";
String s3="<div id=\"ce\"><input onclick=\"oc(this);\" type=\"text\" name=\"b";
String s3_1="\" value=\"";
String s3_2="\" maxlength=\"1\" id=\"ip\"></div>";
String s4="</div>";
String s5="</div><div id='ce'><input id=\"bu\" type=\"submit\" value=\"Change:Ok\"><p></form>";
String s5_0="<form method=\"get\"><input id=\"bu\" type=\"submit\" value=\"Clear\"><input id=\"un\" type=\"text\" name=\"bn\" value=\"clear\"></form>";
String s5_1="<form method=\"get\"><input id=\"bu\" type=\"submit\" value=\"Learn\"><input id=\"un\" type=\"text\" name=\"bn\" value=\"learn\"></form>";
String s5_2="<form method=\"get\"><input id=\"bu\" type=\"submit\" value=\"Detect\"><input id=\"un\" type=\"text\" name=\"bn\" value=\"detect\"></form>";
String s5_3="<form method=\"get\"><input id=\"bu\" type=\"submit\" value=\"Reset\"><input id=\"un\" type=\"text\" name=\"bn\" value=\"reset\"></form>";
String s5_4="<form method=\"get\"><input id=\"bu\" type=\"submit\" value=\"Save\"><input id=\"un\" type=\"text\" name=\"bn\" value=\"save\"></form></div></div></div>";
String par="b";
//-----------------------------------------------------


float bufferArray[100];


//-----------------------------------------------------
//-----------------------------------------------------
void setup() {

Serial.begin(115200);
delay(1000);
Serial.println();

//-----------------------------------------------------
//Anmeldung am Netzwerk
//-----------------------------------------------------
Serial.println("connecting by IPAddress(192,168,2,99)");
WiFi.mode(WIFI_STA);

WiFi.config(IPAddress(192, 168, 2, 99), IPAddress(192, 168, 2, 1), IPAddress(192, 168, 2, 1), IPAddress(255, 255, 255, 0));
WiFi.begin(ssid, password); //begin WiFi connection

Serial.println("");

// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());


//-----------------------------------------------------
//Auswertung und Erstellung des Ein-/Ausgabefeldes
//-----------------------------------------------------
//Einbinden in setup() und in loop() nutzen durch
//Aufruf von "server.handleClient();"
//benötigt Objekt "server", erstellt im globalen Scope
//mittels: ESP8266WebServer server(80);
//benötigt auch: #include <ESP8266WebServer.h>
//-----------------------------------------------------
//erstellt von (c): Moppi @roboternetz.de
//-----------------------------------------------------

memset(matrix , 0, sizeof(matrix));
server.on("/",[]()
{
//Auswerten des Query-String vom Browser
int n = 0;
if(server.hasArg("bn")){
if(server.arg("bn") == "clear") toClear=1; else toClear=0;
if(server.arg("bn") == "save") toSave=1; else toSave=0;
if(server.arg("bn") == "reset") toReset=1; else toReset=0;
if(server.arg("bn") == "detect") toDetect=1; else toDetect=0;
if(server.arg("bn") == "learn") toLearn=1; else toLearn=0;
}
for(int x=0; x < tableHeight; x++){
for(int j=0; j < tableWidth; j++){
if(server.hasArg(par+String(n))){
String a = server.arg(par+String(n));
bool ic = matrix[n];
if (a == "") matrix[n] = 0; else matrix[n] = 1;
if (ic != matrix[n]) toChange = 1;
n++;
}
}
}
//toChange = 1;
//Aufbau des Feldes
String v; body = s1; n = 0;
for(int x=0; x < tableHeight; x++){
body += s2;
for(int j=0; j < tableWidth; j++){
if (matrix[n]) v = fillChar; else v = "";
body += s3 + String(n) + s3_1 + v + s3_2;
n++;
}
body += s4;
}
body += s4+s5+s5_0+s5_1+s5_2+s5_3+s5_4;
//Senden der Seite an den Browser
server.send(200, "text/html", body);
}
);
//-----------------------------------------------------



//-----------------------------------------------------
//Webserver starten
//-----------------------------------------------------
server.begin();
Serial.println("Web server started!");

}


uint32_t timestamp=0, sec=0;
uint8_t modeLearn=0, modeDetect=0;

//-----------------------------------------------------
//-----------------------------------------------------
void loop() {
server.handleClient();
// Aktionen nach ButtonClick:
if(toClear) {
Serial.println((String)"toClear="+toClear);
memset(matrix , 0, sizeof(matrix));
toClear=0;
}
if (toChange) {
Serial.println("new data:");
for (int i = 0; i < 100; i++) {
bufferArray[i] = (float)matrix[i];
Serial.println((String)i + ": " + bufferArray[i]);
}
toChange=0;
}
if(toLearn){
modeLearn=1;
modeDetect=0;
Serial.println((String)"modeLearn="+modeLearn);
toLearn=0;
}
else
if(toDetect) {
modeLearn=0;
modeDetect=1;
Serial.println((String)"modeDetect="+modeDetect);
toDetect=0;
}
if(toReset) {
toLearn=0;
toDetect=1;
Serial.println((String)"toReset="+toReset);
toReset=0;
}
if(toSave) {
toLearn=0;
toDetect=1;
Serial.println((String)"toSave="+toSave);
toSave=0;
}
if (millis() - timestamp >= 1000) {
while (millis() - timestamp >= 1000) {
sec++;
timestamp += 1000;
}
Serial.println(sec);
}
}

in Zeile 115 die Anweisung

if (ic != matrix[n]) toChange = 1;
:?:

Wenn der Status von toChange allein vom ButtonClick auf Btn "Change:OK" abhängig sein soll, braucht man dann die Zeile trotzdem?
Kann man sie auch ohne if(...) immer sofort fest auf toChange = 1 setzen ?
Oder kann man sie auch komplett weglassen?

Moppi
09.11.2019, 10:16
Alle diese Variablen zeigen an, ob Änderungen vorliegen:


//Status, ob Änderungen vorliegen bool isChange = 0;
bool isLearn = 0;
bool isDetect = 0;
bool isReset = 0;
bool isSave = 0;
bool isClear = 0;




An isChange kann man dies für das Eingabefeld (Matrix) ablesen, wird die Zeile "if (ic != matrix[n]) toChange = 1;" entfernt, ist das nicht mehr möglich.
An isLearn kann man dies für den Button Learn ablesen.
An isDetect kann man dies für den Button Detect ablesen.
An isReset kann man dies für den Button Reset ablesen.
An isSave kann man dies für den Button Save ablesen.
An isClear kann man dies für den Button Clear ablesen.

Somit kann man nach jedem "Browserkontakt" feststellen, ob sich etwas geändert hat und wenn, was sich geändert hat. Man kann feststellen: was wollte der Benutzer.

Im Falle eines einfachen Refresh der Ausgabe im Browser (was ich durchaus von Anfang an, aus Erfahrung, einkalkuliert habe), will der Benutzer gar nichts, weil er keine Eingabe tätigt, weder über das Eingabefeld (Matrix) noch über die Buttons. Dann sollten alle oben genannten Variablen auf 0 stehen. Dennoch überträgt mein Programmcode den (eventuell geänderten) Inhalt der Matrix zum Browser, wo der dargestellt wird.


Durch das Umbenennen der Variablen von "is" nach "to" wird der Sinn der Variablen im Code verfälscht und infolge dessen dann vermutlich auch falsch angewendet, das Verständnis leidet darunter.
Mein Code übernimmt die bidirektionale Datenübermittlung zwischen Browser und nodeMCU, auf möglichst minimalistische Art. Ändert man daran etwas, ist diese Funktion nicht mehr sichergestellt.
Um daran nichts ändern zu müssen, gibt es die verschiedenen Variablen für die Steuerungsmöglichkeiten des Codes. Die Beschreibung dafür war anbei.


MfG

HaWe
09.11.2019, 10:20
ja, sorry, deine Beschreibung verstehe ich aber nicht, weil ich generell html-Code und seine Funktionsweise nicht verstehe, insb. auch nicht, was Webserver oder Webclients oder Wifi-Server oder Wifi-Clients sind oder tun.
Ich bräuchte eher eine funktionelle, zweckgerichtete Erklärung, welche Codezeile welches Ergebnis an welcher Stelle für welche Variablen in meinem eigenen Programm erzeugt - in diesem Falle die Codezeile mit dem toChange (hier wäre etwas zu ändern bzw. auf etwas zu reagieren im laufenden Code der loop() ).

Moppi
09.11.2019, 10:22
Habe meinen Beitrag nochmal geändert, um genauer auf die Frage einzugehen (hier nochmal als Auszug):

An isChange kann man dies für das Eingabefeld (Matrix) ablesen, wird die Zeile "if (ic != matrix[n]) toChange = 1;" entfernt, ist das nicht mehr möglich.




MfG

HaWe
09.11.2019, 10:33
das macht es jetzt leider noch nicht klarer:

ich habe mal die Zeile
if (ic != matrix[n]) toChange = 1;
testweise auskommentiert und neu kompiliert: In der Tat reagiert jetzt der Browser nicht mehr auf Eingaben in der 10x10 Matrix.

Nun habe ich toChange=1 fest hinter die for Schleife gesetzt:

for(int x=0; x < tableHeight; x++){
for(int j=0; j < tableWidth; j++){
if(server.hasArg(par+String(n))){
String a = server.arg(par+String(n));
bool ic = matrix[n];
if (a == "") matrix[n] = 0; else matrix[n] = 1;
//if (ic != matrix[n]) toChange = 1;
n++;
}
}
}
toChange = 1;

Hier registriert es nun die entspr. Eingaben (allerdings ändert sich das Laufzeitverhalten nach Druck auf die Clear-Taste)

Moppi
09.11.2019, 10:39
"if (ic != matrix[n])" vergleicht den Inhalt des Arrays (Matrix) mit den Daten, die der Browser gesendet hat.



MfG

HaWe
09.11.2019, 10:44
ja, das ist klar, aber warum soll er nur auf erkannte Änderungen reagieren und nicht "blind" alles neu übernehmen, egal ob eine Änderung erkannt wurde oder nicht?

Moppi
09.11.2019, 11:38
Weil die Daten nicht immer gesendet werden, es wird das verwertet, was gesendet wird. Wird etwas nicht gesendet, ist es auch nicht geändert. Schau in die Browserzeile, dort siehst Du die übergebenen Parameter.



MfG

- - - Aktualisiert - - -

Nochmal anders:

Wenn die Daten für diese Matrix vom Browser gesendet werden, werden die übernommen. Aber es wird geprüft, ob die auch verändert wurden, dies zeigt isChange an.

Übernommen werden die Daten vom Browser hier: if (a == "") matrix[n] = 0; else matrix[n] = 1;
Auf Änderung geprüft hier: if (ic != matrix[n]) isChange = 1;

- - - Aktualisiert - - -

Du musst den Status nicht beachten, Du kannst die Daten auch jedesmal aus dem Array übernehmen, falls das einen Sinn ergibt!

HaWe
09.11.2019, 11:46
dann ist das isChange für die Matrix also etwas anderes als das isChange für den Change:OK Button?
Oder hat der isCahnge-Button gar keine isChange Variable?

Moppi
09.11.2019, 11:59
Dieser Button sendet schon immer das, was der User in der Matrix eingeben kann (also die Kreuzchen setzen). User setzt seine Kreuzchen und klickt den Button zum Versenden der Daten.
Beim ersten Mal stimmt das daher mit dem Buttonstatus überein.

Aber:

User klickt auf den Button, aus irgendeinem Grund auch zweimal hintereinander oder dreimal. Das wird dann abgefangen.



MfG

- - - Aktualisiert - - -

Warum der Change:Ok heißt, habe ich nie erklärt bekommen. Solche Buttons kenne ich nicht und so eine Bezeichnung ist auch vollkommen unüblich.
Falls Du damit verschiedene Sachen zum Ausdruck bringen willst, muss man mal schauen... Vielleicht muss man das dann auch auf zwei Buttons aufteilen "change" und "ok"

HaWe
09.11.2019, 12:28
aha, dann müsste man wschl aber eher für die Events "Left-Click in die Matrix" und "Left-Click auf Change:OK-Button" verschiedene Signal-Variablen verwenden.

- - - Aktualisiert - - -

PS,
der "Change: OK" Button hieß früher nur "OK", das war aber missverständlich.
Was er machen soll:
Der Button soll signalisieren, dass man mit dem Herumklicken in der Matrix fertig ist und der aktuelle Zustand mit den jetzt zuletzt gemachten Änderungen übermittelt und dann weiter verarbeitet werden soll.

Alle vorherigen Klicks und Änderungen in der Matrix (inkl. "Clear"-Buttonclick) sind für das NN Programm eigentlich völlig unwichtig, sie müssen nur in der Matrix sichtbar sein ("X" oder " ");
das ist aber nur für den Benutzer wichtig, damit er sieht, was er bisher so gemacht hat, nicht aber fürs NN-Programm.

Erst nach "Change: OK"
(noch besser: "Matrix: submit")
sollen die Matrix-Daten ans NN-Programm gesendet und dann vom NN Programm in der loop() weiter verarbeitet werden.

Moppi
09.11.2019, 12:42
Der Button soll signalisieren, dass man mit dem Herumklicken in der Matrix fertig ist und der aktuelle Zustand mit den jetzt zuletzt gemachten Änderungen übermittelt und dann weiter verarbeitet werden soll.

Ja das ist Sinn und Zweck dieses Buttons gewesen. Wenn Änderungen der Matrix beim nodeMCU ankommen wird dies in "isChange" mit "1" markiert. Sind keine Änderungen da, wird das mit mit "0" markiert.
Daher kannst Du in Deinem Programm z.B. auch schreiben: bool toChange = isChange;



Ich habe es mal geändert, dass es zwei Variablen gibt: ChangeOk und ChangeM

neue Version: 34459


ChangeOk ist immer "1", wenn Daten mit diesem Button übermittelt wurden.
ChangeM ist nur "1", wenn die Daten der Matrix vom User auch geändert wurden.

HaWe
09.11.2019, 13:39
edit:
die "neue Version" kann ich wieder nicht verwenden - deine jetzigen Änderungen passen nicht zu meiner Programmstruktur.
wie oft noch:
zip Anhänge bringen nichts, besser man kann es dirket lesen, um sich darüber zu verständigen, und es bringt nur ein vollständiges Programm etwas!.


(ich habe es als komplette Block-Änderung versucht, ergibt gefühlt 1000 Fehlermeldungen).

Dann habe ich es schrittweise versucht...:
isChangeM (Matrix) interessiert ja mein Programm (in loop()) wie gesagt auch gar nicht mehr, sondern nur isChangeOK (Button);
wenn ich allerdings jetzt isChangeOK wie bisher isChange abfrage, dann werden nun überhaupt keine Matrix-Daten mehr an loop() weitergegeben.

Ist also alles kompletter Murks im jetzigen Zustand: Ich brauche die kompletten Änderungen in meinem kompletten Programm.
Ich verstehe auch nicht, warum du dich so halsstarrig weigerst, sie in den lauffähigen Code einzubauen, wo es doch als losgelöstes Block-Schnipsel überhapt nichts nutzt!

Du kannst dann dort im Komplett-Programm aber gerne alle "toXXX" nach "isXXX) zurück-verändern.

- - - Aktualisiert - - -

PS:

der Change:OK Button muss IMMER die Matrix senden, auch wenn keine Änderungen in der Matrix vorgenommen wurden - er tut aber sowieso in jedem Falle überhaupt nichts (Auswertung der Variable "isChangeOK")!

Moppi
09.11.2019, 13:58
der Change:OK Button muss IMMER die Matrix senden

Macht der ja auch.

Und da er auch das in der bisherigen Version macht, was Du Dir vorgestellt hast, brauchst Du auch den geänderten Code nicht. Damit wird es in der Tat u.U. nicht einfacher. Obwohl Du im neuen Code, so wie Du es brauchst, dann nicht ChangeOk abfragst, sondern ChangeM, das hat dann eigentlich die Funktion, die Du benötigst. Weil aus isChange ist isChangeM geworden.

Ich habe den Verdacht, dass Du damit nicht richtig umgehst, warum auch immer.
Da mein 3D-Drucker aber heute unter Koprostase leidet, nehme ich mir mal meinen Code und ....

... dann wird ein Video bei rauskommen.




MfG

HaWe
09.11.2019, 14:09
hast du nicht geschrieben, dass isChangeM die MatrixClicks abfragt? das ist aber nicht wichtig.
Wichtig ist nur, dass der Change:OK Button abgefragt wird (isChangeOK) und dann auf Abfrage von isChangeOK ohne wenn und aber den aktuellen Matrix-Inhalt übermittelt.

- - - Aktualisiert - - -


Macht der ja auch.

Und da er auch das in der bisherigen Version macht, was Du Dir vorgestellt hast, brauchst Du auch den geänderten Code nicht. Damit wird es in der Tat u.U. nicht einfacher. Obwohl Du im neuen Code, so wie Du es brauchst, dann nicht ChangeOk abfragst, sondern ChangeM, das hat dann eigentlich die Funktion, die Du benötigst. Weil aus isChange ist isChangeM geworden.

Ich habe den Verdacht, dass Du damit nicht richtig umgehst, warum auch immer.
Da mein 3D-Drucker aber heute unter Koprostase leidet, nehme ich mir mal meinen Code und ....

... dann wird ein Video bei rauskommen.




MfG

Ich habe eher den Verdacht dass DU den Code fürs NN in loop() nicht richtig umgesetzt hast.
poste dann aber auch bitte den kompletten Code, damit ich ihn bei mir kontrollieren kann!

auf Abfrage von isChangeOK muss er folgendes machen (muss sich wie hier per Serial.print() kontrollieren lassen):



void loop() {
if (isChangeOK ) {
Serial.println("new data:");
for (int i = 0; i < 100; i++) {
bufferArray[i] = (float)matrix[i];
Serial.println((String)i + ": " + bufferArray[i]);
}
isChangeOK =0;
}
//...
//...
}

Moppi
09.11.2019, 15:02
Ich habe mal einiges ausprobiert und mir anzeigen lassen, um Missverständnisse zu vermeiden:



meine Version: 20191102.1

Ausgangssituation:


isChange: 0
isLearn: 0
isDetect: 0
isReset: 0
isSave: 0
isClear: 0
stateLearn: 0
stateDetect:0
--------------------------------


Status nach Änderung der Matrix + Change:Ok


isChange: 1
isLearn: 0
isDetect: 0
isReset: 0
isSave: 0
isClear: 0
stateLearn: 0
stateDetect:0
--------------------------------


Status nach Learn


isChange: 0
isLearn: 1
isDetect: 0
isReset: 0
isSave: 0
isClear: 0
stateLearn: 1
stateDetect:0
--------------------------------


Status nach Detect


isChange: 0
isLearn: 0
isDetect: 1
isReset: 0
isSave: 0
isClear: 0
stateLearn: 1
stateDetect:1
--------------------------------


Status nach Reset


isChange: 0
isLearn: 0
isDetect: 0
isReset: 1
isSave: 0
isClear: 0
stateLearn: 1
stateDetect:1
--------------------------------


Status nach Save


isChange: 0
isLearn: 0
isDetect: 0
isReset: 0
isSave: 1
isClear: 0
stateLearn: 1
stateDetect:1
--------------------------------


Status nach Change:Ok, ohne Änderung der Matrix


isChange: 0
isLearn: 0
isDetect: 0
isReset: 0
isSave: 1
isClear: 0
stateLearn: 1
stateDetect:1
--------------------------------


Status nach Änderung der Matrix + Change:Ok


isChange: 1
isLearn: 0
isDetect: 0
isReset: 0
isSave: 1
isClear: 0
stateLearn: 1
stateDetect:1




Was mir dabei aufgefallen ist:

Die Buttons Learn, Detect, Reset, Save und Clear setzen den Status aller anderen Buttons auf "0". Change aber tut das nicht.

Daher: Wenn eine Änderung von Dir registriert wurde, weil isChange == 1 war, muss isChange von Deinem Programm auf "0" gesetzt werden. Solang dies nicht geschieht, bleibt isChange (nach erfolgter Änderung) auf "1", bis Du es entweder löschst oder einer der anderen Buttons angeklickt wurde.

Zu stateLearn und stateDetect steht auch was in der Beschreibung. Wurden die zugehörigen Buttons angeklickt, bleiben diese Variablen auch so lange auf "1", bis Du sie änderst. Bei "1" erscheint hier der zugehörige Button im Browser dann in Rot.

- - - Aktualisiert - - -


hast du nicht geschrieben, dass isChangeM die MatrixClicks abfragt? das ist aber nicht wichtig.
Wichtig ist nur, dass der Change:OK Button abgefragt wird (isChangeOK) und dann auf Abfrage von isChangeOK ohne wenn und aber den aktuellen Matrix-Inhalt übermittelt.

Ich habe oben schon geschrieben, dass dies so funktioniert. Das hat immer so funktioniert. Siehe: https://www.roboternetz.de/community/threads/74178-html-Code-f%C3%BCr-virtuelles-website-Button-Pad?p=656202&viewfull=1#post656202

Moppi
09.11.2019, 15:06
Nein! Du bringst gerade die Versionen durcheinander!

Ich hatte schon geschrieben: lass die neue Version 20191109 in Ruhe, nimm die Alte, die Du vorher auch hattest, die machte das, was Du willst. Ansonsten ist bei der Neuen aus "isChange" "isChangeM" geworden. Es sei denn, es interessiert Dich, ob der User auf Chanke:Ok geklickt hat, ohne dass sich etwas geändert hätte - dies spiegelt dann isChangeOk wieder (mit "1").

HaWe
09.11.2019, 15:11
ich habe noch mehr Fehler entdeckt....

- - - Aktualisiert - - -

ja, es müssen offensichtlich neue Funktionen für Matrix-Änderung und ChangeOK ButtonClick hinzukommen.


falsch:
es darf immer nur bei einem Event die entsprechende Variable auf 1 gesetzt werden, ALLE ANDEREN dürfen nicht geändert werden in ihrem Zustand.


also bei
MatrixClick: nur isChangeM =1

ChangeOK Btn: nur isChangeOK=1

Clear Btn: nur isClear=1

Save Btn: nur isSave=1

Learn Btn: nur IsLearn=1

usw.


auch
stateLearn
stateDetect
darf hier nicht verändert oder gesetzt werden, das muss in loop() passieren

auch alle anderen Variablen-Änderungen dürfen nur in loop() geschehen.

Moppi
09.11.2019, 15:22
Ich hatte Dich schon gebeten, eine Wahrheitstabelle zu erstellen, dann hätte ich das evtl. eingebaut. So, wie es jetzt ist, funktioniert es aber auch. Du kannst die Variableninhalte in Deine eigenen Variablen übernehmen und dann - je nach Status - die auch ändern, wie Du möchtest oder eben auch nicht ändern, dass ein Status erhalten bleibt.


auch
stateLearn
stateDetect
darf hier nicht verändert oder gesetzt werden, das muss in loop() paassieren

Dazu habe ich hier was geschrieben: https://www.roboternetz.de/community/threads/74178-html-Code-f%C3%BCr-virtuelles-website-Button-Pad?p=656019&viewfull=1#post656019

Zitat:
Ich habe weitere Variablen eingeführt, die Dir Kontrolle und Einfluss erlauben. Du kannst nun Einfluss nehmen, ob der Inhalt der
neuen Variablen stateLearn und stateDetect - abhängig von der Nutzeraktion -geändert wird oder nicht und kannst
diese Variablen selbst ändern

namentlich: ifLearn und ifDetect

Nochmal aus der Beschreibung:



---------------------------------------------------------------------
Variable: bool stateLearn = 0;
bool stateDetect = 0;
Beschreibung: Status der Buttons und deren Farbe
Ändern: Ändern beeinflusst die Farbe der Buttons, im Browser
Wirkrichtung: bidirektional, Programm <-> Browser
(wenn ifDetect/ifLearn = 1, dann wird stateLearn /
stateDetect auf "1" gesetzt, wenn der zugeh. Button
im Browser angeklickt wurde)
Wirkrichtung: unidirektional, Programm -> Browser
(wenn ifDetect/ifLearn = 0 und wenn der zugeh.
Button im Browser angeklickt wurde, ändern sich
stateLearn / stateDetect nicht)

HaWe
09.11.2019, 15:23
nein, das ist nicht gut mit stateLearn und statedetect, das muss hier aus dem html code erst mal raus.
erstmal muss der Rest funktionieren.

edit: eine Wahrheitstabelle?
was soll die bringen?
Es gibt keine Wahrheitstabele, es sollen nur immer aktuelle Buttonclicks per Variablen gesendet werden, der Rest bleibt wie er ist!!

Moppi
09.11.2019, 15:25
Du kannst das annehmen oder auch nicht, ich habe das ausreichend beschrieben und erklärt.

Moppi
10.11.2019, 06:32
Wenn der Status für alle Buttons stehen bleiben soll (also wenn er 1 ist, dass er 1 bleibt, bis Du ihn löschst, also auf 0 setzt), habe ich hier die Code-Stellen markiert, die dann entfernt werden könnten:


Hier ein Auszug, aus dem gesamten Code, um den es dabei geht:

//Auswerten des Query-String vom Browser
int n = 0;
if(server.hasArg("bn")){
if(server.arg("bn") == "clear") {isClear=1; for(int i=0; i<(tableWidth*tableHeight); i++) matrix = 0;} [I]else {isClear=0; isChange=0;}
if(server.arg("bn") == "save") isSave=1; else isSave=0;
if(server.arg("bn") == "reset") isReset=1; else isReset=0;
if(server.arg("bn") == "detect") {isDetect=1; if(ifDetect)stateDetect=1;} else isDetect=0;
if(server.arg("bn") == "learn") {isLearn=1; if(ifLearn)stateLearn=1;} else isLearn=0;

}


Nachtrag:
-----------
Dann sieht das nachher so aus, wenn alle Buttons angeklickt sind und nichts zurückgesetzt (auf 0) wurde:


isChange: 1
isLearn: 1
isDetect: 1
isReset: 1
isSave: 1
isClear: 1
stateLearn: 1
stateDetect:1




MfG

HaWe
10.11.2019, 10:29
vielen Dank, aber gundlegende Probleme (s.o.) sind immer noch nicht gelöst bzw. behoben, und portieren auf den ESP32 lässt sich der gesamte Code leider auch nicht.
Ich denke, ich gebe auf, das macht so keinen Sinn mit dem jetzigen Ansatz.

Moppi
10.11.2019, 11:07
auch
stateLearn
stateDetect
darf hier nicht verändert oder gesetzt werden, das muss in loop() passieren

auch alle anderen Variablen-Änderungen dürfen nur in loop() geschehen.

Wenn stateLearn und stateDetect nicht gesetzt werden sollen, musst Du eben dann ifLearn und ifDetect = 0 setzen.

original ist es so:

//Statusänderung der Buttons und deren Farbe
bool ifDetect = 1;
bool ifLearn = 1;


Sonst färben sich die Buttons nicht ein, wenn Du vergisst den Status (stateLearn ...) zu setzen.
Musst es eben nur ändern, wie Du es benötigst. Stand alles schon mal geschrieben.
Setze die if..-Variablen = 0 und niemand, außer Dir, ändert stateLearn und stateDetect.



MfG

HaWe
10.11.2019, 11:23
ich will es ja eigentlich nicht schon wieder aufwärmen, aber ich schrieb ja schon oft genug:
nur ein komplettes, compilier- und lauffähiges Programm mit den neuen WebServer-Funktionen samt getrennter Matrix-MausClick und Change/OK-Button-Mausclick-Erkennung wäre eine Basis für einen nächsten Schritt - aber es hängt ja noch deutlich mehr an ungelösten Problemen mit der Website hinten dran...

Moppi
10.11.2019, 19:11
ich will es ja eigentlich nicht schon wieder aufwärmen, aber ich schrieb ja schon oft genug:
nur ein komplettes, compilier- und lauffähiges Programm mit den neuen WebServer-Funktionen samt getrennter Matrix-MausClick und Change/OK-Button-Mausclick-Erkennung wäre eine Basis für einen nächsten Schritt - aber es hängt ja noch deutlich mehr an ungelösten Problemen mit der Website hinten dran...

Musst Du wissen!

Ich schrieb ja schon, dass ich das nicht weiterführen möchte. Trotzdem habe ich noch Kleinigkeiten am Programm nachgelegt oder geschrieben, wie man es lösen kann.
Ich bin der Meinung, dass man das schon sehr gut verwenden kann. Mir fällt kein Grund ein, warum nicht. Liegt aber auch daran, weil ich Dein Programm nicht kenne,
nicht weiß, wie es nachher ganz genau funktionieren sollte. Das weißt Du. Deshalb Deine Entscheidung.

Ich würde folgende Funktion sehen:

1. Matrix ausfüllen
2. Daten senden
3. die einzelnen Buttons betätigen, deren Status übermitteln
4. Wenn Matrix übertragen, kann ein Lernen beginnen
5. Status über Fortschritt kann man ab und an per Browser-Refresh oder per Buttonklick abfragen (so als erste Lösung überhaupt)
6. Laden der Daten per Buttonklick
7. Speichern der Daten per Buttonklick
8. Muster in Matrix eintragen und schicken
9. Muster erkennen und Ergebnis übermitteln (die Erkennungszeit wird wahrscheinlich immer ähnlich lange sein, so dass man den Browser-Refresh nutzen kann, Zeit ist ja einstellbar)

All das würde funktionieren. Jedenfalls nach meiner Vorstellung. Ist aber Dein Projekt, nicht meines. Daher: Entscheidung bei Dir.
Ich baue das jetzt nur nicht mehr um, weil alle Szenarien, die ich mir vorstellen kann, die nötig wären, damit umsetzbar sind.

Das Problem sind auch Widersprüche Deinerseits. Einmal willst Du unbedingt den Status eines Buttons wissen der Daten verschickt. Das andere Mal aber willst Du diesen Status nur haben, wenn auch Daten geschickt wurden, also die Daten verändert wurden. Wenn Du ermitteln willst, wie oft der User geklickt hat, ohne dass sich was geändert hätte - ok, kann man machen. Meinetwegen bau ich das noch mal ein, ist aber eigentlich recht sinnlos.

Vielleicht sind Hardware-Buttons und LEDs wirklich besser für Dein Projekt (?).



MfG

.

HaWe
10.11.2019, 20:02
doch, du kennst das Programm, es ist genau das, was in Version 0.0.2b vorgestellt wird, plus die genannten Änderungen.
Es ist allerdings nicht MEIN Projekt, ich wollte mein NN damit für die Leser hier lediglich spielerisch nutzbar machen.
Ich sehe aber immer noch nirgends ein tatsächlich nutzbares Programm von DIR! :confused:

Moppi
10.11.2019, 20:29
doch, du kennst das Programm, es ist genau das, was in Version 0.0.2b vorgestellt wird, plus die genannten Änderungen.
Es ist allerdings nicht MEIN Projekt, ich wollte mein NN damit für die Leser hier lediglich spielerisch nutzbar machen.
Ich sehe aber immer noch nirgends ein tatsächlich nutzbares Programm von DIR! :confused:

Dann kann ich Dir nicht helfen. Code, Beschreibung, Erklärungen: alles vorhanden

Wenn Du nicht willst, willst Du nicht.
Ich schreibe nicht in Deinem Programmcode rum, von dem ich nichts verstehe, das sollte ja nun schon deutlich geworden sein.

Dein Problem ist doch, dass Du etwas zur Verfügung stellen willst: Deinen Programmcode.
Du würdest gerne die Zustände und Funktionen nach außen sichtbar machen.
Ich Habe Dir dabei geholfen, mit einem Programmteil, der für Dich "zu schwierig ist".
Aber das genügt nicht. Du zeigst mir die stellen - oder versuchst es - wo das dann wie eingebunden werden soll und ich soll es machen. Aber so, wie Du es haben möchtest.

Nein, das musst Du selber machen.
Ich mache meine Sachen auch selber und suche mir keinen der es für mich macht.

Würde ich mich mit Neuronalen Netzen bestens auskennen, würde ich das selber machen. Fakt ist jedenfalls, dass wir hier im Forum etwas darüber brauchen. Ich hatte das in einem andern Thread als Wünsche geäußert, die ja schon ziemlich konkret waren, wie man das angehen könnte.




Und jetzt könnte bitte mal ein Moderator das Thema hier schließen?




MfG

HaWe
10.11.2019, 21:46
ich habe es oft genug geschrieben:
Deine Schnipsel sind komplett wertlos, das Programm muss als Ganzes entwickelt, im Dialog miteinander angepasst und gemeinsam schrittweise weiter entwickelt werden.
Alles andere ist völlig für die Katz'.

(Bislang hat es ja auch noch gar nichts mit NN zutun, es testet lediglich website-Funktionalitäten.)

Manf
10.11.2019, 22:05
Vielleicht sollten wir dann an der Stelle erst einmal eine kleine Pause machen und gegebenfalls, jederzeit, auch aufbauend auf den ersten Erfahrungen mit dem Vorgehen, einen weiteren Ansatz machen.