Elasticsearch 和 Arduino:一起变得更好!

作者:Enrico Zimuel

使用 Arduino IoT 设备与 Elasticsearch 和 Elastic Cloud 进行通信的简单方法

在 Elastic®,我们不断寻找简化搜索体验的新方法,并开始关注物联网世界。 来自物联网的数据收集可能非常具有挑战性,尤其是当我们拥有数千台设备时。

Elasticsearch® 对于收集、探索、可视化和发现数据非常有用 - 对于来自多个设备的所有数据。 Elastic 的分布式特性使其能够轻松处理来自数百万台设备的请求。

感谢与物联网领域非常受欢迎的品牌 Arduino 的合作,我们测试了一些设备,并开发了一个实验性开源库,可以以非常简单的方式将 Arduino 板连接到 Elasticsearch。

什么是 Arduino?

Arduino 是全球开源硬件和软件领域的领导者,拥有超过 3000 万活跃用户! 该品牌旨在帮助各类创客创建自己的互动项目,随着用户面临新的挑战,该品牌不断成长和适应,并扩展到物联网、可穿戴设备、3D 打印和嵌入式环境。 它还开设了专门的专业业务部门,以支持公司成为各自领域的创新者,采用定制且用户友好的方法,避免供应商锁定,并利用 360° 生态系统,做好从原型设计到大规模生产的准备。

Arduino 专业版

在 Arduino Pro 的高性能技术解决方案中,你会发现低功耗且安全的模块系统,例如 Portenta H7,它可以使用高级语言和 AI 进行编程,同时在其可定制的上执行低延迟操作硬件和最新的 Portenta C33,凭借一系列精简且经济高效的功能,使物联网比以往任何时候都更容易访问。

此外,Arduino Pro 的工业级产品适合整个 Arduino 生态系统,其中包括云服务、无数软件库和社区共享的即用型草图,当然还有满足任何需求的各种组件。 其中包括 MKR WiFi 1010 和 Nano RP2040 板等流行产品 —— 创客运动名副其实的基石。

Elasticsearch 和 Arduino

我们开发了一个研发项目来提供一个在 Arduino 模块上运行的简单 Elasticsearch 客户端库(用 C++ 编写)。 没错:现在你可以直接从 Arduino 板与 Elasticsearch 集群通信!

我们使用 Portenta H7、MKR WiFi 1010 和 NANO RP2040 Connect 测试了该库。 任何具有 Wi-Fi 或以太网连接的 Arduino 板都可以使用该库。

我们使用 Elastic Cloud 作为数据库,从相邻设备收集所有数据并提供平均温度的详细信息。 这是控制工程应用中的典型场景。

想了解更多? 以下是包含所有详细信息的简单教程。

使用案例:监控多个物联网设备的温度

我们为一家需要管理位于意大利的多个物联网设备的公司设计了一个用例。 每个设备将来自传感器的数据(例如温度)发送到 Elastic Cloud。 使用 Elastic Cloud,该公司可以管理任何规模的物联网设备,而无需管理专用基础设施。 此外,该公司还需要根据相邻设备的平均温度来调整每个设备的一些内部参数,范围为 100 公里,这是控制工程应用中的典型场景。

使用 Elasticsearch,我们可以使用过滤、聚合、多重匹配、地理空间、向量搜索 (kNN)、语义搜索和机器学习等搜索功能提供多种反馈。

在此用例中,我们使用平均聚合 (average aggregation) 和地理距离 (geo-distance) 来检索 100 公里之间的所有设备。

使用 Elastic Cloud 中提供的 UI Kibana®,我们可以轻松创建仪表板来监控来自所有设备的数据。 由于我们还有地理数据,因此我们可以在地图中表示这些信息。

这是用不同颜色代表不同温度(蓝色是冷,绿色是热)创建的 heat map。

Elastic Cloud 设置

第一步是拥有 Elastic Cloud 帐户。 如果你没有,可以在此处注册试用(无需信用卡)。 登录后,你可以创建新部署,选择要使用的 Elasticsearch 实例的大小。

