Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ if(NOT ENABLE_DATALAYERS)
list(FILTER NEURON_SRC_PARSE EXCLUDE REGEX "neu_json_datalayers\\.c$")
endif()
set(NEURON_BASE_SOURCES
src/base/property.c
src/base/tag.c
src/base/neu_plugin_common.c
src/base/tag_sort.c
Expand Down Expand Up @@ -232,6 +233,7 @@ add_subdirectory(tests/plugins/c1)
add_subdirectory(tests/plugins/s1)
add_subdirectory(tests/plugins/sc1)
add_subdirectory(tests/plugins/demo_app)
add_subdirectory(tests/plugins/auto_type)

# Set sane defaults for multi-lib linux systems
include(GNUInstallDirs)
Expand Down
128 changes: 128 additions & 0 deletions docs/api/cn/http.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Neuron 将为 IIoT 平台提供一系列 API 服务,用于查询基本信息

### 数据类型

* AUTO = 0
* INT8 = 1
* UINT8 = 2
* INT16 = 3
Expand All @@ -25,6 +26,16 @@ Neuron 将为 IIoT 平台提供一系列 API 服务,用于查询基本信息
* DWORD = 17
* LWORD = 18

### AUTO 点位

请求自动识别类型时,必须显式设置点位配置字段 `"type": 0`,省略 `type` 不等于 AUTO。驱动必须通过现有点位校验主动支持 AUTO,并返回具体类型的样本;不支持的驱动返回 `2204`。Modbus 不支持 AUTO。本次提供的是框架能力,不代表 OPC UA 等闭源驱动已接入;动态协议驱动仍需分别实现支持。

第一笔合法的成功样本确定点位的实际运行时类型,在该点位 cache 生命周期内固定。识别前,读取和写入返回 `3011`(点位未就绪)。之后收到不同语义类型的样本时返回 `3007`(类型不匹配),但不改变已识别类型。通信错误也不会清除类型,恢复原类型的样本后可继续正常采集。点位或组 cache 重建(包括重启)会重新识别,单纯断线不会重置。

AUTO 必须用于可读点位;仅写 AUTO 点位返回 `2204`。识别后,单点及批量写入均按具体类型检查输入类型和数值范围,再交给驱动。例如 INT16 可接受整数 `123`,但拒绝 `40000` 和字符串 `"123"`。已排队写入若因点位或组 cache 重建失效,返回 `3011`,不会按另一类型重新解释。

配置查询、导出和持久化存储始终保留 `type: 0`,不会回写识别结果,也不新增 `resolved_type` 字段。读取和上报值使用已识别的具体类型,并应用该类型适用的 precision、缩放及地址选项。非数值类型不进行数值缩放,缩放后的输出类型也不会改变设备侧已识别类型。

### 波特率

* 115200 = 0
Expand Down Expand Up @@ -299,6 +310,123 @@ Neuron 将为 IIoT 平台提供一系列 API 服务,用于查询基本信息
}
```

## Node 自定义属性

自定义属性是节点的 key/value 元数据,南向驱动节点和北向应用节点均支持。四种操作统一使用 **/api/v2/node/properties**,且节点必须已存在。

属性的 JSON 值类型在查询和重启后保持不变。节点重命名后,属性随节点迁移到新名称;删除节点时,其属性一并删除。重新创建同名节点不会恢复已删除的属性。

### 请求头部

**Authorization** Bearer \<token\>(登录接口返回的 JWT,鉴权规则与其他节点接口一致)

**Content-Type** application/json(POST、PUT、DELETE)

### 键和值

* `node`、`key` 为必填非空字符串,不允许包含 NUL(`\u0000`)。同一节点内的属性 key 唯一。
* `value` 必填,`false`、`0`、`""`、`[]` 均为有效值,不能因其为空或为零而省略。请直接传入 JSON 值,不要将其再次编码成 JSON 字符串。
* 支持的标量值:字符串、布尔值、整数、浮点数。整数范围为有符号 64 位;浮点数必须是可用双精度表示的有限数值。
* 支持的一维数组:元素全部为字符串、全部为布尔值或全部为数值。数值数组允许整数和浮点数混用,例如 `[1, 2.5]`。允许空数组。
* 不接受 `null`、对象、嵌套数组及不同类别混合的数组,例如 `[true, 1]`、`[1, "2"]`。字符串值允许包含转义 NUL(`\u0000`)及其他转义字符。
* POST 的 `properties` 和 DELETE 的 `keys` 必须为非空数组,批次内不允许重复 key,每项都必须合法。批次操作是原子的:全部成功或完全不修改。

### 获取属性

*GET* **/api/v2/node/properties?node=modbus-tcp-node**

查询参数 `node` 必填。节点名称包含特殊字符时需进行 URL 编码。

HTTP 200 响应:

```json
{
"properties": [
{"key": "location", "value": "Building A"},
{"key": "enabled", "value": false},
{"key": "thresholds", "value": [0, 12.5]}
]
}
```

节点没有属性时返回 `{"properties": []}`。响应值保持原有 JSON 类型;客户端应按 key 识别属性,不依赖数组中的位置。

### 新增属性

*POST* **/api/v2/node/properties**

```json
{
"node": "modbus-tcp-node",
"properties": [
{"key": "location", "value": "Building A"},
{"key": "enabled", "value": false},
{"key": "thresholds", "value": [0, 12.5]}
]
}
```

所有 key 都必须是新属性。任一 key 已存在时,拒绝整个批次,不会新增或覆盖任何属性。

HTTP 200 响应:

```json
{"error": 0}
```

### 更新单个属性

*PUT* **/api/v2/node/properties**

```json
{
"node": "modbus-tcp-node",
"key": "enabled",
"value": true
}
```

替换一个已有属性的值,新值可以变为其他支持的类型。此操作不会创建不存在的属性,也不能重命名 key。

HTTP 200 响应:

```json
{"error": 0}
```

### 删除属性

*DELETE* **/api/v2/node/properties**

```json
{
"node": "modbus-tcp-node",
"keys": ["location", "enabled"]
}
```

原子地删除指定 key。不存在的 key 会被忽略,即使所有指定 key 都不存在也返回成功。空 `keys` 数组不表示删除全部属性,而是非法请求。

HTTP 200 响应:

```json
{"error": 0}
```

### 响应状态

| HTTP 状态 | 错误码 | 含义 |
| --- | --- | --- |
| 200 | 0 | POST、PUT、DELETE 成功;GET 返回上述 properties 对象 |
| 400 | 1002 | JSON 请求体、必填字段、key、value 或批次不合法 |
| 400 | 1003 | GET 查询参数缺失或不合法 |
| 401 / 403 | 现有 JWT 错误码 | 令牌缺失、格式错误、过期或无效,遵循现有鉴权规则 |
| 404 | 2003 | 节点不存在,适用于全部四种操作 |
| 404 | 2020 | 属性不存在,仅适用于 PUT |
| 409 | 2019 | 属性已存在,仅适用于 POST;整个批次保持不变 |

错误响应格式为 `{"error": <错误码>}`。

## 获取 Node

*GET* /api/v2/node
Expand Down
128 changes: 128 additions & 0 deletions docs/api/english/http.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Neuron provide a series of API services for IIoT platform, to query the basic in

### Data Type

* AUTO = 0
* INT8 = 1
* UINT8 = 2
* INT16 = 3
Expand All @@ -25,6 +26,16 @@ Neuron provide a series of API services for IIoT platform, to query the basic in
* DWORD = 17
* LWORD = 18

### AUTO tags

Set the required tag configuration field explicitly to `"type": 0` to request automatic type detection. Omitting `type` is not equivalent to AUTO. A driver must opt in through its existing tag validation and return concrete sample types; unsupported drivers reject AUTO with error `2204`. Modbus does not support AUTO. This framework support does not mean that closed-source drivers such as OPC UA have been integrated; each dynamic protocol driver requires its own implementation.

The first valid, successful sample fixes the concrete runtime type for that tag's cache lifecycle. Before detection, reads and writes return `3011` (tag not ready). Later samples with a different semantic type return `3007` (type mismatch), without changing the detected type. Communication errors also preserve it, and sampling recovers when the original type returns. Rebuilding the tag/group cache, including a restart, resets detection; a disconnection alone does not.

AUTO requires a readable tag; write-only AUTO is rejected with `2204`. After detection, single and batch writes are checked against the concrete type, including input type and numeric range, before the driver receives them. For example, an INT16 tag accepts integer `123`, but rejects `40000` and string `"123"`. Writes invalidated by a tag/group cache rebuild return `3011` rather than being reinterpreted with another type.

Configuration queries, exports and persistent storage continue to show `type: 0`; detection does not rewrite metadata or add a `resolved_type` field. Read/report values use the detected concrete type and its applicable precision, scaling and address options. Numeric scaling does not apply to nonnumeric types, and a scaled output value does not change the detected device type.

### Baud

* 115200 = 0
Expand Down Expand Up @@ -291,6 +302,123 @@ Neuron provide a series of API services for IIoT platform, to query the basic in
}
```

