Skip to content

Instantly share code, notes, and snippets.

@X3msnake
Last active June 2, 2025 15:50
Show Gist options
  • Save X3msnake/486318a4bb46f73e65e2fa581b72904b to your computer and use it in GitHub Desktop.
Save X3msnake/486318a4bb46f73e65e2fa581b72904b to your computer and use it in GitHub Desktop.

Bayamo hand dryer reverse engineering

Counter board

image SN74HC164 GD-4021LB

IR Led Barrier

image Infrared Sensor: IRM-56384


/*

http://www.bristolwatch.com/arduino/arduino3.htm
Connecting Arduino to a 74C164 Shift Register
Lewis Loflin [email protected]

Demo to shift byte into 74HC164
8-Bit Serial-In - Parallel-Out Serial Shift Register
Will count from 0 to 255 in binary on eight LEDs

The 74HC164 has three inputs:

Input A-B (pins 1, 2) is for data. they can be tied
together or the one not used tied to +Vcc

Clock pin 8 data is serially shifted in and
out of the 8-bit register during
the positive going transition of clock pulse.

Clear (pin 9) is independent of the clock
and accomplished by a low level at the
clear input.

As far as LSB first or MSB bit first is up to software
and electrical connections on the output

*/

#define DATA 12
#define CLK 11
#define CLR 9
#define VCC 2
#define SIG A0
#define RLAY 6

#define OFF 0
#define ON 1

unsigned long startMillis;  // some global variables available anywhere in the program
unsigned long currentMillis;
const unsigned long period = 1000;  // the value is a number of milliseconds

byte i, j, temp, val;

int data[] = {2, 62, 72, 40, 52, 160, 128, 50, 0, 32};

void setup() {
  pinMode(DATA, OUTPUT);
  pinMode(CLK, OUTPUT);
  pinMode(CLR, OUTPUT);
  pinMode(VCC, OUTPUT);
  pinMode(SIG, INPUT_PULLUP);
  pinMode(RLAY, OUTPUT);

  pinMode(13, OUTPUT);  // used to test-debug various sections of code

  digitalWrite(CLK, OFF);
  digitalWrite(CLR, OFF); // active LOW
  digitalWrite(VCC, ON);

  startMillis = millis();  // initial start time

  Serial.begin(115200); // open the serial port at 9600 bps:

  resetDigits();
}

void loop() {
  
  digitalWrite(13, OFF); // Debug LED 
  digitalWrite(RLAY, OFF); // PowerRelay
  delay(500);
    
  if (!digitalRead(SIG)) {
    digitalWrite(13, ON); // Debug LED
    digitalWrite(RLAY, ON); // PowerRelay

    handleInfraredSensor();
  }
  
}

void handleInfraredSensor() {

  unsigned long previousMillis = millis();
  unsigned long interval = 0; // Adjust this interval as needed

  int number = 60;
  int digit1 = 0;
  int digit2 = 0;

  while (number > 0) {
    if (millis() - previousMillis >= interval) {
      previousMillis = millis();  // Save the last time the digit was updated

      digit1 = number / 10; // First digit of the number
      digit2 = number % 10; // Second digit of the number

      // Display the same count number on both digits
      for (int count = 0; count < 50; count++) {
        digitalWrite(CLR, HIGH); // Select first 7-segment display
        val = data[digit1]; // Set value for the first 7-segment display
        shiftData(val); // Shift the data into the shift register
        delay(10); // Display the first digit for a short time

        digitalWrite(CLR, LOW); // Select second 7-segment display
        val = data[digit2]; // Set value for the second 7-segment display
        shiftData(val); // Shift the data into the shift register
        delay(10); // Display the second digit for a short time
      }

      number--;
     }
     resetDigits();
   }
 }


void shiftData(byte val) {
  for (j = 0; j < 8; j++) {
    temp = (val >> j) & 0x01;
    digitalWrite(DATA, temp);
    pulsout(CLK, 0);
  }
}

void resetDigits(){
     digitalWrite(CLR, LOW); // Select first 7-segment display
     shiftData(B11111111); // Shift the data into the shift register
     digitalWrite(CLR, HIGH); // Select first 7-segment display
     shiftData(B11111111); // Shift the data into the shift register
}

