현관문 프로젝트) LED Strip + Door sensor + esp8266 & pi 6편 (AWS IoT)

최재혁·2023년 3월 6일
0

드디어 끝이 보입니다.

지금까지 진행한 일...

  1. 엔드 디바이스에서 신호를 보내면, 라즈베리파이에서 zigbee 데이터를 받고 AWS IoT로 넘겨줍니다.

  2. WLED가 설치된 ESP8266을 포트포워딩을 통해 외부IP로 접속할 수 있게 설정해 주었습니다.

그럼 이제 무엇을 해야하느냐!

EC2에 node-red를 구성해서 로직을 짜주어야 합니다!!

1. EC2 생성

EC2는 우분투 20.04로 생성하고 Public subnet에 구성해줍니다.

private subnet에 구성하는 것은 테스트를 우선 진행하고 완성한 후 이미지를 따서 넘길 생각입니다.

2. node-red 설치

ec2에 ssh 접속을 통해 node-red를 설치해 줍시다.

   curl -sL https://deb.nodesource.com/setup_12.x | sudo -E bash -
   sudo apt-get install -y nodejs build-essential
   sudo npm install -g --unsafe-perm node-red
   sudo npm install -g --unsafe-perm pm2
   pm2 start `which node-red` -- -v
   pm2 save
   pm2 startup

3. 보안그룹 (수정필요!!!)

테스트할 것이기 때문에 해당 포트에 대해 0.0.0.0/0 으로 설정했습니다.

이부분은 보안상 좋지 못한 예시입니다.

로직만 구성한 후 재정리를 하도록 하겠습니다.

4. node-red 플로우

(잘만 동작하면 되지않을까..?)

딱봐도 복잡해 보입니다.
차근 차근 살펴봅시다.

4-1. mqtt in

  1. 연필 표시를 눌러줍니다.

  2. AWS IoT엔드포인트 및 포트를 입력해 줍니다. (포트는 8883)

  3. 사용TLS에서 연필 부분을 눌러줍니다.

    라즈베리파이에 넣어놨던 인증서, private key, CA를 넣어줍니다.

  4. 확인을 누르면 연결이 완료됩니다.

4-2. function

DO : door open
DF : door close
MO : motion on
MF : motion off

//DO
var msg2 = { payload: {} };

if (msg.payload.contact === false) {
    return msg2
}
//DF, MF
var msg8 = { payload: {} };

if (msg.payload.occupancy === false) {
    return msg8;
}
//MO
var msg3 = { payload: {} };
//msg.payload.contact === true && 
if (msg.payload.occupancy === true) {
    return msg3;
}
//DO,MO
var msg7 = { payload: {} };
//msg.payload.contact === false && 
if (msg.payload.contact === false && msg.payload.occupancy === true) {
    return msg7;
}

여기서 trigger을 추가해줍니다.

이유는 door sensor가 상태값을 가지지 않기 때문에 고정시켜줌으로써 동작 안정화를 위해 달아주었습니다.

4-3. Door Open

4-3-1. 문이 열렸을 때

4-3-2. change

{"on":true,"bri":128,"transition":7,"mainseg":0,"seg":[{"id":0,"start":0,"stop":200,"grp":1,"spc":0,"of":0,"on":true,"frz":false,"bri":248,"cct":127,"col":[[255,200,0],[255,224,160],[255,255,0]],"fx":19,"sx":95,"ix":181,"pal":3,"sel":true,"rev":true,"mi":true},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0},{"stop":0}]}

API 형식으로 HTTP WLED에 request를 날려줍니다.

4-3-3. http request

4-4. Motion On

4-4-1. openweathermap 추가하기

오른쪽 위 배포하기 오른쪽에 줄3개 클릭

팔렛트 관리 클릭

설치가능한노드 에서 openweathermap 검색 후 설치

WLED 또한 설치

4-4-2. openweathermap 설정

openweathermap 에서 얻은 api key와 위도, 경도 추가

4-4-3. 0~50개의 LED는 날씨를 표시

//0~50개 weather 표시

