enebularで値の見えるWebページを作る ~デバイス側~


enebularで値の見えるWebページを作る(http post版)enebularで値の見えるWebページを作る ~enebularからherokuへのデプロイ~の続きの記事になります。

今回、デバイス側はMbedプラットフォームであるFRDM-K64FMulti IoT Boardを使用しました。
enebularで値の見えるWebページを作る(http post版))で書いたプラットフォームと変わってますが、同じプログラムが動作するはずです。)

デバイスのプログラムの準備

K64FはMbedプラットフォームの為、Mbedのオンラインコンパイラ環境でプログラムを作りました。
Web側はhttp postでセンサーの値をアップロードできるようにしたので、http通信が行えるライブラリやJSON型を扱うライブラリ、Multi IoT Boardに搭載されている温度、湿度、気圧センサーのBME280のライブラリを使用します。

mbed-http
picojson
BME280

ここで、問題となるのが、httpsの通信です。
https通信にはルート証明書が必要になります。mbed-httpのライブラリにはルート証明書を取得する処理が無いため、手動で設定する必要があります。

herokuのルート証明書を調べる

センサーの値はenebularで値の見えるWebページを作る ~enebularからherokuへのデプロイ~で行った、heroku上で動作しているフローに対してアップロードします。
そのため、ルート証明書はherokuで使用しているものを調べます。
ルート証明書はブラウザで調べられます。ここでは普段使っているChromeでの調べ方を説明します。
まず、heroku上で動作しているページを開いて、以下の部分をクリックし、証明書を選択します。

ダイアログが表示されるので、証明書のパスのタブを選んで、証明書を選択し、証明書の表示をクリックします。

表示された証明書のダイアログで、詳細のタブからファイルにコピーをクリックします。

証明書のエクスポートウィザードが表示されるので、Base64形式を選び、ダウンロードします。

ダウンロードした証明書をテキストエディタで開き、ちょっと編集をして、ソースコードに貼り付けます。

 デバイスのプログラム

デバイスのプログラムの構成は以下の様にしています。

main_app.jsonはmbed-osの設定項目を定義するファイルになっています。今回のプログラムでは、Wi-Fiの設定を記述しています。


{
    "config": {
        "wifi-ssid": {
            "help": "WiFi SSID",
            "value": "\"SSID\""
        },
        "wifi-password": {
            "help": "WiFi Password",
            "value": "\"PASS\""
        }
    },
    "target_overrides": {
        "*": {
            "platform.stdio-convert-newlines": true,
            "esp8266.provide-default" : true
        }
    }
}

main.cppの内容は以下の様になっています。

#include "mbed.h"
#include "platform/mbed_thread.h"
#include "https_request.h"
#include "BME280.h"
#include "picojson.h"

#define SENSOR_UPDATE_RATE_MS   60000 // 1分おきにセンサーの値をアップロード
#define ID                      1

BME280 sensor(I2C_SDA, I2C_SCL);

const char SSL_CA_PEM[] = "-----BEGIN CERTIFICATE-----\n"
"MIIEsTCCA5mgAwIBAgIQBOHnpNxc8vNtwCtCuF0VnzANBgkqhkiG9w0BAQsFADBs\n"
"MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3\n"
"d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j\n"
"ZSBFViBSb290IENBMB4XDTEzMTAyMjEyMDAwMFoXDTI4MTAyMjEyMDAwMFowcDEL\n"
"MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3\n"
"LmRpZ2ljZXJ0LmNvbTEvMC0GA1UEAxMmRGlnaUNlcnQgU0hBMiBIaWdoIEFzc3Vy\n"
"YW5jZSBTZXJ2ZXIgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC2\n"
"4C/CJAbIbQRf1+8KZAayfSImZRauQkCbztyfn3YHPsMwVYcZuU+UDlqUH1VWtMIC\n"
"Kq/QmO4LQNfE0DtyyBSe75CxEamu0si4QzrZCwvV1ZX1QK/IHe1NnF9Xt4ZQaJn1\n"
"itrSxwUfqJfJ3KSxgoQtxq2lnMcZgqaFD15EWCo3j/018QsIJzJa9buLnqS9UdAn\n"
"4t07QjOjBSjEuyjMmqwrIw14xnvmXnG3Sj4I+4G3FhahnSMSTeXXkgisdaScus0X\n"
"sh5ENWV/UyU50RwKmmMbGZJ0aAo3wsJSSMs5WqK24V3B3aAguCGikyZvFEohQcft\n"
"bZvySC/zA/WiaJJTL17jAgMBAAGjggFJMIIBRTASBgNVHRMBAf8ECDAGAQH/AgEA\n"
"MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIw\n"
"NAYIKwYBBQUHAQEEKDAmMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2Vy\n"
"dC5jb20wSwYDVR0fBEQwQjBAoD6gPIY6aHR0cDovL2NybDQuZGlnaWNlcnQuY29t\n"
"L0RpZ2lDZXJ0SGlnaEFzc3VyYW5jZUVWUm9vdENBLmNybDA9BgNVHSAENjA0MDIG\n"
"BFUdIAAwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQ\n"
"UzAdBgNVHQ4EFgQUUWj/kK8CB3U8zNllZGKiErhZcjswHwYDVR0jBBgwFoAUsT7D\n"
"aQP4v0cB1JgmGggC72NkK8MwDQYJKoZIhvcNAQELBQADggEBABiKlYkD5m3fXPwd\n"
"aOpKj4PWUS+Na0QWnqxj9dJubISZi6qBcYRb7TROsLd5kinMLYBq8I4g4Xmk/gNH\n"
"E+r1hspZcX30BJZr01lYPf7TMSVcGDiEo+afgv2MW5gxTs14nhr9hctJqvIni5ly\n"
"/D6q1UEL2tU2ob8cbkdJf17ZSHwD2f2LSaCYJkJA69aSEaRkCldUxPUd1gJea6zu\n"
"xICaEnL6VpPX/78whQYwvwt/Tv9XBZ0k7YXDK/umdaisLRbvfXknsuvCnQsH6qqF\n"
"0wGjIChBWUMo0oHjqvbsezt3tkBigAVBRQHvFwY+3sAzm2fTYS5yh+Rp/BIAV0Ae\n"
"cPUeybQ=\n"
"-----END CERTIFICATE-----\n";


int main()
{
    WiFiInterface *wifi = WiFiInterface::get_default_instance();
    if (!wifi) {
        printf("ERROR: No WiFiInterface found.\n");
        return -1;
    }

    int ret = wifi->connect(MBED_CONF_APP_WIFI_SSID, MBED_CONF_APP_WIFI_PASSWORD, NSAPI_SECURITY_WPA_WPA2);
    if (ret != 0) {
        printf("\nConnection error: %d\n", ret);
        return -1;
    }

    while (true) {
        picojson::object body_json;
        body_json["id"] = picojson::value((double)ID);
        body_json["temperature"] = picojson::value(sensor.getTemperature());
        body_json["pressure"] = picojson::value(sensor.getPressure());
        body_json["humidity"] = picojson::value(sensor.getHumidity());
        string body = picojson::value(body_json).serialize();
        HttpsRequest* request = new HttpsRequest(wifi, SSL_CA_PEM, HTTP_POST, "https://{herokuのアプリケーション名}.herokuapp.com/push");
        request->set_header("Content-Type", "application/json");
        HttpResponse* http_res = request->send(body.c_str(), body.length());
        delete request;
        thread_sleep_for(SENSOR_UPDATE_RATE_MS);
    }
}

プログラムについて

今回は、Mbed OSのプログラムで書きました。
がっつり宣伝ですが、Mbed OSのプログラミング入門は著書を参照ください。

はじめてのMbed OS 5【前編】: Mbed OS 5で始めるIoTプロトタイピング

とはいえ、プログラミングしないでデバイス側のプログラムを作る方法もあります。
enebularは、デバイスにもフローをデプロイする機能があるので、次回の記事では、enebularで作ったフローがデプロイできるマイコンボード「RAVEN」で紹介したRAVENでデバイス側のプログラムを作ってみたいと思います。