## Node Properties

Node properties are custom key/value metadata for both southbound driver nodes and northbound application nodes. All four operations use **/api/v2/node/properties** and require an existing node.

Properties retain their JSON value types across reads and restarts. Renaming a node moves its properties to the new name; deleting a node also deletes its properties. Recreating a node with the same name starts with no properties.

### Request Headers

**Authorization** Bearer \<token\> (JWT returned by the login API, using the same authentication rules as other node APIs)

**Content-Type** application/json (POST, PUT and DELETE)

### Keys and Values

* `node` and `key` are required, non-empty strings and must not contain NUL (`\u0000`). Keys are unique within a node.
* `value` is required, including when it is `false`, `0`, `""` or `[]`. It is a JSON value, not a JSON-encoded string.
* Supported scalar values: string, boolean, integer and floating-point number. Integers use the signed 64-bit range; floating-point numbers must be finite and representable as double precision.
* Supported arrays: one-dimensional arrays containing only strings, only booleans, or only numbers. Integers and floating-point numbers may be mixed in a numeric array, for example `[1, 2.5]`. Empty arrays are allowed.
* `null`, objects, nested arrays and mixed-category arrays such as `[true, 1]` or `[1, "2"]` are rejected. JSON string values may contain escaped NUL (`\u0000`) and other escaped characters.
* POST `properties` and DELETE `keys` must be non-empty arrays, without duplicate keys. Every item must be valid. A batch either succeeds in full or makes no changes.

