Template coding for ST IoT Challenge 2019
Dependencies: Cayenne-MQTT-mbed mbed X_NUCLEO_IKS01A2 X_NUCLEO_IDW01M1v2 NetworkSocketAPI
Diff: main.cpp
- Revision:
- 18:aedf981aa752
- Parent:
- 13:fc873da5b445
- Child:
- 19:d2a08ee64c36
--- a/main.cpp Wed Sep 27 15:48:21 2017 +0000 +++ b/main.cpp Mon Mar 04 21:54:31 2019 +0000 @@ -1,44 +1,10 @@ -/** - ****************************************************************************** - * @file main.cpp - * @author CLab - * @version V1.0.0 - * @date 2-December-2016 - * @brief Simple Example application for using the X_NUCLEO_IKS01A1 - * MEMS Inertial & Environmental Sensor Nucleo expansion board. - ****************************************************************************** - * @attention - * - * <h2><center>© COPYRIGHT(c) 2016 STMicroelectronics</center></h2> - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. Neither the name of STMicroelectronics nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - ****************************************************************************** -*/ - /* Includes */ #include "mbed.h" #include "XNucleoIKS01A2.h" +#include "MQTTTimer.h" +#include "CayenneMQTTClient.h" +#include "MQTTNetworkIDW01M1.h" +#include "SpwfInterface.h" /* Instantiate the expansion board */ static XNucleoIKS01A2 *mems_expansion_board = XNucleoIKS01A2::instance(D14, D15, D4, D5); @@ -50,6 +16,21 @@ static LSM6DSLSensor *acc_gyro = mems_expansion_board->acc_gyro; static LSM303AGRAccSensor *accelerometer = mems_expansion_board->accelerometer; +// WiFi network info. +char* ssid = "M514@unifi"; +char* wifiPassword = "1210EF0712"; + +// Cayenne authentication info. This should be obtained from the Cayenne Dashboard. +char* username = "4f3fbcb0-3796-11e9-ad96-c15442ccb423"; +char* password = "9e099f3d9aaedd7b76ca94044c6bb488c3999e3c"; +char* clientID = "a22a2090-3797-11e9-8f2a-a7100372a66b"; + +SpwfSAInterface interface(D8, D2); // TX, RX +MQTTNetwork<SpwfSAInterface> network(interface); +CayenneMQTT::MQTTClient<MQTTNetwork<SpwfSAInterface>, MQTTTimer> mqttClient(network, username, password, clientID); + +DigitalOut led1(LED1); + /* Helper function for printing floats & doubles */ static char *print_double(char* str, double v, int decimalDigits=2) { @@ -86,59 +67,218 @@ return str; } +/** +* Print the message info. +* @param[in] message The message received from the Cayenne server. +*/ +void outputMessage(CayenneMQTT::MessageData& message) +{ + switch (message.topic) { + case COMMAND_TOPIC: + printf("topic=Command"); + break; + case CONFIG_TOPIC: + printf("topic=Config"); + break; + default: + printf("topic=%d", message.topic); + break; + } + printf(" channel=%d", message.channel); + if (message.clientID) { + printf(" clientID=%s", message.clientID); + } + if (message.type) { + printf(" type=%s", message.type); + } + for (size_t i = 0; i < message.valueCount; ++i) { + if (message.getValue(i)) { + printf(" value=%s", message.getValue(i)); + } + if (message.getUnit(i)) { + printf(" unit=%s", message.getUnit(i)); + } + } + if (message.id) { + printf(" id=%s", message.id); + } + printf("\n"); +} + +/** +* Handle messages received from the Cayenne server. +* @param[in] message The message received from the Cayenne server. +*/ +void messageArrived(CayenneMQTT::MessageData& message) +{ + int error = 0; + // Add code to process the message. Here we just ouput the message data. + outputMessage(message); + + if (message.topic == COMMAND_TOPIC) { + switch(message.channel) { + case 0: + // Set the onboard LED state + led1 = atoi(message.getValue()); + // Publish the updated LED state + if ((error = mqttClient.publishData(DATA_TOPIC, message.channel, NULL, NULL, message.getValue())) != CAYENNE_SUCCESS) { + printf("Publish LED state failure, error: %d\n", error); + } + break; + } + + // If this is a command message we publish a response. Here we are just sending a default 'OK' response. + // An error response should be sent if there are issues processing the message. + if ((error = mqttClient.publishResponse(message.id, NULL, message.clientID)) != CAYENNE_SUCCESS) { + printf("Response failure, error: %d\n", error); + } + } +} + +/** +* Connect to the Cayenne server. +* @return Returns CAYENNE_SUCCESS if the connection succeeds, or an error code otherwise. +*/ +int connectClient(void) +{ + int error = 0; + // Connect to the server. + printf("Connecting to %s:%d\n", CAYENNE_DOMAIN, CAYENNE_PORT); + while ((error = network.connect(CAYENNE_DOMAIN, CAYENNE_PORT)) != 0) { + printf("TCP connect failed, error: %d\n", error); + wait(2); + } + + if ((error = mqttClient.connect()) != MQTT::SUCCESS) { + printf("MQTT connect failed, error: %d\n", error); + return error; + } + printf("Connected\n"); + + // Subscribe to required topics. + if ((error = mqttClient.subscribe(COMMAND_TOPIC, CAYENNE_ALL_CHANNELS)) != CAYENNE_SUCCESS) { + printf("Subscription to Command topic failed, error: %d\n", error); + } + if ((error = mqttClient.subscribe(CONFIG_TOPIC, CAYENNE_ALL_CHANNELS)) != CAYENNE_SUCCESS) { + printf("Subscription to Config topic failed, error:%d\n", error); + } + + // 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. + mqttClient.publishData(SYS_VERSION_TOPIC, CAYENNE_NO_CHANNEL, NULL, NULL, CAYENNE_VERSION); + mqttClient.publishData(SYS_MODEL_TOPIC, CAYENNE_NO_CHANNEL, NULL, NULL, "mbedDevice"); + //mqttClient.publishData(SYS_CPU_MODEL_TOPIC, CAYENNE_NO_CHANNEL, NULL, NULL, "CPU Model"); + //mqttClient.publishData(SYS_CPU_SPEED_TOPIC, CAYENNE_NO_CHANNEL, NULL, NULL, "1000000000"); + + return CAYENNE_SUCCESS; +} + /* Simple main function */ int main() { - uint8_t id; - float value1, value2; - char buffer1[32], buffer2[32]; - int32_t axes[3]; + uint8_t id; + float value1, value2, value3, value4; + char buffer1[32], buffer2[32], buffer3[32], buffer4[32]; + int32_t axes[3]; - /* Enable all sensors */ - hum_temp->enable(); - press_temp->enable(); - magnetometer->enable(); - accelerometer->enable(); - acc_gyro->enable_x(); - acc_gyro->enable_g(); + /* Enable all sensors */ + hum_temp->enable(); + press_temp->enable(); + magnetometer->enable(); + accelerometer->enable(); + acc_gyro->enable_x(); + acc_gyro->enable_g(); - printf("\r\n--- Starting new run ---\r\n"); + printf("\r\n--- Starting new run ---\r\n"); - hum_temp->read_id(&id); - printf("HTS221 humidity & temperature = 0x%X\r\n", id); - press_temp->read_id(&id); - printf("LPS22HB pressure & temperature = 0x%X\r\n", id); - magnetometer->read_id(&id); - printf("LSM303AGR magnetometer = 0x%X\r\n", id); - accelerometer->read_id(&id); - printf("LSM303AGR accelerometer = 0x%X\r\n", id); - acc_gyro->read_id(&id); - printf("LSM6DSL accelerometer & gyroscope = 0x%X\r\n", id); + hum_temp->read_id(&id); + printf("HTS221 humidity & temperature = 0x%X\r\n", id); + press_temp->read_id(&id); + printf("LPS22HB pressure & temperature = 0x%X\r\n", id); + magnetometer->read_id(&id); + printf("LSM303AGR magnetometer = 0x%X\r\n", id); + accelerometer->read_id(&id); + printf("LSM303AGR accelerometer = 0x%X\r\n", id); + acc_gyro->read_id(&id); + printf("LSM6DSL accelerometer & gyroscope = 0x%X\r\n", id); - while(1) { - printf("\r\n"); + // Initialize the network interface. + printf("Initializing interface\n"); + interface.connect(ssid, wifiPassword, NSAPI_SECURITY_WPA2); + + // Set the default function that receives Cayenne messages. + mqttClient.setDefaultMessageHandler(messageArrived); + + // Connect to Cayenne. + if (connectClient() == CAYENNE_SUCCESS) { + // Start the countdown timer for publishing data every 5 seconds. Change the timeout parameter to publish at a different interval. + MQTTTimer timer(5000); + + while (true) { + // Yield to allow MQTT message processing. + mqttClient.yield(1000); - hum_temp->get_temperature(&value1); - hum_temp->get_humidity(&value2); - printf("HTS221: [temp] %7s C, [hum] %s%%\r\n", print_double(buffer1, value1), print_double(buffer2, value2)); + // Check that we are still connected, if not, reconnect. + if (!network.connected() || !mqttClient.connected()) { + network.disconnect(); + mqttClient.disconnect(); + printf("Reconnecting\n"); + while (connectClient() != CAYENNE_SUCCESS) { + wait(2); + printf("Reconnect failed, retrying\n"); + } + } + + printf("\r\n"); + + hum_temp->get_temperature(&value1); + hum_temp->get_humidity(&value2); + printf("HTS221: [temp] %7s C, [hum] %s%%\r\n", print_double(buffer1, value1), print_double(buffer2, value2)); - press_temp->get_temperature(&value1); - press_temp->get_pressure(&value2); - printf("LPS22HB: [temp] %7s C, [press] %s mbar\r\n", print_double(buffer1, value1), print_double(buffer2, value2)); + press_temp->get_temperature(&value3); + press_temp->get_pressure(&value4); + printf("LPS22HB: [temp] %7s C, [press] %s mbar\r\n", print_double(buffer1, value3), print_double(buffer2, value4)); - printf("---\r\n"); + printf("---\r\n"); - magnetometer->get_m_axes(axes); - printf("LSM303AGR [mag/mgauss]: %6ld, %6ld, %6ld\r\n", axes[0], axes[1], axes[2]); + magnetometer->get_m_axes(axes); + printf("LSM303AGR [mag/mgauss]: %6ld, %6ld, %6ld\r\n", axes[0], axes[1], axes[2]); - accelerometer->get_x_axes(axes); - printf("LSM303AGR [acc/mg]: %6ld, %6ld, %6ld\r\n", axes[0], axes[1], axes[2]); + acc_gyro->get_x_axes(axes); + printf("LSM6DSL [acc/mg]: %6ld, %6ld, %6ld\r\n", axes[0], axes[1], axes[2]); - acc_gyro->get_x_axes(axes); - printf("LSM6DSL [acc/mg]: %6ld, %6ld, %6ld\r\n", axes[0], axes[1], axes[2]); + accelerometer->get_x_axes(axes); + printf("LSM303AGR [acc/mg]: %6ld, %6ld, %6ld\r\n", axes[0], axes[1], axes[2]); + + acc_gyro->get_g_axes(axes); + printf("LSM6DSL [gyro/mdps]: %6ld, %6ld, %6ld\r\n", axes[0], axes[1], axes[2]); + + wait(1.5); + + Cayenne.virtualWrite(2, 25.2, "temp", "c"); + + + // Publish some example data every few seconds. This should be changed to send your actual data to Cayenne. + if (timer.expired()) { + int error = 0; + if ((error = mqttClient.publishData(DATA_TOPIC, 1, TYPE_TEMPERATURE, UNIT_CELSIUS, value1)) != CAYENNE_SUCCESS) { + printf("Publish temperature failed, error: %d\n", error); + } + if ((error = mqttClient.publishData(DATA_TOPIC, 2, TYPE_BAROMETRIC_PRESSURE, UNIT_PASCAL, value4)) != CAYENNE_SUCCESS) { + printf("Publish luminosity failed, error: %d\n", error); + } + if ((error = mqttClient.publishData(DATA_TOPIC, 3, TYPE_PROXIMITY, UNIT_METER, axes[1])) != CAYENNE_SUCCESS) { + printf("Publish barometric pressure failed, error: %d\n", error); + } + // Restart the countdown timer for publishing data every 5 seconds. Change the timeout parameter to publish at a different interval. + timer.countdown_ms(5000); + } + } + } + else { + printf("Connection failed, exiting\n"); + } - acc_gyro->get_g_axes(axes); - printf("LSM6DSL [gyro/mdps]: %6ld, %6ld, %6ld\r\n", axes[0], axes[1], axes[2]); - - wait(1.5); - } + if (mqttClient.connected()) + mqttClient.disconnect(); + if (network.connected()) + network.disconnect(); }