mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	| @@ -8,21 +8,25 @@ static const char *TAG = "scd30"; | |||||||
|  |  | ||||||
| static const uint16_t SCD30_CMD_GET_FIRMWARE_VERSION = 0xd100; | static const uint16_t SCD30_CMD_GET_FIRMWARE_VERSION = 0xd100; | ||||||
| static const uint16_t SCD30_CMD_START_CONTINUOUS_MEASUREMENTS = 0x0010; | static const uint16_t SCD30_CMD_START_CONTINUOUS_MEASUREMENTS = 0x0010; | ||||||
|  | static const uint16_t SCD30_CMD_ALTITUDE_COMPENSATION = 0x5102; | ||||||
|  | static const uint16_t SCD30_CMD_AUTOMATIC_SELF_CALIBRATION = 0x5306; | ||||||
| static const uint16_t SCD30_CMD_GET_DATA_READY_STATUS = 0x0202; | static const uint16_t SCD30_CMD_GET_DATA_READY_STATUS = 0x0202; | ||||||
| static const uint16_t SCD30_CMD_READ_MEASUREMENT = 0x0300; | static const uint16_t SCD30_CMD_READ_MEASUREMENT = 0x0300; | ||||||
|  |  | ||||||
| /// Commands for future use | /// Commands for future use | ||||||
| static const uint16_t SCD30_CMD_STOP_MEASUREMENTS = 0x0104; | static const uint16_t SCD30_CMD_STOP_MEASUREMENTS = 0x0104; | ||||||
| static const uint16_t SCD30_CMD_MEASUREMENT_INTERVAL = 0x4600; | static const uint16_t SCD30_CMD_MEASUREMENT_INTERVAL = 0x4600; | ||||||
| static const uint16_t SCD30_CMD_AUTOMATIC_SELF_CALIBRATION = 0x5306; |  | ||||||
| static const uint16_t SCD30_CMD_FORCED_CALIBRATION = 0x5204; | static const uint16_t SCD30_CMD_FORCED_CALIBRATION = 0x5204; | ||||||
| static const uint16_t SCD30_CMD_TEMPERATURE_OFFSET = 0x5403; | static const uint16_t SCD30_CMD_TEMPERATURE_OFFSET = 0x5403; | ||||||
| static const uint16_t SCD30_CMD_ALTITUDE_COMPENSATION = 0x5102; |  | ||||||
| static const uint16_t SCD30_CMD_SOFT_RESET = 0xD304; | static const uint16_t SCD30_CMD_SOFT_RESET = 0xD304; | ||||||
|  |  | ||||||
| void SCD30Component::setup() { | void SCD30Component::setup() { | ||||||
|   ESP_LOGCONFIG(TAG, "Setting up scd30..."); |   ESP_LOGCONFIG(TAG, "Setting up scd30..."); | ||||||
|  |  | ||||||
|  | #ifdef ARDUINO_ARCH_ESP8266 | ||||||
|  |   Wire.setClockStretchLimit(150000); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|   /// Firmware version identification |   /// Firmware version identification | ||||||
|   if (!this->write_command_(SCD30_CMD_GET_FIRMWARE_VERSION)) { |   if (!this->write_command_(SCD30_CMD_GET_FIRMWARE_VERSION)) { | ||||||
|     this->error_code_ = COMMUNICATION_FAILED; |     this->error_code_ = COMMUNICATION_FAILED; | ||||||
| @@ -40,12 +44,29 @@ void SCD30Component::setup() { | |||||||
|            uint16_t(raw_firmware_version[0] & 0xFF)); |            uint16_t(raw_firmware_version[0] & 0xFF)); | ||||||
|  |  | ||||||
|   /// Sensor initialization |   /// Sensor initialization | ||||||
|   if (!this->write_command_(SCD30_CMD_START_CONTINUOUS_MEASUREMENTS)) { |   if (!this->write_command_(SCD30_CMD_START_CONTINUOUS_MEASUREMENTS, 0)) { | ||||||
|     ESP_LOGE(TAG, "Sensor SCD30 error starting continuous measurements."); |     ESP_LOGE(TAG, "Sensor SCD30 error starting continuous measurements."); | ||||||
|     this->error_code_ = MEASUREMENT_INIT_FAILED; |     this->error_code_ = MEASUREMENT_INIT_FAILED; | ||||||
|     this->mark_failed(); |     this->mark_failed(); | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   // The start measurement command disables the altitude compensation, if any, so we only set it if it's turned on | ||||||
|  |   if (this->altitude_compensation_ != 0xFFFF) { | ||||||
|  |     if (!this->write_command_(SCD30_CMD_ALTITUDE_COMPENSATION, altitude_compensation_)) { | ||||||
|  |       ESP_LOGE(TAG, "Sensor SCD30 error starting continuous measurements."); | ||||||
|  |       this->error_code_ = MEASUREMENT_INIT_FAILED; | ||||||
|  |       this->mark_failed(); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (!this->write_command_(SCD30_CMD_AUTOMATIC_SELF_CALIBRATION, enable_asc_ ? 1 : 0)) { | ||||||
|  |     ESP_LOGE(TAG, "Sensor SCD30 error setting automatic self calibration."); | ||||||
|  |     this->error_code_ = MEASUREMENT_INIT_FAILED; | ||||||
|  |     this->mark_failed(); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| void SCD30Component::dump_config() { | void SCD30Component::dump_config() { | ||||||
| @@ -67,6 +88,12 @@ void SCD30Component::dump_config() { | |||||||
|         break; |         break; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |   if (this->altitude_compensation_ == 0xFFFF) { | ||||||
|  |     ESP_LOGCONFIG(TAG, "  Altitude compensation: OFF"); | ||||||
|  |   } else { | ||||||
|  |     ESP_LOGCONFIG(TAG, "  Altitude compensation: %dm", this->altitude_compensation_); | ||||||
|  |   } | ||||||
|  |   ESP_LOGCONFIG(TAG, "  Automatic self calibration: %s", ONOFF(this->enable_asc_)); | ||||||
|   LOG_UPDATE_INTERVAL(this); |   LOG_UPDATE_INTERVAL(this); | ||||||
|   LOG_SENSOR("  ", "CO2", this->co2_sensor_); |   LOG_SENSOR("  ", "CO2", this->co2_sensor_); | ||||||
|   LOG_SENSOR("  ", "Temperature", this->temperature_sensor_); |   LOG_SENSOR("  ", "Temperature", this->temperature_sensor_); | ||||||
| @@ -130,6 +157,16 @@ bool SCD30Component::write_command_(uint16_t command) { | |||||||
|   return this->write_byte(command >> 8, command & 0xFF); |   return this->write_byte(command >> 8, command & 0xFF); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | bool SCD30Component::write_command_(uint16_t command, uint16_t data) { | ||||||
|  |   uint8_t raw[5]; | ||||||
|  |   raw[0] = command >> 8; | ||||||
|  |   raw[1] = command & 0xFF; | ||||||
|  |   raw[2] = data >> 8; | ||||||
|  |   raw[3] = data & 0xFF; | ||||||
|  |   raw[4] = sht_crc_(raw[2], raw[3]); | ||||||
|  |   return this->write_bytes_raw(raw, 5); | ||||||
|  | } | ||||||
|  |  | ||||||
| uint8_t SCD30Component::sht_crc_(uint8_t data1, uint8_t data2) { | uint8_t SCD30Component::sht_crc_(uint8_t data1, uint8_t data2) { | ||||||
|   uint8_t bit; |   uint8_t bit; | ||||||
|   uint8_t crc = 0xFF; |   uint8_t crc = 0xFF; | ||||||
|   | |||||||
| @@ -13,6 +13,8 @@ class SCD30Component : public PollingComponent, public i2c::I2CDevice { | |||||||
|   void set_co2_sensor(sensor::Sensor *co2) { co2_sensor_ = co2; } |   void set_co2_sensor(sensor::Sensor *co2) { co2_sensor_ = co2; } | ||||||
|   void set_humidity_sensor(sensor::Sensor *humidity) { humidity_sensor_ = humidity; } |   void set_humidity_sensor(sensor::Sensor *humidity) { humidity_sensor_ = humidity; } | ||||||
|   void set_temperature_sensor(sensor::Sensor *temperature) { temperature_sensor_ = temperature; } |   void set_temperature_sensor(sensor::Sensor *temperature) { temperature_sensor_ = temperature; } | ||||||
|  |   void set_automatic_self_calibration(bool asc) { enable_asc_ = asc; } | ||||||
|  |   void set_altitude_compensation(uint16_t altitude) { altitude_compensation_ = altitude; } | ||||||
|  |  | ||||||
|   void setup() override; |   void setup() override; | ||||||
|   void update() override; |   void update() override; | ||||||
| @@ -21,6 +23,7 @@ class SCD30Component : public PollingComponent, public i2c::I2CDevice { | |||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   bool write_command_(uint16_t command); |   bool write_command_(uint16_t command); | ||||||
|  |   bool write_command_(uint16_t command, uint16_t data); | ||||||
|   bool read_data_(uint16_t *data, uint8_t len); |   bool read_data_(uint16_t *data, uint8_t len); | ||||||
|   uint8_t sht_crc_(uint8_t data1, uint8_t data2); |   uint8_t sht_crc_(uint8_t data1, uint8_t data2); | ||||||
|  |  | ||||||
| @@ -30,6 +33,8 @@ class SCD30Component : public PollingComponent, public i2c::I2CDevice { | |||||||
|     MEASUREMENT_INIT_FAILED, |     MEASUREMENT_INIT_FAILED, | ||||||
|     UNKNOWN |     UNKNOWN | ||||||
|   } error_code_{UNKNOWN}; |   } error_code_{UNKNOWN}; | ||||||
|  |   bool enable_asc_{true}; | ||||||
|  |   uint16_t altitude_compensation_{0xFFFF}; | ||||||
|  |  | ||||||
|   sensor::Sensor *co2_sensor_{nullptr}; |   sensor::Sensor *co2_sensor_{nullptr}; | ||||||
|   sensor::Sensor *humidity_sensor_{nullptr}; |   sensor::Sensor *humidity_sensor_{nullptr}; | ||||||
|   | |||||||
| @@ -1,3 +1,4 @@ | |||||||
|  | import re | ||||||
| import esphome.codegen as cg | import esphome.codegen as cg | ||||||
| import esphome.config_validation as cv | import esphome.config_validation as cv | ||||||
| from esphome.components import i2c, sensor | from esphome.components import i2c, sensor | ||||||
| @@ -10,12 +11,24 @@ DEPENDENCIES = ['i2c'] | |||||||
| scd30_ns = cg.esphome_ns.namespace('scd30') | scd30_ns = cg.esphome_ns.namespace('scd30') | ||||||
| SCD30Component = scd30_ns.class_('SCD30Component', cg.PollingComponent, i2c.I2CDevice) | SCD30Component = scd30_ns.class_('SCD30Component', cg.PollingComponent, i2c.I2CDevice) | ||||||
|  |  | ||||||
|  | CONF_AUTOMATIC_SELF_CALIBRATION = 'automatic_self_calibration' | ||||||
|  | CONF_ALTITUDE_COMPENSATION = 'altitude_compensation' | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def remove_altitude_suffix(value): | ||||||
|  |     return re.sub(r"\s*(?:m(?:\s+a\.s\.l)?)|(?:MAM?SL)$", '', value) | ||||||
|  |  | ||||||
|  |  | ||||||
| CONFIG_SCHEMA = cv.Schema({ | CONFIG_SCHEMA = cv.Schema({ | ||||||
|     cv.GenerateID(): cv.declare_id(SCD30Component), |     cv.GenerateID(): cv.declare_id(SCD30Component), | ||||||
|     cv.Required(CONF_CO2): sensor.sensor_schema(UNIT_PARTS_PER_MILLION, |     cv.Required(CONF_CO2): sensor.sensor_schema(UNIT_PARTS_PER_MILLION, | ||||||
|                                                 ICON_PERIODIC_TABLE_CO2, 0), |                                                 ICON_PERIODIC_TABLE_CO2, 0), | ||||||
|     cv.Required(CONF_TEMPERATURE): sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1), |     cv.Required(CONF_TEMPERATURE): sensor.sensor_schema(UNIT_CELSIUS, ICON_THERMOMETER, 1), | ||||||
|     cv.Required(CONF_HUMIDITY): sensor.sensor_schema(UNIT_PERCENT, ICON_WATER_PERCENT, 1), |     cv.Required(CONF_HUMIDITY): sensor.sensor_schema(UNIT_PERCENT, ICON_WATER_PERCENT, 1), | ||||||
|  |     cv.Optional(CONF_AUTOMATIC_SELF_CALIBRATION, default=True): cv.boolean, | ||||||
|  |     cv.Optional(CONF_ALTITUDE_COMPENSATION): cv.All(remove_altitude_suffix, | ||||||
|  |                                                     cv.int_range(min=0, max=0xFFFF, | ||||||
|  |                                                                  max_included=False)), | ||||||
| }).extend(cv.polling_component_schema('60s')).extend(i2c.i2c_device_schema(0x61)) | }).extend(cv.polling_component_schema('60s')).extend(i2c.i2c_device_schema(0x61)) | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -24,6 +37,10 @@ def to_code(config): | |||||||
|     yield cg.register_component(var, config) |     yield cg.register_component(var, config) | ||||||
|     yield i2c.register_i2c_device(var, config) |     yield i2c.register_i2c_device(var, config) | ||||||
|  |  | ||||||
|  |     cg.add(var.set_automatic_self_calibration(config[CONF_AUTOMATIC_SELF_CALIBRATION])) | ||||||
|  |     if CONF_ALTITUDE_COMPENSATION in config: | ||||||
|  |         cg.add(var.set_altitude_compensation(config[CONF_ALTITUDE_COMPENSATION])) | ||||||
|  |  | ||||||
|     if CONF_CO2 in config: |     if CONF_CO2 in config: | ||||||
|         sens = yield sensor.new_sensor(config[CONF_CO2]) |         sens = yield sensor.new_sensor(config[CONF_CO2]) | ||||||
|         cg.add(var.set_co2_sensor(sens)) |         cg.add(var.set_co2_sensor(sens)) | ||||||
|   | |||||||
| @@ -584,6 +584,8 @@ sensor: | |||||||
|       name: "Living Room Humidity 9" |       name: "Living Room Humidity 9" | ||||||
|     address: 0x61 |     address: 0x61 | ||||||
|     update_interval: 15s |     update_interval: 15s | ||||||
|  |     automatic_self_calibration: true | ||||||
|  |     altitude_compensation: 10m | ||||||
|   - platform: sgp30 |   - platform: sgp30 | ||||||
|     eco2: |     eco2: | ||||||
|       name: "Workshop eCO2" |       name: "Workshop eCO2" | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user