diff --git a/CODEOWNERS b/CODEOWNERS index dedd8acc1..3ae9f71ea 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -31,6 +31,7 @@ esphome/components/ble_client/* @buxtronix esphome/components/bme680_bsec/* @trvrnrth esphome/components/canbus/* @danielschramm @mvturnho esphome/components/captive_portal/* @OttoWinter +esphome/components/ccs811/* @habbie esphome/components/climate/* @esphome/core esphome/components/climate_ir/* @glmnet esphome/components/color_temperature/* @jesserockz diff --git a/esphome/components/ccs811/ccs811.cpp b/esphome/components/ccs811/ccs811.cpp index dec070a9b..08df6f777 100644 --- a/esphome/components/ccs811/ccs811.cpp +++ b/esphome/components/ccs811/ccs811.cpp @@ -16,7 +16,7 @@ static const char *const TAG = "ccs811"; return; \ } -#define CHECKED_IO(f) CHECK_TRUE(f, COMMUNICAITON_FAILED) +#define CHECKED_IO(f) CHECK_TRUE(f, COMMUNICATION_FAILED) void CCS811Component::setup() { // page 9 programming guide - hwid is always 0x81 @@ -38,12 +38,14 @@ void CCS811Component::setup() { // set MEAS_MODE (page 5) uint8_t meas_mode = 0; uint32_t interval = this->get_update_interval(); - if (interval <= 1000) - meas_mode = 1 << 4; - else if (interval <= 10000) - meas_mode = 2 << 4; + if (interval >= 60 * 1000) + meas_mode = 3 << 4; // sensor takes a reading every 60 seconds + else if (interval >= 10 * 1000) + meas_mode = 2 << 4; // sensor takes a reading every 10 seconds + else if (interval >= 1 * 1000) + meas_mode = 1 << 4; // sensor takes a reading every second else - meas_mode = 3 << 4; + meas_mode = 4 << 4; // sensor takes a reading every 250ms CHECKED_IO(this->write_byte(0x01, meas_mode)) @@ -51,6 +53,36 @@ void CCS811Component::setup() { // baseline available, write to sensor this->write_bytes(0x11, decode_uint16(*this->baseline_)); } + + auto hardware_version_data = this->read_bytes<1>(0x21); + auto bootloader_version_data = this->read_bytes<2>(0x23); + auto application_version_data = this->read_bytes<2>(0x24); + + uint8_t hardware_version = 0; + uint16_t bootloader_version = 0; + uint16_t application_version = 0; + + if (hardware_version_data.has_value()) { + hardware_version = (*hardware_version_data)[0]; + } + + if (bootloader_version_data.has_value()) { + bootloader_version = encode_uint16((*bootloader_version_data)[0], (*bootloader_version_data)[1]); + } + + if (application_version_data.has_value()) { + application_version = encode_uint16((*application_version_data)[0], (*application_version_data)[1]); + } + + ESP_LOGD(TAG, "hardware_version=0x%x bootloader_version=0x%x application_version=0x%x\n", hardware_version, + bootloader_version, application_version); + if (this->version_ != nullptr) { + char version[20]; // "15.15.15 (0xffff)" is 17 chars, plus NUL, plus wiggle room + sprintf(version, "%d.%d.%d (0x%02x)", (application_version >> 12 & 15), (application_version >> 8 & 15), + (application_version >> 4 & 15), application_version); + ESP_LOGD(TAG, "publishing version state: %s", version); + this->version_->publish_state(version); + } } void CCS811Component::update() { if (!this->status_has_data_()) @@ -117,6 +149,7 @@ void CCS811Component::dump_config() { LOG_UPDATE_INTERVAL(this) LOG_SENSOR(" ", "CO2 Sensor", this->co2_) LOG_SENSOR(" ", "TVOC Sensor", this->tvoc_) + LOG_TEXT_SENSOR(" ", "Firmware Version Sensor", this->version_) if (this->baseline_) { ESP_LOGCONFIG(TAG, " Baseline: %04X", *this->baseline_); } else { @@ -124,7 +157,7 @@ void CCS811Component::dump_config() { } if (this->is_failed()) { switch (this->error_code_) { - case COMMUNICAITON_FAILED: + case COMMUNICATION_FAILED: ESP_LOGW(TAG, "Communication failed! Is the sensor connected?"); break; case INVALID_ID: diff --git a/esphome/components/ccs811/ccs811.h b/esphome/components/ccs811/ccs811.h index cea919c9a..8a0d60d00 100644 --- a/esphome/components/ccs811/ccs811.h +++ b/esphome/components/ccs811/ccs811.h @@ -3,6 +3,7 @@ #include "esphome/core/component.h" #include "esphome/core/preferences.h" #include "esphome/components/sensor/sensor.h" +#include "esphome/components/text_sensor/text_sensor.h" #include "esphome/components/i2c/i2c.h" namespace esphome { @@ -12,6 +13,7 @@ class CCS811Component : public PollingComponent, public i2c::I2CDevice { public: void set_co2(sensor::Sensor *co2) { co2_ = co2; } void set_tvoc(sensor::Sensor *tvoc) { tvoc_ = tvoc; } + void set_version(text_sensor::TextSensor *version) { version_ = version; } void set_baseline(uint16_t baseline) { baseline_ = baseline; } void set_humidity(sensor::Sensor *humidity) { humidity_ = humidity; } void set_temperature(sensor::Sensor *temperature) { temperature_ = temperature; } @@ -34,7 +36,7 @@ class CCS811Component : public PollingComponent, public i2c::I2CDevice { enum ErrorCode { UNKNOWN, - COMMUNICAITON_FAILED, + COMMUNICATION_FAILED, INVALID_ID, SENSOR_REPORTED_ERROR, APP_INVALID, @@ -43,6 +45,7 @@ class CCS811Component : public PollingComponent, public i2c::I2CDevice { sensor::Sensor *co2_{nullptr}; sensor::Sensor *tvoc_{nullptr}; + text_sensor::TextSensor *version_{nullptr}; optional baseline_{}; /// Input sensor for humidity reading. sensor::Sensor *humidity_{nullptr}; diff --git a/esphome/components/ccs811/sensor.py b/esphome/components/ccs811/sensor.py index c177ed6b5..bb8200273 100644 --- a/esphome/components/ccs811/sensor.py +++ b/esphome/components/ccs811/sensor.py @@ -1,9 +1,11 @@ import esphome.codegen as cg import esphome.config_validation as cv -from esphome.components import i2c, sensor +from esphome.components import i2c, sensor, text_sensor from esphome.const import ( + CONF_ICON, CONF_ID, ICON_RADIATOR, + ICON_RESTART, DEVICE_CLASS_CARBON_DIOXIDE, DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS, STATE_CLASS_MEASUREMENT, @@ -14,9 +16,12 @@ from esphome.const import ( CONF_TEMPERATURE, CONF_TVOC, CONF_HUMIDITY, + CONF_VERSION, ICON_MOLECULE_CO2, ) +AUTO_LOAD = ["text_sensor"] +CODEOWNERS = ["@habbie"] DEPENDENCIES = ["i2c"] ccs811_ns = cg.esphome_ns.namespace("ccs811") @@ -42,6 +47,12 @@ CONFIG_SCHEMA = ( device_class=DEVICE_CLASS_VOLATILE_ORGANIC_COMPOUNDS, state_class=STATE_CLASS_MEASUREMENT, ), + cv.Optional(CONF_VERSION): text_sensor.TEXT_SENSOR_SCHEMA.extend( + { + cv.GenerateID(): cv.declare_id(text_sensor.TextSensor), + cv.Optional(CONF_ICON, default=ICON_RESTART): cv.icon, + } + ), cv.Optional(CONF_BASELINE): cv.hex_uint16_t, cv.Optional(CONF_TEMPERATURE): cv.use_id(sensor.Sensor), cv.Optional(CONF_HUMIDITY): cv.use_id(sensor.Sensor), @@ -62,6 +73,11 @@ async def to_code(config): sens = await sensor.new_sensor(config[CONF_TVOC]) cg.add(var.set_tvoc(sens)) + if CONF_VERSION in config: + sens = cg.new_Pvariable(config[CONF_VERSION][CONF_ID]) + await text_sensor.register_text_sensor(sens, config[CONF_VERSION]) + cg.add(var.set_version(sens)) + if CONF_BASELINE in config: cg.add(var.set_baseline(config[CONF_BASELINE]))