mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	Add differential pressure sensor support for CFSensor XGZP68xxD devices (#5562)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
		| @@ -349,6 +349,7 @@ esphome/components/wiegand/* @ssieb | |||||||
| esphome/components/wireguard/* @droscy @lhoracek @thomas0bernard | esphome/components/wireguard/* @droscy @lhoracek @thomas0bernard | ||||||
| esphome/components/wl_134/* @hobbypunk90 | esphome/components/wl_134/* @hobbypunk90 | ||||||
| esphome/components/x9c/* @EtienneMD | esphome/components/x9c/* @EtienneMD | ||||||
|  | esphome/components/xgzp68xx/* @gcormier | ||||||
| esphome/components/xiaomi_lywsd03mmc/* @ahpohl | esphome/components/xiaomi_lywsd03mmc/* @ahpohl | ||||||
| esphome/components/xiaomi_mhoc303/* @drug123 | esphome/components/xiaomi_mhoc303/* @drug123 | ||||||
| esphome/components/xiaomi_mhoc401/* @vevsvevs | esphome/components/xiaomi_mhoc401/* @vevsvevs | ||||||
|   | |||||||
							
								
								
									
										1
									
								
								esphome/components/xgzp68xx/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								esphome/components/xgzp68xx/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | |||||||
|  | CODEOWNERS = ["@gcormier"] | ||||||
							
								
								
									
										62
									
								
								esphome/components/xgzp68xx/sensor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								esphome/components/xgzp68xx/sensor.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,62 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome.components import i2c, sensor | ||||||
|  | from esphome.const import ( | ||||||
|  |     DEVICE_CLASS_PRESSURE, | ||||||
|  |     CONF_ID, | ||||||
|  |     DEVICE_CLASS_TEMPERATURE, | ||||||
|  |     STATE_CLASS_MEASUREMENT, | ||||||
|  |     UNIT_PASCAL, | ||||||
|  |     UNIT_CELSIUS, | ||||||
|  |     CONF_TEMPERATURE, | ||||||
|  |     CONF_PRESSURE, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | DEPENDENCIES = ["i2c"] | ||||||
|  | CODEOWNERS = ["@gcormier"] | ||||||
|  |  | ||||||
|  | CONF_K_VALUE = "k_value" | ||||||
|  |  | ||||||
|  | xgzp68xx_ns = cg.esphome_ns.namespace("xgzp68xx") | ||||||
|  | XGZP68XXComponent = xgzp68xx_ns.class_( | ||||||
|  |     "XGZP68XXComponent", cg.PollingComponent, i2c.I2CDevice | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = ( | ||||||
|  |     cv.Schema( | ||||||
|  |         { | ||||||
|  |             cv.GenerateID(): cv.declare_id(XGZP68XXComponent), | ||||||
|  |             cv.Optional(CONF_PRESSURE): sensor.sensor_schema( | ||||||
|  |                 unit_of_measurement=UNIT_PASCAL, | ||||||
|  |                 accuracy_decimals=1, | ||||||
|  |                 device_class=DEVICE_CLASS_PRESSURE, | ||||||
|  |                 state_class=STATE_CLASS_MEASUREMENT, | ||||||
|  |             ), | ||||||
|  |             cv.Optional(CONF_TEMPERATURE): sensor.sensor_schema( | ||||||
|  |                 unit_of_measurement=UNIT_CELSIUS, | ||||||
|  |                 accuracy_decimals=1, | ||||||
|  |                 device_class=DEVICE_CLASS_TEMPERATURE, | ||||||
|  |                 state_class=STATE_CLASS_MEASUREMENT, | ||||||
|  |             ), | ||||||
|  |             cv.Optional(CONF_K_VALUE, default=4096): cv.uint16_t, | ||||||
|  |         } | ||||||
|  |     ) | ||||||
|  |     .extend(cv.polling_component_schema("60s")) | ||||||
|  |     .extend(i2c.i2c_device_schema(0x6D)) | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 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) | ||||||
|  |  | ||||||
|  |     if temperature_config := config.get(CONF_TEMPERATURE): | ||||||
|  |         sens = await sensor.new_sensor(temperature_config) | ||||||
|  |         cg.add(var.set_temperature_sensor(sens)) | ||||||
|  |  | ||||||
|  |     if pressure_config := config.get(CONF_PRESSURE): | ||||||
|  |         sens = await sensor.new_sensor(pressure_config) | ||||||
|  |         cg.add(var.set_pressure_sensor(sens)) | ||||||
|  |  | ||||||
|  |     cg.add(var.set_k_value(config[CONF_K_VALUE])) | ||||||
							
								
								
									
										91
									
								
								esphome/components/xgzp68xx/xgzp68xx.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								esphome/components/xgzp68xx/xgzp68xx.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,91 @@ | |||||||
|  | #include "xgzp68xx.h" | ||||||
|  | #include "esphome/core/log.h" | ||||||
|  | #include "esphome/core/hal.h" | ||||||
|  | #include "esphome/core/helpers.h" | ||||||
|  | #include "esphome/components/i2c/i2c.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace xgzp68xx { | ||||||
|  |  | ||||||
|  | static const char *const TAG = "xgzp68xx.sensor"; | ||||||
|  |  | ||||||
|  | static const uint8_t CMD_ADDRESS = 0x30; | ||||||
|  | static const uint8_t SYSCONFIG_ADDRESS = 0xA5; | ||||||
|  | static const uint8_t PCONFIG_ADDRESS = 0xA6; | ||||||
|  | static const uint8_t READ_COMMAND = 0x0A; | ||||||
|  |  | ||||||
|  | void XGZP68XXComponent::update() { | ||||||
|  |   // Request temp + pressure acquisition | ||||||
|  |   this->write_register(0x30, &READ_COMMAND, 1); | ||||||
|  |  | ||||||
|  |   // Wait 20mS per datasheet | ||||||
|  |   this->set_timeout("measurement", 20, [this]() { | ||||||
|  |     uint8_t data[5]; | ||||||
|  |     uint32_t pressure_raw; | ||||||
|  |     uint16_t temperature_raw; | ||||||
|  |     float pressure_in_pa, temperature; | ||||||
|  |     int success; | ||||||
|  |  | ||||||
|  |     // Read the sensor data | ||||||
|  |     success = this->read_register(0x06, data, 5); | ||||||
|  |     if (success != 0) { | ||||||
|  |       ESP_LOGE(TAG, "Failed to read sensor data! Error code: %i", success); | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     pressure_raw = encode_uint24(data[0], data[1], data[2]); | ||||||
|  |     temperature_raw = encode_uint16(data[3], data[4]); | ||||||
|  |  | ||||||
|  |     // Convert the pressure data to hPa | ||||||
|  |     ESP_LOGV(TAG, "Got raw pressure=%d, raw temperature=%d ", pressure_raw, temperature_raw); | ||||||
|  |     ESP_LOGV(TAG, "K value is %d ", this->k_value_); | ||||||
|  |  | ||||||
|  |     // The most significant bit of both pressure and temperature will be 1 to indicate a negative value. | ||||||
|  |     // This is directly from the datasheet, and the calculations below will handle this. | ||||||
|  |     if (pressure_raw > pow(2, 23)) { | ||||||
|  |       // Negative pressure | ||||||
|  |       pressure_in_pa = (pressure_raw - pow(2, 24)) / (float) (this->k_value_); | ||||||
|  |     } else { | ||||||
|  |       // Positive pressure | ||||||
|  |       pressure_in_pa = pressure_raw / (float) (this->k_value_); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (temperature_raw > pow(2, 15)) { | ||||||
|  |       // Negative temperature | ||||||
|  |       temperature = (float) (temperature_raw - pow(2, 16)) / 256.0f; | ||||||
|  |     } else { | ||||||
|  |       // Positive temperature | ||||||
|  |       temperature = (float) temperature_raw / 256.0f; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (this->pressure_sensor_ != nullptr) | ||||||
|  |       this->pressure_sensor_->publish_state(pressure_in_pa); | ||||||
|  |  | ||||||
|  |     if (this->temperature_sensor_ != nullptr) | ||||||
|  |       this->temperature_sensor_->publish_state(temperature); | ||||||
|  |   });  // end of set_timeout | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void XGZP68XXComponent::setup() { | ||||||
|  |   ESP_LOGD(TAG, "Setting up XGZP68xx..."); | ||||||
|  |   uint8_t config; | ||||||
|  |  | ||||||
|  |   // Display some sample bits to confirm we are talking to the sensor | ||||||
|  |   this->read_register(SYSCONFIG_ADDRESS, &config, 1); | ||||||
|  |   ESP_LOGCONFIG(TAG, "Gain value is %d", (config >> 3) & 0b111); | ||||||
|  |   ESP_LOGCONFIG(TAG, "XGZP68xx started!"); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void XGZP68XXComponent::dump_config() { | ||||||
|  |   ESP_LOGCONFIG(TAG, "XGZP68xx"); | ||||||
|  |   LOG_SENSOR("  ", "Temperature: ", this->temperature_sensor_); | ||||||
|  |   LOG_SENSOR("  ", "Pressure: ", this->pressure_sensor_); | ||||||
|  |   LOG_I2C_DEVICE(this); | ||||||
|  |   if (this->is_failed()) { | ||||||
|  |     ESP_LOGE(TAG, "  Connection with XGZP68xx failed!"); | ||||||
|  |   } | ||||||
|  |   LOG_UPDATE_INTERVAL(this); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace xgzp68xx | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										27
									
								
								esphome/components/xgzp68xx/xgzp68xx.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								esphome/components/xgzp68xx/xgzp68xx.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "esphome/core/component.h" | ||||||
|  | #include "esphome/components/sensor/sensor.h" | ||||||
|  | #include "esphome/components/i2c/i2c.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace xgzp68xx { | ||||||
|  |  | ||||||
|  | class XGZP68XXComponent : public PollingComponent, public sensor::Sensor, public i2c::I2CDevice { | ||||||
|  |  public: | ||||||
|  |   SUB_SENSOR(temperature) | ||||||
|  |   SUB_SENSOR(pressure) | ||||||
|  |   void set_k_value(uint16_t k_value) { this->k_value_ = k_value; } | ||||||
|  |  | ||||||
|  |   void update() override; | ||||||
|  |   void setup() override; | ||||||
|  |   void dump_config() override; | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   /// Internal method to read the pressure from the component after it has been scheduled. | ||||||
|  |   void read_pressure_(); | ||||||
|  |   uint16_t k_value_; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace xgzp68xx | ||||||
|  | }  // namespace esphome | ||||||
| @@ -351,6 +351,14 @@ dfrobot_sen0395: | |||||||
|     uart_id: dfrobot_mmwave_uart |     uart_id: dfrobot_mmwave_uart | ||||||
|  |  | ||||||
| sensor: | sensor: | ||||||
|  |   - platform: xgzp68xx | ||||||
|  |     i2c_id: i2c_bus | ||||||
|  |     temperature: | ||||||
|  |       name: Pressure Temperature | ||||||
|  |     pressure: | ||||||
|  |       name: Differential pressure | ||||||
|  |     k_value: 4096 | ||||||
|  |  | ||||||
|   - platform: pmwcs3 |   - platform: pmwcs3 | ||||||
|     i2c_id: i2c_bus |     i2c_id: i2c_bus | ||||||
|     e25: |     e25: | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user