31
33

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ESP8266でIDCF Cloudにつなぐ

Last updated at Posted at 2015-09-10

イントロダクション

既に多くの方が記事を書いているように、ESP8266はArduino IDEを使って開発することもできます。そこで、IDCF Cloudのチュートリアルである「myThingsをはじめよう」を元に、Raspberry PiではなくESP8266を使ってIDCF Cloudまで接続できるようにしてみました。

参考にした記事はMasato Shimizuさんの「ArduinoからDHT11の温度と湿度データをMQTTを使ってMeshbluに送信する」です。この記事が書かれたのは今年の4月20日なのですが、その後にArduino Client for MQTTは更新され、若干APIが変わりました。また、この記事はArduino Ethernet Shieldを対象に書かれていますが、Arduino Client for MQTTはESP8266でも動作するため、かなりコンパクトかつ安価に実現できます。

プログラミング:ESP8266からBME280環境センサのデータ送信

これは、Arduino Client for MQTTに含まれるサンプルmqtt_publish_in_callbackとMasato Shimizuさんの記事中のサンプルを元にしたものです。BME280を使用するライブラリやサンプルには様々なものがありますが、ここではのEmbedded AdventuresのIan Harris氏によるライブラリを使用しています。

ファイルは2つに分かれています。Wi-FiアクセスポイントやIDCF CloudでのUUIDやトークンなど、各自で変更する必要のあるものはconfig.hという名前で別のタブ(実体はファイル)にして分離しています。

config.h
// MQTTのクライアントID(ユニークにするためにスケッチをコンパイルした日付と時刻を使用)
const char *mqtt_client_id = "kotobuki" __DATE__ __TIME__;

// Wi-FiアクセスポイントのSSIDとパスワード
const char *ssid = "********";
const char *pass = "********";

// IDCF Cloudに関する設定
const char *server = "210-***-***-***.jp-east.compute.idcfcloud.com";
const char* trigger_1_uuid = "********-****-****-****-************";
const char* trigger_1_token = "********";
const char* action_1_uuid = "********-****-****-****-************";
const char* action_2_uuid = "********-****-****-****-************";
IDCF_MQTT_publisher.ino
#include <Wire.h>

#include <ESP8266WiFi.h>

// MQTTを扱うためのライブラリ
// https://github.com/Imroy/pubsubclient
#include <PubSubClient.h>

// BME280を扱うためのライブラリ
// https://github.com/embeddedadventures/BME280
#include <BME280_MOD-1022.h>

#include "config.h"

WiFiClient wclient;

// MQTTクライアント
PubSubClient client(wclient, server);

// 温度と湿度、気圧を格納する変数
float temperature = 0.0;
float humidity = 0.0;
float pressure = 0.0;

// コールバック関数
void callback(const MQTT::Publish& pub) {
  // コールバックで必要な処理があればここで
}

// JSONフォーマットでペイロードを用意
String getPayloadInJson() {
  String json = "{";
  json +=  "\"devices\":";
  json += "[\"";
  json += action_1_uuid;
  json += "\"";
  json += ",";
  json += "\"";
  json += action_2_uuid;
  json += "\"";
  json += "],";
  json += "\"payload\":";
  json += "{";
  json += "\"pressure\":\"";
  json += pressure;
  json += "\",";
  json += "\"humidity\":\"";
  json += humidity;
  json += "\",";
  json += "\"temperature\":\"";
  json += temperature;
  json += "\"}";
  json += "}";

  return json;
}

// 浮動小数点数を小数点以下2桁でシリアルにプリント
void printFormattedFloat(float val) {
  char buffer[10];

  dtostrf(val, 4, 2, buffer);
  Serial.print(buffer);
}

void setup() {
  // IO4: SDA
  // IO14: SCL
  Wire.begin(4, 14);

  Serial.begin(115200);
  delay(10);
  Serial.println();
  Serial.println();

  // BME280の補償値を読み取る
  BME280.readCompensationParams();

  // オーバーサンプリングの回数を設定
  BME280.writeOversamplingTemperature(os1x);
  BME280.writeOversamplingHumidity(os1x);
  BME280.writeOversamplingPressure(os1x);
}

