BlynkとAmbientで部屋の温度を見る

published_with_changes 更新日: event_note 公開日:

labelBlynk labelIoT

「アレクサ、部屋の温度を教えて」を実現のための第4歩になります。Blynkを導入した目的はESP8266/32で測定した温度データをAlexaへ送るためですが、Blynkアプリを使ってデータの可視化と妥当性の確認をしておきます。

一例として、天井裏の温度を測定しています。夏の暑いときに、いったい天井裏では何度まで上がっているのだろうと気になったのが、天井裏に温度センサをつけるきっかけでした。

これは2年ほど前に作ったものです。今は新しい白地のBlynkアプリに変わっています。ここで書いている従来のBlynkはLegacy Blynkと呼ばれサポート対象外のようです。さらに、local server やBluetoothがなくなっています。


構成

BME280:BOSCHの基板用温度・湿度・気圧センサー(たぶんもどき)
ESP8266:Wemos D1 mini
5V電源:ACアダプター
Blynk
Ambient

スケッチ

Code Examples Browserの「Example:   Push Data」などを参考にしています。

#define BLYNK_PRINT Serial    // Comment this out to disable prints and save space
#include <ESP8266WiFi.h>
#include <BlynkSimpleEsp8266.h>
#include <BME280_MOD-1022.h>
#include <Wire.h>
#include "Ambient.h"

const char* ssid = "***your ssid***";
const char* password = "***your password***";
char server[] = "192.168.*.**";  // IP for your Local Server
int port = 8080;

//for Blynk
BlynkTimer timer;// Create a Timer object called "timer"

//for Ambient
//#define PERIOD 600 //(sec)Ambientへのデータ送信間隔 ex 600(sec)=10分
int PERIOD = 600 ; //(sec)Ambientへのデータ送信間隔 初期値 ex 600(sec)=10分
unsigned long prev = 0 ; // 前回実行時刻を初期化

unsigned int channelId = ****;//channelId for Ambient
const char* writeKey = "***your writeKey***";//writeKey for Ambient

WiFiClient client;
Ambient ambient;

// You should get Auth Token in the Blynk App.
// Go to the Project Settings (nut icon).
char auth[] = "***your token from Blynk***";

unsigned long lastCheck = 0;
double tempMostAccurate, humidityMostAccurate, pressureMostAccurate, WBGT;
char buff[50];

//変数xを小数点以下precision桁の文字列に変換する
void printFormattedFloat(float x, uint8_t precision) {
  char buffer[10];
  dtostrf(x, 7, precision, buffer);//変数xを7文字の文字列に変換して,bufferに格納。precisionは小数点以下の桁数
  Serial.print(buffer);
}

void setup()
{
  Serial.begin(115200);
  //You can also specify server:
  //Blynk.begin(auth, ssid, pass, "blynk-cloud.com", 80);
  //Blynk.begin(auth, ssid, pass, IPAddress(192,168,1,100), 8080);
  Blynk.begin(auth, ssid, password, server, port);  // Blocking until server connected, Blynk local Server
  Wire.begin(); 

  // need to read the NVM compensation parameters
  BME280.readCompensationParams();
  BME280.writeStandbyTime(tsb_0p5ms);         // tsb = 0.5ms
  BME280.writeFilterCoefficient(fc_16);       // IIR Filter coefficient 16
  BME280.writeOversamplingPressure(os16x);    // pressure x16
  BME280.writeOversamplingTemperature(os2x);  // temperature x2
  BME280.writeOversamplingHumidity(os1x);     // humidity x1
  BME280.writeMode(smNormal);
  
  ambient.begin(channelId, writeKey, &client); // チャネルIDとライトキーを指定してAmbientの初期化

  // Setup a function to be called every 60 seconds
  // サーバーへのデータの送信(書き出し)間隔をミリ秒で指定
  timer.setInterval(60*1000L, myTimerEvent);
}

void myTimerEvent()//for Blynk
{
  tempMostAccurate = BME280.getTemperatureMostAccurate();
  humidityMostAccurate = BME280.getHumidityMostAccurate();
  pressureMostAccurate = BME280.getPressureMostAccurate();

  //今回、作成した暑さ指数近似式:(屋内用)
  WBGT = 0.725*tempMostAccurate + 0.0368*humidityMostAccurate + 0.00364*tempMostAccurate*humidityMostAccurate - 3.246;
    
  Blynk.virtualWrite(V0, tempMostAccurate);
  Blynk.virtualWrite(V1, humidityMostAccurate);
  Blynk.virtualWrite(V2, pressureMostAccurate);
  Blynk.virtualWrite(V4, WBGT);
}

