Template coding for ST IoT Challenge 2019

Dependencies:   Cayenne-MQTT-mbed mbed X_NUCLEO_IKS01A2 X_NUCLEO_IDW01M1v2 NetworkSocketAPI

Committer:
stiotchallenge
Date:
Tue Mar 05 00:40:56 2019 +0000
Revision:
19:d2a08ee64c36
Parent:
18:aedf981aa752
Child:
20:51804ecf98a1
STM32F411RE with WiFi expansion, MEMS sensor and Cayenne IoT

Who changed what in which revision?

UserRevisionLine numberNew contents of line
cparata 0:69566eea0fba 1 /* Includes */
cparata 0:69566eea0fba 2 #include "mbed.h"
davide.aliprandi@st.com 13:fc873da5b445 3 #include "XNucleoIKS01A2.h"
stiotchallenge 18:aedf981aa752 4 #include "MQTTTimer.h"
stiotchallenge 18:aedf981aa752 5 #include "CayenneMQTTClient.h"
stiotchallenge 18:aedf981aa752 6 #include "MQTTNetworkIDW01M1.h"
stiotchallenge 18:aedf981aa752 7 #include "SpwfInterface.h"
cparata 0:69566eea0fba 8
cparata 0:69566eea0fba 9 /* Instantiate the expansion board */
davide.aliprandi@st.com 13:fc873da5b445 10 static XNucleoIKS01A2 *mems_expansion_board = XNucleoIKS01A2::instance(D14, D15, D4, D5);
cparata 0:69566eea0fba 11
cparata 0:69566eea0fba 12 /* Retrieve the composing elements of the expansion board */
davide.aliprandi@st.com 13:fc873da5b445 13 static LSM303AGRMagSensor *magnetometer = mems_expansion_board->magnetometer;
cparata 0:69566eea0fba 14 static HTS221Sensor *hum_temp = mems_expansion_board->ht_sensor;
cparata 0:69566eea0fba 15 static LPS22HBSensor *press_temp = mems_expansion_board->pt_sensor;
cparata 0:69566eea0fba 16 static LSM6DSLSensor *acc_gyro = mems_expansion_board->acc_gyro;
davide.aliprandi@st.com 13:fc873da5b445 17 static LSM303AGRAccSensor *accelerometer = mems_expansion_board->accelerometer;
cparata 0:69566eea0fba 18
stiotchallenge 18:aedf981aa752 19 // WiFi network info.
stiotchallenge 19:d2a08ee64c36 20 char* ssid = "wifi_ssid";
stiotchallenge 19:d2a08ee64c36 21 char* wifiPassword = "wifi_password";
stiotchallenge 18:aedf981aa752 22
stiotchallenge 18:aedf981aa752 23 // Cayenne authentication info. This should be obtained from the Cayenne Dashboard.
stiotchallenge 18:aedf981aa752 24 char* username = "4f3fbcb0-3796-11e9-ad96-c15442ccb423";
stiotchallenge 18:aedf981aa752 25 char* password = "9e099f3d9aaedd7b76ca94044c6bb488c3999e3c";
stiotchallenge 18:aedf981aa752 26 char* clientID = "a22a2090-3797-11e9-8f2a-a7100372a66b";
stiotchallenge 18:aedf981aa752 27
stiotchallenge 18:aedf981aa752 28 SpwfSAInterface interface(D8, D2); // TX, RX
stiotchallenge 18:aedf981aa752 29 MQTTNetwork<SpwfSAInterface> network(interface);
stiotchallenge 18:aedf981aa752 30 CayenneMQTT::MQTTClient<MQTTNetwork<SpwfSAInterface>, MQTTTimer> mqttClient(network, username, password, clientID);
stiotchallenge 18:aedf981aa752 31
stiotchallenge 18:aedf981aa752 32 DigitalOut led1(LED1);
stiotchallenge 18:aedf981aa752 33
cparata 0:69566eea0fba 34 /* Helper function for printing floats & doubles */
davide.aliprandi@st.com 13:fc873da5b445 35 static char *print_double(char* str, double v, int decimalDigits=2)
cparata 0:69566eea0fba 36 {
cparata 0:69566eea0fba 37 int i = 1;
cparata 0:69566eea0fba 38 int intPart, fractPart;
cparata 0:69566eea0fba 39 int len;
cparata 0:69566eea0fba 40 char *ptr;
cparata 0:69566eea0fba 41
cparata 0:69566eea0fba 42 /* prepare decimal digits multiplicator */
cparata 0:69566eea0fba 43 for (;decimalDigits!=0; i*=10, decimalDigits--);
cparata 0:69566eea0fba 44
cparata 0:69566eea0fba 45 /* calculate integer & fractinal parts */
cparata 0:69566eea0fba 46 intPart = (int)v;
cparata 0:69566eea0fba 47 fractPart = (int)((v-(double)(int)v)*i);
cparata 0:69566eea0fba 48
cparata 0:69566eea0fba 49 /* fill in integer part */
cparata 0:69566eea0fba 50 sprintf(str, "%i.", intPart);
cparata 0:69566eea0fba 51
cparata 0:69566eea0fba 52 /* prepare fill in of fractional part */
cparata 0:69566eea0fba 53 len = strlen(str);
cparata 0:69566eea0fba 54 ptr = &str[len];
cparata 0:69566eea0fba 55
cparata 0:69566eea0fba 56 /* fill in leading fractional zeros */
cparata 0:69566eea0fba 57 for (i/=10;i>1; i/=10, ptr++) {
davide.aliprandi@st.com 13:fc873da5b445 58 if (fractPart >= i) {
davide.aliprandi@st.com 13:fc873da5b445 59 break;
davide.aliprandi@st.com 13:fc873da5b445 60 }
cparata 0:69566eea0fba 61 *ptr = '0';
cparata 0:69566eea0fba 62 }
cparata 0:69566eea0fba 63
cparata 0:69566eea0fba 64 /* fill in (rest of) fractional part */
cparata 0:69566eea0fba 65 sprintf(ptr, "%i", fractPart);
cparata 0:69566eea0fba 66
cparata 0:69566eea0fba 67 return str;
cparata 0:69566eea0fba 68 }
cparata 0:69566eea0fba 69
stiotchallenge 18:aedf981aa752 70 /**
stiotchallenge 18:aedf981aa752 71 * Print the message info.
stiotchallenge 18:aedf981aa752 72 * @param[in] message The message received from the Cayenne server.
stiotchallenge 18:aedf981aa752 73 */
stiotchallenge 18:aedf981aa752 74 void outputMessage(CayenneMQTT::MessageData& message)
stiotchallenge 18:aedf981aa752 75 {
stiotchallenge 18:aedf981aa752 76 switch (message.topic) {
stiotchallenge 18:aedf981aa752 77 case COMMAND_TOPIC:
stiotchallenge 18:aedf981aa752 78 printf("topic=Command");
stiotchallenge 18:aedf981aa752 79 break;
stiotchallenge 18:aedf981aa752 80 case CONFIG_TOPIC:
stiotchallenge 18:aedf981aa752 81 printf("topic=Config");
stiotchallenge 18:aedf981aa752 82 break;
stiotchallenge 18:aedf981aa752 83 default:
stiotchallenge 18:aedf981aa752 84 printf("topic=%d", message.topic);
stiotchallenge 18:aedf981aa752 85 break;
stiotchallenge 18:aedf981aa752 86 }
stiotchallenge 18:aedf981aa752 87 printf(" channel=%d", message.channel);
stiotchallenge 18:aedf981aa752 88 if (message.clientID) {
stiotchallenge 18:aedf981aa752 89 printf(" clientID=%s", message.clientID);
stiotchallenge 18:aedf981aa752 90 }
stiotchallenge 18:aedf981aa752 91 if (message.type) {
stiotchallenge 18:aedf981aa752 92 printf(" type=%s", message.type);
stiotchallenge 18:aedf981aa752 93 }
stiotchallenge 18:aedf981aa752 94 for (size_t i = 0; i < message.valueCount; ++i) {
stiotchallenge 18:aedf981aa752 95 if (message.getValue(i)) {
stiotchallenge 18:aedf981aa752 96 printf(" value=%s", message.getValue(i));
stiotchallenge 18:aedf981aa752 97 }
stiotchallenge 18:aedf981aa752 98 if (message.getUnit(i)) {
stiotchallenge 18:aedf981aa752 99 printf(" unit=%s", message.getUnit(i));
stiotchallenge 18:aedf981aa752 100 }
stiotchallenge 18:aedf981aa752 101 }
stiotchallenge 18:aedf981aa752 102 if (message.id) {
stiotchallenge 18:aedf981aa752 103 printf(" id=%s", message.id);
stiotchallenge 18:aedf981aa752 104 }
stiotchallenge 18:aedf981aa752 105 printf("\n");
stiotchallenge 18:aedf981aa752 106 }
stiotchallenge 18:aedf981aa752 107
stiotchallenge 18:aedf981aa752 108 /**
stiotchallenge 18:aedf981aa752 109 * Handle messages received from the Cayenne server.
stiotchallenge 18:aedf981aa752 110 * @param[in] message The message received from the Cayenne server.
stiotchallenge 18:aedf981aa752 111 */
stiotchallenge 18:aedf981aa752 112 void messageArrived(CayenneMQTT::MessageData& message)
stiotchallenge 18:aedf981aa752 113 {
stiotchallenge 18:aedf981aa752 114 int error = 0;
stiotchallenge 18:aedf981aa752 115 // Add code to process the message. Here we just ouput the message data.
stiotchallenge 18:aedf981aa752 116 outputMessage(message);
stiotchallenge 18:aedf981aa752 117
stiotchallenge 18:aedf981aa752 118 if (message.topic == COMMAND_TOPIC) {
stiotchallenge 18:aedf981aa752 119 switch(message.channel) {
stiotchallenge 18:aedf981aa752 120 case 0:
stiotchallenge 18:aedf981aa752 121 // Set the onboard LED state
stiotchallenge 18:aedf981aa752 122 led1 = atoi(message.getValue());
stiotchallenge 18:aedf981aa752 123 // Publish the updated LED state
stiotchallenge 18:aedf981aa752 124 if ((error = mqttClient.publishData(DATA_TOPIC, message.channel, NULL, NULL, message.getValue())) != CAYENNE_SUCCESS) {
stiotchallenge 18:aedf981aa752 125 printf("Publish LED state failure, error: %d\n", error);
stiotchallenge 18:aedf981aa752 126 }
stiotchallenge 18:aedf981aa752 127 break;
stiotchallenge 18:aedf981aa752 128 }
stiotchallenge 18:aedf981aa752 129
stiotchallenge 18:aedf981aa752 130 // If this is a command message we publish a response. Here we are just sending a default 'OK' response.
stiotchallenge 18:aedf981aa752 131 // An error response should be sent if there are issues processing the message.
stiotchallenge 18:aedf981aa752 132 if ((error = mqttClient.publishResponse(message.id, NULL, message.clientID)) != CAYENNE_SUCCESS) {
stiotchallenge 18:aedf981aa752 133 printf("Response failure, error: %d\n", error);
stiotchallenge 18:aedf981aa752 134 }
stiotchallenge 18:aedf981aa752 135 }
stiotchallenge 18:aedf981aa752 136 }
stiotchallenge 18:aedf981aa752 137
stiotchallenge 18:aedf981aa752 138 /**
stiotchallenge 18:aedf981aa752 139 * Connect to the Cayenne server.
stiotchallenge 18:aedf981aa752 140 * @return Returns CAYENNE_SUCCESS if the connection succeeds, or an error code otherwise.
stiotchallenge 18:aedf981aa752 141 */
stiotchallenge 18:aedf981aa752 142 int connectClient(void)
stiotchallenge 18:aedf981aa752 143 {
stiotchallenge 18:aedf981aa752 144 int error = 0;
stiotchallenge 18:aedf981aa752 145 // Connect to the server.
stiotchallenge 18:aedf981aa752 146 printf("Connecting to %s:%d\n", CAYENNE_DOMAIN, CAYENNE_PORT);
stiotchallenge 18:aedf981aa752 147 while ((error = network.connect(CAYENNE_DOMAIN, CAYENNE_PORT)) != 0) {
stiotchallenge 18:aedf981aa752 148 printf("TCP connect failed, error: %d\n", error);
stiotchallenge 18:aedf981aa752 149 wait(2);
stiotchallenge 18:aedf981aa752 150 }
stiotchallenge 18:aedf981aa752 151
stiotchallenge 18:aedf981aa752 152 if ((error = mqttClient.connect()) != MQTT::SUCCESS) {
stiotchallenge 18:aedf981aa752 153 printf("MQTT connect failed, error: %d\n", error);
stiotchallenge 18:aedf981aa752 154 return error;
stiotchallenge 18:aedf981aa752 155 }
stiotchallenge 18:aedf981aa752 156 printf("Connected\n");
stiotchallenge 18:aedf981aa752 157
stiotchallenge 18:aedf981aa752 158 // Subscribe to required topics.
stiotchallenge 18:aedf981aa752 159 if ((error = mqttClient.subscribe(COMMAND_TOPIC, CAYENNE_ALL_CHANNELS)) != CAYENNE_SUCCESS) {
stiotchallenge 18:aedf981aa752 160 printf("Subscription to Command topic failed, error: %d\n", error);
stiotchallenge 18:aedf981aa752 161 }
stiotchallenge 18:aedf981aa752 162 if ((error = mqttClient.subscribe(CONFIG_TOPIC, CAYENNE_ALL_CHANNELS)) != CAYENNE_SUCCESS) {
stiotchallenge 18:aedf981aa752 163 printf("Subscription to Config topic failed, error:%d\n", error);
stiotchallenge 18:aedf981aa752 164 }
stiotchallenge 18:aedf981aa752 165
stiotchallenge 18:aedf981aa752 166 // Send device info. Here we just send some example values for the system info. These should be changed to use actual system data, or removed if not needed.
stiotchallenge 18:aedf981aa752 167 mqttClient.publishData(SYS_VERSION_TOPIC, CAYENNE_NO_CHANNEL, NULL, NULL, CAYENNE_VERSION);
stiotchallenge 18:aedf981aa752 168 mqttClient.publishData(SYS_MODEL_TOPIC, CAYENNE_NO_CHANNEL, NULL, NULL, "mbedDevice");
stiotchallenge 18:aedf981aa752 169 //mqttClient.publishData(SYS_CPU_MODEL_TOPIC, CAYENNE_NO_CHANNEL, NULL, NULL, "CPU Model");
stiotchallenge 18:aedf981aa752 170 //mqttClient.publishData(SYS_CPU_SPEED_TOPIC, CAYENNE_NO_CHANNEL, NULL, NULL, "1000000000");
stiotchallenge 18:aedf981aa752 171
stiotchallenge 18:aedf981aa752 172 return CAYENNE_SUCCESS;
stiotchallenge 18:aedf981aa752 173 }
stiotchallenge 18:aedf981aa752 174
cparata 0:69566eea0fba 175 /* Simple main function */
cparata 0:69566eea0fba 176 int main() {
stiotchallenge 18:aedf981aa752 177 uint8_t id;
stiotchallenge 18:aedf981aa752 178 float value1, value2, value3, value4;
stiotchallenge 18:aedf981aa752 179 char buffer1[32], buffer2[32], buffer3[32], buffer4[32];
stiotchallenge 18:aedf981aa752 180 int32_t axes[3];
cparata 0:69566eea0fba 181
stiotchallenge 18:aedf981aa752 182 /* Enable all sensors */
stiotchallenge 18:aedf981aa752 183 hum_temp->enable();
stiotchallenge 18:aedf981aa752 184 press_temp->enable();
stiotchallenge 18:aedf981aa752 185 magnetometer->enable();
stiotchallenge 18:aedf981aa752 186 accelerometer->enable();
stiotchallenge 18:aedf981aa752 187 acc_gyro->enable_x();
stiotchallenge 18:aedf981aa752 188 acc_gyro->enable_g();
cparata 0:69566eea0fba 189
stiotchallenge 18:aedf981aa752 190 printf("\r\n--- Starting new run ---\r\n");
cparata 0:69566eea0fba 191
stiotchallenge 18:aedf981aa752 192 hum_temp->read_id(&id);
stiotchallenge 18:aedf981aa752 193 printf("HTS221 humidity & temperature = 0x%X\r\n", id);
stiotchallenge 18:aedf981aa752 194 press_temp->read_id(&id);
stiotchallenge 18:aedf981aa752 195 printf("LPS22HB pressure & temperature = 0x%X\r\n", id);
stiotchallenge 18:aedf981aa752 196 magnetometer->read_id(&id);
stiotchallenge 18:aedf981aa752 197 printf("LSM303AGR magnetometer = 0x%X\r\n", id);
stiotchallenge 18:aedf981aa752 198 accelerometer->read_id(&id);
stiotchallenge 18:aedf981aa752 199 printf("LSM303AGR accelerometer = 0x%X\r\n", id);
stiotchallenge 18:aedf981aa752 200 acc_gyro->read_id(&id);
stiotchallenge 18:aedf981aa752 201 printf("LSM6DSL accelerometer & gyroscope = 0x%X\r\n", id);
cparata 0:69566eea0fba 202
stiotchallenge 18:aedf981aa752 203 // Initialize the network interface.
stiotchallenge 18:aedf981aa752 204 printf("Initializing interface\n");
stiotchallenge 18:aedf981aa752 205 interface.connect(ssid, wifiPassword, NSAPI_SECURITY_WPA2);
stiotchallenge 18:aedf981aa752 206
stiotchallenge 18:aedf981aa752 207 // Set the default function that receives Cayenne messages.
stiotchallenge 18:aedf981aa752 208 mqttClient.setDefaultMessageHandler(messageArrived);
stiotchallenge 18:aedf981aa752 209
stiotchallenge 18:aedf981aa752 210 // Connect to Cayenne.
stiotchallenge 18:aedf981aa752 211 if (connectClient() == CAYENNE_SUCCESS) {
stiotchallenge 18:aedf981aa752 212 // Start the countdown timer for publishing data every 5 seconds. Change the timeout parameter to publish at a different interval.
stiotchallenge 18:aedf981aa752 213 MQTTTimer timer(5000);
stiotchallenge 18:aedf981aa752 214
stiotchallenge 18:aedf981aa752 215 while (true) {
stiotchallenge 18:aedf981aa752 216 // Yield to allow MQTT message processing.
stiotchallenge 18:aedf981aa752 217 mqttClient.yield(1000);
cparata 0:69566eea0fba 218
stiotchallenge 18:aedf981aa752 219 // Check that we are still connected, if not, reconnect.
stiotchallenge 18:aedf981aa752 220 if (!network.connected() || !mqttClient.connected()) {
stiotchallenge 18:aedf981aa752 221 network.disconnect();
stiotchallenge 18:aedf981aa752 222 mqttClient.disconnect();
stiotchallenge 18:aedf981aa752 223 printf("Reconnecting\n");
stiotchallenge 18:aedf981aa752 224 while (connectClient() != CAYENNE_SUCCESS) {
stiotchallenge 18:aedf981aa752 225 wait(2);
stiotchallenge 18:aedf981aa752 226 printf("Reconnect failed, retrying\n");
stiotchallenge 18:aedf981aa752 227 }
stiotchallenge 18:aedf981aa752 228 }
stiotchallenge 18:aedf981aa752 229
stiotchallenge 18:aedf981aa752 230 printf("\r\n");
stiotchallenge 18:aedf981aa752 231
stiotchallenge 18:aedf981aa752 232 hum_temp->get_temperature(&value1);
stiotchallenge 18:aedf981aa752 233 hum_temp->get_humidity(&value2);
stiotchallenge 18:aedf981aa752 234 printf("HTS221: [temp] %7s C, [hum] %s%%\r\n", print_double(buffer1, value1), print_double(buffer2, value2));
cparata 0:69566eea0fba 235
stiotchallenge 18:aedf981aa752 236 press_temp->get_temperature(&value3);
stiotchallenge 18:aedf981aa752 237 press_temp->get_pressure(&value4);
stiotchallenge 18:aedf981aa752 238 printf("LPS22HB: [temp] %7s C, [press] %s mbar\r\n", print_double(buffer1, value3), print_double(buffer2, value4));
cparata 0:69566eea0fba 239
stiotchallenge 18:aedf981aa752 240 printf("---\r\n");
cparata 0:69566eea0fba 241
stiotchallenge 18:aedf981aa752 242 magnetometer->get_m_axes(axes);
stiotchallenge 18:aedf981aa752 243 printf("LSM303AGR [mag/mgauss]: %6ld, %6ld, %6ld\r\n", axes[0], axes[1], axes[2]);
cparata 0:69566eea0fba 244
stiotchallenge 18:aedf981aa752 245 acc_gyro->get_x_axes(axes);
stiotchallenge 18:aedf981aa752 246 printf("LSM6DSL [acc/mg]: %6ld, %6ld, %6ld\r\n", axes[0], axes[1], axes[2]);
cparata 0:69566eea0fba 247
stiotchallenge 18:aedf981aa752 248 accelerometer->get_x_axes(axes);
stiotchallenge 18:aedf981aa752 249 printf("LSM303AGR [acc/mg]: %6ld, %6ld, %6ld\r\n", axes[0], axes[1], axes[2]);
stiotchallenge 18:aedf981aa752 250
stiotchallenge 18:aedf981aa752 251 acc_gyro->get_g_axes(axes);
stiotchallenge 18:aedf981aa752 252 printf("LSM6DSL [gyro/mdps]: %6ld, %6ld, %6ld\r\n", axes[0], axes[1], axes[2]);
stiotchallenge 18:aedf981aa752 253
stiotchallenge 18:aedf981aa752 254 wait(1.5);
stiotchallenge 18:aedf981aa752 255
stiotchallenge 18:aedf981aa752 256 Cayenne.virtualWrite(2, 25.2, "temp", "c");
stiotchallenge 18:aedf981aa752 257
stiotchallenge 18:aedf981aa752 258
stiotchallenge 18:aedf981aa752 259 // Publish some example data every few seconds. This should be changed to send your actual data to Cayenne.
stiotchallenge 18:aedf981aa752 260 if (timer.expired()) {
stiotchallenge 18:aedf981aa752 261 int error = 0;
stiotchallenge 18:aedf981aa752 262 if ((error = mqttClient.publishData(DATA_TOPIC, 1, TYPE_TEMPERATURE, UNIT_CELSIUS, value1)) != CAYENNE_SUCCESS) {
stiotchallenge 18:aedf981aa752 263 printf("Publish temperature failed, error: %d\n", error);
stiotchallenge 18:aedf981aa752 264 }
stiotchallenge 18:aedf981aa752 265 if ((error = mqttClient.publishData(DATA_TOPIC, 2, TYPE_BAROMETRIC_PRESSURE, UNIT_PASCAL, value4)) != CAYENNE_SUCCESS) {
stiotchallenge 18:aedf981aa752 266 printf("Publish luminosity failed, error: %d\n", error);
stiotchallenge 18:aedf981aa752 267 }
stiotchallenge 18:aedf981aa752 268 if ((error = mqttClient.publishData(DATA_TOPIC, 3, TYPE_PROXIMITY, UNIT_METER, axes[1])) != CAYENNE_SUCCESS) {
stiotchallenge 18:aedf981aa752 269 printf("Publish barometric pressure failed, error: %d\n", error);
stiotchallenge 18:aedf981aa752 270 }
stiotchallenge 18:aedf981aa752 271 // Restart the countdown timer for publishing data every 5 seconds. Change the timeout parameter to publish at a different interval.
stiotchallenge 18:aedf981aa752 272 timer.countdown_ms(5000);
stiotchallenge 18:aedf981aa752 273 }
stiotchallenge 18:aedf981aa752 274 }
stiotchallenge 18:aedf981aa752 275 }
stiotchallenge 18:aedf981aa752 276 else {
stiotchallenge 18:aedf981aa752 277 printf("Connection failed, exiting\n");
stiotchallenge 18:aedf981aa752 278 }
cparata 0:69566eea0fba 279
stiotchallenge 18:aedf981aa752 280 if (mqttClient.connected())
stiotchallenge 18:aedf981aa752 281 mqttClient.disconnect();
stiotchallenge 18:aedf981aa752 282 if (network.connected())
stiotchallenge 18:aedf981aa752 283 network.disconnect();
cparata 0:69566eea0fba 284 }