Skip to content

Commit

Permalink
Merge pull request #9 from myDevicesIoT/feature/cayenne-out-support
Browse files Browse the repository at this point in the history
Add CAYENNE_OUT support.
  • Loading branch information
jburhenn committed Dec 22, 2017
2 parents 060ab43 + 16896f3 commit 5d15f98
Show file tree
Hide file tree
Showing 8 changed files with 86 additions and 66 deletions.
28 changes: 15 additions & 13 deletions examples/ESP32/ESP32.ino
Expand Up @@ -24,23 +24,25 @@ void setup() {

void loop() {
Cayenne.loop();
}

//Publish data every 10 seconds (10000 milliseconds). Change this value to publish at a different interval.
if (millis() - lastMillis > 10000) {
lastMillis = millis();
//Write data to Cayenne here. This example just sends the current uptime in milliseconds.
Cayenne.virtualWrite(0, lastMillis);
//Some examples of other functions you can use to send data.
//Cayenne.celsiusWrite(1, 22.0);
//Cayenne.luxWrite(2, 700);
//Cayenne.virtualWrite(3, 50, TYPE_PROXIMITY, UNIT_CENTIMETER);
}
// Default function for sending sensor data at intervals to Cayenne.
// You can also use functions for specific channels, e.g CAYENNE_OUT(1) for sending channel 1 data.
CAYENNE_OUT_DEFAULT()
{
// Write data to Cayenne here. This example just sends the current uptime in milliseconds on virtual channel 0.
Cayenne.virtualWrite(0, millis());
// Some examples of other functions you can use to send data.
//Cayenne.celsiusWrite(1, 22.0);
//Cayenne.luxWrite(2, 700);
//Cayenne.virtualWrite(3, 50, TYPE_PROXIMITY, UNIT_CENTIMETER);
}

//Default function for processing actuator commands from the Cayenne Dashboard.
//You can also use functions for specific channels, e.g CAYENNE_IN(1) for channel 1 commands.
// Default function for processing actuator commands from the Cayenne Dashboard.
// You can also use functions for specific channels, e.g CAYENNE_IN(1) for channel 1 commands.
CAYENNE_IN_DEFAULT()
{
CAYENNE_LOG("CAYENNE_IN_DEFAULT(%u) - %s, %s", request.channel, getValue.getId(), getValue.asString());
CAYENNE_LOG("Channel %u, value %s", request.channel, getValue.asString());
//Process message here. If there is an error set an error message using getValue.setError(), e.g getValue.setError("Error message");
}

28 changes: 15 additions & 13 deletions examples/ESP8266/ESP8266.ino
Expand Up @@ -23,23 +23,25 @@ void setup() {

void loop() {
Cayenne.loop();
}

//Publish data every 10 seconds (10000 milliseconds). Change this value to publish at a different interval.
if (millis() - lastMillis > 10000) {
lastMillis = millis();
//Write data to Cayenne here. This example just sends the current uptime in milliseconds.
Cayenne.virtualWrite(0, lastMillis);
//Some examples of other functions you can use to send data.
//Cayenne.celsiusWrite(1, 22.0);
//Cayenne.luxWrite(2, 700);
//Cayenne.virtualWrite(3, 50, TYPE_PROXIMITY, UNIT_CENTIMETER);
}
// Default function for sending sensor data at intervals to Cayenne.
// You can also use functions for specific channels, e.g CAYENNE_OUT(1) for sending channel 1 data.
CAYENNE_OUT_DEFAULT()
{
// Write data to Cayenne here. This example just sends the current uptime in milliseconds on virtual channel 0.
Cayenne.virtualWrite(0, millis());
// Some examples of other functions you can use to send data.
//Cayenne.celsiusWrite(1, 22.0);
//Cayenne.luxWrite(2, 700);
//Cayenne.virtualWrite(3, 50, TYPE_PROXIMITY, UNIT_CENTIMETER);
}

//Default function for processing actuator commands from the Cayenne Dashboard.
//You can also use functions for specific channels, e.g CAYENNE_IN(1) for channel 1 commands.
// Default function for processing actuator commands from the Cayenne Dashboard.
// You can also use functions for specific channels, e.g CAYENNE_IN(1) for channel 1 commands.
CAYENNE_IN_DEFAULT()
{
CAYENNE_LOG("CAYENNE_IN_DEFAULT(%u) - %s, %s", request.channel, getValue.getId(), getValue.asString());
CAYENNE_LOG("Channel %u, value %s", request.channel, getValue.asString());
//Process message here. If there is an error set an error message using getValue.setError(), e.g getValue.setError("Error message");
}

61 changes: 38 additions & 23 deletions src/CayenneArduinoMQTTClient.h
Expand Up @@ -29,7 +29,6 @@ class CayenneArduinoMQTTClient
{
public:

static uint32_t virtualChannels[MAX_CHANNEL_ARRAY_SIZE];
#ifdef DIGITAL_AND_ANALOG_SUPPORT
static uint32_t digitalChannels[MAX_CHANNEL_ARRAY_SIZE];
static uint32_t analogChannels[MAX_CHANNEL_ARRAY_SIZE];
Expand Down Expand Up @@ -71,7 +70,6 @@ class CayenneArduinoMQTTClient
CAYENNE_LOG("Connected");
CayenneConnected();
CayenneMQTTSubscribe(&_mqttClient, NULL, COMMAND_TOPIC, CAYENNE_ALL_CHANNELS, NULL);
CayenneMQTTSubscribe(&_mqttClient, NULL, CONFIG_TOPIC, CAYENNE_ALL_CHANNELS, NULL);
#ifdef DIGITAL_AND_ANALOG_SUPPORT
CayenneMQTTSubscribe(&_mqttClient, NULL, DIGITAL_COMMAND_TOPIC, CAYENNE_ALL_CHANNELS, NULL);
CayenneMQTTSubscribe(&_mqttClient, NULL, DIGITAL_CONFIG_TOPIC, CAYENNE_ALL_CHANNELS, NULL);
Expand All @@ -92,7 +90,12 @@ class CayenneArduinoMQTTClient
*/
void loop(int yieldTime = 1000) {
CayenneMQTTYield(&_mqttClient, yieldTime);
pollChannels(virtualChannels);
static unsigned long lastPoll = millis() - 15000;
if (millis() - lastPoll > 15000) {
lastPoll = millis();
pollVirtualChannels();
}

#ifdef DIGITAL_AND_ANALOG_SUPPORT
pollChannels(digitalChannels);
pollChannels(analogChannels);
Expand Down Expand Up @@ -274,6 +277,17 @@ class CayenneArduinoMQTTClient
virtualWrite(channel, value, CAYENNE_FLASH(TYPE_BAROMETRIC_PRESSURE), CAYENNE_FLASH(UNIT_HECTOPASCAL));
}

/**
* Sends a digital sensor value to a Cayenne channel
*
* @param channel Cayenne channel number
* @param value Value to be sent
*/
void digitalSensorWrite(unsigned int channel, int value)
{
virtualWrite(channel, value, CAYENNE_FLASH(TYPE_DIGITAL_SENSOR), CAYENNE_FLASH(UNIT_DIGITAL));
}

/**
* Requests Server to re-send current values for all widgets.
*/
Expand Down Expand Up @@ -379,6 +393,24 @@ class CayenneArduinoMQTTClient
}
#endif

/**
* Call enabled virtual channel handlers to send channel data.
*/
void pollVirtualChannels()
{
for (unsigned int channel = 0; channel < 32; ++channel) {
Request request = { channel };
OutputHandlerFunction handler = GetOutputHandler(request.channel);
if (handler && handler != OutputHandler) {
handler(request);
}
}
if (CayenneOutDefault != EmptyHandler) {
CayenneOutDefault();
}
}

#ifdef DIGITAL_AND_ANALOG_SUPPORT
/**
* Polls enabled digital channels and sends the matching pin's current value.
*/
Expand All @@ -389,20 +421,7 @@ class CayenneArduinoMQTTClient
for (size_t flag = 0; flag < 32; ++flag) {
if (channelArray[index] & ((uint32_t)1 << flag)) {
unsigned int channel = flag + (index * 32);
if (channelArray == virtualChannels)
{
CAYENNE_LOG_DEBUG("Send channel %d", channel);
Request request = { channel };
OutputHandlerFunction handler = GetOutputHandler(request.channel);
if (handler && handler != OutputHandler) {
handler(request);
}
else {
OutputHandlerDefault(request);
}
}
#ifdef DIGITAL_AND_ANALOG_SUPPORT
else if (channelArray == digitalChannels)
if (channelArray == digitalChannels)
{
CAYENNE_LOG_DEBUG("Send digital channel %d %d", channel, digitalRead(channel));
publishData(DIGITAL_TOPIC, channel, digitalRead(channel));
Expand All @@ -412,23 +431,21 @@ class CayenneArduinoMQTTClient
CAYENNE_LOG_DEBUG("Send analog channel %d %d", channel, analogRead(channel));
publishData(ANALOG_TOPIC, channel, analogRead(channel));
}
#endif
}
}
}
}
}
#endif

