2021年1月11日月曜日

ド素人がM5StickCを用いたマルチ環境計を作ってみた Ver3.0

久しぶりのM5StickC関連です。
というかそもそも更新自体が久しぶりか。

ともかく、Multi-Environmental-Sensor-Systemとかいう気取った…どころか痛いシステム名の部分を、日付と時刻の表示に変えてみよう、ということを思いつきまして。
まずは時計を表示するコードを作らなきゃなぁと、色々M5StickCを時計にしているサイトを参考に、自分なり(ほぼほぼコピペ)のコードを作ってみました。Arduinoだとスケッチって言ったほうがいいのかな?
そのあと、前回のコードに今回の日付と時刻の表示を追加して、表示面でちょっと調整を加えました。

※プログラミング素人が、教本すら読まずにネット上の知識のみで組み上げたものです。ガバガバでスパゲッティなコードだったり、変なところもあるかと思いますが温かい目で見てやってください。
※そのため説明が間違っている可能性が高いです。参考の一つになるかも怪しいのはあしからず。


~今回作ったもの~

M5StickCを時計に(今後のことを考えてsetup関数にしかコードを入れていないので、そのまま時計としては使えない)(本当に時計として使いたかったら参考元のコードをぶちこんでください)して、前回のコードにぶちこんで時刻と日付を表示させるようにした
あとちょっと表示位置を調整した

使用したデバイス類

・M5StickC ・ENV Ⅱ HAT ・MH-Z19B ・Grove-メスピンヘッダケーブル
 相変わらず使用した部品に差異は無いので詳細な説明は省きます。
 今回は時刻・日付を表示させたものを追加しただけなので実質必要なのは本体のみですね~

~日付と時刻の表示、参考元コピペとちょっとした苦労~

 まずは、参考元様のコードをコピペしてテスト動作。
 これは、もちろん正常に動作しましたよ。そりゃ。

 次に、私はsetup関数内で実行したいので、そのように改造。
 …とはいっても、知識ゴミカスの私にはどれを消してどれを残せば予定通りに動くのかなんてわかんないので、実際に稼働しているVer2.0のコードだったりWiFiのテストコードだったりと見比べて、あとはいきあたりばったりで改造しました。
 なので、何回もコードがおかしいとArduinoIDEに怒られるし当たり前のように予定通り動かないしでちょっとだけ苦労。
 でも前よりは多少の知識・経験があるのでなんとかなりました。
 というのが下記のコードです。多分誰もいらないだろうけど。
 なにせsetup関数内でしか動かないように、つまりntpから取得した時刻のみを表示するだけとかいう謎コードですから…

 あ、あと、このコードに関しては動作中の写真はありません。
 だって表示全部参考元様のまんまだもん…

code:1 Clock_TEST
#include <M5StickC.h>
#include <WiFi.h>
#include <time.h>

const char* ssid     = "YOUR SSID"; // WiFiのSSID
const char* password = "YOUR PASSWORD"; // WiFiのパスワード

const char* ntpServer = "ntp.jst.mfeed.ad.jp"; // NTPサーバー
const long  gmtOffset_sec = 9 * 3600;          // 時差9時間
const int   daylightOffset_sec = 0;            // サマータイム設定なし

RTC_TimeTypeDef RTC_TimeStruct; // 時刻
RTC_DateTypeDef RTC_DateStruct; // 日付