创建部署后,你需要检索端点 URL 并生成 Elasticsearch 的 API 密钥。 你可以阅读本指南来获取此信息。 对于高级用例,你还可以创建用于不同设备的 API 密钥组,并更改 API 策略以仅允许使用特定索引。

如果你想有自己的本地部署,请参阅文章 “如何在 Linux,MacOS 及 Windows 上进行安装 Elasticsearch”。

准备Elasticsearch索引

我们需要创建一个索引来存储来自 Arduino 板的数据。 我们想要存储温度值、使用地理位置(纬度和经度)的设备位置、设备标识符名称和时间戳。

我们可以通过向 Elasticsearch 发出以下 HTTP 请求来创建索引 “temperature”:

PUT /temperature
{"mappings": {"properties": {"temperature": { "type": "float" }, "timestamp":   { "type": "date" }, "location":    { "type": "geo_point" },"device-id":   { "type": "keyword" }}}
}

要发送此 HTTP 请求,你可以使用 Elastic Cloud 中 Kibana 的 Dev Tools。

我们希望存储每次设备发送数据时操作的时间戳。 这可以使用 Elasticsearch 的摄取管道 (ingest pipeline) 功能来完成。 摄取管道是 Elasticsearch 在索引(存储)文档之前执行的操作。 例如,管道可以根据某些计算分配特定文档字段的值。

在我们的例子中,我们只需要存储时间戳,我们就可以创建一个 “set-timestamp” 管道:

PUT _ingest/pipeline/set-timestamp
{"description": "sets the timestamp","processors": [{"set": {"field": "timestamp","value": "{{{_ingest.timestamp}}}"}}]
}

使用这个管道,我们可以将数据发送到 Elasticsearch,如下所示:

POST /temperature/_doc?pipeline=set-timestamp
{"temperature": 21.45,"device-id": "H7-001","location": {"type": "Point","coordinates": [12.4923, 41.8903]}
}

这里的 device-id H7-001 是 Arduino 板的名称,location 是用12.4923(经度)和41.8903(纬度)表示的地理点,这是罗马斗兽场(意大利)的位置。

请注意,我们没有指定时间戳值,因为这是使用 “set-timestamp” 管道(在 URL 中指定为查询字符串)自动生成的。

地理距离查询

要检索 100 公里以内设备的平均温度,我们可以使用以下 Elasticsearch 查询:

GET /temperature/_search
{"query": {"bool": {"must": {"match_all": {}},"filter": {"geo_distance": {"distance": "100km","location": [12.4923, 41.8903]}}}},"aggs": {"avg_temp": { "avg": { "field": "temperature" } }}
}

该查询将返回一个 “avg_temp” 聚合字段,其中包含 100 公里半径内所有设备的平均温度。

Arduino 的 Elasticsearch 客户端的使用

终于到了展示一些 Arduino 代码的时候了! 在这里,我们报告了一个简单的草图,它将温度值发送到 Elastic Cloud,执行地理距离查询获取平均温度,然后等待 30 秒。

此处报告的代码可在 GitHub 存储库 elastic/elasticsearch-arduino 的 examples 文件夹中在线获取。 该草图使用 elasticsearch_config.h 文件,如下所示:

#define WIFI_SECRET_SSID ""
#define WIFI_SECRET_PASS ""
#define ELASTIC_ENDPOINT ""
#define ELASTIC_PORT 443
#define ELASTIC_CLOUD_API_KEY ""
#define DEVICE_GEO_LON 12.4923
#define DEVICE_GEO_LAT 41.8903
#define DEVICE_ID "x"
#define DEVICE_GEO_DISTANCE "50km"

在我们的示例中,我们使用 Wi-Fi 连接将 Arduino 板连接到互联网。

WIFI_SECRET_SSID 和 WIFI_SECRET_PASS 是要使用的 SSID 网络的名称和 Wi-Fi 密码。

ELASTIC_ENDPOINT 是 Elastic Cloud 端点的 URL,ELASTIC_PORT 是 443,因为 Elastic Cloud 使用 TLS (https)。 ELASTIC_CLOUD_API_KEY 是要在 Elastic Cloud 管理界面中生成的 API 密钥。

该文件还包含与 Arduino 设备相关的其他信息。 我们有地理查询的经度 (DEVICE_GEO_LON) 和纬度 (DEVICE_GEO_LAT)、ID (DEVICE_ID) 和距离 (DEVICE_GEO_DISTANCE)。

填写完前面的信息后,我们可以看一下设计,报告如下。

#include <ArduinoJson.h>
#include <WiFi.h>
#include <WiFiSSLClient.h>
#include "ESClient.h" 
#include "elasticsearch_config.h"// WiFi settings
char ssid[] = WIFI_SECRET_SSID;
char pass[] = WIFI_SECRET_PASS;// Elastic settings
char serverAddress[] = ELASTIC_ENDPOINT;
int serverPort = ELASTIC_PORT;WiFiSSLClient wifi;ESClient client = ESClient(wifi, serverAddress, serverPort); 
int status = WL_IDLE_STATUS;void setup() {Serial.begin(9600);Serial.println("Started");while (status != WL_CONNECTED) {Serial.print("Attempting to connect to Network named: ");Serial.println(ssid);// Connect to WPA/WPA2 network:status = WiFi.begin(ssid, pass);}// print the SSID of the network you're attached to:Serial.print("SSID: ");Serial.println(WiFi.SSID());// print your WiFi shield's IP address:IPAddress ip = WiFi.localIP();Serial.print("IP Address: ");Serial.println(ip);client.setElasticCloudApiKey(ELASTIC_CLOUD_API_KEY);
}void loop() {float temperature;// Set the temperature from a sensor (removing the randomness)temperature = random(10,30) + random(0,100)/100.00;// Prepare the JSON with temperature and geopoint for ElasticsearchStaticJsonDocument<200> doc;doc["temperature"] = temperature;doc["device-id"] = DEVICE_ID;doc["location"]["type"] = "Point";doc["location"]["coordinates"][0] = DEVICE_GEO_LON;doc["location"]["coordinates"][1] = DEVICE_GEO_LAT;String temp;serializeJson(doc, temp);Serial.println("Sending to Elasticsearch:");Serial.println(temp);ESResponse indexResult;// Send the temperature to Elastic CloudindexResult = client.index("temperature", temp, "pipeline=set-timestamp");DynamicJsonDocument result(1024);deserializeJson(result, indexResult.body);if (result["result"] == "created") {Serial.println("Created with _id: " + result["_id"].as<String>());} else {Serial.println("Error sending data: " + indexResult.body);}StaticJsonDocument<512> query;query["query"]["bool"]["filter"]["geo_distance"]["distance"] = DEVICE_GEO_DISTANCE;query["query"]["bool"]["filter"]["geo_distance"]["location"][0] = DEVICE_GEO_LON;query["query"]["bool"]["filter"]["geo_distance"]["location"][1] = DEVICE_GEO_LAT;query["aggs"]["avg_temp"]["avg"]["field"] = "temperature";query["size"] = 0;String search;serializeJson(query, search);Serial.println("Geo-location query:");Serial.println(search);ESResponse searchResult;// Send the temperature to Elastic CloudsearchResult = client.search("temperature", search);DynamicJsonDocument avg(512);deserializeJson(avg, searchResult.body);float avgTemp = avg["aggregations"]["avg_temp"]["value"];int numDevices = avg["hits"]["total"]["value"];Serial.println("Average temperature of " + String(numDevices) + " devices in " + DEVICE_GEO_DISTANCE + ": " + String(avgTemp));Serial.println("Wait 30 seconds");delay(30000);
}

此设计需要 Wi-Fi、WiFiSSLClient(用于使用 TLS 进行连接)进行互联网连接、用于连接 Elasticsearch 的 EsClient 以及用于序列化和反序列化 Json 数据结构的 ArduinoJson 库。

在 setup() 函数中,我们启动 Wi-Fi 连接,并使用 client.setElasticCloudApiKey(ELASTIC_CLOUD_API_KEY) 函数调用设置 Elastic Cloud 的 API 密钥。

客户端对象在主区域中初始化,传递 Wi-Fi 对象、服务器地址(端点)和 HTTP 端口。

在 loop() 函数中,我们有将温度发送到 Elastic Cloud 的代码。 这里的温度只是一个 10 到 30 之间的随机浮点数; 通常它来自连接到 Arduino 板的传感器。

为了准备发送到 Elasticsearch 的文档,我们使用了 ArduinoJson 库。

我们使用以下代码创建一个 “doc” 对象:

StaticJsonDocument<200> doc;
doc["temperature"] = temperature;
doc["device-id"] = DEVICE_ID;
doc["location"]["type"] = "Point";
doc["location"]["coordinates"][0] = DEVICE_GEO_LON;
doc["location"]["coordinates"][1] = DEVICE_GEO_LAT;

该对象被序列化为 JSON 字符串,如下所示:

String temp;
serializeJson(doc, temp);

最后,可以使用索引 API 将存储在 “temp” 变量中的文档发送到 Elasticsearch,如下所示:

ESResponse indexResult;
indexResult = client.index("temperature", temp, "pipeline=set-timestamp");

此 API 使用 “set-timestamp” 管道在索引 “temp” 中添加 “temp” 文档。 结果存储在 “indexResult” 变量中,该变量是一个结构类型,如下所示:

struct ESResponse {int statusCode;String body;
};

“statusCode” 是响应的 HTTP 状态代码,“body” 是响应正文。 如果响应包含值为 “created” 的 “result” 字段,则索引操作成功。

为了获取半径 100 公里内设备的平均温度,我们使用了以下地理距离查询,使用 ArduinoJson 表示。

StaticJsonDocument<512> query;
query["query"]["bool"]["filter"]["geo_distance"]["distance"] = DEVICE_GEO_DISTANCE;
query["query"]["bool"]["filter"]["geo_distance"]["location"][0] = DEVICE_GEO_LON;
query["query"]["bool"]["filter"]["geo_distance"]["location"][1] = DEVICE_GEO_LAT;
query["aggs"]["avg_temp"]["avg"]["field"] = "temperature";
query["size"] = 0;String search;
serializeJson(query, search);ESResponse searchResult;
searchResult = client.search("temperature", search);DynamicJsonDocument avg(512);
deserializeJson(avg, searchResult.body);
float avgTemp = avg["aggregations"]["avg_temp"]["value"];
int numDevices = avg["hits"]["total"]["value"];

搜索的响应包含平均温度作为聚合值。 此外,我们可以使用 Elasticsearch 的 JSON 响应中的 ['hits']['total']['value'] 字段来检索查询检索到的设备数量。

结论

由于与 Arduino 的合作,我们开发了一个非常简单的库,允许直接从 Arduino 板使用 Elasticsearch。 只需几行代码,我们就可以将数据发送到 Elasticsearch 并使用地理定位等执行复杂的阐述。

我们迫不及待地想看看 Arduino 用户将使用 Elasticsearch 设计出哪些其他创意用例。 例如,如果你对生成式人工智能感兴趣,你将享受 Elastic 的所有最新功能。

不要再等待了 —— 尝试一下 Elastic Cloud 和 elasticsearch-arduino 库。

致谢

我要感谢 Arduino 的所有员工,是他们使这个研发项目成为可能。 特别感谢 Giampaolo Mancini 在开发 elasticsearch-arduino 库方面的帮助和协作。 此外,我还要感谢 Arduino 的 Andrea Richetta 和 Stefano Implicito 使这次合作成为可能。

本文中描述的任何特性或功能的发布和时间安排均由 Elastic 自行决定。 当前不可用的任何特性或功能可能无法按时交付或根本无法交付。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/157540.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Webmin(CVE-2019-15107)远程命令执行漏洞复现

漏洞编号 CVE-2019-15107 webmin介绍 什么是webmin Webmin是目前功能最强大的基于Web的Unix系统管理工具。管理员通过浏览器访问Webmin的各种管理功能并完成相应的管理动作http://www.webmin.com/Webmin 是一个用 Perl 编写的基于浏览器的管理应用程序。是一个基于Web的界面…

Python 实训教学,更便捷的学生邀请及内容分发|ModelWhale 版本更新

中秋国庆假期结束&#xff0c;ModelWhale 又迎来了新一轮的版本更新&#xff0c;让我们调整好节奏&#xff0c;一起奔赴新的旅程&#xff01; 本次更新中&#xff0c;ModelWhale 主要进行了以下功能迭代&#xff1a; 新增 一键邀请外部用户加入课程&#xff08;团队版✓&#…

某医疗机构:建立S-SDLC安全开发流程,保障医疗前沿科技应用高质量发展

某医疗机构是头部资本集团旗下专注大健康领域战略性投资与运营的实业公司&#xff0c;市场规模超300亿。该医疗机构已完成数字赋能&#xff0c;形成了标准化、专业化、数字化的疾病和健康管理体系&#xff0c;将进一步规划战略方向&#xff0c;为人工智能纳米技术、高温超导、生…

代码随想录算法训练营第五十八天 |583. 两个字符串的删除操作、72. 编辑距离、编辑距离总结篇

一、583. 两个字符串的删除操作 题目链接/文章讲解/视频讲解&#xff1a;代码随想录 思考&#xff1a; 1.确定dp数组&#xff08;dp table&#xff09;以及下标的含义 dp[i][j]&#xff1a;以i-1为结尾的字符串word1&#xff0c;和以j-1位结尾的字符串word2&#xff0c;想要达…

springboot项目Html页面引入css文件不生效

我的出错原因&#xff1a; 在调用css文件时&#xff1a; <link rel"stylesheet" type"text/css" href"/static/css/style.css" /> 这里我多加了一个/static,而使得css样式不生效 因为在springboot项目中&#xff0c;静态资源是默认存…

TensorFlow入门(二十三、退化学习率)

学习率 学习率,控制着模型的学习进度。模型训练过程中,如果学习率的值设置得比较大,训练速度会提升,但训练结果的精度不够,损失值容易爆炸;如果学习率的值设置得比较小,精度得到了提升,但训练过程会耗费太多的时间,收敛速度慢,同时也容易出现过拟合的情况。 退化学习率 退化学…

PySpark 概述

文章最前&#xff1a; 我是Octopus&#xff0c;这个名字来源于我的中文名--章鱼&#xff1b;我热爱编程、热爱算法、热爱开源。所有源码在我的个人github &#xff1b;这博客是记录我学习的点点滴滴&#xff0c;如果您对 Python、Java、AI、算法有兴趣&#xff0c;可以关注我的…

B站视频“多模态大模型,科大讯飞前NLP专家串讲”记录

文章目录 多模态&#xff1a;对齐 -- align迁移学习和zero-shotClipBlip 多模态&#xff1a; 图片、文字、视频、语音等不同的表征。 表示信息的方式有多种&#xff0c;但是不同的表示方式携带的信息不完全相同。 对齐 – align 如第一个图中&#xff0c;文字内容的描述和图…

shiro反序列化和log4j

文章目录 安装环境shiro漏洞验证log4j 安装环境 进入vulhb目录下的weblogic&#xff0c;复现CVE-2018-2894漏洞&#xff1a; cd /vulhub/shiro/CVE-2010-3863查看docker-compose的配置文件&#xff1a; cat docker-compose.yml如图&#xff0c;里面有一个镜像文件的信息和服…

【数据结构】算法效率的度量方法

&#x1f984;个人主页:修修修也 &#x1f38f;所属专栏:数据结构 ⚙️操作环境:Visual Studio 2022 目录 &#x1f38f;事后统计方法 &#x1f38f;事前分析估算方法 &#x1f38f;函数的渐进式增长 结语 在上篇文章中我们提到了算法的设计要求中我们要尽量满足时间效率高…

【Python 零基础入门】 Numpy

【Python 零基础入门】第六课 Numpy 概述什么是 Numpy?Numpy 与 Python 数组的区别并发 vs 并行单线程 vs 多线程GILNumpy 在数据科学中的重要性 Numpy 安装Anaconda导包 ndarraynp.array 创建数组属性np.zeros 创建np.ones 创建 数组的切片和索引基本索引切片操作数组运算 常…

计算机体系结构和操作系统

这篇文章的主要内容是冯诺依曼计算机体系结构和操作系统的理解。 目录 一.冯诺依曼计算机体系结构 二.操作系统的理解 一.冯诺依曼计算机体系结构 如图是冯诺依曼计算机体系结构&#xff0c;计算机本质就是对数据进行处理的机器&#xff0c;图中&#xff0c;数据从输入设备交给…

uni-app : 生成三位随机数、自定义全局变量、自定义全局函数、传参、多参数返回值

核心代码 function generateRandomNumber() {const min 100;const max 999;// 生成 min 到 max 之间的随机整数// Math.random() 函数返回一个大于等于 0 且小于 1 的随机浮点数。通过将其乘以 (max - min 1)&#xff0c;我们得到一个大于等于 0 且小于等于 (max - min 1…

200、使用默认 Exchange 实现 P2P 消息 之 消息生产者(发送消息) 和 消息消费者(消费消息)

RabbitMQ 工作机制图&#xff1a; Connection&#xff1a; 代表客户端&#xff08;包括消息生产者和消费者&#xff09;与RabbitMQ之间的连接。 Channel&#xff1a; 连接内部的Channel。channel&#xff1a;通道 Exchange&#xff1a; 充当消息交换机的组件。 Queue&#xff…

服务运营 |摘要:学术+业界-近期前沿运筹医疗合作精选

推文作者&#xff1a;李舒湉 编者按 本文归纳整理了近期INFORMS Journal on Applied Analytics中的相关业界合作研究。 这些研究成果体现了运筹学在医疗健康领域实践的效果。文中的学术业界合作使用了不同的研究工具。第一篇文章使用仿真模型帮助诊所进行不同拥挤程度下诊所使用…

【C++】继承 ③ ( 继承的一些重要特性 | 子类拥有父类的所有成员 | 多态性 | 子类可以拥有父类没有的成员 | 代码示例 )

文章目录 一、继承的一些重要特性1、子类拥有父类的所有成员2、子类可以拥有父类没有的成员3、多态性 二、代码示例 一、继承的一些重要特性 1、子类拥有父类的所有成员 子类 继承 父类 , 则 子类 拥有 父类的 所有 成员变量 和 成员函数 ; 这里要注意 : 子类 拥有 父类的 私有…

Python中使用IDLE调试程序

在IDLE中&#xff0c;使用菜单栏中的“Debug”对IDLE打开的python程序进行调试。 1 打开调试开关 选择IDLE菜单栏的“Debug->Debugger”&#xff0c;如图1①所示&#xff1b;此时在IDLE中会显示“[DEBUG ON]”&#xff0c;即“调试模式已打开”&#xff0c;如图1②所示&am…

【使用 TensorFlow 2】03/3 创建自定义损失函数

一、说明 TensorFlow 2发布已经接近5年时间&#xff0c;不仅继承了Keras快速上手和易于使用的特性&#xff0c;同时还扩展了原有Keras所不支持的分布式训练的特性。3大设计原则&#xff1a;简化概念&#xff0c;海纳百川&#xff0c;构建生态.这是本系列的第三部分&#xff0c;…

区块链加密虚拟货币交易平台安全解决方案

区块链机密货币交易锁遭入侵&#xff0c;安全存在隐患。使用泰雷兹Protect server HSM加密机&#xff0c;多方位保护您的数据&#xff0c;并通过集中化管理&#xff0c;安全的存储密钥。 引文部分&#xff1a; 损失7000万美元!黑客入侵香港区块链加密货币交易所 2023年9月&…

如何在Ubuntu 20.04.6 LTS系统上运行Playwright自动化测试

写在前面 这里以 Ubuntu 20.04.6 LTS为例。示例代码&#xff1a;自动化测试代码。 如果过程中遇到其他非文本中提到的错误&#xff0c;可以使用搜索引擎搜索错误&#xff0c;找出解决方案&#xff0c;再逐步往下进行。 一、 环境准备 1.1 安装python3 1.1.1 使用APT安装Py…