diff --git a/VGT_Sub/module.php b/VGT_Sub/module.php index fa39dcd..8556164 100644 --- a/VGT_Sub/module.php +++ b/VGT_Sub/module.php @@ -2,143 +2,158 @@ declare(strict_types=1); -class VGT_Sub extends IPSModule +class EMS_MQTT_Device extends IPSModule { - private bool $Subscribed = false; - public function Create() { parent::Create(); - // MQTT CLIENT – NICHT Splitter! - $this->ConnectParent('{C6D2AEB3-6E1F-4B2E-8E69-3A1A00246850}'); + // Device-ID + $this->RegisterPropertyString("DeviceID", ""); - $this->RegisterPropertyString('DeviceID', ''); + // 6 editable values (response payload) + $this->RegisterVariableFloat("PowerProduction", "Power Production", "", 10); + $this->EnableAction("PowerProduction"); - // Feedback Variablen - $this->RegisterVariableFloat('PowerProduction', 'Power Production', '', 10); - $this->RegisterVariableFloat('StateOfCharge', 'State of Charge', '', 11); - $this->RegisterVariableBoolean('IsRunning', 'Is Running', '', 12); - $this->RegisterVariableBoolean('IsReady', 'Is Ready', '', 13); - $this->RegisterVariableFloat('MinSOC', 'Min SOC', '', 14); - $this->RegisterVariableFloat('MaxSOC', 'Max SOC', '', 15); + $this->RegisterVariableFloat("StateOfCharge", "State of Charge", "", 20); + $this->EnableAction("StateOfCharge"); - // Remote Control - $this->RegisterVariableFloat('PowerSetpoint', 'Power Setpoint', '', 20); - $this->RegisterVariableString('Strategy', 'Strategy', '', 21); + $this->RegisterVariableBoolean("IsRunning", "Is Running", "", 30); + $this->EnableAction("IsRunning"); - // Debug - $this->RegisterVariableString('FeedbackRequestPayload', 'Feedback Request', '', 90); - $this->RegisterVariableString('RemoteControlPayload', 'Remote Control', '', 91); + $this->RegisterVariableBoolean("IsReady", "Is Ready", "", 40); + $this->EnableAction("IsReady"); + + $this->RegisterVariableInteger("MinSOC", "Min SOC", "", 50); + $this->EnableAction("MinSOC"); + + $this->RegisterVariableInteger("MaxSOC", "Max SOC", "", 60); + $this->EnableAction("MaxSOC"); + + // Remote-Control incoming (read-only) + $this->RegisterVariableFloat("RC_PowerSetpoint", "RC Power Setpoint", "", 70); + $this->RegisterVariableString("RC_Strategy", "RC Strategy", "", 80); + + // Parent MQTT Splitter + $this->ConnectParent('{F7A0DD2E-7684-95C0-64C2-D2A9DC47577B}'); } public function ApplyChanges() { parent::ApplyChanges(); - $this->ConnectParent('{C6D2AEB3-6E1F-4B2E-8E69-3A1A00246850}'); - $this->Subscribed = false; + + $this->ConnectParent('{F7A0DD2E-7684-95C0-64C2-D2A9DC47577B}'); } - private function Log($t, $m) + // --------------------------------------------------------------------- + // ACTION HANDLER + // --------------------------------------------------------------------- + public function RequestAction($Ident, $Value) { - IPS_LogMessage("VGT_Sub/$t", $m); - $this->SendDebug($t, $m, 0); + SetValue($this->GetIDForIdent($Ident), $Value); } - private function SafeSend(array $p) - { - $parent = @IPS_GetInstance($this->InstanceID)['ConnectionID'] ?? 0; - if ($parent === 0) return; - if (IPS_GetInstance($parent)['InstanceStatus'] !== 102) return; - @$this->SendDataToParent(json_encode($p)); - } - - private function EnsureSubscribe() - { - if ($this->Subscribed) return; - $this->Subscribed = true; - - $this->SafeSend([ - 'DataID' => '{043EA491-0325-4ADD-8FC2-A30C8EEB4D3F}', - 'PacketType' => 8, - 'QualityOfService' => 0, - 'Retain' => false, - 'Topic' => '#', - 'Payload' => '' - ]); - - $this->Log("Subscribe", "#"); - } - - private function Publish(string $topic, string $payload) - { - $this->SafeSend([ - 'DataID' => '{043EA491-0325-4ADD-8FC2-A30C8EEB4D3F}', - 'PacketType' => 3, - 'QualityOfService' => 0, - 'Retain' => false, - 'Topic' => $topic, - 'Payload' => $payload - ]); - - $this->Log("Publish", "$topic → $payload"); - } - - + // --------------------------------------------------------------------- + // RECEIVE FROM MQTT + // --------------------------------------------------------------------- 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; - - $this->Log("RX", "$topic → $payload"); - - $device = $this->ReadPropertyString('DeviceID'); - - /* ================== FEEDBACK ================== */ - - if ($topic === "feedback-request/$device") { - - $this->SetValue('FeedbackRequestPayload', $payload); - - $resp = [ - "power_production" => GetValueFloat($this->GetIDForIdent("PowerProduction")), - "is_ready" => GetValueBoolean($this->GetIDForIdent("IsReady")), - "is_running" => GetValueBoolean($this->GetIDForIdent("IsRunning")), - "state_of_charge" => GetValueFloat($this->GetIDForIdent("StateOfCharge")), - "min_soc" => GetValueFloat($this->GetIDForIdent("MinSOC")), - "max_soc" => GetValueFloat($this->GetIDForIdent("MaxSOC")) - ]; - - $this->Publish("feedback-response/$device", json_encode($resp)); + $data = json_decode($JSONString); + if (!isset($data->Topic) || !isset($data->Payload)) { return; } - /* ================== REMOTE CONTROL ================== */ + $topic = $data->Topic; + $payload = $data->Payload; - if ($topic === "remote-control-request/$device") { + $deviceID = $this->ReadPropertyString("DeviceID"); - $this->SetValue("RemoteControlPayload", $payload); + // Topics + $feedbackReq = "feedback-request/" . $deviceID; + $remoteReq = "remote-control-request/" . $deviceID; - $json = json_decode($payload, true); - if (!is_array($json)) return; + if ($topic === $feedbackReq) { + $this->HandleFeedbackRequest(); + } - if (isset($json["power_setpoint"])) - SetValueFloat($this->GetIDForIdent("PowerSetpoint"), floatval($json["power_setpoint"])); - - if (isset($json["strategy"])) - SetValueString($this->GetIDForIdent("Strategy"), $json["strategy"]); - - $this->Publish("remote-control-response/$device", json_encode($json)); - return; + if ($topic === $remoteReq) { + $this->HandleRemoteControlRequest($payload); } } -} -?> + // --------------------------------------------------------------------- + // HANDLE FEEDBACK REQUEST -> SEND STATE JSON + // --------------------------------------------------------------------- + private function HandleFeedbackRequest() + { + $response = [ + "power_production" => GetValue($this->GetIDForIdent("PowerProduction")), + "state_of_charge" => GetValue($this->GetIDForIdent("StateOfCharge")), + "is_running" => GetValue($this->GetIDForIdent("IsRunning")), + "is_ready" => GetValue($this->GetIDForIdent("IsReady")), + "min_soc" => GetValue($this->GetIDForIdent("MinSOC")), + "max_soc" => GetValue($this->GetIDForIdent("MaxSOC")) + ]; + + $topic = "feedback-response/" . $this->ReadPropertyString("DeviceID"); + + $this->SendToMQTT($topic, json_encode($response)); + } + + // --------------------------------------------------------------------- + // HANDLE REMOTE CONTROL REQUEST + // payload: + // { "power_setpoint": 150, "strategy": "activation" } + // --------------------------------------------------------------------- + private function HandleRemoteControlRequest(string $payload) + { + $data = json_decode($payload, true); + if (!is_array($data)) { + return; + } + + // Write values to variables + if (isset($data["power_setpoint"])) { + SetValue($this->GetIDForIdent("RC_PowerSetpoint"), $data["power_setpoint"]); + } + + if (isset($data["strategy"])) { + SetValue($this->GetIDForIdent("RC_Strategy"), $data["strategy"]); + } + + // Respond with same JSON + $topic = "remote-control-response/" . $this->ReadPropertyString("DeviceID"); + $this->SendToMQTT($topic, json_encode($data)); + } + + // --------------------------------------------------------------------- + // MQTT SEND HELPERS + // --------------------------------------------------------------------- + private function SendToMQTT(string $topic, string $payload) + { + $this->SendDataToParent(json_encode([ + "DataID" => "{043E0F88-B2B0-4DF4-B1A6-64FB1C385D3C}", + "PacketType" => 3, + "QualityOfService" => 0, + "Retain" => false, + "Topic" => $topic, + "Payload" => $payload + ])); + } + + // --------------------------------------------------------------------- + // CONFIG FORM + // --------------------------------------------------------------------- + public function GetConfigurationForm() + { + return json_encode([ + "elements" => [ + [ + "type" => "ValidationTextBox", + "name" => "DeviceID", + "caption" => "Device ID" + ] + ] + ]); + } +}