麦斯科技 · 2023年04月02日 · 四川

将物联网边缘设备与云原生分析集成,以获得更智能的监测

https://community.arm.com/arm-community-blogs/b/internet-of-things-blog/posts/integrating-iot-edge-devices-with-cloud-native-analytics

作者:Ajeet Singh Raina 2023年3月29日

想象一下,你是一家智能农业公司,使用物联网传感器帮助农民优化作物产量。你们出售各种传感器,可以监测农田中的土壤湿度、温度、湿度和光照水平。

为了帮助农民充分利用他们的资源,你需要建立一个集中的系统。该系统收集来自所有田地的传感器数据,并提供对作物健康和生长的实时监测。有了这些数据,农民可以在知情的情况下决定何时灌溉、施肥和收割作物。

使用Neo4j,一种图形数据库技术,可以成为从收集的数据中释放有价值监测的关键。它还使智能农业系统能够充分发挥其潜力。

在这篇博客文章中,我们探讨了如何使用Neo4j来构建一个强大的智能农业系统。我们首先讨论什么是Neo4j,以及为什么它是存储和查询复杂、互连数据的理想选择。然后,我们深入研究Neo4j在智能农业中的具体用例,例如识别作物模式、预测作物产量和优化资源利用。最后,我们将逐步介绍如何构建基于Neo4j的智能农业系统,帮助农民做出更好的决策,提高作物产量。

架构

硬件组件

1.PNG

2.PNG

软件组件

Jetson Nano开发套件SD卡固件:
https://developer.nvidia.com/embedded/l4t/r32_release_v7.1/jp_4.6.1_b110_sd_card/jeston_nano/jetson-nano-jp461-sd-card-image.zip

etcher:https://www.balena.io/etcher/

desktop Docker:
https://www.docker.com/products/docker-desktop/

Neo4j Aura数据库实例:
https://neo4j.com/cloud/platform/aura-graph-database

步骤1:为操作系统安装准备Jetson Nano SD卡映像

0513.Ajeet blog image 9.png-379x506.png

要将Jetson Nano SD卡映像闪存到SD卡,您可以按照以下步骤操作:
. 从NVIDIA(https://developer.nvidia.com/embedded/downloads)下载Jetson Nano SD卡映像。
. 将SD卡插入计算机的SD卡读卡器。
. 从下载并安装Etcher软件https://www.balena.io/etcher/.
. 打开Etcher并选择要闪存的Jetson Nano SD卡映像文件。

6562.Ajeet blog image 10.png-673x392.png

. 解压缩从下载的SD卡映像https://developer.nvidia.com/embedded/downloads
. 选择SD卡驱动器作为下载目标。
. 点击“烧录!”开始烧录进程。

步骤2:连接传感器

Seeed Studio的BME680传感器是一款紧凑型环境传感器,专为移动应用和可穿戴设备设计。它可以高精度测量温度、压力、湿度和室内空气质量,并且设计为功耗非常低。该传感器与流行的微控制器平台兼容,如树莓派和Arduino,使其易于集成到项目中。

5102.Ajeet blog image 11.png-675x506.png

Grove Base Hat是一款40针Grove附加板,旨在与树莓派板兼容。然而,通过将其连接到适当的GPIO引脚,它也可以与NVIDIA Jetson Nano一起使用。它有15个Grove连接器,包括6个数字、4个模拟、3个I2C、1个UART和1个PWM。

该硬件模块提供了一种将Grove传感器和执行器连接到Jetson Nano的简单方便的方法。它支持各种Grove模块,如温度、湿度、光线和声音传感器,以及电机和显示器等执行器。

要将Grove Base Hat连接到Jetson Nano,您必须连接以下引脚:
. Jetson Nano上的VCC至3.3V引脚
. Jetson Nano上的GND到GND引脚
. SDA至Jetson Nano的引脚3(SDA1)
. SCL至Jetson Nano的引脚5(SCL1)

一旦您将Grove Base Hat连接到Jetson Nano,您就可以开始在Jetson Nano项目中使用Grove传感器和执行器。将传感器连接到Grove后,建议使用i2cdetect命令运行I2C检测,以验证您是否看到设备:在我们的情况下,它显示76。请注意,传感器使用I2C或SPI通信协议与微控制器进行通信。

$ i2cdetect -r -y 1
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:          -- -- -- -- -- -- -- -- -- -- -- -- -- 
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
70: -- -- -- -- -- -- 76 --

步骤3:编写Python代码以获取传感器值

以下是从BME680传感器获取传感器值的Python脚本:

from bme680 import BME680

# Initialize BME680 sensor object
sensor = BME680()

# Check sensor is connected
if not sensor.begin():
    print("Failed to initialize BME680 sensor.")
    exit()

# Read and print sensor values
while True:
    if sensor.get_sensor_data():
        temperature = round(sensor.data.temperature, 2)
        humidity = round(sensor.data.humidity, 2)
        pressure = round(sensor.data.pressure, 2)
        gas_resistance = round(sensor.data.gas_resistance, 2)

        print("Temperature: {} C".format(temperature))
        print("Humidity: {} %".format(humidity))
        print("Pressure: {} hPa".format(pressure))
        print("Gas Resistance: {} Ohms".format(gas_resistance))

    else:
        print("Error reading BME680 sensor data.")

    time.sleep(1)

from bme680 import bme680语句导入bme680传感器库,该库提供了从传感器读取环境数据的接口。传感器变量初始化BME680传感器对象。if not sensor.begin():语句检查传感器是否正确连接和初始化。如果初始化失败,代码将退出并打印一条错误消息。

代码的主循环重复读取BME680传感器的传感器数据,并将值打印到控制台。time.sleep(1)语句在循环的每次迭代之间暂停代码执行1秒。

此脚本使用BME680库从连接到运行脚本的系统的BME680传感器读取温度、湿度、压力和气体电阻值。结果以循环方式打印到控制台,每次读取之间有1秒的延迟。

假设BME680传感器已连接并正常工作,则输出如下所示:
温度:26.68摄氏度
湿度:41.35%
压力:1008.6 hPa
气体电阻:3110.63欧姆

温度、湿度和压力值分别以摄氏度、百分比和百帕斯卡为单位,使用round()函数四舍五入到小数点后两位。气体电阻值以欧姆为单位,也可以四舍五入到小数点后两位。

如果读取BME680传感器数据时出错,脚本将在控制台上打印消息“读取BME680sensor data时出错”

步骤4:编写Python程序,将BME680传感器值发送到Neo4j图形数据库

现在是时候编写Python代码,使用Neo4j驱动程序和BME680环境传感器建立与Neo4j Graph数据库的连接了。


from neo4j import GraphDatabase

from bme680 import BME680

import time

 

# Set up the Neo4j driver

uri = "neo4j+s://41275b2a.databases.neo4j.io"

driver = GraphDatabase.driver(uri, auth=("neo4j", "3DXXXXXXXXXXXXXXXaM"))

 

# Set up the BME680 sensor

sensor = BME680()

 

# Define a function to create a sensor reading node in Neo4j

def create_sensor_reading(tx, temperature, humidity, pressure, gas):

    tx.run("CREATE (:SensorReading {temperature: $temperature, humidity: $humidity, pressure: $pressure, gas: $gas, timestamp: $timestamp})",

           temperature=temperature, humidity=humidity, pressure=pressure, gas=gas, timestamp=int(time.time()))

 

# Generate and insert sensor readings into Neo4j every 5 seconds

while True:

    if sensor.get_sensor_data():

        temperature = round(sensor.data.temperature, 2)

        humidity = round(sensor.data.humidity, 2)

        pressure = round(sensor.data.pressure, 2)

        gas = round(sensor.data.gas_resistance, 2)

 

        with driver.session() as session:

            session.write_transaction(create_sensor_reading, temperature, humidity, pressure, gas)

            print(f"Inserted sensor reading - temperature: {temperature}, humidity: {humidity}, pressure: {pressure}, gas: {gas}")

    else:

        print("Error reading BME680 sensor data.")

 

    time.sleep(5)

此Python代码使用Neo4j驱动程序和BME680环境传感器建立与Neo4j图形数据库的连接。然后,它定义了一个函数,在图形数据库中创建一个传感器读取节点,其中包含当前的温度、湿度、压力、气体阻力和时间戳。代码的主循环每5秒重复生成一次传感器读数,并使用定义的函数将其插入图形数据库。

from neo4j import GraphDatabase语句导入neo4j驱动程序,该驱动程序允许Python代码与neo4j数据库交互。from bme680 import bme680语句导入bme680传感器库,该库提供了从传感器读取环境数据的接口。

uri变量指定Neo4j数据库的位置和访问该数据库的凭据。驱动程序变量使用指定的uri和凭据初始化Neo4j驱动程序。

传感器变量初始化BME680传感器对象。create_sensor_reading函数接收Neo4j事务对象(tx)和当前传感器读数(温度、湿度、压力、气体和时间戳)。然后使用给定的设备在图形数据库中创建一个新节点。

代码的主循环重复读取BME680传感器的传感器数据,并使用Neo4j事务将读数插入图形数据库。time.sleep(5)语句在循环的每次迭代之间暂停代码的执行5秒

步骤5:导入Neo4j Python模块

git clone https://github.com/collabnix/bme680-jetson-neo4j
cd bme680-jetson-neo4j

导入Neo4j Python模块

您可以使用pip为Python安装Neo4j驱动程序:

pip install neo4j
python3 sensorloader.py

结果

Inserted sensor reading - temperature: 26.68, humidity: 41.35, pressure: 1008.6, gas: 3110.63

Inserted sensor reading - temperature: 12.42, humidity: 49.71, pressure: 1149.34, gas: 4815.11

Inserted sensor reading - temperature: 27.73, humidity: 77.2, pressure: 1081.24, gas: 4737.95

Inserted sensor reading - temperature: 19.22, humidity: 50.17, pressure: 958.73, gas: 516.57

步骤6:设置Neo4j Docker扩展

Neo4j Aura是Neo4j提供的一种完全托管的云数据库服务。它是一个数据库即服务(DBaaS)产品,允许您在云中创建、部署和管理自己的图形数据库。这就不必担心底层基础设施和维护任务。假设您已经安装并配置了Neo4j Aura DB连接UI,下一步将安装Neo4j Docker Desktop。

打开Docker Dashboard>Extensions>安装Neo4j Docker Extension。

7268.Ajeet blog image 12.png-663x393.png

要允许Neo4 Docker Extension连接到远程Neo4j Aura DB,您必须提供连接URL、身份验证类型和凭据。一旦成功,您应该能够开始运行密码查询。

2161.Ajeet blog image 13.png-671x419.png

步骤7:测量气体浓度

BME680传感器测量几种不同气体的浓度,包括挥发性有机化合物(VOC)、一氧化碳(CO)和二氧化氮(NO2)。这是除了测量温度、湿度和压力之外的。要从传感器中获取这些气体的浓度,可以使用BME680类的get_sensor_data()方法。这将返回一个包含最新传感器读数的BME680Data对象。然后,您可以使用以下属性访问BME680Data对象中的气体浓度值:
. gas_reresistance:气体传感器的电阻,单位为欧姆,与空气中挥发性有机物的浓度有关。
. gas(List):不同气体的浓度,单位为百万分之一(ppm),包括CO和NO2。


from neo4j import GraphDatabase
import time
import bme680


# Set up the Neo4j driver

uri = "neo4j+s://your-neo4j-instance-url-here"

driver = GraphDatabase.driver(uri, auth=("neo4j", "your-neo4j-instance-password-here"))

# Set up the BME680 sensor

sensor = bme680.BME680(bme680.I2C_ADDR_PRIMARY)

# Define a function to create a CO2 reading node in Neo4j

def create_co2_reading(tx, co2_concentration):

    tx.run("CREATE (:CO2Reading {concentration: $concentration, timestamp: $timestamp})",

           concentration=co2_concentration, timestamp=int(time.time()))

# Wait for the sensor to warm up

print("Warming up sensor...")

sensor.set_gas_status(bme680.ENABLE_GAS_MEAS)

time.sleep(300)

# Start retrieving CO2 concentration data and inserting it into Neo4j

print("Starting CO2 data collection...")

while True:

    if sensor.get_sensor_data():

        co2_concentration = round(sensor.data.gas_resistance / 10, 2)

        with driver.session() as session:

            session.write_transaction(create_co2_reading, co2_concentration)

            print(f"Inserted CO2 reading - concentration: {co2_concentration}")

    else:

        print("Error retrieving sensor data")

    time.sleep(60)

执行脚本

python3 sensorloader_co2.py

结果

Warming up sensor... (takes 4-5 minutes)

Starting CO2 data collection...

Inserted CO2 reading - concentration: 1294686.

与典型的室内二氧化碳水平相比,1294686.06ppm(百万分之一)的二氧化碳浓度相当高。在通风良好的室内环境中,二氧化碳浓度应在400-1000ppm左右。二氧化碳含量超过1000ppm会导致嗜睡、头痛和其他症状,而超过5000ppm会对健康造成严重影响,在极端情况下甚至死亡。

然而,对二氧化碳水平的解释取决于测量的背景和环境。例如,在一些工业环境中,如啤酒厂或温室,出于特定目的,CO2水平可能会故意升高。同样重要的是要考虑可能影响室内空气质量的其他因素,如湿度、通风和其他污染物的存在。

步骤8:对BME680传感器建模

以下是如何在Neo4j中对BME680传感器及其读数进行建模的示例。首先,您将创建一个“传感器”节点来表示您的BME680传感器。此节点可能具有“名称”和“制造商”等属性,以及您要存储的有关传感器的任何其他信息。

CREATE (:Sensor {name: 'BME680', manufacturer: 'Bosch'})

接下来,您将创建一个“时间戳”节点来表示读取的特定时间点。此节点可能有一个“时间戳”属性,用于存储读取的日期和时间。

CREATE (:Timestamp {timestamp: datetime()})

然后,您将在Sensor节点和Timestamp节点之间创建一个“READS”关系。“温度”、“压力”、“湿度”等财产表示当时从传感器读取的值。例如,要创建温度为25摄氏度、压力为1000hPa、湿度为50%的读数,可以使用以下查询:

MATCH (s:Sensor {name: 'BME680'}), (t:Timestamp)

CREATE (s)-[:READS {temperature: 37.0, pressure: 1168.83, humidity: 37.23}]->(t)

1157.Ajeet blog image 14.png-673x419.png

此查询在传感器节点和时间戳节点之间创建“READS”关系。温度、压力和湿度的财产分别设置为25、1000和50。然后,您可以使用Cypher查询来:

. 从数据库中检索读数;

. 根据时间范围或传感器类型等标准对其进行筛选,以及

. 使用Neo4j Bloom等工具或其他可视化工具以各种方式可视化数据

步骤9:将其绘制到Grafana仪表板

Neo4j为Grafana提供了一个数据源插件,允许您直接在Grafana仪表板内可视化和分析存储在Neo4j图形数据库中的数据。要使用Neo4j数据源插件,您必须从Grafana插件库安装该插件。安装插件后,您可以通过指定数据库URL、用户名和密码将其配置为连接到Neo4j数据库。一旦配置了数据源,就可以使用Neo4j查询语言Cypher创建可视化。Cypher是一种功能强大的图形查询语言,允许您遍历和操作存储在Neo4j数据库中的图形数据。

您可以在几秒钟内在Docker Desktop上打开Grafana来使用Grafana Docker扩展。访问Grafana仪表板并使用默认的admin/admin作为用户名/密码登录。

5050.Ajeet blog image 15.png-673x400.png

登录后,单击“设置”>“数据源”>“插件”,然后搜索Neo4j数据源

0601.Ajeet blog image 19.png-671x394.png

安装Grafana数据源。

8182.Ajeet blog image 17.png-635x419.png

提供Neo4j Aura实例的连接URL、用户名和密码,然后连接。

4263.Ajeet blog image 18.png-667x418.png

Grafana使用Neo4j数据源插件的好处包括:
. 能够在用户友好的界面中可视化和分析复杂的图形数据。
. 与Grafana中提供的各种其他数据源和插件集成。
. 具有动态、交互式可视化功能的可定制仪表板。
. 支持基于Neo4j数据库事件的实时数据流和警报。

0601.Ajeet blog image 19.png-671x394.png

一旦连接到远程Neo4j Aura数据库,就应该能够对传感器数据运行密码查询。


MATCH (sr:SensorReading)

WHERE sr.timestamp >= $timeFrom AND sr.timestamp <= $timeTo

RETURN sr.timestamp as time, sr.temperature as temp, sr.humidity as hum, sr.pressure as press, sr.gas as gas_res

ORDER BY sr.timestamp ASC

3324.Ajeet blog image 20.png-669x418.png

查询使用MATCH子句指定节点标签,并指定一个变量sr来表示具有该标签的节点。WHERE子句使用变量$timeFrom和$timeTo指定一系列时间戳。RETURN子句指定每个传感器读数要返回的财产。ORDER BY子句按时间戳升序对结果进行排序。

7673.Ajeet blog image 21.png-672x242.png

最后,您应该能够创建所有四个仪表板——温度、压力、湿度和气体阻力,如下所示:

6204.Ajeet blog image 22.png-672x340.png

结论

图形数据库能够高效查询复杂且相互关联的数据,使其成为数据往往相互关联的环境监测应用程序的理想选择。这与农业尤其相关,因为农业需要这些数据来提高作物产量。

在这个博客中,我们讨论了如何使用Python将BME680环境传感器与Neo4j图形数据库接口。BME680传感器能够测量温度、湿度、压力和气体阻力。这使其成为环境监测应用的理想传感器,可以改善农业行业的决策。

Ajeet S Raina是Docker的开发者倡导者,也是Arm开发者计划的大使。

推荐阅读
关注数
5774
内容数
525
定期发布Arm相关软件信息,微信公众号 ArmSWDevs,欢迎关注~
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息