Refactor children state update mechanism (#24)

Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
Marius Muja 2023-07-01 07:13:38 -07:00 committed by GitHub
parent 8df1b9c0cb
commit eee27761b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 270 additions and 341 deletions

View File

@ -4,6 +4,7 @@ external_components:
- source: - source:
type: git type: git
url: https://github.com/esphome-ratgdo/esphome-ratgdo url: https://github.com/esphome-ratgdo/esphome-ratgdo
ref: observer_callbacks
refresh: 1s refresh: 1s
preferences: preferences:

View File

@ -54,7 +54,7 @@ RATGDO_CLIENT_SCHMEA = cv.Schema(
async def register_ratgdo_child(var, config): async def register_ratgdo_child(var, config):
parent = await cg.get_variable(config[CONF_RATGDO_ID]) parent = await cg.get_variable(config[CONF_RATGDO_ID])
cg.add(parent.register_child(var)) cg.add(var.set_parent(parent))
async def to_code(config): async def to_code(config):

View File

@ -11,6 +11,24 @@ namespace ratgdo {
{ {
if (this->binary_sensor_type_ == SensorType::RATGDO_SENSOR_MOTION || this->binary_sensor_type_ == SensorType::RATGDO_SENSOR_OBSTRUCTION || this->binary_sensor_type_ == SensorType::RATGDO_SENSOR_BUTTON) if (this->binary_sensor_type_ == SensorType::RATGDO_SENSOR_MOTION || this->binary_sensor_type_ == SensorType::RATGDO_SENSOR_OBSTRUCTION || this->binary_sensor_type_ == SensorType::RATGDO_SENSOR_BUTTON)
this->publish_state(false); this->publish_state(false);
if (this->binary_sensor_type_ == SensorType::RATGDO_SENSOR_MOTION) {
this->parent_->subscribe_motion_state([=](MotionState state) {
this->publish_state(state == MotionState::MOTION_STATE_DETECTED);
});
} else if (this->binary_sensor_type_ == SensorType::RATGDO_SENSOR_OBSTRUCTION) {
this->parent_->subscribe_obstruction_state([=](ObstructionState state) {
this->publish_state(state == ObstructionState::OBSTRUCTION_STATE_OBSTRUCTED);
});
} else if (this->binary_sensor_type_ == SensorType::RATGDO_SENSOR_MOTOR) {
this->parent_->subscribe_motor_state([=](MotorState state) {
this->publish_state(state == MotorState::MOTOR_STATE_ON);
});
} else if (this->binary_sensor_type_ == SensorType::RATGDO_SENSOR_BUTTON) {
this->parent_->subscribe_button_state([=](ButtonState state) {
this->publish_state(state == ButtonState::BUTTON_STATE_PRESSED);
});
}
} }
void RATGDOBinarySensor::dump_config() void RATGDOBinarySensor::dump_config()
@ -26,30 +44,6 @@ namespace ratgdo {
ESP_LOGCONFIG(TAG, " Type: Button"); ESP_LOGCONFIG(TAG, " Type: Button");
} }
} }
void RATGDOBinarySensor::on_motion_state(MotionState state)
{
if (this->binary_sensor_type_ != SensorType::RATGDO_SENSOR_MOTION)
return;
this->publish_state(state == MotionState::MOTION_STATE_DETECTED);
}
void RATGDOBinarySensor::on_obstruction_state(ObstructionState state)
{
if (this->binary_sensor_type_ != SensorType::RATGDO_SENSOR_OBSTRUCTION)
return;
this->publish_state(state == ObstructionState::OBSTRUCTION_STATE_OBSTRUCTED);
}
void RATGDOBinarySensor::on_motor_state(MotorState state)
{
if (this->binary_sensor_type_ != SensorType::RATGDO_SENSOR_MOTOR)
return;
this->publish_state(state == MotorState::MOTOR_STATE_ON);
}
void RATGDOBinarySensor::on_button_state(ButtonState state)
{
if (this->binary_sensor_type_ != SensorType::RATGDO_SENSOR_BUTTON)
return;
this->publish_state(state == ButtonState::BUTTON_STATE_PRESSED);
}
} // namespace ratgdo } // namespace ratgdo
} // namespace esphome } // namespace esphome

View File

@ -1,7 +1,6 @@
#pragma once #pragma once
#include "../ratgdo.h" #include "../ratgdo.h"
#include "../ratgdo_child.h"
#include "../ratgdo_state.h" #include "../ratgdo_state.h"
#include "esphome/components/binary_sensor/binary_sensor.h" #include "esphome/components/binary_sensor/binary_sensor.h"
#include "esphome/core/component.h" #include "esphome/core/component.h"
@ -22,11 +21,6 @@ namespace ratgdo {
void dump_config() override; void dump_config() override;
void set_binary_sensor_type(SensorType binary_sensor_type_) { this->binary_sensor_type_ = binary_sensor_type_; } void set_binary_sensor_type(SensorType binary_sensor_type_) { this->binary_sensor_type_ = binary_sensor_type_; }
void on_motion_state(MotionState state) override;
void on_obstruction_state(ObstructionState state) override;
void on_motor_state(MotorState state) override;
void on_button_state(ButtonState state) override;
protected: protected:
SensorType binary_sensor_type_; SensorType binary_sensor_type_;
}; };

View File

