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%としました。そんないい加減な、という方もいらっしゃるでしょうが、まあ、自分で使う範囲では、いまのところ問題ないと思います。バッテリーが劣化してきたら使えなくなるかもしれませんが。なお、バッテリーの放電時の電圧測定は、下記の記事でも書いてありますので、興味のある方はどうぞ。
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...");
}