Commit 7667ff6f authored by Martin Cífka's avatar Martin Cífka
Browse files

Added GUI, fixed some bugs

parent 3d3f746e
Loading
Loading
Loading
Loading
Loading
+136 −18
Original line number Diff line number Diff line
@@ -10,13 +10,15 @@
    
    
    <body>
        <div class="box center">
        <div class="box">
            <h1>Mi Camera Photo</h1>
            <a href="http://192.168.42.1:50422" target="_blank">Photos</a>
            <a href="rtsp://192.168.42.1/live" target="_blank">Live Stream</a><br><br>
            
            <span class="flex">
                <input type="button" id="buttonConnect"  onclick="buttonConnectClick()" value="Connect">
                <input type="button" id="buttonTurnOffApp" onclick="turnOffAppClick()" value="Turn off app" disabled="">
                <button type="button" id="buttonPowerOff" onclick="powerOffClick()" value="Power off" disabled="">
                <input type="button" id="buttonTurnOffApp" onclick="turnOffAppClick()" value="Turn off app" disabled>
                <button type="button" id="buttonPowerOff" onclick="powerOffClick()" value="Power off" disabled>
                    <svg version="1.1" class="svgIcon" xmlns="http://www.w3.org/2000/svg" x="0px" y="0px" width="31.182px" height="31.182px" viewBox="0 0 31.182 31.182">
                        <path d="M15.591,16.089c-0.781,0-1.417-0.635-1.417-1.417V3.074c0-0.783,0.636-1.418,1.417-1.418c0.783,0,1.418,0.635,1.418,1.418 v11.598C17.009,15.454,16.374,16.089,15.591,16.089z"/>
                        <path d="M15.591,29.524c-7.101,0-12.877-5.776-12.877-12.877c0-4.249,2.097-8.224,5.606-10.629c0.646-0.442,1.528-0.278,1.97,0.366 c0.443,0.646,0.278,1.528-0.367,1.972c-2.738,1.878-4.374,4.978-4.374,8.291c0,5.537,4.506,10.042,10.042,10.042 c5.537,0,10.042-4.505,10.042-10.042c0-3.314-1.636-6.414-4.375-8.292c-0.646-0.442-0.811-1.325-0.367-1.972 c0.442-0.646,1.323-0.811,1.971-0.366c3.511,2.405,5.606,6.38,5.606,10.63C28.468,23.748,22.691,29.524,15.591,29.524z"/>
