スマートライフを実現 ! 家電製品をクラウドでコントロールしてみた

2021-02-02
日常で楽しむクラウドテクノロジー

嶺 行伸

こんにちは。IoT ソリューションアーキテクトの嶺です。

皆さんは "HEMS" という言葉を聞いた事はありますか?
"HEMS" とは "Home Energy Management System" の略で、家庭内で使われているエネルギーを見える化したり、家電製品を自動制御する事で省エネを実現したりするためのシステムです。

太陽光発電などを導入した住宅では標準的に設置されていますし、一部の自治体では補助金の対象になっていたりする事もあって、普通の住宅でも最近は HEMS が導入されているケースが珍しくなくなってきています。

かくいう私の自宅にも HEMS が導入されており、電気使用量を確認したり、エアコンの制御や電動シャッターの開閉を行う事などができます。

そうやって普段何の気なしに HEMS を使っていたのですが、ある時、私の頭にある考えが浮かびました。メーカーやジャンルが異なる機器同士を連携させるには、何らかの共通プロトコルが存在するはず。HEMS では一体、どのような技術が使われているのでしょうか ?

調べを進めていくと、「ECHONET Lite」というキーワードに辿り着きました。

ECHONET Lite とは

ECHONET Lite は、エコーネットコンソーシアムによって策定された、各種センサーや家電製品、住宅設備を IoT 化し、スマートハウスを実現するための共通プロトコルです。メーカーが違っても同じように制御できるように、センサーやエアコン、スイッチといったものの共通仕様を機器オブジェクトとして定義しています。

最新のプロトコル規格書は こちら、機器オブジェクト定義書は こちら からダウンロードする事ができます。

定義されている機器オブジェクトは以下のようなカテゴリー分けがされているようです。

  • センサー (ガス漏れセンサー、火災報知器、温度センサーなど)
  • 空調機器 (エアコン、加湿器、空気清浄機など)
  • 住宅設備 (電動シャッター、照明、電気・水道・ガスのメーターなど)
  • 調理・生活家電 (冷蔵庫、炊飯器、洗濯機など)
  • 健康関連機器 (体重計など)
  • 操作用機器 (スイッチなど)
  • AV 機器 (テレビ、オーディオ、カメラなど)

このように、家の中の様々な機器をメーカーの違いを意識する事なく制御できるプロトコルとなっており、2012 年に経済産業省によって日本における HEMS の標準プロトコルとして認定された事もあり、HEMS に関連した機器で広く使われています。特に最近は Wi-Fi に対応して遠隔制御できる家電製品も増えてきましたので、そうとは知らずに ECHONET Lite 対応の家電をお持ちの方も多いのではないかと思います。

今回は、ECHONET Lite に対応した家電製品をホームネットワークで制御し、さらにクラウドから遠隔制御できるようにしたいと思います。


実際にお試しいただくために、あらかじめサンプルコードをダウンロードしておきましょう。

ダウンロードはこちら »

ご注意

本記事で紹介する AWS サービスを起動する際には、料金がかかります。builders.flash メールメンバー特典の、クラウドレシピ向けクレジットコードプレゼントの入手をお勧めします。

*ハンズオン記事およびソースコードにおける免責事項 »

ECHONET Lite は仕様公開されているとはいえ、Jetson nano のような端末から制御できる事が保証されているわけではありません。また、予期せぬ動作によりご家庭の設備に不具合が生じたり、不意に動作する事で事故等が起きる可能性もあります。お試しになる場合はその点をご認識頂いた上で、深刻な影響のない機器を選び、ご自身の責任においての実施をお願い致します。

このクラウドレシピ (ハンズオン記事) を無料でお試しいただけます »

毎月提供されるクラウドレシピのアップデート情報とともに、クレジットコードを受け取ることができます。 


1. 全体の流れ

今回は以下のような流れで進めていきたいと思います。

  1. 家電製品をクラウドから制御するためのゲートウェイとして使うデバイス (Jetson nano) をセットアップする
  2. 自宅ネットワークにどのような ECHONET Lite 対応機器があるのかを調査する
  3. 発見した ECHONET Lite 機器に手動で制御コマンドを送り、制御できる事を確認する
  4. ECHONET Lite 機器の状態をクラウドで確認したり、クラウドから遠隔制御できるようにする

2. 利用するデバイス

今回利用したのは以下のデバイスになります。電子工作などは一切必要ありません。

  • Jetson nano
    • クラウドとホームネットワークのゲートウェイとして動作させます。
    • 自宅の LAN に有線もしくは Wi-Fi で接続でき、インターネットにつながる環境である事を前提としています。
    • 動作させるには 32GB 以上の MicroSD カードと USB 充電器、Wi-Fi で接続する場合は Wi-Fi モジュールも別途必要です。
    • 最近発売された 2GB RAM モデルをお使い頂く事も可能です。また、Jetson の代わりに Raspberry Pi をお使い頂く事も、セットアップ手順を Raspberry Pi 向けに読み替えて頂ければ可能です。
    • セットアップ作業を行う際には SD カードリーダー、キーボード、マウス、ディスプレイ等も別途必要になります。
  • ECHONET Lite 対応家電
    • お持ちでない場合、Sony CSL 様から公開されている「MaekadenRoom」等のエミュレータ環境でも代用可能です。

3. 利用する AWS のサービス

今回利用した AWS サービスは以下の通りです。

