为什么会有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
以上干扰项都去掉以后程序运行正常。
二、设备图片
麦克风
VC02接线
M61-32S接线
完整图
喇叭用的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开关先关闭,然后触发客厅灯关闭。形成联动效果。
MQTT实体详情
自动化配置开灯操作
自动化配置关灯操作
关于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控制。
源码和固件在一楼。