【电子DIY作品】+ M61+VC02语音控制HA设备v1.1版

[复制链接]
查看195 | 回复12 | 2024-7-31 00:50:12 | 显示全部楼层 |阅读模式

为什么会有v1.1版本呢

因为原来的方式不直观,在HomeAssistant上面通过 MQTT 消息直接开关设备,没有一个状态可展示。

为了更加直观的去观察设备的开关,所以做了一个将M61+VC02语音控制组合调整了一下,使用直接使用莫工的HomeAssistant-C做控制的版本。添加开关实体,使用语音和HA都可以来控制开关打开或关闭状态体验更好些,状态展示也更加直观。

以下是v1.0版本

【电子DIY作品】+ M61+VC02语音控制HA设备

整理了一下莫工关于HomeAssistant-C的相关教程:

可以订阅 HomeAssistant

距离上一版本发布已经有一段时间了,后来更新了一版工作也比较忙一只也没整理出来。

正好今天有时间,整理一下顺道看看参加第三期活动呢😄

第二期的结果和预想的有些出入,不过不影响发帖。


文章开头先说下主要遇到的一些问题

一、相关问题

1、关于运行直接报错问题

set(CONFIG_BFLOG 0)

大部分demo CONFIG_BFLOG默认值都是1,但是不知为何这个值为1程序烧录没问题,运行就报错。只要将CONFIG_BFLOG直接设置为0就可以继续跑。

2、使用uart的时候bflb_uart_txint_mask(uart1, false);

这个设置以后程序就会卡住,目前不清楚为什么。

struct bflb_device_s* gpio = bflb_device_get_by_name("gpio");
uart1 = bflb_device_get_by_name("uart1");
struct bflb_uart_config_s cfg = {
    .baudrate = 115200,
    .data_bits = UART_DATA_BITS_8,
    .stop_bits = UART_STOP_BITS_1,
    .parity = UART_PARITY_NONE,
    .flow_ctrl = 0,
    .tx_fifo_threshold = 5,
    .rx_fifo_threshold = 5,
};
bflb_gpio_uart_init(gpio, GPIO_PIN_25, GPIO_UART_FUNC_UART1_TX);
bflb_gpio_uart_init(gpio, GPIO_PIN_26, GPIO_UART_FUNC_UART1_RX);
bflb_uart_init(uart1, &cfg);
//bflb_uart_txint_mask(uart1, false); 这个设置以后程序就会卡住,目前不清楚为什么。
bflb_uart_rxint_mask(uart1, false);
bflb_irq_attach(uart1->irq_num, uart_isr, NULL);
bflb_irq_enable(uart1->irq_num);

3、关于 easyflash

配置位置 proj.conf

set(CONFIG_EASYFLASH4 1)

代码中添加

#include "easyflash.h"

……
easyflash_init();

然后启动 wifi,基本上用不了多久程序就崩溃了。

只是初始化 easyflash,为什么会影响 wifi 运行呢?也没有做存储只是初始化?

4、改变MQTT设备状态需要创建新的任务

不然HA设备状态改变后程序就G了。

5、供电问题

M61-32S 为 VC02供电,VC02接了功率比较大的喇叭,使用电脑供电电流可能不足导致状态不正常。

解决方案

1、换低功率喇叭扬声器功率尽量不要太大,如果用 M61-32S 供电扬声器功率过高会导致掉电。

扬声器:

SPK-8Ω2W SPK+8Ω2W

2、使用充电器给M61-32S供电。

6、如果使用HomeAssistant-C需要配置HA的MQTT

MQTTCONFIG.png

以上干扰项都去掉以后程序运行正常。

二、设备图片

麦克风

MIC.jpg

VC02接线

VC02.jpg

M61-32S接线

接线图.jpg

完整图

完整.jpg

喇叭用的4欧5瓦的,用电脑供电的话,播报声音就掉电重启。

三、源代码

目前程序主要逻辑代码都在main.c文件中

main.c

/**
 * @file main.c
 * @author your name ([email]you@domain.com[/email])
 * @brief
 * @version 0.1
 * @date 2024-01-23
 *
 * @copyright Copyright (c) 2024
 *
*/
#include <FreeRTOS.h>
#include "task.h"
#include "queue.h"
#include "board.h"
#include "bluetooth.h"
#include "btble_lib_api.h"
#include "bl616_glb.h"
#include "rfparam_adapter.h"
#include "bflb_mtd.h"
// #include "easyflash.h"
#include "wifi_event.h"
#include "log.h"
#include "aiio_os_port.h"
#include "homeAssistantMQTT.h"
#include "voice_uart.h"
#include "bflb_uart.h"

#define DBG_TAG "MAIN"

struct bflb_device_s* uart1;
uart_rx_cmd_t uart_cmd;
static char uart_buff[5] = { 0 };

static const uart_data_t g_uart_buf[] = {
  {{0xA1, 0x00, 0x00, 0x00, 0xFF}, 5}, //wakeup_uni
  {{0xA1, 0x00, 0x01, 0x01, 0xFF}, 5}, //openL
  {{0xA1, 0x00, 0x01, 0x00, 0xFF}, 5}, //closeL
};

static bool switch_state;

void send_device_state_task(void){

    while (1)
    {
        ha_sw_entity_t* switch_cur = homeAssistant_fine_entity(CONFIG_HA_ENTITY_SWITCH, "switch1");
        if(switch_cur!=NULL && switch_cur->switch_state!=switch_state){
            switch_cur->switch_state = switch_state;
            int ret = homeAssistant_device_send_entity_state(CONFIG_HA_ENTITY_SWITCH, switch_cur, switch_cur->switch_state);
            if (ret!=-1)LOG_I("%s send entity suceess,state=%s", switch_cur->name, switch_cur->switch_state?"true\n":"flase\n");
        }
        vTaskDelay(pdMS_TO_TICKS(10));
    }

}

void ha_event_cb(ha_event_t event, homeAssisatnt_device_t* ha_dev)
{      
    LOG_I("ha_event_cb");
    switch (event)
    {
        case HA_EVENT_MQTT_CONNECED:
            LOG_I("<<<<<<<<<<  HA_EVENT_MQTT_CONNECED");

            //一定要加static
            static ha_sw_entity_t entity_sw1 = {
                    .name = "开关1",
                    .icon = "mdi:power",
                    .unique_id = "switch1",
            };

            homeAssistant_device_add_entity(CONFIG_HA_ENTITY_SWITCH, &entity_sw1);
            homeAssistant_device_send_status(HOMEASSISTANT_STATUS_ONLINE);
            homeAssistant_device_send_entity_state(CONFIG_HA_ENTITY_SWITCH, &entity_sw1, 0);

            xTaskCreate(send_device_state_task, (char *)"send_state", 1024, NULL, 26, NULL);
            break;
        case HA_EVENT_MQTT_DISCONNECT:
            LOG_I("<<<<<<<<<<  HA_EVENT_MQTT_DISCONNECT");

            break;
        case HA_EVENT_MQTT_COMMAND_SWITCH:
            LOG_I("<<<<<<<<<<  HA_EVENT_MQTT_COMMAND_SWITCH");
            // LOG_I("switch addr =%p", ha_dev->entity_switch->command_switch);
            LOG_I(" switch %s is %s", ha_dev->entity_switch->command_switch->name, ha_dev->entity_switch->command_switch->switch_state?"true":"flase");
            int ret = homeAssistant_device_send_entity_state(CONFIG_HA_ENTITY_SWITCH, ha_dev->entity_switch->command_switch, ha_dev->entity_switch->command_switch->switch_state);
            if (ret!=-1)LOG_I("%s send entity suceess,state=%s", ha_dev->entity_switch->command_switch->name, ha_dev->entity_switch->command_switch->switch_state?"true":"flase");
            break;
        default:
            break;
    }
}

static int voice_cmd_check(char* buff, int len)
{

    int data_cnt = 0, j = 0;
    // char* uart_txbuf = pvPortMalloc(4);
    // memset(uart_txbuf, 0, 4);
    while (1) {
        for (size_t i = 0; i < 5; i++)
        {
            if (buff[i]==g_uart_buf[j].data[i]) data_cnt++;
            else break;
        }
        if (data_cnt==g_uart_buf->len) break;
        data_cnt = 0;
        j++;
        if (j>23) return -1;
    }
    LOG_I("check uart cmd=%d", j);
    return j;
}

