ESP32와 스피커를 활용한 TBM 자동화!!! 특정 시간에 국민체조 틀어주기(24년) – 2

안녕하세요 오늘은 자동 방송을 위한 ESP32 시스템을 이용하여 성공한 방법에 관해 작성해보려합니다. 1편에서는 DFPlayer mini를 이용하여 자동화를 했었는데 일주일만에 DFPlayer mini가 고장이 나면서 시리얼 통신이 되지 않아 자동화가 실패하여서 스피커의 SD카드 플레이 기능을 이용하면서 수동으로 조절해야하는 음량까지 조절하는 IOT 방송 시스템을 구현해 보겠습니다..

ESP32 자동화2
ESP32 자동화2

  • 블루투스 스피커 사운드 자동 조절
  • 블루투스 스피커 On/Off
  • 정해진 시간에 재생

ESP32 스피커 작업중
ESP32 스피커 작업중
  • 스피커 사운드 자동 조절: ESP32와 TR(트랜지스터)
  • 스피커 On/Off: 릴레이
  • 정해진 시간 재생: 서버 시간 가져오기, 아두이노 millis()를 이용한 시계 구현

  1. 트랜지스터는 문턱 전압인 0.7v를 넘으면 on off 가 가능함으로 트랜지스터와 저항을 준비
  2. 스피커의 음량 조절 다이얼 원리를 분석(멀티 테스터기를 이용하여 확인, 필자의 스피커는 거변 저항 방식이 아닌 독특한 다이얼 방식이라 분석에 시간이 걸림)
  3. 저항 값 계산은 너무 어려워서 솔직히 브레드보드에 저항 꼳으면서 테스터기로 트랜지스터 잘 작동하는지 확인하면서 찾음(4.7k옴 짜리 하나로도 됨)

  • 릴레이 모듈의 나사 조이는 부분 인두기로 분리( 나사 조이는 것 잘 풀림)
  • 해당 부분에 인두기로 선 직접 납땜

  • 5분 마다 World Time Api에서 시간 가져오기(http://worldtimeapi.org/api/timezone/Asia/Seoul)
  • 아두이노에서 시간, 분, 초 변수 선언
  • 시간 서버로부터 받으면 대입
  • millis() 함수를 이용하여 매초 1초 추가, 60초 되면 +1 분, 초 0과 같은 방식으로 loop() 함수 설정

  • 홈어시스턴트를 통한 자동화 보조 및 작동 확인
  • mqtt time 메세지를 통한 아두이노상 시각 홈어시스턴트에 전달
  • mqtt 음량 메세지
  • mqtt 스피커 온오프
  • 홈어시스턴트 자동화를 통한 mqtt play 메세지로 스피커 mp3 재생

#include <WiFi.h>
#include <PubSubClient.h>
#include <HTTPClient.h>
#include <Arduino_JSON.h>

const char *ssid =  "";   
const char *password = ""; 

const char* ID = "";  // Name of our device, must be unique
const char* TOPIC = "office/Speaker/Status";
const char* INTOPIC = "office/Speaker/Set";
const char* mqttUser = "";
const char* mqttPassword = "";
const char* broker = "";
char messages[50];
const char* api = "http://worldtimeapi.org/api/timezone/Asia/Seoul";

WiFiClient wclient;
PubSubClient client(wclient); 
bool wifiC = false;
int hour = 0;
int minute = 0;
int sec = 0;
int dayOfWeek = 0;

// Connect to WiFi network
void setup_wifi() {
  Serial.print("\nConnecting to ");
  Serial.println(ssid);
  
  WiFi.begin(ssid, password); 
  if (WiFi.status() != WL_CONNECTED) {
    return;
  }
  Serial.println();
  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
  client.setServer(broker, 1883);
  client.setCallback(callback);
  //reconnect();
  GetReq(api);
}

//서버 시간 가져오기
String GetReq(const char* api) {
  WiFiClient client;
  HTTPClient http;


//API를 통한 시간 가져와 파싱
  http.begin(client, api); 
  int httpResponse = http.GET(); 
  String payload = "{}";
  Serial.print("httpresponse:"); 
  Serial.println(httpResponse);
  if (httpResponse >= 200) {
    Serial.println("Api Response Success!");
    payload = http.getString();
    //Serial.println(payload);
    JSONVar jsonObject = JSON.parse(payload);

    if (JSON.typeof(jsonObject) == "undefined") {
      Serial.println("Parse failed");
      return "nil";
    }

    //응답 변수 대입
    JSONVar keys = jsonObject.keys();
    Serial.print("time: ");
    Serial.println(jsonObject["datetime"]);
    String timeFromServer = String(jsonObject["datetime"]);
    dayOfWeek = jsonObject["day_of_week"];
    int indexOfT = timeFromServer.indexOf('T');
    Serial.println(dayOfWeek);
    hour = timeFromServer.substring(indexOfT+1, indexOfT+3).toInt();
    minute = timeFromServer.substring(indexOfT+4, indexOfT+6).toInt();
    sec = timeFromServer.substring(indexOfT+7, indexOfT+9).toInt();
    Serial.print("Hour: ");
    Serial.println(hour);
    //Serial.println(String(jsonObject["datetime"]).substring(indexOfT+1, indexOfT+3));
    Serial.print("Minute: ");
    Serial.println(minute);
    //Serial.println(String(jsonObject["datetime"]).substring(indexOfT+4, indexOfT+6));
    Serial.print("Seconds: ");
    Serial.println(sec);
    //Serial.println(String(jsonObject["datetime"]).substring(indexOfT+7, indexOfT+9));

  } else {
    Serial.println("Api connection error");
  }
  
  http.end();
  return payload;
}

//홈어시스턴트 MQTT 응답 메시지 처리
void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Received messages: ");
  Serial.print(INTOPIC);
  String msg = "";
  for(int i=0; i<length; i++){
    Serial.println((char)payload[i]);
    msg += (char)payload[i];
  }
  Serial.println(msg);

//메시지 구분
  if (msg == "play") {
    spkOn();
    for(int i=0; i<=9; i++) {
      volUp();
      delay(100);
      
    }
    delay(303000);
    spkOff();
    GetReq(api);
  } else if(msg == "off") {
    spkOff();
  } else if(msg == "plus"){
    volUp();
  } else if(msg == "minus") {
    volDown();
  } else if(msg == "time") {
//홈어시스턴트가 보낸 time 메시지를 통해 아두이노 시간을 홈어시스턴트로 전달
    snprintf(messages, 75, "%s", String(hour)+String(minute));
    client.publish(TOPIC, messages);
  } else {
    
  }
  delay(100);
}

// Reconnect to client
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');
      client.subscribe(INTOPIC);
      GetReq(api);
    } 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 spkOn() {
  digitalWrite(5, LOW);
}

void spkOff() {
  digitalWrite(5, HIGH);
}

void volDown() {
  digitalWrite(12, LOW);
  digitalWrite(13, LOW);
  delay(500);
  digitalWrite(12,HIGH);
  digitalWrite(13,HIGH);
}

void volUp() {
  digitalWrite(13, LOW);
  delay(500);
  digitalWrite(12,HIGH);
  digitalWrite(13,HIGH);
}

void setup() {

  // Init USB serial port for debugging
  Serial.begin(115200);
  pinMode(5, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(13, OUTPUT);
  delay(1000);
  setup_wifi(); // Connect to network
  client.setServer(broker, 1883);
  client.setCallback(callback);
  GetReq(api);
  digitalWrite(5, HIGH); //릴레이
  digitalWrite(12,HIGH); //볼륨 포트
  digitalWrite(13,HIGH); //볼륨 포트
}

void loop() {
  if ((millis()/1000 % 1) == 0) {
    sec += 1; // 매초 1초 추가
  }
  Serial.print(sec);
  if (WiFi.status() != WL_CONNECTED) {
    delay(10);
    Serial.println("와이파이 연결중 ");
    wifiC = false;
    if (WiFi.status() == WL_CONNECTED) {
      Serial.println();
  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
    }
    //setup_wifi();
  }
  if ((sec % 60) == 0) {
    minute += 1;
    if (!client.connected()){
    reconnect();
  }
    //Serial.println(minute);
    sec = 0;
    if ((minute % 60) == 0) {
      hour += 60;
      minute = 0;
    }
  }
  if (hour == 24) {
    hour = 0;
  }
  if (((minute % 5) == 0) && (sec == 0)) {
    GetReq(api);
  }
  
  if (WiFi.status() == WL_CONNECTED && wifiC == false) {
    Serial.println();
  Serial.println("WiFi connected");
  Serial.print("IP address: ");
  Serial.println(WiFi.localIP());
      wifiC = true;
      GetReq(api);
    }
  if (hour == 8 && minute == 30) { //8시 30분에 스피커 틀고 스피커 볼륨 증가
    Serial.println("OK");
    if (0 < dayOfWeek && dayOfWeek < 6) { //월~금 일 경우 실행
      Serial.println("OK");
    spkOn();
    for(int i=0; i<=9; i++) {
      volUp();
      delay(100);
      
    }
    delay(303000);
    minute = 35;
    Serial.println("OK");
    spkOff();
    GetReq(api);
    }
  }
  client.loop();
 int value = Serial.parseInt();
//시리얼 통신을 통한 제어
 if (value == 1){
    volUp();
 } else if (value == 2) {
  volDown();
 } else if (value == 3){
  Serial.println("3");
  spkOff();
 } else if (value == 4){
  Serial.println("4");
  spkOn();
  
 }else if (value == 5){
  Serial.println("5");
  GetReq(api);
 }

 
}

같이 보면 좋은 글

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

이 게시물이 유용하셨나요?

평점을 매겨주세요.

평균 평점 0 / 5. 투표수 0

이 게시물에 첫 평점을 남겨주세요!

Leave a Comment

error: 마우스 우클릭을 하실 수 없습니다.