esp32 matter记录

最近有接触matter这个功能,想在esp32上尝试一下,故而这里记录一下

关于matter的说明,可以参考这个文章
Matter开发,看这一篇就够了

主要参考:(主要还是得参考下面那个文章)
【ESP32-Matter】基于matter协议 chip-tool 控制 esp32-c3 开发板点灯
Developing with the SDK

1、环境搭建

简单来说:
1、matter是个智能家居协议,两个设备无论是不是同一个厂家的产品,只要都支持matter,就可以一起控制,matter生态和其他的生态也一样,需要有一个主控,拓扑如下所示:
在这里插入图片描述
上面图中还有个bridge,bridge也是和其他生态的bridge一样,可以把不支持matter生态的产品通过bridge介入matter生态中。
2、esp32,也就是乐鑫,一般开发esp32用的是esp-idf来开发的,乐鑫针对matter的sdk是esp-matter,使用esp-matter就可以让esp32支持matter

下面是编译记录吧,这里面搭环境有很多坑,建议参考我上面的那个官方的资料(然后整个过程需要全局科学上网,这一点非常重要)

这里我用的开发环境是wsl的ubuntu22.04,直接在windows的商店安装完成即可。然后直接更新软件源,这也是参考的官方资料:
在这里插入图片描述
下面先下载esp-idf,这个是肯定的,就是安装idf的环境

git clone --recursive https://github.com/espressif/esp-idf.git
cd esp-idf; git checkout v5.2.1; git submodule update --init --recursive;
./install.sh
cd ..

之后检查一下环境:

cd esp-idf
source ./export.sh
cd ..

看到这个输出就没啥问题了(这里一般不会有什么问题)
在这里插入图片描述
下面开始安装esp-matter,还是先拉git

git clone --depth 1 https://github.com/espressif/esp-matter.git
cd esp-matter

下面开始拉第三方库,这个可能会失败,失败了就重复执行,科学上网在这个时候的重要性就体现出来了

git submodule update --init --depth 1

之后开始拉matter的sdk

cd ./connectedhomeip/connectedhomeip
./scripts/checkout_submodules.py --platform esp32 darwin --shallow

开始编译matter

cd ../..
./install.sh

会看到下面的输出,这个过程还是有可能会失败,这个失败了我建议是删掉esp-matter,重来一遍即可。
在这里插入图片描述
我遇到过的原因是因为这里的文件拉取的不全导致的,这个repo下面会有这么多文件是正常的
在这里插入图片描述
编译的过程是这样的:
在这里插入图片描述
之后开始安装python库
在这里插入图片描述
下面开始编译chip-tools,发现上面其实已经编译了
在这里插入图片描述

下面开始测试matter,进入下面的目录,选一下板子,发现需要安装一下cmake,apt安装一下即可
在这里插入图片描述
之后再次尝试
在这里插入图片描述
使用idf.py build来进行编译
在这里插入图片描述
编译OK,开始烧录
在这里插入图片描述
总的来说,这个过程一定要连外网,不然很多包真的是很难下载,下面是个安装过程遇到过的问题:
在这里插入图片描述
解决方案是:

sudo apt install build-essential python3-dev

sudo apt-get install pkg-config

sudo apt-get install libglib2.0-dev libglib2.0-dev-bin libgio2.0-cil-dev

然后不是每次启动都要配一下环境吗,就可以这样设置,就在~/.bashrc的结尾加上这两行
在这里插入图片描述

ource /home/lx/Desktop/esp32/esp-idf/export.sh
source /home/lx/Desktop/esp32/esp-matter/export.sh

这样每次打开终端就都会执行
在这里插入图片描述

2、正式测试,烧录chip-light

本次测试用的是比较通用的esp32最小系统(注:需要改一点代码才能跑起来的)
在这里插入图片描述
前面代码已经编译,下面直接编译看看什么情况,使用idf烧录之前需要先给USB提权

sudo chmod 777 /dev/ttyUSB0

