Compare commits
6 Commits
9ddaa45146
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
a23dea333f
|
|||
|
32dfe237f8
|
|||
|
d5cc738a5c
|
|||
|
c3b8e366c7
|
|||
|
d6d37f1e27
|
|||
| 6b139cdc9b |
@@ -69,8 +69,9 @@ these can be configured in YAML.
|
||||
Since a lot of new connections will need to be made to ground, I recommend using
|
||||
something like a perforated prototype board and make a single connection to
|
||||
ground from the prototype board to the front panel control board, then connect
|
||||
all other grounds needed for the circuiti to each other using the prototype
|
||||
board. A 2cm$\times$8cm board fits perfectly in the empty space below the front panel in the front panel assemple. I also made all connections to the back of
|
||||
all other grounds needed for the circuit to each other using the prototype
|
||||
board. A 2cm $\times$ 8cm board fits perfectly in the empty space below the front panel in the front panel assembly. I also made all connections to the
|
||||
back of
|
||||
the front panel control board with wires with female Dupont connectors, then
|
||||
used male headers on the prototype board so that the additional circuitry can
|
||||
easily be removed.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import fan, output
|
||||
from esphome.const import CONF_OUTPUT_ID
|
||||
from esphome.const import CONF_ID
|
||||
from . import (
|
||||
HAUSLANE_SCHEMA,
|
||||
CONF_HAUSLANE_ID,
|
||||
@@ -16,14 +16,14 @@ HauslaneFan = hauslane_ns.class_(
|
||||
)
|
||||
|
||||
CONFIG_SCHEMA = (
|
||||
fan.FAN_SCHEMA.extend({
|
||||
cv.GenerateID(CONF_OUTPUT_ID): cv.declare_id(HauslaneFan),
|
||||
fan.fan_schema(HauslaneFan).extend({
|
||||
cv.GenerateID(CONF_HAUSLANE_ID): cv.use_id(HauslaneFan),
|
||||
})
|
||||
.extend(HAUSLANE_SCHEMA)
|
||||
)
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_OUTPUT_ID])
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await fan.register_fan(var,config)
|
||||
|
||||
paren = await cg.get_variable(config[CONF_HAUSLANE_ID])
|
||||
|
||||
@@ -30,7 +30,9 @@ void Hauslane::setup() {
|
||||
}
|
||||
|
||||
// register ESPHome API service named "command"
|
||||
#if defined(USE_API)
|
||||
register_service(&Hauslane::command, "command", {"command"});
|
||||
#endif
|
||||
}
|
||||
|
||||
void Hauslane::loop() {
|
||||
@@ -49,6 +51,10 @@ void Hauslane::loop() {
|
||||
} else {
|
||||
pos++;
|
||||
}
|
||||
} else if (rx_message.size() > MAX_RX) {
|
||||
parse_state();
|
||||
reading = false;
|
||||
pos = 0;
|
||||
} else {
|
||||
pos = 0;
|
||||
}
|
||||
@@ -94,23 +100,24 @@ void Hauslane::loop() {
|
||||
button_press(pin_down, true);
|
||||
}
|
||||
} else if (this->light_cur != this->light_target) {
|
||||
if (this->power) {
|
||||
// press light button
|
||||
button_press(pin_light, true);
|
||||
} else {
|
||||
// power on hood first
|
||||
if (this->speed==0 && !this->light_target) {
|
||||
// request light turn off and fan is off, so simply hit power button
|
||||
button_press(pin_power, true);
|
||||
} else if (!this->power && this->light_target) {
|
||||
// request light on and fan off, so power on hood first
|
||||
button_press(pin_power, true);
|
||||
} else if (this->power) {
|
||||
// press light button to toggle
|
||||
button_press(pin_light, true);
|
||||
}
|
||||
} else {
|
||||
// target already met, so reset flag
|
||||
this->meet_target=false;
|
||||
}
|
||||
} else if (this->speed==0 && !this->light_cur) {
|
||||
} else if (this->speed==0 && !this->light_cur && this->power) {
|
||||
// reset power flag
|
||||
if(this->power) {
|
||||
this->power=false;
|
||||
ESP_LOGD(TAG, "Hood power: %d", this->power);
|
||||
}
|
||||
this->power=false;
|
||||
ESP_LOGD(TAG, "Hood power: %d", this->power);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -142,7 +149,7 @@ void Hauslane::set_speed(int new_speed) {
|
||||
|
||||
// read message on rx line and turn into current state of fan and light
|
||||
void Hauslane::parse_state() {
|
||||
size_t len = rx_message.size()-4;
|
||||
size_t len = rx_message.size()-END_LEN;
|
||||
std::string msg;
|
||||
std::vector<uint8_t> msg_hex;
|
||||
|
||||
@@ -158,20 +165,20 @@ void Hauslane::parse_state() {
|
||||
// oscilloscope, but as there is only one-way communication from the front
|
||||
// panel to the main controller board, this would only be useful if
|
||||
// replacing the front panel entirely
|
||||
const std::vector<uint8_t> off_0{0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce};
|
||||
const std::vector<uint8_t> on_0{0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xc6};
|
||||
const std::vector<uint8_t> off_1{0xce, 0xc6, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xc6, 0xce, 0xce};
|
||||
const std::vector<uint8_t> on_1{0xce, 0xc6, 0xce, 0xce, 0xce, 0xce, 0xce};
|
||||
const std::vector<uint8_t> off_2{0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xc6, 0xce, 0xce};
|
||||
const std::vector<uint8_t> on_2{0xce, 0xc6, 0xce, 0xce, 0xce, 0xce, 0xce, 0xc6, 0xce, 0xc6};
|
||||
const std::vector<uint8_t> off_3{0x38, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce};
|
||||
const std::vector<uint8_t> on_3{0x38, 0xc6, 0xce, 0xce, 0xce, 0xce, 0xce};
|
||||
const std::vector<uint8_t> off_4{0xc6, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xc6, 0xce, 0xce, 0xce};
|
||||
const std::vector<uint8_t> on_4{0xc6, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce};
|
||||
const std::vector<uint8_t> off_5{0xc6, 0xc6, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xc6, 0xc6, 0xce, 0xce};
|
||||
const std::vector<uint8_t> on_5{0xc6, 0xc6, 0xce, 0xce, 0xce, 0xce, 0xc6};
|
||||
const std::vector<uint8_t> off_6{0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0x38, 0xce, 0xce};
|
||||
const std::vector<uint8_t> on_6{0xce, 0xc6, 0xce, 0xce, 0xce, 0xce, 0x38};
|
||||
const std::vector<uint8_t> off_0{0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0x00};
|
||||
const std::vector<uint8_t> on_0{0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xc6, 0xfe};
|
||||
const std::vector<uint8_t> off_1{0xce, 0xc6, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xc6, 0xce, 0xce, 0xc0};
|
||||
const std::vector<uint8_t> on_1{0xce, 0xc6, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xfe};
|
||||
const std::vector<uint8_t> off_2{0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xc6, 0xce, 0xce, 0xfe};
|
||||
const std::vector<uint8_t> on_2{0xce, 0xce, 0xc6, 0xce, 0xce, 0xce, 0xce, 0xce, 0xc6, 0xce, 0xc6, 0xfe};
|
||||
const std::vector<uint8_t> off_3{0xce, 0x38, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xc6, 0xce, 0xce, 0x00};
|
||||
const std::vector<uint8_t> on_3{0xce, 0x38, 0xc6, 0xce, 0xce, 0xce, 0xce, 0xce, 0xc6, 0xce, 0xfe};
|
||||
const std::vector<uint8_t> off_4{0xc6, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xc6, 0xce, 0xce, 0xce, 0x00};
|
||||
const std::vector<uint8_t> on_4{0xc6, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xfe};
|
||||
const std::vector<uint8_t> off_5{0xc6, 0xc6, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xc6, 0xc6, 0xce, 0xce, 0x00};
|
||||
const std::vector<uint8_t> on_5{0xc6, 0xc6, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xc6, 0xce, 0xfe};
|
||||
const std::vector<uint8_t> off_6{0xc6, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0xce, 0x38, 0xce, 0xce, 0x00};
|
||||
const std::vector<uint8_t> on_6{0xc6, 0xce, 0xc6, 0xce, 0xce, 0xce, 0xce, 0xce, 0x38, 0xce, 0xfe};
|
||||
|
||||
// print out formatted hex string to log
|
||||
char buf[5];
|
||||
@@ -224,6 +231,10 @@ void Hauslane::set_state(bool set_light, uint8_t set_speed) {
|
||||
// save current state of light in memory
|
||||
ESP_LOGD(TAG, "Received light state: %d", set_light);
|
||||
this->light_cur = set_light;
|
||||
if (!this->meet_target) {
|
||||
// sync target light state if changed by button press
|
||||
this->light_target = set_light;
|
||||
}
|
||||
// send light state to API if it is active
|
||||
if (this->send_light_state) {
|
||||
ESP_LOGD(TAG, "Sending new light state.");
|
||||
@@ -234,12 +245,20 @@ void Hauslane::set_state(bool set_light, uint8_t set_speed) {
|
||||
// save current state of fan in memory
|
||||
ESP_LOGD(TAG, "Received fan speed: %d", set_speed);
|
||||
this->speed = set_speed;
|
||||
if (!this->meet_target) {
|
||||
// sync target fan state if changed by button press
|
||||
this->speed_target = set_speed;
|
||||
}
|
||||
// send fan state to API if it is active
|
||||
if (this->send_fan_speed) {
|
||||
ESP_LOGD(TAG,"Sending new fan speed.");
|
||||
this->send_fan_speed(set_speed);
|
||||
}
|
||||
}
|
||||
if (!this->power && (set_speed > 0 || set_light)) {
|
||||
// set power to on if light or fan are on
|
||||
this->power = true;
|
||||
}
|
||||
}
|
||||
|
||||
// custom component API commands
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/uart/uart.h"
|
||||
#ifdef USE_API
|
||||
#include "esphome/components/api/custom_api_device.h"
|
||||
#endif
|
||||
#ifdef USE_LIGHT
|
||||
#include "esphome/components/light/light_output.h"
|
||||
#endif
|
||||
@@ -13,10 +15,11 @@
|
||||
namespace esphome {
|
||||
namespace hauslane {
|
||||
|
||||
static const unsigned char MSG_START[] = {0x08, 0x08, 0x08, 0xfe, 0xc0};
|
||||
static const unsigned char MSG_END[] = {0xc0, 0xce, 0xce, 0xce};
|
||||
static const uint8_t START_LEN=5;
|
||||
static const uint8_t END_LEN=4;
|
||||
static const unsigned char MSG_START[] = {0x08, 0x08, 0x08, 0xfe, 0x00, 0xc0};
|
||||
static const unsigned char MSG_END[] = {0xc0, 0xce, 0xce, 0xce, 0xc6};
|
||||
static const uint8_t START_LEN=6;
|
||||
static const uint8_t END_LEN=5;
|
||||
static const size_t MAX_RX=30;
|
||||
static const int DELAY=250; // how long to press/release buttons in ms
|
||||
|
||||
class Hauslane : public Component, public uart::UARTDevice, public api::CustomAPIDevice {
|
||||
|
||||
@@ -13,12 +13,15 @@ esphome:
|
||||
|
||||
esp32:
|
||||
board: esp32-c3-devkitm-1
|
||||
platform:
|
||||
type: esp-idf
|
||||
|
||||
# Enable logging
|
||||
logger:
|
||||
level: DEBUG
|
||||
|
||||
api:
|
||||
custom_services: true
|
||||
password: !secret api_password
|
||||
|
||||
ota:
|
||||
|
||||
Reference in New Issue
Block a user