【発売間近】Raspberry Pi Pico W 無線LAN機能の使い方完全ガイド

【発売間近】Raspberry Pi Pico W 無線LAN機能の使い方完全ガイド

ラズベリーパイのマイコンであるPico。高性能かつ低価格なPicoには無線LAN(Wi-Fi)が使えないという欠点がありました。

2022年6月30日、満を持して発表されたWi-Fi機能付モデルのRaspberry Pi Pico W。海外ではすでに販売されているものの、技術適合証明(技適)待ちとなっていました。

そんな中ついにPico Wの技適取得が完了発売間近といわれています。

チェックポイント

この記事で使用しているPico WはイギリスのPIMORONIというショップで購入しました。技適マークの付いていない製品のため、自分で特例制度の申請を行っています。

この記事はPico Wの特徴や使い方をまとめました。後半では下記の操作方法を解説しています。

  • スマートフォンからPicoのLEDを操作する
  • PicoからLINEへメッセージを送る
  • インターネットから情報を取得する

Picoは高性能なマイコン

はじめにPicoシリーズの特徴を解説します。すでにPicoを使ったことがある方は下のボタンを押して、説明をスキップしてください。

お急ぎの方はこちらをクリック!

Picoはマイコン=電子工作に特化

Picoとラズベリーパイ。どちらもRaspberry Pi財団が開発した基板で見た目も似ていますが、大きな違いがあります。

PicoとRaspberry Piの違いの図解

Picoは電子工作に特化したマイコン(マイクロコントローラー)です。ラズパイのようにOS(Operating System)を動かすことはできません。つまりPicoをパソコンのように使うことは不可能です。

電子工作はプログラムでパーツを制御すること

電子工作ではセンサーやモーターといった電子パーツを使って、独自の機能を持った作品が作れます。

例えば以下のような「人が通ったことを検知して照明のスイッチを自動で押す」といった装置も、手軽に作れるのが電子工作の魅力です。

単純な動きに見えますが、モーターを動かす角度や動作後の待機時間など緻密な調整が入っています。メイカー(独創的なDIYを楽しむ人)にとってはそこが腕の見せ所であり醍醐味です。

Picoで使える言語

プログラミング言語はMicroPythonまたはC言語が使えます。MicroPythonはマイコンを操作するための言語で、Pythonと同じ文法でプログラミングできます。

Picoとラズパイの使い分け

ラズパイにもGPIOピンが付いているため、電子工作は可能です。Picoでできることは、ほぼラズパイでもできます。しかし比較的シンプルな作品はPicoを使う方がスマートです

ラズパイに単純な仕事をさせるのはオーパースペックといえます。動作確認で使うならまだしも、長期間運用させると別の用途に使えず、もったいなく感じるからです。

低価格なPicoシリーズ

ラズパイは高額なため作品完成後に別のものが作りたくなったとき、一度分解して作り直すケースが多いです。一方Picoは低価格なので、複数購入して新しい作品を次々と作るといった用途に向いています。

参考価格詳細

Rapberry Pi Pico
770円詳細を見る

Rspberry Pi Pico W
1,298円詳細を見る

Raspberry Pi
Zero 2W
2,948円詳細を見る

Raspberry Pi 4
2GB:8,800円
4GB:10,450円
8GB:14,080円
詳細を見る

ラズパイではなくPicoを使うメリット

低価格だから低品質とは限りません。Picoを使うメリットは次の5つです。

  • 低価格
  • 低消費電力
  • コンパクト
  • A/Dコンバーター内蔵
  • 起動が速い

そして今回、Wi-Fi搭載のPico Wが発売され、メリットは大幅に増えることになりました。

Picoとラズパイの違いについてもっと詳しく知りたい方は以下の記事をご覧ください。
≫【レビュー】Raspberry Pi Picoは何ができる?ピコとラズパイ 5つの違い

Raspberry Pi Pico Wのスペック

普通のPicoと同じくRaspberry Pi財団が独自に開発したマイクロコントローラーチップのRP2040が搭載されています。

従来のPicoとの違いはWi-Fiが付いたことだけです。基本スペックは変わっていません。

裏面にはGPIOピンの名前が書いてあります。電子パーツを接続するときにわかりやすいです。

Pico Wのスペックを以下にまとめました。

CPUCortex-M0+ 133MHz × 2
RAM264kB on-chip SRAM
Flash メモリー2MB on-board Quad-SPI
無線LAN2.4GHz IEEE 802.11b/g/n
Bluetoothサポートなし
電源1.8~5.5V
USBmicro-USB
サイズ51mm × 21mm × 3.9mm
重量3g
参考価格
(スイッチサイエンス)
1,298円

公式のプロモーション動画はこちらからご覧いただけます。

Bluetoothは現状使えない

