Example of sending MQTT data to MyDevices Cayenne using the MTSAS library

Dependencies:   Cayenne-MQTT-mbed-MTSAS X_NUCLEO_IKS01A1 mbed mtsas_lat3

Committer:
pferland
Date:
Mon Nov 20 21:25:46 2017 +0000
Revision:
6:cd0be5cc1943
Parent:
5:960d9d8974c8
Child:
7:12131978176d
Fixed credentials

Who changed what in which revision?

UserRevisionLine numberNew contents of line
pferland 0:5107fce16490 1 #include "mbed.h"
pferland 0:5107fce16490 2
pferland 0:5107fce16490 3 #include "mtsas.h"
pferland 0:5107fce16490 4
pferland 0:5107fce16490 5 #include "MQTTTimer.h"
pferland 0:5107fce16490 6 #include "CayenneMQTTClient.h"
pferland 0:5107fce16490 7 #include "MQTTNetwork.h"
pferland 0:5107fce16490 8
pferland 0:5107fce16490 9 #include "x_nucleo_iks01a1.h"
pferland 0:5107fce16490 10
pferland 0:5107fce16490 11 #include <string>
pferland 0:5107fce16490 12 #include <sstream>
pferland 0:5107fce16490 13
pferland 0:5107fce16490 14 using std::string;
pferland 0:5107fce16490 15 typedef CayenneMQTT::MQTTClient<MQTTNetwork<Cellular>, MQTTTimer> MQTTClient;
pferland 0:5107fce16490 16
pferland 0:5107fce16490 17 // Cayenne authentication info. This should be obtained from the Cayenne Dashboard.
pferland 6:cd0be5cc1943 18 string username = "MQTT-Username";
pferland 6:cd0be5cc1943 19 string password = "MQTT-Password";
pferland 6:cd0be5cc1943 20 string clientID = "MQTT-ClientID";
pferland 0:5107fce16490 21
pferland 5:960d9d8974c8 22 DigitalOut Led1Out(D1);
pferland 5:960d9d8974c8 23 DigitalOut Led2Out(D0);
pferland 5:960d9d8974c8 24 DigitalOut Led3Out(D3);
pferland 5:960d9d8974c8 25 DigitalOut Led4Out(D6);
pferland 5:960d9d8974c8 26 DigitalOut Led5Out(D6);
pferland 5:960d9d8974c8 27 DigitalOut Led6Out(D8);
pferland 5:960d9d8974c8 28 DigitalOut Led7Out(D5);
pferland 5:960d9d8974c8 29 DigitalOut Led8Out(D4);
pferland 5:960d9d8974c8 30 DigitalOut Led9Out(D7);
pferland 5:960d9d8974c8 31 DigitalOut LedStatus(D2);
pferland 0:5107fce16490 32
pferland 0:5107fce16490 33 // Debug serial port
pferland 0:5107fce16490 34 //static Serial debug(USBTX, USBRX);
pferland 0:5107fce16490 35 Serial pc(USBTX, USBRX);
pferland 0:5107fce16490 36
pferland 0:5107fce16490 37 // MTSSerialFlowControl - serial link between processor and radio
pferland 0:5107fce16490 38 static MTSSerialFlowControl* io;
pferland 0:5107fce16490 39
pferland 0:5107fce16490 40 // Cellular - radio object for cellular operations (SMS, TCP, etc)
pferland 0:5107fce16490 41 Cellular* radio;
pferland 0:5107fce16490 42
pferland 0:5107fce16490 43 /* Instantiate the expansion board */
pferland 0:5107fce16490 44 static X_NUCLEO_IKS01A1 *mems_expansion_board = X_NUCLEO_IKS01A1::Instance(I2C_SDA, I2C_SCL);
pferland 0:5107fce16490 45
pferland 0:5107fce16490 46 /* Retrieve the composing elements of the expansion board */
pferland 0:5107fce16490 47 static GyroSensor *gyroscope = mems_expansion_board->GetGyroscope();
pferland 0:5107fce16490 48 static MotionSensor *accelerometer = mems_expansion_board->GetAccelerometer();
pferland 0:5107fce16490 49 static MagneticSensor *magnetometer = mems_expansion_board->magnetometer;
pferland 0:5107fce16490 50 static HumiditySensor *humidity_sensor = mems_expansion_board->ht_sensor;
pferland 0:5107fce16490 51 static PressureSensor *pressure_sensor = mems_expansion_board->pt_sensor;
pferland 0:5107fce16490 52 static TempSensor *temp_sensor1 = mems_expansion_board->ht_sensor;
pferland 0:5107fce16490 53 static TempSensor *temp_sensor2 = mems_expansion_board->pt_sensor;
pferland 0:5107fce16490 54
pferland 5:960d9d8974c8 55 static const std::string apn = "iot.aer.net";
pferland 0:5107fce16490 56
pferland 0:5107fce16490 57 CayenneMQTT::MessageData lastMessage;
pferland 0:5107fce16490 58 bool messageReady;
pferland 0:5107fce16490 59
pferland 0:5107fce16490 60 /*
pferland 0:5107fce16490 61 * Initialize cellular radio.
pferland 0:5107fce16490 62 */
pferland 0:5107fce16490 63 bool init_mtsas()
pferland 0:5107fce16490 64 {
pferland 0:5107fce16490 65 io = new MTSSerialFlowControl(RADIO_TX, RADIO_RX, RADIO_RTS, RADIO_CTS);
pferland 0:5107fce16490 66 if (! io)
pferland 0:5107fce16490 67 return false;
pferland 0:5107fce16490 68
pferland 0:5107fce16490 69 io->baud(115200);
pferland 0:5107fce16490 70 radio = CellularFactory::create(io);
pferland 0:5107fce16490 71 if (! radio)
pferland 0:5107fce16490 72 return false;
pferland 0:5107fce16490 73
pferland 5:960d9d8974c8 74 logInfo("setting APN");
pferland 5:960d9d8974c8 75 if (radio->setApn(apn) != MTS_SUCCESS)
pferland 5:960d9d8974c8 76 logError("failed to set APN to \"%s\"", apn);
pferland 5:960d9d8974c8 77
pferland 0:5107fce16490 78 Transport::setTransport(radio);
pferland 0:5107fce16490 79 while (! radio->connect()) {
pferland 0:5107fce16490 80 logError("failed to bring up PPP link");
pferland 0:5107fce16490 81 wait(2);
pferland 0:5107fce16490 82 }
pferland 0:5107fce16490 83
pferland 0:5107fce16490 84 printf("Signal Strength: %d\n\r", radio->getSignalStrength());
pferland 0:5107fce16490 85 return true;
pferland 0:5107fce16490 86 }
pferland 0:5107fce16490 87
pferland 0:5107fce16490 88 /**
pferland 0:5107fce16490 89 * Print the message info.
pferland 0:5107fce16490 90 * @param[in] message The message received from the Cayenne server.
pferland 0:5107fce16490 91 */
pferland 0:5107fce16490 92 void outputMessage(CayenneMQTT::MessageData& message)
pferland 0:5107fce16490 93 {
pferland 0:5107fce16490 94 switch (message.topic) {
pferland 0:5107fce16490 95 case COMMAND_TOPIC:
pferland 0:5107fce16490 96 printf("topic=Command");
pferland 0:5107fce16490 97 break;
pferland 0:5107fce16490 98 case CONFIG_TOPIC:
pferland 0:5107fce16490 99 printf("topic=Config");
pferland 0:5107fce16490 100 break;
pferland 0:5107fce16490 101 default:
pferland 0:5107fce16490 102 printf("topic=%d", message.topic);
pferland 0:5107fce16490 103 break;
pferland 0:5107fce16490 104 }
pferland 0:5107fce16490 105 printf(" channel=%d", message.channel);
pferland 0:5107fce16490 106 if (message.clientID) {
pferland 0:5107fce16490 107 printf(" clientID=%s", message.clientID);
pferland 0:5107fce16490 108 }
pferland 0:5107fce16490 109 if (message.type) {
pferland 0:5107fce16490 110 printf(" type=%s", message.type);
pferland 0:5107fce16490 111 }
pferland 0:5107fce16490 112 for (size_t i = 0; i < message.valueCount; ++i) {
pferland 0:5107fce16490 113 if (message.getValue(i)) {
pferland 0:5107fce16490 114 printf(" value=%s", message.getValue(i));
pferland 0:5107fce16490 115 }
pferland 0:5107fce16490 116 if (message.getUnit(i)) {
pferland 0:5107fce16490 117 printf(" unit=%s", message.getUnit(i));
pferland 0:5107fce16490 118 }
pferland 0:5107fce16490 119 }
pferland 0:5107fce16490 120 if (message.id) {
pferland 0:5107fce16490 121 printf(" id=%s", message.id);
pferland 0:5107fce16490 122 }
pferland 2:abc89d2aede3 123 printf("\r\n");
pferland 0:5107fce16490 124 }
pferland 0:5107fce16490 125
pferland 0:5107fce16490 126 /**
pferland 5:960d9d8974c8 127 *
pferland 5:960d9d8974c8 128 *
pferland 5:960d9d8974c8 129 */
pferland 5:960d9d8974c8 130 void setLEDs(bool newState)
pferland 5:960d9d8974c8 131 {
pferland 5:960d9d8974c8 132 // note: false = lit LED
pferland 5:960d9d8974c8 133 Led1Out = !newState;
pferland 5:960d9d8974c8 134 Led2Out = !newState;
pferland 5:960d9d8974c8 135 Led3Out = !newState;
pferland 5:960d9d8974c8 136 Led4Out = !newState;
pferland 5:960d9d8974c8 137 Led5Out = !newState;
pferland 5:960d9d8974c8 138 Led6Out = !newState;
pferland 5:960d9d8974c8 139 Led7Out = !newState;
pferland 5:960d9d8974c8 140 Led8Out = !newState;
pferland 5:960d9d8974c8 141 Led9Out = !newState;
pferland 5:960d9d8974c8 142 }
pferland 5:960d9d8974c8 143
pferland 5:960d9d8974c8 144 /**
pferland 0:5107fce16490 145 * Handle messages received from the Cayenne server.
pferland 0:5107fce16490 146 * @param[in] message The message received from the Cayenne server.
pferland 0:5107fce16490 147 */
pferland 0:5107fce16490 148 void messageArrived(CayenneMQTT::MessageData& message)
pferland 0:5107fce16490 149 {
pferland 0:5107fce16490 150 int error = 0;
pferland 0:5107fce16490 151 //note: if you change this example to use mbed-os you will need a mutex
pferland 0:5107fce16490 152 lastMessage = message;
pferland 0:5107fce16490 153 messageReady = true;
pferland 0:5107fce16490 154
pferland 0:5107fce16490 155 }
pferland 0:5107fce16490 156
pferland 0:5107fce16490 157 /**
pferland 0:5107fce16490 158 * Connect to the Cayenne server.
pferland 0:5107fce16490 159 * @return Returns CAYENNE_SUCCESS if the connection succeeds, or an error code otherwise.
pferland 0:5107fce16490 160 */
pferland 0:5107fce16490 161 int connectClient(MQTTClient &mqttClient, MQTTNetwork<Cellular> &network)
pferland 0:5107fce16490 162 {
pferland 0:5107fce16490 163 int error = 0;
pferland 0:5107fce16490 164 // Connect to the server.
pferland 2:abc89d2aede3 165 printf("Connecting to %s:%d\r\n", CAYENNE_DOMAIN, CAYENNE_PORT);
pferland 0:5107fce16490 166 while ((error = network.connect(CAYENNE_DOMAIN, CAYENNE_PORT)) != 0) {
pferland 2:abc89d2aede3 167 printf("TCP connect failed, error: %d\r\n", error);
pferland 0:5107fce16490 168 wait(2);
pferland 0:5107fce16490 169 }
pferland 0:5107fce16490 170
pferland 0:5107fce16490 171 if ((error = mqttClient.connect()) != MQTT::SUCCESS) {
pferland 2:abc89d2aede3 172 printf("MQTT connect failed, error: %d\r\n", error);
pferland 0:5107fce16490 173 return error;
pferland 0:5107fce16490 174 }
pferland 2:abc89d2aede3 175 printf("Connected\r\n");
pferland 0:5107fce16490 176
pferland 0:5107fce16490 177 // Subscribe to required topics.
pferland 0:5107fce16490 178 if ((error = mqttClient.subscribe(COMMAND_TOPIC, CAYENNE_ALL_CHANNELS)) != CAYENNE_SUCCESS) {
pferland 2:abc89d2aede3 179 printf("Subscription to Command topic failed, error: %d\r\n", error);
pferland 0:5107fce16490 180 }
pferland 0:5107fce16490 181 if ((error = mqttClient.subscribe(CONFIG_TOPIC, CAYENNE_ALL_CHANNELS)) != CAYENNE_SUCCESS) {
pferland 2:abc89d2aede3 182 printf("Subscription to Config topic failed, error:%d\r\n", error);
pferland 0:5107fce16490 183 }
pferland 0:5107fce16490 184
pferland 0:5107fce16490 185 // 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.
pferland 0:5107fce16490 186 mqttClient.publishData(SYS_VERSION_TOPIC, CAYENNE_NO_CHANNEL, NULL, NULL, CAYENNE_VERSION);
pferland 0:5107fce16490 187 mqttClient.publishData(SYS_MODEL_TOPIC, CAYENNE_NO_CHANNEL, NULL, NULL, "mbedDevice");
pferland 0:5107fce16490 188 //mqttClient.publishData(SYS_CPU_MODEL_TOPIC, CAYENNE_NO_CHANNEL, NULL, NULL, "CPU Model");
pferland 0:5107fce16490 189 //mqttClient.publishData(SYS_CPU_SPEED_TOPIC, CAYENNE_NO_CHANNEL, NULL, NULL, "1000000000");
pferland 0:5107fce16490 190
pferland 0:5107fce16490 191 return CAYENNE_SUCCESS;
pferland 0:5107fce16490 192 }
pferland 0:5107fce16490 193
pferland 0:5107fce16490 194 /**
pferland 0:5107fce16490 195 * Main loop where MQTT code is run.
pferland 0:5107fce16490 196 */
pferland 0:5107fce16490 197 void loop(MQTTClient &mqttClient, MQTTNetwork<Cellular> &network)
pferland 0:5107fce16490 198 {
pferland 0:5107fce16490 199 // Start the countdown timer for publishing data every 5 seconds. Change the timeout parameter to publish at a different interval.
pferland 2:abc89d2aede3 200 MQTTTimer timer(1000);
pferland 2:abc89d2aede3 201 printf("Starting loop.\r\n");
pferland 0:5107fce16490 202 while (true) {
pferland 0:5107fce16490 203 // Yield to allow MQTT message processing.
pferland 2:abc89d2aede3 204 mqttClient.yield(10);
pferland 0:5107fce16490 205 if(messageReady){
pferland 0:5107fce16490 206 int error = 0;
pferland 0:5107fce16490 207 messageReady = false;
pferland 0:5107fce16490 208 // Add code to process the message. Here we just ouput the message data.
pferland 0:5107fce16490 209 outputMessage(lastMessage);
pferland 0:5107fce16490 210
pferland 0:5107fce16490 211 if (lastMessage.topic == COMMAND_TOPIC) {
pferland 0:5107fce16490 212 switch(lastMessage.channel) {
pferland 0:5107fce16490 213 case 0:
pferland 0:5107fce16490 214 // Set the onboard LED state
pferland 5:960d9d8974c8 215 bool value = atoi(lastMessage.getValue());
pferland 5:960d9d8974c8 216 setLEDs(value);
pferland 5:960d9d8974c8 217
pferland 0:5107fce16490 218 // Publish the updated LED state
pferland 5:960d9d8974c8 219 if ((error = mqttClient.publishData(DATA_TOPIC, lastMessage.channel, NULL, NULL, Led1Out.read()==0?1:0)) != CAYENNE_SUCCESS) {
pferland 2:abc89d2aede3 220 printf("Publish LED state failure, error: %d\r\n", error);
pferland 0:5107fce16490 221 }
pferland 0:5107fce16490 222 break;
pferland 0:5107fce16490 223 }
pferland 0:5107fce16490 224
pferland 0:5107fce16490 225 // If this is a command message we publish a response. Here we are just sending a default 'OK' response.
pferland 0:5107fce16490 226 // An error response should be sent if there are issues processing the message.
pferland 0:5107fce16490 227 if ((error = mqttClient.publishResponse(lastMessage.id, NULL, lastMessage.clientID)) != CAYENNE_SUCCESS) {
pferland 2:abc89d2aede3 228 printf("Response failure, error: %d\r\n", error);
pferland 0:5107fce16490 229 }
pferland 0:5107fce16490 230 }
pferland 0:5107fce16490 231 }
pferland 0:5107fce16490 232
pferland 0:5107fce16490 233 // Check that we are still connected, if not, reconnect.
pferland 0:5107fce16490 234 if (!network.connected() || !mqttClient.connected()) {
pferland 0:5107fce16490 235 network.disconnect();
pferland 0:5107fce16490 236 mqttClient.disconnect();
pferland 5:960d9d8974c8 237 LedStatus = true;
pferland 2:abc89d2aede3 238 printf("Reconnecting\r\n");
pferland 0:5107fce16490 239 while (connectClient(mqttClient, network) != CAYENNE_SUCCESS) {
pferland 0:5107fce16490 240 wait(2);
pferland 2:abc89d2aede3 241 printf("Reconnect failed, retrying\r\n");
pferland 0:5107fce16490 242 }
pferland 5:960d9d8974c8 243 LedStatus = false;
pferland 0:5107fce16490 244 }
pferland 0:5107fce16490 245
pferland 0:5107fce16490 246 // Publish some example data every few seconds. This should be changed to send your actual data to Cayenne.
pferland 0:5107fce16490 247 if (timer.expired()) {
pferland 0:5107fce16490 248 int error = 0;
pferland 0:5107fce16490 249 float temp_data;
pferland 0:5107fce16490 250 temp_sensor1->get_temperature(&temp_data);
pferland 2:abc89d2aede3 251 printf("Temperature was: %f \r\n", temp_data);
pferland 0:5107fce16490 252 if ((error = mqttClient.publishData(DATA_TOPIC, 1, TYPE_TEMPERATURE, UNIT_CELSIUS, temp_data)) != CAYENNE_SUCCESS) {
pferland 2:abc89d2aede3 253 printf("Publish temperature failed, error: %d\r\n", error);
pferland 0:5107fce16490 254 }
pferland 0:5107fce16490 255 humidity_sensor->get_humidity(&temp_data);
pferland 2:abc89d2aede3 256 printf("Humidity was: %f \r\n", temp_data);
pferland 0:5107fce16490 257 if ((error = mqttClient.publishData(DATA_TOPIC, 2, TYPE_RELATIVE_HUMIDITY, UNIT_PERCENT, temp_data)) != CAYENNE_SUCCESS) {
pferland 2:abc89d2aede3 258 printf("Publish luminosity failed, error: %d\r\n", error);
pferland 0:5107fce16490 259 }
pferland 0:5107fce16490 260 pressure_sensor->get_pressure(&temp_data);
pferland 2:abc89d2aede3 261 printf("Pressure was: %f \r\n", temp_data);
pferland 0:5107fce16490 262 if ((error = mqttClient.publishData(DATA_TOPIC, 3, TYPE_BAROMETRIC_PRESSURE, UNIT_HECTOPASCAL, temp_data)) != CAYENNE_SUCCESS) {
pferland 2:abc89d2aede3 263 printf("Publish barometric pressure failed, error: %d\r\n", error);
pferland 0:5107fce16490 264 }
pferland 5:960d9d8974c8 265 printf("Led is: %s\r\n", Led1Out.read() > 0 ? "off" : "on");
pferland 5:960d9d8974c8 266 if ((error = mqttClient.publishData(DATA_TOPIC, 0, "digital_actuator", UNIT_DIGITAL, Led1Out.read()==0?1:0)) != CAYENNE_SUCCESS) {
pferland 2:abc89d2aede3 267 printf("Publish LED status failed, error: %d\r\n", error);
pferland 2:abc89d2aede3 268 }
pferland 0:5107fce16490 269 // Restart the countdown timer for publishing data every 5 seconds. Change the timeout parameter to publish at a different interval.
pferland 0:5107fce16490 270 timer.countdown_ms(5000);
pferland 0:5107fce16490 271 } else {
pferland 2:abc89d2aede3 272 // debug
pferland 2:abc89d2aede3 273 // printf("Timer: %d", timer.left_ms());
pferland 0:5107fce16490 274 }
pferland 0:5107fce16490 275 }
pferland 0:5107fce16490 276 }
pferland 0:5107fce16490 277
pferland 0:5107fce16490 278 int main()
pferland 0:5107fce16490 279 {
pferland 0:5107fce16490 280 pc.baud(115200);
pferland 5:960d9d8974c8 281 setLEDs(false);
pferland 5:960d9d8974c8 282 LedStatus = true;
pferland 0:5107fce16490 283 mts::MTSLog::setLogLevel(mts::MTSLog::TRACE_LEVEL);
pferland 0:5107fce16490 284 // init radio, setup Cayenne connection
pferland 0:5107fce16490 285 if (!init_mtsas()) {
pferland 0:5107fce16490 286 while (true) {
pferland 0:5107fce16490 287 logError("failed to initialize cellular radio");
pferland 0:5107fce16490 288 wait(1);
pferland 0:5107fce16490 289 }
pferland 0:5107fce16490 290 }
pferland 5:960d9d8974c8 291
pferland 0:5107fce16490 292 // Test with a ping
pferland 0:5107fce16490 293 if(radio->ping("www.google.com")){
pferland 2:abc89d2aede3 294 printf("Ping test succeeded!\r\n");
pferland 0:5107fce16490 295 } else {
pferland 2:abc89d2aede3 296 printf("Failed ping test!\r\n");
pferland 0:5107fce16490 297 }
pferland 5:960d9d8974c8 298
pferland 0:5107fce16490 299 MQTTNetwork<Cellular> network(*radio);
pferland 0:5107fce16490 300 messageReady = false;
pferland 0:5107fce16490 301 MQTTClient mqttClient(network, username.c_str(), password.c_str(), clientID.c_str());
pferland 0:5107fce16490 302
pferland 0:5107fce16490 303 // Set the default function that receives Cayenne messages.
pferland 0:5107fce16490 304 mqttClient.setDefaultMessageHandler(messageArrived);
pferland 0:5107fce16490 305
pferland 0:5107fce16490 306 // Connect to Cayenne.
pferland 0:5107fce16490 307 if (connectClient(mqttClient, network) == CAYENNE_SUCCESS) {
pferland 0:5107fce16490 308 // Run main loop.
pferland 5:960d9d8974c8 309 LedStatus = false;
pferland 0:5107fce16490 310 loop(mqttClient, network);
pferland 0:5107fce16490 311 }
pferland 0:5107fce16490 312 else {
pferland 2:abc89d2aede3 313 printf("Connection failed, exiting\r\n");
pferland 0:5107fce16490 314 }
pferland 0:5107fce16490 315
pferland 0:5107fce16490 316 if (mqttClient.connected())
pferland 0:5107fce16490 317 mqttClient.disconnect();
pferland 0:5107fce16490 318 if (network.connected())
pferland 0:5107fce16490 319 network.disconnect();
pferland 0:5107fce16490 320
pferland 0:5107fce16490 321 return 0;
pferland 0:5107fce16490 322 }