raspberrydisplay v2 init

This commit is contained in:
Luca Haid
2026-02-03 15:38:55 +01:00
parent 10ecfab41d
commit 0cdb2140a9
7 changed files with 2065 additions and 341 deletions

View File

@@ -1,11 +1,6 @@
<?php
use phpseclib3\Net\SSH2;
class RaspberryDisplayController extends mfBaseController {
private int $port = 22;
private string $username = XINON_RASPBERRY_DISPLAY_SSH_USER;
private string $password = XINON_RASPBERRY_DISPLAY_SSH_PASS;
protected function init(): void {
$me = new User();
@@ -15,161 +10,237 @@ class RaspberryDisplayController extends mfBaseController {
}
protected function apiAction() {
$do = $this->request->do;
if ($do !== "getConfig" && !$this->me->is("employee")) {
$this->redirect("dashboard");
if (!$this->me->is("employee")) {
$this->returnJson(["status" => "error", "message" => "Unauthorized"]);
return;
}
switch ($do) {
case "getDisplays":
$return = $this->getDisplaysApi();
break;
case "change":
$return = $this->change();
break;
case "reboot":
$return = $this->restartRaspberryPi($this->request->displayID);
break;
case "rebootAll":
$return = $this->restartAllRaspberryPis();
break;
case "getConfig":
$return = $this->getConfig();
break;
case "displayPower":
$return = $this->displayPower();
break;
default:
$return = false;
break;
$return = match($this->request->do) {
"getDisplays" => $this->getDisplaysApi(),
"getGroups" => RaspberryDisplayModel::getGroups(),
"createDisplay" => $this->createDisplayApi(),
"updateDisplay" => $this->updateDisplayApi(),
"deleteDisplay" => RaspberryDisplayModel::delete((int)$this->request->id),
"updateOrder" => $this->updateOrderApi(),
"discoverPi" => $this->discoverPiApi(),
"getStatus" => $this->getStatusApi(),
"getBatchStatus" => $this->getBatchStatusApi(),
"setUrl" => $this->setUrlApi(),
"refreshDisplay" => $this->refreshDisplayApi(),
"cecPower" => $this->cecPowerApi(),
"rebootPi" => $this->rebootPiApi(),
"refreshAll" => $this->refreshAllApi(),
"powerAll" => $this->powerAllApi(),
"rebootAll" => $this->rebootAllApi(),
default => null
};
if ($return === null) {
$this->returnJson(["status" => "error", "message" => "Unknown action"]);
} elseif ($return === true) {
$this->returnJson(["status" => "success"]);
} elseif ($return === false) {
$this->returnJson(["status" => "error", "message" => "Operation failed"]);
} else {
$this->returnJson(["status" => "OK", "result" => $return]);
}
$data = [];
if ($return === true) {
$data = ["status" => "success"];
$this->returnJson($data);
}
if (!is_array($return) || !count($return)) {
$data = ["status" => "error"];
$this->returnJson($data);
}
$data['status'] = "OK";
$data['result'] = $return;
$this->returnJson($data);
}
protected function getDisplaysApi(): array {
$displays = RaspberryDisplayModel::getAll();
$result = [];
foreach ($displays as $display) {
$result[] = ["display_label" => $display->display_label,
$grouped = [];
foreach (RaspberryDisplayModel::getAll() as $display) {
$grouped[$display->group_name][] = [
"id" => (int)$display->id,
"display_label" => $display->display_label,
"hostname" => $display->hostname,
"ip" => $display->ip_address,
"ip_address" => $display->ip_address,
"display_url" => $display->display_url,
"auto_refresh_enabled" => $display->auto_refresh_enabled === "1",
"margin_hot_fix_enabled" => $display->margin_hot_fix_enabled === "1",
"group_name" => $display->group_name,
"group_order" => (int)$display->group_order,
"monitor_size" => $display->monitor_size,
"hdmi_port" => (int)$display->hdmi_port,
"agent_port" => (int)$display->agent_port,
"custom_style" => $display->custom_style,
"id" => $display->id,];
];
}
foreach ($grouped as &$group) {
usort($group, fn($a, $b) => $a['group_order'] <=> $b['group_order']);
}
return $grouped;
}
protected function createDisplayApi(): array|bool {
$data = [
'display_label' => $this->request->display_label ?? '',
'hostname' => $this->request->hostname ?? '',
'ip_address' => $this->request->ip_address ?? '',
'display_url' => $this->request->display_url ?? '',
'group_name' => $this->request->group_name ?? '',
'group_order' => (int)($this->request->group_order ?? 0),
'monitor_size' => $this->request->monitor_size ?? '27',
'hdmi_port' => (int)($this->request->hdmi_port ?? 0),
'agent_port' => (int)($this->request->agent_port ?? 5000),
'custom_style' => $this->request->custom_style ?? null,
];
if (empty($data['display_label']) || empty($data['ip_address']) || empty($data['group_name'])) {
return false;
}
$display = RaspberryDisplayModel::create($data);
$display->create_by = $this->me->id;
$display->create = time();
RaspberryDisplayModel::save($display);
return ['id' => $display->id];
}
protected function updateDisplayApi(): bool {
$display = RaspberryDisplayModel::get((int)$this->request->id);
if (!$display) return false;
foreach (['display_label', 'hostname', 'ip_address', 'display_url', 'group_name', 'group_order', 'monitor_size', 'hdmi_port', 'agent_port', 'custom_style'] as $field) {
if (isset($this->request->$field)) $display->$field = $this->request->$field;
}
$display->edit_by = $this->me->id;
$display->edit = time();
RaspberryDisplayModel::save($display);
return true;
}
protected function updateOrderApi(): bool {
if (!is_array($this->request->orders)) return false;
foreach ($this->request->orders as $order) {
$display = RaspberryDisplayModel::get((int)$order['id']);
if ($display) {
$display->group_name = $order['group_name'] ?? $display->group_name;
$display->group_order = (int)($order['group_order'] ?? 0);
$display->edit_by = $this->me->id;
$display->edit = time();
RaspberryDisplayModel::save($display);
}
}
return true;
}
protected function discoverPiApi(): array|bool {
$ip = $this->request->ip_address ?? '';
if (empty($ip)) return false;
$status = (new NocDisplayAgent($ip, (int)($this->request->agent_port ?? 5000)))->status();
if (!$status['success']) {
return ['online' => false, 'error' => $status['error'] ?? 'Failed to connect'];
}
return [
'online' => true,
'hostname' => $status['hostname'] ?? '',
'displays' => $status['displays'] ?? [],
'temperature_c' => $status['temperature_c'] ?? null,
'cpu_percent' => $status['cpu_percent'] ?? null,
'memory' => $status['memory'] ?? null,
];
}
protected function getStatusApi(): array|bool {
$display = RaspberryDisplayModel::get((int)$this->request->id);
if (!$display) return false;
return NocDisplayAgent::fromDisplay(['ip_address' => $display->ip_address, 'agent_port' => $display->agent_port])->status();
}
protected function getBatchStatusApi(): array {
$seen = [];
$results = [];
foreach (RaspberryDisplayModel::getAll() as $display) {
$key = "{$display->ip_address}:{$display->agent_port}";
if (isset($seen[$key])) continue;
$seen[$key] = true;
$results[$display->ip_address] = NocDisplayAgent::fromDisplay(['ip_address' => $display->ip_address, 'agent_port' => $display->agent_port])->status();
}
return $results;
}
protected function setUrlApi(): array|bool {
$display = RaspberryDisplayModel::get((int)$this->request->id);
if (!$display) return false;
$result = NocDisplayAgent::fromDisplay(['ip_address' => $display->ip_address, 'agent_port' => $display->agent_port])
->setUrl((int)$display->hdmi_port, $this->request->url ?? '');
if ($result['success'] ?? false) {
$display->display_url = $this->request->url ?? '';
$display->edit_by = $this->me->id;
$display->edit = time();
RaspberryDisplayModel::save($display);
}
return $result;
}
protected function change() {
$displayID = $this->request->displayID;
$field = $this->request->field;
$value = $this->request->value;
$value = $value === "true" ? 1 : ($value === "false" ? 0 : $value);
$display = RaspberryDisplayModel::get($displayID);
if ($display === null) {
return false;
}
$display->$field = $value;
$display->save();
return true;
protected function refreshDisplayApi(): array|bool {
$display = RaspberryDisplayModel::get((int)$this->request->id);
if (!$display) return false;
return NocDisplayAgent::fromDisplay(['ip_address' => $display->ip_address, 'agent_port' => $display->agent_port])->refresh((int)$display->hdmi_port);
}
protected function restartRaspberryPi($id) {
$display = RaspberryDisplayModel::get($id);
$ssh = new SSH2($display->ip_address, $this->port);
$ssh->login($this->username, $this->password);
$ssh->exec('sudo reboot now');
return true;
protected function cecPowerApi(): array|bool {
$display = RaspberryDisplayModel::get((int)$this->request->id);
if (!$display) return false;
$agent = NocDisplayAgent::fromDisplay(['ip_address' => $display->ip_address, 'agent_port' => $display->agent_port]);
return ($this->request->state ?? 'on') === 'on' ? $agent->cecOn((int)$display->hdmi_port) : $agent->cecOff((int)$display->hdmi_port);
}
protected function restartAllRaspberryPis() {
$displays = RaspberryDisplayModel::getAll();
$ipAddresses = [];
foreach ($displays as $display) {
if (in_array($display->ip_address, $ipAddresses)) {
continue;
}
$ipAddresses[] = $display->ip_address;
$ssh = new SSH2($display->ip_address, $this->port);
$ssh->login($this->username, $this->password);
$ssh->exec('sudo reboot now');
}
return true;
protected function rebootPiApi(): array|bool {
$display = RaspberryDisplayModel::get((int)$this->request->id);
if (!$display) return false;
return NocDisplayAgent::fromDisplay(['ip_address' => $display->ip_address, 'agent_port' => $display->agent_port])->reboot();
}
protected function getConfig() {
$hostname = $this->request->hostname;
$displays = RaspberryDisplayModel::getByHostname($hostname);
if ($displays === null) {
die("No display found for this hostname and ip:" . $hostname . " X ");
protected function refreshAllApi(): array {
$results = [];
foreach (RaspberryDisplayModel::getAll() as $display) {
$results[$display->id] = NocDisplayAgent::fromDisplay(['ip_address' => $display->ip_address, 'agent_port' => $display->agent_port])->refresh((int)$display->hdmi_port);
}
return $results;
}
return array_map(function ($display) {
return ["display_url" => $display->data->display_url,
"auto_refresh_enabled" => $display->data->auto_refresh_enabled === "1",
"margin_hot_fix_enabled" => $display->data->margin_hot_fix_enabled === "1",
"id" => $display->id,];
}, $displays);
protected function powerAllApi(): array {
$state = $this->request->state ?? 'on';
$results = [];
foreach (RaspberryDisplayModel::getAll() as $display) {
$agent = NocDisplayAgent::fromDisplay(['ip_address' => $display->ip_address, 'agent_port' => $display->agent_port]);
$results[$display->id] = $state === 'on' ? $agent->cecOn((int)$display->hdmi_port) : $agent->cecOff((int)$display->hdmi_port);
}
return $results;
}
protected function rebootAllApi(): array {
$seen = [];
$results = [];
foreach (RaspberryDisplayModel::getAll() as $display) {
$key = "{$display->ip_address}:{$display->agent_port}";
if (isset($seen[$key])) continue;
$seen[$key] = true;
$results[$display->ip_address] = NocDisplayAgent::fromDisplay(['ip_address' => $display->ip_address, 'agent_port' => $display->agent_port])->reboot();
}
return $results;
}
protected function indexAction(): void {
$JSGlobals = ["BASE_URL" => self::getUrl("RaspberryDisplay"),
"DASHBOARD_URL" => self::getUrl("Dashboard"),
"MFAPPNAME" => MFAPPNAME_SLUG,
"PAGE_TITLE" => "Raspberry Displays",
"PATH" => [
["text" => MFAPPNAME_SLUG, "href" => self::getUrl("Dashboard")],
["text" => "Raspberry Displays", "href" => self::getUrl("RaspberryDisplay")]
]
];
if (!$this->me->is("employee")) {
$this->redirect("dashboard");
return;
}
$this->layout()->set("vueViewName", "RaspberryDisplay");
$this->layout()->set("JSGlobals", $JSGlobals);
$this->layout()->set("JSGlobals", [
"BASE_URL" => self::getUrl("RaspberryDisplay"),
"DASHBOARD_URL" => self::getUrl("Dashboard"),
"MFAPPNAME" => MFAPPNAME_SLUG,
"PAGE_TITLE" => "NOC Display Manager",
"PATH" => [
["text" => MFAPPNAME_SLUG, "href" => self::getUrl("Dashboard")],
["text" => "NOC Display Manager", "href" => self::getUrl("RaspberryDisplay")]
]
]);
$this->layout()->set("additionalCSS", ["css/views/RaspberryDisplay.css"]);
$this->layout()->setTemplate("VueViews/Vue");
$this->layout()->setTemplate("VueViews/Vue3");
}
private function displayPower(): bool
{
$state = $this->request->state;
$displays = RaspberryDisplayModel::getAll();
$ipAddresses = [];
foreach ($displays as $display) {
if (in_array($display->ip_address, $ipAddresses)) {
continue;
}
$ipAddresses[] = $display->ip_address;
$ssh = new SSH2($display->ip_address, $this->port);
$ssh->login($this->username, $this->password);
if ($state === "on") {
$ssh->exec('sudo bash /root/on.sh');
} else {
$ssh->exec('sudo bash /root/off.sh');
}
}
return true;
}
}
}