mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	Add Initial NPI-19 pressure sensor support (#7181)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
		| @@ -291,6 +291,7 @@ esphome/components/nextion/switch/* @senexcrenshaw | ||||
| esphome/components/nextion/text_sensor/* @senexcrenshaw | ||||
| esphome/components/nfc/* @jesserockz @kbx81 | ||||
| esphome/components/noblex/* @AGalfra | ||||
| esphome/components/npi19/* @bakerkj | ||||
| esphome/components/number/* @esphome/core | ||||
| esphome/components/one_wire/* @ssieb | ||||
| esphome/components/online_image/* @guillempages | ||||
|   | ||||
							
								
								
									
										0
									
								
								esphome/components/npi19/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								esphome/components/npi19/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										111
									
								
								esphome/components/npi19/npi19.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								esphome/components/npi19/npi19.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,111 @@ | ||||
| #include "npi19.h" | ||||
| #include "esphome/core/log.h" | ||||
| #include "esphome/core/helpers.h" | ||||
| #include "esphome/core/hal.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace npi19 { | ||||
|  | ||||
| static const char *const TAG = "npi19"; | ||||
|  | ||||
| static const uint8_t READ_COMMAND = 0xAC; | ||||
|  | ||||
| void NPI19Component::setup() { | ||||
|   ESP_LOGCONFIG(TAG, "Setting up NPI19..."); | ||||
|  | ||||
|   uint16_t raw_temperature(0); | ||||
|   uint16_t raw_pressure(0); | ||||
|   i2c::ErrorCode err = this->read_(raw_temperature, raw_pressure); | ||||
|   if (err != i2c::ERROR_OK) { | ||||
|     ESP_LOGCONFIG(TAG, "    I2C Communication Failed..."); | ||||
|     this->mark_failed(); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   ESP_LOGCONFIG(TAG, "    Success..."); | ||||
| } | ||||
|  | ||||
| void NPI19Component::dump_config() { | ||||
|   ESP_LOGCONFIG(TAG, "NPI19:"); | ||||
|   LOG_I2C_DEVICE(this); | ||||
|   LOG_UPDATE_INTERVAL(this); | ||||
|   LOG_SENSOR("  ", "Raw Pressure", this->raw_pressure_sensor_); | ||||
|   LOG_SENSOR("  ", "Temperature", this->temperature_sensor_); | ||||
| } | ||||
|  | ||||
| float NPI19Component::get_setup_priority() const { return setup_priority::DATA; } | ||||
|  | ||||
| i2c::ErrorCode NPI19Component::read_(uint16_t &raw_temperature, uint16_t &raw_pressure) { | ||||
|   // initiate data read from device | ||||
|   i2c::ErrorCode w_err = write(&READ_COMMAND, sizeof(READ_COMMAND), true); | ||||
|   if (w_err != i2c::ERROR_OK) { | ||||
|     return w_err; | ||||
|   } | ||||
|  | ||||
|   // read 4 bytes from senesor | ||||
|   uint8_t response[4] = {0x00, 0x00, 0x00, 0x00}; | ||||
|   i2c::ErrorCode r_err = this->read(response, 4); | ||||
|  | ||||
|   if (r_err != i2c::ERROR_OK) { | ||||
|     return r_err; | ||||
|   } | ||||
|  | ||||
|   // extract top 6 bits of first byte and all bits of second byte for pressure | ||||
|   raw_pressure = ((response[0] & 0x3F) << 8) | response[1]; | ||||
|  | ||||
|   // extract all bytes of 3rd byte and top 3 bits of fourth byte for temperature | ||||
|   raw_temperature = (response[2] << 3) | ((response[3] & 0xE0) >> 5); | ||||
|  | ||||
|   return i2c::ERROR_OK; | ||||
| } | ||||
|  | ||||
| inline float convert_temperature(uint16_t raw_temperature) { | ||||
|   /* | ||||
|    * Correspondance with Amphenol confirmed the appropriate equation for computing temperature is: | ||||
|    * T (°C) =(((((Th*8)+Tl)/2048)*200)-50), where Th is the high (third) byte and Tl is the low (fourth) byte. | ||||
|    * | ||||
|    * Tl is actually the upper 3 bits of the fourth data byte; the first 5 (LSBs) must be masked out. | ||||
|    * | ||||
|    * | ||||
|    * The NPI-19 I2C has a temperature output, however the manufacturer does | ||||
|    * not specify its accuracy on the published datasheet. They indicate | ||||
|    * that the sensor should not be used as a calibrated temperature | ||||
|    * reading; it’s only intended for curve fitting data during | ||||
|    * compensation. | ||||
|    */ | ||||
|   const float temperature_bits_span = 2048; | ||||
|   const float temperature_max = 150; | ||||
|   const float temperature_min = -50; | ||||
|   const float temperature_span = temperature_max - temperature_min; | ||||
|  | ||||
|   float temperature = (raw_temperature * temperature_span / temperature_bits_span) + temperature_min; | ||||
|  | ||||
|   return temperature; | ||||
| } | ||||
|  | ||||
| void NPI19Component::update() { | ||||
|   uint16_t raw_temperature(0); | ||||
|   uint16_t raw_pressure(0); | ||||
|  | ||||
|   i2c::ErrorCode err = this->read_(raw_temperature, raw_pressure); | ||||
|  | ||||
|   if (err != i2c::ERROR_OK) { | ||||
|     ESP_LOGW(TAG, "I2C Communication Failed"); | ||||
|     this->status_set_warning(); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   float temperature = convert_temperature(raw_temperature); | ||||
|  | ||||
|   ESP_LOGD(TAG, "Got raw pressure=%d, temperature=%.1f°C", raw_pressure, temperature); | ||||
|  | ||||
|   if (this->temperature_sensor_ != nullptr) | ||||
|     this->temperature_sensor_->publish_state(temperature); | ||||
|   if (this->raw_pressure_sensor_ != nullptr) | ||||
|     this->raw_pressure_sensor_->publish_state(raw_pressure); | ||||
|  | ||||
|   this->status_clear_warning(); | ||||
| } | ||||
|  | ||||
| }  // namespace npi19 | ||||
| }  // namespace esphome | ||||
							
								
								
									
										30
									
								
								esphome/components/npi19/npi19.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								esphome/components/npi19/npi19.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/components/sensor/sensor.h" | ||||
