PR

【現在制作中】ESP32でLINE通知するドアスイッチ作ってみた

開閉センサイメージ 組み込み機器

本記事ではESP32でLINE通知するドアスイッチの制作過程を記しています。
不明な点などあればお気軽にコメントどうぞ!

立プロ

新卒でメーカーに入り、10年間組み込みの現場で設計を行う。
今は個人事業主として自作の組み込み機器開発や、エージェント様に紹介いただき業務委託を行っています。
C,C#,JavaScript, Vue, PHP, VBA, GAS, Kotlinなど、扱う言語が増えゆく日々。

立プロをフォローする

完成イメージ

開閉センサイメージ

購入部品

M5stamp picoについて

切手サイズのマイコンで省電力に特化。

ボード自身にJTAGを持たないので、外付けのダウンローダーが必要

CPUはEspressif ESP32-PICO-D4を使用。ちなみにM5 atomもこのマイコンを使用。

M5stamp用のボード定義が必要になる。

技適有り

12個のピンが使用できるが、SPI、I2C、UARTとの共用。

参考文献

M5stamp 中国語マニュアル

M5stamp 製品仕様

esp32-pico-d4_datasheet_en

esp32 レジスタ情報(英語データシート)

想定用途

子どもの帰宅確認

防犯チェック

薬箱開けて飲んだかチェック

競合製品

差別化になりうる要素

指定秒数超えたらブザーを鳴らす

ON/OFF切り替わりのタイミングで子機ブザーに信号送って鳴らすCalltoUで実現済み、これ便利やな)

電源をどこから取るか問題

制作1日目。

部品選定やら設計構想を考えて購入。電源をどこからどのように取るかの判断がつかない…。

開発環境の整備

制作2日目、モノは届いてないが、開発環境だけ整えておく。

PlatformIOでM5stamp picoを探すも見つからない…調べたところ定義されていなかった。

QiitaにてM5stamp picoの定義情報を作る記事が大変参考になりました、ありがとうございます。
PlatformIOにM5Stamp Picoのボード定義を追加してみた

ボード定義とピン配列定義が必要とのこと。(以下参考記事をコピペさせていただいてます)

ボード定義

%UserProfile%\.platformio\platforms\espressif32\boardsにstamp-pico.jsonを追加。

後述しますが、M5stampはM5atomと同じマイコン使用なので、M5atomのvariantキーとnameキーをそれぞれ変更しているだけになります。

{
  "build": {
    "arduino":{
      "ldscript": "esp32_out.ld"
    },
    "core": "esp32",
    "extra_flags": "-DARDUINO_STAMP_PICO",
    "f_cpu": "240000000L",
    "f_flash": "40000000L",
    "flash_mode": "dio",
    "mcu": "esp32",
    "variant": "stamp_pico"
  },
  "connectivity": [
    "wifi",
    "bluetooth",
    "ethernet",
    "can"
  ],
  "frameworks": [
    "arduino",
    "espidf"
  ],
  "name": "STAMP-PICO",
  "upload": {
    "flash_size": "4MB",
    "maximum_ram_size": 327680,
    "maximum_size": 4194304,
    "require_upload_port": true,
    "speed": 1500000
  },
  "url": "http://www.m5stack.com",
  "vendor": "M5Stack"
}

ピン配列定義

%UserProfile%\.platformio\packages\framework-arduinoespressif32\variantsにstamp_picoというディレクトリを作成し、その中にpins_arduino.hを追加。

M5atomとピン配列が違うので注意(これが原因でボード定義が必要になっている)。

差分としては、

  • I2Cのピン配置が異なる 26/32 ⇒ 21/22
  • UARTの2chがstampには無い
  • SPIのピン配置が異なる 19/33/23/22 ⇒ 19/26/36/18
  • I/Oもばらばら
  • ADCの3chがstampには無い&1ch/2chのピン配置が異なる

