前言
在這個項目中地梨,我同時用了 Arduino Pro Mini 和 Esp12E 模塊。Arduino 與 ESP12E 通過串口通信缔恳,ESP12E 與樹莓派同一個 WiFi 宝剖。
ESP12E 模塊已經(jīng)自帶的有 數(shù)字輸入/輸出 口和模擬輸入口,為什么還要用 Arduino褐耳? 因為我這里使用的傳感器模擬量輸入口需要的太多诈闺,ESP12E不夠用。當(dāng)然如果 Arduino 上數(shù)字量端口不夠用的話铃芦,還可以用 ESP12 上的端口去代替雅镊。
Arduino Pro MiNi
Arduino 在這里起到的作用是傳感器信號的收集,Arduino 將所有傳感器信號收集到一起刃滓,然后組合成 Json 格式的字符串仁烹,通過串口發(fā)送給 ESP12 模塊。
這里默認(rèn)你已經(jīng)會使用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
// 初始連接在單總線上的單總線設(shè)備
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);
//火焰?zhèn)鞲衅?狀態(tài)
FireStatus = digitalRead(Fire_DI);
switch (FireStatus)
{
case 1:
JsonData.replace("FIRE_STATE", "Safety");
break;
case 0:
JsonData.replace("FIRE_STATE", "Fired");
break;
}
delay(2);
//火焰?zhèn)鞲衅?紅外值
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);
}
//開關(guān)燈設(shè)備寫在這里
}
ps: 不要吐槽我就用了兩個模擬量砰诵,還有兩個設(shè)備走的是 I2C 征唬,我在測試的時候還有其他的傳感器,最終沒有加(放在室內(nèi)的設(shè)備加個雨水傳感器總覺得怪怪的)茁彭。
Arduino 的程序其實很簡單总寒,就是讀取傳感器,將傳感器的值通過串口發(fā)送理肺,這里將傳感器的值替換到 Json 的字符串中用的是replace 函數(shù)摄闸,這個函數(shù)的效率不太高善镰,當(dāng)然用其他方式也是可以的,只不過這個方式比較簡單年枕。
通過程序可以看到炫欺,這里傳感器的值每隔 1 秒給 ESP12E 模塊發(fā)送一次。這個同步的頻率對于我來說是可以接受的熏兄,當(dāng)然再快也是可以的品洛,只不過可能給ESP12E 的程序處理帶來一定的麻煩,因為 ESP12E 的程序?qū)懙囊埠芎唵巍?/p>
ESP12E
在這里 ESP12E 模塊起到的作用是將從串口收到的 Arduino 數(shù)據(jù)霍弹,通過 WiFi 發(fā)送給樹莓派 毫别。因為在這里 Arduino 上的設(shè)備都是傳感器,沒有執(zhí)行機構(gòu)典格,所以這里的程序中只有發(fā)送岛宦,沒有寫相關(guān)的接收函數(shù)。(帶執(zhí)行機構(gòu)的 Arduino 和樹莓派程序耍缴,將會在隨后完成砾肺,敬請期待。)
以下是我的 ESP12E 的程序:
#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#define wifi_ssid "MyWiFi_SSID"
#define wifi_password "WIFI_Psssword"
#define mqtt_server "Raspberry_IpAddress" #這里建議將 樹莓派設(shè)置為固定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 就可以看到樹莓派上相應(yīng)的傳感器會有相應(yīng)的值變化番官。