萬字長文教你實現華為雲IoT+OpenHarmony智能家居開發

来源:https://www.cnblogs.com/huaweiyun/archive/2023/09/18/17711447.html
-Advertisement-
Play Games

基於OpenHarmony和華為雲平臺打造的智能家居設備,分別為智能門鎖,儲物精靈 NFC版,儲物精靈Pro版三個設備。 ...


本文分享自華為雲社區《華為雲IoT+OpenHarmony的智能家居開發》,作者:袁睿。

選題說明

1. 選題為基於OpenHarmony的智能家居,應用場景為戶用,受益人群為住戶。

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 = k*angle;
    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.i***ta2=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   1
static 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 6

static 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 1000

static 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, 
              
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1. 三管齊下 1.1. 不做、少做、快速地做 1.2. 如果查詢太大,服務端會拒絕接收更多的數據並拋出相應錯誤 1.3. 如果查詢寫得很糟糕,即使庫表結構再合理、索引再合適,也無法實現高性能 1.4. 查詢優化、索引優化、庫表結構優化需要齊頭併進,一個不落 1.5. Percona Toolkit ...
  • 1、背景描述 在真實業務場景下,Linux伺服器一般位於內網,所以無法直接訪問互聯網資源; 特別是安裝資料庫的Linux伺服器,在網路方面的管控只會更加嚴格; 因此,需要提前下載好相關資源,再傳輸到內網Linux伺服器進行安裝; 2、下載Mysql的安裝包 下載地址:https://dev.mysq ...
  • 起因: 上周安裝完mysql後,成功新建了資料庫,一切都是正常的,於是就先擱置一旁。今天周一過來,卻突然發現無法連接mysql了。 過程: 第一反應是服務沒有啟動,畢竟重啟了電腦,說不定是服務沒有自動啟動,於是打開了服務管理器,卻發現沒有mysql對應的服務。既然沒有,那我就自己手動創建一個,找到m ...
  • Ubuntu20.04安裝Mysql8主從 一.主資料庫安裝 1.下載安裝包並初始化資料庫 # 進入目錄 cd /opt # 下載安裝包 wget https://dev.mysql.com/get/Downloads/MySQL-8.0/mysql-8.0.20-linux-glibc2.12-x ...
  • 本文分享自華為雲社區《DTSE Tech Talk | 第43期:數倉數據可靠保證——物理細粒度備份恢復》,作者:華為雲社區精選。 大數據時代,數據對企業的重要性不言而喻,如果發生數據丟失或因為誤操作而造成數據丟失,將對企業的經營決策帶來不可估量的損失。本期《備份恢復全掌握,數倉數據更安全》的主題直 ...
  • UUID(通用唯一識別碼)是由32個十六進位數組成的無序字元串,通過一定的演算法計算出來。為了保證其唯一性,UUID規範定義了包括網卡MAC地址、時間戳、名字空間(Namespace)、隨機或偽隨機數、時序等元素,以及從這些元素生成UUID的演算法。一般來說,演算法可以保證任何地方產生的任意一個UUID都... ...
  • Redis是游戲資料庫重要選型之一,華為雲GaussDB(for Redis)能及時上報用戶下線行為,被廣泛應用於排行榜等多種業務場景。 ...
  • Ubuntu20.04安裝Postgres主從備份 一.查看可安裝的Postgres包 #列出相關的軟體包,這裡安裝的是14版本 apt list | grep -w postgresql-14 | tail -1 #下載Postgres apt install -y postgresql-14/f ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...