| #include "esphome/components/i2c/i2c.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace npi19 { | ||||
|  | ||||
| /// This class implements support for the npi19 pressure and temperature i2c sensors. | ||||
| class NPI19Component : public PollingComponent, public i2c::I2CDevice { | ||||
|  public: | ||||
|   void set_temperature_sensor(sensor::Sensor *temperature_sensor) { this->temperature_sensor_ = temperature_sensor; } | ||||
|   void set_raw_pressure_sensor(sensor::Sensor *raw_pressure_sensor) { | ||||
|     this->raw_pressure_sensor_ = raw_pressure_sensor; | ||||
|   } | ||||
|  | ||||
|   float get_setup_priority() const override; | ||||
|   void setup() override; | ||||
|   void dump_config() override; | ||||
|   void update() override; | ||||
|  | ||||
|  protected: | ||||
|   i2c::ErrorCode read_(uint16_t &raw_temperature, uint16_t &raw_pressure); | ||||
|   sensor::Sensor *temperature_sensor_{nullptr}; | ||||
|   sensor::Sensor *raw_pressure_sensor_{nullptr}; | ||||
| }; | ||||
|  | ||||
| }  // namespace npi19 | ||||
| }  // namespace esphome | ||||
							
								
								
									
										52
									
								
								esphome/components/npi19/sensor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								esphome/components/npi19/sensor.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| import esphome.codegen as cg | ||||
