3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【第2回】家でねてるRaspberry PiでIoTCoreで実装する

3
Last updated at Posted at 2026-05-18

【第2回】IoT Core の三大機能で「使えるIoT」を完成させる ― そして外部連携まで一気に俯瞰する

IoT Core の実装第2回目。第1回で「Pi 3B+ → クラウドにデータが届く」までは到達しました。本記事では IoT Core が標準で持つ Rules Engine / Device Shadow / Jobs の3機能を実装中心にコンパクトに押さえ、後半で Matter / IFTTT / Homey との連携パターンと Greengrass との使い分け を比較表で俯瞰します。これを読み終える頃には、自分で IoT システム一式を設計できる感覚が掴めるはずです。

この記事のスタンス

ハンズオンの詳細は AWS 公式ドキュメント や AWS Skill Builder に良質なものが揃っているので、本記事では 「最小実装」と「動作確認の方法」 にフォーカスします。手順を1ステップずつ丁寧に追うというより、実装パターンを俯瞰できる ことを目指します。

前提:

  • 第1回の構成(Pi 3B+ → IoT Core で MQTT Pub/Sub できている)
  • 証明書、ポリシー、bridge.py が /home/pi/ に配置済み
  • Thing名: raspi-bridge、トピック: hello/raspi

Part A:IoT Core の三大機能

image.png

1. Rules Engine ― 受信メッセージを後続サービスに流す

何をするものか

MQTT で受け取ったメッセージを SQL風の式でフィルタ・加工して、Lambda / DynamoDB / S3 / Kinesis / CloudWatch などに自動でルーティング する仕組み。「IoT Core に届いた後どうする?」の答えがこれです。

最小実装(CloudFormation で定義)

## [SPEC] iot-rule.yaml -- hello/raspi の受信を CloudWatch Logs に流す
AWSTemplateFormatVersion: '2010-09-09'
Resources:
  TelemetryToCWLogs:
    Type: AWS::IoT::TopicRule
    Properties:
      RuleName: HelloRaspiToCWLogs
      TopicRulePayload:
        RuleDisabled: false
        Sql: "SELECT *, topic() AS source_topic, timestamp() AS ts FROM 'hello/raspi'"
        AwsIotSqlVersion: '2016-03-23'
        Actions:
          - CloudwatchLogs:
              LogGroupName: !Ref TelemetryLogGroup
              RoleArn: !GetAtt IoTRuleRole.Arn

  TelemetryLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: /iot/hello-raspi
      RetentionInDays: 7

  IoTRuleRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal: { Service: iot.amazonaws.com }
            Action: sts:AssumeRole
      Policies:
        - PolicyName: WriteLogs
          PolicyDocument:
            Statement:
              - Effect: Allow
                Action: ['logs:CreateLogStream', 'logs:PutLogEvents']
                Resource: !GetAtt TelemetryLogGroup.Arn
## [SPEC] デプロイ
aws cloudformation deploy \
  --template-file iot-rule.yaml \
  --stack-name iot-rule-stack \
  --capabilities CAPABILITY_IAM

動作確認

## [NOTE] Pi 側を起動した状態で、CloudWatch Logs を覗く
aws logs tail /iot/hello-raspi --follow

10秒おきにメッセージが流れてくれば成功。Rules で流す先を変えるだけで「保存」「通知」「集計」「他AWSサービスへの連携」がすべて実現できます

ありがちな次の一手

やりたいこと Action タイプ
DynamoDB に時系列で保存 DynamoDBv2
Lambda で加工してから処理 Lambda
異常値で SNS 通知 Sns(SQL の WHERE で条件指定)
大量データを S3 にバッチ書き出し Firehose → S3
時系列DBに永続化 Timestream

2. Device Shadow ― 状態の双方向同期

何をするものか

各 Thing に紐づく JSONドキュメント で、desired(クラウドが望む状態)と reported(デバイスが現状報告)の2区画があります。MQTT が途切れている間も差分は AWS 側に保持され、再接続時に同期されます。「ON/OFF」のような状態をやりとりするときの王道 です。

詳細: AWS IoT デバイスシャドウサービス(公式ドキュメント)

Shadow ドキュメントのイメージ

{
  "state": {
    "desired":  { "led": "on" },
    "reported": { "led": "off" }
  }
}

desired.ledreported.led が違う = デルタが発生 している状態。デバイスはこのデルタを受け取って、reported を更新することで「指示を実行した」と伝えます。

最小実装(Pi 側)

## [SPEC] /home/pi/shadow.py -- Shadow の delta を受けて状態を切り替える
## [REF]  https://docs.aws.amazon.com/ja_jp/iot/latest/developerguide/iot-device-shadows.html
import json
from awscrt import mqtt
from awsiot import mqtt_connection_builder, iotshadow

THING_NAME = "raspi-bridge"

## [NOTE] MQTT接続は第1回と同じ mtls_from_path で確立済みとする
mqtt_conn = mqtt_connection_builder.mtls_from_path(
    endpoint="xxxxxxxxx-ats.iot.ap-northeast-1.amazonaws.com",
    cert_filepath="/home/pi/certs/cert.pem",
    pri_key_filepath="/home/pi/certs/priv.key",
    ca_filepath="/home/pi/certs/root-CA.pem",
    client_id=THING_NAME,
)
mqtt_conn.connect().result()

shadow_client = iotshadow.IotShadowClient(mqtt_conn)

## [SPEC] delta を受けたら reported を更新する
def on_delta(delta):
    desired_led = delta.state.get("led")
    print(f"[DELTA] LED -> {desired_led}")
    ## [TODO] 実際のGPIO制御をここに書く(本記事では割愛)

    ## [NOTE] reported を更新してクラウドに「やりました」と伝える
    update = iotshadow.UpdateShadowRequest(
        thing_name=THING_NAME,
        state=iotshadow.ShadowState(reported={"led": desired_led}),
    )
    shadow_client.publish_update_shadow(update, mqtt.QoS.AT_LEAST_ONCE)

shadow_client.subscribe_to_shadow_delta_updated_events(
    request=iotshadow.ShadowDeltaUpdatedSubscriptionRequest(thing_name=THING_NAME),
    qos=mqtt.QoS.AT_LEAST_ONCE,
    callback=on_delta,
).result()

print("[INFO] Shadow listener started")
import time
while True:
    time.sleep(60)

動作確認

AWS コンソールで AWS IoT > すべてのデバイス > モノ > raspi-bridge > デバイスシャドウ > Classic Shadow を開き、エディタで以下を保存:

{ "state": { "desired": { "led": "on" } } }

Pi のログに [DELTA] LED -> on が出て、その直後にコンソールの reportedon に更新されれば成功。「クラウドから状態指示 → デバイス受信 → 実行報告」 が双方向に回りました。


3. IoT Jobs ― リモートからの任意処理実行

何をするものか

Shadow が「状態」を扱うのに対し、Jobs は「処理」を扱います。デバイス更新、診断、リブートなど、1回完結のタスク をクラウドから配信して結果を回収する仕組み。

最小実装

1. Job ドキュメントを S3 に置く

## [SPEC] s3://my-iot-jobs/job-restart-bridge.json
{
  "operation": "restart_service",
  "service":   "raspi-bridge.service"
}

2. Job を作成

## [SPEC] raspi-bridge に Job を配信
aws iot create-job \
  --job-id restart-bridge-001 \
  --targets arn:aws:iot:ap-northeast-1:111122223333:thing/raspi-bridge \
  --document-source s3://my-iot-jobs/job-restart-bridge.json \
  --target-selection SNAPSHOT

3. Pi 側で Job を受信して実行

## [SPEC] /home/pi/jobs.py -- Job を受信して実行するエージェント(抜粋)
## [NOTE] 実コードでは IotJobsClient の subscribe / start_next / update を使う
import subprocess, json
from awsiot import iotjobs

def on_job_execution(job):
    doc = job.execution.job_document
    if doc.get("operation") == "restart_service":
        svc = doc["service"]
        subprocess.run(["sudo", "systemctl", "restart", svc])
        ## [NOTE] 実行結果を IoT Core に報告
        return iotjobs.JobExecutionState.SUCCEEDED
    return iotjobs.JobExecutionState.FAILED

## [TODO] iotjobs.IotJobsClient のサブスクライブ設定は AWS サンプル参照
##        https://github.com/aws/aws-iot-device-sdk-python-v2/tree/main/samples

動作確認

## [SPEC] Jobの状態を確認
aws iot describe-job-execution \
  --job-id restart-bridge-001 \
  --thing-name raspi-bridge
## status が SUCCEEDED になれば成功

数台規模の運用Tips: Jobs を target-selection CONTINUOUS で作成し、Thing Group をターゲットにすると、後から追加された Thing にも自動で配信されます。「数台のPiに同じ更新スクリプトを配る」運用はこれで十分まわります。


Part B:外部世界との接続を俯瞰する

