作者:Nitish Joshi (MongoDB 架构师,邮箱:nitish.joshi@mongodb.com)
电动汽车(EV)电池站是支持电动汽车普及和使用便利性的关键基础设施。这些站点为电动汽车用户提供充电或换电服务。随着社会对可持续和清洁能源解决方案的日益关注,电动汽车电池站在从燃油汽车向电动出行转型的过程中扮演着关键角色。
为了高效管理电动车充电站生成的大量带时间戳的数据,例如充电速率、电池电量和能源消耗,MongoDB 的时间序列集合提供了一个理想的解决方案。MongoDB 的时间序列数据设计用于处理电动车充电站不断产生的测量和传感器数据。通过利用这一功能,运营商可以高效存储和分析大量实时数据,同时保持 MongoDB 丰富文档模型的灵活性,便于元数据管理。这使精准监控、预测性维护和优化充电过程成为可能,确保电动车充电站能随着电动出行的增长扩展,满足不断增长的需求。
基于国家的电动汽车基础设施(NEVI)计划在为这篇文章做研究时,我发现美国有一个专门的计划旨在促进电动汽车的普及。这一倡议鼓励民众更多地使用电动汽车,从而促使政府在各州增设更多充电站。
《两党基础设施法》(简称BIL)拨款75亿美元以增强全美电动汽车充电的便捷性,支持短途和长途出行。这笔资金包括50亿美元的国家电动汽车基础设施(NEVI)规划和25亿美元的充电和燃料基础设施计划。最初,各州将使用这些资金在指定的替代燃料走廊(AFCs)沿线战略性部署直流快速充电站,以促进全国电动汽车AFC网络的建设。
根据NEVI计划,有两大关键目标可以通过先进的软件应用和数据库系统有效实现。我的实施方案直接应对这些目标,并建立电动汽车充电站。
此外,除了NEVI计划外,其他机构也有一些举措,通过部署新的充电站来鼓励使用电动汽车。2023年2月,美国联邦公路管理局(FHWA)与能源和交通联合办公室合作,推出了新的联邦资助的电动汽车充电站国家标准。这些标准旨在为电动汽车驾驶员创造一致和可靠的充电体验。指南确保驾驶员可以轻松找到充电站的位置,消除使用多个应用程序或账户的需求,保证充电站按需可用,并确保与未来先进的充电技术兼容。政府提到的政策重点有两个,这两个问题都可通过软件来解决。
数据提交:新规要求季度和年度数据提交,适用于根据NEVI公式计划资助的项目,以及通过某些联邦法律资助的公共电动汽车充电站的建设和运营。此外,还要求一次性的数据提交,适用于NEVI项目和根据23 U.S.C.获得的拨款。这些报告要求旨在确保透明,追踪项目进展,并符合扩大电动汽车基础设施的联邦目标。
互操作性最终规定为全国电动汽车充电网络设定了互操作性标准,确保全国范围内各州之间充电器、电动汽车与网络的无缝通信。FHWA专注于充电器与电动汽车间的通信、充电器与网络间的通信和网络间的通信。这些要求实现了智能充电管理,并支持即插即充(Plug and Charge)功能,促进美国统一且高效的电动汽车充电基础设施建设。
有两种类型的电动汽车充电站:一级充电方式:这使用标准的家庭插座(120伏交流),是充电速度最慢的方式。通过普通家庭中的120伏(120V)交流电插座进行充电。可能需要40到50多个小时才能将电池电动车辆(BEV)从零充至80%,而对于插电式混合动力汽车(PHEV)来说,可能需要五到六个小时。
二级充电(Level 2充电): 二级设备通过240V(家用应用) 或 208V(商用应用) 的交流电提供较高充电速度,并且常用于家庭、工作地和公共充电场所。二级充电器可以在四到十小时之间将纯电动汽车(BEV)从0充至80%,并且可以在一到两小时之间将插电式混合动力汽车(PHEV)充满电。
直流快充(DCFC): DCFC 可在大约 20 分钟到一小时内充满 BEV。目前市场上的大多数插电混动车都不支持快充功能。
On the left, Level 2 charging with 240V, and on the right, DCFC, which can charge the car in 20 minutes to one hour.
基于电池的充电站:数据难题在审查上述公开文件和链接后,我注意到电动汽车充电站对电动汽车至关重要,电动汽车在需要快速充电时依赖这些充电站。这些充电站会产生大量的原始数据,这些数据如果能有效利用,可以用来计算每个站点的电力需求。这些数据可以使得各个站点能够参与每日能源供应的竞价。
此外,这些信息也可以帮助电动汽车用户,因为联网的充电站可以计算并推荐电动汽车能跑多远,并找到最近的充电站,还有其他各种可能。但是要实现所有这些应用程序,首先我们需要重视找到一个能够高效处理大量数据的数据库方案的重要性。然后可以进一步利用这些数据进行分析和决策。
接下来我们将探讨如何使用 MongoDB 数据库来存储有价值的数据,使创新者能够开发解决方案,让用户享受无碳旅程,同时并使机器智能协调。
用于存储数据的应用程序参考架构上述图像可以作为一个高层次的应用参考架构。在该架构中,充电站生成的数据将暂时存储在实时流处理引擎上,比如Kafka或MQTT。这些实时流处理引擎将分批处理数据并通过连接器将其发送到MongoDB Atlas。
这种方法有助于调节数据流入MongoDB系统的流量,从而更好地调整传入的数据包。通过批量处理数据,可以减少突发负载的影响,并减少同时使用的连接数。这反过来又通过更有效地管理流量,并确保MongoDB能够平稳处理数据的摄入,避免系统过载,从而提升了系统的性能、可扩展性和可靠性。
您可以查阅相关文档以获得在MongoDB Atlas上的Kafka连接器文档的实际操作经验。
基于桶模式的时间序列集合的数据摄取。MongoDB 当前使用的是其 7.0 版本,具有出色的存储能力,可以存储由机器在特定时间间隔生成的数据。这种带有时间戳的数据通常被称为时间序列数据。
这种数据可能会突然给系统带来压力,尤其是当通过通用API调用获取数据时,可能会耗尽连接池中的所有连接资源。此外,随着这种时间序列数据的涌入,它会增加对计算资源的消耗,从而可能影响到应用程序中的其他功能。而且,时间序列数据往往具有较短的生命周期,其相关性可能会迅速变化——按天、小时,甚至分钟,这取决于具体使用场景。最后,数据迅速写入磁盘,短时间内可能消耗大量存储,使得以后查询变得困难。
为了应对这些问题,MongoDB Atlas 使用一种特定的数据模式,称为桶模式 (bucket pattern),该模式利用时间序列集合。在这种模式下,数据测量值被分组存储到常见块中,主索引是时间戳,次级索引是带有时间戳的元字段。
在 MongoDB 中,时间序列集合(如这里所示)对用户来说看起来与普通集合和文档相似,但实际上,MongoDB 内部创建了一个视图集合。视图向用户展示了一个概览,而系统在后台处理一个桶集合,真正的工作实际发生在该集合中——数据被分桶,同时维护了与时间相关的主索引。
请参阅下方图片,观察 MongoDB 的时间序列是如何高效管理桶模式,同时保持简单易用。这种方法确保熟悉文档建模的用户无需学习新技术。
在时间序列集合中,MongoDB 自动生成了三个集合:View、Buckets 和 Time-Series。每个集合都有特定的用途:
- Buckets 集合负责根据数据的时间戳和元字段对数据进行分类或“分桶”。
- View 集合维护一个对用户友好的文档视图,展示“分桶”过程的结果。
- 时间序列 集合通过以用户熟悉的格式展示数据,把所有内容联系起来,类似于常规的文档集合。
这种方法让用户处理时间序列数据变得更简单,而MongoDB则高效地处理这些复杂后台工作。
时间序列集合中的桶易于压缩,因为它们以列格式存储信息,如图所示。可以看到,我创建了两个桶,分别对应 example_sensor_1 和 example_sensor_2。
[
{
_id: ObjectId('66ba5214941c491b53ee1302'),
control: {
version: 1,
min: {
_id: ObjectId('66ba524d7b61ac9064b696c5'),
timestamp: ISODate('2024-08-12T18:19:00.000Z'),
value: '{Voltage: 0.00 V, Percentage: 0.00, Long: 77.594563, Lat: 12.971599 }'
},
max: {
_id: ObjectId('66ba55c97b61ac9064b69a0d'),
timestamp: ISODate('2024-08-12T18:34:49.887Z'),
value: '{Voltage: 0.07 V, Percentage: 0.61, Long: 77.594563, Lat: 12.971599 }'
}
},
meta: {
sensor: '示例传感器',
topic: '测试主题'
},
data: {
timestamp: {
'0': ISODate('2024-08-12T18:19:57.548Z'),
'1': ISODate('2024-08-12T18:19:58.572Z'),
'2': ISODate('2024-08-12T18:19:59.589Z')
},
_id: {
'0': ObjectId('66ba524d7b61ac9064b696c5'),
'1': ObjectId('66ba524e7b61ac9064b696c6'),
'2': ObjectId('66ba524f7b61ac9064b696c7')
},
value: {
'0': '{Voltage: 0.00 V, Percentage: 0.00, Long: 77.594563, Lat: 12.971599 }',
'1': '{Voltage: 0.00 V, Percentage: 0.00, Long: 77.594563, Lat: 12.971599 }',
'2': '{Voltage: 0.00 V, Percentage: 0.00, Long: 77.594563, Lat: 12.971599 }'
}
}
},
{
_id: ObjectId('66ba55d4941c491b53ee1303'),
control: {
version: 1,
min: {
_id: ObjectId('66ba55dc3c86109548c9e388'),
timestamp: ISODate('2024-08-12T18:35:00.000Z'),
value: '{Voltage: 0.00 V, Percentage: 0.00, Long: 77.594563, Lat: 12.971599 }'
},
max: {
_id: ObjectId('66ba56853c86109548c9e425'),
timestamp: ISODate('2024-08-12T18:37:57.380Z'),
value: '{Voltage: 0.85 V, Percentage: 7.12, Long: 77.594563, Lat: 12.971599 }'
}
},
meta: {
sensor: '示例传感器1',
topic: '测试主题'
},
data: {
timestamp: {
'0': ISODate('2024-08-12T18:35:08.476Z'),
'1': ISODate('2024-08-12T18:35:09.562Z'),
'2': ISODate('2024-08-12T18:35:10.588Z')
},
_id: {
'0': ObjectId('66ba55dc3c86109548c9e388'),
'1': ObjectId('66ba55dd3c86109548c9e389'),
'2': ObjectId('66ba55de3c86109548c9e38a')
},
value: {
'0': '{Voltage: 0.00 V, Percentage: 0.00, Long: 77.594563, Lat: 12.971599 }',
'1': '{Voltage: 0.00 V, Percentage: 0.00, Long: 77.594563, Lat: 12.971599 }',
'2': '{Voltage: 0.00 V, Percentage: 0.00, Long: 77.594563, Lat: 12.971599 }'
}
}
},
{
_id: ObjectId('66ba5688941c491b53ee1304'),
control: {
version: 1,
min: {
_id: ObjectId('66ba5691b9c27fbdca469402'),
timestamp: ISODate('2024-08-12T18:38:00.000Z'),
value: '{Voltage: 0.00 V, Percentage: 0.00, Long: 77.594563, Lat: 12.971599 }'
},
max: {
_id: ObjectId('66ba56bdb9c27fbdca46942c'),
timestamp: ISODate('2024-08-12T18:38:53.894Z'),
value: '{Voltage: 0.90 V, Percentage: 7.53, Long: 77.594563, Lat: 12.971599 }'
}
},
meta: {
sensor: '示例传感器2',
topic: '测试主题'
},
data: {
timestamp: {
'0': ISODate('2024-08-12T18:38:09.877Z'),
'1': ISODate('2024-08-12T18:38:10.903Z'),
'2': ISODate('2024-08-12T18:38:12.022Z')
},
_id: {
'0': ObjectId('66ba5691b9c27fbdca469402'),
'1': ObjectId('66ba5692b9c27fbdca469403'),
'2': ObjectId('66ba5694b9c27fbdca469404')
},
value: {
'0': '{Voltage: 0.00 V, Percentage: 0.00, Long: 77.594563, Lat: 12.971599 }',
'1': '{Voltage: 0.00 V, Percentage: 0.00, Long: 77.594563, Lat: 12.971599 }',
'2': '{Voltage: 0.00 V, Percentage: 0.00, Long: 77.594563, Lat: 12.971599 }'
}
}
}
]
# 小规模的实施和展示
这一实现分为三个部分:硬件、中间件和数据库。这些组件通过API调用在各层之间互相连接。我将使用开源库和框架来支持硬件和中间件层。在数据库层,我将使用MongoDB的时间序列功能。我将在详细解释数据库组件时说明这一选择的理由。我将分别介绍每个组件。
## 硬件: 硬件设备
我的项目硬件部分选择了ESP8266,这是一款广为使用的开发板,以其灵活性和丰富的输入输出引脚而闻名。这些引脚对于与各种传感器、执行器及其他外设的顺畅连接来说非常重要。
此外,我还加入了TP4056模块,它是一个电池管理系统。该模块在调节交流电源的输入输出电流方面起着关键作用,确保连接电池的安全,通过有效管理充电过程。此外,TP4056模块还提供了有价值的监控功能,能够实时监控电池的状态和性能。
我选择了18650锂离子电池作为演示用的电池。18650电池以其高能量密度、小巧的尺寸和可靠性而闻名,是为便携式电子设备供电的理想选择,比如我正在开发的设备。凭借其大容量特性,18650电池能够确保长时间的运行,适用于多种应用场景,如电动汽车充电站。
请参见以下电路图示,所有组件都按照此图示连接:
![](https://imgapi.imooc.com/6734016c09e4406f14000817.jpg)
ESP8266 运行 C++ 代码,我已经在我的 GitHub 页面 [GitHub](https://github.com/nhpjoshi/EV_TimeSeries) 上分享了我的 C++ 源代码。
## 中间件技术
我在项目中集成了ExpressJS库,它主要用于处理中间件操作。ExpressJS以其简单性和灵活性著称,适合用于构建Web应用程序和API。它能高效地处理与MongoDB的API交互,确保数据库与其它系统组件之间的通信顺畅。
ExpressJS 在处理从硬件接收到的消息以及管理这些消息在 MongoDB 中的存储或检索方面发挥着关键作用。其强大的路由功能可以创建用于处理各种请求(如获取、插入、更新和删除数据)的端点。
为了更好地说明系统架构,我准备了简明的图表。该图表展示了中间件层如何协调数据流的流动,从硬件数据源流向MongoDB目标。它突出了各个组件间的交互和依赖关系,展示了ExpressJS如何有效地管理系统内的通信和数据处理。
![](https://imgapi.imooc.com/6734016d09e9377914000620.jpg)
请看我在上面解释的那个实现的[演示](https://www.linkedin.com/feed/update/urn:li:activity:7192965106350149633/)。
# 简单说一下
很高兴你能看到这里!我做了一个小的演示,展示了如何在时间序列集合中存储电池数据。去看看我在领英上的演示。代码也在[Github](https://github.com/nhpjoshi/EV_TimeSeries)上。
总之,我认为电动汽车快速普及凸显了有效电动汽车充电基础设施建设的迫切需求。国家电动汽车基础设施计划及其他联邦倡议对于扩大充电的可访问性并确保全国一致和可靠的充电体验至关重要。然而,这些站点产生的大量时间序列数据在数据管理及系统性能方面带来了重大挑战。
MongoDB Atlas 通过采用时间序列数据模式和桶策略,为解决这些挑战提供了强大的解决方案,这可以高效地组织和管理大量与时限相关的大数据。通过利用流处理引擎和 MongoDB 的高级特性,电动汽车充电站可以优化数据流,增强系统的可扩展性,并支持创新应用,从而提升电动汽车用户的体验。
电动汽车基础设施和数据管理方面的不断推进的进展和策略实施将继续推动向更可持续和高效的交通系统转型。随着技术的发展,诸如 MongoDB 之类的解决方案将在支持时间序列数据和开发人员数据平台的能力以及电动汽车生态系统的成长和发展方面发挥关键作用。
有问题吗?想要展示你的作品吗?一起来加入我们的[MongoDB 开发者社区](https://www.mongodb.com/community/forums/)吧!