跳到主内容

REST API

API 参考

REST API

EnerOS REST API 遵循 RESTful 规范,使用标准 HTTP 方法语义,所有响应体为 JSON。端点由 eneros-api crate 提供,经 eneros-gateway 校验后转发至内核。每个端点都经过完整的鉴权、限流、审计链路。

通用约定

HTTP 方法语义

方法语义幂等安全请求体典型用途
GET读取资源查询列表/详情
POST创建资源 / 触发动作创建网络、触发潮流
PUT全量更新资源替换资源
PATCH部分更新资源修改字段
DELETE删除资源删除资源

端点列表

方法路径说明鉴权限流
GET/api/v1/health健康检查60/min
POST/api/v1/auth/token获取 Token30/min
POST/api/v1/auth/refresh刷新 Token30/min
GET/api/v1/networks电网列表600/min
POST/api/v1/networks创建电网60/min
GET/api/v1/networks/{id}电网详情600/min
PUT/api/v1/networks/{id}更新电网60/min
DELETE/api/v1/networks/{id}删除电网30/min
POST/api/v1/networks/{id}/powerflow触发潮流计算30/min
POST/api/v1/networks/{id}/validate校验拓扑60/min
GET/api/v1/agentsAgent 列表600/min
POST/api/v1/agents创建 Agent60/min
GET/api/v1/agents/{id}Agent 详情600/min
PUT/api/v1/agents/{id}更新 Agent 配置60/min
DELETE/api/v1/agents/{id}删除 Agent30/min
POST/api/v1/agents/{id}/command下发 Agent 指令100/min
POST/api/v1/agents/{id}/pause暂停 Agent60/min
POST/api/v1/agents/{id}/resume恢复 Agent60/min
GET/api/v1/devices设备列表600/min
GET/api/v1/devices/{id}设备详情600/min
PATCH/api/v1/devices/{id}更新设备状态60/min
GET/api/v1/timeseries时序数据查询600/min
POST/api/v1/timeseries/batch批量写入时序1000/min
GET/api/v1/events事件历史600/min
GET/api/v1/alarms告警列表600/min
PATCH/api/v1/alarms/{id}/ack确认告警60/min
GET/api/v1/audit审计日志600/min
GET/api/v1/tasks/{id}任务状态查询600/min
DELETE/api/v1/tasks/{id}取消任务30/min

分页、过滤、排序

分页参数

列表端点统一支持以下分页参数:

参数类型必填默认值说明
pageint1页码,从 1 开始
page_sizeint20每页数量,最大 100
cursorstring游标(用于游标分页,优先于 page)

分页响应:

{
  "data": [/* ... */],
  "meta": {
    "page": 1,
    "page_size": 20,
    "total": 137,
    "total_pages": 7,
    "next_cursor": "eyJpZCI6Im5ldF94eHgifQ=="
  }
}

过滤参数

各端点支持的过滤字段示例:

端点过滤字段示例
/networksstatus, name?status=ready&name=IEEE
/agentsstatus, type?status=running&type=dispatch
/devicestype, online?type=PV&online=true
/alarmsseverity, status, from, to?severity=critical&from=2026-07-06T00:00:00Z
/eventstopic, from, to?topic=alarm.critical&from=...

排序参数

参数类型必填默认值说明
sortstring-created_at字段名前缀 - 表示降序
sort 多字段string逗号分隔,如 name,-created_at

示例:?sort=-created_at&page=2&page_size=50

端点详解

健康检查

GET /api/v1/health 检查服务可用性,无需鉴权。

请求参数:无

响应字段

字段类型说明
statusstringok / degraded / down
versionstringEnerOS 版本号
uptime_secondsint服务运行时长
checksobject各子系统状态

cURL 示例

curl http://localhost:8080/api/v1/health

响应示例

{
  "data": {
    "status": "ok",
    "version": "0.47.0",
    "uptime_seconds": 86400,
    "checks": {
      "database": "ok",
      "timeseries": "ok",
      "eventbus": "ok",
      "realtime": "ok"
    }
  },
  "request_id": "req_20260706_001",
  "timestamp": "2026-07-06T08:30:00Z"
}