ここまでで デバイス ↔ AWS は完成しました。次に AWS ↔ 外部のIoTエコシステム をどう繋ぐか疑問に思ったので 3つほど取り出して比較してみました。
と、いうのもそれぞれどう違うのか興味があったためです。
次のパターン表を見てもらうとわかりますが、それぞれのサービスは 種類が異なるのでどの層からのアプローチをしたいかなどによっても選択肢があります。

外部連携パターン表

連携先 種類 主な接続方式 IoT Core 側の入口/出口 双方向性 主な用途
Matter デバイス プロトコル標準 ローカル Matter Controller(Pi)経由 で MQTT に変換 Pi側 Device SDK / 後述のブリッジ スマートホーム機器(プラグ、電球、センサ)
IFTTT クラウドiPaaS Webhooks (HTTPS) API Gateway + Lambda 他SaaSをトリガに/結果として接続
Homey (Pro/SHS) ハブ製品 Webhook + Web API API Gateway + Lambda Zigbee/Z-Wave機器をAWSに集約

各連携の最短アーキ

Matter 連携(第3回で詳細実装)

[Matter機器] ──Matter/Wi-Fi── [Pi 3B+: Matter Controller]
                                      ↓ MQTT
                                  IoT Core
                                      ↓ Rule
                            Lambda / DynamoDB / etc.

ポイント: Matter は本質的にローカルプロトコル なので、Pi が「Matter ⇔ MQTT」の変換ハブになります。これが第3回のメインテーマ。

IFTTT 連携

受信(IFTTT → AWS):
[IFTTT Applet] ──Webhook──→ [API Gateway] → [Lambda] → IoT Core (Publish)

送信(AWS → IFTTT):
IoT Core (Rule) → [Lambda] ──Webhook──→ [IFTTT Maker URL]
                            https://maker.ifttt.com/trigger/{event}/with/key/{key}

ポイント: IFTTT は基本的に「人がトリガを書く」世界 なので、双方向にしたい場合も Webhook の URL を Lambda 側に登録するだけで済みます。

Homey 連携

受信(Homey → AWS):
[Homey Flow] ──Webhook──→ [API Gateway] → [Lambda] → IoT Core (Publish)

送信(AWS → Homey):
IoT Core (Rule) → [Lambda] ──HTTP(Bearer Token)──→ [Homey Web API]
                                                    http://<homey-ip>/api/manager/...

ポイント: Homey Pro はローカル Web API を持っているので、LAN内なら直叩きできる。クラウド経由なら webhook.homey.app を経由。


Part C:IoT Core をベースにしたいのですが IoTGreenGlass である理由を教えてください

「Greengrass って必要?IoTCoreはGreenGrassの中の一部なの?どっちがいいかおしえてほしい、これIoT使い始めてから聞かれるもので、ぱっとおなじもので後継サービスなのか?なんて誤解されます。
正直なところ

Greengrass を使う「べき」理由は意外と少ない、という正直な話

ここはちゃんと正直に答えたほうがいいテーマです。
結論から言うと、IoT Core だけで完結する構成は十分アリで、Greengrass は「特定の条件」を満たすときに初めてペイします。 名前の響きからか Greengrass の利便性を強調しすぎた感がある。 

大まかに言えば、「工場などの閉域網で使いたい」「運転のフィードバックに対して即時性処理を要求する」と言った時の選択肢として頭に入れておく。

まず、IoT Core 単体でどこまでできるか
IoT Core は MQTT ブローカーだけだと思われがちですが、実はかなり広い機能を持っています:

機能 できること Greengrass 不要?
MQTT ブローカー デバイス ↔ クラウド通信 ✅ 不要
Device Registry (Things / Groups) デバイス管理、フリート索引 ✅ 不要
X.509 証明書認証 デバイス認証 ✅ 不要
Rules Engine 受信メッセージを Lambda/DynamoDB/S3/Kinesisへ ✅ 不要
Device Shadow デバイス状態の同期(オフライン耐性あり) ✅ 不要
IoT Jobs 任意のリモート処理実行(OTA含む) ✅ 不要
Fleet Provisioning 大量デバイスの一括登録 ✅ 不要
Device Defender セキュリティ異常検知 ✅ 不要
Secure Tunneling NAT越しのSSH ✅ 不要
MQTT over WSS WebSocket経由MQTT ✅ 不要

つまり「クラウドにデータ送る・指示を受ける・OTAする・状態同期する」までは IoT Core だけで全部完結する。

