概要
Raspberry Pi Pico W から LINE Messaging API のプッシュ送信(/v2/bot/message/push)を MicroPython の urequests で叩くとき、メッセージを日本語にすると Status Code: 400(Bad Request)で弾かれることがあります。原因と、.encode('utf-8') を使った対策コードをまとめます。Pico W で温湿度を LINE 通知する装置を作る途中で踏んだ罠です。
つまずいたポイント
半角英数字のメッセージ(Hello from Pico W! Test OK.)では Status Code: 200 で普通に届くのに、text を「テスト成功」などの全角に変えた瞬間に 400 が返る、という症状でした。
原因は文字コードです。次のように data= に str をそのまま渡す と、日本語部分の実バイト数とリクエストボディの長さが食い違い、LINE 側に壊れた JSON と判定されます。
# NG: 日本語を含むと 400 になる
response = urequests.post(url, data=json.dumps(payload), headers=headers)
CPython の requests は内部で符号化してくれますが、urequests はそこまで面倒を見てくれません。
対策: ボディを bytes にしてから渡す
送信直前に json.dumps(payload).encode('utf-8') で bytes に変換し、ヘッダーの Content-Type にも charset=UTF-8 を明示します。
def send_line(message, token, user_id):
url = "https://api.line.me/v2/bot/message/push"
headers = {
"Content-Type": "application/json; charset=UTF-8",
"Authorization": "Bearer " + token,
}
payload = {
"to": user_id,
"messages": [{"type": "text", "text": message}],
}
# str のまま渡すと日本語で 400。bytes に変換してから data= に渡す
body = json.dumps(payload).encode("utf-8")
res = urequests.post(url, data=body, headers=headers)
print("status:", res.status_code)
res.close()
これで send_line("室温が28°Cを超えました", token, user_id) のような日本語メッセージも 200 で届きます。
400 以外のステータスの切り分け
- 401 Unauthorized: チャネルアクセストークンが途中で切れている、または前後に余計な空白・改行が入っている
-
200 なのに届かない:
USER_IDが別人の ID、または LINE Official Account 側の Webhook 設定 -
[Errno 104] ECONNRESETなど: Wi-Fi が不安定か TLS 処理で弾かれている。Pico W を再起動して再実行
完全なソースコードと手順はブログにまとめています
Wi-Fi 接続テスト → 英語で送信テスト → 日本語対応の本番コード、という3段階の全コード、LINE Messaging API のトークン・ユーザーID の取得手順、Pico 本体に main.py を保存して PC なしで自動稼働させる方法まで、以下の記事に書いています。
