用 AJAX 經 Wifi 取代紅外線遙控器

我屋企部電腦係運用最頻密嘅電器,只要簡單整一頁網頁上面有幾粒制,就可以方便遙控有紅外線接收嘅電器,包括冷氣同電視盒,避免揾遙控器同需要對準嘅麻煩。原理同手机紅外線遙控一樣,其實只要能夠發出 38000Hz 嘅超高音,耳机插頭都可以作為紅外線發射訊號嘅接口。

首先要錄低遙控器上面要黚果幾粒制嘅碼,ESP8266 有 IRremote library,其中一個 example 稍為經過修改之後,靠一粒好似 LED 但黑色三腳嘅紅外線接收頭就可以將光波轉為電流訊號,可以透過 Arduino IDE 嘅 Serial Monitor 睇倒 IR碼。一般電器常用嘅係 NEC碼,但我部 Hitachi 冷氣机就認唔倒,要抄低段 raw碼同 bit数,裏面代表晒開机温度同風力之類嘅資訊,所以要每一度整一粒制,同電視盒只需要一粒開關制加両粒轉台制唔同。

#include <IRremoteESP8266.h>
#include <IRac.h>
#include <IRtext.h>
#include <IRutils.h>
//*******************************************************************
//   Instantiate class objects, global constants and Function Prototypes
//*******************************************************************
IRrecv irrecv(pin_d6, 1024, 50, true); //kRecvPin, kCaptureBufferSize, kTimeout
decode_results results;
//*******************************************************************
//   setup
//*******************************************************************
void setup() {
  Serial.begin(115200);
  Serial.println("");
  irrecv.setUnknownThreshold(12);
  irrecv.enableIRIn();  // Start the receiver
}
loop() {
  if (irrecv.decode(&results)) {
    Serial.println();    // Blank line between entries
    Serial.print(resultToHumanReadableBasic(&results));// Display any extra A/C info if we have it.
    yield();
    String description = IRAcUtils::resultAcToString(&results);
    if (description.length()) Serial.println(D_STR_MESGDESC ": " + description);
    Serial.println(resultToSourceCode(&results));
  }
}

一般遙控器都係用低功率聚焦 LED,但如果想一個固定光源遙控超過一件電器,就要好似一般燈膽一樣散射,需要用到四粒大功率 LED 加一粒可見光LED 串聯一齊砌出 9V 嘅数字,於是電腦輸出嘅 12V 就可以用 L7809三端稳压管降壓,放入鋁燈頭入面。雖然只有幾件零件睇落好似好簡單,但制作過程一啲都唔順利,我試過燒 LED、甩焊、接觸不良、錯電壓、駁錯䤼、寫錯 code、用用吓唔 work。DIY 遠比唔上商品嘅可靠性,所以要串聯一粒可見光 LED 對 debug 同日後方便維修有好大幫助,而且好多時要大材小用以提高耐用性。一般可見光大功率 LED 燈珠其實係藍光 LED 加螢光粉,3W款比 1W款燈珠 mil 数高同高效,都係 3.3V * 300mA = 1W 恒流唔恒壓咁用唔會谷到䀆,即係 1W*3 串聯比 3W*1 更光同高效能。940nm 红外線 LED 灯珠電壓大約 1.3 – 1.5V 之間,比一般 LED 容易燒,所以最好買裏面雙芯款先等同一般 3W LED 燈珠。

4 * 940nm + 1 * color LED with L7809 inside

用駁左電腦 Wifi hotspot 嘅 Wemos D1 R2,加一粒 N-Channel MOSFET IRFS7430 銲喺 DC-007B插座上面就可以輸出 12V 電源訊號到紅外線燈膽。Wemos D1 R2 裏面要起 ESP8266webServer,定好幾多條 URL 就相當於幾多粒制,只要靠 broswer 打某句 URL 就相當於黚制。

#include <ESP8266mDNS.h>
#include <ESP8266WebServer.h>
#include <IRremoteESP8266.h>
#include <IRsend.h>
//*******************************************************************
//   Instantiate class objects, global var and Function Prototypes
//*******************************************************************
IRsend irsend(pin_d8); //9.1V 5W
uint16_t AC_27[451] = { 3372, 1722,  418, 1276,  420, 416,  420, 420,  422, 416,  422, 418,  422, 418,  422, 416,  424, 416,  422, 416,  422, 418,  422, 418,  422, 418,  422, 1276,  422, 416,  422, 418,  420, 420,  422, 418,  422, 416,  422, 418,  422, 418,  422, 1278,  418, 1274,  420, 416,  422, 418,  422, 416,  422, 418,  422, 418,  422, 416,  422, 416,  422, 416,  422, 1276,  420, 418,  422, 1276,  420, 1280,  418, 1276,  420, 1276,  420, 1276,  420, 1276,  420, 418,  422, 1276,  420, 1278,  418, 418,  422, 416,  422, 418,  422, 416,  422, 418,  422, 418,  422, 416,  422, 418,  422, 1278,  418, 1224,  472, 1276,  420, 1276,  420, 1276,  420, 1278,  420, 1278,  418, 1276,  420, 418,  422, 418,  422, 418,  422, 1276,  420, 418,  422, 418,  422, 418,  422, 418,  422, 1278,  416, 418,  422, 416,  422, 1278,  420, 416,  422, 418,  422, 416,  422, 1276,  420, 418,  422, 418,  422, 1278,  420, 416,  422, 418,  422, 418,  422, 416,  424, 416,  422, 418,  422, 1276,  418, 418,  422, 418,  422, 418,  422, 418,  422, 416,  422, 418,  422, 1276,  420, 1276,  420, 416,  422, 1276,  418, 1278,  420, 418,  422, 416,  424, 416,  422, 416,  422, 416,  424, 416,  422, 418,  422, 418,  422, 416,  424, 414,  424, 416,  422, 1278,  420, 416,  422, 416,  424, 418,  422, 416,  422, 418,  422, 416,  424, 416,  424, 416,  422, 418,  422, 418,  422, 418,  422, 418,  422, 416,  422, 416,  424, 416,  422, 418,  422, 416,  422, 418,  422, 418,  424, 416,  422, 418,  422, 416,  422, 418,  422, 418,  422, 418,  422, 416,  424, 416,  422, 418,  422, 418,  422, 416,  422, 418,  422, 416,  422, 418,  422, 418,  422, 418,  422, 418,  422, 418,  422, 1278,  418, 418,  422, 416,  422, 418,  422, 418,  422, 418,  422, 416,  422, 418,  424, 418,  420, 420,  422, 416,  422, 418,  422, 418,  422, 416,  422, 418,  422, 418,  422, 418,  422, 416,  422, 416,  424, 416,  422, 416,  422, 418,  422, 418,  422, 418,  422, 418,  422, 416,  422, 418,  422, 418,  422, 416,  424, 418,  422, 418,  422, 418,  422, 418,  422, 418,  422, 418,  422, 418,  422, 418,  424, 416,  422, 416,  424, 416,  422, 418,  422, 418,  422, 418,  422, 418,  422, 416,  422, 418,  422, 418,  422, 418,  422, 418,  422, 1276,  420, 416,  422, 418,  422, 416,  424, 418,  422, 418,  422, 418,  422, 418,  422, 418,  422, 416,  422, 418,  422, 418,  422, 416,  424, 416,  422, 418,  422, 418,  422, 418,  424, 416,  422, 416,  422, 418,  422, 418,  422, 418,  422, 418,  422, 416,  422, 418,  422, 1276,  418, 1280,  418, 416,  422, 1276,  420, 418,  422, 416,  422, 418,  424 };  // HITACHI_AC
uint16_t AC_28[451] = { 3442, 1648,  490, 1232,  466, 340,  502, 338,  504, 336,  504, 334,  504, 336,  504, 336,  504, 336,  504, 336,  504, 336,  504, 336,  504, 336,  504, 1230,  466, 336,  506, 332,  506, 336,  504, 338,  504, 334,  506, 334,  504, 336,  504, 1230,  466, 1230,  468, 336,  504, 334,  506, 336,  504, 334,  506, 334,  504, 336,  506, 334,  506, 334,  506, 1230,  466, 336,  504, 1230,  466, 1230,  466, 1230,  466, 1232,  464, 1232,  460, 1236,  466, 340,  502, 1230,  464, 1232,  460, 352,  494, 336,  504, 338,  502, 338,  502, 338,  504, 334,  506, 338,  504, 336,  504, 1230,  466, 1232,  466, 1232,  468, 1230,  468, 1230,  466, 1230,  466, 1230,  468, 1230,  468, 334,  506, 336,  504, 334,  504, 1232,  466, 336,  504, 334,  504, 336,  504, 336,  504, 1208,  488, 334,  506, 338,  502, 1230,  468, 332,  506, 334,  504, 336,  504, 1230,  466, 336,  502, 336,  504, 336,  504, 334,  504, 338,  502, 336,  502, 338,  502, 338,  502, 336,  502, 1208,  488, 338,  502, 338,  502, 338,  500, 338,  502, 338,  502, 338,  500, 340,  500, 336,  504, 1208,  488, 1208,  488, 1208,  488, 340,  500, 340,  500, 340,  500, 340,  500, 340,  500, 340,  498, 342,  496, 344,  496, 342,  496, 342,  496, 344,  496, 1210,  486, 342,  496, 346,  494, 348,  492, 348,  492, 348,  492, 348,  490, 352,  488, 350,  490, 348,  490, 354,  486, 354,  488, 352,  488, 350,  488, 354,  486, 354,  484, 358,  484, 354,  482, 360,  484, 354,  484, 358,  482, 358,  480, 364,  478, 360,  478, 362,  478, 364,  476, 362,  452, 406,  434, 406,  434, 406,  450, 378,  444, 406,  434, 406,  434, 406,  430, 410,  430, 408,  432, 408,  432, 408,  430, 1246,  450, 408,  430, 410,  430, 410,  430, 412,  428, 412,  428, 410,  430, 410,  430, 412,  428, 412,  428, 412,  430, 410,  430, 410,  428, 412,  428, 412,  428, 412,  426, 414,  426, 414,  426, 414,  426, 414,  426, 414,  426, 414,  426, 414,  426, 414,  426, 414,  426, 414,  426, 414,  424, 416,  424, 416,  424, 414,  424, 416,  426, 414,  424, 416,  424, 416,  424, 414,  424, 416,  424, 416,  424, 416,  424, 416,  424, 414,  424, 416,  424, 416,  424, 416,  424, 416,  424, 416,  424, 418,  424, 416,  424, 416,  424, 416,  424, 1252,  444, 416,  424, 418,  398, 444,  420, 416,  424, 416,  422, 418,  422, 420,  422, 416,  422, 418,  400, 440,  420, 416,  422, 418,  398, 446,  420, 418,  422, 418,  398, 446,  394, 446,  418, 418,  398, 444,  396, 444,  418, 418,  396, 446,  394, 446,  394, 446,  394, 446,  394, 1278,  416, 1280,  416, 1280,  420, 442,  392, 446,  394, 446,  394 };  // HITACHI_AC
uint16_t AC_29[451] = { 3370, 1722,  418, 1278,  418, 416,  424, 418,  422, 416,  424, 416,  424, 416,  424, 416,  424, 418,  422, 416,  422, 416,  424, 416,  422, 418,  426, 1274,  418, 416,  424, 418,  424, 416,  422, 418,  422, 418,  422, 416,  424, 416,  424, 1278,  418, 1278,  420, 416,  424, 416,  422, 416,  422, 418,  422, 416,  424, 418,  424, 416,  422, 416,  424, 1276,  420, 416,  422, 1278,  420, 1276,  420, 1276,  420, 1274,  422, 1276,  418, 1278,  420, 418,  424, 1276,  420, 1274,  422, 418,  422, 418,  422, 418,  424, 416,  422, 418,  422, 418,  422, 416,  422, 418,  422, 1278,  420, 1278,  418, 1276,  420, 1278,  418, 1276,  420, 1278,  420, 1278,  420, 1276,  420, 418,  422, 416,  422, 418,  422, 1278,  418, 418,  422, 418,  422, 418,  422, 416,  424, 1278,  418, 418,  424, 416,  424, 1276,  422, 416,  424, 416,  424, 416,  424, 416,  422, 418,  422, 416,  422, 1276,  420, 416,  424, 418,  422, 416,  424, 418,  422, 418,  422, 418,  422, 1276,  420, 418,  422, 416,  424, 416,  422, 416,  424, 416,  424, 416,  424, 1276,  420, 416,  422, 1278,  418, 1276,  420, 1278,  420, 418,  422, 416,  424, 416,  422, 418,  422, 418,  422, 416,  422, 418,  422, 416,  424, 418,  422, 418,  422, 418,  422, 1278,  418, 418,  422, 416,  422, 418,  422, 418,  422, 418,  424, 416,  422, 418,  422, 416,  424, 416,  422, 416,  422, 418,  422, 416,  422, 418,  422, 416,  422, 416,  424, 416,  422, 418,  422, 416,  424, 416,  422, 416,  422, 416,  422, 418,  422, 418,  422, 418,  422, 416,  422, 418,  422, 416,  422, 418,  422, 416,  422, 418,  422, 416,  424, 416,  422, 418,  422, 418,  422, 418,  422, 418,  422, 416,  422, 1276,  420, 418,  422, 418,  422, 418,  422, 418,  422, 418,  422, 418,  422, 418,  424, 416,  422, 418,  422, 418,  422, 416,  424, 416,  424, 416,  422, 416,  424, 418,  422, 418,  422, 416,  424, 416,  424, 418,  424, 416,  424, 416,  424, 416,  424, 418,  422, 418,  420, 418,  422, 418,  422, 418,  422, 416,  424, 416,  422, 420,  422, 416,  422, 418,  422, 418,  424, 416,  424, 416,  422, 418,  422, 418,  422, 418,  422, 416,  424, 416,  422, 418,  422, 418,  422, 416,  424, 416,  422, 416,  424, 418,  422, 416,  424, 418,  422, 1278,  418, 418,  424, 416,  422, 416,  424, 416,  426, 414,  424, 418,  422, 418,  422, 418,  422, 416,  422, 418,  422, 416,  420, 420,  422, 416,  424, 418,  422, 418,  422, 418,  422, 416,  422, 418,  422, 418,  422, 418,  422, 416,  422, 418,  422, 418,  422, 1278,  418, 1302,  392, 420,  422, 416,  422, 1300,  394, 420,  420, 420,  422, 418,  424 };  // HITACHI_AC
uint16_t AC_30[451] = { 3370, 1714,  424, 1270,  424, 410,  428, 412,  426, 412,  428, 410,  430, 410,  428, 410,  430, 412,  428, 408,  430, 410,  428, 412,  430, 410,  428, 1272,  424, 410,  430, 410,  430, 410,  456, 366,  448, 408,  430, 412,  430, 408,  428, 1272,  422, 1272,  426, 410,  430, 408,  430, 412,  428, 408,  432, 408,  430, 406,  434, 406,  428, 412,  430, 1270,  424, 410,  430, 1270,  426, 1270,  426, 1270,  424, 1270,  426, 1272,  426, 1270,  424, 410,  432, 1270,  424, 1268,  424, 412,  456, 366,  446, 408,  430, 408,  432, 410,  466, 344,  460, 408,  432, 404,  434, 1266,  424, 1274,  426, 1270,  428, 1268,  426, 1268,  428, 1268,  426, 1270,  426, 1268,  430, 404,  434, 408,  428, 410,  432, 1268,  426, 410,  428, 406,  432, 410,  432, 406,  432, 1266,  426, 412,  456, 366,  446, 1266,  428, 408,  430, 408,  430, 412,  428, 412,  426, 408,  430, 410,  428, 1270,  426, 408,  432, 408,  428, 412,  428, 410,  430, 410,  426, 412,  428, 1268,  426, 406,  434, 404,  432, 410,  430, 410,  428, 410,  430, 410,  428, 412,  428, 1270,  452, 1244,  424, 1270,  426, 1268,  426, 410,  430, 410,  428, 410,  426, 410,  428, 410,  430, 408,  428, 412,  428, 410,  428, 410,  430, 408,  430, 440,  400, 1270,  424, 412,  428, 406,  430, 410,  430, 408,  430, 412,  426, 408,  430, 412,  436, 396,  434, 408,  432, 410,  436, 400,  428, 410,  430, 410,  430, 410,  456, 364,  450, 436,  400, 412,  452, 370,  446, 406,  432, 438,  400, 410,  454, 370,  442, 408,  432, 406,  456, 408,  430, 368,  448, 436,  402, 436,  402, 406,  432, 406,  458, 366,  448, 404,  456, 372,  468, 364,  474, 364,  474, 366,  472, 370,  472, 1242,  452, 368,  472, 366,  446, 406,  434, 406,  456, 368,  458, 386,  462, 372,  470, 368,  474, 358,  478, 366,  472, 408,  406, 410,  456, 368,  472, 362,  476, 360,  480, 362,  474, 362,  452, 406,  434, 404,  460, 364,  474, 364,  474, 368,  446, 406,  456, 366,  448, 408,  458, 364,  474, 366,  450, 406,  432, 406,  456, 366,  450, 404,  434, 406,  458, 368,  470, 366,  448, 404,  434, 408,  432, 406,  458, 366,  472, 368,  446, 410,  430, 408,  456, 368,  444, 408,  432, 408,  432, 406,  430, 412,  426, 412,  430, 408,  430, 1268,  424, 412,  428, 410,  430, 412,  426, 412,  428, 412,  428, 412,  428, 412,  426, 412,  428, 410,  430, 412,  424, 414,  426, 412,  426, 412,  426, 412,  426, 416,  424, 414,  424, 414,  424, 414,  424, 416,  424, 414,  424, 414,  426, 416,  398, 442,  420, 1278,  418, 416,  422, 416,  422, 420,  396, 1302,  394, 444,  396, 444,  396, 442,  396 };  // HITACHI_AC
uint16_t AC_off[451] = { 3372, 1722,  418, 1280,  418, 418,  422, 418,  422, 418,  422, 416,  422, 418,  422, 418,  422, 418,  422, 418,  422, 418,  422, 418,  424, 418,  422, 1276,  420, 418,  422, 418,  422, 418,  422, 418,  422, 418,  422, 416,  422, 418,  422, 1278,  420, 1280,  416, 418,  424, 416,  422, 418,  422, 418,  422, 416,  422, 418,  422, 416,  422, 418,  422, 1278,  420, 418,  422, 1278,  418, 1276,  422, 1278,  420, 1276,  420, 1276,  420, 1278,  418, 418,  422, 1278,  418, 1278,  420, 418,  422, 418,  422, 418,  422, 418,  422, 418,  422, 418,  422, 418,  422, 418,  422, 1278,  418, 1280,  416, 1278,  418, 1278,  418, 1278,  420, 1276,  420, 1278,  418, 1280,  418, 418,  422, 418,  422, 418,  422, 1278,  420, 416,  422, 418,  424, 416,  422, 416,  422, 1278,  418, 418,  422, 418,  420, 1280,  418, 418,  422, 418,  422, 416,  422, 420,  426, 1274,  420, 416,  424, 416,  422, 416,  424, 418,  422, 418,  422, 418,  422, 416,  422, 418,  422, 1278,  420, 416,  422, 418,  422, 418,  424, 416,  422, 418,  422, 416,  424, 418,  422, 418,  422, 1278,  418, 1278,  418, 1280,  416, 416,  422, 418,  422, 418,  422, 418,  422, 418,  422, 416,  424, 418,  422, 418,  422, 418,  422, 418,  422, 418,  422, 1278,  418, 418,  424, 416,  422, 418,  422, 418,  422, 418,  422, 416,  424, 418,  422, 418,  422, 416,  424, 418,  422, 418,  422, 418,  422, 418,  422, 418,  422, 416,  424, 416,  424, 416,  422, 418,  422, 418,  422, 418,  422, 416,  422, 418,  422, 416,  422, 416,  422, 418,  422, 418,  422, 418,  422, 418,  424, 416,  422, 418,  422, 418,  422, 416,  422, 418,  422, 416,  422, 418,  422, 416,  424, 418,  422, 416,  420, 418,  422, 416,  422, 418,  422, 416,  422, 418,  422, 418,  422, 416,  424, 416,  422, 418,  422, 418,  422, 418,  422, 420,  422, 416,  422, 418,  422, 418,  422, 418,  422, 418,  422, 418,  422, 418,  422, 416,  424, 418,  422, 418,  422, 418,  422, 416,  422, 418,  422, 418,  422, 418,  424, 416,  422, 418,  422, 418,  424, 416,  422, 416,  422, 418,  422, 418,  424, 416,  422, 418,  422, 416,  424, 418,  422, 416,  424, 416,  422, 418,  424, 416,  424, 416,  424, 418,  422, 416,  424, 416,  422, 416,  424, 418,  422, 1280,  416, 418,  422, 416,  422, 418,  422, 418,  422, 416,  424, 418,  422, 416,  424, 416,  424, 418,  422, 416,  422, 416,  424, 416,  422, 418,  422, 416,  422, 418,  422, 416,  422, 416,  424, 416,  422, 416,  424, 418,  422, 418,  422, 416,  424, 418,  422, 1276,  420, 1280,  414, 420,  422, 1280,  416, 1302,  394, 418,  422, 416,  424, 1278,  416 };  // HITACHI_AC
//*******************************************************************
//   setup
//*******************************************************************
void setup() {
  analogWriteFreq(38000); // IRremote
  irsend.begin();
  //analogWrite(pin_d8, 255);
  ...
  server.on("/tv1", []() {irsend.sendNEC(0xFF9A65);server.send(204);});
  server.on("/tv2", []() {irsend.sendNEC(0xFF6897);server.send(204);});
  server.on("/tv3", []() {irsend.sendNEC(0xFF609F);server.send(204);});
  server.on("/ac1", []() {irsend.sendRaw(AC_27, 451, 38);server.send(204);});
  server.on("/ac2", []() {irsend.sendRaw(AC_28, 451, 38);server.send(204);});
  server.on("/ac3", []() {irsend.sendRaw(AC_29, 451, 38);server.send(204);});
  server.on("/ac4", []() {irsend.sendRaw(AC_30, 451, 38);server.send(204);});
  server.on("/ac0", []() {irsend.sendRaw(AC_off, 451, 38);server.send(204);});
}

