本プロジェクトは、IoT技術を活用して快適な睡眠環境を自動的に維持するシステムの構築を目指すものである。現代社会において、質の高い睡眠は心身の健康に不可欠であるが、昨今の猛烈な暑さで睡眠の質が低下することがある。そこで、ESP8266またはESP32マイコンとSwitchbotのAPIを組み合わせ、室内の温湿度を常時モニタリングし、最適な環境を維持するシステムを開発した。
具体的には、ESP8266またはESP32を壁スイッチに組み込み、天井照明の制御を可能にした。さらに、DHT11温湿度センサーを取り付け、室内環境のリアルタイム監視を実現。これらのデータに基づき、SwitchbotのAPIを介してエアコンを自動制御する。
本システムの目的は、ユーザーが意識することなく、常に快適な睡眠環境を提供することにある。また、エネルギー効率の最適化も視野に入れ、不必要な空調稼働を抑制する。このプロジェクトを通じて、IoT技術の日常生活への実用的な応用例を示すとともに、睡眠の質の向上による健康増進を目指す。
システムの構成要素
ESP8266またはESP32
※注意※ESP8266は日本国内技適未取得なので使用を推奨しない。実際にはESP32でのみ実現しているが以下ではESP8266も含めて説明している。
選択理由
家庭内IoTで既に多数稼働中のため。もう面倒でほかのボードの使い方を学習する気にならないというだけ。
なにも未経験ならどんなマイコンを使っても学習することに変わりはないので必ずしもESPシリーズでなくとも良いかもしれない。かといって他になにがあるかも知らない。
ESP8266またはESP32の特徴と利点
ESP8266またはESP32は、Wi-Fi機能を内蔵した低コストで高性能なマイコンモジュールである。その主な特徴と利点は以下の通りである:
- 内蔵Wi-Fi:IEEE 802.11 b/g/n規格に対応し、容易にネットワーク接続が可能。
- 低消費電力:スリープモード時の消費電力が極めて低く、バッテリー駆動にも適している。
- 豊富なI/O:デジタル入出力ピンやADCを備え、多様なセンサーやアクチュエータと接続可能。
- 高い処理能力:80MHz動作のCPUを搭載し、複雑な処理も高速に実行できる。
- 充実した開発環境:Arduino IDEを使用可能で、豊富なライブラリが利用できる。
これらの特徴により、ESP8266またはESP32は家庭用IoTデバイスの開発に最適なマイコンとして広く採用されている。
Switchbotの概要と選択理由
Switchbotハブ(スマートリモコン)は、既存の家電製品をIoT化する中心的な役割を果たす機器である。その主な特徴は以下の通りである:
- 学習機能:既存のリモコンの信号を学習し、様々な家電製品を制御可能。
- Wi-Fi接続:インターネットを介して遠隔操作が可能。
- 公開API:開発者向けにAPIが提供されており、カスタムアプリケーションやシステムからの制御が可能。
この公開APIを利用することで、自作のIoTシステムからエアコンなどの家電製品を直接制御することができる。これにより、温湿度センサーのデータに基づいた自動制御など、高度なカスタマイズが実現可能となる。
DHT11温湿度センサーの特徴と選択理由
DHT11温湿度センサーは、手軽な温度と湿度の測定が可能なデジタルセンサーである。特徴として、コンパクトで低価格、動作電圧範囲が広く、Arduinoなどのマイコンと簡単に接続できる点が挙げられる。湿度測定範囲は20〜90%RH、温度測定範囲は0〜50℃で、精度も家庭用には十分だ。環境モニタリングやDIYプロジェクトに最適で、手軽にセンサーデータを扱いたい初心者にも向いている。
Blynk Legacyの概要
Blynk Legacyは当ブログの主要コンテンツの1つに成長した重要なIoTプラットフォームだ。
設定方法の詳細は以下にいくつかページを乗せておくので参照してほしい。
システムの構築
ESP8266またはESP32の壁スイッチへの取り付けとDHT11の取り付け
注意:電気工事士の免許が必要なため、詳細な説明は省略する。
一応プロの監修のもと工事した状態が以下の写真だ。垂れ下がっているのが温湿度センサー
ESP8266またはESP32ボードとDHT11センサーの取り付け方法は以下のようになる。ってぜんぜん写真じゃ参考にならんだろうな。興味があればコメントください。っていうかAIに聞けばなんでもわかるよ。
SwitchbotのAPI設定と使用方法
APIを使うにはアカウントを登録するのとともに、API使用のためのトークン(アカウント固有の識別コードみたいなもの)とデバイスID(この場合エアコンの識別コード)を取得する必要がある。
アカウント登録とトークン取得はスマホアプリで行う。デバイスIDはパソコンを使って取得する。
トークン取得のやり方はこちらのサイトを参照してもらえばわかりやすい。
デバイスID取得のやり方はこちらのサイトを参照してもらえばわかるはず。
要するにデバイス一覧の取得にはウィンドウズだったらターミナルのウィンドウで以下のコマンドを打つ。
curl -X GET -H "Authorization: トークン" https://api.switch-bot.com/v1.0/devices -o 出力ファイル.json
トークンの部分をスマホアプリで取得したトークン文字に置き換える。出力ファイル.jsonは任意のファイル名にして大丈夫だが拡張子は.jsonがよいかも。
出力されたファイルは改行のないテキストで読みにくいのでjsonファイルをきれいにするツールを使って読みやすくしよう。これはオンラインツールを利用してもよいが秘密情報をオンラインサービスにアップロードするのは怖いのでpythonプログラムを書いて自分で成形したほうが安心だ。
一応プログラム乗せておくがChatGPTに聞けばすぐ作ってくれるのでこれを参考にする必要もない。
import json
import argparse
# コマンドライン引数を設定
def parse_args():
parser = argparse.ArgumentParser(description="JSONファイルを整形して読みやすくします。")
parser.add_argument('input_file', help='整形したいJSONファイルのパス')
parser.add_argument('output_file', help='整形後のJSONを保存するファイルのパス')
return parser.parse_args()
# JSONファイルを整形して保存する関数
def format_json(input_file, output_file):
try:
# JSONファイルを読み込み
with open(input_file, 'r', encoding='utf-8') as file:
data = json.load(file)
# 読みやすい形式にフォーマット
formatted_json = json.dumps(data, indent=4, ensure_ascii=False)
# 整形されたJSONを出力先ファイルに書き込み
with open(output_file, 'w', encoding='utf-8') as file:
file.write(formatted_json)
print(f"JSONファイルが整形され、'{output_file}'に保存されました。")
except Exception as e:
print(f"エラーが発生しました: {e}")
# プログラムの実行
if __name__ == "__main__":
args = parse_args()
format_json(args.input_file, args.output_file)
これにjson2txt.pyとでも名前をつけてコマンドラインから
python json2txt.py 元のjsonファイル名 出力するテキストファイル名
という感じでコマンド打つと整形して出力してくれるはず。あとはファイルの中から目的のエアコンのデバイスIDを探して抽出する。
システム全体構成
これみてもなんのこっちゃって感じかもしれんが、実際の回路はこんなもんで肝は温湿度センサーが適切につなげてあってちゃんと検知して温度と湿度がプログラムで読めさえすればよい。
プログラムの主要部分
#if defined(ESP8266)
#include <esp8266wifi.h> // ESP8266用Wi-Fiライブラリ
#include <esp8266httpclient.h> // ESP8266用HTTPクライアントライブラリ
#elif defined(ESP32)
#include <wifi.h> // ESP32用Wi-Fiライブラリ
#include <httpclient.h> // ESP32用HTTPクライアントライブラリ
#else
#error "This code is intended to run on ESP8266 or ESP32 platforms."
#endif
// Wi-Fi情報
const char* ssid = "ssid_name"; // Wi-FiのSSID
const char* password = "passwords"; // Wi-Fiのパスワード
// SwitchBot API情報
const char* device_id = "your_device_id"; // SwitchBotのデバイスID(霧ヶ峰)
const char* token = "your_token"; // SwitchBot APIトークン
const char* switchbot_url = "https://api.switch-bot.com/v1.0/devices/";
void setup() {
Serial.begin(115200);
WiFi.begin(ssid, password);
// Wi-Fi接続を確立するまで待機
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.println("Connecting to WiFi...");
}
Serial.printf("Connected to %s\n", WiFi.SSID().c_str());
// tempera:温度 mode:1(自動)2(冷房)3(除湿)4(送風)5(暖房)
// fanSpeed:1(自動)2(弱)~4(強) OnOff:1,0
}
void loop() {
float currentTemp = 0; // 実際の温度はセンサーで取るべし
float currentHumid = 0;// 湿度も同様
checkTemperatureHumidity(currentTemp, currentHumid);
delay(60000);
}
int checkTemperatureHumidity(float currentTemp, float currentHumid) {
int retValue;
int newMode;
int newTemp;
int newBlow;
int newRun;
// 温度が閾値温度+3以上または湿度が閾値湿度2割増以上の場合、冷房を閾値温度&風量自動でオン
if (currentTemp >= AutoAirConMinTemp +3 && currentHumid >= AutoAirConMinHumi +5) {
newMode = MODE_COOL;
newTemp = AutoAirConMinTemp;
newBlow = FAN_AUTO;
newRun = POWR_ON;
}
// 温度が閾値以上または湿度が閾値以上なら弱風
else if(currentTemp >= AutoAirConMinTemp || currentHumid >= AutoAirConMinHumi){
newTemp = AutoAirConMinTemp;
newMode = MODE_COOL;
newBlow = FAN_LOW;
newRun = POWR_ON;
}
// 温度が閾値以下かつ湿度が閾値未満の場合、冷房をオフ
else if (currentTemp <= AutoAirConMinTemp && currentHumid < AutoAirConMinHumi) {
newTemp = AutoAirConMinTemp;
newMode = MODE_COOL;
newBlow = FAN_LOW;
newRun = POWR_OFF; // エアコンをオフ
}
if(AutoAirConMinTemp != preTemp || MODE_COOL != preMode || FAN_AUTO != preBlow || preRun != POWR_ON){
retValue = AirCondition(newTemp, newMode, newBlow, newRun);
preTemp = newTemp;
preMode = newMode;
preBlow = newBlow;
preRun = newRun;
}else{
retValue = -2;
}
return retValue;
}
// tempera:温度 mode:1(自動)2(冷房)3(除湿)4(送風)5(暖房) fanSpeed:1(自動)2(弱)~4(強) OnOff:1,0
// 戻り値 1:Wi-Fi接続エラー 2:clientエラー 0:正常
int AirCondition(int tempera, int mode, int fanSpeed, int OnOff){
int retValue;
if (WiFi.status() == WL_CONNECTED) { // Wi-Fi接続が有効な場合のみ処理実行
HTTPClient http;
// URLの組み立て
String url = String(switchbot_url) + device_id + "/commands";
// HTTPリクエストの初期化
#if defined(ESP8266)
WiFiClientSecure client;
client.setInsecure(); // 証明書の検証をスキップ
http.begin(client, url);
#else
WiFiClientSecure client;
client.setInsecure(); // 証明書の検証をスキップ
http.begin(client, url);
#endif
// ヘッダーを設定
http.addHeader("Authorization", String("Bearer ") + token);
http.addHeader("Content-Type", "application/json");
// JSONペイロードの作成
// commandType=command
// Command=setAll
// command parameter={temperature(1~30)},{mode(1/2/3/4/5)},{fan speed(1/2/3/4)},{power state(on/off)}e.g. 26,1,3,on
// modesについて 1 (auto), 2 (cool), 3 (dry), 4 (fan), 5 (heat);
// fan speedについて 1 (auto), 2 (low), 3 (medium), 4 (high);
// power stateにいついて on or off
// ↓生成されるコマンドパターン
// curl -X POST https://api.switch-bot.com/v1.0/devices/デバイスid/commands -H
// "Authorization:トークン" -H "Content-Type:application/json"
// -d "{""command"":""setAll"",""parameter"":""29,2,1,on"",""commandType"":""command""}"
// OnOffを文字列に変換 (0: off, 1: on)
String OnOffStr = OnOff == 1 ? "on" : "off";
// JSONペイロードの作成 (引数を使って動的に生成)
String jsonPayload = "{\"command\":\"setAll\",\"parameter\":\"" +
String(tempera) + "," +
String(mode) + "," +
String(fanSpeed) + "," +
OnOffStr + "\",\"commandType\":\"command\"}";
// POSTリクエストを送信し、応答コードを取得
int httpResponseCode = http.POST(jsonPayload);
// 応答の確認
if (httpResponseCode > 0) {
String response = http.getString(); // 応答の本文を取得
Serial.println(httpResponseCode); // HTTP応答コードを出力
Serial.println(response); // 応答内容を出力
retValue = 0;
// 設定条件をレスポンス
String st = String(getModStrings(mode)) + "," + String(tempera) + "," ;
st += String(getFanSpeedString(fanSpeed)) + "," + OnOffStr;
Blynk.setProperty(VPIN_aCOND, "offLabel", st);
delay(1);
// 設定時刻をレスポンス
char timeString[10];
int time_h,time_m,time_s;
DisplayTime(timeString, &time_h, &time_m, &time_s);
Blynk.setProperty(VPIN_acTime, "offLabel", timeString);
delay(1);
} else {
Serial.println("Error on sending POST");
retValue = 2;
}
http.end(); // HTTP接続を終了
}else{
retValue = 1;
}
return retValue;
}
実際の使用結果と改善点
テストは上手くいった。会社にいながら自宅のエアコンを操作できた。SwitchBotアプリからでもできるが、SwitchBotも自動機能をつけようと思ったらスマート温度計への課金に応じなければならない。
といっても数千円程度なので手間を考えたら高くはない。
使用感についてはさらに四季を経過したら追記したい。
省エネへの配慮
– やたらとエアコンのオン/オフを繰り返さない工夫
これは難しいのでプログラムのステップ数が徒に増えてしまいそうであるが、温度と湿度の条件がなんだったらエアコンをどうするというのを当面は実測値を見ながらトライアンドエラーして決めるしかない。
将来の拡張計画
– 無料のAI APIを活用した最適エアコン設定の自動化
ChatGPTに相談したらAIのAPIが複数サービスとして一般に公開されていて、温度と湿度の情報を与えたら外気温の情報も加味したりして最適なエアコン設定を提案してくれそうな気配はする。
ただしこれを使えるようになるまでにまだ遠い道のり、つまりアカウント登録から始まり、APIの使い方をマスターしたり、無課金のサービスを探したりといろいろある。
そのうち暇ができたらやってみよう。
プロジェクトの費用
新規にかかった費用はDHT11センサー:約200円というだけで、その他は既存設備を活用したのでほぼ金はかかっていない。
何もない状態からこれを実現しようと思ったらエアコン本体及びエアコン取り付け費用も含めると膨大な時間と金がかかることをここに言っておこう。
それでもざっくり、かなりざっくりだがあげてみると、
エアコン | 5万円 |
エアコン取り付け費用 | 1.5万円 |
SwitchBotハブミニ | 5000~1万円 |
ESP32またはESP8266ボード | 1000~1500円 |
ブレッドボード | 300円 |
ジャンパーワイヤー | 300円 |
USB電源&USBケーブル | 500円 |
壁スイッチ割り込み部品 | 1000円 |
リレー | 1000円 |
最後の壁スイッチ割り込み部品とリレーは今回のエアコン自動操作とは無関係なので無視してよい。それ以外は当プロジェクトを実現しようとしたときに概ね必要な費用だ。
使用したツールとソフトウェア
Blynk(Legacy)
Blynk: a low-code IoT software platform for businesses and developers ←Legacyではない現行Blynkへのリンク
Blynkではなく別のIoTサービスでもできるがどれも無償利用できる条件があり1個や2個のデバイスだけ動かすのなら無料でできる。
【関連】
https://androgundan.blue/handmade-smart-plug-5074.html
Arduino IDE 無料で利用できる開発環境(寄付も可能)
ESP8266またはESP32マイコンボード
ESP8266のほうが平均して少し安いんだが、技適非対応という点と利用できるGPIOの数の多さから見て、少々払ってもESP32のほうが有利であるといいたい。
ESP8266 DEVKIT V3 開発ボード + CH340 USBチップ + 4M Flash デュアルコアCPU NodeMCU (ESP8266開発ボード)
¥698(2024/08/21 14:42時点の価格)
平均評価点:
>>楽天市場で探す
>>Yahoo!ショッピングで探す
Generic ESP32 DEVKIT V1 開発ボード 4M Flash デュアルコアCPU ESP-WROOM-32 NodeMCU (開発ボード)
¥750(2024/08/21 14:41時点の価格)
平均評価点:
>>楽天市場で探す
>>Yahoo!ショッピングで探す
Switchbot API
SwitchbotのAPI設定と使用方法という項で説明している。
Switchbotハブミニ
これは最低必要になる。
SwitchBot スマートリモコン ハブミニ(Matter対応) Alexa – スイッチボット 簡単セットアップに対応 Hub Mini マター対応 スマートホーム 学習リモコン 赤外線家電を管理 節電·省エネ Echo Google Home Siri IFTTT SmartThings対応
¥5,980(2024/08/21 14:49時点の価格)
平均評価点:
>>楽天市場で探す
>>Yahoo!ショッピングで探す
ちょっとここまでヘヴィな開発は自分には無理かもってときには↓こんなSwitchbot温湿度計を買ってしまえばまるまる実現できるらしい。記事執筆時点で価格をみたらたまたまAmazonタイムセールでハブと温湿度計セットが7000円弱とはびっくりするほど安い。
SwitchBot ハブミニ 温湿度計 2個セット スイッチボット スマートホーム 学習リモコン スマートリモコン 赤外線家電を管理 家電を遠隔操作 家電自動化 スマホで温度湿度管理 Alexa Google Home Siriに対応 (ハブミニ 1点+温湿度計 1点)
¥6,660(2024/08/21 14:50時点の価格)
平均評価点:
>>楽天市場で探す
>>Yahoo!ショッピングで探す
プロジェクトに挑戦する読者へのアドバイス
本ブログの熟読
本ブログのメインコンテンツの一つになっているスマートホームに関する記述をいろいろと読み漁ってみてほしい。
体系的に書いているわけでもないんだが、自分が実現したいことをどう実現したかについて詳細に書いているつもりなので多少は参考になるのではないか。
不明点はAIに質問することを推奨
そして最近はもっぱらChatGPTに相談しながらコードを書いている。
一発で完璧なプログラムを書いてくれるわけでもないが、少なくともコンパイルエラーにはならないコードを吐き出してくれる。
おかしいところが出るとしたらロジックエラーというよりライブラリのインストールが不足していただとか泡沫的なトラブルにすぎない。実に助かる。もっと早く出てきてほしかった。
だからこのブログを隅々まで熟読しなくともAIと相談しながら進めるだけでほとんどOKともいえる。
トラブルシューティング
AIの活用による問題解決の効率化が図れるので今IT業界で働いている人は楽じゃないのかなあって思ってしまう。
開発効率が飛躍的に向上しているはずだ。
道半ばでこの記事を書いているわけだが、ESP32でのテストでは成功している。
ただ実機環境での運用にはまだ現時点で至っていない。なぜなら実機はESP8266で、ESP32からのcurlは成功しているが現在稼働中のESP8266に更新プログラムをアップロードしてみたが上手くいっていない。
ESP8266で単発機能だけテストしたいが今手元にテストで使える個体がなくてやっていない。
まとめ
ということで上手くいくのはほぼ間違いない。今後の進め方は
- 実機をESP32に置き換えてプログラムをコンバージョンする
という選択肢が残っているので済ませたら速やかに追記しますよ。
追記
実際に現地で動くようになるまでにはかなり時間を要したんだがなんとか実用に耐えうるレベルになったので画面スクショを公開しておく。
画面のそれぞれのウィジェットについて簡単な説明を以下に残すが常に変化しているので永久ではないしこれで完全でもない。
部屋の温度と湿度のグラフ | |||
部屋の温度 | センサー正常可否 | 部屋の湿度 | Switchbotからの戻り値 |
温度補正 | 湿度補正 | ||
2個目4口プラグ電源 | 2口プラグ電源 | 予備 | デスクライト |
PC左側ディスプレイスイッチ | PC右側ディスプレイスイッチ | 2口プラグ生存時刻 | 1個目4口プラグ生存時刻 |
スキャナー電源 | ベッドライト電源 | 防湿庫電源 | スポットライト電源 |
エアコン自動SW | 和室天井照明 | 和室照明生存時刻 | 2個目4口プラグ生存時刻 |
エアコン制御パラメータ | エアコン指令時刻 | ||
エアコン指令待機カウンター | 自動操作ディレイ 現在設定時間 | 左記を5秒タイマーのカウンター値に換算 | 忘れた |
エアコン自動操作開始時刻 | エアコン自動操作終了時刻 | ||
エアコン自動操作間隔(時間) | |||
エアコン自動操作最低室温 | エアコン自動操作最低湿度 |
上記までは稼働するようになっているがまだ課題は山積だ。
例えば自動操作開始時刻になったときに自動操作間隔タイマーの値に関わらずすぐ動き出すべきだができていない。
あと、自動操作終了時刻になったらエアコンを即止めるべきか、稼働していたらそのままの状態を維持させるべきか。もっともこれは決め打ちしないでウィジェットを増やしてスイッチでダイナミックに決められるようにすれば解決なんだが。
あとはそもそも閾値の温度と湿度を超えているときにどれくらい不快だったらどれくらいエアコン強度を調節するかっていうのはパターンが無限に考えられるから適当に数パターンに絞って制御パラメータを生成するしかない。今のところ。
といったかんじでもう少し改善の余地はあるが一応の完成を見て嬉しく思う。