気の向くままに辿るIT/ICT/IoT
IoT・電子工作

スマートな加湿ストリーマ空気清浄機を更にスマート化

ホーム前へ次へ
スマート家電って?

スマートな加湿ストリーマ空気清浄機を更にスマート化

スマートな加湿ストリーマ空気清浄機を更にスマート化

ダイキン加湿ストリーマ空気清浄機MCK70Y-W
2023/05/24

 約1ヶ月前に届いたスマート家電であるダイキン加湿ストリーマ空気清浄機MCK70Yを本気でスマート化してみた話。

 わかっていて買ったのですが、スマホ専用アプリや市販のAIスマートスピーカーからしか操作できないのは、ちっともスマートじゃない。

 会員登録は面倒、ログイン必須とか、クラウド経由というのは、ちょっと抵抗あるんですよね。

 やっぱり、これは頂けない!

会員登録・ログイン必須・クラウド経由を回避

 というわけで、これは届く日の前後にやったことです。

 調べてみると本家https://www.ac.daikin.co.jp/appの[ネットでコントロール]タブ中段付近に「ご利用にはCLUB DAIKINへの会員登録が必要です(Daikin Smart APPご利用時のCLUB DAIKIN登録必須化について)」という注釈(下三角▼をタップ|クリックで詳細表示)を発見。

 これによるとDAIKIN Smart APPに関しては、バージョン7.0から外から操作だけでなく、宅内操作もクラウド経由となり、2年ほど前から会員登録とログインが必須となった旨、書いてありました。

 つまり、それ以前は、必須ではなかったと。

 というわけで「自己責任で」Google Play Storeにあるアプリ含め多数収録しているAPKPureやAPKMirrorなどから「非公式」で旧バージョンのDAIKIN Smart APPアプリ、バージョン6.4の.apkファイルをダウンロード、タップしてインストール。

 併せて自動更新でいつの間にかログイン必須の最新バージョンにアップデートされないようにAndroidスマホでログインしているGoogle Play Storeの設定で自動更新を停止して、当該バージョンを使い続けることにしました。

 他からインストールしている旧バージョンDAIKIN Smart APP v6.4も自ら積極的にGoogle(Google Play開発者サービス)と通信するようで自動更新を停止しておかないとログイン必須の最新バージョンになってしまうので...。

 当然ながら、以前から[外から操作]に関しては、クラウド経由だったとのことですが、これは、既に環境のあるVPNで代替することに。

 これで以前できたというように宅内のWi-FiだけでスマホからMCK70Yのアクセスポイントに接続、続いて自宅の無線LANアクセスポイントを設定することで操作できるようになりました。

 つまり、自己責任は伴いますし、Google Play Storeの他のアプリについては手動で更新する必要はありますが、この方法で会員登録とクラウド、常時ログインは不要となり、LAN内で完結できました。

 ちなみに自身は、ほぼ、F-Droid収録アプリで事足りており、Google Play Storeからインストールしたアプリは、6つほどしかないのでさほど手間ではありません。

 と言っても後述のようにブラウザ操作パネルや操作スクリプトができて、それを使う(アプリを使う必要がない)なら、アンインストールしても良いわけで、Google Play Storeの自動更新を止めるまでもありませんけどね。

