Skip to content

Commit

Permalink
Merge pull request #16 from myDevicesIoT/revert-15-feature/multivalue
Browse files Browse the repository at this point in the history
Revert "Add new data types and units."
  • Loading branch information
jburhenn authored Dec 13, 2017
2 parents df879cc + 5e997e2 commit bf3908e
Show file tree
Hide file tree
Showing 24 changed files with 844 additions and 357 deletions.
2 changes: 1 addition & 1 deletion library.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name=CayenneMQTT
version=1.0.2-beta
version=1.0.1
author=myDevices
maintainer=myDevices
sentence=Connect a device to the Cayenne dashboard using MQTT.
Expand Down
131 changes: 60 additions & 71 deletions src/CayenneArduinoMQTTClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEAL

#include "CayenneArduinoDefines.h"
#include "CayenneMQTTClient/CayenneMQTTClient.h"
#include "CayenneUtils/CayenneDataArray.h"

const int MAX_CHANNEL_ARRAY_SIZE = 4;

Expand Down Expand Up @@ -163,6 +162,30 @@ class CayenneArduinoMQTTClient
publishData(DATA_TOPIC, channel, data, type, unit);
}

/**
* Sends an array of measurements to a Cayenne channel
*
* @param channel Cayenne channel number
* @param values Array of values to be sent
* @param type Measurement type
*/
void virtualWrite(unsigned int channel, const CayenneDataArray& values, const char* type)
{
publishData(DATA_TOPIC, channel, values.getArray(), values.getCount(), type);
}

/**
* Sends an array of measurements to a Cayenne channel
*
* @param channel Cayenne channel number
* @param values Array of values to be sent
* @param type Measurement type
*/
void virtualWrite(unsigned int channel, const CayenneDataArray& values, const __FlashStringHelper* type)
{
publishData(DATA_TOPIC, channel, values.getArray(), values.getCount(), type);
}

/**
* Sends a response after processing a command
*
Expand Down Expand Up @@ -267,40 +290,6 @@ class CayenneArduinoMQTTClient
virtualWrite(channel, value, F(TYPE_DIGITAL_SENSOR), F(UNIT_DIGITAL));
}

/**
* Sends an acceleration value array to a Cayenne channel
*
* @param channel Cayenne channel number
* @param x Acceration on the X-axis
* @param y Acceration on the Y-axis
* @param z Acceration on the Z-axis
*/
void accelWrite(unsigned int channel, float x, float y, float z)
{
CayenneDataArray values;
values.add(x, 1);
values.add(y, 1);
values.add(z, 1);
virtualWrite(channel, values.getString(), F(TYPE_ACCELERATION), F(UNIT_G));
}

/**
* Sends a GPS value array to a Cayenne channel
*
* @param channel Cayenne channel number
* @param latitude Latitude in degrees
* @param longitude Longitude in degrees
* @param altitude Altitude in meters
*/
void gpsWrite(unsigned int channel, float latitude, float longitude, float altitude)
{
CayenneDataArray values;
values.add(latitude, 5);
values.add(longitude, 5);
values.add(altitude, 1);
virtualWrite(channel, values.getString(), F(TYPE_GPS), F(UNIT_METER));
}

/**
* Requests Server to re-send current values for all widgets.
*/
Expand Down Expand Up @@ -354,9 +343,9 @@ class CayenneArduinoMQTTClient
*/
template <typename T>
static void publishData(CayenneTopic topic, unsigned int channel, const T& data, const char* key = NULL, const char* subkey = NULL) {
CayenneDataArray value;
value.add(data);
publishData(topic, channel, value.getString(), key, subkey);
CayenneDataArray values;
values.add(subkey, data);
publishData(topic, channel, values.getArray(), values.getCount(), key);
}

/**
Expand All @@ -369,42 +358,39 @@ class CayenneArduinoMQTTClient
*/
template <typename T>
static void publishData(CayenneTopic topic, unsigned int channel, const T& data, const __FlashStringHelper* key, const __FlashStringHelper* subkey = NULL) {
char keyBuffer[MAX_TYPE_LENGTH + 1] = { 0 };
char subkeyBuffer[MAX_UNIT_LENGTH + 1] = { 0 };
CayenneDataArray value;
value.add(data);
char keyBuffer[MAX_TYPE_LENGTH + 1];
CayenneDataArray values;
values.add(subkey, data);
CAYENNE_MEMCPY(keyBuffer, reinterpret_cast<const char *>(key), CAYENNE_STRLEN(reinterpret_cast<const char *>(key)) + 1);
if (subkey)
CAYENNE_MEMCPY(subkeyBuffer, reinterpret_cast<const char *>(subkey), CAYENNE_STRLEN(reinterpret_cast<const char *>(subkey)) + 1);
publishData(topic, channel, value.getString(), keyBuffer, subkeyBuffer);
publishData(topic, channel, values.getArray(), values.getCount(), keyBuffer);
}

/**
* Publish value array using specified topic suffix
* @param topic Cayenne topic
* @param channel Cayenne channel number
* @param data Data to send
* @param values Array of values to be sent
* @param valueCount Count of values in array
* @param key Optional key to use for a key=data pair
* @param subkey Optional subkey to use for a key,subkey=data pair
*/
static void publishData(CayenneTopic topic, unsigned int channel, const char* data, const char* key, const char* subkey) {
CAYENNE_LOG_DEBUG("Publish: topic %d, channel %u, key %s, subkey %s, data %s", topic, channel, key, subkey, data);
CayenneMQTTPublishData(&_mqttClient, NULL, topic, channel, key, subkey, data);
static void publishData(CayenneTopic topic, unsigned int channel, const CayenneValuePair values[], size_t valueCount, const char* key) {
CAYENNE_LOG_DEBUG("Publish: topic %d, channel %u, value %s, subkey %s, key %s", topic, channel, values[0].value, values[0].unit, key);
CayenneMQTTPublishDataArray(&_mqttClient, NULL, topic, channel, key, values, valueCount);
}

/**
* Publish value array using specified topic suffix
* @param topic Cayenne topic
* @param channel Cayenne channel number
* @param data Data to send
* @param values Array of values to be sent
* @param valueCount Count of values in array
* @param key Optional key to use for a key=data pair
* @param subkey Optional subkey to use for a key,subkey=data pair
*/
static void publishData(CayenneTopic topic, unsigned int channel, const char* data, const __FlashStringHelper* key, const char* subkey) {
static void publishData(CayenneTopic topic, unsigned int channel, const CayenneValuePair values[], size_t valueCount, const __FlashStringHelper* key) {
char keyBuffer[MAX_TYPE_LENGTH + 1];
CAYENNE_MEMCPY(keyBuffer, reinterpret_cast<const char *>(key), CAYENNE_STRLEN(reinterpret_cast<const char *>(key)) + 1);
CAYENNE_LOG_DEBUG("Publish: topic %d, channel %u, key %s, subkey %s, data %s", topic, channel, keyBuffer, subkey, data);
CayenneMQTTPublishData(&_mqttClient, NULL, topic, channel, keyBuffer, subkey, data);
CAYENNE_LOG_DEBUG("Publish: topic %d, channel %u, value %s, subkey %s, key %s", topic, channel, values[0].value, values[0].unit, keyBuffer);
CayenneMQTTPublishDataArray(&_mqttClient, NULL, topic, channel, keyBuffer, values, valueCount);
}

/**
Expand Down Expand Up @@ -482,8 +468,8 @@ void handleMessage(CayenneMessageData* messageData) {
Request request = { messageData->channel };
const char* response = NULL;
CayenneMessage message(messageData);
if (strlen(messageData->value)) {
CAYENNE_LOG_DEBUG("In: value %s, channel %d", messageData->value, request.channel);
if (strlen(messageData->values[0].value)) {
CAYENNE_LOG_DEBUG("In: value %s, channel %d", messageData->values[0].value, request.channel);
InputHandlerFunction handler = GetInputHandler(request.channel);
if (handler && handler != InputHandler) {
handler(request, message);
Expand All @@ -497,14 +483,14 @@ void handleMessage(CayenneMessageData* messageData) {
}
if(response == NULL) {
// If there was no error, we send the new channel state, which should be the command value we received.
CayenneArduinoMQTTClient::publishState(DATA_TOPIC, messageData->channel, messageData->value);
CayenneArduinoMQTTClient::publishState(DATA_TOPIC, messageData->channel, messageData->values[0].value);
}
CayenneArduinoMQTTClient::responseWrite(response, messageData->id);
}

#ifdef DIGITAL_AND_ANALOG_SUPPORT
void handleAnalogMessage(CayenneMessageData* messageData) {
float value = atof(messageData->value);
float value = atof(messageData->values[0].value);
char* response = NULL;
if (value >= 0 && value <= 1) {
double test = value * 255;
Expand All @@ -515,18 +501,18 @@ void handleAnalogMessage(CayenneMessageData* messageData) {
else {
response = ERROR_INCORRECT_PARAM;
}
CayenneArduinoMQTTClient::responseWrite(response, messageData->id);
CayenneArduinoMQTTClient::responseWrite(messageData->channel, response, messageData->id);
}

void handleDigitalMessage(CayenneMessageData* messageData) {
char* response = NULL;
if (messageData->value && strlen(messageData->value) == 1) {
CAYENNE_LOG_DEBUG("dw %s, channel %d", messageData->value, messageData->channel);
if (messageData->value[0] == '0') {
if (messageData->values[0].value && strlen(messageData->values[0].value) == 1) {
CAYENNE_LOG_DEBUG("dw %s, channel %d", messageData->values[0].value, messageData->channel);
if (messageData->values[0].value[0] == '0') {
digitalWrite(messageData->channel, LOW);
CayenneArduinoMQTTClient::publishState(DIGITAL_TOPIC, messageData->channel, LOW);
}
else if (messageData->value[0] == '1') {
else if (messageData->values[0].value[0] == '1') {
digitalWrite(messageData->channel, HIGH);
CayenneArduinoMQTTClient::publishState(DIGITAL_TOPIC, messageData->channel, HIGH);
}
Expand All @@ -537,7 +523,7 @@ void handleDigitalMessage(CayenneMessageData* messageData) {
else {
response = ERROR_INCORRECT_PARAM;
}
CayenneArduinoMQTTClient::responseWrite(response, messageData->id);
CayenneArduinoMQTTClient::responseWrite(messageData->channel, response, messageData->id);
}
#endif

Expand All @@ -553,13 +539,13 @@ void CayenneMessageArrived(CayenneMessageData* message) {
handleDigitalMessage(message);
break;
case DIGITAL_CONFIG_TOPIC:
configChannel(CayenneArduinoMQTTClient::digitalChannels, message->channel, message->value);
configChannel(CayenneArduinoMQTTClient::digitalChannels, message->channel, message->values[0].value);
break;
case ANALOG_COMMAND_TOPIC:
handleAnalogMessage(message);
break;
case ANALOG_CONFIG_TOPIC:
configChannel(CayenneArduinoMQTTClient::analogChannels, message->channel, message->value);
configChannel(CayenneArduinoMQTTClient::analogChannels, message->channel, message->values[0].value);
break;
#endif
default:
Expand All @@ -569,11 +555,14 @@ void CayenneMessageArrived(CayenneMessageData* message) {
// CAYENNE_PRINT.print(message->type);
// CAYENNE_PRINT.print(", ");
// }
// if (message->unit) {
// CAYENNE_PRINT.print(message->unit);
// CAYENNE_PRINT.print("=");
// for (int i = 0; i < message->valueCount; ++i) {
// if (message->values[i].unit) {
// CAYENNE_PRINT.print(message->values[i].unit);
// CAYENNE_PRINT.print("=");
// }
// CAYENNE_PRINT.print(message->values[i].value);
// CAYENNE_PRINT.print(" ");
// }
// CAYENNE_PRINT.print(message->value);
// CAYENNE_PRINT.println();
//#endif
break;
Expand Down
57 changes: 38 additions & 19 deletions src/CayenneMQTTClient/CayenneMQTTClient.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ void MQTTMessageArrived(MessageData* md, void* userData)
return;
//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.
((char*)md->message->payload)[md->message->payloadlen] = '\0';
result = CayenneParsePayload(&message.type, &message.unit, &message.value, &message.id, message.topic, (char*)md->message->payload);
message.valueCount = CAYENNE_MAX_MESSAGE_VALUES;
result = CayenneParsePayload(message.values, &message.valueCount, &message.type, &message.id, message.topic, (char*)md->message->payload);
if (result != CAYENNE_SUCCESS)
return;

Expand Down Expand Up @@ -109,24 +110,10 @@ int CayenneMQTTConnect(CayenneMQTTClient* client)
*/
int CayenneMQTTPublishData(CayenneMQTTClient* client, const char* clientID, CayenneTopic topic, unsigned int channel, const char* type, const char* unit, const char* value)
{
char buffer[CAYENNE_MAX_MESSAGE_SIZE + 1] = { 0 };
int result = CayenneBuildTopic(buffer, sizeof(buffer), client->username, clientID ? clientID : client->clientID, topic, channel);
if (result == CAYENNE_SUCCESS) {
size_t size = strlen(buffer);
char* payload = &buffer[size + 1];
size = sizeof(buffer) - (size + 1);
result = CayenneBuildDataPayload(payload, &size, type, unit, value);
if (result == CAYENNE_SUCCESS) {
MQTTMessage message;
message.qos = QOS0;
message.retained = (topic != COMMAND_TOPIC) ? 1 : 0;
message.dup = 0;
message.payload = (void*)payload;
message.payloadlen = size;
result = MQTTPublish(&client->mqttClient, buffer, &message);
}
}
return result;
CayenneValuePair valuePair[1];
valuePair[0].value = value;
valuePair[0].unit = unit;
return CayenneMQTTPublishDataArray(client, clientID, topic, channel, type, valuePair, 1);
}


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

/**
* Send multiple value data array to Cayenne.
* @param[in] client The client object
* @param[in] clientID The client ID to use in the topic, NULL to use the clientID the client was initialized with
* @param[in] topic Cayenne topic
* @param[in] channel The channel to send data to, or CAYENNE_NO_CHANNEL if there is none
* @param[in] type Optional type to use for a type=value pair, can be NULL
* @param[in] values Unit/value array
* @param[in] valueCount Number of values
* @return success code
*/
int CayenneMQTTPublishDataArray(CayenneMQTTClient* client, const char* clientID, CayenneTopic topic, unsigned int channel, const char* type, const CayenneValuePair* values, size_t valueCount)
{
char buffer[CAYENNE_MAX_MESSAGE_SIZE + 1] = { 0 };
int result = CayenneBuildTopic(buffer, sizeof(buffer), client->username, clientID ? clientID : client->clientID, topic, channel);
if (result == CAYENNE_SUCCESS) {
size_t size = strlen(buffer);
char* payload = &buffer[size + 1];
size = sizeof(buffer) - (size + 1);
result = CayenneBuildDataPayload(payload, &size, type, values, valueCount);
if (result == CAYENNE_SUCCESS) {
MQTTMessage message;
message.qos = QOS0;
message.retained = 1;
message.dup = 0;
message.payload = (void*)payload;
message.payloadlen = size;
result = MQTTPublish(&client->mqttClient, buffer, &message);
}
}
return result;
}

/**
* Send a response to a channel.
Expand Down
18 changes: 16 additions & 2 deletions src/CayenneMQTTClient/CayenneMQTTClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEAL
#include "MQTTClient.h"
#include "../CayenneUtils/CayenneDefines.h"
#include "../CayenneUtils/CayenneUtils.h"
#include "../CayenneUtils/CayenneDataArray.h"

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

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

/**
* Send multiple value data array to Cayenne.
* @param[in] client The client object
* @param[in] clientID The client ID to use in the topic, NULL to use the clientID the client was initialized with
* @param[in] topic Cayenne topic
* @param[in] channel The channel to send data to, or CAYENNE_NO_CHANNEL if there is none
* @param[in] type Optional type to use for a type=value pair, can be NULL
* @param[in] values Unit / value array
* @param[in] valueCount Number of values
* @return success code
*/
DLLExport int CayenneMQTTPublishDataArray(CayenneMQTTClient* client, const char* clientID, CayenneTopic topic, unsigned int channel, const char* type, const CayenneValuePair* values, size_t valueCount);

/**
* Send a response to a channel.
* @param[in] client The client object
Expand Down
2 changes: 1 addition & 1 deletion src/CayenneMQTTClient/MQTTClient.c
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ int cycle(MQTTClient* c, Timer* timer)
MQTTMessage msg;
int intQoS;
if (MQTTDeserialize_publish(&msg.dup, &intQoS, &msg.retained, &msg.id, &topicName,
(unsigned char**)&msg.payload, &msg.payloadlen, c->readbuf, c->readbuf_size) != 1)
(unsigned char**)&msg.payload, (int*)&msg.payloadlen, c->readbuf, c->readbuf_size) != 1)
goto exit;
msg.qos = (enum QoS)intQoS;
deliverMessage(c, &topicName, &msg);
Expand Down
2 changes: 1 addition & 1 deletion src/CayenneMQTTClient/MQTTClient.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
#define DLLExport
#endif

#include <stdio.h>
#include "../MQTTCommon/MQTTPacket.h"
#include "stdio.h"
#include "PlatformHeader.h"

#if defined(MQTTCLIENT_PLATFORM_HEADER)
Expand Down
Loading

0 comments on commit bf3908e

Please sign in to comment.