Hopefully you had the opportunity to review my last article Device management with LwM2M IOWA stack - Tutorial 1 and start to use the LwM2M protocol.
Now, it is time to play with a *real* device from the ESP32 family. Why not start with the well-known ESP32 ?
Hardware- ESP32 DevkitV1
- Wifi Access point SSID and password !
The purpose of this article is not to explain how to setup the esp-idf framework, and Hackster user @Niket has already written a very nice tutorial, please be sure to have a look at the following page before going further:
https://www.hackster.io/Niket/setup-esp-idf-for-freertos-tutorial-2-e45e16
As soon as you build and run your first code (e.g.: esp-idf/examples/get-started/blink or esp-idf/examples/get-started/hello-world), you are ready for the next part.
( The steps to build IOWA/ESP32 are identical on Windows and Linux so feel free to choose any flavor you want)
CodeIt is time to get the IOWA/ESP32 code from IOTEROP’s repository:
git clone --recurse-submodules https://github.com/IOTEROP/IOWA_esp32
(Don’t forget the –recurse-submodules !)
Now, the code under iowa_esp32 is structured with a components and a esp_samples directory. This would allow us to use IOWA as a separate component for the esp-idf framework.
Let’s have a look at this tree:
components/esp_iowa/iowa_code: This folder contains the “classic & untouched” IOWA code from Github, referred as a submodule from this link: https://github.com/IOTEROP/IOWA
components/esp_iowa/esp32_hal: This folder contains the code specific to the hardware (ESP32) and to esp-idf framework. If needed, you can adapt this code for any specific hardware flavor.
esp_samples/ESP32_01-baseline: This folder contains the basic sample code we will build & run our ESP32 device.
Build and Flash(For context please understand, our code uses esp-idf Connection Example)
ESP32 DevkitV1 will be connected using esp-idf wifi stack. It means that you have to setup the access point SSID and password. Other parameters can be adjusted using the configuration menu.
Enter the sample directory you want work on ( e.g.: move to esp_samples/ESP32_01-baseline)
Configure your project:
idf.py menuconfig
- Wifi configuration
Example Connection Configuration --->
* Set WiFi SSID under Example Configuration
* Set WiFi Password under Example Configuration
- Device configuration (optional – Object sample name could be customized to easily find your device on CONNECTicut)
IOWA ESP3201 sample config --->
* Object sample name : (default: IOWA_Hackster_ESP32)
* LwM2M server URI : (default: coap://iowa-server.ioterop.com)
* Server Short ID : (default: 1234)
* Server Lifetime : (default: 50)
- IOWA component configuration (optional – the most interesting part is the Debug output entry)
Component config --->
Iowa Evaluation version --->
*** IOWA for Kconfig beta version - Work In Progress ***
*** WARNING: (Evaluation version) full IOWA support disabled ***
* IOWA Transport (UDP support) --->
* IOWA Lwm2m mode (LWM2M_CLIENT_MODE) --->
* Debug output: Select components to log --->
* (512) Static buffer size for datagram packets
* IOWA Endianness (LWM2M_LITTLE_ENDIAN) --->
For a first test, except the mandatory information (WIFI), you can keep all the parameters on their default values
Build the project and flash it to the board, then run monitor tool to view serial output:
idf.py build
idf.py -p PORT flash monitor
Example OutputPrerequisite: you have to visit, with your favorite browser, the server URL you specified in menuconfig (in our case: https://iowa-server.ioterop.com also known as CONNECTicut server).
You can now check both “sides”:
On the client:
You can see the device registration against the server, with some messages exchanged.
On the server:
You device is now listed on the Client List (you can press update to retrieve some client information)
On the ESP32 Devkit, there’s an onboard LED (well, two LEDs exist but I want to play with the second one, connected to a GPIO).
The first task is to find the GPIO number associated to this LED (some boards use GPIO5
, others GPIO2
). On my board, the LED is connected to GPIO2
.
IOWA stack allows you to “play” with various predefined IPSO objects or, if you want, you can use your own custom objects. Here, we will use a well known (and simple) object: 3311. You can refer to the Smart Object Standards from OMA (http://www.openmobilealliance.org/wp/omna/lwm2m/lwm2mregistry.html) to get additional information on object 3311 aka Light Control.
Like every object, some resources are mandatory (e.g.: id:5850 On/Off) while others are optional (e.g.:5852 On time). Here’s the official object description:
On our custom object, we will manage:
- id5850 (on/off) to switch on/off the onboard LED
- id5851 (on time) to get how long this LED was ON
Adding a custom object to your code is quite simple as you just have to take care of 4 points: Resources
, Object values
, callback
and Custom object
registration.
Resources
:
Here, we define the two resources (mandatory and optional) we want to manage. Both can be read and write (limited write for On Time, see below, on Advanced view)
iowa_lwm2m_resource_desc_t resources[2] = {
{5850, IOWA_LWM2M_TYPE_BOOLEAN, IOWA_DM_READ | IOWA_DM_WRITE, IOWA_RESOURCE_FLAG_MANDATORY},
{5852, IOWA_LWM2M_TYPE_INTEGER, IOWA_DM_READ | IOWA_DM_WRITE, IOWA_RESOURCE_FLAG_OPTIONAL}
};
Object values
: The variables in this structure will be updated in the callback, on operation requests( e.g.: IOWA_DM_READ or IOWA_DM_WRITE):
custom_object_values_t objectValues = {.state = false, .onTime = 0};
- Callback: Will handle IOWA resource operation requests.
iowa_status_t prv_LEDControlCallback(iowa_dm_operation_t operation,
iowa_lwm2m_data_t *dataP,
size_t numData,
void *userData,
iowa_context_t iowaH)
{
...
}
- Register (and unregister): Any object must be registered (and unregistered on cleanup). Here, the iowa_client_add_custom_object() with the Object ID (3311) we want to support will do the job. iowa_client_remove_custom_object() will remove this custom object
iowa_client_add_custom_object(g_iowaH,
3311,
1, singleInstanceId,
2, resources,
prv_LEDControlCallback,
NULL, NULL,
&objectValues);
Now, the heart of all this stuff is on iowa_step().
The main loop is a little bit more “complex” than the one you saw in previous code…well, not really complex! :
iowa_step(…, 1) runs the IOWA stack for 1 second, then returns (usually with IOWA_COAP_NO_ERROR). So, each second, if the LED status is ON, we increment our timeon counter and notify the server of a resource change (to update the server information).
We don’t care about LED status changes as the changes are requested by the server (maybe it could be interesting to add an update initial value to the server.
This loop loops endlessly (at least, until an error occurs)
On server side, even though it is just a *test* server, we have some UI fun stuff:
Basic view:
Advanced view:
On Advanced view, you can read the On Time value. According to specifications, you are not allowed to write and change the On Time value, except with 0 as a counter reset.
The purpose of this article is to show you how easy you could add IOWA device management very easily to a real hardware, even with an evaluation version. And even with basic features, you can have fun.
Feel free to comment or ask any question, I would be very happy to get your feedback !
Comments