Skip to content

Commit df879cc

Browse files
authored
Merge pull request #15 from myDevicesIoT/feature/multivalue
Add new data types and units.
2 parents ece2c14 + b7e5692 commit df879cc

24 files changed

+357
-844
lines changed

library.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name=CayenneMQTT
2-
version=1.0.1
2+
version=1.0.2-beta
33
author=myDevices
44
maintainer=myDevices
55
sentence=Connect a device to the Cayenne dashboard using MQTT.

src/CayenneArduinoMQTTClient.h

Lines changed: 71 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEAL
2020

2121
#include "CayenneArduinoDefines.h"
2222
#include "CayenneMQTTClient/CayenneMQTTClient.h"
23+
#include "CayenneUtils/CayenneDataArray.h"
2324

2425
const int MAX_CHANNEL_ARRAY_SIZE = 4;
2526

@@ -162,30 +163,6 @@ class CayenneArduinoMQTTClient
162163
publishData(DATA_TOPIC, channel, data, type, unit);
163164
}
164165

165-
/**
166-
* Sends an array of measurements to a Cayenne channel
167-
*
168-
* @param channel Cayenne channel number
169-
* @param values Array of values to be sent
170-
* @param type Measurement type
171-
*/
172-
void virtualWrite(unsigned int channel, const CayenneDataArray& values, const char* type)
173-
{
174-
publishData(DATA_TOPIC, channel, values.getArray(), values.getCount(), type);
175-
}
176-
177-
/**
178-
* Sends an array of measurements to a Cayenne channel
179-
*
180-
* @param channel Cayenne channel number
181-
* @param values Array of values to be sent
182-
* @param type Measurement type
183-
*/
184-
void virtualWrite(unsigned int channel, const CayenneDataArray& values, const __FlashStringHelper* type)
185-
{
186-
publishData(DATA_TOPIC, channel, values.getArray(), values.getCount(), type);
187-
}
188-
189166
/**
190167
* Sends a response after processing a command
191168
*
@@ -290,6 +267,40 @@ class CayenneArduinoMQTTClient
290267
virtualWrite(channel, value, F(TYPE_DIGITAL_SENSOR), F(UNIT_DIGITAL));
291268
}
292269

270+
/**
271+
* Sends an acceleration value array to a Cayenne channel
272+
*
273+
* @param channel Cayenne channel number
274+
* @param x Acceration on the X-axis
275+
* @param y Acceration on the Y-axis
276+
* @param z Acceration on the Z-axis
277+
*/
278+
void accelWrite(unsigned int channel, float x, float y, float z)
279+
{
280+
CayenneDataArray values;
281+
values.add(x, 1);
282+
values.add(y, 1);
283+
values.add(z, 1);
284+
virtualWrite(channel, values.getString(), F(TYPE_ACCELERATION), F(UNIT_G));
285+
}
286+
287+
/**
288+
* Sends a GPS value array to a Cayenne channel
289+
*
290+
* @param channel Cayenne channel number
291+
* @param latitude Latitude in degrees
292+
* @param longitude Longitude in degrees
293+
* @param altitude Altitude in meters
294+
*/
295+
void gpsWrite(unsigned int channel, float latitude, float longitude, float altitude)
296+
{
297+
CayenneDataArray values;
298+
values.add(latitude, 5);
299+
values.add(longitude, 5);
300+
values.add(altitude, 1);
301+
virtualWrite(channel, values.getString(), F(TYPE_GPS), F(UNIT_METER));
302+
}
303+
293304
/**
294305
* Requests Server to re-send current values for all widgets.
295306
*/
@@ -343,9 +354,9 @@ class CayenneArduinoMQTTClient
343354
*/
344355
template <typename T>
345356
static void publishData(CayenneTopic topic, unsigned int channel, const T& data, const char* key = NULL, const char* subkey = NULL) {
346-
CayenneDataArray values;
347-
values.add(subkey, data);
348-
publishData(topic, channel, values.getArray(), values.getCount(), key);
357+
CayenneDataArray value;
358+
value.add(data);
359+
publishData(topic, channel, value.getString(), key, subkey);
349360
}
350361

351362
/**
@@ -358,39 +369,42 @@ class CayenneArduinoMQTTClient
358369
*/
359370
template <typename T>
360371
static void publishData(CayenneTopic topic, unsigned int channel, const T& data, const __FlashStringHelper* key, const __FlashStringHelper* subkey = NULL) {
361-
char keyBuffer[MAX_TYPE_LENGTH + 1];
362-
CayenneDataArray values;
363-
values.add(subkey, data);
372+
char keyBuffer[MAX_TYPE_LENGTH + 1] = { 0 };
373+
char subkeyBuffer[MAX_UNIT_LENGTH + 1] = { 0 };
374+
CayenneDataArray value;
375+
value.add(data);
364376
CAYENNE_MEMCPY(keyBuffer, reinterpret_cast<const char *>(key), CAYENNE_STRLEN(reinterpret_cast<const char *>(key)) + 1);
365-
publishData(topic, channel, values.getArray(), values.getCount(), keyBuffer);
377+
if (subkey)
378+
CAYENNE_MEMCPY(subkeyBuffer, reinterpret_cast<const char *>(subkey), CAYENNE_STRLEN(reinterpret_cast<const char *>(subkey)) + 1);
379+
publishData(topic, channel, value.getString(), keyBuffer, subkeyBuffer);
366380
}
367381

