飘易博客(作者:Flymorn)
订阅《飘易博客》RSS,第一时间查看最新文章!
飘易首页 | 留言本 | 关于我 | 订阅Feed

智能硬件之DIY空气监测仪+自建平台+APP

Author:飘易 Source:飘易
Categories:物联网 PostTime:2020-3-26 14:44:34
正 文:

飘易很久之前就有个想法,自己DIY一套空气质量检测仪,可以实时监测空气的温度、湿度、CO2、TVOC、甲醛、PM2.5等,并通过云端实时记录这些传感器的值,然后通过APP可以方便的查看历史记录,并且通过APP远程控制智能设备上的一些设备比如继电器、电机、全彩LED灯等。


然后2020年春节遇上新冠疫情,得以空出一些时间,飘易就把这个想法落地,开始实施这个空气质量检测仪的DIY方案。


先简单展示一下初步的成果吧。


面包板上的接线:


万用板上焊接的:

板子右下角预留的空白地方是留给日后焊接其他元器件用的。


手机APP里的控制界面:


下面我就大概的分几个方面来说,硬件端 、平台端、APP端来说说这样的智能硬件项目怎样去一步步的实现它。


一、硬件端

需要的硬件列表(总费用大约200多元):

  • MEGA 2560单片机(或2560 PRO)

  • ESP8266-12S wifi模组

  • 0.96寸OLED液晶显示屏或LCD1602

  • 按键一组

  • 温湿度传感器:广州奥松DHT11

  • CO2&TVOC传感器: 瑞士Sensirion盛思锐 SGP30 (或者瑞典SenseAir森尔CO2二氧化碳传感器 S8-0053,小米新风机用的这款)

  • 甲醛传感器: 英国达特WZ-S(或者国产炜盛ZE08-CH2O,小米有品众筹的霍尼韦尔甲醛监测仪用的是这个传感器)

  • PM2.5传感器: 日本夏普GP2Y1014AU0F(或者攀藤PM2S-3 PM2.5激光粉尘传感器,小米新风机用的这款)

  • 若干杜邦线

  • 1-2块面包板或万用板
           


1、单片机MEGA 2560

单片机是核心,所有的传感器都归集到MCU这里集中处理。Arduino mega 2560 有2款,一款是 2560(下图左边的板子),还有一款是 贴片版的2560 PRO(下图右边的板子)

怎么选择呢?如果你是打算通过面包板来连接电路的话,那么就选择左边的2560,一般淘宝上有很多卖家在卖的是Arduino MEGA2560 R3改进CH340G 兼容版本,这是国产的板子,一般创客试验可以买这种的。


如果你是打算把电路焊在洞洞板(万用板)上,那么就购买右侧的mega 2560 pro贴片版本,可以直接焊在洞洞板上,缩小体积。


2560 和 2560 PRO 的区别就是一些引脚的区别,功能基本一样,PRO少了一对IIC引脚,只有一组(D20/D21),而2560有2组IIC引脚,但是对于PRO来说,iic是支持多个设备并联的,因此我们可以把多个设备直接接到这个IIC引脚上,通过不同的地址来区分设备即可。


这是一块以ATmega2560为核心的微控制器开发板,本身具有54组数字I/O input/output端(其中14组可做PWM输出),16组模拟比输入端,4组UART(hardware serial ports),使用16 MHz crystal oscillator。由于具有bootloader,因此能夠通过USB直接下载程序而不需经过其他外部烧写器。供电部份可选择由USB直接提供电源,或者使用AC-to-DC adapter及电池作为外部供电。


下面是2560 PRO 的引脚说明:


2、ESP8266-12S WIFI模组

wifi模组买到手,先刷固件版本到1.6.2,提高下稳定性,关于如何刷固件,可以参考飘易的这篇:乐鑫ESP8266-12S刷固件1.7版本的正确姿势  以及这篇 乐鑫ESP8266烧录固件、升级最新固件、刷MQTT固件 。


刷好了AT固件后,就可以把WIFI模组连接到MCU上去了,我们只需要连接4个线:

RX
TX
VCC
GND


其他线不用连接,除此之外,我们需要设计一个配网按键,当用户按下这个配网按键后,MCU通过AT指令给wifi模组发送配网指令:

//启动smartconfig,支持ESP-Touch和Airkiss智能配网
AT+CWSTARTSMART=3