下面先擦除,不然上次的绑定关系会有影响

idf.py erase-flash

如下所示
在这里插入图片描述
idf.py flash monitor(烧录后直接进入串口)
在这里插入图片描述
这里可以看到一些信息
在这里插入图片描述
如果要退出这个终端,直接ctrl+c是不行的,需要按下ctrl+]退出串口终端
在这里插入图片描述
烧录证书(证书的生成后面会说到)

esptool.py -p /dev/ttyUSB0 write_flash 0x10000 /home/lx/Desktop/esp32/esp-matter/tools/mfg_tool/out/fff2_8001/7ab72773-c568-46fc-9300-892b480cdb3d/7ab72773-c568-46fc-9300-892b480cdb3d-partition.bin

证书烧录的比较快
在这里插入图片描述
重新烧录
在这里插入图片描述
生成的证书在这里
在这里插入图片描述
可以对一下证书
在这里插入图片描述
然后这里我用的是onip的方式连接,需要matter先配个网,输入下面的内容
在这里插入图片描述
从后面的打印中可以看到已经配上网了
在这里插入图片描述
在路由器主页也可以看到
在这里插入图片描述
可以用手机app看一下是不是处于配对模式(选择udp,然后输入matterc搜索)
在这里插入图片描述

之后在一个终端输入chip-tool pairing onnetwork 0x11 22865251(这个码是前面证书的
在这里插入图片描述
之后继续在这个终端输入这样的命令来完成开关灯
在这里插入图片描述
可以观察开发板查看灯的亮灭情况

chip-tool onoff on 0x11 0x2
chip-tool onoff off 0x11 0x2

下面说下证书是怎么生成的,输入下面的内容,我这里是生成5个

esp-matter-mfg-tool -n 5 -cn "My bulb" -v 0xFFF2 -p 0x8001 --pai \
-k ~/Desktop/esp32/esp-matter/connectedhomeip/connectedhomeip/credentials/test/attestation/Chip-Test-PAI-FFF2-8001-Key.pem \
-c ~/Desktop/esp32/esp-matter/connectedhomeip/connectedhomeip/credentials/test/attestation/Chip-Test-PAI-FFF2-8001-Cert.pem \
-cd ~/Desktop/esp32/esp-matter/connectedhomeip/connectedhomeip/credentials/test/certification-declaration/Chip-Test-CD-FFF2-8001.der

也可以用ios的apple home绑定(只是会提示是未认证,点击确认即可)
在这里插入图片描述

3、代码修改部分

这里需要说明下,官方代码用的是一个这个开发板来做的,实在是太贵了
在这里插入图片描述
我用的是自己受伤的替代版本,所以官方代码肯定是能跑,但是跑起来肯定不是那个样,因此需要改动一点才行,这里只改了一个文件
在这里插入图片描述
我这个开发板的灯是led2

#include "driver/gpio.h"

#include <app/server/CommissioningWindowManager.h>
#include <app/server/Server.h>

static const char *TAG = "app_main";
uint16_t light_endpoint_id = 0;

uint16_t light_endpoint2_id = 0;

#define BLINK_GPIO GPIO_NUM_2

新增了一个endpoint和gpio的初始化
在这里插入图片描述
然后在收到更新回调的地方,判断是不是我这个endpoint触发的,如果是的话就根据改变的情况改变gpio状态
在这里插入图片描述
完整代码:

/*
   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/

#include <esp_err.h>
#include <esp_log.h>
#include <nvs_flash.h>

#include <esp_matter.h>
#include <esp_matter_console.h>
#include <esp_matter_ota.h>

#include <common_macros.h>
#include <app_priv.h>
#include <app_reset.h>
#if CHIP_DEVICE_CONFIG_ENABLE_THREAD
#include <platform/ESP32/OpenthreadLauncher.h>
#endif

#include "driver/gpio.h"

#include <app/server/CommissioningWindowManager.h>
#include <app/server/Server.h>

static const char *TAG = "app_main";
uint16_t light_endpoint_id = 0;

uint16_t light_endpoint2_id = 0;

#define BLINK_GPIO GPIO_NUM_2

using namespace esp_matter;
using namespace esp_matter::attribute;
using namespace esp_matter::endpoint;
using namespace chip::app::Clusters;

constexpr auto k_timeout_seconds = 300;

#if CONFIG_ENABLE_ENCRYPTED_OTA
extern const char decryption_key_start[] asm("_binary_esp_image_encryption_key_pem_start");
extern const char decryption_key_end[] asm("_binary_esp_image_encryption_key_pem_end");

static const char *s_decryption_key = decryption_key_start;
static const uint16_t s_decryption_key_len = decryption_key_end - decryption_key_start;
#endif // CONFIG_ENABLE_ENCRYPTED_OTA

static void app_event_cb(const ChipDeviceEvent *event, intptr_t arg)
{
    switch (event->Type) {
    case chip::DeviceLayer::DeviceEventType::kInterfaceIpAddressChanged:
        ESP_LOGI(TAG, "Interface IP Address changed");
        break;

    case chip::DeviceLayer::DeviceEventType::kCommissioningComplete:
        ESP_LOGI(TAG, "Commissioning complete");
        break;

    case chip::DeviceLayer::DeviceEventType::kFailSafeTimerExpired:
        ESP_LOGI(TAG, "Commissioning failed, fail safe timer expired");
        break;

    case chip::DeviceLayer::DeviceEventType::kCommissioningSessionStarted:
        ESP_LOGI(TAG, "Commissioning session started");
        break;

    case chip::DeviceLayer::DeviceEventType::kCommissioningSessionStopped:
        ESP_LOGI(TAG, "Commissioning session stopped");
        break;

    case chip::DeviceLayer::DeviceEventType::kCommissioningWindowOpened:
        ESP_LOGI(TAG, "Commissioning window opened");
        break;

    case chip::DeviceLayer::DeviceEventType::kCommissioningWindowClosed:
        ESP_LOGI(TAG, "Commissioning window closed");
        break;

    case chip::DeviceLayer::DeviceEventType::kFabricRemoved:
        {
            ESP_LOGI(TAG, "Fabric removed successfully");
            if (chip::Server::GetInstance().GetFabricTable().FabricCount() == 0)
            {
                chip::CommissioningWindowManager & commissionMgr = chip::Server::GetInstance().GetCommissioningWindowManager();
                constexpr auto kTimeoutSeconds = chip::System::Clock::Seconds16(k_timeout_seconds);
                if (!commissionMgr.IsCommissioningWindowOpen())
                {
                    /* After removing last fabric, this example does not remove the Wi-Fi credentials
                     * and still has IP connectivity so, only advertising on DNS-SD.
                     */
                    CHIP_ERROR err = commissionMgr.OpenBasicCommissioningWindow(kTimeoutSeconds,
                                                    chip::CommissioningWindowAdvertisement::kDnssdOnly);
                    if (err != CHIP_NO_ERROR)
                    {
                        ESP_LOGE(TAG, "Failed to open commissioning window, err:%" CHIP_ERROR_FORMAT, err.Format());
                    }
                }
            }
        break;
        }

    case chip::DeviceLayer::DeviceEventType::kFabricWillBeRemoved:
        ESP_LOGI(TAG, "Fabric will be removed");
        break;

    case chip::DeviceLayer::DeviceEventType::kFabricUpdated:
        ESP_LOGI(TAG, "Fabric is updated");
        break;

    case chip::DeviceLayer::DeviceEventType::kFabricCommitted:
        ESP_LOGI(TAG, "Fabric is committed");
        break;

    case chip::DeviceLayer::DeviceEventType::kBLEDeinitialized:
        ESP_LOGI(TAG, "BLE deinitialized and memory reclaimed");
        break;

    default:
        break;
    }
}

