この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
1 はじめに
IoT事業部の平内(SIN)です。
エッジデバイスとして、RaspberryPIを使用している場合、遠隔からシャットダウンやリブートしたくなることがあると思います。
今回は、AWS IoT Greengrass V2のコンポーネントで、これを作成してみました。 操作コマンドは、MQTTメッセージとなっています。
2 操作コマンド
操作コマンドの仕様です。
(1) Topic
maintenance/コアデバイス名
例)
maintenance/gg-device-001
(2) Payload
キー | 値 | 備考 |
---|---|---|
cmd | reboot | 再起動 |
cmd | shutdown | シャットダウン |
例)
{
"cmd": "reboot"
}
次のような形でメッセージを送ることで、デバイス(gg-device-001)が、再起動されます。
3 アーティクル
コードです。
環境変数から、コアデバイス名(ホスト名ではありません)を取得し、自身に当てたメッセージをSubscribeしています。
また、cmdの種類に応じて、sudoコマンドを発行しています。
Greenglassのセットアップや、コンポーネントの作成、MQTTのSubscribeに関しては、下記の記事をご参照ください。
[AWS IoT Greengrass V2] RaspberryPIにインストールしてみました
[AWS IoT Greengrass V2] RaspberryPIでコンポーネントを作成してみました
[AWS IoT Greengrass V2] コンポーネントからIoT CoreのメッセージブローカーにPublish/Subscribeしてみました
import time
import os
import json
import subprocess
import awsiot.greengrasscoreipc
import awsiot.greengrasscoreipc.client as client
from awsiot.greengrasscoreipc.model import (
IoTCoreMessage,
QOS,
SubscribeToIoTCoreRequest
)
# MQTT送受信クラス
class Mqtt():
def __init__(self) -> None:
self.ipc_client = awsiot.greengrasscoreipc.connect()
self.timeout = 10
class StreamHandler(client.SubscribeToIoTCoreStreamHandler):
def __init__(self, on_recv):
super().__init__()
self.__on_recv = on_recv
def on_stream_event(self, event: IoTCoreMessage) -> None:
message = str(event.message.payload, "utf-8")
print("Stream.Recv payload:{}".format(message))
self.__on_recv(json.loads(message))
def on_stream_error(self, error: Exception) -> bool:
print("Stream.Error: {}".format(error))
return True
def on_stream_closed(self) -> None:
print("Stream.Close")
pass
def subscribe(self, topic, on_recv):
print("Subscribe: {}".format(topic))
qos = QOS.AT_LEAST_ONCE
request = SubscribeToIoTCoreRequest()
request.topic_name = topic
request.qos = qos
handler = self.StreamHandler(on_recv)
operation = self.ipc_client.new_subscribe_to_iot_core(handler)
future = operation.activate(request)
future.result(self.timeout)
def on_recv(message):
if("cmd" in message):
cmd = ''
if(message["cmd"] == "shutdown"):
cmd = 'sudo shutdown -h now'
elif(message["cmd"] == "reboot"):
cmd = 'sudo reboot'
if(cmd != ''):
print(cmd)
subprocess.Popen(cmd, shell=True)
# 自分のコアデバイス名だけサブスクライブする
thing_name = os.environ['AWS_IOT_THING_NAME']
topic = "maintenance/{}".format(thing_name)
mqtt = Mqtt()
mqtt.subscribe(topic, on_recv)
while True:
time.sleep(1)
4 レシピ
レシピは、以下の通りです。デフォルトのコンフィグで、IoT CoreへのSubscribeを許可しています。
---
RecipeFormatVersion: '2020-01-25'
ComponentName: com.example.Shutdown
ComponentVersion: '1.0.0'
ComponentConfiguration:
DefaultConfiguration:
accessControl:
aws.greengrass.ipc.mqttproxy:
com.example.Shutdown:mqtt:1:
operations:
- "aws.greengrass#SubscribeToIoTCore"
resources:
- "maintenance/#"
Manifests:
- Platform:
os: linux
Lifecycle:
Install: pip3 install awsiotsdk
Run: python3 -u {artifacts:path}/shutdown.py
Artifacts:
- URI: s3://gg-artifacts-2021-08-11/artifacts/com.example.Shutdown/1.0.0/shutdown.py
5 sudo
コンポーネントの中では、sudo をつけたコマンドを実行していますが、何も設定しないと、下記のエラーが発生します。
コンポーネントのログ
stderr. sudo: no tty present and no askpass program specified.
また、この時、syslogには、以下のように出力されています。
pam_unix(sudo:auth): auth could not identify password for [ggc_user]
こちらは、パスワード無しでの実行を許可する必要がります。
具体的には、sudo visudoを実行して、以下の行を追加します。
$ sudo visudo
ggc_user ALL = NOPASSWD: /usr/sbin/shutdown, /usr/sbin/reboot
※ ユーザー(ggc_user)が、reboot/shutdownをパスワードなしで実行することを許可しています。
6 最後に
今回は、MQTTメッセージで、rebootやshutdownを行うコンポーネントを作成してみました。 visudoで許可が必要な点に、ちょっ戸惑いました。
Greengrass V2 強力です。引き続き、色々試して行きたいです。
7 参考リンク
[AWS IoT Greengrass V2] RaspberryPIにインストールしてみました
[AWS IoT Greengrass V2] RaspberryPIでコンポーネントを作成してみました
[AWS IoT Greengrass V2] クラウド側から複数のコアデバイスにコンポーネントをデプロイしてみました
[AWS IoT Greengrass V2] クラウド側からコンポーネントを削除してみました
[AWS IoT Greengrass V2] ローカルデバッグコンソール(aws.greengrass.LocalDebugConsole)を使用してみました
[AWS IoT Greengrass V2] Lambda関数(コンポーネント)をデプロイしてみました
[AWS IoT Greengrass V2] コンポーネントからIoT CoreのメッセージブローカーにPublish/Subscribeしてみました
[AWS IoT Greengrass V2] コンポーネントからシークレットマネージャにアクセスしてみました
[AWS IoT Greengrass V2] コンポーネントでコアデバイス間のPublish/Subscribeを試してみました
[AWS IoT Greengrass V2] ログマネージャでコンポーネントのログをCloudWatch Logsに送ってみました
[AWS IoT Greengrass V2] トークン交換サービスでコンポーネントからDynamoDBにアクセスしてみました
[AWS IoT Greengrass V2] ストリームマネージャーを使用してコンポーネントからKinesis Data Streamsへデータを送ってみました
[AWS IoT Greengrass V2] プロセス間通信 (IPC) を使用してコンポーネントの設定値を使用してみました
[AWS IoT Greengrass V2] ストリームマネージャーを使用してWebカメラの画像を毎秒2フレームでS3に送信してみました
[AWS IoT Greenglass V2] 100円ショップの Bluetooth リモコン シャッターでパトランプ回してみました