Workshop example

Dependencies:   X_NUCLEO_COMMON ST_INTERFACES

Committer:
screamer
Date:
Mon Dec 10 10:42:29 2018 +0000
Revision:
11:8df4529f060d
Parent:
10:b27c962b3c3f
Child:
12:1f1a50e973db
Make use of the physical button and 2 sensors (temp & humidity)

Who changed what in which revision?

UserRevisionLine numberNew contents of line
adustm 1:e86b1cffc402 1 // ----------------------------------------------------------------------------
adustm 4:cf7342047b4d 2 // Copyright 2016-2018 ARM Ltd.
adustm 1:e86b1cffc402 3 //
adustm 1:e86b1cffc402 4 // SPDX-License-Identifier: Apache-2.0
adustm 1:e86b1cffc402 5 //
adustm 1:e86b1cffc402 6 // Licensed under the Apache License, Version 2.0 (the "License");
adustm 1:e86b1cffc402 7 // you may not use this file except in compliance with the License.
adustm 1:e86b1cffc402 8 // You may obtain a copy of the License at
adustm 1:e86b1cffc402 9 //
adustm 1:e86b1cffc402 10 // http://www.apache.org/licenses/LICENSE-2.0
adustm 1:e86b1cffc402 11 //
adustm 1:e86b1cffc402 12 // Unless required by applicable law or agreed to in writing, software
adustm 1:e86b1cffc402 13 // distributed under the License is distributed on an "AS IS" BASIS,
adustm 1:e86b1cffc402 14 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
adustm 1:e86b1cffc402 15 // See the License for the specific language governing permissions and
adustm 1:e86b1cffc402 16 // limitations under the License.
adustm 1:e86b1cffc402 17 // ----------------------------------------------------------------------------
MarceloSalazar 9:265744785d33 18 #ifndef MBED_TEST_MODE
adustm 1:e86b1cffc402 19 #include "mbed.h"
adustm 1:e86b1cffc402 20 #include "simple-mbed-cloud-client.h"
screamer 10:b27c962b3c3f 21 #include "LittleFileSystem.h"
screamer 10:b27c962b3c3f 22
screamer 11:8df4529f060d 23 #define SENSORS_AND_BUTTONS
screamer 10:b27c962b3c3f 24 #ifdef SENSORS_AND_BUTTONS
screamer 10:b27c962b3c3f 25 #include "HTS221Sensor.h"
screamer 10:b27c962b3c3f 26 #include "LPS22HBSensor.h"
screamer 10:b27c962b3c3f 27 #include "LSM6DSLSensor.h"
screamer 10:b27c962b3c3f 28 #include "lis3mdl_class.h"
screamer 11:8df4529f060d 29 // #include "VL53L0X.h"
screamer 10:b27c962b3c3f 30
screamer 10:b27c962b3c3f 31 static DevI2C devI2c(PB_11,PB_10);
screamer 10:b27c962b3c3f 32 static HTS221Sensor hum_temp(&devI2c);
screamer 10:b27c962b3c3f 33 static LPS22HBSensor press_temp(&devI2c);
screamer 10:b27c962b3c3f 34 static LSM6DSLSensor acc_gyro(&devI2c,LSM6DSL_ACC_GYRO_I2C_ADDRESS_LOW,PD_11); // low address
screamer 10:b27c962b3c3f 35 static LIS3MDL magnetometer(&devI2c);
screamer 10:b27c962b3c3f 36 static DigitalOut shutdown_pin(PC_6);
screamer 11:8df4529f060d 37 // static VL53L0X range(&devI2c, &shutdown_pin, PC_7);
screamer 10:b27c962b3c3f 38
screamer 10:b27c962b3c3f 39 InterruptIn button(USER_BUTTON);
screamer 11:8df4529f060d 40 #define SENSORS_POLL_INTERVAL 1.0
screamer 10:b27c962b3c3f 41 #endif /* SENSORS_AND_BUTTONS */
adustm 1:e86b1cffc402 42
adustm 4:cf7342047b4d 43 // An event queue is a very useful structure to debounce information between contexts (e.g. ISR and normal threads)
adustm 4:cf7342047b4d 44 // 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
adustm 4:cf7342047b4d 45 EventQueue eventQueue;
adustm 1:e86b1cffc402 46
MarceloSalazar 9:265744785d33 47 // Default network interface object
MarceloSalazar 9:265744785d33 48 NetworkInterface *net;
adustm 6:e0e1e1b93099 49
MarceloSalazar 9:265744785d33 50 // Default block device
MarceloSalazar 9:265744785d33 51 BlockDevice* bd = BlockDevice::get_default_instance();
screamer 10:b27c962b3c3f 52 SlicingBlockDevice sd(bd, 0, 2*1024*1024);
screamer 10:b27c962b3c3f 53 LittleFileSystem fs("fs", &sd);
adustm 4:cf7342047b4d 54
screamer 11:8df4529f060d 55 // Default LED to use for PUT/POST
screamer 11:8df4529f060d 56 DigitalOut led(LED1);
screamer 11:8df4529f060d 57
MarceloSalazar 9:265744785d33 58 // Declaring pointers for access to Pelion Client resources outside of main()
adustm 4:cf7342047b4d 59 MbedCloudClientResource *button_res;
screamer 11:8df4529f060d 60 MbedCloudClientResource *led_res;
adustm 1:e86b1cffc402 61
screamer 10:b27c962b3c3f 62 #ifdef SENSORS_AND_BUTTONS
screamer 10:b27c962b3c3f 63 // Additional resources for sensor readings
screamer 10:b27c962b3c3f 64 MbedCloudClientResource *humidity_res;
screamer 10:b27c962b3c3f 65 MbedCloudClientResource *temperature_res;
screamer 10:b27c962b3c3f 66 MbedCloudClientResource *distance_res;
screamer 10:b27c962b3c3f 67 #endif /* SENSORS_AND_BUTTONS */
adustm 1:e86b1cffc402 68
screamer 10:b27c962b3c3f 69 // When the device is registered, this variable will be used to access various useful information, like device ID etc.
screamer 10:b27c962b3c3f 70 static const ConnectorClientEndpointInfo* endpointInfo;
adustm 1:e86b1cffc402 71
screamer 10:b27c962b3c3f 72 /**
adustm 4:cf7342047b4d 73 * PUT handler
adustm 4:cf7342047b4d 74 * @param resource The resource that triggered the callback
adustm 4:cf7342047b4d 75 * @param newValue Updated value for the resource
adustm 4:cf7342047b4d 76 */
screamer 11:8df4529f060d 77 void led_put_callback(MbedCloudClientResource *resource, m2m::String newValue) {
adustm 4:cf7342047b4d 78 printf("PUT received, new value: %s\n", newValue.c_str());
screamer 11:8df4529f060d 79 led = atoi(newValue.c_str());
adustm 1:e86b1cffc402 80 }
adustm 1:e86b1cffc402 81
adustm 4:cf7342047b4d 82 /**
adustm 4:cf7342047b4d 83 * POST handler
adustm 4:cf7342047b4d 84 * @param resource The resource that triggered the callback
adustm 4:cf7342047b4d 85 * @param buffer If a body was passed to the POST function, this contains the data.
adustm 4:cf7342047b4d 86 * Note that the buffer is deallocated after leaving this function, so copy it if you need it longer.
adustm 4:cf7342047b4d 87 * @param size Size of the body
adustm 4:cf7342047b4d 88 */
screamer 11:8df4529f060d 89 void led_post_callback(MbedCloudClientResource *resource, const uint8_t *buffer, uint16_t size) {
screamer 11:8df4529f060d 90 printf("POST received. Going to blink LED pattern: %s\n", led_res->get_value().c_str());
screamer 11:8df4529f060d 91 led = atoi(led_res->get_value().c_str());
screamer 11:8df4529f060d 92 }
adustm 1:e86b1cffc402 93
screamer 11:8df4529f060d 94 /**
screamer 11:8df4529f060d 95 * Button function triggered by the physical button press or by timer depending on SENSORS_AND_BUTTONS macro.
screamer 11:8df4529f060d 96 */
screamer 11:8df4529f060d 97 void button_press() {
screamer 11:8df4529f060d 98 int v = button_res->get_value_int() + 1;
screamer 11:8df4529f060d 99 button_res->set_value(v);
screamer 11:8df4529f060d 100 printf("Button clicked %d times\n", v);
adustm 1:e86b1cffc402 101 }
adustm 1:e86b1cffc402 102
adustm 4:cf7342047b4d 103 /**
adustm 4:cf7342047b4d 104 * Notification callback handler
adustm 4:cf7342047b4d 105 * @param resource The resource that triggered the callback
adustm 4:cf7342047b4d 106 * @param status The delivery status of the notification
adustm 4:cf7342047b4d 107 */
adustm 4:cf7342047b4d 108 void button_callback(MbedCloudClientResource *resource, const NoticationDeliveryStatus status) {
adustm 4:cf7342047b4d 109 printf("Button notification, status %s (%d)\n", MbedCloudClientResource::delivery_status_to_string(status), status);
adustm 4:cf7342047b4d 110 }
adustm 1:e86b1cffc402 111
adustm 4:cf7342047b4d 112 /**
adustm 4:cf7342047b4d 113 * Registration callback handler
adustm 4:cf7342047b4d 114 * @param endpoint Information about the registered endpoint such as the name (so you can find it back in portal)
adustm 4:cf7342047b4d 115 */
adustm 4:cf7342047b4d 116 void registered(const ConnectorClientEndpointInfo *endpoint) {
MarceloSalazar 9:265744785d33 117 printf("Connected to Pelion Device Management. Endpoint Name: %s\n", endpoint->internal_endpoint_name.c_str());
screamer 10:b27c962b3c3f 118 endpointInfo = endpoint;
adustm 4:cf7342047b4d 119 }
adustm 1:e86b1cffc402 120
screamer 10:b27c962b3c3f 121 /**
screamer 10:b27c962b3c3f 122 * Initialize sensors
screamer 10:b27c962b3c3f 123 */
screamer 11:8df4529f060d 124 #ifdef SENSORS_AND_BUTTONS
screamer 10:b27c962b3c3f 125 void sensors_init() {
screamer 10:b27c962b3c3f 126 uint8_t id;
screamer 10:b27c962b3c3f 127
screamer 10:b27c962b3c3f 128 // Initialize sensors
screamer 10:b27c962b3c3f 129 hum_temp.init(NULL);
screamer 10:b27c962b3c3f 130 press_temp.init(NULL);
screamer 10:b27c962b3c3f 131 acc_gyro.init(NULL);
screamer 10:b27c962b3c3f 132 magnetometer.init(NULL);
screamer 11:8df4529f060d 133 // range.init_sensor(VL53L0X_DEFAULT_ADDRESS);
screamer 10:b27c962b3c3f 134
screamer 10:b27c962b3c3f 135 /// Call sensors enable routines
screamer 10:b27c962b3c3f 136 hum_temp.enable();
screamer 10:b27c962b3c3f 137 press_temp.enable();
screamer 10:b27c962b3c3f 138 //magnetometer.enable();
screamer 10:b27c962b3c3f 139 acc_gyro.enable_x();
screamer 10:b27c962b3c3f 140 acc_gyro.enable_g();
screamer 10:b27c962b3c3f 141
screamer 10:b27c962b3c3f 142 printf("\033[2J\033[20A");
screamer 10:b27c962b3c3f 143 printf ("\r\n--- Sensors configuration ---\r\n\r\n");
screamer 10:b27c962b3c3f 144
screamer 10:b27c962b3c3f 145 hum_temp.read_id(&id);
screamer 10:b27c962b3c3f 146 printf("HTS221 humidity & temperature = 0x%X\r\n", id);
screamer 10:b27c962b3c3f 147 press_temp.read_id(&id);
screamer 10:b27c962b3c3f 148 printf("LPS22HB pressure & temperature = 0x%X\r\n", id);
screamer 10:b27c962b3c3f 149 magnetometer.read_id(&id);
screamer 10:b27c962b3c3f 150 printf("LIS3MDL magnetometer = 0x%X\r\n", id);
screamer 10:b27c962b3c3f 151 acc_gyro.read_id(&id);
screamer 10:b27c962b3c3f 152 printf("LSM6DSL accelerometer & gyroscope = 0x%X\r\n", id);
screamer 10:b27c962b3c3f 153
screamer 10:b27c962b3c3f 154 printf("\n\r--- Reading sensor values ---\n\r"); ;
screamer 10:b27c962b3c3f 155 }
screamer 10:b27c962b3c3f 156
screamer 10:b27c962b3c3f 157 /**
screamer 10:b27c962b3c3f 158 * Update sensors and report their values.
screamer 10:b27c962b3c3f 159 * This function is called periodically.
screamer 10:b27c962b3c3f 160 */
screamer 10:b27c962b3c3f 161 void sensors_update() {
screamer 10:b27c962b3c3f 162 float value1, value2;
screamer 10:b27c962b3c3f 163 int32_t axes[3];
screamer 10:b27c962b3c3f 164 uint32_t distance;
screamer 10:b27c962b3c3f 165
screamer 10:b27c962b3c3f 166 printf("\r\n");
screamer 10:b27c962b3c3f 167
screamer 10:b27c962b3c3f 168 value1 = value2 = 0.0;
screamer 10:b27c962b3c3f 169 hum_temp.get_temperature(&value1);
screamer 10:b27c962b3c3f 170 hum_temp.get_humidity(&value2);
screamer 10:b27c962b3c3f 171 if (endpointInfo) {
screamer 10:b27c962b3c3f 172 temperature_res->set_value(value1);
screamer 10:b27c962b3c3f 173 humidity_res->set_value(value2);
screamer 10:b27c962b3c3f 174 }
screamer 10:b27c962b3c3f 175 printf("HTS221: [temp] %.2f C, [hum] %.2f%%\r\n", value1, value2);
screamer 10:b27c962b3c3f 176
screamer 10:b27c962b3c3f 177 value1 = value2 = 0.0;
screamer 10:b27c962b3c3f 178 press_temp.get_temperature(&value1);
screamer 11:8df4529f060d 179 // press_temp.get_pressure(&value2);
screamer 10:b27c962b3c3f 180 printf("LPS22HB: [temp] %.2f C, [press] %.2f mbar\r\n", value1, value2);
screamer 10:b27c962b3c3f 181 printf("Mag/Acc/Gyro readings: x, y, z\r\n");
screamer 10:b27c962b3c3f 182
screamer 10:b27c962b3c3f 183 magnetometer.get_m_axes(axes);
screamer 10:b27c962b3c3f 184 printf("LIS3MDL [mag/mgauss]: %6ld, %6ld, %6ld\r\n", axes[0], axes[1], axes[2]);
screamer 10:b27c962b3c3f 185 acc_gyro.get_x_axes(axes);
screamer 10:b27c962b3c3f 186 printf("LSM6DSL [acc/mg]: %6ld, %6ld, %6ld\r\n", axes[0], axes[1], axes[2]);
screamer 10:b27c962b3c3f 187 acc_gyro.get_g_axes(axes);
screamer 10:b27c962b3c3f 188 printf("LSM6DSL [gyro/mdps]: %6ld, %6ld, %6ld\r\n", axes[0], axes[1], axes[2]);
screamer 10:b27c962b3c3f 189
screamer 11:8df4529f060d 190 // if (range.get_distance(&distance) == VL53L0X_ERROR_NONE) {
screamer 11:8df4529f060d 191 // printf("VL53L0X [mm]: %6ld\r\n", distance);
screamer 11:8df4529f060d 192 // if (endpointInfo) {
screamer 11:8df4529f060d 193 // distance_res->set_value((int)distance);
screamer 11:8df4529f060d 194 // }
screamer 11:8df4529f060d 195 // } else {
screamer 11:8df4529f060d 196 // printf("VL53L0X [mm]: --\r\n");
screamer 11:8df4529f060d 197 // }
screamer 10:b27c962b3c3f 198
screamer 11:8df4529f060d 199 printf("\033[7A");
screamer 10:b27c962b3c3f 200 }
screamer 10:b27c962b3c3f 201 #endif /* SENSORS_AND_BUTTONS */
screamer 10:b27c962b3c3f 202
screamer 10:b27c962b3c3f 203
adustm 4:cf7342047b4d 204 int main(void) {
MarceloSalazar 9:265744785d33 205 printf("Starting Simple Pelion Device Management Client example\n");
adustm 4:cf7342047b4d 206 printf("Connecting to the network using Wifi...\n");
adustm 4:cf7342047b4d 207
screamer 10:b27c962b3c3f 208 // If the User button is pressed, then format storage.
screamer 10:b27c962b3c3f 209 const int PRESSED = 0;
screamer 10:b27c962b3c3f 210 DigitalIn *user_button = new DigitalIn(USER_BUTTON);
screamer 10:b27c962b3c3f 211 if (user_button->read() == PRESSED) {
screamer 10:b27c962b3c3f 212 printf("User button is pushed on start. Formatting the storage...\n");
screamer 10:b27c962b3c3f 213 int storage_status = fs.reformat(&sd);
screamer 10:b27c962b3c3f 214 if (storage_status != 0) {
screamer 10:b27c962b3c3f 215 if (sd.erase(0, sd.size()) == 0) {
screamer 10:b27c962b3c3f 216 if (fs.format(&sd) == 0) {
screamer 10:b27c962b3c3f 217 storage_status = 0;
screamer 10:b27c962b3c3f 218 printf("The storage reformatted successfully.\n");
screamer 10:b27c962b3c3f 219 }
screamer 10:b27c962b3c3f 220 }
screamer 10:b27c962b3c3f 221 }
screamer 10:b27c962b3c3f 222 if (storage_status != 0) {
screamer 10:b27c962b3c3f 223 printf("Failed to reformat the storage.\n");
screamer 10:b27c962b3c3f 224 }
screamer 10:b27c962b3c3f 225 }
screamer 10:b27c962b3c3f 226
screamer 10:b27c962b3c3f 227 #ifdef SENSORS_AND_BUTTONS
screamer 10:b27c962b3c3f 228 sensors_init();
screamer 10:b27c962b3c3f 229 #endif /* SENSORS_AND_BUTTONS */
screamer 10:b27c962b3c3f 230
adustm 4:cf7342047b4d 231 // Connect to the internet (DHCP is expected to be on)
MarceloSalazar 9:265744785d33 232 net = NetworkInterface::get_default_instance();
adustm 4:cf7342047b4d 233
screamer 10:b27c962b3c3f 234 nsapi_error_t net_status = -1;
screamer 10:b27c962b3c3f 235 for (int tries = 0; tries < 3; tries++) {
screamer 10:b27c962b3c3f 236 net_status = net->connect();
screamer 10:b27c962b3c3f 237 if (net_status == NSAPI_ERROR_OK) {
screamer 10:b27c962b3c3f 238 break;
screamer 10:b27c962b3c3f 239 } else {
screamer 10:b27c962b3c3f 240 printf("[WARN] Unable to connect to network. Retrying...\n");
screamer 10:b27c962b3c3f 241 }
screamer 10:b27c962b3c3f 242 }
MarceloSalazar 9:265744785d33 243
screamer 10:b27c962b3c3f 244 if (net_status != NSAPI_ERROR_OK) {
screamer 10:b27c962b3c3f 245 printf("Connecting to the network failed %d!\n", net_status);
adustm 1:e86b1cffc402 246 return -1;
adustm 1:e86b1cffc402 247 }
adustm 1:e86b1cffc402 248
MarceloSalazar 9:265744785d33 249 printf("Connected to the network successfully. IP address: %s\n", net->get_ip_address());
adustm 1:e86b1cffc402 250
MarceloSalazar 9:265744785d33 251 // SimpleMbedCloudClient handles registering over LwM2M to Pelion DM
MarceloSalazar 9:265744785d33 252 SimpleMbedCloudClient client(net, bd, &fs);
adustm 4:cf7342047b4d 253 int client_status = client.init();
adustm 4:cf7342047b4d 254 if (client_status != 0) {
MarceloSalazar 9:265744785d33 255 printf("Pelion Client initialization failed (%d)\n", client_status);
adustm 1:e86b1cffc402 256 return -1;
adustm 1:e86b1cffc402 257 }
adustm 1:e86b1cffc402 258
adustm 4:cf7342047b4d 259 // Creating resources, which can be written or read from the cloud
adustm 4:cf7342047b4d 260 button_res = client.create_resource("3200/0/5501", "button_count");
adustm 4:cf7342047b4d 261 button_res->set_value(0);
adustm 4:cf7342047b4d 262 button_res->methods(M2MMethod::GET);
adustm 4:cf7342047b4d 263 button_res->observable(true);
adustm 4:cf7342047b4d 264 button_res->attach_notification_callback(button_callback);
adustm 1:e86b1cffc402 265
screamer 10:b27c962b3c3f 266 #ifdef SENSORS_AND_BUTTONS
screamer 10:b27c962b3c3f 267 // Sensor resources
screamer 10:b27c962b3c3f 268 temperature_res = client.create_resource("3303/0/5700", "temperature");
screamer 10:b27c962b3c3f 269 temperature_res->set_value(0);
screamer 10:b27c962b3c3f 270 temperature_res->methods(M2MMethod::GET);
screamer 10:b27c962b3c3f 271 temperature_res->observable(true);
screamer 10:b27c962b3c3f 272
screamer 10:b27c962b3c3f 273 humidity_res = client.create_resource("3304/0/5700", "humidity");
screamer 10:b27c962b3c3f 274 humidity_res->set_value(0);
screamer 10:b27c962b3c3f 275 humidity_res->methods(M2MMethod::GET);
screamer 10:b27c962b3c3f 276 humidity_res->observable(true);
screamer 10:b27c962b3c3f 277
screamer 11:8df4529f060d 278 // distance_res = client.create_resource("3330/0/5700", "distance");
screamer 11:8df4529f060d 279 // distance_res->set_value(0);
screamer 11:8df4529f060d 280 // distance_res->methods(M2MMethod::GET);
screamer 11:8df4529f060d 281 // distance_res->observable(true);
screamer 10:b27c962b3c3f 282 #endif /* SENSORS_AND_BUTTONS */
screamer 10:b27c962b3c3f 283
screamer 11:8df4529f060d 284 // led_res = client.create_resource("3201/0/5853", "led_state");
screamer 11:8df4529f060d 285 // led_res->set_value(1);
screamer 11:8df4529f060d 286 // led_res->methods(M2MMethod::GET | M2MMethod::PUT);
screamer 11:8df4529f060d 287 // led_res->attach_put_callback(led_put_callback);
screamer 11:8df4529f060d 288
MarceloSalazar 9:265744785d33 289 printf("Initialized Pelion Client. Registering...\n");
adustm 1:e86b1cffc402 290
adustm 4:cf7342047b4d 291 // Callback that fires when registering is complete
adustm 4:cf7342047b4d 292 client.on_registered(&registered);
adustm 1:e86b1cffc402 293
MarceloSalazar 9:265744785d33 294 // Register with Pelion DM
adustm 4:cf7342047b4d 295 client.register_and_connect();
adustm 1:e86b1cffc402 296
adustm 1:e86b1cffc402 297 // Placeholder for callback to update local resource when GET comes.
adustm 4:cf7342047b4d 298 // The timer fires on an interrupt context, but debounces it to the eventqueue, so it's safe to do network operations
screamer 10:b27c962b3c3f 299 #ifdef SENSORS_AND_BUTTONS
screamer 11:8df4529f060d 300 button.fall(eventQueue.event(&button_press));
screamer 10:b27c962b3c3f 301
adustm 4:cf7342047b4d 302 Ticker timer;
screamer 11:8df4529f060d 303 timer.attach(eventQueue.event(&sensors_update), SENSORS_POLL_INTERVAL);
screamer 10:b27c962b3c3f 304 #else /* SENSORS_AND_BUTTONS */
screamer 10:b27c962b3c3f 305 Ticker timer;
screamer 10:b27c962b3c3f 306 timer.attach(eventQueue.event(&button_press), 5.0);
screamer 10:b27c962b3c3f 307 #endif /* SENSORS_AND_BUTTONS */
adustm 1:e86b1cffc402 308
adustm 4:cf7342047b4d 309 // You can easily run the eventQueue in a separate thread if required
adustm 4:cf7342047b4d 310 eventQueue.dispatch_forever();
adustm 1:e86b1cffc402 311 }
MarceloSalazar 9:265744785d33 312 #endif