// This callback is invoked when clients interact with the Identify Cluster.
// In the callback implementation, an endpoint can identify itself. (e.g., by flashing an LED or light).
static esp_err_t app_identification_cb(identification::callback_type_t type, uint16_t endpoint_id, uint8_t effect_id,
                                       uint8_t effect_variant, void *priv_data)
{
    ESP_LOGI(TAG, "Identification callback: type: %u, effect: %u, variant: %u", type, effect_id, effect_variant);
    return ESP_OK;
}

// This callback is called for every attribute update. The callback implementation shall
// handle the desired attributes and return an appropriate error code. If the attribute
// is not of your interest, please do not return an error code and strictly return ESP_OK.
static esp_err_t app_attribute_update_cb(attribute::callback_type_t type, uint16_t endpoint_id, uint32_t cluster_id,
                                         uint32_t attribute_id, esp_matter_attr_val_t *val, void *priv_data)
{
    esp_err_t err = ESP_OK;

    if (type == PRE_UPDATE) {
        /* Driver update */
        if(endpoint_id == light_endpoint2_id)
        {
            if (cluster_id == OnOff::Id) {
                if (attribute_id == OnOff::Attributes::OnOff::Id) {
                    gpio_set_level(BLINK_GPIO, val->val.b);
                    return err;
                }
            }
        }

        app_driver_handle_t driver_handle = (app_driver_handle_t)priv_data;
        err = app_driver_attribute_update(driver_handle, endpoint_id, cluster_id, attribute_id, val);
    }

    return err;
}

