[SOLVED] Best Protocol for Cellular Gateway

I am using a Particle.io Electron as a gateway for many end nodes. I was wondering if anyone had a best practice or preferred method to get the data to Ubidots using the least amount of data possible.

It has to be a cellular deployment, so my goal is to be as efficient as possible.

Thanks!

Hi @Backpacker87

For cellular devices –such as the Particle Electron, where data consumption needs to looked at and care for, the two most data efficient protocol are Particle webhooks and TCP.
You can use Ubidots library for Particle devices. It supports both of the aforementioned protocols.
Some considerations to keep in mind:

  1. Using TCP and Ubidots library will allow you, if you choose so, to send each node data as single devices to Ubidots.
  2. On the other hand, connecting through webhooks would force you –given the Electron acts as a gateway to send all data from the nodes to a single device in Ubidots.
  3. Using webhooks makes data more secure as it is encrypted. Ubidots library when TCP is selected sends the data in plain text

I hope all of this makes sense.

–David

@dsr,

Perfect answer, thank you!

@dsr,

I definitely want to send each nodes data as a single device. So if I have 5 nodes with 3 variables each. I would like Ubidots to have 5 devices and each one has their respective 3 variables.

In order to tell the difference between the nodes I want to use the unique MAC (originally received in decimal format like this: 5526146528751682 from the Xbee radios to determine which device should be targeted for sending to Ubidots.

Each node uses a Xbee radio which have a unique MAC printed on them which is represented in HEX like this 0013A20040D2B042. However, when this value is received by the Electron it is in decimal format but I have to use the HEX format. I am struggling on how to convert the decimal back to hex then to a format that works for replacing the Electron device_label with this node ID so that it can be sent to the correct device in Ubidots. Any suggestions would be appreciated.

Hi there, it depends pretty much in the primitive variable type that stores the MAC, but the code below may serve you as reference to convert from HEX to a char array in C++

byte num_hex = 0x10;
char str[2];
sprintf(str, "%.2X", num_hex);

You may need to modify the byte based on the variable type that captures your MAC address.

All the best

Hey @Backpacker87,

To complement the idea presented by @jotathebest, here’s a function to convert from a const char* representing the MAC in decimal format to a char [] representing the MAC address in Hex format.

void decimalToHexa(char* mac_hexa, const char* mac_decimal) {
    uint8_t macDecimalLength = strlen(mac_decimal);
    sprintf(mac_hexa, "");
    char str[2];
    uint8_t number;
    for(uint8_t i = 0; i < macDecimalLength - 1; i+=2) {
        memcpy(str, mac_decimal + i, 2);
        number = atoi(str);
        sprintf(mac_hexa, "%s%.2X", mac_hexa, number);
    }
} 

For example:

const char* macDecimal = "5526146528751682";
uint8_t macDecimalLength = strlen(macDecimal);
char macHexa[macDecimalLength];
decimalToHexa(macHexa, macDecimal);

Serial.print("MAC in Hex format: ");
Serial.println(macHexa);

Output:
MAC in Hex format: 371A0E411C4B1052

–David

@jotathebest and @dsr thank you both for your response.

I have done more digging and it turns out the 64-bit MAC address of each end node arrives to the gateway as two separate uint32_t values (Msb and Lsb) of which Msb is the first part of the MAC and Lsb is the second. In order to recreate the MAC in its original HEX value I have two combine Msb and Lsb then go through the process you have shown. I have tried the following with no luck.

void loop() {
    xbee.readPacket();
    if (xbee.getResponse().isAvailable()){
        if (xbee.getResponse().getApiId() == ZB_IO_SAMPLE_RESPONSE) {
            xbee.getResponse().getZBRxIoSampleResponse(ioSample);

            uint32_t Msb = ioSample.getRemoteAddress64().getMsb();            
            uint32_t Lsb = ioSample.getRemoteAddress64().getLsb();
            char Msb_string[16] = "";
            char Lsb_string[16] = "";
            char myString[16] = "";
            sprintf(Msb_string, "%d",Msb);
            sprintf(Lsb_string, "%d",Lsb);
            strcpy(myString,Msb_string);
            strcat(myString,Lsb_string);
            const char* macDecimal = ((const char*)myString);
            uint8_t macDecimalLength = strlen(macDecimal);
            char macHexa[macDecimalLength];
            decimalToHexa(macHexa, macDecimal);
            int MPX = -1;
            int BATV = -1;;
            MPX = ioSample.getAnalog(2);
            BATV = ioSample.getAnalog(3);
            ubidots.add("MPX", MPX);
            ubidots.add("BATV", BATV);
            ubidots.send(macHexa);
        }
    }
}


void decimalToHexa(char* mac_hexa, const char* mac_decimal) {
    uint8_t macDecimalLength = strlen(mac_decimal);
    sprintf(mac_hexa, "");
    char str[2];
    uint8_t number;
    for(uint8_t i = 0; i < macDecimalLength - 1; i+=2) {
        memcpy(str, mac_decimal + i, 2);
        number = atoi(str);
        sprintf(mac_hexa, "%s%.2X", mac_hexa, number);
    }
}

Hi @Backpacker87,

I must say I made a mistake in my previous note and to avoid back and forth, the function mentioned in that message doesn’t do what we expect.
Now, under the light of this new information (perhaps would have been useful to share it before), I did another function which receives the MSB and LSB 32 bit unsigned integers, and a char* to store the Hexadecimal representation of the Xbee 64 bit MAC address:

void toHexString(uint32_t msb, uint32_t lsb, char* mac_hexa) {
    sprintf(mac_hexa, "");
    char* msbHexa = (char*) malloc(sizeof(char) * 8);
    char* lsbHexa = (char*) malloc(sizeof(char) * 8);
    uint32_t provisional; 
    for (uint8_t i = 0; i < 4; i++) {
        provisional = (msb >> (24 - (8 * i))) & 0xFF;
        sprintf(msbHexa, "%s%.2x", msbHexa, provisional);
        provisional = (lsb >> (24 - (8 * i))) & 0xFF;
        sprintf(lsbHexa, "%s%.2x", lsbHexa, provisional);
    }
    sprintf(mac_hexa, "%s%s", msbHexa, lsbHexa);
    free(msbHexa);
    free(lsbHexa);
}

For example:

uint32_t msb = 1286656; // For you it would be "uint32_t msb = ioSample.getRemoteAddress64().getMsb();"
uint32_t lsb = 1087549506; // For you it would be "ioSample.getRemoteAddress64().getLsb();"
char* macHexa  = (char*) malloc(sizeof(char) * 16);
toHexString(msb, lsb, macHexa2);
Serial.print("MAC in Hex format: ");
Serial.println(macHexa);

Output:

MAC in Hex format: 0013a20040d2b042

@dsr,

Thank you very much for your help. I apologize for not being more clear upfront.

@Backpacker87 did it worked well?

@dsr it worked but it was resulting in a heap fragmentation issue.

The final solution ended up being:

uint32_t msb = ioSample.getRemoteAddress64().getMsb();
uint32_t lsb = ioSample.getRemoteAddress64().getLsb();
char macHexa[17];
snprintf(macHexa, sizeof(macHexa), "%08X%08X", msb, lsb);

The above works great.

1 Like