M5-T05: add Modbus JSON API (device CRUD, readings, metrics, test)

This commit is contained in:
2026-06-22 13:37:48 +02:00
parent 49d15d8ffe
commit 702a1cec00
7 changed files with 3060 additions and 1 deletions
+981
View File
@@ -625,6 +625,502 @@
}
}
},
"/api/modbus/profiles": {
"get": {
"tags": [
"api-modbus"
],
"summary": "Get Profiles",
"description": "List all available Modbus YAML profiles (name + description).\n\nIntended for the front-end's device-creation profile drop-down.",
"operationId": "get_profiles_api_modbus_profiles_get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ModbusProfilesResponse"
}
}
}
}
}
}
},
"/api/modbus/devices": {
"get": {
"tags": [
"api-modbus"
],
"summary": "List Devices",
"description": "Return all Modbus devices (no pagination — device counts stay small).",
"operationId": "list_devices_api_modbus_devices_get",
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ModbusDeviceListResponse"
}
}
}
}
}
},
"post": {
"tags": [
"api-modbus"
],
"summary": "Create Device",
"description": "Create a new Modbus device.\n\n- Validates that the referenced ``profile`` exists; returns 422 if not.\n- Returns 201 with the created device on success.",
"operationId": "create_device_api_modbus_devices_post",
"parameters": [
{
"name": "X-CSRF-Token",
"in": "header",
"required": false,
"schema": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "X-Csrf-Token"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ModbusDeviceCreate"
}
}
}
},
"responses": {
"201": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ModbusDeviceResponse"
}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
},
"/api/modbus/devices/{uuid}": {
"get": {
"tags": [
"api-modbus"
],
"summary": "Get Device",
"description": "Return a single Modbus device by UUID.",
"operationId": "get_device_api_modbus_devices__uuid__get",
"parameters": [
{
"name": "uuid",
"in": "path",
"required": true,
"schema": {
"type": "string",
"title": "Uuid"
}
}
],
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ModbusDeviceResponse"
}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
},
"patch": {
"tags": [
"api-modbus"
],
"summary": "Patch Device",
"description": "Partially update a Modbus device (including enable/disable).\n\nOnly fields explicitly provided in the request body are updated.\nProviding ``profile`` triggers a profile-existence check (422 if unknown).",
"operationId": "patch_device_api_modbus_devices__uuid__patch",
"parameters": [
{
"name": "uuid",
"in": "path",
"required": true,
"schema": {
"type": "string",
"title": "Uuid"
}
},
{
"name": "X-CSRF-Token",
"in": "header",
"required": false,
"schema": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "X-Csrf-Token"
}
}
],
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ModbusDeviceUpdate"
}
}
}
},
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ModbusDeviceResponse"
}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
},
"delete": {
"tags": [
"api-modbus"
],
"summary": "Delete Device",
"description": "Delete a Modbus device.\n\nReturns 409 Conflict if the device has any associated readings; use\n``enabled=false`` to disable it instead.\n\n**Application-layer safety**: the check is performed via an explicit\nSELECT COUNT query — not by relying on SQLite's FK RESTRICT constraint,\nwhich is not enforced at runtime in this project (no PRAGMA foreign_keys=ON).",
"operationId": "delete_device_api_modbus_devices__uuid__delete",
"parameters": [
{
"name": "uuid",
"in": "path",
"required": true,
"schema": {
"type": "string",
"title": "Uuid"
}
},
{
"name": "X-CSRF-Token",
"in": "header",
"required": false,
"schema": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "X-Csrf-Token"
}
}
],
"responses": {
"204": {
"description": "Successful Response"
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
},
"/api/modbus/devices/{uuid}/latest": {
"get": {
"tags": [
"api-modbus"
],
"summary": "Get Latest Reading",
"description": "Return the most recent reading for a device.\n\nIf no readings exist yet, returns ``{\"found\": false, \"recorded_at\": null,\n\"payload\": null}`` (200, not 404) so the front-end can distinguish\n\"device exists but has no data\" from \"device not found\".",
"operationId": "get_latest_reading_api_modbus_devices__uuid__latest_get",
"parameters": [
{
"name": "uuid",
"in": "path",
"required": true,
"schema": {
"type": "string",
"title": "Uuid"
}
}
],
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ModbusLatestResponse"
}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
},
"/api/modbus/devices/{uuid}/readings": {
"get": {
"tags": [
"api-modbus"
],
"summary": "Get Readings",
"description": "Return time-range readings for a device.\n\nResults are ordered by ``recorded_at`` ascending and capped by ``limit``\n(max {_READINGS_LIMIT_MAX}) to prevent accidental full-table exports.\n\nThe query uses the ``(device_id, recorded_at)`` composite index for\nefficient time-window scans.\n\nQuery parameters:\n- ``start``: inclusive lower bound (ISO8601 datetime)\n- ``end``: inclusive upper bound (ISO8601 datetime)\n- ``limit``: max rows to return (default 500, max {_READINGS_LIMIT_MAX})",
"operationId": "get_readings_api_modbus_devices__uuid__readings_get",
"parameters": [
{
"name": "uuid",
"in": "path",
"required": true,
"schema": {
"type": "string",
"title": "Uuid"
}
},
{
"name": "start",
"in": "query",
"required": false,
"schema": {
"anyOf": [
{
"type": "string",
"format": "date-time"
},
{
"type": "null"
}
],
"title": "Start"
}
},
{
"name": "end",
"in": "query",
"required": false,
"schema": {
"anyOf": [
{
"type": "string",
"format": "date-time"
},
{
"type": "null"
}
],
"title": "End"
}
},
{
"name": "limit",
"in": "query",
"required": false,
"schema": {
"type": "integer",
"maximum": 5000,
"minimum": 1,
"default": 500,
"title": "Limit"
}
}
],
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ModbusReadingsResponse"
}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
},
"/api/modbus/devices/{uuid}/metrics": {
"get": {
"tags": [
"api-modbus"
],
"summary": "Get Metrics",
"description": "Return the metric catalogue for a device's profile.\n\nEach entry has ``key``, ``label`` (derived from key if the profile has\nnone — underscores → spaces, title-cased), ``unit``, and ``device_class``.\nThis is the authoritative metadata source for front-end card labels and\nchart axis labels.",
"operationId": "get_metrics_api_modbus_devices__uuid__metrics_get",
"parameters": [
{
"name": "uuid",
"in": "path",
"required": true,
"schema": {
"type": "string",
"title": "Uuid"
}
}
],
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ModbusMetricsResponse"
}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
},
"/api/modbus/devices/{uuid}/test": {
"post": {
"tags": [
"api-modbus"
],
"summary": "Test Read",
"description": "Immediately read and decode the device once without persisting any data.\n\nUseful for validating gateway connectivity and Modbus address settings\nbefore relying on the background polling job.\n\nThis is a write-class endpoint (it initiates network I/O on demand) and\ntherefore requires a CSRF token. The response payload is never stored.",
"operationId": "test_read_api_modbus_devices__uuid__test_post",
"parameters": [
{
"name": "uuid",
"in": "path",
"required": true,
"schema": {
"type": "string",
"title": "Uuid"
}
},
{
"name": "X-CSRF-Token",
"in": "header",
"required": false,
"schema": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "X-Csrf-Token"
}
}
],
"responses": {
"200": {
"description": "Successful Response",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/ModbusTestReadResponse"
}
}
}
},
"422": {
"description": "Validation Error",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
},
"/api/session": {
"get": {
"tags": [
@@ -1367,6 +1863,472 @@
],
"title": "LoginRequest"
},
"MetricInfo": {
"properties": {
"key": {
"type": "string",
"title": "Key"
},
"label": {
"type": "string",
"title": "Label"
},
"unit": {
"type": "string",
"title": "Unit"
},
"device_class": {
"type": "string",
"title": "Device Class"
}
},
"type": "object",
"required": [
"key",
"label",
"unit",
"device_class"
],
"title": "MetricInfo",
"description": "Metadata for a single measurable quantity in a device's profile."
},
"ModbusDeviceCreate": {
"properties": {
"friendly_name": {
"type": "string",
"maxLength": 255,
"minLength": 1,
"title": "Friendly Name"
},
"transport": {
"type": "string",
"maxLength": 16,
"title": "Transport",
"default": "tcp"
},
"host": {
"type": "string",
"maxLength": 255,
"minLength": 1,
"title": "Host"
},
"port": {
"type": "integer",
"maximum": 65535.0,
"minimum": 1.0,
"title": "Port",
"default": 502
},
"unit_id": {
"type": "integer",
"maximum": 247.0,
"minimum": 0.0,
"title": "Unit Id",
"default": 1
},
"profile": {
"type": "string",
"maxLength": 64,
"minLength": 1,
"title": "Profile"
},
"poll_interval_s": {
"type": "integer",
"maximum": 3600.0,
"minimum": 1.0,
"title": "Poll Interval S",
"default": 5
},
"enabled": {
"type": "boolean",
"title": "Enabled",
"default": true
}
},
"type": "object",
"required": [
"friendly_name",
"host",
"profile"
],
"title": "ModbusDeviceCreate",
"description": "Request body for POST /api/modbus/devices."
},
"ModbusDeviceListResponse": {
"properties": {
"items": {
"items": {
"$ref": "#/components/schemas/ModbusDeviceResponse"
},
"type": "array",
"title": "Items"
},
"total": {
"type": "integer",
"title": "Total"
}
},
"type": "object",
"required": [
"items",
"total"
],
"title": "ModbusDeviceListResponse",
"description": "Response schema for listing Modbus devices."
},
"ModbusDeviceResponse": {
"properties": {
"uuid": {
"type": "string",
"title": "Uuid"
},
"friendly_name": {
"type": "string",
"title": "Friendly Name"
},
"transport": {
"type": "string",
"title": "Transport"
},
"host": {
"type": "string",
"title": "Host"
},
"port": {
"type": "integer",
"title": "Port"
},
"unit_id": {
"type": "integer",
"title": "Unit Id"
},
"profile": {
"type": "string",
"title": "Profile"
},
"poll_interval_s": {
"type": "integer",
"title": "Poll Interval S"
},
"enabled": {
"type": "boolean",
"title": "Enabled"
},
"last_poll_at": {
"anyOf": [
{
"type": "string",
"format": "date-time"
},
{
"type": "null"
}
],
"title": "Last Poll At"
},
"last_poll_ok": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"title": "Last Poll Ok"
},
"created_at": {
"type": "string",
"format": "date-time",
"title": "Created At"
},
"updated_at": {
"type": "string",
"format": "date-time",
"title": "Updated At"
}
},
"type": "object",
"required": [
"uuid",
"friendly_name",
"transport",
"host",
"port",
"unit_id",
"profile",
"poll_interval_s",
"enabled",
"last_poll_at",
"last_poll_ok",
"created_at",
"updated_at"
],
"title": "ModbusDeviceResponse",
"description": "Response schema for a single Modbus device."
},
"ModbusDeviceUpdate": {
"properties": {
"friendly_name": {
"anyOf": [
{
"type": "string",
"maxLength": 255,
"minLength": 1
},
{
"type": "null"
}
],
"title": "Friendly Name"
},
"transport": {
"anyOf": [
{
"type": "string",
"maxLength": 16
},
{
"type": "null"
}
],
"title": "Transport"
},
"host": {
"anyOf": [
{
"type": "string",
"maxLength": 255,
"minLength": 1
},
{
"type": "null"
}
],
"title": "Host"
},
"port": {
"anyOf": [
{
"type": "integer",
"maximum": 65535.0,
"minimum": 1.0
},
{
"type": "null"
}
],
"title": "Port"
},
"unit_id": {
"anyOf": [
{
"type": "integer",
"maximum": 247.0,
"minimum": 0.0
},
{
"type": "null"
}
],
"title": "Unit Id"
},
"profile": {
"anyOf": [
{
"type": "string",
"maxLength": 64,
"minLength": 1
},
{
"type": "null"
}
],
"title": "Profile"
},
"poll_interval_s": {
"anyOf": [
{
"type": "integer",
"maximum": 3600.0,
"minimum": 1.0
},
{
"type": "null"
}
],
"title": "Poll Interval S"
},
"enabled": {
"anyOf": [
{
"type": "boolean"
},
{
"type": "null"
}
],
"title": "Enabled"
}
},
"type": "object",
"title": "ModbusDeviceUpdate",
"description": "Request body for PATCH /api/modbus/devices/{uuid} — all fields optional."
},
"ModbusLatestResponse": {
"properties": {
"found": {
"type": "boolean",
"title": "Found"
},
"recorded_at": {
"anyOf": [
{
"type": "string",
"format": "date-time"
},
{
"type": "null"
}
],
"title": "Recorded At"
},
"payload": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Payload"
}
},
"type": "object",
"required": [
"found",
"recorded_at",
"payload"
],
"title": "ModbusLatestResponse",
"description": "Response for the /latest endpoint.\n\n``found`` is False and ``recorded_at``/``payload`` are None when the device\nhas no readings yet. Callers should check ``found`` before using the values."
},
"ModbusMetricsResponse": {
"properties": {
"profile": {
"type": "string",
"title": "Profile"
},
"metrics": {
"items": {
"$ref": "#/components/schemas/MetricInfo"
},
"type": "array",
"title": "Metrics"
}
},
"type": "object",
"required": [
"profile",
"metrics"
],
"title": "ModbusMetricsResponse",
"description": "Response schema for GET /api/modbus/devices/{uuid}/metrics."
},
"ModbusProfilesResponse": {
"properties": {
"profiles": {
"items": {
"$ref": "#/components/schemas/ProfileSummary"
},
"type": "array",
"title": "Profiles"
}
},
"type": "object",
"required": [
"profiles"
],
"title": "ModbusProfilesResponse",
"description": "Response schema for GET /api/modbus/profiles."
},
"ModbusReadingResponse": {
"properties": {
"recorded_at": {
"type": "string",
"format": "date-time",
"title": "Recorded At"
},
"payload": {
"additionalProperties": true,
"type": "object",
"title": "Payload"
}
},
"type": "object",
"required": [
"recorded_at",
"payload"
],
"title": "ModbusReadingResponse",
"description": "A single reading row: timestamp + decoded payload."
},
"ModbusReadingsResponse": {
"properties": {
"items": {
"items": {
"$ref": "#/components/schemas/ModbusReadingResponse"
},
"type": "array",
"title": "Items"
}
},
"type": "object",
"required": [
"items"
],
"title": "ModbusReadingsResponse",
"description": "Response schema for the readings time-range endpoint."
},
"ModbusTestReadResponse": {
"properties": {
"ok": {
"type": "boolean",
"title": "Ok"
},
"payload": {
"anyOf": [
{
"additionalProperties": true,
"type": "object"
},
{
"type": "null"
}
],
"title": "Payload"
},
"error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Error"
}
},
"type": "object",
"required": [
"ok"
],
"title": "ModbusTestReadResponse",
"description": "Response for POST /api/modbus/devices/{uuid}/test.\n\nOn success ``ok=True`` and ``payload`` contains the decoded values.\nOn failure ``ok=False`` and ``error`` describes the problem."
},
"PasswordChangeRequest": {
"properties": {
"current_password": {
@@ -1484,6 +2446,25 @@
"title": "PooUpdateRequest",
"description": "PATCH body for a poo record — all fields optional; PK field excluded."
},
"ProfileSummary": {
"properties": {
"name": {
"type": "string",
"title": "Name"
},
"description": {
"type": "string",
"title": "Description"
}
},
"type": "object",
"required": [
"name",
"description"
],
"title": "ProfileSummary",
"description": "One entry in the GET /api/modbus/profiles response."
},
"PublicIPCheckResponse": {
"properties": {
"status": {
+711
View File
@@ -452,6 +452,379 @@ paths:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
/api/modbus/profiles:
get:
tags:
- api-modbus
summary: Get Profiles
description: 'List all available Modbus YAML profiles (name + description).
Intended for the front-end''s device-creation profile drop-down.'
operationId: get_profiles_api_modbus_profiles_get
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/ModbusProfilesResponse'
/api/modbus/devices:
get:
tags:
- api-modbus
summary: List Devices
description: Return all Modbus devices (no pagination — device counts stay small).
operationId: list_devices_api_modbus_devices_get
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/ModbusDeviceListResponse'
post:
tags:
- api-modbus
summary: 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.'
operationId: create_device_api_modbus_devices_post
parameters:
- name: X-CSRF-Token
in: header
required: false
schema:
anyOf:
- type: string
- type: 'null'
title: X-Csrf-Token
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ModbusDeviceCreate'
responses:
'201':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/ModbusDeviceResponse'
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
/api/modbus/devices/{uuid}:
get:
tags:
- api-modbus
summary: Get Device
description: Return a single Modbus device by UUID.
operationId: get_device_api_modbus_devices__uuid__get
parameters:
- name: uuid
in: path
required: true
schema:
type: string
title: Uuid
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/ModbusDeviceResponse'
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
patch:
tags:
- api-modbus
summary: 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).'
operationId: patch_device_api_modbus_devices__uuid__patch
parameters:
- name: uuid
in: path
required: true
schema:
type: string
title: Uuid
- name: X-CSRF-Token
in: header
required: false
schema:
anyOf:
- type: string
- type: 'null'
title: X-Csrf-Token
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ModbusDeviceUpdate'
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/ModbusDeviceResponse'
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
delete:
tags:
- api-modbus
summary: 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).'
operationId: delete_device_api_modbus_devices__uuid__delete
parameters:
- name: uuid
in: path
required: true
schema:
type: string
title: Uuid
- name: X-CSRF-Token
in: header
required: false
schema:
anyOf:
- type: string
- type: 'null'
title: X-Csrf-Token
responses:
'204':
description: Successful Response
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
/api/modbus/devices/{uuid}/latest:
get:
tags:
- api-modbus
summary: 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".'
operationId: get_latest_reading_api_modbus_devices__uuid__latest_get
parameters:
- name: uuid
in: path
required: true
schema:
type: string
title: Uuid
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/ModbusLatestResponse'
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
/api/modbus/devices/{uuid}/readings:
get:
tags:
- api-modbus
summary: 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})'
operationId: get_readings_api_modbus_devices__uuid__readings_get
parameters:
- name: uuid
in: path
required: true
schema:
type: string
title: Uuid
- name: start
in: query
required: false
schema:
anyOf:
- type: string
format: date-time
- type: 'null'
title: Start
- name: end
in: query
required: false
schema:
anyOf:
- type: string
format: date-time
- type: 'null'
title: End
- name: limit
in: query
required: false
schema:
type: integer
maximum: 5000
minimum: 1
default: 500
title: Limit
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/ModbusReadingsResponse'
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
/api/modbus/devices/{uuid}/metrics:
get:
tags:
- api-modbus
summary: 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.'
operationId: get_metrics_api_modbus_devices__uuid__metrics_get
parameters:
- name: uuid
in: path
required: true
schema:
type: string
title: Uuid
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/ModbusMetricsResponse'
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
/api/modbus/devices/{uuid}/test:
post:
tags:
- api-modbus
summary: 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.'
operationId: test_read_api_modbus_devices__uuid__test_post
parameters:
- name: uuid
in: path
required: true
schema:
type: string
title: Uuid
- name: X-CSRF-Token
in: header
required: false
schema:
anyOf:
- type: string
- type: 'null'
title: X-Csrf-Token
responses:
'200':
description: Successful Response
content:
application/json:
schema:
$ref: '#/components/schemas/ModbusTestReadResponse'
'422':
description: Validation Error
content:
application/json:
schema:
$ref: '#/components/schemas/HTTPValidationError'
/api/session:
get:
tags:
@@ -987,6 +1360,330 @@ components:
- username
- password
title: LoginRequest
MetricInfo:
properties:
key:
type: string
title: Key
label:
type: string
title: Label
unit:
type: string
title: Unit
device_class:
type: string
title: Device Class
type: object
required:
- key
- label
- unit
- device_class
title: MetricInfo
description: Metadata for a single measurable quantity in a device's profile.
ModbusDeviceCreate:
properties:
friendly_name:
type: string
maxLength: 255
minLength: 1
title: Friendly Name
transport:
type: string
maxLength: 16
title: Transport
default: tcp
host:
type: string
maxLength: 255
minLength: 1
title: Host
port:
type: integer
maximum: 65535.0
minimum: 1.0
title: Port
default: 502
unit_id:
type: integer
maximum: 247.0
minimum: 0.0
title: Unit Id
default: 1
profile:
type: string
maxLength: 64
minLength: 1
title: Profile
poll_interval_s:
type: integer
maximum: 3600.0
minimum: 1.0
title: Poll Interval S
default: 5
enabled:
type: boolean
title: Enabled
default: true
type: object
required:
- friendly_name
- host
- profile
title: ModbusDeviceCreate
description: Request body for POST /api/modbus/devices.
ModbusDeviceListResponse:
properties:
items:
items:
$ref: '#/components/schemas/ModbusDeviceResponse'
type: array
title: Items
total:
type: integer
title: Total
type: object
required:
- items
- total
title: ModbusDeviceListResponse
description: Response schema for listing Modbus devices.
ModbusDeviceResponse:
properties:
uuid:
type: string
title: Uuid
friendly_name:
type: string
title: Friendly Name
transport:
type: string
title: Transport
host:
type: string
title: Host
port:
type: integer
title: Port
unit_id:
type: integer
title: Unit Id
profile:
type: string
title: Profile
poll_interval_s:
type: integer
title: Poll Interval S
enabled:
type: boolean
title: Enabled
last_poll_at:
anyOf:
- type: string
format: date-time
- type: 'null'
title: Last Poll At
last_poll_ok:
anyOf:
- type: boolean
- type: 'null'
title: Last Poll Ok
created_at:
type: string
format: date-time
title: Created At
updated_at:
type: string
format: date-time
title: Updated At
type: object
required:
- uuid
- friendly_name
- transport
- host
- port
- unit_id
- profile
- poll_interval_s
- enabled
- last_poll_at
- last_poll_ok
- created_at
- updated_at
title: ModbusDeviceResponse
description: Response schema for a single Modbus device.
ModbusDeviceUpdate:
properties:
friendly_name:
anyOf:
- type: string
maxLength: 255
minLength: 1
- type: 'null'
title: Friendly Name
transport:
anyOf:
- type: string
maxLength: 16
- type: 'null'
title: Transport
host:
anyOf:
- type: string
maxLength: 255
minLength: 1
- type: 'null'
title: Host
port:
anyOf:
- type: integer
maximum: 65535.0
minimum: 1.0
- type: 'null'
title: Port
unit_id:
anyOf:
- type: integer
maximum: 247.0
minimum: 0.0
- type: 'null'
title: Unit Id
profile:
anyOf:
- type: string
maxLength: 64
minLength: 1
- type: 'null'
title: Profile
poll_interval_s:
anyOf:
- type: integer
maximum: 3600.0
minimum: 1.0
- type: 'null'
title: Poll Interval S
enabled:
anyOf:
- type: boolean
- type: 'null'
title: Enabled
type: object
title: ModbusDeviceUpdate
description: Request body for PATCH /api/modbus/devices/{uuid} — all fields
optional.
ModbusLatestResponse:
properties:
found:
type: boolean
title: Found
recorded_at:
anyOf:
- type: string
format: date-time
- type: 'null'
title: Recorded At
payload:
anyOf:
- additionalProperties: true
type: object
- type: 'null'
title: Payload
type: object
required:
- found
- recorded_at
- payload
title: 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.'
ModbusMetricsResponse:
properties:
profile:
type: string
title: Profile
metrics:
items:
$ref: '#/components/schemas/MetricInfo'
type: array
title: Metrics
type: object
required:
- profile
- metrics
title: ModbusMetricsResponse
description: Response schema for GET /api/modbus/devices/{uuid}/metrics.
ModbusProfilesResponse:
properties:
profiles:
items:
$ref: '#/components/schemas/ProfileSummary'
type: array
title: Profiles
type: object
required:
- profiles
title: ModbusProfilesResponse
description: Response schema for GET /api/modbus/profiles.
ModbusReadingResponse:
properties:
recorded_at:
type: string
format: date-time
title: Recorded At
payload:
additionalProperties: true
type: object
title: Payload
type: object
required:
- recorded_at
- payload
title: ModbusReadingResponse
description: 'A single reading row: timestamp + decoded payload.'
ModbusReadingsResponse:
properties:
items:
items:
$ref: '#/components/schemas/ModbusReadingResponse'
type: array
title: Items
type: object
required:
- items
title: ModbusReadingsResponse
description: Response schema for the readings time-range endpoint.
ModbusTestReadResponse:
properties:
ok:
type: boolean
title: Ok
payload:
anyOf:
- additionalProperties: true
type: object
- type: 'null'
title: Payload
error:
anyOf:
- type: string
- type: 'null'
title: Error
type: object
required:
- ok
title: 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.'
PasswordChangeRequest:
properties:
current_password:
@@ -1064,6 +1761,20 @@ components:
type: object
title: PooUpdateRequest
description: PATCH body for a poo record — all fields optional; PK field excluded.
ProfileSummary:
properties:
name:
type: string
title: Name
description:
type: string
title: Description
type: object
required:
- name
- description
title: ProfileSummary
description: One entry in the GET /api/modbus/profiles response.
PublicIPCheckResponse:
properties:
status: