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","","",
"","","","",
"","","","",
"","","",""]]