9static constexpr uint32_t PAYLOAD_TIMEOUT_MS = 20;
12 ESP_LOGCONFIG(TAG,
"Setting up HLK-FM22X...");
33 if (name.length() > HLK_FM22X_NAME_SIZE - 1) {
34 ESP_LOGE(TAG,
"enroll_face(): name too long '%s'", name.c_str());
37 ESP_LOGI(TAG,
"Starting enrollment for %s", name.c_str());
38 std::array<uint8_t, 35> data{};
40 std::copy(name.begin(), name.end(), data.begin() + 1);
49 ESP_LOGI(TAG,
"Verify face");
50 static const uint8_t DATA[] = {0, 0};
55 ESP_LOGI(TAG,
"Deleting face in slot %d", face_id);
56 const uint8_t data[] = {(uint8_t) (face_id >> 8), (uint8_t) (face_id & 0xFF)};
61 ESP_LOGI(TAG,
"Deleting all stored faces");
66 ESP_LOGD(TAG,
"Getting face count");
71 ESP_LOGI(TAG,
"Resetting module");
79 ESP_LOGV(TAG,
"Send command: 0x%.2X", command);
87 this->
write((uint8_t) (START_CODE >> 8));
88 this->
write((uint8_t) (START_CODE & 0xFF));
89 this->
write((uint8_t) command);
90 uint16_t data_size =
size;
91 this->
write((uint8_t) (data_size >> 8));
92 this->
write((uint8_t) (data_size & 0xFF));
98 for (
size_t i = 0; i <
size; i++) {
103 this->
write(checksum);
118 if ((this->
read() != (uint8_t) (START_CODE >> 8)) || (this->
read() != (uint8_t) (START_CODE & 0xFF))) {
119 ESP_LOGE(TAG,
"Invalid start code");
138 if (
millis() - start > PAYLOAD_TIMEOUT_MS) {
139 ESP_LOGE(TAG,
"Timeout waiting for payload (%u bytes)",
length);
150 size_t to_store = std::min(
static_cast<size_t>(
length), HLK_FM22X_MAX_RESPONSE_SIZE);
151 for (uint16_t idx = 0; idx <
length; ++idx) {
154 if (idx < to_store) {
159 ESP_LOGV_HEX(TAG, this->
recv_buf_.data(), to_store, HLK_FM22X_MAX_RESPONSE_SIZE,
"Recv type: 0x%.2X, data: %s",
163 if (
byte != checksum) {
164 ESP_LOGE(TAG,
"Invalid checksum for data. Calculated: 0x%.2X, Received: 0x%.2X",
checksum,
byte);
167 switch (response_type) {
175 ESP_LOGW(TAG,
"Unexpected response type: 0x%.2X", response_type);
182 ESP_LOGE(TAG,
"Empty note data");
188 ESP_LOGE(TAG,
"Invalid face note data size: %zu",
length);
194 for (int16_t &i : info) {
198 ESP_LOGV(TAG,
"Face state: status: %d, left: %d, top: %d, right: %d, bottom: %d, yaw: %d, pitch: %d, roll: %d",
199 info[0], info[1], info[2], info[3], info[4], info[5], info[6], info[7]);
200 this->
face_info_callback_.call(info[0], info[1], info[2], info[3], info[4], info[5], info[6], info[7]);
220 ESP_LOGW(TAG,
"Unhandled note: 0x%.2X", data[0]);
229 ESP_LOGE(TAG,
"Reply too short: %zu bytes",
length);
232 if (data[0] != (uint8_t) expected) {
233 ESP_LOGE(TAG,
"Unexpected response command. Expected: 0x%.2X, Received: 0x%.2X", expected, data[0]);
238 ESP_LOGE(TAG,
"Command <0x%.2X> failed. Error: 0x%.2X", data[0], data[1]);
258 if (
length < 4 + HLK_FM22X_NAME_SIZE) {
259 ESP_LOGE(TAG,
"VERIFY response too short: %zu bytes",
length);
263 const char *name_ptr =
reinterpret_cast<const char *
>(data + 4);
264 ESP_LOGD(TAG,
"Face verified. ID: %d, name: %.*s", face_id, (
int) HLK_FM22X_NAME_SIZE, name_ptr);
277 ESP_LOGI(TAG,
"Face enrolled. ID: %d, Direction: 0x%.2X", face_id,
direction);
301 ESP_LOGI(TAG,
"Deleted face");
304 ESP_LOGI(TAG,
"Deleted all faces");
307 ESP_LOGI(TAG,
"Module reset");
323 ESP_LOGCONFIG(TAG,
"HLK_FM22X:");
324 LOG_UPDATE_INTERVAL(
this);
331 ESP_LOGCONFIG(TAG,
" Current Value: %s",
void mark_failed()
Mark this component as failed.
void defer(const char *name, std::function< void()> &&f)
Defer a callback to the next loop() call with a const char* name.
void publish_state(bool new_state)
Publish a new state to the front-end.
bool state
The current state of this binary sensor. Also used as the backing storage for StatefulEntityBase.
void delete_face(int16_t face_id)
sensor::Sensor * last_face_id_sensor_
void handle_reply_(const uint8_t *data, size_t length)
text_sensor::TextSensor * last_face_name_text_sensor_
CallbackManager< void(int16_t, int16_t, int16_t, int16_t, int16_t, int16_t, int16_t, int16_t)> face_info_callback_
void enroll_face(const std::string &name, HlkFm22xFaceDirection direction)
void send_command_(HlkFm22xCommand command, const uint8_t *data=nullptr, size_t size=0)
CallbackManager< void(uint8_t)> face_scan_invalid_callback_
std::array< uint8_t, HLK_FM22X_MAX_RESPONSE_SIZE > recv_buf_
sensor::Sensor * face_count_sensor_
CallbackManager< void()> face_scan_unmatched_callback_
void set_enrolling_(bool enrolling)
CallbackManager< void(int16_t, uint8_t)> enrollment_done_callback_
CallbackManager< void(uint8_t)> enrollment_failed_callback_
sensor::Sensor * status_sensor_
text_sensor::TextSensor * version_text_sensor_
void handle_note_(const uint8_t *data, size_t length)
CallbackManager< void(int16_t, std::string)> face_scan_matched_callback_
binary_sensor::BinarySensor * enrolling_binary_sensor_
HlkFm22xCommand active_command_
void dump_config() override
void publish_state(float state)
Publish a new state to the front-end.
float get_state() const
Getter-syntax for .state.
const std::string & get_state() const
Getter-syntax for .state.
void publish_state(const std::string &state)
void discard_available()
Read and drop every byte waiting in the receive buffer.
size_t write(uint8_t data)
ESPHOME_LOG_TAG(TAG, "hlk_fm22x")
constexpr T encode_value_le(const uint8_t *bytes)
Encode a value from its constituent bytes (from least to most significant) in an array with length si...
constexpr T encode_value(const uint8_t *bytes)
Encode a value from its constituent bytes (from most to least significant) in an array with length si...
void HOT delay(uint32_t ms)
uint32_t IRAM_ATTR HOT millis()