mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	Add AS7341 spectral color sensor (#4331)
* Add support for AS7341 spectral color sensor. * Run clang-format and clang-tidy. * Post-review changes. * Apply suggestions from code review --------- Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
		| @@ -25,6 +25,7 @@ esphome/components/analog_threshold/* @ianchi | |||||||
| esphome/components/animation/* @syndlex | esphome/components/animation/* @syndlex | ||||||
| esphome/components/anova/* @buxtronix | esphome/components/anova/* @buxtronix | ||||||
| esphome/components/api/* @OttoWinter | esphome/components/api/* @OttoWinter | ||||||
|  | esphome/components/as7341/* @mrgnr | ||||||
| esphome/components/async_tcp/* @OttoWinter | esphome/components/async_tcp/* @OttoWinter | ||||||
| esphome/components/atc_mithermometer/* @ahpohl | esphome/components/atc_mithermometer/* @ahpohl | ||||||
| esphome/components/b_parasite/* @rbaron | esphome/components/b_parasite/* @rbaron | ||||||
|   | |||||||
							
								
								
									
										0
									
								
								esphome/components/as7341/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								esphome/components/as7341/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										271
									
								
								esphome/components/as7341/as7341.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										271
									
								
								esphome/components/as7341/as7341.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,271 @@ | |||||||
|  | #include "as7341.h" | ||||||
|  | #include "esphome/core/log.h" | ||||||
|  | #include "esphome/core/hal.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace as7341 { | ||||||
|  |  | ||||||
|  | static const char *const TAG = "as7341"; | ||||||
|  |  | ||||||
|  | void AS7341Component::setup() { | ||||||
|  |   ESP_LOGCONFIG(TAG, "Setting up AS7341..."); | ||||||
|  |   LOG_I2C_DEVICE(this); | ||||||
|  |  | ||||||
|  |   // Verify device ID | ||||||
|  |   uint8_t id; | ||||||
|  |   this->read_byte(AS7341_ID, &id); | ||||||
|  |   ESP_LOGCONFIG(TAG, "  Read ID: 0x%X", id); | ||||||
|  |   if ((id & 0xFC) != (AS7341_CHIP_ID << 2)) { | ||||||
|  |     this->mark_failed(); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Power on (enter IDLE state) | ||||||
|  |   if (!this->enable_power(true)) { | ||||||
|  |     ESP_LOGE(TAG, "  Power on failed!"); | ||||||
|  |     this->mark_failed(); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // Set configuration | ||||||
|  |   this->write_byte(AS7341_CONFIG, 0x00); | ||||||
|  |   this->setup_atime(this->atime_); | ||||||
|  |   this->setup_astep(this->astep_); | ||||||
|  |   this->setup_gain(this->gain_); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void AS7341Component::dump_config() { | ||||||
|  |   ESP_LOGCONFIG(TAG, "AS7341:"); | ||||||
|  |   LOG_I2C_DEVICE(this); | ||||||
|  |   if (this->is_failed()) { | ||||||
|  |     ESP_LOGE(TAG, "Communication with AS7341 failed!"); | ||||||
|  |   } | ||||||
|  |   LOG_UPDATE_INTERVAL(this); | ||||||
|  |   ESP_LOGCONFIG(TAG, "  Gain: %u", get_gain()); | ||||||
|  |   ESP_LOGCONFIG(TAG, "  ATIME: %u", get_atime()); | ||||||
|  |   ESP_LOGCONFIG(TAG, "  ASTEP: %u", get_astep()); | ||||||
|  |  | ||||||
|  |   LOG_SENSOR("  ", "F1", this->f1_); | ||||||
|  |   LOG_SENSOR("  ", "F2", this->f2_); | ||||||
|  |   LOG_SENSOR("  ", "F3", this->f3_); | ||||||
|  |   LOG_SENSOR("  ", "F4", this->f4_); | ||||||
|  |   LOG_SENSOR("  ", "F5", this->f5_); | ||||||
|  |   LOG_SENSOR("  ", "F6", this->f6_); | ||||||
|  |   LOG_SENSOR("  ", "F7", this->f7_); | ||||||
|  |   LOG_SENSOR("  ", "F8", this->f8_); | ||||||
|  |   LOG_SENSOR("  ", "Clear", this->clear_); | ||||||
|  |   LOG_SENSOR("  ", "NIR", this->nir_); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | float AS7341Component::get_setup_priority() const { return setup_priority::DATA; } | ||||||
|  |  | ||||||
|  | void AS7341Component::update() { | ||||||
|  |   this->read_channels(this->channel_readings_); | ||||||
|  |  | ||||||
|  |   if (this->f1_ != nullptr) { | ||||||
|  |     this->f1_->publish_state(this->channel_readings_[0]); | ||||||
|  |   } | ||||||
|  |   if (this->f2_ != nullptr) { | ||||||
|  |     this->f2_->publish_state(this->channel_readings_[1]); | ||||||
|  |   } | ||||||
|  |   if (this->f3_ != nullptr) { | ||||||
|  |     this->f3_->publish_state(this->channel_readings_[2]); | ||||||
|  |   } | ||||||
|  |   if (this->f4_ != nullptr) { | ||||||
|  |     this->f4_->publish_state(this->channel_readings_[3]); | ||||||
|  |   } | ||||||
|  |   if (this->f5_ != nullptr) { | ||||||
|  |     this->f5_->publish_state(this->channel_readings_[6]); | ||||||
|  |   } | ||||||
|  |   if (this->f6_ != nullptr) { | ||||||
|  |     this->f6_->publish_state(this->channel_readings_[7]); | ||||||
|  |   } | ||||||
|  |   if (this->f7_ != nullptr) { | ||||||
|  |     this->f7_->publish_state(this->channel_readings_[8]); | ||||||
|  |   } | ||||||
|  |   if (this->f8_ != nullptr) { | ||||||
|  |     this->f8_->publish_state(this->channel_readings_[9]); | ||||||
|  |   } | ||||||
|  |   if (this->clear_ != nullptr) { | ||||||
|  |     this->clear_->publish_state(this->channel_readings_[10]); | ||||||
|  |   } | ||||||
|  |   if (this->nir_ != nullptr) { | ||||||
|  |     this->nir_->publish_state(this->channel_readings_[11]); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | AS7341Gain AS7341Component::get_gain() { | ||||||
|  |   uint8_t data; | ||||||
|  |   this->read_byte(AS7341_CFG1, &data); | ||||||
|  |   return (AS7341Gain) data; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint8_t AS7341Component::get_atime() { | ||||||
|  |   uint8_t data; | ||||||
|  |   this->read_byte(AS7341_ATIME, &data); | ||||||
|  |   return data; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint16_t AS7341Component::get_astep() { | ||||||
|  |   uint16_t data; | ||||||
|  |   this->read_byte_16(AS7341_ASTEP, &data); | ||||||
|  |   return this->swap_bytes(data); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool AS7341Component::setup_gain(AS7341Gain gain) { return this->write_byte(AS7341_CFG1, gain); } | ||||||
|  |  | ||||||
|  | bool AS7341Component::setup_atime(uint8_t atime) { return this->write_byte(AS7341_ATIME, atime); } | ||||||
|  |  | ||||||
|  | bool AS7341Component::setup_astep(uint16_t astep) { return this->write_byte_16(AS7341_ASTEP, swap_bytes(astep)); } | ||||||
|  |  | ||||||
|  | bool AS7341Component::read_channels(uint16_t *data) { | ||||||
|  |   this->set_smux_low_channels(true); | ||||||
|  |   this->enable_spectral_measurement(true); | ||||||
|  |   this->wait_for_data(); | ||||||
|  |   bool low_success = this->read_bytes_16(AS7341_CH0_DATA_L, data, 6); | ||||||
|  |  | ||||||
|  |   this->set_smux_low_channels(false); | ||||||
|  |   this->enable_spectral_measurement(true); | ||||||
|  |   this->wait_for_data(); | ||||||
|  |   bool high_sucess = this->read_bytes_16(AS7341_CH0_DATA_L, &data[6], 6); | ||||||
|  |  | ||||||
|  |   return low_success && high_sucess; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void AS7341Component::set_smux_low_channels(bool enable) { | ||||||
|  |   this->enable_spectral_measurement(false); | ||||||
|  |   this->set_smux_command(AS7341_SMUX_CMD_WRITE); | ||||||
|  |  | ||||||
|  |   if (enable) { | ||||||
|  |     this->configure_smux_low_channels(); | ||||||
|  |  | ||||||
|  |   } else { | ||||||
|  |     this->configure_smux_high_channels(); | ||||||
|  |   } | ||||||
|  |   this->enable_smux(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool AS7341Component::set_smux_command(AS7341SmuxCommand command) { | ||||||
|  |   uint8_t data = command << 3;  // Write to bits 4:3 of the register | ||||||
|  |   return this->write_byte(AS7341_CFG6, data); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void AS7341Component::configure_smux_low_channels() { | ||||||
|  |   // SMUX Config for F1,F2,F3,F4,NIR,Clear | ||||||
|  |   this->write_byte(0x00, 0x30);  // F3 left set to ADC2 | ||||||
|  |   this->write_byte(0x01, 0x01);  // F1 left set to ADC0 | ||||||
|  |   this->write_byte(0x02, 0x00);  // Reserved or disabled | ||||||
|  |   this->write_byte(0x03, 0x00);  // F8 left disabled | ||||||
|  |   this->write_byte(0x04, 0x00);  // F6 left disabled | ||||||
|  |   this->write_byte(0x05, 0x42);  // F4 left connected to ADC3/f2 left connected to ADC1 | ||||||
|  |   this->write_byte(0x06, 0x00);  // F5 left disbled | ||||||
|  |   this->write_byte(0x07, 0x00);  // F7 left disbled | ||||||
|  |   this->write_byte(0x08, 0x50);  // CLEAR connected to ADC4 | ||||||
|  |   this->write_byte(0x09, 0x00);  // F5 right disabled | ||||||
|  |   this->write_byte(0x0A, 0x00);  // F7 right disabled | ||||||
|  |   this->write_byte(0x0B, 0x00);  // Reserved or disabled | ||||||
|  |   this->write_byte(0x0C, 0x20);  // F2 right connected to ADC1 | ||||||
|  |   this->write_byte(0x0D, 0x04);  // F4 right connected to ADC3 | ||||||
|  |   this->write_byte(0x0E, 0x00);  // F6/F8 right disabled | ||||||
|  |   this->write_byte(0x0F, 0x30);  // F3 right connected to AD2 | ||||||
|  |   this->write_byte(0x10, 0x01);  // F1 right connected to AD0 | ||||||
|  |   this->write_byte(0x11, 0x50);  // CLEAR right connected to AD4 | ||||||
|  |   this->write_byte(0x12, 0x00);  // Reserved or disabled | ||||||
|  |   this->write_byte(0x13, 0x06);  // NIR connected to ADC5 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void AS7341Component::configure_smux_high_channels() { | ||||||
|  |   // SMUX Config for F5,F6,F7,F8,NIR,Clear | ||||||
|  |   this->write_byte(0x00, 0x00);  // F3 left disable | ||||||
|  |   this->write_byte(0x01, 0x00);  // F1 left disable | ||||||
|  |   this->write_byte(0x02, 0x00);  // reserved/disable | ||||||
|  |   this->write_byte(0x03, 0x40);  // F8 left connected to ADC3 | ||||||
|  |   this->write_byte(0x04, 0x02);  // F6 left connected to ADC1 | ||||||
|  |   this->write_byte(0x05, 0x00);  // F4/ F2 disabled | ||||||
|  |   this->write_byte(0x06, 0x10);  // F5 left connected to ADC0 | ||||||
|  |   this->write_byte(0x07, 0x03);  // F7 left connected to ADC2 | ||||||
|  |   this->write_byte(0x08, 0x50);  // CLEAR Connected to ADC4 | ||||||
|  |   this->write_byte(0x09, 0x10);  // F5 right connected to ADC0 | ||||||
|  |   this->write_byte(0x0A, 0x03);  // F7 right connected to ADC2 | ||||||
|  |   this->write_byte(0x0B, 0x00);  // Reserved or disabled | ||||||
|  |   this->write_byte(0x0C, 0x00);  // F2 right disabled | ||||||
|  |   this->write_byte(0x0D, 0x00);  // F4 right disabled | ||||||
|  |   this->write_byte(0x0E, 0x24);  // F8 right connected to ADC2/ F6 right connected to ADC1 | ||||||
|  |   this->write_byte(0x0F, 0x00);  // F3 right disabled | ||||||
|  |   this->write_byte(0x10, 0x00);  // F1 right disabled | ||||||
|  |   this->write_byte(0x11, 0x50);  // CLEAR right connected to AD4 | ||||||
|  |   this->write_byte(0x12, 0x00);  // Reserved or disabled | ||||||
|  |   this->write_byte(0x13, 0x06);  // NIR connected to ADC5 | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool AS7341Component::enable_smux() { | ||||||
|  |   this->set_register_bit(AS7341_ENABLE, 4); | ||||||
|  |  | ||||||
|  |   uint16_t timeout = 1000; | ||||||
|  |   for (uint16_t time = 0; time < timeout; time++) { | ||||||
|  |     // The SMUXEN bit is cleared once the SMUX operation is finished | ||||||
|  |     bool smuxen = this->read_register_bit(AS7341_ENABLE, 4); | ||||||
|  |     if (!smuxen) { | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     delay(1); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool AS7341Component::wait_for_data() { | ||||||
|  |   uint16_t timeout = 1000; | ||||||
|  |   for (uint16_t time = 0; time < timeout; time++) { | ||||||
|  |     if (this->is_data_ready()) { | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     delay(1); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool AS7341Component::is_data_ready() { return this->read_register_bit(AS7341_STATUS2, 6); } | ||||||
|  |  | ||||||
|  | bool AS7341Component::enable_power(bool enable) { return this->write_register_bit(AS7341_ENABLE, enable, 0); } | ||||||
|  |  | ||||||
|  | bool AS7341Component::enable_spectral_measurement(bool enable) { | ||||||
|  |   return this->write_register_bit(AS7341_ENABLE, enable, 1); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool AS7341Component::read_register_bit(uint8_t address, uint8_t bit_position) { | ||||||
|  |   uint8_t data; | ||||||
|  |   this->read_byte(address, &data); | ||||||
|  |   bool bit = (data & (1 << bit_position)) > 0; | ||||||
|  |   return bit; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool AS7341Component::write_register_bit(uint8_t address, bool value, uint8_t bit_position) { | ||||||
|  |   if (value) { | ||||||
|  |     return this->set_register_bit(address, bit_position); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return this->clear_register_bit(address, bit_position); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool AS7341Component::set_register_bit(uint8_t address, uint8_t bit_position) { | ||||||
|  |   uint8_t data; | ||||||
|  |   this->read_byte(address, &data); | ||||||
|  |   data |= (1 << bit_position); | ||||||
|  |   return this->write_byte(address, data); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool AS7341Component::clear_register_bit(uint8_t address, uint8_t bit_position) { | ||||||
|  |   uint8_t data; | ||||||
|  |   this->read_byte(address, &data); | ||||||
|  |   data &= ~(1 << bit_position); | ||||||
|  |   return this->write_byte(address, data); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | uint16_t AS7341Component::swap_bytes(uint16_t data) { return (data >> 8) | (data << 8); } | ||||||
|  |  | ||||||
|  | }  // namespace as7341 | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										144
									
								
								esphome/components/as7341/as7341.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										144
									
								
								esphome/components/as7341/as7341.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,144 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "esphome/core/component.h" | ||||||
|  | #include "esphome/components/sensor/sensor.h" | ||||||
|  | #include "esphome/components/i2c/i2c.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace as7341 { | ||||||
|  |  | ||||||
|  | static const uint8_t AS7341_CHIP_ID = 0X09; | ||||||
|  |  | ||||||
|  | static const uint8_t AS7341_CONFIG = 0x70; | ||||||
|  | static const uint8_t AS7341_LED = 0x74; | ||||||
|  |  | ||||||
|  | static const uint8_t AS7341_ENABLE = 0x80; | ||||||
|  | static const uint8_t AS7341_ATIME = 0x81; | ||||||
|  |  | ||||||
|  | static const uint8_t AS7341_WTIME = 0x83; | ||||||
|  |  | ||||||
|  | static const uint8_t AS7341_AUXID = 0x90; | ||||||
|  | static const uint8_t AS7341_REVID = 0x91; | ||||||
|  | static const uint8_t AS7341_ID = 0x92; | ||||||
|  | static const uint8_t AS7341_STATUS = 0x93; | ||||||
|  |  | ||||||
|  | static const uint8_t AS7341_CH0_DATA_L = 0x95; | ||||||
|  | static const uint8_t AS7341_CH0_DATA_H = 0x96; | ||||||
|  | static const uint8_t AS7341_CH1_DATA_L = 0x97; | ||||||
|  | static const uint8_t AS7341_CH1_DATA_H = 0x98; | ||||||
|  | static const uint8_t AS7341_CH2_DATA_L = 0x99; | ||||||
|  | static const uint8_t AS7341_CH2_DATA_H = 0x9A; | ||||||
|  | static const uint8_t AS7341_CH3_DATA_L = 0x9B; | ||||||
|  | static const uint8_t AS7341_CH3_DATA_H = 0x9C; | ||||||
|  | static const uint8_t AS7341_CH4_DATA_L = 0x9D; | ||||||
|  | static const uint8_t AS7341_CH4_DATA_H = 0x9E; | ||||||
|  | static const uint8_t AS7341_CH5_DATA_L = 0x9F; | ||||||
|  | static const uint8_t AS7341_CH5_DATA_H = 0xA0; | ||||||
|  |  | ||||||
|  | static const uint8_t AS7341_STATUS2 = 0xA3; | ||||||
|  |  | ||||||
|  | static const uint8_t AS7341_CFG1 = 0xAA;  ///< Controls ADC Gain | ||||||
|  |  | ||||||
|  | static const uint8_t AS7341_CFG6 = 0xAF;  // Stores SMUX command | ||||||
|  | static const uint8_t AS7341_CFG9 = 0xB2;  // Config for system interrupts (SMUX, Flicker detection) | ||||||
|  |  | ||||||
|  | static const uint8_t AS7341_ASTEP = 0xCA;      // LSB | ||||||
|  | static const uint8_t AS7341_ASTEP_MSB = 0xCB;  // MSB | ||||||
|  |  | ||||||
|  | enum AS7341AdcChannel { | ||||||
|  |   AS7341_ADC_CHANNEL_0, | ||||||
|  |   AS7341_ADC_CHANNEL_1, | ||||||
|  |   AS7341_ADC_CHANNEL_2, | ||||||
|  |   AS7341_ADC_CHANNEL_3, | ||||||
|  |   AS7341_ADC_CHANNEL_4, | ||||||
|  |   AS7341_ADC_CHANNEL_5, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | enum AS7341SmuxCommand { | ||||||
|  |   AS7341_SMUX_CMD_ROM_RESET,  ///< ROM code initialization of SMUX | ||||||
|  |   AS7341_SMUX_CMD_READ,       ///< Read SMUX configuration to RAM from SMUX chain | ||||||
|  |   AS7341_SMUX_CMD_WRITE,      ///< Write SMUX configuration from RAM to SMUX chain | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | enum AS7341Gain { | ||||||
|  |   AS7341_GAIN_0_5X, | ||||||
|  |   AS7341_GAIN_1X, | ||||||
|  |   AS7341_GAIN_2X, | ||||||
|  |   AS7341_GAIN_4X, | ||||||
|  |   AS7341_GAIN_8X, | ||||||
|  |   AS7341_GAIN_16X, | ||||||
|  |   AS7341_GAIN_32X, | ||||||
|  |   AS7341_GAIN_64X, | ||||||
|  |   AS7341_GAIN_128X, | ||||||
|  |   AS7341_GAIN_256X, | ||||||
|  |   AS7341_GAIN_512X, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class AS7341Component : public PollingComponent, public i2c::I2CDevice { | ||||||
|  |  public: | ||||||
|  |   void setup() override; | ||||||
|  |   void dump_config() override; | ||||||
|  |   float get_setup_priority() const override; | ||||||
|  |   void update() override; | ||||||
|  |  | ||||||
|  |   void set_f1_sensor(sensor::Sensor *f1_sensor) { this->f1_ = f1_sensor; } | ||||||
|  |   void set_f2_sensor(sensor::Sensor *f2_sensor) { f2_ = f2_sensor; } | ||||||
|  |   void set_f3_sensor(sensor::Sensor *f3_sensor) { f3_ = f3_sensor; } | ||||||
|  |   void set_f4_sensor(sensor::Sensor *f4_sensor) { f4_ = f4_sensor; } | ||||||
|  |   void set_f5_sensor(sensor::Sensor *f5_sensor) { f5_ = f5_sensor; } | ||||||
|  |   void set_f6_sensor(sensor::Sensor *f6_sensor) { f6_ = f6_sensor; } | ||||||
|  |   void set_f7_sensor(sensor::Sensor *f7_sensor) { f7_ = f7_sensor; } | ||||||
|  |   void set_f8_sensor(sensor::Sensor *f8_sensor) { f8_ = f8_sensor; } | ||||||
|  |   void set_clear_sensor(sensor::Sensor *clear_sensor) { clear_ = clear_sensor; } | ||||||
|  |   void set_nir_sensor(sensor::Sensor *nir_sensor) { nir_ = nir_sensor; } | ||||||
|  |  | ||||||
|  |   void set_gain(AS7341Gain gain) { gain_ = gain; } | ||||||
|  |   void set_atime(uint8_t atime) { atime_ = atime; } | ||||||
|  |   void set_astep(uint16_t astep) { astep_ = astep; } | ||||||
|  |  | ||||||
|  |   AS7341Gain get_gain(); | ||||||
|  |   uint8_t get_atime(); | ||||||
|  |   uint16_t get_astep(); | ||||||
|  |   bool setup_gain(AS7341Gain gain); | ||||||
|  |   bool setup_atime(uint8_t atime); | ||||||
|  |   bool setup_astep(uint16_t astep); | ||||||
|  |  | ||||||
|  |   uint16_t read_channel(AS7341AdcChannel channel); | ||||||
|  |   bool read_channels(uint16_t *data); | ||||||
|  |   void set_smux_low_channels(bool enable); | ||||||
|  |   bool set_smux_command(AS7341SmuxCommand command); | ||||||
|  |   void configure_smux_low_channels(); | ||||||
|  |   void configure_smux_high_channels(); | ||||||
|  |   bool enable_smux(); | ||||||
|  |  | ||||||
|  |   bool wait_for_data(); | ||||||
|  |   bool is_data_ready(); | ||||||
|  |   bool enable_power(bool enable); | ||||||
|  |   bool enable_spectral_measurement(bool enable); | ||||||
|  |  | ||||||
|  |   bool read_register_bit(uint8_t address, uint8_t bit_position); | ||||||
|  |   bool write_register_bit(uint8_t address, bool value, uint8_t bit_position); | ||||||
|  |   bool set_register_bit(uint8_t address, uint8_t bit_position); | ||||||
|  |   bool clear_register_bit(uint8_t address, uint8_t bit_position); | ||||||
|  |   uint16_t swap_bytes(uint16_t data); | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   sensor::Sensor *f1_{nullptr}; | ||||||
|  |   sensor::Sensor *f2_{nullptr}; | ||||||
|  |   sensor::Sensor *f3_{nullptr}; | ||||||
|  |   sensor::Sensor *f4_{nullptr}; | ||||||
|  |   sensor::Sensor *f5_{nullptr}; | ||||||
|  |   sensor::Sensor *f6_{nullptr}; | ||||||
|  |   sensor::Sensor *f7_{nullptr}; | ||||||
|  |   sensor::Sensor *f8_{nullptr}; | ||||||
|  |   sensor::Sensor *clear_{nullptr}; | ||||||
|  |   sensor::Sensor *nir_{nullptr}; | ||||||
|  |  | ||||||
|  |   uint16_t astep_; | ||||||
|  |   AS7341Gain gain_; | ||||||
|  |   uint8_t atime_; | ||||||
|  |   uint16_t channel_readings_[12]; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace as7341 | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										112
									
								
								esphome/components/as7341/sensor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								esphome/components/as7341/sensor.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,112 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome.components import i2c, sensor | ||||||
|  | from esphome.const import ( | ||||||
|  |     CONF_GAIN, | ||||||
|  |     CONF_ID, | ||||||
|  |     DEVICE_CLASS_ILLUMINANCE, | ||||||
|  |     ICON_BRIGHTNESS_5, | ||||||
|  |     STATE_CLASS_MEASUREMENT, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | CODEOWNERS = ["@mrgnr"] | ||||||
|  | DEPENDENCIES = ["i2c"] | ||||||
|  |  | ||||||
|  | as7341_ns = cg.esphome_ns.namespace("as7341") | ||||||
|  |  | ||||||
|  | AS7341Component = as7341_ns.class_( | ||||||
|  |     "AS7341Component", cg.PollingComponent, i2c.I2CDevice | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | CONF_ATIME = "atime" | ||||||
|  | CONF_ASTEP = "astep" | ||||||
|  |  | ||||||
|  | CONF_F1 = "f1" | ||||||
|  | CONF_F2 = "f2" | ||||||
|  | CONF_F3 = "f3" | ||||||
|  | CONF_F4 = "f4" | ||||||
|  | CONF_F5 = "f5" | ||||||
|  | CONF_F6 = "f6" | ||||||
|  | CONF_F7 = "f7" | ||||||
|  | CONF_F8 = "f8" | ||||||
|  | CONF_CLEAR = "clear" | ||||||
|  | CONF_NIR = "nir" | ||||||
|  |  | ||||||
|  | UNIT_COUNTS = "#" | ||||||
|  |  | ||||||
|  | AS7341_GAIN = as7341_ns.enum("AS7341Gain") | ||||||
|  | GAIN_OPTIONS = { | ||||||
|  |     "X0.5": AS7341_GAIN.AS7341_GAIN_0_5X, | ||||||
|  |     "X1": AS7341_GAIN.AS7341_GAIN_1X, | ||||||
|  |     "X2": AS7341_GAIN.AS7341_GAIN_2X, | ||||||
|  |     "X4": AS7341_GAIN.AS7341_GAIN_4X, | ||||||
|  |     "X8": AS7341_GAIN.AS7341_GAIN_8X, | ||||||
|  |     "X16": AS7341_GAIN.AS7341_GAIN_16X, | ||||||
|  |     "X32": AS7341_GAIN.AS7341_GAIN_32X, | ||||||
|  |     "X64": AS7341_GAIN.AS7341_GAIN_64X, | ||||||
|  |     "X128": AS7341_GAIN.AS7341_GAIN_128X, | ||||||
|  |     "X256": AS7341_GAIN.AS7341_GAIN_256X, | ||||||
|  |     "X512": AS7341_GAIN.AS7341_GAIN_512X, | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | SENSOR_SCHEMA = sensor.sensor_schema( | ||||||
|  |     unit_of_measurement=UNIT_COUNTS, | ||||||
|  |     icon=ICON_BRIGHTNESS_5, | ||||||
|  |     accuracy_decimals=0, | ||||||
|  |     device_class=DEVICE_CLASS_ILLUMINANCE, | ||||||
|  |     state_class=STATE_CLASS_MEASUREMENT, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = ( | ||||||
|  |     cv.Schema( | ||||||
|  |         { | ||||||
|  |             cv.GenerateID(): cv.declare_id(AS7341Component), | ||||||
|  |             cv.Optional(CONF_F1): SENSOR_SCHEMA, | ||||||
|  |             cv.Optional(CONF_F2): SENSOR_SCHEMA, | ||||||
|  |             cv.Optional(CONF_F3): SENSOR_SCHEMA, | ||||||
|  |             cv.Optional(CONF_F4): SENSOR_SCHEMA, | ||||||
|  |             cv.Optional(CONF_F5): SENSOR_SCHEMA, | ||||||
|  |             cv.Optional(CONF_F6): SENSOR_SCHEMA, | ||||||
|  |             cv.Optional(CONF_F7): SENSOR_SCHEMA, | ||||||
|  |             cv.Optional(CONF_F8): SENSOR_SCHEMA, | ||||||
|  |             cv.Optional(CONF_CLEAR): SENSOR_SCHEMA, | ||||||
|  |             cv.Optional(CONF_NIR): SENSOR_SCHEMA, | ||||||
|  |             cv.Optional(CONF_GAIN, default="X8"): cv.enum(GAIN_OPTIONS), | ||||||
|  |             cv.Optional(CONF_ATIME, default=29): cv.int_range(min=0, max=255), | ||||||
|  |             cv.Optional(CONF_ASTEP, default=599): cv.int_range(min=0, max=65534), | ||||||
|  |         } | ||||||
|  |     ) | ||||||
|  |     .extend(cv.polling_component_schema("60s")) | ||||||
|  |     .extend(i2c.i2c_device_schema(0x39)) | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | SENSORS = { | ||||||
|  |     CONF_F1: "set_f1_sensor", | ||||||
|  |     CONF_F2: "set_f2_sensor", | ||||||
|  |     CONF_F3: "set_f3_sensor", | ||||||
|  |     CONF_F4: "set_f4_sensor", | ||||||
|  |     CONF_F5: "set_f5_sensor", | ||||||
|  |     CONF_F6: "set_f6_sensor", | ||||||
|  |     CONF_F7: "set_f7_sensor", | ||||||
|  |     CONF_F8: "set_f8_sensor", | ||||||
|  |     CONF_CLEAR: "set_clear_sensor", | ||||||
|  |     CONF_NIR: "set_nir_sensor", | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def to_code(config): | ||||||
|  |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|  |     await cg.register_component(var, config) | ||||||
|  |     await i2c.register_i2c_device(var, config) | ||||||
|  |  | ||||||
|  |     cg.add(var.set_gain(config[CONF_GAIN])) | ||||||
|  |     cg.add(var.set_atime(config[CONF_ATIME])) | ||||||
|  |     cg.add(var.set_astep(config[CONF_ASTEP])) | ||||||
|  |  | ||||||
|  |     for conf_id, set_sensor_func in SENSORS.items(): | ||||||
|  |         if conf_id in config: | ||||||
|  |             sens = await sensor.new_sensor(config[conf_id]) | ||||||
|  |             cg.add(getattr(var, set_sensor_func)(sens)) | ||||||
| @@ -439,6 +439,32 @@ sensor: | |||||||
|     state_topic: hi/me |     state_topic: hi/me | ||||||
|     retain: false |     retain: false | ||||||
|     availability: |     availability: | ||||||
|  |   - platform: as7341 | ||||||
|  |     update_interval: 15s | ||||||
|  |     gain: X8 | ||||||
|  |     atime: 120 | ||||||
|  |     astep: 99 | ||||||
|  |     f1: | ||||||
|  |       name: F1 | ||||||
|  |     f2: | ||||||
|  |       name: F2 | ||||||
|  |     f3: | ||||||
|  |       name: F3 | ||||||
|  |     f4: | ||||||
|  |       name: F4 | ||||||
|  |     f5: | ||||||
|  |       name: F5 | ||||||
|  |     f6: | ||||||
|  |       name: F6 | ||||||
|  |     f7: | ||||||
|  |       name: F7 | ||||||
|  |     f8: | ||||||
|  |       name: F8 | ||||||
|  |     clear: | ||||||
|  |       name: Clear | ||||||
|  |     nir: | ||||||
|  |       name: NIR | ||||||
|  |     i2c_id: i2c_bus | ||||||
|   - platform: atm90e32 |   - platform: atm90e32 | ||||||
|     cs_pin: 5 |     cs_pin: 5 | ||||||
|     phase_a: |     phase_a: | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user