diff --git a/components/ratgdo/binary_sensor/ratgdo_binary_sensor.cpp b/components/ratgdo/binary_sensor/ratgdo_binary_sensor.cpp index a1c3915..456058c 100644 --- a/components/ratgdo/binary_sensor/ratgdo_binary_sensor.cpp +++ b/components/ratgdo/binary_sensor/ratgdo_binary_sensor.cpp @@ -12,21 +12,21 @@ namespace ratgdo { if (this->binary_sensor_type_ == SensorType::RATGDO_SENSOR_MOTION) { this->publish_initial_state(false); 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) { this->publish_initial_state(false); 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) { 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) { this->publish_initial_state(false); this->parent_->subscribe_button_state([=](ButtonState state) { - this->publish_state(state == ButtonState::BUTTON_STATE_PRESSED); + this->publish_state(state == ButtonState::PRESSED); }); } } diff --git a/components/ratgdo/cover/ratgdo_cover.cpp b/components/ratgdo/cover/ratgdo_cover.cpp index 0240c27..6fce621 100644 --- a/components/ratgdo/cover/ratgdo_cover.cpp +++ b/components/ratgdo/cover/ratgdo_cover.cpp @@ -24,26 +24,26 @@ namespace ratgdo { void RATGDOCover::on_door_state(DoorState state, float position) { switch (state) { - case DoorState::DOOR_STATE_OPEN: + case DoorState::OPEN: this->position = COVER_OPEN; this->current_operation = COVER_OPERATION_IDLE; break; - case DoorState::DOOR_STATE_CLOSED: + case DoorState::CLOSED: this->position = COVER_CLOSED; this->current_operation = COVER_OPERATION_IDLE; break; - case DoorState::DOOR_STATE_OPENING: + case DoorState::OPENING: this->current_operation = COVER_OPERATION_OPENING; this->position = position; break; - case DoorState::DOOR_STATE_CLOSING: + case DoorState::CLOSING: this->current_operation = COVER_OPERATION_CLOSING; this->position = position; break; - case DoorState::DOOR_STATE_STOPPED: + case DoorState::STOPPED: this->current_operation = COVER_OPERATION_IDLE; this->position = position; - case DoorState::DOOR_STATE_UNKNOWN: + case DoorState::UNKNOWN: default: this->current_operation = COVER_OPERATION_IDLE; this->position = position; diff --git a/components/ratgdo/enum.h b/components/ratgdo/enum.h new file mode 100644 index 0000000..db090af --- /dev/null +++ b/components/ratgdo/enum.h @@ -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; \ + } \ + } diff --git a/components/ratgdo/light/ratgdo_light_output.cpp b/components/ratgdo/light/ratgdo_light_output.cpp index 976997b..9c44b91 100644 --- a/components/ratgdo/light/ratgdo_light_output.cpp +++ b/components/ratgdo/light/ratgdo_light_output.cpp @@ -32,7 +32,7 @@ namespace ratgdo { 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_->remote_values.set_state(is_on); this->light_state_->publish_state(); diff --git a/components/ratgdo/number/ratgdo_number.cpp b/components/ratgdo/number/ratgdo_number.cpp index 4acf4fd..276b6c5 100644 --- a/components/ratgdo/number/ratgdo_number.cpp +++ b/components/ratgdo/number/ratgdo_number.cpp @@ -44,6 +44,9 @@ namespace ratgdo { this->traits.set_min_value(0.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) diff --git a/components/ratgdo/ratgdo.cpp b/components/ratgdo/ratgdo.cpp index 20db09a..673971a 100644 --- a/components/ratgdo/ratgdo.cpp +++ b/components/ratgdo/ratgdo.cpp @@ -73,7 +73,7 @@ namespace ratgdo { this->input_gdo_pin_->pin_mode(gpio::FLAG_INPUT | gpio::FLAG_PULLUP); 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); @@ -85,8 +85,8 @@ namespace ratgdo { void RATGDOComponent::loop() { - obstruction_loop(); - gdo_state_loop(); + this->obstruction_loop(); + this->gdo_state_loop(); } void RATGDOComponent::dump_config() @@ -99,58 +99,6 @@ namespace ratgdo { 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) { uint32_t rolling = 0; @@ -161,10 +109,12 @@ namespace ratgdo { uint16_t cmd = ((fixed >> 24) & 0xf00) | (data & 0xff); 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); - return 0; + return static_cast(Command::UNKNOWN); } else { 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 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(nibble); + auto door_state = to_DoorState(nibble, DoorState::UNKNOWN); 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(); } - 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) { auto duration = (millis() - this->start_opening) / 1000; duration = *this->opening_duration > 0 ? (duration + *this->opening_duration) / 2 : duration; 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(); } - 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) { auto duration = (millis() - this->start_closing) / 1000; duration = *this->closing_duration > 0 ? (duration + *this->closing_duration) / 2 : duration; 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_closing = -1; } - if (door_state == DoorState::DOOR_STATE_OPEN) { + if (door_state == DoorState::OPEN) { this->door_position = 1.0; - } else if (door_state == DoorState::DOOR_STATE_CLOSED) { + } else if (door_state == DoorState::CLOSED) { this->door_position = 0.0; } else { 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->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->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->door_state = door_state; - this->light_state = static_cast((byte2 >> 1) & 1); - this->lock_state = static_cast(byte2 & 1); - this->motion_state = MotionState::MOTION_STATE_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->light_state = static_cast((byte2 >> 1) & 1); // safe because it can only be 0 or 1 + this->lock_state = static_cast(byte2 & 1); // safe because it can only be 0 or 1 + this->motion_state = MotionState::CLEAR; // when the status message is read, reset motion state to 0|clear + this->motor_state = MotorState::OFF; // when the status message is read, reset motor state to 0|off // this->obstruction_state = static_cast((byte1 >> 6) & 1); - if (door_state == DoorState::DOOR_STATE_CLOSED && door_state != prev_door_state) { - transmit(command::GET_OPENINGS); + if (door_state == DoorState::CLOSED && door_state != prev_door_state) { + this->transmit(Command::GET_OPENINGS); } ESP_LOGD(TAG, "Status: door=%s light=%s lock=%s", - door_state_to_string(*this->door_state), - light_state_to_string(*this->light_state), - lock_state_to_string(*this->lock_state)); - } else if (cmd == command::LIGHT) { + DoorState_to_string(*this->door_state), + LightState_to_string(*this->light_state), + LockState_to_string(*this->lock_state)); + } else if (cmd == Command::LIGHT) { if (nibble == 0) { - this->light_state = LightState::LIGHT_STATE_OFF; + this->light_state = LightState::OFF; } else if (nibble == 1) { - this->light_state = LightState::LIGHT_STATE_ON; + this->light_state = LightState::ON; } else if (nibble == 2) { // toggle this->light_state = light_state_toggle(*this->light_state); } ESP_LOGD(TAG, "Light: action=%s state=%s", nibble == 0 ? "OFF" : nibble == 1 ? "ON" : "TOGGLE", - light_state_to_string(*this->light_state)); - } else if (cmd == command::MOTOR_ON) { - this->motor_state = MotorState::MOTOR_STATE_ON; - ESP_LOGD(TAG, "Motor: state=%s", motor_state_to_string(*this->motor_state)); - } else if (cmd == command::OPEN) { - this->button_state = (byte1 & 1) == 1 ? ButtonState::BUTTON_STATE_PRESSED : ButtonState::BUTTON_STATE_RELEASED; - ESP_LOGD(TAG, "Open: button=%s", button_state_to_string(*this->button_state)); - } else if (cmd == command::OPENINGS) { + LightState_to_string(*this->light_state)); + } else if (cmd == Command::MOTOR_ON) { + this->motor_state = MotorState::ON; + ESP_LOGD(TAG, "Motor: state=%s", MotorState_to_string(*this->motor_state)); + } else if (cmd == Command::OPEN) { + this->button_state = (byte1 & 1) == 1 ? ButtonState::PRESSED : ButtonState::RELEASED; + ESP_LOGD(TAG, "Open: button=%s", ButtonState_to_string(*this->button_state)); + } else if (cmd == Command::OPENINGS) { this->openings = (byte1 << 8) | byte2; ESP_LOGD(TAG, "Openings: %d", *this->openings); - } else if (cmd == command::MOTION) { - this->motion_state = MotionState::MOTION_STATE_DETECTED; - if (*this->light_state == LightState::LIGHT_STATE_OFF) { - transmit(command::GET_STATUS); + } else if (cmd == Command::MOTION) { + this->motion_state = MotionState::DETECTED; + if (*this->light_state == LightState::OFF) { + this->transmit(Command::GET_STATUS); } - ESP_LOGD(TAG, "Motion: %s", motion_state_to_string(*this->motion_state)); - } else { - 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); + ESP_LOGD(TAG, "Motion: %s", MotionState_to_string(*this->motion_state)); + } else if (cmd == Command::SET_TTC) { + auto seconds = (byte1 << 8) | byte2; + ESP_LOGD(TAG, "Time to close (TTC): %ds", seconds); } + 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_; - uint32_t send_data = (data << 8) | (command & 0xff); + auto cmd = static_cast(command); + 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); encode_wireline(*this->rolling_code_counter, fixed, send_data, packet); - print_packet(packet); + this->print_packet(packet); 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 if (this->isr_store_.obstruction_low_count >= 3 && this->isr_store_.obstruction_low_count <= 8) { // 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 } 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 (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(); } else { // asleep @@ -393,8 +346,8 @@ namespace ratgdo { static WirePacket rx_packet; if (!reading_msg) { - while (this->sw_serial.available()) { - uint8_t ser_byte = this->sw_serial.read(); + while (this->sw_serial_.available()) { + uint8_t ser_byte = this->sw_serial_.read(); if (ser_byte != 0x55 && ser_byte != 0x01 && ser_byte != 0x00) { byte_count = 0; continue; @@ -414,15 +367,15 @@ namespace ratgdo { } } if (reading_msg) { - while (this->sw_serial.available()) { - uint8_t ser_byte = this->sw_serial.read(); + while (this->sw_serial_.available()) { + uint8_t ser_byte = this->sw_serial_.read(); rx_packet[byte_count] = ser_byte; byte_count++; if (byte_count == PACKET_LENGTH) { reading_msg = false; byte_count = 0; - decode_packet(rx_packet); + this->decode_packet(rx_packet); return; } } @@ -431,12 +384,12 @@ namespace ratgdo { void RATGDOComponent::query_status() { - transmit(command::GET_STATUS); + transmit(Command::GET_STATUS); } void RATGDOComponent::query_openings() { - transmit(command::GET_OPENINGS); + transmit(Command::GET_OPENINGS); } /************************* DOOR COMMUNICATION *************************/ @@ -448,20 +401,20 @@ namespace ratgdo { * The opener requires a specific duration low/high pulse before it will accept * 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; - 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 // door opener responds to the message delayMicroseconds(1305); this->output_gdo_pin_->digital_write(false); // bring the line low 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() @@ -471,15 +424,15 @@ namespace ratgdo { set_retry( 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 return RetryResult::DONE; } else { - transmit(command::GET_OPENINGS); + this->transmit(Command::GET_OPENINGS); return RetryResult::RETRY; } } else { - transmit(command::GET_STATUS); + this->transmit(Command::GET_STATUS); return RetryResult::RETRY; } }, @@ -488,41 +441,41 @@ namespace ratgdo { void RATGDOComponent::open_door() { - if (*this->door_state == DoorState::DOOR_STATE_OPENING) { + if (*this->door_state == DoorState::OPENING) { return; // gets ignored by opener } this->cancel_position_sync_callbacks(); - door_command(data::DOOR_OPEN); + this->door_command(data::DOOR_OPEN); } 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 } this->cancel_position_sync_callbacks(); - door_command(data::DOOR_CLOSE); + this->door_command(data::DOOR_CLOSE); } 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."); return; } - door_command(data::DOOR_STOP); + this->door_command(data::DOOR_STOP); } void RATGDOComponent::toggle_door() { - if (*this->door_state == DoorState::DOOR_STATE_OPENING) { + if (*this->door_state == DoorState::OPENING) { return; // gets ignored by opener } 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) @@ -563,7 +516,7 @@ namespace ratgdo { 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."); return; } @@ -581,11 +534,11 @@ namespace ratgdo { } if (delta > 0) { // open - door_command(data::DOOR_OPEN); + this->door_command(data::DOOR_OPEN); this->position_sync_while_opening(delta); } else { // close delta = -delta; - door_command(data::DOOR_CLOSE); + this->door_command(data::DOOR_CLOSE); 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); this->moving_to_position = true; set_timeout("move_to_position", operation_time, [=] { - door_command(data::DOOR_STOP); + this->door_command(data::DOOR_STOP); this->moving_to_position = false; this->door_position = position; }); @@ -613,48 +566,48 @@ namespace ratgdo { { data |= (1 << 16); // button 1 ? data |= (1 << 8); // button press - transmit(command::OPEN, data, false); + this->transmit(Command::OPEN, data, false); set_timeout(100, [=] { auto data2 = data & ~(1 << 8); // button release - transmit(command::OPEN, data2); + this->transmit(Command::OPEN, data2); }); } void RATGDOComponent::light_on() { - this->light_state = LightState::LIGHT_STATE_ON; - transmit(command::LIGHT, data::LIGHT_ON); + this->light_state = LightState::ON; + this->transmit(Command::LIGHT, data::LIGHT_ON); } void RATGDOComponent::light_off() { - this->light_state = LightState::LIGHT_STATE_OFF; - transmit(command::LIGHT, data::LIGHT_OFF); + this->light_state = LightState::OFF; + this->transmit(Command::LIGHT, data::LIGHT_OFF); } void RATGDOComponent::toggle_light() { this->light_state = light_state_toggle(*this->light_state); - transmit(command::LIGHT, data::LIGHT_TOGGLE); + this->transmit(Command::LIGHT, data::LIGHT_TOGGLE); } // Lock functions void RATGDOComponent::lock() { - this->lock_state = LockState::LOCK_STATE_LOCKED; - transmit(command::LOCK, data::LOCK_ON); + this->lock_state = LockState::LOCKED; + this->transmit(Command::LOCK, data::LOCK_ON); } void RATGDOComponent::unlock() { - this->lock_state = LockState::LOCK_STATE_UNLOCKED; - transmit(command::LOCK, data::LOCK_OFF); + this->lock_state = LockState::UNLOCKED; + this->transmit(Command::LOCK, data::LOCK_OFF); } void RATGDOComponent::toggle_lock() { 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() diff --git a/components/ratgdo/ratgdo.h b/components/ratgdo/ratgdo.h index b0d7e38..5583292 100644 --- a/components/ratgdo/ratgdo.h +++ b/components/ratgdo/ratgdo.h @@ -13,6 +13,7 @@ #pragma once #include "SoftwareSerial.h" // Using espsoftwareserial https://github.com/plerup/espsoftwareserial +#include "enum.h" #include "esphome/core/component.h" #include "esphome/core/gpio.h" #include "esphome/core/log.h" @@ -25,6 +26,7 @@ extern "C" { #include "ratgdo_state.h" + namespace esphome { namespace ratgdo { @@ -36,34 +38,6 @@ namespace ratgdo { 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 { const uint32_t LIGHT_OFF = 0; const uint32_t LIGHT_ON = 1; @@ -80,36 +54,37 @@ namespace ratgdo { 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 { - 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, + (LEARN_2, 0x181), + (LOCK, 0x18c), + (OPEN, 0x280), + (LIGHT, 0x281), + (MOTOR_ON, 0x284), + (MOTION, 0x285), - LEARN_2 = 0x181, - LOCK = 0x18c, + (LEARN_1, 0x391), + (PING, 0x392), + (PING_RESP, 0x393), - OPEN = 0x280, - LIGHT = 0x281, - MOTOR_ON = 0x284, - MOTION = 0x285, + (PAIR_2, 0x400), + (PAIR_2_RESP, 0x401), + (SET_TTC, 0x402), // ttc_in_seconds = (byte1<<8)+byte2 + (CANCEL_TTC, 0x408), // ? + (TTC, 0x40a), // Time to close + (GET_OPENINGS, 0x48b), + (OPENINGS, 0x48c), // openings = (byte1<<8)+byte2 + ) - LEARN_1 = 0x391, - LEARN_3 = 0x392, - LEARN_3_RESP = 0x393, - - PAIR_2 = 0x400, - PAIR_2_RESP = 0x401, - TTC = 0x40a, // Time to close - GET_OPENINGS = 0x48b, - OPENINGS = 0x48c, - - }; - } + inline bool operator==(const uint16_t cmd_i, const Command& cmd_e) { return cmd_i == static_cast(cmd_e); } + inline bool operator==(const Command& cmd_e, const uint16_t cmd_i) { return cmd_i == static_cast(cmd_e); } struct RATGDOStore { ISRInternalGPIOPin input_obst; @@ -126,8 +101,6 @@ namespace ratgdo { void loop() override; void dump_config() override; - EspSoftwareSerial::UART sw_serial; - observable rolling_code_counter { 0 }; float start_opening { -1 }; @@ -137,27 +110,28 @@ namespace ratgdo { observable openings { 0 }; // number of times the door has been opened - observable door_state { DoorState::DOOR_STATE_UNKNOWN }; + observable door_state { DoorState::UNKNOWN }; observable door_position { DOOR_POSITION_UNKNOWN }; bool moving_to_position { false }; - observable light_state { LightState::LIGHT_STATE_UNKNOWN }; - observable lock_state { LockState::LOCK_STATE_UNKNOWN }; - observable obstruction_state { ObstructionState::OBSTRUCTION_STATE_UNKNOWN }; - observable motor_state { MotorState::MOTOR_STATE_UNKNOWN }; - observable button_state { ButtonState::BUTTON_STATE_UNKNOWN }; - observable motion_state { MotionState::MOTION_STATE_UNKNOWN }; + observable light_state { LightState::UNKNOWN }; + observable lock_state { LockState::UNKNOWN }; + observable obstruction_state { ObstructionState::UNKNOWN }; + observable motor_state { MotorState::UNKNOWN }; + observable button_state { ButtonState::UNKNOWN }; + observable motion_state { MotionState::UNKNOWN }; 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_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 + uint64_t get_remote_id() { return this->remote_id_; } void gdo_state_loop(); uint16_t decode_packet(const WirePacket& packet); void obstruction_loop(); - void transmit(command::cmd command, uint32_t data = 0, bool increment = true); - void encode_packet(command::cmd command, uint32_t data, bool increment, WirePacket& packet); + void transmit(Command command, uint32_t data = 0, bool increment = true); + void encode_packet(Command command, uint32_t data, bool increment, WirePacket& packet); void print_packet(const WirePacket& packet) const; void increment_rolling_code_counter(int delta = 1); @@ -205,12 +179,13 @@ namespace ratgdo { void subscribe_motor_state(std::function&& f); void subscribe_button_state(std::function&& f); void subscribe_motion_state(std::function&& f); - + protected: ESPPreferenceObject rolling_code_counter_pref_; ESPPreferenceObject opening_duration_pref_; ESPPreferenceObject closing_duration_pref_; RATGDOStore isr_store_ {}; + SoftwareSerial sw_serial_; InternalGPIOPin* output_gdo_pin_; InternalGPIOPin* input_gdo_pin_; diff --git a/components/ratgdo/ratgdo_state.cpp b/components/ratgdo/ratgdo_state.cpp index 5dcc84e..2a6ba40 100644 --- a/components/ratgdo/ratgdo_state.cpp +++ b/components/ratgdo/ratgdo_state.cpp @@ -1,132 +1,33 @@ #include "ratgdo_state.h" -#include "esphome/core/log.h" - namespace esphome { 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) { switch (state) { - case LIGHT_STATE_OFF: - return LIGHT_STATE_ON; - case LIGHT_STATE_ON: - return LIGHT_STATE_OFF; + case LightState::OFF: + return LightState::ON; + case LightState::ON: + return LightState::OFF; // 2 and 3 appears sometimes - case LIGHT_STATE_UNKNOWN: + case LightState::UNKNOWN: default: - return LIGHT_STATE_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"; + return LightState::UNKNOWN; } } LockState lock_state_toggle(LockState state) { switch (state) { - case LOCK_STATE_UNLOCKED: - return LOCK_STATE_LOCKED; - case LOCK_STATE_LOCKED: - return LOCK_STATE_UNLOCKED; + case LockState::UNLOCKED: + return LockState::LOCKED; + case LockState::LOCKED: + return LockState::UNLOCKED; // 2 and 3 appears sometimes - case LOCK_STATE_UNKNOWN: + case LockState::UNKNOWN: default: - return LOCK_STATE_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"; + return LockState::UNKNOWN; } } diff --git a/components/ratgdo/ratgdo_state.h b/components/ratgdo/ratgdo_state.h index 434d47f..1397e95 100644 --- a/components/ratgdo/ratgdo_state.h +++ b/components/ratgdo/ratgdo_state.h @@ -12,74 +12,57 @@ ************************************/ #pragma once -#include "esphome/core/component.h" -#include "esphome/core/gpio.h" -#include "esphome/core/log.h" -#include "esphome/core/preferences.h" +#include "enum.h" +#include namespace esphome { namespace ratgdo { - /// Enum for all states a the door can be in. - enum DoorState : uint8_t { - DOOR_STATE_UNKNOWN = 0, - DOOR_STATE_OPEN = 1, - DOOR_STATE_CLOSED = 2, - DOOR_STATE_STOPPED = 3, - DOOR_STATE_OPENING = 4, - DOOR_STATE_CLOSING = 5 - }; - const char* door_state_to_string(DoorState state); + ENUM(DoorState, uint8_t, + (UNKNOWN, 0), + (OPEN, 1), + (CLOSED, 2), + (STOPPED, 3), + (OPENING, 4), + (CLOSING, 5)) /// Enum for all states a the light can be in. - enum LightState : uint8_t { - LIGHT_STATE_OFF = 0, - LIGHT_STATE_ON = 1, - LIGHT_STATE_UNKNOWN = 2, - }; - const char* light_state_to_string(LightState state); + ENUM(LightState, uint8_t, + (OFF, 0), + (ON, 1), + (UNKNOWN, 2)) LightState light_state_toggle(LightState state); /// Enum for all states a the lock can be in. - enum LockState : uint8_t { - LOCK_STATE_UNLOCKED = 0, - LOCK_STATE_LOCKED = 1, - LOCK_STATE_UNKNOWN = 2, - }; - const char* lock_state_to_string(LockState state); + ENUM(LockState, uint8_t, + (UNLOCKED, 0), + (LOCKED, 1), + (UNKNOWN, 2)) LockState lock_state_toggle(LockState state); - /// Enum for all states a the motion can be in. - enum MotionState : uint8_t { - MOTION_STATE_CLEAR = 0, - MOTION_STATE_DETECTED = 1, - MOTION_STATE_UNKNOWN = 2, - }; - const char* motion_state_to_string(MotionState state); + /// MotionState for all states a the motion can be in. + ENUM(MotionState, uint8_t, + (CLEAR, 0), + (DETECTED, 1), + (UNKNOWN, 2)) /// Enum for all states a the obstruction can be in. - enum ObstructionState : uint8_t { - OBSTRUCTION_STATE_OBSTRUCTED = 0, - OBSTRUCTION_STATE_CLEAR = 1, - OBSTRUCTION_STATE_UNKNOWN = 2, - }; - const char* obstruction_state_to_string(ObstructionState state); + ENUM(ObstructionState, uint8_t, + (OBSTRUCTED, 0), + (CLEAR, 1), + (UNKNOWN, 2)) /// Enum for all states a the motor can be in. - enum MotorState : uint8_t { - MOTOR_STATE_OFF = 0, - MOTOR_STATE_ON = 1, - MOTOR_STATE_UNKNOWN = 2, - }; - const char* motor_state_to_string(MotorState state); + ENUM(MotorState, uint8_t, + (OFF, 0), + (ON, 1), + (UNKNOWN, 2)) /// Enum for all states the button can be in. - enum ButtonState : uint8_t { - BUTTON_STATE_PRESSED = 0, - BUTTON_STATE_RELEASED = 1, - BUTTON_STATE_UNKNOWN = 2, - }; - const char* button_state_to_string(ButtonState state); + ENUM(ButtonState, uint8_t, + (PRESSED, 0), + (RELEASED, 1), + (UNKNOWN, 2)) } // namespace ratgdo } // namespace esphome \ No newline at end of file diff --git a/components/ratgdo/switch/ratgdo_switch.cpp b/components/ratgdo/switch/ratgdo_switch.cpp index 9d36bf9..c6ba4e6 100644 --- a/components/ratgdo/switch/ratgdo_switch.cpp +++ b/components/ratgdo/switch/ratgdo_switch.cpp @@ -22,7 +22,7 @@ namespace ratgdo { void RATGDOSwitch::on_lock_state(LockState state) { - bool value = state == LockState::LOCK_STATE_LOCKED; + bool value = state == LockState::LOCKED; this->state = value; this->publish_state(value); }