Pair Over Wired Connection

Last Updated on : 2023-09-06 10:41:15download

Overview

Concept

This topic describes pairing over a wired connection to enable a gateway to connect to the Tuya ecosystem.

The SDK comes with the implementation of the business logic of the pairing process. It defines a set of TuyaOS Kernel Layer (TKL) that shields differences in hardware and system. The underlying hardware is controlled by the TKL interfaces that need to be implemented by you. This topic guides you through developing the TKL interfaces.

Description

Pairing over a wired connection enables a gateway device to connect to the Tuya IoT Cloud. This process does not need the name and password of the router’s network.

Scenario

Pairing over a wired connection applies to:

  • The gateway is connected to an Ethernet cable, and the upstream router has access to the internet.
  • The gateway is not paired.

Principle

Connect the gateway and the mobile phone to the same router, so that they are on the same LAN. The gateway regularly broadcasts its encrypted device information using user datagram protocol (UDP) over LAN. After the mobile app receives and decrypts the UDP packet, it displays the gateway ready for pairing on the page of Auto Discovery.

After users tap the Add button on the app, the app sends the token for pairing to the gateway over a TCP connection. The gateway performs the activation on receiving the information until the pairing is finished.

Development guide

Interfaces

You do not need to call a specific API to initiate pairing over a wired connection, but you need to adapt the following TKL interfaces.

  • tkl_wired_set_status_cb

    OPERATE_RET tkl_wired_set_status_cb(TKL_WIRED_STATUS_CHANGE_CB cb);
    

    The SDK calls this interface during initialization. The parameter of this interface is the pointer to the notification callback invoked when the network status changes. The application should monitor the status of the network interface in real time. Network status changes can be passed to the SDK using the pointer to the notification callback.

    For example, when Ethernet is disconnected, cb(TKL_WIRED_LINK_DOWN) is invoked. When Ethernet is connected, with an IP address assigned, cb(TKL_WIRED_LINK_UP) is invoked.

  • tkl_wired_get_status

    OPERATE_RET tkl_wired_get_status(TKL_WIRED_STAT_E *status);
    

    The SDK calls this interface to request the connection status of the network interface. Assignment of an IP address is the key factor to determine the network status. If the network interface has been activated with an IP address assigned, TKL_WIRED_LINK_UP is returned. Otherwise, TKL_WIRED_LINK_DOWN is returned.

  • tkl_wired_get_ip

    OPERATE_RET tkl_wired_get_ip(NW_IP_S *ip);
    

    The SDK calls this interface to request the IP address of the network interface to set the socket address. If the gateway has multiple Ethernet ports, the network interface of the returned IP address is used for communication. Typically, the network interface connected to the internet is used. Be sure to return the correct IP address based on your scenario.

Example

