跳到主要内容

智能家居项目

本文将通过一个完整的智能家居项目,演示如何从零搭建物联网系统,涵盖硬件选型、软件开发、云端部署等完整流程。

项目概述

项目目标

搭建一个完整的智能家居系统,实现以下功能:

  • 温湿度监测
  • 智能照明控制
  • 门窗状态检测
  • 远程控制与自动化
  • 数据可视化

系统架构

┌─────────────────────────────────────────────────────────┐
│ 用户层 │
│ 手机 App │ Web 控制台 │ 语音助手 │
├─────────────────────────────────────────────────────────┤
│ 云平台 │
│ 设备管理 │ 数据存储 │ 规则引擎 │ 场景联动 │
├─────────────────────────────────────────────────────────┤
│ 网关层 │
│ 智能网关(ESP32/树莓派) │
├─────────────────────────────────────────────────────────┤
│ 设备层 │
│ 温湿度传感器 │ 智能灯 │ 门窗传感器 │ 智能插座 │
└─────────────────────────────────────────────────────────┘

硬件准备

设备清单

设备型号数量功能
主控板ESP32 DevKit1智能网关
温湿度传感器DHT222环境监测
继电器模块5V 继电器2灯光控制
门窗传感器干簧管2门窗检测
LED 灯带WS2812B1智能照明
电源5V 2A1供电

接线图

ESP32 引脚分配:
┌─────────────────────────────────────┐
│ GPIO 4 ─── DHT22 数据线 │
│ GPIO 5 ─── 继电器 1 │
│ GPIO 18 ─── 继电器 2 │
│ GPIO 19 ─── 干簧管 1 │
│ GPIO 21 ─── 干簧管 2 │
│ GPIO 23 ─── WS2812B 数据线 │
│ 3.3V ─── 传感器 VCC │
│ GND ─── 公共地 │
└─────────────────────────────────────┘

设备端开发

项目结构

smart-home-device/
├── src/
│ ├── main.c
│ ├── sensors.c
│ ├── actuators.c
│ ├── mqtt_client.c
│ └── config.h
├── include/
│ ├── sensors.h
│ ├── actuators.h
│ └── mqtt_client.h
├── CMakeLists.txt
└── sdkconfig

主程序

// main.c
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "sensors.h"
#include "actuators.h"
#include "mqtt_client.h"

static const char *TAG = "smart-home";

void app_main(void)
{
ESP_LOGI(TAG, "Smart Home Device Starting...");

// 初始化 WiFi
wifi_init();

// 初始化传感器
sensors_init();

// 初始化执行器
actuators_init();

// 初始化 MQTT
mqtt_app_start();

// 创建任务
xTaskCreate(sensor_task, "sensor_task", 4096, NULL, 5, NULL);
xTaskCreate(actuator_task, "actuator_task", 4096, NULL, 5, NULL);
}

传感器模块

// sensors.c
#include "sensors.h"
#include "driver/gpio.h"
#include "dht.h"

#define DHT_GPIO 4
#define DOOR_GPIO_1 19
#define DOOR_GPIO_2 21

static float temperature = 0;
static float humidity = 0;
static bool door_state_1 = false;
static bool door_state_2 = false;

void sensors_init(void)
{
// 配置干簧管输入
gpio_config_t io_conf = {
.pin_bit_mask = (1ULL << DOOR_GPIO_1) | (1ULL << DOOR_GPIO_2),
.mode = GPIO_MODE_INPUT,
.pull_up_en = 1,
};
gpio_config(&io_conf);
}

void sensor_task(void *pvParameters)
{
while (1) {
// 读取温湿度
if (dht_read_float_data(DHT_TYPE_AM2301, DHT_GPIO, &humidity, &temperature) == ESP_OK) {
ESP_LOGI("SENSOR", "Temp: %.1f°C, Humidity: %.1f%%", temperature, humidity);
}

// 读取门窗状态
door_state_1 = gpio_get_level(DOOR_GPIO_1);
door_state_2 = gpio_get_level(DOOR_GPIO_2);

// 发布数据
publish_sensor_data(temperature, humidity, door_state_1, door_state_2);

vTaskDelay(5000 / portTICK_PERIOD_MS);
}
}

执行器模块

// actuators.c
#include "actuators.h"
#include "driver/gpio.h"
#include "led_strip.h"

#define RELAY_GPIO_1 5
#define RELAY_GPIO_2 18
#define LED_GPIO 23

static led_strip_handle_t led_strip;

void actuators_init(void)
{
// 配置继电器
gpio_config_t io_conf = {
.pin_bit_mask = (1ULL << RELAY_GPIO_1) | (1ULL << RELAY_GPIO_2),
.mode = GPIO_MODE_OUTPUT,
};
gpio_config(&io_conf);

// 配置 LED 灯带
led_strip_config_t strip_config = {
.strip_gpio_num = LED_GPIO,
.max_leds = 30,
};
led_strip_new_rmt_device(&strip_config, &led_strip);
}

void set_light(int light_id, bool state)
{
int gpio = (light_id == 1) ? RELAY_GPIO_1 : RELAY_GPIO_2;
gpio_set_level(gpio, state ? 1 : 0);
ESP_LOGI("ACTUATOR", "Light %d: %s", light_id, state ? "ON" : "OFF");
}

void set_led_color(uint8_t r, uint8_t g, uint8_t b)
{
for (int i = 0; i < 30; i++) {
led_strip_set_pixel(led_strip, i, r, g, b);
}
led_strip_refresh(led_strip);
}

MQTT 客户端

// mqtt_client.c
#include "mqtt_client.h"
#include "esp_mqtt.h"
#include "cJSON.h"

#define MQTT_BROKER "broker.example.com"
#define MQTT_PORT 1883
#define MQTT_TOPIC_SUB "home/+/command"
#define MQTT_TOPIC_PUB "home/sensors"

static esp_mqtt_client_handle_t mqtt_client;

void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
esp_mqtt_event_handle_t event = event_data;

switch (event->event_id) {
case MQTT_EVENT_CONNECTED:
esp_mqtt_client_subscribe(mqtt_client, MQTT_TOPIC_SUB, 0);
break;

case MQTT_EVENT_DATA:
handle_command(event->topic, event->data, event->data_len);
break;

default:
break;
}
}

void mqtt_app_start(void)
{
esp_mqtt_client_config_t mqtt_cfg = {
.broker.address.uri = "mqtt://" MQTT_BROKER ":" STRINGIFY(MQTT_PORT),
.credentials.client_id = "smart-home-device",
};

mqtt_client = esp_mqtt_client_init(&mqtt_cfg);
esp_mqtt_client_register_event(mqtt_client, ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
esp_mqtt_client_start(mqtt_client);
}

void publish_sensor_data(float temp, float humi, bool door1, bool door2)
{
cJSON *root = cJSON_CreateObject();
cJSON_AddNumberToObject(root, "temperature", temp);
cJSON_AddNumberToObject(root, "humidity", humi);
cJSON_AddBoolToObject(root, "door1", door1);
cJSON_AddBoolToObject(root, "door2", door2);

char *json = cJSON_Print(root);
esp_mqtt_client_publish(mqtt_client, MQTT_TOPIC_PUB, json, 0, 1, 0);

cJSON_Delete(root);
free(json);
}

void handle_command(const char *topic, const char *data, int len)
{
cJSON *root = cJSON_ParseWithLength(data, len);

if (strstr(topic, "light")) {
int light_id = cJSON_GetObjectItem(root, "id")->valueint;
bool state = cJSON_GetObjectItem(root, "state")->valueint;
set_light(light_id, state);
}

cJSON_Delete(root);
}

云端开发

后端服务

# main.py
from fastapi import FastAPI, WebSocket
from fastapi.middleware.cors import CORSMiddleware
import aiomqtt
import asyncio
import json

app = FastAPI()

app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["*"],
allow_headers=["*"],
)

# 存储最新数据
latest_data = {}

async def mqtt_listener():
async with aiomqtt.Client("broker.example.com") as client:
await client.subscribe("home/#")
async for message in client.messages:
topic = message.topic.value
payload = json.loads(message.payload)

if "sensors" in topic:
latest_data.update(payload)
await broadcast_to_websockets(payload)

# WebSocket 连接管理
websocket_connections = []

@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
await websocket.accept()
websocket_connections.append(websocket)
try:
while True:
data = await websocket.receive_text()
# 处理客户端命令
command = json.loads(data)
await send_to_device(command)
except:
websocket_connections.remove(websocket)

async def broadcast_to_websockets(data):
for ws in websocket_connections:
await ws.send_json(data)

# REST API
@app.get("/api/sensors")
async def get_sensors():
return latest_data

@app.post("/api/lights/{light_id}")
async def control_light(light_id: int, state: bool):
command = {"id": light_id, "state": state}
await send_to_device(command)
return {"status": "ok"}

前端界面

<!DOCTYPE html>
<html>
<head>
<title>智能家居控制台</title>
<script src="https://cdn.jsdelivr.net/npm/vue@3"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts@5"></script>
</head>
<body>
<div id="app">
<div class="dashboard">
<div class="sensor-card">
<h3>温度</h3>
<div class="value">{{ sensors.temperature }}°C</div>
</div>
<div class="sensor-card">
<h3>湿度</h3>
<div class="value">{{ sensors.humidity }}%</div>
</div>
<div class="sensor-card">
<h3>门状态</h3>
<div class="value">{{ sensors.door1 ? '开启' : '关闭' }}</div>
</div>
</div>

<div class="control-panel">
<div class="light-control" v-for="i in 2" :key="i">
<h3>灯光 {{ i }}</h3>
<button @click="toggleLight(i)">
{{ lights[i] ? '关闭' : '开启' }}
</button>
</div>
</div>

<div id="chart" style="width: 100%; height: 400px;"></div>
</div>

<script>
const app = Vue.createApp({
data() {
return {
sensors: {},
lights: {},
ws: null,
chart: null,
chartData: []
}
},
mounted() {
this.connectWebSocket();
this.initChart();
},
methods: {
connectWebSocket() {
this.ws = new WebSocket('ws://localhost:8000/ws');
this.ws.onmessage = (event) => {
this.sensors = JSON.parse(event.data);
this.updateChart();
};
},
async toggleLight(id) {
const state = !this.lights[id];
await fetch(`/api/lights/${id}`, {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({state})
});
this.lights[id] = state;
},
initChart() {
this.chart = echarts.init(document.getElementById('chart'));
this.chart.setOption({
title: {text: '温湿度趋势'},
xAxis: {type: 'category'},
yAxis: {type: 'value'},
series: [
{name: '温度', type: 'line', data: []},
{name: '湿度', type: 'line', data: []}
]
});
},
updateChart() {
this.chartData.push({
time: new Date().toLocaleTimeString(),
temp: this.sensors.temperature,
humi: this.sensors.humidity
});
// 保留最近 50 条数据
if (this.chartData.length > 50) {
this.chartData.shift();
}
this.chart.setOption({
xAxis: {data: this.chartData.map(d => d.time)},
series: [
{data: this.chartData.map(d => d.temp)},
{data: this.chartData.map(d => d.humi)}
]
});
}
}
});
app.mount('#app');
</script>
</body>
</html>

场景联动

自动化规则

# rules.py
class AutomationEngine:
def __init__(self):
self.rules = []

def add_rule(self, name, trigger, actions):
self.rules.append({
'name': name,
'trigger': trigger,
'actions': actions
})

def evaluate(self, data):
for rule in self.rules:
if rule['trigger'](data):
for action in rule['actions']:
action(data)

engine = AutomationEngine()

# 规则1:温度超过28度开灯
engine.add_rule(
name='high_temp_light',
trigger=lambda d: d.get('temperature', 0) > 28,
actions=[lambda d: control_light(1, True)]
)

# 规则2:门打开时开灯
engine.add_rule(
name='door_open_light',
trigger=lambda d: d.get('door1') == True,
actions=[lambda d: control_light(1, True)]
)

部署上线

Docker Compose

version: '3'
services:
mqtt-broker:
image: eclipse-mosquitto:2
ports:
- "1883:1883"

api-server:
build: ./backend
ports:
- "8000:8000"
depends_on:
- mqtt-broker

web:
build: ./frontend
ports:
- "80:80"
depends_on:
- api-server

小结

本项目演示了完整的智能家居系统开发流程,包括硬件选型、设备端开发、云端开发和前端界面。通过这个项目,你可以掌握物联网系统的完整开发流程,并将所学知识应用到实际项目中。

下一步,我们将学习工业物联网项目,了解工业场景的特殊需求和解决方案。