Die Rega verfügt in Ihrer Methodendefinition des SingleConditionObjektes über eine Möglichkeit, die In der WebUI definierte Bedingung normal oder Invertiert abzufragen.
Dazu dient die offiziell nicht dokumentierte Methode NegateCondition (). Bekannt ist diese einer kleinen Gruppe von Leuten (auch mein SDV berücksichtigt diese Eigenschaft des SingleconditionObjectes seit etwa Mitte letztes Jahres in der Detailview und auch in dem Backup und Restore von einzelnen WebUI-Programmen.
Bei einem neu angelegten WebUI programm ist diese Property immer false, es erfolgt also normale Abfrage und Auswertung.
mit einem Object oSCND des Types OT_SINGLECONDITION lässt sich die Eigenschaft mit oSCND.NegateCondition () abfragen und mit oSCND.NegateCondition (false) bzw oSCND.NegateCondition (true) setzen.
Beispiele folgen noch in den weiteren Posts von mir hin in dem Thema, mit Jens bin ich im Hintergrund dran an einer Möglichen WebUI Umsetzung für alle, nicht nur für eine kleine Gruppe "Auserwählter".
Mein GitHub Issue kommt dann auch noch, immo bin ich noch dienstlich unterwegs und kann nicht wirklich über VPN an mein System.
Was geht damit:
beispielsweise ein ungleich vergleich bei Strings
oder ein NICHT vergleich bei einer WerteListe
z.B. WerteListe möglich mit Aus;An;Auto
triggern soll bei nicht Auto, also bei Aus oder an
schreibweise bisher
systemvariableX bei Aus
oder
systemvariableX bei An
gab immer nette komplexe Konstrukte, wenn noch weitere und oder oder Dazukamen
würde sich nun negiert schreiben lassen:
systemvariableX nicht bei auto
Dito wäre Möglich bei Drehgriffen, Zu,gekippt, auf.
will ich auf nicht zu auswerten musste ich jeweils gekippt und auf in 2 separaten bedingungen prüfen
mit der negation liesse sich das in einer Zeile ;
Drehgriff nicht bei ZU
âbhandeln.
Funktionstechnisch in der Rega sollte da alles schon vorgesehen gewesen sein, aber anscheinend vergessen worden bei der implementierung oder programmierteam gewechselt
oder Launchtermin vor der Tür und musste erstmal so fertigwerden. oder oder oder...
Eine Implementierung könnte folgendermassen aussehen in der WebUI.
bei eingeschalteter Negierung wird vor dem Text des Conditiontypes (bei, gleich, um, im Bereich von etc) das Wort Nicht geschrieben
an der passenden WebUI Stelle bräuchte es dort, wo die Singlecondition als Zeile dargestellt wird, eine Zeile in der Art:
Code: Alles auswählen
if (oSCND.NegateCondition () ) { Write ("Nicht "); }
Damit wäre die Darstellung der zeile eigentlich schon mal erfasst, es bräuchte dann noch eine Möglichkeit in der zeile vor oder hinter dem roten kreuz für Zeile löschen
einen button zu haben, um die bedingung zwischen invertiert und nicht invertiert togglen zu können. Ich habe beispielhaft mal das Invertiersymbol aus einem bekannten SPS Editor genommen,
mit dem Eingänge oder Ausgänge zwischen normal und invertiert umgeschaltet werden können.
damit wäre dann auch die Umschaltung gewährleistet, ein Event auf das Buttonpressed wär dann
Code: Alles auswählen
oSCND.NegateCondition (! oSCND.NegateCondition () );
-------------------------------------------------------------------------------------------------------------------------------------
Wir bauen nun ein testprogramm wie dieses:
wers es nachbauen möchter, dieser BackupCode aus dem SDV legt das Programm unter dem namen TestNegate an. Wichtig, es müssen auch 2 Systemvariablen angelegt sein:
1. TestBool vom Type Logigwert
2: testWerteListe vom Type Werteliste mit den Einträgen Wert1;Wert2;Wert3
Das Programm zum erzeugen des TestWebUI programmes
Code: Alles auswählen
string sPRGName= "TestNegate";
WriteLine ("Backup/Restore CCU Programme by Black 2020");
WriteLine ("Backup erstellt vom SDV V3.11.03 LCL am 22.04.2020 20:02:21");
WriteLine ("CCU ProgrammName: \"" # sPRGName # "\"");
WriteLine ("CCU ProgrammInfo: \"Test con NegateCondition ()\"");
WriteLine ("----------------------------");
!- Verwendete Kanäle
string sCHNList= "";
!- Verwendete Systemvariablen
string sSYSVARList= "TestBool\ttestWerteListe";
!- Referenzierung von im Programm verwendeten HSS-Datenpunkten
!- Die Referenzierung erfolgt über den substituierten Kanal und die HSSID
!- Ab hier bitte die Finger weg !!!
!- ----------------------------
string s= "27|0|2|1089|\t27|1|16|1089|";
string sID; object oID; boolean isOK= true; boolean valid; integer idType; string idName; string okText= "\tOK....\t"; string errText = "\tERROR.\t";
WriteLine ("Test auf Existenz referenzierter Channels");
foreach (sID,sCHNList) {oID=channels.Get(sID); if (oID) { Write (okText);} else {isOK=false; Write (errText); } WriteLine (sID);}
WriteLine ("Test auf Existenz und Typkonsistenz referenzierter Systemvariablen");
foreach (sID,s) {
if (sID.StrValueByIndex ("|",0).ToInteger ()==ID_SYSTEM_VARIABLES) {
idName= sSYSVARList.StrValueByIndex ("\t", ((sID.StrValueByIndex ("|",1)).ToInteger () ));
oID=dom.GetObject (ID_SYSTEM_VARIABLES).Get (idName); valid= false;
if (oID) {
valid= ((oID.Type()== sID.StrValueByIndex ("|",3).ToInteger ()) && (oID.ValueType()== sID.StrValueByIndex ("|",2).ToInteger ()));}
if (valid) {Write (okText); } else { Write (errText); isOK=false; }
if (sID.StrValueByIndex ("|",3).ToInteger ()==OT_VARDP) {Write("SYSVAR\t");} else {Write ("ALARM\t");}
WriteLine (idName);
}
}
WriteLine ("Test auf Existenz und Typkonsistenz referenzierter Geräte-Datenpunkte");
foreach (sID,s) {
if (sID.StrValueByIndex ("|",0).ToInteger ()==ID_DATAPOINTS) {
idName= sCHNList.StrValueByIndex ("\t", ((sID.StrValueByIndex ("|",1)).ToInteger () ));
oID= channels.Get (idName); valid= false;
if (oID) {
oID= oID.DPByHssDP ((sID.StrValueByIndex ("|",4)));
if (oID) {
valid= ((oID.Type()== sID.StrValueByIndex ("|",3).ToInteger ()) && (oID.ValueType()== sID.StrValueByIndex ("|",2).ToInteger ()));
}
}
if (valid) {Write (okText); } else { Write (errText); isOK=false; }
WriteLine (idName #"."# (sID.StrValueByIndex ("|",4)));
}
}
if (!isOK) {WriteLine ("Startbedingungen nicht erfüllt, Restore wird abgebrochen"); quit;}
object oPRG= dom.GetObject (ID_PROGRAMS).Get (sPRGName);
if (oPRG) {isOK= false; WriteLine ("Programm existiert schon mit dem Namen \"" # oPRG.Name () # "\" --> Abbruch"); quit;}
oPRG= dom.CreateObject (OT_PROGRAM,sPRGName);
if (!oPRG) {WriteLine ("Programm konnte nicht angelegt werden. --> Abbruch"); quit; }
dom.GetObject (ID_PROGRAMS).Add (oPRG.ID () );
oPRG.PrgInfo ("Test con NegateCondition ()");
oPRG.Active (false);
oPRG.Enabled (true);
oPRG.Visible (true);
oPRG.Internal (false);
object oRULE= oPRG.Rule ();
object oCND; object oSCND; object oDST; object oSDST; object oOBJ;
!-------- Rule 0
oRULE.RuleOperatorType (2);
oRULE.ElseIfFlag (true);
oCND=oRULE.RuleAddCondition(); !- Condition 0
oCND.CndOperatorType (2);
oSCND=oCND.CndAddSingle (); !- Single Condition 0
oSCND.ConditionType(1);
oSCND.ConditionType2(13);
oSCND.OperatorType(1);
oSCND.NegateCondition(false);
oSCND.ConditionChannel(65535);
oSCND.LeftValType(19);
oSCND.LeftVal (dom.GetObject (ID_SYSTEM_VARIABLES).Get ((sSYSVARList.StrValueByIndex ("\t",0))).ID () ); !- 0. Element aus SystemvariablenListe [TestBool]
oSCND.RightVal1ValType(2);
oSCND.RightVal2ValType(2);
oSCND.RightVal1(true);
oSCND.RightVal2(false);
oSCND=oCND.CndAddSingle (); !- Single Condition 1
oSCND.ConditionType(1);
oSCND.ConditionType2(13);
oSCND.OperatorType(1);
oSCND.NegateCondition(false);
oSCND.ConditionChannel(65535);
oSCND.LeftValType(19);
oSCND.LeftVal (dom.GetObject (ID_SYSTEM_VARIABLES).Get ((sSYSVARList.StrValueByIndex ("\t",1))).ID () ); !- 1. Element aus SystemvariablenListe [testWerteListe]
oSCND.RightVal1ValType(16);
oSCND.RightVal2ValType(16);
oSCND.RightVal1(0);
oSCND.RightVal2(0);
!-------- Rule Destination
oDST=oRULE.RuleDestination();
oDST.BreakOnRestart (true);
oSDST=oDST.DestAddSingle ();
oSDST.DestinationParam(20);
oSDST.DestinationValueType(20);
oSDST.DestinationChannel(65535);
oSDST.DestinationDP(65535);
oSDST.DestinationValueParamType(0);
oSDST.DestinationValue("object osrc= dom.GetObject (\"$src$\");\r\nif (osrc) {\r\n string s= \" ausgelöst von \" # osrc.Name () # \" mit \" # \"$val$\";\r\n system.Exec (\"logger -t LOGGERNAME -p user.debug [DANN TEIL \" # s # \"]\");\r\n} else {\r\n system.Exec (\"logger -t LOGGERNAME -p user.debug [DANN TEIL ohne Trigger]\");\r\n}\r\n");
oRULE=oRULE.RuleCreateSubRule();
!-------- Rule 1
oRULE.RuleOperatorType (2);
oRULE.ElseIfFlag (false);
!-------- Rule Destination
oDST=oRULE.RuleDestination();
oDST.BreakOnRestart (true);
oSDST=oDST.DestAddSingle ();
oSDST.DestinationParam(20);
oSDST.DestinationValueType(20);
oSDST.DestinationChannel(65535);
oSDST.DestinationDP(65535);
oSDST.DestinationValueParamType(0);
oSDST.DestinationValue("object osrc= dom.GetObject (\"$src$\");\r\nif (osrc) {\r\n string s= \" ausgelöst von \" # osrc.Name () # \" mit \" # \"$val$\";\r\n system.Exec (\"logger -t LOGGERNAME -p user.debug [SONST TEIL \" # s # \"]\");\r\n} else {\r\n system.Exec (\"logger -t LOGGERNAME -p user.debug [SONST TEIL ohne Trigger]\");\r\n}\r\n");
oPRG.Active (true);
dom.RTUpdate (0);
WriteLine ("Restore Programm von Program \"" # sPRGName # "\" erfolgreich durchgelaufen");
keine Schwierigkeit.
wir triggern nun mal die testWerteListe mit 0:
wie Erwartet gibts im Systemprotokoll:
Apr 22 20:24:45 homematic-ccu2 user.debug LOGGERNAME: [DANN TEIL ausgelöst von testWerteListe mit 0]
und testWerteListe =1 gibts im Systemprotoll wie erwartet
Apr 22 20:25:55 homematic-ccu2 user.debug LOGGERNAME: [SONST TEIL ausgelöst von testWerteListe mit 1]
nun invertieren wir mal die zweite SingleCondition, die die WeteListe behandelt:
mit dem SDV geht das recht schnell: programm auflösen 2. SCND anwählen, Methode NegateCondition wählen und ändern:
diejenigen ohne SDV können dies in diesem Testprogramm so ändern:
Code: Alles auswählen
object oPRG= dom.GetObject (ID_PROGRAMS).Get ("TestNegate");
oPRG.Rule ().RuleCondition (0).CndSingleCondition (1).NegateCondition (false);
Den Zustand Anzeigen kann man mit:
Code: Alles auswählen
object oPRG= dom.GetObject (ID_PROGRAMS).Get ("TestNegate");
WriteLine (oPRG.Rule ().RuleCondition (0).CndSingleCondition (1).NegateCondition ());
wir triggern nun mal die testWerteListe mit 0:
wie Erwartet gibts im Systemprotokoll:
Apr 22 20:36:35 homematic-ccu2 user.debug LOGGERNAME: [SONST TEIL ausgelöst von testWerteListe mit 0]
und mit Wert = 1:
Apr 22 20:37:16 homematic-ccu2 user.debug LOGGERNAME: [DANN TEIL ausgelöst von testWerteListe mit 1]
die 2 SCND wird also interpretiert als:
Systemzustand testWerteListe NICHT bei "Wert1" bei Aktualisierung
Black