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代码:
xxxxxxxxxx101{2  "method": "createComponentConfig",3  "params": {4    "factoryPid": string,5    "properties": [{6      "name": string,7      "value": any8    }]9  }10}xxxxxxxxxx101{2  "method": "updateComponentConfig",3  "params": {4    "componentId": string,5    "properties": [{6      "name": string,7      "value": any8    }]9  }10}componentID: component的独特ID(unique ID )properties: 带有name和value的集合
例子
Symmetric Balancing Schedule Controller 对称均衡调度控制器
这个控制器用来控制ESS的充电和放电,来使得能够达到电网连接点达到给定的功率。 这个给定的功率在JSON代码中通过时间戳体现。使用updateComponentConfig可以更新设定点
xxxxxxxxxx251{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": 015          },16          {17            "startTimestamp": 1577837700,18            "duration": 900,19            "activePowerSetPoint": -200020          }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的配置:
xxxxxxxxxx401{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配置:
xxxxxxxxxx61{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.
xxxxxxxxxx11[{ "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/lastUpdateExample
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,返回值如下:
xxxxxxxxxx71{2  "type":"INTEGER",3  "accessMode":"RO",4  "text":"",5  "unit":"%",6  "value":507}GET可以使用正则表达式:http://x:user@localhost:8084/rest/channel/.*/Active.*Power
这个链接可以得到所有Components的ActivePower和ReactivePower的通道值。返回值如下:
xxxxxxxxxx341[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":909  },10  {11    "address":"meter0/ActiveProductionPower",12    "type":"INTEGER",13    "accessMode":"RO",14    "text":"",15    "unit":"W",16    "value":46517  },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":46525  },26  {27    "address":"meter0/ActiveConsumptionPower",28    "type":"INTEGER",29    "accessMode":"RO",30    "text":"",31    "unit":"W",32    "value":033  }34]4.1.2 POST
用HTTP请求中的POST方法来写一个Channel。
更改数字输出的状态,发送POST请求到:http://x:user@localhost:8084/rest/channel/io0/Relay1,给出:
xxxxxxxxxx31{2    "value": true3}4.2 EndPoint '/jsonrpc'
可以用远程过程调用(RPC)。JSON-RPC需要用POST方法发送特殊的请求体。
JsonRPC通常需要特殊的属性‘id'以及'jsonrpc',这些可以省略掉,因为POST调用不需要。
4.2.1 getEdgeConfig
xxxxxxxxxx41{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".
xxxxxxxxxx111{2  "method":"componentJsonApi",3  "params":{4    "componentId":"ctrlApiModbusTcp0",5    "payload":{6      "method":"getModbusProtocol",7      "params":{8      }9    }10  }11}4.2.3 updateComponentConfig
更新Component配置项
xxxxxxxxxx101{2    "method": "updateComponentConfig",3    "params": {4        "componentId": "ctrlDebugLog0",5        "properties": [{6            "name": "enabled",7            "value": true8        }]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

