
Amazon Echo Dot(第3世代)とESPr Developerでシャープのアクオスをあやつる。
【はじめのはじめ】
はんだごて持って、みんなで作りましょうよ!
もし分からないところがあれば、コメント欄にご記入ください。出来る限り、対応します。。。
【はじめに】
Amazon Echo Dot単体では、赤外線送信の機能がありません。よって、テレビのリモコンみたいに使いたければ別途、赤外線が送信できるスマートリモコンを導入しなければなりません。このスマートリモコンは5,000円ぐらいからあります。Echo dotも約6,000円しますので、ここでの11,000円ぐらいの出費は痛いものがあります。(たまにEcho自体のセールをやるときがありますが)もっと、機能限定されてもいいから、安価にできないかな?と思いついたのが、マイコンをであるこのESPr Developperを使った自作リモコンです。このボードは1つ約2,000円ですが、プログラム次第では何とでもコントロールできてしまいます。ちょっと本当にできるか実験したいと思います。もちろん、色々なサイトでこのような事をされている方がおられます。真似をしてみましたが、ことごとく失敗に終わってます。2世代目のEcho dotだったら上手く出来たかもしれませんが。。。
もちろん、このnote無料ですが。。。サポート頂けると幸いです。
【主に準備したモノ】
➀Amazon Echo Dot
②ESPr Developper
③赤外線LEDと抵抗
その他、電線、ハンダ、ブレッドボードなどが必要です。
【ハードウエア】
一応、下図のような感じの回路でOKです。
写真でいうとデジタルIOの4番にLEDの+を、その右にLEDのーを。LEDによって違いますが、このLEDの場合、33Ωの抵抗をかませてあります。この抵抗がないとLEDは死んでしまいます。ハードウエアはこれで完成です。簡単なんです。ここまでは。パソコンとUSBでつないじゃいます。
ハードウエアは、最終的にはこのような形になりました。
【ソフトウエア】
◎少なくとも、ここまではわかっています。
まず、このAmazon Echo Dotと、ESPr Developperで、Belkin WeMo 家庭用電源リモートスイッチをマイコンの中に作って、自由にON/OFF制御をする。→これリモコンに活用できるじゃん。ていうことになります。
ちなみに、Amazon Echo Dot(第3世代)とesp8266-alexa-wemo-emulatorとは相性が悪いみたいで、サーバーが応答しないとかエラーとかで使えません。そこで、fauxmoesp を使う事にしました。ソースもここ(https://bitbucket.org/xoseperez/fauxmoesp)から引用してモデファイしております。これも、一癖あって、赤外線LEDをコントロールするためのライブラリであるIRremoteが使えません。別途、IRremoteに代わるものを作らないといけません。(ヒントあれば教えてください)
あと、うちのテレビ、シャープの古いアクオスですが、リモコンが発信するデータを事前に取っておきました。(公表しちゃっていいのかどうか..)このデータを吸い出す方法は、ググれば出てきます。検索ワードは「echo esp8266 スマートホーム リモコン テレビ」です。
ちなみに、吸いだしたデータとしては、下記になります。
btn_電源 0x555AF148688B
btn_消音 0x555AF148E883
btn_1 0x555AF148724C
btn_2 0x555AF148F244
btn_3 0x555AF1480A43
btn_4 0x555AF1488A4B
btn_5 0x555AF1484A47
btn_6 0x555AF148CA4F
btn_7 0x555AF1482A41
btn_8 0x555AF148AA49
btn_9 0x555AF1486A45
btn_10 0x555AF148EA4D
btn_11 0x555AF1481A42
btn_12 0x555AF1489A4A
btn_地デジ 0x555AF1489141
btn_BS 0x555AF148514D
btn_CS 0x555AF148D145
btn_d 0x555AF1487A44
btn_Vol_up 0x555AF148288F
btn_Vol_down 0x555AF148A887
btn_チャンネル_up 0x555AF1488885
btn_チャンネル_down 0x555AF1484889
btn_入力切替 0x555AF148C881
btn_番組表 0x555AF148064F
btn_裏番組 0x555AF148AE4D
btn_番組情報 0x555AF148FA4C
btn_↑ 0x555AF148EA81
btn_↓ 0x555AF1480481
btn_← 0x555AF148EB80
btn_→ 0x555AF1481B8F
btn_終了 0x555AF148AF80
btn_戻る 0x555AF1482780
btn_青 0x555AF1480148
btn_赤 0x555AF1488140
btn_緑 0x555AF148414C
btn_黄 0x555AF148C144
マイコンをプログラミングし、このデータを送信することによって、リモコンとして動作させます。
このマイコンにやらせたい事を大まかにプログラミングしました。さて、次に赤外線送出の所のプログラミングを始めます。「赤外線リモコンの通信フォーマット」を参考させていただきます。果たしてプログラミングできるかがキモになります。ちなみに、シャープは家製協(AEHA)フォーマットです。
そのソースは、こちら。一応、色々盛り込みました。。キタナイソースですが。下記ソース中のFire_tv()、Blu_ray()の中身は、空白にしてあります。これは、どの機器が、どのHDMI端子に刺さってるかによりかわるので。
静岡県に合わせてますので、地デジチャンネルのところの関数名も、その地域に合わせて変えて使ってください。CSは家では観てないので、そこらへんもカットしてあります。プログラム中のスイッチを増設して、割り当ててみてください。
/// リビングのテレビリモコン for SHARP LC-37GX2W(古っ)
/// Amaon Dot Echo でコントロールしてみよう。
/// AEHAフォーマットです。
#include <Arduino.h>
#include <ESP8266WiFi.h>
#include "fauxmoESP.h"
#define SERIAL_BAUDRATE 115200
#define IR_LED 4
#define LED 3
#define delay_time 250
const unsigned long T = 425;
fauxmoESP fauxmo;
char ssid[] = "xxxxx"; //WIFIのSSIDを入力してください
char password[] = "xxxxxx"; //そのSSIDに対するパスワードを入力してください。
char btn_sw[] = "555AF148688B";
char btn_mute[] = "555AF148E883";
char btn_1[] = "555AF148724C";
char btn_2[] = "555AF148F244";
char btn_3[] = "555AF1480A43";
char btn_4[] = "555AF1488A4B";
char btn_5[] = "555AF1484A47";
char btn_6[] = "555AF148CA4F";
char btn_7[] = "555AF1482A41";
char btn_8[] = "555AF148AA49";
char btn_9[] = "555AF1486A45";
char btn_10[] = "555AF148EA4D";
char btn_11[] = "555AF1481A42";
char btn_12[] = "555AF1489A4A";
char btn_Digital[] = "555AF1489141";
char btn_BS[] = "555AF148514D";
char btn_CS[] = "555AF148D145";
char btn_d[] = "555AF1487A44";
char btn_Vol_up[] = "555AF148288F";
char btn_Vol_down[] = "555AF148A887";
char btn_ch_select_up[] = "555AF1488885";
char btn_select_down[] = "555AF1484889";
char btn_input_selector[] = "555AF148C881";
char btn_timetable[] = "555AF148064F";
char btn_urabangumi[] = "555AF148AE4D";
char btn_information[] = "555AF148FA4C";
char btn_up[] = "555AF148EA81";
char btn_down[] = "555AF1480481";
char btn_left[] = "555AF148EB80";
char btn_right[] = "555AF1481B8F";
char btn_exit[] = "555AF148AF80";
char btn_return[] = "555AF1482780";
char btn_blue[] = "555AF1480148";
char btn_red[] = "555AF1488140";
char btn_green[] = "555AF148414C";
char btn_yellow[] = "555AF148C144";
char bin[16][5] = {
"0000", "0001", "0010", "0011",
"0100", "0101", "0110", "0111",
"1000", "1001", "1010", "1011",
"1100", "1101", "1110", "1111"
};
void power_sw();
void mute();
void vol_up();
void vol_down();
void vol_up_more();
void vol_down_more();
void Fire_tv();
void Blu_ray();
void blue();
void red();
void green();
void yellow();
void d_sw();
void NHK();
void NHK_E();
void daiichi();
void asahi();
void SBS();
void tereshizu();
void BS1();
void BS_Premium();
void BS_nittere();
void BS_asahi();
void BS_TBS();
void BS_teretou();
void BS_FUJI();
void BS_11();
void BS_12();
void timetable();
void ir_send();
void sub_carrier();
void wait();
void leader();
void trailer();
void transmit_IR();
// -----------------------------------------------------------------------------
// Wifi
// -----------------------------------------------------------------------------
void wifiSetup() {
// Set WIFI module to STA mode
WiFi.mode(WIFI_STA);
// Connect
Serial.printf("[WIFI] Connecting to %s ", ssid);
WiFi.begin(ssid, password);
// Wait
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(100);
}
Serial.println();
// Connected!
Serial.printf("[WIFI] STATION Mode, SSID: %s, IP address: %s\n", WiFi.SSID().c_str(), WiFi.localIP().toString().c_str());
}
void setup() {
// Init serial port and clean garbage
Serial.begin(SERIAL_BAUDRATE);
Serial.println();
Serial.println();
// Wifi
wifiSetup();
// status
pinMode(LED, OUTPUT);
digitalWrite(LED, HIGH);
pinMode(IR_LED, OUTPUT);
digitalWrite(IR_LED, LOW);
// You have to call enable(true) once you have a WiFi connection
// You can enable or disable the library at any moment
// Disabling it will prevent the devices from being discovered and switched
fauxmo.enable(true);
// Add virtual devices
fauxmo.addDevice("LVTV00"); // 0
fauxmo.addDevice("LVTV01"); // 1
fauxmo.addDevice("LVTV02"); // 2
fauxmo.addDevice("LVTV03"); // 3
fauxmo.addDevice("LVTV04"); // 4
fauxmo.addDevice("LVTV05"); // 5
fauxmo.addDevice("LVTV06"); // 6
fauxmo.addDevice("LVTV07"); // 7
fauxmo.addDevice("LVTV08"); // 8
fauxmo.addDevice("LVTV09"); // 9
fauxmo.addDevice("LVTV10"); // 10
fauxmo.addDevice("LVTV11"); // 11
fauxmo.addDevice("LVTV12"); // 12
fauxmo.addDevice("LVTV13"); // 13
fauxmo.addDevice("LVTV14"); // 14
fauxmo.addDevice("LVTV15"); // 15
//
// fauxmoESP 2.0.0 has changed the callback signature to add the device_id,
// this way it's easier to match devices to action without having to compare strings.
fauxmo.onSetState([](unsigned char device_id, const char * device_name, bool state) {
int id;
Serial.printf("[MAIN] Device #%d (%s) state: %s\n", device_id, device_name, state ? "ON" : "OFF");
Serial.printf("id:%s\n", device_name);
if (device_id == 0)
{
state ? power_sw() : mute();
}
else if (device_id ==1)
{
state ? vol_up() : vol_down();
}
else if (device_id == 2) {
state ? vol_up_more() : vol_down_more();
}
else if (device_id == 3) {
state ? Fire_tv() : Blu_ray();
}
else if (device_id == 4) {
state ? blue() : red();
}
else if (device_id == 5) {
state ? green() : yellow();
}
else if (device_id == 6) {
state ? d_sw() : timetable();
}
else if (device_id == 7) {
state ? NHK() : NHK_E();
}
else if (device_id == 8) {
state ? daiichi() : asahi();
}
else if (device_id == 9) {
state ? SBS() : tereshizu();
}
else if (device_id == 10) {
state ? BS1() : BS_Premium();
}
else if (device_id == 11) {
state ? BS_nittere() : BS_asahi();
}
else if (device_id == 12) {
state ? BS_TBS() : BS_teretou();
}
else if (device_id ==13) {
state ? BS_FUJI() : BS_11();
}
else if (device_id ==14) {
BS_12();
}
else {
}
digitalWrite(LED, state);
});
// Callback to retrieve current state (for GetBinaryState queries)
fauxmo.onGetState([](unsigned char device_id, const char * device_name) {
return digitalRead(LED);
});
}
}
void loop() {
// Since fauxmoESP 2.0 the library uses the "compatibility" mode by
// default, this means that it uses WiFiUdp class instead of AsyncUDP.
// The later requires the Arduino Core for ESP8266 staging version
// whilst the former works fine with current stable 2.3.0 version.
// But, since it's not "async" anymore we have to manually poll for UDP
// packets
fauxmo.handle();
//static unsigned long last = millis();
//if (millis() - last > 5000) {
// last = millis();
// Serial.printf("[MAIN] Free heap: %d bytes\n", ESP.getFreeHeap());
//}
}
void power_sw() {
wait(1000000);
ir_send(btn_sw);
}
void mute() {
ir_send(btn_mute);
}
void vol_up() {
ir_send(btn_Vol_up);
}
void vol_down() {
ir_send(btn_Vol_down);
}
void vol_up_more() {
ir_send(btn_Vol_up);
wait(250000);
ir_send(btn_Vol_up);
wait(250000);
ir_send(btn_Vol_up);
wait(250000);
ir_send(btn_Vol_up);
wait(250000);
ir_send(btn_Vol_up);
}
void vol_down_more() {
ir_send(btn_Vol_down);
wait(250000);
ir_send(btn_Vol_down);
wait(250000);
ir_send(btn_Vol_down);
wait(250000);
ir_send(btn_Vol_down);
wait(250000);
ir_send(btn_Vol_down);
}
void Fire_tv() {
}
void Blu_ray() {
}
void blue() {
ir_send(btn_blue);
}
void red() {
ir_send(btn_red);
}
void green() {
ir_send(btn_green);
}
void yellow() {
ir_send(btn_yellow);
}
void d_sw() {
ir_send(btn_d);
}
void timetable() {
ir_send(btn_timetable);
}
//地デジチャンネル
void NHK() {
ir_send(btn_Digital);
wait(250000);
ir_send(btn_1);
}
void NHK_E() {
ir_send(btn_Digital);
wait(250000);
ir_send(btn_2);
}
void daiichi() {
ir_send(btn_Digital);
wait(250000);
ir_send(btn_4);
}
void asahi() {
ir_send(btn_Digital);
ir_send(btn_5);
}
void SBS() {
ir_send(btn_Digital);
wait(250000);
ir_send(btn_6);
}
void tereshizu() {
ir_send(btn_Digital);
wait(250000);
ir_send(btn_8);
}
//BSチャンネル
void BS1() {
ir_send(btn_BS);
wait(250000);
ir_send(btn_1);
}
void BS_Premium() {
ir_send(btn_BS);
wait(250000);
ir_send(btn_3);
}
void BS_nittere() {
ir_send(btn_BS);
wait(250000);
ir_send(btn_4);
}
void BS_asahi() {
ir_send(btn_BS);
wait(250000);
ir_send(btn_5);
}
void BS_TBS() {
ir_send(btn_BS);
wait(250000);
ir_send(btn_6);
}
void BS_teretou() {
ir_send(btn_BS);
wait(250000);
ir_send(btn_7);
}
void BS_FUJI() {
ir_send(btn_BS);
wait(250000);
ir_send(btn_8);
}
void BS_11() {
ir_send(btn_BS);
wait(250000);
ir_send(btn_11);
}
void BS_12() {
ir_send(btn_BS);
wait(250000);
ir_send(btn_12);
}
void ir_send(char *raw_data) {
unsigned int i;
unsigned int rawdata_length;
char ir_send_data[rawdata_length];
rawdata_length = strlen(raw_data);
char s[2];
leader();
for (i = 0; i < rawdata_length; i++) {
sprintf(s, "%c", raw_data[i]);
sub_carrier(bin[strtol(s, NULL, 16)]);
}
trailer();
}
void sub_carrier(char *data) {
int i, j, d;
unsigned long now;
for (i = 0; i < 4; i++)
{
d = data[i] - 48;
for (j = 0; j < 15; j++) {
transmit_IR();
}
d ? wait(3 * T) : wait(T);
}
}
void leader()
{
unsigned long now;
now = micros();
while (micros() - now < 8 * T + 200)
{
transmit_IR();
}
wait(4 * T);
}
void trailer()
{
int j;
for (j = 0; j < 15; j++) {
transmit_IR();
}
}
void wait(unsigned long wait_time)
{
unsigned long start_time = micros();
while ((4294967295 - start_time) <= (unsigned long)(wait_time * 1.01))
{
delay(1);
}
while (micros() - start_time < wait_time) {
delay(1);
}
}
void transmit_IR() {
digitalWrite(IR_LED, HIGH);
wait(8);
digitalWrite(IR_LED, LOW);
wait(17);
}
ちなみに、下のスクショは、コンパイル条件です。
今度は、NECフォーマットを仕込みにかかります。
とりあえず、以上です。