/*
* Avicore IoT - Bộ điều khiển ổ ấp thông minh
* Phiên bản: 1.0.0
* License: MIT Open Source
*/
#include <WiFi.h>
#include <DHT.h>
#include <BH1750.h>
#include <Wire.h>
// ============ CẤU HÌNH PIN ============
#define DHT_PIN 4 // Cảm biến nhiệt độ/ẩm
#define HEATER_PIN 16 // Relay đèn sưởi
#define FAN_PIN 17 // Relay quạt thông gió
#define MIST_PIN 18 // Relay phun sương
#define LED_STATUS 2 // LED trạng thái
// ============ NGƯỠNG THAM SỐ ============
struct IncubatorParams {
float tempMin = 37.5; // Nhiệt độ tối thiểu (°C)
float tempMax = 38.5; // Nhiệt độ tối đa (°C)
float humidMin = 55.0; // Độ ẩm tối thiểu (%)
float humidMax = 65.0; // Độ ẩm tối đa (%)
int lightMin = 50; // Ánh sáng tối thiểu (lux)
int lightMax = 200; // Ánh sáng tối đa (lux)
};
IncubatorParams params;
DHT dht(DHT_PIN, DHT22);
BH1750 lightMeter;
// ============ BIẾN TOÀN CỤC ============
float currentTemp = 0;
float currentHumid = 0;
uint16_t currentLight = 0;
void setup() {
Serial.begin(115200);
Serial.println("🐣 Avicore IoT - Khởi động...");
// Khởi tạo pin
pinMode(HEATER_PIN, OUTPUT);
pinMode(FAN_PIN, OUTPUT);
pinMode(MIST_PIN, OUTPUT);
pinMode(LED_STATUS, OUTPUT);
// Khởi tạo cảm biến
dht.begin();
Wire.begin();
lightMeter.begin();
// Kết nối WiFi
connectWiFi();
Serial.println("✅ Hệ thống sẵn sàng!");
}
void loop() {
// Đọc cảm biến
readSensors();
// Điều khiển tự động
autoControl();
// Gửi dữ liệu lên server
sendData();
// Nhấp nháy LED trạng thái
blinkStatus();
delay(5000); // Cập nhật mỗi 5 giây
}
void readSensors() {
currentTemp = dht.readTemperature();
currentHumid = dht.readHumidity();
currentLight = lightMeter.readLightLevel();
Serial.printf("📊 Nhiệt: %.1f°C | Ẩm: %.1f%% | Sáng: %d lux\n",
currentTemp, currentHumid, currentLight);
}
void autoControl() {
// === ĐIỀU KHIỂN NHIỆT ĐỘ ===
if (currentTemp < params.tempMin) {
digitalWrite(HEATER_PIN, HIGH); // Bật đèn sưởi
digitalWrite(FAN_PIN, LOW);
Serial.println("🔥 Bật sưởi - Nhiệt độ thấp");
}
else if (currentTemp > params.tempMax) {
digitalWrite(HEATER_PIN, LOW);
digitalWrite(FAN_PIN, HIGH); // Bật quạt làm mát
Serial.println("❄️ Bật quạt - Nhiệt độ cao");
}
else {
digitalWrite(HEATER_PIN, LOW);
digitalWrite(FAN_PIN, LOW);
}
// === ĐIỀU KHIỂN ĐỘ ẨM ===
if (currentHumid < params.humidMin) {
digitalWrite(MIST_PIN, HIGH); // Bật phun sương
Serial.println("💧 Bật phun sương - Độ ẩm thấp");
}
else if (currentHumid > params.humidMax) {
digitalWrite(MIST_PIN, LOW);
digitalWrite(FAN_PIN, HIGH); // Thông gió giảm ẩm
}
else {
digitalWrite(MIST_PIN, LOW);
}
}
void connectWiFi() {
const char* ssid = "YOUR_WIFI_SSID";
const char* password = "YOUR_WIFI_PASSWORD";
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.printf("\n📶 Đã kết nối WiFi: %s\n", WiFi.localIP().toString().c_str());
}
void sendData() {
// Gửi dữ liệu lên server qua HTTP/MQTT
// Xem phần Python Server để biết chi tiết
}
void blinkStatus() {
digitalWrite(LED_STATUS, !digitalRead(LED_STATUS));
}
"""
Avicore IoT - Server giám sát đa ổ ấp
Phiên bản: 1.0.0
License: MIT Open Source
"""
from flask import Flask, jsonify, request
from datetime import datetime
import sqlite3
import json
app = Flask(__name__)
# ============ CẤU HÌNH ============
class IncubatorConfig:
"""Cấu hình ngưỡng cho từng ổ ấp"""
DEFAULT_PARAMS = {
'temp_min': 37.5,
'temp_max': 38.5,
'humid_min': 55.0,
'humid_max': 65.0,
'light_min': 50,
'light_max': 200
}
# Cấu hình theo giai đoạn ấp (ngày)
PHASE_PARAMS = {
'phase_1': { # Ngày 1-7
'temp_min': 38.0, 'temp_max': 38.5,
'humid_min': 55, 'humid_max': 60
},
'phase_2': { # Ngày 8-18
'temp_min': 37.5, 'temp_max': 38.0,
'humid_min': 50, 'humid_max': 55
},
'phase_3': { # Ngày 19-21 (nở)
'temp_min': 37.0, 'temp_max': 37.5,
'humid_min': 65, 'humid_max': 75
}
}
# ============ DATABASE ============
def init_db():
"""Khởi tạo cơ sở dữ liệu SQLite"""
conn = sqlite3.connect('avicore.db')
c = conn.cursor()
# Bảng ổ ấp
c.execute('''
CREATE TABLE IF NOT EXISTS incubators (
id TEXT PRIMARY KEY,
name TEXT,
start_date TEXT,
egg_count INTEGER,
status TEXT DEFAULT 'active'
)
''')
# Bảng dữ liệu cảm biến
c.execute('''
CREATE TABLE IF NOT EXISTS sensor_data (
id INTEGER PRIMARY KEY AUTOINCREMENT,
incubator_id TEXT,
temperature REAL,
humidity REAL,
light INTEGER,
timestamp TEXT,
FOREIGN KEY (incubator_id) REFERENCES incubators(id)
)
''')
# Bảng cảnh báo
c.execute('''
CREATE TABLE IF NOT EXISTS alerts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
incubator_id TEXT,
alert_type TEXT,
message TEXT,
timestamp TEXT,
resolved INTEGER DEFAULT 0
)
''')
conn.commit()
conn.close()
# ============ API ENDPOINTS ============
@app.route('/api/incubators', methods=['GET'])
def get_incubators():
"""Lấy danh sách tất cả ổ ấp"""
conn = sqlite3.connect('avicore.db')
c = conn.cursor()
c.execute('SELECT * FROM incubators WHERE status = "active"')
incubators = c.fetchall()
conn.close()
return jsonify({
'success': True,
'data': [
{
'id': i[0], 'name': i[1],
'start_date': i[2], 'egg_count': i[3]
} for i in incubators
]
})
@app.route('/api/incubator//data', methods=['POST'])
def receive_sensor_data(incubator_id):
"""Nhận dữ liệu từ cảm biến ESP32"""
data = request.json
conn = sqlite3.connect('avicore.db')
c = conn.cursor()
# Lưu dữ liệu
c.execute('''
INSERT INTO sensor_data
(incubator_id, temperature, humidity, light, timestamp)
VALUES (?, ?, ?, ?, ?)
''', (
incubator_id,
data['temperature'],
data['humidity'],
data['light'],
datetime.now().isoformat()
))
# Kiểm tra cảnh báo
check_alerts(c, incubator_id, data)
conn.commit()
conn.close()
return jsonify({'success': True, 'message': 'Data received'})
def check_alerts(cursor, incubator_id, data):
"""Kiểm tra và tạo cảnh báo nếu vượt ngưỡng"""
config = IncubatorConfig.DEFAULT_PARAMS
alerts = []
if data['temperature'] < config['temp_min']:
alerts.append(('temp_low', f"⚠️ Nhiệt độ thấp: {data['temperature']}°C"))
elif data['temperature'] > config['temp_max']:
alerts.append(('temp_high', f"🔥 Nhiệt độ cao: {data['temperature']}°C"))
if data['humidity'] < config['humid_min']:
alerts.append(('humid_low', f"💧 Độ ẩm thấp: {data['humidity']}%"))
elif data['humidity'] > config['humid_max']:
alerts.append(('humid_high', f"💦 Độ ẩm cao: {data['humidity']}%"))
for alert_type, message in alerts:
cursor.execute('''
INSERT INTO alerts (incubator_id, alert_type, message, timestamp)
VALUES (?, ?, ?, ?)
''', (incubator_id, alert_type, message, datetime.now().isoformat()))
@app.route('/api/incubator//stats', methods=['GET'])
def get_stats(incubator_id):
"""Lấy thống kê 24h gần nhất"""
conn = sqlite3.connect('avicore.db')
c = conn.cursor()
c.execute('''
SELECT
AVG(temperature) as avg_temp,
MIN(temperature) as min_temp,
MAX(temperature) as max_temp,
AVG(humidity) as avg_humid,
COUNT(*) as readings
FROM sensor_data
WHERE incubator_id = ?
AND timestamp > datetime('now', '-24 hours')
''', (incubator_id,))
stats = c.fetchone()
conn.close()
return jsonify({
'success': True,
'data': {
'avg_temp': round(stats[0], 1) if stats[0] else 0,
'min_temp': round(stats[1], 1) if stats[1] else 0,
'max_temp': round(stats[2], 1) if stats[2] else 0,
'avg_humid': round(stats[3], 1) if stats[3] else 0,
'readings': stats[4]
}
})
# ============ MAIN ============
if __name__ == '__main__':
init_db()
print("🐣 Avicore Server đang chạy...")
app.run(host='0.0.0.0', port=5000, debug=True)
{
"avicore_config": {
"version": "1.0.0",
"description": "Cấu hình hệ thống Avicore IoT",
"incubator_defaults": {
"temperature": {
"unit": "celsius",
"min": 37.5,
"max": 38.5,
"critical_low": 35.0,
"critical_high": 40.0
},
"humidity": {
"unit": "percent",
"min": 55,
"max": 65,
"critical_low": 40,
"critical_high": 80
},
"light": {
"unit": "lux",
"min": 50,
"max": 200,
"night_mode": true,
"night_start": "20:00",
"night_end": "06:00"
}
},
"incubation_phases": {
"phase_1": {
"name": "Giai đoạn phát triển phôi",
"days": [1, 7],
"temp_range": [38.0, 38.5],
"humid_range": [55, 60],
"turning_interval_hours": 4,
"notes": "Quan trọng nhất, duy trì nhiệt độ ổn định"
},
"phase_2": {
"name": "Giai đoạn phát triển cơ thể",
"days": [8, 18],
"temp_range": [37.5, 38.0],
"humid_range": [50, 55],
"turning_interval_hours": 6,
"notes": "Giảm nhẹ nhiệt độ, tăng thông gió"
},
"phase_3": {
"name": "Giai đoạn nở",
"days": [19, 21],
"temp_range": [37.0, 37.5],
"humid_range": [65, 75],
"turning_interval_hours": 0,
"notes": "KHÔNG xoay trứng, tăng độ ẩm cho gà nở"
}
},
"protection_layers": {
"layer_1_thermal": {
"name": "Vành đai nhiệt",
"temp_target": 38,
"radius_cm": 30,
"hardware": "Đèn sưởi 45W hoặc dây nhiệt"
},
"layer_2_oil": {
"name": "Hồ dầu",
"type": "Dầu thực vật",
"width_cm": 3,
"depth_cm": 1,
"refill_days": 7
},
"layer_3_lime": {
"name": "Vôi bột",
"quantity_grams": 200,
"width_cm": 5,
"replace_days": 14
},
"layer_4_inorganic": {
"name": "Vật liệu vô cơ",
"type": ["Cát", "Sỏi nhỏ"],
"thickness_cm": 8
},
"layer_5_tobacco": {
"name": "Sợi lá thuốc",
"quantity_grams": 80,
"replace_days": 14,
"notes": "Xua đuổi ve, rận tự nhiên"
},
"layer_6_iot": {
"name": "Hệ thống IoT",
"sensors": ["DHT22", "BH1750"],
"controller": "ESP32",
"update_interval_seconds": 5
}
},
"alerts": {
"channels": ["app", "sms", "email"],
"priority_levels": {
"critical": {
"conditions": ["temp < 35", "temp > 40", "humid < 40"],
"notify_immediately": true
},
"warning": {
"conditions": ["temp_outside_range", "humid_outside_range"],
"notify_after_minutes": 5
},
"info": {
"conditions": ["sensor_offline", "low_battery"],
"notify_after_minutes": 30
}
}
},
"3s_philosophy": {
"s1_feeding": {
"name": "Ăn tự chọn",
"food_types": [
"Ngũ cốc hỗn hợp",
"Côn trùng (giun, dế)",
"Rau xanh tươi",
"Vỏ sò nghiền (canxi)"
],
"always_available": true
},
"s2_sleeping": {
"name": "Ngủ tự do",
"options": [
"Tự chọn cành cây bưởi ở các độ cao",
"Ổ rơm ấm",
"Góc tối yên tĩnh"
],
"no_forced_schedule": true
},
"s3_spa": {
"name": "Spa tự phục vụ",
"facilities": [
"Bể tắm cát/tro",
"Khu phơi nắng",
"Đá mài mỏ"
],
"benefits": ["Diệt ký sinh", "Vitamin D", "Lông mượt"]
}
}
}
}