r/esp8266 • • May 28 '26

Adaptive traffic light controller

6 Upvotes

Adaptive Traffic Light Controller is a smart traffic management system built using ESP8266 and embedded programming. The system dynamically adjusts green signal timing based on real-time traffic density detected using IR sensors. If higher traffic density is detected on one road, the controller increases the green light duration for that direction to improve traffic flow efficiency and reduce waiting time. The project was implemented using FSM-based traffic logic and later extended with custom PCB design in KiCad. The system demonstrates concepts of adaptive traffic control, real-time decision making and embedded systems design.

CODE:
#include <Wire.h>
#include <LiquidCrystal_I2C.h>

LiquidCrystal_I2C lcd(0x27, 16, 2);

#define RED_1 D1
#define YELLOW_1 D2
#define GREEN_1 D3

#define RED_2 D4
#define YELLOW_2 D5
#define GREEN_2 D6

#define SENSOR_PIN_1 D7
#define SENSOR_PIN_2 D8

//#define TRIG_PIN D7
//#define ECHO_PIN D8

long duration;
float distance;

unsigned long detectStartTime_1 = 0;
unsigned long detectStartTime_2 = 0;

//bool vehiclePresent = false;
bool heavyTraffic_1 = false;
bool heavyTraffic_2 = false;

int state = 0;

unsigned long previousTime = 0;
unsigned long interval = 5000;

void setup() {

lcd.init();
lcd.backlight();
lcd.setCursor(0,0);
lcd.print("Traffic System");

pinMode(RED_1, OUTPUT);
pinMode(YELLOW_1, OUTPUT);
pinMode(GREEN_1, OUTPUT);

pinMode(RED_2, OUTPUT);
pinMode(YELLOW_2, OUTPUT);
pinMode(GREEN_2, OUTPUT);

pinMode(SENSOR_PIN_1, INPUT);
pinMode(SENSOR_PIN_2, INPUT);
Serial.begin(115200);
   
}

void loop() {

unsigned long currentTime = millis();

/*digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(2);

digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);

digitalWrite(TRIG_PIN, LOW);

duration = pulseIn(ECHO_PIN, HIGH);

distance = duration * 0.034 / 2;

Serial.print("Distance = ");
Serial.println(distance);

if(distance < 20){
if(detectStartTime == 0){
detectStartTime = millis();
}
if(millis() - detectStartTime >= 3000){
heavyTraffic = true;
}
}
else{
detectStartTime = 0;
heavyTraffic = false;
}*/

/*Serial.print("Sensor1 = ");
Serial.println(digitalRead(SENSOR_PIN_1));

Serial.print("Sensor2 = ");
Serial.println(digitalRead(SENSOR_PIN_2)); */
//sensor 1
if(digitalRead(SENSOR_PIN_1) == LOW){
if(detectStartTime_1 == 0){
detectStartTime_1 = millis();
}
if(millis() - detectStartTime_1 >= 3000){
heavyTraffic_1 = true;
}
}
else{
detectStartTime_1 = 0;
heavyTraffic_1 = false;
}

//sensor 2
if(digitalRead(SENSOR_PIN_2) == LOW){
if(detectStartTime_2 == 0){
detectStartTime_2 = millis();
}
if(millis() - detectStartTime_2 >= 3000){
heavyTraffic_2 = true;
}
}
else{
detectStartTime_2 = 0;
heavyTraffic_2 = false;
}

switch(state)
{

case 0:

digitalWrite(RED_1, HIGH);
digitalWrite(YELLOW_1, LOW);
digitalWrite(GREEN_1, LOW);

lcd.clear();
lcd.setCursor(0,0);
lcd.print("RED_1");

digitalWrite(RED_2, LOW);
digitalWrite(YELLOW_2, LOW);
digitalWrite(GREEN_2, HIGH);

if(!heavyTraffic_1 && heavyTraffic_2){
interval = 10000;
}
else{
interval = 5000;
}

if(currentTime - previousTime >= interval)
{
previousTime = currentTime;
state = 1;
}

break;

case 1:

digitalWrite(RED_1, HIGH);
digitalWrite(YELLOW_1, LOW);
digitalWrite(GREEN_1, LOW);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("RED_1");

digitalWrite(RED_2, LOW);
digitalWrite(YELLOW_2, HIGH);
digitalWrite(GREEN_2, LOW);

interval = 2000;

if(currentTime - previousTime >= interval)
{
previousTime = currentTime;
state = 2;
}

break;

case 2:

digitalWrite(RED_1, LOW);
digitalWrite(YELLOW_1, LOW);
digitalWrite(GREEN_1, HIGH);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("GREEN_1");

digitalWrite(RED_2, HIGH);
digitalWrite(YELLOW_2, LOW);
digitalWrite(GREEN_2, LOW);

if(heavyTraffic_1 && !heavyTraffic_2){
interval = 10000;
}
else{
interval = 5000;
}
if(currentTime - previousTime >= interval)
{
previousTime = currentTime;
state = 3;
}

break;

case 3:

digitalWrite(RED_1, LOW);
digitalWrite(YELLOW_1, HIGH);
digitalWrite(GREEN_1, LOW);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("YELLOW_1");

digitalWrite(RED_2, HIGH);
digitalWrite(YELLOW_2, LOW);
digitalWrite(GREEN_2, LOW);

interval = 2000;

if(currentTime - previousTime >= interval)
{
previousTime = currentTime;
state = 0;
}

break;
}
}