パソコン/スマホ/タブレットで自作Web操作パネルや自作スマートスピーカー機能から操作してみる

 続いて解決すべきは、旧バージョンにせよ、そのままだとスマホ専用アプリDAIKIN Smart APPか、連携しているAmazon AlexaやGoogle Homeといった市販のAIスマートスピーカーからしか操作できない件。

 これには、あれこれ試して、結果、救世主たちに出会うまで足掛け約1ヶ月かかりました。

 スマート家電を買うまでもなく、DIYでスマートホーム化している我が家では、後段リンクにもあるようにスマートスピーカー、スマートリモコン、スマートプラグなども自作しており、スマートスピーカー機能に関しては、専用機の他、2台のパソコンにも入れて使っています。

 また、エアコン、テレビ、以前使っていた空気清浄機といった赤外線リモコン対応製品、カーテン、自作ロールカーテン、壁スイッチの照明や紐を引くペンダントライト等々もWi-Fi/Bluetoothの載ったESP32というマイコンボードを使い、電動化・スマート化し、自作Web操作パネルや音声で操作しています。

 やりませんが、Amazon Alexa、Google Home、IFTTTやBlynkでも操作できるはずです。

 そんな中、スマートなはずの生まれながらのスマート家電が操作方法が限定されているって皮肉な話だよねと常々思っていました。

 当初、せめて自作Web操作パネルから呼ぶだけでも呼ぼうかとも思ったのですが、Daikin Smart APPも最新版アプリでは呼べるも旧バージョンは呼べない仕様、そもそも戻ってこれるわけでもなく、イマイチ。

 視点を変えてDebianにWaydroidを入れたり、Raspberry Pi 400にWaydroidを入れたりしてパソコン上で快適にAndroidを動かすことができ満足したものの、各種仮想化同様、Wi-Fiが使えない点で断念。

 他方、以前から、そもそも赤外線リモコンや、はたまたWiresharkみたいな感じでスマート家電のスマホ専用アプリの通信って解析できないのかと思いを馳せていました。

 が、ここにきて、IOT家電をAPIハックして、Siriから簡単に操作する方法のようにすれば、できることがわかり、akiraseto / daikinCleanerと併せ、おかげ様でDAIKIN Smart APPの各種操作コマンドが大方わかりました。

 ただ、PC上にプロキシのアプリをインストール、起動させ、当該PCとスマホを接続させるWi-Fiアクセスポイントにスマホ上で手動でプロキシのIPとポートを設定した上でそこにアクセス、Daikin Smart APPなどアプリから操作してPC上のプロキシアプリを介してコマンドを確認...。

 これ、すごくナイスなんですけど、動作が安定せず、うまくいく時といかない時があるんですよね。

