在這個項目中,我同時用了 Arduino Pro Mini 和 Esp12E 模塊。Arduino 與 ESP12E 通過串口通信,ESP12E 與樹莓派同一個 WiFi 。
ESP12E 模塊已經自帶的有 數字輸入/輸出 口和模擬輸入口,為什麼還要用 Arduino? 因為我這裡使用的感測器模擬量輸入口需要的太多,ESP12E不夠用。當然如果 Arduino 上數字量埠不夠用的話,還可以用 ESP12 上的埠去代替。
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 模塊起到的作用是將從串口收到的 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)) {
boolean isOK = client.publish(mqtt_topic, String(strRecv).c_str(), true);
Serial.println(isOK);
strRecv = ""; newDataComing = false; } } }
程序下載完成後,將 Arduino 的 D8 (程序中定義 #define WIFI_RX 8 )接在ESP12E 的 TX 引腳上,將 Arduino 的 D9 (程序中定義 #define WIFI_TX 9)接在 ESP12E 的 RX 引腳上。注意:兩者之間是通過串口通信,所以兩者的供電一定要共地。
#define WIFI_RX 8
#define WIFI_TX 9
將 Arduino 和 ESP12E 所有的線都接好,連接 WiFi 就可以看到樹莓派上相應的感測器會有相應的值變化。
TAG:Arduino | MQTT | 科技 |