前回までの記事で、ESP-01を使って石油ファンヒーターの「延長」ボタンを自動的に押す回路を作成しました。電源はファンヒーターから取得します。今回は回路を拡張して、「運転」ボタンと動作LEDもESP-01に接続し、ファンヒータに組み込み、HomeKitから操作できるようにします。HomeKit対応の石油ファンヒーターの完成です。
前回の取り組み
以前の記事で、石油ファンヒーターに、Seeed Studio XIAO ESP32C3を組み込んで、「延長」ボタンを自動で押す改造をしました。さらにHomeKitから、自動延長のOn/Offを行いました。
今年もファンヒーターを買い足したので、同様に改造することにしました。前回までの記事で、ESP-01を使って、石油ファンヒーターの「延長」ボタンを自動で押せるようになり、その電源をファンヒーターから得られるようになりました。
でも回路はブレッドボード上で組んであるバラック状態です。
今回は、これをユニバーサル基板で組んで、ファンヒータに組み込みます。回路も拡張して、
- 「延長」ボタンに加えて、
- 「運転」ボタンと、
- 動作状態を示すLEDも、
ESP-01に接続します。さらにMQTTに対応したプログラムに変更し、HomeKitから制御できるようにします。これでHomeKitから運転をOn/Offできる石油ファンヒータが完成します。
燃焼機構を持つヒーターを遠隔操作する改造ですし、製品取説には分解・改造を行わないよう警告されています。DIYする際には自己責任でお願いします。
回路を拡張する
今までに作ったハードウェアは、以下のように、「延長」ボタンを自動押しするための回路でした。
これを拡張しました。使用したフォトスイッチモジュールTLP222にはフォトスイッチが2系統入ってましたので、もう片方を「運転」ボタンスイッチに接続します。また、部品箱にフォトカプラーTLP621がありましたので、これを運転状態を示すLEDの場所に接続します。最終的な回路は、以下になりました。
これで、ESP-01のGPIOピンが、
- GPIO0: 「延長」ボタンスイッチへの出力
- GPIO1: 「運転」ボタンスイッチへの出力
- GPIO2: 運転状態LEDからの入力
に接続され、プログラムからアクセスできるようになりました。
配線する
これらの部品を、ユニバーサル基板の上で配線します。その際に、グラフィックスソフトで部品の配置を考えながら配線しました。作図のグリッドを部品の足間隔にして、実際の部品の写真を使って配置を考えると、イメージを掴みやすいです。
完成した基板が以下です。写真では見えませんが、ESP-01の下に抵抗3本が配置されています。
ファンヒーターに組み込む
完成した基板を、ファンヒーターのボタンパネル内に組み込みます。フォトスイッチTLP222の線は、「延長」ボタンと「運転」ボタンの両端に接続します。
ファンヒーターのパネルには、運転状態を表示するLEDがあり、これのアノード側に保護抵抗が直列に接続されています。そこで、保護抵抗の電源側と、LEDのカソード側から線を引き出して、330Ωの保護抵抗を経由してフォトカプラTLP621の内部LEDに接続しました。下の写真で、黄色の絶縁チューブで330Ω抵抗がハンダ付けされている部分と、(他の配線で隠れてますが)LEDのカソード側が配線引き出し部分です。これでフォトカプラー内のLEDが、運転表示LEDと同様に点灯するはずです。
プログラムを作る
このESP-01に以下のプログラムを書き込みました。Wi-Fi経由でMQTTブローカーに接続し、またArduino OTAも有効にしてあります。これで、MQTTのメッセージに従って制御を行います。
#include <EspMQTTClient.h>
#include <ArduinoOTA.h>
EspMQTTClient *client;
const int switchOn=1; //start switch
const int switchEx=0; //extention switch
const int ledOn=2; //LED for On or Off
//status of the fan heater
bool isExtendMode=false; //true: extend on every 150 min
bool isOn=false; //If fan heater is On (true) or Off (false)
//timer & counter using main loop
long int counter=0; //counter for extend-interval (used in loop())
//WiFi & MQTT
const char SSID[] = "XXXXXXXX"; //WiFi SSID
const char PASS[] = "xxxxxxxx"; //WiFi password
char CLIENTID[] = "ESP32_xx:xx:xx:xx:xx:xx"; //MAC address is set in setup()
//for example, this will be set to "ESP32_84:CC:A8:7A:5F:44"
const char MQTTADD[] = "192.168.xxx.xxx"; //Broker IP address
const short MQTTPORT = 1883; //Broker port
const char MQTTUSER[] = "XXXXXXXX";//Can be omitted if not needed
const char MQTTPASS[] = "xxxxxxxx";//Can be omitted if not needed
const char SUBTOPIC[] = "mqttthing/fanheater2/set"; //mqtt topic to subscribe
const char PUBTOPIC[] = "mqttthing/fanheater2/get"; //mqtt topic to publish
const char PUBDEBUG[] = "mqttthing/fanheater2/debug"; //for debug message
void onConnectionEstablished() {
ArduinoOTA.setHostname("fanheater2");
ArduinoOTA.setPasswordHash("99999999999999999999999999999999");
ArduinoOTA.begin();
client->subscribe(SUBTOPIC, onMessageReceived); //set callback function
client->publish(PUBDEBUG,"Fan Heater 2 started.");
pubCurrentStatus();
}
void pubCurrentStatus(){
if(isOn) client->publish(PUBTOPIC,"ON");
else client->publish(PUBTOPIC,"OFF");
if(isExtendMode) client->publish(PUBTOPIC,"exON");
else client->publish(PUBTOPIC,"exOFF");
}
void onMessageReceived(const String& msg) {
client->publish(PUBDEBUG,"Message received.");
if(msg.compareTo("ON")==0 && !isOn) pressSwitch(switchOn);
else if(msg.compareTo("OFF")==0 && isOn) pressSwitch(switchOn);
else if(msg.compareTo("exON")==0) {
pressSwitch(switchEx);
counter=0; //reset interval counter
isExtendMode=true; //enable succeeding extension
}
else if(msg.compareTo("exOFF")==0) {
pressSwitch(switchEx); //last extension
isExtendMode = false; //desable succeeding extension
}
}
void setup() {
pinMode(ledOn, INPUT); //read the LED indicator
pinMode(switchOn, OUTPUT); // On/Off switch
digitalWrite(switchOn, HIGH);
pinMode(switchEx, OUTPUT); // Extend switch
digitalWrite(switchEx, HIGH);
isExtendMode=false; //default value: no extension
String wifiMACString = WiFi.macAddress(); //WiFi MAC address
wifiMACString.toCharArray(&CLIENTID[6], 18, 0); //"ESP32_xx:xx:xx:xx:xx:xx"
client = new EspMQTTClient(SSID,PASS,MQTTADD,MQTTUSER,MQTTPASS,CLIENTID,MQTTPORT);
delay(1000);
}
void pressSwitch(int gpio) {
digitalWrite(gpio, LOW); // turn the photo switch on
delay(1000);
digitalWrite(gpio, HIGH); // turn the photo switch off
}
static int counterLED=0;
void loop() {
ArduinoOTA.handle(); //for OTA
client->loop(); //for MQTT
delay(100);
if(digitalRead(ledOn) == LOW) { //Power-on LED is on
counterLED=0;
isOn = true;
}else{ //Power-on LED is off
if(++counterLED > 10){ //LED is off for >1sec.
counterLED = 0;
isOn = false;
}
}
if(++counter > (150 * 60 * 10)) { //on every 150 min
counter=0;
if(isExtendMode) pressSwitch(switchEx);
}
if((counter % 300) == 0) // on every 30 sec, reports the mode
pubCurrentStatus();
}
ファンヒーターの状態を示すbool型フラグを2個用意しました。isOnは、ファンヒーターが運転中かどうかを示し、isExtendModeは、自動延長するかどうかを示します。それぞれMQTTのgetとsetトピックスで設定します。getとsetの使い分けはこちらをご覧ください。具体的には、HomeKit側から
- mqttthing/fanheater2/setトピックスにONメッセージが来るとファンヒーター運転開始
- mqttthing/fanheater2/setトピックスにOFFメッセージが来るとファンヒーター運転停止
- mqttthing/fanheater2/setトピックスにexONメッセージが来ると自動延長機能有効
- mqttthing/fanheater2/setトピックスにexOFFメッセージが来ると自動延長機能無効
となります。
実際の石油ファンヒータの動作状態は、運転状態表示LEDを読んで設定してます。LEDが点灯すると、運転状態と判定します。LEDが消灯した場合は、1秒以上継続して消灯していた場合に運転停止状態と判定します。運転準備、停止準備などの場合に、LEDが1秒周期で点滅する場合があり、これを運転状態とみなすために、このようにプログラムしました。
HomeKitと連携
これでMQTT制御できる石油ファンヒーターが完成しました。次に、ファンヒーターのMQTT制御をHomeKitから行うために、HomebridgeとMQTTThingプラグインを用意し、設定します。
MQTTThingプラグインの設定部分は以下としました。ESP-01のプログラムは、運転状態表示LEDの状態を読んで、これをmqttthing/fanheater2/getトピックスで伝達してます。それを”getOn”の項目に設定してあるので、人が手動操作でファンヒーターをOn/Offした場合にも、On/Off状態はHomeKitに反映されます。
{
"type": "switch",
"name": "FH2 Extend",
"topics": {
"getOn": "mqttthing/fanheater2/get",
"setOn": "mqttthing/fanheater2/set"
},
"onValue": "exON",
"offValue": "exOFF",
"accessory": "mqttthing"
},
{
"type": "switch",
"name": "FH2 OnOff",
"topics": {
"getOn": "mqttthing/fanheater2/get",
"setOn": "mqttthing/fanheater2/set"
},
"onValue": "ON",
"offValue": "OFF",
"accessory": "mqttthing"
}
この結果、iPhoneやMacのホーム.appに以下のような2個のスイッチが現れます。
FH2 OnOffスイッチをOn/Offすると、石油ファンヒータが運転・停止します。またFH2 ExtendスイッチをOn/Offすると、自動延長機能が有効・無効になります。
Macから石油ファンヒータを運転開始する動画が以下です。実際には1分弱の予熱過程があるので、その部分は動画からトリミングしてあります。これで地球の裏側からでも、石油ファンヒータを点火できます。作ってはいけないものを作ってしまった感じがして、ワクワクします。
まとめ
ESP-01にフォトスイッチ、フォトカプラーを接続し、石油ファンヒータに組み込み、運転ボタン、延長ボタン、運転表示LEDに接続しました。MQTTで制御するプログラムを用意して、Homebridge経由でHomeKitに対応させました。これでHomeKit対応石油ファンヒーターが完成しました。
HomeKit対応とはいっても、On/Offできるだけです。本来のheater accessoryならば、温度設定などができる必要があります。でも現状のファンヒーター制御パネルから、温度設定情報を取り出すのは困難です。On/Offできるだけでもとても便利なので、これで良いと思います。
遠隔地からファンヒーターを運転できてしまう危険な改造ではありますが、遠隔地からファンヒーターの動作状態を確認することもできます。なので消し忘れに気付けるメリットはあります。また、灯油がなくなればいずれは停止します。電熱ストーブなどを自動化するよりは、むしろ安全と言えるかもしれません。
石油ファンヒーターの上位製品には、赤外線リモコンが使える機種もあります。スマートリモコンと組み合わせれば、HomeKit対応が楽にできるかとも考えましたが、赤外線リモコンからは運転開始ができないように設計されているようです。
コメント