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)}