2022. 12. 27. 14:44ㆍ개발/Node-red
2022.12.26 - [기록/개발 노트] - [Node-red] http 통신 오류 - 1
Node-red에서 오류가 발생했었다.
이어서 수정한다.
아두이노 수정
String sOut = "";
sOut += String(digitalRead(RELAY1_PIN));
sOut += String(digitalRead(RELAY2_PIN));
sOut += String(digitalRead(RELAY3_PIN));
sOut += String(digitalRead(RELAY4_PIN));
doc["temp"] = temp.temperature;
doc["humi"] = humidity.relative_humidity;
doc["mac"] = sMac;
doc["ip"] = WiFi.localIP().toString();
doc["type"] = type;
doc["out"] = sOut;
//doc["email"]= sEmail;
char jsonBuffer[512];
serializeJson(doc, jsonBuffer);
String out_str = sMac + "-out";
const char* topic_out = out_str.c_str();
client.publish(topic_out, jsonBuffer);
아두이노에서 mqtt 로 데이터 출력하는 포맷이다.
key 'out'을 추가했다.
out 은 각 릴레이와 연결된 핀 상태를 반환한다.
pull-up 저항 때문에 반대로 동작한다.
ESP32핀이 0일 때 릴레이가 on 되고
1일 때 릴레이가 off 된다.
즉 1번 on 2번 on 3번 off 4번 on 상태면
"0010" 이 out의 value로 반환된다.
위와 같이 정상적으로 데이터가 수신된다.
하지만 /login에는 나타나지 않는다.
예전에 /login이 정상적으로 동작했던
Node-red 소스를 살펴보았다.
이 소스는 websocket 주소가 잘 동작한다.
반면 같은 websocket 주소를 사용하는데
이 flow 에서는 오류가 발생한다.
혹시 주소가 같아서 충돌이 발생하나? 싶어서
주소를 변경해주었다.
주소를 겹치지 않도록 변경해주었으나
이번에는 /login 페이지는 동작하지만
버튼이 눌러도 변하지 않는다.
현재 사용하는 Node-red flow의 흐름상
사진에 표시한 부분에서 오류가 있지 않는 한
/login 페이지에 오류가 발생할 이유가 없다.
이 부분에 오류가 있다고 가정하고
한 줄 한 줄 살펴봤다.
0,1,2,3 List 노드 검토
var i,j;
var s,sOut;
var r;
sOut="<table>"
sOut+="<tr> <th>모델</th> <th>모니터링</th> <th>이름</th> </tr>"
for(i=0;i<msg.payload.length;i++) {
//r="<input type='hidden' name='chip' value='"+msg.payload[i].chip+"'>";
s="";
s+="<tr><th>";
s+="<form action='/display'>";
s+="<input type='hidden' name='mac' value='"+msg.payload[i].mac+"'>";
s+="<input type='hidden' name='act' value='1'>";
s+="<button type='submit' name='value' value='0' class='button buttonM'>"+msg.payload[i].model+"</button></a>";
s+="</form>";
s+="</th>";
if(msg.payload[i].type==100) {
s+="<td>"
s+="<table>";
s+="<tr>";
s+="<td></td>";
//for(j=0;j<4;j++)
//s+="<td>"+String(j)+"</td>";
s+="<td>"+"히터"+"</td>";
s+="<td>"+"냉풍"+"</td>";
s+="<td>"+"환기"+"</td>";
s+="<td>"+"LED"+"</td>";
s+="</tr>";
s+="<tr>";
s+="<td>출력</td>";
for(j=0;j<4;j++)
s+="<td><span id='"+msg.payload[i].mac+"-out"+String(j)+"'></span></td>";
s+="</tr>";
s+="</table>";
s+="</td>";
s+="<td>"+msg.payload[i].name+"</td>";
}
s+="</tr>"
sOut=sOut+s+"<br>";
}
var newMsg={};
newMsg.payload=msg.payload;
msg.payload={};
msg.payload.list=sOut;
msg.payload.style=global.get("style");
msg.payload.script=global.get("script");
msg.payload.menu=global.get("menu");
return [msg,newMsg];
html 적용 후 바로 실행해볼 수 없기 때문에 ( javascript )
s 라는 문자열에 html 태그 및 형식을 담아
msg로 리턴한다.
sOut에 담아 msg.payload.list로 출력하면
뒤에 이어지는 html노드 및
http response에 의해
웹이 형식에 맞게 생성된다.
s+="<tr>";
s+="<td></td>";
s+="<td>"+"히터"+"</td>";
s+="<td>"+"냉풍"+"</td>";
s+="<td>"+"환기"+"</td>";
s+="<td>"+"LED"+"</td>";
s+="</tr>";
위 코드로 인해
표의 1행이 생성된다.
s+="<tr>";
s+="<td>출력</td>";
for(j=0;j<4;j++)
s+="<td><span id='"+msg.payload[i].mac+"-out"+String(j)+"'></span></td>";
s+="</tr>";
for문을 사용해 4개의 <td> 태그로 4개의 버튼 공간을 생성한다.
수신받은 msg의 mac 주소 말단에
-out + j ( 0 ~ 4 )를 추가해 각 칸의 id를 할당받는다.
사진의 1 2 3 4 칸마다
mac-out0 mac-out1 식으로 id가 부여된다.
Web Socket script 노드 검토
var ws;
var wsUri = "ws:";
var loc = window.location;
console.log(loc);
if (loc.protocol === "https:") { wsUri = "wss:"; }
// This needs to point to the web socket in the Node-RED flow
// ... in this case it's ws/simple
wsUri += "//" + loc.host + loc.pathname.replace("display","ws/simple990115");
function wsConnect() {
console.log("connect",wsUri);
ws = new WebSocket(wsUri);
//var line = ""; // either uncomment this for a building list of messages
ws.onmessage = function(msg) {
var line = ""; // or uncomment this to overwrite the existing message
// parse the incoming message as a JSON object
var data = JSON.parse(msg.data);
//var data = msg.data;
console.log(data);
if(data.type==100) {
if(data.out[0]=='0')
document.getElementById(data.mac+'-out0').innerHTML = "<button class='button button-on' onclick='doit(\"{^mac^:^"+data.mac+"^,^type^:14,^outNo^:0,^value^:0}\");'></button>";
else
document.getElementById(data.mac+'-out0').innerHTML = "<button class='button button-off' onclick='doit(\"{^mac^:^"+data.mac+"^,^type^:14,^outNo^:0,^value^:1}\");'></button>";
if(data.out[1]=='0')
document.getElementById(data.mac+'-out1').innerHTML = "<button class='button button-on' onclick='doit(\"{^mac^:^"+data.mac+"^,^type^:14,^outNo^:1,^value^:0}\");'></button>";
else
document.getElementById(data.mac+'-out1').innerHTML = "<button class='button button-off' onclick='doit(\"{^mac^:^"+data.mac+"^,^type^:14,^outNo^:1,^value^:1}\");'></button>";
if(data.out[2]=='0')
document.getElementById(data.mac+'-out2').innerHTML = "<button class='button button-on' onclick='doit(\"{^mac^:^"+data.mac+"^,^type^:14,^outNo^:2,^value^:0}\");'></button>";
else
document.getElementById(data.mac+'-out2').innerHTML = "<button class='button button-off' onclick='doit(\"{^mac^:^"+data.mac+"^,^type^:14,^outNo^:2,^value^:1}\");'></button>";
if(data.out[3]=='0')
document.getElementById(data.mac+'-out3').innerHTML = "<button class='button button-on' onclick='doit(\"{^mac^:^"+data.mac+"^,^type^:14,^outNo^:3,^value^:0}\");'></button>";
else
document.getElementById(data.mac+'-out3').innerHTML = "<button class='button button-off' onclick='doit(\"{^mac^:^"+data.mac+"^,^type^:14,^outNo^:3,^value^:1}\");'></button>";
}
}
ws.onopen = function() {
// update the status div with the connection status
//document.getElementById('status').innerHTML = "connected";
//ws.send("Open for data");
console.log("connected");
}
ws.onclose = function() {
// update the status div with the connection status
//document.getElementById('status').innerHTML = "not connected";
// in case of lost connection tries to reconnect every 3 secs
setTimeout(wsConnect,3000);
}
}
function doit(m) {
if (ws) { ws.send(m); }
}
평소에 수정할때는 if(data.type) 부분만 다뤘었다.
if(data.type==100) {
if(data.out[0]=='0')
document.getElementById(data.mac+'-out0').innerHTML = "<button class='button button-on' onclick='doit(\"{^mac^:^"+data.mac+"^,^type^:14,^outNo^:0,^value^:0}\");'></button>";
else
document.getElementById(data.mac+'-out0').innerHTML = "<button class='button button-off' onclick='doit(\"{^mac^:^"+data.mac+"^,^type^:14,^outNo^:0,^value^:1}\");'></button>";
if(data.out[1]=='0')
document.getElementById(data.mac+'-out1').innerHTML = "<button class='button button-on' onclick='doit(\"{^mac^:^"+data.mac+"^,^type^:14,^outNo^:1,^value^:0}\");'></button>";
else
document.getElementById(data.mac+'-out1').innerHTML = "<button class='button button-off' onclick='doit(\"{^mac^:^"+data.mac+"^,^type^:14,^outNo^:1,^value^:1}\");'></button>";
if(data.out[2]=='0')
document.getElementById(data.mac+'-out2').innerHTML = "<button class='button button-on' onclick='doit(\"{^mac^:^"+data.mac+"^,^type^:14,^outNo^:2,^value^:0}\");'></button>";
else
document.getElementById(data.mac+'-out2').innerHTML = "<button class='button button-off' onclick='doit(\"{^mac^:^"+data.mac+"^,^type^:14,^outNo^:2,^value^:1}\");'></button>";
if(data.out[3]=='0')
document.getElementById(data.mac+'-out3').innerHTML = "<button class='button button-on' onclick='doit(\"{^mac^:^"+data.mac+"^,^type^:14,^outNo^:3,^value^:0}\");'></button>";
else
document.getElementById(data.mac+'-out3').innerHTML = "<button class='button button-off' onclick='doit(\"{^mac^:^"+data.mac+"^,^type^:14,^outNo^:3,^value^:1}\");'></button>";
}
수신받은 msg 중 out 의 값에 따라서
HTML 버튼 2가지 중 하나를 출력한다.
HTML 버튼은 on 상태 off 상태 2가지가 있다. ( 색깔의 차이 )
즉 버튼을 누를때마다 마치 버튼이 실제로 변하는 것처럼
새로운 형태의 버튼을 즉각적으로 출력해주는 것이다.
이 부분에는 딱히 오류가 없어서
윗줄부터 살펴보았다.
var ws;
var wsUri = "ws:";
var loc = window.location;
console.log(loc);
if (loc.protocol === "https:") { wsUri = "wss:"; }
// This needs to point to the web socket in the Node-RED flow
// ... in this case it's ws/simple
wsUri += "//" + loc.host + loc.pathname.replace("display","ws/simple990115");
websocket 관련 Uri 를 선언하는 부분인데
ws/simple990115 가 선언되어있었다.
즉
데이터는 아까 수정했던
위 사진대로의 Uri에 전송하고
script 처리는 잘못된 Uri와 연동되어서
/ws/simplee 에서 버튼이 동작하지 않는 것이었다.
wsUri += "//" + loc.host + loc.pathname.replace("display","ws/simplee");
위와 같이 수정 후 테스트 해보았다.
해결
위와 같이 정상적으로 동작한다.
환기 버튼을 누르면
msg.out 값이 1111에서 1101로 변한다.
그에 맞춰서 웹 페이지의 버튼도 변한다.
해결!
1. webSocket 에 대한 개념 부족
webSocket 의 모든걸 알고있었다면
무조건 Uri먼저 확인해봤을 것 같은데
처음에는 아두이노 혹은 mongoDB에 저장하는 과정이
원인이라고 생각했다.
더 빨리 해결할 수 있었을텐데 아쉽다.
2. ESP32( 아두이노 )의 출력데이터 out 생각못함
아두이노 에서는 mqtt 데이터만 잘 송신하면
다른 문제는 없을거라고 확실한 근거없는 판단
데이터가 잘 송신되긴 하지만
data.out 이 필요했는데
out 데이터 없이 동작 하고있었다.
'개발 > Node-red' 카테고리의 다른 글
[Node-red] Custom node 중복사용 불가 해결 (0) | 2022.12.28 |
---|---|
[Node-red] http 통신 오류 - 1 (0) | 2022.12.26 |
[Node-red] http 통신 Custom node 제작 (0) | 2022.12.23 |
[Node-red] Custom node 오류 - 중복사용 불가 (0) | 2022.12.22 |
[Node-red] 새로운 릴레이 노드 제작 - 1 (0) | 2022.12.21 |