This section demonstrates the implementation of TKL interfaces for generic Linux.

  1. Initialize the SDK by using the interface for pairing over a wired connection.

    int main(int argc, char **argv)
    {
        // ...
    
    #if defined(GW_SUPPORT_WIRED_WIFI) && (GW_SUPPORT_WIRED_WIFI==1)
        TUYA_CALL_ERR_RETURN(tuya_iot_wired_wf_sdk_init(IOT_GW_NET_WIRED_WIFI, GWCM_OLD, WF_START_AP_ONLY, PID, USER_SW_VER, NULL, 0));
    #elif defined(WIFI_GW) && (WIFI_GW==1)
        // Wireless SDK does not support pairing over wired connection.
        return OPRT_COM_ERROR;
    #else
        TUYA_CALL_ERR_RETURN(tuya_iot_sdk_init(PID, USER_SW_VER, NULL, 0));
    #endif
    
        // ...
    }
    
  2. Implement tkl_wired_get_ip to get the IP address of the network interface.

    #define WIRED_NAME "eth0"
    
    OPERATE_RET tkl_wired_get_ip(OUT NW_IP_S *ip)
    {
        int sock = 0;
        char ipaddr[50] = {0};
    
        struct sockaddr_in *sin;
        struct ifreq ifr;
    
        if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
             PR_ERR("socket create failed");
             return OPRT_COM_ERROR;
        }
    
        memset(&ifr, 0, sizeof(ifr));
        strncpy(ifr.ifr_name, WIRED_NAME, sizeof(ifr.ifr_name) - 1);
    
        if (ioctl(sock, SIOCGIFADDR, &ifr) < 0 ) {
             PR_ERR("ioctl failed");
             close(sock);
             return OPRT_COM_ERROR;
        }
    
        sin = (struct sockaddr_in *)&ifr.ifr_addr;
        strcpy(ip->ip,inet_ntoa(sin->sin_addr));
        close(sock);
    
        return OPRT_OK;
    }
    
  3. Implement tkl_wired_get_status to get the connection status of the network interface.

    OPERATE_RET tkl_wired_get_status(TKL_WIRED_STAT_E *status)
    {
        int sock;
        struct sockaddr_in *sin;
        struct ifreq ifr;
        NW_IP_S ip;
    
        *status = TKL_WIRED_LINK_DOWN;
    
        if ((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
             PR_ERR("socket failed");
             return OPRT_COM_ERROR;
        }
    
        memset(&ifr, 0, sizeof(ifr));
        strncpy(ifr.ifr_name, WIRED_NAME, sizeof(ifr.ifr_name) - 1);
    
        if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
            PR_ERR("ioctl failed");
            close(sock);
            return OPRT_COM_ERROR;
        }
    
        close(sock);
    
        if ((ifr.ifr_flags & IFF_UP) == 0) {
            return OPRT_OK;
        }
    
        if (tkl_wired_get_ip(&ip) != OPRT_OK) {
        	return OPRT_OK;
        }
    
        *status = TKL_WIRED_LINK_UP;
    
        return OPRT_OK;
    }
    
  4. Implement tkl_wired_set_status_cb to monitor the status of the network interface and save the pointer to the notification callback to the global variable. Network status changes can be passed to the SDK using the pointer to the notification callback.

    STATIC TKL_WIRED_STATUS_CHANGE_CB g_link_status_change_cb;
    
    STATIC VOID *link_status_thread(VOID *arg)
    {
        INT_T old_status = -1;
        TKL_WIRED_STAT_E new_status;
    
        while (1) {
            tkl_wired_get_status(&new_status);
            if (old_status != new_status) {
                g_link_status_change_cb(new_status);
                old_status = new_status;
            }
            sleep(1);
        }
    }
    
    OPERATE_RET tkl_wired_set_status_cb(TKL_WIRED_STATUS_CHANGE_CB cb)
    {
        pthread_t tid;
    
        g_link_status_change_cb = cb;
    
        return pthread_create(&tid, NULL, link_status_thread, NULL);
    }
    
  5. Implement tkl_wired_get_mac to get the MAC address of the network interface.

    OPERATE_RET tkl_wired_get_mac(NW_MAC_S *mac)
    {
        int i;
        int sock = -1;
        struct ifreq ifr;
        struct sockaddr *addr;
    
        if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
             PR_ERR("socket failed");
             return OPRT_SOCK_ERR;
        }
    
        memset(&ifr, 0, sizeof(ifr));
        strncpy(ifr.ifr_name, WIRED_NAME, sizeof(ifr.ifr_name) - 1);
        addr = (struct sockaddr *)&ifr.ifr_hwaddr;
        addr->sa_family = 1;
    
        /* get mac addr */
        if (ioctl(sock, SIOCGIFHWADDR, &ifr) < 0) {
            PR_ERR("ioctl failed");
            close(sock);
            return OPRT_COM_ERROR;
        }
    
        memcpy(mac->mac, addr->sa_data, MAC_ADDR_LEN);
    
        close(sock);
        return OPRT_OK;
    }
    
  6. Populate the unused interfaces with nulls.

    OPERATE_RET tkl_wired_set_mac(CONST NW_MAC_S *mac)
    {
        return OPRT_OK;
    }
    

Things to note

Do not block TKL interfaces. It is recommended to process time-consuming tasks asynchronously.