AliSmartLiving使用详解

本文介绍如何在AliSmartLiving平台上集成WebSocketServer支持,使设备能直接通过WiFi热点被APP控制,绕过阿里云生活物联网平台,减少成本并提高灵活性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Li Zheng flyskywhy@gmail.com 也可参见我在 github.com 上的博客 AliSmartLiving使用详解.md

阿里云生活物联网平台

安装设备端编译环境

由于 Ubuntu 用来编译 alios 的工具 aos 只能通过 python3 相关的组件 python3-pip 来安装,而 ali-smartliving-device-alios-things 中一些官方提供的 python 脚本仍然是 python2 语法的,所以需要如下罗嗦的方法来安装编译环境,而非仅仅只是安装 aos 即可。

安装 python 和 aos

sudo apt-get install python2 python3 python3-pip
pip3 install aos-cube

让 python 脚本运行在 python2 中

如果通过如下命令

ls -l /usr/bin/python

发现

/usr/bin/python -> python3

cd /usr/bin
sudo ln -f -s python2 python

否则编译时会出现 NameError: name 'file' is not defined 等错误。

让 aos 运行在 python3 中

用文本编辑器打开 ~/.local/bin/aos ,确保第一行是 #!/usr/bin/python3

否则编译时会出现 ImportError: No module named aos.__main__ 错误。

其它

我也曾想要通过简单将脚本从 python2 升级到 python3 语法来解决 NameError: name 'file' is not defined 等错误,但是又带来了其它语法问题,这已经不是我们而是 sdk 提供者需要再花时间在上面了,还是如上所述安装 python2 吧。之前听说 python 2 和 3 不兼容因而我一直拒绝深入学习使用 python ,果然 python 就是差劲啊,开源世界还不如将用到 python 的地方都切换为 nodejs 呢。

注,上述简单将 python2 的 file 改为 python3 的 open 后,还会出现如下报错信息:

Traceback (most recent call last):
  File "tools/bk7231u/gen_firmware_img_uart0.py", line 39, in <module>
    pack_image(sys.argv[1], sys.argv[2])
  File "tools/bk7231u/gen_firmware_img_uart0.py", line 30, in pack_image
    f.write("\xff")
TypeError: a bytes-like object is required, not 'str'

设备端编译 Ali SmartLiving

参见 ali-smartliving-device-alios-things/README.mdbuild.sh 的使用方法。

设备端添加 WebSocket Server 支持

添加 WebSocket Server 之后,就可以配合模块厂商(不是阿里官方)的 WiFi 热点代码,让 APP 直连控制设备,而无需
Ali SmartLiving 官方的扫描、配网、控制设备流程,无需烧录产品 id 等三元组信息,因此也就无需向阿里购买这些三元组(因为直连模式不走阿里云生活物联网平台也能用),甚至无需烧录可能也要花钱购买的 mac 地址!之所以使用 WebSocket 而非传统的 Socket ,是因为浏览器不支持创建 Socket 连接,而使用 WebSocket 的话,(react-native 和 react-native-web 同一套代码编写的)手机版或网页版 APP 都可以进行连接。

之所以在 Comparison of WebSocket implementations 中选择 libwebsockets 而非 noPoll 等 C 语言 WebSocket 实现,是因为 Ali SmartLiving 所依赖的 AliOS-Things 曾经采用过一段时间的 libwebsockets ,所以可以参考当时的阿里官方适配代码。

以下列出针对 Ali SmartLiving 的飞燕 SDK 1.6.0 添加 WebSocket Server 支持的方法

添加 libwebsockets 的第 1 步: 简单复制 https://github.com/warmcat/libwebsockets/tree/v2.4.1/lib/ 整个目录

将该 lib/ 目录复制为 Living_SDK/framework/libwebsockets/ 。之所以选择 v2.4.1 ,是因为经比较发现,阿里官方曾经适配过的 libwebsockets 代码就是这个版本的。

添加 libwebsockets 的第 2 步: 复制阿里官方的适配代码,来自 https://github.com/alibaba/AliOS-Things/commit/9326fc864c282e6c3209b2fd00082b451effa54e

将该提交点中新增的文件复制到 Living_SDK/framework/libwebsockets/ 中。

添加 libwebsockets 的第 3 步: 在你自己的代码中使用 libwebsockets 并开启 websocket server

Living_SDK/framework/libwebsockets/libwebsockets.mk

Living_SDK/framework/libwebsockets/websockets.mk 重命名为 libwebsockets.mk ,并做如下修改

@@ -1,17 +1,16 @@
-NAME := websockets
+NAME := libwebsockets

 GLOBAL_CFLAGS += -Wall

-$(NAME)_COMPONENTS := mbedtls alicrypto connectivity.websockets.mbedtls_wrapper
+$(NAME)_COMPONENTS := imbedtls alicrypto libwebsockets.mbedtls_wrapper

 $(NAME)_SOURCES := handshake.c libwebsockets.c service.c pollfd.c output.c context.c alloc.c header.c ssl.c

 $(NAME)_SOURCES += misc/base64-decode.c misc/lws-ring.c misc/lws-genhash.c misc/sha-1.c

-#$(NAME)_SOURCES += server/ranges.c server/server.c server/parsers.c server/ssl-server.c server/server-handshake.c
-$(NAME)_SOURCES += server/parsers.c
+$(NAME)_SOURCES += server/server.c server/parsers.c server/ssl-server.c server/server-handshake.c

-$(NAME)_SOURCES += client/client.c client/client-handshake.c client/client-parser.c client/ssl-client.c
+# $(NAME)_SOURCES += client/client.c client/client-handshake.c client/client-parser.c client/ssl-client.c
Living_SDK/framework/libwebsockets/lws_config.h
@@ -75,10 +75,10 @@
 #define LWS_NO_DAEMONIZE

 /* Build without server support */
-#define LWS_NO_SERVER
+/* #undef LWS_NO_SERVER */

 /* Build without client support */
-/* #undef LWS_NO_CLIENT */
+#define LWS_NO_CLIENT
Living_SDK/framework/libwebsockets/mbedtls_wrapper/mbedtls_wrapper.mk
-$(NAME)_COMPONENTS := mbedtls alicrypto
+$(NAME)_COMPONENTS := imbedtls alicrypto
Living_SDK/framework/libwebsockets/sync.py
-sync = False #do not sync this module
+# sync = False #do not sync this module
Products/example/YourAPP/YourAPP.mk
 $(NAME)_COMPONENTS += framework/protocol/linkkit/sdk \
                       framework/protocol/linkkit/hal \
                       framework/netmgr \
+                      framework/libwebsockets \
                       framework/common \
                       utility/cjson \
                       framework/uOTA
Products/example/YourAPP/makefile
@@ -14,6 +14,9 @@ INCLUDE      = $(INCLUDE_PATH)/ \
                -I$(PWD)/../../../prebuild/include/platform/arch/arm/armv7m/gcc/m4 \
                -I$(PWD)/../../../prebuild/include/board/$(BOARD) \
                -I$(PWD)/../../../Living_SDK/kernel/protocols/net/include \
+               -I$(PWD)/../../../Living_SDK/security/imbedtls/include \
+               -I$(PWD)/../../../Living_SDK/framework/libwebsockets \
+               -I$(PWD)/../../../Living_SDK/framework/libwebsockets/mbedtls_wrapper/include \
                -I$(PWD)/../../../Living_SDK/platform/mcu/bk7231u/beken/alios/entry \
                -I$(PWD)/../../../Living_SDK/platform/mcu/bk7231u/beken/alios/lwip-2.0.2/port \
                -I$(PWD)/../../../Living_SDK/platform/mcu/bk7231u/beken/common \
Products/example/YourAPP/softap.c
#include <lwip/sockets.h>

#include <libwebsockets.h>
#define LWS_PLUGIN_STATIC

#include "aos/kv.h"

#define SOCK_IN_PORT 7681

typedef void*(*property_rw_func)(const char *request, const int request_len);
property_rw_func softap_property_setting_cb = 0;

static unsigned char softap_flag = 0;
static bool softap_launch = false;
static bool connected = false;

void SetSoftApPropertySettingHandle(void* cb)
{
    if(cb != NULL){
        softap_property_setting_cb = cb;
    }
}

void softap_msg_response_handle(char* msg, int len)
{
    // lws_callback_on_writable

    return;
}

static void softap_property_setting_handle(const char* buffer, int len)
{
    if(softap_property_setting_cb != NULL){
        softap_property_setting_cb(buffer, len);
    }
}

bool softap_isstart(void){
    return softap_launch;
}

void softap_task_stop(void){
    softap_launch = false;
}

void softap_task_start(void){
    softap_launch = true;
}

// 参见下面 TODO 中的说明
struct per_session_data__minimal {
    struct per_session_data__minimal *pss_list;
    struct lws *wsi;
    int last; /* the last message number we sent */
};

static int
callback_smartliving(struct lws *wsi, enum lws_callback_reasons reason,
            void *user, void *in, size_t len)
{
    LOGD("LWS_CALLBACK %d", reason);
    switch (reason) {
    case LWS_CALLBACK_PROTOCOL_INIT:
        break;

    case LWS_CALLBACK_ESTABLISHED:
        if (connected) {
            // TODO: allow more than 1 connection?
            // 不过直连类的应用,同时只需要连一个手机就可以了吧?
            // 后续如果真要同时连接好几个,可以参考
            // https://github.com/warmcat/libwebsockets/blob/master/minimal-examples/ws-server/minimal-ws-server/minimal-ws-server.c
            // 中的相关代码。
            // 其实上面的 per_session_data__minimal 就是那些代码的残留。
            // UPDATE: 实际上,经测试,现有代码就能同时建立 2 个 connection ,
            // 测试用的 1 个是 macbook 中的网页, 1 个是手机 APP ,理论上可以
            // 有更多连接。
            // 之所以能够不用折腾 per_session_data__minimal 就支持多个连接
            // 可能与我们用的是 ws:// 而非 wss:// 有关?
            // 真正的连接数限制可能与下面的 info.max_http_header_pool
            // 或 info.ip_limit_ah 等相关。
            LOG("only one connection is allowed\n");
            lws_close_reason(wsi, LWS_CLOSE_STATUS_UNEXPECTED_CONDITION,
                     (unsigned char *)"only one", 5);
            return -1;
        } else {
            connected = true;
            LOG("websocket established\n");
        }
        break;

    case LWS_CALLBACK_CLOSED:
            connected = false;
            LOG("websocket closed\n");
        break;

    case LWS_CALLBACK_SERVER_WRITEABLE:
        // TODO: 后续再考虑发送数据给手机,先简化吧
        // 如果要编写发送数据的代码,记得参考
        // https://libwebsockets.org/lws-api-doc-v2.4-stable/html/md_READMEs_README_8coding.html
        // 中提到的使用 lws_callback_on_writable 的方式进行,
        // 还可以一定程度上参考
        // https://github.com/warmcat/libwebsockets/blob/master/minimal-examples/ws-server/minimal-ws-server/minimal-ws-server.c
        // 中 lws_callback_on_writable 的使用,比如在其它需要发送数据的 .c 文件中调用
        // 本文件中内含 lws_callback_on_writable 的 softap_msg_response_handle()
        break;

    case LWS_CALLBACK_RECEIVE:
        if(len <= 0){
            return -1;
        }
        LOG("[SoftAP]recv data = [%d]%s\n", len, (const char *)in);
        softap_property_setting_handle((const char *)in, len);
        break;

    default:
        break;
    }

    return 0;
}

static struct lws_protocols protocols[] = {
    // { "http", lws_callback_http_dummy, 0, 0 },
    {
        "local-ali-smartliving",
        callback_smartliving,
        sizeof(struct per_session_data__minimal),
        200,
        0, NULL, 0
    },
    { NULL, NULL, 0, 0 } /* terminator */
};

static void websocket_server(void)
{
    struct lws_context_creation_info info;
    struct lws_context *context;
    const char *p;
    int n = 0, logs = LLL_USER | LLL_ERR | LLL_WARN | LLL_NOTICE
            /* for LLL_ verbosity above NOTICE to be built into lws,
             * lws must have been configured and built with
             * -DCMAKE_BUILD_TYPE=DEBUG instead of =RELEASE */
            /* | LLL_INFO */ /* | LLL_PARSER */ /* | LLL_HEADER */
            /* | LLL_EXT */ /* | LLL_CLIENT */ /* | LLL_LATENCY */
            /* | LLL_DEBUG */;

    lws_set_log_level(logs, NULL);

    memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
    info.port = SOCK_IN_PORT;
    info.protocols = protocols;
    info.max_http_header_pool = 5;
    // info.vhost_name = "localhost";
    // info.options =
    //     LWS_SERVER_OPTION_HTTP_HEADERS_SECURITY_BEST_PRACTICES_ENFORCE;
    info.options = LWS_SERVER_OPTION_VALIDATE_UTF8;

    // info.ip_limit_ah = 3;
    // info.ip_limit_wsi = 5;

    context = lws_create_context(&info);
    if (!context) {
        LWIP_ASSERT("[SoftAP]WebSocket bind failed.", 0);
        // return;
    }

    LOG("[SoftAP]enter websocket_server loop");
    while (true)
    {
        while(!softap_launch){
            aos_msleep(1000);
        }

        n = lws_service(context, 50);
    }

    lws_context_destroy(context);

    LOG("[SoftAP]exit soft ap task");
    aos_task_exit(0);
}

