前言
在这个项目中,我同时用了 Arduino Pro Mini 和 Esp12E 模块。Arduino 与 ESP12E 通过串口通信,ESP12E 与树莓派同一个 WiFi 。
ESP12E 模块已经自带的有 数字输入/输出 口和模拟输入口,为什么还要用 Arduino? 因为我这里使用的传感器模拟量输入口需要的太多,ESP12E不够用。当然如果 Arduino 上数字量端口不够用的话,还可以用 ESP12 上的端口去代替。
Arduino Pro MiNi
Arduino 在这里起到的作用是传感器信号的收集,Arduino 将所有传感器信号收集到一起,然后组合成 Json 格式的字符串,通过串口发送给 ESP12 模块。
这里默认你已经会使用Arduino读取各种传感器的值,如果不会请在下方留言。
以下是我的 Arduino 程序。
#include <AM2320.h>
#include <SFE_BMP180.h>
#include <Wire.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <SoftwareSerial.h>
#include "SR04.h"
#define Fire_AI 0
#define Brightness_AI 1
#define Fire_DI 2
#define Shock_DI 3
#define TempOnly_DI 4
#define Human1_DI 5
#define HCSR04_TRIG_PIN 6
#define HCSR04_ECHO_PIN 7
#define WIFI_RX 8
#define WIFI_TX 9
// 初始连接在单总线上的单总线设备
OneWire oneWire(TempOnly_DI);
SFE_BMP180 AirPresure;
DallasTemperature DS18B20sensors(&oneWire);
AM2320 Temp_Humi;
SR04 Obstacle = SR04(HCSR04_ECHO_PIN, HCSR04_TRIG_PIN);
SoftwareSerial MySerial(WIFI_RX, WIFI_TX);
float currentTemperature;
int currentBright = 0;
int bodySensor = 0;
int FireStatus = 0;
int FireDegree = 0;
int shockStatus = 0;
long DistanceObstance = 0;
char presureDelayTime;
double presureP, presureT;
long int lastSendTime, Now;
String JsonData = "{\"Temp1\":\"TEMP_VALUE1\",\"Temp2\":\"TEMP_VALUE2\",\"Humidity\":\"HUMI_VALUE\",\"Brightness\":\"BRIGHT_VALUE\",\"Preasure\":\"PREA_VALUE\",\"Atmosphere\":\"ATM_VALUE\",\"Fire\":\"FIRE_VALUE\",\"FireState\":\"FIRE_STATE\",\"BodyState\":\"BODY_STATE\",\"ObjectDistance\":\"DIST_VALUE\",\"ShockState\":\"SHOCK_STATE\"}";
SoftwareSerial mySerial(WIFI_RX, WIFI_TX); // RX, TX
bool lightOn = false;
void setup() {
mySerial.begin(9600);
mySerial.println("Hello, world?");
pinMode(Fire_DI, INPUT);
pinMode(Shock_DI, INPUT);
pinMode(TempOnly_DI, INPUT);
pinMode(Human1_DI, INPUT);
pinMode(HCSR04_TRIG_PIN, OUTPUT);
pinMode(HCSR04_ECHO_PIN, INPUT);
DS18B20sensors.begin();
AirPresure.begin();
Now = millis();
lastSendTime = Now;
}
void loop()
{
Now = millis();
if (Now - lastSendTime > 1000) {
JsonData = "{\"Temp1\":\"TEMP_VALUE1\",\"Temp2\":\"TEMP_VALUE2\",\"Humidity\":\"HUMI_VALUE\",\"Brightness\":\"BRIGHT_VALUE\",\"Preasure\":\"PREA_VALUE\",\"Atmosphere\":\"ATM_VALUE\",\"Fire\":\"FIRE_VALUE\",\"FireState\":\"FIRE_STATE\",\"BodyState\":\"BODY_STATE\",\"ObjectDistance\":\"DIST_VALUE\",\"ShockState\":\"SHOCK_STATE\"}";
//温度传感器
DS18B20sensors.requestTemperatures();
currentTemperature = DS18B20sensors.getTempCByIndex(0);
JsonData.replace("TEMP_VALUE1", String(currentTemperature));
delay(2);
//温湿度传感器
switch (Temp_Humi.Read())
{
case 2:
case 1:
JsonData.replace("TEMP_VALUE2", "CRC faild");
JsonData.replace("HUMI_VALUE", "CRC faild");
break;
case 0:
JsonData.replace("TEMP_VALUE2", String(Temp_Humi.t));
JsonData.replace("HUMI_VALUE", String(Temp_Humi.h));
break;
}
delay(2);
//亮度传感器
currentBright = analogRead(Brightness_AI);
JsonData.replace("BRIGHT_VALUE", String(currentBright));
delay(2);
//人体传感器
bodySensor = digitalRead(Human1_DI);
switch (bodySensor)
{
case 1:
JsonData.replace("BODY_STATE", "Yes");
break;
case 0:
JsonData.replace("BODY_STATE", "No");
break;
}
delay(2);
//距离传感器
DistanceObstance = Obstacle.Distance();
DistanceObstance = DistanceObstance * 10.0;
JsonData.replace("DIST_VALUE", String(DistanceObstance));
delay(2);
//震动传感器
shockStatus = digitalRead(Shock_DI);
switch (shockStatus)
{
case 1:
JsonData.replace("SHOCK_STATE", "Vibrating");
break;
case 0:
JsonData.replace("SHOCK_STATE", "Stable");
break;
}
delay(2);
//火焰传感器 状态
FireStatus = digitalRead(Fire_DI);
switch (FireStatus)
{
case 1:
JsonData.replace("FIRE_STATE", "Safety");
break;
case 0:
JsonData.replace("FIRE_STATE", "Fired");
break;
}
delay(2);
//火焰传感器 红外值
FireDegree = analogRead(Fire_AI);
JsonData.replace("FIRE_VALUE", String(FireDegree));
delay(2);
//大气压
presureDelayTime = AirPresure.startPressure(3);
if (presureDelayTime != 0)
{
delay(presureDelayTime);
presureDelayTime = AirPresure.getPressure(presureP, presureT);
if (presureDelayTime != 0)
{
JsonData.replace("PREA_VALUE", String(presureP));
JsonData.replace("ATM_VALUE", String(presureP / 1000.0));
}
else
{
JsonData.replace("PREA_VALUE", "ERROR");
JsonData.replace("ATM_VALUE", "ERROR");
}
}
else
{
JsonData.replace("PREA_VALUE", "ERROR");
JsonData.replace("ATM_VALUE", "ERROR");
}
delay(2);
mySerial.print(JsonData);
}
//开关灯设备写在这里
}
ps: 不要吐槽我就用了两个模拟量,还有两个设备走的是 I2C ,我在测试的时候还有其他的传感器,最终没有加(放在室内的设备加个雨水传感器总觉得怪怪的)。
Arduino 的程序其实很简单,就是读取传感器,将传感器的值通过串口发送,这里将传感器的值替换到 Json 的字符串中用的是replace 函数,这个函数的效率不太高,当然用其他方式也是可以的,只不过这个方式比较简单。
通过程序可以看到,这里传感器的值每隔 1 秒给 ESP12E 模块发送一次。这个同步的频率对于我来说是可以接受的,当然再快也是可以的,只不过可能给ESP12E 的程序处理带来一定的麻烦,因为 ESP12E 的程序写的也很简单。
ESP12E
在这里 ESP12E 模块起到的作用是将从串口收到的 Arduino 数据,通过 WiFi 发送给树莓派 。因为在这里 Arduino 上的设备都是传感器,没有执行机构,所以这里的程序中只有发送,没有写相关的接收函数。(带执行机构的 Arduino 和树莓派程序,将会在随后完成,敬请期待。)
以下是我的 ESP12E 的程序:
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#define wifi_ssid "MyWiFi_SSID"
#define wifi_password "WIFI_Psssword"
#define mqtt_server "Raspberry_IpAddress" #这里建议将 树莓派设置为固定IP地址
#define mqtt_user "pi" #使用你的 MQTT 用户名
#define mqtt_password "password" //MQTT 密码
#define mqtt_topic "home-assistant/arduino/arduino1"
String strRecv = "";
long now = 0;
long lastRecv = 0;
bool newDataComing = false;
WiFiClient espClient;
PubSubClient client(espClient);
void setup() {
Serial.begin(9600);
setup_wifi();
client.setServer(mqtt_server, 1883);
}
void setup_wifi() {
delay(10);
Serial.println();
Serial.print("Connecting to ");
Serial.println(wifi_ssid);
WiFi.begin(wifi_ssid, wifi_password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print("- ");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void reconnect() {
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
if (client.connect("ESP8266Client", mqtt_user, mqtt_password)) {
Serial.println("connected");
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}
void loop() {
if (!client.connected()) {
reconnect();
}
client.loop();
if (Serial.available() > 0) {
char str = char(Serial.read());
strRecv = strRecv + str;
lastRecv = millis();
newDataComing = true;
delay(2);
}
else {
now = millis();
if ((now - lastRecv > 100) && (newDataComing == true)) {
//Serial.print("recv Data ");
//Serial.print(strRecv);
boolean isOK = client.publish(mqtt_topic, String(strRecv).c_str(), true);
//Serial.print(" send state ");
//
Serial.println(isOK);
strRecv = "";
newDataComing = false;
}
}
}
程序下载完成后,将 Arduino 的 D8 (程序中定义 #define WIFI_RX 8
)接在ESP12E 的 TX 引脚上,将 Arduino 的 D9 (程序中定义 #define WIFI_TX 9
)接在 ESP12E 的 RX 引脚上。注意:两者之间是通过串口通信,所以两者的供电一定要共地。
将 Arduino 和 ESP12E 所有的线都接好,连接 WiFi 就可以看到树莓派上相应的传感器会有相应的值变化。