Pico WにはCYW43439というBluetooth対応の無線チップが搭載されています。しかし、Pico WではBluetoothが有効化されていないため、Wi-Fiしか利用できません。ラズベリーパイ財団のブログによると、将来的にはBluetoothを有効にする可能性があるそうです。

普通のPicoとPico Wの違い

GPIOのピン配置は以下の通りです。基本的には普通のPicoと変わりません。

出典:ラズベリーパイ財団

Picoの基板にはプログラムで点灯できるLEDが付いています。普通のPicoとPico WではLEDの接続場所が違います。

普通のPicoはCPUに直接つないでいるのに対して、Pico Wは無線チップ経由でCPUにつながっています。LEDを光らせるためのプログラムも違うので、注意が必要です。

無線機能でできること

Raspberry Pi Pico Wは無線LAN(Wi-Fi)と接続できます。無線機能を使ってできることは以下の通りです。

  • ネットワーク経由でPico Wに指令を送る
  • ネットワーク経由でPico Wの状態を確認する
  • WebサービスへPico Wの状態をアップロードする
  • インターネットから情報を取得する
  • ChatGPT APIを使ってAIロボットを作る

以下の事例では、電子ペーパーに時刻やビットコインの価格を表示しています。時刻はインターネットを経由して取得しているため、時刻合わせが不要で正確です。ビットコインの価格はコインチェックのAPIから取得しています。

また、話題の文章生成AIであるChatGPTを使ってAIロボットを作ることが可能です。

Raspberry Pi Pico WでChatGPT APIを使う方法は、以下の記事で詳しく説明してします。
≫ AIと電子工作の融合!Raspberry Pi Pico WでChatGPT APIを使用する方法

Raspberry Pi Pico Wの特徴はITエンジニアもりしーさんの動画で詳しく解説されています。

Raspberry Pi Pico Wの使い方(基礎編)

Picoを使ったことがある方はクリック

PicoはOSが利用できないため、単体ではプログラミングできません。Picoにプログラムを書き込む方法は以下の2つです。

【ラズベリーパイを使う場合】

Raspberry Pi OSにあらかじめインストールされているThonnyというソフトを利用します。ラズベリーパイを持っている方は比較的スムーズに環境構築できます。

【パソコンを使う場合】

ネット情報を調べながら作業をする場合は、動作の速いパソコンの方が快適に作業できるでしょう。パソコンでプログラミングをする場合、事前にThonnyというソフトのインストール作業が必要です。

本記事ではパソコンを使ってPico Wにプログラムを書き込む方法を解説します。

パソコンとPico Wを接続する

パソコンとPico Wの接続には以下のようなUSBケーブルを使います。

Pico WのBOOTSELボタンを押しながらパソコンと接続します。先にパソコン側を接続しておくと、ボタンを押しやすくなります。

チェックポイント

BOOTSELボタンを押しながら接続すると、Picoが外部ストレージとして認識されます。

RPI-RP2(D:)としてパソコンが認識します。

Pico WにMicroPythonのファームウェアを書き込む

Pico WでMicroPythonを使えるようにするために、まずファームウェアを書き込む必要があります。ファームウェアはPico Wを動作させるためのソフトウェアです。

パソコンが認識したRPI-RP2(D:)を開くと以下のように表示されます。

INDEXというファイルを開きます。

するとブラウザでRaspberry Pi財団のサイトが立ち上がります。

MicroPythonをクリックします。

画面を少し下にスクロールして、Raspberry Pi Pico Wと書かれたリンクをクリックするとuf2ファイルがパソコンにダウンロードされます。

ダウンロードしたuf2ファイルをRPI-RP2(D:)にドラッグアンドドロップします。

以上の操作でMicroPythonファームウェアの書き込みが完了しました。Pico Wはプログラムが書き込める状態になっています。

パソコンにThonnyをインストールする

Thonnyの画面

パソコンでプログラムを作成するための準備としてThonnyをインストールします。ThonnyはPythonプログラムを書くためのソフトです。Thonnyでは以下の4つの操作ができます。

  • プログラムの作成・編集
  • プログラムの実行
  • Picoへファイルの書き込み
  • Picoに保存されたファイルの管理

Thonnyはこちらのサイトからダウンロードできます。Raspberry Pi OSではあらかじめThonnyが使える状態になっているのでインストール不要です。

Windowsを使っている方はWindowsの部分をクリックして、インストールファイルをダウンロードします。

インストールしたファイルをクリックして実行します。

Install for me only (recommended)をクリック

しばらくNextを押していきます。

デスクトップ画面にThonnyのアイコンを設置したい場合はチェックを入れます。

Installを押すとインストール開始です。

インストールが完了したらThonnyを開いてみましょう。

Pico Wでプログラムを実行する準備

画面右下部分をクリックします。

Raspberry Pi Picoと記載された部分をクリックします。

