単子葉類プログラマーのメモ

プログラミング関連の自分用メモだけど他の人の役に立つかもしれないので公開しておく感じのブログ

M5Stackで温度・湿度・気圧を測ってAmbientに保存

M5Stackで遊んだのでそのときにやったことのメモ。

初心者なのでM5GO IoTスターターキットを購入した。

目次

動作確認

YouTueのSwitchScience 公式チャンネルの以下の動画をマネして、プリインストールされているアプリで付属の各ユニットに初期不良がないことを確認。


【はじめてのM5Stack 】第2回 機能チェックと初期セットアップ

デモを実行

M5Flowのデモを動かそうとしたがファームウェアが古いというエラーになったのでバージョンアップすることに。

https://docs.m5stack.com/en/downloadからCP210x_VCP_WindowsM5Burnerをダウンロード&インストール。 M5StackをPCにUSB接続してから、M5Burnerを適当に操作してファームウェアをバージョンアップ。

その後、M5FlowでデモのWeather StationをLOADしてRUNしたが、今度はENVがつながっていないというエラーが発生。 購入したM5GOに同梱されていたのはENVではなくENV IIだったので、LOADしたコードを書き換えてENV IIを使うようにしたら無事動いた。

Arduino

M5FlowだとMicroPythonでしかプログラミングできなさそうだけど、ネット上のM5StackのソースコードC/C++のほうがよくみつかるので、開発環境としてArduinoをインストール。

以下を参考にしてセットアップした。

raspberrypi.mongonta.com

C言語でENV II用コードを作成

ENV IIの中身はSHT30BMP280なので、Arduinoのライブラリマネージャでこれらの名前で検索し、AirGradient Air Quality SensorAdafruit BMP280 Libraryをインストール。

その後、気温、湿度、気圧を表示するだけのプログラムを作成。

実行結果

ソースコード

#include <M5Stack.h>
#include <Wire.h>
#include "Adafruit_Sensor.h"
#include <Adafruit_BMP280.h>

float cTemperature;
float humidity;
float pressure;
Adafruit_BMP280 bme;

void readSHT30();
void print();

void setup(){
  // setup M5Stack
  M5.begin();
  M5.Power.begin();
  Wire.begin(21, 22, 100000);
  bme.begin(0x76);
}

void loop() {
  readSHT30();
  pressure = bme.readPressure() * 0.01;
  print();

  delay(1000);
}

void readSHT30() {
  static const uint8_t kSht30Addr = 0x44;
  
  unsigned int data[6];

  Wire.beginTransmission(kSht30Addr);

  Wire.write(0x2C);
  Wire.write(0x06);

  Wire.endTransmission();
  delay(500);

  Wire.requestFrom(kSht30Addr, 6);

  int avairable = Wire.available();
  if (avairable == 6) {
    data[0] = Wire.read();
    data[1] = Wire.read();
    data[2] = Wire.read();
    data[3] = Wire.read();
    data[4] = Wire.read();
    data[5] = Wire.read();
  }
  else {
    M5.Lcd.printf("Wire.available()== %d\n", avairable);
    return;
  }

  cTemperature = ((((data[0] * 256.0) + data[1]) * 175) / 65535.0) - 45;
  humidity = ((((data[3] * 256.0) + data[4]) * 100) / 65535.0);
}

void print() {
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setCursor(0,0);
  M5.Lcd.setTextColor(WHITE);
  M5.Lcd.setTextSize(4);
  M5.Lcd.printf("T: %3.2f\n\n", cTemperature);
  M5.Lcd.printf("H: %3.2f\n\n", humidity);
  M5.Lcd.printf("P: %5.2f\n\n", pressure);
}

以下を参考にした。

Ambientにデータを保存

測定したデータを保存&グラフ化するためにAmbientを利用する。

利用方法は公式のチュートリアルが日本語で十分わかりやすい。 チュートリアルの1と2を読めば作りたいものは作れた。 でもサンプルコードでinclude文や変数の定義を省略するのはやめてほしかった。

ENV II用コードにAmbientへの送信機能を追加したコード

#include <M5Stack.h>
#include <Wire.h>
#include "Adafruit_Sensor.h"
#include <Adafruit_BMP280.h>
#include <WiFi.h>
#include <WiFiClient.h>
#include <Ambient.h>

const char* kWiFiSsid = "Wi-FiアクセスポイントのSSID";
const char* kWiFiPassword = "Wi-Fiのパスワード";
const unsigned int kAmbientChannelId = AmbientのチャネルID;
const char* kAmbientWriteKey = "Ambientのライトキー";

float cTemperature;
float humidity;
float pressure;
Adafruit_BMP280 bme;
Ambient ambient;
WiFiClient client;

void readSHT30();
void print();
void sendToAmbient();

void setup(){
  // setup M5Stack
  M5.begin();
  M5.Power.begin();
  Wire.begin(21, 22, 100000);
  bme.begin(0x76);

  // setup WiFi
  M5.Lcd.print("connecting WiFi");
  WiFi.begin(kWiFiSsid, kWiFiPassword);
  while (WiFi.status() != WL_CONNECTED) {
    M5.Lcd.print(".");
    delay(1000);
  }

  // setup Ambient
  ambient.begin(kAmbientChannelId, kAmbientWriteKey, &client);
}

void loop() {
  readSHT30();
  pressure = bme.readPressure() * 0.01;
  print();
  sendToAmbient();

  delay(1000);
}

void readSHT30() {
  static const uint8_t kSht30Addr = 0x44;
  
  unsigned int data[6];

  Wire.beginTransmission(kSht30Addr);

  Wire.write(0x2C);
  Wire.write(0x06);

  Wire.endTransmission();
  delay(500);

  Wire.requestFrom(kSht30Addr, 6);

  int avairable = Wire.available();
  if (avairable == 6) {
    data[0] = Wire.read();
    data[1] = Wire.read();
    data[2] = Wire.read();
    data[3] = Wire.read();
    data[4] = Wire.read();
    data[5] = Wire.read();
  }
  else {
    M5.Lcd.printf("Wire.available()== %d\n", avairable);
    return;
  }

  cTemperature = ((((data[0] * 256.0) + data[1]) * 175) / 65535.0) - 45;
  humidity = ((((data[3] * 256.0) + data[4]) * 100) / 65535.0);
}

void print() {
  M5.Lcd.fillScreen(BLACK);
  M5.Lcd.setCursor(0,0);
  M5.Lcd.setTextColor(WHITE);
  M5.Lcd.setTextSize(4);
  M5.Lcd.printf("T: %3.2f\n\n", cTemperature);
  M5.Lcd.printf("H: %3.2f\n\n", humidity);
  M5.Lcd.printf("P: %5.2f\n\n", pressure);
}

void sendToAmbient() {
  static const unsigned char kInterval= 300;
  static unsigned char counter = 0;

  if (counter == kInterval) {
    ambient.set(1, cTemperature);
    ambient.set(2, humidity);
    ambient.set(3, pressure);
    ambient.send();
    
    counter = 0;
  }
  else {
    counter++;
  }
}