日曜日, 4月 7, 2024

SwitchBotのAPI活用とWebhook設定

SwitchBotでデータ取得

SwitchBotはAPIでデータの取得ができますが、APIの実行回数に制限がある事や、現在の状態を取得はできても過去のデータにはアクセスできません。
そこでWebhookを使い変更時にSwitchBot側から自前のサーバーに通知してもらう事で過去のデータを自前で保管する仕組みを作りました。



MySQLにデータベース構築

※DBの構築は省略
テーブル構成はこんな感じ(JSONの生で登録しています。)

フィールド 種別 その他
No int(11) auto_increment
Registration_Server_Time datetime -
input_json text -



Webhookを受け付けるページを作る

適当なWebサーバー(PHPが動く環境)を用意して設置します。
設置場所例:http://api.hogehoge.jp/SwitchBot/index.php

<?php
// POSTされたJSON文字列を取り出し
$json = file_get_contents("php://input");

//データベースに格納
//[連番][サーバー受信日時][JSON生データ]

if($json == ""){
	print("Not JSON");
}else{
	try {
	  $db = new PDO('mysql:host=localhost; dbname=データベース名', 'ユーザー名', 'パスワード');
	  $db->exec('SET NAMES utf8');
	  $stt = $db->prepare('INSERT INTO SwitchBot_Log(Registration_Server_Time,input_json) 
	  VALUES(:Registration_Server_Time, :input_json)');

	  $stt->bindValue(':Registration_Server_Time', date("Y-m-d H:i:s"));
	  $stt->bindValue(':input_json', $json);
	  $stt->execute();
	  $db = NULL;
	} catch(PDOException $e) {
	  die('エラーメッセージ:'.$e->getMessage());
	}
	print("Registration: OK");
}
?>



Webhookの登録

SwitchBotのデバイス状態に変化があるとSwitchBotのサーバーからWebhookで通知を受けれるように設定します。
※「Authorization」は事前にアプリから取得してください

# AUTH="Authorization:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"

# curl -H ${AUTH} -H "Content-type:application/json" -d '{ "action":"setupWebhook", "url":"http://api.hogehoge.jp/SwitchBot/", "deviceList":"ALL" }' -X POST https://api.switch-bot.com/v1.0/webhook/setupWebhook | jq .



データベースを確認

JSONのデータが溜まっていれば成功です。
これで過去のデータにもアクセスができ色々と遊べそうですね。

火曜日, 2月 27, 2024

Raspberry Pi Zero W で玄関外をカメラ確認

20240226_003537.jpg
20240226_61afqzvcp1l_ac_sl1500_.jpg
20240226_003548.jpg

構築方法

Raspberry Pi Zero W の初期設定
前提としてOSのインストールは完了しているものとします。

# 管理者権限
admin@ZeroW-Camera-001:~ $ sudo -i
# viの設定変更
root@ZeroW-Camera-001:~# vi ~/.vimrc
set nocompatible
set backspace=indent,eol,start
# llコマンドの有効化
root@ZeroW-Camera-001:~# vi .bashrc
alias ll='ls $LS_OPTIONS -l'
# ApacheとPHPをインストール
root@ZeroW-Camera-001:~# apt update
root@ZeroW-Camera-001:~# apt upgrade
root@ZeroW-Camera-001:~# apt install apache2 php php-dev php-fpm php-gd php-cli php-curl libapache2-mod-php
root@ZeroW-Camera-001:~# systemctl restart apache2
# sudo権限を追加
root@ZeroW-Camera-001:~# visudo
www-data        ALL=(ALL:ALL) NOPASSWD: /usr/bin/fswebcam
# ファイル生成用に書き込み権限を付ける
root@ZeroW-Camera-001:~# cd /var/www
root@ZeroW-Camera-001:/var/www# chmod 777 html
# メモリ領域に保存する画像のリンクを作成
root@ZeroW-Camera-001:/var/www# cd /var/www/html
root@ZeroW-Camera-001:/var/www/html# ln -s /dev/shm/img_scope_real-time.jpg img_scope_real-time.jpg
root@ZeroW-Camera-001:/var/www/html# mv index.html Def_index.html
root@ZeroW-Camera-001:/var/www/html# ll
total 16
-rw-r--r-- 1 root root 10701 Sep  5 23:48 Def_index.html
lrwxrwxrwx 1 root root    32 Sep  6 00:36 img_scope_real-time.jpg -> /dev/shm/img_scope_real-time.jpg
root@ZeroW-Camera-001:/var/www/html#
# 撮影スクリプトの設置
root@ZeroW-Camera-001:/var/www/html# vi camera_load.sh
--- ここから
#!/usr/bin/bash

### 多重起動の場合は処理をしない
if [ $$ -ne $(pgrep -fo "$0") ]; then
    echo "起動済みです。(Maine)"
    exit 1
fi

if [ $$ -ne $(pgrep -fo "/usr/bin/ffmpeg") ]; then
    echo "起動済みです。(/usr/bin/ffmpeg)"
    exit 1
fi

### 本プログラム
/usr/bin/ffmpeg -y -pix_fmt yuv420p -s 640x480 -framerate 2 -i /dev/video0 -update true -vf "drawtext=fontfile=/usr/share/fonts/truetype/freefont/FreeSansBold.ttf: fontsize=20: text='%{localtime:%Y-%m-%d %X}': fontcolor=red@0.9: x=10: y=10" -r 1 /dev/shm/img_scope_real-time.jpg > /dev/null 2>&1

---ここまで

※「/dev/shm/*」保存先はメモリ領域にしないとSDカードの読み書きが多くなり安定性が極端に下がります。

# ffmpegのインストール
root@ZeroW-Camera-001:/var/www/html# sudo apt install ffmpeg
# fswebcamのインストール
root@ZeroW-Camera-001:/var/www/html# apt-get install fswebcam
# 撮影用スクリプトの自動起動設定
root@ZeroW-Camera-001:/var/www/html# vi /etc/crontab
  *  *  *  *  * root cd /var/www/html/ && /usr/bin/bash /var/www/html/camera_load.sh& > /dev/null 2>&1
# Webページの作成
root@ZeroW-Camera-001:/var/www/html# vi index.php
--- ここから
<form method="post" action="./index.php">
<p>
<button type="submit" name="Button_Refresh" value="Refresh">画像更新</button>
</p>
</form>

<?php
$UserData_POST_Button_Refresh = $_POST["Button_Refresh"];
if ( "Refresh" == $UserData_POST_Button_Refresh ) {
    $CMD = 'sudo /usr/bin/fswebcam -r 640x480 -F 10 --timestamp '%Y-%m-%d %H:%M:%S (%Z)' /dev/shm/img_scope_real-time.jpg';
    exec($CMD);
    sleep(3);
    echo $UserData_POST_Button_Refresh ." '". $CMD ."' OK<BR>";
}
?>

<script>
    function reloadimg(e,timer){
        setTimeout( function(){
            e.src = "./img_scope_real-time.jpg?r=" + Math.random();
        },timer);
    }
</script>

<img src="./img_scope_real-time.jpg" onload="reloadimg(this,1000)" onerror="reloadimg(this,1500)" /><BR>
---ここまで

実際の映像

20240226_003518.jpg
※JavaScriptで1秒毎(失敗時は1.5秒後再取得)によりWebブラウザでリアルタイムな画像が取得可能

日曜日, 9月 10, 2023

Raspberry Pi Zero W で赤外線リモコンを相互遠隔操作

Raspberry Pi Zero W にIR送受信機の機能を搭載して、自宅でリモコン操作をすると実家の機器が遠隔操作できる


dsc_0014.jpg




課題

関東地方住みで東海地方のテレビが見たい
テレビ映像はPCにHDMIキャプチャーカードを積めば大丈夫
でもリモコン操作ができないからチャンネル切り替えられない




前提条件

  1. 拠点間はVPN等でルーティングをしている(プライベートネットワークが無い場合でもHTTP通信が通れば大丈夫)
  2. Raspberry PiにOSインストールからSSHができるまでの知識がある
  3. 電子工作に関する知識が多少はある(はんだ付けが抵抗なくできる方)




必要な物

  1. Raspberry Pi Zero W ・・・2個(本体)
  2. ABB-RSP-ZNR ・・・2個(基盤)※千石電商で1個400円
  3. GPIOのオスメス端子 ・・・2個(千石電商で購入)
  4. VS1838B 赤外線受光モジュール & 940nm 赤外線LED ・・・2個(セットをAmazonで購入)
  5. MOSFET 2N7000 ・・・2個(秋月電子で購入)
  6. MOSFET IRFU9024NPBF ・・・2個(秋月電子で購入)
  7. カーボン抵抗 1/2W4.7KΩ ・・・2個(秋月電子で購入)
  8. カーボン抵抗 1W27Ω ・・・2個(秋月電子で購入)
  9. 六角スペーサーセット ・・・1個(Amazonで購入)




基盤の下書き

ws008979.jpg



下書き通りにはんだ付けして組み立てれば筐体は完成です。(2個作る)




動かすために構築とプログラミング(2台分作る)

rootになる

admin@IR-001:~ $ sudo -i

VIの操作が辛いのでカーソル操作を直す

root@IR-001:~# vi ~/.vimrc
set nocompatible
set backspace=indent,eol,start

llコマンドが使いたいのでaliasのコメントアウトを外す(再ログイン必要)

root@IR-001:~# vi .bashrc
 alias ll='ls $LS_OPTIONS -l'

赤外線操作に必要なパッケージのインストール

root@IR-001:~# curl http://abyz.me.uk/rpi/pigpio/code/irrp_py.zip | zcat > irrp.py
root@IR-001:~# systemctl enable pigpiod

ApacheとPHPをインストール

root@IR-001:~# apt update
root@IR-001:~# apt install apache2 php php-dev php-fpm php-gd php-cli php-curl libapache2-mod-php
root@IR-001:~# systemctl restart apache2

root@IR-001:~# cd /var/www
root@IR-001:/var/www# chmod 777 html

受信用Webデータの設置

root@IR-001:~# cd /var/www/html
root@IR-001:/var/www/html# pwd
/var/www/html
root@IR-002:/var/www/html# cp -ip ~/irrp.py ./
root@IR-001:/var/www/html# ll
total 48
drwxrwxrwx 2 root     root      4096 Aug  6 04:08 .
drwxr-xr-x 3 root     root      4096 Aug  5 23:26 ..
-rw-r--r-- 1 root     root     10701 Aug  5 23:31 index.html
-rw-r--r-- 1 root     root       743 Aug  6 04:08 ir-control.php <== 新規設置
-rw-r--r-- 1 www-data www-data   395 Aug  6 04:09 ircord <== 「ir-control.php」を実行すると自動生成される
-rw-r--r-- 1 root     root     12409 Aug  3 02:00 irrp.py <== 新規設置
-rwxr-xr-x 1 root     root       576 Aug  6 23:15 IR-Rx.sh <== 新規設置

標準出力が邪魔なのでコメントアウトで消す

root@IR-001:/var/www/html# vi irrp.py
-       print("Short code, probably a repeat, try again")
+       #print("Short code, probably a repeat, try again")

「ir-control.php」の中身

<?php
$VARIABLE_IRDATA_File = "ircord";

$Get_PS = $_GET["ps"];

if($Get_PS == "phpinfo"){
    phpinfo();
}elseif($Get_PS == "tx"){
    print("送信はWebでのコントロールに対応していません。");
}elseif($Get_PS == "rx"){
    $Post_IRCODE = $_POST["ircord"];
    
    if($Post_IRCODE == ""){
    	print("Error: IRデータがありません");
    }else{
        //IRデータをファイルに保存
        file_put_contents($VARIABLE_IRDATA_File,$Post_IRCODE);
	    
        //IR送信
        $IR_Tx_command = "python3 irrp.py -p -g22 -f ". $VARIABLE_IRDATA_File ." webcontrol:on";
        exec($IR_Tx_command,$IR_Tx_output);
        print("OK: $Post_IRCODE");
    }
}else{
    print("不正なリクエストです。");
}
?>

「IR-Rx.sh」の中身(1台でテストをする場合はループバックアドレスを指定するとテストができます。)

#!/usr/bin/bash

### 多重起動の場合は処理をしない
if [ $$ -ne $(pgrep -fo "$0") ]; then
    echo "起動済みです。"
    exit 1
fi

### 本プログラム
while true
do

    CMD_Rx_Result=$(python3 irrp.py -r -g27 -f irdata webcontrol:on --no-confirm --post 130)
    CMD_Rx_Result_Last=$(echo $CMD_Rx_Result | tail -1 | sed 's/^.* Okay$/Okay/g')
    
    if [ "$CMD_Rx_Result_Last" == "Okay" ]; then
        DATA=$(cat ./irdata); curl -X POST -d "ircord=$DATA" http://{{対向のラズパイIPアドレス}}/ir-control.php?ps=rx
        rm -rf ./irdata*
    fi
done

最後にcronの設定をして完了

root@IR-001:/var/www/html# vi /etc/crontab
  *  *  *  *  * root cd /var/www/html/ && /usr/bin/bash /var/www/html/IR-Rx.sh& > /dev/null 2>&1