creating a PWA camera application based on ESP-32

Viewed 25

I would like to ask a question, because I haven't found anything similar on the Internet. I wrote a pwa application for the ESP-32 Cam camera with custom firmware. Everything works perfectly on the local host, but when I put the application on github and connect github pages, my application works, but when I try to get information from the camera, which is located on ip 192.168.4.1, it gives an error: GET https://192.168.4.1/scan net::ERR_CONNECTION_REFUSED

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width; initial-scale=1.0; maximum-scale=1.0; user-scalable=0;">
    <title>KKKCam App</title>
    <link rel="stylesheet" type="text/css" href="elements/styles/style.css">
    <link rel="manifest" href="manifest.json">
    <link rel="stylesheet" type="text/css" href="elements/styles/animation.css">
    <meta http-equiv='cache-control' content='no-cache'>
    <meta http-equiv='expires' content='0'>
    <meta http-equiv='pragma' content='no-cache'>
    <script type="text/javascript">
        let app = {}
        app.fs = window.localStorage;
        if (typeof app.fs.cams == "undefined") {
            app.fs.cams = '[]'
        }

    </script>
</head>
<body>

    <div class="app-preloader screen">
        
        <div class="title"></div>

        <div class="loader" animation-type='loader'></div>

    </div>

    <div class="app-home screen">
        
        <div class="title">KKKCam</div>

        <div app-type='standalone'>
            
            <div class="not-devices" style="display: none;">
                <span class="nd-title">Привет!<img src="elements/emoji/.png" width="24"></span>
                <span class="nd-message">У вас нет добавленных устройств...<br>Не хотите добавить?</span>
                <span class="apple-symbol nd-add sf-button"></span>
            </div>


        </div>

        <div app-type='browser'>
            
            <div class="alert-box">
                    
                <div class="title">Установите приложение!</div>

                <div class="text">
                    Для правильной работы Web приложения его надо установить!<br><br>
                    Для android устройств:
                    <ul>
                        <li>Откройте меню</li>
                        <li>Нажмите на кнопку "Добавить на главный экран"</li>
                        <li>Нажмите "Добавить"</li>
                    </ul>
                    Для устройств Apple (Safari):
                    <ul>
                        <li>Откройте меню, нажатием кнопки <span class="apple-symbol"></span></li>
                        <li>На экран "Домой"<span class="apple-symbol"></span></li>
                        <li>Нажмите "Добавить"</li>
                    </ul>
                    Далее на домашнем экране появится иконка приложения!
                </div>

            </div>

        </div>


    </div>

    <div class="screen-popup app-add-device">
        
        <div class='mini-screen-1'>
            
            <div class="title">Добавить устройство</div>

            <div class="message">Для начала подключитесь к доступной точке доступа Wifi под названием "KKKCam Setup"<br>Далее нажмите на кнопку продолжить и дождитесь ответа камеры</div>

            <div class="button-bottom" onclick="

                let n = new XMLHttpRequest;
                n.timeout = 5e3;
                n.open('GET', 'http://192.168.4.1/scan', true);
                n.onload = function() {

                    mini_screen_redirect(dqs('.screen-popup.app-add-device .mini-screen-1'), dqs('.screen-popup.app-add-device .mini-screen-2'));

                    let db = JSON.parse(n.response).networks

                    let html = ''

                    for (var i = 0; i < db.length; i++) {
                        html += '<div class=\'network\'><div class=\'icon signal-100\'></div><div class=\'name\'>' + db[i].name + '</div>'
                        html += '<div class=\'locked\'></div><div class=\'connect\' onclick=\'connect_to_wifi(' + JSON.stringify(db[i]) +')\'><span class=\'apple-symbol\'></span></div></div>'
                    }
                    dqs('.mini-screen-2 .wifi-networks').innerHTML = html

                }
                n.onerror = function(){

                }
                n.send()
                


            ">Продолжить <span class="apple-symbol"></span></div>
    

        </div>

        <div class="mini-screen-2">
            
            <div class="title">Подключение к сети</div>

            <div class="message">Выберите wifi сеть для подключения к ней</div>

            <div class="wifi-networks">
                
                <div class="network">
                    <div class="icon signal-100"></div>
                    <div class="name">Wifi1</div>
                    <div class="locked"></div>
                    <div class="connect"><span class="apple-symbol"></span></div>
                </div>

                <div class="network">
                    <div class="icon signal-100"></div>
                    <div class="name">Wifi1</div>
                    <div class="locked"></div>
                    <div class="connect"><span class="apple-symbol"></span></div>
                </div>

                <div class="network">
                    <div class="icon signal-100"></div>
                    <div class="name">Wifi1</div>
                    <div class="locked"></div>
                    <div class="connect"><span class="apple-symbol"></span></div>
                </div>

            </div>


        </div>

        <div class="mini-screen-3">
            
            <div class="title">Подключение к {wifi_name}</div>

            <div class="message">Введите пароль от wifi сети</div>

            <input type="password" class="password-in" placeholder="Введите пароль от сети">
            
            <div class="button-bottom" onclick="

            let l = new XMLHttpRequest;
            l.timeout = 5e3;
            l.open('GET', 'http://192.168.4.1/connect?net={wifi_name_full}&pass=' + dqs('.mini-screen-3 .password-in').value, true);
            l.onload = function(){

                console.log(l.response)

                dqs('.mini-screen-4').innerHTML = dqs('.mini-screen-4').innerHTML.replaceAll('{ip}', JSON.parse(l.response).ip)

                mini_screen_redirect(dqs('.screen-popup.app-add-device .mini-screen-3'), dqs('.screen-popup.app-add-device .mini-screen-4'));

            }
            l.send()

            ">Подключить <span class="apple-symbol"></span></div>

        </div>

        <div class="mini-screen-4">
            
            <div class="title">Почти готово!</div>

            <div class="message">Данные на камеру отправлены!<br>Теперь подключитесь к сети к которой подключили камеру и мы закончим настройку устройства!</div>
            <div class="button-bottom" onclick="

            let n = new XMLHttpRequest;
            n.timeout = 5e3;
            n.open('GET', 'http://{ip}/temp', true)
            n.onload = function(){
                
                let camera = {}
                camera.ip = '{ip}'
                camera.wifi = '{wifi_name_full}'
                let dt = JSON.parse(app.fs.cams)
                dt.push(camera)
                app.fs.cams = JSON.stringify(dt)

                app.screens.home.click()

            }
            n.send()

            ">Подключен <span class="apple-symbol"></span></div>

        </div>


    </div>

    <div class="camera_view">

        <div class="close apple-symbol"></div>

    </div>

    <script type="text/javascript" src="elements/scripts/preload.js"></script>
    <script type="text/javascript" src="elements/scripts/dqs.js"></script>
    <script type="text/javascript" src="elements/scripts/check_connection_to_local_wifi.js"></script>

</body>
</html>

preload.js

app.htmlAdd = `

<div class='mini-screen-1'>
            
            <div class="title">Добавить устройство</div>

            <div class="message">Для начала подключитесь к доступной точке доступа Wifi под названием "KKKCam Setup"<br>Далее нажмите на кнопку продолжить и дождитесь ответа камеры</div>

            <div class="button-bottom" onclick="

                let n = new XMLHttpRequest;
                n.timeout = 5e3;
                n.open('GET', 'http://192.168.4.1/scan', true);
                n.onload = function() {

                    mini_screen_redirect(dqs('.screen-popup.app-add-device .mini-screen-1'), dqs('.screen-popup.app-add-device .mini-screen-2'));

                    let db = JSON.parse(n.response).networks

                    let html = ''

                    for (var i = 0; i < db.length; i++) {
                        html += '<div class=\'network\'><div class=\'icon signal-100\'></div><div class=\'name\'>' + db[i].name + '</div>'
                        html += '<div class=\'locked\'></div><div class=\'connect\' onclick=\'connect_to_wifi(' + JSON.stringify(db[i]) +')\'><span class=\'apple-symbol\'></span></div></div>'
                    }
                    dqs('.mini-screen-2 .wifi-networks').innerHTML = html

                }
                n.onerror = function(){

                }
                n.send()
                


            ">Продолжить <span class="apple-symbol"></span></div>
    

        </div>

        <div class="mini-screen-2">
            
            <div class="title">Подключение к сети</div>

            <div class="message">Выберите wifi сеть для подключения к ней</div>

            <div class="wifi-networks">
                
                <div class="network">
                    <div class="icon signal-100"></div>
                    <div class="name">Wifi1</div>
                    <div class="locked"></div>
                    <div class="connect"><span class="apple-symbol"></span></div>
                </div>

                <div class="network">
                    <div class="icon signal-100"></div>
                    <div class="name">Wifi1</div>
                    <div class="locked"></div>
                    <div class="connect"><span class="apple-symbol"></span></div>
                </div>

                <div class="network">
                    <div class="icon signal-100"></div>
                    <div class="name">Wifi1</div>
                    <div class="locked"></div>
                    <div class="connect"><span class="apple-symbol"></span></div>
                </div>

            </div>


        </div>

        <div class="mini-screen-3">
            
            <div class="title">Подключение к {wifi_name}</div>

            <div class="message">Введите пароль от wifi сети</div>

            <input type="password" class="password-in" placeholder="Введите пароль от сети">
            
            <div class="button-bottom" onclick="

            let l = new XMLHttpRequest;
            l.timeout = 5e3;
            l.open('GET', 'http://192.168.4.1/connect?net={wifi_name_full}&pass=' + dqs('.mini-screen-3 .password-in').value, true);
            l.onload = function(){

                console.log(l.response)

                dqs('.mini-screen-4').innerHTML = dqs('.mini-screen-4').innerHTML.replaceAll('{ip}', JSON.parse(l.response).ip)

                mini_screen_redirect(dqs('.screen-popup.app-add-device .mini-screen-3'), dqs('.screen-popup.app-add-device .mini-screen-4'));

            }
            l.send()

            ">Подключить <span class="apple-symbol"></span></div>

        </div>

        <div class="mini-screen-4">
            
            <div class="title">Почти готово!</div>

            <div class="message">Данные на камеру отправлены!<br>Теперь подключитесь к сети к которой подключили камеру и мы закончим настройку устройства!</div>
            <div class="button-bottom" onclick="

            let n = new XMLHttpRequest;
            n.timeout = 5e3;
            n.open('GET', 'http://{ip}/temp', true)
            n.onload = function(){
                
                let camera = {}
                camera.ip = '{ip}'
                camera.wifi = '{wifi_name_full}'
                let dt = JSON.parse(app.fs.cams)
                dt.push(camera)
                app.fs.cams = JSON.stringify(dt)

                app.screens.home.click()

            }
            n.send()

            ">Подключен <span class="apple-symbol"></span></div>

        </div>`



window.addEventListener("DOMContentLoaded", function(){

    if (document.fonts) {

        document.fonts.load("bold 16px 'mnt'").then(function(){

            // Первый шрифт загружен

            document.fonts.load("bold 16px 'aapl'").then(function(){

                // Второй шрифт загружен

                app_start();

            })

        })

    }

})
function getPWADisplayMode() {
  const isStandalone = window.matchMedia('(display-mode: standalone)').matches;
  if (document.referrer.startsWith('android-app://')) {
    return 'twa';
  } else if (navigator.standalone || isStandalone) {
    return 'standalone';
  }
  return 'browser';
}

//function getPWADisplayMode() {return "standalone"}

function app_start() {

    app.screens = {}
    app.screens.appPreloader = dqs(".screen.app-preloader");
    app.screens.home = dqs(".screen.app-home")
    app.screens.add_device = dqs(".screen-popup.app-add-device")




    // Запуск приложения

    document.body.style.setProperty("--root-display-mode", getPWADisplayMode()) 

    if (getPWADisplayMode() == "standalone") {

        for (let i = 0; i < document.querySelectorAll("*[app-type='standalone']").length; i++) {
            document.querySelectorAll("*[app-type='standalone']")[i].style.display = "block"
        }

        for (let i = 0; i < document.querySelectorAll("*[app-type='browser']").length; i++) {
            document.querySelectorAll("*[app-type='browser']")[i].style.display = "none"
        }       

    } else {

        for (let i = 0; i < document.querySelectorAll("*[app-type='standalone']").length; i++) {
            document.querySelectorAll("*[app-type='standalone']")[i].style.display = "none"
        }

        for (let i = 0; i < document.querySelectorAll("*[app-type='browser']").length; i++) {
            document.querySelectorAll("*[app-type='browser']")[i].style.display = "block"
        }

    }

    refresh_home()

    app.screens.appPreloader.querySelector(".title").style.animationName = "hello_animation"
    app.screens.appPreloader.querySelector(".title").style.animationDuration = "0.6s"
    app.screens.appPreloader.querySelector(".title").style.animationTimingFunction = "ease-in"
    app.screens.appPreloader.querySelector(".loader").style.animationName = "fade_out"
    app.screens.appPreloader.querySelector(".loader").style.animationDuration = "0.1s"
    app.screens.appPreloader.querySelector(".loader").style.opacity = "0"
    app.screens.appPreloader.querySelector(".loader").style.animationIterationCount = "1"
    app.screens.appPreloader.querySelector(".title").style.transform = "scale(150) translateY(7px) translateX(2px)"
    
    setTimeout(function(){
        app.screens.home.style.display = "block"
        app.screens.home.style.animationName = "scale"
        app.screens.home.style.animationDuration = "0.4s"
        app.screens.home.style.animationTimingFunction = "linear"
        setTimeout(function(){
            app.screens.appPreloader.style.display = "none"
        }, 350)
    }, 300)
    


}