んー…M5stamp picoにM5atomボード定義を使うのは実質無理やね

#ifndef Pins_Arduino_h
#define Pins_Arduino_h

#include <stdint.h>

#define EXTERNAL_NUM_INTERRUPTS 16
#define NUM_DIGITAL_PINS        40
#define NUM_ANALOG_INPUTS       16

#define analogInputToDigitalPin(p)  (((p)<20)?(esp32_adc2gpio[(p)]):-1)
#define digitalPinToInterrupt(p)    (((p)<40)?(p):-1)
#define digitalPinHasPWM(p)         (p < 34)

static const uint8_t TX = 1;
static const uint8_t RX = 3;

static const uint8_t SDA = 21;
static const uint8_t SCL = 22;

static const uint8_t SS    = 19;
static const uint8_t MOSI  = 26;
static const uint8_t MISO  = 36;
static const uint8_t SCK   = 18;

static const uint8_t G21 = 21;
static const uint8_t G22 = 22;
static const uint8_t G19 = 19;
static const uint8_t G26 = 26;
static const uint8_t G36 = 36;
static const uint8_t G18 = 18;
static const uint8_t G25 = 25;
static const uint8_t G32 = 32;
static const uint8_t G33 = 33;
static const uint8_t G1 = 1;
static const uint8_t G3 = 3;
static const uint8_t G0 = 0;

static const uint8_t DAC1 = 25;
static const uint8_t DAC2 = 26;

static const uint8_t ADC1 = 32;
static const uint8_t ADC2 = 33;
static const uint8_t ADC3 = 36;

#endif /* Pins_Arduino_h */

M5stampへのソフト書き込み&LINE通知

制作3日目、M5stampが到着。

とりあえずPC-ダウンローダ-M5stampの接続で、ROM書くのは何なくクリア。

家のWIFIネットワークからLINE通知させることもできた。

LINE通知は別記事にまとめたので気になる方はこちらをどうぞ。

明日、リードスイッチ他すべて揃う予定で本格的に動き始めます。

筐体に入れてみる

制作4日目、部材が届く。

M5stampを箱におさめてモバイルバッテリーから給電できるようにした。

電源入ってLINE通知飛ぶし、モノで見ると完成イメージが沸きますねえ。

またリードスイッチの動作確認。

はじめて使う部品でどう動くのが正しいか分かってないが、磁場の検知はスイッチ近くではなく足でやるのだろうか?

足周辺の磁場感度が非常に良い、どのサンプルも同じ挙動。

とりあえずAmazonレビュー書いといた。
https://www.amazon.co.jp/gp/customer-reviews/RYFFX57PG9DSV/ref=cm_cr_dp_d_rvw_ttl?ie=UTF8&ASIN=B08CMNYN79

…けど足で検出するのであれば、ダイオードみたいに一方の足が長くてもよいような。

GROVEコネクタをI2C用として使いたい

制作5日目。

将来的な構想としてI2Cでセンサ信号の送受信を考えており、それをふまえてどう設計するか考える。

通常I2Cは21/22の側面のピンに割り当てられているが、どう考えてもVcc, GND, I/O*2(32,33)のGROVEコネクタを使うのが便利としか思えない。

調べたところWire関数にてI/OをI2CのSCL,SDAに変換できるとのこと。

これをsetup関数に入れるわけだが、ただはじめにWire.end()をかませないとbeginで設定できなかった。

Wire.end();
Wire.begin(32, 33);  // Grove端子をI2C通信に設定(SDA, SCL)

たったこれだけでI/OをI2Cとして利用できる、すごい。めちゃ便利。

手元にあったENV Ⅲユニットをつなげて、問題なく受信できることも確認しました。通信はできたから、後はどう表示するか。これやりだすと本筋を脱線するので追々詰める。

DeepSleep設定する

DeepSleepには外部信号、タイマ、タッチパッド、ULP(ESP32のコプロセッサ)の4つから選択できる。

