涂鸦智能 ① tuya-wifi-mcu-sdk-arduino-library 简单剖析

1、简介

Tuya MCU SDK Arduino Library 基于涂鸦Wi-Fi 通用对接方案进行开发的,设备 MCU 通过串口与 Wi-Fi 模组连接实现设备联网。涂鸦模组中的固件应为通用固件,通用固件支持9600,115200两种波特率自适应。

在这里插入图片描述

注意点:

  • Arduino板子 + 涂鸦模块的开发方式,据说后期可以单独模块开发。
  • 串口通信

2、配置Arduino环境

2.1 下载Arduino sdk

  • 方式一:

https://gitee.com/ant_onio/tuya-wifi-mcu-sdk-arduino-library 点击下载
在这里插入图片描述
解压到自己的电脑路径(此电脑->文档->Arduino->libraries)

  • 方式二(推荐):

Arduino IDE -> 工具 -> 管理库 -> 搜索 tuya-> 安装最新版本
在这里插入图片描述

3、剖析SDK

记住一点,这种方式是mcu + module 串口通信开发方式

简单来说,肯定数据是不断处理串口通信,那么从另外一个点来说就是模组已经内置了串口协议数据处理逻辑。

博哥大概代码看了一下:
在这里插入图片描述

3.1 TuyaUart —— 处理和模组进行串口通信(了解即可)

class TuyaUart
{
public:
    // 主要是定义串口通信buffer缓存大小
    volatile unsigned char wifi_uart_rx_buf[PROTOCOL_HEAD + WIFI_UART_RECV_BUF_LMT];     //Serial data processing buffer
    volatile unsigned char wifi_uart_tx_buf[PROTOCOL_HEAD + WIFIR_UART_SEND_BUF_LMT];    //Serial receive buffer
    volatile unsigned char wifi_data_process_buf[PROTOCOL_HEAD + WIFI_DATA_PROCESS_LMT]; //Serial port send buffer

    TuyaUart(void);
    ~TuyaUart(void);
    void wifi_protocol_init(void);

    //  接收数据
    unsigned char uart_receive_input(unsigned char data);
    void uart_receive_buff_input(unsigned char value[], unsigned short data_len);
    unsigned char take_byte_rxbuff(void);
    unsigned char with_data_rxbuff(void);

    // 传输发送数据
    void uart_transmit_output(unsigned char value);
    void wifi_uart_write_data(unsigned char *in, unsigned short len);
    void wifi_uart_write_frame(unsigned char fr_type, unsigned char fr_ver, unsigned short len);
    unsigned short set_wifi_uart_byte(unsigned short dest, unsigned char byte);
    unsigned short set_wifi_uart_buffer(unsigned short dest, const unsigned char *src, unsigned short len);

    /* serial set */
    bool _isHWSerial;

    //  串口设置
    void set_serial(HardwareSerial *serial);
    void set_serial(SoftwareSerial *serial);
    void begin(long baud_rate);
    char read(void);
    size_t write(char value);
    int available(void);

private:
    volatile unsigned char *rx_buf_in;
    volatile unsigned char *rx_buf_out;
    Stream *_port;
};

3.2 TuyaTools —— 工具类方法(了解即可)

class TuyaTools
{
public:
    TuyaTools(void);
    ~TuyaTools(void);

    unsigned char hex_to_bcd(unsigned char Value_H, unsigned char Value_L);
    // 计算字符串长度
    unsigned long my_strlen(unsigned char *str);
    // 设置字符串
    void *my_memset(void *src, unsigned char ch, unsigned short count);
    // 内存拷贝
    void *my_memcpy(void *dest, const void *src, unsigned short count);
    // 字符串拷贝
    char *my_strcpy(char *dest, const char *src);
    // 字符串对比
    int my_strcmp(char *s1, char *s2);
    // int 转字节数组
    void int_to_byte(unsigned long number, unsigned char value[4]);
    // 字节数组 转int
    unsigned long byte_to_int(const unsigned char value[4]);
    unsigned char get_check_sum(unsigned char *pack, unsigned short pack_len);

private:
};