void loop() {
  // Wi-Fiアクセスポイントに接続していなければ接続
  if (WiFi.status() != WL_CONNECTED) {
    Serial.print("Connecting to ");
    Serial.print(ssid);
    Serial.println("...");
    WiFi.begin(ssid, pass);

    if (WiFi.waitForConnectResult() != WL_CONNECTED) {
      Serial.println("Failed");
      return;
    } else {
      Serial.println("WiFi connected");
    }
  }

  // クライアントがICDF Cloudのサーバに接続されていなければ接続
  if (!client.connected()) {
    // トリガー1のUUIDとトークンで認証
    MQTT::Connect mqttConnect(mqtt_client_id);
    mqttConnect.set_auth(trigger_1_uuid, trigger_1_token);

    if (client.connect(mqttConnect)) {
      client.set_callback(callback);
      Serial.println("Client connected");
    } else {
      Serial.println("Client failed to connect");
    }
  }

  // クライアントがICDF Cloudのサーバに接続されていたら以下の処理を実行
  if (client.connected()) {
    // BME280を1度だけ測定を行うモードに設定し計測が終わるまで待機
    BME280.writeMode(smForced);
    while (BME280.isMeasuring()) {
      delay(1);
    }

    // BME280から測定値を読み取る
    BME280.readMeasurements();

    // 温度と湿度、気圧を取得
    temperature = BME280.getTemperature();
    humidity = BME280.getHumidity();
    pressure = BME280.getPressure();

    // 温度と湿度、気圧をシリアルにプリント
    Serial.print("Temperature: ");
    printFormattedFloat(temperature);
    Serial.println();
    Serial.print("Humidity   : ");
    printFormattedFloat(humidity);
    Serial.println();
    Serial.print("Pressure   : ");
    printFormattedFloat(pressure);
    Serial.println();

    // IDCF CloudにMQTTでデータを送信
    bool sent = client.publish("message", getPayloadInJson());
    if (sent) {
      Serial.println("Sent");
    } else {
      Serial.println("Failed to send");
    }

    Serial.println();
  }

  delay(10000);
}

myThingsアプリと接続:myThingsから「IDCF」チャンネルを使う

これは、Arduino Client for MQTTに含まれるサンプルmqtt_subscriberを元にしたものです。オリジナルの記事では、天気・災害のトリガーをfreeboard上で確認するようになっています。このサンプルは受け取ったペイロードをそのままシリアルにプリントしているだけですが、内容に応じてLEDの色を変えて表示する、ディスプレイに文字で表示する、サーボの動きで表現するなど、様々な展開ができると思います。

前のサンプルと同様にファイルは2つに分かれています。Wi-FiアクセスポイントやIDCF CloudでのUUIDやトークンなど、各自で変更する必要のあるものはconfig.hという名前で別のタブ(実体はファイル)にして分離しています。

config.h
// MQTTのクライアントID(ユニークにするためにスケッチをコンパイルした日付と時刻を使用)
const char *mqtt_client_id = "kotobuki" __DATE__ __TIME__;

// Wi-FiアクセスポイントのSSIDとパスワード
const char *ssid =  "********";
const char *pass =  "********";

// IDCF Cloudに関する設定
const char* action_1_uuid = "********-****-****-****-************";
const char* action_1_token = "********";
IPAddress server(210, ***, ***, ***);
IDCF_MQTT_subscriber.ino
#include <ESP8266WiFi.h>
#include <PubSubClient.h>

#include "config.h"

#define BUFFER_SIZE 100

// メッセージを受け取ったらシリアルにプリント
void callback(const MQTT::Publish& pub) {
  Serial.print(pub.topic());
  Serial.print(" => ");
  if (pub.has_stream()) {
    // ペイロードのサイズが大きい場合にはローカルに用意したバッファに分割して読み取り
    // 読み取った単位ごとにシリアルにプリント
    uint8_t buf[BUFFER_SIZE];
    int read;
    while (read = pub.payload_stream()->read(buf, BUFFER_SIZE)) {
      Serial.write(buf, read);
    }
    pub.payload_stream()->stop();
    Serial.println();
  } else {
    // ペイロードのサイズが小さい場合にはそのままシリアルにプリント
    Serial.println(pub.payload_string());
  }
}

WiFiClient wclient;
PubSubClient client(wclient, server);

void setup() {
  Serial.begin(115200);
  delay(10);
  Serial.println();
  Serial.println();
}

void loop() {
  if (WiFi.status() != WL_CONNECTED) {
    Serial.print("Connecting to ");
    Serial.print(ssid);
    Serial.println("...");
    WiFi.begin(ssid, pass);

    if (WiFi.waitForConnectResult() != WL_CONNECTED) {
      return;
    }
    Serial.println("WiFi connected");
  }

  if (!client.connected()) {
    // アクション1のUUIDとトークンをユーザ名およびパスワードとしてサーバに接続
    MQTT::Connect mqttConnect(mqtt_client_id);
    mqttConnect.set_auth(action_1_uuid, action_1_token);

    if (client.connect(mqttConnect)) {
      client.set_callback(callback);
      client.subscribe(action_1_uuid);
    }
  }

  if (client.connected()) {
    client.loop();
  }
}

参照

31
33
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
31
33

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?