YOGYUI

Matter - WiFi IP 주소 할당 이벤트 캐치 본문

홈네트워크(IoT)/Matter

Matter - WiFi IP 주소 할당 이벤트 캐치

요겨 2023. 2. 15. 13:50
반응형

Matter - Catch Wi-Fi IP address assignment event

BLE-WiFi 커미셔닝을 통해 매터 디바이스를 커미셔닝한 경우, 라우터(공유기)의 DHCP를 통해 IP주소(v4, v6)를 할당받게 된다 (dynamic or static address)

 

IP 주소를 할당받은 후 웹서버 등 비매터(non-matter) 동작을 활성화하고 싶은 경우 IP주소 할당 이벤트를 캐치해야하는데, CHIP(Connected Home IP)의 PlatformManager의 이벤트 핸들러에 콜백을 추가하는 방식을 통해 구현하는 방법을 알아보자

함수원형

헤더파일 위치: connectedhomeip/src/include/platform/PlatformManager.h

inline CHIP_ERROR PlatformManager::AddEventHandler(EventHandlerFunct handler, intptr_t arg)
{
    return static_cast<ImplClass *>(this)->_AddEventHandler(handler, arg);
}

CHIP 초기화 (DeviceLayer::PlatformMgr()::ScheduleWork 호출) 전에 AddEventHandler 함수를 통해 콜백을 등록하면 된다

 

콜백함수 원형은 다음과 같다

typedef void (*EventHandlerFunct)(const ChipDeviceEvent * event, intptr_t arg);

ChipDeviceEvent는 connectedhomeip/src/include/platform/CHIPDeviceEvent.h 파일에 선언되어 있는 구조체(struct)이며, 다음과 같이 굉장히 많은 이벤트 관련 변수를 담고 있다

struct ChipDeviceEvent final
{
    uint16_t Type;

    union
    {
        ChipDevicePlatformEvent Platform;
        LambdaBridge LambdaEvent;
        struct
        {
            AsyncWorkFunct WorkFunct;
            intptr_t Arg;
        } CallWorkFunct;
        struct
        {
            ConnectivityChange Result;
        } WiFiConnectivityChange;
        struct
        {
            ConnectivityChange Result;
        } ThreadConnectivityChange;
        struct
        {
            ConnectivityChange IPv4;
            ConnectivityChange IPv6;
            chip::Inet::IPAddress ipAddress;
        } InternetConnectivityChange;
        struct
        {
            struct
            {
                ConnectivityChange Result;
            } Overall;
            struct
            {
                ConnectivityChange Result;
            } ViaThread;
        } ServiceConnectivityChange;
        struct
        {
            ConnectivityChange Result;
        } ServiceSubscriptionStateChange;
        struct
        {
            bool IsMemberOfFabric;
        } FabricMembershipChange;
        struct
        {
            bool IsServiceProvisioned;
            bool ServiceConfigUpdated;
        } ServiceProvisioningChange;
        struct
        {
            bool IsPairedToAccount;
        } AccountPairingChange;
        struct
        {
            bool IsTimeSynchronized;
        } TimeSyncChange;
        struct
        {
            uint64_t PeerNodeId;
            uint16_t SessionKeyId;
            uint8_t SessionType;
            bool IsCommissioner;
        } SessionEstablished;
        struct
        {
            BLE_CONNECTION_OBJECT ConId;
        } CHIPoBLESubscribe;
        struct
        {
            BLE_CONNECTION_OBJECT ConId;
        } CHIPoBLEUnsubscribe;
        struct
        {
            BLE_CONNECTION_OBJECT ConId;
            chip::System::PacketBuffer * Data;
        } CHIPoBLEWriteReceived;
        struct
        {
            BLE_CONNECTION_OBJECT ConId;
        } CHIPoBLEIndicateConfirm;
        struct
        {
            BLE_CONNECTION_OBJECT ConId;
            CHIP_ERROR Reason;
        } CHIPoBLEConnectionError;
        struct
        {
            BLE_CONNECTION_OBJECT ConId;
        } CHIPoBLENotifyConfirm;
        struct
        {
            bool RoleChanged : 1;
            bool AddressChanged : 1;
            bool NetDataChanged : 1;
            bool ChildNodesChanged : 1;
            struct
            {
                uint32_t Flags;
            } OpenThread;
        } ThreadStateChange;
        struct
        {
            ActivityChange Result;
        } CHIPoBLEAdvertisingChange;
        struct
        {
            InterfaceIpChangeType Type;
        } InterfaceIpAddressChanged;

        struct
        {
            uint64_t nodeId;
            FabricIndex fabricIndex;
        } CommissioningComplete;

        struct
        {
            FabricIndex fabricIndex;
            bool addNocCommandHasBeenInvoked;
            bool updateNocCommandHasBeenInvoked;
        } FailSafeTimerExpired;

        struct
        {
            // TODO(cecille): This should just specify wifi or thread since we assume at most 1.
            int network;
        } OperationalNetwork;

        struct
        {
            OtaState newState;
        } OtaStateChanged;
    };

    void Clear() { memset(this, 0, sizeof(*this)); }
    bool IsPublic() const { return DeviceEventType::IsPublic(Type); }
    bool IsInternal() const { return DeviceEventType::IsInternal(Type); }
    bool IsPlatformSpecific() const { return DeviceEventType::IsPlatformSpecific(Type); }
    bool IsPlatformGeneric() const { return DeviceEventType::IsPlatformGeneric(Type); }
};

ChipDeviceEvent 구조체 내에서 눈여겨봐야할 변수는 InterfaceIpAddressChanged 구조체 변수다

※ Type 변수의 값을 통해 전달되고 있는 이벤트가 어떤 종류인지 확인 가능

    struct
    {
        InterfaceIpChangeType Type;
    } InterfaceIpAddressChanged;

IP 주소 변경에 대한 이벤트 정보를 담고 있는데, InterfaceIpChangeType 열거형(enum)의 원형을 살펴보면

enum class InterfaceIpChangeType
{
    kIpV4_Assigned,
    kIpV4_Lost,
    kIpV6_Assigned,
    kIpV6_Lost,
};

IPv4, IPv6 각각에 대해 '주소가 할당되었음(Assigned)', '연결이 해제되었음(Lost)' 값이 이벤트 발생 시 할당되는 것을 알 수 있다

구현

콜백함수를 등록하고 활용하는 예시의 psuedo-code는 다음과 같다

(namespace를 쓰면 코드가 깔끔해지지만, 여기서는 사용하지 않는다)

static void matter_callback(const ChipDeviceEvent * event, intptr_t arg)
{
    switch (event->Type) {
    case chip::DeviceLayer::DeviceEventType::kInterfaceIpAddressChanged:
        if (event->InterfaceIpAddressChanged.Type == chip::DeviceLayer::InterfaceIpChangeType::kIpV6_Assigned) {
            std::cout << "IP Address(v6) assigned\n";
        } else if (event->InterfaceIpAddressChanged.Type == chip::DeviceLayer::InterfaceIpChangeType::kIpV4_Assigned) {
            std::cout << "IP Address(v4) assigned\n";
            // TODO: IP 주소 할당 후 동작 추가
        }
        break;
    default:
        break;
    }
}

void start_matter()
{
    // initialize code
    // ...
    
    // 이벤트 핸들러 콜백함수 등록
    chip::DeviceLayer::PlatformMgr().AddEventHandler(matter_callback, static_cast<intptr_t>(NULL));
    // Matter 시작
    chip::DeviceLayer::PlatformMgr().ScheduleWork(task, task_handle);
}

이벤트 타입이 DeviceEventType::kInterfaceIpAddressChanged일 때, InterfaceIpAddressChanged 구조체 변수 내 Type의 값에 따라 IPv4, IPv6 각각 주소가 할당되었는지 여부를 확인할 수 있다

 

ESP32에서 위와 같이 구현해서 로그를 찍어보면


I (2658) wifi:connected with SEUNGHEE_2G, aid = 5, channel 8, 40D, bssid = 70:5d:cc:24:ec:2d
I (2658) wifi:security: WPA2-PSK, phy: bgn, rssi: -48
I (2668) wifi:pm start, type: 1

I (2668) chip[DL]: WIFI_EVENT_STA_CONNECTED
I (2668) chip[DL]: WiFi station state change: Connecting -> Connecting_Succeeded
I (2688) chip[DL]: WiFi station state change: Connecting_Succeeded -> Connected
I (2688) chip[DL]: WiFi station interface connected
I (2698) wifi:AP's beacon interval = 102400 us, DTIM period = 3
I (2698) chip[ZCL]: WiFiDiagnosticsDelegate: OnConnectionStatusChanged
I (2718) chip[DL]: Done driving station state, nothing else to do...
I (2718) chip[DL]: Updating advertising data
I (3908) chip[DL]: IP_EVENT_GOT_IP6
I (3908) esp_netif_handlers: sta ip: 192.168.10.250, mask: 255.255.0.0, gw: 192.168.0.1
I (3908) chip[DL]: IPv6 addr available. Ready on WIFI_STA_DEF interface: fe80:0000:0000:0000:c6de:e2ff:fec1:b304
I (3928) chip[DL]: IPv4 Internet connectivity ESTABLISHED
I (3928) chip[DL]: IP_EVENT_STA_GOT_IP
I (3938) chip[DL]: IPv4 address changed on WiFi station interface: 192.168.10.250/255.255.0.0 gateway 192.168.0.1
IP Address(v6) assigned
I (3958) chip[DIS]: Updating services using commissioning mode 1
I (3968) chip[DIS]: CHIP minimal mDNS started advertising.
I (3988) chip[DIS]: Advertise commission parameter vendorID=65522 productID=32769 discriminator=3840/15 cm=1
I (3998) chip[DIS]: CHIP minimal mDNS configured as 'Commissionable node device'; instance name: DD16D87950553F61.
I (4018) chip[DIS]: mDNS service published: _matterc._udp
IP Address(v4) assigned
I (4148) chip[DIS]: Updating services using commissioning mode 1
I (4148) chip[DIS]: CHIP minimal mDNS started advertising.
I (4188) chip[DIS]: Advertise commission parameter vendorID=65522 productID=32769 discriminator=3840/15 cm=1
I (4198) chip[DIS]: CHIP minimal mDNS configured as 'Commissionable node device'; instance name: DD16D87950553F61.
I (4218) chip[DIS]: mDNS service published: _matterc._udp
I (4218) ROUTE_HOOK: Hook already installed on netif, skip...
E (4218) chip[DL]: Long dispatch time: 198 ms, for event type 32780
W (4278) wifi:<ba-add>idx:0 (ifx:0, 70:5d:cc:24:ec:2d), tid:0, ssn:3, winSize:64

 


CHIP 자체적으로 기록하는 로그와 임의로 추가한 로그(빨간색)가 함께 찍히는 것을 확인할 수 있다

※ esp-idf의 network interface(netif) 모듈 로그도 같이 찍힌다

  • 커미셔닝에 사용된 Wi-Fi SSID에 접속 (station connect)
  • DHCP로 IPv4, IPv6 주소 할당
  • mDNS 설정

매터 디바이스에 IP 주소가 할당되는 이벤트를 캐치하는 방법에 대해 알아봤다

CHIP 소스코드가 매우 구조화가 잘 되어있기 때문에 코드 트레이싱이 굉장히 쉽다!

이제 열심히 소켓, HTTP, HTTPS 기능을 추가해보자..

 

반응형