IPSShadowing - eine Beschattungssteuerung

Danke, das war der entscheidende Hinweis! :o
So mag ich das, einfach, elegant und genial.
Einzig die Stati c_Control_Step, c_Control_StepsToDo, c_Control_StartTime müssen zurückgesetzt werden um den Refreshtimer zu deaktivieren.

Der Fehler in der 3.1 mit den falsch sortierten Assoziationen ist nun korrigiert. Ihr müsste jedoch die falsch einsortierten Einträge einmal umsortieren (dazu den Wert z.B. auf 100 ändern, Speichern und dann den Wert auf z.B. 0 zurück und wieder Speichern)

paresy

Aufruf der Installation löst das Problem natürlich auch (wenn man die Installation des WebFronts/Mobile über den Wizard deaktiviert dauert es auch nur 1-2 Sekunden)

Ich möchte meine Markise mit einem 2-Tasten-Wandschalter steuern (Taste „raus“ und „rein“). Die Logik soll sein, dass, wenn die Markise eingefahren ist, mit „raus“ das Ausfahren gestartet wird. Wenn während der Fahrt nochmal auf den Taster gedrückt wird, soll an der Stelle gestoppt werden. Dazu habe ich folgendes Skript (Variante für „raus“) erstellt, das mit der Taste als Event getriggert wird und die Variable „Step“ direkt abfrägt:

    IPSUtils_Include('IPSShadowing.inc.php', 'IPSLibrary::app::modules::IPSShadowing');
	 $device_id = 56526; /*[Program\IPSLibrary\data\modules\IPSShadowing\Devices\Device5]*/
    $device = new IPSShadowing_Device($device_id);
    $variableId = IPS_GetObjectIDByIdent(c_Control_Step, $device_id);
    $step = GetValueInteger($variableId);
    if($step == -1){
      $deviceActive = $device->MoveByControl(c_MovementId_MovedOut);
      }
	 else{
      $deviceActive = $device->MoveByControl(c_MovementId_Stop);
      };

Das klappt so einwandfrei - gibt’s dafür aber auch was „hübscheres“, als die Variable direkt per IPS-Bordmitteln abzufragen - die Methoden in der IPSShadowing_Device zur Abfrage sind ja alle private…?

Grüße,
Martin

Prinzipiell ist das schon in Ordnung, ich würde aber eher die Movement Variabale zur Steuerung verwenden:


    IPSUtils_Include('IPSShadowing.inc.php', 'IPSLibrary::app::modules::IPSShadowing');
    $device_id = 56526; /*[Program\IPSLibrary\data\modules\IPSShadowing\Devices\Device5]*/
    $device = new IPSShadowing_Device($device_id);
    $variableId = IPS_GetObjectIDByIdent(c_Control_Movement, $device_id);
    $stateId = GetValueInteger($variableId);
    if($stateId != c_MovementId_Stop){
       $deviceActive = $device->MoveByControl(c_MovementId_MovedOut);
    } else{
       $deviceActive = $device->MoveByControl(c_MovementId_Stop);
    };  

Die Fehler (nicht editierbarkeit der Profile und falsche Darstellung im Webfront) sind mit dem Update behoben.
Danke paresy und Brownson für den schnellen Fix :slight_smile:

Hallo Andreas,

ich hab mich mittlerweile weiter mit den Enocean Beschattungsaktoren, speziell den FSB14, auseinandergesetzt.

Die Implementierung der Module in IPS lässt bisher nur das Simulieren eines Tastendruckes zu (Auf,Ab,Stopp). Die einzigen Rückmeldungen die IPS bisher unterstützt, sind die Endanschläge.

Stoppt man diesen Sensor jedoch, wenn der Rollladen nicht in der Mitte ist, so sendet der Aktor die Fahrzeit. Ich habe auch schon eine RegisterVariable geschrieben, welche die Informationen auffängt. Muss das nur noch sauber in Module packen und die Informationen bei den einzelnen Aktoren ablegen (zB als Fahrzeit, oder direkt in IstPosition umrechnen).

Ferner könnte ich dem Aktor auch direkt eine Fahrzeit vorgeben. Also nicht einfach nur „Fahre hoch“ oder „Fahre runter“ definieren, sondern „Fahre hoch für 10 Sekunden“.

Ich habe mir auch das IPSComponentShutter_Enocean Modul angeschaut, mir ist jedoch nicht klar, wie ich dort den direkten Fahrzeit befehl einbauen könnte.

Die Befehle an den Aktor habe ich im Test im Endeffekt mit dem Befehl

CSCK_SendText(12345/*[Enocean Socket]*/ , MeinSendeCodeInHexFormat);

gesendet.

Den SendeCode muss ich natürzlich zusammen bauen, ja nach Angabe aus IPSShadowing.

Hierfür würde ich gerne für jeden Rollladen analog zum IPSShutterModul die Fahrzeiten für folgende Positionen festlegen:
Öffnen: unten, halb offen, offen
Schließen: halb offen, unten, geschlossen

Mit diesen Angaben und der Rückmeldung über die Fahrzeiten lässt sich dann immer die Aktuelle Position berechnen.

Ich suche derzeit in deiner Programmstruktur die Übergebene Variable für das Steuern der Aktoren. (Auf, 90%, 75%, 50%, Zu).

Es wäre Klasse wenn du mir kurz sagen könntest, ob es Möglich ist, dass ich entweder das IPSComponentShutter_Enocean Modul anpassen kann( oder ein neues IPSComponentShutter_EnoceanFBS14 Modul erstelle), welches die direkte Ansteuerung ermöglicht, sprich ich den Wert für die Zielposition dort mit einbringen kann.

Da ich gerade erst Anfange mich mit PhP auseinander zu setzen und auch das Object orientierte Programmieren neu für mich ist, brauch ich etwas länger bis ich alles verstanden habe.

Danke schon mal im Voraus und Grüße,
Maze

Hallo Maze,

Die Fahrzeit kannst Du über die Variable StepsToDo ermittlen oder Du kannst sie selbst über die Position errechnen. Vorgesehen ist eine Übergabe dieses Wertes an die Ansteuerungs Komponente aber nicht.
Sollte eigentlich auch nicht nötig sein, da IPSShadowing einen Stop auslöst, wenn die Position erreicht ist. Einfach eine Ansteuerung auf Position 0 bzw. 100 implementieren und es sollte klappen.

Zusätzlich kannst Du ja noch die aktuelle Position Deiner Register Variable nach IPSShadowing synchronisieren:


	IPSUtils_Include ("IPSShadowing.inc.php", "IPSLibrary::app::modules::IPSShadowing");
	$device = new IPSShadowing_Device($deviceId);
	$device->MoveByEvent($position);

Hallo Andreas.

Da hast du natürlich recht :slight_smile:

Mir war die Ansteuerung nur zu ungenau, da ich lediglich die auf- und Abzeiten hinterlegen kann, aber der Rollladen ja vorher unten ist. Aber das ist eigentlich nicht so wild.

Das schreiben der neuen Rollladen Position funktioniert.

Kannst du mir eine einfache Möglichkeit mitteilen, wonach die DeviceID Abfragen kann, wenn ich über eine foreach schleife aller devices dessen fortlaufende Nummer ,zB 10, kenne.

Ferner müsste für die EnoceanInstanz noch eine ReturnID zu jedem Device hinzugefügt werden. Ob jetzt im IPSShadowing Device, oder direkt im Enoceanmodul ist prinzipiell egal.

Mit noch einem kleinen Schubs von dir wegen der DeviceID habe ich das Modul bald fertig.

Gruß
Maze

PS: Als „Abfallprodukt“ ist schon ein Enocean Funkprotokoll Reader entstanden und es werden einzelne Klassen für die bei mir verwendeten Eltako Reihe 14 Aktoren entstehen

Habs schon selbst rausgefunden :slight_smile:

Dein IPSUtil_ObjectIDByPath hat geklappt.

Gruß
Maze

Hallo Andreas,

was mich bei dem MoveByEvent noch stört, ist, dass die Movement Variable auf Stopp gestellt wird und zwar auch dann, wenn der Rollladen auf Position 0% oder 100% ist. Hier sollte Movement auf Offen bzw Geschlossen gestellt werden.

Ich setze die Werte 0% und 100% auf die Rückmeldung des Aktors, dass die obere bzw untere Endlage erreicht wurden.

Für zwischen Werte, welche ich aus der Fahrzeit des Aktors berechnen kann, da passt die Anzeige der Movement Variablen mit „Stopp“.

Meine Frage ist nun:

Wenn ich in der IPSShadowing_Device.clss.php die Funktion MoveByEvent anpasse, wir diese bei einem IPS Update überschrieben?

Gruß
Maze

Würde ich mir auch für Homematic wünschen :slight_smile:

Gruß
Bruno

Hallo Zusammen,

ich hab nen bissl im IPSShadowing-Code manipuliert, habe es aber noch nicht testen können. Werde ich heute Abend machen und wenn alles läuft, dann den Code / Modifikationen hier posten.

Bearbeitet wurde die

IPSShadowing_Device.class.php
- public function MoveByEvent($Level) --> Abfrage für Level implementiert, wenn 0 oder 100, dann wird Opened bzw Closed statt Stopp geschrieben.
- private function ClacNextSteps --> Hier habe ich eingefügt, dass immer die Maximale Anzahl der Schritte (Offen bis Geschlossen und viceversa) genommen werden, wenn man „Geschlossen“ bzw „Offen“ drückt.
- wie oben --> für die 90%, 75% und 50% Positionen wurde bisher nur die TimeClosing berücksichtigt, egal in welche Richtung man fuhr. Dies hat bei mir Probleme verursacht. Deswegen habe ich hier auch noch eine Abfrage eingebaut.

Wenn alles läuft, dann poste ich den Code.

Gruß
Maze

EDIT: @ Andreas: Wieso wurde eigentlich die 25% nicht als Button umgesetzt? Ist doch eigentlich (fast) alles dafür implementiert?

Hey Maze

Schön das Du so fleißig an den FSB14 Aktoren dran bist.
Ich werde demnächst auch meine Rolladen Steuerung auf Eltako umbauen.
Dann werden mir wohl deine Veränderungen sehr zu gute kommen.

Mfg Stefan

Hallo Zusammen,

anbei der gesamte Code der Datei „IPSLibrary\app\modules\IPSShadowing\IPSShadowing_Device.class.php“

Meine Änderungen sind mit BOMMH gekennzeichnet (BeginOfModification) und enden bei EOMMH, falls sie mehr als eine Zeile sind.

Die Änderung der Fahrzeiten ist Geschmackssache. Kann man kann auch nur die Änderungen in der MoveByEvent Funktion übernehmen.

<?
	/*
	 * This file is part of the IPSLibrary.
	 *
	 * The IPSLibrary is free software: you can redistribute it and/or modify
	 * it under the terms of the GNU General Public License as published
	 * by the Free Software Foundation, either version 3 of the License, or
	 * (at your option) any later version.
	 *
	 * The IPSLibrary is distributed in the hope that it will be useful,
	 * but WITHOUT ANY WARRANTY; without even the implied warranty of
	 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
	 * GNU General Public License for more details.
	 *
	 * You should have received a copy of the GNU General Public License
	 * along with the IPSLibrary. If not, see http://www.gnu.org/licenses/gpl.txt.
	 */

	/**@addtogroup ipsshadowing
	 * @{
	 *
	 * @file          IPSShadowing_Device.class.php
	 * @author        Andreas Brauneis
	 * @version
	 *   Version 2.50.1, 21.03.2012<br/>
	 *   Version 2.50.2, 29.12.2012  Added Reset of Flags after Change of Day/Night<br/>
	 *	  Version 2.50.3, 15.01.2014  Added Movement Update after MovementByEvent<br/>
	 *
	 * Funktionen zum Bewegen der Beschattung
	 */

	IPSUtils_Include ("IPSLogger.inc.php",                  "IPSLibrary::app::core::IPSLogger");
	IPSUtils_Include ("IPSInstaller.inc.php",               "IPSLibrary::install::IPSInstaller");
	IPSUtils_Include ("IPSComponent.class.php",             "IPSLibrary::app::core::IPSComponent");
	IPSUtils_Include ("IPSShadowing_Constants.inc.php",     "IPSLibrary::app::modules::IPSShadowing");
	IPSUtils_Include ("IPSShadowing_Configuration.inc.php", "IPSLibrary::config::modules::IPSShadowing");
	IPSUtils_Include ("IPSShadowing_Custom.inc.php",        "IPSLibrary::config::modules::IPSShadowing");
	IPSUtils_Include ("IPSShadowing_Logging.inc.php",       "IPSLibrary::app::modules::IPSShadowing");

	/**
	 * @class IPSShadowing_Device
	 *
	 * Definiert ein IPSShadowing_Device Objekt
	 *
	 * @author Andreas Brauneis
	 * @version
	 *   Version 2.50.1, 01.04.2012<br/>
	 */
	class IPSShadowing_Device {

		/**
		 * @private
		 * ID des Shadowing Device
		 */
		private $deviceId;

		/**
		 * @public
		 *
		 * Initialisierung des IPSShadowing_Device Objektes
		 *
		 * @param integer $deviceId Instance ID
		 */
		public function __construct($deviceId) {
			$this->deviceId = IPSUtil_ObjectIDByPath($deviceId);
		}

		// ----------------------------------------------------------------------------------------------------------------------------
		private function GetPropertyValue($propertyName) {
			$deviceConfig = get_ShadowingConfiguration();
			$deviceName   = IPS_GetName($this->deviceId);

			$propertyValue = $deviceConfig[$deviceName][$propertyName];
			return $propertyValue;
		}

		// ----------------------------------------------------------------------------------------------------------------------------
		private function GetVariableValue($variableIdent) {
			$variableId = IPS_GetObjectIDByIdent($variableIdent, $this->deviceId);
			if ($variableId === false) {
				throw new Exception('Variable '.$variableIdent.' could NOT be found for DeviceId='.$this->deviceId);
			}
			return GetValue($variableId);
		}

		// ----------------------------------------------------------------------------------------------------------------------------
		private function SetVariableValue($variableIdent, $value) {
			$variableId = IPS_GetObjectIDByIdent($variableIdent, $this->deviceId);
			if ($variableId === false) {
				throw new Exception('Variable '.$variableIdent.' could NOT be found for DeviceId='.$this->deviceId);
			}
			SetValue($variableId, $value);
		}

		// ----------------------------------------------------------------------------------------------------------------------------
		private function SetStatus() {
			if ($this->GetVariableValue(c_Control_StepsToDo)<>"") {
				return;
			}

			$Position	= $this->GetVariableValue(c_Control_Position);
			$MovementId = $this->GetVariableValue(c_Control_Movement);
			if (!$this->GetVariableValue(c_Control_Automatic)) {
				if ($MovementId<=c_MovementId_Space and $MovementId>=c_MovementId_Closed) {
					$Status = 'Manuell';
				} elseif ($Position<=10) {
					$Status = 'Manuell';
				} else {
					$Status = "Manuell / $Position%";
				}
			} elseif ($this->GetVariableValue(c_Control_ManualChange)) {
				if ($MovementId<=c_MovementId_Space and $MovementId>=c_MovementId_Closed) {
					$Status = 'Autom./Manuell';
				} elseif ($Position<=10) {
					$Status = 'Autom./Manuell';
				} else {
					$Status = "Autom./Manuell $Position%";
				}
			} else {
				$Status = 'Automatik';
			}
			$this->SetVariableValue(c_Control_Display, $Status);
		}

		// ----------------------------------------------------------------------------------------------------------------------------
		public function MoveByCommand($command) {
			$componentParams = $this->GetPropertyValue(c_Property_Component);

			if (IPSShadowing_BeforeActivateShutter($this->deviceId, $command)) {
				$component       = IPSComponent::CreateObjectByParams($componentParams);
				switch ($command) {
					case c_MovementId_Up:
					case c_MovementId_MovingIn:
						$component->MoveUp();
						break;
					case c_MovementId_Down:
					case c_MovementId_MovingOut:
						$component->MoveDown();
						break;
					case c_MovementId_Stop:
						$component->Stop();
						break;
					default:
				}
				IPSShadowing_AfterActivateShutter($this->deviceId, $command);
			}

			if ($this->GetVariableValue(c_Control_Movement) <> $command) {
				$this->SetVariableValue(c_Control_Movement, $command);
			}
		}

		// ----------------------------------------------------------------------------------------------------------------------------
		private function MoveByStatus() {
			$this->CalcNextSteps();
			$this->SetVariableValue(c_Control_Movement, -1);
			$this->ExecuteNextStep();
			$this->StartRefreshTimer(true);
		}

		// ----------------------------------------------------------------------------------------------------------------------------
		public function MoveByEvent($Level) {
			IPSLogger_Dbg(__file__, "Received StateChange from Shutter '".IPS_GetName($this->deviceId)."', NewLevel=".round($Level).", CurrentLevel=".$this->GetVariableValue(c_Control_Position));
			if ( $this->GetVariableValue(c_Control_StepsToDo)=="") { //modified entfernt : $this->GetVariableValue(c_Control_Position) <> $Level and
				IPSLogger_Inf(__file__, "Apply StateChange from Shutter '".IPS_GetName($this->deviceId)."', Level=".round($Level));
				// BOMMH Setzt die Movement Variable für die Endpositionen korrekt
				switch ($Level) {
					case 0:
						$this->SetVariableValue(c_Control_Movement, c_MovementId_Opened);
					break;
					
					case 100:
						$this->SetVariableValue(c_Control_Movement, c_MovementId_Closed);
					break;
					
					default:
						$this->SetVariableValue(c_Control_Movement, c_MovementId_Stop);
				} // EOMMH
				$this->SetVariableValue(c_Control_Position, $Level);
				if (!$this->GetVariableValue(c_Control_ManualChange) and
				    $this->GetVariableValue(c_Control_Automatic)) {
					$this->SetVariableValue(c_Control_ManualChange, true);
				}
			$this->SetStatus();
		}
	}

		// ----------------------------------------------------------------------------------------------------------------------------
		public function MoveByProgram($ProgramId, $logMessage, $DimoutOption=null, $TriggeredByTemp=false) {
			$MovementStatus = $this->GetVariableValue(c_Control_Movement);

			$DoBeMoved = $MovementStatus;
			switch ($ProgramId) {
				case c_ProgramId_Manual:
					break;
				case c_ProgramId_Opened:
				case c_ProgramId_OpenedDay:
				case c_ProgramId_OpenedNight:
					$DoBeMoved = c_MovementId_Opened;
					break;
				case c_ProgramId_MovedIn:
					$DoBeMoved = c_MovementId_MovedIn;
					break;
				case c_ProgramId_OpenedOrShadowing:
					if ($MovementStatus<>c_MovementId_Opened and $MovementStatus<>c_MovementId_Shadowing) {$DoBeMoved = c_MovementId_Shadowing;}
					break;
				case c_ProgramId_MovedOut:
				case c_ProgramId_MovedOutTemp:
					$DoBeMoved = c_MovementId_MovedOut;
					break;
				case c_ProgramId_Closed:
					$DoBeMoved = c_MovementId_Closed;
					break;
				case c_ProgramId_90:
					$DoBeMoved = c_MovementId_90;
					break;
				case c_ProgramId_75:
					$DoBeMoved = c_MovementId_75;
					break;
				case c_ProgramId_50:
					$DoBeMoved = c_MovementId_50;
					break;
				case c_ProgramId_25:
					$DoBeMoved = c_MovementId_25;
					break;
				case c_ProgramId_Dimout:
					$DoBeMoved = c_MovementId_Dimout;
					break;
				case c_ProgramId_DimoutOrShadowing:
					if ($MovementStatus<>c_MovementId_Dimout and $MovementStatus<>c_MovementId_Shadowing) {$DoBeMoved = c_MovementId_Shadowing;}
					break;
				case c_ProgramId_DimoutAndShadowing:
					if ($DimoutOption) {
						$DoBeMoved = c_MovementId_Dimout;
					} else {
						$DoBeMoved = c_MovementId_Shadowing;
					}
					break;
				case c_ProgramId_LastPosition:
					$DoBeMoved = $this->GetVariableValue(c_Control_TempLastPos);
					break;
				default:
					IPSLogger_Err(__file__, "Unknown ProgramId $ProgramId, DeviceId=".$this->DeviceId);
					exit;
			}
			if ($DoBeMoved<>$MovementStatus) {
				if ($TriggeredByTemp and !$this->GetVariableValue(c_Control_TempChange)) {
					$this->SetVariableValue(c_Control_TempChange, true);
					$this->SetVariableValue(c_Control_TempLastPos, $this->GetMovementIdByPosition());
				}
				$this->SetVariableValue(c_Control_Movement, $DoBeMoved);
				$this->MoveByStatus();
				IPSShadowing_LogMoveByProgram($this->deviceId, $ProgramId, $logMessage, $TriggeredByTemp);
			}
		}

		// ----------------------------------------------------------------------------------------------------------------------------
		private function GetMovementIdByPosition() {
			$shadowingType     = $this->GetPropertyValue(c_Property_ShadowingType);
			$currentMovementId = $this->GetVariableValue(c_Control_Movement);
			$currentPosition   = $this->GetVariableValue(c_Control_Position);

			if ($currentMovementId<>c_MovementId_Stop) {
				$lastPosition = $currentMovementId;
			} elseif ($currentPosition<10) {
				if ($shadowingType==c_ShadowingType_Marquees) {
					$lastPosition = c_MovementId_MovedIn;
				} else {
					$lastPosition = c_MovementId_Opened;
				}
			} elseif ($currentPosition<30) {
				$lastPosition = c_MovementId_25;
			} elseif ($currentPosition<55) {
				$lastPosition = c_MovementId_50;
			} elseif ($currentPosition<80) {
				$lastPosition = c_MovementId_75;
			} elseif ($currentPosition<92) {
				$lastPosition = c_MovementId_90;
			} else {
				if ($shadowingType==c_ShadowingType_Marquees) {
					$lastPosition = c_MovementId_MovedOut;
				} elseif ($shadowingType==c_ShadowingType_Shutter) {
					$lastPosition = c_MovementId_Closed;
				} else {
					$lastPosition = c_MovementId_Shadowing;
				}
			}
			return $lastPosition;
		}

		// ----------------------------------------------------------------------------------------------------------------------------
		public function MoveByControl($Value) {
			if ($Value==c_MovementId_Space) {
				return;
			} elseif ($this->GetVariableValue(c_Control_Movement)==$Value) {
				return;
			} else {
				if (!$this->GetVariableValue(c_Control_ManualChange)) {
					$this->SetVariableValue(c_Control_ManualChange, true);
				}
				$this->SetVariableValue(c_Control_Movement, $Value);
				$this->MoveByStatus();
				IPSShadowing_LogMoveByControl($this->deviceId);
			}
		}


		// ----------------------------------------------------------------------------------------------------------------------------
		private function AddNextStep(&$StepsToDo, $Command, $SecondsToDo, $Display, $SecondsTotal, $PercentagePosition) {
			$Step = count($StepsToDo);
			$StepsToDo[$Step]   = $Command;
			$StepsToDo[$Step+1] = $SecondsToDo;
			$StepsToDo[$Step+2] = $Display;
			$StepsToDo[$Step+3] = $SecondsTotal;
			$StepsToDo[$Step+4] = $PercentagePosition;
		}

		// ----------------------------------------------------------------------------------------------------------------------------
		private function CalcNextSteps() {
			$DeviceName   = IPS_GetIdent($this->deviceId);
			$DeviceConfig = get_ShadowingConfiguration();

			$Position     = $this->GetVariableValue(c_Control_Position);
			$ToBeMoved    = $this->GetVariableValue(c_Control_Movement);
			$StepsToDo    = array();
			//BOMMH c_MovementId_Opened und c_MovementId_Up wurden getrennt
			if ($ToBeMoved==c_MovementId_Opened) {
				$SecTotal     = $DeviceConfig[$DeviceName][c_Property_TimeOpening];
				$SecNullToPos = $SecTotal*$Position/100 + 2; // BOMMH Somit wird immer die Gesamte Distanz aufgefahren und es ist sicher gestellt, dass der Rollladen offen ist. Original: $SecNullToPos = $SecTotal*$Position/100;
				$SecPosTo100  = $SecTotal-$SecNullToPos;
				$this->AddNextStep($StepsToDo, c_MovementId_Up, $SecTotal-$SecPosTo100, null,    $SecTotal, $SecPosTo100);
				$this->AddNextStep($StepsToDo, c_MovementId_Stop,   $DeviceConfig[$DeviceName][c_Property_TimePause],  'Offen (Stop)', null, null);
				$this->AddNextStep($StepsToDo, c_MovementId_Opened, 1, null, null , null);
			
			} elseif ($ToBeMoved==c_MovementId_Up) {
			   $SecTotal     = $DeviceConfig[$DeviceName][c_Property_TimeOpening];
				$this->AddNextStep($StepsToDo, c_MovementId_Up, $SecTotal, null,    $SecTotal, 0); //BOMMH $this->AddNextStep($StepsToDo, c_MovementId_Up, $SecTotal-$SecPosTo100, null,    $SecTotal, $SecPosTo100);
				$this->AddNextStep($StepsToDo, c_MovementId_Stop,   $DeviceConfig[$DeviceName][c_Property_TimePause],  'Offen (Stop)', null, null);

			} elseif ($ToBeMoved==c_MovementId_MovedIn or $ToBeMoved==c_MovementId_MovingIn) {
				$SecTotal     = $DeviceConfig[$DeviceName][c_Property_TimeOpening];
				$SecNullToPos = $SecTotal*$Position/100;
				$SecPosTo100  = $SecTotal-$SecNullToPos;
				$this->AddNextStep($StepsToDo, c_MovementId_MovingIn, $SecTotal-$SecPosTo100, null,    $SecTotal, $SecPosTo100);
				$this->AddNextStep($StepsToDo, c_MovementId_Stop,   $DeviceConfig[$DeviceName][c_Property_TimePause],  'Offen (Stop)', null, null);
				$this->AddNextStep($StepsToDo, c_MovementId_MovedIn, 1, null, null , null);

			} elseif ($ToBeMoved==c_MovementId_Shadowing or $ToBeMoved==c_MovementId_Down or $ToBeMoved==c_MovementId_Dimout or $ToBeMoved==c_MovementId_Closed or $ToBeMoved==c_MovementId_MovingOut or $ToBeMoved==c_MovementId_MovedOut) {
				$SecTotal     = $DeviceConfig[$DeviceName][c_Property_TimeClosing];
				$SecNullToPos = $SecTotal*$Position/100;
				if ($ToBeMoved==c_MovementId_Dimout) {
					$this->AddNextStep($StepsToDo, c_MovementId_Down,   $SecTotal-$SecNullToPos, null, $SecTotal, $SecNullToPos);
					$this->AddNextStep($StepsToDo, c_MovementId_Stop,   $DeviceConfig[$DeviceName][c_Property_TimePause],    'Abdunkelung (Pause)', null, null);
					$this->AddNextStep($StepsToDo, c_MovementId_Up,     $DeviceConfig[$DeviceName][c_Property_TimeDimoutUp], 'Abdunkelung (Hoch)', null, null);
					$this->AddNextStep($StepsToDo, c_MovementId_Stop,   $DeviceConfig[$DeviceName][c_Property_TimePause],    'Abdunkelung (Pause)', null, null);
					$this->AddNextStep($StepsToDo, c_MovementId_Down,   $DeviceConfig[$DeviceName][c_Property_TimeDimoutDown], 'Abdunkelung (Runter)', null, null);
					$this->AddNextStep($StepsToDo, c_MovementId_Stop,   $DeviceConfig[$DeviceName][c_Property_TimePause],    'Abdunkelung (Stop)', null, null);
					$this->AddNextStep($StepsToDo, c_MovementId_Dimout, 1,  null, null, null);
				} elseif ($ToBeMoved==c_MovementId_Down) {
					$this->AddNextStep($StepsToDo, c_MovementId_Down, $SecTotal, null, $SecTotal, 0); //BOMMH $this->AddNextStep($StepsToDo, c_MovementId_Down, $SecTotal-$SecNullToPos, null, $SecTotal, $SecNullToPos);
					$this->AddNextStep($StepsToDo, c_MovementId_Stop, 1, null, null, null);
				} elseif ($ToBeMoved==c_MovementId_MovedOut or $ToBeMoved==c_MovementId_MovingOut) {
					$this->AddNextStep($StepsToDo, c_MovementId_MovingOut, $SecTotal-$SecNullToPos, null, $SecTotal, $SecNullToPos);
					$this->AddNextStep($StepsToDo, c_MovementId_Stop, 1, null, null, null);
					$this->AddNextStep($StepsToDo, c_MovementId_MovedOut, 1, null, null, null);
				} elseif ($ToBeMoved==c_MovementId_Shadowing) {
					$this->AddNextStep($StepsToDo, c_MovementId_Down, $SecTotal-$SecNullToPos, null, $SecTotal, $SecNullToPos);
					$this->AddNextStep($StepsToDo, c_MovementId_Stop, 1, "$Position%", null, null);
					$this->AddNextStep($StepsToDo, c_MovementId_Up,    $DeviceConfig[$DeviceName][c_Property_TimeDimoutUp], 'Beschattung (Hoch)', null, null);
					$this->AddNextStep($StepsToDo, c_MovementId_Stop, $DeviceConfig[$DeviceName][c_Property_TimePause],  'Beschattung (Stop)', null, null);
					$this->AddNextStep($StepsToDo, c_MovementId_Shadowing, 1,  null, null, null);
				} else { // Beinhalted c_MovementId_Closed
					$SecNullToPos = $SecTotal*$Position/100 - 2; //BOMMH Somit wird immer die Gesamte Distanz zugefahren und es ist sicher gestellt, dass der Rollladen zu ist. Original: $SecNullToPos = $SecTotal*$Position/100;
					$this->AddNextStep($StepsToDo, c_MovementId_Down, $SecTotal-$SecNullToPos, null, $SecTotal, $SecNullToPos);
					$this->AddNextStep($StepsToDo, c_MovementId_Stop, 1, "$Position%", null, null);
					$this->AddNextStep($StepsToDo, c_MovementId_Closed, 1,  null, null, null);
				}

			} elseif ($ToBeMoved==c_MovementId_90 or $ToBeMoved==c_MovementId_75 or $ToBeMoved==c_MovementId_50 or $ToBeMoved==c_MovementId_25) { //Die Berechnung ist falsch, da sie nur Abwärtszeiten Berücksichtigt!
				// BOMMH Nimmt für Aufwärts und Abwärts unterschiedliche Zeiten für die Berechnung: Original:$SecTotal      = $DeviceConfig[$DeviceName][c_Property_TimeClosing];
				if ($ToBeMoved > $Position) $SecTotal      = $DeviceConfig[$DeviceName][c_Property_TimeClosing];
				if ($ToBeMoved < $Position) $SecTotal      = $DeviceConfig[$DeviceName][c_Property_TimeOpening];
				//EOMMH
				$ShadowingType = $DeviceConfig[$DeviceName][c_Property_ShadowingType];
				$SecNullToPos  = $SecTotal*$Position/100;
				$SecPosTo100   = $SecTotal-$SecNullToPos;
				if ($ToBeMoved==c_MovementId_90) {
					$SecNullToNew = $SecTotal*90/100;
					$Position     = 90;
				} elseif ($ToBeMoved==c_MovementId_75) {
					$SecNullToNew = $SecTotal*75/100;
					$Position     = 75;
				} elseif ($ToBeMoved==c_MovementId_50) {
					$SecNullToNew = $SecTotal*50/100;
					$Position     = 50;
				} else {
					$SecNullToNew = $SecTotal*25/100;
					$Position     = 25;
				}
				if ($SecNullToNew > $SecNullToPos) {
					if ($ShadowingType==c_ShadowingType_Marquees) {
						$this->AddNextStep($StepsToDo, c_MovementId_MovingOut, $SecNullToNew-$SecNullToPos, null, $SecTotal, $SecNullToPos);
					} else {
						$this->AddNextStep($StepsToDo, c_MovementId_Down, $SecNullToNew-$SecNullToPos, null, $SecTotal, $SecNullToPos);
					}
				} elseif ($SecNullToNew < $SecNullToPos) {
					if ($ShadowingType==c_ShadowingType_Marquees) {
						$this->AddNextStep($StepsToDo, c_MovementId_MovingIn, $SecNullToPos-$SecNullToNew, null, $SecTotal, $SecPosTo100);
					} else {
						$this->AddNextStep($StepsToDo, c_MovementId_Up, $SecNullToPos-$SecNullToNew, null, $SecTotal, $SecPosTo100);
					}
				} else {
				}
				$this->AddNextStep($StepsToDo, c_MovementId_Stop, 1, "$Position%", null, null);
				$this->AddNextStep($StepsToDo, $ToBeMoved,        1, null, null, null);

			} elseif ($ToBeMoved==c_MovementId_Stop) {
				$this->AddNextStep($StepsToDo, c_MovementId_Stop, 1, null, null, null);

			} else {
				throw new Exception ("Unknown MovementId $ToBeMoved, DeviceId=".$this->deviceId);
				exit;
			}

			$this->SetVariableValue(c_Control_StepsToDo, implode('|', $StepsToDo));
			$this->SetVariableValue(c_Control_Step, -5);
		}

		// ----------------------------------------------------------------------------------------------------------------------------
		private function ExecuteNextStep() {
			$DeviceName    = IPS_GetIdent($this->deviceId);
			$Step          = $this->GetVariableValue(c_Control_Step)+5;
			$NextStepsToDo = $this->GetVariableValue(c_Control_StepsToDo);
			$NextStepsToDo = Explode('|', $NextStepsToDo);

			if ($Step < count($NextStepsToDo)) {
				$Command = $NextStepsToDo[$Step];
				$Time    = $NextStepsToDo[$Step+1];
				IPSLogger_Trc(__file__, "Shadowing for Device '$DeviceName', Step $Step, Command=$Command, Time=$Time");
				$this->MoveByCommand($Command);

				$this->SetVariableValue(c_Control_Step,      $Step);
				$this->SetVariableValue(c_Control_StartTime, time());
			} else {
				IPSLogger_Dbg(__file__, "Finished all Steps for Device '$DeviceName'");
				$this->SetVariableValue(c_Control_Step,      -1);
				$this->SetVariableValue(c_Control_StepsToDo, "");
				$this->SetVariableValue(c_Control_StartTime, -1);
				$this->StartRefreshTimer(false);
				$this->SetStatus();
			}
		}

		// ----------------------------------------------------------------------------------------------------------------------------
		public function Refresh() {
			$NextStepsToDo = Explode('|', $this->GetVariableValue(c_Control_StepsToDo));
			$StepCount     = count($NextStepsToDo);
			$Step          = $this->GetVariableValue(c_Control_Step);
			if ($StepCount >= ($Step+4) and $Step>=0) {
				$StartTime     = $this->GetVariableValue(c_Control_StartTime);
				$SecsDone      = time()-$StartTime;
				$SecsToDo      = $NextStepsToDo[$Step+1];
				$Display       = $NextStepsToDo[$Step+2];
				$SecsTotal     = $NextStepsToDo[$Step+3];
				$SecStepBegin  = $NextStepsToDo[$Step+4];
				$Command       = $NextStepsToDo[$Step];

				if ($SecsTotal <> null) {
					//  SecTotal   ... 100%
					//  Begin+Done ...   x%
					$Position       = round(($SecStepBegin+$SecsDone)*100/$SecsTotal);
					if ($Command==c_MovementId_Up or $Command==c_MovementId_MovingIn) {
						$Position = 100-$Position;
					}
					if ($Position>100) {$Position=100;}
					if ($Position<0)   {$Position=0;}
					$this->SetVariableValue(c_Control_Position, $Position);
					$SecsOpen      = $SecsToDo-$SecsDone;
					if ($SecsOpen < 0) {$SecsOpen=0;}
					$Display = "$Position% ($SecsOpen Sek)";
				}

				if ($Display!=null) {
					$this->SetVariableValue(c_Control_Display, $Display);
				}

				if ($SecsDone >= $SecsToDo) {
					$this->ExecuteNextStep();
				}
				return true;
			} else {
				return false;
			}
		}

		// ----------------------------------------------------------------------------------------------------------------------------
		private function StartRefreshTimer($Value) {
			if ($Value) {
				$Name    = 'Refresh';
				$refreshTimerScriptId = IPSUtil_ObjectIDByPath('Program.IPSLibrary.app.modules.IPSShadowing.IPSShadowing_RefreshTimer');

				$TimerId = @IPS_GetEventIDByName($Name, $refreshTimerScriptId);
				if ($TimerId === false) {
					$TimerId = IPS_CreateEvent(1 /*Cyclic Event*/);
					IPS_SetName($TimerId, $Name);
					IPS_SetParent($TimerId, $refreshTimerScriptId);
					if (!IPS_SetEventCyclic($TimerId, 2 /*Daily*/, 1 /*Int*/,0 /*Days*/,0 /*DayInt*/,1 /*TimeType Sec*/,1 /*Sec*/)) {
						throw new Exception ("IPS_SetEventCyclic failed for Refresh Timer!!!");
					}
				}
				IPS_SetEventActive($TimerId, true);
			}
		}

		// ----------------------------------------------------------------------------------------------------------------------------
		public function ChangeSetting($controlId, $value) {
			if (GetValue($controlId)<>$value) {
				if (IPS_GetIdent($controlId)==c_Control_Automatic) {
					if (GetValue(IPS_GetObjectIDByIdent(c_Control_TempChange, $this->deviceId))) {
						SetValue(IPS_GetObjectIDByIdent(c_Control_TempChange, $this->deviceId), false);
					}
				} else {
				}
				if (GetValue(IPS_GetObjectIDByIdent(c_Control_ManualChange, $this->deviceId))) {
					SetValue(IPS_GetObjectIDByIdent(c_Control_ManualChange, $this->deviceId), false);
				}
				SetValue($controlId, $value);
				IPSShadowing_LogChange($this->deviceId, $value, $controlId);
				$this->SetStatus();
			}
		}

		// ----------------------------------------------------------------------------------------------------------------------------
		public function CheckPrograms($profileManager) {
			$deviceName        = IPS_GetIdent($this->deviceId);
			$profileIdTemp     = GetValue(IPS_GetObjectIDByIdent(c_Control_ProfileTemp, $this->deviceId));
			$profileIdSun      = GetValue(IPS_GetObjectIDByIdent(c_Control_ProfileSun, $this->deviceId));
			$profileIdBgnOfDay = GetValue(IPS_GetObjectIDByIdent(c_Control_ProfileBgnOfDay, $this->deviceId));
			$profileIdEndOfDay = GetValue(IPS_GetObjectIDByIdent(c_Control_ProfileEndOfDay, $this->deviceId));
			$profileIdWeather  = null;
			$programPresent    = GetValue(IPS_GetObjectIDByIdent(c_Control_ProgramPresent, $this->deviceId));
			$programTemp       = GetValue(IPS_GetObjectIDByIdent(c_Control_ProgramTemp, $this->deviceId));
			$programDay        = GetValue(IPS_GetObjectIDByIdent(c_Control_ProgramDay, $this->deviceId));
			$programNight      = GetValue(IPS_GetObjectIDByIdent(c_Control_ProgramNight, $this->deviceId));
			$programWeather    = null;
			$automaticActive   = GetValue(IPS_GetObjectIDByIdent(c_Control_Automatic, $this->deviceId));
			$tempIndoorPath    = $this->GetPropertyValue(c_Property_TempSensorIndoor);

			$controlId = @IPS_GetObjectIDByIdent(c_Control_ProfileWeather, $this->deviceId);
			if ($controlId!==false) {
				$profileIdWeather  = GetValue($controlId);
				$programWeather    = GetValue(IPS_GetObjectIDByIdent(c_Control_ProgramWeather, $this->deviceId));
			}

			$isDay               = $profileManager->IsDay($profileIdBgnOfDay, $profileIdEndOfDay);
			$isDayNightChange    = $profileManager->IsDayNightChange($profileIdBgnOfDay, $profileIdEndOfDay);
			$closeByTemp         = $profileManager->CloseByTemp($profileIdSun, $profileIdTemp, $tempIndoorPath);
			$shadowingByTemp     = $profileManager->ShadowingByTemp($profileIdSun, $profileIdTemp, $tempIndoorPath);
			$openByTemp          = $profileManager->OpenByTemp($profileIdSun, $profileIdTemp, $tempIndoorPath);
			$activationByWeather = $profileManager->ActivationByWeather($profileIdWeather);


			// Reset Manual Change Flag
			if ($isDayNightChange) {
				if (GetValue(IPS_GetObjectIDByIdent(c_Control_ManualChange, $this->deviceId))) {
					IPSLogger_Dbg(__file__, "Reset ManualChange Flag for Device '$deviceName'");
					SetValue(IPS_GetObjectIDByIdent(c_Control_ManualChange, $this->deviceId), false);
				}
				if (GetValue(IPS_GetObjectIDByIdent(c_Control_TempChange, $this->deviceId))) {
					IPSLogger_Dbg(__file__, "Reset TempChange Flag for Device '$deviceName'");
					SetValue(IPS_GetObjectIDByIdent(c_Control_TempChange, $this->deviceId), false);
				}
			}

			$changeByTemp      = GetValue(IPS_GetObjectIDByIdent(c_Control_TempChange, $this->deviceId));
			$changeByUser      = GetValue(IPS_GetObjectIDByIdent(c_Control_ManualChange, $this->deviceId));

			// Check all Programs
			// --------------------------------------------------------------------------------
			// Automatic Off ...
			if (!$automaticActive) {
				$programInfo = 'Automatic Off';

			// Activation by Wind/Rain
			} elseif ($activationByWeather and $programWeather<>c_ProgramId_Manual) {
				$programInfo = 'Wetterprogramm';
				$this->MoveByProgram($programWeather, 'Wetterprogramm');

			// Manual Change ...
			} elseif ($changeByUser) {
				$programInfo = 'Manuelle Änderung';

			// Custom
			} elseif (IPSShadowing_ProgramCustom($this->deviceId, $isDay)) {
				$programInfo = 'CustomProgram';
				// Action done in Custom Procedure

			// Present ...
			} elseif ($profileManager->GetPresent() and $programPresent==c_ProgramId_OpenedDay and $isDay) {
				$programInfo = 'Anwesenheit (Tag)';
				$this->MoveByProgram($programPresent, 'Anwesenheitsprogramm');
			} elseif ($profileManager->GetPresent() and $programPresent==c_ProgramId_OpenedNight and !$isDay) {
				$programInfo = 'Anwesenheit (Nacht)';
				$this->MoveByProgram($programPresent, 'Anwesenheitsprogramm');
			} elseif ($profileManager->GetPresent() and $programPresent==c_ProgramId_Opened) {
				$programInfo = 'Anwesenheit';
				$this->MoveByProgram($programPresent, 'Anwesenheitsprogramm');
			} elseif ($profileManager->GetPresent() and $programPresent==c_ProgramId_MovedOutTemp and $isDay and $closeByTemp) {
				$programInfo = 'Anwesenheit (Temperatur)';
				$this->MoveByProgram($programPresent, 'Anwesenheitsprogramm (Beschattung bei Temp und Anwesenheit)');

			// Temperature/Sun
			} elseif ($isDay and ($closeByTemp or $shadowingByTemp) and $programTemp<>c_ProgramId_Manual) {
				if ($closeByTemp) {
					$programInfo = 'Temperatur';
					$this->MoveByProgram($programTemp, 'Temperaturprogramm', true/*DimoutOption*/, true/*TriggeredByTemp*/);
				} elseif ($changeByTemp) {
					$programInfo = 'Temperatur (Warte Öffnen)';
				} elseif ($shadowingByTemp) {
					$programInfo = 'Temperatur (Beschattung)';
					$this->MoveByProgram($programTemp, 'Temperaturprogramm (Beschattung)', false/*DimoutOption*/, true/*TriggeredByTemp*/);
				} else {
					$programInfo = 'Temperatur (Error)';
				}

			// Day
			} elseif ($isDay) {
				if (!$openByTemp and $changeByTemp) {
					$programInfo = 'Tag (Warte Öffnen)';
				} elseif ($openByTemp and $changeByTemp) {
					SetValue(IPS_GetObjectIDByIdent(c_Control_TempChange, $this->deviceId), false);
					if ($programDay<>c_ProgramId_Manual) {
						$programInfo = 'Temperatur Reset (Tag)';
						$this->MoveByProgram($programDay, 'Temperatur Reset (Tag)');
					} else {
						$programInfo = 'Temperatur Reset (LastPosition)';
						$this->MoveByProgram(c_ProgramId_LastPosition, 'Temperatur Reset (LastPosition)');
					}
				} else {
					$programInfo = 'Tagesprogramm';
					$this->MoveByProgram($programDay, 'Tagesprogramm');
				}

			// Night
			} else {
				$programInfo = 'Nachtprogramm';
				$this->MoveByProgram($programNight, '"Nachtprogramm"');
			}
			$profileInfo = $profileManager->GetProfileInfo($profileIdBgnOfDay, $profileIdEndOfDay, $profileIdTemp, $tempIndoorPath);
			$deviceName = IPSShadowing_GetDeviceName($this->deviceId);
			echo "$deviceName -> $programInfo, $profileInfo 
";
			SetValue(IPS_GetObjectIDByIdent(c_Control_ProfileInfo, $this->deviceId), $programInfo.', '.$profileInfo);
		}
	}


	/** @}*/
