diff --git a/Layout/default/menu.php b/Layout/default/menu.php
index 01426c782..89b64c5fe 100644
--- a/Layout/default/menu.php
+++ b/Layout/default/menu.php
@@ -130,6 +130,7 @@
isAdmin() || $me->can("Cpeshipping")): ?>
"> CPE Versand
isAdmin()) : ?>"> Domains
isAdmin()) : ?>"> IPAM
+ isAdmin()) : ?>"> Device Congestion
diff --git a/application/DeviceMonitoring/DeviceMonitoring.php b/application/DeviceMonitoring/DeviceMonitoring.php
new file mode 100644
index 000000000..453aacd12
--- /dev/null
+++ b/application/DeviceMonitoring/DeviceMonitoring.php
@@ -0,0 +1,9 @@
+loadMe();
+ $this->layout()->set("me", $me);
+ $this->me = $me;
+
+ if (!$this->me->isAdmin()) {
+ $this->redirect("dashboard");
+ }
+
+ $this->zabbix = new Zabbix($this->ZABBIX_API_URL, $this->ZABBIX_API_KEY);
+
+ }
+
+ protected function congestionAction() {
+ $congestionData = $this->getCongestionData();
+
+ Helper::renderVue($this, "DeviceMonitoringCongestion", $this->mod,
+ ["CONGESTION_DATA" => $congestionData]);
+ }
+
+ public function getCongestionData(): array {
+ $filename = TEMP_DIR . "/DeviceMonitoring/interfacesWithCongestion.json";
+
+ // if file is older than 50 minutes, fetch new data
+ if (file_exists($filename) && (time() - filemtime($filename)) < 3000) {
+ $interfacesWithCongestion = json_decode(file_get_contents($filename), true);
+ $fileCreateTime = date("Y-m-d H:i:s", filemtime($filename));
+
+ return ["interfacesWithCongestion" => $interfacesWithCongestion, "fileCreateTime" => $fileCreateTime];
+ }
+
+ $congestionInterfaces = $this->zabbix->getAllCongestionInterfaces();
+
+ $interfacesWithCongestion = [];
+
+ $fetchedHosts = [];
+
+ foreach ($congestionInterfaces as $interface) {
+ $itemId = $interface['itemid'];
+ $name = $interface['name'];
+ $name = str_replace(": Congestion Packets", "", $name);
+ $hostId = $interface['hostid'];
+
+ $values = $this->zabbix->getItemValues($itemId);
+
+ $highestValue = 0;
+ $highestValueTime = 0;
+ foreach ($values as $value) {
+ if ($value['value'] > $highestValue) {
+ $highestValue = $value['value'];
+ $highestValueTime = $value['clock'];
+ }
+ }
+
+ // if highest value is 0, then there is no congestion
+ if ($highestValue == 0) {
+ continue;
+ }
+
+ if (in_array($hostId, $fetchedHosts)) {
+ $host = $fetchedHosts[$hostId];
+ } else {
+ $host = $this->zabbix->getHostById($hostId);
+ $fetchedHosts[$hostId] = $host;
+ }
+
+ $hostname = $host[0]['name'];
+ $ip = $host[0]['host'];
+
+
+ $interfacesWithCongestion[] = [
+ "hostname" => $hostname,
+ "ip" => $ip,
+ "name" => $name,
+ "zabbixUrl" => ZABBIX_URL . "/zabbix.php?action=latest.view&hostids%5B%5D=" . $hostId,
+ "grafanaUrl" => GRAFANA_URL . "/d/Ta3PtRWZk/mikrotik-dashboard?orgId=1&var-host=" . $hostname,
+ "highestValue" => $highestValue,
+ "highestValueTime" => $highestValueTime
+ ];
+ }
+
+ if (!file_exists(TEMP_DIR . "/DeviceMonitoring")) {
+ mkdir(TEMP_DIR . "/DeviceMonitoring");
+ }
+
+ file_put_contents($filename, json_encode($interfacesWithCongestion));
+ return ["interfacesWithCongestion" => $interfacesWithCongestion, "fileCreateTime" => date("Y-m-d H:i:s")];
+ }
+
+
+ protected function indexAction(): void {
+ $JSGlobals = ["BASE_URL" => self::getUrl("VoiceCallActive"),
+ "DASHBOARD_URL" => self::getUrl("Dashboard"),
+ "MFAPPNAME" => MFAPPNAME_SLUG,
+ "PAGE_TITLE" => "Active Voice Calls",
+ "PATH" => [
+ ["text" => MFAPPNAME_SLUG, "href" => self::getUrl("Dashboard")],
+ ["text" => "Active Voice Calls", "href" => self::getUrl("VoiceCallActive")]
+ ],
+ "VOICE_CALL_ACTIVE_API_URL" => self::getUrl("VoiceCallActive/api"),
+ ];
+
+ $this->layout()->set("additionalCSS", ["css/views/VoiceCallActive.css"]);
+ $this->layout()->set("vueViewName", "VoiceCallActive");
+ $this->layout()->set("JSGlobals", $JSGlobals);
+ $this->layout()->setTemplate("VueViews/Vue");
+ }
+
+ protected function apiAction() {
+ $do = $this->request->do;
+
+ if (!$this->me->isAdmin()) {
+ $this->redirect("dashboard");
+ }
+
+ switch ($do) {
+ case "getActiveCalls":
+ $return = $this->getActiveCalls();
+ break;
+ default:
+ $return = false;
+ break;
+ }
+
+ if (!$return) {
+ $return = [
+ "status" => "error",
+ "message" => "Invalid request."
+ ];
+ }
+
+ die(json_encode($return));
+ }
+
+ private function getActiveCalls(): array {
+ $activeCalls = $this->kolmisoftMore->getActiveCalls();
+
+ return is_null($activeCalls) ? [] : (is_object($activeCalls) ? [$activeCalls] : $activeCalls);
+ }
+}
\ No newline at end of file
diff --git a/lib/Zabbix/Zabbix.php b/lib/Zabbix/Zabbix.php
new file mode 100644
index 000000000..cbe21ddc1
--- /dev/null
+++ b/lib/Zabbix/Zabbix.php
@@ -0,0 +1,97 @@
+url = $url;
+ $this->apiKey = $apiKey;
+ }
+
+ public function zabbixRequest($method, $params) {
+ $data = array(
+ 'jsonrpc' => '2.0',
+ 'method' => $method,
+ 'params' => $params,
+ 'id' => 1
+ );
+
+ $options = array(
+ 'http' => array(
+ 'header' => "Content-Type: application/json\r\n" .
+ "Authorization: Bearer " . $this->apiKey . "\r\n",
+ 'method' => 'POST',
+ 'content' => json_encode($data)
+ )
+ );
+
+ $context = stream_context_create($options);
+ $result = file_get_contents($this->url, false, $context);
+
+ return json_decode($result, true);
+ }
+
+ public function getAllCongestionInterfaces() {
+ $response = $this->zabbixRequest('item.get', array(
+ 'search' => array('name' => array("Congestion")),
+ ));
+ return $response['result'];
+ }
+
+ public function getHostById($hostId) {
+ $response = $this->zabbixRequest('host.get', array(
+ 'hostids' => $hostId
+ ));
+ return $response['result'];
+ }
+
+ public function getItemValues($itemIds) {
+ $response = $this->zabbixRequest('history.get', array(
+ 'itemids' => $itemIds,
+ 'output' => 'extend',
+ 'sortfield' => 'clock',
+ 'sortorder' => 'DESC',
+ 'limit' => 15
+ ));
+ return $response['result'];
+ }
+
+ public function getHosts($hostname) {
+ $response = $this->zabbixRequest('host.get', array(
+ 'search' => array('name' => array($hostname))
+ ));
+ return $response['result'];
+ }
+
+ public function getInterfaceItems($hostId, $interfaceName) {
+ $response = $this->zabbixRequest('item.get', array(
+ 'hostids' => $hostId,
+ 'search' => array('name' => array($interfaceName, "Bits"))
+ ));
+ return $response['result'];
+ }
+
+ public function getUptimeItems($hostId) {
+ $response = $this->zabbixRequest('item.get', array(
+ 'hostids' => $hostId,
+ 'search' => array('name' => array("Uptime"))
+ ));
+ return $response['result'];
+ }
+
+ public function getHostInterfaces($hostIds) {
+ $response = $this->zabbixRequest('hostinterface.get', array('hostids' => $hostIds));
+ return $response['result'];
+ }
+
+ public function createTask($itemid) {
+ $response = $this->zabbixRequest('task.create', array(
+ 'type' => 6,
+ 'request' => array(
+ 'itemid' => $itemid
+ )
+ ));
+ return $response['result'];
+ }
+}
diff --git a/public/js/pages/DeviceMonitoringCongestion/DeviceMonitoringCongestion.js b/public/js/pages/DeviceMonitoringCongestion/DeviceMonitoringCongestion.js
new file mode 100644
index 000000000..0a2d83b09
--- /dev/null
+++ b/public/js/pages/DeviceMonitoringCongestion/DeviceMonitoringCongestion.js
@@ -0,0 +1,41 @@
+Vue.component('device-monitoring-congestion', {
+ //language=Vue
+ template: `
+
+
+
+ Letzte Abfragezeit: {{ window.moment.utc(window['TT_CONFIG']['CONGESTION_DATA']['fileCreateTime']).add(1, 'hours').format('DD.MM.YYYY HH:mm:ss') }}
+
+
+
+
+
+
+
+
+
+ {{ window.moment.unix(row.highestValueTime).format('DD.MM.YYYY HH:mm:ss') }}
+
+
+
+
+ `,
+ data() {
+ return {
+ window: window,
+ DeviceTableConfig: {
+ key: 'DeviceMonitoringCongestion',
+ tableHeader: 'Device Monitoring - Congestion',
+ defaultPageSize: 25,
+ headers: [
+ {text: 'Hostname', key: 'hostname', sortable: true, class: 'text-nowrap'},
+ {text: 'IP-Adresse', key: 'ip', filter: 'search', class: 'text-center'},
+ {text: 'Name', key: 'name', filter: 'search', class: 'text-center'},
+ {text: 'Höchster Wert', key: 'highestValue', filter: 'search', class: 'text-center'},
+ {text: 'Zeit', key: 'highestValueTime', filter: 'search', class: 'text-center'},
+ {text: 'Aktionen', key: 'actions', class: 'text-center', sortable: false, filter: false, priority: 9},
+ ],
+ },
+ }
+ }
+})
\ No newline at end of file
diff --git a/scripts/monitoring/run-device-congestion-cache.php b/scripts/monitoring/run-device-congestion-cache.php
new file mode 100644
index 000000000..f51c54941
--- /dev/null
+++ b/scripts/monitoring/run-device-congestion-cache.php
@@ -0,0 +1,21 @@
+#!/usr/bin/php
+id);
+define("INTERNAL_USER_USERNAME", $me->username);
+
+$DeviceMonitoringController = new DeviceMonitoringController(false);
+
+$DeviceMonitoringController->getCongestionData();
\ No newline at end of file