void setup() {
  M5.begin(); //Initialize M5StickC M5StickCを初期化
  delay(50); //Wait 50msecs 50ミリ秒待機

  WiFi.begin(ssid, password); //Starting connection of WiFi WiFi接続開始

  M5.Lcd.fillScreen(BLACK); //Fill Screen Black 背景色を黒に
  M5.Lcd.setRotation(3); //Set Lcd's Direction 画面を横向き(左上)に
  M5.Lcd.setCursor(0, 2, 2); //Set Cursor to (0,2) and Assign Fonts 2 カーソルを(0,2)へ、フォントは2を指定

  while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        M5.Lcd.print("."); //WiFi接続待ちの間500ミリ秒ごとに"."を表示
  }

  M5.Lcd.println("Successed!!");
  M5.Lcd.println("IP: "); //Print IPaddress IPアドレスを表示
  M5.Lcd.println(WiFi.localIP());

  delay(3000); //Wait 3000msecs 3000ミリ秒待機
  
  static const char *wd[7] = {"Sun","Mon","Tue","Wed","Thr","Fri","Sat"};
  M5.Rtc.GetTime(&RTC_TimeStruct); // 時刻の取り出し
  M5.Rtc.GetData(&RTC_DateStruct); // 日付の取り出し

  M5.Lcd.fillScreen(BLACK); //Fill Screen Black 背景色を黒に
  M5.Lcd.setTextColor(GREEN); //Set text color to green 文字色を緑に
  M5.Lcd.setCursor(0, 10, 7); //Set cursor to (0,10) and assign fonts 7 カーソルを(0,10)に、フォントは7を指定
  M5.Lcd.printf("%02d:%02d", RTC_TimeStruct.Hours, RTC_TimeStruct.Minutes); // 時分を表示

  M5.Lcd.setTextFont(1); //Assign fonts 1 フォントは1を指定
  M5.Lcd.printf(":%02d\n",RTC_TimeStruct.Seconds); // 秒を表示

  M5.Lcd.setTextColor(WHITE); //Set text color to white 文字色を白に
  M5.Lcd.setCursor(25, 65, 1); //Set cursor to (25,65) and assign fonts 1 カーソルを(25,65)に、フォントは1を指定
  M5.Lcd.printf("Date:%04d.%02d.%02d %s\n", RTC_DateStruct.Year, RTC_DateStruct.Month, RTC_DateStruct.Date, wd[RTC_DateStruct.WeekDay]);

}

void loop() {
  
}


~前回のコードに日付と時刻ぶちこみ、あと微調整

 上記のコードでntpからの時刻取得および表示はできたので、あとはそれを実装します。
 ただし、表示方法が大きく異なるので表示位置とか、フォントとかは変更しました。
 それでも日付と時刻は色が違うほうがわかりやすいなーと思ったので、文字色を緑にしました。嫌だったら白にでも変えてください。
稼働している様子 まあちょっと変わっただけですね



code:2 MultiSensingSketchONLYAmbientVer3
//Include Libraries ライブラリをインクルード
#include <M5StickC.h>
#include "SHT3X.h"
#include <Wire.h>
#include "Adafruit_Sensor.h"
#include <Adafruit_BMP280.h>
#include "MHZ19_uart.h"
#include "Ambient.h"
#include <WiFi.h>
#include <time.h>

//Define Valiable 変数を定義
SHT3X sht3x;
Adafruit_BMP280 bme;
MHZ19_uart mhz19;

#define uS_TO_S_FACTOR 1000000 //マイクロ秒を秒に変換する定義?
#define TIME_TO_SLEEP 30 //30秒でESP32をスリープにする定義?

WiFiClient client;
Ambient ambient;

const char* ssid     = "YOUR SSID"; //Ssid and password of connecting WiFi 接続するWiFiのSSIDとパスワード
const char* password = "YOUR PASSWORD";

unsigned int channelID = YOUR ChannelID of Ambient; //ChannelID of Ambient AmbientのチャネルID
const char* writeKey = "YOUR writeKey of Ambient"; //Writekey of Ambient Ambientのライトキー

const char* ntpServer = "ntp.jst.mfeed.ad.jp"; //The server of NTP NTPサーバー
const long  gmtOffset_sec = 9 * 3600;          //Time difference 9 hours 時差9時間
const int   daylightOffset_sec = 0;            //No summer time サマータイム設定なし

RTC_TimeTypeDef RTC_TimeStruct; //Time 時刻
RTC_DateTypeDef RTC_DateStruct; //Date 日付

//Calculate temperature, humidity and air pressure in floating point? 浮動小数点で温湿度・気圧を計算?
float tmp = 0.0;
float hum = 0.0;
float pressure = 0.0;

