下载资源
MQTT扩展下载:
de.ullisroboterseite.ursai2pahomqtt.aix
完整示例项目:
MQTT协议深度解析
1. 协议架构与通信模式
MQTT采用客户端-服务器架构,基于发布/订阅(Publish/Subscribe)模式实现消息传递:
graph LR
A[发布者A] --> C[MQTT代理服务器]
B[发布者B] --> C
C --> D[订阅者X]
C --> E[订阅者Y]
C --> F[订阅者Z]
核心组件说明:
- 发布者(Publisher):消息发送方,向特定主题发布消息
- 订阅者(Subscriber):消息接收方,订阅感兴趣的主题
- 代理服务器(Broker):消息路由中心,负责消息转发和存储
2. 消息质量等级(QoS)详解
| QoS等级 | 传递保证 | 消息流 | 应用场景 | 网络开销 |
|---|---|---|---|---|
| QoS 0 | 最多一次 | PUBLISH → Broker → Subscriber | 传感器数据、温度读数 | 最低 |
| QoS 1 | 至少一次 | PUBLISH → PUBACK → PUBLISH → PUBACK | 控制指令、报警信息 | 中等 |
| QoS 2 | 恰好一次 | PUBLISH → PUBREC → PUBREL → PUBCOMP | 金融交易、计费系统 | 最高 |
QoS实现示例:
// 设置不同QoS级别发布消息
when Button_PublishQoS0.Click() {
UrsPahoMqttClient1.Publish("sensor/temperature", "25.6", 0)
}
when Button_PublishQoS1.Click() {
UrsPahoMqttClient1.Publish("control/light", "ON", 1)
}
when Button_PublishQoS2.Click() {
UrsPahoMqttClient1.Publish("payment/confirm", "SUCCESS", 2)
}
3. 主题设计与最佳实践
主题命名规范:
{namespace}/{device_type}/{device_id}/{attribute}/{action}
示例:
home/thermostat/livingroom/temperature/set
office/light/meeting_room/brightness/get
factory/sensor/machine_001/status/online
通配符使用规则:
// 单级通配符匹配
UrsPahoMqttClient1.Subscribe("home/+/temperature") // 匹配 home/livingroom/temperature
// 多级通配符匹配
UrsPahoMqttClient1.Subscribe("factory/#") // 匹配 factory/sensor/machine_001/status
完整实战项目:智能温室控制系统
项目概述
实现一个基于MQTT的智能温室控制系统,包含:
- 温湿度传感器数据采集
- 自动灌溉控制
- 远程监控和手动控制
- 数据记录和报警功能
系统架构设计
graph TB
subgraph "App Inventor移动应用"
A[控制界面] --> B[MQTT客户端]
B --> C[数据处理模块]
C --> D[图表显示]
C --> E[报警系统]
end
subgraph "MQTT云平台"
F[MQTT Broker]
G[主题路由]
H[消息持久化]
end
subgraph "温室设备"
I[温湿度传感器]
J[水泵控制器]
K[通风扇控制器]
L[光照传感器]
end
B --> F
F --> G
G --> I
G --> J
G --> K
G --> L
I --> F
J --> F
K --> F
L --> F
1. 主题设计策略
// 传感器数据主题
procedure defineTopics() {
global SENSOR_TOPICS = [
"greenhouse/sensor/temperature",
"greenhouse/sensor/humidity",
"greenhouse/sensor/light",
"greenhouse/sensor/soil_moisture"
]
global CONTROL_TOPICS = [
"greenhouse/control/water_pump",
"greenhouse/control/fan",
"greenhouse/control/led_light"
]
global STATUS_TOPICS = [
"greenhouse/status/system",
"greenhouse/status/alerts",
"greenhouse/status/device_status"
]
}
2. 连接管理与重连机制
// 智能连接管理
when Screen1.Initialize() {
MaxRetryCount = 5
CurrentRetry = 0
ReconnectInterval = 3000 // 3秒
initializeMQTTConnection()
}
// MQTT连接初始化
procedure initializeMQTTConnection() {
UrsPahoMqttClient1.Broker = "broker.emqx.io"
UrsPahoMqttClient1.Port = 1883
UrsPahoMqttClient1.ClientID = join("greenhouse_", getDeviceID())
UrsPahoMqttClient1.UserName = "greenhouse_user"
UrsPahoMqttClient1.UserPassword = "secure_password"
// 设置遗愿消息
UrsPahoMqttClient1.WillTopic = "greenhouse/status/device_status"
UrsPahoMqttClient1.WillMessage = join("{\"status\":\"offline\",\"device\":\"", getDeviceID(), "\"}")
UrsPahoMqttClient1.WillQoS = 1
connectToBroker()
}
// 连接到MQTT代理
procedure connectToBroker() {
Label_ConnectionStatus.Text = "正在连接MQTT服务器..."
Button_Connect.Enabled = false
UrsPahoMqttClient1.Connect()
}
// 连接状态处理
when UrsPahoMqttClient1.ConnectionStateChanged(newState) {
if newState = 1 { // 连接成功
CurrentRetry = 0
Label_ConnectionStatus.Text = "已连接 - 在线"
Label_ConnectionStatus.TextColor = "&HFF4CAF50"
subscribeToAllTopics()
startHeartbeat()
} else if newState = 0 { // 连接断开
Label_ConnectionStatus.Text = "连接断开"
Label_ConnectionStatus.TextColor = "&HFFF44336"
// 自动重连机制(AI2 无阻塞等待:实际项目用 Clock 定时器延迟 ReconnectInterval 毫秒后重连)
if CurrentRetry < MaxRetryCount {
CurrentRetry = CurrentRetry + 1
connectToBroker()
} else {
Notifier1.ShowAlert("连接失败,请检查网络设置")
}
}
}
// 自动重连和错误恢复
when UrsPahoMqttClient1.ConnectionError(errorMessage) {
Label_ConnectionStatus.Text = join("连接错误: ", errorMessage)
Label_ConnectionStatus.TextColor = "&HFFF44336"
// 记录错误日志
logError("MQTT连接错误", errorMessage)
// 尝试重连(同上,延迟用 Clock 定时器实现)
if CurrentRetry < MaxRetryCount {
connectToBroker()
}
}
3. 传感器数据处理
// 接收传感器数据
when UrsPahoMqttClient1.MessageReceived(topic, message) {
// 解析JSON数据
Data = Web1.JsonTextDecode(message)
// 根据主题处理不同类型的传感器数据
if textContains(topic, "temperature") {
handleTemperatureData(Data)
} else if textContains(topic, "humidity") {
handleHumidityData(Data)
} else if textContains(topic, "light") {
handleLightData(Data)
} else if textContains(topic, "soil_moisture") {
handleSoilMoistureData(Data)
}
// 更新最后接收时间
LastUpdateTime = Clock1.SystemTime
Label_LastUpdate.Text = join("最后更新: ", formatDateTime(LastUpdateTime))
}
// 温度数据处理
procedure handleTemperatureData(data) {
Temperature = dictLookup(data, "temperature", 0)
SensorID = dictLookup(data, "sensor_id", "")
Timestamp = dictLookup(data, "timestamp", 0)
// 更新显示
Label_Temperature.Text = join("温度: ", Temperature, "°C")
// 记录历史数据
addTemperatureRecord(Timestamp, Temperature)
// 温度控制逻辑
if Temperature > 30 {
// 温度过高,开启风扇
publishControlCommand("fan", "ON", 1)
Alert_TemperatureHigh.Visible = true
} else if Temperature < 15 {
// 温度过低,关闭风扇
publishControlCommand("fan", "OFF", 1)
Alert_TemperatureLow.Visible = true
} else {
// 温度正常
Alert_TemperatureHigh.Visible = false
Alert_TemperatureLow.Visible = false
}
}
// 湿度数据处理
procedure handleHumidityData(data) {
Humidity = dictLookup(data, "humidity", 0)
SensorID = dictLookup(data, "sensor_id", "")
// 更新显示
Label_Humidity.Text = join("湿度: ", Humidity, "%")
// 湿度控制逻辑
if Humidity < 40 {
// 湿度过低,开启水泵
publishControlCommand("water_pump", "ON", 1)
Alert_HumidityLow.Visible = true
} else if Humidity > 80 {
// 湿度过高,关闭水泵
publishControlCommand("water_pump", "OFF", 1)
Alert_HumidityHigh.Visible = true
} else {
Alert_HumidityLow.Visible = false
Alert_HumidityHigh.Visible = false
}
}
4. 控制指令发布
// 发布控制命令
procedure publishControlCommand(device, action, qos) {
Topic = join("greenhouse/control/", device)
// jsonEncode 为自定义 JSON 序列化辅助过程(AI2 无内建 JSON 编码)
Message = {
"device": device,
"action": action,
"timestamp": Clock1.SystemTime,
"operator": "mobile_app"
}
UrsPahoMqttClient1.Publish(Topic, jsonEncode(Message), qos)
// 记录操作日志
logControlOperation(device, action)
}
// 手动控制按钮事件
when Button_WaterPumpManual.Click() {
if Button_WaterPumpManual.Text = "开启水泵" {
publishControlCommand("water_pump", "ON", 1)
Button_WaterPumpManual.Text = "关闭水泵"
Button_WaterPumpManual.BackgroundColor = "&HFFF44336"
} else {
publishControlCommand("water_pump", "OFF", 1)
Button_WaterPumpManual.Text = "开启水泵"
Button_WaterPumpManual.BackgroundColor = "&HFF4CAF50"
}
}
when Button_FanManual.Click() {
if Button_FanManual.Text = "开启风扇" {
publishControlCommand("fan", "ON", 1)
Button_FanManual.Text = "关闭风扇"
Button_FanManual.BackgroundColor = "&HFFF44336"
} else {
publishControlCommand("fan", "OFF", 1)
Button_FanManual.Text = "开启风扇"
Button_FanManual.BackgroundColor = "&HFF4CAF50"
}
}
when Button_LEDLightManual.Click() {
if Button_LEDLightManual.Text = "开启LED灯" {
publishControlCommand("led_light", "ON", 1)
Button_LEDLightManual.Text = "关闭LED灯"
Button_LEDLightManual.BackgroundColor = "&HFFF44336"
} else {
publishControlCommand("led_light", "OFF", 1)
Button_LEDLightManual.Text = "开启LED灯"
Button_LEDLightManual.BackgroundColor = "&HFF4CAF50"
}
}
// 定时控制(AI2 无定时回调:每个任务用一个 Clock 组件 + Timer 事件实现)
when Clock_LedMorning.Timer() {
// 每天早上6点开启LED灯
publishControlCommand("led_light", "ON", 1)
}
when Clock_LedEvening.Timer() {
// 每天晚上8点关闭LED灯
publishControlCommand("led_light", "OFF", 1)
}
when Clock_SoilCheck.Timer() {
// 每小时检查土壤湿度
requestSoilMoistureReading()
}
5. 数据可视化和历史记录
// SSL/TLS安全连接
procedure setupSecureConnection() {
UrsPahoMqttClient1.Broker = "secure-broker.example.com"
UrsPahoMqttClient1.Port = 8883
UrsPahoMqttClient1.Protocol = "TLS"
// 设置证书验证
UrsPahoMqttClient1.TrustedCertFile = "ca.crt"
UrsPahoMqttClient1.TruststoreFile = "truststore.jks"
UrsPahoMqttClient1.TruststorePassword = "truststore_password"
// 客户端证书验证
UrsPahoMqttClient1.ClientCertFile = "client.crt"
UrsPahoMqttClient1.ClientKeyFile = "client.key"
connectToBroker()
}
// 动态密码更新
when Button_UpdateCredentials.Click() {
NewUsername = TextBox_Username.Text
NewPassword = TextBox_Password.Text
if NewUsername = "" or NewPassword = "" {
Notifier1.ShowAlert("用户名和密码不能为空")
} else {
// 断开当前连接(延迟 2 秒用 Clock 定时器实现)
if UrsPahoMqttClient1.IsConnected {
UrsPahoMqttClient1.Disconnect()
}
// 更新凭据
UrsPahoMqttClient1.UserName = NewUsername
UrsPahoMqttClient1.UserPassword = NewPassword
// 重新连接
connectToBroker()
// 保存凭据到安全存储
saveCredentials(NewUsername, NewPassword)
}
}
6. 安全连接和身份验证
// 数据记录和可视化
procedure addTemperatureRecord(timestamp, value) {
// 添加到时间序列数据
listAdd(TemperatureTimestamps, timestamp)
listAdd(TemperatureValues, value)
// 限制数据点数量(保留最近100个点)
if length(TemperatureTimestamps) > 100 {
listRemove(TemperatureTimestamps, 1)
listRemove(TemperatureValues, 1)
}
// 更新图表显示
updateTemperatureChart()
}
// 更新温度图表
procedure updateTemperatureChart() {
// 清除之前的图表数据
Chart_Temperature.Clear()
// 添加数据点
for i = 1 to length(TemperatureTimestamps) {
Timestamp = TemperatureTimestamps[i]
Value = TemperatureValues[i]
TimeLabel = formatTime(Timestamp)
Chart_Temperature.AddDataPoint(TimeLabel, Value)
}
// 设置图表属性
Chart_Temperature.SetTitle("温室温度趋势")
Chart_Temperature.SetYAxisTitle("温度 (°C)")
Chart_Temperature.SetXAxisTitle("时间")
}
// 生成数据报告(calculateAverage/maximum/minimum 为自定义统计辅助过程)
when Button_GenerateReport.Click() {
Report = {
"generated_at": Clock1.SystemTime,
"device_id": getDeviceID(),
"data_period": "24小时",
"temperature_avg": calculateAverage(TemperatureValues),
"temperature_max": maximum(TemperatureValues),
"temperature_min": minimum(TemperatureValues),
"humidity_avg": calculateAverage(HumidityValues),
"device_status": Label_ConnectionStatus.Text,
"alert_count": getAlertCount()
}
// 保存报告(jsonEncode 为自定义 JSON 序列化辅助过程)
saveReportToFile(jsonEncode(Report))
Notifier1.ShowAlert("报告已生成")
}
7. 性能优化和错误处理
// 消息缓存和批处理
global MessageCache = []
global BatchSize = 10
global BatchInterval = 5000
// 批量发送消息
procedure batchPublishMessages() {
if length(MessageCache) >= BatchSize {
BatchMessages = []
// 取出批量消息
for i = 1 to BatchSize {
listAdd(BatchMessages, MessageCache[1])
listRemove(MessageCache, 1)
}
// 合并为一条消息(jsonEncode 为自定义 JSON 序列化辅助过程)
CombinedMessage = {
"type": "batch",
"messages": BatchMessages,
"timestamp": Clock1.SystemTime
}
// 发布批量消息
UrsPahoMqttClient1.Publish("greenhouse/data/batch", jsonEncode(CombinedMessage), 1)
}
}
// 消息缓存管理
procedure cacheMessage(topic, message) {
MessageEntry = {
"topic": topic,
"message": message,
"timestamp": Clock1.SystemTime
}
listAdd(MessageCache, MessageEntry)
// 检查是否需要批量发送
if length(MessageCache) >= BatchSize {
batchPublishMessages()
}
}
// 错误处理和日志记录
when UrsPahoMqttClient1.PublishError(errorCode, errorMessage) {
Label_ErrorStatus.Text = join("发布错误: ", errorMessage)
Label_ErrorStatus.TextColor = "&HFFF44336"
// 记录错误日志
logError("发布失败", errorMessage)
// 错误恢复策略
if errorCode = 32100 { // 连接丢失
handleConnectionLost()
} else if errorCode = 32101 { // 消息过大
handleMessageTooLarge(errorMessage)
} else if errorCode = 32102 { // QoS不支持
handleQoSNotSupported()
}
}
// 连接丢失处理
procedure handleConnectionLost() {
// 停止所有定时任务
stopHeartbeat()
stopDataCollection()
// 标记设备为离线状态
Label_DeviceStatus.Text = "设备离线"
Label_DeviceStatus.BackgroundColor = "&HFFF44336"
// 启动重连机制
startReconnectProcedure()
}
8. 高级功能实现
// 心跳机制(30秒心跳间隔)
procedure startHeartbeat() {
Clock_Heartbeat.TimerInterval = 30000
Clock_Heartbeat.TimerEnabled = true
}
when Clock_Heartbeat.Timer() {
if UrsPahoMqttClient1.IsConnected {
HeartbeatMessage = {
"device_id": getDeviceID(),
"status": "online",
"timestamp": Clock1.SystemTime,
"battery": getBatteryLevel(),
"signal": getSignalStrength()
}
UrsPahoMqttClient1.Publish("greenhouse/heartbeat", jsonEncode(HeartbeatMessage), 1)
} else {
startReconnectProcedure()
}
}
// 设备发现和注册
procedure discoverDevices() {
UrsPahoMqttClient1.Publish("greenhouse/discovery/request",
jsonEncode({"action": "request", "device_id": getDeviceID()}), 1)
}
// 处理设备发现响应
when UrsPahoMqttClient1.MessageReceived(topic, message) {
if topic = "greenhouse/discovery/response" {
Response = Web1.JsonTextDecode(message)
DeviceList = dictLookup(Response, "devices", [])
// 更新设备列表
updateDeviceList(DeviceList)
} else if topic = "greenhouse/discovery/announce" {
Announce = Web1.JsonTextDecode(message)
addDeviceToList(dictLookup(Announce, "device_id", ""), dictLookup(Announce, "device_type", ""))
}
}
// 远程固件更新
procedure checkFirmwareUpdate() {
UrsPahoMqttClient1.Publish("greenhouse/firmware/check",
jsonEncode({"device_id": getDeviceID(), "current_version": getFirmwareVersion()}), 1)
}
when UrsPahoMqttClient1.MessageReceived(topic, message) {
if topic = "greenhouse/firmware/update" {
UpdateInfo = Web1.JsonTextDecode(message)
if dictLookup(UpdateInfo, "device_id", "") = getDeviceID() {
processFirmwareUpdate(UpdateInfo)
}
}
}
// 固件更新处理(AskUser 为自定义确认弹窗辅助过程)
procedure processFirmwareUpdate(updateInfo) {
if dictLookup(updateInfo, "available", false) {
// 显示更新通知
Notifier1.ShowAlert(join("发现新固件版本: ", dictLookup(updateInfo, "new_version", "")))
// 询问用户是否更新
if AskUser("是否立即更新固件?") {
downloadFirmware(dictLookup(updateInfo, "download_url", ""))
}
}
}
测试和验证
1. 功能测试清单
// 自动化测试流程
procedure runAutomatedTests() {
TestResults = []
// 测试1: 连接测试
Test_Connection(TestResults)
// 测试2: 消息发布测试
Test_Publish(TestResults)
// 测试3: 消息订阅测试
Test_Subscribe(TestResults)
// 测试4: QoS测试
Test_QoS(TestResults)
// 测试5: 重连测试
Test_Reconnection(TestResults)
// 生成测试报告
generateTestReport(TestResults)
}
// 连接测试(AI2 无 try/catch:错误统一走 Screen1.ErrorOccurred 事件;
// 连接等待用 Clock 定时器延迟 5 秒后再检查)
procedure Test_Connection(results) {
connectToBroker()
if UrsPahoMqttClient1.IsConnected {
listAdd(results, {"test": "连接测试", "status": "PASS", "message": "连接成功"})
} else {
listAdd(results, {"test": "连接测试", "status": "FAIL", "message": "连接失败"})
}
}
2. 性能监控
// 性能指标收集
global PerformanceMetrics = {}
global MessageCount = 0
global ErrorCount = 0
global AverageResponseTime = 0
// 记录性能指标(calculateAverage 为自定义统计辅助过程)
procedure recordPerformanceMetric(metricType, value) {
if metricType = "message_sent" {
MessageCount = MessageCount + 1
PerformanceMetrics = dictSet(PerformanceMetrics, "messages_sent", MessageCount)
} else if metricType = "message_received" {
PerformanceMetrics = dictSet(PerformanceMetrics, "messages_received",
dictLookup(PerformanceMetrics, "messages_received", 0) + 1)
} else if metricType = "response_time" {
ResponseTimes = dictLookup(PerformanceMetrics, "response_times", [])
listAdd(ResponseTimes, value)
PerformanceMetrics = dictSet(PerformanceMetrics, "response_times", ResponseTimes)
AverageResponseTime = calculateAverage(ResponseTimes)
PerformanceMetrics = dictSet(PerformanceMetrics, "avg_response_time", AverageResponseTime)
} else if metricType = "error" {
ErrorCount = ErrorCount + 1
PerformanceMetrics = dictSet(PerformanceMetrics, "error_count", ErrorCount)
}
}
// 生成性能报告
procedure generatePerformanceReport() {
Report = {
"generated_at": Clock1.SystemTime,
"total_messages": MessageCount,
"error_rate": (ErrorCount / MessageCount) * 100,
"avg_response_time": AverageResponseTime,
"uptime": getUptime()
}
// 保存性能报告
savePerformanceReport(jsonEncode(Report))
}
部署和维护
1. 生产环境配置
// 生产环境初始化
procedure initializeProductionEnvironment() {
// 设置生产服务器
UrsPahoMqttClient1.Broker = "mqtt.production-server.com"
UrsPahoMqttClient1.Port = 8883
UrsPahoMqttClient1.Protocol = "TLS"
// 从安全存储读取凭据(loadSecureCredentials 为自定义辅助过程)
Credentials = loadSecureCredentials()
UrsPahoMqttClient1.UserName = dictLookup(Credentials, "username", "")
UrsPahoMqttClient1.UserPassword = dictLookup(Credentials, "password", "")
// 配置SSL/TLS
UrsPahoMqttClient1.TrustedCertFile = "production_ca.crt"
UrsPahoMqttClient1.TruststoreFile = "production_truststore.jks"
UrsPahoMqttClient1.TruststorePassword = dictLookup(Credentials, "truststore_password", "")
// 设置高QoS用于关键数据
CriticalQoS = 2
NormalQoS = 1
}
2. 监控和告警
// 系统健康监控
procedure healthCheck() {
IsHealthy = true
// 检查系统健康状态
if !UrsPahoMqttClient1.IsConnected {
IsHealthy = false
sendAlert("MQTT连接断开", "critical")
}
if ErrorCount > MessageCount * 0.05 { // 错误率超过5%
IsHealthy = false
sendAlert("错误率过高", "warning")
}
if AverageResponseTime > 5000 { // 平均响应时间超过5秒
IsHealthy = false
sendAlert("响应时间过长", "warning")
}
HealthStatus = {
"timestamp": Clock1.SystemTime,
"mqtt_connected": UrsPahoMqttClient1.IsConnected,
"message_count": MessageCount,
"error_count": ErrorCount,
"avg_response_time": AverageResponseTime,
"healthy": IsHealthy
}
// 发送健康状态报告
UrsPahoMqttClient1.Publish("greenhouse/health", jsonEncode(HealthStatus), 1)
}
总结
本教程提供了完整的MQTT物联网应用开发方案,涵盖了从基础概念到高级应用的各个方面。通过实际项目案例,展示了如何使用App Inventor构建可靠的物联网应用,包括:
- 完整的MQTT连接管理:自动重连、错误处理、状态监控
- 智能数据处理:实时数据分析、自动控制、告警系统
- 高级功能实现:批量处理、心跳机制、设备发现
- 生产级部署:安全连接、性能监控、系统健康检查
这些技术和最佳实践为构建企业级物联网应用提供了坚实的基础。
扫码添加客服咨询