mirror of
https://github.com/esphome/esphome.git
synced 2026-10-22 13:56:10 +00:00
Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2f76c9f1d6 | ||
|
|
99d063455d | ||
|
|
39d8ecf6e6 |
@@ -4,9 +4,7 @@
|
||||
#include "bedjet_child.h"
|
||||
#include "bedjet_const.h"
|
||||
#include "esphome/core/application.h"
|
||||
#include <algorithm>
|
||||
#include <cinttypes>
|
||||
#include <cstring>
|
||||
|
||||
namespace esphome::bedjet {
|
||||
|
||||
@@ -42,7 +40,7 @@ void BedJetHub::upgrade_firmware() {
|
||||
auto status = this->write_bedjet_packet_(pkt);
|
||||
|
||||
if (status) {
|
||||
ESP_LOGW(TAG, "[%s] MAGIC_UPDATE button failed, status=%d", this->get_name(), status);
|
||||
ESP_LOGW(TAG, "[%s] MAGIC_UPDATE button failed, status=%d", this->get_name().c_str(), status);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +64,7 @@ bool BedJetHub::set_fan_index(uint8_t fan_speed_index) {
|
||||
auto status = this->write_bedjet_packet_(pkt);
|
||||
|
||||
if (status) {
|
||||
ESP_LOGW(TAG, "[%s] writing fan speed failed, status=%d", this->get_name(), status);
|
||||
ESP_LOGW(TAG, "[%s] writing fan speed failed, status=%d", this->get_name().c_str(), status);
|
||||
}
|
||||
return status == 0;
|
||||
}
|
||||
@@ -84,7 +82,7 @@ bool BedJetHub::set_target_temp(float temp_c) {
|
||||
auto status = this->write_bedjet_packet_(pkt);
|
||||
|
||||
if (status) {
|
||||
ESP_LOGW(TAG, "[%s] writing target temp failed, status=%d", this->get_name(), status);
|
||||
ESP_LOGW(TAG, "[%s] writing target temp failed, status=%d", this->get_name().c_str(), status);
|
||||
}
|
||||
return status == 0;
|
||||
}
|
||||
@@ -95,7 +93,7 @@ bool BedJetHub::set_time_remaining(uint8_t hours, uint8_t mins) {
|
||||
auto status = this->write_bedjet_packet_(pkt);
|
||||
|
||||
if (status) {
|
||||
ESP_LOGW(TAG, "[%s] writing remaining runtime failed, status=%d", this->get_name(), status);
|
||||
ESP_LOGW(TAG, "[%s] writing remaining runtime failed, status=%d", this->get_name().c_str(), status);
|
||||
}
|
||||
return status == 0;
|
||||
}
|
||||
@@ -105,10 +103,11 @@ bool BedJetHub::send_button(BedjetButton button) {
|
||||
auto status = this->write_bedjet_packet_(pkt);
|
||||
|
||||
if (status) {
|
||||
ESP_LOGW(TAG, "[%s] writing button %s failed, status=%d", this->get_name(),
|
||||
ESP_LOGW(TAG, "[%s] writing button %s failed, status=%d", this->get_name().c_str(),
|
||||
LOG_STR_ARG(bedjet_button_to_string(button)), status);
|
||||
} else {
|
||||
ESP_LOGD(TAG, "[%s] writing button %s success", this->get_name(), LOG_STR_ARG(bedjet_button_to_string(button)));
|
||||
ESP_LOGD(TAG, "[%s] writing button %s success", this->get_name().c_str(),
|
||||
LOG_STR_ARG(bedjet_button_to_string(button)));
|
||||
}
|
||||
return status == 0;
|
||||
}
|
||||
@@ -126,9 +125,9 @@ uint16_t BedJetHub::get_time_remaining() {
|
||||
uint8_t BedJetHub::write_bedjet_packet_(BedjetPacket *pkt) {
|
||||
if (!this->is_connected()) {
|
||||
if (!this->parent_->enabled) {
|
||||
ESP_LOGI(TAG, "[%s] Cannot write packet: Not connected, enabled=false", this->get_name());
|
||||
ESP_LOGI(TAG, "[%s] Cannot write packet: Not connected, enabled=false", this->get_name().c_str());
|
||||
} else {
|
||||
ESP_LOGW(TAG, "[%s] Cannot write packet: Not connected", this->get_name());
|
||||
ESP_LOGW(TAG, "[%s] Cannot write packet: Not connected", this->get_name().c_str());
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
@@ -145,16 +144,16 @@ uint8_t BedJetHub::set_notify_(const bool enable) {
|
||||
status = esp_ble_gattc_register_for_notify(this->parent_->get_gattc_if(), this->parent_->get_remote_bda(),
|
||||
this->char_handle_status_);
|
||||
if (status) {
|
||||
ESP_LOGW(TAG, "[%s] esp_ble_gattc_register_for_notify failed, status=%d", this->get_name(), status);
|
||||
ESP_LOGW(TAG, "[%s] esp_ble_gattc_register_for_notify failed, status=%d", this->get_name().c_str(), status);
|
||||
}
|
||||
} else {
|
||||
status = esp_ble_gattc_unregister_for_notify(this->parent_->get_gattc_if(), this->parent_->get_remote_bda(),
|
||||
this->char_handle_status_);
|
||||
if (status) {
|
||||
ESP_LOGW(TAG, "[%s] esp_ble_gattc_unregister_for_notify failed, status=%d", this->get_name(), status);
|
||||
ESP_LOGW(TAG, "[%s] esp_ble_gattc_unregister_for_notify failed, status=%d", this->get_name().c_str(), status);
|
||||
}
|
||||
}
|
||||
ESP_LOGV(TAG, "[%s] set_notify: enable=%d; result=%d", this->get_name(), enable, status);
|
||||
ESP_LOGV(TAG, "[%s] set_notify: enable=%d; result=%d", this->get_name().c_str(), enable, status);
|
||||
return status;
|
||||
}
|
||||
|
||||
@@ -165,7 +164,7 @@ bool BedJetHub::discover_characteristics_() {
|
||||
if (!this->char_handle_cmd_) {
|
||||
chr = this->parent_->get_characteristic(BEDJET_SERVICE_UUID, BEDJET_COMMAND_UUID);
|
||||
if (chr == nullptr) {
|
||||
ESP_LOGW(TAG, "[%s] No control service found at device, not a BedJet..?", this->get_name());
|
||||
ESP_LOGW(TAG, "[%s] No control service found at device, not a BedJet..?", this->get_name().c_str());
|
||||
result = false;
|
||||
} else {
|
||||
this->char_handle_cmd_ = chr->handle;
|
||||
@@ -175,7 +174,7 @@ bool BedJetHub::discover_characteristics_() {
|
||||
if (!this->char_handle_status_) {
|
||||
chr = this->parent_->get_characteristic(BEDJET_SERVICE_UUID, BEDJET_STATUS_UUID);
|
||||
if (chr == nullptr) {
|
||||
ESP_LOGW(TAG, "[%s] No status service found at device, not a BedJet..?", this->get_name());
|
||||
ESP_LOGW(TAG, "[%s] No status service found at device, not a BedJet..?", this->get_name().c_str());
|
||||
result = false;
|
||||
} else {
|
||||
this->char_handle_status_ = chr->handle;
|
||||
@@ -205,14 +204,14 @@ bool BedJetHub::discover_characteristics_() {
|
||||
if (!this->char_handle_name_) {
|
||||
chr = this->parent_->get_characteristic(BEDJET_SERVICE_UUID, BEDJET_NAME_UUID);
|
||||
if (chr == nullptr) {
|
||||
ESP_LOGW(TAG, "[%s] No name service found at device, not a BedJet..?", this->get_name());
|
||||
ESP_LOGW(TAG, "[%s] No name service found at device, not a BedJet..?", this->get_name().c_str());
|
||||
result = false;
|
||||
} else {
|
||||
this->char_handle_name_ = chr->handle;
|
||||
auto status = esp_ble_gattc_read_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(),
|
||||
this->char_handle_name_, ESP_GATT_AUTH_REQ_NONE);
|
||||
if (status) {
|
||||
ESP_LOGI(TAG, "[%s] Unable to read name characteristic: %d", this->get_name(), status);
|
||||
ESP_LOGI(TAG, "[%s] Unable to read name characteristic: %d", this->get_name().c_str(), status);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -223,7 +222,7 @@ bool BedJetHub::discover_characteristics_() {
|
||||
" - Status char: 0x%x\n"
|
||||
" - config descriptor: 0x%x\n"
|
||||
" - Name char: 0x%x",
|
||||
this->get_name(), this->char_handle_cmd_, this->char_handle_status_, this->config_descr_status_,
|
||||
this->get_name().c_str(), this->char_handle_cmd_, this->char_handle_status_, this->config_descr_status_,
|
||||
this->char_handle_name_);
|
||||
|
||||
return result;
|
||||
@@ -242,7 +241,7 @@ void BedJetHub::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t ga
|
||||
auto result = this->discover_characteristics_();
|
||||
|
||||
if (result) {
|
||||
ESP_LOGD(TAG, "[%s] Services complete: obtained char handles.", this->get_name());
|
||||
ESP_LOGD(TAG, "[%s] Services complete: obtained char handles.", this->get_name().c_str());
|
||||
this->node_state = espbt::ClientState::ESTABLISHED;
|
||||
this->set_notify_(true);
|
||||
|
||||
@@ -254,7 +253,7 @@ void BedJetHub::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t ga
|
||||
|
||||
this->dispatch_state_(true);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "[%s] Failed discovering service characteristics.", this->get_name());
|
||||
ESP_LOGW(TAG, "[%s] Failed discovering service characteristics.", this->get_name().c_str());
|
||||
this->parent()->set_enabled(false);
|
||||
this->status_set_warning();
|
||||
this->dispatch_state_(false);
|
||||
@@ -266,15 +265,15 @@ void BedJetHub::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t ga
|
||||
if (param->write.status == ESP_GATT_INVALID_ATTR_LEN) {
|
||||
// This probably means that our hack for notify_en (8 bit vs 16 bit) didn't work right.
|
||||
// Should we try to fall back to BLEClient's way?
|
||||
ESP_LOGW(TAG, "[%s] Invalid attr length writing descr at handle 0x%04d, status=%d", this->get_name(),
|
||||
ESP_LOGW(TAG, "[%s] Invalid attr length writing descr at handle 0x%04d, status=%d", this->get_name().c_str(),
|
||||
param->write.handle, param->write.status);
|
||||
} else {
|
||||
ESP_LOGW(TAG, "[%s] Error writing descr at handle 0x%04d, status=%d", this->get_name(), param->write.handle,
|
||||
param->write.status);
|
||||
ESP_LOGW(TAG, "[%s] Error writing descr at handle 0x%04d, status=%d", this->get_name().c_str(),
|
||||
param->write.handle, param->write.status);
|
||||
}
|
||||
break;
|
||||
}
|
||||
ESP_LOGD(TAG, "[%s] Write to handle 0x%04x status=%d", this->get_name(), param->write.handle,
|
||||
ESP_LOGD(TAG, "[%s] Write to handle 0x%04x status=%d", this->get_name().c_str(), param->write.handle,
|
||||
param->write.status);
|
||||
break;
|
||||
}
|
||||
@@ -307,11 +306,9 @@ void BedJetHub::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t ga
|
||||
} else if (param->read.handle == this->char_handle_name_) {
|
||||
// The data should represent the name.
|
||||
if (param->read.status == ESP_GATT_OK && param->read.value_len > 0) {
|
||||
ESP_LOGV(TAG, "[%s] Got BedJet name: '%.*s'", this->get_name(), static_cast<int>(param->read.value_len),
|
||||
reinterpret_cast<const char *>(param->read.value));
|
||||
const size_t len = std::min<size_t>(param->read.value_len, sizeof(this->name_) - 1);
|
||||
memcpy(this->name_, param->read.value, len);
|
||||
this->name_[len] = '\0';
|
||||
std::string bedjet_name(reinterpret_cast<char const *>(param->read.value), param->read.value_len);
|
||||
ESP_LOGV(TAG, "[%s] Got BedJet name: '%s'", this->get_name().c_str(), bedjet_name.c_str());
|
||||
this->set_name_(bedjet_name);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -325,8 +322,8 @@ void BedJetHub::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t ga
|
||||
// doesn't break anything.
|
||||
|
||||
if (param->reg_for_notify.handle != this->char_handle_status_) {
|
||||
ESP_LOGW(TAG, "[%s] Register for notify on unexpected handle 0x%04x, expecting 0x%04x", this->get_name(),
|
||||
param->reg_for_notify.handle, this->char_handle_status_);
|
||||
ESP_LOGW(TAG, "[%s] Register for notify on unexpected handle 0x%04x, expecting 0x%04x",
|
||||
this->get_name().c_str(), param->reg_for_notify.handle, this->char_handle_status_);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -338,8 +335,8 @@ void BedJetHub::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t ga
|
||||
case ESP_GATTC_UNREG_FOR_NOTIFY_EVT: {
|
||||
// This event is not handled by the parent BLEClient, so we need to do this either way.
|
||||
if (param->unreg_for_notify.handle != this->char_handle_status_) {
|
||||
ESP_LOGW(TAG, "[%s] Unregister for notify on unexpected handle 0x%04x, expecting 0x%04x", this->get_name(),
|
||||
param->unreg_for_notify.handle, this->char_handle_status_);
|
||||
ESP_LOGW(TAG, "[%s] Unregister for notify on unexpected handle 0x%04x, expecting 0x%04x",
|
||||
this->get_name().c_str(), param->unreg_for_notify.handle, this->char_handle_status_);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -353,13 +350,13 @@ void BedJetHub::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t ga
|
||||
break;
|
||||
|
||||
if (param->notify.conn_id != this->parent_->get_conn_id()) {
|
||||
ESP_LOGW(TAG, "[%s] Received notify event for unexpected parent conn: expect %x, got %x", this->get_name(),
|
||||
this->parent_->get_conn_id(), param->notify.conn_id);
|
||||
ESP_LOGW(TAG, "[%s] Received notify event for unexpected parent conn: expect %x, got %x",
|
||||
this->get_name().c_str(), this->parent_->get_conn_id(), param->notify.conn_id);
|
||||
// FIXME: bug in BLEClient holding wrong conn_id.
|
||||
}
|
||||
|
||||
if (param->notify.handle != this->char_handle_status_) {
|
||||
ESP_LOGW(TAG, "[%s] Unexpected notify handle, wanted %04X, got %04X", this->get_name(),
|
||||
ESP_LOGW(TAG, "[%s] Unexpected notify handle, wanted %04X, got %04X", this->get_name().c_str(),
|
||||
this->char_handle_status_, param->notify.handle);
|
||||
break;
|
||||
}
|
||||
@@ -375,13 +372,13 @@ void BedJetHub::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t ga
|
||||
if (!this->force_refresh_ && this->codec_->compare(param->notify.value, param->notify.value_len)) {
|
||||
// If the packet is meaningfully different, trigger children as well
|
||||
this->force_refresh_ = true;
|
||||
ESP_LOGV(TAG, "[%s] Incoming packet indicates a significant change.", this->get_name());
|
||||
ESP_LOGV(TAG, "[%s] Incoming packet indicates a significant change.", this->get_name().c_str());
|
||||
}
|
||||
|
||||
if (this->last_notify_ == 0 || delta > MIN_NOTIFY_THROTTLE || this->force_refresh_) {
|
||||
// Set reentrant flag to prevent processing multiple packets.
|
||||
this->processing_ = true;
|
||||
ESP_LOGVV(TAG, "[%s] Decoding packet: last=%" PRId32 ", delta=%" PRId32 ", force=%s", this->get_name(),
|
||||
ESP_LOGVV(TAG, "[%s] Decoding packet: last=%" PRId32 ", delta=%" PRId32 ", force=%s", this->get_name().c_str(),
|
||||
this->last_notify_, delta, this->force_refresh_ ? "y" : "n");
|
||||
bool needs_extra = this->codec_->decode_notify(param->notify.value, param->notify.value_len);
|
||||
|
||||
@@ -391,7 +388,7 @@ void BedJetHub::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t ga
|
||||
auto status = esp_ble_gattc_read_char(this->parent_->get_gattc_if(), this->parent_->get_conn_id(),
|
||||
this->char_handle_status_, ESP_GATT_AUTH_REQ_NONE);
|
||||
if (status) {
|
||||
ESP_LOGI(TAG, "[%s] Unable to read extended status packet", this->get_name());
|
||||
ESP_LOGI(TAG, "[%s] Unable to read extended status packet", this->get_name().c_str());
|
||||
}
|
||||
} else {
|
||||
this->status_packet_ready_();
|
||||
@@ -400,7 +397,7 @@ void BedJetHub::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t ga
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ESP_LOGVV(TAG, "[%s] gattc unhandled event: enum=%d", this->get_name(), event);
|
||||
ESP_LOGVV(TAG, "[%s] gattc unhandled event: enum=%d", this->get_name().c_str(), event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -439,7 +436,7 @@ uint8_t BedJetHub::write_notify_config_descriptor_(bool enable) {
|
||||
ESP_LOGW(TAG, "esp_ble_gattc_write_char_descr error, status=%d", status);
|
||||
return status;
|
||||
}
|
||||
ESP_LOGD(TAG, "[%s] wrote notify=%s to status config 0x%04x, for conn %d", this->get_name(),
|
||||
ESP_LOGD(TAG, "[%s] wrote notify=%s to status config 0x%04x, for conn %d", this->get_name().c_str(),
|
||||
enable ? "true" : "false", handle, this->parent_->get_conn_id());
|
||||
return ESP_GATT_OK;
|
||||
}
|
||||
@@ -471,7 +468,7 @@ void BedJetHub::setup_time_() {
|
||||
|
||||
void BedJetHub::set_clock(uint8_t hour, uint8_t minute) {
|
||||
if (!this->is_connected()) {
|
||||
ESP_LOGV(TAG, "[%s] Not connected, cannot send time.", this->get_name());
|
||||
ESP_LOGV(TAG, "[%s] Not connected, cannot send time.", this->get_name().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -480,7 +477,7 @@ void BedJetHub::set_clock(uint8_t hour, uint8_t minute) {
|
||||
if (status) {
|
||||
ESP_LOGW(TAG, "Failed setting BedJet clock: %d", status);
|
||||
} else {
|
||||
ESP_LOGD(TAG, "[%s] BedJet clock set to: %d:%02d", this->get_name(), hour, minute);
|
||||
ESP_LOGD(TAG, "[%s] BedJet clock set to: %d:%02d", this->get_name().c_str(), hour, minute);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -498,7 +495,7 @@ void BedJetHub::dump_config() {
|
||||
"BedJet Hub '%s'\n"
|
||||
" ble_client.app_id: %d\n"
|
||||
" ble_client.conn_id: %d",
|
||||
this->get_name(), this->parent()->app_id, this->parent()->get_conn_id());
|
||||
this->get_name().c_str(), this->parent()->app_id, this->parent()->get_conn_id());
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
ESP_LOGCONFIG(TAG, " Child components (%d):", this->children_.size());
|
||||
for (auto *child : this->children_) {
|
||||
@@ -516,9 +513,10 @@ void BedJetHub::dispatch_status_() {
|
||||
auto *status = this->codec_->get_status_packet();
|
||||
|
||||
if (!this->is_connected()) {
|
||||
ESP_LOGD(TAG, "[%s] Not connected, will not send status.", this->get_name());
|
||||
ESP_LOGD(TAG, "[%s] Not connected, will not send status.", this->get_name().c_str());
|
||||
} else if (status != nullptr) {
|
||||
ESP_LOGD(TAG, "[%s] Notifying %d children of latest status @%p.", this->get_name(), this->children_.size(), status);
|
||||
ESP_LOGD(TAG, "[%s] Notifying %d children of latest status @%p.", this->get_name().c_str(), this->children_.size(),
|
||||
status);
|
||||
for (auto *child : this->children_) {
|
||||
child->on_status(status);
|
||||
}
|
||||
@@ -532,13 +530,13 @@ void BedJetHub::dispatch_status_() {
|
||||
// We can try to unregister for notifications now, and then re-register, hoping to clear it up...
|
||||
// But how do we know for sure which state we're in, and how do we actually clear out the buggy state?
|
||||
|
||||
ESP_LOGI(TAG, "[%s] Still waiting for first GATT notify event.", this->get_name());
|
||||
ESP_LOGI(TAG, "[%s] Still waiting for first GATT notify event.", this->get_name().c_str());
|
||||
} else if (diff > NOTIFY_WARN_THRESHOLD) {
|
||||
ESP_LOGW(TAG, "[%s] Last GATT notify was %" PRId32 " seconds ago.", this->get_name(), diff / 1000);
|
||||
ESP_LOGW(TAG, "[%s] Last GATT notify was %" PRId32 " seconds ago.", this->get_name().c_str(), diff / 1000);
|
||||
}
|
||||
|
||||
if (this->timeout_ > 0 && diff > this->timeout_ && this->parent()->enabled) {
|
||||
ESP_LOGW(TAG, "[%s] Timed out after %" PRId32 " sec. Retrying", this->get_name(), this->timeout_);
|
||||
ESP_LOGW(TAG, "[%s] Timed out after %" PRId32 " sec. Retrying", this->get_name().c_str(), this->timeout_);
|
||||
// set_enabled(false) will only close the connection if state != IDLE.
|
||||
this->parent()->set_state(espbt::ClientState::CONNECTING);
|
||||
this->parent()->set_enabled(false);
|
||||
|
||||
@@ -119,7 +119,13 @@ class BedJetHub final : public esphome::ble_client::BLEClientNode, public Pollin
|
||||
float get_setup_priority() const override { return setup_priority::BLUETOOTH; }
|
||||
|
||||
/** @return The BedJet's configured name, or the MAC address if not discovered yet. */
|
||||
const char *get_name() const { return this->name_[0] == '\0' ? this->parent_->address_str() : this->name_; }
|
||||
std::string get_name() {
|
||||
if (this->name_.empty()) {
|
||||
return this->parent_->address_str();
|
||||
} else {
|
||||
return this->name_;
|
||||
}
|
||||
}
|
||||
|
||||
/* BLEClient overrides */
|
||||
|
||||
@@ -145,8 +151,9 @@ class BedJetHub final : public esphome::ble_client::BLEClientNode, public Pollin
|
||||
uint8_t set_notify_(bool enable);
|
||||
/** Send the `BedjetPacket` to the device. */
|
||||
uint8_t write_bedjet_packet_(BedjetPacket *pkt);
|
||||
// Only used in log lines; longer names are truncated
|
||||
char name_[24]{};
|
||||
void set_name_(const std::string &name) { this->name_ = name; }
|
||||
|
||||
std::string name_;
|
||||
|
||||
uint32_t last_notify_ = 0;
|
||||
inline void status_packet_ready_();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "sen6x.h"
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/progmem.h"
|
||||
#include <cinttypes>
|
||||
#include <cmath>
|
||||
#include <iterator>
|
||||
@@ -9,6 +10,14 @@ namespace esphome::sen6x {
|
||||
|
||||
ESPHOME_LOG_TAG(TAG, "sen6x");
|
||||
|
||||
// Indexed by Sen6xType
|
||||
PROGMEM_STRING_TABLE(TypeStrings, "SEN62", "SEN63C", "SEN65", "SEN66", "SEN68", "SEN69C", "UNKNOWN");
|
||||
|
||||
static SEN6XComponent::Sen6xType infer_type_from_product_name(const char *product_name) {
|
||||
const int16_t type = progmem_string_table_find<TypeStrings>(product_name, strnlen(product_name, 32));
|
||||
return type < 0 ? SEN6XComponent::UNKNOWN : static_cast<SEN6XComponent::Sen6xType>(type);
|
||||
}
|
||||
|
||||
#ifdef SEN6X_STATUS_SENSOR_COUNT
|
||||
// Bit of the status register behind each kind; the CO2 error bit is 9 on SEN66 and 12 on SEN63C/SEN69C
|
||||
static uint8_t status_bit(Sen6xStatus status, SEN6XComponent::Sen6xType type) {
|
||||
@@ -133,33 +142,36 @@ void SEN6XComponent::setup() {
|
||||
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
|
||||
return;
|
||||
}
|
||||
this->serial_number_ = SEN6XComponent::sensirion_convert_to_string_in_place(raw_serial_number, 16);
|
||||
ESP_LOGI(TAG, "Serial number: %s", this->serial_number_.c_str());
|
||||
// The last byte of serial_number_ stays 0, so a full 32-byte serial is still terminated
|
||||
memcpy(this->serial_number_, SEN6XComponent::sensirion_convert_to_string_in_place(raw_serial_number, 16),
|
||||
sizeof(this->serial_number_) - 1);
|
||||
ESP_LOGI(TAG, "Serial number: %s", this->serial_number_);
|
||||
|
||||
// Step 2: Read product name in next loop iteration
|
||||
this->set_timeout(0, [this]() {
|
||||
uint16_t raw_product_name[16];
|
||||
// One spare zero word so a full 32-byte name is still terminated
|
||||
uint16_t raw_product_name[17]{};
|
||||
if (!this->get_register(SEN6X_CMD_GET_PRODUCT_NAME, raw_product_name, 16, 20)) {
|
||||
ESP_LOGE(TAG, ESP_LOG_MSG_COMM_FAIL);
|
||||
this->mark_failed(LOG_STR(ESP_LOG_MSG_COMM_FAIL));
|
||||
return;
|
||||
}
|
||||
|
||||
this->product_name_ = SEN6XComponent::sensirion_convert_to_string_in_place(raw_product_name, 16);
|
||||
const char *product_name = SEN6XComponent::sensirion_convert_to_string_in_place(raw_product_name, 16);
|
||||
|
||||
Sen6xType inferred_type = this->infer_type_from_product_name_(this->product_name_);
|
||||
Sen6xType inferred_type = infer_type_from_product_name(product_name);
|
||||
if (this->sen6x_type_ == UNKNOWN) {
|
||||
this->sen6x_type_ = inferred_type;
|
||||
if (inferred_type == UNKNOWN) {
|
||||
ESP_LOGE(TAG, "Unknown product '%s'", this->product_name_.c_str());
|
||||
ESP_LOGE(TAG, "Unknown product '%s'", product_name);
|
||||
this->mark_failed();
|
||||
return;
|
||||
}
|
||||
ESP_LOGD(TAG, "Type inferred from product: %s", this->product_name_.c_str());
|
||||
ESP_LOGD(TAG, "Type inferred from product: %s", product_name);
|
||||
} else if (this->sen6x_type_ != inferred_type && inferred_type != UNKNOWN) {
|
||||
ESP_LOGW(TAG, "Configured type (used) mismatches product '%s'", this->product_name_.c_str());
|
||||
ESP_LOGW(TAG, "Configured type (used) mismatches product '%s'", product_name);
|
||||
}
|
||||
ESP_LOGI(TAG, "Product: %s", this->product_name_.c_str());
|
||||
ESP_LOGI(TAG, "Product: %s", product_name);
|
||||
|
||||
// Validate configured sensors against detected type and disable unsupported ones
|
||||
const bool has_voc_nox = (this->sen6x_type_ == SEN65 || this->sen6x_type_ == SEN66 ||
|
||||
@@ -329,13 +341,13 @@ bool SEN6XComponent::write_tuning_parameters_(uint16_t i2c_command, const GasTun
|
||||
void SEN6XComponent::dump_config() {
|
||||
ESP_LOGCONFIG(TAG,
|
||||
"sen6x:\n"
|
||||
" Product: %s\n"
|
||||
" Type: %s\n"
|
||||
" Serial: %s\n"
|
||||
" Firmware: %u.%u\n"
|
||||
" Address: 0x%02X\n"
|
||||
" Startup delay: %" PRIu32 " ms",
|
||||
this->product_name_.c_str(), this->serial_number_.c_str(), this->firmware_version_major_,
|
||||
this->firmware_version_minor_, this->address_, this->startup_delay_ms_);
|
||||
LOG_STR_ARG(TypeStrings::get_log_str(this->sen6x_type_, TypeStrings::LAST_INDEX)), this->serial_number_,
|
||||
this->firmware_version_major_, this->firmware_version_minor_, this->address_, this->startup_delay_ms_);
|
||||
LOG_UPDATE_INTERVAL(this);
|
||||
if (this->temperature_compensation_.has_value()) {
|
||||
const auto &comp = this->temperature_compensation_.value();
|
||||
@@ -812,20 +824,4 @@ void SEN6XComponent::activate_sht_heater() {
|
||||
this->set_command_wait_(SHT_HEATER_DELAY);
|
||||
}
|
||||
|
||||
SEN6XComponent::Sen6xType SEN6XComponent::infer_type_from_product_name_(const std::string &product_name) {
|
||||
if (product_name == "SEN62")
|
||||
return SEN62;
|
||||
if (product_name == "SEN63C")
|
||||
return SEN63C;
|
||||
if (product_name == "SEN65")
|
||||
return SEN65;
|
||||
if (product_name == "SEN66")
|
||||
return SEN66;
|
||||
if (product_name == "SEN68")
|
||||
return SEN68;
|
||||
if (product_name == "SEN69C")
|
||||
return SEN69C;
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
} // namespace esphome::sen6x
|
||||
|
||||
@@ -86,9 +86,9 @@ class SEN6XComponent final : public PollingComponent, public sensirion_common::S
|
||||
void dump_config() override;
|
||||
void update() override;
|
||||
|
||||
enum Sen6xType { SEN62, SEN63C, SEN65, SEN66, SEN68, SEN69C, UNKNOWN };
|
||||
enum Sen6xType : uint8_t { SEN62, SEN63C, SEN65, SEN66, SEN68, SEN69C, UNKNOWN };
|
||||
|
||||
void set_type(const std::string &type) { sen6x_type_ = infer_type_from_product_name_(type); }
|
||||
void set_type(Sen6xType type) { this->sen6x_type_ = type; }
|
||||
void set_voc_algorithm_tuning(uint16_t index_offset, uint16_t learning_time_offset_hours,
|
||||
uint16_t learning_time_gain_hours, uint16_t gating_max_duration_minutes,
|
||||
uint16_t std_initial, uint16_t gain_factor) {
|
||||
@@ -139,7 +139,6 @@ class SEN6XComponent final : public PollingComponent, public sensirion_common::S
|
||||
SETUP_STEP_COUNT,
|
||||
};
|
||||
|
||||
Sen6xType infer_type_from_product_name_(const std::string &product_name);
|
||||
void run_next_setup_step_();
|
||||
bool write_setup_step_(SetupStep step);
|
||||
void finish_setup_();
|
||||
@@ -167,8 +166,7 @@ class SEN6XComponent final : public PollingComponent, public sensirion_common::S
|
||||
void parse_and_publish_number_concentration_();
|
||||
#endif
|
||||
|
||||
std::string product_name_;
|
||||
std::string serial_number_;
|
||||
char serial_number_[33]{};
|
||||
#ifdef SEN6X_STATUS_SENSOR_COUNT
|
||||
StaticVector<StatusSensor, SEN6X_STATUS_SENSOR_COUNT> status_sensors_;
|
||||
#endif
|
||||
|
||||
@@ -78,6 +78,15 @@ sen6x_ns = cg.esphome_ns.namespace("sen6x")
|
||||
SEN6XComponent = sen6x_ns.class_(
|
||||
"SEN6XComponent", cg.PollingComponent, sensirion_common.SensirionI2CDevice
|
||||
)
|
||||
Sen6xType = sen6x_ns.namespace("SEN6XComponent").enum("Sen6xType")
|
||||
SEN6X_TYPES = {
|
||||
"SEN62": Sen6xType.SEN62,
|
||||
"SEN63C": Sen6xType.SEN63C,
|
||||
"SEN65": Sen6xType.SEN65,
|
||||
"SEN66": Sen6xType.SEN66,
|
||||
"SEN68": Sen6xType.SEN68,
|
||||
"SEN69C": Sen6xType.SEN69C,
|
||||
}
|
||||
|
||||
|
||||
_PMC_KEYS = (CONF_PMC_0_5, CONF_PMC_1_0, CONF_PMC_2_5, CONF_PMC_4_0, CONF_PMC_10_0)
|
||||
@@ -133,9 +142,7 @@ CONFIG_SCHEMA = cv.All(
|
||||
cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(SEN6XComponent),
|
||||
cv.Optional(CONF_TYPE): cv.one_of(
|
||||
"SEN62", "SEN63C", "SEN65", "SEN66", "SEN68", "SEN69C", upper=True
|
||||
),
|
||||
cv.Optional(CONF_TYPE): cv.enum(SEN6X_TYPES, upper=True),
|
||||
cv.Optional(CONF_PM_1_0): sensor.sensor_schema(
|
||||
unit_of_measurement=UNIT_MICROGRAMS_PER_CUBIC_METER,
|
||||
icon=ICON_CHEMICAL_WEAPON,
|
||||
|
||||
Reference in New Issue
Block a user