遠隔・自動操作できるようにした加湿器をさらに改造 電流(CT)センサ 使い方 ~簡易IoT家電「改」~
背景
今回で4度目になる加湿器の改造がメインの話になります。
以前、加湿器を遠隔・自動で操作できるように改造しました。
タイトルにもある通り、今回はCTセンサを使って改造していきたい思います。
何をしたいからと言うと。。。
今まで、加湿器のハード的な問題でON・OFFそれぞれの独立した信号で操作することが出来ませんでした。(元々ボタンを押すと状態を反転させているだけだったので。。。)
これにより、日時指定して自動で起動している場合だと手動で間違って電源を消してしまった場合、決まった時間に電源状態の反転信号が送られて本来使わない時間に電源が入ったままになってしまうことがありました。
例) 朝6時と夕方18時に信号を送っていたとして、18時以降には電源が落ちている状態にしたいのに18時手前に手動で電源を落として退席してしまうと、18時に電源が入って朝の6時まで切れないということになってしまいます。
今回はこれを解消するために、加湿器が稼働している否かの状態を取れるようにして、その情報を基にうまく制御していきたいと思います。
そこで使うのがCTセンサと言うことです。
これは、コンセントに刺しているコードからほぼ非接触で電流を測れるセンサになっているため、HaLakeで使用している加湿器のみに使える手法ではなく仕組みとプログラムとを理解したうえで、多少の犠牲を払えば誰でも簡単に同じようなことが出来ます。
また、多少の誤差を気にしなければ大まかな消費電力も測ることが出来ます。
消費電力が小さすぎると誤差が大きく出るため、今回の用途としては消費電力の計測には使用しませんが、気になる方はとても参考になった記事があるのでそちらを拝見してください。
先ほどの多少の犠牲と言いましたがセンサを使う際、コードをよく見ると二本の線でてきていることがわかりますが(見た目でわからないものもある)、このうちの一本のみをセンサで挟み込む必要があります。
はさむと言っても洗濯ばさみのようになっているセンサに通すというイメージです。
その点に目をつむれば低コストかつ一般の方でも比較的安全に使うことが出来ます。
- 注意: 以降の記事を読んで試される方は十分に注意を払ったうえで参考にしてください。当記事を参考にしたうえで起こった事故や損害、怪我等のあらゆる問題に関して一切の責任を負いません。
少し脅しになってしまいましたが、コンセントから伸びる線を扱うため気を付けましょう。
以前の記事1・以前の記事2・以前の記事3を読んで頂ける分かりやすい内容になっていますので、読んで頂けると嬉しいです。
使ったもの
配線
配線は以下のようになります。
実際の配線は以下のようになります。
抵抗は1.8KΩを5つで、3.3Vを5分の1(抵抗1個に約0.66V)の分圧をするため、手元にあってサイズが小さい抵抗を使っています。
esp8266が1Vまでしか計測できないのと交流のような値が返ってくるため、0.66Vを中心に値が変動するように設定しています。本来なら1V の半分の0.5Vで設定したいのですが3.3Vや5Vからだと抵抗の値や数がややこしくなるためこれで妥協します。
esp8266で再現するときは1KΩ~10KΩ程度で同じ抵抗値を5つと別にCTセンサの負荷抵抗として33Ω程度を用意してください。
負荷抵抗として33Ωを使ったのは以下の記事を参考に抵抗値を上げると測定の感度が上がるということだったので、通常の10Ωだと消費電力が少ない時にうまく計測出来ないことがあるため、電源がONかOFFの判定がうまく出来ないと不便だったため抵抗値を上げました。
プログラム
まずは筆者の環境で動かしているプログラムです。
以下をそのまま扱う場合は
IPAddress ip(192, 168, ??, ???); //ip
固定するIPアドレスを書く環境に合わせて書き換えてください。
#include <Ticker.h> #include <ESP8266WiFi.h> #define ON_PIN 12 ////IPアドレス固定用 IPAddress ip(192, 168, ??, ???); //ip IPAddress subnet(255, 255, 255, 0); //// long count = 0; int freq = 50; //50Hz double analogPinStatus; double ammeter; double dt = 0.001; double ammeterSum = 0; double realAmmeter = 0; double voltage = 100.0; void getAmmeterValue(); bool last_req_state = false; Ticker tickerCheck(getAmmeterValue, 1, 0, MILLIS); const char* ssid = "**********"; const char* password = "**********"; WiFiServer server(80); void setup() { Serial.begin(115200); Serial.print("Connecting to "); Serial.println(ssid); WiFi.config(ip, ip, subnet); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("WiFi connected."); Serial.println("IP address: "); Serial.println(WiFi.localIP()); server.begin(); pinMode(ON_PIN,OUTPUT); } void loop(){ tickerCheck.update(); WiFiClient client = server.available(); if (client) { Serial.println("New Client."); String currentLine = ""; while (client.connected()) { if (client.available()) { char c = client.read(); Serial.write(c); if (c == '\n') { if (currentLine.length() == 0) { client.println("HTTP/1.1 200 OK"); client.println("Content-type:text/html"); client.println(); client.print("<h1>Server OK</h1>"); client.println(); break; } else { currentLine = ""; } } else if (c != '\r') { currentLine += c; } if (!currentLine.compareTo("x-access-key: HOGEHOGEON")){ last_req_state = true; tickerCheck.start(); } if (!currentLine.compareTo("x-access-key: HOGEHOGEOFF")){ last_req_state = false; tickerCheck.start(); } } } // close the connection: client.stop(); Serial.println("Client Disconnected."); } } int sumRealAmmeter = 0; int avg = 0; void getAmmeterValue() { analogPinStatus = analogRead(0); ammeter = (analogPinStatus - 680.0) * 0.7368359376 * 0.2; ammeterSum = ammeterSum + abs(ammeter) * dt; if (count % 1000 == 0){ realAmmeter = ammeterSum; ammeterSum = 0; Serial.println(realAmmeter); sumRealAmmeter += realAmmeter; } if(count > 10000){ tickerCheck.stop(); Serial.println("ticker stop"); avg = sumRealAmmeter / 10; if(avg * voltage < 400 and last_req_state){ digitalWrite(ON_PIN,HIGH); delay(500); digitalWrite(ON_PIN,LOW); }else if(avg * voltage > 400 and !last_req_state){ digitalWrite(ON_PIN,HIGH); delay(500); digitalWrite(ON_PIN,LOW); } Serial.println(avg * voltage + ":" + last_req_state); sumRealAmmeter = 0; count = 0; } count++; }
消費電力の測定は以下の記事を参考にプログラムを組んでいます。
esp系ではFlexiTimer2のライブラリが使えないのでTickerと言うesp系でも使える割り込みのライブラリを使いました。
動作としては、
- WiFiに接続
- HPPTリクエストを待つ
- 指定しヘッダ情報を持つリクエストが来たらその情報を基にON・OFFの制御に移る
- CTセンサから今の状態(ONかOFF)を10秒ほど計測
- リクエストと直前に計測した状態を比較してリクエスト通りの状態に変化
といった流れになります。
動作確認
動作確認は以前の記事にもあるように、Raspberry Piから送りますが、今回はESPにHTTPリクエストを送って、それを受け取ったら中身の情報(ON/OFF)によって加湿器を制御していきます。
同じプログラムを試したい方で、Raspberry Piを持っていない方もwindowsのコマンドプロンプトから以下のようなコマンドを実行することによって動作します。また、192.168.??.???の部分は各環境に合わせて書き換えてください。
curl -H "x-access-key: HOGEHOGEON" http://192.168.??.??? curl -H "x-access-key: HOGEHOGEOFF" http://192.168.??.???
この二つで制御できるようにしてあります。
もちろんHOGEHOGEONやHOGEHOGEOFFのようにヘッダにのせている情報にONとOFFを付けくわえて単純に制御しています。HOGEHOGEの部分はHaLake利用者が勝手にいじれないように秘密の文字列を使用していますのでダミーが使われています。
Raspberry Piから制御する場合はRaspberry Piのコマンドプロンプトで以下のように設定していきます。
crontab -e
を実行して下記を追記
00 6 * * 0,1,2,4,5,6 sudo curl -H "x-access-key: HOGEHOGEON" http://192.168.??.?? 00 18 * * 0,1,2,4,5,6 sudo curl -H "x-access-key: HOGEHOGEOFF" http://192.168.??.???
cronを使うことによって指定した日時などに自動実行してくれるので便利です。
上記の設定では水曜以外の6時~18時の間で加湿器が稼働する設定になります。
おまけ(設計について)
今回は前回と同様にESP8266を使用していきますが、場合によっては制御側のハードウェアを変えることによって使い方に特化したものが作れます。
正直、使っているESP8266は微妙な性能ではありますが、暇しているものを使っているので妥協しています。
以前で紹介したプログラムは一部の書き換えとパラメータの調製でESP32でも動作するため、わかる人は変えてやってみるのも良いでしょう。
何が微妙かと言うと、大きく以下の2点があげられます。
- シングルコア
- 電圧が1Vまでしか測れない
シングルコアだと常時測定とWiFIなどでの通信が同時に行い辛いためです。
esp8266だとWiFIのクライアントと測定を同時に行うとどちらかがおろそかになります。
理由としては以下になります。
消費電力を正確な値または、常時測定する場合は割り込み処理できっちり決まった時間おきに測定した方が計算できれいな値が取れるのと、細かい間隔で測定しないと値がずれてしまうため、割り込み処理によるWiFi関係の処理が全くされなくなってしまいます。プログラムによってはこれらを回避することもできますが、これらを考慮しないといけないため面倒になります。
また、細かい間隔というのは大雑把に言って大体0.01秒以下での間隔です。標本化定理などからこの測定間隔はおおよ出せます。
関東のコンセントからは50Hzの交流電圧が来るのでセンサからは50Hzの交流のような電圧が測定できるため、50Hzのデータを正確に測るには少なくともこの2倍の周期でセンサから値を取得しなければなりません。
そのため2倍すると100Hzで、この逆数が計測間隔に当たるため1/100 = 0.01秒となります。
それに加え、センサからはノイズなどが乗るためさらに細かい周期で計測しなければ精度が悪くなってしまいます。
そのため上記で示したプログラムでは0.001秒の間隔で測定しています。(ただ増やすだけが良いのかは未検証ですが、対策にはなると考えています。)
さらに今回の内容に関しては先ほど示した2番目にある電圧の測定範囲も重要なポイントになります。
これは、
- CTセンサの値は電圧の変化で返ってくるため1Vの測定範囲はそもそも狭い
- 電源電圧3.3VをCTセンサに向けて測定範囲の1Vまで分圧するのと、電圧が交流のように返ってくるためオフセットの電圧が必要でさらに分圧するため面倒
- 分圧によって測定のずれも出てくる(パラメータ調整で少しはごまかせるが。。。)
そのため、リソースをリッチに使いたい場合はESP32を使用することをお勧めします。しかしESP32では3.6Vまで測定できますが、誤差が乗ると公式でも言われているため、これも注意が必要です。
精度を極めるなら外部でADコンバータなどを付ける必要がありますが、そもそもセンサ自体の精度もあるのでそこまでする必要はないと思います。
また、WiFiを使わない場合は、Arudino UNOや小さいNanoなど、その他互換機を使用すると良いでしょう。
その場合はこちらの記事を参考にするとそのままできると思います。qiita.com
まとめ
- 自宅や工場、会社など電気を扱う場所で電源や消費電力の管理を簡単にできそう。
- はんだ付けや直接被膜の内側である導線を触ることなく測定できるのはとても便利だがリスクは多少ある
コメント
コメントを投稿