368382
/**
369383
* Publish value array using specified topic suffix
370384
* @param topic Cayenne topic
371385
* @param channel Cayenne channel number
372-
* @param values Array of values to be sent
373-
* @param valueCount Count of values in array
386+
* @param data Data to send
374387
* @param key Optional key to use for a key=data pair
388+
* @param subkey Optional subkey to use for a key,subkey=data pair
375389
*/
376-
static void publishData(CayenneTopic topic, unsigned int channel, const CayenneValuePair values[], size_t valueCount, const char* key) {
377-
CAYENNE_LOG_DEBUG("Publish: topic %d, channel %u, value %s, subkey %s, key %s", topic, channel, values[0].value, values[0].unit, key);
378-
CayenneMQTTPublishDataArray(&_mqttClient, NULL, topic, channel, key, values, valueCount);
390+
static void publishData(CayenneTopic topic, unsigned int channel, const char* data, const char* key, const char* subkey) {
391+
CAYENNE_LOG_DEBUG("Publish: topic %d, channel %u, key %s, subkey %s, data %s", topic, channel, key, subkey, data);
392+
CayenneMQTTPublishData(&_mqttClient, NULL, topic, channel, key, subkey, data);
379393
}
380394

381395
/**
382396
* Publish value array using specified topic suffix
383397
* @param topic Cayenne topic
384398
* @param channel Cayenne channel number
385-
* @param values Array of values to be sent
386-
* @param valueCount Count of values in array
399+
* @param data Data to send
387400
* @param key Optional key to use for a key=data pair
401+
* @param subkey Optional subkey to use for a key,subkey=data pair
388402
*/
389-
static void publishData(CayenneTopic topic, unsigned int channel, const CayenneValuePair values[], size_t valueCount, const __FlashStringHelper* key) {
403+
static void publishData(CayenneTopic topic, unsigned int channel, const char* data, const __FlashStringHelper* key, const char* subkey) {
390404
char keyBuffer[MAX_TYPE_LENGTH + 1];
391405
CAYENNE_MEMCPY(keyBuffer, reinterpret_cast<const char *>(key), CAYENNE_STRLEN(reinterpret_cast<const char *>(key)) + 1);
392-
CAYENNE_LOG_DEBUG("Publish: topic %d, channel %u, value %s, subkey %s, key %s", topic, channel, values[0].value, values[0].unit, keyBuffer);
393-
CayenneMQTTPublishDataArray(&_mqttClient, NULL, topic, channel, keyBuffer, values, valueCount);
406+
CAYENNE_LOG_DEBUG("Publish: topic %d, channel %u, key %s, subkey %s, data %s", topic, channel, keyBuffer, subkey, data);
407+
CayenneMQTTPublishData(&_mqttClient, NULL, topic, channel, keyBuffer, subkey, data);
394408
}
395409

396410
/**
@@ -468,8 +482,8 @@ void handleMessage(CayenneMessageData* messageData) {
468482
Request request = { messageData->channel };
469483
const char* response = NULL;
470484
CayenneMessage message(messageData);
471-
if (strlen(messageData->values[0].value)) {
472-
CAYENNE_LOG_DEBUG("In: value %s, channel %d", messageData->values[0].value, request.channel);
485+
if (strlen(messageData->value)) {
486+
CAYENNE_LOG_DEBUG("In: value %s, channel %d", messageData->value, request.channel);
473487
InputHandlerFunction handler = GetInputHandler(request.channel);
474488
if (handler && handler != InputHandler) {
475489
handler(request, message);
@@ -483,14 +497,14 @@ void handleMessage(CayenneMessageData* messageData) {
483497
}
484498
if(response == NULL) {
485499
// If there was no error, we send the new channel state, which should be the command value we received.
486-
CayenneArduinoMQTTClient::publishState(DATA_TOPIC, messageData->channel, messageData->values[0].value);
500+
CayenneArduinoMQTTClient::publishState(DATA_TOPIC, messageData->channel, messageData->value);
487501
}
488502
CayenneArduinoMQTTClient::responseWrite(response, messageData->id);
489503
}
490504

491505
#ifdef DIGITAL_AND_ANALOG_SUPPORT
492506
void handleAnalogMessage(CayenneMessageData* messageData) {
493-
float value = atof(messageData->values[0].value);
507+
float value = atof(messageData->value);
494508
char* response = NULL;
495509
if (value >= 0 && value <= 1) {
496510
double test = value * 255;
@@ -501,18 +515,18 @@ void handleAnalogMessage(CayenneMessageData* messageData) {
501515
else {
502516
response = ERROR_INCORRECT_PARAM;
503517
}
504-
CayenneArduinoMQTTClient::responseWrite(messageData->channel, response, messageData->id);
518+
CayenneArduinoMQTTClient::responseWrite(response, messageData->id);
505519
}
506520

507521
void handleDigitalMessage(CayenneMessageData* messageData) {
508522
char* response = NULL;
509-
if (messageData->values[0].value && strlen(messageData->values[0].value) == 1) {
510-
CAYENNE_LOG_DEBUG("dw %s, channel %d", messageData->values[0].value, messageData->channel);
511-
if (messageData->values[0].value[0] == '0') {
523+
if (messageData->value && strlen(messageData->value) == 1) {
524+
CAYENNE_LOG_DEBUG("dw %s, channel %d", messageData->value, messageData->channel);
525+
if (messageData->value[0] == '0') {
512526
digitalWrite(messageData->channel, LOW);
513527
CayenneArduinoMQTTClient::publishState(DIGITAL_TOPIC, messageData->channel, LOW);
514528
}
515-
else if (messageData->values[0].value[0] == '1') {
529+
else if (messageData->value[0] == '1') {
516530
digitalWrite(messageData->channel, HIGH);
517531
CayenneArduinoMQTTClient::publishState(DIGITAL_TOPIC, messageData->channel, HIGH);
518532
}
@@ -523,7 +537,7 @@ void handleDigitalMessage(CayenneMessageData* messageData) {
523537
else {
524538
response = ERROR_INCORRECT_PARAM;
525539
}
526-
CayenneArduinoMQTTClient::responseWrite(messageData->channel, response, messageData->id);
540+
CayenneArduinoMQTTClient::responseWrite(response, messageData->id);
527541
}
528542
#endif
529543

@@ -539,13 +553,13 @@ void CayenneMessageArrived(CayenneMessageData* message) {
539553
handleDigitalMessage(message);
540554
break;
541555
case DIGITAL_CONFIG_TOPIC:
542-
configChannel(CayenneArduinoMQTTClient::digitalChannels, message->channel, message->values[0].value);
556+
configChannel(CayenneArduinoMQTTClient::digitalChannels, message->channel, message->value);
543557
break;
544558
case ANALOG_COMMAND_TOPIC:
545559
handleAnalogMessage(message);
546560
break;
547561
case ANALOG_CONFIG_TOPIC:
548-
configChannel(CayenneArduinoMQTTClient::analogChannels, message->channel, message->values[0].value);
562+
configChannel(CayenneArduinoMQTTClient::analogChannels, message->channel, message->value);
549563
break;
550564
#endif
551565
default:
@@ -555,14 +569,11 @@ void CayenneMessageArrived(CayenneMessageData* message) {
555569
// CAYENNE_PRINT.print(message->type);
556570
// CAYENNE_PRINT.print(", ");
557571
// }
558-
// for (int i = 0; i < message->valueCount; ++i) {
559-
// if (message->values[i].unit) {
560-
// CAYENNE_PRINT.print(message->values[i].unit);
561-
// CAYENNE_PRINT.print("=");
562-
// }
563-
// CAYENNE_PRINT.print(message->values[i].value);
564-
// CAYENNE_PRINT.print(" ");
572+
// if (message->unit) {
573+
// CAYENNE_PRINT.print(message->unit);
574+
// CAYENNE_PRINT.print("=");
565575
// }
576+
// CAYENNE_PRINT.print(message->value);
566577
// CAYENNE_PRINT.println();
567578
//#endif
568579
break;

src/CayenneMQTTClient/CayenneMQTTClient.c

Lines changed: 19 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,7 @@ void MQTTMessageArrived(MessageData* md, void* userData)
3232
return;
3333
//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.
3434
((char*)md->message->payload)[md->message->payloadlen] = '\0';
35-
message.valueCount = CAYENNE_MAX_MESSAGE_VALUES;
36-
result = CayenneParsePayload(message.values, &message.valueCount, &message.type, &message.id, message.topic, (char*)md->message->payload);
35+
result = CayenneParsePayload(&message.type, &message.unit, &message.value, &message.id, message.topic, (char*)md->message->payload);
3736
if (result != CAYENNE_SUCCESS)
3837
return;
3938

@@ -110,10 +109,24 @@ int CayenneMQTTConnect(CayenneMQTTClient* client)
110109
*/
111110
int CayenneMQTTPublishData(CayenneMQTTClient* client, const char* clientID, CayenneTopic topic, unsigned int channel, const char* type, const char* unit, const char* value)
112111
{
113-
CayenneValuePair valuePair[1];
114-
valuePair[0].value = value;
115-
valuePair[0].unit = unit;
116-
return CayenneMQTTPublishDataArray(client, clientID, topic, channel, type, valuePair, 1);
112+
char buffer[CAYENNE_MAX_MESSAGE_SIZE + 1] = { 0 };
113+
int result = CayenneBuildTopic(buffer, sizeof(buffer), client->username, clientID ? clientID : client->clientID, topic, channel);
114+
if (result == CAYENNE_SUCCESS) {
115+
size_t size = strlen(buffer);
116+
char* payload = &buffer[size + 1];
117+
size = sizeof(buffer) - (size + 1);
118+
result = CayenneBuildDataPayload(payload, &size, type, unit, value);
119+
if (result == CAYENNE_SUCCESS) {
120+
MQTTMessage message;
121+
message.qos = QOS0;
122+
message.retained = (topic != COMMAND_TOPIC) ? 1 : 0;
123+
message.dup = 0;
124+
message.payload = (void*)payload;
125+
message.payloadlen = size;
126+
result = MQTTPublish(&client->mqttClient, buffer, &message);
127+
}
128+
}
129+
return result;
117130
}
118131

119132

@@ -254,38 +267,6 @@ int CayenneMQTTPublishDataFloat(CayenneMQTTClient* client, const char* clientID,
254267
return CayenneMQTTPublishData(client, clientID, topic, channel, type, unit, str);
255268
}
256269

257-
/**
258-
* Send multiple value data array to Cayenne.
259-
* @param[in] client The client object
260-
* @param[in] clientID The client ID to use in the topic, NULL to use the clientID the client was initialized with
261-
* @param[in] topic Cayenne topic
262-
* @param[in] channel The channel to send data to, or CAYENNE_NO_CHANNEL if there is none
263-
* @param[in] type Optional type to use for a type=value pair, can be NULL
264-
* @param[in] values Unit/value array
265-
* @param[in] valueCount Number of values
266-
* @return success code
267-
*/
268-
int CayenneMQTTPublishDataArray(CayenneMQTTClient* client, const char* clientID, CayenneTopic topic, unsigned int channel, const char* type, const CayenneValuePair* values, size_t valueCount)
269-
{
270-
char buffer[CAYENNE_MAX_MESSAGE_SIZE + 1] = { 0 };
271-
int result = CayenneBuildTopic(buffer, sizeof(buffer), client->username, clientID ? clientID : client->clientID, topic, channel);
272-
if (result == CAYENNE_SUCCESS) {
273-
size_t size = strlen(buffer);
274-
char* payload = &buffer[size + 1];
275-
size = sizeof(buffer) - (size + 1);
276-
result = CayenneBuildDataPayload(payload, &size, type, values, valueCount);
277-
if (result == CAYENNE_SUCCESS) {
278-
MQTTMessage message;
279-
message.qos = QOS0;
280-
message.retained = 1;
281-
message.dup = 0;
282-
message.payload = (void*)payload;
283-
message.payloadlen = size;
284-
result = MQTTPublish(&client->mqttClient, buffer, &message);
285-
}
286-
}
287-
return result;
288-
}
289270

290271
/**
291272
* Send a response to a channel.

src/CayenneMQTTClient/CayenneMQTTClient.h

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEAL
2121
#include "MQTTClient.h"
2222
#include "../CayenneUtils/CayenneDefines.h"
2323
#include "../CayenneUtils/CayenneUtils.h"
24-
#include "../CayenneUtils/CayenneDataArray.h"
2524

2625
#if defined(__cplusplus)
2726
extern "C" {
@@ -48,8 +47,8 @@ extern "C" {
4847
unsigned int channel; /**< The channel the message was received on. */
4948
const char* id; /**< The message ID, if it is a command message, otherwise NULL. */
5049
const char* type; /**< The type of data in the message, if it exists, otherwise NULL. */
51-
CayenneValuePair values[CAYENNE_MAX_MESSAGE_VALUES]; /**< The unit/value data pairs in the message. The units and values can be NULL. */
52-
size_t valueCount; /**< The count of items in the values array. */
50+
const char* unit; /**< The unit in the message, if it exists, otherwise NULL. */
51+
const char* value; /**< The value in the message, if it exists, otherwise NULL. */
5352
} CayenneMessageData;
5453

5554
typedef void(*CayenneMessageHandler)(CayenneMessageData*);
@@ -189,19 +188,6 @@ extern "C" {
189188
*/
190189
DLLExport int CayenneMQTTPublishDataFloat(CayenneMQTTClient* client, const char* clientID, CayenneTopic topic, unsigned int channel, const char* type, const char* unit, float value);
191190

192-
/**
193-
* Send multiple value data array to Cayenne.
194-
* @param[in] client The client object
195-
* @param[in] clientID The client ID to use in the topic, NULL to use the clientID the client was initialized with
196-
* @param[in] topic Cayenne topic
197-
* @param[in] channel The channel to send data to, or CAYENNE_NO_CHANNEL if there is none
198-
* @param[in] type Optional type to use for a type=value pair, can be NULL
199-
* @param[in] values Unit / value array
200-
* @param[in] valueCount Number of values
201-
* @return success code
202-
*/
203-
DLLExport int CayenneMQTTPublishDataArray(CayenneMQTTClient* client, const char* clientID, CayenneTopic topic, unsigned int channel, const char* type, const CayenneValuePair* values, size_t valueCount);
204-
205191
/**
206192
* Send a response to a channel.
207193
* @param[in] client The client object

src/CayenneMQTTClient/MQTTClient.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ int cycle(MQTTClient* c, Timer* timer)
273273
MQTTMessage msg;
274274
int intQoS;
275275
if (MQTTDeserialize_publish(&msg.dup, &intQoS, &msg.retained, &msg.id, &topicName,
276-
(unsigned char**)&msg.payload, (int*)&msg.payloadlen, c->readbuf, c->readbuf_size) != 1)
276+
(unsigned char**)&msg.payload, &msg.payloadlen, c->readbuf, c->readbuf_size) != 1)
277277
goto exit;
278278
msg.qos = (enum QoS)intQoS;
279279
deliverMessage(c, &topicName, &msg);

src/CayenneMQTTClient/MQTTClient.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@
3333
#define DLLExport
3434
#endif
3535

36+
#include <stdio.h>
3637
#include "../MQTTCommon/MQTTPacket.h"
37-
#include "stdio.h"
3838
#include "PlatformHeader.h"
3939

4040
#if defined(MQTTCLIENT_PLATFORM_HEADER)

0 commit comments

Comments
 (0)