Index: /branches/amp_4_0/platform/tools/README.md
===================================================================
--- /branches/amp_4_0/platform/tools/README.md	(revision 2705)
+++ /branches/amp_4_0/platform/tools/README.md	(working copy)
@@ -41,3 +41,5 @@
 
 sudo firewall-cmd --reload
 
+### Configure HyperTables for Device Metrics
+psql "host=localhost port=5432 dbname=amp_ts user=amp_ts_user" -v ON_ERROR_STOP=1 -f /opt/telegraf_snmp_timescale.sql 
Index: /branches/amp_4_0/platform/tools/configure_telegraf_timescale.sh
===================================================================
--- /branches/amp_4_0/platform/tools/configure_telegraf_timescale.sh	(revision 2705)
+++ /branches/amp_4_0/platform/tools/configure_telegraf_timescale.sh	(working copy)
@@ -69,6 +69,7 @@
   precision = ""
   hostname = ""
   omit_hostname = false
+  skip_processors_after_aggregators = false
 
 # === Output: TimescaleDB/PostgreSQL ===
 [[outputs.postgresql]]
@@ -82,12 +83,33 @@
   totalcpu = true
 
 [[inputs.disk]]
+  mount_points = ["/", "/home", "/var"]
   ignore_fs = ["tmpfs", "devtmpfs", "overlay", "rootfs"]
 
 [[inputs.mem]]
 
+[[inputs.diskio]]
+
+[[inputs.net]]
+
 [[inputs.system]]
   fieldinclude = ["load1", "load5", "load15", "uptime"]
+
+[[processors.starlark]]
+  source = """
+def apply(metric):
+    # Allow scalar metrics (cpu_usage, etc.)
+    if metric.name != 'ag_virtual_site_stats' and metric.name != 'ag_vpn_stats' and metric.name != 'apv_real_stats':
+        return metric
+
+    # For table metrics, require 'serverid' or 'realServerId'
+    if 'serverid' in metric.fields or 'realServerId' in metric.fields:
+        return metric
+
+    # Drop only table rows missing the key field
+    return None
+"""
+
 EOF
 
 # --- test config (outputs are skipped in test mode) ---
Index: /branches/amp_4_0/platform/tools/install_telegraf.sh
===================================================================
--- /branches/amp_4_0/platform/tools/install_telegraf.sh	(revision 2705)
+++ /branches/amp_4_0/platform/tools/install_telegraf.sh	(working copy)
@@ -29,6 +29,27 @@
 for cmd in sudo dnf grep sed; do need "$cmd"; done
 log "All required commands are present."
 
+# --- Add InfluxData Repo ---
+log "Adding InfluxData repository..."
+REPO_URL="https://repos.influxdata.com/centos/9/x86_64/stable"
+REPO_FILE="/etc/yum.repos.d/influxdata.repo"
+
+if [[ ! -f "$REPO_FILE" ]]; then
+  cat <<EOF | sudo tee "$REPO_FILE"
+[influxdata]
+name = InfluxData Repository - Stable
+baseurl = $REPO_URL
+gpgcheck = 1
+gpgkey = https://repos.influxdata.com/influxdata-archive_compat.key
+enabled = 1
+EOF
+  sudo dnf update -y
+  [[ $? -ne 0 ]] && log_error "Failed to add repo or update system." && exit 1
+  log "InfluxData repo added and system updated."
+else
+  log "InfluxData repo already exists."
+fi
+
 # --- Install Telegraf ---
 log "Installing Telegraf version $TELEGRAF_VERSION..."
 if ! sudo dnf install -y "telegraf-${TELEGRAF_VERSION}"; then
Index: /branches/amp_4_0/platform/tools/install_timescaledb.sh
===================================================================
--- /branches/amp_4_0/platform/tools/install_timescaledb.sh	(revision 2705)
+++ /branches/amp_4_0/platform/tools/install_timescaledb.sh	(working copy)
@@ -46,6 +46,7 @@
 
 log "Installing TimescaleDB CE for PostgreSQL ${PG_VERSION}…"
 dnf -y install "timescaledb-2-postgresql-${PG_VERSION}"
+dnf -y install "timescaledb-toolkit-postgresql-${PG_VERSION}"
 
 # Optional tuning tool
 dnf -y install timescaledb-tools || true
@@ -99,6 +100,7 @@
 sudo -E -u postgres "${PG_BIN_DIR}/psql" -v ON_ERROR_STOP=1 <<SQL
 \c ${NEW_DB_NAME}
 CREATE EXTENSION IF NOT EXISTS timescaledb;
+CREATE EXTENSION IF NOT EXISTS timescaledb_toolkit;
 GRANT ALL PRIVILEGES ON DATABASE ${NEW_DB_NAME} TO ${NEW_USER};
 ALTER DATABASE ${NEW_DB_NAME} OWNER TO ${NEW_USER};
 SQL