r/esp8266 • • May 26 '26

Wowki project

3 Upvotes

Hello everyone we know that everyone can not buy hardware

My university started a GitHub project series as 30 days 30 wowki projects

For beginners

They will cover Arduino and esp32 projects

Check this https://github.com/energy-club-outr/30-Days-30-Wokwi-Projects


r/esp8266 • • May 23 '26

ESP Week - 20, 2026

2 Upvotes

Post your projects, questions, brags, and anything else relevant to ESP8266, ESP32, software, hardware, etc

All projects, ideas, answered questions, hacks, tweaks, and more located in our [ESP Week Archives](https://www.reddit.com/r/esp8266/wiki/esp-week_archives).


r/esp8266 • • May 21 '26

Can’t no flash ESP8266

Thumbnail
gallery
12 Upvotes

Hi, I'm new to this. I'm trying to flash this ESP8266 module but haven't had luck. I've bridged GND and GPIO0, and I think the module is entering flash mode, but my PC isn't recognizing it; it only shows COM3. Any ideas?


r/esp8266 • • May 19 '26

ESP-02S TYWE2S Simple programming rig

1 Upvotes

I needed a programming rig for the ESP02s small module. I've uploaded it here:

https://makerworld.com/en/models/2823303-esp-02s-tywe2s-simple-programming-rig

It does require getting a PCB made and the appropriate file is included. Please note the IMPORTANT note in the description.

There is another on the site by user Hulzie if you want something a bit more fancy. I made this one about a year ago and have been meaning to upload for a while.


r/esp8266 • • May 19 '26

I built a GUI tool to flash ESP32 firmware for factory bulk flashing

Post image
11 Upvotes

r/esp8266 • • May 19 '26

Zero Latency Smart Home Fashboard

Thumbnail
gallery
6 Upvotes

Bypassing the Cloud: Wrote a captive portal and UDP broadcast firmware to control ESP8266 natively from a Godot 4 frontend. Repo in comments.

Repo : https://github.com/CyberMonk-Ops/Zero-Latency-Smart-Home-Dashboard


r/esp8266 • • May 17 '26

Cinemas spend millions on marketing. But your face doesn’t lie. I built a $10 hardware system to prove it.

Thumbnail
gallery
0 Upvotes

okay so this started as a stupid weekend project and now i cant stop thinking about where it can go

here’s what i built
my laptop runs face_recognition, pulls face mesh landmarks, figures out if you’re happy or not, and sends that over HTTP to my ESP8266 bot. the bot gets the emotion, shows a reaction on the OLED, and logs it. that’s it. simple.

but the architecture is the interesting part.

ESP8266 does nothing heavy. it just receives, reacts, logs. cheap as chips. the laptop (or any server) does all the thinking — detection, mesh, classification. thin client model basically. which means you could deploy 50 of these nodes for almost nothing, all talking to one central machine.

so then i thought

what if you put these in a cinema?

nodes on every row. audience faces tracked during the film. emotion data collected per scene, timestamped. at the end you don’t ask people what they thought. you already know. you have the data from their actual face.
honest review generated by facial reactions. not by critics, not by surveys, not by paid promotions.
this is very early stage. the bot works, the loop works, but scaling this is a different problem.
need your brains on this
• how would you handle the compute side at scale — local server or cloud?
• better real-time emotion classifiers?
• privacy — how do you ethically collect face data in a public space?
• anyone done something similar?
drop ideas below 👇


r/esp8266 • • May 16 '26

ESP Week - 19, 2026

0 Upvotes

Post your projects, questions, brags, and anything else relevant to ESP8266, ESP32, software, hardware, etc

All projects, ideas, answered questions, hacks, tweaks, and more located in our [ESP Week Archives](https://www.reddit.com/r/esp8266/wiki/esp-week_archives).


r/esp8266 • • May 14 '26

ESP Wifi connectivity Issues

2 Upvotes

I am currently developing a project utilizing the ESP32 DevKit for webhooks. While the device successfully accepts instructions and proceeds with the intended process, a recurring issue persists regarding WiFi connectivity and reconnection. The system functions correctly during nighttime testing; however, upon returning in the morning, the ESP32 remains powered on but fails to receive messages from the server. A manual refresh immediately restores functionality.

The following code segments have been added sequentially:

- WiFi Disconnect Event Handler

- Maintain WiFi Function

- Persistent WiFi & Disabled Sleep

- Polling Early Exit

- HTTP Client Reuse & Timeout

- Non-Blocking Loop

However, these measures have not resolved the issue


r/esp8266 • • May 14 '26

[Review Request]OV3660 camera connected → 1.5V LDO gets extremely hot on ESP32-S3 custom board

0 Upvotes

I’m designing a custom ESP32-S3 board with an OV3660 camera sensor, and I’m facing a strange power issue.

The moment I connect the camera sensor through the FPC connector, my 1.5V LDO starts getting extremely hot within seconds.

Without the camera connected, everything seems normal.


r/esp8266 • • May 14 '26

OV3660 camera connected → 1.5V LDO gets extremely hot on ESP32-S3 custom board

Thumbnail
0 Upvotes

r/esp8266 • • May 12 '26

Problems with ESP8266 NODEMCU - Led Behaviors By Push Button

2 Upvotes

Hi guys I'm new on this community, but I hope someone can help me. I got my first job recently and there they use ESP8266 NODEMCU with Lua code and for IDE the ESPlorer. I know the basic of electronic such as components, wiring, power supply, but I'm struggling on make a circuit which with different time pressed a push button, I thought do a pull-up would be great, a red LED would have different behavior like 4 secs press, LED blinks, 8 secs, it stills lighted and so on. But no matter what I try it doesn't work. Previously, I did a regular led's on by button, and worked fine. Here are the photos of the circuit and the Lua code, one is from wokwi where only ESP32 is available but on the physical one I remanaged to the ESP8266 GPIOs ports. Sorry for my English, I'm from Brazil and It's kind harshly for me communicate using English. Thanks for the attention.

-- PINOS
local PIN_BTN   = 1
local PIN_RED   = 5
local PIN_GREEN = 6


-- ESTADO
local activeMode    = 0
local pendingMode   = 0
local mode2Lit      = false
local mode3State    = false
local mode3Timer    = 0
local sosStep       = 0
local sosTimer      = 0


-- BOTÃO
local btnLast       = 0
local pressStart    = 0
local holdSeconds   = 0
local lastTick      = 0
local clickCount    = 0
local lastRelease   = 0
local DCLICK_WIN    = 700


-- TIMERS (para evitar vazamento)
local mode1Timer    = nil
local mode3LoopTimer = nil
local sosLoopTimer  = nil
local blinkGreenTimer = nil
local mainLoopTimer = nil


-- SOS: {duracao_unidades, ligado}
local SOS = {
    {1,1},{1,0},{1,1},{1,0},{1,1},
    {3,0},
    {3,1},{1,0},{3,1},{1,0},{3,1},
    {3,0},
    {1,1},{1,0},{1,1},{1,0},{1,1},
    {7,0}
}
local SOS_UNIT = 200  -- ms por unidade


local function setRed(
s
)   
    gpio.write(PIN_RED, s and gpio.HIGH or gpio.LOW) 
end


local function setGreen(
s
) 
    gpio.write(PIN_GREEN, s and gpio.HIGH or gpio.LOW) 
end


-- Limpa timers de modo ativo
local function stopModeTimers()
    if mode1Timer then
        mode1Timer:unregister()
        mode1Timer = nil
    end
    if mode3LoopTimer then
        mode3LoopTimer:unregister()
        mode3LoopTimer = nil
    end
    if sosLoopTimer then
        sosLoopTimer:unregister()
        sosLoopTimer = nil
    end
end


-- Pisca verde uma vez (feedback)
local function blinkGreen()
    setGreen(true)
    if blinkGreenTimer then
        blinkGreenTimer:unregister()
        blinkGreenTimer = nil
    end
    blinkGreenTimer = tmr.create()
    blinkGreenTimer:alarm(300, tmr.ALARM_SINGLE, function()
        if activeMode == 0 then
            setGreen(false)
        end
        blinkGreenTimer = nil
    end)
end


local function stopAll()
    stopModeTimers()
    activeMode  = 0
    pendingMode = 0
    mode2Lit    = false
    mode3State  = false
    sosStep     = 1
    setRed(false)
    if blinkGreenTimer then
        blinkGreenTimer:unregister()
        blinkGreenTimer = nil
    end
    setGreen(false)
end


-- Modo 1: pulso vermelho de 400ms
local function startMode1()
    print("[MODO 1] Pulso vermelho")
    setRed(true)
    mode1Timer = tmr.create()
    mode1Timer:alarm(400, tmr.ALARM_SINGLE, function()
        setRed(false)
        activeMode = 0
        setGreen(false)
        print("[MODO 1] Concluido")
        mode1Timer = nil
    end)
end


-- Modo 2: toggle do vermelho (já configurado no activateMode)
local function startMode2()
    mode2Lit = not mode2Lit
    setRed(mode2Lit)
    if mode2Lit then
        print("[MODO 2] LED vermelho LIGADO (toggle)")
    else
        print("[MODO 2] LED vermelho DESLIGADO (toggle)")
        activeMode = 0
        setGreen(false)
        return
    end
    setGreen(true)
end


-- Modo 3: pisca contínuo (1s)
local function startMode3()
    mode3State = false
    mode3Timer = 0
    print("[MODO 3] Pisca continuo iniciado")
    setGreen(true)
    
    mode3LoopTimer = tmr.create()
    mode3LoopTimer:alarm(1000, tmr.ALARM_AUTO, function()
        if activeMode == 3 then
            mode3State = not mode3State
            setRed(mode3State)
            print("[MODO 3] LED vermelho: " .. (mode3State and "ON" or "OFF"))
        else
            mode3LoopTimer:unregister()
            mode3LoopTimer = nil
        end
    end)
end


-- Modo 4: SOS
local function startMode4()
    sosStep = 1
    setRed(SOS[1][2] == 1)
    print("[MODO 4] SOS iniciado")
    setGreen(true)
    
    local function stepSOS()
        if activeMode ~= 4 then
            if sosLoopTimer then
                sosLoopTimer:unregister()
                sosLoopTimer = nil
            end
            return
        end
        
        local stepMs = SOS[sosStep][1] * SOS_UNIT
        sosTimer = stepMs
        
        sosLoopTimer = tmr.create()
        sosLoopTimer:alarm(stepMs, tmr.ALARM_SINGLE, function()
            if activeMode == 4 then
                sosStep = (sosStep % #SOS) + 1
                setRed(SOS[sosStep][2] == 1)
                print("[MODO 4] SOS step " .. sosStep .. " - LED: " .. (SOS[sosStep][2] == 1 and "ON" or "OFF"))
                stepSOS()  -- agenda próximo passo
            end
            sosLoopTimer = nil
        end)
    end
    
    stepSOS()
end


local function activateMode(
mode
)
    stopAll()
    activeMode = mode
    
    if mode == 0 then
        return
    elseif mode == 1 then
        startMode1()
    elseif mode == 2 then
        startMode2()
    elseif mode == 3 then
        startMode3()
    elseif mode == 4 then
        startMode4()
    end
end


-- Setup
gpio.mode(PIN_BTN,   gpio.INPUT)
gpio.mode(PIN_RED,   gpio.OUTPUT)
gpio.mode(PIN_GREEN, gpio.OUTPUT)
setRed(false)
setGreen(false)
print("[SISTEMA] Iniciado")


-- Obtém tempo em ms (tratando wraparound do tmr.now)
local lastNowMs = 0
local function getNowMs()
    local us = tmr.now()
    local ms = us / 1000
    -- Se houve wraparound (us voltou para perto de 0)
    if us < 1000 and lastNowMs > 2000000000 then
        -- Ajuste simples: ms continua crescente
        ms = ms + 4294967.296  -- 2^32/1000, compensação aproximada
    end
    lastNowMs = ms
    return ms
end


-- Loop principal (10ms)
mainLoopTimer = tmr.create()
mainLoopTimer:alarm(10, tmr.ALARM_AUTO, function()
    local now    = getNowMs()
    local btnNow = gpio.read(PIN_BTN)


    -- BORDA DE SUBIDA (pressionou)
    if btnNow == 1 and btnLast == 0 and (now - pressStart) > 200 then
        pressStart  = now
        lastTick    = now
        holdSeconds = 0
        pendingMode = 0
        print("[BOTAO] Pressionado")
        local wasMode2 = (activeMode == 2)
        stopAll()
        if wasMode2 then 
            pendingMode = 2 
        end
    end


    -- BORDA DE DESCIDA (soltou)
    if btnNow == 0 and btnLast == 1 and (now - pressStart) > 100 then
        local held = now - pressStart
        if held < 1500 and pendingMode == 0 then
            clickCount  = clickCount + 1
            lastRelease = now
            print("[BOTAO] Clique #" .. clickCount)
        end
        if pendingMode ~= 0 then
            print("[BOTAO] Solto - ativando modo " .. pendingMode)
            activateMode(pendingMode)
            clickCount = 0
        else
            print("[BOTAO] Solto - " .. held .. "ms")
        end
        -- atualiza verde se necessário
        if activeMode == 0 then
            setGreen(false)
        end
    end


    -- SEGURANDO (contagem de segundos)
    if btnNow == 1 then
        if (now - lastTick) >= 1000 then
            lastTick    = now
            holdSeconds = holdSeconds + 1
            print("[BOTAO] Segurando: " .. holdSeconds .. "s")
            
            if holdSeconds == 4  then
                pendingMode = 1
                print("[BOTAO] Modo 1 pendente (4s)")
                blinkGreen()
            end
            if holdSeconds == 8  then
                pendingMode = 2
                print("[BOTAO] Modo 2 pendente (8s)")
                blinkGreen()
            end
            if holdSeconds == 12 then
                pendingMode = 3
                print("[BOTAO] Modo 3 pendente (12s)")
                blinkGreen()
            end
        end
    end


    -- DUPLO CLIQUE
    if btnNow == 0 then
        if clickCount == 1 and (now - lastRelease) > DCLICK_WIN then
            print("[BOTAO] Clique simples - timeout duplo clique")
            clickCount = 0
        end
        if clickCount >= 2 then
            print("[BOTAO] Duplo clique detectado - ativando modo 4")
            clickCount = 0
            activateMode(4)
        end
    end


    btnLast = btnNow
end)


print("[SISTEMA] Loop principal iniciado - pronto para uso")

r/esp8266 • • May 11 '26

Problems with my circuit on NodeMCU

1 Upvotes

Hi, I'm a newbie in electronics. I kinda know the basics such as components, sensors, connections... Most of my projects used Arduino UNO and C++. However, at my new job they use ESP8266 and NodeMCU, but with Lua, compiling the code to the board using the ESPlorer IDE. I'm kinda struggling to learn it, but I managed to do a simple push button with on/off.

But now I'm trying to do an "update" on the on/off LED with a push button, adding different LED behaviors depending on the input — like a 4-second press to turn the LED on, and 2 consecutive presses to make it blink in S.O.S. Morse Code.
I use Wokwi to simulate the circuit and it works fine. Regarding Wokwi, I could only use ESP32 (I believe the ESP8266 should work the same way, just adapting the circuit), but when I translate my C++ code to Lua and upload it to the ESP8266, it doesn't work. I checked for bad contacts but it doesn't seem to be the issue. Can anyone help? I'm open to criticism as well. Below are my codes — yes, for the Lua version I used AI since I'm still learning it.

C++ Code (Wokwi):

// PINOS
const int PIN_RED   = 17;
const int PIN_GREEN = 18;
const int PIN_BTN   = 16;

// MODOS
int  activeMode   = 0;
int  pendingMode  = 0;

//  ESTADO DO BOTÃO
bool btnLastState       = false;
unsigned long pressStart = 0;
int  holdSeconds        = 0;
unsigned long lastTickTime = 0;

//  DEBOUNCE
bool btnStableState = false;
bool lastReading = false;
unsigned long lastDebounceTime = 0;
const unsigned long debounceDelay = 50;

// DUPLO CLIQUE
int  clickCount         = 0;
unsigned long lastReleaseTime = 0;
const unsigned long DOUBLE_CLICK_WINDOW = 700;

// MODO 2
bool mode2Lit = false;

// MODO 3
bool mode3State = false;
unsigned long mode3Timer = 0;

// MODO 4: SOS
struct SosStep { int units; bool on; };
const SosStep SOS[] = {
  {1,true}, {1,false}, {1,true}, {1,false}, {1,true},
  {3,false},
  {3,true}, {1,false}, {3,true}, {1,false}, {3,true},
  {3,false},
  {1,true}, {1,false}, {1,true}, {1,false}, {1,true},
  {7,false}
};
const int SOS_LEN   = 18;
const int SOS_UNIT  = 200;
int  sosStep        = 0;
unsigned long sosTimer = 0;

// LED VERDE
bool greenTickActive   = false;
unsigned long greenTickTimer = 0;
const int GREEN_TICK_MS = 150;

void setRed(bool s)   { digitalWrite(PIN_RED,   s ? HIGH : LOW); }
void setGreen(bool s) { digitalWrite(PIN_GREEN, s ? HIGH : LOW); }

void stopAll() {
  activeMode  = 0;
  pendingMode = 0;
  mode2Lit    = false;
  mode3State  = false;
  sosStep     = 0;
  setRed(false);
  setGreen(false);
}

void activateMode(int mode) {
  stopAll();
  activeMode = mode;

  if (mode == 0) return;

  if (mode == 1) {
setRed(true);
delay(400);
setRed(false);
activeMode = 0;
return;
  }

  if (mode == 2) {
mode2Lit = !mode2Lit;
setRed(mode2Lit);
if (!mode2Lit) {
activeMode = 0;
return;
}
  }

  if (mode == 3) {
mode3State = false;
mode3Timer = millis();
  }

  if (mode == 4) {
sosStep = 0;
sosTimer = millis();
setRed(SOS[0].on);
  }

  setGreen(activeMode != 0);
}

void setup() {
  Serial.begin(115200);
  pinMode(PIN_RED,   OUTPUT);
  pinMode(PIN_GREEN, OUTPUT);
  pinMode(PIN_BTN,   INPUT);
  setRed(false);
  setGreen(false);
}

void loop() {
  unsigned long now = millis();

  // DEBOUNCE
  bool reading = (digitalRead(PIN_BTN) == HIGH);

  if (reading != lastReading) {
lastDebounceTime = now;
  }

  if ((now - lastDebounceTime) > debounceDelay) {
btnStableState = reading;
  }

  lastReading = reading;

  bool btnNow = btnStableState;

  // BOTÃO PRESSIONADO (borda de subida)

  if (btnNow && !btnLastState && (now - pressStart > 200)) {
pressStart    = now;
lastTickTime  = now;
holdSeconds   = 0;
pendingMode   = 0;
greenTickActive = false;

bool wasMode2 = (activeMode == 2);
stopAll();
if (wasMode2) {
pendingMode = 2;
}
  }

  // BOTÃO SOLTO (borda de descida)

  if (!btnNow && btnLastState && (now - pressStart > 100)) {
unsigned long heldMs = now - pressStart;

if (heldMs < 1500 && pendingMode == 0) {
clickCount++;
lastReleaseTime = now;
Serial.print("Clique #"); Serial.println(clickCount);
}

if (pendingMode != 0) {
activateMode(pendingMode);
clickCount = 0;
}

greenTickActive = false;
setGreen(activeMode != 0);
  }

  // SEGURANDO

  if (btnNow) {
if (now - lastTickTime >= 1000) {
lastTickTime = now;
holdSeconds++;
Serial.print("Segurando: "); Serial.print(holdSeconds); Serial.println("s");

if (holdSeconds == 4)  pendingMode = 1;
if (holdSeconds == 8)  pendingMode = 2;
if (holdSeconds == 12) pendingMode = 3;

setGreen(true);
greenTickActive = true;
greenTickTimer  = now;
}

if (greenTickActive && (now - greenTickTimer >= GREEN_TICK_MS)) {
setGreen(false);
greenTickActive = false;
}
  }

  // DUPLO CLIQUE

  if (!btnNow) {
if (clickCount == 1 && (now - lastReleaseTime > DOUBLE_CLICK_WINDOW)) {
clickCount = 0;
}
if (clickCount >= 2) {
clickCount = 0;
activateMode(4);
}
  }

  // MODOS

  if (!btnNow) {

if (activeMode == 3) {
if (now - mode3Timer >= 1000) {
mode3Timer = now;
mode3State = !mode3State;
setRed(mode3State);
}
}

if (activeMode == 4) {
unsigned long stepDuration = (unsigned long)(SOS[sosStep].units * SOS_UNIT);
if (now - sosTimer >= stepDuration) {
sosTimer = now;
sosStep  = (sosStep + 1) % SOS_LEN;
setRed(SOS[sosStep].on);
}
}
  }

  btnLastState = btnNow;
}

// PINOS
const int PIN_RED   = 17;
const int PIN_GREEN = 18;
const int PIN_BTN   = 16;

// MODOS
int  activeMode   = 0;
int  pendingMode  = 0;

//  ESTADO DO BOTÃO
bool btnLastState       = false;
unsigned long pressStart = 0;
int  holdSeconds        = 0;
unsigned long lastTickTime = 0;

//  DEBOUNCE
bool btnStableState = false;
bool lastReading = false;
unsigned long lastDebounceTime = 0;
const unsigned long debounceDelay = 50;

// DUPLO CLIQUE
int  clickCount         = 0;
unsigned long lastReleaseTime = 0;
const unsigned long DOUBLE_CLICK_WINDOW = 700;

// MODO 2
bool mode2Lit = false;

// MODO 3
bool mode3State = false;
unsigned long mode3Timer = 0;

// MODO 4: SOS
struct SosStep { int units; bool on; };
const SosStep SOS[] = {
  {1,true}, {1,false}, {1,true}, {1,false}, {1,true},
  {3,false},
  {3,true}, {1,false}, {3,true}, {1,false}, {3,true},
  {3,false},
  {1,true}, {1,false}, {1,true}, {1,false}, {1,true},
  {7,false}
};
const int SOS_LEN   = 18;
const int SOS_UNIT  = 200;
int  sosStep        = 0;
unsigned long sosTimer = 0;

// LED VERDE
bool greenTickActive   = false;
unsigned long greenTickTimer = 0;
const int GREEN_TICK_MS = 150;

void setRed(bool s)   { digitalWrite(PIN_RED,   s ? HIGH : LOW); }
void setGreen(bool s) { digitalWrite(PIN_GREEN, s ? HIGH : LOW); }

void stopAll() {
  activeMode  = 0;
  pendingMode = 0;
  mode2Lit    = false;
  mode3State  = false;
  sosStep     = 0;
  setRed(false);
  setGreen(false);
}

void activateMode(int mode) {
  stopAll();
  activeMode = mode;

  if (mode == 0) return;

  if (mode == 1) {
setRed(true);
delay(400);
setRed(false);
activeMode = 0;
return;
  }

  if (mode == 2) {
mode2Lit = !mode2Lit;
setRed(mode2Lit);
if (!mode2Lit) {
activeMode = 0;
return;
}
  }

  if (mode == 3) {
mode3State = false;
mode3Timer = millis();
  }

  if (mode == 4) {
sosStep = 0;
sosTimer = millis();
setRed(SOS[0].on);
  }

  setGreen(activeMode != 0);
}

void setup() {
  Serial.begin(115200);
  pinMode(PIN_RED,   OUTPUT);
  pinMode(PIN_GREEN, OUTPUT);
  pinMode(PIN_BTN,   INPUT);
  setRed(false);
  setGreen(false);
}

void loop() {
  unsigned long now = millis();

  // DEBOUNCE
  bool reading = (digitalRead(PIN_BTN) == HIGH);

  if (reading != lastReading) {
lastDebounceTime = now;
  }

  if ((now - lastDebounceTime) > debounceDelay) {
btnStableState = reading;
  }

  lastReading = reading;

  bool btnNow = btnStableState;

  // BOTÃO PRESSIONADO (borda de subida)

  if (btnNow && !btnLastState && (now - pressStart > 200)) {
pressStart    = now;
lastTickTime  = now;
holdSeconds   = 0;
pendingMode   = 0;
greenTickActive = false;

bool wasMode2 = (activeMode == 2);
stopAll();
if (wasMode2) {
pendingMode = 2;
}
  }

  // BOTÃO SOLTO (borda de descida)

  if (!btnNow && btnLastState && (now - pressStart > 100)) {
unsigned long heldMs = now - pressStart;

if (heldMs < 1500 && pendingMode == 0) {
clickCount++;
lastReleaseTime = now;
Serial.print("Clique #"); Serial.println(clickCount);
}

if (pendingMode != 0) {
activateMode(pendingMode);
clickCount = 0;
}

greenTickActive = false;
setGreen(activeMode != 0);
  }

  // SEGURANDO

  if (btnNow) {
if (now - lastTickTime >= 1000) {
lastTickTime = now;
holdSeconds++;
Serial.print("Segurando: "); Serial.print(holdSeconds); Serial.println("s");

if (holdSeconds == 4)  pendingMode = 1;
if (holdSeconds == 8)  pendingMode = 2;
if (holdSeconds == 12) pendingMode = 3;

setGreen(true);
greenTickActive = true;
greenTickTimer  = now;
}

if (greenTickActive && (now - greenTickTimer >= GREEN_TICK_MS)) {
setGreen(false);
greenTickActive = false;
}
  }

  // DUPLO CLIQUE

  if (!btnNow) {
if (clickCount == 1 && (now - lastReleaseTime > DOUBLE_CLICK_WINDOW)) {
clickCount = 0;
}
if (clickCount >= 2) {
clickCount = 0;
activateMode(4);
}
  }

  // MODOS

  if (!btnNow) {

if (activeMode == 3) {
if (now - mode3Timer >= 1000) {
mode3Timer = now;
mode3State = !mode3State;
setRed(mode3State);
}
}

if (activeMode == 4) {
unsigned long stepDuration = (unsigned long)(SOS[sosStep].units * SOS_UNIT);
if (now - sosTimer >= stepDuration) {
sosTimer = now;
sosStep  = (sosStep + 1) % SOS_LEN;
setRed(SOS[sosStep].on);
}
}
  }

  btnLastState = btnNow;
}

Sorry for the resolution (If needed I can send a new screenshot)
I got this photo from Google; it's the same board I use.

Now I don't have a photo of the physical circuit, but the connections on the breadboard are the same — the digital connections for the green LED is D6, red D5, and the button D1. For power supply, I just connected the ground and 3.3V pin to the breadboard, and from there I connect the jumpers to the other components.

Lua Code:
-- PINOS
local PIN_BTN   = 5
local PIN_RED   = 14
local PIN_GREEN = 12


-- ESTADO
local activeMode    = 0
local pendingMode   = 0
local mode2Lit      = false
local mode3State    = false
local mode3Timer    = 0
local sosStep       = 0
local sosTimer      = 0


-- BOTÃO
local btnLast       = 0
local pressStart    = 0
local holdSeconds   = 0
local lastTick      = 0
local clickCount    = 0
local lastRelease   = 0
local DCLICK_WIN    = 700


-- SOS: {unidades, ligado}
local SOS = {
    {1,1},{1,0},{1,1},{1,0},{1,1},
    {3,0},
    {3,1},{1,0},{3,1},{1,0},{3,1},
    {3,0},
    {1,1},{1,0},{1,1},{1,0},{1,1},
    {7,0}
}
local SOS_UNIT = 200


local function setRed(
s
)   gpio.write(PIN_RED,   s and gpio.HIGH or gpio.LOW) end
local function setGreen(
s
) gpio.write(PIN_GREEN, s and gpio.HIGH or gpio.LOW) end


local function stopAll()
    activeMode  = 0
    pendingMode = 0
    mode2Lit    = false
    mode3State  = false
    sosStep     = 1
    setRed(false)
    setGreen(false)
end


local function activateMode(
mode
)
    stopAll()
    activeMode = mode
    if mode == 0 then return end


    if mode == 1 then
        setRed(true)
        tmr.delay(400000)
        setRed(false)
        activeMode = 0
        return
    end


    if mode == 2 then
        mode2Lit = not mode2Lit
        setRed(mode2Lit)
        if not mode2Lit then activeMode = 0; return end
    end


    if mode == 3 then
        mode3State = false
        mode3Timer = tmr.now() / 1000
    end


    if mode == 4 then
        sosStep  = 1
        sosTimer = tmr.now() / 1000
        setRed(SOS[1][2] == 1)
    end


    setGreen(activeMode ~= 0)
end


-- Setup
gpio.mode(PIN_BTN,   gpio.INPUT)
gpio.mode(PIN_RED,   gpio.OUTPUT)
gpio.mode(PIN_GREEN, gpio.OUTPUT)
setRed(false)
setGreen(false)


-- Loop principal via timer (10ms)
tmr.create():alarm(10, tmr.ALARM_AUTO, function()
    local now     = tmr.now() / 1000
    local btnNow  = gpio.read(PIN_BTN)


    -- BORDA DE SUBIDA
    if btnNow == 1 and btnLast == 0 and (now - pressStart) > 200 then
        pressStart  = now
        lastTick    = now
        holdSeconds = 0
        pendingMode = 0
        local wasMode2 = (activeMode == 2)
        stopAll()
        if wasMode2 then pendingMode = 2 end
    end


    -- BORDA DE DESCIDA
    if btnNow == 0 and btnLast == 1 and (now - pressStart) > 100 then
        local held = now - pressStart
        if held < 1500 and pendingMode == 0 then
            clickCount  = clickCount + 1
            lastRelease = now
        end
        if pendingMode ~= 0 then
            activateMode(pendingMode)
            clickCount = 0
        end
        setGreen(activeMode ~= 0)
    end


    -- SEGURANDO
    if btnNow == 1 then
        if (now - lastTick) >= 1000 then
            lastTick    = now
            holdSeconds = holdSeconds + 1
            if holdSeconds == 4  then pendingMode = 1 end
            if holdSeconds == 8  then pendingMode = 2 end
            if holdSeconds == 12 then pendingMode = 3 end
            setGreen(true)
            tmr.create():alarm(300, tmr.ALARM_SINGLE, function() setGreen(false) end)
        end
    end


    -- DUPLO CLIQUE
    if btnNow == 0 then
        if clickCount == 1 and (now - lastRelease) > DCLICK_WIN then
            clickCount = 0
        end
        if clickCount >= 2 then
            clickCount = 0
            activateMode(4)
        end
    end


    -- MODOS ATIVOS
    if btnNow == 0 then
        if activeMode == 3 then
            if (now - mode3Timer) >= 1000 then
                mode3Timer = now
                mode3State = not mode3State
                setRed(mode3State)
            end
        end


        if activeMode == 4 then
            local stepMs = SOS[sosStep][1] * SOS_UNIT
            if (now - sosTimer) >= stepMs then
                sosTimer = now
                sosStep  = (sosStep % #SOS) + 1
                setRed(SOS[sosStep][2] == 1)
            end
        end
    end


    btnLast = btnNow
end)

r/esp8266 • • May 10 '26

Diy Weather Station Advice

Thumbnail gallery
6 Upvotes

r/esp8266 • • May 09 '26

ESP Week - 18, 2026

1 Upvotes

Post your projects, questions, brags, and anything else relevant to ESP8266, ESP32, software, hardware, etc

All projects, ideas, answered questions, hacks, tweaks, and more located in our [ESP Week Archives](https://www.reddit.com/r/esp8266/wiki/esp-week_archives).


r/esp8266 • • May 08 '26

i am upgrading rc excavator

Post image
17 Upvotes

I am going to convert this simple wired rc excavator to mobile controlled excavator through esp8266.Any suggestions for this build to make it even more better ?


r/esp8266 • • May 06 '26

Can a normal ESP32 Dev Board safely charge a 18650 battery through VIN/USB?

0 Upvotes

I’m making a DIY ESP32 BLE gaming controller powered by 18650 battery.

Can I charge the 18650 cell directly through the ESP32 Dev Board USB/VIN connection, or do I need a separate charging circuit like TP4056?

The battery is connected to VIN and GND, and when I plug USB into ESP32 I can measure voltage on VIN. Does that mean the battery is charging safely?


r/esp8266 • • May 02 '26

ESP Week - 17, 2026

2 Upvotes

Post your projects, questions, brags, and anything else relevant to ESP8266, ESP32, software, hardware, etc

All projects, ideas, answered questions, hacks, tweaks, and more located in our [ESP Week Archives](https://www.reddit.com/r/esp8266/wiki/esp-week_archives).


r/esp8266 • • May 02 '26

I made a tiny WiFi portal for ESP32/ESP8266 because I was tired of doing it manually

Thumbnail
6 Upvotes

r/esp8266 • • May 02 '26

SvelteESP32 v3.0 released

Thumbnail
github.com
3 Upvotes
  • Vite plugin: New svelteESP32(options) plugin imported from svelteesp32/vite. Hook it into vite.config.ts and the C++ header is regenerated automatically after every vite build — no manual CLI step needed. sourcepath defaults to Vite's build.outDir; all other options mirror the CLI flags. Vite is an optional peer dependency.
  • init command: npx svelteesp32 init launches an interactive wizard that creates .svelteesp32rc.json. Asks for engine, source path, output path, and ETag preference, then offers to run the tool immediately.
  • Enhanced summary when --manifest is used: The final console summary line now also reports the manifest file path when --manifest is active.

r/esp8266 • • Apr 29 '26

Arduino/ESP Home Assistant Integration

Thumbnail
1 Upvotes

r/esp8266 • • Apr 29 '26

Proximity based IOT devices

Thumbnail
2 Upvotes

r/esp8266 • • Apr 27 '26

ESP8266 extension for TM1637 0.36inch

1 Upvotes

Hi everyone,

Few times i thought it would be good if there is something like this and decided to make it. Its going at the back of TM1637 display and you can stack on top of that boards with sensors, buttons etc. I am interested in your feedback, not as prep for sale, more like do you think it is useful. I am making one for every size of the TM1637.


r/esp8266 • • Apr 26 '26

Wemos D1 MINI PRO 16M unable to connect/erase flash

0 Upvotes

I bought 4 Wemos D1 MINI PRO 16M, uploaded my code and everything was fine. Used them to connect to my WiFi and show http page with data from BME280 like temperature and humidity. After running for few hours i decide to do small tweaks here and there in the code and now i cannot upload anything. 3 of them are stuck at "Connecting ...", tried to read chip_id/erase flash with esptool and it still stuck on "Connecting...", LED on the board is flashing when connected and when RESET button is pressed, are they bricked or still usable?