電通総研 テックブログ

電通総研が運営する技術ブログ

スマートプラグHS105とRaspberry Pi、flutter&FastAPIで温室の環境管理をするスマートファームAppのレシピ

こんにちは。XI本部 AIトランスフォーメーションセンターの徳原光です。ISID2022年アドベントカレンダーの12月19日の記事を投稿します。

皆さん、仕事のいやしってありますか?

お仕事にはストレスはつきもの。仕事の合間にメンタルをコントロールする自分なりの方法があるって大事なことだと思うんですよね。

自分はこれです。

raspberry piで温室の温度管理

小さな温室に入った小さなジャングル。日々刻々と変化する熱帯植物の様子を眺めると、今頭の中でグルグル回っている悩みなんてどうでもいいなって気持ちになります。

温室を運用する上で一番大切なことは、当たり前ですが温度を保つことです(あと、湿度も大事)。なので、温室内の温度変化に注意しつつ、季節や天候によって設定温度を微妙に変更したくなるんですよね。

すでに、Raspberry Piに温湿度センサーDHT22を接続して温度遷移の記録を取りつつ、スマートプラグを利用して温室に設置したパネルヒーターの制御を行っていたのですが、パネルヒーターの稼働温度の変更や、温度遷移を確認するのにわざわざRsapberry Piに接続するのは面倒でした。

ということで個人で使用するために、スマホでかんたんに温度の監視やパネルヒーターの設定温度を変更するモバイルアプリを作成したので、そのレシピを紹介したいと思います。

同様のことに挑戦される方のご参考になればと思います。今回実装したコードはすべてこちらのリポジトリに上げたので活用してください。 Pickerdot/smartterrarium

作成したもの

smart-terrariumの操作画面gifアニメ

できること

  • 温室内の現在温度・湿度の取得
  • 日中と夜間のパネルヒーターの稼働温度設定
  • 4日分の温度・湿度遷移記録(15分おき)の確認

動作環境

材料

  • Raspberry Pi(4 Model Bを推奨))
  • 温湿度センサーDHT22
  • スマートプラグHS105(p105でも可)
  • パネルヒーター
  • お手持ちのスマホ(今回はAndroid機を使用)
  • FastAPI
  • Flutter

ラズパイでスマートファームapp構築

手順

  • Raspberry Piに温湿度センサーDHT22を接続
  • スマートプラグHS105をLAN内に接続
  • パネルヒーターの電源プラグをスマートプラグHS105に接続
  • 温湿度センサーとパネルヒーターを温室内に設置
  • 温度によるパネルヒーターの制御プログラムを作成
  • 温度・湿度記録用のデータベースと設定値保持用のデータベースをSQLite3で作成
  • 制御プログラムをFastAPIを利用して、Raspberry Pi上でweb API
  • Flutterで操作画面を作成し、パネルヒーター制御のためのAPIを叩く
  • Flutterで作ったアプリをAndroidにUSBデバッグでインストール

詳細

Raspberry Piに温湿度センサーを接続

一番、つまづいたポイントはここかもしれません。GPIOピンに温湿度センサーを接続します。使用したDHT22はVCC 、DAT、GNDと3つの端子が存在しますが、VCCは3.3Vピン、DATがGPIOピン、GNDはGNDピンに接続する必要があります。

おすすめは配線しやすいので、VCCは1番ピン、DATは37番ピン(GPIO26)、GNDは29番ピンに接続することです。これらはすべて端に配置されているピンなので間違えずに配線できると思います。

ピンの配置がわからなくなったら、Raspberry Piのターミナルで

$ pinout

と実行するとこのようにピンの配置が表示されます

3V3  (1) (2)  5V    
 GPIO2  (3) (4)  5V    
 GPIO3  (5) (6)  GND   
 GPIO4  (7) (8)  GPIO14
   GND  (9) (10) GPIO15
GPIO17 (11) (12) GPIO18
GPIO27 (13) (14) GND   
GPIO22 (15) (16) GPIO23
   3V3 (17) (18) GPIO24
GPIO10 (19) (20) GND   
 GPIO9 (21) (22) GPIO25
GPIO11 (23) (24) GPIO8 
   GND (25) (26) GPIO7 
 GPIO0 (27) (28) GPIO1 
 GPIO5 (29) (30) GND   
 GPIO6 (31) (32) GPIO12
GPIO13 (33) (34) GND   
GPIO19 (35) (36) GPIO16
GPIO26 (37) (38) GPIO20
   GND (39) (40) GPIO21

つまづいた理由は手元のRaspberry Pi 4がDHT22の出力を認識できなかったことでした。GPIOの設定は一通り確認したのですが認識せず、最初はDHT22の故障を疑っていたのでarduinoで動作確認したらすんなり動作しました。

しょうがないので、学生時代に買ったRaspberry Pi 3 B+を引っ張り出してきて、動作確認することになりました。今度はDHT22から温度と湿度を取得できたものの、RAMが1GBの環境は快適にプログラミングできる環境でないので、その後かなりコーディングに苦戦しました。

まずは、必要なパッケージをインストールします。

$ sudo apt-get update
$ sudo apt-get install build-essential python-dev

さらに、DHT22の出力を認識するためのライブラリをインストールします(適当なフォルダ内で実行)。

$ sudo git clone https://github.com/adafruit/Adafruit_Python_DHT.git
$ cd Adafruit_Python_DHT
$ sudo python setup.py install

DHT22読み取り用のプログラムを実装します。

import Adafruit_DHT as DHT
import RPi.GPIO as GPIO

# センサータイプの設定
SENSOR_TYPE = DHT.DHT22
# 使用するGPIOのピン番号
DHT_GPIO = 26

def read_dht():
    try:
        humidity, temperature = DHT.read_retry(
            SENSOR_TYPE, DHT_GPIO)
        message_temp = "Temp= {0:0.1f} deg C".format(temperature)
        message_humidity = "Humidity= {0:0.1f} %".format(humidity)
        message = message_temp + ". " + message_humidity
        print(message)
    except:
        # センサから温度が取得できなかった際に、Nullが返るとエラーが起こるので応急処置
        humidity = 0.0
        temperature = 0.0
    return temperature, humidity

スマートプラグをLAN内に接続

こちらは公式のアプリを操作してください HS105初期設定 p105初期設定 Raspberry Piが接続されているLANに接続できればOKです

パネルヒーターの電源プラグをスマートプラグHS105に接続

パネルヒーターの電源プラグをスマートプラグに接続してください。

Raspberry Piがあるんだったら、リレー回路を組んでRaspberry PiのIOから直接制御すればいいのでは?」と突っ込まれそうですが、リレー素子を購入したものの家庭用電源を自分が組んだ電気回路で制御するのは恐ろしくできませんでした。

スマートプラグは2000円程度で購入できるので、回路を組む手間を考えると素直にスマートプラグを使用したほうがいいと思います。

温湿度センサーとパネルヒーターを温室内に設置

お好きな様に設置してください。

温湿度センサーとRaspberry Piを配線するので、Raspberry Piを温室の近くに設置する必要があり、温室から漏れた水でRaspberry Piが故障しないか若干心配です。

どうせ近く設置するなら、Raspberry Piからの排熱も温室の加温に利用したいですね・・・。

温度によるパネルヒーターの制御プログラムを書く

今回は日中(7:00~20:00)と夜間(20:00~7:00)で設定温度を変えます。市販のサーモスタッドではなく、わざわざRaspberry Piでパネルヒーターを制御している理由はここにあります。ある程度夜間に温度を下げたいので、時間帯によってパネルヒーターの稼働温度を変えています(サーモスタッドも高いやつは時間帯によって設定温度を変えられますが・・・)。

というのも、温室だからといって24時間365日常夏にしたいわけじゃなくて、ある程度一日の寒暖差があった上で、冬は冬らしく枯れない程度に寒さを感じさせる必要があります。なので、この設定温度も寒さが厳しくなる1月や2月にはさらに下げようと考えています。冬に花が咲く品種もありますし、春に向けてちゃんと今が冬であることを理解できるように日中と夜間に温度差が生じるように設定します。

こちらはプラグの制御に用いたクラスの抜粋です。完成版は以下のレポジトリで公開しています。

import Adafruit_DHT as DHT
from tp_plug import *
import sqlite3

# 温度センサーの出力を受けてスマートプラグを制御するためのクラス
class ControlPlug:
    def __init__(self, threshold_day_temperature, threshold_night_temperature, over_temperature):
        # パネルヒーターのオンオフを管理するフラグ(0:off、1:on)
        self.heat_flag = 0
        # 日中のパネルヒーターの稼働温度
        self.threshold_day_temperature = threshold_day_temperature
        # 夜間のパネルヒーターの稼働温度
        self.threshold_night_temperature = threshold_night_temperature
        # 超過温度(一度パネルヒーターが稼働すると稼働温度+超過温度を超えるまで稼働し続ける)
        self.over_temperature = over_temperature
        # 日中、夜間の切り替え温度
        self.day_start_hour = 7
        self.day_end_hour = 20

        # 起動時に一度IOTプラグの電源を落とす
        print(TPLink_Plug("192.168.11.23").off())

# スマートプラグ(HS105)のスイッチング
    def switch_plug(self, temperature, dt_now):
        print("dt_now.hour:", dt_now.hour)
        # 夜間、ヒーターオフ時、温度低下でヒーターオン
        if (dt_now.hour < 7 or 19 < dt_now.hour) and temperature < self.threshold_night_temperature and self.heat_flag == 0:
            self.heat_flag = 1
            print("night_on")
            print(TPLink_Plug("192.168.11.23").on())
        # 昼間、ヒーターオフ時、温度低下でヒーターオン
        if (7 < dt_now.hour < 19) and temperature < self.threshold_day_temperature and self.heat_flag == 0:
            self.heat_flag = 1
            print("day_on")
            print(TPLink_Plug("192.168.11.23").on())
        # 夜間、ヒーターオン時、温度上昇でヒーターオフ
        if (dt_now.hour < 7 or 19 < dt_now.hour) and temperature > (self.threshold_night_temperature + self.over_temperature) and self.heat_flag == 1:
            self.heat_flag = 0
            print("night_off")
            print(TPLink_Plug("192.168.11.23").off())
        # 昼間、ヒーターオン時、温度上昇でヒーターオフ
        if (7 < dt_now.hour < 19) and temperature > (self.threshold_day_temperature + self.over_temperature) and self.heat_flag == 1:
            self.heat_flag = 0
            print("day_off")
            print(TPLink_Plug("192.168.11.23").off())
        return self.heat_flag

over_temperatureは温度が稼働温度を下回って、パネルヒーターがonになった後に温度が稼働温度を超えても加温し続けるための超過温度の設定値です。

あくまで稼働温度はこれ以上温度が下がると困るという値なので、パネルヒーターにより、温度が稼働温度を超えても余分に加温し続けるように設定します(パネルヒーターがoffになったあとすぐに温室内の温度が設定値を下回るのを防ぐためです)。

パネルヒーターが稼働しているかの判断はスマートプラグより情報を取得するのが難しかったので、heat_flagという変数でパネルヒーターの稼働状況を保持しています。

ということで、スイッチングのif文の条件式がやや複雑になってます。

スマートプラグの制御モジュール(tp_plug.py)は、こちらのページのコードーを使用させていただきました。 コスパ最強IoT家電!TPLink製品をRaspberryPiから操作

温度・湿度記録用のデータベースと設定値保持用のデータベースをSQLite3で作成

半分終了しました。疲れていませんか?自分は9月の中旬に材料を買ったのですが、ここまでたどり着いたときには11月になっていました。アドベントカレンダーにこのネタを投稿することが決まったので、少しペースを上げましたが、それでも今ギリギリになって記事を書いています。

このアプリの目玉機能にこれまでの温度・湿度記録を確認できるというものがあります。パネルヒーターがちゃんと動作しているのか確認するという意味合いもありますが、温室内の植物がある日突然調子を崩した際に原因を推測する手がかりになるので、個人的には必ず盛り込みたい機能でした。

今回は物理的な加湿機構を温室内に作成するのが間に合わなかったので湿度の調整はできませんが、温室内の植物は70%~に湿度を保つ必要があり、一瞬でも下回るとそれだけでダメージを負ってしまうので24時間の監視が重要になります。

データを保持するテーブルはシンプルなものにしました(カラム名命名がイケてない気がしますが気にしないことにします)。

温度・湿度記録テーブル(environmental_record)

カラム名 内容 データ型 制約
measurement_time 計測日時 TEXT PRIMARY KEY
temperature 計測温度 float NOT NULL
humidity 計測湿度 float NOT NULL
heat_flag パネルヒーター稼働フラグ int NOT NULL

設定値テーブル(parameter_set)

カラム名 内容 データ型 制約
update_at 更新日時 TEXT PRIMARY KEY
threshold_day_temperature 日中稼働温度 float NOT NULL
threshold_night_temperature 夜間稼働温度 float NOT NULL
diff_temperature 超過温度 float NOT NULL

作業的にはまず、Raspberry PiにSQLite3をインストールするところから始めます。

$ sudo apt install sqlite3 -y

次に、pipでSQLite3のモジュールをインストール。

$ pip install pysqlite3

次にタイムゾーン設定のためのモジュールをインストール。

$ pip install pytz

データベースの初期化用に以下のプログラムを作成しました。こちらのプログラムを一回実行すれば、同じ階層にSQLite3のデータベースが作成されます。

init_sql.py

import sqlite3
import datetime
import pytz

dbname = 'smart-terrarium.db'

# コネクタ作成。dbnameの名前を持つDBへ接続する。
conn = sqlite3.connect(dbname)
cur = conn.cursor()

# 温度・湿度記録用テーブルをリセットする
# cur.execute('DROP TABLE IF EXISTS environmental_record')

# テーブルの作成
cur.execute('CREATE TABLE environmental_record(measurement_time TEXT PRIMARY KEY,temperature float NOT NULL,humidity float NOT NULL,heat_flag int NOT NULL);')
cur.execute('CREATE TABLE parameter_set(update_at TEXT PRIMARY KEY,threshold_day_temperature float NOT NULL,threshold_night_temperature float NOT NULL,diff_temperature float NOT NULL)')

dt_now = datetime.datetime.now(pytz.timezone('Asia/Tokyo'))
measurement_time = dt_now.strftime('%Y-%m-%d %H:%M:%S')
parameter_data = [(measurement_time, 25.0, 22.0, 3.0)]
cur.executemany("insert into parameter_set values (?, ?, ?, ?)",
                parameter_data)


# 処理をコミット
conn.commit()
conn.close()

これで、データベースの準備が整いました。

ここから、データの読み書き用のクラスを作成します。 実装するのは設定値の読み出し、更新。温度・湿度記録の読み出し(1レコード、複数レコード)、追加のためのプログラムです。

全部ここに書くと長いので、一部抜粋して紹介します。 utility.py

# データの読み書き用のクラス
class ReadWriteDB():
    def __init__(self):
        self.dbname = 'smart-terrarium.db'

    # parameter_set読み出し
    def read_parameter_set(self):
        conn = sqlite3.connect(self.dbname)
        cur = conn.cursor()
        data = cur.execute(
            'select * from parameter_set order by update_at desc limit 1')
        latest_record = data.fetchall()
        threshold_day_temperature = latest_record[0][1]
        threshold_night_temperature = latest_record[0][2]
        over_temperature = latest_record[0][3]
        conn.commit()
        conn.close()

        return threshold_day_temperature, threshold_night_temperature, over_temperature

    # 温度・湿度記録追加
    def update_temperature_humidity(self, measurement_time, temperature, humidity, heat_flag):
        conn = sqlite3.connect(self.dbname)
        cur = conn.cursor()
        environmental_data = [
            (measurement_time, temperature, humidity, heat_flag)]
        cur.executemany(
            "insert into environmental_record values (?, ?, ?, ?)", environmental_data).fetchall()
        conn.commit()
        conn.close()

    #  1 レコード取得
    def read_one_records(self):
        # コネクタ作成
        conn = sqlite3.connect(self.dbname)
        cur = conn.cursor()
        # 値の取得
        data = cur.execute(
            'select * from environmental_record order by measurement_time desc limit  1')
        records = data.fetchall()
        print(records[0][1])
        return_value = {
            'timestamp': records[0][0],
            'temperature': records[0][1],
            'humidity': records[0][2],
            'heat_flag': records[0][3]
        }
        return return_value

制御プログラムをFastAPIを利用して、Raspberry Pi上でwebAPI化

いよいよ実装も佳境に入ってきました。

これまでに実装したPython側の制御プログラムをwebAPIとして実装するためのプログラムをFastAPIで作成します。

FastAPIはPythonでRESTful APIを構築するためのマイクロフレームワークです。

FastAPIを使用するのは今回が初めてなのですが、RAMが1GBしかないRaspberry Pi 3 B+で実装しながら動かすので、 とにかく軽いこと、そして日本語のドキュメントが存在していること、最近SNS界隈で噂になっていることがFastAPIの選定理由でした。

実際利用してみると、Raspberry Pi 3 B+でも快適に動かすことができました。これが、同時にリクエストが飛んできた場合どうなるかわかりませんが、今回はLAN内で自分しか使用しないアプリを作るので問題ないです。

これまでに同じRaspberry PiDjangoとSpringで作ったwebアプリを動かしたことがありました。普通に起動はしてくれるものの、サーバーが立ち上がっている際に、同時にエディターでコードの編集をしているともっさりしてまともにコーディングできませんでしたが、FastAPIはwebサーバーが起動していることを感じさせない使用感でした。

軽さよりも気に入ったのは、実装の簡単さですね。デシリアライズもルーティングも直感的に実装できるのが良かったです。きっと何十個もエンドポイントを用意したり、複雑なJSONをやり取りするには物足りないこともあるのかもしれませんが、日曜プログラミングにはぴったりなフレームワークだと思います。

FastAPI公式ドキュメント

まずはFastAPIと必要なモジュールをインストールします

pip install fastapi
pip install fastapi-utils

uvicorn もインストール。

pip install "uvicorn[standard]"

実装は例のリポジトリにまとめてあります。

ここからはFastAPIの気に入ったところだけまとめます。 smartterrarium.py

# FastAPI
app = FastAPI()

@app.get("/")
async def root():
    return {"message": "This is the smart terrarium"}

webサーバを立ち上げるのに必要な記述はこれだけ。あとは、

uvicorn smart-terrarium:app --reload

とコマンドを実行するだけなのがいいですね。フルスタックフレームワークでは、こうは行きませんよね。

15分おきに温度と湿度を出力する部分は以下のように実装しています。

from fastapi_utils.tasks import repeat_every

# 定期実行用の関数
@app.get("/rest/")
@app.on_event("startup")
@repeat_every(seconds=60*15)
def heater_control():
    # 温度・湿度取得
    temperature, humidity = control_plug.read_dht()

リクエストボディーのデシリアライズ

# parameter_setのリクエストボディー
class ParameterSet(BaseModel):
    day_temperature: int
    night_temperature: int
    diff_temperature: int


# 設定値テーブル更新
@app.post("/update_parameter_set/")
async def update_parameter_set(parameter_set: ParameterSet):
    dt_now = datetime.datetime.now(pytz.timezone('Asia/Tokyo'))
    measurement_time = dt_now.strftime('%Y-%m-%d %H:%M:%S.%f')
    read_write_db.update_parameter_set(
        measurement_time,
        int(parameter_set.day_temperature),
        int(parameter_set.night_temperature),
        int(parameter_set.diff_temperature))
    return {"message": "ok", "day_temperature": parameter_set.day_temperature, "night_temperature": parameter_set.night_temperature, " diff_temperature": parameter_set.diff_temperature}

ここらへんは、マイクロフレームワークとしては標準的な機能だと思いますが(他のマイクロフレームワークを触ったことがないのでわからない)、AI系のプロジェクトにはかなり相性がいいなと感じました。

機械学習モデルを実運用するとなると、だいたいPoCでモデルを作ってからあとで、webAPI化という話になりますが、あとからデータの入り口と出口としてさくっとAPIを実装できる感覚がすごく気に入りました。

あと、自動ドキュメント生成や今回は使用しませんでしたがデータベースとの接続もサポートされているのもいいですね。

自分がデータサイエンティストとして、日ごろ関わっているプロジェクトでも最近PoCを終えて実運用に入ろうとしているプロジェクトがありますが、その際に必要なのは既存のシステムに組み込まれて、モデルやデータ処理スクリプトを運用するだけのAPIなのでFastAPIで十分です。

今回は初歩的な機能しか使用しませんでしたが、もうちょっと重厚なアプリケーションを実装すればその恩恵をもっと感じられるのではないでしょうか?

Flutterで操作画面を作成し、パネルヒーター制御APIを叩く

ここまで読んでいただいた方は、すでにお腹いっぱいだと思いますが、書いてる僕はもうヘトヘトです。ただ、最後に一番重いやつが残ってるんですよね。何から説明すればいいんでしょか?

何をしたかというと、Android StudioでFlutterを使ってモバイルアプリを実装しました。画面は3つの本当にシンプルなアプリです。

モバイルアプリにした理由はRaspberry Piでフロントエンドのwebサーバーを立ち上げたくなかったからです。気軽に温室の管理ができるのが今回のアプリのコンセプトなので、スマホから使うユースケースを想定していたのですが、描画処理をRAMが1 MBのRaspberry Piで行うよりは、豊富な計算リソースを活用できるスマートフォンを利用したほうがいいと判断しました。

Flutterを使った理由はいままで使ったことがなかったからです。React Nativeは以前チュートリアルレベルのアプリを実装したことがあったのですが、Flutterは全く触ったことがありませんでした。ということで、ちょうどいいので触ってみようと思ったわけです。

Flutterのアプリのコードはこちらにあります。

現在温度表示画面 現在温度画面

シンプルな現在温度と湿度の表示画面です。

こだわったところはとにかくUIの可愛さです。自分しか使わないアプリなので自分が可愛いと感じるデザインにしました。

ここの実装は特に困った部分はなかったです。Flutterのデフォルトのプロジェクトをいじるだけで実装できると思います。

パネルヒーター稼働温度設定画面 パネルヒーター稼働温度設定画面

左右のプラス、マイナスボタンでパネルヒーターが稼働する設定温度を変更できます。

この画面が一番苦労した画面かもしれません。

プラスorマイナスボタンが押される ↓ Raspberry Pi上のAPIが叩かれて、設定温度が変更される ↓ 現在の設定温度をRaspberry Pi上のAPIから取得 ↓ 再描画

という順番で処理が進むのですが、再描画の際に現在の設定温度が取得されずにエラーを吐くという事態が頻発して、自分は全然非同期処理についてわかってないなと痛感しました。

温度遷移履歴確認画面 温度遷移履歴確認画面

これまでの温度と湿度の記録をスクロールして確認できます。

ここが一番ざんねんな画面です。本当は取得期間を設定したり、折れ線グラフを描画したりしたかったんですが、力尽きました。ここについては年末にでも時間があったら実装します。

Flutterで作ったアプリをAndroidにUSBデバッグでインストール

最後のステップです。

作ったアプリを手元のスマホにインストールします。

あくまで個人利用が目的なので、USBデバッグでインストールするという一番お手軽な方法を取りました。

やり方はかんたんで、Androidスマホを開発者モードにしてからUSBデバッグを有効にします。

そしたら、アプリを開発しているスマホに接続してAndroid Studioの実行先としてスマホを選ぶだけです。

FlutterアプリをスマホでUSBデバッグ

インストールには10分程度時間がかかりました。

最後に

今回作ったアプリですが、個人的にものすごく重宝しています。

自分が前々から欲しかったアプリを形にしたので当たり前ですが、毎日使用してますね。やっぱり気軽に触れるUIがあることはアプリケーションの利便性を格段に向上させますし、何より頻繁に使ってもらえるアプリになりますね。

ただ追加したい機能はもっとあって、まずは加湿や送風の制御がしたいです。さらに、Raspberry Piをインターネット側からアクセス可能にして、カメラで中の様子を視覚的に確認できるようにすれば、旅行先から温室の様子を確認することが可能になります。

あと個人向けには需要がないと思いますが、農業まで視野を広げれば、画像認識AIを導入して、調子を崩した株の早期発見もできると思いますし、温室から取得できるデータを活用して収穫物の品質を向上させるなどの応用ができます。

このアプリを実装していて、就活時に農業向けのITプロジェクトを実施している会社に就職したいと考えていたことを思い出しました。当時は農業案件を実施している企業が少なくて、諦めてしまいましたが、いつかISIDで農業系のプロジェクトに挑戦したいですね。

ということで、この件についてお話がある社内外の方は、ぜひ徳原にお話しください。お役に立てることがあるかもしれません。

この長々とした記事をここまで読んでくださった方、本当にありがとうございます。植物×ITのネタはまたいつか投稿したいと思うので、その際も読んでいただければと思います(AITCwebサイトではAIやデータサイエンスに関してコラムを書いています)。

また、AITCでは新卒、中途問わず一緒に働いてくださる方を絶賛募集中です。 こちらの採用情報ページからカジュアル面談の申込みを受け付けています。

それでは。

参考文献

温度/湿度センサーDHT22をRaspberry Piで使用する方法 コスパ最強IoT家電!TPLink製品をRaspberryPiから操作 FastAPI公式ドキュメント

執筆:@tokuhara.hikaru、レビュー:@yamashita.tsuyoshiShodoで執筆されました