### Get Properties

*GET* **/api/v2/node/properties?node=modbus-tcp-node**

The `node` query parameter is required. URL-encode the node name when needed.

HTTP 200 response:

```json
{
"properties": [
{"key": "location", "value": "Building A"},
{"key": "enabled", "value": false},
{"key": "thresholds", "value": [0, 12.5]}
]
}
```

A node without properties returns `{"properties": []}`. The response contains JSON values with their original types; clients should identify properties by key rather than array position.

### Add Properties

*POST* **/api/v2/node/properties**

```json
{
"node": "modbus-tcp-node",
"properties": [
{"key": "location", "value": "Building A"},
{"key": "enabled", "value": false},
{"key": "thresholds", "value": [0, 12.5]}
]
}
```

All keys must be new. If any key already exists, the entire batch is rejected without adding or replacing any properties.

HTTP 200 response:

```json
{"error": 0}
```

### Update a Property

*PUT* **/api/v2/node/properties**

```json
{
"node": "modbus-tcp-node",
"key": "enabled",
"value": true
}
```

Replaces the value of one existing property. The new value may have a different supported type. This operation does not create a missing property or rename its key.

HTTP 200 response:

```json
{"error": 0}
```

### Delete Properties

*DELETE* **/api/v2/node/properties**

```json
{
"node": "modbus-tcp-node",
"keys": ["location", "enabled"]
}
```

Deletes the listed keys atomically. Missing keys are ignored and do not cause an error, including when all listed keys are missing. An empty `keys` array is not a request to delete all properties and is rejected.

HTTP 200 response:

```json
{"error": 0}
```

### Response Status

| HTTP status | Error | Meaning |
| --- | --- | --- |
| 200 | 0 | POST, PUT or DELETE succeeded; GET returns the properties object shown above |
| 400 | 1002 | Invalid JSON body, missing required fields or invalid keys/values/batch |
| 400 | 1003 | Missing or invalid GET query parameter |
| 401 / 403 | Existing JWT error codes | Missing, malformed, expired or invalid token, following the existing authentication rules |
| 404 | 2003 | Node does not exist (all four operations) |
| 404 | 2020 | Property does not exist (PUT only) |
| 409 | 2019 | A property already exists (POST only); the entire batch is unchanged |

Error responses use `{"error": <error code>}`.

## Get Node

*GET* /api/v2/node
Expand Down
2 changes: 2 additions & 0 deletions include/neuron/errcodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ typedef enum {
NEU_ERR_NODE_TAGS_TOO_LONG = 2016,
NEU_ERR_NODE_TAGS_TOO_MANY = 2017,
NEU_ERR_NODE_TAGS_INVALID = 2018,
NEU_ERR_NODE_PROPERTY_EXIST = 2019,
NEU_ERR_NODE_PROPERTY_NOT_EXIST = 2020,

NEU_ERR_GROUP_ALREADY_SUBSCRIBED = 2101,
NEU_ERR_GROUP_NOT_SUBSCRIBE = 2102,
Expand Down
Loading
Loading