M5-T06: add Energy device management UI and sidebar entry

This commit is contained in:
2026-06-22 13:52:33 +02:00
parent 702a1cec00
commit 2dc469274a
11 changed files with 2301 additions and 8 deletions
+703
View File
@@ -210,6 +210,199 @@ export interface paths {
patch: operations["patch_poo_api_poo__timestamp__patch"];
trace?: never;
};
"/api/modbus/profiles": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/**
* Get Profiles
* @description List all available Modbus YAML profiles (name + description).
*
* Intended for the front-end's device-creation profile drop-down.
*/
get: operations["get_profiles_api_modbus_profiles_get"];
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/api/modbus/devices": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/**
* List Devices
* @description Return all Modbus devices (no pagination — device counts stay small).
*/
get: operations["list_devices_api_modbus_devices_get"];
put?: never;
/**
* Create Device
* @description Create a new Modbus device.
*
* - Validates that the referenced ``profile`` exists; returns 422 if not.
* - Returns 201 with the created device on success.
*/
post: operations["create_device_api_modbus_devices_post"];
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/api/modbus/devices/{uuid}": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/**
* Get Device
* @description Return a single Modbus device by UUID.
*/
get: operations["get_device_api_modbus_devices__uuid__get"];
put?: never;
post?: never;
/**
* Delete Device
* @description Delete a Modbus device.
*
* Returns 409 Conflict if the device has any associated readings; use
* ``enabled=false`` to disable it instead.
*
* **Application-layer safety**: the check is performed via an explicit
* SELECT COUNT query — not by relying on SQLite's FK RESTRICT constraint,
* which is not enforced at runtime in this project (no PRAGMA foreign_keys=ON).
*/
delete: operations["delete_device_api_modbus_devices__uuid__delete"];
options?: never;
head?: never;
/**
* Patch Device
* @description Partially update a Modbus device (including enable/disable).
*
* Only fields explicitly provided in the request body are updated.
* Providing ``profile`` triggers a profile-existence check (422 if unknown).
*/
patch: operations["patch_device_api_modbus_devices__uuid__patch"];
trace?: never;
};
"/api/modbus/devices/{uuid}/latest": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/**
* Get Latest Reading
* @description Return the most recent reading for a device.
*
* If no readings exist yet, returns ``{"found": false, "recorded_at": null,
* "payload": null}`` (200, not 404) so the front-end can distinguish
* "device exists but has no data" from "device not found".
*/
get: operations["get_latest_reading_api_modbus_devices__uuid__latest_get"];
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/api/modbus/devices/{uuid}/readings": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/**
* Get Readings
* @description Return time-range readings for a device.
*
* Results are ordered by ``recorded_at`` ascending and capped by ``limit``
* (max {_READINGS_LIMIT_MAX}) to prevent accidental full-table exports.
*
* The query uses the ``(device_id, recorded_at)`` composite index for
* efficient time-window scans.
*
* Query parameters:
* - ``start``: inclusive lower bound (ISO8601 datetime)
* - ``end``: inclusive upper bound (ISO8601 datetime)
* - ``limit``: max rows to return (default 500, max {_READINGS_LIMIT_MAX})
*/
get: operations["get_readings_api_modbus_devices__uuid__readings_get"];
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/api/modbus/devices/{uuid}/metrics": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/**
* Get Metrics
* @description Return the metric catalogue for a device's profile.
*
* Each entry has ``key``, ``label`` (derived from key if the profile has
* none — underscores → spaces, title-cased), ``unit``, and ``device_class``.
* This is the authoritative metadata source for front-end card labels and
* chart axis labels.
*/
get: operations["get_metrics_api_modbus_devices__uuid__metrics_get"];
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/api/modbus/devices/{uuid}/test": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get?: never;
put?: never;
/**
* Test Read
* @description Immediately read and decode the device once without persisting any data.
*
* Useful for validating gateway connectivity and Modbus address settings
* before relying on the background polling job.
*
* This is a write-class endpoint (it initiates network I/O on demand) and
* therefore requires a CSRF token. The response payload is never stored.
*/
post: operations["test_read_api_modbus_devices__uuid__test_post"];
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/api/session": {
parameters: {
query?: never;
@@ -620,6 +813,202 @@ export interface components {
/** Totp Code */
totp_code?: string | null;
};
/**
* MetricInfo
* @description Metadata for a single measurable quantity in a device's profile.
*/
MetricInfo: {
/** Key */
key: string;
/** Label */
label: string;
/** Unit */
unit: string;
/** Device Class */
device_class: string;
};
/**
* ModbusDeviceCreate
* @description Request body for POST /api/modbus/devices.
*/
ModbusDeviceCreate: {
/** Friendly Name */
friendly_name: string;
/**
* Transport
* @default tcp
*/
transport: string;
/** Host */
host: string;
/**
* Port
* @default 502
*/
port: number;
/**
* Unit Id
* @default 1
*/
unit_id: number;
/** Profile */
profile: string;
/**
* Poll Interval S
* @default 5
*/
poll_interval_s: number;
/**
* Enabled
* @default true
*/
enabled: boolean;
};
/**
* ModbusDeviceListResponse
* @description Response schema for listing Modbus devices.
*/
ModbusDeviceListResponse: {
/** Items */
items: components["schemas"]["ModbusDeviceResponse"][];
/** Total */
total: number;
};
/**
* ModbusDeviceResponse
* @description Response schema for a single Modbus device.
*/
ModbusDeviceResponse: {
/** Uuid */
uuid: string;
/** Friendly Name */
friendly_name: string;
/** Transport */
transport: string;
/** Host */
host: string;
/** Port */
port: number;
/** Unit Id */
unit_id: number;
/** Profile */
profile: string;
/** Poll Interval S */
poll_interval_s: number;
/** Enabled */
enabled: boolean;
/** Last Poll At */
last_poll_at: string | null;
/** Last Poll Ok */
last_poll_ok: boolean | null;
/**
* Created At
* Format: date-time
*/
created_at: string;
/**
* Updated At
* Format: date-time
*/
updated_at: string;
};
/**
* ModbusDeviceUpdate
* @description Request body for PATCH /api/modbus/devices/{uuid} — all fields optional.
*/
ModbusDeviceUpdate: {
/** Friendly Name */
friendly_name?: string | null;
/** Transport */
transport?: string | null;
/** Host */
host?: string | null;
/** Port */
port?: number | null;
/** Unit Id */
unit_id?: number | null;
/** Profile */
profile?: string | null;
/** Poll Interval S */
poll_interval_s?: number | null;
/** Enabled */
enabled?: boolean | null;
};
/**
* ModbusLatestResponse
* @description Response for the /latest endpoint.
*
* ``found`` is False and ``recorded_at``/``payload`` are None when the device
* has no readings yet. Callers should check ``found`` before using the values.
*/
ModbusLatestResponse: {
/** Found */
found: boolean;
/** Recorded At */
recorded_at: string | null;
/** Payload */
payload: {
[key: string]: unknown;
} | null;
};
/**
* ModbusMetricsResponse
* @description Response schema for GET /api/modbus/devices/{uuid}/metrics.
*/
ModbusMetricsResponse: {
/** Profile */
profile: string;
/** Metrics */
metrics: components["schemas"]["MetricInfo"][];
};
/**
* ModbusProfilesResponse
* @description Response schema for GET /api/modbus/profiles.
*/
ModbusProfilesResponse: {
/** Profiles */
profiles: components["schemas"]["ProfileSummary"][];
};
/**
* ModbusReadingResponse
* @description A single reading row: timestamp + decoded payload.
*/
ModbusReadingResponse: {
/**
* Recorded At
* Format: date-time
*/
recorded_at: string;
/** Payload */
payload: {
[key: string]: unknown;
};
};
/**
* ModbusReadingsResponse
* @description Response schema for the readings time-range endpoint.
*/
ModbusReadingsResponse: {
/** Items */
items: components["schemas"]["ModbusReadingResponse"][];
};
/**
* ModbusTestReadResponse
* @description Response for POST /api/modbus/devices/{uuid}/test.
*
* On success ``ok=True`` and ``payload`` contains the decoded values.
* On failure ``ok=False`` and ``error`` describes the problem.
*/
ModbusTestReadResponse: {
/** Ok */
ok: boolean;
/** Payload */
payload?: {
[key: string]: unknown;
} | null;
/** Error */
error?: string | null;
};
/** PasswordChangeRequest */
PasswordChangeRequest: {
/** Current Password */
@@ -661,6 +1050,16 @@ export interface components {
/** Longitude */
longitude?: number | null;
};
/**
* ProfileSummary
* @description One entry in the GET /api/modbus/profiles response.
*/
ProfileSummary: {
/** Name */
name: string;
/** Description */
description: string;
};
/** PublicIPCheckResponse */
PublicIPCheckResponse: {
/**
@@ -1177,6 +1576,310 @@ export interface operations {
};
};
};
get_profiles_api_modbus_profiles_get: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ModbusProfilesResponse"];
};
};
};
};
list_devices_api_modbus_devices_get: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ModbusDeviceListResponse"];
};
};
};
};
create_device_api_modbus_devices_post: {
parameters: {
query?: never;
header?: {
"X-CSRF-Token"?: string | null;
};
path?: never;
cookie?: never;
};
requestBody: {
content: {
"application/json": components["schemas"]["ModbusDeviceCreate"];
};
};
responses: {
/** @description Successful Response */
201: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ModbusDeviceResponse"];
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
get_device_api_modbus_devices__uuid__get: {
parameters: {
query?: never;
header?: never;
path: {
uuid: string;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ModbusDeviceResponse"];
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
delete_device_api_modbus_devices__uuid__delete: {
parameters: {
query?: never;
header?: {
"X-CSRF-Token"?: string | null;
};
path: {
uuid: string;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Successful Response */
204: {
headers: {
[name: string]: unknown;
};
content?: never;
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
patch_device_api_modbus_devices__uuid__patch: {
parameters: {
query?: never;
header?: {
"X-CSRF-Token"?: string | null;
};
path: {
uuid: string;
};
cookie?: never;
};
requestBody: {
content: {
"application/json": components["schemas"]["ModbusDeviceUpdate"];
};
};
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ModbusDeviceResponse"];
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
get_latest_reading_api_modbus_devices__uuid__latest_get: {
parameters: {
query?: never;
header?: never;
path: {
uuid: string;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ModbusLatestResponse"];
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
get_readings_api_modbus_devices__uuid__readings_get: {
parameters: {
query?: {
start?: string | null;
end?: string | null;
limit?: number;
};
header?: never;
path: {
uuid: string;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ModbusReadingsResponse"];
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
get_metrics_api_modbus_devices__uuid__metrics_get: {
parameters: {
query?: never;
header?: never;
path: {
uuid: string;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ModbusMetricsResponse"];
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
test_read_api_modbus_devices__uuid__test_post: {
parameters: {
query?: never;
header?: {
"X-CSRF-Token"?: string | null;
};
path: {
uuid: string;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description Successful Response */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["ModbusTestReadResponse"];
};
};
/** @description Validation Error */
422: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["HTTPValidationError"];
};
};
};
};
get_session_api_session_get: {
parameters: {
query?: never;