IoT演習第10回、IoTその１

# 1. はじめに

[IoT演習シラバス案その２（授業計画表）](https://qiita.com/takashiyamanoue/items/0cf9d58265bff5883698)の第10週に予定している内容の一部です。


今回は、Raspberry Pi Pico W (Pico W) で収集したデータを定期的にサーバにUploadする、IoTシステムを作ってみます。

ここでPico Wに、Pico Botと名付けたソフトウェアを導入することで、Pico WをWebページから制御できるようにすると同時に、Pico Wがセンサで収集したデータをこのWebページに書き込むことができるようにします。

Raspberry Pi Pico Wに温度計測のためのセンサ、AE-BME280、をI2Cで接続し、[Pico Bot](https://qiita.com/takashiyamanoue/items/bb4b08c0f220ba4fd91a) のプログラムに、BME280のデータを読み込むためのモジュールを組み込み、Pico Bot が動作するWi-Fi環境のSSIDとパスフレーズ、Pico Bot が読み書きするPukiWikiページのURLなどを設定して、Pico Wに書き込みます。
この状態で Pico Bot を起動することにより、Pico BotがPukiWiki の指定されたページに書かれたスクリプトに従い、温度計測を行い、このページに計測結果を書き込みます。

以下、今日の内容です。

-2. Web APIの話。
-3. 利用者がWebブラウザで内容を追加・編集できるWebページ、Wiki
-4. Webページをプログラムで読み書きする手法, Webスクレイピング
-5. Webスクレイピングを行うライブラリ、Pico Wiki Driver とそれを使ったIoTのエッジシステム、Pico Bot の紹介
-6. 演習: Pico Bot を使って気温を計測してWebページに定期的に追加するIoTシステムを動かしてみる。
-7. 授業の振り返り


# 2. Web APIの話

Application Program Interface (API)とは、他のプログラムに対して、そのプログラムが簡単に利用できるように公開されているインターフェースのことです。Python Module は一種のAPIと考えてよいと思います。

https://atmarkit.itmedia.co.jp/ait/articles/1907/02/news009.html

Web APIとは、パソコンやスマホのプログラムに対して、Webで利用できる機能（Webサービス）を簡単に利用できるように公開されているインターフェース（インターフェースプログラム）のことです。

https://ja.wikipedia.org/wiki/Webサービス

https://qiita.com/saito_rik/items/20ad8182715b67044fe8

授業担当者は、PukiWikiというWikiソフトウェアをRaspberry Pi Pico Wのプログラムで利用するためのWeb APIである Pico Bot を作成しています。今回、このPico Botを使って、IoTシステムを作ってみます。

# 3. 利用者がWebブラウザで内容を追加・編集できるWebページ、Wiki

WebのコンテンツであるWebページは、基本的にはWebサーバに格納されているHTML形式のファイルです。

ただし、ショッピングサイトのように、同じURLのページを表示しても、買い物の手順の進行によって表示が変わるように、動的にHTMLファイルを生成し、ブラウザにそれが表示される場合もあります。

Webページを書き加えたり、修正したり、削除したりするためには、Webサーバに蓄えられたファイルの内容を書き換える必要があります。これを実施するために、いちいちサーバにログインして、手元のパソコンで作成したHTMLファイルをuploadしたり、手元のHTMLファイルを修正してuploadして、元のファイルに上書きしたり、サーバにログインしてファイルを削除したりするのは面倒です。

そこで、いちいちサーバにログインしなくても、Webブラウザ上でファイルを書き換えることができる、CMS (Contents Management System)が使われるようになりました。

https://ja.wikipedia.org/wiki/%E3%82%B3%E3%83%B3%E3%83%86%E3%83%B3%E3%83%84%E7%AE%A1%E7%90%86%E3%82%B7%E3%82%B9%E3%83%86%E3%83%A0


WikiはCMSの一種です。情報共有の手段として多く使われています。WikiペディアでもWiki が使われています。

https://ja.wikipedia.org/wiki/%E3%82%A6%E3%82%A3%E3%82%AD

# 4. Webページをプログラムで読み書きする手法, Webスクレイピング

Webページから必要な部分だけを自動的に取り出して、他のプログラムなどで利用したい場合があります。このようなことを行うことをWebスクレイピングと呼びます。

https://ja.wikipedia.org/wiki/%E3%82%A6%E3%82%A7%E3%83%96%E3%82%B9%E3%82%AF%E3%83%AC%E3%82%A4%E3%83%94%E3%83%B3%E3%82%B0

https://qiita.com/Octoparse_Japan/items/3a766a5615d82674b873

ここでは、Webページの必要部分を取り出すだけでなく、書き加えたり変更したり削除したりすることもWebスクレイピングを呼ぶことにします。

CMSやWikiは手元のブラウザで操作を行うことでWebページを新規作成（create）、読み込み(read)、更新(update)、削除(delete)(CRUDと言います)することができます。これらの、人間が行っている操作をプログラムで自動的に行うことで、プログラムによってWebページのCRUDを行うことができます。

なお、Webスクレイピングを禁止しているWebサイトもありますので、注意してください。自分でWebスクレイピングを行うプログラムを作る代わりに、できるだけ、そのWebサイトが公開し、利用を許可しているWeb APIを利用してください。

https://help.qiita.com/ja/articles/qiita-api

# 5. Webスクレイピングを行うライブラリ、Pico Wiki Driver とそれを使ったIoTのエッジシステム、Pico Bot の紹介

Pico Botは、Pico WをPukiWikiのページに書かれたスクリプトに従って動作させるための遠隔操作プログラムです。Pico Wが収集したデータを、このPukiWikiのページに書き加えることもできます。

![pico_bot_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/585767/0fc01680-3969-15d2-8730-eea069b94456.png)

Pico Botは、PukiWikiのWebスクレイピングを行うことができる PukiWikiのAPIでもあります。人間が PukiWiki のページを読んだり書き換えたりする代わりに、Pico BotがPukiWikiのページを読んだり書き換えることができます。Pico Botは、PukiWiki以外のWebページを読むこともできます。

Pico Botは PukiWikiのページを読み書きするための Pico Wiki Driver というAPIを持っています。

https://qiita.com/takashiyamanoue/items/03d068a37b79d77bd0e0

Pico Botは、Pico Wiki Driver を使って、PukiWiki のページに書かれたスクリプトを実行できるようにし、なおかつ、Pico Wがそのスクリプトで収集した情報をPukiWikiのページに書き加えることができるようにしたものです。

なお、これ以降、Pico Botはプログラムの名前だけでなく、Pico Botのプログラムを導入した Pico Wのことも意味するものとします。

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

# 6. 演習: Pico Bot を使って気温を計測してWebページに定期的に追加するIoTシステムを動かしてみる。

以下の手順を実施して、Pico Botを使って気温を計測し、その結果をWebページに定期的に追加するIoTシステムを作り、動かしてみます。

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

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


## 6.2 動作環境例

以下のような環境で動作させることにします(IoT演習を行っている教室でこのような設定にしています)。Pico Wはyamaken-pc3-bのWiFiに接続します(Pico Wの WiFiは、IEEE 802.11b/g/nのプロトコルを使います。802.11aを使うことはできません)。Wiki サーバをインターネットの上に置いて、Pico Botのプログラムに書き込むIPアドレスまたはFQDN等をそれに従って設定し直しても動きます。


![portable_cloud_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/585767/ddbb6d90-7874-dc22-4221-57cb8061e4e9.png)


## 6.3 エッジ(Pico Bot)の温度計測ハードウェア

「IoT演習第７回、I2C」のAE-BME280を使って、温度・湿度・気圧を計測する回路をそのまま使います。回路を再掲します。

![20240915-bme280-bbd-sch-01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/585767/dc6a01a0-8b0a-255e-021a-01e6f53866a1.png)

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

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

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

###  ソースプログラムのコピー

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

### ソースプログラムの修正
[このソースプログラム](https://www2.yama-lab.org/IoT/pico_wiki/index.php?Pico_Bot_with_BME280_03.py)の先頭近くにある以下の行は、6.2の実行環境で動くように書いています。

```Python
device_id="yama_pico_0000_0000_0000_0001"
init_url="http://172.16.17.47/pukiwiki/"
init_page="ex01"
ssid="yamaken-pc3-b"
password="*******"
ntp_host="172.16.16.254"
```
ここでdevice_idはPico Botのidを表すのですが、このままにしておいてください。
init_urlは、「6.8 Wikiページのスクリプト」のスクリプトが書いてあるページがあるPukiWikiのURLです。init_pageは、そのURLのPukiWikiの、「6.8 Wikiページのスクリプト」が載っているページです。ssidは6.2の実行環境で使うWiFiのSSIDです。passwordはそのWiFiのSSIDです。授業で伝えたものです。ntp_hostは、ntpサーバ(現在の時間を教えてくれるサーバ)のipアドレスを表すのですが、6.2の環境ではこのままにしておいてください。

この中の、
```Python
init_url="http://172.16.17.47/pukiwiki/"
```
のurlの、サーバのIPアドレスの172.16.17.47を、各受講者に割り当てたサーバのIPアドレスで書き換えます。

この授業を実施している環境では、変更が必要なのはurlのサーバのIPアドレスだけですが、他の環境では適宜、ほかの部分も書き換えてください。

## 6.5 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)

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

## 6.7 テスト
6.2 が終わった時点で、編集した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)


## 6.8 Wikiページのスクリプト

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


![20241202-1912.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/585767/dc3c05ed-846a-f5b1-127a-32cc07f4ab64.png)

なお、授業では受講者それぞれに１台のRaspberry Piのサーバを用意しています。
以下のURLをブラウザで開くと、各自のPico Wで実行されるスクリプトが書かれたページが表示されます。
```
http://172.16.17.<番号>/pukiwiki/?ex01
```

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

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

```Python
object_page http://172.16.17.47/pukiwiki/?ex01 or  http://172.16.17.99/pukiwiki/?ex01
device yamaRasPiDp9_1 or yamaRasPiDp9_2 start after no write for 10 min.
command: set read_interval=60000
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:5 0
```

上の記述の中で、
```
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=60000
```
は、Pico Botがこのページを読む間隔を1分(60000msec)にすることを表します。
```
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ページに書き込みます。

## 6.9 実行結果の例
read_interval=60000　となっているので、Pico Wに書いたプログラム、main.pyの実行が始まってから1分後から、Wikiページの"result:"の行の後から実行結果が書き加えられます。
6.8 の例では"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()
```

VSCodeのterminalに、このプログラムの実行の途中経過に関するメッセージが表示されます。この中で、"something wrong in post"というメッセージも出てきますが、実行に支障はないので、気にしないでください。

## 6. 10レポート提出
実際にやって、実行結果が書かれた各自のWikiページのスクリーンショットまたは写真を提出してください。

## 7. 授業の振り返り

## 8. 謝辞
以下のページを含む様々なページを参考にさせていただきました。感謝します。
* 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/