# S4SensorKit Documentation

​ This set of SDK only supports the Bluetooth Sensor device produced by Minew, and is currently a industrial temperature and humidity sensor. The SDK can help developers handle all the work between mobile phones and Sensors, including: scanning devices, connecting devices, writing data to devices, receiving data from devices, etc.

# Preliminary work

​ Overall framework: MTICentralManager is a device management class, which is always a singleton when the APP is running. MTIPeripheral is a device instance class. This suite will generate a MTIPeripheral instance for each device to facilitate monitoring and operating devices.

MTICentralManager : Device management class, which can scan the surrounding Sensor devices, and can connect them, verify them, etc.

MTIPeripheral : Device instance class. When MTICentralManager discovers a physical device, MTICentralManager will generate a MTIPeripheral instance, which corresponds to a physical device.

MTIFrameHandler : Device broadcast class, which can get the data when the device broadcasts.

MTConnectionHandler : Device connection class for receiving and sending data from the device.

MTISensorHandler:传感器操作类,进行设备的读写数据。

  • # Get started

    # Development environment:

    -Xcode10 +, the current SDK is compiled with Xcode15, please use Xcode10 and above for development; -iOS12.0, the minimum system version is iOS12;

# Import into the project::

  1. Manually

    • Copy the development kit files: MTIndustrialSensorKit.framework files to the project project directory, and then add them to the project.
  2. PS:

    1. !!! In iOS10 and above, Apple added permission restrictions on Bluetooth APi. You need to add a string to the project's info.plist file: Privacy-Bluetooth Peripheral Usage Description-"Your usage description".
    2. !!! In iOS13 and above, Apple added permission restrictions on Bluetooth APi. You need to add a string to the project's info.plist file: Privacy-Bluetooth Always Usage Description-"Your usage description".

# Start development

# Scanning equipment

​ First you need to get the singleton of MTICentralManager, then check the current Bluetooth status of the phone, and then you can scan the device.

// Get Manager singleton
MTICentralManagerV3 *manager = [MTICentralManagerV3 sharedInstance];

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    // The current state of the Bluetooth switch on the mobile phone
    if(self->manager.status == PowerStatePoweredOn) {
        // start device scan
        [manager startScan:^(NSArray<MTIPeripheral *> *peripherals) {
          //According to the type of broadcast attribute, the required sensor type can be filtered.
        	self->deviceAry = peripherals;
    	}];
    }
});
// Scanned devices can also be obtained using manager.scannedPeris
// If you need to respond to the Bluetooth status of your phone. Please listen for the callback.
[manager didChangesBluetoothStatus:^(PowerState status){
    
    switch(status) {
        case PowerStatePoweredOn:
            NSLog(@"bluetooth status change to poweron");
            break;
        case PowerStatePoweredOff:
            NSLog(@"bluetooth status change to poweroff");
            break;
        case PowerStateUnknown:
            NSLog(@"bluetooth status change to unknown");
    }
}];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

PS: The entire SDK works only when the Bluetooth state of the phone is in Poweron.

# Connect to device
// The scanned device can be obtained from the previous step
MTIPeripheralV3 *device = deviceAry[0];
// Connect the device
[manager connectToPeriperal:device SecretKey:@"Device's secretKey"];
// Listen for device connection status.
[p.connector didChangeConnection:^(Connection connection) {
    if (connection == Vaildated) {
      	// Successful verification, successfully connected to the device
        NSLog(@"vaildated");
      	//Need to write a password, perform other operations after the password is verified successfully
    }
    if (connection == Disconnected) {
        NSLog(@"device has disconnected.");
    }
}];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# Frame Type


    MTIFrame *frame = device.frameHandler.advFrames[0];
    if (frame.frameType == MTIFrameDeviceInfo) {
            MTIDeviceInfoFrame *deviceInfoFrame = (MTIDeviceInfoFrame *)frame;
        
        } else if (frame.frameType == MTSModelTypeDoorContactByte) {  // 门磁状态帧
            
            MTIHeaderByteFrame *coordinateFrame = (MTIHeaderByteFrame *)frame;
            
            NSString *text1  = [NSString stringWithFormat:@"%@", tempHumiFrame.doorSensorAlarmStatus? @"open" : @"close";
            NSString *text2 = tempHumiFrame.tamperProofAlarmStatus ? @"Tamper Status: 01 Triggered" : @" Tamper Status: 00 Normal";
            NSLog(@":%@\t%@", text1, text2);
            
        }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# Other command operations

Continuing from the previous step, when the device successfully verifies that the written secretKey is correct, other command operations can be performed.

The following operations are in no particular order and can be selected by yourself.

# Reset Bluetooth to factory settings
    /// Reset Bluetooth to factory settings
    [device.connector.radarSensorHandler resetDevice:^(BOOL success) {
        
        if (success){
            // disconnect Bluetooth after success
            [[MTICentralManager sharedInstance] disconnectFromPeriperal:self->device];
        }else{
        
            NSLog(@"failed");
        }
    }];
    
1
2
3
4
5
6
7
8
9
10
11
12
# Get the broadcast parameters for the device information frame
    /// Get the device information frame broadcast parameters
    /// @param completionHandler the receive block.
    [device.connector.sensorHandler  getDeviceInfoFrameAdvertisingParameters:^(BOOL success, MTIAdvertisingParametersData * _Nonnull data) {

        if (success) {
            NSLog(@"Information Frame Type: %@, Broadcast Interval: %ld, Broadcast Power: %d, Continuous Broadcast: %@", data.frameType == MTIFrameDeviceInfo ? @"Device Information Frame": @"Temperature and humidity frame", data.advertisingInterval, data.txPower, data.isAlwaysAdvertising == YES ? @"Yes":@"No");
        }
    }];
1
2
3
4
5
6
7
8
# Set the broadcast parameters for device information frames

Note that the value of broadcast power can only be set -40, -20, -16, -12, -8, -4, 0, 4。

    int interval = 100; // unit is ms.
    int txpower = 4;
    
    /// Set device information frame broadcast parameters
    /// @param advertisingInterval Broadcast interval in milliseconds
    /// @param txPower -40 -20 -16 -12 -8 -4 0 4dBm
    /// @param completionHandler the receive block.
    [device.connector.sensorHandler setDeviceInfoFrameAdvertisingParametersConfiguration:interval TxPower:txpower CompletionHandle:^(BOOL success) {
        if (success) {
            NSLog(@"Setting deviceInfo frame configuration parameters successfully");

        } else {
            NSLog(@"Setting deviceInfo frame configuration parameters failed");

        }
    }];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Retrieve mode parameter configuration
/// Get doorControl sensor's configuration
/// @param completionHandler the receive block.

    [device.connector.sensorHandler getIndustryHTFrameAdvertisingParameters:^(BOOL success, MTIAdvertisingParametersData *data) {
        
        
        if (success) {
                NSLog(@"Advertising type:\t%@", data.isAlwaysAdvertising ? @"常规模式" : @"Energy-saving");
                
            NSLog(@"Broadcast Interval: %ld,Continuous Broadcast: %d", data.advertisingInterval, data.txPower);
        }
    }];

1
2
3
4
5
6
7
8
9
10
11
12
13
/// Get Energy-saving Mode sensor's configuration
/// @param completionHandler the receive block.

    [device.connector.sensorHandler getDoorcontrolTriggerConfiguration:^(BOOL success, MTIAdvertisingParametersData *data) {
        
        
        if (success) {
                
            NSLog(@"Broadcast Interval: %ld, Continuous Broadcast: %d,Broadcast Interval:%@", data.txPower, data.advertisingInterval, data.timeValues);
        }
    }];

1
2
3
4
5
6
7
8
9
10
11
12
# Set regular mode parameter configuration
/// Set Regular Mode sensor configuration
/// @param completionHandler the receive block.
    [device.connector.sensorHandler  setDoorcontrolFrameAdvertisingParametersConfiguration:interval TxPower:txpower alwaysD:self.isAlwaysAdvertising CompletionHandle:^(BOOL success) {
        if (success) {
          
        } else {
          
        }
    }];


1
2
3
4
5
6
7
8
9
10
11
# Set power-saving mode parameter configuration
/// Set Energy-saving sensor configuration
/// @param completionHandler the receive block.

// note:First, switch to power-saving mode!
    self.isAlwaysAdvertising = false;
    
    [device.connector.sensorHandler  setDoorcontrolFrameAdvertisingParametersConfiguration:interval TxPower:txpower alwaysD: CompletionHandle:^(BOOL success) {
        if (success) {
          
              [device.connector.sensorHandler setDoorContactHTFrameAdvertisingParametersConfiguration:interval TxPower:txpower TimeValue:timeValue CompletionHandle:^(BOOL success) {
            
                    if (success) {
                      
                    } else {
                      
                    }
            
             }];
          
        } else {
         
        }
    }];



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# Store switch && Retrieve door opening light effect

[device.connector.sensorHandler getDoorContactOptionSwitch:^(BOOL optionSwitch1, BOOL optionSwitch2) {

    NSLog(@"Store switch:\t%d\tRetrieve door opening :\t%d",data.isAlwaysAdvertising ? optionSwitch1, optionSwitch2);
    
 }];

1
2
3
4
5
6
7
# Set storage switch

[device.connector.sensorHandler setDoorContactDataOptionSwitch:selectOrNo withReceiceResultHandler:^(BOOL success){

         if (success) {
          
        } else {
         
        }
        
 }];
 
1
2
3
4
5
6
7
8
9
10
11
# Set door opening light effect
 [device.connector.sensorHandler setDoorContactOptionSwitch:selectOrNo withReceiceResultHandler:^(BOOL success){

         if (success) {
          
        } else {
         
        }
    
 }];

1
2
3
4
5
6
7
8
9
10
# Query the time periods during the day when the device remains operational
    [device.connector.sensorHandler getWorkPeriodsConfiguration:^(BOOL success, NSInteger totalNum, NSArray<MTIDoorContactTimeListData *> * _Nonnull data) {
 
        if (success) {
        }
        
    }];

1
2
3
4
5
6
7
# Set the time periods during the day when the device remains operational

NSMutableArray<MTIDoorContactTimeListData *> *modelArray = [NSMutableArray array];
 [device.connector.sensorHandler setWorkPeriodsConfiguration:[modelArray mutableCopy] withHandlerCompletion:^(BOOL success) {
        
        if (success) {
            
        }

    }];

1
2
3
4
5
6
7
8
9
10
# Retrieve historical data by time period
      
      [device.connector.sensorHandler readDoorContactHistoryWithDateFormatter:formatter Unit:MTICelsius StartTimeInterval:timeStamp EndTimeInterval:endtimeStamp SystemTimeInterval:[[NSDate new] timeIntervalSince1970] DeviceHTModelType:1 completionHandler:^(BOOL success, NSInteger totalNum, NSArray<MTIDoorContactTimeListData *> * _Nonnull data) {
            
        if (success) {
        
          NSLog(@"%ld\t\t%@",totalNum,data);
        } 
          
    }];

1
2
3
4
5
6
7
8
9
10
# ##### Fireware update
    // ⚠️Note: The ota upgrade package that comes with the demo may not match the current device. Please use the matching firmware upgrade package to perform the ota upgrade after communicating with the business according to the hardware and firmware information of the device at hand. If you use the wrong firmware update package, this may make your device unusable.
		// It is not feasible to distinguish whether the firmware upgrade package matches the device only by looking at the s3 s4 keywords, because the firmware version and hardware version of the device with different factory settings may not match, so be sure to confirm that the firmware upgrade package is correct.
   
    NSData *otaPacketData = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"S3V2_NV900_20210312_s3_ota_v1_0_23" ofType:@".bin"]];
    

    /// ota device by using this method, input  firmware data, then start ota, get statusChange in stateHandler, get firmware file upload progress in progressHandler, get error in errorHandler
    /// @param originOtaData data of ota
    /// @param stateHandler listen status change, only "Completed" means ota successfully.
    /// @param progressHandler listen file uploading progress
    /// @param errorHandler listen errors in ota stage
    [device.connector startOTAWithOTAData:otaPacketData stateHandler:^(OTAState state) {
        if (state == OTAStateStarting) {
            NSLog(@"ota start");
        } else if(state == OTAStateUploading) {
            NSLog(@"ota uploading");
        } else if(state == OTAStateAborted) {
            NSLog(@"ota aborted");
        } else if(state == OTAStateDisconnecting) {
            NSLog(@"ota disconnect");
        } else if (state == OTAStateCompleted) {
            NSLog(@"ota successfully");
        } else if(state == OTAStateFailed) {
            NSLog(@"ota failed");
        }
    } progressHandler:^(float progress) {
        NSLog(@"ota progress:%f", progress);
    } errorHandler:^(NSError * _Nonnull error) {
        NSLog(@"ota  failed,error:%@",error);
    }];
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30

# Precautions

  1. Writing multiple instructions at the same time may cause an exception. It is recommended to write a new instruction after each instruction is completed.

# Documentation version record

  • 2024.09.23 v1.0 first version;
Last Updated:: 9/24/2024, 10:34:25 AM