Template coding for ST IoT Challenge 2019

Dependencies:   Cayenne-MQTT-mbed mbed X_NUCLEO_IKS01A2 X_NUCLEO_IDW01M1v2 NetworkSocketAPI

Committer:
stiotchallenge
Date:
Wed Mar 06 17:24:15 2019 +0000
Revision:
21:101560c87a89
Parent:
20:51804ecf98a1
Child:
22:22570ebcc4f2
ST-IoT Challenge 2019 Coding Template

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