?>

Soweit erstmal von mir.

Für die Enocean und speziell Eltako FSB14 Fraktion: Da werde ich wohl mal noch nen ausführlicheren Post schreiben müssen und nen paar Skripte mehr für die Rückkopplung zur Verfügung stellen.

Dafür werde ich bei zeiten einen extra Thread im Enocean Forum aufmachen.

Gruß
Maze

Edit: Versionierung des Files geändert
Edit2: Hab den Code noch etwas überarbeitet. Auf Closed / Opened werden jetzt 2 Sekunden Fahrzeit dazu gegeben. Runter und Hoch fahren aber IMMER die komplette Zeit.

@Maze

das hat mich auch schon öfters gestört, bin bis jetzt aber noch nicht dazu gekommen das zu ändern.

Deine Implementierung funktioniert aber nur für Devices vom Type Shutter, für Jalousien und Markisen ist eine analoge Implementierung erforderlich.

Ursprünglicher Grund für Stop war, dass man bei Jalousien in der Endposition nicht weiß ob man Beschattung oder Abdunkelung zu verwenden ist…

Grund für das Fehlen des 25% Button ist, dass sich das auf einem 10" Schirm ohne Zeilenumbruch nicht mehr ausgegangen ist.

Hallo,

hab oben im Code kleinere Verbesserungen eingebracht.

Ich hab das bisher auch nur für Shutter umgesetzt, da ich keine anderen Verschattungen habe. Vielleicht kannst du da einen Blick drauf werfen, ob die noch funktionieren oder damit „verhunzt“ wurden.

Aber nochmal ein Dickes Lob für die ganze Library! Macht echt Spaß darauf aufzubauen.

Als nächstes muss ich mich mal mit IPSLight auseinander setzen.

Gruß
Maze

Könntet ihr das nicht in die Library integrieren, dass nicht jeder selbst rumbasteln muss und beim nächsten „normalen“ Update wieder? Ist das großer Aufwand? Es gibt doch eine Möglichkeit für „Fremdschreiber“. :wink:

Danke im Voraus

Gruß
Bruno

@Bruno

na klar, werd ich integrieren

@Maze

Kann Dir an dieser Stelle nur empfehlen einen GIT Account anzulegen und die Library zu forken
folgende Vorteile ergeben sich dardurch für Dich:

[ol]
[li]Du kannst mir Änderungen dann in Zukunft per Knopfdruck senden
[/li][li]Du kannst Änderungen von mir auch per Knopfdruck übernehmen und das ohne das Deine Änderungen dabei überschrieben werden
[/li][li]Versionierung der Änderungen
[/li][/ol]

Hallo Andreas,

werd ich mir mal ansehen :slight_smile:

Wie gesagt, meine PHP Erfahrungen stecken noch in den Kinderschuhen.

Werd mich mal mit GIT auseinandersetzen.

Schönen Abend,
Maze