0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

LINEから自宅のRaspberry Pi Pico Wを操作する:GAS中継サーバー + ポーリング構成(MicroPython)

0
Posted at

概要

スマホの LINE から、自宅の Raspberry Pi Pico W につないだエアコン(赤外線リモコン)を操作する構成の作り方です。LINE の Webhook は公開 URL を必要としますが、家庭内の Pico W は直接受けられません。そこで Google Apps Script(GAS)を「命令の一時置き場」にして、Pico W 側から定期的に取りに行くポーリング構成にしました。この記事では中核の GAS 側コードと Pico W 側の取得処理だけを抜き出します。自作の温湿度見守り装置を外出先から操作したくて作ったものです。

なぜ直接受信ではなく「GAS中継 + ポーリング」なのか

LINEからのメッセージをGASが受け取って保存し、Pico Wが定期的に取りに来る中継のしくみ図

  • LINE の Webhook 送信先は HTTPS の公開エンドポイントである必要がある。Pico W にグローバル IP やポート開放を割り当てるのは家庭では手間もセキュリティリスクも大きい
  • GAS の doPost / doGet なら無料で公開 HTTPS をもらえる。「LINE → GAS(保存)」と「Pico W → GAS(取得)」の一方向通信2つに分解できる
  • Pico W は「取りに行く」側なので、ルーターの内側にいるままでよい

中継サーバー(GAS)側: 命令を預かって渡す

ScriptProperties を簡易 KVS として使い、doPost で命令を保存、doGet で返して消費(NONE に戻す)します。

const KEY = "AIR_CON_SIGNAL";

// LINE の Webhook。メッセージ本文から命令を決めて保存するだけ
function doPost(e) {
  const event = JSON.parse(e.postData.contents).events[0];
  if (event && event.type === "message" && event.message.type === "text") {
    const text = event.message.text;
    const props = PropertiesService.getScriptProperties();
    if (text.includes("冷房")) props.setProperty(KEY, "COOL_ON");
    else if (text.includes("停止")) props.setProperty(KEY, "COOL_OFF");
  }
  return ContentService.createTextOutput(JSON.stringify({ status: "ok" }))
                       .setMimeType(ContentService.MimeType.JSON);
}

// Pico W が取りに来る。返したら NONE に戻す(命令を消費する)
function doGet() {
  const props = PropertiesService.getScriptProperties();
  const signal = props.getProperty(KEY) || "NONE";
  if (signal !== "NONE") props.setProperty(KEY, "NONE");
  return ContentService.createTextOutput(JSON.stringify({ signal: signal }))
                       .setMimeType(ContentService.MimeType.JSON);
}

デプロイ時は「アクセスできるユーザー」を 「全員」 にします(「Google アカウントを持つ全員」ではありません)。ここが「匿名」でないと、次の GET で JSON ではなくログイン画面の HTML が返ってきます。

Pico W側: GASにポーリングし、302リダイレクトを追う

urequestsリダイレクトを自動で追いませんscript.google.com/.../exec への GET は script.googleusercontent.com への 302 を返すため、Location ヘッダーを自分で取って再度 GET します。

import urequests
import json

GAS_URL = "https://script.google.com/macros/s/XXXXX/exec"

def check_gas_command():
    res = urequests.get(GAS_URL)
    # urequests は 302 を自動で追わないので手動でリダイレクト
    if res.status_code in (301, 302, 303, 307, 308):
        location = res.headers.get("location")
        res.close()
        if not location:
            return "NONE"
        res = urequests.get(location)
    text = res.text
    res.close()
    if text.startswith("<"):        # ログインHTMLが返ってきた = アクセス権の設定ミス
        return "NONE"
    return json.loads(text).get("signal", "NONE")

あとはメインループで check_gas_command() の戻り値(COOL_ON など)に応じて赤外線を送るだけです。

完全なソースコードと手順はブログにまとめています

GAS プロジェクトの作成・デプロイ手順、LINE Developers 側の Webhook URL 設定と応答設定、Pico W の main.py 全文(スタンドアロン運用で print を1つも入れない理由、gc.collect()、連続エラー時の machine.reset() による自動復帰)、動かないときの定番トラブルまで、以下の記事に書いています。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?