add_learn
This commit is contained in:
parent
587ff4c7c5
commit
3744f571d3
|
@ -58,6 +58,13 @@ switch:
|
|||
output: true
|
||||
name: "Status obstruction"
|
||||
entity_category: diagnostic
|
||||
- platform: ratgdo
|
||||
id: "${id_prefix}_learn"
|
||||
type: learn
|
||||
ratgdo_id: ${id_prefix}
|
||||
name: "Learn"
|
||||
icon: mdi:plus-box
|
||||
entity_category: diagnostic
|
||||
|
||||
binary_sensor:
|
||||
- platform: ratgdo
|
||||
|
|
|
@ -194,6 +194,16 @@ namespace ratgdo {
|
|||
this->motion_state = MotionState::CLEAR; // when the status message is read, reset motion state to 0|clear
|
||||
this->motor_state = MotorState::OFF; // when the status message is read, reset motor state to 0|off
|
||||
|
||||
if (*this->learn_state != static_cast<LearnState>((byte2 >> 5) & 1)) {
|
||||
this->learn_state = static_cast<LearnState>((byte2 >> 5) & 1);
|
||||
if (*this->learn_state == LearnState::ACTIVE && this->learn_poll_status_) {
|
||||
set_interval("learn_poll", 1000, [=] { this->send_command(Command::GET_STATUS); });
|
||||
} else {
|
||||
cancel_interval("learn_poll");
|
||||
learn_poll_status_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (this->obstruction_from_status_) {
|
||||
// ESP_LOGD(TAG, "Obstruction: reading from byte2, bit2, status=%d", ((byte2 >> 2) & 1) == 1);
|
||||
this->obstruction_state = static_cast<ObstructionState>((byte1 >> 6) & 1);
|
||||
|
@ -207,10 +217,12 @@ namespace ratgdo {
|
|||
this->send_command(Command::GET_OPENINGS);
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Status: door=%s light=%s lock=%s",
|
||||
ESP_LOGD(TAG, "Status: door=%s light=%s lock=%s learn=%s",
|
||||
DoorState_to_string(*this->door_state),
|
||||
LightState_to_string(*this->light_state),
|
||||
LockState_to_string(*this->lock_state));
|
||||
LockState_to_string(*this->lock_state),
|
||||
LearnState_to_string(*this->learn_state));
|
||||
|
||||
} else if (cmd == Command::LIGHT) {
|
||||
if (nibble == 0) {
|
||||
this->light_state = LightState::OFF;
|
||||
|
@ -251,6 +263,11 @@ namespace ratgdo {
|
|||
auto seconds = (byte1 << 8) | byte2;
|
||||
ESP_LOGD(TAG, "Time to close (TTC): %ds", seconds);
|
||||
}
|
||||
if (cmd == Command::LEARN) {
|
||||
if (nibble == 1) { // LEARN sent from wall control, it will poll status every second
|
||||
learn_poll_status_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
return cmd;
|
||||
}
|
||||
|
@ -724,6 +741,30 @@ namespace ratgdo {
|
|||
return *this->light_state;
|
||||
}
|
||||
|
||||
// Learn functions
|
||||
void RATGDOComponent::activate_learn()
|
||||
{
|
||||
// Send LEARN with nibble = 0 then nibble = 1 to mimic wall control learn button
|
||||
learn_poll_status_ = true;
|
||||
this->send_command(Command::LEARN, 0);
|
||||
set_timeout(150, [=] { this->send_command(Command::LEARN, 1); });
|
||||
set_timeout(500, [=] { this->send_command(Command::GET_STATUS); });
|
||||
}
|
||||
|
||||
void RATGDOComponent::inactivate_learn()
|
||||
{
|
||||
// Send LEARN twice with nibble = 0 to inactivate learn and get status to update switch state
|
||||
this->send_command(Command::LEARN, 0);
|
||||
set_timeout(150, [=] { this->send_command(Command::LEARN, 0); });
|
||||
set_timeout(500, [=] { this->send_command(Command::GET_STATUS); });
|
||||
}
|
||||
|
||||
void RATGDOComponent::toggle_learn()
|
||||
{
|
||||
this->learn_state = learn_state_toggle(*this->learn_state);
|
||||
// this->send_command(Command::learn, data::LOCK_TOGGLE);
|
||||
}
|
||||
|
||||
void RATGDOComponent::subscribe_rolling_code_counter(std::function<void(uint32_t)>&& f)
|
||||
{
|
||||
// change update to children is defered until after component loop
|
||||
|
@ -779,6 +820,10 @@ namespace ratgdo {
|
|||
{
|
||||
this->sync_failed.subscribe(std::move(f));
|
||||
}
|
||||
void RATGDOComponent::subscribe_learn_state(std::function<void(LearnState)>&& f)
|
||||
{
|
||||
this->learn_state.subscribe([=](LearnState state) { defer("learn_state", [=] { f(state); }); });
|
||||
}
|
||||
|
||||
} // namespace ratgdo
|
||||
} // namespace esphome
|
||||
|
|
|
@ -64,7 +64,7 @@ namespace ratgdo {
|
|||
(PAIR_3, 0x0a0),
|
||||
(PAIR_3_RESP, 0x0a1),
|
||||
|
||||
(LEARN_2, 0x181),
|
||||
(LEARN, 0x181),
|
||||
(LOCK, 0x18c),
|
||||
(DOOR_ACTION, 0x280),
|
||||
(LIGHT, 0x281),
|
||||
|
@ -124,6 +124,7 @@ namespace ratgdo {
|
|||
observable<MotorState> motor_state { MotorState::UNKNOWN };
|
||||
observable<ButtonState> button_state { ButtonState::UNKNOWN };
|
||||
observable<MotionState> motion_state { MotionState::UNKNOWN };
|
||||
observable<LearnState> learn_state { LearnState::UNKNOWN };
|
||||
|
||||
OnceCallbacks<void(DoorState)> door_state_received;
|
||||
OnceCallbacks<void()> command_sent;
|
||||
|
@ -173,6 +174,10 @@ namespace ratgdo {
|
|||
void lock();
|
||||
void unlock();
|
||||
|
||||
void toggle_learn();
|
||||
void activate_learn();
|
||||
void inactivate_learn();
|
||||
|
||||
// button functionality
|
||||
void query_status();
|
||||
void query_openings();
|
||||
|
@ -191,6 +196,7 @@ namespace ratgdo {
|
|||
void subscribe_button_state(std::function<void(ButtonState)>&& f);
|
||||
void subscribe_motion_state(std::function<void(MotionState)>&& f);
|
||||
void subscribe_sync_failed(std::function<void(bool)>&& f);
|
||||
void subscribe_learn_state(std::function<void(LearnState)>&& f);
|
||||
|
||||
protected:
|
||||
// tx data
|
||||
|
@ -203,6 +209,8 @@ namespace ratgdo {
|
|||
|
||||
bool obstruction_from_status_ { false };
|
||||
|
||||
bool learn_poll_status_ { true };
|
||||
|
||||
InternalGPIOPin* output_gdo_pin_;
|
||||
InternalGPIOPin* input_gdo_pin_;
|
||||
InternalGPIOPin* input_obst_pin_;
|
||||
|
|
|
@ -31,5 +31,19 @@ namespace ratgdo {
|
|||
}
|
||||
}
|
||||
|
||||
LearnState learn_state_toggle(LearnState state)
|
||||
{
|
||||
switch (state) {
|
||||
case LearnState::ACTIVE:
|
||||
return LearnState::INACTIVE;
|
||||
case LearnState::INACTIVE:
|
||||
return LearnState::ACTIVE;
|
||||
// 2 and 3 appears sometimes
|
||||
case LearnState::UNKNOWN:
|
||||
default:
|
||||
return LearnState::UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ratgdo
|
||||
} // namespace esphome
|
||||
|
|
|
@ -64,5 +64,12 @@ namespace ratgdo {
|
|||
(RELEASED, 1),
|
||||
(UNKNOWN, 2))
|
||||
|
||||
/// Enum for learn states.
|
||||
ENUM(LearnState, uint8_t,
|
||||
(INACTIVE, 0),
|
||||
(ACTIVE, 1),
|
||||
(UNKNOWN, 2))
|
||||
LearnState learn_state_toggle(LearnState state);
|
||||
|
||||
} // namespace ratgdo
|
||||
} // namespace esphome
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
import esphome.codegen as cg
|
||||
import esphome.config_validation as cv
|
||||
from esphome.components import switch
|
||||
from esphome.const import CONF_ID
|
||||
|
||||
from .. import RATGDO_CLIENT_SCHMEA, ratgdo_ns, register_ratgdo_child
|
||||
|
||||
DEPENDENCIES = ["ratgdo"]
|
||||
|
||||
RATGDOSwitch = ratgdo_ns.class_("RATGDOSwitch", switch.Switch, cg.Component)
|
||||
SwitchType = ratgdo_ns.enum("SwitchType")
|
||||
|
||||
CONF_TYPE = "type"
|
||||
TYPES = {
|
||||
"learn": SwitchType.RATGDO_LEARN,
|
||||
}
|
||||
|
||||
|
||||
CONFIG_SCHEMA = (
|
||||
switch.switch_schema(RATGDOSwitch)
|
||||
.extend(
|
||||
{
|
||||
cv.Required(CONF_TYPE): cv.enum(TYPES, lower=True),
|
||||
}
|
||||
)
|
||||
.extend(RATGDO_CLIENT_SCHMEA)
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config):
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await switch.register_switch(var, config)
|
||||
await cg.register_component(var, config)
|
||||
cg.add(var.set_switch_type(config[CONF_TYPE]))
|
||||
await register_ratgdo_child(var, config)
|
|
@ -0,0 +1,46 @@
|
|||
#include "ratgdo_switch.h"
|
||||
#include "../ratgdo_state.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace ratgdo {
|
||||
|
||||
static const char* const TAG = "ratgdo.switch";
|
||||
|
||||
void RATGDOSwitch::dump_config()
|
||||
{
|
||||
LOG_SWITCH("", "RATGDO Switch", this);
|
||||
if (this->switch_type_ == SwitchType::RATGDO_LEARN) {
|
||||
ESP_LOGCONFIG(TAG, " Type: Learn");
|
||||
}
|
||||
}
|
||||
|
||||
void RATGDOSwitch::setup()
|
||||
{
|
||||
if (this->switch_type_ == SwitchType::RATGDO_LEARN) {
|
||||
this->parent_->subscribe_learn_state([=](LearnState state) {
|
||||
this->on_learn_state(state);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void RATGDOSwitch::on_learn_state(LearnState state)
|
||||
{
|
||||
bool value = state == LearnState::ACTIVE;
|
||||
this->state = value;
|
||||
this->publish_state(value);
|
||||
}
|
||||
|
||||
void RATGDOSwitch::write_state(bool state)
|
||||
{
|
||||
if (this->switch_type_ == SwitchType::RATGDO_LEARN) {
|
||||
if (state) {
|
||||
this->parent_->activate_learn();
|
||||
} else {
|
||||
this->parent_->inactivate_learn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ratgdo
|
||||
} // namespace esphome
|
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
#include "../ratgdo.h"
|
||||
#include "../ratgdo_state.h"
|
||||
#include "esphome/components/switch/switch.h"
|
||||
#include "esphome/core/component.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace ratgdo {
|
||||
|
||||
enum SwitchType {
|
||||
RATGDO_LEARN
|
||||
};
|
||||
|
||||
class RATGDOSwitch : public switch_::Switch, public RATGDOClient, public Component {
|
||||
public:
|
||||
void dump_config() override;
|
||||
void setup() override;
|
||||
void set_switch_type(SwitchType switch_type_) { this->switch_type_ = switch_type_; }
|
||||
|
||||
void on_learn_state(LearnState state);
|
||||
void write_state(bool state) override;
|
||||
|
||||
protected:
|
||||
SwitchType switch_type_;
|
||||
};
|
||||
|
||||
} // namespace ratgdo
|
||||
} // namespace esphome
|
Loading…
Reference in New Issue