サンプルコードはこちら。

RTC_DATA_ATTR int bootCount = 0;

//Method to print the reason by which ESP32 has been awaken from sleep
void print_wakeup_reason(){
  esp_sleep_wakeup_cause_t wakeup_reason;
  wakeup_reason = esp_sleep_get_wakeup_cause();
  switch(wakeup_reason){
    case ESP_SLEEP_WAKEUP_EXT0 : Serial.println("Wakeup caused by external signal using RTC_IO"); break;
    case ESP_SLEEP_WAKEUP_EXT1 : Serial.println("Wakeup caused by external signal using RTC_CNTL"); break;
    case ESP_SLEEP_WAKEUP_TIMER : Serial.println("Wakeup caused by timer"); break;
    case ESP_SLEEP_WAKEUP_TOUCHPAD : Serial.println("Wakeup caused by touchpad"); break;
    case ESP_SLEEP_WAKEUP_ULP : Serial.println("Wakeup caused by ULP program"); break;
    default : Serial.printf("Wakeup was not caused by deep sleep: %d\n",wakeup_reason); break;
  }
}


// put function declarations here:
int myFunction(int, int);

void setup() {
  Serial.begin(115200);


  //Increment boot number and print it every reboot
  ++bootCount;
  Serial.println("Boot number: " + String(bootCount));

  //Print the wakeup reason for ESP32
  print_wakeup_reason();

  esp_sleep_enable_ext0_wakeup(GPIO_NUM_25,1); //1 = High, 0 = Low

  Serial.println("Going to sleep now");
  esp_deep_sleep_start();
  Serial.println("This will never be printed");
}

RTC_DATA_ATTRはRTCスローメモリと呼ばれるdeepsleep中でも値が消えないメモリ領域のようで、そこにリブート回数を保存させてます。

print_wakeup_reason関数で復帰要因の確認。esp_sleep_get_wakeup_cause関数から復帰要因を引っ張り出せる。

esp_sleep_enable_ext0_wakeup関数で復帰設定。上記コードでは25番ピンがHighになったときに復帰する、という設定になっている。

esp_sleep.hを見てもらうと分かりますが、復帰に使えるピンは制限されていて、0,2,4,12-15,25-27,32-39のみになってます

esp_deep_sleep_start関数でDeepSleepに入る。復帰したらsetup関数が呼び出されます(=実質の初期化)

DeepSleepして復帰して、を繰り返すとこんな出力になりますよ。

Boot number: 1
Wakeup was not caused by deep sleep: 0
Going to sleep now

rst:0x5 (DEEPSLEEP_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
Boot number: 2
Wakeup caused by external signal using RTC_IO
Going to sleep now

rst:0x5 (DEEPSLEEP_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)

Boot number: 3
Wakeup caused by external signal using RTC_IO
Going to sleep now

rst:0x5 (DEEPSLEEP_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
Boot number: 4
Wakeup caused by external signal using RTC_IO
Going to sleep now

復帰に使うピンを内部プルアップしたい

こんな感じで内部プルアップ設定できる。

pinMode(25,INPUT_PULLUP);

初期設定はどうなっているのか、そして抵抗値はいくつか。

データシートを参照すると、抵抗値は標準状態で45kΩ、初期値は分からん…どこを参照すればよいのやら。

製品化は困難であることを知る

完成に近づいてきたから製品化できるかなあ、と思ったが甘かった。

商工会にとりあえず相談に行ったら、特許だ、法律だ、販路どうするんだ、生産体制は…個人製作だからそこまで考えてないよお…メーカーの時散々やってきたのに、いざ自分でやるとすっかり忘れる始末。

けどたしかに特許侵害とPL法は特に注意しないと、一発で人生終わる。

体験キットとして売り出すか。使用は自己責任で、的な。

ちょっと用意しますわ。また更新します。

コメント

タイトルとURLをコピーしました