- Jelina 概览
- EMS Builder
- 集成与协同
前端实时推送与直接控制
架构总览 里“执行”这一步不仅包括写入点位、发告警、发 MQTT,还包括直接服务前端界面:Edge-EMS Builder 提供两条 WebSocket 通道,让自定义前端既能实时接收数据推送,也能直接向设备下发控制指令,不需要额外开发中间层。
一、两条 WebSocket 通道
Section titled “一、两条 WebSocket 通道”| 通道 | 路径 | 认证方式 | 定位 |
|---|---|---|---|
| 前端推送通道 | ws://<host>:<port>/front |
登录 Token(账号密码 登录后获取) |
面向自定义前端界面:按角色权限校验,支持订阅推送 + 直接写入 |
| 数据读写通道 | ws://<host>:<port>/data/rw |
静态 data-rw-token(ems.yaml 中配置) |
面向后端集成系统:不依赖登录,低延迟读写,适合系统对系统集成 |
两条通道的消息格式完全一致,差异只在认证方式和权限校验粒度上。本页以 /front 为主展开,/data/rw 用法可直接类比。
连接时通过 Query 参数传入:
ws://<host>:<port>/front?socketId=<自定义连接ID>&token=<登录Token>ws://<host>:<port>/data/rw?socketId=<自定义连接ID>&token=<data-rw-token>二、消息格式
Section titled “二、消息格式”请求帧(前端 → Edge-EMS Builder)统一结构:
{ "topic": "read | write | clear", "messageId": "自定义唯一 ID,用于匹配响应", "keep": true, "content": [ { "dataKey": "pcsActivePower" } ]}响应帧(Edge-EMS Builder → 前端),按 messageId 与请求一一对应:
{ "code": "200", "message": "Processed successfully", "topic": "read", "messageId": "...", "time": "2026-07-23T10:00:00+08:00", "data": { "...": "..." }}三、如何接收实时推送(订阅 = read + keep)
Section titled “三、如何接收实时推送(订阅 = read + keep)”Edge-EMS Builder 的推送模型不是“发布订阅到某个 Topic”,而是每个连接自己声明一份“推送配置”:
- 前端发送
topic: "read",content里列出要关注的dataKey(或用groupCode关注整个数据分组),并把keep设为true。 - Edge-EMS Builder 收到后,把这份
content记为该连接(socketId)的推送配置,立即回一次当前值。 - 此后,Edge-EMS Builder 有一个后台任务,每 1 秒遍历所有仍然连接着的前端 socket,把它们各自推送配置里的最新值主动推送过去——不需要前端反复发请求轮询。
- 如果不需要持续推送,
keep设为false(或不传),Edge-EMS Builder 只推送30s。 - 想取消某个连接的推送配置,发送
topic: "clear"。
// 订阅:持续关注 pcsActivePower 和 bmsSOC 的最新值{ "topic": "read", "messageId": "sub-001", "keep": true, "content": [ { "dataKey": "pcsActivePower" }, { "dataKey": "bmsSOC" } ]}
// 或者按分组订阅(关注整个分组下的所有点位,包含子分组){ "topic": "read", "messageId": "sub-002", "keep": true, "content": [ { "groupCode": "pcs-group-01" } ]}同一个连接可以多次发送
read+keep:true来追加/更新推送配置;dataKey与groupCode二者至少填一个。
四、如何直接控制设备(write)
Section titled “四、如何直接控制设备(write)”前端发送 topic: "write",content 里给出要写入的 dataKey 和 dataValue,不需要指定数据类型——Edge-EMS Builder 会根据 dataKey 自动识别它是原始数据(Collection)、聚合数据(Aggregation)还是分时数据(Customization),路由到对应的写入逻辑:
{ "topic": "write", "messageId": "ctrl-001", "content": [ { "dataKey": "pcsActivePower", "dataValue": "300" } ]}写入分时数据(Customization)时可以附带生效区间:
{ "topic": "write", "messageId": "ctrl-002", "resetCustomValue": true, "content": [ { "dataKey": "import_price", "dataValue": "0.85", "availableDate": "2026-06-25T00:00:00+08:00", "expiredDate": "2026-06-25T08:00:00+08:00" } ]}resetCustomValue: true表示先清空该分时数据现有的值,再写入本次内容——用于“整段计划替换”场景,避免新旧时间段重叠冲突。- 写入其他共享设备的点位时,在对应
content元素上加deviceCode字段即可,Edge-EMS Builder 会识别为共享数据写入,路由到目标设备。
- 通过
/data/rw用静态data-rw-token连接:直接放行,不做角色校验,适合后端系统对系统集成。 - 通过
/front用登录 Token 连接:会校验该账号角色是否为超级管理员 / 管理员 / 操作员之一,观察者角色无法写入——与页面端的权限规则一致,不存在“绕过前端权限”的写入路径。
每日重复计划
Section titled “每日重复计划”DAILY_REPEAT 使用 availableTime / expiredTime(例如 08:00:00~12:00:00),整体生效日期配置在分时点位上;DAILY_CHANGE 才使用完整日期时间区间。两种参数不能混用,跨午夜时段应拆分。
连接与执行结果
Section titled “连接与执行结果”/front 通过 Ping/Pong 心跳检测连接,客户端需处理关闭 code/message,重连后重新建立订阅。写入请求不要随订阅一起自动重放。
设备写入以 CommBridge 应答或超时结果为准,不能仅凭发送成功判定设备已执行。可结合 设备控制日志 查看处理中、成功和失败。采集写入系数由 CommBridge 反算,调用方不要重复换算。
维护冻结 期间受保护的控制写入会返回 200162,不应自动退出冻结重试。
五、一个完整的前端集成示例
Section titled “五、一个完整的前端集成示例”const ws = new WebSocket(`ws://<host>:<port>/front?socketId=web-ui-01&token=${loginToken}`);
ws.onopen = () => { // 订阅实时数据:关注 PCS 有功功率与 SOC ws.send(JSON.stringify({ topic: 'read', messageId: 'sub-' + Date.now(), keep: true, content: [ { dataKey: 'pcsActivePower' }, { dataKey: 'bmsSOC' } ] }));};
ws.onmessage = (event) => { const resp = JSON.parse(event.data); if (resp.topic === 'read') { // 每秒都会收到一次最新值,更新界面上的仪表盘/图表 renderDashboard(resp.data); } if (resp.topic === 'write') { // 写入结果反馈:resp.successContent / resp.errorContent showWriteResult(resp); }};
// 用户在界面上点击"设置功率为 300kW"按钮时:function setPower(value) { ws.send(JSON.stringify({ topic: 'write', messageId: 'ctrl-' + Date.now(), content: [{ dataKey: 'pcsActivePower', dataValue: String(value) }] }));}这段代码完整覆盖了“页面加载即订阅实时数据 → 每秒自动刷新界面 → 用户操作直接下发控制指令 → 拿到写入结果反馈”的典型前端交互闭环,中间不需要额外的后端中转服务。
六、与其他能力的关系
Section titled “六、与其他能力的关系”- 通过
/front或/data/rw写入的数据,和触发方案、表达式引擎读取到的是同一份数据——前端控制的最终结果经设备采集回读后,可以继续参与聚合表达式和触发判断。参见 数据模型。 - 如果需要把数据同时推给云端看板而不是只在自定义前端展示,两条路径并不冲突:可以一边用
/front服务自己的前端界面,一边用 MQTT 云边协同 把同样的数据上报云端。 aems-write-dataAI 配置 Skill 封装了/data/rw和/front的调用方式,可以直接用自然语言让 AI Agent 帮你调试写入指令。