I am trying to build a unlocker on my hardlid for my ute. I have replaced the manual unlocking mechanism with 2 of these https://www.jaycar.com.au/slave-door-lock-actuator/p/LR8813.

Now my code below works sometimes and I cannot work out why. The way the code should work is

  1. Press Unlock Button (Count increments)
  2. Press Unlock Button again
  3. When count = 2 turn relay on for 4 seconds then turn off
  4. reset count to 0
  5. If time between presses is longer than 10 seconds reset count to 0

Basic diagram below. Please note the push button is actually wired to a relay which is triggered by the car unlock remote and the LED is the actuators.

enter image description here

This is my code

int switchPin = 2; // choose the input pin (for a pushbutton)
int relayPin = 4; // choose the input pin (for a pushbutton)
int val = 0; // variable for reading the pin status
int counter = 0;
int currentState = 0;
int previousState = 0;
bool lockOn = false;

unsigned long currentMillis = 0;
unsigned long previousMillis = 0;

unsigned long LockcurrentMillis = 0;
unsigned long LockpreviousMillis = 0;

const long interval = 10000;
const long Lockinterval = 4000;

void setup() {

  pinMode(switchPin, INPUT); // declare pushbutton as input
  pinMode(relayPin, OUTPUT); // declare pushbutton as input

  Serial.print("IP address: ");


void loop() {

  currentMillis = millis();
  LockcurrentMillis = millis();
  Serial.print("Current ");
  Serial.print(" | Previous ");

  Serial.print("Lock Current ");
  Serial.print(" | Lock Previous ");
  if (lockOn == true){

    if (LockcurrentMillis - LockpreviousMillis >= Lockinterval) {
      // save the last time you blinked the LED
      LockpreviousMillis = LockcurrentMillis;
      digitalWrite(relayPin, LOW); // turn relayPin off
      lockOn = false;
      Serial.println("relay off");

  val = digitalRead(switchPin); // read input value
  if (val == HIGH) { // check if the input is HIGH (button released)
    currentState = 1;
  else {
    currentState = 0;
  if (currentState != previousState) {
    if (currentState == 1) {
      counter = counter + 1;
      previousMillis = currentMillis;   //reset timer
  if (counter == 2) {
    counter = 0;
    digitalWrite(relayPin, HIGH); // turn relayPin on
    //digitalWrite(relayPin, LOW); // turn relayPin off
    lockOn = true;
          LockpreviousMillis = LockcurrentMillis;

    Serial.println("relay on");

  previousState = currentState;
  if (currentMillis - previousMillis >= interval) {
    // save the last time you presse the button
    previousMillis = currentMillis;
    //LockpreviousMillis = LockcurrentMillis;
    //if (counter >= 1) {
    Serial.println("Took too long reset count");
    counter = 0;
    lockOn = false;

Any Help would be highly appreciated



Your circuit drawing seems very wrong, but it is not helpful since, as you say, it doesn't represent the real circuit. Please, add a proper diagram of the actual circuit.

As for your reliability problem, I did not dig into the logic of the code you posted, but I suspect it may be caused by the lack of debouncing. You could add you own debouncing code but, for the sake of simplicity, I suggest you instead use a ready-made library, like Bounce2.

For the kind of program you are trying to write, I find that the logic becomes way easier to grasp if you think think of it as a finite state machine. This is program construct based on the idea that the system can be in any of a predefined set of possible states, and that its behavior and the possible state transitions depend on what particular state it is in. In this specific case, I would use three states:

  • In the LOCKED state, the lid is locked and you need to press the button twice in order to unlock it. Once you press the button once, it transitions to the WAITING state.
  • In the WAITING state, the lid is still locked, but the first button press has already been registered. If you press the button again, the system transitions to the UNLOCKED state. If not, after a timeout it transitions back to LOCKED.
  • In the UNLOCKED state the lid is unlocked. After another timeout it transitions back to the LOCKED state.

Once you have this logic written down, it can be translated into code in a very straightforward way:

#include <Bounce2.h>

const uint8_t  switch_pin = 2;
const uint8_t  relay_pin  = 4;
const uint32_t wait_interval = 10000;  // 10 s
const uint32_t lock_interval =  4000;  //  4 s

Bounce button;

void setup() {
    button.attach(switch_pin, INPUT_PULLUP);
    pinMode(relay_pin, OUTPUT);

void loop() {
    static enum { LOCKED, WAITING, UNLOCKED } state = LOCKED;
    static uint32_t last_change;  // not used in the LOCKED state

    uint32_t now = millis();
    switch (state) {
    case LOCKED:
        if (button.fell()) {
            Serial.println(F("Waiting for second button press."));
            state = WAITING;
            last_change = now;
    case WAITING:
        if (button.fell()) {
            digitalWrite(relay_pin, HIGH);
            state = UNLOCKED;
            last_change = now;
        } else if (now - last_change >= wait_interval) {
            Serial.println(F("Wait time out."));
            state = LOCKED;
    case UNLOCKED:
        if (now - last_change >= lock_interval) {
            digitalWrite(relay_pin, LOW);
            state = LOCKED;
| improve this answer | |
  • Thank you Edgar. You code certainly looks much easier to read and follow. I will try you code now and report back. Thanks Again – Ben May 18 at 22:32
  • This works perfectly! I update schematic also. thanks – Ben May 18 at 23:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.