Index: /branches/amp_4_0/platform/tools/telegraf_snmp_timescale.sql
===================================================================
--- /branches/amp_4_0/platform/tools/telegraf_snmp_timescale.sql	(revision 2705)
+++ /branches/amp_4_0/platform/tools/telegraf_snmp_timescale.sql	(working copy)
@@ -55,7 +55,7 @@
 CREATE TABLE IF NOT EXISTS apv_virtual_stats (
     time TIMESTAMPTZ NOT NULL,
     agent_host TEXT NOT NULL,
-    serverid TEXT NOT NULL,
+    serverid TEXT,
     addr TEXT NOT NULL,
     port TEXT NOT NULL,
     protocol TEXT NOT NULL,
@@ -96,7 +96,7 @@
 CREATE TABLE IF NOT EXISTS apv_real_stats (
     time TIMESTAMPTZ NOT NULL,
     agent_host TEXT NOT NULL,
-    real_server_id TEXT NOT NULL,
+    real_server_id TEXT,
     addr TEXT NOT NULL,
     port TEXT NOT NULL,
     protocol TEXT NOT NULL,
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/djproject/urls.py
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/djproject/urls.py	(revision 2705)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/djproject/urls.py	(working copy)
@@ -20,6 +20,7 @@
 from hive.controller.restore_controller import handle_restore_req
 from hive.controller.utils import handle_observability_status_req
 from hive.an_opensearch import opensearch_proxy, get_opensearch_sso_token
+from hive.controller.system_metrics import handle_get_latest_system_metrics, handle_get_historical_system_metrics
 
 js_info_dict = {
     #'packages': ('your.app.package',),
@@ -104,6 +105,8 @@
     re_path(r'^UpdateFrontend$', UpdateFrontend),
     re_path(r'^upload$', upload),
     re_path(r'^register_complete$', register_complete),
+    re_path(r'^system-metrics-latest$', handle_get_latest_system_metrics),
+    re_path(r'^system-metrics-history$', handle_get_historical_system_metrics),
 ]
 
 handler404 = 'hive.shared.custom_404_view'
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/log-analysis/log-analysis.ts
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/log-analysis/log-analysis.ts	(revision 2705)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/log-analysis/log-analysis.ts	(working copy)
@@ -3,11 +3,10 @@
 import {MatTabChangeEvent} from '@angular/material/tabs';
 import {SharedModule} from '../../shared/shared-module';
 import {LogAnalysisSlbOverview} from '../sub-components/log-analysis-slb-overview/log-analysis-slb-overview';
-import {LogAnalysisSslVpnOverview} from '../sub-components/log-analysis-ssl-vpn-overview/log-analysis-ssl-vpn-overview';
 
 @Component({
   selector: 'app-log-analysis',
-  imports: [SharedModule, LogAnalysisSlbOverview, LogAnalysisSslVpnOverview],
+  imports: [SharedModule, LogAnalysisSlbOverview],
   templateUrl: './log-analysis.html',
   styleUrl: './log-analysis.scss'
 })
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/dashboard-system-insights.html
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/dashboard-system-insights.html	(revision 2705)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/dashboard-system-insights.html	(working copy)
@@ -6,10 +6,14 @@
           <mat-card-title class="card-title">Devices</mat-card-title>
         </div>
         <div class="metric-value">
-          <span class="online-count">3</span>
-          <span class="total-count">/4</span>
+          <span class="online-count">{{connectedDevices}}</span>
+          <span class="total-count">/{{devices.length}}</span>
         </div>
-        <p class="status-details">1 device(s) offline</p>
+        @if (devices.length - connectedDevices > 0) {
+          <p class="status-details">{{devices.length - connectedDevices}} device(s) offline</p>
+        } @else {
+          <p class="success-icon align-center">All devices are online.</p>
+        }
       </mat-card-content>
     </mat-card>
   </mat-grid-tile>
@@ -20,7 +24,7 @@
           <mat-card-title class="card-title">Services</mat-card-title>
         </div>
         <div class="metric-value">
-          <span class="online-count">5</span>
+          <span class="online-count">-1</span>
           <span class="total-count"></span>
         </div>
         <p class="status-details active">Active Services</p>
@@ -34,7 +38,7 @@
           <mat-card-title class="card-title">Events</mat-card-title>
         </div>
         <div class="metric-value">
-          <span class="online-count">5</span>
+          <span class="online-count">-1</span>
           <span class="total-count"></span>
         </div>
         <p class="status-details active">(last 7 days)</p>
@@ -48,7 +52,7 @@
           <mat-card-title class="card-title">Alerts</mat-card-title>
         </div>
         <div class="metric-value">
-          <span class="online-count">5</span>
+          <span class="online-count">-1</span>
           <span class="total-count"></span>
         </div>
         <p class="status-details active">(last 7 days)</p>
@@ -85,11 +89,11 @@
         <div class="card-body-content">
           <div class="metrics-horizontal-container">
             <div class="metric-item">
-              <span class="metric-value">227.26 Kbps</span>
+              <span class="metric-value">{{networkMetrics?.bytes_sent_bps | bytes}}</span>
               <span class="metric-label">Outbound</span>
             </div>
             <div class="metric-item">
-              <span class="metric-value">278.28 Kbps</span>
+              <span class="metric-value">{{networkMetrics?.bytes_recv_bps | bytes}}</span>
               <span class="metric-label">Inbound</span>
             </div>
           </div>
@@ -114,19 +118,19 @@
         <div class="chart-flex-container">
           <div class="metrics-horizontal-container">
             <div class="metric-item">
-              <span class="metric-value">25.50 GB</span>
+              <span class="metric-value">{{diskMetrics?.used_bytes | bytes}}</span>
               <span class="metric-label">Used</span>
             </div>
             <div class="metric-item">
-              <span class="metric-value">474.50 GB</span>
+              <span class="metric-value">{{diskMetrics?.free_bytes | bytes}}</span>
               <span class="metric-label">Free</span>
             </div>
             <div class="metric-item">
-              <span class="metric-value">227.26 Kbps</span>
+              <span class="metric-value">{{currentSystemMetrics?.diskio?.read_speed | bytes}}</span>
               <span class="metric-label">Read Rate</span>
             </div>
             <div class="metric-item">
-              <span class="metric-value">227.26 Kbps</span>
+              <span class="metric-value">{{currentSystemMetrics?.diskio?.write_speed | bytes}}</span>
               <span class="metric-label">Write Rate</span>
             </div>
           </div>
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/dashboard-system-insights.ts
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/dashboard-system-insights.ts	(revision 2705)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/dashboard-system-insights.ts	(working copy)
@@ -2,10 +2,25 @@
 import {SharedModule} from '../../../shared/shared-module';
 import {EChartsOption} from 'echarts';
 import {MAT_DIALOG_DATA, MatDialog, MatDialogConfig, MatDialogRef} from '@angular/material/dialog';
+import {take} from 'rxjs/operators';
+import {MatTableDataSource} from '@angular/material/table';
+import {DeviceService} from '../../../services/device-service';
+import {NotificationService} from '../../../services/notification';
+import {SystemService} from '../../../services/system-service';
+import {BytesPipe} from '../../../pipes/bytes-pipe';
 
+export interface DeviceTypeStatus {
+  connected: number;
+  disconnected: number;
+}
+
+export interface DeviceGraphData {
+  total: DeviceTypeStatus;
+  types: Map<string, DeviceTypeStatus>;
+}
 @Component({
   selector: 'app-dashboard-system-insights',
-  imports: [SharedModule],
+  imports: [SharedModule, BytesPipe],
   templateUrl: './dashboard-system-insights.html',
   styleUrl: './dashboard-system-insights.scss'
 })
@@ -17,10 +32,126 @@
   chartOption4: EChartsOption = {};
   chartOption5: EChartsOption = {};
 
+  constructor(
+    private _device: DeviceService,
+    private _system: SystemService,
+    private _notification: NotificationService,
+  ) {
+  }
+
   ngOnInit(): void {
-    this.updateChartOption();
+    this.getDeviceGroups();
+    this.getLatestSystemMetrics();
   }
 
+  devices: any[] = [];
+  groups: any[] = [];
+  connectedDevices: number = 0;
+  currentSystemMetrics: any = {};
+  diskMetrics: any = {};
+  networkMetrics: any = {};
+
+  getLatestSystemMetrics() {
+    this._system.getLatestSystemMetrics()
+      .pipe(take(1))
+      .subscribe({
+        next: (result: any) => {
+          this.currentSystemMetrics = result;
+          if (this.currentSystemMetrics?.disk_usage && this.currentSystemMetrics.disk_usage.length > 0) {
+            this.diskMetrics = this.currentSystemMetrics.disk_usage[0];
+          }
+          if (this.currentSystemMetrics?.net_metrics && this.currentSystemMetrics.net_metrics.length > 0) {
+            this.networkMetrics = this.currentSystemMetrics.net_metrics[0];
+          }
+          this.updateChartOption();
+        },
+        error: (error: { message: string; }) => {
+          console.log(error);
+          this._notification.showError(error.message);
+        }
+      });
+  }
+
+  deviceStats: any = {}
+  deviceConnectionStats: any = {}
+  getDeviceGroups(): void {
+    this.devices = [];
+    this.groups = [];
+    // ToDo: Update with actual RoleId
+    let roleId = "0"
+    let rawPayload = new FormData();
+    rawPayload.set('action', 'FilterRoleDeviceGroups');
+    rawPayload.set('options', JSON.stringify({"role_id": roleId}));
+    this._device.getDeviceGroups(rawPayload)
+      .pipe(take(1))
+      .subscribe({
+        next: (result: any) => {
+          if (result && result.length > 1) {
+            if (result[1] && 'result' in result[1]) {
+              let groups = result[1].result;
+              groups.forEach((group: any) => {
+                this.groups.push(group?.group_name);
+                group?.device_list.forEach((device: any) => {
+                  this.devices.push(device);
+                })
+              })
+              this.deviceStats =  this.getDeviceGraphData(this.devices);
+              this.deviceConnectionStats = this.transformChartData(this.deviceStats.types.entries());
+              this.connectedDevices = this.devices.filter((device: any) => device?.connection === true).length;
+            }
+          }
+        }, error: (error: { message: string; }) => {
+          console.log(error);
+          this._notification.showError(error.message);
+        }
+      })
+  }
+
+  transformChartData(deviceData: [string, { connected: number, disconnected: number }][]) {
+    const yAxisData: string[] = [];
+    const connectedData: number[] = [];
+    const disconnectedData: number[] = [];
+
+    deviceData.forEach(([type, status]) => {
+      yAxisData.push(type);
+      connectedData.push(status.connected);
+      disconnectedData.push(status.disconnected);
+    });
+
+    return { yAxisData, connectedData, disconnectedData };
+  }
+
+  getDeviceGraphData(devices: any): DeviceGraphData {
+    const totalStatus: DeviceTypeStatus = { connected: 0, disconnected: 0 };
+    const typesStatus = new Map<string, DeviceTypeStatus>();
+
+    if (!devices || devices.length === 0) {
+      return { total: totalStatus, types: typesStatus };
+    }
+
+    devices.forEach((device: any) => {
+      // Update the total counts
+      if (device.connection) {
+        totalStatus.connected++;
+      } else {
+        totalStatus.disconnected++;
+      }
+
+      // Update the per-type counts
+      if (!typesStatus.has(device.type)) {
+        typesStatus.set(device.type, { connected: 0, disconnected: 0 });
+      }
+      const status = typesStatus.get(device.type)!;
+      if (device.connection) {
+        status.connected++;
+      } else {
+        status.disconnected++;
+      }
+    });
+
+    return { total: totalStatus, types: typesStatus };
+  }
+
   ngOnChanges(changes: SimpleChanges): void {
     if (changes['cpuUsagePercentage']) {
       this.updateChartOption();
@@ -30,20 +161,20 @@
   private updateChartOption() {
     let _data: any = {
       cpu: {
-        usage: 5,
-        remaining: 95
+        usage: this.currentSystemMetrics?.cpu?.cpu_percent,
+        remaining: 100 - this.currentSystemMetrics?.cpu?.cpu_percent
       },
       memory: {
-        usage: 45,
-        remaining: 55
+        usage: this.currentSystemMetrics?.memory?.mem_percent,
+        remaining: 100 - this.currentSystemMetrics?.memory?.mem_percent
       },
       disk: {
-        usage: 5.1,
-        remaining: 94.9
+        usage: this.diskMetrics?.used_percent,
+        remaining: 100 - this.diskMetrics?.used_percent,
       },
       diskIO: {
-        usage: 10,
-        remaining: 90
+        usage: this.currentSystemMetrics?.diskio?.disk_io_percent,
+        remaining: 100 - this.currentSystemMetrics?.diskio?.disk_io_percent,
       }
     }
 
@@ -171,7 +302,7 @@
               },
             },
             {
-              value: _data?.disk?.remaining,
+              value: _data?.disk?.remaining.toFixed(2),
               name: 'Remaining',
               itemStyle: {
                 color: '#E0E0E0'
@@ -241,7 +372,7 @@
       },
       yAxis: {
         type: 'category',
-        data: ['APV', 'vAPV', 'ASF', 'vASF', 'AG', 'vxAG']
+        data: this.deviceConnectionStats?.yAxisData
       },
       series: [
         {
@@ -255,7 +386,7 @@
           emphasis: {
             focus: 'series'
           },
-          data: [3, 10, 2, 0, 3, 5]
+          data: this.deviceConnectionStats?.connectedData
         },
         {
           name: 'Disconnected',
@@ -268,7 +399,7 @@
           emphasis: {
             focus: 'series'
           },
-          data: [0, 2, 0, 0, 0, 1]
+          data: this.deviceConnectionStats?.disconnectedData
         }
       ]
     };
@@ -278,7 +409,7 @@
   dialogConfig = new MatDialogConfig();
 
   enlargeSystemLoad() {
-    this.dialogConfig.width = '50%';
+    this.dialogConfig.width = '60%';
     const dialogRef = this.dialog.open(EnlargeSystemLoad, this.dialogConfig);
     dialogRef.afterClosed().subscribe((isAdded: boolean) => {
     })
@@ -300,6 +431,7 @@
 
   enlargeSystemDevices() {
     this.dialogConfig.width = '50%';
+    this.dialogConfig.data = this.deviceStats;
     const dialogRef = this.dialog.open(EnlargeSystemDevices, this.dialogConfig);
     dialogRef.afterClosed().subscribe((isAdded: boolean) => {
     })
@@ -318,12 +450,40 @@
   readonly data = inject(MAT_DIALOG_DATA);
   readonly dialogRef = inject(MatDialogRef<EnlargeSystemLoad>);
 
+  constructor(
+    private _system: SystemService,
+    private _notification: NotificationService,
+  ) {
+  }
+
   ngOnInit() {
-    this.updateChartOptions()
+    setTimeout(()=>{
+      this.getHistoricalSystemMetrics();
+    })
+  }
+
+  cpuMetrics: any = {};
+  memoryMetrics: any = {};
+  getHistoricalSystemMetrics() {
+    this._system.getHistoricalSystemMetrics()
+      .pipe(take(1))
+      .subscribe({
+        next: (result: any) => {
+          this.cpuMetrics = result?.cpu_history;
+          this.memoryMetrics = result?.mem_history;
+          this.updateChartOptions();
+        },
+        error: (error: { message: string; }) => {
+          console.log(error);
+          this._notification.showError(error.message);
+        }
+      });
   }
 
   updateChartOptions() {
-    let _data: any = {}
+    const cpu_data_formatted = this.cpuMetrics.map((d: any) => [d.time, d.cpu_percent]);
+    const memory_data_formatted = this.memoryMetrics.map((d: any) => [d.time, d.mem_percent]);
+
     this.chartOption1 = {
       tooltip: {
         trigger: 'axis',
@@ -357,76 +517,12 @@
         {
           name: 'CPU',
           type: 'line',
-          data: [
-            ['2025-08-28 10:00:00', 25],
-            ['2025-08-28 10:01:00', 25],
-            ['2025-08-28 10:02:00', 26],
-            ['2025-08-28 10:03:00', 25],
-            ['2025-08-28 10:04:00', 26],
-            ['2025-08-28 10:05:00', 27],
-            ['2025-08-28 10:06:00', 26],
-            ['2025-08-28 10:07:00', 27],
-            ['2025-08-28 10:08:00', 28],
-            ['2025-08-28 10:09:00', 28],
-            ['2025-08-28 10:10:00', 28],
-            ['2025-08-28 10:11:00', 29],
-            ['2025-08-28 10:12:00', 29],
-            ['2025-08-28 10:13:00', 29],
-            ['2025-08-28 10:14:00', 30],
-            ['2025-08-28 10:15:00', 30],
-            ['2025-08-28 10:16:00', 31],
-            ['2025-08-28 10:17:00', 30],
-            ['2025-08-28 10:18:00', 31],
-            ['2025-08-28 10:19:00', 32],
-            ['2025-08-28 10:20:00', 31],
-            ['2025-08-28 10:21:00', 32],
-            ['2025-08-28 10:22:00', 33],
-            ['2025-08-28 10:23:00', 32],
-            ['2025-08-28 10:24:00', 35],
-            ['2025-08-28 10:25:00', 34],
-            ['2025-08-28 10:26:00', 33],
-            ['2025-08-28 10:27:00', 34],
-            ['2025-08-28 10:28:00', 35],
-            ['2025-08-28 10:29:00', 34],
-            ['2025-08-28 10:30:00', 35]
-          ]
+          data: cpu_data_formatted
         },
         {
           name: 'Memory',
           type: 'line',
-          data: [
-            ['2025-08-28 10:00:00', 18],
-            ['2025-08-28 10:01:00', 18],
-            ['2025-08-28 10:02:00', 19],
-            ['2025-08-28 10:03:00', 18],
-            ['2025-08-28 10:04:00', 19],
-            ['2025-08-28 10:05:00', 20],
-            ['2025-08-28 10:06:00', 19],
-            ['2025-08-28 10:07:00', 20],
-            ['2025-08-28 10:08:00', 21],
-            ['2025-08-28 10:09:00', 21],
-            ['2025-08-28 10:10:00', 21],
-            ['2025-08-28 10:11:00', 22],
-            ['2025-08-28 10:12:00', 22],
-            ['2025-08-28 10:13:00', 22],
-            ['2025-08-28 10:14:00', 23],
-            ['2025-08-28 10:15:00', 23],
-            ['2025-08-28 10:16:00', 24],
-            ['2025-08-28 10:17:00', 23],
-            ['2025-08-28 10:18:00', 24],
-            ['2025-08-28 10:19:00', 25],
-            ['2025-08-28 10:20:00', 24],
-            ['2025-08-28 10:21:00', 25],
-            ['2025-08-28 10:22:00', 26],
-            ['2025-08-28 10:23:00', 25],
-            ['2025-08-28 10:24:00', 26],
-            ['2025-08-28 10:25:00', 27],
-            ['2025-08-28 10:26:00', 26],
-            ['2025-08-28 10:27:00', 27],
-            ['2025-08-28 10:28:00', 28],
-            ['2025-08-28 10:29:00', 27],
-            ['2025-08-28 10:30:00', 28]
-          ]
+          data: memory_data_formatted
         }
       ]
     };
@@ -449,11 +545,40 @@
   readonly data = inject(MAT_DIALOG_DATA);
   readonly dialogRef = inject(MatDialogRef<EnlargeSystemThroughput>);
 
+  constructor(
+    private _system: SystemService,
+    private _notification: NotificationService,
+  ) {
+  }
+
   ngOnInit() {
-    this.updateChartOptions()
+    setTimeout(()=>{
+      this.getHistoricalSystemMetrics();
+    })
+  }
+
+  networkMetrics: any = {};
+  getHistoricalSystemMetrics() {
+    this._system.getHistoricalSystemMetrics()
+      .pipe(take(1))
+      .subscribe({
+        next: (result: any) => {
+          this.networkMetrics = result?.net_history;
+          this.updateChartOptions();
+        },
+        error: (error: { message: string; }) => {
+          console.log(error);
+          this._notification.showError(error.message);
+        }
+      });
   }
 
   updateChartOptions() {
+    const { unit, factor }: any = {unit: 'MB/s', factor: 1024 * 1024};
+
+    const sent_data_formatted = this.networkMetrics.map((d: any) => [d.time, d.bytes_sent_bps / factor]);
+    const received_data_formatted = this.networkMetrics.map((d: any) => [d.time, d.bytes_recv_bps / factor]);
+
     this.chartOption1 = {
       tooltip: {
         trigger: 'axis',
@@ -467,93 +592,32 @@
           });
           let tooltipContent = `Time: ${formattedTime}<br/>`;
           params.forEach((item: any) => {
-            tooltipContent += `${item.marker} ${item.seriesName}: ${item.value[1]}<br/>`;
+            tooltipContent += `${item.marker} ${item.seriesName}: ${item.value[1].toFixed(2)} ${unit}<br/>`;
           });
           return tooltipContent;
         }
       },
+      legend: {
+        data: ['Sent', 'Received']
+      },
       xAxis: {
         type: 'time',
         name: 'Time'
       },
       yAxis: {
         type: 'value',
-        name: 'Throughput'
+        name: `Bandwidth (${unit})`
       },
       series: [
         {
           name: 'Sent',
-          type: 'bar',
-          data: [
-            ['2025-08-28 10:00:00', 100],
-            ['2025-08-28 10:01:00', 105],
-            ['2025-08-28 10:02:00', 102],
-            ['2025-08-28 10:03:00', 110],
-            ['2025-08-28 10:04:00', 115],
-            ['2025-08-28 10:05:00', 112],
-            ['2025-08-28 10:06:00', 120],
-            ['2025-08-28 10:07:00', 125],
-            ['2025-08-28 10:08:00', 122],
-            ['2025-08-28 10:09:00', 130],
-            ['2025-08-28 10:10:00', 135],
-            ['2025-08-28 10:11:00', 132],
-            ['2025-08-28 10:12:00', 140],
-            ['2025-08-28 10:13:00', 145],
-            ['2025-08-28 10:14:00', 142],
-            ['2025-08-28 10:15:00', 150],
-            ['2025-08-28 10:16:00', 155],
-            ['2025-08-28 10:17:00', 152],
-            ['2025-08-28 10:18:00', 160],
-            ['2025-08-28 10:19:00', 165],
-            ['2025-08-28 10:20:00', 162],
-            ['2025-08-28 10:21:00', 170],
-            ['2025-08-28 10:22:00', 175],
-            ['2025-08-28 10:23:00', 172],
-            ['2025-08-28 10:24:00', 180],
-            ['2025-08-28 10:25:00', 185],
-            ['2025-08-28 10:26:00', 182],
-            ['2025-08-28 10:27:00', 190],
-            ['2025-08-28 10:28:00', 195],
-            ['2025-08-28 10:29:00', 192],
-            ['2025-08-28 10:30:00', 200]
-          ]
+          type: 'line',
+          data: sent_data_formatted
         },
         {
           name: 'Received',
-          type: 'bar',
-          data: [
-            ['2025-08-28 10:00:00', 90],
-            ['2025-08-28 10:01:00', 95],
-            ['2025-08-28 10:02:00', 92],
-            ['2025-08-28 10:03:00', 100],
-            ['2025-08-28 10:04:00', 105],
-            ['2025-08-28 10:05:00', 102],
-            ['2025-08-28 10:06:00', 110],
-            ['2025-08-28 10:07:00', 115],
-            ['2025-08-28 10:08:00', 112],
-            ['2025-08-28 10:09:00', 120],
-            ['2025-08-28 10:10:00', 125],
-            ['2025-08-28 10:11:00', 122],
-            ['2025-08-28 10:12:00', 130],
-            ['2025-08-28 10:13:00', 135],
-            ['2025-08-28 10:14:00', 132],
-            ['2025-08-28 10:15:00', 140],
-            ['2025-08-28 10:16:00', 145],
-            ['2025-08-28 10:17:00', 142],
-            ['2025-08-28 10:18:00', 150],
-            ['2025-08-28 10:19:00', 155],
-            ['2025-08-28 10:20:00', 152],
-            ['2025-08-28 10:21:00', 160],
-            ['2025-08-28 10:22:00', 165],
-            ['2025-08-28 10:23:00', 162],
-            ['2025-08-28 10:24:00', 170],
-            ['2025-08-28 10:25:00', 175],
-            ['2025-08-28 10:26:00', 172],
-            ['2025-08-28 10:27:00', 180],
-            ['2025-08-28 10:28:00', 185],
-            ['2025-08-28 10:29:00', 182],
-            ['2025-08-28 10:30:00', 190]
-          ]
+          type: 'line',
+          data: received_data_formatted
         }
       ]
     };
@@ -578,108 +642,72 @@
   readonly data = inject(MAT_DIALOG_DATA);
   readonly dialogRef = inject(MatDialogRef<EnlargeSystemDiskUsage>);
 
+  constructor(
+    private _system: SystemService,
+    private _notification: NotificationService,
+  ) {
+  }
+
   ngOnInit() {
-    this.updateChartOptions()
+    setTimeout(()=>{
+      this.getHistoricalSystemMetrics();
+    })
   }
 
+  diskIOMetrics: any = {};
+  getHistoricalSystemMetrics() {
+    this._system.getHistoricalSystemMetrics()
+      .pipe(take(1))
+      .subscribe({
+        next: (result: any) => {
+          this.diskIOMetrics = result?.diskio_history;
+          this.updateChartOptions();
+        },
+        error: (error: { message: string; }) => {
+          console.log(error);
+          this._notification.showError(error.message);
+        }
+      });
+  }
+
   updateChartOptions() {
-    let _data: any = {
-      disk: {
-        usage: 5.1,
-        remaining: 94.9
-      },
-      diskIO: {
-        usage: 10,
-        remaining: 90
-      }
-    }
+    const disk_io_formatted = this.diskIOMetrics.map((d: any) => [d.time, d.disk_io_percent]);
+
     this.chartOption1 = {
-      title: {
-        text: `Usage - ${_data?.disk?.usage.toFixed(1)}%`,
-        left: 'center',
-        top: '60%',
-        textStyle: {
-          fontSize: 12,
-          fontWeight: 'bold',
-          color: '#333'
+      tooltip: {
+        trigger: 'axis',
+        formatter: (params: any) => {
+          const date = new Date(params[0].value[0]);
+          const formattedTime = date.toLocaleTimeString('en-US', {
+            hour: '2-digit',
+            minute: '2-digit',
+            second: '2-digit',
+            hour12: false
+          });
+          let tooltipContent = `Time: ${formattedTime}<br/>`;
+          params.forEach((item: any) => {
+            tooltipContent += `${item.marker} ${item.seriesName}: ${item.value[1].toFixed(2)}<br/>`;
+          });
+          return tooltipContent;
         }
       },
-      tooltip: {
-        trigger: 'item',
-        formatter: '{b}: {c}%'
+      legend: {
+        data: ['Disk I/O',]
       },
-      series: [
-        {
-          type: 'pie',
-          radius: ['70%', '90%'],
-          center: ['50%', '75%'],
-          startAngle: 180,
-          endAngle: 0,
-          label: {
-            show: false
-          },
-          data: [
-            {
-              value: _data?.disk?.usage,
-              name: 'Disk Usage',
-              itemStyle: {
-                color: '#1170cf'
-              },
-            },
-            {
-              value: _data?.disk?.remaining,
-              name: 'Remaining',
-              itemStyle: {
-                color: '#E0E0E0'
-              },
-            },
-          ]
-        }
-      ]
-    };
-
-    this.chartOption2 = {
-      title: {
-        text: `I/O - ${_data?.diskIO?.usage.toFixed(1)}%`,
-        left: 'center',
-        top: '60%',
-        textStyle: {
-          fontSize: 12,
-          fontWeight: 'bold',
-          color: '#333'
-        }
+      xAxis: {
+        type: 'time',
+        name: 'Time'
       },
-      tooltip: {
-        trigger: 'item',
-        formatter: '{b}: {c}%'
+      yAxis: {
+        type: 'value',
+        name: `Percentage %`
       },
       series: [
         {
-          type: 'pie',
-          radius: ['70%', '90%'],
-          center: ['50%', '75%'],
-          startAngle: 180,
-          endAngle: 0,
-          label: {
-            show: false
-          },
-          data: [
-            {
-              value: _data?.diskIO?.usage,
-              name: 'Disk Usage',
-              itemStyle: {
-                color: '#1170cf'
-              },
-            },
-            {
-              value: _data?.diskIO?.remaining,
-              name: 'Remaining',
-              itemStyle: {
-                color: '#E0E0E0'
-              },
-            },
-          ]
-        }
+          name: 'Disk I/O',
+          type: 'line',
+          data: disk_io_formatted
+        },
       ]
     };
   }
@@ -707,18 +735,22 @@
     this.updateChartOptions()
   }
 
-  updateChartOptions() {
-    let _data: any = {
-      disk: {
-        usage: 5.1,
-        remaining: 94.9
-      },
-      diskIO: {
-        usage: 10,
-        remaining: 90
-      }
-    }
+  transformChartData(deviceData: [string, { connected: number, disconnected: number }][]) {
+    const yAxisData: string[] = [];
+    const connectedData: number[] = [];
+    const disconnectedData: number[] = [];
 
+    deviceData.forEach(([type, status]) => {
+      yAxisData.push(type);
+      connectedData.push(status.connected);
+      disconnectedData.push(status.disconnected);
+    });
+
+    return { yAxisData, connectedData, disconnectedData };
+  }
+
+  updateChartOptions() {
+    const { yAxisData, connectedData, disconnectedData } = this.transformChartData(this.data.types.entries());
     this.chartOption1 = {
       tooltip: {
         trigger: 'axis',
@@ -735,7 +767,7 @@
       },
       yAxis: {
         type: 'category',
-        data: ['APV', 'vAPV', 'ASF', 'vASF', 'AG', 'vxAG']
+        data: yAxisData
       },
       series: [
         {
@@ -749,7 +781,7 @@
           emphasis: {
             focus: 'series'
           },
-          data: [3, 10, 2, 0, 3, 5]
+          data: connectedData
         },
         {
           name: 'Disconnected',
@@ -762,7 +794,7 @@
           emphasis: {
             focus: 'series'
           },
-          data: [0, 2, 0, 0, 0, 1]
+          data: disconnectedData
         }
       ]
     };
@@ -785,8 +817,8 @@
             show: false
           },
           data: [
-            {value: 10, name: 'Connected', itemStyle: {color: '#4CAF50'}},
-            {value: 1, name: 'Disconnected', itemStyle: {color: '#F44336'}}
+            {value: this.data?.total?.connected, name: 'Connected', itemStyle: {color: '#4CAF50'}},
+            {value: this.data?.total?.disconnected, name: 'Disconnected', itemStyle: {color: '#F44336'}}
           ]
         }
       ]
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/enlarge-system-devices.html
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/enlarge-system-devices.html	(revision 2705)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/enlarge-system-devices.html	(working copy)
@@ -1,4 +1,4 @@
-<h2 mat-dialog-title>System Devices Status (10/11)</h2>
+<h2 mat-dialog-title>System Devices Status ({{data?.total?.connected}}/{{data?.total?.connected + data?.total?.disconnected}})</h2>
 <mat-dialog-content>
   <div class="dialog-charts-wrapper">
     <div echarts [options]="chartOption1" class="dialog-chart-container"></div>
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/enlarge-system-disk-usage.html
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/enlarge-system-disk-usage.html	(revision 2705)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/enlarge-system-disk-usage.html	(working copy)
@@ -1,8 +1,7 @@
-<h2 mat-dialog-title>System Disk Usage</h2>
+<h2 mat-dialog-title>System Disk Usage (Last 1 Hour)</h2>
 <mat-dialog-content>
   <div class="dialog-charts-wrapper">
     <div echarts [options]="chartOption1" class="dialog-chart-container"></div>
-    <div echarts [options]="chartOption2" class="dialog-chart-container"></div>
   </div>
 </mat-dialog-content>
 <mat-dialog-actions>
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/enlarge-system-load.html
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/enlarge-system-load.html	(revision 2705)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/enlarge-system-load.html	(working copy)
@@ -1,4 +1,4 @@
-<h2 mat-dialog-title>System Load</h2>
+<h2 mat-dialog-title>System Load (Last 1 Hour)</h2>
 <mat-dialog-content>
   <div echarts [options]="chartOption1" class="chart-container"></div>
 </mat-dialog-content>
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/enlarge-system-throughput.html
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/enlarge-system-throughput.html	(revision 2705)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/components/sub-components/dashboard-system-insights/enlarge-system-throughput.html	(working copy)
@@ -1,4 +1,4 @@
-<h2 mat-dialog-title>System Throughput</h2>
+<h2 mat-dialog-title>System Throughput (Last 1 Hour)</h2>
 <mat-dialog-content>
   <div echarts [options]="chartOption1" class="chart-container"></div>
 </mat-dialog-content>
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/constants/api_urls.ts
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/constants/api_urls.ts	(revision 2705)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/constants/api_urls.ts	(working copy)
@@ -157,6 +157,8 @@
   GET_SLB_SERVICES_URL: `${PREFIX}/proxy_req_dev/webui_utils/''`,
   GET_REAL_SERVICES_URL: `${PREFIX}/real_service?role_id=0`,
   UPDATE_SLB_REAL_SERVICE_URL: `${PREFIX}/real_service`,
+  GET_SYSTEM_LATEST_METRICS_URL: `${PREFIX}/system-metrics-latest`,
+  GET_SYSTEM_HISTORICAL_METRICS_URL: `${PREFIX}/system-metrics-history`,
   // AVX
   GET_AVX_DEVICES_URL: `${PREFIX}/api/cm/virtualization/Host/_get_list_data`,
   ADD_AVX_DEVICE_URL: `${PREFIX}/api/cm/virtualization/Host/_add`,
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/pipes/bytes-pipe.spec.ts
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/pipes/bytes-pipe.spec.ts	(nonexistent)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/pipes/bytes-pipe.spec.ts	(working copy)
@@ -0,0 +1,8 @@
+import { BytesPipe } from './bytes-pipe';
+
+describe('BytesPipe', () => {
+  it('create an instance', () => {
+    const pipe = new BytesPipe();
+    expect(pipe).toBeTruthy();
+  });
+});
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/pipes/bytes-pipe.ts
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/pipes/bytes-pipe.ts	(nonexistent)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/pipes/bytes-pipe.ts	(working copy)
@@ -0,0 +1,24 @@
+import {Pipe, PipeTransform} from '@angular/core';
+
+@Pipe({
+  name: 'bytes'
+})
+export class BytesPipe implements PipeTransform {
+
+  private readonly units = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB'];
+
+  transform(bytes: number | null, precision: number = 2): string {
+    if (bytes === null || bytes === 0) {
+      return '0 Bytes';
+    }
+
+    if (isNaN(bytes) || !isFinite(bytes)) {
+      return 'Invalid value';
+    }
+
+    const unitIndex = Math.floor(Math.log(bytes) / Math.log(1024));
+    const convertedValue = bytes / Math.pow(1024, unitIndex);
+
+    return `${convertedValue.toFixed(precision)} ${this.units[unitIndex]}`;
+  }
+}
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/services/system-service.ts
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/services/system-service.ts	(revision 2705)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/gui/src/app/services/system-service.ts	(working copy)
@@ -449,5 +449,13 @@
 
   getOpenSearchAuthToken() {
     return this.http.get(URLS.GET_OPENSEARCH_SSO_TOKEN_URL);
+  }
+
+  getLatestSystemMetrics() {
+    return this.http.get(URLS.GET_SYSTEM_LATEST_METRICS_URL);
+  }
+
+  getHistoricalSystemMetrics() {
+    return this.http.get(URLS.GET_SYSTEM_HISTORICAL_METRICS_URL);
   }
 }
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/controller/system_metrics.py
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/controller/system_metrics.py	(nonexistent)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/controller/system_metrics.py	(working copy)
@@ -0,0 +1,49 @@
+import json
+
+from django.http import HttpResponse, JsonResponse
+from cm.lib.libbasic_operation import oper_log
+from hive.custom_exceptions import generic_exception as ge
+from hive.services.system_metrics import get_latest_system_metrics, get_historical_system_metrics
+from hive.utils import andebug
+
+
+def handle_get_latest_system_metrics(request, path=None):
+    try:
+        if request.method == 'GET':
+            status_data = get_latest_system_metrics()
+            return JsonResponse(status_data, safe=False)
+        else:
+            return JsonResponse({
+                'error': 400,
+                'message': "Invalid HTTP method"
+            }, status=400)
+
+    except ge.GenericError as e:
+        oper_log('error', 'system', e.message)
+        return ge.handle_exception(e)
+    except Exception as e:
+        andebug('an.model.cli', e)
+        oper_log('error', 'system', 'Exception while getting latest metrics.,  details: {}'.format(e.message))
+        e.message = 'Exception while getting latest metrics,  details: {}'.format(str(e.message))
+        raise ge.GenericError(500, e.message)
+
+
+def handle_get_historical_system_metrics(request, path=None):
+    try:
+        if request.method == 'GET':
+            status_data = get_historical_system_metrics()
+            return JsonResponse(status_data, safe=False)
+        else:
+            return JsonResponse({
+                'error': 400,
+                'message': "Invalid HTTP method"
+            }, status=400)
+
+    except ge.GenericError as e:
+        oper_log('error', 'system', e.message)
+        return ge.handle_exception(e)
+    except Exception as e:
+        andebug('an.model.cli', e)
+        oper_log('error', 'system', 'Exception while getting last 1 hour metrics.,  details: {}'.format(e.message))
+        e.message = 'Exception while getting last 1 hour metrics,  details: {}'.format(str(e.message))
+        raise ge.GenericError(500, e.message)
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/db/system_metrics_database.py
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/db/system_metrics_database.py	(nonexistent)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/db/system_metrics_database.py	(working copy)
@@ -0,0 +1,109 @@
+import psycopg2
+import os
+
+from hive.utils import andebug
+
+DB_HOST = os.environ.get("TIMESCALEDB_HOST", "localhost")
+DB_NAME = os.environ.get("TIMESCALEDB_DB", "amp_ts")
+DB_USER = os.environ.get("TIMESCALEDB_USER", "amp_ts_user")
+DB_PASSWORD = os.environ.get("TIMESCALEDB_PASSWORD", "Array@123$")
+
+
+class SystemMetrics:
+    def __init__(self, time, host, cpu_percent=None, mem_percent=None, disk_io_percent=None, read_speed=None,
+                 write_speed=None):
+        self.time = time
+        self.host = host
+        self.cpu_percent = cpu_percent
+        self.mem_percent = mem_percent
+        self.disk_io_percent = disk_io_percent
+        self.read_speed = read_speed
+        self.write_speed = write_speed
+
+    def to_dict(self):
+        data = {'time': self.time.isoformat() if self.time else None, 'host': self.host}
+
+        if self.cpu_percent is not None:
+            data['cpu_percent'] = float(round(self.cpu_percent, 2))
+
+        if self.mem_percent is not None:
+            data['mem_percent'] = float(round(self.mem_percent, 2))
+
+        if self.disk_io_percent is not None:
+            data['disk_io_percent'] = float(round(self.disk_io_percent, 2))
+
+        if self.read_speed is not None:
+            data['read_speed'] = float(round(self.read_speed, 2))
+
+        if self.write_speed is not None:
+            data['write_speed'] = float(round(self.write_speed, 2))
+
+        return data
+
+
+class DiskMetrics:
+    def __init__(self, time, host, device, path, total, used, free, used_percent):
+        self.time = time
+        self.host = host
+        self.device = device
+        self.path = path
+        self.total = total
+        self.used = used
+        self.free = free
+        self.used_percent = used_percent
+
+    def to_dict(self):
+        return {
+            'time': self.time.isoformat() if self.time else None,
+            'host': self.host,
+            'device': self.device,
+            'path': self.path,
+            'total_bytes': float(self.total),
+            'used_bytes': float(self.used),
+            'free_bytes': float(self.free),
+            'used_percent': float(round(self.used_percent, 2))
+        }
+
+
+class NetworkMetrics:
+    def __init__(self, time, host, interface, bytes_sent_bps, bytes_recv_bps):
+        self.time = time
+        self.host = host
+        self.interface = interface
+        self.bytes_sent_bps = bytes_sent_bps
+        self.bytes_recv_bps = bytes_recv_bps
+
+    def to_dict(self):
+        return {
+            'time': self.time.isoformat() if self.time else None,
+            'host': self.host,
+            'interface': self.interface,
+            'bytes_sent_bps': float(round(self.bytes_sent_bps, 2)) if self.bytes_sent_bps is not None else None,
+            'bytes_recv_bps': float(round(self.bytes_recv_bps, 2)) if self.bytes_recv_bps is not None else None
+        }
+
+
+def get_db_connection():
+    return psycopg2.connect(
+        host=DB_HOST,
+        dbname=DB_NAME,
+        user=DB_USER,
+        password=DB_PASSWORD
+    )
+
+
+def with_db_connection(func):
+    def wrapper(*args, **kwargs):
+        conn = None
+        try:
+            conn = get_db_connection()
+            result = func(conn, *args, **kwargs)
+            return result
+        except (Exception, psycopg2.DatabaseError) as error:
+            andebug('an.model.cli', error)
+            print(f"Error in {func.__name__}: {error}")
+        finally:
+            if conn:
+                conn.close()
+
+    return wrapper
Index: /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/services/system_metrics.py
===================================================================
--- /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/services/system_metrics.py	(nonexistent)
+++ /branches/amp_4_0/src/webui/webui/htdocs/new/src/hive/services/system_metrics.py	(working copy)
@@ -0,0 +1,325 @@
+from datetime import datetime, timedelta, timezone
+from tzlocal import get_localzone
+
+from hive.db.system_metrics_database import with_db_connection
+from hive.db.system_metrics_database import SystemMetrics, DiskMetrics, NetworkMetrics
+from hive.utils import andebug
+
+
+# ToDo: Add data access layer and reuse the db_client.
+# --- LATEST METRICS FUNCTIONS ---
+
+@with_db_connection
+def _get_latest_cpu_metrics(conn, host='AN'):
+    cur = conn.cursor()
+    # The query now directly calculates 100 - usage_idle
+    cpu_query = "SELECT time, host, 100 - usage_idle as cpu_percent FROM cpu WHERE time IN (SELECT max(time) FROM cpu WHERE host = %s) AND host = %s AND cpu = 'cpu-total' ORDER BY time DESC LIMIT 1;"
+    cur.execute(cpu_query, (host, host))
+    result = cur.fetchone()
+    cur.close()
+    if result:
+        time, host, cpu_percent = result
+        return SystemMetrics(time=time, host=host, cpu_percent=cpu_percent)
+    return None
+
+
+@with_db_connection
+def _get_latest_diskio_metrics(conn, host='AN'):
+    cur = conn.cursor()
+    disk_query = """
+                 SELECT
+                     bucket_time,
+                     ROUND(LEAST((SUM(io_time_total_ms) * 100.0 / 60000), 100), 2) AS disk_io_percent,
+                     ROUND(SUM(read_bytes_diff) / GREATEST(1, SUM(time_diff_sec)), 2) AS read_speed_bps,
+                     ROUND(SUM(write_bytes_diff) / GREATEST(1, SUM(time_diff_sec)), 2) AS write_speed_bps
+                 FROM (
+                          SELECT
+                              time_bucket('1 minute', time) AS bucket_time,
+                              GREATEST(io_time::BIGINT - LAG(io_time) OVER (PARTITION BY host ORDER BY time), 0) AS io_time_total_ms,
+                              GREATEST(read_bytes::BIGINT - LAG(read_bytes) OVER (PARTITION BY host ORDER BY time), 0) AS read_bytes_diff,
+                              GREATEST(write_bytes::BIGINT - LAG(write_bytes) OVER (PARTITION BY host ORDER BY time), 0) AS write_bytes_diff,
+                              EXTRACT(EPOCH FROM (time - LAG(time) OVER (PARTITION BY host ORDER BY time))) AS time_diff_sec
+                          FROM diskio
+                          WHERE host = %s
+                      ) sub
+                 WHERE io_time_total_ms IS NOT NULL
+                 GROUP BY bucket_time
+                 ORDER BY bucket_time DESC
+                 LIMIT 1;
+                 """
+    cur.execute(disk_query, (host,))
+    result = cur.fetchone()
+    cur.close()
+    if result:
+        time, disk_io_percent, read_speed, write_speed = result
+        return SystemMetrics(time=time, host=host, disk_io_percent=disk_io_percent, read_speed=read_speed,
+                             write_speed=write_speed)
+    return None
+
+
+@with_db_connection
+def _get_latest_mem_metrics(conn, host='AN'):
+    cur = conn.cursor()
+    # The query now directly selects used_percent
+    mem_query = "SELECT time, host, used_percent as mem_percent FROM mem WHERE time IN (SELECT max(time) FROM mem WHERE host = %s) AND host = %s ORDER BY time DESC LIMIT 1;"
+    cur.execute(mem_query, (host, host))
+    result = cur.fetchone()
+    cur.close()
+    if result:
+        time, host, mem_percent = result
+        return SystemMetrics(time=time, host=host, mem_percent=mem_percent)
+    return None
+
+
+@with_db_connection
+def _get_latest_disk_metrics(conn, host='AN'):
+    cur = conn.cursor()
+    disk_query = """
+                 SELECT time,
+                        host,
+                        device,
+                        path,
+                        total,
+                        used,
+                        free,
+                        used_percent
+                 FROM disk
+                 WHERE (host, device, time) IN (SELECT host,
+                                                       device,
+                                                       MAX(time)
+                                                FROM disk
+                                                WHERE host = %s
+                                                  AND path NOT LIKE 'tmpfs'
+                                                GROUP BY host, device)
+                 ORDER BY device ASC; \
+                 """
+
+    cur.execute(disk_query, (host,))
+    results = cur.fetchall()
+    cur.close()
+    metrics_list = []
+    for time, host, device, path, total, used, free, used_percent in results:
+        metrics_list.append(DiskMetrics(
+            time=time,
+            host=host,
+            device=device,
+            path=path,
+            total=total,
+            used=used,
+            free=free,
+            used_percent=used_percent
+        ))
+    return [m.to_dict() for m in metrics_list]
+
+
+@with_db_connection
+def _get_latest_net_metrics(conn, host='AN'):
+    cur = conn.cursor()
+    net_query = """
+                SELECT
+                    bucket_time,
+                    interface,
+                    ROUND(SUM(bytes_sent_diff) / GREATEST(1, SUM(time_diff_sec)), 2) AS bytes_sent_bps,
+                    ROUND(SUM(bytes_recv_diff) / GREATEST(1, SUM(time_diff_sec)), 2) AS bytes_recv_bps
+                FROM (
+                         SELECT
+                             time_bucket('1 minute', time) AS bucket_time,
+                             interface,
+                             GREATEST(bytes_sent::BIGINT - LAG(bytes_sent) OVER (PARTITION BY host, interface ORDER BY time), 0) AS bytes_sent_diff,
+                             GREATEST(bytes_recv::BIGINT - LAG(bytes_recv) OVER (PARTITION BY host, interface ORDER BY time), 0) AS bytes_recv_diff,
+                             EXTRACT(EPOCH FROM (time - LAG(time) OVER (PARTITION BY host, interface ORDER BY time))) AS time_diff_sec
+                         FROM net
+                         WHERE host = %s AND interface NOT LIKE 'lo' AND interface NOT LIKE 'all'
+                     ) sub
+                WHERE bytes_sent_diff IS NOT NULL
+                GROUP BY bucket_time, interface
+                ORDER BY bucket_time DESC
+                LIMIT 1;
+                """
+    cur.execute(net_query, (host,))
+    results = cur.fetchall()
+    cur.close()
+
+    metrics_list = []
+    for time, interface, bytes_sent, bytes_recv in results:
+        metrics_list.append(NetworkMetrics(
+            time=time,
+            host=host,
+            interface=interface,
+            bytes_sent_bps=bytes_sent,
+            bytes_recv_bps=bytes_recv
+        ))
+    return [m.to_dict() for m in metrics_list]
+
+
+def get_latest_system_metrics(host='AN'):
+    cpu_metrics = _get_latest_cpu_metrics(host=host)
+    mem_metrics = _get_latest_mem_metrics(host=host)
+    diskio_metrics = _get_latest_diskio_metrics(host=host)
+    disk_metrics = _get_latest_disk_metrics(host=host)
+    net_metrics = _get_latest_net_metrics(host=host)
+    return {
+        'cpu': cpu_metrics.to_dict() if cpu_metrics else None,
+        'memory': mem_metrics.to_dict() if mem_metrics else None,
+        'diskio': diskio_metrics.to_dict() if diskio_metrics else None,
+        'disk_usage': disk_metrics,
+        'net_metrics': net_metrics
+    }
+
+
+# --- LAST 1HOUR METRICS FUNCTIONS ---
+@with_db_connection
+def _get_historical_cpu_metrics(conn, host='AN', hours=1):
+    cur = conn.cursor()
+    now_utc_aware = datetime.now(timezone.utc)
+    end_time = now_utc_aware.replace(tzinfo=None)
+    start_time = end_time - timedelta(hours=hours)
+    bucket_interval = '1 minute'
+    cpu_query = """
+                SELECT time_bucket(%s, time)        AS bucket_time,
+                       last(100 - usage_idle, time) AS cpu_usage
+                FROM cpu
+                WHERE time BETWEEN %s AND %s
+                  AND host = %s
+                  AND cpu = 'cpu-total'
+                GROUP BY bucket_time
+                ORDER BY bucket_time ASC; \
+                """
+    cur.execute(cpu_query, (bucket_interval, start_time, end_time, host))
+    results = cur.fetchall()
+    cur.close()
+
+    metrics_list = []
+    for time_bucket, usage in results:
+        metrics_list.append(SystemMetrics(
+            time=time_bucket,
+            host=host,
+            cpu_percent=usage
+        ))
+    return [m.to_dict() for m in metrics_list]
+
+
+@with_db_connection
+def _get_historical_mem_metrics(conn, host='AN', hours=1):
+    cur = conn.cursor()
+    now_utc_aware = datetime.now(timezone.utc)
+    end_time = now_utc_aware.replace(tzinfo=None)
+    start_time = end_time - timedelta(hours=hours)
+    bucket_interval = '1 minute'
+    mem_query = """
+                SELECT time_bucket(%s, time)    AS bucket_time,
+                       last(used_percent, time) AS mem_usage
+                FROM mem
+                WHERE time BETWEEN %s AND %s
+                  AND host = %s
+                GROUP BY bucket_time
+                ORDER BY bucket_time ASC; \
+                """
+    cur.execute(mem_query, (bucket_interval, start_time, end_time, host))
+    results = cur.fetchall()
+    cur.close()
+
+    metrics_list = []
+    for time_bucket, usage in results:
+        metrics_list.append(SystemMetrics(
+            time=time_bucket,
+            host=host,
+            mem_percent=usage
+        ))
+    return [m.to_dict() for m in metrics_list]
+
+
+@with_db_connection
+def _get_historical_diskio_metrics(conn, host='AN', hours=1):
+    cur = conn.cursor()
+    now_utc_aware = datetime.now(timezone.utc)
+    end_time = now_utc_aware.replace(tzinfo=None)
+    start_time = end_time - timedelta(hours=hours)
+    bucket_interval = '1 minute'
+    diskio_query = """
+                   SELECT bucket_time,
+                          ROUND(LEAST((disk_io_total_ms * 100.0 / 60000), 100), 2) AS disk_io_percent
+                   FROM (SELECT time_bucket('1 minute', time)                            AS bucket_time,
+                                SUM(GREATEST(io_time::BIGINT - prev_io_time::BIGINT, 0)) AS disk_io_total_ms
+                         FROM (SELECT time,
+                                      io_time,
+                                      LAG(io_time) OVER (PARTITION BY host ORDER BY time) AS prev_io_time
+                               FROM diskio
+                               WHERE host = %s
+                                 AND time BETWEEN %s AND %s) sub
+                         WHERE prev_io_time IS NOT NULL
+                         GROUP BY bucket_time) final
+                   ORDER BY bucket_time ASC; \
+                   """
+    cur.execute(diskio_query, (host, start_time, end_time))
+    results = cur.fetchall()
+    cur.close()
+
+    metrics_list = []
+    for time_bucket, usage in results:
+        metrics_list.append(SystemMetrics(
+            time=time_bucket,
+            host=host,
+            disk_io_percent=usage
+        ))
+    return [m.to_dict() for m in metrics_list]
+
+
+@with_db_connection
+def _get_historical_net_metrics(conn, host='AN', hours=1):
+    cur = conn.cursor()
+    now_utc_aware = datetime.now(timezone.utc)
+    end_time = now_utc_aware.replace(tzinfo=None)
+    start_time = end_time - timedelta(hours=hours)
+    bucket_interval = '1 minute'
+    net_query = """
+                SELECT bucket_time,
+                       interface,
+                       ROUND(SUM(bytes_sent_diff) * 8 / GREATEST(1, SUM(time_diff_sec)),
+                             2)                                                                       AS bytes_sent_bps,
+                       ROUND(SUM(bytes_recv_diff) * 8 / GREATEST(1, SUM(time_diff_sec)), 2) AS bytes_recv_bps
+                FROM (SELECT time_bucket('1 minute', time)                                                            AS bucket_time,
+                             interface,
+                             GREATEST(bytes_sent::BIGINT -
+                                      LAG(bytes_sent) OVER (PARTITION BY host, interface ORDER BY time),
+                                      0)                                                                              AS bytes_sent_diff,
+                             GREATEST(bytes_recv::BIGINT -
+                                      LAG(bytes_recv) OVER (PARTITION BY host, interface ORDER BY time),
+                                      0)                                                                              AS bytes_recv_diff,
+                             EXTRACT(EPOCH FROM
+                                     (time - LAG(time) OVER (PARTITION BY host, interface ORDER BY time)))            AS time_diff_sec
+                      FROM net
+                      WHERE host = %s
+                        AND interface NOT LIKE 'lo' AND interface NOT LIKE 'all'
+                        AND time BETWEEN %s AND %s) sub
+                WHERE bytes_sent_diff IS NOT NULL
+                GROUP BY bucket_time, interface
+                ORDER BY bucket_time ASC; \
+                """
+    cur.execute(net_query, (host, start_time, end_time))
+    results = cur.fetchall()
+    cur.close()
+
+    metrics_list = []
+    for time, interface, bytes_sent, bytes_recv in results:
+        metrics_list.append(NetworkMetrics(
+            time=time,
+            host=host,
+            interface=interface,
+            bytes_sent_bps=bytes_sent,
+            bytes_recv_bps=bytes_recv
+        ))
+    return [m.to_dict() for m in metrics_list]
+
+
+def get_historical_system_metrics(host='AN'):
+    cpu_metrics = _get_historical_cpu_metrics(host=host)
+    mem_metrics = _get_historical_mem_metrics(host=host)
+    diskio_metrics = _get_historical_diskio_metrics(host=host)
+    net_metrics = _get_historical_net_metrics(host=host)
+    return {
+        'cpu_history': cpu_metrics,
+        'mem_history': mem_metrics,
+        'diskio_history': diskio_metrics,
+        'net_history': net_metrics
+    }
