Gameran blog

日常の気になったことなどを書いていきます。ご参考になれば幸いです。

IOT

ESP32C3でバッテリーを使って振動検知してLineに通知してDeepSleepする

投稿日:

ESP32C3でバッテリーを使って、振動を検知してLineに通知してみました。通知後、すぐにDeepSleepするようにしたので、一度充電しておけば、単独で何か月かは稼働するかと思います。なお、Arduino IDEでスケッチを作成しました。
使用場所は、郵便受けに貼り付けて配達の監視に使ったり、見守り用途ではドアや戸棚に貼り付けて検知したり、と思っています。

(注意)本内容を参照して実行することは全て自己責任となります。




ハードウエア

Xiao ESP32C3に、バッテリーと振動センサをつないでケースに入れました。
・バッテリー・・・EEMB LP553454 (1050mAh)
・振動センサー・・・ SW-18010P
・ケース・・・MINTIA
・抵抗 3本

ESP32C3の左にある黒い筒が振動センサーです。ESP32の上にある白いのは、ESP32C3を固定するための消しゴムです。あと、ESP32C3の下に抵抗が3本隠れています。センサーのプルアップに1kΩを1本と、バッテリー電圧を測定するために分圧用に220kΩを2本です。

MINTIAのケースを使用したら、充電時やスケッチ修正時には取り出し口にUSBを接続できて大変便利です。充電後は、USBケーブルを外して両面テープでMINTIAを検知したい場所に貼り付けておくだけで、LINEに通知されます。

振動センサーの接続

振動センサーは、シリーズの中では最も感度の高いセンサーを買いました。10本で数百円。
プルアップ抵抗を1kΩをいれて、d4ピンに接続します。あとは、d4ピンがlowレベルになったら起こしてねと宣言してDeepSleepスタートして眠るだけです。(全スケッチは、本ページ最後に)

      esp_deep_sleep_enable_gpio_wakeup(BIT(D3), ESP_GPIO_WAKEUP_GPIO_LOW);
      delay(1000); //Take some time to open up the Serial Monitor
      esp_deep_sleep_start();

バッテリー電圧の測定

バッテリーの状態を見ることは重要です。過放電状態は避けなければなりません。そのため、電圧を測定して、スマホからBluetooth経由で確認したり、LINEに通知するようにします。ESP32Cへの接続は、バッテリーの+端子を220kΩの抵抗経由でD0ピンに接続し、そこからまた220kΩの抵抗で0Vに接続することで測定します。残量が何%かの計算は、4.1Vを100%、3.3Vを0%としました。そんないい加減な、という方もいらっしゃるでしょうが、まあ、自分で使う範囲では、いまのところ問題ないと思います。バッテリーが劣化してきたら使えなくなるかもしれませんが。なお、バッテリーの放電時の電圧測定は、下記の記事でも書いてありますので、興味のある方はどうぞ。

  ESP32C3でバッテリーをつないでみた

 

LINEへの通知

PCでLine Notifyのサイトからトークンを取得するなどの準備が必要です。その辺は詳しく書いてあるサイトがたくさんあるので、ここでは割愛します。振動でDeepSleepから起こされますので、setup()の中でLINEに通知します。この通知時には、バッテリーの残量も通知するようにして充電時期を逃さないようにしました。

BlueTooth LEの接続

バッテリーで動作するものなので、ちょっとUSBでPCを接続してみるというのも、面倒な時があります。そのため、BlueTooth LEを接続しました。スマホ側はSerial Bluetooth Terminalというアプリを使いました。接続時にwifiが接続されたか、LINEの送信のstatusはどうだったか、とか確認できます。また、振動センサー検知でWake upして、LINE通知して、また、DeepSleepするという動きなのですが、振動センサーの動きの確認をしたいときもあります。そのため、通常の状態をsleep modeとし、もう一つの状態をnon-sleep modeとし、DeepSleepに入らない状態を準備しました。non-sleep modeへの切り替えは、センサーを検知してから20秒後のDeepSleepまでの間に、スマホから「non」と送ることで実行できます。そのときに振動を与えると、「!!センサー検知!!」と表示されることでセンサーの動作を確認できます。その後、sleep modeに戻るにはスマホから「sleep」と送ると20秒後にDeepSleepします。

スケッチ

最後に今回使用したスケッチを載せておきます。

