uni farm

スタックチャン で CO2 センサー。Ambient で可視化

スタックチャン で CO2 センサー。Ambient で可視化

スタックチャン(m5stack basic)に CO2 センサーをつないで、数値を計測。Ambient(IoTデータの可視化サービス)に値を送信して、簡単に推移を可視化してみた

ファームウェアには platform io を用いた。使用言語は C++。コードはほとんど ChatGPT とかいた

環境

  • m5stack basic
  • platformio: 6.11.1
  • 依存ライブラリ
sensirion/Sensirion I2C SCD4x @ ^0.4.0
m5stack/M5Unified@^0.1.9
meganetaaan/M5Stack-Avatar@^0.9.0
ambientdatainc/Ambient ESP32 ESP8266 lib@^1.0.3

センサーから値を取得、送信

ほぼサンプルコードまま

  • setup

wifi への接続と色々初期化。ambientの定数周りはサイトから取得しておく

#include <M5Unified.h>
#include <Ambient.h>
#include <Avatar.h>
#include <SensirionI2CScd4x.h>

SensirionI2CScd4x scd4x;

// wifi
const char* SSID = "xxxx";
const char* PASSWORD = "xxxx";

// for ambient
WiFiClient client;
Ambient ambient;
const unsigned channelId = 0;
const char* writeKey = "0xxx";

void co2_setup() {
    WiFi.begin(SSID, PASSWORD);
    unsigned long startTime = millis();
 
    while (WiFi.status() != WL_CONNECTED) {
        delay(100);
        if (millis() - startTime > 10000) {
            Serial.println("wifi not connected");
            break;
        }
    }

    uint16_t error;
    char errorMessage[256];

    ambient.begin(channelId, writeKey, &client);
    scd4x.begin(Wire);

    // stop potentially previously started measurement
    error = scd4x.stopPeriodicMeasurement();
    if (error) {
        Serial.print("Error trying to execute stopPeriodicMeasurement(): ");
        errorToString(error, errorMessage, 256);
        Serial.println(errorMessage);
    }

    // Start Measurement
    error = scd4x.startPeriodicMeasurement();
    if (error) {
        Serial.print("Error trying to execute startPeriodicMeasurement(): ");
        errorToString(error, errorMessage, 256);
        Serial.println(errorMessage);
    }

    Serial.println("Waiting for first measurement... (5 sec)");
}
  • loop

ambient の一日あたりのデータ登録数の上限が 3000 なので適当に間隔を開けて送信している

// 送信間隔
const int SEND_PEDIOD = 300;

void co2_loop() {
    M5.update();
    static unsigned long lastSendTime = 0;
    unsigned long currentTime = millis();

    uint16_t error;
    char errorMessage[256];

    // Read Measurement
    uint16_t co2      = 0;
    float temperature = 0.0f;
    float humidity    = 0.0f;
    bool isDataReady  = false;
    error             = scd4x.getDataReadyFlag(isDataReady);
    if (error) {
        M5.Lcd.print("Error trying to execute readMeasurement(): ");
        errorToString(error, errorMessage, 256);
        Serial.println(errorMessage);
        return;
    }
    if (!isDataReady) {
        return;
    }
    error = scd4x.readMeasurement(co2, temperature, humidity);

// ここに描画処理をかいている
// ...

    if (currentTime - lastSendTime > SEND_PEDIOD) {
      lastSendTime = currentTime;
      ambient.set(1, temperature);
      ambient.set(2, humidity);
      ambient.set(3, co2);
      ambient.send();
      Serial.println("send to ambient");
    };
}

可視化結果はこんな感じ。ダッシュボードの設定も ambient 上で簡単に設定できた

dashboard

取得した値に応じて表情を変える

せっかくスタックチャンなので外気の状態によって表情を変化させてみた

co2 もしくは温度と湿度によって表情を変える

enum State {
    HOT,
    COLD,
    NORMAL
};

// Define a function to determine the state based on temperature and humidity
State determineState(float temperature, float humidity) {
    if (temperature > 25 && humidity > 60) {
        return HOT;
    } else if (temperature < 15) {
        return COLD;
    } else {
        return NORMAL;
    }
}
State currentState = determineState(temperature, humidity);
if (co2 < 1000) {
          switch (currentState) {
              case HOT:
                  avatar.setExpression(Expression::Angry);
                  break;
              case COLD:
                  avatar.setExpression(Expression::Sad);
                  break;
              case NORMAL:
                  avatar.setExpression(Expression::Happy);
                  break;
          }
} else {
          avatar.setExpression(Expression::Sleepy);
}
// display 表示
char c[100];
sprintf(c, "co2:%d\n temp:%.2f\n RH:%.0f", co2, temperature, humidity);
avatar.setSpeechText(c);

画面にはこんな感じで表示される。CO2 は 1000 ppm を上回ると眠気を感じるらしい

sleepy

所感

関連のライブラリが充実しており、思った以上に簡単なコードで実現できた。用語周り(ファームウェア、I2Cなど)に馴染みがないため環境構築などには少し苦労した

せっかく躯体があるのに活かせてないため、動きの要素も追加したいと思った

参考

  • m5stack のコード構造の基本

https://nouka-it.hatenablog.com/entry/2022/02/27/133549

  • CO2センサー

https://massa4649.com/m5stack_co2unit/

  • ambientの使い方

https://www.giardino-familiare.com/2021/08/08/m5stickcでガーデニングの水やりセンサを作る-その3-【/

  • ambientのコードサンプル

https://github.com/AmbientDataInc/Ambient_ESP8266_lib/blob/master/examples/M5Stack_ESP32/Ambient_BME280/Ambient_BME280.ino

  • スタックチャンや環境構築のメモ

https://zenn.dev/uni/scraps/16803af5e771b1

2023, Built with Gatsby. This site uses Google Analytics.