From 67ec0678a3ea07c8b3d5aca1fecdbe30bd54bb16 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 11 Dec 2018 14:24:52 +0100 Subject: [PATCH] 6.3.0.17 Add features 6.3.0.17 20181211 * Add support for TheoV2 sensors as documented on https://sidweb.nl * Add support for SDM220 (#3610) * Enhance support for MPU6050 using DMP (#4581) --- sonoff/_changelog.ino | 7 +- sonoff/i18n.h | 13 +- sonoff/language/bg-BG.h | 1 + sonoff/language/cs-CZ.h | 1 + sonoff/language/de-DE.h | 1 + sonoff/language/el-GR.h | 1 + sonoff/language/en-GB.h | 3 +- sonoff/language/es-AR.h | 1 + sonoff/language/fr-FR.h | 1 + sonoff/language/he-HE.h | 1 + sonoff/language/hu-HU.h | 1 + sonoff/language/it-IT.h | 1 + sonoff/language/nl-NL.h | 1 + sonoff/language/pl-PL.h | 1 + sonoff/language/pt-BR.h | 1 + sonoff/language/pt-PT.h | 2 +- sonoff/language/ru-RU.h | 1 + sonoff/language/sv-SE.h | 3 +- sonoff/language/tr-TR.h | 1 + sonoff/language/uk-UK.h | 1 + sonoff/language/zh-CN.h | 1 + sonoff/language/zh-TW.h | 1 + sonoff/my_user_config.h | 6 +- sonoff/sonoff.ino | 1 + sonoff/sonoff_template.h | 7 +- sonoff/sonoff_version.h | 2 +- sonoff/support_features.ino | 13 +- sonoff/support_rtc.ino | 40 +-- sonoff/xsns_10_bh1750.ino | 5 - sonoff/xsns_37_rfsensor.ino | 634 ++++++++++++++++++++++++++++++++++++ tools/decode-status.py | 4 +- 31 files changed, 714 insertions(+), 43 deletions(-) create mode 100644 sonoff/xsns_37_rfsensor.ino diff --git a/sonoff/_changelog.ino b/sonoff/_changelog.ino index cbad2b3c2..4ca0e0dd7 100644 --- a/sonoff/_changelog.ino +++ b/sonoff/_changelog.ino @@ -1,4 +1,9 @@ -/* 6.3.0.16 20181201 +/* 6.3.0.17 20181211 + * Add support for TheoV2 sensors as documented on https://sidweb.nl + * Add support for SDM220 (#3610) + * Enhance support for MPU6050 using DMP (#4581) + * + * 6.3.0.16 20181201 * Add support for iFan02 Fanspeed in Domoticz using a selector (#4517) * Add Announce Switches to MQTT Discovery (#4531) * Update MCP230xx driver to support interrupt retention over teleperiod (#4547) diff --git a/sonoff/i18n.h b/sonoff/i18n.h index 66ee5e490..b1bec3289 100644 --- a/sonoff/i18n.h +++ b/sonoff/i18n.h @@ -49,12 +49,6 @@ #define D_JSON_COUNT "Count" #define D_JSON_COUNTER "Counter" #define D_JSON_CURRENT "Current" // As in Voltage and Current -#define D_JSON_PHASE_ANGLE "Phase angle" -#define D_JSON_IMPORT_ACTIVE "Import Active Power" -#define D_JSON_EXPORT_ACTIVE "Export Active Power" -#define D_JSON_IMPORT_REACTIVE "Import Reactive Power" -#define D_JSON_EXPORT_REACTIVE "Export Reactive Power" -#define D_JSON_TOTAL_REACTIVE "Total Reactive Power" #define D_JSON_DATA "Data" #define D_JSON_DISTANCE "Distance" #define D_JSON_DNSSERVER "DNSServer" @@ -65,6 +59,8 @@ #define D_JSON_ERASE "Erase" #define D_JSON_ERROR "Error" #define D_JSON_EVERY "Every" +#define D_JSON_EXPORT_ACTIVE "ExportActivePower" +#define D_JSON_EXPORT_REACTIVE "ExportReactivePower" #define D_JSON_FAILED "Failed" #define D_JSON_FALLBACKTOPIC "FallbackTopic" #define D_JSON_FEATURES "Features" @@ -86,6 +82,8 @@ #define D_JSON_I2CSCAN_NO_DEVICES_FOUND "No devices found" #define D_JSON_ID "Id" #define D_JSON_ILLUMINANCE "Illuminance" +#define D_JSON_IMPORT_ACTIVE "ImportActivePower" +#define D_JSON_IMPORT_REACTIVE "ImportReactivePower" #define D_JSON_INFRARED "Infrared" #define D_JSON_UNKNOWN "Unknown" #define D_JSON_LIGHT "Light" @@ -99,6 +97,7 @@ #define D_JSON_NONE "None" #define D_JSON_OR "or" #define D_JSON_PERIOD "Period" +#define D_JSON_PHASE_ANGLE "PhaseAngle" #define D_JSON_POWERFACTOR "Factor" #define D_JSON_POWERUSAGE "Power" #define D_JSON_ACTIVE_POWERUSAGE "ActivePower" @@ -135,6 +134,7 @@ #define D_JSON_TIME "Time" #define D_JSON_TODAY "Today" #define D_JSON_TOTAL "Total" +#define D_JSON_TOTAL_REACTIVE "TotalReactivePower" #define D_JSON_TOTAL_START_TIME "TotalStartTime" #define D_JSON_TVOC "TVOC" #define D_JSON_TYPE "Type" @@ -546,6 +546,7 @@ const char HTTP_SNS_HUM[] PROGMEM = "%s{s}%s " D_HUMIDITY "{m}%s%%{e}"; const char HTTP_SNS_PRESSURE[] PROGMEM = "%s{s}%s " D_PRESSURE "{m}%s %s{e}"; // {s} = , {m} = , {e} = const char HTTP_SNS_SEAPRESSURE[] PROGMEM = "%s{s}%s " D_PRESSUREATSEALEVEL "{m}%s %s{e}"; // {s} = , {m} = , {e} = const char HTTP_SNS_ANALOG[] PROGMEM = "%s{s}%s " D_ANALOG_INPUT "%d{m}%d{e}"; // {s} = , {m} = , {e} = +const char HTTP_SNS_ILLUMINANCE[] PROGMEM = "%s{s}%s " D_ILLUMINANCE "{m}%d " D_UNIT_LUX "{e}"; // {s} = , {m} = , {e} = #if defined(USE_MHZ19) || defined(USE_SENSEAIR) const char HTTP_SNS_CO2[] PROGMEM = "%s{s}%s " D_CO2 "{m}%d " D_UNIT_PARTS_PER_MILLION "{e}"; // {s} = , {m} = , {e} = diff --git a/sonoff/language/bg-BG.h b/sonoff/language/bg-BG.h index 9cad9f63f..9ed4734a8 100644 --- a/sonoff/language/bg-BG.h +++ b/sonoff/language/bg-BG.h @@ -536,6 +536,7 @@ #define D_SENSOR_SSPI_SCLK "SSPI SCLK" #define D_SENSOR_SSPI_CS "SSPI CS" #define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/cs-CZ.h b/sonoff/language/cs-CZ.h index ffd69a714..8bcde604b 100644 --- a/sonoff/language/cs-CZ.h +++ b/sonoff/language/cs-CZ.h @@ -536,6 +536,7 @@ #define D_SENSOR_SSPI_SCLK "SSPI SCLK" #define D_SENSOR_SSPI_CS "SSPI CS" #define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/de-DE.h b/sonoff/language/de-DE.h index 69f12e56e..21f7e5dd8 100644 --- a/sonoff/language/de-DE.h +++ b/sonoff/language/de-DE.h @@ -536,6 +536,7 @@ #define D_SENSOR_SSPI_SCLK "SSPI SCLK" #define D_SENSOR_SSPI_CS "SSPI CS" #define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/el-GR.h b/sonoff/language/el-GR.h index bafc460c4..e59855a24 100644 --- a/sonoff/language/el-GR.h +++ b/sonoff/language/el-GR.h @@ -536,6 +536,7 @@ #define D_SENSOR_SSPI_SCLK "SSPI SCLK" #define D_SENSOR_SSPI_CS "SSPI CS" #define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/en-GB.h b/sonoff/language/en-GB.h index 4cb1d381e..a38664d2f 100644 --- a/sonoff/language/en-GB.h +++ b/sonoff/language/en-GB.h @@ -536,7 +536,7 @@ #define D_SENSOR_SSPI_SCLK "SSPI SCLK" #define D_SENSOR_SSPI_CS "SSPI CS" #define D_SENSOR_SSPI_DC "SSPI DC" - +#define D_SENSOR_RF_SENSOR "RF Sensor" // Units #define D_UNIT_AMPERE "A" @@ -594,6 +594,7 @@ #define D_LOG_UPNP "UPP: " // UPnP #define D_LOG_WIFI "WIF: " // Wifi +//SDM220 #define D_PHASE_ANGLE "Phase Angle" #define D_IMPORT_ACTIVE "Import Active" #define D_EXPORT_ACTIVE "Export Active" diff --git a/sonoff/language/es-AR.h b/sonoff/language/es-AR.h index c0d8885a5..7039d66a6 100644 --- a/sonoff/language/es-AR.h +++ b/sonoff/language/es-AR.h @@ -536,6 +536,7 @@ #define D_SENSOR_SSPI_SCLK "SSPI SCLK" #define D_SENSOR_SSPI_CS "SSPI CS" #define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/fr-FR.h b/sonoff/language/fr-FR.h index b6dc5132f..a038153c9 100644 --- a/sonoff/language/fr-FR.h +++ b/sonoff/language/fr-FR.h @@ -536,6 +536,7 @@ #define D_SENSOR_SSPI_SCLK "SSPI SCLK" #define D_SENSOR_SSPI_CS "SSPI CS" #define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/he-HE.h b/sonoff/language/he-HE.h index 2039683a4..6f3612fb7 100644 --- a/sonoff/language/he-HE.h +++ b/sonoff/language/he-HE.h @@ -536,6 +536,7 @@ #define D_SENSOR_SSPI_SCLK "SSPI SCLK" #define D_SENSOR_SSPI_CS "SSPI CS" #define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/hu-HU.h b/sonoff/language/hu-HU.h index 8fefbfa7d..82c911fb1 100644 --- a/sonoff/language/hu-HU.h +++ b/sonoff/language/hu-HU.h @@ -536,6 +536,7 @@ #define D_SENSOR_SSPI_SCLK "SSPI SCLK" #define D_SENSOR_SSPI_CS "SSPI CS" #define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/it-IT.h b/sonoff/language/it-IT.h index da2f91107..b971d1c02 100644 --- a/sonoff/language/it-IT.h +++ b/sonoff/language/it-IT.h @@ -536,6 +536,7 @@ #define D_SENSOR_SSPI_SCLK "SSPI SCLK" #define D_SENSOR_SSPI_CS "SSPI CS" #define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/nl-NL.h b/sonoff/language/nl-NL.h index c8a32a463..73a201448 100644 --- a/sonoff/language/nl-NL.h +++ b/sonoff/language/nl-NL.h @@ -536,6 +536,7 @@ #define D_SENSOR_SSPI_SCLK "SSPI SCLK" #define D_SENSOR_SSPI_CS "SSPI CS" #define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/pl-PL.h b/sonoff/language/pl-PL.h index 2a26afa78..e4728bda8 100644 --- a/sonoff/language/pl-PL.h +++ b/sonoff/language/pl-PL.h @@ -536,6 +536,7 @@ #define D_SENSOR_SSPI_SCLK "SSPI SCLK" #define D_SENSOR_SSPI_CS "SSPI CS" #define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/pt-BR.h b/sonoff/language/pt-BR.h index 4bad901e7..487f4793d 100644 --- a/sonoff/language/pt-BR.h +++ b/sonoff/language/pt-BR.h @@ -536,6 +536,7 @@ #define D_SENSOR_SSPI_SCLK "SSPI SCLK" #define D_SENSOR_SSPI_CS "SSPI CS" #define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/pt-PT.h b/sonoff/language/pt-PT.h index a0ec3643b..4b2366758 100644 --- a/sonoff/language/pt-PT.h +++ b/sonoff/language/pt-PT.h @@ -536,7 +536,7 @@ #define D_SENSOR_SSPI_SCLK "SSPI SCLK" #define D_SENSOR_SSPI_CS "SSPI CS" #define D_SENSOR_SSPI_DC "SSPI DC" - +#define D_SENSOR_RF_SENSOR "RF Sensor" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/ru-RU.h b/sonoff/language/ru-RU.h index ac7b5ea16..e2e6079cd 100644 --- a/sonoff/language/ru-RU.h +++ b/sonoff/language/ru-RU.h @@ -536,6 +536,7 @@ #define D_SENSOR_SSPI_SCLK "SSPI SCLK" #define D_SENSOR_SSPI_CS "SSPI CS" #define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" // Units #define D_UNIT_AMPERE "А" diff --git a/sonoff/language/sv-SE.h b/sonoff/language/sv-SE.h index abaa994db..9ec54c62b 100644 --- a/sonoff/language/sv-SE.h +++ b/sonoff/language/sv-SE.h @@ -536,7 +536,7 @@ #define D_SENSOR_SSPI_SCLK "SSPI SCLK" #define D_SENSOR_SSPI_CS "SSPI CS" #define D_SENSOR_SSPI_DC "SSPI DC" - +#define D_SENSOR_RF_SENSOR "RF Sensor" // Units #define D_UNIT_AMPERE "A" @@ -594,6 +594,7 @@ #define D_LOG_UPNP "UPP: " // UPnP #define D_LOG_WIFI "WIF: " // Wifi +//SDM220 #define D_PHASE_ANGLE "Phase Angle" #define D_IMPORT_ACTIVE "Import Active" #define D_EXPORT_ACTIVE "Export Active" diff --git a/sonoff/language/tr-TR.h b/sonoff/language/tr-TR.h index cee31869f..4425431ee 100755 --- a/sonoff/language/tr-TR.h +++ b/sonoff/language/tr-TR.h @@ -536,6 +536,7 @@ #define D_SENSOR_SSPI_SCLK "SSPI SCLK" #define D_SENSOR_SSPI_CS "SSPI CS" #define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" // Units #define D_UNIT_AMPERE "A" diff --git a/sonoff/language/uk-UK.h b/sonoff/language/uk-UK.h index 281975c07..82449858e 100644 --- a/sonoff/language/uk-UK.h +++ b/sonoff/language/uk-UK.h @@ -536,6 +536,7 @@ #define D_SENSOR_SSPI_SCLK "SSPI SCLK" #define D_SENSOR_SSPI_CS "SSPI CS" #define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" // Units #define D_UNIT_AMPERE "А" diff --git a/sonoff/language/zh-CN.h b/sonoff/language/zh-CN.h index f882765a5..f1ba0c93d 100644 --- a/sonoff/language/zh-CN.h +++ b/sonoff/language/zh-CN.h @@ -536,6 +536,7 @@ #define D_SENSOR_SSPI_SCLK "SSPI SCLK" #define D_SENSOR_SSPI_CS "SSPI CS" #define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" // Units #define D_UNIT_AMPERE "安" diff --git a/sonoff/language/zh-TW.h b/sonoff/language/zh-TW.h index 6a9b9bd52..3a9d12336 100644 --- a/sonoff/language/zh-TW.h +++ b/sonoff/language/zh-TW.h @@ -536,6 +536,7 @@ #define D_SENSOR_SSPI_SCLK "SSPI SCLK" #define D_SENSOR_SSPI_CS "SSPI CS" #define D_SENSOR_SSPI_DC "SSPI DC" +#define D_SENSOR_RF_SENSOR "RF Sensor" // Units #define D_UNIT_AMPERE "安" diff --git a/sonoff/my_user_config.h b/sonoff/my_user_config.h index a9caabdb8..3a35b7d33 100644 --- a/sonoff/my_user_config.h +++ b/sonoff/my_user_config.h @@ -357,7 +357,7 @@ #define USE_SERIAL_BRIDGE // Add support for software Serial Bridge (+0k8 code) //#define USE_SDM120 // Add support for Eastron SDM120-Modbus energy meter (+1k7 code) #define SDM120_SPEED 9600 // SDM120-Modbus RS485 serial speed (default: 2400 baud) - #define USE_SDM220 // add extra parameters for SDM220 (+0k1 code) + #define USE_SDM220 // Add extra parameters for SDM220 (+0k1 code) //#define USE_SDM630 // Add support for Eastron SDM630-Modbus energy meter (+2k code) #define SDM630_SPEED 9600 // SDM630-Modbus RS485 serial speed (default: 9600 baud) //#define USE_MP3_PLAYER // Use of the DFPlayer Mini MP3 Player RB-DFR-562 commands: play, volume and stop @@ -399,6 +399,10 @@ #define USE_RC_SWITCH // Add support for RF transceiver using library RcSwitch (+2k7 code, 460 iram) +//#define USE_RF_SENSOR // Add support for RF (434MHz or 868MHz) receiver (+2k code) +// #define USE_THEO_V2 // Add support for 434MHz Theo V2 sensors as documented on https://sidweb.nl +// #define USE_ALECTO_V2 // Add support for 868MHz Alecto V2 sensors like ACH2010, WS3000 and DKW2012 + /*********************************************************************************************\ * Debug features are only supported in development branch \*********************************************************************************************/ diff --git a/sonoff/sonoff.ino b/sonoff/sonoff.ino index ad14aeccd..8e4006ca1 100755 --- a/sonoff/sonoff.ino +++ b/sonoff/sonoff.ino @@ -2766,6 +2766,7 @@ void loop(void) uint32_t my_sleep = millis(); XdrvCall(FUNC_LOOP); + XsnsCall(FUNC_LOOP); OsWatchLoop(); diff --git a/sonoff/sonoff_template.h b/sonoff/sonoff_template.h index 225d3767a..f3b366d38 100644 --- a/sonoff/sonoff_template.h +++ b/sonoff/sonoff_template.h @@ -140,6 +140,7 @@ enum UserSelectablePins { GPIO_SSPI_SCLK, // Software SPI Serial Clock GPIO_SSPI_CS, // Software SPI Chip Select GPIO_SSPI_DC, // Software SPI Data or Command + GPIO_RF_SENSOR, // Rf receiver with sensor decoding GPIO_SENSOR_END }; // Programmer selectable GPIO functionality offset by user selectable GPIOs @@ -199,7 +200,8 @@ const char kSensorNames[] PROGMEM = D_SENSOR_RFSEND "|" D_SENSOR_RFRECV "|" D_SENSOR_TUYA_TX "|" D_SENSOR_TUYA_RX "|" D_SENSOR_MGC3130_XFER "|" D_SENSOR_MGC3130_RESET "|" - D_SENSOR_SSPI_MISO "|" D_SENSOR_SSPI_MOSI "|" D_SENSOR_SSPI_SCLK "|" D_SENSOR_SSPI_CS "|" D_SENSOR_SSPI_DC; + D_SENSOR_SSPI_MISO "|" D_SENSOR_SSPI_MOSI "|" D_SENSOR_SSPI_SCLK "|" D_SENSOR_SSPI_CS "|" D_SENSOR_SSPI_DC "|" + D_SENSOR_RF_SENSOR; /********************************************************************************************/ @@ -382,6 +384,9 @@ const uint8_t kGpioNiceList[] PROGMEM = { GPIO_RFSEND, // RF transmitter GPIO_RFRECV, // RF receiver #endif +#ifdef USE_RF_SENSOR + GPIO_RF_SENSOR, // Rf receiver with sensor decoding +#endif #ifdef USE_SR04 GPIO_SR04_TRIG, // SR04 Trigger pin GPIO_SR04_ECHO, // SR04 Echo pin diff --git a/sonoff/sonoff_version.h b/sonoff/sonoff_version.h index 9c41f0220..ed771e734 100644 --- a/sonoff/sonoff_version.h +++ b/sonoff/sonoff_version.h @@ -20,7 +20,7 @@ #ifndef _SONOFF_VERSION_H_ #define _SONOFF_VERSION_H_ -#define VERSION 0x06030010 +#define VERSION 0x06030011 #define D_PROGRAMNAME "Sonoff-Tasmota" #define D_AUTHOR "Theo Arends" diff --git a/sonoff/support_features.ino b/sonoff/support_features.ino index 8859cca55..652116b2f 100644 --- a/sonoff/support_features.ino +++ b/sonoff/support_features.ino @@ -361,10 +361,15 @@ void GetFeatures(void) #ifdef USE_MGC3130 feature_sns2 |= 0x00004000; // xsns_36_mgc3130.ino #endif - -// feature_sns2 |= 0x00008000; -// feature_sns2 |= 0x00010000; -// feature_sns2 |= 0x00020000; +#ifdef USE_RF_SENSOR + feature_sns2 |= 0x00008000; // xsns_37_rfsensor.ino +#endif +#ifdef USE_THEO_V2 + feature_sns2 |= 0x00010000; +#endif +#ifdef USE_ALECTO_V2 + feature_sns2 |= 0x00020000; +#endif // feature_sns2 |= 0x00040000; // feature_sns2 |= 0x00080000; // feature_sns2 |= 0x00100000; diff --git a/sonoff/support_rtc.ino b/sonoff/support_rtc.ino index 4ba0747a5..b09c593e2 100644 --- a/sonoff/support_rtc.ino +++ b/sonoff/support_rtc.ino @@ -87,6 +87,20 @@ String GetTimeZone(void) return String(tz); // -03:45 } +String GetDT(uint32_t time) +{ + // "2017-03-07T11:08:02" - ISO8601:2004 + + char dt[20]; + TIME_T tmpTime; + + BreakTime(time, tmpTime); + snprintf_P(dt, sizeof(dt), PSTR("%04d-%02d-%02dT%02d:%02d:%02d"), + tmpTime.year +1970, tmpTime.month, tmpTime.day_of_month, tmpTime.hour, tmpTime.minute, tmpTime.second); + + return String(dt); // 2017-03-07T11:08:02 +} + /* * timestamps in https://en.wikipedia.org/wiki/ISO_8601 format * @@ -101,39 +115,27 @@ String GetTimeZone(void) String GetDateAndTime(byte time_type) { // "2017-03-07T11:08:02-07:00" - ISO8601:2004 - char dt[27]; - TIME_T tmpTime; + uint32_t time = local_time; switch (time_type) { case DT_ENERGY: - BreakTime(Settings.energy_kWhtotal_time, tmpTime); - tmpTime.year += 1970; + time = Settings.energy_kWhtotal_time; break; case DT_UTC: - BreakTime(utc_time, tmpTime); - tmpTime.year += 1970; + time = utc_time; break; case DT_RESTART: if (restart_time == 0) { return ""; } - BreakTime(restart_time, tmpTime); - tmpTime.year += 1970; + time = restart_time; break; - default: - tmpTime = RtcTime; } - - - snprintf_P(dt, sizeof(dt), PSTR("%04d-%02d-%02dT%02d:%02d:%02d"), - tmpTime.year, tmpTime.month, tmpTime.day_of_month, tmpTime.hour, tmpTime.minute, tmpTime.second); - + String dt = GetDT(time); // 2017-03-07T11:08:02 if (Settings.flag3.time_append_timezone && (DT_LOCAL == time_type)) { -// if (Settings.flag3.time_append_timezone && ((DT_LOCAL == time_type) || (DT_ENERGY == time_type))) { - strncat(dt, GetTimeZone().c_str(), sizeof(dt) - strlen(dt) -1); + dt += GetTimeZone(); // 2017-03-07T11:08:02-07:00 } - - return String(dt); // 2017-03-07T11:08:02-07:00 + return dt; // 2017-03-07T11:08:02-07:00 } String GetTime(int type) diff --git a/sonoff/xsns_10_bh1750.ino b/sonoff/xsns_10_bh1750.ino index c93a3513f..af0d1aebb 100644 --- a/sonoff/xsns_10_bh1750.ino +++ b/sonoff/xsns_10_bh1750.ino @@ -89,11 +89,6 @@ void Bh1750EverySecond(void) } } -#ifdef USE_WEBSERVER -const char HTTP_SNS_ILLUMINANCE[] PROGMEM = - "%s{s}%s " D_ILLUMINANCE "{m}%d " D_UNIT_LUX "{e}"; // {s} = , {m} = , {e} = -#endif // USE_WEBSERVER - void Bh1750Show(boolean json) { if (bh1750_valid) { diff --git a/sonoff/xsns_37_rfsensor.ino b/sonoff/xsns_37_rfsensor.ino new file mode 100644 index 000000000..63c567839 --- /dev/null +++ b/sonoff/xsns_37_rfsensor.ino @@ -0,0 +1,634 @@ +/* + xsns_37_rfsensor.ino - RF sensor receiver for Sonoff-Tasmota + + Copyright (C) 2018 Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef USE_RF_SENSOR +/*********************************************************************************************\ + * RF receive based on work by Paul Tonkes (www.nodo-domotica.nl) + * + * USE_THEO_V2 Add support for 434MHz Theo V2 sensors as documented on https://sidweb.nl + * USE_ALECTO_V2 Add support for 868MHz Alecto V2 sensors like ACH2010, WS3000 and DKW2012 +\*********************************************************************************************/ + +#define XSNS_37 37 + +//#define USE_THEO_V2 // Add support for 434MHz Theo V2 sensors as documented on https://sidweb.nl +//#define USE_ALECTO_V2 // Add support for 868MHz Alecto V2 sensors like ACH2010, WS3000 and DKW2012 + +#define RFSNS_VALID_WINDOW 1800 // Number of seconds for sensor to respond (1800 = 30 minutes) + +#define RFSNS_LOOPS_PER_MILLI 1900 // (345 voor 16MHz ATMega) Voor 80MHz NodeMCU (ESP-12E). Getest met TheoV2 Protocol. +#define RFSNS_RAW_BUFFER_SIZE 180 // (256) Maximum number of RF pulses that can be captured +#define RFSNS_MIN_RAW_PULSES 112 // (16) =8 bits. Minimaal aantal ontvangen bits*2 alvorens cpu tijd wordt besteed aan decodering, etc. + // Zet zo hoog mogelijk om CPU-tijd te sparen en minder 'onzin' te ontvangen. +#define RFSNS_MIN_PULSE_LENGTH 300 // (50) Pulsen korter dan deze tijd uSec. worden als stoorpulsen beschouwd. +#define RFSNS_RAWSIGNAL_SAMPLE 50 // Sample grootte / Resolutie in uSec waarmee ontvangen Rawsignalen pulsen worden opgeslagen +#define RFSNS_SIGNAL_TIMEOUT 10 // Pulse timings in mSec. Beyond this value indicate end of message +#define RFSNS_SIGNAL_REPEAT_TIME 500 // (500) Tijd in mSec. waarbinnen hetzelfde event niet nogmaals via RF mag binnenkomen. Onderdrukt ongewenste herhalingen van signaal + +struct RawSignalStruct // Variabelen geplaatst in struct zodat deze later eenvoudig kunnen worden weggeschreven naar SDCard +{ + int Number; // aantal bits, maal twee omdat iedere bit een mark en een space heeft. + byte Repeats; // Aantal maal dat de pulsreeks verzonden moet worden bij een zendactie. + byte Multiply; // Pulses[] * Multiply is de echte tijd van een puls in microseconden + unsigned long Time; // Tijdstempel wanneer signaal is binnengekomen (millis()) + byte Pulses[RFSNS_RAW_BUFFER_SIZE+2]; // Tabel met de gemeten pulsen in microseconden gedeeld door rfsns_raw_signal.Multiply. Dit scheelt helft aan RAM geheugen. + // Om legacy redenen zit de eerste puls in element 1. Element 0 wordt dus niet gebruikt. +} rfsns_raw_signal = {0, 0, 0, 0L}; + +uint8_t rfsns_rf_bit; +uint8_t rfsns_rf_port; + +/*********************************************************************************************\ + * Fetch signals from RF pin +\*********************************************************************************************/ + +boolean RfSnsFetchSignal(byte DataPin, boolean StateSignal) +{ + uint8_t Fbit = digitalPinToBitMask(DataPin); + uint8_t Fport = digitalPinToPort(DataPin); + uint8_t FstateMask = (StateSignal ? Fbit : 0); + + if ((*portInputRegister(Fport) & Fbit) == FstateMask) { // Als er signaal is + const unsigned long LoopsPerMilli = RFSNS_LOOPS_PER_MILLI; + + // Als het een herhalend signaal is, dan is de kans groot dat we binnen hele korte tijd weer in deze + // routine terugkomen en dan midden in de volgende herhaling terecht komen. Daarom wordt er in dit + // geval gewacht totdat de pulsen voorbij zijn en we met het capturen van data beginnen na een korte + // rust tussen de signalen. Op deze wijze wordt het aantal zinloze captures teruggebracht. + + unsigned long PulseLength = 0; + if (rfsns_raw_signal.Time) { // Eerst een snelle check, want dit bevindt zich in een tijdkritisch deel... + if (rfsns_raw_signal.Repeats && (rfsns_raw_signal.Time + RFSNS_SIGNAL_REPEAT_TIME) > millis()) { // ...want deze check duurt enkele micro's langer! + PulseLength = micros() + RFSNS_SIGNAL_TIMEOUT *1000; // Wachttijd + while (((rfsns_raw_signal.Time + RFSNS_SIGNAL_REPEAT_TIME) > millis()) && (PulseLength > micros())) { + if ((*portInputRegister(Fport) & Fbit) == FstateMask) { + PulseLength = micros() + RFSNS_SIGNAL_TIMEOUT *1000; + } + } + while (((rfsns_raw_signal.Time + RFSNS_SIGNAL_REPEAT_TIME) > millis()) && ((*portInputRegister(Fport) & Fbit) != FstateMask)); + } + } + + int RawCodeLength = 1; // We starten bij 1, dit om legacy redenen. Vroeger had element 0 een speciaal doel. + bool Ftoggle = false; + unsigned long numloops = 0; + unsigned long maxloops = RFSNS_SIGNAL_TIMEOUT * LoopsPerMilli; + rfsns_raw_signal.Multiply = RFSNS_RAWSIGNAL_SAMPLE; // Ingestelde sample groote. + do { // lees de pulsen in microseconden en plaats deze in de tijdelijke buffer rfsns_raw_signal + numloops = 0; + while(((*portInputRegister(Fport) & Fbit) == FstateMask) ^ Ftoggle) { // while() loop *A* + if (numloops++ == maxloops) { break; } // timeout opgetreden + } + PulseLength = (numloops *1000) / LoopsPerMilli; // Bevat nu de pulslengte in microseconden + if (PulseLength < RFSNS_MIN_PULSE_LENGTH) { break; } + Ftoggle = !Ftoggle; + rfsns_raw_signal.Pulses[RawCodeLength++] = PulseLength / (unsigned long)rfsns_raw_signal.Multiply; // sla op in de tabel rfsns_raw_signal + } + while(RawCodeLength < RFSNS_RAW_BUFFER_SIZE && numloops <= maxloops); // Zolang nog ruimte in de buffer, geen timeout en geen stoorpuls + + if ((RawCodeLength >= RFSNS_MIN_RAW_PULSES) && (RawCodeLength < RFSNS_RAW_BUFFER_SIZE -1)) { + rfsns_raw_signal.Repeats = 0; // Op dit moment weten we nog niet het type signaal, maar de variabele niet ongedefinieerd laten. + rfsns_raw_signal.Number = RawCodeLength -1; // Aantal ontvangen tijden (pulsen *2) + rfsns_raw_signal.Pulses[rfsns_raw_signal.Number] = 0; // Laatste element bevat de timeout. Niet relevant. + rfsns_raw_signal.Time = millis(); + return true; + } + else + rfsns_raw_signal.Number = 0; + } + + return false; +} + +#ifdef USE_THEO_V2 +/*********************************************************************************************\ + * Theo V2 protocol + * Dit protocol zorgt voor ontvangst van Theo sensoren met protocol V2 + * + * Auteur : Theo Arends + * Support : www.sidweb.nl + * Datum : 17 Apr 2014 + * Versie : 0.1 - Initiele versie + ********************************************************************************************** + * Technische informatie: + * + * Theo Sensor V2 type 1 Message Format (7 Bytes, 57 bits): + * Checksum Type Chl BsVoltag Temperature Light + * S AAAAAAAA BBBBBCCC DEFFFFFF GGGGGGGG GGGGGGGG HHHHHHHH HHHHHHHH + * idx: 0 1 2 3 4 5 6 + * + * Theo Sensor V2 type 2 Message Format (7 Bytes, 57 bits): + * Checksum Type Chl BsVoltag Temperature Humidity + * S AAAAAAAA BBBBBCCC DEFFFFFF GGGGGGGG GGGGGGGG HHHHHHHH HHHHHHHH + * idx: 0 1 2 3 4 5 6 +\*********************************************************************************************/ + +#define RFSNS_THEOV2_MAX_CHANNEL 2 // Max number of ATTiny sensor channels supported + +#define RFSNS_THEOV2_PULSECOUNT 114 +#define RFSNS_THEOV2_RF_PULSE_MID 1000 // PWM: Pulsen langer zijn '1' + +typedef struct { + uint32_t time; + int16_t temp; + uint16_t lux; + uint8_t volt; +} theo_v2_t1_t; + +theo_v2_t1_t rfsns_theo_v2_t1[RFSNS_THEOV2_MAX_CHANNEL]; + +typedef struct { + uint32_t time; + int16_t temp; + uint16_t hum; + uint8_t volt; +} theo_v2_t2_t; + +theo_v2_t2_t rfsns_theo_v2_t2[RFSNS_THEOV2_MAX_CHANNEL]; + +boolean RfSnsAnalyzeTheov2(void) +{ + if (rfsns_raw_signal.Number != RFSNS_THEOV2_PULSECOUNT) return false; + + byte Checksum; // 8 bits Checksum over following bytes + byte Channel; // 3 bits channel + byte Type; // 5 bits type + byte Voltage; // 8 bits Vcc like 45 = 4.5V, bit 8 is batt low + int Payload1; // 16 bits + int Payload2; // 16 bits + + byte b, bytes, bits, id; + char log[128]; + + byte idx = 3; + byte chksum = 0; + for (bytes = 0; bytes < 7; bytes++) { + b = 0; + for (bits = 0; bits <= 7; bits++) + { + if ((rfsns_raw_signal.Pulses[idx] * rfsns_raw_signal.Multiply) > RFSNS_THEOV2_RF_PULSE_MID) { + b |= 1 << bits; + } + idx += 2; + } + if (bytes > 0) { chksum += b; } // bereken checksum + + switch (bytes) { + case 0: + Checksum = b; + break; + case 1: + id = b; + Channel = b & 0x7; + Type = (b >> 3) & 0x1f; + break; + case 2: + Voltage = b; + break; + case 3: + Payload1 = b; + break; + case 4: + Payload1 = (b << 8) | Payload1; + break; + case 5: + Payload2 = b; + break; + case 6: + Payload2 = (b << 8) | Payload2; + break; + } + } + + if (Checksum != chksum) { return false; } + if (Channel == 0) { return false; } + + rfsns_raw_signal.Repeats = 1; // het is een herhalend signaal. Bij ontvangst herhalingen onderdukken + + int Payload3 = Voltage & 0x3f; + Channel--; + + switch (Type) { + case 1: // Temp / Lux + rfsns_theo_v2_t1[Channel].time = LocalTime(); + rfsns_theo_v2_t1[Channel].volt = Payload3; + rfsns_theo_v2_t1[Channel].temp = Payload1; + rfsns_theo_v2_t1[Channel].lux = Payload2; + break; + case 2: // Temp / Hum + rfsns_theo_v2_t2[Channel].time = LocalTime(); + rfsns_theo_v2_t2[Channel].volt = Payload3; + rfsns_theo_v2_t2[Channel].temp = Payload1; + rfsns_theo_v2_t2[Channel].hum = Payload2; + break; + } + + snprintf_P(log_data, sizeof(log_data), PSTR("RFS: TheoV2, ChkCalc %d, Chksum %d, id %d, Type %d, Ch %d, Volt %d, BattLo %d, Pld1 %d, Pld2 %d"), + chksum, Checksum, id, Type, Channel +1, Payload3, (Voltage & 0x80) >> 7, Payload1, Payload2); + AddLog(LOG_LEVEL_DEBUG); + + return true; +} + +void RfSnsTheoV2Show(boolean json) +{ + bool sensor_once = false; + + for (uint8_t i = 0; i < RFSNS_THEOV2_MAX_CHANNEL; i++) { + if (rfsns_theo_v2_t1[i].time) { + char sensor[10]; + snprintf_P(sensor, sizeof(sensor), PSTR("TV2T1C%d"), i +1); + char voltage[10]; + dtostrfd((float)rfsns_theo_v2_t1[i].volt / 10, 1, voltage); + + if (rfsns_theo_v2_t1[i].time < LocalTime() - RFSNS_VALID_WINDOW) { + if (json) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_RFRECEIVED "\":\"%s\",\"" D_JSON_VOLTAGE "\":%s}"), + mqtt_data, sensor, GetDT(rfsns_theo_v2_t1[i].time).c_str(), voltage); + } + } else { + char temperature[10]; + dtostrfd(ConvertTemp((float)rfsns_theo_v2_t1[i].temp / 100), Settings.flag2.temperature_resolution, temperature); + + if (json) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_ILLUMINANCE "\":%d,\"" D_JSON_VOLTAGE "\":%s}"), + mqtt_data, sensor, temperature, rfsns_theo_v2_t1[i].lux, voltage); +#ifdef USE_DOMOTICZ + if ((0 == tele_period) && !sensor_once) { + DomoticzSensor(DZ_TEMP, temperature); + DomoticzSensor(DZ_ILLUMINANCE, rfsns_theo_v2_t1[i].lux); + sensor_once = true; + } +#endif // USE_DOMOTICZ +#ifdef USE_WEBSERVER + } else { + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TEMP, mqtt_data, sensor, temperature, TempUnit()); + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_ILLUMINANCE, mqtt_data, sensor, rfsns_theo_v2_t1[i].lux); +#endif // USE_WEBSERVER + } + } + } + } + + sensor_once = false; + for (uint8_t i = 0; i < RFSNS_THEOV2_MAX_CHANNEL; i++) { + if (rfsns_theo_v2_t2[i].time) { + char sensor[10]; + snprintf_P(sensor, sizeof(sensor), PSTR("TV2T2C%d"), i +1); + char voltage[10]; + dtostrfd((float)rfsns_theo_v2_t2[i].volt / 10, 1, voltage); + + if (rfsns_theo_v2_t2[i].time < LocalTime() - RFSNS_VALID_WINDOW) { + if (json) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_RFRECEIVED" \":\"%s\",\"" D_JSON_VOLTAGE "\":%s}"), + mqtt_data, sensor, GetDT(rfsns_theo_v2_t2[i].time).c_str(), voltage); + } + } else { + float temp = ConvertTemp((float)rfsns_theo_v2_t2[i].temp / 100); + char temperature[10]; + dtostrfd(temp, Settings.flag2.temperature_resolution, temperature); + float humi = (float)rfsns_theo_v2_t2[i].hum / 100; + char humidity[10]; + dtostrfd(humi, Settings.flag2.humidity_resolution, humidity); + + if (json) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_HUMIDITY "\":%s,\"" D_JSON_VOLTAGE "\":%s}"), + mqtt_data, sensor, temperature, humidity, voltage); + if ((0 == tele_period) && !sensor_once) { +#ifdef USE_DOMOTICZ + DomoticzTempHumSensor(temperature, humidity); +#endif // USE_DOMOTICZ +#ifdef USE_KNX + KnxSensor(KNX_TEMPERATURE, temp); + KnxSensor(KNX_HUMIDITY, humi); +#endif // USE_KNX + sensor_once = true; + } +#ifdef USE_WEBSERVER + } else { + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TEMP, mqtt_data, sensor, temperature, TempUnit()); + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_HUM, mqtt_data, sensor, humidity); +#endif // USE_WEBSERVER + } + } + } + } +} + +#endif // USE_THEO_V2 ************************************************************************ + +#ifdef USE_ALECTO_V2 +/*********************************************************************************************\ + * Alecto V2 protocol + * Dit protocol zorgt voor ontvangst van Alecto weerstation buitensensoren + * + * Auteur : Nodo-team (Martinus van den Broek) www.nodo-domotica.nl + * Support ACH2010 en code optimalisatie door forumlid: Arendst + * Support : www.nodo-domotica.nl + * Datum : 25 Jan 2013 + * Versie : 1.3 + ********************************************************************************************** + * Technische informatie: + * DKW2012 Message Format: (11 Bytes, 88 bits): + * AAAAAAAA AAAABBBB BBBB__CC CCCCCCCC DDDDDDDD EEEEEEEE FFFFFFFF GGGGGGGG GGGGGGGG HHHHHHHH IIIIIIII + * Temperature Humidity Windspd_ Windgust Rain____ ________ Winddir Checksum + * A = start/unknown, first 8 bits are always 11111111 + * B = Rolling code + * C = Temperature (10 bit value with -400 base) + * D = Humidity + * E = windspeed (* 0.3 m/s, correction for webapp = 3600/1000 * 0.3 * 100 = 108)) + * F = windgust (* 0.3 m/s, correction for webapp = 3600/1000 * 0.3 * 100 = 108)) + * G = Rain ( * 0.3 mm) + * H = winddirection (0 = north, 4 = east, 8 = south 12 = west) + * I = Checksum, calculation is still under investigation + * + * WS3000 and ACH2010 systems have no winddirection, message format is 8 bit shorter + * Message Format: (10 Bytes, 80 bits): + * AAAAAAAA AAAABBBB BBBB__CC CCCCCCCC DDDDDDDD EEEEEEEE FFFFFFFF GGGGGGGG GGGGGGGG HHHHHHHH + * Temperature Humidity Windspd_ Windgust Rain____ ________ Checksum + * + * DCF Time Message Format: (NOT DECODED!) + * AAAAAAAA BBBBCCCC DDDDDDDD EFFFFFFF GGGGGGGG HHHHHHHH IIIIIIII JJJJJJJJ KKKKKKKK LLLLLLLL MMMMMMMM + * 11 Hours Minutes Seconds Year Month Day ? Checksum + * B = 11 = DCF + * C = ? + * D = ? + * E = ? + * F = Hours BCD format (7 bits only for this byte, MSB could be '1') + * G = Minutes BCD format + * H = Seconds BCD format + * I = Year BCD format (only two digits!) + * J = Month BCD format + * K = Day BCD format + * L = ? + * M = Checksum +\*********************************************************************************************/ + +#define RFSNS_DKW2012_PULSECOUNT 176 +#define RFSNS_ACH2010_MIN_PULSECOUNT 160 // reduce this value (144?) in case of bad reception +#define RFSNS_ACH2010_MAX_PULSECOUNT 160 + +typedef struct { + uint32_t time; + float temp; + float rain; + float wind; + float gust; + uint8_t type; + uint8_t humi; + uint8_t wdir; +} alecto_v2_t; + +alecto_v2_t rfsns_alecto_v2; + +uint16_t rfsns_alecto_rain_base = 0; +//unsigned long rfsns_alecto_time = 60000; + +boolean RfSnsAnalyzeAlectov2() +{ + if (!(((rfsns_raw_signal.Number >= RFSNS_ACH2010_MIN_PULSECOUNT) && + (rfsns_raw_signal.Number <= RFSNS_ACH2010_MAX_PULSECOUNT)) || (rfsns_raw_signal.Number == RFSNS_DKW2012_PULSECOUNT))) { return false; } + + byte c = 0; + byte rfbit; + byte data[9]; + byte msgtype = 0; + byte rc = 0; + int temp; + byte checksum = 0; + byte checksumcalc = 0; + byte maxidx = 8; + unsigned long atime; + float factor; + char buf1[16]; + + if (rfsns_raw_signal.Number > RFSNS_ACH2010_MAX_PULSECOUNT) { maxidx = 9; } + // Get message back to front as the header is almost never received complete for ACH2010 + byte idx = maxidx; + for (byte x = rfsns_raw_signal.Number; x > 0; x = x-2) { + if (rfsns_raw_signal.Pulses[x-1] * rfsns_raw_signal.Multiply < 0x300) { + rfbit = 0x80; + } else { + rfbit = 0; + } + data[idx] = (data[idx] >> 1) | rfbit; + c++; + if (c == 8) { + if (idx == 0) { break; } + c = 0; + idx--; + } + } + + checksum = data[maxidx]; + checksumcalc = RfSnsAlectoCRC8(data, maxidx); + + msgtype = (data[0] >> 4) & 0xf; + rc = (data[0] << 4) | (data[1] >> 4); + + if (checksum != checksumcalc) { return false; } + if ((msgtype != 10) && (msgtype != 5)) { return true; } + + rfsns_raw_signal.Repeats = 1; // het is een herhalend signaal. Bij ontvangst herhalingen onderdukken + + factor = 1.22; // (1.08) +// atime = rfsns_raw_signal.Time - rfsns_alecto_time; +// if ((atime > 10000) && (atime < 60000)) factor = (float)60000 / atime; +// rfsns_alecto_time = rfsns_raw_signal.Time; +// Serial.printf("atime %d, rfsns_alecto_time %d\n", atime, rfsns_alecto_time); + + rfsns_alecto_v2.time = LocalTime(); + rfsns_alecto_v2.type = (rfsns_raw_signal.Number == RFSNS_DKW2012_PULSECOUNT); + rfsns_alecto_v2.temp = (float)(((data[1] & 0x3) * 256 + data[2]) - 400) / 10; + rfsns_alecto_v2.humi = data[3]; + uint16_t rain = (data[6] * 256) + data[7]; + // check if rain unit has been reset! + if (rain < rfsns_alecto_rain_base) { rfsns_alecto_rain_base = rain; } + if (rfsns_alecto_rain_base > 0) { + rfsns_alecto_v2.rain += ((float)rain - rfsns_alecto_rain_base) * 0.30; + } + rfsns_alecto_rain_base = rain; + rfsns_alecto_v2.wind = (float)data[4] * factor; + rfsns_alecto_v2.gust = (float)data[5] * factor; + if (rfsns_alecto_v2.type) { + rfsns_alecto_v2.wdir = data[8] & 0xf; + } + + snprintf_P(log_data, sizeof(log_data), PSTR("RFS: AlectoV2, ChkCalc %d, Chksum %d, rc %d, Temp %d, Hum %d, Rain %d, Wind %d, Gust %d, Dir %d, Factor %s"), + checksumcalc, checksum, rc, ((data[1] & 0x3) * 256 + data[2]) - 400, data[3], (data[6] * 256) + data[7], data[4], data[5], data[8] & 0xf, dtostrfd(factor, 3, buf1)); + AddLog(LOG_LEVEL_DEBUG); + + return true; +} + +void RfSnsAlectoResetRain(void) +{ + if ((RtcTime.hour == 0) && (RtcTime.minute == 0) && (RtcTime.second == 5)) { + rfsns_alecto_v2.rain = 0; // Reset Rain + } +} + +/*********************************************************************************************\ + * Calculates CRC-8 checksum + * reference http://lucsmall.com/2012/04/29/weather-station-hacking-part-2/ + * http://lucsmall.com/2012/04/30/weather-station-hacking-part-3/ + * https://github.com/lucsmall/WH2-Weather-Sensor-Library-for-Arduino/blob/master/WeatherSensorWH2.cpp + \*********************************************************************************************/ +uint8_t RfSnsAlectoCRC8(uint8_t *addr, uint8_t len) +{ + uint8_t crc = 0; + while (len--) { + uint8_t inbyte = *addr++; + for (uint8_t i = 8; i; i--) { + uint8_t mix = (crc ^ inbyte) & 0x80; + crc <<= 1; + if (mix) { crc ^= 0x31; } + inbyte <<= 1; + } + } + return crc; +} + +void RfSnsAlectoV2Show(boolean json) +{ + if (rfsns_alecto_v2.time) { + char sensor[10]; + snprintf_P(sensor, sizeof(sensor), PSTR("AlectoV2")); + + if (rfsns_alecto_v2.time < LocalTime() - RFSNS_VALID_WINDOW) { + if (json) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_RFRECEIVED "\":\"%s\"}"), + mqtt_data, sensor, GetDT(rfsns_alecto_v2.time).c_str()); + } + } else { + float temp = ConvertTemp(rfsns_alecto_v2.temp); + char temperature[10]; + dtostrfd(temp, Settings.flag2.temperature_resolution, temperature); + float humi = (float)rfsns_alecto_v2.humi; + char humidity[10]; + dtostrfd(humi, Settings.flag2.humidity_resolution, humidity); + char rain[10]; + dtostrfd(rfsns_alecto_v2.rain, 2, rain); + char wind[10]; + dtostrfd(rfsns_alecto_v2.wind, 2, wind); + char gust[10]; + dtostrfd(rfsns_alecto_v2.gust, 2, gust); + + if (json) { + snprintf_P(mqtt_data, sizeof(mqtt_data), PSTR("%s,\"%s\":{\"" D_JSON_TEMPERATURE "\":%s,\"" D_JSON_HUMIDITY "\":%s, \"Rain\":%s,\"Wind\":%s,\"Gust\":%s}"), + mqtt_data, sensor, temperature, humidity, rain, wind, gust); + if (0 == tele_period) { +#ifdef USE_DOMOTICZ + DomoticzTempHumSensor(temperature, humidity); +#endif // USE_DOMOTICZ +#ifdef USE_KNX +// KnxSensor(KNX_TEMPERATURE, temp); +// KnxSensor(KNX_HUMIDITY, humi); +#endif // USE_KNX + } +#ifdef USE_WEBSERVER + } else { + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_TEMP, mqtt_data, sensor, temperature, TempUnit()); + snprintf_P(mqtt_data, sizeof(mqtt_data), HTTP_SNS_HUM, mqtt_data, sensor, humidity); +#endif // USE_WEBSERVER + } + } + } +} +#endif // USE_ALECTO_V2 ********************************************************************** + +void RfSnsInit(void) +{ + rfsns_rf_bit = digitalPinToBitMask(pin[GPIO_RF_SENSOR]); + rfsns_rf_port = digitalPinToPort(pin[GPIO_RF_SENSOR]); + pinMode(pin[GPIO_RF_SENSOR], INPUT); +} + +void RfSnsAnalyzeRawSignal(void) +{ + snprintf_P(log_data, sizeof(log_data), PSTR("RFS: Pulses %d"), (int)rfsns_raw_signal.Number); + AddLog(LOG_LEVEL_DEBUG); + +// if (Settings.flag3.rf_type) { +#ifdef USE_THEO_V2 + RfSnsAnalyzeTheov2(); +#endif +// } else { +#ifdef USE_ALECTO_V2 + RfSnsAnalyzeAlectov2(); +#endif +// } +} + +void RfSnsEverySecond(void) +{ +#ifdef USE_ALECTO_V2 + RfSnsAlectoResetRain(); +#endif +} + +void RfSnsShow(boolean json) +{ +#ifdef USE_THEO_V2 + RfSnsTheoV2Show(json); +#endif + +#ifdef USE_ALECTO_V2 + RfSnsAlectoV2Show(json); +#endif +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +boolean Xsns37(byte function) +{ + boolean result = false; + + if (pin[GPIO_RF_SENSOR] < 99) { + switch (function) { + case FUNC_INIT: + RfSnsInit(); + break; + case FUNC_LOOP: + if ((*portInputRegister(rfsns_rf_port) &rfsns_rf_bit) == rfsns_rf_bit) { + if (RfSnsFetchSignal(pin[GPIO_RF_SENSOR], HIGH)) { + RfSnsAnalyzeRawSignal(); + } + } + sleep = 0; + break; + case FUNC_EVERY_SECOND: + RfSnsEverySecond(); + break; + case FUNC_JSON_APPEND: + RfSnsShow(1); + break; +#ifdef USE_WEBSERVER + case FUNC_WEB_APPEND: + RfSnsShow(0); + break; +#endif // USE_WEBSERVER + } + } + return result; +} + +#endif // USE_RF_SENSOR diff --git a/tools/decode-status.py b/tools/decode-status.py index 3de4dfca3..fa108bc02 100644 --- a/tools/decode-status.py +++ b/tools/decode-status.py @@ -134,8 +134,8 @@ a_features = [[ "USE_MCP230xx","USE_MPR121","USE_CCS811","USE_MPU6050", "USE_MCP230xx_OUTPUT","USE_MCP230xx_DISPLAYOUTPUT","USE_HLW8012","USE_CSE7766", "USE_MCP39F501","USE_PZEM_AC","USE_DS3231","USE_HX711", - "USE_PZEM_DC","USE_TX20_WIND_SENSOR","USE_MGC3130","", - "","","","", + "USE_PZEM_DC","USE_TX20_WIND_SENSOR","USE_MGC3130","USE_RF_SENSOR", + "USE_THEO_V2","USE_ALECTO_V2","","", "","","","", "","","","", "","","",""]]