OpenEMS是一个能源管理系统,主要用于能源消耗监测和控制。这个系统可以帮助用户识别能源浪费,降低能源成本,并减少环境影响。OpenEMS能够集成各种不同类型的能源设备,如太阳能电池板、风力涡轮机、发电机等,并提供实时的数据监测、控制和分析。
本篇是OpenEMS Edge模块文档的学习笔记。
OpenEMS — EDGE
OpenEMS — EDGEArchitecture2. IPO模型InputProcessOutput3. Controller4. Scheduler5. Cycle6. Process Image7. Asynchronous threads and Cycle synchronization8. Architecture schemeConfiguration1. Manage Configuration1.1 Via OpenEMS UI1.2. Via Apache Felix Web Console1.3 Via Json-RPC例子1.4 By editing/preseeding configuration files2. Edge-ConfigNatureChannelFactoryInstanceNature1. Battery2. Battery-Inverter3. Controller4. ESSESSSymmetricEssReadOnlyEssDcCharger5. EVCS(Electric Vehicle Charging Station)6. I/O7. Meter8. Predictor9. Scheduler10. Thermometer11. Timedata12. Time-Of-Use Tariff APIScheduler1. All-Alphabetically2. Daily2.1 Configuration3. Fixed OrderController1. API Backend2. API Modbus3. API MQTT4. REST-API Controller4.1 Endpoint /rest/channel/<Component-ID>/<Channel-ID>
4.1.1 GET 4.1.2 POST4.2 EndPoint ‘/jsonrpc’4.2.1 getEdgeConfig4.2.2 componentJsonAPI4.2.2.1 getModbusProtocol4.2.3 updateComponentConfig5. Api Websocket6. Asymmetric Balancing Cos-Phi7. Asymmetric Fix Active Power8. Asymmetric Fix Reactive Power9. Asymmetric Peak-Shaving10. Asymmetric Phase Rectification11. Channel-Threshold
Architecture
抽象设备通信和控制算法
2. IPO模型
Input
电池数据
Process
根据输入进行处理,是否应该打开充电开关
Output
打开/关闭开关
3. Controller
根据Channel Data,处理业务逻辑。例子:控制算法,用于评估输入数据,定义控制的硬件的行为。确保外部系统的任何设置点请求能够被嵌入到本地的优先级系统?
例如电池充电应该被单独连接到内部控制算法的一个控制器。
4. Scheduler
当两个Controller调用统一资源,例如一个开关时,规定优先级,避免冲突。
执行过程:使用一个Scheduler实现来接收一个Controller列表。Controllers就这样被定义了一个执行顺序。Controller列表后面的controller将不被允许修改前面controller已经写好的结果。
5. Cycle
整个模型是在Cycle中执行,会发出Cycle事件来和其他组件同步
6. Process Image
Process Image类似于共享内存区,数据的生产者和消费者将在这个区域存取数据,避免直接交互造成混乱。每个通道存储一种数据,比如电池温度等。每个计算周期通道数据更新一次。
所以有了value字段和nextvalue字段,value字段用于消费者读取,nextvalue用于生产者写入。
只有再上图Process Image阶段,next value会复制值到Value字段,保证在计算阶段值不会变。
7. Asynchronous threads and Cycle synchronization
与外部硬件和服务的通信时异步的,可以避免阻塞系统,同时可以与Cycle同步。
8. Architecture scheme
Configuration
要求本地的EMS机器有一个静态配置,声明可用硬件和服务以及激活的控制算法,参数。程序不应频繁更改配置。
1. Manage Configuration
1.1 Via OpenEMS UI
可以配置Open EMS Edge直接链接还是通过后端连接
1.2. Via Apache Felix Web Console
通过8080端口的Apache Felix Web Console
1.3 Via Json-RPC
JSON-RPC协议时再整个项目上使用来直接在Edge或者是Backend上直接访问功能。
调整配置的json代码:
xxxxxxxxxx
101{
2 "method": "createComponentConfig",
3 "params": {
4 "factoryPid": string,
5 "properties": [{
6 "name": string,
7 "value": any
8 }]
9 }
10}
xxxxxxxxxx
101{
2 "method": "updateComponentConfig",
3 "params": {
4 "componentId": string,
5 "properties": [{
6 "name": string,
7 "value": any
8 }]
9 }
10}
componentID
: component的独特ID(unique ID )properties
: 带有name
和value
的集合
例子
Symmetric Balancing Schedule Controller 对称均衡调度控制器
这个控制器用来控制ESS的充电和放电,来使得能够达到电网连接点达到给定的功率。 这个给定的功率在JSON代码中通过时间戳体现。使用updateComponentConfig可以更新设定点
xxxxxxxxxx
251{
2 "jsonrpc": "2.0",
3 "id": UUID,
4 "method": "updateComponentConfig",
5 "params": {
6 "componentId": "ctrlBalancingSchedule0",
7 "properties": [
8 {
9 "name": "schedule",
10 "value": [
11 {
12 "startTimestamp": 1577836800,
13 "duration": 900,
14 "activePowerSetPoint": 0
15 },
16 {
17 "startTimestamp": 1577837700,
18 "duration": 900,
19 "activePowerSetPoint": -2000
20 }
21 ]
22 }
23 ]
24 }
25}
上面的代码表示从1577836800时间点开始,电网连接点应该尽量保持在0W,保持900秒,而从1577837700开始,电网连接点尽量保持在-2000W,也就是向电网输送2000W的电力,保持900秒。其他时间段这个控制器不会控制,更低优先级的控制器可以接管。
1.4 By editing/preseeding configuration files
OSGi的配置储存在文件系统的文本文件中。修改EdgeApp.bndrun中的felix.cm.dir参数。
可以用来在生产部署或者是快速更改edge设备上预置配置。重启程序后即可应用更改。
2. Edge-Config
Edge的配置文件在上面图片中展示,包含:
Nature
一个Nature可以看成是Java中的‘Interface’,定义了实现一个Component所需要的Channel。
定义battery需要定义通道ChargeMaxVoltage
,DischargeMaxVoltage
以及Soc
等。
Channel
一个Channel代表了一个Component的信息,比如描述,度量单位等等。
ChargeMaxVoltage
是Battery Nature的一个Channel,描述了充电的最大电压,被定义为一个Integer,单位是Ampere?
Factory
可以看成是面向对象中的Class,它是Java/OSGi的元数据的丰富,定义了一些需要的配置参数。一个Factory实现了一个或者更多的Nature,Factory提供了实现Nature所有的通道。也可以定义特定于单个实现的更多通道。
对于BMW电池的Factory,实现了Battery Nature。同时定义了AmbientTemperature,虽然是不可用的,但是每个电池实现都需要这个通道。
Instance
可以看成是面向对象中的Object,已经定义好具体参数的Factory对象。实例化之后可以看成是Open EMS的组件,通过单独的Component-ID来识别。
通过JSON来进行定义Edge的配置:
xxxxxxxxxx
401{
2 "components": {
3 "ess0": {
4 "alias": "Battery Energy Storage System",
5 "factoryId": "Ess.Generic.ManagedSymmetric",
6 "properties": {
7 "enabled": true,
8 "battery.id": "battery0",
9 "batteryInverter.id": "batteryInverter0"
10 },
11 "channels": {
12 "ActivePower": {
13 "type": "INTEGER",
14 "accessMode": "RO",
15 "text": "Negative values for Charge; positive for Discharge",
16 "unit": "W"
17 }
18 }
19 }
20 },
21 "factories": {
22 "Ess.Generic.ManagedSymmetric": {
23 "id": "Ess.Generic.ManagedSymmetric",
24 "name": "ESS Generic Managed Symmetric",
25 "description": "",
26 "natureIds": [
27 "io.openems.edge.ess.api.SymmetricEss",
28 ],
29 "properties": [
30 {
31 "id": "id",
32 "name": "Component-ID",
33 "description": "Unique ID of this Component",
34 "isRequired": true,
35 "defaultValue": "ess0"
36 }
37 ]
38 }
39 }
40}
要查询EdgeConfig配置:
xxxxxxxxxx
61{
2 "jsonrpc": "2.0",
3 "id": "UUID",
4 "method": "getEdgeConfig",
5 "params": {}
6}
Nature
硬件在OpenEMS Edge中被抽象成Natures
。Nature定义了一个Component所需要的特征,属性。这些特征通过通道Channel来定义。
Ess(Energy Storage System)的实现需要提供一个(Soc-Channel)。
其实Nature是通过OSGi API Bundles来实现。
1. Battery
电池会连接到一个电池逆变器上。
2. Battery-Inverter
电池和电池逆变器一起组成一个ESS。
Source Code:https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.batteryinverter.api
3. Controller
见Controller
4. ESS
Energy Storage System,集成了电池和电池逆变器。
ESS
SymmetricEssReadOnly
一个对称的,可以控制的ESS。
EssDcCharger
太阳能充电器,连接到ESS的DC端。
5. EVCS(Electric Vehicle Charging Station)
6. I/O
DigitalOutput:https://github.com/OpenEMS/openems/blob/develop/io.openems.edge.io.api/src/io/openems/edge/io/api/DigitalOutput.java
一个或多个数字输出或继电器。
7. Meter
通用功率表
SymmetricMeter:https://github.com/OpenEMS/openems/blob/develop/io.openems.edge.meter.api/src/io/openems/edge/meter/api/SymmetricMeter.java
对称功率表
AsymmetricMeter:https://github.com/OpenEMS/openems/blob/develop/io.openems.edge.meter.api/src/io/openems/edge/meter/api/AsymmetricMeter.java
非对称功率表
8. Predictor
预测未来的用电/发电需求
9. Scheduler
详情见后面的Scheduler章节
10. Thermometer
温度计
11. Timedata
提供时间数据
12. Time-Of-Use Tariff API
提供价格数据
https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.timeofusetariff.api
Scheduler
Scheduler计划控制器的运行顺序,它定义了
哪个控制器应该运行
控制器的优先级
1. All-Alphabetically
获取一个组件ID的有序列表,以ID的字母序排序
https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.scheduler.allalphabetically
2. Daily
调度器可以根据"Daily Schedule"配置运行不同的控制器。如果有无论何时都需要运行的控制器,可以使用'Always Run Before'或者是“Always Run After”。
2.1 Configuration
Component-ID 组件的ID
Alias 可读的组件名字,默认是ComponentID
Always Run Before,在所有控制器启动前启动的控制器
Daily Schedule 每天的执行顺序: e.g.
xxxxxxxxxx
11[{ "time": "08:00:00", "controllers": [ "ctrlFixActivePower0" ] }, { "time": "13:45:00" "controllers": [""]" }]
Always Run After,在所有控制器启动后要执行的控制器的ID。
https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.scheduler.daily
3. Fixed Order
执行固定顺序的控制器。
https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.scheduler.fixedorder
Controller
Controller就是用来控制实际的业务逻辑或者是用某种算法来控制硬件。每个执行周期,比如说每秒,EMS可以发送给Contoller一个指令。可以有两种方法来控制硬件:
通过setpoint来控制 EMS计算setpoint指令,并且发送给硬件做立即执行 功率平滑算法,用光伏系统的电流和之前的输出功率值。我们配置一个最大斜坡率(maximum defined ramp rate),当EMS推断出系统需要以150kW来放电,那么EMS将会立即发送以150kW放电的指令给ESS做立即执行。
通过参数化来控制 EMS直接发送参数给嵌入硬件的控制算法,让硬件内部执行。
1. API Backend
连接到OpenEMS后台,并且定期发送Channel数据。通道中的数据可以被后台覆盖。
https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.controller.api.backend
2. API Modbus
Modbus API定义了哪些EMS组件应该被导出,并通过API提供。然后生成一个动态的Modbus协议,这个协议分为两部分:地址块,映射到OpenEMS组件;寄存器地址,映射到OpenEMS通道。
Modbus表允许对所有可用的寄存器进行动态解析。也就是运行时动态获得数据结构等
例子,导出一个Sum-Component(_sum),完整的Modbus协议可以被动态解析:
寄存器0表示一个Open EMS系统,用0x17ed6201哈希
寄存器1表示第一个块的长度,199表示长度,1表示下一个块开始的长度(199+1=200)
寄存器200给出16个字符长度的ComponentID
寄存器216表示完整的块的长度。添加长度300给出下一个块的位置
寄存器220给出第一个子块,子块里表示 OpenemsComponent。下一个子块从221开始,一直到300地址
除了动态解析Modbus协议,同样可以通过UI下载EMS专用excel,来得到系统配置文档。
如果要和特定的通道通信,需要去读写相对应的寄存器。例子:读寄存器302_sum/EssSoc可以得到ESS总体平均值.
https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.controller.api.modbus
3. API MQTT
把Edge的数据交给MQTT
edge/{OpenEMS-Edge-ID}/channel/{Component-ID}/{Channel-ID}
Example
edge/edge0/channel/_sum/GridActivePower
至少每五分钟发布一次
edge/{OpenEMS-Edge-ID}/channel/lastUpdate
Example
edge/edge0/channel/lastUpdate
给出最后一次更新数据的时间戳
edge/{OpenEMS-Edge-ID}/edgeConfig
得到JSON格式的Config
edge/edge0/edgeConfig
https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.controller.api.mqtt
4. REST-API Controller
REST-API提供外部访问OpenEMS Edge的途径。控制器提供访问通道的权限以及JSON-RPC请求通过JSON/REST
默认的端口是8084,默认基地址是http://x:<Password>@<IP>:8084/rest
x: 用户名
http:协议
密码和8084是自定义的,如果没有设置密码,这里默认是用户名,或者是admin。
chrome进行REST测试:https://chrome.google.com/webstore/detail/restlet-client-rest-api-t/aejoelaoggembcahagimdiliamlcdmfm
https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.controller.api.rest
4.1 Endpoint /rest/channel/<Component-ID>/<Channel-ID>
Component-ID: "_sum","ess0","meter9“…
Channel-ID
is the ID of the Channel, e.g. "ActivePowerL1", "Soc",…
4.1.1 GET
用GET
来得到一个通道的值
想要得到battery Soc,则需要发送GET请求到http://x:user@localhost:8084/rest/channel/_sum/EssSoC,返回值如下:
xxxxxxxxxx
71{
2 "type":"INTEGER",
3 "accessMode":"RO",
4 "text":"",
5 "unit":"%",
6 "value":50
7}
GET可以使用正则表达式:http://x:user@localhost:8084/rest/channel/.*/Active.*Power
这个链接可以得到所有Components的ActivePower和ReactivePower的通道值。返回值如下:
xxxxxxxxxx
341[
2 {
3 "address":"pvInverter0/ActivePower",
4 "type":"INTEGER",
5 "accessMode":"RO",
6 "text":"Negative values for Consumption; positive for Production",
7 "unit":"W",
8 "value":90
9 },
10 {
11 "address":"meter0/ActiveProductionPower",
12 "type":"INTEGER",
13 "accessMode":"RO",
14 "text":"",
15 "unit":"W",
16 "value":465
17 },
18 {
19 "address":"meter0/ActivePower",
20 "type":"INTEGER",
21 "accessMode":"RO",
22 "text":"Negative values for Consumption; positive for Production",
23 "unit":"W",
24 "value":465
25 },
26 {
27 "address":"meter0/ActiveConsumptionPower",
28 "type":"INTEGER",
29 "accessMode":"RO",
30 "text":"",
31 "unit":"W",
32 "value":0
33 }
34]
4.1.2 POST
用HTTP请求中的POST方法来写一个Channel。
更改数字输出的状态,发送POST请求到:http://x:user@localhost:8084/rest/channel/io0/Relay1,给出:
xxxxxxxxxx
31{
2 "value": true
3}
4.2 EndPoint '/jsonrpc'
可以用远程过程调用(RPC)。JSON-RPC需要用POST方法发送特殊的请求体。
JsonRPC通常需要特殊的属性‘id'以及'jsonrpc',这些可以省略掉,因为POST调用不需要。
4.2.1 getEdgeConfig
xxxxxxxxxx
41{
2 "method": "getEdgeConfig",
3 "params": {}
4}
4.2.2 componentJsonAPI
转发一个JSON-RPC负载给对应的Component,通过Component-ID识别
4.2.2.1 getModbusProtocol
Gets the currently active Modbus-TCP protocol definition from the Modbus-TCP-Api Controller with the ID "ctrlModbusTcp0".
xxxxxxxxxx
111{
2 "method":"componentJsonApi",
3 "params":{
4 "componentId":"ctrlApiModbusTcp0",
5 "payload":{
6 "method":"getModbusProtocol",
7 "params":{
8 }
9 }
10 }
11}
4.2.3 updateComponentConfig
更新Component配置项
xxxxxxxxxx
101{
2 "method": "updateComponentConfig",
3 "params": {
4 "componentId": "ctrlDebugLog0",
5 "properties": [{
6 "name": "enabled",
7 "value": true
8 }]
9 }
10}
5. Api Websocket
用于和OpenEMS UI的本地连接。通过HTTP websocket为OpenEMS Edge提供JSON/REST实现。通过Websocket从外部设备提供对Channel和JSON-RPC请求的访问。
https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.controller.api.websocket
6. Asymmetric Balancing Cos-Phi
Controls an asymmetric energy storage system in self-consumption optimization mode while keeping the grid meter on a defined cos-phi.
在自我消费优化模式下控制非对称储能系统,同时将电网电表保持在一个确定的余度上。
7. Asymmetric Fix Active Power
Sets a fixed active power for charging/discharging of an asymmetric energy storage system.
为非对称储能系统的充电/放电设置固定有功功率。
https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.controller.asymmetric.fixactivepower