Specific Pelion ready example using features of Seeed Wio boards including cellular and SD Card

Dependencies:   WS2812 PixelArray

Fork of simple-mbed-cloud-example-wio_3g by Toyomasa Watarai

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:
Seeed Wio 3G and Seeed Wio LTE-M1/NB1(BG96) over cellular and using SD card.

https://os.mbed.com/media/cache/platforms/Wio_3G.png.250x250_q85.png

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

Example functionality

This example showcases the following device functionality:

  • Allow the user to change the state of the board LED from Pelion LWM2M led_state resource and PUT request.

Instructions to use this program with mbed CLI

1. Import the application into your desktop:

mbed import https://os.mbed.com/teams/Seeed/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.9.x or above.

  • Set APN name, username and password in the mbed_app.json.

            "nsapi.default-cellular-plmn"      : "\"00000\"",
            "nsapi.default-cellular-sim-pin"   : "\"0000\"",
            "nsapi.default-cellular-apn"       : "\"apn\"",
            "nsapi.default-cellular-username"  : "\"username\"",
            "nsapi.default-cellular-password"  : "\"password\""

Information

For the Wio LTE-M1/NB1(BG96) target, PLMN (Public land mobile network) should be specified to get quick connection to the network. This is usually found first 5 digit from your SIM card IMSI (International Mobile Subscriber Identity) number. e.g. 44052

4. Compile and program:

mbed compile -t <toolchain> -m WIO_3G

(supported toolchains : GCC_ARM / ARM / IAR)

Troubleshooting

  • Make sure the fields nsapi.default-cellular-sim-pin, nsapi.default-cellular-apn, nsapi.default-cellular-username and nsapi.default-cellular-password from the mbed_app.json file are filled in correctly. The correct values should appear in the user manual in the details of the SIM card.
  • Enable trace flag to have access to debug information "mbed-trace.enable": true.
  • Try both TCP and UDP socket types.
  • Try both "lwip.ppp-enabled": true and "lwip.ppp-enabled": false.
  • The modem and network may only support IPv6 in which case "lwip.ipv6-enabled": true shall be defined.
  • The SIM and modem must have compatible cellular technology (3G, 4G, NB-IoT, ...) supported and cellular network available.
Committer:
MACRUM
Date:
Thu May 16 07:16:24 2019 +0000
Revision:
4:d4caf0ec02d0
Parent:
3:6f3b402196cc
Add PLMN info for the BG96

Who changed what in which revision?

UserRevisionLine numberNew contents of line
MACRUM 0:91c16b1711c2 1 // ----------------------------------------------------------------------------
MACRUM 0:91c16b1711c2 2 // Copyright 2016-2018 ARM Ltd.
MACRUM 0:91c16b1711c2 3 //
MACRUM 0:91c16b1711c2 4 // SPDX-License-Identifier: Apache-2.0
MACRUM 0:91c16b1711c2 5 //
MACRUM 0:91c16b1711c2 6 // Licensed under the Apache License, Version 2.0 (the "License");
MACRUM 0:91c16b1711c2 7 // you may not use this file except in compliance with the License.
MACRUM 0:91c16b1711c2 8 // You may obtain a copy of the License at
MACRUM 0:91c16b1711c2 9 //
MACRUM 0:91c16b1711c2 10 // http://www.apache.org/licenses/LICENSE-2.0
MACRUM 0:91c16b1711c2 11 //
MACRUM 0:91c16b1711c2 12 // Unless required by applicable law or agreed to in writing, software
MACRUM 0:91c16b1711c2 13 // distributed under the License is distributed on an "AS IS" BASIS,
MACRUM 0:91c16b1711c2 14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
MACRUM 0:91c16b1711c2 15 // See the License for the specific language governing permissions and
MACRUM 0:91c16b1711c2 16 // limitations under the License.
MACRUM 0:91c16b1711c2 17 // ----------------------------------------------------------------------------
MACRUM 0:91c16b1711c2 18 #ifndef MBED_TEST_MODE
MACRUM 0:91c16b1711c2 19
MACRUM 0:91c16b1711c2 20 #include "mbed.h"
MACRUM 0:91c16b1711c2 21 #include "simple-mbed-cloud-client.h"
MACRUM 0:91c16b1711c2 22 #include "FATFileSystem.h"
Osamu Koizumi 2:aadfd874279d 23 #include "LittleFileSystem.h"
Osamu Koizumi 2:aadfd874279d 24
Osamu Koizumi 2:aadfd874279d 25 #include "string.h"
Osamu Koizumi 2:aadfd874279d 26
Osamu Koizumi 2:aadfd874279d 27 // Default network interface object. Don't forget to change the WiFi SSID/password in mbed_app.json if you're using WiFi.
Osamu Koizumi 2:aadfd874279d 28 NetworkInterface *net = NetworkInterface::get_default_instance();
Osamu Koizumi 2:aadfd874279d 29
Osamu Koizumi 2:aadfd874279d 30 // Default block device available on the target board
Osamu Koizumi 2:aadfd874279d 31 BlockDevice *bd = BlockDevice::get_default_instance();
Osamu Koizumi 2:aadfd874279d 32
Osamu Koizumi 2:aadfd874279d 33 #if COMPONENT_SD || COMPONENT_NUSD
Osamu Koizumi 2:aadfd874279d 34 // Use FATFileSystem for SD card type blockdevices
Osamu Koizumi 2:aadfd874279d 35 FATFileSystem fs("fs");
Osamu Koizumi 2:aadfd874279d 36 #else
Osamu Koizumi 2:aadfd874279d 37 // Use LittleFileSystem for non-SD block devices to enable wear leveling and other functions
Osamu Koizumi 2:aadfd874279d 38 LittleFileSystem fs("fs");
Osamu Koizumi 2:aadfd874279d 39 #endif
Osamu Koizumi 2:aadfd874279d 40
Osamu Koizumi 2:aadfd874279d 41 #if USE_BUTTON == 1
Osamu Koizumi 2:aadfd874279d 42 InterruptIn button(BUTTON1);
Osamu Koizumi 2:aadfd874279d 43 #endif /* USE_BUTTON */
Osamu Koizumi 2:aadfd874279d 44
Osamu Koizumi 2:aadfd874279d 45 DigitalOut SD_POWER(PA_15, 1);
MACRUM 1:ddb04b438959 46 #include "Wio_LED.h"
Osamu Koizumi 2:aadfd874279d 47
Osamu Koizumi 2:aadfd874279d 48 // Declaring pointers for access to Pelion Device Management Client resources outside of main()
Osamu Koizumi 2:aadfd874279d 49 MbedCloudClientResource *button_res;
Osamu Koizumi 2:aadfd874279d 50 MbedCloudClientResource *led_res;
Osamu Koizumi 2:aadfd874279d 51 MbedCloudClientResource *post_res;
MACRUM 0:91c16b1711c2 52
MACRUM 0:91c16b1711c2 53 // An event queue is a very useful structure to debounce information between contexts (e.g. ISR and normal threads)
MACRUM 0:91c16b1711c2 54 // 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
MACRUM 0:91c16b1711c2 55 EventQueue eventQueue;
MACRUM 0:91c16b1711c2 56
Osamu Koizumi 2:aadfd874279d 57 /**
Osamu Koizumi 2:aadfd874279d 58 * PUT handler - sets the value of the built-in LED
Osamu Koizumi 2:aadfd874279d 59 * @param resource The resource that triggered the callback
Osamu Koizumi 2:aadfd874279d 60 * @param newValue Updated value for the resource
Osamu Koizumi 2:aadfd874279d 61 */
Osamu Koizumi 2:aadfd874279d 62 void put_callback(MbedCloudClientResource *resource, m2m::String newValue) {
Osamu Koizumi 2:aadfd874279d 63 printf("PUT received. New value: %s\n", newValue.c_str());
Osamu Koizumi 2:aadfd874279d 64 if(atoi(newValue.c_str())) {
Osamu Koizumi 2:aadfd874279d 65 setColor(WS2812_RED);
Osamu Koizumi 2:aadfd874279d 66 } else {
Osamu Koizumi 2:aadfd874279d 67 setColor(WS2812_BLACK);
Osamu Koizumi 2:aadfd874279d 68 }
MACRUM 0:91c16b1711c2 69 }
MACRUM 0:91c16b1711c2 70
MACRUM 0:91c16b1711c2 71 /**
Osamu Koizumi 2:aadfd874279d 72 * POST handler - prints the content of the payload
MACRUM 0:91c16b1711c2 73 * @param resource The resource that triggered the callback
MACRUM 0:91c16b1711c2 74 * @param buffer If a body was passed to the POST function, this contains the data.
MACRUM 0:91c16b1711c2 75 * Note that the buffer is deallocated after leaving this function, so copy it if you need it longer.
MACRUM 0:91c16b1711c2 76 * @param size Size of the body
MACRUM 0:91c16b1711c2 77 */
Osamu Koizumi 2:aadfd874279d 78 void post_callback(MbedCloudClientResource *resource, const uint8_t *buffer, uint16_t size) {
Osamu Koizumi 2:aadfd874279d 79 printf("POST received (length %u). Payload: ", size);
Osamu Koizumi 2:aadfd874279d 80 for (size_t ix = 0; ix < size; ix++) {
Osamu Koizumi 2:aadfd874279d 81 printf("%02x ", buffer[ix]);
Osamu Koizumi 2:aadfd874279d 82 }
Osamu Koizumi 2:aadfd874279d 83 printf("\n");
Osamu Koizumi 2:aadfd874279d 84 }
MACRUM 0:91c16b1711c2 85
Osamu Koizumi 2:aadfd874279d 86 /**
Osamu Koizumi 2:aadfd874279d 87 * Button handler
Osamu Koizumi 2:aadfd874279d 88 * This function will be triggered either by a physical button press or by a ticker every 5 seconds (see below)
Osamu Koizumi 2:aadfd874279d 89 */
Osamu Koizumi 2:aadfd874279d 90 void button_press() {
Osamu Koizumi 2:aadfd874279d 91 int v = button_res->get_value_int() + 1;
Osamu Koizumi 2:aadfd874279d 92 button_res->set_value(v);
Osamu Koizumi 2:aadfd874279d 93 printf("Button clicked %d times\n", v);
MACRUM 0:91c16b1711c2 94 }
MACRUM 0:91c16b1711c2 95
MACRUM 0:91c16b1711c2 96 /**
MACRUM 0:91c16b1711c2 97 * Notification callback handler
MACRUM 0:91c16b1711c2 98 * @param resource The resource that triggered the callback
MACRUM 0:91c16b1711c2 99 * @param status The delivery status of the notification
MACRUM 0:91c16b1711c2 100 */
MACRUM 0:91c16b1711c2 101 void button_callback(MbedCloudClientResource *resource, const NoticationDeliveryStatus status) {
MACRUM 0:91c16b1711c2 102 printf("Button notification, status %s (%d)\n", MbedCloudClientResource::delivery_status_to_string(status), status);
MACRUM 0:91c16b1711c2 103 }
MACRUM 0:91c16b1711c2 104
MACRUM 0:91c16b1711c2 105 /**
MACRUM 0:91c16b1711c2 106 * Registration callback handler
MACRUM 0:91c16b1711c2 107 * @param endpoint Information about the registered endpoint such as the name (so you can find it back in portal)
MACRUM 0:91c16b1711c2 108 */
MACRUM 0:91c16b1711c2 109 void registered(const ConnectorClientEndpointInfo *endpoint) {
Osamu Koizumi 2:aadfd874279d 110 printf("Registered to Pelion Device Management. Endpoint Name: %s\n", endpoint->internal_endpoint_name.c_str());
MACRUM 0:91c16b1711c2 111 }
MACRUM 0:91c16b1711c2 112
MACRUM 0:91c16b1711c2 113 int main(void) {
Osamu Koizumi 2:aadfd874279d 114 printf("\nStarting Simple Pelion Device Management Client example\n");
Osamu Koizumi 2:aadfd874279d 115
Osamu Koizumi 2:aadfd874279d 116 int storage_status = fs.mount(bd);
Osamu Koizumi 2:aadfd874279d 117 if (storage_status != 0) {
Osamu Koizumi 2:aadfd874279d 118 printf("Storage mounting failed.\n");
Osamu Koizumi 2:aadfd874279d 119 }
MACRUM 0:91c16b1711c2 120
Osamu Koizumi 2:aadfd874279d 121 #if USE_BUTTON == 1
Osamu Koizumi 2:aadfd874279d 122 // If the User button is pressed ons start, then format storage.
Osamu Koizumi 2:aadfd874279d 123 bool btn_pressed = (button.read() == MBED_CONF_APP_BUTTON_PRESSED_STATE);
Osamu Koizumi 2:aadfd874279d 124 if (btn_pressed) {
Osamu Koizumi 2:aadfd874279d 125 printf("User button is pushed on start...\n");
Osamu Koizumi 2:aadfd874279d 126 }
Osamu Koizumi 2:aadfd874279d 127 #else
Osamu Koizumi 2:aadfd874279d 128 bool btn_pressed = false;
Osamu Koizumi 2:aadfd874279d 129 #endif /* USE_BUTTON */
MACRUM 0:91c16b1711c2 130
Osamu Koizumi 2:aadfd874279d 131 if (storage_status || btn_pressed) {
Osamu Koizumi 2:aadfd874279d 132 printf("Formatting the storage...\n");
Osamu Koizumi 2:aadfd874279d 133 int storage_status = StorageHelper::format(&fs, bd);
Osamu Koizumi 2:aadfd874279d 134 if (storage_status != 0) {
Osamu Koizumi 2:aadfd874279d 135 printf("ERROR: Failed to reformat the storage (%d).\n", storage_status);
Osamu Koizumi 2:aadfd874279d 136 }
Osamu Koizumi 2:aadfd874279d 137 } else {
Osamu Koizumi 2:aadfd874279d 138 printf("You can hold the user button during boot to format the storage and change the device identity.\n");
Osamu Koizumi 2:aadfd874279d 139 }
MACRUM 0:91c16b1711c2 140
Osamu Koizumi 2:aadfd874279d 141 // Connect to the Internet (DHCP is expected to be on)
Osamu Koizumi 2:aadfd874279d 142 printf("Connecting to the network using the default network interface...\n");
Osamu Koizumi 2:aadfd874279d 143 net = NetworkInterface::get_default_instance();
MACRUM 0:91c16b1711c2 144
Osamu Koizumi 2:aadfd874279d 145 nsapi_error_t net_status = NSAPI_ERROR_NO_CONNECTION;
Osamu Koizumi 2:aadfd874279d 146 while ((net_status = net->connect()) != NSAPI_ERROR_OK) {
Osamu Koizumi 2:aadfd874279d 147 printf("Unable to connect to network (%d). Retrying...\n", net_status);
MACRUM 0:91c16b1711c2 148 }
MACRUM 0:91c16b1711c2 149
MACRUM 0:91c16b1711c2 150 printf("Connected to the network successfully. IP address: %s\n", net->get_ip_address());
MACRUM 0:91c16b1711c2 151
Osamu Koizumi 2:aadfd874279d 152 printf("Initializing Pelion Device Management Client...\n");
Osamu Koizumi 2:aadfd874279d 153
Osamu Koizumi 2:aadfd874279d 154 // SimpleMbedCloudClient handles registering over LwM2M to Pelion Device Management
MACRUM 0:91c16b1711c2 155 SimpleMbedCloudClient client(net, bd, &fs);
MACRUM 0:91c16b1711c2 156 int client_status = client.init();
MACRUM 0:91c16b1711c2 157 if (client_status != 0) {
MACRUM 0:91c16b1711c2 158 printf("Pelion Client initialization failed (%d)\n", client_status);
MACRUM 0:91c16b1711c2 159 return -1;
MACRUM 0:91c16b1711c2 160 }
MACRUM 0:91c16b1711c2 161
MACRUM 0:91c16b1711c2 162 // Creating resources, which can be written or read from the cloud
MACRUM 0:91c16b1711c2 163 button_res = client.create_resource("3200/0/5501", "button_count");
MACRUM 0:91c16b1711c2 164 button_res->set_value(0);
MACRUM 0:91c16b1711c2 165 button_res->methods(M2MMethod::GET);
MACRUM 0:91c16b1711c2 166 button_res->observable(true);
MACRUM 0:91c16b1711c2 167 button_res->attach_notification_callback(button_callback);
MACRUM 0:91c16b1711c2 168
Osamu Koizumi 2:aadfd874279d 169 led_res = client.create_resource("3201/0/5853", "led_state");
Osamu Koizumi 2:aadfd874279d 170 led_res->set_value(0);
Osamu Koizumi 2:aadfd874279d 171 led_res->methods(M2MMethod::GET | M2MMethod::PUT);
Osamu Koizumi 2:aadfd874279d 172 led_res->attach_put_callback(put_callback);
MACRUM 0:91c16b1711c2 173
Osamu Koizumi 2:aadfd874279d 174 post_res = client.create_resource("3300/0/5605", "execute_function");
Osamu Koizumi 2:aadfd874279d 175 post_res->methods(M2MMethod::POST);
Osamu Koizumi 2:aadfd874279d 176 post_res->attach_post_callback(post_callback);
MACRUM 0:91c16b1711c2 177
Osamu Koizumi 2:aadfd874279d 178 printf("Initialized Pelion Device Management Client. Registering...\n");
MACRUM 0:91c16b1711c2 179
MACRUM 0:91c16b1711c2 180 // Callback that fires when registering is complete
MACRUM 0:91c16b1711c2 181 client.on_registered(&registered);
MACRUM 0:91c16b1711c2 182
Osamu Koizumi 2:aadfd874279d 183 // Register with Pelion DM
MACRUM 0:91c16b1711c2 184 client.register_and_connect();
MACRUM 0:91c16b1711c2 185
Osamu Koizumi 2:aadfd874279d 186 #if USE_BUTTON == 1
Osamu Koizumi 2:aadfd874279d 187 // The button fires on an interrupt context, but debounces it to the eventqueue, so it's safe to do network operations
Osamu Koizumi 2:aadfd874279d 188 button.fall(eventQueue.event(&button_press));
Osamu Koizumi 2:aadfd874279d 189 printf("Press the user button to increment the LwM2M resource value...\n");
Osamu Koizumi 2:aadfd874279d 190 #else
MACRUM 0:91c16b1711c2 191 // The timer fires on an interrupt context, but debounces it to the eventqueue, so it's safe to do network operations
MACRUM 0:91c16b1711c2 192 Ticker timer;
Osamu Koizumi 2:aadfd874279d 193 timer.attach(eventQueue.event(&button_press), 5.0);
Osamu Koizumi 2:aadfd874279d 194 printf("Simulating button press every 5 seconds...\n");
Osamu Koizumi 2:aadfd874279d 195 #endif /* USE_BUTTON */
MACRUM 0:91c16b1711c2 196
MACRUM 0:91c16b1711c2 197 // You can easily run the eventQueue in a separate thread if required
MACRUM 0:91c16b1711c2 198 eventQueue.dispatch_forever();
MACRUM 0:91c16b1711c2 199 }
Osamu Koizumi 2:aadfd874279d 200
Osamu Koizumi 2:aadfd874279d 201 #endif /* MBED_TEST_MODE */