void setup() {
  // put your setup code here, to run once:
  M5.begin(); //Initialize M5StickC M5StickCを初期化
  delay(50); //Wait 50msecs 50ミリ秒待機

  mhz19.begin(32,33); //Initialize I2C of MHZ19 MHZ19のI2Cを初期化
  mhz19.setAutoCalibration(false); //AutoCalibration turn off 自動校正をしない
  delay(2000); //Wait 2000msecs 2000ミリ秒待機
  
  Wire.begin(0,26); //Initialize I2C of ENV2HAT ENV2HATのI2Cを初期化
  M5.Axp.ScreenBreath(10); //Decrease Lcd's Brightness 画面の輝度を下げる
  setCpuFrequencyMhz(160); //Set Cpu Frequency to 80MHz CPUの動作周波数を80MHzに
  M5.Lcd.fillScreen(BLACK); //Fill Screen Black 背景色を黒に
  M5.Lcd.setRotation(3); //Set Lcd's Direction 画面を横向き(左上)に
  M5.Lcd.setCursor(0, 2, 2); //Set Cursor to (0,2) and Assign Fonts 2 カーソルを(0,2)へ、フォントは2を指定
  M5.Lcd.println("Multi-Environmental-Sensor-System"); //Print to Lcds in"" 画面に””内の文章を表示
  
  if (!bme.begin(0x76)){  
      Serial.println("Could not find a valid BMP280 sensor, check wiring!");
      while (1);  //Error message if the BMP280 sensor was not detected? BMP280センサが検出されなかった場合のエラー表示?
  }

  WiFi.begin(ssid, password); //Starting connection of WiFi WiFi接続開始
  
  while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        M5.Lcd.print("."); //WiFi接続待ちの間500ミリ秒ごとに"."を表示
  }

  M5.Lcd.println("Successed!!");
  M5.Lcd.println("IP: "); //Print IPaddress IPアドレスを表示
  M5.Lcd.println(WiFi.localIP());

  ambient.begin(channelID, writeKey, &client); //Assign channelID and writekey and initialize ambient チャネルIDとライトキーを指定してAmbientの初期化
  
  delay(3000); //Wait 3000msecs 3000ミリ秒待機



  if(sht3x.get()==0){
    tmp = sht3x.cTemp;
    hum = sht3x.humidity; //Acquisition of temperature and humidity data from sht3x? sht3xからの温湿度データの取得?
  }

  float pressure = bme.readPressure(); //Calculating atmospheric pressure in floating point? 浮動小数点で大気圧を計算?
  int co2, temp; //Calculate CO2 concentration by integer? 整数でCO2濃度を計算?
  int i;
  unsigned int t; 
  co2 = mhz19.getPPM(); //Read datas from MH-Z19 MH-Z19からのデータ呼び出し?
  temp = mhz19.getTemperature();
  float vbat = M5.Axp.GetBatVoltage(); //Get the battery voltage of the M5StickC? M5StickCのバッテリー電圧を取得?

  static const char *wd[7] = {"Sun","Mon","Tue","Wed","Thr","Fri","Sat"};

  M5.Lcd.fillScreen(BLACK); //Fill Screen Black(overwrite) 背景色を黒に上書き

  M5.Rtc.GetTime(&RTC_TimeStruct); //Acquisition of time 時刻の取り出し
  M5.Rtc.GetData(&RTC_DateStruct); //Acquisition of date 日付の取り出し
  
  M5.Lcd.setCursor(0, 2, 2); //Set Cursor to (0,2) and Assign Fonts 2 カーソルを(0,2)へ、フォントは2を指定
  M5.Lcd.setTextColor(GREEN); //Assign text color to green テキスト色を緑に
  M5.Lcd.printf("%02d:%02d", RTC_TimeStruct.Hours, RTC_TimeStruct.Minutes); //Display of time(hours and minutes) 時分を2桁で表示
  M5.Lcd.setCursor(40, 2, 2); //Set cursor to (20,2) and assign fonts 1 カーソルを(40,2)へ、フォントは1を指定
  M5.Lcd.printf("%04d-%02d-%02d %s\n", RTC_DateStruct.Year, RTC_DateStruct.Month, RTC_DateStruct.Date, wd[RTC_DateStruct.WeekDay]); //Display date 日付を表示
  
  M5.Lcd.setCursor(0, 22, 2); //Set Cursor to (0,22) and Assign Fonts 2 カーソルを(0,22)へ、フォントは2を指定
  M5.Lcd.setTextColor(WHITE); //Assign text color to white テキスト色を白に
  M5.Lcd.printf("Temp: %2.1fC Humi: %2.1f%%", tmp, hum); //Display of degrees Celsius and humidity in one decimal place 摂氏度および湿度を小数点以下1桁で表示

  M5.Lcd.setCursor(0, 42, 2); //Set Cursor to (0,42) and Assign Fonts 2 カーソルを(0,42)へ、フォントは2を指定
  M5.Lcd.printf("Pressure: %4.2fhPa", pressure / 100); //Atmospheric pressure in units of hPa to three decimal places 大気圧をhPaの単位で小数点以下3桁まで表示 
  
  delay(100); //Wait 100msecs 100ミリ秒待機

  if (!bme.begin(0x76)){  
      Serial.println("Could not find a valid BMP280 sensor, check wiring!");
      while (1); //Error message if the BMP280 sensor was not detected? BMP280センサが検出されなかった場合のエラー表示?
  }

  M5.Lcd.setCursor(0, 62, 2); //Set Cursor to (0,62) and Assign Fonts 2 カーソルを(0,62)へ、フォントは2を指定
  M5.Lcd.printf("CO2: %4dppm",co2); //CO2 concentration in integers in ppm CO2濃度をppmの単位で整数で表示
  
  delay(100); //Wait 100msecs 100ミリ秒待機
  
  M5.Lcd.setCursor(93, 62, 2); //Set Cursor to (93,62) and Assign Fonts 2 カーソルを(93,62)へ、フォントは2を指定
  M5.Lcd.printf("vb: %4.2fV",vbat); //Battery voltage displayed in 2 decimal places バッテリー電圧を小数点以下2桁で表示

  //温湿度・気圧・CO2濃度・バッテリ電圧をAmbientに送信
  ambient.set(1, tmp);
  ambient.set(2, hum);
  ambient.set(3, co2);
  ambient.set(4, pressure / 100);
  ambient.set(5, vbat);

  ambient.send();

  delay(3000); //Wait 3000msecs 3000ミリ秒待機

  esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR); //Wakeup time from deep sleep ディープスリープからの復帰時間
  esp_deep_sleep_start(); //Start DEEP SLEEP MODE ディープスリープ開始

}

