![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
Example of sending MQTT data to MyDevices Cayenne using the MTSAS library
Dependencies: Cayenne-MQTT-mbed-MTSAS X_NUCLEO_IKS01A1 mbed mtsas_lat3
main.cpp
- Committer:
- pferland
- Date:
- 2017-11-21
- Revision:
- 7:12131978176d
- Parent:
- 6:cd0be5cc1943
File content as of revision 7:12131978176d:
#include "mbed.h" #include "mtsas.h" #include "MQTTTimer.h" #include "CayenneMQTTClient.h" #include "MQTTNetwork.h" #include "x_nucleo_iks01a1.h" #include <string> #include <sstream> using std::string; typedef CayenneMQTT::MQTTClient<MQTTNetwork<Cellular>, MQTTTimer> MQTTClient; // Cayenne authentication info. This should be obtained from the Cayenne Dashboard. string username = "da497640-dcce-11e6-b089-9f6bfa78ab33"; //"MQTT-Username"; string password = "68e890972b6cc0fc47fcd152554db7e78ec9b29f"; //"MQTT-Password"; string clientID = "dc9c10d0-ced9-11e7-98e1-8369df76aa6d"; //"MQTT-ClientID"; DigitalOut Led1Out(D1); DigitalOut Led2Out(D0); DigitalOut Led3Out(D3); DigitalOut Led4Out(D6); DigitalOut Led5Out(D6); DigitalOut Led6Out(D8); DigitalOut Led7Out(D5); DigitalOut Led8Out(D4); DigitalOut Led9Out(D7); DigitalOut LedStatus(D2); // Debug serial port //static Serial debug(USBTX, USBRX); Serial pc(USBTX, USBRX); // MTSSerialFlowControl - serial link between processor and radio static MTSSerialFlowControl* io; // Cellular - radio object for cellular operations (SMS, TCP, etc) Cellular* radio; /* Instantiate the expansion board */ static X_NUCLEO_IKS01A1 *mems_expansion_board = X_NUCLEO_IKS01A1::Instance(I2C_SDA, I2C_SCL); /* Retrieve the composing elements of the expansion board */ static GyroSensor *gyroscope = mems_expansion_board->GetGyroscope(); static MotionSensor *accelerometer = mems_expansion_board->GetAccelerometer(); static MagneticSensor *magnetometer = mems_expansion_board->magnetometer; static HumiditySensor *humidity_sensor = mems_expansion_board->ht_sensor; static PressureSensor *pressure_sensor = mems_expansion_board->pt_sensor; static TempSensor *temp_sensor1 = mems_expansion_board->ht_sensor; static TempSensor *temp_sensor2 = mems_expansion_board->pt_sensor; static const std::string apn = "b2b.tmobile.com"; //"iot.aer.net"; CayenneMQTT::MessageData lastMessage; bool messageReady; bool gpsAvailable; /* * Initialize cellular radio. */ bool init_mtsas() { io = new MTSSerialFlowControl(RADIO_TX, RADIO_RX, RADIO_RTS, RADIO_CTS); if (! io) return false; io->baud(115200); radio = CellularFactory::create(io); if (! radio) return false; logInfo("setting APN"); if (radio->setApn(apn) != MTS_SUCCESS) logError("failed to set APN to \"%s\"", apn.c_str()); Transport::setTransport(radio); while (! radio->connect()) { logError("failed to bring up PPP link"); wait(2); } printf("Signal Strength: %d\n\r", radio->getSignalStrength()); return true; } /** * 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("\r\n"); } /** * * */ void setLEDs(bool newState) { // note: false = lit LED Led1Out = !newState; Led2Out = !newState; Led3Out = !newState; Led4Out = !newState; Led5Out = !newState; Led6Out = !newState; Led7Out = !newState; Led8Out = !newState; Led9Out = !newState; } /** * 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; //note: if you change this example to use mbed-os you will need a mutex lastMessage = message; messageReady = true; } /** * Connect to the Cayenne server. * @return Returns CAYENNE_SUCCESS if the connection succeeds, or an error code otherwise. */ int connectClient(MQTTClient &mqttClient, MQTTNetwork<Cellular> &network) { int error = 0; // Connect to the server. printf("Connecting to %s:%d\r\n", CAYENNE_DOMAIN, CAYENNE_PORT); while ((error = network.connect(CAYENNE_DOMAIN, CAYENNE_PORT)) != 0) { printf("TCP connect failed, error: %d\r\n", error); wait(2); } if ((error = mqttClient.connect()) != MQTT::SUCCESS) { printf("MQTT connect failed, error: %d\r\n", error); return error; } printf("Connected\r\n"); // Subscribe to required topics. if ((error = mqttClient.subscribe(COMMAND_TOPIC, CAYENNE_ALL_CHANNELS)) != CAYENNE_SUCCESS) { printf("Subscription to Command topic failed, error: %d\r\n", error); } if ((error = mqttClient.subscribe(CONFIG_TOPIC, CAYENNE_ALL_CHANNELS)) != CAYENNE_SUCCESS) { printf("Subscription to Config topic failed, error:%d\r\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; } /** * Main loop where MQTT code is run. */ void loop(MQTTClient &mqttClient, MQTTNetwork<Cellular> &network) { // Start the countdown timer for publishing data every 5 seconds. Change the timeout parameter to publish at a different interval. MQTTTimer timer(1000); printf("Starting loop.\r\n"); while (true) { // Yield to allow MQTT message processing. mqttClient.yield(10); if(messageReady){ int error = 0; messageReady = false; // Add code to process the message. Here we just ouput the message data. outputMessage(lastMessage); if (lastMessage.topic == COMMAND_TOPIC) { switch(lastMessage.channel) { case 0: // Set the onboard LED state bool value = atoi(lastMessage.getValue()); setLEDs(value); // Publish the updated LED state if ((error = mqttClient.publishData(DATA_TOPIC, lastMessage.channel, NULL, NULL, Led1Out.read()==0?1:0)) != CAYENNE_SUCCESS) { printf("Publish LED state failure, error: %d\r\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(lastMessage.id, NULL, lastMessage.clientID)) != CAYENNE_SUCCESS) { printf("Response failure, error: %d\r\n", error); } } } // Check that we are still connected, if not, reconnect. if (!network.connected() || !mqttClient.connected()) { network.disconnect(); mqttClient.disconnect(); LedStatus = true; printf("Reconnecting\r\n"); while (connectClient(mqttClient, network) != CAYENNE_SUCCESS) { wait(2); printf("Reconnect failed, retrying\r\n"); } LedStatus = false; } // Publish some example data every few seconds. This should be changed to send your actual data to Cayenne. if (timer.expired()) { printf("Sampling sensors\r\n"); int error = 0; float temp_data; temp_sensor1->get_temperature(&temp_data); printf("Temperature was: %f \r\n", temp_data); if ((error = mqttClient.publishData(DATA_TOPIC, 1, TYPE_TEMPERATURE, UNIT_CELSIUS, temp_data)) != CAYENNE_SUCCESS) { printf("Publish temperature failed, error: %d\r\n", error); } humidity_sensor->get_humidity(&temp_data); printf("Humidity was: %f \r\n", temp_data); if ((error = mqttClient.publishData(DATA_TOPIC, 2, TYPE_RELATIVE_HUMIDITY, UNIT_PERCENT, temp_data)) != CAYENNE_SUCCESS) { printf("Publish luminosity failed, error: %d\r\n", error); } pressure_sensor->get_pressure(&temp_data); printf("Pressure was: %f \r\n", temp_data); if ((error = mqttClient.publishData(DATA_TOPIC, 3, TYPE_BAROMETRIC_PRESSURE, UNIT_HECTOPASCAL, temp_data)) != CAYENNE_SUCCESS) { printf("Publish barometric pressure failed, error: %d\r\n", error); } printf("Led is: %s\r\n", Led1Out.read() > 0 ? "off" : "on"); if ((error = mqttClient.publishData(DATA_TOPIC, 0, "digital_actuator", UNIT_DIGITAL, Led1Out.read()==0?1:0)) != CAYENNE_SUCCESS) { printf("Publish LED status failed, error: %d\r\n", error); } if(gpsAvailable){ // disconnect socket so we can query GPS mqttClient.disconnect(); network.disconnect(); if( !radio->GPSenabled() ) { printf("GPS: enabling"); radio->GPSenable(); while( !radio->GPSenabled() ) { logInfo("..."); wait(5); } } //collect gps data Cellular::gpsData loc = radio->GPSgetPosition(); LedStatus = true; printf("Reconnecting\r\n"); while (connectClient(mqttClient, network) != CAYENNE_SUCCESS) { wait(2); printf("Reconnect failed, retrying\r\n"); } if(loc.success == false){ printf("GPSgetPosition failed\r\n"); } else { switch(loc.fix){ case 0: case 1: printf("GPS - no Lock\r\n"); break; case 2: printf("GPS - 2d Lock\r\n"); break; case 3: printf("GPS - 3d Lock\r\n"); break; } } if(loc.fix > 1){ std::string payload = loc.latitude + ","; payload += loc.longitude; payload += ","; payload += loc.altitude; error = mqttClient.publishData(DATA_TOPIC, 4, "gps", "m", payload.c_str()); if( error != CAYENNE_SUCCESS) { printf("Publish GPS latitude status failed, error: %d\r\n", error); } // error = mqttClient.publishData(DATA_TOPIC, 5, "location_long", NULL, loc.longitude.c_str()); // if( error != CAYENNE_SUCCESS) { // printf("Publish GPS longitude status failed, error: %d\r\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 { // debug // printf("Timer: %d", timer.left_ms()); } } } int main() { pc.baud(115200); setLEDs(false); LedStatus = true; mts::MTSLog::setLogLevel(mts::MTSLog::TRACE_LEVEL); // init radio, setup Cayenne connection if (!init_mtsas()) { while (true) { logError("failed to initialize cellular radio"); wait(1); } } // Test with a ping if(radio->ping("www.google.com")){ printf("Ping test succeeded!\r\n"); } else { printf("Failed ping test!\r\n"); } gpsAvailable = radio ->GPSenable(); MQTTNetwork<Cellular> network(*radio); messageReady = false; MQTTClient mqttClient(network, username.c_str(), password.c_str(), clientID.c_str()); // Set the default function that receives Cayenne messages. mqttClient.setDefaultMessageHandler(messageArrived); // Connect to Cayenne. if (connectClient(mqttClient, network) == CAYENNE_SUCCESS) { // Run main loop. LedStatus = false; loop(mqttClient, network); } else { printf("Connection failed, exiting\r\n"); } if (mqttClient.connected()) mqttClient.disconnect(); if (network.connected()) network.disconnect(); return 0; }