皆さん、こんにちは
前回のつづきとしてESP8266からMQTTブローカーに接続し、データを送信する部分の内容ついて説明したいと思います。
今回は温度湿度センサーのDHT11と気圧センサーのBME180を使って気温、湿度、気圧を計測し、1分に1回、MQTTブローカーに送信しています。
ハードウェア
回路図は以下のようにDHT11のDATAピンはGPIO、BMP180のSDA,SCLピンはそれぞれGPIO2,GPIO5に接続しました。
電源は紆余曲折の末、単純にmicro USBから供給し、NodeMCUのボードから出力されている3.3Vをそれぞれのセンサーで使用しています。
今回は外気温を測りたかったので、ケースに入れた方が良いと思いましたが、ブレッドボードだと見合った箱がありませんでした。
そこで、手元にあったユニバーサル基板にESP8266をはんだ付けし、100均で購入した食品保存用の箱に入れてみました。
箱からUSB電源の接続やセンサーとリード線を出す必要がありますので、ニッパで適当に欠きとっています。
センサーは各ピンとリード線をはんだ付けし、熱収縮チューブで覆っています。BMP180の表面はそのままですが...
ソフトウェア
ESP8266のプログラムはArduino IDEを利用し、以下のプログラムを書きこんでいます。
#include <PubSubClient.h>
#include <ESP8266WiFi.h>
#include <Wire.h>
#include <Adafruit_BMP085.h>
#include <DHTesp.h>
// 接続情報
const char *ssid = "**********";
const char *password = "**********";
const char *mqtt_server = "**********";
const int mqtt_port = 8883;
const char *mqtt_user = "mqttclient";
const char *mqtt_pass = "**********";
// 計測間隔 (60秒)
unsigned short interval = 60;
// クライアントID
char clientID[10];
// WiFiオブジェクト
WiFiClientSecure wifiClient;
// MQTTクライアントオブジェクト
PubSubClient mqttClient(wifiClient);
// 温度湿度計オブジェクト
DHTesp dht;
// 気圧計オブジェクト
Adafruit_BMP085 bmp;
void init_wifi();
void init_mqtt();
// センサーからの情報を集める
void collectSensors() {
float humidity = dht.getHumidity();
float temperature = dht.getTemperature();
float pressure = bmp.readPressure();
pressure /= 100;
Serial.print("気温:");
Serial.print(temperature);
Serial.println(" ℃");
Serial.print("湿度:");
Serial.print(humidity);
Serial.println(" %");
Serial.print("気圧:");
Serial.print(pressure);
Serial.println(" hPa");
// トピック名
String topic=String("point/")+String(clientID);
// データ
String str=String(temperature,2);
str += String(",");
str += String(humidity,3);
str += String(",");
str += String(pressure,5);
// MQTTでサーバに送信
mqttClient.publish((char *)topic.c_str(),(char *)str.c_str());
}
// 初期化処理
void setup() {
Serial.begin(115200);
// I2Cプロトコルの初期化
Wire.begin(2,5); // Define(SDA, SCL)
init_wifi();
init_mqtt();
// 温度湿度センサー(DHT11)の初期化(GPIO 13に接続)
dht.setup(13, DHTesp::DHT11);
Serial.println("bmpの初期化(GPIO2[SDA],GPIO5[SCL]");
if (!bmp.begin())
{
Serial.println("Could not find BMP180 sensor at 0x77");
}
}
// WiFiの初期化
void init_wifi() {
Serial.println("init wiri interface");
WiFi.mode(WIFI_STA);
WiFi.begin(ssid,password);
while( WiFi.status() != WL_CONNECTED ) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
}
// MQTTの初期化
void init_mqtt() {
// ClientIDの生成
for (int i = 0; i < 8; i++) {
clientID[i] = random(26)+65;
}
clientID[8]=0;
wifiClient.setInsecure();
mqttClient.setServer(mqtt_server, mqtt_port);
}
// メインループ
void loop() {
// 計測開始時刻を取得
unsigned long st = millis();
if (!mqttClient.connected()) {
reconnect();
}
collectSensors();
// 計測終了時刻を取得
unsigned long ed = millis();
// 計測間隔から計測や転送に要した時間を差し引いた分Waitする
delay(interval * 1000 - ( ed - st ));
}
void reconnect()
{
// Loop until we're reconnected
while (!mqttClient.connected())
{
Serial.print("Attempting MQTT connection...");
// Connect to the MQTT broker
if (mqttClient.connect(clientID,mqtt_user,mqtt_pass))
{
Serial.println("connected");
} else
{
Serial.print("failed, rc=");
Serial.print(mqttClient.state());
Serial.println(" try again in 5 seconds");
delay(5000);
}
}
}
7行目からの接続情報にある各定数の値については以下の通りです。
- ssid ... WiFiに接続する際に使用するSSID
- password ... WiFiに接続する際のパスワード
- mqtt_server ... 前回設定したmosquittoがインストールされているサーバのIPアドレス
- mqtt_port ... mosquittoがListenしているポート番号
- mqtt_user ... mosquittoにアクセスするためのユーザ名
- mqtt_pass ... mosquittoにアクセスするユーザのパスワード
ざっくりとした処理の内容としましては
ESP8266をブートしますと、setup()関数が実行されます。その中でinit_wifi()、init_mqtt()が実行され、WiFiの初期化、MQTTの初期化を行います。
その後、DHT11ならびにBMP180の初期化も行います。BMP180はI2Cプロトコルを使用してESP8266と通信を行いますので、I2Cプロトコルも初期化します。
I2Cプロトコルは2本のピン(SDA,SCL)で通信をおこないますが、今回、
Wire.begin(2,5);
と記載することで、SDAはGPIO2、SCLはGPIO5のピンを指定しています。
初期化が終了しますと、メインループ(loop()関数)が実行されます。
loop()関数ではMQTTの接続状況をチェックし、接続されていなければreconnect()メソッドを実行し再接続を行います。
接続できればcollectSensors()メソッドを実行し、DHT11センサーの温度、湿度とBMP180センサーの気圧を取得、<気温>,<湿度>,<気圧> のフォーマットでメッセージを作成、mqttClient.publish()メソッドでmosquittoにメッセージを送信しています。
次回はIRISでのMQTTメッセージ取得方法について説明します。