基于QT+树莓派实现智能家居系统

一、环境条件

上位机开发环境:Qt Creator 4.8.1

下位机开发环境:树莓派4b

此处省略Qt前端设计,只阐述后端逻辑实现

二、框架构建

上位机:

 下位机:

 三、程序编写(Qt)

1.程序初始界面

初始界面包含登录,网络控制,串口控制三个按钮。此时为未登录状态,登录标志按钮flag=0,此时点击其中的任意按钮,都会跳转到登录按钮。登录成功后,标志按钮flag=1,此时再点击登录按钮,只会弹出QMessageBox消息框提示登录成功,点击网络控制按钮则跳转到网络控制界面,点击串口控制按钮则会跳转到串口控制页面。

.h文件:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();


private slots:

    void on_logButton_clicked();

    void on_networkButton_clicked();

    void on_serialButton_clicked();

private:
    Ui::Widget *ui;
};

#endif // WIDGET_H

.c文件:

#include "widget.h"
#include "ui_widget.h"
#include "login.h"
#include "QMessageBox"
#include <network.h>
#include <serial.h>
extern int flag;
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
   ui->setupUi(this);
}

Widget::~Widget()
{

    delete ui;
}



void Widget::on_logButton_clicked()
{
    if(flag==0)//登录标志位flag=0
    {
        login *lg=new login;
        lg->setGeometry(this->geometry());
        lg->show();
        this->close();
    }
    else if (flag==1) {
        QMessageBox::information(this,"提示","您已成功登录");
    }


}

void Widget::on_networkButton_clicked()
{
    if(flag==0)
    {
        login *lg=new login;
        lg->setGeometry(this->geometry());
        lg->show();
        this->close();
    }
    else if (flag==1) {
        network *net=new network;
        net->setGeometry(this->geometry());
        net->show();

    }

}

void Widget::on_serialButton_clicked()
{
    if(flag==0)
    {
        login *lg=new login;
        lg->setGeometry(this->geometry());
        lg->show();
        this->close();
    }
    else if (flag==1) {
        serial *se=new serial;
        se->setGeometry(this->geometry());
        se->show();
        this->close();
    }

}

2.登录界面

登录框输入账号密码,点击"登录",拉取账号密码与数据库进行比对。若对比成功,登录标志flag置1,定时器启动,弹出QMessageBox消息框提示登录成功,保持1.5s,后自动关闭。若失败,登录标志不改变,弹出QMessageBox消息框提示登录失败。

.h文件

#ifndef LOGIN_H
#define LOGIN_H

#include <QWidget>

namespace Ui {
class login;
}

class login : public QWidget
{
    Q_OBJECT

public:
    explicit login(QWidget *parent = nullptr);
    ~login();

private slots:
    void on_pushButton_clicked();

    void on_backButton_clicked();

private:
    Ui::login *ui;
};

#endif // LOGIN_H

.c文件

#include "login.h"
#include "ui_login.h"
#include "QString"
#include "widget.h"
#include "QMessageBox"
#include "QTimer"
login::login(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::login)
{
    ui->setupUi(this);
    setWindowIcon(QIcon(":/home.ico"));
}

login::~login()
{
    delete ui;
}

extern int flag=0;
void login::on_pushButton_clicked()
{
    QString username=ui->countEdit->text();
    QString passwd=ui->passwdEdit->text();

    if(username=="8888"&&passwd=="6688")
    {
        Widget *wd=new Widget;
        wd->setGeometry(this->geometry());
        wd->show();
        flag=1;
        QMessageBox *box=new QMessageBox(QMessageBox::Information,"提示","登录成功");
        QTimer::singleShot(1500,box,SLOT(close()));
        this->close();
    }
    else {
        QMessageBox::critical(this,"提示","密码或用户名错误");

    }
}

void login::on_backButton_clicked()
{

    Widget *wd=new Widget;
    wd->setGeometry(this->geometry());
    wd->show();
    this->close();
}

3.网络控制界面

