【2022年最新版】Timer Camera Fで定点カメラを作ってLINEに通知

1年前に書いたTimer Camera Fで定点カメラを作ってLINEに通知が2022/8/11時点でうまく動かないことがわかりました。修正箇所を記載します。

目次

最小構成でビルド

まずは、以下の構成

  • platformio.ini
[env:m5stack-timer-cam]
platform = espressif32
board = m5stack-timer-cam
framework = arduino
lib_deps = 
	m5stack/Timer-CAM
upload_speed = 1500000
monitor_speed = 115200
  • main.cpp
#include <Arduino.h>
#include <WiFi.h>

#include "battery.h"
#include "led.h"
#include "bmm8563.h"

#include "esp_camera.h"
#include "camera_pins.h"

void setup()
{

}

void loop()
{

}

結果

ビルド失敗

*** [.pio\build\m5stack-timer-cam\lib44b\Timer-CAM\battery.c.o] Error 1
.pio/libdeps/m5stack-timer-cam/Timer-CAM/src/app_httpd.cpp:22:10: fatal error: fd_forward.h: No such file or directory

********************************************************************
* Looking for fd_forward.h dependency? Check our library registry!
*
* CLI  > platformio lib search "header:fd_forward.h"
* Web  > https://registry.platformio.org/search?q=header:fd_forward.h
*
********************************************************************

# 
 #include "fd_forward.h"
          ^~~~~~~~~~~~~~
compilation terminated.
*** [.pio\build\m5stack-timer-cam\lib44b\Timer-CAM\app_httpd.cpp.o] Error 1
======================================== [FAILED] Took 5.33 seconds ========================================

Timer-CAMライブラリーのバージョンは0.0.2が使われています。

Dependency Graph
|-- Timer-CAM @ 0.0.2

Timer-CAMライブラリーをGitから最新版を取得

PlatformIOではGitリポジトリを指定してライブラリーを取得することが可能です。

[env:m5stack-timer-cam]
platform = espressif32
board = m5stack-timer-cam
framework = arduino
lib_deps = 
	; m5stack/Timer-CAM
	https://github.com/m5stack/TimerCam-arduino.git
upload_speed = 1500000
monitor_speed = 115200

GitHubのリポジトリを直接指定できます。

結果

ビルド成功

2022/8/11時点のバージョンはこちら

Dependency Graph
|-- Timer-CAM @ 0.0.2+sha.eabb74f

platformio.iniの指定をhttps://github.com/m5stack/TimerCam-arduino.git#eabb74fとしておけばこのバージョン固定になります。

ENV IIに使用するライブラリーを追加

  • platformio.ini
[env:m5stack-timer-cam]
platform = espressif32
board = m5stack-timer-cam
framework = arduino
lib_deps = 
	; m5stack/Timer-CAM
	https://github.com/m5stack/TimerCam-arduino.git#eabb74f
	
	adafruit/Adafruit BMP280 Library
	adafruit/Adafruit SHT31 Library
	adafruit/Adafruit BusIO
	adafruit/Adafruit Unified Sensor
	Wire

upload_speed = 1500000
monitor_speed = 115200
  • main.cpp
#include <Arduino.h>
#include <WiFi.h>

#include "battery.h"
#include "led.h"
#include "bmm8563.h"

#include "esp_camera.h"
#include "camera_pins.h"

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

void setup()
{

}

void loop()
{

}

結果

ビルド失敗

In file included from src/main.cpp:12:
.pio/libdeps/m5stack-timer-cam/Adafruit Unified Sensor/Adafruit_Sensor.h:157:3: error: conflicting declaration 'typedef struct sensor_t sensor_t'
 } sensor_t;
   ^~~~~~~~
In file included from C:/Users/xxxxx/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp32-camera/driver/include/esp_camera.h:71,
                 from src/main.cpp:8:
C:/Users/xxxxx/.platformio/packages/framework-arduinoespressif32/tools/sdk/esp32/include/esp32-camera/driver/include/sensor.h:249:3: note: previous declaration as 'typedef struct _sensor sensor_t'
 } sensor_t;
   ^~~~~~~~
Compiling .pio\build\m5stack-timer-cam\libeb4\Adafruit BusIO\Adafruit_BusIO_Register.cpp.o
*** [.pio\build\m5stack-timer-cam\src\main.cpp.o] Error 1
======================================== [FAILED] Took 8.21 seconds ========================================

sensor_tが競合しているようです。(これは実は1年前にも発生していた気がします。)

ライブラリーのバージョンはこちら。

Dependency Graph
|-- Timer-CAM @ 0.0.2+sha.eabb74f
|-- Adafruit BMP280 Library @ 2.6.3
|   |-- Adafruit Unified Sensor @ 1.1.6
|   |-- Adafruit BusIO @ 1.13.1
|   |   |-- Wire @ 2.0.0
|   |   |-- SPI @ 2.0.0
|   |-- Wire @ 2.0.0
|   |-- SPI @ 2.0.0
|-- Adafruit SHT31 Library @ 2.2.0
|   |-- Adafruit BusIO @ 1.13.1
|   |   |-- Wire @ 2.0.0
|   |   |-- SPI @ 2.0.0
|   |-- Wire @ 2.0.0
|-- Adafruit BusIO @ 1.13.1
|   |-- Wire @ 2.0.0
|   |-- SPI @ 2.0.0
|-- Adafruit Unified Sensor @ 1.1.6
|-- WiFi @ 2.0.0
|-- Wire @ 2.0.0

Adafruit Unified Sensorのsensor_tをリネーム

.pio/libdeps配下にある4ファイルのsensor_tsensor_t2にリネームします。

  1. .pio\libdeps\m5stack-timer-cam\Adafruit BMP280 Library\Adafruit_BMP280.h
  2. .pio\libdeps\m5stack-timer-cam\Adafruit BMP280 Library\Adafruit_BMP280.cpp
  3. .pio\libdeps\m5stack-timer-cam\Adafruit Unified Sensor\Adafruit_Sensor.h
  4. .pio\libdeps\m5stack-timer-cam\Adafruit Unified Sensor\Adafruit_Sensor.cpp

結果

ビルド成功

LINE通知ライブラリーの追加

  • platformio.ini
[env:m5stack-timer-cam]
platform = espressif32
board = m5stack-timer-cam
framework = arduino
lib_deps = 
	; m5stack/Timer-CAM
	https://github.com/m5stack/TimerCam-arduino.git#eabb74f
	
	adafruit/Adafruit BMP280 [email protected]^2.6.3
	adafruit/Adafruit SHT31 [email protected]^2.2.0
	adafruit/Adafruit [email protected]^1.13.1
	adafruit/Adafruit Unified [email protected]^1.1.6
	[email protected]^2.0.0

	mobizt/ESP Line Notify

upload_speed = 1500000
monitor_speed = 115200
  • main.cpp
#include <Arduino.h>
#include <WiFi.h>

#include "battery.h"
#include "led.h"
#include "bmm8563.h"

#include "esp_camera.h"
#include "camera_pins.h"

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

#include <ESP_Line_Notify.h>

void setup()
{

}

void loop()
{

}

結果

ビルド成功

このライブラリーは特にエラーにはなりませんでした。バージョンは2.1.0に更新されています。

Dependency Graph
|-- Timer-CAM @ 0.0.2+sha.eabb74f
…省略
|-- ESP Line Notify @ 2.1.0
|   |-- WiFi @ 2.0.0
|   |-- FS @ 2.0.0
|   |-- SPI @ 2.0.0
|   |-- Ethernet @ 2.0.0
|   |   |-- WiFi @ 2.0.0
|   |-- WiFiClientSecure @ 2.0.0
|   |   |-- WiFi @ 2.0.0
|   |-- SD @ 2.0.0
|   |   |-- FS @ 2.0.0
|   |   |-- SPI @ 2.0.0
|   |-- SD_MMC @ 2.0.0
|   |   |-- FS @ 2.0.0
|   |-- SPIFFS @ 2.0.0
|   |   |-- FS @ 2.0.0
…省略

main.cppの実装を追加

去年のコードで実行してみます。

main.cpp
#include <Arduino.h>
#include <WiFi.h>

#include "battery.h"
#include "led.h"
#include "bmm8563.h"

#include "esp_camera.h"
#include "camera_pins.h"

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

#include <ESP_Line_Notify.h>

const char *ssid = "xxxxxxxxxx";
const char *password = "xxxxxxxxxx";

const char *line_token = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

// int sleep_time = 15 * 60;
int sleep_time = 10;

#define ENV_I2C_SDA 4
#define ENV_I2C_SCL 13

#define BM8563_I2C_SDA 12
#define BM8563_I2C_SCL 14

float tmp = 0.0;
float hum = 0.0;
float pressure = 0.0;

Adafruit_BMP280 bme = Adafruit_BMP280(&Wire);
Adafruit_SHT31 sht3x = Adafruit_SHT31(&Wire);

LineNotiFyClient line;

String message = "";

void enterSleep()
{
  Serial.println("Enter Sleep! Wake Up after " + String(sleep_time) + " Sec.");
  delay(500);
  Wire.begin(BM8563_I2C_SDA, BM8563_I2C_SCL);
  delay(500);

  bmm8563_init();
  bmm8563_setTimerIRQ(sleep_time);

  bat_disable_output();

  esp_deep_sleep(sleep_time * 1000 * 1000);
  esp_deep_sleep_start();
}

void setup()
{
  Serial.begin(115200);
  Serial.setDebugOutput(true);
  Serial.println();

  bat_init();

  led_init(CAMERA_LED_GPIO);

  Wire.begin(ENV_I2C_SDA, ENV_I2C_SCL);
  while (!bme.begin(0x76))
  {
    Serial.println("Could not find a valid BMP280 sensor, check wiring!");
  }
  while (!sht3x.begin(0x44))
  {
    Serial.println("Could not find a valid SHT3X sensor, check wiring!");
  }

  pressure = bme.readPressure();
  tmp = sht3x.readTemperature();
  hum = sht3x.readHumidity();

  message = "\r\nきおん" + String(tmp) + "℃\r\n" +
            "しつど" + String(hum) + "%\r\n" +
            "きあつ" + String((int)pressure / 100) + "hPa\r\n" +
            "バッテリー" + String(bat_get_voltage()) + "mv";

  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;
  config.frame_size = FRAMESIZE_UXGA;
  config.jpeg_quality = 10;
  config.fb_count = 2;

  // camera init
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK)
  {
    Serial.printf("Camera init failed with error 0x%x", err);
    return;
  }

  sensor_t *s = esp_camera_sensor_get();
  // initial sensors are flipped vertically and colors are a bit saturated
  s->set_vflip(s, 1);       // flip it back
  s->set_brightness(s, 1);  // up the blightness just a bit
  s->set_saturation(s, -2); // lower the saturation

  // drop down frame size for higher initial frame rate
  s->set_framesize(s, FRAMESIZE_SXGA);

  Serial.printf("Connect to %s, %s\r\n", ssid, password);

  WiFi.begin(ssid, password);

  int count = 0;
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
    count++;
    if (count > 20)
    {
      enterSleep();
    }
  }
  Serial.println("");
  Serial.println("WiFi connected");
}

/* Function to print the sending result via Serial */
void printRessult(LineNotifySendingResult result)
{
  if (result.status == LineNotify_Sending_Success)
  {
    Serial.printf("Status: %s\n", "success");
    Serial.printf("Text limit: %d\n", result.quota.text.limit);
    Serial.printf("Text remaining: %d\n", result.quota.text.remaining);
    Serial.printf("Image limit: %d\n", result.quota.image.limit);
    Serial.printf("Image remaining: %d\n", result.quota.image.remaining);
    Serial.printf("Reset: %d\n", result.quota.reset);
  }
  else if (result.status == LineNotify_Sending_Error)
  {
    Serial.printf("Status: %s\n", "error");
    Serial.printf("error code: %d\n", result.error.code);
    Serial.printf("error msg: %s\n", result.error.message.c_str());
  }
}

