Hostapd already parsed signal strength and rx/tx counters but the station -> ConnectedDevice conversion threw them away. Add signalDbm, rxBytes, txBytes and connectedAt to the OpenAPI schema and the ConnectedDevice model, and centralise the conversion in station.ToConnectedDevice so handlers, the periodic refresh and the event callbacks all serialise the same shape. Two follow-on bugs surfaced while wiring this up: - The hostapd backend only stored station entries on first contact. Subsequent polls were dropped, so signal and byte counters never refreshed. Reconcile updates in checkStationChanges. - ConnectedAt was reset to time.Now() on every conversion. Track FirstSeen on HostapdStation when the station joins, and preserve the timestamp across periodic refreshes in app.go so the UI's "connected since" badge is stable. Frontend gains a metrics row on each device card with signal bars, total traffic and a live duration. Falls back gracefully when a backend (DHCP, ARP) doesn't expose these fields.
576 lines
16 KiB
YAML
576 lines
16 KiB
YAML
openapi: 3.0.3
|
|
info:
|
|
title: Travel Router Control API
|
|
description: |
|
|
API for controlling a mini travel router with dual WiFi interfaces and Ethernet connectivity.
|
|
The router can operate as a WiFi repeater, connecting to upstream networks while providing
|
|
a hotspot for client devices.
|
|
version: 1.0.0
|
|
contact:
|
|
name: API Support
|
|
license:
|
|
name: MIT
|
|
|
|
servers:
|
|
- url: http://localhost:8080
|
|
description: Local router API
|
|
|
|
tags:
|
|
- name: WiFi
|
|
description: WiFi client operations (upstream network connection)
|
|
- name: Hotspot
|
|
description: Access point operations (client-facing hotspot)
|
|
- name: Devices
|
|
description: Connected devices management
|
|
- name: System
|
|
description: System status and monitoring
|
|
- name: Logs
|
|
description: System logs and real-time monitoring
|
|
|
|
paths:
|
|
/api/wifi/networks:
|
|
get:
|
|
tags:
|
|
- WiFi
|
|
summary: Get discovered WiFi networks
|
|
description: |
|
|
Returns the list of WiFi networks from the last scan without triggering a new scan.
|
|
Returns an empty list if no scan has been performed yet.
|
|
operationId: getWiFiNetworks
|
|
responses:
|
|
'200':
|
|
description: List of discovered networks
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/WiFiNetwork'
|
|
example:
|
|
- ssid: "Hotel-Guest"
|
|
signal: 5
|
|
security: "WPA2"
|
|
channel: 6
|
|
bssid: "aa:bb:cc:dd:ee:ff"
|
|
- ssid: "Public-WiFi"
|
|
signal: 3
|
|
security: "Open"
|
|
channel: 11
|
|
bssid: "11:22:33:44:55:66"
|
|
'500':
|
|
description: Error retrieving networks
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
/api/wifi/scan:
|
|
get:
|
|
tags:
|
|
- WiFi
|
|
summary: Scan for available WiFi networks
|
|
description: |
|
|
Triggers a WiFi scan using wpa_supplicant via D-Bus and returns all discovered networks
|
|
sorted by signal strength. The scan takes approximately 2 seconds to complete.
|
|
operationId: scanWiFi
|
|
responses:
|
|
'200':
|
|
description: Successfully scanned networks
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/WiFiNetwork'
|
|
example:
|
|
- ssid: "Hotel-Guest"
|
|
signal: 5
|
|
security: "WPA2"
|
|
channel: 6
|
|
bssid: "aa:bb:cc:dd:ee:ff"
|
|
- ssid: "Public-WiFi"
|
|
signal: 3
|
|
security: "Open"
|
|
channel: 11
|
|
bssid: "11:22:33:44:55:66"
|
|
'500':
|
|
description: Scan error
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
/api/wifi/connect:
|
|
post:
|
|
tags:
|
|
- WiFi
|
|
summary: Connect to a WiFi network
|
|
description: |
|
|
Connects the router to an upstream WiFi network using wpa_supplicant.
|
|
Supports both open and password-protected networks (WPA/WPA2).
|
|
operationId: connectWiFi
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/WiFiConnectRequest'
|
|
examples:
|
|
protected:
|
|
summary: WPA2 protected network
|
|
value:
|
|
ssid: "Hotel-Guest"
|
|
password: "guest1234"
|
|
open:
|
|
summary: Open network
|
|
value:
|
|
ssid: "Public-WiFi"
|
|
password: ""
|
|
responses:
|
|
'200':
|
|
description: Successfully connected
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/SuccessResponse'
|
|
'400':
|
|
description: Invalid request data
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
'500':
|
|
description: Connection failed
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
/api/wifi/disconnect:
|
|
post:
|
|
tags:
|
|
- WiFi
|
|
summary: Disconnect from WiFi network
|
|
description: |
|
|
Disconnects from the currently connected upstream WiFi network
|
|
and removes all saved network configurations.
|
|
operationId: disconnectWiFi
|
|
responses:
|
|
'200':
|
|
description: Successfully disconnected
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/SuccessResponse'
|
|
'500':
|
|
description: Disconnection failed
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
/api/hotspot/toggle:
|
|
post:
|
|
tags:
|
|
- Hotspot
|
|
summary: Toggle hotspot on/off
|
|
description: |
|
|
Enables or disables the hotspot (access point) by starting/stopping
|
|
the hostapd service. Returns the new enabled state and updates
|
|
the system status with current hostapd_cli information.
|
|
operationId: toggleHotspot
|
|
responses:
|
|
'200':
|
|
description: Hotspot state changed successfully
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
properties:
|
|
enabled:
|
|
type: boolean
|
|
description: Current hotspot state after toggle
|
|
required:
|
|
- enabled
|
|
example:
|
|
enabled: true
|
|
'500':
|
|
description: Failed to change hotspot state
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
/api/devices:
|
|
get:
|
|
tags:
|
|
- Devices
|
|
summary: Get connected devices
|
|
description: |
|
|
Returns a list of all devices currently connected to the hotspot.
|
|
Device information is gathered from DHCP leases and ARP tables.
|
|
Only devices with active ARP entries are considered connected.
|
|
operationId: getDevices
|
|
responses:
|
|
'200':
|
|
description: List of connected devices
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/ConnectedDevice'
|
|
example:
|
|
- name: "iPhone-12"
|
|
type: "mobile"
|
|
mac: "aa:bb:cc:11:22:33"
|
|
ip: "192.168.1.100"
|
|
- name: "MacBook-Pro"
|
|
type: "laptop"
|
|
mac: "dd:ee:ff:44:55:66"
|
|
ip: "192.168.1.101"
|
|
'500':
|
|
description: Failed to retrieve device list
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/Error'
|
|
|
|
/api/status:
|
|
get:
|
|
tags:
|
|
- System
|
|
summary: Get system status
|
|
description: |
|
|
Returns comprehensive system status including WiFi connection state,
|
|
detailed hotspot status from hostapd_cli, connected device count,
|
|
data usage, and uptime.
|
|
operationId: getStatus
|
|
responses:
|
|
'200':
|
|
description: Current system status
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/SystemStatus'
|
|
|
|
/api/logs:
|
|
get:
|
|
tags:
|
|
- Logs
|
|
summary: Get system logs
|
|
description: |
|
|
Returns the last 100 log entries from the system.
|
|
For real-time log streaming, use the WebSocket endpoint.
|
|
operationId: getLogs
|
|
responses:
|
|
'200':
|
|
description: List of log entries
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: array
|
|
items:
|
|
$ref: '#/components/schemas/LogEntry'
|
|
example:
|
|
- timestamp: "2025-10-28T14:32:10Z"
|
|
source: "WiFi"
|
|
message: "Scan terminé - 5 réseaux trouvés"
|
|
- timestamp: "2025-10-28T14:32:15Z"
|
|
source: "WiFi"
|
|
message: "Tentative de connexion à Hotel-Guest"
|
|
delete:
|
|
tags:
|
|
- Logs
|
|
summary: Clear system logs
|
|
description: Clears all stored log entries (keeps only the "logs cleared" entry)
|
|
operationId: clearLogs
|
|
responses:
|
|
'200':
|
|
description: Logs cleared successfully
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: '#/components/schemas/SuccessResponse'
|
|
|
|
/ws/logs:
|
|
get:
|
|
tags:
|
|
- Logs
|
|
summary: WebSocket for real-time logs
|
|
description: |
|
|
WebSocket endpoint for receiving real-time log updates.
|
|
Upon connection, all existing logs are sent, followed by new logs as they occur.
|
|
|
|
This is a WebSocket endpoint - upgrade the HTTP connection to WebSocket protocol.
|
|
operationId: logsWebSocket
|
|
responses:
|
|
'101':
|
|
description: WebSocket connection established
|
|
'400':
|
|
description: WebSocket upgrade failed
|
|
|
|
components:
|
|
schemas:
|
|
WiFiNetwork:
|
|
type: object
|
|
description: Discovered WiFi network information
|
|
properties:
|
|
ssid:
|
|
type: string
|
|
description: Network SSID (name)
|
|
example: "Hotel-Guest"
|
|
signal:
|
|
type: integer
|
|
description: Signal strength (1-5 scale)
|
|
minimum: 1
|
|
maximum: 5
|
|
example: 4
|
|
security:
|
|
type: string
|
|
description: Security type
|
|
enum:
|
|
- Open
|
|
- WEP
|
|
- WPA
|
|
- WPA2
|
|
example: "WPA2"
|
|
channel:
|
|
type: integer
|
|
description: WiFi channel number
|
|
minimum: 1
|
|
maximum: 165
|
|
example: 6
|
|
bssid:
|
|
type: string
|
|
description: Access point MAC address
|
|
pattern: '^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$'
|
|
example: "aa:bb:cc:dd:ee:ff"
|
|
required:
|
|
- ssid
|
|
- signal
|
|
- security
|
|
- channel
|
|
- bssid
|
|
|
|
WiFiConnectRequest:
|
|
type: object
|
|
description: Request to connect to a WiFi network
|
|
properties:
|
|
ssid:
|
|
type: string
|
|
description: Network SSID to connect to
|
|
example: "Hotel-Guest"
|
|
password:
|
|
type: string
|
|
description: Network password (empty string for open networks)
|
|
example: "guest1234"
|
|
required:
|
|
- ssid
|
|
- password
|
|
|
|
HotspotStatus:
|
|
type: object
|
|
description: Detailed hotspot status from hostapd_cli
|
|
properties:
|
|
state:
|
|
type: string
|
|
description: Hotspot state (ENABLED, DISABLED, etc.)
|
|
example: "ENABLED"
|
|
ssid:
|
|
type: string
|
|
description: Current SSID being broadcast
|
|
example: "TravelRouter"
|
|
bssid:
|
|
type: string
|
|
description: MAC address of the access point
|
|
pattern: '^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$'
|
|
example: "4a:e3:4e:09:57:f8"
|
|
channel:
|
|
type: integer
|
|
description: Current WiFi channel
|
|
minimum: 1
|
|
maximum: 14
|
|
example: 11
|
|
frequency:
|
|
type: integer
|
|
description: Frequency in MHz
|
|
example: 2462
|
|
numStations:
|
|
type: integer
|
|
description: Number of connected stations
|
|
minimum: 0
|
|
example: 2
|
|
hwMode:
|
|
type: string
|
|
description: Hardware mode (g, a, n, ac, etc.)
|
|
example: "g"
|
|
countryCode:
|
|
type: string
|
|
description: Country code
|
|
example: "VN"
|
|
required:
|
|
- state
|
|
|
|
ConnectedDevice:
|
|
type: object
|
|
description: Device connected to the hotspot
|
|
properties:
|
|
name:
|
|
type: string
|
|
description: Device hostname (may be empty when DHCP did not provide one)
|
|
example: "iPhone-12"
|
|
type:
|
|
type: string
|
|
description: Detected device type
|
|
enum:
|
|
- mobile
|
|
- tablet
|
|
- laptop
|
|
- desktop
|
|
- unknown
|
|
example: "mobile"
|
|
mac:
|
|
type: string
|
|
description: Device MAC address
|
|
pattern: '^([0-9a-fA-F]{2}:){5}[0-9a-fA-F]{2}$'
|
|
example: "aa:bb:cc:11:22:33"
|
|
ip:
|
|
type: string
|
|
description: Assigned IP address
|
|
pattern: '^(?:[0-9]{1,3}\.){3}[0-9]{1,3}$'
|
|
example: "192.168.1.100"
|
|
vendor:
|
|
type: string
|
|
description: Hardware vendor inferred from the MAC OUI prefix (empty when unknown)
|
|
example: "Apple"
|
|
signalDbm:
|
|
type: integer
|
|
format: int32
|
|
description: Wi-Fi signal strength in dBm (0 when unavailable, e.g. for non-hostapd backends)
|
|
example: -54
|
|
rxBytes:
|
|
type: integer
|
|
format: int64
|
|
description: Total bytes received from the device since connection (0 when unavailable)
|
|
example: 1048576
|
|
txBytes:
|
|
type: integer
|
|
format: int64
|
|
description: Total bytes sent to the device since connection (0 when unavailable)
|
|
example: 524288
|
|
connectedAt:
|
|
type: string
|
|
format: date-time
|
|
description: Timestamp when the station first appeared (best effort)
|
|
example: "2026-05-01T08:30:00Z"
|
|
required:
|
|
- name
|
|
- type
|
|
- mac
|
|
- ip
|
|
|
|
SystemStatus:
|
|
type: object
|
|
description: Overall system status
|
|
properties:
|
|
connected:
|
|
type: boolean
|
|
description: Whether router is connected to upstream WiFi
|
|
example: true
|
|
connectionState:
|
|
type: string
|
|
description: Current WiFi connection state
|
|
enum:
|
|
- connected
|
|
- disconnected
|
|
- connecting
|
|
- disconnecting
|
|
- roaming
|
|
example: "connected"
|
|
connectedSSID:
|
|
type: string
|
|
description: SSID of connected upstream network (empty if not connected)
|
|
example: "Hotel-Guest"
|
|
hotspotStatus:
|
|
allOf:
|
|
- $ref: '#/components/schemas/HotspotStatus'
|
|
nullable: true
|
|
description: Detailed hotspot status (null if hotspot is not running)
|
|
connectedCount:
|
|
type: integer
|
|
description: Number of devices connected to hotspot
|
|
minimum: 0
|
|
example: 3
|
|
dataUsage:
|
|
type: number
|
|
format: double
|
|
description: Total data usage in MB
|
|
example: 145.7
|
|
uptime:
|
|
type: integer
|
|
format: int64
|
|
description: System uptime in seconds
|
|
example: 3600
|
|
connectedDevices:
|
|
type: array
|
|
description: List of devices connected to hotspot
|
|
items:
|
|
$ref: '#/components/schemas/ConnectedDevice'
|
|
required:
|
|
- connected
|
|
- connectionState
|
|
- connectedSSID
|
|
- connectedCount
|
|
- dataUsage
|
|
- uptime
|
|
- connectedDevices
|
|
|
|
LogEntry:
|
|
type: object
|
|
description: System log entry
|
|
properties:
|
|
timestamp:
|
|
type: string
|
|
format: date-time
|
|
description: When the log entry was created
|
|
example: "2025-10-28T14:32:10Z"
|
|
source:
|
|
type: string
|
|
description: Log source component
|
|
enum:
|
|
- Système
|
|
- WiFi
|
|
- Hotspot
|
|
example: "WiFi"
|
|
message:
|
|
type: string
|
|
description: Log message
|
|
example: "Scan terminé - 5 réseaux trouvés"
|
|
required:
|
|
- timestamp
|
|
- source
|
|
- message
|
|
|
|
SuccessResponse:
|
|
type: object
|
|
description: Generic success response
|
|
properties:
|
|
status:
|
|
type: string
|
|
enum:
|
|
- success
|
|
example: "success"
|
|
required:
|
|
- status
|
|
|
|
Error:
|
|
type: object
|
|
description: Error response
|
|
properties:
|
|
error:
|
|
type: string
|
|
description: Error message
|
|
example: "Erreur lors du scan WiFi"
|
|
required:
|
|
- error
|