Develop Note

IoT 모션 감지 조명: W5500-EVB-Pico, Adafruit IO, PIR 센서, IFTTT 연동 본문

개발 (Ko)

IoT 모션 감지 조명: W5500-EVB-Pico, Adafruit IO, PIR 센서, IFTTT 연동

Chalsu 2023. 9. 19. 13:27

 

Introduction

개인적으로 모션 인식 LED 센서등을 유용하게 사용하고 있다. 모션이 인식되면 LED가 켜지고 일정 시간 내에 꺼지는 방식으로 동작한다.

집의 형광등 버튼이 현관문에서 멀리 있어서 저녁 늦게 들어갈 때면 불빛 없는 방에 조심히 들어가야 한다. 센서등을 구입해 설치한 이후에는 모션 인식에 의해 센서등이 켜져서 보다 안전하게 들어갈 수 있다.

Pico 보드를 사용해서 이와 비슷한 기능을 구현해보고, 추가로 서비스를 연동해 로그를 남겨보기로 했다.

Component

  • W5500-EVB-Pico
  • M5Stack PIR Sensor: https://docs.m5stack.com/en/unit/pir
  • Picobricks (LED): 각 모듈을 분리해서 사용할 수 있지만 이번에는 그대로 사용했다.
  • Adafruit.io

Picobricks와 같은 확장 보드를 사용하면 Grove 커넥터를 사용할 수 있어서 연결이 간편하다. GPIO Pin 번호만 맞춰주면 된다. 다음과 같이 연결했다.

 

Adafruit IO

wiznet5k에서 지원하는 예제 중 aio라는 항목이 있어서 보니, Adafruit에서 지원하는 API가 있었고 http(Non-SSL)를 지원하고 있었다.

또한 Adafruit IO를 IFTTT에서도 지원하고 있어서, 이를 이용해 외부 서비스를 연동해보기로 했다.

Get Started

https://io.adafruit.com/

간단하게 정보 입력 후 가입할 수 있고, 이메일 인증을 거치면 가입이 완료된다.

매뉴얼이 예전에 작성된 것인지 화면 UI가 문서와 달라서 혼동이 있었다.

IO 페이지에 내 계정 페이지로 가면, 키 모양의 노란색 버튼이 있다.

버튼을 누르면 key가 발급 되고 곧바로 사용이 가능하다.

이제 Pico를 사용해서 피드를 올릴 건데, 무료 구독은 피드를 10개까지 생성할 수 있다.

초기 피드는 비어있는 상태이다.

wiznet5k는 아쉽게도 아직 SSL이 지원되지 않는다.

우선 예제로 주어진 CURL을 사용하여 API 동작 테스트를 진행했다.

윈도우 CMD에서 실행했는데 요청이 실패해서 리눅스 Shell(WSL)에서 실행하니 동작이 잘 됐다.

curl -X POST -H "Content-Type: application/json" -H "X-AIO-Key: <key>" --data '{"feed": {"name": "New Feed"}}' http://io.adafruit.com/api/v2/<username>/feeds

이제 Circuitpython 코드를 작성한다.

main 코드인 code.py 외에 비공개 정보를 secrets.py 파일에 별도로 작성하여 사용한다.

secrets = {
    'aio_username' : "your-aio-username",
    'aio_key' : 'your-aio-key',
}

게시된 피드는 이렇게 보인다.

이제, IFTTT로 연동해 보자.

IFTTT

IFTTT (If This Then That)는 사용자가 다양한 앱과 서비스를 연결하여 자동화된 작업을 생성할 수 있는 웹 기반 플랫폼이다. 여기에서는 Adafruit IO를 트리거로 사용하고 알람을 받기위한 서비스를 액션으로 연결할 것이다.

Trigger(If): Monitor a feed on Adafruit IO

https://ifttt.com/adafruit/triggers/monitor_your_data

Adafruit 서비스에 대해 아래 트리거를 지원하고 있다.

Connect 버튼을 클릭하면 권한 허용 팝업이 나타난다.

참고로 기존 가입했던 구글 계정 있어 시도했는데 기존 APPLET으로 계속 리다이렉트 되고 권한은 설정되지 않는 무한 반복이 발생해서 새 계정 생성 후 진행했다. 새 계정에서는 잘 된다.

