Esp32 - 동생 컴퓨터 감시 장치

반응형

동생 녀석 이 장치 달 때부터 표정이 매우 매우 매우 매우 좋지 않았는데 가족 블로그에 아래의 글을 작성해서 올렸다.

etc-image-0

ㅋㅋㅋ 성공인가 싶다 ㅋㅋㅋ

 

아버지 하우스 개폐기를 만들면서 업로드 하려고 포트를 너무 많이 꼽았다 빼면서 Esp32포트가 망가져 부러졌다....

그때, 임시방편으로 Vcc GND에 케이블을 잘라 +/-를 납땜하여 놓고 왔었는데 오프라인용 비상 스위치를 만들면서 바꾸려고 일단 그대로 사용중이다.

 

그래서!

 

이번에는 수정할 때에 OTA를 이용하여 업로드 하기로 했다 ( * 원래 코드가 길어지는게 싫어 하지 않았다.)

 

원래 계획은 

1. 5v sb 가져다가 Esp32에 공급하고
 - 트랜지스터로 스위치랑 병렬로 연결하여 만들고 컴퓨터를 끄기도하고 켜기도 하도록 만들고
 - 켜지면 3v3에 전원이 공급될 테니 그 전기로 켜졌는지 꺼졌는지 판단하려 했다

 ----> 메인보드에 들어가는 전기를 건들기는 불안하니까 포기
 ----> 컴퓨터가 오류가 나서 안켜져서 트렌지스터 잘라 넴..

 ----> 그러면 컴퓨터가 꺼졌는지 아닌지 알기 위해 전기를 USB로 부터 가져와
           컴퓨터가 켜지면 전기를 공급받고 메세지를 보내도록함. 

>>>>>>>>>>>>> 결국 선은 USB-A로 부터 공급받는 전기선만 남음....

etc-image-1
etc-image-2

이거 하기 전에 OTA 업로드를 위한 코드를 업로드 해야한다.

 

아두이노 코드


etc-image-3

이 예제를 바탕으로 Mqtt를 추가하고 코드를 작성!

 

#전체 코드

#include <WiFi.h>
#include <WiFiClient.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <Update.h>
#include <PubSubClient.h>
const char* host = "esp32";
const char *ssid = "olleh_WiFi_BA83";
const char *password = "0000002583";
const char* ID = "Child_Pc_Control"; // Name of our device, must be unique
const char* TOPIC = "room/pc/state";
const char* mqttUser = "XXXXXXXX";
const char* mqttPassword = "XXXXXXXXXX";
const char* broker = "172.30.1.48";
WebServer server(80);
WiFiClient wclient;
PubSubClient client(wclient);
char messages[50];
/*
* Login page
*/
const char* loginIndex =
"<form name='loginForm'>"
"<table width='20%' bgcolor='A09F9F' align='center'>"
"<tr>"
"<td colspan=2>"
"<center><font size=4><b>ESP32 Login Page</b></font></center>"
"<br>"
"</td>"
"<br>"
"<br>"
"</tr>"
"<tr>"
"<td>Username:</td>"
"<td><input type='text' size=25 name='userid'><br></td>"
"</tr>"
"<br>"
"<br>"
"<tr>"
"<td>Password:</td>"
"<td><input type='Password' size=25 name='pwd'><br></td>"
"<br>"
"<br>"
"</tr>"
"<tr>"
"<td><input type='submit' onclick='check(this.form)' value='Login'></td>"
"</tr>"
"</table>"
"</form>"
"<script>"
"function check(form)"
"{"
"if(form.userid.value=='admin' && form.pwd.value=='admin')"
"{"
"window.open('/serverIndex')"
"}"
"else"
"{"
" alert('Error Password or Username')/*displays error message*/"
"}"
"}"
"</script>";
/*
* Server Index Page
*/
const char* serverIndex =
"<script src='https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js'></script>"
"<form method='POST' action='#' enctype='multipart/form-data' id='upload_form'>"
"<input type='file' name='update'>"
"<input type='submit' value='Update'>"
"</form>"
"<div id='prg'>progress: 0%</div>"
"<script>"
"$('form').submit(function(e){"
"e.preventDefault();"
"var form = $('#upload_form')[0];"
"var data = new FormData(form);"
" $.ajax({"
"url: '/update',"
"type: 'POST',"
"data: data,"
"contentType: false,"
"processData:false,"
"xhr: function() {"
"var xhr = new window.XMLHttpRequest();"
"xhr.upload.addEventListener('progress', function(evt) {"
"if (evt.lengthComputable) {"
"var per = evt.loaded / evt.total;"
"$('#prg').html('progress: ' + Math.round(per*100) + '%');"
"}"
"}, false);"
"return xhr;"
"},"
"success:function(d, s) {"
"console.log('success!')"
"},"
"error: function (a, b, c) {"
"}"
"});"
"});"
"</script>";
/*
* setup function
*/
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect(ID, mqttUser, mqttPassword)) {
Serial.println("connected");
Serial.print("Publishing to: ");
Serial.println(TOPIC);
Serial.println('\n');
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println("\n try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void setup(void) {
Serial.begin(115200);
// Connect to WiFi network
WiFi.begin(ssid, password);
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
/*use mdns for host name resolution*/
if (!MDNS.begin(host)) { //http://esp32.local
Serial.println("Error setting up MDNS responder!");
while (1) {
delay(1000);
}
}
Serial.println("mDNS responder started");
/*return index page which is stored in serverIndex */
server.on("/", HTTP_GET, []() {
server.sendHeader("Connection", "close");
server.send(200, "text/html", loginIndex);
});
server.on("/serverIndex", HTTP_GET, []() {
server.sendHeader("Connection", "close");
server.send(200, "text/html", serverIndex);
});
/*handling uploading firmware file */
server.on("/update", HTTP_POST, []() {
server.sendHeader("Connection", "close");
server.send(200, "text/plain", (Update.hasError()) ? "FAIL" : "OK");
ESP.restart();
}, []() {
HTTPUpload& upload = server.upload();
if (upload.status == UPLOAD_FILE_START) {
Serial.printf("Update: %s\n", upload.filename.c_str());
if (!Update.begin(UPDATE_SIZE_UNKNOWN)) { //start with max available size
Update.printError(Serial);
}
} else if (upload.status == UPLOAD_FILE_WRITE) {
/* flashing firmware to ESP*/
if (Update.write(upload.buf, upload.currentSize) != upload.currentSize) {
Update.printError(Serial);
}
} else if (upload.status == UPLOAD_FILE_END) {
if (Update.end(true)) { //true to set the size to the current progress
Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize);
} else {
Update.printError(Serial);
}
}
});
server.begin();
client.setServer(broker, 1883);
pinMode(4, OUTPUT);
pinMode(18, INPUT);
}
void loop(void) {
if (WiFi.status() != WL_CONNECTED) {
ESP.restart();
}
server.handleClient();
delay(1);
if (!client.connected()){
reconnect();
}
client.loop();
snprintf(messages, 75, "%s", "online");
client.publish(TOPIC, messages);
delay(1000);
}

 

 

# 부분 코드(OTAWebUpdater 코드는 잘모르니 제외)

const char *ssid = "olleh_WiFi_BA83"; //와이파이 SSID
const char *password = "0000002583"; // 와이파이 비밀번호
const char* ID = "Child_Pc_Control"; // Mqtt 브로커에 전달하는 이름으로 유닉해야함.
const char* TOPIC = "room/pc/state"; // Mqtt에 전달할 토픽
const char* mqttUser = "XXXXXXXX"; // Mqtt 브로커 로그인을 위한 유저
const char* mqttPassword = "XXXXXXXXXX"; // Mqtt 브로커 로그인 패스워드
const char* broker = "172.30.1.48"; // Mqtt 서버 주소
char messages[50]; // 버퍼가 담길 변수
// Mqtt 재 연결
void reconnect() {
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect(ID, mqttUser, mqttPassword)) {
Serial.println("connected");
Serial.print("Publishing to: ");
Serial.println(TOPIC);
Serial.println('\n');
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println("\n try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
}
}
}
void setup(void) {
client.setServer(broker, 1883); //Mqtt 접속 코드 void seup(void) 함수에 추가
}
void loop(void) {
if (WiFi.status() != WL_CONNECTED) { // 와이파이 연결 안되면 Esp 보드 새로 시작(실 사용중 이런 와이파이 연결 안되서 센서 값이 안들어 오는 경우가 있어서 추가함)
ESP.restart();
}
if (!client.connected()){ //Mqtt 재연결
reconnect();
}
client.loop();
snprintf(messages, 75, "%s", "online"); // 컴이 켜지면 켜짐의 메세지(online)를 버퍼로 바꾸는 코드
client.publish(TOPIC, messages); //Mqtt에 메시지 전달
delay(1000);
}

 

홈어시스턴트(Home Assistant) 코드


File Editor - configuration.yaml에 코드 추가

etc-image-4

switch:
- platform: wake_on_lan # hassio wol 스위치
mac: "D8:BB:C1:15:62:A6" # pc mac 주소
name: PcWol
host: 172.30.1.41 # pc 주소
sensor:
- platform: mqtt
name: "컴 상태" # 센서 이름
state_topic: "room/pc/state" # 토픽
expire_after: 10 # 10 초 내에 센서 값이 안 오면 Unavailable 전시

저장후 서버 재시작한 뒤

전 글에서 처럼 엔티티 아이콘을 변경(나는 mdi:microsoft-windows)

File Editor - ui-lovelace.yaml에 코드 추가

- type: horizontal-stack
cards:
- type: 'custom:button-card'
entity: sensor.keom_sangtae
show_entity_picture: true
aspect_ratio: '1/1'
size: 80%
name: "Pc Status"
state:
- value: 'online'
icon: 'mdi:microsoft-windows'
styles:
card:
- background: rgba(255, 255, 255, 0.3)
icon:
- color: rgba(0, 173, 239, 0.8)
show_state: true
tap_action: #클릭시 wol을 통한 pc 시작
action: 'call-service'
service: switch.turn_on
service_data:
entity_id: switch.pcwol
hold_action: # 꾹 누르면 히스토리 나오도록
action: 'more-info'
styles:
card:
- background: rgba(0, 0, 0, 0.5)
border-radius: 10%
padding: 10%
text-align: center
grid:
- grid-template-areas: '"i" "n" "s"'
- grid-template-columns: 1fr
- grid-template-rows: 1fr min-content min-content
img_cell:
- align-self: start
- text-align: start
name:
- justify-self: start
- color: white
- font-weight: bold
- text-shadow: 0px 0px 5px black
state:
- justify-self: start
- padding-left: 0px

etc-image-5

 

kt 공유기 Wake On Lan 설정은 구글링 ㄱ  다른 분들이 잘 해두심 ㅋ

윈도우, 공유기, 메인보드 모두 wol 설정함

끄는건 안됨...

대신 크롬에서 원격 데스크톱 설정해서 크롬으로 되도록함.

etc-image-6

홈어시스턴트로 킨다음

etc-image-7
etc-image-8

이걸루 끌수 있음 ㅋ

etc-image-9

크롬 원격 데스크톱 영상도 은근히 잘 돌아가더라 ㅋ

 

이제 이후에 코드를 수정할 일이 있으면 OTA로 하면 되는데 나의 경우 KT공유기를 이용함으로 그걸 바탕으로 하겠다.


공유기에 접속!(http://172.30.1.254) - 로그인(ktuser/homehub/보안코드) - 유무선 단말 정보에서 경과시간을 바탕으로 Esp32의 아이피를 찾는다. 컴을 처음에 킨 다음 새로고침하면 몇초만 경과한 녀석의 MAC주소를 바탕으로 찾으면 된다. 나의 경우 172.30.1.26 이다.

etc-image-10

 

etc-image-11
etc-image-12

 

해당아이피를 인터넷 브라우저에 넣고 엔터를 치면! 아래와 같은 화면이 나오는데 설정을 바꾸지 않았다면 기본적으로 admin/admin이다. 

etc-image-13

로그인을 하면 아래와 같은 화면이 나오는데 여기서

etc-image-14

파일선택에서 아까 아두이노 스케치 폴더에 만들어진 bin 파일을 선택한 뒤 업데이트한 뒤 Progress가 100%가 되면  반영이 된거다 ㅋㅋ

반응형