ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
hob2hood_protocol.cpp
Go to the documentation of this file.
1#include "hob2hood_protocol.h"
2#include "esphome/core/log.h"
4
5#include <array>
6#include <cstdlib>
7
8namespace esphome::remote_base {
9
10ESPHOME_LOG_TAG(TAG, "remote.hob2hood");
11
12// A frame is 25 bits: a leading 0, then the command byte, command + 1 and command + 2. Zero bits are marks
13// and one bits are spaces; equal neighbours merge into one run of n * BIT_TIME_US plus a fixed adjustment.
14static constexpr uint8_t NBITS = 25;
15static constexpr uint32_t BIT_TIME_US = 700;
16static constexpr int32_t MARK_ADJUST_US = 300;
17static constexpr int32_t SPACE_ADJUST_US = -200;
18// The longest frame (light_off) has 18 runs
19static constexpr uint8_t MAX_RUNS = 18;
20
21static constexpr std::array<Hob2HoodCommand, 7> COMMANDS = {
24};
25// Same order as COMMANDS; the last entry is the fallback
26PROGMEM_STRING_TABLE(Hob2HoodCommandNames, "light_off", "light_on", "fan_off", "fan_low", "fan_medium", "fan_high",
27 "fan_max", "unknown");
28
29// Walks the frame of `command` as runs of equal bits. emit(is_mark, length_us, is_last) returns false to stop.
30template<typename F> static bool walk_runs(Hob2HoodCommand command, F &&emit) {
31 // Shifted so the first of the 25 bits is the top bit
32 uint32_t bits = ((uint32_t(command) << 16) | (uint32_t(uint8_t(command + 1)) << 8) | uint8_t(command + 2))
33 << (32 - NBITS);
34 int8_t run = 0;
35 for (uint8_t i = 0; i < NBITS; i++, bits <<= 1) {
36 const bool bit = (bits & 0x80000000) != 0;
37 run += bit ? 1 : -1;
38 const bool last = i == NBITS - 1;
39 if (last || (((bits << 1) & 0x80000000) != 0) != bit) {
40 const uint32_t length = BIT_TIME_US * std::abs(run) + (run < 0 ? MARK_ADJUST_US : SPACE_ADJUST_US);
41 if (!emit(run < 0, length, last))
42 return false;
43 run = 0;
44 }
45 }
46 return true;
47}
48
50 dst->set_carrier_frequency(38000);
51 dst->reserve(MAX_RUNS);
52 walk_runs(data.command, [dst](bool is_mark, uint32_t length, bool) {
53 if (is_mark) {
54 dst->mark(length);
55 } else {
56 dst->space(length);
57 }
58 return true;
59 });
60}
61
62optional<Hob2HoodData> Hob2HoodProtocol::decode(RemoteReceiveData src) {
63 for (auto command : COMMANDS) {
64 src.reset();
65 // The receiver does not capture a trailing space, so the last run only has to match when it is a mark
66 const bool matched = walk_runs(command, [&src](bool is_mark, uint32_t length, bool last) {
67 return is_mark ? src.expect_mark(length) : (last || src.expect_space(length));
68 });
69 if (matched)
70 return Hob2HoodData{command};
71 }
72 return {};
73}
74
75void Hob2HoodProtocol::dump(const Hob2HoodData &data) {
76 uint8_t index = 0;
77 while (index < COMMANDS.size() && COMMANDS[index] != data.command)
78 index++;
79 ESP_LOGI(TAG, "Received Hob2Hood: %s",
80 LOG_STR_ARG(Hob2HoodCommandNames::get_log_str(index, Hob2HoodCommandNames::LAST_INDEX)));
81}
82
83} // namespace esphome::remote_base
void encode(RemoteTransmitData *dst, const Hob2HoodData &data)
void set_carrier_frequency(uint32_t carrier_frequency)
Definition remote_base.h:31
ESPHOME_LOG_TAG(TAG, "remote.abbwelcome")
PROGMEM_STRING_TABLE(Hob2HoodCommandNames, "light_off", "light_on", "fan_off", "fan_low", "fan_medium", "fan_high", "fan_max", "unknown")
const void * src
Definition hal.h:68
static void uint32_t
uint16_t length
Definition tt21100.cpp:0