extern "C" void app_main()
{
    esp_err_t err = ESP_OK;

    /* Initialize the ESP NVS layer */
    nvs_flash_init();

    /* Initialize driver */
    app_driver_handle_t light_handle = app_driver_light_init();
    app_driver_handle_t button_handle = app_driver_button_init();
    app_reset_button_register(button_handle);

    /* Create a Matter node and add the mandatory Root Node device type on endpoint 0 */
    node::config_t node_config;

    // node handle can be used to add/modify other endpoints.
    node_t *node = node::create(&node_config, app_attribute_update_cb, app_identification_cb);
    ABORT_APP_ON_FAILURE(node != nullptr, ESP_LOGE(TAG, "Failed to create Matter node"));

    extended_color_light::config_t light_config;
    light_config.on_off.on_off = DEFAULT_POWER;
    light_config.on_off.lighting.start_up_on_off = nullptr;
    light_config.level_control.current_level = DEFAULT_BRIGHTNESS;
    light_config.level_control.on_level = DEFAULT_BRIGHTNESS;
    light_config.level_control.lighting.start_up_current_level = DEFAULT_BRIGHTNESS;
    light_config.color_control.color_mode = (uint8_t)ColorControl::ColorMode::kColorTemperature;
    light_config.color_control.enhanced_color_mode = (uint8_t)ColorControl::ColorMode::kColorTemperature;
    light_config.color_control.color_temperature.startup_color_temperature_mireds = nullptr;

    // endpoint handles can be used to add/modify clusters.
    endpoint_t *endpoint = extended_color_light::create(node, &light_config, ENDPOINT_FLAG_NONE, light_handle);
    ABORT_APP_ON_FAILURE(endpoint != nullptr, ESP_LOGE(TAG, "Failed to create extended color light endpoint"));

    light_endpoint_id = endpoint::get_id(endpoint);
    ESP_LOGI(TAG, "Light created with endpoint_id %d", light_endpoint_id);

    /* Mark deferred persistence for some attributes that might be changed rapidly */
    cluster_t *level_control_cluster = cluster::get(endpoint, LevelControl::Id);
    attribute_t *current_level_attribute = attribute::get(level_control_cluster, LevelControl::Attributes::CurrentLevel::Id);
    attribute::set_deferred_persistence(current_level_attribute);

    cluster_t *color_control_cluster = cluster::get(endpoint, ColorControl::Id);
    attribute_t *current_x_attribute = attribute::get(color_control_cluster, ColorControl::Attributes::CurrentX::Id);
    attribute::set_deferred_persistence(current_x_attribute);
    attribute_t *current_y_attribute = attribute::get(color_control_cluster, ColorControl::Attributes::CurrentY::Id);
    attribute::set_deferred_persistence(current_y_attribute);
    attribute_t *color_temp_attribute = attribute::get(color_control_cluster, ColorControl::Attributes::ColorTemperatureMireds::Id);
    attribute::set_deferred_persistence(color_temp_attribute);

#if CHIP_DEVICE_CONFIG_ENABLE_THREAD && CHIP_DEVICE_CONFIG_ENABLE_WIFI_STATION
    // Enable secondary network interface
    secondary_network_interface::config_t secondary_network_interface_config;
    endpoint = endpoint::secondary_network_interface::create(node, &secondary_network_interface_config, ENDPOINT_FLAG_NONE, nullptr);
    ABORT_APP_ON_FAILURE(endpoint != nullptr, ESP_LOGE(TAG, "Failed to create secondary network interface endpoint"));
#endif


#if CHIP_DEVICE_CONFIG_ENABLE_THREAD
    /* Set OpenThread platform config */
    esp_openthread_platform_config_t config = {
        .radio_config = ESP_OPENTHREAD_DEFAULT_RADIO_CONFIG(),
        .host_config = ESP_OPENTHREAD_DEFAULT_HOST_CONFIG(),
        .port_config = ESP_OPENTHREAD_DEFAULT_PORT_CONFIG(),
    };
    set_openthread_platform_config(&config);
#endif

    // on_off_light::app_driver_attribute_update
    on_off_light::config_t light_config2;
    light_config2.on_off.on_off = DEFAULT_POWER;
    light_config2.on_off.lighting.start_up_on_off = DEFAULT_POWER;
    endpoint_t *endpoint2 = on_off_light::create(node, &light_config2, ENDPOINT_FLAG_NONE, 0);
    light_endpoint2_id = endpoint::get_id(endpoint2);

    /* Matter start */
    err = esp_matter::start(app_event_cb);
    ABORT_APP_ON_FAILURE(err == ESP_OK, ESP_LOGE(TAG, "Failed to start Matter, err:%d", err));

    /*GPIO设置*/
    gpio_reset_pin(BLINK_GPIO);
    /* Set the GPIO as a push/pull output */
    gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT);
    gpio_set_level(BLINK_GPIO, DEFAULT_POWER);

    /* Starting driver with default values */
    app_driver_light_set_defaults(light_endpoint_id);

