Ich habe es geschafft, die Basis-Funktionalitäten in den EibPc zu integrieren. Ich poste das hier einmal, auch wenn es noch nicht vollständig ist.
Die meiste Zeit hat es gebraucht, die IP Kommunikation stabil hinzubekommen. Das Problem liegt hier in der (Enertex EibPC) Software, welche
mit dem "Validierungsschema" und der kryptischen Syntax zwar gerade noch eine State-Machine erlaubt, aber bei mehrfach-Aufrufen
(Instanzen - von verschiedenen Bedienelementen aus) seine liebe Not hat... Jetzt ist es also EINE globale Kommunikations-Funktion geworden, welche (mühsam) über ebenso globale Variablen gesteuert wird.
Hier einmal die Kommunikation als Makro.
Code: Alles auswählen
//=================================================================
//
// RobonectQuery
//
//=================================================================
// When Start is EIN, a TCP connection is established and Command is
// sent to this address. The answer is received in ReceiveData.
// The connection is then closed and the variable Done changes to EIN
// However, if the process does not finish within some time, the
// connection is closed, Done will change to EIN but ReceiveData will
// contain $$.
//=================================================================
:begin RobonectQuery(Command,ReceiveData,Start,Done)
Ro_IP=192.168.1.70
Ro_Port=80u16
Ro_ConnectionState=99u08
Ro_RemotePort=0u16
Ro_RemoteIP=0u32
Ro_Next=0u16
Ro_Timeout=0u64
Ro_SendStr=$$
// (0) Built up TCP Connection
// ===========================
if Start and Ro_ConnectionState>=2u08 then {
Done=AUS;
Start=AUS;
ReceiveData=$$;
Ro_ConnectionState = connecttcp(Ro_Port,Ro_IP);
} endif
// (0) Wait until connected
// ========================
if change(Ro_ConnectionState) and Ro_ConnectionState==0u08 then {
Ro_Next=1u16;
}endif
// (1) Send Request to TCP Server
// ==============================
if after(change(Ro_Next),1u64) and Ro_Next==1u16 then {
Ro_SendStr=$GET /xml?$+Command+$ HTTP/1.1$+CRLF+CRLF;
sendtcparray(Ro_Port,Ro_IP,Ro_SendStr,size(Ro_SendStr));
Ro_Next=2u16;
} endif
// (2) Collect received data (event is triggered asynchronously)
// =============================================================
if event(readtcp(Ro_RemotePort,Ro_RemoteIP,ReceiveData)) then {
Ro_Next=3u16;
}endif
// (3) Close Connection
// ====================
if after(change(Ro_Next),1u64) and Ro_Next==3u16 then {
closetcp(Ro_Port,Ro_IP);
Ro_ConnectionState=99u08;
Ro_Timeout=0u64;
Ro_Next=0u16;
Done=EIN;
} endif
// Close Connection anyway after 3 seconds after start
// ===================================================
if afterc(Start,3000u64,Ro_Timeout) then {
ReceiveData=$$;
Ro_Next=3u16;
} endif
:end
Die Variable Ro_IP muss natürlich auf die jeweiligen Gegebenheiten angepasst werden.
Für die nachfolgende Verarbeitung gibt's noch einen primitven XML-Parser. Der funktioniert natürlich nur wenn man schon im Vorhinein weiss
wie die Syntax aussieht (z.B. doppeltes Vorkommen des Strings "status") und man daher auch Vorkommen überspringen kann
Code: Alles auswählen
//=================================================================
//
// XmlExtract
//
//=================================================================
// Extract an XML Element located between <Ident> und </Ident>.
// Since it is possible that an input like
// <status>
// <status>123</status>
// <data>456</data>
// </status>
// exists, a parameter Skip will specify how many closing targets
// to skip before the element is extracted. This will work correctly
// only if the syntax is known in advance, as it will be for
// e.g. Robonect.
//=================================================================
:begin XmlExtract(XmlString,Ident,Skip)
:return split(XmlString,find(XmlString,$<$+Ident+$>$,0u16)+size(Ident)+2u16,find(XmlString,$</$+Ident+$>$,convert(Skip,0u16))-1u16)
:end
Diese beiden Makros gehören in eine externe Datei und müssen im EibStudio z.B. so eingebunden werden:
Code: Alles auswählen
[MacroLibs]
C:/Program Files (x86)/EibStudio/Program/MeineMacros.lib
Der Makro XmlExtract ist eine Funktion und wird einfach im Code verwendet. Der Makro "RobonectQuery" dagegen ist global und
muss daher 1x im Code platziert werden:
Code: Alles auswählen
#addto [Macros]
RobonectQuery(RobonectSend, RobonectData, RobonectStart, RobonectDone);
Das eigentliche Programm kommt in die Sektion [EibPc]:
Code: Alles auswählen
#addto [EibPC]
RobonectSend=$$
RobonectData=$$
RobonectStart=AUS
RobonectDone=AUS
RobonectString=$$
RobonectStatus=$$
RobonectTimer=$$
RobonectWlan=$$
RobonectStatusNum=$$
RobonectStatusTxt=$$
RobonectModeNum=$$
RobonectModeTxt=$$
RobonectTimerStatNum=$$
RobonectTimerStatTxt=$$
// start update of Robonect data every minute or if button pressed manually
if stime(22) or pbutton(LidRobonectStatus,PageIdRobonect)==1 then {
pdisplay(LidRobonectStatus,$UPDATING$,FORWARD,BRIGHTRED,GREEN,PageIdRobonect);
RobonectSend = $cmd=status$;
RobonectStart = EIN;
} endif
// if update done, display the result
if RobonectDone and RobonectSend==$cmd=status$ then {
if RobonectData==$$ then {
pdisplay(LidRobonectStatus,$ERROR$,FORWARD,INACTIVE,GREEN,PageIdRobonect);
weboutput(DidInfo2, \\
$<h3>$ +\\
$<i>Error</i>$ +\\
$</h3>$);
} else {
pdisplay(LidRobonectStatus,$$,FORWARD,INACTIVE,GREEN,PageIdRobonect);
RobonectString=XmlExtract(RobonectData,$robonect$,0);
RobonectStatus=XmlExtract(RobonectString,$status$,1);
RobonectTimer=XmlExtract(RobonectString,$timer$,0);
RobonectWlan=XmlExtract(RobonectString,$wlan$,0);
RobonectStatusNum=XmlExtract(RobonectStatus,$status$,0);
if RobonectStatusNum==$0$ then RobonectStatusTxt=$wird ermittelt$ endif;
if RobonectStatusNum==$1$ then RobonectStatusTxt=$parkt$ endif;
if RobonectStatusNum==$2$ then RobonectStatusTxt=$mäht$ endif;
if RobonectStatusNum==$3$ then RobonectStatusTxt=$sucht Ladestation$ endif;
if RobonectStatusNum==$4$ then RobonectStatusTxt=$lädt$ endif;
if RobonectStatusNum==$5$ then RobonectStatusTxt=$sucht$ endif;
if RobonectStatusNum==$7$ then RobonectStatusTxt=$Fehler$ endif;
if RobonectStatusNum==$8$ then RobonectStatusTxt=$Schleifensignal verloren$ endif;
if RobonectStatusNum==$16$ then RobonectStatusTxt=$abgeschaltet$ endif;
if RobonectStatusNum==$17$ then RobonectStatusTxt=$schläft$ endif;
RobonectModeNum=XmlExtract(RobonectStatus,$mode$,0);
if RobonectModeNum==$0$ then RobonectModeTxt=$Auto$ endif;
if RobonectModeNum==$1$ then RobonectModeTxt=$Manuell$ endif;
if RobonectModeNum==$2$ then RobonectModeTxt=$Home$ endif;
if RobonectModeNum==$3$ then RobonectModeTxt=$Demo$ endif;
RobonectTimerStatNum=XmlExtract(RobonectTimer,$status$,0);
if RobonectTimerStatNum==$0$ then RobonectTimerStatTxt=$Deaktiviert$ endif;
if RobonectTimerStatNum==$1$ then RobonectTimerStatTxt=$Aktiv$ endif;
if RobonectTimerStatNum==$2$ then RobonectTimerStatTxt=$Standby$ endif;
weboutput(DidInfo2, \\
$<h3>$ +\\
$<i>Robonect Status:</i>$ +\\
$</h3>$ +\\
$<ul style="list-style-type:disc">$ +\\
$<li>Name : $+XmlExtract(RobonectString,$name$,0)+$</li>$ +\\
$<li>Status : $+RobonectStatusNum+$ ($+RobonectStatusTxt+$)</li>$ +\\
$<li>Stopped : $+XmlExtract(RobonectStatus,$stopped$,0)+$</li>$ +\\
$<li>Duration : $+XmlExtract(RobonectStatus,$duration$,0)+$</li>$ +\\
$<li>Mode : $+RobonectModeNum+$ ($+RobonectModeTxt+$)</li>$ +\\
$<li>Battery : $+XmlExtract(RobonectStatus,$battery$,0)+$</li>$ +\\
$<li>Hours : $+XmlExtract(RobonectStatus,$hours$,0)+$</li>$ +\\
$<li>Timer Status : $+RobonectTimerStatNum+$ ($+RobonectTimerStatTxt+$)</li>$ +\\
$<li>Wlan Signal : $+XmlExtract(RobonectWlan,$signal$,0)+$</li>$ +\\
$</ul>$ );
} endif;
} endif
// Button Stop & Parken
if pbutton(LidRobonectGoHome,PageIdRobonect)==1 then {
pdisplay(LidRobonectGoHome,$UPDATING$,HALT,BRIGHTRED,GREEN,PageIdRobonect);
RobonectSend = $cmd=mode&mode=home$;
RobonectStart = EIN;
} endif
if RobonectDone and RobonectSend==$cmd=mode&mode=home$ then {
if RobonectData==$$ \\
then pdisplay(LidRobonectGoHome,$ERROR$,HALT,INACTIVE,GREEN,PageIdRobonect) \\
else pdisplay(LidRobonectGoHome,$OK$,HALT,INACTIVE,GREEN,PageIdRobonect) endif;
pdisplay(LidRobonectGoEod,$$,PREVIOUS,INACTIVE,GREEN,PageIdRobonect);
pdisplay(LidRobonectGoAuto,$$,FORWARD,INACTIVE,GREEN,PageIdRobonect);
} endif
// Button Feierabend
if pbutton(LidRobonectGoEod,PageIdRobonect)==1 then {
pdisplay(LidRobonectGoEod,$UPDATING$,PREVIOUS,BRIGHTRED,GREEN,PageIdRobonect);
RobonectSend = $cmd=mode&mode=eod$;
RobonectStart = EIN;
} endif
if RobonectDone and RobonectSend==$cmd=mode&mode=eod$ then {
if RobonectData==$$ \\
then pdisplay(LidRobonectGoEod,$ERROR$,PREVIOUS,INACTIVE,GREEN,PageIdRobonect) \\
else pdisplay(LidRobonectGoEod,$OK$,PREVIOUS,INACTIVE,GREEN,PageIdRobonect) endif;
pdisplay(LidRobonectGoAuto,$$,FORWARD,INACTIVE,GREEN,PageIdRobonect);
pdisplay(LidRobonectGoHome,$$,HALT,INACTIVE,GREEN,PageIdRobonect);
} endif
// Button Auto Start
if pbutton(LidRobonectGoAuto,PageIdRobonect)==1 then {
pdisplay(LidRobonectGoAuto,$UPDATING$,FORWARD,BRIGHTRED,GREEN,PageIdRobonect);
RobonectSend = $cmd=mode&mode=auto$;
RobonectStart = EIN;
} endif
if RobonectDone and RobonectSend==$cmd=mode&mode=auto$ then {
if RobonectData==$$ \\
then pdisplay(LidRobonectGoAuto,$ERROR$,FORWARD,INACTIVE,GREEN,PageIdRobonect) \\
else pdisplay(LidRobonectGoAuto,$OK$,FORWARD,INACTIVE,GREEN,PageIdRobonect) endif;
pdisplay(LidRobonectGoEod,$$,PREVIOUS,INACTIVE,GREEN,PageIdRobonect);
pdisplay(LidRobonectGoHome,$$,HALT,INACTIVE,GREEN,PageIdRobonect);
} endif
Für das WEB-Interface gibt es noch diese Definitonen:
Code: Alles auswählen
#addto [WebServer]
// Webserver Bewässerung
page (PageIdRobonect) [$Zentral$,$Robonect$]
header(0)
footer(0)
line $ROBONECT$
weboutput(DidInfo2)[QUAD,NOICON] pbutton(LidRobonectStatus)[FORWARD]$Update$
pbutton(LidRobonectGoHome)[HALT]$Stop & Parken$ pbutton(LidRobonectGoEod)[PREVIOUS]$Feierabend$ pbutton(LidRobonectGoAuto)[FORWARD]$Auto Start$
Und noch der Vollständigkeit halber die Konstanten (als Beispiel) - aber die muss sich sowieso jeder selbst festlegen:
Code: Alles auswählen
PageIdRobonect = 4
DidInfo2 = 31
LidRobonectStatus = 20
LidRobonectGoHome = 21
LidRobonectGoEod = 22
LidRobonectGoAuto = 23
Wie das dann im WEB Interface aussieht, kann man im Dateianhang sehen.
Wie gesagt, das ist nur die Basis-Funktionalität, aber darauf könnte man natürlich alle anderen Funktionen aufbauen
(soferne der EibPC das zulässt
).
Falls jemand meinen Code verwendet und weiterentwickelt wäre es natürlich nett wenn das hier gepostet würde.
Liebe Grüße
Eduard