static void uart_isr(int irq, void* arg)
{ 
    LOG_I("uart_isr");
    uint32_t intstatus = bflb_uart_get_intstatus(uart1);
    if (intstatus & UART_INTSTS_RTO) {
        LOG_I("rx rto\r\n");
        memset(uart_buff, 0, 5);
        int index = 0;
        while (bflb_uart_rxavailable(uart1)) {
            // LOG_I("0x%02x\r\n", bflb_uart_getchar(uart1));
            uart_buff[index++] =  bflb_uart_getchar(uart1);
        }
         LOG_I("uart recv:%02X %02X %02X %02X %02X", uart_buff[0], uart_buff[1], uart_buff[2], uart_buff[3], uart_buff[4]);

        uart_cmd = voice_cmd_check(uart_buff, 5);

        switch (uart_cmd)
        {
            case UART_RX_CMD_OPENL:
            {
                LOG_I("Open");
                switch_state = true;
            }
            break;
            case UART_RX_CMD_CLOSEL:
            {
                LOG_I("Close");
                switch_state = false;
            }
            break;
            default:
                break;
        }
        uart_cmd = UART_RX_CMD_NONE;
        bflb_uart_int_clear(uart1, UART_INTCLR_RTO);
        LOG_I("Voice cmd: bflb_uart_int_clear\n");
    }
}

int main(void)
{

    board_init();
    bflb_mtd_init();
    // easyflash_init();
    // aiio_log_init();

    if (0 != rfparam_init(0, NULL, 0)) {
        LOG_E("PHY RF init failed!\r\n");
        return 0;
    }

    struct bflb_device_s* gpio = bflb_device_get_by_name("gpio");
    uart1 = bflb_device_get_by_name("uart1");
    struct bflb_uart_config_s cfg = {
        .baudrate = 115200,
        .data_bits = UART_DATA_BITS_8,
        .stop_bits = UART_STOP_BITS_1,
        .parity = UART_PARITY_NONE,
        .flow_ctrl = 0,
        .tx_fifo_threshold = 5,
        .rx_fifo_threshold = 5,
    };
    bflb_gpio_uart_init(gpio, GPIO_PIN_25, GPIO_UART_FUNC_UART1_TX);
    bflb_gpio_uart_init(gpio, GPIO_PIN_26, GPIO_UART_FUNC_UART1_RX);

    bflb_uart_init(uart1, &cfg);
    bflb_uart_rxint_mask(uart1, false);
    bflb_irq_attach(uart1->irq_num, uart_isr, NULL);
    bflb_irq_enable(uart1->irq_num);

    staWiFiInit();
    // homeassistant_blufi_init();

    static homeAssisatnt_device_t ha_device = {
        .mqtt_info.mqtt_host = "192.168.50.40",
        .mqtt_info.port = 1883,
        .mqtt_info.mqtt_username = "admin",
        .mqtt_info.mqtt_password = "",
        .name = "Ai-M6X-Voice",
        .model = "Ai-M6x-12F",
        .manufacturer = "Ai-Thinker",
        .hw_version = "v1.0",
        .sw_version = "v1.0.0",
    };
    homeAssistant_device_init(&ha_device, ha_event_cb);

    vTaskStartScheduler();

    while (1) {
        LOG_F("HomeAssistant free heap size=%d", aiio_os_get_free_heap_size());
        vTaskDelay(pdMS_TO_TICKS(3000));
    }
}

配置文件

# Components
set(CONFIG_BFLOG 0)
set(CONFIG_LOG_LEVEL 5)
set(CONFIG_FREERTOS 1)
set(CONFIG_POSIX 1)
set(CONFIG_TLSF 1)
set(CONFIG_SHELL 1)
set(CONFIG_LWIP 1)
set(CONFIG_WIFI6 1)
set(CONFIG_RF 1)
set(CONFIG_MBEDTLS 1)
set(CONFIG_PSRAM 0)
set(CONFIG_DHCPD 1)
set(CONFIG_MDNS 1)
set(CONFIG_PING 1)

# set(CONFIG_MQTT 1)

set(CONFIG_PARTITION 1)
set(CONFIG_BFLB_MTD 1)
# set(CONFIG_EASYFLASH4 1)
# set(CONFIG_CJSON 1)

# Config
## mbedtls
set(CONFIG_VSNPRINTF_FLOAT      1)
set(CONFIG_VSNPRINTF_FLOAT_EX   1)
set(CONFIG_VSNPRINTF_LONG_LONG  1)

# mbedtls
set(CONFIG_MBEDTLS_AES_USE_HW 1)
set(CONFIG_MBEDTLS_BIGNUM_USE_HW 1)
set(CONFIG_MBEDTLS_ECC_USE_HW 1)
set(CONFIG_MBEDTLS_SHA1_USE_HW 1)
set(CONFIG_MBEDTLS_SHA256_USE_HW 1)
set(CONFIG_MBEDTLS_SHA512_USE_HW 1)

# wifi
set(CONFIG_VIF_MAX 2)
set(CONFIG_STA_MAX 4)
set(CONFIG_MAC_TXQ_DEPTH 16)
set(CONFIG_MAC_RXQ_DEPTH 12)

