ME910 support

Dependents:   5_Dragonfly_Cayenne_Sprint_IKS01A1

Fork of Cayenne-MQTT-mbed-MTSAS by Peter Ferland

Committer:
jburhenn
Date:
Tue Oct 25 16:19:29 2016 -0600
Revision:
6:82e142a864ad
Parent:
4:421366004b5d
Child:
8:aec9cfdd4c8e
Updates from Cayenne-MQTT-CPP repo.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
jburhenn 0:09ef59d2d0f7 1 /*
jburhenn 0:09ef59d2d0f7 2 The MIT License(MIT)
jburhenn 0:09ef59d2d0f7 3
jburhenn 0:09ef59d2d0f7 4 Cayenne MQTT Client Library
jburhenn 0:09ef59d2d0f7 5 Copyright (c) 2016 myDevices
jburhenn 0:09ef59d2d0f7 6
jburhenn 0:09ef59d2d0f7 7 Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
jburhenn 0:09ef59d2d0f7 8 documentation files(the "Software"), to deal in the Software without restriction, including without limitation
jburhenn 0:09ef59d2d0f7 9 the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software,
jburhenn 0:09ef59d2d0f7 10 and to permit persons to whom the Software is furnished to do so, subject to the following conditions :
jburhenn 0:09ef59d2d0f7 11 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
jburhenn 0:09ef59d2d0f7 12 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
jburhenn 0:09ef59d2d0f7 13 WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR
jburhenn 0:09ef59d2d0f7 14 COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
jburhenn 0:09ef59d2d0f7 15 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
jburhenn 0:09ef59d2d0f7 16 */
jburhenn 0:09ef59d2d0f7 17
jburhenn 0:09ef59d2d0f7 18 #ifndef _CAYENNEMQTTCLIENT_h
jburhenn 0:09ef59d2d0f7 19 #define _CAYENNEMQTTCLIENT_h
jburhenn 0:09ef59d2d0f7 20
jburhenn 0:09ef59d2d0f7 21 #include <string.h>
jburhenn 0:09ef59d2d0f7 22 #include "MQTTClient.h"
jburhenn 0:09ef59d2d0f7 23 #include "../CayenneUtils/CayenneDefines.h"
jburhenn 0:09ef59d2d0f7 24 #include "../CayenneUtils/CayenneUtils.h"
jburhenn 0:09ef59d2d0f7 25 #include "../CayenneUtils/CayenneDataArray.h"
jburhenn 0:09ef59d2d0f7 26
jburhenn 0:09ef59d2d0f7 27 namespace Cayenne
jburhenn 0:09ef59d2d0f7 28 {
jburhenn 2:c0419dbecfbd 29 /**
jburhenn 2:c0419dbecfbd 30 * Cayenne message data passed to message handler functions.
jburhenn 2:c0419dbecfbd 31 */
jburhenn 0:09ef59d2d0f7 32 typedef struct MessageData
jburhenn 0:09ef59d2d0f7 33 {
jburhenn 4:421366004b5d 34 const char* clientID; /**< The client ID of the message. */
jburhenn 4:421366004b5d 35 CayenneTopic topic; /**< The topic the message was received on. */
jburhenn 4:421366004b5d 36 unsigned int channel; /**< The channel the message was received on. */
jburhenn 4:421366004b5d 37 const char* id; /**< The message ID, if it is a command message, otherwise NULL. */
jburhenn 4:421366004b5d 38 const char* type; /**< The type of data in the message, if it exists, otherwise NULL. */
jburhenn 4:421366004b5d 39 CayenneValuePair values[CAYENNE_MAX_MESSAGE_VALUES]; /**< The unit/value data pairs in the message. The units and values can be NULL. */
jburhenn 4:421366004b5d 40 size_t valueCount; /**< The count of items in the values array. */
jburhenn 0:09ef59d2d0f7 41 } MessageData;
jburhenn 1:90dccf306268 42
jburhenn 1:90dccf306268 43 /**
jburhenn 1:90dccf306268 44 * Client class for connecting to Cayenne via MQTT.
jburhenn 1:90dccf306268 45 * @class MQTTClient
jburhenn 1:90dccf306268 46 * @param Network A network class with the methods: read, write. See NetworkInterface.h for function definitions.
jburhenn 1:90dccf306268 47 * @param Timer A timer class with the methods: countdown_ms, countdown, left_ms, expired. See TimerInterface.h for function definitions.
jburhenn 1:90dccf306268 48 * @param MAX_MQTT_PACKET_SIZE Maximum size of an MQTT message, in bytes.
jburhenn 1:90dccf306268 49 * @param MAX_MESSAGE_HANDLERS Maximum number of message handlers.
jburhenn 1:90dccf306268 50 */
jburhenn 0:09ef59d2d0f7 51 template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE = 128, int MAX_MESSAGE_HANDLERS = 5>
jburhenn 0:09ef59d2d0f7 52 class MQTTClient : private MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, 0>
jburhenn 0:09ef59d2d0f7 53 {
jburhenn 0:09ef59d2d0f7 54 public:
jburhenn 0:09ef59d2d0f7 55 typedef MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, 0> Base;
jburhenn 0:09ef59d2d0f7 56 typedef void(*CayenneMessageHandler)(MessageData&);
jburhenn 0:09ef59d2d0f7 57
jburhenn 0:09ef59d2d0f7 58 /**
jburhenn 0:09ef59d2d0f7 59 * Create an Cayenne MQTT client object.
jburhenn 0:09ef59d2d0f7 60 * @param[in] network Pointer to an instance of the Network class. Must be connected to the endpoint before calling MQTTClient connect.
jburhenn 0:09ef59d2d0f7 61 * @param[in] command_timeout_ms Timeout for commands in milliseconds.
jburhenn 0:09ef59d2d0f7 62 */
jburhenn 0:09ef59d2d0f7 63 MQTTClient(Network& network, unsigned int command_timeout_ms = 30000) : Base(network, command_timeout_ms), _username(NULL), _clientID(NULL)
jburhenn 0:09ef59d2d0f7 64 {
jburhenn 0:09ef59d2d0f7 65 Base::setDefaultMessageHandler(this, &MQTTClient::mqttMessageArrived);
jburhenn 0:09ef59d2d0f7 66 };
jburhenn 0:09ef59d2d0f7 67
jburhenn 0:09ef59d2d0f7 68 /**
jburhenn 0:09ef59d2d0f7 69 * Set default handler function called when a message is received.
jburhenn 0:09ef59d2d0f7 70 * @param[in] handler Function called when message is received, if no other handlers exist for the topic.
jburhenn 0:09ef59d2d0f7 71 */
jburhenn 0:09ef59d2d0f7 72 void setDefaultMessageHandler(CayenneMessageHandler handler)
jburhenn 0:09ef59d2d0f7 73 {
jburhenn 0:09ef59d2d0f7 74 _defaultMessageHandler.attach(handler);
jburhenn 0:09ef59d2d0f7 75 };
jburhenn 0:09ef59d2d0f7 76
jburhenn 0:09ef59d2d0f7 77 /**
jburhenn 0:09ef59d2d0f7 78 * Connect to the Cayenne server.
jburhenn 0:09ef59d2d0f7 79 * @param[in] username Cayenne username
jburhenn 0:09ef59d2d0f7 80 * @param[in] clientID Cayennne client ID
jburhenn 0:09ef59d2d0f7 81 * @param[in] password Password
jburhenn 0:09ef59d2d0f7 82 * @return success code
jburhenn 0:09ef59d2d0f7 83 */
jburhenn 6:82e142a864ad 84 int connect(const char* username, const char* clientID, const char* password) {
jburhenn 0:09ef59d2d0f7 85 MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
jburhenn 0:09ef59d2d0f7 86 data.MQTTVersion = 3;
jburhenn 6:82e142a864ad 87 _clientID = clientID;
jburhenn 6:82e142a864ad 88 _username = username;
jburhenn 6:82e142a864ad 89 data.clientID.cstring = const_cast<char*>(_clientID);
jburhenn 6:82e142a864ad 90 data.username.cstring = const_cast<char*>(_username);
jburhenn 6:82e142a864ad 91 data.password.cstring = const_cast<char*>(password);
jburhenn 0:09ef59d2d0f7 92 return Base::connect(data);
jburhenn 0:09ef59d2d0f7 93 };
jburhenn 0:09ef59d2d0f7 94
jburhenn 0:09ef59d2d0f7 95 /**
jburhenn 0:09ef59d2d0f7 96 * Yield to allow MQTT message processing.
jburhenn 0:09ef59d2d0f7 97 * @param[in] timeout_ms The time in milliseconds to yield for
jburhenn 0:09ef59d2d0f7 98 * @return success code
jburhenn 0:09ef59d2d0f7 99 */
jburhenn 0:09ef59d2d0f7 100 int yield(unsigned long timeout_ms = 1000L) {
jburhenn 0:09ef59d2d0f7 101 return Base::yield(timeout_ms);
jburhenn 0:09ef59d2d0f7 102 };
jburhenn 0:09ef59d2d0f7 103
jburhenn 0:09ef59d2d0f7 104 /**
jburhenn 0:09ef59d2d0f7 105 * Check if the client is connected to the Cayenne server.
jburhenn 0:09ef59d2d0f7 106 * @return true if connected, false if not connected
jburhenn 0:09ef59d2d0f7 107 */
jburhenn 0:09ef59d2d0f7 108 bool connected() {
jburhenn 0:09ef59d2d0f7 109 return Base::isConnected();
jburhenn 0:09ef59d2d0f7 110 };
jburhenn 0:09ef59d2d0f7 111
jburhenn 0:09ef59d2d0f7 112 /**
jburhenn 0:09ef59d2d0f7 113 * Disconnect from the Cayenne server.
jburhenn 0:09ef59d2d0f7 114 * @return success code
jburhenn 0:09ef59d2d0f7 115 */
jburhenn 0:09ef59d2d0f7 116 int disconnect() {
jburhenn 0:09ef59d2d0f7 117 return Base::disconnect();
jburhenn 0:09ef59d2d0f7 118 };
jburhenn 0:09ef59d2d0f7 119
jburhenn 0:09ef59d2d0f7 120 /**
jburhenn 0:09ef59d2d0f7 121 * Send data to Cayenne.
jburhenn 0:09ef59d2d0f7 122 * @param[in] topic Cayenne topic
jburhenn 0:09ef59d2d0f7 123 * @param[in] channel The channel to send data to, or CAYENNE_NO_CHANNEL if there is none
jburhenn 0:09ef59d2d0f7 124 * @param[in] type Type to use for a type=value pair, can be NULL if sending to a topic that doesn't require type
jburhenn 0:09ef59d2d0f7 125 * @param[in] unit Optional unit to use for a type,unit=value payload, can be NULL
jburhenn 0:09ef59d2d0f7 126 * @param[in] value Data value
jburhenn 0:09ef59d2d0f7 127 * @param[in] clientID The client ID to use in the topic, NULL to use the clientID the client was initialized with
jburhenn 0:09ef59d2d0f7 128 * @return success code
jburhenn 0:09ef59d2d0f7 129 */
jburhenn 0:09ef59d2d0f7 130 int publishData(CayenneTopic topic, unsigned int channel, const char* type, const char* unit, const char* value, const char* clientID = NULL) {
jburhenn 0:09ef59d2d0f7 131 CayenneValuePair valuePair[1];
jburhenn 0:09ef59d2d0f7 132 valuePair[0].value = value;
jburhenn 0:09ef59d2d0f7 133 valuePair[0].unit = unit;
jburhenn 0:09ef59d2d0f7 134 return publishData(topic, channel, type, valuePair, 1, clientID);
jburhenn 0:09ef59d2d0f7 135 };
jburhenn 0:09ef59d2d0f7 136
jburhenn 0:09ef59d2d0f7 137 /**
jburhenn 0:09ef59d2d0f7 138 * Send data to Cayenne.
jburhenn 0:09ef59d2d0f7 139 * @param[in] topic Cayenne topic
jburhenn 0:09ef59d2d0f7 140 * @param[in] channel The channel to send data to, or CAYENNE_NO_CHANNEL if there is none
jburhenn 0:09ef59d2d0f7 141 * @param[in] type Type to use for a type=value pair, can be NULL if sending to a topic that doesn't require type
jburhenn 0:09ef59d2d0f7 142 * @param[in] unit Optional unit to use for a type,unit=value payload, can be NULL
jburhenn 0:09ef59d2d0f7 143 * @param[in] value Data value
jburhenn 0:09ef59d2d0f7 144 * @param[in] clientID The client ID to use in the topic, NULL to use the clientID the client was initialized with
jburhenn 0:09ef59d2d0f7 145 * @return success code
jburhenn 0:09ef59d2d0f7 146 */
jburhenn 0:09ef59d2d0f7 147 int publishData(CayenneTopic topic, unsigned int channel, const char* type, const char* unit, int value, const char* clientID = NULL) {
jburhenn 0:09ef59d2d0f7 148 char str[2 + 8 * sizeof(value)];
jburhenn 0:09ef59d2d0f7 149 #if defined(__AVR__) || defined (ARDUINO_ARCH_ARC32)
jburhenn 0:09ef59d2d0f7 150 itoa(value, str, 10);
jburhenn 0:09ef59d2d0f7 151 #else
jburhenn 0:09ef59d2d0f7 152 snprintf(str, sizeof(str), "%d", value);
jburhenn 0:09ef59d2d0f7 153 #endif
jburhenn 0:09ef59d2d0f7 154 return publishData(topic, channel, type, unit, str, clientID);
jburhenn 0:09ef59d2d0f7 155 };
jburhenn 0:09ef59d2d0f7 156
jburhenn 0:09ef59d2d0f7 157 /**
jburhenn 0:09ef59d2d0f7 158 * Send data to Cayenne.
jburhenn 0:09ef59d2d0f7 159 * @param[in] topic Cayenne topic
jburhenn 0:09ef59d2d0f7 160 * @param[in] channel The channel to send data to, or CAYENNE_NO_CHANNEL if there is none
jburhenn 0:09ef59d2d0f7 161 * @param[in] type Type to use for a type=value pair, can be NULL if sending to a topic that doesn't require type
jburhenn 0:09ef59d2d0f7 162 * @param[in] unit Optional unit to use for a type,unit=value payload, can be NULL
jburhenn 0:09ef59d2d0f7 163 * @param[in] value Data value
jburhenn 0:09ef59d2d0f7 164 * @param[in] clientID The client ID to use in the topic, NULL to use the clientID the client was initialized with
jburhenn 0:09ef59d2d0f7 165 * @return success code
jburhenn 0:09ef59d2d0f7 166 */
jburhenn 0:09ef59d2d0f7 167 int publishData(CayenneTopic topic, unsigned int channel, const char* type, const char* unit, unsigned int value, const char* clientID = NULL) {
jburhenn 0:09ef59d2d0f7 168 char str[1 + 8 * sizeof(value)];
jburhenn 0:09ef59d2d0f7 169 #if defined(__AVR__) || defined (ARDUINO_ARCH_ARC32)
jburhenn 0:09ef59d2d0f7 170 utoa(value, str, 10);
jburhenn 0:09ef59d2d0f7 171 #else
jburhenn 0:09ef59d2d0f7 172 snprintf(str, sizeof(str), "%u", value);
jburhenn 0:09ef59d2d0f7 173 #endif
jburhenn 0:09ef59d2d0f7 174 return publishData(topic, channel, type, unit, str, clientID);
jburhenn 0:09ef59d2d0f7 175 };
jburhenn 0:09ef59d2d0f7 176
jburhenn 0:09ef59d2d0f7 177 /**
jburhenn 0:09ef59d2d0f7 178 * Send data to Cayenne.
jburhenn 0:09ef59d2d0f7 179 * @param[in] topic Cayenne topic
jburhenn 0:09ef59d2d0f7 180 * @param[in] channel The channel to send data to, or CAYENNE_NO_CHANNEL if there is none
jburhenn 0:09ef59d2d0f7 181 * @param[in] type Type to use for a type=value pair, can be NULL if sending to a topic that doesn't require type
jburhenn 0:09ef59d2d0f7 182 * @param[in] unit Optional unit to use for a type,unit=value payload, can be NULL
jburhenn 0:09ef59d2d0f7 183 * @param[in] value Data value
jburhenn 0:09ef59d2d0f7 184 * @param[in] clientID The client ID to use in the topic, NULL to use the clientID the client was initialized with
jburhenn 0:09ef59d2d0f7 185 * @return success code
jburhenn 0:09ef59d2d0f7 186 */
jburhenn 0:09ef59d2d0f7 187 int publishData(CayenneTopic topic, unsigned int channel, const char* type, const char* unit, long value, const char* clientID = NULL) {
jburhenn 0:09ef59d2d0f7 188 char str[2 + 8 * sizeof(value)];
jburhenn 0:09ef59d2d0f7 189 #if defined(__AVR__) || defined (ARDUINO_ARCH_ARC32)
jburhenn 0:09ef59d2d0f7 190 ltoa(value, str, 10);
jburhenn 0:09ef59d2d0f7 191 #else
jburhenn 0:09ef59d2d0f7 192 snprintf(str, sizeof(str), "%ld", value);
jburhenn 0:09ef59d2d0f7 193 #endif
jburhenn 0:09ef59d2d0f7 194 return publishData(topic, channel, type, unit, str, clientID);
jburhenn 0:09ef59d2d0f7 195 };
jburhenn 0:09ef59d2d0f7 196
jburhenn 0:09ef59d2d0f7 197 /**
jburhenn 0:09ef59d2d0f7 198 * Send data to Cayenne.
jburhenn 0:09ef59d2d0f7 199 * @param[in] topic Cayenne topic
jburhenn 0:09ef59d2d0f7 200 * @param[in] channel The channel to send data to, or CAYENNE_NO_CHANNEL if there is none
jburhenn 0:09ef59d2d0f7 201 * @param[in] type Type to use for a type=value pair, can be NULL if sending to a topic that doesn't require type
jburhenn 0:09ef59d2d0f7 202 * @param[in] unit Optional unit to use for a type,unit=value payload, can be NULL
jburhenn 0:09ef59d2d0f7 203 * @param[in] value Data value
jburhenn 0:09ef59d2d0f7 204 * @param[in] clientID The client ID to use in the topic, NULL to use the clientID the client was initialized with
jburhenn 0:09ef59d2d0f7 205 * @return success code
jburhenn 0:09ef59d2d0f7 206 */
jburhenn 0:09ef59d2d0f7 207 int publishData(CayenneTopic topic, unsigned int channel, const char* type, const char* unit, unsigned long value, const char* clientID = NULL) {
jburhenn 0:09ef59d2d0f7 208 char str[1 + 8 * sizeof(value)];
jburhenn 0:09ef59d2d0f7 209 #if defined(__AVR__) || defined (ARDUINO_ARCH_ARC32)
jburhenn 0:09ef59d2d0f7 210 ultoa(value, str, 10);
jburhenn 0:09ef59d2d0f7 211 #else
jburhenn 0:09ef59d2d0f7 212 snprintf(str, sizeof(str), "%lu", value);
jburhenn 0:09ef59d2d0f7 213 #endif
jburhenn 0:09ef59d2d0f7 214 return publishData(topic, channel, type, unit, str, clientID);
jburhenn 0:09ef59d2d0f7 215 };
jburhenn 0:09ef59d2d0f7 216
jburhenn 0:09ef59d2d0f7 217 /**
jburhenn 0:09ef59d2d0f7 218 * Send data to Cayenne.
jburhenn 0:09ef59d2d0f7 219 * @param[in] topic Cayenne topic
jburhenn 0:09ef59d2d0f7 220 * @param[in] channel The channel to send data to, or CAYENNE_NO_CHANNEL if there is none
jburhenn 0:09ef59d2d0f7 221 * @param[in] type Type to use for a type=value pair, can be NULL if sending to a topic that doesn't require type
jburhenn 0:09ef59d2d0f7 222 * @param[in] unit Optional unit to use for a type,unit=value payload, can be NULL
jburhenn 0:09ef59d2d0f7 223 * @param[in] value Data value
jburhenn 0:09ef59d2d0f7 224 * @param[in] clientID The client ID to use in the topic, NULL to use the clientID the client was initialized with
jburhenn 0:09ef59d2d0f7 225 * @return success code
jburhenn 0:09ef59d2d0f7 226 */
jburhenn 0:09ef59d2d0f7 227 int publishData(CayenneTopic topic, unsigned int channel, const char* type, const char* unit, double value, const char* clientID = NULL) {
jburhenn 0:09ef59d2d0f7 228 char str[33];
jburhenn 0:09ef59d2d0f7 229 #if defined(__AVR__) || defined (ARDUINO_ARCH_ARC32)
jburhenn 0:09ef59d2d0f7 230 dtostrf(value, 5, 3, str);
jburhenn 0:09ef59d2d0f7 231 #else
jburhenn 0:09ef59d2d0f7 232 snprintf(str, 33, "%2.3f", value);
jburhenn 0:09ef59d2d0f7 233 #endif
jburhenn 0:09ef59d2d0f7 234 return publishData(topic, channel, type, unit, str, clientID);
jburhenn 0:09ef59d2d0f7 235 };
jburhenn 0:09ef59d2d0f7 236
jburhenn 0:09ef59d2d0f7 237 /**
jburhenn 0:09ef59d2d0f7 238 * Send data to Cayenne.
jburhenn 0:09ef59d2d0f7 239 * @param[in] topic Cayenne topic
jburhenn 0:09ef59d2d0f7 240 * @param[in] channel The channel to send data to, or CAYENNE_NO_CHANNEL if there is none
jburhenn 0:09ef59d2d0f7 241 * @param[in] type Type to use for a type=value pair, can be NULL if sending to a topic that doesn't require type
jburhenn 0:09ef59d2d0f7 242 * @param[in] unit Optional unit to use for a type,unit=value payload, can be NULL
jburhenn 0:09ef59d2d0f7 243 * @param[in] value Data value
jburhenn 0:09ef59d2d0f7 244 * @param[in] clientID The client ID to use in the topic, NULL to use the clientID the client was initialized with
jburhenn 0:09ef59d2d0f7 245 * @return success code
jburhenn 0:09ef59d2d0f7 246 */
jburhenn 0:09ef59d2d0f7 247 int publishData(CayenneTopic topic, unsigned int channel, const char* type, const char* unit, float value, const char* clientID = NULL) {
jburhenn 0:09ef59d2d0f7 248 char str[33];
jburhenn 0:09ef59d2d0f7 249 #if defined(__AVR__) || defined (ARDUINO_ARCH_ARC32)
jburhenn 0:09ef59d2d0f7 250 dtostrf(value, 5, 3, str);
jburhenn 0:09ef59d2d0f7 251 #else
jburhenn 0:09ef59d2d0f7 252 snprintf(str, 33, "%2.3f", value);
jburhenn 0:09ef59d2d0f7 253 #endif
jburhenn 0:09ef59d2d0f7 254 return publishData(topic, channel, type, unit, str, clientID);
jburhenn 0:09ef59d2d0f7 255 };
jburhenn 0:09ef59d2d0f7 256
jburhenn 0:09ef59d2d0f7 257 /**
jburhenn 0:09ef59d2d0f7 258 * Send data to Cayenne.
jburhenn 0:09ef59d2d0f7 259 * @param[in] topic Cayenne topic
jburhenn 0:09ef59d2d0f7 260 * @param[in] channel The channel to send data to, or CAYENNE_NO_CHANNEL if there is none
jburhenn 0:09ef59d2d0f7 261 * @param[in] type Type to use for a type=value pair, can be NULL if sending to a topic that doesn't require type
jburhenn 0:09ef59d2d0f7 262 * @param[in] unit Optional unit to use for a type,unit=value payload, can be NULL
jburhenn 0:09ef59d2d0f7 263 * @param[in] value Data value
jburhenn 0:09ef59d2d0f7 264 * @param[in] clientID The client ID to use in the topic, NULL to use the clientID the client was initialized with
jburhenn 0:09ef59d2d0f7 265 * @return success code
jburhenn 0:09ef59d2d0f7 266 */
jburhenn 0:09ef59d2d0f7 267 int publishData(CayenneTopic topic, unsigned int channel, const char* type, const CayenneValuePair* values, size_t valueCount, const char* clientID = NULL) {
jburhenn 0:09ef59d2d0f7 268 char buffer[MAX_MQTT_PACKET_SIZE + 1] = { 0 };
jburhenn 0:09ef59d2d0f7 269 int result = CayenneBuildTopic(buffer, sizeof(buffer), _username, clientID ? clientID : _clientID, topic, channel);
jburhenn 0:09ef59d2d0f7 270 if (result == CAYENNE_SUCCESS) {
jburhenn 0:09ef59d2d0f7 271 size_t size = strlen(buffer);
jburhenn 0:09ef59d2d0f7 272 char* payload = &buffer[size + 1];
jburhenn 0:09ef59d2d0f7 273 size = sizeof(buffer) - (size + 1);
jburhenn 0:09ef59d2d0f7 274 result = CayenneBuildDataPayload(payload, &size, type, values, valueCount);
jburhenn 0:09ef59d2d0f7 275 if (result == CAYENNE_SUCCESS) {
jburhenn 0:09ef59d2d0f7 276 result = Base::publish(buffer, payload, size, MQTT::QOS0, true);
jburhenn 0:09ef59d2d0f7 277 }
jburhenn 0:09ef59d2d0f7 278 }
jburhenn 0:09ef59d2d0f7 279 return result;
jburhenn 0:09ef59d2d0f7 280 };
jburhenn 0:09ef59d2d0f7 281
jburhenn 0:09ef59d2d0f7 282 /**
jburhenn 0:09ef59d2d0f7 283 * Send a response to a channel.
jburhenn 0:09ef59d2d0f7 284 * @param[in] topic Cayenne topic
jburhenn 0:09ef59d2d0f7 285 * @param[in] channel The channel to send data to, or CAYENNE_NO_CHANNEL if there is none
jburhenn 0:09ef59d2d0f7 286 * @param[in] channel The channel to send response to
jburhenn 0:09ef59d2d0f7 287 * @param[in] id ID of message the response is for
jburhenn 0:09ef59d2d0f7 288 * @param[in] error Optional error message, NULL for success
jburhenn 0:09ef59d2d0f7 289 * @param[in] clientID The client ID to use in the topic, NULL to use the clientID the client was initialized with
jburhenn 0:09ef59d2d0f7 290 * @return success code
jburhenn 0:09ef59d2d0f7 291 */
jburhenn 0:09ef59d2d0f7 292 int publishResponse(unsigned int channel, const char* id, const char* error, const char* clientID = NULL) {
jburhenn 0:09ef59d2d0f7 293 char buffer[MAX_MQTT_PACKET_SIZE + 1] = { 0 };
jburhenn 0:09ef59d2d0f7 294 int result = CayenneBuildTopic(buffer, sizeof(buffer), _username, clientID ? clientID : _clientID, RESPONSE_TOPIC, channel);
jburhenn 0:09ef59d2d0f7 295 if (result == CAYENNE_SUCCESS) {
jburhenn 0:09ef59d2d0f7 296 size_t size = strlen(buffer);
jburhenn 0:09ef59d2d0f7 297 char* payload = &buffer[size + 1];
jburhenn 0:09ef59d2d0f7 298 size = sizeof(buffer) - (size + 1);
jburhenn 0:09ef59d2d0f7 299 result = CayenneBuildResponsePayload(payload, &size, id, error);
jburhenn 0:09ef59d2d0f7 300 if (result == CAYENNE_SUCCESS) {
jburhenn 0:09ef59d2d0f7 301 result = Base::publish(buffer, payload, size, MQTT::QOS1, true);
jburhenn 0:09ef59d2d0f7 302 }
jburhenn 0:09ef59d2d0f7 303 }
jburhenn 0:09ef59d2d0f7 304 return result;
jburhenn 0:09ef59d2d0f7 305 }
jburhenn 0:09ef59d2d0f7 306
jburhenn 0:09ef59d2d0f7 307 /**
jburhenn 0:09ef59d2d0f7 308 * Subscribe to a topic.
jburhenn 0:09ef59d2d0f7 309 * @param[in] topic Cayenne topic
jburhenn 0:09ef59d2d0f7 310 * @param[in] channel The topic channel, CAYENNE_NO_CHANNEL for none, CAYENNE_ALL_CHANNELS for all
jburhenn 0:09ef59d2d0f7 311 * @param[in] handler The message handler, NULL to use default handler
jburhenn 0:09ef59d2d0f7 312 * @param[in] clientID The client ID to use in the topic, NULL to use the clientID the client was initialized with. This string is not copied, so it must remain available for the life of the subscription.
jburhenn 0:09ef59d2d0f7 313 * @return success code
jburhenn 0:09ef59d2d0f7 314 */
jburhenn 0:09ef59d2d0f7 315 int subscribe(CayenneTopic topic, unsigned int channel, CayenneMessageHandler handler = NULL, const char* clientID = NULL) {
jburhenn 0:09ef59d2d0f7 316 char topicName[MAX_MQTT_PACKET_SIZE] = { 0 };
jburhenn 0:09ef59d2d0f7 317 int result = CayenneBuildTopic(topicName, sizeof(topicName), _username, clientID ? clientID : _clientID, topic, channel);
jburhenn 0:09ef59d2d0f7 318 if (result == CAYENNE_SUCCESS) {
jburhenn 0:09ef59d2d0f7 319 result = Base::subscribe(topicName, MQTT::QOS0, NULL);
jburhenn 0:09ef59d2d0f7 320 if (handler && result == MQTT::QOS0) {
jburhenn 0:09ef59d2d0f7 321 for (int i = 0; i < MAX_MESSAGE_HANDLERS; ++i) {
jburhenn 0:09ef59d2d0f7 322 if (!_messageHandlers[i].fp.attached()) {
jburhenn 0:09ef59d2d0f7 323 _messageHandlers[i].clientID = clientID ? clientID : _clientID;
jburhenn 0:09ef59d2d0f7 324 _messageHandlers[i].topic = topic;
jburhenn 0:09ef59d2d0f7 325 _messageHandlers[i].channel = channel;
jburhenn 0:09ef59d2d0f7 326 _messageHandlers[i].fp.attach(handler);
jburhenn 0:09ef59d2d0f7 327 break;
jburhenn 0:09ef59d2d0f7 328 }
jburhenn 0:09ef59d2d0f7 329 }
jburhenn 0:09ef59d2d0f7 330 }
jburhenn 0:09ef59d2d0f7 331 }
jburhenn 0:09ef59d2d0f7 332 return result;
jburhenn 0:09ef59d2d0f7 333 };
jburhenn 0:09ef59d2d0f7 334
jburhenn 0:09ef59d2d0f7 335 /**
jburhenn 0:09ef59d2d0f7 336 * Unsubscribe from a topic.
jburhenn 0:09ef59d2d0f7 337 * @param[in] topic Cayenne topic
jburhenn 0:09ef59d2d0f7 338 * @param[in] channel The topic channel, CAYENNE_NO_CHANNEL for none, CAYENNE_ALL_CHANNELS for all
jburhenn 0:09ef59d2d0f7 339 * @param[in] clientID The client ID to use in the topic, NULL to use the clientID the client was initialized with
jburhenn 0:09ef59d2d0f7 340 * @return success code
jburhenn 0:09ef59d2d0f7 341 */
jburhenn 0:09ef59d2d0f7 342 int unsubscribe(CayenneTopic topic, unsigned int channel, const char* clientID = NULL) {
jburhenn 0:09ef59d2d0f7 343 char topicName[MAX_MQTT_PACKET_SIZE] = { 0 };
jburhenn 0:09ef59d2d0f7 344 int result = CayenneBuildTopic(topicName, sizeof(topicName), _username, clientID ? clientID : _clientID, topic, channel);
jburhenn 0:09ef59d2d0f7 345 if (result == CAYENNE_SUCCESS) {
jburhenn 0:09ef59d2d0f7 346 result = Base::unsubscribe(topicName);
jburhenn 0:09ef59d2d0f7 347 if (result == MQTT::SUCCESS) {
jburhenn 0:09ef59d2d0f7 348 for (int i = 0; i < MAX_MESSAGE_HANDLERS; ++i) {
jburhenn 0:09ef59d2d0f7 349 if ((_messageHandlers[i].topic == topic && _messageHandlers[i].channel == channel) &&
jburhenn 0:09ef59d2d0f7 350 (strcmp(clientID ? clientID : _clientID, _messageHandlers[i].clientID) == 0)) {
jburhenn 0:09ef59d2d0f7 351 _messageHandlers[i].clientID = NULL;
jburhenn 0:09ef59d2d0f7 352 _messageHandlers[i].topic = UNDEFINED_TOPIC;
jburhenn 0:09ef59d2d0f7 353 _messageHandlers[i].channel = CAYENNE_NO_CHANNEL;
jburhenn 0:09ef59d2d0f7 354 _messageHandlers[i].fp.detach();
jburhenn 0:09ef59d2d0f7 355 }
jburhenn 0:09ef59d2d0f7 356 }
jburhenn 0:09ef59d2d0f7 357 }
jburhenn 0:09ef59d2d0f7 358 }
jburhenn 0:09ef59d2d0f7 359 return result;
jburhenn 0:09ef59d2d0f7 360 }
jburhenn 0:09ef59d2d0f7 361
jburhenn 0:09ef59d2d0f7 362 /**
jburhenn 0:09ef59d2d0f7 363 * Handler for incoming MQTT::Client messages.
jburhenn 0:09ef59d2d0f7 364 * @param[in] md Message data
jburhenn 0:09ef59d2d0f7 365 */
jburhenn 0:09ef59d2d0f7 366 void mqttMessageArrived(MQTT::MessageData& md)
jburhenn 0:09ef59d2d0f7 367 {
jburhenn 0:09ef59d2d0f7 368 int result = MQTT::FAILURE;
jburhenn 0:09ef59d2d0f7 369 MessageData message;
jburhenn 0:09ef59d2d0f7 370
jburhenn 0:09ef59d2d0f7 371 result = CayenneParseTopic(&message.topic, &message.channel, &message.clientID, _username, md.topicName.lenstring.data, md.topicName.lenstring.len);
jburhenn 0:09ef59d2d0f7 372 if (result != CAYENNE_SUCCESS)
jburhenn 0:09ef59d2d0f7 373 return;
jburhenn 0:09ef59d2d0f7 374 //Null terminate the string since that is required by CayenneParsePayload. The readbuf is set to CAYENNE_MAX_MESSAGE_SIZE+1 to allow for appending a null.
jburhenn 0:09ef59d2d0f7 375 (static_cast<char*>(md.message.payload))[md.message.payloadlen] = '\0';
jburhenn 0:09ef59d2d0f7 376 message.valueCount = CAYENNE_MAX_MESSAGE_VALUES;
jburhenn 0:09ef59d2d0f7 377 result = CayenneParsePayload(message.values, &message.valueCount, &message.type, &message.id, message.topic, static_cast<char*>(md.message.payload));
jburhenn 0:09ef59d2d0f7 378 if (result != CAYENNE_SUCCESS)
jburhenn 0:09ef59d2d0f7 379 return;
jburhenn 0:09ef59d2d0f7 380
jburhenn 0:09ef59d2d0f7 381 result = MQTT::FAILURE;
jburhenn 0:09ef59d2d0f7 382 for (int i = 0; i < MAX_MESSAGE_HANDLERS; ++i) {
jburhenn 0:09ef59d2d0f7 383 if (_messageHandlers[i].fp.attached() && _messageHandlers[i].topic == message.topic &&
jburhenn 0:09ef59d2d0f7 384 (_messageHandlers[i].channel == message.channel || _messageHandlers[i].channel == CAYENNE_ALL_CHANNELS) &&
jburhenn 0:09ef59d2d0f7 385 (strcmp(_messageHandlers[i].clientID, message.clientID) == 0))
jburhenn 0:09ef59d2d0f7 386 {
jburhenn 0:09ef59d2d0f7 387 _messageHandlers[i].fp(message);
jburhenn 0:09ef59d2d0f7 388 result = MQTT::SUCCESS;
jburhenn 0:09ef59d2d0f7 389 }
jburhenn 0:09ef59d2d0f7 390 }
jburhenn 0:09ef59d2d0f7 391
jburhenn 0:09ef59d2d0f7 392 if (result == MQTT::FAILURE && _defaultMessageHandler.attached()) {
jburhenn 0:09ef59d2d0f7 393 _defaultMessageHandler(message);
jburhenn 0:09ef59d2d0f7 394 }
jburhenn 0:09ef59d2d0f7 395 }
jburhenn 0:09ef59d2d0f7 396
jburhenn 0:09ef59d2d0f7 397 private:
jburhenn 6:82e142a864ad 398 const char* _username;
jburhenn 6:82e142a864ad 399 const char* _clientID;
jburhenn 0:09ef59d2d0f7 400 struct CayenneMessageHandlers
jburhenn 0:09ef59d2d0f7 401 {
jburhenn 0:09ef59d2d0f7 402 const char* clientID;
jburhenn 0:09ef59d2d0f7 403 CayenneTopic topic;
jburhenn 0:09ef59d2d0f7 404 unsigned int channel;
jburhenn 0:09ef59d2d0f7 405 FP<void, MessageData&> fp;
jburhenn 0:09ef59d2d0f7 406 } _messageHandlers[MAX_MESSAGE_HANDLERS]; /* Message handlers are indexed by subscription topic */
jburhenn 0:09ef59d2d0f7 407 FP<void, MessageData&> _defaultMessageHandler;
jburhenn 0:09ef59d2d0f7 408 };
jburhenn 0:09ef59d2d0f7 409
jburhenn 0:09ef59d2d0f7 410 }
jburhenn 0:09ef59d2d0f7 411
jburhenn 0:09ef59d2d0f7 412 #endif