Pico Bot で温度計測

## 1. はじめに
[Pico Bot](https://qiita.com/takashiyamanoue/items/bb4b08c0f220ba4fd91a) を開発中です。Pico Botは、PukiWikiのページに書かれたスクリプトを定期的に読み、そのスクリプトを実行し、実行結果をPukiWikiに書き戻す、Raspberry Pi Pico W (Pico W)で作られたBotです。今回、Pico Bot で気温を計測し、その値をPukiWikiページに書き込むIoTシステムを作成しました。
## 2. 概要
Raspberry Pi Pico Wに温度計測のためのセンサ、AE-BME280、をI2Cで接続し、Pico Botのプログラムに、BME280のデータを読み込むためのモジュールを組み込み、Pico Bot が動作するWi-Fi環境のSSIDとパスフレーズ、Pico Bot が読み書きするPukiWikiページのURLなどを設定して、Pico Wに書き込みます。
この状態で Pico Bot を起動することにより、Pico BotがPukiWiki の指定されたページに書かれたスクリプトに従い、温度計測を行い、このページに計測結果を書き込みます。計測結果をグラフ表示するための、JavaScript も作成しました。

## 3. 動作環境例
例として、以下のような環境で動作させることにします。WikiサーバとPico WはローカルネットワークのWiFiに接続します。Wiki サーバをインターネットの上に置いて、Pico Botのプログラムに書き込むIPアドレスまたはFQDN等をそれに従って設定し直しても動きます。

![networking.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/585767/d5a02eea-e883-8e3d-8e37-d7651aef4b09.png)


## 4. エッジ(Pico Bot)の温度計測ハードウェア
秋月のボード、[AE-BME280](https://akizukidenshi.com/catalog/g/g109421/)、のJ3を半田でブリッジ（ジャンプ？）し、I2Cの動作モードにします。

![DSC_2047.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/585767/f94fe293-75a2-d3dc-ab15-9060a2a13cf9.jpeg)

AE-BME280とPico Wをブレッドボードとジャンプワイヤを使って以下のように接続します。

![DSC_2046.JPG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/585767/1706e38e-e9a2-4e6a-5875-6eb97c2a5dd0.jpeg)

回路（fritzing）：
![pico-bme280-fritzing.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/585767/6f4da294-b291-4c5f-3da6-45469af16b20.png)

上の図を描くために作ったAE-BME280のfritzingの部品：
[AE-BME280.fzpz](https://www2.yama-lab.org/IoT/pico_wiki/index.php?plugin=attach&pcmd=open&file=AE-BME280.fzpz&refer=Pico_Wiki_Driver)


## 5. エッジ(Pico Bot)のソフトウェア

Pico Bot のプログラムに、I2CでBME280 を利用するためのモジュールを加えたソースプログラム（[main.py](https://www2.yama-lab.org/IoT/pico_wiki/index.php?Pico_Bot_with_BME280_02.py)）を用意しました。

以下の手順に従って、Pico Botを4.で作成したハードウェアのPico Wに書き込みます。

### 5.1 Pico Wの開発環境の準備

ここでは、パソコン(PC)に、Visual Studio Code (VSCode)をインストールし、VSCodeの拡張機能として、MicroPico を導入したものを利用することを想定しています。また、4.のハードウェアで利用するPico Wには、すでにMicroPythonを実行するためのファームウェアが書き込まれていることを想定しています。VSCode, MicroPico, ファームウェアの書き込みについては、
[IoT演習第２回、マイクロコントローラ](https://qiita.com/takashiyamanoue/items/4baba8e23c86dc07962d)
等を参考にしてください。

### 5.2 ソースプログラムのコピー
MicroPico が利用できるVSCodeがインストールされたPCを用意し、VSCodeの上で[このソースプログラム](https://www2.yama-lab.org/IoT/pico_wiki/index.php?Pico_Bot_with_BME280_02.py)をmain.pyと名前をつけて保存します。

(2024 12/1, ntpを使って時間を得る部分に問題があったので修正しました)

### 5.3 ソースプログラムの修正
[このソースプログラム](https://www2.yama-lab.org/IoT/pico_wiki/index.php?Pico_Bot_with_BME280.py)の先頭近くにある以下の行は、3. の実行環境で動くように書いています。これを、実際に実行する環境に合わせて書き換えます。ここでinit_pageは、3. の図の Wiki Page URLです。init_pageは、3.の図のPageです。

```Python
init_url="http://192.168.8.237/pukiwiki/pico_wiki/"
init_page="bme280-01"
ssid="GL-SFT1200-8f4"
password="goodlife"
```
このプログラムの中でntpを使って現在の時間を得る部分があります。
上の、password=の次の行に、ntpサーバを指定している行があり、以下のようになっています。
```Python
ntp_host="ntp.nict.jp"
```
必要に応じてntp_host=の右辺を書き換えてください。

### 5.4 Pico Wの接続

USBケーブルでPC(VSCodeとその拡張機能としてMicroPico が利用できるもの)と、Pico Wを接続します。接続が成功したら、VSCodeの下の行に、接続されていなかった時の、Pico Disconnectedの表示が、Pico Connected に変わります。

![micropico_install_13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/585767/1f6bae6d-021f-0d85-a578-5b7a7fcbe97e.png)

### 5.5 Wiki ページの作成
順番が前後しますが、「6. Wikiページのスクリプト」に示す手順に従って、Pico Botが実行するスクリプトが書かれたWikiページを作成します。

### 5.6 テスト
5.3 が終わった時点で、編集したmain.py が選ばれている状態になっていると思います。この状態で、画面の下に表示されている、Run ボタンをクリックすると、main.py のPico Botのプログラムが実行されます。実行の経過がMicroPythonのREPのターミナルに表示されます。また、Wikiページに実行結果が書き込まれます。これらを見て、Pico Botの不具合があれば、それを修正します。なお、メモリー不足のエラーが発生した場合、一度、Pico Wを接続するUSBケーブルをPico Wから外し、もう一度接続するとメモリー不足のエラーが解消する場合があります。

![20240505-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/585767/8b0b2918-6bb3-2bdc-1bb9-cceef3c15973.png)

### 5.7 Pico Wへ upload

VSCode の上のメニューの[View]>[Command Palette]>を選び、そこで表示されるプロンプトで、MicroPico:Upload current file to Pico (選択肢が補完されて表示されるので、それを選択)を入力し、実行します。


![20240505-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/585767/379318e1-3ddc-fcc6-0988-e48484f6cf86.png)

![20240505-05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/585767/11b92468-1826-330f-2150-2a82729dc9b1.png)


### 5.8 起動時の自動実行の設定

VSCode の上のメニューの[View]>[Command Palette]>を選び、そこで表示されるプロンプトで、MicroPico:Run current file on Pico (選択肢が補完されて表示されるので、それを選択)を入力し、実行します。

![20240505-03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/585767/379318e1-3ddc-fcc6-0988-e48484f6cf86.png)

![20240505-04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/585767/c008ecdd-0580-dfad-0a32-8d185d362d28.png)


### 5.9 Pico Bot の起動
Pico WのUSBケーブルを抜き差しすることで、書き込んだPico Botのプログラムの実行が行われますが、その前に、次の6. Wikiページのスクリプトを用意しておきます。

## 6. Wikiページのスクリプト

「5.3 ソースプログラムの修正」で行った、URLにあるWikiページに、Pico Botが読み書きするためのスクリプトなどを記述します。3. の環境で動作させる場合、次の図のように記述します。

![wiki-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/585767/f46efcc4-0f95-7716-9f02-f7032a582351.png)

Pico Botが読み込むスクリプトと実行結果等は、PukiWiki のページの、（最初の）書式なしテキスト(pre defined)の領域で、薄い青色の背景で表されています。ソースエディタで、行の左端に半角の空白を入れることでこの領域を記述します。

以下をコピペして書き換えても良いです。

```Python
 object_page http://192.168.8.237/pukiwiki/pico_wiki/?bme280-01 or   http://192.168.8.237/pukiwiki/pico_wiki/?bme280-01
 device yamaRasPiDp9_1 or yamaRasPiDp9_2 start after no write for 10 min.
 command: set read_interval=300000
 command: set exec_interval=0
 command: set report_length=20
 command: py test
 py: #
 py: from machine import Pin, I2C
 py: import time
 py: i2c= I2C(0, sda=Pin(0), scl=Pin(1), freq = 40000)
 py: bme=BME280(i2c=i2c)
 py: v=bme.values[0]
 py: line="device=temp, Date="+self.Pico_Time.get_now()+", v="+v
 py: self.write_line(line)
 py: self.send_result()
 command: end test
 command: run test
 result:
 current_device="yama_pico_0000_0000_0000_0001". Date=2024/04/03 06:35:50
```

上の記述の中で、
```
object_page <URI-1> or <URI-2>  
```
は、Pico Botが読み込むページ（このページ）のURI(URI-1)と、このページが障害発生などで使えない時の代替ページのURI(URI-2)を表しています。代替ページがない場合、同じURIを書きます。
```
device <device-1> or <device-2> start after no write for 10 min.
```
は、このページは<device-1>の Pico Botが読み書きしますが、それが障害などで動かなくなった場合(結果を書かなくなった場合)、10分後に、<device-2>のPico Botが読み書きを開始することを表します。しかしながら、現在、この機能は動いていません。
```
command: set read_interval=300000
```
は、Pico Botがこのページを読む間隔を５分(300000msec)にすることを表します。
```
command: set exec_interval=0
```
は、Pico Botがこのページを読んだ直後、一回、記述されたスクリプトを実行することを表します。0でない場合は、ページを読んだ後、ここに記述された間隔(単位はmsec)でスクリプトを繰り返し実行することを表します。
```
command: set report_length=20
```
は、resurt: の行より後に書かれた実行結果の行数の最大を20行にすることを表します。
```
command: py test
```
と
```
command: end test
```
は、
この間にある、py: で始まる行が MicroPythonのプログラムで、そのプログラムに、test という名前をつけていることを表しています。
```
command: run test 
```
は、test という名前がついたプログラムを実行することを表しています。
```
result:
```
は、この行の後ろの行から、結果が書き込まれることを表します。
```
current_device="<device>". Date=<date-time>
```
は、このページに最後に書き込んだPico Botのidが<device>で、その時間が<date-time>であることを表しています。

MicroPython のプログラムの部分について、
```Python
 py: from machine import Pin, I2C
 py: import time
```
は、Raspberry Pi Pico のMicroPythonの標準モジュール, machine のなかの、Pin クラスとI2Cクラスを利用することと、標準クラス time を利用することを表しています。

```Python
 py: i2c= I2C(0, sda=Pin(0), scl=Pin(1), freq = 40000)
```
は、変数i2cにI2Cクラスのインスタンスを生成し、代入することを表しています。ここで、コンストラクタI2Cの最初の引数 0 は、Pico の0番目のi2cインターフェースを利用することを表しています。
i2c通信のsda信号は0番ピンを利用し、i2c通信のscl信号は1番ピンを利用しています。freqはi2cインターフェースの最大周波数を表しています。

```Python
 py: bme=BME280(i2c=i2c)
```
は、温度・湿度・気圧センサ、BME280のインスタンスを生成し、前の行で作成したi2cをi2cインターフェースとして利用するよう初期化して、変数bmeに代入することを表しています。
 
```Python
 py: v=bme.values[0]
```
は、BME280で計測した温度(values[0])の値（文字列）を取り出して、変数vに代入しています。

```Python
 py: line="device=temp, Date="+self.Pico_Time.get_now()+", v="+v
 ```
は、変数 line に、実行結果を表す行、"device=temp, Date=<Date>, v=<温度>"を代入しています。

```Python
 py: self.write_line(line)
```
は、変数lineの値(実行結果を表す行)をWikiの実行結果の列を表すバッファに追加しています。

```Python
 py: self.send_result()
```
は、バッファをWikiページに書き込みます。

## 8. 実行結果の例
Wikiページの"result:"の行の後から実行結果が書き加えられます。6. の例では"set report length="の行で、最大行数が20となっているので、最大20行の結果が書き加えられます。20行を超え当た部分は前の方にある古いデータから削除されます。

```
 device=temp, Date=2024/04/03 05:00:43, v=21.2C
 device=temp, Date=2024/04/03 05:05:43, v=21.3C
 device=temp, Date=2024/04/03 05:10:43, v=21.2C
 device=temp, Date=2024/04/03 05:15:43, v=21.09C
 device=temp, Date=2024/04/03 05:20:44, v=20.98C
 device=temp, Date=2024/04/03 05:25:43, v=21.08C
 device=temp, Date=2024/04/03 05:30:43, v=21.1C
 device=temp, Date=2024/04/03 05:35:43, v=21.12C
 device=temp, Date=2024/04/03 05:40:43, v=21.05C
 device=temp, Date=2024/04/03 05:45:43, v=21.07C
 device=temp, Date=2024/04/03 05:50:43, v=21.04C
 device=temp, Date=2024/04/03 05:55:44, v=20.94C
 device=temp, Date=2024/04/03 06:00:43, v=20.88C
 device=temp, Date=2024/04/03 06:05:44, v=21.8C
 device=temp, Date=2024/04/03 06:10:44, v=21.76C
 device=temp, Date=2024/04/03 06:15:44, v=21.75C
 device=temp, Date=2024/04/03 06:20:44, v=21.97C
 device=temp, Date=2024/04/03 06:25:44, v=22.1C
 device=temp, Date=2024/04/03 06:30:44, v=22.19C
 device=temp, Date=2024/04/03 06:35:44, v=22.26C
```
各行の実行結果は、Pythonのプログラムの以下の部分で書き加えられています。
```Python
 py: v=bme.values[0]
 py: line="device=temp, Date="+self.Pico_Time.get_now()+", v="+v
 py: self.write_line(line)
 py: self.send_result()
```


## 8. JavaScript でグラフ描画
Pico Botの実行結果である温度の変化をグラフで表示するためのJava Scriptを用意しています。6.のPukiWikiのページのスクリーンショットの、スクリプトの記述の前に書かれたURIのリンクが示すページ、http://192.168.8.237/pukiwiki/pico_wiki/sensors-graph-01.html に、以下の[ソース](https://www2.yama-lab.org/IoT/pico_wiki/index.php?sensors-graph-ex01.html)のhtmlページを置くと、このリンクをクリックすることで、以下のようなグラフが表示されます。

![graph-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/585767/5f67cba6-65a6-0d52-be10-df42214924ef.png)

[ソース](https://www2.yama-lab.org/IoT/pico_wiki/index.php?sensors-graph-ex01.html)

## 9. 終わりに
Pico Botで温度を計測し、それをWikiページに書き込むことができたことについて紹介しました。現在、PukiWikiのページに記述するMicroPythonのプログラムが使用するモジュールは、あらかじめ、Pico Bot のソースプログラムに組み込んでいますが、Thony のMicroPython用に登録されたライブラリを検索し、マイコンボードのファイルシステムに組み込む機能のようなものが VSCodeのMicroPicoで使うことができれば、それを使いたいと思っています。
## 9. 謝辞
以下のページを含む様々なページを参考にさせていただきました。感謝します。
* https://github.com/robert-hh/BME280
* https://msr-r.net/raspi-picow-bme280/
* https://micropython-docs-ja.readthedocs.io/ja/latest/library/index.html
* https://jumbleat.com/2017/01/18/making_custom_parts_fritzing/
* http://kunsen.net/2018/05/23/post-137/
*