8. @Anvilを用いたWebアプリの構築

このプロジェクトでは、Raspberry Pi Pico WとAnvilのサーバーとの間で双方向通信を行います。 Pico Wから送信される温度と湿度はAnvilでリアルタイムに表示されます。さらに、Anvilでメッセージを入力すると、それがPico WのI2C LCD1602に表示されます。

anvil

1. 必要なコンポーネント

このプロジェクトで必要なコンポーネントは以下の通りです。

全体のキットを購入する方が確実に便利です。リンクはこちら:

名前

このキットに含まれるアイテム

リンク

ケプラーキット

450以上

Kepler Kit

以下のリンクから個々に購入することも可能です。

SN

コンポーネント

数量

リンク

1

Raspberry Pi Pico W

1

BUY

2

Micro USBケーブル

1

3

ブレッドボード

1

BUY

4

ジャンパーワイヤー

複数

BUY

5

I2C LCD1602

1

BUY

6

DHT11 湿温度センサー

1

BUY

7

Li-po充電モジュール

1

8

18650バッテリー

1

9

バッテリーホルダー

1

2. 回路を組む

警告

図に示されているようにLi-poチャージャーモジュールが接続されていることを確認してください。そうでない場合、短絡が発生してバッテリーと回路が損傷する可能性があります。

../_images/8.anvil_bb.png

3. Anvilアプリを作成する

  1. Anvil website にアクセスして、 Start building をクリックします。

    ../_images/anvil-1.png
  2. サインインまたはサインアップします。

    ../_images/anvil-2.png
  3. 新しいブランクアプリ を作成します。

    ../_images/anvil-3.png
  4. マテリアルデザインテーマ を選択します。

    ../_images/anvil-4.png
  5. これでアプリの編集ページに移動します。

    ../_images/anvil-5.png
  6. ツールボックスから Label ツールをドラッグして Drop title here に配置します。

    ../_images/anvil-6.png
  7. プロパティ メニューの下の テキスト フィールドでラベルのテキストを入力できます。

    ../_images/anvil-7.png
  8. 同様に、右側に TextBox をドラッグします。

    ../_images/anvil-17.png
  9. ボタン を右端にドラッグし、 テキスト フィールドを変更できます。このボタンはRaspberry Pi Pico Wにメッセージを「送信」するために使用されます。

    ../_images/anvil-14.png
  10. SHOW ボタンをダブルクリックすると、フォームはデザインページからコードページに切り替わり、その ボタン のコードが強調表示されます。次のコードを入力する必要があります。このコードは、サーバー(この場合、Pico W)内の関数を呼び出す機能があります。

    anvil.server.call_s("show_message",self.text_box_1.text)
    
    • show_message はPico Wがプログラムされたときに定義される関数です。

    • self.text_box_1.text はテキストボックスに入力するメッセージであり、 show_message() にパススルーとして送信されます。

    ../_images/anvil-15.png
  11. デザインページに戻って、別のラベルをドラッグして以前の要素の下に配置します。このラベルはPico WからのDHT11センサーデータを表示します。

    ../_images/anvil-9.png
  12. ツールボックスMore Components をクリックし、 Timer をフォームにドラッグします。

    ../_images/anvil-12.png
  13. プロパティ を使用して、タイマーを3秒の間隔に設定します。この時間は、センサーデータの画面を更新するために使用されます。

    ../_images/anvil-18.png
  14. Timer ツールをダブルクリックしてプログラムします。 anvil.server.call_s() 関数を使用して、Anvilアプリに表示する必要のあるメッセージをサーバーから取得するための publish_data() 関数を呼び出し、それを self.label_2.text に割り当てて完了します。

    data=anvil.server.call_s("publish_data")
    self.label_2.text=data
    
    ../_images/anvil-16.png
  15. この時点で、Anvilでプログラムする必要のある部分は完了です。Anvilの使用に関する詳細は、 Anvil Docs で確認できます。

4. Pico Wのセットアップ

AnvilサービスへのRaspberry Pi Pico Wの接続を簡単にするため、Anvilはカスタムファームウェアイメージを使用します。Pico WのファームウェアはMicroPythonで書かれており、USBドライブとして(boot.pyとmain.pyの2つのファイルを持つ形で)認識されます。コードを書き始める前に、Pico Wにカスタムファームウェアをフラッシュし、Wi-Fiに接続する必要があります。

  1. Raspberry Pi Pico W用のカスタムファームウェア firmware from Anvil をダウンロードします。完全版のダウンロードが推奨されます。

    ../_images/anvil-p-1.png
  2. Pico Wの BOOTSEL ボタンを押しながら、マイクロUSBケーブルでコンピュータに接続します。ドライブRPI-RP2がコンピュータに表示されたら、BOOTSELを離します。

    ../_images/anvil-p-2.png
  3. ダウンロードしたばかりの .uf2 ファイルをドラッグ&ドロップします。この時点でPico Wはファームウェアをインストールします。完了すると、 main.pyboot.py ファイルが表示されます。

    注釈

    ファームウェアを再インストールする前に、Pico Wに保存された重要なファイルのバックアップを取ってください。

    ../_images/anvil-p-3.png
  4. Thonny IDEでインタプリタとして"MicroPython(Raspberry Pi Pico).COMXX"を選択します。 View -> Files をクリックすると、ローカルドライブとRaspberry Pi Picoのハードドライブが表示されます。

    ../_images/anvil-20.png
  5. boot.py スクリプトをダブルクリックし、WiFiの SSIDPASSWORD を入力します。

    ../_images/anvil-21.png

5. コードの完成

  1. kepler-kit-main/libs のパスから dht.pylcd1602.py をRaspberry Pi Pico Wにアップロードします。

    ../_images/anvil-22.png
  2. main.py を開き、以下のコードで元のコードを置き換えます。

    import anvil.pico
    import uasyncio as a
    from machine import Pin,I2C
    
    from lcd1602 import LCD
    lcd = LCD()
    
    from dht import DHT11
    sensor = DHT11(Pin(16, Pin.OUT, Pin.PULL_DOWN))
    
    UPLINK_KEY = "<uplink_key_goes_here>"
    
    @anvil.pico.callable(is_async=True)
    async def show_message(text):
        print(f"show anvil's input message: {text}")
        lcd.clear()
        lcd.message(text)
        return
    
    @anvil.pico.callable(is_async=True)
    async def publish_data():
        sensor.measure()
        return "Temperature: {}, Humidity: {}".format(sensor.temperature, sensor.humidity)
    
    anvil.pico.connect(UPLINK_KEY)
    
  3. Anvilインターフェースに戻り、App Browserの設定でUplinkオプションをタップします。

    ../_images/anvil-p-6.png
  4. Enable the Anvil Server Uplink for this app をクリックして、uplinkキーを取得します。

    ../_images/anvil-p-7.png
  5. それをコピーし、 main.py<uplink_key_goes_here> を置き換えます。これにより、作成したAnvil APPにPico Wが接続できるようになります。

    ../_images/anvil-p-8.png

6. プロジェクトの実行

  1. Run current script ボタンをクリックするか、F5を押して実行します。接続が成功すると、Shellに接続成功のプロンプトが表示されます。

    ../_images/anvil-19.png
  2. Anvilを実行します。これで、Anvil APPから温度と湿度が表示されるようになります。テキストボックスにメッセージを入力した後に SHOW ボタンをクリックすると、I2C LCD1602に入力したメッセージが表示されます。

    注釈

    入力した文字がI2C LCD1602に表示されない場合は、モジュールの裏側にあるポテンショメータを回してコントラストを調整できます。

    ../_images/anvil-r-2.png

7. APPの公開

作成したアプリを他人と共有したい場合は、以下の方法で共有リンクを生成できます。

  1. Anvil ページに戻って、 App Browser settings 内の publish app オプションをクリックします。

    ../_images/anvil-s-1.png
  2. Share via private link タブにはリンクのリストが表示されます。このリンクを通じて誰でもアプリにアクセスできます。

    ../_images/anvil-s-2.png
  3. リンクにアクセスすると、アプリは直接使用可能になります。

    ../_images/anvil-s-3.png
  4. 公開リンクを通じてもアプリを共有できます。独自のドメイン名を入力し、下の Apply をクリックして有効にします。

    ../_images/anvil-s-4.png

仕組みは?

以下は、Pico WとAnvil APPの通信の基本となる main.py の基本フレームワークです。

import anvil.pico
import uasyncio as a

UPLINK_KEY = "<uplink_key_goes_here>"

anvil.pico.connect(UPLINK_KEY)

dht11とlcd1602のセットアップ。これら2つのコンポーネントの使用方法の詳細は、 6.2 温度・湿度センサー3.4 液晶ディスプレイ で確認できます。

from machine import Pin,I2C

from lcd1602 import LCD
lcd = LCD()

from dht import DHT11
sensor = DHT11(Pin(16, Pin.OUT, Pin.PULL_DOWN))

Anvilのコードでは、サーバー(Pico W)の2つの内部関数を呼び出しています。

最初は show_message() で、この関数はAnvilで入力されたメッセージをLCDに表示させる役割があります。 デコレータ @anvil.pico.callable(is_async=True) は、この関数をAnvilから呼び出し可能にします。

@anvil.pico.callable(is_async=True)
async def show_message(text):
    print(f"show anvil's input message: {text}")
    lcd.clear()
    lcd.message(text)
    return

次は publish_data() で、これはdht11の値を取得し、温度と湿度をAnvilに返す機能があります。 これもデコレータ @anvil.pico.callable(is_async=True) を使用して、Anvilから呼び出し可能にします。

@anvil.pico.callable(is_async=True)
async def publish_data():
    sensor.measure()
    return "Temperature: {}, Humidity: {}".format(sensor.temperature, sensor.humidity)