async function screen_animation(screen_to_open, screen_to_close) {

    screen_to_close.style.display = "block"
    screen_to_close.style.zIndex = "1"
    screen_to_open.style.transform = "translateX(100vw)"
    screen_to_open.style.display = "block"
    screen_to_open.style.zIndex = "2"
    screen_to_open.style.animationName = "kk_anim_openScreen"
    screen_to_open.style.animationDuration = "0.6s"
    screen_to_open.style.animationTimingFunction = "ease-in-out"
    screen_to_close.style.animationName = "kk_anim_blacked"
    screen_to_close.style.animationDuration = "0.6s"
    screen_to_close.style.animationTimingFunction = "ease-in-out"
    setTimeout(await function(){

        screen_to_close.style.display = "none"
        screen_to_open.style.transform = "translateX(0px)"

        screen_to_close.animationName = ""

    }, 598)

}


async function screen_animation_up(screen_to_open, screen_to_close) {

    screen_to_close.style.display = "block"
    screen_to_close.style.zIndex = "1"
    screen_to_open.style.transform = "translateY(100vh)"
    screen_to_open.style.display = "block"
    screen_to_open.style.zIndex = "2"
    screen_to_open.style.animationName = "kk_anim_openScreenUP"
    screen_to_open.style.animationDuration = "0.4s"
    screen_to_open.style.animationTimingFunction = "ease-in-out"
    screen_to_close.style.animationName = "kk_anim_blacked"
    screen_to_close.style.animationDuration = "0.4s"
    screen_to_close.style.animationTimingFunction = "ease-in-out"
    setTimeout(await function(){

        screen_to_close.style.display = "block"
        screen_to_open.style.transform = "translateY(0px)"

        screen_to_close.style.filter ="brightness(0.2)"
        screen_to_close.animationName = ""

    }, 398)

}

async function screen_animation_up_close(screen_to_open, screen_to_close) {

    screen_to_close.style.display = "block"
    screen_to_close.style.zIndex = "2"
    screen_to_close.style.transform = "translateY(0px)"
    screen_to_open.style.display = "block"
    screen_to_open.style.zIndex = "1"
    screen_to_close.style.animationName = "kk_anim_closeScreenUP"
    screen_to_close.style.animationDuration = "0.4s"
    screen_to_close.style.animationTimingFunction = "ease-in-out"
    screen_to_open.style.animationName = "kk_anim_unblacked"
    screen_to_open.style.animationDuration = "0.4s"
    screen_to_open.style.animationTimingFunction = "ease-in-out"
    setTimeout(await function(){

        screen_to_close.style.display = "none"
        screen_to_open.style.transform = "translateY(0px)"

        screen_to_close.animationName = ""

        screen_to_open.style.filter = "brightness(1)"

    }, 398)

}

function mini_screen_redirect(screen_to_close, screen_to_open) {

    screen_to_close.style.display = "none"
    screen_to_open.style.display = "block"

}


function connect_to_wifi(data) {
    console.log(data)
    if (data.name.length >= 12) {
        name = data.name[0] + data.name[1] + data.name[2] + data.name[3] + data.name[4] + data.name[5] + data.name[6] + "..."
    } else {
        name = data.name
    }
    mini_screen_redirect(dqs('.screen-popup.app-add-device .mini-screen-2'), dqs('.screen-popup.app-add-device .mini-screen-3'));
    dqs(".screen-popup").innerHTML = dqs(".screen-popup").innerHTML.replaceAll("{wifi_name}", name)
    dqs(".screen-popup").innerHTML = dqs(".screen-popup").innerHTML.replaceAll("{wifi_name_full}", data.name)
}



