nRF5 SDK for Mesh v4.0.0
Simple OnOff model

The Mesh Model Specification specifies a Generic OnOff Model to be used in real applications with the mesh. This vendor-specific model is a simplified version of the Generic OnOff Model. It is an introductory example for Creating new models, but you can also use it in your applications.

See the following sections for information about how to implement a vendor-specific Simple OnOff model that turns something On or Off, for example a light bulb, a heater, or a washing machine.

Note
For brevity, some important features such as error handling are not discussed on this page. When writing your application, check the error codes returned by all API functions to avoid bugs in your application.

Table of contents

You can check the complete model implementation and its layout in the models/vendor/simple_on_off directory.

If you want to see this model integrated into a complete application, take a look at the Light switch example and at the examples/light_switch directory.


Properties and features

A mesh application is specified using a client-server architecture, where client and server models use publish and subscribe mechanism to communicate with each other. For this reason, the intended functionality of this model will be realized using two parts:

When the server model receives a GET or a (reliable) SET message from a client model, it sends the current value of the OnOff state as response. This keeps the client up-to-date about the server state.

For more details about setting up publication and subscription, see Creating new models.

Supported opcodes

The following table shows the opcodes that are supported by this model.

Name Definition Opcode Description Parameter Parameter size
SET SIMPLE_ON_OFF_OPCODE_SET 0xc1 Sets the current on/off state New state 1 byte
GET SIMPLE_ON_OFF_OPCODE_GET 0xc2 Gets the current on/off state N/A No parameter
SET UNRELIABLE SIMPLE_ON_OFF_OPCODE_SET_UNRELIABLE 0xc3 Sets the current on/off state New state 1 byte
Status SIMPLE_ON_OFF_OPCODE_STATUS 0xc4 Contains the current state Current state 1 byte

The opcodes sent on-air are three bytes for the vendor-specific models. The complete opcode is the combination of the vendor-specific opcode and the company identifier. For more information, see the access_opcode_t documentation.

Identifiers

For this model, the following identifiers are used.

Description Value
Company identifier 0x0059
Server identifier 0x0000
Client identifier 0x0001

The company identifier used in this table is Nordic Semiconductor's assigned Bluetooth company ID. In a real application, use your own company's assigned ID.


Implementing the model

As described earlier, a model comprises of two entities that together implement the complete behavior:

Implement both the server and the client models for the Simple OnOff model to work.

Implementing the server model

The behavior of the simple OnOff server is illustrated by the following message sequence chart.

simple_on_off_model.png
Simple OnOff behavior

When the OnOff server receives SET and GET messages:

To implement the server model:

  1. Define a model context structure that contains pointers to the callback functions. This context structure gets passed to all message handlers.
  2. Define the opcodes and create the necessary opcode handler functions to handle the incoming messages for the server model.
  3. Implement the reply_status() function.
  4. Implement the simple_on_off_server_status_publish() function.
  5. Ensure the specified opcode and company ID are linked to the corresponding handler function in the specified opcode handler lookup table.
  6. Put the model together in an initialization function.

You now have the basic skeleton of a simple OnOff server model, which can be expanded or tweaked to produce more complex server models. See models/vendor/simple_on_off/ for the complete code of this model.

Implementing the client model

The client model is used to interact with the corresponding server model. It sends SET and GET messages and processes incoming status replies. The client model sends messages using a publish mechanism. It uses assigned publication address as the destination for outgoing messages.

Just as in the server implementation, the client needs a context structure to keep information about callbacks and its model handle. In addition, a boolean variable is used to keep track of whether a transaction is currently active and to prevent running multiple simultaneous transactions.

Note
In a mesh network, messages may be delivered out of order, or may not be delivered at all. For this reason, a client must perform only one transaction at a time with its corresponding server.

The client model uses a callback function to provide information about the state of the server to the user application. If the server does not reply within a given time frame, it will notify the user application with the error code SIMPLE_ON_OFF_STATUS_ERROR_NO_REPLY.

The following code snippet shows the status codes (simple_on_off_status_t), the context structure (simple_on_off_client_t), and associated callbacks required for this model:

To implement the client model:

  1. Define the message type the client model will send by choosing one of the following:
  2. Create the API functions for the user application to send GET and SET messages. The following snippet defines these functions:
    uint32_t simple_on_off_client_set(simple_on_off_client_t * p_client, bool on_off)
    {
    if (p_client == NULL || p_client->status_cb == NULL)
    {
    return NRF_ERROR_NULL;
    }
    else if (p_client->state.reliable_transfer_active)
    {
    return NRF_ERROR_INVALID_STATE;
    }
    p_client->state.data.on_off = on_off ? 1 : 0;
    p_client->state.data.tid = m_tid++;
    uint32_t status = send_reliable_message(p_client,
    (const uint8_t *)&p_client->state.data,
    if (status == NRF_SUCCESS)
    {
    p_client->state.reliable_transfer_active = true;
    }
    return status;
    }
    uint32_t simple_on_off_client_set_unreliable(simple_on_off_client_t * p_client, bool on_off, uint8_t repeats)
    {
    set_unreliable.on_off = on_off ? 1 : 0;
    set_unreliable.tid = m_tid++;
    message.p_buffer = (const uint8_t*) &set_unreliable;
    message.length = sizeof(set_unreliable);
    message.force_segmented = false;
    uint32_t status = NRF_SUCCESS;
    for (uint8_t i = 0; i < repeats; ++i)
    {
    status = access_model_publish(p_client->model_handle, &message);
    if (status != NRF_SUCCESS)
    {
    break;
    }
    }
    return status;
    }
    uint32_t simple_on_off_client_get(simple_on_off_client_t * p_client)
    {
    if (p_client == NULL || p_client->status_cb == NULL)
    {
    return NRF_ERROR_NULL;
    }
    else if (p_client->state.reliable_transfer_active)
    {
    return NRF_ERROR_INVALID_STATE;
    }
    uint32_t status = send_reliable_message(p_client,
    NULL,
    0);
    if (status == NRF_SUCCESS)
    {
    p_client->state.reliable_transfer_active = true;
    }
    return status;
    }
  3. Add an opcode handler for the SIMPLE_ON_OFF_OPCODE_STATUS opcode to process the reply message.
  4. Provide callback for supporting periodic publication.
    • To support publishing features, a model must provide publish_timeout_cb. This callback will be called by the publish mechanism if the provisioner configures periodic publishing.
    • The following snippet shows the implementation of the periodic publishing callback. In this implementation, the client model's periodic publish timeout callback calls the user-specified callback.
      static void handle_publish_timeout(access_model_handle_t handle, void * p_args)
      {
      simple_on_off_client_t * p_client = p_args;
      if (p_client->timeout_cb != NULL)
      {
      p_client->timeout_cb(handle, p_args);
      }
      }
  5. Initialize the client model.

The client model is now implemented. You can now use it to turn something On or Off by communicating with the server node.


Documentation feedback | Developer Zone | Subscribe | Updated