오후에 나만의 스마트 홈을 구축하는 방법
Published: 2024-02-20 15:40:20

사물 인터넷(IoT)은 수년에 걸쳐 크게 변화했으며 스마트 홈은 점점 더 널리 보급되고 있습니다. 최신 기술의 발전으로 이제 주택 소유자는 정교한 보안 시스템부터 지능형 홈 비서에 이르기까지 다양한 스마트 홈 기술을 이용할 수 있게 되었습니다.

_홈팟과_ 같은 _Spotify 지원_ 스마트 스피커, _Z-Wave_ 및 _지그비_ 구동 장치와 함께 _SmartThings_ 및 _Apple HomeKit 호환_ 장치와 같은 새로운 제품과 기술이 등장했습니다. 라우터도 이제 스마트 홈을 지원합니다. 이러한 변화에도 불구하고 이 글은 스마트 홈 프로젝트 개발에 관심이 있는 모든 분들에게 여전히 유용한 인사이트를 제공합니다.

PubNub이 [전 세계 수천 명의 고객을](https://www.pubnub.com/customers/) 지원하는 방법에 대한 자세한 내용은 [개발자를 위한 PubNub](https://www.pubnub.com/developers/) 리소스에서 확인하세요. 또한 실제 환경에서 저희 제품의 효과를 보여주는 여러 고객 성공 사례도 확인할 수 있습니다. 이 글의 내용과 관련하여 제안이나 질문이 있으면 언제든지 [devrel@pubnub.com](mailto:devrel@pubnub.com) 으로 문의해 주세요.

오늘날 IoT 기술로 인해 [스마트 홈과 홈 오토메이션이](https://www.pubnub.com/industry/iot-and-connected-devices/) 더욱 보편화되었습니다. 이제 집주인들은 집 보안을 위해 Ring의 디바이스 제품군과 같은 고급 제품을 사용합니다. 여기에는 모션 센서, 비디오 초인종, 스마트 잠금장치, 스마트싱스 및 애플 홈키트 기반의 스마트홈 제품과 통합된 최첨단 보안 카메라 등이 포함됩니다.

스마트 홈 시스템은 집주인의 일상 생활에도 도움을 줄 수 있습니다. Nest 온도조절기와 같은 제품은 자동으로 온도를 조절할 수 있으며, Lenovo의 스마트 디스플레이와 같은 스마트 디스플레이는 개인화된 콘텐츠를 표시할 수 있습니다. 필립스 휴는 스마트 전구를 통해 전등 스위치를 제어할 수 있으며, 애플 홈팟과 스포티파이를 지원하는 Bose 제품은 스마트 스피커 기능을 제공합니다. 구글 홈, 아마존 알렉사, 아마존 에코, 시리 등의 개인 비서 기기를 통해 음성 제어 관리도 가능하며, 타이머 설정과 함께 다양한 IoT 기기를 쉽게 제어할 수 있습니다. 이 튜토리얼에서는 기존 스마트홈 기기의 방대한 목록에도 불구하고 PubNub을 사용하여 나만의 스마트홈 시스템을 개발하는 방법을 안내합니다.

PubNub은 IoT의 영역을 대중에게 더 가까이 다가가는 데 주력하고 있습니다. [실시간 데이터 API와](https://www.pubnub.com/learn/glossary/what-is-real-time-data/) [가상 공간 플랫폼으로](https://www.pubnub.com/learn/glossary/virtual-spaces/) 스마트 홈 허브를 강화할 수 있습니다. 3가지 스마트 홈 기술을 통해 직관적이고 효율적인 스마트 홈 시스템을 구축하는 방법을 살펴보세요.

스마트 홈 시스템 구축하기
--------------

스마트 홈과 일반 홈의 차이점은 무엇일까요? 두 가지 중요한 요소는 **자동화와** **중앙 집중**성입니다. 스마트 홈은 기본 작업을 자동화하고 중앙 위치(일반적으로 홈 앱)에서 양방향으로 정보를 전송할 수 있습니다. 이 튜토리얼에서는 PubNub를 사용하여 IoT의 이 두 가지 요소를 구현하고 다음 기술을 구축해 보겠습니다:

-   스마트 조명 - 조명 자동화
    
-   조명 감지기 - 데이터 중앙 집중화
    
-   열림감지기 - 데이터 중앙 집중화
    

요구 사항
-----

스마트 홈 시스템을 구성하는 이 세 가지 IoT 기술을 만들려면 다음과 같은 재료와 하드웨어가 필요합니다:

### 라즈베리 파이

IoT 기술을 프로그래밍하여 사용자와 집이 통신할 수 있도록 하려면 [마이크로컨트롤러가](https://www.techopedia.com/definition/3641/microcontroller) 필요합니다. 가장 사용하기 쉬운 마이크로컨트롤러 중 하나는 2022년 1월 현재 최신 버전의 [라즈베리](https://www.raspberrypi.com/products/) 파이인 라즈베리 파이 4입니다. 한 번도 설정해 본 적이 없다면 제품 웹사이트에서 [지침을](https://www.raspberrypi.org/documentation/setup/) 확인할 수 있습니다.

### 릴레이

라즈베리파이를 손상시킬 수 있는 고전압으로부터 보호하려면 [릴레이가](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)

### 은박지 및 와이어

도어 센서를 만들려면 패드가 접촉하면 전기가 통과할 수 있는 은박 접촉 패드를 사용해야 합니다. 이렇게 하면 문과 문틀에 패드를 부착하여 문이 닫힐 때마다 패드가 접촉하여 라즈베리파이에 문이 닫혔다는 것을 알릴 수 있습니다. 두 개의 은박 패드를 만들고 각 패드에 전선을 연결해야 합니다. 하나의 패드는 문에, 다른 하나는 페인트 테이프를 사용하여 프레임에 부착합니다.

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

이제 하드웨어 설정으로 넘어가겠습니다.

하드웨어 설정
-------

### 스마트 램프

일반 램프로 스마트 램프를 만들려면 전원 케이블을 두 부분으로 분리하고(물론 플러그를 뽑은 상태에서) 전선이 노출되도록 케이스의 일부를 벗겨내야 합니다. 모든 램프에는 전원 케이블(일반적으로 빨간색)과 접지 케이블(일반적으로 검은색)이 있습니다.

![](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 핀 중 하나에 연결합니다.

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

### 도어 센서

도어 센서의 경우 하나의 패드를 RPi의 GPIO 핀에 연결하고 다른 패드를 접지에 연결합니다(다이어그램에서 패드는 LED로 표시됨).

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

시스템 설계
------

PubNub 네트워크를 통해 정보를 전송하려면 게시/구독 키가 필요하므로 코드 구현을 시작하기 전에 무료 [PubNub 계정에](https://admin.pubnub.com/#/register) 가입하세요.

### SSH 활성화

보안 셸 프로토콜(SSH)을 사용하면 사용자가 WiFi를 통해 컴퓨터에서 RPi 단말기에 원격으로 액세스할 수 있습니다. GitHub로 보완하면 사용자는 컴퓨터에서 원격 리포지토리로 코드를 푸시하고, SSH를 통해 Pi 터미널에 접속하여 무선으로 코드를 가져올 수 있습니다. 이를 통해 더 빠르고 원활한 개발 프로세스를 진행할 수 있습니다.

RPi에서 SSH를 활성화하려면 [간단하고 빠른 지침을 따르세요](https://www.raspberrypi.org/documentation/remote-access/ssh/).

### 디바이스 라이브러리 및 종속성 다운로드

장치를 켜려면 RPI에서 1 또는 0의 출력 전압을 작동시켜야 합니다. 반대로, 센서는 습식 또는 건식 여부에 따라 RPi에 1 또는 0의 입력 전압을 제공합니다. 이 두 가지 기능 모두 RPi의 GPIO 핀을 사용해야 합니다.

파이썬으로 코딩할 것이므로 간단한 함수 호출을 통해 핀을 활성화하거나 읽을 수 있는 [GPIO Zero 라이브러리를](https://gpiozero.readthedocs.io/en/stable/) 설치하는 것이 유용할 것입니다.

_참고: 이러한 라이브러리는 장치에 SSH로 접속하여 아래 명령을 실행하여 RPi에 설치해야 한다는 점을 기억하세요._

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

### PubNub로 앱 빌드하기

[이 프로젝트의 전체 코드는 이 리포지토리에 있으니 참고하세요.](https://github.com/PubNubDevelopers/beginner-smarthome) 센서를 인터넷에 연결하는 파이썬 스크립트를 만듭니다. 즐겨 사용하는 텍스트 편집기에서 새 문서를 열고 라이브러리 및 기타 종속 요소를 가져와서 장치가 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)
#--------------------------------------------#
```

어떤 장치가 어떤 핀에 연결되어 있는지 라즈베리파이에 알려주어야 합니다:

```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처럼 제어하고 싶기 때문에 LED로 선언합니다. 센서는 버튼이 누르거나 누를 때와 같은 방식으로 일정한 활성 신호를 출력하므로 버튼으로 초기화됩니다. 이것이 바로 센서 및 장치와 쉽게 인터페이스할 수 있는 GPIO Zero 라이브러리의 마법입니다._

또한 카운터 변수를 생성하여 문이 몇 번 열렸는지 알 수 있도록 해야 합니다:

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

IoT 램프가 클라이언트와 상호 작용하려면 PubNub의 양방향 pub/sub 기능을 활용해야 합니다. 이를 위해서는 수신 메시지를 관리할 리스너를 추가하고 특정 채널에서 수신 대기하도록 구독을 구성해야 합니다.

```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는` 수신되는 프레즌스 데이터를 처리하고 `메시지는` 램프 명령을 처리합니다. 클라이언트가 "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()
```

메시지 이벤트 핸들러를 기록해 두세요. 프로그램이 애플리케이션 클라이언트로부터 메시지를 받을 때마다 `message.message를` 사용하여 메시지를 구문 분석합니다. 그런 다음 if 문을 사용하여 이벤트 핸들러를 생성하여 GPIO 명령 `.on()` 또는 `.off()` 를 사용하여 램프를 켜거나 끕니다.

마지막으로 메시지가 클라이언트에 다시 게시되면 사용자에게 요청이 성공적으로 실행되었음을 알립니다. 이 경우 램프가 켜져 있는지 또는 꺼져 있는지 여부를 클라이언트에 알립니다.

이 섹션은 선택 사항이지만(이 프로그램에서는 사용하지 않으므로) 메시지가 게시될 때마다 함수를 실행하는 게시자 콜백을 만들 수 있습니다.

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

프로그램의 마지막 세그먼트는 센서 입력을 지속적으로 확인하여 센서가 감지하는 것이 있는지 확인합니다. 일종의 '라우터'인 메인 while 루프는 입력을 반복적으로 확인합니다: while True:\`입니다. 이 메인 동안 루프 내에서 서브 동안 루프를 구성하여 센서를 구체적으로 폴링할 수 있습니다. 센서가 GPIO Zero 라이브러리에서 버튼으로 초기화되었으므로 '.is\_held' 함수가 필요합니다.

버튼을 사용하지 않더라도 센서가 활성화되어 있을 때(즉, 무언가를 감지할 때) 동일한 '버튼을 누르고 있는 신호'를 시뮬레이션하므로 센서가 버튼인 것처럼 작동합니다. 도어 센서와 조명을 폴링하여 상태를 확인하는 몇 가지 코드 조각이 있습니다. 센서가 활성화되면 센서가 켜져 있는지 또는 꺼져 있는지 알려주는 메시지가 클라이언트에 다시 게시됩니다. 유사한 원리를 SmartThings, Apple HomeKit 장치 또는 HomePod와 같은 다른 스마트 홈 제품에도 적용하여 스마트 홈의 기능을 크게 확장할 수 있습니다.

### 코드 업로드하기

라즈베리파이에 코드를 업로드하려면 항상 코드를 저장소에 커밋한 다음 라즈베리파이로 가져옵니다. 터미널을 열고 작업 디렉토리를 입력한 다음 다음 명령을 사용하여 코드를 클라우드에 커밋합니다.

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

라즈베리 파이에 SSH로 접속하여 적절한 디렉터리로 이동합니다.

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

그런 다음 클라우드에서 코드를 가져와 실행합니다. 기다리는 동안 좋아하는 Spotify 재생 목록을 듣거나 작업에 대한 타이머를 설정하는 시간을 가져보세요. 멀티태스킹의 효율성은 연결된 세상의 아름다움 중 하나입니다!

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

### PubNub로 클라이언트 구축하기

다음으로 휴대폰이나 컴퓨터를 사용하여 센서와 데이터를 주고받을 수 있는 클라이언트 스크립트를 작성해야 합니다. 이를 위해서는 라즈베리파이에 명령을 게시하는 버튼과 라즈베리파이에서 데이터를 검색하는 텍스트 상자를 사용하는 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);
        });
      }
```

마지막으로, 라즈베리파이가 광센서 데이터를 게시하는 채널을 수신합니다. 다음 코드 블록으로 리스너를 인스턴스화할 수 있습니다:

```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)

이제 라즈베리파이에서 간단한 스마트 홈 장치 세 개를 구현하는 작업을 완료했습니다! 라즈베리 파이에 ssh로 접속하여 파이썬 코드를 실행한 다음 클라이언트 프로그램과 상호 작용하여 코드를 테스트해 보세요. 두 개의 버튼으로 스마트 램프를 제어할 수 있을 뿐만 아니라 문이 열려 있거나 조명이 켜져 있는지 문자 메시지를 확인할 수 있을 것입니다. 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) 문의해 주세요.