function refresh_home() {
    if (app.fs.cams != "[]") {

        let dt = JSON.parse(app.fs.cams)
        let html = ""
        html += "<div class='add-device apple-symbol'></div>"
        html += "<div class='devices'>"
        for (var i = 0; i < dt.length; i++) {

            html += "<div class='device' onclick='open_device(this)'>"
            html += "<img class='preview' src='http://" + dt[i].ip  +"/stream'>"
            html += "<div class='ip'>" + dt[i].ip +"</div>"
            html += "</div>"
        }
        html += "</div>"
        dqs(".app-home.screen *[app-type='standalone']").innerHTML = html
        dqs(".app-home *[app-type='standalone'] .add-device").addEventListener("click", function(){

        screen_animation_up(app.screens.add_device, app.screens.home)

        setTimeout(function(){
            app.screens.home.onclick= function(){
                screen_animation_up_close(app.screens.home, app.screens.add_device)
                setTimeout(function(){
                    dqs(".screen-popup.app-add-device .mini-screen-1").style.display = "block"
                    dqs(".screen-popup.app-add-device .mini-screen-2").style.display = "none"
                    dqs(".screen-popup.app-add-device .mini-screen-3").style.display = "none"
                }, 398)
                app.screens.home.onclick = null
                app.screens.add_device.innerHTML = app.htmlAdd

            }
        }, 398)

    })

    } else {
        dqs('.app-home *[app-type=\'standalone\'] .not-devices').style.display = "block"
        dqs(".app-home *[app-type='standalone'] .not-devices .nd-add.apple-symbol.sf-button").addEventListener("click", function(){

        screen_animation_up(app.screens.add_device, app.screens.home)

        setTimeout(function(){
            app.screens.home.onclick= function(){
                screen_animation_up_close(app.screens.home, app.screens.add_device)
                setTimeout(function(){
                    dqs(".screen-popup.app-add-device .mini-screen-1").style.display = "block"
                    dqs(".screen-popup.app-add-device .mini-screen-2").style.display = "none"
                    dqs(".screen-popup.app-add-device .mini-screen-3").style.display = "none"
                }, 398)
                app.screens.home.onclick = null
                app.screens.add_device.innerHTML = app.htmlAdd

            }
        }, 398)

    })
    }
}

function open_device(el){

    let img = el.querySelector("img.preview")
    let x = img.x
    let y = img.y
    let height = img.height
    let width = img.width
    let style = `
@keyframes anim_to_image {
    0% {

        position: fixed;
        top: ` + y +`px;
        left: ` + x+`px;
        width: ` + width +`px;
        height: ` + height +`px;

    }
    100% {
        position: fixed;
        width: 100vw;
        height: calc(100vw / 4 * 3);
        top: calc(50% - ((100vw / 4 * 3) / 2));
        left: 0px;
    }

    `

    let styleEL = document.createElement("style")
    styleEL.innerHTML = style
    document.head.appendChild(styleEL)
    styleEL.id = "tempStyle";
    img.style.left = "0px";
    img.style.position = "fixed";
    img.style.top = "calc(50% - ((100vw / 4 * 3) / 2))"
    img.style.height = "calc(100vw / 4 * 3)"
    img.style.width = "100vw"
    img.style.animationName = "anim_to_image"
    img.style.animationDuration = "0.5s"
    img.style.animationTimingFunction = "ease-in-out"
    img.style.zIndex = "999"
    dqs(".camera_view").style.display = "block"
    dqs(".camera_view").style.animationName = "home_fade"
    dqs(".camera_view").style.animationDuration = "0.5s"
    dqs(".camera_view").style.animationTimingFunction = "ease-in-out"

    el.setAttribute("onclick", "")

    setTimeout(function(){
        document.head.removeChild(dqs("#tempStyle"))
        dqs(".camera_view .close").onclick = function(){
            let style = `
                @keyframes anim_to_image {
                    100% {

                        position: fixed;
                        top: ` + y +`px;
                        left: ` + x+`px;
                        width: ` + width +`px;
                        height: ` + height +`px;

                    }
                    0% {
                        position: fixed;
                        width: 100vw;
                        height: calc(100vw / 4 * 3);
                        top: calc(50% - ((100vw / 4 * 3) / 2));
                        left: 0px;
                    }

            `
            let styleEL = document.createElement("style")
            styleEL.innerHTML = style
            document.head.appendChild(styleEL)
            styleEL.id = "tempStyle";

            img.style.left = null;
            img.style.position = null;
            img.style.top = null
            img.style.height = "calc((50vw - 20px - 5px) / 4*3)"
            img.style.width = "calc(100%)"
            img.style.animationName = "anim_to_image"
            img.style.animationDuration = "0.5s"
            img.style.animationTimingFunction = "ease-in-out"
            img.style.zIndex = "999"
            dqs(".camera_view").style.opacity = "0"
            dqs(".camera_view").style.animationName = "fade_out"
            dqs(".camera_view").style.animationDuration = "0.5s"
            dqs(".camera_view").style.animationTimingFunction = "ease-in-out"
            el.setAttribute("onclick", "open_device(this)")

            setTimeout(function(){
                dqs(".camera_view").style.display = "none"
                dqs(".camera_view").style.opacity = "1"
                document.head.removeChild(dqs("#tempStyle"))
            }, 500)
    

        }
    }, 500)

}

dqs.js

function dqs(e) {return document.querySelector(e)}
0 Answers
Related