Merge branch 'main' into lesson3

pull/432/head
Hyejin Kim 3 years ago committed by GitHub
commit 16b19fc03c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -0,0 +1,268 @@
# IoT로 식물 성장 예측
![이 수업에 대한 스케치 노트 개요](../../../../sketchnotes/lesson-5.jpg)
> [Nitya Narasimhan](https://github.com/nitya)의 스케치 노트. 클릭하면 크게 보실 수 있습니다.
## 수업 전 퀴즈
[수업 전 퀴즈](https://black-meadow-040d15503.1.azurestaticapps.net/quiz/9)
## 개요
식물이 자라기 위해서는 물, 이산화탄소, 영양분, 빛, 열과 같은 특정 요소가 필요합니다. 이 수업에서는 기온을 측정하여 식물의 성장과 성숙도를 계산하는 방법을 배웁니다.
이 수업에서 다룰 내용은 다음과 같습니다:
- [디지털 농업](#디지털-농업)
- [농사에서 왜 온도가 중요할까요?](#농사에서-왜-온도가-중요할까요?)
- [주변 온도 측정](#주변-온도-측정)
- [유효 적산 온도(Growing Degree Days, GDD)](#유효-적산-온도)
- [온도 센서 데이터를 이용한 GDD 계산](#온도-센서-데이터를-이용한-GDD-계산)
## 디지털 농업
디지털 농업은 농업 데이터를 수집, 저장, 분석하는 도구를 사용하여 우리가 농사를 짓는 방식을 변화시키고 있습니다. 우리는 현재 세계 경제 포럼(WEF)이 '4차 산업 혁명'이라 설명하는 시기에 살고 있고, 디지털 농업의 증가는 `4차 농업 혁명` 또는 `농업 4.0`이라고 불리게 되었습니다.
> 🎓 디지털 농업이라는 용어는 또한 농장에서 식탁까지 가는 전체 여정인 '농업 가치사슬'도 포함합니다. 이는 식품 배송 및 가공, 창고 및 전자 상거래 시스템, 심지어 트랙터 대여 앱에 대한 제품 품질 추적을 포함합니다!
이러한 변화를 통해 농부들은 생산량을 증가시키고, 더 적은 비료와 농약을 사용하고, 더 효율적으로 급수할 수 있었습니다. 주로 부유한 나라에서 사용하지만, 센서와 다른 장치들은 천천히 가격을 내리고 있고 개발도상국에서도 더 접근이 용이하도록 만들고 있습니다.
디지털 농업에서 사용 가능한 몇 가지 기술:
- 온도 측정 - 온도를 측정하는 것은 농부들에게 식물의 성장과 성숙도를 예측할 수 있게 합니다.
- 자동 관수 - 토양의 수분을 측정하고 토양이 너무 건조할 때, 시간을 정해 물을 주는 대신 관개 시스템을 켭니다. 시간을 정해 물을 주면 농작물이 더운 기간이나 가뭄 동안 물이 부족하거나, 비가 오는 동안 물이 너무 많아질 수 있습니다. 토양이 필요로 할 때만 물을 줌으로써 농부들은 물 사용을 최적화할 수 있습니다.
- 해충 방제 - 농부들은 자동화된 로봇이나 드론에 해충을 확인하기 위해서 카메라를 장착하여 사용할 수 있고, 필요한 곳에만 살충제를 적용하여 사용되는 살충제의 양과 지역 상수로의 농약 유출을 줄일 수 있습니다.
✅ 조사를 해봅시다. 농산물의 생산량을 증가시키기 위한 다른 기술들에는 무엇이 있습니까?
> 🎓 '정밀 농업'이라는 용어는 밭 단위를 기준으로 또는 밭의 일부에서 농작물의 관찰, 측정, 대응을 정의하기 위해 사용됩니다. 물, 영양분과 해충의 정도를 측정하고, 밭의 일부분에 물을 주는 것과 같이 정확하게 대응하는 것을 포함합니다.
## 농사에서 왜 온도가 중요할까요?
식물에 대해 배울 때, 대부분의 학생들은 물, 빛, 이산화탄소(CO<sub>2</sub>)와 영양분의 필요성에 대해 배웁니다. 식물은 또한 자라기 위해서 따뜻함을 필요로 합니다. 기온이 오르면서 봄에 식물들이 피어나는 이유, 짧은 온난 기간으로 설강화나 수선화가 일찍 싹을 틔울 수 있는 이유, 온실(hothouse)과 온실(greenhouse)이 식물을 잘 자라게 하는 이유가 여기에 있습니다.
> 🎓 온실(Hothouse)과 온실(Greenhouse)은 비슷한 일을 하지만, 중요한 차이점이 있습니다. 온실(Hothouse)은 인위적으로 열을 공급하고 농부가 온도를 조금 더 정밀하게 조절할 수 있게 합니다. 온실(Greenhouse)은 따뜻함을 위해 태양에 의존하고 유일한 제어는 일반적으로 열을 내보내는 창이나 기타 개구부입니다.
식물은 일 평균 기온을 기준으로 기준 혹은 최저 온도와 적정 온도, 최고 온도를 가지고 있습니다.
- 기준 온도 - 식물이 자라는 데에 필요한 최소한의 일 평균 온도입니다.
- 적정 온도 - 식물이 가장 많이 자라게 하는 최적의 일 평균 온도입니다.
- 최고 온도 - 식물이 견딜 수 있는 최고 일 평균 온도입니다. 이 온도 이상에서 식물은 물을 아끼고 살아 남기 위해 스스로의 성장을 멈춥니다.
> 💁 이것들은 일간 및 야간 온도에 대한 평균을 낸 평균 온도입니다. 식물은 또한 더 효율적으로 광합성을 하고 밤에 에너지를 절약하기 위해 밤낮으로 다른 온도가 필요합니다.
각각의 식물 종들은 기준, 적정, 최고 온도의 값이 서로 다릅니다. 이것이 일부 식물이 더운 나라에서 번성하고, 다른 식물이 추운 나라에서 번성하는 이유입니다.
✅ 간단한 조사를 해봅시다. 정원, 학교, 지역 공원에서 기르는 식물들에 대해 기준 온도를 찾아보십시오.
![온도가 상승함에 따라 증가하는 성장률을 나타내는 그래프, 온도가 너무 높아지면 감소하는 그래프](../../../../images/plant-growth-temp-graph.png)
상단의 그래프는 기온이 성장에 끼치는 영향에 대한 예시를 보여주는 그래프입니다. 기준 온도까지는 성장을 하지 않습니다. 성장률은 적정 온도까지 계속해서 증가하고, 최고점에 도달한 후에는 점점 떨어집니다. 최고 온도에서는 성장을 멈추게 됩니다.
이 그래프의 형태는 식물의 종에 따라 달라집니다. 어떤 것은 적정 온도 이상에서 더 급격하게 떨어지고, 어떤 것은 기준 온도부터 적정 온도까지 느리게 증가합니다.
> 💁 최고의 성장을 얻기 위해서 농부는 자신이 기르는 식물들에 대해 이 세 가지 온도의 값과 이 그래프의 형태에 대해 이해해야 합니다.
만약 농부가 상업용 온실에서와 온도를 조절한다면, 식물에 최적화 할 수 있습니다. 예를 들어, 토마토를 재배하는 상업용 온실은 가장 빠른 성장을 위해 낮에는 약 25°C, 밤에는 약 20°C로 온도를 설정합니다.
> 🍅 이러한 온도를 인공 조명, 비료 및 통제된 CO<sub>2</sub> 레벨과 결합하면 상업적 재배자들이 일년 내내 재배하고 수확할 수 있습니다.
## 주변 온도 측정
온도 센서는 주변 온도를 측정하기 위해 IoT 장치와 함께 사용될 수 있습니다.
### 작업 - 온도 측정
IoT 장치를 사용하여 온도를 모니터링하려면 관련 가이드를 참조하십시오.
- [Arduino - Wio Terminal](../wio-terminal-temp.md)
- [싱글 보드 컴퓨터 - Raspberry Pi](./pi-temp.ko.md)
- [싱글 보드 컴퓨터- 가상 장치](./virtual-device-temp.md)
## 유효 적산 온도
유효 적산 온도(Growing degree days, growing degree units)은 온도를 기준으로 식물의 성장을 측정하는 방법입니다. 식물에 물과 영양분, CO<sub>2</sub>가 충분하다고 가정하면, 기온이 성장 속도를 결정합니다.
유효 적산 온도(GDD)는 식물 기준 온도보다 높은 하루의 평균 섭씨 온도로 계산됩니다. 각 식물은 성장, 개화, 또는 생산과 성장을 위해 특정한 수의 GDD가 필요합니다. 매일 GDD가 더 많을수록, 식물은 더 빨리 자랄 것입니다.
> 🇺🇸 미국인의 경우 성장도 일수는 화씨로 계산할 수도 있습니다. 5 GDD<sup>C</sup>(섭씨 기준의 GDD)는 9 GDD<sup>F</sup>(화씨 기준의 GDD)와 동알합니다.
GDD를 계산하는 전체 공식은 약간 복잡합니다. 하지만 좋은 근사치로 종종 사용되는 단순화된 방정식이 있습니다:
![GDD = (최고 온도 + 최소 온도) 을 2로 나누고, 전체에서 기준 온도를 뺀 값](../../../../images/gdd-calculation.png)
- **GDD** - 유효 적산 온도
- **T<sub>max</sub>** - 섭씨 단위의 일간 최고 기온
- **T<sub>min</sub>** - 섭씨 단위의 일간 최저 기온
- **T<sub>base</sub>** - 섭씨 단위의 식물의 기준 온도
> 💁 30°C가 넘는 T<sub>max</sub>나 T<sub>base</sub> 보다 낮은 T<sub>min</sub>에 대해 다루는 변형식이 있지만, 지금은 넘어가도록 하겠습니다.
### 예시 - 옥수수 🌽
품종에 따라 옥수수는 성숙하는 데에 기준 온도 10°C에서 800부터 2,700 사이의 GDD를 필요로 합니다.
기준 온도보다 높은 첫 날, 다음과 같은 온도가 측정되었습니다:
| 측정 | 온도 °C |
| :---------- | :-----: |
| 최고 온도 | 16 |
| 최저 온도 | 12 |
계산식에 이 숫자들을 대입합시다:
- T<sub>max</sub> = 16
- T<sub>min</sub> = 12
- T<sub>base</sub> = 10
계산 결과는 다음과 같습니다:
![GDD = 16 + 12 에서 2로 나누고, 전체에서 10을 빼면, 정답은 4](../../../../images/gdd-calculation-corn.png)
옥수수는 그날 4 GDD를 받았습니다. 옥수수 품종이 성숙하는 데 800 GDD가 필요하다고 가정하면, 성숙에 도달하기 위해서는 추가적으로 796 GDD가 더 필요합니다.
✅ 조사를 해봅시다. 정원, 학교, 지역 공원에서 기르는 식물들에 대해 식물이 다 자라거나 작물을 생산하는 데 필요한 GDD 수를 조사해보십시오.
## 온도 센서 데이터를 이용한 GDD 계산
식물은 정해진 날짜에 자라지 않습니다. 예를 들어 씨앗을 심고 정확히 100일 후에 열매를 맺는다는 것을 알 수는 없습니다. 대신 농부는 식물이 자라는 데 걸리는 시간을 대략적으로 알 수 있으며 매일 작물이 준비되는 시간을 확인합니다.
이는 대규모 농장의 노동력에 막대한 영향을 끼칩니다. 그리고 농부들이 예상치 못하게 일찍 준비된 작물을 놓치는 위험을 줍니다. 농부는 기온을 측정하여 식물이 받은 GDD를 계산할 수 있고, 그들이 예상 성숙도와 가까워졌는지 확인 하도록 합니다.
IoT 장치를 이용하여 온도 데이터를 수집하면, 농부는 자동적으로 식물이 성숙에 가까워졌는지 알 수 있습니다. 이러한 일일반적인 아키텍처는 IoT 장치가 온도를 측정한 다음 MQTT와 같은 것을 사용하여 인터넷을 통해 이 원격 측정 데이터를 게시하도록 하는 것입니다. 서버 코드는 이 데이터를 수신하고 이것을 데이터베이스와 같은 어딘가에 저장합니다. 이것은 데이터가 나중에 분석될 수 있다는 것을 의미합니다. 예를 들어, 야간 작업을 통해 하루의 GDD를 계산하고, 지금까지 각 작물에 대한 GDD를 합산하고, 식물이 성숙에 가까워지면 알림을 보낼 수 있습니다.
![원격 측정 데이터는 서버로 보내져 데이터베이스에 저장됩니다.](../../../../images/save-telemetry-database.png)
서버 코드는 또한 부가 정보를 추가함으로써 데이터를 보강할 수 있습니다. 예를 들어, IoT 장치는 어떤 장치인지 나타내기 위해 식별자를 게시할 수 있으며, 서버 코드는 이를 사용하여 장치의 위치와 모니터링 중인 작물을 조회할 수 있습니다.또한 일부 IoT 장치에는 정확한 시간을 추적하는 데 필요한 하드웨어가 없거나 인터넷을 통해 현재 시간을 읽는 데 추가 코드가 필요하므로 현재 시간과 같은 기본 데이터를 추가할 수 있습니다.
✅ 당신이 생각하기에 밭마다 다른 기온이 필요한 이유는 무엇입니까?
### 작업 - 온도 정보 게시
IoT 장치를 사용하여 MQTT를 통해 온도 데이터를 게시하여 나중에 분석할 수 있도록 관련 가이드를 참조하십시오:
- [Arduino - Wio Terminal](../wio-terminal-temp-publish.md)
- [싱글 보드 컴퓨터 - Raspberry Pi/가상 IoT 장치](single-board-computer-temp-publish.ko.md)
### 작업 - 온도 정보를 캡처하고 저장하십시오.
IoT 장치가 원격 분석을 게시하면, 서버 코드를 작성하여 이 데이터를 구독하고 저장할 수 있습니다. 이것을 데이터베이스에 저장하는 대신 서버 코드가 Comma Seperated Values(CSV)로 저장합니다. CSV 파일은 데이터를 텍스트로 된 값의 행으로 저장합니다. 각 값은 쉼표(,)로 분리되고 각각이 새로운 줄에 기록됩니다. 이것은 편리하고, 사람이 읽을 수 있고 잘 지원되는 데이터를 파일로 저장하는 방법입니다.
CSV 파일은 _날짜__온도_ 2개의 열을 가집니다. _날짜_ 열 은 서버가 메시지를 수신한 현재 날짜와 시간으로 설정되며 _온도_ 는 원격 측정 메시지에서 가져옵니다.
1. 원격 분석을 구독하기 위한 서버 코드를 생성하기 위해 레슨 4에 있는 단계를 반복하십시오. 명령을 게시하기 위해서 코드를 추가할 필요는 없습니다.
이를 위한 단계는 다음과 같습니다:
- Python 가상 환경 구성 및 활성화
- paho-mqtt pip package를 설치
- 원격 분석 주제에 게시된 MQTT 메시지를 수신 대기하는 코드 작성
> ⚠️ 필요한 경우 원격 분석을 수신할 Python 앱을 만드는 방법은 [Lesson4의 지침](../../../1-getting-started/lessons/4-connect-internet/README.md#receive-telemetry-from-the-mqtt-broker)을 참고할 수 있습니다.
이 프로젝트의 폴더명을 입력하십시오.
`temperature-sensor-server`.
1. `client_name`이 이 프로젝트를 반영하는 지 확인하십시오.
```cpp
client_name = id + 'temperature_sensor_server'
```
1. 아래의 import 목록을 보고 파일의 상단에 import 하는 부분을 추가하십시오:
```python
from os import path
import csv
from datetime import datetime
```
이것은 파일을 읽기 위한 라이브러리, CSV 파일과 상호작용하는 라이브러리, 날짜와 시간을 지원하는 라이브러리를 가져옵니다.
1. `handle_telemetry` 함수 앞에 다음 코드를 추가합니다:
```python
temperature_file_name = 'temperature.csv'
fieldnames = ['date', 'temperature']
if not path.exists(temperature_file_name):
with open(temperature_file_name, mode='w') as csv_file:
writer = csv.DictWriter(csv_file, fieldnames=fieldnames)
writer.writeheader()
```
이 코드는 작성할 파일의 이름과 CSV 파일의 열 헤더의 이름을 위한 몇 가지 상수를 선언합니다. CSV 파일의 첫 번째 행은 관습적으로 콤마로 분리된 열 헤더를 포함합니다.
그런 다음 CSV 파일이 이미 존재하는 지 확인합니다. 만약 존재하지 않는다면, 첫 번째 행에 열 헤더를 포함하여 생성합니다.
1. 다음 코드를 `handle_telemetry` 함수 뒷 부분에 추가하십시오:
```python
with open(temperature_file_name, mode='a') as temperature_file:
temperature_writer = csv.DictWriter(temperature_file, fieldnames=fieldnames)
temperature_writer.writerow({'date' : datetime.now().astimezone().replace(microsecond=0).isoformat(), 'temperature' : payload['temperature']})
```
이 코드는 CSV 파일을 열고 끝 부분에 새로운 행을 추가합니다. 행에는 사람이 읽을 수 있는 형식으로 현재 데이터와 시간이 있으며 그 뒤에 IoT 장치에서 받은 온도가 표시됩니다. 데이터는 [ISO 8601 형식](https://wikipedia.org/wiki/ISO_8601)으로 마이크로초 없이 시간대와 함께 저장됩니다.
1. 이전과 동일한 방법으로 이 코드를 실행하고, IoT 장치가 데이터를 전송하는 지 확인하십시오. `temperature.csv` 이라 불리는 CSV 파일이 같은 폴더 내에 생성됩니다. 이것을 확인하면 날짜/시간과 기온 측정을 볼 수 있습니다.
```output
date,temperature
2021-04-19T17:21:36-07:00,25
2021-04-19T17:31:36-07:00,24
2021-04-19T17:41:36-07:00,25
```
1. 데이터를 캡쳐하기 위해 이 코드를 잠시동안 실행하십시오. 이상적으로는 GDD 계산을 위한 충분한 데이터를 수집하기 위해 하루 종일 실행해야 합니다.
> 💁 만약 당신이 가상 IoT 장치를 사용한다면, 랜덤 체크 박스를 선택하고 온도 값이 반환될 때마다 동일한 온도가 나오지 않도록 범위를 설정합니다.
> ![랜덤 체크 박스를 선택하고 범위를 설정함](../../../../images/select-the-random-checkbox-and-set-a-range.png)
> 💁 만약 이것을 하루 종일 실행하고 싶다면 전원 세팅을 바꾸거나 [시스템 활성 유지 Python 스크립트](https://github.com/jaqsparow/keep-system-active)와 같은 것을 실행하여 절전 상태에 빠지지 않도록 확인해야 합니다.
> 💁 이 코드는 [code-server/temperature-sensor-server](code-server/temperature-sensor-server) 폴더에서 찾을 수 있습니다.
### 작업 - 저장된 데이터를 이용한 GDD 계산
서버가 온도 데이터를 캡쳐하고 나면, 식물의 GDD를 계산할 수 있습니다.
수동으로 하는 방법은 다음과 같습니다:
1. 식물의 기준 온도를 찾습니다. 예를 들어, 딸기의 기준 온도는 10°C 입니다.
1. `temperature.csv`에 가장 일간 최고 온도 최저 온도를 찾습니다.
1. 이전에 제공된 GDD 계산식을 이용하여 GDD를 계산합니다.
예를 들어, 만약 일간 최고 온도가 25°C이고, 최저 온도가 12°C라면:
![GDD = 25 + 12 를 2로 나누고 , 10을 빼면 결과는 8.5입니다.](../../../../images/gdd-calculation-strawberries.png)
- 25 + 12 = 37
- 37 / 2 = 18.5
- 18.5 - 10 = 8.5
따라서 딸기는 지금까지 8.5의 GDD를 받았습니다. 딸기는 열매를 맺기 위해 약 250 GDD를 필요로 합니다. 따라서 아직 시간이 필요합니다.
---
## 🚀 도전
식물이 자라기 위해선 열 말고도 많은 것들을 필요로 합니다. 다른 필요한 것에는 무엇이 있을까요?
이를 측정할 수 있는 센서가 있는지 찾아보십시오. 이러한 레벨을 제어하는 액추에이터는 어떻습니까? 식물의 성장을 최적화하기 위해 하나 이상의 IoT 장치를 어떻게 조합해야 할까요?
## 강의 후 퀴즈
[강의 후 퀴즈](https://black-meadow-040d15503.1.azurestaticapps.net/quiz/10)
## 복습 및 독학
- 디지털 농업에 대해 [디지털 농업에 대한 Wikipedia 페이지](https://wikipedia.org/wiki/Digital_agriculture)에서 더 읽어보십시오. 정밀 농업에 대해서는 [정밀 농업에 대한 Wikipedia 페이지](https://wikipedia.org/wiki/Precision_agriculture)에서 읽어보십시오.
- 유효 적산 온도(GDD) 계산식의 원본은 이 수업에서의 간략한 식보다 훨씬 복잡합니다. [Growing Degree Day Wikipedia 페이지](https://wikipedia.org/wiki/Growing_degree-day)에서 더 복잡한 방정식과 기준 이하의 온도를 처리하는 방법에 대해 자세히 알아보십시오.
- 우리가 여전히 농사에 동일한 방법을 사용하더라도 미래에는 식량이 부족할 수 있습니다. 하이테크 농업에 대해서 [YouTube의 미래의 하이테크 농장 비디오](https://www.youtube.com/watch?v=KIEOuKD9KX8)에서 더 자세히 배워봅시다.
## 과제
[Jupyter Notebook을 이용한 GDD 데이터 시각화](assignment.ko.md)

@ -0,0 +1,43 @@
# Jupyter Notebook을 이용한 GDD 데이터 시각화
## 개요
이번 수업에서 IoT 센서를 사용해 GDD 데이터를 수집했습니다. 좋은 GDD 데이터를 얻기 위해서는 수 일간 데이터를 수집해야 합니다. 온도 데이터를 시각화 하고 GDD를 계산하는 것을 돕기 위해선 [Jupyter Notebooks](https://jupyter.org)과 같은 도구를 사용하여 데이터를 분석할 수 있습니다.
며칠 간 데이터를 수집하는 것으로 시작하십시오. 전원 관리 설정을 조정하거나 [시스템 활성 유지 Python 스크립트](https://github.com/jaqsparow/keep-system-active) 와 같은 것을 실행하여 IoT 장치가 실행되는 동안 서버 코드가 항상 실행되고 있는지 확인해야 합니다.
온도 데이터를 얻은 후에는 이 레포지토리에 있는 Jupyter Notebook을 이용하여 데이터를 시각화하고 GDD를 계산할 수 있습니다. Jupyter Notebook은 _셀_ 이라 불리는 블럭 안에 코드와 지침들이 섞여있습니다. 이는 주로 파이썬으로 작성됩니다. 지침을 읽고, 각각의 코드 블럭을 하나씩 실행할 수 있습니다. 또한 코드를 수정할 수도 있습니다. 예를 들자면 당신의 식물을 위해 GDD를 계산할 때 사용되는 기준 온도를 이 notebook에서 수정할 수 있습니다.
1. `gdd-calculation` 이름을 가진 폴더를 생성합니다.
1. [gdd.ipynb](../code-notebook/gdd.ipynb) 파일을 다운받고 `gdd-calculation`로 복사합니다.
1. MQTT 서버가 생성한 `temperature.csv` 파일을 복사합니다.
1. `gdd-calculation`폴더에 새로운 Python 환경을 생성합니다.
1. 데이터를 관리하고 표시하는 데 필요한 라이브러리와 함께 Jupyter Notebook을 위한 몇가지 pip 패키지들을 설치합니다:
```sh
pip install --upgrade pip
pip install pandas
pip install matplotlib
pip install jupyter
```
1. 이 notebook을 Jupyter에서 실행합니다:
```sh
jupyter notebook gdd.ipynb
```
Jupyter가 시작되고 브라우저에서 notebook을 열게 됩니다. notebook의 지시에 따라 측정된 온도를 시각화하고 유효 적산 온도(GDD)를 계산합니다.
![The jupyter notebook](../../../../images/gdd-jupyter-notebook.png)
## 평가 기준
| 기준 | 모범 답안 | 적절함 | 개선이 필요함 |
| ----------- | ------------------------------------------- | ------------------------------------- | ------------------------- |
| 데이터 캡쳐 | 최소 완전한 이틀 이상의 데이터를 캡처함 | 최소 완전한 하루 이상의 데이터 캡처함 | 몇개의 데이터를 캡처함 |
| GDD 계산 | 성공적으로 notebook을 실행하고 GDD를 계산함 | 성공적으로 notebook을 실행함 | notebook을 실행할 수 없음 |

@ -0,0 +1,111 @@
# 온도 측정 - 라즈베리 파이
이 단원에서는 라즈베리 파이에 온도 센서를 추가합니다.
## 하드웨어
당신이 사용할 센서는 두 센서를 하나의 패키지로 결합한 [DHT11 습도 및 온도 센서](https://www.seeedstudio.com/Grove-Temperature-Humidity-Sensor-DHT11.html)입니다. 이것은 온도, 습도와 때로는 대기압을 결합한 다수의 상업적으로 이용 가능한 센서로 상당히 인기가 있습니다. 온도 센서 구성 요소는 음의 온도 계수(NTC) 서미스터로, 온도가 증가함에 따라 저항이 감소하는 서미스터입니다.
이것은 디지털 센서이므로 마이크로컨트롤러가 읽을 수 있는 온도와 습도 데이터가 포함된 디지털 신호를 생성하는 온보드 ADC를 가지고 있습니다.
### 온도 센서 연결
Grove 온도 센서는 라즈베리 파이에 연결할 수 있습니다.
#### 임무
온도 센서를 연결하십시오.
![Grove 온도 센서](../../../../images/grove-dht11.png)
1. 온도와 습도 센서의 소켓에 Grove 케이블의 한 쪽 끝을 삽입합니다. 한쪽 방향으로만 진행됩니다.
1. 라즈베리 파이의 전원을 끈 상태에서 Grove 케이블의 다른 쪽 끝을 Pi에 부착된 Grove Base hat의 **D5**가 적힌 디지털 소켓에 연결합니다. 이 소켓은 GPIO 핀 옆의 소켓 행에서 왼쪽 두 번째입니다.
![소켓 A0에 연결된 Grove 온도 센서](../../../../images/pi-temperature-sensor.png)
## 온도 센서 프로그래밍
이제 부착된 온도 센서를 사용하도록 장치를 프로그래밍할 수 있습니다.
### 임무
장치를 프로그래밍합니다.
1. Pi의 전원을 켜고 부팅될 때까지 기다립니다.
1. Pi에서 직접 VS Code를 실행하거나 원격 SSH 확장을 통해 연결합니다.
> ⚠️ 필요한 경우 [레슨 1의 VS Code를 설정 및 실행 설명](../../../../1-getting-started/lessons/1-introduction-to-iot/pi.md)을 참고할 수 있습니다.
1. 터미널에서 `pi` 사용자 홈 디렉토리에 `temperature-sensor`라는 새 폴더를 만듭니다. 이 폴더 안에 `app.py` 파일을 생성합니다.
```sh
mkdir temperature-sensor
cd temperature-sensor
touch app.py
```
1. 이 폴더를 VS Code에서 엽니다.
1. 온습도 센서를 사용하기 위해서는 추가적인 pip 패키지 설치가 필요합니다. VS Code의 터미널에서 Pi에 이 pip 패키지를 설치하기 위한 다음의 명령어를 실행합니다:
```sh
pip3 install seeed-python-dht
```
1. 필요한 라이브러리를 import하기 위해 다음의 코드를 `app.py` 파일에 추가합니다:
```python
import time
from seeed_dht import DHT
```
`from seeed_dht import DHT``seeed_dht` 모듈에서 Grove 온도 센서와 상호 작용할 `DHT` 클래스를 import 합니다.
1. 위의 코드 뒤에 다음의 코드를 추가하여 온도 센서를 관리하는 클래스의 인스턴스를 생성합니다:
```python
sensor = DHT("11", 5)
```
이것은 디지털 온습도 센서(**D**igital **H**umidity and **T**emperature)를 제어하는 `DHT` 클래스의 인스턴스를 선언입니다. 첫 번째 파라미터는 사용되는 센서가 _DHT11_ 센서임을 나타내는 코드입니다. 사용 중인 라이브러리는 이 센서의 다른 버전들을 지원합니다. 두 번째 파라미터는 센서가 Grove base hat에서 디지털 포트 `D5`에 연결되었다는 것을 나타내는 코드입니다.
> ✅ 모든 소켓은 고유한 핀 번호를 가졌다는 것을 기억하세요.핀 번호 0, 2, 4, 6번은 아날로그 핀이고, 핀 번호 5, 16, 18, 22, 24, 26 번은 디지털 핀입니다.
1. 위의 코드 뒤에 무한 루프를 추가하여 온도 센서 값을 폴링하고 콘솔에 출력합니다:
```python
while True:
_, temp = sensor.read()
print(f'Temperature {temp}°C')
```
`sensor.read()`의 호출은 습도와 온도의 튜플을 반환합니다. 온도 값만 필요하므로 습도 값은 무시됩니다. 온도 값은 콘솔에 출력됩니다.
1. 온도를 지속적으로 확인할 필요는 없으므로 10초의 짧은 sleep을 `loop`의 끝에 추가합니다. sleep은 장치가 소비하는 전력을 줄여줍니다.
```python
time.sleep(10)
```
1. VS Code의 터미널에서 다음을 실행하여 Python 앱을 실행합니다:
```sh
python3 app.py
```
콘솔에 온도 값이 출력되는 것을 볼 수 있습니다. 엄지 손가락으로 누르는 것처럼 센서에 따뜻한 것을 데거나 팬을 사용하여 값이 변하는 것을 확인하십시오:
```output
pi@raspberrypi:~/temperature-sensor $ python3 app.py
Temperature 26°C
Temperature 26°C
Temperature 28°C
Temperature 30°C
Temperature 32°C
```
> 💁 이 코드는 [code-temperature/pi](../code-temperature/pi) 폴더에 있습니다.
😀 온도 센서 프로그램이 성공적이었습니다!

@ -0,0 +1,57 @@
# 온도 게시 - 가상 IoT 하드웨어와 라즈베리 파이
이 단원에서는 나중에 GDD를 계산하는 데 사용될 수 있도록 MQTT를 이용해 라즈베리 파이나 가상 IoT 장치에서 감지한 온도 값을 게시합니다.
## 온도 게시
온도를 읽은 후에는 MQTT를 통해 값을 읽고 GDD 계산에 사용할 수 있도록 저장하는 '서버' 코드에 게시할 수 있습니다.
### 임무 - 온도 게시하기
온도를 게시하기 위해 장치를 프로그래밍하십시오.
1. `temperature-sensor` 앱 프로젝트가 열려있지 않다면 해당 프로젝트를 엽니다.
1. 레슨 4에서 했던 MQTT를 연결하고 원격 분석을 전송하는 다음 단계들을 반복합니다. 동일한 공개 Mosquitto 브로커를 사용하게 됩니다.
이를 위한 단계는 다음과 같습니다:
- MQTT pip 패키지를 추가합니다.
- MQTT 브로커와 연결하는 코드를 추가합니다.
- 원격 분석을 게시하는 코드르 추가합니다.
> ⚠️ 필요하다면 레슨 4의 [MQTT 연결을 위한 지침](../../../../1-getting-started/lessons/4-connect-internet/translations/single-board-computer-mqtt.md)과 [원격 분석 전송 지침](../../../../1-getting-started/lessons/4-connect-internet/translations/single-board-computer-telemetry.ko.md)를 참고하십시오.
1. `client_name`이 이 프로젝트의 이름을 반영 하는지 확인하십시오.
```python
client_name = id + 'temperature_sensor_client'
```
1. 원격 분석 전송의 경우 빛의 값을 전송하는 대신 DHT 센서에서 읽은 온도 값을 전송하기 위해 JSON 문서의 속성 `temperature`에서 다음과 같이 보냅니다.
```python
_, temp = sensor.read()
telemetry = json.dumps({'temperature' : temp})
```
1. 온도 값은 자주 읽어올 필요가 없습니다. 짧은 시간에 크게 변하지 않기 때문에 `time.sleep`을 10분으로 설정합니다.
```cpp
time.sleep(10 * 60);
```
> 💁 `sleep`함수는 몇 초간 시간이 가지는 함수입니다. 따라서 계산식의 결과로 전달되는 값을 읽어 오는 것을 더 쉽게 만들어줍니다. 60초는 1분이므로, 10 x (1분에 60초)는 10분의 지연을 제공합니다.
1. 과제의 이전 부분에서 코드를 실행한 것과 동일한 방식으로 코드를 실행합니다. 가상 IoT 장치를 사용한다면 CounterFit 앱이 실행 중인지, 습도 및 온도 센서가 올바른 핀에 생성되었는지 확인하십시오.
```output
pi@raspberrypi:~/temperature-sensor $ python3 app.py
MQTT connected!
Sending telemetry {"temperature": 25}
Sending telemetry {"temperature": 25}
```
> 💁 이 코드는 [code-publish-temperature/virtual-device](../code-publish-temperature/virtual-device) 폴더 또는 [code-publish-temperature/pi](../code-publish-temperature/pi) 폴더에서 찾을 수 있습니다.
😀장치에서 원격 분석 전송으로 온도를 성공적으로 게시했습니다.

@ -0,0 +1,468 @@
# 위치 데이터 저장
![A sketchnote overview of this lesson](../../../../sketchnotes/lesson-12.jpg)
> [Nitya Narasimhan](https://github.com/nitya)의 스케치노트. 크게 보려면 클릭하세요.
## 강의 전 퀴즈
[강의 전 퀴즈](https://black-meadow-040d15503.1.azurestaticapps.net/quiz/23)
## 개요
지난 강의에서는 위치 정보를 캡처하기 위한 GPS 센서 사용법에 대해 배웠습니다. 이 데이터를 사용하여 음식을 실은 트럭으 위치와 이동 경로를 시각화 하기 위해서는 이 데이터가 클라우드의 IoT 서비스로 전송하고 어딘가에 저장해야 합니다.
이 강의에서는 IoT 데이터를 저장하는 다양한 방법과 서버리스 코드를 이용하여 IoT 서비스의 데이터를 저장하는 방법에 대해 배웁니다.
이 강의에서는 다음을 배웁니다:
- [정형 및 비정형 데이터](#정형-및-비정형-데이터)
- [IoT Hub로 GPS 데이터 전송하기](#IoT-Hub로-GPS-데이터-전송하기)
- [Hot, Warm, Cold 경로](#hot,-warm-cold-경로)
- [서버리스 코드를 이용한 GPS 이벤트 처리](#서버리스-코드를-이용한-GPS-이벤트-처리)
- [Azure Storage 계정](#Azure-Storage-계정)
- [서버리스 코드와 저장소 연결하기](#서버리스-코드와-저장소-연결하기)
## 정형 및 비정형 데이터
컴퓨터 시스템은 데이터를 다루고, 이 데이터는 다양한 모양과 크기로 제공됩니다. 단일 숫자에서 많은 양의 텍스트, 비디오 및 이미지, IoT 데이터까지 다양합니다. 데이터는 _정형 데이터__비정형 데이터_ 두 가지 중 하나로 나눌 수 있습니다.
- **정형 데이터**는 변경되지 않는 잘 정의되고 엄격한 구조를 가진 데이터로, 일반적으로 관계가 있는 데이터 테이블에 매핑됩니다. 이름, 생년월일, 주소를 포함한 개인 정보를 예로 들 수 있습니다.
- **비정형 데이터** 는 잘 정의되고 엄격한 구조가 없는 데이터로, 자주 구조가 변경될 수 있는 데이터입니다. 문서나 스프레드 시트와 같은 것을 예로 들 수 있습니다.
✅ 조사해봅시다 : 정형 데이터와 비정형 데이터의 다른 예를 생각해 볼 수 있습니까?
> 💁 구조화는 되었지만 고정된 테이블에 맞지 않는 반정형 데이터도 존재합니다.
IoT 데이터는 주로 비정형 데이터로 간주됩니다.
대규모 상업 농장의 차량에 IoT 장치를 추가한다고 생각해봅시다. 차량 유형에 따라 다른 장치를 사용하기를 원할 것입니다. 예를 들어:
- 트랙터와 같은 농업용 차량의 경우 올바른 밭에서 동작하는지 확인하기 위한 GPS 데이터가 필요합니다.
- 식량을 창고로 나르는 배달 트럭의 경우 GPS 데이터는 물론이고 운전자가 안전하게 운전할 수 있도록 속도 및 가속 데이터를 제공하고, 운전자 식별 및 시작/정지 데이터를 제공하여 운전자가 근무 시간에 대한 현지 법률을 준수하도록 보장해야 합니다.
- 냉장 트럭의 경우 음식이 너무 뜨겁거나 차갑지 않고 운송 중에 상하지 않도록 온도 데이터도 필요합니다.
이러한 데이터는 지속적으로 변합니다. 예를 들어, 트럭 운전실에 IoT 장치가 있다면 트레일러가 변경된다면 전송하는 데이터가 변경될 수 있습니다. 예를 들어 냉장 트레일러를 사용할 때만 온도 데이터를 전송합니다.
✅ 다른 캡처되는 IoT 데이터 어떤 것이 있을까요? 트럭이 운반할 수 있는 화물의 종류와 유지 관리 데이터에 대해 생각해 보십시오.
이 데이터는 차량에 따라 변하지만 처리를 위해 모두 동일한 IoT 서비스로 전송됩니다. IoT 서비스는 이 비정형 데이터를 검색하거나 분석할 수 있는 방식으로 저장하면서 이 데이터와 다른 구조로도 작동할 수 있어야 합니다.
### SQL vs NoSQL 스토리지
데이터베이스는 데이터를 저장하고 쿼리할 수 있는 서비스입니다. 데이터 베이스는 SQL과 NoSQL 2개의 타입으로 나뉩니다.
#### SQL 데이터베이스
첫 번째 데이터베이스는 관계형 데이터베이스 관리 시스템(RDBMS) 또는 관계형 데이터베이스입니다. 이는 데이터를 추가, 제거, 업데이트 또는 쿼리하기 위해 SQL(Structured Query Language)을 사용하여 SQL 데이터베이스라고도 합니다. 이러한 데이터베이스는 스프레드시트와 유사한 잘 정의된 데이터 테이블 집합인 스키마로 구성됩니다. 각 테이블에는 여러 개의 명명된 열이 있습니다. 데이터를 삽입할 때 테이블에 행을 추가하여 각 열에 값을 넣습니다. 이렇게 하면 데이터가 매우 엄격한 구조로 유지됩니다. 열을 비워 둘 수 있지만 새 열을 추가하려면 데이터베이스에서 이 작업을 수행하여 기존 행의 값을 채워야 합니다. 이러한 데이터베이스는 한 테이블이 다른 테이블과 관계를 가질 수 있다는 점에서 관계형이라고 합니다.
![구매 테이블의 사용자 ID 열과 관련된 User 테이블의 ID와 구매 테이블의 제품 ID와 관련된 제품 테이블의 ID가 있는 관계형 데이터베이스](../../../../images/sql-database.png)
예를 들어, 사용자 개인 정보를 테이블에 저장한 경우 사용자 이름과 주소가 포함된 테이블의 행에 사용되는 사용자당 내부 고유 ID가 있을 수 있습니다. 그런 다음 해당 사용자에 대한 구매 정보와 같은 다른 세부 정보를 다른 테이블에 저장하려는 경우, 해당 사용자 ID에 대한 하나의 열이 새 테이블에 저장됩니다. 사용자를 조회할 때 사용자 ID를 사용하여 한 테이블에서 사용자의 개인 정보를 가져오고 다른 테이블에서 구입한 사용자의 정보를 가져올 수 있습니다.
SQL 데이터베이스는 정형 데이터를 저장하고 데이터와 스키마가 매치하는지 확인하고자 하는 경우에 이상적입니다.
✅ 이전에 SQL을 사용해본 적이 없다면 잠시 시간을 내어 [SQL page on Wikipedia](https://wikipedia.org/wiki/SQL)에서 읽어보세요.
잘 알려진 SQL 데이터베이스로는 Microsoft SQL Server, MySQL, PostgreSQL이 있습니다.
✅ 조사해봅시다 : 이러한 몇몇 SQL 데이터베이스 및 기능에 대해 읽어봅시다.
#### NoSQL 데이터베이스
NoSQL 데이터베이스는 SQL 데이터베이스와 동일한 엄격한 구조를 가지고 있지 않기 때문에 NoSQL이라 불립니다. 또한 문서와 같은 구조화되지 않은 데이터를 저장할 수 있으므로 문서 데이터베이스라고도 불립니다.
> 💁 이름과는 무관하게 일부 NoSQL 데이터베이스에서는 SQL을 사용하여 데이터를 쿼리할 수 있습니다.
![NoSQL 데이터베이스의 폴더에 있는 문서](../../../../images/noqsl-database.png)
NoSQL 데이터베이스에는 데이터 저장 방법을 제한하는 미리 정의된 스키마가 없으며, 대신 일반적으로 JSON 문서를 사용하여 비정형 데이터를 삽입할 수 있습니다. 이러한 문서는 컴퓨터의 파일과 유사하게 폴더로 구성할 수 있습니다. 각 문서는 다른 문서와 다른 필드를 가질 수 있습니다. 예를 들어, 농장 차량의 IoT 데이터를 저장하는 경우 일부는 가속도계 및 속도 데이터를 위한 필드를 가질 수 있고, 다른 일부는 트레일러의 온도를 위한 필드를 가질 수 있습니다. 운반되는 농산물의 무게를 추적하기 위해 척도가 내장된 트럭과 같은 새로운 트럭 유형을 추가하는 경우, IoT장치가 해당 새로운 필드를 추가할 수 있고 그것은 데이터베이스를 변경하지 않고 저장될 수 있습니다.
잘 알려진 NoSQL 데이터베이스에는 Azure CosmosDB, MongoDB, CouchDB가 있습니다.
✅ 조사해봅시다 : 이러한 몇몇 NoSQL 데이터베이스 및 기능에 대해 읽어봅시다.
이 강의에서는 IoT 데이터를 저장하기 위해 NoSQL을 사용합니다.
## IoT Hub로 GPS 데이터 전송하기
지난 강의에서는 IoT 장치에 연결된 GPS 센서로부터 GPS 데이터를 캡처했습니다. IoT 데이터를 클라우드에 저장하기 위해서 그것을 IoT 서비스로 보내야합니다. 이전 프로젝트에서 사용한 것과 동일한 IoT 클라우드 서비스인 Azure IoT Hub를 다시 한 번 사용하게 됩니다.
![IoT 장치에서 IoT 허브로 GPS 원격 측정 전송](../../../../images/gps-telemetry-iot-hub.png)
### 작업 - GPS 데이터를 IoT Hub로 전송하기
1. free 티어를 사용해서 새로운 IoT Hub를 생성합니다.
> ⚠️ 필요하다면 [프로젝트 2의 Lesson 4에서 IoT Hub 생성을 위한 지침](../../../../2-farm/lessons/4-migrate-your-plant-to-the-cloud/README.md#create-an-iot-service-in-the-cloud) 을 참조할 수 있습니다.
새로운 리소스 그룹을 생성해야합니다. 새 리소스 그룹을 `gps-sensor`라고 지정하고, 새로운 IoT Hub의 이름을 `gps-sensor-<your name>`과 같이 `gps-sensor`에 기반한 고유한 이름으로 지정합니다.
> 💁 이전 프로젝트에서 사용한 IoT Hub를 가지고 있다면 그것을 재사용해도 좋습니다. 다른 서비스를 만들 때 이 IoT Hub의 이름과 해당 서비스가 속한 리소스 그룹을 사용해야 합니다.
1. IoT Hub에 새 장치를 추가합니다. 해당 장치를 `gps-sensor`라 부릅니다. 장치의 연결 문자열을 가져옵니다.
1. 이전 단계의 장치 연결 문자열을 사용하여 GPS 데이터를 새로운 IoT 허브로 전송하도록 디바이스 코드를 업데이트합니다.
> ⚠️ 필요한 경우 [프로젝트 2의 lesson 4에서 IoT와 장치를 연결하는 방법](../../../../2-farm/lessons/4-migrate-your-plant-to-the-cloud/README.md#connect-your-device-to-the-iot-service)을 참조할 수 있습니다.
1. GPS data를 전송할 때 다음 형식의 JSON으로 보냅니다:
```json
{
"gps" :
{
"lat" : <latitude>,
"lon" : <longitude>
}
}
```
1. GPS 데이터를 1분마다 보내서 일일 메세지 할당량을 모두 사용하지 않도록 합니다.
Wio Terminal을 사용한다면 필요한 라이브러리들을 모두 추가하고 NTP serer에서 사용하여 시간을 설정해야 합니다. 또한 코드는 지난 수업의 기존 코드를 사용하여 GPS 위치를 보내기 전에 직렬 포트에서 모든 데이터를 읽었는지 확인해야 합니다. 다음 코드를 사용하여 JSON 문서를 생성합니다:
```cpp
DynamicJsonDocument doc(1024);
doc["gps"]["lat"] = gps.location.lat();
doc["gps"]["lon"] = gps.location.lng();
```
가상 IoT 장치를 사용하는 경우 가상 환경을 사용하여 필요한 라이브러리들을 모두 설치해야합니다.
Raspberry Pi나 가상 IoT 장치 모두 이전 강의의 기존 코드를 사용하여 위도 및 경도 값을 가져온 후 다음 코드를 사용하여 올바른 JSON 형시으로 전송합니다:
```python
message_json = { "gps" : { "lat":lat, "lon":lon } }
print("Sending telemetry", message_json)
message = Message(json.dumps(message_json))
```
> 💁 해당 코드는 [code/wio-terminal](../code/wio-terminal), [code/pi](../code/pi) or [code/virtual-device](../code/virtual-device) 폴더에 있습니다.
> 디바이스 코드를 실행하고 CLI 명령 을 사용하여 메시지가 IoT Hub로 흘러들어가고 있는지 확인합니다 .
## Hot, Warm, Cold 경로
IoT 장치에서 클라우드로 전송되는 데이터들이 항상 실시간으로 처리되는 것은 아닙니다. 어떤 데이터는 실시간 처리가 필요하고, 다른 데이터는 짧은 시간 뒤에 처리될 수 있으며, 또 다른 데이터는 훨씬 더 나중에 처리되어도 됩니다. 서로 다른 시간에 데이터를 처리하는 서로 다른 서비스로의 데이터 흐름을 Hot 경로, Warm 경로, Cold 경로라고 합니다.
### Hot 경로
Hot 경로는 실시간으로 처리되거나 거의 실시간에 근접하게 처리되어야 하는 데이터를 말합니다. 차량이 차고에 접근하고 있거나 냉장 트럭의 온도가 너무 높다는 경고를 받는 등의 경고에 Hot 경로 데이터를 사용할 수 있습니다.
Hot 경로 데이터를 사용하기 위해서 코드는 클라우드 서비스에서 이벤트를 수신하는 즉시 이벤트에 응답합니다.
### Warm 경로
Warm 경로는 수신 후 짧은 시간 동안 보고 또는 단기 분석같은 처리할 수 있는 데이터를 말합니다. 전날 수집된 데이터를 사용하는 차량 주행 거리에 대한 일일 보고서에 웜 경로 데이터를 사용할 수 있습니다.
Warm 경로 데이터는 빠르게 액세스할 수 있는 일종의 스토리지 내부의 클라우드 서비스에서 수신한 후 저장됩니다.
### Cold 경로
Cold 경로는 과거 데이터를 말하며 데이터를 장기간 저장하여 필요할 때마다 처리합니다. 예를 들어, Cold 경로를 사용하여 차량의 연간 주행 거리 보고서를 얻거나, 경로 분석을 실행하여 연료 비용을 절감할 수 있는 최적의 경로를 찾을 수 있습니다.
Cold 경로 데이터는 절대 변경되지 않고 빠르고 쉽게 쿼리할 수 있는 대량의 데이터를 저장하도록 설계된 데이터베이스인 데이터 웨어하우스에 저장됩니다. 일반적으로 클라우드 애플리케이션에서는 매일, 매주 또는 매월 정기적으로 실행되어 Warm 경로 스토리지에서 데이터 웨어하우스로 데이터를 이동하는 정기적인 작업을 수행합니다.
✅ 이 강의에서 지금까지 캡처한 데이터에 대해 생각해 봅시다. Hot 경로, Warm 경로, Cold 경로 중 어떤 데이터 입니까?
## 서버리스 코드를 이용한 GPS 이벤트 처리
데이터가 IoT 허브로 유입되면 서버리스 코드를 작성하여 Event-Hub와 호환되는 엔드포인트에 게시된 이벤트를 수신 대기할 수 있습니다. 이 경로는 Warm 경로입니다. 이 데이터는 다음 레슨에서의 여정 보고를 위해 저장되고 사용됩니다.
![IoT 장치에서 IoT 허브로 GPS 원격 측정을 전송하고 Event-Hub 트리거를 통해 Azure Functions로 전송](../../../../images/gps-telemetry-iot-hub-functions.png)
### 작업 - 서버리스 코드를 이용하여 GPS 이벤트 처리하기
1. Azure Functions CLI를 사용하여 Azure Functions App을 생성합니다. 파이썬 런타임을 사용하여 `gps-trigger` 폴더 안에에 만들고 Functions App 프로젝트 이름에도 동일한 이름을 사용합니다. 이 작업에 사용할 가상 환경을 생성해야 합니다.
> ⚠️ 필요한 경우 [프로젝트 2의 Lesson 5에서 Azure Functions Project 생성을 위한 지침](../../../../2-farm/lessons/5-migrate-application-to-the-cloud/README.md#create-a-serverless-application)을 참조할 수 있습니다.
1. IoT Hub의 Event Hub 호환 엔드포인트를 사용하는 IoT Hub 이벤트 트리거를 추가합니다.
> ⚠️ 필요한 경우 [프로젝트 2의 Lesson 5에서 IoT Hub 이벤트 트리거 생성을 위한 지침](../../../../2-farm/lessons/5-migrate-application-to-the-cloud/README.md#create-an-iot-hub-event-trigger)을 참조할 수 있습니다.
1. `local.settings.json` 파일에서 Event Hub 호환 엔드포인트 연결 문자열을 설정하고 `function.json` 파일에서 해당 항목에 대한 키를 사용합니다.
1. Azurite app을 로컬 저장 에뮬레이터로 사용합니다.
1. functions app을 실행하여 GPS 장치에서 이벤트를 수신하고 있는지 확인합니다. IoT 장치도 실행 중이고 GPS 데이터를 전송하고 있는지 확인하십시오.
```output
Python EventHub trigger processed an event: {"gps": {"lat": 47.73481, "lon": -122.25701}}
```
## Azure Storage 계정
![The Azure Storage logo](../../../../images/azure-storage-logo.png)
Azure Storage 계정은 다양한 방식으로 데이터를 저장할 수 있는 범용 스토리지 서비스입니다. 데이터를 Blob, 큐, 테이블 또는 파일로 동시에 저장할 수 있습니다.
### Blob 스토리지
_Blob_ 이라는 단어는 이진 대형 개체를 의미하지만, 구조화되지 않은 모든 데이터를 가리키는 용어가 되었습니다. IoT 데이터가 포함된 JSON 문서에서 이미지 및 동영상 파일에 이르기까지 모든 데이터를 Blob 스토리지에 저장할 수 있습니다. Blob 스토리지에는 관계형 데이터베이스의 테이블과 유사하게 데이터를 저장할 수 있는 bucket이라는 _컨테이너_ 개념이 있습니다. 이러한 컨테이너에는 Blob을 저장할 하나 이상의 폴더가 있을 수 있으며, 각 폴더에는 파일이 컴퓨터 하드 디스크에 저장되는 방식과 유사하게 다른 폴더가 포함될 수 있습니다.
이번 강의에서는 IoT 데이터를 저장하기 위해 Blob 스토리지를 사용합니다.
✅ 조사하기: [Azure Blob Storage](https://docs.microsoft.com/azure/storage/blobs/storage-blobs-overview?WT.mc_id=academic-17441-jabenn)에 대해 읽어보세요.
### Table 스토리지
Table 스토리지는 반정형 데이터를 저장할 수 있습니다. Table 스토리지는 실제로 NoSQL 데이터베이스이므로 미리 정의된 테이블 집합이 필요하지 않지만 각 행을 정의하는 고유 키를 사용하여 하나 이상의 테이블에 데이터를 저장하도록 설계되었습니다.
✅ 조사하기: [Azure Table Storage](https://docs.microsoft.com/azure/storage/tables/table-storage-overview?WT.mc_id=academic-17441-jabenn)에 대해 읽어보세요.
### Queue 스토리지
Queue 스토리지를 사용하면 최대 64KB 크기의 메시지를 큐에 저장할 수 있습니다. Queue의 뒤에 메시지를 추가하고 앞에서 읽어나갈 수 있습니다. Queue는 저장 공간이 있는 한 메시지를 무기한 저장하므로 메시지를 장기간 저장하고 필요할 때 읽을 수 있습니다. 예를 들어 GPS 데이터를 처리하기 위해 매달 작업을 실행하려는 경우 한 달 동안 매일 작업을 Queue에 추가한 다음 월말에 모든 메시지를 Queue에서 처리할 수 있습니다.
✅ 조사하기: [Azure Queue Storage](https://docs.microsoft.com/azure/storage/queues/storage-queues-introduction?WT.mc_id=academic-17441-jabenn)에 대해 읽어보세요.
### 파일 스토리지
파일 스토리지는 클라우드의 파일 저장소이며 모든 앱 또는 장치와 업계 표준 프로토콜을 사용하여 연결할 수 있습니다. 파일 스토리지에 파일을 쓴 다음 PC 또는 Mac의 드라이브로 마운트할 수 있습니다.
✅ 조사하기: [Azure File Storage](https://docs.microsoft.com/azure/storage/files/storage-files-introduction?WT.mc_id=academic-17441-jabenn)에 대해 읽어보세요.
## 서버리스 코드와 저장소 연결하기
이제 IoT Hub의 메시지를 저장하기 위해 function app을 Blob Storage에 연결해야 합니다. 이를 수행하는 방법에는 두 가지가 있습니다:
- function 코드 내에서 Blob 스토리지 Python SDK를 사용하여 Blob 스토리지에 연결하고 데이터를 Blob으로 작성합니다.
- 출력 함수 바인딩을 사용하여 함수의 반환 값을 Blob 스토리지에 바인딩하고 Blob을 자동으로 저장합니다.
이 강의에서는 Blob 스토리지와 어떻게 상호작용 하는지 확인하기 위해 Python SDK를 사용합니다.
![이벤트 허브 트리거를 통해 IoT 장치에서 IoT 허브로 GPS 원격 측정 전송한 뒤 Azure Functions로 전송하고 BLOB 스토리지에 저장](../../../../images/save-telemetry-to-storage-from-functions.png)
데이터는 다음 형식의 JSON Blob으로 저장됩니다:
```json
{
"device_id": <device_id>,
"timestamp" : <time>,
"gps" :
{
"lat" : <latitude>,
"lon" : <longitude>
}
}
```
### 작업 - 서버리스 코드와 저장소 연결하기
1. Azure Storage 계정을 생성합니다. 이름을 `gps<your name>`과 같이 지정합니다.
> ⚠️ 필요한 경우 [프로젝트 2의 Lesson 5에서 저장소 계정 생성을 위한 지침](../../../../2-farm/lessons/5-migrate-application-to-the-cloud/README.md#task---create-the-cloud-resources)을 읽어보세요.
이전 프로젝트에서 사용한 스토리지 계정이 아직 있다면 이를 다시 사용할 수 있습니다.
> 💁 이 단원의 뒷부분에서 동일한 저장소 계정을 사용하여 Azure Functions 앱을 배포할 수 있습니다.
1. 다음 명령을 실행하여 스토리지 계정에 대한 연결 문자열을 가져옵니다.
```sh
az storage account show-connection-string --output table \
--name <storage_name>
```
`<storage_name>`을 이전 단계에서 만든 스토리지 계정의 이름으로 변경합니다.
1. 이전 단계의 값을 사용하여 스토리지 계정 연결 문자열에 대한 새 항목을 `local.settings.json` 파일에 추가합니다. 이름을 `STORAGE_CONNECTION_STRING`으로 지정하십시오.
1. `requirements.txt` 파일에 다음 내용을 추가하여 Azure storage Pip 패키지를 설치합니다 :
```sh
azure-storage-blob
```
가상 환경에 이 파일의 패키지들을 설치합니다.
> 오류가 발생하면 다음 명령을 사용하여 가상 환경의 Pip 버전을 최신 버전으로 업그레이드한 후 다시 시도하십시오.
>
> ```sh
> pip install --upgrade pip
> ```
1. `__init__.py` 파일의 `iot-hub-trigger`에 다음 import문을 추가합니다:
```python
import json
import os
import uuid
from azure.storage.blob import BlobServiceClient, PublicAccess
```
`json` 시스템 모듈은 JSON을 읽어오고 작성하는 데 사용됩니다. `os` 시스템 모듈은 연결 문자열을 읽어오는 데 사용됩니다. `uuid` 시스템 모듈은 GPS 판독을 위한 고유 ID를 생성하는 데 사용됩니다.
`azure.storage.blob` 패키지는 Blob 스토리지에서 작동하는 Python SDK가 포함되어 있습니다.
1. `main` 메서드 앞에 다음 도우미 함수를 추가합니다:
```python
def get_or_create_container(name):
connection_str = os.environ['STORAGE_CONNECTION_STRING']
blob_service_client = BlobServiceClient.from_connection_string(connection_str)
for container in blob_service_client.list_containers():
if container.name == name:
return blob_service_client.get_container_client(container.name)
return blob_service_client.create_container(name, public_access=PublicAccess.Container)
```
Python blob SDK에는 컨테이너가 없는 경우 컨테이너를 만드는 도우미 메서드가 없습니다. 이 코드는 `local.settings.json` 파일(또는 클라우드에 배포된 이후 애플리케이션 설정)에서 연결 문자열을 로드한 다음, 여기에서 `BlobServiceClient` 클래스를 만들어 blob 스토리지 계정과 상호 작용합니다. 그런 다음 blob 저장소 계정에 대한 모든 컨테이너를 순회하여 제공된 이름을 가진 컨테이너를 찾습니다. 해당 컨테이너를 찾으면 해당 컨테이너와 상호 작용하여 blob을 만들 수 있는 `ContainerClient` 클래스를 반환합니다. 컨테이너가 발견되지 않으면 컨테이너가 생성되고 새 컨테이너의 클라이언트가 반환됩니다.
새 컨테이너가 생성되면 컨테이너의 Blob을 쿼리할 수 있는 공용 액세스 권한이 부여됩니다. 이것은 다음 강의에서 GPS 데이터를 지도에 시각화하는 데 사용됩니다.
1. 토양 수분과는 달리 이 코드를 사용하면 모든 이벤트를 저장할 수 있으므로 다음 코드를 `main` 함수의 `logging` 문 아래에 있는 `for event in events:` 루프 안에 추가합니다:
```python
device_id = event.iothub_metadata['connection-device-id']
blob_name = f'{device_id}/{str(uuid.uuid1())}.json'
```
이 코드는 이벤트 메타데이터에서 장치 ID를 가져온 다음 이를 사용하여 Blob 이름을 만듭니다. Blob은 폴더에 저장될 수 있으며 장치 ID는 폴더 이름에 사용되므로 각 장치는 하나의 폴더에 모든 GPS 이벤트를 포함합니다. Blob 이름은 이 폴더 다음에 슬래시로 구분된 문서 이름으로, Linux 및 macOS 경로와 유사합니다(Windows와 유사하지만 Windows는 백슬래시를 사용함). 문서 이름은 Python의 `uuid` 모듈을 사용하여 생성된 고유 ID이며 파일 형식은 `json`을 사용합니다.
예를 들어, `gps-sensor` 디바이스 ID의 경우 Blob 이름은 `gps-sensor/a9487ac2-b9cf-11eb-b5cd-1e00621e3648.json`이 됩니다.
1. 이 뒤에 다음 코드를 추가합니다:
```python
container_client = get_or_create_container('gps-data')
blob = container_client.get_blob_client(blob_name)
```
이 코드는 `get_or_create_container` 도우미 클래스를 사용하여 컨테이너 클라이언트를 가져온 다음 blob 이름을 사용하여 blob 클라이언트 개체를 가져옵니다. 이러한 blob 클라이언트는 기존 blob을 참조하거나, 이 경우처럼 새로운 blob을 참조할 수 있습니다.
1. 이 뒤에 다음 코드를 추가합니다:
```python
event_body = json.loads(event.get_body().decode('utf-8'))
blob_body = {
'device_id' : device_id,
'timestamp' : event.iothub_metadata['enqueuedtime'],
'gps': event_body['gps']
}
```
이렇게 하면 Blob Storage에 기록될 Blob의 본문이 빌드됩니다. 이는 장치 ID, 원격 분석이 IoT Hub로 전송된 시간 및 원격 분석의 GPS 좌표가 포함하는 JSON 문서입니다.
> 💁 메시지가 전송된 시간을 가져오려면 현재 시간이 아니라 메시지의 대기열에 포함된 시간을 사용하는 것이 중요합니다. Functions App이 실행되고 있지 않으면 선택되기 전에 잠시 동안 허브에 있을 수 있습니다.
1. 이 코드 아래에 다음을 추가합니다:
```python
logging.info(f'Writing blob to {blob_name} - {blob_body}')
blob.upload_blob(json.dumps(blob_body).encode('utf-8'))
```
이 코드는 blob이 세부 정보와 함께 작성될 예정임을 기록한 다음, blob 본문을 새 blob의 내용으로 업로드합니다.
1. Functions app을 실행합니다. 출력에서 모든 GPS 이벤트에 대해 Blob이 작성되는 것을 볼 수 있습니다.
```output
[2021-05-21T01:31:14.325Z] Python EventHub trigger processed an event: {"gps": {"lat": 47.73092, "lon": -122.26206}}
...
[2021-05-21T01:31:14.351Z] Writing blob to gps-sensor/4b6089fe-ba8d-11eb-bc7b-1e00621e3648.json - {'device_id': 'gps-sensor', 'timestamp': '2021-05-21T00:57:53.878Z', 'gps': {'lat': 47.73092, 'lon': -122.26206}}
```
> 💁 동시에 IoT Hub 이벤트 모니터를 실행하고 있지는 않은지 확인합니다.
> 💁 해당 코드는 [code/functions](../code/functions) 폴더에 있습니다.
### 작업 - 업로드된 Blob 확인
1. 생성된 blob을 보려면 스토리지 계정을 보고 관리할 수 있는 무료 도구인 [Azure Storage Explorer](https://azure.microsoft.com/features/storage-explorer/?WT.mc_id=cademic-17441-jaben)를 사용하거나 CLI에서 확인할 수 있습니다.
1. CLI를 사용하기 위해서는 우선적으로 계정 key가 필요합니다. 다음 명령어를 실행하여 해당 key를 얻습니다:
```sh
az storage account keys list --output table \
--account-name <storage_name>
```
`<storage_name>`을 스토리지 계정의 이름으로 수정합니다.
`key1`의 값을 복사합니다.
1. 다음 명령어를 실행하여 컨테이너의 Blob을 나열합니다.
```sh
az storage blob list --container-name gps-data \
--output table \
--account-name <storage_name> \
--account-key <key1>
```
`<storage_name>` 을 스토리지 계정의 이름으로 바꾸고, `<key1>`값을 이전 단계에서 복사한 `<key1>` 값으로 바꿉니다.
그러면 컨테이너의 모든 Blob이 나열됩니다:
```output
Name Blob Type Blob Tier Length Content Type Last Modified Snapshot
---------------------------------------------------- ----------- ----------- -------- ------------------------ ------------------------- ----------
gps-sensor/1810d55e-b9cf-11eb-9f5b-1e00621e3648.json BlockBlob Hot 45 application/octet-stream 2021-05-21T00:54:27+00:00
gps-sensor/18293e46-b9cf-11eb-9f5b-1e00621e3648.json BlockBlob Hot 45 application/octet-stream 2021-05-21T00:54:28+00:00
gps-sensor/1844549c-b9cf-11eb-9f5b-1e00621e3648.json BlockBlob Hot 45 application/octet-stream 2021-05-21T00:54:28+00:00
gps-sensor/1894d714-b9cf-11eb-9f5b-1e00621e3648.json BlockBlob Hot 45 application/octet-stream 2021-05-21T00:54:28+00:00
```
1. 다음 명령어를 이용하여 blob 중 하나를 다운로드 합니다:
```sh
az storage blob download --container-name gps-data \
--account-name <storage_name> \
--account-key <key1> \
--name <blob_name> \
--file <file_name>
```
`<storage_name>`를 스토리지 계정의 이름으로 바꿉니다. `<key1>` 값을 이전 단계에서 복사한 `<key1>` 값으로 바꿉니다.
폴더 이름을 포함하여 마지막 단계 출력의 `Name` 열에 있는 전체 이름으로 `<blob_name>`을 바꿉니다. `<file_name>`을 blob을 저장할 로컬 파일의 이름으로 바꿉니다.
다운로드가 완료되면 이 JSON 파일을 VS Code에서 열 수 있으며 GPS 위치 세부 정보가 포함된 Blob이 표시됩니다:
```json
{
"device_id": "gps-sensor",
"timestamp": "2021-05-21T00:57:53.878Z",
"gps": { "lat": 47.73092, "lon": -122.26206 }
}
```
### 업무 - Functions App을 클라우드에 배포가히
이제 Function app이 작동하므로 클라우드에 배포할 수 있습니다.
1. 이전에 생성한 스토리지 계정을 사용하여 새로운 Azure Functions app을 생성합니다. `gps-sensor-`와 같이 이름을 지정하고 끝 부분에 임의의 단어나 이름과 같은 고유 식별자를 추가합니다.
> ⚠️ 필요하다면 [프로젝트 2의 Lesson 5에서 Functions app을 생성하기 위한 지침](../../../../2-farm/lessons/5-migrate-application-to-the-cloud/README.md#task---create-the-cloud-resources)을 읽어보세요.
1. `IOT_HUB_CONNECTION_STRING``STORAGE_CONNECTION_STRING` 값을 Application 설정에 업로드합니다.
> ⚠️ 필요하다면 [프로젝트 2의 Lesson 5에서 Application 설정 업로드를 위한 지침](../../../../2-farm/lessons/5-migrate-application-to-the-cloud/README.md#task---upload-your-application-settings)을 읽어보세요.
1. 로컬에 있는 Functions app을 클라우드로 배포합니다.
> ⚠️ 필요하다면 [프로젝트 2의 Lesson 5에서 Functions app 배포를 위한 지침](../../../../2-farm/lessons/5-migrate-application-to-the-cloud/README.md#task---deploy-your-functions-app-to-the-cloud)을 읽어보세요.
---
## 🚀 도전
GPS 데이터는 완벽하게 정확하지 않으며, 특히 터널과 높은 건물의 지역에서 감지되는 위치는 수 미터 정도 떨어져 있을 수 있습니다.
위성 내비게이션이 이를 어떻게 이것을 극복할 수 있을지 생각해 보세요. 위성 내비게이션이 당신의 위치를 더 잘 예측할 수 있게 해주는 데이터에는 무엇이 있습니까?
## 강의 후 퀴즈
[강의 후 퀴즈](https://black-meadow-040d15503.1.azurestaticapps.net/quiz/24)
## 복습 및 자습
- 정형 데이터에 대해 [Data model page on Wikipedia](https://wikipedia.org/wiki/Data_model)에서 더 읽어보세요.
- 반정형 데이터에 대해 [Semi-structured data page on Wikipedia](https://wikipedia.org/wiki/Semi-structured_data)에서 더 읽어보세요
- 비정형 데이터에 대해 [Unstructured data page on Wikipedia](https://wikipedia.org/wiki/Unstructured_data)에서 더 읽어보세요
- Azure 스토리지와 다른 스토리지 타임에 대해 더 알아보고 싶다면 [Azure Storage documentation](https://docs.microsoft.com/azure/storage/?WT.mc_id=academic-17441-jabenn)를 참고하세요.
## 과제
[함수 바인딩 조사](../assignment.md)
Loading…
Cancel
Save