Statusabfrage träge,Semaphore?

Hallo zusammen, ich habe mir jetzt ein Script geschrieben, worüber ich meine Rollos über den HomePilot steuern kann. Wenn ich jetzt mit setPosition($rollo, 100); das Rollo runter fahre muss ich ca. 3Sek warten bis ich mit getPosition($rollo); die richtige Position auslesen kann.

Alle 30 Sekunden soll die Position des Rollos periodisch abgerufen werden (um manuelle Positionsänderungen mitzubekommen) und bei Änderung in die Positionsvariable geschrieben werden. Diese wird mit Schieberegler im Webfront zum Steuern angezeigt. Bei Änderung der Position mit dem Schieberegler wird setPosition() ausgeführt.
Wenn ich jetzt <3Sek vor Positionsabfrage die Position setze. Bekommt er noch die alte Position und fährt das Rollo wieder auf die alte Position zurück.

Sollte ich in setPosition() ans Ende ein sleep(3) einbauen und in getPosition() und setPosition() Semaphore einbauen? Oder hat jemand eine bessere Idee?

Danke!

Gruß Basti

Hat wirklich keiner eine Idee? Ich komme hier seit Tagen nicht weiter. :frowning: Semaphore fallen wohl weg, da ich ja sonst während er die Positionsabfrage macht nicht setPosition() ausführen kann.

Ich hätte noch eine Idee, aber das kann keine gute Lösung sein:

Immer wenn ich setPosition() ausführe schreibe ich einen boolean Wert in eine MySQL DB. Bei getPosition() frage am Anfang und Ende des Scripts die Variable ab. Wenn true dann warte 3 Sekunden und fühere getPos() erneut aus. Nach der Wartezweit kann der Wert in der MySQL Datenbank wieder auf false gesetzt werden.

Danke!

Gruß Basti

P.S.: Vielleicht kann ein Mod das mal unter Scripte verschieben…

Wozu einen Wert in eine DB schreiben? Nimm eine Variable in IPS und setze sie entsprechend.

Habe das hier an einigen Stellen so gelöst. Wenn die Variable TRUE ist, dann probiert dss Script es so lange, bis sie wieder FALSE ist.

Gruß,
Christoph

Daran sieht man, dass ich noch IPS Anfänger bin. Klar der umständliche Weg über eine MySQL Datenbank ist nicht nötig.

Aber kann ich denn in setPosition() die Variable auf wieder FALSE setzen? Nach dem Ausführen von setPosition() soll die Variable noch 3 Sek auf TRUE bleiben und dann wieder auf FALSE gesetzt werden. Allerdings soll ja die setPosition() Funktion nicht 3 Sekunden laufen/brauchen…

Danke!

Kann ich ein Ereigniss an die Variabel hängen, welches bei setzten auf TRUE ein weiteres Skript aussführt. Dort mache ich ein IPS_SLEEP(3000) und Variable=FALSE; ?

Kann man das verstehen was ich meine? Hier nochmal in Pseudocode:

IPS Variable: lockStatusUpdate = FALSE;

setPos() {
IPS_SetBool(lockStatusUpdate) = TRUE;
fahre Rollo an pos
}

Ereignis: Wenn lockStatusUpdate == TRUE dann IPS_Sleep(3000); lockStatusUpdate = FALSE;

getPos() {
if (IPS_GetBool(lockStatusUpdate) = TRUE) WARTE
frage Position ab

if (IPS_GetBool(lockStatusUpdate) = TRUE) return getPos()
else return aktuelle Position;
}

Aber wie realisiere ich das WARTE?

So? Oder wird dadurch die CPU zu stark ausgelastet?
while(IPS_GetBool(lockStatusUpdate) != TRUE) {

}

Ich glaube eher, wenn ich dein Problem so durch lese, dass du die Ansteuerung ändern solltest.
Bitte korrigierte mich:
Dein Aktionsskript ändert die Pos-Variable.
Das ändern der Var löst das SetPos aus.
Das ändere mal so dass das Aktionsskript gleich SetPos ausführt und die Var ändert.
Und das Ereignis für das SetPos löschen.
Dann hast du keine Schleife mehr durch die Var Änderungen.
Michael

So „leicht“ ist es nicht: Ich habe die funktion getPos() und setPos() in einem externen Script was ich einbinde.

Ich habe eine IPS Variable pos. Bei Variablenänderung von pos wird ein Aktionsscript gestartet, worin die setPos() Funktion aufgerufen wird.