Greengrass が本当に必要になる条件
Greengrass は「エッジコンピューティングランタイム」です。逆に言うと、エッジで処理する必要がない限り、選択から外すことが可能になります。

Greengrass が不要なケース(IoT Core で十分)

シナリオ IoT Core で実現する方法
単純にセンサ値を送りたい Device SDK + MQTT Publish
クラウドから ON/OFF 指示を受けたい Shadow + Device SDK
ファームウェア更新したい IoT Jobs + 自前の更新スクリプト
デバイスを大量に登録したい Fleet Provisioning
デバイスにSSH接続したい Secure Tunneling
デバイスの異常を検知したい Device Defender

「Greengrass あり」と「なし」の本当の差分

項目 IoT Core only + Greengrass
MQTT 通信 Device SDK Greengrass経由(同じ)
証明書管理 手動配置 Connection Kit で簡略化
デーモン化 自前 systemd unit greengrass-lite.target 付属
アプリ更新 IoT Jobs + 自前スクリプト コンポーネントデプロイ
複数台展開 Fleet Provisioning Thing Group へのデプロイ
オフライン耐性 自前で実装 Stream Manager で標準対応
設定ファイル更新 自前 デプロイの設定マージで対応

Greengrass が真価を発揮する条件(箇条書きだったもの)
これは元々表ではなく箇条書きでしたが、表にしておくほうがQiitaに貼ったときに見映えがすると思うので、表形式に整理し直したものも置いておきます。

機能で見る差分

機能 IoT Core 単体 + Greengrass
MQTT 送受信 ◎(同じ)
証明書認証 ◎(Connection Kit で簡略化)
クラウド連携(Rules Engine) ◎(同じ)
双方向制御(Shadow) ◎(同じ)
リモート処理(Jobs) ◎(同じ)
Fleet Provisioning
ローカル処理(ML推論など) ×
オフライン動作・データバッファ △(自前) ◎(Stream Manager)
デバイス同士のローカル通信 × ◎(IPC)
コンポーネント単位のOTA △(Jobs+自前スクリプト)
ランタイム必要RAM Python SDKで30〜50MB Nucleus Lite で5MB

ユースケースで見る使い分け

シナリオ おすすめ 理由
個人で1〜数台、テレメトリと制御だけ IoT Core単体 Rules/Shadow/Jobs で十分
業務で数台〜十数台、安定したネットワーク IoT Core単体 同上、運用工数も少ない
工場・車載でネット切断中も動作必須 + Greengrass Stream Manager のオフライン耐性
エッジでML推論・動画解析を回したい + Greengrass ローカル処理用ランタイム
数百〜数千台で頻繁にコード更新 + Greengrass コンポーネントデプロイ
親機 - 子機構成でローカル制御 + Greengrass IPC / Lambda local

目安: 「数台規模 + 安定したインターネット」なら IoT Core 単体で困りません。逆に「オフライン耐性 / エッジ処理 / 大規模フリート」のいずれかが要件に出てきたら Greengrass の出番です。本連載の想定読者(数台規模)なら、まずは IoT Core 単体を使い倒せれば十分。


まとめ:ここまでで「一通りつくれる」状態へキタ

第1回と本記事で、IoT Core を中心とした以下の能力がすべて手に入った状態になりました。

能力 使う機能 第何回で扱った
デバイスからクラウドへデータを送る MQTT + Device SDK 第1回
受信データを保存・分析・通知に流す Rules Engine 第2回
クラウドからデバイスを双方向制御する Device Shadow 第2回
デバイスのコードを遠隔で更新する Jobs 第2回
他のIoTエコシステム(Matter/IFTTT/Homey)と繋ぐ Rules + Lambda + Webhook 第2回
エッジ処理や大規模フリートにスケールする Greengrass(必要に応じて) 第2回(概要のみ)

つまり、個人〜業務で数台規模の IoT システムなら、これだけの知識で一通り設計・実装できる という状態にたどり着きました🎉

第3回は学んだことの 実践編 として、Pi 3B+ を Matter Controller 化し、市販の Matter デバイスを IoT Core に繋ぐエンドツーエンドのサンプルを作ります。Rules Engine / Shadow / Jobs / Matter連携、すべてが1つの構成に集約される回になります。
お家にいるAlexa との連携とも、あとちょっと❤️


参考リンク


この記事は IoT Core 連載シリーズ(全3回)の第2回です。次回「Pi 3B+ を Matter Controller 化して IoT Core と繋ぐ」もぜひ。

3
2
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
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?