@ -13,6 +13,14 @@ namespace ratgdo {
{ {
LOG_COVER("", "RATGDO Cover", this); LOG_COVER("", "RATGDO Cover", this);
} }
void RATGDOCover::setup()
{
this->parent_->subscribe_door_state([=](DoorState state, float position) {
this->on_door_state(state, position);
});
}
void RATGDOCover::on_door_state(DoorState state, float position) void RATGDOCover::on_door_state(DoorState state, float position)
{ {
switch (state) { switch (state) {

View File

@ -1,7 +1,6 @@
#pragma once #pragma once
#include "../ratgdo.h" #include "../ratgdo.h"
#include "../ratgdo_child.h"
#include "../ratgdo_state.h" #include "../ratgdo_state.h"
#include "esphome/components/cover/cover.h" #include "esphome/components/cover/cover.h"
#include "esphome/core/component.h" #include "esphome/core/component.h"
@ -12,8 +11,10 @@ namespace ratgdo {
class RATGDOCover : public cover::Cover, public RATGDOClient, public Component { class RATGDOCover : public cover::Cover, public RATGDOClient, public Component {
public: public:
void dump_config() override; void dump_config() override;
void setup() override;
cover::CoverTraits get_traits() override; cover::CoverTraits get_traits() override;
void on_door_state(DoorState state, float position) override; void on_door_state(DoorState state, float position);
protected: protected:
void control(const cover::CoverCall& call) override; void control(const cover::CoverCall& call) override;

View File

@ -13,6 +13,14 @@ namespace ratgdo {
{ {
ESP_LOGCONFIG("", "RATGDO Light"); ESP_LOGCONFIG("", "RATGDO Light");
} }
void RATGDOLightOutput::setup()
{
this->parent_->subscribe_light_state([=](LightState s) {
this->on_light_state(s);
});
}
void RATGDOLightOutput::on_light_state(esphome::ratgdo::LightState state) void RATGDOLightOutput::on_light_state(esphome::ratgdo::LightState state)
{ {
if (this->light_state_) { if (this->light_state_) {

View File

@ -1,7 +1,6 @@
#pragma once #pragma once
#include "../ratgdo.h" #include "../ratgdo.h"
#include "../ratgdo_child.h"
#include "../ratgdo_state.h" #include "../ratgdo_state.h"
#include "esphome/components/light/light_output.h" #include "esphome/components/light/light_output.h"
#include "esphome/core/component.h" #include "esphome/core/component.h"
@ -12,13 +11,14 @@ namespace ratgdo {
class RATGDOLightOutput : public light::LightOutput, public RATGDOClient, public Component { class RATGDOLightOutput : public light::LightOutput, public RATGDOClient, public Component {
public: public:
void dump_config() override; void dump_config() override;
void setup() override;
light::LightTraits get_traits() override; light::LightTraits get_traits() override;
void write_state(light::LightState* state) override; void write_state(light::LightState* state) override;
void setup_state(light::LightState* state) override; void setup_state(light::LightState* state) override;
void set_state(esphome::ratgdo::LightState state); void set_state(esphome::ratgdo::LightState state);
light::LightState* get_state() { return this->light_state_; } light::LightState* get_state() { return this->light_state_; }
void on_light_state(esphome::ratgdo::LightState state) override; void on_light_state(esphome::ratgdo::LightState state);
protected: protected:
light::LightState* light_state_; light::LightState* light_state_;

View File

@ -19,6 +19,23 @@ namespace ratgdo {
} }
} }
void RATGDONumber::setup()
{
if (this->number_type_ == RATGDO_ROLLING_CODE_COUNTER) {
this->parent_->subscribe_rolling_code_counter([=](uint32_t value) {
this->publish_state(value);
});
} else if (this->number_type_ == RATGDO_OPENING_DURATION) {
this->parent_->subscribe_opening_duration([=](float value) {
this->publish_state(value);
});
} else if (this->number_type_ == RATGDO_CLOSING_DURATION) {
this->parent_->subscribe_closing_duration([=](float value) {
this->publish_state(value);
});
}
}
void RATGDONumber::set_number_type(NumberType number_type_) void RATGDONumber::set_number_type(NumberType number_type_)
{ {
this->number_type_ = number_type_; this->number_type_ = number_type_;
@ -27,30 +44,6 @@ namespace ratgdo {
} }
} }
void RATGDONumber::on_rolling_code_change(uint32_t rollingCodeCounter)
{
if (this->number_type_ != RATGDO_ROLLING_CODE_COUNTER) {
return;
}
this->publish_state(rollingCodeCounter);
}
void RATGDONumber::on_opening_duration_change(float duration)
{
if (this->number_type_ != RATGDO_OPENING_DURATION) {
return;
}
this->publish_state(duration);
}
void RATGDONumber::on_closing_duration_change(float duration)
{
if (this->number_type_ != RATGDO_CLOSING_DURATION) {
return;
}
this->publish_state(duration);
}
void RATGDONumber::control(float value) void RATGDONumber::control(float value)
{ {
if (this->number_type_ == RATGDO_ROLLING_CODE_COUNTER) { if (this->number_type_ == RATGDO_ROLLING_CODE_COUNTER) {

View File

@ -1,7 +1,6 @@
#pragma once #pragma once
#include "../ratgdo.h" #include "../ratgdo.h"
#include "../ratgdo_child.h"
#include "../ratgdo_state.h" #include "../ratgdo_state.h"
#include "esphome/components/number/number.h" #include "esphome/components/number/number.h"
#include "esphome/core/component.h" #include "esphome/core/component.h"
@ -18,12 +17,9 @@ namespace ratgdo {
class RATGDONumber : public number::Number, public RATGDOClient, public Component { class RATGDONumber : public number::Number, public RATGDOClient, public Component {
public: public:
void dump_config() override; void dump_config() override;
void setup() override;
void set_number_type(NumberType number_type_); void set_number_type(NumberType number_type_);
void on_rolling_code_change(uint32_t rollingCodeCounter) override;
void on_opening_duration_change(float duration) override;
void on_closing_duration_change(float duration) override;
void control(float value) override; void control(float value) override;
protected: protected:

View File

@ -0,0 +1,46 @@
#pragma once
namespace esphome {
namespace ratgdo {
template <typename T>
class observable {
public:
observable(const T& value)
: value_(value)
{
}
template <typename U>
observable& operator=(U value)
{
if (value != this->value_) {
this->value_ = value;
this->notify();
}
return *this;
}
T const* operator&() const { return &this->value_; }
T const& operator*() const { return this->value_; }
template <typename Observer>
void subscribe(Observer&& observer)
{
this->observers_.push_back(std::forward<Observer>(observer));
}
void notify() const
{
for (const auto& observer : this->observers_) {
observer(this->value_);
}
}
private:
T value_;
std::vector<std::function<void(T)>> observers_;
};
} // namespace ratgdo
} // namespace esphome

View File

@ -12,7 +12,6 @@
************************************/ ************************************/
#include "ratgdo.h" #include "ratgdo.h"
#include "ratgdo_child.h"
#include "ratgdo_state.h" #include "ratgdo_state.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
@ -46,22 +45,23 @@ namespace ratgdo {
void RATGDOComponent::setup() void RATGDOComponent::setup()
{ {
this->rollingCodePref_ = global_preferences->make_preference<int>(734874333U); this->rollingCodePref_ = global_preferences->make_preference<int>(734874333U);
if (!this->rollingCodePref_.load(&this->rollingCodeCounter)) { uint32_t rolling_code_counter = 0;
this->rollingCodeCounter = 0; this->rollingCodePref_.load(&rolling_code_counter);
} this->rollingCodeCounter = rolling_code_counter;
// observers are subscribed in the setup() of children defer notify until after setup()
defer([=] { this->rollingCodeCounter.notify(); });
this->openingDurationPref_ = global_preferences->make_preference<float>(734874334U); this->openingDurationPref_ = global_preferences->make_preference<float>(734874334U);
if (!this->openingDurationPref_.load(&this->openingDuration)) { float opening_duration = 0;
this->setOpeningDuration(0); this->openingDurationPref_.load(&opening_duration);
} else { this->setOpeningDuration(opening_duration);
this->sendOpeningDuration(); defer([=] { this->openingDuration.notify(); });
}
this->closingDurationPref_ = global_preferences->make_preference<float>(734874335U); this->closingDurationPref_ = global_preferences->make_preference<float>(734874335U);
if (!this->closingDurationPref_.load(&this->closingDuration)) { float closing_duration = 0;
this->setClosingDuration(0.f); this->closingDurationPref_.load(&closing_duration);
} else { this->setClosingDuration(closing_duration);
this->sendClosingDuration(); defer([=] { this->closingDuration.notify(); });
}
this->output_gdo_pin_->setup(); this->output_gdo_pin_->setup();
this->input_gdo_pin_->setup(); this->input_gdo_pin_->setup();
@ -87,7 +87,6 @@ namespace ratgdo {
{ {
obstructionLoop(); obstructionLoop();
gdoStateLoop(); gdoStateLoop();
statusUpdateLoop();
} }
void RATGDOComponent::dump_config() void RATGDOComponent::dump_config()
@ -96,7 +95,7 @@ namespace ratgdo {
LOG_PIN(" Output GDO Pin: ", this->output_gdo_pin_); LOG_PIN(" Output GDO Pin: ", this->output_gdo_pin_);
LOG_PIN(" Input GDO Pin: ", this->input_gdo_pin_); LOG_PIN(" Input GDO Pin: ", this->input_gdo_pin_);
LOG_PIN(" Input Obstruction Pin: ", this->input_obst_pin_); LOG_PIN(" Input Obstruction Pin: ", this->input_obst_pin_);
ESP_LOGCONFIG(TAG, " Rolling Code Counter: %d", this->rollingCodeCounter); ESP_LOGCONFIG(TAG, " Rolling Code Counter: %d", *this->rollingCodeCounter);
ESP_LOGCONFIG(TAG, " Remote ID: %d", this->remote_id); ESP_LOGCONFIG(TAG, " Remote ID: %d", this->remote_id);
} }
@ -183,53 +182,53 @@ namespace ratgdo {
if (cmd == command::STATUS) { if (cmd == command::STATUS) {
this->doorState = static_cast<DoorState>(nibble); auto doorState = static_cast<DoorState>(nibble);
if (this->doorState == DoorState::DOOR_STATE_OPENING && this->previousDoorState == DoorState::DOOR_STATE_CLOSED) { if (doorState == DoorState::DOOR_STATE_OPENING && *this->doorState == DoorState::DOOR_STATE_CLOSED) {
this->startOpening = millis(); this->startOpening = millis();
} }
if (this->doorState == DoorState::DOOR_STATE_OPEN && this->previousDoorState == DoorState::DOOR_STATE_OPENING) { if (doorState == DoorState::DOOR_STATE_OPEN && *this->doorState == DoorState::DOOR_STATE_OPENING) {
if (this->startOpening > 0) { if (this->startOpening > 0) {
auto duration = (millis() - this->startOpening) / 1000; auto duration = (millis() - this->startOpening) / 1000;
duration = this->openingDuration > 0 ? (duration + this->openingDuration) / 2 : duration; duration = *this->openingDuration > 0 ? (duration + *this->openingDuration) / 2 : duration;
this->setOpeningDuration(round(duration * 10) / 10); this->setOpeningDuration(round(duration * 10) / 10);
} }
} }
if (this->doorState == DoorState::DOOR_STATE_CLOSING && this->previousDoorState == DoorState::DOOR_STATE_OPEN) { if (doorState == DoorState::DOOR_STATE_CLOSING && *this->doorState == DoorState::DOOR_STATE_OPEN) {
this->startClosing = millis(); this->startClosing = millis();
} }
if (this->doorState == DoorState::DOOR_STATE_CLOSED && this->previousDoorState == DoorState::DOOR_STATE_CLOSING) { if (doorState == DoorState::DOOR_STATE_CLOSED && *this->doorState == DoorState::DOOR_STATE_CLOSING) {
if (this->startClosing > 0) { if (this->startClosing > 0) {
auto duration = (millis() - this->startClosing) / 1000; auto duration = (millis() - this->startClosing) / 1000;
duration = this->closingDuration > 0 ? (duration + this->closingDuration) / 2 : duration; duration = *this->closingDuration > 0 ? (duration + *this->closingDuration) / 2 : duration;
this->setClosingDuration(round(duration * 10) / 10); this->setClosingDuration(round(duration * 10) / 10);
} }
} }
if (this->doorState == DoorState::DOOR_STATE_STOPPED) { if (doorState == DoorState::DOOR_STATE_STOPPED) {
this->startOpening = -1; this->startOpening = -1;
this->startClosing = -1; this->startClosing = -1;
} }
if (this->doorState == DoorState::DOOR_STATE_OPEN) { if (doorState == DoorState::DOOR_STATE_OPEN) {
this->doorPosition = 1.0; this->doorPosition = 1.0;
} else if (this->doorState == DoorState::DOOR_STATE_CLOSED) { } else if (doorState == DoorState::DOOR_STATE_CLOSED) {
this->doorPosition = 0.0; this->doorPosition = 0.0;
} else { } else {
if (this->closingDuration == 0 || this->openingDuration == 0 || this->doorPosition == DOOR_POSITION_UNKNOWN) { if (*this->closingDuration == 0 || *this->openingDuration == 0 || *this->doorPosition == DOOR_POSITION_UNKNOWN) {
this->doorPosition = 0.5; // best guess this->doorPosition = 0.5; // best guess
} }
} }
if (this->doorState == DoorState::DOOR_STATE_OPENING && !this->movingToPosition) { if (doorState == DoorState::DOOR_STATE_OPENING && !this->movingToPosition) {
this->positionSyncWhileOpening(1.0 - this->doorPosition); this->positionSyncWhileOpening(1.0 - *this->doorPosition);
this->movingToPosition = true; this->movingToPosition = true;
} }
if (this->doorState == DoorState::DOOR_STATE_CLOSING && !this->movingToPosition) { if (doorState == DoorState::DOOR_STATE_CLOSING && !this->movingToPosition) {
this->positionSyncWhileClosing(this->doorPosition); this->positionSyncWhileClosing(*this->doorPosition);
this->movingToPosition = true; this->movingToPosition = true;
} }
if (this->doorState == DoorState::DOOR_STATE_OPEN || this->doorState == DoorState::DOOR_STATE_CLOSED || this->doorState == DoorState::DOOR_STATE_STOPPED) { if (doorState == DoorState::DOOR_STATE_OPEN || doorState == DoorState::DOOR_STATE_CLOSED || doorState == DoorState::DOOR_STATE_STOPPED) {
this->cancelPositionSyncCallbacks(); this->cancelPositionSyncCallbacks();
} }
@ -239,41 +238,43 @@ namespace ratgdo {
this->motorState = MotorState::MOTOR_STATE_OFF; // when the status message is read, reset motor state to 0|off this->motorState = MotorState::MOTOR_STATE_OFF; // when the status message is read, reset motor state to 0|off
// this->obstructionState = static_cast<ObstructionState>((byte1 >> 6) & 1); // this->obstructionState = static_cast<ObstructionState>((byte1 >> 6) & 1);
if (this->doorState == DoorState::DOOR_STATE_CLOSED && this->doorState != this->previousDoorState) { if (doorState == DoorState::DOOR_STATE_CLOSED && doorState != *this->doorState) {
transmit(command::GET_OPENINGS); transmit(command::GET_OPENINGS);
} }
this->doorState = doorState;
ESP_LOGD(TAG, "Status: door=%s light=%s lock=%s", ESP_LOGD(TAG, "Status: door=%s light=%s lock=%s",
door_state_to_string(this->doorState), door_state_to_string(*this->doorState),
light_state_to_string(this->lightState), light_state_to_string(*this->lightState),
lock_state_to_string(this->lockState)); lock_state_to_string(*this->lockState));
} else if (cmd == command::LIGHT) { } else if (cmd == command::LIGHT) {
if (nibble == 0) { if (nibble == 0) {
this->lightState = LightState::LIGHT_STATE_OFF; this->lightState = LightState::LIGHT_STATE_OFF;
} else if (nibble == 1) { } else if (nibble == 1) {
this->lightState = LightState::LIGHT_STATE_ON; this->lightState = LightState::LIGHT_STATE_ON;
} else if (nibble == 2) { // toggle } else if (nibble == 2) { // toggle
this->lightState = light_state_toggle(this->lightState); this->lightState = light_state_toggle(*this->lightState);
} }
ESP_LOGD(TAG, "Light: action=%s state=%s", ESP_LOGD(TAG, "Light: action=%s state=%s",
nibble == 0 ? "OFF" : nibble == 1 ? "ON" nibble == 0 ? "OFF" : nibble == 1 ? "ON"
: "TOGGLE", : "TOGGLE",
light_state_to_string(this->lightState)); light_state_to_string(*this->lightState));
} else if (cmd == command::MOTOR_ON) { } else if (cmd == command::MOTOR_ON) {
this->motorState = MotorState::MOTOR_STATE_ON; this->motorState = MotorState::MOTOR_STATE_ON;
ESP_LOGD(TAG, "Motor: state=%s", motor_state_to_string(this->motorState)); ESP_LOGD(TAG, "Motor: state=%s", motor_state_to_string(*this->motorState));
} else if (cmd == command::OPEN) { } else if (cmd == command::OPEN) {
this->buttonState = (byte1 & 1) == 1 ? ButtonState::BUTTON_STATE_PRESSED : ButtonState::BUTTON_STATE_RELEASED; this->buttonState = (byte1 & 1) == 1 ? ButtonState::BUTTON_STATE_PRESSED : ButtonState::BUTTON_STATE_RELEASED;
ESP_LOGD(TAG, "Open: button=%s", button_state_to_string(this->buttonState)); ESP_LOGD(TAG, "Open: button=%s", button_state_to_string(*this->buttonState));
} else if (cmd == command::OPENINGS) { } else if (cmd == command::OPENINGS) {
this->openings = (byte1 << 8) | byte2; this->openings = (byte1 << 8) | byte2;
ESP_LOGD(TAG, "Openings: %d", this->openings); ESP_LOGD(TAG, "Openings: %d", *this->openings);
} else if (cmd == command::MOTION) { } else if (cmd == command::MOTION) {
this->motionState = MotionState::MOTION_STATE_DETECTED; this->motionState = MotionState::MOTION_STATE_DETECTED;
if (this->lightState == LightState::LIGHT_STATE_OFF) { if (*this->lightState == LightState::LIGHT_STATE_OFF) {
transmit(command::GET_STATUS); transmit(command::GET_STATUS);
} }
ESP_LOGD(TAG, "Motion: %s", motion_state_to_string(this->motionState)); ESP_LOGD(TAG, "Motion: %s", motion_state_to_string(*this->motionState));
} else { } else {
ESP_LOGD(TAG, "Unhandled command: cmd=%03x nibble=%02x byte1=%02x byte2=%02x fixed=%010" PRIx64 " data=%08" PRIx32, cmd, nibble, byte1, byte2, fixed, data); ESP_LOGD(TAG, "Unhandled command: cmd=%03x nibble=%02x byte1=%02x byte2=%02x fixed=%010" PRIx64 " data=%08" PRIx32, cmd, nibble, byte1, byte2, fixed, data);
} }
@ -285,8 +286,8 @@ namespace ratgdo {
uint64_t fixed = ((command & ~0xff) << 24) | this->remote_id; uint64_t fixed = ((command & ~0xff) << 24) | this->remote_id;
uint32_t send_data = (data << 8) | (command & 0xff); uint32_t send_data = (data << 8) | (command & 0xff);
ESP_LOGD(TAG, "[%ld] Encode for transmit rolling=%07" PRIx32 " fixed=%010" PRIx64 " data=%08" PRIx32, millis(), this->rollingCodeCounter, fixed, send_data); ESP_LOGD(TAG, "[%ld] Encode for transmit rolling=%07" PRIx32 " fixed=%010" PRIx64 " data=%08" PRIx32, millis(), *this->rollingCodeCounter, fixed, send_data);
encode_wireline(this->rollingCodeCounter, fixed, send_data, this->txRollingCode); encode_wireline(*this->rollingCodeCounter, fixed, send_data, this->txRollingCode);
printRollingCode(); printRollingCode();
if (increment) { if (increment) {
@ -300,68 +301,38 @@ namespace ratgdo {
this->openingDuration = duration; this->openingDuration = duration;
this->openingDurationPref_.save(&this->openingDuration); this->openingDurationPref_.save(&this->openingDuration);
sendOpeningDuration(); if (*this->closingDuration == 0 && duration != 0) {
if (this->closingDuration == 0 && duration != 0) {
this->setClosingDuration(duration); this->setClosingDuration(duration);
} }
} }
void RATGDOComponent::sendOpeningDuration()
{
for (auto* child : this->children_) {
child->on_opening_duration_change(this->openingDuration);
}
}
void RATGDOComponent::setClosingDuration(float duration) void RATGDOComponent::setClosingDuration(float duration)
{ {
ESP_LOGD(TAG, "Set closing duration: %.1fs", duration); ESP_LOGD(TAG, "Set closing duration: %.1fs", duration);
this->closingDuration = duration; this->closingDuration = duration;
this->closingDurationPref_.save(&this->closingDuration); this->closingDurationPref_.save(&this->closingDuration);
sendClosingDuration(); if (*this->openingDuration == 0 && duration != 0) {
if (this->openingDuration == 0 && duration != 0) {
this->setOpeningDuration(duration); this->setOpeningDuration(duration);
} }
} }
void RATGDOComponent::sendClosingDuration()
{
for (auto* child : this->children_) {
child->on_closing_duration_change(this->closingDuration);
}
}
void RATGDOComponent::setRollingCodeCounter(uint32_t counter) void RATGDOComponent::setRollingCodeCounter(uint32_t counter)
{ {
ESP_LOGV(TAG, "Set rolling code counter to %d", counter); ESP_LOGV(TAG, "Set rolling code counter to %d", counter);
this->rollingCodeCounter = counter; this->rollingCodeCounter = counter;
this->rollingCodePref_.save(&this->rollingCodeCounter); this->rollingCodePref_.save(&this->rollingCodeCounter);
sendRollingCodeChanged();
} }
void RATGDOComponent::incrementRollingCodeCounter(int delta) void RATGDOComponent::incrementRollingCodeCounter(int delta)
{ {
this->rollingCodeCounter = (this->rollingCodeCounter + delta) & 0xfffffff; this->rollingCodeCounter = (*this->rollingCodeCounter + delta) & 0xfffffff;
sendRollingCodeChanged();
}
void RATGDOComponent::sendRollingCodeChanged()
{
if (!this->rollingCodeUpdatesEnabled_) {
return;
}
for (auto* child : this->children_) {
child->on_rolling_code_change(this->rollingCodeCounter);
}
} }
void RATGDOComponent::printRollingCode() void RATGDOComponent::printRollingCode()
{ {
ESP_LOGV(TAG, "Counter: %d Send code: [%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X]", ESP_LOGV(TAG, "Counter: %d Send code: [%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X]",
this->rollingCodeCounter, *this->rollingCodeCounter,
this->txRollingCode[0], this->txRollingCode[0],
this->txRollingCode[1], this->txRollingCode[1],
this->txRollingCode[2], this->txRollingCode[2],
@ -455,88 +426,15 @@ namespace ratgdo {
if (byte_count == CODE_LENGTH) { if (byte_count == CODE_LENGTH) {
reading_msg = false; reading_msg = false;
byte_count = 0; byte_count = 0;
if (readRollingCode() == command::STATUS && this->forceUpdate_) { readRollingCode();
this->forceUpdate_ = false;
this->previousDoorState = DoorState::DOOR_STATE_UNKNOWN;
this->previousLightState = LightState::LIGHT_STATE_UNKNOWN;
this->previousLockState = LockState::LOCK_STATE_UNKNOWN;
}
return; return;
} }
} }
} }
} }
void RATGDOComponent::statusUpdateLoop()
{
if (this->doorState != this->previousDoorState) {
ESP_LOGV(TAG, "Door state: %s", door_state_to_string(this->doorState));
for (auto* child : this->children_) {
child->on_door_state(this->doorState, this->doorPosition);
}
this->previousDoorState = this->doorState;
}
if (this->doorPosition != this->previousDoorPosition) {
ESP_LOGV(TAG, "Door position: %f", this->doorPosition);
for (auto* child : this->children_) {
child->on_door_state(this->doorState, this->doorPosition);
}
this->previousDoorPosition = this->doorPosition;
}
if (this->lightState != this->previousLightState) {
ESP_LOGV(TAG, "Light state %s (%d)", light_state_to_string(this->lightState), this->lightState);
for (auto* child : this->children_) {
child->on_light_state(this->lightState);
}
this->previousLightState = this->lightState;
}
if (this->lockState != this->previousLockState) {
ESP_LOGV(TAG, "Lock state %s", lock_state_to_string(this->lockState));
for (auto* child : this->children_) {
child->on_lock_state(this->lockState);
}
this->previousLockState = this->lockState;
}
if (this->obstructionState != this->previousObstructionState) {
ESP_LOGV(TAG, "Obstruction state %s", obstruction_state_to_string(this->obstructionState));
for (auto* child : this->children_) {
child->on_obstruction_state(this->obstructionState);
}
this->previousObstructionState = this->obstructionState;
}
if (this->motorState != this->previousMotorState) {
ESP_LOGV(TAG, "Motor state %s", motor_state_to_string(this->motorState));
for (auto* child : this->children_) {
child->on_motor_state(this->motorState);
}
this->previousMotorState = this->motorState;
}
if (this->motionState != this->previousMotionState) {
ESP_LOGV(TAG, "Motion state %s", motion_state_to_string(this->motionState));
for (auto* child : this->children_) {
child->on_motion_state(this->motionState);
}
this->previousMotionState = this->motionState;
}
if (this->buttonState != this->previousButtonState) {
ESP_LOGV(TAG, "Button state %s", button_state_to_string(this->buttonState));
for (auto* child : this->children_) {
child->on_button_state(this->buttonState);
}
this->previousButtonState = this->buttonState;
}
if (this->openings != this->previousOpenings) {
ESP_LOGV(TAG, "Openings: %d", this->openings);
for (auto* child : this->children_) {
child->on_openings_change(this->openings);
}
this->previousOpenings = this->openings;
}
}
void RATGDOComponent::query_status() void RATGDOComponent::query_status()
{ {
this->forceUpdate_ = true;
transmit(command::GET_STATUS); transmit(command::GET_STATUS);
} }
@ -574,9 +472,9 @@ namespace ratgdo {
this->incrementRollingCodeCounter(MAX_CODES_WITHOUT_FLASH_WRITE); this->incrementRollingCodeCounter(MAX_CODES_WITHOUT_FLASH_WRITE);
set_retry( set_retry(
300, 10, [=](auto r) { 300, 10, [=](uint8_t r) {
if (this->doorState != DoorState::DOOR_STATE_UNKNOWN) { // have status if (*this->doorState != DoorState::DOOR_STATE_UNKNOWN) { // have status
if (this->openings != 0) { // have openings if (*this->openings != 0) { // have openings
return RetryResult::DONE; return RetryResult::DONE;
} else { } else {
transmit(command::GET_OPENINGS); transmit(command::GET_OPENINGS);
@ -592,7 +490,7 @@ namespace ratgdo {
void RATGDOComponent::openDoor() void RATGDOComponent::openDoor()
{ {
if (this->doorState == DoorState::DOOR_STATE_OPENING) { if (*this->doorState == DoorState::DOOR_STATE_OPENING) {
return; // gets ignored by opener return; // gets ignored by opener
} }
this->cancelPositionSyncCallbacks(); this->cancelPositionSyncCallbacks();
@ -602,7 +500,7 @@ namespace ratgdo {
void RATGDOComponent::closeDoor() void RATGDOComponent::closeDoor()
{ {
if (this->doorState == DoorState::DOOR_STATE_CLOSING || this->doorState == DoorState::DOOR_STATE_OPENING) { if (*this->doorState == DoorState::DOOR_STATE_CLOSING || *this->doorState == DoorState::DOOR_STATE_OPENING) {
return; // gets ignored by opener return; // gets ignored by opener
} }
this->cancelPositionSyncCallbacks(); this->cancelPositionSyncCallbacks();
@ -612,7 +510,7 @@ namespace ratgdo {
void RATGDOComponent::stopDoor() void RATGDOComponent::stopDoor()
{ {
if (this->doorState != DoorState::DOOR_STATE_OPENING && this->doorState != DoorState::DOOR_STATE_CLOSING) { if (*this->doorState != DoorState::DOOR_STATE_OPENING && *this->doorState != DoorState::DOOR_STATE_CLOSING) {
ESP_LOGW(TAG, "The door is not moving."); ESP_LOGW(TAG, "The door is not moving.");
return; return;
} }
@ -621,7 +519,7 @@ namespace ratgdo {
void RATGDOComponent::toggleDoor() void RATGDOComponent::toggleDoor()
{ {
if (this->doorState == DoorState::DOOR_STATE_OPENING) { if (*this->doorState == DoorState::DOOR_STATE_OPENING) {
return; // gets ignored by opener return; // gets ignored by opener
} }
this->cancelPositionSyncCallbacks(); this->cancelPositionSyncCallbacks();
@ -631,54 +529,54 @@ namespace ratgdo {
void RATGDOComponent::positionSyncWhileOpening(float delta, float update_period) void RATGDOComponent::positionSyncWhileOpening(float delta, float update_period)
{ {
if (this->openingDuration == 0) { if (*this->openingDuration == 0) {
ESP_LOGW(TAG, "I don't know opening duration, ignoring position sync"); ESP_LOGW(TAG, "I don't know opening duration, ignoring position sync");
return; return;
} }
auto updates = this->openingDuration * 1000 * delta / update_period; auto updates = *this->openingDuration * 1000 * delta / update_period;
auto position_update = delta / updates; auto position_update = delta / updates;
auto count = int(updates); auto count = int(updates);
ESP_LOGD(TAG, "[Opening] Position sync %d times: ", count); ESP_LOGD(TAG, "[Opening] Position sync %d times: ", count);
// try to keep position in sync while door is moving // try to keep position in sync while door is moving
set_retry("position_sync_while_moving", update_period, count, [=](uint8_t r) { set_retry("position_sync_while_moving", update_period, count, [=](uint8_t r) {
ESP_LOGD(TAG, "[Opening] Position sync: %d: ", r); ESP_LOGD(TAG, "[Opening] Position sync: %d: ", r);
this->doorPosition += position_update; this->doorPosition = *this->doorPosition + position_update;
return RetryResult::RETRY; return RetryResult::RETRY;
}); });
} }
void RATGDOComponent::positionSyncWhileClosing(float delta, float update_period) void RATGDOComponent::positionSyncWhileClosing(float delta, float update_period)
{ {
if (this->closingDuration == 0) { if (*this->closingDuration == 0) {
ESP_LOGW(TAG, "I don't know closing duration, ignoring position sync"); ESP_LOGW(TAG, "I don't know closing duration, ignoring position sync");
return; return;
} }
auto updates = this->closingDuration * 1000 * delta / update_period; auto updates = *this->closingDuration * 1000 * delta / update_period;
auto position_update = delta / updates; auto position_update = delta / updates;
auto count = int(updates); auto count = int(updates);
ESP_LOGD(TAG, "[Closing] Position sync %d times: ", count); ESP_LOGD(TAG, "[Closing] Position sync %d times: ", count);
// try to keep position in sync while door is moving // try to keep position in sync while door is moving
set_retry("position_sync_while_moving", update_period, count, [=](uint8_t r) { set_retry("position_sync_while_moving", update_period, count, [=](uint8_t r) {
ESP_LOGD(TAG, "[Closing] Position sync: %d: ", r); ESP_LOGD(TAG, "[Closing] Position sync: %d: ", r);
this->doorPosition -= position_update; this->doorPosition = *this->doorPosition - position_update;
return RetryResult::RETRY; return RetryResult::RETRY;
}); });
} }
void RATGDOComponent::setDoorPosition(float position) void RATGDOComponent::setDoorPosition(float position)
{ {
if (this->doorState == DoorState::DOOR_STATE_OPENING || this->doorState == DoorState::DOOR_STATE_CLOSING) { if (*this->doorState == DoorState::DOOR_STATE_OPENING || *this->doorState == DoorState::DOOR_STATE_CLOSING) {
ESP_LOGW(TAG, "The door is moving, ignoring."); ESP_LOGW(TAG, "The door is moving, ignoring.");
return; return;
} }
auto delta = position - this->doorPosition; auto delta = position - *this->doorPosition;
if (delta == 0) { if (delta == 0) {
ESP_LOGD(TAG, "Door is already at position %.2f", position); ESP_LOGD(TAG, "Door is already at position %.2f", position);
return; return;
} }
auto duration = delta > 0 ? this->openingDuration : this->closingDuration; auto duration = delta > 0 ? *this->openingDuration : *this->closingDuration;
if (duration == 0) { if (duration == 0) {
ESP_LOGW(TAG, "I don't know duration, ignoring move to position"); ESP_LOGW(TAG, "I don't know duration, ignoring move to position");
return; return;
@ -738,7 +636,7 @@ namespace ratgdo {
void RATGDOComponent::toggleLight() void RATGDOComponent::toggleLight()
{ {
this->lightState = light_state_toggle(this->lightState); this->lightState = light_state_toggle(*this->lightState);
transmit(command::LIGHT, data::LIGHT_TOGGLE); transmit(command::LIGHT, data::LIGHT_TOGGLE);
} }
@ -756,7 +654,7 @@ namespace ratgdo {
void RATGDOComponent::toggleLock() void RATGDOComponent::toggleLock()
{ {
this->lockState = lock_state_toggle(this->lockState); this->lockState = lock_state_toggle(*this->lockState);
transmit(command::LOCK, data::LOCK_TOGGLE); transmit(command::LOCK, data::LOCK_TOGGLE);
} }
@ -768,14 +666,61 @@ namespace ratgdo {
// we have configured preferences to write every 5s // we have configured preferences to write every 5s
} }
void RATGDOComponent::register_child(RATGDOClient* obj)
{
this->children_.push_back(obj);
obj->set_parent(this);
}
LightState RATGDOComponent::getLightState() LightState RATGDOComponent::getLightState()
{ {
return this->lightState; return *this->lightState;
}
void RATGDOComponent::subscribe_rolling_code_counter(std::function<void(uint32_t)>&& f)
{
// change update to children is defered until after component loop
// if multiple changes occur during component loop, only the last one is notified
this->rollingCodeCounter.subscribe([=](uint32_t state) { defer("rolling_code_counter", [=] { f(state); }); });
}
void RATGDOComponent::subscribe_opening_duration(std::function<void(float)>&& f)
{
this->openingDuration.subscribe([=](float state) { defer("opening_duration", [=] { f(state); }); });
}
void RATGDOComponent::subscribe_closing_duration(std::function<void(float)>&& f)
{
this->closingDuration.subscribe([=](float state) { defer("closing_duration", [=] { f(state); }); });
}
void RATGDOComponent::subscribe_openings(std::function<void(uint16_t)>&& f)
{
this->openings.subscribe([=](uint16_t state) { defer("openings", [=] { f(state); }); });
}
void RATGDOComponent::subscribe_door_state(std::function<void(DoorState, float)>&& f)
{
this->doorState.subscribe([=](DoorState state) {
defer("door_state", [=] { f(state, *this->doorPosition); });
});
this->doorPosition.subscribe([=](float position) {
defer("door_state", [=] { f(*this->doorState, position); });
});
}
void RATGDOComponent::subscribe_light_state(std::function<void(LightState)>&& f)
{
this->lightState.subscribe([=](LightState state) { defer("light_state", [=] { f(state); }); });
}
void RATGDOComponent::subscribe_lock_state(std::function<void(LockState)>&& f)
{
this->lockState.subscribe([=](LockState state) { defer("lock_state", [=] { f(state); }); });
}
void RATGDOComponent::subscribe_obstruction_state(std::function<void(ObstructionState)>&& f)
{
this->obstructionState.subscribe([=](ObstructionState state) { defer("obstruction_state", [=] { f(state); }); });
}
void RATGDOComponent::subscribe_motor_state(std::function<void(MotorState)>&& f)
{
this->motorState.subscribe([=](MotorState state) { defer("motor_state", [=] { f(state); }); });
}
void RATGDOComponent::subscribe_button_state(std::function<void(ButtonState)>&& f)
{
this->buttonState.subscribe([=](ButtonState state) { defer("button_state", [=] { f(state); }); });
}
void RATGDOComponent::subscribe_motion_state(std::function<void(MotionState)>&& f)
{
this->motionState.subscribe([=](MotionState state) { defer("motion_state", [=] { f(state); }); });
} }
} // namespace ratgdo } // namespace ratgdo

View File

@ -17,19 +17,19 @@
#include "esphome/core/gpio.h" #include "esphome/core/gpio.h"
#include "esphome/core/log.h" #include "esphome/core/log.h"
#include "esphome/core/preferences.h" #include "esphome/core/preferences.h"
#include "observable.h"
extern "C" { extern "C" {
#include "secplus.h" #include "secplus.h"
} }
#include "ratgdo_child.h"
#include "ratgdo_state.h" #include "ratgdo_state.h"
namespace esphome { namespace esphome {
namespace ratgdo { namespace ratgdo {
// Forward declare RATGDOClient class RATGDOComponent;
class RATGDOClient; typedef Parented<RATGDOComponent> RATGDOClient;
static const uint8_t CODE_LENGTH = 19; static const uint8_t CODE_LENGTH = 19;
@ -128,44 +128,29 @@ namespace ratgdo {
EspSoftwareSerial::UART swSerial; EspSoftwareSerial::UART swSerial;
uint32_t rollingCodeCounter { 0 }; observable<uint32_t> rollingCodeCounter { 0 };
uint32_t lastSyncedRollingCodeCounter { 0 }; uint32_t lastSyncedRollingCodeCounter { 0 };
float startOpening { -1 }; float startOpening { -1 };
float openingDuration { 0 }; observable<float> openingDuration { 0 };
float startClosing { -1 }; float startClosing { -1 };
float closingDuration { 0 }; observable<float> closingDuration { 0 };
uint8_t txRollingCode[CODE_LENGTH]; uint8_t txRollingCode[CODE_LENGTH];
uint8_t rxRollingCode[CODE_LENGTH]; uint8_t rxRollingCode[CODE_LENGTH];
uint16_t previousOpenings { 0 }; // number of times the door has been opened observable<uint16_t> openings { 0 }; // number of times the door has been opened
uint16_t openings { 0 }; // number of times the door has been opened
DoorState previousDoorState { DoorState::DOOR_STATE_UNKNOWN }; observable<DoorState> doorState { DoorState::DOOR_STATE_UNKNOWN };
DoorState doorState { DoorState::DOOR_STATE_UNKNOWN }; observable<float> doorPosition { DOOR_POSITION_UNKNOWN };
float doorPosition { DOOR_POSITION_UNKNOWN };
float previousDoorPosition { DOOR_POSITION_UNKNOWN };
bool movingToPosition { false }; bool movingToPosition { false };
LightState previousLightState { LightState::LIGHT_STATE_UNKNOWN }; observable<LightState> lightState { LightState::LIGHT_STATE_UNKNOWN };
LightState lightState { LightState::LIGHT_STATE_UNKNOWN }; observable<LockState> lockState { LockState::LOCK_STATE_UNKNOWN };
observable<ObstructionState> obstructionState { ObstructionState::OBSTRUCTION_STATE_UNKNOWN };
LockState previousLockState { LockState::LOCK_STATE_UNKNOWN }; observable<MotorState> motorState { MotorState::MOTOR_STATE_UNKNOWN };
LockState lockState { LockState::LOCK_STATE_UNKNOWN }; observable<ButtonState> buttonState { ButtonState::BUTTON_STATE_UNKNOWN };
observable<MotionState> motionState { MotionState::MOTION_STATE_UNKNOWN };
ObstructionState previousObstructionState { ObstructionState::OBSTRUCTION_STATE_UNKNOWN };
ObstructionState obstructionState { ObstructionState::OBSTRUCTION_STATE_UNKNOWN };
MotorState previousMotorState { MotorState::MOTOR_STATE_UNKNOWN };
MotorState motorState { MotorState::MOTOR_STATE_UNKNOWN };
ButtonState previousButtonState { ButtonState::BUTTON_STATE_UNKNOWN };
ButtonState buttonState { ButtonState::BUTTON_STATE_UNKNOWN };
MotionState previousMotionState { MotionState::MOTION_STATE_UNKNOWN };
MotionState motionState { MotionState::MOTION_STATE_UNKNOWN };
void set_output_gdo_pin(InternalGPIOPin* pin) { this->output_gdo_pin_ = pin; }; void set_output_gdo_pin(InternalGPIOPin* pin) { this->output_gdo_pin_ = pin; };
void set_input_gdo_pin(InternalGPIOPin* pin) { this->input_gdo_pin_ = pin; }; void set_input_gdo_pin(InternalGPIOPin* pin) { this->input_gdo_pin_ = pin; };
@ -180,7 +165,6 @@ namespace ratgdo {
void gdoStateLoop(); void gdoStateLoop();
void obstructionLoop(); void obstructionLoop();
void statusUpdateLoop();
void saveCounter(); void saveCounter();
@ -210,25 +194,30 @@ namespace ratgdo {
void getRollingCode(command::cmd command, uint32_t data, bool increment); void getRollingCode(command::cmd command, uint32_t data, bool increment);
uint16_t readRollingCode(); uint16_t readRollingCode();
void incrementRollingCodeCounter(int delta = 1); void incrementRollingCodeCounter(int delta = 1);
void sendRollingCodeChanged();
void setRollingCodeCounter(uint32_t counter); void setRollingCodeCounter(uint32_t counter);
void setOpeningDuration(float duration); void setOpeningDuration(float duration);
void sendOpeningDuration();
void setClosingDuration(float duration); void setClosingDuration(float duration);
void sendClosingDuration();
LightState getLightState(); LightState getLightState();
/** Register a child component. */
void register_child(RATGDOClient* obj); void subscribe_rolling_code_counter(std::function<void(uint32_t)>&& f);
void subscribe_opening_duration(std::function<void(float)>&& f);
void subscribe_closing_duration(std::function<void(float)>&& f);
void subscribe_openings(std::function<void(uint16_t)>&& f);
void subscribe_door_state(std::function<void(DoorState, float)>&& f);
void subscribe_light_state(std::function<void(LightState)>&& f);
void subscribe_lock_state(std::function<void(LockState)>&& f);
void subscribe_obstruction_state(std::function<void(ObstructionState)>&& f);
void subscribe_motor_state(std::function<void(MotorState)>&& f);
void subscribe_button_state(std::function<void(ButtonState)>&& f);
void subscribe_motion_state(std::function<void(MotionState)>&& f);
protected: protected:
ESPPreferenceObject rollingCodePref_; ESPPreferenceObject rollingCodePref_;
ESPPreferenceObject openingDurationPref_; ESPPreferenceObject openingDurationPref_;
ESPPreferenceObject closingDurationPref_; ESPPreferenceObject closingDurationPref_;
std::vector<RATGDOClient*> children_;
bool rollingCodeUpdatesEnabled_ { true }; bool rollingCodeUpdatesEnabled_ { true };
bool forceUpdate_ { false };
RATGDOStore store_ {}; RATGDOStore store_ {};
InternalGPIOPin* output_gdo_pin_; InternalGPIOPin* output_gdo_pin_;

View File

@ -1,22 +0,0 @@
#include "esphome/core/helpers.h"
#include "ratgdo.h"
#include "ratgdo_state.h"
namespace esphome {
namespace ratgdo {
void RATGDOClient::on_door_state(DoorState state, float position) {};
void RATGDOClient::on_light_state(LightState state) {};
void RATGDOClient::on_lock_state(LockState state) {};
void RATGDOClient::on_motion_state(MotionState state) {};
void RATGDOClient::on_obstruction_state(ObstructionState state) {};
void RATGDOClient::on_motor_state(MotorState state) {};
void RATGDOClient::on_rolling_code_change(uint32_t rollingCodeCounter) {};
void RATGDOClient::on_opening_duration_change(float duration) {};
void RATGDOClient::on_closing_duration_change(float duration) {};
void RATGDOClient::on_openings_change(uint32_t openings) {};
void RATGDOClient::on_button_state(ButtonState state) {};
} // namespace ratgdo
} // namespace esphome

View File

@ -1,33 +0,0 @@
#pragma once
#include "esphome/core/helpers.h"
#include "ratgdo.h"
#include "ratgdo_state.h"
namespace esphome {
namespace ratgdo {
// Forward declare RATGDOComponent
class RATGDOComponent;
class RATGDOClient : public Parented<RATGDOComponent> {
public:
virtual void on_door_state(DoorState state, float position);
virtual void on_light_state(LightState state);
virtual void on_lock_state(LockState state);
virtual void on_motion_state(MotionState state);
virtual void on_obstruction_state(ObstructionState state);
virtual void on_motor_state(MotorState state);
virtual void on_rolling_code_change(uint32_t rollingCodeCounter);
virtual void on_opening_duration_change(float duration);
virtual void on_closing_duration_change(float duration);
virtual void on_openings_change(uint32_t openings);
virtual void on_button_state(ButtonState state);
protected:
friend RATGDOComponent;
};
} // namespace ratgdo
} // namespace esphome

View File

@ -12,9 +12,12 @@ namespace ratgdo {
LOG_SENSOR("", "RATGDO Sensor", this); LOG_SENSOR("", "RATGDO Sensor", this);
ESP_LOGCONFIG(TAG, " Type: Openings"); ESP_LOGCONFIG(TAG, " Type: Openings");
} }
void RATGDOSensor::on_openings_change(uint32_t openings)
void RATGDOSensor::setup()
{ {
this->publish_state(openings); this->parent_->subscribe_openings([=](uint16_t value) {
this->publish_state(value);
});
} }
} // namespace ratgdo } // namespace ratgdo

View File

@ -1,7 +1,6 @@
#pragma once #pragma once
#include "../ratgdo.h" #include "../ratgdo.h"
#include "../ratgdo_child.h"
#include "../ratgdo_state.h" #include "../ratgdo_state.h"
#include "esphome/components/sensor/sensor.h" #include "esphome/components/sensor/sensor.h"
#include "esphome/core/component.h" #include "esphome/core/component.h"
@ -16,10 +15,9 @@ namespace ratgdo {
class RATGDOSensor : public sensor::Sensor, public RATGDOClient, public Component { class RATGDOSensor : public sensor::Sensor, public RATGDOClient, public Component {
public: public:
void dump_config() override; void dump_config() override;
void setup() override;
void set_ratgdo_sensor_type(RATGDOSensorType ratgdo_sensor_type_) { this->ratgdo_sensor_type_ = ratgdo_sensor_type_; } void set_ratgdo_sensor_type(RATGDOSensorType ratgdo_sensor_type_) { this->ratgdo_sensor_type_ = ratgdo_sensor_type_; }
void on_openings_change(uint32_t openings) override;
protected: protected:
RATGDOSensorType ratgdo_sensor_type_; RATGDOSensorType ratgdo_sensor_type_;
}; };

View File

@ -13,6 +13,13 @@ namespace ratgdo {
ESP_LOGCONFIG(TAG, " Type: Lock"); ESP_LOGCONFIG(TAG, " Type: Lock");
} }
void RATGDOSwitch::setup()
{
this->parent_->subscribe_lock_state([=](LockState state) {
this->on_lock_state(state);
});
}
void RATGDOSwitch::on_lock_state(LockState state) void RATGDOSwitch::on_lock_state(LockState state)
{ {
bool value = state == LockState::LOCK_STATE_LOCKED; bool value = state == LockState::LOCK_STATE_LOCKED;

View File

@ -1,7 +1,6 @@
#pragma once #pragma once
#include "../ratgdo.h" #include "../ratgdo.h"
#include "../ratgdo_child.h"
#include "../ratgdo_state.h" #include "../ratgdo_state.h"
#include "esphome/components/switch/switch.h" #include "esphome/components/switch/switch.h"
#include "esphome/core/component.h" #include "esphome/core/component.h"
@ -16,9 +15,10 @@ namespace ratgdo {
class RATGDOSwitch : public switch_::Switch, public RATGDOClient, public Component { class RATGDOSwitch : public switch_::Switch, public RATGDOClient, public Component {
public: public:
void dump_config() override; void dump_config() override;
void setup() override;
void set_switch_type(SwitchType switch_type_) { this->switch_type_ = switch_type_; } void set_switch_type(SwitchType switch_type_) { this->switch_type_ = switch_type_; }
void on_lock_state(LockState state) override; void on_lock_state(LockState state);
void write_state(bool state) override; void write_state(bool state) override;
protected: protected:

View File

@ -33,6 +33,7 @@ packages:
url: https://github.com/esphome-ratgdo/esphome-ratgdo url: https://github.com/esphome-ratgdo/esphome-ratgdo
files: [base.yaml] files: [base.yaml]
refresh: 1s refresh: 1s
ref: observer_callbacks
# Sync time with Home Assistant. # Sync time with Home Assistant.
time: time: