Wi-Fi EZ Mode

Last Updated on : 2023-10-11 03:39:07download

This topic describes pairing a device using the Wi-Fi EZ mode, also known as Wi-Fi Easy Connect or SmartConfig. In the pairing process, a mobile phone connects to the router and broadcasts the Wi-Fi credentials and pairing token to enable the smart device to get this information for connection and pairing. It is easy-to-use, but has compatibility requirements for mobile phones and routers. The success rate is lower than that of AP mode.

For iOS 14.5 and later, we recommend that you use the AP mode instead of the Wi-Fi EZ mode. The former trumps the latter when it comes to the following aspects:

  • Compared with the Wi-Fi EZ mode, the AP mode results in a higher success rate, optimal reliability, and fewer compatibility requirements for mobile phones and routers.
  • The app built with Xcode 12.5 cannot send the EZ pairing data packets from an iPhone that runs iOS 14.5 or later. In this case, the permission com.apple.developer.networking.multicast must be enabled for the app. This permission must be approved by Apple before it can be enabled.

Pairing process

AppBizBundle SDKCloudDeviceRouterEnter pairing mode.Wi-Fi LED indicatorblinks quickly.Connect to the router.1Request a pairing token.2Request a pairing token.3Return the pairing token.4Return the pairing token.5User enters the Wi-Fipassword.Send the Wi-Fi credentials(SSID and password) andpairing token.6Send the Wi-Fi credentials (SSID and password) and pairingtoken.7Indicator is off.Connect to the router.8Connected successfully.9Indicator is steadyon.Request device activation.10Device is activated.11Return the device list.12Return the device list.13AppBizBundle SDKCloudDeviceRouterWi-Fi EZ Mode Pairing

Register the pairing type

When the device pairing service is initialized, register the pairing type, which is ThingSmartActivatorTypeEZModel.

API description

/// Initialize network configuration types
/// @param typeList Network configuration types
- (void)registerWithActivatorList:(NSArray<ThingSmartActivatorTypeModel *>*)typeList;

Parameter description

Parameters Description
typeList The list of pairing types.

Get a token

The SDK gets a pairing token from the cloud before it can start the pairing process. The token is valid for 10 minutes and expires immediately after the device is paired. A new token must be generated if the device needs to be paired again.

API description

- (void)getTokenWithHomeId:(long long)homeId
                   success:(ThingSuccessString)success
                   failure:(ThingFailureError)failure;

Parameter description

Parameters Description
homeId The ID of the home with which the device is bound.
success The success callback. A pairing token is returned.
failure The failure callback. An error message is returned.

Start searching

Pass in the registered typeList to start searching.

API description

/// Start searching
/// @param typeList Network configuration types
- (void)startSearch:(NSArray <ThingSmartActivatorTypeModel *>*)typeList;

Parameter description

Parameters Description
typeList The list of pairing types.

Stop searching

API description

/// Stop searching
/// @param typeList Network configuration types
/// @param clearCache Whether to clear the cache
- (void)stopSearch:(NSArray <ThingSmartActivatorTypeModel *>*)typeList clearCache:(BOOL)clearCache;

Parameter description

Parameters Description
typeList The list of pairing types.
clearCache Specifies whether to clear the cache search result.

Device search callback

After the device is paired, the callback returns the device information. If the operation fails, the callback returns the error message.

Device discovery callback

API description

/// Device search callback
/// @param service Search instance
/// @param type Network configuration type
/// @param device Discovered device
/// @param errorModel Error callback
- (void)activatorService:(id<ThingSmartActivatorSearchProtocol>)service
            activatorType:(ThingSmartActivatorTypeModel *)type
             didFindDevice:(nullable ThingSmartActivatorDeviceModel *)device
                     error:(nullable ThingSmartActivatorErrorModel *)errorModel;

Parameter description

Parameters Description
service The pairing service.
type The pairing type. ThingSmartActivatorTypeEZModel is returned.
device The discovered device. The device model is returned on success. nil is returned on failure.
errorModel This model is returned if pairing fails or times out. nil is returned on success.

Device information update callback

API description

/// Device information update or device rediscovered on a different channel
/// @param service Search instance
/// @param type Network configuration type
/// @param device Device model
- (void)activatorService:(id<ThingSmartActivatorSearchProtocol>)service
            activatorType:(ThingSmartActivatorTypeModel *)type
           didUpdateDevice:(ThingSmartActivatorDeviceModel *)device;

Parameter description

Parameters Description
service The pairing service.
type The pairing type. ThingSmartActivatorTypeEZModel is returned.
device The updated device information.

Error codes

ThingSmartActivatorErrorModel is returned if pairing fails or times out.

@interface ThingSmartActivatorErrorModel : NSObject
@property (nonatomic, strong) ThingSmartActivatorDeviceModel *deviceModel;
@property (nonatomic) NSError *error;
@end

ThingSmartActivatorDiscoveryError includes the definition of error codes. The following table lists the common error codes.

Error codes Description
ThingSmartActivatorDiscoveryErrorTimeout Pairing timeout.
ThingSmartActivatorDiscoveryErrorDeviceAlreadyBound Strong binding error. The device is already bound with a user. Pairing can work only after the device is unbound from the current user.
ThingSmartActivatorDiscoveryErrorAPPUnsupportProduct The app used for pairing is not bound with the product.
ThingSmartActivatorDiscoveryErrorTokenExpired Token expired.
ThingSmartActivatorDiscoveryErrorGuestNotSupportStrongBind A guest account is not allowed to pair a device of strong binding.
ThingSmartActivatorDiscoveryErrorRemoteApiParamIllegal Invalid parameter.