#include <WiFi.h>
#include <HTTPClient.h>
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

const char* ssid = "Buffa**********";   //ssid
const char* passwd = "**************"; //ネットワークパスワード
const int sensorPin = D3;     // sensor connected to digital pin 

// LINE Notify設定
String LINE_NOTIFY_TOKEN = "********************************************************";

//BLE server
BLEServer *pServer = NULL;
BLECharacteristic * pTxCharacteristic;
bool deviceConnected = false;
bool oldDeviceConnected = false;
uint8_t txValue = 0;
#define SERVICE_UUID           "6be41***-****-****-****-************" // UART service UUID
#define CHARACTERISTIC_UUID_RX "6be41***-****-****-****-************"
#define CHARACTERISTIC_UUID_TX "6be41***-****-****-****-************"

bool sleepMode = true;

void mySerial(String txdata,bool lineFeed = true){
  if(lineFeed)txdata +="\n";
  Serial.print(txdata);
  if (deviceConnected) {
     pTxCharacteristic->setValue(txdata.c_str());
     pTxCharacteristic->notify();
  }
}

class MyBLEServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer)    {deviceConnected = true;};
    void onDisconnect(BLEServer* pServer) {deviceConnected = false;}
};

class MyBLECallbacks: public BLECharacteristicCallbacks {
  void onWrite(BLECharacteristic *pCharacteristic) {
    String rx = pCharacteristic->getValue();
    if (rx.length() > 0) {
      mySerial("recieved : " + rx ,false);
      
      if (rx.substring(0,5).equalsIgnoreCase("sleep")){
        sleepMode = true;
      }else if (rx.substring(0,3).equalsIgnoreCase("non")){
        sleepMode = false;
      }

      //ピンAOの電圧測定
      mySerial(measureBAT());

      //guidance
      if(sleepMode){
        mySerial("【 sleep Mode 】" );
        mySerial("input \"non\" for Mode change ");
      }else{
        mySerial("【 non-sleep Mode 】");
        mySerial("input \"sleep\" for Mode change ");
      }
      mySerial("");
    } 
  }
};

void setup(){
  Serial.begin(115200);
  bleSetup();   //BLEのセットアップ
  pinMode(A0, INPUT);pinMode(A1, INPUT);         // ADC
  pinMode(sensorPin, INPUT);
  delay(1000); //Take some time to open up the Serial Monitor
  
  mySerial("ESP32 Wake Up");
  WiFi.begin(ssid, passwd);               //アクセスポイント接続のためのIDとパスワードの設定
  while (WiFi.status() != WL_CONNECTED) { //接続状態の確認
  delay(300);                             //接続していなければ0.3秒待つ
  mySerial(".",false);                      //接続しなかったらシリアルモニタに「.」と表示
  }
  mySerial("WiFi Connected"); //接続したらシリアルモニタに「WiFi Connected」と表示

  String batterymsg =measureBAT();
  String linemsg = "!!センサー検知!!\r\n";
  linemsg += batterymsg ;
  mySerial(linemsg);
  sendLine(linemsg) ;
}

void loop(){

  unsigned long time;
  time = millis();

  if(sleepMode){
    mySerial("【 sleep Mode 】" );
    mySerial("Going to sleep 20sec later");
    mySerial("input \"non\" for Mode change ");
    mySerial("");

    delay(20000); //Take some time to open up the Serial Monitor
    if(sleepMode){
      mySerial("Going to sleep now");
      esp_deep_sleep_enable_gpio_wakeup(BIT(D3), ESP_GPIO_WAKEUP_GPIO_LOW);
      delay(1000); //Take some time to open up the Serial Monitor
      esp_deep_sleep_start();
      mySerial("This will never be printed");
    }
  }

  static int presensor0 = 1;
  int sensor0 = digitalRead(sensorPin);
  if (sensor0 ==0 && presensor0 ==1){
      mySerial("センサー検知 " +String(millis()));
      delay(1000);
  }
  presensor0 = sensor0;


  // BLE disconnecting
  if (!deviceConnected && oldDeviceConnected) {
      delay(500); // give the bluetooth stack the chance to get things ready
      pServer->startAdvertising(); // restart advertising
      mySerial("start advertising");
      oldDeviceConnected = deviceConnected;
  }
  // BLE connecting
  if (deviceConnected && !oldDeviceConnected) {
      delay(1000); 
      oldDeviceConnected = deviceConnected;
  }  
}

