mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	Add KMeterISO component. (#5170)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
		
							
								
								
									
										0
									
								
								esphome/components/kmeteriso/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								esphome/components/kmeteriso/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										82
									
								
								esphome/components/kmeteriso/kmeteriso.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								esphome/components/kmeteriso/kmeteriso.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,82 @@ | ||||
| #include "kmeteriso.h" | ||||
| #include "esphome/core/hal.h" | ||||
| #include "esphome/core/log.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace kmeteriso { | ||||
|  | ||||
| static const char *const TAG = "kmeteriso.sensor"; | ||||
|  | ||||
| static const uint8_t KMETER_ERROR_STATUS_REG = 0x20; | ||||
| static const uint8_t KMETER_TEMP_VAL_REG = 0x00; | ||||
| static const uint8_t KMETER_INTERNAL_TEMP_VAL_REG = 0x10; | ||||
| static const uint8_t KMETER_FIRMWARE_VERSION_REG = 0xFE; | ||||
|  | ||||
| void KMeterISOComponent::setup() { | ||||
|   ESP_LOGCONFIG(TAG, "Setting up KMeterISO..."); | ||||
|   this->error_code_ = NONE; | ||||
|  | ||||
|   // Mark as not failed before initializing. Some devices will turn off sensors to save on batteries | ||||
|   // and when they come back on, the COMPONENT_STATE_FAILED bit must be unset on the component. | ||||
|   if ((this->component_state_ & COMPONENT_STATE_MASK) == COMPONENT_STATE_FAILED) { | ||||
|     this->component_state_ &= ~COMPONENT_STATE_MASK; | ||||
|     this->component_state_ |= COMPONENT_STATE_CONSTRUCTION; | ||||
|   } | ||||
|  | ||||
|   auto err = this->bus_->writev(this->address_, nullptr, 0); | ||||
|   if (err == esphome::i2c::ERROR_OK) { | ||||
|     ESP_LOGCONFIG(TAG, "Could write to the address %d.", this->address_); | ||||
|   } else { | ||||
|     ESP_LOGCONFIG(TAG, "Could not write to the address %d.", this->address_); | ||||
|     this->error_code_ = COMMUNICATION_FAILED; | ||||
|     this->mark_failed(); | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   uint8_t read_buf[4] = {1}; | ||||
|   if (!this->read_bytes(KMETER_ERROR_STATUS_REG, read_buf, 1)) { | ||||
|     ESP_LOGCONFIG(TAG, "Could not read from the device."); | ||||
|     this->error_code_ = COMMUNICATION_FAILED; | ||||
|     this->mark_failed(); | ||||
|     return; | ||||
|   } | ||||
|   if (read_buf[0] != 0) { | ||||
|     ESP_LOGCONFIG(TAG, "The device is not ready."); | ||||
|     this->error_code_ = STATUS_FAILED; | ||||
|     this->mark_failed(); | ||||
|     return; | ||||
|   } | ||||
|   ESP_LOGCONFIG(TAG, "The device was successfully setup."); | ||||
| } | ||||
|  | ||||
| float KMeterISOComponent::get_setup_priority() const { return setup_priority::DATA; } | ||||
|  | ||||
| void KMeterISOComponent::update() { | ||||
|   uint8_t read_buf[4]; | ||||
|  | ||||
|   if (this->temperature_sensor_ != nullptr) { | ||||
|     if (!this->read_bytes(KMETER_TEMP_VAL_REG, read_buf, 4)) { | ||||
|       ESP_LOGW(TAG, "Error reading temperature."); | ||||
|     } else { | ||||
|       int32_t temp = encode_uint32(read_buf[3], read_buf[2], read_buf[1], read_buf[0]); | ||||
|       float temp_f = temp / 100.0; | ||||
|       ESP_LOGV(TAG, "Got temperature=%.2f °C", temp_f); | ||||
|       this->temperature_sensor_->publish_state(temp_f); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (this->internal_temperature_sensor_ != nullptr) { | ||||
|     if (!this->read_bytes(KMETER_INTERNAL_TEMP_VAL_REG, read_buf, 4)) { | ||||
|       ESP_LOGW(TAG, "Error reading internal temperature."); | ||||
|       return; | ||||
|     } else { | ||||
|       int32_t internal_temp = encode_uint32(read_buf[3], read_buf[2], read_buf[1], read_buf[0]); | ||||
|       float internal_temp_f = internal_temp / 100.0; | ||||
|       ESP_LOGV(TAG, "Got internal temperature=%.2f °C", internal_temp_f); | ||||
|       this->internal_temperature_sensor_->publish_state(internal_temp_f); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| }  // namespace kmeteriso | ||||
| }  // namespace esphome | ||||
							
								
								
									
										34
									
								
								esphome/components/kmeteriso/kmeteriso.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								esphome/components/kmeteriso/kmeteriso.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "esphome/core/component.h" | ||||
| #include "esphome/components/sensor/sensor.h" | ||||
| #include "esphome/components/i2c/i2c.h" | ||||
| #include "esphome/components/i2c/i2c_bus.h" | ||||
|  | ||||
| namespace esphome { | ||||
| namespace kmeteriso { | ||||
|  | ||||
| /// This class implements support for the KMeterISO thermocouple sensor. | ||||
| class KMeterISOComponent : public PollingComponent, public i2c::I2CDevice { | ||||
|  public: | ||||
|   void set_temperature_sensor(sensor::Sensor *t) { this->temperature_sensor_ = t; } | ||||
|   void set_internal_temperature_sensor(sensor::Sensor *t) { this->internal_temperature_sensor_ = t; } | ||||
|  | ||||
|   // ========== INTERNAL METHODS ========== | ||||
|   // (In most use cases you won't need these) | ||||
|   void setup() override; | ||||
|   float get_setup_priority() const override; | ||||
|   void update() override; | ||||
|  | ||||
|  protected: | ||||
|   sensor::Sensor *temperature_sensor_{nullptr}; | ||||
|   sensor::Sensor *internal_temperature_sensor_{nullptr}; | ||||
|   enum ErrorCode { | ||||
|     NONE = 0, | ||||
|     COMMUNICATION_FAILED, | ||||
|     STATUS_FAILED, | ||||
|   } error_code_{NONE}; | ||||
| }; | ||||
|  | ||||
| }  // namespace kmeteriso | ||||
| }  // namespace esphome | ||||
							
								
								
									
										55
									
								
								esphome/components/kmeteriso/sensor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								esphome/components/kmeteriso/sensor.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | ||||
| import esphome.codegen as cg | ||||
| import esphome.config_validation as cv | ||||
| from esphome.components import i2c, sensor | ||||
| from esphome.const import ( | ||||
|     CONF_ID, | ||||
|     CONF_TEMPERATURE, | ||||
|     DEVICE_CLASS_TEMPERATURE, | ||||
|     STATE_CLASS_MEASUREMENT, | ||||
|     UNIT_CELSIUS, | ||||
|     ENTITY_CATEGORY_DIAGNOSTIC, | ||||
| ) | ||||
|  | ||||
| CONF_INTERNAL_TEMPERATURE = "internal_temperature" | ||||
| DEPENDENCIES = ["i2c"] | ||||
|  | ||||
| kmeteriso_ns = cg.esphome_ns.namespace("kmeteriso") | ||||
|  | ||||
| KMeterISOComponent = kmeteriso_ns.class_( | ||||
|     "KMeterISOComponent", cg.PollingComponent, i2c.I2CDevice | ||||
| ) | ||||
|  | ||||
| CONFIG_SCHEMA = ( | ||||
|     cv.Schema( | ||||
|         { | ||||
|             cv.GenerateID(): cv.declare_id(KMeterISOComponent), | ||||
|             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_INTERNAL_TEMPERATURE): sensor.sensor_schema( | ||||
|                 unit_of_measurement=UNIT_CELSIUS, | ||||
|                 device_class=DEVICE_CLASS_TEMPERATURE, | ||||
|                 state_class=STATE_CLASS_MEASUREMENT, | ||||
|                 entity_category=ENTITY_CATEGORY_DIAGNOSTIC, | ||||
|             ), | ||||
|         } | ||||
|     ) | ||||
|     .extend(cv.polling_component_schema("60s")) | ||||
|     .extend(i2c.i2c_device_schema(0x66)) | ||||
| ) | ||||
|  | ||||
|  | ||||
| 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 internal_temperature_config := config.get(CONF_INTERNAL_TEMPERATURE): | ||||
|         sens = await sensor.new_sensor(internal_temperature_config) | ||||
|         cg.add(var.set_internal_temperature_sensor(sens)) | ||||
| @@ -792,6 +792,13 @@ sensor: | ||||
|         name: INA3221 Channel 1 Shunt Voltage | ||||
|     update_interval: 15s | ||||
|     i2c_id: i2c_bus | ||||
|   - platform: kmeteriso | ||||
|     temperature: | ||||
|       name: Outside Temperature | ||||
|     internal_temperature: | ||||
|       name: Internal Ttemperature | ||||
|     update_interval: 15s | ||||
|     i2c_id: i2c_bus | ||||
|   - platform: kalman_combinator | ||||
|     name: Kalman-filtered temperature | ||||
|     process_std_dev: 0.00139 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user