Ver3.0
์ ์ฒด ์ด๋
Ver3.0 ๐ C์ธ์ด๋ก ์์ํ๋ IoT ํ๋ก๊ทธ๋๋ฐ ์ฌํ

๐ C์ธ์ด๋ก ์์ํ๋ IoT ํ๋ก๊ทธ๋๋ฐ ์ฌํ
์ผ์ ๋ฐ์ดํฐ ์์ง๋ถํฐ ์ฒ๋ฆฌ๊น์ง, ์ค์ ์์คํ ๊ตฌ์ถ ์๋ฒฝ ๊ฐ์ด๋ ๐
๐ฏ IoT์ C์ธ์ด, ์ ์ด ์กฐํฉ์ด ์ต๊ณ ์ผ๊น?
์๋ ! ์ค๋์ ์ ๋ง ์ฌ๋ฏธ์๋ ์ฃผ์ ๋ก ์ด์ผ๊ธฐ๋ฅผ ๋๋ ๋ณผ ๊ฑฐ์ผ. ๋ฐ๋ก **C์ธ์ด๋ฅผ ํ์ฉํ IoT ํ๋ก๊ทธ๋๋ฐ**์ด์ผ. ์์ฆ ์ค๋งํธํ, ์จ์ด๋ฌ๋ธ ๊ธฐ๊ธฐ, ์์จ์ฃผํ์ฐจ ๋ฑ IoT ๊ธฐ์ ์ด ์ฐ๋ฆฌ ์ํ ๊ณณ๊ณณ์ ์ค๋ฉฐ๋ค๊ณ ์์์? ๐ โจ๊ทธ๋ฐ๋ฐ ๋ง์ด์ผ, ๋ง์ ์ฌ๋๋ค์ด IoT ํ๋ก๊ทธ๋๋ฐ์ด๋ผ๊ณ ํ๋ฉด ํ์ด์ฌ์ด๋ ์๋ฐ์คํฌ๋ฆฝํธ ๊ฐ์ ์ธ์ด๋ฅผ ๋จผ์ ๋ ์ฌ๋ ค. ๋ฌผ๋ก ๊ทธ๊ฒ๋ค๋ ์ข์ง๋ง, ์ง์ง ํ๋์จ์ด์ ์ง์ ๋ํํ๊ณ ์ถ๋ค๋ฉด C์ธ์ด๋งํ ๊ฒ ์์ด. ์๋๊ณ ? C์ธ์ด๋ ํ๋์จ์ด์ ๊ฐ์ฅ ๊ฐ๊น์ด ๊ณ ๊ธ ์ธ์ด๊ฑฐ๋ ! ๐ช
์ผ์์์ ๋ฐ์ดํฐ๋ฅผ ์ฝ์ด์ค๊ณ , ๊ทธ ๋ฐ์ดํฐ๋ฅผ ์ฒ๋ฆฌํ๊ณ , ๋ค์ ์ก์ถ์์ดํฐ๋ฅผ ์ ์ดํ๋ ๋ชจ๋ ๊ณผ์ ์์ C์ธ์ด๋ ๋น ๋ฅด๊ณ ํจ์จ์ ์ด์ผ. ํนํ ๋ฉ๋ชจ๋ฆฌ๊ฐ ์ ํ์ ์ธ ์๋ฒ ๋๋ ์์คํ ์์๋ C์ธ์ด์ ์ง๊ฐ๊ฐ ๋ฐํ๋์ง. ์๋์ด๋ ธ, ๋ผ์ฆ๋ฒ ๋ฆฌํ์ด, ESP32 ๊ฐ์ ๋ณด๋๋ค๋ ๋ชจ๋ C/C++ ๊ธฐ๋ฐ์ผ๋ก ๋์ํ๊ณ ์์ด!
๐ก IoT ์์คํ
์ ํต์ฌ ๊ตฌ์ฑ์์
์ผ์(Sensor): ์จ๋, ์ต๋, ๋น, ์์ง์ ๋ฑ ๋ฌผ๋ฆฌ์ ๋ฐ์ดํฐ๋ฅผ ์ ๊ธฐ ์ ํธ๋ก ๋ณํ
๋ง์ดํฌ๋ก์ปจํธ๋กค๋ฌ(MCU): ์ผ์ ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ณ ์ฒ๋ฆฌํ๋ ๋๋ ์ญํ
ํต์ ๋ชจ๋: WiFi, Bluetooth, LoRa ๋ฑ์ผ๋ก ๋ฐ์ดํฐ ์ ์ก
์ก์ถ์์ดํฐ: LED, ๋ชจํฐ, ๋ฆด๋ ์ด ๋ฑ ๋ฌผ๋ฆฌ์ ๋์ ์ํ
ํด๋ผ์ฐ๋/์๋ฒ: ๋ฐ์ดํฐ ์ ์ฅ ๋ฐ ๋ถ์
์ผ์(Sensor): ์จ๋, ์ต๋, ๋น, ์์ง์ ๋ฑ ๋ฌผ๋ฆฌ์ ๋ฐ์ดํฐ๋ฅผ ์ ๊ธฐ ์ ํธ๋ก ๋ณํ
๋ง์ดํฌ๋ก์ปจํธ๋กค๋ฌ(MCU): ์ผ์ ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ณ ์ฒ๋ฆฌํ๋ ๋๋ ์ญํ
ํต์ ๋ชจ๋: WiFi, Bluetooth, LoRa ๋ฑ์ผ๋ก ๋ฐ์ดํฐ ์ ์ก
์ก์ถ์์ดํฐ: LED, ๋ชจํฐ, ๋ฆด๋ ์ด ๋ฑ ๋ฌผ๋ฆฌ์ ๋์ ์ํ
ํด๋ผ์ฐ๋/์๋ฒ: ๋ฐ์ดํฐ ์ ์ฅ ๋ฐ ๋ถ์
๐ง ๊ฐ๋ฐ ํ๊ฒฝ ๊ตฌ์ถํ๊ธฐ
์, ๊ทธ๋ผ ๋ณธ๊ฒฉ์ ์ผ๋ก ์์ํด๋ณผ๊น? ๋จผ์ ๊ฐ๋ฐ ํ๊ฒฝ๋ถํฐ ์ธํ ํด์ผ๊ฒ ์ง? ๊ฑฑ์ ๋ง, ์๊ฐ๋ณด๋ค ์ด๋ ต์ง ์์! ๐ํ์ ํ๋์จ์ด ์ค๋น๋ฌผ
IoT ํ๋ก์ ํธ๋ฅผ ์์ํ๋ ค๋ฉด ๋ช ๊ฐ์ง ํ๋์จ์ด๊ฐ ํ์ํด. ์ด๋ณด์๋ผ๋ฉด **์๋์ด๋
ธ ์ฐ๋
ธ**๋ **ESP32** ๋ณด๋๋ฅผ ์ถ์ฒํด. ๊ฐ๊ฒฉ๋ ์ ๋ ดํ๊ณ ์ปค๋ฎค๋ํฐ๋ ํ๋ฐํด์ ๋ฌธ์ ๊ฐ ์๊ฒจ๋ ํด๊ฒฐํ๊ธฐ ์ฝ๊ฑฐ๋ ! ๐ฎ| ๋ณด๋ ์ข ๋ฅ | ํน์ง | ์ถ์ฒ ์ฉ๋ |
|---|---|---|
| Arduino Uno | ์ด๋ณด์ ์นํ์ , ํ๋ถํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ | ๊ธฐ๋ณธ ์ผ์ ์ค์ต |
| ESP32 | WiFi/Bluetooth ๋ด์ฅ, ์ ๋ ดํ ๊ฐ๊ฒฉ | ๋ฌด์ IoT ํ๋ก์ ํธ |
| Raspberry Pi | ๋ฆฌ๋ ์ค OS, ๊ฐ๋ ฅํ ์ฑ๋ฅ | ๋ณต์กํ ๋ฐ์ดํฐ ์ฒ๋ฆฌ |
| STM32 | ์ฐ์ ์ฉ ์์ค, ๋ค์ํ ์๋ฆฌ์ฆ | ์ ๋ฌธ์ ์ธ ์๋ฒ ๋๋ ๊ฐ๋ฐ |
์ํํธ์จ์ด ๊ฐ๋ฐ ๋๊ตฌ
ํ๋์จ์ด ์ค๋น๊ฐ ๋๋ฌ๋ค๋ฉด ์ด์ ์ฝ๋ฉ ํ๊ฒฝ์ ๋ง๋ค์ด์ผ์ง. ์๋์ด๋
ธ๋ฅผ ์ฌ์ฉํ๋ค๋ฉด **Arduino IDE**๊ฐ ๊ฐ์ฅ ๊ฐ๋จํด. ํ์ง๋ง ์ข ๋ ์ ๋ฌธ์ ์ธ ๊ฐ๋ฐ์ ์ํ๋ค๋ฉด **PlatformIO**๋ **VS Code**๋ฅผ ์ถ์ฒํด! ๐ฅ๏ธESP32๋ STM32 ๊ฐ์ ๋ณด๋๋ฅผ ์ฌ์ฉํ๋ค๋ฉด ๊ฐ ์ ์กฐ์ฌ์์ ์ ๊ณตํ๋ SDK๋ฅผ ์ค์นํด์ผ ํด. ESP32๋ **ESP-IDF**, STM32๋ **STM32CubeIDE**๋ฅผ ์ฌ์ฉํ๋ฉด ๋ผ. ์ฒ์์ ๋ณต์กํด ๋ณด์ด์ง๋ง, ํ๋ฒ ์ต์ํด์ง๋ฉด ์ ๋ง ๊ฐ๋ ฅํ ๋๊ตฌ๋ค์ด์ผ! ๐ช
๐ ์ด๋ณด์ ํ
์ฒ์ ์์ํ๋ค๋ฉด Arduino IDE๋ก ์์ํ๋ ๊ฑธ ์ถ์ฒํด! ๊ฐ๋จํ ์์ ์ฝ๋๋ค์ด ๋ง์์ ํ์ตํ๊ธฐ ์ข๊ฑฐ๋ . ๋์ค์ ์ค๋ ฅ์ด ๋๋ฉด ๋ ์ ๋ฌธ์ ์ธ ๋๊ตฌ๋ก ๋์ด๊ฐ๋ฉด ๋ผ. ์ฌ๋ฅ๋ท์์ IoT ํ๋ก๊ทธ๋๋ฐ ๋ฉํ ๋ฅผ ์ฐพ์๋ณด๋ ๊ฒ๋ ์ข์ ๋ฐฉ๋ฒ์ด์ผ!
์ฒ์ ์์ํ๋ค๋ฉด Arduino IDE๋ก ์์ํ๋ ๊ฑธ ์ถ์ฒํด! ๊ฐ๋จํ ์์ ์ฝ๋๋ค์ด ๋ง์์ ํ์ตํ๊ธฐ ์ข๊ฑฐ๋ . ๋์ค์ ์ค๋ ฅ์ด ๋๋ฉด ๋ ์ ๋ฌธ์ ์ธ ๋๊ตฌ๋ก ๋์ด๊ฐ๋ฉด ๋ผ. ์ฌ๋ฅ๋ท์์ IoT ํ๋ก๊ทธ๋๋ฐ ๋ฉํ ๋ฅผ ์ฐพ์๋ณด๋ ๊ฒ๋ ์ข์ ๋ฐฉ๋ฒ์ด์ผ!
๐ก ์ผ์ ๋ฐ์ดํฐ ์ฝ๊ธฐ์ ๊ธฐ์ด
์, ์ด์ ๋ณธ๊ฒฉ์ ์ผ๋ก ์ผ์์ ๋ํํด๋ณผ ์๊ฐ์ด์ผ! ์ผ์ ๋ฐ์ดํฐ๋ฅผ ์ฝ๋ ๊ฑด ์๊ฐ๋ณด๋ค ๊ฐ๋จํด. ๊ธฐ๋ณธ์ ์ผ๋ก **๋์งํธ ์ ๋ ฅ**๊ณผ **์๋ ๋ก๊ทธ ์ ๋ ฅ** ๋ ๊ฐ์ง ๋ฐฉ์์ด ์์ด. ๐๏ธ๋์งํธ ์ผ์ ๋ค๋ฃจ๊ธฐ
๋์งํธ ์ผ์๋ 0 ๋๋ 1, ์ฆ HIGH๋ LOW ๊ฐ๋ง ๋ฐํํด. ์๋ฅผ ๋ค์ด ๋ฒํผ์ด๋ PIR ๋ชจ์
์ผ์ ๊ฐ์ ๊ฑฐ์ง. ์ฝ๋๋ก ๋ณด๋ฉด ์ด๋ ๊ฒ ์๊ฒจ๋จน์์ด:
#define BUTTON_PIN 2
void setup() {
pinMode(BUTTON_PIN, INPUT);
Serial.begin(9600);
}
void loop() {
int buttonState = digitalRead(BUTTON_PIN);
if (buttonState == HIGH) {
Serial.println("๋ฒํผ์ด ๋๋ ธ์ด์! ๐");
}
delay(100);
}
๊ฐ๋จํ์ง? pinMode()๋ก ํ์ ์
๋ ฅ ๋ชจ๋๋ก ์ค์ ํ๊ณ , digitalRead()๋ก ๊ฐ์ ์ฝ์ด์ค๋ฉด ๋์ด์ผ! ๐
์๋ ๋ก๊ทธ ์ผ์์ ์ธ๊ณ
์๋ ๋ก๊ทธ ์ผ์๋ ์ข ๋ ์ฌ๋ฏธ์์ด. 0๋ถํฐ 1023๊น์ง(10๋นํธ ADC ๊ธฐ์ค) ์ฐ์์ ์ธ ๊ฐ์ ๋ฐํํ๊ฑฐ๋ . ์จ๋ ์ผ์, ์กฐ๋ ์ผ์, ๊ฐ๋ณ์ ํญ ๋ฑ์ด ์ฌ๊ธฐ ์ํด. ๐ก๏ธ์๋ฅผ ๋ค์ด ์กฐ๋ ์ผ์๋ก ๋น์ ๋ฐ๊ธฐ๋ฅผ ์ธก์ ํ๋ ์ฝ๋๋ฅผ ๋ณผ๊น?
#define LDR_PIN A0
void setup() {
Serial.begin(9600);
}
void loop() {
int lightValue = analogRead(LDR_PIN);
// 0-1023 ๊ฐ์ 0-100 ํผ์ผํธ๋ก ๋ณํ
int brightness = map(lightValue, 0, 1023, 0, 100);
Serial.print("๋ฐ๊ธฐ: ");
Serial.print(brightness);
Serial.println("%");
// ์ด๋์ฐ๋ฉด ๊ฒฝ๊ณ ๋ฉ์์ง
if (brightness < 30) {
Serial.println("โ ๏ธ ๋๋ฌด ์ด๋์์!");
}
delay(500);
}
์ฌ๊ธฐ์ map() ํจ์๊ฐ ์ ๋ง ์ ์ฉํด! ์ผ์ ๊ฐ์ ๋ฒ์๋ฅผ ์ฐ๋ฆฌ๊ฐ ์ํ๋ ๋ฒ์๋ก ์ฝ๊ฒ ๋ณํํด์ฃผ๊ฑฐ๋ . ์ด๋ฐ ์์ ํ๋ค์ด ๋ชจ์ฌ์ ๋ฉ์ง ํ๋ก์ ํธ๊ฐ ๋๋ ๊ฑฐ์ผ! โจ
๐ก๏ธ ์ค์ ! DHT11 ์จ์ต๋ ์ผ์ ํ๋ก์ ํธ
์ด๋ก ๋ง ๋ฐฐ์ฐ๋ฉด ์ฌ๋ฏธ์์์? ์ด์ ์ค์ ๋ก DHT11 ์จ์ต๋ ์ผ์๋ฅผ ์ฌ์ฉํด์ ๋ฐ์ดํฐ๋ฅผ ์์งํ๊ณ ์ฒ๋ฆฌํ๋ ์์ ํ ์์คํ ์ ๋ง๋ค์ด๋ณผ ๊ฑฐ์ผ! ์ด ํ๋ก์ ํธ๋ ์ ๋ง ์ค์ฉ์ ์ด๋ผ์ ์ค๋งํธํ ์์คํ ์ ๊ธฐ์ด๊ฐ ๋ ์ ์์ด. ๐กํ๋์จ์ด ์ฐ๊ฒฐํ๊ธฐ
DHT11 ์ผ์๋ ๋ณดํต 3๊ฐ์ ํ์ ๊ฐ์ง๊ณ ์์ด. VCC(์ ์), GND(์ ์ง), DATA(๋ฐ์ดํฐ) ํ์ด์ง. ์ฐ๊ฒฐ์ ์ด๋ ๊ฒ ํ๋ฉด ๋ผ:โข DHT11 VCC โ Arduino 5V
โข DHT11 GND โ Arduino GND
โข DHT11 DATA โ Arduino Digital Pin 2
โข DATA ํ๊ณผ VCC ์ฌ์ด์ 10kฮฉ ํ์ ์ ํญ ์ฐ๊ฒฐ (์ค์!) ๐
โ ๏ธ ์ฃผ์์ฌํญ
ํ์ ์ ํญ์ ๊ผญ ์ฐ๊ฒฐํด์ผ ํด! ์ ๊ทธ๋ฌ๋ฉด ๋ฐ์ดํฐ ์ฝ๊ธฐ๊ฐ ๋ถ์์ ํด์ง ์ ์์ด. ์ผ๋ถ DHT11 ๋ชจ๋์ ์ด๋ฏธ ์ ํญ์ด ๋ด์ฅ๋์ด ์์ผ๋ ํ์ธํด๋ณด์.
ํ์ ์ ํญ์ ๊ผญ ์ฐ๊ฒฐํด์ผ ํด! ์ ๊ทธ๋ฌ๋ฉด ๋ฐ์ดํฐ ์ฝ๊ธฐ๊ฐ ๋ถ์์ ํด์ง ์ ์์ด. ์ผ๋ถ DHT11 ๋ชจ๋์ ์ด๋ฏธ ์ ํญ์ด ๋ด์ฅ๋์ด ์์ผ๋ ํ์ธํด๋ณด์.
DHT11 ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค์น ๋ฐ ๊ธฐ๋ณธ ์ฝ๋
Arduino IDE์์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋งค๋์ ๋ฅผ ์ด๊ณ "DHT sensor library"๋ฅผ ๊ฒ์ํด์ ์ค์นํ์. Adafruit์์ ๋ง๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ๊ฐ์ฅ ์์ ์ ์ด์ผ! ๐์, ์ด์ ๋ณธ๊ฒฉ์ ์ธ ์ฝ๋๋ฅผ ์์ฑํด๋ณผ๊น?
#include "DHT.h"
#define DHTPIN 2 // DHT11 ๋ฐ์ดํฐ ํ
#define DHTTYPE DHT11 // ์ผ์ ํ์
์ง์
DHT dht(DHTPIN, DHTTYPE);
// ๋ฐ์ดํฐ ์ ์ฅ์ ์ํ ๊ตฌ์กฐ์ฒด
typedef struct {
float temperature;
float humidity;
unsigned long timestamp;
bool isValid;
} SensorData;
SensorData currentData;
void setup() {
Serial.begin(9600);
Serial.println("๐ก๏ธ DHT11 ์ผ์ ์์คํ
์์!");
dht.begin();
// ์ด๊ธฐํ
currentData.isValid = false;
}
void loop() {
// ์ผ์ ์ฝ๊ธฐ (2์ด๋ง๋ค)
delay(2000);
// ์จ์ต๋ ๋ฐ์ดํฐ ์ฝ๊ธฐ
float h = dht.readHumidity();
float t = dht.readTemperature();
// ์ฝ๊ธฐ ์คํจ ์ฒดํฌ
if (isnan(h) || isnan(t)) {
Serial.println("โ ์ผ์ ์ฝ๊ธฐ ์คํจ!");
currentData.isValid = false;
return;
}
// ๋ฐ์ดํฐ ์ ์ฅ
currentData.temperature = t;
currentData.humidity = h;
currentData.timestamp = millis();
currentData.isValid = true;
// ๋ฐ์ดํฐ ์ถ๋ ฅ
printSensorData();
// ๊ฒฝ๊ณ ์์คํ
checkAlerts();
}
void printSensorData() {
Serial.println("โโโโโโโโโโโโโโโโโโโโ");
Serial.print("๐ก๏ธ ์จ๋: ");
Serial.print(currentData.temperature);
Serial.println("ยฐC");
Serial.print("๐ง ์ต๋: ");
Serial.print(currentData.humidity);
Serial.println("%");
// ์ฒด๊ฐ์จ๋ ๊ณ์ฐ (์ด์ง์)
float heatIndex = calculateHeatIndex(
currentData.temperature,
currentData.humidity
);
Serial.print("๐ฅ ์ฒด๊ฐ์จ๋: ");
Serial.print(heatIndex);
Serial.println("ยฐC");
Serial.println("โโโโโโโโโโโโโโโโโโโโ");
}
// ์ด์ง์(Heat Index) ๊ณ์ฐ ํจ์
float calculateHeatIndex(float temp, float humidity) {
// ๊ฐ๋จํ ์ด์ง์ ๊ณต์
float hi = temp + 0.5555 * (6.11 * exp(5417.7530 *
((1/273.16) - (1/(273.15+temp)))) *
(humidity/100.0) - 10.0);
return hi;
}
void checkAlerts() {
// ์จ๋ ๊ฒฝ๊ณ
if (currentData.temperature > 30.0) {
Serial.println("๐ด ๊ฒฝ๊ณ : ์จ๋๊ฐ ๋๋ฌด ๋์ต๋๋ค!");
} else if (currentData.temperature < 15.0) {
Serial.println("๐ต ๊ฒฝ๊ณ : ์จ๋๊ฐ ๋๋ฌด ๋ฎ์ต๋๋ค!");
}
// ์ต๋ ๊ฒฝ๊ณ
if (currentData.humidity > 70.0) {
Serial.println("๐ฆ ๊ฒฝ๊ณ : ์ต๋๊ฐ ๋๋ฌด ๋์ต๋๋ค!");
} else if (currentData.humidity < 30.0) {
Serial.println("๐๏ธ ๊ฒฝ๊ณ : ์ต๋๊ฐ ๋๋ฌด ๋ฎ์ต๋๋ค!");
}
}
์! ์ฝ๋๊ฐ ์ข ๊ธธ์ด ๋ณด์ด์ง? ํ์ง๋ง ํ๋ํ๋ ๋ฏ์ด๋ณด๋ฉด ์ ํ ์ด๋ ต์ง ์์. ๊ตฌ์กฐ์ฒด๋ฅผ ์ฌ์ฉํด์ ๋ฐ์ดํฐ๋ฅผ ์ฒด๊ณ์ ์ผ๋ก ๊ด๋ฆฌํ๊ณ , ํจ์๋ก ๊ธฐ๋ฅ์ ๋ถ๋ฆฌํด์ ์ฝ๋๋ฅผ ๊น๋ํ๊ฒ ๋ง๋ค์์ด. ์ด๊ฒ ๋ฐ๋ก ์ข์ C ํ๋ก๊ทธ๋๋ฐ ์ต๊ด์ด์ผ! ๐
๐ ์ผ์ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ๋ฐ ํํฐ๋ง
์ผ์์์ ์ฝ์ด์จ ๋ฐ์ดํฐ๋ฅผ ๊ทธ๋๋ก ์ฌ์ฉํ๋ฉด ์ ๋ผ! ์๋๊ณ ? ์ผ์ ๋ฐ์ดํฐ์๋ ํญ์ **๋ ธ์ด์ฆ**๊ฐ ์์ฌ ์๊ฑฐ๋ . ์ ๊ธฐ์ ๊ฐ์ญ, ์ผ์ ์์ฒด์ ์ค์ฐจ, ํ๊ฒฝ์ ์์ธ ๋ฑ์ผ๋ก ์ธํด ๊ฐ์ด ํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์. ๐ฐ๊ทธ๋์ ์ฐ๋ฆฌ๋ ๋ฐ์ดํฐ๋ฅผ **ํํฐ๋ง**ํ๊ณ **ํํํ**ํด์ผ ํด. ์ฌ๋ฌ ๊ฐ์ง ๋ฐฉ๋ฒ์ด ์๋๋ฐ, ๊ฐ์ฅ ๋ง์ด ์ฐ์ด๋ ๊ธฐ๋ฒ๋ค์ ์์๋ณด์!
์ด๋ ํ๊ท ํํฐ (Moving Average Filter)
๊ฐ์ฅ ๊ฐ๋จํ๋ฉด์๋ ํจ๊ณผ์ ์ธ ๋ฐฉ๋ฒ์ด์ผ. ์ต๊ทผ N๊ฐ์ ๋ฐ์ดํฐ๋ฅผ ํ๊ท ๋ด์ ์ฌ์ฉํ๋ ๊ฑฐ์ง. ์ฝ๋๋ก ๊ตฌํํ๋ฉด ์ด๋ ๊ฒ ๋ผ:
#define WINDOW_SIZE 10
typedef struct {
float buffer[WINDOW_SIZE];
int index;
int count;
float sum;
} MovingAverage;
MovingAverage tempFilter;
MovingAverage humidFilter;
void initMovingAverage(MovingAverage *ma) {
ma->index = 0;
ma->count = 0;
ma->sum = 0.0;
for (int i = 0; i < WINDOW_SIZE; i++) {
ma->buffer[i] = 0.0;
}
}
float addValue(MovingAverage *ma, float value) {
// ์ด์ ๊ฐ์ ํฉ๊ณ์์ ๋นผ๊ธฐ
ma->sum -= ma->buffer[ma->index];
// ์ ๊ฐ์ ๋ฒํผ์ ์ ์ฅ
ma->buffer[ma->index] = value;
ma->sum += value;
// ์ธ๋ฑ์ค ์
๋ฐ์ดํธ (์ํ ๋ฒํผ)
ma->index = (ma->index + 1) % WINDOW_SIZE;
// ์นด์ดํธ ์
๋ฐ์ดํธ
if (ma->count < WINDOW_SIZE) {
ma->count++;
}
// ํ๊ท ๋ฐํ
return ma->sum / ma->count;
}
void setup() {
Serial.begin(9600);
dht.begin();
// ํํฐ ์ด๊ธฐํ
initMovingAverage(&tempFilter);
initMovingAverage(&humidFilter);
}
void loop() {
delay(2000);
float rawTemp = dht.readTemperature();
float rawHumid = dht.readHumidity();
if (!isnan(rawTemp) && !isnan(rawHumid)) {
// ํํฐ๋ง๋ ๊ฐ ์ป๊ธฐ
float filteredTemp = addValue(&tempFilter, rawTemp);
float filteredHumid = addValue(&humidFilter, rawHumid);
Serial.print("์๋ณธ ์จ๋: ");
Serial.print(rawTemp);
Serial.print("ยฐC โ ํํฐ๋ง: ");
Serial.print(filteredTemp);
Serial.println("ยฐC");
Serial.print("์๋ณธ ์ต๋: ");
Serial.print(rawHumid);
Serial.print("% โ ํํฐ๋ง: ");
Serial.print(filteredHumid);
Serial.println("%");
}
}
์ด ์ฝ๋์ ํต์ฌ์ **์ํ ๋ฒํผ(Circular Buffer)**๋ฅผ ์ฌ์ฉํ๋ค๋ ๊ฑฐ์ผ. ๋ฉ๋ชจ๋ฆฌ๋ฅผ ํจ์จ์ ์ผ๋ก ์ฌ์ฉํ๋ฉด์๋ ์ต๊ทผ ๋ฐ์ดํฐ๋ง ์ ์งํ ์ ์์ง! ๐
์นผ๋ง ํํฐ (Kalman Filter)
์ข ๋ ๊ณ ๊ธ ๊ธฐ๋ฒ์ ์ํ๋ค๋ฉด ์นผ๋ง ํํฐ๋ฅผ ์ฌ์ฉํด๋ณผ ์ ์์ด. ์ด๊ฑด NASA์์ ์ํด๋ก ์ฐ์ฃผ์ ํญ๋ฒ์ ์ฌ์ฉํ๋ ์๊ณ ๋ฆฌ์ฆ์ด์ผ! ๐ ๋ณต์กํด ๋ณด์ด์ง๋ง, 1์ฐจ์ ์นผ๋ง ํํฐ๋ ์๊ฐ๋ณด๋ค ๊ฐ๋จํด:
typedef struct {
float q; // ํ๋ก์ธ์ค ๋
ธ์ด์ฆ
float r; // ์ธก์ ๋
ธ์ด์ฆ
float x; // ์ถ์ ๊ฐ
float p; // ์ถ์ ์ค์ฐจ
float k; // ์นผ๋ง ๊ฒ์ธ
} KalmanFilter;
void initKalman(KalmanFilter *kf, float q, float r, float initial) {
kf->q = q;
kf->r = r;
kf->x = initial;
kf->p = 1.0;
}
float updateKalman(KalmanFilter *kf, float measurement) {
// ์์ธก ๋จ๊ณ
kf->p = kf->p + kf->q;
// ์นผ๋ง ๊ฒ์ธ ๊ณ์ฐ
kf->k = kf->p / (kf->p + kf->r);
// ์
๋ฐ์ดํธ ๋จ๊ณ
kf->x = kf->x + kf->k * (measurement - kf->x);
kf->p = (1 - kf->k) * kf->p;
return kf->x;
}
KalmanFilter tempKalman;
KalmanFilter humidKalman;
void setup() {
Serial.begin(9600);
dht.begin();
// ์นผ๋ง ํํฐ ์ด๊ธฐํ
// (ํ๋ก์ธ์ค ๋
ธ์ด์ฆ, ์ธก์ ๋
ธ์ด์ฆ, ์ด๊ธฐ๊ฐ)
initKalman(&tempKalman, 0.01, 0.1, 25.0);
initKalman(&humidKalman, 0.01, 0.1, 50.0);
}
void loop() {
delay(2000);
float rawTemp = dht.readTemperature();
float rawHumid = dht.readHumidity();
if (!isnan(rawTemp) && !isnan(rawHumid)) {
float kalmanTemp = updateKalman(&tempKalman, rawTemp);
float kalmanHumid = updateKalman(&humidKalman, rawHumid);
Serial.print("์นผ๋ง ์จ๋: ");
Serial.print(kalmanTemp);
Serial.println("ยฐC");
Serial.print("์นผ๋ง ์ต๋: ");
Serial.print(kalmanHumid);
Serial.println("%");
}
}
์นผ๋ง ํํฐ๋ ์ด๋ ํ๊ท ๋ณด๋ค ๋ฐ์์ด ๋น ๋ฅด๋ฉด์๋ ๋
ธ์ด์ฆ๋ฅผ ํจ๊ณผ์ ์ผ๋ก ์ ๊ฑฐํด์ค. ํนํ ๋น ๋ฅด๊ฒ ๋ณํ๋ ์ผ์ ๊ฐ์ ์ถ์ ํ ๋ ์ ์ฉํด! ๐ฏ
๐ค ์ด๋ค ํํฐ๋ฅผ ์ ํํด์ผ ํ ๊น?
์ด๋ ํ๊ท ํํฐ: ๊ตฌํ์ด ๊ฐ๋จํ๊ณ ์์ ์ . ์ฒ์ฒํ ๋ณํ๋ ๊ฐ์ ์ ํฉ
์นผ๋ง ํํฐ: ๋น ๋ฅธ ๋ฐ์๊ณผ ์ ํ๋๊ฐ ํ์ํ ๋. ์ฝ๊ฐ ๋ณต์กํจ
์ค๊ฐ๊ฐ ํํฐ: ๊ฐ์์ค๋ฌ์ด ์คํ์ดํฌ ๋ ธ์ด์ฆ ์ ๊ฑฐ์ ํจ๊ณผ์
์ง์ ์ด๋ ํ๊ท : ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ ์ด๊ณ ์ต๊ทผ ๊ฐ์ ๋ ํฐ ๊ฐ์ค์น
์ด๋ ํ๊ท ํํฐ: ๊ตฌํ์ด ๊ฐ๋จํ๊ณ ์์ ์ . ์ฒ์ฒํ ๋ณํ๋ ๊ฐ์ ์ ํฉ
์นผ๋ง ํํฐ: ๋น ๋ฅธ ๋ฐ์๊ณผ ์ ํ๋๊ฐ ํ์ํ ๋. ์ฝ๊ฐ ๋ณต์กํจ
์ค๊ฐ๊ฐ ํํฐ: ๊ฐ์์ค๋ฌ์ด ์คํ์ดํฌ ๋ ธ์ด์ฆ ์ ๊ฑฐ์ ํจ๊ณผ์
์ง์ ์ด๋ ํ๊ท : ๋ฉ๋ชจ๋ฆฌ ํจ์จ์ ์ด๊ณ ์ต๊ทผ ๊ฐ์ ๋ ํฐ ๊ฐ์ค์น
๐ ๋ค์ค ์ผ์ ํตํฉ ์์คํ
์ค์ IoT ํ๋ก์ ํธ์์๋ ํ๋์ ์ผ์๋ง ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๊ฐ ๊ฑฐ์ ์์ด. ์ฌ๋ฌ ์ผ์๋ฅผ ๋์์ ์ฝ๊ณ ์ฒ๋ฆฌํด์ผ ํ์ง! ์ด์ DHT11, ์กฐ๋ ์ผ์, ์ด์ํ ์ผ์๋ฅผ ๋ชจ๋ ํตํฉํ ์์คํ ์ ๋ง๋ค์ด๋ณด์. ๐จ์ผ์ ๋งค๋์ ๊ตฌ์กฐ ์ค๊ณ
์ฌ๋ฌ ์ผ์๋ฅผ ํจ์จ์ ์ผ๋ก ๊ด๋ฆฌํ๋ ค๋ฉด ์ฒด๊ณ์ ์ธ ๊ตฌ์กฐ๊ฐ ํ์ํด. ๊ฐ์ฒด์งํฅ์ ์ฌ๊ณ ๋ฅผ C์ธ์ด๋ก ๊ตฌํํด๋ณด์!
#include "DHT.h"
// ์ผ์ ํ์
์ ์
typedef enum {
SENSOR_DHT11,
SENSOR_LDR,
SENSOR_ULTRASONIC,
SENSOR_COUNT
} SensorType;
// ์ผ์ ์ํ
typedef enum {
SENSOR_OK,
SENSOR_ERROR,
SENSOR_NOT_READY
} SensorStatus;
// ์ผ์ ๋ฐ์ดํฐ ๊ตฌ์กฐ์ฒด
typedef struct {
SensorType type;
SensorStatus status;
float value1; // ์จ๋ or ์กฐ๋ or ๊ฑฐ๋ฆฌ
float value2; // ์ต๋ (DHT11๋ง ์ฌ์ฉ)
unsigned long lastRead;
unsigned int readInterval; // ms ๋จ์
} Sensor;
// ์ผ์ ๋ฐฐ์ด
Sensor sensors[SENSOR_COUNT];
// DHT11 ์ค์
#define DHTPIN 2
#define DHTTYPE DHT11
DHT dht(DHTPIN, DHTTYPE);
// ์กฐ๋ ์ผ์ ์ค์
#define LDR_PIN A0
// ์ด์ํ ์ผ์ ์ค์
#define TRIG_PIN 9
#define ECHO_PIN 10
// ์ผ์ ์ด๊ธฐํ ํจ์
void initSensors() {
// DHT11 ์ด๊ธฐํ
sensors[SENSOR_DHT11].type = SENSOR_DHT11;
sensors[SENSOR_DHT11].readInterval = 2000; // 2์ด
sensors[SENSOR_DHT11].lastRead = 0;
sensors[SENSOR_DHT11].status = SENSOR_NOT_READY;
dht.begin();
// ์กฐ๋ ์ผ์ ์ด๊ธฐํ
sensors[SENSOR_LDR].type = SENSOR_LDR;
sensors[SENSOR_LDR].readInterval = 500; // 0.5์ด
sensors[SENSOR_LDR].lastRead = 0;
sensors[SENSOR_LDR].status = SENSOR_OK;
pinMode(LDR_PIN, INPUT);
// ์ด์ํ ์ผ์ ์ด๊ธฐํ
sensors[SENSOR_ULTRASONIC].type = SENSOR_ULTRASONIC;
sensors[SENSOR_ULTRASONIC].readInterval = 100; // 0.1์ด
sensors[SENSOR_ULTRASONIC].lastRead = 0;
sensors[SENSOR_ULTRASONIC].status = SENSOR_OK;
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
Serial.println("โ
๋ชจ๋ ์ผ์ ์ด๊ธฐํ ์๋ฃ!");
}
// DHT11 ์ฝ๊ธฐ
bool readDHT11(Sensor *sensor) {
float h = dht.readHumidity();
float t = dht.readTemperature();
if (isnan(h) || isnan(t)) {
sensor->status = SENSOR_ERROR;
return false;
}
sensor->value1 = t;
sensor->value2 = h;
sensor->status = SENSOR_OK;
return true;
}
// ์กฐ๋ ์ผ์ ์ฝ๊ธฐ
bool readLDR(Sensor *sensor) {
int rawValue = analogRead(LDR_PIN);
// 0-1023์ 0-100%๋ก ๋ณํ
sensor->value1 = map(rawValue, 0, 1023, 0, 100);
sensor->status = SENSOR_OK;
return true;
}
// ์ด์ํ ์ผ์ ์ฝ๊ธฐ
bool readUltrasonic(Sensor *sensor) {
// ํธ๋ฆฌ๊ฑฐ ํ์ค ์์ฑ
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
// ์์ฝ ํ์ค ์ธก์
long duration = pulseIn(ECHO_PIN, HIGH, 30000); // ํ์์์ 30ms
if (duration == 0) {
sensor->status = SENSOR_ERROR;
return false;
}
// ๊ฑฐ๋ฆฌ ๊ณ์ฐ (cm)
float distance = duration * 0.034 / 2;
sensor->value1 = distance;
sensor->status = SENSOR_OK;
return true;
}
// ์ผ์ ์
๋ฐ์ดํธ (๋
ผ๋ธ๋กํน ๋ฐฉ์)
void updateSensors() {
unsigned long currentTime = millis();
for (int i = 0; i < SENSOR_COUNT; i++) {
// ์ฝ๊ธฐ ๊ฐ๊ฒฉ ์ฒดํฌ
if (currentTime - sensors[i].lastRead >= sensors[i].readInterval) {
bool success = false;
switch (sensors[i].type) {
case SENSOR_DHT11:
success = readDHT11(&sensors[i]);
break;
case SENSOR_LDR:
success = readLDR(&sensors[i]);
break;
case SENSOR_ULTRASONIC:
success = readUltrasonic(&sensors[i]);
break;
}
sensors[i].lastRead = currentTime;
if (success) {
printSensorData(&sensors[i]);
}
}
}
}
// ์ผ์ ๋ฐ์ดํฐ ์ถ๋ ฅ
void printSensorData(Sensor *sensor) {
Serial.print("[");
Serial.print(millis());
Serial.print("ms] ");
switch (sensor->type) {
case SENSOR_DHT11:
Serial.print("๐ก๏ธ ์จ๋: ");
Serial.print(sensor->value1);
Serial.print("ยฐC, ๐ง ์ต๋: ");
Serial.print(sensor->value2);
Serial.println("%");
break;
case SENSOR_LDR:
Serial.print("๐ก ์กฐ๋: ");
Serial.print(sensor->value1);
Serial.println("%");
break;
case SENSOR_ULTRASONIC:
Serial.print("๐ ๊ฑฐ๋ฆฌ: ");
Serial.print(sensor->value1);
Serial.println("cm");
break;
}
}
void setup() {
Serial.begin(9600);
Serial.println("๐ ๋ค์ค ์ผ์ ์์คํ
์์!");
Serial.println("โโโโโโโโโโโโโโโโโโโโโโโโ");
initSensors();
}
void loop() {
updateSensors();
// ๋ค๋ฅธ ์์
๋ ์ฌ๊ธฐ์ ์ํ ๊ฐ๋ฅ
// ๋
ผ๋ธ๋กํน ๋ฐฉ์์ด๋ผ ์์คํ
์ด ๋ฉ์ถ์ง ์์!
}
์ด ์ฝ๋์ ํต์ฌ์ ๋
ผ๋ธ๋กํน(Non-blocking) ๋ฐฉ์์ด์ผ! ๊ฐ ์ผ์๊ฐ ์์ ์ ์ฝ๊ธฐ ๊ฐ๊ฒฉ์ ๊ฐ์ง๊ณ ์์ด์, ํ๋์ ์ผ์๋ฅผ ๊ธฐ๋ค๋ฆฌ๋๋ผ ๋ค๋ฅธ ์ผ์๊ฐ ๋ฉ์ถ๋ ์ผ์ด ์์ด. ์ด๊ฒ ๋ฐ๋ก ์ค์ IoT ์์คํ
์ ํต์ฌ์ด์ง! โก
๐ก Pro Tip
์ค์ ํ๋ก์ ํธ์์๋ ์ด๋ฐ ์ผ์ ๋งค๋์ ๊ตฌ์กฐ๋ฅผ ์ฌ์ฉํ๋ฉด ์ ๋ง ํธํด! ์๋ก์ด ์ผ์๋ฅผ ์ถ๊ฐํ๊ธฐ๋ ์ฝ๊ณ , ๊ฐ ์ผ์๋ฅผ ๋ ๋ฆฝ์ ์ผ๋ก ๊ด๋ฆฌํ ์ ์๊ฑฐ๋ . ์ฌ๋ฅ๋ท์์ ์๋ฒ ๋๋ ์์คํ ์ ๋ฌธ๊ฐ๋ค์ ์กฐ์ธ์ ๋ฐ์ผ๋ฉด ๋ ํจ์จ์ ์ธ ๊ตฌ์กฐ๋ฅผ ๋ฐฐ์ธ ์ ์์ด!
์ค์ ํ๋ก์ ํธ์์๋ ์ด๋ฐ ์ผ์ ๋งค๋์ ๊ตฌ์กฐ๋ฅผ ์ฌ์ฉํ๋ฉด ์ ๋ง ํธํด! ์๋ก์ด ์ผ์๋ฅผ ์ถ๊ฐํ๊ธฐ๋ ์ฝ๊ณ , ๊ฐ ์ผ์๋ฅผ ๋ ๋ฆฝ์ ์ผ๋ก ๊ด๋ฆฌํ ์ ์๊ฑฐ๋ . ์ฌ๋ฅ๋ท์์ ์๋ฒ ๋๋ ์์คํ ์ ๋ฌธ๊ฐ๋ค์ ์กฐ์ธ์ ๋ฐ์ผ๋ฉด ๋ ํจ์จ์ ์ธ ๊ตฌ์กฐ๋ฅผ ๋ฐฐ์ธ ์ ์์ด!
๐ก ๋ฐ์ดํฐ ํต์ ํ๋กํ ์ฝ
์ผ์ ๋ฐ์ดํฐ๋ฅผ ์์งํ์ผ๋ฉด ์ด์ ์ด๋๊ฐ๋ก ๋ณด๋ด์ผ๊ฒ ์ง? IoT์ ํต์ฌ์ ๋ฐ๋ก **ํต์ **์ด์ผ! ์ฌ๋ฌ ๊ฐ์ง ํต์ ๋ฐฉ๋ฒ์ด ์๋๋ฐ, ํ๋์ฉ ์์๋ณด์. ๐ถ์๋ฆฌ์ผ ํต์ (UART)
๊ฐ์ฅ ๊ธฐ๋ณธ์ ์ธ ํต์ ๋ฐฉ๋ฒ์ด์ผ. ์ฐ๋ฆฌ๊ฐ ์ง๊ธ๊น์ง ์ฌ์ฉํ Serial.print()๊ฐ ๋ฐ๋ก UART ํต์ ์ด์ง! ๊ฐ๋จํ์ง๋ง ๊ฐ๋ ฅํด:
// JSON ํ์์ผ๋ก ๋ฐ์ดํฐ ์ ์ก
void sendSensorDataJSON() {
Serial.print("{");
Serial.print("\"temperature\":");
Serial.print(sensors[SENSOR_DHT11].value1);
Serial.print(",\"humidity\":");
Serial.print(sensors[SENSOR_DHT11].value2);
Serial.print(",\"light\":");
Serial.print(sensors[SENSOR_LDR].value1);
Serial.print(",\"distance\":");
Serial.print(sensors[SENSOR_ULTRASONIC].value1);
Serial.print(",\"timestamp\":");
Serial.print(millis());
Serial.println("}");
}
// ๋ฐ์ด๋๋ฆฌ ํ๋กํ ์ฝ (๋ ํจ์จ์ )
typedef struct {
uint8_t header; // 0xAA (์์ ๋ง์ปค)
float temperature;
float humidity;
float light;
float distance;
uint32_t timestamp;
uint8_t checksum;
} __attribute__((packed)) DataPacket;
void sendBinaryData() {
DataPacket packet;
packet.header = 0xAA;
packet.temperature = sensors[SENSOR_DHT11].value1;
packet.humidity = sensors[SENSOR_DHT11].value2;
packet.light = sensors[SENSOR_LDR].value1;
packet.distance = sensors[SENSOR_ULTRASONIC].value1;
packet.timestamp = millis();
// ์ฒดํฌ์ฌ ๊ณ์ฐ (๊ฐ๋จํ XOR)
uint8_t *data = (uint8_t*)&packet;
packet.checksum = 0;
for (int i = 0; i < sizeof(DataPacket) - 1; i++) {
packet.checksum ^= data[i];
}
// ๋ฐ์ด๋๋ฆฌ ๋ฐ์ดํฐ ์ ์ก
Serial.write((uint8_t*)&packet, sizeof(DataPacket));
}
JSON์ ์ฌ๋์ด ์ฝ๊ธฐ ์ฝ์ง๋ง ๋ฐ์ดํฐ ํฌ๊ธฐ๊ฐ ์ปค. ๋ฐ๋ฉด ๋ฐ์ด๋๋ฆฌ ํ๋กํ ์ฝ์ ํจ์จ์ ์ด์ง๋ง ํ์ฑ์ด ๋ณต์กํด. ์ํฉ์ ๋ง๊ฒ ์ ํํ๋ฉด ๋ผ! ๐ฏ
WiFi ํต์ (ESP32 ์์ )
ESP32๋ฅผ ์ฌ์ฉํ๋ฉด WiFi๋ก ๋ฐ์ดํฐ๋ฅผ ์ ์กํ ์ ์์ด. ์ง์ง IoT์ ์์์ด์ง! ๐
#include <WiFi.h>
#include <HTTPClient.h>
const char* ssid = "your_wifi_ssid";
const char* password = "your_wifi_password";
const char* serverUrl = "http://your-server.com/api/sensor-data";
void setupWiFi() {
Serial.print("WiFi ์ฐ๊ฒฐ ์ค");
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nโ
WiFi ์ฐ๊ฒฐ ์๋ฃ!");
Serial.print("IP ์ฃผ์: ");
Serial.println(WiFi.localIP());
}
void sendDataToServer() {
if (WiFi.status() == WL_CONNECTED) {
HTTPClient http;
http.begin(serverUrl);
http.addHeader("Content-Type", "application/json");
// JSON ๋ฐ์ดํฐ ์์ฑ
String jsonData = "{";
jsonData += "\"temperature\":" + String(sensors[SENSOR_DHT11].value1) + ",";
jsonData += "\"humidity\":" + String(sensors[SENSOR_DHT11].value2) + ",";
jsonData += "\"light\":" + String(sensors[SENSOR_LDR].value1) + ",";
jsonData += "\"distance\":" + String(sensors[SENSOR_ULTRASONIC].value1) + ",";
jsonData += "\"timestamp\":" + String(millis());
jsonData += "}";
// POST ์์ฒญ
int httpResponseCode = http.POST(jsonData);
if (httpResponseCode > 0) {
String response = http.getString();
Serial.print("โ
์๋ฒ ์๋ต: ");
Serial.println(response);
} else {
Serial.print("โ ์ ์ก ์คํจ: ");
Serial.println(httpResponseCode);
}
http.end();
} else {
Serial.println("โ ๏ธ WiFi ์ฐ๊ฒฐ ๋๊น!");
}
}
// MQTT ํ๋กํ ์ฝ (๋ ํจ์จ์ ์ธ IoT ํต์ )
#include <PubSubClient.h>
WiFiClient espClient;
PubSubClient mqttClient(espClient);
const char* mqttServer = "broker.hivemq.com";
const int mqttPort = 1883;
const char* mqttTopic = "myiot/sensors";
void setupMQTT() {
mqttClient.setServer(mqttServer, mqttPort);
mqttClient.setCallback(mqttCallback);
}
void mqttCallback(char* topic, byte* payload, unsigned int length) {
Serial.print("๐จ ๋ฉ์์ง ์์ : ");
for (int i = 0; i < length; i++) {
Serial.print((char)payload[i]);
}
Serial.println();
}
void reconnectMQTT() {
while (!mqttClient.connected()) {
Serial.print("MQTT ์ฐ๊ฒฐ ์๋...");
if (mqttClient.connect("ESP32Client")) {
Serial.println("โ
์ฐ๊ฒฐ ์ฑ๊ณต!");
mqttClient.subscribe("myiot/commands");
} else {
Serial.print("โ ์คํจ, rc=");
Serial.print(mqttClient.state());
Serial.println(" 5์ด ํ ์ฌ์๋");
delay(5000);
}
}
}
void publishSensorData() {
if (!mqttClient.connected()) {
reconnectMQTT();
}
mqttClient.loop();
String payload = "{";
payload += "\"temp\":" + String(sensors[SENSOR_DHT11].value1) + ",";
payload += "\"humid\":" + String(sensors[SENSOR_DHT11].value2);
payload += "}";
mqttClient.publish(mqttTopic, payload.c_str());
Serial.println("๐ค ๋ฐ์ดํฐ ๋ฐํ ์๋ฃ!");
}
MQTT๋ IoT์ ์ต์ ํ๋ ํ๋กํ ์ฝ์ด์ผ. HTTP๋ณด๋ค ํจ์ฌ ๊ฐ๋ณ๊ณ ํจ์จ์ ์ด์ง! ์ค์๊ฐ ์๋ฐฉํฅ ํต์ ๋ ๊ฐ๋ฅํด์ ๋ช
๋ น์ ๋ฐ์ ์ก์ถ์์ดํฐ๋ฅผ ์ ์ดํ ์๋ ์์ด. ๐ฎ
๐พ ๋ฐ์ดํฐ ์ ์ฅ ๋ฐ ๋ก๊น ์์คํ
์ผ์ ๋ฐ์ดํฐ๋ฅผ ์์งํ๊ณ ํต์ ๊น์ง ํ๋ค๋ฉด, ์ด์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํด์ผ๊ฒ ์ง? ๋์ค์ ๋ถ์ํ๊ฑฐ๋ ๋ฌธ์ ๊ฐ ์๊ฒผ์ ๋ ๋๋ฒ๊น ํ๋ ค๋ฉด ๋ก๊ทธ๊ฐ ํ์์ผ! ๐SD ์นด๋ ๋ฐ์ดํฐ ๋ก๊น
์๋์ด๋
ธ๋ ESP32์ SD ์นด๋ ๋ชจ๋์ ์ฐ๊ฒฐํ๋ฉด ๋ก์ปฌ์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ์ ์์ด. ์ธํฐ๋ท ์ฐ๊ฒฐ์ด ๋๊ฒจ๋ ๋ฐ์ดํฐ๋ฅผ ์์ด๋ฒ๋ฆฌ์ง ์์ง!
#include <SD.h>
#include <SPI.h>
#define SD_CS_PIN 5 // SD ์นด๋ ์นฉ ์
๋ ํธ ํ
File dataFile;
unsigned long lastLogTime = 0;
const unsigned long LOG_INTERVAL = 60000; // 1๋ถ๋ง๋ค ๋ก๊ทธ
bool initSDCard() {
Serial.print("SD ์นด๋ ์ด๊ธฐํ ์ค...");
if (!SD.begin(SD_CS_PIN)) {
Serial.println("โ SD ์นด๋ ์ด๊ธฐํ ์คํจ!");
return false;
}
Serial.println("โ
SD ์นด๋ ์ค๋น ์๋ฃ!");
// ๋ก๊ทธ ํ์ผ ํค๋ ์์ฑ (ํ์ผ์ด ์์ ๋๋ง)
if (!SD.exists("/sensor_log.csv")) {
dataFile = SD.open("/sensor_log.csv", FILE_WRITE);
if (dataFile) {
dataFile.println("Timestamp,Temperature,Humidity,Light,Distance");
dataFile.close();
Serial.println("๐ ์ ๋ก๊ทธ ํ์ผ ์์ฑ");
}
}
return true;
}
void logSensorData() {
unsigned long currentTime = millis();
// ๋ก๊ทธ ๊ฐ๊ฒฉ ์ฒดํฌ
if (currentTime - lastLogTime < LOG_INTERVAL) {
return;
}
lastLogTime = currentTime;
// CSV ํ์์ผ๋ก ๋ฐ์ดํฐ ์ ์ฅ
dataFile = SD.open("/sensor_log.csv", FILE_APPEND);
if (dataFile) {
dataFile.print(currentTime);
dataFile.print(",");
dataFile.print(sensors[SENSOR_DHT11].value1);
dataFile.print(",");
dataFile.print(sensors[SENSOR_DHT11].value2);
dataFile.print(",");
dataFile.print(sensors[SENSOR_LDR].value1);
dataFile.print(",");
dataFile.println(sensors[SENSOR_ULTRASONIC].value1);
dataFile.close();
Serial.println("๐พ ๋ฐ์ดํฐ ์ ์ฅ ์๋ฃ!");
} else {
Serial.println("โ ํ์ผ ์ด๊ธฐ ์คํจ!");
}
}
// ๋ก๊ทธ ํ์ผ ์ฝ๊ธฐ ๋ฐ ์ถ๋ ฅ
void printLogFile() {
dataFile = SD.open("/sensor_log.csv", FILE_READ);
if (dataFile) {
Serial.println("๐ ๋ก๊ทธ ํ์ผ ๋ด์ฉ:");
Serial.println("โโโโโโโโโโโโโโโโโโโโโโโโ");
while (dataFile.available()) {
Serial.write(dataFile.read());
}
dataFile.close();
Serial.println("โโโโโโโโโโโโโโโโโโโโโโโโ");
} else {
Serial.println("โ ๋ก๊ทธ ํ์ผ ์์!");
}
}
// ๋ก๊ทธ ํ์ผ ํฌ๊ธฐ ๊ด๋ฆฌ (์ํ ๋ก๊น
)
void manageLogSize() {
File logFile = SD.open("/sensor_log.csv", FILE_READ);
if (logFile) {
unsigned long fileSize = logFile.size();
logFile.close();
// ํ์ผ์ด 1MB๋ฅผ ์ด๊ณผํ๋ฉด ๋ฐฑ์
ํ๊ณ ์๋ก ์์
if (fileSize > 1048576) {
Serial.println("๐ฆ ๋ก๊ทธ ํ์ผ ๋ฐฑ์
์ค...");
// ๊ธฐ์กด ํ์ผ์ ๋ฐฑ์
์ผ๋ก ์ด๋ฆ ๋ณ๊ฒฝ
SD.remove("/sensor_log_old.csv");
SD.rename("/sensor_log.csv", "/sensor_log_old.csv");
// ์ ๋ก๊ทธ ํ์ผ ์์ฑ
dataFile = SD.open("/sensor_log.csv", FILE_WRITE);
if (dataFile) {
dataFile.println("Timestamp,Temperature,Humidity,Light,Distance");
dataFile.close();
Serial.println("โ
์ ๋ก๊ทธ ํ์ผ ์์!");
}
}
}
}
์ด๋ ๊ฒ ํ๋ฉด ์ฅ๊ธฐ๊ฐ ๋ฐ์ดํฐ๋ฅผ ์์ ํ๊ฒ ์ ์ฅํ ์ ์์ด! CSV ํ์์ด๋ผ ์์
์ด๋ ํ์ด์ฌ์ผ๋ก ๋ถ์ํ๊ธฐ๋ ์ฝ์ง. ๐
EEPROM ํ์ฉํ๊ธฐ
์ค์ ๊ฐ์ด๋ ์ค์ํ ๋ฐ์ดํฐ๋ EEPROM์ ์ ์ฅํ๋ฉด ์ ์์ด ๊บผ์ ธ๋ ์ ์ง๋ผ. ํ์ง๋ง ์ฐ๊ธฐ ํ์ ์ ํ์ด ์์ผ๋ ์ฃผ์ํด์ผ ํด!
#include <EEPROM.h>
// EEPROM ์ฃผ์ ์ ์
#define EEPROM_SIZE 512
#define ADDR_TEMP_THRESHOLD 0
#define ADDR_HUMID_THRESHOLD 4
#define ADDR_LOG_INTERVAL 8
#define ADDR_WIFI_SSID 12
#define ADDR_WIFI_PASS 44
// ์ค์ ๊ตฌ์กฐ์ฒด
typedef struct {
float tempThreshold;
float humidThreshold;
unsigned long logInterval;
char wifiSSID[32];
char wifiPassword[32];
} SystemConfig;
SystemConfig config;
void initEEPROM() {
EEPROM.begin(EEPROM_SIZE);
Serial.println("๐พ EEPROM ์ด๊ธฐํ ์๋ฃ");
}
// ์ค์ ์ ์ฅ
void saveConfig() {
EEPROM.put(ADDR_TEMP_THRESHOLD, config.tempThreshold);
EEPROM.put(ADDR_HUMID_THRESHOLD, config.humidThreshold);
EEPROM.put(ADDR_LOG_INTERVAL, config.logInterval);
// ๋ฌธ์์ด ์ ์ฅ
for (int i = 0; i < 32; i++) {
EEPROM.write(ADDR_WIFI_SSID + i, config.wifiSSID[i]);
EEPROM.write(ADDR_WIFI_PASS + i, config.wifiPassword[i]);
}
EEPROM.commit(); // ESP32์์๋ commit ํ์
Serial.println("โ
์ค์ ์ ์ฅ ์๋ฃ!");
}
// ์ค์ ๋ถ๋ฌ์ค๊ธฐ
void loadConfig() {
EEPROM.get(ADDR_TEMP_THRESHOLD, config.tempThreshold);
EEPROM.get(ADDR_HUMID_THRESHOLD, config.humidThreshold);
EEPROM.get(ADDR_LOG_INTERVAL, config.logInterval);
// ๋ฌธ์์ด ๋ถ๋ฌ์ค๊ธฐ
for (int i = 0; i < 32; i++) {
config.wifiSSID[i] = EEPROM.read(ADDR_WIFI_SSID + i);
config.wifiPassword[i] = EEPROM.read(ADDR_WIFI_PASS + i);
}
Serial.println("โ
์ค์ ๋ถ๋ฌ์ค๊ธฐ ์๋ฃ!");
printConfig();
}
void printConfig() {
Serial.println("โโโโโโโโโโโโโโโโโโโโโโโโ");
Serial.println("โ๏ธ ํ์ฌ ์ค์ :");
Serial.print("์จ๋ ์๊ณ๊ฐ: ");
Serial.print(config.tempThreshold);
Serial.println("ยฐC");
Serial.print("์ต๋ ์๊ณ๊ฐ: ");
Serial.print(config.humidThreshold);
Serial.println("%");
Serial.print("๋ก๊ทธ ๊ฐ๊ฒฉ: ");
Serial.print(config.logInterval / 1000);
Serial.println("์ด");
Serial.println("โโโโโโโโโโโโโโโโโโโโโโโโ");
}
โ ๏ธ EEPROM ์ฃผ์์ฌํญ
EEPROM์ ์ฐ๊ธฐ ํ์๊ฐ ์ ํ๋์ด ์์ด (๋ณดํต 10๋ง~100๋ง ํ). ์์ฃผ ๋ณํ๋ ๋ฐ์ดํฐ๋ RAM์ ์ ์ฅํ๊ณ , ์ ๋ง ํ์ํ ๋๋ง EEPROM์ ์ฐ์!
EEPROM์ ์ฐ๊ธฐ ํ์๊ฐ ์ ํ๋์ด ์์ด (๋ณดํต 10๋ง~100๋ง ํ). ์์ฃผ ๋ณํ๋ ๋ฐ์ดํฐ๋ RAM์ ์ ์ฅํ๊ณ , ์ ๋ง ํ์ํ ๋๋ง EEPROM์ ์ฐ์!
๐จ ๊ณ ๊ธ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ๊ธฐ๋ฒ
์ด์ ์ข ๋ ๊ณ ๊ธ ๊ธฐ์ ์ ๋ฐฐ์๋ณผ๊น? ์ค์ ์ฐ์ ํ์ฅ์์ ์ฌ์ฉํ๋ ๋ฐ์ดํฐ ์ฒ๋ฆฌ ๊ธฐ๋ฒ๋ค์ด์ผ! ๐์ด์์น ํ์ง (Outlier Detection)
์ผ์๊ฐ ๊ฐ๋ ์ด์ํ ๊ฐ์ ๋ฑ์ ๋๊ฐ ์์ด. ์ด๋ฐ ์ด์์น๋ฅผ ์๋์ผ๋ก ๊ฐ์งํ๊ณ ์ ๊ฑฐํ๋ ์๊ณ ๋ฆฌ์ฆ์ ๋ง๋ค์ด๋ณด์!
#define HISTORY_SIZE 20
typedef struct {
float values[HISTORY_SIZE];
int count;
int index;
} DataHistory;
DataHistory tempHistory;
void initHistory(DataHistory *hist) {
hist->count = 0;
hist->index = 0;
for (int i = 0; i < HISTORY_SIZE; i++) {
hist->values[i] = 0.0;
}
}
void addToHistory(DataHistory *hist, float value) {
hist->values[hist->index] = value;
hist->index = (hist->index + 1) % HISTORY_SIZE;
if (hist->count < HISTORY_SIZE) {
hist->count++;
}
}
// ํ๊ท ๊ณ์ฐ
float calculateMean(DataHistory *hist) {
if (hist->count == 0) return 0.0;
float sum = 0.0;
for (int i = 0; i < hist->count; i++) {
sum += hist->values[i];
}
return sum / hist->count;
}
// ํ์คํธ์ฐจ ๊ณ์ฐ
float calculateStdDev(DataHistory *hist) {
if (hist->count < 2) return 0.0;
float mean = calculateMean(hist);
float sumSquares = 0.0;
for (int i = 0; i < hist->count; i++) {
float diff = hist->values[i] - mean;
sumSquares += diff * diff;
}
return sqrt(sumSquares / (hist->count - 1));
}
// ์ด์์น ํ๋จ (Z-score ๋ฐฉ๋ฒ)
bool isOutlier(DataHistory *hist, float newValue, float threshold) {
if (hist->count < 3) return false; // ๋ฐ์ดํฐ๊ฐ ์ถฉ๋ถํ์ง ์์
float mean = calculateMean(hist);
float stdDev = calculateStdDev(hist);
if (stdDev < 0.01) return false; // ํ์คํธ์ฐจ๊ฐ ๋๋ฌด ์์
// Z-score ๊ณ์ฐ
float zScore = abs(newValue - mean) / stdDev;
// ์๊ณ๊ฐ ์ด๊ณผ ์ ์ด์์น๋ก ํ๋จ
if (zScore > threshold) {
Serial.print("๐จ ์ด์์น ๊ฐ์ง! ๊ฐ: ");
Serial.print(newValue);
Serial.print(", Z-score: ");
Serial.println(zScore);
return true;
}
return false;
}
// ์ด์์น ์ ๊ฑฐ ํ ๊ฐ ๋ฐํ
float getFilteredValue(DataHistory *hist, float newValue) {
// ์ด์์น ํ๋จ (Z-score > 3์ด๋ฉด ์ด์์น)
if (isOutlier(hist, newValue, 3.0)) {
// ์ด์์น๋ฉด ์ด์ ํ๊ท ๊ฐ ๋ฐํ
Serial.println("โ ๏ธ ์ด์์น ์ ๊ฑฐ, ํ๊ท ๊ฐ ์ฌ์ฉ");
return calculateMean(hist);
}
// ์ ์ ๊ฐ์ด๋ฉด ํ์คํ ๋ฆฌ์ ์ถ๊ฐํ๊ณ ๋ฐํ
addToHistory(hist, newValue);
return newValue;
}
void loop() {
delay(2000);
float rawTemp = dht.readTemperature();
if (!isnan(rawTemp)) {
// ์ด์์น ํํฐ๋ง ์ ์ฉ
float filteredTemp = getFilteredValue(&tempHistory, rawTemp);
Serial.print("์๋ณธ: ");
Serial.print(rawTemp);
Serial.print("ยฐC โ ํํฐ๋ง: ");
Serial.print(filteredTemp);
Serial.println("ยฐC");
}
}
์ด ์๊ณ ๋ฆฌ์ฆ์ ํต๊ณ์ ๋ฐฉ๋ฒ์ผ๋ก ์ด์์น๋ฅผ ๊ฐ์งํด. Z-score๊ฐ 3์ ๋์ผ๋ฉด 99.7% ํ๋ฅ ๋ก ์ด์์น๋ผ๊ณ ํ๋จํ ์ ์์ด! ๐
์์ธก ์๊ณ ๋ฆฌ์ฆ (Simple Linear Regression)
๊ณผ๊ฑฐ ๋ฐ์ดํฐ๋ฅผ ๋ฐํ์ผ๋ก ๋ฏธ๋ ๊ฐ์ ์์ธกํ ์๋ ์์ด! ๊ฐ๋จํ ์ ํ ํ๊ท๋ฅผ ๊ตฌํํด๋ณด์:
typedef struct {
float slope;
float intercept;
float correlation;
} RegressionModel;
// ์ ํ ํ๊ท ๊ณ์ฐ
RegressionModel calculateRegression(DataHistory *hist) {
RegressionModel model = {0.0, 0.0, 0.0};
if (hist->count < 2) return model;
float sumX = 0.0, sumY = 0.0, sumXY = 0.0, sumX2 = 0.0;
for (int i = 0; i < hist->count; i++) {
float x = (float)i;
float y = hist->values[i];
sumX += x;
sumY += y;
sumXY += x * y;
sumX2 += x * x;
}
int n = hist->count;
// ๊ธฐ์ธ๊ธฐ ๊ณ์ฐ
model.slope = (n * sumXY - sumX * sumY) / (n * sumX2 - sumX * sumX);
// ์ ํธ ๊ณ์ฐ
model.intercept = (sumY - model.slope * sumX) / n;
// ์๊ด๊ณ์ ๊ณ์ฐ
float meanX = sumX / n;
float meanY = sumY / n;
float sumXDiff2 = 0.0, sumYDiff2 = 0.0, sumXYDiff = 0.0;
for (int i = 0; i < n; i++) {
float xDiff = i - meanX;
float yDiff = hist->values[i] - meanY;
sumXDiff2 += xDiff * xDiff;
sumYDiff2 += yDiff * yDiff;
sumXYDiff += xDiff * yDiff;
}
model.correlation = sumXYDiff / sqrt(sumXDiff2 * sumYDiff2);
return model;
}
// ๋ฏธ๋ ๊ฐ ์์ธก
float predictValue(RegressionModel *model, int stepsAhead) {
int futureX = HISTORY_SIZE + stepsAhead;
return model->slope * futureX + model->intercept;
}
void analyzeTemperatureTrend() {
RegressionModel model = calculateRegression(&tempHistory);
Serial.println("๐ ์จ๋ ํธ๋ ๋ ๋ถ์:");
Serial.print("๊ธฐ์ธ๊ธฐ: ");
Serial.println(model.slope, 4);
Serial.print("์๊ด๊ณ์: ");
Serial.println(model.correlation, 4);
if (model.slope > 0.1) {
Serial.println("๐ ์จ๋ ์์น ์ถ์ธ!");
} else if (model.slope < -0.1) {
Serial.println("๐ ์จ๋ ํ๊ฐ ์ถ์ธ!");
} else {
Serial.println("โก๏ธ ์จ๋ ์์ ์ ");
}
// 10๋ถ ํ ์์ธก
float prediction = predictValue(&model, 5); // 5๊ฐ ๋ฐ์ดํฐ ํฌ์ธํธ ํ
Serial.print("๐ฎ ์์ ์จ๋ (10๋ถ ํ): ");
Serial.print(prediction);
Serial.println("ยฐC");
}
์ด๋ฐ ์์ธก ์๊ณ ๋ฆฌ์ฆ์ ์ฌ์ฉํ๋ฉด ์จ๋๊ฐ ์๊ณ๊ฐ์ ๋๊ธฐ ์ ์ ๋ฏธ๋ฆฌ ๊ฒฝ๊ณ ๋ฅผ ์ค ์ ์์ด! ์ ๋ง ์ค๋งํธํ์ง? ๐ง
โก ์ ๋ ฅ ๊ด๋ฆฌ ๋ฐ ์ต์ ํ
IoT ๊ธฐ๊ธฐ๋ ๋๋ถ๋ถ ๋ฐฐํฐ๋ฆฌ๋ก ๋์ํ์์? ๊ทธ๋์ ์ ๋ ฅ ๊ด๋ฆฌ๊ฐ ์ ๋ง ์ค์ํด! ํจ์จ์ ์ธ ์ ๋ ฅ ๊ด๋ฆฌ ๊ธฐ๋ฒ์ ์์๋ณด์. ๐์ฌ๋ฆฝ ๋ชจ๋ ํ์ฉํ๊ธฐ
์ผ์๋ฅผ ๊ณ์ ์ฝ์ ํ์๊ฐ ์๋ค๋ฉด ๋ง์ดํฌ๋ก์ปจํธ๋กค๋ฌ๋ฅผ ์ฌ๋ฆฝ ๋ชจ๋๋ก ๋ณด๋ด์. ์ ๋ ฅ ์๋น๋ฅผ 90% ์ด์ ์ค์ผ ์ ์์ด!
#include <esp_sleep.h> // ESP32์ฉ
#define SLEEP_DURATION 60 // ์ด ๋จ์
// ๋ฅ ์ฌ๋ฆฝ ์ค์
void setupDeepSleep() {
// ํ์ด๋จธ๋ก ๊นจ์ด๋๊ธฐ ์ค์
esp_sleep_enable_timer_wakeup(SLEEP_DURATION * 1000000ULL);
Serial.println("๐ค ๋ฅ ์ฌ๋ฆฝ ๋ชจ๋ ์ง์
...");
Serial.flush(); // ์๋ฆฌ์ผ ๋ฒํผ ๋น์ฐ๊ธฐ
// ๋ฅ ์ฌ๋ฆฝ ์ง์
esp_deep_sleep_start();
}
// ๋ผ์ดํธ ์ฌ๋ฆฝ (๋ ๋น ๋ฅธ ๊นจ์ด๋จ)
void lightSleep(int seconds) {
Serial.println("๐ด ๋ผ์ดํธ ์ฌ๋ฆฝ ๋ชจ๋...");
esp_sleep_enable_timer_wakeup(seconds * 1000000ULL);
esp_light_sleep_start();
Serial.println("๐ ๊นจ์ด๋จ!");
}
// ์ผ์ ์ฝ๊ธฐ โ ์ ์ก โ ์ฌ๋ฆฝ ์ฌ์ดํด
void efficientDataCollection() {
// 1. ์ผ์ ๋ฐ์ดํฐ ์ฝ๊ธฐ
float temp = dht.readTemperature();
float humid = dht.readHumidity();
// 2. ๋ฐ์ดํฐ ์ ์ก
if (!isnan(temp) && !isnan(humid)) {
sendDataToServer(); // WiFi๋ก ์ ์ก
}
// 3. WiFi ๋๊ธฐ (์ ๋ ฅ ์ ์ฝ)
WiFi.disconnect(true);
WiFi.mode(WIFI_OFF);
// 4. ๋ฅ ์ฌ๋ฆฝ (1๋ถ๊ฐ)
setupDeepSleep();
}
// ๊นจ์ด๋ฌ์ ๋ ์คํ๋๋ ์ฝ๋
void setup() {
Serial.begin(115200);
// ๊นจ์ด๋ ์ด์ ํ์ธ
esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause();
switch(wakeup_reason) {
case ESP_SLEEP_WAKEUP_TIMER:
Serial.println("โฐ ํ์ด๋จธ๋ก ๊นจ์ด๋จ");
break;
case ESP_SLEEP_WAKEUP_EXT0:
Serial.println("๐ ์ธ๋ถ ์ธํฐ๋ฝํธ๋ก ๊นจ์ด๋จ");
break;
default:
Serial.println("๐ ์ ์ ์ผ์ง");
break;
}
// WiFi ์ฐ๊ฒฐ
setupWiFi();
// ์ผ์ ์ด๊ธฐํ
dht.begin();
}
void loop() {
efficientDataCollection();
// ์ด ์ฝ๋๋ ์คํ๋์ง ์์ (๋ฅ ์ฌ๋ฆฝ ํ ์ฌ๋ถํ
)
}
๋ฅ ์ฌ๋ฆฝ์ ์ฌ์ฉํ๋ฉด ๋ฐฐํฐ๋ฆฌ ์๋ช
์ด ๋ช ์ฃผ์์ ๋ช ๋ฌ๋ก ๋์ด๋ ์ ์์ด! ํ์ง๋ง ๊นจ์ด๋ ๋๋ง๋ค ์ฌ๋ถํ
๋๋ ์ฃผ์ํด์ผ ํด. ๐ก
๋์ ์ ๋ ฅ ๊ด๋ฆฌ
์ํฉ์ ๋ฐ๋ผ ์ผ์ ์ฝ๊ธฐ ์ฃผ๊ธฐ๋ฅผ ์กฐ์ ํ๋ ๊ฒ๋ ์ข์ ๋ฐฉ๋ฒ์ด์ผ:
typedef enum {
POWER_MODE_NORMAL,
POWER_MODE_ECO,
POWER_MODE_ULTRA_ECO
} PowerMode;
PowerMode currentPowerMode = POWER_MODE_NORMAL;
float batteryVoltage = 4.2; // ๋ฆฌํฌ ๋ฐฐํฐ๋ฆฌ ์ ์
// ๋ฐฐํฐ๋ฆฌ ์ ์ ์ฝ๊ธฐ (ESP32 ADC ์ฌ์ฉ)
float readBatteryVoltage() {
int adcValue = analogRead(35); // ๋ฐฐํฐ๋ฆฌ ์ ์ ๋ถ๋ฐฐ ํ๋ก ์ฐ๊ฒฐ
// ADC ๊ฐ์ ์ ์์ผ๋ก ๋ณํ (๋ณด์ ํ์)
return (adcValue / 4095.0) * 3.3 * 2.0; // ์ ์ ๋ถ๋ฐฐ ๋น์จ 2:1
}
// ์ ๋ ฅ ๋ชจ๋ ๊ฒฐ์
void updatePowerMode() {
batteryVoltage = readBatteryVoltage();
if (batteryVoltage > 3.8) {
currentPowerMode = POWER_MODE_NORMAL;
Serial.println("๐ ๋ฐฐํฐ๋ฆฌ ์ถฉ๋ถ - ์ผ๋ฐ ๋ชจ๋");
} else if (batteryVoltage > 3.5) {
currentPowerMode = POWER_MODE_ECO;
Serial.println("๐ ๋ฐฐํฐ๋ฆฌ ๋ณดํต - ์ ์ฝ ๋ชจ๋");
} else {
currentPowerMode = POWER_MODE_ULTRA_ECO;
Serial.println("๐ ๋ฐฐํฐ๋ฆฌ ๋ถ์กฑ - ์ด์ ์ฝ ๋ชจ๋");
}
}
// ๋ชจ๋์ ๋ฐ๋ฅธ ์ผ์ ์ฝ๊ธฐ ๊ฐ๊ฒฉ
unsigned long getSensorInterval() {
switch (currentPowerMode) {
case POWER_MODE_NORMAL:
return 10000; // 10์ด
case POWER_MODE_ECO:
return 60000; // 1๋ถ
case POWER_MODE_ULTRA_ECO:
return 300000; // 5๋ถ
default:
return 10000;
}
}
// ๋ชจ๋์ ๋ฐ๋ฅธ WiFi ์ฌ์ฉ ๊ฒฐ์
bool shouldUseWiFi() {
switch (currentPowerMode) {
case POWER_MODE_NORMAL:
return true; // ํญ์ ์ ์ก
case POWER_MODE_ECO:
return (millis() % 300000 < 10000); // 5๋ถ๋ง๋ค ์ ์ก
case POWER_MODE_ULTRA_ECO:
return false; // SD ์นด๋์๋ง ์ ์ฅ
default:
return true;
}
}
void smartDataCollection() {
static unsigned long lastSensorRead = 0;
unsigned long currentTime = millis();
// ์ ๋ ฅ ๋ชจ๋ ์
๋ฐ์ดํธ (10๋ถ๋ง๋ค)
if (currentTime % 600000 < 1000) {
updatePowerMode();
}
// ์ผ์ ์ฝ๊ธฐ ๊ฐ๊ฒฉ ์ฒดํฌ
if (currentTime - lastSensorRead >= getSensorInterval()) {
lastSensorRead = currentTime;
// ์ผ์ ๋ฐ์ดํฐ ์ฝ๊ธฐ
float temp = dht.readTemperature();
float humid = dht.readHumidity();
// SD ์นด๋์ ์ ์ฅ (ํญ์)
logSensorData();
// WiFi ์ ์ก (๋ชจ๋์ ๋ฐ๋ผ)
if (shouldUseWiFi()) {
sendDataToServer();
}
}
}
์ด๋ ๊ฒ ํ๋ฉด ๋ฐฐํฐ๋ฆฌ ์ํ์ ๋ฐ๋ผ ์๋์ผ๋ก ์ ๋ ฅ ์๋น๋ฅผ ์กฐ์ ํ ์ ์์ด! ์ ๋ง ์ค๋งํธํ์ง? ๐ค
๐ก ์ ๋ ฅ ์ ์ฝ ํ ๋ชจ์
โข LED ์ฌ์ฉ ์ต์ํ (์์ธ๋ก ์ ๋ ฅ ๋ง์ด ๋จน์)
โข ์ผ์ ์ ์์ ํธ๋์ง์คํฐ๋ก ์ ์ด (ํ์ํ ๋๋ง ์ผ๊ธฐ)
โข WiFi ์ ์ก ํ์ ์ค์ด๊ธฐ (๋ฐฐ์น ์ ์ก)
โข ๋ฎ์ ํด๋ญ ์๋ ์ฌ์ฉ (์ฑ๋ฅ vs ์ ๋ ฅ ํธ๋ ์ด๋์คํ)
โข ํจ์จ์ ์ธ ์๊ณ ๋ฆฌ์ฆ ์ฌ์ฉ (CPU ์ฌ์ฉ ์๊ฐ ๋จ์ถ)
โข LED ์ฌ์ฉ ์ต์ํ (์์ธ๋ก ์ ๋ ฅ ๋ง์ด ๋จน์)
โข ์ผ์ ์ ์์ ํธ๋์ง์คํฐ๋ก ์ ์ด (ํ์ํ ๋๋ง ์ผ๊ธฐ)
โข WiFi ์ ์ก ํ์ ์ค์ด๊ธฐ (๋ฐฐ์น ์ ์ก)
โข ๋ฎ์ ํด๋ญ ์๋ ์ฌ์ฉ (์ฑ๋ฅ vs ์ ๋ ฅ ํธ๋ ์ด๋์คํ)
โข ํจ์จ์ ์ธ ์๊ณ ๋ฆฌ์ฆ ์ฌ์ฉ (CPU ์ฌ์ฉ ์๊ฐ ๋จ์ถ)
๐ก๏ธ ์๋ฌ ์ฒ๋ฆฌ ๋ฐ ์์คํ ์์ ์ฑ
์ค์ IoT ์์คํ ์์๋ ์์์น ๋ชปํ ๋ฌธ์ ๊ฐ ํญ์ ๋ฐ์ํด. ๊ฒฌ๊ณ ํ ์๋ฌ ์ฒ๋ฆฌ๊ฐ ํ์์ผ! ๐ ๏ธWatchdog Timer ๊ตฌํ
์์คํ
์ด ๋ฉ์ท์ ๋ ์๋์ผ๋ก ์ฌ์์ํ๋ ์์น๋
ํ์ด๋จธ๋ฅผ ์ค์ ํ์:
#include <esp_task_wdt.h>
#define WDT_TIMEOUT 30 // 30์ด
void setupWatchdog() {
Serial.println("๐ ์์น๋
ํ์ด๋จธ ์ค์ ");
// ์์น๋
์ด๊ธฐํ
esp_task_wdt_init(WDT_TIMEOUT, true);
esp_task_wdt_add(NULL); // ํ์ฌ ํ์คํฌ ์ถ๊ฐ
}
void feedWatchdog() {
// ์์น๋
์๊ฒ "๋ ์ด์์์ด!" ์ ํธ ๋ณด๋ด๊ธฐ
esp_task_wdt_reset();
}
void loop() {
// ์ผ์ ์ฝ๊ธฐ
updateSensors();
// ๋ฐ์ดํฐ ์ฒ๋ฆฌ
processData();
// ์์น๋
๋ฆฌ์
(์ ์ ๋์ ์ค์์ ์๋ฆผ)
feedWatchdog();
delay(1000);
}
์ฌ์๋ ๋ก์ง ๊ตฌํ
WiFi ์ฐ๊ฒฐ์ด๋ ์ผ์ ์ฝ๊ธฐ๊ฐ ์คํจํ์ ๋ ์๋์ผ๋ก ์ฌ์๋ํ๋ ๋ก์ง:
typedef struct {
int maxRetries;
int currentRetry;
unsigned long retryDelay;
unsigned long lastAttempt;
} RetryHandler;
bool readSensorWithRetry(RetryHandler *retry) {
unsigned long currentTime = millis();
// ์ฌ์๋ ๊ฐ๊ฒฉ ์ฒดํฌ
if (currentTime - retry->lastAttempt < retry->retryDelay) {
return false;
}
retry->lastAttempt = currentTime;
// ์ผ์ ์ฝ๊ธฐ ์๋
float temp = dht.readTemperature();
if (isnan(temp)) {
retry->currentRetry++;
Serial.print("โ ์ผ์ ์ฝ๊ธฐ ์คํจ (");
Serial.print(retry->currentRetry);
Serial.print("/");
Serial.print(retry->maxRetries);
Serial.println(")");
if (retry->currentRetry >= retry->maxRetries) {
Serial.println("๐จ ์ต๋ ์ฌ์๋ ํ์ ์ด๊ณผ!");
// ์ผ์ ์ฌ์ด๊ธฐํ ์๋
dht.begin();
retry->currentRetry = 0;
retry->retryDelay *= 2; // ์ง์ ๋ฐฑ์คํ
}
return false;
}
// ์ฑ๊ณต!
retry->currentRetry = 0;
retry->retryDelay = 1000; // ์ด๊ธฐ๊ฐ์ผ๋ก ๋ฆฌ์
return true;
}
// WiFi ์ฌ์ฐ๊ฒฐ ๋ก์ง
bool reconnectWiFi(int maxAttempts) {
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < maxAttempts) {
attempts++;
Serial.print("๐ WiFi ์ฌ์ฐ๊ฒฐ ์๋ ");
Serial.print(attempts);
Serial.print("/");
Serial.println(maxAttempts);
WiFi.disconnect();
delay(1000);
WiFi.begin(ssid, password);
int timeout = 0;
while (WiFi.status() != WL_CONNECTED && timeout < 20) {
delay(500);
Serial.print(".");
timeout++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\nโ
WiFi ์ฌ์ฐ๊ฒฐ ์ฑ๊ณต!");
return true;
}
}
Serial.println("\nโ WiFi ์ฌ์ฐ๊ฒฐ ์คํจ");
return false;
}
์์คํ
์ํ ๋ชจ๋ํฐ๋ง
์์คํ
์ ๊ฑด๊ฐ ์ํ๋ฅผ ์ง์์ ์ผ๋ก ์ฒดํฌํ๋ ๋ชจ๋ํฐ๋ง ์์คํ
:
typedef struct {
unsigned long uptime;
int wifiReconnects;
int sensorErrors;
int dataTransmissions;
int failedTransmissions;
float avgLoopTime;
unsigned long freeHeap;
} SystemStats;
SystemStats stats = {0};
void updateSystemStats() {
static unsigned long lastUpdate = 0;
static unsigned long loopStartTime = 0;
static int loopCount = 0;
unsigned long currentTime = millis();
// ๋ฃจํ ์๊ฐ ์ธก์
if (loopStartTime > 0) {
unsigned long loopTime = currentTime - loopStartTime;
stats.avgLoopTime = (stats.avgLoopTime * loopCount + loopTime) / (loopCount + 1);
loopCount++;
}
loopStartTime = currentTime;
// 1๋ถ๋ง๋ค ํต๊ณ ์
๋ฐ์ดํธ
if (currentTime - lastUpdate >= 60000) {
lastUpdate = currentTime;
stats.uptime = currentTime / 1000; // ์ด ๋จ์
stats.freeHeap = ESP.getFreeHeap();
printSystemStats();
}
}
void printSystemStats() {
Serial.println("\nโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
Serial.println("๐ ์์คํ
ํต๊ณ");
Serial.println("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
// ๊ฐ๋ ์๊ฐ
unsigned long hours = stats.uptime / 3600;
unsigned long minutes = (stats.uptime % 3600) / 60;
Serial.print("โฑ๏ธ ๊ฐ๋ ์๊ฐ: ");
Serial.print(hours);
Serial.print("์๊ฐ ");
Serial.print(minutes);
Serial.println("๋ถ");
// WiFi ํต๊ณ
Serial.print("๐ก WiFi ์ฌ์ฐ๊ฒฐ: ");
Serial.print(stats.wifiReconnects);
Serial.println("ํ");
// ์ผ์ ํต๊ณ
Serial.print("๐ก๏ธ ์ผ์ ์๋ฌ: ");
Serial.print(stats.sensorErrors);
Serial.println("ํ");
// ์ ์ก ํต๊ณ
Serial.print("๐ค ๋ฐ์ดํฐ ์ ์ก: ");
Serial.print(stats.dataTransmissions);
Serial.print("ํ (์คํจ: ");
Serial.print(stats.failedTransmissions);
Serial.println("ํ)");
float successRate = 100.0 * (stats.dataTransmissions - stats.failedTransmissions) /
max(stats.dataTransmissions, 1);
Serial.print("โ
์ฑ๊ณต๋ฅ : ");
Serial.print(successRate, 1);
Serial.println("%");
// ์ฑ๋ฅ ํต๊ณ
Serial.print("โก ํ๊ท ๋ฃจํ ์๊ฐ: ");
Serial.print(stats.avgLoopTime);
Serial.println("ms");
// ๋ฉ๋ชจ๋ฆฌ ํต๊ณ
Serial.print("๐พ ์ฌ์ ๋ฉ๋ชจ๋ฆฌ: ");
Serial.print(stats.freeHeap);
Serial.println(" bytes");
// ๋ฐฐํฐ๋ฆฌ ์ํ
Serial.print("๐ ๋ฐฐํฐ๋ฆฌ ์ ์: ");
Serial.print(batteryVoltage, 2);
Serial.println("V");
Serial.println("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n");
}
// ์์คํ
๊ฑด๊ฐ ์ฒดํฌ
bool isSystemHealthy() {
bool healthy = true;
// ๋ฉ๋ชจ๋ฆฌ ๋ถ์กฑ ์ฒดํฌ
if (stats.freeHeap < 10000) {
Serial.println("โ ๏ธ ๊ฒฝ๊ณ : ๋ฉ๋ชจ๋ฆฌ ๋ถ์กฑ!");
healthy = false;
}
// ์ผ์ ์๋ฌ์จ ์ฒดํฌ
if (stats.sensorErrors > 100) {
Serial.println("โ ๏ธ ๊ฒฝ๊ณ : ์ผ์ ์๋ฌ ๊ณผ๋ค!");
healthy = false;
}
// ์ ์ก ์คํจ์จ ์ฒดํฌ
float failRate = 100.0 * stats.failedTransmissions / max(stats.dataTransmissions, 1);
if (failRate > 50.0) {
Serial.println("โ ๏ธ ๊ฒฝ๊ณ : ๋ฐ์ดํฐ ์ ์ก ์คํจ์จ ๋์!");
healthy = false;
}
// ๋ฐฐํฐ๋ฆฌ ์ฒดํฌ
if (batteryVoltage < 3.3) {
Serial.println("๐ด ๊ฒฝ๊ณ : ๋ฐฐํฐ๋ฆฌ ์ํ ์์ค!");
healthy = false;
}
return healthy;
}
์ด๋ฐ ๋ชจ๋ํฐ๋ง ์์คํ
์ด ์์ผ๋ฉด ๋ฌธ์ ๋ฅผ ์กฐ๊ธฐ์ ๋ฐ๊ฒฌํ๊ณ ๋์ํ ์ ์์ด! ๐ฏ
๐ ์ค์ ํ๋ก์ ํธ: ์ค๋งํธ ํ๊ฒฝ ๋ชจ๋ํฐ๋ง ์์คํ
์, ์ด์ ์ง๊ธ๊น์ง ๋ฐฐ์ด ๋ชจ๋ ๊ฑธ ์ข ํฉํด์ ์์ ํ IoT ์์คํ ์ ๋ง๋ค์ด๋ณด์! ์ด๊ฑด ์ค์ ๋ก ์ฌ์ฉํ ์ ์๋ ์์ค์ ํ๋ก์ ํธ์ผ. ๐์์คํ
์ํคํ
์ฒ
์ฐ๋ฆฌ๊ฐ ๋ง๋ค ์์คํ
์ ์ด๋ฐ ๊ตฌ์กฐ์ผ:**ํ๋์จ์ด ๋ ์ด์ด**
โข ESP32 ๋ฉ์ธ ๋ณด๋
โข DHT22 ์จ์ต๋ ์ผ์
โข BH1750 ์กฐ๋ ์ผ์
โข MQ-135 ๊ณต๊ธฐ์ง ์ผ์
โข OLED ๋์คํ๋ ์ด
โข SD ์นด๋ ๋ชจ๋
โข ๋ฐฐํฐ๋ฆฌ + ์ถฉ์ ํ๋ก
**์ํํธ์จ์ด ๋ ์ด์ด**
โข ์ผ์ ๋ฐ์ดํฐ ์์ง ๋ชจ๋
โข ๋ฐ์ดํฐ ํํฐ๋ง ๋ฐ ์ฒ๋ฆฌ
โข ๋ก์ปฌ ์ ์ฅ (SD ์นด๋)
โข WiFi ํต์ (MQTT)
โข ์น ์๋ฒ (์ค์ ํ์ด์ง)
โข ์ ๋ ฅ ๊ด๋ฆฌ
โข ์๋ฌ ์ฒ๋ฆฌ
// ์์ ํ ์ค๋งํธ ํ๊ฒฝ ๋ชจ๋ํฐ๋ง ์์คํ
#include <WiFi.h>
#include <PubSubClient.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <DHT.h>
#include <BH1750.h>
#include <SD.h>
#include <ArduinoJson.h>
// ========== ํ ์ ์ ==========
#define DHT_PIN 4
#define DHT_TYPE DHT22
#define MQ135_PIN 34
#define SD_CS_PIN 5
#define BATTERY_PIN 35
// ========== ๋์คํ๋ ์ด ์ค์ ==========
#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 64
#define OLED_RESET -1
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// ========== ์ผ์ ๊ฐ์ฒด ==========
DHT dht(DHT_PIN, DHT_TYPE);
BH1750 lightMeter;
// ========== WiFi & MQTT ์ค์ ==========
const char* ssid = "YourWiFiSSID";
const char* password = "YourPassword";
const char* mqtt_server = "broker.hivemq.com";
const char* mqtt_topic = "smartenv/data";
WiFiClient espClient;
PubSubClient mqtt(espClient);
// ========== ๋ฐ์ดํฐ ๊ตฌ์กฐ์ฒด ==========
typedef struct {
float temperature;
float humidity;
float light;
int airQuality;
float batteryVoltage;
unsigned long timestamp;
bool valid;
} EnvironmentData;
EnvironmentData currentData;
EnvironmentData dataHistory[100];
int historyIndex = 0;
// ========== ์์คํ
์ํ ==========
typedef enum {
STATE_INIT,
STATE_NORMAL,
STATE_LOW_POWER,
STATE_ERROR
} SystemState;
SystemState systemState = STATE_INIT;
// ========== ํํฐ ==========
MovingAverage tempFilter;
MovingAverage humidFilter;
MovingAverage lightFilter;
// ========== ์ด๊ธฐํ ํจ์๋ค ==========
void setupDisplay() {
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
Serial.println("โ OLED ์ด๊ธฐํ ์คํจ!");
return;
}
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(SSD1306_WHITE);
display.setCursor(0, 0);
display.println("Smart Environment");
display.println("Monitor v1.0");
display.display();
delay(2000);
Serial.println("โ
๋์คํ๋ ์ด ์ด๊ธฐํ ์๋ฃ");
}
void setupSensors() {
// DHT22 ์ด๊ธฐํ
dht.begin();
Serial.println("โ
DHT22 ์ด๊ธฐํ");
// BH1750 ์ด๊ธฐํ
if (lightMeter.begin(BH1750::CONTINUOUS_HIGH_RES_MODE)) {
Serial.println("โ
BH1750 ์ด๊ธฐํ");
} else {
Serial.println("โ BH1750 ์ด๊ธฐํ ์คํจ");
}
// MQ-135 ํ ์ค์
pinMode(MQ135_PIN, INPUT);
Serial.println("โ
MQ-135 ์ด๊ธฐํ");
// ํํฐ ์ด๊ธฐํ
initMovingAverage(&tempFilter);
initMovingAverage(&humidFilter);
initMovingAverage(&lightFilter);
}
void setupSDCard() {
if (!SD.begin(SD_CS_PIN)) {
Serial.println("โ SD ์นด๋ ์ด๊ธฐํ ์คํจ");
return;
}
Serial.println("โ
SD ์นด๋ ์ด๊ธฐํ ์๋ฃ");
// ๋ก๊ทธ ํ์ผ ์์ฑ
File logFile = SD.open("/env_log.csv", FILE_WRITE);
if (logFile) {
logFile.println("Timestamp,Temp,Humid,Light,AirQuality,Battery");
logFile.close();
}
}
void setupWiFiAndMQTT() {
Serial.print("WiFi ์ฐ๊ฒฐ ์ค");
WiFi.begin(ssid, password);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 20) {
delay(500);
Serial.print(".");
attempts++;
}
if (WiFi.status() == WL_CONNECTED) {
Serial.println("\nโ
WiFi ์ฐ๊ฒฐ ์ฑ๊ณต!");
Serial.print("IP: ");
Serial.println(WiFi.localIP());
mqtt.setServer(mqtt_server, 1883);
connectMQTT();
} else {
Serial.println("\nโ WiFi ์ฐ๊ฒฐ ์คํจ");
}
}
void connectMQTT() {
while (!mqtt.connected()) {
Serial.print("MQTT ์ฐ๊ฒฐ ์๋...");
if (mqtt.connect("SmartEnvMonitor")) {
Serial.println("โ
์ฐ๊ฒฐ ์ฑ๊ณต!");
} else {
Serial.print("โ ์คํจ, rc=");
Serial.println(mqtt.state());
delay(5000);
}
}
}
// ========== ์ผ์ ์ฝ๊ธฐ ํจ์๋ค ==========
bool readAllSensors() {
currentData.timestamp = millis();
currentData.valid = true;
// ์จ์ต๋ ์ฝ๊ธฐ
float temp = dht.readTemperature();
float humid = dht.readHumidity();
if (isnan(temp) || isnan(humid)) {
Serial.println("โ DHT22 ์ฝ๊ธฐ ์คํจ");
currentData.valid = false;
return false;
}
// ํํฐ๋ง ์ ์ฉ
currentData.temperature = addValue(&tempFilter, temp);
currentData.humidity = addValue(&humidFilter, humid);
// ์กฐ๋ ์ฝ๊ธฐ
float lux = lightMeter.readLightLevel();
currentData.light = addValue(&lightFilter, lux);
// ๊ณต๊ธฐ์ง ์ฝ๊ธฐ (0-4095)
currentData.airQuality = analogRead(MQ135_PIN);
// ๋ฐฐํฐ๋ฆฌ ์ ์ ์ฝ๊ธฐ
int batteryADC = analogRead(BATTERY_PIN);
currentData.batteryVoltage = (batteryADC / 4095.0) * 3.3 * 2.0;
// ํ์คํ ๋ฆฌ์ ์ ์ฅ
dataHistory[historyIndex] = currentData;
historyIndex = (historyIndex + 1) % 100;
return true;
}
// ========== ๋์คํ๋ ์ด ์
๋ฐ์ดํธ ==========
void updateDisplay() {
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0, 0);
// ์จ๋
display.print("Temp: ");
display.print(currentData.temperature, 1);
display.println(" C");
// ์ต๋
display.print("Humid: ");
display.print(currentData.humidity, 1);
display.println(" %");
// ์กฐ๋
display.print("Light: ");
display.print(currentData.light, 0);
display.println(" lux");
// ๊ณต๊ธฐ์ง
display.print("Air: ");
if (currentData.airQuality < 1000) {
display.println("Good");
} else if (currentData.airQuality < 2000) {
display.println("Moderate");
} else {
display.println("Poor");
}
// ๋ฐฐํฐ๋ฆฌ
display.print("Batt: ");
display.print(currentData.batteryVoltage, 2);
display.println("V");
// WiFi ์ํ
if (WiFi.status() == WL_CONNECTED) {
display.println("WiFi: OK");
} else {
display.println("WiFi: --");
}
display.display();
}
// ========== ๋ฐ์ดํฐ ์ ์ฅ ==========
void saveToSD() {
File logFile = SD.open("/env_log.csv", FILE_APPEND);
if (logFile) {
logFile.print(currentData.timestamp);
logFile.print(",");
logFile.print(currentData.temperature);
logFile.print(",");
logFile.print(currentData.humidity);
logFile.print(",");
logFile.print(currentData.light);
logFile.print(",");
logFile.print(currentData.airQuality);
logFile.print(",");
logFile.println(currentData.batteryVoltage);
logFile.close();
Serial.println("๐พ SD ์ ์ฅ ์๋ฃ");
}
}
// ========== MQTT ์ ์ก ==========
void publishToMQTT() {
if (!mqtt.connected()) {
connectMQTT();
}
// JSON ์์ฑ
StaticJsonDocument<256> doc;
doc["temperature"] = currentData.temperature;
doc["humidity"] = currentData.humidity;
doc["light"] = currentData.light;
doc["airQuality"] = currentData.airQuality;
doc["battery"] = currentData.batteryVoltage;
doc["timestamp"] = currentData.timestamp;
char jsonBuffer[256];
serializeJson(doc, jsonBuffer);
if (mqtt.publish(mqtt_topic, jsonBuffer)) {
Serial.println("๐ค MQTT ์ ์ก ์๋ฃ");
} else {
Serial.println("โ MQTT ์ ์ก ์คํจ");
}
}
// ========== ๊ฒฝ๊ณ ์์คํ
==========
void checkAlerts() {
bool alert = false;
if (currentData.temperature > 35.0) {
Serial.println("๐ด ๊ฒฝ๊ณ : ๊ณ ์จ!");
alert = true;
}
if (currentData.humidity > 80.0) {
Serial.println("๐ฆ ๊ฒฝ๊ณ : ๊ณ ์ต๋!");
alert = true;
}
if (currentData.airQuality > 2000) {
Serial.println("๐ท ๊ฒฝ๊ณ : ๊ณต๊ธฐ์ง ๋์จ!");
alert = true;
}
if (currentData.batteryVoltage < 3.5) {
Serial.println("๐ ๊ฒฝ๊ณ : ๋ฐฐํฐ๋ฆฌ ๋ถ์กฑ!");
alert = true;
}
if (alert) {
// ๊ธด๊ธ ์๋ฆผ ์ ์ก
mqtt.publish("smartenv/alerts", "ALERT");
}
}
// ========== ๋ฉ์ธ ํจ์๋ค ==========
void setup() {
Serial.begin(115200);
Serial.println("\n๐ ์ค๋งํธ ํ๊ฒฝ ๋ชจ๋ํฐ๋ง ์์คํ
์์!");
Serial.println("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
// ์ด๊ธฐํ
setupDisplay();
setupSensors();
setupSDCard();
setupWiFiAndMQTT();
systemState = STATE_NORMAL;
Serial.println("โ
๋ชจ๋ ์ด๊ธฐํ ์๋ฃ!");
}
void loop() {
static unsigned long lastSensorRead = 0;
static unsigned long lastMQTTPublish = 0;
static unsigned long lastSDSave = 0;
static unsigned long lastDisplayUpdate = 0;
unsigned long currentTime = millis();
// ์ผ์ ์ฝ๊ธฐ (10์ด๋ง๋ค)
if (currentTime - lastSensorRead >= 10000) {
lastSensorRead = currentTime;
if (readAllSensors()) {
checkAlerts();
}
}
// ๋์คํ๋ ์ด ์
๋ฐ์ดํธ (2์ด๋ง๋ค)
if (currentTime - lastDisplayUpdate >= 2000) {
lastDisplayUpdate = currentTime;
updateDisplay();
}
// SD ์นด๋ ์ ์ฅ (1๋ถ๋ง๋ค)
if (currentTime - lastSDSave >= 60000) {
lastSDSave = currentTime;
saveToSD();
}
// MQTT ์ ์ก (30์ด๋ง๋ค)
if (currentTime - lastMQTTPublish >= 30000) {
lastMQTTPublish = currentTime;
if (WiFi.status() == WL_CONNECTED) {
publishToMQTT();
}
}
// MQTT ๋ฃจํ
mqtt.loop();
delay(100);
}
์! ์ ๋ง ์์ ํ ์์คํ
์ด์ง? ์ด ์ฝ๋๋ ์ค์ ๋ก ๋์ํ๋ ํ๋ก๋์
์์ค์ IoT ์์คํ
์ด์ผ! ๐
๐ ํ์ต ํ
์ด๋ฐ ๋ณต์กํ ํ๋ก์ ํธ๋ฅผ ์ฒ์๋ถํฐ ์๋ฒฝํ๊ฒ ๋ง๋ค๋ ค๊ณ ํ์ง ๋ง! ์์ ๋ถ๋ถ๋ถํฐ ์์ํด์ ํ๋์ฉ ์ถ๊ฐํด๊ฐ๋ ๊ฒ ์ข์. ์ฌ๋ฅ๋ท์์ IoT ํ๋ก์ ํธ ๊ฒฝํ์๋ค์ ์กฐ์ธ์ ๋ฐ์ผ๋ฉด ํจ์ฌ ๋น ๋ฅด๊ฒ ๋ฐฐ์ธ ์ ์์ด!
์ด๋ฐ ๋ณต์กํ ํ๋ก์ ํธ๋ฅผ ์ฒ์๋ถํฐ ์๋ฒฝํ๊ฒ ๋ง๋ค๋ ค๊ณ ํ์ง ๋ง! ์์ ๋ถ๋ถ๋ถํฐ ์์ํด์ ํ๋์ฉ ์ถ๊ฐํด๊ฐ๋ ๊ฒ ์ข์. ์ฌ๋ฅ๋ท์์ IoT ํ๋ก์ ํธ ๊ฒฝํ์๋ค์ ์กฐ์ธ์ ๋ฐ์ผ๋ฉด ํจ์ฌ ๋น ๋ฅด๊ฒ ๋ฐฐ์ธ ์ ์์ด!
๐ ๋ฐ์ดํฐ ๋ถ์ ๋ฐ ์๊ฐํ
์ผ์ ๋ฐ์ดํฐ๋ฅผ ์์งํ์ผ๋ฉด ์ด์ ๋ถ์ํด์ผ๊ฒ ์ง? ๊ฐ๋จํ ํต๊ณ ๋ถ์๋ถํฐ ์์ํด๋ณด์! ๐๊ธฐ๋ณธ ํต๊ณ ๋ถ์
typedef struct {
float min;
float max;
float mean;
float stdDev;
float median;
} Statistics;
Statistics calculateStatistics(float* data, int count) {
Statistics stats = {0};
if (count == 0) return stats;
// ์ต์/์ต๋/ํฉ๊ณ
stats.min = data[0];
stats.max = data[0];
float sum = 0.0;
for (int i = 0; i < count; i++) {
if (data[i] < stats.min) stats.min = data[i];
if (data[i] > stats.max) stats.max = data[i];
sum += data[i];
}
// ํ๊ท
stats.mean = sum / count;
// ํ์คํธ์ฐจ
float sumSquares = 0.0;
for (int i = 0; i < count; i++) {
float diff = data[i] - stats.mean;
sumSquares += diff * diff;
}
stats.stdDev = sqrt(sumSquares / count);
// ์ค๊ฐ๊ฐ (์ ๋ ฌ ํ์)
float sorted[count];
memcpy(sorted, data, count * sizeof(float));
// ๊ฐ๋จํ ๋ฒ๋ธ ์ ๋ ฌ
for (int i = 0; i < count - 1; i++) {
for (int j = 0; j < count - i - 1; j++) {
if (sorted[j] > sorted[j + 1]) {
float temp = sorted[j];
sorted[j] = sorted[j + 1];
sorted[j + 1] = temp;
}
}
}
if (count % 2 == 0) {
stats.median = (sorted[count/2 - 1] + sorted[count/2]) / 2.0;
} else {
stats.median = sorted[count/2];
}
return stats;
}
void analyzeTemperatureData() {
float tempData[100];
// ํ์คํ ๋ฆฌ์์ ์จ๋ ๋ฐ์ดํฐ ์ถ์ถ
for (int i = 0; i < 100; i++) {
tempData[i] = dataHistory[i].temperature;
}
Statistics stats = calculateStatistics(tempData, 100);
Serial.println("\n๐ ์จ๋ ํต๊ณ ๋ถ์ (์ต๊ทผ 100๊ฐ ๋ฐ์ดํฐ)");
Serial.println("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
Serial.print("์ต์๊ฐ: ");
Serial.print(stats.min, 2);
Serial.println("ยฐC");
Serial.print("์ต๋๊ฐ: ");
Serial.print(stats.max, 2);
Serial.println("ยฐC");
Serial.print("ํ๊ท : ");
Serial.print(stats.mean, 2);
Serial.println("ยฐC");
Serial.print("ํ์คํธ์ฐจ: ");
Serial.print(stats.stdDev, 2);
Serial.println("ยฐC");
Serial.print("์ค๊ฐ๊ฐ: ");
Serial.print(stats.median, 2);
Serial.println("ยฐC");
Serial.println("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ\n");
}
์๊ด๊ด๊ณ ๋ถ์
์จ๋์ ์ต๋์ ์๊ด๊ด๊ณ๋ฅผ ๋ถ์ํด๋ณด์:
float calculateCorrelation(float* x, float* y, int count) {
if (count < 2) return 0.0;
// ํ๊ท ๊ณ์ฐ
float meanX = 0.0, meanY = 0.0;
for (int i = 0; i < count; i++) {
meanX += x[i];
meanY += y[i];
}
meanX /= count;
meanY /= count;
// ๊ณต๋ถ์ฐ๊ณผ ํ์คํธ์ฐจ ๊ณ์ฐ
float covariance = 0.0;
float stdX = 0.0, stdY = 0.0;
for (int i = 0; i < count; i++) {
float diffX = x[i] - meanX;
float diffY = y[i] - meanY;
covariance += diffX * diffY;
stdX += diffX * diffX;
stdY += diffY * diffY;
}
stdX = sqrt(stdX / count);
stdY = sqrt(stdY / count);
if (stdX == 0.0 || stdY == 0.0) return 0.0;
return covariance / (count * stdX * stdY);
}
void analyzeCorrelations() {
float tempData[100], humidData[100], lightData[100];
for (int i = 0; i < 100; i++) {
tempData[i] = dataHistory[i].temperature;
humidData[i] = dataHistory[i].humidity;
lightData[i] = dataHistory[i].light;
}
float tempHumidCorr = calculateCorrelation(tempData, humidData, 100);
float tempLightCorr = calculateCorrelation(tempData, lightData, 100);
float humidLightCorr = calculateCorrelation(humidData, lightData, 100);
Serial.println("\n๐ ์๊ด๊ด๊ณ ๋ถ์");
Serial.println("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
Serial.print("์จ๋ โ ์ต๋: ");
Serial.println(tempHumidCorr, 3);
Serial.print("์จ๋ โ ์กฐ๋: ");
Serial.println(tempLightCorr, 3);
Serial.print("์ต๋ โ ์กฐ๋: ");
Serial.println(humidLightCorr, 3);
Serial.println("โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ");
Serial.println("(1์ ๊ฐ๊น์ธ์๋ก ๊ฐํ ์์ ์๊ด๊ด๊ณ)");
Serial.println("(-1์ ๊ฐ๊น์ธ์๋ก ๊ฐํ ์์ ์๊ด๊ด๊ณ)\n");
}
์ด๋ฐ ๋ถ์์ ํตํด ์ผ์ ๋ฐ์ดํฐ ๊ฐ์ ๊ด๊ณ๋ฅผ ์ดํดํ ์ ์์ด! ์๋ฅผ ๋ค์ด ์จ๋๊ฐ ์ฌ๋ผ๊ฐ๋ฉด ์ต๋๊ฐ ๋ด๋ ค๊ฐ๋ ๊ฒฝํฅ์ด ์๋ค๋ ์ง ํ๋ ํจํด์ ๋ฐ๊ฒฌํ ์ ์์ง. ๐
๐ฏ ๋ง๋ฌด๋ฆฌํ๋ฉฐ
์! ์ ๋ง ๊ธด ์ฌ์ ์ด์์ง? ์ฐ๋ฆฌ๋ C์ธ์ด๋ฅผ ์ฌ์ฉํด์ ์์ ํ IoT ์ผ์ ๋ฐ์ดํฐ ์์ง ๋ฐ ์ฒ๋ฆฌ ์์คํ ์ ๋ง๋ค์ด๋ดค์ด. ๊ธฐ๋ณธ์ ์ธ ์ผ์ ์ฝ๊ธฐ๋ถํฐ ์์ํด์ ๋ฐ์ดํฐ ํํฐ๋ง, ํต์ , ์ ์ฅ, ์ ๋ ฅ ๊ด๋ฆฌ, ์๋ฌ ์ฒ๋ฆฌ, ๊ทธ๋ฆฌ๊ณ ๋ฐ์ดํฐ ๋ถ์๊น์ง ๋ชจ๋ ๊ฑธ ๋ค๋ค์ด! ๐์ด์ ๋๋ ์ค์ IoT ํ๋ก์ ํธ๋ฅผ ๋ง๋ค ์ ์๋ ์ค๋ ฅ์ ๊ฐ์ท์ด. ๋ฌผ๋ก ์ฒ์๋ถํฐ ์๋ฒฝํ ์ ์์ด. ํ์ง๋ง ์ด ๊ธ์์ ๋ฐฐ์ด ๊ฐ๋ ๋ค์ ํ๋์ฉ ์ ์ฉํด๊ฐ๋ฉด์ ์ ์ ๋ ๋์ ์์คํ ์ ๋ง๋ค ์ ์์ ๊ฑฐ์ผ! ๐ช
๐ ๋ค์ ๋จ๊ณ๋ก ๋์๊ฐ๊ธฐ
1๋จ๊ณ: ๊ฐ๋จํ ์ผ์ ํ๋๋ก ์์ํด์ ๋ฐ์ดํฐ ์ฝ๊ธฐ ๋ง์คํฐํ๊ธฐ
2๋จ๊ณ: ์ฌ๋ฌ ์ผ์๋ฅผ ํตํฉํ๊ณ ํํฐ๋ง ์ ์ฉํ๊ธฐ
3๋จ๊ณ: WiFi ํต์ ์ถ๊ฐํ๊ณ ํด๋ผ์ฐ๋์ ๋ฐ์ดํฐ ์ ์กํ๊ธฐ
4๋จ๊ณ: ์ ๋ ฅ ๊ด๋ฆฌ์ ์๋ฌ ์ฒ๋ฆฌ๋ก ์์คํ ์์ ํํ๊ธฐ
5๋จ๊ณ: ๋ฐ์ดํฐ ๋ถ์๊ณผ ๋จธ์ ๋ฌ๋์ผ๋ก ์ค๋งํธํ ์์คํ ๋ง๋ค๊ธฐ
ํผ์์ ๋งํ๋ ๋ถ๋ถ์ด ์๋ค๋ฉด ์ฌ๋ฅ๋ท์์ IoT ์ ๋ฌธ๊ฐ๋ค์ ๋์์ ๋ฐ์๋ณด๋ ๊ฒ๋ ์ข์ ๋ฐฉ๋ฒ์ด์ผ. ์ค์ ๊ฒฝํ์ด ํ๋ถํ ๊ฐ๋ฐ์๋ค์ ์กฐ์ธ์ ์ ๋ง ๊ฐ์ง ์์ฐ์ด ๋ ๊ฑฐ์ผ! ๐1๋จ๊ณ: ๊ฐ๋จํ ์ผ์ ํ๋๋ก ์์ํด์ ๋ฐ์ดํฐ ์ฝ๊ธฐ ๋ง์คํฐํ๊ธฐ
2๋จ๊ณ: ์ฌ๋ฌ ์ผ์๋ฅผ ํตํฉํ๊ณ ํํฐ๋ง ์ ์ฉํ๊ธฐ
3๋จ๊ณ: WiFi ํต์ ์ถ๊ฐํ๊ณ ํด๋ผ์ฐ๋์ ๋ฐ์ดํฐ ์ ์กํ๊ธฐ
4๋จ๊ณ: ์ ๋ ฅ ๊ด๋ฆฌ์ ์๋ฌ ์ฒ๋ฆฌ๋ก ์์คํ ์์ ํํ๊ธฐ
5๋จ๊ณ: ๋ฐ์ดํฐ ๋ถ์๊ณผ ๋จธ์ ๋ฌ๋์ผ๋ก ์ค๋งํธํ ์์คํ ๋ง๋ค๊ธฐ
IoT๋ ์ ๋ง ์ฌ๋ฏธ์๊ณ ๋ฌดํํ ๊ฐ๋ฅ์ฑ์ ๊ฐ์ง ๋ถ์ผ์ผ. ์ค๋งํธํ, ๋์ , ์๋ฃ, ์ฐ์ ์๋ํ ๋ฑ ๋ชจ๋ ๊ณณ์์ IoT ๊ธฐ์ ์ด ํ์ํด. ๋์ ์ฐฝ์๋ ฅ๊ณผ C์ธ์ด ์ค๋ ฅ์ ๊ฒฐํฉํ๋ฉด ์ ๋ง ๋ฉ์ง ํ๋ก์ ํธ๋ฅผ ๋ง๋ค ์ ์์ ๊ฑฐ์ผ! ๐จ
์, ์ด์ ์ง์ ์ผ์๋ฅผ ์ฐ๊ฒฐํ๊ณ ์ฝ๋๋ฅผ ์์ฑํด๋ณด์! ์คํจ๋ฅผ ๋๋ ค์ํ์ง ๋ง๊ณ , ํ๋์ฉ ์๋ํด๋ณด๋ฉด์ ๋ฐฐ์๊ฐ๋ ๊ฑฐ์ผ. ๊ทธ๊ฒ ๋ฐ๋ก ์ง์ง ๊ฐ๋ฐ์๊ฐ ๋๋ ๊ธธ์ด๋๊น! ๐
ํ์ด์ ๋น์ด! ๊ทธ๋ฆฌ๊ณ ๋ฉ์ง IoT ํ๋ก์ ํธ๋ฅผ ๋ง๋ค๋ฉด ๊ผญ ์๋ํด์ค! ๐โจ
๊ด๋ จ ํค์๋
๋๊ธ 0
์ง์์ธ์ ์ฒ - ์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
์ง์ ์ฌ์ฐ๊ถ ๋ณดํธ ๊ณ ์ง
- ์ ์๊ถ ๋ฐ ์์ ๊ถ: ๋ณธ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ๋ ์ AI ๊ธฐ์ ๋ก ์์ฑ๋์์ผ๋ฉฐ, ๋ํ๋ฏผ๊ตญ ์ ์๊ถ๋ฒ ๋ฐ ๊ตญ์ ์ ์๊ถ ํ์ฝ์ ์ํด ๋ณดํธ๋ฉ๋๋ค.
- AI ์์ฑ ์ปจํ ์ธ ์ ๋ฒ์ ์ง์: ๋ณธ AI ์์ฑ ์ปจํ ์ธ ๋ ์ฌ๋ฅ๋ท์ ์ง์ ์ฐฝ์๋ฌผ๋ก ์ธ์ ๋๋ฉฐ, ๊ด๋ จ ๋ฒ๊ท์ ๋ฐ๋ผ ์ ์๊ถ ๋ณดํธ๋ฅผ ๋ฐ์ต๋๋ค.
- ์ฌ์ฉ ์ ํ: ์ฌ๋ฅ๋ท์ ๋ช ์์ ์๋ฉด ๋์ ์์ด ๋ณธ ์ปจํ ์ธ ๋ฅผ ๋ณต์ , ์์ , ๋ฐฐํฌ, ๋๋ ์์ ์ ์ผ๋ก ํ์ฉํ๋ ํ์๋ ์๊ฒฉํ ๊ธ์ง๋ฉ๋๋ค.
- ๋ฐ์ดํฐ ์์ง ๊ธ์ง: ๋ณธ ์ปจํ ์ธ ์ ๋ํ ๋ฌด๋จ ์คํฌ๋ํ, ํฌ๋กค๋ง, ๋ฐ ์๋ํ๋ ๋ฐ์ดํฐ ์์ง์ ๋ฒ์ ์ ์ฌ์ ๋์์ด ๋ฉ๋๋ค.
- AI ํ์ต ์ ํ: ์ฌ๋ฅ๋ท์ AI ์์ฑ ์ปจํ ์ธ ๋ฅผ ํ AI ๋ชจ๋ธ ํ์ต์ ๋ฌด๋จ ์ฌ์ฉํ๋ ํ์๋ ๊ธ์ง๋๋ฉฐ, ์ด๋ ์ง์ ์ฌ์ฐ๊ถ ์นจํด๋ก ๊ฐ์ฃผ๋ฉ๋๋ค.

๋๊ธ ์์ฑ
์ด ๊ธ์ ๋ํ ์ฌ๋ฌ๋ถ์ ์๊ฐ์ ๋ค๋ ค์ฃผ์ธ์
๋ก๊ทธ์ธ์ด ํ์ํฉ๋๋ค
๋๊ธ์ ์์ฑํ๋ ค๋ฉด ๋จผ์ ๋ก๊ทธ์ธํด์ฃผ์ธ์.