問題在於 request 一句 URL 會造成黚幾吓制,所以要用 Http PUT 而唔係 GET,相當於 form submit 嘅效果避免 multi click。一般 form submit 係 reload page,之後會清晒之前喺 form 入啲 data;為左唔想 reload 又可以 send request 出去,就要用到相當流行嘅 XMLHttpRequest,即係 AJAX 一部份需要用到 javascript。jQuery 可以簡化 AJAX 部份,同以 query 嘅形式簡化 javascript 揾 component 嘅 command,例如 $("#btn_tv1");因為 PHP 又用 $ 造 variable 茗,所以最好寫番全寫 jQuery("#btn_tv1"),一開頭加上 jQuery.noConflict();

/********************************************************************
  setup
 ********************************************************************/
'use strict';
jQuery.noConflict();

/********************************************************************
  document ready
 ********************************************************************/

jQuery(function () {
    jQuery("#btn_tv1").on("click", function () { fn_ajax_put('http://wemos-send.local/tv1') });
    jQuery("#btn_tv2").on("click", function () { fn_ajax_put('http://wemos-send.local/tv2') });
    jQuery("#btn_tv3").on("click", function () { fn_ajax_put('http://wemos-send.local/tv3') });
    jQuery("#btn_ac0").on("click", function () { fn_ajax_put('http://wemos-send.local/ac0') });
    jQuery("#btn_ac1").on("click", function () { fn_ajax_put('http://wemos-send.local/ac1') });
    jQuery("#btn_ac2").on("click", function () { fn_ajax_put('http://wemos-send.local/ac2') });
    jQuery("#btn_ac3").on("click", function () { fn_ajax_put('http://wemos-send.local/ac3') });
    jQuery("#btn_ac4").on("click", function () { fn_ajax_put('http://wemos-send.local/ac4') });
});//end document ready

/********************************************************************
  function
 ********************************************************************/
function fn_ajax_put(URL) {
    jQuery.ajax({
        url: URL,
        type: 'PUT'
    });
}

Reference: