1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

M5Cameraで写真撮影しつつ温度や湿度を測る

Posted at

概要

過去の記事で実現した以下を組み合わせ、M5Cameraで写真撮影しつつ温度や湿度を測れるようにした。

  1. M5Cameraで環境センサユニット ver.2(ENV II)を使う
  2. M5Cameraを極めて融通の利かない写真専門家にする

今回は、同じ名前の型sensor_tが複数のライブラリで定義されてて、これに対処するのに苦労した。とりあえず動くようにすることが目的なので、どう見てもソースが汚すぎるのは一旦無視する。

試した環境

  • M5Camera Version B
  • M5Stack用環境センサユニット ver.2(ENV II)
  • Arduino IDE 1.8.15
  • Arduino core for the ESP stable 1.0.6

手順

ソースの統合

1.2.のソースを1つのスケッチブックに統合する。どちらかのスケッチブックを別名で保存して一旦閉じる(今回はM5Camera-Image-ENVIIにした)。これによって新しくできたフォルダにもう一方のスケッチブックの中身(.inoなど)を全部コピーして、もう一度開きなおせばOK。ここでは以下のソースがある前提で書いていく。

  • M5Camera-Image-ENVII.ino (もとはM5Camera-Image.ino)
  • app_httpd.cpp
  • camera_pins.h
  • M5Camera-ENVII.ino
  • Adafruit_Sensor.h
  • SHT3X.cpp
  • SHT3X.h

M5Camera-Image-ENVIIにM5Camera-ENVIIを埋め込む

M5Camera-ENVIIで処理されている、環境センサーのライブラリ読み込みや動作確認の部分を、M5Camera-Image-ENVIIに移植する。

  • ヘッダファイルの読み込み(ソースの先頭)
M5Camera-Image-ENVII.ino
// For ENVII
#include <Wire.h>
#include "Adafruit_Sensor.h"
#include <Adafruit_BMP280.h>
#include "SHT3X.h"

#include "esp_camera.h" # ここからは元々ある
#include <WiFi.h>
  • グローバル変数の定義(他のグローバル変数の定義の後ろ辺り)
M5Camera-Image-ENVII.ino
const char* password = "********" # ここまでは元々ある

// For ENVII
SHT3X sht30;
Adafruit_BMP280 bme;

void startCameraServer(); # ここからは元々ある
  • ENV IIの動作確認(WiFi.beginの前辺り)
M5Camera-Image-ENVII.ino
void setup() {
  ....
  // For ENVII
  Wire.begin(4,13);
  Serial.println(F("ENV Unit(SHT30 and BMP280) test..."));
  while (!bme.begin(0x76)){  
    Serial.println("Could not find a valid BMP280 sensor, check wiring!");
  }

  WiFi.begin(ssid, password); # ここからは元々ある
  ...
}

app_httpd.cppにM5Camera-ENVIIを埋め込む

実際にセンサーからデータを読み込むのはapp_httpd.cppの方になる。よって、こちらにも同じように移植する。

  • ヘッダファイルの読み込み(ソースの先頭)
app_httpd.cpp
// For ENVII
#include "Adafruit_Sensor.h"
#include <Adafruit_BMP280.h>
#include "SHT3X.h"

#include "esp_http_server.h" # ここからは元々ある
  • グローバル変数の定義(他のグローバル変数の定義の後ろ辺り)
app_httpd.cpp
httpd_handle_t camera_httpd = NULL; #ここまでは元々ある

// For ENVII
extern SHT3X sht30;
extern Adafruit_BMP280 bme;