3.3 TuyaDataPoint —— 处理数据节点(上传、下发)


class TuyaDataPoint
{
public:
    // TuyaDataPoint(void);
    // ~TuyaDataPoint(void);
    // 下发节点数据
    unsigned char mcu_get_dp_download_bool(const unsigned char value[], unsigned short len);
    unsigned char mcu_get_dp_download_enum(const unsigned char value[], unsigned short len);
    unsigned long mcu_get_dp_download_value(const unsigned char value[], unsigned short len);

    // 上报节点数据
    unsigned char mcu_dp_raw_update(unsigned char dpid, const unsigned char value[], unsigned short len);
    unsigned char mcu_dp_bool_update(unsigned char dpid, unsigned char value);
    unsigned char mcu_dp_value_update(unsigned char dpid, unsigned long value);
    unsigned char mcu_dp_string_update(unsigned char dpid, const unsigned char value[], unsigned short len);
    unsigned char mcu_dp_enum_update(unsigned char dpid, unsigned char value);
    unsigned char mcu_dp_fault_update(unsigned char dpid, unsigned long value);

private:
};

注意区分一下数据类型。
DP为 Data Point 的缩写,即数据点,偶尔被称为 DP 点,表示智能设备所具备的功能点。

  • 涂鸦智能将每个功能点抽象成数据点,数据点定义成不同的类型,例如布尔、枚举、数值等。
  • 数据点具备读写属性。例如,一个两路的开关,可以抽象成两个数据点,每个数据点类型为布尔型,可取值为 TrueFalse
  • 数据点可读写,读表示获取开关目前的值,写表示改变开关目前的值。

DPID:指定通信协议下 DP 事件的 ID。

节点类型:

#define DP_TYPE_RAW     0x00    //RAW type
#define DP_TYPE_BOOL    0x01    //bool type
#define DP_TYPE_VALUE   0x02    //value type
#define DP_TYPE_STRING  0x03    //string type
#define DP_TYPE_ENUM    0x04    //enum type
#define DP_TYPE_BITMAP  0x05    //fault type

3.4 TuyaWifi —— 处理wifi网络相关操作,重点内容

在Arduino中使用该库进行编程开发时,必须在你的Arduino工程文件中包含 TuyaWifi.h 头文件。

一般很多sdk的开发方式都是:

  • 1、创建对象 构造方法
  • 2、初始化 init
  • 3、回调配置、信息注册 register、callbackHandler
  • 4、不断轮询处理响应
3.4.1 unsigned char TuyaWifi::init(unsigned char *pid, unsigned char *mcu_ver) —— 初始化

PID通过在 Tuya IoT平台 上创建产品获取,wifi类的长度一般为16,mcu_ver 这个参数是软件的版本号。

3.4.2 void set_dp_cmd_total(unsigned char download_cmd_array[][2], unsigned char download_cmd_num) —— 配置节点

Tuya IoT平台创建产品,获取产品DP点信息。

DP为 Data Point 的缩写,即数据点,偶尔被称为 DP 点,表示智能设备所具备的功能点。

  • 涂鸦智能将每个功能点抽象成数据点,数据点定义成不同的类型,例如布尔、枚举、数值等。
  • 数据点具备读写属性。例如,一个两路的开关,可以抽象成两个数据点,每个数据点类型为布尔型,可取值为 TrueFalse
  • 数据点可读写,读表示获取开关目前的值,写表示改变开关目前的值。

DPID:指定通信协议下 DP 事件的 ID。

MCU SDK需要知道你创建了哪些DP点,他们是什么类型的。

3.4.3 void mcu_set_wifi_mode(unsigned char mode) —— 配网模式
/**
 * @description: MCU set wifi working mode
 * @param {unsigned char} mode : enter mode 
 *                               0(SMART_CONFIG):enter smartconfig mode
 *                               1(AP_CONFIG):enter AP mode
 * @return {*}
 */
