前言
- 使用mqtt通讯,远程控制RPC
- round switch和Led indicator部件,外观能设置的东西很少,甚至开关的title文字颜色都不能改
MQTTFX模拟
服务器发RPC报文给客户端
- 默认设置新建一个round switch部件,注意:高级中Retrieve led status value using method(检查设备状态的方法)是Subscribe for attribute
- 默认设置新建一个Led indicator部件用于显示当前led状态
- 仪表板点击round switch会向v1/devices/me/rpc/request/$id主题发送报文{“method”:”setValue”,”params”:$true(false)}
客户端收到RPC报文后执行
- 解析报文id,向v1/devices/me/rpc/response/ParseError: KaTeX parse error: Expected ‘}’, got ‘EOF’ at end of input: …red”>{“value”: 0 or 1}确认连接
- 客户端记录led的状态,暂时只考虑开关两种状态
- 客户端向v1/devices/me/attributes主题发送属性报文
- 别忘记执行led开关操作,此处只需要digitalWrite(LED_BUILTIN, !ledStatus)(板载灯是反逻辑的)就可以了,也可以理解成更新led灯状态
服务器收到应答报文后执行
- 服务器根据v1/devices/me/rpc/response/$request_id主题响应报文更新round switch的状态
- 服务器根据v1/devices/me/attributes主题属性报文更新Led indicator的状态
至此远程点亮led就完成了,单片机上只要点灯成功,执行其他操作也就同理了
完整代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
<em>// MQTT操作库</em> #include <ESP8266WiFi.h> #include <PubSubClient.h> float humi_read = 0; <em>// 存放湿度</em> float temp_read = 0; <em>// 存放温度</em> long lastMsg = 0; <em>// 记录最后发送的时间</em> <em>// 温湿度传感器库</em> #include <DHT.h> #define DHTPIN D1 #define DHTTYPE DHT11 DHT dht(DHTPIN, DHTTYPE); <em>// 预加载传感器型号DHT11</em> <em>// 设置wifi接入信息(请根据您的WiFi信息进行修改)</em> const char* ssid = "****"; const char* password = "*******"; const char* mqttServer = "www.weishadian.com"; WiFiClient wifiClient; PubSubClient mqttClient(wifiClient); const char* client_ID = "esp8266_1"; <em>// id可以任意</em> const char* mqttUserName = "g6Wj*****SnNEL"; <em>// 设备令牌,token</em> const char* mqttPassword = ""; <em>// 密码为空</em> char dataTemplate[] = "{\"temp\": %.2f, \"humi\": %.2f, \"times\": %d}"; <em>// 简单信息模板</em> char postData[50]; <em>// 报文</em> int reportTimes = 0; <em>// 上报次数</em> <em>// 主题</em> char topic1[] = "v1/devices/me/telemetry"; <em>// 发布遥测数据的主题</em> char topic2[] = "v1/devices/me/rpc/request/+"; <em>// RPC客户端主题</em> char topic3[] = "v1/devices/me/attributes"; <em>// 属性主题</em> int subQoS = 0; <em>// QOS级别</em> bool ledStatus = true; <em>// led状态</em> char statusTemplate[] = "{\"value\": %d}"; char postStatus[50]; <em>// 报文</em> <em>// 连接wifi的函数</em> void connectWifi(){ WiFi.begin(ssid, password); <em>//等待WiFi连接,成功连接后输出成功信息</em> while (WiFi.status() != WL_CONNECTED) { delay(1000); Serial.print("."); } Serial.println(""); Serial.println("WiFi 连接成功!"); Serial.println(""); } <em>// 连接MQTT服务器</em> void connectMQTTserver(){ if (mqttClient.connect(client_ID, mqttUserName, mqttPassword)) { Serial.print("MQTT服务器连接成功。 ClientId: "); Serial.println(client_ID); Serial.print("MQTT服务器地址: "); Serial.println(mqttServer); } else { Serial.print("MQTT服务器连接失败,当前客户端状态:"); Serial.println(mqttClient.state()); } } <em>// 订阅指定主题</em> void subscribeTopic(char subTopic[], int subQoS){ if(mqttClient.subscribe(subTopic, subQoS)){ Serial.print("订阅主题: "); Serial.println(subTopic); } else { Serial.print("Subscribe Fail..."); } } <em>// 收到信息后的回调函数</em> void receiveCallback(char* topic, byte* payload, unsigned int length) { Serial.print("报文 ["); Serial.print(topic); Serial.print("] "); for (int i = 0; i < length; i++) { Serial.print((char)payload[i]); } Serial.println(""); Serial.print("报文长度(Bytes) "); Serial.println(length); <em>// 截取request主题的id,添加给response主题</em> char reTopic[50] = "v1/devices/me/rpc/response/"; <em>// RPC应答主题</em> for (int i; i < strlen(topic); i++){ if (i >= 26){ reTopic[i+1] = topic[i]; <em>// RPC应答主题后面加上id</em> } } ledStatus = !ledStatus; snprintf(postStatus, 50, statusTemplate, ledStatus); <em>// 发布应答报文,确认连接 </em> mqttClient.publish(reTopic, (uint8_t *)postStatus, strlen(postStatus)); <em>// 发布属性报文,更新led indicator状态</em> mqttClient.publish(topic3, (uint8_t *)postStatus, strlen(postStatus)); digitalWrite(LED_BUILTIN, !ledStatus); <em>// 改变LED状态</em> } void setup() { pinMode(LED_BUILTIN, OUTPUT); <em>// LED_BUILTIN是ESP8266自带的led灯</em> digitalWrite(LED_BUILTIN, HIGH); Serial.begin(9600); dht.begin(); <em>// 执行DHT库</em> <em>//设置为无线终端模式</em> WiFi.mode(WIFI_STA); <em>// 连接WiFi</em> connectWifi(); <em>// 设置MQTT服务器和端口号</em> mqttClient.setServer(mqttServer, 1883); <em>// 明文模式</em> mqttClient.setCallback(receiveCallback); <em>// 收到报文的回调函数</em> connectMQTTserver(); subscribeTopic(topic2, 0); <em>// 订阅主题</em> } void loop() { humi_read = dht.readHumidity(); <em>// 用dht库读取湿度数据</em> temp_read = dht.readTemperature(); <em>// 用dht库读取温度数据</em> if (isnan(humi_read) || isnan(temp_read)) <em>// 如果数据有缺失</em> { Serial.println("读取温湿度传感器数据失败!"); <em>// 输出信息</em> } else { Serial.print("湿度: "); <em>// 串口输出湿度</em> Serial.print(humi_read); Serial.println(" %"); Serial.print("温度: "); <em>// 串口输出温度</em> Serial.print(temp_read); Serial.println(" ℃"); } <em>// 如果MQTT未连接,则尝试连接服务器</em> if (!mqttClient.connected()) { connectMQTTserver(); } <em>// 保持心跳</em> mqttClient.loop(); <em>// 格式化json串,把reportTimes, temp_read, humi_read三个数据放入字符串模板dataTemplate,取前100个字节(全部)赋值给postData</em> snprintf(postData, 50, dataTemplate, temp_read, humi_read, reportTimes); <em>// 10秒发送一次数据</em> long now = millis(); if (now - lastMsg > 10000) { reportTimes++; lastMsg = now; Serial.print("报文信息: "); Serial.println(postData); mqttClient.publish(topic1, (uint8_t *)postData, strlen(postData)); } delay(500); } |
近期评论