void loop()
{
  // put your main code here, to run repeatedly:

  camera_fb_t *fb = NULL;
  fb = esp_camera_fb_get();

  if (!fb)
  {
    Serial.println("Camera capture failed");
    return;
  }

  Serial.println("capture complete");

  line.reconnect_wifi = true;
  line.token = line_token;
  line.message = message.c_str();

  line.image.data.blob = fb->buf;
  line.image.data.size = fb->len;
  line.image.data.file_name = "camera.jpg";

  Serial.println(message);

  LineNotifySendingResult result = LineNotify.send(line);
  printRessult(result);

  esp_camera_fb_return(fb);

  enterSleep();
}

結果

ビルド失敗

src/main.cpp:39:1: error: 'LineNotiFyClient' does not name a type; did you mean 'LineNotifyClient'?
 LineNotiFyClient line;
 ^~~~~~~~~~~~~~~~
 LineNotifyClient
src/main.cpp: In function 'void loop()':
src/main.cpp:184:3: error: 'line' was not declared in this scope
   line.reconnect_wifi = true;
   ^~~~
src/main.cpp:184:3: note: suggested alternative: 'link'
   line.reconnect_wifi = true;
   ^~~~
   link
*** [.pio\build\m5stack-timer-cam\src\main.cpp.o] Error 1
======================================= [FAILED] Took 10.91 seconds =======================================

LineNotiFyClientLineNotifyClientに変更されていますので、ここを修正すると、ビルド成功します。

typoが修正されたようです

LINE Notifyトークンの発行

