智能家居 的话,如果只能手动控制会觉得不太 智能 ,如果能用说的或者自动的话体验可能会更好一些。
智能家居其实就是为了给生活添加一些便利,懒人推送 科技 发展是没错的。
对于个人而言接入智能家居无非有以下几个原因:
1、动动手动动嘴不动腿就是懒恨不能意念控制
2、开关对小朋友不友好,个头不够摸不到开关
3、全屋联动回家模式离家模式等等
基于以上几个原因
通过尝试。实现了语音控制 HA 设备的基本功能。
主要思路如图:
开始想着增加 机械 开关手动去操作,后来想了以下都语音控制了还要物理开关干嘛呢。
小朋友和老人,直接语音控制开关设备。就很舒服呢。
对于 红外 设备,还没研究透彻怎么去获取遥控器的红外编码,然后发射出来。这样就可以实现更多的功能。
可以语音控制空调、电视等红外设备。
[智能家居]MQTT 控制 HomeAssistant 设备
(出处: 物联网 开发者 社区-安信可 论坛 )
这里主要还是用到了 HomeAssistant 的自动化功能,这种设置不需要对 HomeAssistant 有很深的了解,简单配置即可。
对于小白用户体验更好一些,上手就用。对于大佬的话,可以延伸出更多的功能。
下面介绍一下主要功能模块
一、离线语音模组系列
VC-02 模组
扬声器功率尽量不要太大,如果用 M61-32S 供电 扬声器功率过高会导致掉电。
扬声器:
官方 资料
VC-02 模组 规格 书:
中文:
EN:
VC-02 原理图:
VC-02 封装:
串口烧录工具
定制语音
安信可语音开放平台:
在安信可语音开放平台创建产品,选择 VC 系列模组。
然后修改唤醒词
设置n 引脚功能
波特率设置 115200,引脚 B6 设置为 UART1_RX 引脚 B7 设置为 UART1_TX,用来发送接收数据。注意不要配置多个 UART1,否则不生效。
添加语音指令
然后添加控制详情
这里主要用到的就是串口数据,这里发送指令 第一位是指令开头默认 A1,第二位定义的是设备位置,第三位定义的是设备类型,第四位定义的是开关状态,第五位结束位默认 FF。根据自己的需要设置解析即可。
还有免唤醒命令,不用唤醒词直接就可以用,比如开灯、关灯等等。
免唤醒命令词最多 10 个选择自己需要的添加,添多了也是默认取前 10 条。
二、Ai-M61-32S模组
M61-32S 模组
官方资料
Ai-M61-32S-Kit 开发板规格书:
中文:
EN:
Ai-M61-32S 开发板原理图:
Ai-M61-32S 模组规格书:
中文 :
EN:
Ai-M61-32S 推荐 封装:点击 下载
Ai-M61 系列出厂固件
固件下载工具:点击下载
固件烧录指南:M61/M62 系列烧录指导(包含模组&开发板)
三、代码部分
主要用 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 easyflashbflb_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);exrn 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 target="_blank">et(uart_txbuf, 0, 4);while (1) {for (size_t i = 0; i < 5; i++){if (buff[i]==g_uart_buf[j].data[i])>MQTT 与 WIFI#include ".h"#include "task.h"#include "time.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 "pa_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 fai!");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_S_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());sprin(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_scribe("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;}//先断开WiFiif (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:wifi_sta_ip4_addr_get(&ipv4_addr, NULL, NULL, NULL);LOG_I("wifi connened %s,IP:%s", ssid, inet_ntoa(ipv4_addr));sprintf(queue_buff, "{"ip":{"IP":"%s"}}", inet_ntoa(ipv4_addr));flash_erase_set(SSID_KEY, ssid);flash_erase_set(PASS_KEY, passwd);LOG_I("Wating wifi connet OK and get ip OK");vPortFree(queue_buff);return 0;default://等待连接成功break;}}vPortFree(queue_buff);return 14; //连接超时}
#include <stdio.h>#include <string.h>#include <stdlib.h>#include "FreeRTOS.h"#include "log.h"#include <mqtt.h>#include "user_mqtt.h"#include "ha_task.h"#include <lwip/inet.h>#include "bflb_uart.h"#include <sys/socket.h>#include <sys/types.h>#include <lwip/errno.h>#include <netdb.h>#include "bflb_uart.h"#include "voice_uart.h"#include "utils_getopt.h"#include "config.h"#define DBG_TAG "MQTT"// #define USER_MQTTint test_sockfd;struct mqtt_client client;static mqtt_event_t event;uint8_t sendbuf[2048]; /* sendbuf should be large enough to hold multiple whole mqtt messages */uint8_t recvbuf[1024]; /* recvbuf should be large enough any whole mqtt message expected to be received */static TaskHandle_t client_daemon;static int open_socket(const char* host, const char* port);static int open_socket(const char* host, const char* port){struct addrinfo hints = { 0 };hints.ai_family = AF_UNSPEC; /* IPv4 or IPv6 */hints.ai_socktype = SOCK_STREAM; /* Must be TCP */int sockfd = -1;int rv;struct addrinfo* p, * servinfo;/* get address information */LOG_I("host:%s, port=%s", host, port);rv = getaddrinfo(host, port, &hints, &servinfo);if (rv != 0) {LOG_E("Failed to open socket (getaddrinfo): %d", rv);return -1;}/* open the first possible socket */for (p = servinfo; p != NULL; p = p->ai_next) {sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);if (sockfd == -1) continue;/* connect to server */rv = connect(sockfd, p->ai_addr, p->ai_addrlen);if (rv == -1) {close(sockfd);sockfd = -1;continue;}break;}/* free servinfo */freeaddrinfo(servinfo);/* make non-blocking */if (sockfd != -1) {int iMode = 1;ioctlsocket(sockfd, FIONBIO, &iMode);}return sockfd;}/*** @brief* @param sig*/static void test_close(void){if (test_sockfd){close(test_sockfd);}vTaskDelete(client_daemon);}/*** @brief* @param unused* @param published*/static void publish_callback_1(void** unused, struct mqtt_response_publish* published){/* not used in this example */char* topic_name = (char*)malloc(published->topic_name_size + 1);memcpy(topic_name, published->topic_name, published->topic_name_size);topic_name[published->topic_name_size] = '';char* topic_msg = (char*)malloc(published->application_message_size + 1);memcpy(topic_msg, published->application_message, published->application_message_size);topic_msg[published->application_message_size] = '';printf("%s:[%s]rn", topic_name, topic_msg);char* queue_buff = pvPortMalloc(512);memset(queue_buff, 0, 512);sprintf(queue_buff, "{"mqtt_msg":{"topic":"%s","data":%.*s}}", topic_name, published->application_message_size, topic_msg);vPortFree(queue_buff);free(topic_name);free(topic_msg);}/*** @brief _inspector_callback* @param client_arg* @return enum MQTTErrors*/enum MQTTErrors _inspector_callback(struct mqtt_client* client_arg){if (client_arg->mq.queue_tail->state!=MQTT_QUEUED_UNSENT) return MQTT_OK; //识别消息状态是否有更新,没有更新就返回event = client_arg->mq.queue_tail->control_type;static struct bflb_device_s* uartx;uartx = bflb_device_get_by_name("uart1");switch (event) {case MQTT_EVENT_CONNECT:{LOG_I("MQTT_EVENT_CONNECT");}break;case MQTT_EVENT_CONNACK:{LOG_I("MQTT_EVENT_CONNACK");}break;case MQTT_EVENT_PUBLISH:{LOG_I("MQTT_EVENT_PUBLISH");}break;case MQTT_EVENT_PUBACK:{LOG_I("MQTT_EVENT_PUBACK");}break;case MQTT_EVENT_PUBREC:{LOG_I("MQTT_EVENT_PUBREC");}break;case MQTT_EVENT_PUBREL:{LOG_I("MQTT_EVENT_PUBREL");}break;case MQTT_EVENT_PUBCOMP:{LOG_I("MQTT_EVENT_PUBCOMP");}break;case MQTT_EVENT_SUBSCRIBE:{LOG_I("MQTT_EVENT_SUBSCRIBE");}break;case MQTT_EVENT_SUBACK:{LOG_I("MQTT_EVENT_SUBACK");}break;case MQTT_EVENT_UNSUBSCRIBE:{LOG_I("MQTT_EVENT_UNSUBSCRIBE");}break;case MQTT_EVENT_UNSUBACK:{LOG_I("MQTT_EVENT_UNSUBACK");}break;case MQTT_EVENT_PINGREQ:{LOG_I("MQTT_EVENT_PINGREQ");}break;case MQTT_EVENT_PINGRESP:{LOG_I("MQTT_EVENT_PINGRESP");}break;case MQTT_EVENT_DISCONNECT:{LOG_I("MQTT_EVENT_DISCONNECT");}break;default:break;}return MQTT_OK;}/*** @brief* @param host* @param port*/void mqtt_client_init(const char* host, int port){LOG_I("MQTT init start");test_sockfd = open_socket(host, "1883");if (test_sockfd < 0) {LOG_E("Failed to open socket: %d", test_sockfd);test_close();return;}LOG_I(" test_sockfd crater OK id=%d", test_sockfd);mqtt_init(&client, test_sockfd, sendbuf, sizeof(sendbuf), recvbuf, sizeof(recvbuf), publish_callback_1);}/*** @brief* @param client*/static void client_refresher(void* arg){struct mqtt_client* client = (struct mqtt_client*)arg;while (1){mqtt_sync(client);vTaskDelay(200/portTICK_PERIOD_MS);}}/*** @brief mqtt_start_connect* MQTT启动连接* @param host* @param port* @param user_name* @param pass* @return int*/int mqtt_start_connect(char* host, uint16_t port, char* user_name, char* pass){int ret = 0;/* Ensure we have a clean session */uint8_t connect_flags = MQTT_CONNECT_CLEAN_SESSION;/* Send connection request to the broker. */ret = mqtt_connect(&client, MQTT_CLIENT_ID, NULL, NULL, 0, user_name, pass, connect_flags, 400);if (ret != MQTT_OK){LOG_E("MQTT init fail");}/* check that we don't have any errors */if (client.error != MQTT_OK) {LOG_E("error: %s", mqtt_error_str(client.error));test_close();}xTaskCreate(client_refresher, (char*)"client_ref", 1024, &client, 10, &client_daemon);return 0;}void mqtt_app_diconnect(void){test_close();}/*** @brief mqtt_app_publish* @param topic* @param payload* @param qos* @return int*/int mqtt_app_publish(const char* topic, const char* payload, int qos){static enum MQTTPublishFlags qos_flags;if (qos==0)qos_flags = MQTT_PUBLISH_QOS_0;else if (qos==1)qos_flags = MQTT_PUBLISH_QOS_1;else qos_flags = MQTT_PUBLISH_QOS_2;mqtt_publish(&client, topic, payload, strlen(payload), qos_flags);if (client.error != MQTT_OK) {LOG_E("error: %s", mqtt_error_str(client.error));test_close();return -1;}return 0;}/*** @brief mqtt_app_subscribe* @param topic* @param qos* @return int*/int mqtt_app_subscribe(char* topic, int qos){mqtt_subscribe(&client, topic, 0);return 0;}void mqtt_client_register_event(void){client.inspector_callback = _inspector_callback;}
配置文件
#define SSID_KEY "SSID"#define PASS_KEY "PASS"#define USER_SSID "******"#define USER_PASSWORD "******"#define MQTT_HOST "192.168.5*.*"#define MQTT_PORT 1883#define MQTT_USERNAME "******"#define MQTT_PASSWORD "******"#define MQTT_TOPIC "/HA/Ai/topic"#define MQTT_MSG_OPEN_L "{status:true}"#define MQTT_MSG_CLOSE_L "{status:false}"
如果感兴趣的话可以看下
[智能家居]小安派 DSL 通过 MQTT 控制 Home Assistant 灯
【完全开源】智能桌面助手——AiPi-DSL_Dashboard
自动化方案低配置,低代码。操作简单。
现在手里只有 M61 开发板,不知道有没有小一些功耗低一些的模组。希望一块小电池能坚持一个月那种。