1.实现功能介绍
语音灯控、远程灯控的实现(LD3320、APP远程控制)
火灾报警功能实现(火灾传感器模块、蜂鸣器实现)
人脸识别开锁
温湿度采集(未实现)
2.设计模式------------工厂模式
工厂模式(Factory Pattern)是 Java 中最常用的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。
在C语言中,因为没有接口、类这一说法,所以这里采用了结构体来“等效替换”。有四个灯控,所以我创建了四个灯控.c程序。每一个程序文件中,都有一个Devices结构体,每个程序文件的函数实现方法不同.当有新设备进入只需要在创建一个.c文件,改变函数实现方法即可。
程序中,通过链表将各个模块连接起来(头插法)。在要使用某个模块时,只需要使用链表遍历,找到所需即可.
struct Devices corridorLight={
.deviceName="C",
.pinNumber=26,
.open=corridorLightopen,
.close=corridorLightclose,
.deviceInit =corridorLightCloseinit,
.changeStatus=corridorLightCloseStatus,
.status = 0
};
struct Devices *corridorLightinlink(struct Devices *phead)
{
if(phead==NULL)
{
phead=&corridorLight;
return phead;
}else{
corridorLight.next=phead;
phead=&corridorLight;
return phead;
}
}
3.火灾报警功能
模块在环境火焰光谱或者光源达不到设定值时,D0口输出高电平,当外界环境火焰光谱或者光源超过设定值时,模块D0出低电平;
所以我们只需要在程序中开一个线程循环检测传感器模块的输出是否变低即可。再去控制有源蜂鸣器的鸣叫即可。
void *Firewaring(void *arg)/*火灾报警扫描处理函数*/
{
struct Devices *firedevices = (struct Devices *)arg;
//printf("%s\n",firedevices->deviceName);
//******蜂鸣器初始化******//
pinMode(Buzzer,OUTPUT);
digitalWrite(Buzzer,HIGH);
while(1)
{
if(firedevices->readStatus(firedevices->pinNumber)== LOW && firedevices->status== 1)
{
delay(10);
if(firedevices->readStatus(firedevices->pinNumber)== LOW && firedevices->status== 1)
{
digitalWrite(Buzzer,LOW);
/*printf("yes\n");*/
delay(500);
}
}else{
digitalWrite(Buzzer,HIGH);
/*printf("no\n");*/
delay(500);
}
}
}
4.人脸识别实现
这个涉及到图像处理,但自己又未涉及过,所以这里直接调用祥云平台的功能进行处理。
根据祥云平台提供的API文档,进行开发。因为用的时C语言所以我们只能选择图片为base64流,根据文档要求只需将接口所需参数通过POST发送给接口地址即可.
5.关于socket与串口接收到数据后的处理
基于我最初的想法,我的手机APP端需要在我连接后知道我的房子的灯控、安全等信息,所以我们的服务器需要在接收的同时去接收消息。并且还支持同时接纳多个客户端的连接。所以我选择在连接一个客户端时同时开辟两个线程。在接受到数据后,按照我自己规定的协议,将数据提取出来,找到对应需要控制的设备,以及接下来的操作指令。
在创建收发线程时,需要将我们连接的客户端的对应套接字传入线程,不然,当有另外客户端接入时,会改变之前套接字的值,以至于线程不知道套接字改变,依然在进行“收”和“发”.
客户端接入后:
sfinder->Init(sfinder,NULL,NULL);
//printf("find %s\n",sfinder->commandName);
while(1)
{
c_sockfd=accept(sfinder->fd,(struct sockaddr *)&client_addr, &clen);
printf("client's c_socked=%d\n",c_sockfd);
if(c_sockfd==-1)
{
perror("accept");
}
printf("Connection successful!\n");
printf("from:%s\n",inet_ntoa(client_addr.sin_addr));
pthread_create(&readid,NULL,read_pthread,&c_sockfd);
pthread_create(&sendid,NULL,send_pthread,&c_sockfd);
}
socket服务器处理数据(串口于此类似处理)
memset(sfinder->command,0,32*sizeof(char));
int n_read=read(fd,sfinder->command,sizeof(sfinder->command));
if(n_read==0)
{
printf("The client disconnects!\n");
close(fd);
pthread_exit (NULL);
}else if(n_read>0)
{
printf("socket get nuread:%d\ncontext:%s\n",n_read,sfinder->command);
devices = strtok(sfinder->command,",");
//printf("after(devices):%s\n",devices);
order = strtok(NULL,"\0");
//printf("after2(order):%s\n",order);
struct Devices *opDevices = finduserwantinlink(devices,front);
if(strcmp(devices,"lock")==0)
{
postUrl("/tmp/post.html");
}else if(strcmp(devices,"all")== 0)
{
front_socket=front;
if(strcmp(order,"O")== 0)
{
while(front_socket!=NULL)
{
front_socket->open(front_socket->pinNumber);
front_socket->status=1;
front_socket=front_socket->next;
}
}else if(strcmp(order,"C")== 0)
{
while(front_socket!=NULL)
{
front_socket->close(front_socket->pinNumber);
front_socket->status=0;
front_socket=front_socket->next;
}
}
}else if(opDevices!=NULL)
{
//printf("operate %s\n",opDevices->deviceName);
if(strcmp(order,"O")== 0)
{
opDevices->open(opDevices->pinNumber);
opDevices->status = 1;
//printf("open %s\n",opDevices->deviceName);
}else if(strcmp(order,"C")== 0)
{
opDevices->close(opDevices->pinNumber);
opDevices->status = 0;
//printf("close %s\n",opDevices->deviceName);
}
}
}
6.关于客户端APP的编写
最开始是用的eclipse进行编写,但是由于遇到问题后,我将工程转移到Android Studio进行编写。APP端最重要的也就是与服务器端的连接,以及服务器端的异常关闭等的处理。因为只是现学现用,所以对此也只是在百度进行了有关异常处理代码的参考。
在对socket的编写完后,记得给APP添加网络权限。
7.总结
后面会考虑加入红外模块的来达到控制家中空调等设备。
温湿度数据采集未实现是因为,用的模块树莓派只有一个串口且已被占用。所以暂未了解怎么去处理接收模块采集的信息。
此次项目涉及到 JAVA APP编写、网络编程、串口通信和C语言的链表、结构体。新学习的知识:curl、openssl、https、http;post请求、get请求。