137 lines
3.6 KiB
PHP
137 lines
3.6 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
final class ShellyParser
|
|
{
|
|
/**
|
|
* Extrahiert den Modellteil aus einer Shelly-RPC-Source.
|
|
*/
|
|
public static function extractType(string $source): string
|
|
{
|
|
if (preg_match('/^shelly([a-z0-9]+)-/i', trim($source), $matches) !== 1) {
|
|
return 'unknown';
|
|
}
|
|
|
|
return strtolower($matches[1]);
|
|
}
|
|
|
|
/**
|
|
* @return array{outputs: array<int, bool>, inputs: array<int, bool>, temperature: ?float}
|
|
*/
|
|
public static function mapParams(array $params): array
|
|
{
|
|
$mapped = [
|
|
'outputs' => [],
|
|
'inputs' => [],
|
|
'temperature' => null,
|
|
];
|
|
|
|
foreach ($params as $component => $value) {
|
|
if (!is_string($component) || !is_array($value)) {
|
|
continue;
|
|
}
|
|
|
|
if (preg_match('/^switch:(\d+)$/', $component, $matches) === 1) {
|
|
$index = (int) $matches[1];
|
|
$output = self::toBoolean($value['output'] ?? null);
|
|
$input = self::toBoolean($value['input'] ?? null);
|
|
|
|
if ($output !== null) {
|
|
$mapped['outputs'][$index] = $output;
|
|
}
|
|
if ($input !== null) {
|
|
$mapped['inputs'][$index] = $input;
|
|
}
|
|
}
|
|
|
|
if (preg_match('/^input:(\d+)$/', $component, $matches) === 1) {
|
|
$state = self::toBoolean($value['state'] ?? null);
|
|
if ($state !== null) {
|
|
$mapped['inputs'][(int) $matches[1]] = $state;
|
|
}
|
|
}
|
|
}
|
|
|
|
$mapped['temperature'] = self::findTemperature($params);
|
|
ksort($mapped['outputs']);
|
|
ksort($mapped['inputs']);
|
|
|
|
return $mapped;
|
|
}
|
|
|
|
public static function toBoolean($value): ?bool
|
|
{
|
|
if (is_bool($value)) {
|
|
return $value;
|
|
}
|
|
|
|
if ($value === 1 || $value === '1') {
|
|
return true;
|
|
}
|
|
if ($value === 0 || $value === '0') {
|
|
return false;
|
|
}
|
|
|
|
if (is_string($value)) {
|
|
$normalized = strtolower(trim($value));
|
|
if (in_array($normalized, ['true', 'on', 'online'], true)) {
|
|
return true;
|
|
}
|
|
if (in_array($normalized, ['false', 'off', 'offline'], true)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private static function findTemperature(array $data): ?float
|
|
{
|
|
foreach ($data as $key => $value) {
|
|
if (!is_string($key)) {
|
|
continue;
|
|
}
|
|
|
|
$lowerKey = strtolower($key);
|
|
if ($lowerKey === 'temperature') {
|
|
$temperature = self::temperatureFromValue($value);
|
|
if ($temperature !== null) {
|
|
return $temperature;
|
|
}
|
|
}
|
|
|
|
if ($lowerKey === 'tc' && is_numeric($value)) {
|
|
return (float) $value;
|
|
}
|
|
|
|
if (is_array($value)) {
|
|
$temperature = self::findTemperature($value);
|
|
if ($temperature !== null) {
|
|
return $temperature;
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private static function temperatureFromValue($value): ?float
|
|
{
|
|
if (is_numeric($value)) {
|
|
return (float) $value;
|
|
}
|
|
if (!is_array($value)) {
|
|
return null;
|
|
}
|
|
|
|
foreach (['tC', 'tc', 't'] as $key) {
|
|
if (array_key_exists($key, $value) && is_numeric($value[$key])) {
|
|
return (float) $value[$key];
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
}
|