Inteligentny system parkowania ze śledzeniem przestrzeni na żywo
Published: 2024-01-11 11:59:22

Nigdy wcześniej nie żyliśmy w czasach, w których każda "rzecz" mogła być bezproblemowo połączona przez Internet. Idea [Internetu Rzeczy (IoT](https://www.pubnub.com/solutions/iot-device-control/) ) nieustannie przekształca nasz świat, prezentując innowacyjne rozwiązania wielu problemów przy użyciu **architektury Pub/Sub sterowanej zdarzeniami**. Na przykład, aby rozwiązać męczący problem ze znalezieniem miejsca parkingowego w zatłoczonych miejscach, parkingi zainstalowały elektroniczne pulpity nawigacyjne pokazujące na żywo, które miejsca są dostępne, subskrybując aktualizacje statusu publikowane z poszczególnych czujników na parkingu. Zbudowanie takiej aplikacji IoT może być trudne ze względu na szereg przeszkód.

Jedną z tych przeszkód jest hostowanie serwera zdolnego do obsługi wiadomości wysyłanych między aplikacją mobilną a urządzeniami czujnikowymi w czasie rzeczywistym. Inną jest obsługa sieci Wi-Fi zdolnej do obsługi każdego wbudowanego czujnika na inteligentnym parkingu.

Używając **PubNub** i **Soracom** obok siebie, deweloperzy mogą jednak szybko obejść te wyzwania. Dzięki platformie czasu rzeczywistego PubNub deweloperzy mogą łatwo [tworzyć złożone rozwiązania IoT](https://www.pubnub.com/solutions/iot-device-control/) do [monitorowania pojazdów](https://www.pubnub.com/solutions/transport-delivery/), nie martwiąc się o żmudne zadania, takie jak hosting serwerów. Dodatkowo, dzięki [Soracom Air](https://www.soracom.io/products/air/) i [Soracom Beam](https://www.soracom.io/products/beam/), deweloperzy mogą łatwo tworzyć rozwiązania IoT, które wykorzystują LTE, zamiast restrykcyjnej sieci WFI.

Przegląd samouczka
------------------

W tym samouczku zbudujemy symulację inteligentnego parkowania przy użyciu Raspberry Pi i czujnika ultradźwiękowego do wykrywania, czy miejsce parkingowe jest zajęte czy wolne. Użyjemy Soracom Air do wysyłania wiadomości z czujnika do PubNub za pośrednictwem danych komórkowych. Następnie za pomocą interfejsu API PubNub Publish-Subscribe udostępnimy dane o parkowaniu na żywo wszystkim użytkownikom aplikacji mobilnej. Przedstawia to poniższy schemat.

* * *

**Aby uzyskać pełny kod źródłowy, [kliknij tutaj](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)

Aby zbudować to demo, będziesz potrzebować:

1.  Raspberry Pi (dowolna wersja)
2.  Płytka montażowa
3.  Czujnik ultradźwiękowy HC-SR04
4.  1 żeńsko-żeński + 6 męsko-żeńskich przewodów połączeniowych
5.  1 rezystor **1k Ω** i 1 rezystor **2k Ω**
6.  Karta MicroSD + przejściówka z MicroSD na SD
7.  Modem USB Huawei
8.  Karta SIM Soracom Air

Konfiguracja Raspberry Pi
-------------------------

### **1\. Instalacja systemu operacyjnego Raspbian**

Jeśli jeszcze tego nie zrobiłeś, upewnij się, że zainstalowałeś Raspbian OS na swoim Raspberry Pi. Aby to zrobić, najpierw zainstalujemy go lokalnie na naszym komputerze. Będzie to format obrazu dysku, więc będziemy musieli sflashować dysk przed jego użyciem. Możesz użyć programu [Etcher](https://www.balena.io/etcher/), aby sflashować dysk na kartę microSD.

[![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)

Gdy pliki systemu operacyjnego Raspbian znajdą się na naszym adapterze karty microSD, możemy wyjąć kartę microSD z adaptera, a następnie włożyć ją do dolnego gniazda naszego Raspberry Pi. Po zainstalowaniu systemu operacyjnego można teraz uruchomić Raspberry Pi, podłączając klawiaturę, mysz, monitor i źródło zasilania.

### 2\. Konfiguracja czujnika

[![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.  Podłącz 3 nasze **męskie i że** ńskie przewody połączeniowe do **czujnika ultradźwiękowego HC-SR04** w **gniazdach VCC, Echo i GND.** Podłącz jeden z naszych **żeńskich** **i** **żeńskich przewodów połączeniowych** do gniazda **Trig** czujnika.
2.  Podłącz **przewód** **VCC** do dodatniej **szyny** naszej płytki prototypowej, a **przewód** **GND** do **szyny ujemnej**.
3.  Podłącz GPIO **5V** na Raspberry Pi do dodatniej **szyny** naszej płytki, a **GPIO GND** do **szyny u**jemnej.
4.  Podłącz przewód **Trig** do GPIO **23**.
5.  Podłącz przewód **Echo** do **pustej** szyny na płytce prototypowej.
6.  Podłącz kolejną pustą szynę za pomocą **rezystora 1k Ω**. (Powodem, dla którego potrzebujemy rezystorów jest to, że możemy obniżyć napięcie wyjściowe, aby upewnić się, że nasz Raspberry Pi nie zostanie uszkodzony przez konfigurację czujnika).
7.  Następnie podłącz pustą szynę za pomocą **rezystora** 2k Ω do ujemnej szyny naszej płytki drukowanej, pozostawiając wolne miejsce. Jeśli nie masz rezystora 2k Ω, możesz utworzyć serię 2 rezystorów 1k Ω, jak pokazano na poniższym obrazku.[![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.  W miejscu, które nam pozostało, użyjemy **zworki męsko-żeńskiej** , aby połączyć się z **GPIO 24**.

Gratulacje, zakończyliśmy konfigurację naszego czujnika ultradźwiękowego. Jeśli utknąłeś w konfiguracji czujnika, zapoznaj się z tym [samouczkiem](https://thepihut.com/blogs/raspberry-pi-tutorials/hc-sr04-ultrasonic-range-sensor-on-the-raspberry-pi), aby uzyskać bardziej szczegółowe wyjaśnienie. Podczas budowania obwodu należy pamiętać, że na pustych szynach [płytki](https://en.wikipedia.org/wiki/Breadboard) prąd płynie poziomo, a na szynach dodatnich i ujemnych prąd płynie pionowo. Następnie skonfigurujemy PubNub i Soracom w naszej aplikacji IoT.

Konfiguracja PubNub
-------------------

Najpierw utworzymy naszą aplikację w konsoli [administracyjnej Pub](https://dashboard.pubnub.com/login) Nub**(jest bezpłatna**). Po utworzeniu aplikacji w konsoli zobaczysz klucze publikowania i subskrypcji, których użyjemy w następnym kroku do połączenia PubNub i Soracom.

Konfiguracja Soracom
--------------------

### **Zarejestruj kartę SIM**

Przejdziemy do [konsoli administratora Soracom](https://console.soracom.io/). Tutaj klikniemy **Zarejestruj kartę SIM** i wprowadzimy cyfry **ICCID** i **PUK**, które można znaleźć z tyłu **karty SIM Soracom Air**.

[![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)

### Konfiguracja modemu USB

Po zarejestrowaniu naszej karty SIM, wyjmiemy chip SIM (pokazany fioletowym kółkiem, które narysowałem wokół niego na powyższym obrazku). Następnie włożymy go do **modemu USB Huawei**. Upewnij się, że wsunąłeś kartę SIM do końca, prawą stroną do góry.

[![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)

Aby nasze Raspberry Pi działało na danych komórkowych, po prostu podłączymy [modem Huawei](https://consumer.huawei.com/en/routers/e3372/specs/) USB Stick do portu USB Raspberry Pi. **Stałe niebieskie światło** (nie miga) wskazuje, że modem pomyślnie odbiera dane 3g. Jeśli miga, oznacza to, że nadal próbuje się połączyć.

[![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)

Po zaświeceniu się niebieskiego światła musimy dodać nasz modem USB Stick do Menedżera sieci Raspberry Pi. Aby to zrobić, najpierw zainstaluj Network Manager na Raspberry Pi. W terminalu Raspberry Pi wpisz następujące polecenie.

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

Następnie, aby podłączyć nasz modem USB Stick do naszego konta Soracom, musimy wpisać następujące polecenie z terminala Raspberry Pi. Zastąp **<ENTER\_USERNAME>** i **<ENTER\_PASSWORD>** odpowiednimi danymi uwierzytelniającymi konta.

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

Aby ta konfiguracja weszła w życie, musimy zrestartować nasze Raspberry Pi.

```js
sudo reboot
```

Teraz, aby upewnić się, że modem USB jest rozpoznawany przez menedżera sieci Raspberry Pi, wpisz:

```js
ifconfig
```

Powinieneś zobaczyć

```js
ppp0
```

(Twój modem USB). Następnie wpisz następujące 3 polecenia terminala, aby upewnić się, że pobrałeś skrypt ppp route metric Soracom i że skrypt jest uruchamiany za każdym razem, gdy modem USB jest podłączony lub ponownie uruchomiony.

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

Teraz nasz modem USB Stick powinien być poprawnie skonfigurowany. Jeśli nadal nie możesz skonfigurować modemu USB Stick, upewnij się, że dokładnie przeczytałeś [dokumentację Soracom](https://github.com/soracom/handson/wiki/1.3.-USB-Dongle-configuration-tutorial-(SIM-pre-registered)).

### Konfiguracja MQTT

[**MQTT**](https://www.pubnub.com/guides/mqtt/) (Mosquitto) to nazwa protokołu, którego będziemy używać do publikowania wiadomości na naszym kanale PubNub z aplikacji Raspberry Pi IoT. W konsoli administratora otworzymy łącze bocznego paska nawigacyjnego zatytułowane Grupy, aby **dodać nową grupę**. Nazwiemy tę nową grupę **Beam-Soracom**. W ustawieniach podstawowych tej nowej grupy klikamy na **Soracom Beam**. Tutaj utworzymy **punkt wejścia MQTT**. Upewnij się, że podczas tworzenia punktu wejścia [MQTT](https://www.pubnub.com/blog/what-is-mqtt-use-cases/) wprowadzono następujące dane. Będziesz musiał określić typ miejsca docelowego jako **PubNub**. Tam, gdzie widzisz **Credentials Set**, dodamy nasze poświadczenia [PubNub](https://admin.pubnub.com/#/register)**(Publish i Subscribe Key**), aby umożliwić naszemu urządzeniu Soracom publikowanie wiadomości na naszym kanale 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)

Następnie wybierzemy naszą zarejestrowaną kartę SIM w konsoli administratora i ustawimy jej grupę na tę, którą właśnie utworzyliśmy, o nazwie **Beam-Soracom**. Upewnij się, że kliknąłeś **aktywuj** na naszej zarejestrowanej karcie SIM, aby była aktywna i odbierała dane.

Teraz musimy zainstalować pakiet **mosquitto-clients** na naszym Raspberry Pi, abyśmy mogli korzystać z metody publikowania MQTT. W terminalu Raspberry Pi uruchom następujące polecenie.

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

Po zainstalowaniu mosquitto-clients możemy przetestować nasze polecenie **mosquitto\_pub**, którego użyjemy do opublikowania wiadomości na naszym kanale PubNub. Format naszego polecenia mosquitto\_pub będzie następujący. Po **\-t** wstawimy nazwę naszego kanału, **parking\_spot**. A po **\-m** wstawimy wiadomość testową "test". Podnieś widok debugowania w konsoli administratora PubNub. Po uruchomieniu poniższego polecenia w terminalu Raspberry Pi powinieneś zobaczyć, że wiadomość została pomyślnie opublikowana na naszym kanale 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)

Teraz nasze urządzenie Soracom Air może z powodzeniem publikować wiadomości z naszego Raspberry Pi na naszym kanale PubNub. Dzięki tej konfiguracji jesteśmy gotowi do rozpoczęcia pisania kodu do publikowania z czujnika ultradźwiękowego i subskrybowania z aplikacji mobilnej na Androida.

Publikowanie - czujnik ultradźwiękowy - skrypt Python
-----------------------------------------------------

Napiszemy nasz kod Pythona w skrypcie o nazwie **sensor\_publish.py** (ten skrypt musi znajdować się wewnątrz Raspberry Pi!). Zacznij od zaimportowania niektórych modułów, których będziemy potrzebować w górnej części skryptu. Moduł **RPI.GPIO** pozwoli nam uzyskać dane z czujników. Moduł **time** pozwoli nam okresowo uzyskiwać odczyty z czujnika. **Signal** i **sys** pozwolą nam napisać naszą metodę, która zabije skrypt i przestanie odczytywać dane z czujnika, gdy użytkownik użyje polecenia ^ C. **Subprocess** i **json** pozwolą nam przeanalizować naszą wartość logiczną do odpowiedniego formatu JSON String i wysłać ją do naszego [kanału 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
```

### Konfiguracja czujnika

Po zaimportowaniu naszych modułów musimy upewnić się, że nasz obiekt GPIO używa numerów pinów płytki Raspberry Pi. Zrobimy to za pomocą następującej linii.

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

Następnie musimy przypisać wartości do naszych pinów wejściowych i wyjściowych. Nasz pin wejściowy nazywa się **ECHO**, a nasz pin wyjściowy nazywa się **TRIG**. ECHO jest podłączone do pinu 18**(****GPIO 24**), a TRIG do pinu 16**(GPIO 23**), co można sprawdzić w konfiguracji Raspberry Pi. Musimy również zainicjować naszą zmienną

```js
occupied
```

której będziemy używać do śledzenia ostatnio zaktualizowanego statusu miejsca parkingowego. Zainicjujemy ją na False.

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

Następnie zdefiniujemy naszą funkcję, która skonfiguruje nasz czujnik. Nazwiemy tę funkcję

```js
setup_sensor()
```

. Tutaj musimy zdefiniować, który pin jest naszym wejściem, a który wyjściem. Wywołamy tę funkcję później w naszej funkcji głównej.

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

### Uzyskanie odczytu odległości z czujnika

Użyjemy funkcji

```js
get_distance()
```

aby uzyskać dane dotyczące odległości obiektu od naszego czujnika. Funkcja ta wykona obliczenia dotyczące czasu, jaki sygnał impulsowy potrzebował, aby przejść i powrócić z obiektu. Wykorzystując czas, obliczy odległość od czujnika do obiektu.

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

### Publikowanie dostępności miejsc parkingowych

Będziemy publikować dostępność naszego miejsca parkingowego w głównej funkcji naszego skryptu Python. Będzie to funkcja wykonywana po uruchomieniu skryptu. Funkcja główna musi wykonać następujące czynności w kolejności.

1.  Konfiguracja czujnika
2.  Przeprowadzić wstępne sprawdzenie dostępności miejsca parkingowego
3.  Sprawdzić, czy status uległ zmianie (co 5 sekund): Jeśli się zmienił, opublikuj komunikat o nowym statusie. Zapisz ten status jako ostatni zaktualizowany status.

Aby skonfigurować czujnik, wywołamy funkcję, którą zdefiniowaliśmy wcześniej,

```js
setup_sensor()
```

. Następnie wykona ona wstępne sprawdzenie, czy miejsce parkingowe jest dostępne lub wolne. Zdefiniujemy metodę

```js
initial_check()
```

aby to zrobić.

Następnie będziemy mieć pętlę, która będzie wykonywana co 5 sekund w celu sprawdzenia nowego odczytu odległości samochodu. Jeśli odczyt odległości uzyskany przez funkcję

```js
get_distance()
```

jest większa niż 7 cm (długość miejsca parkingowego w moim modelu), możemy wywnioskować, że miejsce parkingowe jest wolne. Odległość, którą odbiera funkcja, jest w tym przypadku po prostu szumem. Jeśli jest mniejsza niż 7 cm, wiemy, że miejsce parkingowe jest zajęte przez samochód.

Aby zminimalizować koszty i zmaksymalizować wydajność, będziemy aktualizować status miejsca parkingowego tylko wtedy, gdy czujnik pokaże, że status zmienił się od ostatniego odczytu. Jest to pokazane poniżej:

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

Nasza funkcja

```js
initial_check()
```

przypisze naszą zmienną

```js
occupied
```

do aktualnego stanu miejsca parkingowego. Musimy to opublikować za pomocą modułu

```js
subprocess
```

który zaimportowaliśmy wcześniej. Dzięki temu modułowi jesteśmy w stanie uruchamiać polecenia terminala ze skryptu Pythona. Używając metody

```js
Popen()
```

po prostu przekazujemy tablicę ciągów z polecenia, tak jak wpisuje się je w terminalu. Po **\-m**, chcemy przekazać wiadomość zakodowaną jako JSON String, z kluczem "occupied" i wartością zmiennej

```js
occupied
```

. Możemy to zrobić, wywołując naszą metodę pomocniczą

```js
convertToJsonString()
```

która pobiera wartość logiczną i konwertuje ją na wiadomość JSON String, którą możemy wysłać.

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

Wreszcie, wewnątrz naszej pętli, która jest wykonywana co 5 sekund w naszej głównej funkcji, będziemy mieli następujący kod. Spowoduje to przełączenie zajętej wartości logicznej, a następnie opublikowanie jej na naszym kanale **parking\_spot****,** jeśli różni się od ostatnio zaktualizowanego stanu.

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

### Skrypt zabijania

Musimy również upewnić się, że nasz skrypt Pythona może zostać poprawnie zabity. Definiujemy

```js
close()
```

jako funkcję wywoływaną, gdy użytkownik zabije skrypt poleceniem ^C. W tym miejscu możemy wyczyścić nasze odczyty czujników za pomocą linii

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

.

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

Gratulacje, napisaliśmy teraz skrypt Pythona, który publikuje aktualizacje statusu miejsca parkingowego.

Subskrybuj - aplikacja mobilna na Androida
------------------------------------------

Teraz, gdy nasz czujnik z powodzeniem publikuje dane do naszego kanału PubNub, musimy skonfigurować aplikację mobilną tak, aby była subskrybowana do kanału zawierającego dane o dostępności miejsc parkingowych.

Najpierw musimy dodać następujące zależności gradle do naszego pliku Module build.gradle, aby wykorzystać [PubNub Android SDK](https://www.pubnub.com/docs/sdks/android).

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

Następnie dodamy następujące uprawnienia manifestu Androida, aby umożliwić naszej aplikacji korzystanie z Internetu.

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

Dla tej aplikacji mobilnej zbudujemy jedną aktywność, klasę **MainActivity** . Ta aktywność będzie zawierać podstawowy widok składający się z 3 elementów interfejsu użytkownika.

-   TextView do podawania dostępności
-   ImageView dla ikony samochodu
-   ImageView dla ikony miejsca parkingowego

Użyjemy TextView do stwierdzenia, czy miejsce parkingowe jest dostępne i będziemy mieć prostą animację pokazującą ikonę samochodu wewnątrz miejsca parkingowego lub poza nim. Zaparkowany samochód będzie miał pozycję Y równą

```js
203f
```

a niezaparkowany samochód będzie miał pozycję Y równą

```js
903f
```

. Aby pokazać, czy miejsce parkingowe jest wolne, czy zajęte, będziemy przełączać jego pozycję między nimi za pomocą animacji.

![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)

Najpierw zadeklarujemy pola naszej klasy MainActivity.

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

Następnie utworzymy instancję elementów interfejsu użytkownika za pomocą metody

```js
findViewById()
```

wewnątrz metody

```js
onCreate()
```

metoda. Musimy upewnić się, że **plik układu aktywności** głównej zawiera następujące elementy interfejsu użytkownika z odpowiednimi identyfikatorami określonymi poniżej. Identyfikatory, które wybrałem to

```js
occupiedText
```

,

```js
car
```

oraz

```js
parkingspot
```

. Aby zobaczyć mój kompletny plik układu, [kliknij tutaj](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);
```

Teraz musimy utworzyć instancję

```js
PubNub
```

abyśmy mogli wykonywać wywołania PubNub API z poziomu naszej aplikacji na Androida. Aby to zrobić, napiszemy następujący kod i przekażemy **Subscribe Key** i **Publish Key**, które wygenerowaliśmy podczas tworzenia aplikacji w [PubNub Admin Console](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);
```

Teraz, gdy utworzyliśmy instancję

```js
PubNub
```

możemy zasubskrybować kanał, do którego nasz czujnik publikuje dane o dostępności parkingu, **parking\_spot**. Aby to zrobić, będziemy musieli dodać słuchacza wywołania zwrotnego, gdy wiadomość zostanie opublikowana na kanale. Następnie musimy zasubskrybować kanał. Jest to pokazane poniżej.

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

Następnie zaimplementujemy logikę obsługi wiadomości. Chcemy zasadniczo przełączać dostępność miejsca parkingowego w interfejsie użytkownika naszej aplikacji mobilnej, sprawdzając jego aktualny stan zajętości. Dlatego sprawdzimy wiadomość właśnie opublikowaną na naszym kanale, aby sprawdzić, czy miejsce parkingowe jest teraz dostępne, czy zajęte. W przypadku, gdy jest ono dostępne, wywołamy naszą metodę pomocniczą

```js
carLeaveAnimation()
```

. W przypadku, gdy jest zajęte, wywołamy naszą metodę pomocniczą

```js
carEnterAnimation()
```

. Tak więc wewnątrz naszej metody

```js
message()
```

mamy następującą metodę.

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

W

```js
carEnterAnimation()
```

po prostu ustawiamy widok tekstowy na zajęty. Wywołujemy również metodę

```js
animate()
```

na widoku obrazu samochodu i przesuwamy jego pozycję Y na miejsce parkingowe (do wartości współrzędnej Y przechowywanej w zmiennej,

```js
parkedCar
```

). W

```js
carLeaveAnimation()
```

po prostu ustawiamy widok tekstowy na dostępny i wywołujemy metodę

```js
animate()
```

na widoku obrazu samochodu, aby przesunąć jego pozycję Y poza miejsce parkingowe (do wartości współrzędnej 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");
}
```

  
**Jeśli osadzona zawartość nie jest dostępna** na tej stronie, można ją również wyświetlić pod adresem [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).

To wszystko dla naszej aplikacji mobilnej! Teraz z powodzeniem odbiera aktualizacje z czujnika dotyczące dostępności naszego miejsca parkingowego.

Uruchamianie aplikacji
----------------------

Aby uruchomić czujnik, wystarczy wejść do katalogu, w którym znajduje się skrypt z terminala Raspberry Pi. Następnie wykonaj następujące polecenie.

```js
python sensor_publish.py
```

Zobaczysz, że czujnik został włączony i sprawdza odczyty odległości. Uruchom aplikację mobilną na Androida i powinieneś zobaczyć, że interfejs użytkownika aplikacji mobilnej zostanie zaktualizowany i wyświetli status miejsca parkingowego.

Podsumowanie
------------

Gratulacje! Stworzyliśmy teraz prostą aplikację Smart Parking [IoT](https://www.pubnub.com/solutions/iot-device-control/). **Aby uzyskać pełny kod źródłowy, [kliknij tutaj](https://github.com/PubNubDevelopers/Smart-Parking)**. Integrując PubNub i Soracom, stworzyliśmy aplikację IoT, która wykorzystuje LTE do wysyłania wiadomości w czasie rzeczywistym z Raspberry Pi. Zamiast być ograniczonym przez sieć Wi-Fi, nasza aplikacja Smart Parking IoT jest niezwykle przenośna i idealna do użytku na zewnątrz.

Zachęcamy również do zapoznania się z naszym [demo pulpitu nawigacyjnego IoT](https://www.pubnub.com/demos/iot-dashboard/) i [samouczkiem IoT opartym na tym pulpicie](https://www.pubnub.com/tutorials/iot-dashboard/).

Jak PubNub może ci pomóc?
=========================

Ten artykuł został pierwotnie opublikowany na [PubNub.com](https://www.pubnub.com/blog/smart-parking-iot-simulation-with-realtime-space-monitoring/)

Nasza platforma pomaga programistom tworzyć, dostarczać i zarządzać interaktywnością w czasie rzeczywistym dla aplikacji internetowych, aplikacji mobilnych i urządzeń IoT.

Fundamentem naszej platformy jest największa w branży i najbardziej skalowalna sieć przesyłania wiadomości w czasie rzeczywistym. Dzięki ponad 15 punktom obecności na całym świecie obsługującym 800 milionów aktywnych użytkowników miesięcznie i niezawodności na poziomie 99,999%, nigdy nie będziesz musiał martwić się o przestoje, limity współbieżności lub jakiekolwiek opóźnienia spowodowane skokami ruchu.

Poznaj PubNub
-------------

Sprawdź [Live Tour](https://www.pubnub.com/tour/introduction/), aby zrozumieć podstawowe koncepcje każdej aplikacji opartej na PubNub w mniej niż 5 minut.

Rozpocznij konfigurację
-----------------------

Załóż [konto](https://admin.pubnub.com/signup/) PubNub, aby uzyskać natychmiastowy i bezpłatny dostęp do kluczy PubNub.

Rozpocznij
----------

[Dokumenty](https://www.pubnub.com/docs) PubNub pozwolą Ci rozpocząć pracę, niezależnie od przypadku użycia lub [zestawu SDK](https://www.pubnub.com/docs).