Example

Swift:

class EZmodeConfigurationVC: UITableViewController {
    @IBOutlet weak var ssidTextField: UITextField!
    @IBOutlet weak var passwordTextField: UITextField!

    private var token: String = ""
    private var ezType:ThingSmartActivatorTypeEZModel = {
        let type = ThingSmartActivatorTypeEZModel()
        type.type = ThingSmartActivatorType.ezSearch
        type.typeName = NSStringFromThingSmartActivatorType(ThingSmartActivatorType.ezSearch)
        type.timeout = 120
        return type
    }()

    lazy var discovery: ThingSmartActivatorDiscovery = {
        let discovery = ThingSmartActivatorDiscovery()
        discovery.register(withActivatorList: [self.ezType])
        discovery.setupDelegate(self)
        discovery.loadConfig()
        return discovery
    }()

    private func startConfiguration() {
        guard let homeID = Home.current?.homeId else { return }
        SVProgressHUD.show(withStatus: NSLocalizedString("Requesting for Token", comment: ""))

        ThingSmartActivator.sharedInstance()?.getTokenWithHomeId(homeID, success: { [weak self] (token) in
            guard let self = self else { return }
            self.token = token ?? ""
            self.startConfiguration(with: self.token)
        }, failure: { (error) in
            let errorMessage = error?.localizedDescription ?? ""
            SVProgressHUD.showError(withStatus: errorMessage)
        })
    }

    private func startConfiguration(with token: String) {
        SVProgressHUD.show(withStatus: NSLocalizedString("Configuring", comment: ""))
        guard let homeID = Home.current?.homeId else { return }
        let ssid = ssidTextField.text ?? ""
        let password = passwordTextField.text ?? ""
        ezType.ssid = ssid
        ezType.password = password
        ezType.token = self.token
        ezType.spaceId = homeID
        discovery.startSearch([ezType])
    }

    func stopConfigWifi() {
        if !isSuccess {
            SVProgressHUD.dismiss()
        }
        discovery.stopSearch([self.typeModel], clearCache: true)
        discovery.removeDelegate(self)
    }
}

extension EZmodeConfigurationVC: ThingSmartActivatorSearchDelegate {

    func activatorService(_ service: ThingSmartActivatorSearchProtocol, activatorType type: ThingSmartActivatorTypeModel, didFindDevice device: ThingSmartActivatorDeviceModel?, error errorModel: ThingSmartActivatorErrorModel?) {
        if (errorModel != nil) {
            // Error
            SVProgressHUD.showError(withStatus: errorModel?.error.localizedDescription)
            return
        }

        if (device != nil) {
            if device?.step == ThingActivatorStep.found {
                // device find
            }
        }
    }

    func activatorService(_ service: ThingSmartActivatorSearchProtocol, activatorType type: ThingSmartActivatorTypeModel, didUpdateDevice device: ThingSmartActivatorDeviceModel) {
        if device.step == ThingActivatorStep.intialized {
            // Success
            let name = device.name
            SVProgressHUD.showSuccess(withStatus: NSLocalizedString("Successfully Added \(name)", comment: "Successfully added one device."))
            isSuccess = true
            navigationController?.popViewController(animated: true)
        }
    }

}

Objective-C:

/// Get token
- (void)getToken {
    ThingSmartActivator *ezActivator = [[ThingSmartActivator alloc] init];
    [ezActivator getTokenWithHomeId:homeId success:^(NSString *token) {
        NSLog(@"getToken success: %@", token);
        [self startConfigWiFi:token];
    } failure:^(NSError *error) {
        NSLog(@"getToken failure: %@", error.localizedDescription);
    }];
}

/// Start config
- (void)startConfigWifi:(NSString *)token {
  ThingSmartActivatorTypeEZModel *ezModel  = [[ThingSmartActivatorTypeEZModel alloc] init];
  ezModel.type = ThingSmartActivatorTypeEZSearch;
  ezModel.typeName = NSStringFromThingSmartActivatorType(ThingSmartActivatorTypeEZSearch);
  ezModel.timeout = 120;
  ezModel.ssid = ssid;
  ezModel.password = password;
  ezModel.token = token;
  ezModel.spaceId = homeId;

  [self.discovery registerWithActivatorList:@[ezModel]];
  [self.discovery setupDelegate:self];

  [self.discovery startSearch:@[ezModel]];
}

- (void)activatorService:(id<ThingSmartActivatorSearchProtocol>)service activatorType:(ThingSmartActivatorTypeModel *)type didFindDevice:(ThingSmartActivatorDeviceModel *)device error:(ThingSmartActivatorErrorModel *)errorModel {

    if (errorModel) {
        [self _connectWifiError:errorModel];
        return;
    }

    if (device) {
        [self _handleDevice:device];
    }
}

- (void)activatorService:(id<ThingSmartActivatorSearchProtocol>)service activatorType:(ThingSmartActivatorTypeModel *)type didUpdateDevice:(ThingSmartActivatorDeviceModel *)device {
    if (device) {
        [self _handleDevice:device];
    }
}

- (void)_handleDevice:(ThingSmartActivatorDeviceModel *)device {
    ThingActivatorStep step = device.step;

    if (step == ThingActivatorStepFound) {
      // discovery device
    } else if (step == ThingActivatorStepRegisted) {
      // device registe
    } else if (step == ThingActivatorStepIntialized) {
        /// activated successfully
    }
}

- (ThingSmartActivatorDiscovery *)discovery {
    if (!_discovery) {
        _discovery = [[ThingSmartActivatorDiscovery alloc] init];
    }
    return _discovery;
}