获取 Token

POST /api/v1/auth/token 通过用户名密码换取 Bearer Token。

请求参数

字段类型必填默认值说明
usernamestring用户名
passwordstring密码
tenant_idstring默认租户租户 ID
scopestringdefault权限范围

cURL 示例

curl -X POST http://localhost:8080/api/v1/auth/token \
  -H "Content-Type: application/json" \
  -d '{"username":"admin","password":"admin"}'

响应示例

{
  "data": {
    "token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
    "refresh_token": "rft_20260706_abc123",
    "expires_in": 3600,
    "token_type": "Bearer"
  },
  "request_id": "req_20260706_002",
  "timestamp": "2026-07-06T08:30:00Z"
}

创建电网

POST /api/v1/networks 创建一个新的电网模型。

请求参数

字段类型必填默认值说明
namestring电网名称,最长 64 字符
descriptionstring""描述,最长 256 字符
base_kvfloat110.0基准电压(kV)
base_mvafloat100.0基准容量(MVA)
busesarray母线列表,至少 1 条
buses[].idint母线编号
buses[].typestringslack / pv / pq
buses[].vfloat1.0电压标幺值(slack/pv 必填)
buses[].thetafloat0.0相角(弧度,slack 必填)
buses[].areaint1区域编号
branchesarray[]支路列表
branches[].fromint起始母线
branches[].toint终止母线
branches[].rfloat电阻标幺值
branches[].xfloat电抗标幺值
branches[].bfloat0.0充电容纳标幺值
generatorsarray[]发电机列表
loadsarray[]负荷列表
tagsobject{}自定义标签

cURL 示例

curl -X POST http://localhost:8080/api/v1/networks \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "IEEE-14",
    "base_kv": 110.0,
    "base_mva": 100.0,
    "buses": [
      {"id": 1, "type": "slack", "v": 1.05, "theta": 0.0},
      {"id": 2, "type": "pv", "v": 1.04},
      {"id": 3, "type": "pq"}
    ],
    "branches": [
      {"from": 1, "to": 2, "r": 0.01938, "x": 0.05917, "b": 0.0528}
    ],
    "generators": [
      {"bus": 1, "mw": 50.0, "mvar": 0.0}
    ],
    "loads": [
      {"bus": 3, "mw": 94.2, "mvar": 19.0}
    ],
    "tags": {"owner": "ieee", "scenario": "summer"}
  }'

Rust 示例

use eneros_sdk::{ApiClient, models::NetworkInput};
use serde_json::json;

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    let client = ApiClient::builder()
        .endpoint("http://localhost:8080")
        .token("<bearer-token>")
        .build()?;

    let input = NetworkInput {
        name: "IEEE-14".to_string(),
        base_kv: Some(110.0),
        base_mva: Some(100.0),
        buses: vec![
            json!({"id": 1, "type": "slack", "v": 1.05, "theta": 0.0}),
            json!({"id": 2, "type": "pv", "v": 1.04}),
            json!({"id": 3, "type": "pq"}),
        ],
        branches: vec![
            json!({"from": 1, "to": 2, "r": 0.01938, "x": 0.05917, "b": 0.0528}),
        ],
        generators: vec![json!({"bus": 1, "mw": 50.0, "mvar": 0.0})],
        loads: vec![json!({"bus": 3, "mw": 94.2, "mvar": 19.0})],
        tags: json!({"owner": "ieee", "scenario": "summer"}),
        ..Default::default()
    };

    let network = client.networks().create(&input).await?;
    println!("created network: {}", network.id);
    Ok(())
}

Python 示例

from eneros_sdk import ApiClient

client = ApiClient(
    endpoint="http://localhost:8080",
    token="<bearer-token>",
)

