16xRelay with ESP12F Onboard and two Shift Register (74HC595)

Awesome work! Can this be adapted to turn on 16 valves?

1 Like

Sure!
If fitting to the relay, no issue.
Just connect your power to the relay and configure ESPhome to your needs.

e.g. Sprinkler system, some example also here:
Sprinkler

2 Likes

Awesome! Thx. Now I can compare mine to that code see how to use ESPHome as this is a nice complicated setup.

Thx again :smile:

any one was able to use al 16 relays?

Yes.
All tested and working.

Hello All,

I’ve got the same board with 16 relays.
Can anyone please share the source code for the demo sample (Arduino code)?

Thank you.

Hello smart people,

I have purchased a couple of these boards, and was hoping based on the above discussion if someone knows how to adapt this to address the relays directly when uploading a sketch, so something like:

int latchPin = 12;  // Latch pin of 74HC595 is connected to Digital pin 5
int clockPin = 13; // Clock pin of 74HC595 is connected to Digital pin 6
int dataPin = 14;  // Data pin of 74HC595 is connected to Digital pin 4

void setup() 
{
  // Set all the pins of 74HC595 as OUTPUT
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);  
  pinMode(clockPin, OUTPUT);

My problem is, if these 3 pins are the ones to use to address the 74HC595’s then how would you go about sending the data to trigger the LED/RELAY for each of the 16 relays, I’m just a bit out of my depth here and there is no doco and I am awaiting responses from LC Tech in china.

Do I need to care about the OE pin ? Tried to gain some better understanding from this article: In-Depth: How 74HC595 Shift Register Works & Interface with Arduino

But yeah wondering if anyone had any ideas on how to actually control the LED’s/RELAYS on these 16 relay boards when you flash the code it comes shipped with.

Does anyone have example code or the code with which these units are shipped so I could reverse engineer ? The code provided in some of the listings doesn’t seem to do anything I think it is for the lower count relay boards that do direct pinout to relay: DC 5V/12V/24V ESP8266 WIFI 16 Channels Relay Module ESP-12F Development Board | eBay

I know this is more of a HOME automation site, but its the only place I have found a conversation about this board and the code to control it.

I have some code that sort of works on this board (short pin IO0 to GND to put in flash mode)
If anyone knows what the data format you need to feed the 74HC595 I would be eternally grateful, I am just trying stuff but its not particularly reliable (different results dependant on data order sent, makes me think sending too much data and there is overflow from one request to the next).

This version seems to activate Relay 9 (not sure how), then it jump switches between relay 8 and 16.

// LCTech 16ch Relay board with 2x74HC595 shift registers - replicates close to out of box relay testing function
int latchPin = 12;  // Latch pin of 74HC595 is connected to Digital pin 5
int clockPin = 13; // Clock pin of 74HC595 is connected to Digital pin 6
int dataPin = 14;  // Data pin of 74HC595 is connected to Digital pin 4
int oePin = 5;    // oePin - not using this

void setup() 
{
  // Set all the pins of 74HC595 as OUTPUT
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);  
  pinMode(clockPin, OUTPUT);
  pinMode(oePin, OUTPUT);

  // Setup serial comms
  Serial.begin(115200);  
}

void loop() 
{

      Serial.println("Relay #16 = 0b0000");       
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, LSBFIRST, 0b0000);
      digitalWrite(latchPin, HIGH);
      delay(3000);

      Serial.println("Relay #8 = 0b0001");       
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, LSBFIRST, 0b0001);
      digitalWrite(latchPin, HIGH);
      delay(3000);

}

I contacted the manufacture as well, no answer received.
You could check the source code of the component in ESPhome and you would have some indications how to port to arduino.

Hello
I have found out how to control it using Arduino I will create a sample code with a function that takes the relay number and state as a parameter and chang the state.
I will be posting it later today.

Hi Again,
I tried to replicate the demo behavior below is the source code:

