萬字長文教你實現華為雲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
  • 一個自定義WPF窗體的解決方案,借鑒了呂毅老師的WPF製作高性能的透明背景的異形視窗一文,併在此基礎上增加了滑鼠穿透的功能。可以使得透明窗體的滑鼠事件穿透到下層,在下層窗體中響應。 ...
  • 在C#中使用RabbitMQ做個簡單的發送郵件小項目 前言 好久沒有做項目了,這次做一個發送郵件的小項目。發郵件是一個比較耗時的操作,之前在我的個人博客裡面回覆評論和友鏈申請是會通過發送郵件來通知對方的,不過當時只是簡單的進行了非同步操作。 那麼這次來使用RabbitMQ去統一發送郵件,我的想法是通過 ...
  • 當你使用Edge等瀏覽器或系統軟體播放媒體時,Windows控制中心就會出現相應的媒體信息以及控制播放的功能,如圖。 SMTC (SystemMediaTransportControls) 是一個Windows App SDK (舊為UWP) 中提供的一個API,用於與系統媒體交互。接入SMTC的好 ...
  • 最近在微軟商店,官方上架了新款Win11風格的WPF版UI框架【WPF Gallery Preview 1.0.0.0】,這款應用引入了前沿的Fluent Design UI設計,為用戶帶來全新的視覺體驗。 ...
  • 1.簡單使用實例 1.1 添加log4net.dll的引用。 在NuGet程式包中搜索log4net並添加,此次我所用版本為2.0.17。如下圖: 1.2 添加配置文件 右鍵項目,添加新建項,搜索選擇應用程式配置文件,命名為log4net.config,步驟如下圖: 1.2.1 log4net.co ...
  • 之前也分享過 Swashbuckle.AspNetCore 的使用,不過版本比較老了,本次演示用的示例版本為 .net core 8.0,從安裝使用開始,到根據命名空間分組顯示,十分的有用 ...
  • 在 Visual Studio 中,至少可以創建三種不同類型的類庫: 類庫(.NET Framework) 類庫(.NET 標準) 類庫 (.NET Core) 雖然第一種是我們多年來一直在使用的,但一直感到困惑的一個主要問題是何時使用 .NET Standard 和 .NET Core 類庫類型。 ...
  • WPF的按鈕提供了Template模板,可以通過修改Template模板中的內容對按鈕的樣式進行自定義。結合資源字典,可以將自定義資源在xaml視窗、自定義控制項或者整個App當中調用 ...
  • 實現了一個支持長短按得按鈕組件,單擊可以觸發Click事件,長按可以觸發LongPressed事件,長按鬆開時觸發LongClick事件。還可以和自定義外觀相結合,實現自定義的按鈕外形。 ...
  • 一、WTM是什麼 WalkingTec.Mvvm框架(簡稱WTM)最早開發與2013年,基於Asp.net MVC3 和 最早的Entity Framework, 當初主要是為瞭解決公司內部開發效率低,代碼風格不統一的問題。2017年9月,將代碼移植到了.Net Core上,併進行了深度優化和重構, ...