mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-30 22:53:59 +00:00 
			
		
		
		
	Add integration hydreon_rgxx for rain sensors by Hydreon (#2711)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com>
This commit is contained in:
		| @@ -82,6 +82,7 @@ esphome/components/hitachi_ac424/* @sourabhjaiswal | |||||||
| esphome/components/homeassistant/* @OttoWinter | esphome/components/homeassistant/* @OttoWinter | ||||||
| esphome/components/honeywellabp/* @RubyBailey | esphome/components/honeywellabp/* @RubyBailey | ||||||
| esphome/components/hrxl_maxsonar_wr/* @netmikey | esphome/components/hrxl_maxsonar_wr/* @netmikey | ||||||
|  | esphome/components/hydreon_rgxx/* @functionpointer | ||||||
| esphome/components/i2c/* @esphome/core | esphome/components/i2c/* @esphome/core | ||||||
| esphome/components/improv_serial/* @esphome/core | esphome/components/improv_serial/* @esphome/core | ||||||
| esphome/components/ina260/* @MrEditor97 | esphome/components/ina260/* @MrEditor97 | ||||||
|   | |||||||
							
								
								
									
										11
									
								
								esphome/components/hydreon_rgxx/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								esphome/components/hydreon_rgxx/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | from esphome.components import uart | ||||||
|  |  | ||||||
|  | CODEOWNERS = ["@functionpointer"] | ||||||
|  | DEPENDENCIES = ["uart"] | ||||||
|  |  | ||||||
|  | hydreon_rgxx_ns = cg.esphome_ns.namespace("hydreon_rgxx") | ||||||
|  | RGModel = hydreon_rgxx_ns.enum("RGModel") | ||||||
|  | HydreonRGxxComponent = hydreon_rgxx_ns.class_( | ||||||
|  |     "HydreonRGxxComponent", cg.PollingComponent, uart.UARTDevice | ||||||
|  | ) | ||||||
							
								
								
									
										36
									
								
								esphome/components/hydreon_rgxx/binary_sensor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								esphome/components/hydreon_rgxx/binary_sensor.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome.components import binary_sensor | ||||||
|  | from esphome.const import ( | ||||||
|  |     CONF_ID, | ||||||
|  |     DEVICE_CLASS_COLD, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | from . import hydreon_rgxx_ns, HydreonRGxxComponent | ||||||
|  |  | ||||||
|  | CONF_HYDREON_RGXX_ID = "hydreon_rgxx_id" | ||||||
|  | CONF_TOO_COLD = "too_cold" | ||||||
|  |  | ||||||
|  | HydreonRGxxBinarySensor = hydreon_rgxx_ns.class_( | ||||||
|  |     "HydreonRGxxBinaryComponent", cg.Component | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = cv.Schema( | ||||||
|  |     { | ||||||
|  |         cv.GenerateID(): cv.declare_id(HydreonRGxxBinarySensor), | ||||||
|  |         cv.GenerateID(CONF_HYDREON_RGXX_ID): cv.use_id(HydreonRGxxComponent), | ||||||
|  |         cv.Optional(CONF_TOO_COLD): binary_sensor.binary_sensor_schema( | ||||||
|  |             device_class=DEVICE_CLASS_COLD | ||||||
|  |         ), | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def to_code(config): | ||||||
|  |     main_sensor = await cg.get_variable(config[CONF_HYDREON_RGXX_ID]) | ||||||
|  |     bin_component = cg.new_Pvariable(config[CONF_ID], main_sensor) | ||||||
|  |     await cg.register_component(bin_component, config) | ||||||
|  |     if CONF_TOO_COLD in config: | ||||||
|  |         tc = await binary_sensor.new_binary_sensor(config[CONF_TOO_COLD]) | ||||||
|  |         cg.add(main_sensor.set_too_cold_sensor(tc)) | ||||||
							
								
								
									
										211
									
								
								esphome/components/hydreon_rgxx/hydreon_rgxx.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										211
									
								
								esphome/components/hydreon_rgxx/hydreon_rgxx.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,211 @@ | |||||||
|  | #include "hydreon_rgxx.h" | ||||||
|  | #include "esphome/core/log.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace hydreon_rgxx { | ||||||
|  |  | ||||||
|  | static const char *const TAG = "hydreon_rgxx.sensor"; | ||||||
|  | static const int MAX_DATA_LENGTH_BYTES = 80; | ||||||
|  | static const uint8_t ASCII_LF = 0x0A; | ||||||
|  | #define HYDREON_RGXX_COMMA , | ||||||
|  | static const char *const PROTOCOL_NAMES[] = {HYDREON_RGXX_PROTOCOL_LIST(, HYDREON_RGXX_COMMA)}; | ||||||
|  |  | ||||||
|  | void HydreonRGxxComponent::dump_config() { | ||||||
|  |   this->check_uart_settings(9600, 1, esphome::uart::UART_CONFIG_PARITY_NONE, 8); | ||||||
|  |   ESP_LOGCONFIG(TAG, "hydreon_rgxx:"); | ||||||
|  |   if (this->is_failed()) { | ||||||
|  |     ESP_LOGE(TAG, "Connection with hydreon_rgxx failed!"); | ||||||
|  |   } | ||||||
|  |   LOG_UPDATE_INTERVAL(this); | ||||||
|  |  | ||||||
|  |   int i = 0; | ||||||
|  | #define HYDREON_RGXX_LOG_SENSOR(s) \ | ||||||
|  |   if (this->sensors_[i++] != nullptr) { \ | ||||||
|  |     LOG_SENSOR("  ", #s, this->sensors_[i - 1]); \ | ||||||
|  |   } | ||||||
|  |   HYDREON_RGXX_PROTOCOL_LIST(HYDREON_RGXX_LOG_SENSOR, ); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void HydreonRGxxComponent::setup() { | ||||||
|  |   ESP_LOGCONFIG(TAG, "Setting up hydreon_rgxx..."); | ||||||
|  |   while (this->available() != 0) { | ||||||
|  |     this->read(); | ||||||
|  |   } | ||||||
|  |   this->schedule_reboot_(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool HydreonRGxxComponent::sensor_missing_() { | ||||||
|  |   if (this->sensors_received_ == -1) { | ||||||
|  |     // no request sent yet, don't check | ||||||
|  |     return false; | ||||||
|  |   } else { | ||||||
|  |     if (this->sensors_received_ == 0) { | ||||||
|  |       ESP_LOGW(TAG, "No data at all"); | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |     for (int i = 0; i < NUM_SENSORS; i++) { | ||||||
|  |       if (this->sensors_[i] == nullptr) { | ||||||
|  |         continue; | ||||||
|  |       } | ||||||
|  |       if ((this->sensors_received_ >> i & 1) == 0) { | ||||||
|  |         ESP_LOGW(TAG, "Missing %s", PROTOCOL_NAMES[i]); | ||||||
|  |         return true; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void HydreonRGxxComponent::update() { | ||||||
|  |   if (this->boot_count_ > 0) { | ||||||
|  |     if (this->sensor_missing_()) { | ||||||
|  |       this->no_response_count_++; | ||||||
|  |       ESP_LOGE(TAG, "data missing %d times", this->no_response_count_); | ||||||
|  |       if (this->no_response_count_ > 15) { | ||||||
|  |         ESP_LOGE(TAG, "asking sensor to reboot"); | ||||||
|  |         for (auto &sensor : this->sensors_) { | ||||||
|  |           if (sensor != nullptr) { | ||||||
|  |             sensor->publish_state(NAN); | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |         this->schedule_reboot_(); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |     } else { | ||||||
|  |       this->no_response_count_ = 0; | ||||||
|  |     } | ||||||
|  |     this->write_str("R\n"); | ||||||
|  | #ifdef USE_BINARY_SENSOR | ||||||
|  |     if (this->too_cold_sensor_ != nullptr) { | ||||||
|  |       this->too_cold_sensor_->publish_state(this->too_cold_); | ||||||
|  |     } | ||||||
|  | #endif | ||||||
|  |     this->too_cold_ = false; | ||||||
|  |     this->sensors_received_ = 0; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void HydreonRGxxComponent::loop() { | ||||||
|  |   uint8_t data; | ||||||
|  |   while (this->available() > 0) { | ||||||
|  |     if (this->read_byte(&data)) { | ||||||
|  |       buffer_ += (char) data; | ||||||
|  |       if (this->buffer_.back() == static_cast<char>(ASCII_LF) || this->buffer_.length() >= MAX_DATA_LENGTH_BYTES) { | ||||||
|  |         // complete line received | ||||||
|  |         this->process_line_(); | ||||||
|  |         this->buffer_.clear(); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Communication with the sensor is asynchronous. | ||||||
|  |  * We send requests and let esphome continue doing its thing. | ||||||
|  |  * Once we have received a complete line, we process it. | ||||||
|  |  * | ||||||
|  |  * Catching communication failures is done in two layers: | ||||||
|  |  * | ||||||
|  |  * 1. We check if all requested data has been received | ||||||
|  |  *    before we send out the next request. If data keeps | ||||||
|  |  *    missing, we escalate. | ||||||
|  |  * 2. Request the sensor to reboot. We retry based on | ||||||
|  |  *    a timeout. If the sensor does not respond after | ||||||
|  |  *    several boot attempts, we give up. | ||||||
|  |  */ | ||||||
|  | void HydreonRGxxComponent::schedule_reboot_() { | ||||||
|  |   this->boot_count_ = 0; | ||||||
|  |   this->set_interval("reboot", 5000, [this]() { | ||||||
|  |     if (this->boot_count_ < 0) { | ||||||
|  |       ESP_LOGW(TAG, "hydreon_rgxx failed to boot %d times", -this->boot_count_); | ||||||
|  |     } | ||||||
|  |     this->boot_count_--; | ||||||
|  |     this->write_str("K\n"); | ||||||
|  |     if (this->boot_count_ < -5) { | ||||||
|  |       ESP_LOGE(TAG, "hydreon_rgxx can't boot, giving up"); | ||||||
|  |       for (auto &sensor : this->sensors_) { | ||||||
|  |         if (sensor != nullptr) { | ||||||
|  |           sensor->publish_state(NAN); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       this->mark_failed(); | ||||||
|  |     } | ||||||
|  |   }); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool HydreonRGxxComponent::buffer_starts_with_(const std::string &prefix) { | ||||||
|  |   return this->buffer_starts_with_(prefix.c_str()); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | bool HydreonRGxxComponent::buffer_starts_with_(const char *prefix) { return buffer_.rfind(prefix, 0) == 0; } | ||||||
|  |  | ||||||
|  | void HydreonRGxxComponent::process_line_() { | ||||||
|  |   ESP_LOGV(TAG, "Read from serial: %s", this->buffer_.substr(0, this->buffer_.size() - 2).c_str()); | ||||||
|  |  | ||||||
|  |   if (buffer_[0] == ';') { | ||||||
|  |     ESP_LOGI(TAG, "Comment: %s", this->buffer_.substr(0, this->buffer_.size() - 2).c_str()); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   if (this->buffer_starts_with_("PwrDays")) { | ||||||
|  |     if (this->boot_count_ <= 0) { | ||||||
|  |       this->boot_count_ = 1; | ||||||
|  |     } else { | ||||||
|  |       this->boot_count_++; | ||||||
|  |     } | ||||||
|  |     this->cancel_interval("reboot"); | ||||||
|  |     this->no_response_count_ = 0; | ||||||
|  |     ESP_LOGI(TAG, "Boot detected: %s", this->buffer_.substr(0, this->buffer_.size() - 2).c_str()); | ||||||
|  |     this->write_str("P\nH\nM\n");  // set sensor to polling mode, high res mode, metric mode | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   if (this->buffer_starts_with_("SW")) { | ||||||
|  |     std::string::size_type majend = this->buffer_.find('.'); | ||||||
|  |     std::string::size_type endversion = this->buffer_.find(' ', 3); | ||||||
|  |     if (majend == std::string::npos || endversion == std::string::npos || majend > endversion) { | ||||||
|  |       ESP_LOGW(TAG, "invalid version string: %s", this->buffer_.substr(0, this->buffer_.size() - 2).c_str()); | ||||||
|  |     } | ||||||
|  |     int major = strtol(this->buffer_.substr(3, majend - 3).c_str(), nullptr, 10); | ||||||
|  |     int minor = strtol(this->buffer_.substr(majend + 1, endversion - (majend + 1)).c_str(), nullptr, 10); | ||||||
|  |  | ||||||
|  |     if (major > 10 || minor >= 1000 || minor < 0 || major < 0) { | ||||||
|  |       ESP_LOGW(TAG, "invalid version: %s", this->buffer_.substr(0, this->buffer_.size() - 2).c_str()); | ||||||
|  |     } | ||||||
|  |     this->sw_version_ = major * 1000 + minor; | ||||||
|  |     ESP_LOGI(TAG, "detected sw version %i", this->sw_version_); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |   bool is_data_line = false; | ||||||
|  |   for (int i = 0; i < NUM_SENSORS; i++) { | ||||||
|  |     if (this->sensors_[i] != nullptr && this->buffer_starts_with_(PROTOCOL_NAMES[i])) { | ||||||
|  |       is_data_line = true; | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   if (is_data_line) { | ||||||
|  |     std::string::size_type tc = this->buffer_.find("TooCold"); | ||||||
|  |     this->too_cold_ |= tc != std::string::npos; | ||||||
|  |     if (this->too_cold_) { | ||||||
|  |       ESP_LOGD(TAG, "Received TooCold"); | ||||||
|  |     } | ||||||
|  |     for (int i = 0; i < NUM_SENSORS; i++) { | ||||||
|  |       if (this->sensors_[i] == nullptr) { | ||||||
|  |         continue; | ||||||
|  |       } | ||||||
|  |       std::string::size_type n = this->buffer_.find(PROTOCOL_NAMES[i]); | ||||||
|  |       if (n == std::string::npos) { | ||||||
|  |         continue; | ||||||
|  |       } | ||||||
|  |       int data = strtol(this->buffer_.substr(n + strlen(PROTOCOL_NAMES[i])).c_str(), nullptr, 10); | ||||||
|  |       this->sensors_[i]->publish_state(data); | ||||||
|  |       ESP_LOGD(TAG, "Received %s: %f", PROTOCOL_NAMES[i], this->sensors_[i]->get_raw_state()); | ||||||
|  |       this->sensors_received_ |= (1 << i); | ||||||
|  |     } | ||||||
|  |   } else { | ||||||
|  |     ESP_LOGI(TAG, "Got unknown line: %s", this->buffer_.c_str()); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | float HydreonRGxxComponent::get_setup_priority() const { return setup_priority::DATA; } | ||||||
|  |  | ||||||
|  | }  // namespace hydreon_rgxx | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										76
									
								
								esphome/components/hydreon_rgxx/hydreon_rgxx.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										76
									
								
								esphome/components/hydreon_rgxx/hydreon_rgxx.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,76 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "esphome/core/component.h" | ||||||
|  | #include "esphome/core/defines.h" | ||||||
|  | #include "esphome/components/sensor/sensor.h" | ||||||
|  | #ifdef USE_BINARY_SENSOR | ||||||
|  | #include "esphome/components/binary_sensor/binary_sensor.h" | ||||||
|  | #endif | ||||||
|  | #include "esphome/components/uart/uart.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace hydreon_rgxx { | ||||||
|  |  | ||||||
|  | enum RGModel { | ||||||
|  |   RG9 = 1, | ||||||
|  |   RG15 = 2, | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | #ifdef HYDREON_RGXX_NUM_SENSORS | ||||||
|  | static const uint8_t NUM_SENSORS = HYDREON_RGXX_NUM_SENSORS; | ||||||
|  | #else | ||||||
|  | static const uint8_t NUM_SENSORS = 1; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #ifndef HYDREON_RGXX_PROTOCOL_LIST | ||||||
|  | #define HYDREON_RGXX_PROTOCOL_LIST(F, SEP) F("") | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | class HydreonRGxxComponent : public PollingComponent, public uart::UARTDevice { | ||||||
|  |  public: | ||||||
|  |   void set_sensor(sensor::Sensor *sensor, int index) { this->sensors_[index] = sensor; } | ||||||
|  | #ifdef USE_BINARY_SENSOR | ||||||
|  |   void set_too_cold_sensor(binary_sensor::BinarySensor *sensor) { this->too_cold_sensor_ = sensor; } | ||||||
|  | #endif | ||||||
|  |   void set_model(RGModel model) { model_ = model; } | ||||||
|  |  | ||||||
|  |   /// Schedule data readings. | ||||||
|  |   void update() override; | ||||||
|  |   /// Read data once available | ||||||
|  |   void loop() override; | ||||||
|  |   /// Setup the sensor and test for a connection. | ||||||
|  |   void setup() override; | ||||||
|  |   void dump_config() override; | ||||||
|  |  | ||||||
|  |   float get_setup_priority() const override; | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   void process_line_(); | ||||||
|  |   void schedule_reboot_(); | ||||||
|  |   bool buffer_starts_with_(const std::string &prefix); | ||||||
|  |   bool buffer_starts_with_(const char *prefix); | ||||||
|  |   bool sensor_missing_(); | ||||||
|  |  | ||||||
|  |   sensor::Sensor *sensors_[NUM_SENSORS] = {nullptr}; | ||||||
|  | #ifdef USE_BINARY_SENSOR | ||||||
|  |   binary_sensor::BinarySensor *too_cold_sensor_ = nullptr; | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |   int16_t boot_count_ = 0; | ||||||
|  |   int16_t no_response_count_ = 0; | ||||||
|  |   std::string buffer_; | ||||||
|  |   RGModel model_ = RG9; | ||||||
|  |   int sw_version_ = 0; | ||||||
|  |   bool too_cold_ = false; | ||||||
|  |  | ||||||
|  |   // bit field showing which sensors we have received data for | ||||||
|  |   int sensors_received_ = -1; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class HydreonRGxxBinaryComponent : public Component { | ||||||
|  |  public: | ||||||
|  |   HydreonRGxxBinaryComponent(HydreonRGxxComponent *parent) {} | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace hydreon_rgxx | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										119
									
								
								esphome/components/hydreon_rgxx/sensor.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								esphome/components/hydreon_rgxx/sensor.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,119 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome.components import uart, sensor | ||||||
|  | from esphome.const import ( | ||||||
|  |     CONF_ID, | ||||||
|  |     CONF_MODEL, | ||||||
|  |     CONF_MOISTURE, | ||||||
|  |     DEVICE_CLASS_HUMIDITY, | ||||||
|  |     STATE_CLASS_MEASUREMENT, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | from . import RGModel, HydreonRGxxComponent | ||||||
|  |  | ||||||
|  | UNIT_INTENSITY = "intensity" | ||||||
|  | UNIT_MILLIMETERS = "mm" | ||||||
|  | UNIT_MILLIMETERS_PER_HOUR = "mm/h" | ||||||
|  |  | ||||||
|  | CONF_ACC = "acc" | ||||||
|  | CONF_EVENT_ACC = "event_acc" | ||||||
|  | CONF_TOTAL_ACC = "total_acc" | ||||||
|  | CONF_R_INT = "r_int" | ||||||
|  |  | ||||||
|  | RG_MODELS = { | ||||||
|  |     "RG_9": RGModel.RG9, | ||||||
|  |     "RG_15": RGModel.RG15, | ||||||
|  |     # https://rainsensors.com/wp-content/uploads/sites/3/2020/07/rg-15_instructions_sw_1.000.pdf | ||||||
|  |     # https://rainsensors.com/wp-content/uploads/sites/3/2021/03/2020.08.25-rg-9_instructions.pdf | ||||||
|  |     # https://rainsensors.com/wp-content/uploads/sites/3/2021/03/2021.03.11-rg-9_instructions.pdf | ||||||
|  | } | ||||||
|  | SUPPORTED_SENSORS = { | ||||||
|  |     CONF_ACC: ["RG_15"], | ||||||
|  |     CONF_EVENT_ACC: ["RG_15"], | ||||||
|  |     CONF_TOTAL_ACC: ["RG_15"], | ||||||
|  |     CONF_R_INT: ["RG_15"], | ||||||
|  |     CONF_MOISTURE: ["RG_9"], | ||||||
|  | } | ||||||
|  | PROTOCOL_NAMES = { | ||||||
|  |     CONF_MOISTURE: "R", | ||||||
|  |     CONF_ACC: "Acc", | ||||||
|  |     CONF_R_INT: "Rint", | ||||||
|  |     CONF_EVENT_ACC: "EventAcc", | ||||||
|  |     CONF_TOTAL_ACC: "TotalAcc", | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def _validate(config): | ||||||
|  |     for conf, models in SUPPORTED_SENSORS.items(): | ||||||
|  |         if conf in config: | ||||||
|  |             if config[CONF_MODEL] not in models: | ||||||
|  |                 raise cv.Invalid( | ||||||
|  |                     f"{conf} is only available on {' and '.join(models)}, not {config[CONF_MODEL]}" | ||||||
|  |                 ) | ||||||
|  |     return config | ||||||
|  |  | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = cv.All( | ||||||
|  |     cv.Schema( | ||||||
|  |         { | ||||||
|  |             cv.GenerateID(): cv.declare_id(HydreonRGxxComponent), | ||||||
|  |             cv.Required(CONF_MODEL): cv.enum( | ||||||
|  |                 RG_MODELS, | ||||||
|  |                 upper=True, | ||||||
|  |                 space="_", | ||||||
|  |             ), | ||||||
|  |             cv.Optional(CONF_ACC): sensor.sensor_schema( | ||||||
|  |                 unit_of_measurement=UNIT_MILLIMETERS, | ||||||
|  |                 accuracy_decimals=2, | ||||||
|  |                 device_class=DEVICE_CLASS_HUMIDITY, | ||||||
|  |                 state_class=STATE_CLASS_MEASUREMENT, | ||||||
|  |             ), | ||||||
|  |             cv.Optional(CONF_EVENT_ACC): sensor.sensor_schema( | ||||||
|  |                 unit_of_measurement=UNIT_MILLIMETERS, | ||||||
|  |                 accuracy_decimals=2, | ||||||
|  |                 device_class=DEVICE_CLASS_HUMIDITY, | ||||||
|  |                 state_class=STATE_CLASS_MEASUREMENT, | ||||||
|  |             ), | ||||||
|  |             cv.Optional(CONF_TOTAL_ACC): sensor.sensor_schema( | ||||||
|  |                 unit_of_measurement=UNIT_MILLIMETERS, | ||||||
|  |                 accuracy_decimals=2, | ||||||
|  |                 device_class=DEVICE_CLASS_HUMIDITY, | ||||||
|  |                 state_class=STATE_CLASS_MEASUREMENT, | ||||||
|  |             ), | ||||||
|  |             cv.Optional(CONF_R_INT): sensor.sensor_schema( | ||||||
|  |                 unit_of_measurement=UNIT_MILLIMETERS_PER_HOUR, | ||||||
|  |                 accuracy_decimals=2, | ||||||
|  |                 device_class=DEVICE_CLASS_HUMIDITY, | ||||||
|  |                 state_class=STATE_CLASS_MEASUREMENT, | ||||||
|  |             ), | ||||||
|  |             cv.Optional(CONF_MOISTURE): sensor.sensor_schema( | ||||||
|  |                 unit_of_measurement=UNIT_INTENSITY, | ||||||
|  |                 accuracy_decimals=0, | ||||||
|  |                 device_class=DEVICE_CLASS_HUMIDITY, | ||||||
|  |                 state_class=STATE_CLASS_MEASUREMENT, | ||||||
|  |             ), | ||||||
|  |         } | ||||||
|  |     ) | ||||||
|  |     .extend(cv.polling_component_schema("60s")) | ||||||
|  |     .extend(uart.UART_DEVICE_SCHEMA), | ||||||
|  |     _validate, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def to_code(config): | ||||||
|  |     var = cg.new_Pvariable(config[CONF_ID]) | ||||||
|  |     await cg.register_component(var, config) | ||||||
|  |     await uart.register_uart_device(var, config) | ||||||
|  |  | ||||||
|  |     cg.add_define( | ||||||
|  |         "HYDREON_RGXX_PROTOCOL_LIST(F, sep)", | ||||||
|  |         cg.RawExpression( | ||||||
|  |             " sep ".join([f'F("{name}")' for name in PROTOCOL_NAMES.values()]) | ||||||
|  |         ), | ||||||
|  |     ) | ||||||
|  |     cg.add_define("HYDREON_RGXX_NUM_SENSORS", len(PROTOCOL_NAMES)) | ||||||
|  |  | ||||||
|  |     for i, conf in enumerate(PROTOCOL_NAMES): | ||||||
|  |         if conf in config: | ||||||
|  |             sens = await sensor.new_sensor(config[conf]) | ||||||
|  |             cg.add(var.set_sensor(sens, i)) | ||||||
| @@ -349,6 +349,24 @@ sensor: | |||||||
|       name: 'Temperature' |       name: 'Temperature' | ||||||
|     humidity: |     humidity: | ||||||
|       name: 'Humidity' |       name: 'Humidity' | ||||||
|  |   - platform: hydreon_rgxx | ||||||
|  |     model: "RG 9" | ||||||
|  |     uart_id: uart6 | ||||||
|  |     id: "hydreon_rg9" | ||||||
|  |     moisture: | ||||||
|  |       name: "hydreon_rain" | ||||||
|  |       id: hydreon_rain | ||||||
|  |   - platform: hydreon_rgxx | ||||||
|  |     model: "RG_15" | ||||||
|  |     uart_id: uart6 | ||||||
|  |     acc: | ||||||
|  |       name: "hydreon_acc" | ||||||
|  |     event_acc: | ||||||
|  |       name: "hydreon_event_acc" | ||||||
|  |     total_acc: | ||||||
|  |       name: "hydreon_total_acc" | ||||||
|  |     r_int: | ||||||
|  |       name: "hydreon_r_int" | ||||||
|   - platform: adc |   - platform: adc | ||||||
|     pin: VCC |     pin: VCC | ||||||
|     id: my_sensor |     id: my_sensor | ||||||
| @@ -796,6 +814,10 @@ binary_sensor: | |||||||
|       then: |       then: | ||||||
|         - cover.toggle: time_based_cover |         - cover.toggle: time_based_cover | ||||||
|         - cover.toggle: endstop_cover |         - cover.toggle: endstop_cover | ||||||
|  |   - platform: hydreon_rgxx | ||||||
|  |     hydreon_rgxx_id: "hydreon_rg9" | ||||||
|  |     too_cold: | ||||||
|  |       name: "rg9_toocold" | ||||||
|   - platform: template |   - platform: template | ||||||
|     id: 'pzemac_reset_energy' |     id: 'pzemac_reset_energy' | ||||||
|     on_press: |     on_press: | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user