network = client.networks.create({
    "name": "IEEE-14",
    "base_kv": 110.0,
    "base_mva": 100.0,
    "buses": [
        {"id": 1, "type": "slack", "v": 1.05, "theta": 0.0},
        {"id": 2, "type": "pv", "v": 1.04},
        {"id": 3, "type": "pq"},
    ],
    "branches": [
        {"from": 1, "to": 2, "r": 0.01938, "x": 0.05917, "b": 0.0528},
    ],
    "generators": [{"bus": 1, "mw": 50.0, "mvar": 0.0}],
    "loads": [{"bus": 3, "mw": 94.2, "mvar": 19.0}],
    "tags": {"owner": "ieee", "scenario": "summer"},
})
print(f"created network: {network.id}")

响应示例

{
  "data": {
    "id": "net_8f3a2b",
    "name": "IEEE-14",
    "description": "",
    "base_kv": 110.0,
    "base_mva": 100.0,
    "bus_count": 14,
    "branch_count": 20,
    "generator_count": 5,
    "load_count": 11,
    "status": "ready",
    "tags": {"owner": "ieee", "scenario": "summer"},
    "created_at": "2026-07-06T08:30:00Z",
    "updated_at": "2026-07-06T08:30:00Z"
  },
  "request_id": "req_20260706_003",
  "timestamp": "2026-07-06T08:30:00Z"
}

获取电网列表

GET /api/v1/networks 返回当前租户下的电网列表。

请求参数(Query):

字段类型必填默认值说明
pageint1页码
page_sizeint20每页数量
statusstring过滤状态
namestring模糊匹配名称
tagstring按 tag 过滤,格式 key:value
sortstring-created_at排序字段

响应示例

{
  "data": [
    {
      "id": "net_8f3a2b",
      "name": "IEEE-14",
      "bus_count": 14,
      "status": "ready",
      "created_at": "2026-07-06T08:30:00Z"
    },
    {
      "id": "net_9c4d1e",
      "name": "IEEE-30",
      "bus_count": 30,
      "status": "ready",
      "created_at": "2026-07-05T10:00:00Z"
    }
  ],
  "meta": {
    "page": 1,
    "page_size": 20,
    "total": 2,
    "total_pages": 1
  },
  "request_id": "req_20260706_004",
  "timestamp": "2026-07-06T08:30:00Z"
}

触发潮流计算

POST /api/v1/networks/{id}/powerflow 触发一次潮流计算任务。

路径参数

字段类型必填说明
idstring电网 ID

请求参数

字段类型必填默认值说明
methodstringnewton_raphson算法:newton_raphson / fast_decoupled / dc
tolerancefloat1e-8收敛精度
max_iterationsint50最大迭代次数
asyncboolfalse是否异步执行
flat_startboolfalse是否平启动
timeout_msint30000超时时间(毫秒)

cURL 示例

curl -X POST http://localhost:8080/api/v1/networks/net_8f3a2b/powerflow \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{"method": "newton_raphson", "tolerance": 1e-8, "max_iterations": 50}'

响应示例(同步模式):

{
  "data": {
    "task_id": "pf_20260706_001",
    "network_id": "net_8f3a2b",
    "status": "converged",
    "method": "newton_raphson",
    "iterations": 4,
    "duration_ms": 12,
    "tolerance": 1e-8,
    "buses": [
      {"id": 1, "v": 1.05, "theta": 0.0, "p_gen": 50.0, "q_gen": 12.5},
      {"id": 2, "v": 1.04, "theta": -0.039, "p_gen": 0.0, "q_gen": 0.0}
    ],
    "branches": [
      {"from": 1, "to": 2, "p_from": 50.0, "q_from": 12.5, "loading": 0.45}
    ],
    "losses": {"p_mw": 1.23, "q_mvar": 5.67},
    "started_at": "2026-07-06T08:30:00Z",
    "completed_at": "2026-07-06T08:30:00.012Z"
  },
  "request_id": "req_20260706_005",
  "timestamp": "2026-07-06T08:30:00Z"
}

响应示例(异步模式):

{
  "data": {
    "task_id": "pf_20260706_002",
    "network_id": "net_8f3a2b",
    "status": "queued",
    "poll_url": "/api/v1/tasks/pf_20260706_002"
  },
  "request_id": "req_20260706_006",
  "timestamp": "2026-07-06T08:30:00Z"
}

创建 Agent

POST /api/v1/agents 创建并注册一个新的 Agent。

请求参数

字段类型必填默认值说明
namestringAgent 名称
typestringdispatch / self_healing / trading / maintenance / planning
network_idstring关联电网 ID
configobject{}Agent 配置
toolsarray[]允许使用的工具列表
reasoning_modelstringdefault推理模型
max_actions_per_minuteint60最大动作频率
auto_startboolfalse创建后自动启动

cURL 示例

curl -X POST http://localhost:8080/api/v1/agents \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "DispatchAgent-01",
    "type": "dispatch",
    "network_id": "net_8f3a2b",
    "config": {"objective": "economic", "horizon_minutes": 15},
    "tools": ["powerflow", "topology", "forecast"],
    "reasoning_model": "default",
    "max_actions_per_minute": 30,
    "auto_start": true
  }'

JavaScript 示例

import { ApiClient } from '@eneros/sdk';

const client = new ApiClient({
  endpoint: 'http://localhost:8080',
  token: '<bearer-token>',
});

const agent = await client.agents.create({
  name: 'DispatchAgent-01',
  type: 'dispatch',
  networkId: 'net_8f3a2b',
  config: { objective: 'economic', horizonMinutes: 15 },
  tools: ['powerflow', 'topology', 'forecast'],
  reasoningModel: 'default',
  maxActionsPerMinute: 30,
  autoStart: true,
});
console.log('created agent:', agent.id);

响应示例

{
  "data": {
    "id": "agent_dispatch_01",
    "name": "DispatchAgent-01",
    "type": "dispatch",
    "network_id": "net_8f3a2b",
    "status": "running",
    "config": {"objective": "economic", "horizon_minutes": 15},
    "tools": ["powerflow", "topology", "forecast"],
    "reasoning_model": "default",
    "max_actions_per_minute": 30,
    "created_at": "2026-07-06T08:30:00Z",
    "started_at": "2026-07-06T08:30:01Z"
  },
  "request_id": "req_20260706_007",
  "timestamp": "2026-07-06T08:30:00Z"
}

下发 Agent 指令

POST /api/v1/agents/{id}/command 向 Agent 下发一条指令。

请求参数

字段类型必填默认值说明
commandstring指令名称
paramsobject{}指令参数
prioritystringnormallow / normal / high / emergency
timeout_msint5000指令超时
await_resultbooltrue是否等待结果

cURL 示例

curl -X POST http://localhost:8080/api/v1/agents/agent_dispatch_01/command \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "command": "set_generation",
    "params": {"bus": 2, "mw": 50.0},
    "priority": "normal",
    "timeout_ms": 5000,
    "await_result": true
  }'

响应示例

{
  "data": {
    "command_id": "cmd_20260706_001",
    "agent_id": "agent_dispatch_01",
    "command": "set_generation",
    "status": "success",
    "result": {
      "bus": 2,
      "mw_set": 50.0,
      "constraint_checked": true,
      "audit_id": "aud_20260706_001"
    },
    "duration_ms": 12,
    "executed_at": "2026-07-06T08:30:00Z"
  },
  "request_id": "req_20260706_008",
  "timestamp": "2026-07-06T08:30:00Z"
}

时序数据查询

GET /api/v1/timeseries 查询时序数据,支持聚合与降采样。

请求参数(Query):

字段类型必填默认值说明
metricstring指标名,如 branch_loading
tagsstring标签过滤,格式 key:value,key2:value2
fromdatetime起始时间(RFC 3339)
todatetime结束时间
aggregationstringnonenone / avg / sum / max / min / count
intervalstring降采样间隔,如 1m / 5m / 1h
fillstringnull缺失值填充策略:null / zero / linear
limitint10000最大返回点数

cURL 示例

