mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	airthings_wave: refactor to eliminate code duplication (#4910)
This commit is contained in:
		
				
					committed by
					
						 Jesse Hills
						Jesse Hills
					
				
			
			
				
	
			
			
			
						parent
						
							98e3426769
						
					
				
				
					commit
					244a212592
				
			| @@ -17,6 +17,7 @@ esphome/components/adc/* @esphome/core | |||||||
| esphome/components/adc128s102/* @DeerMaximum | esphome/components/adc128s102/* @DeerMaximum | ||||||
| esphome/components/addressable_light/* @justfalter | esphome/components/addressable_light/* @justfalter | ||||||
| esphome/components/airthings_ble/* @jeromelaban | esphome/components/airthings_ble/* @jeromelaban | ||||||
|  | esphome/components/airthings_wave_base/* @jeromelaban @ncareau | ||||||
| esphome/components/airthings_wave_mini/* @ncareau | esphome/components/airthings_wave_mini/* @ncareau | ||||||
| esphome/components/airthings_wave_plus/* @jeromelaban | esphome/components/airthings_wave_plus/* @jeromelaban | ||||||
| esphome/components/alarm_control_panel/* @grahambrown11 | esphome/components/alarm_control_panel/* @grahambrown11 | ||||||
|   | |||||||
							
								
								
									
										81
									
								
								esphome/components/airthings_wave_base/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								esphome/components/airthings_wave_base/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,81 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome.components import sensor, ble_client | ||||||
|  |  | ||||||
|  | from esphome.const import ( | ||||||
|  |     DEVICE_CLASS_HUMIDITY, | ||||||
|  |     DEVICE_CLASS_TEMPERATURE, | ||||||
|  |     DEVICE_CLASS_PRESSURE, | ||||||
|  |     STATE_CLASS_MEASUREMENT, | ||||||
|  |     UNIT_PERCENT, | ||||||
|  |     UNIT_CELSIUS, | ||||||
|  |     UNIT_HECTOPASCAL, | ||||||
|  |     CONF_HUMIDITY, | ||||||
|  |     CONF_TVOC, | ||||||
|  |     CONF_PRESSURE, | ||||||
|  |     CONF_TEMPERATURE, | ||||||
|  |     UNIT_PARTS_PER_BILLION, | ||||||
|  |     ICON_RADIATOR, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | CODEOWNERS = ["@ncareau", "@jeromelaban"] | ||||||
|  |  | ||||||
|  | DEPENDENCIES = ["ble_client"] | ||||||
|  |  | ||||||
|  | airthings_wave_base_ns = cg.esphome_ns.namespace("airthings_wave_base") | ||||||
|  | AirthingsWaveBase = airthings_wave_base_ns.class_( | ||||||
|  |     "AirthingsWaveBase", cg.PollingComponent, ble_client.BLEClientNode | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | BASE_SCHEMA = ( | ||||||
|  |     sensor.SENSOR_SCHEMA.extend( | ||||||
|  |         { | ||||||
|  |             cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( | ||||||
|  |                 unit_of_measurement=UNIT_PERCENT, | ||||||
|  |                 device_class=DEVICE_CLASS_HUMIDITY, | ||||||
|  |                 state_class=STATE_CLASS_MEASUREMENT, | ||||||
|  |                 accuracy_decimals=0, | ||||||
|  |             ), | ||||||
|  |             cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( | ||||||
|  |                 unit_of_measurement=UNIT_CELSIUS, | ||||||
|  |                 accuracy_decimals=2, | ||||||
|  |                 device_class=DEVICE_CLASS_TEMPERATURE, | ||||||
|  |                 state_class=STATE_CLASS_MEASUREMENT, | ||||||
|  |             ), | ||||||
|  |             cv.Optional(CONF_PRESSURE): sensor.sensor_schema( | ||||||
|  |                 unit_of_measurement=UNIT_HECTOPASCAL, | ||||||
|  |                 accuracy_decimals=1, | ||||||
|  |                 device_class=DEVICE_CLASS_PRESSURE, | ||||||
|  |                 state_class=STATE_CLASS_MEASUREMENT, | ||||||
|  |             ), | ||||||
|  |             cv.Optional(CONF_TVOC): sensor.sensor_schema( | ||||||
|  |                 unit_of_measurement=UNIT_PARTS_PER_BILLION, | ||||||
|  |                 icon=ICON_RADIATOR, | ||||||
|  |                 accuracy_decimals=0, | ||||||
|  |                 state_class=STATE_CLASS_MEASUREMENT, | ||||||
|  |             ), | ||||||
|  |         } | ||||||
|  |     ) | ||||||
|  |     .extend(cv.polling_component_schema("5min")) | ||||||
|  |     .extend(ble_client.BLE_CLIENT_SCHEMA) | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def wave_base_to_code(var, config): | ||||||
|  |     await cg.register_component(var, config) | ||||||
|  |  | ||||||
|  |     await ble_client.register_ble_node(var, config) | ||||||
|  |  | ||||||
|  |     if CONF_HUMIDITY in config: | ||||||
|  |         sens = await sensor.new_sensor(config[CONF_HUMIDITY]) | ||||||
|  |         cg.add(var.set_humidity(sens)) | ||||||
|  |     if CONF_TEMPERATURE in config: | ||||||
|  |         sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) | ||||||
|  |         cg.add(var.set_temperature(sens)) | ||||||
|  |     if CONF_PRESSURE in config: | ||||||
|  |         sens = await sensor.new_sensor(config[CONF_PRESSURE]) | ||||||
|  |         cg.add(var.set_pressure(sens)) | ||||||
|  |     if CONF_TVOC in config: | ||||||
|  |         sens = await sensor.new_sensor(config[CONF_TVOC]) | ||||||
|  |         cg.add(var.set_tvoc(sens)) | ||||||
| @@ -0,0 +1,83 @@ | |||||||
|  | #include "airthings_wave_base.h" | ||||||
|  |  | ||||||
|  | #ifdef USE_ESP32 | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace airthings_wave_base { | ||||||
|  |  | ||||||
|  | static const char *const TAG = "airthings_wave_base"; | ||||||
|  |  | ||||||
|  | void AirthingsWaveBase::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, | ||||||
|  |                                             esp_ble_gattc_cb_param_t *param) { | ||||||
|  |   switch (event) { | ||||||
|  |     case ESP_GATTC_OPEN_EVT: { | ||||||
|  |       if (param->open.status == ESP_GATT_OK) { | ||||||
|  |         ESP_LOGI(TAG, "Connected successfully!"); | ||||||
|  |       } | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     case ESP_GATTC_DISCONNECT_EVT: { | ||||||
|  |       ESP_LOGW(TAG, "Disconnected!"); | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     case ESP_GATTC_SEARCH_CMPL_EVT: { | ||||||
|  |       this->handle_ = 0; | ||||||
|  |       auto *chr = this->parent()->get_characteristic(this->service_uuid_, this->sensors_data_characteristic_uuid_); | ||||||
|  |       if (chr == nullptr) { | ||||||
|  |         ESP_LOGW(TAG, "No sensor characteristic found at service %s char %s", this->service_uuid_.to_string().c_str(), | ||||||
|  |                  this->sensors_data_characteristic_uuid_.to_string().c_str()); | ||||||
|  |         break; | ||||||
|  |       } | ||||||
|  |       this->handle_ = chr->handle; | ||||||
|  |       this->node_state = esp32_ble_tracker::ClientState::ESTABLISHED; | ||||||
|  |  | ||||||
|  |       this->request_read_values_(); | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     case ESP_GATTC_READ_CHAR_EVT: { | ||||||
|  |       if (param->read.conn_id != this->parent()->get_conn_id()) | ||||||
|  |         break; | ||||||
|  |       if (param->read.status != ESP_GATT_OK) { | ||||||
|  |         ESP_LOGW(TAG, "Error reading char at handle %d, status=%d", param->read.handle, param->read.status); | ||||||
|  |         break; | ||||||
|  |       } | ||||||
|  |       if (param->read.handle == this->handle_) { | ||||||
|  |         this->read_sensors(param->read.value, param->read.value_len); | ||||||
|  |       } | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     default: | ||||||
|  |       break; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool AirthingsWaveBase::is_valid_voc_value_(uint16_t voc) { return 0 <= voc && voc <= 16383; } | ||||||
|  |  | ||||||
|  | void AirthingsWaveBase::update() { | ||||||
|  |   if (this->node_state != esp32_ble_tracker::ClientState::ESTABLISHED) { | ||||||
|  |     if (!this->parent()->enabled) { | ||||||
|  |       ESP_LOGW(TAG, "Reconnecting to device"); | ||||||
|  |       this->parent()->set_enabled(true); | ||||||
|  |       this->parent()->connect(); | ||||||
|  |     } else { | ||||||
|  |       ESP_LOGW(TAG, "Connection in progress"); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void AirthingsWaveBase::request_read_values_() { | ||||||
|  |   auto status = esp_ble_gattc_read_char(this->parent()->get_gattc_if(), this->parent()->get_conn_id(), this->handle_, | ||||||
|  |                                         ESP_GATT_AUTH_REQ_NONE); | ||||||
|  |   if (status) { | ||||||
|  |     ESP_LOGW(TAG, "Error sending read request for sensor, status=%d", status); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace airthings_wave_base | ||||||
|  | }  // namespace esphome | ||||||
|  |  | ||||||
|  | #endif  // USE_ESP32 | ||||||
							
								
								
									
										50
									
								
								esphome/components/airthings_wave_base/airthings_wave_base.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								esphome/components/airthings_wave_base/airthings_wave_base.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,50 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #ifdef USE_ESP32 | ||||||
|  |  | ||||||
|  | #include <esp_gattc_api.h> | ||||||
|  | #include <algorithm> | ||||||
|  | #include <iterator> | ||||||
|  | #include "esphome/components/ble_client/ble_client.h" | ||||||
|  | #include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h" | ||||||
|  | #include "esphome/components/sensor/sensor.h" | ||||||
|  | #include "esphome/core/component.h" | ||||||
|  | #include "esphome/core/log.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace airthings_wave_base { | ||||||
|  |  | ||||||
|  | class AirthingsWaveBase : public PollingComponent, public ble_client::BLEClientNode { | ||||||
|  |  public: | ||||||
|  |   AirthingsWaveBase() = default; | ||||||
|  |  | ||||||
|  |   void update() override; | ||||||
|  |  | ||||||
|  |   void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, | ||||||
|  |                            esp_ble_gattc_cb_param_t *param) override; | ||||||
|  |  | ||||||
|  |   void set_temperature(sensor::Sensor *temperature) { temperature_sensor_ = temperature; } | ||||||
|  |   void set_humidity(sensor::Sensor *humidity) { humidity_sensor_ = humidity; } | ||||||
|  |   void set_pressure(sensor::Sensor *pressure) { pressure_sensor_ = pressure; } | ||||||
|  |   void set_tvoc(sensor::Sensor *tvoc) { tvoc_sensor_ = tvoc; } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   bool is_valid_voc_value_(uint16_t voc); | ||||||
|  |  | ||||||
|  |   virtual void read_sensors(uint8_t *value, uint16_t value_len) = 0; | ||||||
|  |   void request_read_values_(); | ||||||
|  |  | ||||||
|  |   sensor::Sensor *temperature_sensor_{nullptr}; | ||||||
|  |   sensor::Sensor *humidity_sensor_{nullptr}; | ||||||
|  |   sensor::Sensor *pressure_sensor_{nullptr}; | ||||||
|  |   sensor::Sensor *tvoc_sensor_{nullptr}; | ||||||
|  |  | ||||||
|  |   uint16_t handle_; | ||||||
|  |   esp32_ble_tracker::ESPBTUUID service_uuid_; | ||||||
|  |   esp32_ble_tracker::ESPBTUUID sensors_data_characteristic_uuid_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace airthings_wave_base | ||||||
|  | }  // namespace esphome | ||||||
|  |  | ||||||
|  | #endif  // USE_ESP32 | ||||||
| @@ -7,105 +7,47 @@ namespace airthings_wave_mini { | |||||||
|  |  | ||||||
| static const char *const TAG = "airthings_wave_mini"; | static const char *const TAG = "airthings_wave_mini"; | ||||||
|  |  | ||||||
| void AirthingsWaveMini::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, | void AirthingsWaveMini::read_sensors(uint8_t *raw_value, uint16_t value_len) { | ||||||
|                                             esp_ble_gattc_cb_param_t *param) { |  | ||||||
|   switch (event) { |  | ||||||
|     case ESP_GATTC_OPEN_EVT: { |  | ||||||
|       if (param->open.status == ESP_GATT_OK) { |  | ||||||
|         ESP_LOGI(TAG, "Connected successfully!"); |  | ||||||
|       } |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     case ESP_GATTC_DISCONNECT_EVT: { |  | ||||||
|       ESP_LOGW(TAG, "Disconnected!"); |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     case ESP_GATTC_SEARCH_CMPL_EVT: { |  | ||||||
|       this->handle_ = 0; |  | ||||||
|       auto *chr = this->parent()->get_characteristic(service_uuid_, sensors_data_characteristic_uuid_); |  | ||||||
|       if (chr == nullptr) { |  | ||||||
|         ESP_LOGW(TAG, "No sensor characteristic found at service %s char %s", service_uuid_.to_string().c_str(), |  | ||||||
|                  sensors_data_characteristic_uuid_.to_string().c_str()); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       this->handle_ = chr->handle; |  | ||||||
|       this->node_state = esp32_ble_tracker::ClientState::ESTABLISHED; |  | ||||||
|  |  | ||||||
|       request_read_values_(); |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     case ESP_GATTC_READ_CHAR_EVT: { |  | ||||||
|       if (param->read.conn_id != this->parent()->get_conn_id()) |  | ||||||
|         break; |  | ||||||
|       if (param->read.status != ESP_GATT_OK) { |  | ||||||
|         ESP_LOGW(TAG, "Error reading char at handle %d, status=%d", param->read.handle, param->read.status); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       if (param->read.handle == this->handle_) { |  | ||||||
|         read_sensors_(param->read.value, param->read.value_len); |  | ||||||
|       } |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     default: |  | ||||||
|       break; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void AirthingsWaveMini::read_sensors_(uint8_t *raw_value, uint16_t value_len) { |  | ||||||
|   auto *value = (WaveMiniReadings *) raw_value; |   auto *value = (WaveMiniReadings *) raw_value; | ||||||
|  |  | ||||||
|   if (sizeof(WaveMiniReadings) <= value_len) { |   if (sizeof(WaveMiniReadings) <= value_len) { | ||||||
|  |     if (this->humidity_sensor_ != nullptr) { | ||||||
|       this->humidity_sensor_->publish_state(value->humidity / 100.0f); |       this->humidity_sensor_->publish_state(value->humidity / 100.0f); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (this->pressure_sensor_ != nullptr) { | ||||||
|       this->pressure_sensor_->publish_state(value->pressure / 50.0f); |       this->pressure_sensor_->publish_state(value->pressure / 50.0f); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (this->temperature_sensor_ != nullptr) { | ||||||
|       this->temperature_sensor_->publish_state(value->temperature / 100.0f - 273.15f); |       this->temperature_sensor_->publish_state(value->temperature / 100.0f - 273.15f); | ||||||
|     if (is_valid_voc_value_(value->voc)) { |     } | ||||||
|  |  | ||||||
|  |     if ((this->tvoc_sensor_ != nullptr) && this->is_valid_voc_value_(value->voc)) { | ||||||
|       this->tvoc_sensor_->publish_state(value->voc); |       this->tvoc_sensor_->publish_state(value->voc); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     // This instance must not stay connected |     // This instance must not stay connected | ||||||
|     // so other clients can connect to it (e.g. the |     // so other clients can connect to it (e.g. the | ||||||
|     // mobile app). |     // mobile app). | ||||||
|     parent()->set_enabled(false); |     this->parent()->set_enabled(false); | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| bool AirthingsWaveMini::is_valid_voc_value_(uint16_t voc) { return 0 <= voc && voc <= 16383; } |  | ||||||
|  |  | ||||||
| void AirthingsWaveMini::update() { |  | ||||||
|   if (this->node_state != esp32_ble_tracker::ClientState::ESTABLISHED) { |  | ||||||
|     if (!parent()->enabled) { |  | ||||||
|       ESP_LOGW(TAG, "Reconnecting to device"); |  | ||||||
|       parent()->set_enabled(true); |  | ||||||
|       parent()->connect(); |  | ||||||
|     } else { |  | ||||||
|       ESP_LOGW(TAG, "Connection in progress"); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void AirthingsWaveMini::request_read_values_() { |  | ||||||
|   auto status = esp_ble_gattc_read_char(this->parent()->get_gattc_if(), this->parent()->get_conn_id(), this->handle_, |  | ||||||
|                                         ESP_GATT_AUTH_REQ_NONE); |  | ||||||
|   if (status) { |  | ||||||
|     ESP_LOGW(TAG, "Error sending read request for sensor, status=%d", status); |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
| void AirthingsWaveMini::dump_config() { | void AirthingsWaveMini::dump_config() { | ||||||
|  |   // these really don't belong here, but there doesn't seem to be a | ||||||
|  |   // practical way to have the base class use LOG_SENSOR and include | ||||||
|  |   // the TAG from this component | ||||||
|   LOG_SENSOR("  ", "Humidity", this->humidity_sensor_); |   LOG_SENSOR("  ", "Humidity", this->humidity_sensor_); | ||||||
|   LOG_SENSOR("  ", "Temperature", this->temperature_sensor_); |   LOG_SENSOR("  ", "Temperature", this->temperature_sensor_); | ||||||
|   LOG_SENSOR("  ", "Pressure", this->pressure_sensor_); |   LOG_SENSOR("  ", "Pressure", this->pressure_sensor_); | ||||||
|   LOG_SENSOR("  ", "TVOC", this->tvoc_sensor_); |   LOG_SENSOR("  ", "TVOC", this->tvoc_sensor_); | ||||||
| } | } | ||||||
|  |  | ||||||
| AirthingsWaveMini::AirthingsWaveMini() | AirthingsWaveMini::AirthingsWaveMini() { | ||||||
|     : PollingComponent(10000), |   this->service_uuid_ = esp32_ble_tracker::ESPBTUUID::from_raw(SERVICE_UUID); | ||||||
|       service_uuid_(esp32_ble_tracker::ESPBTUUID::from_raw(SERVICE_UUID)), |   this->sensors_data_characteristic_uuid_ = esp32_ble_tracker::ESPBTUUID::from_raw(CHARACTERISTIC_UUID); | ||||||
|       sensors_data_characteristic_uuid_(esp32_ble_tracker::ESPBTUUID::from_raw(CHARACTERISTIC_UUID)) {} | } | ||||||
|  |  | ||||||
| }  // namespace airthings_wave_mini | }  // namespace airthings_wave_mini | ||||||
| }  // namespace esphome | }  // namespace esphome | ||||||
|   | |||||||
| @@ -2,14 +2,7 @@ | |||||||
|  |  | ||||||
| #ifdef USE_ESP32 | #ifdef USE_ESP32 | ||||||
|  |  | ||||||
| #include <esp_gattc_api.h> | #include "esphome/components/airthings_wave_base/airthings_wave_base.h" | ||||||
| #include <algorithm> |  | ||||||
| #include <iterator> |  | ||||||
| #include "esphome/components/ble_client/ble_client.h" |  | ||||||
| #include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h" |  | ||||||
| #include "esphome/components/sensor/sensor.h" |  | ||||||
| #include "esphome/core/component.h" |  | ||||||
| #include "esphome/core/log.h" |  | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace airthings_wave_mini { | namespace airthings_wave_mini { | ||||||
| @@ -17,35 +10,14 @@ namespace airthings_wave_mini { | |||||||
| static const char *const SERVICE_UUID = "b42e3882-ade7-11e4-89d3-123b93f75cba"; | static const char *const SERVICE_UUID = "b42e3882-ade7-11e4-89d3-123b93f75cba"; | ||||||
| static const char *const CHARACTERISTIC_UUID = "b42e3b98-ade7-11e4-89d3-123b93f75cba"; | static const char *const CHARACTERISTIC_UUID = "b42e3b98-ade7-11e4-89d3-123b93f75cba"; | ||||||
|  |  | ||||||
| class AirthingsWaveMini : public PollingComponent, public ble_client::BLEClientNode { | class AirthingsWaveMini : public airthings_wave_base::AirthingsWaveBase { | ||||||
|  public: |  public: | ||||||
|   AirthingsWaveMini(); |   AirthingsWaveMini(); | ||||||
|  |  | ||||||
|   void dump_config() override; |   void dump_config() override; | ||||||
|   void update() override; |  | ||||||
|  |  | ||||||
|   void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, |  | ||||||
|                            esp_ble_gattc_cb_param_t *param) override; |  | ||||||
|  |  | ||||||
|   void set_temperature(sensor::Sensor *temperature) { temperature_sensor_ = temperature; } |  | ||||||
|   void set_humidity(sensor::Sensor *humidity) { humidity_sensor_ = humidity; } |  | ||||||
|   void set_pressure(sensor::Sensor *pressure) { pressure_sensor_ = pressure; } |  | ||||||
|   void set_tvoc(sensor::Sensor *tvoc) { tvoc_sensor_ = tvoc; } |  | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   bool is_valid_voc_value_(uint16_t voc); |   void read_sensors(uint8_t *value, uint16_t value_len) override; | ||||||
|  |  | ||||||
|   void read_sensors_(uint8_t *value, uint16_t value_len); |  | ||||||
|   void request_read_values_(); |  | ||||||
|  |  | ||||||
|   sensor::Sensor *temperature_sensor_{nullptr}; |  | ||||||
|   sensor::Sensor *humidity_sensor_{nullptr}; |  | ||||||
|   sensor::Sensor *pressure_sensor_{nullptr}; |  | ||||||
|   sensor::Sensor *tvoc_sensor_{nullptr}; |  | ||||||
|  |  | ||||||
|   uint16_t handle_; |  | ||||||
|   esp32_ble_tracker::ESPBTUUID service_uuid_; |  | ||||||
|   esp32_ble_tracker::ESPBTUUID sensors_data_characteristic_uuid_; |  | ||||||
|  |  | ||||||
|   struct WaveMiniReadings { |   struct WaveMiniReadings { | ||||||
|     uint16_t unused01; |     uint16_t unused01; | ||||||
|   | |||||||
| @@ -1,82 +1,28 @@ | |||||||
| 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 sensor, ble_client | from esphome.components import airthings_wave_base | ||||||
|  |  | ||||||
| from esphome.const import ( | from esphome.const import ( | ||||||
|     DEVICE_CLASS_HUMIDITY, |  | ||||||
|     DEVICE_CLASS_TEMPERATURE, |  | ||||||
|     DEVICE_CLASS_PRESSURE, |  | ||||||
|     STATE_CLASS_MEASUREMENT, |  | ||||||
|     UNIT_PERCENT, |  | ||||||
|     UNIT_CELSIUS, |  | ||||||
|     UNIT_HECTOPASCAL, |  | ||||||
|     CONF_ID, |     CONF_ID, | ||||||
|     CONF_HUMIDITY, |  | ||||||
|     CONF_TVOC, |  | ||||||
|     CONF_PRESSURE, |  | ||||||
|     CONF_TEMPERATURE, |  | ||||||
|     UNIT_PARTS_PER_BILLION, |  | ||||||
|     ICON_RADIATOR, |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| DEPENDENCIES = ["ble_client"] | DEPENDENCIES = airthings_wave_base.DEPENDENCIES | ||||||
|  |  | ||||||
|  | AUTO_LOAD = ["airthings_wave_base"] | ||||||
|  |  | ||||||
| airthings_wave_mini_ns = cg.esphome_ns.namespace("airthings_wave_mini") | airthings_wave_mini_ns = cg.esphome_ns.namespace("airthings_wave_mini") | ||||||
| AirthingsWaveMini = airthings_wave_mini_ns.class_( | AirthingsWaveMini = airthings_wave_mini_ns.class_( | ||||||
|     "AirthingsWaveMini", cg.PollingComponent, ble_client.BLEClientNode |     "AirthingsWaveMini", airthings_wave_base.AirthingsWaveBase | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  |  | ||||||
| CONFIG_SCHEMA = cv.All( | CONFIG_SCHEMA = airthings_wave_base.BASE_SCHEMA.extend( | ||||||
|     cv.Schema( |  | ||||||
|     { |     { | ||||||
|         cv.GenerateID(): cv.declare_id(AirthingsWaveMini), |         cv.GenerateID(): cv.declare_id(AirthingsWaveMini), | ||||||
|             cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( |  | ||||||
|                 unit_of_measurement=UNIT_PERCENT, |  | ||||||
|                 device_class=DEVICE_CLASS_HUMIDITY, |  | ||||||
|                 state_class=STATE_CLASS_MEASUREMENT, |  | ||||||
|                 accuracy_decimals=2, |  | ||||||
|             ), |  | ||||||
|             cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( |  | ||||||
|                 unit_of_measurement=UNIT_CELSIUS, |  | ||||||
|                 accuracy_decimals=2, |  | ||||||
|                 device_class=DEVICE_CLASS_TEMPERATURE, |  | ||||||
|                 state_class=STATE_CLASS_MEASUREMENT, |  | ||||||
|             ), |  | ||||||
|             cv.Optional(CONF_PRESSURE): sensor.sensor_schema( |  | ||||||
|                 unit_of_measurement=UNIT_HECTOPASCAL, |  | ||||||
|                 accuracy_decimals=2, |  | ||||||
|                 device_class=DEVICE_CLASS_PRESSURE, |  | ||||||
|                 state_class=STATE_CLASS_MEASUREMENT, |  | ||||||
|             ), |  | ||||||
|             cv.Optional(CONF_TVOC): sensor.sensor_schema( |  | ||||||
|                 unit_of_measurement=UNIT_PARTS_PER_BILLION, |  | ||||||
|                 icon=ICON_RADIATOR, |  | ||||||
|                 accuracy_decimals=0, |  | ||||||
|                 state_class=STATE_CLASS_MEASUREMENT, |  | ||||||
|             ), |  | ||||||
|     } |     } | ||||||
|     ) |  | ||||||
|     .extend(cv.polling_component_schema("5min")) |  | ||||||
|     .extend(ble_client.BLE_CLIENT_SCHEMA), |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  |  | ||||||
| async def to_code(config): | async def to_code(config): | ||||||
|     var = cg.new_Pvariable(config[CONF_ID]) |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|     await cg.register_component(var, config) |     await airthings_wave_base.wave_base_to_code(var, config) | ||||||
|  |  | ||||||
|     await ble_client.register_ble_node(var, config) |  | ||||||
|  |  | ||||||
|     if CONF_HUMIDITY in config: |  | ||||||
|         sens = await sensor.new_sensor(config[CONF_HUMIDITY]) |  | ||||||
|         cg.add(var.set_humidity(sens)) |  | ||||||
|     if CONF_TEMPERATURE in config: |  | ||||||
|         sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) |  | ||||||
|         cg.add(var.set_temperature(sens)) |  | ||||||
|     if CONF_PRESSURE in config: |  | ||||||
|         sens = await sensor.new_sensor(config[CONF_PRESSURE]) |  | ||||||
|         cg.add(var.set_pressure(sens)) |  | ||||||
|     if CONF_TVOC in config: |  | ||||||
|         sens = await sensor.new_sensor(config[CONF_TVOC]) |  | ||||||
|         cg.add(var.set_tvoc(sens)) |  | ||||||
|   | |||||||
| @@ -7,55 +7,7 @@ namespace airthings_wave_plus { | |||||||
|  |  | ||||||
| static const char *const TAG = "airthings_wave_plus"; | static const char *const TAG = "airthings_wave_plus"; | ||||||
|  |  | ||||||
| void AirthingsWavePlus::gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, | void AirthingsWavePlus::read_sensors(uint8_t *raw_value, uint16_t value_len) { | ||||||
|                                             esp_ble_gattc_cb_param_t *param) { |  | ||||||
|   switch (event) { |  | ||||||
|     case ESP_GATTC_OPEN_EVT: { |  | ||||||
|       if (param->open.status == ESP_GATT_OK) { |  | ||||||
|         ESP_LOGI(TAG, "Connected successfully!"); |  | ||||||
|       } |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     case ESP_GATTC_DISCONNECT_EVT: { |  | ||||||
|       ESP_LOGW(TAG, "Disconnected!"); |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     case ESP_GATTC_SEARCH_CMPL_EVT: { |  | ||||||
|       this->handle_ = 0; |  | ||||||
|       auto *chr = this->parent()->get_characteristic(service_uuid_, sensors_data_characteristic_uuid_); |  | ||||||
|       if (chr == nullptr) { |  | ||||||
|         ESP_LOGW(TAG, "No sensor characteristic found at service %s char %s", service_uuid_.to_string().c_str(), |  | ||||||
|                  sensors_data_characteristic_uuid_.to_string().c_str()); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       this->handle_ = chr->handle; |  | ||||||
|       this->node_state = esp32_ble_tracker::ClientState::ESTABLISHED; |  | ||||||
|  |  | ||||||
|       request_read_values_(); |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     case ESP_GATTC_READ_CHAR_EVT: { |  | ||||||
|       if (param->read.conn_id != this->parent()->get_conn_id()) |  | ||||||
|         break; |  | ||||||
|       if (param->read.status != ESP_GATT_OK) { |  | ||||||
|         ESP_LOGW(TAG, "Error reading char at handle %d, status=%d", param->read.handle, param->read.status); |  | ||||||
|         break; |  | ||||||
|       } |  | ||||||
|       if (param->read.handle == this->handle_) { |  | ||||||
|         read_sensors_(param->read.value, param->read.value_len); |  | ||||||
|       } |  | ||||||
|       break; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|     default: |  | ||||||
|       break; |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void AirthingsWavePlus::read_sensors_(uint8_t *raw_value, uint16_t value_len) { |  | ||||||
|   auto *value = (WavePlusReadings *) raw_value; |   auto *value = (WavePlusReadings *) raw_value; | ||||||
|  |  | ||||||
|   if (sizeof(WavePlusReadings) <= value_len) { |   if (sizeof(WavePlusReadings) <= value_len) { | ||||||
| @@ -64,26 +16,38 @@ void AirthingsWavePlus::read_sensors_(uint8_t *raw_value, uint16_t value_len) { | |||||||
|     if (value->version == 1) { |     if (value->version == 1) { | ||||||
|       ESP_LOGD(TAG, "ambient light = %d", value->ambientLight); |       ESP_LOGD(TAG, "ambient light = %d", value->ambientLight); | ||||||
|  |  | ||||||
|  |       if (this->humidity_sensor_ != nullptr) { | ||||||
|         this->humidity_sensor_->publish_state(value->humidity / 2.0f); |         this->humidity_sensor_->publish_state(value->humidity / 2.0f); | ||||||
|       if (is_valid_radon_value_(value->radon)) { |       } | ||||||
|  |  | ||||||
|  |       if ((this->radon_sensor_ != nullptr) && this->is_valid_radon_value_(value->radon)) { | ||||||
|         this->radon_sensor_->publish_state(value->radon); |         this->radon_sensor_->publish_state(value->radon); | ||||||
|       } |       } | ||||||
|       if (is_valid_radon_value_(value->radon_lt)) { |  | ||||||
|  |       if ((this->radon_long_term_sensor_ != nullptr) && this->is_valid_radon_value_(value->radon_lt)) { | ||||||
|         this->radon_long_term_sensor_->publish_state(value->radon_lt); |         this->radon_long_term_sensor_->publish_state(value->radon_lt); | ||||||
|       } |       } | ||||||
|  |  | ||||||
|  |       if (this->temperature_sensor_ != nullptr) { | ||||||
|         this->temperature_sensor_->publish_state(value->temperature / 100.0f); |         this->temperature_sensor_->publish_state(value->temperature / 100.0f); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       if (this->pressure_sensor_ != nullptr) { | ||||||
|         this->pressure_sensor_->publish_state(value->pressure / 50.0f); |         this->pressure_sensor_->publish_state(value->pressure / 50.0f); | ||||||
|       if (is_valid_co2_value_(value->co2)) { |       } | ||||||
|  |  | ||||||
|  |       if ((this->co2_sensor_ != nullptr) && this->is_valid_co2_value_(value->co2)) { | ||||||
|         this->co2_sensor_->publish_state(value->co2); |         this->co2_sensor_->publish_state(value->co2); | ||||||
|       } |       } | ||||||
|       if (is_valid_voc_value_(value->voc)) { |  | ||||||
|  |       if ((this->tvoc_sensor_ != nullptr) && this->is_valid_voc_value_(value->voc)) { | ||||||
|         this->tvoc_sensor_->publish_state(value->voc); |         this->tvoc_sensor_->publish_state(value->voc); | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       // This instance must not stay connected |       // This instance must not stay connected | ||||||
|       // so other clients can connect to it (e.g. the |       // so other clients can connect to it (e.g. the | ||||||
|       // mobile app). |       // mobile app). | ||||||
|       parent()->set_enabled(false); |       this->parent()->set_enabled(false); | ||||||
|     } else { |     } else { | ||||||
|       ESP_LOGE(TAG, "Invalid payload version (%d != 1, newer version or not a Wave Plus?)", value->version); |       ESP_LOGE(TAG, "Invalid payload version (%d != 1, newer version or not a Wave Plus?)", value->version); | ||||||
|     } |     } | ||||||
| @@ -92,44 +56,26 @@ void AirthingsWavePlus::read_sensors_(uint8_t *raw_value, uint16_t value_len) { | |||||||
|  |  | ||||||
| bool AirthingsWavePlus::is_valid_radon_value_(uint16_t radon) { return 0 <= radon && radon <= 16383; } | bool AirthingsWavePlus::is_valid_radon_value_(uint16_t radon) { return 0 <= radon && radon <= 16383; } | ||||||
|  |  | ||||||
| bool AirthingsWavePlus::is_valid_voc_value_(uint16_t voc) { return 0 <= voc && voc <= 16383; } |  | ||||||
|  |  | ||||||
| bool AirthingsWavePlus::is_valid_co2_value_(uint16_t co2) { return 0 <= co2 && co2 <= 16383; } | bool AirthingsWavePlus::is_valid_co2_value_(uint16_t co2) { return 0 <= co2 && co2 <= 16383; } | ||||||
|  |  | ||||||
| void AirthingsWavePlus::update() { |  | ||||||
|   if (this->node_state != esp32_ble_tracker::ClientState::ESTABLISHED) { |  | ||||||
|     if (!parent()->enabled) { |  | ||||||
|       ESP_LOGW(TAG, "Reconnecting to device"); |  | ||||||
|       parent()->set_enabled(true); |  | ||||||
|       parent()->connect(); |  | ||||||
|     } else { |  | ||||||
|       ESP_LOGW(TAG, "Connection in progress"); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void AirthingsWavePlus::request_read_values_() { |  | ||||||
|   auto status = esp_ble_gattc_read_char(this->parent()->get_gattc_if(), this->parent()->get_conn_id(), this->handle_, |  | ||||||
|                                         ESP_GATT_AUTH_REQ_NONE); |  | ||||||
|   if (status) { |  | ||||||
|     ESP_LOGW(TAG, "Error sending read request for sensor, status=%d", status); |  | ||||||
|   } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| void AirthingsWavePlus::dump_config() { | void AirthingsWavePlus::dump_config() { | ||||||
|  |   // these really don't belong here, but there doesn't seem to be a | ||||||
|  |   // practical way to have the base class use LOG_SENSOR and include | ||||||
|  |   // the TAG from this component | ||||||
|   LOG_SENSOR("  ", "Humidity", this->humidity_sensor_); |   LOG_SENSOR("  ", "Humidity", this->humidity_sensor_); | ||||||
|   LOG_SENSOR("  ", "Radon", this->radon_sensor_); |  | ||||||
|   LOG_SENSOR("  ", "Radon Long Term", this->radon_long_term_sensor_); |  | ||||||
|   LOG_SENSOR("  ", "Temperature", this->temperature_sensor_); |   LOG_SENSOR("  ", "Temperature", this->temperature_sensor_); | ||||||
|   LOG_SENSOR("  ", "Pressure", this->pressure_sensor_); |   LOG_SENSOR("  ", "Pressure", this->pressure_sensor_); | ||||||
|   LOG_SENSOR("  ", "CO2", this->co2_sensor_); |  | ||||||
|   LOG_SENSOR("  ", "TVOC", this->tvoc_sensor_); |   LOG_SENSOR("  ", "TVOC", this->tvoc_sensor_); | ||||||
|  |  | ||||||
|  |   LOG_SENSOR("  ", "Radon", this->radon_sensor_); | ||||||
|  |   LOG_SENSOR("  ", "Radon Long Term", this->radon_long_term_sensor_); | ||||||
|  |   LOG_SENSOR("  ", "CO2", this->co2_sensor_); | ||||||
| } | } | ||||||
|  |  | ||||||
| AirthingsWavePlus::AirthingsWavePlus() | AirthingsWavePlus::AirthingsWavePlus() { | ||||||
|     : PollingComponent(10000), |   this->service_uuid_ = esp32_ble_tracker::ESPBTUUID::from_raw(SERVICE_UUID); | ||||||
|       service_uuid_(esp32_ble_tracker::ESPBTUUID::from_raw(SERVICE_UUID)), |   this->sensors_data_characteristic_uuid_ = esp32_ble_tracker::ESPBTUUID::from_raw(CHARACTERISTIC_UUID); | ||||||
|       sensors_data_characteristic_uuid_(esp32_ble_tracker::ESPBTUUID::from_raw(CHARACTERISTIC_UUID)) {} | } | ||||||
|  |  | ||||||
| }  // namespace airthings_wave_plus | }  // namespace airthings_wave_plus | ||||||
| }  // namespace esphome | }  // namespace esphome | ||||||
|   | |||||||
| @@ -2,14 +2,7 @@ | |||||||
|  |  | ||||||
| #ifdef USE_ESP32 | #ifdef USE_ESP32 | ||||||
|  |  | ||||||
| #include <esp_gattc_api.h> | #include "esphome/components/airthings_wave_base/airthings_wave_base.h" | ||||||
| #include <algorithm> |  | ||||||
| #include <iterator> |  | ||||||
| #include "esphome/components/ble_client/ble_client.h" |  | ||||||
| #include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h" |  | ||||||
| #include "esphome/components/sensor/sensor.h" |  | ||||||
| #include "esphome/core/component.h" |  | ||||||
| #include "esphome/core/log.h" |  | ||||||
|  |  | ||||||
| namespace esphome { | namespace esphome { | ||||||
| namespace airthings_wave_plus { | namespace airthings_wave_plus { | ||||||
| @@ -17,43 +10,25 @@ namespace airthings_wave_plus { | |||||||
| static const char *const SERVICE_UUID = "b42e1c08-ade7-11e4-89d3-123b93f75cba"; | 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 CHARACTERISTIC_UUID = "b42e2a68-ade7-11e4-89d3-123b93f75cba"; | ||||||
|  |  | ||||||
| class AirthingsWavePlus : public PollingComponent, public ble_client::BLEClientNode { | class AirthingsWavePlus : public airthings_wave_base::AirthingsWaveBase { | ||||||
|  public: |  public: | ||||||
|   AirthingsWavePlus(); |   AirthingsWavePlus(); | ||||||
|  |  | ||||||
|   void dump_config() override; |   void dump_config() override; | ||||||
|   void update() override; |  | ||||||
|  |  | ||||||
|   void gattc_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, |  | ||||||
|                            esp_ble_gattc_cb_param_t *param) override; |  | ||||||
|  |  | ||||||
|   void set_temperature(sensor::Sensor *temperature) { temperature_sensor_ = temperature; } |  | ||||||
|   void set_radon(sensor::Sensor *radon) { radon_sensor_ = radon; } |   void set_radon(sensor::Sensor *radon) { radon_sensor_ = radon; } | ||||||
|   void set_radon_long_term(sensor::Sensor *radon_long_term) { radon_long_term_sensor_ = radon_long_term; } |   void set_radon_long_term(sensor::Sensor *radon_long_term) { radon_long_term_sensor_ = radon_long_term; } | ||||||
|   void set_humidity(sensor::Sensor *humidity) { humidity_sensor_ = humidity; } |  | ||||||
|   void set_pressure(sensor::Sensor *pressure) { pressure_sensor_ = pressure; } |  | ||||||
|   void set_co2(sensor::Sensor *co2) { co2_sensor_ = co2; } |   void set_co2(sensor::Sensor *co2) { co2_sensor_ = co2; } | ||||||
|   void set_tvoc(sensor::Sensor *tvoc) { tvoc_sensor_ = tvoc; } |  | ||||||
|  |  | ||||||
|  protected: |  protected: | ||||||
|   bool is_valid_radon_value_(uint16_t radon); |   bool is_valid_radon_value_(uint16_t radon); | ||||||
|   bool is_valid_voc_value_(uint16_t voc); |  | ||||||
|   bool is_valid_co2_value_(uint16_t co2); |   bool is_valid_co2_value_(uint16_t co2); | ||||||
|  |  | ||||||
|   void read_sensors_(uint8_t *value, uint16_t value_len); |   void read_sensors(uint8_t *value, uint16_t value_len) override; | ||||||
|   void request_read_values_(); |  | ||||||
|  |  | ||||||
|   sensor::Sensor *temperature_sensor_{nullptr}; |  | ||||||
|   sensor::Sensor *radon_sensor_{nullptr}; |   sensor::Sensor *radon_sensor_{nullptr}; | ||||||
|   sensor::Sensor *radon_long_term_sensor_{nullptr}; |   sensor::Sensor *radon_long_term_sensor_{nullptr}; | ||||||
|   sensor::Sensor *humidity_sensor_{nullptr}; |  | ||||||
|   sensor::Sensor *pressure_sensor_{nullptr}; |  | ||||||
|   sensor::Sensor *co2_sensor_{nullptr}; |   sensor::Sensor *co2_sensor_{nullptr}; | ||||||
|   sensor::Sensor *tvoc_sensor_{nullptr}; |  | ||||||
|  |  | ||||||
|   uint16_t handle_; |  | ||||||
|   esp32_ble_tracker::ESPBTUUID service_uuid_; |  | ||||||
|   esp32_ble_tracker::ESPBTUUID sensors_data_characteristic_uuid_; |  | ||||||
|  |  | ||||||
|   struct WavePlusReadings { |   struct WavePlusReadings { | ||||||
|     uint8_t version; |     uint8_t version; | ||||||
|   | |||||||
| @@ -1,49 +1,32 @@ | |||||||
| 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 sensor, ble_client | from esphome.components import sensor, airthings_wave_base | ||||||
|  |  | ||||||
| from esphome.const import ( | from esphome.const import ( | ||||||
|     DEVICE_CLASS_CARBON_DIOXIDE, |     DEVICE_CLASS_CARBON_DIOXIDE, | ||||||
|     DEVICE_CLASS_HUMIDITY, |  | ||||||
|     DEVICE_CLASS_TEMPERATURE, |  | ||||||
|     DEVICE_CLASS_PRESSURE, |  | ||||||
|     STATE_CLASS_MEASUREMENT, |     STATE_CLASS_MEASUREMENT, | ||||||
|     UNIT_PERCENT, |  | ||||||
|     UNIT_CELSIUS, |  | ||||||
|     UNIT_HECTOPASCAL, |  | ||||||
|     ICON_RADIOACTIVE, |     ICON_RADIOACTIVE, | ||||||
|     CONF_ID, |     CONF_ID, | ||||||
|     CONF_RADON, |     CONF_RADON, | ||||||
|     CONF_RADON_LONG_TERM, |     CONF_RADON_LONG_TERM, | ||||||
|     CONF_HUMIDITY, |  | ||||||
|     CONF_TVOC, |  | ||||||
|     CONF_CO2, |     CONF_CO2, | ||||||
|     CONF_PRESSURE, |  | ||||||
|     CONF_TEMPERATURE, |  | ||||||
|     UNIT_BECQUEREL_PER_CUBIC_METER, |     UNIT_BECQUEREL_PER_CUBIC_METER, | ||||||
|     UNIT_PARTS_PER_MILLION, |     UNIT_PARTS_PER_MILLION, | ||||||
|     UNIT_PARTS_PER_BILLION, |  | ||||||
|     ICON_RADIATOR, |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
| DEPENDENCIES = ["ble_client"] | DEPENDENCIES = airthings_wave_base.DEPENDENCIES | ||||||
|  |  | ||||||
|  | AUTO_LOAD = ["airthings_wave_base"] | ||||||
|  |  | ||||||
| airthings_wave_plus_ns = cg.esphome_ns.namespace("airthings_wave_plus") | airthings_wave_plus_ns = cg.esphome_ns.namespace("airthings_wave_plus") | ||||||
| AirthingsWavePlus = airthings_wave_plus_ns.class_( | AirthingsWavePlus = airthings_wave_plus_ns.class_( | ||||||
|     "AirthingsWavePlus", cg.PollingComponent, ble_client.BLEClientNode |     "AirthingsWavePlus", airthings_wave_base.AirthingsWaveBase | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  |  | ||||||
| CONFIG_SCHEMA = cv.All( | CONFIG_SCHEMA = airthings_wave_base.BASE_SCHEMA.extend( | ||||||
|     cv.Schema( |  | ||||||
|     { |     { | ||||||
|         cv.GenerateID(): cv.declare_id(AirthingsWavePlus), |         cv.GenerateID(): cv.declare_id(AirthingsWavePlus), | ||||||
|             cv.Optional(CONF_HUMIDITY): sensor.sensor_schema( |  | ||||||
|                 unit_of_measurement=UNIT_PERCENT, |  | ||||||
|                 device_class=DEVICE_CLASS_HUMIDITY, |  | ||||||
|                 state_class=STATE_CLASS_MEASUREMENT, |  | ||||||
|                 accuracy_decimals=0, |  | ||||||
|             ), |  | ||||||
|         cv.Optional(CONF_RADON): sensor.sensor_schema( |         cv.Optional(CONF_RADON): sensor.sensor_schema( | ||||||
|             unit_of_measurement=UNIT_BECQUEREL_PER_CUBIC_METER, |             unit_of_measurement=UNIT_BECQUEREL_PER_CUBIC_METER, | ||||||
|             icon=ICON_RADIOACTIVE, |             icon=ICON_RADIOACTIVE, | ||||||
| @@ -56,61 +39,26 @@ CONFIG_SCHEMA = cv.All( | |||||||
|             accuracy_decimals=0, |             accuracy_decimals=0, | ||||||
|             state_class=STATE_CLASS_MEASUREMENT, |             state_class=STATE_CLASS_MEASUREMENT, | ||||||
|         ), |         ), | ||||||
|             cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( |  | ||||||
|                 unit_of_measurement=UNIT_CELSIUS, |  | ||||||
|                 accuracy_decimals=2, |  | ||||||
|                 device_class=DEVICE_CLASS_TEMPERATURE, |  | ||||||
|                 state_class=STATE_CLASS_MEASUREMENT, |  | ||||||
|             ), |  | ||||||
|             cv.Optional(CONF_PRESSURE): sensor.sensor_schema( |  | ||||||
|                 unit_of_measurement=UNIT_HECTOPASCAL, |  | ||||||
|                 accuracy_decimals=1, |  | ||||||
|                 device_class=DEVICE_CLASS_PRESSURE, |  | ||||||
|                 state_class=STATE_CLASS_MEASUREMENT, |  | ||||||
|             ), |  | ||||||
|         cv.Optional(CONF_CO2): sensor.sensor_schema( |         cv.Optional(CONF_CO2): sensor.sensor_schema( | ||||||
|             unit_of_measurement=UNIT_PARTS_PER_MILLION, |             unit_of_measurement=UNIT_PARTS_PER_MILLION, | ||||||
|             accuracy_decimals=0, |             accuracy_decimals=0, | ||||||
|             device_class=DEVICE_CLASS_CARBON_DIOXIDE, |             device_class=DEVICE_CLASS_CARBON_DIOXIDE, | ||||||
|             state_class=STATE_CLASS_MEASUREMENT, |             state_class=STATE_CLASS_MEASUREMENT, | ||||||
|         ), |         ), | ||||||
|             cv.Optional(CONF_TVOC): sensor.sensor_schema( |  | ||||||
|                 unit_of_measurement=UNIT_PARTS_PER_BILLION, |  | ||||||
|                 icon=ICON_RADIATOR, |  | ||||||
|                 accuracy_decimals=0, |  | ||||||
|                 state_class=STATE_CLASS_MEASUREMENT, |  | ||||||
|             ), |  | ||||||
|     } |     } | ||||||
|     ) |  | ||||||
|     .extend(cv.polling_component_schema("5min")) |  | ||||||
|     .extend(ble_client.BLE_CLIENT_SCHEMA), |  | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  |  | ||||||
| async def to_code(config): | async def to_code(config): | ||||||
|     var = cg.new_Pvariable(config[CONF_ID]) |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|     await cg.register_component(var, config) |     await airthings_wave_base.wave_base_to_code(var, config) | ||||||
|  |  | ||||||
|     await ble_client.register_ble_node(var, config) |  | ||||||
|  |  | ||||||
|     if CONF_HUMIDITY in config: |  | ||||||
|         sens = await sensor.new_sensor(config[CONF_HUMIDITY]) |  | ||||||
|         cg.add(var.set_humidity(sens)) |  | ||||||
|     if CONF_RADON in config: |     if CONF_RADON in config: | ||||||
|         sens = await sensor.new_sensor(config[CONF_RADON]) |         sens = await sensor.new_sensor(config[CONF_RADON]) | ||||||
|         cg.add(var.set_radon(sens)) |         cg.add(var.set_radon(sens)) | ||||||
|     if CONF_RADON_LONG_TERM in config: |     if CONF_RADON_LONG_TERM in config: | ||||||
|         sens = await sensor.new_sensor(config[CONF_RADON_LONG_TERM]) |         sens = await sensor.new_sensor(config[CONF_RADON_LONG_TERM]) | ||||||
|         cg.add(var.set_radon_long_term(sens)) |         cg.add(var.set_radon_long_term(sens)) | ||||||
|     if CONF_TEMPERATURE in config: |  | ||||||
|         sens = await sensor.new_sensor(config[CONF_TEMPERATURE]) |  | ||||||
|         cg.add(var.set_temperature(sens)) |  | ||||||
|     if CONF_PRESSURE in config: |  | ||||||
|         sens = await sensor.new_sensor(config[CONF_PRESSURE]) |  | ||||||
|         cg.add(var.set_pressure(sens)) |  | ||||||
|     if CONF_CO2 in config: |     if CONF_CO2 in config: | ||||||
|         sens = await sensor.new_sensor(config[CONF_CO2]) |         sens = await sensor.new_sensor(config[CONF_CO2]) | ||||||
|         cg.add(var.set_co2(sens)) |         cg.add(var.set_co2(sens)) | ||||||
|     if CONF_TVOC in config: |  | ||||||
|         sens = await sensor.new_sensor(config[CONF_TVOC]) |  | ||||||
|         cg.add(var.set_tvoc(sens)) |  | ||||||
|   | |||||||
| @@ -312,7 +312,8 @@ sensor: | |||||||
|     id: freezer_temp_source |     id: freezer_temp_source | ||||||
|     reference_voltage: 3.19 |     reference_voltage: 3.19 | ||||||
|     number: 0 |     number: 0 | ||||||
|   - platform: airthings_wave_plus |   - id: airthingswp | ||||||
|  |     platform: airthings_wave_plus | ||||||
|     ble_client_id: airthings01 |     ble_client_id: airthings01 | ||||||
|     update_interval: 5min |     update_interval: 5min | ||||||
|     temperature: |     temperature: | ||||||
| @@ -329,7 +330,8 @@ sensor: | |||||||
|       name: Wave Plus CO2 |       name: Wave Plus CO2 | ||||||
|     tvoc: |     tvoc: | ||||||
|       name: Wave Plus VOC |       name: Wave Plus VOC | ||||||
|   - platform: airthings_wave_mini |   - id: airthingswm | ||||||
|  |     platform: airthings_wave_mini | ||||||
|     ble_client_id: airthingsmini01 |     ble_client_id: airthingsmini01 | ||||||
|     update_interval: 5min |     update_interval: 5min | ||||||
|     temperature: |     temperature: | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user