AWS IoT Greengrass V1

ホームネットワーク側でコードを動かし、クラウドから制御できるようにするために利用します

AWS サービスを利用するコードを AWS Lambda 上で簡潔に記述でき、それを Jetson nano に簡単にデプロイ・アップデートする事ができます

現在は AWS IoT Greengrass V2 がリリースされていますが、今回は V1 を利用しました。以降、特にバージョンを指定しない場合は V1 についての説明となります

AWS IoT Core

「デバイスシャドウ」という機能で、ホームネットワーク内の機器の情報をクラウドと同期するために利用します

AWS Lambda

AWS IoT Greengrass V1 で動かすコードを Lambda 関数として定義します

Alexa のスマートホームスキルから AWS IoT Core のデバイスシャドウを通してデバイスを制御します


4. 全体アーキテクチャ

全体のアーキテクチャはこのようになっています。

ホームネットワークに配置した Jetson nano で AWS IoT Greengrass V1 を動かし、ECHONET Lite 対応機器を制御するための AWS Lambda 関数をデプロイします。AWS Lambda 関数は AWS IoT Core 上のデバイスシャドウに ECHONET Lite 機器の状態を送信すると共に、クラウド側でデバイスシャドウの状態が変更されると ECHONET Lite 機器に制御コマンドを送信してその変更を反映します。これによって、デバイスシャドウの状態を変更する事で ECHONET Lite 対応機器を制御する事ができます。

また、Alexa のスマートホームスキルとして実装した Lambda 関数からデバイスシャドウの状態を読み書きする事により、Alexa の音声コマンドで ECHONET Lite 対応機器を操作できるようにします。


5. Jetson nano のセットアップ

それでは、まずはホームネットワークの制御を担当してもらう Jetson nano の設定から始めていきたいと思います。

5-1. SD カードイメージのダウンロード

Jetsonシリーズでは、Jetpack という名前で公式の SD カードイメージがリリースされています。今回は 2GB RAM モデルに対応したバージョン 4.4.1 を利用しました。お使いのモデルに対応した SD カードイメージを前記のリンク先からダウンロードして下さい。

もし、4.4.1 より新しいバージョンが配布されている場合、こちらのリンク から 4.4.1 を選んでダウンロードして頂ければ、この先の手順でバージョンの違いによるエラー等が発生する可能性を減らせると思います。

5-2. SD カードへのイメージ書き込み

お使いの PC に SD カードリーダーを接続し、MicroSD カードにイメージを書き込みます。こちらのページ で、Windows / macOS / Linux の各環境における書き込み手順が解説されているので、参考にして頂ければと思います。

5-3. Jetson nano の起動、初期セットアップ

Jetson nano の MicroSD カードスロットに MicroSD カードを挿入し、電源に接続して初期セットアップを行います。こちらのページ で、キーボードやディスプレイを Jetson nano に接続しているケースと、接続していないケースそれぞれの手順が解説されています。(2GB 版の場合は こちら)

5-4. node.js のインストール

今回は node.js の ECHONET Lite ライブラリを使いますので、node.js のインストールをここで行います。

Jetpack 4.4.1 がベースとしている Ubuntu 18.04 LTS では node.js v8 が標準となっています。しかし、今回利用する AWS IoT Greengrass V1 で動作するコードを設定するために使う AWS Lambda では現在 node.js v8 の Lambda 関数が新規作成できなくなっているため、今回は node.js のバージョン管理を容易にする n というツールを使い、AWS IoT Greengrass V1 が対応している最新バージョンである v12 をインストールします。

Jetson nano でターミナルを立ち上げ、以下のコマンドを入力して下さい。

# node.js v8.10 をインストール
sudo apt install -y nodejs npm
# npm で n をインストール
sudo npm install n -g
# n で node.js v12 をインストール
sudo n 12
# node.js v8.10 を削除
sudo apt purge -y nodejs npm

ターミナルを閉じて再び開き、node -v と入力して v12.20.1 のように表示されれば、v12 が正しくインストールされています。


6. ECHONET Lite 対応デバイスを探す

Jetson の準備ができたので、まずはホームネットワークにどのような ECHONET Lite 対応デバイスが存在しているのか調査するところから始めたいと思います。

ECHONET Lite を使うためのライブラリにはいくつかの選択肢がありますが、今回は node.js 向けのライブラリとして公開されている echonet-lite というライブラリを利用しました。まずは、このライブラリのインストールから始めたいと思います。

6-1. echonet-lite ライブラリのインストール

ターミナルを開き、以下のコマンドを入力して下さい。

# 作業用ディレクトリを作成 ディレクトリ名は任意
mkdir echonet
cd echonet
# 作業用ディレクトリの node_modules に echonet-lite をインストール
npm install echonet-lite

6-2. デバイス探索プログラムの実装と実行

インストールが成功したら、search.js という名前のファイルを作成し、以下のコードをコピーします。

