Skip to content

Commit

Permalink
Merge pull request #58 from konnected-io/door-op-fixes
Browse files Browse the repository at this point in the history
Door op fixes
  • Loading branch information
heythisisnate authored Jun 7, 2024
2 parents cdc79d3 + 7d4d207 commit debbc5a
Show file tree
Hide file tree
Showing 11 changed files with 146 additions and 31 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
# You can modify this file to suit your needs.
/.esphome/
/secrets.yaml
__pycache__/
__pycache__/
.vscode
6 changes: 1 addition & 5 deletions components/secplus_gdo/cover/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
CONF_PRE_CLOSE_WARNING_DURATION = "pre_close_warning_duration"
CONF_PRE_CLOSE_WARNING_START = "pre_close_warning_start"
CONF_PRE_CLOSE_WARNING_END = "pre_close_warning_end"
CONF_TOGGLE_ONLY = "toggle_only"

CONFIG_SCHEMA = cover.COVER_SCHEMA.extend(
{
Expand All @@ -52,7 +51,6 @@
cv.Optional(CONF_PRE_CLOSE_WARNING_END): automation.validate_automation(
{cv.GenerateID(CONF_TRIGGER_ID): cv.declare_id(CoverClosingEndTrigger)}
),
cv.Optional(CONF_TOGGLE_ONLY, default=False): cv.boolean,
}
).extend(SECPLUS_GDO_CONFIG_SCHEMA)

Expand All @@ -62,10 +60,8 @@ async def to_code(config):
await cg.register_component(var, config)
await cover.register_cover(var, config)
parent = await cg.get_variable(config[CONF_SECPLUS_GDO_ID])
text = "std::bind(&" + str(GDODoor) + "::set_state," + str(config[CONF_ID]) + ",std::placeholders::_1,std::placeholders::_2)"
cg.add(parent.register_door(cg.RawExpression(text)))
cg.add(parent.register_door(var))
cg.add(var.set_pre_close_warning_duration(config[CONF_PRE_CLOSE_WARNING_DURATION]))
cg.add(var.set_toggle_only(config[CONF_TOGGLE_ONLY]))
for conf in config.get(CONF_PRE_CLOSE_WARNING_START, []):
trigger = cg.new_Pvariable(conf[CONF_TRIGGER_ID], var)
await automation.build_automation(trigger, [], conf)
Expand Down
57 changes: 53 additions & 4 deletions components/secplus_gdo/cover/gdo_door.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ void GDODoor::set_state(gdo_door_state_t state, float position) {
this->position = position;
break;
case GDO_DOOR_STATE_STOPPED:
this->prev_operation = this->current_operation;
// falls through
case GDO_DOOR_STATE_MAX:
default:
this->current_operation = COVER_OPERATION_IDLE;
Expand All @@ -49,6 +51,7 @@ void GDODoor::set_state(gdo_door_state_t state, float position) {
}

this->publish_state(false);
this->state_ = state;
}

void GDODoor::do_action_after_warning(const cover::CoverCall& call) {
Expand Down Expand Up @@ -79,7 +82,8 @@ void GDODoor::do_action(const cover::CoverCall& call) {
ESP_LOGD(TAG, "Sending STOP action");
gdo_door_stop();
}
if (call.get_toggle()) {

if (call.get_toggle()) {
if (this->position == COVER_CLOSED) {
this->set_state(GDO_DOOR_STATE_OPENING, this->position);
} else if (this->position == COVER_OPEN) {
Expand All @@ -88,26 +92,47 @@ void GDODoor::do_action(const cover::CoverCall& call) {
ESP_LOGD(TAG, "Sending TOGGLE action");
gdo_door_toggle();
}

if (call.get_position().has_value()) {
auto pos = *call.get_position();
if (pos == COVER_OPEN) {
this->set_state(GDO_DOOR_STATE_OPENING, this->position);
if (this->toggle_only_) {
ESP_LOGD(TAG, "Sending TOGGLE action");
gdo_door_toggle();
if (this->state_ == GDO_DOOR_STATE_STOPPED && this->prev_operation == COVER_OPERATION_OPENING) {
// If the door was stopped while opening, then we need to toggle to stop, then toggle again to open,
this->set_timeout("stop_door", 1000, [=]() {
gdo_door_stop();
});
this->set_timeout("open_door", 2000, [=]() {
gdo_door_toggle();
});
}
} else {
ESP_LOGD(TAG, "Sending OPEN action");
gdo_door_open();
}
} else if (pos == COVER_CLOSED) {
this->set_state(GDO_DOOR_STATE_CLOSING, this->position);

this->set_state(GDO_DOOR_STATE_OPENING, this->position);
} else if (pos == COVER_CLOSED) {
if (this->toggle_only_) {
ESP_LOGD(TAG, "Sending TOGGLE action");
gdo_door_toggle();
if (this->state_ == GDO_DOOR_STATE_STOPPED && this->prev_operation == COVER_OPERATION_CLOSING) {
// If the door was stopped while closing, then we need to toggle to stop, then toggle again to close,
this->set_timeout("stop_door", 1000, [=]() {
gdo_door_stop();
});
this->set_timeout("close_door", 2000, [=]() {
gdo_door_toggle();
});
}
} else {
ESP_LOGD(TAG, "Sending CLOSE action");
gdo_door_close();
}

this->set_state(GDO_DOOR_STATE_CLOSING, this->position);
} else {
ESP_LOGD(TAG, "Moving garage door to position %f", pos);
gdo_door_move_to_target(10000 - (pos * 10000));
Expand All @@ -126,22 +151,44 @@ void GDODoor::control(const cover::CoverCall& call) {
this->pre_close_end_trigger->trigger();
}
}
this->target_position_ = this->position;
this->do_action(call);
}

if (call.get_toggle()) {
ESP_LOGD(TAG, "Toggle command received");
if (this->position != COVER_CLOSED) {
this->target_position_ = COVER_CLOSED;
this->do_action_after_warning(call);
} else {
this->target_position_ = COVER_OPEN;
this->do_action(call);
}
}

if (call.get_position().has_value()) {
auto pos = *call.get_position();
if (this->position == pos) {
ESP_LOGD(TAG, "Door is already %s", pos == COVER_OPEN ? "open" : "closed");
this->publish_state(false);
return;
}

if ((this->current_operation == COVER_OPERATION_OPENING && pos > this->position) ||
(this->current_operation == COVER_OPERATION_CLOSING && pos < this->position)) {
ESP_LOGD(TAG, "Door is already moving in target direction; target position: %.0f%%", *this->target_position_);
this->publish_state(false);
return;
}

if (this->pre_close_active_) {
// don't start the pre-close again if the door is already going to close.
if (pos < this->position) {
ESP_LOGD(TAG, "Door is already closing");
this->publish_state(false);
return;
}

ESP_LOGD(TAG, "Canceling pending action");
this->cancel_timeout("pre_close");
this->pre_close_active_ = false;
Expand Down Expand Up @@ -172,6 +219,8 @@ void GDODoor::control(const cover::CoverCall& call) {
this->do_action(call);
}
}

this->target_position_ = pos;
}
}

Expand Down
7 changes: 5 additions & 2 deletions components/secplus_gdo/cover/gdo_door.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ using namespace esphome::cover;
}

void do_action(const cover::CoverCall& call);
void do_action_after_warning(const cover::CoverCall& call);
void do_action_after_warning(const cover::CoverCall& call);
void set_pre_close_warning_duration(uint32_t ms) { this->pre_close_duration_ = ms; }
void set_toggle_only(bool val) { this->toggle_only_ = val; }
void set_state(gdo_door_state_t state, float position);
Expand All @@ -55,9 +55,12 @@ using namespace esphome::cover;

CoverClosingStartTrigger *pre_close_start_trigger{nullptr};
CoverClosingEndTrigger *pre_close_end_trigger{nullptr};
uint32_t pre_close_duration_{0};
uint32_t pre_close_duration_{0};
bool pre_close_active_{false};
bool toggle_only_{false};
optional<float> target_position_{0};
CoverOperation prev_operation{COVER_OPERATION_IDLE};
gdo_door_state_t state_{GDO_DOOR_STATE_MAX};
};
} // namespace secplus_gdo
} // namespace esphome
5 changes: 5 additions & 0 deletions components/secplus_gdo/secplus_gdo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ namespace secplus_gdo {
}

void GDOComponent::setup() {
// Set the toggle only state and control here because we cannot guarantee the cover instance was created before the switch
this->door_->set_toggle_only(this->toggle_only_switch_->state);
this->toggle_only_switch_->set_control_function(std::bind(&esphome::secplus_gdo::GDODoor::set_toggle_only,
this->door_, std::placeholders::_1));

gdo_config_t gdo_conf = {
.uart_num = UART_NUM_1,
.obst_from_status = true,
Expand Down
25 changes: 17 additions & 8 deletions components/secplus_gdo/secplus_gdo.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#include "number/gdo_number.h"
#include "esphome/core/defines.h"
#include "select/gdo_select.h"
#include "switch/gdo_switch.h"
#include "cover/gdo_door.h"
#include "gdo.h"

namespace esphome {
Expand All @@ -35,7 +37,9 @@ namespace secplus_gdo {
float get_setup_priority() const override { return setup_priority::LATE; }

void register_protocol_select(GDOSelect *select) { this->protocol_select_ = select; }
void set_protocol_state(gdo_protocol_type_t protocol) { if (this->protocol_select_) { this->protocol_select_->update_state(protocol); } }
void set_protocol_state(gdo_protocol_type_t protocol) { if (this->protocol_select_) {
this->protocol_select_->update_state(protocol); }
}

void register_motion(std::function<void(bool)> f) { f_motion = f; }
void set_motion_state(gdo_motion_state_t state) { if (f_motion) { f_motion(state == GDO_MOTION_STATE_DETECTED); } }
Expand All @@ -54,17 +58,19 @@ namespace secplus_gdo {
void register_openings(std::function<void(uint16_t)> f) { f_openings = f; }
void set_openings(uint16_t openings) { if (f_openings) { f_openings(openings); } }

void register_door(std::function<void(gdo_door_state_t, float)> f) { f_door = f; }
void set_door_state(gdo_door_state_t state, float position) { if (f_door) { f_door(state, position); } }
void register_door(GDODoor *door) { this->door_ = door; }
void set_door_state(gdo_door_state_t state, float position) { if (this->door_) { this->door_->set_state(state, position); } }

void register_light(std::function<void(gdo_light_state_t)> f) { f_light = f; }
void set_light_state(gdo_light_state_t state) { if (f_light) { f_light(state); } }

void register_lock(std::function<void(gdo_lock_state_t)> f) { f_lock = f; }
void set_lock_state(gdo_lock_state_t state) { if (f_lock) { f_lock(state); } }

void register_learn(std::function<void(bool)> f) { f_learn = f; }
void set_learn_state(gdo_learn_state_t state) { if (f_learn) { f_learn(state == GDO_LEARN_STATE_ACTIVE); } }
void register_learn(GDOSwitch *sw) { this->learn_switch_ = sw; }
void set_learn_state(gdo_learn_state_t state) { if (this->learn_switch_) {
this->learn_switch_->write_state(state == GDO_LEARN_STATE_ACTIVE); }
}

void register_open_duration(GDONumber* num) { open_duration_ = num; }
void set_open_duration(uint16_t ms ) { if (open_duration_) { open_duration_->update_state(ms); } }
Expand All @@ -78,22 +84,25 @@ namespace secplus_gdo {
void register_rolling_code(GDONumber* num) { rolling_code_ = num; }
void set_rolling_code(uint32_t num) { if (rolling_code_) { rolling_code_->update_state(num); } }

void register_toggle_only(GDOSwitch *sw) { this->toggle_only_switch_ = sw; }

protected:
gdo_status_t status_;
std::function<void(gdo_door_state_t, float)> f_door{nullptr};
gdo_status_t status_{};
std::function<void(gdo_lock_state_t)> f_lock{nullptr};
std::function<void(gdo_light_state_t)> f_light{nullptr};
std::function<void(uint16_t)> f_openings{nullptr};
std::function<void(bool)> f_motion{nullptr};
std::function<void(bool)> f_obstruction{nullptr};
std::function<void(bool)> f_button{nullptr};
std::function<void(bool)> f_motor{nullptr};
std::function<void(bool)> f_learn{nullptr};
GDODoor* door_{nullptr};
GDONumber* open_duration_{nullptr};
GDONumber* close_duration_{nullptr};
GDONumber* client_id_{nullptr};
GDONumber* rolling_code_{nullptr};
GDOSelect* protocol_select_{nullptr};
GDOSwitch* learn_switch_{nullptr};
GDOSwitch* toggle_only_switch_{nullptr};

}; // GDOComponent
} // namespace secplus_gdo
Expand Down
7 changes: 5 additions & 2 deletions components/secplus_gdo/switch/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
CONF_TYPE = "type"
TYPES = {
"learn": "register_learn",
"toggle_only": "register_toggle_only",
}


Expand All @@ -32,5 +33,7 @@ async def to_code(config):
await cg.register_component(var, config)
parent = await cg.get_variable(config[CONF_SECPLUS_GDO_ID])
fcall = str(parent) + "->" + str(TYPES[config[CONF_TYPE]])
text = fcall + "(std::bind(&" + str(GDOSwitch) + "::write_state," + str(config[CONF_ID]) + ",std::placeholders::_1))"
cg.add((cg.RawExpression(text)))
text = fcall + "(" + str(var) + ")"
cg.add((cg.RawExpression(text)))
text = "secplus_gdo::SwitchType::" + str(config[CONF_TYPE]).upper()
cg.add(var.set_type(cg.RawExpression(text)))
48 changes: 44 additions & 4 deletions components/secplus_gdo/switch/gdo_switch.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,61 @@
#pragma once

#include "esphome/components/switch/switch.h"
#include "esphome/core/preferences.h"
#include "esphome/core/component.h"
#include "gdo.h"

namespace esphome {
namespace secplus_gdo {

enum SwitchType {
LEARN,
TOGGLE_ONLY,
};

class GDOSwitch : public switch_::Switch, public Component {
public:
void dump_config() override {}
void setup() override {
bool value = false;
this->pref_ = global_preferences->make_preference<bool>(this->get_object_id_hash());
if (!this->pref_.load(&value)) {
value = false;
}

this->write_state(value);
}

void write_state(bool state) override {
if (state) {
gdo_activate_learn();
} else {
gdo_deactivate_learn();
if (state == this->state) {
return;
}

if (this->type_ == SwitchType::TOGGLE_ONLY) {
if (this->f_control) {
this->f_control(state);
this->pref_.save(&state);
}
}

if (this->type_ == SwitchType::LEARN) {
if (state) {
gdo_activate_learn();
} else {
gdo_deactivate_learn();
}
}

this->publish_state(state);
}

void set_type(SwitchType type) { this->type_ = type; }
void set_control_function(std::function<void(bool)> f) { f_control = f; }

protected:
SwitchType type_{SwitchType::LEARN};
std::function<void(bool)> f_control{nullptr};
ESPPreferenceObject pref_;
};

} // namespace secplus_gdo
Expand Down
8 changes: 4 additions & 4 deletions garage-door-GDOv2-Q.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ substitutions:
status_led: GPIO18

external_components:
- source: github://konnected-io/konnected-esphome@master
- source: github://konnected-io/konnected-esphome@door-op-fixes
components: [ mdns, secplus_gdo ]

# Un-comment below and comment above for local modification
Expand All @@ -106,7 +106,7 @@ packages:

remote_package:
url: https://github.com/konnected-io/konnected-esphome
ref: master
ref: door-op-fixes
refresh: 5min
files:

Expand Down Expand Up @@ -155,7 +155,7 @@ packages:
# Enables automatic discovery and upgrades via ESPHome Dashboard
# more: https://esphome.io/guides/getting_started_hassio.html
dashboard_import:
package_import_url: github://konnected-io/konnected-esphome/garage-door-GDOv2-Q.yaml@master
package_import_url: github://konnected-io/konnected-esphome/garage-door-GDOv2-Q.yaml@door-op-fixes
import_full_config: false

####
Expand Down Expand Up @@ -193,6 +193,6 @@ web_server:
esphome:
platformio_options:
lib_deps:
- https://github.com/konnected-io/gdolib
- https://github.com/konnected-io/gdolib#command-delay-rx-fix
build_flags:
- -DUART_SCLK_DEFAULT=UART_SCLK_APB
Loading

0 comments on commit debbc5a

Please sign in to comment.