Esp32 - 동생 컴퓨터 감시 장치

반응형

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

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

 

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

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

 

그래서!

 

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

 

원래 계획은 

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

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

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

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

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

 

아두이노 코드


이 예제를 바탕으로 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에 코드 추가

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

 

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

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

끄는건 안됨...

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

홈어시스턴트로 킨다음

이걸루 끌수 있음 ㅋ

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

 

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


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

 

 

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

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

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

반응형