Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sub-GHz: Added Vauno-EN8822 weather station #262

Merged
merged 3 commits into from
Oct 20, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Filetype: Flipper SubGhz Key File
Version: 1
Frequency: 433920000
Preset: FuriHalSubGhzPresetOok270Async
Lat: 0.000000
Lon: 0.000000
Protocol: Vauno-EN8822C
Id: 64
Bit: 42
Data: 00 00 01 00 02 16 88 1D
Batt: 0
Hum: 81
Ts: 1728836876
Ch: 0
Btn: 255
Temp: 13.300000
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Filetype: Flipper SubGhz RAW File
Version: 1
Frequency: 433920000
Preset: FuriHalSubGhzPresetOok270Async
Protocol: RAW
RAW_Data: 588 -4136 546 -4150 578 -4158 546 -2096 578 -2092 592 -2068 592 -4126 578 -4144 570 -2064 580 -2092 594 -2102 564 -2168 582 -2078 582 -2112 544 -2102 572 -2096 572 -4130 574 -2114 552 -2090 594 -2064 590 -2104 560 -2094 566 -2090 564 -2092 580 -2098 566 -2096 570 -2164 578 -2090 546 -4140 578 -2104 568 -4138 578 -2078 550 -2086 594 -9092 592 -61848 200 -17582 66 -5072 130 -11038 100 -60 164 -8288 166 -2374 302 -94 166 -300 66 -18706 96 -25730 192 -66 158 -29578 64 -99962 128 -99858 96 -99908 130 -9892 164 -96 98 -89580 162 -106 76 -11000 196 -88450 506 -3900 522 -1900 522 -3878 500 -1936 482 -1958 488 -1938 500 -3906 462 -1966 482 -1950 500 -1924 502 -1958 474 -1940 480 -1960 520 -3858 512 -3878 524 -3888 464 -1968 482 -3910 478 -7792 518 -1912 502 -7802 478 -1962 476 -3902 510 -1938 500 -1938 480 -1954 504 -1936 488 -1954 476 -1960 476 -1948 478 -1964 466 -1994 446 -1970 464 -1972 480 -1954 474 -1954 482 -1970 474 -3934 446 -1958 466 -1978 480 -1956 468 -1960 472 -3900 516 -1948 478 -3908 494 -3878 508 -1938 502 -3896 482 -1950 480 -1938 514 -1924 516 -3884 484 -1940 502 -1942 480 -1958 502 -1930 506 -1938 480 -1934 516 -3860 510 -3912 488 -3888 504 -1940 486 -3876 506 -7800 526 -1928 476 -7790 512 -1942 508 -3876 486 -1918 518 -1962 482 -1954 482 -1930 498 -1958 470 -1936 490 -1962 484 -1960 476 -1932 520 -1938 490 -1928 508 -1952 478 -1940 480 -1958 500 -3892 498 -1930 484 -1960 474 -1936 496 -1934 514 -3890 508 -1906 522 -3882 478 -3916 484 -1932 506 -3888 512 -1928 502 -1928 502 -1938 492 -3920 490 -1924 510 -1928 498 -1934 480 -1954 488 -1972 462 -1964 478 -3896 484 -3902 476 -3912 484 -1944 476 -3916 498 -7784 510 -1930 504 -7796 498 -1936 518 -3864 492 -1964 482 -1950 474 -1962 470 -1954 490 -1960 478 -1952 482 -1934 520 -1934 482 -1948 482 -1944 486 -1970 448 -1976 500 -1936 480 -1964 474 -3902 484 -1960 480 -1952 482 -1962 474 -1950 486 -3914 448 -1984 450 -3916 520 -3872 490 -1942 480 -3938 448 -1970 464 -1972 482 -1964 484 -3910 484 -1938 476 -1950 516 -1926 470 -1970 514 -1906 500 -1950 506 -3876 510 -3850 524 -3896 486 -1934 518 -3870 506 -7798 512 -1912 512 -7798 516 -1918 478 -3924 458 -1956 472 -1954 506 -1936 512 -1930 474 -1968 482 -1930 504 -1940 486 -1958 482 -1960 486 -1936 486 -1936 494 -1934 516 -1912 510 -1962 474 -3882 504 -1956 478 -1938 510 -1926 500 -1924 514 -3920 450 -1970 478 -3904 488 -3896 502 -1942 486 -3912 476 -1926 508 -1940 486 -1962 474 -3920 484 -1930 512 -1944 470 -1970 470 -1948 502 -1936 478 -1962 482 -3914 484 -3878 502 -3906 472 -1968 488 -3894 498 -7774 496 -1948
8 changes: 8 additions & 0 deletions applications/debug/unit_tests/tests/subghz/subghz_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -691,6 +691,13 @@ MU_TEST(subghz_decoder_bresser_3ch_v0_test) {
"Test decoder " WS_PROTOCOL_BRESSER_3CH_NAME " v0 error\r\n");
}

