Browse Source
实现了通过设备ID和时间范围查询设备数据的功能,包括: 1. 新增查询参数DTO和返回值VO 2. 在CommonService中添加接口定义并实现查询逻辑 3. 在CommonController中添加对外接口路由 4. 补充完整的技能文档和OpenAPI接口文档zhc
11 changed files with 669 additions and 0 deletions
Binary file not shown.
@ -0,0 +1,19 @@ |
|||
package com.techsor.datacenter.business.dto.data; |
|||
|
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import lombok.Data; |
|||
|
|||
import java.util.List; |
|||
|
|||
@Data |
|||
public class QueryDeviceDataParams { |
|||
|
|||
@Schema(description = "Device ID list", example = "[\"FFFF0001\",\"FFFF0002\"]", required = true) |
|||
private List<String> deviceIds; |
|||
|
|||
@Schema(description = "Start time, Unix milliseconds timestamp", example = "1709870240425", required = true) |
|||
private Long startTime; |
|||
|
|||
@Schema(description = "End time, Unix milliseconds timestamp", example = "1709889240425", required = true) |
|||
private Long endTime; |
|||
} |
|||
@ -0,0 +1,41 @@ |
|||
package com.techsor.datacenter.business.vo.data; |
|||
|
|||
import io.swagger.v3.oas.annotations.media.Schema; |
|||
import lombok.Data; |
|||
|
|||
@Data |
|||
public class DeviceDataVO { |
|||
|
|||
@Schema(description = "Device ID", example = "FFFF0001") |
|||
private String deviceId; |
|||
|
|||
@Schema(description = "Device name", example = "温度传感器") |
|||
private String deviceName; |
|||
|
|||
@Schema(description = "Raw data JSON", example = "{\"temp\":25.5}") |
|||
private String rawData; |
|||
|
|||
@Schema(description = "Device data values, comma-separated", example = "25.5") |
|||
private String dataValue; |
|||
|
|||
@Schema(description = "Receive timestamp (milliseconds)", example = "1709870240425") |
|||
private Long receiveTs; |
|||
|
|||
@Schema(description = "Status", example = "UP") |
|||
private String status; |
|||
|
|||
@Schema(description = "Alert level", example = "1") |
|||
private String alertLevel; |
|||
|
|||
@Schema(description = "Alert content", example = "温度异常") |
|||
private String alertContent; |
|||
|
|||
@Schema(description = "Building info", example = "东京建物日本桥ビル") |
|||
private String buildingInfo; |
|||
|
|||
@Schema(description = "Floor info", example = "3F") |
|||
private String floorInfo; |
|||
|
|||
@Schema(description = "Space info", example = "会議室A") |
|||
private String spaceInfo; |
|||
} |
|||
Binary file not shown.
@ -0,0 +1,236 @@ |
|||
{ |
|||
"openapi": "3.0.0", |
|||
"info": { |
|||
"title": "Device Data Query API", |
|||
"description": "通过设备ID列表和时间范围查询设备数据的接口文档", |
|||
"version": "1.0.0" |
|||
}, |
|||
"servers": [ |
|||
{ |
|||
"url": "https://api.example.com", |
|||
"description": "Production Server" |
|||
} |
|||
], |
|||
"paths": { |
|||
"/common/queryDeviceData": { |
|||
"post": { |
|||
"summary": "Query device data by device IDs and time range", |
|||
"description": "根据设备ID列表和时间范围查询Aurora中的设备原始数据,支持跨天查询但时间跨度不能超过7天", |
|||
"tags": ["CommonController"], |
|||
"parameters": [ |
|||
{ |
|||
"name": "Apikey", |
|||
"in": "header", |
|||
"required": true, |
|||
"schema": { |
|||
"type": "string" |
|||
}, |
|||
"description": "API key for authentication, provided by user" |
|||
}, |
|||
{ |
|||
"name": "Referer", |
|||
"in": "header", |
|||
"required": true, |
|||
"schema": { |
|||
"type": "string" |
|||
}, |
|||
"description": "Request source domain, must match server's accessControlAllowOrigin config (e.g. https://bilplartform-stg.ifmservice.jp)" |
|||
} |
|||
], |
|||
"requestBody": { |
|||
"description": "Query parameters including device IDs and time range", |
|||
"required": true, |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/QueryDeviceDataParams" |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
"responses": { |
|||
"200": { |
|||
"description": "Successful operation", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/SimpleDataResponse_List_DeviceDataVO" |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
"400": { |
|||
"description": "Bad request - validation error", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/SimpleDataResponse" |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
"401": { |
|||
"description": "Unauthorized - invalid API key", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/SimpleDataResponse" |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
"500": { |
|||
"description": "Internal server error", |
|||
"content": { |
|||
"application/json": { |
|||
"schema": { |
|||
"$ref": "#/components/schemas/SimpleDataResponse" |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
"components": { |
|||
"schemas": { |
|||
"QueryDeviceDataParams": { |
|||
"type": "object", |
|||
"required": ["deviceIds", "startTime", "endTime"], |
|||
"properties": { |
|||
"deviceIds": { |
|||
"type": "array", |
|||
"items": { |
|||
"type": "string" |
|||
}, |
|||
"description": "Device ID list", |
|||
"example": ["FFFF0001", "FFFF0002"] |
|||
}, |
|||
"startTime": { |
|||
"type": "integer", |
|||
"format": "int64", |
|||
"description": "Start time, Unix milliseconds timestamp", |
|||
"example": 1709870240425 |
|||
}, |
|||
"endTime": { |
|||
"type": "integer", |
|||
"format": "int64", |
|||
"description": "End time, Unix milliseconds timestamp (must not exceed 7 days from startTime)", |
|||
"example": 1709889240425 |
|||
} |
|||
} |
|||
}, |
|||
"DeviceDataVO": { |
|||
"type": "object", |
|||
"properties": { |
|||
"deviceId": { |
|||
"type": "string", |
|||
"description": "Device ID", |
|||
"example": "FFFF0001" |
|||
}, |
|||
"deviceName": { |
|||
"type": "string", |
|||
"description": "Device name", |
|||
"example": "温度传感器" |
|||
}, |
|||
"rawData": { |
|||
"type": "string", |
|||
"description": "Raw data JSON", |
|||
"example": "{\"temp\":25.5}" |
|||
}, |
|||
"dataValue": { |
|||
"type": "string", |
|||
"description": "Device data values, comma-separated", |
|||
"example": "25.5" |
|||
}, |
|||
"receiveTs": { |
|||
"type": "integer", |
|||
"format": "int64", |
|||
"description": "Receive timestamp (milliseconds)", |
|||
"example": 1709870240425 |
|||
}, |
|||
"status": { |
|||
"type": "string", |
|||
"description": "Status", |
|||
"example": "UP" |
|||
}, |
|||
"alertLevel": { |
|||
"type": "string", |
|||
"description": "Alert level", |
|||
"example": "1" |
|||
}, |
|||
"alertContent": { |
|||
"type": "string", |
|||
"description": "Alert content", |
|||
"example": "温度异常" |
|||
}, |
|||
"buildingInfo": { |
|||
"type": "string", |
|||
"description": "Building info", |
|||
"example": "东京建物日本桥ビル" |
|||
}, |
|||
"floorInfo": { |
|||
"type": "string", |
|||
"description": "Floor info", |
|||
"example": "3F" |
|||
}, |
|||
"spaceInfo": { |
|||
"type": "string", |
|||
"description": "Space info", |
|||
"example": "会議室A" |
|||
} |
|||
} |
|||
}, |
|||
"SimpleDataResponse": { |
|||
"type": "object", |
|||
"properties": { |
|||
"code": { |
|||
"type": "integer", |
|||
"description": "Status code, 0 or 200 indicates success", |
|||
"example": 0 |
|||
}, |
|||
"msg": { |
|||
"type": "string", |
|||
"description": "Response message", |
|||
"example": "success" |
|||
}, |
|||
"data": { |
|||
"description": "Response data (null on error)" |
|||
}, |
|||
"errorMap": { |
|||
"type": "object", |
|||
"additionalProperties": { |
|||
"type": "string" |
|||
}, |
|||
"description": "Detailed error information", |
|||
"example": { |
|||
"deviceIds": "Device ID list is required" |
|||
} |
|||
} |
|||
} |
|||
}, |
|||
"SimpleDataResponse_List_DeviceDataVO": { |
|||
"type": "object", |
|||
"properties": { |
|||
"code": { |
|||
"type": "integer", |
|||
"description": "Status code, 0 or 200 indicates success", |
|||
"example": 0 |
|||
}, |
|||
"msg": { |
|||
"type": "string", |
|||
"description": "Response message", |
|||
"example": "success" |
|||
}, |
|||
"data": { |
|||
"type": "array", |
|||
"items": { |
|||
"$ref": "#/components/schemas/DeviceDataVO" |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Binary file not shown.
Binary file not shown.
@ -0,0 +1,239 @@ |
|||
--- |
|||
name: "query-device-data" |
|||
description: "Queries device raw data from Aurora by device IDs and time range via /common/queryDeviceData API. Invoke when user needs to retrieve device telemetry/historical data with device ID list and time range." |
|||
--- |
|||
|
|||
# Query Device Data |
|||
|
|||
通过设备ID列表和时间范围查询 Aurora 中的设备原始数据。 |
|||
|
|||
## 触发条件 |
|||
|
|||
当用户需要按设备ID列表和时间范围查询设备原始数据时调用此 skill。 |
|||
|
|||
用户可能用自然语言表达,例如: |
|||
- "查询设备A和设备B昨天的数据" |
|||
- "查一下FT0001最近3天的数据" |
|||
- "看看FFFF0001今天的数据" |
|||
- "获取设备A和C在2024年1月1日到1月5日的数据" |
|||
|
|||
## API 信息 |
|||
|
|||
| 项目 | 内容 | |
|||
|------|------| |
|||
| 接口路径 | `POST /common/queryDeviceData` | |
|||
| 认证方式 | Header 传入 `Apikey` | |
|||
| Referer 校验 | Header 需传入 `Referer`(值为服务端域名),否则被过滤器拦截返回 403 | |
|||
| 时间范围限制 | 最多7天 | |
|||
| 数据源 | Aurora 数据库 `rawData_yyyy_MM_dd` 分表 | |
|||
|
|||
## 自然语言转 API 参数 |
|||
|
|||
### 1. 时间范围解析 |
|||
|
|||
用户可能会用各种方式描述时间,需要根据当前时间(`Today's date`)计算出对应的毫秒时间戳。 |
|||
|
|||
| 自然语言表达 | 转换为 API 参数 | |
|||
|:-------------|:----------------| |
|||
| "最近 X 天 / 近 X 天 / 过去 X 天" | `startTime` = 当前日期往前推 X 天 的 00:00:00(时区 Asia/Tokyo),`endTime` = 当前时间的 23:59:59 | |
|||
| "昨天" | `startTime` = 昨天 00:00:00,`endTime` = 昨天 23:59:59 | |
|||
| "今天" | `startTime` = 今天 00:00:00,`endTime` = 当前时间 | |
|||
| "今天 x 点到 y 点" | `startTime` = 今天 x:00:00,`endTime` = 今天 y:59:59 | |
|||
| "2024年1月1日到2024年1月5日" | `startTime` = 2024-01-01 00:00:00,`endTime` = 2024-01-05 23:59:59 | |
|||
| "X月Y日到X月Y日" | 根据当前年份推算,`startTime` = X月Y日 00:00:00,`endTime` = X月Y日 23:59:59 | |
|||
| "上个月" | `startTime` = 上个月1号 00:00:00,`endTime` = 上个月最后一天 23:59:59 | |
|||
| "最近X小时" | `startTime` = 当前时间往前推X小时,`endTime` = 当前时间 | |
|||
|
|||
**注意**: |
|||
- 所有时间戳需要转换为 **毫秒**(13位数字) |
|||
- 时区统一使用 `Asia/Tokyo` |
|||
- `startTime` 和 `endTime` 之间的跨度不能超过 **7 天** |
|||
|
|||
### 2. 设备ID解析 |
|||
|
|||
请求参数要求传入 `deviceIds`(设备ID列表),用户可能会用不同方式描述设备: |
|||
|
|||
| 自然语言表达 | 转换方式 | |
|||
|:-------------|:---------| |
|||
| "设备A"、"设备B" | 如果用户提及设备名/编号,先根据上下文尝试确定是否为已知设备ID | |
|||
| "FFFF0001"、"FT0001" | 直接作为设备ID使用 | |
|||
| "所有设备"、"全部设备" | **不支持**,需要用户提供具体的设备ID列表 | |
|||
| "传感器A"、"温度计1" | 如果已知设备ID和名称的映射关系,转换为对应设备ID | |
|||
|
|||
如果用户只说了设备名称但没有提供具体ID,需要向用户确认具体的设备ID。 |
|||
|
|||
### 3. 请求头解析 |
|||
|
|||
- `Apikey` 由用户提供,**不设置默认值** |
|||
- 如果用户没有提供 Apikey,需要向用户询问具体的 Apikey 值 |
|||
|
|||
## 自然语言处理流程 |
|||
|
|||
当收到自然语言请求时,按以下步骤执行: |
|||
|
|||
``` |
|||
1. 提取时间描述 → 计算 startTime/endTime(毫秒时间戳) |
|||
2. 提取设备描述 → 构建设备ID列表 deviceIds |
|||
3. 检查参数完整性:如有缺漏,向用户询问补齐 |
|||
4. 检查 Apikey:如用户未提供,向用户询问 |
|||
5. 检查 Referer:如用户未提供,向用户询问 |
|||
6. 构建请求体 JSON 并设置请求头(Apikey、Referer) |
|||
7. 调用 POST /common/queryDeviceData |
|||
8. 返回结果给用户 |
|||
``` |
|||
|
|||
### 参数不完整时的处理 |
|||
|
|||
**所有参数不设默认值**,缺失时需向用户询问。 |
|||
|
|||
| 缺失参数 | 询问示例 | |
|||
|:---------|:---------| |
|||
| 未提供 `deviceIds` | "请问要查询哪些设备的ID?请提供设备ID列表。" | |
|||
| 未提供时间范围 | "请问要查询什么时间范围的数据?例如:最近3天、昨天、或指定日期区间。" | |
|||
| 仅提供开始/结束时间之一 | 补齐另一个时间点,例如:用户只说"从2024年1月1日开始",则询问"请问结束时间是什么时候?" | |
|||
| 未提供 `Apikey` | "请提供用于认证的 Apikey。" | |
|||
| 未提供 `Referer` | "请提供请求来源域名(Referer),例如服务的域名地址。" | |
|||
|
|||
### 处理后响应模板 |
|||
|
|||
调用接口后将结果以自然语言呈现给用户: |
|||
- 查询到数据时:告知用户共查询到多少条数据,以及设备的主要信息摘要 |
|||
- 未查询到数据时:告知用户在指定时间范围内没有找到对应设备的数据 |
|||
- 接口报错时:将错误信息展示给用户 |
|||
|
|||
## 请求参数 |
|||
|
|||
### Header |
|||
|
|||
| 参数名 | 必填 | 说明 | |
|||
|--------|:----:|------| |
|||
| `Apikey` | 是 | API key,用于认证,由用户提供 | |
|||
| `Referer` | 是 | 请求来源域名,需与服务端配置的 `accessControlAllowOrigin` 匹配(例如 `https://bilplartform-stg.ifmservice.jp`),否则返回 403 | |
|||
|
|||
### Request Body (JSON) |
|||
|
|||
| 字段 | 类型 | 必填 | 说明 | |
|||
|------|:----:|:----:|------| |
|||
| `deviceIds` | `List<String>` | 是 | 设备ID列表,由用户提供 | |
|||
| `startTime` | `Long` | 是 | 开始时间戳(毫秒,也支持秒级自动转换),由用户提供或根据用户描述计算 | |
|||
| `endTime` | `Long` | 是 | 结束时间戳(毫秒,也支持秒级自动转换),与 startTime 跨度不能超过7天,由用户提供或根据用户描述计算 | |
|||
|
|||
## 返回数据 |
|||
|
|||
返回 `SimpleDataResponse<List<DeviceDataVO>>`,其中 `data` 为设备数据列表: |
|||
|
|||
| 字段 | 类型 | 说明 | |
|||
|------|:----:|------| |
|||
| `deviceId` | String | 设备ID | |
|||
| `deviceName` | String | 设备名称 | |
|||
| `rawData` | String | 原始数据 JSON | |
|||
| `dataValue` | String | 从 rawData 解析出的数值,逗号拼接 | |
|||
| `receiveTs` | Long | 接收时间戳(毫秒) | |
|||
| `status` | String | 状态 | |
|||
| `alertLevel` | String | 告警级别 | |
|||
| `alertContent` | String | 告警内容 | |
|||
| `buildingInfo` | String | 楼宇信息 | |
|||
| `floorInfo` | String | 楼层信息 | |
|||
| `spaceInfo` | String | 空间信息 | |
|||
|
|||
## 调用示例 |
|||
|
|||
### 请求 |
|||
|
|||
``` |
|||
POST /common/queryDeviceData |
|||
Apikey: <用户提供的Apikey> |
|||
Referer: <服务端域名,例如 https://bilplartform-stg.ifmservice.jp> |
|||
``` |
|||
|
|||
```json |
|||
{ |
|||
"deviceIds": ["FFFF0001", "FFFF0002"], |
|||
"startTime": 1709870240425, |
|||
"endTime": 1709889240425 |
|||
} |
|||
``` |
|||
|
|||
### 成功响应 |
|||
|
|||
```json |
|||
{ |
|||
"code": 0, |
|||
"msg": "success", |
|||
"data": [ |
|||
{ |
|||
"deviceId": "FFFF0001", |
|||
"deviceName": "温度传感器", |
|||
"rawData": "{\"temp\":25.5}", |
|||
"dataValue": "25.5", |
|||
"receiveTs": 1709870240425, |
|||
"status": "UP", |
|||
"alertLevel": null, |
|||
"alertContent": null, |
|||
"buildingInfo": "东京建物日本桥ビル", |
|||
"floorInfo": "3F", |
|||
"spaceInfo": "会議室A" |
|||
} |
|||
] |
|||
} |
|||
``` |
|||
|
|||
### 错误响应示例 |
|||
|
|||
```json |
|||
{ |
|||
"code": 20001, |
|||
"msg": "[deviceIds] is required", |
|||
"data": null |
|||
} |
|||
``` |
|||
|
|||
## 自然语言用例映射 |
|||
|
|||
### 用例1:查询某设备最近N天的数据 |
|||
|
|||
> 用户说:**"查一下设备FFFF0001最近3天的数据"** |
|||
|
|||
``` |
|||
步骤: |
|||
1. 假设 Today's date = 2026-06-01 |
|||
2. 计算 startTime = 2026-05-30 00:00:00 JST → 毫秒时间戳 |
|||
3. 计算 endTime = 2026-06-01 23:59:59 JST → 毫秒时间戳 |
|||
4. deviceIds = ["FFFF0001"] |
|||
5. 调用接口 |
|||
``` |
|||
|
|||
### 用例2:查询多个设备特定日期的数据 |
|||
|
|||
> 用户说:**"查询FFFF0001和FT0002在2024年1月1日的数据"** |
|||
|
|||
``` |
|||
步骤: |
|||
1. 计算 startTime = 2024-01-01 00:00:00 JST → 毫秒时间戳 |
|||
2. 计算 endTime = 2024-01-01 23:59:59 JST → 毫秒时间戳 |
|||
3. deviceIds = ["FFFF0001", "FT0002"] |
|||
4. 调用接口 |
|||
``` |
|||
|
|||
### 用例3:查询设备今天的数据 |
|||
|
|||
> 用户说:**"看看FT0001今天的监测数据"** |
|||
|
|||
``` |
|||
步骤: |
|||
1. 假设 Today's date = 2026-06-01 |
|||
2. 计算 startTime = 2026-06-01 00:00:00 JST → 毫秒时间戳 |
|||
3. 计算 endTime = 当前时间 JST → 毫秒时间戳 |
|||
4. deviceIds = ["FT0001"] |
|||
5. 调用接口 |
|||
``` |
|||
|
|||
## 注意事项 |
|||
|
|||
1. `startTime` 和 `endTime` 支持毫秒和秒级时间戳(< 10000000000L 时自动按秒处理) |
|||
2. 时间跨度不能超过 **7 天**,否则接口会返回错误 |
|||
3. 跨天查询时自动查询多张 `rawData_yyyy_MM_dd` 分表并合并结果 |
|||
4. 使用 Apikey 认证,与 `/common/queryDeviceInfo` 相同的方式 |
|||
5. 所有时间计算都基于 `Asia/Tokyo` 时区 |
|||
6. Apikey 和所有请求参数均**不设置默认值**,缺失时需向用户询问补齐 |
|||
7. **Referer 头必传**:请求必须携带 `Referer` 头,否则被 `CrosXssFilter` 过滤器拦截返回 403。Referer 值需与服务端配置的 `accessControlAllowOrigin` 匹配(通常为服务域名本身,如 `https://bilplartform-stg.ifmservice.jp`) |
|||
Loading…
Reference in new issue