Skripte gegeneinander verriegeln

Hallo zusammen,

ich habe folgende Aufgabenstellung:
Meiner Wärmepumpe müssen Raumtemperaturen geschickt werden. Jeder Raum hat einen Index. Zuerst muss der Index gesendet werden, dann muss 3 Sekunden gewartet werden bis die Wärmepumpe den Index übernommen hat (kein Handshake), dann kann die Temperatur gesendet werden.
Mein erster Gedanke war, an jedes Raumtemperatur Objekt ein Skript hängen, welches bei Temperaturänderung den Index setzt, 3s wartet und dann den Wert schickt. Dann könnte es aber passieren, das zwei Skripte gleichzeitig aktiv sind und dann irgendwas undefiniertes passiert. Kann man die Skripte irgendwie gegeneinander verriegeln?

Alternativ wäre auch möglich alle 30min ein Skript ausführen welches nacheinander alle Temperaturen versendet. Das wären 5 Stück, jeweils dann mit 3s Pause dazwischen. Das wäre aber auch unschön.

Wie würdet ihr das lösen?

Wäre das etwas für dich?
IPS_SemaphoreEnter — IP-Symcon :: Automatisierungssoftware

Grüße,
Kai

Ich denke der Ansatz hiersollte helfen.

Ich glaube der Ansatz mit Semiphore gefällt mir gut.

Jetzt scheitere ich aber schon an anderer Stelle, kann nichts auf KNX schreiben.

Ich habe jetzt für die Raumadresse eine Variable im Objektbaum angelegt. (ETS Import funktioniert hier nicht weil die Variablen in der ETS nicht verknüpft sind). Dazu habe ich ein bestehendes KNX Objekt, welches schon durch den KNX Konfigurator angelegt wurde dupliziert und dann die Adressen und Einstellungen entsprechen angepasst.
Hab jetzt eine Variable vom Typ EIS10 und wollte da über die Funktion Wert schreiben die Zahl 50 schicken, aber auf dem Bus kommt nichts an. Angeblich ist die Variable als „nur lesen“ markiert, aber ich hab nur senden markiert.

Du musst über die Instanz gehen.

Wie versuchst du den Variablenwert zu setzen? Wenn du in deinem Skript SetValue verwendest, dann verwende einfach stattdessen RequestAction. SetValue setzt einfach nur den Variablenwert in IP-Symcon (bzw. versucht und es scheitert, da die Variable schreibgeschützt ist). RequestAction führt stattdessen die Aktion aus, die zu dem Variablenwert gehört, verhält sich also genau so als würdest du die Umschaltung im WebFront machen.

Hierfür musst du entgegen der Aussage von DerStandart nicht über die Instanz gehen, sondern bleibst bei der Variablen als Ziel.

@ DerStandart: Was meinst du mit über die Instanz gehen? Da finde ich nirgends eine Möglichkeit den Wert zu setzen. Oder meinst du im Skript die ID der Instanz verwenden? Hab ich auch versucht, ohne Erfolg.

So ist die Instanz konfiguriert

Und so wollte ich versuchsweise den Wert schreiben

Ich habe auch testweise ein Ereignis erstellt welches jede Minute einen Wert schreiben soll.

Einmal

 <?
SetValue(35911, 50); 
?> 

und einmal mit

<?
SetValue(31193, 50);
?>

Dann jeweils noch mit RequestAction, auch ohne Erfolg.

Edit: Kommando zurück! Hab das hier noch entdeckt EIB/KNX — IP-Symcon :: Automatisierungssoftware
Ich dachte aber wenn die Instanzen richtig angelegt sind braucht man keine spezifischen EIB Befehle, da war ich zu optimistisch :wink:

Jetzt muss ich nur noch rausfinden, warum mit


<?
EIB_Counter16Bit(35911, 50); 
?>

der Wert 0,5 auf dem Bus landet :wink:

Meine Empfehlung wäre, dass Du die EIB Instanz löschst und eine KNX Instanz mit korrektem Datentyp anlegt und den entsprechenden Befehl dafür verwendest. Dann ist die Chance, dass der richtige Wert auf dem Bus landet, größer.

Ich nutze KNX_WriteDPTx aber mit RequestAction sollte es auch gehen. SetValue ist nur für das Zuweisen von Werten von Variablen gedacht, nicht aber zum Ansprechen von Instanzen.

Ich hab jetzt mal eine KNX DPT7.xx Instanz angelegt und habe dann in der Instanz Wert schreiben 50 gemacht (über den Schalten Button)
Kommt wieder 0,5 auf dem Bus an.

Habe mich zwischenzeitlich auch mal mit dem Semaphore Befehl beschäftig und das Beispiel aus der Doku herkopiert.

<?
if (IPS_SemaphoreEnter("RTCschreiben", 3000))
{
    // ...Kritischer Codeabschnitt
EIB_Counter16Bit(35911, 51) 
    //Semaphore wieder freigeben
    IPS_SemaphoreLeave("RTCschreiben");
}
else
{
    // ...Keine ausführung Möglich. Ein anderes Skript nutzt den "KritischenPunkt" 
    // für länger als 1 Sekunde, sodass unsere Wartezeit überschritten wird.
EIB_Counter16Bit(49996, 234) 

}
; 
?>

Wenn ich das Skript ausführe kommt folgender Fehler:
Parse error: syntax error, unexpected ‚IPS_SemaphoreLeave‘ (T_STRING) in C:\IP-Symcon\scripts\29494.ips.php on line 7

Was könnte das sein? Ich seh nix, bin ich blind?

Okay. Ich kann es gerade leider nicht testen. Sorry.

Anscheinend ja. Das Semikolon fehlt.

:banghead:
Ja, man sollte sich nicht immer auf die Zeilenangabe des Kompilers verlassen bzw. auch davor und danach suchen :smiley:
Danke fürs Augen öffnen :wink:

Also vom Prinzip hab ich jetzt das was ich wollte. Allerdings nur mit Testwerten, muss noch die entsprechenden Variablen einfügen.
Danke für die Hilfe!


<?
if (IPS_SemaphoreEnter("RTCschreiben", 3500))
{
    // Raumadresse umschalten
    EIB_Counter16Bit(35911, 52); 
    // 3s warten
    IPS_Sleep(3000);
    // Temperatur schreiben
    EIB_Counter16Bit(49996, 220); 
    //Semaphore wieder freigeben
    IPS_SemaphoreLeave("RTCschreiben");
}
; 
?>

Wozu sind die 3 Sekunden Pause?

Der Hersteller gibt die 3s Pause vor damit in der Wärmepumpe die Raumadresse sicher umgeschalten werden kann bevor die Temperatur geschrieben wird. Obs nötig ist oder nicht, ich glaubs nicht, aber ich halt mich mal an die Herstellerangabe.

Okay. Das solltest Du nur nicht allzu oft in zu vielen Skripten machen, ansonsten kann es passieren, dass Dir die Threads voll laufen und IPS dann nicht mehr in Echtzeit reagiert. So, wie es jetzt ist, wird der Thread für die Dauer des Skriptes + 3 Sekunden blockiert.

Besser wäre es dann, einen SkriptTimer zu erstellen, der das Skript dann nach 3 Sekunden wieder aufruft.

Besser wäre es dann, einen SkriptTimer zu erstellen, der das Skript dann nach 3 Sekunden wieder aufruft.

Womit mein Vorschlag wieder ins Rampenlicht rückt :slight_smile:

Ja, dessen bin ich mir bewusst. Allerdings ist ja nur maximal ein Sleep aktiv, die anderen Skripte werden ja durch das Semaphore geblockt. Es geht hier um vier Skripte die hier zusammenspielen. Diese werden nur getriggert wenn sich an einem Sensor die Temperatur ändert. Die Sensoren haben glaub ich eine Aktualisierungsrate von ca 1 min. Also ich denk das ist alles recht überschaubar.

Ich bin hier einfach mal den einfachsten Weg gegangen der für mich am schnellsten zu durchschauen war. Hab leider nur wenig Zeit das nötigste umzusetzen, werde wohl eher nicht zum Poweruser :wink:

Bin mir aber durchaus bewusst, dass man mit Sleep Befehlen vorsichtig umgehen muss. Trotzdem danke für die Hinweise! :wink:

Ok, ihr habt mich überzeugt :wink:

Ich denke es ist besser ein Skript zu haben das alles erledigt als mehrere einzelne.

Ich hab mir das Beispiel mit dem Skripttimer und der Schrittkette nochmal angeschaut und etwas ausgemistet und umgestaltet.
Leider kann ich es nicht mehr testen. Aber vielleicht könnt ihr mal einen Blick drauf werfen ob das so machbar ist?

Ich würde das Skript dann über ein Ereignis mit IPS_RunScript alle 10 Minuten starten und dann sämtliche Raumdaten an die WP schicken. Wäre der richtige Weg oder?

<?php
$step =    GetValue(30180 /*Schrittmerker*/);
$setpoint = (GetValue(59741 /*Raumsolltemperatur*/)*10); //*10 weil WP Ganzzahl erwartet

if(($IPS_SENDER <> "TimerEvent")and($step == 0)){
    $step = 1;
}
if($IPS_SENDER == "TimerEvent"){
    switch($step) {
      case 1:
        $step = $step++;
        IPS_SetScriptTimer($IPS_SELF, 3);
        // Raumadresse auf 50 umschalten
        EIB_Counter16Bit(35911, 50);
       break;
   case 2: // Raumwerte OG schreiben
        $step = $step++;
        IPS_SetScriptTimer($IPS_SELF, 1);
        // Raum Solltemperatur schreiben
        EIB_Counter16Bit(28260, $setpoint);
        // Raum Isttemperatur schreiben
        EIB_Counter16Bit(28260, (GetValue(38372)*10);
        break;
    case 3:
        $step = $step++;
        IPS_SetScriptTimer($IPS_SELF, 3);
        // Raumadresse auf 51 umschalten
        EIB_Counter16Bit(35911, 51);
       break;
   case 4: // Raumwerte Kind 1 schreiben
        $step = $step++;
        IPS_SetScriptTimer($IPS_SELF, 1);
        // Raum Solltemperatur schreiben
        EIB_Counter16Bit(28260, $setpoint);
        // Raum Isttemperatur schreiben
        EIB_Counter16Bit(28260, (GetValue(38372)*10);
        break;
   case 5:
        // Ablauf  fertig
        SetValue(30180 /*[6 Szenarien\Beschatten\Step]*/, 0);
        IPS_SetScriptTimer($IPS_SELF, 0);
    }
//Schrittnumer an Variable übergeben
SetValue(30180, $step);
} 
?>

Hab mittlerweile die Funktion am Laufen, so siehts aus.
Für weitere Raumadressen muss ich dann einfach noch die Schritte 1 und 2 vervielfältigen.

Nochmals Danke für eure Hilfe!

<?php
$step =    GetValue(30180 /*Schrittmerker*/);
$setpoint = (GetValue(59741 /*Raumsolltemperatur*/)*10); //*10 weil WP Ganzzahl erwartet

if(($IPS_SENDER <> "TimerEvent")and($step == 0)){   // Skript wurde nicht durch Timer gestartet und Schrittkette ist auf 0
    $step = 1;
    IPS_SetScriptTimer($IPS_SELF, 1); // Skript soll nach 1s wieder gestartet werden
}

if($IPS_SENDER == "TimerEvent"){
    switch($step) {
      case 1:
        // Schrittmerker um 1 erhöhen
        $step++;    
        // Skript soll nach 3s wieder gestartet werden
        IPS_SetScriptTimer($IPS_SELF, 3); 
        // Raumadresse auf 50 umschalten
        EIB_Counter16Bit(35911, 50);
       break;
   case 2: // Raumwerte OG schreiben
        // Schrittmerker um 1 erhöhen
        $step++;    
        // Skript soll nach 1s wieder gestartet werden
        IPS_SetScriptTimer($IPS_SELF, 1);
        // Raum Solltemperatur schreiben
        EIB_Counter16Bit(28260, $setpoint);
        // Raum Isttemperatur schreiben, Wert aus Variable holen und mit 100 multiplizieren
        EIB_Counter16Bit(49996, (GetValue(20344)*10));
        break;
   case 3:
        // Ablauf  fertig
        $step = 0;
        IPS_SetScriptTimer($IPS_SELF, 0);
    }
}
//Schrittnumer an Variable übergeben
SetValue(30180, $step); 
?>