피드를 생성하는 함수를 별도로 만들었다.

def create_feed(name):
    data = {
        "feed": {"name": name}
    }
    endpoint = f'http://io.adafruit.com/api/v2/{secrets["aio_username"]}/feeds'
    headers = {"X-AIO-KEY": secrets["aio_key"]}
    response = requests.post(endpoint, json=data, headers=headers)
    print(response.json())
    response.close()

w5100s-evb-pico 이름으로 피드를 생성했다.

생성된 피드에 들어가보면, 다음과 같이 피드 안에서 데이터를 누적시킬 수 있는 형태로 나타난다.

여기에 데이터를 보내고 IFTTT가 트리거 되는지 확인해 보자

Postman으로 요청할 경우 다음과 같이 포맷팅 된 데이터를 볼 수 있다.

Create data API

동일한 피드 내에 데이터를 전송할 때 Create Data API를 사용할 수 있다.

다음과 같이 피드 내에 데이터가 Timeseries 형태로 수신된 것을 볼 수 있다.

페이지를 새로고침 하지 않아도 페이지가 실시간 업데이트 된다.

main 코드에 다음과 같이 함수를 추가했다.

def create_data(feed_name, data):
    endpoint = f'http://io.adafruit.com/api/v2/{secrets["aio_username"]}/feeds/{feed_name}/data'
    headers = {"X-AIO-KEY": secrets["aio_key"]}
    response = requests.post(endpoint, json=data, headers=headers)
    print(response.json())
    response.close()

실행 및 요청에 성공했다면 다음과 같이 응답을 받을 수 있다.

Action (Then)

트리거로 전송된 데이터는 어디로 보낼 수 있을까?

많은 선택지가 있다.

  • Twitter
  • Telegram
  • Discord
  • SMS
  • IFTTT Notification

간단히 테스트 해볼 수 있는 Notifications 라는 항목과 Slack을 연동해 보았다.

IFTTT Notification

IFTTT에서 스마트폰 App을 제공하는데, 이쪽으로 푸시 알림을 받을 수 있다.

이렇게 설정되었다.

확인 후 설정을 완료한다.

다음과 같이 알람이 수신된다.

 

 

Slack

Slack 서비스에도 연결 후 메시지를 게시해 보았다.

권한 허용이 필요하다.

설정 후 테스트 해 보니, 알람이 잘 들어온다.

Sensor 및 LED 연동

모션을 인식하기 위해 PIR 센서를 사용했는데, M5Stack의 Unit 모듈이 있어서 이를 Picobricks에 GROVE 케이블로 연결해서 사용했다. 점퍼 케이블보다 연결이 간편하다.

LED는 Picobricks에 있는 WS2812를 사용했다.

모션 인식, LED 제어 코드를 각각 작성 및 테스트하고 코드를 병합하는 방식으로 진행했다.
모션 센서 인식 코드

import board
import digitalio

PIR_PIN = board.GP17   # Pin number connected to PIR sensor output wire.

# Setup digital input for PIR sensor:
pir = digitalio.DigitalInOut(PIR_PIN)
pir.direction = digitalio.Direction.INPUT
print('Check')

# Main loop that will run forever:
old_value = pir.value
while True:
    pir_value = pir.value
    if pir_value:
        if not old_value:
            print('Motion detected!')
    else:
        if old_value:
            print('Motion ended!')
    old_value = pir_value

LED 제어 코드

import board
import neopixel
import time

pixel = neopixel.NeoPixel(board.GP6, 1)
pixel.brightness = 0.1

pixel.fill((0, 255, 0))
time.sleep(3)
pixel.fill((0, 0, 0))

Code

basic 코드를 포함한 전체 코드는 아래 Github 링크에서 참조할 수 있다.

문제점

알람이 밀려서 들어오는 문제가 있다.

동일한 Trigger를 사용하는 Applet이 2개인 것이 원인인가 싶어서 하나를 Disconnect 시키고 테스트 해봤지만 Delay 되는건 동일하다. 이 부분은 더 살펴봐야 겠다.

Reference

Circuitpython 코드 참조

https://github.com/adafruit/Adafruit_CircuitPython_Bundle

Comments