From 13994d9bd10653c07ec97badba14e742a3c6c54b Mon Sep 17 00:00:00 2001 From: Joris S <100357138+Jorre05@users.noreply.github.com> Date: Fri, 3 Nov 2023 07:54:47 +0100 Subject: [PATCH] Add Micronova component (#4760) Co-authored-by: Jesse Hills <3060199+jesserockz@users.noreply.github.com> Co-authored-by: Graham Brown --- CODEOWNERS | 1 + esphome/components/micronova/__init__.py | 69 +++++++ .../components/micronova/button/__init__.py | 44 +++++ .../micronova/button/micronova_button.cpp | 18 ++ .../micronova/button/micronova_button.h | 23 +++ esphome/components/micronova/micronova.cpp | 148 +++++++++++++++ esphome/components/micronova/micronova.h | 164 +++++++++++++++++ .../components/micronova/number/__init__.py | 110 +++++++++++ .../micronova/number/micronova_number.cpp | 45 +++++ .../micronova/number/micronova_number.h | 28 +++ .../components/micronova/sensor/__init__.py | 172 ++++++++++++++++++ .../micronova/sensor/micronova_sensor.cpp | 35 ++++ .../micronova/sensor/micronova_sensor.h | 27 +++ .../components/micronova/switch/__init__.py | 56 ++++++ .../micronova/switch/micronova_switch.cpp | 33 ++++ .../micronova/switch/micronova_switch.h | 29 +++ .../micronova/text_sensor/__init__.py | 43 +++++ .../text_sensor/micronova_text_sensor.cpp | 31 ++++ .../text_sensor/micronova_text_sensor.h | 20 ++ tests/test1.yaml | 38 ++++ 20 files changed, 1134 insertions(+) create mode 100644 esphome/components/micronova/__init__.py create mode 100644 esphome/components/micronova/button/__init__.py create mode 100644 esphome/components/micronova/button/micronova_button.cpp create mode 100644 esphome/components/micronova/button/micronova_button.h create mode 100644 esphome/components/micronova/micronova.cpp create mode 100644 esphome/components/micronova/micronova.h create mode 100644 esphome/components/micronova/number/__init__.py create mode 100644 esphome/components/micronova/number/micronova_number.cpp create mode 100644 esphome/components/micronova/number/micronova_number.h create mode 100644 esphome/components/micronova/sensor/__init__.py create mode 100644 esphome/components/micronova/sensor/micronova_sensor.cpp create mode 100644 esphome/components/micronova/sensor/micronova_sensor.h create mode 100644 esphome/components/micronova/switch/__init__.py create mode 100644 esphome/components/micronova/switch/micronova_switch.cpp create mode 100644 esphome/components/micronova/switch/micronova_switch.h create mode 100644 esphome/components/micronova/text_sensor/__init__.py create mode 100644 esphome/components/micronova/text_sensor/micronova_text_sensor.cpp create mode 100644 esphome/components/micronova/text_sensor/micronova_text_sensor.h diff --git a/CODEOWNERS b/CODEOWNERS index bf5f6a233e..b639088900 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -184,6 +184,7 @@ esphome/components/mcp9808/* @k7hpn esphome/components/md5/* @esphome/core esphome/components/mdns/* @esphome/core esphome/components/media_player/* @jesserockz +esphome/components/micronova/* @jorre05 esphome/components/microphone/* @jesserockz esphome/components/mics_4514/* @jesserockz esphome/components/midea/* @dudanov diff --git a/esphome/components/micronova/__init__.py b/esphome/components/micronova/__init__.py new file mode 100644 index 0000000000..bd253f8ebd --- /dev/null +++ b/esphome/components/micronova/__init__.py @@ -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)) diff --git a/esphome/components/micronova/button/__init__.py b/esphome/components/micronova/button/__init__.py new file mode 100644 index 0000000000..442f69c08b --- /dev/null +++ b/esphome/components/micronova/button/__init__.py @@ -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)) diff --git a/esphome/components/micronova/button/micronova_button.cpp b/esphome/components/micronova/button/micronova_button.cpp new file mode 100644 index 0000000000..c1903fd878 --- /dev/null +++ b/esphome/components/micronova/button/micronova_button.cpp @@ -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 diff --git a/esphome/components/micronova/button/micronova_button.h b/esphome/components/micronova/button/micronova_button.h new file mode 100644 index 0000000000..77649051d6 --- /dev/null +++ b/esphome/components/micronova/button/micronova_button.h @@ -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 diff --git a/esphome/components/micronova/micronova.cpp b/esphome/components/micronova/micronova.cpp new file mode 100644 index 0000000000..b96798ed12 --- /dev/null +++ b/esphome/components/micronova/micronova.cpp @@ -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 diff --git a/esphome/components/micronova/micronova.h b/esphome/components/micronova/micronova.h new file mode 100644 index 0000000000..aebef277e5 --- /dev/null +++ b/esphome/components/micronova/micronova.h @@ -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 + +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 micronova_listeners_{}; + MicroNovaSwitchListener *stove_switch_{nullptr}; +}; + +} // namespace micronova +} // namespace esphome diff --git a/esphome/components/micronova/number/__init__.py b/esphome/components/micronova/number/__init__.py new file mode 100644 index 0000000000..7124bf50d0 --- /dev/null +++ b/esphome/components/micronova/number/__init__.py @@ -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)) diff --git a/esphome/components/micronova/number/micronova_number.cpp b/esphome/components/micronova/number/micronova_number.cpp new file mode 100644 index 0000000000..244eb7ee9f --- /dev/null +++ b/esphome/components/micronova/number/micronova_number.cpp @@ -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 diff --git a/esphome/components/micronova/number/micronova_number.h b/esphome/components/micronova/number/micronova_number.h new file mode 100644 index 0000000000..49c6358255 --- /dev/null +++ b/esphome/components/micronova/number/micronova_number.h @@ -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 diff --git a/esphome/components/micronova/sensor/__init__.py b/esphome/components/micronova/sensor/__init__.py new file mode 100644 index 0000000000..32e42f3888 --- /dev/null +++ b/esphome/components/micronova/sensor/__init__.py @@ -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)) diff --git a/esphome/components/micronova/sensor/micronova_sensor.cpp b/esphome/components/micronova/sensor/micronova_sensor.cpp new file mode 100644 index 0000000000..3f0c0feaf8 --- /dev/null +++ b/esphome/components/micronova/sensor/micronova_sensor.cpp @@ -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 diff --git a/esphome/components/micronova/sensor/micronova_sensor.h b/esphome/components/micronova/sensor/micronova_sensor.h new file mode 100644 index 0000000000..9d5ae96b87 --- /dev/null +++ b/esphome/components/micronova/sensor/micronova_sensor.h @@ -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 diff --git a/esphome/components/micronova/switch/__init__.py b/esphome/components/micronova/switch/__init__.py new file mode 100644 index 0000000000..9846d46cc6 --- /dev/null +++ b/esphome/components/micronova/switch/__init__.py @@ -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)) diff --git a/esphome/components/micronova/switch/micronova_switch.cpp b/esphome/components/micronova/switch/micronova_switch.cpp new file mode 100644 index 0000000000..dcc96102db --- /dev/null +++ b/esphome/components/micronova/switch/micronova_switch.cpp @@ -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 diff --git a/esphome/components/micronova/switch/micronova_switch.h b/esphome/components/micronova/switch/micronova_switch.h new file mode 100644 index 0000000000..b0ca33b497 --- /dev/null +++ b/esphome/components/micronova/switch/micronova_switch.h @@ -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 diff --git a/esphome/components/micronova/text_sensor/__init__.py b/esphome/components/micronova/text_sensor/__init__.py new file mode 100644 index 0000000000..dc27c4f32c --- /dev/null +++ b/esphome/components/micronova/text_sensor/__init__.py @@ -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)) diff --git a/esphome/components/micronova/text_sensor/micronova_text_sensor.cpp b/esphome/components/micronova/text_sensor/micronova_text_sensor.cpp new file mode 100644 index 0000000000..03b192ffd1 --- /dev/null +++ b/esphome/components/micronova/text_sensor/micronova_text_sensor.cpp @@ -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 diff --git a/esphome/components/micronova/text_sensor/micronova_text_sensor.h b/esphome/components/micronova/text_sensor/micronova_text_sensor.h new file mode 100644 index 0000000000..b4e5de9bb3 --- /dev/null +++ b/esphome/components/micronova/text_sensor/micronova_text_sensor.h @@ -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 diff --git a/tests/test1.yaml b/tests/test1.yaml index da6227e235..7bd6dcb41d 100644 --- a/tests/test1.yaml +++ b/tests/test1.yaml @@ -342,6 +342,10 @@ mcp23s17: cs_pin: GPIO12 deviceaddress: 1 +micronova: + enable_rx_pin: 4 + uart_id: uart_0 + dfrobot_sen0395: - id: mmwave uart_id: dfrobot_mmwave_uart @@ -1518,6 +1522,24 @@ sensor: field_strength_z: name: "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: setup_mode: false @@ -2705,6 +2727,9 @@ switch: name: "control ld2410 engineering mode" bluetooth: name: "control ld2410 bluetooth" + - platform: micronova + stove: + name: Stove on/off fan: - platform: binary @@ -3489,6 +3514,12 @@ number: name: g8 move threshold still_threshold: name: g8 still threshold + - platform: micronova + thermostat_temperature: + name: Micronova Thermostaat + step: 1 + power_level: + name: Micronova Power level select: - platform: template @@ -3619,6 +3650,12 @@ button: uart_id: uart_0 name: UART button data: "Pressed\r\n" + - platform: micronova + custom_button: + name: Custom Micronova Button + memory_location: 0xA0 + memory_address: 0x7D + memory_data: 0x0F ld2410: id: my_ld2410 @@ -3727,3 +3764,4 @@ alarm_control_panel: then: - lambda: !lambda |- ESP_LOGD("TEST", "State change %s", alarm_control_panel_state_to_string(id(alarmcontrolpanel1)->get_state())); +