From 716620cf09f4d6a525f517034cb95b297e271daf Mon Sep 17 00:00:00 2001 From: "belevo\\mh" Date: Tue, 26 May 2026 13:05:51 +0200 Subject: [PATCH] no message --- MQTTBatterySDL/form.json | 5 - MQTTBatterySDL/module.json | 1 - MQTTBatterySDL/module.php | 418 ++++++++++++++----------------------- 3 files changed, 155 insertions(+), 269 deletions(-) diff --git a/MQTTBatterySDL/form.json b/MQTTBatterySDL/form.json index fb37bc6..e7d7bcf 100644 --- a/MQTTBatterySDL/form.json +++ b/MQTTBatterySDL/form.json @@ -5,11 +5,6 @@ "name": "TopicSuffix", "caption": "Topic Suffix / x" }, - { - "type": "SelectVariable", - "name": "FeedbackResponseID", - "caption": "Feedback Response Variable" - }, { "type": "SelectVariable", "name": "ReqActionID", diff --git a/MQTTBatterySDL/module.json b/MQTTBatterySDL/module.json index 25eeb4a..eca32f0 100644 --- a/MQTTBatterySDL/module.json +++ b/MQTTBatterySDL/module.json @@ -7,7 +7,6 @@ "MQTT Battery SDL" ], "parentRequirements": [ - "{018EF6B5-AB94-40C6-AA53-46943E824ACF}", "{043EA491-0325-4ADD-8FC2-A30C8EEB4D3F}" ], "childRequirements": [], diff --git a/MQTTBatterySDL/module.php b/MQTTBatterySDL/module.php index 9fea76d..465ec57 100644 --- a/MQTTBatterySDL/module.php +++ b/MQTTBatterySDL/module.php @@ -2,11 +2,12 @@ class MQTTBatterySDL extends IPSModule { + private bool $Subscribed = false; + public function Create() { parent::Create(); - // Eigenschaften $this->RegisterPropertyString('TopicSuffix', ''); $this->RegisterPropertyInteger('ReqActionID', 0); @@ -18,9 +19,6 @@ class MQTTBatterySDL extends IPSModule $this->RegisterPropertyInteger('DischargePower', 2500); $this->RegisterPropertyInteger('MaxPowerSetpoint', 10000); - $this->RegisterPropertyInteger('FeedbackResponseID', 0); - - // Variablen $this->RegisterVariableBoolean('IsReady', 'Is Ready', '', 10); $this->RegisterVariableBoolean('IsRunning', 'Is Running', '', 20); @@ -36,37 +34,37 @@ class MQTTBatterySDL extends IPSModule $this->RegisterVariableString('LastReadResponse', 'Letzte Lese-Antwort', '', 70); $this->RegisterVariableString('LastWriteResponse', 'Letzte Steuer-Antwort', '', 80); - $this->ConnectParent('{F7A0DD2E-7684-95C0-64C2-D2A9DC47577B}'); - + $this->ConnectParent('{C6D2AEB3-6E1F-4B2E-8E69-3A1A00246850}'); } -public function ApplyChanges() -{ - parent::ApplyChanges(); + public function ApplyChanges() + { + parent::ApplyChanges(); - $suffix = $this->ReadPropertyString('TopicSuffix'); + $suffix = $this->ReadPropertyString('TopicSuffix'); - if ($suffix == '') { - $this->SetStatus(IS_INACTIVE); - return; + if ($suffix == '') { + $this->SetStatus(IS_INACTIVE); + return; + } + + $filter = + '.*"Topic":"(feedback-request|remote-control-request)\/' + . preg_quote($suffix, '/') + . '".*'; + + $this->SetReceiveDataFilter($filter); + + $this->Subscribed = false; + $this->EnsureSubscribe(); + + $this->SetStatus(IS_ACTIVE); } - $filter = - '.*"Topic":"(feedback-request|remote-control-request)\/' - . preg_quote($suffix, '/') - . '".*'; - - $this->SetReceiveDataFilter($filter); - - $this->SetStatus(IS_ACTIVE); -} - public function RequestAction($Ident, $Value) { switch ($Ident) { - case 'PowerSetpoint': - $max = $this->ReadPropertyInteger('MaxPowerSetpoint'); if ($Value > $max) { @@ -78,24 +76,64 @@ public function ApplyChanges() } SetValue($this->GetIDForIdent('PowerSetpoint'), $Value); - $this->RunBatteryControl(); - break; case 'Strategy': - - SetValueString( - $this->GetIDForIdent('Strategy'), - (string)$Value - ); - + SetValueString($this->GetIDForIdent('Strategy'), (string)$Value); $this->RunBatteryControl(); - break; } } + public function ReceiveData($JSONString) + { + $this->EnsureSubscribe(); + + $data = json_decode($JSONString, true); + + if (!is_array($data)) { + return; + } + + $topic = $data['Topic'] ?? ''; + $payload = $data['Payload'] ?? ''; + + if ($topic == '') { + return; + } + + $suffix = $this->ReadPropertyString('TopicSuffix'); + + if ($suffix == '') { + return; + } + + if ($topic === 'feedback-request/' . $suffix) { + $json = $this->BuildReadResponse(); + + $this->PublishMQTT( + 'feedback-response/' . $suffix, + $json + ); + + return; + } + + if ($topic === 'remote-control-request/' . $suffix) { + $json = $this->HandleRemoteControlJSON($payload); + + if ($json !== null) { + $this->PublishMQTT( + 'remote-control-response/' . $suffix, + $json + ); + } + + return; + } + } + public function RunBatteryControl() { $reqActionID = $this->ReadPropertyInteger('ReqActionID'); @@ -103,59 +141,29 @@ public function ApplyChanges() $powerProductionID = $this->ReadPropertyInteger('PowerProductionID'); if (!$this->IsValidVariable($reqActionID)) { - $this->SendDebug( - 'RunBatteryControl', - 'Keine gültige Ausgabe-Variable gewählt', - 0 - ); + $this->SendDebug('RunBatteryControl', 'Keine gültige Ausgabe-Variable gewählt', 0); return; } if (!$this->IsValidVariable($socID)) { - $this->SendDebug( - 'RunBatteryControl', - 'Keine gültige SoC Variable gewählt', - 0 - ); + $this->SendDebug('RunBatteryControl', 'Keine gültige SoC Variable gewählt', 0); return; } - $strategy = GetValueString( - $this->GetIDForIdent('Strategy') - ); - - $setpoint = GetValue( - $this->GetIDForIdent('PowerSetpoint') - ); - - $soc = GetValue($socID); - - $targetSoC = $this->ReadPropertyInteger('TargetSoC'); - - $chargePower = $this->ReadPropertyInteger('ChargePower'); + $strategy = GetValueString($this->GetIDForIdent('Strategy')); + $setpoint = GetValue($this->GetIDForIdent('PowerSetpoint')); + $soc = GetValue($socID); + $targetSoC = $this->ReadPropertyInteger('TargetSoC'); + $chargePower = $this->ReadPropertyInteger('ChargePower'); $dischargePower = $this->ReadPropertyInteger('DischargePower'); - // ------------------------------------------------- - // Strategy activate - // ------------------------------------------------- - if ($strategy == 'activate') { - - RequestAction( - $reqActionID, - $setpoint * -1 - ); - + RequestAction($reqActionID, $setpoint * -1); return; } - // ------------------------------------------------- - // Strategy stop - // ------------------------------------------------- - if ($strategy == 'stop') { - RequestAction($reqActionID, 0); if ($this->IsValidVariable($powerProductionID)) { @@ -165,42 +173,18 @@ public function ApplyChanges() return; } - // ------------------------------------------------- - // Ziel erreicht - // ------------------------------------------------- - if ((int)$soc == $targetSoC) { - RequestAction($reqActionID, 0); - return; } - // ------------------------------------------------- - // Laden - // ------------------------------------------------- - if ($soc < $targetSoC) { - - RequestAction( - $reqActionID, - abs($chargePower) - ); - + RequestAction($reqActionID, abs($chargePower)); return; } - // ------------------------------------------------- - // Entladen - // ------------------------------------------------- - if ($soc > $targetSoC) { - - RequestAction( - $reqActionID, - abs($dischargePower) * -1 - ); - + RequestAction($reqActionID, abs($dischargePower) * -1); return; } } @@ -208,51 +192,20 @@ public function ApplyChanges() public function BuildReadResponse() { $socID = $this->ReadPropertyInteger('SoCID'); - - $powerProductionID = $this->ReadPropertyInteger( - 'PowerProductionID' - ); + $powerProductionID = $this->ReadPropertyInteger('PowerProductionID'); $data = [ - - 'power_production' => $this->IsValidVariable( - $powerProductionID - ) - ? GetValue($powerProductionID) - : 0, - - 'is_ready' => GetValue( - $this->GetIDForIdent('IsReady') - ), - - 'is_running' => GetValue( - $this->GetIDForIdent('IsRunning') - ), - - 'state_of_charge' => $this->IsValidVariable( - $socID - ) - ? GetValue($socID) - : 0, - - 'min_soc' => GetValue( - $this->GetIDForIdent('MinSoC') - ), - - 'max_soc' => GetValue( - $this->GetIDForIdent('MaxSoC') - ) + 'power_production' => $this->IsValidVariable($powerProductionID) ? GetValue($powerProductionID) : 0, + 'is_ready' => GetValue($this->GetIDForIdent('IsReady')), + 'is_running' => GetValue($this->GetIDForIdent('IsRunning')), + 'state_of_charge' => $this->IsValidVariable($socID) ? GetValue($socID) : 0, + 'min_soc' => GetValue($this->GetIDForIdent('MinSoC')), + 'max_soc' => GetValue($this->GetIDForIdent('MaxSoC')) ]; - $json = json_encode( - $data, - JSON_PRETTY_PRINT - ); + $json = json_encode($data, JSON_PRETTY_PRINT); - SetValueString( - $this->GetIDForIdent('LastReadResponse'), - $json - ); + SetValueString($this->GetIDForIdent('LastReadResponse'), $json); return $json; } @@ -260,25 +213,17 @@ public function ApplyChanges() public function HandleRemoteControlJSON(string $payload) { if ($payload == '') { - return; + return null; } $data = json_decode($payload, true); if (!is_array($data)) { - return; + return null; } - // ------------------------------------------------- - // Power Setpoint - // ------------------------------------------------- - if (isset($data['power_setpoint'])) { - - $max = $this->ReadPropertyInteger( - 'MaxPowerSetpoint' - ); - + $max = $this->ReadPropertyInteger('MaxPowerSetpoint'); $val = (int)$data['power_setpoint']; if ($val > $max) { @@ -289,142 +234,88 @@ public function ApplyChanges() $val = $max * -1; } - SetValue( - $this->GetIDForIdent('PowerSetpoint'), - $val - ); + SetValue($this->GetIDForIdent('PowerSetpoint'), $val); } - // ------------------------------------------------- - // Strategy - // ------------------------------------------------- - if (isset($data['strategy'])) { - - SetValueString( - $this->GetIDForIdent('Strategy'), - (string)$data['strategy'] - ); + SetValueString($this->GetIDForIdent('Strategy'), (string)$data['strategy']); } - // ------------------------------------------------- - // Batterie-Regelung ausführen - // ------------------------------------------------- - $this->RunBatteryControl(); - // ------------------------------------------------- - // Antwort bauen - // ------------------------------------------------- - $output = [ - - 'power_setpoint' => GetValue( - $this->GetIDForIdent('PowerSetpoint') - ), - - 'strategy' => GetValueString( - $this->GetIDForIdent('Strategy') - ) + 'power_setpoint' => GetValue($this->GetIDForIdent('PowerSetpoint')), + 'strategy' => GetValueString($this->GetIDForIdent('Strategy')) ]; - $json = json_encode( - $output, - JSON_PRETTY_PRINT - ); + $json = json_encode($output, JSON_PRETTY_PRINT); - SetValueString( - $this->GetIDForIdent('LastWriteResponse'), - $json - ); + SetValueString($this->GetIDForIdent('LastWriteResponse'), $json); return $json; } -public function ReceiveData($JSONString) -{ - $data = json_decode($JSONString, true); - - if (!is_array($data)) { - return; - } - - if (($data['PacketType'] ?? 0) != 3) { - return; - } - - if (!isset($data['Topic'])) { - return; - } - - $topic = $data['Topic']; - - if (strpos($topic, 'feedback-response/') === 0) { - return; - } - - if (strpos($topic, 'remote-control-response/') === 0) { - return; - } - - $this->SendDebug('ReceiveData', $JSONString, 0); - - $payload = $data['Payload'] ?? ''; - $suffix = $this->ReadPropertyString('TopicSuffix'); - - if ($topic === 'feedback-request/' . $suffix) { - $json = $this->BuildReadResponse(); - - $this->SendFeedbackResponse($json); - - return; - } - - if ($topic === 'remote-control-request/' . $suffix) { - $json = $this->HandleRemoteControlJSON($payload); - - if ($json !== null) { - $this->QueuePublish( - 'remote-control-response/' . $suffix, - $json - ); + private function EnsureSubscribe() + { + if ($this->Subscribed) { + return; } - return; - } -} + $suffix = $this->ReadPropertyString('TopicSuffix'); + if ($suffix == '') { + return; + } -private function PublishMQTT(string $topic, string $payload) -{ - $this->SendDebug( - 'PublishMQTT', - $topic . ' => ' . $payload, - 0 - ); + $this->Subscribed = true; - $this->SendDataToParent(json_encode([ - 'DataID' => '{043EA491-0325-4ADD-8FC2-A30C8EEB4D3F}', - 'PacketType' => 3, - 'Payload' => $payload, - 'QualityOfService' => 0, - 'Retain' => false, - 'Topic' => $topic - ])); -} + foreach ([ + 'feedback-request/' . $suffix, + 'remote-control-request/' . $suffix + ] as $topic) { + $this->SafeSend([ + 'DataID' => '{043EA491-0325-4ADD-8FC2-A30C8EEB4D3F}', + 'PacketType' => 8, + 'QualityOfService' => 0, + 'Retain' => false, + 'Topic' => $topic, + 'Payload' => '' + ]); - -private function SendFeedbackResponse(string $payload) -{ - $id = $this->ReadPropertyInteger('FeedbackResponseID'); - - if (!$this->IsValidVariable($id)) { - $this->SendDebug('SendFeedbackResponse', 'Keine gültige FeedbackResponseID gewählt', 0); - return; + $this->SendDebug('Subscribe', $topic, 0); + } } - RequestAction($id, $payload); -} + private function PublishMQTT(string $topic, string $payload) + { + $this->SafeSend([ + 'DataID' => '{043EA491-0325-4ADD-8FC2-A30C8EEB4D3F}', + 'PacketType' => 3, + 'QualityOfService' => 0, + 'Retain' => false, + 'Topic' => $topic, + 'Payload' => $payload + ]); + + $this->SendDebug('PublishMQTT', $topic . ' → ' . $payload, 0); + } + + private function SafeSend(array $packet) + { + $parent = @IPS_GetInstance($this->InstanceID)['ConnectionID'] ?? 0; + + if ($parent === 0 || !IPS_InstanceExists($parent)) { + $this->SendDebug('SafeSend', 'Kein gültiger Parent vorhanden', 0); + return; + } + + if (IPS_GetInstance($parent)['InstanceStatus'] !== 102) { + $this->SendDebug('SafeSend', 'Parent ist nicht aktiv', 0); + return; + } + + @$this->SendDataToParent(json_encode($packet)); + } private function IsValidVariable(int $id) { @@ -435,4 +326,5 @@ private function SendFeedbackResponse(string $payload) ); } } -?> + +?> \ No newline at end of file