随着智能家居逐渐融入日常生活,智能家居的控制方法与智能话手段也在不断革新。传统的使用手机软件点击操控控制的方法,复杂而不实用。同时当前智能家居体验割裂严重,由于智能家居设备的高度相互独立性,即在单个家居产品足够智能化的同时多个家居的联动体验较差,经常需要在手机上下载不同的软件以适应不同品牌产品的差异。
同时对生产厂家而言消除这样的差异也并不容易,由于信息差、智能家居产品功能性能要求各不相同、其内核、芯片和设计底层架构不同,难以实现同步设备差异以达到目标效果
在此有以下的解决方案:如米家通过全线生产智能家居产品实现良好的互联效果;如(未来的)鸿蒙通过类似电脑的操作系统,针对不同资源受限的设备选用合适的OS内核,内核抽象层KAL通过屏蔽多内核差异,对上层提供极差的内核能力,通过HDF驱动框架提供统一的外设访问能力和驱动开发,管理框架。
本作品基于OpenHarmony开源鸿蒙操作系统对智能家居的构想实现了一个简单的通过系统进行差异化的资源分配然后对上层提供统一的基础内核能力的智能家居互联产品。其功能如下:
关键词:智能家居 语音控制 Openharmony
性能要求:
功能分析:
系统方案设计
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2EKWLntK-1653230470807)(/img/1.png)]
2016年3月,小米正式发布米家品牌,以承载小米生态链公司的智能家居产品。通过米家APP可以控制家庭的智能设备,并能够实现智能设备之间的互联互通。
米家产品主要核心在于联动与自家有关的设备(米家家居设备),同时打造价格实惠,配网方便简单,操作简单的亲民产品
以华为全屋智能为例,多条件动态预判、智能布防撤防、精细化控制管理、
华为智慧生活提供的是一个平台,供各个终端共同联动,理论上可以接入所有支持openharmony/harmonyos的设备,即除了自身生态链产品外,也提供了美的,格力和海尔等第三方品牌接入,与华为智能家居联动
本文依据OpenHarmony技术特性简单打造了一个基于Openharmony的智能家居微型系统。通过借助手机自带的语音助手,实现对智能家居的电器控制(本作品以点亮led灯为例),极大的方便了传统上通过手机软件控制的繁杂方法。
其本质依然是通过语音助手执行脚本访问url,从而实现远程控制。作品使用支持搭载OpenHarmony操作系统和WIFI模块的Neptune开发板,实现在智能家居场景下的简单控制。
OpenHarmony整体遵从分层设计,从下向上依次为:内核层、系统服务层、框架层和应用层。系统功能按照“系统 > 子系统 > 组件”逐级展开,在多设备部署场景下,支持根据实际需求裁剪某些非必要的组件。OpenHarmony技术架构如下所示:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-u7ul3QVo-1653230470808)(…/img/2.png)]
内核层
内核子系统:采用多内核(Linux内核或者LiteOS)设计,支持针对不同资源受限设备选用适合的OS内核。内核抽象层(KAL,Kernel Abstract Layer)通过屏蔽多内核差异,对上层提供基础的内核能力,包括进程/线程管理、内存管理、文件系统、网络管理和外设管理等。
驱动子系统:驱动框架(HDF)是系统硬件生态开放的基础,提供统一外设访问能力和驱动开发、管理框架。
系统服务层
系统服务层是OpenHarmony的核心能力集合,通过框架层对应用程序提供服务。该层包含以下几个部分:
系统基本能力子系统集:为分布式应用在多设备上的运行、调度、迁移等操作提供了基础能力,由分布式软总线、分布式数据管理、分布式任务调度、公共基础库、多模输入、图形、安全、AI等子系统组成。
基础软件服务子系统集:提供公共的、通用的软件服务,由事件通知、电话、多媒体、DFX(Design For X) 等子系统组成。
增强软件服务子系统集:提供针对不同设备的、差异化的能力增强型软件服务,由智慧屏专有业务、穿戴专有业务、IoT专有业务等子系统组成。
硬件服务子系统集:提供硬件服务,由位置服务、用户IAM、穿戴专有硬件服务、IoT专有硬件服务等子系统组成。
根据不同设备形态的部署环境,基础软件服务子系统集、增强软件服务子系统集、硬件服务子系统集内部可以按子系统粒度裁剪,每个子系统内部又可以按功能粒度裁剪。
框架层
框架层为应用开发提供了C/C++/JS等多语言的用户程序框架和Ability框架,适用于JS语言的ArkUI框架,以及各种软硬件服务对外开放的多语言框架API。根据系统的组件化裁剪程度,设备支持的API也会有所不同。
应用层
应用层包括系统应用和第三方非系统应用。应用由一个或多个FA(Feature Ability)或PA(Particle Ability)组成。其中,FA有UI界面,提供与用户交互的能力;而PA无UI界面,提供后台运行任务的能力以及统一的数据访问抽象。基于FA/PA开发的应用,能够实现特定的业务功能,支持跨设备调度与分发,为用户提供一致、高效的应用体验。
主要通过下列模块达成
分布式软总线
分布式数据管理
分布式任务调度
设备虚拟化
OpenHarmony提供用户程序框架、Ability框架以及UI框架,能够保证开发的应用在多终端运行时保证一致性。一次开发、多端部署。
多终端软件平台API具备一致性,确保用户程序的运行兼容性。
OpenHarmony通过组件化和组件弹性化等设计方法,做到硬件资源的可大可小,在多种终端设备间,按需弹性部署,全面覆盖了ARM、RISC-V、x86等各种CPU,从百KiB到GiB级别的RAM。
OpenHarmony支持如下几种系统类型:
轻量系统(mini system)
小型系统(small system)
标准系统(standard system)
根据设备能力不同,总共分为L0-L5级别,它们所代表的领域,如下:
本作品基于真实的家居环境使用基于Lite-OS子系统的Neptune开发板:(模拟微型无显示屏外设,具备简单控制和运算能力)
实现功能: 通过终端使用语音助手识别发出的语音指令,与开发板建立tcp连接并驱动开发板输出低电平,点亮led灯
系统架构如下:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RaaJdrpl-1653230470808)(…/img/3.png)]
TCP/IP 是用于因特网 (Internet) 的通信协议。 TCP/IP 通信协议是对计算机必须遵守的规则的描述,只有遵守这些规则,计算机之间才能进行通信。
TCP (Transmission Control Protocol)和UDP(User Datagram Protocol)协议属于传输层协议。其中TCP提供IP环境下的数据可靠传输,它提供的服务包括数据流传送、可靠性、有效流控、全双工操作和多路复 用。通过面向连接、端到端和可靠的数据包发送。通俗说,它是事先为所发送的数据开辟出连接好的通道,然后再进行数据发送;而UDP则不为IP提供可靠性、 流控或差错恢复功能。一般来说,TCP对应的是可靠性要求高的应用,而UDP对应的则是可靠性要求低、传输经济的应用。 TCP支持的应用协议主要有:Telnet、FTP、SMTP等; UDP支持的应用层协议主要有:NFS(网络文件系统)、SNMP(简单网络管理协议)、DNS(主域名称系统)、TFTP(通用文件传输协议)等。 TCP/IP协议与低层的数据链路层和物理层无关,这也是TCP/IP的重要特点
TCP(Transimision Control Protocal)特点:
协议的分层
网络协议通常分不同层次进行开发,每一层分别负责不同的通信功能。一个协议族,比如TCP/IP,是一组不同层次上的多个协议的组合。 传统上来说 TCP/IP 被认为是一个四层协议, 而ISO(国际标准化组织),制定了一个国际标准OSI七层协议模型,OSI协议以OSI参考模型为基础界定了每个阶层的协议和每个阶层之间接口相关的标准。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BWyruMpM-1653230470809)(…/img/4.jpg)]
分层的作用:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-glWZcfYY-1653230470809)(…/img/5.jpg)]
tcp属于传输层协议,socket属于传输层与应用层之间的抽象层
本作品使用tcp服务端与tcp客户端之间进行socket通信。
简单的说,socket是tcpip的具体实现流程,是把TCP协议层的数据发送、接收等的封装。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2goW1PpJ-1653230470810)(…/img/6.jpg)]
socket技术是以TCP/IP协议为基础的一组接口函数,应用于通信环节中,在协议中TCP需要建立三次握手的过程建立连接。其中socket定义了三次握手:
在计算机通信领域,socket 被翻译为“套接字”,它是计算机之间进行通信的一种约定或一种方式。通过 socket 这种约定,一台计算机可以接收其他计算机的数据,也可以向其他计算机发送数据。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-l0Yt3adi-1653230470810)(…/img/7.jpg)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WgGKaNY0-1653230470810)(…/img/8.jpg)]
1. 使用socket()函数创建套接字
int socket(int af, int type, int protocol);
af 为地址族(Address Family),也就是 IP 地址类型,常用的有 AF_INET 和 AF_INET6。AF 是“Address Family”的简写,INET是“Inetnet”的简写。AF_INET 表示 IPv4 地址,例如 127.0.0.1;AF_INET6 表示 IPv6 地址,例如 1030::C9B4:FF12:48AA:1A2B。
大家需要记住127.0.0.1,它是一个特殊IP地址,表示本机地址,后面的教程会经常用到。
type 为数据传输方式,常用的有 SOCK_STREAM 和 SOCK_DGRAM
protocol 表示传输协议,常用的有 IPPROTO_TCP 和 IPPTOTO_UDP,分别表示 TCP 传输协议和 UDP 传输协议
3. 使用bind()和connect()函数
int bind(int sock, struct sockaddr *addr, socklen_t addrlen);
int connect(int sock, struct sockaddr *serv_addr, socklen_t addrlen);
4. 使用listen()和accept()函数
int listen(int sock, int backlog);
5.请求队列
当套接字正在处理客户端请求时,如果有新的请求进来,套接字是没法处理的,只能把它放进缓冲区,待当前请求处理完毕后,再从缓冲区中读取出来处理。如果不断有新的请求进来,它们就按照先后顺序在缓冲区中排队,直到缓冲区满。这个缓冲区,就称为请求队列(Request Queue)。
缓冲区的长度(能存放多少个客户端请求)可以通过 listen() 函数的 backlog 参数指定,但究竟为多少并没有什么标准,可以根据你的需求来定,并发量小的话可以是10或者20。
如果将 backlog 的值设置为 SOMAXCONN,就由系统来决定请求队列长度,这个值一般比较大,可能是几百,或者更多。
当请求队列满时,就不再接收新的请求,对于 Linux,客户端会收到 ECONNREFUSED 错误
注意:listen() 只是让套接字处于监听状态,并没有接收请求。接收请求需要使用 accept() 函数。
当套接字处于监听状态时,可以通过 accept() 函数来接收客户端请求。它的原型为:
int accept(int sock, struct sockaddr *addr, socklen_t *addrlen);
它的参数与 listen() 和 connect() 是相同的:sock 为服务器端套接字,addr 为 sockaddr_in 结构体变量,addrlen 为参数 addr 的长度,可由 sizeof() 求得。
accept() 返回一个新的套接字来和客户端通信,addr 保存了客户端的IP地址和端口号,而 sock 是服务器端的套接字,大家注意区分。后面和客户端通信时,要使用这个新生成的套接字,而不是原来服务器端的套接字。
最后需要说明的是:listen() 只是让套接字进入监听状态,并没有真正接收客户端请求,listen() 后面的代码会继续执行,直到遇到 accept()。accept() 会阻塞程序执行(后面代码不能被执行),直到有新的请求到来。
6.socket数据的接收和发送
Linux下数据的接收和发送
Linux 不区分套接字文件和普通文件,使用 write() 可以向套接字中写入数据,使用 read() 可以从套接字中读取数据。
前面我们说过,两台计算机之间的通信相当于两个套接字之间的通信,在服务器端用 write() 向套接字写入数据,客户端就能收到,然后再使用 read() 从套接字中读取出来,就完成了一次通信。
write() 的原型为:
ssize_t write(int fd, const void *buf, size_t nbytes);
fd 为要写入的文件的描述符,buf 为要写入的数据的缓冲区地址,nbytes 为要写入的数据的字节数。
write() 函数会将缓冲区 buf 中的 nbytes 个字节写入文件 fd,成功则返回写入的字节数,失败则返回 -1。
read() 的原型为:
ssize_t read(int fd, void *buf, size_t nbytes);
fd 为要读取的文件的描述符,buf 为要接收数据的缓冲区地址,nbytes 为要读取的数据的字节数。
read() 函数会从 fd 文件中读取 nbytes 个字节并保存到缓冲区 buf,成功则返回读取到的字节数(但遇到文件结尾则返回0),失败则返回 -1。
7.socket缓冲区以及阻塞模式
每个 socket 被创建后,都会分配两个缓冲区,输入缓冲区和输出缓冲区。
缓冲区
write()/send() 并不立即向网络中传输数据,而是先将数据写入缓冲区中,再由TCP协议将数据从缓冲区发送到目标机器。一旦将数据写入到缓冲区,函数就可以成功返回,不管它们有没有到达目标机器,也不管它们何时被发送到网络,这些都是TCP协议负责的事情。
TCP协议独立于 write()/send() 函数,数据有可能刚被写入缓冲区就发送到网络,也可能在缓冲区中不断积压,多次写入的数据被一次性发送到网络,这取决于当时的网络情况、当前线程是否空闲等诸多因素,不由程序员控制。
read()/recv() 函数也是如此,也从输入缓冲区中读取数据,而不是直接从网络中读取
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fKFpengV-1653230470810)(…/img/9.png)]
这些I/O缓冲区特性可整理如下:
unsigned optVal;
int optLen = sizeof(int);
getsockopt(servSock, SOL_SOCKET, SO_SNDBUF, (char*)&optVal, &optLen);
printf("Buffer length: %d\n", optVal);
阻塞模式
对于TCP套接字(默认情况下),当使用 write()/send() 发送数据时:
当使用 read()/recv() 读取数据时:
TCP套接字默认情况下是阻塞模式
本作品选用集合WIFI与蓝牙双模的OpenHarmony开发板Neptune
基于选用Openharmony操作系统的开发板思路,我们选择以下开发板:
Neptune是一款基于w800芯片的开发板,w800是由“北京联盛德微电子有限责任公司(Winner Micro)”推出的一款芯片,基于C-SKY架构的用于物联网的32位芯片。
开发板具有代表性:成本低,纯内核层操作,适合智能家居小型系统,适用广泛。
硬件原理图
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Jba7yGdL-1653230470811)(…/img/10.png)]
软件部分分为:
操作系统的编译与烧录
网页设计
语音助手的脚本编写
核心内容为:驱动GPIO输出低电平
enum LedState {
LED_ON = 0,
LED_OFF,
LED_SPARK,
};
enum LedState g_ledState = LED_SPARK;
static void* GpioTask(const char* arg)
{
printf("****************");
printf("led load success");
printf("****************");
(void)arg;
while (1) {
switch (g_ledState) {
case LED_ON:
printf(" LED_ON! \n");
GpioSetOutputVal(WIFI_IOT_GPIO_PB_08, WIFI_IOT_GPIO_VALUE0);
osDelay(500);
break;
case LED_OFF:
printf(" LED_OFF! \n");
GpioSetOutputVal(WIFI_IOT_GPIO_PB_08, WIFI_IOT_GPIO_VALUE1);
osDelay(500);
break;
case LED_SPARK:
printf(" LED_SPARK! \n");
GpioSetOutputVal(WIFI_IOT_GPIO_PB_08, WIFI_IOT_GPIO_VALUE0);
osDelay(100);
GpioSetOutputVal(WIFI_IOT_GPIO_PB_08, WIFI_IOT_GPIO_VALUE1);
osDelay(100);
break;
default:
osDelay(500);
break;
}
}
return NULL;
}
static void GpioIsr(char* arg)
{
(void)arg;
enum LedState nextState = LED_SPARK;
printf(" GpioIsr entry\n");
GpioSetIsrMask(WIFI_IOT_GPIO_PB_09, 0);
switch (g_ledState) {
case LED_ON:
nextState = LED_OFF;
break;
case LED_OFF:
nextState = LED_ON;
break;
case LED_SPARK:
nextState = LED_OFF;
break;
default:
break;
}
g_ledState = nextState;
}
static void GpioExampleEntry(void)
{
osThreadAttr_t attr;
GpioInit();
GpioSetDir(WIFI_IOT_GPIO_PB_08, WIFI_IOT_GPIO_DIR_OUTPUT); // output is 0 PB08 control led
GpioSetDir(WIFI_IOT_GPIO_PB_09, WIFI_IOT_GPIO_DIR_INPUT); // input is PB09
IoSetPull(WIFI_IOT_GPIO_PB_09, WIFI_IOT_GPIO_ATTR_PULLHIGH);
GpioRegisterIsrFunc(WIFI_IOT_GPIO_PB_09, WIFI_IOT_INT_TYPE_EDGE, WIFI_IOT_GPIO_EDGE_FALL_LEVEL_LOW, GpioIsr, NULL);
attr.name = "GpioTask";
attr.attr_bits = 0U;
attr.cb_mem = NULL;
attr.cb_size = 0U;
attr.stack_mem = NULL;
attr.stack_size = LED_TASK_STACK_SIZE;
attr.priority = LED_TASK_PRIO;
if (osThreadNew((osThreadFunc_t)GpioTask, NULL, &attr) == NULL) {
printf("[GpioExample] Falied to create GpioTask!\n");
}
}
SYS_RUN(GpioExampleEntry); // if test add it
Neptune服务端(核心代码)
static char request[128] = "";
void TcpServerTest(unsigned short port)
{
printf("*********************TCP server test *****************");
int retval = 0;
int backlog = 1;
int sockfd = socket(AF_INET, SOCK_STREAM, 0); // TCP socket
int connfd = -1;
struct sockaddr_in clientAddr = {0};
socklen_t clientAddrLen = sizeof(clientAddr);
struct sockaddr_in serverAddr = {0};
serverAddr.sin_family = AF_INET;
serverAddr.sin_port = htons(port); // 端口号,从主机字节序转为网络字节序
serverAddr.sin_addr.s_addr = htonl(INADDR_ANY); // 允许任意主机接入, 0.0.0.0
retval = bind(sockfd, (struct sockaddr *)&serverAddr, sizeof(serverAddr)); // 绑定端口
if (retval < 0) {
printf("bind failed, %ld!\r\n", retval);
goto do_cleanup;
}
printf("bind to port %d success!\r\n", port);
retval = listen(sockfd, backlog); // 开始监听
if (retval < 0) {
printf("listen failed!\r\n");
goto do_cleanup;
}
printf("listen with %d backlog success!\r\n", backlog);
// 接受客户端连接,成功会返回一个表示连接的 socket , clientAddr 参数将会携带客户端主机和端口信息 ;失败返回 -1
// 此后的 收、发 都在 表示连接的 socket 上进行;之后 sockfd 依然可以继续接受其他客户端的连接,
// UNIX系统上经典的并发模型是“每个连接一个进程”——创建子进程处理连接,父进程继续接受其他客户端的连接
// 鸿蒙liteos-a内核之上,可以使用UNIX的“每个连接一个进程”的并发模型
// liteos-m内核之上,可以使用“每个连接一个线程”的并发模型
connfd = accept(sockfd, (struct sockaddr *)&clientAddr, &clientAddrLen);
if (connfd < 0) {
printf("accept failed, %d, %d\r\n", connfd, errno);
goto do_cleanup;
}
printf("accept success, connfd = %d!\r\n", connfd);
printf("client addr info: host = %s, port = %d\r\n", inet_ntoa(clientAddr.sin_addr), ntohs(clientAddr.sin_port));
// 后续 收、发 都在 表示连接的 socket 上进行;
retval = recv(connfd, request, sizeof(request), 0);
if (retval < 0) {
printf("recv request failed, %ld!\r\n", retval);
goto do_disconnect;
}
printf("recv request{%s} from client done!\r\n", request);
retval = send(connfd, request, strlen(request), 0);
if (retval <= 0) {
printf("send response failed, %ld!\r\n", retval);
goto do_disconnect;
}
printf("send response{%s} to client done!\r\n", request);
do_disconnect:
osDelay(500);
close(connfd);
osDelay(500);; // for debug
do_cleanup:
printf("do_cleanup...\r\n");
close(sockfd);
}
SERVER_TEST_DEMO(TcpServerTest);
作品通过WINNER MICRO官方提供的烧录工具Upgrade_Tools进行烧录和串口调试,串口打印如下:
Begin to run the OHOS SYSTEM
Begin to run the user main
user task:17:20:53:May 17 2022
ble_npl_eventq_init:bigger queue 64
load our sec; addr=0x1e 0xa2 0x3c 0x3d 0x1a 0x4c peer_addr_type=0 ediv=0 rand=0 authenticated=0 ltk=0xca 0xc0 0x77 0x3a 0xaa 0x1b 0x14 0x9e 0x5f 0xed 0x9e 0xbe 0x53 0x0f 0xb5 0xc6
load peer sec; addr=0x1e 0xa2 0x3c 0x3d 0x1a 0x4c peer_addr_type=0 ediv=0 rand=0 authenticated=0 ltk=0xca 0xc0 0x77 0x3a 0xaa 0x1b 0x14 0x9e 0x5f 0xed 0x9e 0xbe 0x53 0x0f 0xb5 0xc6 irk=0x9f 0x1d 0x65 0xd3 0xba 0x87 0xb8 0x1e 0x58 0xb1 0xdd 0x62 0x6e 0xb7 0xdb 0x6b
load our cccd; addr=0x1e 0xa2 0x3c 0x3d 0x1a 0x4c peer_addr_type=0 chr_val_handle=3(0x0003) flags=1(0x0001) value_changed=0(0x0000)
load our cccd; addr=0x1e 0xa2 0x3c 0x3d 0x1a 0x4c peer_addr_type=0 chr_val_handle=35(0x0023) flags=1(0x0001) value_changed=0(0x0000)
load our cccd; addr=0x1e 0xa2 0x3c 0x3d 0x1a 0x4c peer_addr_type=0 chr_val_handle=39(0x0027) flags=1(0x0001) value_changed=0(0x0000)
load our cccd; addr=0x1e 0xa2 0x3c 0x3d 0x1a 0x4c peer_addr_type=0 chr_val_handle=46(0x002e) flags=1(0x0001) value_changed=0(0x0000)
load our cccd; addr=0x1e 0xa2 0x3c 0x3d 0x1a 0x4c peer_addr_type=0 chr_val_handle=50(0x0032) flags=1(0x0001) value_changed=0(0x0000)
load our cccd; addr=0x1e 0xa2 0x3c 0x3d 0x1a 0x4c peer_addr_type=0 chr_val_handle=55(0x0037) flags=1(0x0001) value_changed=0(0x0000)
load our sec; addr=0x06 0xcc 0x1d 0x36 0x56 0x9c peer_addr_type=0 ediv=0 rand=0 authenticated=0 ltk=0x5b 0x52 0xb8 0x93 0xa3 0xd7 0x05 0xbd 0xe8 0x50 0x09 0x6b 0x52 0x88 0x7d 0x58
load peer sec; addr=0x06 0xcc 0x1d 0x36 0x56 0x9c peer_addr_type=0 ediv=0 rand=0 authenticated=0 ltk=0x5b 0x52 0xb8 0x93 0xa3 0xd7 0x05 0xbd 0xe8 0x50 0x09 0x6b 0x52 0x88 0x7d 0x58 irk=0x8c 0x94 0x10 0xd8 0xd9 0x3d 0x27 0x5b 0xf3 0x3d 0x02 0xf5 0x55 0x24 0x2d 0x7a
load our cccd; addr=0x06 0xcc 0x1d 0x36 0x56 0x9c peer_addr_type=0 chr_val_handle=35(0x0023) flags=1(0x0001) value_changed=0(0x0000)
load our cccd; addr=0x06 0xcc 0x1d 0x36 0x56 0x9c peer_addr_type=0 chr_val_handle=39(0x0027) flags=1(0x0001) value_changed=0(0x0000)
load our cccd; addr=0x06 0xcc 0x1d 0x36 0x56 0x9c peer_addr_type=0 chr_val_handle=46(0x002e) flags=1(0x0001) value_changed=0(0x0000)
load our cccd; addr=0x06 0xcc 0x1d 0x36 0x56 0x9c peer_addr_type=0 chr_val_handle=50(0x0032) flags=1(0x0001) value_changed=0(0x0000)
load our cccd; addr=0x06 0xcc 0x1d 0x36 0x56 0x9c peer_addr_type=0 chr_val_handle=55(0x0037) flags=1(0x0001) value_changed=0(0x0000)
00 00:00:00 0 92 D 0/HIVIEW: hilog init success.
00 00:00:00 0 92 D 0/HIVIEW: log limit init success.
00 00:00:00 0 92 I 1/SAMGR: Bootstrap core services(count:3).
00 00:00:00 0 92 I 1/SAMGR: Init service:0x81782bf TaskPool:0x20014d10
00 00:00:00 0 92 I 1/SAMGR: Init service:0x81782e1 TaskPool:0x20015380
00 00:00:00 0 92 I 1/SAMGR: Init service:0x81783e9 TaskPool:0x20015540
00 00:00:00 0 244 I 1/SAMGR: RegisterWifiEvent: 0
EnableWifi: 0
AddDeviceConfig: 0
InitWifiConfig, disconnect wifi...
Init service 0x81782e1 success!
00 00:00:00 0 160 I 1/SAMGR: Init service 0x81782bf success!
00 00:00:00 0 72 D 0/HIVIEW: hiview init success.
00 00:00:00 0 72 I 1/SAMGR: Init service 0x81783e9 success!
00 00:00:00 0 72 I 1/SAMGR: Initialized all core system services!
00 00:00:00 0 160 I 1/SAMGR: Bootstrap system and application services(count:0).
00 00:00:00 0 160 I 1/SAMGR: Initialized all system and application services!
00 00:00:00 0 160 I 1/SAMGR: Bootstrap dynamic registered services(count:0).
WifiEventCallback status = WIFI_JOIN_SUCCESS
OnWifiConnectionChanged 56, state = 1, info =
bssid: E2:E5:18:B7:8B:96, rssi: 40, connState: 1, reason: 0, ssid: FsrLab
Connect to FsrLab done, status = 1!
ConnectTo(0): 0
g_connected: 1
WifiEventCallback status = NETIF_IP_NET_UP
[101]: name = 6E 02 0
[0]: ip = 192.168.43.254
[0]: gw = 192.168.43.1
[0]: netmask = 255.255.255.0
[101]: name = 6E 01 0
[1]: ip = 0.0.0.0
[1]: gw = 0.0.0.0
[1]: netmask = 0.0.0.0
[108]: name = 6F 00 0
[2]: ip = 127.0.0.1
[2]: gw = 127.0.0.1
[2]: netmask = 255.0.0.0
After 9 seconds, I will start TcpServerTest test!
After 8 seconds, I will start TcpServerTest test!
After 7 seconds, I will start TcpServerTest test!
After 6 seconds, I will start TcpServerTest test!
After 5 seconds, I will start TcpServerTest test!
After 4 seconds, I will start TcpServerTest test!
After 3 seconds, I will start TcpServerTest test!
data length changed...251, 27
After 2 seconds, I will start TcpServerTest test!
After 1 seconds, I will start TcpServerTest test!
After 0 seconds, I will start TcpServerTest test!
TcpServerTest start
*********************TCP server test *****************
bind to port 5678 success!
listen with 1 backlog success!
accept success, connfd = 1!
client addr info: host = 192.168.43.1, port = 38328
recv request{GET / HTTP/1.1
Host: 192.168.43.254:5678
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Linux;} from client done!
send response{GET / HTTP/1.1
Host: 192.168.43.254:5678
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Linux;} to client done!
do_cleanup...
TcpServerTest done!
disconnect to AP ...
Disconnect: -9
UnRegisterWifiEvent: 0
RemoveDevice: 0
DisableWifi: 0
disconnect to AP done!
编译前需要修改build.gn文件,如下:
生成静态库,gn编译流程的第一部
static_library("demo") {
sources = [
"my_test_1.c"
]
include_dirs = [
"//utils/native/lite/include",
"//kernel/liteos_m/components/cmsis/2.0",
"//foundation/communication/interfaces/kits/wifi_lite/wifiservice",
"//base/iot_hardware/interfaces/kits/wifiiot_lite",
]
if (board_name == "w800" || board_name == "hi3861v100") {
sources += ["wifi_connecter.c", "net_demo_ohos.c"]
}
if (board_name == "w800") {
include_dirs += [
"//vendor/winnermicro/w800/src/network/lwip2.0.3/include/",
"//vendor/winnermicro/w800/include/arch/xt804/csi_core",
"//vendor/winnermicro/w800/include/arch/xt804",
"//vendor/winnermicro/w800/include/platform",
"//vendor/winnermicro/w800/include/os",
"//vendor/winnermicro/w800/include/net",
"//vendor/winnermicro/w800/include/app",
"//vendor/winnermicro/w800/include/wifi",
"//vendor/winnermicro/w800/include",
]
}
}
编译文件,需要引用待编译的静态库
import("//build/lite/config/component/lite_component.gni")
lite_component("app") {
features = [
#"iothardware:gpio_example",
#"my_app:my_app",
#"wifitest:wifi_test",
#"uart_sample:uart_demo",
#"demolink:example_demolink",
#"my_app_gpio:my_app_gpio",
#"network:net_demo",
"my_demo:demo",
]
}
见演示视频,系统各功能配合完好。串口打印正常,通信延时较短
[1]孙威. 基于物联网技术的智能家居控制系统研究[D].吉林建筑大学,2021.DOI:10.27714/d.cnki.gjljs.2021.000055.
[2]杨诗宇. 基于人体行为识别算法的智能家居系统研究[D].贵州大学,2021.DOI:10.27047/d.cnki.ggudu.2021.000130.