2023/06/03

 あ、失礼、できた、できました。

 スマホからSSIDにプロキシ設定を追加した際、一時的にネットに接続できないこともあるようで、考えてみれば、デフォルトの8080や8000など使用される可能性の高いポートではないポートを指定した方が良かったのか、まさにmitm.itにアクセスできず、証明書のダウンロードすらできていなかったことが原因でした。

 そりゃ、できないわ...って証明書もインストールできてなかったのに一瞬でも見られたのは逆になんだったんでしょう...。

 さておき、改めてやってみると設定後もネット接続でき、mitm.itにアクセス、自身の場合、Android用の証明書をダウンロード、証明書を追加、削除する by Googleで証明書を追加することで起動中の端末ベースのmitmproxy画面にもその様子が表示され、専用アプリの通信もいろいろ表示されました。

 ただし、mitmproxy画面は自動スクロールしないので画面いっぱいに表示された後の最新の操作状況は逐一、下矢印キー等でスクロールする必要があります。

 確かに1つ1つ確認するとなると自動スクロールされると困るので、そうじゃないと。

 というわけで確認できてみると、操作系とは別に、まだ、知らないコマンドがいくつもありました。

 ただ、PC上にプロキシのアプリをインストール、起動させ、当該PCとスマホを接続させるWi-Fiアクセスポイントにスマホ上で手動でプロキシのIPとポートを設定した上でそこにアクセス、Daikin Smart APPなどアプリから操作してPC上のプロキシアプリを介してコマンドを確認...。

 これ、すごくナイスなんですけど、動作が安定せず、うまくいく時といかない時があるんですよね。

 実際やってみるとスマホでプロキシ設定した既存のSSIDにアクセスした時点でアプリはネット接続できないからと操作不能になり、個々のコマンドを確認できないという...。

 うまくいったというのは、アプリが操作できなくなる前に操作もしていないのにズラーッと操作コマンドが並んだことがあり、そこに多くのコマンドとなるパスがあったというだけで、その後、再現できていません...。

 幸いにして今回は、その取得できたパス群、前掲2つのリンク先に記載のコマンド、あっても引数の調整で事足りているので事なきを得ています。

 これって、ちょっと前まではアプリがネット接続を前提としていなかったのか、逆にリンク先で使っているアプリがより新しく、自身が使う旧バージョンではネット接続前提となっていたのか、はたまたAndroidの仕業なのか...、自身のやり方に問題があるのか。

 さておき、操作コマンドがわかれば、ShellやPythonなどでスクリプトを組めるので自作のスマートスピーカーからでも音声操作できますし、指定パスを投げれば良いだけなら、ブラウザベースの自作操作パネルからでも労せず、操作できるように。

 よってパソコンのみならず、スマホ・タブレットも専用アプリを使うまでもなく、操作できるようになります。

 ESPボードなどで自作する場合もそうですが、ESPボードをサーバとして実行したい機能ごとにIPアドレスやmDNSベースのパスに必要なら引数を渡すというのが定石。

 Androidは素直にmDNSを使える方法がないのでIPアドレスを使うしかありません。

 ただ、MCK70Y含め、はなからスマート家電と言われるものの多くは、その機器にIPアドレスを固定する方法がない模様。

 他方、我が家のONU/ルーターでもDHCP配布範囲を指定(=範囲外を固定)することはできても個々に固定することはできません。

 固定できないとDHCPでIPが、ふいに変更された時、各機能はIPアドレス込みで指定する必要があるため、操作不能となってしまいます。

 そこで世界で唯一、一意となる(はずの)macアドレスからIPアドレスを割り出すことにしました。

 ただ、独立したマイコンではmacアドレスやIPアドレス自体の収集はできても特定・抽出、文字列加工してパスとしてセット...はできないため(ん?できるか...?)、パソコンなどコンピュータ上のスクリプトを噛ませる必要が生じ、結果、Webサーバを建てることにしました。

 後述の通り、さして難しいことではないのでサラリと言ってますが、とは言え、Webサーバを建てる=パソコンやラズパイなどコンピュータが必要、操作する際には、それらパソコンなりが起動していないといけないわけです。

 サーバなら1台で済みますが、操作する度に起動するわけにはいかないので常時起動、もしくは操作する時間が決まっているならその時間帯は起動しておかないと操作できないことになります。

 後者を考えるとパソコンの前にいる時に起動していれば良いので複数ある場合は、それぞれ重複して設定する必要はあるものの、個々のパソコンを起動する際に同時にWebサーバも起動しておくという手もありますが。

 我が家でも各種サーバをまとめてラズパイ1台で運用はしていますが、常時起動させるまでもなく、ラズパイが入手しづらい折り、より長持ちするかなとの思いもあって...と言ってもそうして使っていたRaspberry Pi 2Bは6年ほどで壊れ(と思ったら、壊れてなかったけど)、今は3B+ですが、必要都度起動させています。

 何れにせよ、このためだけにサーバを常時起動させる気にはならないので2台あるパソコンにそれぞれWebサーバを建てて、同じスクリプトを置いて運用することにしました。

 スマホはアプリを使えばいいかと思ってのことですが、スマホもこの方式でやるなら、サーバ常時起動一択ですが。

 IPの固定さえできれば、その必要もないんですけどね...。

 現に自宅内のスマート化していたものは、単に操作パネルホーム画面用のHTML/CSSをESPボード上に配置、一部JavaScriptも使ってはいましたが、各機器用のESPボードにアクセスする固定IPアドレス含むパスを投げると、それぞれWeb操作パネルを仕込んであるのでそこから操作するだけで済んでおり、Webサーバは不要だったわけで。

 初めて触るNode-REDやNode.jsでPython-shellもやってみたりもしましたが、これらはサーバサイドスクリプトであり、ブラウザをクライアントに使う場合は、素直にJavaScriptを使えばよく、Python-shellというのはお門違い...。

 一方、最近は、Python界隈だけでもJavaScriptの代わりにPythonで書けるBrython、HTMLに直書きで挿入して使えるPyScriptなどはありますが、前者は、あくまでブラウザ上で使えるJavaScriptの代替、後者はスクリプトも呼べたりしますが、現状では処理速度がネック...。

 また、Eelやpywebviewといったものもありますが、デスクトップアプリで遠隔操作は対応してない模様。

 Webサーバに関しては、PythonだとTornado、Flask、DjangoなどPythonベースのフレームワークが多々あるので連携も楽でCGIよりも簡単でありがたい。

2023/06/03

 と一度はFlaskで作ってみたものの、忘れていた機能を組み込むに当たり、Flaskで戸惑ったのでほぼ初めてながらNode.jsに変更することにしました。

 また、Pythonスクリプトはそのままですが、併せて以下リンク先に転載しました。

転載先
市販スマート家電用ブラウザ操作パネルと操作スクリプトを自作
from flask import Flask, render_template
 
app = Flask(__name__)
 
import logging
logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
from scapy.all import srp1, Ether, ARP
 
def scan(macaddr: str, nwaddr: str) -> str:
  ans = srp1(Ether(dst=macaddr) / ARP(pdst=nwaddr), timeout=1, verbose=0)
  if not ans:
    return ""
  return ans.psrc
 
ipaddr = scan("**:**:**:**:**:**", "192.168.0.0/24")
print('ipaddr',ipaddr)
 
url = 'http://' + ipaddr
 
data = [url]
 
@app.route("/index")
def index():
  return render_template("index.html",input_from_python= data)
 
if __name__ == "__main__":
  app.run(debug=False, host='0.0.0.0', port=8000)

 というわけでWebサーバには、Flaskを選択。

 PythonでMAC AddressからIP Addressを調べるをほぼそのままに組み込ませていただき書いたPythonスクリプトはこんな感じ。

 scanの第1引数に予めnmapコマンドなどで調べた当該機器のMACアドレス、第2引数にはネットワークアドレスとアドレス範囲を指定。

 returnするrender_template()でtemplates/index.htmlで値を参照・取得する際は、{{ input_from_python }}を二重中括弧付きで使用でき、def index():でIP:PORT/indexにアクセスした際、そのindex.htmlが表示されるようにしています。

 また、app.run()でhostに0.0.0.0と指定することで自端末のみならず、他端末からでもIPアドレスでアクセスできるようにしています。

 尤も起動中のパソコンでだけ使うのであれば、単にapp.run()としてlocalhostや127.0.0.1でアクセスしても良いんですけどね。

 ということで他端末からアクセスさせることを考えると自端末もIPを固定しておく必要があることになります。

 Flaskは検証・開発環境でのみ、実運用では、WebサーバとしてWSGIServerなどを使う旨、ドキュメントに記述があったり、時折メッセージ表示されたりすることがあります。

 Raspberry Pi/Flask/RPI.GPIO/28BYJ-48でUSBカメラをパンチルトでは、FlaskでWSGIServerを使っています。

 今回、なぜか、WSGIServerのインストールでエラーが出たのでそのまま使うことに...、あ、pipモジュールパッケージはWSGIServerじゃなくてgeventか(gunicornじゃないよね)...間違えた。

パソコン/スマホ/タブレットから自作ブラウザ操作パネルでスマート家電操作

 あと、自家製スマートガジェットでは、個別にボタンをタップ|クリックすればよかったのですが、MCK70Yでは、ちょっとJavaScriptでの工夫を要しました。

 風量と運転モードを分けたこともあり、そのボタンを押したら、こっちは押してないことにしないと不自然とか押下ボタンが排他になるケース、これらに加湿機能の有無及びレベル設定を組み合わせたりとか。

 デザインは再考の余地が多分にありますが。

 尤も現在の運転状況を考慮せず、ボタンだけを配置して都度実行すれば、簡単なんですけど、つい、スマホアプリ仕様に釣られました。

<!doctype html>
<head>
<link rel="stylesheet" href="{{ url_for('static', filename='css.css') }}">
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
 
<script>
var fullarg = "";
var getpath = "";
function http_req(url) {
 var req = new XMLHttpRequest();
 req.open("GET", url, true);
 req.send();
}
window.addEventListener('DOMContentLoaded', function(){
 var input_mode = document.querySelectorAll("input[name=mode]");
 for(var element of input_mode) {
  element.checked = false;
 }
 var input_wind = document.querySelectorAll("input[name=wind]");
 for(var element of input_wind) {
  element.checked = false;
 }
 document.getElementById('humi_off').checked = true;
});
 
window.addEventListener('DOMContentLoaded', function(){
 var input_power = document.querySelectorAll("input[name=power]");
 for(var element of input_power) {
  element.addEventListener('change',function(){
   if( this.checked ) {
    var list_data = {{ input_from_python | tojson }};
    console.log("this.value : " + this.value);
    var getpath = list_data + this.value;
    if ( this.value.includes('pow=0') ) {
     var input_mode = document.querySelectorAll("input[name=mode]");
     for(var element of input_mode) {
      element.checked = false;
     }
     var input_wind = document.querySelectorAll("input[name=wind]");
     for(var element of input_wind) {
      element.checked = false;
     }
     document.getElementById('humi_off').checked = true;
    }
    console.log(getpath);
    http_req(getpath);
   }
  });
 }
});
 
window.addEventListener('DOMContentLoaded', function(){
 var input_mode = document.querySelectorAll("input[name=mode]");
 var list_data = "";
 for(var element of input_mode) {
  element.addEventListener('change',function(){
   if( this.checked ) {
    var input_wind = document.querySelectorAll("input[name=wind]");
    for(var element of input_wind) {
     element.checked = false;
    }
    document.getElementById('humi_off').checked = true;
    list_data = {{ input_from_python | tojson }};
    getpath = list_data + this.value;
    console.log("getpath : " + getpath);
    var input_humd = document.querySelectorAll("input[name=humd]");
    var cnt = 0;
    for(var element of input_humd) {
     element.addEventListener('change',function(){
      if( this.checked ) {
       cnt++;
      }
     });
    }
    if (cnt > 0) {
      fullarg = getpath + '&' + this.value;
    } else {
      fullarg = getpath + '&' + "humd=0";
    }
    console.log("fullarg : " + fullarg);
    http_req(fullarg);
    document.getElementById('poweron').checked = true;
   }
  });
 }
});
 
window.addEventListener('DOMContentLoaded', function(){
 var input_wind = document.querySelectorAll("input[name=wind]");
 for(var element of input_wind) {
  element.addEventListener('change',function(){
   if( this.checked ) {
    var input_mode = document.querySelectorAll("input[name=mode]");
    for(var element of input_mode) {
     element.checked = false;
    }
    document.getElementById('humi_off').checked = true;
    list_data = {{ input_from_python | tojson }};
    getpath = list_data + this.value;
    console.log("getpath : " + getpath);
    var input_humd = document.querySelectorAll("input[name=humd]");
    var cnt = 0;
    for(var element of input_humd) {
     element.addEventListener('change',function(){
      if( this.checked ) {
       cnt++;
      }
     });
    }
    if (cnt > 0) {
      fullarg = getpath + '&' + this.value;
    } else {
      fullarg = getpath + '&' + "humd=0";
    }
    console.log("fullarg : " + fullarg);
    http_req(fullarg);
    document.getElementById('poweron').checked = true;
   }
  });
 }
});
 
window.addEventListener('DOMContentLoaded', function(){
 var input_humd = document.querySelectorAll("input[name=humd]");
 var cnt = 0;
 for(var element of input_humd) {
  element.addEventListener('change',function(){
   if( this.checked ) {
    fullarg = fullarg.replace(/humd=[0-9]/, this.value);
    console.log("fullarg : " + fullarg);
    http_req(fullarg);
   }
  });
 }
});
 
</script>
</head>
<body>
 
<div style="margin:10px ;padding:10px ;text-align:center ;font-size:80% ;">DAIKIN 加湿ストリーマ空気清浄機MCK70Y</div>
<div style="text-align:center ;">【電源】</div>
<form method="post" id="onoff_form">
<table style="width:100%">
<tr><td style="text-align:center">
<input id="poweron" type="radio" name="power" value="/cleaner/set_control_info?pow=1">
<br><label for="poweron">ON</label>
</td>
<td style="text-align:center">
<input id="poweroff" type="radio" name="power" value="/cleaner/set_control_info?pow=0">
<br><label for="poweroff">OFF</label>
</td></tr>
</table>
</form>
 
<div style="margin:auto ;padding:auto ;text-align:center ;width:100% ;">
 
<div style="margin:3px ;padding:3px ;width:30% ;float:none ;">
<div style="text-align:center ;">【モード】</div>
<form method="post" id="mode_form">
<table style="margin:3px ;padding:3px ;">
<tr><td style="width:40% ;">
<div style="width:40% ;float:none ;overflow:auto ;">
<input id="reliance" type="radio" name="mode" value="/cleaner/set_control_info?pow=1&mode=1&airvol=0">
<br><label for="reliance">おまかせ</label>
</div>
<div style="width:40% ;float:none ;overflow:auto ;">
<input id="power_save" type="radio" name="mode" value="/cleaner/set_control_info?pow=1&mode=2&airvol=0">
<br><label for="power_save">節電</label>
</div>
<div class="clear_pos"></div>
</td></tr>
<tr><td>
<div style="width:40% ;float:none ;overflow:auto ;">
<input id="pollen" type="radio" name="mode" value="/cleaner/set_control_info?pow=1&mode=3&airvol=0">
<br><label for="pollen">花粉</label>
</div>
<div style="width:40% ;float:none ;overflow:auto ;">
<input id="throat_skin" type="radio" name="mode" value="/cleaner/set_control_info?pow=1&mode=4&airvol=0">
<br><label for="throat_skin">のど・はだ</label>
</div>
<div class="clear_pos"></div>
</td></tr>
<tr><td>
<div style="width:40% ;float:none ;overflow:auto ;">
<input id="circulator" type="radio" name="mode" value="/cleaner/set_control_info?pow=1&mode=5&airvol=0">
<br><label for="circulator">サーキュレーター</label>
<div class="clear_pos"></div>
</td></tr>
</table>
</form>
</div>
 
<div style="margin:3px ;padding:3px ;width:30% ;float:none ;">
<div style="text-align:center ;">【風量】</div>
<form method="post" id="wind_form">
<table style="margin:3px ;padding:3px ;">
<tr><td style="width:40% ;">
<div style="width:40% ;float:none ;overflow:auto ;">
<input id="auto_wind" type="radio" name="wind" value="/cleaner/set_control_info?pow=1&mode=0&airvol=0">
<br><label for="auto_wind">風量自動</label>
</div>
<div style="width:40% ;float:none ;overflow:auto ;">
<input id="reliance" type="radio" name="wind" value="/cleaner/set_control_info?pow=1&mode=0&airvol=1">
<br><label for="reliance">しずか</label>
</div>
<div class="clear_pos"></div>
</td></tr>
<tr><td>
<div style="width:40% ;float:none ;overflow:auto ;">
<input id="weak" type="radio" name="wind" value="/cleaner/set_control_info?pow=1&mode=0&airvol=2">
<br><label for="weak">弱</label>
</div>
<div style="width:40% ;float:none ;overflow:auto ;">
<input id="standard" type="radio" name="wind" value="/cleaner/set_control_info?pow=1&mode=0&airvol=3">
<br><label for="standard">標準</label>
</div>
<div class="clear_pos"></div>
</td></tr>
<tr><td>
<div style="width:40% ;float:none ;overflow:auto ;">
<input id="turbo" type="radio" name="wind" value="/cleaner/set_control_info?pow=1&mode=0&airvol=5">
<br><label for="turbo">ターボ</label>
</div>
<div class="clear_pos"></div>
</td></tr>
</table>
</form>
</div>
 
