camera - (real) remote control, brandschutz - configurable course, dashboard - vbb licensed API (a real vbb license, how cool)
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
const CAMERA_REMOTE_ACTIONS = [
|
||||
'power' => ['entity_id' => 'script.kamera_on_off', 'calls' => 1],
|
||||
'total' => ['entity_id' => 'script.kamera_totale', 'calls' => 2],
|
||||
'lectern' => ['entity_id' => 'script.kamera_pult', 'calls' => 2],
|
||||
'altar' => ['entity_id' => 'script.kamera_altar', 'calls' => 2],
|
||||
'chancel' => ['entity_id' => 'script.kamera_altarraum', 'calls' => 2],
|
||||
'before_altar' => ['entity_id' => 'script.kamera_vor_dem_altar', 'calls' => 2],
|
||||
'flowers' => ['entity_id' => 'script.kamera_blumenschmuck', 'calls' => 2],
|
||||
'choir' => ['entity_id' => 'script.kamera_chor', 'calls' => 2],
|
||||
'piano' => ['entity_id' => 'script.kamera_klavier', 'calls' => 2],
|
||||
'organ' => ['entity_id' => 'script.kamera_orgel', 'calls' => 2],
|
||||
'orchestra' => ['entity_id' => 'script.kamera_orchester_kinderchor', 'calls' => 2],
|
||||
];
|
||||
|
||||
function camera_remote_is_authorized(array $groups): bool
|
||||
{
|
||||
return !empty($groups['Technik']) || !empty($groups['Admin']);
|
||||
}
|
||||
|
||||
function camera_remote_csrf_token(): string
|
||||
{
|
||||
return $_SESSION['camera_remote_csrf_token'] ??= bin2hex(random_bytes(32));
|
||||
}
|
||||
|
||||
function camera_remote_verify_csrf(mixed $token): void
|
||||
{
|
||||
$sessionToken = $_SESSION['camera_remote_csrf_token'] ?? '';
|
||||
if (!is_string($token) || !is_string($sessionToken) || $sessionToken === '' || !hash_equals($sessionToken, $token)) {
|
||||
throw new InvalidArgumentException('Ungültige Anfrage. Bitte laden Sie die Seite neu.');
|
||||
}
|
||||
}
|
||||
|
||||
/** @return array{base_url: string, token: string} */
|
||||
function camera_remote_config(): array
|
||||
{
|
||||
$baseUrl = rtrim(trim((string) getenv('HA_BASE_URL')), '/');
|
||||
$token = trim((string) getenv('HA_TOKEN'));
|
||||
$scheme = strtolower((string) parse_url($baseUrl, PHP_URL_SCHEME));
|
||||
$host = parse_url($baseUrl, PHP_URL_HOST);
|
||||
|
||||
if ($baseUrl === '' || $token === '') {
|
||||
throw new RuntimeException('Home Assistant ist noch nicht konfiguriert.');
|
||||
}
|
||||
if (!in_array($scheme, ['http', 'https'], true) || !is_string($host) || $host === '') {
|
||||
throw new RuntimeException('Die Home-Assistant-Adresse ist ungültig.');
|
||||
}
|
||||
|
||||
return ['base_url' => $baseUrl, 'token' => $token];
|
||||
}
|
||||
|
||||
function camera_remote_is_configured(): bool
|
||||
{
|
||||
try {
|
||||
camera_remote_config();
|
||||
return true;
|
||||
} catch (RuntimeException) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function camera_remote_request(string $path, ?array $payload = null): void
|
||||
{
|
||||
$config = camera_remote_config();
|
||||
$handle = curl_init($config['base_url'] . $path);
|
||||
if ($handle === false) {
|
||||
throw new RuntimeException('Die Verbindung zu Home Assistant konnte nicht vorbereitet werden.');
|
||||
}
|
||||
|
||||
$options = [
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_HTTPHEADER => [
|
||||
'Authorization: Bearer ' . $config['token'],
|
||||
'Content-Type: application/json',
|
||||
'Accept: application/json',
|
||||
],
|
||||
CURLOPT_CONNECTTIMEOUT => 3,
|
||||
CURLOPT_TIMEOUT => 8,
|
||||
CURLOPT_FOLLOWLOCATION => false,
|
||||
];
|
||||
if ($payload !== null) {
|
||||
$options[CURLOPT_POST] = true;
|
||||
$options[CURLOPT_POSTFIELDS] = json_encode($payload, JSON_THROW_ON_ERROR);
|
||||
}
|
||||
curl_setopt_array($handle, $options);
|
||||
|
||||
try {
|
||||
$response = curl_exec($handle);
|
||||
$status = (int) curl_getinfo($handle, CURLINFO_HTTP_CODE);
|
||||
$error = curl_error($handle);
|
||||
} finally {
|
||||
curl_close($handle);
|
||||
}
|
||||
|
||||
if ($response === false || $status < 200 || $status >= 300) {
|
||||
error_log('Camera Remote: Home Assistant antwortete mit ' . ($error !== '' ? $error : 'HTTP ' . $status));
|
||||
throw new RuntimeException('Home Assistant konnte den Kamerabefehl nicht ausführen.');
|
||||
}
|
||||
|
||||
try {
|
||||
json_decode($response, true, 512, JSON_THROW_ON_ERROR);
|
||||
} catch (JsonException $exception) {
|
||||
throw new RuntimeException('Home Assistant hat unerwartet geantwortet.', 0, $exception);
|
||||
}
|
||||
}
|
||||
|
||||
function camera_remote_run(string $action): void
|
||||
{
|
||||
$command = CAMERA_REMOTE_ACTIONS[$action] ?? null;
|
||||
if (!is_array($command)) {
|
||||
throw new InvalidArgumentException('Unbekannter Kamerabefehl.');
|
||||
}
|
||||
|
||||
for ($call = 0; $call < $command['calls']; $call++) {
|
||||
camera_remote_request('/api/services/script/turn_on', ['entity_id' => $command['entity_id']]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user