25、Android Things与IoT:嵌入式场景、外设控制、云端对接

说到Android Things,我脑子里第一个蹦出来的画面,是几年前在实验室里调试一块智能灯板。灯板死活不亮,我折腾了整整一个下午。最后发现,是GPIO的引脚号写错了。嗯,这种低级错误,我相信不止我一个人犯过。

Android Things,说白了就是Google为IoT设备定制的Android系统。它砍掉了手机上的那些花哨功能,保留了核心的Linux内核和Android框架。你想想看,一个智能音箱、一个工业传感器网关,它们不需要跑微信和抖音,它们需要的是稳定、低功耗、能直接操作硬件引脚。

这就是Android Things存在的意义。

嵌入式场景:Android Things能做什么?

我个人习惯把IoT设备分成三类:

  • 智能家居类:智能灯、智能插座、温控器。这类设备对实时性要求不高,但需要稳定的Wi-Fi连接。
  • 工业监测类:传感器数据采集、设备状态上报。这类设备往往7×24小时运行,掉线了要能自动重连。
  • 边缘计算类:在设备端做简单的AI推理,比如人脸识别门禁。这类设备需要一定的算力。

Android Things在这三类场景里都能找到位置。我记得有个项目,客户要求在工厂里部署一批温湿度监测器。用单片机做吧,开发周期长;用树莓派跑Linux吧,又太重了。最后我们选了Android Things,开发效率高,而且OTA升级机制现成的。

核心优势:Android Things继承了Android的权限管理、网络栈、多媒体框架。你不需要从零开始写驱动,大部分外设都有现成的API。

外设控制:GPIO、PWM、I2C、SPI

外设控制是嵌入式开发的核心。Android Things提供了统一的Peripheral API,操作起来比Linux原生的sysfs要友好得多。

GPIO:最基础的数字信号

GPIO就是高低电平。控制一个LED,或者读取一个按键状态,都用它。

// 初始化GPIO引脚
PeripheralManager manager = PeripheralManager.getInstance();
Gpio ledGpio = manager.openGpio("BCM17"); // 树莓派上的GPIO17

// 设置为输出模式
ledGpio.setDirection(Gpio.DIRECTION_OUT_INITIALLY_LOW);

// 点亮LED
ledGpio.setValue(true);

// 读取按键状态
Gpio buttonGpio = manager.openGpio("BCM18");
buttonGpio.setDirection(Gpio.DIRECTION_IN);
boolean isPressed = buttonGpio.getValue();

我曾经踩过一个坑:GPIO的引脚编号在不同平台上不一样。树莓派上叫BCM17,在NXP i.MX7D上可能叫GPIO1_IO12。所以代码里最好用配置文件来管理引脚映射,别写死。

PWM:控制电机速度、灯光亮度

PWM就是脉冲宽度调制。通过改变占空比,可以控制LED的亮度,或者直流电机的转速。

Pwm pwm = manager.openPwm("PWM0");
pwm.setPwmFrequencyHz(1000); // 1kHz
pwm.setPwmDutyCycle(50.0);   // 50%占空比
pwm.setEnabled(true);

小技巧:PWM频率不要设得太高。人眼对100Hz以上的闪烁就不敏感了,但电机驱动需要几百Hz到几kHz。我一般LED用200Hz,电机用1kHz。

I2C与SPI:与传感器通信

I2C和SPI是嵌入式世界里最常见的两种总线协议。I2C适合连接多个低速设备,SPI适合高速数据传输。

举个例子,读取一个BME280温湿度传感器(I2C接口):

I2cDevice i2c = manager.openI2cDevice("I2C1", 0x76); // 设备地址0x76

// 读取温度寄存器
byte[] data = new byte[2];
i2c.readRegBuffer(0xFA, data, 2); // 0xFA是温度寄存器地址

// 解析数据(简化版)
int rawTemp = ((data[0] & 0xFF) << 8) | (data[1] & 0xFF);
double temperature = rawTemp / 100.0;

这里要注意:I2C设备的地址是7位的,但很多数据手册写的是8位地址(左移了一位)。我刚开始做的时候,拿着0xEC去通信,死活没响应。后来才发现,Android Things的API用的是7位地址,0x76才对。