<div style="margin:3px ;padding:3px ;width:30% ;float:none ;">
<div style="text-align:center ;">【加湿】</div>
<form method="post" id="humi_form">
<table style="margin:3px ;padding:3px ;">
<tr><td style="width:40% ;">
<input id="humi_off" type="radio" name="humd" value="humd=0" checked="checked">
<br><label for="humi_off">OFF</label>
</td></tr>
<tr><td>
<div style="width:40% ;float:none ;overflow:auto ;">
<input id="humi_low" type="radio" name="humd" value="humd=1">
<br><label for="humi_low">ひかえめ</label>
</div>
<div style="width:40% ;float:none ;overflow:auto ;">
<input id="humi_standard" type="radio" name="humd" value="humd=2">
<br><label for="humi_standard">標準</label>
</div>
<div class="clear_pos"></div>
</td></tr>
<tr><td>
<div style="width:40% ;float:none ;overflow:auto ;">
<input id="humi_high" type="radio" name="humd" value="humd=3">
<br><label for="humi_high">高め</label>
</div>
<div style="width:40% ;float:none ;overflow:auto ;">
<input id="skin_auto" type="radio" name="wind" value="humd=4" disabled="disabled" readonly="readonly">
<br><label for="skin_auto">のど・はだ自動</label>
</div>
<div class="clear_pos"></div>
</td></tr>
</table>
</form>
</div>
<div class="clear_pos"></div>
 
</div>
 
</body>
</html>

 CSSは割愛、よって各ラジオボタンは大きな丸にはならないですが、JavaScript込みのHTMLファイルindex.htmlはこれ。

 CSSではなくHTMLタグで無理やりレイアウトしているところもありますが、ご愛嬌ということで。

 操作パネルからはこれで操作できます。

 パソコンでもスマホでもタブレットでも。

 コマンドも実際のものなので後述の対象となるダイキン加湿ストリーマ空気清浄機とWi-Fi環境があってpythonスクリプトでMACアドレスとネットワークアドレスを指定し、Python実行環境があれば、そのまま操作できるでしょう。

 あ、運転中に操作パネルを閉じて、改めて開いた時の為に運転情報を読み込んでボタンに反映させるの忘れてた...今のままだと開く度にパネル上ではOFFに...、pythonも追加ロジックいりますね、気が向いたら、また、あとで...。

 結果、スマホ・タブレットに限らず、パソコンの操作パネルからでもラズパイやパソコンに入れたJulius/Open JTalkスマートスピーカー機能からでも操作できるようになりました。

 ここまでできただけに惜しむらくは、ルーバーは自動であって欲しかった...。

 さておき、これでMCK70Yもスマートホーム化した我が家にふさわしく本当の意味でスマートに。

 参考にさせて頂いた前掲リンク先は、共にMCK70Wを使用しているとのこと、加えて今回、MCK70Yも、ということは間のMCK70Xも、また、現行、最新はMCK70Zですが、ルックスも機能もYと全く同じと思われるので、また、販路が異なるだけで同じ仕様だと言われるACK70W/ACK70X/ACK70Y/ACK70Z、TCK70W/TCK70X/TCK70Y/TCK70Zなども存在するなら同様にできるかと。

 改めてMCK70Y、ようこそスマートホームな我が家へ。

ホーム前へ次へ