From 35028b1c827910db32264a2789c94fba16852073 Mon Sep 17 00:00:00 2001 From: Stefan Persson Date: Mon, 2 Sep 2013 16:28:39 +0200 Subject: [PATCH] Added support for rain and wind sensors (Oregon Scientific) in telldus-core --- telldus-core/client/telldus-core.cpp | 22 +++- telldus-core/client/telldus-core.h | 5 + telldus-core/service/DeviceManager.cpp | 5 + telldus-core/service/ProtocolOregon.cpp | 123 +++++++++++++++++++++ telldus-core/service/ProtocolOregon.h | 2 + telldus-core/tdtool/main.cpp | 140 +++++++++++++++++++++++- 6 files changed, 291 insertions(+), 6 deletions(-) diff --git a/telldus-core/client/telldus-core.cpp b/telldus-core/client/telldus-core.cpp index fdb1f3e7..c9a977b6 100644 --- a/telldus-core/client/telldus-core.cpp +++ b/telldus-core/client/telldus-core.cpp @@ -73,6 +73,16 @@ * The sensor can report the temperature. * @def TELLSTICK_HUMIDITY * The sensor can report the humidity. + * @def TELLSTICK_RAINRATE + * The sensor can report rain fall rate. + * @def TELLSTICK_RAINTOTAL + * The sensor can report total rain fall. + * @def TELLSTICK_WINDDIRECTION + * The sensor can report wind direction. + * @def TELLSTICK_WINDAVERAGE + * The sensor can report average wind speed. + * @def TELLSTICK_WINDGUST + * The sensor can report gust wind speed. * **//* @} */ @@ -255,8 +265,10 @@ * @param id * The unique id for the sensor. * @param dataType - * The type that @a value is. Can be one of @ref TELLSTICK_TEMPERATURE or - * @ref TELLSTICK_HUMIDITY. + * The type that @a value is. Can be one of @ref TELLSTICK_TEMPERATURE, + * @ref TELLSTICK_HUMIDITY, @ref TELLSTICK_RAINTOTAL, + * @ref TELLSTICK_RAINRATE, @ref TELLSTICK_WINDDIRECTION, + * @ref TELLSTICK_WINDAVERAGE or @ref TELLSTICK_WINDGUST. * @param value * A human readable string of the data. * @param timestamp @@ -1135,8 +1147,10 @@ int WINAPI tdSensor(char *protocol, int protocolLen, char *model, int modelLen, * @param[in] id * The id of the sensor. * @param[in] dataType - * Which sensor value to retrive (one of @ref TELLSTICK_TEMPERATURE or @ref - * TELLSTICK_HUMIDITY). + * Which sensor value to retrive (one of @ref TELLSTICK_TEMPERATURE, + * @ref TELLSTICK_HUMIDITY, @ref TELLSTICK_RAINTOTAL, + * @ref TELLSTICK_RAINRATE, @ref TELLSTICK_WINDDIRECTION, + * @ref TELLSTICK_WINDAVERAGE or @ref TELLSTICK_WINDGUST. * @param[out] value * A by ref string where the value will be placed. * @param[in] len diff --git a/telldus-core/client/telldus-core.h b/telldus-core/client/telldus-core.h index c50804ea..21a9bf9a 100644 --- a/telldus-core/client/telldus-core.h +++ b/telldus-core/client/telldus-core.h @@ -118,6 +118,11 @@ extern "C" { // Sensor value types #define TELLSTICK_TEMPERATURE 1 #define TELLSTICK_HUMIDITY 2 +#define TELLSTICK_RAINRATE 4 +#define TELLSTICK_RAINTOTAL 8 +#define TELLSTICK_WINDDIRECTION 16 +#define TELLSTICK_WINDAVERAGE 32 +#define TELLSTICK_WINDGUST 64 // Error codes #define TELLSTICK_SUCCESS 0 diff --git a/telldus-core/service/DeviceManager.cpp b/telldus-core/service/DeviceManager.cpp index e33e66d2..82b8cba4 100644 --- a/telldus-core/service/DeviceManager.cpp +++ b/telldus-core/service/DeviceManager.cpp @@ -722,6 +722,11 @@ void DeviceManager::handleSensorMessage(const ControllerMessage &msg) { setSensorValueAndSignal("temp", TELLSTICK_TEMPERATURE, sensor, msg, t); setSensorValueAndSignal("humidity", TELLSTICK_HUMIDITY, sensor, msg, t); + setSensorValueAndSignal("rainrate", TELLSTICK_RAINRATE, sensor, msg, t); + setSensorValueAndSignal("raintotal", TELLSTICK_RAINTOTAL, sensor, msg, t); + setSensorValueAndSignal("winddirection", TELLSTICK_WINDDIRECTION, sensor, msg, t); + setSensorValueAndSignal("windaverage", TELLSTICK_WINDAVERAGE, sensor, msg, t); + setSensorValueAndSignal("windgust", TELLSTICK_WINDGUST, sensor, msg, t); } void DeviceManager::setSensorValueAndSignal( const std::string &dataType, int dataTypeId, Sensor *sensor, const ControllerMessage &msg, time_t timestamp) const { diff --git a/telldus-core/service/ProtocolOregon.cpp b/telldus-core/service/ProtocolOregon.cpp index 4fb962b5..79dc3614 100644 --- a/telldus-core/service/ProtocolOregon.cpp +++ b/telldus-core/service/ProtocolOregon.cpp @@ -21,6 +21,10 @@ std::string ProtocolOregon::decodeData(const ControllerMessage &dataMsg) { return decode1A2D(data); } else if (model.compare(L"0xF824") == 0) { return decodeF824(data); + } else if (model.compare(L"0x1984") == 0 || model.compare(L"0x1994") == 0) { + return decode1984(data, model); + } else if (model.compare(L"0x2914") == 0) { + return decode2914(data); } return ""; @@ -73,6 +77,71 @@ std::string ProtocolOregon::decodeEA4C(const std::string &data) { return retString.str(); } +std::string ProtocolOregon::decode1984(const std::string &data, const std::wstring &model) { + + //wind + uint64_t value = TelldusCore::hexTo64l(data); + + uint8_t crcCheck = value & 0xF; //PROBABLY crc + value >>= 4; + uint8_t messageChecksum1 = value & 0xF; + value >>= 4; + uint8_t messageChecksum2 = value & 0xF; + + value >>= 4; + uint8_t avg1 = value & 0xF; + value >>= 4; + uint8_t avg2 = value & 0xF; + value >>= 4; + uint8_t avg3 = value & 0xF; + value >>= 4; + uint8_t gust1 = value & 0xF; + value >>= 4; + uint8_t gust2 = value & 0xF; + value >>= 4; + uint8_t gust3 = value & 0xF; + value >>= 4; + uint8_t unknown1 = value & 0xF; + value >>= 4; + uint8_t unknown2 = value & 0xF; + value >>= 4; + uint8_t direction = value & 0xF; + + value >>= 4; + uint8_t battery = value & 0xF; //PROBABLY battery + value >>= 4; + uint8_t rollingcode = ((value >> 4) & 0xF) + (value & 0xF); + uint8_t checksum = ((value >> 4) & 0xF) + (value & 0xF); + value >>= 8; + uint8_t channel = value & 0xF; + checksum += unknown1 + unknown2 + avg1 + avg2 + avg3 + gust1 + gust2 + gust3 + direction + battery + channel; + + if (model.compare(L"0x1984") == 0) { + checksum += 0x1 + 0x9 + 0x8 + 0x4; + } + else { + checksum += 0x1 + 0x9 + 0x9 + 0x4; + } + + if (((checksum >> 4) & 0xF) != messageChecksum1 || (checksum & 0xF) != messageChecksum2){ + //checksum error + return ""; + } + + + double avg = ((avg1 * 100) + (avg2 * 10) + avg3)/10.0; + double gust = ((gust1 * 100) + (gust2 * 10) + gust3)/10.0; + float directiondegree = 22.5 * direction; + + std::stringstream retString; + retString << "class:sensor;protocol:oregon;model:1984;id:" << static_cast(rollingcode) + << ";winddirection:" << directiondegree + << ";windaverage:" << std::fixed << std::setprecision(1) << avg + << ";windgust:" << std::fixed << std::setprecision(1) << gust << ";"; + + return retString.str(); +} + std::string ProtocolOregon::decode1A2D(const std::string &data) { uint64_t value = TelldusCore::hexTo64l(data); // checksum2 not used yet @@ -128,6 +197,60 @@ std::string ProtocolOregon::decode1A2D(const std::string &data) { return retString.str(); } +std::string ProtocolOregon::decode2914(const std::string &data) { + + //rain + uint64_t value = TelldusCore::hexTo64l(data); + + uint8_t messageChecksum1 = value & 0xF; + value >>= 4; + uint8_t messageChecksum2 = value & 0xF; + + value >>= 4; + uint8_t totRain1 = value & 0xF; + value >>= 4; + uint8_t totRain2 = value & 0xF; + value >>= 4; + uint8_t totRain3 = value & 0xF; + value >>= 4; + uint8_t totRain4 = value & 0xF; + value >>= 4; + uint8_t totRain5 = value & 0xF; + value >>= 4; + uint8_t totRain6 = value & 0xF; + value >>= 4; + uint8_t rainRate1 = value & 0xF; + value >>= 4; + uint8_t rainRate2 = value & 0xF; + value >>= 4; + uint8_t rainRate3 = value & 0xF; + value >>= 4; + uint8_t rainRate4 = value & 0xF; + + value >>= 4; + uint8_t battery = value & 0xF; //PROBABLY battery + value >>= 4; + uint8_t rollingcode = ((value >> 4) & 0xF) + (value & 0xF); + uint8_t checksum = ((value >> 4) & 0xF) + (value & 0xF); + value >>= 8; + uint8_t channel = value & 0xF; + checksum += totRain1 + totRain2 + totRain3 + totRain4 + totRain5 + totRain6 + rainRate1 + rainRate2 + rainRate3 + rainRate4 + battery + channel + 0x2 + 0x9 + 0x1 + 0x4; + + if (((checksum >> 4) & 0xF) != messageChecksum1 || (checksum & 0xF) != messageChecksum2){ + //checksum error + return ""; + } + + double totRain = ((totRain1 * 100000) + (totRain2 * 10000) + (totRain3 * 1000) + (totRain4 * 100) + (totRain5 * 10) + totRain6)/1000.0*25.4; + double rainRate = ((rainRate1 * 1000) + (rainRate2 * 100) + (rainRate3 * 10) + rainRate4)/100.0*25.4; + + std::stringstream retString; + retString << "class:sensor;protocol:oregon;model:2914;id:" << static_cast(rollingcode) + << ";raintotal:" << std::fixed << std::setprecision(1) << totRain + << ";rainrate:" << std::fixed << std::setprecision(1) << rainRate << ";"; + return retString.str(); +} + std::string ProtocolOregon::decodeF824(const std::string &data) { uint64_t value = TelldusCore::hexTo64l(data); diff --git a/telldus-core/service/ProtocolOregon.h b/telldus-core/service/ProtocolOregon.h index f0c757a8..dbf4aaa5 100644 --- a/telldus-core/service/ProtocolOregon.h +++ b/telldus-core/service/ProtocolOregon.h @@ -19,6 +19,8 @@ protected: static std::string decodeEA4C(const std::string &data); static std::string decode1A2D(const std::string &data); static std::string decodeF824(const std::string &data); + static std::string decode1984(const std::string &data, const std::wstring &model); + static std::string decode2914(const std::string &data); }; #endif // TELLDUS_CORE_SERVICE_PROTOCOLOREGON_H_ diff --git a/telldus-core/tdtool/main.cpp b/telldus-core/tdtool/main.cpp index c21b1e98..b75d281b 100644 --- a/telldus-core/tdtool/main.cpp +++ b/telldus-core/tdtool/main.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include "../client/telldus-core.h" #ifdef _WINDOWS @@ -140,13 +141,27 @@ int list_devices() { int sensorStatus = tdSensor(protocol, DATA_LENGTH, model, DATA_LENGTH, &sensorId, &dataTypes); if(sensorStatus == 0){ - printf("\n\nSENSORS:\n\n%-20s\t%-20s\t%-5s\t%-5s\t%-8s\t%-20s\n", "PROTOCOL", "MODEL", "ID", "TEMP", "HUMIDITY", "LAST UPDATED"); + printf("\n\nSENSORS:\n\n%-20s\t%-20s\t%-5s\t%-5s\t%-8s\t%-20s\t%-20s\t%-20s\n", "PROTOCOL", "MODEL", "ID", "TEMP", "HUMIDITY", "RAIN", "WIND", "LAST UPDATED"); } while(sensorStatus == 0){ char tempvalue[DATA_LENGTH]; tempvalue[0] = 0; char humidityvalue[DATA_LENGTH]; humidityvalue[0] = 0; + char windvalue[DATA_LENGTH]; + windvalue[0] = 0; + char winddirectionvalue[DATA_LENGTH]; + winddirectionvalue[0] = 0; + char windaveragevalue[DATA_LENGTH]; + windaveragevalue[0] = 0; + char windgustvalue[DATA_LENGTH]; + windgustvalue[0] = 0; + char rainvalue[DATA_LENGTH]; + rainvalue[0] = 0; + char raintotvalue[DATA_LENGTH]; + raintotvalue[0] = 0; + char rainratevalue[DATA_LENGTH]; + rainratevalue[0] = 0; char timeBuf[80]; timeBuf[0] = 0; time_t timestamp = 0; @@ -162,7 +177,98 @@ int list_devices() { strcat(humidityvalue, "%"); strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", localtime(×tamp)); } - printf("%-20s\t%-20s\t%-5i\t%-5s\t%-8s\t%-20s\n", protocol, model, sensorId, tempvalue, humidityvalue, timeBuf); + + if (dataTypes & TELLSTICK_RAINRATE) { + tdSensorValue(protocol, model, sensorId, TELLSTICK_RAINRATE, rainratevalue, DATA_LENGTH, (int *)×tamp); + strcat(rainratevalue, " mm/h, "); + strcat(rainvalue, rainratevalue); + strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", localtime(×tamp)); + } + + if (dataTypes & TELLSTICK_RAINTOTAL) { + tdSensorValue(protocol, model, sensorId, TELLSTICK_RAINTOTAL, raintotvalue, DATA_LENGTH, (int *)×tamp); + //TODO detta blir väl fel, kan väl hamna i andra ordningar, eller hur? + strcat(raintotvalue, " mm"); + strcat(rainvalue, raintotvalue); + strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", localtime(×tamp)); + } + + if (dataTypes & TELLSTICK_WINDDIRECTION) { + tdSensorValue(protocol, model, sensorId, TELLSTICK_WINDDIRECTION, winddirectionvalue, DATA_LENGTH, (int *)×tamp); + //TODO or use charToInteger in common? + std::stringstream inputstream; + inputstream << winddirectionvalue; + int direction; + inputstream >> direction; + direction = direction / 22.5; + std::string directionabbrev = "N"; + switch (direction) { + case 1: + directionabbrev = "NNE"; + break; + case 2: + directionabbrev = "NE"; + break; + case 3: + directionabbrev = "ENE"; + break; + case 4: + directionabbrev = "E"; + break; + case 5: + directionabbrev = "ESE"; + break; + case 6: + directionabbrev = "SE"; + break; + case 7: + directionabbrev = "SSE"; + break; + case 8: + directionabbrev = "S"; + break; + case 9: + directionabbrev = "SSW"; + break; + case 10: + directionabbrev = "SW"; + break; + case 11: + directionabbrev = "WSW"; + break; + case 12: + directionabbrev = "W"; + break; + case 13: + directionabbrev = "WNW"; + break; + case 14: + directionabbrev = "NW"; + break; + case 15: + directionabbrev = "NNW"; + break; + } + strcat(windvalue, directionabbrev.c_str()); + strcat(windvalue, ", "); + strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", localtime(×tamp)); + } + + if (dataTypes & TELLSTICK_WINDAVERAGE) { + tdSensorValue(protocol, model, sensorId, TELLSTICK_WINDAVERAGE, windaveragevalue, DATA_LENGTH, (int *)×tamp); + strcat(windaveragevalue, " m/s ("); + strcat(windvalue, windaveragevalue); + strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", localtime(×tamp)); + } + + if (dataTypes & TELLSTICK_WINDGUST) { + tdSensorValue(protocol, model, sensorId, TELLSTICK_WINDGUST, windgustvalue, DATA_LENGTH, (int *)×tamp); + strcat(windgustvalue, " m/s) "); + strcat(windvalue, windgustvalue); + strftime(timeBuf, sizeof(timeBuf), "%Y-%m-%d %H:%M:%S", localtime(×tamp)); + } + + printf("%-20s\t%-20s\t%-5i\t%-5s\t%-8s\t%-20s\t%-20s\t%-20s\n", protocol, model, sensorId, tempvalue, humidityvalue, rainvalue, windvalue, timeBuf); sensorStatus = tdSensor(protocol, DATA_LENGTH, model, DATA_LENGTH, &sensorId, &dataTypes); } @@ -209,6 +315,36 @@ int list_kv_sensors() { printf("\thumidity=%s", humidityvalue); } + if (dataTypes & TELLSTICK_WINDDIRECTION) { + char winddirectionvalue[DATA_LENGTH]; + tdSensorValue(protocol, model, sensorId, TELLSTICK_WINDDIRECTION, winddirectionvalue, DATA_LENGTH, (int *)×tamp); + printf("\twinddirection=%s", winddirectionvalue); + } + + if (dataTypes & TELLSTICK_WINDAVERAGE) { + char windaveragevalue[DATA_LENGTH]; + tdSensorValue(protocol, model, sensorId, TELLSTICK_WINDAVERAGE, windaveragevalue, DATA_LENGTH, (int *)×tamp); + printf("\twindaverage=%s", windaveragevalue); + } + + if (dataTypes & TELLSTICK_WINDGUST) { + char windgustvalue[DATA_LENGTH]; + tdSensorValue(protocol, model, sensorId, TELLSTICK_WINDGUST, windgustvalue, DATA_LENGTH, (int *)×tamp); + printf("\twindgust=%s", windgustvalue); + } + + if (dataTypes & TELLSTICK_RAINRATE) { + char rainratevalue[DATA_LENGTH]; + tdSensorValue(protocol, model, sensorId, TELLSTICK_RAINRATE, rainratevalue, DATA_LENGTH, (int *)×tamp); + printf("\trainrate=%s", rainratevalue); + } + + if (dataTypes & TELLSTICK_RAINTOTAL) { + char raintotalvalue[DATA_LENGTH]; + tdSensorValue(protocol, model, sensorId, TELLSTICK_RAINTOTAL, raintotalvalue, DATA_LENGTH, (int *)×tamp); + printf("\traintotal=%s", raintotalvalue); + } + if (dataTypes & (TELLSTICK_TEMPERATURE | TELLSTICK_HUMIDITY)) { /* timestamp has been set, print time & age */ /* (age is more useful on e.g. embedded systems