var weather = msg.payload.weather;
var temperature = msg.payload.tempc;
var msg4 = { payload: {} };
msg4.payload.on = true
msg4.payload.bri = 128
msg4.payload.transition = 7
msg4.payload.mainseg = 0



// Set the color and effect of the first LED segment based on the weather
switch (weather) {
    case "Clear":
        msg4.payload.seg =
            [{
                "id": 0, "start": 0, "stop": 50, "grp": 1, "spc": 0, "of": 0, "on": true, "frz": false,
                "col": [[3, 169, 244], [3, 169, 244], [3, 169, 244]],
                "fx": 12,
                "sx": 95,
                "ix": 181,
                "pal": 2,
                "sel": false,
                "rev": true,
                "mi": false
            }];
        break;
    case "Clouds":
        msg4.payload.seg =
            [{
                "id": 0, "start": 0, "stop": 50, "grp": 1, "spc": 0, "of": 0, "on": true, "frz": false,
                "col": [[189, 189, 189], [189, 180, 189], [189, 200, 189]],
                "fx": 12,
                "sx": 95,
                "ix": 181,
                "pal": 2,
                "sel": false,
                "rev": true,
                "mi": false
            }];
        break;
    case "Rain":
        [{
            "id": 0, "start": 0, "stop": 50, "grp": 1, "spc": 0, "of": 0, "on": true, "frz": false,
            "col": [[33, 150, 243], [33, 150, 243], [33, 150, 243]],
            "fx": 12,
            "sx": 95,
            "ix": 181,
            "pal": 2,
            "sel": false,
            "rev": true,
            "mi": false
        }];
        break;
    case "Snow":
        [{
            "id": 0, "start": 0, "stop": 50, "grp": 1, "spc": 0, "of": 0, "on": true, "frz": false,
            "col": [[255, 245, 254], [255, 245, 254], [255, 245, 254]],
            "fx": 12,
            "sx": 95,
            "ix": 181,
            "pal": 2,
            "sel": false,
            "rev": true,
            "mi": false
        }];
        break;
    default:
        msg4.payload.seg =
            [{
                "id": 0, "start": 0, "stop": 60, "grp": 1, "spc": 0, "of": 0, "on": true, "frz": false,
                "col": [[128, 128, 128], [128, 128, 128], [128, 128, 128]],
                "fx": 12,
                "sx": 95,
                "ix": 181,
                "pal": 2,
                "sel": false,
                "rev": true,
                "mi": false
            }];
}



return msg4;
//날씨 컬러

Clear: #03A9F4 [3, 169, 244] (파란색)
Clouds: #BDBDBD [189, 189, 189] (회색)
Rain: #2196F3 [33, 150, 243] (진한 파란색)
Snow: #E1F5FE [225, 245, 254](연한 파란색)

잘 보시면 col의 배열이 3개입니다. 기준이 되는 색상 1개와 비슷한 계열의 색상 2개를 추가함으로써 밋밋한 효과를 줄일 수 있습니다.

4-4-4. 51~100개의 LED는 온도를 표시

//51 ~ 100개의 LED는 온도 표시

var weather = msg.payload.weather;
var temperature = msg.payload.tempc;
var msg6 = { payload: {} };

msg6.payload.bri = 128
msg6.payload.transition = 7
msg6.payload.mainseg = 0


