I'm primarily not an Arduino coder. I'm trying to vibe-code my way out of a problem and my complete lack of understanding of electronics.
The situation... I had a remote control with a decent amount of buttons that I wanted to get into Home Assistant. Despite being a cheap Chinese remote commonly used for LED controllers, it turned out to be proprietary RF and I couldn't sniff it.
That meant replacing the electronics with an ESP32 board and using that instead. However, restrictions with BTHome codes don't lend themselves well to what I was trying to do. That ended trying to use ESPHome directly.
So... I ended up with an ESP32 C6 Zero that I built into the remote matrix which uses Arduino code to hack a button code into the manufacturer code of a BLT transmission. A separate C3 Zero listens for transmissions from that specific MAC address, extracts the code and passes it to HA. - that part is all good.
What isn't good is the sleep function.
I tried to get the C6 to wake on GPIO 1, 2, 3 or 22 going high... but that didn't work. So I tried to put diodes and get it to wake on GPIO 0. That failed.
My belief was that when the C6 Zero was in deep sleep, that the matrix wouldn't be powered, so there'd be nothing to oppose the resistor from 3.3v and GPIO 0 wouldn't get pulled down.
When I took an oscilloscope to it, it appears that all the matrix pins are at 3.3v... so I stepped back, cursed AI and decided I needed to ask actual people for help.
Grateful for any advice please, as I'm clueless and have vibe-hacked myself into a corner.
#include <Arduino.h>
#include <BLEDevice.h>
#include <BLEAdvertising.h>
#include "esp_sleep.h"
// ---------------- KEYPAD ----------------
const int ROWS = 5;
const int COLS = 4;
int rowPins[ROWS] = {18, 19, 20, 21, 14};
int colPins[COLS] = {1, 2, 3, 22};
char keys[ROWS][COLS] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'},
{'E','F','G','H'}
};
// ---------------- BLE ----------------
BLEAdvertising *pAdvertising;
// ---------------- STATE ----------------
unsigned long lastActivity = 0;
const unsigned long sleepDelay = 5000;
// ---------------- BLE SEND ----------------
void sendBLE(uint8_t key_id) {
uint8_t data[] = {0xFF, 0xFF, key_id};
String md = "";
for (int i = 0; i < 3; i++) {
md += (char)data[i];
}
BLEAdvertisementData adv;
adv.setFlags(0x06);
adv.setManufacturerData(md);
pAdvertising->setAdvertisementData(adv);
// fast burst (low power, low latency)
pAdvertising->start();
delay(12);
pAdvertising->stop();
}
// ---------------- SLEEP ----------------
void goToSleep() {
Serial.println("SLEEP: preparing");
delay(50);
pinMode(0, INPUT_PULLUP);
delay(20);
// EXT1 wake on GPIO0 LOW
esp_sleep_enable_ext1_wakeup(
(1ULL << GPIO_NUM_0),
ESP_EXT1_WAKEUP_ANY_LOW
);
Serial.println("SLEEP: entering");
delay(50);
esp_deep_sleep_start();
}
// ---------------- SETUP ----------------
void setup() {
Serial.begin(115200);
delay(1000);
Serial.println("BOOT");
// rows
for (int r = 0; r < ROWS; r++) {
pinMode(rowPins[r], OUTPUT);
digitalWrite(rowPins[r], HIGH);
}
// columns
for (int c = 0; c < COLS; c++) {
pinMode(colPins[c], INPUT_PULLUP);
}
// BLE init
BLEDevice::init("BLE-Remote-1");
pAdvertising = BLEDevice::getAdvertising();
// low power BLE tuning
BLEDevice::setPower(ESP_PWR_LVL_N12);
pAdvertising->setMinInterval(160);
pAdvertising->setMaxInterval(160);
pAdvertising->setScanResponse(false);
// FIXED: ESP32 core does NOT define ADV_TYPE_NONCONN_IND
pAdvertising->setAdvertisementType(0x03);
Serial.print("BLE MAC: ");
Serial.println(BLEDevice::getAddress().toString().c_str());
pinMode(0, INPUT_PULLUP);
lastActivity = millis();
Serial.println("READY");
}
// ---------------- LOOP ----------------
void loop() {
bool keyPressed = false;
int key_id = -1;
// scan keypad
for (int r = 0; r < ROWS; r++) {
digitalWrite(rowPins[r], LOW);
for (int c = 0; c < COLS; c++) {
if (digitalRead(colPins[c]) == LOW) {
delay(20);
if (digitalRead(colPins[c]) == LOW) {
key_id = (r * COLS) + c + 1;
Serial.print("KEY: ");
Serial.println(key_id);
keyPressed = true;
lastActivity = millis();
}
}
}
digitalWrite(rowPins[r], HIGH);
}
// BLE send (isolated from scan)
if (keyPressed && key_id > 0) {
sendBLE(key_id);
delay(30);
sendBLE(0);
}
// sleep logic
if (!keyPressed && (millis() - lastActivity > sleepDelay)) {
// DEBUG: check wake line state BEFORE sleeping
Serial.print("GPIO0 before sleep: ");
Serial.println(digitalRead(0));
if (digitalRead(0) == LOW) {
Serial.println("Wake line already LOW - will sleep and immediately wake again risk");
}
goToSleep();
}
}

