mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-26 12:43:48 +00:00 
			
		
		
		
	Support for the AirThings Wave Plus (#1656)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
		| @@ -14,6 +14,8 @@ esphome/core/* @esphome/core | |||||||
| esphome/components/ac_dimmer/* @glmnet | esphome/components/ac_dimmer/* @glmnet | ||||||
| esphome/components/adc/* @esphome/core | esphome/components/adc/* @esphome/core | ||||||
| esphome/components/addressable_light/* @justfalter | esphome/components/addressable_light/* @justfalter | ||||||
|  | esphome/components/airthings_ble/* @jeromelaban | ||||||
|  | esphome/components/airthings_wave_plus/* @jeromelaban | ||||||
| esphome/components/am43/* @buxtronix | esphome/components/am43/* @buxtronix | ||||||
| esphome/components/am43/cover/* @buxtronix | esphome/components/am43/cover/* @buxtronix | ||||||
| esphome/components/animation/* @syndlex | esphome/components/animation/* @syndlex | ||||||
|   | |||||||
							
								
								
									
										23
									
								
								esphome/components/airthings_ble/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								esphome/components/airthings_ble/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome.components import esp32_ble_tracker | ||||||
|  | from esphome.const import CONF_ID | ||||||
|  |  | ||||||
|  | DEPENDENCIES = ["esp32_ble_tracker"] | ||||||
|  | CODEOWNERS = ["@jeromelaban"] | ||||||
|  |  | ||||||
|  | airthings_ble_ns = cg.esphome_ns.namespace("airthings_ble") | ||||||
|  | AirthingsListener = airthings_ble_ns.class_( | ||||||
|  |     "AirthingsListener", esp32_ble_tracker.ESPBTDeviceListener | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = cv.Schema( | ||||||
|  |     { | ||||||
|  |         cv.GenerateID(): cv.declare_id(AirthingsListener), | ||||||
|  |     } | ||||||
|  | ).extend(esp32_ble_tracker.ESP_BLE_DEVICE_SCHEMA) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def to_code(config): | ||||||
|  |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|  |     yield esp32_ble_tracker.register_ble_device(var, config) | ||||||
							
								
								
									
										33
									
								
								esphome/components/airthings_ble/airthings_listener.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								esphome/components/airthings_ble/airthings_listener.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | |||||||
|  | #include "airthings_listener.h" | ||||||
|  | #include "esphome/core/log.h" | ||||||
|  |  | ||||||
|  | #ifdef ARDUINO_ARCH_ESP32 | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace airthings_ble { | ||||||
|  |  | ||||||
|  | static const char *TAG = "airthings_ble"; | ||||||
|  |  | ||||||
|  | bool AirthingsListener::parse_device(const esp32_ble_tracker::ESPBTDevice &device) { | ||||||
|  |   for (auto &it : device.get_manufacturer_datas()) { | ||||||
|  |     if (it.uuid == esp32_ble_tracker::ESPBTUUID::from_uint32(0x0334)) { | ||||||
|  |       if (it.data.size() < 4) | ||||||
|  |         continue; | ||||||
|  |  | ||||||
|  |       uint32_t sn = it.data[0]; | ||||||
|  |       sn |= ((uint32_t) it.data[1] << 8); | ||||||
|  |       sn |= ((uint32_t) it.data[2] << 16); | ||||||
|  |       sn |= ((uint32_t) it.data[3] << 24); | ||||||
|  |  | ||||||
|  |       ESP_LOGD(TAG, "Found AirThings device Serial:%u (MAC: %s)", sn, device.address_str().c_str()); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return false; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace airthings_ble | ||||||
|  | }  // namespace esphome | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										20
									
								
								esphome/components/airthings_ble/airthings_listener.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								esphome/components/airthings_ble/airthings_listener.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #ifdef ARDUINO_ARCH_ESP32 | ||||||
|  |  | ||||||
|  | #include "esphome/core/component.h" | ||||||
|  | #include "esphome/components/esp32_ble_tracker/esp32_ble_tracker.h" | ||||||
|  | #include <BLEDevice.h> | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace airthings_ble { | ||||||
|  |  | ||||||
|  | class AirthingsListener : public esp32_ble_tracker::ESPBTDeviceListener { | ||||||
|  |  public: | ||||||
|  |   bool parse_device(const esp32_ble_tracker::ESPBTDevice &device) override; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace airthings_ble | ||||||
|  | }  // namespace esphome | ||||||
|  |  | ||||||
|  | #endif | ||||||
							
								
								
									
										1
									
								
								esphome/components/airthings_wave_plus/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								esphome/components/airthings_wave_plus/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | CODEOWNERS = ["@jeromelaban"] | ||||||
							
								
								
									
										142
									
								
								esphome/components/airthings_wave_plus/airthings_wave_plus.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								esphome/components/airthings_wave_plus/airthings_wave_plus.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,142 @@ | |||||||
|  | #include "airthings_wave_plus.h" | ||||||
|  |  | ||||||
|  | #ifdef ARDUINO_ARCH_ESP32 | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace airthings_wave_plus { | ||||||
|  |  | ||||||
|  | void AirthingsWavePlus::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(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 = espbt::ClientState::Established; | ||||||
|  |  | ||||||
|  |       request_read_values_(); | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     case ESP_GATTC_READ_CHAR_EVT: { | ||||||
|  |       if (param->read.conn_id != this->parent()->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; | ||||||
|  |  | ||||||
|  |   if (sizeof(WavePlusReadings) <= value_len) { | ||||||
|  |     ESP_LOGD(TAG, "version = %d", value->version); | ||||||
|  |  | ||||||
|  |     if (value->version == 1) { | ||||||
|  |       ESP_LOGD(TAG, "ambient light = %d", value->ambientLight); | ||||||
|  |  | ||||||
|  |       this->humidity_sensor_->publish_state(value->humidity / 2.0f); | ||||||
|  |       if (is_valid_radon_value_(value->radon)) { | ||||||
|  |         this->radon_sensor_->publish_state(value->radon); | ||||||
|  |       } | ||||||
|  |       if (is_valid_radon_value_(value->radon_lt)) { | ||||||
|  |         this->radon_long_term_sensor_->publish_state(value->radon_lt); | ||||||
|  |       } | ||||||
|  |       this->temperature_sensor_->publish_state(value->temperature / 100.0f); | ||||||
|  |       this->pressure_sensor_->publish_state(value->pressure / 50.0f); | ||||||
|  |       if (is_valid_co2_value_(value->co2)) { | ||||||
|  |         this->co2_sensor_->publish_state(value->co2); | ||||||
|  |       } | ||||||
|  |       if (is_valid_voc_value_(value->voc)) { | ||||||
|  |         this->tvoc_sensor_->publish_state(value->voc); | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       // This instance must not stay connected | ||||||
|  |       // so other clients can connect to it (e.g. the | ||||||
|  |       // mobile app). | ||||||
|  |       parent()->set_enabled(false); | ||||||
|  |     } else { | ||||||
|  |       ESP_LOGE(TAG, "Invalid payload version (%d != 1, newer version or not a Wave Plus?)", value->version); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool AirthingsWavePlus::is_valid_radon_value_(short radon) { return 0 <= radon && radon <= 16383; } | ||||||
|  |  | ||||||
|  | bool AirthingsWavePlus::is_valid_voc_value_(short voc) { return 0 <= voc && voc <= 16383; } | ||||||
|  |  | ||||||
|  | bool AirthingsWavePlus::is_valid_co2_value_(short co2) { return 0 <= co2 && co2 <= 16383; } | ||||||
|  |  | ||||||
|  | void AirthingsWavePlus::loop() {} | ||||||
|  |  | ||||||
|  | void AirthingsWavePlus::update() { | ||||||
|  |   if (this->node_state != espbt::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()->gattc_if, this->parent()->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() { | ||||||
|  |   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("  ", "Pressure", this->pressure_sensor_); | ||||||
|  |   LOG_SENSOR("  ", "CO2", this->co2_sensor_); | ||||||
|  |   LOG_SENSOR("  ", "TVOC", this->tvoc_sensor_); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | AirthingsWavePlus::AirthingsWavePlus() : PollingComponent(10000) { | ||||||
|  |   auto service_bt = *BLEUUID::fromString(std::string("b42e1c08-ade7-11e4-89d3-123b93f75cba")).getNative(); | ||||||
|  |   auto characteristic_bt = *BLEUUID::fromString(std::string("b42e2a68-ade7-11e4-89d3-123b93f75cba")).getNative(); | ||||||
|  |  | ||||||
|  |   service_uuid = espbt::ESPBTUUID::from_uuid(service_bt); | ||||||
|  |   sensors_data_characteristic_uuid = espbt::ESPBTUUID::from_uuid(characteristic_bt); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void AirthingsWavePlus::setup() {} | ||||||
|  |  | ||||||
|  | }  // namespace airthings_wave_plus | ||||||
|  | }  // namespace esphome | ||||||
|  |  | ||||||
|  | #endif  // ARDUINO_ARCH_ESP32 | ||||||
							
								
								
									
										79
									
								
								esphome/components/airthings_wave_plus/airthings_wave_plus.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								esphome/components/airthings_wave_plus/airthings_wave_plus.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,79 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "esphome/core/component.h" | ||||||
|  | #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/log.h" | ||||||
|  | #include <algorithm> | ||||||
|  | #include <iterator> | ||||||
|  |  | ||||||
|  | #ifdef ARDUINO_ARCH_ESP32 | ||||||
|  | #include <esp_gattc_api.h> | ||||||
|  | #include <BLEDevice.h> | ||||||
|  |  | ||||||
|  | using namespace esphome::ble_client; | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace airthings_wave_plus { | ||||||
|  |  | ||||||
|  | static const char *TAG = "airthings_wave_plus"; | ||||||
|  |  | ||||||
|  | class AirthingsWavePlus : public PollingComponent, public BLEClientNode { | ||||||
|  |  public: | ||||||
|  |   AirthingsWavePlus(); | ||||||
|  |  | ||||||
|  |   void setup() override; | ||||||
|  |   void dump_config() override; | ||||||
|  |   void update() override; | ||||||
|  |   void loop() 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_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_tvoc(sensor::Sensor *tvoc) { tvoc_sensor_ = tvoc; } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   bool is_valid_radon_value_(short radon); | ||||||
|  |   bool is_valid_voc_value_(short voc); | ||||||
|  |   bool is_valid_co2_value_(short co2); | ||||||
|  |  | ||||||
|  |   void read_sensors_(uint8_t *value, uint16_t value_len); | ||||||
|  |   void request_read_values_(); | ||||||
|  |  | ||||||
|  |   sensor::Sensor *temperature_sensor_{nullptr}; | ||||||
|  |   sensor::Sensor *radon_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 *tvoc_sensor_{nullptr}; | ||||||
|  |  | ||||||
|  |   uint16_t handle; | ||||||
|  |   espbt::ESPBTUUID service_uuid; | ||||||
|  |   espbt::ESPBTUUID sensors_data_characteristic_uuid; | ||||||
|  |  | ||||||
|  |   struct WavePlusReadings { | ||||||
|  |     uint8_t version; | ||||||
|  |     uint8_t humidity; | ||||||
|  |     uint8_t ambientLight; | ||||||
|  |     uint8_t unused01; | ||||||
|  |     uint16_t radon; | ||||||
|  |     uint16_t radon_lt; | ||||||
|  |     uint16_t temperature; | ||||||
|  |     uint16_t pressure; | ||||||
|  |     uint16_t co2; | ||||||
|  |     uint16_t voc; | ||||||
|  |   }; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace airthings_wave_plus | ||||||
|  | }  // namespace esphome | ||||||
|  |  | ||||||
|  | #endif  // ARDUINO_ARCH_ESP32 | ||||||
							
								
								
									
										116
									
								
								esphome/components/airthings_wave_plus/sensor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								esphome/components/airthings_wave_plus/sensor.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,116 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome.components import sensor, ble_client | ||||||
|  |  | ||||||
|  | from esphome.const import ( | ||||||
|  |     DEVICE_CLASS_CARBON_DIOXIDE, | ||||||
|  |     DEVICE_CLASS_HUMIDITY, | ||||||
|  |     DEVICE_CLASS_TEMPERATURE, | ||||||
|  |     DEVICE_CLASS_PRESSURE, | ||||||
|  |     STATE_CLASS_MEASUREMENT, | ||||||
|  |     UNIT_PERCENT, | ||||||
|  |     UNIT_CELSIUS, | ||||||
|  |     UNIT_HECTOPASCAL, | ||||||
|  |     ICON_RADIOACTIVE, | ||||||
|  |     CONF_ID, | ||||||
|  |     CONF_RADON, | ||||||
|  |     CONF_RADON_LONG_TERM, | ||||||
|  |     CONF_HUMIDITY, | ||||||
|  |     CONF_TVOC, | ||||||
|  |     CONF_CO2, | ||||||
|  |     CONF_PRESSURE, | ||||||
|  |     CONF_TEMPERATURE, | ||||||
|  |     UNIT_BECQUEREL_PER_CUBIC_METER, | ||||||
|  |     UNIT_PARTS_PER_MILLION, | ||||||
|  |     UNIT_PARTS_PER_BILLION, | ||||||
|  |     ICON_RADIATOR, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | DEPENDENCIES = ["ble_client"] | ||||||
|  |  | ||||||
|  | airthings_wave_plus_ns = cg.esphome_ns.namespace("airthings_wave_plus") | ||||||
|  | AirthingsWavePlus = airthings_wave_plus_ns.class_( | ||||||
|  |     "AirthingsWavePlus", cg.PollingComponent, ble_client.BLEClientNode | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = ( | ||||||
|  |     cv.Schema( | ||||||
|  |         { | ||||||
|  |             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( | ||||||
|  |                 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_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( | ||||||
|  |                 unit_of_measurement=UNIT_PARTS_PER_MILLION, | ||||||
|  |                 accuracy_decimals=0, | ||||||
|  |                 device_class=DEVICE_CLASS_CARBON_DIOXIDE, | ||||||
|  |                 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("5mins")) | ||||||
|  |     .extend(ble_client.BLE_CLIENT_SCHEMA) | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def to_code(config): | ||||||
|  |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|  |     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_RADON in config: | ||||||
|  |         sens = await sensor.new_sensor(config[CONF_RADON]) | ||||||
|  |         cg.add(var.set_radon(sens)) | ||||||
|  |     if CONF_RADON_LONG_TERM in config: | ||||||
|  |         sens = await sensor.new_sensor(config[CONF_RADON_LONG_TERM]) | ||||||
|  |         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: | ||||||
|  |         sens = await sensor.new_sensor(config[CONF_CO2]) | ||||||
|  |         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)) | ||||||
| @@ -507,6 +507,8 @@ CONF_PROTOCOL = "protocol" | |||||||
| CONF_PULL_MODE = "pull_mode" | CONF_PULL_MODE = "pull_mode" | ||||||
| CONF_PULSE_LENGTH = "pulse_length" | CONF_PULSE_LENGTH = "pulse_length" | ||||||
| CONF_QOS = "qos" | CONF_QOS = "qos" | ||||||
|  | CONF_RADON = "radon" | ||||||
|  | CONF_RADON_LONG_TERM = "radon_long_term" | ||||||
| CONF_RANDOM = "random" | CONF_RANDOM = "random" | ||||||
| CONF_RANGE = "range" | CONF_RANGE = "range" | ||||||
| CONF_RANGE_FROM = "range_from" | CONF_RANGE_FROM = "range_from" | ||||||
| @@ -732,6 +734,7 @@ ICON_PERCENT = "mdi:percent" | |||||||
| ICON_POWER = "mdi:power" | ICON_POWER = "mdi:power" | ||||||
| ICON_PULSE = "mdi:pulse" | ICON_PULSE = "mdi:pulse" | ||||||
| ICON_RADIATOR = "mdi:radiator" | ICON_RADIATOR = "mdi:radiator" | ||||||
|  | ICON_RADIOACTIVE = "mdi:radioactive" | ||||||
| ICON_RESTART = "mdi:restart" | ICON_RESTART = "mdi:restart" | ||||||
| ICON_ROTATE_RIGHT = "mdi:rotate-right" | ICON_ROTATE_RIGHT = "mdi:rotate-right" | ||||||
| ICON_RULER = "mdi:ruler" | ICON_RULER = "mdi:ruler" | ||||||
| @@ -753,6 +756,7 @@ ICON_WEATHER_WINDY = "mdi:weather-windy" | |||||||
| ICON_WIFI = "mdi:wifi" | ICON_WIFI = "mdi:wifi" | ||||||
|  |  | ||||||
| UNIT_AMPERE = "A" | UNIT_AMPERE = "A" | ||||||
|  | UNIT_BECQUEREL_PER_CUBIC_METER = "Bq/m³" | ||||||
| UNIT_CELSIUS = "°C" | UNIT_CELSIUS = "°C" | ||||||
| UNIT_COUNT_DECILITRE = "/dL" | UNIT_COUNT_DECILITRE = "/dL" | ||||||
| UNIT_COUNTS_PER_CUBIC_METER = "#/m³" | UNIT_COUNTS_PER_CUBIC_METER = "#/m³" | ||||||
|   | |||||||
| @@ -246,6 +246,24 @@ 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 | ||||||
|  |     ble_client_id: airthings01 | ||||||
|  |     update_interval: 5min | ||||||
|  |     temperature: | ||||||
|  |       name: "Wave Plus Temperature" | ||||||
|  |     radon: | ||||||
|  |       name: "Wave Plus Radon" | ||||||
|  |     radon_long_term: | ||||||
|  |       name: "Wave Plus Radon Long Term" | ||||||
|  |     pressure: | ||||||
|  |       name: "Wave Plus Pressure" | ||||||
|  |     humidity: | ||||||
|  |       name: "Wave Plus Humidity" | ||||||
|  |     co2: | ||||||
|  |       name: "Wave Plus CO2" | ||||||
|  |     tvoc: | ||||||
|  |       name: "Wave Plus VOC" | ||||||
|  |  | ||||||
| time: | time: | ||||||
|   - platform: homeassistant |   - platform: homeassistant | ||||||
|     on_time: |     on_time: | ||||||
| @@ -334,6 +352,12 @@ esp32_ble_tracker: | |||||||
|         - lambda: !lambda |- |         - lambda: !lambda |- | ||||||
|             ESP_LOGD("main", "Length of manufacturer data is %i", x.size()); |             ESP_LOGD("main", "Length of manufacturer data is %i", x.size()); | ||||||
|  |  | ||||||
|  | ble_client: | ||||||
|  |   - mac_address: 01:02:03:04:05:06 | ||||||
|  |     id: airthings01 | ||||||
|  |      | ||||||
|  | airthings_ble: | ||||||
|  |  | ||||||
| #esp32_ble_beacon: | #esp32_ble_beacon: | ||||||
| #  type: iBeacon | #  type: iBeacon | ||||||
| #  uuid: 'c29ce823-e67a-4e71-bff2-abaa32e77a98' | #  uuid: 'c29ce823-e67a-4e71-bff2-abaa32e77a98' | ||||||
| @@ -431,3 +455,4 @@ interval: | |||||||
|     - logger.log: 'Interval Run' |     - logger.log: 'Interval Run' | ||||||
|  |  | ||||||
| display: | display: | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user