// Set the color and effect of the second LED segment based on the temperature
if (temperature <= 0) {
    msg6.payload.seg =
        [{
            "id": 1, "start": 51, "stop": 100, "grp": 1, "spc": 0, "of": 0, "on": true, "frz": false,
            "col": [[135, 206, 250], [150, 206, 250], [170, 206, 250]],
            "fx": 12,
            "sx": 95,
            "ix": 181,
            "pal": 2,
            "sel": false,
            "rev": true,
            "mi": false
        }];
} else if (temperature > 0 && temperature <= 5) {
    msg6.payload.seg =
    [{
        "id": 1, "start": 51, "stop": 100, "grp": 1, "spc": 0, "of": 0, "on": true, "frz": false,
        "col": [[0, 255, 255], [100, 255, 255], [200, 255, 255]],
        "fx": 12,
        "sx": 95,
        "ix": 181,
        "pal": 2,
        "sel": false,
        "rev": true,
        "mi": false
    }];
} else if (temperature > 5 && temperature <= 10) {
    msg6.payload.seg =
        [{
            "id": 1, "start": 51, "stop": 100, "grp": 1, "spc": 0, "of": 0, "on": true, "frz": false,
            "col": [[154, 205, 50], [154, 205, 100], [154, 205, 150]],
            "fx": 12,
            "sx": 95,
            "ix": 181,
            "pal": 2,
            "sel": false,
            "rev": true,
            "mi": false
        }];
} 
else if (temperature > 10 && temperature <= 15) {
    msg6.payload.seg =
        [{
            "id": 1, "start": 51, "stop": 100, "grp": 1, "spc": 0, "of": 0, "on": true, "frz": false,
            "col": [[255, 255, 0], [255, 255, 100], [255, 255, 200]],
            "fx": 12,
            "sx": 95,
            "ix": 181,
            "pal": 2,
            "sel": false,
            "rev": true,
            "mi": false
        }];
}
else if (temperature > 15 && temperature <= 20) {
    msg6.payload.seg =
        [{
            "id": 1, "start": 51, "stop": 100, "grp": 1, "spc": 0, "of": 0, "on": true, "frz": false,
            "col": [[255, 165, 0], [255, 165, 100], [255, 165, 150]],
            "fx": 12,
            "sx": 95,
            "ix": 181,
            "pal": 2,
            "sel": false,
            "rev": true,
            "mi": false
        }];
}
else if (temperature > 20 && temperature <= 25) {
    msg6.payload.seg =
        [{
            "id": 1, "start": 51, "stop": 100, "grp": 1, "spc": 0, "of": 0, "on": true, "frz": false,
            "col": [[255, 0, 0], [255, 0, 50], [255, 0, 100]],
            "fx": 12,
            "sx": 95,
            "ix": 181,
            "pal": 2,
            "sel": false,
            "rev": true,
            "mi": false
        }];
}
else {
    msg6.payload.seg =
        [{
            "id": 1, "start": 51, "stop": 100, "grp": 1, "spc": 0, "of": 0, "on": true, "frz": false,
            "col": [[255, 0, 255], [255, 100, 255], [255, 200, 255]],
            "fx": 12,
            "sx": 95,
            "ix": 181,
            "pal": 2,
            "sel": false,
            "rev": true,
            "mi": false
        }];
}
return msg6;
//온도에 따른 컬러 값

하늘색: (135, 206, 250) 0도 이하
연녹색 (0, 255, 255) 0도 이상 5도 이하 
연두색: (154, 205, 50) 5도이상 10도이하 
노란색: (255, 255, 0) 10도이상 15도 이하 
주황색: (255, 165, 0) 15도 이상 20도 이하
빨간색: (255, 0, 0) 20도 이상 25이하
자홍색: (255, 0, 255) 25도 이상 30도 이하

4-4-5. 기타

1,2번 WLED는 OFF
3,4번 WLED는 ON

모션센서의 탐지 시간은 트리거된 후 1분이 소요되므로 모션센서에서 보여주는 LED는 1분으로 설정했습니다.

5. 왜 이딴 형식인가?

  • 모션센서가 ON 됬을 때 LED strip을 반으로 갈라서 보여주려하니 도어센서 seg 설정과 겹치는 문제가 발생되었다.
  • 즉, seg0을 1~50, seg1을 51~100으로 지정하고, seg2로 0~100으로 지정이 안되었다.
  • 따라서, 도어센서가 반응할 때는 seg0을 강제로 0~100으로 만들고, 모션센서가 반응할 때는 seg 0~50, seg1 51~100을 지정해주었다.
  • 무수한 시도끝에 이렇게 설정할 수 밖에 없었다...ㅠㅠ
profile
한다면 하는 남자! 줄여서 한남!

0개의 댓글