77 lines
2.4 KiB
PHP
77 lines
2.4 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\Command;
|
|
use App\Models\Device;
|
|
use App\Models\Entity;
|
|
use App\Support\Drivers\DeviceDriver;
|
|
use App\Support\Drivers\ShellyMqttDriver;
|
|
use Illuminate\Support\Facades\Auth;
|
|
|
|
/**
|
|
* The one path from UI/automations to a device (H1). Resolves the driver, executes the
|
|
* command and writes an audit row to `commands` — always, success or failure.
|
|
*/
|
|
class DeviceCommandService
|
|
{
|
|
public function toggle(Entity $entity, string $source = 'user'): Command
|
|
{
|
|
$current = (bool) data_get($entity->state?->state, 'on', false);
|
|
|
|
return $this->setOn($entity, ! $current, $source);
|
|
}
|
|
|
|
public function setOn(Entity $entity, bool $on, string $source = 'user'): Command
|
|
{
|
|
return $this->run(
|
|
$entity->device,
|
|
$entity,
|
|
$on ? 'turn_on' : 'turn_off',
|
|
['on' => $on],
|
|
$source,
|
|
fn (DeviceDriver $driver) => $on ? $driver->turnOn($entity) : $driver->turnOff($entity),
|
|
);
|
|
}
|
|
|
|
public function reboot(Device $device, string $source = 'user'): Command
|
|
{
|
|
return $this->run($device, null, 'reboot', [], $source, fn (DeviceDriver $driver) => $driver->reboot($device));
|
|
}
|
|
|
|
public function setLight(Entity $entity, array $params, string $source = 'user'): Command
|
|
{
|
|
return $this->run($entity->device, $entity, 'set_light', $params, $source, fn (DeviceDriver $driver) => $driver->setLight($entity, $params));
|
|
}
|
|
|
|
private function run(Device $device, ?Entity $entity, string $command, array $payload, string $source, callable $action): Command
|
|
{
|
|
$result = 'ok';
|
|
|
|
try {
|
|
$action($this->driverFor($device));
|
|
} catch (\Throwable $e) {
|
|
report($e);
|
|
$result = 'error: '.$e->getMessage();
|
|
}
|
|
|
|
return Command::create([
|
|
'device_id' => $device->id,
|
|
'entity_id' => $entity?->id,
|
|
'source' => $source,
|
|
'user_id' => Auth::id(),
|
|
'command' => $command,
|
|
'payload' => $payload,
|
|
'result' => $result,
|
|
]);
|
|
}
|
|
|
|
private function driverFor(Device $device): DeviceDriver
|
|
{
|
|
return match (true) {
|
|
$device->vendor === 'Shelly' && $device->protocol === 'mqtt' => app(ShellyMqttDriver::class),
|
|
default => throw new \RuntimeException("No driver for {$device->vendor}/{$device->protocol}."),
|
|
};
|
|
}
|
|
}
|