Zusätzlich alle 30Sekunden:
Eignes periodisches Script welches den Status mit getPos() abruft und in die IPS-Variable speichert, falls sie sich geändert hat.

Variablenänderungen sollten niemals die HW ansteuern, das ist dein Problem.
Das sollte das Aktionsskript direkt machen.
Michael

Hm irgendwie stehe ich auf dem Schlauch. Eine Variable kann doch keine HW ansprechen? setPos() und getPos() wird ja immer über ein Aktionsskript ausgeführt.

Wie hier beschrieben: „Bei Variablenänderung von pos wird ein Aktionsscript gestartet, worin die setPos() Funktion aufgerufen wird.“

Oder verstehe ich da was falsch?

//EDIT:
Anders als: Aktionsscript bei Variablenänderung lässt sich doch garkeine Rollosteuerung realisieren, oder liege ich da falsch? Im WebFronst soll ein Schieberegler von 0-100% angezeigt werden.

Mal eben schnell zusammengetippt…kann Fehler enthalten :slight_smile:
Bin auf dem Sprung zur Weihnachtsfeier:


<?
// Funktionen einbinden
require_once(IPS_GetScriptFile(99999));
$devices= array(
12345 => "HW1",
12346 => "HW2",
12347 => "HW3"
);

if ($_IPS['SENDER'] == "WebFront") //Wen von WebFront bedient wird
{
	$device = $devices[$_IPS['VARIABLE']];  //Variable ID zu Gerät
	$result = setPos($device);    // Hardware ansteuern
	if ($result === false) echo "Fehler beim Ansteuern der Hardware";  // Fehler im WebFront ausgeben
	else SetValueFloat($_IPS['VARIABLE'],$_IPS['VALUE']);    // Bei Erfolg Variable nachführen, da sonst erst nach 30Sek der neue Wert sichbar ist.
}
elseif (($_IPS['SENDER'] == "TimerEvent") or ($_IPS['SENDER'] == "Execute"))  //Ausführen oder Timer
{
	IPS_SetScriptTimer($_IPS['SELF'],0);  //Timer erstmal aus, dann Abfragen (falls die Abfrage Timeout führen kann...)
	foreach ($devices as $id => $device)
	{
	   if ((time() - IPS_GetVariable($id)['VariableUpdated']) < 10) continue; //Variable wurde vor weniger als 10sek geändert -> Also von setPos geändert -> Abfrage überspringen
	   $newPos = getPos($device); // false bei Fehler, sonst neuer Wert als Float
	   if ($newPos !== false) SetValueFloat($id,$newPos);    // Bei Erfolg Variable ändern
	}
	IPS_SetScriptTimer($_IPS['SELF'],30);
}
?>

Michael

PS: Du brauchts keine weiteren Ereignisse, nur bei den Variablen das hier als Aktions-Skript.
Edit:
Aktionsskripte werden die Scripte genannt welche durch die Bedienung im Webfront eine Aktion auslösen sollen.
Das muss nicht heißen dass hier nur eine Var gesetzt wird. Sondern es sollte schon die ‚Aktion‘ also die HW angesteuert werden.

Hallo Michael,

ahhso jetzt hab ich das mit dem Aktionsscript verstanden :smiley: Vielen dank!

Allerdings bleibt das ursprüngliche Problem mit den 3 Sekunden auch bei deinem Script immer noch bestehen.
Wenn das Script übers WebFront weniger als 3 Sekunden, bevor es perodisch aufgrufen würde, gestartet wird. Setzt es wieder die „alte“ Position, da getPos() nur die neue/richtige Position bekommt wenn setPos() 3 Sekunden vorher nicht ausgeführt wurde.

Viel Spaß bei der Weihnachtsfeier! :slight_smile:

Gruß Basti

Stimmt getpos holt dann die ‚alte‘ Position. Dann wie oben schon beschrieben einfach im Sender=Webfront eine Hilfsvar setzen, und im Getpos auswerten. Wenn wahr dann getpos überspringen.
Durch das SetValue bei det Aktion sollte der Wert ja stimmen.
Rücksetztscript ist ebenfalls am besten über Scripttimer zu lösen.
Kann ich morgen mal Posten.
Michael

Das wäre super nett! Ich habe einfach Probleme IPS ohne passende Geräte/Module zu verstehen. Meine jetzigen Geräte muss ich halt alle „manuell“ einbinden.

