用安信可Wi-Fi6 & 蓝牙模组+VC-02语音控制HA设备

发布时间:2024-08-14  

智能家居的话,如果只能手动控制会觉得不太智能,如果能用说的或者自动的话体验可能会更好一些。


智能家居其实就是为了给生活添加一些便利,懒人推送科技发展是没错的。

对于个人而言接入智能家居无非有以下几个原因:

1、动动手动动嘴不动腿就是懒恨不能意念控制

2、开关对小朋友不友好,个头不够摸不到开关

3、全屋联动回家模式离家模式等等

基于以上几个原因

通过尝试。实现了语音控制 HA 设备的基本功能。

主要思路如图:

wKgaoma6-FmADONeAAC7s6NWiwE81.jpeg

开始想着增加机械开关手动去操作,后来想了以下都语音控制了还要物理开关干嘛呢。

小朋友和老人,直接语音控制开关设备。就很舒服呢。

对于红外设备,还没研究透彻怎么去获取遥控器的红外编码,然后发射出来。这样就可以实现更多的功能。

可以语音控制空调、电视等红外设备。

[智能家居]MQTT 控制 HomeAssistant 设备

https://bbs.ai-thinker.com/forum.php?mod=viewthread&tid=44644&fromuid=15918

(出处: 物联网开发者社区-安信可论坛)

这里主要还是用到了 HomeAssistant 的自动化功能,这种设置不需要对 HomeAssistant 有很深的了解,简单配置即可。

对于小白用户体验更好一些,上手就用。对于大佬的话,可以延伸出更多的功能。

下面介绍一下主要功能模块

一、离线语音模组系列

VC 系列模组是我司开发的一款 AI 离线语音识别的产品,主芯片是云知声推出的离线语音识别芯片锋鸟 M(US516P6),具有高可靠性,通用性强的特点。在语音识别技术上实现了高可靠的唤醒识别率、更远距离的唤醒、更低误唤醒率、更强的抗噪音能力、更快的响应识别时间,免联网的纯离线识别。

VC 系列模组采用了 32bit RISC 架构内核,并加入了专门针对信号处理和语音识别所需要的 DSP 指令集,支持浮点运算的 FPU 运算单元,以及 FFT 加速器。支持最高 150 条本地指令离线识别,支持 RTOS 轻量级系统,以及简单友好的客制化工具。

VC 系列模组具有丰富的外围接口,包括 UART/I2C/PWM/SPI,以及简单友好的二次开发工具,方便客户实现单模组的语音控制应用场景方案。

VC-02 模组

wKgZoma6-FmAWfbGAACE9TU9KNA51.jpeg

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

扬声器:

SPK-8Ω2W

SPK+8Ω2W

官方资料

VC-02 模组规格书:

中文: https://docs.ai-thinker.com/_media/vc-02_v1.0.0%E8%A7%84%E6%A0%BC%E4%B9%A6_516.pdf

EN:https://docs.ai-thinker.com/_media/vc-02_v1.0.0_specification_516.pdf

VC-02 原理图:https://docs.ai-thinker.com/_media/vc-02_v1.0_%E5%8E%9F%E7%90%86%E5%9B%BE-20220531.pdf

VC-02 封装: https://mp.weixin.qq.com/s?__biz=MzIzODA0NDgxNg==&mid=2650092833&idx=5&sn=b8dfe99e2b08c31a704256f79c351b47&chksm=f13ec6dec6494fc88d033ff313ab824fc41695f4a188a9e98b237bf563e0c6fc07a1c5f4fabd&token=2098411327&lang=zh_CN#rd

串口烧录工具

定制语音

安信可语音开放平台:http://voice.ai-thinker.com/

在安信可语音开放平台创建产品,选择 VC 系列模组。

wKgaoma6-FmAHpqXAACb-uX2Bfs83.jpeg

然后修改唤醒词

wKgZoma6-GSAOC5HAAAv-VgF0_049.jpeg

设置 Pin 引脚功能

wKgaoma6-GSAJkk0AABfxm2s1iQ45.jpeg

波特率设置 115200,引脚 B6 设置为 UART1_RX 引脚 B7 设置为 UART1_TX,用来发送接收数据。注意不要配置多个 UART1,否则不生效。

添加语音指令

wKgZoma6-G6AR1w2AACj3_s7Gwc76.jpeg

然后添加控制详情

wKgaoma6-G-APHmPAABlklqGUv422.jpeg

这里主要用到的就是串口数据,这里发送指令 第一位是指令开头默认 A1,第二位定义的是设备位置,第三位定义的是设备类型,第四位定义的是开关状态,第五位结束位默认 FF。根据自己的需要设置解析即可。

