button
This commit is contained in:
parent
df01b002cf
commit
13f85e33e1
|
@ -75,420 +75,421 @@ namespace ratgdo {
|
||||||
ESP_LOGCONFIG(TAG, " Rolling Code Counter: %d", this->rollingCodeCounter);
|
ESP_LOGCONFIG(TAG, " Rolling Code Counter: %d", this->rollingCodeCounter);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint16_t RATGDOComponent::readRollingCode() {
|
uint16_t RATGDOComponent::readRollingCode()
|
||||||
{
|
{
|
||||||
uint32_t rolling = 0;
|
{
|
||||||
uint64_t fixed = 0;
|
uint32_t rolling = 0;
|
||||||
uint32_t data = 0;
|
uint64_t fixed = 0;
|
||||||
|
uint32_t data = 0;
|
||||||
|
|
||||||
uint16_t cmd = 0;
|
uint16_t cmd = 0;
|
||||||
uint8_t nibble = 0;
|
uint8_t nibble = 0;
|
||||||
uint8_t byte1 = 0;
|
uint8_t byte1 = 0;
|
||||||
uint8_t byte2 = 0;
|
uint8_t byte2 = 0;
|
||||||
|
|
||||||
decode_wireline(this->rxRollingCode, &rolling, &fixed, &data);
|
decode_wireline(this->rxRollingCode, &rolling, &fixed, &data);
|
||||||
|
|
||||||
cmd = ((fixed >> 24) & 0xf00) | (data & 0xff);
|
cmd = ((fixed >> 24) & 0xf00) | (data & 0xff);
|
||||||
|
|
||||||
nibble = (data >> 8) & 0xf;
|
nibble = (data >> 8) & 0xf;
|
||||||
byte1 = (data >> 16) & 0xff;
|
byte1 = (data >> 16) & 0xff;
|
||||||
byte2 = (data >> 24) & 0xff;
|
byte2 = (data >> 24) & 0xff;
|
||||||
|
|
||||||
if (cmd == STATUS_CMD) {
|
if (cmd == STATUS_CMD) {
|
||||||
this->doorState = nibble;
|
this->doorState = nibble;
|
||||||
this->lightState = (byte2 >> 1) & 1;
|
this->lightState = (byte2 >> 1) & 1;
|
||||||
this->lockState = byte2 & 1;
|
this->lockState = byte2 & 1;
|
||||||
this->motionState = MotionState::MOTION_STATE_CLEAR; // when the status message is read, reset motion state to 0|clear
|
this->motionState = MotionState::MOTION_STATE_CLEAR; // when the status message is read, reset motion state to 0|clear
|
||||||
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
|
||||||
// obstruction = (byte1 >> 6) & 1; // unreliable due to the time it takes to register an obstruction
|
// obstruction = (byte1 >> 6) & 1; // unreliable due to the time it takes to register an obstruction
|
||||||
ESP_LOGD(TAG, "Door: %d Light: %d Lock: %d Motion: %d Obstruction: %d", door, light, lock, motion, obstruction);
|
ESP_LOGD(TAG, "Door: %d Light: %d Lock: %d Motion: %d Obstruction: %d", door, light, lock, motion, obstruction);
|
||||||
|
|
||||||
} else if (cmd == 0x281) {
|
} else if (cmd == 0x281) {
|
||||||
this->lightState ^= 1; // toggle bit
|
this->lightState ^= 1; // toggle bit
|
||||||
ESP_LOGD(TAG, "Light: %d (toggle)", this->lightState);
|
ESP_LOGD(TAG, "Light: %d (toggle)", this->lightState);
|
||||||
} else if (cmd == 0x84) {
|
} else if (cmd == 0x84) {
|
||||||
ESP_LOGD(TAG, "Unknown 0x84");
|
ESP_LOGD(TAG, "Unknown 0x84");
|
||||||
} else if (cmd == 0x284) {
|
} else if (cmd == 0x284) {
|
||||||
this->motorState = MotorState::MOTOR_STATE_ON;
|
this->motorState = MotorState::MOTOR_STATE_ON;
|
||||||
} else if (cmd == 0x280) {
|
} else if (cmd == 0x280) {
|
||||||
this->buttonState = byte1 == 1 ? ButtonState::BUTTON_STATE_PRESSED : ButtonState::BUTTON_STATE_RELEASED;
|
this->buttonState = byte1 == 1 ? ButtonState::BUTTON_STATE_PRESSED : ButtonState::BUTTON_STATE_RELEASED;
|
||||||
ESP_LOGD(TAG, "Pressed: %s", byte1 == 1 ? "pressed" : "released");
|
ESP_LOGD(TAG, "Pressed: %s", byte1 == 1 ? "pressed" : "released");
|
||||||
} else if (cmd == 0x48c) {
|
} else if (cmd == 0x48c) {
|
||||||
this->openings = (byte1 << 8) | byte2;
|
this->openings = (byte1 << 8) | byte2;
|
||||||
ESP_LOGD(TAG, "Openings: %d", (byte1 << 8) | byte2);
|
ESP_LOGD(TAG, "Openings: %d", (byte1 << 8) | byte2);
|
||||||
} else if (cmd == 0x285) {
|
} else if (cmd == 0x285) {
|
||||||
this->motionState = MotionState::MOTION_STATE_DETECTED; // toggle bit
|
this->motionState = MotionState::MOTION_STATE_DETECTED; // toggle bit
|
||||||
ESP_LOGD(TAG, "Motion: %d (toggle)", motion);
|
ESP_LOGD(TAG, "Motion: %d (toggle)", motion);
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGD(TAG, "Unknown command: %04x", cmd);
|
ESP_LOGD(TAG, "Unknown command: %04x", cmd);
|
||||||
}
|
|
||||||
return cmd;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RATGDOComponent::getRollingCode(cmd command)
|
|
||||||
{
|
|
||||||
uint64_t fixed = command.fixed | REMOTE_ID;
|
|
||||||
encode_wireline(this->rollingCodeCounter, fixed, command.data, this->txRollingCode);
|
|
||||||
printRollingCode();
|
|
||||||
if (command != Command.DOOR1) { // door2 is created with same counter and should always be called after door1
|
|
||||||
incrementRollingCodeCounter();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RATGDOComponent::setRollingCodeCounter(uint32_t counter)
|
|
||||||
{
|
|
||||||
ESP_LOGD(TAG, "Set rolling code counter to %d", counter);
|
|
||||||
this->rollingCodeCounter = counter;
|
|
||||||
this->pref_.save(&this->rollingCodeCounter);
|
|
||||||
sendRollingCodeChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RATGDOComponent::incrementRollingCodeCounter()
|
|
||||||
{
|
|
||||||
ESP_LOGD(TAG, "Incrementing rolling code counter");
|
|
||||||
this->rollingCodeCounter = (this->rollingCodeCounter + 1) & 0xfffffff;
|
|
||||||
sendRollingCodeChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RATGDOComponent::sendRollingCodeChanged()
|
|
||||||
{
|
|
||||||
for (auto* child : this->children_) {
|
|
||||||
child->on_rolling_code_change(this->rollingCodeCounter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RATGDOComponent::printRollingCode()
|
|
||||||
{
|
|
||||||
ESP_LOGD(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->txRollingCode[0],
|
|
||||||
this->txRollingCode[1],
|
|
||||||
this->txRollingCode[2],
|
|
||||||
this->txRollingCode[3],
|
|
||||||
this->txRollingCode[4],
|
|
||||||
this->txRollingCode[5],
|
|
||||||
this->txRollingCode[6],
|
|
||||||
this->txRollingCode[7],
|
|
||||||
this->txRollingCode[8],
|
|
||||||
this->txRollingCode[9],
|
|
||||||
this->txRollingCode[10],
|
|
||||||
this->txRollingCode[11],
|
|
||||||
this->txRollingCode[12],
|
|
||||||
this->txRollingCode[13],
|
|
||||||
this->txRollingCode[14],
|
|
||||||
this->txRollingCode[15],
|
|
||||||
this->txRollingCode[16],
|
|
||||||
this->txRollingCode[17],
|
|
||||||
this->txRollingCode[18]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*************************** OBSTRUCTION DETECTION ***************************/
|
|
||||||
|
|
||||||
void RATGDOComponent::obstructionLoop()
|
|
||||||
{
|
|
||||||
long currentMillis = millis();
|
|
||||||
static unsigned long lastMillis = 0;
|
|
||||||
|
|
||||||
// the obstruction sensor has 3 states: clear (HIGH with LOW pulse every 7ms), obstructed (HIGH), asleep (LOW)
|
|
||||||
// the transitions between awake and asleep are tricky because the voltage drops slowly when falling asleep
|
|
||||||
// and is high without pulses when waking up
|
|
||||||
|
|
||||||
// If at least 3 low pulses are counted within 50ms, the door is awake, not obstructed and we don't have to check anything else
|
|
||||||
|
|
||||||
// Every 50ms
|
|
||||||
if (currentMillis - lastMillis > 50) {
|
|
||||||
// check to see if we got between 3 and 8 low pulses on the line
|
|
||||||
if (this->store_.obstructionLowCount >= 3 && this->store_.obstructionLowCount <= 8) {
|
|
||||||
// obstructionCleared();
|
|
||||||
this->obstructionState = ObstructionState::OBSTRUCTION_STATE_CLEAR;
|
|
||||||
|
|
||||||
// if there have been no pulses the line is steady high or low
|
|
||||||
} else if (this->store_.obstructionLowCount == 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() && currentMillis - this->store_.lastObstructionHigh > 70) {
|
|
||||||
this->obstructionState = ObstructionState::OBSTRUCTION_STATE_OBSTRUCTED;
|
|
||||||
// obstructionDetected();
|
|
||||||
} else {
|
|
||||||
// asleep
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return cmd;
|
||||||
lastMillis = currentMillis;
|
|
||||||
this->store_.obstructionLowCount = 0;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void RATGDOComponent::gdoStateLoop()
|
void RATGDOComponent::getRollingCode(cmd command)
|
||||||
{
|
{
|
||||||
static uint32_t msgStart;
|
uint64_t fixed = command.fixed | REMOTE_ID;
|
||||||
static bool reading = false;
|
encode_wireline(this->rollingCodeCounter, fixed, command.data, this->txRollingCode);
|
||||||
static uint16_t byteCount = 0;
|
printRollingCode();
|
||||||
static bool isStatus = false;
|
if (command != Command.DOOR1) { // door2 is created with same counter and should always be called after door1
|
||||||
|
incrementRollingCodeCounter();
|
||||||
if (!this->available()) {
|
}
|
||||||
// ESP_LOGD(TAG, "No data available input:%d output:%d", this->input_gdo_pin_->get_pin(), this->output_gdo_pin_->get_pin());
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
uint8_t serData;
|
|
||||||
if (!this->read_byte(&serData)) {
|
void RATGDOComponent::setRollingCodeCounter(uint32_t counter)
|
||||||
ESP_LOGD(TAG, "Failed to read byte");
|
{
|
||||||
return;
|
ESP_LOGD(TAG, "Set rolling code counter to %d", counter);
|
||||||
|
this->rollingCodeCounter = counter;
|
||||||
|
this->pref_.save(&this->rollingCodeCounter);
|
||||||
|
sendRollingCodeChanged();
|
||||||
}
|
}
|
||||||
if (!reading) {
|
|
||||||
// shift serial byte onto msg start
|
|
||||||
msgStart <<= 8;
|
|
||||||
msgStart |= serData;
|
|
||||||
|
|
||||||
// truncate to 3 bytes
|
void RATGDOComponent::incrementRollingCodeCounter()
|
||||||
msgStart &= 0x00FFFFFF;
|
{
|
||||||
|
ESP_LOGD(TAG, "Incrementing rolling code counter");
|
||||||
|
this->rollingCodeCounter = (this->rollingCodeCounter + 1) & 0xfffffff;
|
||||||
|
sendRollingCodeChanged();
|
||||||
|
}
|
||||||
|
|
||||||
// if we are at the start of a message, capture the next 16 bytes
|
void RATGDOComponent::sendRollingCodeChanged()
|
||||||
if (msgStart == 0x550100) {
|
{
|
||||||
byteCount = 3;
|
for (auto* child : this->children_) {
|
||||||
rxRollingCode[0] = 0x55;
|
child->on_rolling_code_change(this->rollingCodeCounter);
|
||||||
rxRollingCode[1] = 0x01;
|
}
|
||||||
rxRollingCode[2] = 0x00;
|
}
|
||||||
|
|
||||||
reading = true;
|
void RATGDOComponent::printRollingCode()
|
||||||
|
{
|
||||||
|
ESP_LOGD(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->txRollingCode[0],
|
||||||
|
this->txRollingCode[1],
|
||||||
|
this->txRollingCode[2],
|
||||||
|
this->txRollingCode[3],
|
||||||
|
this->txRollingCode[4],
|
||||||
|
this->txRollingCode[5],
|
||||||
|
this->txRollingCode[6],
|
||||||
|
this->txRollingCode[7],
|
||||||
|
this->txRollingCode[8],
|
||||||
|
this->txRollingCode[9],
|
||||||
|
this->txRollingCode[10],
|
||||||
|
this->txRollingCode[11],
|
||||||
|
this->txRollingCode[12],
|
||||||
|
this->txRollingCode[13],
|
||||||
|
this->txRollingCode[14],
|
||||||
|
this->txRollingCode[15],
|
||||||
|
this->txRollingCode[16],
|
||||||
|
this->txRollingCode[17],
|
||||||
|
this->txRollingCode[18]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*************************** OBSTRUCTION DETECTION ***************************/
|
||||||
|
|
||||||
|
void RATGDOComponent::obstructionLoop()
|
||||||
|
{
|
||||||
|
long currentMillis = millis();
|
||||||
|
static unsigned long lastMillis = 0;
|
||||||
|
|
||||||
|
// the obstruction sensor has 3 states: clear (HIGH with LOW pulse every 7ms), obstructed (HIGH), asleep (LOW)
|
||||||
|
// the transitions between awake and asleep are tricky because the voltage drops slowly when falling asleep
|
||||||
|
// and is high without pulses when waking up
|
||||||
|
|
||||||
|
// If at least 3 low pulses are counted within 50ms, the door is awake, not obstructed and we don't have to check anything else
|
||||||
|
|
||||||
|
// Every 50ms
|
||||||
|
if (currentMillis - lastMillis > 50) {
|
||||||
|
// check to see if we got between 3 and 8 low pulses on the line
|
||||||
|
if (this->store_.obstructionLowCount >= 3 && this->store_.obstructionLowCount <= 8) {
|
||||||
|
// obstructionCleared();
|
||||||
|
this->obstructionState = ObstructionState::OBSTRUCTION_STATE_CLEAR;
|
||||||
|
|
||||||
|
// if there have been no pulses the line is steady high or low
|
||||||
|
} else if (this->store_.obstructionLowCount == 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() && currentMillis - this->store_.lastObstructionHigh > 70) {
|
||||||
|
this->obstructionState = ObstructionState::OBSTRUCTION_STATE_OBSTRUCTED;
|
||||||
|
// obstructionDetected();
|
||||||
|
} else {
|
||||||
|
// asleep
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lastMillis = currentMillis;
|
||||||
|
this->store_.obstructionLowCount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RATGDOComponent::gdoStateLoop()
|
||||||
|
{
|
||||||
|
static uint32_t msgStart;
|
||||||
|
static bool reading = false;
|
||||||
|
static uint16_t byteCount = 0;
|
||||||
|
static bool isStatus = false;
|
||||||
|
|
||||||
|
if (!this->available()) {
|
||||||
|
// ESP_LOGD(TAG, "No data available input:%d output:%d", this->input_gdo_pin_->get_pin(), this->output_gdo_pin_->get_pin());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
uint8_t serData;
|
||||||
if (reading) {
|
if (!this->read_byte(&serData)) {
|
||||||
this->rxRollingCode[byteCount] = serData;
|
ESP_LOGD(TAG, "Failed to read byte");
|
||||||
byteCount++;
|
return;
|
||||||
|
}
|
||||||
|
if (!reading) {
|
||||||
|
// shift serial byte onto msg start
|
||||||
|
msgStart <<= 8;
|
||||||
|
msgStart |= serData;
|
||||||
|
|
||||||
if (byteCount == CODE_LENGTH) {
|
// truncate to 3 bytes
|
||||||
reading = false;
|
msgStart &= 0x00FFFFFF;
|
||||||
msgStart = 0;
|
|
||||||
byteCount = 0;
|
// if we are at the start of a message, capture the next 16 bytes
|
||||||
if (readRollingCode() == STATUS_CMD && this->forceUpdate_) {
|
if (msgStart == 0x550100) {
|
||||||
this->forceUpdate_ = false;
|
byteCount = 3;
|
||||||
this->previousDoorState = DoorState::DOOR_STATE_UNKNOWN;
|
rxRollingCode[0] = 0x55;
|
||||||
this->previousLightState = LightState::LIGHT_STATE_UNKNOWN;
|
rxRollingCode[1] = 0x01;
|
||||||
this->previousLockState = LockState::LOCK_STATE_UNKNOWN;
|
rxRollingCode[2] = 0x00;
|
||||||
|
|
||||||
|
reading = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (reading) {
|
||||||
|
this->rxRollingCode[byteCount] = serData;
|
||||||
|
byteCount++;
|
||||||
|
|
||||||
|
if (byteCount == CODE_LENGTH) {
|
||||||
|
reading = false;
|
||||||
|
msgStart = 0;
|
||||||
|
byteCount = 0;
|
||||||
|
if (readRollingCode() == STATUS_CMD && this->forceUpdate_) {
|
||||||
|
this->forceUpdate_ = false;
|
||||||
|
this->previousDoorState = DoorState::DOOR_STATE_UNKNOWN;
|
||||||
|
this->previousLightState = LightState::LIGHT_STATE_UNKNOWN;
|
||||||
|
this->previousLockState = LockState::LOCK_STATE_UNKNOWN;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void RATGDOComponent::statusUpdateLoop()
|
void RATGDOComponent::statusUpdateLoop()
|
||||||
{
|
{
|
||||||
if (this->doorState != this->previousDoorState) {
|
if (this->doorState != this->previousDoorState) {
|
||||||
DoorState val = static_cast<DoorState>(this->doorState);
|
DoorState val = static_cast<DoorState>(this->doorState);
|
||||||
ESP_LOGD(TAG, "Door state: %s", door_state_to_string(val));
|
ESP_LOGD(TAG, "Door state: %s", door_state_to_string(val));
|
||||||
for (auto* child : this->children_) {
|
for (auto* child : this->children_) {
|
||||||
child->on_door_state(val);
|
child->on_door_state(val);
|
||||||
|
}
|
||||||
|
this->previousDoorState = this->doorState;
|
||||||
|
}
|
||||||
|
if (this->lightState != this->previousLightState) {
|
||||||
|
LightState val = static_cast<LightState>(this->lightState);
|
||||||
|
ESP_LOGD(TAG, "Light state %s (%d)", light_state_to_string(val), this->lightState);
|
||||||
|
for (auto* child : this->children_) {
|
||||||
|
child->on_light_state(val);
|
||||||
|
}
|
||||||
|
this->previousLightState = this->lightState;
|
||||||
|
}
|
||||||
|
if (this->lockState != this->previousLockState) {
|
||||||
|
LockState val = static_cast<LockState>(this->lockState);
|
||||||
|
ESP_LOGD(TAG, "Lock state %s", lock_state_to_string(val));
|
||||||
|
for (auto* child : this->children_) {
|
||||||
|
child->on_lock_state(val);
|
||||||
|
}
|
||||||
|
this->previousLockState = this->lockState;
|
||||||
|
}
|
||||||
|
if (this->obstructionState != this->previousObstructionState) {
|
||||||
|
ObstructionState val = static_cast<ObstructionState>(this->obstructionState);
|
||||||
|
ESP_LOGD(TAG, "Obstruction state %s", obstruction_state_to_string(val));
|
||||||
|
for (auto* child : this->children_) {
|
||||||
|
child->on_obstruction_state(val);
|
||||||
|
}
|
||||||
|
this->previousObstructionState = this->obstructionState;
|
||||||
|
}
|
||||||
|
if (this->motorState != this->previousMotorState) {
|
||||||
|
MotorState val = static_cast<MotorState>(this->motorState);
|
||||||
|
ESP_LOGD(TAG, "Motor state %s", motor_state_to_string(val));
|
||||||
|
for (auto* child : this->children_) {
|
||||||
|
child->on_motor_state(val);
|
||||||
|
}
|
||||||
|
this->previousMotorState = this->motorState;
|
||||||
|
}
|
||||||
|
if (this->motionState == this->previousMotionState) {
|
||||||
|
MotionState val = static_cast<MotionState>(this->motionState);
|
||||||
|
ESP_LOGD(TAG, "Motion state %s", motion_state_to_string(val));
|
||||||
|
for (auto* child : this->children_) {
|
||||||
|
child->on_motion_state(val);
|
||||||
|
}
|
||||||
|
this->previousMotionState = this->motionState;
|
||||||
|
}
|
||||||
|
if (this->buttonState != this->previousButtonState) {
|
||||||
|
ButtonState val = static_cast<ButtonState>(this->buttonState);
|
||||||
|
ESP_LOGD(TAG, "Button state %s", button_state_to_string(val));
|
||||||
|
for (auto* child : this->children_) {
|
||||||
|
child->on_button_state(val);
|
||||||
|
}
|
||||||
|
this->previousButtonState = this->buttonState;
|
||||||
|
}
|
||||||
|
if (this->openings != this->previousOpenings) {
|
||||||
|
ESP_LOGD(TAG, "Openings: %d", this->openings);
|
||||||
|
for (auto* child : this->children_) {
|
||||||
|
child->on_openings_change(this->openings);
|
||||||
|
}
|
||||||
|
this->previousOpenings = this->openings;
|
||||||
}
|
}
|
||||||
this->previousDoorState = this->doorState;
|
|
||||||
}
|
}
|
||||||
if (this->lightState != this->previousLightState) {
|
|
||||||
LightState val = static_cast<LightState>(this->lightState);
|
void RATGDOComponent::query()
|
||||||
ESP_LOGD(TAG, "Light state %s (%d)", light_state_to_string(val), this->lightState);
|
{
|
||||||
for (auto* child : this->children_) {
|
this->forceUpdate_ = true;
|
||||||
child->on_light_state(val);
|
sendCommandAndSaveCounter(Command.REBOOT2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************* DOOR COMMUNICATION *************************/
|
||||||
|
/*
|
||||||
|
* Transmit a message to the door opener over uart1
|
||||||
|
* The TX1 pin is controlling a transistor, so the logic is inverted
|
||||||
|
* A HIGH state on TX1 will pull the 12v line LOW
|
||||||
|
*
|
||||||
|
* The opener requires a specific duration low/high pulse before it will accept
|
||||||
|
* a message
|
||||||
|
*/
|
||||||
|
void RATGDOComponent::transmit(cmd command)
|
||||||
|
{
|
||||||
|
getRollingCode(command);
|
||||||
|
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->write_array(this->txRollingCode, CODE_LENGTH);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RATGDOComponent::sync()
|
||||||
|
{
|
||||||
|
transmit(Command.REBOOT1);
|
||||||
|
delay(65);
|
||||||
|
transmit(Command.REBOOT2);
|
||||||
|
delay(65);
|
||||||
|
transmit(Command.REBOOT3);
|
||||||
|
delay(65);
|
||||||
|
transmit(Command.REBOOT4);
|
||||||
|
delay(65);
|
||||||
|
transmit(Command.REBOOT5);
|
||||||
|
delay(65);
|
||||||
|
sendCommandAndSaveCounter(Command.REBOOT6);
|
||||||
|
delay(65);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RATGDOComponent::openDoor()
|
||||||
|
{
|
||||||
|
if (this->doorState == DoorState::DOOR_STATE_OPEN || this->doorState == DoorState::DOOR_STATE_OPENING) {
|
||||||
|
ESP_LOGD(TAG, "The door is already %s", door_state_to_string(static_cast<DoorState>(this->doorState)));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
toggleDoor();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RATGDOComponent::closeDoor()
|
||||||
|
{
|
||||||
|
if (this->doorState == DoorState::DOOR_STATE_CLOSED || this->doorState == DoorState::DOOR_STATE_CLOSING) {
|
||||||
|
ESP_LOGD(TAG, "The door is already %s", door_state_to_string(static_cast<DoorState>(this->doorState)));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
toggleDoor();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RATGDOComponent::stopDoor()
|
||||||
|
{
|
||||||
|
if (this->doorState != DoorState::DOOR_STATE_OPENING && this->doorState != DoorState::DOOR_STATE_CLOSING) {
|
||||||
|
ESP_LOGD(TAG, "The door is not moving.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
toggleDoor();
|
||||||
|
}
|
||||||
|
|
||||||
|
void RATGDOComponent::toggleDoor()
|
||||||
|
{
|
||||||
|
transmit(Command.DOOR1);
|
||||||
|
delay(40);
|
||||||
|
sendCommandAndSaveCounter(Command.DOOR2);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RATGDOComponent::isLightOn()
|
||||||
|
{
|
||||||
|
return this->lightState == LightState::LIGHT_STATE_ON;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RATGDOComponent::lightOn()
|
||||||
|
{
|
||||||
|
if (this->lightState == LightState::LIGHT_STATE_ON) {
|
||||||
|
ESP_LOGD(TAG, "The light is already on");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
toggleLight();
|
||||||
|
// We don't always get the state back so be optimistic
|
||||||
this->previousLightState = this->lightState;
|
this->previousLightState = this->lightState;
|
||||||
|
this->lightState = LightState::LIGHT_STATE_ON;
|
||||||
}
|
}
|
||||||
if (this->lockState != this->previousLockState) {
|
|
||||||
LockState val = static_cast<LockState>(this->lockState);
|
void RATGDOComponent::lightOff()
|
||||||
ESP_LOGD(TAG, "Lock state %s", lock_state_to_string(val));
|
{
|
||||||
for (auto* child : this->children_) {
|
if (this->lightState == LightState::LIGHT_STATE_OFF) {
|
||||||
child->on_lock_state(val);
|
ESP_LOGD(TAG, "The light is already off");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
this->previousLockState = this->lockState;
|
toggleLight();
|
||||||
|
// We don't always get the state back so be optimistic
|
||||||
|
this->previousLightState = this->lightState;
|
||||||
|
this->lightState = LightState::LIGHT_STATE_OFF;
|
||||||
}
|
}
|
||||||
if (this->obstructionState != this->previousObstructionState) {
|
|
||||||
ObstructionState val = static_cast<ObstructionState>(this->obstructionState);
|
void RATGDOComponent::toggleLight()
|
||||||
ESP_LOGD(TAG, "Obstruction state %s", obstruction_state_to_string(val));
|
{
|
||||||
for (auto* child : this->children_) {
|
sendCommandAndSaveCounter(Command.LIGHT);
|
||||||
child->on_obstruction_state(val);
|
}
|
||||||
|
|
||||||
|
// Lock functions
|
||||||
|
void RATGDOComponent::lock()
|
||||||
|
{
|
||||||
|
if (this->lockState == LockState::LOCK_STATE_LOCKED) {
|
||||||
|
ESP_LOGD(TAG, "already locked");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
this->previousObstructionState = this->obstructionState;
|
toggleLock();
|
||||||
}
|
}
|
||||||
if (this->motorState != this->previousMotorState) {
|
|
||||||
MotorState val = static_cast<MotorState>(this->motorState);
|
void RATGDOComponent::unlock()
|
||||||
ESP_LOGD(TAG, "Motor state %s", motor_state_to_string(val));
|
{
|
||||||
for (auto* child : this->children_) {
|
if (this->lockState == LockState::LOCK_STATE_UNLOCKED) {
|
||||||
child->on_motor_state(val);
|
ESP_LOGD(TAG, "already unlocked");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
this->previousMotorState = this->motorState;
|
toggleLock();
|
||||||
}
|
}
|
||||||
if (this->motionState == this->previousMotionState) {
|
|
||||||
MotionState val = static_cast<MotionState>(this->motionState);
|
void RATGDOComponent::toggleLock()
|
||||||
ESP_LOGD(TAG, "Motion state %s", motion_state_to_string(val));
|
{
|
||||||
for (auto* child : this->children_) {
|
sendCommandAndSaveCounter(Command.LOCK);
|
||||||
child->on_motion_state(val);
|
|
||||||
}
|
|
||||||
this->previousMotionState = this->motionState;
|
|
||||||
}
|
}
|
||||||
if (this->buttonState != this->previousButtonState) {
|
|
||||||
ButtonState val = static_cast<ButtonState>(this->buttonState);
|
void RATGDOComponent::sendCommandAndSaveCounter(cmd command)
|
||||||
ESP_LOGD(TAG, "Button state %s", button_state_to_string(val));
|
{
|
||||||
for (auto* child : this->children_) {
|
transmit(command);
|
||||||
child->on_button_state(val);
|
this->pref_.save(&this->rollingCodeCounter);
|
||||||
}
|
global_preferences->sync();
|
||||||
this->previousButtonState = this->buttonState;
|
|
||||||
}
|
}
|
||||||
if (this->openings != this->previousOpenings) {
|
|
||||||
ESP_LOGD(TAG, "Openings: %d", this->openings);
|
void RATGDOComponent::register_child(RATGDOClient * obj)
|
||||||
for (auto* child : this->children_) {
|
{
|
||||||
child->on_openings_change(this->openings);
|
this->children_.push_back(obj);
|
||||||
}
|
obj->set_parent(this);
|
||||||
this->previousOpenings = this->openings;
|
|
||||||
}
|
}
|
||||||
}
|
LightState RATGDOComponent::getLightState()
|
||||||
|
{
|
||||||
void RATGDOComponent::query()
|
return static_cast<LightState>(this->lightState);
|
||||||
{
|
|
||||||
this->forceUpdate_ = true;
|
|
||||||
sendCommandAndSaveCounter(Command.REBOOT2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/************************* DOOR COMMUNICATION *************************/
|
|
||||||
/*
|
|
||||||
* Transmit a message to the door opener over uart1
|
|
||||||
* The TX1 pin is controlling a transistor, so the logic is inverted
|
|
||||||
* A HIGH state on TX1 will pull the 12v line LOW
|
|
||||||
*
|
|
||||||
* The opener requires a specific duration low/high pulse before it will accept
|
|
||||||
* a message
|
|
||||||
*/
|
|
||||||
void RATGDOComponent::transmit(cmd command)
|
|
||||||
{
|
|
||||||
getRollingCode(command);
|
|
||||||
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->write_array(this->txRollingCode, CODE_LENGTH);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RATGDOComponent::sync()
|
|
||||||
{
|
|
||||||
transmit(Command.REBOOT1);
|
|
||||||
delay(65);
|
|
||||||
transmit(Command.REBOOT2);
|
|
||||||
delay(65);
|
|
||||||
transmit(Command.REBOOT3);
|
|
||||||
delay(65);
|
|
||||||
transmit(Command.REBOOT4);
|
|
||||||
delay(65);
|
|
||||||
transmit(Command.REBOOT5);
|
|
||||||
delay(65);
|
|
||||||
sendCommandAndSaveCounter(Command.REBOOT6);
|
|
||||||
delay(65);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RATGDOComponent::openDoor()
|
|
||||||
{
|
|
||||||
if (this->doorState == DoorState::DOOR_STATE_OPEN || this->doorState == DoorState::DOOR_STATE_OPENING) {
|
|
||||||
ESP_LOGD(TAG, "The door is already %s", door_state_to_string(static_cast<DoorState>(this->doorState)));
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
toggleDoor();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RATGDOComponent::closeDoor()
|
} // namespace ratgdo
|
||||||
{
|
|
||||||
if (this->doorState == DoorState::DOOR_STATE_CLOSED || this->doorState == DoorState::DOOR_STATE_CLOSING) {
|
|
||||||
ESP_LOGD(TAG, "The door is already %s", door_state_to_string(static_cast<DoorState>(this->doorState)));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
toggleDoor();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RATGDOComponent::stopDoor()
|
|
||||||
{
|
|
||||||
if (this->doorState != DoorState::DOOR_STATE_OPENING && this->doorState != DoorState::DOOR_STATE_CLOSING) {
|
|
||||||
ESP_LOGD(TAG, "The door is not moving.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
toggleDoor();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RATGDOComponent::toggleDoor()
|
|
||||||
{
|
|
||||||
transmit(Command.DOOR1);
|
|
||||||
delay(40);
|
|
||||||
sendCommandAndSaveCounter(Command.DOOR2);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RATGDOComponent::isLightOn()
|
|
||||||
{
|
|
||||||
return this->lightState == LightState::LIGHT_STATE_ON;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RATGDOComponent::lightOn()
|
|
||||||
{
|
|
||||||
if (this->lightState == LightState::LIGHT_STATE_ON) {
|
|
||||||
ESP_LOGD(TAG, "The light is already on");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
toggleLight();
|
|
||||||
// We don't always get the state back so be optimistic
|
|
||||||
this->previousLightState = this->lightState;
|
|
||||||
this->lightState = LightState::LIGHT_STATE_ON;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RATGDOComponent::lightOff()
|
|
||||||
{
|
|
||||||
if (this->lightState == LightState::LIGHT_STATE_OFF) {
|
|
||||||
ESP_LOGD(TAG, "The light is already off");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
toggleLight();
|
|
||||||
// We don't always get the state back so be optimistic
|
|
||||||
this->previousLightState = this->lightState;
|
|
||||||
this->lightState = LightState::LIGHT_STATE_OFF;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RATGDOComponent::toggleLight()
|
|
||||||
{
|
|
||||||
sendCommandAndSaveCounter(Command.LIGHT);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lock functions
|
|
||||||
void RATGDOComponent::lock()
|
|
||||||
{
|
|
||||||
if (this->lockState == LockState::LOCK_STATE_LOCKED) {
|
|
||||||
ESP_LOGD(TAG, "already locked");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
toggleLock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RATGDOComponent::unlock()
|
|
||||||
{
|
|
||||||
if (this->lockState == LockState::LOCK_STATE_UNLOCKED) {
|
|
||||||
ESP_LOGD(TAG, "already unlocked");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
toggleLock();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RATGDOComponent::toggleLock()
|
|
||||||
{
|
|
||||||
sendCommandAndSaveCounter(Command.LOCK);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RATGDOComponent::sendCommandAndSaveCounter(cmd command)
|
|
||||||
{
|
|
||||||
transmit(command);
|
|
||||||
this->pref_.save(&this->rollingCodeCounter);
|
|
||||||
global_preferences->sync();
|
|
||||||
}
|
|
||||||
|
|
||||||
void RATGDOComponent::register_child(RATGDOClient* obj)
|
|
||||||
{
|
|
||||||
this->children_.push_back(obj);
|
|
||||||
obj->set_parent(this);
|
|
||||||
}
|
|
||||||
LightState RATGDOComponent::getLightState()
|
|
||||||
{
|
|
||||||
return static_cast<LightState>(this->lightState);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace ratgdo
|
|
||||||
} // namespace esphome
|
} // namespace esphome
|
||||||
|
|
Loading…
Reference in New Issue