MU_TEST(subghz_decoder_vauno_en8822c_test) {
mu_assert(
subghz_decoder_test(
EXT_PATH("unit_tests/subghz/vauno_en8822c.sub"), WS_PROTOCOL_VAUNO_EN8822C_NAME),
"Test decoder " WS_PROTOCOL_VAUNO_EN8822C_NAME " error\r\n");
}

//test encoders
MU_TEST(subghz_encoder_princeton_test) {
mu_assert(
Expand Down Expand Up @@ -916,6 +923,7 @@ MU_TEST_SUITE(subghz) {
MU_RUN_TEST(subghz_decoder_solight_te44_test);
MU_RUN_TEST(subghz_decoder_bresser_3ch_v1_test);
MU_RUN_TEST(subghz_decoder_bresser_3ch_v0_test);
MU_RUN_TEST(subghz_decoder_vauno_en8822c_test);

MU_RUN_TEST(subghz_encoder_princeton_test);
MU_RUN_TEST(subghz_encoder_came_test);
Expand Down
1 change: 1 addition & 0 deletions lib/subghz/protocols/protocol_items.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ const SubGhzProtocol* subghz_protocol_registry_items[] = {
&ws_protocol_kedsum_th,
&ws_protocol_emose601x,
&ws_protocol_acurite_5n1,
&ws_protocol_vauno_en8822c,
&subghz_protocol_pocsag,
&tpms_protocol_schrader_gg4,
&subghz_protocol_bin_raw,
Expand Down
1 change: 1 addition & 0 deletions lib/subghz/protocols/protocol_items.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
#include "acurite_5n1.h"
#include "solight_te44.h"
#include "bresser_3ch.h"
#include "vauno_en8822c.h"
#include "pocsag.h"
#include "schrader_gg4.h"
#include "bin_raw.h"
Expand Down
258 changes: 258 additions & 0 deletions lib/subghz/protocols/vauno_en8822c.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,258 @@
#include "vauno_en8822c.h"
#include "furi/core/log.h"
#define TAG "WSProtocolVaunoEN8822C"

/*
* Help
* https://github.com/merbanan/rtl_433/blob/master/src/devices/vauno_en8822c.c
*
* Vauno EN8822C sensor on 433.92MHz.
*
* Largely the same as Esperanza EWS, s3318p.
* @sa esperanza_ews.c s3318p.c

* List of known supported devices:
* - Vauno EN8822C-1
* - FUZHOU ESUN ELECTRONIC outdoor T21 sensor
*
* Frame structure (42 bits):
*
* Byte: 0 1 2 3 4
* Nibble: 1 2 3 4 5 6 7 8 9 10 11
* Type: IIIIIIII B?CCTTTT TTTTTTTT HHHHHHHF FFFBXXXX XX
*
* - I: Random device ID
* - C: Channel (1-3)
* - T: Temperature (Little-endian)
* - H: Humidity (Little-endian)
* - F: Flags (unknown)
* - B: Battery (1=low voltage ~<2.5V)
* - X: Checksum (6 bit nibble sum)
*
* Sample Data:
*
* [00] {42} af 0f a2 7c 01 c0 : 10101111 00001111 10100010 01111100 00000001 11
*
* - Sensor ID = 175 = 0xaf
* - Channel = 0
* - temp = -93 = 0x111110100010
* - TemperatureC = -9.3
* - hum = 62% = 0x0111110
*
* Copyright (C) 2022 Jamie Barron <gumbald@gmail.com>
*
* @m7i-org - because the ether is wavy
*
*/

static const SubGhzBlockConst ws_protocol_vauno_en8822c_const = {
.te_short = 500,
.te_long = 1940,
.te_delta = 150,
.min_count_bit_for_found = 42,
};

struct WSProtocolDecoderVaunoEN8822C {
SubGhzProtocolDecoderBase base;

SubGhzBlockDecoder decoder;
WSBlockGeneric generic;
};

struct WSProtocolEncoderVaunoEN8822C {
SubGhzProtocolEncoderBase base;

SubGhzProtocolBlockEncoder encoder;
WSBlockGeneric generic;
};

const SubGhzProtocolDecoder ws_protocol_vauno_en8822c_decoder = {
.alloc = ws_protocol_decoder_vauno_en8822c_alloc,
.free = ws_protocol_decoder_vauno_en8822c_free,

.feed = ws_protocol_decoder_vauno_en8822c_feed,
.reset = ws_protocol_decoder_vauno_en8822c_reset,

.get_hash_data = NULL,
.get_hash_data_long = ws_protocol_decoder_vauno_en8822c_get_hash_data,
.serialize = ws_protocol_decoder_vauno_en8822c_serialize,
.deserialize = ws_protocol_decoder_vauno_en8822c_deserialize,
.get_string = ws_protocol_decoder_vauno_en8822c_get_string,
.get_string_brief = NULL,
};

const SubGhzProtocolEncoder ws_protocol_vauno_en8822c_encoder = {
.alloc = NULL,
.free = NULL,

.deserialize = NULL,
.stop = NULL,
.yield = NULL,
};

const SubGhzProtocol ws_protocol_vauno_en8822c = {
.name = WS_PROTOCOL_VAUNO_EN8822C_NAME,
.type = SubGhzProtocolTypeStatic,
.flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 |
SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable | SubGhzProtocolFlag_Load |
SubGhzProtocolFlag_Save,
.filter = SubGhzProtocolFilter_Weather,
.decoder = &ws_protocol_vauno_en8822c_decoder,
.encoder = &ws_protocol_vauno_en8822c_encoder,
};

typedef enum {
VaunoEN8822CDecoderStepReset = 0,
VaunoEN8822CDecoderStepSaveDuration,
VaunoEN8822CDecoderStepCheckDuration,
} VaunoEN8822CDecoderStep;

void* ws_protocol_decoder_vauno_en8822c_alloc(SubGhzEnvironment* environment) {
UNUSED(environment);
WSProtocolDecoderVaunoEN8822C* instance = malloc(sizeof(WSProtocolDecoderVaunoEN8822C));
instance->base.protocol = &ws_protocol_vauno_en8822c;
instance->generic.protocol_name = instance->base.protocol->name;
return instance;
}

void ws_protocol_decoder_vauno_en8822c_free(void* context) {
furi_assert(context);
WSProtocolDecoderVaunoEN8822C* instance = context;
free(instance);
}

void ws_protocol_decoder_vauno_en8822c_reset(void* context) {
furi_assert(context);
WSProtocolDecoderVaunoEN8822C* instance = context;
instance->decoder.parser_step = VaunoEN8822CDecoderStepReset;
}

static bool ws_protocol_vauno_en8822c_check(WSProtocolDecoderVaunoEN8822C* instance) {
if(!instance->decoder.decode_data) return false;

// The sum of all nibbles should match the last 6 bits
uint8_t sum = 0;
for(uint8_t i = 6; i <= 38; i += 4) {
sum += ((instance->decoder.decode_data >> i) & 0x0f);
}

return sum != 0 && (sum & 0x3f) == (instance->decoder.decode_data & 0x3f);
}

/**
* Analysis of received data
* @param instance Pointer to a WSBlockGeneric* instance
*/
static void ws_protocol_vauno_en8822c_extract_data(WSBlockGeneric* instance) {
instance->id = (instance->data >> 34) & 0xff;
instance->battery_low = (instance->data >> 33) & 0x01;
instance->channel = ((instance->data >> 30) & 0x03);

int16_t temp = (instance->data >> 18) & 0x0fff;
/* Handle signed data */
if(temp & 0x0800) {
temp |= 0xf000;
}
instance->temp = (float)temp / 10.0;

instance->humidity = (instance->data >> 11) & 0x7f;
instance->btn = WS_NO_BTN;
}

void ws_protocol_decoder_vauno_en8822c_feed(void* context, bool level, uint32_t duration) {
furi_assert(context);
WSProtocolDecoderVaunoEN8822C* instance = context;

switch(instance->decoder.parser_step) {
case VaunoEN8822CDecoderStepReset:
if((!level) && DURATION_DIFF(duration, ws_protocol_vauno_en8822c_const.te_long * 4) <
ws_protocol_vauno_en8822c_const.te_delta) {
instance->decoder.parser_step = VaunoEN8822CDecoderStepSaveDuration;
instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
}
break;

case VaunoEN8822CDecoderStepSaveDuration:
if(level) {
instance->decoder.te_last = duration;
instance->decoder.parser_step = VaunoEN8822CDecoderStepCheckDuration;
} else {
instance->decoder.parser_step = VaunoEN8822CDecoderStepReset;
}
break;

case VaunoEN8822CDecoderStepCheckDuration:
if(!level) {
if(DURATION_DIFF(instance->decoder.te_last, ws_protocol_vauno_en8822c_const.te_short) <
ws_protocol_vauno_en8822c_const.te_delta) {
if(DURATION_DIFF(duration, ws_protocol_vauno_en8822c_const.te_long * 2) <
ws_protocol_vauno_en8822c_const.te_delta) {
subghz_protocol_blocks_add_bit(&instance->decoder, 1);
instance->decoder.parser_step = VaunoEN8822CDecoderStepSaveDuration;
} else if(
DURATION_DIFF(duration, ws_protocol_vauno_en8822c_const.te_long) <
ws_protocol_vauno_en8822c_const.te_delta) {
subghz_protocol_blocks_add_bit(&instance->decoder, 0);
instance->decoder.parser_step = VaunoEN8822CDecoderStepSaveDuration;
} else if(
DURATION_DIFF(duration, ws_protocol_vauno_en8822c_const.te_long * 4) <
ws_protocol_vauno_en8822c_const.te_delta) {
instance->decoder.parser_step = VaunoEN8822CDecoderStepReset;
if(instance->decoder.decode_count_bit ==
ws_protocol_vauno_en8822c_const.min_count_bit_for_found &&
ws_protocol_vauno_en8822c_check(instance)) {
instance->generic.data = instance->decoder.decode_data;
instance->generic.data_count_bit = instance->decoder.decode_count_bit;
ws_protocol_vauno_en8822c_extract_data(&instance->generic);

if(instance->base.callback) {
instance->base.callback(&instance->base, instance->base.context);
}
} else if(instance->decoder.decode_count_bit == 1) {
instance->decoder.parser_step = VaunoEN8822CDecoderStepSaveDuration;
}

instance->decoder.decode_data = 0;
instance->decoder.decode_count_bit = 0;
} else
instance->decoder.parser_step = VaunoEN8822CDecoderStepReset;
} else
instance->decoder.parser_step = VaunoEN8822CDecoderStepReset;
} else
instance->decoder.parser_step = VaunoEN8822CDecoderStepReset;
break;
}
}

uint32_t ws_protocol_decoder_vauno_en8822c_get_hash_data(void* context) {
furi_assert(context);
WSProtocolDecoderVaunoEN8822C* instance = context;
return subghz_protocol_blocks_get_hash_data_long(
&instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
}

SubGhzProtocolStatus ws_protocol_decoder_vauno_en8822c_serialize(
void* context,
FlipperFormat* flipper_format,
SubGhzRadioPreset* preset) {
furi_assert(context);
WSProtocolDecoderVaunoEN8822C* instance = context;
return ws_block_generic_serialize(&instance->generic, flipper_format, preset);
}

SubGhzProtocolStatus
ws_protocol_decoder_vauno_en8822c_deserialize(void* context, FlipperFormat* flipper_format) {
furi_assert(context);
WSProtocolDecoderVaunoEN8822C* instance = context;
return ws_block_generic_deserialize_check_count_bit(
&instance->generic,
flipper_format,
ws_protocol_vauno_en8822c_const.min_count_bit_for_found);
}

void ws_protocol_decoder_vauno_en8822c_get_string(void* context, FuriString* output) {
furi_assert(context);
WSProtocolDecoderVaunoEN8822C* instance = context;
ws_block_generic_get_string(&instance->generic, output);
}
Loading
Loading