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.
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.
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.
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
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
Ja, man sollte sich nicht immer auf die Zeilenangabe des Kompilers verlassen bzw. auch davor und danach suchen
Danke fürs Augen öffnen
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");
}
;
?>
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.
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
Bin mir aber durchaus bewusst, dass man mit Sleep Befehlen vorsichtig umgehen muss. Trotzdem danke für die Hinweise!
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?
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);
?>