智能家居系统:基于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 | 时间戳 |

运行步骤

  1. 创建数据库文件 home_automation.db
  2. 运行服务器程序。
  3. 运行客户端程序。

总结

该项目提供了一个完整的智能家居系统解决方案,包含了客户端、服务器和数据库的设计和实现。开发者可以基于该项目进行扩展,添加更多功能和智能设备,实现更强大的智能家居系统。

智能家居系统:基于Qt和C++的客户端以及C语言服务器

原文地址: https://www.cveoy.top/t/topic/qaj5 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录