This post walks through the generic C client for development on embedded devices. While this library does required porting to your particular OS/TCP stack, we’ve tried to make it as easy as possible.
The example implements two basic functions: provisioning a device and normal sensor publishing.
- Provisioning: This associates a device to a particular m2m.io user account. This allows easy visualization of data sent by the device through various widgets on the portal. This is an optional step and is done once per device.
- Sensor publishing: A common use of the m2m.io platform is publishing sensor data from various devices. For example, a temperature monitoring device may wake up once every 15 minutes and publish the current temperature. This would be the device’s “normal” operation. The example code includes a dummy call to read a sensor value to illustrate this.
The m2m.io client libraries repo can be found on GitHub here. In this repo you will find a folder named c_embedded.
In the base directory there is a Makefile, source subdirectories and a README file. The include and src directories contain the libemqtt library. This is a lightweight MQTT client written in C and targeted for use in embedded devices. Inside the client directory are the application files which make use of the library. The client/example.c file is the file we’ll look at in this post.
Inside this file you’ll find four methods which need to be ported for use with your particular platform’s TCP/IP stack:
- init_socket
- close_socket
- send_packet
- read_packet
If you are currently doing communication across a raw socket connection this porting should be straight forward.
For the remainder of the example we’ll be building and running in a Linux environment using the gcc toolchain.
Continuing the example from this point assumes you have a developer account on the m2m.io portal. Instructions on how to sign up can be found at the bottom of the portal page.
At the top of example.c are a few constant values that are required to connect to the m2m.io platform. These values are constants in this example but could easily be programmed into non-volatile storage in an embedded device.
The values for username and domain can be found on the Account tab of the m2m.io portal:
Note on the password field: This is the password you use to sign into the developer portal. This value is not the clear text password, rather the MD5 hash of the password. An MD5 string can be generated through command line tools such as md5 on Mac OS X and md5sum on Linux. Online generators are also available by searching “md5 generator” with an online search engine. To validate your chosen tool, the correct MD5 hash of “helloworld” is MD5 (“helloworld”) = fc5e038d38a57032085441e7fe7010b0.
Now that the user information has been added the example can be built and run.
The example can then be run. Running the example with the -p flag causes a provisioning message to be sent before sensor values are published. Running without -p jumps straight to publishing sensor values.
Sensor Values
The screen on the right of the above screenshot is an MQTT client subscribed to the same topic on which the example app is publishing. The same messages can be seen in the client as were published by the example running on the left.
The MQTT client used in this example is the MQTT web client developed by us at 2lemetry. If using this client be sure to click on the Options tab at the top to enter your m2m.io credential when connecting to the MQTT broker.
Sensor values are published on the topic <domain>/<device type>/<device ID>. In my specific case this is the topic io.m2m/things/device01 so this is the topic to which I subscribed in the MQTT client.
Provisioning
A provisioning message can be sent to associate the device to a user’s account. To see a list of current devices click on the Devices tab when signed into the portal:
To provision a device to your account, first click on the Register a device button. The portal will start listening for the provisioning message. While the portal is listening, run the example with the -p flag. The portal will recognize your device.
At this point you can navigate to your device.
I ran this example on a general purpose PC to easily show the flow of provisioning a device and publishing sensor data. This also makes for a nice runnable package you can play with “out of the box”. However, there are obvious changes that will need to be made to the example to adapt it to your embedded application.
First, as mentioned above, each device/OS has its own TCP/IP library. The socket specific functions will need to be ported to your chosen library.
Secondly, there are pieces of the example that may not make sense in an embedded environment:
- The device ID will most likely not be a constant in your code. It will change for each device - ideally it will be a uniquely identifying string such as serial number or MAC address. This will most likely be put into EEPROM or other non-volatile storage when the device is manufactured.
- The provisioning mode will not be triggered by running with a -p flag. This could be done by having the device recognize it is not currently provisioned (by a flag stored in EEPROM) and send a provisioning message on startup if not provisioned. The device could also be provisioned at the time it is built. Another simple option would be exposing a push-button or other user interaction to provision. These are all application specific depending on how your device is used.
- The sensor loop will read actual hardware values.