[アップデート]AWS IoT Coreにデバイスとの接続を切断できるDeleteConnection APIが追加されました
はじめに
こんにちは、コンサルティング部の神野です。
2025年8月11日にAWS IoT Coreに新しくDeleteConnection APIが追加されました!
これにより、APIからデバイスとのMQTT接続を強制的に切断できるようになりました。
今回は、このDeleteConnection APIを実際に試してみて、どのように使うのかを詳しく見ていきたいと思います!
DeleteConnection APIとは
今回追加されたDeleteConnection APIは、AWS IoT CoreにMQTT接続しているデバイスを、クライアントIDを指定してプログラム的に切断できるAPIです。
主な機能
- クライアントIDによる接続切断: 特定のデバイスのMQTT接続を即座に切断
- Persistent Sessionのクリア: オプションで永続化されたセッション情報をクリア可能
- LWT(Last Will and Testament)メッセージの制御: 切断時のLWT(遺言)メッセージの送信を抑制可能
- Lifecycle Eventsの生成: 切断時に
API_INITIATED_DISCONNECT
というreasonでライフサイクルイベントを発行
これまでは、デバイス側に処理を実装して切断するか、タイムアウトを待つしかなかったのがクラウド側からも切断できるようになったと言った機能ですね。
APIパラメータの詳細
DeleteConnection APIには以下のパラメータがあります。
パラメータ | 必須 | デフォルト値 | 説明 |
---|---|---|---|
clientId | Yes | - | 切断するMQTTクライアントのID($で始まるIDは不可) |
cleanSession | No | FALSE | TRUEにするとセッション情報(サブスクリプションや未配信メッセージ)を削除 |
preventWillMessage | No | FALSE | TRUEにするとLWTメッセージの送信を抑制 |
前提条件
今回の検証環境は以下の通りです。
- AWS CLI: 2.24.0
- Python: 3.12.6
- リージョン: ap-northeast-1(東京)
AWS IoT Coreの基本的な設定(Thing、証明書、ポリシーの作成)は完了していることを前提とします。
プロジェクト構成
まず、今回の検証で使用したディレクトリ構成を紹介します。
発行した証明書などはcerts
フォルダに格納しておきます。
deleteconnection-api-aws/
├── scripts/
│ ├── mqtt_client_aws.py # MQTTクライアント(メイン)
│ └── delete_connection.py # DeleteConnection API実行スクリプト
├── certs/
│ ├── AmazonRootCA1.pem # ルート証明書
│ ├── device.pem.crt # デバイス証明書
│ └── device.pem.key # 秘密鍵
└── config.json # 設定ファイル
実際の環境に合わせて、エンドポイントやクライアントIDなどの設定値を変更してください!
実装してみる
それでは、実際にDeleteConnection APIを使ってみましょう!
ライブラリインストール
事前に使用するライブラリをインストールします。
pip install awsiotsdk
テスト用のMQTTクライアントを作成
まずは、接続を維持するテスト用のMQTTクライアントを作成します。
今回はAWS IoT Device SDKを使ってシンプルに実装してみました!
import time
import json
from awscrt import mqtt
from awsiot import mqtt_connection_builder
class DeviceClient:
def __init__(self):
# 設定値(実際の値に置き換えてください)
self.endpoint = "your-endpoint.iot.ap-northeast-1.amazonaws.com"
self.client_id = "test-device-001"
self.cert_path = "../certs/device.pem.crt"
self.key_path = "../certs/device.pem.key"
self.ca_path = "../certs/AmazonRootCA1.pem"
self.mqtt_connection = None
self.is_connected = False
def on_connection_interrupted(self, connection, error, **kwargs):
"""接続が中断された時のコールバック"""
print(f"\n⚠️ 接続が中断されました: {error}")
self.is_connected = False
def on_connection_closed(self, connection, **kwargs):
"""接続が閉じられた時のコールバック"""
print(f"\n🔌 接続が閉じられました")
self.is_connected = False
def connect(self):
"""AWS IoT Coreに接続"""
print(f"🔄 接続中: {self.client_id}")
# LWT(Last Will and Testament)メッセージの設定
lwt_message = {
"client_id": self.client_id,
"status": "disconnected_unexpectedly",
"timestamp": int(time.time()),
"message": "Connection lost without proper disconnect"
}
# MQTT接続を作成(LWT付き)
self.mqtt_connection = mqtt_connection_builder.mtls_from_path(
endpoint=self.endpoint,
port=8883,
cert_filepath=self.cert_path,
pri_key_filepath=self.key_path,
ca_filepath=self.ca_path,
client_id=self.client_id,
clean_session=False, # Persistent Session使用
keep_alive_secs=30,
will=mqtt.Will(
topic="device/lwt",
qos=mqtt.QoS.AT_LEAST_ONCE,
payload=json.dumps(lwt_message).encode('utf-8'),
retain=False
),
on_connection_interrupted=self.on_connection_interrupted,
on_connection_closed=self.on_connection_closed
)
print("⚰️ LWT設定済み: device/lwt トピックに異常切断時メッセージを送信")
# 接続
connected_future = self.mqtt_connection.connect()
connected_future.result()
self.is_connected = True
print(f"✅ 接続成功!")
def keep_alive(self, duration=120):
"""接続を維持(DeleteConnection APIテスト用)"""
print(f"\n⏱️ {duration}秒間接続を維持します(Ctrl+Cで停止)")
try:
for i in range(duration):
# 接続状態をチェック
if not self.is_connected:
print(f"\n❌ 接続が切断されました ({i}秒後)")
break
if i % 30 == 0:
# 30秒ごとにハートビート
heartbeat = {
"client_id": self.client_id,
"uptime": i,
"timestamp": int(time.time())
}
try:
self.mqtt_connection.publish(
topic="device/heartbeat",
payload=json.dumps(heartbeat).encode('utf-8'),
qos=mqtt.QoS.AT_MOST_ONCE
)
print(f"💓 ハートビート送信 ({i}秒経過)")
except Exception as e:
print(f"❌ ハートビート送信失敗: {e}")
break
time.sleep(1)
except KeyboardInterrupt:
print("\n🛑 停止")
if __name__ == "__main__":
client = DeviceClient()
try:
client.connect()
client.keep_alive(120) # 2分間接続維持
except Exception as e:
print(f"❌ エラー: {e}")
動作確認してみた
実際に動作を確認してみましょう!
MQTTクライアントを起動
まず、作成したMQTTクライアントを起動します。
python scripts/mqtt_client_aws.py
実行すると以下のような出力が得られます。
🔄 接続中: test-device-001
⚰️ LWT設定済み: device/lwt トピックに異常切断時メッセージを送信
✅ 接続成功!
⏱️ 120秒間接続を維持します(Ctrl+Cで停止)
💓 ハートビート送信 (0秒経過)
💓 ハートビート送信 (30秒経過)
💓 ハートビート送信 (60秒経過)
接続が成功し、30秒ごとにハートビートが送信されているのが確認できますね!
DeleteConnection APIで切断してみる
別のターミナルから、DeleteConnection APIを実行してみます。
aws iot-data delete-connection \
--client-id "test-device-001" \
--prevent-will-message \
--region ap-northeast-1
すると、MQTTクライアント側に以下のような切断メッセージが表示されました。
⚠️ 接続が中断されました: AWS_ERROR_MQTT_UNEXPECTED_HANGUP: The connection was closed unexpectedly.
❌ 接続が切断されました (4秒後)
💤 既に切断済み
おお、見事に切断されました!
DeleteConnection APIがちゃんと動作していることが確認できます。
AWS_ERROR_MQTT_UNEXPECTED_HANGUP: The connection was closed unexpectedly.
といったエラーが出るんですね。
LWT抑制の効果
今回は--prevent-will-message
フラグを使用したので、LWTメッセージは送信されませんでした。これが計画的なメンテナンスと予期しない障害を区別する重要な機能だと思います!
もしLWTメッセージを送信したい場合は、--prevent-will-message
を外すだけです。
aws iot-data delete-connection \
--client-id "test-device-001" \
--region ap-northeast-1
コンソール上からテストで確認してみるとこんな感じで抑制されず送信されているのを確認できます。
抑制されずコード上で設定したLWTメッセージが送信されていますね!
lwt_message = {
"client_id": self.client_id,
"status": "disconnected_unexpectedly",
"timestamp": int(time.time()),
"message": "Connection lost without proper disconnect"
}
どんな場面で有用か
実際にこのAPIが活躍するシーンをいくつか考えてみました。
異常動作するデバイスの強制切断
デバイスが大量のメッセージを送信し続けるような異常動作をした場合、APIを使って即座に切断できます。
メンテナンス時のデバイス移行
IoT Coreのエンドポイントを変更する際や、デバイスを別のリージョンに移行する際に、既存の接続を切断して、異なるエンドポイントへ再接続を促すことができます。
セキュリティインシデント対応
不正なアクセスが疑われるデバイスを即座に切断し、被害を最小限に抑えることができます。
おわりに
AWS IoT CoreのDeleteConnection APIを実際に使ってみて、デバイスとの接続を切断できるようになりました!
切断時のライフサイクルメッセージやcleanSession
パラメータについて、またユースケースなどの深掘りも別の記事で詳しく検証してブログで共有できたらなと思っています!
本記事が少しでも参考になりましたら幸いです!最後までご覧いただきありがとうございました!