还有免唤醒命令,不用唤醒词直接就可以用,比如开灯、关灯等等。

wKgZoma6-G-AI7FwAABGIrsrfxA60.jpeg

免唤醒命令词最多 10 个选择自己需要的添加,添多了也是默认取前 10 条。

二、Ai-M61-32S Wi-Fi 模组

Ai-M61 系列模组(下称模组)是由深圳市安信可科技有限公司开发的 Wi-Fi6 & 蓝牙双模模组,搭载 BL618 芯片作为处理器,支持 Wi-Fi 802.11b/g/n/ax 协议和 BLE 5.3 协议。BL618 芯片内置低功耗的 32 位 RISC-V CPU,最高主频可达 320M. 丰富的外围接口,包括 DVP、MJPEG、Dispaly、Audio Codec、USB2.0、SDU、以太网(EMAC)、SD/MMC(SDH)、SPI、UART、I2C、I2S、PWM、GPDAC、GPADC、ACOMP 和 GPIO 等。可广泛应用于音视频多媒体、物联网(IoT)、移动设备、可穿戴电子设备、智能家居等领域。

M61-32S 模组

wKgaoma6-G-AD5uIAAFKHzGBJmQ17.jpeg

官方资料


Ai-M61-32S-Kit 开发板规格书:

中文:https://docs.ai-thinker.com/_media/ai-m61-32s-kit_v1.1.2_product_specification_cn.pdf

EN:https://docs.ai-thinker.com/_media/ai-m61-32s-kit_v1.1.2_product_specification_en.pdf


Ai-M61-32S 开发板原理图:https://docs.ai-thinker.com/_media/nodemcu-ai-m61-32s-kit_v1.1.pdf


Ai-M61-32S 模组规格书:

中文 :https://docs.ai-thinker.com/_media/ai-m61-32s_v1.3.0_product_specification_cn.pdf

EN:https://docs.ai-thinker.com/_media/ai-m61-32s_v1.3.0_product_specification_en.pdf

Ai-M61-32S 推荐封装:点击下载

Ai-M61 系列出厂固件

固件下载工具:点击下载

固件烧录指南:M61/M62 系列烧录指导(包含模组&开发板)https://blog.csdn.net/Boantong_/article/details/140183535?


三、代码部分


主要用 wifi、mqtt、uart、flash


uart 代码主要参考


【完全开源】智能桌面助手——AiPi-DSL_Dashboard


主程序代码


#include < stdio.h >

#include < stdlib.h >

#include < string.h >

#include < FreeRTOS.h >

#include < task.h >

#include < queue.h >

#include 'log.h'

#include 'board.h'

#include 'mem.h'

//easy flash

#include 'easyflash.h'

#include 'bflb_mtd.h'

#include 'bl_fw_api.h'

#include 'wifi_mgmr_ext.h'

#include 'wifi_mgmr.h'

#include 'ha_task.h'

#include 'wifi_event.h'

#include 'voice_uart.h'

int main(void)

{

board_init();

wifi_start_firmware_task();

//init easyflash

bflb_mtd_init();

easyflash_init();

xTaskCreate(voice_uart_task, 'uart task', 1024, NULL, 10, NULL);

xTaskCreate(queue_receive_task, 'queue_receive_task', 1024*3, NULL, 3, NULL);

vTaskStartScheduler();

}

VC02 模组交互代码


#include < stdio.h >

#include < string.h >

#include < stdlib.h >

#include < FreeRTOS.h >

#include < queue.h >

#include < timers.h >

#include < task.h >

#include 'ha_task.h'

#include 'bflb_uart.h'

#include 'bflb_gpio.h'

#include 'voice_uart.h'

#include 'user_mqtt.h'

#include 'log.h'

#define GBD_TAG 'UART'

static void uart_init(void);

extern xQueueHandle queue;

uart_rx_cmd_t uart_cmd;

static struct bflb_device_s* uart1;

static char uart_buff[5] = { 0 };

static const uart_data_t g_uart_buf[] = {

{{0xA1, 0x00, 0x01, 0x00, 0xFF}, 5}, //wakeup_uni

{{0xA1, 0x00, 0x01, 0x01, 0xFF}, 5}, //openL

{{0xA1, 0x00, 0x01, 0x00, 0xFF}, 5}, //closeL

};

void voice_uart_task(void* arg)

{

uart_init();

while (1) {

vTaskDelay(1000/portTICK_PERIOD_MS);

}

}

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)

{

uint32_t intstatus = bflb_uart_get_intstatus(uart1);

uint32_t rx_data_len = 0;

char data_type[1] = { 0 };

if (intstatus & UART_INTSTS_RX_FIFO) {

int index = 0;

memset(uart_buff, 0, 5);

LOG_I('rx fiforn');

while (bflb_uart_rxavailable(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]);

}

}

/**

* @brief

*/

static void uart_init(void)

{

struct bflb_device_s* gpio;

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 = 4,

.rx_fifo_threshold = 4,

};

gpio = bflb_device_get_by_name('gpio');

uart1 = bflb_device_get_by_name('uart1');

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);

}

MQTT 与 WIFI


wifi


#include 'FreeRTOS.h'

#include 'task.h'

#include 'timers.h'

#include < lwip/tcpip.h >

#include < lwip/sockets.h >

#include < lwip/netdb.h >

#include 'bl_fw_api.h'

#include 'wifi_mgmr_ext.h'

#include 'wifi_mgmr.h'

#include 'bflb_irq.h'

#include 'bflb_uart.h'

#include 'bflb_l1c.h'

#include 'bflb_mtimer.h'

#include 'bl616_glb.h'

#include 'rfparam_adapter.h'

#include 'board.h'

#include 'log.h'

#include 'ha_task.h'

#include 'config.h'

#define DBG_TAG 'WIFI EVENT'

#define WIFI_STACK_SIZE (1024*4)

#define TASK_PRIORITY_FW (16)

static wifi_conf_t conf =

{

.country_code = 'CN',

};

static TaskHandle_t wifi_fw_task;

static uint32_t sta_ConnectStatus = 0;

extern TaskHandle_t https_Handle;

/**

* @brief WiFi 任务

* @return int

*/

int wifi_start_firmware_task(void)

{

LOG_I('Starting wifi ...');

/* enable wifi clock */

GLB_PER_Clock_UnGate(GLB_AHB_CLOCK_IP_WIFI_PHY | GLB_AHB_CLOCK_IP_WIFI_MAC_PHY | GLB_AHB_CLOCK_IP_WIFI_PLATFORM);

GLB_AHB_MCU_Software_Reset(GLB_AHB_MCU_SW_WIFI);

/* set ble controller EM Size */

GLB_Set_EM_Sel(GLB_WRAM160KB_EM0KB);

if (0 != rfparam_init(0, NULL, 0)) {

LOG_I('PHY RF init failed!');

return 0;

}

LOG_I('PHY RF init success!');

/* Enable wifi irq */

extern void interrupt0_handler(void);

bflb_irq_attach(WIFI_IRQn, (irq_callback)interrupt0_handler, NULL);

bflb_irq_enable(WIFI_IRQn);

xTaskCreate(wifi_main, (char*)'fw', WIFI_STACK_SIZE, NULL, TASK_PRIORITY_FW, &wifi_fw_task);

return 0;

}

/**

* @brief wifi event handler

* WiFi 事件回调

* @param code

*/

void wifi_event_handler(uint32_t code)

{

sta_ConnectStatus = code;

switch (code) {

case CODE_WIFI_ON_INIT_DONE:

{

LOG_I('[APP] [EVT] %s, CODE_WIFI_ON_INIT_DONE', __func__);

wifi_mgmr_init(&conf);

}

break;

case CODE_WIFI_ON_MGMR_DONE:

{

LOG_I('[APP] [EVT] %s, CODE_WIFI_ON_MGMR_DONE', __func__);

}

break;

case CODE_WIFI_ON_SCAN_DONE:

{

char* scan_msg = pvPortMalloc(128);

wifi_mgmr_sta_scanlist();

LOG_I('[APP] [EVT] %s, CODE_WIFI_ON_SCAN_DONE SSID numbles:%d', __func__, wifi_mgmr_sta_scanlist_nums_get());

sprintf(scan_msg, '{'wifi_scan':{'status':0}}');

vPortFree(scan_msg);

}

break;

case CODE_WIFI_ON_CONNECTED:

{

LOG_I('[APP] [EVT] %s, CODE_WIFI_ON_CONNECTED', __func__);

void mm_sec_keydump();

mm_sec_keydump();

}

break;

case CODE_WIFI_ON_GOT_IP:

{

LOG_I('[APP] [EVT] %s, CODE_WIFI_ON_GOT_IP', __func__);

mqtt_client_init(MQTT_HOST, MQTT_PORT);

mqtt_client_register_event();

vTaskDelay(500/portTICK_PERIOD_MS);

mqtt_start_connect(MQTT_HOST, MQTT_PORT, MQTT_USERNAME, MQTT_PASSWORD);

mqtt_app_subscribe('sub', 0);

}

break;

case CODE_WIFI_ON_DISCONNECT:

{

LOG_I('[APP] [EVT] %s, CODE_WIFI_ON_DISCONNECT', __func__);

}

break;

case CODE_WIFI_ON_AP_STARTED:

{

LOG_I('[APP] [EVT] %s, CODE_WIFI_ON_AP_STARTED', __func__);

}

break;

case CODE_WIFI_ON_AP_STOPPED:

{

LOG_I('[APP] [EVT] %s, CODE_WIFI_ON_AP_STOPPED', __func__);

}

break;

case CODE_WIFI_ON_AP_STA_ADD:

{

LOG_I('[APP] [EVT] [AP] [ADD] %lld', xTaskGetTickCount());

}

break;

case CODE_WIFI_ON_AP_STA_DEL:

{

LOG_I('[APP] [EVT] [AP] [DEL] %lld', xTaskGetTickCount());

}

break;

default:

{

LOG_I('[APP] [EVT] Unknown code %u ', code);

}

}

}

uint8_t wifi_connect(char* ssid, char* passwd)

{

int ret = 255;

// struct fhost_vif_ip_addr_cfg ip_cfg = { 0 };

uint32_t ipv4_addr = 0;

char* queue_buff = pvPortMalloc(128);

memset(queue_buff, 0, 128);

if (NULL==ssid || 0==strlen(ssid)) {

return 1;

}

//先断开WiFi

if (wifi_mgmr_sta_state_get() == 1) {

wifi_sta_disconnect();

}

LOG_I('WiFi STA connect .....');

if (wifi_sta_connect(ssid, passwd, NULL, NULL, 0, 0, 0, 1)< 0) {

vPortFree(queue_buff);

return 4;

}

LOG_I('Wating wifi connet');

//等待连接成功

sta_ConnectStatus = 0;

for (int i = 0;i< 10*30;i++) {

vTaskDelay(100/portTICK_PERIOD_MS);

switch (sta_ConnectStatus) {

case CODE_WIFI_ON_MGMR_DONE:

// vTaskDelay(2000);

// LOG_I('wifi_mgmr_sta_scan:%d', wifi_mgmr_sta_scan(wifi_scan_config));

vPortFree(queue_buff);

return 3;

case CODE_WIFI_ON_SCAN_DONE:

// LOG_I('WIFI STA SCAN DONE %s', wifi_scan_config[0].ssid_array);

vPortFree(queue_buff);

return 2;

case CODE_WIFI_ON_DISCONNECT: //连接失败(超过了重连次数还没有连接成功的状态)

// wifi_sta_disconnect();

// vPortFree(queue_buff);

return 4;

case CODE_WIFI_ON_CONNECTED: //连接成功(表示wifi sta状态的时候表示同时获取IP(DHCP)成功,或者使用静态IP)

// LOG_I('Wating wifi connet OK');

break;

case CODE_WIFI_ON_GOT_IP:

文章来源于:电子工程世界    原文链接
本站所有转载文章系出于传递更多信息之目的,且明确注明来源,不希望被转载的媒体或个人可与我们联系,我们将立即进行删除处理。

我们与500+贴片厂合作,完美满足客户的定制需求。为品牌提供定制化的推广方案、专属产品特色页,多渠道推广,SEM/SEO精准营销以及与公众号的联合推广...详细>>

利用葫芦芯平台的卓越技术服务和新产品推广能力,原厂代理能轻松打入消费物联网(IOT)、信息与通信(ICT)、汽车及新能源汽车、工业自动化及工业物联网、装备及功率电子...详细>>

充分利用其强大的电子元器件采购流量,创新性地为这些物料提供了一个全新的窗口。我们的高效数字营销技术,不仅可以助你轻松识别与连接到需求方,更能够极大地提高“闲置物料”的处理能力,通过葫芦芯平台...详细>>

我们的目标很明确:构建一个全方位的半导体产业生态系统。成为一家全球领先的半导体互联网生态公司。目前,我们已成功打造了智能汽车、智能家居、大健康医疗、机器人和材料等五大生态领域。更为重要的是...详细>>

我们深知加工与定制类服务商的价值和重要性,因此,我们倾力为您提供最顶尖的营销资源。在我们的平台上,您可以直接接触到100万的研发工程师和采购工程师,以及10万的活跃客户群体...详细>>

凭借我们强大的专业流量和尖端的互联网数字营销技术,我们承诺为原厂提供免费的产品资料推广服务。无论是最新的资讯、技术动态还是创新产品,都可以通过我们的平台迅速传达给目标客户...详细>>

我们不止于将线索转化为潜在客户。葫芦芯平台致力于形成业务闭环,从引流、宣传到最终销售,全程跟进,确保每一个potential lead都得到妥善处理,从而大幅提高转化率。不仅如此...详细>>