실시간 공간 추적 기능을 갖춘 지능형 주차 시스템
Published: 2024-01-11 12:13:54

모든 '사물'이 인터넷으로 원활하게 연결될 수 있는 시대에 살고 있습니다. [사물 인터넷(IoT)](https://www.pubnub.com/solutions/iot-device-control/) 이라는 개념은 **이벤트 기반 펍/서브 아키텍처를** 사용하여 수많은 문제에 대한 혁신적인 솔루션을 제시함으로써 세상을 지속적으로 변화시켜 왔습니다. 예를 들어, 혼잡한 공간에서 주차 공간을 찾느라 지친 문제를 해결하기 위해 주차장에서는 주차장의 개별 센서에서 게시되는 상태 업데이트를 구독하여 사용 가능한 공간을 보여주는 실시간 전자 대시보드를 설치했습니다. 이러한 IoT 앱을 구축하는 것은 여러 가지 장애물로 인해 어려울 수 있습니다.

이러한 장애물 중 하나는 모바일 앱과 센서 디바이스 간에 전송되는 메시지를 실시간으로 처리할 수 있는 서버를 호스팅하는 것입니다. 또 하나는 스마트 주차장의 모든 임베디드 센서 디바이스를 지원할 수 있는 Wi-Fi 네트워크를 호스팅하는 것입니다.

하지만 **PubNub과** **Soracom을** 함께 사용하면 개발자는 이러한 문제를 빠르게 해결할 수 있습니다. PubNub의 실시간 플랫폼을 사용하면 개발자는 서버 호스팅과 같은 지루한 작업에 대한 걱정 없이 [차량 모니터링을](https://www.pubnub.com/solutions/transport-delivery/) 위한 [복잡한 IoT 솔루션을](https://www.pubnub.com/solutions/iot-device-control/) 쉽게 [구축할](https://www.pubnub.com/solutions/iot-device-control/) 수 있습니다. 또한 [소라콤 에어와](https://www.soracom.io/products/air/) [소라콤 빔을](https://www.soracom.io/products/beam/) 사용하면 개발자는 제한적인 WFI 네트워크 대신 LTE를 활용하는 IoT 솔루션을 쉽게 구축할 수 있습니다.

튜토리얼 개요
-------

이 튜토리얼에서는 라즈베리파이와 초음파 센서를 사용하여 주차 공간이 비어 있는지 여부를 감지하는 스마트 주차 시뮬레이션을 구축합니다. 소라콤 에어를 사용하여 센서에서 셀룰러 데이터를 통해 PubNub로 메시지를 전송합니다. 그런 다음 PubNub의 게시-구독 API를 사용하여 앱의 모든 모바일 사용자가 실시간 주차 데이터를 즉시 사용할 수 있도록 합니다. 이는 다음 다이어그램에 나와 있습니다.

* * *

**전체 소스 코드를 보려면 [여기를 클릭하세요](https://github.com/PubNubDevelopers/Smart-Parking)**.

* * *

[![Smart Parking Lot](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1ja5/9d106e47efa5221bc12537d32cfa2d3a/screenshot.png "Smart Parking Lot")](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1ja5/9d106e47efa5221bc12537d32cfa2d3a/screenshot.png)

이 데모를 빌드하려면 다음이 필요합니다:

1.  라즈베리파이(모든 버전)
2.  브레드보드
3.  HC-SR04 초음파 센서
4.  암-암 1개 + 수-암 6개 점퍼 전선
5.  **1k Ω** 저항 1개 및 **2k Ω** 저항 1개
6.  MicroSD 카드 + MicroSD - SD 어댑터
7.  화웨이 USB 스틱 모뎀
8.  소라콤 에어 심 카드

라즈베리 파이 설정
----------

### **1\. 라즈비안 OS 설치**

아직 설치하지 않으셨다면, 라즈베리파이에 라즈비안 OS를 설치해야 합니다. 이를 위해 먼저 컴퓨터에 로컬로 설치합니다. 이것은 디스크 이미지 형식이므로 사용하기 전에 디스크를 플래시해야 합니다. [에처를](https://www.balena.io/etcher/) 사용해 디스크를 마이크로SD 카드 어댑터에 플래시할 수 있습니다.

[![Smart Parking Lot](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1ja6/56bde9961fc7faffc78d276cc5dd8916/Screen-Shot-2018-07-31-at-12.47.07-PM.png "Smart Parking Lot")](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1ja6/56bde9961fc7faffc78d276cc5dd8916/Screen-Shot-2018-07-31-at-12.47.07-PM.png)

라즈비안 OS 파일이 마이크로SD 카드 어댑터에 저장되면, 어댑터에서 마이크로SD 카드를 제거한 다음 라즈베리파이의 하단 슬롯에 삽입할 수 있습니다. OS가 설치되었으면 이제 키보드, 마우스, 모니터, 전원을 연결하여 라즈베리파이를 부팅할 수 있습니다.

### 2\. 센서 구성하기

[![Smart Parking Lot](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1ja7/9791eceb9d4aa6d43903901e40097b21/Screen-Shot-2018-07-31-at-1.45.55-PM.png "Smart Parking Lot")](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1ja7/9791eceb9d4aa6d43903901e40097b21/Screen-Shot-2018-07-31-at-1.45.55-PM.png)

1.  **암-수 점퍼 와이어** 3개를 **HC-SR04 초음파 센서의** **VCC, 에코 및 GND 슬롯에 꽂습니다.** **암-수 점퍼 와이어** 중 하나를 센서의 **Trig** 슬롯에 꽂습니다.
2.  **VCC** **와이어를** 브레드보드의 **양극 레일에** 연결하고 **GND** **와이어를** 음극 **레일에** 연결합니다.
3.  라즈베리파이의 **GPIO 5V를** 브레드보드의 **양극 레일에** 연결하고, **GPIO GND를** 음극 **레일에** 연결합니다.
4.  **Trig 와이어를** **GPIO 23에** 연결합니다.
5.  **에코 와이어를** 브레드보드의 **빈 레** 일에 꽂습니다.
6.  **1kΩ 저항을** 사용하여 다른 블랭크 레일을 연결합니다. (저항이 필요한 이유는 센서 구성으로 인해 라즈베리파이가 손상되지 않도록 전압 출력을 낮추기 위해서입니다.)
7.  그런 다음 **2kΩ 저항을** 사용하여 빈 레일을 브레드보드의 음극 레일에 연결하고 공간을 남겨 둡니다. 2k Ω 저항이 없는 경우 다음 그림과 같이 1k Ω 저항 2개를 연속으로 만들 수 있습니다.[![IMG_20180731_151118-1](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1ja9/1c9c8a5ed42e0d91b802e6dd117bcd1a/IMG_20180731_151118-1.jpg "IMG_20180731_151118-1")](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1ja8/3f8e169838914d011b94fa213f65b1b7/IMG_20180731_151118-1.jpg)
8.  남은 공간에는 **수-암 점퍼 와이어를** 사용하여 **GPIO 24에** 연결합니다.

이제 초음파 센서의 구성을 완료했습니다. 센서 구성이 막막하다면 이 [튜토리얼에서](https://thepihut.com/blogs/raspberry-pi-tutorials/hc-sr04-ultrasonic-range-sensor-on-the-raspberry-pi) 더 자세한 설명을 확인하세요. 회로를 구축하는 동안 [브레드보드의](https://en.wikipedia.org/wiki/Breadboard) 빈 레일에서는 전류가 수평으로 흐르고 브레드보드의 양극 및 음극 레일에서는 전류가 수직으로 흐른다는 점을 기억하세요. 다음으로 PubNub과 Soracom을 IoT 앱에 설정하겠습니다.

PubNub 설정
---------

먼저 [PubNub 관리자 콘솔에서](https://dashboard.pubnub.com/login) 앱을 생성합니다**(무료**). 콘솔에서 앱을 생성하면 다음 단계에서 PubNub과 Soracom을 연결하는 데 사용할 게시 및 구독 키가 표시됩니다.

소라콤 설정
------

### **SIM 등록**

[소라콤 관리자 콘솔로](https://console.soracom.io/) 이동합니다. 여기에서 **SIM 등록을** 클릭하고 **소라콤 에어 심 카드** 뒷면에서 찾을 수 있는 **ICCID** 및 **PUK** 숫자를 입력합니다.

[![imageedit_2_3979299183](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1jab/26b73ca8e719f9eaf8cc42ea2c631087/imageedit_2_3979299183.png "imageedit_2_3979299183")](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1jaa/2dcb1f4a63420c662d7dbcf859027a23/imageedit_2_3979299183.png)[![Smart Parking Lot](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1jac/d927cf8efc47161a592fd4ea756a69d5/Screen-Shot-2018-07-31-at-3.47.58-PM.png "Smart Parking Lot")](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1jac/d927cf8efc47161a592fd4ea756a69d5/Screen-Shot-2018-07-31-at-3.47.58-PM.png)

### USB 모뎀 구성

SIM 카드를 등록한 후 SIM 칩을 제거합니다(위 이미지에서 주위에 그려진 보라색 원으로 표시됨). 그런 다음 **Huawei USB 스틱 모뎀에** 삽입합니다. SIM 카드가 위를 향하도록 올바른 방향으로 끝까지 밀어 넣었는지 확인하세요.

[![Smart Parking Lot](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1jad/dddd1f8435888122020be80479bfe8de/Screen-Shot-2018-08-01-at-11.21.56-AM.png "Smart Parking Lot")](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1jad/dddd1f8435888122020be80479bfe8de/Screen-Shot-2018-08-01-at-11.21.56-AM.png)

라즈베리파이가 셀룰러 데이터로 실행되도록 하기 위해, [화웨이 USB 스틱 모뎀을](https://consumer.huawei.com/en/routers/e3372/specs/) 라즈베리파이의 USB 포트에 꽂기만 하면 됩니다. **파란색** 표시등이 깜박이지 않으면 모뎀이 3G 데이터를 성공적으로 수신하고 있음을 나타냅니다. 깜박이면 여전히 연결을 시도 중이라는 뜻입니다.

[![IMG_20180801_141334](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1jaf/445f100919feb6626cc4f1167b36f290/IMG_20180801_141334.jpg "IMG_20180801_141334")](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1jae/a9574a8b0e9a08f80e430d03605c3bbd/IMG_20180801_141334.jpg)

파란색 불빛이 계속 켜져 있으면 USB 스틱 모뎀을 라즈베리파이의 네트워크 매니저에 추가해야 합니다. 이렇게 하려면 먼저 라즈베리파이에 네트워크 매니저를 설치합니다. 라즈베리파이의 터미널에 다음을 입력합니다.

```js
sudo apt-get update && sudo apt-get install network-manager
```

그런 다음 USB 스틱 모뎀을 소라콤 계정에 연결하려면 라즈베리 파이 터미널에서 다음 명령을 입력해야 합니다. **<ENTER\_USERNAME>과** **<ENTER\_PASSWORD>를** 각자의 계정 자격 증명으로 대체합니다.

```js
sudo nmcli con add type gsm ifname "*" con-name soracom apn soracom.io user <ENTER_USERNAME> password <ENTER_PASSWORD>
```

이 구성을 적용하려면 라즈베리 파이를 재부팅해야 합니다.

```js
sudo reboot
```

이제 라즈베리파이의 네트워크 관리자에서 USB 모뎀이 인식되고 있는지 확인하려면 다음과 같이 입력합니다:

```js
ifconfig
```

다음과 같이 입력하면

```js
ppp0
```

(USB 모뎀)이 표시되어야 합니다. 그런 다음 다음 터미널 명령어 3개를 입력하여 Soracom의 ppp 경로 메트릭 스크립트를 다운로드하고 USB 모뎀을 연결하거나 재시작할 때마다 스크립트가 실행되는지 확인합니다.

```js
sudo curl -o /etc/NetworkManager/dispatcher.d/90.set_ppp_route_metric https://soracom-files.s3.amazonaws.com/handson/90.set_ppp_route_metric
```

```js
sudo chmod +x /etc/NetworkManager/dispatcher.d/90.set_ppp_route_metric
```

```js
sudo /etc/NetworkManager/dispatcher.d/90.set_ppp_route_metric ppp0 up
```

이제 USB 스틱 모뎀이 올바르게 구성되었습니다. USB 스틱 모뎀을 구성하는 데 여전히 문제가 있는 경우 이 [Soracom 문서를](https://github.com/soracom/handson/wiki/1.3.-USB-Dongle-configuration-tutorial-(SIM-pre-registered)) 꼼꼼히 읽어보세요.

### MQTT 설정

[**MQTT**](https://www.pubnub.com/guides/mqtt/) (모스키토)는 라즈베리파이 IoT 앱에서 PubNub 채널에 메시지를 게시하기 위해 사용할 프로토콜의 이름입니다. 관리자 콘솔의 사이드 탐색 모음에서 그룹이라는 제목의 링크를 열어 **새 그룹을 추가합니다**. 이 새 그룹을 **빔-소라콤이라고** 부르겠습니다. 이 새 그룹의 기본 설정에서 **소라콤 빔을** 클릭합니다. 여기에서 **MQTT 엔트리 포인트를** 생성합니다. [MQTT](https://www.pubnub.com/blog/what-is-mqtt-use-cases/) 엔트리 포인트를 만들 때 다음 사항을 입력했는지 확인하세요. 대상 유형을 **PubNub로** 지정해야 합니다. **자격 증명 설정이** 표시되는 곳에 [PubNub](https://admin.pubnub.com/#/register) 자격 증명**(게시 및 구독 키)**을 추가하여 소라콤 디바이스가 PubNub 채널에 메시지를 게시할 수 있도록 합니다.

[![IMG_20180801_141334](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1jag/91b258ac62700455e397540e39711e13/Screen-Shot-2018-07-31-at-3.55.03-PM.png "IMG_20180801_141334")](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1jag/91b258ac62700455e397540e39711e13/Screen-Shot-2018-07-31-at-3.55.03-PM.png)

그런 다음, 관리 콘솔에서 등록된 SIM 카드를 선택하고 해당 그룹을 방금 생성한 **Beam-Soracom이라는** 그룹으로 설정합니다. 등록된 SIM 카드에서 **활성화를** 클릭하여 활성화되고 데이터를 수신하는지 확인합니다.

이제 MQTT의 게시 방법을 사용할 수 있도록 라즈베리파이에 **모기-클라이언트** 패키지를 설치해야 합니다. 라즈베리파이의 터미널에서 다음 명령을 실행합니다.

```js
sudo apt-get update && sudo apt-get install mosquitto-clients
```

mosquitto-clients가 설치되면 PubNub 채널에 메시지를 게시하는 데 사용할 **mosquitto\_pub** 명령을 테스트할 수 있습니다. mosquitto\_pub 명령의 형식은 다음과 같습니다. **t** 뒤에 채널 이름인 **parking\_spot을** 삽입합니다. 그리고 **\-m** 뒤에 테스트 메시지 "test"를 삽입합니다. 펍넙 관리자 콘솔에서 디버그 뷰를 불러옵니다. 라즈베리파이의 터미널에서 아래 명령을 실행하면 메시지가 PubNub 채널에 성공적으로 게시된 것을 확인할 수 있습니다.

```js
mosquitto_pub -h beam.soracom.io -p 1883 -t parking_spot  -m "test"
```

[![Smart Parking Lot](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1jah/c9c174db5a0b05b0f6e55c495a2a30fd/Screen-Shot-2018-08-02-at-12.42.00-PM.png "Smart Parking Lot")](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1jah/c9c174db5a0b05b0f6e55c495a2a30fd/Screen-Shot-2018-08-02-at-12.42.00-PM.png)

이제 소라콤 에어 디바이스가 라즈베리파이의 메시지를 펍넙 채널에 성공적으로 게시할 수 있게 되었습니다. 이 설정이 완료되었으므로 초음파 센서에서 게시하고 Android 모바일 앱에서 구독하기 위한 코드 작성을 시작할 준비가 되었습니다.

게시 - 초음파 센서 파이썬 스크립트
--------------------

**sensor\_publish.py라는** 스크립트로 파이썬 코드를 작성합니다(이 스크립트는 라즈베리파이 안에 있어야 합니다!). 먼저 스크립트 상단에서 필요한 몇 가지 모듈을 가져오는 것으로 시작하세요. **RPI.GPIO** 모듈을 사용하면 센서에서 데이터를 가져올 수 있습니다. **시간** 모듈을 사용하면 센서에서 주기적으로 판독값을 얻을 수 있습니다. 사용자가 ^C 명령을 사용할 때 스크립트를 종료하고 센서 데이터 읽기를 중지하는 메서드를 작성할 수 있습니다. **서브프로세스와** **json을** 사용하면 부울을 적절한 JSON 문자열 형식으로 파싱하여 [PubNub 채널로](https://www.pubnub.com/docs/general/channels/overview) 전송할 수 있습니다.

```js
import RPi.GPIO as GPIO
import time
import signal
import sys
import subprocess
import json
```

### 센서 설정

모듈을 가져온 후, GPIO 객체가 라즈베리파이 보드 핀 번호를 사용하고 있는지 확인해야 합니다. 다음 줄을 통해 이를 수행합니다.

```js
GPIO.setmode(GPIO.BCM)
```

그런 다음 입력 및 출력 핀에 값을 할당해야 합니다. 입력 핀을 **ECHO라고** 하고 출력 핀을 **TRIG라고** 합니다. 라즈베리파이 설정에서 확인할 수 있듯이 ECHO는 18번 핀**(GPIO 24**)에 연결되고 TRIG는 16번 핀**(GPIO 23**)에 연결됩니다. 또한 추적하는 데 사용할

```js
occupied
```

변수를 초기화해야 합니다. 이 변수는 주차 공간의 마지막 업데이트 상태를 추적하는 데 사용됩니다. False로 초기화하겠습니다.

```js
TRIG = 23
ECHO = 24
occupied = False
```

다음으로 센서를 설정할 함수를 정의하겠습니다. 이 함수의 이름은

```js
setup_sensor()
```

. 여기서 어떤 핀이 입력이고 어떤 핀이 출력인지 정의해야 합니다. 이 함수는 나중에 메인 함수에서 호출할 것입니다.

```js
def setup_sensor():
  GPIO.setup(TRIG, GPIO.OUT)
  GPIO.setup(ECHO, GPIO.IN)
```

### 센서 거리 측정값 얻기

함수

```js
get_distance()
```

함수를 사용하여 물체가 센서에서 얼마나 멀리 떨어져 있는지에 대한 데이터를 얻습니다. 이 함수는 펄스 신호가 물체에서 갔다가 돌아오는 데 걸린 시간을 계산합니다. 걸린 시간을 사용하여 센서에서 물체까지의 거리를 계산합니다.

```js
def get_distance():
  # set Trigger to HIGH
  GPIO.output(TRIG, True)
  # set Trigger after 0.01ms to LOW
  time.sleep(0.00001)
  GPIO.output(TRIG, False)
  startTime = time.time()
  stopTime = time.time()
  # save start time
  while 0 == GPIO.input(ECHO):
    startTime = time.time()
  # save time of arrival
  while 1 == GPIO.input(ECHO):
    stopTime = time.time()
  # time difference between start and arrival
  TimeElapsed = stopTime - startTime
  # multiply with the sonic speed (34300 cm/s)
  # and divide by 2, because there and back
  distance = (TimeElapsed * 34300) / 2
  return distance
```

### 주차 공간 이용 가능 여부 게시

파이썬 스크립트의 메인 함수에 주차 공간의 이용 가능 여부를 게시할 것입니다. 이 함수는 스크립트가 시작되면 실행되는 함수입니다. 메인 함수는 다음 작업을 순서대로 수행해야 합니다.

1.  센서 설정
2.  주차 공간의 사용 가능 여부에 대한 초기 확인 수행
3.  상태가 변경되었는지 확인합니다(5초마다): 변경된 경우 새 상태 메시지를 게시합니다. 이 상태를 마지막으로 업데이트된 새 상태로 저장합니다.

센서를 설정하기 위해 앞서 정의한 함수를 호출합니다,

```js
setup_sensor()
```

. 다음으로 주차 공간이 사용 가능한지 또는 비어 있는지 초기 확인을 수행합니다. 이를 위해 메서드

```js
initial_check()
```

를 정의합니다.

그런 다음 5초마다 실행되는 루프를 통해 차량의 새로운 거리 측정값을 확인합니다. 함수를 통해 얻은 거리 측정값이

```js
get_distance()
```

로 얻은 거리 판독값이 7cm(내 모델의 주차 공간 길이)보다 크면 주차 공간이 비어 있다고 추론할 수 있습니다. 이 경우 감지하는 거리는 단순히 노이즈입니다. 7cm 미만이면 주차 공간이 자동차에 의해 점유되고 있다는 것을 알 수 있습니다.

비용을 최소화하고 효율성을 극대화하기 위해 센서가 마지막 판독 이후 상태가 변경된 것으로 표시되는 경우에만 주차 공간의 상태를 업데이트합니다. 그 예는 다음과 같습니다:

```js
if __name__ == '__main__':
  setup_sensor()
  initial_check()
  while True:
    if (occupied and (get_distance() >= 7)) or (not occupied and (get_distance() < 7)):
         // TODO toggle the availability of the parking space and publish new status
    time.sleep(5)
```

우리의

```js
initial_check()
```

함수는 변수

```js
occupied
```

변수를 주차 공간의 현재 상태에 할당합니다. 앞서 가져온

```js
subprocess
```

모듈을 사용하여 게시해야 합니다. 이 모듈을 사용하면 파이썬 스크립트에서 터미널 명령을 실행할 수 있습니다. 메서드

```js
Popen()
```

를 사용하여 터미널에 입력하는 것처럼 명령의 문자열 배열을 전달하기만 하면 됩니다. **m** 뒤에는 키 "occupied"를 사용하여 JSON 문자열로 인코딩된 메시지를 전달하고 변수

```js
occupied
```

. 이 작업은 도우미 메서드(

```js
convertToJsonString()
```

를 호출하면 되는데, 이 메서드는 부울을 받아 전송할 수 있는 JSON 문자열 메시지로 변환합니다.

```js
def initial_check():
  occupied = True if get_distance() < 7 else False
  subprocess.Popen(["mosquitto_pub", "-h", "beam.soracom.io", "-p", "1883", "-t", "parking_spot", "-m", convertToJsonString(occupied)], stdout=subprocess.PIPE)
  print(occupied)
```

```js
def convertToJsonString(occupied):
  dictionary_object = {
    "occupied": occupied
  }
  return json.dumps(dictionary_object)
```

마지막으로 메인 함수에서 5초마다 실행되는 루프 안에 다음 코드가 있습니다. 이 코드는 점유된 부울을 토글한 다음 마지막으로 업데이트된 상태와 다른 **경우** 이를 **parking\_spot** 채널에 게시합니다.

```js
occupied = not occupied
subprocess.Popen(["mosquitto_pub", "-h", "beam.soracom.io", "-p", "1883", "-t", "parking_spot", "-m", convertToJsonString(occupied)], stdout=subprocess.PIPE)
print(occupied)
```

### 킬 스크립트

또한 파이썬 스크립트를 제대로 종료할 수 있는지 확인해야 합니다. 우리는

```js
close()
```

를 사용자가 ^C 명령으로 스크립트를 종료할 때 호출되는 함수로 정의합니다. 여기에서는 센서 판독값을 정리하기 위해 라인

```js
GPIO.cleanup()
```

.

```js
def close(signal, frame):
  print("Turning off ultrasonic distance detection...")
  GPIO.cleanup()
  sys.exit(0)
signal.signal(signal.SIGINT, close)
```

이제 주차 공간의 상태 업데이트를 게시하는 파이썬 스크립트를 작성했습니다.

구독 - 안드로이드 모바일 앱
----------------

이제 센서가 PubNub 채널에 데이터를 성공적으로 게시하고 있으므로 모바일 앱이 주차 공간 가용성 데이터가 포함된 채널을 구독하도록 설정해야 합니다.

먼저 [PubNub Android SDK를](https://www.pubnub.com/docs/sdks/android) 활용하기 위해 모듈 build.gradle 파일에 다음 gradle 종속 요소를 추가해야 합니다.

```js
implementation group: 'com.pubnub', name: 'pubnub-gson', version: '6.4.5'
```

다음으로 앱이 인터넷을 사용할 수 있도록 다음 안드로이드 매니페스트 권한을 추가합니다.

```js
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
```

이 모바일 앱에서는 하나의 액티비티인 **MainActivity** 클래스를 빌드하겠습니다. 이 액티비티에는 3개의 UI-요소로 구성된 기본 보기가 포함됩니다.

-   가용성 상태를 표시하는 TextView
-   자동차 아이콘을 위한 이미지 뷰
-   주차 공간 아이콘을 위한 이미지 뷰

텍스트 뷰를 사용하여 주차 공간의 사용 가능 여부를 표시하고 주차 공간 내부 또는 외부에 자동차 아이콘을 표시하는 간단한 애니메이션을 만들겠습니다. 주차된 차량의 Y 위치는

```js
203f
```

이고, 주차되지 않은 차량의 Y 위치는

```js
903f
```

. 주차 공간이 비어 있는지 또는 사람이 있는지 표시하기 위해 애니메이션을 사용하여 두 위치 사이를 전환합니다.

![Smart Parking Lot](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1jai/c49db6142edb3aba23c185ba1cc254d4/Screenshot_20180802-125832.png "Smart Parking Lot") [![Smart Parking Lot](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1jak/13634e1cfbae33fbc5da29409018fe87/Screenshot_20180802-125822.png "Smart Parking Lot")](https://images.ctfassets.net/3prze68gbwl1/asset-17suaysk1qa1jaj/ac205dec3aff8b815d037ebb91ac8e53/Screenshot_20180802-125822.png)

먼저 MainActivity 클래스의 필드를 선언하겠습니다.

```js
PubNub pubNub;
TextView occupiedText;
ImageView car, parkingSpot;
float outsideCar = 903f;
float parkedCar = 203f;
```

그런 다음, 활동의 메서드 안에 있는

```js
findViewById()
```

메서드를 사용하여 UI 요소를 인스턴스화합니다.

```js
onCreate()
```

메서드로 인스턴스화합니다. **메인 액티비티 레이아웃 파일에** 아래에 지정된 대로 적절한 ID와 함께 다음과 같은 UI 요소가 포함되어 있는지 확인해야 합니다. 제가 선택한 ID는

```js
occupiedText
```

,

```js
car
```

및

```js
parkingspot
```

. 전체 레이아웃 파일을 보려면 [여기를 클릭하세요](https://github.com/kaushikravikumar/Smart-Parking/blob/master/SmartParkingAndroid/app/src/main/res/layout/activity_main.xml).

```js
occupiedText = findViewById(R.id.occupiedText);
car = findViewById(R.id.car);
parkingSpot = findViewById(R.id.parkingspot);
```

이제 인스턴스를 인스턴스화해야 합니다.

```js
PubNub
```

인스턴스를 인스턴스화해야 안드로이드 앱 내에서 PubNub API를 호출할 수 있습니다. 이를 위해 다음 코드를 작성하고 [PubNub 관리 콘솔에서](https://dashboard.pubnub.com/login) 앱을 만들 때 생성한 **구독 키와** **게시 키를** 전달합니다.

```js
PNConfiguration pnConfiguration = new PNConfiguration();
pnConfiguration.setSubscribeKey("ENTER_SUBSCRIBE_KEY_HERE");
pnConfiguration.setPublishKey("ENTER_PUBLISH_KEY_HERE");
pnConfiguration.setSecure(true);
pubNub = new PubNub(pnConfiguration);
```

이제 인스턴스를 인스턴스화했으므로

```js
PubNub
```

인스턴스를 인스턴스화했으므로 센서가 주차 가능 여부 데이터를 게시하는 채널인 **parking\_spot을** 구독할 수 있습니다. 이렇게 하려면 채널에 메시지가 게시될 때 콜백 리스너를 추가해야 합니다. 그런 다음 실제로 채널을 구독해야 합니다. 이는 아래와 같습니다.

```js
pubNub.addListener(new SubscribeCallback() {
      @Override
      public void status(PubNub pubnub, PNStatus status) {
      }
      @Override
      public void message(PubNub pubnub, PNMessageResult message) {
         // HANDLE MESSAGE
      }
      @Override
      public void presence(PubNub pubnub, PNPresenceEventResult presence) {
      }
  });
  pubNub.subscribe()
          .channels(Arrays.asList("parking_spot")) // subscribe to channels
          .execute();
```

그런 다음 메시지를 처리하는 로직을 구현합니다. 우리는 기본적으로 현재 점유 상태를 확인하여 모바일 앱 UI에서 주차 공간의 사용 가능 여부를 전환하고 싶습니다. 따라서 방금 채널에 게시된 메시지를 확인하여 주차 공간이 현재 사용 가능한지 또는 점유 중인지 확인합니다. 사용 가능한 경우 헬퍼 메서드인

```js
carLeaveAnimation()
```

. 점유 중인 경우, 헬퍼 메서드인

```js
carEnterAnimation()
```

. 따라서 우리의

```js
message()
```

메서드 안에는 다음이 있습니다.

```js
final boolean occupied = message.getMessage().getAsJsonObject().get("occupied").getAsBoolean();
 runOnUiThread(new Runnable() {
     public void run() {
         if(occupied)
         {
             carEnterAnimation();
         }
         else
         {
             carLeaveAnimation();
         }
     }
 });
```

에서

```js
carEnterAnimation()
```

에서 텍스트뷰를 occupied라고 설정하기만 하면 됩니다. 또한 자동차의 이미지뷰에서

```js
animate()
```

메서드를 호출하고 Y 위치를 주차 공간으로 이동합니다(변수에 저장된 Y 좌표 값으로),

```js
parkedCar
```

). 에서

```js
carLeaveAnimation()
```

에서 텍스트뷰를 사용 가능으로 설정하고 자동차 이미지뷰의

```js
animate()
```

메서드를 호출하여 차량의 Y 위치를 주차 공간 외부로 이동합니다(Y 좌표 값으로),

```js
outsideCar
```

).

```js
private void carEnterAnimation()
{
    car.animate().y(parkedCar).setDuration(1500);
    occupiedText.setText("Occupied");
}
private void carLeaveAnimation()
{
    car.animate().y(outsideCar).setDuration(1500);
    occupiedText.setText("Vacant");
}
```

  
이 페이지에서 **임베드된 콘텐츠를 사용할 수 없는 경우** [https://www.youtube.com/embed/KySPa\_D2ne0?enablejsapi=1&origin=https%3A%2F%2Fwww.pubnub.com](https://www.youtube.com/embed/KySPa_D2ne0?enablejsapi=1&origin=https%3A%2F%2Fwww.pubnub.com) 에서도 볼 수 있습니다.

모바일 앱은 여기까지입니다! 이제 센서로부터 주차 가능 여부에 대한 업데이트를 성공적으로 수신했습니다.

앱 실행
----

센서를 시작하려면 라즈베리 파이 터미널에서 스크립트가 있는 디렉토리를 입력하기만 하면 됩니다. 그런 다음 다음 명령을 실행합니다.

```js
python sensor_publish.py
```

이제 센서가 켜져 있고 거리 측정값을 확인하고 있는 것을 확인할 수 있습니다. Android 모바일 앱을 실행하면 모바일 앱의 UI가 업데이트되고 주차 공간의 상태가 표시되는 것을 볼 수 있습니다.

결론
--

축하합니다! 이제 간단한 스마트 주차 [IoT](https://www.pubnub.com/solutions/iot-device-control/) 앱을 구축했습니다. **전체 소스 코드를 보려면 [여기를 클릭하세요](https://github.com/PubNubDevelopers/Smart-Parking)**. PubNub과 Soracom을 통합하여 LTE를 사용하여 라즈베리파이에서 실시간 메시지를 전송하는 IoT 앱을 구축했습니다. Wi-Fi 네트워크의 제약을 받지 않는 스마트 주차 IoT 앱은 휴대성이 뛰어나 실외에서 사용하기에 적합합니다.

[IoT 대시보드 데모와](https://www.pubnub.com/demos/iot-dashboard/) [해당 대시보드에 기반한 IoT 튜토리얼도](https://www.pubnub.com/tutorials/iot-dashboard/) 확인해 보세요.

펍넙이 어떤 도움을 드릴 수 있을까요?
=====================

이 문서는 원래 [PubNub.com에](https://www.pubnub.com/blog/smart-parking-iot-simulation-with-realtime-space-monitoring/) 게시되었습니다.

저희 플랫폼은 개발자가 웹 앱, 모바일 앱, IoT 디바이스를 위한 실시간 인터랙티브를 구축, 제공, 관리할 수 있도록 지원합니다.

저희 플랫폼의 기반은 업계에서 가장 크고 확장성이 뛰어난 실시간 에지 메시징 네트워크입니다. 전 세계 15개 이상의 PoP가 8억 명의 월간 활성 사용자를 지원하고 99.999%의 안정성을 제공하므로 중단, 동시 접속자 수 제한, 트래픽 급증으로 인한 지연 시간 문제를 걱정할 필요가 없습니다.

PubNub 체험하기
-----------

[라이브 투어를](https://www.pubnub.com/tour/introduction/) 통해 5분 이내에 모든 PubNub 기반 앱의 필수 개념을 이해하세요.

설정하기
----

PubNub [계정에](https://admin.pubnub.com/signup/) 가입하여 PubNub 키에 무료로 즉시 액세스하세요.

시작하기
----

사용 사례나 [SDK에](https://www.pubnub.com/docs) 관계없이 [PubNub 문서를](https://www.pubnub.com/docs) 통해 바로 시작하고 실행할 수 있습니다.