TCP连接与发送:界面初始化时,就已经初始化好tcpSocket,输入目的ip地址,目的端口后,点击连接,TCP开始与树莓派服务器连接,若连接成功,会接收到连接成功信号,触发绑定的槽函数并弹出QMessageBox消息框提示登录成功,并建立新的TCP连接。随后调节智能家电的参数,点击发送按钮,会将参数打包成TCP数据包,发送到树莓派控制硬件。

UDP连接与发送:网络控制界面开启时,就已经初始化好udpSocket,输入本地端口,点击接收开启连接,若连接成功弹出QMessageBox消息框,若此时有数据传输,则触发接收槽函数,并将接收到的内容显示到lable框中。

.h文件

#ifndef NETWORK_H
#define NETWORK_H

#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#include <QUdpSocket>
namespace Ui {
class network;
}

class network : public QWidget
{
    Q_OBJECT

public:
    explicit network(QWidget *parent = nullptr);
    ~network();
    QTcpSocket *tcpSocket;
    QUdpSocket *udpSocket;

private slots:
    void on_horizontalSlider_valueChanged(int value);

    void on_spinBox_valueChanged(int arg1);

    void on_openTVButton_clicked();

    void on_upButton_clicked();

    void on_nextButton_clicked();

    void on_TCPconnectButton_clicked();

    void connect_slot();
    void readyRead_slot();
    void readyReadUDP_slot();

    void on_TCPcloseButton_clicked();

    void on_sendButton_clicked();

    void on_UDPconnectButton_clicked();


    void on_UDPcloseButton_clicked();

private:
    Ui::network *ui;
};

#endif // NETWORK_H

.c文件

#include "network.h"
#include "ui_network.h"
#include <widget.h>
#include <iostream>
#include "QMessageBox"
#include "QString"
using namespace std;

static int lightnum;//灯的数值
static int airnum=15;//空调的数值
static int TVon=0;//0表示电视关闭
static int TVchannle=35;//表示电视频道
network::network(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::network)
{
    ui->setupUi(this);
    setWindowIcon(QIcon(":/home.ico"));
    tcpSocket=new QTcpSocket(this);
    udpSocket=new QUdpSocket(this);
}

network::~network()
{
    delete ui;
    Widget *wd=new Widget;
    wd->setGeometry(this->geometry());
    wd->show();
}

void network::on_horizontalSlider_valueChanged(int value)
{
    lightnum=ui->horizontalSlider->value();
    ui->light_value_label->setText(QString::number(lightnum));
}

void network::on_spinBox_valueChanged(int arg1)
{
    airnum=ui->spinBox->value();
    cout<<airnum<<endl;
}

void network::on_openTVButton_clicked()
{
    if(TVon==0)
    {
       TVon=1;
       ui->openTVButton->setText("关");
    }
    else if (TVon==1) {
        TVon=0;
        ui->openTVButton->setText("开");
    }
}

void network::on_upButton_clicked()
{
    if(TVon==1)
    {
        TVchannle=TVchannle+1;
        if(TVchannle=100)
        {
            TVchannle=10;
        }
        cout<<TVchannle<<endl;
    }

}

void network::on_nextButton_clicked()
{
    if(TVon==1)
    {
        TVchannle=TVchannle-1;
        if(TVchannle==10)
        {
            TVchannle=99;
        }
        cout<<TVchannle<<endl;
    }

}

void network::on_TCPconnectButton_clicked()
{
    //tcpSocket->connectToHost(ui->ipaddrEdit->text(),ui->aimportEdit->text().toUInt());
    tcpSocket->connectToHost("192.168.43.146",50001);
    connect(tcpSocket,SIGNAL(connected()),this,SLOT(connect_slot()));
}

void network::connect_slot()
{
    QMessageBox(QMessageBox::Information,"提示","连接成功");
    connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(readyRead_slot()));
}
void network::readyRead_slot()
{
    cout<<"TCP数据来喽!!"<<endl;
}

void network::on_TCPcloseButton_clicked()
{
    tcpSocket->close();
}

void network::on_sendButton_clicked()
{
    QString temp;
    if(lightnum>9)
    {
        temp.sprintf("%d%d%d%d",lightnum,airnum,TVon,TVchannle);
    }
    else if (0<=lightnum<=9) {
        temp.sprintf("0%d%d%d%d",lightnum,airnum,TVon,TVchannle);
    }

    tcpSocket->write(temp.toLocal8Bit().data());
}

void network::on_UDPconnectButton_clicked()
{
    if(udpSocket->bind(5554))
    {
        QMessageBox::information(this,"提示","UDP打开成功");
    }
    else {
        QMessageBox::critical(this,"提示","UDP打开失败");
    }
    connect(udpSocket,SIGNAL(readyRead()),SLOT(readyReadUDP_slot()));
}

void network::readyReadUDP_slot()
{
    cout<<"UDP数据来咯!"<<endl;
    while (udpSocket->hasPendingDatagrams()) {
        QByteArray array;
        array.resize(udpSocket->pendingDatagramSize());
        udpSocket->readDatagram(array.data(),array.size());
        QString buf;
        buf=array.data();
        ui->plainTextEdit->appendPlainText(buf);

    }

}

void network::on_UDPcloseButton_clicked()
{
    udpSocket->close();
}

4.串口控制界面

串口界面打开时,使用foreach函数将可用的串口查找出来,保存到QStringList的变量中并在界面上显示,将串口各个参数配置好后,点击"打开",配置的参数被赋给serialPort结构体的各个参数,并触发serialPort的open函数打开串口,若打开成功,QMessageBox弹窗提示打开成功。若打开失败,QMessageBox弹窗提示。

.h文件

#ifndef SERIAL_H
#define SERIAL_H

#include <QWidget>
#include <QSerialPortInfo>
#include <QSerialPort>
#include <QTimer>
#include <QTime>
namespace Ui {
class serial;
}

class serial : public QWidget
{
    Q_OBJECT

public:
    explicit serial(QWidget *parent = nullptr);
    ~serial();
    QSerialPort *serialPort;
    QTimer timer;

private slots:
    void on_openButton_clicked();

    void on_closeButton_clicked();
    void serialPort_ReadyRead_slot();
    void timeout_slot();
    void on_snedButton_clicked();

    void on_clearButton_clicked();

    void on_backButton_clicked();

private:
    Ui::serial *ui;
};

#endif // SERIAL_H

.c文件

#include "serial.h"
#include "ui_serial.h"
#include "QMessageBox"
#include "widget.h"

serial::serial(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::serial)
{
    ui->setupUi(this);
    setWindowIcon(QIcon(":/home.ico"));
    QStringList serialNamePort;
    foreach(const QSerialPortInfo &info,QSerialPortInfo::availablePorts())
    {
        serialNamePort<<info.portName();
    }
    ui->serialcomboBox->addItems(serialNamePort);
    connect(&timer,SIGNAL(timeout()),this,SLOT(timeout_slot()));



}

serial::~serial()
{
    delete ui;
}


void serial::serialPort_ReadyRead_slot()
{
    QString buf;
    QTime time=QTime::currentTime();
    buf=QString(serialPort->readAll());
    ui->revcTextEdit->appendPlainText(time.toString("hh:mm:ss"));
    ui->revcTextEdit->appendPlainText(buf);

}
void serial::timeout_slot()
{

}


void serial::on_openButton_clicked()
{
    serialPort=new QSerialPort(this);
    QSerialPort::BaudRate buadRate;
    QSerialPort::DataBits dataBits;
    QSerialPort::StopBits stopBits;
    QSerialPort::Parity checkBits;

    if(ui->botecomboBox->currentText()=="4800")
    {
        buadRate=QSerialPort::Baud4800;
    }
    else if (ui->botecomboBox->currentText()=="9600") {
        buadRate=QSerialPort::Baud9600;
    }
    else if (ui->botecomboBox->currentText()=="19200") {
        buadRate=QSerialPort::Baud19200;
    }
    else if (ui->botecomboBox->currentText()=="115200") {
        buadRate=QSerialPort::Baud115200;
    }

    if(ui->datacomboBox->currentText()=="5")
    {
        dataBits=QSerialPort::Data5;
    }
    else if (ui->datacomboBox->currentText()=="6") {
        dataBits=QSerialPort::Data6;
    }
    else if (ui->datacomboBox->currentText()=="7") {
        dataBits=QSerialPort::Data7;
    }
    else if (ui->datacomboBox->currentText()=="8") {
        dataBits=QSerialPort::Data8;
    }

    if(ui->stopcomboBox->currentText()=="1")
    {
        stopBits=QSerialPort::OneStop;
    }
    else if (ui->stopcomboBox->currentText()=="3") {
        stopBits=QSerialPort::OneAndHalfStop;
    }
    else if (ui->stopcomboBox->currentText()=="2") {
        stopBits=QSerialPort::TwoStop;
    }

    if(ui->jiaoyancomboBox->currentText()=="none")
    {
        checkBits=QSerialPort::NoParity;
    }

    serialPort->setPortName(ui->serialcomboBox->currentText());
    serialPort->setBaudRate(buadRate);
    serialPort->setDataBits(dataBits);
    serialPort->setStopBits(stopBits);
    serialPort->setParity(checkBits);

    if(serialPort->open(QIODevice::ReadWrite)==true)
    {
        QMessageBox::information(this,"提示","成功");
        connect(serialPort,SIGNAL(readyRead()),this,SLOT(serialPort_ReadyRead_slot()));

    }
    else {
        QMessageBox::critical(this,"提示","失败");
    }
}

void serial::on_closeButton_clicked()
{
    serialPort->close();
}

void serial::on_snedButton_clicked()
{
    serialPort->write(ui->snedlineEdit->text().toLocal8Bit().data());
}

void serial::on_clearButton_clicked()
{
    ui->revcTextEdit->clear();
    ui->snedlineEdit->clear();
}


void serial::on_backButton_clicked()
{
    Widget *wd=new Widget;
    wd->setGeometry(this->geometry());
    wd->show();
    this->close();
}

四、程序编写(树莓派wiringPi)

程序启动后,首先调用pthread_create创建2个线程tcp\serial,并使用pthread_detach分离线程。串口线程创建成功后,使用serialOpen打开串口,配置参数,发送验证性字符随后进入while(1)采集并发送环境信息。tcp线程创建后等待客户端连接,客户端连接成功后,创建第3个udp线程,随后进入while(1)等待tcp数据并处理。udp线程创建成功后,创建套接字,绑定端口和ip地址,等待连接,连接成功后进入while(1)进入发送

#include <sys/types.h>        
#include <sys/socket.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <time.h>
#include <wiringPi.h>
#include <wiringSerial.h>
#include <sys/wait.h>
#include <signal.h>
#include <pthread.h>

#include <stdio.h>
#include <time.h>
#include <sys/time.h>
#include <stdlib.h>
#include <signal.h>
char msg[20];
void *UDP(void)
{
	pthread_detach(pthread_self());//将当前线程分离
	//创建套接字
	int sock_fd = socket(AF_INET,SOCK_DGRAM,0);
	
	//绑定地址(IP+PORT)
	struct sockaddr_in srvaddr,ciladdr;
	
	srvaddr.sin_family = AF_INET;//地址族
	//端口
	srvaddr.sin_port = htons(5554);	//端口一般取50000以上	
	//IP地址
	srvaddr.sin_addr.s_addr = inet_addr("192.168.43.210");//将文本字符串转换为32位无符号网络地址
	
	
	
	char buf[100];
	int len = sizeof(ciladdr);
	
	while(1)
	{	
		bzero(buf,100);
		fgets(buf,100,stdin);				//从键盘输入数据
		sendto(sock_fd,buf,100,0,(struct sockaddr *)&srvaddr,sizeof(srvaddr));	

		
		
		
	}
	
	//关闭套接字
	close(sock_fd);
	
}

int light;
int airnum;
int TVon;
int TVchannel;

void *TCPServer(void)
{
	pthread_detach(pthread_self());//将当前线程分离
	//创建套接字
	int sock_fd = socket(PF_INET,SOCK_STREAM,0);
	
	//绑定地址(IP+PORT)
	struct sockaddr_in srvaddr;
	
	srvaddr.sin_family = PF_INET;//地址族
	//端口
	srvaddr.sin_port = htons(50001);	//端口一般取50000以上	
	//IP地址
	srvaddr.sin_addr.s_addr = inet_addr("192.168.43.146");//将文本字符串转换为32位无符号网络地址
	
	bind(sock_fd,(struct sockaddr *)&srvaddr,sizeof(srvaddr));
	
	//设置监听套接字
	listen(sock_fd,4);
	
	//等待客户端连接
	printf("等待连接\n");
	
	int conn_fd = accept(sock_fd,NULL,NULL);
	
	printf("连接成功\n");
	
	pthread_t th3;
	pthread_create(&th3,NULL,UDP,NULL);
	
	
	
	while(1)
	{
		bzero(msg,20);
		recv(conn_fd,msg,20,0);
		printf("recv:%s\n",msg);
		
		light=(msg[0]-48)*10+(msg[1]-48);
		airnum=(msg[2]-48)*10+(msg[3]-48);
		TVon=msg[4]-48;
		TVchannel=(msg[5]-48)*10+(msg[6]-48);
		
		
		
	}
	
	//关闭套接字
	close(conn_fd);
	close(sock_fd);
	
}
void *serial()
{
	pthread_detach(pthread_self());//将当前线程分离
	int fd;
	int cmd;
	int i=0;
	if(wiringPiSetup()==-1)
	{
		printf("setup wiringPi failed!\n");
		return 1;
	}

	fd=serialOpen("/dev/ttyAMA0",115200);
	if(-1==fd)
	{
		printf("ttyAMA open error!\n");
	}
	

	serialPuts(fd,"message from uart\r\n");
	printf("uart send finish\n");
	delay(1000);
	while(1)
	{
		serialPuts(fd,"Temp: Lum:\0");
		delay(3000);
		serialPrintf(fd,"%d %.1f\r\n",(airnum+5),light*0.657);
		delay(3000);
		
	//	serialFlush(fd);
	}

	serialClose(fd);
}

void signal_handler()
{
	static int i=0;
	i++;
	if(i<=light)
	{
		digitalWrite(7,HIGH);
	}
	else if(light<i<100)
	{
		digitalWrite(7,LOW);
	}
	if(100==i)
	{
		i=0;
	}
}

int main()
{
	
	pthread_t th1,th2;
	pthread_create(&th1,NULL,TCPServer,NULL);
	pthread_create(&th2,NULL,serial,NULL);
	
	if(wiringPiSetup()==-1)
	{
		printf("setup wiringPi faild!");
		return 1;
	}
	struct itimerval itv;
	itv.it_interval.tv_sec=0;
	itv.it_interval.tv_usec=500;

	itv.it_value.tv_sec=1;
	itv.it_value.tv_usec=0;

	pinMode(7,OUTPUT);
	pinMode(1,OUTPUT);
	pinMode(0,OUTPUT);
	setitimer(ITIMER_REAL,&itv,NULL);
	signal(SIGALRM,signal_handler);
	
	while(1)
	{
			if(airnum==15)
			{
				digitalWrite(1,LOW);	
			}
			else if(airnum>16)
			{
				digitalWrite(1,HIGH);
			}
			
			if(TVon==0)
			{
				digitalWrite(0,LOW);	
			}
			else if(TVon==1)
			{
				digitalWrite(0,HIGH);	
			}
	};
	return 0;
}

五、结语

        这个项目做的马马虎虎,很多设想的功能都是通过模拟的方式实现,还有许多不足之处需要好好打磨斟酌。因此有错误之处,还请批评指正。

  • 3
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值