资讯动态

从传感器到手机屏幕:Android温湿度监控BLE数据链路全解析

发布时间:2026/10/20 8:10:26 来源:尧图企业网站定制
简介温湿度监控手机APP开发代码是一套面向物联网与Android开发者的完整工程示例适合学习环境温湿度采集、服务端数据接口交互、实时显示与远程控制的全流程实现可迁移到智能家居、仓储或实验室等场景。资源将传感器数据读取、网络通信、UI展示和简单开关控制逻辑整合为一个可直接研究的项目压缩包共143个文件、约3.98MB主要包含png界面与图标资源、class编译文件、xml布局与配置、jar依赖库以及少量java源码另附一个可安装到手机的APK便于直接观察运行效果。目前已有1617人学习下载。借助整份工程包读者可梳理Android项目结构与资源组织方式理解主线程、输入线程和LED控制操作之间的协作关系把握从硬件数据接入到手机端可视化的实现思路是一份贴近真实开发流程的实用参考。1. 温湿度监控手机APP这条数据链路怎么从零串起来做温湿度监控手机APP卡住大多数人的不是界面而是从传感器到手机屏幕这条完整链路传感器怎么选、协议帧怎么解析、蓝牙连上之后数据如何校验、App退到后台还怎么持续记录。这份温湿度监控_手机APP开发代码我完整跟了一遍它把采集、传输、存储、曲线、告警串成了一条可跑的闭环不是那种只有界面的空壳Demo。适合三类人拿它做课程设计或毕设的学生、要给仓库或机房做环境监控的独立开发者、以及想把成品蓝牙温湿度计数据接进自己App的嵌入式转移动端工程师。下面按拆项目的顺序讲先定选型再看实现最后说坑、校准和优化。其中不少是我实际部署时踩过的雷写出来给你省点时间。2. 选型与架构传感器、传输协议、手机端框架怎么搭2.1 传感器端DHT11、DHT22、SHT30 到底差在哪环境监控项目里传感器选型直接决定后面代码的复杂度。DHT11 便宜但温度精度只有 ±2℃湿度 ±5%RH单总线协议时序敏感读数据经常失败做演示可以做正经监控不够。DHT22 精度好一些温度 ±0.5℃湿度 ±2~5%RH但响应慢不适合快速轮询。SHT30 走 I2C温度 ±0.3℃湿度 ±2%RH自带 CRC 校验字节是监控项目里性价比比较稳的选择。这份代码包在采集层做了抽象DHT11/DHT22 走单总线读取SHT30 走 I2C 读取对上统一暴露温湿度结构体。换传感器只改初始化处上层逻辑不用动。写代码前先定采样频率仓库环境监控 30 秒一次足够机房建议 10 秒冷链运输才需要秒级。频率设太高电池供电的 BLE 设备撑不住频率太低曲线看不了细节。这个参数建议做成可配置代码包里确实也是这样做的第 3 章会说到具体位置。2.2 传输链路BLE、WiFi 直连、局域网 HTTP 怎么取舍手机端和设备端的连接方式基本就三种我分别说边界条件BLE 低功耗蓝牙适合电池供电的温湿度计手机直接连不依赖路由器代码走 BluetoothLeScanner 扫描、BluetoothGatt 连接加 notify 回调拿数据。缺点吞吐低、有效距离 10 米左右隔一堵墙就掉线。WiFi 直连设备连路由器手机通过局域网 IP 拉 HTTP 接口。适合插座供电的集中式采集器一个设备挂多个传感器。调试简单但设备 IP 变化后要处理重连逻辑。WiFi MQTT设备推消息到 broker手机订阅主题好处是设备离线也能在服务端看到最后在线时间。但你要自己维护 broker监控规模不到十台设备这笔运维成本不划算。选型建议单点监控、电池供电、手机拿起来就能看选 BLE固定点位、同时要看多个传感器选 WiFi 本地 HTTP设备超过十台并且分散在不同房间再上 MQTT。别一上来就上 MQTT监控 5 台以内设备时它带来的运维成本比收益大。2.3 手机端框架原生 Android、Flutter 还是小程序代码包主工程是 Android 原生Kotlin 写的BLE 部分走官方 BluetoothLeScanner 和 BluetoothGatt。用原生的优势是 API 最全后台扫描、连接参数、MTU 协商这些底层能力都露在外面出问题好排查。想一套代码两端跑Flutter 的 flutter_blue_plus 也能做但 BLE 的后台保活、权限弹窗逻辑 iOS 和 Android 差异很大跨平台框架在这块经常要写平台通道绕回去反而比原生费事。微信小程序更不适合做连续监控小程序退到后台会被系统挂起蓝牙连接直接断开只能做「打开看一眼当前值」的轻量场景。另外提醒一点不管你选哪个框架BLE 权限申请都要重视。Android 12 以上扫描蓝牙需要 BLUETOOTH_SCAN 权限Android 11 及以下要定位权限这两套逻辑代码包都处理了但从零写的时候特别容易漏掉 BLUETOOTH_SCAN导致扫描接口返回空列表看起来像没扫到设备。所以结论很直接要做正经的连续监控 AppAndroid 原生起步最顺。这份代码包把原生 BLE 的主流程都写了——权限申请、扫描过滤、连接重试、notify 订阅拿过来改包名和设备广播名就能跑。3. 代码落地采集、存储、曲线、告警四个模块逐个拆3.1 设备端数据读取与广播帧解析先看设备端。以常见的 BLE 温湿度计为例它要么在广播包里直接带温湿度数据要么连接后某个 characteristic 周期性 notify。广播帧解析代码大致长这样// BLE 广播帧温湿度解析长度 类型 厂商自定义数据 fun parseTempHumi(scanRecord: ScanRecord?): PairDouble, Double? { val mfg scanRecord?.getManufacturerSpecificData(0xFFFF) ?: return null if (mfg.size 4) return null // 前 2 字节温度有符号定点数实际值 原始值 / 100 val rawTemp ((mfg[0].toInt() and 0xFF) shl 8) or (mfg[1].toInt() and 0xFF) val temp rawTemp / 100.0 // 后 2 字节湿度无符号定点数实际值 原始值 / 100 val rawHumi ((mfg[2].toInt() and 0xFF) shl 8) or (mfg[3].toInt() and 0xFF) val humi rawHumi / 100.0 return temp to humi }逻辑说明先取厂商自定义数据段长度不足 4 字节直接返回 null避免后面移位拼接时数组越界。温度按有符号数处理因为冷库场景温度可能是负数如果设备端用的是无符号数得额外处理符号位。参数说明0xFFFF 里的厂商 ID 是示例值必须替换成你设备的真实厂商 ID这是拿到代码后第一处要改的地方拼接顺序是高位在前大端部分国产芯片是小端顺序反了读数会完全不对。这段代码在 ScanCallback 的 onScanResult 里对每台目标设备调用解析成功后再决定要不要发起连接。如果是 SHT30 这类走 I2C 的传感器读取流程是发命令、等转换完成、读 6 字节温度 2 字节 CRC 1 字节 湿度 2 字节 CRC 1 字节CRC 校验失败就丢弃这一帧。代码包里两套读取逻辑独立成函数初始化时用配置切换上层代码不用动。3.2 手机端接收、校验与本地存储数据到了手机端第一件事不是画图是校验和落库。BLE notify 回调里拿到的字节数组先做长度和范围检查温度不在 -40~85℃、湿度不在 0~100%RH 的直接丢弃。这类脏数据多半是传输丢包或传感器上电初始化未完成产生的。// BLE notify 回调 SQLite 落库 override fun onCharacteristicChanged( gatt: BluetoothGatt, characteristic: BluetoothGattCharacteristic ) { val value characteristic.value if (value.size 4) return val temp bytesToTemp(value) // 与设备端对应的解析函数 val humi bytesToHumi(value) // 范围校验挡掉脏数据 if (temp !in -40.0..85.0 || humi !in 0.0..100.0) return val now System.currentTimeMillis() val record EnvRecord(id now, temp temp, humi humi) db.insertRecord(record) viewModel.onNewRecord(record) // 通知界面刷新和告警检查 }逻辑说明数据库表按时间戳主键插入前靠主键去重。BLE notify 有时会重复推送同一帧不去重的话曲线图上出现重复点统计最大值最小值时会重复计数。参数说明范围校验的上限 85℃ 和下限 -40℃ 是普通消费级传感器的工作极限例子里是通用值实际以你传感器手册为准。存储用的 SQLite 表结构就四列id、timestamp、temp、humi监控场景一天 2880 条记录30 秒采样完全没有压力不需要引入数据库框架。注意这里的时间戳默认用手机时间单手机场景调试方便如果多台设备汇总做分析建议换成设备 RTC 时间并统一到 UTC否则时间轴对不齐。3.3 曲线绘制与阈值告警曲线用的是自定义 View不是重型图表库因为整个 App 只有一条切换温度/湿度的曲线自己画省掉图表库几十 MB 依赖绘制性能也好控制。核心是维护一个固定长度的滑动窗口// 滑动窗口曲线绘制窗口 6 小时30 秒一点共 720 点 override fun onDraw(canvas: Canvas) { val windowSize 720 val data memoryCache.queryLast(windowSize) // 内存缓存不直接查库 if (data.isEmpty()) return var lastX 0f var lastY 0f for ((index, record) in data.withIndex()) { val x index / (windowSize - 1f) * width val y mapTempToY(record.temp) if (index 0) canvas.drawLine(lastX, lastY, x, y, linePaint) lastX x lastY y } }逻辑说明onDraw 里不查数据库查询结果缓存在内存里只有新数据到达或窗口变化时才重新查。否则每次 invalidate 都查库帧率会掉到 20 帧以下。参数说明windowSize 是窗口内点数和采样周期强相关。30 秒采样、6 小时窗口就是 720 点改成 10 秒采样还想看 6 小时窗口就是 2160 点drawLine 次数多了要注意性能第 6 章会提到优化方法。告警逻辑放在新记录写入之后和配置里的上下限比较超限就触发本地通知。这里有个关键细节——防抖。仓库门打开关门温湿度可能瞬间越过阈值又回来不做防抖一晚上推几十条通知。代码里做的是连续 3 条记录超限才告警约 90 秒这个参数按场景调机房收紧到 2 条粮仓放宽到 5 条。告警触发后还要做恢复通知否则用户不知道环境已经恢复正常。3.4 参数配置采样周期、阈值、重试策略集中管理把需要调的参数集中列出来下面是代码包里配置对象的关键项参数默认值说明采样周期30 秒设备端上报频率影响功耗和曲线粒度温度高阈值30℃超限触发告警温度低阈值10℃超限触发告警湿度高阈值70%RH超限触发告警湿度低阈值30%RH超限触发告警防抖窗口3 条连续 N 条超限才告警重连间隔30 秒BLE 断线后重试间隔可配退避历史保留天数30 天SQLite 定期清理窗口参数都收敛在配置类里业务代码里不要散落魔法数字。我拆过不少代码包典型毛病是阈值散落在告警函数里改一次找三个地方这份代码在这点上收敛得不错。4. 温湿度监控APP避坑指南五条高频翻车记录4.1 现象蓝牙连上几秒就断开重连又要十几秒原因分析这是消费级 BLE 温湿度计的高频问题。一个是设备端连接参数太激进连接间隔设得太短手机协议栈处理不过来会主动断开另一个是不同手机厂商的蓝牙协议栈实现有差异同一台设备在一款手机上稳定在另一款上频繁断。解决先查 MTU。默认 MTU 是 23 字节完整温湿度帧发不完系统会分包分包后 notify 频率高、容易丢包。我把 MTU 协商到 185数据一帧发完断连概率明显下降。再不行就把设备端连接间隔调到 30~50ms 区间牺牲一点响应换稳定性。最后检查扫描过滤条件按设备名前缀过滤比按 MAC 地址过滤可靠因为有些设备 MAC 会随机化按 MAC 过滤越用越失效。4.2 现象曲线像心电图数据突然跳高又跳回原因分析八成不是传感器坏了是数据还没稳定就采了一笔。温湿度传感器在开机、唤醒或从省电模式恢复时头几百毫秒到几秒的数据是无效的芯片手册叫「唤醒稳定时间」。采集函数在初始化后立刻读数据就会采到这笔。解决在采集流程里加稳定等待——丢弃设备返回的头两条数据或读取前 sleep 传感器指定的最小稳定时间。DHT22 要 2 秒左右SHT30 约 10 毫秒。这个参数必须看芯片手册不能拍脑袋。另一个隐蔽原因是电源纹波电池快没电时读数波动剧烈加个稳压电容就好了。先加软件滤波再怀疑硬件排查顺序别反。4.3 现象App 退后台几分钟再打开发现中间一段曲线是空的原因分析Android 省电策略把后台进程冻结了。Android 6 以上的 Doze 模式、厂商的省电管家都会在熄屏后限制 App 的 CPU 和网络访问BLE notify 回调收不到数据自然断档。解决三条路。第一前台服务加常驻通知最稳的做法状态栏能看到「环境监控运行中」系统不容易杀第二申请电池优化白名单部分机型需要用户去设置页手动授权第三降低采集频率系统对低频任务容忍度更高。代码包里前台服务部分写得很完整我就是照它改的。注意 Android 13 以上通知权限要运行时申请没授权前台服务通知不显示用户感知不到 App 还在工作可能手动杀掉进程。4.4 现象App 用了三个月打开慢数据库好几百 MB原因分析SQLite 只插不删历史表无限膨胀查询和绘制要扫全表当然慢。这是设计缺陷不是玄学。解决代码包自带的清理策略是保留 30 天但清理任务必须放在应用启动或前台服务启动时执行不能依赖系统闹钟——手机重启后闹钟任务会丢。另一个细节删除要按时间分批一次删掉 90 天数据在低端机上可能卡几十毫秒分 10 批删更平滑每批之间稍微 sleep 一下。顺带给时间戳列建索引CREATE INDEX idx_time ON envs(timestamp)数据量上去后查询从秒级回到毫秒级。SQLite 开 WAL 模式读写并发不互相阻塞曲线绘制时数据库插入也不会卡。4.5 现象冷链车读数正常到了 -18℃ 环境湿度读数乱跳原因分析低温对电容式湿度传感器影响很大。很多传感器工作范围只到 -20℃ 左右低于此温度芯片本身不保证精度而且低温下水汽凝结甚至结霜探头被冰晶覆盖读数当然离谱。解决这类场景别指望手机 App 校准救回来这是物理限制。正确做法是选宽温型传感器带加热探头的型号安装位置避开冷风直吹。代码层面能做的加数据合理性过滤温度低于 -30℃ 时暂停记录湿度并打标记给用户提示而不是一堆乱跳的数字。冷链监控建议温度和湿度分开两个传感器湿度只做参考不做告警依据。5. 精度校准与数据可信度把读数变成决策依据5.1 精度等级先搞清楚传感器能干什么监控 App 做得再漂亮读数是假的就没意义。数据可信度是一条链传感器精度 → 安装位置 → 软件校准 → 数据滤波 → 多设备一致性任何一环断了App 上的数字都只是参考。传感器出厂精度决定系统天花板DHT11 只能判断「热不热」不能指导药品存储SHT30 适合一般环境监控制药或样本存储才需要更高等级。常用传感器对照如下传感器温度精度湿度精度接口适用场景DHT11±2℃±5%RH单总线教学演示、开关型监控DHT22±0.5℃±2~5%RH单总线一般环境监控SHT30±0.3℃±2%RHI2C仓库、机房、小型冷链SHT40±0.2℃±1%RHI2C制药、样本存储选型唯一原则让传感器精度比你的业务要求高一档以上。业务要求 ±1℃传感器至少选 ±0.5℃ 级别否则校准和补偿空间不够。5.2 软件校准偏移补偿与温漂修正软件校准解决的是系统误差。同一批传感器每颗读数和标准值之间有固定偏移和标准温湿度计对比测出来即可。代码包里预留了校准接口每台设备可做两点校准// 两点线性校准低点 15℃高点 35℃ class Calibration { private val lowRef 15.0 // 低点标准值 private val lowRead 15.8 // 低点本机读数 private val highRef 35.0 // 高点标准值 private val highRead 34.2 // 高点本机读数 fun compensate(raw: Double): Double { val slope (highRef - lowRef) / (highRead - lowRead) return lowRef (raw - lowRead) * slope } }逻辑说明不是简单加固定偏移而是用两点做线性插值把传感器的斜率误差增益偏差一起校掉。参数说明低点和高点要覆盖实际监控范围。恒温恒湿实验室主要工作区 18~28℃就在这个区间选两个校准点而不是随便拿室内温度填。监控范围横跨 -20℃ 到 50℃ 这种大区间线性校准不够要改成查表法或多项式拟合Calibration 类留了扩展点直接替换 compensate 方法体即可。5.3 数据平滑与异常值剔除采集到的原始数据要不要平滑取决于用途。趋势展示轻度平滑更直观临界值决策千万别平滑报警响应会变慢。代码包里滤波是可选开关默认关闭我建议日常展示时打开// 滑动中值滤波窗口 5 fun medianFilter(values: ListDouble): Double { if (values.size 3) return values.last() val sorted values.sorted() return sorted[sorted.size / 2] }对比均值滤波中值滤波抗单点突变均值会被一个异常大数带偏中值不会。窗口 5 意味着攒满 5 个点才输出一个输出频率降为原来的五分之一——30 秒采样下 150 秒才更新一个点展示端要有心理预期。提示中值滤波窗口决定了输出延迟窗口越大曲线越平但越滞后展示用 5 就够了。我的习惯是原始数据永远落库展示层才做滤波回头做数据分析手里还是干净的原始数据。5.4 多设备一致性同一房间两台设备读数差 1℃这是用户投诉最多的问题。同一间仓库装了四台设备手机上四台读数各不相同最大差 1.5℃用户问哪台是准的。原因有两层。第一层是传感器个体差异同一型号同一批次也可能偏差 0.5℃ 以上属于硬件容差。第二层是安装位置差异贴墙安装和悬挂在中央测到的本来就不是同一个「环境温度」墙面热传导会让贴墙那台在夏天明显偏高。解决每台设备建立自己的校准偏移。部署时拿一台标准温湿度计和每台设备并排摆放 30 分钟等热平衡后记录差值填进设备校准参数。另外可以用同时序对比来发现站差问题把四台设备同一小时的曲线叠在一起画离群的那台就是安装位置或校准有问题的。代码包的多设备曲线叠加视图就是干这个的部署验收时一定要跑一遍。这个步骤不能省尤其是有精度审查要求的场景。6. 进阶优化从「能跑」到「省电、流畅、不丢数据」6.1 曲线渲染减少无效刷新监控 App 的曲线如果固定每秒刷新大部分刷新其实没有新数据纯浪费 CPU。我把刷新逻辑改成只有收到新数据点才触发 invalidate界面拖动缩放单独处理没变化就不重绘// 新数据到达才重绘曲线 fun onNewRecord(record: EnvRecord) { memoryCache.append(record) curveView.invalidate() }逻辑说明invalidate 会触发下一次 onDraw比 launchActivity 之类轻量但也不能乱调。1000 点以上记得抽稀可见区域外的点不画遍历还是要遍历但只画屏幕内的线段低端机上差距很明显。6.2 省电与后台保活Android 12 之后后台对 BLE 约束进一步收紧。前台服务启动时机要提早到「用户打开监控开关」那一刻等退后台再补启要处理更复杂的权限路径。前台服务类型声明为 dataSync清单文件要成对声明Android 14 上漏了类型直接抛异常。设备端不要高频上报按采样周期推即可BLE 连接建立后系统会自动协商省电参数你手动调低频率反而可能触发系统异常断开。6.3 历史数据导出与断点补传导出功能把 SQLite 历史数据转 CSV走系统分享面板发出去Excel 直接打开做月度报表很方便。断线补传设备端保留最近 24 小时记录App 重连后从断点时间戳补拉。关键点是设备记录时间做主键去重否则补传和实时记录重复入账。补传期间 UI 要显示进度用户才明白这是在补数据而不是卡住了。说回我自己的教训最早给某仓库做温湿度监控上线三个月没出过问题第四个月夜间断电仓库设备全离线App 里留下一个大空档用户问数据去哪了。从那以后我每次做这类项目都强制走「断电恢复 数据补传 告警失灵」三个场景演练确认设备重启能自动重连、历史记录能补传才敢交付。这份代码包拿到手也建议你先花半天跑这三个场景再改业务逻辑。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