2. 开拓的软件设备为智能门锁,储物精灵,软硬件开拓都有的是光伏逆变器。
3. 办理的问题:

传统的智能家居:智能单品,须要手动加入场景,无网不能智能掌握

创新的智能家居:空间智能,自发现后融入场景,分布式软总线掌握
4. 关键功能点:
智能门锁:密码解锁,NFC解锁,数字管家掌握,做事卡片掌握
储物精灵:密码解锁,NFC解锁,防火帘掌握,分布式软总线掌握
逆变器:单相逆变,隔离拓扑,组件小型化,高转换率与低总谐波失落真
二、竞赛开拓平台1. 操作系统:OpenHarmony 3.0
2. 开拓软件:VS code(Deveco studio tool),DevEco Studio
3. 开拓板:深开鸿KHDVK-3861B,润和DAYU200,润和hispark AI Camera
3. 关于环境:
操作系统:Ubuntu 编译构建:Python
包管理工具:HPM NPM 环境:Node.js
烧录软件:Hiburn USB串口驱动:CH341SER.exe
本地ssh:finalshell ssh文件比拟:Beyond Conpare
4. 虚拟机
(1) 虚拟机环境
Ubuntu(华为的硬件开拓一样平常都在此linux环境下进行)
虚拟机Vmware:下载之后利用上述提到的华为云中国镜像。
下载VS code的Linux版与OpenHarmony3.0源码。
(2)虚拟机环境:
将Ubuntu Shell环境修正为bash:ls -l /bin/sh
不才载VS code后下载华为硬件体例插件(Device tool)
(3) HB编译插件:
安装:python3 -m pip install --user ohos-build
变量:vim ~/.bashrc
复制粘贴到.bashrc的末了一行:export PATH=~/.local/bin:$PATH
更新变量:source ~/.bashrc
检讨:pip install ohos-build
5. 逆变器的紧张硬件选材:
(1)选材方案(选型依据)
Diode(二极管):高频检波电路,小型化,配对二极管不混组
Inductor(感应器):标称电感值,自共振频率(与互感值成正比)直流电阻(尽可能小),额定电流,直流重叠许可电流,温度上升许可电流。
Resistor(电阻器):贴片电阻,根据稳定性需求选择薄膜或厚膜
SPICE NMOS:封装尺寸,基本上封装越大越好,能承受的电流就越大;导通电压Vgs,只管即便选择比实际电路中可供应的掌握电压小的;导通电阻Rds,越小越好相应的导通电阻越小、分压越小、发热也越小。寄生电容Cgs,会影响mos的打开速率。寄生电容太大,方波会失落真Rds越小,Cgs越大。
(2)紧张选材
半导体选材:国产半导体RX65T125PS2A
电源IC选材:国产IC芯片ID7s625
DSP处理器:洞察到STM32系列软合了DSP处理器的功能。
三、方案详述(一)储物精灵
(1)用户角度:先从用户角度考虑需求与如何利用,再从技能层面解析
(详细用户利用方法这里不多赘述,详细内容直接看下午开拓内容)
(2)实现事理:(下文的步骤会详细先容,在这里先先容初期设想)
① 关于Mqtt协议在华为云的打通(设备在线激活):利用mqttX或mqttfx。
② 华为云:根据提示创建并获取密钥等信息,获取ClientID等身份识别信息,然后在云真个Topic(事宜主题)中自定义订阅与发布,对产品进行定义。
③ AppGallery Connect网站:创建并注册HarmonyOS产品,根据提示流程。
④ 设备开拓详细解析:每个设备都是一个子节点,实现了基于OpenHarmony设备的L0、L1、L2设备之间的互联互通。主控程序基于 OpenHarmony JS运用程序框架设计实现,并利用MQTT物联网通信协议接入华为云IOT平台,同时可将掌握指令发送至华为云IOT平台,供云端处理。DAYU开拓板(软件+硬件)详细实现为中控MQTT通信过程处于内核态驱动程序,JS运用通过发起接口调用后,进入用户态调用内核态接口的流程,并且JS运用会将所须要向云端发送的MQTT协议主题内容直接传入内核态,内核态欠妥准据处理和解析,直接将数据发布至云端,这样设计的目的是为了在添加设备的时候,仅需改变JS运用的数据构造,并不须要修正设备的代码,完成理解耦合。
NFC录入与记录:利用NFC扩展板录入,详细请见下方软总线设备通讯链接。
⑤ 智能识别比拟:识别工具的数据库,这里的识别作为单一的照片识别。vuforia 的做事器制作该 target 的识别数据库,该数据库要下载并绑定工程到target。图片由摄像头获取视频逐帧比对。
(3)设备侧
第一步:网络连接 使设备接电后自动联网
我们会在代码中预置热点名称与密码
在创建包后新建mqtt_entry.c用于存放热点自连代码的地址:
/home/open/Downloads/code-v3.0-LTS/OpenHarmony/applications/sample/wifi-iot/app/mqtt_demo
{ int ret; errno_t rc; hi_wifi_assoc_request assoc_req = {0}; / 拷贝SSID到assoc的req / / copy SSID to assoc_req / rc = memcpy_s(assoc_req.ssid, HI_WIFI_MAX_SSID_LEN + 1, "rui666", 8); //热点名 / WPA-PSK. CNcomment: 认证类型:WPA2-PSK.CNend / if (rc != EOK) { return -1; }//热点加密办法 assoc_req.auth = HI_WIFI_SECURITY_WPA2PSK; memcpy(assoc_req.key, "88888888", 11); //热点的密码 ret = hi_wifi_sta_connect(&assoc_req); if (ret != HISI_OK) { return -1; } return 0;} //预置热点名和密码 在设备通电后会自连
这里把原有的ability等量代换成了自发现热点。
OpenHarmony_ability的碰一碰自发现与自配网见下述。
第二步:上报订阅与下发,在此包内创建main函数
/home/open/Downloads/code-v3.0-LTS/OpenHarmony/applications/sample/wifi-iot/app/mqtt_demo
void mqtt_callback(MessageData msg_data) { size_t res_len = 0; uint8_t response_buf = NULL; char topicname[45] = { "$crsp/" }; LOS_ASSERT(msg_data); printf("topic %.s receive a message\r\n", msg_data->topicName->lenstring.len, msg_data->topicName->lenstring.data); printf("message is %.s\r\n", msg_data->message->payloadlen, msg_data->message->payload); } int mqtt_connect(void) { int rc = 0; NetworkInit(&n); NetworkConnect(&n, "a161fa3144.iot-mqtts.cn-north-4.myhuaweicloud.com", 1883); buf_size = 4096+1024; onenet_mqtt_buf = (unsigned char ) malloc(buf_size); onenet_mqtt_readbuf = (unsigned char ) malloc(buf_size); if (!(onenet_mqtt_buf && onenet_mqtt_readbuf)) { printf("No memory for MQTT client buffer!"); return -2; } MQTTClientInit(&mq_client, &n, 1000, onenet_mqtt_buf, buf_size, onenet_mqtt_readbuf, buf_size); MQTTStartTask(&mq_client); data.keepAliveInterval = 30; data.cleansession = 1; data.clientID.cstring = "61f6e729de9933029be57672_88888888_0_0_2022020905"; data.username.cstring = "61f6e729de9933029be57672_88888888"; data.password.cstring = "43872acc0b1e6aa7bf9e6a69f12aa9b1ebc07daffb67e18cf905c847a594f813"; data.cleansession = 1; mq_client.defaultMessageHandler = mqtt_callback; //连接做事器 rc = MQTTConnect(&mq_client, &data); //订阅,设置回调函数 MQTTSubscribe(&mq_client, "porsche", 0, mqtt_callback); while(1) { MQTTMessage message; message.qos = QOS1; message.retained = 0; message.payload = (void )"openharmony"; message.payloadlen = strlen("openharmony"); //上报 if (MQTTPublish(&mq_client, "hi3861", &message) < 0) { printf("MQTTPublish faild !\r\n"); } IoTGpioSetOutputVal(9, 0); //9gpio 0 light on usleep(1000000); } return 0; }
第三步:储物精灵保险模式&舵机开门
舵机开锁:
int servoID =0;void My_servo(uint8_t servoID,int angle){ int j=0; int k=2000/200; angle = kangle; for (j=0;j<5;j++){ IoTGpioSetOutputVal(servoID, 1); hi_udelay(angle); IoTGpioSetOutputVal(servoID, 1); hi_udelay(20000-angle); }}
保险模式:
static int DealSetPassword(cJSON objCmd){ int ret = -1; char pstr = NULL; cJSON objParas = NULL; cJSON objPara = NULL; CommandParamSetPsk setLockPskParam; memset(&setLockPskParam, 0x00, sizeof(CommandParamSetPsk)); if ((objParas = cJSON_GetObjectItem(objCmd, "paras")) == NULL) { RaiseLog(LOG_LEVEL_ERR, "Paras not exist"); return ret;} if ((objPara = cJSON_GetObjectItem(objParas, "PskId")) != NULL) { char id = cJSON_GetStringValue(objPara); //密码标识(string型) if (id == NULL || strlen(id) > LOCK_ID_LENGTH) { RaiseLog(LOG_LEVEL_ERR, "check lock id failed!"); return -1; } strncpy(setLockPskParam.id, id, strlen(id)); } else { return ret;} if ((objPara = cJSON_GetObjectItem(objParas, "Option")) != NULL) { char option = cJSON_GetStringValue(objPara); printf("option = %c \n", option); //三个命令(string型) if (option == 'A') { setLockPskParam.option = OPTION_ADD; //新增密码 } else if (option == 'U') { setLockPskParam.option = OPTION_UPDATE; //更新密码 } else if (option == 'D') { setLockPskParam.option = OPTION_DELETE; //删除密码 } else { RaiseLog(LOG_LEVEL_ERR, "no such option(%c)!", option); return -1; } } else { return ret; } if ((objPara = cJSON_GetObjectItem(objParas, "LockPsk")) != NULL) { char psk = cJSON_GetStringValue(objPara); if (psk == NULL || strlen(psk) > LOCK_PSK_LENGTH) { RaiseLog(LOG_LEVEL_ERR, "check psk failed!"); return -1; } strncpy(setLockPskParam.password, psk, strlen(psk)); } else { return ret;} ret = IotProfile_CommandCallback(CLOUD_COMMAND_SETPSK, &setLockPskParam); return ret;}
第四步:标注GPIO口
识别GPIO口与接入(这里要把稳一个接的是正极一个是接地还有一个为旗子暗记传输口)
void mqtt_test(void){ IoTGpioInit(9); IoTGpioSetDir(9, IOT_GPIO_DIR_OUT); mqtt_connect();}
第五步:吊起mqtt协议(build.gn版)
与主函数平行的Build.gn,吊起函数与第三方库的内容:
sources = [ "mqtt_test.c", "mqtt_entry.c" ]include_dirs = [ "//utils/native/lite/include", "//kernel/liteos_m/components/cmsis/2.0", "//base/iot_hardware/interfaces/kits/wifiiot_lite", "//vendor/hisi/hi3861/hi3861/third_party/lwip_sack/include", "//foundation/communication/interfaces/kits/wifi_lite/wifiservice", "//third_party/pahomqtt/MQTTPacket/src", "//third_party/pahomqtt/MQTTClient-C/src", "//third_party/pahomqtt/MQTTClient-C/src/liteOS", "//kernel/liteos_m/kal/cmsis", "//base/iot_hardware/peripheral/interfaces/kits", ] deps = [ "//third_party/pahomqtt:pahomqtt_static", //吊起MQTT协议 ]}
Build.gn:与APP并列的build.gn用于指出要编译的主函数,可以利用startup后面跟要编译的主包也可以直接features进行选中,在这里可以把不须要参与编译的项目通过#给注释掉。
在start_up里的builld.gn:
import("//build/lite/config/component/lite_component.gni")lite_component("app") { features = [ "mqtt_demo:mqtt_test", //标注主函数,指定位置编译]
储物精灵Pro版(识别功能版):(利用第三方平台:Vuforia)
我们的事理便是上传画面到云端,然后逐帧分解比对(此功能目前还在完善)
(4)软件侧(倾向软件,但是还是嵌入式开拓)
步骤一:吸收做事器的存储代码
exports.ita2=function(req,res){ console.log("iot_data:",req) const url = new URL("Get the URL provided by HUAWEI CLOUD"+req.url) //The address configured inside the forwarding destination let properties = JSON.stringify(req.body.notify_data.body.services) console.log("Store data:",properties) let addArr = [properties] var addSql = 'INSERT INTO sesnor_Record(properties) VALUES (?)' var callBack = function(err,data){ console.log("error:"+err) console.log("Property insertion result:"+JSON.stringify(data)) res.send(data) } sqlUtil.sqlContent(addSql,addArr,callBack) }
步骤二:射频贴纸&复旦卡拉取本地方案
写入复旦卡请用第三方的软件,NFC射频贴纸利用运用调试助手(华为运用市场可下载)。
void RC522_Config ( void ){ uint8_t ucStatusReturn; //Returns the status uint8_t flag_station = 1; //Leave the flag bit of the function while ( flag_station ) { / Seek cards (method: all in the range), the first search fails again, and when the search is successful, the card sequence is passed into the array ucArray_ID/ if ( ( ucStatusReturn = PcdRequest ( PICC_REQALL, ucArray_ID ) ) != MI_OK ) ucStatusReturn = PcdRequest ( PICC_REQALL, ucArray_ID ); if ( ucStatusReturn == MI_OK ) { / An anti-collision operation in which the selected sequence of cards is passed into an array ucArray_ID / if ( PcdAnticoll ( ucArray_ID ) == MI_OK ) { if ( PcdSelect ( ucArray_ID ) == MI_OK ) { printf ("\nRC522 is Ready!\n"); flag_station = 0; } } } }}
步骤三:智能窗帘轨办理方案
由于马达可以无限前后方向的对窗帘轨进行拉动以是选择马达来进行拉动。其余要把稳马达的功率来判断是否加入继电器,详情请移步源码仓(购买马达时要向供应商索要干系数据,同时向开拓板供应商索要已公开的脚位置图)
static void RtcTimeUpdate(void){ extern int SntpGetRtcTime(int localTimeZone, struct tm rtcTime); struct tm rtcTime; SntpGetRtcTime(CONFIG_LOCAL_TIMEZONE,&rtcTime); RaiseLog(LOG_LEVEL_INFO, "Year:%d Month:%d Mday:%d Wday:%d Hour:%d Min:%d Sec:%d", \ rtcTime.tm_year + BASE_YEAR_OF_TIME_CALC, rtcTime.tm_mon + 1, rtcTime.tm_mday,\ rtcTime.tm_wday, rtcTime.tm_hour, rtcTime.tm_min, rtcTime.tm_sec); if (rtcTime.tm_wday > 0) { g_appController.curDay = rtcTime.tm_wday - 1; } else { g_appController.curDay = EN_SUNDAY; } g_appController.curSecondsInDay = rtcTime.tm_hour CN_SECONDS_IN_HOUR + \ rtcTime.tm_min CN_SECONDS_IN_MINUTE + rtcTime.tm_sec + 8; // add 8 ms offset}static uint32_t Time2Tick(uint32_t ms){ uint64_t ret; ret = ((uint64_t)ms osKernelGetTickFreq()) / CN_MINISECONDS_IN_SECOND; return (uint32_t)ret;}#define CN_REACTION_TIME_SECONDS 1static void BoardLedButtonCallbackF1(char arg){ static uint32_t lastSec = 0; uint32_t curSec = 0; RaiseLog(LOG_LEVEL_INFO, "BUTTON PRESSED"); curSec = g_appController.curSecondsInDay; if((curSec) < (lastSec + CN_REACTION_TIME_SECONDS)) { RaiseLog(LOG_LEVEL_WARN, "Frequecy Pressed Button"); return; } lastSec = curSec; g_appController.curtainStatus = CN_BOARD_SWITCH_ON; g_appController.pwmLedDutyCycle = \ g_appController.pwmLedDutyCycle > 0 ? g_appController.pwmLedDutyCycle:CONFIG_LED_DUTYCYCLEDEFAULT; osEventFlagsSet(g_appController.curtainEvent, CN_LAMP_EVENT_SETSTATUS); return;}static void BoardLedButtonCallbackF2(char arg){ uint32_t lastSec = 0; uint32_t curSec = 0; RaiseLog(LOG_LEVEL_INFO, "BUTTON PRESSED"); curSec = g_appController.curSecondsInDay; if ((curSec) < (lastSec + CN_REACTION_TIME_SECONDS)) { RaiseLog(LOG_LEVEL_WARN, "Frequecy Pressed Button"); return; } lastSec = curSec; g_appController.curtainStatus = CN_BOARD_SWITCH_OFF; osEventFlagsSet(g_appController.curtainEvent, CN_LAMP_EVENT_SETSTATUS); return;}#define CURTAIN_MOTOR_GPIO_IDX 8#define WIFI_IOT_IO_FUNC_GPIO_8_GPIO 0#define WIFI_IOT_IO_FUNC_GPIO_14_GPIO 4#define MOTOR_WORK_SECOND 6static void E53SC1_MotorInit(void){ IoTGpioInit(CURTAIN_MOTOR_GPIO_IDX); IoTGpioSetFunc(CURTAIN_MOTOR_GPIO_IDX, WIFI_IOT_IO_FUNC_GPIO_8_GPIO); IoTGpioSetDir(CURTAIN_MOTOR_GPIO_IDX, IOT_GPIO_DIR_OUT); //设置GPIO_8为输出模式 return;}static void E53SC1_SetCurtainStatus(int curtainStatus){ if ((curtainStatus == CN_BOARD_CURTAIN_OPEN) || (curtainStatus == CN_BOARD_CURTAIN_CLOSE)) { IoTGpioSetOutputVal(CURTAIN_MOTOR_GPIO_IDX, 1); //设置GPIO_8输出高电平打开电机 sleep(MOTOR_WORK_SECOND); IoTGpioSetOutputVal(CURTAIN_MOTOR_GPIO_IDX, 0); //设置GPIO_8输出低电平关闭电机 } return;}static void DataCollectAndReport(const void arg){ (void)arg; uint32_t curtainEvent; uint32_t waitTicks; waitTicks = Time2Tick(CONFIG_SENSOR_SAMPLE_CYCLE); while (1) { curtainEvent = osEventFlagsWait(g_appController.curtainEvent, CN_CURTAIN_EVENT_SETSTATUS, \ osFlagsWaitAny, waitTicks); if (curtainEvent & CN_CURTAIN_EVENT_SETSTATUS) { RaiseLog(LOG_LEVEL_INFO, "GetEvent:%08x", curtainEvent); E53SC1_SetCurtainStatus(g_appController.curtainStatus); } (void) IotProfile_Report(g_appController.curtainStatus); } return;}static int UpdateShedule(CommandParamSetShedule shedule){ if (shedule->num == 1 && shedule->day[0] == 0) { // set the one time schedule to current weekday shedule->day[0] = (g_appController.curDay + 1); } switch (shedule->option) { case 'A': IOT_ScheduleAdd(shedule->scheduleID, shedule->day, shedule->num, shedule->startHour CN_SECONDS_IN_HOUR +\ shedule->startMinute CN_SECONDS_IN_MINUTE, shedule->duration, shedule->shedulecmd.cmd, 0); break; case 'U': IOT_ScheduleUpdate(shedule->scheduleID, shedule->day, shedule->num, shedule->startHour CN_SECONDS_IN_HOUR +\ shedule->startMinute CN_SECONDS_IN_MINUTE, shedule->duration, shedule->shedulecmd.cmd, 0); break; case 'D': IOT_ScheduleDelete(shedule->scheduleID, shedule->day, shedule->num, shedule->startHour CN_SECONDS_IN_HOUR +\ shedule->startMinute CN_SECONDS_IN_MINUTE, shedule->duration, shedule->shedulecmd.cmd, 0); break; default: RaiseLog(LOG_LEVEL_ERR, "the schedule has no such option!\n"); break; } return 0;}void CurrentTimeCalcTimerHander(){ g_appController.curSecondsInDay ++;}#define TimeCalcTicks_NUMBER 100#define CN_MINISECONDS_IN_1000MS 1000static void CurtainShedule(void){ int startSecondInDay = 0; int endSecondInDay = 0; int settingCmd = 0; int executeTaskTime = 0; // indicate the do something busy osTimerId_t CurrentTimeCalc_id; CurrentTimeCalc_id = osTimerNew(CurrentTimeCalcTimerHander, osTimerPeriodic, NULL, NULL); osTimerStart(CurrentTimeCalc_id, TimeCalcTicks_NUMBER); while (1) { osDelay(Time2Tick(CN_MINISECONDS_IN_1000MS)); if (g_appController.curSecondsInDay >= CN_SECONS_IN_DAY) { g_appController.curSecondsInDay = 0; g_appController.curDay++; if (g_appController.curDay >= EN_DAYALL) { g_appController.curDay = EN_MONDAY; } IOT_ScheduleSetUpdate(1); } // check if we need do some task here if (IOT_ScheduleIsUpdate(g_appController.curDay, g_appController.curSecondsInDay)) { if (executeTaskTime > 0) { executeTaskTime = 0; if (g_appController.curtainStatus == CN_BOARD_CURTAIN_OPEN) { g_appController.curtainStatus = CN_BOARD_CURTAIN_CLOSE; osEventFlagsSet(g_appController.curtainEvent, CN_CURTAIN_EVENT_SETSTATUS); } } startSecondInDay = IOT_ScheduleGetStartTime(); endSecondInDay = startSecondInDay + IOT_ScheduleGetDurationTime(); IOT_ScheduleGetCommand(&settingCmd, NULL); } RaiseLog(LOG_LEVEL_INFO, "start:%d end:%d cur:%d",startSecondInDay, endSecondInDay, g_appController.curSecondsInDay); if ((endSecondInDay == startSecondInDay) && (g_appController.curSecondsInDay == endSecondInDay)) { if (g_appController.curtainStatus != settingCmd) { RaiseLog(LOG_LEVEL_INFO, "Triggering"); g_appController.curtainStatus = settingCmd; osEventFlagsSet(g_appController.curtainEvent, CN_CURTAIN_EVENT_SETSTATUS); } IOT_ScheduleSetUpdate(1); } } return;}int IotProfile_CommandCallback(int command, void buf){ CommandParamSetShedule setSheduleParam; CommandParamSetCurtain setCurtainParam; //CommandParamSetDutyCycle setDutyCycleParam; CLOUD_CommandType cmd = (CLOUD_CommandType)command; if (cmd == CLOUD_COMMAND_SETCURTAIN_STATUS) { setCurtainParam = (CommandParamSetCurtain )buf; g_appController.curtainStatus = setCurtainParam.status; RaiseLog(LOG_LEVEL_INFO, "setCurtainParam.status:%d\r\n", setCurtainParam.status); osEventFlagsSet(g_appController.curtainEvent, CN_LAMP_EVENT_SETSTATUS); return 0; } else if (cmd == CLOUD_COMMAND_SETSHEDULE) { setSheduleParam = (CommandParamSetShedule )buf; RaiseLog(LOG_LEVEL_INFO, "setshedule:day:%d hour:%d minute:%d duration:%d \r\n", \ setSheduleParam.day,setSheduleParam.startHour,setSheduleParam.startMinute, setSheduleParam.duration); return UpdateShedule(&setSheduleParam); } return -1;}static int IotWifiInfo_get(char ssid, int id_size, char pwd, int pd_size){ int retval = UtilsGetValue(SID_KEY, ssid, id_size); if (retval <= 0) { RaiseLog(LOG_LEVEL_ERR, "no such ssid stored! \n"); return 0; } if ( UtilsGetValue(PWD_KEY, pwd, pd_size) < 0) { RaiseLog(LOG_LEVEL_INFO, "ssid(%s) no password stored! \n", ssid); } else { RaiseLog(LOG_LEVEL_INFO, "ssid : %s, pwd : %s! \n", ssid, pwd); } return 1;}static void IotWifiInfo_set(char ssid, char pwd){ if (UtilsSetValue(SID_KEY, ssid) != 0) { RaiseLog(LOG_LEVEL_ERR, "store ssid failed! \n"); return; } if (UtilsSetValue(PWD_KEY, pwd) != 0) { RaiseLog(LOG_LEVEL_ERR, "store password failed! \n"); UtilsDeleteValue(SID_KEY); return; } RaiseLog(LOG_LEVEL_INFO, "store password success! \n");}static void IotMainTaskEntry(const void arg){ osThreadAttr_t attr; NfcInfo nfcInfo; (void)arg; char ssid[BUFF_SIZE] = {0}; char pwd[BUFF_SIZE] = {0}; int ret = 0; g_appController.pwmLedDutyCycle = CONFIG_LED_DUTYCYCLEDEFAULT; BOARD_InitPwmLed(); BOARD_InitWifi(); E53SC1_MotorInit(); IOT_ScheduleInit(); ret = Board_IsButtonPressedF2(); osDelay(MAIN_TASK_DELAY_TICKS); LedFlashFrequencySet(CONFIG_FLASHLED_FRENETCONFIG); nfcInfo.deviceID = "6136ceba0ad1ed02866fa3b2_Curtain01"; nfcInfo.devicePWD = "12345678"; if (ret) { RaiseLog(LOG_LEVEL_INFO, "Netconfig Button has pressed! \n"); if (BOARD_NAN_NetCfgStartConfig(SOFTAP_NAME, ssid, sizeof(ssid), pwd, sizeof(pwd)) < 0) { RaiseLog(LOG_LEVEL_ERR, "BOARD_NetCfgStartConfig failed! \n"); return; } else { ret = AFTER_NETCFG_ACTION; } } else { ret = IotWifiInfo_get(ssid, sizeof(ssid), pwd, sizeof(pwd)); if (ret == 0) { if (BOARD_NAN_NetCfgStartConfig(SOFTAP_NAME, ssid, sizeof(ssid), pwd, sizeof(pwd)) < 0) { RaiseLog(LOG_LEVEL_ERR, "BOARD_NetCfgStartConfig failed! \n"); return; } else { ret = AFTER_NETCFG_ACTION; } } } LedFlashFrequencySet(CONFIG_FLASHLED_FREWIFI); if (BOARD_ConnectWifi(ssid, pwd) != 0) { RaiseLog(LOG_LEVEL_ERR, "BOARD_ConnectWifi failed! \n"); if (ret == AFTER_NETCFG_ACTION) { NotifyNetCfgResult(NETCFG_DEV_INFO_INVALID); } hi_hard_reboot(HI_SYS_REBOOT_CAUSE_CMD); return; } if (ret == AFTER_NETCFG_ACTION) { RaiseLog(LOG_LEVEL_DEBUG, "Connect wifi success ! \n"); NotifyNetCfgResult(NETCFG_OK); osDelay(MAIN_TASK_DELAY_TICKS); RaiseLog(LOG_LEVEL_DEBUG, "StopNetCfg wifi success ! \n"); StopNetCfg(); IotWifiInfo_set(ssid, pwd); } LedFlashFrequencySet(CONFIG_FLASHLED_FRECLOUD); RtcTimeUpdate(); if (CLOUD_Init() != 0) { return; } if (CLOUD_Connect(nfcInfo.deviceID, nfcInfo.devicePWD, \ CONFIG_CLOUD_DEFAULT_SERVERIP, CONFIG_CLOUD_DEFAULT_SERVERPORT) != 0) { return; } LedFlashFrequencySet(CONFIG_FLASHLED_WORKSWELL); attr.attr_bits = 0U; attr.cb_mem = NULL; attr.cb_size = 0U; attr.stack_mem = NULL; attr.stack_size = CONFIG_TASK_DEFAULT_STACKSIZE; attr.priority = CONFIG_TASK_DEFAULT_PRIOR; attr.name = "DataCollectAndReport"; if (osThreadNew((osThreadFunc_t)DataCollectAndReport, NULL, (const osThreadAttr_t )&attr) == NULL) { return; } attr.name = "CurtainShedule"; if (osThreadNew((osThreadFunc_t)CurtainShedule, NULL, (const osThreadAttr_t )&attr) == NULL) { return; } return;}static void IotMainEntry(void){ osThreadAttr_t attr; RaiseLog(LOG_LEVEL_INFO, "DATA:%s Time:%s \r\n",__FUNCTION__, __DATE__, __TIME__); g_appController.curtainEvent = osEventFlagsNew(NULL); if ( g_appController.curtainEvent == NULL) { return; } // Create the IoT Main task attr.attr_bits = 0U; attr.cb_mem = NULL; attr.cb_size = 0U; attr.stack_mem = NULL; attr.stack_size = CONFIG_TASK_MAIN_STACKSIZE; attr.priority = CONFIG_TASK_MAIN_PRIOR; attr.name = "IoTMain"; (void) osThreadNew((osThreadFunc_t)IotMainTaskEntry, NULL, (const osThreadAttr_t )&attr); return;}
步骤四:无感配网办理方案(主要ability)
OpenHarmony设备之间的信息通报利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家与设备之间的互联。在完成设备间的认证和相应后,即可发送干系配网数据。同时还支持与常规SoftAP配网办法共存。
干系代码:teamX/common/iot_wifi/libs/libhilinkadapter_3861.a // 无感配网干系库文件teamX/common/iot_wifi/libs/libnetcfgdevicesdk.a // 无感配网干系库文件teamX/common/inc/iot_netcfg_nan.hteamX/common/inc/network_config_service.h // 无感配网干系头文件teamX/common/iot_wifi/iot_wifi.c // 干系联网接口teamX/common/iot_wifi/iot_netcfg_nan.c // 无感配网干系实现
数字管家可以在gitee下载源码,不才载的team_X中查看详细先容
步骤五:第三方平台接入
储物精灵Pro版(识别功能版):(利用第三方平台:Vuforia)
我们的事理便是上传画面到云端,然后逐帧分解比对(此功能目前还在完善)
第六步:实时摄像功能与智能检测光照值功能(正在实验中)
int GetLightAverageVal(unsigned char cnt){ unsigned short readVal = 0; unsigned int totalVal = 0, totalCnt = 0; for(unsigned char i=0; i<cnt; i++) { if(LightSensorVal(&readVal) == IOT_SUCCESS) { totalVal += readVal; totalCnt++; } usleep(50000); } return (totalVal/totalCnt); }enum ENV_LIGHT_STATE GetEnvLightState(void){ enum ENV_LIGHT_STATE lightState = LIGHT_DAY; int lightVal = GetLightAverageVal(5); if(lightVal > ENV_LIGHT_LEVEL_LOWEST) { lightState = LIGHT_NIGHT; } else if(lightVal > ENV_LIGHT_LEVEL_LOW) { lightState = LIGHT_DUSK; } else { lightState = LIGHT_DAY; } return lightState;}
第七步:分布式检索功能(实验中)
传统的分布式利用的是Elasticsearch进行,鉴于OpenHarmony能力以是须要开拓出对口的ability。
isCreateIfMissing() //分布式数据库创建、打开、关闭和删除setCreateIfMissing(boolean isCreateIfMissing) //数据库不存在时是否创建isEncrypt() //获取数据库是否加密setEncrypt(boolean isEncrypt) //设置数据库是否加密getStoreType() //获取分布式数据库的类型setStoreType(KvStoreType storeType) //设置分布式数据库的类型KvStoreType.DEVICE_COLLABORATION //设备协同分布式数据库类型KvStoreType.SINGLE_VERSION //单版本分布式数据库类型getKvStore(Options options, String storeId) //根据Options配置创建和打开标识符为 storeId 的分布式数据库closeKvStore(KvStore kvStore) //关闭分布式数据库getStoreId() //分布式数据增、删、改、查。subscribe(SubscribeType subscribeType, KvStoreObserver observer) //订阅sync(List<String> deviceIdList, SyncMode mode) 数据同步
开拓解释:(包括OH分布式文件)
1. 布局分布式数据库管理类(创建 KvManagerConfig 工具)
Context context;...KvManagerConfig config = new KvManagerConfig(context);KvManager kvManager = KvManagerFactory.getInstance().createKvManager(config);
2. 获取/创建单版本分布式数据库(声明须要创建的单版本分布式数据库ID解释)
Options CREATE = new Options();CREATE.setCreateIfMissing(true).setEncrypt(false).setKvStoreType(KvStoreType.SINGLE_VERSION);String storeID = "testApp";SingleKvStore singleKvStore = kvManager.getKvStore(CREATE, storeID);
3. 订阅分布式数据变动(客户端须要实现KvStoreObserver接口&构造并注册KvStoreObserver实例)
class KvStoreObserverClient implements KvStoreObserver() { public void onChange(ChangeNotification notification) { List<Entry> insertEntries = notification.getInsertEntries(); List<Entry> updateEntries = notification.getUpdateEntries(); List<Entry> deleteEntries = notification.getDeleteEntries(); } }KvStoreObserver kvStoreObserverClient = new KvStoreObserverClient();singleKvStore.subscribe(SubscribeType.SUBSCRIBE_TYPE_ALL, kvStoreObserverClient);
4. 布局须要写入单版本分布式数据库的Key和Value(将键值数据写入单版本分布式数据库)
String key = "todayWeather";String value = "Sunny";singleKvStore.putString(key, value);
5. 布局须要从单版本分布式数据库快照中查询的Key(数据取自单版本分布式数据库快照)
String key = "todayWeather";String value = singleKvStore.getString(key);
6. 获取设备列表与同步数据(PUSH_ONLY)
List<DeviceInfo> deviceInfoList = kvManager.getConnectedDevicesInfo(DeviceFilterStrategy.NO_FILTER); List<String> deviceIdList = new ArrayList<>(); for (DeviceInfo deviceInfo : deviceInfoList) { deviceIdList.add(deviceInfo.getId()); } singleKvStore.sync(deviceIdList, SyncMode.PUSH_ONLY);
7. 首先get到设备数据交流权限
ohos.permission.DISTRIBUTED_DATASYNCrequestPermissionsFromUser(new String[]{"ohos.permission.DISTRIBUTED_DATASYNC"}, 0);//然后在AbilitySlice中声明数据库并利用即可,这里不多赘述
9. 关于API的开放能力请详见官方文档,这里不再赘述。
10. 怼干系接口(正在实验的内容)
SearchAbility searchAbility = new SearchAbility(context);CountDownLatch lock = new CountDownLatch(1);searchAbility.connect(new ServiceConnectCallback() { @Override public void onConnect() { lock.countDown(); } @Override public void onDisconnect() { }});lock.await(3000, TimeUnit.MILLISECONDS);
11. 设置搜索属性与插入索引和重构查询等将会不才一次提交中进行补充。
(二)智能门锁
(上面的储物精灵源码也包括智能门锁的功能实现,这里补充先容开拓)
1. 环境搭建:
(1) 须要手动配置在deveco tool里的用户组件
(2) 接舵机的Gpio口
这里要把稳一个接的是正极一个是接地还有一个为旗子暗记传输口
(3) 云端配置
首先在华为云官方获取Client ID等身份识别信息,然后在云真个Topic中自定义订阅与发布。
在初次开拓时可以利用MQTTX软件进行了命令的订阅与下发实验,显示在线成功吸收到上报和订阅的。
这样华为云的配置就成功了
如有须要还要进行产品定义与多功能的增加与实验
2.关于编译:
(1) 在VS code编译
点击build就可以天生json文件啦,编译成功后upload就可以直接烧录进去。(把稳:在编译之后如果要再编译必须点击clean以删除build产生的json文件避免报错)
(2)在Ubuntu通过命令行编译
hb set //这是用于产生json文件的
hb build //这是用于编译的,编译后则会在源码的out文件夹中产生bin文件
hb clean //在build一次往后如果如果要再build那就必须进行此命令来删除json文件
在build成功后开拓者就会创造在源码中的out文件夹中看到allinone.bin,然后发送到windows下利用Hiburn进行烧录即可(波特兰最大3000000,否则会烧坏板子)下图为HiBurn的配置方法,点击Connect即可烧录。
3.碰一碰卡片(原子化做事)
数字管家须要通过在APPGallery Connect中创建项目后添加运用从而获取Json文件,然后放在码云中下在的DistSchedule\netconfig\src\main\resources中。然后按照文档开拓UI界面,点击构建的Generate Key and CSR创建用户名与密钥进行署名。
用户操作界面:在slice目录下新建 xxxSlice.java文件,通过addActionRoute方法为此AbilitySlice配置一条路由规则,并且在在运用配置文件(config.json)中注册。在resources/base/layout下新建对应xml布局文件,在上述两个文件中编写相应的UI。
数字管家数据处理:从slice获取deviceId:在onStart中通过调用DeviceID等,获取设备的名称等方便数字管家识别设备。从slice页面获取状态:开关锁可以直接调用intent.getBooleanParam来确定是进行开关锁还是对门锁的日程进行编排。
编写设备掌握命令的解析:在CommandUtil中根据详细设备定义profile,来新增获取命令和解析命令的方法,用于设备在本地调用sendCommand来发送命令和解析。
配置设备端信息:在DeviceData的initData中,根据设备ProductID添加设备图片ID、跳转的action参数和解析方法,配置完成后设备列表页、用户页面等都能通过该配置进行图片加载、路由跳转和解析。
最后进行接口对接与NFC写入就可以了(通过运用调试助手写入NFC识别详细用于快速让手机识别到设备从而吊起数字管家实现鸿蒙的Ability)
(三)逆变器
1. 拓扑图
设计的单相逆变器,拥有隔离拓扑,通过掌握GaN(HEMT)的高频开关实现逆变
关于桥臂:两个半桥产生中性点电压,其余两个半桥产生线电压,末了一个半桥作为有源滤波器。
2.现在STM32f407兼容了OpenHarmony 3.2 bata版,由于f4系列软合了dsp处理以是无需其余利用dsp从处理器。考虑到只管即便减少直流侧输入电流纹波,输出的正弦波尽可能的平滑与减小总谐波失落真,设计了一种并联有源滤波器,它比在输入端利用批量电容更有效地补偿纹波。
3.考虑到大部分EDA的元件库原件都不全,我在kicad按照厂家供应的数据手册画了个原件,并按照例出的参数进行了标注。
4. 关于电流与电压的总谐波失落真等:有源滤波器事情在更高的电压变革下将相应的能量存储在陶瓷电容器中,陶瓷电容器的电容随着电压的降落而增加。通过算法保持Vin稳定同时许可有源滤波器产生大的波纹。输出电流结合电磁屏蔽的开环霍尔传感器形成非常紧凑的丈量装置供应电流解耦并降落对共模和寄生感应噪声的敏感性。特定的GaN掌握调制降落了滤波器电感中的电流可以在不达到饱和水平的情形低落低其核心尺寸。
5. 关于硬件选材:在上文的 二.竞赛开拓平台 的逆变器中有先容
6.通讯部分
(1)分布式软总线
基于UDP的coap协议,OpenHarmony特有分布式软总线。
编程步骤: 1.创建socket;
2.设置socket属性,用函数setsockopt();
3.绑定IP地址、端口等信息到socket上,用函数bind();
4.循环吸收/发送数据,用函数recvfrom&sendto;
5.关闭网络连接。
创建一个socket,无论是客户端还是做事器端都须要创建一个socket。该函数返回socket文件描述符,类似于文件描述符。socket是一个构造体,被创建在内核中。
class UdpClient { private DatagramSocket client; public String sendAndReceive(String ip, int port, String msg) { String responseMsg = ""; try { //Create a client-side DatagramSocket object without having to pass in addresses and objects client = new DatagramSocket(); byte[] sendBytes = msg.getBytes(); //Encapsulates the address of the destination to be sent InetAddress address = InetAddress.getByName(ip); //Encapsulates the object to send the DatagramPacket DatagramPacket sendPacket = new DatagramPacket(sendBytes,sendBytes.length,address,port); try { //sent Data client.send(sendPacket); }catch (Exception e){ // e.printStackTrace(); } byte[] responseBytes = new byte[2048]; //Create a DatagramPacket object for the response information DatagramPacket responsePacket = new DatagramPacket(responseBytes,responseBytes.length); try { //Waiting for the response information, as on the server side, the client blocks at this step until it receives a packet client.receive(responsePacket); }catch (Exception e){ // e.printStackTrace(); } //Parse the packet contents responseMsg = new String(responsePacket.getData(),0,responsePacket.getLength()); }catch (Exception e){ // e.printStackTrace(); }finally { //Close the client if(client != null){ client.close(); client = null; } } return responseMsg; }}
DatagramSocket类代表一个发送和吸收数据包的插座该类是遵照 UDP协议 实现的一个Socket类
#define _PROT_ 8800 //UDP server port number#define _SERVER_IP_ "666.66.66.666"#define TCP_BACKLOG 5#define IP_LEN 16#define WIFI_SSID "rui666" //WiFi name#define WIFI_PASSWORD "1145141919810" //WIFI oassword
开拓板的IP与端口号
public void performClassification() { int res = classifier.getResult(accelMeasurements, gyroMeasurements); TaskDispatcher uiTaskDispatcher = this.getContext().getUITaskDispatcher(); String lab = classes[res]; result = lab; TaskDispatcher globalTaskDispatcher = getContext().getGlobalTaskDispatcher(TaskPriority.DEFAULT); globalTaskDispatcher.asyncDispatch(new Runnable() { public void run() { HiLog.warn(label, udpClient.sendAndReceive("666.66.66.666", 8800, result)); } });
干系参数意义(把稳要手搓的定义内容):
sin_family //Refers to protocol families, which can only be AF_INET in socket programmingsin_port //Storage port number (using network byte order)sin_addr //Store the IP address and use the in_addr this data structuresin_zero //Empty bytes are reserved in order to keep sockaddr and sockaddr_in two data structures the same sizefd //socketbuf //UDP datagram buffer (contains data to be sent)len //The length of the UDP datagramflags //Invocation operation mode (typically set to 0)addr //A struct that points to the host address information that receives the data (type conversion required sockaddr_in)alen //The length of the structure referred to by addrnfds //Represents the range of all file descriptors in a collectionreadfds //Select monitors a collection of readable file handles、writefds //A collection of writable file handles that select monitorsexceptfds //A collection of exception file handles that select monitorstimeout //The timeout end time of select() this time, NULL means permanent wait
测试客户真个成功方法:通过UDP软件进行干系的发送与吸收,并查看打印信息。由于与下文先容的MQTTX软件利用事理差不多以是这里不多赘述。
(2) MQTT
Mqtt是用于设备与做事器通讯的一种协议,使设备可以上报订阅下发信息。须要下载此协议并存放在thirdparty(第三方库),并在头文件中吊起。
从开拓板厂商官网下载实验demo进行实验。由于目前大多数厂商利用的都是OpenHarmony 1.0代码作为演示,不同的源码版本在编译规则和文件名上都会不同,以是不才载的源码中的头文件吊起等也要修正才能接入mqtt协议。
Mqtt最主要要吊起的功能文件在 /home/open/Downloads/code_v3.0LTS/OpenHarmony/third_party/pahomqtt/MQTTClient-C/src里,特殊是liteOS中。
7.做事卡片
(1)做事卡片事理
(2)APPGallery Connect
①数字管家:
数字管家须要通过在APPGallery Connect中创建项目后添加运用从而获取Json文件,在完成下述的2后把此文件放在码云中下载的FA源码的:
DistSchedule\netconfig\src\main\resources中。然后按照文档开拓UI界面,点击构建的Generate Key and CSR创建用户名与密钥进行署名。
官网在我的项目中创建项目,选择harmonyOS平台等完成填写
https://developer.huawei.com/consumer/cn/service/josp/agc/index.html#/
②逻辑处理:
(i)用户操作界面:在slice目录下新建 xxxSlice.java文件,通过addActionRoute方法为此AbilitySlice配置一条路由规则,并且在在运用配置文件(config.json)中注册。在resources/base/layout下新建对应xml布局文件,在上述两个文件中编写相应的UI。
(ii)数字管家数据处理:从slice获取deviceId:在onStart中通过调用DeviceID等,获取设备的名称等方便数字管家识别设备。从slice页面获取状态:开关锁可以直接调用intent.getBooleanParam来确定是进行开关锁还是对门锁的日程进行编排。
(iii)编写设备掌握命令的解析:在CommandUtil中根据详细设备定义profile,来新增获取命令和解析命令的方法,用于设备在本地调用sendCommand来发送命令和解析。
(iv)配置设备端信息:在DeviceData的initData中,根据设备ProductID添加设备图片ID、跳转的action参数和解析方法,配置完成后设备列表页、用户页面等都能通过该配置进行图片加载、路由跳转和解析。
(v) NFC写入:最后进行接口对接与NFC写入就可以了(通过运用调试助手写入NFC识别详细用于快速让手机识别到设备从而吊起数字管家实现鸿蒙的Ability)可以写到开拓板的NFC预存区,也可以写在huawei share的碰一碰卡片上。(目前这两种写法都可以写无数次,不才一次写入时会自动打消上一次所写的)
③开拓办法:
(i) 用户操作界面:通过桌面可以在卡片中点击干系做事,卡片中可以呈现一个或多个做事。
(ii)事情事理:通过嵌入到UI界面拉起那款运用的做事(可以通过缓存实现快速打开)从而起到交互功能的原子化做事。
(iii)生命周期管理:对设备利用方的 RPC 工具进行管理,要求进行校验以及对更新后的进行回调处理。
(iv)卡片尺寸:目前官方有四种尺寸,可以在new中自己选中喜好的尺寸。
(v)上手开拓:新建一个做事卡片
选择自己所需的卡片框架
(vi)开拓环节:创建完之后然后就可以看到在原有的subject中天生了config.json文件。js默认配置了卡片大小等信息,froms下的是ability中生命周期管理的核心部分(用于回调),会在主函数中实现调用。
要在这里把false改成true。
上图的文件包为紧张的开拓位置,开拓者动的是index下的三个包。
完成署名之后在在线调试的实验机器上运行后就会产生一张纯的FA卡片了,此时环境已经搭建完毕。
本地缓存调取:src在main下的resources中建rawfile用于存放缓存,在编译时候打包进hap中怼到鸿蒙设备中即可get到。
下面以开拓12的mini卡片为例,在本地预置了缓存文件后我们目光转向卡片,连续把播放按钮与卡片解耦开,通过hml塞入显示信息等。isWidget当true时,card_containerdiv就会变为div布局。Ispause为true时,按钮呈现播放;为false时,显示停息按钮。
在 css 文件采取原子布局的display-index。display-index 的值越大,则越优先显示。在 main中的onCreateForm 里isMiniWidget 的data设置为 true。
在.json和main中相对应的地方添加点击事宜,到此为止就可以通过点击卡片就可以得到start与stop的互动了。做完显示界面往后,接入界面与预置确当地缓存,然后封装即可。
上图上中下分别是更新(onUpdateForm),删除(onDeleteForm),事宜(message),
更新(onUpdateForm): 卡片更新与持久化储存卡片,定时更新与要求更新时进行调用。
删除(onDeleteForm):用于删除卡片时调用。 图三:formid&massage,吸收关照。一张Fa卡片创建时须要知足的基本功能:布局加载~要求数据(ohos&intent)~产生卡片(long&天生ID用于调用){通过列举值得到}。
这样一张做事卡片就开拓好了。
四、创新点描述1. 关于智能门锁:
基于OpenHarmony开拓,利用原子化做事,拥有密码解锁,NFC解锁,数字管家掌握等功能。
2. 关于储物精灵
基于OpenHarmony开拓,利用原子化做事,密码解锁,NFC解锁,防火帘掌握,分布式软总线掌握等。
3. 关于逆变器
基于OpenHarmony开拓,拓扑架构大幅度缩小转换器桥臂和EMI滤波器的尺寸,在算法利用CEC加权效率设计与峰值电压追踪,通过品质因数公式FOM算出利用得当的GaN半导体选型结合五个桥臂的设计可以最小化逆变器的能量通报。
五、成果展现1. 编译成功
2. 动图演示(导入到word中是动图,word可能无法显示出动图效果以是把干系图片动图在上传文件夹中备份了一份)
以下动图分别是门锁的舵机驱动,NFC打卡,智能门轨的演示动图。
关注#华为云开拓者同盟# 点击下方,第一韶光理解华为云新鲜技能~
华为云博客_大数据博客_AI博客_云打算博客_开拓者中央-华为云