// line通知
void sendLine(String body){ 
  HTTPClient httpClient;
  String postUrl = "https://notify-api.line.me/api/notify";
  httpClient.begin(postUrl);
  httpClient.addHeader("Content-Type", "application/x-www-form-urlencoded");
  httpClient.addHeader("Authorization", "Bearer " + LINE_NOTIFY_TOKEN);
  // POSTしてステータスコードを取得
  int status_code = httpClient.POST("message=" + body);
  mySerial(httpClient.getString());
  if (status_code == 200) {
    mySerial("[SUCCESS]LINE Notify ");
  } else  {
    mySerial("[SUCCESS]LINE Notify (URL:" +postUrl + ")Code:"+ status_code);
  }
  mySerial(""); 
  httpClient.end();  // HTTPClinetを終了する
}

String measureBAT(){
  uint32_t Vbatt = 0;
  int mCounter =16;
  for(int i = 0; i < mCounter; i++) {
    Vbatt = Vbatt + analogReadMilliVolts(D0); // ADC with correction   
  }
  int Vbattf = Vbatt / mCounter;

  float v0 = 2.0f * Vbattf /1000;
  int batRemain = (v0 -3.3)/(4.1-3.3) *100;
  String msg = "Battery:";
  msg += String(batRemain) +"パーセント";
  msg += " (" + String(v0,2) +"V)";
  return msg;
}

void bleSetup(){
  // Create the BLE Device
  BLEDevice::init("myESP32_UART2");  //スマホなどのBLEターミナルから見えるデバイス名

  // Create the BLE Server
  pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyBLEServerCallbacks());

  // Create the BLE Service
  BLEService *pService = pServer->createService(SERVICE_UUID);

  // Create a BLE Characteristic
  pTxCharacteristic = pService->createCharacteristic(
										CHARACTERISTIC_UUID_TX,
										BLECharacteristic::PROPERTY_NOTIFY
									);
                      
  pTxCharacteristic->addDescriptor(new BLE2902());

  BLECharacteristic * pRxCharacteristic = pService->createCharacteristic(
											 CHARACTERISTIC_UUID_RX,
											BLECharacteristic::PROPERTY_WRITE
										);

  pRxCharacteristic->setCallbacks(new MyBLECallbacks());

  // Start the service
  pService->start();

  // Start advertising
  pServer->getAdvertising()->start();
  mySerial("Waiting a client connection to notify...");
}

-IOT
-, , , , , ,

執筆者:


comment

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

関連記事

ESP32C3でバッテリーをつないでみた

ESP32C3をバッテリーをつないで何かをしようと思ったのですが、つないだときの扱い?がよく判らないので、充放電の状況を確認してみました。 (注意)バッテリーは扱いを間違えると危険ですので真似をしない …

ESP32でGoogle sheetとLineに水耕栽培の水温と流量を通知して管理する方法【ハードウェア】

最近、水耕栽培を始めました。水耕栽培は水の管理が大切なのですが、なかなか大変です。もっと簡単に水を管理したいと思い、今回の方法を考えました。 何をしたいかは本編に記載しています。本記事ではハードウェア …

ESP32でGoogle sheetとLineに水耕栽培の水温と流量を通知して管理する方法【スケッチ(後編)】

最近、水耕栽培を始めました。水耕栽培は水の管理が大切なのですが、なかなか大変です。もっと簡単に水を管理したいと思い、今回の方法を考えました。 本記事は後編です。前編(スケッチ含む)はこちら。 前編・・ …

ESP32でGoogle sheetとLineに水耕栽培の水温と流量を通知して管理する方法【本編】

最近、水耕栽培を始めました。水耕栽培は水の管理が大切なのですが、なかなか大変です。もっと簡単に水を管理したいと思い、今回の方法を考えました。 やっている水耕栽培は図のようにタンクに水を入れ、そこから上 …

ESP32でGoogle sheetとLineに水耕栽培の水温と流量を通知して管理する方法【スケッチ(前編)】

最近、水耕栽培を始めました。水耕栽培は水の管理が大切なのですが、なかなか大変です。もっと簡単に水を管理したいと思い、今回の方法を考えました。 何をしたいかは本編に記載しています。本記事ではスケッチにつ …