萬字長文教你實現華為雲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 微服務框架,幫助我們輕鬆構建和管理微服務應用。 本框架不僅支持 Consul 服務註 ...
  • 先看一下效果吧: 如果不會寫動畫或者懶得寫動畫,就直接交給Blend來做吧; 其實Blend操作起來很簡單,有點類似於在操作PS,我們只需要設置關鍵幀,滑鼠點來點去就可以了,Blend會自動幫我們生成我們想要的動畫效果. 第一步:要創建一個空的WPF項目 第二步:右鍵我們的項目,在最下方有一個,在B ...
  • Prism:框架介紹與安裝 什麼是Prism? Prism是一個用於在 WPF、Xamarin Form、Uno 平臺和 WinUI 中構建鬆散耦合、可維護和可測試的 XAML 應用程式框架 Github https://github.com/PrismLibrary/Prism NuGet htt ...
  • 在WPF中,屏幕上的所有內容,都是通過畫筆(Brush)畫上去的。如按鈕的背景色,邊框,文本框的前景和形狀填充。藉助畫筆,可以繪製頁面上的所有UI對象。不同畫筆具有不同類型的輸出( 如:某些畫筆使用純色繪製區域,其他畫筆使用漸變、圖案、圖像或繪圖)。 ...
  • 前言 嗨,大家好!推薦一個基於 .NET 8 的高併發微服務電商系統,涵蓋了商品、訂單、會員、服務、財務等50多種實用功能。 項目不僅使用了 .NET 8 的最新特性,還集成了AutoFac、DotLiquid、HangFire、Nlog、Jwt、LayUIAdmin、SqlSugar、MySQL、 ...
  • 本文主要介紹攝像頭(相機)如何採集數據,用於類似攝像頭本地顯示軟體,以及流媒體數據傳輸場景如傳屏、視訊會議等。 攝像頭採集有多種方案,如AForge.NET、WPFMediaKit、OpenCvSharp、EmguCv、DirectShow.NET、MediaCaptre(UWP),網上一些文章以及 ...
  • 前言 Seal-Report 是一款.NET 開源報表工具,擁有 1.4K Star。它提供了一個完整的框架,使用 C# 編寫,最新的版本採用的是 .NET 8.0 。 它能夠高效地從各種資料庫或 NoSQL 數據源生成日常報表,並支持執行複雜的報表任務。 其簡單易用的安裝過程和直觀的設計界面,我們 ...
  • 背景需求: 系統需要對接到XXX官方的API,但因此官方對接以及管理都十分嚴格。而本人部門的系統中包含諸多子系統,系統間為了穩定,程式間多數固定Token+特殊驗證進行調用,且後期還要提供給其他兄弟部門系統共同調用。 原則上:每套系統都必須單獨接入到官方,但官方的接入複雜,還要官方指定機構認證的證書 ...
  • 本文介紹下電腦設備關機的情況下如何通過網路喚醒設備,之前電源S狀態 電腦Power電源狀態- 唐宋元明清2188 - 博客園 (cnblogs.com) 有介紹過遠程喚醒設備,後面這倆天瞭解多了點所以單獨加個隨筆 設備關機的情況下,使用網路喚醒的前提條件: 1. 被喚醒設備需要支持這WakeOnL ...
  • 前言 大家好,推薦一個.NET 8.0 為核心,結合前端 Vue 框架,實現了前後端完全分離的設計理念。它不僅提供了強大的基礎功能支持,如許可權管理、代碼生成器等,還通過採用主流技術和最佳實踐,顯著降低了開發難度,加快了項目交付速度。 如果你需要一個高效的開發解決方案,本框架能幫助大家輕鬆應對挑戰,實 ...