mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +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_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_READ_MEASUREMENT = 0x0300; | ||||
|  | ||||
| /// Commands for future use | ||||
| static const uint16_t SCD30_CMD_STOP_MEASUREMENTS = 0x0104; | ||||
| 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_TEMPERATURE_OFFSET = 0x5403; | ||||
| static const uint16_t SCD30_CMD_ALTITUDE_COMPENSATION = 0x5102; | ||||
| static const uint16_t SCD30_CMD_SOFT_RESET = 0xD304; | ||||
|  | ||||
| void SCD30Component::setup() { | ||||
|   ESP_LOGCONFIG(TAG, "Setting up scd30..."); | ||||
|  | ||||
| #ifdef ARDUINO_ARCH_ESP8266 | ||||
|   Wire.setClockStretchLimit(150000); | ||||
| #endif | ||||
|  | ||||
|   /// Firmware version identification | ||||
|   if (!this->write_command_(SCD30_CMD_GET_FIRMWARE_VERSION)) { | ||||
|     this->error_code_ = COMMUNICATION_FAILED; | ||||
| @@ -40,12 +44,29 @@ void SCD30Component::setup() { | ||||
|            uint16_t(raw_firmware_version[0] & 0xFF)); | ||||
|  | ||||
|   /// 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."); | ||||
|     this->error_code_ = MEASUREMENT_INIT_FAILED; | ||||
|     this->mark_failed(); | ||||
|     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() { | ||||
| @@ -67,6 +88,12 @@ void SCD30Component::dump_config() { | ||||
|         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_SENSOR("  ", "CO2", this->co2_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); | ||||
| } | ||||
|  | ||||
| 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 bit; | ||||
|   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_humidity_sensor(sensor::Sensor *humidity) { humidity_sensor_ = humidity; } | ||||
|   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 update() override; | ||||
| @@ -21,6 +23,7 @@ class SCD30Component : public PollingComponent, public i2c::I2CDevice { | ||||
|  | ||||
|  protected: | ||||
|   bool write_command_(uint16_t command); | ||||
|   bool write_command_(uint16_t command, uint16_t data); | ||||
|   bool read_data_(uint16_t *data, uint8_t len); | ||||
|   uint8_t sht_crc_(uint8_t data1, uint8_t data2); | ||||
|  | ||||
| @@ -30,6 +33,8 @@ class SCD30Component : public PollingComponent, public i2c::I2CDevice { | ||||
|     MEASUREMENT_INIT_FAILED, | ||||
|     UNKNOWN | ||||
|   } error_code_{UNKNOWN}; | ||||
|   bool enable_asc_{true}; | ||||
|   uint16_t altitude_compensation_{0xFFFF}; | ||||
|  | ||||
|   sensor::Sensor *co2_sensor_{nullptr}; | ||||
|   sensor::Sensor *humidity_sensor_{nullptr}; | ||||
|   | ||||
| @@ -1,3 +1,4 @@ | ||||
| import re | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.components import i2c, sensor | ||||
| @@ -10,12 +11,24 @@ DEPENDENCIES = ['i2c'] | ||||
| scd30_ns = cg.esphome_ns.namespace('scd30') | ||||
| 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({ | ||||
|     cv.GenerateID(): cv.declare_id(SCD30Component), | ||||
|     cv.Required(CONF_CO2): sensor.sensor_schema(UNIT_PARTS_PER_MILLION, | ||||
|                                                 ICON_PERIODIC_TABLE_CO2, 0), | ||||
|     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.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)) | ||||
|  | ||||
|  | ||||
| @@ -24,6 +37,10 @@ def to_code(config): | ||||
|     yield cg.register_component(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: | ||||
|         sens = yield sensor.new_sensor(config[CONF_CO2]) | ||||
|         cg.add(var.set_co2_sensor(sens)) | ||||
|   | ||||
| @@ -584,6 +584,8 @@ sensor: | ||||
|       name: "Living Room Humidity 9" | ||||
|     address: 0x61 | ||||
|     update_interval: 15s | ||||
|     automatic_self_calibration: true | ||||
|     altitude_compensation: 10m | ||||
|   - platform: sgp30 | ||||
|     eco2: | ||||
|       name: "Workshop eCO2" | ||||
|   | ||||
		Reference in New Issue
	
	Block a user