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;
}