@@ -24,23 +26,139 @@
                </button>
            </span>
            
            <!--
            <input type="checkbox" name="checkboxWifiOff" id="checkboxWifiOff" disabled=""> 
            <label for="checkboxWifiOff" id="label-chekboxWifiOff">Turn off Wifi when disconnecting</label>
            -->
            
            <label class="switch">
                <input id="checkboxWifiOff" type="checkbox" disabled><span class="slider"></span>
                <label for="checkboxWifiOff">Turn off Wifi when disconnecting</label>
            </label>
            <form id="wsForm" onsubmit="return false;"> <!-- onchange="wsFormOnChange()" -->
                <table id="wsFormTable1">
                    <tr>
                        <td><label for="speedSelect">Speed:</label></td>
                        <td><select id="speedSelect" name="speed" disabled>
                            <option value="0">Auto</option>
                            <option value="39168">1/6400</option>
                            <option value="35968">1/3200</option>
                            <option value="34768">1/2000</option>
                            <option value="33768">1/1000</option>
                            <option value="33268">1/500</option>
                            <option value="33008">1/240</option>
                            <option value="32888">1/120</option>
                            <option value="32828">1/60</option>
                            <option value="32798">1/30</option>
                            <option value="32783">1/15</option>
                            <option value="32776">1/8</option>
                            <option value="32772">1/4</option>
                            <option value="1">1</option>
                            <option value="2">2</option>
                            <option value="4">4</option>
                            <option value="8">8</option>
                            <option value="16">16</option>
                            <option value="32">32</option>
                        </select></td>

                        <td><label for="isoSelect">ISO:</label></td>
                        <td><select id="isoSelect" name="iso" disabled>
                            <option value="0">Auto</option>
                            <option value="50">50</option>
                            <option value="100">100</option>
                            <option value="200">200</option>
                            <option value="400">400</option>
                            <option value="800">800</option>
                            <option value="1600">1600</option>
                        </select></td>
                    </tr>
                    
                    <tr>
                        <td><label for="wbSelect">Whitebalance:</label></td>
                        <td><select id="wbSelect" name="photoWB" disabled>
                            <option value="0">Auto</option>
                            <option value="1">Outdoor</option>
                            <option value="2">Shadow</option>
                            <option value="3">Cloudy</option>
                            <option value="4">Night</option>
                        </select></td>
                        <td></td>
                        <td></td>
                    </tr>
                    
                    <tr>
                        <td><label for="checkboxBracketing">Bracketing</label></td>
                        <td><label class="switch">
                            <input id="checkboxBracketing" type="checkbox" disabled><span class="slider"></span>
                        </label></td>
                        <td><label for="checkboxTimelapse">Timelapse</label></td>
                        <td><label class="switch">
                            <input id="checkboxTimelapse" type="checkbox" disabled><span class="slider"></span>
                        </label></td>
                    </tr>
                    
                    
                    <tr>
                        <td><label for="bracketingEvSelect">EV:</label></td>
                        <td><select id="bracketingEvSelect" name="bracketingEV" disabled>
                            <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>
                        </select></td>
                        
                        <td><label for="timelapseIntervalSelect">Interval:</label></td>
                        <td><select id="timelapseIntervalSelect" name="timelapseInterval" disabled>
                            <option value="10">10 s</option>
                            <option value="30">30 s</option>
                            <option value="60">1 min</option>
                            <option value="120">2 min</option>
                            <option value="180">3 min</option>
                            <option value="240">4 min</option>
                            <option value="320">5 min</option>
                            <option value="480">8 min</option>
                            <option value="600">10 min</option>
                            <option value="900">15 min</option>
                            <option value="1200">20 min</option>
                            <option value="1500">25 min</option>
                            <option value="1800">30 min</option>
                        </select></td>
                    </tr>
                    
            <form id="wsForm" onsubmit="wsFormSubmit(); return false;">
                <input id="wsForm-data" type="text" placeholder="Data to send" disabled="">
                <input id="wsForm-submit" type="submit" value="Send" disabled="">
                    <tr>
                        <td><label for="bracketingCountSelect">Count:</label></td>
                        <td><select id="bracketingCountSelect" name="bracketingHalf" disabled>
                            <option value="1">3</option>
                            <option value="2">5</option>
                            <option value="3">7</option>
                            <option value="4">9</option>
                        </select></td> 
                        
                        <td><label for="timelapseCountSelect">Count:</label></td>
                        <td><select id="timelapseCountSelect" name="timelapseCount" disabled>
                            <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>
                            <option value="7">7</option>
                            <option value="8">8</option>
                            <option value="9">9</option>
                            <option value="10">10</option>
                            <option value="12">12</option>
                            <option value="14">14</option>
                            <option value="16">16</option>
                            <option value="18">20</option>
                        </select></td>  
                    </tr>
                </table>
                
                <table id="wsFormTable2">
                    <tr>
                        <td><label for="checkboxWifiOff">Turn off Wifi when shooting<br> timelapse above 1 minute</label></td>
                        <td><label class="switch">
                            <input id="checkboxWifiOff" type="checkbox" name="wifiOff" disabled><span class="slider"></span>
                            </label>
                        </td>
                    </tr>
                </table>
                
                <button type="button" id="buttonShoot" onclick="wsFormSubmit();" name="cmd" value="SHOOT" disabled>Shoot!</button>
            </form>
            <a href="http://192.168.42.1:50422">Photos</a>
            <a href="rtsp://192.168.42.1/live">Live Stream</a>
            
        </div>
        <div id="notification-wrapper"><div id="notification" style="display: none;"></div></div>
    </body>
+160 −56
Original line number Diff line number Diff line
const CameraState = {
    DISCONNECTED: 0,
    SHOOTING: 1,
    READY: 2   
}
        
var ws;
var notifying = false;
var connected = false;
var state = CameraState.DISCONNECTED;
var host = "192.168.42.1";



function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}


function waitFor(conditionFunction) {

  const poll = resolve => {
@@ -20,6 +28,7 @@ function waitFor(conditionFunction) {




function wsConnect()
{
    if (!("WebSocket" in window))
@@ -45,23 +54,18 @@ function wsConnect()
            var json = JSON.parse(event.data);
            switch(json["cmd"])
            {
                case "CONNECT":
                case "STATE":
                {
                    document.getElementById("buttonConnect").disabled = false;
                    if (json["param"] === true)
                    {
                        enableForm(true);
                        notify("Connected!",false, 1000)
                    if (json["param"] == CameraState.DISCONNECTED)
                        ws.close(); // onclose will call setFormState
                    else
                        setCameraState(json["param"]);
                    break;
                }
                    else if (json["param"] === false)
                case "NOTIFY":
                {
                        enableForm(false);
                        ws.close();
                        notify("Couldn't connect. Maybe someone else is using the camera?", true, 2000);
                    }
                    else
                    notify(json["param"]);
                    break;
                    return;
                }
                default:
                    break;
@@ -73,60 +77,114 @@ function wsConnect()
            notify(`[message] Non-JSON data received from server: ${event.data}`, true);
        }
    };
    ws.onping = function(event)
    ws.onping = function(event){}
    ws.onclose = function(event)
    {
        notify("ping!");
        if (!event.wasClean && state != CameraState.DISCONNECTED)
        {
            notify('Connection died.');
        }
    ws.onclose = function(event)
        
        setCameraState(CameraState.DISCONNECTED);
    };

    ws.onerror = function(error){};
}

function setCameraState(newState)
{
    document.getElementById("buttonConnect").disabled = false;
    
        if (event.wasClean)
    let disabled = false;
    switch(newState)
    {
            if (event.code === 1000)
            notify(`[close] Connection closed cleanly, code=${event.code} reason=${event.reason}`);
        }
        else
        case CameraState.DISCONNECTED:
        {
            // e.g. server process killed or network down
            // event.code is usually 1006 in this case
            if (!connected)
                notify("Couldn't connect. Maybe anothe user is using the app or you are not connected to the network?", true, 3000);
            else
                notify("Connection died.", true);
            document.getElementById("buttonConnect").value = "Connect";
            document.getElementById("buttonShoot").innerHTML = "Shoot!";
            disabled = true;
            
            switch(state)
            {
                //DISCONNECTED -> DISCONNECTED
                case CameraState.DISCONNECTED:
                    notify("Couldn't connect. Maybe someone else is using the camera?", true, 2000);
                    break;
                    
                //READY/SHOOTING -> DISCONNECTED
                default:
                    notify("Disconnected!", true, 2000);
                    break;
            }
            break;
        }
        
        enableForm(false);
        connected = false;
        case CameraState.SHOOTING:
        {
            document.getElementById("buttonConnect").value = "Disconnect";
            document.getElementById("buttonShoot").innerHTML = "Stop shooting!";
            disabled = true;
            
    };
            switch(state)
            {
                //DISCONNECTED -> SHOOTING
                case CameraState.DISCONNECTED:
                    notify("Connected, camera is shooting!",false, 1000);
                    break;
                    
    ws.onerror = function(error){};
                //REDY/SHOOTING -> SHOOTING
                default:
                    notify("Shooting has started!",false, 1000);
                    break;
            }
            break;
        }
        
function enableForm(enable)
        case CameraState.READY:
        {
    var elements = document.getElementById("wsForm").elements;
        for (var i = 0, len = elements.length; i < len; ++i)
            document.getElementById("buttonConnect").value = "Disconnect";
            document.getElementById("buttonShoot").innerHTML = "Shoot!";
            disabled = false;
            
            switch(state)
            {
            elements[i].disabled = !enable;
                //DISCONNECTED -> READY
                case CameraState.DISCONNECTED:
                    notify("Connected!",false, 1000);
                    break;
                    
                //SHOOTING -> READY
                case CameraState.SHOOTING:
                    notify("Shooting has finished!",false, 1000);
                    break;
            }
            break;
        }
        default:
            return;
    }
    
        document.getElementById("checkboxWifiOff").disabled = !enable;
        document.getElementById("buttonTurnOffApp").disabled = !enable;
        document.getElementById("buttonPowerOff").disabled = !enable;
    // disable/enable whole form
    var elements = document.getElementById("wsForm").elements;
    for (var i = 0, len = elements.length; i < len; ++i)
        elements[i].disabled = disabled;
    
        if (enable)
            document.getElementById("buttonConnect").value = "Disconnect";
        else
            document.getElementById("buttonConnect").value = "Connect";
    // disable/enable additional buttons outside form
    //document.getElementById("checkboxWifiOff").disabled = disabled;
    document.getElementById("buttonTurnOffApp").disabled = disabled;
    document.getElementById("buttonPowerOff").disabled = disabled;

    if (newState == CameraState.SHOOTING)
        document.getElementById("buttonShoot").disabled = false;

    state = newState;
}

function wsDisconnect()
{
    if (document.getElementById("checkboxWifiOff").checked)
    /*if (document.getElementById("checkboxWifiOff").checked)
        ws.send('{"cmd":"WIFI_OFF"}');
    document.getElementById("checkboxWifiOff").disabled = true;
    document.getElementById("checkboxWifiOff").disabled = true;*/
    
    ws.close(1000, "disconnected by user");
    connected = false;
@@ -146,15 +204,21 @@ function buttonConnectClick()

function wsFormSubmit()
{
    var input = document.getElementById('wsForm-data')
    ws.send(input.value);
    input.value = "";
    if (state === CameraState.READY)
    {
        let str = JSON.stringify(wsFormToJson());
        ws.send(str);
    }
    else if (state === CameraState.SHOOTING)
    {
        ws.send('{"cmd":"STOP"}');
    }
}

function turnOffAppClick()
{
    if (document.getElementById("checkboxWifiOff").checked)
        ws.send('{"cmd":"WIFI_OFF"}');
    /*if (document.getElementById("checkboxWifiOff").checked)
        ws.send('{"cmd":"WIFI_OFF"}');*/
    ws.send('{"cmd":"APP_OFF"}');
    wsDisconnect();
}
@@ -168,8 +232,8 @@ function powerOffClick()

async function notify(text, error = false, time = 1500)
{
    if (error)
        console.error(text)
    if (error === true)
        console.error(text);
    else
        console.log(text);
    
@@ -191,3 +255,43 @@ async function notify(text, error = false, time = 1500)
    });
}