// inverts state of pin, delays, then reverts state back
void pulsout(byte x, int y) {
  byte z = digitalRead(x);
  z = !z;
  digitalWrite(x, z);
  delayMicroseconds(y);
  z = !z; // return to original state
  digitalWrite(x, z);
  return;
} // end pulsout()


image image


image

@X3msnake
Copy link
Author

X3msnake commented Jan 4, 2024

IR barrier reverse engineering test code

This code assumes that you have connected your analog sensors to pins A0, A1, and A2, and an LED to pin D13 on your Arduino board. Adjust the pin configurations based on your actual hardware connections if necessary. The voltages are read and printed to the serial monitor, and if any of them goes below 3 volts, the LED on pin D13 is turned on for X seconds.

const int analogPinA0 = A0;
const int analogPinA1 = A1;
const int analogPinA2 = A2;
const int ledPin = 13;

void setup() {
  Serial.begin(9600);
  pinMode(ledPin, OUTPUT);
}

void loop() {
  // Read voltages from analog pins
  float voltageA0 = analogRead(analogPinA0) * (5.0 / 1023.0);
  float voltageA1 = analogRead(analogPinA1) * (5.0 / 1023.0);
  float voltageA2 = analogRead(analogPinA2) * (5.0 / 1023.0);

  // Check if any voltage is lower than 3 volts
  if (voltageA0 < 3.0 || voltageA1 < 3.0 || voltageA2 < 3.0) {
  
    // Output message to serial monitor
    Serial.println("Voltage below 3V detected. LED turned on.");
    
    // Output voltages to serial monitor
    Serial.print("Voltage A0: ");
    Serial.print(voltageA0);
    Serial.print("V, Voltage A1: ");
    Serial.print(voltageA1);
    Serial.print("V, Voltage A2: ");
    Serial.print(voltageA2);
    Serial.println("V");
    
    // Turn on LED for X seconds
    digitalWrite(ledPin, HIGH);
    delay(1000);
    digitalWrite(ledPin, LOW);
    
  }

  delay(50); // Adjust delay as needed
}

@X3msnake
Copy link
Author

X3msnake commented Feb 12, 2024

First Version Merged Code (DEPRECATED)

With the help of Copilot


#define DATA 12
#define CLK 11
#define CLR 9
#define VCC 2
#define RLAY 6

#define OFF 0
#define ON 1

const int analogPinA0 = A0;
const int analogPinA1 = A1;
const int analogPinA2 = A2;

unsigned long startMillis;  // some global variables available anywhere in the program
unsigned long currentMillis;
const unsigned long period = 1000;  // the value is a number of milliseconds

byte i, j, temp, val;

int data[] = {2, 62, 72, 40, 52, 160, 128, 50, 0, 32};

void setup() {
  pinMode(DATA, OUTPUT);
  pinMode(CLK, OUTPUT);
  pinMode(CLR, OUTPUT);
  pinMode(VCC, OUTPUT);
  pinMode(RLAY, OUTPUT);

  pinMode(13, OUTPUT);  // used to test-debug various sections of code

  digitalWrite(CLK, OFF);
  digitalWrite(CLR, OFF); // active LOW
  digitalWrite(VCC, ON);

  startMillis = millis();  // initial start time

  Serial.begin(115200); // open the serial port at 9600 bps:

  resetDigits();
}

void loop() {
  
  digitalWrite(13, OFF); // Debug LED 
  digitalWrite(RLAY, OFF); // PowerRelay
  delay(500);
    
  // Read voltages from analog pins
  float voltageA0 = analogRead(analogPinA0) * (5.0 / 1023.0);
  float voltageA1 = analogRead(analogPinA1) * (5.0 / 1023.0);
  float voltageA2 = analogRead(analogPinA2) * (5.0 / 1023.0);

  // Check if any voltage is lower than 3 volts
  if (voltageA0 < 3.0 || voltageA1 < 3.0 || voltageA2 < 3.0) {
    digitalWrite(13, ON); // Debug LED
    digitalWrite(RLAY, ON); // PowerRelay

    handleInfraredSensor();
  }
  
}

void handleInfraredSensor() {

  unsigned long previousMillis = millis();
  unsigned long interval = 0; // Adjust this interval as needed

  int number = 30;
  int digit1 = 0;
  int digit2 = 0;

  while (number > 0) {
    if (millis() - previousMillis >= interval) {
      previousMillis = millis();  // Save the last time the digit was updated

      digit1 = number / 10; // First digit of the number
      digit2 = number % 10; // Second digit of the number

      // Display the same count number on both digits
      for (int count = 0; count < 50; count++) {
        digitalWrite(CLR, HIGH); // Select first 7-segment display
        val = data[digit1]; // Set value for the first 7-segment display
        shiftData(val); // Shift the data into the shift register
        delay(10); // Display the first digit for a short time

        digitalWrite(CLR, LOW); // Select second 7-segment display
        val = data[digit2]; // Set value for the second 7-segment display
        shiftData(val); // Shift the data into the shift register
        delay(10); // Display the second digit for a short time
      }

      number--;
     }
     resetDigits();
   }
 }


void shiftData(byte val) {
  for (j = 0; j < 8; j++) {
    temp = (val >> j) & 0x01;
    digitalWrite(DATA, temp);
    pulsout(CLK, 0);
  }
}

void resetDigits(){
     digitalWrite(CLR, LOW); // Select first 7-segment display
     shiftData(B11111111); // Shift the data into the shift register
     digitalWrite(CLR, HIGH); // Select first 7-segment display
     shiftData(B11111111); // Shift the data into the shift register
}

// inverts state of pin, delays, then reverts state back
void pulsout(byte x, int y) {
  byte z = digitalRead(x);
  z = !z;
  digitalWrite(x, z);
  delayMicroseconds(y);
  z = !z; // return to original state
  digitalWrite(x, z);
  return;
} // end pulsout()

@X3msnake
Copy link
Author

X3msnake commented Feb 12, 2024

@X3msnake
Copy link
Author

X3msnake commented Jun 2, 2025

New version with active shutdown after 5 inactive seconds and timer rollback if the motion is still active

// ------------------------------------------------------------------------
// Code design by X3msnake and ChatGPT OpenAI o4-mini.
// Version: 2.250602
// ------------------------------------------------------------------------

#define DATA   12 
#define CLK    11
#define CLR     9
#define VCC     2
#define RLAY    6

#define OFF     0
#define ON      1

const int analogPinA0 = A0;
const int analogPinA1 = A1;
const int analogPinA2 = A2;

// “Standard” 7‐segment bit patterns (unchanged)
int data[] = { 
  2,    // 0
  62,   // 1
  72,   // 2
  40,   // 3
  52,   // 4
  160,  // 5
  128,  // 6
  50,   // 7
  0,    // 8
  32    // 9
};

// ------------------------------------------------------------------------
//  ––  LOWER‐LEVEL DISPLAY / SHIFT‐REGISTER CODE (UNCHANGED) ––
// ------------------------------------------------------------------------

void pulsout(byte x, int y) {
  byte z = digitalRead(x);
  z = !z;
  digitalWrite(x, z);
  delayMicroseconds(y);
  z = !z;
  digitalWrite(x, z);
}

void shiftData(byte val) {
  for (byte j = 0; j < 8; j++) {
    byte bitVal = (val >> j) & 0x01;
    digitalWrite(DATA, bitVal);
    pulsout(CLK, 0);
  }
}

void resetDigits() {
  digitalWrite(CLR, LOW);
  shiftData(B11111111);
  digitalWrite(CLR, HIGH);
  shiftData(B11111111);
}

// ------------------------------------------------------------------------
//  ––  GLOBAL VARIABLES FOR THE NON‐BLOCKING COUNTDOWN FSM ––
// ------------------------------------------------------------------------

enum State {
  IDLE,
  COUNTDOWN
};

State currentState = IDLE;
int  currentNumber = 30;

unsigned long lastCountMillis    = 0;   // when we last did “--currentNumber”
unsigned long lastRefreshMillis  = 0;   // when we last toggled the display digit
unsigned long sensorAboveMillis  = 0;   // when all sensors first went ≥ 3V

// NEW: remember last time any sensor was < 3V
unsigned long lastSensorActiveMillis = 0;

// 0 = tens digit, 1 = ones digit
byte displayDigit = 0;

const unsigned long refreshInterval    = 10;    // 10 ms per half‐cycle
const unsigned long countdownInterval  = 1000;  // 1 000 ms = 1 s per step
const unsigned long abortThreshold     = 5000;  // sensors ≥ 3 V for 5 s → abort

// ------------------------------------------------------------------------
//  ––  Arduino SETUP() ––
// ------------------------------------------------------------------------