# ble
set(CONFIG_BLUETOOTH 1)
set(CONFIG_BTBLECONTROLLER_LIB ble1m0s1bredr0)
set(CONFIG_RF 1)
set(CONFIG_BLE_USE_MAC2 0)
set(CONFIG_BLE_TP_SERVER 1)
set(CONFIG_BTBLECONTROLLER_LIB ble1m10s1bredr0)

set(CONFIG_COREDUMP 0)

CmakeLists.txt

cmake_minimum_required(VERSION 3.15)

include(proj.conf)

find_package(bouffalo_sdk REQUIRED HINTS $ENV{BL_SDK_BASE})

file(GLOB_RECURSE sources ${CMAKE_CURRENT_SOURCE_DIR}/components/*.c)

aux_source_directory(../../../aiTinkerCloud_SDK/driver SRC_FILES)
aux_source_directory(.../../../aiTinkerCloud_SDK/protocol SRC_FILES)
aux_source_directory(../../../aiTinkerCloud_SDK/system SRC_FILES)
aux_source_directory(../../../aiTinkerCloud_SDK/utils SRC_FILES)

# aux_source_directory(./../../aiTinkerCloud_SDK/application SRC_FILES)
aux_source_directory(../../../aiTinkerCloud_SDK/3rdparty/http-parser/src SRC_FILES)
aux_source_directory(../../../aiTinkerCloud_SDK/3rdparty/aiio/tcp_transport SRC_FILES)
aux_source_directory(../../../aiTinkerCloud_SDK/3rdparty/aiio/tcp_transport SRC_FILES)
aux_source_directory(../../../aiTinkerCloud_SDK/3rdparty/aiio/aiio_tls SRC_FILES)
aux_source_directory(../../../aiTinkerCloud_SDK/3rdparty/aiio/aiio_tls/aiio-tls-crypto SRC_FILES)
aux_source_directory(../../../aiTinkerCloud_SDK/3rdparty/aiio/mqtt/aiio_mqtt SRC_FILES)
aux_source_directory(../../../aiTinkerCloud_SDK/3rdparty/aiio/mqtt/aiio_mqtt/lib SRC_FILES)
aux_source_directory(../../../aiTinkerCloud_SDK/3rdparty/blufi SRC_FILES)

# 添加头文件的引用路径(Add .h include directories)
sdk_add_include_directories(../../../aiTinkerCloud_SDK/driver)
sdk_add_include_directories(../../../aiTinkerCloud_SDK/protocol)
sdk_add_include_directories(../../../aiTinkerCloud_SDK/system)
sdk_add_include_directories(../../../aiTinkerCloud_SDK/utils)

# sdk_add_include_directories(../../aiTinkerCloud_SDK/application)
sdk_add_include_directories(../../../aiTinkerCloud_SDK/3rdparty/http-parser/include)
sdk_add_include_directories(../../../aiTinkerCloud_SDK/3rdparty/aiio/tcp_transport/include)
sdk_add_include_directories(../../../aiTinkerCloud_SDK/3rdparty/aiio/tcp_transport/private_include)
sdk_add_include_directories(../../../aiTinkerCloud_SDK/3rdparty/aiio/aiio_tls)
sdk_add_include_directories(../../../aiTinkerCloud_SDK/3rdparty/aiio/aiio_tls/aiio-tls-crypto)
sdk_add_include_directories(../../../aiTinkerCloud_SDK/3rdparty/aiio)

# sdk_add_include_directories(../../../aiTinkerCloud_SDK/3rdparty/aiio/aiio_http_client/include)
# sdk_add_include_directories(../../../aiTinkerCloud_SDK/3rdparty/aiio/aiio_http_client/lib/include)
# sdk_add_include_directories(../../../aiTinkerCloud_SDK/3rdparty/aiio/aiio_http_server/include)
# sdk_add_include_directories(../../../aiTinkerCloud_SDK/3rdparty/aiio/aiio_http_server/src/port)
sdk_add_include_directories(./../../../aiTinkerCloud_SDK/3rdparty/aiio/mqtt/aiio_mqtt/lib/include)
sdk_add_include_directories(./../../../aiTinkerCloud_SDK/3rdparty/aiio/mqtt/aiio_mqtt/include)
sdk_add_include_directories(./../../../aiTinkerCloud_SDK/3rdparty/blufi)

sdk_add_include_directories(.)
sdk_add_include_directories(main systemConfig)
# 这里
sdk_add_include_directories(components/wifi components/voice components/bluficonfig )

# 添加HomeAssistant 库
file(GLOB_RECURSE HA ${CMAKE_CURRENT_SOURCE_DIR}/../Ai-M6x_HomeAssistant-C/HomeAssistant-C/*.c)
sdk_add_include_directories(..//Ai-M6x_HomeAssistant-C/HomeAssistant-C)

list(REMOVE_ITEM SRC_FILES "./main/main.c")

target_sources(app PRIVATE ${SRC_FILES} ${sources} ${HA})

sdk_set_main_file(main/main.c)

get_filename_component(PROJECT_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME)
project(${PROJECT_NAME})

主要是49行添加components/voice

sdk_add_include_directories(components/wifi components/voice components/bluficonfig )

四、效果展示

其他功能保持基础配置就可以

仪表状态,开灯的时候,Ai-M6X-Voice开关先亮起,然后触发客厅灯亮起。

关灯的时候Ai-M6X-Voice开关先关闭,然后触发客厅灯关闭。形成联动效果。

图标.png

MQTT实体详情

小安派开关.png

自动化配置开灯操作

自动化配置开启.png

自动化配置关灯操作

自动化配置关闭.png关于MQTT通过自动化控制HA设备可以参考

[智能家居]MQTT控制HomeAssistant设备 https://bbs.ai-thinker.com/forum.php?mod=viewthread&tid=44644&fromuid=15918

之所以使用自动化控制,是因为其他设备都不支持MQTT协议,使用自动化控制好像更方便一点。

这个就类似于随意贴的感觉。

视频就不拍了效果和下面这个差不多

【电子DIY作品】+ M61+VC02语音控制HA设备 https://bbs.ai-thinker.com/forum.php?mod=viewthread&tid=45021&fromuid=15918

五、后期设想

1、增加通讯Ai-M61-32S灯光展示

传输数据 亮蓝灯

正常运行 亮绿灯

2、增加继电器模块

3、增加模组化外壳

4、蓝牙/网页配网【还没研究】

其实主要功能就是语音控制设备,一种是直接通过继电器控制,一种是通过HA控制。

源码和固件在一楼。

回复

使用道具 举报

WT_0213 | 2024-7-31 00:57:35 | 显示全部楼层
源码奉上
home-assistant_vcha_bl616.bin.zip 把zip去掉就是M61-32S固件
uni_app_release_update.bin.zip把zip去掉就是VC02固件

home-assistant_vcha.zip

21.23 KB, 下载次数: 1

home-assistant_vcha_bl616.bin.zip

942 KB, 下载次数: 1

uni_app_release_update.bin.zip

1.19 MB, 下载次数: 3

回复 支持 反对

使用道具 举报

WangChong | 2024-7-31 04:04:23 | 显示全部楼层
跟我想做的东西重复了 我很不爽!
回复 支持 反对

使用道具 举报

bzhou830 | 2024-7-31 08:05:03 | 显示全部楼层
厉害
选择去发光,而不是被照亮
回复

使用道具 举报

爱笑 | 2024-7-31 08:36:23 | 显示全部楼层
优秀啊!
用心做好保姆工作
回复

使用道具 举报

WT_0213 | 2024-7-31 09:06:20 | 显示全部楼层
WangChong 发表于 2024-7-31 04:04
跟我想做的东西重复了 我很不爽!

肯定王哥做个更好,我这个抛砖引玉喽
回复 支持 反对

使用道具 举报

djy876 | 2024-7-31 09:08:21 | 显示全部楼层
WT_0213 发表于 2024-7-31 00:57
源码奉上
home-assistant_vcha_bl616.bin.zip 把zip去掉就是M61-32S固件
uni_app_release_update.bin.zip ...

要刷三个固件?能不能不用M61开发版,直接用M61模块+PCB板+继电器+VC02模块用一个TC-Y口一次性刷入固件?
回复 支持 反对

使用道具 举报

WT_0213 | 2024-7-31 09:10:16 | 显示全部楼层
djy876 发表于 2024-7-31 09:08
要刷三个固件?能不能不用M61开发版,直接用M61模块+PCB板+继电器+VC02模块用一个TC-Y口一次性刷入固件? ...

源码直接编译烧录也行,固件就是这套源码编译出来的。
回复 支持 反对

使用道具 举报

WangChong | 2024-7-31 15:14:36 | 显示全部楼层
真牛啊
回复

使用道具 举报

bzhou830 | 2024-7-31 17:57:16 | 显示全部楼层
WangChong 发表于 2024-7-31 04:04
跟我想做的东西重复了 我很不爽!

做一个更好的出来
选择去发光,而不是被照亮
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则