function wsFormToJson() {
    form = document.getElementById("wsForm")
    var json = {};
    for (var i = 0; i < form.length; i++)
    {
        if (form[i]["type"] === "checkbox")
        {
            json[form[i]['name']] = form[i].checked;
        }
        else
        {
            if (isNaN(form[i]['value']))
                json[form[i]['name']] = form[i]['value'];
            else
                json[form[i]['name']] = parseInt(form[i]['value']);
        }
    }
    
    if (document.getElementById("checkboxBracketing").checked === false)
    {
        json["bracketingEV"] = 0;
        json["bracketingHalf"] = 0;
    }
    
    if (document.getElementById("checkboxTimelapse").checked === false)
    {
        json["timelapseCount"] = 0;
        json["timelapseInterval"] = 0;
        json["wifiOff"] = false;
    }
    else
    {
        if (json["timelapseInterval"] * json["timelapseCount"] < 60)
            json["wifiOff"] = false;
    }
    
    delete json[""]
    return json;
}
+71 −19
Original line number Diff line number Diff line
@@ -3,6 +3,12 @@ body
    color: #fff6cb;
    background-color: #fffae0;
}
body,html
{
    display: grid;
    height: 100%;
}

a
{
  color: #fff6cb;
@@ -16,9 +22,11 @@ a:active
{
  color: #ffecdd;
}
form

label
{
    margin: 5px 0px 12px 0px;
    vertical-align: middle;
    margin-right: 5px;
}
.flex
{
@@ -31,7 +39,7 @@ form
    padding: 15px 30px 35px 30px;
    margin: auto;
    border-radius: 10px;
    min-width: 300px;
    width: 370px;
}

.center
@@ -49,15 +57,7 @@ form
    display: block;
}

#buttonPowerOff
{
    padding: 2px;
}
#buttonPowerOff > svg
{
    width: 26px;
    height: 26px;
}



#notification-wrapper
@@ -107,7 +107,11 @@ input[type="submit"]
    border-radius: 3px;
}


input[type="submit"]
{
    display: table;
    margin: 4px auto;
}

button:disabled,
input[type="button"]:disabled,
@@ -123,11 +127,6 @@ input[type="checkbox" i]:disabled+label
  color: #777;
}

#buttonConnect,#wsForm-turnOffApp
{
    width: 105px;
}

input
{
    border-radius: 3px;
@@ -137,6 +136,10 @@ input[type=text]
{
    padding: 7px;
}
select
{
    padding: 6px;
}

input[type="checkbox"] {
    width: 20px;
@@ -144,3 +147,52 @@ input[type="checkbox"] {
    position: relative;
    margin: 7px 5px;
}


#wsForm
{
    margin: 5px 0px 12px 0px;
}

#buttonPowerOff
{
    padding: 2px;
}
#buttonPowerOff > svg
{
    width: 26px;
    height: 26px;
}



/********** TABLE **********/
table {
    margin: 20px 0px;
    border-spacing: 0;
}
td:nth-child(2n) {
    text-align: left;
}


#wsFormTable1 td:nth-child(2n+3) {
    padding-left: 25px;
}

#wsFormTable1 tr:nth-child(2) td
{
    padding-bottom: 10px;
    border-bottom: 1px solid #fff6cb;
}

#wsFormTable1 tr:nth-child(n+3) td:nth-child(2)
{
    border-right: 1px solid #fff6cb;
}


#wsFormTable2 td:first-child
{
    width: 200px;
}1
 No newline at end of file
+93 −23

File changed.

Preview size limit exceeded, changes collapsed.

+6 −0
Original line number Diff line number Diff line
@@ -26,6 +26,8 @@ public:
    void runReceiver();
    void stopReceiver();
    
    bool isShooting();
    
    void enqueueCommand(const std::string& cmd);
    
private:
@@ -62,6 +64,10 @@ private:
    size_t _timelapseInterval;
    size_t _timelapseCount;
    
    
    bool _isShooting;
    std::mutex _isShootingMutex;
    
    bool _stopShooting;
    std::mutex _stopShootingMutex;
    std::condition_variable _stopShootingCV;
Loading