简介:面向物联网课程实践的一份PDF教程,基于开源平台ThingsBoard完成智慧农场项目的搭建与数据模拟。资源定位清晰,适合需要完成同类实验或课程设计的学生,也适合初次接触该平台的开发者了解设备配置、仪表盘设计与数据上报流程。教程从实验背景与目的讲起,依次给出设备配置、添加别名、地图仪表盘、空气检测、土壤检测、光照监测、温度湿度模块、土壤盐分、二号大棚以及报警器规则等界面创建步骤,并配套编写随机数据脚本、启动与结束脚本,通过HTTP接口模拟真实设备数据上传,同时提供运行时缺少curl等常见问题的解决方法。内容按实验报告形式组织,步骤直观,可帮助读者快速复现并掌握基于开源物联网平台构建可视化监控项目的方法。资源仅包含一个PDF文件,压缩包大小约1.78MB,目前已有215人学习下载,适合作为课程实验的参考或模板。
1. 基于ThingsBoard的智慧农场项目:从零搭起可复现的物联网可视化平台
如果你手头正好有一台装了ThingsBoard的PC机,想在几小时内把温湿度、光照、土壤盐分、报警器这些农业监测点全部可视化出来,而不是从协议栈开始造轮子,那这份基于ThingsBoard的智慧农场项目教程就是为你准备的。它用HTTP API模拟设备上报,把平台侧的设备管理、仪表盘设计、报警规则跑通一整遍。我做的时候最深的感受是:ThingsBoard这东西,搭UI远比想象中快,坑却藏在脚本和规则链的细节里。下面按我实际操作的顺序,把每个步骤、参数和翻车点一次说清。
2. 设备与仪表盘初始化:先让ThingsBoard认识你的农场
2.1 设备配置与添加流程
打开ThingsBoard控制台后,第一步不是急着画仪表盘,而是先把"设备"这个概念在平台里立住。ThingsBoard里的设备不是物理硬件,而是一个抽象实体,它承载着属性、遥测数据和报警状态,后续所有可视化都是围绕设备展开的。
在左侧菜单进入"设备"页面,点击右上角的加号创建新设备。这里有几个关键字段需要注意:
- 设备名称:建议用能一眼识别的命名规则,比如
greenhouse_1_air、greenhouse_1_soil,避免后面设备多了认不出谁是谁 - 设备类型:填写
farm_sensor作为统一类型,方便后续按类型批量筛选 - 传输配置:保持默认即可,我们走HTTP API上报,不需要额外修改
设备创建完成后,ThingsBoard会自动生成两个凭证:访问令牌(Access Token)和设备ID。其中访问令牌是关键,HTTP上报数据时要放在请求头里做鉴权,格式是X-Authorization: Bearer <token>。设备ID则用于在仪表盘上绑定数据源,这两者不要搞混。
提示:创建设备后立即在设备详情页复制保存访问令牌,后面写模拟脚本,每个设备的令牌对应一个数据源。令牌丢失需要重新生成,并改动脚本,这个时间浪费不值。
2.2 设备别名:让数据源引用可读化
直接在仪表盘上引用设备时会显示原始设备名,如果设备名里有下划线或数字,编辑仪表盘时会比较费眼神。ThingsBoard提供了"别名"机制,相当于给实体起一个逻辑名,仪表盘组件通过别名去引用实体。
操作路径是:在仪表盘页面右上角"编辑"进入编辑模式,选择"实体别名",然后添加一个新的别名。别名必须包含两部分:
- 别名:自定义的易读名字,比如
一号大棚空气监测 - 过滤器类型:选择"设备列表"或"单个设备",并指定刚才创建的设备
单个设备这种用法更精确,在数据源绑定环节不容易出现歧义。多个设备同型号时,再用类型过滤会更高效。我建议同一大棚下所有传感器设备各自定义独立别名,后缀带设备类型,方便在多个组件里快速识别。
2.3 地图仪表盘:让农场监控从"数据"变成"空间"
设备配置和别名准备好之后,先别急着画折线图,把地图仪表盘放前面会更有场景感。地图类组件在ThingsBoard里叫"实体表",但真正好用的是一个集成了OpenStreetMap的卡片组件:在仪表盘里添加一个"地图"部件,数据源选择2.1中创建的设备,然后在设备属性里添加纬度(latitude)和经度(longitude)两个属性,格式为十进制度数。
这样说可能有点抽象——实际上,地图仪表盘能在同一界面里显示多个设备的空间分布。比如在一号大棚里,空气监测模块和土壤监测模块分别挂在农场对角,配置各自的经纬度后地图上会同时出现两个标记点。放大看发现位置和图斑完全对得上,那一刻才真正理解"空间可视化"对农业管理的意义:不是说装个地图组件就完了,而是要让每个监测点位与真实物理位置一一映射。
地图部件的属性配置里,标记颜色可以按设备类型区分,我用绿色对应空气、褐色对应土壤、黄色对应光照,告警设备用红色。设置方式是在部件的"高级"标签里写一个简单的函数。调试时传一个false进去也能让地图正常出图,攻击者很容易忽略这个参数,但它是决定故障拓扑展示完整度的关键。
3. 环境监测模块落地:六大传感器一张屏
3.1 空气检测与土壤检测
回到仪表盘编辑界面,添加部件库中的"图表"部件,选择折线图。编辑数据源时,选实体别名,再选遥测键(key),比如pm25、humidity。这里遥测键的命名必须和后面脚本里JSON数据的key保持一致,比如脚本上报{"pm25": 35.6},仪表盘数据源就选pm25,对不上只会显示空白曲线。
空气检测模块我加了一个大气压的副Y轴。如果是温湿度这类完全不同的量级放同一张图,不分开设Y轴,某条线会压成一条直线。比如温度20-35之间波动、湿度50%-90%波动,数字接近但含义不同,强制同轴显示的结果是湿度曲线的变化幅度被温度的范围撑扁,特征模式直接丢失。
土壤检测模块同理,选择遥测键soil_moisture。要重点提示的是:土壤检测和空气检测的更新频率可以被设计成不同值——物理上土壤温度变化就慢,用同频上报纯属浪费流量。脚本里为土传传感器设置更高的上报间隔,这样曲线均匀平滑,且不会产生多余的平台存储压力。
3.2 光照与温湿度模块
光照监测模块我用的是"LED指示灯"部件来显示光照强度区间,同时在旁边放一个"模拟量表"显示具体lux数值。LED指示灯部件通过阈值配置,低于300显示灰色、300-800显示蓝色、高于800显示黄色,这样一眼就能判断大棚内光照是否充足。阈值配置里要留意比较符方向,等于写反了会出现光照800却显示灰色的情况。
温湿度模块我用双轴图,温度在左、湿度在右。创建的设备需要上报两个key:temperature和humidity。仪表盘里各加一个数据源就可以,不需要建两个部件。双轴设置的入口是部件属性的Y轴配置,勾选"显示第二个Y轴",把湿度曲线绑定到Y轴2,范围设为0-100,温度范围按季节动态调整。这个配置逻辑适用所有农业场景,不限于单一设备。
3.3 土壤盐分与二号大棚的复用
盐分模块用的是"模拟量表",范围0-10 mS/cm,超过阈值会变色。第五个模块创建完成后,二号大棚的做法是直接复制一号大棚的仪表盘:仪表盘属性里选择"从当前仪表盘创建副本"。这是个至关重要的做法——复用比手工新建省出至少半小时,尤其对于还有六个以上监测模块的项目。
复制后在副本里修改别名为二号大棚对应的设备,替换数据源,仪表盘的布局、图表类型、尺度范围全部保留。我发现复制后容易遗漏修改部件的标题,比如一号大棚的盐分刻度移到二号大棚里面去了,但三块都在页面上显示为"一号大棚"。若后面项目扩展到多个大棚,第一类复盘就是检查所有部件的标题与数据源是否双双替换,别只改了一个地方。
4. 报警器与规则链:从被动展示到主动告警
4.1 规则与条件定义
到此为止仪表盘都是静态展示,数据异常了不会有人知道。ThingsBoard里的规则链就是用来解决这个事的。在"规则链"页面创建一条新规则链,比如叫farm_alarm_rules。规则链由多个节点组成,核心节点是"过滤器"和"动作"。最常用的过滤器是按消息类型过滤——我们HTTP上报的数据类型为"遥测",所以过滤器节点选择特定消息类型并填遥测。
条件定义我用的是脚本节点。例如盐分超过5.5就触发报警,脚本大致是这样的:
if (msg.soil_salinity > 5.5) { return { msg: msg, metadata: metadata, msgType: msgType }; } else { return {}; }返回空对象表示不满足条件,规则链不再往下走。返回原消息表示继续执行。
4.2 报警部件与清除逻辑
在规则链的后续动作节点里,选择"创建报警"。报警类型填high_salinity,严重性按级别设置。同时可以接一个"发送邮件"节点,服务器没配SMTP的话这里会报错,但并不影响报警记录本身。
报警一旦产生,仪表盘上绑定该设备的部件会自动显示报警状态。但ThingsBoard不会自动清除报警——即使下一次上报盐分已经恢复正常,报警记录仍然存在。解决办法是在规则链里再加一个判断:
if (msg.soil_salinity <= 5.5) { return { msg: msg, metadata: metadata, msgType: msgType }; } else { return {}; }这个分支接"清除报警"节点,当盐分回落时自动把对应报警关掉。不加清除逻辑的后果是:一个历史报警可能一直悬挂,后续想用报警位做统计时会发现数据失真,搞不清哪些是真故障、哪些是历史残留。
提示:规则链调试器值得多用。在规则链页面打开调试模式,尝试手动上报一条超限数据,可以看到消息如何流经各个节点、在哪一步被过滤、在哪一步被丢弃——这是排查报警不触发的最快路径。
5. 模拟设备脚本:让数据像真实传感器一样跳动
5.1 数据文本与随机数据生成
没有物理传感器,就得靠脚本造数据。ThingsBoard平台侧的配置全部完成后,模拟脚本就成了整个项目的引擎。
第一步,新建一个数据模板文件data_template.txt,定义数据传输格式:
{"temperature": 25.3, "humidity": 62.5, "pm25": 35.8, "soil_moisture": 42.1, "soil_salinity": 3.2, "illumination": 750.5}这个JSON结构里的每个键对应仪表盘部件绑定的遥测key,不要随便改名。
第二步,生成随机数据脚本generate_data.sh:
#!/bin/bash # 生成符合农作物生长环境的模拟数据 # 温度:20-35摄氏度 湿度:50%-90% # 光照:300-800 lux temp=$((20 + RANDOM % 16)) humidity=$((50 + RANDOM % 41)) pm25=$((20 + RANDOM % 60)) soil_moisture=$((30 + RANDOM % 50)) soil_salinity=$((2 + RANDOM % 4)) illumination=$((300 + RANDOM % 501)) echo "{\"temperature\": $temp, \"humidity\": $humidity, \"pm25\": $pm25, \"soil_moisture\": $soil_moisture, \"soil_salinity\": $soil_salinity, \"illumination\": $illumination}"需要注意:bash的$RANDOM只生成0-32767的整数,想要带小数得用printf格式化或结合awk处理。纯整数用于模拟完全没问题;如果后续要做平滑曲线或算法验证,建议切换到Python脚本,用random.uniform生成连续值。
5.2 启动与结束脚本
数据生成后还需要上报到ThingsBoard。启动脚本fakeData.sh如下:
#!/bin/bash ACCESS_TOKEN="YOUR_DEVICE_ACCESS_TOKEN" THINGSBOARD_HOST="your-thingsboard-server-ip" while true; do # 生成带随机波动的数据并POST到平台 data=$(./generate_data.sh) curl -s -X POST "http://$THINGSBOARD_HOST/api/v1/$ACCESS_TOKEN/telemetry" \ -H "Content-Type: application/json" \ -d "$data" sleep 10 done循环里每10秒上报一次,可以根据需要调整sleep时间。一号大棚模拟间隔设置为10秒——太快会造成大量冗余数据和无意义的存储开销,平台侧曲线会被密集的点位掩盖掉真实趋势;太慢则调试时等半天才能看到数据更新,建议开发阶段5-10秒、演示阶段10-30秒。
结束脚本比较简单,杀掉对应进程即可:
#!/bin/bash pkill -f fakeData.sh pkill -f generate_data.sh需要注意的是,如果fakeData.sh里的curl因为网络抖动挂起,pkill一条命令是杀不干净所有关联子进程的。更稳妥的做法是用pkill -f配合pgrep再确认,或者用PID文件管理——启动脚本执行前把当前PID写到/tmp/farm_demo.pid,结束脚本直接从文件读取PID再kill:
echo $$ > /tmp/farm_demo.pid kill $(cat /tmp/farm_demo.pid)5.3 权限设置与运行
脚本写好后必须加执行权限:
chmod +x generate_data.sh fakeData.sh stop_farm.sh没有执行权限直接运行会报Permission denied。运行后ThingsBoard的"最新遥测"页面如果能看到不断刷新的数据行,说明脚本和平台之间的链路已经打通。此时切到仪表盘,折线图应该是动态向前滚动的状态。
如果curl版本过老,可能还需要确认它支持-H和-d参数。否则数据一直报错但看不出原因。
6. 常见问题排查与后续验证:绕开我踩过的五个坑
6.1 curl命令缺失与脚本权限失效
我在模拟运行阶段第一次执行就遇到./fakeData.sh: line 38: curl: command not found。这是典型的系统环境没有curl。当时在干净系统上直接跑脚本,没注意基础命令是否齐全。解决办法:
sudo apt-get update sudo apt-get install curl -y安装完重新跑脚本即恢复正常。
第二个是脚本执行权限问题——之前明明chmod +x过了,结果运行还是报权限错误。原因是编辑脚本时用文本编辑器保存,如果编辑器创建了新文件(比如通过重定向生成),原文件的执行位就会丢失。检查办法是ls -l查看文件权限位,确认-rwxr-xr-x三个x都在。修改文件时务必在原有文件上编辑,不要在保存时生成新副本。
6.2 数据没显示:令牌、遥测键与时间窗口三个方向
仪表盘上曲线空白,最常见的三个原因是:访问令牌填错、JSON的key与图表的遥测键不一致、时间窗口范围不对。令牌错会出现401报错;key不对时平台能收到数据但图表找不到数据源;时间窗口选了"过去一小时"但脚本刚启动还在10秒间隔内产生数据时,直接查最新数据反而看不到。
排查顺序建议:先看脚本运行有没有报错,再确认ThingsBoard设备详情页的"最新遥测"里有没有数据,最后回仪表盘检查部件数据源的遥测键拼写。别一上来就折腾规则链,大部分空白都是这三级问题里的第一级。
6.3 双轴图和报警不触发的隐藏陷阱
双轴图配置后出现一条线被压平的情况,检查一下两个数据源的量级差异和Y轴范围设置。温度0-40和湿度0-100放同一轴,湿度波动变化会被温度区间稀释到肉眼看不见。解决方式是配置独立Y轴,至少让湿度轴范围(例如40-100)覆盖实际值域,折线才能呈现足够的起伏幅度。
报警不触发的情况则要返回看规则链里脚本节点的条件表达式。判断盐分大于5.5时正常创建报警,但盐分一直不高的情况下很难知道脚本是否真的工作。此时开启规则链调试模式,手动用POST工具发一条盐分等于7的数据进去,调试界面会完整显示消息的流转路径,过滤节点是否拦截一目了然。
6.4 时间窗口没设对导致报警不上屏
还有一类很隐蔽的坑:告警产生后仪表盘上的部件没有变红。往往不是因为规则链的问题,而是仪表盘的时间窗口把"最近一小时"过滤掉了,报警时间恰好落在窗口外。把时间窗口改为"今天"或者清除时间过滤条件,告警状态自然会出现。这类问题排查优先级应该放在规则链之前。
6.5 外网访问延迟导致上报失败后的重试策略
另一个我实际遇见的场景是ThingsBoard服务器在内网,脚本在同网段PC机上运行,偶尔出现curl超时或连接拒绝,脚本没有重试机制,报错就退出了。简单但有效的补救是在curl后面加--retry 3 --retry-delay 5,让脚本在偶发网络抖动时具备自愈能力。这个参数在长时间运行的模拟脚本里是性价比最高的加固手段,尤其是要跑一整晚做数据积累的场景。
6.6 仪表盘复用后的标题残留检查
复制一号大棚仪表盘生成二号大棚后,最容易遗漏的是部件标题。我见过有人一号大棚和二号大棚的湿度图标题都叫"一号大棚湿度",后面做多棚对比时数据来源彻底分不清。复制完先全局过一遍标题和别名,这个动作花不了五分钟,但能省下后期整理仪表盘时一整天的困惑。
6.7 验证方法:用一份稳定的数据源做回归
数据持续上报后,如何验证仪表盘和报警功能是正常工作的?我的做法是准备一份固定的基础数据模板,比如known_data_template.txt,内容是一组确定的环境值。每隔一段时间手动执行一次curl,把这份固定数据POST到平台,然后检查对应设备的仪表盘曲线是否出现一个已知的量级变化。这样做的好处是:脚本的随机数逻辑出问题、网络传输丢数据、平台侧解析失败,都能通过对比期望值和实际显示数据来定位,不至于让随机波动把真实故障掩盖掉。
从那以后,我每次搭类似的ThingsBoard演示项目,都会把上面这些环节强制走一遍:先确认基础命令齐全、再验证令牌和遥测键、最后检查仪表盘时间窗口和报警清除逻辑。这套流程帮我躲开了不少返工,希望也能帮你少踩几个坑。
本文还有配套的精品资源,点击获取