2022. 12. 5. 11:52ㆍ개발/Node-red
2022.11.21 - [기록/개발 노트] - [Node-red] Schedule node 수정 - 4
[Node-red] Schedule node 수정 - 4
2022.11.21 - [기록/개발 노트] - [Node-red] Custom node 수정 - 3 [Node-red] Custom node 수정 - 3 마지막 수정 후 보완할 점들 mqtt 통신 불안정 mqtt 통신 불안정에 따른 Node-red 서버 중지 ( cmd 에서 자주 node-red 종료
iruk.tistory.com
Node-red 에서 새로운 custom node를 만들어 보았다.
위 링크에서 만들었던 schedule node는
시간 데이터를 입력받아 타이머 기능을 한다.
지정 시간이 되면 MQTT프로토콜을 사용해
ESP32에 원격으로 데이터를 전송해 릴레이가 동작한다.
새로 만든 custom node는
단순히 JSON 데이터를 입력받아서
MQTT 로 ESP32를 제어한다.
schedule node 와 별개로
시간 데이터 없이 단순 동작을 구현한다.
.js 파일
node.on('input', function(msg) {
var pLoad = msg.payload;
var msg_toPublish = '{\"mac\" : ' + "\"" + String(config.id) + "\",\"type\" : 100,\"outNo\" : "
+ String(pLoad.outNo) + ",\"value\" : " + String(pLoad.value) + "}";
console.log(msg.payload);
//var pLoad = JSON.parse(msg.payload);
if(pLoad.outNo != undefined && pLoad.value != undefined){
client.publish(inTopic, msg_toPublish);
}
//client.publish(inTopic, msg.payload);
//node.send(msg);
});
custom node에 msg가 입력됐을 때 실행 함수다.
입력된 msg에 outNo, value Key가 입력됐을 때만
msg_toPublish 문자열 데이터를 MQTT로 전송한다.
var mqtt = require('mqtt');
var nodeContext = this.context();
var outTopic= String(config.id) + "-out";
var inTopic = String(config.id) + "-in";
MQTT의 Topic은 ESP32의 고유번호를 사용하도록 했다.
위와 같이 ESP32 겉면에
C049EF34003C 같이 고유번호가 있다.
Arduino 소스로 확인해본 결과
uint8_t macH[6]="";
WiFi.macAddress(macH);
sprintf(mac,"%02x%02x%02x%02x%02x%02x%c",macH[0], macH[1], macH[2], macH[3], macH[4], macH[5],0);
sMac=mac;
clientName=mac;
Serial.println(mac);
WiFi.macAddress(macH) 로 추출한 값과
ESP32의 겉면에 적혀있는 값이 같았다.
따라서 사용자들로 하여금
각자 사용하는 ESP32의 번호는 겹치지 않으므로
본인 칩을 확인해서 node에 입력하면
그 값에 따라서 MQTT topic이 각각 부여된다.
위와 같이 node 설정에서 칩 겉면의 값을 입력하면
사용자 모두의 MQTT topic이 고유한 값으로 설정된다.
Arduino 처리
//outNo1 켜기 function
msg.payload={
"outNo":1,
"value":1
}
return msg;
// outNo0 끄기 function
msg.payload={
"outNo":0,
"value":0
}
return msg;
위와 같이 node-red flow를 구성했다.
// 아두이노 데이터 수신할 때 callback 처리문
deserializeJson(doc,payload);
root = doc.as<JsonObject>();
int md_value = root["outNo"];
int payload_val = root["value"];
Serial.print("payload_val : ");
Serial.println(payload_val);
switch (md_value){
//heat = 0, cool = 1, exhaust = 2, led = 3
case 0 :
on_off(payload_val, heat_pin);
Serial.println("case 0");
break;
case 1 :
on_off(payload_val, cool_pin);
Serial.println("case 1");
break;
case 2 :
on_off(payload_val, exha_pin);
Serial.println("case 2");
break;
default :
on_off(payload_val, led_pin);
Serial.println("last case");
}
outNo 와 value Key값을 반환해서 각각의 처리를 실행한다.
다른 방식의 동작 추가
위 까지의 동작은
outNo, value 두가지 key를 사용했다.
즉 사용자가 on/off 하고 싶은 릴레이의 동작 데이터를
하나 하나 기입해줘야 했다.
번거로운 점이 있으므로 모든 릴레이의 동작 데이터를
하나의 msg로 전송하도록 하는 방식을 생각했다.
// 노드레드 function 코드
msg.payload={
"outNo0":0,
"outNo1": 0,
"outNo2": 0,
"outNo3": 0
}
return msg;
위와 같이 outNo0 ~ outNo3 데이터를 한 번에 전송해서
사용자가 보다 편리하게 제어할 수 있도록 한다.
.js 파일 수정
node.on('input', function(msg) {
var pLoad = msg.payload;
var msg_toPublish = '{\"mac\" : ' + "\"" + String(config.id) + "\",\"type\" : 100,\"outNo\" : "
+ String(pLoad.outNo) + ",\"value\" : " + String(pLoad.value) + "}";
//-----추가-------
var msg_toPublish2 = '{\"mac\" : ' + "\"" + String(config.id) + "\",\"type\" : 100,\"outNo0\" : "
+ String(pLoad.outNo0) + ",\"outNo1\" : " + String(pLoad.outNo1) + ",\"outNo2\" : " + String(pLoad.outNo2)
+ ",\"outNo3\" : " + String(pLoad.outNo3) + "}";
//-----추가-------
console.log(msg.payload);
//var pLoad = JSON.parse(msg.payload);
if(pLoad.outNo != undefined && pLoad.value != undefined){
client.publish(inTopic, msg_toPublish);
}
//-----추가-------
else if(pLoad.outNo0 != undefined && pLoad.outNo1 != undefined && pLoad.outNo2 != undefined && pLoad.outNo3 != undefined){
client.publish(inTopic,msg_toPublish2);
}
//-----추가-------
//client.publish(inTopic, msg.payload);
//node.send(msg);
});
outNo0 outNo1 outNo2 outNo3 값이 동시에 존재할때만
동작이 구현되도록 했다.
아두이노의 처리문도 수정해서 동작한다.
아두이노 처리문 수정
int md_value = root["outNo"]; // 구분해서 들어오는 데이터
int payload_val = root["value"];
Serial.print("payload_val : ");
Serial.println(payload_val);
int out0 = root["outNo0"]; // 한 줄로 들어오는 데이터
int out1 = root["outNo1"];
int out2 = root["outNo2"];
int out3 = root["outNo3"];
if(root["outNo0"] && root["outNo1"] && root["outNo2"] && root["outNo3"]){
Serial.println("test");
}
기존에 사용하던 outNo, value 두 가지 key를 제외하고
4가지 key를 추가했다.
outNo0 outNo1 outNo2 outNo3 데이터를 반환해서
처리 동작을 구현한다.
전체 데이터가 수신됐을 때
시리얼 모니터에 'test'를 출력하도록 한다.
오류
분명 전체 데이터가 한 번에 들어왔는데
아두이노 에서는 outNo, value 가 들어왔을 경우로 인식한다.
int md_value = root["outNo"]; // 구분해서 들어오는 데이터
int payload_val = root["value"];
switch (md_value){
//heat = 0, cool = 1, exhaust = 2, led = 3
case 0 :
on_off(payload_val, heat_pin);
Serial.println("case 0");
break;
위 처리로 인식해서 case 0 이 출력되는 상태다.
int md_value = root["outNo"]; // 구분해서 들어오는 데이터
int payload_val = root["value"];
Serial.print("payload_val : ");
Serial.println(payload_val);
int out0 = root["outNo0"]; // 한 줄로 들어오는 데이터
int out1 = root["outNo1"];
int out2 = root["outNo2"];
int out3 = root["outNo3"];
if(root["outNo0"] && root["outNo1"] && root["outNo2"] && root["outNo3"]){
Serial.println("test");
}
root["outNo"] 와 root["outNo0"] 에서 충돌이 나는건가 싶어서
아두이노와 노드의 소스를 수정했다.
오류 후 수정
// node 소스 수정
node.on('input', function(msg) {
var pLoad = msg.payload;
var msg_toPublish = '{\"mac\" : ' + "\"" + String(config.id) + "\",\"type\" : 100,\"outNo\" : "
+ String(pLoad.outNo) + ",\"value\" : " + String(pLoad.value) + "}";
var msg_toPublish2 = '{\"mac\" : ' + "\"" + String(config.id) + "\",\"type\" : 100,\"No0\" : "
+ String(pLoad.outNo0) + ",\"No1\" : " + String(pLoad.outNo1) + ",\"No2\" : " + String(pLoad.outNo2)
+ ",\"No3\" : " + String(pLoad.outNo3) + "}";
console.log(msg.payload);
//var pLoad = JSON.parse(msg.payload);
if(pLoad.outNo != undefined && pLoad.value != undefined){
client.publish(inTopic, msg_toPublish);
}
else if(pLoad.outNo0 != undefined && pLoad.outNo1 != undefined && pLoad.outNo2 != undefined && pLoad.outNo3 != undefined){
client.publish(inTopic,msg_toPublish2);
}
//client.publish(inTopic, msg.payload);
//node.send(msg);
});
// 아두이노 처리문 수정
int out0 = root["No0"]; // 한 줄로 들어오는 데이터
int out1 = root["No1"];
int out2 = root["No2"];
int out3 = root["No3"];
if(root["No0"] && root["No1"] && root["No2"] && root["No3"]){
Serial.println("test");
}
node 에서 msg를 인식하고, MQTT 데이터를 송신할 때
key를 outNo0 ~ outNo3 에서 No0~No3 로 수정했다.
그에 따라서 아두이노 처리문도 같이 수정했다.
데이터는 정상적으로 수신된다.
하지만 'test'가 출력되지 않는다.
No0 ~ No3 이 존재하므로 'test'가 출력돼야 하는데
이유를 모르겠다. 다른 방식으로 수정해보았다.
오류 후 수정 - 2
if(root["No0"] && root["No1"] && root["No2"] && root["No3"]){
Serial.println("test");
}
else if(root["outNo"] && root["value"]){
int md_value = root["outNo"];
int payload_val = root["value"];
switch (md_value){
//heat = 0, cool = 1, exhaust = 2, led = 3
case 0 :
on_off(payload_val, heat_pin);
Serial.println("case 0");
break;
case 1 :
on_off(payload_val, cool_pin);
Serial.println("case 1");
break;
case 2 :
on_off(payload_val, exha_pin);
Serial.println("case 2");
break;
default :
on_off(payload_val, led_pin);
Serial.println("last case");
}
}
위와 같이 switch 문도 else if 문에 포함시켜
outNo 와 value가 수신됐을 때만 동작하도록 했다.
case 1 이 출력되긴 하지만
on 동작일때만 출력된다. 심지어 릴레이가 off되지가 않는다.
소스에서의 오류는 아닌 것 같은데
일단 소스부터 계속 수정해보고
아니면 MQTT 프로토콜의 최대 크기 초과일수도 있겠다.
'개발 > Node-red' 카테고리의 다른 글
[Node-red] Schedule 노드 ( mqtt x ) 제작 (0) | 2022.12.09 |
---|---|
[Node-red] Relay node 제작 - 2 (0) | 2022.12.07 |
[Node-red] Custom node 만드는 방법 (0) | 2022.12.02 |
[Node-red] Custom node 배포 (0) | 2022.12.01 |
[Node-red] Schedule node 수정 - 4 (0) | 2022.11.21 |