mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	Adding support for Airthings Wave Gen2 (#8460)
Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
		| @@ -1 +1 @@ | ||||
| CODEOWNERS = ["@jeromelaban"] | ||||
| CODEOWNERS = ["@jeromelaban", "@precurse"] | ||||
|   | ||||
| @@ -73,11 +73,29 @@ void AirthingsWavePlus::dump_config() { | ||||
|   LOG_SENSOR("  ", "Illuminance", this->illuminance_sensor_); | ||||
| } | ||||
|  | ||||
| AirthingsWavePlus::AirthingsWavePlus() { | ||||
|   this->service_uuid_ = espbt::ESPBTUUID::from_raw(SERVICE_UUID); | ||||
|   this->sensors_data_characteristic_uuid_ = espbt::ESPBTUUID::from_raw(CHARACTERISTIC_UUID); | ||||
| void AirthingsWavePlus::setup() { | ||||
|   const char *service_uuid; | ||||
|   const char *characteristic_uuid; | ||||
|   const char *access_control_point_characteristic_uuid; | ||||
|  | ||||
|   // Change UUIDs for Wave Radon Gen2 | ||||
|   switch (this->wave_device_type_) { | ||||
|     case WaveDeviceType::WAVE_GEN2: | ||||
|       service_uuid = SERVICE_UUID_WAVE_RADON_GEN2; | ||||
|       characteristic_uuid = CHARACTERISTIC_UUID_WAVE_RADON_GEN2; | ||||
|       access_control_point_characteristic_uuid = ACCESS_CONTROL_POINT_CHARACTERISTIC_UUID_WAVE_RADON_GEN2; | ||||
|       break; | ||||
|     default: | ||||
|       // Wave Plus | ||||
|       service_uuid = SERVICE_UUID; | ||||
|       characteristic_uuid = CHARACTERISTIC_UUID; | ||||
|       access_control_point_characteristic_uuid = ACCESS_CONTROL_POINT_CHARACTERISTIC_UUID; | ||||
|   } | ||||
|  | ||||
|   this->service_uuid_ = espbt::ESPBTUUID::from_raw(service_uuid); | ||||
|   this->sensors_data_characteristic_uuid_ = espbt::ESPBTUUID::from_raw(characteristic_uuid); | ||||
|   this->access_control_point_characteristic_uuid_ = | ||||
|       espbt::ESPBTUUID::from_raw(ACCESS_CONTROL_POINT_CHARACTERISTIC_UUID); | ||||
|       espbt::ESPBTUUID::from_raw(access_control_point_characteristic_uuid); | ||||
| } | ||||
|  | ||||
| }  // namespace airthings_wave_plus | ||||
|   | ||||
| @@ -9,13 +9,20 @@ namespace airthings_wave_plus { | ||||
|  | ||||
| namespace espbt = esphome::esp32_ble_tracker; | ||||
|  | ||||
| enum WaveDeviceType : uint8_t { WAVE_PLUS = 0, WAVE_GEN2 = 1 }; | ||||
|  | ||||
| static const char *const SERVICE_UUID = "b42e1c08-ade7-11e4-89d3-123b93f75cba"; | ||||
| static const char *const CHARACTERISTIC_UUID = "b42e2a68-ade7-11e4-89d3-123b93f75cba"; | ||||
| static const char *const ACCESS_CONTROL_POINT_CHARACTERISTIC_UUID = "b42e2d06-ade7-11e4-89d3-123b93f75cba"; | ||||
|  | ||||
| static const char *const SERVICE_UUID_WAVE_RADON_GEN2 = "b42e4a8e-ade7-11e4-89d3-123b93f75cba"; | ||||
| static const char *const CHARACTERISTIC_UUID_WAVE_RADON_GEN2 = "b42e4dcc-ade7-11e4-89d3-123b93f75cba"; | ||||
| static const char *const ACCESS_CONTROL_POINT_CHARACTERISTIC_UUID_WAVE_RADON_GEN2 = | ||||
|     "b42e50d8-ade7-11e4-89d3-123b93f75cba"; | ||||
|  | ||||
| class AirthingsWavePlus : public airthings_wave_base::AirthingsWaveBase { | ||||
|  public: | ||||
|   AirthingsWavePlus(); | ||||
|   void setup() override; | ||||
|  | ||||
|   void dump_config() override; | ||||
|  | ||||
| @@ -23,12 +30,14 @@ class AirthingsWavePlus : public airthings_wave_base::AirthingsWaveBase { | ||||
|   void set_radon_long_term(sensor::Sensor *radon_long_term) { radon_long_term_sensor_ = radon_long_term; } | ||||
|   void set_co2(sensor::Sensor *co2) { co2_sensor_ = co2; } | ||||
|   void set_illuminance(sensor::Sensor *illuminance) { illuminance_sensor_ = illuminance; } | ||||
|   void set_device_type(WaveDeviceType wave_device_type) { wave_device_type_ = wave_device_type; } | ||||
|  | ||||
|  protected: | ||||
|   bool is_valid_radon_value_(uint16_t radon); | ||||
|   bool is_valid_co2_value_(uint16_t co2); | ||||
|  | ||||
|   void read_sensors(uint8_t *raw_value, uint16_t value_len) override; | ||||
|   WaveDeviceType wave_device_type_{WaveDeviceType::WAVE_PLUS}; | ||||
|  | ||||
|   sensor::Sensor *radon_sensor_{nullptr}; | ||||
|   sensor::Sensor *radon_long_term_sensor_{nullptr}; | ||||
|   | ||||
| @@ -7,6 +7,7 @@ from esphome.const import ( | ||||
|     CONF_ILLUMINANCE, | ||||
|     CONF_RADON, | ||||
|     CONF_RADON_LONG_TERM, | ||||
|     CONF_TVOC, | ||||
|     DEVICE_CLASS_CARBON_DIOXIDE, | ||||
|     DEVICE_CLASS_ILLUMINANCE, | ||||
|     ICON_RADIOACTIVE, | ||||
| @@ -15,6 +16,7 @@ from esphome.const import ( | ||||
|     UNIT_LUX, | ||||
|     UNIT_PARTS_PER_MILLION, | ||||
| ) | ||||
| from esphome.types import ConfigType | ||||
|  | ||||
| DEPENDENCIES = airthings_wave_base.DEPENDENCIES | ||||
|  | ||||
| @@ -25,35 +27,59 @@ AirthingsWavePlus = airthings_wave_plus_ns.class_( | ||||
|     "AirthingsWavePlus", airthings_wave_base.AirthingsWaveBase | ||||
| ) | ||||
|  | ||||
| CONF_DEVICE_TYPE = "device_type" | ||||
| WaveDeviceType = airthings_wave_plus_ns.enum("WaveDeviceType") | ||||
| DEVICE_TYPES = { | ||||
|     "WAVE_PLUS": WaveDeviceType.WAVE_PLUS, | ||||
|     "WAVE_GEN2": WaveDeviceType.WAVE_GEN2, | ||||
| } | ||||
|  | ||||
| CONFIG_SCHEMA = airthings_wave_base.BASE_SCHEMA.extend( | ||||
|     { | ||||
|         cv.GenerateID(): cv.declare_id(AirthingsWavePlus), | ||||
|         cv.Optional(CONF_RADON): sensor.sensor_schema( | ||||
|             unit_of_measurement=UNIT_BECQUEREL_PER_CUBIC_METER, | ||||
|             icon=ICON_RADIOACTIVE, | ||||
|             accuracy_decimals=0, | ||||
|             state_class=STATE_CLASS_MEASUREMENT, | ||||
|         ), | ||||
|         cv.Optional(CONF_RADON_LONG_TERM): sensor.sensor_schema( | ||||
|             unit_of_measurement=UNIT_BECQUEREL_PER_CUBIC_METER, | ||||
|             icon=ICON_RADIOACTIVE, | ||||
|             accuracy_decimals=0, | ||||
|             state_class=STATE_CLASS_MEASUREMENT, | ||||
|         ), | ||||
|         cv.Optional(CONF_CO2): sensor.sensor_schema( | ||||
|             unit_of_measurement=UNIT_PARTS_PER_MILLION, | ||||
|             accuracy_decimals=0, | ||||
|             device_class=DEVICE_CLASS_CARBON_DIOXIDE, | ||||
|             state_class=STATE_CLASS_MEASUREMENT, | ||||
|         ), | ||||
|         cv.Optional(CONF_ILLUMINANCE): sensor.sensor_schema( | ||||
|             unit_of_measurement=UNIT_LUX, | ||||
|             accuracy_decimals=0, | ||||
|             device_class=DEVICE_CLASS_ILLUMINANCE, | ||||
|             state_class=STATE_CLASS_MEASUREMENT, | ||||
|         ), | ||||
|     } | ||||
|  | ||||
| def validate_wave_gen2_config(config: ConfigType) -> ConfigType: | ||||
|     """Validate that Wave Gen2 devices don't have CO2 or TVOC sensors.""" | ||||
|     if config[CONF_DEVICE_TYPE] == "WAVE_GEN2": | ||||
|         if CONF_CO2 in config: | ||||
|             raise cv.Invalid("Wave Gen2 devices do not support CO2 sensor") | ||||
|         # Check for TVOC in the base schema config | ||||
|         if CONF_TVOC in config: | ||||
|             raise cv.Invalid("Wave Gen2 devices do not support TVOC sensor") | ||||
|     return config | ||||
|  | ||||
|  | ||||
| CONFIG_SCHEMA = cv.All( | ||||
|     airthings_wave_base.BASE_SCHEMA.extend( | ||||
|         { | ||||
|             cv.GenerateID(): cv.declare_id(AirthingsWavePlus), | ||||
|             cv.Optional(CONF_RADON): sensor.sensor_schema( | ||||
|                 unit_of_measurement=UNIT_BECQUEREL_PER_CUBIC_METER, | ||||
|                 icon=ICON_RADIOACTIVE, | ||||
|                 accuracy_decimals=0, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ), | ||||
|             cv.Optional(CONF_RADON_LONG_TERM): sensor.sensor_schema( | ||||
|                 unit_of_measurement=UNIT_BECQUEREL_PER_CUBIC_METER, | ||||
|                 icon=ICON_RADIOACTIVE, | ||||
|                 accuracy_decimals=0, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ), | ||||
|             cv.Optional(CONF_CO2): sensor.sensor_schema( | ||||
|                 unit_of_measurement=UNIT_PARTS_PER_MILLION, | ||||
|                 accuracy_decimals=0, | ||||
|                 device_class=DEVICE_CLASS_CARBON_DIOXIDE, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ), | ||||
|             cv.Optional(CONF_ILLUMINANCE): sensor.sensor_schema( | ||||
|                 unit_of_measurement=UNIT_LUX, | ||||
|                 accuracy_decimals=0, | ||||
|                 device_class=DEVICE_CLASS_ILLUMINANCE, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|             ), | ||||
|             cv.Optional(CONF_DEVICE_TYPE, default="WAVE_PLUS"): cv.enum( | ||||
|                 DEVICE_TYPES, upper=True | ||||
|             ), | ||||
|         } | ||||
|     ), | ||||
|     validate_wave_gen2_config, | ||||
| ) | ||||
|  | ||||
|  | ||||
| @@ -73,3 +99,4 @@ async def to_code(config): | ||||
|     if config_illuminance := config.get(CONF_ILLUMINANCE): | ||||
|         sens = await sensor.new_sensor(config_illuminance) | ||||
|         cg.add(var.set_illuminance(sens)) | ||||
|     cg.add(var.set_device_type(config[CONF_DEVICE_TYPE])) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user