具体的可以参考:Arduino利用AT指令连接乐鑫ESP8266实现串口通讯、配网



3、0.96 英寸 OLED 液晶显示屏

图片就是下面的这种:

引脚定义:

GND: 接地
VCC: 3.3-5V
SCL: 串行时钟
SDA: 串行数据


如何编程:

#include "U8glib.h"
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE | U8G_I2C_OPT_DEV_0); // I2C / TWI

// OLED显示,每行16字,共5行,超过80字符不显示
void oledShow(String s) {
  //u8g.setFont(u8g_font_unifont);// 每行16字母,高10px
  int l = s.length();
  int lineTotal = l / 16;// 共几行
  if (l % 16) lineTotal++;
  String ss = "";
  u8g.firstPage();
  do {
    for (int i = 0; i < lineTotal; i++)
    {
      if(i >= 5) break;
      ss = s.substring(i * 16, i * 16 + 16);
      u8g.setPrintPos(0, (i + 1) * 10 + i * 3);// 坐标,行高10px,行间距3px
      u8g.print(ss);
    }
  } while (u8g.nextPage());
}

void setup(void) {
  u8g.setFont(u8g_font_8x13B);//u8g_font_unifont 高10px
}

在需要显示的地方,直接调用

oledShow(F("TEMP:25.00"));

就可以了。


但是,OLED屏在写入数据的时候,会发出滋滋的电流声,这种声音我个人听上去会感觉非常的不舒服,虽然不是很响,但是你调试设备,放在键盘附近的话,这个电流声还是很扰人的。如果你也讨厌这种吱吱的电流声,可以使用LCD屏幕,比如LCD1602,LCD是非常安静的。


4、DHT11温湿度传感器

DHT11是比较成熟的一种温湿度传感器了。淘宝搜一下一大堆,图片像下面的这种:

引脚定义:

VCC   → 3.3V/5V电源正极
GND   →电源负极
DATA  →单片机IO口


如何编程?

直接引用 arduino IDE 库 

#include <DHT.h>

// 获取温湿度
void getTempHumi()
{
  // 读取温度或湿度需要约250ms
  float t = dht.readTemperature();// 温度
  float h = dht.readHumidity();// 湿度
  // 检查是否读取失败
  if (isnan(h) || isnan(t)) {
    Serial.println(F("Failed to read from DHT sensor!"));
    return;
  }
  temp = String(t);
  humi = String(h);
}



5、CO2&TVOC传感器 SGP30

CO2和TVOC的采集我们使用SGP30传感器

这个传感器一般的价格是在50元上下,各位可以自行淘宝下。


SGP30是一款单一芯片上具有多个传感元件的金属氧化物气体传感器,内集成4个气体传感元件,具有完全校准的空气质量输出信号。另外,SGP易于集成,能够将金属氧化物气体传感器集成到移动设备中,为智能家居、家电和物联网应用中的环境监测开辟了新的可能性。


SGP30模块规格:

工作电源电压: 1.8V-5V

功耗:40MA

尺寸: 12 mm x 12 mm x 1.6 mm

接口类型: I2C


如何编程?

我们可以引用Adafruit_SGP30库,里面提供了一些例子,可以从例子里改写程序:

#include "Adafruit_SGP30.h"

/* SGP30传感器 温湿度补偿 - return absolute humidity [mg/m^3] with approximation formula
  @param temperature [°C]
  @param humidity [%RH]
*/
uint32_t getAbsoluteHumidity(float temperature, float humidity) {
  // approximation formula from Sensirion SGP30 Driver Integration chapter 3.15
  const float absoluteHumidity = 216.7f * ((humidity / 100.0f) * 6.112f * exp((17.62f * temperature) / (243.12f + temperature)) / (273.15f + temperature)); // [g/m^3]
  const uint32_t absoluteHumidityScaled = static_cast<uint32_t>(1000.0f * absoluteHumidity); // [mg/m^3]
  return absoluteHumidityScaled;
}

// 获取CO2 & TVOC
void getCo2Tvoc(float temperature, float humidity)
{
  // 温湿度补偿 - If you have a temperature / humidity sensor, you can set the absolute humidity to enable the humditiy compensation for the air quality signals
  //float temperature = 22.1; // [°C]
  //float humidity = 45.2; // [%RH]
  sgp.setHumidity(getAbsoluteHumidity(temperature, humidity));

  if (! sgp.IAQmeasure()) {
    Serial.println("Measurement failed");
    return;
  }
  CO2 = sgp.eCO2;// 单位ppm
  TVOC = sgp.TVOC;// 单位ppb
}



