AZ3166

Getting started with Azure and AZ3166

Overview of device

MXCHIP AZ3166 is a microcontroller unit(MCU) that aggregates most useful sensors (magnetometer, pressure, humidity, temperature, gyroscope, accelerometer) and peripherals(microphone, headphones, IR, WiFi, security chip) into one device with two programmable buttons.

The device is powered via Micro USB or battery holder via Micro:Bit. Maximum power consumption is around 5W(3,3V/1,5A).

IoT Devkit and my repo contain examples described below.

Interacting with IoT Hub via MQTT

Sending and receiving data from IoT Hub is realizing via DevKitMQTTClient.h library. This implementation of MQTT protocol is fast and robust interaction DevKit’s devices with IoT Hub. In the Arduino setup function, we have the possibility to add various functions, such as:

DevKitMQTTClient_Init(true);
DevKitMQTTClient_SetSendConfirmationCallback(sendConfirmationCallback);
DevKitMQTTClient_SetMessageCallback(messageCallback);
DevKitMQTTClient_SetDeviceTwinCallback(deviceTwinCallback);
DevKitMQTTClient_SetDeviceMethodCallback(deviceMethodCallback);

These functions work as event handlers. Passing an additional function into callback we receive an event which depends on the setup you took. By calling

DevKitMQTTClient_Init(true);

you’re able to use device twins. Normally function is called under the scope, so if you don’t need device twins, also omit this function.

Confirmation callback

Confirmation callbacks are the events that were sent by IoT Hub to notice device about status of data, e.g. confirmation of received data by IoT Hub. A sample implementation of this callback:

static void sendConfirmationCallback(IOTHUB_CLIENT_CONFIRMATION_RESULT result)
{
if (result == IOTHUB_CLIENT_CONFIRMATION_OK)
{
//call LED
}
}

Message callback

Message callback is the implementation of fire-and-forget pattern. IoT Hub sends messages to a device that we can handle in such a way:

static void messageCallback(const char *payLoad, int size)
{
char buff[MESSAGE_MAX_LEN];
snprintf(buff, MESSAGE_MAX_LEN, "%s", payLoad);
Screen.print(1, "Msg arrived:");
Screen.print(2, buff);
}

Device twin callback

Device twin callback contains information that stores in the cloud, such as metadata, configurations, and conditions. In most cases, you know remotely what’s going on with the device. To update state on the device you will create callback such as:

static void deviceTwinCallback(DEVICE_TWIN_UPDATE_STATE updateState, const unsigned char *payLoad, int size)
{
char *temp = (char *)malloc(size + 1);
if (temp == NULL)
{
return;
}
memcpy(temp, payLoad, size);
temp[size] = '\0';
parseTwinMessage(updateState, temp);
free(temp);
}

Device method callback

Device method callback calling functions from the cloud that you can execute on the device, e.g. change interval of messages or turn off sending messages as below.

int deviceMethodCallback(const char *methodName, const unsigned char *payload, int size, unsigned char **response, int *response_size)
{
LogInfo("Try to invoke method %s", methodName);
const char *responseMessage = "\"Successfully invoke device method\"";
int result = 200;
if (strcmp(methodName, "start") == 0)
{
message_sending = true;
}
else if (strcmp(methodName, "stop") == 0)
{
message_sending = false;
}
else
{
LogInfo("No method %s found", methodName);
responseMessage = "\"No method found\"";
result = 404;
}
*response_size = strlen(responseMessage);
*response = (unsigned char *)malloc(*response_size);
strncpy((char *)(*response), responseMessage, *response_size);
return result;
}

Generating and sending messages

To create an event that cloud will consume, call function:

DevKitMQTTClient_Event_Generate(messagePayload, MESSAGE);

It requires message payload which is serialized JSON. The payload cannot be null, so if you don’t need to send any information, just put into payload the empty string. The second parameter describes the type of event.

  • MESSAGE – any data that the device can send to the cloud, e.g temperature measurement.
  • STATE – state of the device’s components, e.g temperature sensor is on or off.

To send event we need to call function:

DevKitMQTTClient_SendEventInstance(message);

By wrapping everything together message generator will look like:

void sendToAzure()
{
// message_sending is for device method callbacks
// getInterval() describes interval for all sending messages(by default, message per 2 seconds)
if (message_sending && (int)(SystemTickCounterRead() - send_interval_ms) >= getInterval())
{
// create serialized JSON and fill message payload
readMessage(messageCount++, messagePayload);
EVENT_INSTANCE *message = DevKitMQTTClient_Event_Generate(messagePayload, MESSAGE);
DevKitMQTTClient_SendEventInstance(message);
send_interval_ms = SystemTickCounterRead();
}
else
{
DevKitMQTTClient_Check(); //if sending a message will take more than 5 sec check that device is connected to IoT Hub, otherwise, do nothing.
}
}

Generating and sending states

To create state we need only one function to call:

DevKitMQTTClient_ReportState(state);

A sample implementation of state generator of the device:

char state[500];
// motion describes the state of sensor motion(on or off)
snprintf(state, 500, "{\"firmware\":\"%s\", \"motion\":%d}", firmware, motion);
DevKitMQTTClient_ReportState(state);

Wrapping up about AZ3166

The whole implementation of DevKitMQTTClient you will find here. Most of the terminology is from IoT Hub, so for more information, you can visit this documentation

MXCHIP AZ3166 is a good device to start with IoT because most of the things working under the hood and MQTT client is one of the examples.

Piotr Czech

I am software developer, blogger, mentor, geek, startupper, team leader. I started writing code when I was about 15 years old, creating my first program in C++. I believe that everything can be fixed or changed, by just keep doing small steps each day.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.