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」に必要な処理を追記します。以下に倣って、ファイルを更新してください。

注釈

①「/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オブジェクトストレージへHTTP送信
  • 撮影した画像の情報をThings CloudへMQTT送信

Pythonコードは以下のとおりです。

注釈

ヘッダー部分のパラメーターは、以下のとおり設定してください。

注釈

  • 以下のコード例では、撮影時点での日時情報を基に画像保存先ファイルパス・画像ファイル名を指定しています。
    (例) 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