Convert enums to scoped enums (#28)
Co-authored-by: J. Nick Koston <nick@koston.org>
This commit is contained in:
parent
64c409cab9
commit
3721bb5465
|
@ -12,21 +12,21 @@ namespace ratgdo {
|
||||||
if (this->binary_sensor_type_ == SensorType::RATGDO_SENSOR_MOTION) {
|
if (this->binary_sensor_type_ == SensorType::RATGDO_SENSOR_MOTION) {
|
||||||
this->publish_initial_state(false);
|
this->publish_initial_state(false);
|
||||||
this->parent_->subscribe_motion_state([=](MotionState state) {
|
this->parent_->subscribe_motion_state([=](MotionState state) {
|
||||||
this->publish_state(state == MotionState::MOTION_STATE_DETECTED);
|
this->publish_state(state == MotionState::DETECTED);
|
||||||
});
|
});
|
||||||
} else if (this->binary_sensor_type_ == SensorType::RATGDO_SENSOR_OBSTRUCTION) {
|
} else if (this->binary_sensor_type_ == SensorType::RATGDO_SENSOR_OBSTRUCTION) {
|
||||||
this->publish_initial_state(false);
|
this->publish_initial_state(false);
|
||||||
this->parent_->subscribe_obstruction_state([=](ObstructionState state) {
|
this->parent_->subscribe_obstruction_state([=](ObstructionState state) {
|
||||||
this->publish_state(state == ObstructionState::OBSTRUCTION_STATE_OBSTRUCTED);
|
this->publish_state(state == ObstructionState::OBSTRUCTED);
|
||||||
});
|
});
|
||||||
} else if (this->binary_sensor_type_ == SensorType::RATGDO_SENSOR_MOTOR) {
|
} else if (this->binary_sensor_type_ == SensorType::RATGDO_SENSOR_MOTOR) {
|
||||||
this->parent_->subscribe_motor_state([=](MotorState state) {
|
this->parent_->subscribe_motor_state([=](MotorState state) {
|
||||||
this->publish_state(state == MotorState::MOTOR_STATE_ON);
|
this->publish_state(state == MotorState::ON);
|
||||||
});
|
});
|
||||||
} else if (this->binary_sensor_type_ == SensorType::RATGDO_SENSOR_BUTTON) {
|
} else if (this->binary_sensor_type_ == SensorType::RATGDO_SENSOR_BUTTON) {
|
||||||
this->publish_initial_state(false);
|
this->publish_initial_state(false);
|
||||||
this->parent_->subscribe_button_state([=](ButtonState state) {
|
this->parent_->subscribe_button_state([=](ButtonState state) {
|
||||||
this->publish_state(state == ButtonState::BUTTON_STATE_PRESSED);
|
this->publish_state(state == ButtonState::PRESSED);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,26 +24,26 @@ namespace ratgdo {
|
||||||
void RATGDOCover::on_door_state(DoorState state, float position)
|
void RATGDOCover::on_door_state(DoorState state, float position)
|
||||||
{
|
{
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case DoorState::DOOR_STATE_OPEN:
|
case DoorState::OPEN:
|
||||||
this->position = COVER_OPEN;
|
this->position = COVER_OPEN;
|
||||||
this->current_operation = COVER_OPERATION_IDLE;
|
this->current_operation = COVER_OPERATION_IDLE;
|
||||||
break;
|
break;
|
||||||
case DoorState::DOOR_STATE_CLOSED:
|
case DoorState::CLOSED:
|
||||||
this->position = COVER_CLOSED;
|
this->position = COVER_CLOSED;
|
||||||
this->current_operation = COVER_OPERATION_IDLE;
|
this->current_operation = COVER_OPERATION_IDLE;
|
||||||
break;
|
break;
|
||||||
case DoorState::DOOR_STATE_OPENING:
|
case DoorState::OPENING:
|
||||||
this->current_operation = COVER_OPERATION_OPENING;
|
this->current_operation = COVER_OPERATION_OPENING;
|
||||||
this->position = position;
|
this->position = position;
|
||||||
break;
|
break;
|
||||||
case DoorState::DOOR_STATE_CLOSING:
|
case DoorState::CLOSING:
|
||||||
this->current_operation = COVER_OPERATION_CLOSING;
|
this->current_operation = COVER_OPERATION_CLOSING;
|
||||||
this->position = position;
|
this->position = position;
|
||||||
break;
|
break;
|
||||||
case DoorState::DOOR_STATE_STOPPED:
|
case DoorState::STOPPED:
|
||||||
this->current_operation = COVER_OPERATION_IDLE;
|
this->current_operation = COVER_OPERATION_IDLE;
|
||||||
this->position = position;
|
this->position = position;
|
||||||
case DoorState::DOOR_STATE_UNKNOWN:
|
case DoorState::UNKNOWN:
|
||||||
default:
|
default:
|
||||||
this->current_operation = COVER_OPERATION_IDLE;
|
this->current_operation = COVER_OPERATION_IDLE;
|
||||||
this->position = position;
|
this->position = position;
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
|
||||||
|
|
||||||
|
#define PARENS ()
|
||||||
|
|
||||||
|
// Rescan macro tokens 256 times
|
||||||
|
#define EXPAND(...) EXPAND4(EXPAND4(EXPAND4(EXPAND4(__VA_ARGS__))))
|
||||||
|
#define EXPAND4(...) EXPAND3(EXPAND3(EXPAND3(EXPAND3(__VA_ARGS__))))
|
||||||
|
#define EXPAND3(...) EXPAND2(EXPAND2(EXPAND2(EXPAND2(__VA_ARGS__))))
|
||||||
|
#define EXPAND2(...) EXPAND1(EXPAND1(EXPAND1(EXPAND1(__VA_ARGS__))))
|
||||||
|
#define EXPAND1(...) __VA_ARGS__
|
||||||
|
|
||||||
|
#define FOR_EACH(macro, name, ...) \
|
||||||
|
__VA_OPT__(EXPAND(FOR_EACH_HELPER(macro, name, __VA_ARGS__)))
|
||||||
|
#define FOR_EACH_HELPER(macro, name, a1, ...) \
|
||||||
|
macro(name, a1) \
|
||||||
|
__VA_OPT__(FOR_EACH_AGAIN PARENS(macro, name, __VA_ARGS__))
|
||||||
|
#define FOR_EACH_AGAIN() FOR_EACH_HELPER
|
||||||
|
|
||||||
|
#define ENUM_VARIANT0(name, val) name = val,
|
||||||
|
#define ENUM_VARIANT(name, tuple) ENUM_VARIANT0 tuple
|
||||||
|
|
||||||
|
#define TUPLE(x, y) x, y
|
||||||
|
|
||||||
|
#define LPAREN (
|
||||||
|
|
||||||
|
#define TO_STRING_CASE0(type, name, val) \
|
||||||
|
case type::name: \
|
||||||
|
return #name;
|
||||||
|
#define TO_STRING_CASE(type, tuple) TO_STRING_CASE0 LPAREN type, TUPLE tuple)
|
||||||
|
|
||||||
|
#define FROM_INT_CASE0(type, name, val) \
|
||||||
|
case val: \
|
||||||
|
return type::name;
|
||||||
|
#define FROM_INT_CASE(type, tuple) FROM_INT_CASE0 LPAREN type, TUPLE tuple)
|
||||||
|
|
||||||
|
#define ENUM(name, type, ...) \
|
||||||
|
enum class name : type { \
|
||||||
|
FOR_EACH(ENUM_VARIANT, name, __VA_ARGS__) \
|
||||||
|
}; \
|
||||||
|
inline const char* \
|
||||||
|
name##_to_string(name _e) \
|
||||||
|
{ \
|
||||||
|
switch (_e) { \
|
||||||
|
FOR_EACH(TO_STRING_CASE, name, __VA_ARGS__) \
|
||||||
|
default: \
|
||||||
|
return "UNKNOWN"; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
inline name \
|
||||||
|
to_##name(type _t, name _unknown) \
|
||||||
|
{ \
|
||||||
|
switch (_t) { \
|
||||||
|
FOR_EACH(FROM_INT_CASE, name, __VA_ARGS__) \
|
||||||
|
default: \
|
||||||
|
return _unknown; \
|
||||||
|
} \
|
||||||
|
}
|
|
@ -32,7 +32,7 @@ namespace ratgdo {
|
||||||
void RATGDOLightOutput::set_state(esphome::ratgdo::LightState state)
|
void RATGDOLightOutput::set_state(esphome::ratgdo::LightState state)
|
||||||
{
|
{
|
||||||
|
|
||||||
bool is_on = state == LightState::LIGHT_STATE_ON;
|
bool is_on = state == LightState::ON;
|
||||||
this->light_state_->current_values.set_state(is_on);
|
this->light_state_->current_values.set_state(is_on);
|
||||||
this->light_state_->remote_values.set_state(is_on);
|
this->light_state_->remote_values.set_state(is_on);
|
||||||
this->light_state_->publish_state();
|
this->light_state_->publish_state();
|
||||||
|
|
|
@ -44,6 +44,9 @@ namespace ratgdo {
|
||||||
this->traits.set_min_value(0.0);
|
this->traits.set_min_value(0.0);
|
||||||
this->traits.set_max_value(180.0);
|
this->traits.set_max_value(180.0);
|
||||||
}
|
}
|
||||||
|
if (this->number_type_ == RATGDO_ROLLING_CODE_COUNTER) {
|
||||||
|
this->traits.set_max_value(0xfffffff);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RATGDONumber::control(float value)
|
void RATGDONumber::control(float value)
|
||||||
|
|
|
@ -73,7 +73,7 @@ namespace ratgdo {
|
||||||
this->input_gdo_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP);
|
this->input_gdo_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP);
|
||||||
this->input_obst_pin_->pin_mode(gpio::FLAG_INPUT);
|
this->input_obst_pin_->pin_mode(gpio::FLAG_INPUT);
|
||||||
|
|
||||||
this->sw_serial.begin(9600, SWSERIAL_8N1, this->input_gdo_pin_->get_pin(), this->output_gdo_pin_->get_pin(), true);
|
this->sw_serial_.begin(9600, SWSERIAL_8N1, this->input_gdo_pin_->get_pin(), this->output_gdo_pin_->get_pin(), true);
|
||||||
|
|
||||||
this->input_obst_pin_->attach_interrupt(RATGDOStore::isr_obstruction, &this->isr_store_, gpio::INTERRUPT_ANY_EDGE);
|
this->input_obst_pin_->attach_interrupt(RATGDOStore::isr_obstruction, &this->isr_store_, gpio::INTERRUPT_ANY_EDGE);
|
||||||
|
|
||||||
|
@ -85,8 +85,8 @@ namespace ratgdo {
|
||||||
|
|
||||||
void RATGDOComponent::loop()
|
void RATGDOComponent::loop()
|
||||||
{
|
{
|
||||||
obstruction_loop();
|
this->obstruction_loop();
|
||||||
gdo_state_loop();
|
this->gdo_state_loop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RATGDOComponent::dump_config()
|
void RATGDOComponent::dump_config()
|
||||||
|
@ -99,58 +99,6 @@ namespace ratgdo {
|
||||||
ESP_LOGCONFIG(TAG, " Remote ID: %d", this->remote_id_);
|
ESP_LOGCONFIG(TAG, " Remote ID: %d", this->remote_id_);
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* cmd_name(uint16_t cmd)
|
|
||||||
{
|
|
||||||
// from: https://github.com/argilo/secplus/blob/f98c3220356c27717a25102c0b35815ebbd26ccc/secplus.py#L540
|
|
||||||
switch (cmd) {
|
|
||||||
// sent by opener (motor)
|
|
||||||
case 0x081:
|
|
||||||
return "status";
|
|
||||||
case 0x084:
|
|
||||||
return "unknown_1";
|
|
||||||
case 0x085:
|
|
||||||
return "unknown_2";
|
|
||||||
case 0x0a1:
|
|
||||||
return "pair_3_resp";
|
|
||||||
case 0x284:
|
|
||||||
return "motor_on";
|
|
||||||
case 0x393:
|
|
||||||
return "learn_3_resp";
|
|
||||||
case 0x401:
|
|
||||||
return "pair_2_resp";
|
|
||||||
case 0x48c:
|
|
||||||
return "openings";
|
|
||||||
|
|
||||||
// sent by switch
|
|
||||||
case 0x080:
|
|
||||||
return "get_status";
|
|
||||||
case 0x0a0:
|
|
||||||
return "pair_3";
|
|
||||||
case 0x181:
|
|
||||||
return "learn_2";
|
|
||||||
case 0x18c:
|
|
||||||
return "lock";
|
|
||||||
case 0x280:
|
|
||||||
return "open";
|
|
||||||
case 0x281:
|
|
||||||
return "light";
|
|
||||||
case 0x285:
|
|
||||||
return "motion";
|
|
||||||
case 0x391:
|
|
||||||
return "learn_1";
|
|
||||||
case 0x392:
|
|
||||||
return "learn_3";
|
|
||||||
case 0x400:
|
|
||||||
return "pair_2";
|
|
||||||
case 0x48b:
|
|
||||||
return "get_openings";
|
|
||||||
case 0x40a:
|
|
||||||
return "ttc"; // Time to close
|
|
||||||
default:
|
|
||||||
return "unknown";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t RATGDOComponent::decode_packet(const WirePacket& packet)
|
uint16_t RATGDOComponent::decode_packet(const WirePacket& packet)
|
||||||
{
|
{
|
||||||
uint32_t rolling = 0;
|
uint32_t rolling = 0;
|
||||||
|
@ -161,10 +109,12 @@ namespace ratgdo {
|
||||||
|
|
||||||
uint16_t cmd = ((fixed >> 24) & 0xf00) | (data & 0xff);
|
uint16_t cmd = ((fixed >> 24) & 0xf00) | (data & 0xff);
|
||||||
data &= ~0xf000; // clear parity nibble
|
data &= ~0xf000; // clear parity nibble
|
||||||
|
|
||||||
|
Command cmd_enum = to_Command(cmd, Command::UNKNOWN);
|
||||||
|
|
||||||
if ((fixed & 0xfff) == this->remote_id_) { // my commands
|
if ((fixed & 0xfffffff) == this->remote_id_) { // my commands
|
||||||
ESP_LOGV(TAG, "[%ld] received mine: rolling=%07" PRIx32 " fixed=%010" PRIx64 " data=%08" PRIx32, millis(), rolling, fixed, data);
|
ESP_LOGV(TAG, "[%ld] received mine: rolling=%07" PRIx32 " fixed=%010" PRIx64 " data=%08" PRIx32, millis(), rolling, fixed, data);
|
||||||
return 0;
|
return static_cast<uint16_t>(Command::UNKNOWN);
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGV(TAG, "[%ld] received rolling=%07" PRIx32 " fixed=%010" PRIx64 " data=%08" PRIx32, millis(), rolling, fixed, data);
|
ESP_LOGV(TAG, "[%ld] received rolling=%07" PRIx32 " fixed=%010" PRIx64 " data=%08" PRIx32, millis(), rolling, fixed, data);
|
||||||
}
|
}
|
||||||
|
@ -173,41 +123,41 @@ namespace ratgdo {
|
||||||
uint8_t byte1 = (data >> 16) & 0xff;
|
uint8_t byte1 = (data >> 16) & 0xff;
|
||||||
uint8_t byte2 = (data >> 24) & 0xff;
|
uint8_t byte2 = (data >> 24) & 0xff;
|
||||||
|
|
||||||
ESP_LOGV(TAG, "cmd=%03x (%s) byte2=%02x byte1=%02x nibble=%01x", cmd, cmd_name(cmd), byte2, byte1, nibble);
|
ESP_LOGV(TAG, "cmd=%03x (%s) byte2=%02x byte1=%02x nibble=%01x", cmd, Command_to_string(cmd_enum), byte2, byte1, nibble);
|
||||||
|
|
||||||
if (cmd == command::STATUS) {
|
if (cmd == Command::STATUS) {
|
||||||
|
|
||||||
auto door_state = static_cast<DoorState>(nibble);
|
auto door_state = to_DoorState(nibble, DoorState::UNKNOWN);
|
||||||
auto prev_door_state = *this->door_state;
|
auto prev_door_state = *this->door_state;
|
||||||
|
|
||||||
if (door_state == DoorState::DOOR_STATE_OPENING && prev_door_state == DoorState::DOOR_STATE_CLOSED) {
|
if (door_state == DoorState::OPENING && prev_door_state == DoorState::CLOSED) {
|
||||||
this->start_opening = millis();
|
this->start_opening = millis();
|
||||||
}
|
}
|
||||||
if (door_state == DoorState::DOOR_STATE_OPEN && prev_door_state == DoorState::DOOR_STATE_OPENING) {
|
if (door_state == DoorState::OPEN && prev_door_state == DoorState::OPENING) {
|
||||||
if (this->start_opening > 0) {
|
if (this->start_opening > 0) {
|
||||||
auto duration = (millis() - this->start_opening) / 1000;
|
auto duration = (millis() - this->start_opening) / 1000;
|
||||||
duration = *this->opening_duration > 0 ? (duration + *this->opening_duration) / 2 : duration;
|
duration = *this->opening_duration > 0 ? (duration + *this->opening_duration) / 2 : duration;
|
||||||
this->set_opening_duration(round(duration * 10) / 10);
|
this->set_opening_duration(round(duration * 10) / 10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (door_state == DoorState::DOOR_STATE_CLOSING && prev_door_state == DoorState::DOOR_STATE_OPEN) {
|
if (door_state == DoorState::CLOSING && prev_door_state == DoorState::OPEN) {
|
||||||
this->start_closing = millis();
|
this->start_closing = millis();
|
||||||
}
|
}
|
||||||
if (door_state == DoorState::DOOR_STATE_CLOSED && prev_door_state == DoorState::DOOR_STATE_CLOSING) {
|
if (door_state == DoorState::CLOSED && prev_door_state == DoorState::CLOSING) {
|
||||||
if (this->start_closing > 0) {
|
if (this->start_closing > 0) {
|
||||||
auto duration = (millis() - this->start_closing) / 1000;
|
auto duration = (millis() - this->start_closing) / 1000;
|
||||||
duration = *this->closing_duration > 0 ? (duration + *this->closing_duration) / 2 : duration;
|
duration = *this->closing_duration > 0 ? (duration + *this->closing_duration) / 2 : duration;
|
||||||
this->set_closing_duration(round(duration * 10) / 10);
|
this->set_closing_duration(round(duration * 10) / 10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (door_state == DoorState::DOOR_STATE_STOPPED) {
|
if (door_state == DoorState::STOPPED) {
|
||||||
this->start_opening = -1;
|
this->start_opening = -1;
|
||||||
this->start_closing = -1;
|
this->start_closing = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (door_state == DoorState::DOOR_STATE_OPEN) {
|
if (door_state == DoorState::OPEN) {
|
||||||
this->door_position = 1.0;
|
this->door_position = 1.0;
|
||||||
} else if (door_state == DoorState::DOOR_STATE_CLOSED) {
|
} else if (door_state == DoorState::CLOSED) {
|
||||||
this->door_position = 0.0;
|
this->door_position = 0.0;
|
||||||
} else {
|
} else {
|
||||||
if (*this->closing_duration == 0 || *this->opening_duration == 0 || *this->door_position == DOOR_POSITION_UNKNOWN) {
|
if (*this->closing_duration == 0 || *this->opening_duration == 0 || *this->door_position == DOOR_POSITION_UNKNOWN) {
|
||||||
|
@ -215,78 +165,81 @@ namespace ratgdo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (door_state == DoorState::DOOR_STATE_OPENING && !this->moving_to_position) {
|
if (door_state == DoorState::OPENING && !this->moving_to_position) {
|
||||||
this->position_sync_while_opening(1.0 - *this->door_position);
|
this->position_sync_while_opening(1.0 - *this->door_position);
|
||||||
this->moving_to_position = true;
|
this->moving_to_position = true;
|
||||||
}
|
}
|
||||||
if (door_state == DoorState::DOOR_STATE_CLOSING && !this->moving_to_position) {
|
if (door_state == DoorState::CLOSING && !this->moving_to_position) {
|
||||||
this->position_sync_while_closing(*this->door_position);
|
this->position_sync_while_closing(*this->door_position);
|
||||||
this->moving_to_position = true;
|
this->moving_to_position = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (door_state == DoorState::DOOR_STATE_OPEN || door_state == DoorState::DOOR_STATE_CLOSED || door_state == DoorState::DOOR_STATE_STOPPED) {
|
if (door_state == DoorState::OPEN || door_state == DoorState::CLOSED || door_state == DoorState::STOPPED) {
|
||||||
this->cancel_position_sync_callbacks();
|
this->cancel_position_sync_callbacks();
|
||||||
}
|
}
|
||||||
|
|
||||||
this->door_state = door_state;
|
this->door_state = door_state;
|
||||||
this->light_state = static_cast<LightState>((byte2 >> 1) & 1);
|
this->light_state = static_cast<LightState>((byte2 >> 1) & 1); // safe because it can only be 0 or 1
|
||||||
this->lock_state = static_cast<LockState>(byte2 & 1);
|
this->lock_state = static_cast<LockState>(byte2 & 1); // safe because it can only be 0 or 1
|
||||||
this->motion_state = MotionState::MOTION_STATE_CLEAR; // when the status message is read, reset motion state to 0|clear
|
this->motion_state = MotionState::CLEAR; // when the status message is read, reset motion state to 0|clear
|
||||||
this->motor_state = MotorState::MOTOR_STATE_OFF; // when the status message is read, reset motor state to 0|off
|
this->motor_state = MotorState::OFF; // when the status message is read, reset motor state to 0|off
|
||||||
// this->obstruction_state = static_cast<ObstructionState>((byte1 >> 6) & 1);
|
// this->obstruction_state = static_cast<ObstructionState>((byte1 >> 6) & 1);
|
||||||
|
|
||||||
if (door_state == DoorState::DOOR_STATE_CLOSED && door_state != prev_door_state) {
|
if (door_state == DoorState::CLOSED && door_state != prev_door_state) {
|
||||||
transmit(command::GET_OPENINGS);
|
this->transmit(Command::GET_OPENINGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
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->door_state),
|
DoorState_to_string(*this->door_state),
|
||||||
light_state_to_string(*this->light_state),
|
LightState_to_string(*this->light_state),
|
||||||
lock_state_to_string(*this->lock_state));
|
LockState_to_string(*this->lock_state));
|
||||||
} else if (cmd == command::LIGHT) {
|
} else if (cmd == Command::LIGHT) {
|
||||||
if (nibble == 0) {
|
if (nibble == 0) {
|
||||||
this->light_state = LightState::LIGHT_STATE_OFF;
|
this->light_state = LightState::OFF;
|
||||||
} else if (nibble == 1) {
|
} else if (nibble == 1) {
|
||||||
this->light_state = LightState::LIGHT_STATE_ON;
|
this->light_state = LightState::ON;
|
||||||
} else if (nibble == 2) { // toggle
|
} else if (nibble == 2) { // toggle
|
||||||
this->light_state = light_state_toggle(*this->light_state);
|
this->light_state = light_state_toggle(*this->light_state);
|
||||||
}
|
}
|
||||||
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->light_state));
|
LightState_to_string(*this->light_state));
|
||||||
} else if (cmd == command::MOTOR_ON) {
|
} else if (cmd == Command::MOTOR_ON) {
|
||||||
this->motor_state = MotorState::MOTOR_STATE_ON;
|
this->motor_state = MotorState::ON;
|
||||||
ESP_LOGD(TAG, "Motor: state=%s", motor_state_to_string(*this->motor_state));
|
ESP_LOGD(TAG, "Motor: state=%s", MotorState_to_string(*this->motor_state));
|
||||||
} else if (cmd == command::OPEN) {
|
} else if (cmd == Command::OPEN) {
|
||||||
this->button_state = (byte1 & 1) == 1 ? ButtonState::BUTTON_STATE_PRESSED : ButtonState::BUTTON_STATE_RELEASED;
|
this->button_state = (byte1 & 1) == 1 ? ButtonState::PRESSED : ButtonState::RELEASED;
|
||||||
ESP_LOGD(TAG, "Open: button=%s", button_state_to_string(*this->button_state));
|
ESP_LOGD(TAG, "Open: button=%s", ButtonState_to_string(*this->button_state));
|
||||||
} 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->motion_state = MotionState::MOTION_STATE_DETECTED;
|
this->motion_state = MotionState::DETECTED;
|
||||||
if (*this->light_state == LightState::LIGHT_STATE_OFF) {
|
if (*this->light_state == LightState::OFF) {
|
||||||
transmit(command::GET_STATUS);
|
this->transmit(Command::GET_STATUS);
|
||||||
}
|
}
|
||||||
ESP_LOGD(TAG, "Motion: %s", motion_state_to_string(*this->motion_state));
|
ESP_LOGD(TAG, "Motion: %s", MotionState_to_string(*this->motion_state));
|
||||||
} else {
|
} else if (cmd == Command::SET_TTC) {
|
||||||
ESP_LOGV(TAG, "Unhandled command: cmd=%03x nibble=%02x byte1=%02x byte2=%02x fixed=%010" PRIx64 " data=%08" PRIx32, cmd, nibble, byte1, byte2, fixed, data);
|
auto seconds = (byte1 << 8) | byte2;
|
||||||
|
ESP_LOGD(TAG, "Time to close (TTC): %ds", seconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cmd;
|
return cmd;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RATGDOComponent::encode_packet(command::cmd command, uint32_t data, bool increment, WirePacket& packet)
|
void RATGDOComponent::encode_packet(Command command, uint32_t data, bool increment, WirePacket& packet)
|
||||||
{
|
{
|
||||||
uint64_t fixed = ((command & ~0xff) << 24) | this->remote_id_;
|
auto cmd = static_cast<uint64_t>(command);
|
||||||
uint32_t send_data = (data << 8) | (command & 0xff);
|
uint64_t fixed = ((cmd & ~0xff) << 24) | this->remote_id_;
|
||||||
|
uint32_t send_data = (data << 8) | (cmd & 0xff);
|
||||||
|
|
||||||
ESP_LOGV(TAG, "[%ld] Encode for transmit rolling=%07" PRIx32 " fixed=%010" PRIx64 " data=%08" PRIx32, millis(), *this->rolling_code_counter, fixed, send_data);
|
ESP_LOGV(TAG, "[%ld] Encode for transmit rolling=%07" PRIx32 " fixed=%010" PRIx64 " data=%08" PRIx32, millis(), *this->rolling_code_counter, fixed, send_data);
|
||||||
encode_wireline(*this->rolling_code_counter, fixed, send_data, packet);
|
encode_wireline(*this->rolling_code_counter, fixed, send_data, packet);
|
||||||
|
|
||||||
print_packet(packet);
|
this->print_packet(packet);
|
||||||
if (increment) {
|
if (increment) {
|
||||||
increment_rolling_code_counter();
|
this->increment_rolling_code_counter();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -367,13 +320,13 @@ namespace ratgdo {
|
||||||
// check to see if we got between 3 and 8 low pulses on the line
|
// check to see if we got between 3 and 8 low pulses on the line
|
||||||
if (this->isr_store_.obstruction_low_count >= 3 && this->isr_store_.obstruction_low_count <= 8) {
|
if (this->isr_store_.obstruction_low_count >= 3 && this->isr_store_.obstruction_low_count <= 8) {
|
||||||
// obstructionCleared();
|
// obstructionCleared();
|
||||||
this->obstruction_state = ObstructionState::OBSTRUCTION_STATE_CLEAR;
|
this->obstruction_state = ObstructionState::CLEAR;
|
||||||
|
|
||||||
// if there have been no pulses the line is steady high or low
|
// if there have been no pulses the line is steady high or low
|
||||||
} else if (this->isr_store_.obstruction_low_count == 0) {
|
} else if (this->isr_store_.obstruction_low_count == 0) {
|
||||||
// if the line is high and the last high pulse was more than 70ms ago, then there is an obstruction present
|
// if the line is high and the last high pulse was more than 70ms ago, then there is an obstruction present
|
||||||
if (this->input_obst_pin_->digital_read() && current_millis - this->isr_store_.last_obstruction_high > 70) {
|
if (this->input_obst_pin_->digital_read() && current_millis - this->isr_store_.last_obstruction_high > 70) {
|
||||||
this->obstruction_state = ObstructionState::OBSTRUCTION_STATE_OBSTRUCTED;
|
this->obstruction_state = ObstructionState::OBSTRUCTED;
|
||||||
// obstructionDetected();
|
// obstructionDetected();
|
||||||
} else {
|
} else {
|
||||||
// asleep
|
// asleep
|
||||||
|
@ -393,8 +346,8 @@ namespace ratgdo {
|
||||||
static WirePacket rx_packet;
|
static WirePacket rx_packet;
|
||||||
|
|
||||||
if (!reading_msg) {
|
if (!reading_msg) {
|
||||||
while (this->sw_serial.available()) {
|
while (this->sw_serial_.available()) {
|
||||||
uint8_t ser_byte = this->sw_serial.read();
|
uint8_t ser_byte = this->sw_serial_.read();
|
||||||
if (ser_byte != 0x55 && ser_byte != 0x01 && ser_byte != 0x00) {
|
if (ser_byte != 0x55 && ser_byte != 0x01 && ser_byte != 0x00) {
|
||||||
byte_count = 0;
|
byte_count = 0;
|
||||||
continue;
|
continue;
|
||||||
|
@ -414,15 +367,15 @@ namespace ratgdo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (reading_msg) {
|
if (reading_msg) {
|
||||||
while (this->sw_serial.available()) {
|
while (this->sw_serial_.available()) {
|
||||||
uint8_t ser_byte = this->sw_serial.read();
|
uint8_t ser_byte = this->sw_serial_.read();
|
||||||
rx_packet[byte_count] = ser_byte;
|
rx_packet[byte_count] = ser_byte;
|
||||||
byte_count++;
|
byte_count++;
|
||||||
|
|
||||||
if (byte_count == PACKET_LENGTH) {
|
if (byte_count == PACKET_LENGTH) {
|
||||||
reading_msg = false;
|
reading_msg = false;
|
||||||
byte_count = 0;
|
byte_count = 0;
|
||||||
decode_packet(rx_packet);
|
this->decode_packet(rx_packet);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -431,12 +384,12 @@ namespace ratgdo {
|
||||||
|
|
||||||
void RATGDOComponent::query_status()
|
void RATGDOComponent::query_status()
|
||||||
{
|
{
|
||||||
transmit(command::GET_STATUS);
|
transmit(Command::GET_STATUS);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RATGDOComponent::query_openings()
|
void RATGDOComponent::query_openings()
|
||||||
{
|
{
|
||||||
transmit(command::GET_OPENINGS);
|
transmit(Command::GET_OPENINGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
/************************* DOOR COMMUNICATION *************************/
|
/************************* DOOR COMMUNICATION *************************/
|
||||||
|
@ -448,20 +401,20 @@ namespace ratgdo {
|
||||||
* The opener requires a specific duration low/high pulse before it will accept
|
* The opener requires a specific duration low/high pulse before it will accept
|
||||||
* a message
|
* a message
|
||||||
*/
|
*/
|
||||||
void RATGDOComponent::transmit(command::cmd command, uint32_t data, bool increment)
|
void RATGDOComponent::transmit(Command command, uint32_t data, bool increment)
|
||||||
{
|
{
|
||||||
WirePacket tx_packet;
|
WirePacket tx_packet;
|
||||||
|
|
||||||
encode_packet(command, data, increment, tx_packet);
|
this->encode_packet(command, data, increment, tx_packet);
|
||||||
this->output_gdo_pin_->digital_write(true); // pull the line high for 1305 micros so the
|
this->output_gdo_pin_->digital_write(true); // pull the line high for 1305 micros so the
|
||||||
// door opener responds to the message
|
// door opener responds to the message
|
||||||
delayMicroseconds(1305);
|
delayMicroseconds(1305);
|
||||||
this->output_gdo_pin_->digital_write(false); // bring the line low
|
this->output_gdo_pin_->digital_write(false); // bring the line low
|
||||||
|
|
||||||
delayMicroseconds(1260); // "LOW" pulse duration before the message start
|
delayMicroseconds(1260); // "LOW" pulse duration before the message start
|
||||||
this->sw_serial.write(tx_packet, PACKET_LENGTH);
|
this->sw_serial_.write(tx_packet, PACKET_LENGTH);
|
||||||
|
|
||||||
save_rolling_code_counter();
|
this->save_rolling_code_counter();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RATGDOComponent::sync()
|
void RATGDOComponent::sync()
|
||||||
|
@ -471,15 +424,15 @@ namespace ratgdo {
|
||||||
|
|
||||||
set_retry(
|
set_retry(
|
||||||
300, 10, [=](uint8_t r) {
|
300, 10, [=](uint8_t r) {
|
||||||
if (*this->door_state != DoorState::DOOR_STATE_UNKNOWN) { // have status
|
if (*this->door_state != DoorState::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);
|
this->transmit(Command::GET_OPENINGS);
|
||||||
return RetryResult::RETRY;
|
return RetryResult::RETRY;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
transmit(command::GET_STATUS);
|
this->transmit(Command::GET_STATUS);
|
||||||
return RetryResult::RETRY;
|
return RetryResult::RETRY;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -488,41 +441,41 @@ namespace ratgdo {
|
||||||
|
|
||||||
void RATGDOComponent::open_door()
|
void RATGDOComponent::open_door()
|
||||||
{
|
{
|
||||||
if (*this->door_state == DoorState::DOOR_STATE_OPENING) {
|
if (*this->door_state == DoorState::OPENING) {
|
||||||
return; // gets ignored by opener
|
return; // gets ignored by opener
|
||||||
}
|
}
|
||||||
this->cancel_position_sync_callbacks();
|
this->cancel_position_sync_callbacks();
|
||||||
|
|
||||||
door_command(data::DOOR_OPEN);
|
this->door_command(data::DOOR_OPEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RATGDOComponent::close_door()
|
void RATGDOComponent::close_door()
|
||||||
{
|
{
|
||||||
if (*this->door_state == DoorState::DOOR_STATE_CLOSING || *this->door_state == DoorState::DOOR_STATE_OPENING) {
|
if (*this->door_state == DoorState::CLOSING || *this->door_state == DoorState::OPENING) {
|
||||||
return; // gets ignored by opener
|
return; // gets ignored by opener
|
||||||
}
|
}
|
||||||
this->cancel_position_sync_callbacks();
|
this->cancel_position_sync_callbacks();
|
||||||
|
|
||||||
door_command(data::DOOR_CLOSE);
|
this->door_command(data::DOOR_CLOSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RATGDOComponent::stop_door()
|
void RATGDOComponent::stop_door()
|
||||||
{
|
{
|
||||||
if (*this->door_state != DoorState::DOOR_STATE_OPENING && *this->door_state != DoorState::DOOR_STATE_CLOSING) {
|
if (*this->door_state != DoorState::OPENING && *this->door_state != DoorState::CLOSING) {
|
||||||
ESP_LOGW(TAG, "The door is not moving.");
|
ESP_LOGW(TAG, "The door is not moving.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
door_command(data::DOOR_STOP);
|
this->door_command(data::DOOR_STOP);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RATGDOComponent::toggle_door()
|
void RATGDOComponent::toggle_door()
|
||||||
{
|
{
|
||||||
if (*this->door_state == DoorState::DOOR_STATE_OPENING) {
|
if (*this->door_state == DoorState::OPENING) {
|
||||||
return; // gets ignored by opener
|
return; // gets ignored by opener
|
||||||
}
|
}
|
||||||
this->cancel_position_sync_callbacks();
|
this->cancel_position_sync_callbacks();
|
||||||
|
|
||||||
door_command(data::DOOR_TOGGLE);
|
this->door_command(data::DOOR_TOGGLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RATGDOComponent::position_sync_while_opening(float delta, float update_period)
|
void RATGDOComponent::position_sync_while_opening(float delta, float update_period)
|
||||||
|
@ -563,7 +516,7 @@ namespace ratgdo {
|
||||||
|
|
||||||
void RATGDOComponent::door_move_to_position(float position)
|
void RATGDOComponent::door_move_to_position(float position)
|
||||||
{
|
{
|
||||||
if (*this->door_state == DoorState::DOOR_STATE_OPENING || *this->door_state == DoorState::DOOR_STATE_CLOSING) {
|
if (*this->door_state == DoorState::OPENING || *this->door_state == DoorState::CLOSING) {
|
||||||
ESP_LOGW(TAG, "The door is moving, ignoring.");
|
ESP_LOGW(TAG, "The door is moving, ignoring.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -581,11 +534,11 @@ namespace ratgdo {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (delta > 0) { // open
|
if (delta > 0) { // open
|
||||||
door_command(data::DOOR_OPEN);
|
this->door_command(data::DOOR_OPEN);
|
||||||
this->position_sync_while_opening(delta);
|
this->position_sync_while_opening(delta);
|
||||||
} else { // close
|
} else { // close
|
||||||
delta = -delta;
|
delta = -delta;
|
||||||
door_command(data::DOOR_CLOSE);
|
this->door_command(data::DOOR_CLOSE);
|
||||||
this->position_sync_while_closing(delta);
|
this->position_sync_while_closing(delta);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -593,7 +546,7 @@ namespace ratgdo {
|
||||||
ESP_LOGD(TAG, "Moving to position %.2f in %.1fs", position, operation_time / 1000.0);
|
ESP_LOGD(TAG, "Moving to position %.2f in %.1fs", position, operation_time / 1000.0);
|
||||||
this->moving_to_position = true;
|
this->moving_to_position = true;
|
||||||
set_timeout("move_to_position", operation_time, [=] {
|
set_timeout("move_to_position", operation_time, [=] {
|
||||||
door_command(data::DOOR_STOP);
|
this->door_command(data::DOOR_STOP);
|
||||||
this->moving_to_position = false;
|
this->moving_to_position = false;
|
||||||
this->door_position = position;
|
this->door_position = position;
|
||||||
});
|
});
|
||||||
|
@ -613,48 +566,48 @@ namespace ratgdo {
|
||||||
{
|
{
|
||||||
data |= (1 << 16); // button 1 ?
|
data |= (1 << 16); // button 1 ?
|
||||||
data |= (1 << 8); // button press
|
data |= (1 << 8); // button press
|
||||||
transmit(command::OPEN, data, false);
|
this->transmit(Command::OPEN, data, false);
|
||||||
set_timeout(100, [=] {
|
set_timeout(100, [=] {
|
||||||
auto data2 = data & ~(1 << 8); // button release
|
auto data2 = data & ~(1 << 8); // button release
|
||||||
transmit(command::OPEN, data2);
|
this->transmit(Command::OPEN, data2);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void RATGDOComponent::light_on()
|
void RATGDOComponent::light_on()
|
||||||
{
|
{
|
||||||
this->light_state = LightState::LIGHT_STATE_ON;
|
this->light_state = LightState::ON;
|
||||||
transmit(command::LIGHT, data::LIGHT_ON);
|
this->transmit(Command::LIGHT, data::LIGHT_ON);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RATGDOComponent::light_off()
|
void RATGDOComponent::light_off()
|
||||||
{
|
{
|
||||||
this->light_state = LightState::LIGHT_STATE_OFF;
|
this->light_state = LightState::OFF;
|
||||||
transmit(command::LIGHT, data::LIGHT_OFF);
|
this->transmit(Command::LIGHT, data::LIGHT_OFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RATGDOComponent::toggle_light()
|
void RATGDOComponent::toggle_light()
|
||||||
{
|
{
|
||||||
this->light_state = light_state_toggle(*this->light_state);
|
this->light_state = light_state_toggle(*this->light_state);
|
||||||
transmit(command::LIGHT, data::LIGHT_TOGGLE);
|
this->transmit(Command::LIGHT, data::LIGHT_TOGGLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lock functions
|
// Lock functions
|
||||||
void RATGDOComponent::lock()
|
void RATGDOComponent::lock()
|
||||||
{
|
{
|
||||||
this->lock_state = LockState::LOCK_STATE_LOCKED;
|
this->lock_state = LockState::LOCKED;
|
||||||
transmit(command::LOCK, data::LOCK_ON);
|
this->transmit(Command::LOCK, data::LOCK_ON);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RATGDOComponent::unlock()
|
void RATGDOComponent::unlock()
|
||||||
{
|
{
|
||||||
this->lock_state = LockState::LOCK_STATE_UNLOCKED;
|
this->lock_state = LockState::UNLOCKED;
|
||||||
transmit(command::LOCK, data::LOCK_OFF);
|
this->transmit(Command::LOCK, data::LOCK_OFF);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RATGDOComponent::toggle_lock()
|
void RATGDOComponent::toggle_lock()
|
||||||
{
|
{
|
||||||
this->lock_state = lock_state_toggle(*this->lock_state);
|
this->lock_state = lock_state_toggle(*this->lock_state);
|
||||||
transmit(command::LOCK, data::LOCK_TOGGLE);
|
this->transmit(Command::LOCK, data::LOCK_TOGGLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RATGDOComponent::save_rolling_code_counter()
|
void RATGDOComponent::save_rolling_code_counter()
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "SoftwareSerial.h" // Using espsoftwareserial https://github.com/plerup/espsoftwareserial
|
#include "SoftwareSerial.h" // Using espsoftwareserial https://github.com/plerup/espsoftwareserial
|
||||||
|
#include "enum.h"
|
||||||
#include "esphome/core/component.h"
|
#include "esphome/core/component.h"
|
||||||
#include "esphome/core/gpio.h"
|
#include "esphome/core/gpio.h"
|
||||||
#include "esphome/core/log.h"
|
#include "esphome/core/log.h"
|
||||||
|
@ -25,6 +26,7 @@ extern "C" {
|
||||||
|
|
||||||
#include "ratgdo_state.h"
|
#include "ratgdo_state.h"
|
||||||
|
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace ratgdo {
|
namespace ratgdo {
|
||||||
|
|
||||||
|
@ -36,34 +38,6 @@ namespace ratgdo {
|
||||||
|
|
||||||
const float DOOR_POSITION_UNKNOWN = -1.0;
|
const float DOOR_POSITION_UNKNOWN = -1.0;
|
||||||
|
|
||||||
/*
|
|
||||||
from: https://github.com/argilo/secplus/blob/f98c3220356c27717a25102c0b35815ebbd26ccc/secplus.py#L540
|
|
||||||
_WIRELINE_COMMANDS = {
|
|
||||||
# sent by opener
|
|
||||||
0x081: "status",
|
|
||||||
0x084: "unknown_1",
|
|
||||||
0x085: "unknown_2",
|
|
||||||
0x0a1: "pair_3_resp",
|
|
||||||
0x284: "motor_on",
|
|
||||||
0x393: "learn_3_resp",
|
|
||||||
0x401: "pair_2_resp",
|
|
||||||
0x48c: "openings",
|
|
||||||
|
|
||||||
# sent by switch
|
|
||||||
0x080: "get_status",
|
|
||||||
0x0a0: "pair_3",
|
|
||||||
0x181: "learn_2",
|
|
||||||
0x18c: "lock",
|
|
||||||
0x280: "open",
|
|
||||||
0x281: "light",
|
|
||||||
0x285: "motion",
|
|
||||||
0x391: "learn_1",
|
|
||||||
0x392: "learn_3",
|
|
||||||
0x400: "pair_2",
|
|
||||||
0x48b: "get_openings",
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
namespace data {
|
namespace data {
|
||||||
const uint32_t LIGHT_OFF = 0;
|
const uint32_t LIGHT_OFF = 0;
|
||||||
const uint32_t LIGHT_ON = 1;
|
const uint32_t LIGHT_ON = 1;
|
||||||
|
@ -80,36 +54,37 @@ namespace ratgdo {
|
||||||
const uint32_t DOOR_STOP = 3;
|
const uint32_t DOOR_STOP = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace command {
|
ENUM(Command, uint16_t,
|
||||||
|
(UNKNOWN, 0x000),
|
||||||
|
(GET_STATUS, 0x080),
|
||||||
|
(STATUS, 0x081),
|
||||||
|
(OBST_1, 0x084), // sent when an obstruction happens?
|
||||||
|
(OBST_2, 0x085), // sent when an obstruction happens?
|
||||||
|
(PAIR_3, 0x0a0),
|
||||||
|
(PAIR_3_RESP, 0x0a1),
|
||||||
|
|
||||||
enum cmd : uint64_t {
|
(LEARN_2, 0x181),
|
||||||
GET_STATUS = 0x080,
|
(LOCK, 0x18c),
|
||||||
STATUS = 0x081,
|
(OPEN, 0x280),
|
||||||
OBST_1 = 0x084, // sent when an obstruction happens?
|
(LIGHT, 0x281),
|
||||||
OBST_2 = 0x085, // sent when an obstruction happens?
|
(MOTOR_ON, 0x284),
|
||||||
PAIR_3 = 0x0a0,
|
(MOTION, 0x285),
|
||||||
PAIR_3_RESP = 0x0a1,
|
|
||||||
|
|
||||||
LEARN_2 = 0x181,
|
(LEARN_1, 0x391),
|
||||||
LOCK = 0x18c,
|
(PING, 0x392),
|
||||||
|
(PING_RESP, 0x393),
|
||||||
|
|
||||||
OPEN = 0x280,
|
(PAIR_2, 0x400),
|
||||||
LIGHT = 0x281,
|
(PAIR_2_RESP, 0x401),
|
||||||
MOTOR_ON = 0x284,
|
(SET_TTC, 0x402), // ttc_in_seconds = (byte1<<8)+byte2
|
||||||
MOTION = 0x285,
|
(CANCEL_TTC, 0x408), // ?
|
||||||
|
(TTC, 0x40a), // Time to close
|
||||||
|
(GET_OPENINGS, 0x48b),
|
||||||
|
(OPENINGS, 0x48c), // openings = (byte1<<8)+byte2
|
||||||
|
)
|
||||||
|
|
||||||
LEARN_1 = 0x391,
|
inline bool operator==(const uint16_t cmd_i, const Command& cmd_e) { return cmd_i == static_cast<uint16_t>(cmd_e); }
|
||||||
LEARN_3 = 0x392,
|
inline bool operator==(const Command& cmd_e, const uint16_t cmd_i) { return cmd_i == static_cast<uint16_t>(cmd_e); }
|
||||||
LEARN_3_RESP = 0x393,
|
|
||||||
|
|
||||||
PAIR_2 = 0x400,
|
|
||||||
PAIR_2_RESP = 0x401,
|
|
||||||
TTC = 0x40a, // Time to close
|
|
||||||
GET_OPENINGS = 0x48b,
|
|
||||||
OPENINGS = 0x48c,
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
struct RATGDOStore {
|
struct RATGDOStore {
|
||||||
ISRInternalGPIOPin input_obst;
|
ISRInternalGPIOPin input_obst;
|
||||||
|
@ -126,8 +101,6 @@ namespace ratgdo {
|
||||||
void loop() override;
|
void loop() override;
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
|
|
||||||
EspSoftwareSerial::UART sw_serial;
|
|
||||||
|
|
||||||
observable<uint32_t> rolling_code_counter { 0 };
|
observable<uint32_t> rolling_code_counter { 0 };
|
||||||
|
|
||||||
float start_opening { -1 };
|
float start_opening { -1 };
|
||||||
|
@ -137,27 +110,28 @@ namespace ratgdo {
|
||||||
|
|
||||||
observable<uint16_t> openings { 0 }; // number of times the door has been opened
|
observable<uint16_t> openings { 0 }; // number of times the door has been opened
|
||||||
|
|
||||||
observable<DoorState> door_state { DoorState::DOOR_STATE_UNKNOWN };
|
observable<DoorState> door_state { DoorState::UNKNOWN };
|
||||||
observable<float> door_position { DOOR_POSITION_UNKNOWN };
|
observable<float> door_position { DOOR_POSITION_UNKNOWN };
|
||||||
bool moving_to_position { false };
|
bool moving_to_position { false };
|
||||||
|
|
||||||
observable<LightState> light_state { LightState::LIGHT_STATE_UNKNOWN };
|
observable<LightState> light_state { LightState::UNKNOWN };
|
||||||
observable<LockState> lock_state { LockState::LOCK_STATE_UNKNOWN };
|
observable<LockState> lock_state { LockState::UNKNOWN };
|
||||||
observable<ObstructionState> obstruction_state { ObstructionState::OBSTRUCTION_STATE_UNKNOWN };
|
observable<ObstructionState> obstruction_state { ObstructionState::UNKNOWN };
|
||||||
observable<MotorState> motor_state { MotorState::MOTOR_STATE_UNKNOWN };
|
observable<MotorState> motor_state { MotorState::UNKNOWN };
|
||||||
observable<ButtonState> button_state { ButtonState::BUTTON_STATE_UNKNOWN };
|
observable<ButtonState> button_state { ButtonState::UNKNOWN };
|
||||||
observable<MotionState> motion_state { MotionState::MOTION_STATE_UNKNOWN };
|
observable<MotionState> motion_state { MotionState::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; }
|
||||||
void set_input_obst_pin(InternalGPIOPin* pin) { this->input_obst_pin_ = pin; }
|
void set_input_obst_pin(InternalGPIOPin* pin) { this->input_obst_pin_ = pin; }
|
||||||
void set_remote_id(uint64_t remote_id) { this->remote_id_ = remote_id & 0xffffff; } // not sure how large remote_id can be, assuming not more than 24 bits
|
void set_remote_id(uint64_t remote_id) { this->remote_id_ = remote_id & 0xffffff; } // not sure how large remote_id can be, assuming not more than 24 bits
|
||||||
|
uint64_t get_remote_id() { return this->remote_id_; }
|
||||||
|
|
||||||
void gdo_state_loop();
|
void gdo_state_loop();
|
||||||
uint16_t decode_packet(const WirePacket& packet);
|
uint16_t decode_packet(const WirePacket& packet);
|
||||||
void obstruction_loop();
|
void obstruction_loop();
|
||||||
void transmit(command::cmd command, uint32_t data = 0, bool increment = true);
|
void transmit(Command command, uint32_t data = 0, bool increment = true);
|
||||||
void encode_packet(command::cmd command, uint32_t data, bool increment, WirePacket& packet);
|
void encode_packet(Command command, uint32_t data, bool increment, WirePacket& packet);
|
||||||
void print_packet(const WirePacket& packet) const;
|
void print_packet(const WirePacket& packet) const;
|
||||||
|
|
||||||
void increment_rolling_code_counter(int delta = 1);
|
void increment_rolling_code_counter(int delta = 1);
|
||||||
|
@ -205,12 +179,13 @@ namespace ratgdo {
|
||||||
void subscribe_motor_state(std::function<void(MotorState)>&& f);
|
void subscribe_motor_state(std::function<void(MotorState)>&& f);
|
||||||
void subscribe_button_state(std::function<void(ButtonState)>&& f);
|
void subscribe_button_state(std::function<void(ButtonState)>&& f);
|
||||||
void subscribe_motion_state(std::function<void(MotionState)>&& f);
|
void subscribe_motion_state(std::function<void(MotionState)>&& f);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ESPPreferenceObject rolling_code_counter_pref_;
|
ESPPreferenceObject rolling_code_counter_pref_;
|
||||||
ESPPreferenceObject opening_duration_pref_;
|
ESPPreferenceObject opening_duration_pref_;
|
||||||
ESPPreferenceObject closing_duration_pref_;
|
ESPPreferenceObject closing_duration_pref_;
|
||||||
RATGDOStore isr_store_ {};
|
RATGDOStore isr_store_ {};
|
||||||
|
SoftwareSerial sw_serial_;
|
||||||
|
|
||||||
InternalGPIOPin* output_gdo_pin_;
|
InternalGPIOPin* output_gdo_pin_;
|
||||||
InternalGPIOPin* input_gdo_pin_;
|
InternalGPIOPin* input_gdo_pin_;
|
||||||
|
|
|
@ -1,132 +1,33 @@
|
||||||
#include "ratgdo_state.h"
|
#include "ratgdo_state.h"
|
||||||
|
|
||||||
#include "esphome/core/log.h"
|
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace ratgdo {
|
namespace ratgdo {
|
||||||
|
|
||||||
const char* door_state_to_string(DoorState state)
|
|
||||||
{
|
|
||||||
switch (state) {
|
|
||||||
case DOOR_STATE_OPEN:
|
|
||||||
return "OPEN";
|
|
||||||
case DOOR_STATE_CLOSED:
|
|
||||||
return "CLOSED";
|
|
||||||
case DOOR_STATE_STOPPED:
|
|
||||||
return "STOPPED";
|
|
||||||
case DOOR_STATE_OPENING:
|
|
||||||
return "OPENING";
|
|
||||||
case DOOR_STATE_CLOSING:
|
|
||||||
return "CLOSING";
|
|
||||||
case DOOR_STATE_UNKNOWN:
|
|
||||||
default:
|
|
||||||
return "UNKNOWN";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* light_state_to_string(LightState state)
|
|
||||||
{
|
|
||||||
switch (state) {
|
|
||||||
case LIGHT_STATE_OFF:
|
|
||||||
return "OFF";
|
|
||||||
case LIGHT_STATE_ON:
|
|
||||||
return "ON";
|
|
||||||
// 2 and 3 appears sometimes
|
|
||||||
case LIGHT_STATE_UNKNOWN:
|
|
||||||
default:
|
|
||||||
return "UNKNOWN";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LightState light_state_toggle(LightState state)
|
LightState light_state_toggle(LightState state)
|
||||||
{
|
{
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case LIGHT_STATE_OFF:
|
case LightState::OFF:
|
||||||
return LIGHT_STATE_ON;
|
return LightState::ON;
|
||||||
case LIGHT_STATE_ON:
|
case LightState::ON:
|
||||||
return LIGHT_STATE_OFF;
|
return LightState::OFF;
|
||||||
// 2 and 3 appears sometimes
|
// 2 and 3 appears sometimes
|
||||||
case LIGHT_STATE_UNKNOWN:
|
case LightState::UNKNOWN:
|
||||||
default:
|
default:
|
||||||
return LIGHT_STATE_UNKNOWN;
|
return LightState::UNKNOWN;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* lock_state_to_string(LockState state)
|
|
||||||
{
|
|
||||||
switch (state) {
|
|
||||||
case LOCK_STATE_UNLOCKED:
|
|
||||||
return "UNLOCKED";
|
|
||||||
case LOCK_STATE_LOCKED:
|
|
||||||
return "LOCKED";
|
|
||||||
case LOCK_STATE_UNKNOWN:
|
|
||||||
default:
|
|
||||||
return "UNKNOWN";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
LockState lock_state_toggle(LockState state)
|
LockState lock_state_toggle(LockState state)
|
||||||
{
|
{
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case LOCK_STATE_UNLOCKED:
|
case LockState::UNLOCKED:
|
||||||
return LOCK_STATE_LOCKED;
|
return LockState::LOCKED;
|
||||||
case LOCK_STATE_LOCKED:
|
case LockState::LOCKED:
|
||||||
return LOCK_STATE_UNLOCKED;
|
return LockState::UNLOCKED;
|
||||||
// 2 and 3 appears sometimes
|
// 2 and 3 appears sometimes
|
||||||
case LOCK_STATE_UNKNOWN:
|
case LockState::UNKNOWN:
|
||||||
default:
|
default:
|
||||||
return LOCK_STATE_UNKNOWN;
|
return LockState::UNKNOWN;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* motion_state_to_string(MotionState state)
|
|
||||||
{
|
|
||||||
switch (state) {
|
|
||||||
case MOTION_STATE_CLEAR:
|
|
||||||
return "CLEAR";
|
|
||||||
case MOTION_STATE_DETECTED:
|
|
||||||
return "DETECTED";
|
|
||||||
case MOTION_STATE_UNKNOWN:
|
|
||||||
default:
|
|
||||||
return "UNKNOWN";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* motor_state_to_string(MotorState state)
|
|
||||||
{
|
|
||||||
switch (state) {
|
|
||||||
case MOTOR_STATE_ON:
|
|
||||||
return "ON";
|
|
||||||
case MOTOR_STATE_OFF:
|
|
||||||
return "OFF";
|
|
||||||
default:
|
|
||||||
return "UNKNOWN";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* obstruction_state_to_string(ObstructionState state)
|
|
||||||
{
|
|
||||||
switch (state) {
|
|
||||||
case OBSTRUCTION_STATE_CLEAR:
|
|
||||||
return "CLEAR";
|
|
||||||
case OBSTRUCTION_STATE_OBSTRUCTED:
|
|
||||||
return "OBSTRUCTED";
|
|
||||||
case OBSTRUCTION_STATE_UNKNOWN:
|
|
||||||
default:
|
|
||||||
return "UNKNOWN";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const char* button_state_to_string(ButtonState state)
|
|
||||||
{
|
|
||||||
switch (state) {
|
|
||||||
case BUTTON_STATE_PRESSED:
|
|
||||||
return "PRESSED";
|
|
||||||
case BUTTON_STATE_RELEASED:
|
|
||||||
return "RELEASED";
|
|
||||||
case BUTTON_STATE_UNKNOWN:
|
|
||||||
default:
|
|
||||||
return "UNKNOWN";
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,74 +12,57 @@
|
||||||
************************************/
|
************************************/
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "esphome/core/component.h"
|
#include "enum.h"
|
||||||
#include "esphome/core/gpio.h"
|
#include <cstdint>
|
||||||
#include "esphome/core/log.h"
|
|
||||||
#include "esphome/core/preferences.h"
|
|
||||||
|
|
||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace ratgdo {
|
namespace ratgdo {
|
||||||
|
|
||||||
/// Enum for all states a the door can be in.
|
ENUM(DoorState, uint8_t,
|
||||||
enum DoorState : uint8_t {
|
(UNKNOWN, 0),
|
||||||
DOOR_STATE_UNKNOWN = 0,
|
(OPEN, 1),
|
||||||
DOOR_STATE_OPEN = 1,
|
(CLOSED, 2),
|
||||||
DOOR_STATE_CLOSED = 2,
|
(STOPPED, 3),
|
||||||
DOOR_STATE_STOPPED = 3,
|
(OPENING, 4),
|
||||||
DOOR_STATE_OPENING = 4,
|
(CLOSING, 5))
|
||||||
DOOR_STATE_CLOSING = 5
|
|
||||||
};
|
|
||||||
const char* door_state_to_string(DoorState state);
|
|
||||||
|
|
||||||
/// Enum for all states a the light can be in.
|
/// Enum for all states a the light can be in.
|
||||||
enum LightState : uint8_t {
|
ENUM(LightState, uint8_t,
|
||||||
LIGHT_STATE_OFF = 0,
|
(OFF, 0),
|
||||||
LIGHT_STATE_ON = 1,
|
(ON, 1),
|
||||||
LIGHT_STATE_UNKNOWN = 2,
|
(UNKNOWN, 2))
|
||||||
};
|
|
||||||
const char* light_state_to_string(LightState state);
|
|
||||||
LightState light_state_toggle(LightState state);
|
LightState light_state_toggle(LightState state);
|
||||||
|
|
||||||
/// Enum for all states a the lock can be in.
|
/// Enum for all states a the lock can be in.
|
||||||
enum LockState : uint8_t {
|
ENUM(LockState, uint8_t,
|
||||||
LOCK_STATE_UNLOCKED = 0,
|
(UNLOCKED, 0),
|
||||||
LOCK_STATE_LOCKED = 1,
|
(LOCKED, 1),
|
||||||
LOCK_STATE_UNKNOWN = 2,
|
(UNKNOWN, 2))
|
||||||
};
|
|
||||||
const char* lock_state_to_string(LockState state);
|
|
||||||
LockState lock_state_toggle(LockState state);
|
LockState lock_state_toggle(LockState state);
|
||||||
|
|
||||||
/// Enum for all states a the motion can be in.
|
/// MotionState for all states a the motion can be in.
|
||||||
enum MotionState : uint8_t {
|
ENUM(MotionState, uint8_t,
|
||||||
MOTION_STATE_CLEAR = 0,
|
(CLEAR, 0),
|
||||||
MOTION_STATE_DETECTED = 1,
|
(DETECTED, 1),
|
||||||
MOTION_STATE_UNKNOWN = 2,
|
(UNKNOWN, 2))
|
||||||
};
|
|
||||||
const char* motion_state_to_string(MotionState state);
|
|
||||||
|
|
||||||
/// Enum for all states a the obstruction can be in.
|
/// Enum for all states a the obstruction can be in.
|
||||||
enum ObstructionState : uint8_t {
|
ENUM(ObstructionState, uint8_t,
|
||||||
OBSTRUCTION_STATE_OBSTRUCTED = 0,
|
(OBSTRUCTED, 0),
|
||||||
OBSTRUCTION_STATE_CLEAR = 1,
|
(CLEAR, 1),
|
||||||
OBSTRUCTION_STATE_UNKNOWN = 2,
|
(UNKNOWN, 2))
|
||||||
};
|
|
||||||
const char* obstruction_state_to_string(ObstructionState state);
|
|
||||||
|
|
||||||
/// Enum for all states a the motor can be in.
|
/// Enum for all states a the motor can be in.
|
||||||
enum MotorState : uint8_t {
|
ENUM(MotorState, uint8_t,
|
||||||
MOTOR_STATE_OFF = 0,
|
(OFF, 0),
|
||||||
MOTOR_STATE_ON = 1,
|
(ON, 1),
|
||||||
MOTOR_STATE_UNKNOWN = 2,
|
(UNKNOWN, 2))
|
||||||
};
|
|
||||||
const char* motor_state_to_string(MotorState state);
|
|
||||||
|
|
||||||
/// Enum for all states the button can be in.
|
/// Enum for all states the button can be in.
|
||||||
enum ButtonState : uint8_t {
|
ENUM(ButtonState, uint8_t,
|
||||||
BUTTON_STATE_PRESSED = 0,
|
(PRESSED, 0),
|
||||||
BUTTON_STATE_RELEASED = 1,
|
(RELEASED, 1),
|
||||||
BUTTON_STATE_UNKNOWN = 2,
|
(UNKNOWN, 2))
|
||||||
};
|
|
||||||
const char* button_state_to_string(ButtonState state);
|
|
||||||
|
|
||||||
} // namespace ratgdo
|
} // namespace ratgdo
|
||||||
} // namespace esphome
|
} // namespace esphome
|
|
@ -22,7 +22,7 @@ namespace ratgdo {
|
||||||
|
|
||||||
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::LOCKED;
|
||||||
this->state = value;
|
this->state = value;
|
||||||
this->publish_state(value);
|
this->publish_state(value);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue