智能家居系统:基于Qt和C++的客户端以及C语言服务器
智能家居系统:基于Qt和C++的客户端以及C语言服务器
概述
本项目构建了一个完整的智能家居系统,包含基于Qt和C++的客户端以及基于C语言的服务器。客户端提供用户界面,包括登录注册、控制智能灯、空调、加湿器、窗帘、模式切换,并显示温度和湿度信息。服务器与客户端通信,将数据存储到SQLite数据库并返回数据。
客户端
1. 界面设计
- 登录界面:提供用户名和密码输入框,以及登录和注册按钮。
- 主界面:包含控制智能设备的开关和调节参数,以及显示温度和湿度信息的折线图。
2. 功能实现
- 登录和注册:使用服务器验证用户身份并进行注册。
- 控制智能设备:
- 控制智能灯的开关和亮度。
- 控制空调的开关并监测温度。
- 控制加湿器的开关并监测湿度。
- 控制窗帘的开关并调节窗帘高度。
- 切换模式(睡眠模式、节能模式、日常模式)。
- 显示温度和湿度信息:从服务器获取温度和湿度数据并创建折线图进行可视化展示。
3. 代码示例 (基于Qt和C++)
#include <QtWidgets>
#include <QtCharts>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlRecord>
#include <QSqlError>
// 登录界面
class LoginWidget : public QWidget {
Q_OBJECT
public:
LoginWidget(QWidget *parent = nullptr) : QWidget(parent) {
usernameLineEdit = new QLineEdit(this);
passwordLineEdit = new QLineEdit(this);
passwordLineEdit->setEchoMode(QLineEdit::Password);
loginButton = new QPushButton('Login', this);
registerButton = new QPushButton('Register', this);
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(new QLabel('Username:', this));
layout->addWidget(usernameLineEdit);
layout->addWidget(new QLabel('Password:', this));
layout->addWidget(passwordLineEdit);
layout->addWidget(loginButton);
layout->addWidget(registerButton);
setLayout(layout);
connect(loginButton, &QPushButton::clicked, this, &LoginWidget::login);
connect(registerButton, &QPushButton::clicked, this, &LoginWidget::registerUser);
}
signals:
void loginSuccess(const QString &username); // 登录成功信号
private slots:
void login() {
// 验证账号密码
QString username = usernameLineEdit->text();
QString password = passwordLineEdit->text();
// TODO: 在此处与服务器通信,验证账号密码
emit loginSuccess(username); // 发送登录成功信号
}
void registerUser() {
// 注册新用户
QString username = usernameLineEdit->text();
QString password = passwordLineEdit->text();
// TODO: 在此处与服务器通信,注册新用户
QMessageBox::information(this, 'Success', 'Registration Successful!');
}
private:
QLineEdit *usernameLineEdit;
QLineEdit *passwordLineEdit;
QPushButton *loginButton;
QPushButton *registerButton;
};
// 主界面
class HomeAutomationWidget : public QWidget {
Q_OBJECT
public:
HomeAutomationWidget(const QString &username, QWidget *parent = nullptr) : QWidget(parent), currentUser(username) {
// 初始化控件
lightSwitch = new QCheckBox('Light Switch', this);
lightIntensitySlider = new QSlider(Qt::Horizontal, this);
airConditionerSwitch = new QCheckBox('Air Conditioner Switch', this);
temperatureLabel = new QLabel('Temperature: N/A', this);
humidifierSwitch = new QCheckBox('Humidifier Switch', this);
humidityLabel = new QLabel('Humidity: N/A', this);
curtainSwitch = new QCheckBox('Curtain Switch', this);
curtainHeightSlider = new QSlider(Qt::Horizontal, this);
modeComboBox = new QComboBox(this);
modeComboBox->addItem('Sleep Mode');
modeComboBox->addItem('Energy Saving Mode');
modeComboBox->addItem('Normal Mode');
chartView = new QChartView(this);
chart = new QChart;
chart->legend()->hide();
chartView->setChart(chart);
chartView->setRenderHint(QPainter::Antialiasing);
// 布局
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(lightSwitch);
layout->addWidget(new QLabel('Light Intensity:', this));
layout->addWidget(lightIntensitySlider);
layout->addWidget(airConditionerSwitch);
layout->addWidget(temperatureLabel);
layout->addWidget(humidifierSwitch);
layout->addWidget(humidityLabel);
layout->addWidget(curtainSwitch);
layout->addWidget(new QLabel('Curtain Height:', this));
layout->addWidget(curtainHeightSlider);
layout->addWidget(modeComboBox);
layout->addWidget(chartView);
setLayout(layout);
// 定时器,每隔一分钟更新温度和湿度信息
QTimer *timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &HomeAutomationWidget::updateTemperatureHumidity);
timer->start(60000);
// 初始化数据库连接
initDatabase();
// 初始化折线图
initChart();
// 初始化控件状态
updateControls();
}
private slots:
void updateTemperatureHumidity() {
// 获取温度和湿度信息
// TODO: 在此处与服务器通信,获取温度和湿度信息
float temperature = 25.0;
float humidity = 50.0;
// 更新数据库中的温度和湿度信息
insertTemperatureHumidity(temperature, humidity);
// 显示最新的温度和湿度信息
temperatureLabel->setText(QString('Temperature: %1').arg(temperature));
humidityLabel->setText(QString('Humidity: %1').arg(humidity));
// 更新折线图
updateChart();
}
void updateControls() {
// 获取智能家居状态
// TODO: 在此处与服务器通信,获取智能家居状态
bool lightState = true;
int lightIntensity = 50;
bool airConditionerState = true;
bool humidifierState = false;
bool curtainState = false;
int curtainHeight = 0;
int modeIndex = 2;
// 更新控件状态
lightSwitch->setChecked(lightState);
lightIntensitySlider->setValue(lightIntensity);
airConditionerSwitch->setChecked(airConditionerState);
humidifierSwitch->setChecked(humidifierState);
curtainSwitch->setChecked(curtainState);
curtainHeightSlider->setValue(curtainHeight);
modeComboBox->setCurrentIndex(modeIndex);
}
void insertTemperatureHumidity(float temperature, float humidity) {
QSqlQuery query;
query.prepare('INSERT INTO home_status (username, temperature, humidity) ' 'VALUES (:username, :temperature, :humidity)');
query.bindValue(':username', currentUser);
query.bindValue(':temperature', temperature);
query.bindValue(':humidity', humidity);
query.exec();
if (query.lastError().isValid()) {
qDebug() << 'Failed to insert temperature and humidity: ' << query.lastError().text();
}
}
void initDatabase() {
QSqlDatabase database = QSqlDatabase::addDatabase('QSQLITE');
database.setDatabaseName('home_automation.db');
if (!database.open()) {
qDebug() << 'Failed to open database: ' << database.lastError().text();
}
// 创建用户表
QSqlQuery query;
query.exec('CREATE TABLE IF NOT EXISTS users (' 'id INTEGER PRIMARY KEY AUTOINCREMENT,' 'username TEXT NOT NULL,' 'password TEXT NOT NULL)');
// 创建智能家居状态表
query.exec('CREATE TABLE IF NOT EXISTS home_status (' 'id INTEGER PRIMARY KEY AUTOINCREMENT,' 'username TEXT NOT NULL,' 'temperature REAL NOT NULL,' 'humidity REAL NOT NULL,' 'timestamp DATETIME DEFAULT CURRENT_TIMESTAMP)');
if (query.lastError().isValid()) {
qDebug() << 'Failed to create table: ' << query.lastError().text();
}
}
void initChart() {
// 查询最近的温度和湿度信息
QSqlQuery query;
query.prepare('SELECT temperature, humidity, timestamp FROM home_status ' 'WHERE username = :username ' 'ORDER BY timestamp DESC ' 'LIMIT 10');
query.bindValue(':username', currentUser);
query.exec();
if (query.lastError().isValid()) {
qDebug() << 'Failed to query chart data: ' << query.lastError().text();
}
// 创建折线图数据
QSplineSeries *series = new QSplineSeries;
QDateTimeAxis *axisX = new QDateTimeAxis;
QValueAxis *axisY = new QValueAxis;
axisX->setTickCount(10);
axisX->setFormat('yyyy-MM-dd HH:mm:ss');
axisX->setTitleText('Time');
axisY->setLabelFormat('%d');
axisY->setTitleText('Value');
while (query.next()) {
float temperature = query.value(0).toFloat();
float humidity = query.value(1).toFloat();
QDateTime timestamp = query.value(2).toDateTime();
series->append(timestamp.toMSecsSinceEpoch(), temperature);
series->append(timestamp.toMSecsSinceEpoch(), humidity);
}
chart->addSeries(series);
chart->addAxis(axisX, Qt::AlignBottom);
chart->addAxis(axisY, Qt::AlignLeft);
series->attachAxis(axisX);
series->attachAxis(axisY);
}
void updateChart() {
// 查询最近的温度和湿度信息
QSqlQuery query;
query.prepare('SELECT temperature, humidity, timestamp FROM home_status ' 'WHERE username = :username ' 'ORDER BY timestamp DESC ' 'LIMIT 10');
query.bindValue(':username', currentUser);
query.exec();
if (query.lastError().isValid()) {
qDebug() << 'Failed to query chart data: ' << query.lastError().text();
}
// 更新折线图数据
QSplineSeries *series = static_cast<QSplineSeries *>(chart->series().at(0));
series->clear();
while (query.next()) {
float temperature = query.value(0).toFloat();
float humidity = query.value(1).toFloat();
QDateTime timestamp = query.value(2).toDateTime();
series->append(timestamp.toMSecsSinceEpoch(), temperature);
series->append(timestamp.toMSecsSinceEpoch(), humidity);
}
}
private:
QString currentUser;
QCheckBox *lightSwitch;
QSlider *lightIntensitySlider;
QCheckBox *airConditionerSwitch;
QLabel *temperatureLabel;
QCheckBox *humidifierSwitch;
QLabel *humidityLabel;
QCheckBox *curtainSwitch;
QSlider *curtainHeightSlider;
QComboBox *modeComboBox;
QChart *chart;
QChartView *chartView;
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
LoginWidget loginWidget;
HomeAutomationWidget homeAutomationWidget('username');
QObject::connect(&loginWidget, &LoginWidget::loginSuccess, [&](const QString &username){
loginWidget.hide();
homeAutomationWidget.show();
});
loginWidget.show();
return app.exec();
}
#include 'main.moc'
服务器
1. 功能实现
- 与客户端通信:接收客户端的登录、注册和控制命令。
- 验证用户身份:根据用户名和密码验证用户登录。
- 注册新用户:将新用户的信息存储到数据库。
- 更新智能家居状态:将客户端的控制命令更新到数据库中。
- 返回数据:将数据库中的温度和湿度信息返回给客户端。
2. 代码示例 (基于C语言)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sqlite3.h>
#define MAX_BUFFER_SIZE 1024
// 数据库文件路径
#define DATABASE_PATH 'home_automation.db'
// 服务器监听地址和端口
#define SERVER_IP '127.0.0.1'
#define SERVER_PORT 8888
// 命令类型
enum CommandType {
Login,
Register,
LightSwitch,
LightIntensity,
ACState,
HumidifierState,
CurtainState,
CurtainHeight,
Mode
};
// 命令结构体
ty typedef struct {
enum CommandType type;
char username[64];
char password[64];
bool state;
int value;
} Command;
// 连接数据库
sqlite3 *connectDatabase() {
sqlite3 *db;
int rc;
rc = sqlite3_open(DATABASE_PATH, &db);
if (rc != SQLITE_OK) {
fprintf(stderr, 'Cannot open database: %s\n', sqlite3_errmsg(db));
return NULL;
}
return db;
}
// 关闭数据库连接
void closeDatabase(sqlite3 *db) {
sqlite3_close(db);
}
// 验证用户登录
bool verifyLogin(const char *username, const char *password) {
sqlite3 *db = connectDatabase();
bool result = false;
if (db == NULL) {
return result;
}
sqlite3_stmt *stmt;
const char *query = 'SELECT * FROM users WHERE username = ? AND password = ?';
int rc = sqlite3_prepare_v2(db, query, -1, &stmt, NULL);
if (rc != SQLITE_OK) {
fprintf(stderr, 'Failed to prepare statement: %s\n', sqlite3_errmsg(db));
closeDatabase(db);
return result;
}
sqlite3_bind_text(stmt, 1, username, -1, SQLITE_STATIC);
sqlite3_bind_text(stmt, 2, password, -1, SQLITE_STATIC);
rc = sqlite3_step(stmt);
if (rc == SQLITE_ROW) {
result = true;
}
sqlite3_finalize(stmt);
closeDatabase(db);
return result;
}
// 注册新用户
bool registerUser(const char *username, const char *password) {
sqlite3 *db = connectDatabase();
bool result = false;
if (db == NULL) {
return result;
}
sqlite3_stmt *stmt;
const char *query = 'INSERT INTO users (username, password) VALUES (?, ?)';
int rc = sqlite3_prepare_v2(db, query, -1, &stmt, NULL);
if (rc != SQLITE_OK) {
fprintf(stderr, 'Failed to prepare statement: %s\n', sqlite3_errmsg(db));
closeDatabase(db);
return result;
}
sqlite3_bind_text(stmt, 1, username, -1, SQLITE_STATIC);
sqlite3_bind_text(stmt, 2, password, -1, SQLITE_STATIC);
rc = sqlite3_step(stmt);
if (rc == SQLITE_DONE) {
result = true;
}
sqlite3_finalize(stmt);
closeDatabase(db);
return result;
}
// 更新智能家居状态
bool updateHomeAutomationState(const char *username, const Command *command) {
sqlite3 *db = connectDatabase();
bool result = false;
if (db == NULL) {
return result;
}
sqlite3_stmt *stmt;
int rc;
switch (command->type) {
case LightSwitch:
rc = sqlite3_prepare_v2(db, 'UPDATE home_status SET light_state = ? WHERE username = ?', -1, &stmt, NULL);
sqlite3_bind_int(stmt, 1, command->state);
sqlite3_bind_text(stmt, 2, username, -1, SQLITE_STATIC);
break;
case LightIntensity:
rc = sqlite3_prepare_v2(db, 'UPDATE home_status SET light_intensity = ? WHERE username = ?', -1, &stmt, NULL);
sqlite3_bind_int(stmt, 1, command->value);
sqlite3_bind_text(stmt, 2, username, -1, SQLITE_STATIC);
break;
case ACState:
rc = sqlite3_prepare_v2(db, 'UPDATE home_status SET ac_state = ? WHERE username = ?', -1, &stmt, NULL);
sqlite3_bind_int(stmt, 1, command->state);
sqlite3_bind_text(stmt, 2, username, -1, SQLITE_STATIC);
break;
case HumidifierState:
rc = sqlite3_prepare_v2(db, 'UPDATE home_status SET humidifier_state = ? WHERE username = ?', -1, &stmt, NULL);
sqlite3_bind_int(stmt, 1, command->state);
sqlite3_bind_text(stmt, 2, username, -1, SQLITE_STATIC);
break;
case CurtainState:
rc = sqlite3_prepare_v2(db, 'UPDATE home_status SET curtain_state = ? WHERE username = ?', -1, &stmt, NULL);
sqlite3_bind_int(stmt, 1, command->state);
sqlite3_bind_text(stmt, 2, username, -1, SQLITE_STATIC);
break;
case CurtainHeight:
rc = sqlite3_prepare_v2(db, 'UPDATE home_status SET curtain_height = ? WHERE username = ?', -1, &stmt, NULL);
sqlite3_bind_int(stmt, 1, command->value);
sqlite3_bind_text(stmt, 2, username, -1, SQLITE_STATIC);
break;
case Mode:
rc = sqlite3_prepare_v2(db, 'UPDATE home_status SET mode = ? WHERE username = ?', -1, &stmt, NULL);
sqlite3_bind_int(stmt, 1, command->value);
sqlite3_bind_text(stmt, 2, username, -1, SQLITE_STATIC);
break;
}
if (rc != SQLITE_OK) {
fprintf(stderr, 'Failed to prepare statement: %s\n', sqlite3_errmsg(db));
closeDatabase(db);
return result;
}
rc = sqlite3_step(stmt);
if (rc == SQLITE_DONE) {
result = true;
}
sqlite3_finalize(stmt);
closeDatabase(db);
return result;
}
// 处理客户端请求
void handleClientRequest(int clientSocket) {
char buffer[MAX_BUFFER_SIZE];
memset(buffer, 0, MAX_BUFFER_SIZE);
// 接收命令
ssize_t bytesRead = recv(clientSocket, buffer, MAX_BUFFER_SIZE - 1, 0);
if (bytesRead < 0) {
perror('Failed to receive data');
return;
}
Command command;
memcpy(&command, buffer, sizeof(Command));
// 处理命令
bool success = false;
switch (command.type) {
case Login:
success = verifyLogin(command.username, command.password);
break;
case Register:
success = registerUser(command.username, command.password);
break;
case LightSwitch:
case LightIntensity:
case ACState:
case HumidifierState:
case CurtainState:
case CurtainHeight:
case Mode:
success = updateHomeAutomationState(command.username, &command);
break;
}
// 发送响应
char response[MAX_BUFFER_SIZE];
memset(response, 0, MAX_BUFFER_SIZE);
response[0] = success ? 1 : 0;
send(clientSocket, response, sizeof(response), 0);
}
// 服务器主函数
int main() {
int serverSocket, clientSocket;
struct sockaddr_in serverAddress, clientAddress;
socklen_t clientAddressSize;
// 创建套接字
serverSocket = socket(AF_INET, SOCK_STREAM, 0);
if (serverSocket < 0) {
perror('Failed to create socket');
return 1;
}
// 设置服务器地址
memset(&serverAddress, 0, sizeof(serverAddress));
serverAddress.sin_family = AF_INET;
serverAddress.sin_addr.s_addr = inet_addr(SERVER_IP);
serverAddress.sin_port = htons(SERVER_PORT);
// 绑定套接字
if (bind(serverSocket, (struct sockaddr *)&serverAddress, sizeof(serverAddress)) < 0) {
perror('Failed to bind socket');
close(serverSocket);
return 1;
}
// 监听连接
if (listen(serverSocket, 5) < 0) {
perror('Failed to listen on socket');
close(serverSocket);
return 1;
}
// 循环接受客户端连接
while (true) {
clientAddressSize = sizeof(clientAddress);
clientSocket = accept(serverSocket, (struct sockaddr *)&clientAddress, &clientAddressSize);
if (clientSocket < 0) {
perror('Failed to accept client connection');
continue;
}
// 处理客户端请求
handleClientRequest(clientSocket);
// 关闭客户端连接
close(clientSocket);
}
// 关闭服务器套接字
close(serverSocket);
return 0;
}
数据库设计
-
用户表(users):存储用户的用户名和密码信息。
| 字段 | 类型 | 说明 | |---|---|---| | id | INTEGER | 主键,自动递增 | | username | TEXT | 用户名 | | password | TEXT | 密码 |
-
智能家居状态表(home_status):存储智能家居的状态信息,包括温度、湿度、时间戳等。
| 字段 | 类型 | 说明 | |---|---|---| | id | INTEGER | 主键,自动递增 | | username | TEXT | 用户名 | | temperature | REAL | 温度 | | humidity | REAL | 湿度 | | timestamp | DATETIME | 时间戳 |
运行步骤
- 创建数据库文件 home_automation.db。
- 运行服务器程序。
- 运行客户端程序。
总结
该项目提供了一个完整的智能家居系统解决方案,包含了客户端、服务器和数据库的设计和实现。开发者可以基于该项目进行扩展,添加更多功能和智能设备,实现更强大的智能家居系统。
原文地址: https://www.cveoy.top/t/topic/qaj5 著作权归作者所有。请勿转载和采集!