ここ最近、HGユニコーンガンダムのUV LED台座制作が完全にストップしている。
理由は明確。蛍光塗料を塗っただけのパチ組みで終わらせるつもりが、眺めているうちに「なんだか味気ないな……」と感じてしまい、衝動的にアニメ塗りを始めてしまったのだ。
寄り道のつもりが大仕事になってしまったが、現在ようやく8割完成といったところ。ようやく終わりが見えてきた。(マクドナルドのガンダムコラボで、チキンタツタ専用ガンダムも作ったような気がするが…)


ガンプラの制作に熱中しているうちにも季節は進み、最近はすっかり暑くなって気温も上昇してきた。
となると気になってくるのが、熱帯魚水槽の水温管理だ。
「水温が上がりすぎるのを自動で防ぎたい!」という日常の課題を解決するため、今回はAIの知恵を借りながら、ESP32-C3マイコンを使った「自動水温監視・冷却ファンシステム」を自作することにした。
回路の設計からプログラムの構築、さらには3Dプリンタによる専用ケースの製作まで、一連の開発プロセスを経て無事に本番稼働を迎えたので、その全貌を記録としてお届けする。
今回作ったシステムの概要
目指したのは、「水温を常に監視し、設定温度以上になったら自動でファンを回して冷却。冷えたら自動で止まる」という賢いシステムだ。
- 頭脳(マイコン):コンパクトでWi-Fiも使える「ESP32-C3」
- 温度センサー:防水仕様の「DS18B20」
- 冷却機能:小型で取り回しの良い「40mm DCファン(12V / 0.08A)」
- 電源:手軽なUSB 5V電源から、昇圧モジュールを使って12Vを生成
- ブラウザ監視:Wi-Fi経由で、スマホやPCのブラウザからいつでも水温とファンの状態をリアルタイム確認可能
使用した主要パーツ(ガジェット紹介)
今回のシステムを構成するパーツたちだ。電子工作の定番かつ、手に入りやすいものばかりで構成している。なお、私は電子工作にあまり詳しくないので、AIに言われるがまま材料を集めている。
- ESP32-C3 開発ボード 安価で非常にパワフルなマイコン。Wi-Fi機能が標準搭載されているのが最大の強み。とにかく小さい!
- DS18B20 防水型温度センサー 水槽などに直接ドボンと入れられる金属保護タイプ。1-Wire通信という方式で、正確な温度をマイコンに伝えてくれるらしい。
- N-ch MOSFET(2SK4017) ESP32-C3の3.3Vという低い信号電圧でも、12Vのファンを確実にON/OFFスイッチングできる優秀な素子らしい。
- 5V➔12V 昇圧モジュール USBの5V電源を、ファンに必要な12Vへ引き上げるための心臓部。
- 40mm DCファン(12V / 0.08A) 小型ながらもしっかりピンポイントで風を当てて冷やしてくれる、今回の冷却の主役だ。作動音もサイズも小さくて良い!

以下がAIが出してきた回路図だ。よくわからん私はこの回路図を見つつ不明な部分はAIに聞きながらブレッドボード上に仮組みを行った。(綺麗な回路図を画像生成してくれと何度か頼み込んだが、無理だと突っぱねられた。)


こだわりの「ヒステリシス制御」とWebブラウザ監視
プログラムの構築にあたり、AIと相談して2つの重要な機能を盛り込んだ。
① チャタリングを防ぐ温度制御
単純に「27度でON/OFF」にすると、27.0度付近でファンが数秒ごとに回ったり止まったりを繰り返してしまいます。これではファンや回路に負担がかかります。 そこで、「27.0℃以上でファンON、26.5℃までしっかり冷えたらファンOFF」という0.5℃の「幅(ヒステリシス)」を持たせろ!とAIが言ってた。温度制御でよくあるパターンだな。
② スマホからいつでも見える安心感
ESP32-C3をWebサーバーとして動作させ、ローカルネットワーク内のブラウザからアクセスすると、現在の水温とファンのステータスが3秒ごとに自動更新されるモニターページを作成した。 これで、本体をケースに完全に収めてしまっても、リビングや寝室(同じWi-Fi内)から水温の推移をニヤニヤしながら見守ることが可能だ。ファンの音が小さいから動作してるのか判らん!というのもある。あくまで現在の温度と冷却ファンの動作状況を確認するだけのシンプルなものだ。温度のチャート表示機能は未実装である。
#include <WiFi.h>
#include <WebServer.h>
#include <OneWire.h>
#include <DallasTemperature.h>
// Wi-Fi接続情報(自宅のWi-Fi環境に合わせて書き換えてくれ)
const char* ssid = "YOUR_SSID";
const char* password = "YOUR_PASSWORD";
// ピン配置の設定
const int ONE_WIRE_BUS = 2; // DS18B20のデータピン(DQ)
const int FAN_PIN = 3; // MOSFET制御用のピン(GPIO 3)
// 温度制御パラメーターの設定
const float TURN_ON_TEMP = 27.0;
const float TURN_OFF_TEMP = 26.5;
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
WebServer server(80); // ポート80でWebサーバーを起動
// グローバル変数
float currentTemp = 0.0;
bool isFanRunning = false;
unsigned long lastMeasureTime = 0;
// ルートページ(ブラウザに表示するHTML)の処理
void handleRoot() {
String html = "<!DOCTYPE html><html><head><meta charset='utf-8'>";
html += "<meta name='viewport' content='width=device-width, initial-scale=1.0'>";
html += "<title>水温監視システム</title>";
// 3秒ごとにページを自動更新するJavaScript
html += "<script>setInterval(function(){ location.reload(); }, 3000);</script>";
html += "<style>";
html += "body { font-family: sans-serif; background: #f0f4f8; text-align: center; padding: 20px; color: #333; }";
html += ".card { background: white; max-width: 400px; margin: 0 auto; padding: 20px; border-radius: 12px; box-shadow: 0 4px 6px rgba(0,0,0,0.1); }";
html += "h1 { font-size: 20px; color: #1a252f; margin-bottom: 20px; }";
html += ".temp-display { font-size: 48px; font-weight: bold; color: #2c3e50; margin: 10px 0; }";
html += ".status { display: inline-block; padding: 8px 16px; border-radius: 20px; font-weight: bold; color: white; }";
html += ".status.on { background: #e74c3c; animation: pulse 2s infinite; }";
html += ".status.off { background: #7f8c8d; }";
html += "@keyframes pulse { 0% { opacity: 1; } 50% { opacity: 0.6; } 100% { opacity: 1; } }";
html += "</style></head><body>";
html += "<div class='card'>";
html += "<h1>Ordered by AI <br>水温・ファン監視モニター</h1>";
// 温度表示(エラーチェック付き)
if (currentTemp == DEVICE_DISCONNECTED_C) {
html += "<div class='temp-display' style='color:#e74c3c; font-size:24px;'>センサーエラー</div>";
} else {
html += "<div class='temp-display'>" + String(currentTemp, 1) + " <span style='font-size:24px;'>°C</span></div>";
}
// ファンの状態表示
if (isFanRunning) {
html += "<div class='status on'>冷却ファン: 作動中</div>";
} else {
html += "<div class='status off'>冷却ファン: 停止中</div>";
}
html += "<p style='font-size:12px; color:#95a5a6; margin-top:20px;'>※3秒ごとに自動更新中</p>";
html += "</div></body></html>";
server.send(200, "text/html", html);
}
void setup() {
Serial.begin(115200);
delay(1000);
sensors.begin();
pinMode(FAN_PIN, OUTPUT);
digitalWrite(FAN_PIN, LOW);
// Wi-Fi接続開始
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
// 接続成功したらIPアドレスを表示
Serial.println("");
Serial.println("WiFi connected.");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
// Webサーバーの設定
server.on("/", handleRoot);
server.begin();
Serial.println("HTTP server started");
}
void loop() {
// Webサーバーへのアクセスを処理
server.handleClient();
// 2秒ごとに温度計測とファン制御(非ブロッキング処理)
unsigned long now = millis();
if (now - lastMeasureTime >= 2000) {
lastMeasureTime = now;
sensors.requestTemperatures();
currentTemp = sensors.getTempCByIndex(0);
if (currentTemp == DEVICE_DISCONNECTED_C) {
digitalWrite(FAN_PIN, LOW);
isFanRunning = false;
return;
}
// ファン制御ロジック
if (!isFanRunning && currentTemp >= TURN_ON_TEMP) {
digitalWrite(FAN_PIN, HIGH);
isFanRunning = true;
}
else if (isFanRunning && currentTemp <= TURN_OFF_TEMP) {
digitalWrite(FAN_PIN, LOW);
isFanRunning = false;
}
}
}
3Dプリンタによる専用ケースの製作と実装
ブレッドボードでのテスト動作が無事に確認できた後は、いよいよ実用機としての「実装」だ。
長期間の運用、しかも水回りでの使用を想定しているため、配線のハンダ付けを入念に行い、基板が結露や水滴に触れないよう、3Dプリンタで専用のコントロールボックス(ケース)を設計・出力する。設計開始するまでは気合い入ってるのだが、いざ設計を始めると次第にいい加減になってくるのはなぜなのだろう。面取りとかケースのデザインとかどうでもよくなってケースは豆腐建築となった。(マイクラでよくあるやつ)
材料のサイズに合わせたケースを作れるのも、3Dプリンタ自作ならではの醍醐味だ。3Dプリント後にピッタリ部品が収まるのは何とも気持ちが良い。 マイコンはピンソケットを使わずユニバーサル基板上に半田付けだ。後のメンテナンスなど考えない。ケーブルの引き出し口には防水・防湿を意識することもなく、水槽から少し高い位置に離して設置したら良いだろうという考えに落ち着いた。


ついに稼働開始!
全てのコンポーネントをケースに収め、水槽へセット。 電源を投入すると、シリアルモニタを繋がずとも、スマホのブラウザから「26.8℃、冷却ファン:作動中」の文字が。

AIの正確なコード生成とアドバイスのおかげで、極めて安定して動作している。水槽が40cm規格であったため、小さめの40mmDCファンを選択したが、もっと大きなファンで回してもよかったかもしれない。まあ、装置のコンパクトさは気に入っている。


まとめ
これまではハードウェアの仕様を自分で一から調べるのは電子工作素人には大変だったが、AIに「3.3V駆動で12V 0.08Aのファンを回したい」と相談するだけで、最適なMOSFETの型番(2SK4017)や必要な抵抗の構成を一瞬で導き出してくれる時代になったことを実感した。
まさに「Ordered by AI(AIの命令・注文通りに)」具現化した、大満足のDIYプロジェクトとなった。
夏場の水温上昇に悩んでいるアクアリストや、機器の熱対策を考えている方の参考になれば幸いだ。
それでは、また次のプロジェクトで!
(そろそろHGユニコーンを完成させねば。。。)