curl -G http://localhost:8080/api/v1/timeseries \
  -H "Authorization: Bearer <token>" \
  --data-urlencode "metric=branch_loading" \
  --data-urlencode "tags=network:net_8f3a2b,branch:1-2" \
  --data-urlencode "from=2026-07-06T00:00:00Z" \
  --data-urlencode "to=2026-07-06T08:00:00Z" \
  --data-urlencode "aggregation=avg" \
  --data-urlencode "interval=5m"

Python 示例

from eneros_sdk import ApiClient
from datetime import datetime, timezone, timedelta

client = ApiClient(endpoint="http://localhost:8080", token="<bearer-token>")

result = client.timeseries.query(
    metric="branch_loading",
    tags={"network": "net_8f3a2b", "branch": "1-2"},
    from_=datetime.now(timezone.utc) - timedelta(hours=8),
    to=datetime.now(timezone.utc),
    aggregation="avg",
    interval="5m",
)
for point in result.points:
    print(f"{point.timestamp} -> {point.value}")

响应示例

{
  "data": {
    "metric": "branch_loading",
    "tags": {"network": "net_8f3a2b", "branch": "1-2"},
    "aggregation": "avg",
    "interval": "5m",
    "points": [
      {"timestamp": "2026-07-06T00:00:00Z", "value": 0.42},
      {"timestamp": "2026-07-06T00:05:00Z", "value": 0.45},
      {"timestamp": "2026-07-06T00:10:00Z", "value": 0.48}
    ],
    "count": 96
  },
  "request_id": "req_20260706_009",
  "timestamp": "2026-07-06T08:30:00Z"
}

批量写入时序

POST /api/v1/timeseries/batch 批量写入时序数据点,单次最多 10000 点。

请求参数

字段类型必填默认值说明
pointsarray数据点数组
points[].metricstring指标名
points[].timestampdatetime当前时间时间戳
points[].valuefloat数值
points[].tagsobject{}标签

cURL 示例

curl -X POST http://localhost:8080/api/v1/timeseries/batch \
  -H "Authorization: Bearer <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "points": [
      {"metric": "branch_loading", "timestamp": "2026-07-06T08:30:00Z", "value": 0.42, "tags": {"network": "net_8f3a2b", "branch": "1-2"}},
      {"metric": "bus_voltage", "timestamp": "2026-07-06T08:30:00Z", "value": 1.05, "tags": {"network": "net_8f3a2b", "bus": "1"}}
    ]
  }'

响应示例

{
  "data": {
    "accepted": 2,
    "rejected": 0,
    "errors": []
  },
  "request_id": "req_20260706_010",
  "timestamp": "2026-07-06T08:30:00Z"
}

告警列表与确认

GET /api/v1/alarms 获取告警列表,PATCH /api/v1/alarms/{id}/ack 确认告警。

列表请求参数

字段类型必填默认值说明
severitystringinfo / warn / error / critical
statusstringactive / acknowledged / cleared
network_idstring限定电网
fromdatetime起始时间
todatetime结束时间

确认告警请求参数

字段类型必填默认值说明
acknowledged_bystring确认人
notestring""备注

响应示例(列表):

{
  "data": [
    {
      "id": "alm_001",
      "severity": "critical",
      "status": "active",
      "type": "BRANCH_OVERLOAD",
      "message": "Branch 1-2 overload: 105% of limit",
      "network_id": "net_8f3a2b",
      "source": {"type": "constraint_engine", "id": "ce_01"},
      "details": {"branch_id": "1-2", "loading": 1.05, "limit": 1.0},
      "raised_at": "2026-07-06T08:30:00Z",
      "acknowledged_at": null,
      "cleared_at": null
    }
  ],
  "meta": {"page": 1, "page_size": 20, "total": 1, "total_pages": 1},
  "request_id": "req_20260706_011",
  "timestamp": "2026-07-06T08:30:00Z"
}

审计日志查询

GET /api/v1/audit 查询操作审计日志,需要审计权限。

请求参数

字段类型必填默认值说明
actorstring操作者
actionstring操作类型
resource_typestring资源类型
resource_idstring资源 ID
fromdatetime起始时间
todatetime结束时间
pageint1页码
page_sizeint50每页数量

