基于树莓派4B的智能家居

news2024/11/24 7:21:22

基于树莓派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>

.

页面展示

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/540395.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何创建样本手册?

第一步&#xff1a;提前研究和规划 首先明确目标客户群体在其中扮演的角色。 谁会穿你的衣服&#xff1f;您品牌的潜在客户是谁&#xff1f;他们的愿望是什么&#xff1f;他们会被什么打动&#xff1f;设置客户角色至关重要&#xff0c;因为它将决定样本手册的基调&#xff0…

Simulink 自动代码生成电机控制:模型仿真速度的优化

目录 方法一 Simulationmode 方法二 多核并行 方法三 Performance Advisor 总结 方法一 Simulationmode 执行下面的指令获取Simulink仿真实时&#xff0c;这里以霍尔FOC的模型为例&#xff0c;在切换模式为Accelerator时不能使用调用子模型的形式&#xff0c;需要把子模型复制…

map的forEach区别

map的forEach区别 先总结下&#xff1a; map和forEach区别是&#xff1a; 1.map有返回值而且必须return返回一个数组才行 ; 而forEach没有返回值可直接打印结果&#xff1b; 即&#xff1a;forEach()方法不会返回执行结果&#xff0c;而是undefined。也就是说&#xff0c;forEa…

vue 在线聊天实战范例(含选择发送表情、图片、视频、音频,自定义右键快捷菜单,一键复制,左右聊天气泡)

最终效果 完整代码 index.vue <template><div class"page"><div class"leftBox"><h1>访客</h1><div class"chatBox"><div class"chatRecordBox"><div v-for"(item, index) in cha…

DBCO-COOH分子量:305.3,CAS:1353016-70-2,二苯基环辛炔-羧基;类似有DBCO-NH2、SH、MAL、NHS等等

中文名称&#xff1a;二苯基环辛炔-羧基 英文名称&#xff1a;DBCO-acid 英文别称&#xff1a;DBCO-COOH cas: 1353016-70-2 分子式&#xff1a;C19H15NO3 分子量&#xff1a;305.3 DBCO-COOH是DBCO 衍生化的常用构件&#xff0c;在EDC、DCC和HATU等活化剂存在下&#xf…

linux kernel menuconfig kconfig makefile

概述 menuconfig是Linux平台用于管理代码工程、模块及功能的实用工具。 menuconfig的使用方式通常是在编译系统之前在系统源代码根目录下执行make menuconfig命令从而打开一个图形化配置界面&#xff0c;再通过对各项的值按需配置从而达到影响系统编译结果的目的。 Nuttx的me…

Spring Boot 数据库操作Druid和HikariDataSource

目录 Spring Boot 数据库操作 应用实例-需求 创建测试数据库和表 进行数据库开发&#xff0c; 在pom.xml 引入data-jdbc starter 参考官方文档 需要在pom.xml 指定导入数据库驱动 在application.yml 配置操作数据源的信息 创建bean\Furn.java 测试结果 整合Druid 到…

六、easyUI中的window(窗口)组件

1.window&#xff08;窗口&#xff09;组件的概述 窗口控件是一个浮动和可拖拽的面板&#xff0c;它可以用作应用程序窗口。默认情况下&#xff0c;窗口可以移动&#xff0c;调整大小和关闭。它的内容也可以被定义为静态HTML或要么通过Ajax动态加载 2.window&#xff08;窗口&…

MySQL-备份+日志:介质故障与数据库恢复

MySQL-备份日志&#xff1a;介质故障与数据库恢复 第1关&#xff1a;备份与恢复任务描述相关知识MySQL的恢复机制MySQL的备份与恢复工具编程要求代码参考 第2关 备份日志&#xff1a;介质故障的发生与数据库的恢复任务描述相关知识编程要求测试说明代码参考 第1关&#xff1a;备…

《分布式微服务电商源码》-项目简介

1.常见的电商模式 市面上有 5 种常见的电商模式 B2B、B2C、C2B、C2C、O2O 1.1.B2B 模式 B2B(Business to Business)&#xff0c;是指商家和商家建立的商业关系&#xff0c;如阿里巴巴. 1.2.B2C 模式 B2C(Business to Consumer) 就是我们经常看到的供应商直接把商品买个用户&a…

