はじめ
Nature Remoアプリを使っている方の中で、こんな悩みを抱えている人はいませんか?
「「「今から1時間後にエアコンを弱めたい……!!」」」
Nature Remoアプリのオートメーション機能でこれを実現しようとすると、毎回時刻を計算してスケジュールを登録する必要があり、非常に面倒です。オートメーション自体もどんどん増えていってしまいます。
最初はiOSショートカットアプリの「待機」アクションで解決しようとしましたが、画面をロックするとショートカットの実行が停止してしまい、動かないという問題にぶつかりました。
そこで今回は、AWS Lambda + EventBridge Schedulerを使い、時間管理をiPhone側からクラウド側に完全に移すことで、画面ロック中でも確実に「n分後にエアコン操作」を実行できる仕組みを作ったので、その内容をまとめます。
構成方針
[iOSショートカット]
→ Lambda Function URL(HTTPS)にPOSTリクエスト { "minutes": N }
→ Lambda①「schedule-aircon」
→ EventBridge Schedulerで「現在時刻+N分後」の1回限りスケジュールを作成
→ 実行後は自動削除(ActionAfterCompletion: DELETE)
→ N分後、EventBridgeがLambda②「run-aircon」を起動
→ Nature Remo Cloud APIを叩いてエアコンを操作
実装
Nature Remo Cloud APIの準備
Nature Remo公式サイトからアクセストークンを発行し、appliances一覧を取得してエアコンのappliance_idを控えます。
curl -X GET "https://api.nature.global/1/appliances" \
-H "Authorization: Bearer <アクセストークン>"
エアコン操作は以下のように呼び出せます。
curl -X POST "https://api.nature.global/1/appliances/<appliance_id>/aircon_settings" \
-H "Authorization: Bearer <アクセストークン>" \
-d "operation_mode=cool" \
-d "temperature=26" \
-d "air_direction=1" \
-d "air_volume=1" \
-d "button="
button=(空文字)を指定すると電源ONの意味になります。
Lambda②: エアコンを実際に操作する関数(run-aircon)
import os
import urllib.request
import urllib.parse
ACCESS_TOKEN = os.environ["NATURE_REMO_TOKEN"]
APPLIANCE_ID = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
def lambda_handler(event, context):
url = f"https://api.nature.global/1/appliances/{APPLIANCE_ID}/aircon_settings"
params = {
"operation_mode": "cool",
"temperature": "26",
"air_direction": "1",
"air_volume": "1",
"button": "",
}
data = urllib.parse.urlencode(params).encode()
req = urllib.request.Request(url, data=data, method="POST")
req.add_header("Authorization", f"Bearer {ACCESS_TOKEN}")
urllib.request.urlopen(req)
return {"statusCode": 200, "body": "OK"}
温度パラメータは、appliances一覧のレスポンスに含まれるrange.modes.cool.tempの候補値(文字列)と完全に一致する形式で送る必要があります。"26.0"のような表記は候補にないためHTTPError: 400 Bad Requestになる点は注意(1敗)。
Lambda①: n分後の実行をスケジュールする関数(schedule-aircon)
import boto3
import json
import time
import os
from datetime import datetime, timedelta, timezone
scheduler = boto3.client("scheduler")
TARGET_LAMBDA_ARN = "arn:aws:lambda:ap-northeast-1:xxxxxxxxxxxx:function:run-aircon"
ROLE_ARN = "arn:aws:iam::xxxxxxxxxxxx:role/scheduler-invoke-role"
SECRET = os.environ["SHORTCUT_SECRET"]
def lambda_handler(event, context):
body = json.loads(event.get("body") or "{}")
if body.get("secret") != SECRET:
return {"statusCode": 403, "body": "Forbidden"}
minutes = int(body.get("minutes", 0))
run_at = datetime.now(timezone.utc) + timedelta(minutes=minutes)
schedule_name = f"aircon-{int(time.time())}"
scheduler.create_schedule(
Name=schedule_name,
ScheduleExpression=f"at({run_at.strftime('%Y-%m-%dT%H:%M:%S')})",
ScheduleExpressionTimezone="UTC",
FlexibleTimeWindow={"Mode": "OFF"},
Target={
"Arn": TARGET_LAMBDA_ARN,
"RoleArn": ROLE_ARN,
"Input": "{}",
},
ActionAfterCompletion="DELETE",
)
return {
"statusCode": 200,
"body": json.dumps({"scheduled": schedule_name, "run_at_utc": run_at.isoformat()})
}
呼び出し元を限定するため、簡易的な合言葉(secret)をbodyに含めてチェックする形にしています。厳密にやるならAWS_IAM認証や署名付きリクエストにするのがより安全です。
IAMロールの構成
今回は3つのロールに分けています。
-
run-aircon-role: run-aircon用。AWSLambdaBasicExecutionRoleのみ -
schedule-aircon-role: schedule-aircon用。scheduler:CreateScheduleとiam:PassRoleを許可 -
scheduler-invoke-role: EventBridge Scheduler自体が引き受けるロール。信頼ポリシーでscheduler.amazonaws.comを許可し、lambda:InvokeFunctionを許可
iam:PassRoleをワイルドカードで許可すると、IAMのポリシーチェッカーから警告が出ます。今回は動作確認が取れた後に、iam:PassedToService条件キーを付けて対象をscheduler-invoke-roleのみに絞り込みました。
{
"Effect": "Allow",
"Action": "iam:PassRole",
"Resource": "arn:aws:iam::<アカウントID>:role/scheduler-invoke-role",
"Condition": {
"StringEquals": {
"iam:PassedToService": "scheduler.amazonaws.com"
}
}
}
iOSショートカットアプリの構成
schedule-airconにLambda Function URLを発行し、iOSショートカットアプリ側からPOSTでJSONを送るだけの構成にしました。実際に組んだショートカット「エアコンおやすみタイマー」の中身は以下の通りです。
1. メニューから選択
├─ 30 → テキスト「30」
├─ 60 → テキスト「60」
├─ 120 → テキスト「120」
└─ 手入力する → 入力を要求(数字)
メニューの終了
2. URLの内容を取得(POST, Lambda Function URL)
POST先はLambda Function URLで、bodyにはminutesとsecretをJSON形式で渡します。
{
"minutes": 30,
"secret": "xxxxxxxxxxxx"
}
まとめ
iOSショートカットアプリの「待機」アクションは画面ロックで停止してしまうため、時間管理が重要な処理には不向きでした。時間管理をAWS Lambda + EventBridge Schedulerというクラウド側に完全に移すことで、iPhone側の状態に左右されない、タイマーの仕組みを作ることができました。
個人利用の範囲であれば、Lambda・EventBridge Schedulerともに無料枠に収まる規模のため、追加コストはほぼかからずに運用できています。
同じようにNature Remoアプリのオートメーション機能の使いにくさに悩んでいる方の参考になれば幸いです。