mirror of
				https://github.com/esphome/esphome.git
				synced 2025-10-31 07:03:55 +00:00 
			
		
		
		
	Add Micronova component (#4760)
Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Co-authored-by: Graham Brown <grahambrown11@gmail.com>
This commit is contained in:
		| @@ -184,6 +184,7 @@ esphome/components/mcp9808/* @k7hpn | |||||||
| esphome/components/md5/* @esphome/core | esphome/components/md5/* @esphome/core | ||||||
| esphome/components/mdns/* @esphome/core | esphome/components/mdns/* @esphome/core | ||||||
| esphome/components/media_player/* @jesserockz | esphome/components/media_player/* @jesserockz | ||||||
|  | esphome/components/micronova/* @jorre05 | ||||||
| esphome/components/microphone/* @jesserockz | esphome/components/microphone/* @jesserockz | ||||||
| esphome/components/mics_4514/* @jesserockz | esphome/components/mics_4514/* @jesserockz | ||||||
| esphome/components/midea/* @dudanov | esphome/components/midea/* @dudanov | ||||||
|   | |||||||
							
								
								
									
										69
									
								
								esphome/components/micronova/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								esphome/components/micronova/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome import pins | ||||||
|  | from esphome.components import uart | ||||||
|  | from esphome.const import ( | ||||||
|  |     CONF_ID, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | CODEOWNERS = ["@jorre05"] | ||||||
|  |  | ||||||
|  | DEPENDENCIES = ["uart"] | ||||||
|  |  | ||||||
|  | CONF_MICRONOVA_ID = "micronova_id" | ||||||
|  | CONF_ENABLE_RX_PIN = "enable_rx_pin" | ||||||
|  | CONF_MEMORY_LOCATION = "memory_location" | ||||||
|  | CONF_MEMORY_ADDRESS = "memory_address" | ||||||
|  |  | ||||||
|  | micronova_ns = cg.esphome_ns.namespace("micronova") | ||||||
|  |  | ||||||
|  | MicroNovaFunctions = micronova_ns.enum("MicroNovaFunctions", is_class=True) | ||||||
|  | MICRONOVA_FUNCTIONS_ENUM = { | ||||||
|  |     "STOVE_FUNCTION_SWITCH": MicroNovaFunctions.STOVE_FUNCTION_SWITCH, | ||||||
|  |     "STOVE_FUNCTION_ROOM_TEMPERATURE": MicroNovaFunctions.STOVE_FUNCTION_ROOM_TEMPERATURE, | ||||||
|  |     "STOVE_FUNCTION_THERMOSTAT_TEMPERATURE": MicroNovaFunctions.STOVE_FUNCTION_THERMOSTAT_TEMPERATURE, | ||||||
|  |     "STOVE_FUNCTION_FUMES_TEMPERATURE": MicroNovaFunctions.STOVE_FUNCTION_FUMES_TEMPERATURE, | ||||||
|  |     "STOVE_FUNCTION_STOVE_POWER": MicroNovaFunctions.STOVE_FUNCTION_STOVE_POWER, | ||||||
|  |     "STOVE_FUNCTION_FAN_SPEED": MicroNovaFunctions.STOVE_FUNCTION_FAN_SPEED, | ||||||
|  |     "STOVE_FUNCTION_STOVE_STATE": MicroNovaFunctions.STOVE_FUNCTION_STOVE_STATE, | ||||||
|  |     "STOVE_FUNCTION_MEMORY_ADDRESS_SENSOR": MicroNovaFunctions.STOVE_FUNCTION_MEMORY_ADDRESS_SENSOR, | ||||||
|  |     "STOVE_FUNCTION_WATER_TEMPERATURE": MicroNovaFunctions.STOVE_FUNCTION_WATER_TEMPERATURE, | ||||||
|  |     "STOVE_FUNCTION_WATER_PRESSURE": MicroNovaFunctions.STOVE_FUNCTION_WATER_PRESSURE, | ||||||
|  |     "STOVE_FUNCTION_POWER_LEVEL": MicroNovaFunctions.STOVE_FUNCTION_POWER_LEVEL, | ||||||
|  |     "STOVE_FUNCTION_CUSTOM": MicroNovaFunctions.STOVE_FUNCTION_CUSTOM, | ||||||
|  | } | ||||||
|  |  | ||||||
|  | MicroNova = micronova_ns.class_("MicroNova", cg.PollingComponent, uart.UARTDevice) | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = ( | ||||||
|  |     cv.Schema( | ||||||
|  |         { | ||||||
|  |             cv.GenerateID(): cv.declare_id(MicroNova), | ||||||
|  |             cv.Required(CONF_ENABLE_RX_PIN): pins.gpio_output_pin_schema, | ||||||
|  |         } | ||||||
|  |     ) | ||||||
|  |     .extend(uart.UART_DEVICE_SCHEMA) | ||||||
|  |     .extend(cv.polling_component_schema("60s")) | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | def MICRONOVA_LISTENER_SCHEMA(default_memory_location, default_memory_address): | ||||||
|  |     return cv.Schema( | ||||||
|  |         { | ||||||
|  |             cv.GenerateID(CONF_MICRONOVA_ID): cv.use_id(MicroNova), | ||||||
|  |             cv.Optional( | ||||||
|  |                 CONF_MEMORY_LOCATION, default=default_memory_location | ||||||
|  |             ): cv.hex_int_range(), | ||||||
|  |             cv.Optional( | ||||||
|  |                 CONF_MEMORY_ADDRESS, default=default_memory_address | ||||||
|  |             ): cv.hex_int_range(), | ||||||
|  |         } | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | 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) | ||||||
|  |     enable_rx_pin = await cg.gpio_pin_expression(config[CONF_ENABLE_RX_PIN]) | ||||||
|  |     cg.add(var.set_enable_rx_pin(enable_rx_pin)) | ||||||
							
								
								
									
										44
									
								
								esphome/components/micronova/button/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								esphome/components/micronova/button/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome.components import button | ||||||
|  |  | ||||||
|  | from .. import ( | ||||||
|  |     MicroNova, | ||||||
|  |     MicroNovaFunctions, | ||||||
|  |     CONF_MICRONOVA_ID, | ||||||
|  |     CONF_MEMORY_LOCATION, | ||||||
|  |     CONF_MEMORY_ADDRESS, | ||||||
|  |     MICRONOVA_LISTENER_SCHEMA, | ||||||
|  |     micronova_ns, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | MicroNovaButton = micronova_ns.class_("MicroNovaButton", button.Button, cg.Component) | ||||||
|  |  | ||||||
|  | CONF_CUSTOM_BUTTON = "custom_button" | ||||||
|  | CONF_MEMORY_DATA = "memory_data" | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = cv.Schema( | ||||||
|  |     { | ||||||
|  |         cv.GenerateID(CONF_MICRONOVA_ID): cv.use_id(MicroNova), | ||||||
|  |         cv.Optional(CONF_CUSTOM_BUTTON): button.button_schema( | ||||||
|  |             MicroNovaButton, | ||||||
|  |         ) | ||||||
|  |         .extend( | ||||||
|  |             MICRONOVA_LISTENER_SCHEMA( | ||||||
|  |                 default_memory_location=0xA0, default_memory_address=0x7D | ||||||
|  |             ) | ||||||
|  |         ) | ||||||
|  |         .extend({cv.Required(CONF_MEMORY_DATA): cv.hex_int_range()}), | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def to_code(config): | ||||||
|  |     mv = await cg.get_variable(config[CONF_MICRONOVA_ID]) | ||||||
|  |  | ||||||
|  |     if custom_button_config := config.get(CONF_CUSTOM_BUTTON): | ||||||
|  |         bt = await button.new_button(custom_button_config, mv) | ||||||
|  |         cg.add(bt.set_memory_location(custom_button_config.get(CONF_MEMORY_LOCATION))) | ||||||
|  |         cg.add(bt.set_memory_address(custom_button_config.get(CONF_MEMORY_ADDRESS))) | ||||||
|  |         cg.add(bt.set_memory_data(custom_button_config[CONF_MEMORY_DATA])) | ||||||
|  |         cg.add(bt.set_function(MicroNovaFunctions.STOVE_FUNCTION_CUSTOM)) | ||||||
							
								
								
									
										18
									
								
								esphome/components/micronova/button/micronova_button.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								esphome/components/micronova/button/micronova_button.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | |||||||
|  | #include "micronova_button.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace micronova { | ||||||
|  |  | ||||||
|  | void MicroNovaButton::press_action() { | ||||||
|  |   switch (this->get_function()) { | ||||||
|  |     case MicroNovaFunctions::STOVE_FUNCTION_CUSTOM: | ||||||
|  |       this->micronova_->write_address(this->memory_location_, this->memory_address_, this->memory_data_); | ||||||
|  |       break; | ||||||
|  |     default: | ||||||
|  |       break; | ||||||
|  |   } | ||||||
|  |   this->micronova_->update(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace micronova | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										23
									
								
								esphome/components/micronova/button/micronova_button.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								esphome/components/micronova/button/micronova_button.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "esphome/components/micronova/micronova.h" | ||||||
|  | #include "esphome/core/component.h" | ||||||
|  | #include "esphome/components/button/button.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace micronova { | ||||||
|  |  | ||||||
|  | class MicroNovaButton : public Component, public button::Button, public MicroNovaButtonListener { | ||||||
|  |  public: | ||||||
|  |   MicroNovaButton(MicroNova *m) : MicroNovaButtonListener(m) {} | ||||||
|  |   void dump_config() override { LOG_BUTTON("", "Micronova button", this); } | ||||||
|  |  | ||||||
|  |   void set_memory_data(uint8_t f) { this->memory_data_ = f; } | ||||||
|  |   uint8_t get_memory_data() { return this->memory_data_; } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   void press_action() override; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace micronova | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										148
									
								
								esphome/components/micronova/micronova.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										148
									
								
								esphome/components/micronova/micronova.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,148 @@ | |||||||
|  | #include "micronova.h" | ||||||
|  | #include "esphome/core/log.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace micronova { | ||||||
|  |  | ||||||
|  | void MicroNova::setup() { | ||||||
|  |   if (this->enable_rx_pin_ != nullptr) { | ||||||
|  |     this->enable_rx_pin_->setup(); | ||||||
|  |     this->enable_rx_pin_->pin_mode(gpio::FLAG_OUTPUT); | ||||||
|  |     this->enable_rx_pin_->digital_write(false); | ||||||
|  |   } | ||||||
|  |   this->current_transmission_.request_transmission_time = millis(); | ||||||
|  |   this->current_transmission_.memory_location = 0; | ||||||
|  |   this->current_transmission_.memory_address = 0; | ||||||
|  |   this->current_transmission_.reply_pending = false; | ||||||
|  |   this->current_transmission_.initiating_listener = nullptr; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void MicroNova::dump_config() { | ||||||
|  |   ESP_LOGCONFIG(TAG, "MicroNova:"); | ||||||
|  |   if (this->enable_rx_pin_ != nullptr) { | ||||||
|  |     LOG_PIN("  Enable RX Pin: ", this->enable_rx_pin_); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   for (auto &mv_sensor : this->micronova_listeners_) { | ||||||
|  |     mv_sensor->dump_config(); | ||||||
|  |     ESP_LOGCONFIG(TAG, "    sensor location:%02X, address:%02X", mv_sensor->get_memory_location(), | ||||||
|  |                   mv_sensor->get_memory_address()); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void MicroNova::update() { | ||||||
|  |   ESP_LOGD(TAG, "Schedule sensor update"); | ||||||
|  |   for (auto &mv_listener : this->micronova_listeners_) { | ||||||
|  |     mv_listener->set_needs_update(true); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void MicroNova::loop() { | ||||||
|  |   // Only read one sensor that needs update per loop | ||||||
|  |   // If STOVE_REPLY_DELAY time has passed since last loop() | ||||||
|  |   // check for a reply from the stove | ||||||
|  |   if ((this->current_transmission_.reply_pending) && | ||||||
|  |       (millis() - this->current_transmission_.request_transmission_time > STOVE_REPLY_DELAY)) { | ||||||
|  |     int stove_reply_value = this->read_stove_reply(); | ||||||
|  |     if (this->current_transmission_.initiating_listener != nullptr) { | ||||||
|  |       this->current_transmission_.initiating_listener->process_value_from_stove(stove_reply_value); | ||||||
|  |       this->current_transmission_.initiating_listener = nullptr; | ||||||
|  |     } | ||||||
|  |     this->current_transmission_.reply_pending = false; | ||||||
|  |     return; | ||||||
|  |   } else if (!this->current_transmission_.reply_pending) { | ||||||
|  |     for (auto &mv_listener : this->micronova_listeners_) { | ||||||
|  |       if (mv_listener->get_needs_update()) { | ||||||
|  |         mv_listener->set_needs_update(false); | ||||||
|  |         this->current_transmission_.initiating_listener = mv_listener; | ||||||
|  |         mv_listener->request_value_from_stove(); | ||||||
|  |         return; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void MicroNova::request_address(uint8_t location, uint8_t address, MicroNovaSensorListener *listener) { | ||||||
|  |   uint8_t write_data[2] = {0, 0}; | ||||||
|  |   uint8_t trash_rx; | ||||||
|  |  | ||||||
|  |   if (this->reply_pending_mutex_.try_lock()) { | ||||||
|  |     // clear rx buffer. | ||||||
|  |     // Stove hickups may cause late replies in the rx | ||||||
|  |     while (this->available()) { | ||||||
|  |       this->read_byte(&trash_rx); | ||||||
|  |       ESP_LOGW(TAG, "Reading excess byte 0x%02X", trash_rx); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     write_data[0] = location; | ||||||
|  |     write_data[1] = address; | ||||||
|  |     ESP_LOGV(TAG, "Request from stove [%02X,%02X]", write_data[0], write_data[1]); | ||||||
|  |  | ||||||
|  |     this->enable_rx_pin_->digital_write(true); | ||||||
|  |     this->write_array(write_data, 2); | ||||||
|  |     this->flush(); | ||||||
|  |     this->enable_rx_pin_->digital_write(false); | ||||||
|  |  | ||||||
|  |     this->current_transmission_.request_transmission_time = millis(); | ||||||
|  |     this->current_transmission_.memory_location = location; | ||||||
|  |     this->current_transmission_.memory_address = address; | ||||||
|  |     this->current_transmission_.reply_pending = true; | ||||||
|  |     this->current_transmission_.initiating_listener = listener; | ||||||
|  |   } else { | ||||||
|  |     ESP_LOGE(TAG, "Reply is pending, skipping read request"); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int MicroNova::read_stove_reply() { | ||||||
|  |   uint8_t reply_data[2] = {0, 0}; | ||||||
|  |   uint8_t checksum = 0; | ||||||
|  |  | ||||||
|  |   // assert enable_rx_pin is false | ||||||
|  |   this->read_array(reply_data, 2); | ||||||
|  |  | ||||||
|  |   this->reply_pending_mutex_.unlock(); | ||||||
|  |   ESP_LOGV(TAG, "Reply from stove [%02X,%02X]", reply_data[0], reply_data[1]); | ||||||
|  |  | ||||||
|  |   checksum = ((uint16_t) this->current_transmission_.memory_location + | ||||||
|  |               (uint16_t) this->current_transmission_.memory_address + (uint16_t) reply_data[1]) & | ||||||
|  |              0xFF; | ||||||
|  |   if (reply_data[0] != checksum) { | ||||||
|  |     ESP_LOGE(TAG, "Checksum missmatch! From [0x%02X:0x%02X] received [0x%02X,0x%02X]. Expected 0x%02X, got 0x%02X", | ||||||
|  |              this->current_transmission_.memory_location, this->current_transmission_.memory_address, reply_data[0], | ||||||
|  |              reply_data[1], checksum, reply_data[0]); | ||||||
|  |     return -1; | ||||||
|  |   } | ||||||
|  |   return ((int) reply_data[1]); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void MicroNova::write_address(uint8_t location, uint8_t address, uint8_t data) { | ||||||
|  |   uint8_t write_data[4] = {0, 0, 0, 0}; | ||||||
|  |   uint16_t checksum = 0; | ||||||
|  |  | ||||||
|  |   if (this->reply_pending_mutex_.try_lock()) { | ||||||
|  |     write_data[0] = location; | ||||||
|  |     write_data[1] = address; | ||||||
|  |     write_data[2] = data; | ||||||
|  |  | ||||||
|  |     checksum = ((uint16_t) write_data[0] + (uint16_t) write_data[1] + (uint16_t) write_data[2]) & 0xFF; | ||||||
|  |     write_data[3] = checksum; | ||||||
|  |  | ||||||
|  |     ESP_LOGV(TAG, "Write 4 bytes [%02X,%02X,%02X,%02X]", write_data[0], write_data[1], write_data[2], write_data[3]); | ||||||
|  |  | ||||||
|  |     this->enable_rx_pin_->digital_write(true); | ||||||
|  |     this->write_array(write_data, 4); | ||||||
|  |     this->flush(); | ||||||
|  |     this->enable_rx_pin_->digital_write(false); | ||||||
|  |  | ||||||
|  |     this->current_transmission_.request_transmission_time = millis(); | ||||||
|  |     this->current_transmission_.memory_location = location; | ||||||
|  |     this->current_transmission_.memory_address = address; | ||||||
|  |     this->current_transmission_.reply_pending = true; | ||||||
|  |     this->current_transmission_.initiating_listener = nullptr; | ||||||
|  |   } else { | ||||||
|  |     ESP_LOGE(TAG, "Reply is pending, skipping write"); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace micronova | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										164
									
								
								esphome/components/micronova/micronova.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								esphome/components/micronova/micronova.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,164 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "esphome/core/component.h" | ||||||
|  | #include "esphome/components/uart/uart.h" | ||||||
|  | #include "esphome/core/log.h" | ||||||
|  | #include "esphome/core/defines.h" | ||||||
|  | #include "esphome/core/helpers.h" | ||||||
|  |  | ||||||
|  | #include <vector> | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace micronova { | ||||||
|  |  | ||||||
|  | static const char *const TAG = "micronova"; | ||||||
|  | static const int STOVE_REPLY_DELAY = 60; | ||||||
|  |  | ||||||
|  | static const std::string STOVE_STATES[11] = {"Off", | ||||||
|  |                                              "Start", | ||||||
|  |                                              "Pellets loading", | ||||||
|  |                                              "Ignition", | ||||||
|  |                                              "Working", | ||||||
|  |                                              "Brazier Cleaning", | ||||||
|  |                                              "Final Cleaning", | ||||||
|  |                                              "Standby", | ||||||
|  |                                              "No pellets alarm", | ||||||
|  |                                              "No ignition alarm", | ||||||
|  |                                              "Undefined alarm"}; | ||||||
|  |  | ||||||
|  | enum class MicroNovaFunctions { | ||||||
|  |   STOVE_FUNCTION_VOID = 0, | ||||||
|  |   STOVE_FUNCTION_SWITCH = 1, | ||||||
|  |   STOVE_FUNCTION_ROOM_TEMPERATURE = 2, | ||||||
|  |   STOVE_FUNCTION_THERMOSTAT_TEMPERATURE = 3, | ||||||
|  |   STOVE_FUNCTION_FUMES_TEMPERATURE = 4, | ||||||
|  |   STOVE_FUNCTION_STOVE_POWER = 5, | ||||||
|  |   STOVE_FUNCTION_FAN_SPEED = 6, | ||||||
|  |   STOVE_FUNCTION_STOVE_STATE = 7, | ||||||
|  |   STOVE_FUNCTION_MEMORY_ADDRESS_SENSOR = 8, | ||||||
|  |   STOVE_FUNCTION_WATER_TEMPERATURE = 9, | ||||||
|  |   STOVE_FUNCTION_WATER_PRESSURE = 10, | ||||||
|  |   STOVE_FUNCTION_POWER_LEVEL = 11, | ||||||
|  |   STOVE_FUNCTION_CUSTOM = 12 | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class MicroNova; | ||||||
|  |  | ||||||
|  | ////////////////////////////////////////////////////////////////////// | ||||||
|  | // Interface classes. | ||||||
|  | class MicroNovaBaseListener { | ||||||
|  |  public: | ||||||
|  |   MicroNovaBaseListener() {} | ||||||
|  |   MicroNovaBaseListener(MicroNova *m) { this->micronova_ = m; } | ||||||
|  |   virtual void dump_config(); | ||||||
|  |  | ||||||
|  |   void set_micronova_object(MicroNova *m) { this->micronova_ = m; } | ||||||
|  |  | ||||||
|  |   void set_function(MicroNovaFunctions f) { this->function_ = f; } | ||||||
|  |   MicroNovaFunctions get_function() { return this->function_; } | ||||||
|  |  | ||||||
|  |   void set_memory_location(uint8_t l) { this->memory_location_ = l; } | ||||||
|  |   uint8_t get_memory_location() { return this->memory_location_; } | ||||||
|  |  | ||||||
|  |   void set_memory_address(uint8_t a) { this->memory_address_ = a; } | ||||||
|  |   uint8_t get_memory_address() { return this->memory_address_; } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   MicroNova *micronova_{nullptr}; | ||||||
|  |   MicroNovaFunctions function_ = MicroNovaFunctions::STOVE_FUNCTION_VOID; | ||||||
|  |   uint8_t memory_location_ = 0; | ||||||
|  |   uint8_t memory_address_ = 0; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class MicroNovaSensorListener : public MicroNovaBaseListener { | ||||||
|  |  public: | ||||||
|  |   MicroNovaSensorListener() {} | ||||||
|  |   MicroNovaSensorListener(MicroNova *m) : MicroNovaBaseListener(m) {} | ||||||
|  |   virtual void request_value_from_stove() = 0; | ||||||
|  |   virtual void process_value_from_stove(int value_from_stove) = 0; | ||||||
|  |  | ||||||
|  |   void set_needs_update(bool u) { this->needs_update_ = u; } | ||||||
|  |   bool get_needs_update() { return this->needs_update_; } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   bool needs_update_ = false; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class MicroNovaNumberListener : public MicroNovaBaseListener { | ||||||
|  |  public: | ||||||
|  |   MicroNovaNumberListener(MicroNova *m) : MicroNovaBaseListener(m) {} | ||||||
|  |   virtual void request_value_from_stove() = 0; | ||||||
|  |   virtual void process_value_from_stove(int value_from_stove) = 0; | ||||||
|  |  | ||||||
|  |   void set_needs_update(bool u) { this->needs_update_ = u; } | ||||||
|  |   bool get_needs_update() { return this->needs_update_; } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   bool needs_update_ = false; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class MicroNovaSwitchListener : public MicroNovaBaseListener { | ||||||
|  |  public: | ||||||
|  |   MicroNovaSwitchListener(MicroNova *m) : MicroNovaBaseListener(m) {} | ||||||
|  |   virtual void set_stove_state(bool v) = 0; | ||||||
|  |   virtual bool get_stove_state() = 0; | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   uint8_t memory_data_on_ = 0; | ||||||
|  |   uint8_t memory_data_off_ = 0; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class MicroNovaButtonListener : public MicroNovaBaseListener { | ||||||
|  |  public: | ||||||
|  |   MicroNovaButtonListener(MicroNova *m) : MicroNovaBaseListener(m) {} | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   uint8_t memory_data_ = 0; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | ///////////////////////////////////////////////////////////////////// | ||||||
|  | // Main component class | ||||||
|  | class MicroNova : public PollingComponent, public uart::UARTDevice { | ||||||
|  |  public: | ||||||
|  |   MicroNova() {} | ||||||
|  |  | ||||||
|  |   void setup() override; | ||||||
|  |   void loop() override; | ||||||
|  |   void update() override; | ||||||
|  |   void dump_config() override; | ||||||
|  |   void register_micronova_listener(MicroNovaSensorListener *l) { this->micronova_listeners_.push_back(l); } | ||||||
|  |  | ||||||
|  |   void request_address(uint8_t location, uint8_t address, MicroNovaSensorListener *listener); | ||||||
|  |   void write_address(uint8_t location, uint8_t address, uint8_t data); | ||||||
|  |   int read_stove_reply(); | ||||||
|  |  | ||||||
|  |   void set_enable_rx_pin(GPIOPin *enable_rx_pin) { this->enable_rx_pin_ = enable_rx_pin; } | ||||||
|  |  | ||||||
|  |   void set_current_stove_state(uint8_t s) { this->current_stove_state_ = s; } | ||||||
|  |   uint8_t get_current_stove_state() { return this->current_stove_state_; } | ||||||
|  |  | ||||||
|  |   void set_stove(MicroNovaSwitchListener *s) { this->stove_switch_ = s; } | ||||||
|  |   MicroNovaSwitchListener *get_stove_switch() { return this->stove_switch_; } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   uint8_t current_stove_state_ = 0; | ||||||
|  |  | ||||||
|  |   GPIOPin *enable_rx_pin_{nullptr}; | ||||||
|  |  | ||||||
|  |   struct MicroNovaSerialTransmission { | ||||||
|  |     uint32_t request_transmission_time; | ||||||
|  |     uint8_t memory_location; | ||||||
|  |     uint8_t memory_address; | ||||||
|  |     bool reply_pending; | ||||||
|  |     MicroNovaSensorListener *initiating_listener; | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   Mutex reply_pending_mutex_; | ||||||
|  |   MicroNovaSerialTransmission current_transmission_; | ||||||
|  |  | ||||||
|  |   std::vector<MicroNovaSensorListener *> micronova_listeners_{}; | ||||||
|  |   MicroNovaSwitchListener *stove_switch_{nullptr}; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace micronova | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										110
									
								
								esphome/components/micronova/number/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								esphome/components/micronova/number/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,110 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome.components import number | ||||||
|  | from esphome.const import ( | ||||||
|  |     DEVICE_CLASS_TEMPERATURE, | ||||||
|  |     UNIT_CELSIUS, | ||||||
|  |     CONF_STEP, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | from .. import ( | ||||||
|  |     MicroNova, | ||||||
|  |     MicroNovaFunctions, | ||||||
|  |     CONF_MICRONOVA_ID, | ||||||
|  |     CONF_MEMORY_LOCATION, | ||||||
|  |     CONF_MEMORY_ADDRESS, | ||||||
|  |     MICRONOVA_LISTENER_SCHEMA, | ||||||
|  |     micronova_ns, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | ICON_FLASH = "mdi:flash" | ||||||
|  |  | ||||||
|  | CONF_THERMOSTAT_TEMPERATURE = "thermostat_temperature" | ||||||
|  | CONF_POWER_LEVEL = "power_level" | ||||||
|  | CONF_MEMORY_WRITE_LOCATION = "memory_write_location" | ||||||
|  |  | ||||||
|  | MicroNovaNumber = micronova_ns.class_("MicroNovaNumber", number.Number, cg.Component) | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = cv.Schema( | ||||||
|  |     { | ||||||
|  |         cv.GenerateID(CONF_MICRONOVA_ID): cv.use_id(MicroNova), | ||||||
|  |         cv.Optional(CONF_THERMOSTAT_TEMPERATURE): number.number_schema( | ||||||
|  |             MicroNovaNumber, | ||||||
|  |             unit_of_measurement=UNIT_CELSIUS, | ||||||
|  |             device_class=DEVICE_CLASS_TEMPERATURE, | ||||||
|  |         ) | ||||||
|  |         .extend( | ||||||
|  |             MICRONOVA_LISTENER_SCHEMA( | ||||||
|  |                 default_memory_location=0x20, default_memory_address=0x7D | ||||||
|  |             ) | ||||||
|  |         ) | ||||||
|  |         .extend( | ||||||
|  |             { | ||||||
|  |                 cv.Optional( | ||||||
|  |                     CONF_MEMORY_WRITE_LOCATION, default=0xA0 | ||||||
|  |                 ): cv.hex_int_range(), | ||||||
|  |                 cv.Optional(CONF_STEP, default=1.0): cv.float_range(min=0.1, max=10.0), | ||||||
|  |             } | ||||||
|  |         ), | ||||||
|  |         cv.Optional(CONF_POWER_LEVEL): number.number_schema( | ||||||
|  |             MicroNovaNumber, | ||||||
|  |             icon=ICON_FLASH, | ||||||
|  |         ) | ||||||
|  |         .extend( | ||||||
|  |             MICRONOVA_LISTENER_SCHEMA( | ||||||
|  |                 default_memory_location=0x20, default_memory_address=0x7F | ||||||
|  |             ) | ||||||
|  |         ) | ||||||
|  |         .extend( | ||||||
|  |             {cv.Optional(CONF_MEMORY_WRITE_LOCATION, default=0xA0): cv.hex_int_range()} | ||||||
|  |         ), | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def to_code(config): | ||||||
|  |     mv = await cg.get_variable(config[CONF_MICRONOVA_ID]) | ||||||
|  |  | ||||||
|  |     if thermostat_temperature_config := config.get(CONF_THERMOSTAT_TEMPERATURE): | ||||||
|  |         numb = await number.new_number( | ||||||
|  |             thermostat_temperature_config, | ||||||
|  |             min_value=0, | ||||||
|  |             max_value=40, | ||||||
|  |             step=thermostat_temperature_config.get(CONF_STEP), | ||||||
|  |         ) | ||||||
|  |         cg.add(numb.set_micronova_object(mv)) | ||||||
|  |         cg.add(mv.register_micronova_listener(numb)) | ||||||
|  |         cg.add( | ||||||
|  |             numb.set_memory_location( | ||||||
|  |                 thermostat_temperature_config[CONF_MEMORY_LOCATION] | ||||||
|  |             ) | ||||||
|  |         ) | ||||||
|  |         cg.add( | ||||||
|  |             numb.set_memory_address(thermostat_temperature_config[CONF_MEMORY_ADDRESS]) | ||||||
|  |         ) | ||||||
|  |         cg.add( | ||||||
|  |             numb.set_memory_write_location( | ||||||
|  |                 thermostat_temperature_config.get(CONF_MEMORY_WRITE_LOCATION) | ||||||
|  |             ) | ||||||
|  |         ) | ||||||
|  |         cg.add( | ||||||
|  |             numb.set_function(MicroNovaFunctions.STOVE_FUNCTION_THERMOSTAT_TEMPERATURE) | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |     if power_level_config := config.get(CONF_POWER_LEVEL): | ||||||
|  |         numb = await number.new_number( | ||||||
|  |             power_level_config, | ||||||
|  |             min_value=1, | ||||||
|  |             max_value=5, | ||||||
|  |             step=1, | ||||||
|  |         ) | ||||||
|  |         cg.add(numb.set_micronova_object(mv)) | ||||||
|  |         cg.add(mv.register_micronova_listener(numb)) | ||||||
|  |         cg.add(numb.set_memory_location(power_level_config[CONF_MEMORY_LOCATION])) | ||||||
|  |         cg.add(numb.set_memory_address(power_level_config[CONF_MEMORY_ADDRESS])) | ||||||
|  |         cg.add( | ||||||
|  |             numb.set_memory_write_location( | ||||||
|  |                 power_level_config.get(CONF_MEMORY_WRITE_LOCATION) | ||||||
|  |             ) | ||||||
|  |         ) | ||||||
|  |         cg.add(numb.set_function(MicroNovaFunctions.STOVE_FUNCTION_POWER_LEVEL)) | ||||||
							
								
								
									
										45
									
								
								esphome/components/micronova/number/micronova_number.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								esphome/components/micronova/number/micronova_number.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | |||||||
|  | #include "micronova_number.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace micronova { | ||||||
|  |  | ||||||
|  | void MicroNovaNumber::process_value_from_stove(int value_from_stove) { | ||||||
|  |   float new_sensor_value = 0; | ||||||
|  |  | ||||||
|  |   if (value_from_stove == -1) { | ||||||
|  |     this->publish_state(NAN); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   switch (this->get_function()) { | ||||||
|  |     case MicroNovaFunctions::STOVE_FUNCTION_THERMOSTAT_TEMPERATURE: | ||||||
|  |       new_sensor_value = ((float) value_from_stove) * this->traits.get_step(); | ||||||
|  |       break; | ||||||
|  |     case MicroNovaFunctions::STOVE_FUNCTION_POWER_LEVEL: | ||||||
|  |       new_sensor_value = (float) value_from_stove; | ||||||
|  |       break; | ||||||
|  |     default: | ||||||
|  |       break; | ||||||
|  |   } | ||||||
|  |   this->publish_state(new_sensor_value); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void MicroNovaNumber::control(float value) { | ||||||
|  |   uint8_t new_number = 0; | ||||||
|  |  | ||||||
|  |   switch (this->get_function()) { | ||||||
|  |     case MicroNovaFunctions::STOVE_FUNCTION_THERMOSTAT_TEMPERATURE: | ||||||
|  |       new_number = (uint8_t) (value / this->traits.get_step()); | ||||||
|  |       break; | ||||||
|  |     case MicroNovaFunctions::STOVE_FUNCTION_POWER_LEVEL: | ||||||
|  |       new_number = (uint8_t) value; | ||||||
|  |       break; | ||||||
|  |     default: | ||||||
|  |       break; | ||||||
|  |   } | ||||||
|  |   this->micronova_->write_address(this->memory_write_location_, this->memory_address_, new_number); | ||||||
|  |   this->micronova_->update(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace micronova | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										28
									
								
								esphome/components/micronova/number/micronova_number.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								esphome/components/micronova/number/micronova_number.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "esphome/components/micronova/micronova.h" | ||||||
|  | #include "esphome/components/number/number.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace micronova { | ||||||
|  |  | ||||||
|  | class MicroNovaNumber : public number::Number, public MicroNovaSensorListener { | ||||||
|  |  public: | ||||||
|  |   MicroNovaNumber() {} | ||||||
|  |   MicroNovaNumber(MicroNova *m) : MicroNovaSensorListener(m) {} | ||||||
|  |   void dump_config() override { LOG_NUMBER("", "Micronova number", this); } | ||||||
|  |   void control(float value) override; | ||||||
|  |   void request_value_from_stove() override { | ||||||
|  |     this->micronova_->request_address(this->memory_location_, this->memory_address_, this); | ||||||
|  |   } | ||||||
|  |   void process_value_from_stove(int value_from_stove) override; | ||||||
|  |  | ||||||
|  |   void set_memory_write_location(uint8_t l) { this->memory_write_location_ = l; } | ||||||
|  |   uint8_t get_memory_write_location() { return this->memory_write_location_; } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   uint8_t memory_write_location_ = 0; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace micronova | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										172
									
								
								esphome/components/micronova/sensor/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								esphome/components/micronova/sensor/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,172 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome.components import sensor | ||||||
|  | from esphome.const import ( | ||||||
|  |     DEVICE_CLASS_TEMPERATURE, | ||||||
|  |     DEVICE_CLASS_PRESSURE, | ||||||
|  |     STATE_CLASS_MEASUREMENT, | ||||||
|  |     UNIT_CELSIUS, | ||||||
|  |     UNIT_REVOLUTIONS_PER_MINUTE, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | from .. import ( | ||||||
|  |     MicroNova, | ||||||
|  |     MicroNovaFunctions, | ||||||
|  |     CONF_MICRONOVA_ID, | ||||||
|  |     CONF_MEMORY_LOCATION, | ||||||
|  |     CONF_MEMORY_ADDRESS, | ||||||
|  |     MICRONOVA_LISTENER_SCHEMA, | ||||||
|  |     micronova_ns, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | UNIT_BAR = "bar" | ||||||
|  |  | ||||||
|  | MicroNovaSensor = micronova_ns.class_("MicroNovaSensor", sensor.Sensor, cg.Component) | ||||||
|  |  | ||||||
|  | CONF_ROOM_TEMPERATURE = "room_temperature" | ||||||
|  | CONF_FUMES_TEMPERATURE = "fumes_temperature" | ||||||
|  | CONF_STOVE_POWER = "stove_power" | ||||||
|  | CONF_FAN_SPEED = "fan_speed" | ||||||
|  | CONF_WATER_TEMPERATURE = "water_temperature" | ||||||
|  | CONF_WATER_PRESSURE = "water_pressure" | ||||||
|  | CONF_MEMORY_ADDRESS_SENSOR = "memory_address_sensor" | ||||||
|  | CONF_FAN_RPM_OFFSET = "fan_rpm_offset" | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = cv.Schema( | ||||||
|  |     { | ||||||
|  |         cv.GenerateID(CONF_MICRONOVA_ID): cv.use_id(MicroNova), | ||||||
|  |         cv.Optional(CONF_ROOM_TEMPERATURE): sensor.sensor_schema( | ||||||
|  |             MicroNovaSensor, | ||||||
|  |             unit_of_measurement=UNIT_CELSIUS, | ||||||
|  |             device_class=DEVICE_CLASS_TEMPERATURE, | ||||||
|  |             state_class=STATE_CLASS_MEASUREMENT, | ||||||
|  |             accuracy_decimals=1, | ||||||
|  |         ).extend( | ||||||
|  |             MICRONOVA_LISTENER_SCHEMA( | ||||||
|  |                 default_memory_location=0x00, default_memory_address=0x01 | ||||||
|  |             ) | ||||||
|  |         ), | ||||||
|  |         cv.Optional(CONF_FUMES_TEMPERATURE): sensor.sensor_schema( | ||||||
|  |             MicroNovaSensor, | ||||||
|  |             unit_of_measurement=UNIT_CELSIUS, | ||||||
|  |             device_class=DEVICE_CLASS_TEMPERATURE, | ||||||
|  |             state_class=STATE_CLASS_MEASUREMENT, | ||||||
|  |             accuracy_decimals=1, | ||||||
|  |         ).extend( | ||||||
|  |             MICRONOVA_LISTENER_SCHEMA( | ||||||
|  |                 default_memory_location=0x00, default_memory_address=0x5A | ||||||
|  |             ) | ||||||
|  |         ), | ||||||
|  |         cv.Optional(CONF_STOVE_POWER): sensor.sensor_schema( | ||||||
|  |             MicroNovaSensor, | ||||||
|  |             state_class=STATE_CLASS_MEASUREMENT, | ||||||
|  |             accuracy_decimals=0, | ||||||
|  |         ).extend( | ||||||
|  |             MICRONOVA_LISTENER_SCHEMA( | ||||||
|  |                 default_memory_location=0x00, default_memory_address=0x34 | ||||||
|  |             ) | ||||||
|  |         ), | ||||||
|  |         cv.Optional(CONF_FAN_SPEED): sensor.sensor_schema( | ||||||
|  |             MicroNovaSensor, | ||||||
|  |             state_class=STATE_CLASS_MEASUREMENT, | ||||||
|  |             unit_of_measurement=UNIT_REVOLUTIONS_PER_MINUTE, | ||||||
|  |         ) | ||||||
|  |         .extend( | ||||||
|  |             MICRONOVA_LISTENER_SCHEMA( | ||||||
|  |                 default_memory_location=0x00, default_memory_address=0x37 | ||||||
|  |             ) | ||||||
|  |         ) | ||||||
|  |         .extend( | ||||||
|  |             {cv.Optional(CONF_FAN_RPM_OFFSET, default=0): cv.int_range(min=0, max=255)} | ||||||
|  |         ), | ||||||
|  |         cv.Optional(CONF_WATER_TEMPERATURE): sensor.sensor_schema( | ||||||
|  |             MicroNovaSensor, | ||||||
|  |             unit_of_measurement=UNIT_CELSIUS, | ||||||
|  |             device_class=DEVICE_CLASS_TEMPERATURE, | ||||||
|  |             state_class=STATE_CLASS_MEASUREMENT, | ||||||
|  |             accuracy_decimals=1, | ||||||
|  |         ).extend( | ||||||
|  |             MICRONOVA_LISTENER_SCHEMA( | ||||||
|  |                 default_memory_location=0x00, default_memory_address=0x3B | ||||||
|  |             ) | ||||||
|  |         ), | ||||||
|  |         cv.Optional(CONF_WATER_PRESSURE): sensor.sensor_schema( | ||||||
|  |             MicroNovaSensor, | ||||||
|  |             unit_of_measurement=UNIT_BAR, | ||||||
|  |             device_class=DEVICE_CLASS_PRESSURE, | ||||||
|  |             state_class=STATE_CLASS_MEASUREMENT, | ||||||
|  |             accuracy_decimals=1, | ||||||
|  |         ).extend( | ||||||
|  |             MICRONOVA_LISTENER_SCHEMA( | ||||||
|  |                 default_memory_location=0x00, default_memory_address=0x3C | ||||||
|  |             ) | ||||||
|  |         ), | ||||||
|  |         cv.Optional(CONF_MEMORY_ADDRESS_SENSOR): sensor.sensor_schema( | ||||||
|  |             MicroNovaSensor, | ||||||
|  |         ).extend( | ||||||
|  |             MICRONOVA_LISTENER_SCHEMA( | ||||||
|  |                 default_memory_location=0x00, default_memory_address=0x00 | ||||||
|  |             ) | ||||||
|  |         ), | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def to_code(config): | ||||||
|  |     mv = await cg.get_variable(config[CONF_MICRONOVA_ID]) | ||||||
|  |  | ||||||
|  |     if room_temperature_config := config.get(CONF_ROOM_TEMPERATURE): | ||||||
|  |         sens = await sensor.new_sensor(room_temperature_config, mv) | ||||||
|  |         cg.add(mv.register_micronova_listener(sens)) | ||||||
|  |         cg.add(sens.set_memory_location(room_temperature_config[CONF_MEMORY_LOCATION])) | ||||||
|  |         cg.add(sens.set_memory_address(room_temperature_config[CONF_MEMORY_ADDRESS])) | ||||||
|  |         cg.add(sens.set_function(MicroNovaFunctions.STOVE_FUNCTION_ROOM_TEMPERATURE)) | ||||||
|  |  | ||||||
|  |     if fumes_temperature_config := config.get(CONF_FUMES_TEMPERATURE): | ||||||
|  |         sens = await sensor.new_sensor(fumes_temperature_config, mv) | ||||||
|  |         cg.add(mv.register_micronova_listener(sens)) | ||||||
|  |         cg.add(sens.set_memory_location(fumes_temperature_config[CONF_MEMORY_LOCATION])) | ||||||
|  |         cg.add(sens.set_memory_address(fumes_temperature_config[CONF_MEMORY_ADDRESS])) | ||||||
|  |         cg.add(sens.set_function(MicroNovaFunctions.STOVE_FUNCTION_FUMES_TEMPERATURE)) | ||||||
|  |  | ||||||
|  |     if stove_power_config := config.get(CONF_STOVE_POWER): | ||||||
|  |         sens = await sensor.new_sensor(stove_power_config, mv) | ||||||
|  |         cg.add(mv.register_micronova_listener(sens)) | ||||||
|  |         cg.add(sens.set_memory_location(stove_power_config[CONF_MEMORY_LOCATION])) | ||||||
|  |         cg.add(sens.set_memory_address(stove_power_config[CONF_MEMORY_ADDRESS])) | ||||||
|  |         cg.add(sens.set_function(MicroNovaFunctions.STOVE_FUNCTION_STOVE_POWER)) | ||||||
|  |  | ||||||
|  |     if fan_speed_config := config.get(CONF_FAN_SPEED): | ||||||
|  |         sens = await sensor.new_sensor(fan_speed_config, mv) | ||||||
|  |         cg.add(mv.register_micronova_listener(sens)) | ||||||
|  |         cg.add(sens.set_memory_location(fan_speed_config[CONF_MEMORY_LOCATION])) | ||||||
|  |         cg.add(sens.set_memory_address(fan_speed_config[CONF_MEMORY_ADDRESS])) | ||||||
|  |         cg.add(sens.set_function(MicroNovaFunctions.STOVE_FUNCTION_FAN_SPEED)) | ||||||
|  |         cg.add(sens.set_fan_speed_offset(fan_speed_config[CONF_FAN_RPM_OFFSET])) | ||||||
|  |  | ||||||
|  |     if memory_address_sensor_config := config.get(CONF_MEMORY_ADDRESS_SENSOR): | ||||||
|  |         sens = await sensor.new_sensor(memory_address_sensor_config, mv) | ||||||
|  |         cg.add(mv.register_micronova_listener(sens)) | ||||||
|  |         cg.add( | ||||||
|  |             sens.set_memory_location(memory_address_sensor_config[CONF_MEMORY_LOCATION]) | ||||||
|  |         ) | ||||||
|  |         cg.add( | ||||||
|  |             sens.set_memory_address(memory_address_sensor_config[CONF_MEMORY_ADDRESS]) | ||||||
|  |         ) | ||||||
|  |         cg.add( | ||||||
|  |             sens.set_function(MicroNovaFunctions.STOVE_FUNCTION_MEMORY_ADDRESS_SENSOR) | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |     if water_temperature_config := config.get(CONF_WATER_TEMPERATURE): | ||||||
|  |         sens = await sensor.new_sensor(water_temperature_config, mv) | ||||||
|  |         cg.add(mv.register_micronova_listener(sens)) | ||||||
|  |         cg.add(sens.set_memory_location(water_temperature_config[CONF_MEMORY_LOCATION])) | ||||||
|  |         cg.add(sens.set_memory_address(water_temperature_config[CONF_MEMORY_ADDRESS])) | ||||||
|  |         cg.add(sens.set_function(MicroNovaFunctions.STOVE_FUNCTION_WATER_TEMPERATURE)) | ||||||
|  |  | ||||||
|  |     if water_pressure_config := config.get(CONF_WATER_PRESSURE): | ||||||
|  |         sens = await sensor.new_sensor(water_pressure_config, mv) | ||||||
|  |         cg.add(mv.register_micronova_listener(sens)) | ||||||
|  |         cg.add(sens.set_memory_location(water_pressure_config[CONF_MEMORY_LOCATION])) | ||||||
|  |         cg.add(sens.set_memory_address(water_pressure_config[CONF_MEMORY_ADDRESS])) | ||||||
|  |         cg.add(sens.set_function(MicroNovaFunctions.STOVE_FUNCTION_WATER_PRESSURE)) | ||||||
							
								
								
									
										35
									
								
								esphome/components/micronova/sensor/micronova_sensor.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								esphome/components/micronova/sensor/micronova_sensor.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,35 @@ | |||||||
|  | #include "micronova_sensor.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace micronova { | ||||||
|  |  | ||||||
|  | void MicroNovaSensor::process_value_from_stove(int value_from_stove) { | ||||||
|  |   if (value_from_stove == -1) { | ||||||
|  |     this->publish_state(NAN); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   float new_sensor_value = (float) value_from_stove; | ||||||
|  |   switch (this->get_function()) { | ||||||
|  |     case MicroNovaFunctions::STOVE_FUNCTION_ROOM_TEMPERATURE: | ||||||
|  |       new_sensor_value = new_sensor_value / 2; | ||||||
|  |       break; | ||||||
|  |     case MicroNovaFunctions::STOVE_FUNCTION_THERMOSTAT_TEMPERATURE: | ||||||
|  |       break; | ||||||
|  |     case MicroNovaFunctions::STOVE_FUNCTION_FAN_SPEED: | ||||||
|  |       new_sensor_value = new_sensor_value == 0 ? 0 : (new_sensor_value * 10) + this->fan_speed_offset_; | ||||||
|  |       break; | ||||||
|  |     case MicroNovaFunctions::STOVE_FUNCTION_WATER_TEMPERATURE: | ||||||
|  |       new_sensor_value = new_sensor_value / 2; | ||||||
|  |       break; | ||||||
|  |     case MicroNovaFunctions::STOVE_FUNCTION_WATER_PRESSURE: | ||||||
|  |       new_sensor_value = new_sensor_value / 10; | ||||||
|  |       break; | ||||||
|  |     default: | ||||||
|  |       break; | ||||||
|  |   } | ||||||
|  |   this->publish_state(new_sensor_value); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace micronova | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										27
									
								
								esphome/components/micronova/sensor/micronova_sensor.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								esphome/components/micronova/sensor/micronova_sensor.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "esphome/components/micronova/micronova.h" | ||||||
|  | #include "esphome/components/sensor/sensor.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace micronova { | ||||||
|  |  | ||||||
|  | class MicroNovaSensor : public sensor::Sensor, public MicroNovaSensorListener { | ||||||
|  |  public: | ||||||
|  |   MicroNovaSensor(MicroNova *m) : MicroNovaSensorListener(m) {} | ||||||
|  |   void dump_config() override { LOG_SENSOR("", "Micronova sensor", this); } | ||||||
|  |  | ||||||
|  |   void request_value_from_stove() override { | ||||||
|  |     this->micronova_->request_address(this->memory_location_, this->memory_address_, this); | ||||||
|  |   } | ||||||
|  |   void process_value_from_stove(int value_from_stove) override; | ||||||
|  |  | ||||||
|  |   void set_fan_speed_offset(uint8_t f) { this->fan_speed_offset_ = f; } | ||||||
|  |   uint8_t get_set_fan_speed_offset() { return this->fan_speed_offset_; } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   int fan_speed_offset_ = 0; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace micronova | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										56
									
								
								esphome/components/micronova/switch/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								esphome/components/micronova/switch/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome.components import switch | ||||||
|  | from esphome.const import ( | ||||||
|  |     ICON_POWER, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | from .. import ( | ||||||
|  |     MicroNova, | ||||||
|  |     MicroNovaFunctions, | ||||||
|  |     CONF_MICRONOVA_ID, | ||||||
|  |     CONF_MEMORY_LOCATION, | ||||||
|  |     CONF_MEMORY_ADDRESS, | ||||||
|  |     MICRONOVA_LISTENER_SCHEMA, | ||||||
|  |     micronova_ns, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | CONF_STOVE = "stove" | ||||||
|  | CONF_MEMORY_DATA_ON = "memory_data_on" | ||||||
|  | CONF_MEMORY_DATA_OFF = "memory_data_off" | ||||||
|  |  | ||||||
|  | MicroNovaSwitch = micronova_ns.class_("MicroNovaSwitch", switch.Switch, cg.Component) | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = cv.Schema( | ||||||
|  |     { | ||||||
|  |         cv.GenerateID(CONF_MICRONOVA_ID): cv.use_id(MicroNova), | ||||||
|  |         cv.Optional(CONF_STOVE): switch.switch_schema( | ||||||
|  |             MicroNovaSwitch, | ||||||
|  |             icon=ICON_POWER, | ||||||
|  |         ) | ||||||
|  |         .extend( | ||||||
|  |             MICRONOVA_LISTENER_SCHEMA( | ||||||
|  |                 default_memory_location=0x80, default_memory_address=0x21 | ||||||
|  |             ) | ||||||
|  |         ) | ||||||
|  |         .extend( | ||||||
|  |             { | ||||||
|  |                 cv.Optional(CONF_MEMORY_DATA_OFF, default=0x06): cv.hex_int_range(), | ||||||
|  |                 cv.Optional(CONF_MEMORY_DATA_ON, default=0x01): cv.hex_int_range(), | ||||||
|  |             } | ||||||
|  |         ), | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def to_code(config): | ||||||
|  |     mv = await cg.get_variable(config[CONF_MICRONOVA_ID]) | ||||||
|  |  | ||||||
|  |     if stove_config := config.get(CONF_STOVE): | ||||||
|  |         sw = await switch.new_switch(stove_config, mv) | ||||||
|  |         cg.add(mv.set_stove(sw)) | ||||||
|  |         cg.add(sw.set_memory_location(stove_config[CONF_MEMORY_LOCATION])) | ||||||
|  |         cg.add(sw.set_memory_address(stove_config[CONF_MEMORY_ADDRESS])) | ||||||
|  |         cg.add(sw.set_memory_data_on(stove_config[CONF_MEMORY_DATA_ON])) | ||||||
|  |         cg.add(sw.set_memory_data_off(stove_config[CONF_MEMORY_DATA_OFF])) | ||||||
|  |         cg.add(sw.set_function(MicroNovaFunctions.STOVE_FUNCTION_SWITCH)) | ||||||
							
								
								
									
										33
									
								
								esphome/components/micronova/switch/micronova_switch.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								esphome/components/micronova/switch/micronova_switch.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | |||||||
|  | #include "micronova_switch.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace micronova { | ||||||
|  |  | ||||||
|  | void MicroNovaSwitch::write_state(bool state) { | ||||||
|  |   switch (this->get_function()) { | ||||||
|  |     case MicroNovaFunctions::STOVE_FUNCTION_SWITCH: | ||||||
|  |       if (state) { | ||||||
|  |         // Only send power-on when current state is Off | ||||||
|  |         if (this->micronova_->get_current_stove_state() == 0) { | ||||||
|  |           this->micronova_->write_address(this->memory_location_, this->memory_address_, this->memory_data_on_); | ||||||
|  |           this->publish_state(true); | ||||||
|  |         } else | ||||||
|  |           ESP_LOGW(TAG, "Unable to turn stove on, invalid state: %d", micronova_->get_current_stove_state()); | ||||||
|  |       } else { | ||||||
|  |         // don't send power-off when status is Off or Final cleaning | ||||||
|  |         if (this->micronova_->get_current_stove_state() != 0 && micronova_->get_current_stove_state() != 6) { | ||||||
|  |           this->micronova_->write_address(this->memory_location_, this->memory_address_, this->memory_data_off_); | ||||||
|  |           this->publish_state(false); | ||||||
|  |         } else | ||||||
|  |           ESP_LOGW(TAG, "Unable to turn stove off, invalid state: %d", micronova_->get_current_stove_state()); | ||||||
|  |       } | ||||||
|  |       this->micronova_->update(); | ||||||
|  |       break; | ||||||
|  |  | ||||||
|  |     default: | ||||||
|  |       break; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace micronova | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										29
									
								
								esphome/components/micronova/switch/micronova_switch.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								esphome/components/micronova/switch/micronova_switch.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "esphome/components/micronova/micronova.h" | ||||||
|  | #include "esphome/core/component.h" | ||||||
|  | #include "esphome/components/switch/switch.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace micronova { | ||||||
|  |  | ||||||
|  | class MicroNovaSwitch : public Component, public switch_::Switch, public MicroNovaSwitchListener { | ||||||
|  |  public: | ||||||
|  |   MicroNovaSwitch(MicroNova *m) : MicroNovaSwitchListener(m) {} | ||||||
|  |   void dump_config() override { LOG_SWITCH("", "Micronova switch", this); } | ||||||
|  |  | ||||||
|  |   void set_stove_state(bool v) override { this->publish_state(v); } | ||||||
|  |   bool get_stove_state() override { return this->state; } | ||||||
|  |  | ||||||
|  |   void set_memory_data_on(uint8_t f) { this->memory_data_on_ = f; } | ||||||
|  |   uint8_t get_memory_data_on() { return this->memory_data_on_; } | ||||||
|  |  | ||||||
|  |   void set_memory_data_off(uint8_t f) { this->memory_data_off_ = f; } | ||||||
|  |   uint8_t get_memory_data_off() { return this->memory_data_off_; } | ||||||
|  |  | ||||||
|  |  protected: | ||||||
|  |   void write_state(bool state) override; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace micronova | ||||||
|  | }  // namespace esphome | ||||||
							
								
								
									
										43
									
								
								esphome/components/micronova/text_sensor/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								esphome/components/micronova/text_sensor/__init__.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | |||||||
|  | import esphome.codegen as cg | ||||||
|  | import esphome.config_validation as cv | ||||||
|  | from esphome.components import text_sensor | ||||||
|  |  | ||||||
|  | from .. import ( | ||||||
|  |     MicroNova, | ||||||
|  |     MicroNovaFunctions, | ||||||
|  |     CONF_MICRONOVA_ID, | ||||||
|  |     CONF_MEMORY_LOCATION, | ||||||
|  |     CONF_MEMORY_ADDRESS, | ||||||
|  |     MICRONOVA_LISTENER_SCHEMA, | ||||||
|  |     micronova_ns, | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | CONF_STOVE_STATE = "stove_state" | ||||||
|  |  | ||||||
|  | MicroNovaTextSensor = micronova_ns.class_( | ||||||
|  |     "MicroNovaTextSensor", text_sensor.TextSensor, cg.Component | ||||||
|  | ) | ||||||
|  |  | ||||||
|  | CONFIG_SCHEMA = cv.Schema( | ||||||
|  |     { | ||||||
|  |         cv.GenerateID(CONF_MICRONOVA_ID): cv.use_id(MicroNova), | ||||||
|  |         cv.Optional(CONF_STOVE_STATE): text_sensor.text_sensor_schema( | ||||||
|  |             MicroNovaTextSensor | ||||||
|  |         ).extend( | ||||||
|  |             MICRONOVA_LISTENER_SCHEMA( | ||||||
|  |                 default_memory_location=0x00, default_memory_address=0x21 | ||||||
|  |             ) | ||||||
|  |         ), | ||||||
|  |     } | ||||||
|  | ) | ||||||
|  |  | ||||||
|  |  | ||||||
|  | async def to_code(config): | ||||||
|  |     mv = await cg.get_variable(config[CONF_MICRONOVA_ID]) | ||||||
|  |  | ||||||
|  |     if stove_state_config := config.get(CONF_STOVE_STATE): | ||||||
|  |         sens = await text_sensor.new_text_sensor(stove_state_config, mv) | ||||||
|  |         cg.add(mv.register_micronova_listener(sens)) | ||||||
|  |         cg.add(sens.set_memory_location(stove_state_config[CONF_MEMORY_LOCATION])) | ||||||
|  |         cg.add(sens.set_memory_address(stove_state_config[CONF_MEMORY_ADDRESS])) | ||||||
|  |         cg.add(sens.set_function(MicroNovaFunctions.STOVE_FUNCTION_STOVE_STATE)) | ||||||
| @@ -0,0 +1,31 @@ | |||||||
|  | #include "micronova_text_sensor.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace micronova { | ||||||
|  |  | ||||||
|  | void MicroNovaTextSensor::process_value_from_stove(int value_from_stove) { | ||||||
|  |   if (value_from_stove == -1) { | ||||||
|  |     this->publish_state("unknown"); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   switch (this->get_function()) { | ||||||
|  |     case MicroNovaFunctions::STOVE_FUNCTION_STOVE_STATE: | ||||||
|  |       this->micronova_->set_current_stove_state(value_from_stove); | ||||||
|  |       this->publish_state(STOVE_STATES[value_from_stove]); | ||||||
|  |       // set the stove switch to on for any value but 0 | ||||||
|  |       if (value_from_stove != 0 && this->micronova_->get_stove_switch() != nullptr && | ||||||
|  |           !this->micronova_->get_stove_switch()->get_stove_state()) { | ||||||
|  |         this->micronova_->get_stove_switch()->set_stove_state(true); | ||||||
|  |       } else if (value_from_stove == 0 && this->micronova_->get_stove_switch() != nullptr && | ||||||
|  |                  this->micronova_->get_stove_switch()->get_stove_state()) { | ||||||
|  |         this->micronova_->get_stove_switch()->set_stove_state(false); | ||||||
|  |       } | ||||||
|  |       break; | ||||||
|  |     default: | ||||||
|  |       break; | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | }  // namespace micronova | ||||||
|  | }  // namespace esphome | ||||||
| @@ -0,0 +1,20 @@ | |||||||
|  | #pragma once | ||||||
|  |  | ||||||
|  | #include "esphome/components/micronova/micronova.h" | ||||||
|  | #include "esphome/components/text_sensor/text_sensor.h" | ||||||
|  |  | ||||||
|  | namespace esphome { | ||||||
|  | namespace micronova { | ||||||
|  |  | ||||||
|  | class MicroNovaTextSensor : public text_sensor::TextSensor, public MicroNovaSensorListener { | ||||||
|  |  public: | ||||||
|  |   MicroNovaTextSensor(MicroNova *m) : MicroNovaSensorListener(m) {} | ||||||
|  |   void dump_config() override { LOG_TEXT_SENSOR("", "Micronova text sensor", this); } | ||||||
|  |   void request_value_from_stove() override { | ||||||
|  |     this->micronova_->request_address(this->memory_location_, this->memory_address_, this); | ||||||
|  |   } | ||||||
|  |   void process_value_from_stove(int value_from_stove) override; | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | }  // namespace micronova | ||||||
|  | }  // namespace esphome | ||||||
| @@ -342,6 +342,10 @@ mcp23s17: | |||||||
|     cs_pin: GPIO12 |     cs_pin: GPIO12 | ||||||
|     deviceaddress: 1 |     deviceaddress: 1 | ||||||
|  |  | ||||||
|  | micronova: | ||||||
|  |   enable_rx_pin: 4 | ||||||
|  |   uart_id: uart_0 | ||||||
|  |  | ||||||
| dfrobot_sen0395: | dfrobot_sen0395: | ||||||
|   - id: mmwave |   - id: mmwave | ||||||
|     uart_id: dfrobot_mmwave_uart |     uart_id: dfrobot_mmwave_uart | ||||||
| @@ -1518,6 +1522,24 @@ sensor: | |||||||
|     field_strength_z: |     field_strength_z: | ||||||
|       name: "Magnet Z" |       name: "Magnet Z" | ||||||
|       id: magnet_z |       id: magnet_z | ||||||
|  |   - platform: micronova | ||||||
|  |     room_temperature: | ||||||
|  |       name: Room Temperature | ||||||
|  |     fumes_temperature: | ||||||
|  |       name: Fumes Temperature | ||||||
|  |     water_temperature: | ||||||
|  |       name: Water temperature | ||||||
|  |     water_pressure: | ||||||
|  |       name: Water pressure | ||||||
|  |     stove_power: | ||||||
|  |       name: Stove Power | ||||||
|  |     fan_speed: | ||||||
|  |       fan_rpm_offset: 240 | ||||||
|  |       name: Fan RPM | ||||||
|  |     memory_address_sensor: | ||||||
|  |       memory_location: 0x20 | ||||||
|  |       memory_address: 0x7d | ||||||
|  |       name: Adres sensor | ||||||
|  |  | ||||||
| esp32_touch: | esp32_touch: | ||||||
|   setup_mode: false |   setup_mode: false | ||||||
| @@ -2705,6 +2727,9 @@ switch: | |||||||
|       name: "control ld2410 engineering mode" |       name: "control ld2410 engineering mode" | ||||||
|     bluetooth: |     bluetooth: | ||||||
|       name: "control ld2410 bluetooth" |       name: "control ld2410 bluetooth" | ||||||
|  |   - platform: micronova | ||||||
|  |     stove: | ||||||
|  |       name: Stove on/off | ||||||
|  |  | ||||||
| fan: | fan: | ||||||
|   - platform: binary |   - platform: binary | ||||||
| @@ -3489,6 +3514,12 @@ number: | |||||||
|         name: g8 move threshold |         name: g8 move threshold | ||||||
|       still_threshold: |       still_threshold: | ||||||
|         name: g8 still threshold |         name: g8 still threshold | ||||||
|  |   - platform: micronova | ||||||
|  |     thermostat_temperature: | ||||||
|  |       name: Micronova Thermostaat | ||||||
|  |       step: 1 | ||||||
|  |     power_level: | ||||||
|  |       name: Micronova Power level | ||||||
|  |  | ||||||
| select: | select: | ||||||
|   - platform: template |   - platform: template | ||||||
| @@ -3619,6 +3650,12 @@ button: | |||||||
|     uart_id: uart_0 |     uart_id: uart_0 | ||||||
|     name: UART button |     name: UART button | ||||||
|     data: "Pressed\r\n" |     data: "Pressed\r\n" | ||||||
|  |   - platform: micronova | ||||||
|  |     custom_button: | ||||||
|  |       name: Custom Micronova Button | ||||||
|  |       memory_location: 0xA0 | ||||||
|  |       memory_address: 0x7D | ||||||
|  |       memory_data: 0x0F | ||||||
|  |  | ||||||
| ld2410: | ld2410: | ||||||
|   id: my_ld2410 |   id: my_ld2410 | ||||||
| @@ -3727,3 +3764,4 @@ alarm_control_panel: | |||||||
|       then: |       then: | ||||||
|         - lambda: !lambda |- |         - lambda: !lambda |- | ||||||
|             ESP_LOGD("TEST", "State change %s", alarm_control_panel_state_to_string(id(alarmcontrolpanel1)->get_state())); |             ESP_LOGD("TEST", "State change %s", alarm_control_panel_state_to_string(id(alarmcontrolpanel1)->get_state())); | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user