no message

This commit is contained in:
2026-02-10 14:57:13 +01:00
parent 57a4594e38
commit ccb068dd5d
2 changed files with 84 additions and 173 deletions

View File

@@ -6,9 +6,12 @@
"aliases": [ "aliases": [
"VGT MQTT Device" "VGT MQTT Device"
], ],
"parentRequirements": ["{F7A0DD2E-7684-95C0-64C2-D2A9DC47577B}"], "parentRequirements": [
"{F7A0DD2E-7684-95C0-64C2-D2A9DC47577B}",
"{F66ADE63-8834-4178-8CA5-AE4465D2E252}"
],
"childRequirements": [], "childRequirements": [],
"implemented": ["{018EF6B5-AB94-40C6-AA53-46943E824ACF}"], "implemented": ["{018EF6B5-AB94-40C6-AA53-46943E824ACF}"],
"prefix": "VGT", "prefix": "VGT",
"version": "1.6" "version": "2.1"
} }

View File

@@ -8,19 +8,15 @@ class VGT_Sub extends IPSModule
{ {
parent::Create(); parent::Create();
// --------------------------------------------------------------------- // --- Konfiguration ---
// 1. MQTT Verbindungsdaten (für den IO/Socket)
// ---------------------------------------------------------------------
$this->RegisterPropertyString('MQTTBaseTopic', 'Test VGT_Steuerung/Komm'); $this->RegisterPropertyString('MQTTBaseTopic', 'Test VGT_Steuerung/Komm');
$this->RegisterPropertyString('MQTTClientID', 'symcon_vgt_client');
// --- Optionale Gateway-Konfig (Nur für IO/Socket relevant) ---
$this->RegisterPropertyString('MQTTUser', ''); $this->RegisterPropertyString('MQTTUser', '');
$this->RegisterPropertyString('MQTTPassword', ''); $this->RegisterPropertyString('MQTTPassword', '');
// Checkbox: Sollen die IO-Daten überschrieben werden? $this->RegisterPropertyBoolean('UpdateGatewayConfig', false);
$this->RegisterPropertyBoolean('UpdateGatewayConfig', true);
// --------------------------------------------------------------------- // --- Hardware Quellen ---
// 2. Hardware Verknüpfungen
// ---------------------------------------------------------------------
$this->RegisterPropertyInteger('SourceSoC', 0); $this->RegisterPropertyInteger('SourceSoC', 0);
$this->RegisterPropertyInteger('SourcePowerProd', 0); $this->RegisterPropertyInteger('SourcePowerProd', 0);
$this->RegisterPropertyInteger('SourceIsReady', 0); $this->RegisterPropertyInteger('SourceIsReady', 0);
@@ -29,17 +25,10 @@ class VGT_Sub extends IPSModule
$this->RegisterPropertyInteger('SourceMaxSoC', 0); $this->RegisterPropertyInteger('SourceMaxSoC', 0);
$this->RegisterPropertyInteger('TargetControlVar', 0); $this->RegisterPropertyInteger('TargetControlVar', 0);
// --------------------------------------------------------------------- // --- Interne Variablen ---
// 3. Interne Variablen
// ---------------------------------------------------------------------
$this->RegisterVariableString('Strategy', 'Strategy', '', 10); $this->RegisterVariableString('Strategy', 'Strategy', '', 10);
$this->RegisterVariableInteger('PowerSetpoint', 'Power Setpoint', '', 20); $this->RegisterVariableInteger('PowerSetpoint', 'Power Setpoint', '', 20);
// Visu (Nur zur Anzeige)
$this->RegisterVariableFloat('Visu_SoC', 'State of Charge', '~Intensity.100', 30);
$this->RegisterVariableFloat('Visu_Production', 'Power Production', '~Watt', 40);
$this->RegisterVariableBoolean('Visu_IsReady', 'Is Ready', '~Switch', 50);
$this->EnableAction('Strategy'); $this->EnableAction('Strategy');
$this->EnableAction('PowerSetpoint'); $this->EnableAction('PowerSetpoint');
} }
@@ -48,105 +37,35 @@ class VGT_Sub extends IPSModule
{ {
parent::ApplyChanges(); parent::ApplyChanges();
// --------------------------------------------------------------------- // 1. Filter setzen (Abonnieren)
// A. Filter setzen (Subscribe)
// ---------------------------------------------------------------------
$topic = $this->ReadPropertyString('MQTTBaseTopic'); $topic = $this->ReadPropertyString('MQTTBaseTopic');
if($topic !== "") { if($topic !== "") {
$cleanTopic = preg_quote($topic, '/'); $cleanTopic = preg_quote($topic, '/');
// Filter für den Splitter: Alles empfangen, was mit BaseTopic beginnt // Dieser Filter funktioniert für beide Splitter-Varianten
$this->SetReceiveDataFilter(".*\"Topic\":\"" . $cleanTopic . "/.*\".*"); $this->SetReceiveDataFilter(".*\"Topic\":\"" . $cleanTopic . "/.*\".*");
} }
// --------------------------------------------------------------------- // 2. Gateway Config (Optional)
// B. Gateway (IO/Socket) Konfiguration aktualisieren
// ---------------------------------------------------------------------
if ($this->ReadPropertyBoolean('UpdateGatewayConfig')) { if ($this->ReadPropertyBoolean('UpdateGatewayConfig')) {
$this->ConfigureGateway(); $this->ConfigureGateway();
} }
// --------------------------------------------------------------------- // 3. Events registrieren
// C. Events registrieren
// ---------------------------------------------------------------------
$socID = $this->ReadPropertyInteger('SourceSoC'); $socID = $this->ReadPropertyInteger('SourceSoC');
if (IPS_VariableExists($socID)) { if (IPS_VariableExists($socID)) $this->RegisterMessage($socID, VM_UPDATE);
$this->RegisterMessage($socID, VM_UPDATE);
}
$this->RegisterMessage($this->GetIDForIdent('Strategy'), VM_UPDATE); $this->RegisterMessage($this->GetIDForIdent('Strategy'), VM_UPDATE);
$this->RegisterMessage($this->GetIDForIdent('PowerSetpoint'), VM_UPDATE); $this->RegisterMessage($this->GetIDForIdent('PowerSetpoint'), VM_UPDATE);
} }
/**
* Sucht den IO (Socket) und setzt User/Passwort/ClientID
*/
private function ConfigureGateway()
{
// 1. Parent (Splitter) holen
$instance = IPS_GetInstance($this->InstanceID);
$splitterID = $instance['ConnectionID'];
if ($splitterID > 0) {
// 2. Grandparent (IO / Client Socket) holen
$splitter = IPS_GetInstance($splitterID);
$ioID = $splitter['ConnectionID'];
if ($ioID > 0) {
$user = $this->ReadPropertyString('MQTTUser');
$pass = $this->ReadPropertyString('MQTTPassword');
$client = $this->ReadPropertyString('MQTTClientID');
$hasChanged = false;
// --- 1. Benutzer/Passwort am IO setzen (meist MQTT Client Socket) ---
// Prüfen ob Properties existieren, um Fehler zu vermeiden
if (@IPS_GetProperty($ioID, 'Username') !== false) {
if (IPS_GetProperty($ioID, 'Username') != $user) {
IPS_SetProperty($ioID, 'Username', $user);
$hasChanged = true;
}
}
if (@IPS_GetProperty($ioID, 'Password') !== false) {
if (IPS_GetProperty($ioID, 'Password') != $pass) {
IPS_SetProperty($ioID, 'Password', $pass);
$hasChanged = true;
}
}
// --- 2. ClientID am Splitter setzen (oft ist ClientID im Splitter, nicht IO) ---
// Falls ClientID im Splitter definiert ist:
if (@IPS_GetProperty($splitterID, 'ClientID') !== false) {
if (IPS_GetProperty($splitterID, 'ClientID') != $client) {
IPS_SetProperty($splitterID, 'ClientID', $client);
IPS_ApplyChanges($splitterID); // Splitter sofort übernehmen
}
}
// Falls ClientID doch am IO ist:
elseif (@IPS_GetProperty($ioID, 'ClientID') !== false) {
if (IPS_GetProperty($ioID, 'ClientID') != $client) {
IPS_SetProperty($ioID, 'ClientID', $client);
$hasChanged = true;
}
}
// IO Änderungen speichern
if ($hasChanged) {
IPS_ApplyChanges($ioID);
}
}
}
}
// -------------------------------------------------------------------------
// MQTT Logik
// -------------------------------------------------------------------------
public function ReceiveData($JSONString) public function ReceiveData($JSONString)
{ {
$data = json_decode($JSONString); $data = json_decode($JSONString);
// Payload Dekodierung
$payload = utf8_decode($data->Payload); $payload = utf8_decode($data->Payload);
$topic = $data->Topic; $topic = $data->Topic;
$baseTopic = $this->ReadPropertyString('MQTTBaseTopic');
//$this->SendDebug('MQTT Received', "Topic: $topic | Payload: $payload", 0); $baseTopic = $this->ReadPropertyString('MQTTBaseTopic');
if ($topic === $baseTopic . '/Writebefehl') { if ($topic === $baseTopic . '/Writebefehl') {
$this->ProcessWriteCommand($payload); $this->ProcessWriteCommand($payload);
@@ -156,38 +75,14 @@ class VGT_Sub extends IPSModule
} }
} }
public function MessageSink($TimeStamp, $SenderID, $Message, $Data)
{
if ($Message == VM_UPDATE) {
$socID = $this->ReadPropertyInteger('SourceSoC');
if ($SenderID == $socID) {
$this->SetValue('Visu_SoC', $Data[0]);
}
$this->ExecuteControlLogic();
}
}
public function RequestAction($Ident, $Value)
{
switch ($Ident) {
case 'Strategy':
case 'PowerSetpoint':
$this->SetValue($Ident, $Value);
$this->ExecuteControlLogic();
break;
}
}
private function ProcessWriteCommand($jsonInput) private function ProcessWriteCommand($jsonInput)
{ {
if ($jsonInput == "") return;
$data = json_decode($jsonInput, true); $data = json_decode($jsonInput, true);
if ($data === null) return; if ($data === null) return;
if (isset($data['power_setpoint'])) { if (isset($data['power_setpoint'])) {
$val = $data['power_setpoint']; $val = $data['power_setpoint'];
if ($val > 6000) $val = 6000; if ($val > 6000) $val = 6000; elseif ($val < -6000) $val = -6000;
elseif ($val < -6000) $val = -6000;
$this->SetValue('PowerSetpoint', $val); $this->SetValue('PowerSetpoint', $val);
} }
if (isset($data['strategy'])) { if (isset($data['strategy'])) {
@@ -196,26 +91,21 @@ class VGT_Sub extends IPSModule
$this->ExecuteControlLogic(); $this->ExecuteControlLogic();
$output = [ $output = ['power_setpoint' => $this->GetValue('PowerSetpoint'), 'strategy' => $this->GetValue('Strategy')];
'power_setpoint' => $this->GetValue('PowerSetpoint'),
'strategy' => $this->GetValue('Strategy')
];
$this->SendMQTT($this->ReadPropertyString('MQTTBaseTopic') . '/Writebefehl Antwort', json_encode($output)); $this->SendMQTT($this->ReadPropertyString('MQTTBaseTopic') . '/Writebefehl Antwort', json_encode($output));
} }
private function ProcessReadCommand() private function ProcessReadCommand()
{ {
$data = $this->GatherHardwareData(); $safeGet = function($prop) { $id = $this->ReadPropertyInteger($prop); return IPS_VariableExists($id) ? GetValue($id) : 0; };
$this->SetValue('Visu_Production', $data['raw_prod']);
$this->SetValue('Visu_IsReady', $data['is_ready']);
$mqttData = [ $mqttData = [
'power_production' => -1 * $data['raw_prod'], 'power_production' => -1 * $safeGet('SourcePowerProd'),
'is_ready' => $data['is_ready'], 'is_ready' => (bool)$safeGet('SourceIsReady'),
'is_running' => $data['is_running'], 'is_running' => (bool)$safeGet('SourceIsRunning'),
'state_of_charge' => $data['soc'], 'state_of_charge' => $safeGet('SourceSoC'),
'min_soc' => $data['min_soc'], 'min_soc' => $safeGet('SourceMinSoC'),
'max_soc' => $data['max_soc'] 'max_soc' => $safeGet('SourceMaxSoC')
]; ];
$this->SendMQTT($this->ReadPropertyString('MQTTBaseTopic') . '/Lesebefehl Antwort', json_encode($mqttData)); $this->SendMQTT($this->ReadPropertyString('MQTTBaseTopic') . '/Lesebefehl Antwort', json_encode($mqttData));
} }
@@ -235,47 +125,65 @@ class VGT_Sub extends IPSModule
} elseif ($strategy == "stop") { } elseif ($strategy == "stop") {
RequestAction($targetID, 0); RequestAction($targetID, 0);
} else { } else {
if ((int)$soc == 50) { if ((int)$soc == 50) RequestAction($targetID, 0);
RequestAction($targetID, 0); elseif ($soc < 50) RequestAction($targetID, 2500);
} elseif ($soc < 50) { else RequestAction($targetID, -2500);
RequestAction($targetID, 2500);
} else {
RequestAction($targetID, -2500);
}
} }
} }
private function GatherHardwareData()
{
$safeGet = function($propName) {
$id = $this->ReadPropertyInteger($propName);
return IPS_VariableExists($id) ? GetValue($id) : 0;
};
return [
'raw_prod' => $safeGet('SourcePowerProd'),
'is_ready' => (bool)$safeGet('SourceIsReady'),
'is_running' => (bool)$safeGet('SourceIsRunning'),
'soc' => $safeGet('SourceSoC'),
'min_soc' => $safeGet('SourceMinSoC'),
'max_soc' => $safeGet('SourceMaxSoC'),
];
}
protected function SendMQTT($Topic, $Payload) protected function SendMQTT($Topic, $Payload)
{ {
// DataID für Symcon MQTT Publish. // Standard DataID für MQTT. Funktioniert meistens auch mit dem 77B-Modul.
// Falls der Schnittcher-Splitter eine andere ID will, könnte hier ein Fehler kommen.
// In den meisten Fällen funktioniert diese ID aber auch mit kompatiblen Splittern.
$Data['DataID'] = '{043EA491-0325-4ADD-8FC2-A30C8EEB4D3F}'; $Data['DataID'] = '{043EA491-0325-4ADD-8FC2-A30C8EEB4D3F}';
$Data['PacketType'] = 3; $Data['PacketType'] = 3;
$Data['QualityOfService'] = 0; $Data['QualityOfService'] = 0;
$Data['Retain'] = false; $Data['Retain'] = false;
$Data['Topic'] = $Topic; $Data['Topic'] = $Topic;
$Data['Payload'] = $Payload; $Data['Payload'] = $Payload;
$this->SendDataToParent(json_encode($Data));
}
$JSON = json_encode($Data); // Automatische Konfiguration des Parents (falls aktiviert)
$this->SendDataToParent($JSON); private function ConfigureGateway()
{
$instance = IPS_GetInstance($this->InstanceID);
$parentId = $instance['ConnectionID']; // Das ist dein 77B Modul oder der native Splitter
if ($parentId > 0) {
// Wir versuchen, User/Pass auf dem Parent zu setzen (manche Module haben das direkt)
// Oder wir suchen den IO darunter.
$user = $this->ReadPropertyString('MQTTUser');
$pass = $this->ReadPropertyString('MQTTPassword');
// Check: Hat der Parent direkt Username/Password? (Schnittcher Modul hat das oft)
if (@IPS_GetProperty($parentId, 'Username') !== false) {
IPS_SetProperty($parentId, 'Username', $user);
IPS_SetProperty($parentId, 'Password', $pass);
IPS_ApplyChanges($parentId);
return;
}
// Wenn nicht, suchen wir den IO darunter (Native Symcon Logik)
$parentInfo = IPS_GetInstance($parentId);
$ioID = $parentInfo['ConnectionID'];
if ($ioID > 0) {
if (@IPS_GetProperty($ioID, 'Username') !== false) {
IPS_SetProperty($ioID, 'Username', $user);
IPS_SetProperty($ioID, 'Password', $pass);
IPS_ApplyChanges($ioID);
}
}
}
}
public function RequestAction($Ident, $Value) {
$this->SetValue($Ident, $Value);
$this->ExecuteControlLogic();
}
public function MessageSink($TimeStamp, $SenderID, $Message, $Data) {
if ($Message == VM_UPDATE) $this->ExecuteControlLogic();
} }
} }
?> ?>