| from esphome.components import i2c, sensor | ||||
| import esphome.config_validation as cv | ||||
| from esphome.const import ( | ||||
|     CONF_ID, | ||||
|     CONF_TEMPERATURE, | ||||
|     DEVICE_CLASS_TEMPERATURE, | ||||
|     STATE_CLASS_MEASUREMENT, | ||||
|     UNIT_CELSIUS, | ||||
| ) | ||||
|  | ||||
| CODEOWNERS = ["@bakerkj"] | ||||
| DEPENDENCIES = ["i2c"] | ||||
|  | ||||
| npi19_ns = cg.esphome_ns.namespace("npi19") | ||||
|  | ||||
| NPI19Component = npi19_ns.class_("NPI19Component", cg.PollingComponent, i2c.I2CDevice) | ||||
|  | ||||
| CONF_RAW_PRESSURE = "raw_pressure" | ||||
|  | ||||
| CONFIG_SCHEMA = ( | ||||
|     cv.Schema( | ||||
|         { | ||||
|             cv.GenerateID(): cv.declare_id(NPI19Component), | ||||
|             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_RAW_PRESSURE): sensor.sensor_schema( | ||||
|                 accuracy_decimals=0, state_class=STATE_CLASS_MEASUREMENT | ||||
|             ), | ||||
|         } | ||||
|     ) | ||||
|     .extend(cv.polling_component_schema("60s")) | ||||
|     .extend(i2c.i2c_device_schema(0x28)) | ||||
| ) | ||||
|  | ||||
|  | ||||
| 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 raw_pressure_config := config.get(CONF_RAW_PRESSURE): | ||||
|         sens = await sensor.new_sensor(raw_pressure_config) | ||||
|         cg.add(var.set_raw_pressure_sensor(sens)) | ||||
							
								
								
									
										16
									
								
								tests/components/npi19/common.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								tests/components/npi19/common.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| i2c: | ||||
|   id: i2c_bus | ||||
|   scl: ${scl_pin} | ||||
|   sda: ${sda_pin} | ||||
|   frequency: 200kHz | ||||
|  | ||||
| sensor: | ||||
|   - platform: npi19 | ||||
|     update_interval: 1s | ||||
|     i2c_id: i2c_bus | ||||
|  | ||||
|     temperature: | ||||
|       name: water temperature | ||||
|  | ||||
|     raw_pressure: | ||||
|       name: water pressure | ||||
							
								
								
									
										5
									
								
								tests/components/npi19/test.esp32-ard.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/components/npi19/test.esp32-ard.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| substitutions: | ||||
|   scl_pin: GPIO22 | ||||
|   sda_pin: GPIO21 | ||||
|  | ||||
| <<: !include common.yaml | ||||
							
								
								
									
										5
									
								
								tests/components/npi19/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/components/npi19/test.esp32-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| substitutions: | ||||
|   scl_pin: GPIO22 | ||||
|   sda_pin: GPIO21 | ||||
|  | ||||
| <<: !include common.yaml | ||||
							
								
								
									
										5
									
								
								tests/components/npi19/test.esp32-s3-ard.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/components/npi19/test.esp32-s3-ard.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| substitutions: | ||||
|   scl_pin: GPIO40 | ||||
|   sda_pin: GPIO41 | ||||
|  | ||||
| <<: !include common.yaml | ||||
							
								
								
									
										5
									
								
								tests/components/npi19/test.esp32-s3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/components/npi19/test.esp32-s3-idf.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| substitutions: | ||||
|   scl_pin: GPIO40 | ||||
|   sda_pin: GPIO41 | ||||
|  | ||||
| <<: !include common.yaml | ||||
							
								
								
									
										5
									
								
								tests/components/npi19/test.esp8266-ard.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								tests/components/npi19/test.esp8266-ard.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| substitutions: | ||||
|   scl_pin: GPIO05 | ||||
|   sda_pin: GPIO04 | ||||
|  | ||||
| <<: !include common.yaml | ||||
		Reference in New Issue
	
	Block a user