1.1.5.6. IoT機器設定・コード例を確認する¶
本項では、以下の実装において必要なIoT機器での設定手順の説明およびPythonコード例を記載しています。
- 実装2: IoT機器からの画像送信・Things Cloudでの画像表示
なお、本書中の設定値の「< >」の表記については、ご利用の環境により各自入力いただく箇所となります("<"から">"までを設定値に置き換えてください)。
c8yエージェントを設定する¶
本実装用に、IoT機器に導入したc8yエージェントの構成・設定ファイルを以下のとおり書き換えます。
あらかじめ、前項までに記載の処理が完了していることを確認してください。
構成ファイル「pi.properties」¶
c8yエージェントの構成ファイルである「pi.properties」を本実装用に編集します。以下の内容をファイルの末尾に追記してください。
/usr/local/sdpf-iot/pi.properties
sendinterval2 = <画像の取得・送信間隔(秒)>
Pythonコード「piAgent.py」¶
c8yエージェントの実行プログラムである「piAgent.py」に必要な処理を追記します。以下に倣って、ファイルを更新してください。
注釈
- 「TOPIC = "s/uc/img"」の「img」部分には、「1.1.5.4. Things Cloudを設定する - SmartRESTテンプレートを作成する」で作成したテンプレートIDが入ります。
- SmartRESTテンプレート作成にて異なる設定を入れた際は、記載する値にご注意ください。
①「/usr/local/sdpf-iot/piAgent.py」のヘッダーに以下の内容を追記
from sendImg_ImgInfo import sendImg_ImgInfo
②「/usr/local/sdpf-iot/piAgent.py」の「def on_message_default(client, obj, msg):」の前に以下の内容を追記
def sendImgInfo(stopEvent, interval):
c8y.logger.info("Start Thread 2...")
c8y.logger.info('Starting send_Img_ImgInfo with interval: ' + str(interval))
try:
while True:
c8y.logger.info('send_Img_ImgInfo called')
try:
sense.send()
except Exception:
c8y.logger.info('No sense hat found omitting.')
tempString = sendImg_ImgInfo()
c8y.logger.debug("Sending Image and ImageInfo: " + str(tempString))
c8y.publish("s/uc/img", tempString)
if stopEvent.wait(timeout=interval):
c8y.logger.info('send_Img_ImgInfo was stopped..')
break
except (KeyboardInterrupt, SystemExit):
c8y.logger.info('Exiting send_Img_ImgInfo...')
sys.exit()
c8y.logger.info("End Thread 2...")
③「/usr/local/sdpf-iot/piAgent.py」の「def runAgent():」内の末尾に以下の内容を追記
c8y.logger.info('Starting send Image and Image Info.')
sendThread2 = Thread(target=sendImgInfo, args=(stopEvent, int(config.get('device','sendinterval2'))))
sendThread2.start()
完成形は以下のとおりです。
/usr/local/sdpf-iot/piAgent.py
#(略)
from requests.auth import HTTPBasicAuth
from zipfile import ZipFile
from device_proxy import DeviceProxy
import concurrent.futures
##### ①追加ここから↓ #####
from sendImg_ImgInfo import sendImg_ImgInfo
##### ①追加ここまで↑ #####
def sendConfiguration():
#(略)
except (KeyboardInterrupt, SystemExit):
c8y.logger.info('Exiting sendMeasurement...')
sys.exit()
##### ②追加ここから↓ #####
def sendImgInfo(stopEvent, interval):
c8y.logger.info("Start Thread 2...")
c8y.logger.info('Starting send_Img_ImgInfo with interval: ' + str(interval))
try:
while True:
c8y.logger.info('send_Img_ImgInfo called')
try:
sense.send()
except Exception:
c8y.logger.info('No sense hat found omitting.')
tempString = sendImg_ImgInfo()
c8y.logger.debug("Sending Image and ImageInfo: " + str(tempString))
c8y.publish("s/uc/img", tempString)
if stopEvent.wait(timeout=interval):
c8y.logger.info('send_Img_ImgInfo was stopped..')
break
except (KeyboardInterrupt, SystemExit):
c8y.logger.info('Exiting send_Img_ImgInfo...')
sys.exit()
c8y.logger.info("End Thread 2...")
##### ②追加ここまで↑ #####
def on_message_default(client, obj, msg):
message = msg.payload.decode('utf-8')
c8y.logger.info("Message Received: " + msg.topic + " " + str(msg.qos) + " " + message)
#(略)
def runAgent():
#(略)
c8y.connect(on_message_default,config.get('device', 'subscribe'))
c8y.logger.info('Starting sendMeasurements.')
sendThread = Thread(target=sendMeasurements, args=(stopEvent, int(config.get('device','sendinterval'))))
sendThread.start()
##### ③追加ここから↓ #####
c8y.logger.info('Starting send Image and Image Info.')
sendThread2 = Thread(target=sendImgInfo, args=(stopEvent, int(config.get('device','sendinterval2'))))
sendThread2.start()
##### ③追加ここまで↑ #####
stopEvent = threading.Event()
#(略)
Pythonコード「sendImg_ImgInfo.py」¶
「piAgent.py」から呼び出される、以下の動作をするPythonコードを作成します。
- カメラセンサーからの画像取得
- 撮影した画像をWasabiオブジェクトストレージ(以下Wasabi)へHTTP送信
- 撮影した画像の情報をThings CloudへMQTT送信
Pythonコードは以下のとおりです。
注釈
ヘッダー部分のパラメーターは、以下のとおり設定してください。
WIDTH: 撮影画像の幅(pixel)を任意で指定します。
HEIGHT: 撮影画像の高さ(pixel)を任意で指定します。
IMAGE_PATH: 撮影画像のIoT機器内一時保管先フォルダーを指定します。
- WASABI_PATH: 画像を保存するWasabiバケット内のファイルパスを指定します。
- 「1.1.5.2. Wasabiオブジェクトストレージを設定する - バケットを作成する」にて作成したバケット内のどのファイルパスに画像を保存するかを指定します。
- 「1.1.5.3. IoT Connect Gatewayを設定する - Wasabiオブジェクトストレージへの接続設定をする - クラウドサービス接続(ストレージ)設定」内の「エントリーポイント」>「Path」にて設定したファイルパスを指定してください(先頭の"/"および末尾の"*"は不要です)。
- 下記の例のように、「iot-device/」と指定した場合、「/<Wasabiバケット名>/iot-device/」配下に画像が保存されます。
- KEYSTORE_ID: Wasabiの認証情報を保管したThings CloudのKeyStore IDを指定します。
- KeyStore IDは前の作業で作成したIDを使用します。「1.1.5.4. Things Cloudを設定する - KeyStoreへWasabiオブジェクトストレージの認証情報を格納する」をご参照ください。
注釈
- 以下のコード例では、撮影時点での日時情報を基に画像保存先ファイルパス・画像ファイル名を指定しています。(例) 2022年12月31日 12時34分56秒に画像を撮影した場合:「/<Wasabiバケット名>/<バケット内のファイルパス>/2022-12-31/20221231_123456.jpg」
/usr/local/sdpf-iot/sendImg_ImgInfo.py
import time
import datetime
import subprocess
import os
ADDR = "an1.icgw.ntt.com"
PORT = "8081"
WIDTH = "<撮影画像の幅(例:640)>"
HEIGHT = "<撮影画像の高さ(例:480)>"
IMAGE_PATH = "<撮影画像の一時保管先フォルダー(例:/tmp/)>"
WASABI_PATH = "<Wasabiのバケット内のファイルパス(例:iot-device/)>"
KEYSTORE_ID = "<Wasabi認証情報を保管したKeyStoreのID>"
def sendImg_ImgInfo():
devnull = open('/dev/null', 'w')
# 現在時刻取得
datetime_now = datetime.datetime.now()
year = datetime_now.strftime('%Y')
month = datetime_now.strftime('%m')
day = datetime_now.strftime('%d')
hour = datetime_now.strftime('%H')
minute = datetime_now.strftime('%M')
second = datetime_now.strftime('%S')
datetime_now_jst_tc = (datetime_now.utcnow() + datetime.timedelta(hours=9)).strftime('%Y-%m-%dT%H:%M:%S')
# 画像ファイル名
filename = datetime_now.strftime('%Y%m%d_%H%M%S') + ".jpg"
# Wasabiバケット内の画像保存先フォルダー
wasabi_filepath = str(WASABI_PATH) + datetime_now.strftime('%Y-%m-%d/')
# 画像をカメラモジュールから取得
## 画像の保存先パス(IMAGE_PATH/現在日時.jpg)
iot_filepath = str(IMAGE_PATH) + str(year) + str(month) + str(day) + "_" + str(hour) + str(minute) + str(second) + ".jpg"
## 画像撮影
cmd = "libcamera-jpeg --output " + str(iot_filepath) + " --nopreview --width " + str(WIDTH) + " --height " + str(HEIGHT) + " --timeout 500"
proc = subprocess.run(cmd, shell = True, stdout = devnull, stderr = devnull)
# ICGWへの画像転送
## 画像の存在確認
if os.path.exists(str(iot_filepath)):
# 画像をICGW経由でWasabiへ送信
cmd = "curl -X PUT --data-binary '@" + str(iot_filepath) +"' " + str(ADDR) + ":" + str(PORT) + "/" + str(wasabi_filepath) + str(filename) + " --header 'Content-Type: image/jpg'"
proc = subprocess.run(cmd, shell = True)
# 画像を削除
cmd = "rm " + str(iot_filepath)
proc = subprocess.run(cmd, shell = True)
# 画像情報のMQTTメッセージを生成
tempString = "987,Image(" + str(datetime_now) + "),," + str(KEYSTORE_ID) + "," + str(wasabi_filepath) + str(filename)
return tempString