uint8_t setup_flag = 1;

void loop() {
  // put your main code here, to run repeatedly:
  
}
 上記コード内25行目、unsigned int channelID = YOUR ChannelID of Ambient;となっているところですが、ここは定数(数字)が直接入るため""(ダブルクォーテーション)は必要ありません。
 あと、WiFi.hはインクルードしなくてもいいかもしれません。だって今までなくても接続できてたし。
 他に、なんとなく接続確認からの待機時間が微妙に長く感じてたので3秒から2秒に減らしました。ちなみになんで3秒だったのかとかわかってません。参考元のコードまんま使っているので…もしかしたら3秒位は待機したほうがいいのかもしれません。

 時刻と日付についてですが、白文字でも良かったのですがなんとなく色を変えたくて緑にしています。また、初期段階では8ピクセルフォントでの表示だったのですが、可読性が低かったため記述方式を変更したうえで他と同じ16ピクセルフォントでの表示としました。
 また、バッテリ電圧の表示位置を大幅に変更してCO2濃度の隣に移動させ、vbat→vbと省略したうえで文字を大きくして、可読性を上げました。
 
 それ以外はほんとに何も変えてませんね~

2021/02/09追記:PCに接続しっぱなしで24時間常時稼働させていたのですが、なぜか最近すぐフリーズするように。原因を探るも全くわからず。
 もしかしてPCのUSB電源のノイズのせい?と思って給電用のケーブルをAnkerの充電器に変更。そうしたところ、問題なく稼働するようになったため”よくわからんけど動いてるからヨシ!”な状態ですが問題への対処は終了ということで…
 電源は比較的クリーンなUSB充電器からとり、プログラムを書き換えるときだけ別途PCに接続したほうがいいのかもしれません。まじでわからん。ほんとにノイズのせい?????

~次回以降の展望Ⅲ~

 次のメジャーアップデートは、あったとしてボタンを押したときに何かしらの挙動を示すようにする…かなぁ?
 それはまた気が向いたらってことになりますね…なにせこれ以降完全にちんぷんかんぷんな状態なので…

~巻末の参考資料欄~

0 件のコメント:

コメントを投稿