Version 1.1 - Multi-Board Architecture
cd frontend
npm install
npm install leaflet
npm start
✅ Dashboard will be available at http://localhost:3000
Automatic Setup (Recommended):
python3 --version
python3 WebDashboard.py
✅ The system automatically installs dependencies and starts the Flask server
Manual Setup (If needed):
cd backend/dependencies/flask_pkgs
pip3 install *.whl --no-deps
cd ../pexpect_pkgs
pip3 install *.whl --no-deps
cd ../pytest_pkgs
pip3 install *.whl --no-deps
python3 WebDashboard.py --edgeq # Explicit EdgeQ board
python3 WebDashboard.py # Auto-detect board type
The dashboard implements an extensible multi-board architecture supporting different 5G gNB hardware platforms:
┌─────────────────────────────────────────────────────────────────┐
│ Frontend (React SPA) │
├─────────────────────────────────────────────────────────────────┤
│ Components: HomePage | NodeDashboard | Map | Sidebar │
│ Features: Network Scanner | Real-time Updates | Controls │
└─────────────────────────────────────────────────────────────────┘
│ HTTP/REST API
┌─────────────────────────────────────────────────────────────────┐
│ Backend (Flask + Multi-Board) │
├─────────────────────────────────────────────────────────────────┤
│ WebDashboard.py (Entry Point + Auto-Setup) │
│ ├── BoardFactory (Auto-Detection & Board Creation) │
│ ├── Flask.py (REST API Routes) │
│ └── ConfigManager (Board-Specific Configuration) │
└─────────────────────────────────────────────────────────────────┘
│
┌─────────────────────────────────────────────────────────────────┐
│ Board Implementations │
├─────────────────────────────────────────────────────────────────┤
│ BaseBoard (Abstract) │
│ ├── EdgeQBoard (EdgeQ Implementation) │
│ ├── [Future Board Types] │
│ └── Board-Specific: Attributes | Commands | Configs │
└─────────────────────────────────────────────────────────────────┘
│
┌─────────────────────────────────────────────────────────────────┐
│ Hardware Layer │
├─────────────────────────────────────────────────────────────────┤
│ EdgeQ gNB Hardware | Other 5G Platforms | MANET Devices │
└─────────────────────────────────────────────────────────────────┘
WebDashboard.py
detects board type and initializes appropriate board instance/api/attributes
and /api/node_status
(5s)NetworkScanner
performs dual-sweep scanning (Health + MANET APIs every 20s)/api/setup_script
// Key state management
const [allNodeData, setAllNodeData] = useState([]);
const [autoDiscoveredNodes, setAutoDiscoveredNodes] = useState([]);
const [isNetworkScanning, setIsNetworkScanning] = useState(false);
const [subnet, setSubnet] = useState('192.168.1');
class BoardFactory:
AVAILABLE_BOARDS = {
'edgeq': EdgeQBoard
# Future board types added here
}
@staticmethod
def create_board(board_type: str = None):
if board_type is None:
board_type = BoardFactory.detect_board_type()
return BoardFactory.AVAILABLE_BOARDS[board_type.lower()]()
class BaseBoard(ABC):
@abstractmethod
def get_board_name(self) -> str: pass
@abstractmethod
def get_board_config(self) -> Dict[str, Any]: pass
@abstractmethod
def create_attributes(self): pass
@abstractmethod
def ensure_config_exists(self) -> bool: pass
gnb_commission -g
handlinggnb_ctl
integrationThe board factory system enables support for multiple hardware platforms:
The network discovery system performs intelligent device detection:
http://[ip]:5000/api/health
http://[ip]/status?content=temp
Frontend Implementation:
App.js
manages multiple polling intervals:
// Real-time updates flow via state
useEffect(() => {
const attributeInterval = setInterval(async () => {
// Update CPU, RAM, etc. for all nodes
}, 5000);
}, [allNodeData]);
Backend Implementation: Board-specific attribute classes collect real-time data:
# EdgeQ example
class EdgeQCpuUsage(BaseAttribute):
def refresh(self):
# EdgeQ-specific CPU monitoring
pass
Frontend NetworkScanner:
class NetworkScanner {
async scanSubnet(subnet, onProgress, onNodeFound) {
// Dual-sweep: Health API + MANET API
await this.performSweep(allIPs, 'health', onProgress, onNodeFound);
await this.performSweep(allIPs, 'manet', onProgress, onNodeFound);
}
}
Integration with Sidebar:
Performance Charts:
Interactive Map:
Frontend Control Flow:
const handleNodeControl = async (action) => {
setLoading(true);
try {
const response = await fetch('/api/setup_script', {
method: 'POST',
body: JSON.stringify({ action })
});
// Handle response and update UI
} finally {
setLoading(false);
}
};
Backend Control Flow:
Data Flow Architecture:
Client-Side Persistence:
// Save to localStorage
const saveNodes = (nodes) => {
localStorage.setItem('nodes', JSON.stringify(nodes));
};
// Load on app startup
const loadNodes = () => {
const saved = localStorage.getItem('nodes');
return saved ? JSON.parse(saved) : [];
};
Configuration includes:
Adding New Board Types:
BaseBoard
BoardFactory.AVAILABLE_BOARDS
Board-Specific Features:
The backend Flask service provides REST API endpoints for monitoring and controlling gNB nodes. This API enables external applications and services to integrate with the gNB Dashboard functionality.
For comprehensive interactive API documentation with “Try it out” functionality, see the Flasgger Documentation System:
Quick Start:
docs_generator/
start_docs.bat
(Windows) or run python swagger_docs.py
Features:
http://<gnb-board-ip>:5000/api
Get current board information and configuration details.
Response Schema:
Name | JSON Attribute | Type | Remarks |
---|---|---|---|
Board Type | board_type |
string | Type of board hardware (e.g., “EdgeQ”) |
Config Path | config_path |
string | Absolute path to configuration file on board |
Log Directory | log_directory |
string | Directory where system logs are stored |
Available Files | available_files |
array[string] | List of downloadable file keys |
Timeouts | timeouts |
object | Configuration timeout values |
Raptor Status Timeout | timeouts.raptor_status |
number | Timeout for status checks in seconds |
Setup Max Wait | timeouts.setup_max_wait |
number | Maximum wait time for setup operations |
Example:
curl -X GET http://192.168.1.100:5000/api/board-info
Get comprehensive system attributes and real-time metrics.
Response Schema:
Name | JSON Attribute | Type | Remarks |
---|---|---|---|
gNB ID | gnb_id |
string | Unique identifier for the gNodeB |
gNB ID Length | gnb_id_length |
string | Length specification for gNodeB identifier |
NR Band | nr_band |
string | 5G NR frequency band (e.g., “n78”) |
Subcarrier Spacing | scs |
string | Subcarrier spacing configuration |
TX Power | tx_power |
string | Transmission power level in dBm |
Downlink Frequency | frequency_down_link |
string | Downlink center frequency in Hz |
gNB IP Address | ip_address_gnb |
string | IP address of the gNodeB interface |
NGC IP Address | ip_address_ngc |
string | Next Generation Core IP address |
NGU IP Address | ip_address_ngu |
string | NG User plane interface IP address |
Mobile Country Code | MCC |
string | Mobile Country Code for network identification |
Mobile Network Code | MNC |
string | Mobile Network Code for operator identification |
Cell ID | cell_id |
string | Unique cell identifier within the network |
NR TAC | nr_tac |
string | 5G NR Tracking Area Code |
Slice Service Type | sst |
string | Network slice service type identifier |
Slice Differentiator | sd |
string | Network slice differentiator value |
Profile | profile |
string | Active configuration profile name |
CPU Usage | cpu_usage |
number | Current CPU utilization percentage (0-100) |
CPU Usage History | cpu_usage_history |
array[number] | Historical CPU usage data points |
CPU Temperature | cpu_temp |
number | Current CPU temperature in Celsius |
RAM Usage | ram_usage |
number | Current RAM utilization percentage (0-100) |
RAM Usage History | ram_usage_history |
array[number] | Historical RAM usage data points |
RAM Total | ram_total |
number | Total system RAM in megabytes |
Drive Total | drive_total |
number | Total disk space in gigabytes |
Drive Used | drive_used |
number | Used disk space in gigabytes |
Drive Free | drive_free |
number | Available disk space in gigabytes |
Board Date | board_date |
string | Current system date on the board |
Board Time | board_time |
string | Current system time on the board |
Core Connection | core_connection |
string | Status of connection to core network |
Example:
curl -X GET http://192.168.1.100:5000/api/attributes
Get current operational status of the gNB node.
Response Schema:
Name | JSON Attribute | Type | Remarks |
---|---|---|---|
Node Status | node_status |
string | Current operational state: OFF , INITIALISING , or RUNNING |
Example:
curl -X GET http://192.168.1.100:5000/api/node_status
Execute node control commands for managing gNB operations.
⏱️ Expected Execution Times:
Request Body Schema:
Name | JSON Attribute | Type | Remarks |
---|---|---|---|
Action | action |
string | Command to execute: “start”, “stop”, “status”, or “setupv2” |
Response Schema (Success):
Name | JSON Attribute | Type | Remarks |
---|---|---|---|
Action | action |
string | Echo of the executed action command |
Status | status |
string | Result status: “ok” for successful start/setup, “completed” for stop/status |
Output | output |
string | Command execution output and logs from log file |
Log File | log_file |
string | Path to the generated log file |
Exit Code | exit_code |
number | Process exit code (0 = success) |
Response Schema (Error):
Name | JSON Attribute | Type | Remarks |
---|---|---|---|
Action | action |
string | Echo of the attempted action command |
Error | error |
string | Error type: “timeout”, “process_terminated_unexpectedly”, etc. |
Details | details |
string | Detailed error description and context |
Output | output |
string | Partial command output before failure |
Exit Code | exit_code |
number | Process exit code (-1 for timeouts, actual code for process failures) |
Examples:
# Start the gNB node (takes ~2 minutes)
curl -X POST http://192.168.1.100:5000/api/setup_script \
-H "Content-Type: application/json" \
-d '{"action": "start"}'
# Stop the gNB node (takes 5-10 seconds)
curl -X POST http://192.168.1.100:5000/api/setup_script \
-H "Content-Type: application/json" \
-d '{"action": "stop"}'
Important Notes:
/api/download/
Update gNB configuration parameters dynamically.
Request Body Schema:
Name | JSON Attribute | Type | Remarks |
---|---|---|---|
Field | field |
string | Configuration parameter name to update (see valid fields below) |
Value | value |
string | New value for the configuration parameter |
Valid Configuration Fields:
Field Name | Type | Category | Description | Example Value |
---|---|---|---|---|
gNBId |
string | Radio | gNodeB identifier | “001” |
gNBIdLength |
string | Radio | Length specification for gNodeB ID | “24” |
band |
string | Radio | 5G NR frequency band | “n78” |
scs |
string | Radio | Subcarrier spacing configuration | “30kHz” |
txMaxPower |
string | Radio | Maximum transmission power in dBm | “23.0” |
dl_centre_freq |
string | Radio | Downlink center frequency in Hz | “3500000000” |
gnbIP |
string | Core | gNodeB IP address | “192.168.1.50” |
n3_local_ip |
string | Core | N3 interface local IP address | “192.168.1.51” |
n2_local_ip |
string | Core | N2 interface local IP address | “192.168.1.52” |
n3_remote_ip |
string | Core | N3 interface local IP address | “192.168.1.10” |
n2_remote_ip |
string | Core | N2 interface local IP address | “192.168.1.11” |
MCC |
string | Core | Mobile Country Code | “001” |
MNC |
string | Core | Mobile Network Code | “01” |
cellId |
string | Core | Cell identifier | “1” |
nrTAC |
string | Core | 5G NR Tracking Area Code | “1” |
sst |
string | Core | Network slice service type | “1” |
sd |
string | Core | Network slice differentiator | “000001” |
Response Schema:
Name | JSON Attribute | Type | Remarks |
---|---|---|---|
Status | status |
string | Operation result: “success” or “error” |
Message | message |
string | Descriptive message about the operation result |
Examples:
# Update gNB IP configuration
curl -X POST http://192.168.1.100:5000/api/config \
-H "Content-Type: application/json" \
-d '{"field": "gnbIP", "value": "192.168.1.50"}'
# Update gNB ID Length
curl -X POST http://192.168.1.100:5000/api/config \
-H "Content-Type: application/json" \
-d '{"field": "gNBIdLength", "value": "28"}'
# Update NR Band
curl -X POST http://192.168.1.100:5000/api/config \
-H "Content-Type: application/json" \
-d '{"field": "band", "value": "n77"}'
Important Notes:
Download board-specific files and logs.
Parameters:
file_key
: String identifier for the file to downloadResponse: File download (binary content) or error message
Error Response Schema:
Name | JSON Attribute | Type | Remarks |
---|---|---|---|
Error | error |
string | Error description for invalid file keys |
Available Files | available_files |
array[string] | List of valid file keys that can be downloaded |
Example:
curl -X GET http://192.168.1.100:5000/api/download/log_file \
-o downloaded_log.txt
All endpoints return appropriate HTTP status codes:
200
: Success - Request completed successfully400
: Bad Request - Invalid request format or parameters500
: Internal Server Error - Server-side processing error504
: Gateway Timeout - Operation timed outStandard Error Response Schema:
Name | JSON Attribute | Type | Remarks |
---|---|---|---|
Error | error |
string | Brief error description |
Details | details |
string | Additional error context and troubleshooting information |
Status | status |
string | Always “error” for error responses |
The API is designed for dashboard polling and control operations:
import requests
import json
# Monitor node attributes
response = requests.get('http://192.168.1.100:5000/api/attributes')
if response.status_code == 200:
data = response.json()
print(f"CPU Usage: {data['cpu_usage']}%")
print(f"RAM Usage: {data['ram_usage']}%")
# Start node
payload = {"action": "start"}
response = requests.post(
'http://192.168.1.100:5000/api/setup_script',
headers={'Content-Type': 'application/json'},
data=json.dumps(payload)
)
// Fetch node status
async function getNodeStatus() {
try {
const response = await fetch('http://192.168.1.100:5000/api/node_status');
const data = await response.json();
console.log('Node Status:', data.node_status);
} catch (error) {
console.error('Error fetching status:', error);
}
}
// Update configuration
async function updateConfig(field, value) {
try {
const response = await fetch('http://192.168.1.100:5000/api/config', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ field, value })
});
const result = await response.json();
console.log('Config update:', result);
} catch (error) {
console.error('Error updating config:', error);
}
}
Step 1: Create Board Implementation
# backend/boards/new_board.py
from .base_board import BaseBoard
class NewBoard(BaseBoard):
def get_board_name(self) -> str:
return "NewBoard"
def get_board_config(self) -> Dict[str, Any]:
return {
"config_file_path": "/path/to/config",
"setup_commands": {...},
# Board-specific configuration
}
def create_attributes(self):
return {
'cpu_usage': NewBoardCpuUsage(),
'custom_attr': NewBoardCustomAttr(),
# Board-specific attributes
}
Step 2: Register with BoardFactory
# backend/board_factory.py
from boards.new_board import NewBoard
class BoardFactory:
AVAILABLE_BOARDS = {
'edgeq': EdgeQBoard,
'newboard': NewBoard # Add new board
}
Step 3: Add Detection Logic
@staticmethod
def detect_board_type():
if os.path.exists("/opt/newboard/bin/control"):
return "newboard"
# Existing detection logic...
Step 4: Create Board-Specific Attributes
# backend/logic/newboard_attributes/NewBoardCpuUsage.py
from logic.shared_attributes.BaseAttribute import BaseAttribute
class NewBoardCpuUsage(BaseAttribute):
def __init__(self):
super().__init__()
self.value = 0.0
def refresh(self):
# Board-specific CPU monitoring implementation
pass
Step 5: Add Command-Line Support
# In board_factory.py parse_board_from_args()
board_group.add_argument('--newboard', action='store_true',
help='Use NewBoard configuration')
Testing Overview:
The dashboard includes comprehensive testing for both frontend and backend components:
Frontend Testing:
Backend Testing:
📖 Complete Testing Documentation
Quick Testing Commands:
# Frontend testing
cd frontend
npm test
# Backend testing
cd backend
python3 -m pytest tests/
# Debug network scanning
# Check browser console for NetworkScanner logs
console.log("NetworkScanner: Starting scan...");
# Debug API endpoints
curl http://localhost:5000/api/board-info
curl http://localhost:5000/api/attributes
Testing Logs:
Important Notes:
npm run coverage
to check frontend test coverageDevelopment Environment:
# Frontend development
cd frontend && npm start
# Backend development with hot reload
cd backend && python3 WebDashboard.py --edgeq
Production Deployment:
cd frontend
npm start
# Ensure all dependencies are in backend/dependencies/
ls backend/dependencies/
# flask_pkgs/ pexpect_pkgs/ pytest_pkgs/
# Configure firewalls for required ports
sudo ufw allow 3000/tcp # Frontend
sudo ufw allow 5000/tcp # Backend API
Release Checklist:
Frontend Optimizations:
Backend Optimizations:
Network Optimizations:
API Security:
Network Security:
Board Access:
Horizontal Scaling:
Vertical Scaling:
Future Extensibility:
Target Users:
Value Proposition:
Priority | Role | Feature | Benefit |
---|---|---|---|
*** | Network Engineer | See all node statuses | Quickly spot failures across the network |
*** | Operator | Start/stop nodes | Remote control without physical access |
*** | Support Engineer | View CPU/RAM/disk metrics | Diagnose performance issues efficiently |
*** | Operator | Network device discovery | Automatically find new equipment |
** | Network Engineer | Historical trends | Identify recurring issues and patterns |
** | Operator | Add/remove nodes | Flexible dashboard configuration |
** | Support Engineer | MANET GPS tracking | Visualize mesh network topology |
** | System Integrator | API access | Integrate with existing systems |
* | Support Engineer | Download logs | Advanced troubleshooting capabilities |
* | Network Engineer | Multi-board support | Manage heterogeneous networks |
Main Success Scenario (MSS):
Extensions:
MSS:
Extensions:
MSS:
Extensions:
MSS:
Extensions:
MSS:
Extensions:
MSS:
Extensions:
Technical Terms:
System Terms:
API Terms: