62 lines
2.2 KiB
PHP
62 lines
2.2 KiB
PHP
<?php
|
|
|
|
namespace App\Support\Mqtt;
|
|
|
|
/**
|
|
* Normalizes a ring-mqtt state payload into protocol-agnostic entity updates
|
|
* ({key, type, state}), the same shape the Shelly path produces. Vendor specifics stay here (H3).
|
|
*
|
|
* Covers the common Ring doorbell/camera signals (ding, motion, battery, contact, lock). The
|
|
* bridge sends plain "ON"/"OFF"/"open"/"closed" for binary sensors and JSON for the info topic.
|
|
*/
|
|
class RingNormalizer
|
|
{
|
|
/**
|
|
* @return array<int, array{key:string,type:string,state:array<string,mixed>}>
|
|
*/
|
|
public static function normalize(string $entity, string $rawPayload): array
|
|
{
|
|
return match ($entity) {
|
|
'ding' => [['key' => 'ding', 'type' => 'ding', 'state' => ['on' => self::isOn($rawPayload)]]],
|
|
'motion' => [['key' => 'motion', 'type' => 'motion', 'state' => ['on' => self::isOn($rawPayload)]]],
|
|
'contact', 'contactSensor', 'contact_sensor' => [['key' => 'contact', 'type' => 'contact', 'state' => ['open' => self::isOpen($rawPayload)]]],
|
|
'lock' => [['key' => 'lock', 'type' => 'lock', 'state' => ['locked' => self::isLocked($rawPayload)]]],
|
|
'info' => self::fromInfo($rawPayload),
|
|
default => [],
|
|
};
|
|
}
|
|
|
|
/** The info topic carries a JSON blob with battery/signal attributes. */
|
|
private static function fromInfo(string $rawPayload): array
|
|
{
|
|
$data = json_decode($rawPayload, true);
|
|
if (! is_array($data)) {
|
|
return [];
|
|
}
|
|
|
|
$updates = [];
|
|
|
|
$battery = $data['batteryLevel'] ?? $data['battery_level'] ?? null;
|
|
if ($battery !== null && is_numeric($battery)) {
|
|
$updates[] = ['key' => 'battery', 'type' => 'battery', 'state' => ['percent' => (int) $battery]];
|
|
}
|
|
|
|
return $updates;
|
|
}
|
|
|
|
private static function isOn(string $payload): bool
|
|
{
|
|
return in_array(strtoupper(trim($payload)), ['ON', 'TRUE', '1'], true);
|
|
}
|
|
|
|
private static function isOpen(string $payload): bool
|
|
{
|
|
return in_array(strtolower(trim($payload)), ['open', 'on', 'true', '1'], true);
|
|
}
|
|
|
|
private static function isLocked(string $payload): bool
|
|
{
|
|
return strtolower(trim($payload)) === 'locked';
|
|
}
|
|
}
|