Generating Messages

Each stage in the device model has a Sender and a receiver function. The sender function is used to send outbound messages to an external server. It is where we generate payloads depending on the device logic and send them to your backend. The sender function must return a payload which will be passed on to the server. Let's take a look at some use cases and functions you may come across while working with a sender function.

Getting the current iteration

When the template is running, it might be required to do some actions based on a specific iteration, For example, for every 10th call, you would like to send a special message. Simply call the index() function to find out which iteration you are currently in. The iterations start from 0 and continue up to the number of iterations you have specified in the run settings tab.

{
    if (index() == 0 ) {
        return "This is the first iteration"
    }  
    if (index() % 10 == 0 ) {
        return "Special Message at every 10th iteration"
    }
    if (index() % 2 == 0 ) {
        return "Special Message at every even iteration"
    }   
    var randomIteration = Math.floor(Math.random()*100);
    
    if (index() == random ) {
        return "This is a random message triggered one time in 100 iteration"
    }      
    
    return "Normal message";
}

Knowing the client ID

If you are simulating more than 1 client, you could find the current client ID in the template by accessing the client() function. This returns an integer starting from 0 and going up to the maximum number of clients specified. If you have passed a client offset while running the simulation, that offset will be added to the client.

{
    if (client() === 0 ) {
        return "I am the leader with ID 0"
    }
    return "I am the follower with id "+ client();
}

A combination of the client() and index() functions could be used to create some complex scenarios. For example:

{
    if ( (client() % 3 == 0) and (index() %5 == 0) ) {
        return "I am a rogue client"
    }
    else { 
        return "I am a good client"
    }
}

In the above case, every third client on every 5th iteration will send a rogue message while others will send a good message. The behaviour could also be changed dynamically by using glob keys.

Logging

You can call console.log() or console.error() anywhere in the function. The output for this would be saved in the results and can be seen in the Logs tab under results. Note that other console functions such as console.warn() are not captured and will not be displayed to the user.

{
    console.log("This is a log", state.myvariable);
    console.error("This is an error")
}

Generating Payload

The device model will eventually generate a payload to be sent to the cloud platform. This could be a string or the sender function could also return a binary payload. This is really helpful when dealing with TCP/UDP payload types. For example, let's create a raw payload and send it as a Buffer.

{ 
  state.content = [0x62, 0x75, 0x66, 0x66, 0x65, 0x72];
  state.content.push(0);

  return Buffer.from(state.content);
}

This will result in the following hex content being sent to the server

62 75 66 66 65 72 00

You can also generate a JSON payload to be sent at the end of the iteration.

{
    var message = {
        device: "Light_RGB",
        id: client(),
        brightness: state.brightness,
        r_value: state.r_value,
        g_value: state.g_value,
        b_value: state.b_value,
        status: "ON",
      };
    
    return JSON.stringify(message, null, 2);
}

This will send a payload which looks like the JSON object below:

{
    device: "Light_RGB",
    id: 99,
    brightness: 45,
    r_value: 230,
    g_value: 230,
    b_value: 250,
    status: "ON",
}

Skipping message sending

It is important that at the end of processing, the function body must return a value to be sent to the cloud platform. The return value could either be a string or a Node.js binary Buffer object, depending upon what values are accepted by your cloud platform provider. If you would like to skip sending anything for that particular iteration, simply call the skip() helper function. This will cause the current payload to be skipped from being sent to the cloud platform.

{ 
  if (index() == 2){
    skip(); // This will cause payload sending to be skipped
  }
  
  return JSON.stringify(state, null, 2);
}

When a skip call is encountered by our back-end simulation engine, the message-sending part will be skipped for the client for that iteration, even though a payload has been successfully generated. This helps in simplifying the code structure for the end user. Note that the skip() effect will be automatically cleared for the next iteration for the client. However, the iteration result will not be counted as a failure if the payload is skipped. If you want to explicitly mark the current client iteration as a failure, you could use the assert(false) function.

Last updated