auriol_hg0601a.c 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  1. #include "auriol_hg0601a.h"
  2. #define TAG "WSProtocolAuriol_TH"
  3. /*
  4. *
  5. Auriol HG06061A-DCF-TX sensor.
  6. Data layout:
  7. DDDDDDDD-B0-NN-TT-TTTTTTTTTT-CCCC-HHHHHHHH
  8. Exmpl.: 11110100-10-01-00-0001001100-1111-01011101
  9. - D: id, 8 bit
  10. - B: where B is the battery status: 1=OK, 0=LOW, 1 bit
  11. - 0: just zero :)
  12. - N: NN is the channel: 00=CH1, 01=CH2, 11=CH3, 2bit
  13. - T: temperature, 12 bit: 2's complement, scaled by 10
  14. - C: 4 bit: seems to be 0xf constantly, a separator between temp and humidity
  15. - H: humidity sensor, humidity is 8 bits
  16. * The sensor sends 37 bits 10 times,
  17. * the packets are ppm modulated (distance coding) with a pulse of ~500 us
  18. * followed by a short gap of ~1000 us for a 0 bit or a long ~2000 us gap for a
  19. * 1 bit, the sync gap is ~4000 us.
  20. *
  21. */
  22. #define AURIOL_TH_CONST_DATA 0b1110
  23. static const SubGhzBlockConst ws_protocol_auriol_th_const = {
  24. .te_short = 500,
  25. .te_long = 2000,
  26. .te_delta = 150,
  27. .min_count_bit_for_found = 37,
  28. };
  29. struct WSProtocolDecoderAuriol_TH {
  30. SubGhzProtocolDecoderBase base;
  31. SubGhzBlockDecoder decoder;
  32. WSBlockGeneric generic;
  33. };
  34. struct WSProtocolEncoderAuriol_TH {
  35. SubGhzProtocolEncoderBase base;
  36. SubGhzProtocolBlockEncoder encoder;
  37. WSBlockGeneric generic;
  38. };
  39. typedef enum {
  40. auriol_THDecoderStepReset = 0,
  41. auriol_THDecoderStepSaveDuration,
  42. auriol_THDecoderStepCheckDuration,
  43. } auriol_THDecoderStep;
  44. const SubGhzProtocolDecoder ws_protocol_auriol_th_decoder = {
  45. .alloc = ws_protocol_decoder_auriol_th_alloc,
  46. .free = ws_protocol_decoder_auriol_th_free,
  47. .feed = ws_protocol_decoder_auriol_th_feed,
  48. .reset = ws_protocol_decoder_auriol_th_reset,
  49. .get_hash_data = ws_protocol_decoder_auriol_th_get_hash_data,
  50. .serialize = ws_protocol_decoder_auriol_th_serialize,
  51. .deserialize = ws_protocol_decoder_auriol_th_deserialize,
  52. .get_string = ws_protocol_decoder_auriol_th_get_string,
  53. };
  54. const SubGhzProtocolEncoder ws_protocol_auriol_th_encoder = {
  55. .alloc = NULL,
  56. .free = NULL,
  57. .deserialize = NULL,
  58. .stop = NULL,
  59. .yield = NULL,
  60. };
  61. const SubGhzProtocol ws_protocol_auriol_th = {
  62. .name = WS_PROTOCOL_AURIOL_TH_NAME,
  63. .type = SubGhzProtocolWeatherStation,
  64. .flag = SubGhzProtocolFlag_433 | SubGhzProtocolFlag_315 | SubGhzProtocolFlag_868 |
  65. SubGhzProtocolFlag_AM | SubGhzProtocolFlag_Decodable,
  66. .decoder = &ws_protocol_auriol_th_decoder,
  67. .encoder = &ws_protocol_auriol_th_encoder,
  68. };
  69. void* ws_protocol_decoder_auriol_th_alloc(SubGhzEnvironment* environment) {
  70. UNUSED(environment);
  71. WSProtocolDecoderAuriol_TH* instance = malloc(sizeof(WSProtocolDecoderAuriol_TH));
  72. instance->base.protocol = &ws_protocol_auriol_th;
  73. instance->generic.protocol_name = instance->base.protocol->name;
  74. return instance;
  75. }
  76. void ws_protocol_decoder_auriol_th_free(void* context) {
  77. furi_assert(context);
  78. WSProtocolDecoderAuriol_TH* instance = context;
  79. free(instance);
  80. }
  81. void ws_protocol_decoder_auriol_th_reset(void* context) {
  82. furi_assert(context);
  83. WSProtocolDecoderAuriol_TH* instance = context;
  84. instance->decoder.parser_step = auriol_THDecoderStepReset;
  85. }
  86. static bool ws_protocol_auriol_th_check(WSProtocolDecoderAuriol_TH* instance) {
  87. uint8_t type = (instance->decoder.decode_data >> 8) & 0x0F;
  88. if((type == AURIOL_TH_CONST_DATA) && ((instance->decoder.decode_data >> 4) != 0xffffffff)) {
  89. return true;
  90. } else {
  91. return false;
  92. }
  93. return true;
  94. }
  95. /**
  96. * Analysis of received data
  97. * @param instance Pointer to a WSBlockGeneric* instance
  98. */
  99. static void ws_protocol_auriol_th_remote_controller(WSBlockGeneric* instance) {
  100. instance->id = (instance->data >> 31) & 0xFF;
  101. instance->battery_low = ((instance->data >> 30) & 1);
  102. instance->channel = ((instance->data >> 25) & 0x03) + 1;
  103. instance->btn = WS_NO_BTN;
  104. if(!((instance->data >> 23) & 1)) {
  105. instance->temp = (float)((instance->data >> 13) & 0x07FF) / 10.0f;
  106. } else {
  107. instance->temp = (float)((~(instance->data >> 13) & 0x07FF) + 1) / -10.0f;
  108. }
  109. instance->humidity = (instance->data >> 1) & 0x7F;
  110. }
  111. void ws_protocol_decoder_auriol_th_feed(void* context, bool level, uint32_t duration) {
  112. furi_assert(context);
  113. WSProtocolDecoderAuriol_TH* instance = context;
  114. switch(instance->decoder.parser_step) {
  115. case auriol_THDecoderStepReset:
  116. if((!level) && (DURATION_DIFF(duration, ws_protocol_auriol_th_const.te_short * 8) <
  117. ws_protocol_auriol_th_const.te_delta)) {
  118. //Found sync
  119. instance->decoder.parser_step = auriol_THDecoderStepSaveDuration;
  120. instance->decoder.decode_data = 0;
  121. instance->decoder.decode_count_bit = 0;
  122. }
  123. break;
  124. case auriol_THDecoderStepSaveDuration:
  125. if(level) {
  126. instance->decoder.te_last = duration;
  127. instance->decoder.parser_step = auriol_THDecoderStepCheckDuration;
  128. } else {
  129. instance->decoder.parser_step = auriol_THDecoderStepReset;
  130. }
  131. break;
  132. case auriol_THDecoderStepCheckDuration:
  133. if(!level) {
  134. if(DURATION_DIFF(duration, ws_protocol_auriol_th_const.te_short * 8) <
  135. ws_protocol_auriol_th_const.te_delta) {
  136. //Found sync
  137. instance->decoder.parser_step = auriol_THDecoderStepReset;
  138. if((instance->decoder.decode_count_bit ==
  139. ws_protocol_auriol_th_const.min_count_bit_for_found) &&
  140. ws_protocol_auriol_th_check(instance)) {
  141. instance->generic.data = instance->decoder.decode_data;
  142. instance->generic.data_count_bit = instance->decoder.decode_count_bit;
  143. ws_protocol_auriol_th_remote_controller(&instance->generic);
  144. if(instance->base.callback)
  145. instance->base.callback(&instance->base, instance->base.context);
  146. instance->decoder.parser_step = auriol_THDecoderStepCheckDuration;
  147. }
  148. instance->decoder.decode_data = 0;
  149. instance->decoder.decode_count_bit = 0;
  150. break;
  151. } else if(
  152. (DURATION_DIFF(instance->decoder.te_last, ws_protocol_auriol_th_const.te_short) <
  153. ws_protocol_auriol_th_const.te_delta) &&
  154. (DURATION_DIFF(duration, ws_protocol_auriol_th_const.te_short * 2) <
  155. ws_protocol_auriol_th_const.te_delta)) {
  156. subghz_protocol_blocks_add_bit(&instance->decoder, 0);
  157. instance->decoder.parser_step = auriol_THDecoderStepSaveDuration;
  158. } else if(
  159. (DURATION_DIFF(instance->decoder.te_last, ws_protocol_auriol_th_const.te_short) <
  160. ws_protocol_auriol_th_const.te_delta) &&
  161. (DURATION_DIFF(duration, ws_protocol_auriol_th_const.te_short * 4) <
  162. ws_protocol_auriol_th_const.te_delta * 2)) {
  163. subghz_protocol_blocks_add_bit(&instance->decoder, 1);
  164. instance->decoder.parser_step = auriol_THDecoderStepSaveDuration;
  165. } else {
  166. instance->decoder.parser_step = auriol_THDecoderStepReset;
  167. }
  168. } else {
  169. instance->decoder.parser_step = auriol_THDecoderStepReset;
  170. }
  171. break;
  172. }
  173. }
  174. uint8_t ws_protocol_decoder_auriol_th_get_hash_data(void* context) {
  175. furi_assert(context);
  176. WSProtocolDecoderAuriol_TH* instance = context;
  177. return subghz_protocol_blocks_get_hash_data(
  178. &instance->decoder, (instance->decoder.decode_count_bit / 8) + 1);
  179. }
  180. SubGhzProtocolStatus ws_protocol_decoder_auriol_th_serialize(
  181. void* context,
  182. FlipperFormat* flipper_format,
  183. SubGhzRadioPreset* preset) {
  184. furi_assert(context);
  185. WSProtocolDecoderAuriol_TH* instance = context;
  186. return ws_block_generic_serialize(&instance->generic, flipper_format, preset);
  187. }
  188. SubGhzProtocolStatus
  189. ws_protocol_decoder_auriol_th_deserialize(void* context, FlipperFormat* flipper_format) {
  190. furi_assert(context);
  191. WSProtocolDecoderAuriol_TH* instance = context;
  192. return ws_block_generic_deserialize_check_count_bit(
  193. &instance->generic, flipper_format, ws_protocol_auriol_th_const.min_count_bit_for_found);
  194. }
  195. void ws_protocol_decoder_auriol_th_get_string(void* context, FuriString* output) {
  196. furi_assert(context);
  197. WSProtocolDecoderAuriol_TH* instance = context;
  198. furi_string_printf(
  199. output,
  200. "%s %dbit\r\n"
  201. "Key:0x%lX%08lX\r\n"
  202. "Sn:0x%lX Ch:%d Bat:%d\r\n"
  203. "Temp:%3.1f C Hum:%d%%",
  204. instance->generic.protocol_name,
  205. instance->generic.data_count_bit,
  206. (uint32_t)(instance->generic.data >> 32),
  207. (uint32_t)(instance->generic.data),
  208. instance->generic.id,
  209. instance->generic.channel,
  210. instance->generic.battery_low,
  211. (double)instance->generic.temp,
  212. instance->generic.humidity);
  213. }