SensorSimulator2.0实战:用数据表达式模拟物联网传感器上报 简介一份面向 Android 传感器开发与测试的实用工具包内置 SensorSimulator 2.0 RC1 传感器模拟器覆盖加速度计、指南针、方位、温度、光照、距离、压力、重力、线加速度、旋转矢量、陀螺仪等常见传感器适合在模拟器或缺少真机传感器环境下调试应用。资源共 25 个文件体积 1.53MB包含 Java 源码与 class 字节码、XML 界面与配置、PNG 图标资源、APK 安装包、DEX 文件以及两份 Word 安装说明文档方便开发者按需查看工程结构或直接部署。已有 342 人学习参考。压缩包内附一份自行编写的示例程序标注编译运行通过并配套安装步骤与使用说明可帮助初学者快速理解 SensorSimulator 的接入流程、传感器事件监听和界面展示方式减少环境配置踩坑成本。1. 为什么需要传感器模拟器从一次物联网调试说起做物联网开发的朋友应该都有过这种经历硬件还没到位或者传感器模块还在快递路上但云端平台、数据上报链路、告警规则已经排期上线了。我最早做智慧农业项目时就卡在这个问题上温湿度传感器硬件到货晚了一周但数据看板和后端接口必须按时交付最后只能拿脚本伪造数据硬撑写出来的假数据格式还和真实上报不一致反而给联调埋了一堆雷。SensorSimulator2.0 就是用来解决这个场景的工具。它本质上是一个传感器数据仿真器能够按照指定协议、指定频率、指定数据范围模拟各类传感器节点的上报行为让你在没有真实硬件的情况下先把整个数据处理链路跑通。它的核心价值有三个一是让开发进度不被硬件供应链卡脖子二是可以在可控范围内构造极端数据比如高温告警、信号丢失、波动异常三是为演示环境提供稳定的虚拟数据源。这篇文章适合谁看如果你是做 IoT 平台开发、嵌入式应用调试、数据可视化大屏、或者智能硬件 Demo 演示的开发者这篇内容可以直接帮你省掉自己造轮子的时间。下面我会从设计思路、核心配置、完整例子到排坑经验把 SensorSimulator2.0 的用法拆开聊清楚。2. SensorSimulator2.0 的整体设计思路拆解2.1 模拟器的核心模型传感器节点、数据点与上报策略SensorSimulator2.0 在架构上抽象出了三个核心概念传感器节点Sensor Node、数据点Data Point和上报策略Report Policy。传感器节点对应一个物理设备比如“会议室东侧温湿度计”或者“仓库3号门门磁传感器”。节点本身持有标识信息比如设备ID、设备名称、分组标签这些字段会出现在每条上报数据中方便下游系统识别数据来源。数据点则是传感器上具体的一个测量通道。一个设备可以挂多个数据点比如一个环境监测器同时上报温度、湿度、PM2.5三个数据点每个数据点有自己的数据类型float/int/bool/string、单位、取值范围和模拟方式。上报策略解决的是“什么时候发、发多少”的问题。你可以按固定间隔上报也可以配置随机抖动来模拟真实网络的不稳定还可以通过脚本触发一次性的数据注入。2.0 版本在策略上做得比较灵活这一点后面实操环节会详细演示。2.2 为什么用 JSON 做配置灵活性与可读性的平衡SensorSimulator2.0 选择了 JSON 作为设备模型的描述格式这个选型我估计是参考了 Home Assistant 和 Node-RED 这类开源项目的做法。JSON 的好处不需要多讲嵌套结构天然适配“节点—数据点”这种层级关系而它更实际的好处是配置可以直接挂在版本仓库里做 diff每次改动都留痕多人协作时不会因为配置漂移吵起来。我自己实际体验下来JSON 配置相比传统 ini/csv 的好处主要有三点一是支持动态扩展新增一个数据点字段不需要改动解析框架二是生态好VS Code 装个 JSON Schema 插件就能自动补全校验三是写脚本生成配置非常方便用 Python 的 json 库十来行代码就能批量产出几十个虚拟传感器。当然 JSON 也有缺点比如不支持注释。我的解决办法是统一用_note字段存说明信息或者在外层套一层辅助配置文件这块习惯看个人。2.3 2.0 版本相比 1.0 的几点关键变化用过 1.0 版本的朋友应该记得老版本最大的痛点是模拟方式单一只能生成固定值或者简单正弦波数据之间的关联性没法模拟。举个例子真实环境下温度升高时湿度通常会下降这个联动关系 1.0 就表达不了。2.0 重点改进了三件事。第一引入了“数据表达式”机制数据点之间可以引用其他数据点的当前值参与计算比如湿度数据点可以写成60 - (temperature - 25) * 0.8 noise()这样模拟出来的数据就有物理逻辑了。第二内置了多协议输出通道除了传统的 MQTT还能直接输出到 HTTP Webhook、TCP Socket 和本地 CSV 文件方便对接不同场景。第三增加了“回放模式”可以把历史采集的真实数据文件灌进去重新上报这个对复现线上问题太有用了。3. 核心配置与实操指南3.1 快速启动安装与环境准备SensorSimulator2.0 是基于 Java 11 开发的官方提供了三个发行包Windows 的 exe、macOS/Linux 的 tar.gz还有一个 Docker 镜像。我日常在 Linux 服务器上用得多最省事的方式是直接跑 Dockerdocker run -d --name sensor-sim \ -v /opt/sensor-sim/config:/app/config \ -v /opt/sensor-sim/output:/app/output \ -p 1883:1883 \ sensorsimulator/sensor-sim:2.0.0如果你不想用 Docker在本地跑 jar 包也就两条命令java -jar SensorSimulator2.0.jar --init-config java -jar SensorSimulator2.0.jar --config ./config/device_config.json第一条命令会在当前目录生成一份默认配置文件里面包含了所有支持的数据类型示例强烈建议先跑一遍这条命令把它当作官方文档的活样例来研究。3.2 配置文件核心字段逐项说明打开生成的默认配置核心结构一般是这样的{ nodes: [ { id: env-sensor-001, name: 会议室环境传感器, group: meeting-room, protocol: mqtt, mqtt: { broker: 192.168.1.100:1883, topic: iot/data/env-sensor-001, qos: 1, username: simulator, password: 123456 }, reportInterval: 10, jitter: 2, dataPoints: [ { key: temperature, type: float, unit: ℃, mode: expression, expression: 25 5 * sin(t / 300) noise(0.3) }, { key: humidity, type: float, unit: %RH, mode: expression, expression: 55 - (temperature - 25) * 0.6 noise(0.5) } ] } ] }逐字段看几个重点。reportInterval和jitter决定了上报节奏。reportInterval是基础间隔单位秒jitter是随机抖动窗口比如基础间隔 10 秒加抖动 2 秒实际间隔会在 8 到 12 秒之间随机浮动。为什么要加抖动真实设备的上报间隔不可能完全均匀网络延迟、设备时钟漂移都会造成微小偏差如果下游做时序异常检测均匀的数据反而会让模型产生误判。mode字段支持三种取值fixed固定值、random范围随机、expression表达式。固定值适合测试静态场景随机值适合边界测试表达式适合需要伪真实联动关系的场景也就是刚才说的 2.0 核心能力。expression里可用的变量和函数需要单独说。变量包括系统内置的t自启动以来的秒数、timestamp当前毫秒时间戳以及同一节点下其他数据点的key注意引用其他数据点时直接写 key 名即可。常用函数有sin/cos周期波动、noise(amplitude)高斯噪声、random(min, max)区间随机、clamp(val, min, max)限幅、step(val, threshold)阶跃输出。3.3 数据表达式让模拟数据活起来表达式引擎是整个 2.0 最值得花时间研究的部分。它给你提供了一种从造数据升级到造规律的能力。举个例子你想模拟一个冷库的温度曲线真实场景应该是压缩机启动时温度缓慢下降到达设定值后停机温度再缓慢回升。用固定值做不到用普通正弦波也不像。但通过表达式可以组合出一个近似的循环{ key: coldroom_temp, type: float, unit: ℃, expression: 4 2 * sign(sin(t / 1800)) - 0.8 * sin(t / 1800) noise(0.1) }这个表达式拆开来看sin(t / 1800)的周期是 1800 秒半小时sign函数把它变成了方波方波让温度在 2℃ 和 6℃ 两个区间切换后面减去的正弦波给切换过程增加了一点倾斜度noise(0.1)模拟传感器本身的微小噪声。最终效果就是高低交替、带过渡趋势的冷库温度曲线。另外提醒一个关键的坑表达式里如果引用了其他数据点被引用的数据点必须在配置里排在前面否则启动时会报undefined variable错误。这属于初始化顺序问题2.0 文档里写得不明显我第一次用的时候踩了个正着。4. 例子完整模拟一个温湿度传感器上报的 MQTT 流程4.1 场景说明与前置条件这一节我用一个完整的例子走一遍全流程。场景是模拟一个农业大棚里的温湿度传感器每 10 秒上报一次数据到本地 MQTT Broker温度在 20~35℃ 之间波动湿度与温度负相关同时每 5 分钟出现一次短时波动模拟通风设备启停。为了验证效果我提前用 EMQX 作为 MQTT Broker用 MQTT X 客户端订阅同一个主题来观察数据。如果你本地没有 Broker也可以用 SensorSimulator2.0 内置的--embedded-broker参数启动一个临时 Broker适合快速验证。4.2 编写设备配置文件先创建目录和配置文件mkdir -p /opt/sensor-sim/config cd /opt/sensor-sim/config创建一个greenhouse_sensor.json文件内容如下{ nodes: [ { id: gh-sensor-001, name: 1号大棚环境传感器, group: greenhouse, protocol: mqtt, mqtt: { broker: 192.168.1.200:1883, topic: iot/device/gh-sensor-001/data, qos: 0 }, reportInterval: 10, jitter: 1.5, dataPoints: [ { key: temperature, type: float, unit: ℃, mode: expression, expression: 27 5 * sin(t / 600) noise(0.4) }, { key: humidity, type: float, unit: %RH, mode: expression, expression: clamp(68 - (temperature - 27) * 1.2 3 * square(0.002 * t), 40, 90) noise(0.6) }, { key: battery, type: int, unit: %, mode: expression, expression: round(clamp(88 - t / 86400 * 3, 20, 100)) } ] } ] }这个配置里我同时放了三个数据点除了温湿度还模拟了电池电量缓慢下降的过程这样数据看板上的设备状态也能跟着动起来。需要注意湿度表达式里的square(0.002 * t)是一个周期函数0.002 * t会让周期大约为 3140 秒每隔一段时间会增强湿度波动模拟通风设备启停的效果。clamp把湿度限制在 40 到 90 之间避免出现超过物理极限的假数据。4.3 启动模拟器并验证数据配置文件准备好之后启动模拟器java -jar SensorSimulator2.0.jar --config ./config/greenhouse_sensor.json --verbose--verbose参数会打印每条上报记录的摘要类似这样[2025-01-10 14:03:22.118] gh-sensor-001 - temperature28.42, humidity63.75, battery84 [2025-01-10 14:03:32.440] gh-sensor-001 - temperature28.90, humidity62.10, battery84 [2025-01-10 14:03:42.017] gh-sensor-001 - temperature29.31, humidity60.88, battery84同时打开 MQTT X 订阅iot/device/gh-sensor-001/data能够看到 payload 的完整结构{ deviceId: gh-sensor-001, timestamp: 1736582602118, group: greenhouse, data: { temperature: 28.42, humidity: 63.75, battery: 84 } }payload 里自动带上了设备 ID、分组、毫秒时间戳和具体数据点字段这个结构基本可以直接对接常见的 IoT 平台数据解析规则。4.4 回放模式用历史数据复现线上问题刚才提到过 2.0 新增的回放模式这里补一个实际用法。假设你之前导出了一段真实设备的数据 CSV字段是timestamp,temperature,humidity回放配置可以这样写{ replay: { file: ./history/greenhouse_history.csv, timeColumn: timestamp, timestampUnit: ms, speed: 10 } }speed是回放倍速10 表示以 10 倍速快速重放需要慢速观察就设成 1。回放模式常用于两类场景一是线上数据异常时用原始数据反复复现验证修复是否生效二是给算法模型喂历史数据做测试。相比脚本回放工具它省了写解析逻辑的功夫而且数据点映射直接在配置里声明改起来更快。5. 常见问题与排查技巧实录5.1 典型问题速查表这几个月用下来我把碰到的典型问题和排查思路整理成了表格供大家参考问题现象可能原因排查与解决办法启动时报 JSON 解析错误配置文件多了注释或尾逗号检查配置是否为纯 JSON移除注释用jq .做语法校验MQTT 数据收不到Broker 地址或 Topic 配置错误先用--verbose看本地是否打印记录再用 MQTT X 手动订阅确认话题表达式里引用数据点报 undefined被引用字段定义顺序靠后调整 dataPoints 顺序被引用的字段放前面数据上报频率忽快忽慢jitter 配置过大确认jitter值不超过reportInterval的 30%否则抖动太明显温度值长期不变表达式里只用了fixed或random改用expression模式引入t变量制造变化高并发模拟时 CPU 占用过高节点数量太多且间隔太短降低reportInterval或拆分数个模拟器进程分到不同端口上报模拟的电池电量出现负数表达式计算越界对百分比类数据统一加clamp限幅5.2 两个容易忽略的配置细节第一个细节是 MQTT QoS 的选择。模拟器默认 QoS 是 0最多一次这在本地联调没问题但如果你要通过公网 Broker 上报或者链路本身不稳定建议改成 1至少一次否则丢包后你在后端看不到任何提示容易误判是模拟器没工作。修改方式就是配置里qos字段改成 1。第二个细节是时间戳精度。模拟器默认生成毫秒时间戳但如果你接的下游系统是按秒解析的比如某些老版时序数据库需要在配置里加一个顶层字段timestampUnit: s。这个字段容易漏我第一次对接 TDengine 时就因为这个所有数据的时间被解析成了 1970 年附近的值排查了半天。5.3 性能参考能模拟多少设备有人可能会关心模拟器的容量上限。我实测过的场景是一台 4 核 8G 的云主机跑 500 个节点、每个节点 3 个数据点、上报间隔 10 秒CPU 占用稳定在 35% 左右内存占用约 1.2G没有出现消息积压。如果超过 500 节点建议按节点分组拆多个进程分别跑或者改用 Docker Compose 起多套容器效果更好。模拟器的输出瓶颈基本在 MQTT Broker 的吞吐上限而不是模拟器本身所以做大规模压测时Broker 选型更重要。5.4 数据校验的实用技巧我每次启动新的模拟配置之前都会用--dry-run参数先跑一遍。这个参数会解析配置、生成前 10 条数据并打印在控制台但不会真正发到 Broker用来验证表达式结果是否合理。比如看湿度是否始终卡在 clamp 的边界、温度是否出现 NaN这些一眼就能发现问题。另外如果你配了多个数据点建议在正式跑之前先用一个 Python 脚本把表达式生成的数据画成曲线图直观检查规律是否和预期一致。下面的脚本可以配合--export-sample 100参数使用它会导出前 100 条模拟数据到 CSVimport pandas as pd import matplotlib.pyplot as plt df pd.read_csv(sample_output.csv) plt.figure(figsize(12, 4)) plt.plot(df[timestamp], df[temperature], labeltemperature) plt.plot(df[timestamp], df[humidity], labelhumidity) plt.legend() plt.tight_layout() plt.savefig(preview.png)曲线图比看数字直观太多如果发现湿度曲线没有和温度成反向联动十有八九是表达式里的引用或者符号写错了。6. 在真实项目中的一点使用心得截至到这里SensorSimulator2.0 的安装、配置、例子和排坑都已经过了一遍。最后说点我在实际项目中总结的体会。这个工具最顺手的地方不在于它能帮你省掉写几行代码而在于它让数据行为变得可编程、可复现。以前做演示环境临时改一个数据范围要改代码重新编译现在改一行 JSON 重启进程就完事。以前复现现场问题只能求着运维捞日志现在把日志转成 CSV 丢进回放模式第二天就能在本地把问题重演。这种从碰运气到确定性的转变是工具版本迭代给我最直观的感受。如果你准备在自己的项目里引入 SensorSimulator2.0我的建议是先别急着模仿复杂的表达式从最简单的固定值节点跑通全链路再逐步加入随机、噪声和关联表达式最后再尝试回放模式。工具本身不复杂复杂的是你的数据场景先把基础流程走顺了后面再加功能会顺手得多。本文还有配套的精品资源点击获取