안녕하세요 오늘은 자동 방송을 위한 ESP32 시스템을 이용하여 성공한 방법에 관해 작성해보려합니다. 1편에서는 DFPlayer mini를 이용하여 자동화를 했었는데 일주일만에 DFPlayer mini가 고장이 나면서 시리얼 통신이 되지 않아 자동화가 실패하여서 스피커의 SD카드 플레이 기능을 이용하면서 수동으로 조절해야하는 음량까지 조절하는 IOT 방송 시스템을 구현해 보겠습니다..
1. 과제
- 블루투스 스피커 사운드 자동 조절
- 블루투스 스피커 On/Off
- 정해진 시간에 재생
2. ESP32 활용한 방안
- 스피커 사운드 자동 조절: ESP32와 TR(트랜지스터)
- 스피커 On/Off: 릴레이
- 정해진 시간 재생: 서버 시간 가져오기, 아두이노 millis()를 이용한 시계 구현
3. 트랜지스터를 이용한 음량 조절
- 트랜지스터는 문턱 전압인 0.7v를 넘으면 on off 가 가능함으로 트랜지스터와 저항을 준비
- 스피커의 음량 조절 다이얼 원리를 분석(멀티 테스터기를 이용하여 확인, 필자의 스피커는 거변 저항 방식이 아닌 독특한 다이얼 방식이라 분석에 시간이 걸림)
- 저항 값 계산은 너무 어려워서 솔직히 브레드보드에 저항 꼳으면서 테스터기로 트랜지스터 잘 작동하는지 확인하면서 찾음(4.7k옴 짜리 하나로도 됨)
4. 릴레이를 이용한 스피커 On Off
- 릴레이 모듈의 나사 조이는 부분 인두기로 분리( 나사 조이는 것 잘 풀림)
- 해당 부분에 인두기로 선 직접 납땜
5. ESP32 시간 계산
- 5분 마다 World Time Api에서 시간 가져오기(http://worldtimeapi.org/api/timezone/Asia/Seoul)
- 아두이노에서 시간, 분, 초 변수 선언
- 시간 서버로부터 받으면 대입
- millis() 함수를 이용하여 매초 1초 추가, 60초 되면 +1 분, 초 0과 같은 방식으로 loop() 함수 설정
6. 보조 수단
- 홈어시스턴트를 통한 자동화 보조 및 작동 확인
- mqtt time 메세지를 통한 아두이노상 시각 홈어시스턴트에 전달
- mqtt 음량 메세지
- mqtt 스피커 온오프
- 홈어시스턴트 자동화를 통한 mqtt play 메세지로 스피커 mp3 재생
7. 구현 코드
#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);
}
}
같이 보면 좋은 글
- 건강보험 EDI란?
- KTX 예매 바로가기
- 경찰정에서 만든 보이스 피싱 방지 앱
- 파파고보다 좋은 번역기 추천
- 여름 벌레 95% 막는 법
- 신복환승센터
- 알리소형제습기리뷰
- 필자 티스토리 블로그 홈어시스턴트 MQTT
이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.