17static constexpr uint8_t MAX_ATTEMPTS = 3;
19static constexpr uint32_t COMMAND_GAP_MS = 100;
21static constexpr uint32_t COALESCE_MS = 1000;
22static constexpr uint32_t DEFAULT_TIMEOUT_MS = 1000;
23static constexpr uint32_t LONG_TIMEOUT_MS = 2000;
24static constexpr uint32_t FACTORY_RESET_TIMEOUT_MS = 3000;
26static constexpr uint32_t RESTART_MS = 1500;
27static constexpr uint32_t GIVE_UP_BACKOFF_MS = 30000;
29static constexpr uint32_t FRAME_TIMEOUT_MS = 10000;
30static constexpr uint8_t FRAME_FIELDS = 5;
32static constexpr uint8_t LINE_END[] = {
'\r',
'\n'};
35PROGMEM_STRING_TABLE(ReadCommands,
"",
"",
"getRange",
"getTrigRange",
"getSensitivity",
"getLatency",
"getInhibit",
36 "getThrFactor",
"getMicroMotion",
"getGpioMode 1",
"",
"",
"getSWV",
"getHWV");
38static_assert(
PARAM_COUNT <= 16,
"pending_writes_ and pending_reads_ hold one bit per parameter");
39static constexpr uint16_t param_bit(
Param param) {
return static_cast<uint16_t
>(1U << param); }
42static constexpr uint16_t PERSISTENT_PARAMS =
56static_assert(
NUMBER_COUNT <= 16,
"changed_numbers_ holds one bit per number");
63static bool starts_with(
const char *str, ESPHOME_PGM_P prefix) {
64 return ESPHOME_strncmp_P(str, prefix, ESPHOME_strlen_P(prefix)) == 0;
67static bool contains(
const char *str, ESPHOME_PGM_P needle) {
68 const size_t len = ESPHOME_strlen_P(needle);
69 for (; *str !=
'\0'; str++) {
70 if (ESPHOME_strncmp_P(str, needle,
len) == 0)
77static uint8_t split_fields(
char *str,
char **fields, uint8_t max_fields) {
81 if (*str !=
',' && *str !=
'*' && *str !=
'\0')
83 const bool last = *str !=
',';
85 if (
count < max_fields)
86 fields[
count++] = start;
94static bool answer_means_done(
Operation operation,
const char *line) {
97 return contains(line, ESPHOME_PSTR(
"stopped already"));
99 return contains(line, ESPHOME_PSTR(
"started already"));
101 return starts_with(line, ESPHOME_PSTR(
"no parameter"));
107static bool parse_float(
const char *str,
float &value) {
109 value = strtof(str, &
end);
110 return end != str && *
end ==
'\0';
113static const LogString *operation_to_str(
Operation operation) {
116 return LOG_STR(
"stop");
118 return LOG_STR(
"start");
120 return LOG_STR(
"restart");
122 return LOG_STR(
"factory reset");
124 return LOG_STR(
"write");
126 return LOG_STR(
"save");
128 return LOG_STR(
"read");
130 return LOG_STR(
"none");
134DFRobotSEN0609Component::DFRobotSEN0609Component(
RunMode mode) : mode_(
mode) {
136 this->number_values_.fill(NAN);
140void DFRobotSEN0609Component::dump_config() {
145 this->mode_ == RunMode::RUN_MODE_PRESENCE ? LOG_STR_LITERAL(
"presence") : LOG_STR_LITERAL(
"speed and distance"));
146#ifdef USE_BINARY_SENSOR
147 LOG_BINARY_SENSOR(
" ",
"HasTarget", this->has_target_binary_sensor_);
150 LOG_SENSOR(
" ",
"TargetDistance", this->target_distance_sensor_);
151 LOG_SENSOR(
" ",
"TargetSpeed", this->target_speed_sensor_);
152 LOG_SENSOR(
" ",
"TargetEnergy", this->target_energy_sensor_);
154#ifdef USE_TEXT_SENSOR
155 LOG_TEXT_SENSOR(
" ",
"Version", this->version_text_sensor_);
156 LOG_TEXT_SENSOR(
" ",
"HardwareVersion", this->hardware_version_text_sensor_);
159 for (number::Number *n : this->numbers_) {
160 LOG_NUMBER(
" ",
"Number", n);
164 for (switch_::Switch *s : this->switches_) {
165 LOG_SWITCH(
" ",
"Switch", s);
169 LOG_SELECT(
" ",
"OutPinLevel", this->out_pin_level_select_);
172 LOG_BUTTON(
" ",
"FactoryReset", this->factory_reset_button_);
173 LOG_BUTTON(
" ",
"Query", this->query_button_);
174 LOG_BUTTON(
" ",
"Restart", this->restart_button_);
178void DFRobotSEN0609Component::setup() {
182 switch_::Switch *sw = this->switches_[i];
185 const bool on = sw->get_initial_state_with_restore_mode().value_or(
true);
186 this->publish_switch_(
static_cast<SwitchSetting>(i), on != sw->is_inverted());
189 this->queue_configuration_();
192void DFRobotSEN0609Component::loop() {
193 uint8_t buf[MAX_LINE_LENGTH];
194 size_t avail = this->available();
196 const size_t to_read = std::min(avail,
sizeof(buf));
197 if (!this->read_array(buf, to_read)) {
198 if (!this->read_failed_) {
199 ESP_LOGW(TAG,
"UART read failed");
201 this->read_failed_ =
true;
204 this->read_failed_ =
false;
206 for (
size_t i = 0; i < to_read; i++)
207 this->readline_(buf[i]);
209 this->run_sequencer_();
212void DFRobotSEN0609Component::readline_(uint8_t c) {
216 if (!this->line_overflow_) {
217 this->line_[this->line_pos_] =
'\0';
218 this->handle_line_(this->line_);
220 this->line_overflow_ =
false;
224 if (this->line_overflow_)
226 if (this->line_pos_ >= MAX_LINE_LENGTH - 1) {
227 ESP_LOGW(TAG,
"Line too long, dropped");
228 this->line_overflow_ =
true;
231 this->line_[this->line_pos_++] =
static_cast<char>(c);
234 this->line_[this->line_pos_] =
'\0';
235 if (ESPHOME_strcmp_P(this->line_, ESPHOME_PSTR(
"DFRobot:/>")) == 0)
240void DFRobotSEN0609Component::handle_line_(
char *line) {
243 ESP_LOGV(TAG,
"RX: %s", line);
244 if (line[0] ==
'$') {
245 this->handle_frame_(line);
249 const bool software = starts_with(line, ESPHOME_PSTR(
"SoftwareVersion:"));
250 if (software || starts_with(line, ESPHOME_PSTR(
"HardwareVersion:"))) {
251 if (this->operation_ == Operation::OPERATION_READ &&
253 this->version_received_ =
true;
254#ifdef USE_TEXT_SENSOR
261 if (this->operation_ == Operation::OPERATION_NONE) {
262 ESP_LOGD(TAG,
"Ignored line, no command pending: %s", line);
265 if (strcmp(line, this->command_) == 0) {
266 this->echo_seen_ =
true;
270 if (!this->echo_seen_) {
271 ESP_LOGD(TAG,
"Ignored line from an earlier command: %s", line);
275 if (starts_with(line, ESPHOME_PSTR(
"Done")) || answer_means_done(this->operation_, line)) {
276 this->finish_operation_();
277 }
else if (starts_with(line, ESPHOME_PSTR(
"Response "))) {
278 this->parse_response_(line + 9);
279 }
else if (contains(line, ESPHOME_PSTR(
"not stopped"))) {
281 this->stopped_ =
false;
282 this->fail_operation_();
283 }
else if (starts_with(line, ESPHOME_PSTR(
"Error")) || contains(line, ESPHOME_PSTR(
"not recognized"))) {
284 ESP_LOGW(TAG,
"Command '%s' rejected: %s", this->command_, line);
285 this->fail_operation_();
287 ESP_LOGD(TAG,
"Unexpected answer to '%s': %s", this->command_, line);
291void DFRobotSEN0609Component::handle_frame_(
char *line) {
293 if (starts_with(line, ESPHOME_PSTR(
"$DFHPD,"))) {
294 const char presence = line[7];
295 if (presence !=
'0' && presence !=
'1') {
296 this->log_bad_frame_(LOG_STR(
"Malformed presence frame"), line);
300#ifdef USE_BINARY_SENSOR
301 if (this->has_target_binary_sensor_ !=
nullptr)
302 this->has_target_binary_sensor_->publish_state(presence ==
'1');
307 if (!starts_with(line, ESPHOME_PSTR(
"$DFDMD,"))) {
308 this->log_bad_frame_(LOG_STR(
"Unknown frame"), line);
311 char *fields[FRAME_FIELDS];
315 if (split_fields(line + 7, fields, FRAME_FIELDS) < FRAME_FIELDS) {
316 this->log_bad_frame_(LOG_STR(
"Malformed target frame"), line);
320 if (!targets.has_value()) {
321 this->log_bad_frame_(LOG_STR(
"Malformed target frame"), line);
325#ifdef USE_BINARY_SENSOR
326 if (this->has_target_binary_sensor_ !=
nullptr)
327 this->has_target_binary_sensor_->publish_state(
false);
330 this->publish_target_(NAN, NAN, NAN);
335 this->log_bad_frame_(LOG_STR(
"Malformed target frame"), line);
338#ifdef USE_BINARY_SENSOR
339 if (this->has_target_binary_sensor_ !=
nullptr)
340 this->has_target_binary_sensor_->publish_state(
true);
343 this->publish_target_(distance,
speed, energy);
347void DFRobotSEN0609Component::log_bad_frame_(
const LogString *problem,
const char *line) {
349 if (this->bad_frame_logged_)
351 this->bad_frame_logged_ =
true;
352 ESP_LOGW(TAG,
"%s: %s", LOG_STR_ARG(problem), line);
363void DFRobotSEN0609Component::publish_target_(
float distance,
float speed,
float energy) {
364 publish_deduplicated(this->target_distance_sensor_, this->distance_dedup_, distance);
365 publish_deduplicated(this->target_speed_sensor_, this->speed_dedup_,
speed);
366 publish_deduplicated(this->target_energy_sensor_, this->energy_dedup_, energy);
370void DFRobotSEN0609Component::parse_response_(
const char *args) {
371 this->response_count_ = 0;
372 while (this->response_count_ < MAX_RESPONSE_VALUES) {
374 const float value = strtof(args, &
end);
376 if (
end == args || !std::isfinite(value))
378 this->response_[this->response_count_++] = value;
383void DFRobotSEN0609Component::queue_configuration_() {
386 if (this->mode_ == RunMode::RUN_MODE_PRESENCE)
394 this->pending_writes_ |= writes;
395 this->pending_reads_ |= this->wanted_reads_();
398uint16_t DFRobotSEN0609Component::wanted_reads_()
const {
400#ifdef USE_TEXT_SENSOR
401 if (this->version_text_sensor_ !=
nullptr)
403 if (this->hardware_version_text_sensor_ !=
nullptr)
408 if (this->numbers_[i] !=
nullptr)
417 if (this->out_pin_level_select_ !=
nullptr)
423void DFRobotSEN0609Component::check_frames_(
uint32_t now) {
425 if (this->mode_ != RunMode::RUN_MODE_PRESENCE || now - this->last_frame_ms_ < FRAME_TIMEOUT_MS)
428 ESP_LOGW(TAG,
"No presence frames, applying the configuration again");
429 this->status_set_warning();
430#ifdef USE_BINARY_SENSOR
431 if (this->has_target_binary_sensor_ !=
nullptr)
432 this->has_target_binary_sensor_->invalidate_state();
434 this->last_frame_ms_ = now;
435 this->queue_configuration_();
438void DFRobotSEN0609Component::request_write_(
Param param) {
440 this->pending_writes_ |= param_bit(param);
441 this->last_change_ms_ = now;
442 if (this->operation_ != Operation::OPERATION_NONE || this->stopped_)
446 const uint32_t elapsed = now - this->hold_start_ms_;
447 if (elapsed >= this->hold_ms_ || this->hold_ms_ - elapsed < COALESCE_MS)
448 this->hold_(COALESCE_MS);
451void DFRobotSEN0609Component::restart() {
452 this->restart_pending_ =
true;
453 this->hold_(COMMAND_GAP_MS);
456void DFRobotSEN0609Component::factory_reset() {
457 this->factory_reset_pending_ =
true;
458 this->hold_(COMMAND_GAP_MS);
461void DFRobotSEN0609Component::query_params() {
462 this->pending_reads_ |= this->wanted_reads_();
463 this->hold_(COMMAND_GAP_MS);
467void DFRobotSEN0609Component::control_number(NumberSetting setting,
float value) {
469 const auto &values = this->number_values_;
473 if (setting <= NUMBER_TRIGGER_RANGE &&
474 (min_range > max_range || trigger_range < min_range || trigger_range > max_range)) {
475 ESP_LOGW(TAG,
"Ranges must keep minimum <= trigger <= maximum, not written");
476 if (!std::isnan(this->number_values_[setting]))
477 this->publish_number_(setting, this->number_values_[setting]);
480 this->changed_numbers_ |= 1U << setting;
481 this->publish_number_(setting, value);
485void DFRobotSEN0609Component::forget_number_changes_(
Param param,
bool unknown) {
489 this->changed_numbers_ &= ~(1U << i);
495void DFRobotSEN0609Component::publish_number_(
NumberSetting setting,
float value) {
496 this->number_values_[setting] = value;
497 if (this->numbers_[setting] !=
nullptr)
498 this->numbers_[setting]->publish_state(value);
504 this->publish_switch_(setting,
state);
507 this->request_write_(PARAM_MICRO_MOTION);
510 this->request_write_(PARAM_RUN_LED);
513 this->request_write_(PARAM_OUT_LED);
519 this->switch_states_[setting] =
state;
520 if (this->switches_[setting] !=
nullptr)
521 this->switches_[setting]->publish_state(
state);
526void DFRobotSEN0609Component::control_out_pin_level(
size_t index) {
527 this->out_pin_level_ =
static_cast<uint8_t
>(index);
528 this->out_pin_level_select_->publish_state(index);
529 this->request_write_(PARAM_GPIO_MODE);
533void DFRobotSEN0609Component::hold_(
uint32_t duration_ms) {
535 this->hold_ms_ = duration_ms;
538void DFRobotSEN0609Component::run_sequencer_() {
540 if (this->operation_ != Operation::OPERATION_NONE) {
541 uint32_t timeout = DEFAULT_TIMEOUT_MS;
542 switch (this->operation_) {
543 case Operation::OPERATION_RESTART:
544 timeout = RESTART_MS;
546 case Operation::OPERATION_FACTORY_RESET:
547 timeout = FACTORY_RESET_TIMEOUT_MS;
549 case Operation::OPERATION_STOP:
550 case Operation::OPERATION_SAVE:
551 timeout = LONG_TIMEOUT_MS;
556 if (now - this->sent_ms_ < timeout)
558 if (this->operation_ == Operation::OPERATION_RESTART) {
559 this->finish_operation_();
561 ESP_LOGD(TAG,
"No answer to '%s'", this->command_);
562 this->fail_operation_();
566 if (now - this->hold_start_ms_ < this->hold_ms_)
569 const bool work_pending =
570 this->factory_reset_pending_ || this->save_pending_ || this->pending_writes_ != 0 || this->pending_reads_ != 0;
573 if (this->restart_pending_) {
575 operation = this->stopped_ && this->save_pending_ ? Operation::OPERATION_SAVE : Operation::OPERATION_RESTART;
576 }
else if (!work_pending) {
577 if (!this->stopped_) {
578 this->check_frames_(now);
580 if ((this->deferred_writes_ != 0 || this->deferred_save_) && now - this->deferred_ms_ >= GIVE_UP_BACKOFF_MS) {
581 this->pending_writes_ |= this->deferred_writes_;
582 this->save_pending_ = this->save_pending_ || this->deferred_save_;
583 this->deferred_writes_ = 0;
584 this->deferred_save_ =
false;
588 operation = Operation::OPERATION_START;
589 }
else if (!this->stopped_) {
590 operation = Operation::OPERATION_STOP;
591 }
else if (this->factory_reset_pending_) {
592 operation = Operation::OPERATION_FACTORY_RESET;
593 }
else if (this->pending_writes_ != 0) {
594 operation = Operation::OPERATION_WRITE;
595 param =
static_cast<Param>(__builtin_ctz(this->pending_writes_));
596 }
else if (this->save_pending_) {
598 if (now - this->last_change_ms_ < COALESCE_MS)
600 operation = Operation::OPERATION_SAVE;
602 operation = Operation::OPERATION_READ;
603 param =
static_cast<Param>(__builtin_ctz(this->pending_reads_));
606 const uint16_t bit = param_bit(param);
607 bool built = this->build_command_(operation, param);
608 if (!built && operation == Operation::OPERATION_WRITE) {
610 if ((this->paired_reads_ & bit) == 0)
611 this->pending_reads_ |= this->wanted_reads_() & bit;
612 if ((this->pending_reads_ & bit) != 0) {
613 this->paired_reads_ |= bit;
614 operation = Operation::OPERATION_READ;
615 built = this->build_command_(operation, param);
619 if (operation == Operation::OPERATION_WRITE) {
620 ESP_LOGW(TAG,
"Setting not written: the value it is paired with could not be read");
621 this->pending_writes_ &= ~bit;
622 this->paired_reads_ &= ~bit;
625 this->forget_number_changes_(param,
true);
628 ESP_LOGE(TAG,
"No command for %s of parameter %u", LOG_STR_ARG(operation_to_str(operation)),
629 static_cast<unsigned>(param));
630 this->pending_reads_ &= ~bit;
632 this->sequence_failed_ =
true;
633 this->status_set_warning();
637 if (operation == Operation::OPERATION_WRITE) {
638 this->pending_writes_ &= ~bit;
639 this->paired_reads_ &= ~bit;
641 this->forget_number_changes_(param,
false);
644 this->operation_ = operation;
645 this->param_ = param;
646 this->response_count_ = 0;
647 this->echo_seen_ =
false;
648 this->version_received_ =
false;
649 this->sent_ms_ = now;
650 ESP_LOGV(TAG,
"TX: %s", this->command_);
651 this->write_str(this->command_);
652 this->write_array(LINE_END,
sizeof(LINE_END));
656 char *buf = this->command_;
657 constexpr size_t len = MAX_COMMAND_LENGTH;
659 case Operation::OPERATION_STOP:
660 ESPHOME_strncpy_P(buf, ESPHOME_PSTR(
"sensorStop"),
len);
662 case Operation::OPERATION_START:
663 ESPHOME_strncpy_P(buf, ESPHOME_PSTR(
"sensorStart"),
len);
665 case Operation::OPERATION_RESTART:
666 ESPHOME_strncpy_P(buf, ESPHOME_PSTR(
"resetSystem"),
len);
668 case Operation::OPERATION_FACTORY_RESET:
669 ESPHOME_strncpy_P(buf, ESPHOME_PSTR(
"resetCfg"),
len);
671 case Operation::OPERATION_SAVE:
672 ESPHOME_strncpy_P(buf, ESPHOME_PSTR(
"saveConfig"),
len);
674 case Operation::OPERATION_READ:
675 ESPHOME_strncpy_P(buf,
reinterpret_cast<ESPHOME_PGM_P
>(ReadCommands::get_progmem_str(param, 0)),
len);
676 return buf[0] !=
'\0';
683 ESPHOME_snprintf_P(buf,
len, ESPHOME_PSTR(
"setRunApp %u"),
static_cast<unsigned>(this->mode_));
686 ESPHOME_strncpy_P(buf, ESPHOME_PSTR(
"setUartOutput 1 1 1 1.0"),
len);
690 ESPHOME_snprintf_P(buf,
len, ESPHOME_PSTR(
"setMicroMotion %u"),
696 const bool on = this->switch_states_[led_switch(param)];
697 this->sent_led_on_ = on;
698 ESPHOME_snprintf_P(buf,
len, ESPHOME_PSTR(
"setLedMode %u %u"), param ==
PARAM_RUN_LED ? 1U : 2U, on ? 0U : 1U);
704 ESPHOME_snprintf_P(buf,
len, ESPHOME_PSTR(
"setGpioMode 1 %u"),
static_cast<unsigned>(this->out_pin_level_));
712 const auto &values = this->number_values_;
715 ESPHOME_PGM_P
format =
nullptr;
720 format = ESPHOME_PSTR(
"setRange %.2f %.2f");
724 format = ESPHOME_PSTR(
"setTrigRange %.2f");
729 format = ESPHOME_PSTR(
"setSensitivity %.0f %.0f");
734 format = ESPHOME_PSTR(
"setLatency %.2f %.1f");
738 format = ESPHOME_PSTR(
"setInhibit %.2f");
742 format = ESPHOME_PSTR(
"setThrFactor %.0f");
748 if (std::isnan(first) || std::isnan(
second))
757bool DFRobotSEN0609Component::apply_read_(
Param param) {
758 const float *r = this->response_;
759 const uint8_t
count = this->response_count_;
761 const bool write_pending = (this->pending_writes_ & param_bit(param)) != 0;
764 auto read_number = [
this](
NumberSetting setting,
float value) {
765 if ((this->changed_numbers_ & (1U << setting)) == 0)
766 this->publish_number_(setting, value);
816 if (
count < 2 || (r[1] != 0.0f && r[1] != 1.0f))
818 if (!write_pending) {
819 this->out_pin_level_ =
static_cast<uint8_t
>(r[1]);
820 this->out_pin_level_select_->publish_state(this->out_pin_level_);
827 return this->version_received_;
833void DFRobotSEN0609Component::finish_operation_() {
834 switch (this->operation_) {
835 case Operation::OPERATION_STOP:
836 this->stopped_ =
true;
838 case Operation::OPERATION_START:
839 this->stopped_ =
false;
841 if (!this->sequence_failed_)
842 this->status_clear_warning();
843 this->sequence_failed_ =
false;
845 case Operation::OPERATION_RESTART:
847 this->restart_pending_ =
false;
848 this->stopped_ =
false;
849 this->queue_configuration_();
851 case Operation::OPERATION_FACTORY_RESET:
852 this->factory_reset_pending_ =
false;
853 this->queue_configuration_();
855 case Operation::OPERATION_WRITE:
856 this->deferred_writes_ &= ~param_bit(this->param_);
857 if (PERSISTENT_PARAMS & param_bit(this->param_))
858 this->save_pending_ =
true;
860 if (is_led(this->param_)) {
861 const uint8_t bit = 1U << led_switch(this->param_);
862 this->led_known_ |= bit;
863 this->led_on_ = this->sent_led_on_ ? (this->led_on_ | bit) : (this->led_on_ & ~bit);
867 case Operation::OPERATION_SAVE:
868 this->save_pending_ =
false;
869 this->deferred_save_ =
false;
871 case Operation::OPERATION_READ:
872 if (!this->apply_read_(this->param_)) {
873 ESP_LOGW(TAG,
"Malformed answer to '%s'", this->command_);
874 this->fail_operation_();
877 this->pending_reads_ &= ~param_bit(this->param_);
878 this->paired_reads_ &= ~param_bit(this->param_);
883 if (this->is_aux_operation_()) {
884 this->aux_attempts_ = 0;
888 this->operation_ = Operation::OPERATION_NONE;
889 this->hold_(COMMAND_GAP_MS);
892void DFRobotSEN0609Component::fail_operation_() {
893 const bool aux = this->is_aux_operation_();
894 uint8_t &attempts = aux ? this->aux_attempts_ : this->attempts_;
895 const Operation operation = this->operation_;
896 this->operation_ = Operation::OPERATION_NONE;
897 this->hold_(COMMAND_GAP_MS);
898 const bool keep_write = operation == Operation::OPERATION_WRITE && (FRAME_PARAMS & param_bit(this->param_)) != 0;
899 const bool retry = ++attempts < MAX_ATTEMPTS;
900 if (operation == Operation::OPERATION_WRITE && (retry || keep_write))
901 this->pending_writes_ |= param_bit(this->param_);
906 this->status_set_warning();
907 if (aux || keep_write) {
909 ESP_LOGW(TAG,
"Command '%s' failed, trying again later", this->command_);
910 this->hold_ms_ = GIVE_UP_BACKOFF_MS;
913 ESP_LOGW(TAG,
"Giving up on %s '%s'", LOG_STR_ARG(operation_to_str(operation)), this->command_);
914 this->sequence_failed_ =
true;
916 case Operation::OPERATION_RESTART:
917 this->restart_pending_ =
false;
919 case Operation::OPERATION_FACTORY_RESET:
920 this->factory_reset_pending_ =
false;
922 case Operation::OPERATION_WRITE:
924 if (is_led(this->param_)) {
926 if ((this->pending_writes_ & param_bit(this->param_)) != 0)
929 const uint8_t bit = 1U << led_switch(this->param_);
930 if ((this->led_known_ & bit) != 0) {
931 this->publish_switch_(led_switch(this->param_), (this->led_on_ & bit) != 0);
933 this->deferred_writes_ |= param_bit(this->param_);
940 this->pending_reads_ |= this->wanted_reads_() & param_bit(this->param_);
942 case Operation::OPERATION_SAVE:
944 this->save_pending_ =
false;
945 this->deferred_save_ =
true;
948 case Operation::OPERATION_READ:
949 this->pending_reads_ &= ~param_bit(this->param_);
BedjetMode mode
BedJet operating mode.
uint32_t IRAM_ATTR HOT get_loop_component_start_time() const
Get the cached time in milliseconds from when the current component started its loop execution.
Helper class to deduplicate items in a series of values.
bool next(T value)
Feeds the next item in the series to the deduplicator and returns false if this is a duplicate.
bool next_unknown()
Returns true if the deduplicator's value was previously known.
Base-class for all sensors.
void publish_state(float state)
Publish a new state to the front-end.
void publish_state(const std::string &state)
constexpr float BME680_GAS_LOOKUP_TABLE_1[16] PROGMEM
NumberSetting
Settings shown as number entities.
@ NUMBER_THRESHOLD_FACTOR
@ NUMBER_HOLD_SENSITIVITY
@ NUMBER_TRIGGER_SENSITIVITY
Param
Module parameters; a write or read of each is one command. Pending work runs in this order.
@ OPERATION_FACTORY_RESET
ESPHOME_LOG_TAG(TAG, "dfrobot_sen0609")
SwitchSetting
Settings shown as switch entities.
PROGMEM_STRING_TABLE(ReadCommands, "", "", "getRange", "getTrigRange", "getSensitivity", "getLatency", "getInhibit", "getThrFactor", "getMicroMotion", "getGpioMode 1", "", "", "getSWV", "getHWV")
optional< T > parse_number(const char *str)
Parse an unsigned decimal number from a null-terminated string.
optional< float > parse_float(const char *str)
Parse a decimal floating-point number; plain decimals skip the libc parser.
Application App
Global storage of Application pointer - only one Application can exist.
uint8_t progmem_read_byte(const uint8_t *addr)