Skip to content

Commit

Permalink
Merge pull request #68 from konnected-io/dev
Browse files Browse the repository at this point in the history
GDO blaQ command parsing, reliability, sync and logging improvements
  • Loading branch information
heythisisnate authored Jul 9, 2024
2 parents c871e4a + 74baea4 commit f8af4c7
Show file tree
Hide file tree
Showing 11 changed files with 101 additions and 32 deletions.
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

0 comments on commit f8af4c7

Please sign in to comment.