#if CONFIG_ENABLE_ENCRYPTED_OTA
    err = esp_matter_ota_requestor_encrypted_init(s_decryption_key, s_decryption_key_len);
    ABORT_APP_ON_FAILURE(err == ESP_OK, ESP_LOGE(TAG, "Failed to initialized the encrypted OTA, err: %d", err));
#endif // CONFIG_ENABLE_ENCRYPTED_OTA

#if CONFIG_ENABLE_CHIP_SHELL
    esp_matter::console::diagnostics_register_commands();
    esp_matter::console::wifi_register_commands();
#if CONFIG_OPENTHREAD_CLI
    esp_matter::console::otcli_register_commands();
#endif
    esp_matter::console::init();
#endif
}

4、待做

这里可以考虑下ble的方式,但我没有实现

我之前用这个2204的虚拟机,开启蓝牙就挂掉了(这个问题有待研究下)
在这里插入图片描述
看起来是这里挂了
在这里插入图片描述
然后我又重新装了个2004的虚拟机,终于跑起来了,参考下面这个大佬的
【Matter】使用chip tool在ESP32-C3上进行matter开发

但是最终也失败了
esp32端打印
在这里插入图片描述
配网的那一端打印
在这里插入图片描述
后面在研究下,有知道的也可以分享一下

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

桃成蹊2.0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值