void softap_task(void)
{
    LOG("[SoftAP]enter soft ap task");
    websocket_server();
}


int init_softap_flag()
{
    unsigned char value;
    int ret, len = sizeof(value);

    ret = aos_kv_get("soft ap flag", &value, &len);
    if (ret == 0 && len > 0) {
        softap_flag = value;
        LOG("soft ap flag = %d", (int)value);
    }else{
        LOG("soft ap get err ret = %d", ret);
        softap_flag = 1;
        aos_kv_set("soft ap flag", &softap_flag, len, 1);
    }
    return 0;
}

int set_softap_flag(unsigned char value)
{
    int ret, len = sizeof(value);
    softap_flag = value;
    ret = aos_kv_set("soft ap flag", &value, len, 1);
    if(ret != 0){
        LOG("kv set failed ret = %d", ret);
    }
}

inline const unsigned char get_softap_flag(void)
{
    return softap_flag;
}
tools/bk7231udevkitc.sh
    if [[ "$2" == httpapp ]] || [[ "$2" == coapapp ]];then
-       COMMON_LIBS="$p/$2.a  $p/board_bk7231u.a  $p/vcall.a  $p/kernel_init.a  $p/auto_component.a  $p/libiot_sdk.a $p/iotx-hal.a  $p/hal_init.a  $p/netmgr.a  $p/framework.a  $p/cjson.a   $p/cli.a   $p/$ARCH.a  $p/newlib_stub.a  $p/rhino.a  $p/digest_algorithm.a  $p/net.a  $p/log.a  $p/activation.a  $p/chip_code.a  $p/imbedtls.a  $p/kv.a  $p/yloop.a  $p/hal.a   $p/alicrypto.a  $p/vfs.a  $p/vfs_device.a   $p/awss_security.a $p/libaiotss.a "
+       COMMON_LIBS="$p/$2.a  $p/mbedtls_wrapper.a  $p/libwebsockets.a  $p/board_bk7231u.a  $p/vcall.a  $p/kernel_init.a  $p/auto_component.a  $p/libiot_sdk.a $p/iotx-hal.a  $p/hal_init.a  $p/netmgr.a  $p/framework.a  $p/cjson.a   $p/cli.a   $p/$ARCH.a  $p/newlib_stub.a  $p/rhino.a  $p/digest_algorithm.a  $p/net.a  $p/log.a  $p/activation.a  $p/chip_code.a  $p/imbedtls.a  $p/kv.a  $p/yloop.a  $p/hal.a   $p/alicrypto.a  $p/vfs.a  $p/vfs_device.a   $p/awss_security.a $p/libaiotss.a "
    else
-       COMMON_LIBS="$p/$2.a  $p/board_bk7231u.a  $p/vcall.a  $p/kernel_init.a  $p/auto_component.a  $p/libiot_sdk.a $p/iotx-hal.a  $p/hal_init.a  $p/netmgr.a  $p/framework.a  $p/cjson.a  $p/ota.a  $p/cli.a  $p/ota_hal.a  $p/$ARCH.a  $p/newlib_stub.a  $p/rhino.a  $p/digest_algorithm.a  $p/net.a  $p/log.a  $p/activation.a  $p/chip_code.a  $p/imbedtls.a  $p/kv.a  $p/yloop.a  $p/hal.a  $p/ota_transport.a  $p/ota_download.a  $p/ota_verify.a  $p/base64.a  $p/alicrypto.a  $p/vfs.a  $p/vfs_device.a   $p/awss_security.a $p/libaiotss.a "
+       COMMON_LIBS="$p/$2.a  $p/mbedtls_wrapper.a  $p/libwebsockets.a  $p/board_bk7231u.a  $p/vcall.a  $p/kernel_init.a  $p/auto_component.a  $p/libiot_sdk.a $p/iotx-hal.a  $p/hal_init.a  $p/netmgr.a  $p/framework.a  $p/cjson.a  $p/ota.a  $p/cli.a  $p/ota_hal.a  $p/$ARCH.a  $p/newlib_stub.a  $p/rhino.a  $p/digest_algorithm.a  $p/net.a  $p/log.a  $p/activation.a  $p/chip_code.a  $p/imbedtls.a  $p/kv.a  $p/yloop.a  $p/hal.a  $p/ota_transport.a  $p/ota_download.a  $p/ota_verify.a  $p/base64.a  $p/alicrypto.a  $p/vfs.a  $p/vfs_device.a   $p/awss_security.a $p/libaiotss.a "
    fi
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值