避坑指南:我曾经在SPI通信时忽略了片选信号的电平极性。有些设备是低电平有效,有些是高电平有效。不匹配的话,数据根本读不出来。一定要仔细看数据手册。

云端对接:MQTT与Firebase

设备采集了数据,总得传到云端吧。Android Things设备通常通过Wi-Fi联网,云端对接最常用的协议是MQTT。

MQTT:轻量级物联网协议

MQTT的优点是:协议开销小、支持QoS(消息质量)、支持发布/订阅模式。非常适合低带宽、不稳定的网络环境。

// 使用Eclipse Paho MQTT客户端
MqttClient client = new MqttClient("tcp://broker.emqx.io:1883", "device_001");

MqttConnectOptions options = new MqttConnectOptions();
options.setCleanSession(true);
options.setConnectionTimeout(10);
options.setKeepAliveInterval(60);

client.connect(options);

// 发布传感器数据
String payload = "{\"temperature\":25.3, \"humidity\":60.1}";
MqttMessage message = new MqttMessage(payload.getBytes());
message.setQos(1); // 至少一次
client.publish("sensor/temperature", message);

// 订阅控制指令
client.subscribe("device/001/control", (topic, msg) -> {
    String command = new String(msg.getPayload());
    if ("led_on".equals(command)) {
        ledGpio.setValue(true);
    }
});

我个人习惯把MQTT的Broker地址和Topic都放在配置文件中,不要硬编码。因为设备出厂后,Broker地址可能会变。用Firebase Remote Config或者本地配置文件来管理,方便后期维护。

Firebase:快速搭建云端后台

如果你不想自己搭服务器,Firebase是个不错的选择。Android Things设备可以直接集成Firebase SDK,把数据写到Firestore或者Realtime Database里。

// 初始化Firebase
FirebaseApp.initializeApp(context);
FirebaseFirestore db = FirebaseFirestore.getInstance();

// 上传传感器数据
Map<String, Object> data = new HashMap<>();
data.put("temperature", 25.3);
data.put("humidity", 60.1);
data.put("timestamp", System.currentTimeMillis());

db.collection("sensors")
  .document("device_001")
  .set(data)
  .addOnSuccessListener(aVoid -> Log.d("IoT", "数据上传成功"))
  .addOnFailureListener(e -> Log.e("IoT", "上传失败", e));

注意:Firebase SDK体积不小,对于存储空间有限的IoT设备来说,要掂量一下。我一般只在内存大于512MB的设备上用Firebase,小内存设备还是用MQTT更合适。

知识体系总览

下面这张图,是我梳理的Android Things IoT开发的核心知识结构。你可以把它当作一张地图,开发时按图索骥就好。

Android Things IoT 嵌入式场景 智能家居 工业监测 边缘计算 外设控制 GPIO(数字I/O) PWM(模拟输出) I2C / SPI(总线通信) 云端对接 MQTT协议 Firebase OTA升级 开发流程:硬件选型 → 外设驱动 → 数据采集 → 云端上报 核心原则:稳定优先,功耗控制,异常处理

避坑总结

做Android Things开发,有几个坑我反复踩过,分享给你:

  1. 引脚复用问题:很多SoC的引脚有多个功能。比如同一个引脚,既可以做GPIO,也可以做I2C的SCL。如果你在代码里同时用了两个功能,系统会报错。记得在Board Support Package里确认引脚配置。
  2. 电源管理:IoT设备很多是电池供电的。Android Things默认的电源策略是为手机设计的,耗电很快。我建议关掉不必要的系统服务,比如蓝牙、GPS,用JobScheduler来管理后台任务。
  3. 网络断连:Wi-Fi在IoT环境里并不总是稳定。设备掉线后,要能自动重连。我一般会在onNetworkFailure回调里,启动一个指数退避的重连策略。
  4. 日志管理:设备跑在现场,出了问题你没法插USB看logcat。所以一定要把关键日志写到本地文件,或者通过MQTT上报到云端。我习惯用Timber库,配合一个自定义的Tree,把日志同时写到文件和网络。

最后说一句:Android Things虽然已经停止更新了,但它的设计思路和API接口,对现在主流的嵌入式Android开发(比如基于AOSP裁剪的系统)依然有很强的参考价值。你学会了这些,换个平台也能很快上手。


公众号:蓝海资料掘金营,微信deep3321