static esp_err_t capture_handler(httpd_req_t *req){ # ここからは元々ある

externを付けているのはM5Camera-Image-ENVII.inoで定義されてるから。

sensor_t型の二重定義に応急処置を施す

実はsensor_tという名前の型はesp_camera.hAdafruit_Sensor.hの両方で定義されていて、このままだとコンパイルで以下のエラーが出て怒られる。

conflicting declaration 'typedef struct sensor_t sensor_t'

なので、どちらかの型名を変更しないといけない。でも、相手はどちらもライブラリ。手は入れたくない。該当するヘッダファイルをスケッチブック内にコピーして改変する手もあるけど面倒。ということで、#define#undefを使って、この場をしのぐ。修正するのはM5Camera-Image-ENVIIapp_httpd.cppに追加した、ヘッダファイルの読み込み部分。

M5Camera-Image-ENVII.ino
// For ENVII
#include <Wire.h>
#define sensor_t sensor_t_    # 追加
#include "Adafruit_Sensor.h"
#include <Adafruit_BMP280.h>
#undef sensor_t               # 追加
#include "SHT3X.h"
app_httpd.cpp
// For ENVII
#define sensor_t sensor_t_    # 追加
#include "Adafruit_Sensor.h"
#include <Adafruit_BMP280.h>
#undef sensor_t               # 追加
#include "SHT3X.h"

これによって、Adafruit_Sensor.hAdafruit_BMP280.hは、sensor_tsensor_t_に置換される(んだと思う)。これらのヘッダファイルの読み込みをソースの最初に置いた理由は、esp_camera.hで定義されているsensor_tapp_httpd.cppの中でも使われてて、生かしておかないといけないと思ったから。

ソースの汚さがにじみ出てるけど、それは一旦横に置いておく。この魔法については、以下のページを参考にした。

環境データを読み込むためのハンドラやURIを定義する

あとはapp_httpd.cppにWebサーバ用のハンドラ等を定義する。今回は特定のURL(/env)にアクセスすると温度、湿度、気圧を返してくれるようにした。

  • ハンドラの定義(capture_handlerの後ろ辺り)
app_httpd.cpp
// For ENVII
static esp_err_t env_handler(httpd_req_t *req){
  static char json_response[1024];
  
  float tmp = 0.0;
  float hum = 0.0;
  float pressure = 0.0;
    
  pressure = bme.readPressure();
  if(sht30.get()==0){
    tmp = sht30.cTemp;
    hum = sht30.humidity;
  }

  char * p = json_response;
  *p++ = '{';
  p+=sprintf(p, "\"temperatura\":%2.2f,", tmp);
  p+=sprintf(p, "\"humedad\":%0.2f%,", hum);
  p+=sprintf(p, "\"pressure\":%0.2f", pressure);
  *p++ = '}';
  *p++ = 0;

  httpd_resp_set_type(req, "application/json");
  httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
  return httpd_resp_send(req, json_response, strlen(json_response));
}

一応、JSONで返す。オリジナルのapp_httpd.cppにあったstatus_handlerを引用して作った。

  • URIの定義(他のURIの定義の周り)
app_httpd.cpp
void startCameraServer(){
    ...
    // For ENVII
    httpd_uri_t env_uri = {
        .uri       = "/env",
        .method    = HTTP_GET,
        .handler   = env_handler,
        .user_ctx  = NULL
    };
    
    Serial.printf("Starting web server on port: '%d'\n", config.server_port); # ここからは元々ある
    ...
}
  • URIの登録(他のURIの登録の周り)
app_httpd.cpp
void startCameraServer(){
    ...
    if (httpd_start(&camera_httpd, &config) == ESP_OK) {
        ....
        httpd_register_uri_handler(camera_httpd, &capture_uri); # ここまでは元々ある

        // For ENVII
        httpd_register_uri_handler(camera_httpd, &env_uri);
    }
}

M5Camera-ENVII.inoを削除する

感謝の念を込めながら、さよならする。

動かす

何ら構造化もされてないソースではあるが、これでも何となく動く。以下のURLにアクセス。

URL 機能
/ 写真を撮る
/env 環境データ(温度、湿度、気圧)を測る

最後に

今回はド級初心者の自分には結構辛かった。C++とか分からないし(大昔に趣味レベルでCを触ったことはある)。これでひとまず**「M5Cameraで写真撮影+環境データ測定」**という、意味不明ではあるがやりたいことはできるようになった。気が向いたら、ソースをキレイにしたい。

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?