Das Aktionsscript muss ich einmal Manuell ausführen, damit der Timer gesetzt wird? Wie ist das dann nach einem IPS neustart?

Funktionen die ich bisher implementiert habe:


$result = HP_getFullAllDevicesStatus(); // dauert ca. 1000ms (Array 1zu1 unformatiert wie es vom HomePilot kommt)
HP_getFullDeviceStatusStandAlone($deviceID); // ca. 100ms schneller als HP_getFullAllDevicesStatus()
HP_getFullDeviceStatus($deviceID, $result); //Array mit einem Gerät 1zu1 unformatiert
HP_getDeviceBugStatus($result); //Liest Fehlerstatus aus einem Gerät (returnt ein Array)
HP_getDeviceAutomation($result);  //Liest Automationen aus einem Gerät (returnt ein Array)
HP_getDevicePosition($result); //Liest Pos aus einem Gerät (returnt ein Array)
HP_getDeviceSwitchingState($result); // //Liest Zustand aus (Steckdose): pos=100 -> an und pos=0 ->  aus  (returnt ein Array)
HP_getDeviceInfo($result); //Liest Namen und Beschreibung aus (returnt ein Array)
HP_getReturnAsBoolean($result); //Liesst Status aus Array aus - bei Erfolg true und bei Fehler false

HP_setDeviceCommand($deviceID, POSITION_N, 50); //Command (returnt ein Array)
HP_setDevicePosition($deviceID, 100); //Command für Rollo (returnt ein Array)
HP_setDeviceSwitchingState($deviceID, AUS); //Command Steckdose (returnt ein Array)
HP_setDeviceAutomation($deviceID , MORGENDAEMMERUNG, AN); // Rollo Automationstasten (returnt ein Array)

Ich wollte immer den Status aller Geräte abrufen (HP_getFullAllDevicesStatus), da dies 1000ms dauert. Wenn ich
den Status einzeln für jedes Gerät abrufen würde, dauert das pro Gerät 900ms und das bei 20 Rollos… Der
HomePilot (Gerät welches ich über http ansteure) wäre über die vielen Anfragen wohl auch nicht begeistert.

Beispielscript Position setzen:


<?
require_once("50358.ips.php"); //[HomePilot\HomePilot Controller]

$result = HP_setDevicePosition(10015 , 100); //Rollo
//$result = HP_setDeviceCommand($deviceID, POSITION_N, 50); //identisch zu oberen 

print_r(HP_getReturnAsBoolean($result) ? 'Status: OK' : 'Status: FEHLER');
?>

Beispielscript Position abfragen:


<?
require_once("50358.ips.php"); //[HomePilot\HomePilot Controller]

$result = HP_getFullAllDevicesStatus();
$result = HP_getFullDeviceStatus(10015, $result);
$result = HP_getDevicePosition($result);

print_r(HP_getReturnAsBoolean($result) ? 'Status: OK' : 'Status: FEHLER');

//$devicePos = $result['Position'];
?>

Mein Ziel für jedes Rollo (Ich hoffe das das so Sinn ergibt):
Dummy Instanz mit Variable Position (Schieberegeler), Morgendämmerung (Schalter), Abendämmerung (Schalter), Zeitsteuerung (Schalter), Manuellbetrieb (Schalter), Sonne (Schalter), Regen (Schalter), Wind (Schalter), Fehlerstatus (soll Position Icon ändern wenn Gerät Fehler hat)

Wenn ein Befehl nicht erfolgreich ausgeführt wurde oder Variable Fehlerstatus === true soll das Icon der Variable Position auf „Fehler“ geändert werden. Wenn nicht normales Icon.

Für die Automations-Schalter brauche ich dann ein eigenes Aktionsscript, aber nicht noch eine periodische Statusabfrage. Sollte ich „Position setzen“, „Automation setzen“ und „Statusabfrage“ in 3 eigene Scripte auslagern?

Vielen Dank!

Gruß Basti

Ich habe oben jetzt eine Abfrage eingebaut, welche getPos überspringt, wenn die Variable innerhalb der letzten 10sek aktualisiert wurde.
Ist dann ja auch egal, da der Teil vom Script welches als Aktionsskript dient (Sender=WebFront) den Wert schon beim HW-Ansteuern nachgeführt hat.

