Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GDO blaQ command parsing, reliability, sync and logging improvements #68

Merged
merged 9 commits into from
Jul 9, 2024
1 change: 1 addition & 0 deletions components/secplus_gdo/binary_sensor/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
"obstruction": "register_obstruction",
"motor": "register_motor",
"button": "register_button",
"sync": "register_sync",
}


Expand Down
11 changes: 11 additions & 0 deletions components/secplus_gdo/cover/gdo_door.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ void GDODoor::set_state(gdo_door_state_t state, float position) {
}
}

if (this->state_ == state && this->position == position) {
return;
}

ESP_LOGI(TAG, "Door state: %s, position: %.0f%%", gdo_door_state_to_string(state), position * 100.0f);

switch (state) {
case GDO_DOOR_STATE_OPEN:
this->position = COVER_OPEN;
Expand Down Expand Up @@ -141,6 +147,11 @@ void GDODoor::do_action(const cover::CoverCall& call) {
}

void GDODoor::control(const cover::CoverCall& call) {
if (!this->synced_) {
this->publish_state(false);
return;
}

if (call.get_stop()) {
ESP_LOGD(TAG, "Stop command received");
if (this->pre_close_active_) {
Expand Down
5 changes: 5 additions & 0 deletions components/secplus_gdo/cover/gdo_door.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ using namespace esphome::cover;
this->pre_close_end_trigger = trigger;
}

void set_sync_state(bool synced) {
this->synced_ = synced;
}

void do_action(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; }
Expand All @@ -61,6 +65,7 @@ using namespace esphome::cover;
optional<float> target_position_{0};
CoverOperation prev_operation{COVER_OPERATION_IDLE};
gdo_door_state_t state_{GDO_DOOR_STATE_MAX};
bool synced_{false};
};
} // namespace secplus_gdo
} // namespace esphome
3 changes: 1 addition & 2 deletions components/secplus_gdo/light/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,4 @@ async def to_code(config):
await cg.register_component(var, config)
await light.register_light(var, config)
parent = await cg.get_variable(config[CONF_SECPLUS_GDO_ID])
text = "std::bind(&" + str(GDOLight) + "::set_state," + str(config[CONF_OUTPUT_ID]) + ",std::placeholders::_1)"
cg.add(parent.register_light(cg.RawExpression(text)))
cg.add(parent.register_light(var))
17 changes: 17 additions & 0 deletions components/secplus_gdo/light/gdo_light.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ class GDOLight : public binary::BinaryLightOutput, public Component {
void setup_state(light::LightState *state) override { this->state_ = state; }

void write_state(light::LightState *state) override {
if (!this->synced_) {
return;
}

bool binary;
state->current_values_as_binary(&binary);
if (binary)
Expand All @@ -38,14 +42,27 @@ class GDOLight : public binary::BinaryLightOutput, public Component {
}

void set_state(gdo_light_state_t state) {
if (state == this->light_state_) {
return;
}

this->light_state_ = state;
ESP_LOGI(TAG, "Light state: %s", gdo_light_state_to_string(state));
bool is_on = state == GDO_LIGHT_STATE_ON;
this->state_->current_values.set_state(is_on);
this->state_->remote_values.set_state(is_on);
this->state_->publish_state();
}

void set_sync_state(bool synced) {
this->synced_ = synced;
}

private:
light::LightState *state_{nullptr};
gdo_light_state_t light_state_{GDO_LIGHT_STATE_MAX};
static constexpr auto TAG{"GDOLight"};
bool synced_{false};
}; // GDOLight
} // namespace secplus_gdo
} // namespace esphome
3 changes: 1 addition & 2 deletions components/secplus_gdo/lock/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,4 @@ async def to_code(config):
await lock.register_lock(var, config)
await cg.register_component(var, config)
parent = await cg.get_variable(config[CONF_SECPLUS_GDO_ID])
text = "std::bind(&" + str(GDOLock) + "::set_state," + str(config[CONF_ID]) + ",std::placeholders::_1)"
cg.add(parent.register_lock(cg.RawExpression(text)))
cg.add(parent.register_lock(var))
30 changes: 18 additions & 12 deletions components/secplus_gdo/lock/gdo_lock.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,33 +27,39 @@ namespace secplus_gdo {
class GDOLock : public lock::Lock, public Component {
public:
void set_state(gdo_lock_state_t state) {
if (state == GDO_LOCK_STATE_LOCKED && this->state == lock::LockState::LOCK_STATE_LOCKED) {
return;
}
if (state == GDO_LOCK_STATE_UNLOCKED && this->state == lock::LockState::LOCK_STATE_UNLOCKED) {
if (state == this->lock_state_) {
return;
}

auto call = this->make_call();
if (state == GDO_LOCK_STATE_LOCKED) {
call.set_state(lock::LockState::LOCK_STATE_LOCKED);
} else if (state == GDO_LOCK_STATE_UNLOCKED) {
call.set_state(lock::LockState::LOCK_STATE_UNLOCKED);
}
this->control(call);
this->lock_state_ = state;
ESP_LOGI(TAG, "Lock state: %s", gdo_lock_state_to_string(state));
this->publish_state(state == GDO_LOCK_STATE_LOCKED ?
lock::LockState::LOCK_STATE_LOCKED :
lock::LockState::LOCK_STATE_UNLOCKED);
}

void control(const lock::LockCall& call) override {
if (!this->synced_) {
return;
}

auto state = *call.get_state();

if (state == lock::LockState::LOCK_STATE_LOCKED) {
gdo_lock();
} else if (state == lock::LockState::LOCK_STATE_UNLOCKED) {
gdo_unlock();
}
}

this->publish_state(state);
void set_sync_state(bool synced) {
this->synced_ = synced;
}

private:
gdo_lock_state_t lock_state_{GDO_LOCK_STATE_MAX};
bool synced_{false};
static constexpr const char* TAG = "GDOLock";
};

} // namespace secplus_gdo
Expand Down
33 changes: 25 additions & 8 deletions components/secplus_gdo/secplus_gdo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,11 @@ namespace secplus_gdo {
ESP_LOGI(TAG, "Synced: %s, protocol: %s", status->synced ? "true" : "false", gdo_protocol_type_to_string(status->protocol));
if (status->protocol == GDO_PROTOCOL_SEC_PLUS_V2) {
ESP_LOGI(TAG, "Client ID: %" PRIu32 ", Rolling code: %" PRIu32, status->client_id, status->rolling_code);
gdo->set_client_id(status->client_id);
gdo->set_rolling_code(status->rolling_code);
if (status->synced) {
// Save the last successful ClientID rolling code value to NVS for use on reboot
gdo->set_client_id(status->client_id);
gdo->set_rolling_code(status->rolling_code);
}
}

if (!status->synced) {
Expand All @@ -47,28 +50,24 @@ namespace secplus_gdo {
gdo->set_protocol_state(status->protocol);
}

gdo->set_sync_state(status->synced);
break;
case GDO_CB_EVENT_LIGHT:
ESP_LOGI(TAG, "Light: %s", gdo_light_state_to_string(status->light));
gdo->set_light_state(status->light);
break;
case GDO_CB_EVENT_LOCK:
ESP_LOGI(TAG, "Lock: %s", gdo_lock_state_to_string(status->lock));
gdo->set_lock_state(status->lock);
break;
case GDO_CB_EVENT_DOOR_POSITION: {
float position = (float)(10000 - status->door_position)/10000.0f;
float target = (float)(10000 - status->door_target)/10000.0f;
ESP_LOGI(TAG, "Door: %s, %.0f%%, target: %.0f%%", gdo_door_state_to_string(status->door),
position*100, target*100);
gdo->set_door_state(status->door, position);
if (status->door != GDO_DOOR_STATE_OPENING && status->door != GDO_DOOR_STATE_CLOSING) {
gdo->set_motor_state(GDO_MOTOR_STATE_OFF);
}
break;
}
case GDO_CB_EVENT_LEARN:
ESP_LOGI(TAG, "Learn: %s", gdo_learn_state_to_string(status->learn));
//ESP_LOGI(TAG, "Learn: %s", gdo_learn_state_to_string(status->learn));
break;
case GDO_CB_EVENT_OBSTRUCTION:
ESP_LOGI(TAG, "Obstruction: %s", gdo_obstruction_state_to_string(status->obstruction));
Expand Down Expand Up @@ -153,5 +152,23 @@ namespace secplus_gdo {
ESP_LOGCONFIG(TAG, "Setting up secplus GDO ...");
}

void GDOComponent::set_sync_state(bool synced) {
if (this->door_) {
this->door_->set_sync_state(synced);
}

if (this->light_) {
this->light_->set_sync_state(synced);
}

if (this->lock_) {
this->lock_->set_sync_state(synced);
}

if (this->f_sync) {
this->f_sync(synced);
}
}

} // namespace secplus_gdo
} // namespace esphome
19 changes: 13 additions & 6 deletions components/secplus_gdo/secplus_gdo.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#include "select/gdo_select.h"
#include "switch/gdo_switch.h"
#include "cover/gdo_door.h"
#include "light/gdo_light.h"
#include "lock/gdo_lock.h"
#include "gdo.h"

namespace esphome {
Expand Down Expand Up @@ -57,17 +59,19 @@ namespace secplus_gdo {
void register_motor(std::function<void(bool)> f) { f_motor = f; }
void set_motor_state(gdo_motor_state_t state) { if (f_motor) { f_motor(state == GDO_MOTOR_STATE_ON); } }

void register_sync(std::function<void(bool)> f) { f_sync = f; }

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(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_light(GDOLight *light) { this->light_ = light; }
void set_light_state(gdo_light_state_t state) { if (this->light_) { this->light_->set_state(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_lock(GDOLock *lock) { this->lock_ = lock; }
void set_lock_state(gdo_lock_state_t state) { if (this->lock_) { this->lock_->set_state(state); } }

void register_learn(GDOSwitch *sw) { this->learn_switch_ = sw; }
void set_learn_state(gdo_learn_state_t state) { if (this->learn_switch_) {
Expand All @@ -88,16 +92,19 @@ namespace secplus_gdo {

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

void set_sync_state(bool synced);

protected:
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_sync{nullptr};
GDODoor* door_{nullptr};
GDOLight* light_{nullptr};
GDOLock* lock_{nullptr};
GDONumber* open_duration_{nullptr};
GDONumber* close_duration_{nullptr};
GDONumber* client_id_{nullptr};
Expand Down
5 changes: 3 additions & 2 deletions garage-door-GDOv2-Q.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ substitutions:
name: konnected
friendly_name: GDO blaQ
project_name: konnected.garage-door-gdov2-q
project_version: "1.2.5"
project_version: "1.3.0"
garage_door_cover_name: Garage Door
garage_light_name: Garage Light
garage_openings_name: Garage Openings
Expand All @@ -66,6 +66,7 @@ substitutions:
garage_obstruction_name: Obstruction
garage_motor_name: Motor
garage_button_name: Wall Button
garage_sync_name: Synced


####
Expand Down Expand Up @@ -185,6 +186,6 @@ web_server:
esphome:
platformio_options:
lib_deps:
- https://github.com/konnected-io/gdolib#4e6f493
- https://github.com/konnected-io/gdolib#76ba232
build_flags:
- -DUART_SCLK_DEFAULT=UART_SCLK_APB
6 changes: 6 additions & 0 deletions packages/secplus-gdo.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ binary_sensor:
id: gdo_button
secplus_gdo_id: gdo_blaq
type: button
- platform: secplus_gdo
name: $garage_sync_name
id: gdo_synced
secplus_gdo_id: gdo_blaq
type: sync
device_class: connectivity

switch:
- platform: secplus_gdo
Expand Down
Loading