OpenHarmony项目实战:智能体重秤
一、简介
本demo基于OpenHarmony3.1Beta版本开发,该样例能够接入数字管家应用,通过数字管家应用监测体重秤上报数据,获得当前测量到的体重,身高,并在应用端形成一段时间内记录的体重值,以折线图的形式表现出来,根据计算的BMI值来提醒当前身体健康状态,推送健康小知识。
如上图所示,智能体重称整体方案原理图可以大致分成:智能体重称设备、数字管家应用、云平台三部分。智能体重称通过MQTT协议连接华为IOT物联网平台,从而实现命令的接收和属性上报。 关于智能设备接入华为云IoT平台的详细细节可以参考 连接IOT云平台指南;智能设备同数字管家应用之间的设备模型定义可以参考profile .
如上图示,左边为全志xr806模组,右边为超声波测距模块,echo脚连接PA19,Triq脚连接PA20,Vcc脚连接5V电源,Gnd脚接地,
如上图示,右边为称重模块,clk脚接PB15,dt脚接PB14,vcc脚接5V,gnd脚接地,称重传感器红色线接E+,黑色线接E-,白色线接A-,绿色线接A+
左边xr806模块左下角k1按键,长按k1按键不放,同时上电,4-5秒后松开按键,可以清除已保存得配网信息
xr806模块,在设备正常工作后,按k1按键,可以初始化当前得重量为0,高度为0
二、 快速上手
1.硬件准备
- 全志xr806模组
- hcsr04超声波模块
- hx711称重模块带支架托盘
- 预装HarmonyOS手机一台
2、环境准备
参照文档: XR806快速上手指导文档
3、编译前准备
设备侧代码下载
具体仓库地址:https://gitee.com/openharmony-sig/knowledge_demo_smart_home/
下载方式:使用git 命令下载,指令如下(用户也可以根据需要将该仓库fork到自己的目录下后进行下载)
cd ~ git clone git@gitee.com:openharmony-sig/knowledge_demo_smart_home.git
代码拷贝
cp -rfa ~/knowledge_demo_smart_home/dev/team_x ~/openharmony/vendor/ cp -rfa ~/knowledge_demo_smart_home/dev/third_party/iot_link ~/openharmony/third_party/
SOC代码下载替换
当前官方soc代码由于DHCP暂未适配,所以暂时不支持AP模式,这时需要下载并替换之前SOC代码。如果官方soc代码已修复该问题,可忽略此步骤。
git clone https://gitee.com/moldy-potato-chips/xr806_-ap_mode.git mv ~/openharmony/device/soc/allwinner ~/allwinner.org // 不建议直接删除, cp -raf xr806_-ap_mode ~/openharmony/device/soc/allwinner
整合并修改完成后的目录结构如下图
修改文件
- 修改编译依赖
打开 device/soc/allwinner/xradio/xr806/BUILD.gn,添加应用依赖(deps字段):
module_group(module_name) { modules = [ "src", "project", "include", ] configs = [ ":SdkLdCconfig", ] deps = [ "//vendor/team_x/smart_weight_scale/demo_smart_weight_scale:smart_weight_scale" ] }
- 修改编译方式
将demo依赖的库编译方式(static_library)修改为(source_set):
具体依赖查看demo_smart_weight_scale目录下的BUILD.gn:
deps = [ "../../common/iot_wifi_xradio:iot_wifi", "../../common/iot_cloud:iot_cloud", "//third_party/cJSON:cjson", "../../common/iot_boardbutton_xradio:iot_boardbutton", "../../common/iot_boardled_xradio:iot_boardled_xradio", ]
其中//third_party/cJSON目录下的BUILD.gn建议参照下面的修改:
source_set("cJSON") { sources = [ "cJSON.c", "cJSON_Utils.c", ] ldflags = [ "-lm" ] }
third_party/iot_link目录下的各级使用到的BUILD.gn也需要将编译方式修改为source_set,或者将所有需要编译的文件放在iot_link目录的BUILD.gn中,如下:
source_set("iot_link") { sources = [ "link_log/link_log.c", "link_misc/link_random.c", "link_misc/link_ring_buffer.c", "link_misc/link_string.c", "network/dtls/dtls_al/dtls_al.c", "network/dtls/mbedtls/mbedtls_port/dtls_interface.c", "network/dtls/mbedtls/mbedtls_port/mbed_port.c", "network/dtls/mbedtls/mbedtls_port/timing_alt.c", "network/mqtt/mqtt_al/mqtt_al.c", "network/mqtt/paho_mqtt/port/paho_mqtt_port.c", "network/mqtt/paho_mqtt/port/paho_osdepends.c", "network/mqtt/paho_mqtt/paho/MQTTClient-C/src/MQTTClient.c", "network/mqtt/paho_mqtt/paho/MQTTPacket/src/MQTTConnectClient.c", "network/mqtt/paho_mqtt/paho/MQTTPacket/src/MQTTConnectServer.c", "network/mqtt/paho_mqtt/paho/MQTTPacket/src/MQTTDeserializePublish.c", "network/mqtt/paho_mqtt/paho/MQTTPacket/src/MQTTFormat.c", "network/mqtt/paho_mqtt/paho/MQTTPacket/src/MQTTPacket.c", "network/mqtt/paho_mqtt/paho/MQTTPacket/src/MQTTSerializePublish.c", "network/mqtt/paho_mqtt/paho/MQTTPacket/src/MQTTSubscribeClient.c", "network/mqtt/paho_mqtt/paho/MQTTPacket/src/MQTTSubscribeServer.c", "network/mqtt/paho_mqtt/paho/MQTTPacket/src/MQTTUnsubscribeClient.c", "network/mqtt/paho_mqtt/paho/MQTTPacket/src/MQTTUnsubscribeServer.c", "oc_mqtt/oc_mqtt_al/oc_mqtt_al.c", "oc_mqtt/oc_mqtt_profile_v5/oc_mqtt_profile.c", "oc_mqtt/oc_mqtt_profile_v5/oc_mqtt_profile_package.c", "oc_mqtt/oc_mqtt_profile_v5/oc_mqtt_event.c", "oc_mqtt/oc_mqtt_tiny_v5/oc_mqtt_tiny.c", "oc_mqtt/oc_mqtt_tiny_v5/hmac.c", "queue/queue.c", ] cflags = [ "-Wno-unused-variable" ] cflags += [ "-Wno-unused-but-set-variable" ] cflags += [ "-Wno-sign-compare" ] cflags += [ "-Wno-unused-parameter" ] cflags += [ "-Wno-unused-function" ] ldflags = [ "-Wl,-rpath-link=//device/xradio/xr806/xr_skylark/lib" ] ldflags += [ "-lmbedtls" ] include_dirs = [ "inc", "link_log", "link_misc", "queue", "oc_mqtt/oc_mqtt_tiny_v5", "oc_mqtt/oc_mqtt_profile_v5", "oc_mqtt/oc_mqtt_al", "network/dtls/mbedtls/mbedtls_port", "network/mqtt/paho_mqtt/port", "network/mqtt/paho_mqtt/paho/MQTTClient-C/src", "network/mqtt/paho_mqtt/paho/MQTTPacket/src", "//third_party/mbedtls/include/", "//third_party/mbedtls/include/", "//third_party/cJSON", "//kernel/liteos_m/components/cmsis/2.0", "//device/xradio/xr806/xr_skylark/include/net/mbedtls-2.2.0/", ] defines = [ "MQTTCLIENT_PLATFORM_HEADER=paho_osdepends.h", "WITH_DTLS", "MBEDTLS_AES_ROM_TABLES", "MBEDTLS_CONFIG_FILE=\"los_mbedtls_config_dtls.h\"", "CONFIG_DTLS_MBEDTLS_CERT", "CONFIG_DTLS_MBEDTLS_PSK", "CFG_MBEDTLS_MODE=PSK_CERT", "CONFIG_OC_MQTT_TINY_ENABLE=1" ] }
- 修改iot_link中的部分文件
1.third_party/iot_link/network/mqtt/paho_mqtt/port/paho_mqtt_port.c
测试发现,当fd为0的时候,在执行recv时会立马返回-1,因此做下面规避操作。
static int __socket_connect(Network *n, const char *host, int port) { ... int tmpfd = socket(AF_INET,SOCK_STREAM,0); // to skip fd = 0; fd = socket(AF_INET,SOCK_STREAM,0); if(fd == -1) { return ret; } close(tmpfd); // to skip fd = 0; ... }
系统setsockopt函数未适配,因此需要做下面的修改:
static int __socket_read(void *ctx, unsigned char *buf, int len, int timeout) { int fd; int ret = 0; #if 0 struct timeval timedelay = {timeout / 1000, (timeout % 1000) * 1000}; if(NULL== uf) { return ret; } fd = (int)(intptr_t)ctx; ///< socket could be zero if (timedelay.tv_sec < 0 || (timedelay.tv_sec == 0 && timedelay.tv_usec <= 0)) { timedelay.tv_sec = 0; timedelay.tv_usec = 100; } if(0 != setsockopt(fd,SOL_SOCKET,SO_RCVTIMEO,&timedelay,sizeof(struct timeval))) { return ret; //could not support the rcv timeout } int bytes = 0; while (bytes < len) { int rc = recv(fd, &buf[bytes], (size_t)(len - bytes), 0); printf("[%s|%s|%d]fd = %d, rc = %d\n", __FILE__,__func__,__LINE__, fd, rc); if (rc == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK) { bytes = -1; } break; } else if (rc == 0) { bytes = 0; break; } else { bytes += rc; } } return bytes; #else int bytes = 0; fd_set fdset; struct timeval timedelay = {timeout / 1000, (timeout % 1000) * 1000}; if(NULL== buf) { return ret; } fd = (int)(intptr_t)ctx; ///< socket could be zero if (timedelay.tv_sec < 0 || (timedelay.tv_sec == 0 && timedelay.tv_usec <= 0)) { timedelay.tv_sec = 0; timedelay.tv_usec = 100; } timedelay.tv_sec = 2; FD_ZERO(&fdset); FD_SET(fd, &fdset); ret = select(fd + 1, &fdset, NULL, NULL, &timedelay); if (ret > 0) { while (bytes < len) { int rc = recv(fd, &buf[bytes], (size_t)(len - bytes), 0); // printf("[%s|%s|%d]fd = %d, rc = %d, errno=%d(%s)\n", __FILE__,__func__,__LINE__, fd, rc,errno, strerror(errno)); if (rc == -1) { if (errno != EAGAIN && errno != EWOULDBLOCK) { bytes = -1; } break; } else if (rc == 0) { bytes = 0; break; } else { bytes += rc; } } } return bytes; #endif }
2.third_party/iot_link/network/dtls/mbedtls/mbedtls_port/dtls_interface.c
在文件顶部添加打印函数定义以及添加mbedtls_calloc以及mbedtls_free的定义,否则编译会提示错误:
#define MBEDTLS_LOG LINK_LOG_DEBUG #ifndef mbedtls_calloc #define mbedtls_calloc calloc #endif #ifndef mbedtls_free #define mbedtls_free free #endif
系统部分mbedtls接口不一致,固需要注释部分接口代码:
mbedtls_ssl_context dtls_ssl_new(dtls_establish_info_s *info, char plat_type) { ... if (info->psk_or_cert == VERIFY_WITH_PSK) { /* if ((ret = mbedtls_ssl_conf_psk(conf, info->v.p.psk, info->v.p.psk_len, info->v.p.psk_identity, strlen((const char *)info->v.p.psk_identity))) != 0) { MBEDTLS_LOG("mbedtls_ssl_conf_psk failed: -0x%x", -ret); goto exit_fail; } */ } ... } int dtls_shakehand(mbedtls_ssl_context *ssl, const dtls_shakehand_info_s *info) { ... if (MBEDTLS_SSL_IS_CLIENT == info->client_or_server) { ret = mbedtls_net_connect(server_fd, info->u.c.host, info->u.c.port, info->udp_or_tcp); if( 0 != ret) { ret = MBEDTLS_ERR_NET_CONNECT_FAILED; goto exit_fail; } } else { //server_fd = (mbedtls_net_context*)atiny_net_bind(NULL, info->u.s.local_port, MBEDTLS_NET_PROTO_UDP); ///< --TODO ,not implement yet } ... } void dtls_init(void) { (void)mbedtls_platform_set_calloc_free(calloc, free); (void)mbedtls_platform_set_snprintf(snprintf); // (void)mbedtls_platform_set_printf(printf); }
在iot_link/network/dtls/mbedtls/mbedtls_port/mbed_port.c文件中的dtls_imp_init()函数中,也需要注释掉未实现的接口,否则编译报错:
int dtls_imp_init(void) { int ret =-1; // (void)mbedtls_platform_set_calloc_free(calloc, free); // (void)mbedtls_platform_set_snprintf(snprintf); // (void)mbedtls_platform_set_printf(printf); ret = dtls_al_install(&s_mbedtls_io); return ret; }
3.在文件iot_link/network/mqtt/paho_mqtt/port/paho_osdepends.c中添加对应timersub和timeradd的实现(系统中未实现该函数):
// add this for "timersub" && "timeradd" #ifndef timersub #define timersub(s,t,a) (void) ( (a)->tv_sec = (s)->tv_sec - (t)->tv_sec, \ ((a)->tv_usec = (s)->tv_usec - (t)->tv_usec) < 0 && \ ((a)->tv_usec += 1000000, (a)->tv_sec--) ) #endif #ifndef timeradd #define timeradd(s,t,a) (void) ( (a)->tv_sec = (s)->tv_sec + (t)->tv_sec, \ ((a)->tv_usec = (s)->tv_usec + (t)->tv_usec) >= 1000000 && \ ((a)->tv_usec -= 1000000, (a)->tv_sec++) ) #endif
4.编译中会有部分头文件提示找不到,这个时候直接将其注释即可
(iot_link/network/mqtt/paho_mqtt/port/paho_osdepends.h): #define INVALID_SOCKET SOCKET_ERROR // #include <sys/socket.h> #include <sys/param.h> #include <sys/time.h> // #include <netinet/in.h> // #include <netinet/tcp.h> // #include <arpa/inet.h> // #include <netdb.h> #include <stdio.h> #include <unistd.h> #include <errno.h> #include <fcntl.h> #include <string.h> #include <stdlib.h> #endif #if defined(WIN32) #include <Iphlpapi.h> #else // #include <sys/ioctl.h> // #include <net/if.h> #endif
5.因为弱引用导致无法链接相关符号,因此需要注释以下几个文件中的弱引用。
文件一 third_party/iot_link/network/dtls/dtls_al/dtls_al.c #if 0 __attribute__((weak)) int dtls_imp_init(void) { LINK_LOG_DEBUG("%s:###please implement dtls by yourself####",__FUNCTION__); return -1; } #endif extern int dtls_imp_init(void); 文件二 third_party/iot_link/network/mqtt/mqtt_al/mqtt_al.c #if 0 __attribute__((weak)) int mqtt_imp_init(void) { LINK_LOG_DEBUG("%s:###please implement mqtt by yourself####",__FUNCTION__); return -1; } #endif extern int mqtt_imp_init(void); 文件三 third_party/iot_link/oc_mqtt/oc_mqtt_al/oc_mqtt_al.c #if 0 __attribute__ ((weak)) int oc_mqtt_imp_init(void) { LINK_LOG_DEBUG("%s:###please implement oc mqtt by yourself####",__FUNCTION__); return 0; } __attribute__ ((weak)) int oc_mqtt_demo_main(void) { LINK_LOG_WARN("Please implement the oc mqtt v5 demo yourself"); return -1; } #endif extern int oc_mqtt_demo_main(void);
- 修改GPIO查找方式
因为GPIO框架修改了设备驱动注册的管脚号,导致应用无法根据HCS的引脚操作对应的GPIO,此问题已经提issue,如果该问题已解决,可以忽略此步骤。
打开drivers/framework/support/platform/src/gpio/gpio_manager.c,将cntlr->start = start;注释即可。
static int32_t GpioManagerAdd(struct PlatformManager *manager, struct PlatformDevice *device) { uint16_t start; struct GpioCntlr *cntlr = CONTAINER_OF(device, struct GpioCntlr, device); if ((start = GpioCntlrQueryStart(cntlr, &manager->devices)) >= GPIO_NUM_MAX) { PLAT_LOGE("GpioCntlrAdd: query range for start:%d fail:%d", cntlr->start, start); return HDF_ERR_INVALID_PARAM; } // cntlr->start = start; DListInsertTail(&device->node, &manager->devices); PLAT_LOGI("%s: start:%u count:%u", __func__, cntlr->start, cntlr->count); return HDF_SUCCESS; }
- 将对应的驱动文件复制到drvier对应目录:
因为主仓代码中未将对应的驱动文件合并到driver/adpater/platform对应的目录下,固需要手动将文件拷贝到对应目录。若主仓已合入,可忽略此步骤。
// 拷贝gpio驱动 cp -af device/soc/allwinner/xradio/drivers/gpio/gpio_xradio.* driver/adpater/platform/gpio // 修改driver/adpater/platform/gpio/BUILD.gn文件,加上gpio_xradio的编译 hdf_driver(module_name) { sources = [] if (defined(LOSCFG_SOC_COMPANY_BESTECHNIC)) { sources += [ "gpio_bes.c" ] } if (defined(LOSCFG_SOC_COMPANY_ALLWINNER)) { sources += [ "gpio_xradio.c" ] } include_dirs = [ "." ] }
为了节省ram资源,可以把无用的资源先关闭,如关闭内部codec,将 device/soc/allwinner/xradio/xr806/project/prj_config.h中的PRJCONF_INTERNAL_SOUNDCARD_EN设置为0,如下:
/* Xradio internal codec sound card enable/disable */ #define PRJCONF_INTERNAL_SOUNDCARD_EN 0
4、代码编译
#首先可以查看一下hb的版本,如果hb版本为0.4.4版本就不需要更新。
查看hb版本
hb --version
更新hb, 以下指令需要在openharmony SDK根目录执行
pip3 uninstall ohos_build
pip3 install build/li
编译命令: hb set // 如果是第一次编译,Input code path 命令行中键入"./" 指定OpenHarmony工程编译根目录后 回车,
hb build // 如果需要全量编译,可以添加-f 选项
生成的固件保存在out/xradio/smart_weight_scale目录下
5、固件烧录
参照文档: XR806快速上手指导文档
6、设备配网
在设备上电前需准备好安装了数字管家应用的HarmonyOS手机,详情见数字管家应用开发, 并在设置中开启手机的NFC功能;
写设备NFC标签,详细操作见设备NFC标签指导文档;
烧录完成后,上电。开发者在观察开发板上状态LED灯以8Hz的频率闪烁时,将手机上半部靠近开发板NFC标签处(无NFC标签的可用NFC贴纸替代);
碰一碰后手机将自动拉起数字管家应用并进入配网状态;
配网过程中需要 连接设备的AP热点,然后填写需要配置的wifi的密码;
最后点击配置,手机会将ssid以及对应的密码通过AP热点发送到设备。
本文整理自:https://bbs.aw-ol.com/topic/1116/
作者@budbool

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
高并发场景下,如何优化服务器的性能
摘要:tcp_nodelay参数主要是对TCP套接字来说的,那对于服务器硬件,如果要使其能够支撑上百万甚至上千万的并发,我们该如何对其进行优化呢? 本文分享自华为云社区《【高并发】高并发场景下如何优化服务器的性能?》,作者: 冰 河 。 写在前面 最近,有小伙伴在群里提问:Linux系统怎么设置tcp_nodelay参数?也有小伙伴说问我。那今天,我们就来根据这个问题来聊聊在高并发场景下如何优化服务器的性能这个话题。 其实,tcp_nodelay参数并不是在操作系统级别进行配置的,而是在TCP套接字上添加tcp_nodelay参数来关闭粘包算法,以便使数据包能够立即投递出去。tcp_nodelay参数主要是对TCP套接字来说的,那对于服务器硬件,如果要使其能够支撑上百万甚至上千万的并发,我们该如何对其进行优化呢? 操作系统 这里,我使用的操作系统为CentOS 8,我们可以输入如下命令来查看操作系统的版本。 CentOS Linux release 8.0.1905 (Core) 对于高并发的场景,我们主要还是优化操作系统的网络性能,而操作系统中,有很多关于网络协议的参数,我们对于服务...
- 下一篇
软件测试面试:拿到一个产品(版本)如何开展测试?
产品提测后,如何开展测试? 我们都了解软件测试的执行流程,......提测-冒烟测试-详细测试-提交缺陷报告-回归测试,但软件测试并不总是线性过程,它甚至可能是螺旋结构,不断地试错,不断地迭代,不断地回归,直至最终的可用版本。 那么测试人员拿到提测版本后,如何开展测试?如何进行第一轮、第二轮测试? 第一轮测试: 1、从冒烟测试开始,也就是最简单的测试,如果不是特别复杂的项目,可以直接由基本流+备用流的方式来进行快速测试,也可以认为是可用性测试,能否继续进行下一步取决于冒烟测试结果是否通过,如基本流未通,则可以直接退回。否则,继续下一步 2、在快速测试过程中,可能激发了某些灵感,这时一定要记录下来,或者遇到一个新的问题可能引发其他的问题时,也做好记录;做记录的同时可以去补充测试用例,也可以暂时放在待测试想法列表中,通过后续的步骤时,来决定这些想法是否有进一步测试的必要 3、开始执行用例,测试用例一般情况下会区分正向反向用例的,在这个步骤中,先执行正向用例,若未通过数没有超过规定的比例,再执行反向用例;同时在这个过程中,很可能开发人员已提交过N个版本,那么仍需要不定期进行可用性测试 4、确...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Red5直播服务器,属于Java语言的直播服务器
- CentOS7,8上快速安装Gitea,搭建Git服务器
- CentOS6,7,8上安装Nginx,支持https2.0的开启
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- Jdk安装(Linux,MacOS,Windows),包含三大操作系统的最全安装
- SpringBoot2整合MyBatis,连接MySql数据库做增删改查操作
- SpringBoot2全家桶,快速入门学习开发网站教程
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- CentOS8编译安装MySQL8.0.19