Wie du jetzt deine anderen Funktionen umsetzt ist gröstenteils Ansichtssache.
Zuerst würde ich empfehlen alle das alle diese Variablen welche über das WF bedient werden, und somit ein Aktionsskript starten die Fehlermeldung direkt per echo ausgeben. Dann siehts du beim betätigen gleich das was nicht funktioniert hat.
Dazu solltest du vielleicht deine Funktionen von deinem HP-Script so umbauen das die bei Erfolg den Wert/Array zurückgeben und bei Fehler ein false.
Das kann dann ganz leicht mit $ret ===false -> echo ‚fehler‘ else -> Werte speichern abgefragt werden.

Die ‚meisten‘ IPS-HW-Instanzen funktionieren nach einer Bidirektionalen Kommunikation.
Dabei ist die Ansteuerung der HW entweder die eingebaute ‚Standardaktion‘ bzw. ein PHP-Befehl. Niemals direkt ein ändern der StatusVariable selbst (wie der Name sagt gibt sie nur den Status wieder). Das ist hier ganz gut erklärt unter StatusVariablen http://www.ip-symcon.de/service/dokumentation/konzepte/variablen/
Die StatusVariable wird dann durch die Rückmeldung der HW nachgeführt. Dies kann durch intelligenz seitens der HW automatisch passieren (EIB / Homematic / Z-Wave), oder IPS pollt die HW regelmässig (ModBus, 1-Wire).
Teilweise wird die StatusVariable von IPS gleich beim ansteuern nachgeführt (Status emulieren) weil die Rückmeldung der HW zu lange braucht und der Bediener dann keine Änderung beim Schalten im WF sieht.

Wenn du jetzt so etwas zu Fuß nachbaust, solltest du also ebenfalls in etwas diesem Weg folgen.
HW-Ansteuern -> Bei Fehler diesen Ausgeben
Kein Fehler -> 'Status’Variable nachführen, da es sonst bis zu 30sek dauert bis deine LeseTimer den Wert holt.

Und um das jetzt das Lesen der alten Werte zu umgehen, habe ich oben das Script geändert.
Diese Funktionalität kannst du natürlich auch direkt in die Funktionen deines HP-Script einbauen.

Auch das/die Aktionsscripte kannst du zusammenfassen.
Dafür nutze ich gerne den Ident einer Variable bzw. Instanz.
Z.B. erhalten alle Positions-Variablen den Ident Pos, alle Automationen-Variablen den Ident Modus etc…
Und im Script kannst du dann abfragen mit IPS_GetObject($_IPS[‚VARIABLE‘])[ObjectIdent] ==‚Pos‘ -> Betätigte Variable $_IPS[‚VARIABLE‘] ist eine Positions-Variable und soll dann SetPos aufrufen.

Vielleicht bist du jetzt total verwirrt, oder aber ich habe dir zumindest genug Denkanstöße geliefert :slight_smile:

Michael

Hallo Michael,

im Gegenteil, dein Beitrag hat mir extrem viel gebracht. Soviel kann ich mir so schnell nicht anlesen.
Ungefähr so hab ich mir das auch vorgestellt. Bei mir wird halt immer ein Array zurückgegeben
egal ob Fehler oder nicht, da ich so auch noch die explizite Fehlermeldung bekomme, warum es
nicht geklappt hat. In dem Array ist aber auch ein Element Status welches ich mit HP_getReturnAsBoolean($result);
auf true oder false überprüfen kann, ob der Befehl funktioniert hat.

Dann werd ich mich da mal ran machen, wird ein paar Tage dauern, aber ich gebe aufjedenfall Rückmeldung.

Achso eine Frage hab ich noch: Sollte ich die IPS Variablen alle manuell erstellen und das Aktionsscript manuell anfügen?

Vielen Dank!

Gruß Basti

Du kannst dir mit den PHP-Befehlen von IPS auch eine Art Installer schreiben welcher die Instanzen, Variablen inkl. Aktion und Profilen erstellt und zuweist.
Ist relative simpel, aber immer die Frage ob sich der Aufwand lohnt. Wenn du aber jetzt 20 Rollläden mit je 5 Vars erstellen musst, lohnt sich der Aufwand schon.
Oder nur eine Instanz erstellen und testen bis es geht und dann die Instanzen duplizieren (per Script oder demnächst auch per Konsole).
Michael

Okay kopieren, hatte ich versucht, wusste nicht das das per Script schon möglich ist.
Oder einfach ein Installer-Script für Rollos und ein Installer-Script für Schaltsteckdosen.
welches ich an die gewünschte Position kopiere und dann erstellt er mir eine Dummy Instanz
mit allen dazugehörigen Variablen für ein Gerät.

