资讯动态

Android Things 智能家居中枢实战:从树莓派到全屋智能

发布时间:2026/10/4 13:56:20 来源:尧图企业网站定制
1. 从一块开发板到全屋智能我为什么选择 Android Things 做智能家居中枢2017 年夏天我拿到第一块 Raspberry Pi 3 的时候脑子里想的全是这玩意儿能不能当家里的控制中心。当时市面上主流的方案无非是树莓派跑 Home Assistant、ESP8266 接继电器、或者直接买小米/涂鸦的成品套装。成品套装省事但扩展性差想加个自定义传感器就得看厂商脸色ESP8266 方案便宜但每个节点都要单独写固件设备一多维护成本直线上升。后来接触到 Android Things我才算找到了一个相对平衡的切入点——它既有 Android 成熟的开发工具链和 UI 框架又能直接操作 GPIO、I2C、SPI 这些硬件接口最关键的是我可以用写 App 的思路去写硬件逻辑这对一个 Android 开发者来说几乎是零门槛。Android Things 是 Google 在 2015 年当时叫 Brillo推出、2016 年正式更名的物联网操作系统本质上是裁剪过的 Android 系统专门跑在 Raspberry Pi 3、NXP i.MX7D、Intel Edison 这类开发板上。它的核心价值在于把 Android 的 Framework 层保留下来同时提供一套 Peripheral I/O API让开发者用 Java/Kotlin 就能控制 GPIO 引脚、读写 I2C 传感器、驱动 PWM 设备。换句话说你不需要懂 Linux 驱动开发也不需要写 C 语言固件只要会写 Android App就能做出一个能跑起来的智能家居网关。这篇文章适合谁看如果你是有 Android 开发基础、想折腾智能家居但不想从零学嵌入式的人那这篇内容基本就是为你写的。如果你完全没接触过 Android 开发也没关系我会把关键概念用生活化的方式讲清楚你至少能理解整套系统的运作逻辑。整篇内容我会围绕一个实际项目展开用 Raspberry Pi 3 Android Things 做一个智能家居中枢接入温湿度传感器、继电器控制灯光、通过手机 App 远程查看和控制。所有代码和配置我都会给出可直接参考的版本踩过的坑也会一并说明。2. 整体方案设计与技术选型思路2.1 为什么不用 Home Assistant 或 ESP8266 方案在动手之前我先花了两周时间对比了三种主流方案最后才确定用 Android Things。这个对比过程很有必要因为选型决定了后面所有的开发路径。Home Assistant 方案的优势是生态成熟插件多几乎支持市面上所有主流品牌的设备。但它的短板也很明显配置全靠 YAML 文件逻辑稍微复杂一点就要写 Python 脚本而且 UI 定制能力有限。我之前用 Home Assistant 接了一个自定义的土壤湿度传感器光是调试 MQTT 通信就花了一个周末最后发现是 YAML 缩进问题。对于想深度定制交互逻辑的人来说Home Assistant 更像是一个配置平台而不是开发平台。ESP8266/ESP32 方案的优势是成本低、功耗小一个节点十几块钱就能搞定。但问题在于每个节点都是独立的固件你要么用 Arduino IDE 写 C要么用 MicroPython。设备少的时候还好一旦超过 5 个节点固件版本管理、OTA 升级、设备间通信都会变成噩梦。我之前做过一个 8 节点的 ESP8266 方案光是统一固件版本就折腾了三天。Android Things 的定位刚好在两者之间它比 Home Assistant 更灵活因为你可以完全自定义业务逻辑它比 ESP8266 方案更好维护因为所有设备可以共享一套 Android 代码库OTA 升级直接用 Android 的机制。当然它的成本比 ESP8266 高一块 Raspberry Pi 3 大概 200 多块但作为中枢只需要一块终端节点还是可以用便宜的 ESP8266 通过 MQTT 接入。2.2 系统架构中枢 终端 手机 App 三层结构最终确定的架构是三层中枢层Raspberry Pi 3 跑 Android Things负责设备管理、数据聚合、逻辑决策。它直接通过 GPIO/I2C 连接本地传感器和执行器同时通过 MQTT 或 HTTP 与远程终端节点通信。终端层ESP8266 节点负责分布式传感和执行比如卧室的温湿度采集、客厅的灯光控制。它们通过 Wi-Fi 与中枢通信协议用 MQTT因为 MQTT 轻量、支持发布订阅、断线重连机制成熟。应用层Android 手机 App 通过 HTTP/WebSocket 与中枢交互查看数据、下发控制指令。App 本身也是 Android 项目可以复用一部分代码逻辑。这个架构的核心思路是集中决策、分布执行。中枢负责所有逻辑判断终端只做数据采集和指令执行这样终端固件可以做得非常简单几乎不需要改动。比如温度高于 28 度自动开风扇这个逻辑放在中枢里用 Kotlin 写几行代码就行不需要在每个终端节点里重复实现。2.3 硬件选型与参数计算硬件清单如下设备型号数量用途参考价格开发板Raspberry Pi 3 Model B1中枢主机220 元温湿度传感器DHT111环境监测8 元继电器模块5V 单路继电器2灯光控制6 元/个电源5V 2.5A Micro USB1中枢供电25 元杜邦线母对母 20cm1 排接线5 元ESP8266 模块NodeMCU2终端节点15 元/个这里重点说一下电源的选择。Raspberry Pi 3 的峰值电流可以到 2.5A如果用手机充电器通常 1A 或 2A在 Wi-Fi 满负荷 GPIO 驱动继电器的时候会出现电压跌落导致系统重启。我一开始用了一个 5V 1A 的充电器结果每次继电器吸合的瞬间树莓派就重启排查了半天才定位到是供电不足。后来换成 5V 2.5A 的专用电源问题彻底消失。所以电源这块千万别省宁可买大一点。DHT11 的精度是温度 ±2°C、湿度 ±5%RH对于家居环境监测够用了。如果你需要更高精度可以换成 DHT22 或 SHT30但价格会贵一些而且 SHT30 是 I2C 接口接线方式不同。DHT11 用的是单总线协议Android Things 的 Peripheral I/O API 不直接支持这种协议需要自己用 GPIO 模拟时序这部分后面会详细讲。3. Android Things 核心开发细节与实操要点3.1 环境搭建从 Android Studio 到开发板烧录Android Things 的开发环境搭建和普通 Android 开发差不多但有几个关键区别。首先Android Studio 需要安装 Android Things SDK。在 SDK Manager 里勾选 Android Things 相关的包主要是com.google.android.things这个库。然后在build.gradle里添加依赖dependencies { implementation com.google.android.things:androidthings:1.0 }注意版本号1.0 是稳定版0.8 之前的 API 有较大变动网上很多老教程用的是 0.5 或 0.6代码直接拿过来会编译不过。其次开发板需要烧录 Android Things 镜像。以 Raspberry Pi 3 为例去 Android Things 官网下载对应版本的镜像文件.img格式然后用 Etcher 或dd命令写入 SD 卡。写入完成后把 SD 卡插入树莓派接上 HDMI 显示器和网线上电启动。第一次启动会比较慢大概 2-3 分钟屏幕上会显示一个 Android Things 的 Logo 和 IP 地址。这里有个坑Android Things 默认通过 ADB over Ethernet 连接但如果你没有网线想用 Wi-Fi 连接需要先通过串口或 HDMI 键盘进入系统设置。我当时的做法是先用网线连上通过adb connect IP连上去然后用adb shell执行 Wi-Fi 配置命令adb shell am startservice \ -n com.google.wifisetup/.WifiSetupService \ -a WifiSetupService.Connect \ -e ssid 你的WiFi名称 \ -e passphrase 你的WiFi密码配置成功后拔掉网线重启树莓派就会自动连上 Wi-Fi。之后每次连接只需要adb connect Wi-Fi IP就行。3.2 GPIO 控制用代码点亮一盏灯Android Things 的 GPIO 操作非常直观。核心类是PeripheralManagerService通过它获取Gpio对象然后设置方向输入或输出和初始状态。PeripheralManagerService manager new PeripheralManagerService(); Gpio ledPin manager.openGpio(BCM17); ledPin.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW); ledPin.setValue(true); // 点亮这里的BCM17是引脚名称对应 Raspberry Pi 的 GPIO17。不同开发板的引脚名称不一样Raspberry Pi 用的是 BCM 编号NXP i.MX7D 用的是另一套命名。你可以在 Android Things 的官方文档里查到对应开发板的引脚映射表。实际接线的时候GPIO 输出是 3.3V 逻辑电平而继电器模块通常是 5V 触发的。这里有两种处理方式一是用 3.3V 兼容的继电器模块市面上有专门为 3.3V 设计的二是加一个电平转换模块。我一开始用的是普通 5V 继电器直接接 GPIO 发现继电器不吸合用万用表一量GPIO 输出只有 3.3V达不到继电器的触发阈值。后来换了一个 3.3V 兼容的继电器模块问题解决。所以买继电器的时候一定要看清楚触发电压。另外GPIO 引脚在系统启动时的默认状态是不确定的可能会在初始化之前有一个短暂的高电平脉冲。如果你控制的是灯光这个脉冲会导致灯闪一下。解决办法是在硬件上加一个下拉电阻或者在软件里尽早初始化 GPIO。我在代码里是在onCreate里第一时间就打开 GPIO 并设置为低电平这样脉冲时间可以缩短到几毫秒肉眼基本看不出来。3.3 I2C 与单总线DHT11 的驱动实现DHT11 用的是单总线协议Android Things 没有现成的 API需要用 GPIO 手动模拟时序。这个协议的核心是主机拉低总线至少 18ms然后释放等待传感器响应。传感器会拉低 80us再拉高 80us然后开始传输 40 位数据8 位湿度整数 8 位湿度小数 8 位温度整数 8 位温度小数 8 位校验和。用 Java 实现的时候最大的难点是时序精度。Android Things 跑在 Linux 上Java 的Thread.sleep()精度只有毫秒级而 DHT11 的时序要求是微秒级。我试过直接用System.nanoTime()做忙等待但 Java 的 JIT 编译和 GC 会导致偶尔的延迟抖动读取成功率只有 60% 左右。后来我换了一个思路用 Android Things 的Gpio回调机制来捕获边沿变化而不是主动轮询。具体做法是设置setEdgeTriggerType(Gpio.EDGE_BOTH)然后注册GpioCallback在回调里记录时间戳。这样虽然不能完全消除抖动但成功率能提高到 85% 以上。对于家居环境监测来说这个成功率够用了因为你可以每秒读一次连续读 3 次取有效值。如果你对精度要求更高建议直接用 I2C 接口的传感器比如 SHT30 或 BME280。Android Things 对 I2C 的支持非常完善I2cDevice device manager.openI2cDevice(I2C1, 0x44); byte[] data new byte[6]; device.read(data, data.length); // 解析温湿度数据I2C 的读取是硬件级别的不受 Java 时序抖动影响稳定性远超单总线方案。我后来把 DHT11 换成了 SHT30读取成功率直接到 100%而且精度也更高。3.4 网络通信MQTT 与 HTTP 的取舍中枢与终端节点的通信我选了 MQTT。原因有三第一MQTT 是发布订阅模型终端节点只需要订阅自己关心的主题不需要知道其他节点的存在第二MQTT 有 QoS 等级可以保证消息至少送达一次第三MQTT 的 Keep Alive 机制可以自动检测断线配合遗嘱消息Last Will可以在节点离线时通知中枢。Android Things 上跑 MQTT 客户端我用的是 Eclipse Paho 库implementation org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.0连接代码MqttClient client new MqttClient(tcp://192.168.1.100:1883, android-things-hub, new MemoryPersistence()); MqttConnectOptions options new MqttConnectOptions(); options.setCleanSession(true); options.setKeepAliveInterval(30); options.setAutomaticReconnect(true); client.connect(options); client.subscribe(home/sensor/#, (topic, message) - { // 处理传感器数据 });这里有个细节setAutomaticReconnect(true)是必须的因为 Wi-Fi 不稳定的时候 MQTT 连接会断自动重连可以省去很多手动处理的代码。但自动重连有个问题重连后之前的订阅会丢失如果cleanSession为 true所以需要在MqttCallback的connectComplete方法里重新订阅。HTTP 主要用于手机 App 与中枢的交互。我在中枢上跑了一个轻量级的 HTTP 服务器用的是 NanoHTTPD大概 50KB 的 jar 包足够处理 REST 请求。手机 App 通过GET /api/sensors获取传感器数据通过POST /api/control下发控制指令。WebSocket 用于实时推送比如温度变化时主动通知 App 更新 UI。4. 完整实操流程从零搭建一个可运行的系统4.1 硬件接线与检查接线是整个过程里最容易出错的一步。我按照以下顺序操作第一步断开所有电源把 Raspberry Pi 3 放在桌面上确认 GPIO 引脚编号。树莓派的 GPIO 引脚有两套编号物理引脚号1-40和 BCM 编号。Android Things 用的是 BCM 编号所以接线的时候要看 BCM 映射图不能看物理引脚号。第二步连接 DHT11。DHT11 有三个引脚VCC、DATA、GND。VCC 接 3.3V物理引脚 1GND 接 GND物理引脚 6DATA 接 GPIO4物理引脚 7BCM 编号是 4。注意 DHT11 的 DATA 引脚需要接一个 4.7K 到 10K 的上拉电阻到 VCC否则信号不稳定。我一开始没加上拉电阻读取成功率只有 30%加上之后提升到 85%。第三步连接继电器模块。继电器的 VCC 接 5V物理引脚 2GND 接 GND物理引脚 9IN 接 GPIO17物理引脚 11。继电器的输出端接灯具的火线零线直连。这里涉及 220V 强电如果你没有电工经验建议先用 LED 灯珠模拟等逻辑跑通了再接触强电。安全第一。第四步上电检查。先不插 SD 卡只接电源用万用表测量各引脚电压确认 3.3V 和 5V 正常。然后断电插上 SD 卡上电启动。4.2 Android Things 项目结构与关键代码项目结构如下app/ ├── src/main/ │ ├── java/com/example/smarthome/ │ │ ├── MainActivity.java // 主入口初始化 GPIO 和 MQTT │ │ ├── SensorManager.java // 传感器读取逻辑 │ │ ├── DeviceController.java // 继电器控制逻辑 │ │ ├── MqttHandler.java // MQTT 通信 │ │ └── HttpServer.java // HTTP API │ ├── res/ │ └── AndroidManifest.xmlAndroidManifest.xml里需要声明权限和特性uses-permission android:nameandroid.permission.INTERNET / uses-permission android:nameandroid.permission.ACCESS_NETWORK_STATE / uses-feature android:nameandroid.hardware.type.embedded /uses-feature这一行很关键它告诉系统这是一个嵌入式设备应用没有它的话Android Things 可能不会在启动时自动运行你的 App。主入口MainActivity的核心逻辑public class MainActivity extends Activity { private Gpio ledPin; private SensorManager sensorManager; private MqttHandler mqttHandler; Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); PeripheralManagerService manager new PeripheralManagerService(); try { ledPin manager.openGpio(BCM17); ledPin.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW); } catch (IOException e) { Log.e(TAG, GPIO init failed, e); } sensorManager new SensorManager(manager); mqttHandler new MqttHandler(this); mqttHandler.connect(); } Override protected void onDestroy() { super.onDestroy(); if (ledPin ! null) { try { ledPin.close(); } catch (IOException e) { } } mqttHandler.disconnect(); } }传感器读取的定时任务用ScheduledExecutorService每 5 秒读一次ScheduledExecutorService scheduler Executors.newSingleThreadScheduledExecutor(); scheduler.scheduleAtFixedRate(() - { float temp sensorManager.readTemperature(); float humidity sensorManager.readHumidity(); mqttHandler.publish(home/sensor/bedroom, String.format({\temp\:%.1f,\humidity\:%.1f}, temp, humidity)); }, 0, 5, TimeUnit.SECONDS);4.3 手机 App 与中枢的联调手机 App 我用的是 Kotlin Retrofit接口定义很简单interface SmartHomeApi { GET(/api/sensors) suspend fun getSensors(): SensorData POST(/api/control) suspend fun controlDevice(Body command: ControlCommand): ResponseUnit }联调的时候遇到一个典型问题Android Things 的 HTTP 服务器默认监听 8080 端口但手机 App 用 Retrofit 请求的时候一直超时。排查后发现是 Android Things 的防火墙默认只开放了 ADB 端口5555其他端口需要手动开放。解决办法是在adb shell里执行adb shell iptables -A INPUT -p tcp --dport 8080 -j ACCEPT但这个命令重启后会失效需要写一个启动脚本。我把命令放到了MainActivity的onCreate里用Runtime.getRuntime().exec()执行这样每次 App 启动都会自动开放端口。另一个问题是 JSON 解析。Android Things 上跑的是完整 Android 系统可以用 Gson 或 Moshi但要注意混淆规则。我在proguard-rules.pro里加了-keep class com.example.smarthome.model.** { *; }否则 Release 版本会因为混淆导致 JSON 字段名被改解析失败。4.4 自动化逻辑的实现智能家居的核心价值在于自动化。我实现了几个基础规则温度高于 28°C 自动开风扇继电器 1湿度低于 40% 自动开加湿器继电器 2晚上 10 点后自动关闭所有灯光这些规则用简单的if-else就能实现但更好的方式是做一个规则引擎。我用了一个轻量级的方案把规则定义成 JSON存在 SD 卡里中枢启动时加载{ rules: [ { name: 高温开风扇, condition: {sensor: temperature, operator: , value: 28}, action: {device: fan, command: on} } ] }然后写一个RuleEngine类每次传感器数据更新时遍历规则匹配到就执行动作。这样做的好处是修改规则不需要重新编译代码直接改 JSON 文件重启就行。5. 常见问题与排查技巧实录5.1 系统启动失败与 ADB 连接问题问题现象树莓派上电后 HDMI 无输出或者卡在 Android Things Logo 不动。排查思路首先检查电源用万用表量一下电压是否稳定在 5V。如果电压低于 4.8V系统会启动失败。其次检查 SD 卡Android Things 对 SD 卡的速度有要求Class 10 以上比较稳妥。我用过一张杂牌的 Class 4 卡写入镜像后启动一直失败换卡后正常。ADB 连接问题如果adb connect一直失败先确认树莓派和电脑在同一个网段。然后检查 ADB 版本Android Things 需要 ADB 1.0.39 以上。如果还是不行用adb kill-server adb start-server重启 ADB 服务。5.2 GPIO 控制异常与电平匹配问题现象继电器不吸合或者吸合后树莓派重启。排查思路继电器不吸合先量 GPIO 输出电压如果是 3.3V 而继电器需要 5V就需要电平转换。吸合后重启基本是电源功率不够换大功率电源。另外继电器线圈在断电时会产生反向电动势可能干扰树莓派建议在继电器线圈两端并联一个续流二极管1N4007。5.3 传感器读取不稳定问题现象DHT11 读取成功率低数据偶尔为 NaN。排查思路首先检查上拉电阻4.7K 到 10K 都可以我用的 10K。其次检查接线长度杜邦线太长会引入干扰建议不超过 20cm。如果还是不稳定在代码里加重试机制for (int i 0; i 3; i) { float temp sensorManager.readTemperature(); if (!Float.isNaN(temp)) return temp; Thread.sleep(100); } return Float.NaN;5.4 MQTT 断线重连与消息丢失问题现象Wi-Fi 波动后 MQTT 连接断开重连后收不到消息。排查思路确保setAutomaticReconnect(true)和setCleanSession(false)。cleanSession设为 false 时Broker 会保留订阅关系和未送达的消息QoS 1 或 2。但要注意cleanSession为 false 时客户端 ID 必须固定否则 Broker 会认为是新客户端。5.5 常见问题速查表问题可能原因解决方法系统启动失败电源不足 / SD 卡速度慢换 5V 2.5A 电源 / Class 10 SD 卡ADB 连不上网段不同 / ADB 版本低检查网络 / 升级 ADB继电器不吸合电平不匹配换 3.3V 继电器或加电平转换树莓派重启电源功率不够换大功率电源DHT11 读取失败缺上拉电阻 / 线太长加上拉电阻 / 缩短线长MQTT 断线Wi-Fi 不稳定开启自动重连 / 固定客户端 IDHTTP 超时防火墙未开放端口iptables 开放端口JSON 解析失败混淆规则缺失添加 keep 规则6. 系统扩展与个人实操体会这套系统跑了大半年中间经历过几次迭代。最开始只有温湿度和灯光控制后来陆续加了人体红外传感器HC-SR501、门窗磁传感器MC-38、以及一个简单的语音控制模块。每次加新设备核心逻辑几乎不用改只需要在SensorManager里加一个读取方法在RuleEngine里加一条规则。这种中枢集中决策的架构扩展性确实比分散式方案好很多。不过 Android Things 也有它的局限。首先是启动速度从通电到 App 完全就绪大概需要 40 秒比 ESP8266 的 3 秒慢太多。如果你需要快速响应的场景比如人体感应开灯纯 Android Things 方案会有明显的延迟。我的做法是把人体感应这种低延迟需求放到 ESP8266 终端节点上本地直接触发继电器同时通过 MQTT 通知中枢记录状态。这样既保证了响应速度又保留了中枢的数据聚合能力。其次是成本。一块 Raspberry Pi 3 加上电源、SD 卡、外壳整套下来接近 300 块。如果你只是想做一两个灯的控制用 ESP8266 方案 30 块就能搞定。Android Things 适合的是那种需要复杂逻辑、多设备协同、且你本身有 Android 开发经验的场景。如果你完全不懂 Android为了做智能家居去学 Android 开发投入产出比可能不太划算。最后分享一个我在调试过程中总结的小技巧Android Things 的日志可以通过adb logcat查看但默认输出量很大建议用标签过滤adb logcat -s SmartHome:V MqttHandler:V SensorManager:V这样只看自己代码的日志排查问题效率高很多。另外Android Things 支持远程调试你可以在 Android Studio 里直接对树莓派上的 App 下断点单步调试硬件逻辑这个体验比串口打印日志好太多了。我第一次用远程调试定位到 DHT11 时序问题时感觉就像在调试一个普通的 Android App完全忘了自己是在操作硬件。

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

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

免费获取报价 →
↑