基于树莓派4B的智能家居
- 前言
- C语言的简单工厂模式
- 工厂模式介绍
- 类和对象
- 工厂模式的优缺点
- 优点
- 缺点
- 智能家居框架
- 产品工厂
- 卫生间灯设备
- 二楼灯设备
- 餐厅灯设备
- 客厅灯设备
- 泳池灯设备
- 风扇设备
- 锁设备
- 警报器设备
- 地震监测设备
- 火灾监测设备
- 温湿度检测设备
- 指令工厂
- 语音控制设备
- server控制设备
- 人脸识别设备
- 主文件 main.c
- 主线程 main()
- 语音线程
- 人脸识别线程
- 火灾监测线程
- 地震监测线程
- 温湿度检测线程
- server控制线程
- 客户端连接后处理线程
- 发送数据线程
- 智能家居APP
- AndroidManiFest.xml
- 倒计时页面
- Java文件
- xml文件
- 页面展示
- 显示页面
- Java文件
- xml文件
- 页面展示
- 控制页面
- Java文件
- xml文件
- 页面展示
前言
本博文的智能家居使用的树莓派4B作为驱动板,当然也可以使用搭载了freeRtos的STM32驱动板,由于时间匆忙,没办法把从0到1的教程写到博文中,以后有时间的话会出一篇从0到1搭建这个智能家居的博文,到时候也会添加一些新的功能,如触摸屏、红外遥控、等等。
C语言的简单工厂模式
工厂模式介绍
工厂模式就最常用的设计模式之一,属于创建型模式,提供一种创建对象的最佳方式。在工厂模式中,创建对象时,不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。即工厂模式把创建对象和使用对象的两个过程分离,对于使用者无需关心对象时如何创建出来的,直接指定一个对象即可使用该对象的方法。
- C语言不是一门面向对象的语言,而是一门面向过程的语言,但C语言一样支持面向对象编程,即支持简单工厂模式。
- 工厂模式就是类的继承,C语言使用函数指针来实现类的继承,工厂中的设备用链表来链接起来
类和对象
- 类:一种用户定义的数据类型,也称类类型,例如结构体。
- 对象:类的一种实例化,例如结构体赋值。
工厂模式的优缺点
优点
- 在创建对象时,只需要知道对象的名字就行,代码维护性强。
- 需要添加设备时,只需要添加一个对象就行了,代码扩展性。
缺点
- 代码阅读性变复杂。
- 设备增多时会使对象增多,提高了代码复杂度。
智能家居框架
本篇博文介绍的智能家居由两个工厂和若干个设备组成,分别是产品工厂和指令工厂。包含功能如下:
产品工厂
该工厂主要是用来生产一些供人们使用的设备,如灯设备、收集环境数据设备、检测安全设备等等。
#include <stdio.h>
#include <wiringPi.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <stdlib.h>
//创建产品工厂的类,即产品工厂的生产线
struct Devices
{
char devicesName[128]; //设备名称
int status; //设备状态
int pinNum; //设备引脚
unsigned long databuf; //设备数据存储区
/* 设备功能 */
int (*open)(int pinNum);
int (*close)(int pinNum);
int (*devicesInit)(int pinNum);
int (*readStatus)(int pinNum);
int (*changeStatus)(int status);
int (*readData)(struct Devices *devices,int pinNum);
struct Devices *next; //链表链接节点
};
/* 告知工厂,对应的设备已经上线成为商品了 */
struct Devices* addBashroomLightToDevicesLink(struct Devices *phead);
struct Devices* addsecondfloorLightToDevicesLink(struct Devices *phead);
struct Devices* addrestaurantLightToDevicesLink(struct Devices *phead);
struct Devices* addlivingroomLightToDevicesLink(struct Devices *phead);
struct Devices* addswimmingLightToDevicesLink(struct Devices *phead);
struct Devices* addlockToDevicesLink(struct Devices *phead);
struct Devices* addfireToDevicesLink(struct Devices *phead);
struct Devices* addbuzzerToDevicesLink(struct Devices *phead);
struct Devices* addishockToDevicesLink(struct Devices *phead);
struct Devices* addfanToDevicesLink(struct Devices *phead);
struct Devices* addsensorToDevicesLink(struct Devices *phead);
.
卫生间灯设备
#include "controlDevices.h"
int bashroomLightOpen(int pinNum)
{
digitalWrite(pinNum,LOW);
}
int bashroomLightClose(int pinNum)
{
digitalWrite(pinNum,HIGH);
}
int bashroomLightInit(int pinNum)
{
pinMode(pinNum,OUTPUT);
digitalWrite(pinNum,HIGH);
}
/* 继承产品工厂的类,生产卫生间灯设备 */
struct Devices bashroomLight = {
.devicesName = "bathroom",
.pinNum = 23,
.open = bashroomLightOpen,
.close = bashroomLightClose,
.devicesInit = bashroomLightInit,
.next = NULL,
};
/* 头插法加入链表,提供购买渠道,以供客户购买 */
struct Devices* addBashroomLightToDevicesLink(struct Devices *phead)
{
if(phead == NULL){
phead = &bashroomLight;
return phead;
}else{
bashroomLight.next = phead;
phead = &bashroomLight;
return phead;
}
}
.
二楼灯设备
#include "controlDevices.h"
int secondfloorLightOpen(int pinNum)
{
digitalWrite(pinNum,LOW);
}
int secondfloorLightClose(int pinNum)
{
digitalWrite(pinNum,HIGH);
}
int secondfloorLightInit(int pinNum)
{
pinMode(pinNum,OUTPUT);
digitalWrite(pinNum,HIGH);
}
/* 继承产品工厂的类,生产二楼灯设备 */
struct Devices secondfloorLight = {
.devicesName = "secondfloor",
.pinNum = 21,
.open = secondfloorLightOpen,
.close = secondfloorLightClose,
.devicesInit = secondfloorLightInit,
.next = NULL,
};
/* 头插法加入链表,提供购买渠道,以供客户购买 */
struct Devices* addsecondfloorLightToDevicesLink(struct Devices *phead)
{
if(phead == NULL){
phead = &secondfloorLight;
return phead;
}else{
secondfloorLight.next = phead;
phead = &secondfloorLight;
return phead;
}
}
.
餐厅灯设备
#include "controlDevices.h"
int restaurantLightOpen(int pinNum)
{
digitalWrite(pinNum,LOW);
}
int restaurantLightClose(int pinNum)
{
digitalWrite(pinNum,HIGH);
}
int restaurantLightInit(int pinNum)
{
pinMode(pinNum,OUTPUT);
digitalWrite(pinNum,HIGH);
}
/* 继承产品工厂的类,生产餐厅灯设备 */
struct Devices restaurantLight = {
.devicesName = "restaurant",
.pinNum = 22,
.open = restaurantLightOpen,
.close = restaurantLightClose,
.devicesInit = restaurantLightInit,
.next = NULL,
};
/* 头插法加入链表,提供购买渠道,以供客户购买 */
struct Devices* addrestaurantLightToDevicesLink(struct Devices *phead)
{
if(phead == NULL){
phead = &restaurantLight;
return phead;
}else{
restaurantLight.next = phead;
phead = &restaurantLight;
return phead;
}
}
.
客厅灯设备
#include "controlDevices.h"
int livingroomLightOpen(int pinNum)
{
digitalWrite(pinNum,LOW);
}
int livingroomLightClose(int pinNum)
{
digitalWrite(pinNum,HIGH);
}
int livingroomLightInit(int pinNum)
{
pinMode(pinNum,OUTPUT);
digitalWrite(pinNum,HIGH);
}
/* 继承产品工厂的类,生产客厅灯设备 */
struct Devices livingroomLight = {
.devicesName = "livingroom",
.pinNum = 24,
.open = livingroomLightOpen,
.close = livingroomLightClose,
.devicesInit = livingroomLightInit,
.next = NULL,
};
/* 头插法加入链表,提供购买渠道,以供客户购买 */
struct Devices* addlivingroomLightToDevicesLink(struct Devices *phead)
{
if(phead == NULL){
phead = &livingroomLight;
return phead;
}else{
livingroomLight.next = phead;
phead = &livingroomLight;
return phead;
}
}
.
泳池灯设备
#include "controlDevices.h"
int swimmingLightOpen(int pinNum)
{
digitalWrite(pinNum,LOW);
}
int swimmingLightClose(int pinNum)
{
digitalWrite(pinNum,HIGH);
}
int swimmingLightInit(int pinNum)
{
pinMode(pinNum,OUTPUT);
digitalWrite(pinNum,HIGH);
}
/* 继承产品工厂的类,生产泳池灯设备 */
struct Devices swimmingLight = {
.devicesName = "swimming",
.pinNum = 25,
.open = swimmingLightOpen,
.close = swimmingLightClose,
.devicesInit = swimmingLightInit,
.next = NULL,
};
/* 头插法加入链表,提供购买渠道,以供客户购买 */
struct Devices* addswimmingLightToDevicesLink(struct Devices *phead)
{
if(phead == NULL){
phead = &swimmingLight;
return phead;
}else{
swimmingLight.next = phead;
phead = &swimmingLight;
return phead;
}
}
.
风扇设备
#include "controlDevices.h"
int fanOpen(int pinNum)
{
digitalWrite(pinNum,LOW);
}
int fanClose(int pinNum)
{
digitalWrite(pinNum,HIGH);
}
int fanInit(int pinNum)
{
pinMode(pinNum,OUTPUT);
digitalWrite(pinNum,HIGH);
}
/* 继承产品工厂的类,生产风扇设备 */
struct Devices fan = {
.devicesName = "fan",
.pinNum = 29,
.open = fanOpen,
.close = fanClose,
.devicesInit = fanInit,
.next = NULL,
};
/* 头插法加入链表,提供购买渠道,以供客户购买 */
struct Devices* addfanToDevicesLink(struct Devices *phead)
{
if(phead == NULL){
phead = &fan;
return phead;
}else{
fan.next = phead;
phead = &fan;
return phead;
}
}
.
锁设备
#include "controlDevices.h"
int lockOpen(int pinNum)
{
digitalWrite(pinNum,LOW);
}
int lockClose(int pinNum)
{
digitalWrite(pinNum,HIGH);
}
int lockInit(int pinNum)
{
pinMode(pinNum,OUTPUT);
digitalWrite(pinNum,HIGH);
}
/* 继承产品工厂的类,生产锁设备 */
struct Devices lock = {
.devicesName = "lock",
.pinNum = 28,
.open = lockOpen,
.close = lockClose,
.devicesInit = lockInit,
.next = NULL,
};
/* 头插法加入链表,提供购买渠道,以供客户购买 */
struct Devices* addlockToDevicesLink(struct Devices *phead)
{
if(phead == NULL){
phead = &lock;
return phead;
}else{
lock.next = phead;
phead = &lock;
return phead;
}
}
.
警报器设备
#include "controlDevices.h"
int buzzerOpen(int pinNum)
{
digitalWrite(pinNum,LOW);
}
int buzzerClose(int pinNum)
{
digitalWrite(pinNum,HIGH);
}
int buzzerInit(int pinNum)
{
pinMode(pinNum,OUTPUT);
digitalWrite(pinNum,HIGH);
}
/* 继承产品工厂的类,生产警报器设备 */
struct Devices buzzer = {
.devicesName = "buzzer",
.pinNum = 27,
.open = buzzerOpen,
.close = buzzerClose,
.devicesInit = buzzerInit,
.next = NULL,
};
/* 头插法加入链表,提供购买渠道,以供客户购买 */
struct Devices* addbuzzerToDevicesLink(struct Devices *phead)
{
if(phead == NULL){
phead = &buzzer;
return phead;
}else{
buzzer.next = phead;
phead = &buzzer;
return phead;
}
}
.
地震监测设备
#include "controlDevices.h"
int shockInit(int pinNum)
{
pinMode(pinNum,INPUT);
digitalWrite(pinNum,HIGH);
}
/* 检测地震发生情况 */
int shockReadStatus(int pinNum)
{
return digitalRead(pinNum);
}
/* 继承产品工厂的类,生产地震监测设备 */
struct Devices shock = {
.devicesName = "shock",
.pinNum = 6,
.devicesInit = shockInit,
.readStatus = shockReadStatus,
.next = NULL,
};
/* 头插法加入链表,提供购买渠道,以供客户购买 */
struct Devices* addishockToDevicesLink(struct Devices *phead)
{
if(phead == NULL){
phead = &shock;
return phead;
}else{
shock.next = phead;
phead = &shock;
return phead;
}
}
.
火灾监测设备
#include "controlDevices.h"
int fireInit(int pinNum)
{
pinMode(pinNum,INPUT);
digitalWrite(pinNum,HIGH);
}
/* 检测火灾发生情况 */
int fireReadStatus(int pinNum)
{
return digitalRead(pinNum);
}
/* 继承产品工厂的类,生产火灾监测设备 */
struct Devices fire = {
.devicesName = "fire",
.pinNum = 4,
.devicesInit = fireInit,
.readStatus = fireReadStatus,
.next = NULL,
};
/* 头插法加入链表,提供购买渠道,以供客户购买 */
struct Devices* addfireToDevicesLink(struct Devices *phead)
{
if(phead == NULL){
phead = &fire;
return phead;
}else{
fire.next = phead;
phead = &fire;
return phead;
}
}
.
温湿度检测设备
#include "controlDevices.h"
int sensorInit(int pinNum)
{
pinMode(pinNum,OUTPUT);
digitalWrite(pinNum,HIGH);
}
/* 获取温度传感器的数据 */
int sensorReadData(struct Devices *sensorMsg,int pinNum)
{
char crc;
char i;
unsigned long databuf; //温湿度存储地址
pinMode(pinNum, OUTPUT);
digitalWrite(pinNum, 0);
delay(25);
digitalWrite(pinNum, 1);
pinMode(pinNum, INPUT);
pullUpDnControl(pinNum, PUD_UP);//启用上拉电阻,引脚电平拉倒3.3v
delayMicroseconds(27);
if (digitalRead(pinNum) == 0)
{
while (!digitalRead(pinNum));
for (i = 0; i < 32; i++)
{
while (digitalRead(pinNum));
while (!digitalRead(pinNum));
delayMicroseconds(32);
databuf *= 2;
if (digitalRead(pinNum) == 1)
{
databuf++;
}
}
for (i = 0; i < 8; i++)
{
while (digitalRead(pinNum));
while (!digitalRead(pinNum));
delayMicroseconds(32);
crc *= 2;
if (digitalRead(pinNum) == 1)
{
crc++;
}
}
sensorMsg->databuf = databuf;
return 1;
}
else
{
return 0;
}
}
/* 继承产品工厂的类,生产温度检测设备 */
struct Devices sensor = {
.devicesName = "sensor",
.pinNum = 1,
.devicesInit = sensorInit,
.readData = sensorReadData,
.next = NULL,
};
/* 头插法加入链表,提供购买渠道,以供客户购买 */
struct Devices* addsensorToDevicesLink(struct Devices *phead)
{
if(phead == NULL){
phead = &sensor;
return phead;
}else{
sensor.next = phead;
phead = &sensor;
return phead;
}
}
.
指令工厂
该工厂主要是用来生产一些供人们发出指令控制的设备,如语音设备、server设备、摄像头设备等等,这些设备可以控制产品工厂的设备做出一些控制行为。
#include <wiringPi.h>
#include <stdio.h>
#include <wiringSerial.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <curl/curl.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
//创建指令工厂的类,即指令工厂的生产线
struct InputCmd
{
int fd; //文件的fd
char deviceName[128]; //设备名称
char cmd[64]; //指令内容
char cmdName[128]; //指令名称
char log[1024]; //日志
int sfd; //server的fd
char port[12]; //端口号
char ipAress[32]; //IP地址
char *img_buf; //指向主人的人脸图片数据存储区的指针
char *camera_buf; //指向临时的人脸图片数据存储区的指针
float face_data; //人脸识别匹配度
/* 设备功能 */
int (*Init)(struct InputCmd *voicer,char *ipAdress,char *port);
int (*getCmd)(struct InputCmd *voicer);
int (*ReadHandle)(void *ptr, size_t size, size_t nmemb, void *stream);
struct InputCmd *next; //链表链接节点
};
//告知工厂,对应的设备已经上线成为商品了
struct InputCmd* addvoiceControlToInputCmdLink(struct InputCmd *phead);
struct InputCmd* addserverControlToInputCmdLink(struct InputCmd *phead);
struct InputCmd* addcameraControlToInputCmdLink(struct InputCmd *phead);
.
语音控制设备
该设备通过语音模块su-03获取主人的命令词并通过智能公元平台将相应的命令词转换成字符串通过串口发送给树莓派。
#include "inputCmd.h"
/* 语音控制设备初始化,启用串口 */
int voiceInit(struct InputCmd *voicer,char *ipAdress,char *port)
{
int fd;
if((fd = serialOpen(voicer->deviceName,9600))==-1){ //打开串口
exit(-1);
}
voicer->fd = fd;
return fd;
}
/* 读取来自语音控制设备的命令 */
int voiceGetCmd(struct InputCmd *voicer)
{
char tmp[128];
int nread;
memset(tmp,'\0',sizeof(tmp));
nread = read(voicer->fd,tmp,sizeof(tmp)); //一切皆文件,串口也是文件,读串口数据
if(nread == 0){
printf("usart for voice read overtime\n");
}else if(nread > 0){
memset(voicer->cmd,'\0',sizeof(voicer->cmd));
/* 对串口数据进行优化 */
if(strstr(tmp,"open ba") != NULL){
strcat(voicer->cmd,"open bathroom light");
}
if(strstr(tmp,"close ba") != NULL){
strcat(voicer->cmd,"close bathroom light");
}
if(strstr(tmp,"open li") != NULL){
strcat(voicer->cmd,"open livingroom light");
}
if(strstr(tmp,"close li") != NULL){
strcat(voicer->cmd,"close livingroom light");
}
if(strstr(tmp,"open re") != NULL){
strcat(voicer->cmd,"open restaurant light");
}
if(strstr(tmp,"close re") != NULL){
strcat(voicer->cmd,"close restaurant light");
}
if(strstr(tmp,"open se") != NULL){
strcat(voicer->cmd,"open secondfloor light");
}
if(strstr(tmp,"close se") != NULL){
strcat(voicer->cmd,"close secondfloor light");
}
if(strstr(tmp,"open sw") != NULL){
strcat(voicer->cmd,"open swimming light");
}
if(strstr(tmp,"close sw") != NULL){
strcat(voicer->cmd,"close swimming light");
}
if(strstr(tmp,"open bu") != NULL){
strcat(voicer->cmd,"open buzzer light");
}
if(strstr(tmp,"close bu") != NULL){
strcat(voicer->cmd,"close buzzer light");
}
if(strstr(tmp,"open fn") != NULL){
strcat(voicer->cmd,"open fan light");
}
if(strstr(tmp,"close fn") != NULL){
strcat(voicer->cmd,"close fan light");
}
if(strstr(tmp,"open fac") != NULL){
strcat(voicer->cmd,"open face light");
}
if(strstr(tmp,"open lo") != NULL){
strcat(voicer->cmd,"open lock light");
}
if(strstr(tmp,"close lo") != NULL){
strcat(voicer->cmd,"close lock light");
}
return nread;
}else{
printf("read is fali\n");
}
}
/* 继承指令工厂的类,生产语音控制设备 */
struct InputCmd voiceControl = {
.cmdName = "voice",
.deviceName = "/dev/ttyAMA0",
.cmd = {'\0'},
.Init = voiceInit,
.getCmd = voiceGetCmd,
.next = NULL,
};
/* 头插法加入链表,提供购买渠道,以供客户购买 */
struct InputCmd* addvoiceControlToInputCmdLink(struct InputCmd *phead)
{
if(phead == NULL){
phead = &voiceControl;
return phead;
}else{
voiceControl.next = phead;
phead = &voiceControl;
return phead;
}
}
.
server控制设备
该设备是架设socket服务器,监听客户端的连接。
#include "inputCmd.h"
/* server控制设备初始化,为套接字绑定端口号和IP地址 */
int serverInit(struct InputCmd *serverMsg,char *ipAdress,char *port)
{
int s_fd;
struct sockaddr_in s_addr;
memset(&s_addr,0,sizeof(struct sockaddr_in));
s_fd = socket(AF_INET,SOCK_STREAM,0);
if(s_fd == -1){
perror("socket");
exit(-1);
}
s_addr.sin_family = AF_INET;
s_addr.sin_port = htons(atoi(serverMsg->port));
inet_aton(serverMsg->ipAress,&s_addr.sin_addr);
bind(s_fd,(struct sockaddr *)&s_addr,sizeof(struct sockaddr_in));
listen(s_fd,10);
serverMsg->sfd = s_fd;
return s_fd;
}
/* 继承指令工厂的类,生产server控制设备 */
struct InputCmd serverControl = {
.cmdName = "server",
.cmd = {'\0'},
.log = {'\0'},
.Init = serverInit,
.port = "8801",
.ipAress = "192.168.104.61",
.next = NULL,
};
/* 头插法加入链表,提供购买渠道,以供客户购买 */
struct InputCmd* addserverControlToInputCmdLink(struct InputCmd *phead)
{
if(phead == NULL){
phead = &serverControl;
return phead;
}else{
serverControl.next = phead;
phead = &serverControl;
return phead;
}
}
.
人脸识别设备
该设备通过使用curl第三方库访问网站,调用祥云人脸识别平台进行人脸识别。
#include "inputCmd.h"
char post_info[500];
/* 人脸识别设备初始化 */
int cameraInit(struct InputCmd *camera,char *ipAdress,char *port)
{
int fd;
int imgSize=0;
char cmd[30];
memset(post_info,'\0',500);
curl_global_init(CURL_GLOBAL_ALL); //curl库初始化
/* 获取主人的人脸图片的base64编码 */
fd = open("imgfile.txt",O_RDWR,0666); //打开用来存放主人的人脸图片的base64编码的文件
imgSize = lseek(fd,0,SEEK_END);
camera->img_buf = (char *)malloc(imgSize + 8);
memset(camera->img_buf,'\0',imgSize + 8);
lseek(fd,0,SEEK_SET);
read(fd,camera->img_buf,imgSize); //将主人的人脸图片的base64编码读到img_buf数据存储区
close(fd);
system("raspistill -q 5 -o haozi.jpg"); //调用树莓派摄像头拍摄图片,-q 5为降低画质
while(access("./haozi.jpg",F_OK) != 0); //等待拍摄完成
sprintf(cmd,"base64 %s >camerafile.txt","haozi.jpg"); //字符串拼接
if(system(cmd) == 256){ //生成摄像头拍摄图片的base64编码的图像地址
return -1;
}
/* 获取临时拍摄的人脸图片的base64编码 */
fd = open("camerafile.txt",O_RDWR,0666); //打开用来存放临时拍摄的人脸图片的base64编码的文件
imgSize = lseek(fd,0,SEEK_END);
camera->camera_buf = (char *)malloc(imgSize + 8);
memset(camera->camera_buf,'\0',imgSize + 8);
lseek(fd,0,SEEK_SET);
read(fd,camera->camera_buf,imgSize); //将临时拍摄的人脸图片的base64编码读到camera_buf数据存储区
close(fd);
system("rm camerafile.txt");
system("rm haozi.jpg");
if((camera->img_buf == NULL)||(camera->camera_buf == NULL)){
printf("img dont exist!\n");
return -1;
}
return 0;
}
/* 获取祥云平台的人脸识别结果数据 */
int cameraReadHandle( void *ptr, size_t size, size_t nmemb, void *stream)
{
int buf_size=size*nmemb;
char *buf=malloc(buf_size+1);
memset(buf,'\0',buf_size+1);
strncpy(buf,ptr,buf_size); //获取祥云平台的人脸识别结果
memset(post_info,'\0',sizeof(post_info));
strcat(post_info,buf);
free(buf);
return buf_size;
}
/* 调用祥云平台进行人脸识别 */
int cameraGetCmd(struct InputCmd *camera)
{
CURL *curl;
CURLcode res;
char *PostString;
/* 祥云平台的个人基本信息 */
char *key="6M9M9rFAa3DuG33Awu9hKq";
char *secret="db56882c3a0b4a3dbeeaed2af79f026c";
int typeId=21;
char *format="xml";
char *result_str = NULL;
float result_data;
int len = strlen(camera->img_buf)+strlen(camera->camera_buf)+strlen(key)+strlen(secret)+sizeof(typeId)+strlen(format) + 24;
PostString=malloc(len);
sprintf(PostString,"&img1=%s&img2=%s&key=%s&secret=%s&typeId=%d&format=%s",camera->img_buf,camera->camera_buf,key,secret,typeId,format); //设置需要发送给祥云平台的数据格式
curl = curl_easy_init(); //获取句柄
if (curl){
curl_easy_setopt(curl, CURLOPT_URL, "https://netocr.com/api/faceliu.do"); //设置访问的URL,即祥云人脸识别的接口地址
curl_easy_setopt(curl, CURLOPT_POSTFIELDS,PostString); //向祥云平台发送数据,调用人脸识别功能
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, camera->ReadHandle); //设置回调函数,该函数用来接收人脸识别的结果
res = curl_easy_perform(curl);//错误检测,0没有错误,非0出现错误
curl_easy_cleanup(curl);
/* 处理人脸识别的结果数据 */
result_str = strstr(post_info,"CDATA");
if(result_str != NULL){
result_str += 6;
result_str = strtok(result_str,"]");
result_data = atof(result_str);
}else{
printf("get result error!\n");
}
}else{
printf("get result error!\n");
}
camera->face_data = result_data;
return result_data;
}
/* 继承指令工厂的类,生产人脸识别设备 */
struct InputCmd cameraControl = {
.cmdName = "camera",
.cmd = {'\0'},
.log = {'\0'},
.Init = cameraInit,
.getCmd = cameraGetCmd,
.ReadHandle = cameraReadHandle,
.next = NULL,
.img_buf = NULL,
.camera_buf = NULL,
};
/* 头插法加入链表,提供购买渠道,以供客户购买 */
struct InputCmd* addcameraControlToInputCmdLink(struct InputCmd *phead)
{
if(phead == NULL){
phead = &cameraControl;
return phead;
}else{
cameraControl.next = phead;
phead = &cameraControl;
return phead;
}
}
.
主文件 main.c
主线程 main()
.
语音线程
/* 语音线程执行函数 */
void *voice_thread(void *data)
{
struct InputCmd *voiceHandle = NULL;
struct Devices *devicesHandle = NULL;
char behavior[32];
char room[32];
char *tmp;
int n_read = 0;
voiceHandle = findCmdByName("voice",pCmdHead); //找到指令工厂的语音控制设备
if(voiceHandle == NULL){
printf("find voiceHandle error\n");
pthread_exit(NULL);
}else{
if(voiceHandle->Init(voiceHandle,NULL,NULL) < 0){
printf("voice Init error\n");
pthread_exit(NULL);
}
while(1){
n_read = voiceHandle->getCmd(voiceHandle);
if(n_read == 0){
printf("no data from voice\n");
}else{
/* 获取命令和设备名称 */
memset(behavior,'\0',sizeof(behavior));
tmp = strtok(voiceHandle->cmd," ");
strcat(behavior,tmp); //命令:open or close
printf("behavior:%s\n",behavior);
memset(room,'\0',sizeof(room));
tmp = strtok(NULL," ");
strcat(room,tmp); //产品工厂的设备名称
printf("room:%s\n",room);
devicesHandle = findDeviceByName(room,pDevicesHead); //找到产品工厂的设备
if(devicesHandle != NULL && strcmp(behavior,"open") == 0){
devicesHandle->devicesInit(devicesHandle->pinNum);
devicesHandle->open(devicesHandle->pinNum);
}
if(devicesHandle != NULL && strcmp(behavior,"close") == 0){
devicesHandle->devicesInit(devicesHandle->pinNum);
devicesHandle->close(devicesHandle->pinNum);
}
/* 如果是人脸识别命令,则拍照并进行人脸识别 */
if(strcmp(room,"face") == 0){
pthread_create(&camera_pid,NULL,camera_thread,NULL); //摄像头线程建立
pthread_join(camera_pid,NULL);
}
}
}
}
}
该线程的功能主要是:
接收主人的命令,根据命令来调用产品工厂不同的设备实现不同的功能,如开灯、关灯、人脸识别等等,使用人脸识别设备时会建立人脸识别线程。
.
人脸识别线程
/* 人脸识别线程执行函数 */
void *camera_thread(void *data)
{
struct InputCmd *cameraHandle = NULL;
struct Devices *devicesHandle = NULL;
float face_result;
cameraHandle = findCmdByName("camera",pCmdHead); //找到指令工厂的人脸识别设备
if(cameraHandle == NULL){
printf("find voiceHandle error\n");
pthread_exit(NULL);
}else{
if(cameraHandle->Init(cameraHandle,NULL,NULL) < 0){
printf("camera Init error\n");
pthread_exit(NULL);
}
cameraHandle->getCmd(cameraHandle); //调用祥云平台进行人脸识别
/* 根据人脸识别结果进行控制行为 */
if(cameraHandle->face_data > 0.75){ //主人回家了,开门
printf("same\n");
devicesHandle = findDeviceByName("lock",pDevicesHead); //找到产品工厂的锁设备
if(devicesHandle != NULL){
devicesHandle->devicesInit(devicesHandle->pinNum);
devicesHandle->open(devicesHandle->pinNum);
sleep(10);
devicesHandle->close(devicesHandle->pinNum);
pthread_exit(NULL);
}
}else{
printf("no same\n"); //不是主人回家了,不开门,并报警
devicesHandle = findDeviceByName("buzzer",pDevicesHead); //找到指令工厂的警报器设备
if(devicesHandle != NULL){
devicesHandle->devicesInit(devicesHandle->pinNum);
devicesHandle->open(devicesHandle->pinNum);
sleep(3);
devicesHandle->close(devicesHandle->pinNum);
pthread_exit(NULL);
}
}
}
}
该线程的功能主要是:
调用摄像头拍照进行人脸识别,如果不是主人进行的人脸识别会调用警报器设备进行报警,如果是主人进行的人脸识别会调用锁设备进行开锁。
.
火灾监测线程
/* 火灾监测线程执行函数 */
void *fire_thread(void *data)
{
struct Devices *fireHandle = NULL;
struct Devices *devicesHandle = NULL;
int fireStatus = 1;
fireHandle = findDeviceByName("fire",pDevicesHead); //找到产品工厂的火灾设备
if(fireHandle == NULL){
printf("find fireHandle error\n");
pthread_exit(NULL);
}else{
fireHandle->devicesInit(fireHandle->pinNum);
while(1){
fireStatus = fireHandle->readStatus(fireHandle->pinNum);
//printf("fireStatus:%d\n",fireStatus);
delay(125);
if((fireStatus) == 0){
firetype = 1;
devicesHandle = findDeviceByName("buzzer",pDevicesHead); //找到指令工厂的报警器设备
if(devicesHandle != NULL){
devicesHandle->open(devicesHandle->pinNum);
}
}else if(fireStatus == 1){
firetype = 0;
devicesHandle = findDeviceByName("buzzer",pDevicesHead); //找到指令工厂的报警器设备
if(devicesHandle != NULL){
devicesHandle->close(devicesHandle->pinNum);
}
}
}
}
}
该线程的功能主要是:
监测房子附近的火灾的发生情况,如果发生火灾会调用警报器设备进行报警,同时在手机APP上也会显示火灾的发生情况,在后面的sever控制线程会进行详述。
.
地震监测线程
/* 地震监测线程执行函数 */
void *shock_thread(void *data)
{
struct Devices *shockHandle = NULL;
struct Devices *devicesHandle = NULL;
int shockStatus = 1;
shockHandle = findDeviceByName("shock",pDevicesHead); //找到产品工厂的地震监测设备
if(shockHandle == NULL){
printf("find shockHandle error\n");
pthread_exit(NULL);
}else{
shockHandle->devicesInit(shockHandle->pinNum);
while(1){
shockStatus = shockHandle->readStatus(shockHandle->pinNum);
//printf("shockStatus:%d\n",shockStatus);
delay(125);
if((shockStatus) == 0){
shocktype = 1;
devicesHandle = findDeviceByName("buzzer",pDevicesHead); //找到指令工厂的报警器设备
if(devicesHandle != NULL){
devicesHandle->open(devicesHandle->pinNum);
}
}else if(shockStatus == 1){
shocktype = 0;
devicesHandle = findDeviceByName("buzzer",pDevicesHead); //找到指令工厂的报警器设备
if(devicesHandle != NULL){
devicesHandle->close(devicesHandle->pinNum);
}
}
}
}
}
该线程的功能主要是:
监测房子附近的地震的发生情况,如果发生地震会调用警报器设备进行报警,同时在手机APP上也会显示地震的发生情况,在后面的sever控制线程会进行详述。
.
温湿度检测线程
/* 温度检测线程执行函数 */
void *sensor_thread(void *data){
struct Devices *sensorHandle = NULL;
sensorHandle = findDeviceByName("sensor",pDevicesHead); //找到产品工厂的温湿度检测设备
if(sensorHandle == NULL){
printf("find sensorHandle error\n");
pthread_exit(NULL);
}else{
sensorHandle->devicesInit(sensorHandle->pinNum);
while(1){
sensorHandle->devicesInit(sensorHandle->pinNum);
delay(2000);
/* 获取空气中的温室度 */
if (sensorHandle->readData(sensorHandle,sensorHandle->pinNum)){
printf("Congratulations ! Sensor data read ok!\n");
printf("RH:%d.%d\n", (sensorHandle->databuf >> 24) & 0xff, (sensorHandle->databuf >> 16) & 0xff);
printf("TMP:%d.%d\n", (sensorHandle->databuf >> 8) & 0xff, sensorHandle->databuf & 0xff);
memset(sensorToStr,'\0',sizeof(sensorToStr));
sprintf(sensorToStr,"Temperature: %d.%dC Humidity: %d.%dhPa",(sensorHandle->databuf >> 8) & 0xff, sensorHandle->databuf & 0xff,(sensorHandle->databuf >> 24) & 0xff, (sensorHandle->databuf >> 16) & 0xff);
sensorHandle->databuf = 0;
printf("%s\n",sensorToStr);
}
else{
printf("Sorry! Sensor dosent ans!\n");
sensorHandle->databuf = 0;
}
}
}
}
该线程的功能主要是:
调用温湿度检测设备获取空气中的温湿度,同时在手机APP上也会显示空气中的温湿度,在后面的sever控制线程会进行详述。
.
server控制线程
/* sever控制线程执行函数 */
void *server_thread(void *data)
{
int clen = sizeof(struct sockaddr_in);
struct sockaddr_in c_addr;
memset(&c_addr,0,sizeof(struct sockaddr_in));
pthread_t connect_pid;
serverHandle = findCmdByName("server",pCmdHead); //找到指令工厂的server控制设备
if(serverHandle == NULL){
printf("find serverHandle error\n");
pthread_exit(NULL);
}else{
if(serverHandle->Init(serverHandle,NULL,NULL) < 0){
printf("server Init error\n");
pthread_exit(NULL);
}
while(1){
c_fd = accept(serverHandle->sfd,(struct sockaddr *)&c_addr,&clen);
printf("have people\n");
pthread_create(&connect_pid,NULL,connect_thread,NULL); //建立客户端连接后处理线程
}
}
}
该线程的功能主要是:
调用server控制设备,架设socket服务器,等待客户端的连接,当客户端连接后会建立客户端连接后处理线程。
.
客户端连接后处理线程
/* 客户端连接后处理线程执行函数 */
void *connect_thread(void *data)
{
int n_read;
struct Devices *devicesHandle = NULL;
char behavior[32];
char room[32];
char *tmp;
pthread_create(&sendData_pid,NULL,sendData_thread,NULL); //建立发送数据线程
n_read = read(c_fd,serverHandle->cmd,sizeof(serverHandle->cmd)); //读取客户端的数据
if(n_read == -1){
perror("read");
}else if(n_read > 0){
printf("cmd: %s\n",serverHandle->cmd);
/* 获取命令和设备名称 */
memset(behavior,'\0',sizeof(behavior));
tmp = strtok(serverHandle->cmd," "); //命令:open or close
strcat(behavior,tmp);
printf("behavior:%s\n",behavior);
memset(room,'\0',sizeof(room));
tmp = strtok(NULL," ");
strcat(room,tmp); //产品工厂的设备名称
printf("room:%s\n",room);
devicesHandle = findDeviceByName(room,pDevicesHead); //找到产品工厂的设备
if(devicesHandle != NULL && strcmp(behavior,"open") == 0){
devicesHandle->devicesInit(devicesHandle->pinNum);
devicesHandle->open(devicesHandle->pinNum);
}
if(devicesHandle != NULL && strcmp(behavior,"close") == 0){
devicesHandle->devicesInit(devicesHandle->pinNum);
devicesHandle->close(devicesHandle->pinNum);
}
/* 如果是人脸识别命令,则拍照并进行人脸识别 */
if(strcmp(room,"face") == 0){
pthread_create(&camera_pid,NULL,camera_thread,NULL); //摄像头线程建立
pthread_join(camera_pid,NULL);
}
}else{
printf("client is quit\n");
}
}
该线程的功能主要是:
接收APP的命令,根据命令来调用不同的设备实现不同的功能,如开灯、关灯、人脸识别等等,使用人脸识别设备时会建立人脸识别线程,同时会建立发送数据线程,将火灾和地震的发生情况以及空气的温湿度发送给APP,在APP上显示这些信息。
.
发送数据线程
/* 发送数据线程执行函数 */
void *sendData_thread(void *data){
while(1){
delay(1000);
if(firetype == 1){
write(c_fd,"fire",4);
}else if(shocktype == 1){
write(c_fd,"shock",5);
}else{
write(c_fd,"1",1); //随便发个数据与客户端进行响应
}
write(c_fd,sensorToStr,strlen(sensorToStr));
}
}
该线程的功能主要是:
将火灾和地震的发生情况以及空气的温湿度发送给APP,在APP上显示这些信息。APP会通过Java和Android来实现,如果受限于本文篇幅将在下一篇文章带大家实现。
.
智能家居APP
该APP实现了以下功能:
- 架设客户端与树莓派建立网络链接。
- 接收来自树莓派的火灾发生情况和地震发生情况以及空气中的温湿度并显示在显示页面上。
- 在显示页面上显示树莓派摄像头的监控画面。
- 在控制页面上调用产品工厂不同的设备实现不同的功能,如开灯、关灯等等。
.
AndroidManiFest.xml
该文件主要是关于APP的配置:
- 一些权限
- 目标机器的SDK版本
- App的名字
- App的配置
- 配置第一个被加载的启动页面
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.haozige.learn"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" />
<uses-permission android:name="android.permission.INTERNET"/>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.example.haozige.learn.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.example.haozige.learn.DisplayActivity"
android:label="@string/title_activity_display" >
</activity>
<activity
android:name="com.example.haozige.learn.ControlActivity"
android:label="@string/title_activity_control" >
</activity>
</application>
</manifest>
.
倒计时页面
Java文件
package com.example.haozige.learn;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.content.Intent;
import android.view.Menu;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends Activity {
public TextView time;
public Handler h;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
time = (TextView) findViewById(R.id.daojishi);
h = new Handler(){@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
time.setText("" + msg.what);
}};
new Thread(new Runnable() {
public void run() {
for(int i = 5;i>0;i--){
Message msg = new Message();//事件的信息
msg.what = i;
//打电话,去把UI线程要显示(要处理)的事件交给Handler
h.sendMessage(msg);//成员方法textfun操控成员变量h
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//新建一个对象并且实例化为Intent来设置跳转的页面
Intent intent = new Intent(MainActivity.this,DisplayActivity.class);
//跳转
startActivity(intent);
}
}).start();
}
public void goMainDisplay(View v){
//新建一个对象并且实例化为Intent来设置跳转的页面
Intent intent = new Intent(this,DisplayActivity.class);
//跳转
startActivity(intent);
}
}
.
xml文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/b1"
tools:context=".MainActivity" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="5"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="欢迎来到浩子哥的智能家居APP"
android:textSize="30dp"
android:textStyle="bold"
android:textColor="#ffc0cb"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="5"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="5"
android:textSize="60dp"
android:textStyle="bold"
android:textColor="#000000"
android:id="@+id/daojishi"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="跳转到显示页面"
android:onClick="goMainDisplay"
android:background="@drawable/btn_selector"/>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
.
页面展示
.
显示页面
Java文件
package com.example.haozige.learn;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.Arrays;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.KeyEvent;
import android.view.View;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.EditText;
import android.widget.TextView;
@SuppressLint("HandlerLeak") public class DisplayActivity extends Activity {
public Handler h;
public TextView fire;
public TextView shock;
public TextView wendu;
//public TextView shidu;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_display);
fire = (TextView)findViewById(R.id.fire);
shock = (TextView)findViewById(R.id.shock);
wendu = (TextView)findViewById(R.id.wendu);
//shidu = (TextView)findViewById(R.id.shidu);
h = new Handler(){
//区分事件的类型
@SuppressLint("HandlerLeak") public void handleMessage(Message msg) {
super.handleMessage(msg);
Bundle b = msg.getData();
String string = b.getString("dataMsg");
//fire.setTextColor(0xff0000ff);
if(string.contains("shock") == true){
shock.setText("Shock: abnormal");
}else if(string.contains("fire") == true){
fire.setText("Fire: abnormal");
}else if(string.contains("Temperature") == true){
wendu.setText(string);
}else if(string.contains("Humidity") == true){
//shidu.setText(string);
}else{
fire.setText("Fire: normal");
shock.setText("Shock: normal");
}
}
};
View v = findViewById(R.id.beijing);
v.getBackground().setAlpha(230);
//系统默认会通过手机浏览器打开网页
final WebView wb = (WebView) findViewById(R.id.webView);
//想要直接通过WebView显示网页,需要调用以下方法
wb.setWebViewClient(new WebViewClient());
final EditText et = (EditText) findViewById(R.id.et);
//按下回车获取文本框内容
et.setOnEditorActionListener(new TextView.OnEditorActionListener() {
public boolean onEditorAction(TextView arg0, int arg1, KeyEvent event) {
String str = et.getText().toString();
wb.loadUrl(str);
return (event.getKeyCode() == KeyEvent.KEYCODE_ENTER);
}
});
}
public void requestServer(final String cmd){
new Thread(new Runnable() {
public void run() {
try {
final Socket client = new Socket("192.168.104.61", 8801);
OutputStream out = null;
out = client.getOutputStream();
out.write(cmd.getBytes());
new Thread(new Runnable() {
byte[]data = new byte[128];
int readDataLen = 0;
//创建一个输入流对象,并且获得通道的输入流,在方法中,对变量赋值要在创建变量时完成
InputStream in = client.getInputStream();
public void run() {
String str;
while(true){
try {
readDataLen = in.read(data);
} catch (IOException e) {
e.printStackTrace();
}
//网络通信的数据类型都是byte类型,将byte类型数据转换为String类型
str = new String(data, 0, readDataLen);
Message msg = new Message(); //类Message用于发送数据
Bundle b = new Bundle(); //类Bundle用于发数据
b.putString("dataMsg", str);//根据键值获取数据
msg.setData(b); //
h.sendMessage(msg);
Arrays.fill(data,(byte)0);//byte类型数组清0的方法
readDataLen = 0;
}
}
}){}.start();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
public void requestData(View v){
if(v.getId() == R.id.requestButton){
requestServer("open haozige light");
}
}
public void goControl(View v){
//新建一个对象并且实例化为Intent来设置跳转的页面
Intent intent = new Intent(this,ControlActivity.class);
//跳转
startActivity(intent);
}
}
.
xml文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/zhutoucai"
tools:context=".DisplayActivity" >
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="4"
android:orientation="vertical"
android:background="#ffffff"
android:id="@+id/beijing">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_gravity="center">
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Temperature: 32.5C Humidity: 68.5hPa"
android:textSize="20dp"
android:textStyle="bold"
android:textColor="#ffc0cb"
android:id="@+id/wendu"/>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Fire: normal"
android:textSize="20dp"
android:textStyle="bold"
android:textColor="#ffc0cb"
android:id="@+id/fire"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:gravity="center_vertical">
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Shock: normal"
android:textSize="20dp"
android:textStyle="bold"
android:textColor="#ffc0cb"
android:id="@+id/shock"/>
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center_vertical">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="获取服务器数据"
android:background="@drawable/xuanzhe"
android:layout_marginBottom="3dp"
android:layout_marginLeft="3dp"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:id="@+id/requestButton"
android:onClick="requestData"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="10"
android:orientation="vertical">
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入网址"
android:id="@+id/et"
android:background="#ffcfcb"/>
<WebView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/webView"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="2"
android:orientation="vertical">
<TextureView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"/>
<Button
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:text="前往控制页面"
android:onClick="goControl"
android:id="@+id/gotoCmd"
android:textColor="#000000"
android:background="@drawable/btn_selector"/>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
.
页面展示
.
控制页面
Java文件
package com.example.haozige.learn;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
public class ControlActivity extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_control);
}
public void sendHandle(final String cmd){
new Thread(new Runnable() {
public void run() {
try {
final Socket client = new Socket("192.168.104.61", 8801);
OutputStream out = null;
out = client.getOutputStream();
out.write(cmd.getBytes());
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}).start();
}
public void sendcmd(View v){
switch(v.getId()){
case R.id.opsecond:
sendHandle("open secondfloor light");
break;
case R.id.clsecond:
sendHandle("close secondfloor light");
break;
case R.id.opliving:
sendHandle("open livingroom light");
break;
case R.id.clliving:
sendHandle("close livingroom light");
break;
case R.id.opbath:
sendHandle("open bathroom light");
break;
case R.id.clbath:
sendHandle("close bathroom light");
break;
case R.id.oprestaurant:
sendHandle("open restaurant light");
break;
case R.id.clrestaurant:
sendHandle("close restaurant light");
break;
case R.id.opswimming:
sendHandle("open swimming light");
break;
case R.id.clswimming:
sendHandle("close swimming light");
break;
case R.id.opfan:
sendHandle("open fan light");
break;
case R.id.clfan:
sendHandle("close fan light");
break;
case R.id.oplock:
sendHandle("open lock light");
break;
case R.id.cllock:
sendHandle("close lock light");
break;
case R.id.opbuzzer:
sendHandle("open buzzer light");
break;
case R.id.clbuzzer:
sendHandle("close buzzer light");
break;
}
}
public void goDisplay(View v){
//新建一个对象并且实例化为Intent来设置跳转的页面
Intent intent = new Intent(this,DisplayActivity.class);
//跳转
startActivity(intent);
}
}
.
xml文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#ffffff"
tools:context=".MainActivity" >
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<Button
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:text="前往显示页面"
android:onClick="goDisplay"
android:id="@+id/gotoDisplay"
android:textColor="#000000"
android:background="@drawable/xuanzhe"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextureView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<Button
android:layout_width="0dp"
android:layout_weight="10"
android:layout_height="wrap_content"
android:text="开二楼灯"
android:onClick="sendcmd"
android:id="@+id/opsecond"
android:textColor="#000000"
android:background="@drawable/btn_selector"/>
<TextureView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"/>
<Button
android:layout_width="0dp"
android:layout_weight="10"
android:layout_height="wrap_content"
android:text="关二楼灯"
android:textColor="#000000"
android:background="@drawable/btn_selector"
android:onClick="sendcmd"
android:id="@+id/clsecond"/>
<TextureView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextureView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
<Button
android:layout_width="0dp"
android:layout_weight="10"
android:layout_height="wrap_content"
android:text="开客厅灯"
android:onClick="sendcmd"
android:id="@+id/opliving"
android:textColor="#000000"
android:background="@drawable/btn_selector"/>
<TextureView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"/>
<Button
android:layout_width="0dp"
android:layout_weight="10"
android:layout_height="wrap_content"
android:text="关客厅灯"
android:textColor="#000000"
android:background="@drawable/btn_selector"
android:onClick="sendcmd"
android:id="@+id/clliving"/>
<TextureView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextureView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
/>
<Button
android:layout_width="0dp"
android:layout_weight="10"
android:layout_height="wrap_content"
android:text="开泳池灯"
android:onClick="sendcmd"
android:id="@+id/opswimming"
android:textColor="#000000"
android:background="@drawable/btn_selector"/>
<TextureView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
/>
<Button
android:layout_width="0dp"
android:layout_weight="10"
android:layout_height="wrap_content"
android:text="关泳池灯"
android:textColor="#000000"
android:background="@drawable/btn_selector"
android:onClick="sendcmd"
android:id="@+id/clswimming"/>
<TextureView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextureView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
/>
<Button
android:layout_width="0dp"
android:layout_weight="10"
android:layout_height="wrap_content"
android:text="开卫生间灯"
android:onClick="sendcmd"
android:id="@+id/opbath"
android:textColor="#000000"
android:background="@drawable/btn_selector"/>
<TextureView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
/>
<Button
android:layout_width="0dp"
android:layout_weight="10"
android:layout_height="wrap_content"
android:text="关卫生间灯"
android:textColor="#000000"
android:background="@drawable/btn_selector"
android:onClick="sendcmd"
android:id="@+id/clbath"/>
<TextureView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextureView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
/>
<Button
android:layout_width="0dp"
android:layout_weight="10"
android:layout_height="wrap_content"
android:text="开餐厅灯"
android:onClick="sendcmd"
android:id="@+id/oprestaurant"
android:textColor="#000000"
android:background="@drawable/btn_selector"/>
<TextureView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
/>
<Button
android:layout_width="0dp"
android:layout_weight="10"
android:layout_height="wrap_content"
android:text="关餐厅灯"
android:textColor="#000000"
android:background="@drawable/btn_selector"
android:onClick="sendcmd"
android:id="@+id/clrestaurant"/>
<TextureView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextureView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
/>
<Button
android:layout_width="0dp"
android:layout_weight="10"
android:layout_height="wrap_content"
android:text="开报警器"
android:onClick="sendcmd"
android:id="@+id/opbuzzer"
android:textColor="#000000"
android:background="@drawable/btn_selector"/>
<TextureView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
/>
<Button
android:layout_width="0dp"
android:layout_weight="10"
android:layout_height="wrap_content"
android:text="关报警器"
android:textColor="#000000"
android:background="@drawable/btn_selector"
android:onClick="sendcmd"
android:id="@+id/clbuzzer"/>
<TextureView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextureView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
/>
<Button
android:layout_width="0dp"
android:layout_weight="10"
android:layout_height="wrap_content"
android:text="开风扇"
android:onClick="sendcmd"
android:id="@+id/opfan"
android:textColor="#000000"
android:background="@drawable/btn_selector"/>
<TextureView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
/>
<Button
android:layout_width="0dp"
android:layout_weight="10"
android:layout_height="wrap_content"
android:text="关风扇"
android:textColor="#000000"
android:background="@drawable/btn_selector"
android:onClick="sendcmd"
android:id="@+id/clfan"/>
<TextureView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<TextureView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
/>
<Button
android:layout_width="0dp"
android:layout_weight="10"
android:layout_height="wrap_content"
android:text="开门"
android:onClick="sendcmd"
android:id="@+id/oplock"
android:textColor="#000000"
android:background="@drawable/btn_selector"/>
<TextureView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
/>
<Button
android:layout_width="0dp"
android:layout_weight="10"
android:layout_height="wrap_content"
android:text="关门"
android:textColor="#000000"
android:background="@drawable/btn_selector"
android:onClick="sendcmd"
android:id="@+id/cllock"/>
<TextureView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
/>
</LinearLayout>
</LinearLayout>
</RelativeLayout>
.