mirror of
https://github.com/esphome/esphome.git
synced 2024-11-25 08:28:12 +01: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:
parent
22cdb8dfc3
commit
13994d9bd1
20 changed files with 1134 additions and 0 deletions
|
@ -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()));
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue