基于MQTT协议与ESP8266平台的家庭环境监控实现 | 千里

标签: mqtt 协议 esp8266 | 发表时间:2017-08-20 16:18 | 作者:
出处:http://liangshuang.name

在智能家居的应用场景中,传感器一直是非常重要的组成部分。比如传感器报告的温度高了可以自动关窗开空调。在一般的使用场景中,众多的传感器和开关会分散在房子中的不同位置,通过布线连接是不现实的,理想的情况当然是通过已有的无线网络进行连接,网络传输就需要特定的协议,MQTT协议就是一个不错的选择。

手头刚好有一些传感器和一个ESP8266芯片的单片机(WeMos D1),做了一个家庭温湿度、光照及空气质量监控器,并通过MQTT协议推送数据到Home Assistant平台。

MQTT

MQTT(Message Queue Telemetry Transport)是一个基于TCP/IP协议的轻量级的发布/订阅消息通讯协议,其最初就是设计来适应嵌入式设备通讯中遇到的硬件计算能力有限,网络带宽低且不可靠等问题,因此它具有开销小(固定长度的头部只有2字节)及异常中断处理等特性。它在IoT领域被大量的应用,尤其在传感器的监测数据推送方面。如Amazon IoT、Microsoft Azure IoT Hub等都把MQTT做为其主要支持的协议。

MQTT需要一个Broker服务器才可以正常工作,我选择了一个开源的MQTT服务器EMQ,可以通过Docker来部署:

1
docker run -d --name=emq -d -p 18083:18083 -p 1883:1883 -p 8083:8083 -p 8443:8443 --restart=always devicexx/emqttd

硬件

下边是硬件的BOM,价格是我购买时的淘宝价:

硬件价格说明
WeMos D1¥16.5支持Wifi的单片机,可以使用Arduino的IDE进行开发
DHT22¥13.7可能是使用最广泛的温湿度模块之一,测量结果准确
Arduino光敏电阻模块¥3.49量程较短,弱光测量效果不理想
攀藤科技G5¥130淘宝上能找到的比较靠谱的空气质量传感器

装起来就是这个样子的:

IMG_9566.JPG

下边是代码:

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
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
#include<Arduino.h>
#include<SoftwareSerial.h>
#include<ESP8266WiFi.h>
#include<MQTTClient.h>
#include<Adafruit_Sensor.h>
#include<DHT.h>
#include<DHT_U.h>
WiFiClient net;
MQTTClient client;
// DHT22传感器连在Pin D4
DHT_Unifieddht(D4, DHT22);
// 攀藤科技G5使用serial连接,这里使用Pin D1与D2做Software Serial
SoftwareSerialpmSerial(D1, D2);
constcharssid[] ="你的WIFI网络名称";
constcharpass[] ="你的WIFI密码";
#defineLENG 31//0x42 + 31 bytes equal to 32 bytes
unsignedcharbuf[LENG];
intPM01Value =0;// PM1值
intPM2_5Value =0;// PM2.5值
intPM10Value =0;// PM10值
unsignedlonglastMillis =0;
voidconnect();// <- predefine connect() for setup()
voidsetup(){
Serial.begin(115200);
pmSerial.begin(9600);
pmSerial.setTimeout(1500);
dht.begin();
sensor_tsensor;
dht.temperature().getSensor(&sensor);
Serial.println("------------------------------------");
Serial.println("Temperature");
Serial.print ("Sensor: "); Serial.println(sensor.name);
Serial.print ("Driver Ver: "); Serial.println(sensor.version);
Serial.print ("Unique ID: "); Serial.println(sensor.sensor_id);
Serial.print ("Max Value: "); Serial.print(sensor.max_value); Serial.println(" *C");
Serial.print ("Min Value: "); Serial.print(sensor.min_value); Serial.println(" *C");
Serial.print ("Resolution: "); Serial.print(sensor.resolution); Serial.println(" *C");
Serial.println("------------------------------------");
// Print humidity sensor details.
dht.humidity().getSensor(&sensor);
Serial.println("------------------------------------");
Serial.println("Humidity");
Serial.print ("Sensor: "); Serial.println(sensor.name);
Serial.print ("Driver Ver: "); Serial.println(sensor.version);
Serial.print ("Unique ID: "); Serial.println(sensor.sensor_id);
Serial.print ("Max Value: "); Serial.print(sensor.max_value); Serial.println("%");
Serial.print ("Min Value: "); Serial.print(sensor.min_value); Serial.println("%");
Serial.print ("Resolution: "); Serial.print(sensor.resolution); Serial.println("%");
Serial.println("------------------------------------");
WiFi.begin(ssid, pass);
// Note: Local domain names (e.g. "Computer.local" on OSX) are not supported by Arduino.
// You need to set the IP address directly.
client.begin("MQTT服务器地址", net);
client.onMessage(messageReceived);
connect();
}
voidconnect(){
Serial.print("checking wifi...");
while(WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(1000);
}
Serial.print("\nconnecting...");
while(!client.connect("arduino","try","try")) {
Serial.print(".");
delay(1000);
}
Serial.println("\nconnected!");
// 这里可以订阅自己发布的消息,调试用
// client.subscribe("/home/livingroom/brightness");
// client.subscribe("/home/livingroom/temperature");
// client.subscribe("/home/livingroom/humidity");
// client.subscribe("/home/livingroom/air");
}
voidloop(){
client.loop();
delay(10);// <- fixes some issues with WiFi stability
if(!client.connected()) {
connect();
}
// 每5秒推送一次状态
if(millis() - lastMillis >5000) {
lastMillis = millis();
client.publish("/home/livingroom/brightness","{\"value\": "+ String(1024- analogRead(A0)) +"}");
sensors_event_tevent;
dht.temperature().getEvent(&event);
if(isnan(event.temperature)) {
Serial.println("Error reading temperature!");
}
else{
client.publish("/home/livingroom/temperature","{\"value\": "+ String(event.temperature) +"}");
}
// Get humidity event and print its value.
dht.humidity().getEvent(&event);
if(isnan(event.relative_humidity)) {
Serial.println("Error reading humidity!");
}
else{
client.publish("/home/livingroom/humidity","{\"value\": "+ String(event.relative_humidity) +"}");
}
if(pmSerial.find(0x42)) {//start to read when detect 0x42
pmSerial.readBytes(buf, LENG);
if(buf[0] ==0x4d) {
if(checkValue(buf, LENG)) {
PM01Value = transmitPM01(buf);//count PM1.0 value of the air detector module
PM2_5Value = transmitPM2_5(buf);//count PM2.5 value of the air detector module
PM10Value = transmitPM10(buf);//count PM10 value of the air detector module
client.publish("/home/livingroom/air","{\"pm1\":"+ String(PM01Value) +", \"pm25\": "+ String(PM2_5Value) +", \"pm10\": "+ String(PM10Value) +"}");
}
}
}
}
}
voidmessageReceived(String &topic, String &payload){
Serial.println("incoming: "+ topic +" - "+ payload);
}
charcheckValue(unsignedchar*thebuf,charleng)
{
charreceiveflag =0;
intreceiveSum =0;
for(inti =0; i < (leng -2); i++) {
receiveSum = receiveSum + thebuf[i];
}
receiveSum = receiveSum +0x42;
if(receiveSum == ((thebuf[leng -2] <<8) + thebuf[leng -1]))//check the serial data
{
receiveSum =0;
receiveflag =1;
}
returnreceiveflag;
}
inttransmitPM01(unsignedchar*thebuf)
{
intPM01Val;
PM01Val = ((thebuf[3] <<8) + thebuf[4]);//count PM1.0 value of the air detector module
returnPM01Val;
}
inttransmitPM2_5(unsignedchar*thebuf)
{
intPM2_5Val;
PM2_5Val = ((thebuf[5] <<8) + thebuf[6]);//count PM2.5 value of the air detector module
returnPM2_5Val;
}
inttransmitPM10(unsignedchar*thebuf)
{
intPM10Val;
PM10Val = ((thebuf[7] <<8) + thebuf[8]);//count PM10 value of the air detector module
returnPM10Val;
}

编译烧录还需要在Arduino IDE的库管器中安装下边的库:

  • Adafruit Unified Sensor
  • DHT sensor library
  • MQTT

Home Assistant

关于Home Assistant介绍与安装可以参考使用Docker安装Home Bridge与Home Assistant,用Siri控制智能家居

Home Assistant的配置如下,需要替换“MQTT服务器的IP地址”为真实的服务器地址:

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
homeassistant:
customize:
sensor.brightness_sensor:
friendly_name:'光照强度'
sensor.temperature_sensor:
friendly_name:'室内温度'
sensor.humidity_sensor:
friendly_name:'室内湿度'
sensor.pm1_sensor:
friendly_name:'PM1.0'
sensor.pm25_sensor:
friendly_name:'PM2.5'
sensor.pm10_sensor:
friendly_name:'PM10'
mqtt:
broker:MQTT服务器的IP地址
discovery:true
discovery_prefix:homeassistant
birth_message:
topic:'hass/status'
payload:'online'
will_message:
topic:'hass/status'
payload:'offline'
sensor:
- platform:mqtt
name:"Brightness Sensor"
state_topic:"/home/livingroom/brightness"
value_template:"{{ value_json.value }}"
- platform:mqtt
name:"Temperature Sensor"
state_topic:"/home/livingroom/temperature"
unit_of_measurement:"°C"
value_template:"{{ value_json.value }}"
- platform:mqtt
name:"Humidity Sensor"
state_topic:"/home/livingroom/humidity"
unit_of_measurement:"%"
value_template:"{{ value_json.value }}"
- platform:mqtt
name:"PM1 Sensor"
state_topic:"/home/livingroom/air"
unit_of_measurement:"ug/m3"
value_template:"{{ value_json.pm1 }}"
- platform:mqtt
name:"PM2.5 Sensor"
state_topic:"/home/livingroom/air"
unit_of_measurement:"ug/m3"
value_template:"{{ value_json.pm25 }}"
- platform:mqtt
name:"PM10 Sensor"
state_topic:"/home/livingroom/air"
unit_of_measurement:"ug/m3"
value_template:"{{ value_json.pm10 }}"

在Home Assistant中看到的效果是这样的:

IMG_0942.PNG

参考

相关 [mqtt 协议 esp8266] 推荐:

基于MQTT协议与ESP8266平台的家庭环境监控实现 | 千里

- -
在智能家居的应用场景中,传感器一直是非常重要的组成部分. 比如传感器报告的温度高了可以自动关窗开空调. 在一般的使用场景中,众多的传感器和开关会分散在房子中的不同位置,通过布线连接是不现实的,理想的情况当然是通过已有的无线网络进行连接,网络传输就需要特定的协议,MQTT协议就是一个不错的选择. 手头刚好有一些传感器和一个ESP8266芯片的单片机(WeMos D1),做了一个家庭温湿度、光照及空气质量监控器,并通过MQTT协议推送数据到Home Assistant平台.

MQTT协议 - 安全问题

- - ITeye博客
        物联网的核心是连接万物,通过交换并分析数据使得生活更舒适与便捷. 不过,敏感数据泄露或者设备被非法控制可不是闹着玩的. 比如前段时间国内某著名家电企业的智能洗衣机,使用了某著名电商基于XMPP协议的物联网平台,不费吹灰之力便被黑客攻破并远程遥控,给智能家居的发展带来了一些阴影. 究其本质,并不是物联网技术本身有缺陷,而是在物联网系统的设计中最基本的安全设计被工程师轻视了,才导致整个系统的崩塌.

MQTT协议笔记之mqtt.io项目TCP协议支持

- - BlogJava-首页技术区
MQTT定义了物联网传输协议,其标准倾向于原始TCP实现. 构建于TCP的上层协议堆栈,诸如HTTP等,在空间上多了一些处理路径,稍微耗费了CPU和内存,虽看似微乎其微,但对很多处理能力不足的嵌入式设备而言,选择原始的TCP却是最好的选择. 但单纯TCP不是所有物件联网的最佳选择,提供构建与TCP基础之上的传统的HTTP通信支持,尤其是浏览器、性能富裕的桌面涉及领域,还是企业最 可信赖、最可控的传输方式之一.

XMPP协议、MQTT协议、HTTP协议、CoAP协议的基本比较

- - ITeye博客
一、先看下相关国外的专业数据对四大协议的比较:.           XML的解析对于嵌入多设备来说是比较痛苦的 ,所以在嵌入设备上做开发的时候,最好不要选择基于XML的协议.          二、四大协议的基本介绍:.    XMPP是一种基于标准通用标记语言的子集XML的协议,它继承了在XML环境中灵活的发展性.

网络抓包学MQTT物联网协议

- -
MQTT (Message Queue Telemetry Transport),翻译成中文就是,遥测传输协议,其主要提供了订阅/发布两种消息模式,更为简约、轻量,易于使用,特别适合于受限环境(带宽低、网络延迟高、网络通信不稳定)的消息分发,属于物联网(Internet of Thing)的一个标准传输协议.

互联网推送服务原理:长连接+心跳机制(MQTT协议)

- - 移动开发 - ITeye博客
互联网推送消息的方式很常见,特别是移动互联网上,手机每天都能收到好多推送消息,经过研究发现,这些推送服务的原理都是维护一个长连接(要不不可能达到实时效果),但普通的socket连接对服务器的消耗太大了,所以才会出现像MQTT这种轻量级低消耗的协议来维护长连接,那么要如何维护长连接呢:.        在写之前,我们首先了解一下为什么android维护长连接需要心跳机制,首先我们知道,维护任何一个长连接都需要心跳机制,客户端发送一个心跳给服务器,服务器给客户端一个心跳应答,这样就形成客户端服务器的一次完整的握手,这个握手是让双方都知道他们之间的连接是没有断开,客户端是在线的.

activeMQ 推送之mqtt客户端

- - ITeye博客
使用activeMQ进行android推送. activeMQ下载地址:http://activemq.apache.org/download.html. 下载后是一个压缩包:apache-activemq-5.9.0-bin.zip. 解压缩,进入apache-activemq-5.9.0-bin\apache-activemq-5.9.0\bin,双击activemq.bat,即可启动activeMQ服务.

Android推送方案分析(MQTT/XMPP/GCM)

- - 移动开发 - ITeye博客
本文主旨在于,对目前Android平台上最主流的几种消息推送方案进行分析和对比,比较客观地反映出这些推送方案的优缺点,帮助大家选择最合适的实施方案. 方案1、使用GCM服务(Google Cloud Messaging). 简介:Google推出的云消息服务,即第二代的C2DM. 优点:Google提供的服务、原生、简单,无需实现和部署服务端.

使用ActiveMQ+MQTT实现Android点对点消息通知-转载

- - 开源软件 - ITeye博客
ActiveMQ使用MQTT协议,加上android上的paho包,即可简单实现消息通知功能,但是mqtt协议只支持topic,而且不能用selector,使得点对点的消息投递变成问题. 1、每个clientId,建一个topic...这个办法对解决消息点对点投递非常有效,但是有两个大问题:. 随着用户数增多,topic数量增多,对管理性要求增大,对内存的管理也有问题.

MQTT 3.1.1,值得升级的6个新特性

- - BlogJava-首页技术区
以前看英文文章或资料,看完之后,摘要或者忘记. 这一次选择感兴趣的MQTT 3.1.1介绍文章资料,引文见文末,作为练手;非完全翻译,去除掉一些广告性描述,若侵权,请告知. 在沉寂了四年之后, QTT 3.1.1规范于2014年10月30号正式发布,与此同时MQTT 3.1.1已成为OASIS(结构化信息标准促进组织)开放物联网消息传递协议标准( 连接1 连接2),换种说法就是MQTT 3.1.1已升级为国际物联网标准.