午後のひとときでスマートホームを構築する方法
Published: 2024-02-20 15:35:19

モノのインターネット（IoT）は年々大きく変化し、スマートホームはますます普及している。最新の進歩により、住宅所有者は高度なセキュリティ・システムからインテリジェントなホーム・アシスタントまで、さまざまなスマートホーム技術を利用できるようになった。

_SmartThingsや_ _Apple HomeKit対応_デバイスに加え、_HomePodの_ような_Spotify対応_スマートスピーカー、_Z-Waveや_ _Zigbee_搭載デバイスなど、新しい製品や技術が登場している。ルーターでさえ、スマートホームをサポートするようになった。このような変化があったにもかかわらず、この記事はスマートホームプロジェクトの開発に興味がある人にとって貴重な洞察を提供している。

PubNubがどのように[世界中の何千もの顧客を](https://www.pubnub.com/customers/)サポートしているかについては、[PubNub for Developersの](https://www.pubnub.com/developers/)リソースで詳細をご覧ください。また、現実世界での私たちのオファリングの有効性を説明するいくつかの顧客の成功事例を見つけることができます。本記事の内容に関するご提案やご質問は、[devrel@pubnub.com](mailto:devrel@pubnub.com)までお気軽にお寄せください。

現在、IoT技術により、[スマートホームやホームオートメーションが](https://www.pubnub.com/industry/iot-and-connected-devices/)一般的になりました。ホームオーナーは現在、ホームセキュリティのためにRingの一連のデバイスのような高度な製品を使用している。この製品群には、人感センサー、ビデオドアベル、スマートロック、そしてSmartThingsやApple HomeKitを搭載したスマートホーム製品と統合された最先端のセキュリティカメラが含まれる。

スマートホームシステムは、住宅所有者の日常生活を支援することもできる。Nest Thermostatのような製品は温度を自動調節でき、LenovoのSmart Displayのようなスマートディスプレイはパーソナライズされたコンテンツを表示できる。Philips Hueは、スマート電球を通して照明スイッチをコントロールすることを可能にし、Apple HomePodやSpotify対応のBose製品はスマートスピーカー機能を提供する。Google Home、Amazon Alexa、Amazon Echo、Siriのようなパーソナル・アシスタント・デバイスを使った音声制御管理も可能で、タイマーの設定とともに様々なIoTデバイスの制御を容易にする。既存のスマートホームデバイスのリストは膨大ですが、このチュートリアルではPubNubを使って独自のスマートホームシステムを開発する方法を説明します。

PubNubでは、IoTの領域を大衆に近づけることを専門としています。当社の[リアルタイムデータAPIと](https://www.pubnub.com/learn/glossary/what-is-real-time-data/) [Virtual Spaces Platformを](https://www.pubnub.com/learn/glossary/virtual-spaces/)利用すれば、PubNubにスマートホームハブを任せることができます。3つのスマートホームテクノロジーで、直感的で効率的なスマートホームシステムを構築する方法を探ってみましょう。

スマートホームシステムを構築しよう
-----------------

スマートホームと普通のホームの違いは何だろう？2つの重要な要素、**自動**化と**中心性**だ。スマートホームは基本的なタスクを自動化し、中央の場所（通常はホームアプリ）から情報を双方向に送信できる。このチュートリアルでは、PubNubを使ってIoTのこの2つの柱を実装し、以下の技術を構築します：

-   スマートライト - ライトの自動化
    
-   光検出器 - データの集中化
    
-   ドア検知器 - データの一元化
    

必要条件
----

スマート・ホーム・システムを構成するこれら3つのIoT技術を構築するには、以下の材料とハードウェアが必要です：

### ラズベリーパイ

IoT技術をプログラムし、あなたとあなたの家の間で通信できるようにするには、[マイクロコントローラーが](https://www.techopedia.com/definition/3641/microcontroller)必要です。最も使いやすいマイコンの1つは、[Raspberry Piの](https://www.raspberrypi.com/products/)最新バージョンで、2022年1月現在、Raspberry Pi 4です。初めてセットアップする場合は、製品のウェブサイトに[手順が](https://www.raspberrypi.org/documentation/setup/)掲載されている。

### リレー

高電圧からRaspberry Piを保護するために、[リレーが](https://en.wikipedia.org/wiki/Relay)必要です。リレーは基本的に、大電流と大電圧に対応できるスイッチなので、RPiはその必要はありません。

![](https://www.pubnub.com/cdn/3prze68gbwl1/asset-17suaysk1qa1jfx/798b2af320f8250dbc8ce0de8bd57659/image4-1024x400.png)

### ランプ

スマート・ランプを作るには、シンプルで安価なランプが必要です。

### フォトトランジスタ

スマート光センサーを作るには、[フォトトランジスター](https://www.electronics-notes.com/articles/electronic_components/transistor/what-is-a-phototransistor-tutorial.php)が必要です。この部品はスイッチとして機能し、光があるときだけ電流を流すので、家の電気がついているかどうかを判断する理想的なセンサーとなる。

![](https://www.pubnub.com/cdn/3prze68gbwl1/asset-17suaysk1qa1jfy/e1a23b21d6c4ebae2e8564dba4fa99ea/image1-1024x768.png)

### 錫箔と針金

ドア・センサーを作るには、接触すると電気が流れる錫箔の接触パッドを使う必要がある。このパッドをドアとドア枠に取り付けると、ドアが閉まるたびにパッドが接触し、ドアが閉まったことをRaspberry Piに知らせることができます。錫箔パッドを2つ作り、それぞれのパッドにワイヤーを接続する。片方のパッドをドアに、もう片方を枠に画鋲で貼り付けます。

![](https://www.pubnub.com/cdn/3prze68gbwl1/2E3nPnFTq0dJS77tTCxdGt/a40b63f3c1130fcef370ff8945ee8953/iot-tin-foil-prep.png)

それでは、ハードウェアのセットアップに進みましょう。

ハードウェアのセットアップ
-------------

### スマート・ランプ

普通のランプからスマート・ランプを作るには、電源ケーブルを2つにつなぎ（もちろんプラグを抜いた状態で）、ケーシングの一部を剥がしてワイヤーを露出させる必要がある。どのランプにも、電源ケーブル（通常は赤）とアースケーブル（通常は黒）がある。

![](https://www.pubnub.com/cdn/3prze68gbwl1/3X0oSvQDbmvFgd8N9hFwO8/863deb74f4c162236b1c213266929df9/IoT_Splice_Power_Cable.png)

次にリレーを手に取り、アース線を元通りに接続し、電源線の一端をリレーのNO（ノーマルオープン）ポートに、もう一端をリレーのNC（ノーマルクローズ）ポートに接続します。

![](https://www.pubnub.com/cdn/3prze68gbwl1/7k8iovdFS1eXjN4W6JWvNr/259aa20723db1ac47dbe1d3371ed42c3/IoT_Relay_Connections.png)

次に、ランプ・リレー・モジュールをRPiに接続するために、それらをRPiのGPIOピンに接続する。

![](https://www.pubnub.com/cdn/3prze68gbwl1/asset-17suaysk1qa1jg3/f16339a7dabec603ee165f67f535ece1/image8-1024x601.png)

### 光センサー

光センサー回路の実装はもっと簡単です。フォトトランジスタをRPIのGPIOピンの1つに配線する。

![](https://www.pubnub.com/cdn/3prze68gbwl1/asset-17suaysk1qa1jg4/f0789c8071f37ec279a90dafc868118c/image10-1024x904.png)

### ドアセンサー

ドアセンサーは、1つのパッドをRPiのGPIOピンに配線し、もう1つのパッドをグラウンドに配線します（図ではパッドをLEDに見立てています）。

![](https://www.pubnub.com/cdn/3prze68gbwl1/asset-17suaysk1qa1jg5/9a1f1a3135aaf16f027810de40443f68/image2-1024x894.png)

システムの設計
-------

後ろのコードを実装し始める前に、無料の[PubNubアカウントに](https://admin.pubnub.com/#/register)サインアップしてください。PubNubネットワークを介して情報を送信するには、発行/購読キーが必要になります。

### SSHを有効にする

Secure Shellプロトコル（SSH）により、ユーザーはWiFi経由でコンピュータからRPi端末にリモートアクセスできるようになります。GitHubで補完すれば、ユーザーは自分のコンピュータからリモートリポジトリにコードをプッシュし、SSHでPi端末にアクセスし、ワイヤレスでコードを引き出すことができます。これにより、より迅速でスムーズな開発プロセスが可能になる。

RPiでSSHを有効にするには、[簡単で素早い手順に従って](https://www.raspberrypi.org/documentation/remote-access/ssh/)ください。

### デバイスライブラリと依存関係のダウンロード

私たちのデバイスの場合、RPIから1または0の出力電圧を操作してオンにする必要があります。逆に、センサーは、濡れているか乾いているかによって、1または0の入力電圧をRPiに与えます。どちらの機能も、RPiのGPIOピンを使用する必要があります。

Pythonでコーディングするので、ピンをアクティブにしたり読み込んだりする簡単な関数呼び出しができる[GPIO Zeroライブラリを](https://gpiozero.readthedocs.io/en/stable/)インストールしておくと便利です。

_注：これらのライブラリは、デバイスにSSH接続して以下のコマンドを実行してRPiにインストールする必要があることを忘れないでください。_

```js
sudo apt install python-gpiozero
```

### PubNubを使ってアプリをビルドする

[このプロジェクトの完全なコードは参考のためにこのリポジトリに](https://github.com/PubNubDevelopers/beginner-smarthome)あります。 センサーをインターネットに接続するためのpythonスクリプトを作成します。お気に入りのテキストエディタで新しいドキュメントを開き、デバイスがPubNubネットワーク上で通信できるようにするためのライブラリやその他の依存関係をインポートします。

```js
#---------------Library Setup----------------#
import pubnub
from pubnub.pnconfiguration import PNConfiguration
from pubnub.pubnub import PubNub
from pubnub.callbacks import SubscribeCallback
from pubnub.enums import PNOperationType, PNStatusCategory
 
from gpiozero import Button, LED
from time import sleep
 
#--------------------------------------------#
 
 
 
 
#----------------PubNub Setup----------------#
pnconfig = PNConfiguration()
pnconfig.subscribe_key = "YOUR SUBSCRIBE KEY"
pnconfig.publish_key = "YOUR PUBLISH KEY"
pnconfig.ssl = False
pubnub = PubNub(pnconfig)
#--------------------------------------------#
```

どのデバイスがどのピンに接続されているかをRaspberry Piに伝える必要があります：

```js
#------------Sensor Declarations-------------#
#lamp is connected to GPIO4 as an LED
lamp = LED(4)
 
#door sensor is connected to GPIO3 as a Button
door_sensor = Button(3)
#light sensor is connected to GPIO14 as a Button
light = Button(14)
#--------------------------------------------#
```

_注意: ランプはLEDとして宣言されています。センサーはボタンとして初期化されます。ボタンが押されたとき、または押されたときと同じように、一定のアクティブ信号を出力するからです。これは、センサーやデバイスと簡単にインターフェースできるGPIO Zeroライブラリーのマジックです。_

また、ドアが何回開けられたかを知るために、カウンタ変数を作成する必要があります：

```js
#door counter
doorCount = 0
```

IoTランプがクライアントとやりとりするためには、PubNubの双方向パブ／サブ機能を利用する必要がある。そのためには、受信メッセージを管理するリスナーを追加し、特定のチャンネルをリッスンするサブスクリプションを設定する必要があります。

```js
class MySubscribeCallback(SubscribeCallback):
    def status(self, pubnub, status):
        # The status object returned is always related to subscribe but could contain information about subscribe, heartbeat, or errors
        # use the operationType to switch on different options
        if status.operation == PNOperationType.PNSubscribeOperation or status.operation == PNOperationType.PNUnsubscribeOperation:
            if status.category == PNStatusCategory.PNConnectedCategory:
                # This is expected for a subscribe, this signifies no error or issue exists
            elif status.category == PNStatusCategory.PNReconnectedCategory:
                # This usually occurs if subscribe temporarily fails but reconnects. This indicates there was a temporary error but it has already been resolved
            elif status.category == PNStatusCategory.PNDisconnectedCategory:
                # This is the expected category for an unsubscribe. This means there was no error in unsubscribing from everything
            elif status.category == PNStatusCategory.PNUnexpectedDisconnectCategory:
                # This is usually an issue with the internet connection, this is an error, handle appropriately. A retry will be initiated automatically.
            elif status.category == PNStatusCategory.PNAccessDeniedCategory:
                # This indicates that PAM does not permit this client to subscribe to this channel and channel group configuration. This constitutes a specific error
            else:
                # This is usually an issue with the internet connection, this is an error, handle appropriately. A retry will be initiated automatically.
        elif status.operation == PNOperationType.PNSubscribeOperation:
            # Heartbeat operations can indeed encounter errors, so it is essential to verify if there's an error first. For more detailed information on how to configure heartbeat notifications through the status PNObjectEventListener callback, please refer to [PNConfiguration heartbeat config](https://www.pubnub.com/docs/sdks/javascript/api-reference/pn-configuration)
            if status.is_error():
                # There was an error with the heartbeat operation, handle here
            else:
                # Heartbeat operation was successful
        else:
            # Encountered unknown status type
```

上記のコールバックでは、`presenceは`受信プレゼンスデータを処理し、`messageは`Lampコマンドを処理します。クライアントが "ON "というメッセージを送信した場合、ランプを点灯させる。逆に、メッセージが "OFF "であれば、ランプをオフにする。

```js
def presence(self, pubnub, presence):
    pass  # handle incoming presence data
 
def message(self, pubnub, message):
    #message handler for Lamp commands
    #Turn the lamp on if client receives the message “ON”
    if message.message == 'ON':
        lamp.on()
        #let your subscriber client know that the lamp has been turned on
        pubnub.publish().channel('ch1').message("lamp has been turned on").sync()
        sleep(3)
    #Turn the lamp on if client receives the message “OFF”
    elif message.message == 'OFF':
        lamp.off()
        #let your subscriber client know that the lamp has been turned off
        pubnub.publish().channel('ch1').message("lamp has been turned off").sync()
```

次に、プログラムが`MySubscribeCallback()`を追加し、選択したチャンネル（この場合は "ch1"）にサブスクライブしていることを確認する。

```js
pubnub.add_listener(MySubscribeCallback())
#make sure to subscribe to the channel of your choice. In this case, we chose to create a channel called “ch1” to publish to
pubnub.subscribe().channels('ch1').execute()
```

メッセージ・イベント・ハンドラに注意してください。Whenever your program receives a message from the application client, you parse the message using`message.message`.そして、GPIOコマンド`.on()`または`.off()`でランプをオンまたはオフにするために、if文を使ってイベント・ハンドラを作成します。

最後に、メッセージがクライアントにパブリッシュバックされると、ユーザはリクエストが正常に実行されたことを知らされます。この場合、ランプが点灯しているか消灯しているかをクライアントに知らせます。

このセクションはオプションですが（このプログラムでは使用しないため）、パブリッシャーコールバックを作成し、メッセージが発行されるたびに関数を実行することができます。

```js
def publish_callback(result, status):
    pass
    # Handle PNPublishResult and PNStatus
```

プログラムの最後のセグメントでは、センサーが何かを検知したかどうかを判別するために、センサーの入力を継続的にチェックします。ルーター'のようなもので、メインの while ループは繰り返し入力をチェックします：while True:\`。このメインのwhileループの中で、サブのwhileループを構築して、センサーを特別にポーリングすることができる。センサーはGPIO Zeroライブラリーのボタンとして初期化されているので、関数 \`.is\_held\` が必要です。

ボタンを使っていないにもかかわらず、センサーはボタンであるかのように動作します。センサーがアクティブなとき（つまり何かを検知しているとき）、同じ「ボタンを押し続けている信号」をシミュレートするからです。ドアセンサーとライトをポーリングし、ステータスをチェックするコードがいくつかある。センサーがアクティブであれば、センサーがオンかオフかを知らせるメッセージがクライアントに返される。同様の原理は、SmartThings、Apple HomeKitデバイス、あるいはHomePodなど、他のスマートホーム製品にも適用でき、スマートホームの機能を大幅に拡張することができます。

### コードのアップロード

コードをRaspberry Piにアップロードするには、必ずコードをリポジトリにコミットしてからRaspberry Piにプルします。ターミナルを開き、作業ディレクトリを入力し、以下のコマンドを使用してコードをクラウドにコミットします。

```js
git add .
git commit -m "updates"
git push
```

SSH で Raspberry Pi にログインし、適切なディレクトリに移動します。

```js
ssh pi@<YOUR IP ADDRESS>
cd <your directory>
```

そして、クラウドからコードを取り出して実行する。待っている間に、お気に入りのSpotifyのプレイリストを聴いたり、タスクにタイマーをセットしたりする時間が取れるかもしれない。マルチタスクの効率は、つながった世界の美しさのひとつだ！

```js
git pull
python <Your program>.py
```

### PubNubでクライアントを構築する

次に、携帯電話やコンピューターを使ってセンサーとデータを送受信できるようにするためのクライアント・スクリプトを構築する必要がある。そのためには、ボタンを使ってRaspberry Piにコマンドを発行し、テキストボックスを使ってRaspberry Piからデータを取得するHTMLファイルを作成する必要があります。これは簡単なHTMLスクリプトと、いくつかのボタン、IDタグ、PubNub JavaScript SDKの追加で実現できる。このシステムは、Z-WaveやZigBeeを含む様々なプロトコルと統合するのに十分な柔軟性を持っており、開発のための新たな分野を切り開くことができる。

```js
<!DOCTYPE html>
<html>
  <body>
    <button type="button" onclick="publish('ON')">Lamp ON</button>
    <button type="button" onclick="publish('OFF')">Lamp OFF</button>
    <p id="lights">Lights are on?</p>
    <script src="https://cdn.pubnub.com/sdk/javascript/pubnub.4.20.2.js"></script>
    <script>
    var pubnub = new PubNub({
      publishKey : 'pub-c-2d8f55f6-daa7-467b-923b-6a1e6570c9fc',
      subscribeKey : 'sub-c-1575c412-2116-11e8-a7d0-2e884fd949d2',
      });
      function publish(a){
        var publishConfig = 
        {
          channel : "ch1",   //Your publishing channel name
          message : a
        };
        pubnub.publish(publishConfig, function(status, response){
          console.log(status, response);
        });
      }
```

最後に、Raspberry Piが光センサーのデータを公開しているチャンネルをリッスンします。以下のコードでリスナーをインスタンス化できる：

```js
    pubnub.addListener({
            message: function(m) {
                // handle message
                var channelName = m.channel; // The channel for which the message belongs
                var channelGroup = m.subscription; // The channel group or wildcard subscription match (if exists)
                var pubTT = m.timetoken; // Publish timetoken
                var msg = m.message; // The Payload
                var publisher = m.publisher; //The Publisher
                document.getElementById("lights").innerHTML = msg;
                console.log(msg);
            },
            presence: function(p) {
                // handle presence
                var action = p.action; // Can be join, leave, state-change or timeout
                var channelName = p.channel; // The channel for which the message belongs
                var occupancy = p.occupancy; // No. of users connected with the channel
                var state = p.state; // User State
                var channelGroup = p.subscription; //  The channel group or wildcard subscription match (if exists)
                var publishTime = p.timestamp; // Publish timetoken
                var timetoken = p.timetoken;  // Current timetoken
                var uuid = p.uuid; // UUIDs of users who are connected with the channel
            },
            status: function(s) {
                var affectedChannelGroups = s.affectedChannelGroups;
                var affectedChannels = s.affectedChannels;
                var category = s.category;
                var operation = s.operation;
            }
        });
        pubnub.subscribe({
            channels: ['ch2'],
            
        });
    </script>
  </body>
</html>
```

ch2を購読していることに注意してください。これは、光センサー・データ専用のチャンネルが欲しいからで、他のセンサーとデータを区別する必要はない。もし以前のアプリケーション・プロセスで専用チャンネルにパブリッシュするのを忘れていたら、必ず戻ってパブリッシュしてください。

スクリプトを保存したら、そのファイルをウェブブラウザで開くと、このようになっているはずです：

![](https://www.pubnub.com/cdn/3prze68gbwl1/asset-17suaysk1qa1jg6/06a91807b15406afcdf3499f565d6c1d/image7-1024x431.png)

これで、Raspberry Piに3つのシンプルなスマートホームデバイスを実装することができました！Raspberry Piにsshログインしてpythonコードを実行し、クライアントプログラムとやりとりしてコードをテストしてみましょう。2つのボタンでスマートランプを操作したり、ドアが開いていたり電気がついていたりすると、テキストプロンプトが表示されるはずです。これでPubNubで通信するコネクテッドデバイスを使ったスマートホームシステムの作成は成功です。

IoTアプリケーションやスマートホームシステムのパワーアップ方法についてもっと知りたい方は、IoTリソースをご覧ください。

-   [リアルタイムIoTダッシュボードのデモを見る](https://www.pubnub.com/demos/iot-dashboard/)
    
-   [IoTソリューションの開発方法](https://www.pubnub.com/how-to/develop-an-iot-solution/)
    
-   [PubNubを使用したIoTソリューションの構築](https://www.pubnub.com/tutorials/iot-dashboard/)
    
-   [IoT通信を保護するための5つの要件](https://www.pubnub.com/resources/whitepaper/5-key-requirements-to-securing-iot-communications/)
    
-   [MQTT](https://www.pubnub.com/guides/mqtt/)
    

その他ご質問やご不明な点がございましたら、devrel@pubnub.com[まで](mailto:devrel@pubnub.com)お気軽にお問い合わせください。