057:cesium设置纯颜色材质

第057个 点击查看专栏目录 本示例的目的是介绍如何在vue+cesium中设置纯颜色的材质,颜色的表达方式可以参考这篇文章 Cesium七种方法设置颜色 直接复制下面的 vue+cesium源代码,操作2分钟即可运行实现效果. 文章目录 示例效果配置方式示例源代码(共87行)相关API参考:专…

用友BIP新零售产品发布,与零售企业共创新未来

随着数智化时代的到来&#xff0c;零售企业不断面临着更多的挑战和机遇。为了满足消费者多元化的需求&#xff0c;零售企业需要采用多种方式来提高竞争力&#xff0c;如多渠道销售、线上线下融合、数智化运营、个性化营销和无缝化体验等。用友BIP新零售为零售企业提供了数智化转…

Jenkins的持续集成与持续部署

系统总体架构 Gitlab Gitlab是一款主要用于代码管理的工具&#xff0c;相较于GitHub&#xff0c;可以自己搭建服务器&#xff0c;这可以避免因为网络速度慢导致部署效率低下&#xff0c;同时&#xff0c;自己搭建服务器&#xff0c;安全性更高。Jenkins Jenkins主要用于管理版本…

改图片分辨率:提升图像质量的关键步骤

无论您是一名摄影师、设计师&#xff0c;还是一个爱好者&#xff0c;改变图片分辨率都是必不可少的工作。在本文中&#xff0c;我们将介绍改图片分辨率的作用以及它在哪些场景下使用。 改图片分辨率介绍 图片分辨率是指图像中所包含的像素数量&#xff0c;通常以“每英寸像素…

threejs 相机OrbitControls常用方法及属性

相机控件OrbitControls 通过OrbitControls可以对三维场景进行缩放、平移、旋转&#xff0c;本质上改变的不是场景&#xff0c;而是相机的参数&#xff0c;相机的位置角度不同&#xff0c;同一个场景的渲染效果是不一样&#xff0c;比如相机围绕着一个场景旋转&#xff0c;就像…

有哪些工具软件一旦用了就离不开?

&#x1f496;前言 目前&#xff0c;随着科技的快速发展&#xff0c;电脑已经进入了许许多多人的生活 &#xff0c;在平日的学习、工作和生活里&#xff0c;我们会用的各种各样的强大软件。市面上除了某些大公司开发在强大软件&#xff0c;还有各路大神开发具有某些功能的强大…

nodejs+vue网上课程在线教学网站平台a53y0

(1) vue引入elementui 1.使用npm安装element-ui npm i element-ui -S 2.在main.js中导入使用vue import element-ui/lib/theme-chalk/index.css //别忘了导入样式 import ElementUI from element-ui Vue.use(ElementUI) 后端&#xff1a;java(springbootssm)/python/php/node…

MySQL入门到精通——运维篇(基础篇——进阶篇——运维篇)本文以MySQL8.0版本以上为例

文章目录 前言MySQL——运维篇一、日志1.日志-错误日志2.日志-二进制日志3.日志-查询日志4.日志-慢查询日志 二、主从复制1.主从复制-概述2.主从复制-原理3.主从复制-搭建3.1.主从复制-搭建-主库配置3.2.主从复制-搭建-从库配置3.2.主从复制-搭建-测试 三、分库分表1.分库分表-…

Nacos简介和安装

1.Nacos简介 1.1.为什么叫Nacos 前四个字母分别为Naming和Configuration的前两个字母&#xff0c;最后的s为Service。 1.2.是什么 一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。Nacos: Dynamic Naming and Configuration ServiceNacos就是注册中心&am…

Fiddler 到底能做什么?一篇文章给你详细介绍

Fiddler是检查 Http 流量的最流行的工具之一。此工具可帮助我们非常轻松地测试 REST API / SOAP Web 请求。 题主的问题&#xff1a;Fiddler 到底能做什么。仔细思考&#xff0c;其实有两层意思&#xff1a; 第一层&#xff1a;Fiddler工具的应用范围 第二层&#xff1a;Fiddl…