# Ai-M6x_HomeAssistant-C **Repository Path**: Ai-Thinker-Open/Ai-M6x_HomeAssistant-C ## Basic Information - **Project Name**: Ai-M6x_HomeAssistant-C - **Description**: Ai-M6x模组HomeAssistant 平台 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 0 - **Created**: 2024-04-02 - **Last Updated**: 2024-07-27 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # HomeAssistant-C HomeAssistant-C 这是一个主要为安信可WiFi 模组开发的HomeAssistant 连接库,使用安信可模组时,只需要简单的修改就能接入HomeAssistant。目前已对Ai-M6x系列模组,Ai-WB2系列模组做了简单的适配,对应的SDK如下: **Ai-WB2 SDK:**[https://gitee.com/Ai-Thinker-Open/Ai-Thinker-WB2](https://gitee.com/Ai-Thinker-Open/Ai-Thinker-WB2) **Ai-M6x SDK:**[https://gitee.com/Ai-Thinker-Open/AiPi-Open-Kits](https://gitee.com/Ai-Thinker-Open/AiPi-Open-Kits) **master 分支已开发完成的实体:** |实体类型|实体名称|状态| | :-: | :-: | :-: | |switch|开关|✔| |sensor|传感器|✔| |binary sensor|二进制传感器|✔| |Light|灯|✔| |Text|文本|✔| |Number|数字|✔| ## 基本使用方法 ### 源码获取 推荐使用git进行克隆下载;当然如果不会git的,也可以使用ZIP压缩下载: ```shell git clone https://gitee.com/Ai-Thinker-Open/Ai-M6x_HomeAssistant-C.git ``` ### 移植方法 - Ai-WB2 SDK 移植方法请参考:[README_Ai-WB2.md](docs/README_Ai-WB2.md) - Ai-M6x SDK 移植方法请参考:[README_Ai-M6x.md](docs/README_Ai-M6x.md) ### 修改接口 把[HomeAssistant-C](./HomeAssistant-C/)库源码复制到你的工程当中。 >*我推荐使用已经可以连接WiFi功能的工程,比如(wifi/station),并且能够获取到IP地址* 开启 `homeAssistantPort.h` 当中相对应模组的宏定义,以启用它的MQTT接口,例如开启Ai-M62,而Ai-WB2 关闭: ``` #define CONFIG_Ai_M6x // #define CONFIG_Ai_WB2 ``` ***注意:如果开启的接口和目前正在使用的模组SDK不对应,会导致编译错误*** ### 初始化HomeAssistant 首先需要在使用HomeAssistant 的 C 文件中应用库的头文件: ``` #include "homeAssistantPort.h" ``` 在你工程代码初始化的地方初始化HomeAssistant,使用 **homeAssistant_device_init** 函数对HomeAssistant库进行初始化: ```c /** * @brief HomeAssistant 库初始化函数 * * @param ha_dev HomeAssistant 设备句柄 * @param event_cb HomeAssistant 事件回调函数 */ homeAssistant_device_init(homeAssisatnt_device_t* ha_dev, void(*event_cb)(ha_event_t, homeAssisatnt_device_t*)) ``` #### 用法示例(Ai-M6x): ``` /* HomeAssistant 事件回调 */ void ha_event_cb(ha_event_t event, homeAssisatnt_device_t* ha_dev) { switch (event) { /* 连接服务器事件 */ case HA_EVENT_MQTT_CONNECED: HA_LOG_I("<<<<<<<<<< HA_EVENT_MQTT_CONNECED\r\n"); break; /* 服务器断开事件 */ case HA_EVENT_MQTT_DISCONNECT: HA_LOG_I("<<<<<<<<<< HA_EVENT_MQTT_DISCONNECT\r\n"); default: break; } } int main(void) { board_init(); bflb_mtd_init(); easyflash_init(); if (0 != rfparam_init(0, NULL, 0)) { LOG_E("PHY RF init failed!\r\n"); return 0; } /* 初始化WiFi */ staWiFiInit(); /* 定义 device 变量 */ homeAssisatnt_device_t ha_device; /* 初始化 HomeAssistant */ homeAssistant_device_init(&ha_device, ha_event_cb); vTaskStartScheduler(); while (1) { vTaskDelay(pdMS_TO_TICKS(3000)); } } ``` ### 启动HomeAssistant 的连接 - **注意:HomeAssistant 启动的时候需要需要连接MQTT服务器,所以再次之前,先确保工程已经连接WiFi,并成功获取IP地址** 找到WiFi 获取IP地址事件处理的地方调用<**homeAssistant_device_start()**>函数启动HomeAssistant 的连接,例如Ai-M6x: ``` static void cb_wifi_event(aiio_input_event_t* event, void* data) { int32_t ret = 0; switch (event->code) { /* 上面为其他事件 */ /* STA 连接WiFi 并且获取到IP地址 */ case AIIO_WIFI_EVENT_STA_GOT_IP: { LOG_I("<<<<<<<<< CONNECTED GOT IP <<<<<<<<<<<"); /* 发起连接 */ homeAssistant_device_start(); } break; default: break; } } ``` >当成功连接MQTT 服务器之后,会触发HomeAssistant的**HA_EVENT_MQTT_CONNECED**事件,你可以在此事件下定义实体。需要注意的是,如果你没有重新定义MQTT的连接,**那么HomeAssitant 会根据默认的配置,连接到Ai-Thinker的MQTT服务器**,这样的话,你是不能从HomeAssistant 的MQTT集成当中查看到这段代码的连接,因此,需要在初始化的时候,重新定义HomeAssistant 设备的[MQTT连接信息](#set_mqtt_msg)。 ## 重定义设备信息 虽然可以通过修改宏定义的方式修改MQTT的默认连接信息,通过修改[homeAssistantDevConfig.h](HomeAssistant-C/homeAssistantDevConfig.h)相关定义的宏,但是我并不推荐这种方式,一旦使用 *git pull* 更新库之后,这些连接信息就被重置。 因此我推荐直接给**homeAssisatnt_device_t ha_device**设备变量进行初始定义。 #### 用法示例: ``` /* 定义 HomeAssistant 设备并对MQTT 进行赋值 */ homeAssisatnt_device_t ha_device = { .mqtt_info.mqtt_host = "your mqtt server host", //定义服务器地址,支持域名解析(必要) .mqtt_info.port = 1883, //定义端口号 (必要) .mqtt_info.mqtt_username = "myHomeAssistant", //定义 userName(可选) .mqtt_info.mqtt_password = "mypassword", //定义 密码 (可选) }; /* 为了防止同一份代码 MQTT Clienti 冲突 ,不建议使用固定的Client,采用Client=MAC地址进行区分*/ unsigned char mac[6]; //定义 STA MAC 地址变量 homeAssistant_get_sta_mac(mac);// 获取MAC 地址 ha_device.mqtt_info.mqtt_clientID = pvPortMalloc(12);//Client 申请空间 /* 赋值MAC 地址给 mqtt clientID */ sprintf(ha_device.mqtt_info.mqtt_clientID, "%02x%02x%02x%02x%02x%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); homeAssistant_device_init(&ha_device, ha_event_cb); ``` ## 重定义MQTT设备信息 设备信息是指设备名称,产商等之类的信息,本代码中,默认设备信息如下: >**模块:** Ai-M61 >**制造商:** 安信可科技 >**固件:** V1.0.0 >**硬件:** Ai-M61-32S-Kit_01 虽然你可以在 [homeAssistantDevConfig.h](./HomeAssistant-C/homeAssistantDevConfig.h) 中修改这些信息,但同样不推荐, ![alt text](./docs/IMG/image_dev.png) 同样也可以在定义HomeAssistant设备时对设备信息进行定义。 #### 用法示例 Linux 环境: ``` /* 定义 HomeAssistant 设备并对MQTT 进行赋值 */ homeAssisatnt_device_t ha_device = { .mqtt_info.mqtt_host = "your mqtt server host", //定义服务器地址,支持域名解析(必要) .mqtt_info.port = 1883, //定义端口号 (必要) .mqtt_info.mqtt_username = "myHomeAssistant", //定义 userName(可选) .mqtt_info.mqtt_password = "mypassword", //定义 密码 (可选) /* 定义设备信息 */ .name = "myDevice", //设备名称 .model = "Ai-M6x-12F", //模组名称 .manufacturer = "Ai-Thinker", //产商名称 .hw_version = "v1.0", //硬件版本号 .sw_version = "v1.0.0", //软件版本号 }; /* 为了防止同一份代码 MQTT Clienti 冲突 ,不建议使用固定的Client,采用Client=MAC地址进行区分*/ unsigned char mac[6]; //定义 STA MAC 地址变量 homeAssistant_get_sta_mac(mac);// 获取MAC 地址 ha_device.mqtt_info.mqtt_clientID = pvPortMalloc(12);//Client 申请空间 /* 赋值MAC 地址给 mqtt clientID */ sprintf(ha_device.mqtt_info.mqtt_clientID, "%02x%02x%02x%02x%02x%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); homeAssistant_device_init(&ha_device, ha_event_cb); ``` ## 启动实体资源 HomeAssitant-C的实体资源以链表的方式存在,为了节省HomeAssitant-C占用的空间,默认不会开启所有实体的编译(只开启"switch"实体资源),如果想要创建更多实体类型,则需要开启,在[homeAssistantDevConfig.h](HomeAssistant-C/homeAssistantDevConfig.h) 中,选择需要开启的实体,这些实体功能是否有用还取决于该功能是否已经开发完成,可以在本文开头看到已经[支持的实体类型](#ok_entity_type): ``` /********************** 需要开启的实体 *************************/ //报警控制面板 实体 默认不开启,需要使用就置 1 #define CONFIG_ENTITY_ENABLE_ALARM_CONTROL_PANEL 0 //高低电平传感器 实体 默认不开启,需要使用就置 1 #define CONFIG_ENTITY_ENABLE_BINARY_SENSOR 0 //按钮实体 默认不开启,需要使用就置 1 #define CONFIG_ENTITY_ENABLE_BUTTON 0 //摄像头实体 默认不开启,需要使用就置 1 #define CONFIG_ENTITY_ENABLE_CAMERA 0 //门类实体,窗帘、车门等 默认不开启,需要使用就置 1 #define CONFIG_ENTITY_ENABLE_COVER 0 //跟踪器实体,GPS定位等 默认不开启,需要使用就置 1 #define CONFIG_ENTITY_ENABLE_DEVICE_TRACKER 0 //触发器实体 默认不开启,需要使用就置 1 #define CONFIG_ENTITY_ENABLE_DEVICE_TRIGGER 0 //时间实体 默认不开启,需要使用就置 1 #define CONFIG_ENTITY_ENABLE_EVENT 0 //风扇实体 默认不开启,需要使用就置 1 #define CONFIG_ENTITY_ENABLE_FAN 0 //加湿器实体 默认不开启,需要使用就置 1 #define CONFIG__ENTITY_ENABLE_HUMIDIFIER 0 //图片实体 默认不开启,需要使用就置 1 #define CONFIG_ENTITY_ENABLE_IMAGE 0 //空调实体 默认不开启,需要使用就置 1 #define CONFIG_ENTITY_ENABLE_CLIMATE_HVAC 0 //割草机实体 默认不开启,需要使用就置 1 #define CONFIG_ENTITY_ENABLE_LAWN_MOWER 0 //灯实体 默认不开启,需要使用就置 1 #define CONFIG_ENTITY_ENABLE_LIGHT 0 //门锁实体 默认不开启,需要使用就置 1 #define CONFIG_ENTITY_ENABLE_LOCK 0 //数字实体 默认不开启,需要使用就置 1 #define CONFIG_ENTITY_ENABLE_NUMBER 0 //场景实体 默认不开启,需要使用就置 1 #define CONFIG_ENTITY_ENABLE_SCENE 0 //选择器实体 默认不开启,需要使用就置 1 #define CONFIG_ENTITY_ENABLE_SELECT 0 //传感器实体 默认不开启,需要使用就置 1 #define CONFIG_ENTITY_ENABLE_SENSOR 0 //警报器实体 默认不开启,需要使用就置 1 #define CONFIG_ENTITY_ENABLE_SIREN 0 //开关实体 默认开启 #define CONFIG_ENTITY_ENABLE_SWITCH 1 //更新实体 默认不开启,需要使用就置 1 #define CONFIG_ENTITY_ENABLE_UPDATE 0 //标签扫描仪实体 默认不开启,需要使用就置 1 #define CONFIG_ENTITY_ENABLE_TAG_SCANNER 0 //文本实体 默认不开启,需要使用就置 1 #define CONFIG_ENTITY_ENABLE_TEXT 1 //真空吸尘器实体 默认不开启,需要使用就置 1 #define CONFIG_ENTITY_ENABLE_VACUUM 0 //阀门实体 默认不开启,需要使用就置 1 #define CONFIG_ENTITY_ENABLE_VALVE 0 //热水器实体 默认不开启,需要使用就置 1 #define CONFIG_ENTITY_ENABLE_WATER_HEATER 0 ``` ## 实体创建 因为如果没有实体的话,设备上线也不会显示,所以需要创建实体之后再去上线,HomeAssistant-C库当中已经做好了实体创建的函数,只需要配置实体的参数即可,函数介绍如下: #### homeAssistant_device_add_entity(uint8_t* entity_type, void* ha_entity_list) > **参数说明** > **entity_type**: 实体类型,字符串变参数,在[homeAssistantDevConfig.h](./HomeAssistant-C/homeAssistantDevConfig.h) 中有参考 > **ha_entity_list**:实体描述,通常是实体的结构体 >通常情况下,应该在连接MQTT服务器成功后才创建实体。 #### 用法示例,以创建switch 实体为例: ``` /* HomeAssistant 事件回调 */ void ha_event_cb(ha_event_t event, homeAssisatnt_device_t* ha_dev) { switch (event) { /* 连接服务器事件 */ case HA_EVENT_MQTT_CONNECED: HA_LOG_I("<<<<<<<<<< HA_EVENT_MQTT_CONNECED\r\n"); /* 定义 switch 实体 */ ha_sw_entity_t entity_sw1 = { .name = "开关1", //实体名称 .icon = "mdi:power", //实体图标(可选) .unique_id = "switch1", //实体的unique id (必要,且唯一) }; /* 添加实体到设备当中 */ homeAssistant_device_add_entity(CONFIG_HA_ENTITY_SWITCH, &entity_sw1); break; /* 服务器断开事件 */ case HA_EVENT_MQTT_DISCONNECT: HA_LOG_I("<<<<<<<<<< HA_EVENT_MQTT_DISCONNECT\r\n"); default: break; } } ``` ## 设备上下线 设备的上线只需要一个函数就能实现,值得注意的是:设备上线之前,需要创建完成所以实体,否则实体不会顺利显示在HomeAssistant MQTT集成当中。 #### homeAssistant_device_send_status(bool status) > **参数说明** > **status**: HOMEASSISTANT_STATUS_ONLINE为上线,HOMEASSISTANT_STATUS_OFFLINE 为下线 #### 用法示例: ``` /* HomeAssistant 事件回调 */ void ha_event_cb(ha_event_t event, homeAssisatnt_device_t* ha_dev) { switch (event) { /* 连接服务器事件 */ case HA_EVENT_MQTT_CONNECED: HA_LOG_I("<<<<<<<<<< HA_EVENT_MQTT_CONNECED\r\n"); /* 定义 switch 实体 */ ha_sw_entity_t entity_sw1 = { .name = "开关1", //实体名称 .icon = "mdi:power", //实体图标(可选) .unique_id = "switch1", //实体的unique id (必要,且唯一) }; /* 添加实体到设备当中 */ homeAssistant_device_add_entity(CONFIG_HA_ENTITY_SWITCH, &entity_sw1); /* 设备上线 */ homeAssistant_device_send_status(HOMEASSISTANT_STATUS_ONLINE); break; /* 服务器断开事件 */ case HA_EVENT_MQTT_DISCONNECT: HA_LOG_I("<<<<<<<<<< HA_EVENT_MQTT_DISCONNECT\r\n"); /* 设备下线 */ homeAssistant_device_send_status(HOMEASSISTANT_STATUS_OFFLINE); default: break; } } ``` 在例程**HomeAssistant_basic**运行后,HomeAssistant 设备显示如下: ![alt text](./docs/IMG/image.png) ## 实体状态上报 HomeAssistant命令下发后,建议及时上报状态,提升UI交互体验。 #### homeAssistan_device_send_entity_state(uint8_t* entity_type, void* ha_entity_list, uint16_t state) > **参数说明** > > **entity_type**: 实体类型,字符串变参数,在[homeAssistantDevConfig.h](./HomeAssistant-C/homeAssistantDevConfig.h) 中有参考 > > **ha_entity_list**:实体描述,通常是实体的结构体 > > **state**:状态,当为开关实体为: true 或 flase > > **返回值**:成功返回 消息ID,失败返回-1 #### 用法示例: 上报开关状态:关 ``` homeAssistan_device_send_entity_state(CONFIG_HA_ENTITY_SWITCH, &entity_sw1, 0); ```