Aber ich habe noch eine andere Idee:

Im Wiki habe ich mir Scripte zur SOAP Schnittstelle der Firtzbox angeschaut. Dort werden
die Variablen einfach mittels einer Hilfsfunktion UpdateIPSvar() angelegt/geupdatet.
Hier der Link: http://www.ip-symcon.de/wiki/SOAP-Funktionen_für_die_FritzBox
Dazu wird keine ID verwendet sondern nur der Ident, ist sowas sinnvoll? So könnte ich gucken
ob die Dumm Instanz mit Variablen schon verhanden ist, falls ja nur updaten, falls nein Dummy Instanz mit passenden
Variablen anlegen. Dazu müsste ich testen ob es ein Rollo ist und wenn ja dann in Kategorie: Geräte->Rolläden eine Dummy Instanz mit passenden Variablen erstellen. Wenn es eine Schaltsteckdose ist in Kategorie Geräte->Schaltsteckdosen eine Dummy Instanz mit passenden Variablen erstellen.

Zusätzlich könnte ich sogar alle am HomePilot angemeldeten IDS der Geräte abrufen, sodass automatisch für
alle am HomePilot angemeldeten Geräte Dummy Instanzen mit den passenden Variablen in der jeweiligen Kategorie
erstellt werden. Aber macht das sinn? Oder lieber jedes Gerät manuell anlegen.

Gruß Basti

//EDIT: P.S.: An dem HomePilot sind momentan 17 Rollos und 1 Schaltsteckdose angeschlossen.

//EDIT2: Ich sehe grad die FritzBox Scripte sind von dir :slight_smile:

Klar kannst du auch durch das Abfragen automatisch Instanzen und Variablen anlgegen, wenn nicht vorhanden bzw. das Objekt mit diesem Ident nicht gibt.
Den Ident zu verwenden ist häufig besser als den Namen, welcher ja für die Visu gerne mal geändert wird.
Außerdem ist der Ident pro Ebene eindeutig.
Und du kannst die Scripte universell erstellen ohne die ObjektID für jedes Objekt anpassen zu müssen.
Der Ident wird bei internen Modulen verwendet um zu Instanze dazugehörige Variablen zu identifizieren.
Ist also der ‚sinnvollste‘ Weg.
Du musst nur eine Basis-Ebene z.b. eine Kategorie haben ab wo dein Script die Dummy-Instazen und darunter die Variablen sucht.
Michael

Ja, den Namen würde ich nicht verwenden. Entweder die ID (wobei das ja nicht funktioniert bei der UpdateIPSvar()-Funktion) oder halt den Ident. Dann werde ich das erstmal mit dem Ident versuchen. Ich hoffe es wird mir nicht zu komplex, aber versuchen will ich es.

Ich prüfe welche Art Gerät es ist und lege dann entweder die Kategorie
Geräte->Rolläden oder Geräte->Schaltsteckdosen als Kategorie, worin gesucht
werden soll, fest. //EDIT: Oder ist das keine sinnvolle Einordnung? Sortierung nach Geschoss und Raum
wollte ich eigentlich nur im WebFront (mit Links) machen und in Objektbaum einfach nur nach
Gerätetyp, unabhängig vom Gerätehersteller und Einsatzort. (Was ich mir noch vorstellen könnte: Geräte -> Schaltsteckdosen -> HomePilot und Geräte -> Schaltsteckdosen -> HomeMatic also nochmal nach Hersteller unterscheiden)

Allerdings müsste ich so ja für jede Variable einen eigenen Ident setzen und kann dann nicht mehr so einfach prüfen ob es
eine Variable „Position“ oder eine Variable „Automation“ ist. Wie von dir vorhin vorgeschlagen:

Auch das/die Aktionsscripte kannst du zusammenfassen.
Dafür nutze ich gerne den Ident einer Variable bzw. Instanz.
Z.B. erhalten alle Positions-Variablen den Ident Pos, alle Automationen-Variablen den Ident Modus etc…
Und im Script kannst du dann abfragen mit IPS_GetObject($_IPS[‚VARIABLE‘])[ObjectIdent] ==‚Pos‘ -> Betätigte Variable $_IPS[‚VARIABLE‘] ist eine Positions-Variable und soll dann SetPos aufrufen.

Danke!

Gruß Basti