BLYNK_WRITE(V3){
  //スマホ側 Blynk アプリで設定したスライダー値の受信
  int PERIOD_level = param.asInt();
  
  if ( PERIOD_level < 256 ) {PERIOD = 60 ;} //1分周期
  else if ( PERIOD_level >= 256 && PERIOD_level < 512 ) {PERIOD = 600 ;} //10分周期
  else if ( PERIOD_level >= 512 && PERIOD_level < 768 ) {PERIOD = 3600 ;} //1Hr周期
  else if ( PERIOD_level >= 768 && PERIOD_level < 1024) {PERIOD = 10800 ;} //3Hr分周期
 
  Serial.printf("PERIOD_level = %d\r\n", PERIOD_level );
  Serial.println((String)"PERIOD = "+ PERIOD + " sec" );
}

void loop()
{
  int diff = millis() - lastCheck;
  if (diff > 1000) { //1000msごとに
    while (BME280.isMeasuring()) {// BME280の計測が終わるまで待機
    } 
    // read out the data - must do this before calling the getxxxxx routines
    // getxxxxxルーチンの呼び出し前に、データの読み込みを行う
    BME280.readMeasurements(); //1000msごとに、BME280の計測を行う
    lastCheck = millis();
  } else if (diff < 0) {
    lastCheck = 0;
  }

  Blynk.run();
  timer.run(); // Initiates BlynkTimer

  unsigned long curr = millis();
  if ((curr-prev) >= PERIOD * 1000 ) { //PERIOD secごとに以下の処理を実行  
    Serial.print((String)"milleis/1000: "+millis()/1000 +" sec, ");

    // 読み取った値をシリアルにプリント
    Serial.print("Temperature: ");
    printFormattedFloat(tempMostAccurate, 1);
    //Serial.println("");

    Serial.print(" ℃, Humidity: ");
    printFormattedFloat(humidityMostAccurate, 1);
    //Serial.println("");

    Serial.print(" %, Pressure: ");
    printFormattedFloat(pressureMostAccurate, 1);
    Serial.println(" hpa");
    //Serial.println("");

    Serial.print(", WBGT: ");
    printFormattedFloat(WBGT, 1);
    Serial.println(" ℃");
    //Serial.println("");

    ambient.set(1, tempMostAccurate); // 温度をデータ1にセット
    ambient.set(2, humidityMostAccurate); // 湿度をデータ2にセット
    ambient.set(3, pressureMostAccurate); // 気圧をデータ3にセット

    ambient.send(); // データをAmbientに送信

    prev += PERIOD * 1000; // 前回実行時刻に実行周期を加算
  }
  else if ((curr-prev) < PERIOD * 1000 ) {;}

}


Blynkの設定

iphone側

アプリ初期設定