6、甲醛传感器 D-art WZ-S

甲醛传感器,飘易使用的英国达特的wz-s,这个是带ph2.0 连接线的,还有另外一款是 wz-s-k,这个是插针版本的。这2款的技术指标是一样的,只是对外的引脚方式不同而已。大家可以根据需要自行选择合适的传感器。

WZ-S 型甲醛检测模组是全球甲醛检测专家——英国达特公司的最新力作,采用 升级版达特甲醛传感器结合先进的微检测技术,直接将环境中的甲醛含量转换成 浓度值,标准化数字输出,便于客户集成使用。WZ-S 型甲醛检测模组经过严格 的工厂校准,可直接应用于您的检测体系中。


技术指标如下:

wz-s和单片机通讯是采用串口通讯的,我们只要接四个线就可以了:

VCC
GND
RX
TX

通讯串口协议:


通讯分主动上传和问答式,出厂默认为主动上传,每隔 1 秒发送 1 次浓度值。


飘易采用问答式。切换到问答式,命令行格式如下:


如何编程?

// 获取甲醛
void getCH2O()
{
  int flag_end = false;
  int flag_start = false;
  int count = 0;
  byte buffer[9] = {};
  for (int i = 0; i < 9; i++) {
    CH2OSerial.write(Ask_code[i]);//在问答模式下请求数据
  }
  sleep(10);
  // 读取
  while (flag_end == false)
  {
    if (CH2OSerial.available() > 0) {//接收到数据
      byte inChar = CH2OSerial.read();
      buffer[count] = inChar;
      if (buffer[count] == 0xFF) { //接收到起始标志
        count = 0;
        flag_start = true;
      }
      count++;
      if (count >= 9 ) { //接收9个byte数据
        count = 0;
        if (flag_start) {
          // 校验 且 命令号是 0X86
          if (buffer[8] == FucCheckSum(buffer, 9) && buffer[1] == 0x86 ) { //校验
            flag_end = true;
          }
        }
      }
    }
  }
  if (flag_end)
  {
    int h1 = (int)buffer[2] * 256 + (int)buffer[3];// 单位ug/m3,国家标准是80ug/m3(0.08mg/m3)
    //int h2 = (int)buffer[6] * 256 + (int)buffer[7];// 单位ppb
    CH2O = String(h1);
  }
}

// 甲醛校验函数
unsigned char FucCheckSum(unsigned char *i, unsigned char ln) {
  unsigned char j, tempq = 0; i += 1;
  for (j = 0; j < (ln - 2); j++) {
    tempq += *i;
    i++;
  }
  tempq = (~tempq) + 1;
  return (tempq);
}



7、PM2.5传感器 夏普 GP2Y1014AYU0F

PM2.5传感器,飘易目前选用的是日本夏普GP2Y1014AYU0F,这是一款性价比很高的传感器,淘宝上的价格一般在20元左右,它的前一代产品是夏普 GP2Y1010AYU0F,目前已经被1014代替了。这是基于红外的灰尘传感器,如果你希望拥有更高的精确度,可以选用激光类型的传感器。

一般发货清单如下:

1,GP2Y1014AU0F 灰尘传感器(1个)代替已经停产的GP2Y1010AU0F 

2,150ohm的电阻(1个)

3,220uF的电容(1个)

4,6pin连接线(1个)


技术参数:

  • 电源电压:5-7V

  • 工作温度:-10-65摄氏度

  • 消耗电流:20mA最大

  • 最小粒子检出值:0.8微米

  • 灵敏度:0.5V/(0.1mg/m3)

  • 清洁空气中电压:0.9V 典型值

  • 工作温度:-10~65℃

  • 存储温度:-20~80℃

  • 使用寿命:5年

  • 尺寸大小:46mm×30mm×17.6mm

  • 重量大小:15g


这个传感器总共有6口,ph2.0接线,怎么连接呢?

实际接线像下面的这样:

注意LED-VCC引脚需要接一个150欧姆的电阻后再到VCC,同时再接一个220uF的电容再到GND,不能直接接VCC哦。


电压和灰尘之间的关系图:

我们需要根据上面的这个关系图,推导一个传感器输出电压和灰尘浓度之间的关系:

float dustDensity = (0.17 * voltage - 0.1) * 1000; // 单位:ug/m3


编程:

// PM2.5传感器 - 夏普GP2Y1014AU0F
String PM25 = "0";
int dustPin = A1;//粉尘传感器模拟输入引脚
int dustLedPower = 29;//粉尘传感器led数字引脚
int dustDelayTime = 280;//采样时间为280微秒
int dustDelayTime2 = 40;//测量完后脉冲需要继续保持,保持时间为320-280=40
int dustOffTime = 9680;//LED脉冲周期为10毫秒,故此处为10000-320=9680

// 获取PM2.5
void getPm25()
{
  // 10ms采样周期
  digitalWrite(dustLedPower, LOW);
  delayMicroseconds(dustDelayTime);
  float dustVal = analogRead(dustPin);
  delayMicroseconds(dustDelayTime2);
  digitalWrite(dustLedPower, HIGH);
  delayMicroseconds(dustOffTime);
  // 电压
  float voltage = dustVal * (5.0 / 1024);
  // 粉尘密度 0.9v洁净空气,3.6V最大污染-512ug/m3
  float dustDensity = (0.17 * voltage - 0.1) * 1000; // 单位:ug/m3
  if (dustDensity < 0) dustDensity = 0;
  int density = dustDensity * 1.0;// 取整
  //Serial.println(dustDensity);
  PM25 = String(density);
}


8、其他控制

其他还有一些继电器、全彩LED灯(可以实现1600万种颜色变化)、步进电机(正反转、0-100%转速)等设备的远程控制,就不在本篇文章里展开叙述了。



二、平台端

平台端也就是我们的服务器端,该怎么设计呢?


因为我们的终端设备是通过ESP8266 WIFI模组和服务器保持长连接的,因此需要服务器选择支持长链接的的技术实施方案。传统的PHP并不适合用在这样的智能硬件项目里,在java里有大量的实现方案,如果你想采用java来开发服务器端,那么会有很多成熟的套件供你选用。


除了java,我们还可以搭建 MQTT 服务器,参考:源码编译安装EMQX V3.0服务器(MQTT) 以及 EMQX之Kafka插件编译安装 


那么PHP这块还有解决方案吗?可以基于SWOOLE,我们实现长链接。


关于Swoole的并发能力测试《并发10万TCP连接的测试》:


本测试启动10个子进程,发起长连接到Swoole的TCP Server.


由于单台机器的原因,ip_local_port_range的范围是32000-60000。 运行到28000个长连接时,由于local port不够用,无法再继续连接。并发测试中使用4台客户端机器同时连接服务器,每台机器与服务器建立2.8W个TCP连接。TCP Server共维持了11.2W长连接


Swoole使用epoll作为事件轮询,可维持大量TCP连接。只要操作系统的内存足够,就一直可以增加维持的TCP长连接。swoole_server每个连接所占用的内存为220字节,使用数据缓存,如EOF_CHECK/LENGTH_CHECK后可能会增加到每连接8K。


来源:https://wiki.swoole.com/wiki/page/p-c100k.html


服务器和终端设备之间采取TCP长连接,解决了设备和服务器之间的实时通讯 。那么,别忘了,我们还有APP端口,用户在APP上打开页面的时候,需要接收传感器的实时状态,和远程下发控制命令给设备,这又怎么做到呢?也就是如何解决用户(APP)和设备的实时通讯?


幸运的是,swoole也可以方便的创建 websocket 服务器,APP端可以通过websocket和服务器保持长链接,这样即使我们的部分APP页面是基于webview的形式集成的也没关系,html5+js也可以通过 websocket 和服务器保持长链接。


这样,我们只需要在服务器器端做好转发就好了,APP通过websocket下发控制指令的时候先给服务器发送,服务器收到后找到对应的设备,通过TCP长连接转发指令给设备;设备上报状态的时候,先通过TCP上报给服务器,服务器收到后,立即通过websocket再转发给对应的websocket客户端(APP)或h5网页就OK了。


至此,APP(或H5网页) + 服务器 (云端)+ 终端设备 这三者就实现了实时通讯,互联互通了。



三、APP端

APP端我们采用html 5 plus的集成解决方案(标准)。我们分别集成安卓和iOS的离线sdk到我们的app里面。


iOS如何集成离线5+sdk:iOS离线打包5+SDK并编写自定义插件

Android如何集成离线5+SDK:Hbuilder离线打包及蓝牙插件开发Android注意事项 


最重要的是我们需要在APP里面实现为ESP8266 WIFI模组配网的功能,乐鑫已经为我们提供了开源的项目demo了,我们只需要把乐鑫的库离线集成到app里面就OK了。


配网采用 ESPTouch 技术方案。乐鑫自主研发的 ESP-TOUCH 协议采用的是 Smart Config(智能配置)技术来帮助用户将嵌入了 ESP8266EX 的设备连接至 Wi-Fi 网络。用户只需在手机上进行简单操作即可实现智能配置。


步骤描述

1.用户创建任务对象,其中包含参数对象、服务器对象和客户端对象

2.设置超时时间与成功返回设备上限数值

3.获取本地ip地址

4.创建配网对象

5.配网对象包含导向数据对象、主数据对象

6.导向数据对象以固定格式生成,主要用于告知设备解析主数据时的一个参数

7.主数据对象包含:总长度、密码长度、ssid的crckey、bssid的crckey、本机ip地址、密码内容和前面所有数据异或的校验位一个字节

8.如果该ssid是隐藏ssid,则需要在总长度加上ssid的长度,以及主数据对象中包含ssid的数据

9.将导向数据对象和主数据对象,以一定格式转化为两个byte数组

10.使用服务器对象开启监听,设备回复的数据

11.客户端对象开始循环发送导向数据和主数据,导向数据发两秒,主数据发四秒,六秒一个循环,直到收到回复或者超时

12.如果超时还没有成功,则直接返回给用户失败

13.如果服务器对象收到了设备返回的信息,则对比第一个字符与ssid拼接密码的字节长度加9是否相等

14.如果不相等忽略,如果相等则解析出回复数据中的设备bssid和设备ip地址

15.将获取到的所有设备的bssid和ip地址返回给用户

16.清理资源


备注:

1.导向数据实际长度(数据长度+udp+ip层) - 数据长度 = 基准值(udp+ip层)

2.将每个子数据对象变为六个字节的数据后,每两个字节合并成一个uint16的数据并且加上固定值40存起来

3.发送完成导向数据后,每两个字节发送一个包


乐鑫iOS的ESPTouch:https://github.com/EspressifApp/EsptouchForIOS

乐鑫Android的ESPTouch:https://github.com/EspressifApp/EsptouchForAndroid


注意,这一部分需要你同时具备html+js+安卓原生(java)+iOS原生(objective c)的开发能力。


开发完成后,飘易同时发布了安卓版本的app和在苹果app store里上架了这一款应用。


到这里,整个智能硬件项目就可以告一段落了。目前先放在面包板上做演示,这一版本暂时为1.0,后续再用洞洞板把相应的传感器焊接上去。 到时再分享给大家吧。


如果你也有智能硬件的项目,或者希望实现智能硬件 + 平台(云端) + APP(微信或小程序)终端等一整套解决方案,欢迎和我交流哦:

关于飘易:我的个人介绍

关于飘易:我的个人介绍


(END)

作者:飘易
来源:飘易
版权所有。转载时必须以链接形式注明作者和原始出处及本声明。
上一篇:Centos7 防火墙 Firewall 开放端口,查看状态的常用方法
下一篇:乐鑫ESP8266-12S刷固件1.7版本的正确姿势
2条评论 “智能硬件之DIY空气监测仪+自建平台+APP”
1 unfalt
2021-4-13 11:35:29
如何实现成品,量产呢。有这方面的公司或工厂吗?我们是产品采购  可交流 QQ:511970709
2 maligebie
2021-10-19 20:18:19
朋友你好:

受到你文章的启发,目前使用ESP8266刷espeasy来观察wz-s的数值,但是始终都是看不到数据。
想问问你的固件用的是什么?
如果方便的话,能给我回个邮件么?
发表评论
名称(*必填)
邮件(选填)
网站(选填)

记住我,下次回复时不用重新输入个人信息
© 2007-2019 飘易博客 Www.Piaoyi.Org 原创文章版权由飘易所有