以下のような表示になれば、プログラムの実行対象がPicoに切り替わっています。

Pico W本体のLEDをプログラミングで点滅させる

Pico Wの基板にはプログラムで制御できるLEDが付いています。まずはこのLEDを点滅させて、プログラムを実行するまでの手順を確認してみましょう。

以下のプログラムをコピーしてThonnyの画面にペーストします。

import machine
import utime
led = machine.Pin("LED", machine.Pin.OUT)
while True:
    led.on()
    utime.sleep(1)
    led.off()
    utime.sleep(1)

プログラムは以下の場所へペーストしてください。

チェックポイント

LEDを点滅させるためのプログラムは普通のPicoと同じではありません。基板上のLEDの接続方法が違うからです。普通のPicoはCPUに接続されているのに対して、Pico Wは無線LANのGPIOに接続されています。

実行する前にプログラムをPico Wに書き込みます

名前はmain.pyで保存しておきます。ファイル名の理由はあとで解説します。

プログラムが保存出来たら、実行ボタンを押してみましょう。

以下のようにLEDが点滅するはずです。

「main.py」は自動で実行される

一度パソコンからPico Wを外して、今度はBOOTSELボタンを押さずにパソコンにつないでみましょう。するとLED点滅が始まります。

今度は以下のようなACアダプターをPico Wに接続してみましょう。パソコンにつながっていなくても、LED点滅が実行されます。Pico Wにプログラムが書き込まれていることが確認できました

チェックポイント

Picoは電源供給時に「main.py」と いう名前で保存したプログラムを自動で実行します。

再度パソコンに接続してプログラムを編集する方法

Pico WのBOOTSELボタンを押さずにパソコンに接続したら、Thonnyを立ち上げます。

「main.py」のプログラムが実行されるので、停止ボタンを押します。

以下の表示が出れば接続成功です。

これで、プログラムの編集ができる状態になりました。

Raspberry Pi Pico Wの使い方(Wi-Fi編)

Pico Wの大本命であるWi-Fiを使っていきます。あらかじめ自宅Wi-FiのSSIDパスワードを調べておきましょう。SSIDは2.4Gのものが使えます。Pico Wは5GのWi-Fiに対応していません

Pico W本体のLEDをWi-Fi経由で操作する

先ほど点滅させたLEDをWi-Fiから操作してみましょう。

以下のコードをコピペしてください。10行目と11行目のYOUR NETWORK SSIDYOUR NETWORK PASSWORDの部分は自宅Wi-FiのSSIDとパスワードに変更する必要があります。

import time
import network
import socket
from machine import Pin

led = Pin("LED", machine.Pin.OUT)
ledState = 'LED State Unknown'

#自宅Wi-FiのSSIDとパスワードを入力
ssid = 'YOUR NETWORK SSID'
password = 'YOUR NETWORK PASSWORD'

wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)

html = """<!DOCTYPE html><html>
<head><meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="data:,">
<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}
.buttonGreen { background-color: #4CAF50; border: 2px solid #000000;; color: white; padding: 15px 32px; text-align: center; text-decoration: none; display: inline-block; font-size: 16px; margin: 4px 2px; cursor: pointer; }
.buttonRed { background-color: #D11D53; border: 2px solid #000000;; color: white; padding: 15px 32px; text-align: center; text-decoration: none; display: inline-block; font-size: 16px; margin: 4px 2px; cursor: pointer; }
text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}
</style></head>
<body><center><h1>Raspberry Pi Pico W</h1></center><br><br>
<form><center>
<center> <button class="buttonGreen" name="led" value="on" type="submit">LED ON</button>
<br><br>
<center> <button class="buttonRed" name="led" value="off" type="submit">LED OFF</button>
</form>
<br><br>
<br><br>
<p>%s<p></body></html>
"""

# Wait for connect or fail
max_wait = 10
while max_wait > 0:
    if wlan.status() < 0 or wlan.status() >= 3:
        break
    max_wait -= 1
    print('waiting for connection...')
    time.sleep(1)
    
# Handle connection error
if wlan.status() != 3:
    raise RuntimeError('network connection failed')
else:
    print('Connected')
    status = wlan.ifconfig()
    print( 'ip = ' + status[0] )
    
    
# Open socket
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
s = socket.socket()
s.bind(addr)
s.listen(1)
print('listening on', addr)

# Listen for connections, serve client
while True:
    try:       
        cl, addr = s.accept()
        print('client connected from', addr)
        request = cl.recv(1024)
        print("request:")
        print(request)
        request = str(request)
        led_on = request.find('led=on')
        led_off = request.find('led=off')
        
        print( 'led on = ' + str(led_on))
        print( 'led off = ' + str(led_off))
        
        if led_on == 8:
            print("led on")
            led.value(1)
        if led_off == 8:
            print("led off")
            led.value(0)
        
        ledState = "LED is OFF" if led.value() == 0 else "LED is ON" # a compact if-else statement
        
        # Create and send response
        stateis = ledState
        response = html % stateis
        cl.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n')
        cl.send(response)
        cl.close()
        
    except OSError as e:
        cl.close()
        print('connection closed')