Blynk アプリで(詳細はこのリンク先で
  1. 新しいプロジェクトを作成します。(ハードウェアモデルesp8266を使用)
  2. AUTHTOKENを生成します。
  3. Eメールトークンを送信します。(ESP8266スケッチでトークンを使います)

アプリ表示設定

上に挙げたスケッチでは、4個のVirtual pin(たぶん、ESP8266のデジタル出力とアナログ出力を区別なく使えるのでVirtual pinという名前にしているのだと思う)を設定しています。これらのデータをアプリに取り込んで表示させます。

  Blynk.virtualWrite(V0, tempMostAccurate); 温度
  Blynk.virtualWrite(V1, humidityMostAccurate); 湿度
  Blynk.virtualWrite(V2, pressureMostAccurate); 大気圧
  Blynk.virtualWrite(V4, WBGT); 暑さ指数

アプリではValue Display widget やGauge widgetを使用します。新しいProjectでwidget配置画面(方眼紙のような画面)をタッチすると現れるWidget Box(左下図)から所望のwidgetを選びます。各々のwidgetの設定を行い、右下図のようになりました。

メータ表示がGauge widget、数値表示が3個ともLabeled Valueです。グラフ表示がSuperChartになります。(Blynk local serverを作ったので、widgetが無料で自由に使えます。)


次の図はwidgetの設定例です。左下の図は温度を表示するGauge widgetです。INPUTの項目はVirtual pinのV0を選びます。また、その他の表示されている項目をタップして書き込みます。左上の「i」アイコンをタップすると説明(英語)が出ます。

右下の図はSuperChartの設定です。グラフ表示をさせたい温度、湿度、気圧について、それぞれ右の「?」をタップすると詳細設定画面になります。

ESP8266側 スケッチ

Blynkの接続設定

8,9行目:wifiのIDとPasswordを設定します。
29行目:char auth[] = "xxxxxxxxxx"; //Blynkから送信されてきたTokenを設定します。
48行目:Blynk.begin(auth, ssid, password, server, port); //SSID and passwordに加え、ローカルBlynkサーバーを使う場合はserverとportも必要です。これは10行目、11行目で設定しています。

SuperChartの設定

"SuperChart"は、ライブデータと履歴データを可視化するために使用されます。センサーデータ、バイナリイベントロギングなどに使用できます。"gauge widget"などでは"Fresh Interval"で更新間隔を指定しています。この更新データを"SuperChart"でも利用しているのですが、次に示すデータをプッシュする設定を行わないと正常なグラフ表示ができません。

Blynk.ccのドキュメントにsuperchartに関して次のように書いてあります。この設定を行います。

To use SuperChart widget you would need to push the data from the hardware with the desired interval by using timers.
SuperChartウィジェットを使用するには、タイマーを使用して、ハードウェアから必要な間隔でデータをプッシュする必要があります。

私の自己解釈で補足すると、Blynkにはpull型とpush型があって、アプリを開いてデータを見たりボタンを押して動かすのがpull型です。一方、push型はアプリを開かなくても定期的にセンサを読んだりできます。"SuperChart"はpush型なのでスケッチはpull型と違う書き方をしなければなりません。

14行目:"timer"という名前のBlynkTimer Objectを設定します。delay を使ってプログラムを長い間停止する場合には、Blynk サーバと接続が切れてしまう場合があります。それに比べ、BlynkTimerはBlynkライブラリルーチンに干渉しない正確な一定の間隔で定期的にデータを送信できます。
64行目:"timer" で正確にカウントされ、60*1000L(msec)ごとにmyTimerEventを実行します。
67行目:一連のデータ掃き出しを定期的に実行するため、myTimerEvent()関数を作ります。一連のデータとは、温度、湿度、気圧と計算値の暑さ指数です。それらは、Blynk.virtualWriteでBlynkサーバーへ送られます。

(注記)Blynk.virtualWriteに関しては1秒に10個より多くの値は送らないでくださいとBlynk.ccのドキュメントに書かれています。

Ambientの設定

Ambientではマイコンからデーターを送ってグラフ化まで非常に簡単にできます。 最低限必要なのはAmbientサイトで「チャネル」を作ることと、 マイコン側のプログラムでチャネルIDとライトキーを指定してデーターを送ることだけです。


チャンネル生成

上記の引用元で書いてあるとおりにチャンネルを作ります。

ESP8266側 スケッチ

21,22行目:チャンネル生成で作ったチャネルIDとライトキーを指定します。
24行目:WiFiClientの管理データーのアドレスです。
25行目:ambient object を設定します。
60行目:ambient.begin チャネルIDとライトキーを指定してAmbientの初期化をします。

137~139行目:データーを送るときは、送るデータそれぞれをambient.set()して、まとめてambient.send()します。

82~93行目:Virtual pin V3でAmbientへのデータの送信間隔を変更できるようにしています。BlynkのSlider Settings widgetを使っています。

(注記)Ambientのデータ制限
送信間隔:5秒以上あけて
データ量:3,000件/1日(最低28.5秒間隔)1件あたり8種類のデータを送れるので、8個までチャートを生成できます。
保存期間:1年

可視化データ

Blynk

SuperChartの単位横軸を3days(左下図)と1month(右下図)で表示してみました。3月初めのデータです。最高温度は20度を超えています。最低温度は半月くらい前で5度でした。


Ambient

Webブラウザ表示

温度データが分かりやすいですが、一つの山が一日になります。

ダウンロード Excelグラフ

7~9月のデータをダウンロードしてグラフ化してみました。7月の後半が温度が高く、最高温度は7月25日で46度でした。最低でも28度あります。






Powered by Blogger | Designed by QooQ

keyboard_double_arrow_down

keyboard_double_arrow_down