使用 Arduino 通過 MQTT 協(xié)議連接 HomeAssistant -- Arduino端

前言

在這個項目中地梨,我同時用了 Arduino Pro Mini 和 Esp12E 模塊。Arduino 與 ESP12E 通過串口通信缔恳,ESP12E 與樹莓派同一個 WiFi 宝剖。

我使用Arduino Pro Mini 模塊
我使用的ESP12E模塊

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)的值變化番官。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市钢属,隨后出現(xiàn)的幾起案子徘熔,更是在濱河造成了極大的恐慌,老刑警劉巖淆党,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件酷师,死亡現(xiàn)場離奇詭異,居然都是意外死亡染乌,警方通過查閱死者的電腦和手機山孔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來荷憋,“玉大人饱须,你說我怎么就攤上這事√ㄒ辏” “怎么了蓉媳?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長锅铅。 經(jīng)常有香客問我酪呻,道長,這世上最難降的妖魔是什么盐须? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任仰挣,我火速辦了婚禮熔吗,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己赁温,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布胞谈。 她就那樣靜靜地躺著薇宠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪统舀。 梳的紋絲不亂的頭發(fā)上匆骗,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天,我揣著相機與錄音誉简,去河邊找鬼碉就。 笑死,一個胖子當(dāng)著我的面吹牛闷串,可吹牛的內(nèi)容都是我干的瓮钥。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼烹吵,長吁一口氣:“原來是場噩夢啊……” “哼碉熄!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起年叮,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤具被,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后只损,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體一姿,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年跃惫,在試婚紗的時候發(fā)現(xiàn)自己被綠了叮叹。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡爆存,死狀恐怖蛉顽,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情先较,我是刑警寧澤携冤,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布悼粮,位于F島的核電站,受9級特大地震影響曾棕,放射性物質(zhì)發(fā)生泄漏扣猫。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一翘地、第九天 我趴在偏房一處隱蔽的房頂上張望申尤。 院中可真熱鬧,春花似錦衙耕、人聲如沸昧穿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽时鸵。三九已至,卻和暖如春渴杆,著一層夾襖步出監(jiān)牢的瞬間寥枝,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工磁奖, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留囊拜,地道東北人。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓比搭,卻偏偏與公主長得像冠跷,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子身诺,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容