The Cayenne MQTT mbed Library provides functions to easily connect to the Cayenne IoT project builder.

Dependents:   Cayenne-ESP8266Interface Cayenne-WIZnet_Library Cayenne-WIZnetInterface Cayenne-X-NUCLEO-IDW01M1 ... more

Committer:
jburhenn
Date:
Fri Oct 07 17:21:45 2016 +0000
Revision:
0:09ef59d2d0f7
Child:
1:90dccf306268
Initial commit.

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 0:09ef59d2d0f7 29 typedef struct MessageData
jburhenn 0:09ef59d2d0f7 30 {
jburhenn 0:09ef59d2d0f7 31 const char* clientID;
jburhenn 0:09ef59d2d0f7 32 CayenneTopic topic;
jburhenn 0:09ef59d2d0f7 33 unsigned int channel;
jburhenn 0:09ef59d2d0f7 34 const char* id;
jburhenn 0:09ef59d2d0f7 35 const char* type;
jburhenn 0:09ef59d2d0f7 36 CayenneValuePair values[CAYENNE_MAX_MESSAGE_VALUES];
jburhenn 0:09ef59d2d0f7 37 size_t valueCount;
jburhenn 0:09ef59d2d0f7 38 } MessageData;
jburhenn 0:09ef59d2d0f7 39
jburhenn 0:09ef59d2d0f7 40 template<class Network, class Timer, int MAX_MQTT_PACKET_SIZE = 128, int MAX_MESSAGE_HANDLERS = 5>
jburhenn 0:09ef59d2d0f7 41 class MQTTClient : private MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, 0>
jburhenn 0:09ef59d2d0f7 42 {
jburhenn 0:09ef59d2d0f7 43 public:
jburhenn 0:09ef59d2d0f7 44 typedef MQTT::Client<Network, Timer, MAX_MQTT_PACKET_SIZE, 0> Base;
jburhenn 0:09ef59d2d0f7 45 typedef void(*CayenneMessageHandler)(MessageData&);
jburhenn 0:09ef59d2d0f7 46
jburhenn 0:09ef59d2d0f7 47 /**
jburhenn 0:09ef59d2d0f7 48 * Create an Cayenne MQTT client object.
jburhenn 0:09ef59d2d0f7 49 * @param[in] network Pointer to an instance of the Network class. Must be connected to the endpoint before calling MQTTClient connect.
jburhenn 0:09ef59d2d0f7 50 * @param[in] command_timeout_ms Timeout for commands in milliseconds.
jburhenn 0:09ef59d2d0f7 51 */
jburhenn 0:09ef59d2d0f7 52 MQTTClient(Network& network, unsigned int command_timeout_ms = 30000) : Base(network, command_timeout_ms), _username(NULL), _clientID(NULL)
jburhenn 0:09ef59d2d0f7 53 {
jburhenn 0:09ef59d2d0f7 54 Base::setDefaultMessageHandler(this, &MQTTClient::mqttMessageArrived);
jburhenn 0:09ef59d2d0f7 55 };
jburhenn 0:09ef59d2d0f7 56
jburhenn 0:09ef59d2d0f7 57 /**
jburhenn 0:09ef59d2d0f7 58 * Set default handler function called when a message is received.
jburhenn 0:09ef59d2d0f7 59 * @param[in] handler Function called when message is received, if no other handlers exist for the topic.
jburhenn 0:09ef59d2d0f7 60 */
jburhenn 0:09ef59d2d0f7 61 void setDefaultMessageHandler(CayenneMessageHandler handler)
jburhenn 0:09ef59d2d0f7 62 {
jburhenn 0:09ef59d2d0f7 63 _defaultMessageHandler.attach(handler);
jburhenn 0:09ef59d2d0f7 64 };
jburhenn 0:09ef59d2d0f7 65
jburhenn 0:09ef59d2d0f7 66 /**
jburhenn 0:09ef59d2d0f7 67 * Connect to the Cayenne server.
jburhenn 0:09ef59d2d0f7 68 * @param[in] username Cayenne username
jburhenn 0:09ef59d2d0f7 69 * @param[in] clientID Cayennne client ID
jburhenn 0:09ef59d2d0f7 70 * @param[in] password Password
jburhenn 0:09ef59d2d0f7 71 * @return success code
jburhenn 0:09ef59d2d0f7 72 */
jburhenn 0:09ef59d2d0f7 73 int connect(char* username, char* clientID, char* password) {
jburhenn 0:09ef59d2d0f7 74 MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
jburhenn 0:09ef59d2d0f7 75 data.MQTTVersion = 3;
jburhenn 0:09ef59d2d0f7 76 data.clientID.cstring = _clientID = clientID;
jburhenn 0:09ef59d2d0f7 77 data.username.cstring = _username = username;
jburhenn 0:09ef59d2d0f7 78 data.password.cstring = password;
jburhenn 0:09ef59d2d0f7 79 return Base::connect(data);
jburhenn 0:09ef59d2d0f7 80 };
jburhenn 0:09ef59d2d0f7 81
jburhenn 0:09ef59d2d0f7 82 /**
jburhenn 0:09ef59d2d0f7 83 * Yield to allow MQTT message processing.
jburhenn 0:09ef59d2d0f7 84 * @param[in] timeout_ms The time in milliseconds to yield for
jburhenn 0:09ef59d2d0f7 85 * @return success code
jburhenn 0:09ef59d2d0f7 86 */
jburhenn 0:09ef59d2d0f7 87 int yield(unsigned long timeout_ms = 1000L) {
jburhenn 0:09ef59d2d0f7 88 return Base::yield(timeout_ms);
jburhenn 0:09ef59d2d0f7 89 };
jburhenn 0:09ef59d2d0f7 90
jburhenn 0:09ef59d2d0f7 91 /**
jburhenn 0:09ef59d2d0f7 92 * Check if the client is connected to the Cayenne server.
jburhenn 0:09ef59d2d0f7 93 * @return true if connected, false if not connected
jburhenn 0:09ef59d2d0f7 94 */
jburhenn 0:09ef59d2d0f7 95 bool connected() {
jburhenn 0:09ef59d2d0f7 96 return Base::isConnected();
jburhenn 0:09ef59d2d0f7 97 };
jburhenn 0:09ef59d2d0f7 98
jburhenn 0:09ef59d2d0f7 99 /**
jburhenn 0:09ef59d2d0f7 100 * Disconnect from the Cayenne server.
jburhenn 0:09ef59d2d0f7 101 * @return success code
jburhenn 0:09ef59d2d0f7 102 */
jburhenn 0:09ef59d2d0f7 103 int disconnect() {
jburhenn 0:09ef59d2d0f7 104 return Base::disconnect();
jburhenn 0:09ef59d2d0f7 105 };
jburhenn 0:09ef59d2d0f7 106
jburhenn 0:09ef59d2d0f7 107 /**
jburhenn 0:09ef59d2d0f7 108 * Send data to Cayenne.
jburhenn 0:09ef59d2d0f7 109 * @param[in] topic Cayenne topic
jburhenn 0:09ef59d2d0f7 110 * @param[in] channel The channel to send data to, or CAYENNE_NO_CHANNEL if there is none
jburhenn 0:09ef59d2d0f7 111 * @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 112 * @param[in] unit Optional unit to use for a type,unit=value payload, can be NULL
jburhenn 0:09ef59d2d0f7 113 * @param[in] value Data value
jburhenn 0:09ef59d2d0f7 114 * @param[in] clientID The client ID to use in the topic, NULL to use the clientID the client was initialized with
jburhenn 0:09ef59d2d0f7 115 * @return success code
jburhenn 0:09ef59d2d0f7 116 */
jburhenn 0:09ef59d2d0f7 117 int publishData(CayenneTopic topic, unsigned int channel, const char* type, const char* unit, const char* value, const char* clientID = NULL) {
jburhenn 0:09ef59d2d0f7 118 CayenneValuePair valuePair[1];
jburhenn 0:09ef59d2d0f7 119 valuePair[0].value = value;
jburhenn 0:09ef59d2d0f7 120 valuePair[0].unit = unit;
jburhenn 0:09ef59d2d0f7 121 return publishData(topic, channel, type, valuePair, 1, clientID);
jburhenn 0:09ef59d2d0f7 122 };
jburhenn 0:09ef59d2d0f7 123
jburhenn 0:09ef59d2d0f7 124 /**
jburhenn 0:09ef59d2d0f7 125 * Send data to Cayenne.
jburhenn 0:09ef59d2d0f7 126 * @param[in] topic Cayenne topic
jburhenn 0:09ef59d2d0f7 127 * @param[in] channel The channel to send data to, or CAYENNE_NO_CHANNEL if there is none
jburhenn 0:09ef59d2d0f7 128 * @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 129 * @param[in] unit Optional unit to use for a type,unit=value payload, can be NULL
jburhenn 0:09ef59d2d0f7 130 * @param[in] value Data value
jburhenn 0:09ef59d2d0f7 131 * @param[in] clientID The client ID to use in the topic, NULL to use the clientID the client was initialized with
jburhenn 0:09ef59d2d0f7 132 * @return success code
jburhenn 0:09ef59d2d0f7 133 */
jburhenn 0:09ef59d2d0f7 134 int publishData(CayenneTopic topic, unsigned int channel, const char* type, const char* unit, int value, const char* clientID = NULL) {
jburhenn 0:09ef59d2d0f7 135 char str[2 + 8 * sizeof(value)];
jburhenn 0:09ef59d2d0f7 136 #if defined(__AVR__) || defined (ARDUINO_ARCH_ARC32)
jburhenn 0:09ef59d2d0f7 137 itoa(value, str, 10);
jburhenn 0:09ef59d2d0f7 138 #else
jburhenn 0:09ef59d2d0f7 139 snprintf(str, sizeof(str), "%d", value);
jburhenn 0:09ef59d2d0f7 140 #endif
jburhenn 0:09ef59d2d0f7 141 return publishData(topic, channel, type, unit, str, clientID);
jburhenn 0:09ef59d2d0f7 142 };
jburhenn 0:09ef59d2d0f7 143
jburhenn 0:09ef59d2d0f7 144 /**
jburhenn 0:09ef59d2d0f7 145 * Send data to Cayenne.
jburhenn 0:09ef59d2d0f7 146 * @param[in] topic Cayenne topic
jburhenn 0:09ef59d2d0f7 147 * @param[in] channel The channel to send data to, or CAYENNE_NO_CHANNEL if there is none
jburhenn 0:09ef59d2d0f7 148 * @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 149 * @param[in] unit Optional unit to use for a type,unit=value payload, can be NULL
jburhenn 0:09ef59d2d0f7 150 * @param[in] value Data value
jburhenn 0:09ef59d2d0f7 151 * @param[in] clientID The client ID to use in the topic, NULL to use the clientID the client was initialized with
jburhenn 0:09ef59d2d0f7 152 * @return success code
jburhenn 0:09ef59d2d0f7 153 */
jburhenn 0:09ef59d2d0f7 154 int publishData(CayenneTopic topic, unsigned int channel, const char* type, const char* unit, unsigned int value, const char* clientID = NULL) {
jburhenn 0:09ef59d2d0f7 155 char str[1 + 8 * sizeof(value)];
jburhenn 0:09ef59d2d0f7 156 #if defined(__AVR__) || defined (ARDUINO_ARCH_ARC32)
jburhenn 0:09ef59d2d0f7 157 utoa(value, str, 10);
jburhenn 0:09ef59d2d0f7 158 #else
jburhenn 0:09ef59d2d0f7 159 snprintf(str, sizeof(str), "%u", value);
jburhenn 0:09ef59d2d0f7 160 #endif
jburhenn 0:09ef59d2d0f7 161 return publishData(topic, channel, type, unit, str, clientID);
jburhenn 0:09ef59d2d0f7 162 };
jburhenn 0:09ef59d2d0f7 163
jburhenn 0:09ef59d2d0f7 164 /**
jburhenn 0:09ef59d2d0f7 165 * Send data to Cayenne.
jburhenn 0:09ef59d2d0f7 166 * @param[in] topic Cayenne topic
jburhenn 0:09ef59d2d0f7 167 * @param[in] channel The channel to send data to, or CAYENNE_NO_CHANNEL if there is none
jburhenn 0:09ef59d2d0f7 168 * @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 169 * @param[in] unit Optional unit to use for a type,unit=value payload, can be NULL
jburhenn 0:09ef59d2d0f7 170 * @param[in] value Data value
jburhenn 0:09ef59d2d0f7 171 * @param[in] clientID The client ID to use in the topic, NULL to use the clientID the client was initialized with
jburhenn 0:09ef59d2d0f7 172 * @return success code
jburhenn 0:09ef59d2d0f7 173 */
jburhenn 0:09ef59d2d0f7 174 int publishData(CayenneTopic topic, unsigned int channel, const char* type, const char* unit, long value, const char* clientID = NULL) {
jburhenn 0:09ef59d2d0f7 175 char str[2 + 8 * sizeof(value)];
jburhenn 0:09ef59d2d0f7 176 #if defined(__AVR__) || defined (ARDUINO_ARCH_ARC32)
jburhenn 0:09ef59d2d0f7 177 ltoa(value, str, 10);
jburhenn 0:09ef59d2d0f7 178 #else
jburhenn 0:09ef59d2d0f7 179 snprintf(str, sizeof(str), "%ld", value);
jburhenn 0:09ef59d2d0f7 180 #endif
jburhenn 0:09ef59d2d0f7 181 return publishData(topic, channel, type, unit, str, clientID);
jburhenn 0:09ef59d2d0f7 182 };
jburhenn 0:09ef59d2d0f7 183
jburhenn 0:09ef59d2d0f7 184 /**
jburhenn 0:09ef59d2d0f7 185 * Send data to Cayenne.
jburhenn 0:09ef59d2d0f7 186 * @param[in] topic Cayenne topic
jburhenn 0:09ef59d2d0f7 187 * @param[in] channel The channel to send data to, or CAYENNE_NO_CHANNEL if there is none
jburhenn 0:09ef59d2d0f7 188 * @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 189 * @param[in] unit Optional unit to use for a type,unit=value payload, can be NULL
jburhenn 0:09ef59d2d0f7 190 * @param[in] value Data value
jburhenn 0:09ef59d2d0f7 191 * @param[in] clientID The client ID to use in the topic, NULL to use the clientID the client was initialized with
jburhenn 0:09ef59d2d0f7 192 * @return success code
jburhenn 0:09ef59d2d0f7 193 */
jburhenn 0:09ef59d2d0f7 194 int publishData(CayenneTopic topic, unsigned int channel, const char* type, const char* unit, unsigned long value, const char* clientID = NULL) {
jburhenn 0:09ef59d2d0f7 195 char str[1 + 8 * sizeof(value)];
jburhenn 0:09ef59d2d0f7 196 #if defined(__AVR__) || defined (ARDUINO_ARCH_ARC32)
jburhenn 0:09ef59d2d0f7 197 ultoa(value, str, 10);
jburhenn 0:09ef59d2d0f7 198 #else
jburhenn 0:09ef59d2d0f7 199 snprintf(str, sizeof(str), "%lu", value);
jburhenn 0:09ef59d2d0f7 200 #endif
jburhenn 0:09ef59d2d0f7 201 return publishData(topic, channel, type, unit, str, clientID);
jburhenn 0:09ef59d2d0f7 202 };
jburhenn 0:09ef59d2d0f7 203
jburhenn 0:09ef59d2d0f7 204 /**
jburhenn 0:09ef59d2d0f7 205 * Send data to Cayenne.
jburhenn 0:09ef59d2d0f7 206 * @param[in] topic Cayenne topic
jburhenn 0:09ef59d2d0f7 207 * @param[in] channel The channel to send data to, or CAYENNE_NO_CHANNEL if there is none
jburhenn 0:09ef59d2d0f7 208 * @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 209 * @param[in] unit Optional unit to use for a type,unit=value payload, can be NULL
jburhenn 0:09ef59d2d0f7 210 * @param[in] value Data value
jburhenn 0:09ef59d2d0f7 211 * @param[in] clientID The client ID to use in the topic, NULL to use the clientID the client was initialized with
jburhenn 0:09ef59d2d0f7 212 * @return success code
jburhenn 0:09ef59d2d0f7 213 */
jburhenn 0:09ef59d2d0f7 214 int publishData(CayenneTopic topic, unsigned int channel, const char* type, const char* unit, double value, const char* clientID = NULL) {
jburhenn 0:09ef59d2d0f7 215 char str[33];
jburhenn 0:09ef59d2d0f7 216 #if defined(__AVR__) || defined (ARDUINO_ARCH_ARC32)
jburhenn 0:09ef59d2d0f7 217 dtostrf(value, 5, 3, str);
jburhenn 0:09ef59d2d0f7 218 #else
jburhenn 0:09ef59d2d0f7 219 snprintf(str, 33, "%2.3f", value);
jburhenn 0:09ef59d2d0f7 220 #endif
jburhenn 0:09ef59d2d0f7 221 return publishData(topic, channel, type, unit, str, clientID);
jburhenn 0:09ef59d2d0f7 222 };
jburhenn 0:09ef59d2d0f7 223
jburhenn 0:09ef59d2d0f7 224 /**
jburhenn 0:09ef59d2d0f7 225 * Send data to Cayenne.
jburhenn 0:09ef59d2d0f7 226 * @param[in] topic Cayenne topic
jburhenn 0:09ef59d2d0f7 227 * @param[in] channel The channel to send data to, or CAYENNE_NO_CHANNEL if there is none
jburhenn 0:09ef59d2d0f7 228 * @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 229 * @param[in] unit Optional unit to use for a type,unit=value payload, can be NULL
jburhenn 0:09ef59d2d0f7 230 * @param[in] value Data value
jburhenn 0:09ef59d2d0f7 231 * @param[in] clientID The client ID to use in the topic, NULL to use the clientID the client was initialized with
jburhenn 0:09ef59d2d0f7 232 * @return success code
jburhenn 0:09ef59d2d0f7 233 */
jburhenn 0:09ef59d2d0f7 234 int publishData(CayenneTopic topic, unsigned int channel, const char* type, const char* unit, float value, const char* clientID = NULL) {
jburhenn 0:09ef59d2d0f7 235 char str[33];
jburhenn 0:09ef59d2d0f7 236 #if defined(__AVR__) || defined (ARDUINO_ARCH_ARC32)
jburhenn 0:09ef59d2d0f7 237 dtostrf(value, 5, 3, str);
jburhenn 0:09ef59d2d0f7 238 #else
jburhenn 0:09ef59d2d0f7 239 snprintf(str, 33, "%2.3f", value);
jburhenn 0:09ef59d2d0f7 240 #endif
jburhenn 0:09ef59d2d0f7 241 return publishData(topic, channel, type, unit, str, clientID);
jburhenn 0:09ef59d2d0f7 242 };
jburhenn 0:09ef59d2d0f7 243
jburhenn 0:09ef59d2d0f7 244 /**
jburhenn 0:09ef59d2d0f7 245 * Send data to Cayenne.
jburhenn 0:09ef59d2d0f7 246 * @param[in] topic Cayenne topic
jburhenn 0:09ef59d2d0f7 247 * @param[in] channel The channel to send data to, or CAYENNE_NO_CHANNEL if there is none
jburhenn 0:09ef59d2d0f7 248 * @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 249 * @param[in] unit Optional unit to use for a type,unit=value payload, can be NULL
jburhenn 0:09ef59d2d0f7 250 * @param[in] value Data value
jburhenn 0:09ef59d2d0f7 251 * @param[in] clientID The client ID to use in the topic, NULL to use the clientID the client was initialized with
jburhenn 0:09ef59d2d0f7 252 * @return success code
jburhenn 0:09ef59d2d0f7 253 */
jburhenn 0:09ef59d2d0f7 254 int publishData(CayenneTopic topic, unsigned int channel, const char* type, const CayenneValuePair* values, size_t valueCount, const char* clientID = NULL) {
jburhenn 0:09ef59d2d0f7 255 char buffer[MAX_MQTT_PACKET_SIZE + 1] = { 0 };
jburhenn 0:09ef59d2d0f7 256 int result = CayenneBuildTopic(buffer, sizeof(buffer), _username, clientID ? clientID : _clientID, topic, channel);
jburhenn 0:09ef59d2d0f7 257 if (result == CAYENNE_SUCCESS) {
jburhenn 0:09ef59d2d0f7 258 size_t size = strlen(buffer);
jburhenn 0:09ef59d2d0f7 259 char* payload = &buffer[size + 1];
jburhenn 0:09ef59d2d0f7 260 size = sizeof(buffer) - (size + 1);
jburhenn 0:09ef59d2d0f7 261 result = CayenneBuildDataPayload(payload, &size, type, values, valueCount);
jburhenn 0:09ef59d2d0f7 262 if (result == CAYENNE_SUCCESS) {
jburhenn 0:09ef59d2d0f7 263 result = Base::publish(buffer, payload, size, MQTT::QOS0, true);
jburhenn 0:09ef59d2d0f7 264 }
jburhenn 0:09ef59d2d0f7 265 }
jburhenn 0:09ef59d2d0f7 266 return result;
jburhenn 0:09ef59d2d0f7 267 };
jburhenn 0:09ef59d2d0f7 268
jburhenn 0:09ef59d2d0f7 269 /**
jburhenn 0:09ef59d2d0f7 270 * Send a response to a channel.
jburhenn 0:09ef59d2d0f7 271 * @param[in] topic Cayenne topic
jburhenn 0:09ef59d2d0f7 272 * @param[in] channel The channel to send data to, or CAYENNE_NO_CHANNEL if there is none
jburhenn 0:09ef59d2d0f7 273 * @param[in] channel The channel to send response to
jburhenn 0:09ef59d2d0f7 274 * @param[in] id ID of message the response is for
jburhenn 0:09ef59d2d0f7 275 * @param[in] error Optional error message, NULL for success
jburhenn 0:09ef59d2d0f7 276 * @param[in] clientID The client ID to use in the topic, NULL to use the clientID the client was initialized with
jburhenn 0:09ef59d2d0f7 277 * @return success code
jburhenn 0:09ef59d2d0f7 278 */
jburhenn 0:09ef59d2d0f7 279 int publishResponse(unsigned int channel, const char* id, const char* error, const char* clientID = NULL) {
jburhenn 0:09ef59d2d0f7 280 char buffer[MAX_MQTT_PACKET_SIZE + 1] = { 0 };
jburhenn 0:09ef59d2d0f7 281 int result = CayenneBuildTopic(buffer, sizeof(buffer), _username, clientID ? clientID : _clientID, RESPONSE_TOPIC, channel);
jburhenn 0:09ef59d2d0f7 282 if (result == CAYENNE_SUCCESS) {
jburhenn 0:09ef59d2d0f7 283 size_t size = strlen(buffer);
jburhenn 0:09ef59d2d0f7 284 char* payload = &buffer[size + 1];
jburhenn 0:09ef59d2d0f7 285 size = sizeof(buffer) - (size + 1);
jburhenn 0:09ef59d2d0f7 286 result = CayenneBuildResponsePayload(payload, &size, id, error);
jburhenn 0:09ef59d2d0f7 287 if (result == CAYENNE_SUCCESS) {
jburhenn 0:09ef59d2d0f7 288 result = Base::publish(buffer, payload, size, MQTT::QOS1, true);
jburhenn 0:09ef59d2d0f7 289 }
jburhenn 0:09ef59d2d0f7 290 }
jburhenn 0:09ef59d2d0f7 291 return result;
jburhenn 0:09ef59d2d0f7 292 }
jburhenn 0:09ef59d2d0f7 293
jburhenn 0:09ef59d2d0f7 294 /**
jburhenn 0:09ef59d2d0f7 295 * Subscribe to a topic.
jburhenn 0:09ef59d2d0f7 296 * @param[in] topic Cayenne topic
jburhenn 0:09ef59d2d0f7 297 * @param[in] channel The topic channel, CAYENNE_NO_CHANNEL for none, CAYENNE_ALL_CHANNELS for all
jburhenn 0:09ef59d2d0f7 298 * @param[in] handler The message handler, NULL to use default handler
jburhenn 0:09ef59d2d0f7 299 * @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 300 * @return success code
jburhenn 0:09ef59d2d0f7 301 */
jburhenn 0:09ef59d2d0f7 302 int subscribe(CayenneTopic topic, unsigned int channel, CayenneMessageHandler handler = NULL, const char* clientID = NULL) {
jburhenn 0:09ef59d2d0f7 303 char topicName[MAX_MQTT_PACKET_SIZE] = { 0 };
jburhenn 0:09ef59d2d0f7 304 int result = CayenneBuildTopic(topicName, sizeof(topicName), _username, clientID ? clientID : _clientID, topic, channel);
jburhenn 0:09ef59d2d0f7 305 if (result == CAYENNE_SUCCESS) {
jburhenn 0:09ef59d2d0f7 306 result = Base::subscribe(topicName, MQTT::QOS0, NULL);
jburhenn 0:09ef59d2d0f7 307 if (handler && result == MQTT::QOS0) {
jburhenn 0:09ef59d2d0f7 308 for (int i = 0; i < MAX_MESSAGE_HANDLERS; ++i) {
jburhenn 0:09ef59d2d0f7 309 if (!_messageHandlers[i].fp.attached()) {
jburhenn 0:09ef59d2d0f7 310 _messageHandlers[i].clientID = clientID ? clientID : _clientID;
jburhenn 0:09ef59d2d0f7 311 _messageHandlers[i].topic = topic;
jburhenn 0:09ef59d2d0f7 312 _messageHandlers[i].channel = channel;
jburhenn 0:09ef59d2d0f7 313 _messageHandlers[i].fp.attach(handler);
jburhenn 0:09ef59d2d0f7 314 break;
jburhenn 0:09ef59d2d0f7 315 }
jburhenn 0:09ef59d2d0f7 316 }
jburhenn 0:09ef59d2d0f7 317 }
jburhenn 0:09ef59d2d0f7 318 }
jburhenn 0:09ef59d2d0f7 319 return result;
jburhenn 0:09ef59d2d0f7 320 };
jburhenn 0:09ef59d2d0f7 321
jburhenn 0:09ef59d2d0f7 322 /**
jburhenn 0:09ef59d2d0f7 323 * Unsubscribe from a topic.
jburhenn 0:09ef59d2d0f7 324 * @param[in] topic Cayenne topic
jburhenn 0:09ef59d2d0f7 325 * @param[in] channel The topic channel, CAYENNE_NO_CHANNEL for none, CAYENNE_ALL_CHANNELS for all
jburhenn 0:09ef59d2d0f7 326 * @param[in] clientID The client ID to use in the topic, NULL to use the clientID the client was initialized with
jburhenn 0:09ef59d2d0f7 327 * @return success code
jburhenn 0:09ef59d2d0f7 328 */
jburhenn 0:09ef59d2d0f7 329 int unsubscribe(CayenneTopic topic, unsigned int channel, const char* clientID = NULL) {
jburhenn 0:09ef59d2d0f7 330 char topicName[MAX_MQTT_PACKET_SIZE] = { 0 };
jburhenn 0:09ef59d2d0f7 331 int result = CayenneBuildTopic(topicName, sizeof(topicName), _username, clientID ? clientID : _clientID, topic, channel);
jburhenn 0:09ef59d2d0f7 332 if (result == CAYENNE_SUCCESS) {
jburhenn 0:09ef59d2d0f7 333 result = Base::unsubscribe(topicName);
jburhenn 0:09ef59d2d0f7 334 if (result == MQTT::SUCCESS) {
jburhenn 0:09ef59d2d0f7 335 for (int i = 0; i < MAX_MESSAGE_HANDLERS; ++i) {
jburhenn 0:09ef59d2d0f7 336 if ((_messageHandlers[i].topic == topic && _messageHandlers[i].channel == channel) &&
jburhenn 0:09ef59d2d0f7 337 (strcmp(clientID ? clientID : _clientID, _messageHandlers[i].clientID) == 0)) {
jburhenn 0:09ef59d2d0f7 338 _messageHandlers[i].clientID = NULL;
jburhenn 0:09ef59d2d0f7 339 _messageHandlers[i].topic = UNDEFINED_TOPIC;
jburhenn 0:09ef59d2d0f7 340 _messageHandlers[i].channel = CAYENNE_NO_CHANNEL;
jburhenn 0:09ef59d2d0f7 341 _messageHandlers[i].fp.detach();
jburhenn 0:09ef59d2d0f7 342 }
jburhenn 0:09ef59d2d0f7 343 }
jburhenn 0:09ef59d2d0f7 344 }
jburhenn 0:09ef59d2d0f7 345 }
jburhenn 0:09ef59d2d0f7 346 return result;
jburhenn 0:09ef59d2d0f7 347 }
jburhenn 0:09ef59d2d0f7 348
jburhenn 0:09ef59d2d0f7 349 /**
jburhenn 0:09ef59d2d0f7 350 * Handler for incoming MQTT::Client messages.
jburhenn 0:09ef59d2d0f7 351 * @param[in] md Message data
jburhenn 0:09ef59d2d0f7 352 */
jburhenn 0:09ef59d2d0f7 353 void mqttMessageArrived(MQTT::MessageData& md)
jburhenn 0:09ef59d2d0f7 354 {
jburhenn 0:09ef59d2d0f7 355 int result = MQTT::FAILURE;
jburhenn 0:09ef59d2d0f7 356 MessageData message;
jburhenn 0:09ef59d2d0f7 357
jburhenn 0:09ef59d2d0f7 358 result = CayenneParseTopic(&message.topic, &message.channel, &message.clientID, _username, md.topicName.lenstring.data, md.topicName.lenstring.len);
jburhenn 0:09ef59d2d0f7 359 if (result != CAYENNE_SUCCESS)
jburhenn 0:09ef59d2d0f7 360 return;
jburhenn 0:09ef59d2d0f7 361 //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 362 (static_cast<char*>(md.message.payload))[md.message.payloadlen] = '\0';
jburhenn 0:09ef59d2d0f7 363 message.valueCount = CAYENNE_MAX_MESSAGE_VALUES;
jburhenn 0:09ef59d2d0f7 364 result = CayenneParsePayload(message.values, &message.valueCount, &message.type, &message.id, message.topic, static_cast<char*>(md.message.payload));
jburhenn 0:09ef59d2d0f7 365 if (result != CAYENNE_SUCCESS)
jburhenn 0:09ef59d2d0f7 366 return;
jburhenn 0:09ef59d2d0f7 367
jburhenn 0:09ef59d2d0f7 368 result = MQTT::FAILURE;
jburhenn 0:09ef59d2d0f7 369 for (int i = 0; i < MAX_MESSAGE_HANDLERS; ++i) {
jburhenn 0:09ef59d2d0f7 370 if (_messageHandlers[i].fp.attached() && _messageHandlers[i].topic == message.topic &&
jburhenn 0:09ef59d2d0f7 371 (_messageHandlers[i].channel == message.channel || _messageHandlers[i].channel == CAYENNE_ALL_CHANNELS) &&
jburhenn 0:09ef59d2d0f7 372 (strcmp(_messageHandlers[i].clientID, message.clientID) == 0))
jburhenn 0:09ef59d2d0f7 373 {
jburhenn 0:09ef59d2d0f7 374 _messageHandlers[i].fp(message);
jburhenn 0:09ef59d2d0f7 375 result = MQTT::SUCCESS;
jburhenn 0:09ef59d2d0f7 376 }
jburhenn 0:09ef59d2d0f7 377 }
jburhenn 0:09ef59d2d0f7 378
jburhenn 0:09ef59d2d0f7 379 if (result == MQTT::FAILURE && _defaultMessageHandler.attached()) {
jburhenn 0:09ef59d2d0f7 380 _defaultMessageHandler(message);
jburhenn 0:09ef59d2d0f7 381 }
jburhenn 0:09ef59d2d0f7 382 }
jburhenn 0:09ef59d2d0f7 383
jburhenn 0:09ef59d2d0f7 384 private:
jburhenn 0:09ef59d2d0f7 385 char* _username;
jburhenn 0:09ef59d2d0f7 386 char* _clientID;
jburhenn 0:09ef59d2d0f7 387 struct CayenneMessageHandlers
jburhenn 0:09ef59d2d0f7 388 {
jburhenn 0:09ef59d2d0f7 389 const char* clientID;
jburhenn 0:09ef59d2d0f7 390 CayenneTopic topic;
jburhenn 0:09ef59d2d0f7 391 unsigned int channel;
jburhenn 0:09ef59d2d0f7 392 FP<void, MessageData&> fp;
jburhenn 0:09ef59d2d0f7 393 } _messageHandlers[MAX_MESSAGE_HANDLERS]; /* Message handlers are indexed by subscription topic */
jburhenn 0:09ef59d2d0f7 394 FP<void, MessageData&> _defaultMessageHandler;
jburhenn 0:09ef59d2d0f7 395 };
jburhenn 0:09ef59d2d0f7 396
jburhenn 0:09ef59d2d0f7 397 }
jburhenn 0:09ef59d2d0f7 398
jburhenn 0:09ef59d2d0f7 399 #endif