int latchPin = 12;  // Latch pin of 74HC595 is connected to Digital pin 5
int clockPin = 13; // Clock pin of 74HC595 is connected to Digital pin 6
int dataPin = 14;  // Data pin of 74HC595 is connected to Digital pin 4
int oePin = 5;    // oePin - not using this

uint16_t Data ;

void setup() 
{
  // Set all the pins of 74HC595 as OUTPUT
  pinMode(latchPin, OUTPUT);
  pinMode(dataPin, OUTPUT);  
  pinMode(clockPin, OUTPUT);
  pinMode(oePin, OUTPUT);

}

void loop() 
{

            Data = 0b0000000000000001;         
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, (Data >> 8));
      shiftOut(dataPin, clockPin, MSBFIRST, Data);
      digitalWrite(latchPin, HIGH);
      delay(100);
            Data = 0b0000000000000011;         
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, (Data >> 8));
      shiftOut(dataPin, clockPin, MSBFIRST, Data);
      digitalWrite(latchPin, HIGH);
      delay(100);
            Data = 0b0000000000000111;         
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, (Data >> 8));
      shiftOut(dataPin, clockPin, MSBFIRST, Data);
      digitalWrite(latchPin, HIGH);
      delay(100);
            Data = 0b0000000000001111;         
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, (Data >> 8));
      shiftOut(dataPin, clockPin, MSBFIRST, Data);
      digitalWrite(latchPin, HIGH);
      delay(100);
            Data = 0b0000000000011111;         
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, (Data >> 8));
      shiftOut(dataPin, clockPin, MSBFIRST, Data);
      digitalWrite(latchPin, HIGH);
      delay(100);
            Data = 0b0000000000111111;         
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, (Data >> 8));
      shiftOut(dataPin, clockPin, MSBFIRST, Data);
      digitalWrite(latchPin, HIGH);
      delay(100);
            Data = 0b0000000001111111;         
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, (Data >> 8));
      shiftOut(dataPin, clockPin, MSBFIRST, Data);
      digitalWrite(latchPin, HIGH);
      delay(100);
            Data = 0b0000000011111111;         
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, (Data >> 8));
      shiftOut(dataPin, clockPin, MSBFIRST, Data);
      digitalWrite(latchPin, HIGH);
      delay(100);
            Data = 0b0000000111111111;         
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, (Data >> 8));
      shiftOut(dataPin, clockPin, MSBFIRST, Data);
      digitalWrite(latchPin, HIGH);
      delay(100);
            Data = 0b0000001111111111;         
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, (Data >> 8));
      shiftOut(dataPin, clockPin, MSBFIRST, Data);
      digitalWrite(latchPin, HIGH);
      delay(100);
            Data = 0b0000011111111111;         
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, (Data >> 8));
      shiftOut(dataPin, clockPin, MSBFIRST, Data);
      digitalWrite(latchPin, HIGH);
      delay(100);
            Data = 0b0000111111111111;         
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, (Data >> 8));
      shiftOut(dataPin, clockPin, MSBFIRST, Data);
      digitalWrite(latchPin, HIGH);
      delay(100);
            Data = 0b0001111111111111;         
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, (Data >> 8));
      shiftOut(dataPin, clockPin, MSBFIRST, Data);
      digitalWrite(latchPin, HIGH);
      delay(100);
            Data = 0b0011111111111111;         
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, (Data >> 8));
      shiftOut(dataPin, clockPin, MSBFIRST, Data);
      digitalWrite(latchPin, HIGH);
      delay(100);
            Data = 0b0111111111111111;         
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, (Data >> 8));
      shiftOut(dataPin, clockPin, MSBFIRST, Data);
      digitalWrite(latchPin, HIGH);
      delay(100);
            Data = 0b1111111111111111;         
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, (Data >> 8));
      shiftOut(dataPin, clockPin, MSBFIRST, Data);
      digitalWrite(latchPin, HIGH);
      delay(100);               
            Data = 0b1111111111111110;
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, (Data >> 8));
      shiftOut(dataPin, clockPin, MSBFIRST, Data);
      digitalWrite(latchPin, HIGH);
      delay(100);
            Data = 0b1111111111111100;
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, (Data >> 8));
      shiftOut(dataPin, clockPin, MSBFIRST, Data);
      digitalWrite(latchPin, HIGH);
      delay(100); 
            Data = 0b1111111111111000;
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, (Data >> 8));
      shiftOut(dataPin, clockPin, MSBFIRST, Data);
      digitalWrite(latchPin, HIGH);
      delay(100); 
            Data = 0b1111111111110000;
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, (Data >> 8));
      shiftOut(dataPin, clockPin, MSBFIRST, Data);
      digitalWrite(latchPin, HIGH);
      delay(100); 
            Data = 0b1111111111100000;
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, (Data >> 8));
      shiftOut(dataPin, clockPin, MSBFIRST, Data);
      digitalWrite(latchPin, HIGH);
      delay(100); 
            Data = 0b1111111111000000;
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, (Data >> 8));
      shiftOut(dataPin, clockPin, MSBFIRST, Data);
      digitalWrite(latchPin, HIGH);
      delay(100); 
            Data = 0b1111111110000000;
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, (Data >> 8));
      shiftOut(dataPin, clockPin, MSBFIRST, Data);
      digitalWrite(latchPin, HIGH);
      delay(100); 
            Data = 0b1111111100000000;
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, (Data >> 8));
      shiftOut(dataPin, clockPin, MSBFIRST, Data);
      digitalWrite(latchPin, HIGH);
      delay(100); 
            Data = 0b1111111000000000;
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, (Data >> 8));
      shiftOut(dataPin, clockPin, MSBFIRST, Data);
      digitalWrite(latchPin, HIGH);
      delay(100); 
            Data = 0b1111110000000000;
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, (Data >> 8));
      shiftOut(dataPin, clockPin, MSBFIRST, Data);
      digitalWrite(latchPin, HIGH);
      delay(100); 
            Data = 0b1111100000000000;
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, (Data >> 8));
      shiftOut(dataPin, clockPin, MSBFIRST, Data);
      digitalWrite(latchPin, HIGH);
      delay(100); 
            Data = 0b1111000000000000;
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, (Data >> 8));
      shiftOut(dataPin, clockPin, MSBFIRST, Data);
      digitalWrite(latchPin, HIGH);
      delay(100); 
            Data = 0b1110000000000000;
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, (Data >> 8));
      shiftOut(dataPin, clockPin, MSBFIRST, Data);
      digitalWrite(latchPin, HIGH);
      delay(100); 
            Data = 0b1100000000000000;
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, (Data >> 8));
      shiftOut(dataPin, clockPin, MSBFIRST, Data);
      digitalWrite(latchPin, HIGH);
      delay(100); 
            Data = 0b1000000000000000;
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, (Data >> 8));
      shiftOut(dataPin, clockPin, MSBFIRST, Data);
      digitalWrite(latchPin, HIGH);
      delay(100); 
            Data = 0b0000000000000000;
      digitalWrite(latchPin, LOW);
      shiftOut(dataPin, clockPin, MSBFIRST, (Data >> 8));
      shiftOut(dataPin, clockPin, MSBFIRST, Data);
      digitalWrite(latchPin, HIGH);
      delay(100); 
}
2 Likes

