更新时间:2024-11-20 08:51:29下载pdf
本文详细介绍使用综合 SDK 如何实现有线配网功能,我们将会实现通过有线配网方式来激活网关设备。
有线配网的工作原理是,设备通过有线方式连接到路由器,手机也连接到路由器,让手机和设备处于同一局域网下,设备把它的 PID、IP 地址等信息加密后发送 UDP 广播,手机 App 接收并解密广播包数据后,显示待配网设备。
用户点击添加设备后,手机 App 使用 UDP 广播的 IP 地址与设备建立 TCP 长连接,把配网令牌发送给设备,设备接收到配网令牌,完成配网流程。
SDK 已经实现有线配网的底层逻辑,定义了一套有线适配接口,应用只需要完成接口适配即可。
有线适配接口比较简单,SDK 只关心有线是否连接和网口的 IP 地址,所以我们主要适配这两个接口。
使用支持有线配网接口初始化 SDK。
// ...
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)
// 无线 SDK,不支持有线配网
return OPRT_COM_ERROR;
#else
TUYA_CALL_ERR_RETURN(tuya_iot_sdk_init(PID, USER_SW_VER, NULL, 0));
#endif
// ...
}
适配获取有线 IP 地址接口,实现获取有线接口的 IP 地址。主要用于局域网通讯,从该网口发送 UDP 广播以及把 IP 地址广播出去,开发者可根据实际情况适配。
OPERATE_RET tuya_adapter_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, ETH_DEV, 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;
}
适配获取有线连接状态,实现检测网线插拔状态,并把状态返回给 SDK。SDK 会定时调用该接口来检测有线连接状态是否正常,所以该接口不能阻塞,任务处理尽量不超过 1 秒。
BOOL_T tuya_adapter_wired_station_conn(VOID)
{
int sock;
struct sockaddr_in *sin;
struct ifreq ifr;
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, ETH_DEV, sizeof(ifr.ifr_name) - 1);
if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
PR_ERR("ioctl failed");
close(sock);
return FALSE;
}
close(sock);
if ((ifr.ifr_flags & IFF_UP) == 0)
return FALSE;
return TRUE;
}
如果是有线 + 无线 SDK,还需要额外适配获取有线外网状态接口。有线 + 无线 SDK 内部实现了有线和无线的切换,有线和无线同时连接则有线优先。当前状态从无线切换到有线,SDK 会调用该接口获取有线的外网是否连通,有线外网正常才会切换到有线。
/**
* 简单处理,任何情况都认为有线外网是连通的,只要网线连接并分配了 IP 地址,都是有线优先。
*/
OPERATE_RET tuya_adapter_wired_if_connect_internet(BOOL_T *status)
{
*status = TRUE;
return OPRT_OK;
}
#include <unistd.h>
#include "uni_log.h"
#include "base_os_adapter.h"
#include "tuya_iot_base_api.h"
#include "tuya_iot_com_api.h"
#include "tuya_iot_sdk_api.h"
#include "tuya_iot_sdk_defs.h"
#if defined(TY_BT_MOD) && (TY_BT_MOD == 1)
#include "tuya_os_adapt_bt.h"
#endif
#define PID "fljmamufiym5fktz" // 替换成自己的产品 ID
#define UUID "tuya461dbc63aeeb991f" // 替换成自己的 UUID
#define AUTHKEY "c8X4PR4wx1gMFaQlaZu5dfgVvVRwB8Ug" // 替换成自己的 AUTHKEY
STATIC VOID __gw_reset_cb(GW_RESET_TYPE_E type)
{
PR_DEBUG("gw reset callback, type: %d", type);
if (GW_RESET_DATA_FACTORY != type) {
exit(0);
}
return;
}
STATIC VOID __gw_upgrade_cb(CONST FW_UG_S *fw)
{
PR_DEBUG("gw upgrade callback");
if (fw == NULL) {
PR_ERR("invalid param");
return;
}
PR_DEBUG(" tp: %d", fw->tp);
PR_DEBUG(" fw_url: %s", fw->fw_url);
PR_DEBUG(" sw_ver: %s", fw->sw_ver);
PR_DEBUG(" fw_hmac: %s", fw->fw_hmac);
PR_DEBUG(" file_size: %u", fw->file_size);
return;
}
STATIC VOID __gw_active_stat_cb(GW_STATUS_E status)
{
PR_DEBUG("gw active stat callback, status: %d", status);
return;
}
STATIC VOID __gw_reboot_cb(VOID)
{
PR_DEBUG("gw reboot callback");
exit(0);
return;
}
STATIC VOID __nw_stat_cb(IN CONST SDK_NW_STAT_T stat)
{
PR_DEBUG("network stat: %d", stat);
return;
}
STATIC VOID __wired_stat_cb(IN CONST SDK_WIRED_NW_STAT_T stat)
{
PR_DEBUG("wired stat: %d", stat);
return;
}
int main(int argc, char **argv)
{
OPERATE_RET rt = OPRT_OK;
GW_PROD_INFO_S prod_info = {0};
/* gw base callback */
TY_GW_INFRA_CBS_S gw_cbs = {
.gw_reset_cb = __gw_reset_cb,
.gw_upgrade_cb = __gw_upgrade_cb,
.gw_active_stat_cb = __gw_active_stat_cb,
.gw_reboot_cb = __gw_reboot_cb,
};
#if defined(TY_BT_MOD) && (TY_BT_MOD == 1)
tuya_os_adapt_reg_bt_intf();
#endif
/* initiate os-layer service*/
tuya_os_intf_init();
/* initiate iot-layer service */
TUYA_CALL_ERR_RETURN(tuya_iot_init("./"));
/* set the logging level to debug */
SET_PR_DEBUG_LEVEL(TY_LOG_LEVEL_DEBUG);
PR_DEBUG("SDK INFO: %s", tuya_iot_get_sdk_info());
/* set uuid and authkey */
prod_info.uuid = UUID;
prod_info.auth_key = AUTHKEY;
TUYA_CALL_ERR_RETURN(tuya_iot_set_gw_prod_info(&prod_info));
/* pre-initiate sdk service */
TUYA_CALL_ERR_RETURN(tuya_iot_sdk_pre_init(TRUE));
/* initiate application service, more service in here */
TUYA_CALL_ERR_RETURN(tuya_user_svc_init(&gw_cbs));
/* initiate sdk service */
#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)
// 无线 SDK,不支持有线配网
return OPRT_COM_ERROR;
#else
TUYA_CALL_ERR_RETURN(tuya_iot_sdk_init(PID, USER_SW_VER, NULL, 0));
#endif
/* register net stat notification callback */
TUYA_CALL_ERR_RETURN(tuya_iot_sdk_reg_netstat_cb(__nw_stat_cb, __wired_stat_cb, NULL));
/* start application service, more service in here */
TUYA_CALL_ERR_RETURN(tuya_user_svc_start(NULL));
while (1) {
sleep(10);
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <netinet/in.h>
#include "uni_log.h"
#include "tuya_os_adapt_wired.h"
#define ETH_DEV "eth0"
/**
* 获取网口 IP 地址接口
*/
OPERATE_RET tuya_adapter_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, ETH_DEV, 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;
}
/**
* 获取网线连接状态接口
*/
BOOL_T tuya_adapter_wired_station_conn(VOID)
{
int sock;
struct sockaddr_in *sin;
struct ifreq ifr;
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, ETH_DEV, sizeof(ifr.ifr_name) - 1);
if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
PR_ERR("ioctl failed");
close(sock);
return FALSE;
}
close(sock);
if ((ifr.ifr_flags & IFF_UP) == 0)
return FALSE;
return TRUE;
}
/**
* 获取有线外网状态接口,仅在有线+无线 SDK 有效。
*/
OPERATE_RET tuya_adapter_wired_if_connect_internet(BOOL_T *status)
{
*status = TRUE;
return OPRT_OK;
}
/**
* 获取无线信号强度接口,仅在有线+无线 SDK 有效。获取信号强度上报到涂鸦云。
* a) 当前是有线连接时,通过该接口获取无线的信号强度。
* b) 当前是无线连接时,通过 tuya_adapter_wifi_station_get_conn_ap_rssi 接口获取无线的信号强度。
*/
OPERATE_RET tuya_adapter_wired_wifi_station_get_conn_ap_rssi(OUT SCHAR_T *rssi)
{
*rssi = 99;
return OPRT_OK;
}
/* 无需实现 */
OPERATE_RET tuya_adapter_wired_get_mac(OUT NW_MAC_S *mac)
{
return OPRT_OK;
}
/* 无需实现 */
OPERATE_RET tuya_adapter_wired_set_mac(IN CONST NW_MAC_S *mac)
{
return OPRT_OK;
}
/* 无需实现 */
OPERATE_RET tuya_adapter_wired_wifi_set_station_connect(IN CONST CHAR_T *ssid, IN CONST CHAR_T *passwd)
{
return OPRT_OK;
}
/* 无需实现 */
BOOL_T tuya_adapter_wired_wifi_need_cfg(VOID)
{
return FALSE;
}
/* 无需实现 */
OPERATE_RET tuya_adapter_wired_get_nw_stat(GW_BASE_NW_STAT_T *stat)
{
return OPRT_OK;
}
该内容对您有帮助吗?
是意见反馈该内容对您有帮助吗?
是意见反馈