From 5d9428e568debde4862dc056d68a0a0aa0f6b775 Mon Sep 17 00:00:00 2001 From: Totoo Date: Wed, 24 Jul 2024 11:53:09 +0200 Subject: [PATCH] Weather station update (#2209) * Acurite609txc fix * Added Kedsum * Add auriol 5in1 * prev was: FPW_Acurite5in1, this is EmosE601x * Remove BTN from weather Saved flash space by creating chaos. Fix EmosE601 --- .../application/apps/ui_weatherstation.cpp | 7 +- firmware/baseband/fprotos/w-acurite592txr.hpp | 1 - firmware/baseband/fprotos/w-acurite5in1.hpp | 149 ++++++++++++++++++ firmware/baseband/fprotos/w-acurite606tx.hpp | 1 - firmware/baseband/fprotos/w-acurite609tx.hpp | 22 +-- firmware/baseband/fprotos/w-acurite986.hpp | 1 - firmware/baseband/fprotos/w-ambient.hpp | 3 +- firmware/baseband/fprotos/w-auriol-ahfl.hpp | 2 +- firmware/baseband/fprotos/w-auriol-th.hpp | 1 - firmware/baseband/fprotos/w-emose601x.hpp | 146 +++++++++++++++++ firmware/baseband/fprotos/w-gt-wt-02.hpp | 2 +- firmware/baseband/fprotos/w-gt-wt-03.hpp | 2 +- firmware/baseband/fprotos/w-infactory.hpp | 1 - firmware/baseband/fprotos/w-kedsum.hpp | 146 +++++++++++++++++ firmware/baseband/fprotos/w-lacrosse-tx.hpp | 1 - .../fprotos/w-lacrosse-tx141thbv2.hpp | 2 +- firmware/baseband/fprotos/w-nexus-th.hpp | 1 - firmware/baseband/fprotos/w-oregon2.hpp | 2 +- firmware/baseband/fprotos/w-oregon3.hpp | 2 +- firmware/baseband/fprotos/w-oregonv1.hpp | 3 +- firmware/baseband/fprotos/w-thermoprotx4.hpp | 2 +- firmware/baseband/fprotos/w-tx8300.hpp | 1 - firmware/baseband/fprotos/w-wendox-w6726.hpp | 2 - firmware/baseband/fprotos/weatherbase.hpp | 27 ++-- firmware/baseband/fprotos/weatherprotos.hpp | 9 +- firmware/baseband/fprotos/weathertypes.hpp | 8 +- firmware/common/message.hpp | 7 +- 27 files changed, 492 insertions(+), 59 deletions(-) create mode 100644 firmware/baseband/fprotos/w-acurite5in1.hpp create mode 100644 firmware/baseband/fprotos/w-emose601x.hpp create mode 100644 firmware/baseband/fprotos/w-kedsum.hpp diff --git a/firmware/application/apps/ui_weatherstation.cpp b/firmware/application/apps/ui_weatherstation.cpp index 2b3cc98e7..dbf9bea94 100644 --- a/firmware/application/apps/ui_weatherstation.cpp +++ b/firmware/application/apps/ui_weatherstation.cpp @@ -203,7 +203,12 @@ const char* WeatherView::getWeatherSensorTypeName(FPROTO_WEATHER_SENSOR type) { return "Wendox W6726"; case FPW_Acurite986: return "Acurite986"; - + case FPW_KEDSUM: + return "Kedsum"; + case FPW_Acurite5in1: + return "Acurite5in1"; + case FPW_EmosE601x: + return "EmosE601x"; case FPW_Invalid: default: return "Unknown"; diff --git a/firmware/baseband/fprotos/w-acurite592txr.hpp b/firmware/baseband/fprotos/w-acurite592txr.hpp index 5727b7101..5ca4cf521 100644 --- a/firmware/baseband/fprotos/w-acurite592txr.hpp +++ b/firmware/baseband/fprotos/w-acurite592txr.hpp @@ -148,7 +148,6 @@ class FProtoWeatherAcurite592TXR : public FProtoWeatherBase { humidity = (data >> 24) & 0x7F; uint16_t temp_raw = ((data >> 9) & 0xF80) | ((data >> 8) & 0x7F); temp = ((float)(temp_raw)-1000) / 10.0f; - btn = WS_NO_BTN; } }; diff --git a/firmware/baseband/fprotos/w-acurite5in1.hpp b/firmware/baseband/fprotos/w-acurite5in1.hpp new file mode 100644 index 000000000..5842c90a6 --- /dev/null +++ b/firmware/baseband/fprotos/w-acurite5in1.hpp @@ -0,0 +1,149 @@ + +#ifndef __FPROTO_Acurite_5in1_H__ +#define __FPROTO_Acurite_5in1_H__ + +#include "weatherbase.hpp" + +typedef enum { + Acurite_5n1DecoderStepReset = 0, + Acurite_5n1DecoderStepCheckPreambule, + Acurite_5n1DecoderStepSaveDuration, + Acurite_5n1DecoderStepCheckDuration, +} Acurite_5n1DecoderStep; + +class FProtoWeatherAcurite5in1 : public FProtoWeatherBase { + public: + FProtoWeatherAcurite5in1() { + sensorType = FPW_Acurite5in1; + } + + void feed(bool level, uint32_t duration) { + switch (parser_step) { + case Acurite_5n1DecoderStepReset: + if ((level) && (DURATION_DIFF(duration, te_short * 3) < te_delta * 2)) { + parser_step = Acurite_5n1DecoderStepCheckPreambule; + te_last = duration; + header_count = 0; + } + break; + + case Acurite_5n1DecoderStepCheckPreambule: + if (level) { + te_last = duration; + } else { + if ((DURATION_DIFF(te_last, te_short * 3) < te_delta * 2) && + (DURATION_DIFF(duration, te_short * 3) < te_delta * 2)) { + // Found preambule + header_count++; + } else if ((header_count > 2) && (header_count < 5)) { + if ((DURATION_DIFF(te_last, te_short) < te_delta) && + (DURATION_DIFF(duration, te_long) < te_delta)) { + decode_data = 0; + decode_count_bit = 0; + subghz_protocol_blocks_add_bit(0); + parser_step = Acurite_5n1DecoderStepSaveDuration; + } else if ( + (DURATION_DIFF(te_last, te_long) < te_delta) && + (DURATION_DIFF(duration, te_short) < te_delta)) { + decode_data = 0; + decode_count_bit = 0; + subghz_protocol_blocks_add_bit(1); + parser_step = Acurite_5n1DecoderStepSaveDuration; + } else { + parser_step = Acurite_5n1DecoderStepReset; + } + } else { + parser_step = Acurite_5n1DecoderStepReset; + } + } + break; + + case Acurite_5n1DecoderStepSaveDuration: + if (level) { + te_last = duration; + parser_step = Acurite_5n1DecoderStepCheckDuration; + } else { + parser_step = Acurite_5n1DecoderStepReset; + } + break; + + case Acurite_5n1DecoderStepCheckDuration: + if (!level) { + if (duration >= ((uint32_t)te_short * 5)) { + if ((decode_count_bit == min_count_bit_for_found) && + ws_protocol_acurite_5n1_check_crc() && + ws_protocol_acurite_5n1_check_message_type()) { + data = decode_data; + data_count_bit = decode_count_bit; + ws_protocol_acurite_5n1_remote_controller(); + if (callback) callback(this); + } + decode_data = 0; + decode_count_bit = 0; + parser_step = Acurite_5n1DecoderStepReset; + break; + } else if ((DURATION_DIFF(te_last, te_short) < te_delta) && + (DURATION_DIFF(duration, te_long) < te_delta)) { + subghz_protocol_blocks_add_bit(0); + parser_step = Acurite_5n1DecoderStepSaveDuration; + } else if ( + (DURATION_DIFF(te_last, te_long) < te_delta) && + (DURATION_DIFF(duration, te_short) < te_delta)) { + subghz_protocol_blocks_add_bit(1); + parser_step = Acurite_5n1DecoderStepSaveDuration; + } else { + parser_step = Acurite_5n1DecoderStepReset; + } + } else { + parser_step = Acurite_5n1DecoderStepReset; + } + break; + } + } + + protected: + uint32_t te_short = 200; + uint32_t te_long = 400; + uint32_t te_delta = 90; + uint32_t min_count_bit_for_found = 64; + + bool ws_protocol_acurite_5n1_check_message_type() { + if (((decode_data >> 40) & 0x3F) == 0x38) { + return true; + } else { + return false; + } + } + + bool ws_protocol_acurite_5n1_check_crc() { + uint8_t msg[] = { + (uint8_t)(decode_data >> 56), + (uint8_t)(decode_data >> 48), + (uint8_t)(decode_data >> 40), + (uint8_t)(decode_data >> 32), + (uint8_t)(decode_data >> 24), + (uint8_t)(decode_data >> 16), + (uint8_t)(decode_data >> 8)}; + + if ((FProtoGeneral::subghz_protocol_blocks_add_bytes(msg, 7) == + (uint8_t)(decode_data & 0xFF)) && + (!FProtoGeneral::subghz_protocol_blocks_parity_bytes(&msg[2], 5))) { + return true; + } else { + return false; + } + } + + void ws_protocol_acurite_5n1_remote_controller() { + uint8_t channell[] = {3, 0, 2, 1}; + uint8_t channel_raw = ((data >> 62) & 0x03); + channel = channell[channel_raw]; + id = (data >> 48) & 0x3FFF; + battery_low = !((data >> 46) & 1); + humidity = (data >> 8) & 0x7F; + uint16_t temp_raw = ((data >> (24 - 7)) & 0x780) | ((data >> 16) & 0x7F); + temp = FProtoGeneral::locale_fahrenheit_to_celsius(((float)(temp_raw)-400) / 10.0f); + }; +}; + +#endif diff --git a/firmware/baseband/fprotos/w-acurite606tx.hpp b/firmware/baseband/fprotos/w-acurite606tx.hpp index 60584b270..2e3e8e6b7 100644 --- a/firmware/baseband/fprotos/w-acurite606tx.hpp +++ b/firmware/baseband/fprotos/w-acurite606tx.hpp @@ -92,7 +92,6 @@ class FProtoWeatherAcurite606TX : public FProtoWeatherBase { } else { temp = (float)((~(data >> 8) & 0x07FF) + 1) / -10.0f; } - btn = WS_NO_BTN; humidity = WS_NO_HUMIDITY; } bool ws_protocol_acurite_606tx_check() { diff --git a/firmware/baseband/fprotos/w-acurite609tx.hpp b/firmware/baseband/fprotos/w-acurite609tx.hpp index 4eff0b628..aa0a9b7b3 100644 --- a/firmware/baseband/fprotos/w-acurite609tx.hpp +++ b/firmware/baseband/fprotos/w-acurite609tx.hpp @@ -39,16 +39,11 @@ class FProtoWeatherAcurite609TX : public FProtoWeatherBase { case Acurite_609TXCDecoderStepCheckDuration: if (!level) { - if (DURATION_DIFF(te_last, te_short) < - te_delta) { - if ((DURATION_DIFF(duration, te_short) < - te_delta) || - (duration > te_long * 3)) { + if (DURATION_DIFF(te_last, te_short) < te_delta) { + if ((DURATION_DIFF(duration, te_short) < te_delta) || (duration > te_long * 3)) { // Found syncPostfix parser_step = Acurite_609TXCDecoderStepReset; - if ((decode_count_bit == - min_count_bit_for_found) && - ws_protocol_acurite_609txc_check()) { + if ((decode_count_bit == min_count_bit_for_found) && ws_protocol_acurite_609txc_check()) { data = decode_data; data_count_bit = decode_count_bit; ws_protocol_acurite_609txc_remote_controller(); @@ -56,14 +51,10 @@ class FProtoWeatherAcurite609TX : public FProtoWeatherBase { } decode_data = 0; decode_count_bit = 0; - } else if ( - DURATION_DIFF(duration, te_long) < - te_delta * 2) { + } else if (DURATION_DIFF(duration, te_long) < te_delta * 2) { subghz_protocol_blocks_add_bit(0); parser_step = Acurite_609TXCDecoderStepSaveDuration; - } else if ( - DURATION_DIFF(duration, te_long * 2) < - te_delta * 4) { + } else if (DURATION_DIFF(duration, te_long * 2) < te_delta * 4) { subghz_protocol_blocks_add_bit(1); parser_step = Acurite_609TXCDecoderStepSaveDuration; } else { @@ -81,7 +72,7 @@ class FProtoWeatherAcurite609TX : public FProtoWeatherBase { protected: uint32_t te_short = 500; - uint32_t te_long = 2000; + uint32_t te_long = 1000; uint32_t te_delta = 150; uint32_t min_count_bit_for_found = 32; @@ -97,7 +88,6 @@ class FProtoWeatherAcurite609TX : public FProtoWeatherBase { (int16_t)(((data >> 12) & 0xf000) | ((data >> 16) << 4)); temp = (temp_raw >> 4) * 0.1f; humidity = (data >> 8) & 0xff; - btn = WS_NO_BTN; } bool ws_protocol_acurite_609txc_check() { if (!decode_data) return false; diff --git a/firmware/baseband/fprotos/w-acurite986.hpp b/firmware/baseband/fprotos/w-acurite986.hpp index 3e4ba9967..21a85eae2 100644 --- a/firmware/baseband/fprotos/w-acurite986.hpp +++ b/firmware/baseband/fprotos/w-acurite986.hpp @@ -118,7 +118,6 @@ class FProtoWeatherAcurite986 : public FProtoWeatherBase { temp = -(temp & 0x7F); } temp = FProtoGeneral::locale_fahrenheit_to_celsius((float)temp); - btn = WS_NO_BTN; humidity = WS_NO_HUMIDITY; } diff --git a/firmware/baseband/fprotos/w-ambient.hpp b/firmware/baseband/fprotos/w-ambient.hpp index c01d80642..952258452 100644 --- a/firmware/baseband/fprotos/w-ambient.hpp +++ b/firmware/baseband/fprotos/w-ambient.hpp @@ -62,7 +62,7 @@ class FProtoWeatherAmbient : public FProtoWeatherBase { uint32_t te_long = 1000; uint32_t te_delta = 120; uint32_t min_count_bit_for_found = 48; - + ManchesterState manchester_saved_state = ManchesterStateMid1; bool ws_protocol_ambient_weather_check_crc() { uint8_t msg[] = { static_cast(decode_data >> 40), @@ -81,7 +81,6 @@ class FProtoWeatherAmbient : public FProtoWeatherBase { channel = ((data >> 28) & 0x07) + 1; temp = FProtoGeneral::locale_fahrenheit_to_celsius(((float)((data >> 16) & 0x0FFF) - 400.0f) / 10.0f); humidity = (data >> 8) & 0xFF; - btn = WS_NO_BTN; } }; diff --git a/firmware/baseband/fprotos/w-auriol-ahfl.hpp b/firmware/baseband/fprotos/w-auriol-ahfl.hpp index 42967e315..77088143c 100644 --- a/firmware/baseband/fprotos/w-auriol-ahfl.hpp +++ b/firmware/baseband/fprotos/w-auriol-ahfl.hpp @@ -91,7 +91,7 @@ class FProtoWeatherAuriolAhfl : public FProtoWeatherBase { void ws_protocol_auriol_ahfl_remote_controller() { id = data >> 34; battery_low = (data >> 33) & 1; - btn = (data >> 32) & 1; + // btn = (data >> 32) & 1; channel = ((data >> 30) & 0x3) + 1; if (!((data >> 29) & 1)) { temp = (float)((data >> 18) & 0x07FF) / 10.0f; diff --git a/firmware/baseband/fprotos/w-auriol-th.hpp b/firmware/baseband/fprotos/w-auriol-th.hpp index afb999556..0bed7832e 100644 --- a/firmware/baseband/fprotos/w-auriol-th.hpp +++ b/firmware/baseband/fprotos/w-auriol-th.hpp @@ -91,7 +91,6 @@ class FProtoWeatherAuriolTh : public FProtoWeatherBase { id = (data >> 31) & 0xFF; battery_low = ((data >> 30) & 1); channel = ((data >> 25) & 0x03) + 1; - btn = WS_NO_BTN; if (!((data >> 23) & 1)) { temp = (float)((data >> 13) & 0x07FF) / 10.0f; } else { diff --git a/firmware/baseband/fprotos/w-emose601x.hpp b/firmware/baseband/fprotos/w-emose601x.hpp new file mode 100644 index 000000000..44071a956 --- /dev/null +++ b/firmware/baseband/fprotos/w-emose601x.hpp @@ -0,0 +1,146 @@ + +#ifndef __FPROTO_EmosE601x_H__ +#define __FPROTO_EmosE601x_H__ + +#include "weatherbase.hpp" + +#define EmosE601xMAGIC_HEADER 0xaaa583 + +typedef enum { + EmosE601xDecoderStepReset = 0, + EmosE601xDecoderStepCheckPreamble, + EmosE601xDecoderStepSaveDuration, + EmosE601xDecoderStepCheckDuration, +} EmosE601xDecoderStep; + +class FProtoWeatherEmosE601x : public FProtoWeatherBase { + public: + FProtoWeatherEmosE601x() { + sensorType = FPW_EmosE601x; + } + + void feed(bool level, uint32_t duration) { + switch (parser_step) { + case EmosE601xDecoderStepReset: + if ((level) && (DURATION_DIFF(duration, te_short * 7) < + te_delta * 2)) { + parser_step = EmosE601xDecoderStepCheckPreamble; + te_last = duration; + } + break; + + case EmosE601xDecoderStepCheckPreamble: + if (level) { + te_last = duration; + } else { + if ((DURATION_DIFF(te_last, te_short * 7) < + te_delta * 2) && + (DURATION_DIFF(duration, te_short) < + te_delta)) { + // Found preamble + parser_step = EmosE601xDecoderStepSaveDuration; + decode_data = 0; + decode_count_bit = 0; + } else { + parser_step = EmosE601xDecoderStepReset; + } + } + break; + + case EmosE601xDecoderStepSaveDuration: + if (level) { + te_last = duration; + parser_step = EmosE601xDecoderStepCheckDuration; + } else { + parser_step = EmosE601xDecoderStepReset; + } + break; + + case EmosE601xDecoderStepCheckDuration: + if (!level) { + if ((DURATION_DIFF(te_last, te_short) < te_delta) && + (DURATION_DIFF(duration, te_long) < te_delta)) { + subghz_protocol_blocks_add_to_128_bit(0, &upper_decode_data); + parser_step = EmosE601xDecoderStepSaveDuration; + } else if ( + (DURATION_DIFF(te_last, te_long) < te_delta) && + (DURATION_DIFF(duration, te_short) < te_delta)) { + subghz_protocol_blocks_add_to_128_bit(1, &upper_decode_data); + parser_step = EmosE601xDecoderStepSaveDuration; + } else { + parser_step = EmosE601xDecoderStepReset; + break; + } + + /* Bail out if the header doesn't match */ + if (decode_count_bit == min_count_bit_for_found) { + if (decode_data != EmosE601xMAGIC_HEADER) { + parser_step = EmosE601xDecoderStepReset; + break; + } + } + + if (decode_count_bit == 120) { + data_count_bit = decode_count_bit; + if (ws_protocol_emose601x_check()) { + ws_protocol_emose601x_extract_data(); + if (callback) callback(this); + } + break; + } + } else { + parser_step = EmosE601xDecoderStepReset; + } + break; + } + } + + protected: + uint32_t te_short = 260; + uint32_t te_long = 800; + uint32_t te_delta = 100; + uint32_t min_count_bit_for_found = 24; + + uint64_t upper_decode_data = 0; + void subghz_protocol_blocks_add_to_128_bit(uint8_t bit, uint64_t* head_64_bit) { + if (++decode_count_bit > 64) { + (*head_64_bit) = ((*head_64_bit) << 1) | (decode_data >> 63); + } + decode_data = decode_data << 1 | bit; + } + bool ws_protocol_emose601x_check() { + uint8_t msg[] = { + static_cast(upper_decode_data >> 48), + static_cast(upper_decode_data >> 40), + static_cast(upper_decode_data >> 32), + static_cast(upper_decode_data >> 24), + static_cast(upper_decode_data >> 16), + static_cast(upper_decode_data >> 8), + static_cast(upper_decode_data), + static_cast(decode_data >> 56), + static_cast(decode_data >> 48), + static_cast(decode_data >> 40), + static_cast(decode_data >> 32), + static_cast(decode_data >> 24), + static_cast(decode_data >> 16)}; + + uint8_t sum = FProtoGeneral::subghz_protocol_blocks_add_bytes(msg, 13); + return (sum == ((decode_data >> 8) & 0xff)); + } + + void ws_protocol_emose601x_extract_data() { + id = (upper_decode_data >> 24) & 0xff; + battery_low = (decode_data >> 10) & 1; + int16_t temp = (decode_data >> 40) & 0xfff; + /* Handle signed data */ + if (temp & 0x800) { + temp |= 0xf000; + } + temp = (float)temp / 10.0; + humidity = (decode_data >> 32) & 0xff; + channel = (decode_data >> 52) & 0x03; + data = (decode_data >> 16); + } +}; + +#endif diff --git a/firmware/baseband/fprotos/w-gt-wt-02.hpp b/firmware/baseband/fprotos/w-gt-wt-02.hpp index 4c9541855..1120e5c35 100644 --- a/firmware/baseband/fprotos/w-gt-wt-02.hpp +++ b/firmware/baseband/fprotos/w-gt-wt-02.hpp @@ -91,7 +91,7 @@ class FProtoWeatherGTWT02 : public FProtoWeatherBase { void ws_protocol_gt_wt_02_remote_controller() { id = (data >> 29) & 0xFF; battery_low = (data >> 28) & 1; - btn = (data >> 27) & 1; + // btn = (data >> 27) & 1; channel = ((data >> 25) & 0x3) + 1; if (!((data >> 24) & 1)) { diff --git a/firmware/baseband/fprotos/w-gt-wt-03.hpp b/firmware/baseband/fprotos/w-gt-wt-03.hpp index 565b059f3..3b0b99e73 100644 --- a/firmware/baseband/fprotos/w-gt-wt-03.hpp +++ b/firmware/baseband/fprotos/w-gt-wt-03.hpp @@ -124,7 +124,7 @@ class FProtoWeatherGTWT03 : public FProtoWeatherBase { } battery_low = (data >> 24) & 1; - btn = (data >> 23) & 1; + // (data >> 23) & 1; channel = ((data >> 21) & 0x03) + 1; if (!((data >> 20) & 1)) { diff --git a/firmware/baseband/fprotos/w-infactory.hpp b/firmware/baseband/fprotos/w-infactory.hpp index bc5e23437..a035a6734 100644 --- a/firmware/baseband/fprotos/w-infactory.hpp +++ b/firmware/baseband/fprotos/w-infactory.hpp @@ -125,7 +125,6 @@ class FProtoWeatherInfactory : public FProtoWeatherBase { void ws_protocol_infactory_remote_controller() { id = data >> 32; battery_low = (data >> 26) & 1; - btn = WS_NO_BTN; temp = FProtoGeneral::locale_fahrenheit_to_celsius(((float)((data >> 12) & 0x0FFF) - 900.0f) / 10.0f); humidity = (((data >> 8) & 0x0F) * 10) + ((data >> 4) & 0x0F); // BCD, 'A0'=100%rH channel = data & 0x03; diff --git a/firmware/baseband/fprotos/w-kedsum.hpp b/firmware/baseband/fprotos/w-kedsum.hpp new file mode 100644 index 000000000..7a480bf97 --- /dev/null +++ b/firmware/baseband/fprotos/w-kedsum.hpp @@ -0,0 +1,146 @@ + +#ifndef __FPROTO_Kedsum_H__ +#define __FPROTO_Kedsum_H__ + +#include "weatherbase.hpp" + +typedef enum { + KedsumTHDecoderStepReset = 0, + KedsumTHDecoderStepCheckPreambule, + KedsumTHDecoderStepSaveDuration, + KedsumTHDecoderStepCheckDuration, +} KedsumTHDecoderStep; + +class FProtoWeatherKedsum : public FProtoWeatherBase { + public: + FProtoWeatherKedsum() { + sensorType = FPW_KEDSUM; + } + + void feed(bool level, uint32_t duration) { + switch (parser_step) { + case KedsumTHDecoderStepReset: + if ((level) && (DURATION_DIFF(duration, te_short) < te_delta)) { + parser_step = KedsumTHDecoderStepCheckPreambule; + te_last = duration; + header_count = 0; + } + break; + + case KedsumTHDecoderStepCheckPreambule: + if (level) { + te_last = duration; + } else { + if ((DURATION_DIFF(te_last, te_short) < te_delta) && + (DURATION_DIFF(duration, te_long * 4) < te_delta * 4)) { + // Found preambule + header_count++; + } else if ( + (DURATION_DIFF(te_last, te_short) < te_delta) && + (duration < (te_long * 2 + te_delta * 2))) { + // Found syncPrefix + if (header_count > 0) { + parser_step = KedsumTHDecoderStepSaveDuration; + decode_data = 0; + decode_count_bit = 0; + if ((DURATION_DIFF(te_last, te_short) < te_delta) && + (DURATION_DIFF(duration, te_long) < te_delta * 2)) { + subghz_protocol_blocks_add_bit(0); + parser_step = KedsumTHDecoderStepSaveDuration; + } else if ( + (DURATION_DIFF(te_last, te_short) < te_delta) && + (DURATION_DIFF(duration, te_long * 2) < te_delta * 4)) { + subghz_protocol_blocks_add_bit(1); + parser_step = KedsumTHDecoderStepSaveDuration; + } else { + parser_step = KedsumTHDecoderStepReset; + } + } + } else { + parser_step = KedsumTHDecoderStepReset; + } + } + break; + + case KedsumTHDecoderStepSaveDuration: + if (level) { + te_last = duration; + parser_step = KedsumTHDecoderStepCheckDuration; + } else { + parser_step = KedsumTHDecoderStepReset; + } + break; + + case KedsumTHDecoderStepCheckDuration: + if (!level) { + if (DURATION_DIFF(duration, te_long * 4) < te_delta * 4) { + // Found syncPostfix + if ((decode_count_bit == + min_count_bit_for_found) && + ws_protocol_kedsum_th_check_crc()) { + data = decode_data; + data_count_bit = decode_count_bit; + ws_protocol_kedsum_th_remote_controller(); + if (callback) callback(this); + } + decode_data = 0; + decode_count_bit = 0; + parser_step = KedsumTHDecoderStepReset; + break; + } else if ( + (DURATION_DIFF(te_last, te_short) < te_delta) && + (DURATION_DIFF(duration, te_long) < te_delta * 2)) { + subghz_protocol_blocks_add_bit(0); + parser_step = KedsumTHDecoderStepSaveDuration; + } else if ( + (DURATION_DIFF(te_last, te_short) < + te_delta) && + (DURATION_DIFF(duration, te_long * 2) < + te_delta * 4)) { + subghz_protocol_blocks_add_bit(1); + parser_step = KedsumTHDecoderStepSaveDuration; + } else { + parser_step = KedsumTHDecoderStepReset; + } + } else { + parser_step = KedsumTHDecoderStepReset; + } + break; + } + } + + protected: + uint32_t te_short = 500; + uint32_t te_long = 2000; + uint32_t te_delta = 150; + uint32_t min_count_bit_for_found = 42; + + bool ws_protocol_kedsum_th_check_crc() { + uint8_t msg[] = { + static_cast(decode_data >> 32), + static_cast(decode_data >> 24), + static_cast(decode_data >> 16), + static_cast(decode_data >> 8), + static_cast(decode_data)}; + + uint8_t crc = FProtoGeneral::subghz_protocol_blocks_crc4(msg, 4, 0x03, 0); // CRC-4 poly 0x3 init 0x0 xor last 4 bits + crc ^= msg[4] >> 4; // last nibble is only XORed + return (crc == (msg[4] & 0x0F)); + } + + void ws_protocol_kedsum_th_remote_controller() { + id = data >> 32; + if ((data >> 30) & 0x3) { + battery_low = 0; + } else { + battery_low = 1; + } + channel = ((data >> 28) & 0x3) + 1; + uint16_t temp_raw = ((data >> 16) & 0x0f) << 8 | + ((data >> 20) & 0x0f) << 4 | ((data >> 24) & 0x0f); + temp = FProtoGeneral::locale_fahrenheit_to_celsius(((float)temp_raw - 900.0f) / 10.0f); + humidity = ((data >> 8) & 0x0f) << 4 | ((data >> 12) & 0x0f); + } +}; + +#endif diff --git a/firmware/baseband/fprotos/w-lacrosse-tx.hpp b/firmware/baseband/fprotos/w-lacrosse-tx.hpp index 6bbcd93ae..da1510060 100644 --- a/firmware/baseband/fprotos/w-lacrosse-tx.hpp +++ b/firmware/baseband/fprotos/w-lacrosse-tx.hpp @@ -137,7 +137,6 @@ class FProtoWeatherLaCrosseTx : public FProtoWeatherBase { // furi_crash("WS: WSProtocolLaCrosse_TX incorrect msg_type."); } - btn = WS_NO_BTN; battery_low = WS_NO_BATT; channel = WS_NO_CHANNEL; } diff --git a/firmware/baseband/fprotos/w-lacrosse-tx141thbv2.hpp b/firmware/baseband/fprotos/w-lacrosse-tx141thbv2.hpp index 72d3c494a..5d22981e3 100644 --- a/firmware/baseband/fprotos/w-lacrosse-tx141thbv2.hpp +++ b/firmware/baseband/fprotos/w-lacrosse-tx141thbv2.hpp @@ -113,7 +113,7 @@ class FProtoWeatherLaCrosseTx141thbv2 : public FProtoWeatherBase { } id = data >> 32; battery_low = (data >> 31) & 1; - btn = (data >> 30) & 1; + // btn = (data >> 30) & 1; channel = ((data >> 28) & 0x03) + 1; temp = ((float)((data >> 16) & 0x0FFF) - 500.0f) / 10.0f; humidity = (data >> 8) & 0xFF; diff --git a/firmware/baseband/fprotos/w-nexus-th.hpp b/firmware/baseband/fprotos/w-nexus-th.hpp index a1944229d..cdea2877f 100644 --- a/firmware/baseband/fprotos/w-nexus-th.hpp +++ b/firmware/baseband/fprotos/w-nexus-th.hpp @@ -104,7 +104,6 @@ class FProtoWeatherNexusTH : public FProtoWeatherBase { id = (data >> 28) & 0xFF; battery_low = !((data >> 27) & 1); channel = ((data >> 24) & 0x03) + 1; - btn = WS_NO_BTN; if (!((data >> 23) & 1)) { temp = (float)((data >> 12) & 0x07FF) / 10.0f; } else { diff --git a/firmware/baseband/fprotos/w-oregon2.hpp b/firmware/baseband/fprotos/w-oregon2.hpp index 94bf5124c..9da650ea5 100644 --- a/firmware/baseband/fprotos/w-oregon2.hpp +++ b/firmware/baseband/fprotos/w-oregon2.hpp @@ -160,7 +160,7 @@ class FProtoWeatherOregon2 : public FProtoWeatherBase { bool prev_bit = 0; uint8_t var_bits{0}; uint32_t var_data{0}; - + ManchesterState manchester_saved_state = ManchesterStateMid1; void ws_protocol_decoder_oregon2_reset() { parser_step = Oregon2DecoderStepReset; decode_data = 0UL; diff --git a/firmware/baseband/fprotos/w-oregon3.hpp b/firmware/baseband/fprotos/w-oregon3.hpp index 629d34746..e698b7b91 100644 --- a/firmware/baseband/fprotos/w-oregon3.hpp +++ b/firmware/baseband/fprotos/w-oregon3.hpp @@ -117,7 +117,7 @@ class FProtoWeatherOregon3 : public FProtoWeatherBase { bool prev_bit = false; uint8_t var_bits{0}; uint64_t var_data{0}; - + ManchesterState manchester_saved_state = ManchesterStateMid1; ManchesterEvent level_and_duration_to_event(bool level, uint32_t duration) { bool is_long = false; diff --git a/firmware/baseband/fprotos/w-oregonv1.hpp b/firmware/baseband/fprotos/w-oregonv1.hpp index 14a34b728..6bb3a6020 100644 --- a/firmware/baseband/fprotos/w-oregonv1.hpp +++ b/firmware/baseband/fprotos/w-oregonv1.hpp @@ -137,7 +137,7 @@ class FProtoWeatherOregonV1 : public FProtoWeatherBase { uint32_t min_count_bit_for_found = 32; uint8_t first_bit{0}; - + ManchesterState manchester_saved_state = ManchesterStateMid1; bool ws_protocol_oregon_v1_check() { if (!decode_data) return false; uint64_t data = FProtoGeneral::subghz_protocol_blocks_reverse_key(decode_data, 32); @@ -159,7 +159,6 @@ class FProtoWeatherOregonV1 : public FProtoWeatherBase { temp = -temp_raw; } battery_low = !((data2 >> 23) & 1ULL); - btn = WS_NO_BTN; humidity = WS_NO_HUMIDITY; } }; diff --git a/firmware/baseband/fprotos/w-thermoprotx4.hpp b/firmware/baseband/fprotos/w-thermoprotx4.hpp index c7a3ec7c0..b2329f074 100644 --- a/firmware/baseband/fprotos/w-thermoprotx4.hpp +++ b/firmware/baseband/fprotos/w-thermoprotx4.hpp @@ -96,7 +96,7 @@ class FProtoWeatherThermoProTx4 : public FProtoWeatherBase { void ws_protocol_thermopro_tx4_remote_controller() { id = (data >> 25) & 0xFF; battery_low = (data >> 24) & 1; - btn = (data >> 23) & 1; + // btn = (data >> 23) & 1; channel = ((data >> 21) & 0x03) + 1; if (!((data >> 20) & 1)) { temp = (float)((data >> 9) & 0x07FF) / 10.0f; diff --git a/firmware/baseband/fprotos/w-tx8300.hpp b/firmware/baseband/fprotos/w-tx8300.hpp index 9852bfcae..6cca94dd4 100644 --- a/firmware/baseband/fprotos/w-tx8300.hpp +++ b/firmware/baseband/fprotos/w-tx8300.hpp @@ -120,7 +120,6 @@ class FProtoWeatherTX8300 : public FProtoWeatherBase { } void ws_protocol_tx_8300_remote_controller() { humidity = (((data >> 28) & 0x0F) * 10) + ((data >> 24) & 0x0F); - btn = WS_NO_BTN; if (!((data >> 22) & 0x03)) battery_low = 0; else diff --git a/firmware/baseband/fprotos/w-wendox-w6726.hpp b/firmware/baseband/fprotos/w-wendox-w6726.hpp index f6629c336..bc778ba5e 100644 --- a/firmware/baseband/fprotos/w-wendox-w6726.hpp +++ b/firmware/baseband/fprotos/w-wendox-w6726.hpp @@ -147,8 +147,6 @@ class FProtoWeatherWendoxW6726 : public FProtoWeatherBase { } else if (temp > 70.0f) { temp = 70.0f; } - - btn = WS_NO_BTN; humidity = WS_NO_HUMIDITY; } }; diff --git a/firmware/baseband/fprotos/weatherbase.hpp b/firmware/baseband/fprotos/weatherbase.hpp index f5be59300..77816c58d 100644 --- a/firmware/baseband/fprotos/weatherbase.hpp +++ b/firmware/baseband/fprotos/weatherbase.hpp @@ -24,12 +24,11 @@ class FProtoWeatherBase { void setCallback(SubGhzProtocolDecoderBaseRxCallback cb) { callback = cb; } // this is called when there is a hit. uint8_t getSensorType() { return sensorType; } - uint32_t getSensorId() { return id; } - float getTemp() { return temp; } uint8_t getHumidity() { return humidity; } uint8_t getBattLow() { return battery_low; } uint8_t getChannel() { return channel; } - uint8_t getButton() { return btn; } + uint32_t getSensorId() { return id; } + float getTemp() { return temp; } protected: // Helper functions to keep it as compatible with flipper as we can, so adding new protos will be easy. @@ -38,25 +37,27 @@ class FProtoWeatherBase { decode_count_bit++; } - // General weather data holder + // needs to be in this chaotic order, to save flash! + // General weather data holder uint8_t sensorType = FPW_Invalid; - uint32_t id = WS_NO_ID; - float temp = WS_NO_TEMPERATURE; uint8_t humidity = WS_NO_HUMIDITY; uint8_t battery_low = WS_NO_BATT; uint8_t channel = WS_NO_CHANNEL; - uint8_t btn = WS_NO_BTN; - + // inner logic stuff + uint8_t parser_step = 0; // inner logic stuff, also for flipper compatibility. - SubGhzProtocolDecoderBaseRxCallback callback = NULL; uint16_t header_count = 0; - uint8_t parser_step = 0; + // General weather data holder + float temp = WS_NO_TEMPERATURE; + uint32_t id = WS_NO_ID; + // inner logic stuff, + uint32_t te_last = 0; - uint64_t data = 0; uint32_t data_count_bit = 0; - uint64_t decode_data = 0; uint32_t decode_count_bit = 0; - ManchesterState manchester_saved_state = ManchesterStateMid1; + uint64_t decode_data = 0; + uint64_t data = 0; + SubGhzProtocolDecoderBaseRxCallback callback = NULL; }; #endif \ No newline at end of file diff --git a/firmware/baseband/fprotos/weatherprotos.hpp b/firmware/baseband/fprotos/weatherprotos.hpp index ab0ca1d5a..9e08bb271 100644 --- a/firmware/baseband/fprotos/weatherprotos.hpp +++ b/firmware/baseband/fprotos/weatherprotos.hpp @@ -25,6 +25,10 @@ So include here the .hpp, and add a new element to the protos vector in the cons #include "w-tx8300.hpp" #include "w-wendox-w6726.hpp" #include "w-acurite986.hpp" +#include "w-kedsum.hpp" +#include "w-acurite5in1.hpp" +#include "w-emose601x.hpp" + #include #include #include "portapack_shared_memory.hpp" @@ -55,6 +59,9 @@ class WeatherProtos : public FProtoListGeneral { protos.push_back(std::make_unique()); // 17 protos.push_back(std::make_unique()); // 18 protos.push_back(std::make_unique()); // 19 + protos.push_back(std::make_unique()); // 20 + protos.push_back(std::make_unique()); // 21 + protos.push_back(std::make_unique()); // 22 // set callback for them for (const auto& obj : protos) { @@ -65,7 +72,7 @@ class WeatherProtos : public FProtoListGeneral { static void callbackTarget(FProtoWeatherBase* instance) { WeatherDataMessage packet_message{instance->getSensorType(), instance->getSensorId(), instance->getTemp(), instance->getHumidity(), instance->getBattLow(), - instance->getChannel(), instance->getButton()}; + instance->getChannel()}; shared_memory.application_queue.push(packet_message); } diff --git a/firmware/baseband/fprotos/weathertypes.hpp b/firmware/baseband/fprotos/weathertypes.hpp index 371297058..c49357802 100644 --- a/firmware/baseband/fprotos/weathertypes.hpp +++ b/firmware/baseband/fprotos/weathertypes.hpp @@ -11,7 +11,7 @@ Also it must have a switch-case element in the getWeatherSensorTypeName() functi #define WS_NO_BATT 0xFF #define WS_NO_HUMIDITY 0xFF #define WS_NO_CHANNEL 0xFF -#define WS_NO_BTN 0xFF +// #define WS_NO_BTN 0xFF #define WS_NO_TEMPERATURE -273.0f enum FPROTO_WEATHER_SENSOR { @@ -34,7 +34,11 @@ enum FPROTO_WEATHER_SENSOR { FPW_THERMOPROTX4 = 16, FPW_TX_8300 = 17, FPW_WENDOX_W6726 = 18, - FPW_Acurite986 = 19 + FPW_Acurite986 = 19, + FPW_KEDSUM = 20, + FPW_Acurite5in1 = 21, + FPW_EmosE601x = 22 + }; #endif \ No newline at end of file diff --git a/firmware/common/message.hpp b/firmware/common/message.hpp index df2a1cc43..6cd415851 100644 --- a/firmware/common/message.hpp +++ b/firmware/common/message.hpp @@ -1267,16 +1267,14 @@ class WeatherDataMessage : public Message { float temp = -273.0f, uint8_t humidity = 0xFF, uint8_t battery_low = 0xFF, - uint8_t channel = 0xFF, - uint8_t btn = 0xFF) + uint8_t channel = 0xFF) : Message{ID::WeatherData}, sensorType{sensorType}, id{id}, temp{temp}, humidity{humidity}, battery_low{battery_low}, - channel{channel}, - btn{btn} { + channel{channel} { } uint8_t sensorType = 0; uint32_t id = 0xFFFFFFFF; @@ -1284,7 +1282,6 @@ class WeatherDataMessage : public Message { uint8_t humidity = 0xFF; uint8_t battery_low = 0xFF; uint8_t channel = 0xFF; - uint8_t btn = 0xFF; }; class SubGhzDDataMessage : public Message {