由于工作需要,笔者近期集中阅读了IEEE 2030.5标准协议,即《IEEE Standard for Smart Energy Profile Application Protocol》,并将继续深入学习实践相关内容,因此,笔者在这里分享自己学习的具体标准内容及后续学习的心得体会,一来促进自己的深入理解,二来也与给读者朋友作为参考,一同交流学习。
IEEE 2030.5 标准协议的前三章主要是标准综述,此外也对文档的规范性引用及定义和缩写等进行了总结,引用部分可以查看原文,定义及所写的部分将会在不同概念第一次出现的位置进行说明。
概述
IEEE 2030.5 标准定义了通过 TCP/IP 协议提供传输层和网络层功能的应用层协议,以实现终端用户能源环境的公用事业管理,包括需求响应、负荷控制、分时电价、分布式能源管理和电动汽车等。基于所使用的物理层标准(IEEE 802.15.4、IEEE 802.11、IEEE 1901、IEEE1901.2),可能需要结合多种更低层协议来提供完整的解决方案。
IEEE 802.15.4 (LR-WPAN 的基础协议标准)、IEEE 802.11 (无线局域网 WAN 协议的核心标准)、IEEE1901 (电力线通信 PLC 协议标准)及 IEEE1901.2 (窄带电力线通信 Narrowband PLC 协议标准)是不同无线或有线通信技术的定义标准,IEEE 2030.5 本身只定义了应用层的相关标准,更低层的标准则会根据实际设备的安装情况具体选择。
IEEE 2030.5标准定义了交换应用信息的机制,具体包括错误信息(error message)以及用于保护应用信息的安全特性(security features),2030.5 基于 OSI 四层网络模型构建,定义的应用配置源自很多已有的标准(包括IEC 61968 和 IEC 61850)中的元素,同时相关应用配置遵循使用 IETF 协议(如 HTTP)的RESTful架构。
IEC 61968 和 IEC 61850 都是由国际电工委员会 (IEC) 发布的电力系统相关标准,其中,IEC 61968 是为配电管理系统设计的标准,定义了电力公司内部不同系统间的数据交换接口,IEC 61850 是专为变电站自动化和电力自动化系统设计的标准,定义了实时通信协议,旨在确保变电站设备之间的互操作性和高效通信。
IEEE 2030.5 标准由三个文档定义,所有 2030.5 设备必须遵守这些文档的规定:
- IEEE 2030.5 标准文档
- IEEE 2030.5 XML Schema Definition (XSD):包含 IEEE 2030.5 资源、属性和元素机器文字描述的定义
- IEEE 2030.5 WADL:包含推荐的 URI 结构和与这些对象相关的HTTP方法的使用
此外,IEEE 2030.5 UML 模型被用于 XSD 的构建。
语言规则
IEEE 2030.5 参考 IETF RFC 2119 对关键字进行解释,后续学习和应用将会遵循如下固定规则:
- MUST / REQUIRED / SHALL:表示要求是强制性的,必须执行,后文翻译为“必须”
- MUST NOT / SHALL NOT:表示行为禁止,绝对不允许发生,后文翻译为“禁止”“必须不”
- SHOULD:表示该要求是推荐的,虽然不强制,但最好遵循,不遵循可能存在问题,但不一定破坏协议的兼容性,后文翻译为“应当”
- SHOULD NOT:表示该要求是推荐不做的,虽然不强制,但最好遵循,不遵循可能存在问题,但不一定破坏协议的兼容性,后文翻译为“不应当”
- RECOMMENDED:表示行为是推荐的,遵循会带来好处,不遵循也不会导致严重问题,后文翻译为“推荐”
- MAY:表示行为是可选的,用户可以选择是否执行,后文翻译为“可能”
- OPTIONAL:表示行为完全可选,可执行,也可不执行,后文翻译为“可以选择”
设计原则
IEEE 2030.5 遵循 RESTful 架构,有几个重要的设计原则:
- 尽管设备可能维持状态,接口本身应当是无状态的 (While devices may maintain state, interfaces should be stateless)
- URI结构应当尽可能简洁高效 (URI structure should be clear but as efficient as possbile)
- 最小化实现特定功能所需的事务数量 (Minimize the number of transactions required to achieve a given function)
关于这几个设计原则,我们逐个理解:
尽管设备可能维持状态,接口本身应当是无状态的
能源设备可以根据实际需求保留自身的状态信息,例如设备内部可能记录运行状态、配置参数、当前用户的会话信息等,我们以一个智能灯泡为例,它可能存在以下状态:
当前亮度:50%
电源状态:开启
模式:夜间模式
这些状态存在于设备中,与接口设计原则无关,用于保持设备的运行逻辑。
而 RESTful 架构则要求接口是无状态的,即服务器每次的请求都是独立的,不依赖前面的任何请求,也不存储客户端的临时会话状态,应用到前面的智能灯泡上,可以理解为:
- 客户端可以通过
GET / light查询设备状态 - 客户端可以通过
POST / light { "brightness": 80 }修改亮度
但是,接口无状态的要求下,客户端发送的每个请求都是独立完整的,即每条请求都独立实现了其目标,不会通过连续几的请求来实现一个单独的目标(如果上面的 POST / light 和后面的改变亮度的请求分开了,那么由于服务器不存储之前的请求,后续的改变亮度的请求就不能完成)
URI结构应当尽可能简洁高效
URI 应当清晰描述资源的层级关系及其含义,例如, /products/smart_light/123是ID为123的描述清晰的智能灯泡,而/getOrder?id=123&user=456或/abc/xyz则未能清晰描述资源含义
此外,URI的设计不仅要清晰易读,还要高效简洁,即
- 避免冗长路径,如
/company/Mike/products/electic_products/light/smart_light/123存在嵌套层级过深的问题 - 减少重复信息,如
/products/smart_light/products/smart_light/123重复包含了/products/smart_light的信息 - 必要信息完整,如
/products/123则缺乏了产品类型的具体信息
此外,URI中单词的单复数一致性以及缩写避免过度原则也需要遵守,以免造成混用或者难以理解。
最小化实现特定功能所需的事务数量
事务 (transaction):客户端发送一个 GET /products/smart_light/123 请求,服务器返回用户数据,这是一个完整事务
最小化事务数量,可以降低延迟,降低服务器负载以及节省带宽,以下方法可以实现这一原则:
-
通过设计API,使得单个请求可以完成多个操作,例如:
低效设计
GET /products/smart_light # 获取智能灯泡信息 GET /products/smart_light/orders # 获取该灯泡的订单信息高效设计
GET /products/smart_light?include=orders # 获取智能灯泡信息及其订单信息 -
允许客户端通过一个请求批量处理资源,例如:
低效设计
POST /products/smart_light/123 { "brightness": 80 } POST /products/smart_light/123 { "duration": 10 } POST /products/smart_light/123 { "color": white }高效设计
POST /products/smart_light/123 [ { "brightness": 80 } { "duration": 10 } { "color": white } ] -
使用合适的资源设计,充分考虑资源的关系和聚合方式,避免分散请求,例如:
低效设计
GET /products/smart_light/123/details GET /products/smart_light/123/reviews GET /products/smart_light/123/related高效设计
GET /products/smart_light/123?include=details,reviews,related -
设置适当的缓存策略(如
HTTP缓存头ETag或Cache-Control),减少重复请求。
这里的缓存策略和 RESTful API 的无状态性要求并不冲突,因为缓存是在客户端和服务器之间的网络层进行优化,而无状态性是关于服务器的接口设计原则。说人话就是,客户端请求信息->服务器返回标记为可缓存的信息->客户端或代理层存储返回的结果->客户端再请求->读取缓存内容,可以看到服务器本身仍然维持无状态性。
当然,设计API时也要避免过度合并,保持清晰的语义,同时在数据量过大时支持分页或部分加载,避免单个请求返回过多数据。