Generic Pelion Device Management example for various U-blox-based boards.

Dependencies:   ublox-at-cellular-interface ublox-cellular-base

DEPRECATED

This example application is not maintained and not recommended. It uses an old version of Mbed OS, Pelion DM, and Arm toolchain. It doesn't work with Mbed Studio.

Please use: https://os.mbed.com/teams/mbed-os-examples/code/mbed-os-example-pelion/

This example is known to work great on the following platforms:

For Odin-W2 please go to Repository link

Follow the Quick-Start instructions: https://cloud.mbed.com/quick-start

UBLOX_C030_U201

UBLOX_C030_R412M

Example functionality

This example showcases the following device functionality:

  • On user button click, increment Pelion LWM2M button resource.
  • Allow the user to change the state of the board LED from Pelion LWM2M led_state resource and PUT request.
  • (currently disabled) Read ADC temperature and ADC vref, and report them as Pelion LWM2M resources.

Use this example with Mbed CLI

1. Import the application into your desktop:

mbed import https://os.mbed.com/teams/ublox/code/pelion-example-common

cd pelion-example-common

2. Install the CLOUD_SDK_API_KEY

mbed config -G CLOUD_SDK_API_KEY <PELION_DM_API_KEY>

For instructions on how to generate your API key, please see the documentation.

3. Initialize firmware credentials (done once per repository). You can use the following command:

mbed dm init -d "<your company name in Pelion DM>" --model-name "<product model identifier>" -q --force

If above command do not work for your Mbed CLI, please consider upgrading Mbed CLI to version 1.8.x or above.

4. Compile and program:

mbed compile -t <toolchain> -m <TARGET_BOARD>

(supported toolchains : GCC_ARM / ARM / IAR)

Committer:
screamer
Date:
Sun Dec 16 15:03:49 2018 +0000
Revision:
3:3b2db67b206e
Parent:
1:a50c1e691ff1
Child:
6:2fb5057c0e42
Updated main application for pin names and inline documentation

Who changed what in which revision?

UserRevisionLine numberNew contents of line
screamer 0:a076a1bbe630 1 // ----------------------------------------------------------------------------
screamer 0:a076a1bbe630 2 // Copyright 2016-2018 ARM Ltd.
screamer 0:a076a1bbe630 3 //
screamer 0:a076a1bbe630 4 // SPDX-License-Identifier: Apache-2.0
screamer 0:a076a1bbe630 5 //
screamer 0:a076a1bbe630 6 // Licensed under the Apache License, Version 2.0 (the "License");
screamer 0:a076a1bbe630 7 // you may not use this file except in compliance with the License.
screamer 0:a076a1bbe630 8 // You may obtain a copy of the License at
screamer 0:a076a1bbe630 9 //
screamer 0:a076a1bbe630 10 // http://www.apache.org/licenses/LICENSE-2.0
screamer 0:a076a1bbe630 11 //
screamer 0:a076a1bbe630 12 // Unless required by applicable law or agreed to in writing, software
screamer 0:a076a1bbe630 13 // distributed under the License is distributed on an "AS IS" BASIS,
screamer 0:a076a1bbe630 14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
screamer 0:a076a1bbe630 15 // See the License for the specific language governing permissions and
screamer 0:a076a1bbe630 16 // limitations under the License.
screamer 0:a076a1bbe630 17 // ----------------------------------------------------------------------------
screamer 0:a076a1bbe630 18 #ifndef MBED_TEST_MODE
screamer 0:a076a1bbe630 19
screamer 0:a076a1bbe630 20 #include "mbed.h"
screamer 0:a076a1bbe630 21 #include "simple-mbed-cloud-client.h"
screamer 0:a076a1bbe630 22 #include "FATFileSystem.h"
screamer 0:a076a1bbe630 23 #include "LittleFileSystem.h"
screamer 0:a076a1bbe630 24
screamer 0:a076a1bbe630 25 // An event queue is a very useful structure to debounce information between contexts (e.g. ISR and normal threads)
screamer 0:a076a1bbe630 26 // This is great because things such as network operations are illegal in ISR, so updating a resource in a button's fall() function is not allowed
screamer 0:a076a1bbe630 27 EventQueue eventQueue;
screamer 0:a076a1bbe630 28
screamer 3:3b2db67b206e 29 // Default network interface object. Don't forget to change the WiFi SSID/password in mbed_app.json if you're using WiFi.
screamer 0:a076a1bbe630 30 NetworkInterface *net = NetworkInterface::get_default_instance();
screamer 0:a076a1bbe630 31
screamer 3:3b2db67b206e 32 // Default block device available on the target board
screamer 0:a076a1bbe630 33 BlockDevice *bd = BlockDevice::get_default_instance();
screamer 3:3b2db67b206e 34
screamer 3:3b2db67b206e 35 #if COMPONENT_SD || COMPONENT_NUSD
screamer 3:3b2db67b206e 36 // Use FATFileSystem for SD card type blockdevices
screamer 3:3b2db67b206e 37 FATFileSystem fs("fs", bd);
screamer 3:3b2db67b206e 38 #else
screamer 3:3b2db67b206e 39 // Use LittleFileSystem for non-SD block devices to enable wear leveling and other functions
screamer 3:3b2db67b206e 40 LittleFileSystem fs("fs", bd);
screamer 3:3b2db67b206e 41 #endif
screamer 3:3b2db67b206e 42
screamer 3:3b2db67b206e 43 // Fix for older versions of Mbed OS where BUTTON1 is undefined
screamer 3:3b2db67b206e 44 #if TARGET_UBLOX_C030
screamer 3:3b2db67b206e 45 #define BUTTON1 PC_13
screamer 3:3b2db67b206e 46 #endif
screamer 0:a076a1bbe630 47
screamer 0:a076a1bbe630 48 // Default User button for GET example
screamer 1:a50c1e691ff1 49 InterruptIn button(BUTTON1);
screamer 0:a076a1bbe630 50 // Default LED to use for PUT/POST example
screamer 0:a076a1bbe630 51 DigitalOut led(LED1);
screamer 1:a50c1e691ff1 52
screamer 3:3b2db67b206e 53 // Currently disabled until ADC sensors are introduced for U-blox targets.
screamer 1:a50c1e691ff1 54 #ifdef ENABLE_SENSORS
screamer 0:a076a1bbe630 55 // Default temperature reading from microcontroller
screamer 0:a076a1bbe630 56 AnalogIn adc_temp(ADC_TEMP);
screamer 0:a076a1bbe630 57 // Voltage reference from microcontroller
screamer 0:a076a1bbe630 58 AnalogIn adc_vref(ADC_VREF);
screamer 0:a076a1bbe630 59
screamer 0:a076a1bbe630 60 #define SENSORS_POLL_INTERVAL 1.0
screamer 1:a50c1e691ff1 61 #endif /* ENABLE_SENSORS */
screamer 0:a076a1bbe630 62
screamer 0:a076a1bbe630 63 // Declaring pointers for access to Pelion Client resources outside of main()
screamer 0:a076a1bbe630 64 MbedCloudClientResource *res_button;
screamer 0:a076a1bbe630 65 MbedCloudClientResource *res_led;
screamer 1:a50c1e691ff1 66 #ifdef ENABLE_SENSORS
screamer 0:a076a1bbe630 67 MbedCloudClientResource *res_temperature;
screamer 0:a076a1bbe630 68 MbedCloudClientResource *res_voltage;
screamer 1:a50c1e691ff1 69 #endif /* ENABLE_SENSORS */
screamer 0:a076a1bbe630 70
screamer 0:a076a1bbe630 71 // When the device is registered, this variable will be used to access various useful information, like device ID etc.
screamer 0:a076a1bbe630 72 static const ConnectorClientEndpointInfo* endpointInfo;
screamer 0:a076a1bbe630 73
screamer 0:a076a1bbe630 74 /**
screamer 0:a076a1bbe630 75 * PUT handler
screamer 0:a076a1bbe630 76 * @param resource The resource that triggered the callback
screamer 0:a076a1bbe630 77 * @param newValue Updated value for the resource
screamer 0:a076a1bbe630 78 */
screamer 0:a076a1bbe630 79 void led_put_callback(MbedCloudClientResource *resource, m2m::String newValue) {
screamer 3:3b2db67b206e 80 printf("PUT received. New value: %s\n", newValue.c_str());
screamer 0:a076a1bbe630 81 led = atoi(newValue.c_str());
screamer 0:a076a1bbe630 82 }
screamer 0:a076a1bbe630 83
screamer 0:a076a1bbe630 84 /**
screamer 0:a076a1bbe630 85 * POST handler
screamer 0:a076a1bbe630 86 * @param resource The resource that triggered the callback
screamer 0:a076a1bbe630 87 * @param buffer If a body was passed to the POST function, this contains the data.
screamer 0:a076a1bbe630 88 * Note that the buffer is deallocated after leaving this function, so copy it if you need it longer.
screamer 0:a076a1bbe630 89 * @param size Size of the body
screamer 0:a076a1bbe630 90 */
screamer 0:a076a1bbe630 91 void led_post_callback(MbedCloudClientResource *resource, const uint8_t *buffer, uint16_t size) {
screamer 3:3b2db67b206e 92 printf("POST received. Payload: %s\n", res_led->get_value().c_str());
screamer 0:a076a1bbe630 93 led = atoi(res_led->get_value().c_str());
screamer 0:a076a1bbe630 94 }
screamer 0:a076a1bbe630 95
screamer 0:a076a1bbe630 96 /**
screamer 0:a076a1bbe630 97 * Button function triggered by the physical button press.
screamer 0:a076a1bbe630 98 */
screamer 0:a076a1bbe630 99 void button_press() {
screamer 0:a076a1bbe630 100 int v = res_button->get_value_int() + 1;
screamer 0:a076a1bbe630 101 res_button->set_value(v);
screamer 0:a076a1bbe630 102 printf("Button clicked %d times\n", v);
screamer 0:a076a1bbe630 103 }
screamer 0:a076a1bbe630 104
screamer 0:a076a1bbe630 105 /**
screamer 0:a076a1bbe630 106 * Notification callback handler
screamer 0:a076a1bbe630 107 * @param resource The resource that triggered the callback
screamer 0:a076a1bbe630 108 * @param status The delivery status of the notification
screamer 0:a076a1bbe630 109 */
screamer 0:a076a1bbe630 110 void button_callback(MbedCloudClientResource *resource, const NoticationDeliveryStatus status) {
screamer 0:a076a1bbe630 111 printf("Button notification, status %s (%d)\n", MbedCloudClientResource::delivery_status_to_string(status), status);
screamer 0:a076a1bbe630 112 }
screamer 0:a076a1bbe630 113
screamer 0:a076a1bbe630 114 /**
screamer 0:a076a1bbe630 115 * Registration callback handler
screamer 0:a076a1bbe630 116 * @param endpoint Information about the registered endpoint such as the name (so you can find it back in portal)
screamer 0:a076a1bbe630 117 */
screamer 0:a076a1bbe630 118 void registered(const ConnectorClientEndpointInfo *endpoint) {
screamer 3:3b2db67b206e 119 printf("Registered to Pelion Device Management. Endpoint Name: %s\n", endpoint->internal_endpoint_name.c_str());
screamer 0:a076a1bbe630 120 endpointInfo = endpoint;
screamer 0:a076a1bbe630 121 }
screamer 0:a076a1bbe630 122
screamer 0:a076a1bbe630 123 /**
screamer 0:a076a1bbe630 124 * Update sensors and report their values.
screamer 0:a076a1bbe630 125 * This function is called periodically.
screamer 0:a076a1bbe630 126 */
screamer 1:a50c1e691ff1 127 #ifdef ENABLE_SENSORS
screamer 0:a076a1bbe630 128 void sensors_update() {
screamer 0:a076a1bbe630 129 float temp = adc_temp.read()*100;
screamer 0:a076a1bbe630 130 float vref = adc_vref.read();
screamer 0:a076a1bbe630 131 printf("ADC temp: %6.4f C, vref: %6.4f %%\r\n", temp, vref);
screamer 0:a076a1bbe630 132 if (endpointInfo) {
screamer 0:a076a1bbe630 133 res_temperature->set_value(temp);
screamer 0:a076a1bbe630 134 res_voltage->set_value(vref);
screamer 0:a076a1bbe630 135 }
screamer 0:a076a1bbe630 136 }
screamer 1:a50c1e691ff1 137 #endif /* ENABLE_SENSORS */
screamer 0:a076a1bbe630 138
screamer 0:a076a1bbe630 139
screamer 0:a076a1bbe630 140 int main(void) {
screamer 3:3b2db67b206e 141 printf("\nStarting Simple Pelion Device Management Client example\n");
screamer 0:a076a1bbe630 142
screamer 0:a076a1bbe630 143 // If the User button is pressed ons start, then format storage.
screamer 3:3b2db67b206e 144 DigitalIn *user_button = new DigitalIn(BUTTON1);
screamer 0:a076a1bbe630 145 const int PRESSED = 1;
screamer 0:a076a1bbe630 146 if (user_button->read() == PRESSED) {
screamer 0:a076a1bbe630 147 printf("User button is pushed on start. Formatting the storage...\n");
screamer 3:3b2db67b206e 148 int storage_status = fs.reformat(bd);
screamer 0:a076a1bbe630 149 if (storage_status != 0) {
screamer 3:3b2db67b206e 150 if (bd->erase(0, bd->size()) == 0) {
screamer 3:3b2db67b206e 151 if (fs.format(bd) == 0) {
screamer 0:a076a1bbe630 152 storage_status = 0;
screamer 0:a076a1bbe630 153 printf("The storage reformatted successfully.\n");
screamer 0:a076a1bbe630 154 }
screamer 0:a076a1bbe630 155 }
screamer 0:a076a1bbe630 156 }
screamer 0:a076a1bbe630 157 if (storage_status != 0) {
screamer 0:a076a1bbe630 158 printf("ERROR: Failed to reformat the storage (%d).\n", storage_status);
screamer 0:a076a1bbe630 159 }
screamer 3:3b2db67b206e 160 } else {
screamer 3:3b2db67b206e 161 printf("You can hold the user button during boot to format the storage and change the device identity.\n");
screamer 0:a076a1bbe630 162 }
screamer 0:a076a1bbe630 163
screamer 0:a076a1bbe630 164 // Connect to the internet (DHCP is expected to be on)
screamer 3:3b2db67b206e 165 printf("Connecting to the network using default network interface...\n");
screamer 0:a076a1bbe630 166 net = NetworkInterface::get_default_instance();
screamer 0:a076a1bbe630 167
screamer 0:a076a1bbe630 168 nsapi_error_t net_status = -1;
screamer 0:a076a1bbe630 169 for (int tries = 0; tries < 3; tries++) {
screamer 0:a076a1bbe630 170 net_status = net->connect();
screamer 0:a076a1bbe630 171 if (net_status == NSAPI_ERROR_OK) {
screamer 0:a076a1bbe630 172 break;
screamer 0:a076a1bbe630 173 } else {
screamer 0:a076a1bbe630 174 printf("Unable to connect to network. Retrying...\n");
screamer 0:a076a1bbe630 175 }
screamer 0:a076a1bbe630 176 }
screamer 0:a076a1bbe630 177
screamer 0:a076a1bbe630 178 if (net_status != NSAPI_ERROR_OK) {
screamer 0:a076a1bbe630 179 printf("ERROR: Connecting to the network failed (%d)!\n", net_status);
screamer 0:a076a1bbe630 180 return -1;
screamer 0:a076a1bbe630 181 }
screamer 0:a076a1bbe630 182
screamer 0:a076a1bbe630 183 printf("Connected to the network successfully. IP address: %s\n", net->get_ip_address());
screamer 0:a076a1bbe630 184
screamer 0:a076a1bbe630 185 // SimpleMbedCloudClient handles registering over LwM2M to Pelion DM
screamer 0:a076a1bbe630 186 SimpleMbedCloudClient client(net, bd, &fs);
screamer 0:a076a1bbe630 187 int client_status = client.init();
screamer 0:a076a1bbe630 188 if (client_status != 0) {
screamer 0:a076a1bbe630 189 printf("ERROR: Pelion Client initialization failed (%d)\n", client_status);
screamer 0:a076a1bbe630 190 return -1;
screamer 0:a076a1bbe630 191 }
screamer 0:a076a1bbe630 192
screamer 0:a076a1bbe630 193 // Creating resources, which can be written or read from the cloud
screamer 0:a076a1bbe630 194 res_button = client.create_resource("3200/0/5501", "button_count");
screamer 0:a076a1bbe630 195 res_button->set_value(0);
screamer 0:a076a1bbe630 196 res_button->methods(M2MMethod::GET);
screamer 0:a076a1bbe630 197 res_button->observable(true);
screamer 0:a076a1bbe630 198 res_button->attach_notification_callback(button_callback);
screamer 0:a076a1bbe630 199
screamer 0:a076a1bbe630 200 res_led = client.create_resource("3201/0/5853", "led_state");
screamer 0:a076a1bbe630 201 res_led->set_value(1);
screamer 0:a076a1bbe630 202 res_led->methods(M2MMethod::GET | M2MMethod::PUT);
screamer 0:a076a1bbe630 203 res_led->attach_put_callback(led_put_callback);
screamer 0:a076a1bbe630 204
screamer 1:a50c1e691ff1 205 #ifdef ENABLE_SENSORS
screamer 0:a076a1bbe630 206 // Sensor resources
screamer 0:a076a1bbe630 207 res_temperature = client.create_resource("3303/0/5700", "temperature");
screamer 0:a076a1bbe630 208 res_temperature->set_value(0);
screamer 0:a076a1bbe630 209 res_temperature->methods(M2MMethod::GET);
screamer 0:a076a1bbe630 210 res_temperature->observable(true);
screamer 0:a076a1bbe630 211
screamer 0:a076a1bbe630 212 res_voltage = client.create_resource("3316/0/5700", "voltage");
screamer 0:a076a1bbe630 213 res_voltage->set_value(0);
screamer 0:a076a1bbe630 214 res_voltage->methods(M2MMethod::GET);
screamer 0:a076a1bbe630 215 res_voltage->observable(true);
screamer 1:a50c1e691ff1 216 #endif /* ENABLE_SENSORS */
screamer 0:a076a1bbe630 217
screamer 0:a076a1bbe630 218 printf("Initialized Pelion Client. Registering...\n");
screamer 0:a076a1bbe630 219
screamer 0:a076a1bbe630 220 // Callback that fires when registering is complete
screamer 0:a076a1bbe630 221 client.on_registered(&registered);
screamer 0:a076a1bbe630 222
screamer 0:a076a1bbe630 223 // Register with Pelion DM
screamer 0:a076a1bbe630 224 client.register_and_connect();
screamer 0:a076a1bbe630 225
screamer 3:3b2db67b206e 226 int i = 600; // wait up 60 seconds before attaching sensors and button events
screamer 0:a076a1bbe630 227 while (i-- > 0 && !client.is_client_registered()) {
screamer 0:a076a1bbe630 228 wait_ms(100);
screamer 0:a076a1bbe630 229 }
screamer 0:a076a1bbe630 230
screamer 0:a076a1bbe630 231 button.fall(eventQueue.event(&button_press));
screamer 3:3b2db67b206e 232 printf("Press the user button to increment the LwM2M resource value...\n");
screamer 0:a076a1bbe630 233
screamer 1:a50c1e691ff1 234 #ifdef ENABLE_SENSORS
screamer 0:a076a1bbe630 235 // The timer fires on an interrupt context, but debounces it to the eventqueue, so it's safe to do network operations
screamer 0:a076a1bbe630 236 Ticker timer;
screamer 0:a076a1bbe630 237 timer.attach(eventQueue.event(&sensors_update), SENSORS_POLL_INTERVAL);
screamer 1:a50c1e691ff1 238 #endif /* ENABLE_SENSORS */
screamer 0:a076a1bbe630 239
screamer 0:a076a1bbe630 240 // You can easily run the eventQueue in a separate thread if required
screamer 0:a076a1bbe630 241 eventQueue.dispatch_forever();
screamer 0:a076a1bbe630 242 }
screamer 0:a076a1bbe630 243 #endif