PR

Pico WからLINEへ通知を送るMicroPythonコード|urequestsでプッシュ送信・日本語エラー400対策【自作スマートリモコン 第3回】

ハードウェア制御 / 電子工作
スポンサーリンク

はじめに:Pico WからLINEへ通知を送るIoTシステムの総仕上げ

自作スマートリモコン 第3回

スポンサーリンク

はじめに:Pico WからLINEへ通知を送るコードを完成させる

こんにちは、ニンジンです🥕

この記事では、Raspberry Pi Pico Wの温度データを、Wi-Fi経由でスマホのLINEに通知するMicroPythonコードを完成させます。urequestsでLINE Messaging APIを叩くプッシュ送信の書き方、初心者がほぼ必ずハマる「日本語メッセージを送るとエラー400になる」問題の対処、そしてPCから切り離してコンセントで自動稼働させるmain.pyの作り方まで解説します。

前提として、第1回(配線・温度取得)と第2回(LINE Messaging APIの設定)が終わっている必要があります。第2回で取得した「ユーザーID」と「チャネルアクセストークン(長期)」を手元に用意してください。

いきなり全部を組み合わせるとエラーの原因が分からなくなるため、①Wi-Fi接続テスト → ②LINE送信テスト(英語)→ ③本番コード(日本語対応)の3ステップで進めます。

この記事で分かること

  • MicroPythonでPico Wを自宅Wi-Fiに接続するコード(network.WLAN)
  • urequestsでLINE Messaging APIのプッシュ送信を行うコード
  • 日本語メッセージがエラー400になる原因と、.encode('utf-8')での対策
  • Status Code 400 / 401 / 200なのに届かない、それぞれのチェックポイント
  • Pico Wにmain.pyを保存してPC不要で自動稼働させる方法

スポンサーリンク

Pico WのWi-Fi接続テスト:MicroPythonでネットワークにつなぐ

まずはPico Wの内蔵Wi-Fiで、自宅のルーターに接続できるかをテストします。Thonnyで新しいファイルを開き、下のコードを貼り付けます。WIFI_SSIDとWIFI_PASSWORDは自分の環境に書き換えてください。

# Wifi_Connection_test.py
import network
import time

# Wi-Fi情報をご自身の環境に書き換えてください
WIFI_SSID = "あなたのWi-FiのSSID"
WIFI_PASSWORD = "あなたのWi-Fiのパスワード"

wlan = network.WLAN(network.STA_IF)
wlan.active(True)

print(f"Wi-Fi({WIFI_SSID})に接続中...")
wlan.connect(WIFI_SSID, WIFI_PASSWORD)

# 接続を少し待つ(最大10秒)
timeout = 10
while timeout > 0:
    if wlan.isconnected():
        break
    timeout -= 1
    print(".")
    time.sleep(1)

if wlan.isconnected():
    print("Wi-Fi接続に成功しました!")
    # Pico Wに割り当てられたIPアドレスを表示
    print("IP設定:", wlan.ifconfig())
else:
    print("Wi-Fi接続に失敗しました。SSIDやパスワードを確認してください。")

テスト結果

ThonnyのShellにWi-Fi接続成功とIPアドレスが表示された状態

SSIDとパスワードを書き換えて実行(F5)し、画面下のShellに「Wi-Fi接続に成功しました! IP設定: …」と表示されれば第1関門クリアです。

接続できないときは、Pico Wが2.4GHz帯のみ対応である点に注意してください。ルーターの5GHz専用SSIDを指定していると接続できません。

スポンサーリンク

LINE送信テストとStatus Code別のチェックポイント

Wi-Fiがつながったら、第2回で設定したLINE Messaging APIへ送信テストをします。文字化けの問題を切り分けるため、まずは半角英数字だけのメッセージで通信の成功を確かめます。

下のコードを新しいファイルに貼り付け、WIFI_SSID / WIFI_PASSWORD / LINE_TOKEN / USER_ID の4つを自分の値に書き換えて実行します。

# get_line_message.py
import network
import time
import urequests
import json

# --- ここをご自身の環境のものに書き換えて下さい ---
WIFI_SSID = "あなたのWi-FiのSSID"
WIFI_PASSWORD = "あなたのWi-Fiのパスワード"
LINE_TOKEN = "あなたのトークン(b7+ux...)"
USER_ID = "あなたのユーザーID(U...)"
# --------------------------------------------------

wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(WIFI_SSID, WIFI_PASSWORD)

print("Connecting to Wi-Fi...")
while not wlan.isconnected():
    time.sleep(1)
print("Wi-Fi Connected!")

url = "https://api.line.me/v2/bot/message/push"

# f-stringを使って、完全に1本の文字列にしてヘッダーを作ります
auth_header = f"Bearer {LINE_TOKEN}"

headers = {
    "Content-Type": "application/json",
    "Authorization": auth_header
}

payload = {
    "to": USER_ID,
    "messages": [
        {
            "type": "text",
            "text": "Hello from Pico W! Test OK."
        }
    ]
}

print("Sending to LINE...")
try:
    # データをLINEのサーバーへ送信します
    response = urequests.post(url, data=json.dumps(payload), headers=headers)
    print("Status Code:", response.status_code)
    print("Response:", response.text)
    response.close()
except Exception as e:
    print("Error:", e)

テスト結果

ThonnyのShellにStatus Code 200が表示された状態

実行して「Status Code: 200」が表示され、スマホのLINEに「Hello from Pico W! Test OK.」が届けば、API連携は成功です。

うまくいかないときのチェックポイント

400Bad Request と出る

Aデータ形式が不正、とLINEに弾かれています。① LINE_TOKEN や USER_ID の "" の中に余計なスペースや改行が入っていないか、② メッセージを日本語(全角)に書き換えて実行していないか(日本語対策は次のセクション)を確認します。

401Unauthorized と出る

Aチャネルアクセストークンが違います。第2回で発行した b7+ux… から始まる長い文字列が、途中で切れずに正しく貼れているか確認してください。

200成功なのにスマホに届かない

AUSER_ID が別人のIDになっているか、LINE Official Account Managerの「応答設定」でWebhookがオフのままです。第2回の設定を見直してください。

通信[Errno 104] ECONNRESET などが出る

AWi-Fiが不安定か、TLS処理で弾かれています。Pico WのUSBを抜き差しして再起動し、もう一度実行してみてください。


スポンサーリンク

日本語メッセージを送るとエラー400になる原因と対策

送信テストのメッセージを「テスト成功」などの日本語(全角文字)に変えて実行すると、多くの場合 Status Code: 400(Bad Request) で弾かれます。

原因は文字コードです。urequests.post() に data=json.dumps(payload) と文字列のまま渡すと、日本語部分のバイト長とヘッダーが食い違い、LINE側に「壊れたデータ」と判定されてしまいます。

対策:送信の直前に json.dumps(payload).encode('utf-8') でバイト列(bytes)に変換してから data= に渡します。あわせてヘッダーの Content-Type を application/json; charset=UTF-8 にします。次のセクションの本番コードには、この対策を最初から組み込んであります。

スポンサーリンク

本番コード:室温超過でLINE通知する自動アラートプログラム

第1回の温度取得コードと、日本語対応版のLINE送信コードを1つにまとめたものが下の Main_Temp_Line_bot.py です。コード上部の4つの設定(Wi-Fi情報・LINEトークン・ユーザーID)を自分の環境に書き換えてください。しきい値の ALERT_TEMP(既定28℃)とチェック間隔の CHECK_INTERVAL(既定10秒)も好みで調整できます。

# Main_Temp_Line_bot.py
import machine
import dht
import network
import time
import urequests
import json

# --- ここをご自身の環境のものに書き換えて下さい ---
WIFI_SSID = "SSIDを入力"
WIFI_PASSWORD = "Passwordを入力"
LINE_TOKEN = "b7+u・・・で始まるLINEトークンを入力"
USER_ID = "U・・・・から始まるユーザーIDを入力"
# --------------------------------------------------

# --- 2. 見守りの設定 ---
ALERT_TEMP = 28          # この温度(℃)を超えたらLINEを送る
CHECK_INTERVAL = 10      # 温度をチェックする間隔(秒) ※テスト用に短くしています
# --------------------------------------------

# センサーとWi-Fiの初期設定
sensor = dht.DHT11(machine.Pin(15))
wlan = network.WLAN(network.STA_IF)

def connect_wifi():
    wlan.active(True)
    if not wlan.isconnected():
        print("Wi-Fiに接続中...")
        wlan.connect(WIFI_SSID, WIFI_PASSWORD)
        while not wlan.isconnected():
            time.sleep(1)
    print("Wi-Fi接続成功! IP:", wlan.ifconfig()[0])

def send_line(message):
    try:
        connect_wifi()
        url = "https://api.line.me/v2/bot/message/push"
        headers = {
            "Content-Type": "application/json; charset=UTF-8", # 文字コードを指定
            "Authorization": f"Bearer {LINE_TOKEN}"
        }
        payload = {
            "to": USER_ID,
            "messages": [{"type": "text", "text": message}]
        }
        
        # ★ココが重要! json.dumps(payload) をさらに .encode('utf-8') で変換します
        binary_data = json.dumps(payload).encode('utf-8')
        
        # data= にバイナリデータを渡す
        response = urequests.post(url, data=binary_data, headers=headers)
        print(f"LINE送信結果ステータス: {response.status_code}")
        response.close()
    except Exception as e:
        print(f"LINE送信エラー: {e}")

# メイン処理開始
print("温湿度監視システムを起動しました")
send_line("温湿度監視システムが起動しました!監視を開始します。")

# 一度LINEを送ったら、しばらく連続送信を防ぐためのフラグ
alert_sent = False

while True:
    try:
        # センサーから値を読み取る
        sensor.measure()
        temp = sensor.temperature()
        humidity = sensor.humidity()
        print(f"【現在値】 温度: {temp}°C, 湿度: {humidity}%")
        
        # 温度がしきい値を超えた場合の判定
        if temp >= ALERT_TEMP:
            if not alert_sent:
                # まだアラートを送っていない場合のみ送信
                msg = f"【警告】室温が{temp}°Cになりました!エアコンを確認してください!(湿度: {humidity}%)"
                print("警報レベル到達!LINEを送ります。")
                send_line(msg)
                alert_sent = True # フラグを立てて、連続送信を防ぐ
        else:
            if alert_sent:
                # 温度が安全圏内に戻ったらフラグをリセットし、安心通知を送る
                print("温度が安全圏に戻りました。")
                send_line(f"室温が{temp}°Cに下がりました。安全圏内です。")
                alert_sent = False
                
    except OSError as e:
        print("センサーの読み取りエラー(スキップします)")
        
    # 指定した時間だけ待つ
    time.sleep(CHECK_INTERVAL)

動作確認

起動通知がLINEに届いた画面

実行すると、まずスマホに「温湿度監視システムが起動しました!」と日本語で届きます。

室温超過の警告メッセージがLINEに届いた画面

DHT11センサーに温かい息を吹きかけて28℃を超えると、「【警告】室温が◯◯℃になりました!」というアラートが届きます。

アラート解除メッセージがLINEに届いた画面

その後27℃以下に下がると、「室温が◯◯℃に下がりました。安全圏内です。」という解除メッセージが届けば成功です。

alert_sent フラグは、28℃を超えている間ずっと10秒おきに何十通も通知が飛ぶのを防ぐためのものです。一度送ると True になり、27℃以下に戻ると解除通知を送って False に戻ります。


スポンサーリンク

PC不要で自動化:Pico Wにmain.pyを保存して独立稼働させる

ここまではThonnyの「実行」ボタンで動かしてきました。実用するにはPCを24時間つなぎっぱなしにはできないので、プログラムをPico W本体に保存して、コンセントに挿すだけで動くようにします。

Thonnyの名前を付けて保存メニュー

Thonnyのメニューから「ファイル」>「名前を付けて保存」を選びます。

保存先選択ダイアログでRaspberry Pi Picoを選ぶ

保存先に「Raspberry Pi Pico」を選びます。

ファイル名をmain.pyにして保存する画面

ファイル名を必ず main.py にして保存します。

なぜ main.py なのか:Raspberry Pi Pico系は、電源が入ると本体内の main.py を自動実行する仕様です。この名前で保存しておけば、PCなしでも起動と同時にプログラムが走ります。

保存できたらPico WからUSBケーブルを抜き、5V ACアダプター(スマホの充電器で可)につないで部屋のコンセントに挿します。PCなしで自動的にWi-Fiに接続し、LINEに起動通知が届けば完成です。


スポンサーリンク

第3回のまとめ:3つの罠を越えて温湿度アラートが完成

これで「室温が危険な値になったらスマホに通知が飛ぶ」システムが完成しました。この連載でつまずきやすかったのは、①充電専用USBケーブルでPico Wが認識されない(第1回)、②LINE側の仕様変更でWebhookをオンにできない(第2回)、③日本語メッセージがエラー400になる(第3回)、の3点です。

次は、この仕組みを発展させて「LINEから『冷房ON』と送るとエアコンが動く」スマートリモコン化に進みます。第4回で赤外線の送受信回路を作り、第5回でGASを挟んで遠隔操作を実現します。

前後の記事

📲 前の記事・第2回 LINE Messaging APIの始め方|チャネル作成とアクセストークン・ユーザーIDの取得手順 この記事で使うトークンとユーザーIDの取得手順はこちら。 → 📡 次の記事・第4回 ラズパイPico Wで赤外線リモコンを自作|受信・送信回路と38kHz PWM制御 エアコンのリモコン信号を読み取り、Pico Wから赤外線で再送信する回路を作ります。 → 🗺️ 総集編・全体像 ラズパイPico WとLINE Botで作る自作スマートリモコン|全5回ロードマップ 温湿度監視からエアコンの遠隔操作まで、シリーズ全体の完成像。 →

スポンサーリンク

よくある質問(FAQ)

QurequestsがImportErrorになります。

AurequestsはMicroPython(Pico)に組み込まれているモジュールです。標準のPython(CPython)では動きません。Thonny下部のインタプリタ表示が「MicroPython (Raspberry Pi Pico)」になっているか確認してください。

Q日本語対策を入れたのにStatus Code 400のままです。

A送信直前にjson.dumps(payload).encode('utf-8')でbytesへ変換しているか、ヘッダーのContent-Typeに; charset=UTF-8を付けているかを確認します。トークンやユーザーIDの前後に空白・改行が混ざっているケースも多いです。

QPico WがWi-Fiに接続できません。

APico Wは2.4GHz帯のWi-Fiのみ対応です。ルーターの5GHz専用SSIDを指定していると接続できないので、2.4GHz側のSSIDとパスワードを使ってください。ステルスSSIDや企業向けの認証(WPA2-Enterprise)も接続できません。

Qalert_sentフラグは何のためにありますか?

A28℃を超えている間、チェックのたびに通知が何十通も飛ぶのを防ぐためのフラグです。一度アラートを送るとTrueになり、27℃以下に戻ると解除通知を送ってFalseに戻します。

Qしきい値やチェック間隔を変えたいです。

Aコード上部のALERT_TEMP(既定28)とCHECK_INTERVAL(既定10秒)を書き換えます。テスト用に10秒にしていますが、実運用では60〜300秒くらいに延ばすとWi-Fiとセンサーの負荷が下がります。

Qmain.pyを修正・削除したくなったらどうしますか?

AThonnyで「ファイル」>「開く」>「Raspberry Pi Pico」からmain.pyを開いて編集・保存します。削除はThonnyのファイルビューで右クリックから行えます。BOOTSELでの初期化は不要です。



ニンジン🥕アイコン

Follow me on X

本ブログの中の人「ニンジン🥕」はXやってます。新着記事はいち早くポストでお知らせしているので、見逃したくない方は @ninjin_py_vba をフォローしてみてください🥕

@ninjin_py_vba をフォロー

この記事が役に立ったら、シェアしてもらえると嬉しいです🥕

Xでポスト はてブ LINE Pocket

PROJECT LOG — SERIES INDEX
スポンサーリンク

シリーズ記事一覧

電子工作・自動化ツールの製作記録をシリーズごとにまとめています。気になるテーマからお読みください。


GPSロガーのCSVを地図に表示する方法|Pico 2 WでGT-502MGG-NとATGM336Hを車に積んで走行・トンネル比較【Python・folium】
GPSロガーで記録したCSVを、Pythonのfoliumと地理院タイルで地図に表示する方法。GT-502MGG-NとATGM336Hを車に積んで4回走り、再起動の原因やトンネルでの違いも比べました。
今週の注目ガジェット〜10/19週〜|電子工作・自作向け新製品まとめ(Romu/W1700K SDR ほか)
大手が拾わないニッチな新製品を毎週チェック。今週はe-Paper開発キット、超小型USBボード、自作SDRなど5本立て。
GT-502MGG-NとATGM336Hの使い方|Raspberry Pi Pico 2 WとMicroPythonでGPSを受信して2台を比較
GT-502MGG-NとATGM336Hの使い方を、Pico 2 W×MicroPythonで解説。北斗で衛星数が多いATGM336H、信号が強いGT-502MGG-N。単精度floatで緯度経度が約1.4m刻みになる落とし穴も紹介します。
今週の注目ガジェット〜10/12週〜|電子工作・自作向け新製品まとめ(Q8botOne/Sipeed SLogic32U3 ほか)
大手が拾わないニッチな新製品を毎週チェック。今週は四足歩行ロボット、ロジックアナライザー、広告ブロッカーなど5本立て。
MOSFETはPicoの3.3Vで足りる?DCソレノイド駆動でゲート電圧不足を実測【Pico 2 W】
Pico 2 WとMOSFET(IRLU3410)で12VのDCソレノイドを駆動。ゲート3.3Vでは発振し、オン抵抗も約2.4倍に。レベル変換で5V駆動にした比較と、電流が8割止まりだった本当の原因を実測で紹介します。
まとめハブ
ハードウェア制御 / 電子工作
スポンサーリンク

コメント