Hi All

I’ve noticed that if I leave the board unpowered for a long time then I try to plug it it doesn’t start only if I connect the external ttl frasher tx, rx and GND then power it.
Anyone is facing the same?
Once started it remains functional even if unplug the ttl but after 1 to 2 hours it returns to same state.
Is there a jumper that should remain connected ?
But somehow with the electricity stored in the capacitor it could word for some time?

Thank you.

Brilliant work ! That gives full control over all 16 relays including turning any number on at once. Saved me a bundle of pain and trial and error.

I can confirm this works as expected and yes emulates the test mode out of the box.

In regards to issues with it powering on or not powering on, I had real issues with the first one of these I tried to code, kept getting “Connecting ------…-----…Timeout”.
Admittedly I had tried to desolder some of the relay wire connection blocks and had also possibly pushed 5v TTL signals into it or overpowered it using the 5v from the TTL converter. I was at wits end, then pulled another one out of its box and it worked first go using separate regulated power and only RX/TX and GND pins from TTL that specifically pushes out 3.3v signals. My flash and power process is in the description of the video below.

Recorded a video and back-linked to this thread/code.

Note on wiring:
Yellow/Orange/Brown = RX/TX/GND only (I do not connect the power from the TTL unit, TTL unit is 3,3v switchable signal voltage output)
Green/blue leads = connects GND to IO0 through a push button, so I press this to go into flash mode on start
Red/Black = Separate regulated 12v lab supply, it max’s out around 500mA when all the relays are on using the test code above. (check which voltage version you bought before supplying power to board)

