LoginSignup
0
0

ESP32で鍵閉め忘れ防止装置を作る

Last updated at Posted at 2024-04-13

明日,昨日の自分がなにをどこまでどうやったのか思い出すために

やりたいこと

  • PCとESP32をシリアル通信させたい
  • センサーが一定の距離以下の値を検知したらteamsに通知を投稿させたい

使うものとか実行環境とか

  • ESP32 WROOM
  • 距離センサGP2Y0E03
  • WSL vscode
  • Arudino IDE
    とりあえず最新版入れとけばええやろ,知らんけど.

準備

ESP32側

を参考にしまくる
ちなみにESP32のSDAとSCLのピンアサインを確認すると、SDAはGPIO21、SCLはGPIO22に割り当てられてている.そのようにつなげ

少し手を加えて

isDoorLocked.ino
#include <Wire.h>
//アドレス指定
#define GP2Y0E03_ADDR 0x40
#define DISTANCE_ADDR 0x5E

void setup()
{
  Serial.begin(9600);//シリアル通信を9600bpsで初期化
  Wire.begin();//I2Cを初期化

  delay(500);//500msec待機(0.5秒待機)
}

void loop() {
  //変数宣言
  unsigned int dac[2];
  unsigned int i, distance;

  Wire.beginTransmission(GP2Y0E03_ADDR);//I2Cスレーブ「Arduino Uno」のデータ送信開始
  Wire.write(DISTANCE_ADDR);//距離の測定
  Wire.endTransmission();//I2Cスレーブ「Arduino Uno」のデータ送信終了

  Wire.requestFrom(GP2Y0E03_ADDR, 2);//I2Cデバイス「GP2Y0E03」に2Byteのデータ要求
  for (i=0; i<2; i++){
    dac[i] = Wire.read();//dacにI2Cデバイス「GP2Y0E03」のデータ読み込み
  }
  Wire.endTransmission();//I2Cスレーブ「Arduino Uno」のデータ送信終了

  distance = ((dac[0]*16+dac[1]) / 16) / (2*2);//距離(cm)を計算

  if (distance <= 15) {
    Serial.println("The key was Locked!!");
  } else {
    Serial.println("The key is not locked");
  }

    delay(1000); // 1000msec待機(1秒待機)
}

PC側

チームに投稿するシェルスクリプトを作る

ms teamsで適当なチームを作り,適当なチャネルでwebhookを設定する
それに向かってHTTPリクエストするシェルスクリプトを書く

これを読めばすべてわかる

post_notice.sh
#!/bin/bash
# プロキシ環境下で実行する場合は適宜設定
# export https_proxy=http://aaa.bbb.ccc:nnnn

# WebフックURL(※事前準備で発行したURLを設定する)
WEBHOOK_URL='https:hogehogehoge

# curlコマンド実行
curl -H "Content-Type: application/json" -d "{\"text\":hogehogehoge \"\"}" $WEBHOOK_URL

こいつ単体で実行してみるといい感じに動いた
スクリーンショット 2024-03-05 192444.png

ESPからのシリアルを見てシェルスクリプトを実行するPythonプログラムを書く

serial_data_processor.py
import serial
import subprocess

# ESP32とのシリアルポートを開く
ser = serial.Serial('/dev/ttyUSB0', 9600) # '/dev/ttyUSB0'は適切なポートに置き換える

while True:
    # ESP32からのデータを読み取る
    if ser.in_waiting > 0:
        data = ser.readline().decode().strip()
        print("Received:", data)
        
        # 受信したデータが指定された命令ならば、シェルスクリプトを実行
        if data == "the key was Locked!!":
            subprocess.run(["./notice_post.sh"]) 

実行してみる

※.shも.pyもWSL上で作成しWSL上で実行しています.

まずはsudo python3 serial_data_processor.py

import serialできないという旨のエラーが出たので
pip install pyserial
をコマンドラインで実行する.するとpipを入れろとエラーが出たので
sudo apt install python3-pip
でpipを入れた.でもっかいpip~を実行すると正しくimport serialできた

今度はシリアルポートが開けねぇ!というエラーが出た
こちらを参考にやってみる

↑二個目の記事なんか上手くいかなかった
WSLでシリアル通信ほんとにできんの?

これもだめだった
Chat GPTにきいてみたところ

WSL(Windows Subsystem for Linux)を使用している場合、COM ポートは直接 /dev/tty* の形式では表示されません。WSLでは、Windowsのデバイスとして COM ポートが認識されているため、Linux側でのデバイスファイルとしては直接アクセスできません。
その代わりに、WSL上で COM ポートを使用するには、Windows側のパスを使用する必要があります。通常、COM ポートは \.\COM5 のような形式で表されます。
したがって、Pythonのコードを次のように変更してください。

import serial
ser = serial.Serial('\\\\.\\COM5', 9600)  # COM5は実際のポート番号に置き換える

と言われたので書き換えてみる.

はいダメーーーーーーーー,ふざけんなChat GPT
まだポート見つからないんですけど?!?!ってぶちぎれたらつぎのコマンドをbashで実行するように言われた

bash
sudo ln -s /mnt/c/COM5 /dev/ttyS5

スクリーンショット 2024-03-05 182622.png
最後のところにCOM5が追加されたのがわかる.うれしいねーーー
これ革命すぎ

でもまだだめ

[Errno 2] could not open port /dev/ttyS5: [Errno 2] No such file or directory: '/dev/ttyS5'

なんもわからんからとりあえずchmodで権限与えてみる
ひらけないよーーー
ランタイムエラーはでなくなったけど動きもしない
Pythonプログラムに

  • シリアル通信ができているか
  • 受け取ったシリアルの内容
    を表示するように書き換える
serial_data_processor.py
import serial
import subprocess

print("serial_data_processor.py started")
print("Trying to open serial port...")

ser = serial.Serial('/dev/ttyS5', 9600)  

if ser.isOpen():
    while True:
        if ser.in_waiting > 0:
            data = ser.readline().decode().strip()
            print("Receives:", data)
            if data == "The key was Locked!!":
                subprocess.run(["./notice.sh"])  # your_script.shは実行したいシェルスクリプトに置き換える
                print("notice posted")
else:
    print("Serial port is not open")


これでもういちど実行してみると...
スクリーンショット 2024-03-05 190912.png
はあん?
if文実行されてない??

うーーん,シリアル通信諦めてもうwifiでやるか
hazamaru使おうとするとブロックされるって先輩に聞いたんだよな
とりあえず,PCをwindowsからlinuxに変えます.
ESPとESPを無線通信させて片方のESPをPCと繋ぐとかにするか

2024/4/13
前回更新から全然2週間くらい経っててなんの記憶もない.これ書いてたのナイスすぎ~~^-^)>
linuxを使うと言ったな,あれは嘘だ^-^)/
windowsでHTTPリクエストをする方法を調べてたらPythonでもできるらしいのでそれを試しますよーん^-^)v
IMEをいじって句点の変換で^-^)v^-^)/^-^)>を出せるようにした,通称よねむらIME^-^)b

で,Pythonでやる方法についてなんだけども,chatgptに,きいてみたら

notice.py
import requests

# POSTリクエストの送信
url = "http://example.com/api/submit"
data = {"key1": "value1", "key2": "value2"}
response_post = requests.post(url, data=data)

おっと,実行前にrequestsライブラリを入れなきゃな~~~~
それは,すごく簡単で

pip install requests

をターミナル上で実行するだけだぜ~~~^-^)d
そんで,requestsライブラリの,細かいことについては下のリンクが超わかりやすいよーーん^-^)>

いつのまにかpip24.0がリリースされてた~~

で,実行してみたんだけど,

Bad payload received by generic incoming webhook.

って出てきて,またまたchatgptに聞いてみたら

このエラーは、リクエストが正しくフォーマットされていない可能性があります。Microsoft Teamsの>Webhookにデータを送信する際に、正しい形式でデータを渡す必要があります。

次の点に注意してください:

Microsoft TeamsのWebhookには、JSON形式のデータが必要です。requests.post()メソッドを使用して>データを送信する際に、jsonパラメータを使用してデータを渡します。

データは{"text": "Hello, World!"}のような形式である必要があります。他のフィールドを含めることもできますが、最低限textフィールドが必要です。

って言われた~~(ToT)
なに言ってるかよくわかんないけども,要するに送るdataの型を変えろってことだね^-^)b

修正したコードがこちら^-^)>

notice.py
import requests
# POSTリクエストの送信
url = "http://example.com/api/submit"
data = {"text": "Hello, World!"}
response_post = requests.post(url, json=data)

てなわけで,実行してみよ~~^-^)b
スクリーンショット 2024-04-13 142354.png
うん,teamsに投稿できてるね^-^)b

じゃあつぎは,ESPからnotice.pyを実行できるようにしてみよう
シリアルを読めるようになるために,pyserialライブラリをダウンロードするよん
で,書いてくけどこれはそんなに難しくないから過程は省略.ぐぐっていちばんうえのやつ見れば間違いない
いまこんな感じ~

notice.py
import serial
import requests

def send_notification(message):
    # Microsoft TeamsのWebhook URL
    url = "https://kosenjp.webhook.office.com/webhookb2/8aaa7a61-f810-441c-a4fe-faa644a1204c@72fe835d-5e95-4512-8ae0-a7b38af25fc8/IncomingWebhook/ac27c1e2a3e6452ab3c9cd7b31f2c6f5/101ee8dd-06c6-445c-aa21-c4293aebba40"
    
    # 送信するメッセージ
    data = {"text": message}

    # POSTリクエストを送信
    response = requests.post(url, json=data)
    
    # レスポンスを表示
    print(response.text)

def main():
    # シリアルポートを開く
    ser = serial.Serial('COM3', 9600)  # ポート名とボーレートを指定
    
    try:
        # シリアルポートからデータを読み取り、通知を送信
        while True:
            data = ser.readline().decode().strip()  # シリアルポートから1行読み取り
            if data:  # データがある場合のみ処理を実行
                if data == "locked!!":  # シリアルから "locked!!" が受信された場合
                    send_notification("Hello, World!")
                else:
                    send_notification(f"Serial data received: {data}")
    
    except KeyboardInterrupt:
        # Ctrl+Cが押されたらプログラムを終了
        ser.close()
        print("Program terminated.")

if __name__ == "__main__":
    main()

ここに書くほどのことでもないから書かないけどESP側も少しだけ変えたけどLockedの文言だけ^-^)>

serial.serialutil.SerialException: could not open port 'COM3': PermissionError(13, 'アクセスが拒否されました。', None, 5)

こういうエラーが出てくる.
権限がないか,ほかのプログラムがポートを使用しているからしい.
管理者権限で実行してもだめだからなぁ
どうしたらいいんだろうね

↑これから9時間ぐらい経過したころにTwitterでつよつよ友人にだる絡みしながら尋ねたらシリアルモニタを閉じれば解決するかも?というふうに教えてもらった。
添付してもらった記事がこれ

いや、持つべきものは友である。とても感謝。
月曜ゼミで試そうと思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0