Refactor CounterClient to CounterServer with improved payload handling and measurement storage
- Renamed class from CounterClient to CounterServer for clarity. - Updated properties to include Connector and SourceJSON. - Removed MQTT-related properties and methods. - Implemented checkTable method to handle JSON input and database operations. - Added logic for inserting/updating meter devices and measurements in the database. - Simplified unit handling and removed unused methods. - Enhanced logging for better debugging and error tracking.
This commit is contained in:
+150
-312
@@ -50,8 +50,6 @@ class CounterClient extends IPSModule
|
||||
|
||||
if ($mqttClientId > 0 && IPS_InstanceExists($mqttClientId) && $mqttTopic !== '') {
|
||||
$this->MqttPublish($mqttClientId, $mqttTopic, $json, true);
|
||||
} else {
|
||||
IPS_LogMessage('CounterClient', 'MQTT ist aktiviert, aber ungültige MQTT Client ID oder Topic.');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,82 +62,90 @@ class CounterClient extends IPSModule
|
||||
return '';
|
||||
}
|
||||
|
||||
$counterIds = IPS_GetChildrenIDs($counterCategoryId);
|
||||
|
||||
$payload = [
|
||||
'timestamp' => date('Y-m-d H:i:s'),
|
||||
'counters' => []
|
||||
];
|
||||
|
||||
foreach ($counterIds as $counterObjectId) {
|
||||
if (!IPS_ObjectExists($counterObjectId)) {
|
||||
$counterFolders = IPS_GetChildrenIDs($counterCategoryId);
|
||||
|
||||
foreach ($counterFolders as $counterFolderId) {
|
||||
if (!IPS_ObjectExists($counterFolderId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$obj = IPS_GetObject($counterObjectId);
|
||||
|
||||
$obj = IPS_GetObject($counterFolderId);
|
||||
if ((int)$obj['ObjectType'] !== 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$counterName = IPS_GetName($counterObjectId);
|
||||
$counterName = IPS_GetName($counterFolderId);
|
||||
$counterId = $this->makeSlug($counterName);
|
||||
|
||||
$entries = $this->CollectEntriesRecursive($counterObjectId, [$counterName], []);
|
||||
if (count($entries) === 0) {
|
||||
IPS_LogMessage('CounterClient', 'Keine Variablen gefunden in Counter: ' . $counterName);
|
||||
continue;
|
||||
}
|
||||
|
||||
$counterData = [
|
||||
'id' => $counterId,
|
||||
'name' => $counterName
|
||||
];
|
||||
|
||||
$tempSlots = [];
|
||||
$pressureSlots = [];
|
||||
$found = 0;
|
||||
$children = IPS_GetChildrenIDs($counterFolderId);
|
||||
|
||||
foreach ($entries as $entry) {
|
||||
$classified = $this->ClassifyEntry($entry);
|
||||
if ($classified === null) {
|
||||
foreach ($children as $childId) {
|
||||
if (!IPS_ObjectExists($childId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$field = $classified['field'];
|
||||
$value = $classified['value'];
|
||||
$unit = $classified['unit'];
|
||||
if (IPS_LinkExists($childId)) {
|
||||
$link = IPS_GetLink($childId);
|
||||
$targetId = (int)$link['TargetID'];
|
||||
$linkName = IPS_GetName($childId);
|
||||
|
||||
if ($targetId <= 0 || !IPS_ObjectExists($targetId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IPS_VariableExists($targetId)) {
|
||||
if ($this->addVariableToCounter($counterData, $targetId, $counterName . ' ' . $linkName)) {
|
||||
$found++;
|
||||
}
|
||||
} else {
|
||||
$subChildren = IPS_GetChildrenIDs($targetId);
|
||||
foreach ($subChildren as $subChildId) {
|
||||
if (IPS_VariableExists($subChildId)) {
|
||||
if ($this->addVariableToCounter($counterData, $subChildId, $counterName . ' ' . $linkName . ' ' . IPS_GetName($targetId))) {
|
||||
$found++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($field === 'temperature_auto') {
|
||||
$tempSlots[] = $classified;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($field === 'pressure_auto') {
|
||||
$pressureSlots[] = $classified;
|
||||
if (IPS_VariableExists($childId)) {
|
||||
if ($this->addVariableToCounter($counterData, $childId, $counterName)) {
|
||||
$found++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
$counterData[$field] = $value;
|
||||
|
||||
if ($field === 'total_value' && !isset($counterData['unit']) && $unit !== '') {
|
||||
$counterData['unit'] = $unit;
|
||||
$subChildren = IPS_GetChildrenIDs($childId);
|
||||
foreach ($subChildren as $subChildId) {
|
||||
if (IPS_VariableExists($subChildId)) {
|
||||
if ($this->addVariableToCounter($counterData, $subChildId, $counterName . ' ' . IPS_GetName($childId))) {
|
||||
$found++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->assignInOutValues($counterData, $tempSlots, 'temperature_in_value', 'temperature_out_value');
|
||||
$this->assignInOutValues($counterData, $pressureSlots, 'pressure_in_value', 'pressure_out_value');
|
||||
|
||||
$contextString = mb_strtolower($counterName . ' ' . implode(' ', array_map(function ($e) {
|
||||
return $e['context'];
|
||||
}, $entries)));
|
||||
|
||||
$counterData['type'] = $this->DetectCounterType($counterData, $contextString);
|
||||
$counterData['type'] = $this->DetectCounterType($counterData, $counterName);
|
||||
|
||||
if (!isset($counterData['unit'])) {
|
||||
$counterData['unit'] = $this->inferDefaultUnit($counterData);
|
||||
}
|
||||
|
||||
if ($this->hasUsableMeasurement($counterData)) {
|
||||
if ($found > 0) {
|
||||
$payload['counters'][] = $counterData;
|
||||
} else {
|
||||
IPS_LogMessage('CounterClient', 'Counter ohne erkannte Messwerte übersprungen: ' . $counterName);
|
||||
@@ -149,273 +155,164 @@ class CounterClient extends IPSModule
|
||||
return json_encode($payload, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
}
|
||||
|
||||
private function CollectEntriesRecursive(int $objectId, array $pathParts, array $visited): array
|
||||
private function addVariableToCounter(array &$counterData, int $varId, string $contextPrefix): bool
|
||||
{
|
||||
$result = [];
|
||||
|
||||
if (isset($visited[$objectId])) {
|
||||
return $result;
|
||||
}
|
||||
$visited[$objectId] = true;
|
||||
|
||||
if (!IPS_ObjectExists($objectId)) {
|
||||
return $result;
|
||||
}
|
||||
|
||||
if (IPS_LinkExists($objectId)) {
|
||||
$link = IPS_GetLink($objectId);
|
||||
$targetId = (int)$link['TargetID'];
|
||||
$linkName = IPS_GetName($objectId);
|
||||
|
||||
if ($targetId > 0 && IPS_ObjectExists($targetId)) {
|
||||
$newPath = $pathParts;
|
||||
if ($linkName !== '') {
|
||||
$newPath[] = $linkName;
|
||||
}
|
||||
|
||||
return $this->CollectEntriesRecursive($targetId, $newPath, $visited);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
if (IPS_VariableExists($objectId)) {
|
||||
$result[] = [
|
||||
'varId' => $objectId,
|
||||
'context' => $this->buildContextString($pathParts, IPS_GetName($objectId)),
|
||||
'path' => $pathParts,
|
||||
'varName' => IPS_GetName($objectId)
|
||||
];
|
||||
return $result;
|
||||
}
|
||||
|
||||
$children = IPS_GetChildrenIDs($objectId);
|
||||
foreach ($children as $childId) {
|
||||
if (!IPS_ObjectExists($childId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$childName = IPS_GetName($childId);
|
||||
$newPath = $pathParts;
|
||||
|
||||
if ($childName !== '') {
|
||||
$newPath[] = $childName;
|
||||
}
|
||||
|
||||
$sub = $this->CollectEntriesRecursive($childId, $newPath, $visited);
|
||||
foreach ($sub as $entry) {
|
||||
$result[] = $entry;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function ClassifyEntry(array $entry): ?array
|
||||
{
|
||||
$varId = (int)$entry['varId'];
|
||||
|
||||
if (!IPS_VariableExists($varId)) {
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
|
||||
$var = IPS_GetVariable($varId);
|
||||
$type = (int)$var['VariableType'];
|
||||
|
||||
if ($type !== 1 && $type !== 2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$profileName = '';
|
||||
if ($var['VariableCustomProfile'] !== '') {
|
||||
$profileName = $var['VariableCustomProfile'];
|
||||
} elseif ($var['VariableProfile'] !== '') {
|
||||
$profileName = $var['VariableProfile'];
|
||||
}
|
||||
|
||||
if ($profileName === '' || !IPS_VariableProfileExists($profileName)) {
|
||||
IPS_LogMessage('CounterClient', 'Variable ohne gültiges Profil ignoriert: ' . $entry['context']);
|
||||
return null;
|
||||
}
|
||||
|
||||
$profile = IPS_GetVariableProfile($profileName);
|
||||
$suffix = trim((string)$profile['Suffix']);
|
||||
$prefix = trim((string)$profile['Prefix']);
|
||||
$unit = trim($prefix . ' ' . $suffix);
|
||||
|
||||
if ($unit === '') {
|
||||
IPS_LogMessage('CounterClient', 'Variable ohne Einheit ignoriert: ' . $entry['context']);
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
|
||||
$value = GetValue($varId);
|
||||
if (!is_numeric($value)) {
|
||||
return null;
|
||||
return false;
|
||||
}
|
||||
|
||||
$value = round((float)$value, 3);
|
||||
$context = mb_strtolower($entry['context']);
|
||||
|
||||
$varName = IPS_GetName($varId);
|
||||
$context = mb_strtolower(trim($contextPrefix . ' ' . $varName));
|
||||
$unit = $this->getVariableUnit($varId, $var, $value);
|
||||
$unitNorm = $this->normalizeUnit($unit);
|
||||
|
||||
if ($unitNorm === '') {
|
||||
IPS_LogMessage('CounterClient', 'Keine Einheit erkannt: ' . $context);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->isTotalUnit($unitNorm, $context)) {
|
||||
return [
|
||||
'field' => 'total_value',
|
||||
'value' => $value,
|
||||
'unit' => $this->formatOutputUnit($suffix, $unitNorm),
|
||||
'name' => $context,
|
||||
'context' => $context
|
||||
];
|
||||
$counterData['total_value'] = $value;
|
||||
if (!isset($counterData['unit'])) {
|
||||
$counterData['unit'] = $this->formatOutputUnit($unitNorm);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->isPowerUnit($unitNorm, $context)) {
|
||||
return [
|
||||
'field' => 'power_value',
|
||||
'value' => $value,
|
||||
'unit' => $unitNorm,
|
||||
'name' => $context,
|
||||
'context' => $context
|
||||
];
|
||||
$counterData['power_value'] = $value;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->isFlowUnit($unitNorm, $context)) {
|
||||
return [
|
||||
'field' => 'flow_value',
|
||||
'value' => $value,
|
||||
'unit' => $unitNorm,
|
||||
'name' => $context,
|
||||
'context' => $context
|
||||
];
|
||||
$counterData['flow_value'] = $value;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($unitNorm === 'a') {
|
||||
return [
|
||||
'field' => 'current_value',
|
||||
'value' => $value,
|
||||
'unit' => $unitNorm,
|
||||
'name' => $context,
|
||||
'context' => $context
|
||||
];
|
||||
$counterData['current_value'] = $value;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($unitNorm === 'v') {
|
||||
return [
|
||||
'field' => 'voltage_value',
|
||||
'value' => $value,
|
||||
'unit' => $unitNorm,
|
||||
'name' => $context,
|
||||
'context' => $context
|
||||
];
|
||||
$counterData['voltage_value'] = $value;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($unitNorm === 'hz') {
|
||||
return [
|
||||
'field' => 'frequency_value',
|
||||
'value' => $value,
|
||||
'unit' => $unitNorm,
|
||||
'name' => $context,
|
||||
'context' => $context
|
||||
];
|
||||
$counterData['frequency_value'] = $value;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (in_array($unitNorm, ['bar', 'mbar', 'pa'], true)) {
|
||||
if ($this->looksLikeIn($context)) {
|
||||
return [
|
||||
'field' => 'pressure_in_value',
|
||||
'value' => $value,
|
||||
'unit' => $unitNorm,
|
||||
'name' => $context,
|
||||
'context' => $context
|
||||
];
|
||||
}
|
||||
|
||||
if ($this->looksLikeOut($context)) {
|
||||
return [
|
||||
'field' => 'pressure_out_value',
|
||||
'value' => $value,
|
||||
'unit' => $unitNorm,
|
||||
'name' => $context,
|
||||
'context' => $context
|
||||
];
|
||||
$counterData['pressure_out_value'] = $value;
|
||||
} else {
|
||||
$counterData['pressure_in_value'] = $value;
|
||||
}
|
||||
|
||||
return [
|
||||
'field' => 'pressure_auto',
|
||||
'value' => $value,
|
||||
'unit' => $unitNorm,
|
||||
'name' => $context,
|
||||
'context' => $context
|
||||
];
|
||||
return true;
|
||||
}
|
||||
|
||||
if (in_array($unitNorm, ['°c', 'c', 'k'], true)) {
|
||||
if ($this->looksLikeIn($context)) {
|
||||
return [
|
||||
'field' => 'temperature_in_value',
|
||||
'value' => $value,
|
||||
'unit' => $unitNorm,
|
||||
'name' => $context,
|
||||
'context' => $context
|
||||
];
|
||||
}
|
||||
|
||||
if ($this->looksLikeOut($context)) {
|
||||
return [
|
||||
'field' => 'temperature_out_value',
|
||||
'value' => $value,
|
||||
'unit' => $unitNorm,
|
||||
'name' => $context,
|
||||
'context' => $context
|
||||
];
|
||||
$counterData['temperature_out_value'] = $value;
|
||||
} else {
|
||||
$counterData['temperature_in_value'] = $value;
|
||||
}
|
||||
|
||||
return [
|
||||
'field' => 'temperature_auto',
|
||||
'value' => $value,
|
||||
'unit' => $unitNorm,
|
||||
'name' => $context,
|
||||
'context' => $context
|
||||
];
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($unitNorm === 'cos' || $unitNorm === 'cosphi' || $unitNorm === 'pf') {
|
||||
return [
|
||||
'field' => 'power_factor',
|
||||
'value' => $value,
|
||||
'unit' => $unitNorm,
|
||||
'name' => $context,
|
||||
'context' => $context
|
||||
];
|
||||
$counterData['power_factor'] = $value;
|
||||
return true;
|
||||
}
|
||||
|
||||
IPS_LogMessage('CounterClient', 'Nicht erkannt: ' . $context . ' | Unit: ' . $unitNorm . ' | Profile: ' . $profileName);
|
||||
return null;
|
||||
IPS_LogMessage('CounterClient', 'Nicht zugeordnet: ' . $context . ' | Einheit: ' . $unitNorm . ' | Wert: ' . $value);
|
||||
return false;
|
||||
}
|
||||
|
||||
private function assignInOutValues(array &$counterData, array $items, string $fieldIn, string $fieldOut): void
|
||||
private function getVariableUnit(int $varId, array $var, float $value): string
|
||||
{
|
||||
foreach ($items as $item) {
|
||||
if ($this->looksLikeIn($item['name']) && !isset($counterData[$fieldIn])) {
|
||||
$counterData[$fieldIn] = $item['value'];
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($this->looksLikeOut($item['name']) && !isset($counterData[$fieldOut])) {
|
||||
$counterData[$fieldOut] = $item['value'];
|
||||
continue;
|
||||
if (function_exists('IPS_GetPresentation')) {
|
||||
try {
|
||||
$presentation = @IPS_GetPresentation($varId);
|
||||
if (is_array($presentation)) {
|
||||
if (isset($presentation['Suffix']) && trim((string)$presentation['Suffix']) !== '') {
|
||||
return trim((string)$presentation['Suffix']);
|
||||
}
|
||||
if (isset($presentation['Prefix']) && trim((string)$presentation['Prefix']) !== '') {
|
||||
return trim((string)$presentation['Prefix']);
|
||||
}
|
||||
if (isset($presentation['Unit']) && trim((string)$presentation['Unit']) !== '') {
|
||||
return trim((string)$presentation['Unit']);
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($items as $item) {
|
||||
if (!isset($counterData[$fieldIn])) {
|
||||
$counterData[$fieldIn] = $item['value'];
|
||||
continue;
|
||||
}
|
||||
$profileName = '';
|
||||
if (isset($var['VariableCustomProfile']) && $var['VariableCustomProfile'] !== '') {
|
||||
$profileName = $var['VariableCustomProfile'];
|
||||
} elseif (isset($var['VariableProfile']) && $var['VariableProfile'] !== '') {
|
||||
$profileName = $var['VariableProfile'];
|
||||
}
|
||||
|
||||
if (!isset($counterData[$fieldOut])) {
|
||||
$counterData[$fieldOut] = $item['value'];
|
||||
continue;
|
||||
if ($profileName !== '' && IPS_VariableProfileExists($profileName)) {
|
||||
$profile = IPS_GetVariableProfile($profileName);
|
||||
$suffix = trim((string)$profile['Suffix']);
|
||||
$prefix = trim((string)$profile['Prefix']);
|
||||
$unit = trim($prefix . ' ' . $suffix);
|
||||
if ($unit !== '') {
|
||||
return $unit;
|
||||
}
|
||||
}
|
||||
|
||||
$formatted = GetValueFormatted($varId);
|
||||
return $this->extractUnitFromFormattedValue($formatted, $value);
|
||||
}
|
||||
|
||||
private function extractUnitFromFormattedValue(string $formatted, float $value): string
|
||||
{
|
||||
$formatted = trim($formatted);
|
||||
if ($formatted === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
$search = [
|
||||
number_format($value, 0, ',', '.'),
|
||||
number_format($value, 1, ',', '.'),
|
||||
number_format($value, 2, ',', '.'),
|
||||
number_format($value, 3, ',', '.'),
|
||||
str_replace('.', ',', (string)$value),
|
||||
str_replace(',', '.', (string)$value),
|
||||
(string)$value
|
||||
];
|
||||
|
||||
$unit = $formatted;
|
||||
foreach ($search as $needle) {
|
||||
if ($needle !== '') {
|
||||
$unit = str_replace($needle, '', $unit);
|
||||
}
|
||||
}
|
||||
|
||||
$unit = trim($unit);
|
||||
$unit = preg_replace('/^[\-\+\d\.,\s]+/u', '', $unit);
|
||||
return trim($unit);
|
||||
}
|
||||
|
||||
private function DetectCounterType(array $counterData, string $context): string
|
||||
@@ -459,7 +356,7 @@ class CounterClient extends IPSModule
|
||||
{
|
||||
if (isset($counterData['total_value'])) {
|
||||
if ($counterData['type'] === 'water' || $counterData['type'] === 'gas') {
|
||||
return 'm3';
|
||||
return 'm³';
|
||||
}
|
||||
return 'kWh';
|
||||
}
|
||||
@@ -467,39 +364,9 @@ class CounterClient extends IPSModule
|
||||
return '';
|
||||
}
|
||||
|
||||
private function hasUsableMeasurement(array $counterData): bool
|
||||
{
|
||||
$fields = [
|
||||
'total_value',
|
||||
'consumption_value',
|
||||
'power_value',
|
||||
'flow_value',
|
||||
'current_value',
|
||||
'voltage_value',
|
||||
'temperature_in_value',
|
||||
'temperature_out_value',
|
||||
'pressure_in_value',
|
||||
'pressure_out_value',
|
||||
'frequency_value',
|
||||
'power_factor'
|
||||
];
|
||||
|
||||
foreach ($fields as $field) {
|
||||
if (array_key_exists($field, $counterData)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function isTotalUnit(string $unitNorm, string $context): bool
|
||||
{
|
||||
if (in_array($unitNorm, ['kwh', 'wh', 'mwh', 'm3', 'l'], true)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($unitNorm === 'kw/h' || $unitNorm === 'w/h' || $unitNorm === 'mw/h') {
|
||||
if (in_array($unitNorm, ['kwh', 'wh', 'mwh', 'm3', 'l', 'kw/h', 'w/h', 'mw/h'], true)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -539,25 +406,17 @@ class CounterClient extends IPSModule
|
||||
return false;
|
||||
}
|
||||
|
||||
private function formatOutputUnit(string $suffix, string $unitNorm): string
|
||||
private function formatOutputUnit(string $unitNorm): string
|
||||
{
|
||||
$suffix = trim($suffix);
|
||||
if ($suffix !== '') {
|
||||
return $suffix;
|
||||
}
|
||||
|
||||
if ($unitNorm === 'm3') {
|
||||
return 'm³';
|
||||
}
|
||||
|
||||
if ($unitNorm === 'kwh') {
|
||||
return 'kWh';
|
||||
}
|
||||
|
||||
if ($unitNorm === 'kw/h') {
|
||||
return 'kW/h';
|
||||
}
|
||||
|
||||
return $unitNorm;
|
||||
}
|
||||
|
||||
@@ -591,9 +450,6 @@ class CounterClient extends IPSModule
|
||||
$unit = mb_strtolower(trim($unit));
|
||||
$unit = str_replace(["\xc2\xa0", ' '], '', $unit);
|
||||
$unit = str_replace(['m³', '㎥'], 'm3', $unit);
|
||||
$unit = str_replace(['°'], '°', $unit);
|
||||
$unit = str_replace(['kw/hh'], 'kw/h', $unit);
|
||||
$unit = str_replace(['㎾/h'], 'kw/h', $unit);
|
||||
return $unit;
|
||||
}
|
||||
|
||||
@@ -611,20 +467,6 @@ class CounterClient extends IPSModule
|
||||
return $text;
|
||||
}
|
||||
|
||||
private function buildContextString(array $pathParts, string $varName): string
|
||||
{
|
||||
$parts = $pathParts;
|
||||
if ($varName !== '') {
|
||||
$parts[] = $varName;
|
||||
}
|
||||
|
||||
$parts = array_values(array_filter($parts, function ($v) {
|
||||
return trim((string)$v) !== '';
|
||||
}));
|
||||
|
||||
return implode(' ', $parts);
|
||||
}
|
||||
|
||||
public function MqttPublish($server_id, $topic, $payload, $retain)
|
||||
{
|
||||
if (!IPS_InstanceExists($server_id)) {
|
||||
@@ -644,7 +486,6 @@ class CounterClient extends IPSModule
|
||||
if ($id === false) {
|
||||
$id = @IPS_CreateInstance($module_id);
|
||||
if ($id === false) {
|
||||
IPS_SemaphoreLeave($ident);
|
||||
return false;
|
||||
}
|
||||
IPS_SetParent($id, $this->InstanceID);
|
||||
@@ -652,7 +493,6 @@ class CounterClient extends IPSModule
|
||||
}
|
||||
|
||||
if (!IPS_IsInstanceCompatible($id, $server_id)) {
|
||||
IPS_SemaphoreLeave($ident);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -660,7 +500,6 @@ class CounterClient extends IPSModule
|
||||
if ((int)$inst_config['ConnectionID'] !== (int)$server_id) {
|
||||
IPS_DisconnectInstance($id);
|
||||
if (!@IPS_ConnectInstance($id, $server_id)) {
|
||||
IPS_SemaphoreLeave($ident);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -679,7 +518,6 @@ class CounterClient extends IPSModule
|
||||
|
||||
$var_id = @IPS_GetObjectIDByIdent('Value', $id);
|
||||
if ($var_id === false) {
|
||||
IPS_SemaphoreLeave($ident);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
+120
-481
@@ -1,21 +1,17 @@
|
||||
<?php
|
||||
|
||||
class CounterClient extends IPSModule
|
||||
class CounterServer extends IPSModule
|
||||
{
|
||||
public function Create()
|
||||
{
|
||||
parent::Create();
|
||||
|
||||
$this->RegisterPropertyInteger('CounterCategoryID', 0);
|
||||
$this->RegisterPropertyInteger('JsonOutputVariableID', 0);
|
||||
$this->RegisterPropertyInteger('Connector', 0);
|
||||
$this->RegisterPropertyInteger('SourceJSON', 0);
|
||||
$this->RegisterPropertyInteger('UpdateTime', 60);
|
||||
$this->RegisterPropertyBoolean('EnableMQTT', false);
|
||||
$this->RegisterPropertyInteger('MqttClientID', 0);
|
||||
$this->RegisterPropertyString('Projectname', '');
|
||||
$this->RegisterPropertyInteger('Projectyear', 2026);
|
||||
$this->RegisterPropertyInteger('Projectnumber', 0);
|
||||
|
||||
$this->RegisterTimer('Update', 0, 'SECC_BuildAndStorePayload(' . $this->InstanceID . ');');
|
||||
$this->RegisterPropertyString('Projectname', 60);
|
||||
$this->RegisterPropertyInteger('ProjectIdPortal', -1);
|
||||
$this->RegisterTimer('Update', 0, 'SECS_checkTable('.$this->InstanceID.');');
|
||||
}
|
||||
|
||||
public function ApplyChanges()
|
||||
@@ -28,505 +24,148 @@ class CounterClient extends IPSModule
|
||||
}
|
||||
|
||||
$this->SetTimerInterval('Update', $updateTime * 1000);
|
||||
$this->checkTable();
|
||||
}
|
||||
|
||||
public function BuildAndStorePayload()
|
||||
public function checkTable()
|
||||
{
|
||||
$json = $this->BuildPayload();
|
||||
if ($json === '') {
|
||||
$sqlId = $this->ReadPropertyInteger('Connector');
|
||||
$jsonVar = $this->ReadPropertyInteger('SourceJSON');
|
||||
|
||||
if ($sqlId <= 0 || $jsonVar <= 0) {
|
||||
IPS_LogMessage('CounterTable', 'Config fehlt.');
|
||||
return;
|
||||
}
|
||||
|
||||
$targetVarId = $this->ReadPropertyInteger('JsonOutputVariableID');
|
||||
if ($targetVarId > 0 && IPS_VariableExists($targetVarId)) {
|
||||
SetValueString($targetVarId, $json);
|
||||
$jsonString = GetValueString($jsonVar);
|
||||
if ($jsonString === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
IPS_LogMessage('CounterClient', $json);
|
||||
|
||||
if ($this->ReadPropertyBoolean('EnableMQTT')) {
|
||||
$mqttClientId = $this->ReadPropertyInteger('MqttClientID');
|
||||
$mqttTopic = 'Projekte' . $this->ReadPropertyInteger('Projectyear') . '/P' . $this->ReadPropertyInteger('Projectnumber') . '/Counters';
|
||||
|
||||
if ($mqttClientId > 0 && IPS_InstanceExists($mqttClientId) && $mqttTopic !== '') {
|
||||
$this->MqttPublish($mqttClientId, $mqttTopic, $json, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function BuildPayload()
|
||||
{
|
||||
$counterCategoryId = $this->ReadPropertyInteger('CounterCategoryID');
|
||||
if ($counterCategoryId <= 0 || !IPS_ObjectExists($counterCategoryId)) {
|
||||
IPS_LogMessage('CounterClient', 'Ungültige CounterCategoryID');
|
||||
return '';
|
||||
$payload = json_decode($jsonString, true);
|
||||
if (!is_array($payload)) {
|
||||
IPS_LogMessage('CounterTable', 'JSON Fehler');
|
||||
return;
|
||||
}
|
||||
|
||||
$payload = [
|
||||
'timestamp' => date('Y-m-d H:i:s'),
|
||||
'counters' => []
|
||||
];
|
||||
$clientId = (string)$this->InstanceID;
|
||||
$clientName = IPS_GetName($this->InstanceID);
|
||||
$projectName = $this->ReadPropertyString('Projectname');
|
||||
$timestamp = $payload['timestamp'] ?? date('Y-m-d H:i:s');
|
||||
$counters = $payload['counters'] ?? [];
|
||||
$projectId = $this->ReadPropertyInteger('ProjectIdPortal');
|
||||
|
||||
$counterFolders = IPS_GetChildrenIDs($counterCategoryId);
|
||||
if ($projectId !== -1) {
|
||||
foreach ($counters as $c) {
|
||||
|
||||
foreach ($counterFolders as $counterFolderId) {
|
||||
if (!IPS_ObjectExists($counterFolderId)) {
|
||||
$counterId = $c['id'] ?? '';
|
||||
if ($counterId === '') continue;
|
||||
|
||||
$counterName = $c['name'] ?? $counterId;
|
||||
$type = $c['type'] ?? 'other';
|
||||
$unit = $c['unit'] ?? 'kWh';
|
||||
|
||||
|
||||
// ---------- UPSERT ----------
|
||||
$sql = "
|
||||
INSERT INTO meter_devices
|
||||
(project_id, counter_id, meter_uuid, external_id, external_name, meter_type, billing_unit, is_active)
|
||||
VALUES
|
||||
(
|
||||
'" . $this->esc($projectId) . "',
|
||||
'" . $this->esc($counterId) . "',
|
||||
'" . hash('sha256', $projectId.$clientId . '_' . $counterId) . "',
|
||||
'" . $this->esc($clientId) . "',
|
||||
'" . $this->esc($projectName.'_'. $counterId) . "',
|
||||
'" . $this->esc($type) . "',
|
||||
'" . $this->esc($unit) . "',
|
||||
1
|
||||
)
|
||||
ON DUPLICATE KEY UPDATE
|
||||
meter_name = VALUES(meter_name),
|
||||
meter_type = VALUES(meter_type),
|
||||
billing_unit = VALUES(billing_unit),
|
||||
is_active = 1
|
||||
";
|
||||
|
||||
|
||||
MySQL_ExecuteSimple($sqlId, $sql);
|
||||
|
||||
|
||||
// ---------- GET meter_id ----------
|
||||
$sqlGet = "
|
||||
SELECT id FROM meter_devices
|
||||
WHERE meter_uuid = '" . hash('sha256', $projectId.$clientId . '_' . $counterId) . "'
|
||||
LIMIT 1
|
||||
";
|
||||
|
||||
$res = MySQL_ExecuteSimple($sqlId, $sqlGet);
|
||||
|
||||
if (!is_array($res) || count($res) === 0) {
|
||||
IPS_LogMessage('CounterTable', 'Kein meter_id gefunden');
|
||||
continue;
|
||||
}
|
||||
|
||||
$obj = IPS_GetObject($counterFolderId);
|
||||
if ((int)$obj['ObjectType'] !== 0) {
|
||||
continue;
|
||||
}
|
||||
$meterId = $res[0]->id;
|
||||
|
||||
$counterName = IPS_GetName($counterFolderId);
|
||||
$counterId = $this->makeSlug($counterName);
|
||||
// ---------- INSERT measurement ----------
|
||||
$sqlInsert = "
|
||||
INSERT INTO meter_measurements
|
||||
(
|
||||
meter_id, measured_at,
|
||||
total_value, consumption_value,
|
||||
power_value, flow_value,
|
||||
current_value, voltage_value,
|
||||
temperature_in_value, temperature_out_value,
|
||||
pressure_in_value, pressure_out_value,
|
||||
frequency_value, power_factor
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
" . $meterId . ",
|
||||
'" . $this->esc($timestamp) . "',
|
||||
" . $this->f($c, 'total_value') . ",
|
||||
" . $this->f($c, 'consumption_value') . ",
|
||||
" . $this->f($c, 'power_value') . ",
|
||||
" . $this->f($c, 'flow_value') . ",
|
||||
" . $this->f($c, 'current_value') . ",
|
||||
" . $this->f($c, 'voltage_value') . ",
|
||||
" . $this->f($c, 'temperature_in_value') . ",
|
||||
" . $this->f($c, 'temperature_out_value') . ",
|
||||
" . $this->f($c, 'pressure_in_value') . ",
|
||||
" . $this->f($c, 'pressure_out_value') . ",
|
||||
" . $this->f($c, 'frequency_value') . ",
|
||||
" . $this->f($c, 'power_factor') . "
|
||||
)
|
||||
";
|
||||
|
||||
$counterData = [
|
||||
'id' => $counterId,
|
||||
'name' => $counterName
|
||||
];
|
||||
|
||||
$found = 0;
|
||||
$children = IPS_GetChildrenIDs($counterFolderId);
|
||||
|
||||
foreach ($children as $childId) {
|
||||
if (!IPS_ObjectExists($childId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IPS_LinkExists($childId)) {
|
||||
$link = IPS_GetLink($childId);
|
||||
$targetId = (int)$link['TargetID'];
|
||||
$linkName = IPS_GetName($childId);
|
||||
|
||||
if ($targetId <= 0 || !IPS_ObjectExists($targetId)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IPS_VariableExists($targetId)) {
|
||||
if ($this->addVariableToCounter($counterData, $targetId, $counterName . ' ' . $linkName)) {
|
||||
$found++;
|
||||
}
|
||||
} else {
|
||||
$subChildren = IPS_GetChildrenIDs($targetId);
|
||||
foreach ($subChildren as $subChildId) {
|
||||
if (IPS_VariableExists($subChildId)) {
|
||||
if ($this->addVariableToCounter($counterData, $subChildId, $counterName . ' ' . $linkName . ' ' . IPS_GetName($targetId))) {
|
||||
$found++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IPS_VariableExists($childId)) {
|
||||
if ($this->addVariableToCounter($counterData, $childId, $counterName)) {
|
||||
$found++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
$subChildren = IPS_GetChildrenIDs($childId);
|
||||
foreach ($subChildren as $subChildId) {
|
||||
if (IPS_VariableExists($subChildId)) {
|
||||
if ($this->addVariableToCounter($counterData, $subChildId, $counterName . ' ' . IPS_GetName($childId))) {
|
||||
$found++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$counterData['type'] = $this->DetectCounterType($counterData, $counterName);
|
||||
|
||||
if (!isset($counterData['unit'])) {
|
||||
$counterData['unit'] = $this->inferDefaultUnit($counterData);
|
||||
}
|
||||
|
||||
if ($found > 0) {
|
||||
$payload['counters'][] = $counterData;
|
||||
} else {
|
||||
IPS_LogMessage('CounterClient', 'Counter ohne erkannte Messwerte übersprungen: ' . $counterName);
|
||||
}
|
||||
MySQL_ExecuteSimple($sqlId, $sqlInsert);
|
||||
}
|
||||
} else {
|
||||
IPS_LogMessage('CounterTable', 'Keine Project-ID für Portal angegeben.');
|
||||
}
|
||||
|
||||
return json_encode($payload, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
||||
}
|
||||
|
||||
private function addVariableToCounter(array &$counterData, int $varId, string $contextPrefix): bool
|
||||
private function f($arr, $key)
|
||||
{
|
||||
if (!IPS_VariableExists($varId)) {
|
||||
return false;
|
||||
if (!isset($arr[$key]) || $arr[$key] === '' || $arr[$key] === null) {
|
||||
return 'NULL';
|
||||
}
|
||||
|
||||
$var = IPS_GetVariable($varId);
|
||||
$type = (int)$var['VariableType'];
|
||||
|
||||
if ($type !== 1 && $type !== 2) {
|
||||
return false;
|
||||
if (is_numeric($arr[$key])) {
|
||||
return str_replace(',', '.', (string)$arr[$key]);
|
||||
}
|
||||
|
||||
$value = GetValue($varId);
|
||||
if (!is_numeric($value)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$value = round((float)$value, 3);
|
||||
|
||||
$varName = IPS_GetName($varId);
|
||||
$context = mb_strtolower(trim($contextPrefix . ' ' . $varName));
|
||||
$unit = $this->getVariableUnit($varId, $var, $value);
|
||||
$unitNorm = $this->normalizeUnit($unit);
|
||||
|
||||
if ($unitNorm === '') {
|
||||
IPS_LogMessage('CounterClient', 'Keine Einheit erkannt: ' . $context);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->isTotalUnit($unitNorm, $context)) {
|
||||
$counterData['total_value'] = $value;
|
||||
if (!isset($counterData['unit'])) {
|
||||
$counterData['unit'] = $this->formatOutputUnit($unitNorm);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->isPowerUnit($unitNorm, $context)) {
|
||||
$counterData['power_value'] = $value;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($this->isFlowUnit($unitNorm, $context)) {
|
||||
$counterData['flow_value'] = $value;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($unitNorm === 'a') {
|
||||
$counterData['current_value'] = $value;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($unitNorm === 'v') {
|
||||
$counterData['voltage_value'] = $value;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($unitNorm === 'hz') {
|
||||
$counterData['frequency_value'] = $value;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (in_array($unitNorm, ['bar', 'mbar', 'pa'], true)) {
|
||||
if ($this->looksLikeOut($context)) {
|
||||
$counterData['pressure_out_value'] = $value;
|
||||
} else {
|
||||
$counterData['pressure_in_value'] = $value;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if (in_array($unitNorm, ['°c', 'c', 'k'], true)) {
|
||||
if ($this->looksLikeOut($context)) {
|
||||
$counterData['temperature_out_value'] = $value;
|
||||
} else {
|
||||
$counterData['temperature_in_value'] = $value;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if ($unitNorm === 'cos' || $unitNorm === 'cosphi' || $unitNorm === 'pf') {
|
||||
$counterData['power_factor'] = $value;
|
||||
return true;
|
||||
}
|
||||
|
||||
IPS_LogMessage('CounterClient', 'Nicht zugeordnet: ' . $context . ' | Einheit: ' . $unitNorm . ' | Wert: ' . $value);
|
||||
return false;
|
||||
return 'NULL';
|
||||
}
|
||||
|
||||
private function getVariableUnit(int $varId, array $var, float $value): string
|
||||
private function esc($v)
|
||||
{
|
||||
if (function_exists('IPS_GetPresentation')) {
|
||||
try {
|
||||
$presentation = @IPS_GetPresentation($varId);
|
||||
if (is_array($presentation)) {
|
||||
if (isset($presentation['Suffix']) && trim((string)$presentation['Suffix']) !== '') {
|
||||
return trim((string)$presentation['Suffix']);
|
||||
}
|
||||
if (isset($presentation['Prefix']) && trim((string)$presentation['Prefix']) !== '') {
|
||||
return trim((string)$presentation['Prefix']);
|
||||
}
|
||||
if (isset($presentation['Unit']) && trim((string)$presentation['Unit']) !== '') {
|
||||
return trim((string)$presentation['Unit']);
|
||||
}
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
}
|
||||
}
|
||||
|
||||
$profileName = '';
|
||||
if (isset($var['VariableCustomProfile']) && $var['VariableCustomProfile'] !== '') {
|
||||
$profileName = $var['VariableCustomProfile'];
|
||||
} elseif (isset($var['VariableProfile']) && $var['VariableProfile'] !== '') {
|
||||
$profileName = $var['VariableProfile'];
|
||||
}
|
||||
|
||||
if ($profileName !== '' && IPS_VariableProfileExists($profileName)) {
|
||||
$profile = IPS_GetVariableProfile($profileName);
|
||||
$suffix = trim((string)$profile['Suffix']);
|
||||
$prefix = trim((string)$profile['Prefix']);
|
||||
$unit = trim($prefix . ' ' . $suffix);
|
||||
if ($unit !== '') {
|
||||
return $unit;
|
||||
}
|
||||
}
|
||||
|
||||
$formatted = GetValueFormatted($varId);
|
||||
return $this->extractUnitFromFormattedValue($formatted, $value);
|
||||
}
|
||||
|
||||
private function extractUnitFromFormattedValue(string $formatted, float $value): string
|
||||
{
|
||||
$formatted = trim($formatted);
|
||||
if ($formatted === '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
$search = [
|
||||
number_format($value, 0, ',', '.'),
|
||||
number_format($value, 1, ',', '.'),
|
||||
number_format($value, 2, ',', '.'),
|
||||
number_format($value, 3, ',', '.'),
|
||||
str_replace('.', ',', (string)$value),
|
||||
str_replace(',', '.', (string)$value),
|
||||
(string)$value
|
||||
];
|
||||
|
||||
$unit = $formatted;
|
||||
foreach ($search as $needle) {
|
||||
if ($needle !== '') {
|
||||
$unit = str_replace($needle, '', $unit);
|
||||
}
|
||||
}
|
||||
|
||||
$unit = trim($unit);
|
||||
$unit = preg_replace('/^[\-\+\d\.,\s]+/u', '', $unit);
|
||||
return trim($unit);
|
||||
}
|
||||
|
||||
private function DetectCounterType(array $counterData, string $context): string
|
||||
{
|
||||
$unit = isset($counterData['unit']) ? $this->normalizeUnit((string)$counterData['unit']) : '';
|
||||
$ctx = mb_strtolower($context);
|
||||
|
||||
if (isset($counterData['voltage_value']) || isset($counterData['current_value']) || isset($counterData['frequency_value']) || isset($counterData['power_factor'])) {
|
||||
return 'electricity';
|
||||
}
|
||||
|
||||
if (isset($counterData['temperature_in_value']) || isset($counterData['temperature_out_value'])) {
|
||||
if (strpos($ctx, 'kalt') !== false || strpos($ctx, 'cool') !== false || strpos($ctx, 'kaelte') !== false || strpos($ctx, 'kälte') !== false) {
|
||||
return 'cooling';
|
||||
}
|
||||
return 'heat';
|
||||
}
|
||||
|
||||
if ($unit === 'm3' || $unit === 'l') {
|
||||
if (strpos($ctx, 'gas') !== false) {
|
||||
return 'gas';
|
||||
}
|
||||
return 'water';
|
||||
}
|
||||
|
||||
if ($unit === 'kwh' || $unit === 'kw/h' || $unit === 'mwh' || $unit === 'wh') {
|
||||
if (isset($counterData['flow_value']) || strpos($ctx, 'waerme') !== false || strpos($ctx, 'wärme') !== false || strpos($ctx, 'warmwasser') !== false || strpos($ctx, 'heizung') !== false) {
|
||||
return 'heat';
|
||||
}
|
||||
return 'electricity';
|
||||
}
|
||||
|
||||
if (strpos($ctx, 'gas') !== false) {
|
||||
return 'gas';
|
||||
}
|
||||
|
||||
return 'other';
|
||||
}
|
||||
|
||||
private function inferDefaultUnit(array $counterData): string
|
||||
{
|
||||
if (isset($counterData['total_value'])) {
|
||||
if ($counterData['type'] === 'water' || $counterData['type'] === 'gas') {
|
||||
return 'm³';
|
||||
}
|
||||
return 'kWh';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
private function isTotalUnit(string $unitNorm, string $context): bool
|
||||
{
|
||||
if (in_array($unitNorm, ['kwh', 'wh', 'mwh', 'm3', 'l', 'kw/h', 'w/h', 'mw/h'], true)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (strpos($context, 'energy') !== false && in_array($unitNorm, ['kw', 'w', 'mw'], true)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (strpos($context, 'volume') !== false && in_array($unitNorm, ['m3', 'l'], true)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function isPowerUnit(string $unitNorm, string $context): bool
|
||||
{
|
||||
if (in_array($unitNorm, ['kw', 'w', 'mw'], true)) {
|
||||
if (strpos($context, 'energy') !== false) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function isFlowUnit(string $unitNorm, string $context): bool
|
||||
{
|
||||
if (in_array($unitNorm, ['m3/h', 'l/h', 'l/min'], true)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (strpos($context, 'flow') !== false && in_array($unitNorm, ['m3', 'l'], true)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function formatOutputUnit(string $unitNorm): string
|
||||
{
|
||||
if ($unitNorm === 'm3') {
|
||||
return 'm³';
|
||||
}
|
||||
if ($unitNorm === 'kwh') {
|
||||
return 'kWh';
|
||||
}
|
||||
if ($unitNorm === 'kw/h') {
|
||||
return 'kW/h';
|
||||
}
|
||||
return $unitNorm;
|
||||
}
|
||||
|
||||
private function looksLikeIn(string $name): bool
|
||||
{
|
||||
$name = mb_strtolower($name);
|
||||
|
||||
return strpos($name, 'vorlauf') !== false
|
||||
|| strpos($name, 'vl') !== false
|
||||
|| strpos($name, 'flow') !== false
|
||||
|| strpos($name, 'ein') !== false
|
||||
|| strpos($name, 'iv') !== false
|
||||
|| strpos($name, 'inlet') !== false;
|
||||
}
|
||||
|
||||
private function looksLikeOut(string $name): bool
|
||||
{
|
||||
$name = mb_strtolower($name);
|
||||
|
||||
return strpos($name, 'ruecklauf') !== false
|
||||
|| strpos($name, 'rücklauf') !== false
|
||||
|| strpos($name, 'rl') !== false
|
||||
|| strpos($name, 'return') !== false
|
||||
|| strpos($name, 'aus') !== false
|
||||
|| strpos($name, 'ri') !== false
|
||||
|| strpos($name, 'outlet') !== false;
|
||||
}
|
||||
|
||||
private function normalizeUnit(string $unit): string
|
||||
{
|
||||
$unit = mb_strtolower(trim($unit));
|
||||
$unit = str_replace(["\xc2\xa0", ' '], '', $unit);
|
||||
$unit = str_replace(['m³', '㎥'], 'm3', $unit);
|
||||
return $unit;
|
||||
}
|
||||
|
||||
private function makeSlug(string $text): string
|
||||
{
|
||||
$text = mb_strtolower($text);
|
||||
$text = str_replace(['ä', 'ö', 'ü', 'ß'], ['ae', 'oe', 'ue', 'ss'], $text);
|
||||
$text = preg_replace('/[^a-z0-9]+/u', '_', $text);
|
||||
$text = trim($text, '_');
|
||||
|
||||
if ($text === '') {
|
||||
$text = 'counter_' . time();
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
public function MqttPublish($server_id, $topic, $payload, $retain)
|
||||
{
|
||||
if (!IPS_InstanceExists($server_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$ips_var_type = 3;
|
||||
$module_id = '{01C00ADD-D04E-452E-B66A-D253278743FE}';
|
||||
$ident = 'TempMQTTDevice_' . $this->InstanceID;
|
||||
|
||||
if (!IPS_SemaphoreEnter($ident, 100)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
$id = @IPS_GetObjectIDByIdent($ident, $this->InstanceID);
|
||||
if ($id === false) {
|
||||
$id = @IPS_CreateInstance($module_id);
|
||||
if ($id === false) {
|
||||
return false;
|
||||
}
|
||||
IPS_SetParent($id, $this->InstanceID);
|
||||
IPS_SetIdent($id, $ident);
|
||||
}
|
||||
|
||||
if (!IPS_IsInstanceCompatible($id, $server_id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$inst_config = IPS_GetInstance($id);
|
||||
if ((int)$inst_config['ConnectionID'] !== (int)$server_id) {
|
||||
IPS_DisconnectInstance($id);
|
||||
if (!@IPS_ConnectInstance($id, $server_id)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
IPS_SetName($id, 'Temporary MQTT Device for: ' . $topic);
|
||||
|
||||
$config_arr = [
|
||||
'Retain' => $retain,
|
||||
'Topic' => $topic,
|
||||
'Type' => $ips_var_type
|
||||
];
|
||||
|
||||
IPS_SetConfiguration($id, json_encode($config_arr));
|
||||
IPS_SetHidden($id, true);
|
||||
IPS_ApplyChanges($id);
|
||||
|
||||
$var_id = @IPS_GetObjectIDByIdent('Value', $id);
|
||||
if ($var_id === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RequestAction($var_id, $payload);
|
||||
} finally {
|
||||
IPS_SemaphoreLeave($ident);
|
||||
}
|
||||
|
||||
return true;
|
||||
return str_replace(
|
||||
['\\', "'", '"'],
|
||||
['\\\\', "\\'", '\\"'],
|
||||
$v
|
||||
);
|
||||
}
|
||||
}
|
||||
?>
|
||||
Reference in New Issue
Block a user