Files
Symcon_Belevo_Energiemanage…/VGT_Sub/module.php
2025-11-19 13:37:10 +01:00

270 lines
8.8 KiB
PHP
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
class VGT_Sub extends IPSModule
{
public function Create()
{
parent::Create();
// Konfiguration
$this->RegisterPropertyString('DeviceID', '');
// Auf Parent-Connect reagieren (für Re-Subscribe)
$this->RegisterMessage($this->InstanceID, FM_CONNECT);
/** -------------------------------------------
* STATUS Variablen (schreibbar)
* ------------------------------------------*/
$this->RegisterVariableInteger('PowerProduction', 'Power Production', '', 10);
$this->EnableAction('PowerProduction');
$this->RegisterVariableBoolean('IsReady', 'Is Ready', '', 11);
$this->EnableAction('IsReady');
$this->RegisterVariableBoolean('IsRunning', 'Is Running', '', 12);
$this->EnableAction('IsRunning');
$this->RegisterVariableInteger('StateOfCharge', 'State of Charge', '', 13);
$this->EnableAction('StateOfCharge');
$this->RegisterVariableInteger('MinSOC', 'Min SOC', '', 14);
$this->EnableAction('MinSOC');
$this->RegisterVariableInteger('MaxSOC', 'Max SOC', '', 15);
$this->EnableAction('MaxSOC');
/** -------------------------------------------
* REMOTE CONTROL Variablen (read-only)
* ------------------------------------------*/
$this->RegisterVariableInteger('PowerSetpoint', 'Power Setpoint', '', 20);
$this->RegisterVariableString('Strategy', 'Strategy', '', 21);
// Debug
$this->RegisterVariableString('RemoteControlPayload', 'Remote Control Payload', '', 30);
/** -------------------------------------------
* FEEDBACK REQUEST Variablen (read-only)
* ------------------------------------------*/
$this->RegisterVariableString('FeedbackRequestPayload', 'Feedback Request Payload', '', 40);
}
public function ApplyChanges()
{
parent::ApplyChanges();
// Nach Konfigänderung Topics abonnieren
if ($this->HasActiveParent()) {
$this->SubscribeAll();
}
}
/**
* Reaktion auf Systemnachrichten (z.B. Parent verbindet sich)
*/
public function MessageSink($TimeStamp, $SenderID, $Message, $Data)
{
parent::MessageSink($TimeStamp, $SenderID, $Message, $Data);
switch ($Message) {
case FM_CONNECT:
// Parent (MQTT-Client) hat Verbindung aufgebaut -> erneut subscriben
if ($this->HasActiveParent()) {
$this->SendDebug('MQTT', 'FM_CONNECT -> Re-Subscribe Topics', 0);
$this->SubscribeAll();
}
break;
}
}
/**
* Alle benötigten Topics abonnieren
*/
private function SubscribeAll(): void
{
$device = $this->ReadPropertyString('DeviceID');
if ($device === '') {
$this->SendDebug('MQTT', 'Kein DeviceID gesetzt, keine Subscribes', 0);
return;
}
$this->Subscribe("feedback-request/$device");
$this->Subscribe("remote-control-request/$device");
}
/** -------------------------------------------
* VARIABLE WRITE SUPPORT
* ------------------------------------------*/
public function RequestAction($Ident, $Value)
{
$this->SetValue($Ident, $Value);
$device = $this->ReadPropertyString('DeviceID');
if ($device !== '') {
switch ($Ident) {
case 'PowerProduction':
case 'IsReady':
case 'IsRunning':
case 'StateOfCharge':
case 'MinSOC':
case 'MaxSOC':
$payload = json_encode([
'power_production' => $this->GetValue('PowerProduction'),
'is_ready' => $this->GetValue('IsReady'),
'is_running' => $this->GetValue('IsRunning'),
'state_of_charge' => $this->GetValue('StateOfCharge'),
'min_soc' => $this->GetValue('MinSOC'),
'max_soc' => $this->GetValue('MaxSOC')
]);
$this->Publish("status/$device", $payload);
break;
}
}
}
/** -------------------------------------------
* MQTT SUBSCRIBE
* ------------------------------------------*/
private function Subscribe(string $topic): void
{
if (!$this->HasActiveParent()) {
$this->SendDebug('MQTT', 'Subscribe ohne aktiven Parent: ' . $topic, 0);
return;
}
$packet = [
'PacketType' => 8, // SUBSCRIBE
'QualityOfService' => 0,
'Retain' => false,
'Topic' => $topic,
'Payload' => ''
];
$this->SendDebug('MQTT', 'Subscribe Topic=' . $topic, 0);
$this->SendDataToParent(json_encode([
'DataID' => '{043EA491-0325-4ADD-8FC2-A30C8EEB4D3F}'
] + $packet));
}
/** -------------------------------------------
* MQTT PUBLISH
* ------------------------------------------*/
private function Publish(string $topic, string $payload): void
{
if (!$this->HasActiveParent()) {
$this->SendDebug('MQTT', 'Publish ohne aktiven Parent: ' . $topic, 0);
return;
}
$packet = [
'PacketType' => 3, // PUBLISH
'QualityOfService' => 0,
'Retain' => false,
'Topic' => $topic,
'Payload' => $payload
];
$this->SendDebug('MQTT', 'Publish Topic=' . $topic . ' Payload=' . $payload, 0);
$this->SendDataToParent(json_encode([
'DataID' => '{043EA491-0325-4ADD-8FC2-A30C8EEB4D3F}'
] + $packet));
}
/** -------------------------------------------
* RECEIVE DATA
* ------------------------------------------*/
public function ReceiveData($JSONString)
{
// Äußeres JSON vom MQTT-Client
$data = json_decode($JSONString);
if ($data === null) {
$this->SendDebug('MQTT', 'Ungültiges JSON: ' . $JSONString, 0);
return;
}
// Neuere MQTT-Client-Version: Topic/Payload stecken in Buffer als JSON-String
if (isset($data->Buffer)) {
$buffer = json_decode($data->Buffer, true);
} else {
// Fallback: evtl. altes Format
$buffer = json_decode($JSONString, true);
}
if (!is_array($buffer)) {
$this->SendDebug('MQTT', 'Buffer ist kein Array: ' . print_r($buffer, true), 0);
return;
}
$topic = $buffer['Topic'] ?? '';
$payload = $buffer['Payload'] ?? '';
$this->SendDebug('MQTT', 'Receive: Topic=' . $topic . ' Payload=' . $payload, 0);
$device = $this->ReadPropertyString('DeviceID');
if ($device === '') {
$this->SendDebug('MQTT', 'Keine DeviceID gesetzt, ignoriere Receive', 0);
return;
}
/** -------------------------------------------
* 1⃣ FEEDBACK REQUEST
* ------------------------------------------*/
if ($topic === "feedback-request/$device") {
$this->SetValue('FeedbackRequestPayload', $payload);
$json = json_decode($payload, true);
if (!is_array($json)) {
$json = [];
}
$response = array_merge($json, [
"power_production" => $this->GetValue('PowerProduction'),
"is_ready" => $this->GetValue('IsReady'),
"is_running" => $this->GetValue('IsRunning'),
"state_of_charge" => $this->GetValue('StateOfCharge'),
"min_soc" => $this->GetValue('MinSOC'),
"max_soc" => $this->GetValue('MaxSOC')
]);
$this->Publish("feedback-response/$device", json_encode($response));
return;
}
/** -------------------------------------------
* 2⃣ REMOTE CONTROL REQUEST
* ------------------------------------------*/
if ($topic === "remote-control-request/$device") {
$this->SetValue('RemoteControlPayload', $payload);
$json = json_decode($payload, true);
if (is_array($json)) {
if (array_key_exists('power_setpoint', $json)) {
$this->SetValue('PowerSetpoint', (int)$json['power_setpoint']);
}
if (array_key_exists('strategy', $json)) {
$this->SetValue('Strategy', (string)$json['strategy']);
}
}
$this->Publish("remote-control-response/$device", $payload);
return;
}
}
}