Wiki Bot in Python 202501

# はじめに

Bot Computing/Wiki IoT というのをやっています。これは、PukiWikiのページにかかれたスクリプトをIoTのEdge端末が実行し、実行結果をスクリプトが書かれたPukiWikiのページに書き加える、というものです。

https://www.jstage.jst.go.jp/article/ipsjjip/28/0/28_204/_article/-char/ja/

https://www.jstage.jst.go.jp/article/ipsjjip/30/0/30_251/_article

Edge端末がWikiのページの記述で遠隔操作されるBot となります。これをWiki Botと呼んでいます。

![wiki-bot-20250102-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/585767/925c7759-4b23-921d-716a-669505f339ac.png)

2024年1月には、Wiki Botの機能をMicro Python で一部実現することで、Raspberry Pi Pico をWiki Botとして使えるようにしました。

https://qiita.com/takashiyamanoue/items/bb4b08c0f220ba4fd91a

その後、Wiki Botのプログラムを Python でも書いて、Raspberry PiでPython版のWiki Botを動かすことができるようになりました。

いままでは、Wiki Botは、PukiWikiのテキストページのみの読み書きを行っていましたが、今回、Wiki Botにより、Wiki Botである Raspberry Pi が持っている画像などを添付ファイルとして、PukiWiki のページにUpload できるように拡張しました。

このWiki Botの拡張を行う準備について、Qiita に以下の記事を書いています。

https://qiita.com/takashiyamanoue/items/3d8a33d53eae880a97b5

なお、Wiki Botを作る以前は、PukiWikiのプラグインとして Javaのアプレットを使って、音声や画像をテキストデータに変換してPukiWikiのページに保存することをやっていたのですが、Java アプレットが使えなくなってしまって、それができなくなってしまっていました。


## Wiki Iot/Bot Computing 2025年 1月バージョン

Wikiは人間同士の共同作業を推進するのによく使われるツールです。Wiki IoT/Bot Computing は、Wikiを人間だけでなく、人間と機械(Bot)との共同作業に使おうとするものです。
![man-machine-collabo-using-wiki-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/585767/b768134d-9d75-57a2-6719-9ac2f8a175f1.png)

Wiki IoTはインターネット上のWikiページと、センサが接続されたWiki Botや、 センサネットワークと通信が可能なWiki Bot/Gateway や、センサ及びセンサネットワークが接続されていない Wiki Botから構成されています。
センサだけでなく, アクチュエータを使うこともできます。

![wiki-iot-20250102-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/585767/ee291364-7e09-5a03-7040-63d60a40de33.png)

2025年1月時点の Wiki Bot は以下の機能を持っています。
- BotはWikiに書かれたスクリプトを定期的に実行
- スクリプト内に、Wiki Botで実行されるPythonのプログラムを埋め込み可。これをWiki Pythonと呼ぶことにします
- Wiki BotはWikiに実行結果を書き込み可
- Wiki Bot を実行しているRaspberry Pi に格納された画像などのデータをUploadして、Wikiページの添付ファイルとして、Wiki ページに格納可能
- Wiki ページの添付ファイルのリストをWiki Python が入手可能
- Wiki ページの添付ファイルをWiki Python が削除可能
- Wiki Bot のGUIで、最初に実行するWikiページを設定可能。そのときのWikiサーバのPukiWikiのadmin passを設定可能
- Wiki Bot の起動時のオプションにより、保存された最初に実行するWikiページなどの情報を元に、自動起動可能


# システム例
LAN上でPukiWikiサーバを立ち上げ、そのLAN上でカメラをつけたWiki Botを動かし、このカメラで定期的に撮影した画像をPukiWiki のページに添付するシステムを構築してみます。

ネットワークは以下のようになっているとします。

![network-20250101-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/585767/e41a58f6-3b89-6f05-b8cc-8d766a8fd9be.png)

PukiWikiサーバとなるRaspberry Pi では、 Apache2などのWebサーバと、PHP ver.8以上をインストールし、その上に、PukiWiki-1.5.4以上のファイルをダウンロードして解凍し、/var/www/html/pukiwiki に配置します。このディレクトリのpukiwiki.ini.phpを編集して、admin pass を設定しておきます。
(pukiwiki-1.5.3 以前のバージョンでは複数の脆弱性が見つかっているそうです)

https://pukiwiki.sourceforge.io

PukiWikiサーバ (IPアドレスは 192.168.1.19, PukiWikiのURLは、http://192.168.1.19/pukiwiki/) で ex01 という名前でWikiのページを作成します。このページの編集画面（新しいページを作ったときは最初に編集ページが表示されます）で以下のスクリプトをPukiWiki の Plain text (PukiWikiの編集状態で、各行の左端に半角の空白を挿入) として書き込みます。

```Python
 object_page http://192.168.1.19/pukiwiki/?ex01 or http://192.168.1.19/pukiwiki/?ex01
 device yama_bot_0000_0000_0000_0001 or yama_bot_0000_0000_0000_0001 start after no write for 10 min.
 command: set read_interval=600000
 command: set exec_interval=0
 command: set report_length=400
 command: py test
 py: import subprocess
 py: date=self.Pico_Time.get_now()
 py: #date=2024-12-31 14:25:16.61944
 py: time_x=(date.split())[1]
 py: print('time_x='+time_x)
 py: time_xx=time_x.split(':')
 py: hm=time_xx[0]+'_'+time_xx[1]
 py: print('time='+hm)
 py: attach_dir='/home/pi/python/'
 py: attach_name=hm+'.jpg'
 py: print('attach_name='+attach_name)
 py: cmd_line="/usr/bin/libcamera-jpeg -o "+attach_dir+attach_name+" -t 1000 --width 640 --height 480"
 py: print(cmd_line)
 py: cmd_line_list=cmd_line.split()
 py: subprocess.run(cmd_line_list)
 py: list=self.get_attachment_list()
 py: if attach_name in list:
 py:      self.delete_attachment(attach_name)
 py: self.upload_file(attach_dir, attach_name)
 command: end test
 command: run test
 result:
 current_device="yama_bot_0000_0000_0000_0001". Date=2024-12-29 01:13:35.523630
```

上のプログラムで、
```Python
object_page http://192.168.1.19/pukiwiki/?ex01 or http://192.168.1.19/pukiwiki/?ex01
```
は、このページがWiki Botによって実行されることを示しています。URIを or でくくって並べていますが、これは片方のURIのページを読むことができなかった場合、もう片方のURIのページを読みに行くことを表しています。

```Python
device yama_bot_0000_0000_0000_0001 or yama_bot_0000_0000_0000_0001 start after no write for 10 min.
```
は、device \<botのID-1> or \<botのID-2> start after no write for 10 min.の形式で書かれた、このWikiページを実行できるWiki BotのIDを表しています。普段は\<botのID-1>のWiki Botを利用し、もし、このWiki Botの、このWikiページへの書き込みが 10 min. より長い間なければ、\<botのID-1>のBotに障害が発生したと解釈し、\<botのID-2>のBotが起動することを表しています。

```Python
command: set read_interval=600000
```
は、Wiki Botがこのページを 600000 ミリ秒 (10分)ごとに読み込むことを表しています。

```Python
command: set exec_interval=0
```
は、読み込んだページをすぐに1度実行することを表しています。もし、上の代入文の右辺が0でない場合は、読み込んだページをその間隔(ミリ秒)で繰り返し実行することを表します。

```Python
command: set report_length=400
```
は、このページの result: の行の下に追加される実行結果の行数を最大400行に制限することを表しています。400行を超えたものについては、先頭の方から（古い方から）削除されます。

```Python
command: py test
```
と
```Python
command: end test
```
は、この２行の間に、py: で始まる、Wiki Python のプログラムが記述され、そのプログラムに、test という名前を付けることを表しています。

```Python
command: run test
```
は、test という名前をつけた Wiki Pythonのプログラムを実行することを表しています。

```Python
result:
```
は、この行の後ろにWiki Python のプログラムの実行結果が追加されることを表しています。

```Python
current_device="yama_bot_0000_0000_0000_0001". Date=2024-12-29 01:13:35.523630
```
は、このページを現在実行しているWiki BotのIDと、このWiki Botが最後にこのページに書き込みを行った時間を表しています。現在は使っていませんが、将来は、Wiki Botに障害が発生したとき、待機させていたWiki Botを起動することに利用する予定です。

Wiki Python のプログラムの中で、
```Python
py: date=self.Pico_Time.get_now()
```
は変数 date に、現在の日時を文字列として格納することを表しています。そのときの形式は、次の行のコメントの
```Python
py: #date=2024-12-31 14:25:16.61944
```
のようになっています。

```Python
py: cmd_line="/usr/bin/libcamera-jpeg -o "+attach_dir+attach_name+" -t 1000 --width 640 --height 480"
py: cmd_line_list=cmd_line.split()
py: subprocess.run(cmd_line_list)
```
は、Wiki Botに接続されたRaspberry Pi のカメラで、Raspberry Pi のlibcamera-jpegコマンドを使って写真を撮影し、jpeg 形式でattach_dir+attach_name のパスに格納することを表しています。このとき、1000 ミリ秒(1秒)、撮影された画像がRaspberry Pi に表示されます。また、このときの画像の解像度は横 640ドット、縦 480ドットです。

```Python
py: list=self.get_attachment_list()
```
は、このWikiページに添付されたファイル名の一覧をPythonのListとして変数listに格納することを表しています。

```Python
py: if attach_name in list:
py:      self.delete_attachment(attach_name)
```
は、list の要素として attach_name があったら、すでにその名前のファイルは添付されている、として、そのファイルをこのページから削除することを表しています。

```Python
py: self.upload_file(attach_dir, attach_name)
```
は、Raspberry Piのattach_dirにあるファイル attach_name を、このWikiページにuploadして添付することを表しています。

Wiki BotになるRaspberry Pi には、以下のリンク先のプログラムをダウンロードして保存します。

https://www2.yama-lab.org/BotComputing-WikiIoT/?wiki_bot_03.py

なお、このプログラムを実行するためには、requests_toolbelt モジュールをimport できるようにしておく必要がありますが、標準のPython3ではこれがないので、
```Python
pip3 install requests-toolbelt
```
を実行しておく必要があります。
しかしながら、2025年1月現在のRaspberry Pi OSでは、pip3コマンドは標準環境ではうごかないそうです。そこで、仮想環境を作って、pip3 install でインストールし、このプログラムの実行も、仮想環境で実行する必要があります。

https://blog.piwheels.org/debian-bookworm-and-raspberry-pi-5/

なお、標準環境で、sudo apt install python3-requests-toolbelt を実行しようとしましたが、requests-toolbeltはインストールできませんでした。

また、raspberry pi のreboot時に、systemd で自動起動するように、起動のシェルスクリプトを書いたのですが、仮想環境に移行するための　source コマンドが実行できない、というエラーに遭遇しました。この問題はこのシェルスクリプトの
```
#!/bin/sh
```
を
```
#!/usr/bin/bash
```
に書き換えることで回避することができました。


このプログラムがうまく起動できたら、以下のWindowが表示されます。

![20250101-1103.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/585767/3893864b-c9b0-66c7-61dd-8d7c9e287a1e.png)

この画面のURIの欄に、実行するWikiページのURIを記述し、passの欄に、admin passを記述し、「save property」ボタンをクリックし、「start」ボタンをクリックすることでWiki ページのスクリプトが繰り返し実行されます。admin pass は添付ファイルのuploadや削除のときに必要になります。
一度これらの設定を行って、実行できることを確認した後、実行を終了し、
仮想環境を動かしているターミナルで、
```
python3 wiki_bot_03.py -s
```
のように、-sオプションをつけて起動することにより、
それ以前に設定して保存した実行URIやadmin pass を使って、自動的にstartボタンがクリックされて実行が開始されます。
以下に起動シェルスクリプトの例を示します。

```bash
#!/usr/bin/bash
sleep 120
xhost +
export DISPLAY=:0.0
cd /home/pi/python
source testpip/bin/activate
python3 wiki_bot_03.py -s
```

以下の図は、このシステムが実行された結果、添付ファイルが添付されたこのWikiページの表示例です。

![20250101-0943.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/585767/08cefddd-7c16-f825-a14c-0b10bbc5a9bd.png)


# 参考URL等
以下のページなどを参考にしました。感謝します。

https://pukiwiki.sourceforge.io

https://blog.piwheels.org/debian-bookworm-and-raspberry-pi-5/

https://forums.raspberrypi.com/viewtopic.php?t=361758

https://hellobreak.net/raspberry-pi-bullseye-libcamera/

https://rikoubou.hatenablog.com/entry/2024/02/26/163945