void setup() {
  pinMode(DATA, OUTPUT);
  pinMode(CLK,  OUTPUT);
  pinMode(CLR,  OUTPUT);
  pinMode(VCC,  OUTPUT);
  pinMode(RLAY, OUTPUT);

  pinMode(13, OUTPUT);            
  digitalWrite(CLK, OFF);
  digitalWrite(CLR, OFF);         
  digitalWrite(VCC, ON);

  Serial.begin(115200);
  resetDigits();
}

// ------------------------------------------------------------------------
//  ––  Arduino LOOP() ––
// ------------------------------------------------------------------------

void loop() {
  // 1) Read voltages (0…5 V) from the three analog pins:
  float voltageA0 = analogRead(analogPinA0) * (5.0 / 1023.0);
  float voltageA1 = analogRead(analogPinA1) * (5.0 / 1023.0);
  float voltageA2 = analogRead(analogPinA2) * (5.0 / 1023.0);

  unsigned long now = millis();

  // ─────────────────────────────
  // NEW: If ANY sensor is < 3 V right now,
  // record “last‐active” timestamp:
  if (voltageA0 < 3.0 || voltageA1 < 3.0 || voltageA2 < 3.0) {
    lastSensorActiveMillis = now;
  }
  // ─────────────────────────────

  switch (currentState) {
    // ============================================
    //   IDLE STATE: WAIT FOR ANY SENSOR < 3 V
    // ============================================
    case IDLE:
      digitalWrite(13, OFF);
      digitalWrite(RLAY, OFF);
      resetDigits();

      if (voltageA0 < 3.0 || voltageA1 < 3.0 || voltageA2 < 3.0) {
        currentState      = COUNTDOWN;
        currentNumber     = 30;
        lastCountMillis   = now;
        lastRefreshMillis = now;
        sensorAboveMillis = 0;
        displayDigit      = 0;
        digitalWrite(13, ON);
        digitalWrite(RLAY, ON);
      }
      break;


    // ============================================
    //   COUNTDOWN STATE: NON‐BLOCKING 30 → 1
    // ============================================
    case COUNTDOWN:
      // 1) Check if all three sensors are ≥ 3 V:
      if (voltageA0 >= 3.0 && voltageA1 >= 3.0 && voltageA2 >= 3.0) {
        if (sensorAboveMillis == 0) {
          sensorAboveMillis = now;
        }
        else if (now - sensorAboveMillis >= abortThreshold) {
          // ABORT: go back to IDLE immediately
          currentState      = IDLE;
          sensorAboveMillis = 0;
          resetDigits();
          return;
        }
      }
      else {
        sensorAboveMillis = 0;
      }

      // 2) Has 1 s passed since last countdown step?
      if (now - lastCountMillis >= countdownInterval) {
        lastCountMillis += countdownInterval;
        currentNumber--;

        // ───────────────────────────────────────────────────────────────────────
        // MODIFIED: when countdown hits zero, check “lastSensorActiveMillis”:
        if (currentNumber <= 0) {
          // If any sensor was active in the last 2 000 ms, restart countdown:
          if (lastSensorActiveMillis != 0 && (now - lastSensorActiveMillis) <= 2000) {
            currentNumber     = 30;
            lastCountMillis   = now;
            lastRefreshMillis = now;
            // keep relay + LED ON (stay in COUNTDOWN)
            return;
          }
          // Else truly finish:
          currentState = IDLE;
          resetDigits();
          digitalWrite(13, OFF);
          digitalWrite(RLAY, OFF);
          return;
        }
        // ───────────────────────────────────────────────────────────────────────
      }

      // 3) Every ~10 ms, flip between tens / ones digit:
      if (now - lastRefreshMillis >= refreshInterval) {
        lastRefreshMillis += refreshInterval;

        byte digitValue;
        if (displayDigit == 0) {
          digitalWrite(CLR, HIGH);  
          digitValue = data[currentNumber / 10];
        }
        else {
          digitalWrite(CLR, LOW);
          digitValue = data[currentNumber % 10];
        }
        shiftData(digitValue);
        displayDigit = 1 - displayDigit;
      }

      // Keep LED + relay ON throughout this state
      digitalWrite(13, ON);
      digitalWrite(RLAY, ON);
      break;
  }
}

https://chatgpt.com/share/683dade2-a8b0-8000-9c16-d6d5951f0d83

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment