Make a button to interact with esp32cam webpage

Hi, it's my first post here, so forgive me if it is in the wrong topic or whatever.
what I am trying to do is a button inside the app that let me turn on and off face recognition in esp32cam webpage(I also need to turn resolution to CIF to activate it). So far i managed to make the stream work and avoid the "header fields are too long" issue, following other topics in here. I also came across a topic that helped to make a button that interact with an html page but I tried and it did not work for me. Since i can't acess the full webpage i'm stuck with only the stream and can't really use face recognition on my app. The code i am using for esp32 is not the same in the esp32 camera arduino example, instead it is another one created by someone and shared with the community. So the html is not encoded and i can post the full html code here. I don't know how to post images here so i can't really show my progress on the app so far. I am using customwebview to make the stream work. I tried really hard before asking this here, but really couldn't do it (I don't have too much experience with any tipe of coding)... so thanks in advance and sorry again if anything is wrong.

the html of my code:

<!doctype html>
<html>
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width,initial-scale=1">
        <title>ESP32 OV2460</title>
        <style> 
          body { font-family: Arial,Helvetica,sans-serif; background: #181818; color: #EFEFEF; font-size: 16px } h2 { font-size: 18px } section.main { display: flex } #menu,section.main { flex-direction: column } #menu { display: none; flex-wrap: nowrap; min-width: 340px; background: #363636; padding: 8px; border-radius: 4px; margin-top: -10px; margin-right: 10px; } #content { display: flex; flex-wrap: wrap; align-items: stretch } figure { padding: 0px; margin: 0; -webkit-margin-before: 0; margin-block-start: 0; -webkit-margin-after: 0; margin-block-end: 0; -webkit-margin-start: 0; margin-inline-start: 0; -webkit-margin-end: 0; margin-inline-end: 0 } figure img { display: block; width: 100%; height: auto; border-radius: 4px; margin-top: 8px; } @media (min-width: 800px) and (orientation:landscape) { #content { display:flex; flex-wrap: nowrap; align-items: stretch } figure img { display: block; max-width: 100%; max-height: calc(100vh - 40px); width: auto; height: auto } figure { padding: 0 0 0 0px; margin: 0; -webkit-margin-before: 0; margin-block-start: 0; -webkit-margin-after: 0; margin-block-end: 0; -webkit-margin-start: 0; margin-inline-start: 0; -webkit-margin-end: 0; margin-inline-end: 0 } } section#buttons { display: flex; flex-wrap: nowrap; justify-content: space-between } #nav-toggle { cursor: pointer; display: block } #nav-toggle-cb { outline: 0; opacity: 0; width: 0; height: 0 } #nav-toggle-cb:checked+#menu { display: block } .input-group { display: flex; flex-wrap: nowrap; line-height: 22px; margin: 5px 0 } .input-group>label { display: inline-block; padding-right: 10px; min-width: 47% } .input-group input,.input-group select { flex-grow: 1 } .range-max,.range-min { display: inline-block; padding: 0 5px } button { display: block; margin: 5px; padding: 0 12px; border: 0; line-height: 28px; cursor: pointer; color: #fff; background: #ff3034; border-radius: 5px; font-size: 16px; outline: 0 } button:hover { background: #ff494d } button:active { background: #f21c21 } button.disabled { cursor: default; background: #a0a0a0 } input[type=range] { -webkit-appearance: none; width: 100%; height: 22px; background: #363636; cursor: pointer; margin: 0 } input[type=range]:focus { outline: 0 } input[type=range]::-webkit-slider-runnable-track { width: 100%; height: 2px; cursor: pointer; background: #EFEFEF; border-radius: 0; border: 0 solid #EFEFEF } input[type=range]::-webkit-slider-thumb { border: 1px solid rgba(0,0,30,0); height: 22px; width: 22px; border-radius: 50px; background: #ff3034; cursor: pointer; -webkit-appearance: none; margin-top: -11.5px } input[type=range]:focus::-webkit-slider-runnable-track { background: #EFEFEF } input[type=range]::-moz-range-track { width: 100%; height: 2px; cursor: pointer; background: #EFEFEF; border-radius: 0; border: 0 solid #EFEFEF } input[type=range]::-moz-range-thumb { border: 1px solid rgba(0,0,30,0); height: 22px; width: 22px; border-radius: 50px; background: #ff3034; cursor: pointer } input[type=range]::-ms-track { width: 100%; height: 2px; cursor: pointer; background: 0 0; border-color: transparent; color: transparent } input[type=range]::-ms-fill-lower { background: #EFEFEF; border: 0 solid #EFEFEF; border-radius: 0 } input[type=range]::-ms-fill-upper { background: #EFEFEF; border: 0 solid #EFEFEF; border-radius: 0 } input[type=range]::-ms-thumb { border: 1px solid rgba(0,0,30,0); height: 22px; width: 22px; border-radius: 50px; background: #ff3034; cursor: pointer; height: 2px } input[type=range]:focus::-ms-fill-lower { background: #EFEFEF } input[type=range]:focus::-ms-fill-upper { background: #363636 } .switch { display: block; position: relative; line-height: 22px; font-size: 16px; height: 22px } .switch input { outline: 0; opacity: 0; width: 0; height: 0 } .slider { width: 50px; height: 22px; border-radius: 22px; cursor: pointer; background-color: grey } .slider,.slider:before { display: inline-block; transition: .4s } .slider:before { position: relative; content: ""; border-radius: 50%; height: 16px; width: 16px; left: 4px; top: 3px; background-color: #fff } input:checked+.slider { background-color: #ff3034 } input:checked+.slider:before { -webkit-transform: translateX(26px); transform: translateX(26px) } select { border: 1px solid #363636; font-size: 14px; height: 22px; outline: 0; border-radius: 5px } .image-container { position: relative; min-width: 160px } .close { position: absolute; right: 5px; top: 5px; background: #ff3034; width: 16px; height: 16px; border-radius: 100px; color: #fff; text-align: center; line-height: 18px; cursor: pointer } .hidden { display: none } 
        </style>
    </head>
    <body>
        <figure>
            <div id="stream-container" class="image-container hidden">
                <div class="close" id="close-stream">×</div>
                <img id="stream" src="" crossorigin="anonymous">
            </div>
        </figure>    
        <section class="main">
            <div id="logo">
                <label for="nav-toggle-cb" id="nav-toggle">&#9776;&nbsp;&nbsp;Toggle OV2640 settings</label>
            </div>
            <div id="content">
                <div id="sidebar">
                    <input type="checkbox" id="nav-toggle-cb" checked="checked">
                    <nav id="menu">
                        <section id="buttons">
                            <button id="get-still">Get Still</button>
                            <button id="toggle-stream">Start Stream</button>
                            <button id="face_enroll" class="disabled" disabled="disabled">Enroll Face</button>
                        </section> 
                        <div class="input-group" id="face_detect-group">
                            <label for="face_detect">Face Detection</label>
                            <div class="switch">
                                <input id="face_detect" type="checkbox" class="default-action">
                                <label class="slider" for="face_detect"></label>
                            </div>
                        </div>
                        <div class="input-group" id="face_recognize-group">
                            <label for="face_recognize">Face Recognition</label>
                            <div class="switch">
                                <input id="face_recognize" type="checkbox" class="default-action">
                                <label class="slider" for="face_recognize"></label>
                            </div>
                        </div>                        
                        <div class="input-group" id="flash-group">
                            <label for="flash">Flash</label>
                            <div class="range-min">0</div>
                            <input type="range" id="flash" min="0" max="255" value="0" onchange="try{fetch(document.location.origin+'/control?var=flash&val='+this.value);}catch(e){}" class="default-action">
                            <div class="range-max">255</div>
                        </div>                        
                        <div class="input-group" id="framesize-group">
                            <label for="framesize">Resolution</label>
                            <select id="framesize" class="default-action">
                                <option value="10">UXGA(1600x1200)</option>
                                <option value="9">SXGA(1280x1024)</option>
                                <option value="8">XGA(1024x768)</option>
                                <option value="7">SVGA(800x600)</option>
                                <option value="6">VGA(640x480)</option>
                                <option value="5" selected="selected">CIF(400x296)</option>
                                <option value="4">QVGA(320x240)</option>
                                <option value="3">HQVGA(240x176)</option>
                                <option value="0">QQVGA(160x120)</option>
                            </select>
                        </div>
                        <div class="input-group" id="quality-group">
                            <label for="quality">Quality</label>
                            <div class="range-min">10</div>
                            <input type="range" id="quality" min="10" max="63" value="10" class="default-action">
                            <div class="range-max">63</div>
                        </div>
                        <div class="input-group" id="brightness-group">
                            <label for="brightness">Brightness</label>
                            <div class="range-min">-2</div>
                            <input type="range" id="brightness" min="-2" max="2" value="0" class="default-action">
                            <div class="range-max">2</div>
                        </div>
                        <div class="input-group" id="contrast-group">
                            <label for="contrast">Contrast</label>
                            <div class="range-min">-2</div>
                            <input type="range" id="contrast" min="-2" max="2" value="0" class="default-action">
                            <div class="range-max">2</div>
                        </div>
                        <div class="input-group" id="facename-group">
                            <label for="facename">Face Name</label>
                            <select id="faceid" class="default-action">
                              <option value="0">0</option>
                              <option value="1">1</option>
                              <option value="2">2</option>
                              <option value="3">3</option>
                              <option value="4">4</option>
                              <option value="5">5</option>
                              <option value="6">6</option>
                            </select>
                            <input type="text" id="facename" size="6" style="height:16px">
                            <button onclick="var ifr = document.getElementById('ifr');var ifrlab = document.getElementById('ifrlab');ifr.style.display='block';ifrlab.style.display='block';ifr.src=document.location.origin+'/control?facename='+document.getElementById('faceid').value+';'+document.getElementById('facename').value;">Set</button>
                        </div>    
                        <div class="input-group" id="facename-group">
                            <label for="facename"></label>
                            <button onclick="var ifr = document.getElementById('ifr');ifr.src=document.location.origin+'/control?deleteface'">Clear Face</button>
                        </div> 
                        <div class="input-group" id="contrast-group">
                            <label id="ifrlab" style="display:none;" for="ifr">Name List</label>
                            <iframe id="ifr" style="display:none;width:170px"></iframe>
                        </div>  
                        <div class="input-group" id="controlstate-group">
                            <label for="controlstate">Control State</label>
                            <div class="switch">
                                <input id="controlstate" type="checkbox" class="default-action">
                                <label class="slider" for="controlstate"></label>
                            </div>
                        </div>
                    </nav>
                </div>
            </div>
        </section>
        
        <script>
          document.addEventListener('DOMContentLoaded', function (event) {
            var baseHost = document.location.origin
            var streamUrl = baseHost + ':81'
          
            const hide = el => {
              el.classList.add('hidden')
            }
            const show = el => {
              el.classList.remove('hidden')
            }
          
            const disable = el => {
              el.classList.add('disabled')
              el.disabled = true
            }
          
            const enable = el => {
              el.classList.remove('disabled')
              el.disabled = false
            }
          
            const updateValue = (el, value, updateRemote) => {
              updateRemote = updateRemote == null ? true : updateRemote
              let initialValue
              if (el.type === 'checkbox') {
                initialValue = el.checked
                value = !!value
                el.checked = value
              } else {
                initialValue = el.value
                el.value = value
              }
          
              if (updateRemote && initialValue !== value) {
                updateConfig(el);
              } else if(!updateRemote){
                if(el.id === "aec"){
                  value ? hide(exposure) : show(exposure)
                } else if(el.id === "agc"){
                  if (value) {
                    show(gainCeiling)
                    hide(agcGain)
                  } else {
                    hide(gainCeiling)
                    show(agcGain)
                  }
                } else if(el.id === "awb_gain"){
                  value ? show(wb) : hide(wb)
                } else if(el.id === "face_recognize"){
                  value ? enable(enrollButton) : disable(enrollButton)
                }
              }
            }
          
            function updateConfig (el) {
              let value
              switch (el.type) {
                case 'checkbox':
                  value = el.checked ? 1 : 0
                  break
                case 'range':
                case 'select-one':
                  value = el.value
                  break
                case 'button':
                case 'submit':
                  value = '1'
                  break
                default:
                  return
              }
          
              const query = `${baseHost}/control?var=${el.id}&val=${value}`
          
              fetch(query)
                .then(response => {
                  console.log(`request to ${query} finished, status: ${response.status}`)
                })
            }
          
            document
              .querySelectorAll('.close')
              .forEach(el => {
                el.onclick = () => {
                  hide(el.parentNode)
                }
              })
          
            // read initial values
            fetch(`${baseHost}/status`)
              .then(function (response) {
                return response.json()
              })
              .then(function (state) {
                document
                  .querySelectorAll('.default-action')
                  .forEach(el => {
                    updateValue(el, state[el.id], false)
                  })
              })
          
            const view = document.getElementById('stream')
            const viewContainer = document.getElementById('stream-container')
            const stillButton = document.getElementById('get-still')
            const streamButton = document.getElementById('toggle-stream')
            const enrollButton = document.getElementById('face_enroll')
            const closeButton = document.getElementById('close-stream')
          
            const stopStream = () => {
              window.stop();
              streamButton.innerHTML = 'Start Stream'
            }
          
            const startStream = () => {
              view.src = `${streamUrl}/stream`
              show(viewContainer)
              streamButton.innerHTML = 'Stop Stream'
            }
          
            // Attach actions to buttons
            stillButton.onclick = () => {
              stopStream()
              view.src = `${baseHost}/capture?_cb=${Date.now()}`
              show(viewContainer)
            }
          
            closeButton.onclick = () => {
              stopStream()
              hide(viewContainer)
            }
          
            streamButton.onclick = () => {
              const streamEnabled = streamButton.innerHTML === 'Stop Stream'
              if (streamEnabled) {
                stopStream()
              } else {
                startStream()
              }
            }
          
            enrollButton.onclick = () => {
              updateConfig(enrollButton)
            }
          
            // Attach default on change action
            document
              .querySelectorAll('.default-action')
              .forEach(el => {
                el.onchange = () => updateConfig(el)
              })
          
            // Custom actions
          
            // Detection and framesize
            const detect = document.getElementById('face_detect')
            const recognize = document.getElementById('face_recognize')
            const framesize = document.getElementById('framesize')
            
            const controlstate = document.getElementById('controlstate')
          
            framesize.onchange = () => {
              updateConfig(framesize)
              if (framesize.value > 5) {
                updateValue(detect, false)
                updateValue(recognize, false)
              }
            }
          
            detect.onchange = () => {
              if (framesize.value > 5) {
                alert("Please select CIF or lower resolution before enabling this feature!");
                updateValue(detect, false)
                return;
              }
              updateConfig(detect)
              if (!detect.checked) {
                disable(enrollButton)
                updateValue(recognize, false)
              }
            }
          
            recognize.onchange = () => {
              if (framesize.value > 5) {
                alert("Please select CIF or lower resolution before enabling this feature!");
                updateValue(recognize, false)
                return;
              }
              updateConfig(recognize)
              if (recognize.checked) {
                enable(enrollButton)
                updateValue(detect, true)
              } else {
                disable(enrollButton)
              }
            }

            controlstate.onchange = () => {
              if (controlstate.checked) {
                fetch(document.location.origin+'/control?controlstate=1');
              } else {
                fetch(document.location.origin+'/control?controlstate=0');
              }  
            }            
          })
        </script>
    </body>
</html>

(I edited your post to make the html readable)

Use the upload button

image

to upload files and images to your posts

thanks!

I tried using these two methods on the right side, none have worked ...

There are no elements in your html with an "id" tag, e.g. id="img1", and you do not set the value of your variable id...

really, i though the id was here:

                        </div>
                        <div class="input-group" id="face_recognize-group">
                            <label for="face_recognize">Face Recognition</label>
                            <div class="switch">
                                <input id="face_recognize" type="checkbox" class="default-action">
                                <label class="slider" for="face_recognize"></label>
                            </div>
                        </div>  

and i thought i had set the id value here :

2

I have no idea what to do, can't even start thinking on how to change the resolution to CIF, wich i'll have too. :grimacing: ... could you shed a light please?(just tell me if it can be done and how.) Thanks.

This is all I can see

image

Sorry, i didn't understant what you meant. You can't see the rest of the image? is there any information that is missing?