概要
過去の記事で実現した以下を組み合わせ、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に移植する。
- ヘッダファイルの読み込み(ソースの先頭)
// For ENVII
#include <Wire.h>
#include "Adafruit_Sensor.h"
#include <Adafruit_BMP280.h>
#include "SHT3X.h"
#include "esp_camera.h" # ここからは元々ある
#include <WiFi.h>
- グローバル変数の定義(他のグローバル変数の定義の後ろ辺り)
const char* password = "********" # ここまでは元々ある
// For ENVII
SHT3X sht30;
Adafruit_BMP280 bme;
void startCameraServer(); # ここからは元々ある
- ENV IIの動作確認(WiFi.beginの前辺り)
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の方になる。よって、こちらにも同じように移植する。
- ヘッダファイルの読み込み(ソースの先頭)
// For ENVII
#include "Adafruit_Sensor.h"
#include <Adafruit_BMP280.h>
#include "SHT3X.h"
#include "esp_http_server.h" # ここからは元々ある
- グローバル変数の定義(他のグローバル変数の定義の後ろ辺り)
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.hとAdafruit_Sensor.hの両方で定義されていて、このままだとコンパイルで以下のエラーが出て怒られる。
conflicting declaration 'typedef struct sensor_t sensor_t'
なので、どちらかの型名を変更しないといけない。でも、相手はどちらもライブラリ。手は入れたくない。該当するヘッダファイルをスケッチブック内にコピーして改変する手もあるけど面倒。ということで、#define
と#undef
を使って、この場をしのぐ。修正するのはM5Camera-Image-ENVIIとapp_httpd.cppに追加した、ヘッダファイルの読み込み部分。
// For ENVII
#include <Wire.h>
#define sensor_t sensor_t_ # 追加
#include "Adafruit_Sensor.h"
#include <Adafruit_BMP280.h>
#undef sensor_t # 追加
#include "SHT3X.h"
// For ENVII
#define sensor_t sensor_t_ # 追加
#include "Adafruit_Sensor.h"
#include <Adafruit_BMP280.h>
#undef sensor_t # 追加
#include "SHT3X.h"
これによって、Adafruit_Sensor.hとAdafruit_BMP280.hは、sensor_t
がsensor_t_
に置換される(んだと思う)。これらのヘッダファイルの読み込みをソースの最初に置いた理由は、esp_camera.hで定義されているsensor_t
はapp_httpd.cppの中でも使われてて、生かしておかないといけないと思ったから。
ソースの汚さがにじみ出てるけど、それは一旦横に置いておく。この魔法については、以下のページを参考にした。
環境データを読み込むためのハンドラやURIを定義する
あとはapp_httpd.cppにWebサーバ用のハンドラ等を定義する。今回は特定のURL(/env)にアクセスすると温度、湿度、気圧を返してくれるようにした。
- ハンドラの定義(capture_handlerの後ろ辺り)
// 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の定義の周り)
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の登録の周り)
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で写真撮影+環境データ測定」**という、意味不明ではあるがやりたいことはできるようになった。気が向いたら、ソースをキレイにしたい。