参考にしたサイト:Raspberry Pi Pico W | Create a Simple HTTP Server

エラーが出る場合は一度Pico Wを取り外す

プログラムを実行します。以下のエラー表示が出る場合はPico Wを一旦パソコンから外して、接続しなおしてから実行してください。≫Pico Wを再接続する方法

IPアドレスを確認する

Wi-Fi接続が成功するとシェルに以下のような表示が出ます。

上の画像中の赤線部分がPico WのIPアドレスです。

チェックポイント

IPアドレスとはネットワーク内で自動的に割り振られた番号のことです。この場合はプライベートIPアドレスといい、自宅のネットワーク内での番号となります。IPアドレスを使ってPCやスマホからPicoにアクセスします。

IPアドレスをブラウザのアドレスバーに入力してください。ブラウザはChromeでもEdgeでも何でも構いません。

すると以下の画面が表示されます。

LED ONLED OFFのボタンをクリックすると、Pico WのLEDが点灯したり消えたりします。Wi-Fiにつながっていれば、スマートフォンやタブレットのブラウザでも操作可能です。

温度センサーの数値をWi-Fi経由で確認する

Pico Wには温度センサーが内蔵されています。この温度をWi-Fiネットワーク経由で確認してみましょう。

温度取得の基本

温度センサーの数値を取得するプログラムは以下の通りです。

import machine
import utime
sensor_temp = machine.ADC(4)
conversion_factor = 3.3 / (65535)
 
while True:
    reading = sensor_temp.read_u16() * conversion_factor
    temp = 27 - (reading - 0.706)/0.001721
    temp = round(temp, 1)
    print(temp)
    utime.sleep(1)

実行するとPico Wの温度が1秒おきに表示されます。

IC内部の温度なので、室温より少し高めに表示されることが多いです。

温度をWi-Fi経由で見る方法

Pico Wの温度をWebページに表示させるプログラムは以下のようになります。

import time
import network
import socket
from machine import Pin

led = Pin("LED", machine.Pin.OUT)
ledState = 'LED State Unknown'

sensor_temp = machine.ADC(4)
conversion_factor = 3.3 / (65535)

#自宅Wi-FiのSSIDとパスワードを入力
ssid = 'YOUR NETWORK SSID'
password = 'YOUR NETWORK PASSWORD'

wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)

html = """<!DOCTYPE html>
<html>
<head> <title>Pico W</title> </head>
<body> <h1>Pico W HTTP Server</h1>
<p>Hello, World!</p>
<p>%s</p>
</body>
</html>
"""

# Wait for connect or fail
max_wait = 10
while max_wait > 0:
    if wlan.status() < 0 or wlan.status() >= 3:
        break
    max_wait -= 1
    print('waiting for connection...')
    time.sleep(1)
    
# Handle connection error
if wlan.status() != 3:
    raise RuntimeError('network connection failed')
else:
    print('Connected')
    status = wlan.ifconfig()
    print( 'ip = ' + status[0] )
    
    
# Open socket
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
s = socket.socket()
s.bind(addr)
s.listen(1)
print('listening on', addr)

# Listen for connections, serve client
while True:
    try:       
        cl, addr = s.accept()
        print('client connected from', addr)
        request = cl.recv(1024)
        print("request:")
        print(request)
        request = str(request)
        
        reading = sensor_temp.read_u16() * conversion_factor
        temp = 27 - (reading - 0.706)/0.001721
        temp = round(temp, 1)
        temp = str(temp)
        
        # Create and send response
        stateis = "Pico Temp: " + temp
        response = html % stateis
        cl.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n')
        cl.send(response)
        cl.close()
        
    except OSError as e:
        cl.close()
        print('connection closed')

プログラムを実行してブラウザからアクセスすると、以下の画面が表示されます。Pico Wの温度が確認できます。

ページを更新すると最新の温度が表示されます。

LED操作と温度確認を同時にできるようにする

先ほどのLEDをブラウザから操作するプログラムと合体すると以下のようになります。

import time
import network
import socket
from machine import Pin

led = Pin("LED", machine.Pin.OUT)
ledState = 'LED State Unknown'

sensor_temp = machine.ADC(4)
conversion_factor = 3.3 / (65535)

#自宅Wi-FiのSSIDとパスワードを入力
ssid = 'YOUR NETWORK SSID'
password = 'YOUR NETWORK PASSWORD'

wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)

html = """<!DOCTYPE html><html>
<head><meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="icon" href="data:,">
<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}
.buttonGreen { background-color: #4CAF50; border: 2px solid #000000;; color: white; padding: 15px 32px; text-align: center; text-decoration: none; display: inline-block; font-size: 16px; margin: 4px 2px; cursor: pointer; }
.buttonRed { background-color: #D11D53; border: 2px solid #000000;; color: white; padding: 15px 32px; text-align: center; text-decoration: none; display: inline-block; font-size: 16px; margin: 4px 2px; cursor: pointer; }
text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}
</style></head>
<body><center><h1>Raspberry Pi Pico W</h1></center><br><br>
<form><center>
<center> <button class="buttonGreen" name="led" value="on" type="submit">LED ON</button>
<br><br>
<center> <button class="buttonRed" name="led" value="off" type="submit">LED OFF</button>
</form>
<br><br>
<br><br>
<p>%s<p></body></html>
"""

# Wait for connect or fail
max_wait = 10
while max_wait > 0:
    if wlan.status() < 0 or wlan.status() >= 3:
        break
    max_wait -= 1
    print('waiting for connection...')
    time.sleep(1)
    
# Handle connection error
if wlan.status() != 3:
    raise RuntimeError('network connection failed')
else:
    print('Connected')
    status = wlan.ifconfig()
    print( 'ip = ' + status[0] )
    
    
# Open socket
addr = socket.getaddrinfo('0.0.0.0', 80)[0][-1]
s = socket.socket()
s.bind(addr)
s.listen(1)
print('listening on', addr)

# Listen for connections, serve client
while True:
    try:       
        cl, addr = s.accept()
        print('client connected from', addr)
        request = cl.recv(1024)
        print("request:")
        print(request)
        request = str(request)
        led_on = request.find('led=on')
        led_off = request.find('led=off')
        
        print( 'led on = ' + str(led_on))
        print( 'led off = ' + str(led_off))
        
        if led_on == 8:
            print("led on")
            led.value(1)
        if led_off == 8:
            print("led off")
            led.value(0)
        
        ledState = "LED is OFF" if led.value() == 0 else "LED is ON" # a compact if-else statement
        
        reading = sensor_temp.read_u16() * conversion_factor
        temp = 27 - (reading - 0.706)/0.001721
        temp = round(temp, 1)
        temp = str(temp)
        
        # Create and send response
        stateis = ledState + "<br><br>Pico Temp: " + temp
        response = html % stateis
        cl.send('HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n')
        cl.send(response)
        cl.close()
        
    except OSError as e:
        cl.close()
        print('connection closed')

画面下に温度が表示されれば成功です。

応用編

僕はIPアドレスを手入力するのが面倒だったので、QRコードを表示して簡単に接続できるようにしました。QRコードの表示には、有機ELディスプレイ(OLED)を使用しています。

BOOTSELボタンを押してLINEにメッセージを送る

Pico WのWi-Fi機能を利用すれば、LINEへメッセージ送信することが可能です。Pico Wのボタンを使って呼び出しボタンを作ってみましょう。

LINE Notifyのトークンを取得する

メッセージの送信にはLINE Notifyという、LINEアプリに自動で通知を行うサービスを利用します。LINEアカウントを持っていれば無料で登録できます。登録時に発行されるトークンを保存しておいてください。

LINE Notifyの登録方法は以下の記事で詳しく解説しています。
≫【Python入門】LINEに自動メッセージを送る

BOOTSELボタンを読み取る

BOOTSELボタンを読み取るにはファームウェアの変更が必要です。ファームウェアはこちらからダウンロードできます。ダウンロードしたuf2ファイルをRPI-RP2(D:)にドラッグアンドドロップします。ファームウェアを書き換えても、保存されたプログラムは消えません。

ファームウェア書き換え後、以下のプログラムを実行すると、BOOTSELボタンが押されたときにPico WのLEDが光ります。

import utime
    
while True:
    if rp2.bootsel_button() == 1:
        machine.Pin('LED', machine.Pin.OUT).on()
    else:
        machine.Pin('LED', machine.Pin.OUT).off()
    utime.sleep(0.1)

参考にしたサイト:BOOTSELボタンでLチカ【Raspberry Pi Pico W】 

Pico WからLINEメッセージを送る

まずMicroPythonでLINEに通知を送るためのモジュールを準備します。こちらのサイトが参考になります。

以下のプログラム(モジュール)をtiny_line.pyという名前で保存します。

import usocket as socket
import ussl as ssl

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# ---- percent encoding
def RFC3986_encode(s):
    ret = ''
    bts = s.encode('utf-8')
    for c in bts :
        if c in range(0x30, 0x39 + 1) or \
           c in range(0x41, 0x5a + 1) or \
           c in range(0x61, 0x7a + 1) or \
           c in (0x2d, 0x2e, 0x5f, 0x7e):
            ret += chr(c)
        else :
            ret += '%%%02X' % (c)
    return ret

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class tiny_line :
    def __init__(self, access_token, debug=False) :
        # パラメータチェック
        if type(access_token) is not str:
            raise ValueError("access key must be string")
        
        self.access_token      = access_token
        self.__DEBUG__         = debug

    def __debug_print(self, str) :
        if self.__DEBUG__ :
            print(str)
    
    def __makeRequestMessage(self, method, host, message) :
        method = method.upper()                                     # to upper
        
        # make request
        request = method + ' ' + host['endpoint'] + ' HTTP/1.0\n'   # HTTP/1.0 を指定するとChunked Transferにならないので、レスポンスが1行で済む
        
        # make message body
        body = 'message=' + RFC3986_encode(message)
        
        # make message header
        header  = 'Host: ' + host['host'] + '\n'                        \
                + 'User-Agent: micropython line Bot v0.1\n'             \
                + 'Accept: */*\n'                                       \
                + 'Authorization: Bearer ' + self.access_token +'\n'    \
                + 'Content-Type: application/x-www-form-urlencoded\n'   \
                + 'Content-Length: ' + str(len(body)) + '\n'
                # HTTP/1.0の場合は以下は要らない
                #+ 'Connection: close\n'                                 \

        # request message
        ret = request + header + '\n' + body + '\n'
        return(ret)
    
    def __sendmessage(self, host, msg) :
        sock = socket.socket()
        addr = socket.getaddrinfo(host['host'], host['port'])[0][-1]
        
        # connect socket
        sock.connect(addr)
        try :
            # SSL wrap
            ssl_sock = ssl.wrap_socket(sock)
            
            # send data
            ssl_sock.write(msg)

        except Exception as e:
            # エラーが発生したらクローズして上位へ例外通知
            ssl_sock.close()
            raise e
        # メッセージ本体を受信(とりあえず読み捨て)
        # 制限回数を超えた場合なんかはここでチェックが必要?
        rcv_line = b''
        while True :
            try :
                l = ssl_sock.readline()
            except Exception as e:              # エラーが発生したらクローズして上位へ例外通知
                ssl_sock.close()
                raise e
           
            if not l:                           # データがない → 終了
                break
            
            # 読み込んだデータをためる
            rcv_line += l
        
        # self.__debug_print("@@@@" + str(rcv_line))
        self.__debug_print("close!!")
        ssl_sock.close()
    
    # ######## notify API ################################
    def notify(self, msg) : 
        host = { 'host': 'notify-api.line.me', 'port': 443, 'endpoint': '/api/notify'}
        
        reqMessage = self.__makeRequestMessage('POST', host, msg)
        self.__debug_print('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%')
        self.__debug_print(reqMessage)
        self.__debug_print('%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%')
        
        self.__sendmessage(host, reqMessage)

モジュールを保存後、以下のプログラムを実行するとLINEに通知が届きます。10行目のaccess_tokenの部分にLINE Notifyのトークンを入力してください。

from tiny_line import tiny_line
import urequests as requests
import network
import utime

#自宅Wi-FiのSSIDとパスワードを入力
ssid = 'YOUR NETWORK SSID'
password = 'YOUR NETWORK PASSWORD'

access_token    = 'トークンをここに入力'

wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)

# Wait for connect or fail
max_wait = 10
while max_wait > 0:
    if wlan.status() < 0 or wlan.status() >= 3:
        break
    max_wait -= 1
    print('waiting for connection...')
    utime.sleep(1)
    
# Define blinking function for onboard LED to indicate error codes    
def blink_onboard_led(num_blinks):
    led = machine.Pin('LED', machine.Pin.OUT)
    for i in range(num_blinks):
        led.on()
        utime.sleep(.2)
        led.off()
        utime.sleep(.2)
        
# Handle connection error
# Error meanings
# 0  Link Down
# 1  Link Join
# 2  Link NoIp
# 3  Link Up
# -1 Link Fail
# -2 Link NoNet
# -3 Link BadAuth        
    
wlan_status = wlan.status()
blink_onboard_led(wlan_status)

if wlan_status != 3:
    raise RuntimeError('Wi-Fi connection failed')
else:
    print('Connected')
    status = wlan.ifconfig()
    print('ip = ' + status[0])


# 初期化
tl = tiny_line(access_token, debug=True)
# メッセージ送信
tl.notify("Raspberry Pi Pico Wのボタンが押されました!")

本番用のプログラム

BOOTSELボタンが押されたときにLINEへメッセージを送るプログラムは以下のようになります。LINE Notifyのトークン入力はお忘れなく。

import utime
import urequests as requests
import network
import socket
from tiny_line import tiny_line

#自宅Wi-FiのSSIDとパスワードを入力
ssid = 'YOUR NETWORK SSID'
password = 'YOUR NETWORK PASSWORD'

#LINE token
access_token    = 'トークンをここに入力'
# 初期化
tl = tiny_line(access_token, debug=True)

wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)

# Wait for connect or fail
max_wait = 10
while max_wait > 0:
    if wlan.status() < 0 or wlan.status() >= 3:
        break
    max_wait -= 1
    print('waiting for connection...')
    utime.sleep(1)
    
# Define blinking function for onboard LED to indicate error codes    
def blink_onboard_led(num_blinks):
    led = machine.Pin('LED', machine.Pin.OUT)
    for i in range(num_blinks):
        led.on()
        utime.sleep(.2)
        led.off()
        utime.sleep(.2)
        
# Handle connection error
# Error meanings
# 0  Link Down
# 1  Link Join
# 2  Link NoIp
# 3  Link Up
# -1 Link Fail
# -2 Link NoNet
# -3 Link BadAuth        
    
wlan_status = wlan.status()
blink_onboard_led(wlan_status)

if wlan_status != 3:
    raise RuntimeError('Wi-Fi connection failed')
else:
    print('Connected')
    status = wlan.ifconfig()
    print('ip = ' + status[0])

last_state = 0

while True:
    current_state = rp2.bootsel_button()
    if last_state == 0 and current_state == 1:
        machine.Pin('LED', machine.Pin.OUT).on()
        utime.sleep(0.5)
        machine.Pin('LED', machine.Pin.OUT).off()
        tl.notify("Raspberry Pi Pico Wのボタンが押されました!")
        print("send")
        utime.sleep(2)
    last_state = current_state

参考にしたサイト:Raspberry Pi Pico W Wi-Fi Doorbell tutorial (HTTP requests & IFTTT)

インターネットから情報を取得する

Pico WはWi-Fiが使えるため、Web上で公開されているさまざまな情報を自動で取得できます。今回はビットコインの価格を取得して表示してみましょう。ビットコインの価格はコインチェックという仮想通貨取引所のAPIから取得します。

チェックポイント

APIとはApplication Programming Interface(アプリケーションプログラミングインタフェース)の略です。コインチェックのAPIでは、取引所の注文状況や取引の履歴などが、自動で取得しやすい形式で公開されています。APIを利用すれば、必要な情報を比較的簡単に取得できます

コインチェックのAPIから現在のビットコイン価格を取得するプログラムは以下の通りです。

import utime
import urequests as requests
import network

#自宅Wi-FiのSSIDとパスワードを入力
ssid = 'YOUR NETWORK SSID'
password = 'YOUR NETWORK PASSWORD'
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)

# Wait for connect or fail
max_wait = 10
while max_wait > 0:
    if wlan.status() < 0 or wlan.status() >= 3:
        break
    max_wait -= 1
    print('waiting for connection...')
    utime.sleep(1)
    
# Define blinking function for onboard LED to indicate error codes    
def blink_onboard_led(num_blinks):
    led = machine.Pin('LED', machine.Pin.OUT)
    for i in range(num_blinks):
        led.on()
        utime.sleep(.2)
        led.off()
        utime.sleep(.2)
        
# Handle connection error
# Error meanings
# 0  Link Down
# 1  Link Join
# 2  Link NoIp
# 3  Link Up
# -1 Link Fail
# -2 Link NoNet
# -3 Link BadAuth        
    
wlan_status = wlan.status()
blink_onboard_led(wlan_status)

if wlan_status != 3:
    raise RuntimeError('Wi-Fi connection failed')
else:
    print('Connected')
    status = wlan.ifconfig()
    print('ip = ' + status[0])
    
#コインチェックのAPIのURL
url = 'https://coincheck.com/api/ticker'

#コインチェックのAPIからデータを取得
cc = requests.get(url).json()

#必要なデータを取り出して見やすくなるように加工する
cc_last = '{:,}'.format(int(cc['last']))

print("Coincheck 現在のビットコインの価格 =", cc_last, "円")

参考にしたサイト:【Python】ビットコインの価格を取得する(Coincheck編)

プログラムを実行すると、以下のように結果が表示されます。

ディスプレイに表示

別売りの有機ELディスプレイ(OLED)にビットコインの価格を表示させることも可能です。

参考までにコードを載せておきます。

import utime
import urequests as requests
import network
import machine
import ssd1306

sda = machine.Pin(0)
scl = machine.Pin(1)
i2c = machine.I2C(0,sda=sda, scl=scl, freq=400000)
oled = ssd1306.SSD1306_I2C(128, 64, i2c)

#自宅Wi-FiのSSIDとパスワードを入力
ssid = 'YOUR NETWORK SSID'
password = 'YOUR NETWORK PASSWORD'
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)

# Wait for connect or fail
max_wait = 10
while max_wait > 0:
    if wlan.status() < 0 or wlan.status() >= 3:
        break
    max_wait -= 1
    print('waiting for connection...')
    utime.sleep(1)
    