static CayenneMQTTClient _mqttClient;
Network _network;
};

CayenneMQTTClient CayenneArduinoMQTTClient::_mqttClient;
uint32_t CayenneArduinoMQTTClient::virtualChannels[MAX_CHANNEL_ARRAY_SIZE] = { 0 };
#ifdef DIGITAL_AND_ANALOG_SUPPORT
uint32_t CayenneArduinoMQTTClient::digitalChannels[MAX_CHANNEL_ARRAY_SIZE] = { 0 };
uint32_t CayenneArduinoMQTTClient::analogChannels[MAX_CHANNEL_ARRAY_SIZE] = { 0 };
#endif

void configChannel(uint32_t channelArray[], uint8_t channel, const char* bytes) {
CAYENNE_LOG_DEBUG("configChannel: %d %s", channel, bytes);
Expand All @@ -445,6 +462,7 @@ void configChannel(uint32_t channelArray[], uint8_t channel, const char* bytes)
}
}
}
#endif

void handleMessage(CayenneMessageData* messageData) {
Request request = { messageData->channel };
Expand Down Expand Up @@ -516,9 +534,6 @@ void CayenneMessageArrived(CayenneMessageData* message) {
case COMMAND_TOPIC:
handleMessage(message);
break;
case CONFIG_TOPIC:
configChannel(CayenneArduinoMQTTClient::virtualChannels, message->channel, message->values[0].value);
break;
#ifdef DIGITAL_AND_ANALOG_SUPPORT
case DIGITAL_COMMAND_TOPIC:
handleDigitalMessage(message);
Expand Down
4 changes: 2 additions & 2 deletions src/CayenneHandlers.cpp
Expand Up @@ -49,7 +49,7 @@ CAYENNE_CONNECTED() __attribute__((weak, alias("EmptyHandler")));
CAYENNE_DISCONNECTED() __attribute__((weak, alias("EmptyHandler")));

CAYENNE_IN_IMPL(Default);
CAYENNE_OUT_IMPL(Default);
CAYENNE_OUT_DEFAULT() __attribute__((weak, alias("EmptyHandler")));;

CAYENNE_IN_IMPL(0);
CAYENNE_IN_IMPL(1);
Expand Down Expand Up @@ -160,4 +160,4 @@ OutputHandlerFunction GetOutputHandler(uint8_t channel)
#else
return OutputHandlerVector[channel];
#endif
}
}
12 changes: 8 additions & 4 deletions src/CayenneHandlers.h
Expand Up @@ -62,12 +62,16 @@ Code adapted from Blynk library BlynkHandlers.h. Copyright info below.
#define V30 30
#define V31 31

//Input & Output handlers
#define CAYENNE_IN(channel) void InputHandler ## channel (Request& request, CayenneMessage& getValue)
#define CAYENNE_OUT(channel) void OutputHandler ## channel (Request& request)
// Input & Output handlers
// Two IN & OUT handler macros are used to allow processing the channel value correctly if a macro is used
// for the channel when declaring the handler, e.g. CAYENNE_IN(V1).
#define CAYENNE_IN_2(channel) void InputHandler ## channel (Request& request, CayenneMessage& getValue)
#define CAYENNE_OUT_2(channel) void OutputHandler ## channel (Request& request)
#define CAYENNE_IN(channel) CAYENNE_IN_2(channel)
#define CAYENNE_OUT(channel) CAYENNE_OUT_2(channel)

#define CAYENNE_IN_DEFAULT() CAYENNE_IN(Default)
#define CAYENNE_OUT_DEFAULT() CAYENNE_OUT(Default)
#define CAYENNE_OUT_DEFAULT() void CayenneOutDefault()

// Additional handlers
#define CAYENNE_CONNECTED() void CayenneConnected()
Expand Down
2 changes: 0 additions & 2 deletions src/CayenneUtils/CayenneTopics.h
Expand Up @@ -24,7 +24,6 @@ typedef enum CayenneTopic
UNDEFINED_TOPIC,
DATA_TOPIC,
COMMAND_TOPIC,
CONFIG_TOPIC,
RESPONSE_TOPIC,
SYS_MODEL_TOPIC,
SYS_VERSION_TOPIC,
Expand All @@ -42,7 +41,6 @@ typedef enum CayenneTopic

#define DATA_STRING CAYENNE_PSTR("data")
#define COMMAND_STRING CAYENNE_PSTR("cmd")
#define CONFIG_STRING CAYENNE_PSTR("conf")
#define RESPONSE_STRING CAYENNE_PSTR("response")
#define SYS_MODEL_STRING CAYENNE_PSTR("sys/model")
#define SYS_VERSION_STRING CAYENNE_PSTR("sys/version")
Expand Down
4 changes: 3 additions & 1 deletion src/CayenneUtils/CayenneTypes.h
Expand Up @@ -26,8 +26,9 @@ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEAL
#define TYPE_RELATIVE_HUMIDITY "rel_hum" // Relative Humidity
#define TYPE_TEMPERATURE "temp" // Temperature
#define TYPE_VOLTAGE "voltage" // Voltage
#define TYPE_DIGITAL_SENSOR "digital_sensor" // Voltage

#define MAX_TYPE_LENGTH 7
#define MAX_TYPE_LENGTH 14

// Unit types
#define UNIT_UNDEFINED "null"
Expand All @@ -37,6 +38,7 @@ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEAL
#define UNIT_RATIO "r" // Ratio
#define UNIT_VOLTS "v" // Volts
#define UNIT_LUX "lux" // Lux
#define UNIT_MILLIMETER "mm" // Millimeter
#define UNIT_CENTIMETER "cm" // Centimeter
#define UNIT_METER "m" // Meter
#define UNIT_DIGITAL "d" // Digital (0/1)
Expand Down
13 changes: 5 additions & 8 deletions src/CayenneUtils/CayenneUtils.c
Expand Up @@ -22,15 +22,15 @@ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEAL

#ifdef DIGITAL_AND_ANALOG_SUPPORT
#ifdef PARSE_INFO_PAYLOADS
#define PARSE_TOPICS_COUNT 13
#define PARSE_TOPICS_COUNT 12
#else
#define PARSE_TOPICS_COUNT 6
#define PARSE_TOPICS_COUNT 5
#endif
#else
#ifdef PARSE_INFO_PAYLOADS
#define PARSE_TOPICS_COUNT 7
#define PARSE_TOPICS_COUNT 6
#else
#define PARSE_TOPICS_COUNT 2
#define PARSE_TOPICS_COUNT 1
#endif
#endif

Expand Down Expand Up @@ -87,9 +87,6 @@ int buildSuffix(char* suffix, size_t length, const CayenneTopic topic, unsigned
case COMMAND_TOPIC:
topicString = COMMAND_STRING;
break;
case CONFIG_TOPIC:
topicString = CONFIG_STRING;
break;
case DATA_TOPIC:
topicString = DATA_STRING;
break;
Expand Down Expand Up @@ -403,7 +400,7 @@ int CayenneBuildResponsePayload(char* payload, size_t* length, const char* id, c
int CayenneParseTopic(CayenneTopic* topic, unsigned int* channel, const char** clientID, const char* username, char* topicName, unsigned int length) {
char* index = NULL;
int i = 0;
TopicChannel parseTopics[PARSE_TOPICS_COUNT] = { { COMMAND_TOPIC, CAYENNE_ALL_CHANNELS },{ CONFIG_TOPIC, CAYENNE_ALL_CHANNELS },
TopicChannel parseTopics[PARSE_TOPICS_COUNT] = { { COMMAND_TOPIC, CAYENNE_ALL_CHANNELS },
#ifdef DIGITAL_AND_ANALOG_SUPPORT
{ ANALOG_COMMAND_TOPIC, CAYENNE_ALL_CHANNELS },{ ANALOG_CONFIG_TOPIC, CAYENNE_ALL_CHANNELS },{ DIGITAL_COMMAND_TOPIC, CAYENNE_ALL_CHANNELS },{ DIGITAL_CONFIG_TOPIC, CAYENNE_ALL_CHANNELS },
#ifdef PARSE_INFO_PAYLOADS
Expand Down

0 comments on commit 5d15f98

Please sign in to comment.