Ich stelle heute mal ein neues FHT Zeitabgleichs-Script für die IPS-Version 2.x (inkl. 2.2) vor. Es gab bereits ein tolles ähnliches Script für die V1, dessen Grundgedanken ich dabei aufgefasst habe. Von dieser V1-Version gibt es mittlerweile auch wenigstens 2 „Übersetzungen“ für die V2. Allerdings hatte ich bereits bei der V1 das Problem, dass meine FHT Ihre Befehle sehr unzuverlässig bei der FHZ abholten. Das konnte dazu führen, dass die Uhr des FHT plötzlich falsch lief.
(Beispiel: Die FHZ sendet um x:15 Uhr „es ist x:15 Uhr“ und das FHT holt sich diesen Befehl erst um x:39 Uhr aus der Queue der FHZ ab…)
Somit war ich gezwungen eine Variante mit Empfangskontrolle zu basteln. Und das funktioniert etwa so:
Das Script sucht sich nach seinem Start automatisch das FHT, das am längsten nicht mehr synchronisiert wurde und beginnt mit dem Zeitabgleich:
- Das Script wartet, bis die gesamte Queue der FHZ frei ist – das ist später für die Empfangskontrolle wichtig
- Berechnet das nächste Zeitfenster für den Empfang von Daten des jeweiligen FHT und wartet darauf – das habe ich aus der Diskussion zum o.g. Script für die V1 übernommen (obwohl es eigentlich nicht mehr nötig wäre…) Im Script habe ich das als „Timeport“ bezeichnet.
- Wenige Sekunden vor dem „Timeport“ wird die aktuelle Minute an das FHT gesendet. Sollte die Minute innerhalb dieser wenigen Sekunden noch umspringen, wird dies berücksichtigt. (Deshalb wäre das warten auf den „Timeport“ eigentlich nicht nötig…)
- Wenige Sekunden NACH diesem Timeport wird die FHZ-Queue wieder ausgelesen. Wenn diese wieder komplett frei ist, ist das Sekunden-Signal garantiert angekommen à weiter zu 5.
Ansonsten ist das Signal vermutlich nicht abgerufen worden und könnte die Zeiteinstellung des FHT nach dem verspäteten Abruf verfälschen. Also warten bis das Signal (zu spät) abgerufen wurde und dann zurück zu 2. - Nach der zweifellos erfolgreichen Übertragung des Minuten-Signals wird jetzt noch die aktuelle Stunde an die FHT übertragen (sicher = sicher).
- Auch hier wird der Abruf des Signals über die FHZ-Queue überwacht. Sofern die Queue innerhalb der aktuellen Stunde wieder auf Null ist, wurde dieses Signal ganz sicher rechtzeitig von dem FHT abgerufen. Ansonsten (falls die Stunde umspringt, bevor das Signal bei dem FHT ist) wird auch dieser Schritt wiederholt -> zurück zu 5.
Dieses Script setzt sich also so lange immer wieder einen eigenen Script-Timer, bis das FHT garantiert rechzeitig die richtigen Zeit-Signale abgerufen hat – selbst wenn das Stunden dauern sollte! Danach unternimmt das Script selbstständig nichts mehr: Für das Update des nächsten FHT muss dieses Script also möglichst von einem externen Script wieder gestartet werden (vielleicht reicht auch ein Script-Timer?). Ideal ist ein Zeitpunkt nachts (wenn wenig Funkverkehr ist) – und möglichst kurz nach einem Stundenwechsel. (z.B. 02:10 Uhr)…
Ich habe dieses Script jetzt zur Veröffentlichung bewusst nicht mehr „verschönt“ um nicht noch einen Fehler zu generieren – das ist buchstäblich meine auskommentierte Version, die bei mir seit 6 Monaten fehlerfrei läuft (jetzt auch unter V2.2). Es sind auch reichlich „echo“-Kommentare drin, die die Funktionen verdeutlichen.
Im Gegensatz zu der oben erwähnten Vorgänger-Version für die V1 ist hier allerdings etwas handarbeit bei der Installation erforderlich:
1.) Für jede FHT muss manuell eine String-Variable angelegt werden. Diese Variable wird dann vom Script im „Klartext“ beschrieben, was zur Beobachtung und Kontrolle der Funktion recht interessant ist.
2.) Innerhalb des Scripts muss (im oberen Bereich) für jede FHT eine Zeile zur Belegung der Array-Daten eingefügt werden: „ID der FHT“, „ID der Variable aus Punkt 1.“, „ID der Status-Variable des Ventilantriebs der FHT“.
3.) In der ersten Zeile bitte die ID der FHZ eintragen (statt der „00000“).
-NACHTRAG: DURCH DIE ÄNERDUNGEN IM BEITRAG NR. 9 VON HIRSCHBRAT (weiter unten) ENTFALLEN DIE HIER GENANNTEN „HANDARBEITEN“. Dadurch wird das Script „Plug&Play-fähig“ wie die Vorgängerversionen der V1!
Und jetzt endlich zum Script:
<?
$FHZ_ID=00000 /*[FHZ 1300 PC]*/;
$Sende_Interval_Ventilpos=115;
$Signal_vor_Sendezeit=11;
$FHT_Liste=array();
//FHT-Daten in Array ablegen: FHT-ID, FHT-Zeitabgleich-Variable, FHT-Ventil-Variable
$FHT_Liste[]=array(11111 /*[erste_FHT_ID]*/,22222 /*[erste_String_Variable]*/,33333 /*[erste_FHT_Ventil_ID]*/);
$FHT_Liste[]=array(44444 /*[zweite_FHT_ID]*/,55555/*[zweite_String_Variable]*/,66666 /*[zweite_FHT_Ventil_ID]*/);
$FHT_Liste[]=array(77777 /*[dritte_FHT_ID]*/,88888 /*[dritte_String_Variable]*/,99999 /*[dritte_FHT_Ventil_ID]*/);
//FHT mit dem ältesten Update suchen
$aeltester_Wert=9999999999999;
$weitersuchen=TRUE;
foreach($FHT_Liste as $FHT_Daten)
{
$v=IPS_GetVariable($FHT_Daten['1']);
$letztes_Update=$v['VariableUpdated'];
if((($letztes_Update<$aeltester_Wert) OR (GetValue($FHT_Daten['1'])<>"gesendet")) AND $weitersuchen==TRUE)
{
$aeltester_Wert=$letztes_Update;
if(GetValue($FHT_Daten['1'])<>"gesendet") $weitersuchen=FALSE; //Falls diese FHT bereits in bearbeitung ist, nicht weitersuchen
$FHT_ID=$FHT_Daten['0'];
$FHT_Variable=$FHT_Daten['1'];
$FHT_Ventil_Variable=$FHT_Daten['2'];
}
}
echo $FHT_ID."
".$FHT_Variable."
".$FHT_Ventil_Variable."
".$weitersuchen."
";
//Stunde wurde gesendet - Jetzt prüfen
if(substr((GetValue($FHT_Variable)),0,12)=="sende Stunde")
{
Stunde_pruefen($FHT_ID, $FHT_Variable, $IPS_SELF, $FHZ_ID);
return;
}
//Uhrzeit prüfen - zum Stundenwechsel könnte es zur Verschiebung kommen
if(date('i')>50)
{
echo "ungünstige Zeit (Stundenwechsel) - warten...";
IPS_SetScriptTimer ($IPS_SELF,300);
return;
}
if(date('i')<5)
{
echo "ungünstige Zeit (Stundenwechsel) - warten...";
IPS_SetScriptTimer ($IPS_SELF,120);
return;
}
//Buffer der FHZ prüfen - freier Buffer ist zur Empfangskontrolle erforderlich
$Freie_Buffer=FHZ_GetFreeBuffer($FHZ_ID);
if($Freie_Buffer<10)
{
echo "Buffer belegt... 2 Minuten warten";
IPS_SetScriptTimer ($IPS_SELF,120); //nächster Versuch in 2 Minuten (auf Buffer warten)
return;
}
//------------------ Was soll getan werden? --------------------
//Minute wurde gesendet - Jetzt Stunde senden
if(GetValue($FHT_Variable)=="Minute gesendet")
{
Stunde_senden($FHT_ID, $FHT_Variable, $IPS_SELF);
return;
}
//----------------- Minute senden ----------------------------------
//letzten und nächsten Timeport / Sendeplatz ermitteln
$v=IPS_GetVariable($FHT_Ventil_Variable);
$letzter_Timeport_Zeit=$v['VariableUpdated'];
$letzter_Timeport=intval(time()-$letzter_Timeport_Zeit);
echo "letzter Empfang: ".$letzter_Timeport." s
";
if($letzter_Timeport>$Sende_Interval_Ventilpos)
{
echo "letzte Ventilposition nicht empfangen - nächster Versuch in 1,5 Minuten!";
IPS_SetScriptTimer ($IPS_SELF,90); //nächster Versuch in 2 Minuten (Warte auf Empfang der Ventilposition)
return;
}
$Empfang_in=$Sende_Interval_Ventilpos-$letzter_Timeport;
echo "nächster Timeport: ".$Empfang_in." s
";
$Sende_in=$Empfang_in-$Signal_vor_Sendezeit;
if ($Sende_in < -1) //Sendeplatz überspringen (Signal_vor_Sendzeit um mehr als eine Sekunde unterschritten)
{
$Sende_in=$Sende_in+$Sende_Interval_Ventilpos;
}
echo "Sende in ".$Sende_in." s
";
//Signal senden oder Script beim nächsten Timeport neu starten
if ($Sende_in < 13) //Timeport getroffen - Signal senden
{
echo "Timeport getroffen - jetzt senden!
";
IPS_SetScriptTimer ($IPS_SELF, 0);
$sende_Minute=date('i',time()+$Empfang_in); //aktuelle Minute zum voraussichtlichen Zeitpunkt des Empfangs
SetValue($FHT_Variable,"sende m=".$sende_Minute);
FHT_SetMinute($FHT_ID,intval($sende_Minute));
IPS_SetScriptTimer ($IPS_SELF,0); //zunächst löschen um neuen Programmstart während Empfangstest zu vermeiden
$Empfangstest=TRUE; //nächsten Programmteil starten
}
ELSE //warten auf nächsten Timeport
{
echo "Setze Script-Timer auf ".$Sende_in." s
";
IPS_SetScriptTimer ($IPS_SELF, $Sende_in);
SetValue($FHT_Variable,"sende in ".$Sende_in."s");
$Empfangstest=FALSE; //nächsten Programmteil nicht starten
}
//------------------------------ Empfangstest für Minutensignal ------------------------------
if ($Empfangstest==TRUE)
{
IPS_Sleep(1000); //warten bis Signal im Buffer ist
$Durchlauf=0;
while((FHZ_GetFreeBuffer($FHZ_ID)<10) AND ($Durchlauf<20))
{
$Durchlauf=$Durchlauf+1;
//echo "Buffer geprüft - Signal wartet
";
IPS_Sleep(1000);
}
if(FHZ_GetFreeBuffer($FHZ_ID)==10)
{
echo "Signal wurde nach ".$Durchlauf." Sekunden abgerufen!
";
SetValue($FHT_Variable,"Minute gesendet");
IPS_SetScriptTimer ($IPS_SELF,60); //erneut starten um Übertragung der Stunde zu starten
}
ELSE //Signal wurde nicht abgerufen
{
echo "Fehler - Signal wurde nach 20 Sek nicht abgerufen!
";
SetValue($FHT_Variable,"Fehler!");
IPS_SetScriptTimer ($IPS_SELF,120); //nächster Versuch in 2 Minuten (neues Signal senden)
}
}
//---------------------------- ab hier Definition der Funktionen zur Stundenübertragung -------------
function Stunde_senden($FHT_ID, $FHT_Variable, $IPS_SELF)
{
$akt_Stunde=date('H');
SetValue($FHT_Variable,"sende Stunde ".$akt_Stunde);
echo "Sende Stunde ".$akt_Stunde."
";
FHT_SetHour($FHT_ID,intval($akt_Stunde));
IPS_SetScriptTimer ($IPS_SELF,60); //erneut starten um Empfang der Stunde zu prüfen
}
function Stunde_pruefen($FHT_ID, $FHT_Variable, $IPS_SELF, $FHZ_ID)
{
if(FHZ_GetFreeBuffer($FHZ_ID)<10) //Signal wurde noch nicht empfangen
{
echo "Stunde wurde noch nicht abgerufen - warte weiter
";
echo "gesendete Stunde: ".substr(GetValue($FHT_Variable),-2)."
";
echo "aktuelle Stunde: ".intval(date('H'))."
";
IPS_SetScriptTimer ($IPS_SELF,60); //in einer Minute erneut prüfen
return;
}
ELSE //Stunden-Signal wurde abgerufen
{
//Wurde die Stunde rechzeitig abgerufen (Stundenwechsel)?
if(substr(GetValue($FHT_Variable),-2)==intval(date('H')))
{
echo "akutelle Stunde wurde erfolgreich übertragen!
Script-Timer wird gelöscht.
";
echo "übertragene Stunde: ".substr(GetValue($FHT_Variable),-2)."
";
echo "aktuelle Stunde: ".intval(date('H'))."
";
IPS_SetScriptTimer ($IPS_SELF,0); //Vorgang beendet - Script-Timer löschen
SetValue($FHT_Variable,"gesendet");
return;
}
ELSE
{
echo "Stunde wurde zu spät übertragen!
neuer Versuch!
";
echo "übertragene Stunde: ".substr(GetValue($FHT_Variable),-2)."
";
echo "aktuelle Stunde: ".intval(date('H'))."
";
IPS_SetScriptTimer ($IPS_SELF,60);
SetValue($FHT_Variable,"Minute gesendet");
return;
}
}
}
?>
PS: Der erste Schritt des Scripts nach dem Start beginnt etwa im oberen Drittel" //Uhrzeit prüfen - …". (Leider konnte ich die Funktionen nicht ganz in der logischen Abfolge halten…)
Viele Grüße, Euer douglas882