Thank you Atef, awesome solution.

Finally got a hold of a link to the manuals, code and utilities for this 16 relay board from LCTech
https://www.mediafire.com/file/vzx664wc9xle9hj/LC-Relay-ESP12-16R-DXX_EN.zip/file

Happy coding.

Anyone willing to share an esphome code aswell with all 16 relay configured? Just as simple switches?

If this one shared is not enough for you, I doubt anyone can help you.

Hi

Awesome topic and timing hehe

Received the unit last week, (16 relay wifi thing, with the 2 bit shifters 595)

Using arduino ide

So far the codes and info in this topic has been most useful getting it to work.
Pin numbers and such.
I had to define a pin for the enable pin before it actually started working.

The thing where I needed actual 24v to switch the relay felt a bit silly ghehe >.<

Anyway, in my sketch, when I use Atef’s code in functions, (16 of ehm) as to try and call them individually with a parameter stating to run the first or the second block of code … ahem … odd results lol

Any of you have an example where I can call each relay individually, setting it on or of ?

Hi Lennaert
Please refer to this simulation, I am in the middle of making a program to control the relays individually with Amazon Alexa.
bellow is part of the code, you can consider the LEDs to be the relays (Make sure to change the 74HC595 at the top int latchPin = 12; int clockPin = 13; int dataPin = 14; int oePin = 5)

Thanks, I already had that running :slight_smile: with indeed the aforementioned pins …
Looking forward to individual relay addressing, atm the logic of the shifters eludes me, at least in application in code. I tried using that code, and 2 others, but they give the same result, one state causes different states for different relays, and the other one (“on” I think) makes the unit crash and reboot.

ets Jan 8 2013,rst cause:2, boot mode:(3,6)

*load 0x4010f000, len 3460, room 16 *
tail 4
chksum 0xcc
*load 0x3fff20b8, len 40, room 4 *
tail 4
chksum 0xc9
csum 0xc9
v0004d560
~ld

From what I can find it indicates some incorrect use of the pins … but I could be wrong.

I’ve missed that post.

Atef, I am very grateful, I took a different approach with your code and got it working as it should, or at least in functionality.

Here is a massively trimmed down version of what I am building, a push web server, with a post/get system for controlling a whole bunch of things. atm it only hold the switches …

Feel free to use

make sure to update the ip in the filename var in the javascript bit (adress of device)

and ofc wifi settings

#include <avr/pgmspace.h>

const char index_html[] PROGMEM = R"rawliteral(
<!doctype html>
  <head>
    <title>Arduino controls</title>
    <meta charset="UTF-8">
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <meta name="viewport" content="initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0" />
    <link rel="icon" href="data:,">
<style>
* { 
  height: 100%;
  width: 100%;
  margin: 0;
  padding: 0;
}


body{
  width: 100%;
  height: 100%;
  background: black !important;
  overflow: hidden; 
  -ms-overflow-style: none; /* for Internet Explorer, Edge */
    scrollbar-width: none; /* for Firefox */
    overflow: no-scroll; 
}
body::-webkit-scrollbar {
    display: none; /* for Chrome, Safari, and Opera */
}

#commonsection{
  position: absolute;
  top: 0.5%;
  left: 1%;
  width: 97.5%;
  height: 8%;
  border: 0.2em groove gold;
  border-radius: 45px;
  background: grey;
  overflow: show;
  box-shadow: 0.2em 0.2em 0.2em 0.2em rgba(255,255,255,.4); 
  z-index: 100;
  }

#switchbuttons{
  position: absolute;
  bottom: 2%;
  left: 1%;
  width: 48%;
  height: 85%;
  border: 0.2em groove gold;
  border-radius: 45px;
  background: grey;
  overflow: hidden;
  z-index: 90;
  transition:1s ease;
}
   button.halves {
     width: 50%;
     float: left;
    }


.responses {
  height: 20px;
}

.bottoms{
  position: absolute;
  bottom: 2%;
  right: 1%;
  width: 48%;
  height: 85%;
  border: 0.2em groove gold;
  border-radius: 2em;
  background: grey;
  overflow: hidden;
  z-index: 90;
  transition:1s ease; 
  }

  
.sections {
/** border: 2px solid red; **/
  width: 14.3em;
  height: 20em;
  float: left;
  padding: 0.1em 0.3em 0.1em 0.3em; 
  }
  .sections button {
      margin: 1%;
      height:15%;
      background: white;
      border: 0.1% solid black;
      border-radius: 45px;
      font-size: 16px;
      font-family: Courier;
      font-weight: bold;
      text-transform: uppercase;
    }



 
.buts{
  width: 90%;
  height: 3vw;
  margin-top: 5px;
  background: white;
  border: 1px groove black;
  border-radius: 3em;
  text-align: center;
  vertical-align: bottom;
  font-size: 1vw;
  font-family: Courier;
  font-weight: bold;
  text-transform: uppercase;
  box-shadow: 2px 2px 12px 1px rgba(255,255,255,.9); 
  z-index: 1500;

}
.buts:hover {
  color: grey;
  border-color: 1px solid grey;
  box-shadow: 0.2em 0.2em 0.2em 0.2em rgba(255,255,255,.4); 
} 
button {
  width: 100%;
  height: 2vw;
  box-shadow: 2px 2px 12px 1px rgba(255,255,255,.9); 
}

button:hover {
  color: grey;
  border-color: 1px solid grey;
  box-shadow: 0.2em 0.2em 0.2em 0.2em rgba(255,255,255,.4); 
} 
  
.coolshadow{
  box-shadow: 0.2em 0.2em 0.2em 0.2em rgba(255,255,255,.4); 
}

button.sectionbuts {
  width: 15em;
  height: 3vw;
  margin-top: 2%;
  line-height: 3vw;
  background: white;
  border: 1px groove black;
  border-radius: 3em;
  text-align: center;
  vertical-align: bottom;
  font-size: 16px;
  font-family: Courier;
  font-weight: bold;
  text-transform: uppercase;
  box-shadow: 2px 2px 12px 1px rgba(255,255,255,.9); 
  z-index: 1500;
}

  

table.tables {
  position: absolute; 
  top: 0; 
  left: 0; 
  width: 100%; 
  height: 100%; 
  vertical-align: top;
}
tr {
  height: 100%; 
  vertical-align: top;
}
td.half {
  padding: 2%;
  width: 50%;
  vertical-align: top;
  text-align: center;
}