响应示例

{
  "data": [
    {
      "id": "aud_20260706_001",
      "timestamp": "2026-07-06T08:30:00Z",
      "actor": {"type": "user", "id": "admin", "tenant": "default"},
      "action": "agent.command",
      "resource": {"type": "agent", "id": "agent_dispatch_01"},
      "request_id": "req_20260706_008",
      "ip": "192.168.1.10",
      "user_agent": "curl/7.88.1",
      "result": "success",
      "details": {"command": "set_generation", "params": {"bus": 2, "mw": 50.0}}
    }
  ],
  "meta": {"page": 1, "page_size": 50, "total": 1, "total_pages": 1},
  "request_id": "req_20260706_012",
  "timestamp": "2026-07-06T08:30:00Z"
}

错误码

通用错误码

HTTP 状态错误码含义
400INVALID_REQUEST请求参数错误
400INVALID_FIELD字段值非法
401UNAUTHORIZED未认证或 token 失效
401TOKEN_EXPIREDToken 已过期
403FORBIDDEN权限不足
404NOT_FOUND资源不存在
405METHOD_NOT_ALLOWED方法不支持
409CONFLICT资源状态冲突
409CONSTRAINT_VIOLATION违反安全约束
413PAYLOAD_TOO_LARGE请求体过大
422VALIDATION_FAILED业务校验失败
429RATE_LIMITED触发限流
500INTERNAL_ERROR内核错误
503SERVICE_UNAVAILABLE服务不可用
504GATEWAY_TIMEOUT网关超时

业务错误码

HTTP 状态错误码含义
409POWERFLOW_DIVERGED潮流不收敛
409NETWORK_LOCKED网络被锁定
422TOPOLOGY_INVALID拓扑不合法
422PARAM_OUT_OF_RANGE参数越界
422AGENT_BUSYAgent 忙
422BUS_NOT_FOUND母线不存在
422BRANCH_NOT_FOUND支路不存在
422ISLANDED_BUS母线孤岛
422VOLTAGE_OUT_OF_LIMIT电压越限

错误响应体统一格式:

{
  "error": {
    "code": "CONSTRAINT_VIOLATION",
    "message": "Branch 1-2 overload: 105% of limit",
    "details": {"branch_id": "1-2", "loading": 1.05, "limit": 1.0},
    "trace_id": "trace_abc123",
    "doc_url": "https://docs.openeneros.com/api-reference/rest#错误码"
  },
  "request_id": "req_20260706_008"
}

字段枚举值说明

NetworkStatus

说明
draft草稿,可编辑
ready就绪,可参与计算
locked锁定(计算中),不可修改
archived归档,只读

AgentType

说明
dispatch调度 Agent
self_healing自愈 Agent
trading交易 Agent
maintenance运维 Agent
planning规划 Agent

AgentStatus

说明
idle空闲
running运行中
paused已暂停
error错误
stopped已停止

PowerFlowMethod

说明
newton_raphson牛顿-拉夫逊法(默认)
fast_decoupled快速解耦法(PQ 分解)
dc直流潮流

BusType

说明
slack平衡节点
pvPV 节点(电压可控)
pqPQ 节点(负荷节点)

DeviceType

说明
PV光伏
WIND风电
BESS储能
EV电动汽车
LOAD负荷
TRANSFORMER变压器
BREAKER断路器

批量操作

除时序写入外,REST API 还支持以下批量端点:

方法路径说明单批上限
POST/api/v1/networks/batch批量创建电网20
POST/api/v1/agents/batch批量创建 Agent50
POST/api/v1/devices/batch批量创建设备200
DELETE/api/v1/networks/batch批量删除电网50

批量请求统一返回每个条目的独立结果:

{
  "data": {
    "succeeded": [{"index": 0, "id": "net_a"}, {"index": 1, "id": "net_b"}],
    "failed": [{"index": 2, "error": {"code": "VALIDATION_FAILED", "message": "invalid bus"}}]
  }
}

相关文档