2018年2月24日土曜日

Raspberry pi zero Wでgoogle-home-notifier

2021/11/22追記 現在はGoogleHome側の仕様変更により、下記の方法ではうまく動かないようです。


GoogleHomeにしゃべらせたくてラズベリーパイ ( Raspberry pi zero W ) を買いました。

ラズパイもnode.jsも触ったことがありませんが、有益なことを公開してくださっている皆様の情報をたよりに進めます。

私は中身が何もわかってないので以下の情報は間違っているかもしれません。

(1) Raspberry pi zero Wのセットアップ
(2) google-home-notifierのセットアップ
(3)外部からRaspberry piにリクエストを送ってGoogleHomeがしゃべる


@mascii様の
Raspberry PiにNode.jsとnpmの最新版をインストールする
を参考にnode.jsのセットアップしました。
以下引用:
sudo apt-get update
sudo apt-get install -y nodejs npm
sudo npm cache clean
sudo npm install npm n -g
sudo n stable

@ktetsuo
Raspberry PiからGoogle Homeを喋らせる
を参考にgoogle-home-notifierをセットアップしました。
以下引用:
sudo apt-get install libavahi-compat-libdnssd-dev
npm install google-home-notifier

しゃべるだけなら下記を実行すればしゃべります。簡単すぎてビックリします。
以下引用
ファイル名:main2.js
const googlehome = require('google-home-notifier');
const language = 'ja';
googlehome.device("Google-Home", language);
googlehome.ip("192.168.xxx.xxx");
googlehome.notify('こんにちは。私はグーグルホームです。', function(res) {
  console.log(res);
});

node main2.js (パスは適宜追加してください)

次は
次に下記のファイルを編集して
/home/(ユーザー名)/node_modules/google-home-notifier/example.js

以下引用:
ファイル名:example.js
(略)
var ip = '192.168.1.10'; // default IP      //ここにIPを記載
(略)
  var language = 'ja'; // default language code   //ここに「ja」を記載
  if (req.query.language) {
    language;
  }
(略)
  if (req.query.ip) {
     ip = req.query.ip;
  }
  var language = 'ja'; // default language code     //ここに「ja」を記載
  if (req.query.language) {
    language;
  }
(略)

下記で実行
node /home/(ユーザー名)/node_modules/google-home-notifier/example.js

/etc/rc.localに下記を追記すると電源をオフにしても自動で起動します。
forever start /home/(ユーザー名)/node_modules/google-home-notifier/example.js

ラズベリーパイ上のコンソールから

curl -X POST -d "text=テスト" http://(RaspberryPiのIP):(ポート番号)/google-home-notifier

でしゃべると思います。

esp32からでも
下記のスケッチで無事しゃべりました。

#include
#include

const char* ssid     = "(SSID)";
const char* password = "(パスワード)";
const char URL[] = "http://(ラズパイのID):(ポート番号)/google-home-notifier";
WiFiServer server(80);

void setup()
{
    Serial.begin(115200);
    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }
    server.begin();
}

void loop() {
  HTTPClient http;
  http.begin(URL);
  String requestBody = "text=テストです";
  http.addHeader("Content-Type", "application/x-www-form-urlencoded");
  int httpCode = http.POST(requestBody);

  Serial.printf("Response: %d", httpCode);
  Serial.println();
  if (httpCode == HTTP_CODE_OK) {
    String body = http.getString();
    Serial.print("Response Body: ");
    Serial.println(body);
  }

  delay(10000);
}


上記のやり方でなくても、Raspberry piとGoogle homeをBluetoothで接続してBluetoothスピーカとして鳴らすという手段もあると思います。
(スマホからは普通にBluetoothスピーカとしてGoogle homeに音を出せました。)


2018年2月18日日曜日

Google homeとESP32+Blynkで家電制御

Google Homeを購入しました。

【2021/11/22追記】
現在は赤外線リモコンやUSBのon/offは行っていません。
リモコンはラトックシステムの家電リモコンを使っています。
ESP32はシャッターと給湯の制御のみに使用しています。
Wi-fiが切れたときに再接続できずオフラインのままになる対策を入れました。(下のほう参照)

ESP32やM5シリーズを使う場合、GoogleHomeで使おうとするとBlynkやIFTTTを使わないといけませんが、アレクサなら単体でデバイスとして認識するらしいのでアレクサと組み合わせたほうが良いみたいです。いつかアレクサを買ったらまたいろいろやってみたいです。

【2021/5/19 追記】
IFTTTが3つまでしか使えなくなってしまったため、現在は大幅に構成を見直しました。
また機会があれば記事を書きたいと思います。

やったこと
・赤外線リモコンによる家電の操作 (照明、エアコン、TVの操作)
・USB機器(ドライブレコーダ)の電源ON/OFF
・HA機器(電動シャッター、エコキュート)の制御(JEM-A端子)
・スマートコンセントによる100V機器のオン/オフ (ホットカーペット、ゲーム機)

使ったもの
・Google Home mini
・ESP32-DevkitC (ESP-WROOM-32)
 今回の用途の場合、Wi-Fi内蔵のArduinoと考えて問題ありません。
しかも今回の用途の場合、前モデルのESP-WROOM-02 (ESP8266)をつかった方が赤外線送受信ライブラリ等がそろっていて便利です。

・IFTTT Google Homeと連携するwebサービスです
・Blynk Arduinoをスマホから操作するwebサービスです


セットアップ関係についてはmgo-tec様で詳細に説明されているので、特に説明することはないです。

「mgo-tec電子工作」
Google Home Mini を使って、声で ESP32 の LED を光らせてみた
https://www.mgo-tec.com/blog-entry-esp32-googlehome-ifttt-webhooks-blynk.html


回路図は以下の通り。動作を保証するものではありません。あくまでも自己責任で。

赤外線リモコンの方は、webを調べるとLEDの電圧ドロップを1.2Vとしているものがたくさん出てきますが、SE303A-Cという赤外線LEDのデータシートによると、定格1.25V@50mA、パルス2.1V@1.0Aとなっていますので、今回使った赤外LEDがどうかは知りませんが、パルスで大電流を流した時はもっと電圧ドロップが大きくなるようです。
今回は適当に設定してしまいました。
メモ書きが間違っていて、ESP32-DevkitCの5V端子はUSB電源からダイオードで電圧ドロップしてから出てきているので4.5V程度、想定電流が0.7Aだと、抵抗で2.3V、LEDで1.9V、Trで0.3Vくらい。
書き忘れましたが、パルス電流の供給用に5Vの端子とGNDの間に10uFの電解コンデンサを入れています。電荷が足りているかの検討は全くしていません。無責任で申し訳ない。

赤外線の送受信は下記のサイトを参考に信号をキャプチャしました。
送信もほぼ下記サイトそのままですが、delayMicrosecondsの値が7と8だと、エアコン以外が動作しませんでした。9と17に変更することで照明も動作するようになりましたが、TVは動作しません。38kHzになってないのだと思います。

「ソースに絡まるエスカルゴ」
http://rikoubou.hatenablog.com/entry/2017/06/12/142227


USB機器のオン/オフは参考にできるサイトが探せず、適当に作ってしまいました。
電圧がギリギリですし、GND電位が浮くので注意が必要です。
p-chのMOSか何かを使った方が良いように思います。

赤外線送受信とカメラのオン/オフのスケッチ(メモ書きの1号のほう)は下記になりました。
==========================
#define BLYNK_PRINT Serial
#include
#include
#include

char auth[] = "(Blynkから送られてきたメール内にある Auth コード)";
char ssid[] = "(ご自宅のWi-FiのSSID)";
char pass[] = "(ご自宅のWi-Fiのパスワード)";

// 送信データ
unsigned int TVon[] = {(キャプチャした赤外線のコード)};
unsigned int TVof[] =  {(キャプチャした赤外線のコード)};

・(以下好きなだけ列挙)


const int IR_SEND_PIN = 33; // 赤外線LEDのピン
const int LED1_PIN = 27;

void setup()
{
    Serial.begin(115200);
  pinMode(IR_SEND_PIN, OUTPUT);
  pinMode(LED1_PIN, OUTPUT);
    delay(10);

    // We start by connecting to a WiFi network

    Serial.println();
    Serial.println();
    Serial.print("Connecting to ");
    Serial.println(ssid);

  Blynk.begin(auth, ssid, pass);

//  sigmaDeltaSetup(0, 312500);
//  sigmaDeltaAttachPin(LED_pin, 0);
//  sigmaDeltaWrite(0, 0); // LED OFF ( level 0 )
}

int value = 0;

void loop(){
    Blynk.run();
}

// dataの赤外線信号を送信
void sendSignalP(unsigned int dataP[], unsigned int dataSize) {
  for (int cnt = 0; cnt < dataSize; cnt++) {
    unsigned long len = dataP[cnt]*10;
    unsigned long us = micros();
    do {
      digitalWrite(IR_SEND_PIN, 1 - (cnt&1));
      delayMicroseconds(9);
      digitalWrite(IR_SEND_PIN, 0);
      delayMicroseconds(17);
    } while (long(us + len - micros()) > 0); // 送信時間に達するまでループ
  }
}

BLYNK_WRITE(V4){
  //スマホ側 Blynk アプリで設定したスライダー値の受信
int cmd1 = param[0].asInt();
  switch (cmd1) {
    case 0:
      sendSignalP(TVon, sizeof(TVon) / sizeof(TVon[0]));
      break;
    case 1:
      sendSignalP(TVof, sizeof(TVof) / sizeof(TVof[0]));
      break;
  }

}

BLYNK_WRITE(V5){
  //USB機器の電源ON/OFF
int cmd1 = param[0].asInt();
  switch (cmd1) {
    case 0:
      digitalWrite(LED1_PIN, HIGH);
      break;
    case 1:
      digitalWrite(LED1_PIN, LOW);
      break;
  }
}
==========================

上記とは別にもう一台ESP32-DevkitC を使って、赤外線リモコンで動作しない機器をHA端子(JEM-A端子)を使って制御しています。
(2018/3/25追記 1か月くらい運用したところ、数時間~数日でWi-Fiが切断してしまうようになりました。3/25にもう1台作り直して再投入しています。初号機との違いは5V端子-GND間に25V 100uFの電解コンデンサ追加、フォトカプラの入力端子間に100kΩ追加の2点です。)

それぞれの機器の場所が近くて、1台で全部接続できればそれが一番良いのですが、我が家の場合はカメラ(ドライブレコーダ)とHA機器の場所が離れており、2台体制になりました。

そもそも聞きなれないHA端子について。
日立のエアコンハンドブックの説明がわかりやすかったです。

オン/オフの制御を4ピンの共通端子で行えるようです。搭載機器は電気錠、エアコン、電動シャッター、インターホン、エコキュートなどの給湯関係くらいのようです。

まずコネクタですが、XHコネクタの4Pになるようです。
秋月電子で下記2点を購入し、アセンブリしました。難しかったです。
XHコネクタハウジング 4P XHP-4
XHコネクタハウジング用コンタクト SXH-001T-P0.6

たぶんパソコンの内蔵CDドライブに昔ついていたオーディオケーブル等が使えると思います。
フォトカプラ、ダイオード、抵抗で簡単な回路を作ってケーブル、コネクタと接続します。
回路は簡単なのですが、壁についている電動シャッターの制御ユニットの裏
(壁の中)に設置しなければならず、電源5Vの確保が大変でした。

スケッチは下記。信号オンオフをせめてサブルーチンにすればよかっのですが、面倒でコピペしてしまいました。

V6ピンは
0: シャッター開く
1:シャッター閉じる
2:お風呂オフ
3:お風呂オン
です。

オンもオフも同じ信号なので、モニタ信号で現在の状態を見て、
動作が必要なときのみ信号を送るようになっています。

2021/11/22追記
WIfiが切れたときに再接続できずずっとオフラインになるので下記を追記しました。
void loop()に入れてよいのかわかりませんでしたが、とりあえず様子を見ます。

    while(!Blynk.connected()) {
      Blynk.begin(auth, ssid, pass);
      delay(1000);
    }

================================
#define BLYNK_PRINT Serial
#include
#include
#include

char auth[] = "(Blynkから送られてきたメール内にある Auth コード)";
char ssid[] = "(ご自宅のWi-FiのSSID)";
char pass[] = "(ご自宅のWi-Fiのパスワード)";

void setup()
{
    Serial.begin(115200);
    pinMode(33, OUTPUT);      //シャッター制御
    pinMode(34, INPUT);      // シャッターモニタ
    pinMode(26, OUTPUT);      // お風呂制御
    pinMode(27, INPUT);      // お風呂モニタ
    delay(10);

    // We start by connecting to a WiFi network
    Serial.println();
    Serial.println();
    Serial.print("Connecting to ");
    Serial.println(ssid);
  Blynk.begin(auth, ssid, pass);
}

int value = 0;

void loop(){
    Blynk.run();
    
    while(!Blynk.connected()) {
      Blynk.begin(auth, ssid, pass);
      delay(1000);
    }
}


BLYNK_WRITE(V6){
  //スマホ側 Blynk アプリで設定したスライダー値の受信
int cmd1 = param[0].asInt();
  switch (cmd1) {
    case 0:
       if (digitalRead(34) ==0) {
          digitalWrite(33, HIGH); 
          delay(200);
          digitalWrite(33, LOW); 
        }                  
       break;
    case 1:
      if (digitalRead(34) ==1) {
        digitalWrite(33, HIGH);
        delay(200);
        digitalWrite(33, LOW);         
      }
      break;
    case 2:
       if (digitalRead(27) ==0) {
        digitalWrite(26, HIGH);  
        delay(200);
        digitalWrite(26, LOW); 
      }                  
      break;
    case 3:
      if (digitalRead(27) ==1) {
        digitalWrite(26, HIGH); 
        delay(200);
        digitalWrite(26, LOW); 
      }
      break;
  }
}
================================

このほか、スマートコンセント(Wifiスマートプラグ)という製品を2個購入し、ホットカーペットとWiiUの主電源オン/オフをGoogle homeから行っています。
1台1500円と、そんなに安くはありませんが、100V系を扱うならこちらも大変便利です。
========

おまけ
三和シャッター操作HY-800ユニット背面
〇で囲んだ端子がHA端子です。ピン配置は適当に調べてください。