diff --git a/API.md b/API.md index 4acaa3b..1772f9f 100644 --- a/API.md +++ b/API.md @@ -147,6 +147,9 @@ uint8_t addDistance(uint8_t channel, float value); // in meters (3 decimals) uint8_t addEnergy(uint8_t channel, float value); // in kWh (3 decimals) uint8_t addDirection(uint8_t channel, float value); // in degrees uint8_t addSwitch(uint8_t channel, uint32_t value); // 0 or 1 + +uint8_t CayenneLPP::addConcentration(uint8_t channel, uint32_t value); // 1 PPM unsigned - PPM means Parts per million 1PPM = 1 * 10 ^-6 = 0.000 001 +uint8_t CayenneLPP::addColour(uint8_t channel, uint8_t r, uint8_t g, uint8_t b); // R: 255 G: 255 B: 255 ``` ### Method: `getError` diff --git a/decoders/decoder.js b/decoders/decoder.js index 89c642e..11ebe45 100644 --- a/decoders/decoder.js +++ b/decoders/decoder.js @@ -28,11 +28,14 @@ * Frequency 3318 118 76 4 1 Hz Unsigned MSB * Percentage 3320 120 78 1 1% Unsigned * Altitude 3321 121 79 2 1m Signed MSB + * Concentration 3325 125 7D 2 1 PPM unsigned : 1pmm = 1 * 10 ^-6 = 0.000 001 * Power 3328 128 80 2 1 W Unsigned MSB * Distance 3330 130 82 4 0.001m Unsigned MSB * Energy 3331 131 83 4 0.001kWh Unsigned MSB + * Colour 3335 135 87 3 R: 255 G: 255 B: 255 * Direction 3332 132 84 2 1º Unsigned MSB * Switch 3342 142 8E 1 0/1 + * */ @@ -57,12 +60,14 @@ function lppDecode(bytes) { 118: {'size': 4, 'name': 'frequency', 'signed': false, 'divisor': 1}, 120: {'size': 1, 'name': 'percentage', 'signed': false, 'divisor': 1}, 121: {'size': 2, 'name': 'altitude', 'signed': true, 'divisor': 1}, + 125: {'size': 2, 'name': 'concentration', 'signed': false, 'divisor': 1}, 128: {'size': 2, 'name': 'power', 'signed': false, 'divisor': 1}, 130: {'size': 4, 'name': 'distance', 'signed': false, 'divisor': 1000}, 131: {'size': 4, 'name': 'energy', 'signed': false, 'divisor': 1000}, 132: {'size': 2, 'name': 'direction', 'signed': false, 'divisor': 1}, 133: {'size': 4, 'name': 'time', 'signed': false, 'divisor': 1}, 134: {'size': 6, 'name': 'gyrometer', 'signed': true , 'divisor': 100}, + 135: {'size': 3, 'name': 'colour', 'signed': false, 'divisor': 1}, 136: {'size': 9, 'name': 'gps', 'signed': true, 'divisor': [10000,10000,100]}, 142: {'size': 1, 'name': 'switch', 'signed': false, 'divisor': 1}, }; @@ -117,6 +122,13 @@ function lppDecode(bytes) { 'longitude': arrayToDecimal(bytes.slice(i+3, i+6), type.signed, type.divisor[1]), 'altitude': arrayToDecimal(bytes.slice(i+6, i+9), type.signed, type.divisor[2]) }; + break; + case 135: // Colour + s_value = { + 'r': arrayToDecimal(bytes.slice(i+0, i+1), type.signed, type.divisor), + 'g': arrayToDecimal(bytes.slice(i+1, i+2), type.signed, type.divisor), + 'b': arrayToDecimal(bytes.slice(i+2, i+3), type.signed, type.divisor) + }; break; default: // All the rest diff --git a/examples/Decode/Decode.ino b/examples/Decode/Decode.ino index 879bdc7..aae09da 100644 --- a/examples/Decode/Decode.ino +++ b/examples/Decode/Decode.ino @@ -46,6 +46,10 @@ void setup() lpp.addEnergy(1 , 19.055); lpp.addDirection(1 , 90); lpp.addSwitch(1 , 0); + + lpp.addConcentration(1 , 512); + lpp.addColour(1 , 64, 128, 255); + lpp.decode(lpp.getBuffer(), lpp.getSize(), root); diff --git a/examples/DecodeTTN/DecodeTTN.ino b/examples/DecodeTTN/DecodeTTN.ino index 4bb2c48..c8e5b7f 100644 --- a/examples/DecodeTTN/DecodeTTN.ino +++ b/examples/DecodeTTN/DecodeTTN.ino @@ -46,6 +46,10 @@ void setup() lpp.addEnergy(1 , 19.055); lpp.addDirection(1 , 90); lpp.addSwitch(1 , 0); + + lpp.addConcentration(1 , 512); + lpp.addColour(1 , 64, 128, 255); + lpp.decodeTTN(lpp.getBuffer(), lpp.getSize(), root); diff --git a/keywords.txt b/keywords.txt index e875831..ed328c1 100644 --- a/keywords.txt +++ b/keywords.txt @@ -44,6 +44,9 @@ addEnergy KEYWORD2 addDirection KEYWORD2 addSwitch KEYWORD2 +addConcentration KEYWORD2 +addColour KEYWORD2 + getTypeName KEYWORD2 decode KEYWORD2 decodeTTN KEYWORD2 diff --git a/src/CayenneLPP.cpp b/src/CayenneLPP.cpp index c8d86b6..a683b76 100644 --- a/src/CayenneLPP.cpp +++ b/src/CayenneLPP.cpp @@ -66,6 +66,8 @@ bool CayenneLPP::isType(uint8_t type) { if (LPP_GYROMETER == type) return true; if (LPP_GPS == type) return true; if (LPP_SWITCH == type) return true; + if (LPP_CONCENTRATION == type) return true; + if (LPP_COLOUR == type) return true; return false; } @@ -94,6 +96,8 @@ const char * CayenneLPP::getTypeName(uint8_t type) { if (LPP_GYROMETER == type) return "gyrometer"; if (LPP_GPS == type) return "gps"; if (LPP_SWITCH == type) return "switch"; + if (LPP_CONCENTRATION == type) return "concentration"; + if (LPP_COLOUR == type) return "colour"; return 0; } @@ -122,6 +126,8 @@ uint8_t CayenneLPP::getTypeSize(uint8_t type) { if (LPP_GYROMETER == type) return LPP_GYROMETER_SIZE; if (LPP_GPS == type) return LPP_GPS_SIZE; if (LPP_SWITCH == type) return LPP_SWITCH_SIZE; + if (LPP_CONCENTRATION == type) return LPP_CONCENTRATION_SIZE; + if (LPP_COLOUR == type) return LPP_COLOUR_SIZE; return 0; } @@ -149,6 +155,8 @@ uint32_t CayenneLPP::getTypeMultiplier(uint8_t type) { if (LPP_UNIXTIME == type) return LPP_UNIXTIME_MULT; if (LPP_GYROMETER == type) return LPP_GYROMETER_MULT; if (LPP_SWITCH == type) return LPP_SWITCH_MULT; + if (LPP_CONCENTRATION == type) return LPP_CONCENTRATION_MULT; + if (LPP_COLOUR == type) return LPP_COLOUR_MULT; return 0; } @@ -298,6 +306,27 @@ uint8_t CayenneLPP::addSwitch(uint8_t channel, uint32_t value) { return addField(LPP_SWITCH, channel, value); } +uint8_t CayenneLPP::addConcentration(uint8_t channel, uint32_t value) { + return addField(LPP_CONCENTRATION, channel, value); +} + +uint8_t CayenneLPP::addColour(uint8_t channel, uint8_t r, uint8_t g, uint8_t b) +{ + // check buffer overflow + if ((_cursor + LPP_COLOUR_SIZE + 2) > _maxsize) { + _error = LPP_ERROR_OVERFLOW; + return 0; + } + _buffer[_cursor++] = channel; + _buffer[_cursor++] = LPP_COLOUR; + _buffer[_cursor++] = r; + _buffer[_cursor++] = g; + _buffer[_cursor++] = b; + + + return _cursor; +} + uint8_t CayenneLPP::addAccelerometer(uint8_t channel, float x, float y, float z) { // check buffer overflow @@ -446,7 +475,14 @@ uint8_t CayenneLPP::decode(uint8_t *buffer, uint8_t len, JsonArray& root) { data["name"] = String(getTypeName(type)); // Parse types - if (LPP_ACCELEROMETER == type || LPP_GYROMETER == type) { + if (LPP_COLOUR == type) { + + JsonObject object = data.createNestedObject("value"); + object["r"] = getValue(&buffer[index], 1, multiplier, is_signed); + object["g"] = getValue(&buffer[index+1], 1, multiplier, is_signed); + object["b"] = getValue(&buffer[index+2], 1, multiplier, is_signed); + + } else if (LPP_ACCELEROMETER == type || LPP_GYROMETER == type) { JsonObject object = data.createNestedObject("value"); object["x"] = getValue(&buffer[index], 2, multiplier, is_signed); @@ -512,7 +548,13 @@ uint8_t CayenneLPP::decodeTTN(uint8_t *buffer, uint8_t len, JsonObject& root) { String name = String(getTypeName(type)) + "_" + channel; // Parse types - if (LPP_ACCELEROMETER == type || LPP_GYROMETER == type) { + if (LPP_COLOUR == type) { + JsonObject object = root.createNestedObject(name); + object["r"] = getValue(&buffer[index], 1, multiplier, is_signed); + object["g"] = getValue(&buffer[index+1], 1, multiplier, is_signed); + object["b"] = getValue(&buffer[index+2], 1, multiplier, is_signed); + + } else if (LPP_ACCELEROMETER == type || LPP_GYROMETER == type) { JsonObject object = root.createNestedObject(name); object["x"] = getValue(&buffer[index], 2, multiplier, is_signed); @@ -542,4 +584,4 @@ uint8_t CayenneLPP::decodeTTN(uint8_t *buffer, uint8_t len, JsonObject& root) { return count; -} +} \ No newline at end of file diff --git a/src/CayenneLPP.h b/src/CayenneLPP.h index a490383..33e750a 100644 --- a/src/CayenneLPP.h +++ b/src/CayenneLPP.h @@ -25,12 +25,14 @@ #define LPP_FREQUENCY 118 // 4 bytes 1Hz unsigned #define LPP_PERCENTAGE 120 // 1 byte 1-100% unsigned #define LPP_ALTITUDE 121 // 2 byte 1m signed +#define LPP_CONCENTRATION 125 // 2 bytes, 1 ppm unsigned #define LPP_POWER 128 // 2 byte, 1W, unsigned #define LPP_DISTANCE 130 // 4 byte, 0.001m, unsigned #define LPP_ENERGY 131 // 4 byte, 0.001kWh, unsigned #define LPP_DIRECTION 132 // 2 bytes, 1deg, unsigned #define LPP_UNIXTIME 133 // 4 bytes, unsigned #define LPP_GYROMETER 134 // 2 bytes per axis, 0.01 °/s +#define LPP_COLOUR 135 // 1 byte per RGB Color #define LPP_GPS 136 // 3 byte lon/lat 0.0001 °, 3 bytes alt 0.01 meter #define LPP_SWITCH 142 // 1 byte, 0/1 @@ -59,6 +61,8 @@ #define LPP_GYROMETER_SIZE 6 #define LPP_GPS_SIZE 9 #define LPP_SWITCH_SIZE 1 +#define LPP_CONCENTRATION_SIZE 2 +#define LPP_COLOUR_SIZE 3 // Multipliers #define LPP_DIGITAL_INPUT_MULT 1 @@ -86,6 +90,8 @@ #define LPP_GPS_LAT_LON_MULT 10000 #define LPP_GPS_ALT_MULT 100 #define LPP_SWITCH_MULT 1 +#define LPP_CONCENTRATION_MULT 1 +#define LPP_COLOUR_MULT 1 #define LPP_ERROR_OK 0 #define LPP_ERROR_OVERFLOW 1 @@ -136,6 +142,8 @@ class CayenneLPP { uint8_t addEnergy(uint8_t channel, float value); uint8_t addDirection(uint8_t channel, float value); uint8_t addSwitch(uint8_t channel, uint32_t value); + uint8_t addConcentration(uint8_t channel, uint32_t value); + uint8_t addColour(uint8_t channel, uint8_t r, uint8_t g, uint8_t b); protected: diff --git a/test/aunit/main.cpp b/test/aunit/main.cpp index 7e7b7a8..690676d 100644 --- a/test/aunit/main.cpp +++ b/test/aunit/main.cpp @@ -193,7 +193,19 @@ testF(EncoderTest, Frequency) { testF(EncoderTest, Altitude) { lpp->addAltitude(5, -17); - uint8_t expected[] = {0x05,0x79,0xFF,0XEF}; + uint8_t expected[] = {0x05,0x79,0xFF,0xEF}; + compare(sizeof(expected), expected); +} + +testF(EncoderTest, Concentration) { + lpp->addConcentration(4, 4079); + uint8_t expected[] = {0x05,0x7D,0x0F,0xEF}; + compare(sizeof(expected), expected); +} + +testF(EncoderTest, Colour) { + lpp->addColour(7, 24, 239, 15); + uint8_t expected[] = {0x07,0x87,0x0F,0xEF, 0x18}; compare(sizeof(expected), expected); }