microCMS

ブラウザから家電を操作しよう (microCMS × Nature Remo)

この記事は公開後、1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに


皆さんは Nature Remo というデバイスをご存知でしょうか?
これは赤外線方式のリモコンを備えた家電をスマートフォンのアプリやスマートスピーカーから操作することができるようになる製品です。

この Nature Remo は Web API を公開しています。
つまり Nature Remo を使用すると curl コマンドや任意のプログラミング言語で家電を操作できるということです。

この Web API を活用してブラウザから家電を操作できるようにすると PC の前から離れずに生活することができて便利そうなので、実際にそんな仕組みを作ってみました。
私はあまり UI を作るのが得意ではないので UI は自作せず microCMS の管理画面を UI として使うことにしました。

microCMS は本来外部の Web API と直接やりとりするような仕組みを備えていませんが、コンテンツの更新をトリガーとした Webhook 機能を持っています。
Web API を叩くコードを実装して Webhook サーバを用意すると、間接的に任意の Web API を microCMS から操作できることになります。
今回はこのサーバを Go 言語で実装し、 AWS AppRunnner 上で動作させることにしました。

簡易的なものですが、構成図としては以下のようになります。



実際に動作させた様子が以下の動画になります。
ブラウザを操作して部屋の照明をON/OFFしています。



ここからは実際にどんな作業をすればこの仕組みを構築できるか解説していきます。

構築

AWS AppRunner にサーバ(仮実装)をデプロイ


AWS AppRunner は AWS 上でコンテナを実行、 HTTP リクエストを受け付けるための最も簡単な手段だと思います。
今回はこれを使用します。
まずは Webhook を受け付けてそのままログ取得するようなコードをデプロイしてみましょう。

Dockerfile を以下のように記述します。

FROM golang
WORKDIR /app
EXPOSE 8888

ADD go.mod go.sum ./
RUN go mod download

ADD . ./
RUN go build -o main

ENTRYPOINT [ "/app/main" ]


main.go を以下のように記述します。

package main

import (
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
)

func main() {
    log.Println("Start")

    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        reqBody, _ := ioutil.ReadAll(r.Body)
        println(string(reqBody))

        fmt.Fprintf(w, "OK")
    })

    log.Fatal(http.ListenAndServe(":8888", nil))
}


AWS Copilot CLI を使うことによって以下のようなコマンドでこのコンテナを AppRunner にデプロイすることができます。
--app, --name はお好みの名前に変更してください。

$ copilot init --app go-docker --name go-docker --type "Request-Driven Web Service" --deploy --dockerfile ./Dockerfile


デプロイが成功するとターミナルに以下のようなログが表示されます。

Recommended follow-up action:
  - You can access your service at https://xxxx.ap-northeast-1.awsapprunner.com over the internet.


この URL を後ほど microCMS の Webhook URL として登録することになります。

microCMS で API 作成


家電操作の UI として microCMS を利用する際の最適な API スキーマは家電によって異なると思います。
私の家のリビングには照明とエアコンが1つずつあり、それぞれ Nature Remo がセットアップ済みです。
照明は単純に ON/OFF ができれば十分で、エアコンは ON/OFF、モード(冷房or暖房)、風向き、風の強さ、温度を制御したいと思ったため、以下のように API スキーマを定義しました。



家電ごとに行える操作は異なりますが、 Nature が公開している OpenAPI スキーマ を読むとどんな操作が可能なのか分かります。
特に以下の API が今回注目するべきものです。

POST /1/appliances/{appliance}/light
POST /1/appliances/{appliance}/aircon_setting
POST /1/appliances/{appliance}/tv

microCMS で Webhook 設定


以下のように Webhook の設定を行うことによって microCMS と AppRunner の繋ぎこみを行います。
今回のユースケースでは通知タイミングは「コンテンツ編集画面による操作」だけチェックされていれば十分です。



シークレットの設定も行い、後ほどシークレットの検証コードも書くことをおすすめします。
もしシークレットを検証せず誰でも AppRunner の Webhook を叩けるようになってしまった場合、悪意を持った人が真夏に30度の暖房を設定しようとするかもしれません。

Nature Remo のアクセストークンを取得


home.nature.global からアクセストークンを取得可能です。

アクセストークンを取得したら AppRunner にそれを環境変数として設定する必要があります。
これは AWS のコンソール画面から簡単に設定することができます。

Nature Remo の OpenAPI から SDK を生成


ここまでで各種設定作業は一通り完了しました。

Nature Remo の API を叩くためには何かしらのクライアントライブラリがあると便利です。
今回は OpenAPI からコード生成をすることにしました。
以下のようなコマンドでコード生成をすることによって API 仕様とコードを見比べながらクライアントコードを実装する手間が省けます。

$ curl -sSLO https://swagger.nature.global/swagger.yml
$ openapi-generator generate -i swagger.yml -g go -o openapi/nature/ --additional-properties=enumClassPrefix=true


サーバのロジックを実装


あとは microCMS から送られた Webhook を受け取って、 Nature Remo の API を叩くコードを書くだけです。

今回定義したスキーマの API から送られる Webhook イベントをパースできる Go の struct は以下のようになります。
このような struct は手書きせず Quicktype などを使って実際の JSON から生成すると簡単に作れます。

type WebhookEvent struct {
	API      string   `json:"api,omitempty"`
	Contents Contents `json:"contents,omitempty"`
}

type Contents struct {
	New New `json:"new,omitempty"`
}

type New struct {
	PublishValue PublishValue `json:"publishValue,omitempty"`
}

type PublishValue struct {
	LightOn     bool     `json:"lightOn,omitempty"`
	AirconOn    bool     `json:"airconOn,omitempty"`
	AirMode     []string `json:"airMode,omitempty"`
	AirDir      []string `json:"airDir,omitempty"`
	AirVol      []string `json:"airVol,omitempty"`
	Temp        float64  `json:"temp,omitempty"`
}


AirMode などは管理画面上では日本語で表示すると分かりやすいですが、 Nature Remo の API を叩く時は warm または cold という値でやりとり必要があります。
この変換を行うヘルパーメソッドもついでに定義すると便利です。

func (value PublishValue) AirModeValue() string {
    switch v := value.AirMode[0]; v {
    case "暖房":
        return "warm"
    case "冷房":
        return "cool"
    default:
        return v
    }
}

func (value PublishValue) AirDirValue() string {
    switch v := value.AirDir[0]; v {
    case "自動":
        return "auto"
    case "スイング":
        return "swing"
    default:
        return v
    }
}

func (value PublishValue) AirVolValue() string {
    switch v := value.AirVol[0]; v {
    case "自動":
        return "auto"
    default:
        return v
    }
}


この struct を使って Webhook イベントを以下のようにパースできます。

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    // ...
    event := &WebhookEvent{}
    _ := json.Unmarshal(r.Body, &event)
    // ...
})


この event オブジェクトを元に実際に家電の操作を行う API を叩きます。

照明を操作する場合は以下のようになります。

appliances, _, _ := api.Call1AppliancesGet(ctx).Execute()

var light string
for _, a := range appliances { // 家電の一覧でループ
    if *a.Nickname == "リビングの照明" { // 名前で家電を特定する
        light = *a.Id
    }
}

if value.LightOn == true {
    // 照明を ON にする
    api.Call1AppliancesApplianceLightPost(ctx, light).Button("on").Execute()
} else {
    // 照明を OFF にする
    api.Call1AppliancesApplianceLightPost(ctx, light).Button("off").Execute()
}


エアコンを操作する場合はもう少し複雑になります。

appliances, _, _ := api.Call1AppliancesGet(ctx).Execute()

var aricon string
for _, a := range appliances { // 家電の一覧でループ
    if *a.Nickname == "リビングのエアコン" { // 名前で家電を特定する
        aricon = *a.Id
    }
}

if value.AirconOn == true {
    api.
        Call1AppliancesApplianceAirconSettingsPost(ctx, aircon).
        OperationMode(value.AirModeValue()).  // 暖房 or 冷房
        AirDirection(value.AirDirValue()). // 風向き
        AirVolume(value.AirVolValue()).  // 風量
        Temperature(fmt.Sprint(value.Temp)).  // 温度
        Execute()
} else {
    api.
        Call1AppliancesApplianceAirconSettingsPost(ctx, aircon).
        Button("power-off").
        Execute()
}


終わりに

以上の作業でブラウザから管理画面を操作できるようになりました。お疲れ様でした!

今回のような microCMS の利用方法はマイナーですが、実用的でもあります。
ぜひ皆さんも microCMS の面白い利用方法を思いついたらツイートしたり、ブログに書いたりしていただけると嬉しいです。

まずは、無料で試してみましょう。

APIベースの日本製ヘッドレスCMS「microCMS」を使えば、 ものの数分でAPIの作成ができます。

microCMSを無料で始める

microCMSについてお問い合わせ

初期費用無料・14日間の無料トライアル付き。ご不明な点はお気軽にお問い合わせください。

お問い合わせ

microCMS公式アカウント

microCMSは各公式アカウントで最新情報をお届けしています。
フォローよろしくお願いします。

  • X
  • Discord
  • github

ABOUT ME

λ沢
新卒で入った会社では Go を用いた API サーバの開発、Vue.js を用いた管理画面の開発、Arch Linux 上の Jenkins 運用などを担当。 次の会社では Express + TypeScript を用いたサーバレスなシステム開発、Rails/Laravel/AWS CDK などを用いた複数プロジェクトの立ち上げを担当。現在は microCMS でサーバサイドの開発、インフラ運用を担当。