51、C++项目实战:智能家居控制系统
智能家居,说白了就是让家里的设备学会「听话」。灯、空调、窗帘、门锁……这些设备如果能统一管理,生活能省不少事。我几年前接过一个项目,客户想把老宅子改造成智能屋,结果发现设备来自五六个品牌,协议五花八门。嗯,那时候我就意识到——一个灵活的设备抽象层,比什么都重要。
今天这个实战项目,我们就来搭建一个轻量级的智能家居控制系统。它不依赖任何第三方库,纯 C++ 实现,核心思路是:设备抽象 + 命令模式 + 简单调度。
系统整体架构
先看看我们要做什么。整个系统分三层:
- 设备层:每个设备都是一个独立对象,比如灯、空调、传感器。
- 控制层:接收用户指令,转换成设备能理解的命令。
- 调度层:支持定时任务、场景联动(比如「离家模式」一键关所有)。
下面这张图是我画的结构图,你看一眼就明白了:
设备抽象基类
所有设备都继承自同一个基类。我习惯把公共接口定义得尽量简洁:
class Device {
public:
virtual ~Device() = default;
virtual void turnOn() = 0;
virtual void turnOff() = 0;
virtual std::string getStatus() const = 0;
virtual std::string getDeviceName() const = 0;
};
你想想看,如果每个设备都自己定义一套接口,控制层就得写一堆 if-else。有了基类,控制层只需要操作 Device* 指针,多态就搞定了。
getStatus() 返回 JSON 格式的字符串,这样将来对接 Web 或 App 时,解析起来非常方便。
具体设备实现
拿「智能灯」举个例子。它除了开关,还支持亮度调节和色温控制:
class Light : public Device {
public:
Light(const std::string& name) : name_(name), on_(false), brightness_(100), colorTemp_(4000) {}
void turnOn() override {
on_ = true;
std::cout << name_ << " 已打开\n";
}
void turnOff() override {
on_ = false;
std::cout << name_ << " 已关闭\n";
}
void setBrightness(int level) {
if (level < 0 || level > 100) {
std::cerr << "亮度范围 0-100\n";
return;
}
brightness_ = level;
std::cout << name_ << " 亮度设为 " << level << "%\n";
}
void setColorTemp(int kelvin) {
colorTemp_ = kelvin;
std::cout << name_ << " 色温设为 " << kelvin << "K\n";
}
std::string getStatus() const override {
return "{\"name\":\"" + name_ + "\",\"on\":" + (on_ ? "true" : "false") +
",\"brightness\":" + std::to_string(brightness_) +
",\"colorTemp\":" + std::to_string(colorTemp_) + "}";
}
std::string getDeviceName() const override { return name_; }
private:
std::string name_;
bool on_;
int brightness_;
int colorTemp_;
};
命令模式:让控制更灵活
控制层如果直接调用设备方法,代码会耦合得很紧。我选择用命令模式——每个操作都是一个命令对象:
class Command {
public:
virtual ~Command() = default;
virtual void execute() = 0;
virtual void undo() = 0;
};
class LightOnCommand : public Command {
public:
explicit LightOnCommand(Light* light) : light_(light) {}
void execute() override { light_->turnOn(); }
void undo() override { light_->turnOff(); }
private:
Light* light_;
};
这样做的好处是什么?你可以把命令存到队列里,支持撤销、重做,甚至批量执行。我记得有个客户要求「一键离家模式」,其实就是把十几个命令打包成一个宏命令:
class MacroCommand : public Command {
public:
void addCommand(std::unique_ptr<Command> cmd) {
commands_.push_back(std::move(cmd));
}
void execute() override {
for (auto& cmd : commands_) cmd->execute();
}
void undo() override {
for (auto it = commands_.rbegin(); it != commands_.rend(); ++it)
(*it)->undo();
}
private:
std::vector<std::unique_ptr<Command>> commands_;
};
调度器:定时任务与场景
调度器是整个系统的「大脑」。它维护一个任务列表,每个任务包含触发条件和要执行的命令:
struct ScheduledTask {
std::chrono::system_clock::time_point triggerTime;
std::unique_ptr<Command> command;
bool repeatDaily; // 是否每天重复
};
class Scheduler {
public:
void addTask(ScheduledTask task) {
tasks_.push_back(std::move(task));
}
void runOnce() {
auto now = std::chrono::system_clock::now();
for (auto& task : tasks_) {
if (task.triggerTime <= now) {
task.command->execute();
if (task.repeatDaily) {
task.triggerTime += std::chrono::hours(24);
}
}
}
}
private:
std::vector<ScheduledTask> tasks_;
};
场景联动:让设备协同工作
场景是智能家居的灵魂。比如「睡眠模式」:关灯、关窗帘、空调调到睡眠温度。用我们的系统实现起来很简单:
auto sleepMode = std::make_unique<MacroCommand>();
sleepMode->addCommand(std::make_unique<LightOffCommand>(bedroomLight));
sleepMode->addCommand(std::make_unique<CurtainCloseCommand>(bedroomCurtain));
sleepMode->addCommand(std::make_unique<ACSetTempCommand>(bedroomAC, 26));
// 注册到调度器,每晚22:00执行
ScheduledTask task;
task.triggerTime = getTimeToday(22, 0);
task.command = std::move(sleepMode);
task.repeatDaily = true;
scheduler.addTask(std::move(task));
你可能会问:如果某个设备执行失败了怎么办?嗯,这里要注意——宏命令默认是「尽力而为」的。我建议在实际项目中加入回滚机制,或者至少记录日志。我曾经因为窗帘卡住没关上,结果空调一整晚都在拼命制冷,电费哗哗的。
完整示例:主循环
最后,我们把这些拼起来,跑一个简单的主循环:
int main() {
Light livingRoomLight("客厅灯");
Light bedroomLight("卧室灯");
Curtain livingRoomCurtain("客厅窗帘");
Scheduler scheduler;
// 注册场景
auto leaveHome = std::make_unique<MacroCommand>();
leaveHome->addCommand(std::make_unique<LightOffCommand>(&livingRoomLight));
leaveHome->addCommand(std::make_unique<LightOffCommand>(&bedroomLight));
leaveHome->addCommand(std::make_unique<CurtainCloseCommand>(&livingRoomCurtain));
// 模拟用户触发
std::cout << "=== 离家模式 ===\n";
leaveHome->execute();
// 模拟定时任务
auto nightLight = std::make_unique<LightOnCommand>(&bedroomLight);
ScheduledTask task;
task.triggerTime = std::chrono::system_clock::now() + std::chrono::seconds(2);
task.command = std::move(nightLight);
task.repeatDaily = false;
scheduler.addTask(std::move(task));
std::this_thread::sleep_for(std::chrono::seconds(3));
scheduler.runOnce();
return 0;
}
输出效果:
=== 离家模式 ===
客厅灯 已关闭
卧室灯 已关闭
客厅窗帘 已关闭
(2秒后)
卧室灯 已打开
总结一下
这个项目虽然小,但五脏俱全。你掌握了:
- 设备抽象:用基类统一接口,方便扩展新设备
- 命令模式:把操作封装成对象,支持撤销和宏命令
- 调度器:定时任务 + 场景联动,让系统自动化
说实话,智能家居的难点从来不是单个设备控制,而是如何优雅地管理一堆设备之间的协作。这个架构你吃透了,以后做物联网后台、机器人控制,思路都是相通的。
代码量不大,我建议你亲手敲一遍。遇到问题?很正常。调试的时候多打点日志,把每个命令的执行结果打印出来,问题很快就定位了。