Open stefan123t opened 2 years ago
Hi,
die eigentliche Funktion ist schon implementiert.
ToDo's / Ideen für die weitere Umsetzung: R1: Es Bedarf zwingend einer Command-Queue da in der Antwort keine Information enthalten ist auf welche Anfrage die Antwort kam. Lediglich könnte man die Anzahl der Bytes als Plausibilität testen. Akutell ist im Prinzip eine Queue implementiert aber nur mit der Länge "1 Kommando". Wird während man auf die Antwort wartet ein neues anderes Kommando via rest api od. mqtt gesetzt läuft das Antwort-Verarbeiten falsch. --> Wie ist das in OpenDTU umgesetzt? R2: Um die Antworten im WebUI darzustellen bzw. asynchron anzufragen via rest api benötigen wir entweder den async webserver oder wir müssen einen zweiten port bereitstellen und dort mit SSE / WS antworten.
R3: Parser für die InfoCmds erstellen.
Wer Ansätze / Vorschläge hat bitte einfach Bezug nehmen auf die Anfroderungen R1 / R2 / R3 die m.E. zunächst notwendig sind bevor die Funktion implementiert wird.
Ein aufwendigerer alternativer Ansatz -- aber m.E. der beste Weg -- wäre per git sub modul das repository https://github.com/tbnobody/OpenDTU einzubinden und dort die Quellen unter /lib/Hoymiles/* 1:1 zu verwenden. Dann wäre was das Thema / Modul Applikation <-> Inverter alles einheitlich.
@aschiffler bzgl.
R1: eine Command Queue ist für die noch anstehenden Commands von der API / UI notwendig. Sollte also eventuell auch als Liste in der UI angezeigt werden können, zumindest deren Länge.
Hier ist aber zu unterscheiden, die DTU-Pro (wie auch unsere Ahoy/OpenDTU) kann immer nur ein Command aktuell ausführen, das steht dann als aktuelles Command im Uart_CurRecMainCmd
bzw. Uart_CurRecSubCmd
. Es gibt außerdem noch ein CurRecSendPackageDataType
mit dem die aktuelle UsartNrf_Process_*()
Methode gewählt wird, der das Parsen der Antwort überlassen wird.
D.h. erst wenn das Uart_CurRecMainCmd
wieder auf einen default Wert gesetzt wird, kann ein neues Kommando aus der API / UI Command Queue oder aus dem Scheduler gesetzt werden. Wie wir das Interleaving zwischen Scheduler und Command Queue umsetzen sollen, da bin ich noch unschlüßig, evtl. einfach Scheduler Commands auch ans Ende der Command Queue ?
Wie lang sollte die Command Queue sein, und welche Parameter / Struktur sollten die Objekte in der Queue haben ?
MainCmd
,SubCmd
,DataType
,PowerLimit
, PowerFactor
, etc.UserData
,AlarmSerNub
(immer die aktuellste)
Wie können wir das so allgemein gestalten, daß wir alle Kommandos sauber in der Queue halten können ?0x80
/ 0x81
, Retransmit Command 0x8X
R2: AsyncWebServer gibt es im Branch asyncWeb, es gab aber einen Merge Conflict #107, den ich offenbar nicht richtig auflösen konnte. Einziger Schwachpunkt aktuell bricht der AsyncWebServer unser OTA Update Methode. Hier wird empfohlen auf Elegant OTA zu wechseln. @lumapu ist da m.W. aktuell dran ...
R3: Vielleicht können wir das schon mal nach vorne ziehen, dafür müssen die entsprechenden Strukturen zur Ablage der Daten (AlarmData
/AlarmUpdate
, InverterDevInform_Simple
/InverterDevInform_All
, etc.) angelegt werden und dann die Parser die Daten dort rein schreiben. Ich vermute das geht analog zu den Parser-Strukturen für RealTimeRunData_Debug
und RealTimeRunData_Reality
. Diese muß die DTU entweder im RAM halten oder wie die DTU-Pro in ihrer Memory.c
Klasse auf das SPIFFS/LittleFS in die jeweiligen Dateien schreiben. Hierfür wäre dann evtl. eine echte SD Karte sinnvoll ?
R3: den Vorschlag die Code Basis von @tbnobody zu verwenden finde ich nicht schlecht. Das hatte ich mit dem Aufräumen der app.cpp ebenfalls vor. Leider bin ich bisher gescheitert den OpenDTU Code auf dem ESP8266 zum Laufen zu bekommen. Ich hänge immer an den Interrupt Handlern die über std::bind als Callback angebunden werden. Meine bisheriger Informationsstand ist daß das für den ESP nicht als Methode einer Klasse unterstützt wird. Man müsste die Interrupt Handler also als globale Funktionen / Methoden auslagern. Ich weiß nicht ob das wirklich ein Problem ist ?
R3: Memory, daran habe ich gar nicht gedacht, dass der Speicher evtl. knapp wird wenn wir die ganzen Parser implementieren. R3: Lib, callbacks: Es scheint ich war da an einem ähnlichen Punkt mit dem "binden" der MQTT Callback. https://github.com/grindylow/ahoy/blob/aca98b6911c22d667ef6a5bb7184dba7dd51ff5c/tools/esp8266/app.cpp#L166 Das habe ich nur hinbekommen wenn in der mqtt Klasse die Instanz des PubSubclients public ist und ich direkt "durchgreifen" kann auf die Methode setCallback.
R3: Richtig, die setCallback Methode muß public sein! Willst Du mal versuchen OpenDTU (bereits mit ESPAsyncWebServer) auf ESP8266 zu portieren ? Dann hätten wir einen sauberen Stand um die aktuell in AhoyDTU erfolgten Erweiterungen nachzuziehen ?
ich hätte gerne den ESP8266 weiterentwickelt und nicht die OpenDTU kopiert - was genau ist dort aus deiner Sicht besser Aufgelöst? Für app und main habe ich fest vor den Webserver Teil zu extrahieren. Zudem ist der Async-Webserver auf dem besten Weg bald in den main-branch zu kommen. Bzgl. OTA: warum meinst du, dass das mit Async nicht ginge - das ist doch bereits in meinem aktuellen branch möglich - ohne zusätzliche libs.
R3: Memory, daran habe ich gar nicht gedacht, dass der Speicher evtl. knapp wird wenn wir die ganzen Parser implementieren. R3: Lib, callbacks: Es scheint ich war da an einem ähnlichen Punkt mit dem "binden" der MQTT Callback.
Das habe ich nur hinbekommen wenn in der mqtt Klasse die Instanz des PubSubclients public ist und ich direkt "durchgreifen" kann auf die Methode setCallback.
ja das liegt daran, dass du versuchst direkt auf mClient
zuzugreifen. Wenn dieser Member private
sein soll, dann müsstest du einen public
wrapper in der mqtt Klasse bauen. Wäre sauberer, da man dadurch weiß, das mClient
nicht noch sonst irgendwo im Code manipuliert wird.
Vielleicht sollten wir ein eigenes Issue zum Refaktorisieren des bestehenden AhoyDTU Codes machen ? Wie gesagt ich finde mich leider zwischen esp8266.cpp, main.cpp und app.cpp aktuell nicht immer zu Recht.
<offtopic>
ich hätte gerne den ESP8266 weiterentwickelt und nicht die OpenDTU kopiert - was genau ist dort aus deiner Sicht besser gelöst?
Wie an anderer Stelle schon gesagt finde ich den Scheduler mit den EVERY_XXX Defines in OpenDTU sehr einfach zu lesen. Vermutlich auch kein Hexenwerk das nach AhoyDTU zu portieren und die verschiedenen Ticker und sonstigen Counter zu vereinheitlichen.
Vielleicht ist das aber auch ein guter Ansatzpunkt um den bestehenden Code zu entwirren ? Momentan haben wir einen Scheduler der m.W. in app.cpp über den loop verteilt ist. Wenn wir den rausziehen und dann die einzelnen Blöcke des loop codes in anderen Klassen aufrufen wird es vermutlich übersichtlicher.
Für app und main habe ich fest vor den Webserver Teil zu extrahieren. Zudem ist der Async-Webserver auf dem besten Weg bald in den main-branch zu kommen.
Ja das ist der Hauptgrund, das hat tbnobody an dieser Stelle in OpenDTU ja schon gemacht. Bestimmt auch kein Problem das nochmal in AhoyDTU zu machen. Aber ich fände es halt gut wenn die beiden Projekte wieder zu einander finden würden. Und da halte ich den Code von OpenDTU aktuell etwas einfacher lesbar, erweiterbar und wartbar. Aber er läuft halt nicht auf dem ESP8266. Vielleicht können wir auch einige der Webserver Klassen oder Methoden von OpenDTU verwenden, um hier das wieder etwas zu vereinheitlichen ? Obwohl ich mit Vue.js ehrlich gesagt noch nichts gemacht habe, weshalb ich das nicht wirklich beurteilen kann, ob das Sinn macht.
Bzgl. OTA: warum meinst du, dass das mit Async nicht ginge - das ist doch bereits in meinem aktuellen branch möglich - ohne zusätzliche libs.
Ich habe keinen Bedarf für OTA aber ich hatte mslookup im PR 107 zum AsyncWebServer so verstanden, daß es mit Async nicht funktioniert und das Selbe steht dort https://github.com/grindylow/ahoy/pull/107#issuecomment-1211563142. Ich würde nur ungern die Erwartungen der Nutzer die den ESP8266 schon irgendwo montiert haben wo sie nur noch mit OTA flashen können enttäuschen.
</offtopic>
Ich verwende fast ausschließlich OTA mit und ohne Async-Webserver
Ich würde vorschlagen für den o.g. Scheduler und eventuell auch die Command Queue das bestehende Issue #78 zu verwenden.
einen
public
wrapper in der mqtt Klasse bauen. Wäre sauberer, da man dadurch weiß, dasmClient
nicht noch sonst irgendwo im Code manipuliert wird.
@lumapu Ja aber genau dieser Public Wrapper geht nicht wegen dem Methodenaufruf. Der Public-Wrapper übergibt dann eine Funktion app::XXXX an den PubSubClient und nicht std::func (void*) oder so ähnlich. Ich habe dazu einiges im I-Net gelesen und man müssten dann die Methode setCallback des PubSubClient anders abauen. --> das habe ich dann gelassen.
ok, ich werde da auch nochmal drauf schauen, evtl. finde ich ja eine Lösung
@aschiffler jetzt ist mClient
wieder private
@lumapu Klasse! Das habe ich nicht gefunden mit dieser Callback Signature
R1 ist nun erledigt. Man kann vie iv->enqueCommand
R2 ist nun Baustelle. SSE wäre mein Vorschlag.
R2: comparison of SSE (server side events, half-duplex, ESP->Client push) vs WebSocket (full-duplex, ESP<->Client): https://developer.ibm.com/articles/wa-http-server-push-with-websocket-sse/
According to Random Nerd example SSE may require ESPAsyncWebServer too, though the general effort being HTML5 seems lower:
https://randomnerdtutorials.com/esp8266-nodemcu-web-server-sent-events-sse/
@lumapu wir hatten heute im Discord #ahoy-esp8266 diskutiert wie wir die Integration von HM- und MI-Wechselrichter weiter voranbringen können. Hier geht es ebenfalls um das Queuing von Kommandos die zum WR geschickt werden müssen und deren Antworten ausgewertet werden sollen:
nrf24Radio.h
)nrf24Radio.h
)cc1101Radio.h
oder Anderes)Man müsste dann in den ersten beiden Fällen auch nicht mehr von MI/HM reden sondern vielleicht eher von:
Alle zum MainCmd
0x15
REQ_ARW_DAT_ALL
bzw. dem. Device Information gehörenden SubCmd Kommandos implementieren:Subtask: #178
0x00
InverterDevInform_Simple
0x01
InverterDevInform_All
0x02
GridOnProFilePara
0x03
HardWareConfig
0x04
SimpleCalibrationPara
[x]
0x05
SystemConfigPara
Subtasks: ?
0x0B
RealTimeRunData_Debug
0x0C
RealTimeRunData_Reality
0x0D
RealTimeRunData_A_Phase
0x0E
RealTimeRunData_B_Phase
[ ]
0x0F
RealTimeRunData_C_Phase
Subtask: #177
0x11
AlarmData
[ ]
0x12
AlarmUpdate
Subtask: ?
0x13
RecordData
0x14
InternalData
0x15
GetLossRate
0x1E
GetSelfCheckState
0xFF
InitDataState