.format {font-size:3rem}
small {font-size:1.4rem}
</style>
    <script type="text/javascript">
    

    
    function jsGo(c)
    {
        var command = c;
        var x = "?command=" + command; //encodeURIComponent(command);
        var fileName = "http://192.168.2.94/get"+x;
        var fileName = fileName;
        var ajaxRequest;
        ajaxRequest = new XMLHttpRequest();
        ajaxRequest.onreadystatechange = function(){
            if(ajaxRequest.readyState == 4){
            theParent = document.getElementById("feedtd");
            theKid = document.createElement("div");
            theKid.className = "responses";
            theKid.innerHTML = ajaxRequest.responseText; //decodeURIComponent(ajaxRequest.responseText);
            theParent.appendChild(theKid);
            theParent.insertBefore(theKid, theParent.firstChild);
            }
        }
        ajaxRequest.open("GET", fileName, true);
        ajaxRequest.send(null);
    }
    </script>
</head>
<body>
  <div id="fulldiv" class="fullpage">
    <div id="commonsection">
      
    </div>
    
    

    <div id="switchbuttons">
        <table class="tables">
          <tr class="tables">
            <td class="half">
              <button  class="buts halves"  onclick="jsGo('switch:1:1')">1 on</button>
              <button  class="buts halves"  onclick="jsGo('switch:1:0')">1 off</button>
              <button  class="buts halves"  onclick="jsGo('switch:2:1')">2 on</button>
              <button  class="buts halves"  onclick="jsGo('switch:2:0')">2 off</button>
              <button  class="buts halves"  onclick="jsGo('switch:3:1')">3 on</button>
              <button  class="buts halves"  onclick="jsGo('switch:3:0')">3 off</button>
              <button  class="buts halves"  onclick="jsGo('switch:4:1')">4 on</button>
              <button  class="buts halves"  onclick="jsGo('switch:4:0')">4 off</button>
              <button  class="buts halves"  onclick="jsGo('switch:5:1')">5 on</button>
              <button  class="buts halves"  onclick="jsGo('switch:5:0')">5 off</button>
              <button  class="buts halves"  onclick="jsGo('switch:6:1')">6 on</button>
              <button  class="buts halves"  onclick="jsGo('switch:6:0')">6 off</button>
              <button  class="buts halves"  onclick="jsGo('switch:7:1')">7 on</button>
              <button  class="buts halves"  onclick="jsGo('switch:7:0')">7 off</button>
              <button  class="buts halves"  onclick="jsGo('switch:8:1')">8 on</button>
              <button  class="buts halves"  onclick="jsGo('switch:8:0')">8 off</button>
            </td>
            <td class="half">
              <button  class="buts halves"  onclick="jsGo('switch:9:1')">9 on</button>
              <button  class="buts halves"  onclick="jsGo('switch:9:0')">9 off</button>
              <button  class="buts halves"  onclick="jsGo('switch:10:1')">10 on</button>
              <button  class="buts halves"  onclick="jsGo('switch:10:0')">10 off</button>
              <button  class="buts halves"  onclick="jsGo('switch:11:1')">11 on</button>
              <button  class="buts halves"  onclick="jsGo('switch:11:0')">11 off</button>
              <button  class="buts halves"  onclick="jsGo('switch:12:1')">12 on</button>
              <button  class="buts halves"  onclick="jsGo('switch:12:0')">12 off</button>
              <button  class="buts halves"  onclick="jsGo('switch:13:1')">13 on</button>
              <button  class="buts halves"  onclick="jsGo('switch:13:0')">13 off</button>
              <button  class="buts halves"  onclick="jsGo('switch:14:1')">14 on</button>
              <button  class="buts halves"  onclick="jsGo('switch:14:0')">14 off</button>
              <button  class="buts halves"  onclick="jsGo('switch:15:1')">15 on</button>
              <button  class="buts halves"  onclick="jsGo('switch:15:0')">15 off</button>
              <button  class="buts halves"  onclick="jsGo('switch:16:1')">16 on</button>
              <button  class="buts halves"  onclick="jsGo('switch:16:0')">16 off</button>
            </td>
          </tr>
        </table>
        </div>
    <div id="switchessection" class="bottoms" data="Switches">
        <table class="tables">
          <tr class="tables">
            <td class="half" id="feedtd">
            </td>
            <td class="half">
            </td>
          </tr>
        </table>
    </div>

  </div>
  <script>