void TuyaWifi::mcu_set_wifi_mode(unsigned char mode);
3.4.4 void dp_process_func_register(tuya_callback_dp_download _func) —— 下发回调注册

当APP控制设备的时候,会从云端下发对应的DP命令到设备,设备对数据进行解析后,对下发的命令执行相对于的动作。

对下发命令的处理,通过回调函数来调用,所以我们需要把你的处理函数注册一下。

伪代码:

//register DP download processing callback function
  my_device.dp_process_func_register(dp_process);

/**
 * @description: DP download callback function.
 * @param {unsigned char} dpid
 * @param {const unsigned char} value
 * @param {unsigned short} length
 * @return {unsigned char}
 */
unsigned char dp_process(unsigned char dpid, const unsigned char value[], unsigned short length)
{
    switch (dpid) {
        case DPID_BOOL:
            DebugSerial.println("Bool type:");
            dp_bool_value = my_device.mcu_get_dp_download_data(dpid, value, length);
            DebugSerial.println(dp_bool_value);
            /* After processing the download DP command, the current status should be reported. */
            my_device.mcu_dp_update(DPID_BOOL, dp_bool_value, 1);
        break;
            
        case DPID_VALUE:
            DebugSerial.println("Value type:");
            dp_value_value = my_device.mcu_get_dp_download_data(DPID_VALUE, value, length);
            DebugSerial.println(dp_value_value);
            /* After processing the download DP command, the current status should be reported. */
            my_device.mcu_dp_update(DPID_VALUE, dp_value_value, 1);
        break;

        case DPID_ENUM:
            DebugSerial.println("Enum type:");
            dp_enum_value = my_device.mcu_get_dp_download_data(dpid, value, length);
            DebugSerial.println(dp_enum_value);
            /* After processing the download DP command, the current status should be reported. */
            my_device.mcu_dp_update(DPID_ENUM, dp_enum_value, 1);
        break;

        case DPID_STRING:
            DebugSerial.println("String type:");
            /*  */
            for (unsigned int i=0; i<length; i++) {
                dp_string_value[i] = value[i];
                DebugSerial.write(dp_string_value[i]);
            }
            DebugSerial.println("");
            /* After processing the download DP command, the current status should be reported. */
            my_device.mcu_dp_update(DPID_STRING, dp_string_value, length);
        break;

        case DPID_RAW:
            DebugSerial.println("Raw type:");
            /*  */
            for (unsigned int i=0; i<length; i++) {
                dp_raw_value[i] = value[i];
                DebugSerial.write(dp_raw_value[i]);
            }
            DebugSerial.println("");
            /* After processing the download DP command, the current status should be reported. */
            my_device.mcu_dp_update(DPID_RAW, dp_raw_value, length);
        break;

        default:
            break;
    }
    
    return SUCCESS;
}

这里得注意一个方法:

mcu_get_dp_download_data  (`下发DP数据处理`)

对字节数组进行数据解析。

3.4.5 mcu_dp_update —— 真正上报设备状态

    /* char * */
    unsigned char mcu_dp_update(unsigned char dpid, const unsigned char value[], unsigned short len); /* char raw */
    /* unsigned long / long */
    unsigned char mcu_dp_update(unsigned char dpid, unsigned long value, unsigned short len);
    unsigned char mcu_dp_update(unsigned char dpid, long value, unsigned short len);
    /* unsigned char / char */
    unsigned char mcu_dp_update(unsigned char dpid, unsigned char value, unsigned short len);
    unsigned char mcu_dp_update(unsigned char dpid, char value, unsigned short len);
    /* unsigned int / int */
    unsigned char mcu_dp_update(unsigned char dpid, unsigned int value, unsigned short len);
    unsigned char mcu_dp_update(unsigned char dpid, int value, unsigned short len);

基本上大同小异。注意一下dpid和数据类型即可。

3.4.6 dp_update_all_func_register —— 上报设备状态函数注册
#include <TuyaWifi.h>

TuyaWifi my_device;

#define DPID_SWITCH 20
//Record the current status of the led
unsigned char switch_value = 0;
...
void setup() 
{
    ...
  //register DP download processing callback function
  my_device.dp_update_all_func_register(dp_update_all);
    ...
}

/**
 * @description: Upload all DP status of the current device.
 * @param {*}
 * @return {*}
 */
void dp_update_all(void)
{
  my_device.mcu_dp_update(DPID_SWITCH, switch_v
3.4.7 mcu_get_wifi_work_state —— 获取wifi连接状态
3.4.8 void TuyaWifi::uart_service(void) —— 轮询串口数据

/**
 * @description: Wifi serial port processing service
 * @param {*}
 * @return {*}
 */
void TuyaWifi::uart_service(void)

在arduino loop中调用。不断检测串口数据。

4、官方案例

/*
 * @FileName: DataPointType.ino
 * @Author: Tuya
 * @Email: 
 * @LastEditors: Tuya
 * @Date: 2021-04-19 14:31:52
 * @LastEditTime: 2021-04-28 19:47:36
 * @Copyright: HANGZHOU TUYA INFORMATION TECHNOLOGY CO.,LTD
 * @Company: http://www.tuya.com
 * @Description: 
 * @Github:https://github.com/tuya/tuya-wifi-mcu-sdk-arduino-library
 */

#include <TuyaWifi.h>
#include <SoftwareSerial.h>

TuyaWifi my_device;
SoftwareSerial DebugSerial(8,9);

/* Current LED status */
unsigned char led_state = 0;
/* Connect network button pin */
int wifi_key_pin = 7;

/* Data point define */
#define DPID_BOOL   101
#define DPID_VALUE  102
#define DPID_ENUM   103
#define DPID_STRING 104
#define DPID_RAW    105
#define DPID_FAULT  106

/* Current device DP values */
unsigned char dp_bool_value = 0;
long dp_value_value = 0;
unsigned char dp_enum_value = 0;
unsigned char dp_string_value[8] = {"Hi,Tuya"};
unsigned char dp_raw_value[8] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef};
int dp_fault_value = 0x01;

/* Stores all DPs and their types. PS: array[][0]:dpid, array[][1]:dp type. 
 *                                     dp type(TuyaDefs.h) : DP_TYPE_RAW, DP_TYPE_BOOL, DP_TYPE_VALUE, DP_TYPE_STRING, DP_TYPE_ENUM, DP_TYPE_BITMAP
*/
unsigned char dp_array[][2] = {
    {DPID_BOOL, DP_TYPE_BOOL},
    {DPID_VALUE, DP_TYPE_VALUE},
    {DPID_ENUM, DP_TYPE_ENUM},
    {DPID_STRING, DP_TYPE_STRING},
    {DPID_RAW, DP_TYPE_RAW},
    {DPID_FAULT, DP_TYPE_BITMAP},
};

unsigned char pid[] = {"xxxxxxxxxxx"}; //  填上自己的产品ID
unsigned char mcu_ver[] = {"1.0.0"};

/* last time */
unsigned long last_time = 0;

void setup()
{
    Serial.begin(9600);
    DebugSerial.begin(9600);

    //Initialize led port, turn off led.
    pinMode(LED_BUILTIN, OUTPUT);
    digitalWrite(LED_BUILTIN, LOW);

    //Initialize networking keys.
    pinMode(wifi_key_pin, INPUT_PULLUP);

    // 三部曲 —— 初始化、配置、注册回调
    //Enter the PID and MCU software version
    my_device.init(pid, mcu_ver);
    //incoming all DPs and their types array, DP numbers
    my_device.set_dp_cmd_total(dp_array, 6);
    //register DP download processing callback function
    my_device.dp_process_func_register(dp_process);
    //register upload all DP callback function
    my_device.dp_update_all_func_register(dp_update_all);

    last_time = millis();
}

void loop()
{
    // 不断轮询
    my_device.uart_service();

    //Enter the connection network mode when Pin7 is pressed.
    if (digitalRead(wifi_key_pin) == LOW) {
        delay(80);
        if (digitalRead(wifi_key_pin) == LOW) {
            my_device.mcu_set_wifi_mode(SMART_CONFIG);
        }
    }

    /* LED blinks when network is being connected */
    if ((my_device.mcu_get_wifi_work_state() != WIFI_LOW_POWER) && (my_device.mcu_get_wifi_work_state() != WIFI_CONN_CLOUD) && (my_device.mcu_get_wifi_work_state() != WIFI_SATE_UNKNOW)) {
        if (millis() - last_time >= 500) {
            last_time = millis();
            /* Toggle current LED status */
            if (led_state == LOW) {
                led_state = HIGH;
            } else {
                led_state = LOW;
            }

            digitalWrite(LED_BUILTIN, led_state);
        }
    }

    delay(10);
}

/**
 * @description: DP download callback function.
 * @param {unsigned char} dpid
 * @param {const unsigned char} value
 * @param {unsigned short} length
 * @return {unsigned char}
 */
unsigned char dp_process(unsigned char dpid, const unsigned char value[], unsigned short length)
{
    switch (dpid) {
        case DPID_BOOL:
            DebugSerial.println("Bool type:");
            dp_bool_value = my_device.mcu_get_dp_download_data(dpid, value, length);
            DebugSerial.println(dp_bool_value);
            /* After processing the download DP command, the current status should be reported. */
            my_device.mcu_dp_update(DPID_BOOL, dp_bool_value, 1);
        break;
            
        case DPID_VALUE:
            DebugSerial.println("Value type:");
            dp_value_value = my_device.mcu_get_dp_download_data(DPID_VALUE, value, length);
            DebugSerial.println(dp_value_value);
            /* After processing the download DP command, the current status should be reported. */
            my_device.mcu_dp_update(DPID_VALUE, dp_value_value, 1);
        break;

        case DPID_ENUM:
            DebugSerial.println("Enum type:");
            dp_enum_value = my_device.mcu_get_dp_download_data(dpid, value, length);
            DebugSerial.println(dp_enum_value);
            /* After processing the download DP command, the current status should be reported. */
            my_device.mcu_dp_update(DPID_ENUM, dp_enum_value, 1);
        break;

        case DPID_STRING:
            DebugSerial.println("String type:");
            /*  */
            for (unsigned int i=0; i<length; i++) {
                dp_string_value[i] = value[i];
                DebugSerial.write(dp_string_value[i]);
            }
            DebugSerial.println("");
            /* After processing the download DP command, the current status should be reported. */
            my_device.mcu_dp_update(DPID_STRING, dp_string_value, length);
        break;

        case DPID_RAW:
            DebugSerial.println("Raw type:");
            /*  */
            for (unsigned int i=0; i<length; i++) {
                dp_raw_value[i] = value[i];
                DebugSerial.write(dp_raw_value[i]);
            }
            DebugSerial.println("");
            /* After processing the download DP command, the current status should be reported. */
            my_device.mcu_dp_update(DPID_RAW, dp_raw_value, length);
        break;

        default:
            break;
    }
    
    return SUCCESS;
}

/**
 * @description: Upload all DP status of the current device.
 * @param {*}
 * @return {*}
 */
void dp_update_all(void)
{
    my_device.mcu_dp_update(DPID_BOOL, dp_bool_value, 1);
    my_device.mcu_dp_update(DPID_VALUE, dp_value_value, 1);
    my_device.mcu_dp_update(DPID_ENUM, dp_enum_value, 1);
    my_device.mcu_dp_update(DPID_STRING, dp_string_value, (sizeof(dp_string_value) / sizeof(dp_string_value[0])));
    my_device.mcu_dp_update(DPID_RAW, dp_raw_value, (sizeof(dp_raw_value) / sizeof(dp_raw_value[0])));
    my_device.mcu_dp_update(DPID_FAULT, dp_fault_value, 1); /* Fault type Only report */
}

  • 3
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

单片机菜鸟哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值