Manage the Pairing Code

There are two ways to activate the miuPanel module on a new smartphone.
The first procedure, presented in the getting started section  requires that the smartphone have to be near to the module.

The second procedure, explaned here, makes possible to activate the module on a new remote smartphone without the need for the smartphone to be near to the module during this procedure. In other words, you can share the control of the system with a friend located on the other side of the world.

What you need is a password, called pairing code, to enter on the new phone. Few second after the pressing of the button “Add New Module”, the App will ask a “pairing code”, as shows the following image:

The pairing code is a password that you can generate and manage through two module serial commands:

How you can see, the PCODE:SET command require two parameters used to generate the pairing code: the “seed” (which will become a part of the pairing code) and the “number of valid uses” of that pairing code.

If you want to enable a fixed pairing code for the entire useful life of the project, simply send these commands to the module only once, at project stage, without providing for specific firmware management.

On the contrary, if you want to manage the pairing code of the module after the project phase, it’s good to think about its management in the firmware (for example, through a panel accessible to the system administrators only).

Here we propose a sample panel that can be integrated into the application to manage directly the pairing code from the App. The layout of the panel we propose is:

Using the Online Panel Simulator we built this HCTML string:

D!EEE;-0{!356^m%100,y8T*20:Remote Pairing Code;}{m^%100,y8!FFF#356M1:Display Log;}{%95,y5}{^{<%80,y5#666T:SEED: Enter a number of 12-Digit;|>M2#f00:;}_{E1!FFF%80,8*12fb:;}_{%95,y2}{<%80,y5T#666:N: Enter number of uses [1-100];|>M3#f00:;}_{E2!FFF%80,8*12fb:;}_{%95,y5}_{mB1%50,y6!FFF,888:SET PCODE;}}/20{%100,y1!FFF}/20{mB2%50,y6!FFF,888:GET STATUS;}/20{%100,y1!FFF}/20{mB3%50,y6!FFF,888:DISABLE PCODE;}/20{%100,y1!FFF}

Arduino UNO sketch

String Msg;
String seed_str = "";
String n_uses_str = "";
String str_tmp = "";     // generic string variable for temporary use
unsigned char flag_seed_ok = 0;
unsigned char flag_n_uses_ok = 0;

void setup(){
  Serial.begin(57600); // Initialise serial
  delay(5000);                
  SendPanel();        // Send The Panel calling a function
}

void loop(){
  int c;
  int int1 = 0;

  while ((c = Serial.read()) > '\n') Msg += (char) c;  // Read incoming chars, if any, until new line
  if (c == '\n'){                                      // is the message complete?    
    // -------------------------------------------
    if (Msg.substring(0, 4).equals("#E1:")){ // SEED
      seed_str = Msg.substring(4);      
      if (seed_str.length() == 12 && IsNumber(seed_str) == true){ // Check number length (must be 12 digit)  
          Serial.println(F("#M2OK"));
          flag_seed_ok = 1;
      }
      else{
          Serial.println(F("#M2Error"));
          flag_seed_ok = 0; 
      }
    }
    // -------------------------------------------
    else if (Msg.substring(0, 4).equals("#E2:")){ // NUMBER OF USES
      n_uses_str = Msg.substring(4);
      if (IsNumber(n_uses_str) == true && n_uses_str.toInt() > 0 && n_uses_str.toInt() < 1000){ 
        Serial.println(F("#M3OK"));
        flag_n_uses_ok = 1;
      }
      else{ // error seed
        Serial.println(F("#M3Error"));
        flag_n_uses_ok = 0;
      }
    }
    // -------------------------------------------
    else if (Msg.equals("#B1P")){ // Pressed "SET PCODE"
      if (flag_seed_ok == 1 && flag_n_uses_ok == 1){
        Serial.print(F("$CLOUD PCODE:SET:"));
        Serial.print(seed_str);
        Serial.write(':');
        Serial.println(n_uses_str);
      }
    }
    // -------------------------------------------    
    else if (Msg.equals("#B2P")) // Pressed "GET STATUS"
    {
      Serial.println(F("$CLOUD PCODE:GET:"));
    }
    // -------------------------------------------    
    else if (Msg.equals("#B3P")){ // Pressed "GET STATUS"
      Serial.println(F("$CLOUD PCODE:SET:")); // Disable code
    }
    // -------------------------------------------    
    else if (Msg.substring(0, 17).equals("$CLOUD:PCODE-SET:")){ // Reply from cloud
      int1 = Msg.indexOf("(Pairing-Pin"); 
      if (int1 >= 0){ // String found
        Serial.print("#M1");
        Serial.println(Msg.substring(int1)); 
      }  
      else{
        Serial.println("#M1CLOUD:PCODE-SET: -Unknown Reply-");
      }   
    }
    // -------------------------------------------    
    else if (Msg.substring(0, 17).equals("$CLOUD:PCODE-GET:")){ // Reply from cloud
      if (Msg.substring(17) == "::0:0"){
       Serial.println("#M1 None pairing code"); 
      }
      else{
        //Serial.print("#M1");
        //Serial.println(Msg);

        Serial.print("#M1Status: ACTIVE --- Num. valid uses: ");

        int start_i = Msg.indexOf(':', 29); 
        int stop_i = Msg.indexOf(':', 30);        
        Serial.print(Msg.substring(start_i +1, stop_i));

        Serial.print(" --- Errors: ");       
        start_i = Msg.indexOf(':',stop_i);       
        Serial.println(Msg.substring(start_i +1));
      }
    }
    // -------------------------------------------
    // WiFi Module unwanted RESET >>>>> send panel again
    else if (Msg.equals("$ERR-CLOUD")){
      Serial.println("#M1ERROR CLOUD: Connect via CLOUD!");
    }    
    // -------------------------------------------
    // WiFi Module unwanted RESET >>>>> send panel again
    else if (Msg.equals("$RES")){
      SendPanel();
    }
    Msg = "";
  }
} // END Loop
//----------------------------------------------------------------
//---------------------------  FUNCTIONS -------------------------
//----------------------------------------------------------------
void SendPanel(void){

  // Discharge old partial messages and send panel
  Serial.println("");

  //Send Panel slit in more serial print
  Serial.print  (F("$P:D!EEE;-0{!356^m%100,y8T*20:Remote Pairing Code;}{m^%100,y8!FFF#356M1:;}{%95,y5}"));
  Serial.print  (F("{^{<%80,y5#666T:SEED: Enter a number of 12-Digit;|>M2#f00:;}_{E1!FFF%80,8*12fb:;}_{%95,y2}"));
  Serial.print  (F("{<%80,y5T#666:N: Enter number of uses [1-100];|>M3#f00:;}_{E2!FFF%80,8*12fb:;}_{%95,y5}_"));
  Serial.print  (F("{mB1%50,y6!FFF,888:SET PCODE;}}/20{%100,y1!FFF}/20{mB2%50,y6!FFF,888:GET STATUS;}/20{%100,y1!FFF}"));
  Serial.println(F("/20{mB3%50,y6!FFF,888:DISABLE PCODE;}/20{%100,y1!FFF}"));
}
//----------------------------------------------------------------

// Check if a string contains a number

boolean IsNumber(String str){
  boolean result = true;
  int str_length = str.length();   
   for(int i=0; i <str_length;  i++)
   {
      if(!isDigit(str.charAt(i))) result = false;
   }
   return result;
}