if (!!window.EventSource) {
 var source = new EventSource('/events');

 source.addEventListener('open', function(e) {
  console.log("Events Connected");
 }, false);
 source.addEventListener('error', function(e) {
  if (e.target.readyState != EventSource.OPEN) {
    console.log("Events Disconnected");
  }
 }, false);

 source.addEventListener('message', function(e) {
  console.log("message", e.data);
 }, false);


}
</script> 
  </body>
</html>)rawliteral";




//wifi
#include <Arduino.h>
#ifdef ESP32
#include <WiFi.h>
#include <AsyncTCP.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#endif
#include <ESPAsyncWebServer.h>




const char* ssid = "YOUR WIFI"; //your WiFi Name
const char* password = "YOUR PASS";  //Your Wifi Password



AsyncWebServer server(80);
// Create an Event Source on /events
AsyncEventSource events("/events");

unsigned long lastTime = 0;  
unsigned long timerDelay = 30000;

const char* PARAM_INPUT_1 = "command";
const char* PARAM_MESSAGE = "command";

void notFound(AsyncWebServerRequest *request) {
    request->send(404, "text/plain", "Not found");
}
//Progmem
#define PROGMEM   ICACHE_RODATA_ATTR
#define ICACHE_RODATA_ATTR  __attribute__((section(".irom.text")))
#define PGM_P       const char *
#define PGM_VOID_P  const void *
#define PSTR(s) (__extension__({static const char __c[] PROGMEM = (s); &__c[0];}))


char buffer[18];
char reply[22];


#define LATCH_PIN 12  // Latch pin of 74HC595 is connected to Digital pin 5
#define CLOCK_PIN 13  // Clock pin of 74HC595 is connected to Digital pin 6
#define DATA_PIN  14  // Data pin of 74HC595 is connected to Digital pin 4
#define OE_PIN    5   // oePin - not using this

enum RELAY_ID {
    RELAY_ID_1,
    RELAY_ID_2,
    RELAY_ID_3,
    RELAY_ID_4,
    RELAY_ID_5,
    RELAY_ID_6,
    RELAY_ID_7,
    RELAY_ID_8,
    RELAY_ID_9,
    RELAY_ID_10,
    RELAY_ID_11,
    RELAY_ID_12,
    RELAY_ID_13,
    RELAY_ID_14,
    RELAY_ID_15,
    RELAY_ID_16
};

enum RELAY_STATE {
    RELAY_STATE_OFF,
    RELAY_STATE_ON,
};

uint16_t Relays_Status_Current = 0;
uint16_t Relays_Status_Stored = 0;

void Update_Relays_State();
void Set_Relay_Status(RELAY_ID ID, RELAY_STATE STATE);
RELAY_STATE Get_Relay_Status(RELAY_ID ID);
void Init_Shifter_Pins();


void switcher(int p,int s){

p = p -1;

  for(int i = 0; i<=15; i++)
  {
      if(p == i){    
          if(s == 1){
          Set_Relay_Status((RELAY_ID)i, RELAY_STATE_ON);
          }
          if(s == 0){
          Set_Relay_Status((RELAY_ID)i, RELAY_STATE_OFF);
          }
      }

    Update_Relays_State();
    delay(100);
  }

}


String getValue(String data, char separator, int index){
    int found = 0;
    int strIndex[] = { 0, -1 };
    int maxIndex = data.length() - 1;
    for (int i = 0; i <= maxIndex && found <= index; i++) {
        if (data.charAt(i) == separator || i == maxIndex) {
            found++;
            strIndex[0] = strIndex[1] + 1;
            strIndex[1] = (i == maxIndex) ? i+1 : i;
        }
    }
    return found > index ? data.substring(strIndex[0], strIndex[1]) : "";
}


void checkcommand(String inputMessage){
      float value;
      String command;
      inputMessage.trim();
         command = getValue(inputMessage, ':', 0);
             
            if(command == "switch"){
              int  unit = getValue(inputMessage, ':', 1).toInt();
              int stat = getValue(inputMessage, ':', 2).toInt();
              String(command + String(unit) + ":"+  String(stat)).toCharArray(reply, 20);
                switcher(unit, stat);
              }
            
          if(strcmp(reply, "unknown") == 0) {
            String("unknown:" + inputMessage).toCharArray(reply, 20);
            }
       

          
}

// Initialize WiFi
void initWiFi() {
  ESP.eraseConfig(); 
    WiFi.mode(WIFI_STA);
    WiFi.begin(ssid, password);
    Serial.print("Connecting to WiFi ..");
    while (WiFi.status() != WL_CONNECTED) {
        Serial.print('.');
        delay(1000);
    }
    Serial.println(WiFi.localIP());
}


String processor(const String& var){


  return String();
}



void setup() {
#if ESP8266
  Serial.begin(115200, SERIAL_8N1, SERIAL_TX_ONLY);
#else  // ESP8266
  Serial.begin(115200, SERIAL_8N1);
#endif  // ESP8266

  Init_Shifter_Pins();

   String("unknown").toCharArray(reply, 8);

      
  delay(10);
  initWiFi();
  delay(10);


   
  // Handle Web Server
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/html", index_html, processor);
  });

  // Send a GET request to <ESP_IP>/get?input1=<inputMessage>
  server.on("/get", HTTP_GET, [] (AsyncWebServerRequest *request) {
    String com;
    String vari;
    // GET input1 value on <ESP_IP>/get?input1=<inputMessage>
    if (request->hasParam(PARAM_INPUT_1)) {
      com = request->getParam(PARAM_INPUT_1)->value();
        vari = PARAM_INPUT_1;
    }  else {
      com = "No message sent";
      vari = "none";
    }
  if(vari == "command"){

  checkcommand(com); 
//String("awesome reply").toCharArray(reply, 20); 

  } else {
      strcpy(reply, "unknown");
    }
    
    request->send(200, "text/html", reply);
    strcpy(reply, "");
  });

  // Handle Web Server Events
  events.onConnect([](AsyncEventSourceClient *client){
    if(client->lastId()){
      //Serial.printf("Client reconnected! Last message ID that it got is: %u\n", client->lastId());
    }
    // send event with message "hello!", id current millis
    // and set reconnect delay to 1 second
    client->send("hello!", NULL, millis(), 10000);
  });
  server.addHandler(&events);
  server.begin();  

}



void loop() {

 delay(0); 
}




void Update_Relays_State()
{
  //Check if the State has changed
  if (Relays_Status_Current != Relays_Status_Stored)
  {
    //Update the EEPROM
    
    //Set Relays_Status_Stored to Relays_Status_Current
    Relays_Status_Stored = Relays_Status_Current;
    //Send data to Shifter
    digitalWrite(LATCH_PIN, LOW);
    shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, (Relays_Status_Stored >> 8));
    shiftOut(DATA_PIN, CLOCK_PIN, MSBFIRST, Relays_Status_Stored);
    digitalWrite(LATCH_PIN, HIGH);

  }else{
    //Do nothing
  }
}

void Set_Relay_Status(RELAY_ID ID, RELAY_STATE STATE)
{
  bitWrite(Relays_Status_Current, ID, STATE);
}

RELAY_STATE Get_Relay_Status(RELAY_ID ID)
{
  return (RELAY_STATE)bitRead(Relays_Status_Current, ID);
}

void Init_Shifter_Pins()
{
  // Set all the pins of 74HC595 as OUTPUT
  pinMode(LATCH_PIN, OUTPUT);
  pinMode(DATA_PIN, OUTPUT);  
  pinMode(CLOCK_PIN, OUTPUT);
  pinMode(OE_PIN, OUTPUT);
}