# Define blinking function for onboard LED to indicate error codes    
def blink_onboard_led(num_blinks):
    led = machine.Pin('LED', machine.Pin.OUT)
    for i in range(num_blinks):
        led.on()
        utime.sleep(.2)
        led.off()
        utime.sleep(.2)
        
# Handle connection error
# Error meanings
# 0  Link Down
# 1  Link Join
# 2  Link NoIp
# 3  Link Up
# -1 Link Fail
# -2 Link NoNet
# -3 Link BadAuth        
    
wlan_status = wlan.status()
blink_onboard_led(wlan_status)

if wlan_status != 3:
    raise RuntimeError('Wi-Fi connection failed')
else:
    print('Connected')
    status = wlan.ifconfig()
    print('ip = ' + status[0])

#コインチェックのAPIのURL
url = 'https://coincheck.com/api/ticker'

while True:
    cc = requests.get(url).json()
    cc_last = '{:,}'.format(int(cc['last']))
    print("Coincheck 現在のビットコインの価格 =", cc_last, "円")
    oled.fill(0)
    oled.text("BTC/JPY", 0, 5)
    oled.hline(0, 20, 128, 1)
    oled.text(str(cc_last), 30, 30)
    oled.show()
    
    utime.sleep(20)
    


Picoで有機ELディスプレイを使う方法は、以下のサイトで詳しく解説されています。
≫【Raspberry Pi Pico】OLEDディスプレイ(I2C)に文字を描画する方法【MicroPython】

インターネットから時刻を取得する

時刻同期を行うことで、センサーデータやログデータなどのタイムスタンプを正確に記録することができます。以下のコードはNTP(Network Time Protocol)を使用して時刻同期を行い、現在の日付と時刻を出力するものです。

import utime
import network
import ntptime

#自宅Wi-FiのSSIDとパスワードを入力
ssid = 'YOUR NETWORK SSID'
password = 'YOUR NETWORK PASSWORD'
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)

# Wait for connect or fail
max_wait = 10
while max_wait > 0:
    if wlan.status() < 0 or wlan.status() >= 3:
        break
    max_wait -= 1
    print('waiting for connection...')
    utime.sleep(1)
    
# Define blinking function for onboard LED to indicate error codes    
def blink_onboard_led(num_blinks):
    led = machine.Pin('LED', machine.Pin.OUT)
    for i in range(num_blinks):
        led.on()
        utime.sleep(.2)
        led.off()
        utime.sleep(.2)
        
# Handle connection error
# Error meanings
# 0  Link Down
# 1  Link Join
# 2  Link NoIp
# 3  Link Up
# -1 Link Fail
# -2 Link NoNet
# -3 Link BadAuth        
    
wlan_status = wlan.status()
blink_onboard_led(wlan_status)

if wlan_status != 3:
    raise RuntimeError('Wi-Fi connection failed')
else:
    print('Connected')
    status = wlan.ifconfig()
    print('ip = ' + status[0])

while True:
    timZone = 9
    ntptime.host = "ntp.nict.jp"
    ntptime.settime()
    t0 = machine.RTC().datetime()
    hour = t0[4] + timZone

    # 24時を超えた場合、時間を-24する
    if hour >= 24:
        hour -= 24
        
    print("{0}/{1:02d}/{2:02d} {3:02d}:{4:02d}:{5:02d}".format(t0[0],t0[1],t0[2],hour,t0[5],t0[6]))
    utime.sleep(1)

上記のコードを実行すると、1秒おきに現在の日付と時刻が出力されます。

51~54行目の解説は以下の通りです。

timZoneに値9を割り当てます。これは、日本標準時のUTCとの時差を表します。

“ntp.nict.jp”というNTPサーバーから現在の時刻を取得します。ntptime.settime()メソッドを使用して、Picoの内部RTC(Real Time Clock)を、NTPサーバーから取得した現在時刻に設定します。

machine.RTC().datetime()メソッドを使用して、RTCから現在時刻を取得し、t0変数に代入します。t0は、年、月、日、曜日、時、分、秒の7つの要素を持つタプルです。

ピンヘッダーを取り付ければ可能性は無限大

Wi-Fiの便利さは偉大です。Pico W本体だけでも多くの楽しみ方があります。今回の記事ではPico W本体のLEDをWi-Fi経由で操作する方法やLINEへメッセージを送る方法を解説しました。

Pico Wには40か所の入出力があります。ここに別売りのピンヘッダーをはんだ付けすれば、さまざまな電子パーツを簡単に接続できます。スマホからモーターを操作したり、センサーの値を通知をしたりと活用の幅が大きく広がります。そんなときにも、本記事の内容がPico W活用方法の基礎として役立つはずです。

コメント一覧

吉田 純造

きたな pico W
電子工作 最強ですね
楽しみです

返信する

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です