久しぶりにやるとやり方がわからなくなったので備忘録

  1. https://notify-bot.line.me/login にアクセス
  2. ログイン
  3. マイページ( https://notify-bot.line.me/my/ )へ遷移
  4. アクセストークンの発行(開発者向け) からトークンを発行

LINE Notify便利です。

実行結果

成功しました。

image.png

それにしても暑い😫

ソースコード

platformio.ini
[env:m5stack-timer-cam]
platform = espressif32
board = m5stack-timer-cam
framework = arduino
lib_deps = 
	; m5stack/Timer-CAM
	https://github.com/m5stack/TimerCam-arduino.git#eabb74f
	
	adafruit/Adafruit BMP280 [email protected]^2.6.3
	adafruit/Adafruit SHT31 [email protected]^2.2.0
	adafruit/Adafruit [email protected]^1.13.1
	adafruit/Adafruit Unified [email protected]^1.1.6
	[email protected]^2.0.0

	mobizt/ESP Line [email protected]^2.1.0

upload_speed = 1500000
monitor_speed = 115200
main.cpp
#include <Arduino.h>
#include <WiFi.h>

#include "battery.h"
#include "led.h"
#include "bmm8563.h"

#include "esp_camera.h"
#include "camera_pins.h"

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

#include <ESP_Line_Notify.h>

const char *ssid = "xxxxxxxxxx";
const char *password = "xxxxxxxxxx";

const char *line_token = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";

// int sleep_time = 15 * 60;
int sleep_time = 10;

#define ENV_I2C_SDA 4
#define ENV_I2C_SCL 13

#define BM8563_I2C_SDA 12
#define BM8563_I2C_SCL 14

float tmp = 0.0;
float hum = 0.0;
float pressure = 0.0;

Adafruit_BMP280 bme = Adafruit_BMP280(&Wire);
Adafruit_SHT31 sht3x = Adafruit_SHT31(&Wire);

LineNotifyClient line;

String message = "";

void enterSleep()
{
  Serial.println("Enter Sleep! Wake Up after " + String(sleep_time) + " Sec.");
  delay(500);
  Wire.begin(BM8563_I2C_SDA, BM8563_I2C_SCL);
  delay(500);

  bmm8563_init();
  bmm8563_setTimerIRQ(sleep_time);

  bat_disable_output();

  esp_deep_sleep(sleep_time * 1000 * 1000);
  esp_deep_sleep_start();
}

void setup()
{
  Serial.begin(115200);
  Serial.setDebugOutput(true);
  Serial.println();

  bat_init();

  led_init(CAMERA_LED_GPIO);

  Wire.begin(ENV_I2C_SDA, ENV_I2C_SCL);
  while (!bme.begin(0x76))
  {
    Serial.println("Could not find a valid BMP280 sensor, check wiring!");
  }
  while (!sht3x.begin(0x44))
  {
    Serial.println("Could not find a valid SHT3X sensor, check wiring!");
  }

  pressure = bme.readPressure();
  tmp = sht3x.readTemperature();
  hum = sht3x.readHumidity();

  message = "\r\nきおん" + String(tmp) + "℃\r\n" +
            "しつど" + String(hum) + "%\r\n" +
            "きあつ" + String((int)pressure / 100) + "hPa\r\n" +
            "バッテリー" + String(bat_get_voltage()) + "mv";

  camera_config_t config;
  config.ledc_channel = LEDC_CHANNEL_0;
  config.ledc_timer = LEDC_TIMER_0;
  config.pin_d0 = Y2_GPIO_NUM;
  config.pin_d1 = Y3_GPIO_NUM;
  config.pin_d2 = Y4_GPIO_NUM;
  config.pin_d3 = Y5_GPIO_NUM;
  config.pin_d4 = Y6_GPIO_NUM;
  config.pin_d5 = Y7_GPIO_NUM;
  config.pin_d6 = Y8_GPIO_NUM;
  config.pin_d7 = Y9_GPIO_NUM;
  config.pin_xclk = XCLK_GPIO_NUM;
  config.pin_pclk = PCLK_GPIO_NUM;
  config.pin_vsync = VSYNC_GPIO_NUM;
  config.pin_href = HREF_GPIO_NUM;
  config.pin_sscb_sda = SIOD_GPIO_NUM;
  config.pin_sscb_scl = SIOC_GPIO_NUM;
  config.pin_pwdn = PWDN_GPIO_NUM;
  config.pin_reset = RESET_GPIO_NUM;
  config.xclk_freq_hz = 20000000;
  config.pixel_format = PIXFORMAT_JPEG;
  config.frame_size = FRAMESIZE_UXGA;
  config.jpeg_quality = 10;
  config.fb_count = 2;

  // camera init
  esp_err_t err = esp_camera_init(&config);
  if (err != ESP_OK)
  {
    Serial.printf("Camera init failed with error 0x%x", err);
    return;
  }

  sensor_t *s = esp_camera_sensor_get();
  // initial sensors are flipped vertically and colors are a bit saturated
  s->set_vflip(s, 1);       // flip it back
  s->set_brightness(s, 1);  // up the blightness just a bit
  s->set_saturation(s, -2); // lower the saturation

  // drop down frame size for higher initial frame rate
  s->set_framesize(s, FRAMESIZE_SXGA);

  Serial.printf("Connect to %s, %s\r\n", ssid, password);

  WiFi.begin(ssid, password);

  int count = 0;
  while (WiFi.status() != WL_CONNECTED)
  {
    delay(500);
    Serial.print(".");
    count++;
    if (count > 20)
    {
      enterSleep();
    }
  }
  Serial.println("");
  Serial.println("WiFi connected");
}

/* Function to print the sending result via Serial */
void printRessult(LineNotifySendingResult result)
{
  if (result.status == LineNotify_Sending_Success)
  {
    Serial.printf("Status: %s\n", "success");
    Serial.printf("Text limit: %d\n", result.quota.text.limit);
    Serial.printf("Text remaining: %d\n", result.quota.text.remaining);
    Serial.printf("Image limit: %d\n", result.quota.image.limit);
    Serial.printf("Image remaining: %d\n", result.quota.image.remaining);
    Serial.printf("Reset: %d\n", result.quota.reset);
  }
  else if (result.status == LineNotify_Sending_Error)
  {
    Serial.printf("Status: %s\n", "error");
    Serial.printf("error code: %d\n", result.error.code);
    Serial.printf("error msg: %s\n", result.error.message.c_str());
  }
}

void loop()
{
  // put your main code here, to run repeatedly:

  camera_fb_t *fb = NULL;
  fb = esp_camera_fb_get();

  if (!fb)
  {
    Serial.println("Camera capture failed");
    return;
  }

  Serial.println("capture complete");

  line.reconnect_wifi = true;
  line.token = line_token;
  line.message = message.c_str();

  line.image.data.blob = fb->buf;
  line.image.data.size = fb->len;
  line.image.data.file_name = "camera.jpg";

  Serial.println(message);

  LineNotifySendingResult result = LineNotify.send(line);
  printRessult(result);

  esp_camera_fb_return(fb);

  enterSleep();
}