/*
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: MIT-0
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of thi
* software and associated documentation files (the "Software"), to deal in the Softwa
* without restriction, including without limitation the rights to use, copy, modify,
* merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
// echonet-lite モジュールを EL という名前でインポート
const EL = require('echonet-lite');
// 自分自身のオブジェクト種別指定
const myObject = '05ff01'; // オブジェクト種別 '05ff01' は「コントローラーオブジェクト」
// 自分のオブジェクトを指定して echonet-lite モジュールを初期化
// ECHONET Lite では通信はオブジェクト間で行われるため、通信元となる際のオブジェクトをここで指定しま
var elsocket = EL.initialize([myObject], (rinfo, els, error) => {
  if (error) {
   console.log(error);
   return;
  }
  // 発見した ECHONET Lite 機器のIPアドレスと通信内容をダンプ
  console.log('====================');
  console.dir(rinfo, {depth: null});
  console.dir(els, {depth: null});
});
// ホームネットワーク上で ECHONET Lite 機器を探すコマンドを実行
EL.search();

コードがコピーできたら、以下のコマンドで実行してみましょう。

node search.js

実行すると、ホームネットワークに ECHONET Lite 機器があれば、以下のようなログが連続で表示されます。

====================
{ address: '192.168.1.100', family: 'IPv4', port: 49154, size: 24 }
{
  EHD: '1081',
  TID: '0037',
  SEOJ: '013001',
  DEOJ: '0ef001',
  EDATA: '72019e0a0980a0b081a193b3a48f',
  ESV: '72',
  OPC: '01',
  DETAIL: '9e0a0980a0b081a193b3a48f',
  DETAILs: { '9e': '0980a0b081a193b3a48f' }
}

addressfamily は ECHONET Lite デバイスの IP アドレス、port は TCP や UDP の送信元ポートです。
その下の EHD TID SEOJ といった項目は何でしょうか。規格書を確認すると、以下のような内容が記載されていました。

列 1

列 2

EHD

ECHONET Lite ヘッダ
通常は '1081'

TID

トランザクションID
レスポンスにおいて、どのリクエストに対するレスポンスかを明示するために利用

SEOJ

送信元 (Source) ECHONET オブジェクト指定
通信元の機器の種類と通し番号を指定
'013001' は「エアコン (0130) の1番目 (01)」

DEOJ

相手先 (Destination) ECHONET オブジェクト指定
通信相手の機器の種類と通し番号を指定

EDATA

ECHONET Lite データ
ESV と OPC と DETAIL から構成される

ESV

ECHONET Lite サービス
プロパティの読み出し/書き込み/通知などの要求/応答のどれかを表す識別子
'72' は「プロパティ値読み出し要求への応答」

OPC

処理対象プロパティカウンタ
同時にいくつのプロパティを読み書きするかの指定

DETAIL

プロパティ値
プロパティコードとその値である DETAILs から構成される

DETAILs

実際に読み書きされたプロパティのプロパティコードとその値
同時に複数の読み書きを行う場合は複数から構成される
'9e' は「書き込み可能なプロパティのプロパティコード一覧」というプロパティ

調べたいのは「ネットワークに存在する ECHONET Lite 対応デバイスの種類と IP アドレス」です。これが判れば、デバイスにコマンドを送信する事が可能になります。

デバイスから送られてきている SEOJ と送信元の address の組み合わせ一覧を作成すれば、そのようなリストを作成する事ができそうです。

実は、echonet-lite ライブラリは内部で自動的にそのようなデータを EL.facilities という名前で構築してくれています。早速そのデータをダンプしてみましょう。

6-3. 制御対象デバイスのリストアップ

search.js の「発見した ECHONET Lite 機器の IP アドレスと通信内容をダンプ」というコメントから始まっているコードを、以下のように書き換えて下さい。

// デバイスのIPアドレスとオブジェクト一覧をダンプ
console.log("====================");
console.dir(EL.facilities, {depth: null});

node search.js を実行すると、以下のようなログが出力されると思います。

{
  '192.168.1.100': {
    '0ef001': {
        // 省略
    },
    '013001': {
        // 省略
    }
  },
  '192.168.1.200': {
    '0ef001': {
        // 省略
    },
    '05fd01': {
        // 省略
    }
  }
}

0ef001 というのは「ノードプロファイルオブジェクト」と呼ばれるもので、詳細は割愛しますが、全ての ECHONET Lite デバイスが持っているものです。上述の通り 013001 はエアコンです。では、05fd01 とは一体何でしょうか?

規格書の「機器オブジェクト詳細規定」を調べてみたところ、05fd は「スイッチ (JEM-A / HA 端子対応)」と書かれていました。これは、機器の ON / OFF を遠隔制御するための JEM-A 1427 という規格に対応したスイッチの事です。家の中の設備で該当するものを考えると、電動シャッターの操作スイッチが思い当たりました。確かに、これは HEMS でも操作対象として出てくるものなので、ECHONET Lite に対応していそうですね。


7. デバイスを手動で制御してみる

それでは早速エアコンとシャッターに制御コマンドを送ってみたいと思いますが、その前に、エアコンとシャッターのスイッチはどのようなコマンドに対応しているのか、仕様を確認する必要があります。改めて「機器オブジェクト詳細規定」を見てみましょう。

7-1. デバイスの仕様を調べる

「機器オブジェクト詳細規定」によると、エアコンとスイッチで読み書きできるプロパティは以下のようになっています。
(数が多いので、必須プロパティと記載されたもののみを記載しています)

列 1

列 2

列 3

列 4

列 5

クラス名

プロパティコード

プロパティ名

対応操作

説明

エアコン

0x80

動作状態

読み出し
書き込み
通知

ON/OFF の状態
ON: 0x30 OFF: 0x31

 

0x8F

節電動作設定

読み出し
書き込み
通知

節電モードの状態
節電動作中: 0x41 通常動作中: 0x42

 

0xB0

運転モード設定

読み出し
書き込み
通知

現在の運転モード
自動: 0x41 冷房: 0x42 暖房: 0x43
除湿: 0x44 送風: 0x45 その他: 0x40

 

0xB3

温度設定値

読み出し
書き込み

現在の設定温度 (℃)
0℃: 0x00 〜 50℃: 0x32

 

0xBB

室内温度計測値

読み出し

現在の室内温度 (℃)
-127℃: 0x81 ~ 125℃: 0x7D

 

0xA0

風量設定

読み出し
書き込み

風量の設定状態
自動: 0x41
風量レベル1: 0x31 〜 レベル8: 0x38

スイッチ

0x80

動作状態

読み出し
書き込み
通知

ON/OFF の状態
ON: 0x30 OFF: 0x31

エアコンは必須プロパティだけでも色々と面白い事ができそうですね。
スイッチは機能がシンプルなだけに仕様もシンプルです。

どちらも ON/OFF はプロパティコード 0x80 に 0x30 / 0x31 を書き込む事で制御できる事がわかりました。

今回は、シンプルなスイッチを制御してみたいと思います。

7-2. デバイス手動制御プログラムの実装と実行

制御したいデバイスの仕様が判明したので、早速制御してみたいと思います。まずは仕様がシンプルなシャッターのスイッチを制御してみたいと思います。

control.js という名前のファイルを作成し、以下のコードをコピーして下さい。

/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: MIT-0
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this
 * software and associated documentation files (the "Software"), to deal in the Software
 * without restriction, including without limitation the rights to use, copy, modify,
 * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

// echonet-lite モジュールを EL という名前でインポート
const EL = require('echonet-lite');

// 自分自身のオブジェクト種別指定
const myObject = '05ff01'; // オブジェクト種別 '05ff01' は「コントローラーオブジェクト」

// 自分のオブジェクトを指定して echonet-lite モジュールを初期化
// ECHONET Lite では通信はオブジェクト間で行われるため、通信元となる際のオブジェクトをここで指定します
var elsocket = EL.initialize([myObject], (rinfo, els, error) => {
  if (error) {
    console.log(error);
    return;
  }
});

// 制御対象のIPアドレス (前記の手順で実際に発見したアドレスに置き換えて下さい)
const deviceAddress = '192.168.1.100';

// 制御対象のオブジェクト (05fd01 はスイッチですが、実際に発見したオブジェクトに置き換えて下さい)
const deviceObject = '05fd01';

// 制御対象のプロパティコード (0x80 は ON/OFF の状態)
const propertyCode = 0x80;

// 送信する値 (0x31 は OFF)
const value = [0x31];

// スイッチを OFF にする (シャッターの場合は上げる) コマンドを送信
// EL.SETI は「応答を要求しない書き込み」
// sendOPC1() は「制御対象プロパティが1つのコマンドを送信」という関数
EL.sendOPC1(deviceAddress, EL.toHexArray(myObject), EL.toHexArray(deviceObject), EL.SETI, propertyCode, value);

node control.js で実行すると、シャッターが動きました !

8. デバイスの状態をクラウドと同期する

デバイスを想定通りに制御できる事が判明したので、ここからは AWS IoT Greengrass V1 を使ってクラウドと連携していきたいと思います。

まずは AWS IoT Greengrass V1 の設定から始めます。AWS IoT Greengrass V1 を使うには、AWS 上で「Greengrass グループ」を作成し、生成された設定ファイルを使って Jetson nano に「Greengrass Core ソフトウェア」をインストールする必要があります。

それでは、Jetson nano で Greengrass Core ソフトウェアを実行するための準備から始めましょう。

8-1. AWS IoT Greengrass V1 の実行に必要な設定を行う

ターミナルで以下のコマンドを実行し、Jetson nano 上で AWS IoT Greengrass V1 を実行するためのユーザーとグループを作成します。

sudo adduser --system ggc_user
sudo addgroup --system ggc_group

次に、以下のコマンドで AWS IoT Greengrass V1 が node.js v12 を実行するために使うシンボリックリンクを作成します。

sudo ln -s /usr/local/bin/node /usr/local/bin/nodejs12.x

これで Jetson nano で AWS IoT Greengrass V1 を実行するための環境が整ったはずですが、実行できるかどうかをチェックできるツールが公開されていますので、これを使って確認してみましょう。

以下のコマンドでツールをダウンロードし、展開して実行して下さい。

wget https://github.com/aws-samples/aws-greengrass-samples/raw/master/greengrass-dependency-checker-GGCv1.11.x.zip
unzip greengrass-dependency-checker-GGCv1.11.x.zip
cd greengrass-dependency-checker-GGCv1.11.x/
sudo ./check_ggc_dependencies

以下のようなログが表示されれば成功です。

==========================Checking script dependencies==============================
The device has all commands required for the script to run.

========================Dependency check report for GGC v1.11.x=========================
System configuration:
Kernel architecture: aarch64
Init process: /lib/systemd/systemd
Kernel version: 4.9.140
C library: Ubuntu GLIBC 2.27-3ubuntu1.4
C library version: 2.27
Directory /var/run: Present
/dev/stdin: Found
/dev/stdout: Found
/dev/stderr: Found
----------------------------Commands and software packages--------------------------
Python 2.7 version: 2.7.17
Python 3.7: Not found
NodeJS version: 12.20.1
Java 8: Not found

# 中略

------------------------------------Results-----------------------------------------
Note:
1. It looks like the kernel uses 'systemd' as the init process. Be sure to set the
'useSystemd' field in the file 'config.json' to 'yes' when configuring Greengrass core.

Missing optional dependencies:
1. Could not find the binary 'python3.7'.

If Python 3.7 is installed on the device, name the binary 'python3.7' and add its parent 
directory to the PATH environment variable. Python 3.7 is required to execute Python 3.7
lambdas on Greengrass core.

2. Could not find the binary 'java8'.

If Java 8 or later is installed on the device name the binary 'java8' and add its
parent directory to the PATH environment variable. Java 8 or later is required to
execute Java lambdas as well as stream management features on Greengrass core.

Supported lambda isolation modes:
No Container: Supported
Greengrass Container: Supported

----------------------------------Exit status---------------------------------------
You can now proceed to installing the Greengrass core 1.11.x software on the device.
Please reach out to the AWS Greengrass support if issues arise.

Python 3.7 と Java 8 に関しては、これらで実装された AWS Lambda 関数を実行する等の必要がない限り、インストールしなくても問題ありません。

8-2. Greengrass グループの作成

Jetson nano のブラウザで AWS IoT Greengrass のコンソールを表示し、左側の一覧から「Classic (V1)」を選択し、「グループの作成」をクリックします。

クリックすると拡大します

「デフォルト作成を使用」をクリックします。

クリックすると拡大します

「グループ名」に任意のグループ名を入力して「次へ」をクリックします。

クリックすると拡大します

Greengrass Core の名前を変更する必要は特にないので、そのまま「次へ」をクリックします。

クリックすると拡大します

内容を確認して「グループと Core の作成」をクリックします。

クリックすると拡大します

「これらのリソースは tar.gz としてダウンロードしてください」をクリックして Greengrass Core の設定ファイルをダウンロードします。
(「AWS IoT のルート CA をダウンロードする必要があります」とありますが、この後の手順でダウンロードするので、ここではダウンロードしなくても大丈夫です)

クリックすると拡大します

「プラットフォームを選択」をクリックし、Greengrass Core ソフトウェアのダウンロードページを開きます。

クリックすると拡大します

Jetson nano に対応した「Armv8 (AArch64)」の「Arch Linux」の行の「ダウンロード」をクリックし、ダウンロードします。

ダウンロードが完了したら元のタブに戻り、「完了」をクリックして下さい。

クリックすると拡大します

8-3. Greengrass Core ソフトウェアのインストール

次に、Jetson nano のターミナルで以下のコマンドを実行し、ダウンロードした Greengrass Core ソフトウェアと設定ファイルを展開します。

# ファイル名は実際にダウンロードしたものに置き換えて下さい
sudo tar zxvf greengrass-linux-aarch64-1.11.0.tar.gz -C /
sudo tar zxvf xxxxxxxxxx-setup.tar.gz -C /greengrass/

以下のコマンドで、Greengrass Core の実行に必要な最新の Amazon Root CA1 証明書をダウンロードします。

sudo wget https://www.amazontrust.com/repository/AmazonRootCA1.pem -O /greengrass/certs/root.ca.pem

8-4. Greengrass Core ソフトウェアの起動

これでインストールが完了しましたので、以下のコマンドで Greengrass Core ソフトウェアを起動します。

sudo /greengrass/ggc/core/greengrassd start

以下のようなログが表示されれば成功です。

Greengrass successfully started with PID: xxxxx

9. クラウドからデバイスを遠隔制御する

次に、以下のような手順で、シャッターをクラウドから遠隔制御できるようにしたいと思います。

  1. Greengrass グループに「shutter」というデバイスを登録する
  2. 「shutter」のデバイスシャドウにシャッターの開閉状態を定義する
  3. AWS Lambda に、ECHONET Lite 機器のシャッターの開閉状態と、デバイスシャドウに定義した開閉状態を同期する機能を持つ Lambda 関数を登録する
  4. 登録した Lambda 関数をGreengrass グループに追加する
  5. Greengrass グループにサブスクリプションを登録して Jetson nano にデプロイする
  6. デバイスシャドウ上のシャッター開閉状態を変更すると、実際にシャッターが動く事を確認する

9-1. Greengrass グループへのデバイスの登録

AWS IoT Greengrass のコンソールに戻り、前の章で作成した Greengrass グループを選択した後、左側の一覧から「デバイス」を選択して「デバイスの追加」をクリックします。

クリックすると拡大します

「新しいデバイスの作成」をクリックします。

クリックすると拡大します

「名前」「shutter」と入力して「次へ」をクリックします。

クリックすると拡大します

「デフォルトを使用」をクリックします。

クリックすると拡大します

「これらのリソースは tar.gz としてダウンロードしてください」をクリックして設定ファイルをダウンロードし、「完了」をクリックします。

(このファイルは、AWS IoT Device SDK でデバイスが AWS IoT Core に接続する場合に利用します。今回はデバイスシャドウを使うだけの目的でデバイスを登録していて、AWS IoT Core への接続は AWS Greengrass Core SDK を使うため、このファイルは使用しません。しかし、ここでダウンロードしないと二度と取得できず、後で AWS IoT Device SDK での接続を試したくなってもできなくなってしまうため、念のためダウンロードする事をお勧めします)

クリックすると拡大します

作成したデバイスが表示されるので、デバイスの項目の右上の「…」をクリックして「クラウドに同期」をクリックします。

これによって、このデバイスのデバイスシャドウの内容をクラウドと同期できるようになります。

クリックすると拡大します

9-2. デバイスシャドウに開閉状態を定義

作成したデバイスをクリックし、左側の一覧から「シャドウ」を選択して「シャドウを追加する」をクリックします。

クリックすると拡大します

名前は空欄のまま「追加」をクリックします。

クリックすると拡大します

追加された「Classic Shadow」をクリックし、「シャドウドキュメント」のセクションの「編集」をクリックします。

クリックすると拡大します

「シャドウステータス」を以下のように編集し、右上の「保存」をクリックします。

{
  "desired": null,
  "reported": {
    "is_open": false,
    "welcome": null
  }
}

ここでは、自動的に作成されたシャドウの内容を削除し、シャッターの開閉状態を表す「is_open」という項目を追加しています。シャドウステータスの詳細について詳しく知りたい方は、こちらの開発者ガイド をご参照下さい。

9-3. AWS Lambda への Lambda 関数の登録

次に、AWS IoT Greengrass V1 でコードを動作させるため、AWS Lambda に Lambda 関数を登録します。AWS IoT Greengrass V1 で動作する Lambda 関数にするため、node.js 向けの aws-greengrass-core-sdk というモジュールを npm でインストールする必要があります。

先ほど作成した control.js があるディレクトリで以下のコマンドを実行して下さい。

npm install aws-greengrass-core-sdk

次に、本記事のソースコードの ZIP ファイルの解凍先の greengrass ディレクトリから index.js をコピーして下さい。
実装の解説についてはソースコードのコメントをご参照頂ければと思いますが、いくつか要点をここで説明します。

以下のコードでは、デバイスシャドウの変更通知を Greengrass Core で受信し、変更内容を元に ECHONET Lite デバイスのプロパティを変更します。

// デバイスシャドウの変更通知が行われる MQTT トピックの正規表現パターン
const pattern_updateDelta = /^\$aws\/things\/(?<thingName>.*)\/shadow\/update\/delta$/

// MQTT メッセージを受信したら起動されるハンドラー
exports.handler = async (event, context) => {
  // メッセージを受信したトピック (subject)
  const subject = context.clientContext.Custom.subject;

  // トピックがデバイスシャドウの変更通知かどうかを正規表現で判定する
  let result = subject.match(pattern_updateDelta);
  if (result && result.groups.thingName === deviceName) {
    // 変更通知だった場合は変更内容を取得
    const isOpen = event.state.is_open;

    // 変更内容を制御対象の ECHONET Lite デバイスに送信
    // プロパティコード 0x80 (動作状態) を 0x30 (ON) または 0x31 (OFF) に変更する
    const value = [isOpen ? 0x31 : 0x30];
    EL.sendOPC1(deviceAddress, EL.toHexArray(myObject), EL.toHexArray(deviceObject), EL.SETI, 0x80, value);
  }
};

以下のコードでは逆に、ECHONET Lite デバイスからプロパティ変更通知を受け取り、変更内容を元にデバイスシャドウを更新します。

// echonet-lite モジュールの初期化
// ECHONET Lite パケットを受信した際の処理をここで実装
var elsocket = EL.initialize([myObject], async (rinfo, els, error) => {
  // 受信したパケットの種別を調査
  switch(els.ESV) {
  case EL.INF: // プロパティ変更通知
    if (els.SEOJ === deviceObject) {
      // 送信元が制御対象デバイスなら、内容をデバイスシャドウに送信
      // プロパティ変更通知は不特定多数へのブロードキャストであるため、宛先の判定は不要
      const value = els.DETAILs['80'];
      if (value) {
        const isOpen = (value === '31');
        await updateDeviceShadow(deviceName, isOpen);
      }
    }
    break;

  default:
    break;
  }
});

解説は以上です。index.js のコピーができたら、以下のコマンドで Lambda 関数の zip アーカイブを作成します。

zip -r ../lambda.zip *

これで AWS Lambda にアップロードするための Lambda 関数ができたので、AWS Lambda に登録しましょう。

AWS Lambda コンソールを開き、「関数の作成」をクリックします。

クリックすると拡大します

「一から作成」が選択されている事を確認し、「関数名」に任意の名前を入力し、「ランタイム」「Node.js 12.x」が選択されている事を確認して「関数の作成」をクリックします。

クリックすると拡大します

「関数コード」のセクションの「アクション」をクリックし、表示されたメニューから「.zip ファイルをアップロード」をクリックします。

クリックすると拡大します

「アップロード」をクリックし、先ほど作成した lambda.zip を選択してアップロードします。

クリックすると拡大します

ページの一番上まで戻って「アクション」をクリックし、表示されたメニューから「新しいバージョンを発行」をクリックします。

(必須ではありませんが、さらに「エイリアスを作成」して「バージョン1」にエイリアス名を割り当てると、コードを書き換えた場合のバージョンアップ作業がやりやすくなります。詳細はこちらのドキュメントをご参照下さい。)

クリックすると拡大します

9-4. Greengrass グループへの Lambda 関数の登録

AWS IoT Greengrass のコンソールに戻り、作成した Greengrass グループを選択した後、左側の一覧から「Lambda」を選択して「Lambda の追加」をクリックします。

クリックすると拡大します

「既存の Lambda を使用」をクリックします。

クリックすると拡大します

表示された一覧から先ほど作成した Lambda 関数を選択し、「次へ」をクリックします。

クリックすると拡大します

「バージョン 1」を選択して「完了」をクリックします。
(前の手順で「エイリアス」を作成していた場合、ここではエイリアス名を選択します)

クリックすると拡大します

追加された Lambda 関数の項目の右上にある「…」をクリックし、表示されたメニューから「設定の編集」をクリックします。

クリックすると拡大します

「Lambda のライフサイクル」のセクションで「存続期間が長く無制限に稼働する関数にする」を選択し、ページの一番下の「更新」をクリックします。

クリックすると拡大します

9-5. Greengrass グループへのサブスクリプションの登録

左側の一覧から「Classic (V1)」の下の「グループ」を選択し、設定中の Greengrass グループを再度選択した後、左側の一覧から「サブスクリプション」を選択し、「サブスクリプションの追加」をクリックします。

クリックすると拡大します

「ソースの選択」「選択」をクリックし、上の一覧から「Lambda」を選択して先ほど登録した Lambda 関数を選択します。

クリックすると拡大します

クリックすると拡大します

「ターゲットの選択」「選択」をクリックし、「Local Shadow Service」を選択して「次へ」をクリックします。

クリックすると拡大します

「トピックのフィルター」に以下の内容を入力して「次へ」をクリックします。

$aws/things/+/shadow/#

このフィルターの意味は、「MQTT プロトコルを使って Lambda 関数からのデバイスシャドウの更新ができるようにする」という意味になります。MQTT プロトコルによるデバイスシャドウの操作について詳しく知りたい方は こちらの開発者ガイド をご参照下さい。

クリックすると拡大します

内容を確認して「完了」をクリックします。

クリックすると拡大します

次に、「MQTT プロトコルを使った Lambda 関数からのデバイスシャドウの状態取得を許可する」ためのサブスクリプションを作成します。再度「サブスクリプションの追加」をクリックし、以下のようにソースとターゲットを逆にしたサブスクリプションを追加します。

  • ソースの選択 : Local Shadow Service
  • ターゲットの選択 : 作成した Lambda 関数
  • トピックのフィルター
$aws/things/+/shadow/#

以上で Greengrass グループの設定は終わりです。左側の一覧から「デプロイ」を選択し、画面上部の「アクション」をクリックして表示されたメニューから「デプロイ」をクリックします。

クリックすると拡大します

9-6. 動作確認

リストの一番上に表示されているデプロイのステータスが「正常に完了しました」となれば、これまでの手順は全て完了です。実際に動作確認を行なってみましょう。

9-2 の手順で作成した「Classic Shadow」の設定画面に移動し、「シャドウドキュメント」のセクションの「編集」をクリックして「シャドウステータス」を以下のように編集し、右上の「保存」をクリックします。

{
  "desired": {
    "is_open": true
  }
}

シャッターが開けば動作確認は成功です !


10. Alexa による機器制御

遠隔制御ができたので、次はもっと使いやすくしたいと思います。

使いやすくする方法には、スマートフォンアプリの開発や Web アプリの開発など様々な手段が考えられますが、今回は手軽に実装できて使いやすさも抜群の方法である「Alexa スマートホームスキル」を使いました。

こちらは詳しく解説すると、それだけでもう1本記事が書けてしまうボリュームになりますので、今回は要点だけ解説したいと思います。

10-1. Alexa スマートホームスキルとは

スマートホームスキルとは、Alexa から様々なデバイスを音声コマンドで制御できるようにするための仕組みです。メーカーが異なっても共通の使い方ができるように、様々な種類のデバイスの共通仕様が インターフェイス として定義されています。

開発者は、開発するデバイスに適したインターフェイスを選択し、Alexa からの「デバイス発見」「デバイス制御」「デバイス状態取得」といったリクエストを処理するためのコードを AWS Lambda で実装するだけで、「アレクサ、シャッター開けて」といった音声コマンドによるデバイス制御を実現する事ができます。

10-2. スマートホームスキルの開発方法

スマートホームスキルの開発方法の詳細については こちらのドキュメント をご参照下さい。注意点としては、日本語に対応したスマートホームスキルを開発する際は、AWS Lambda は 米国西部 (オレゴン) (us-west-2) リージョンに作成する必要があります。

米国西部 (オレゴン) の AWS Lambda に作成し、Alexa Smart Home のトリガーを有効にした node.js 12 の Lambda 関数を作成します。AWS IoT Core のデバイスシャドウにアクセスするため、「アクセス権限」で実行ロールに AWSIoTDataAccess ポリシーをアタッチする必要があります。

作成できたら、解凍した ZIP ファイルの alexa ディレクトリにある index.js の内容を「関数コード」の index.js にコピーします。実装内容の解説はソースコードのコメントをご参照頂ければと思いますが、いくつか要点をここで説明します。

このコードでは、Alexa スマートホームの ToggleController というインターフェイス経由で、デバイスシャドウを操作する機能を提供するスマートホームスキルを実装しています。ToggleControllerON / OFF という 2 つの状態を持つ toggleState を切り替える事ができる汎用的なインターフェイスですが、「semantics」を定義する事により、ON / OFF それぞれに、「開ける」「閉める」「上げる」「下げる」といった言葉を割り当てる事ができます。今回は「ON」を「閉める」、「OFF」を「開ける」に割り当てました。

以下のコードで、Alexa から ToggleController への制御コマンドを受信した際の処理を実装しています。TurnOn に対してはデバイスシャドウの is_open false に、TurnOff に対しては true にする事で、デバイスシャドウの状態を監視している Greengrass Core 経由で ECHONET Lite デバイスを制御します。

// 制御リクエストを処理するハンドラー
async function handleToggleControl(request, context) {
    var requestMethod = request.directive.header.name;
    var responseHeader = request.directive.header;
    responseHeader.namespace = "Alexa";
    responseHeader.name = "Response";
    responseHeader.messageId = responseHeader.messageId + "-R";
    var requestToken = request.directive.endpoint.scope.token;

    // ToggleController への TurnOn / TurnOff をデバイスシャドウの is_open の false / true として書き込む
    var isOpen = (requestMethod === "TurnOff");
    const payload = {
      state: {
        desired: {
          is_open: isOpen
        }
      }
    };
    const result = await iotData.updateThingShadow({
      payload: JSON.stringify(payload),
      thingName: deviceName
    }).promise();

    var contextResult = {
        "properties": [{
            "namespace": "Alexa.ToggleController",
            "name": "toggleState",
            "instance": "Shutter.State",
            "value": isOpen ? "OFF" : "ON",
            "timeOfSample": new Date().toISOString(),
            "uncertaintyInMilliseconds": 50
        }]
    };
    var response = {
        context: contextResult,
        event: {
            header: responseHeader,
            endpoint: {
                scope: {
                    type: "BearerToken",
                    token: requestToken
                },
                endpointId: "shutter_id"
            },
            payload: {}
        }
    };
    return response;
}

以下のコードでは、Alexa から ToggleController の状態の問い合わせがあった際の処理を実装しています。デバイスシャドウの is_open の状態を取得し、true であれば toggleStateOFFfalse であれば ON として結果を返却する事で、ECHONET Lite デバイスの状態を Alexa に伝える事ができます。

// 状態取得リクエストを処理するハンドラー
async function handleReportState(request, context) {
    var responseHeader = request.directive.header;
    responseHeader.namespace = "Alexa";
    responseHeader.name = "StateReport";
    responseHeader.messageId = responseHeader.messageId + "-R";
    var requestToken = request.directive.endpoint.scope.token;

    // デバイスシャドウの状態を取得し、is_open を toggleState にマッピングして返す
    const result = await iotData.getThingShadow({thingName: deviceName}).promise();
    const shadow = JSON.parse(result.payload);
    var contextResult = {
        "properties": [{
            "namespace": "Alexa.ToggleController",
            "instance": "Shutter.State",
            "name": "toggleState",
            "value": shadow.state.reported.is_open ? "OFF" : "ON",
            "timeOfSample": new Date().toISOString(),
            "uncertaintyInMilliseconds": 50
        }]
    };
    var response = {
        context: contextResult,
        event: {
            header: responseHeader,
            endpoint: {
                scope: {
                    type: "BearerToken",
                    token: requestToken
                },
                endpointId: "shutter_id"
            },
            payload: {}
        }
    };
    return response;
}

それでは、Alexa アプリでこのスマートホームスキルを有効化してユーザー認証し、デバイスを検出できたら、「アレクサ、シャッター閉めて」と言ってみましょう。

アレクサがシャッターを閉めてくれました !


11. まとめ

いかがでしたでしょうか。今回は ON/OFF で制御する簡単な例でしたが、日常生活に溶け込んでいた身近な家電製品でも、声で操作できるようになると新鮮な気分で使えるのではないでしょうか。

今回は ON / OFF で制御できる簡単な仕様の機器を選びましたが、次のステップとしては、エアコンといったもう少し複雑な仕様を持つ機器も制御できると、より面白くなりそうです。Alexa スマートホームスキルでも、ThermostatController といったインターフェイスが提供されています。

また、Alexa なら単純な操作だけでなく、定型アクションで複数の家電を同時に操作したり、特定の時間に制御したりといった事も可能になります。皆さんもぜひ、身近な家電を解析してクラウドに繋ぎ、スマートライフを実現しましょう !


builders.flash メールメンバーへ登録することで
AWS のベストプラクティスを毎月無料でお試しいただけます

筆者プロフィール

嶺 行伸
アマゾン ウェブ サービス ジャパン合同会社
IoT スペシャリスト ソリューションアーキテクト

学生時代からスマート家電やロボットといった IoT の分野に興味を持ち、エンジニアとしてスマートロックやネットワーク AV 機器などの開発に携わってきました。
AWS では IoT ソリューションアーキテクトとして、主に工場やプラントへの IoT 導入を支援しています。
趣味は旅行で、特に目的もなく街を散策し、新たな発見をするのが好きです。

AWS のベストプラクティスを毎月無料でお試しいただけます

さらに最新記事・デベロッパー向けイベントを検索

下記の項目で絞り込む
1

AWS を無料でお試しいただけます

AWS 無料利用枠の詳細はこちら ≫
5 ステップでアカウント作成できます
無料サインアップ ≫
ご不明な点がおありですか?
日本担当チームへ相談する