1<html data-bs-theme="dark"> 2 3<head> 4 <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" 5 integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous"> 6</head> 7 8<body> 9 <nav class="navbar navbar-dark bg-primary"> 10 <div class="container"> 11 <span class="navbar-brand mb-0 h1">Bumble Handsfree</span> 12 </div> 13 </nav> 14 <br> 15 16 <div class="container"> 17 18 <label class="form-label">Server Port</label> 19 <div class="input-group mb-3"> 20 <input type="text" class="form-control" aria-label="Port Number" value="8989" id="port"> 21 <button class="btn btn-primary" type="button" onclick="connect()">Connect</button> 22 </div> 23 24 <label class="form-label">Dial Phone Number</label> 25 <div class="input-group mb-3"> 26 <input type="text" class="form-control" placeholder="Phone Number" aria-label="Phone Number" 27 id="dial_number"> 28 <button class="btn btn-primary" type="button" 29 onclick="send_at_command(`ATD${dialNumberInput.value}`)">Dial</button> 30 </div> 31 32 <label class="form-label">Send AT Command</label> 33 <div class="input-group mb-3"> 34 <input type="text" class="form-control" placeholder="AT Command" aria-label="AT command" id="at_command"> 35 <button class="btn btn-primary" type="button" 36 onclick="send_at_command(document.getElementById('at_command').value)">Send</button> 37 </div> 38 39 <div class="row"> 40 <div class="col-auto"> 41 <label class="form-label">Battery Level</label> 42 <div class="input-group mb-3"> 43 <input type="text" class="form-control" placeholder="0 - 100" aria-label="Battery Level" 44 id="battery_level"> 45 <button class="btn btn-primary" type="button" 46 onclick="send_at_command(`AT+BIEV=2,${document.getElementById('battery_level').value}`)">Set</button> 47 </div> 48 </div> 49 <div class="col-auto"> 50 <label class="form-label">Speaker Volume</label> 51 <div class="input-group mb-3 col-auto"> 52 <input type="text" class="form-control" placeholder="0 - 15" aria-label="Speaker Volume" 53 id="speaker_volume"> 54 <button class="btn btn-primary" type="button" 55 onclick="send_at_command(`AT+VGS=${document.getElementById('speaker_volume').value}`)">Set</button> 56 </div> 57 </div> 58 <div class="col-auto"> 59 <label class="form-label">Mic Volume</label> 60 <div class="input-group mb-3 col-auto"> 61 <input type="text" class="form-control" placeholder="0 - 15" aria-label="Mic Volume" 62 id="mic_volume"> 63 <button class="btn btn-primary" type="button" 64 onclick="send_at_command(`AT+VGM=${document.getElementById('mic_volume').value}`)">Set</button> 65 </div> 66 </div> 67 </div> 68 69 <button class="btn btn-primary" onclick="send_at_command('ATA')">Answer</button> 70 <button class="btn btn-primary" onclick="send_at_command('AT+CHUP')">Hang Up</button> 71 <button class="btn btn-primary" onclick="send_at_command('AT+BLDN')">Redial</button> 72 <button class="btn btn-primary" onclick="send({ type: 'query_call'})">Get Call Status</button> 73 74 <br><br> 75 76 <button class="btn btn-primary" onclick="send_at_command('AT+BVRA=1')">Start Voice Assistant</button> 77 <button class="btn btn-primary" onclick="send_at_command('AT+BVRA=0')">Stop Voice Assistant</button> 78 79 <hr> 80 81 <div id="socketStateContainer" class="bg-body-tertiary p-3 rounded-2"> 82 <h3>Log</h3> 83 <code id="log" style="white-space: pre-line;"></code> 84 </div> 85 </div> 86 87 88 <script> 89 let portInput = document.getElementById("port") 90 let atCommandInput = document.getElementById("at_command") 91 let log = document.getElementById("log") 92 let socket 93 94 function connect() { 95 socket = new WebSocket(`ws://localhost:${portInput.value}`); 96 socket.onopen = _ => { 97 log.textContent += 'OPEN\n' 98 } 99 socket.onclose = _ => { 100 log.textContent += 'CLOSED\n' 101 } 102 socket.onerror = (error) => { 103 log.textContent += 'ERROR\n' 104 console.log(`ERROR: ${error}`) 105 } 106 socket.onmessage = (event) => { 107 log.textContent += `<-- ${event.data}\n` 108 let volume_state = JSON.parse(event.data) 109 volumeSetting.value = volume_state.volume_setting 110 changeCounter.value = volume_state.change_counter 111 muted.checked = volume_state.muted ? true : false 112 } 113 } 114 115 function send(message) { 116 if (socket && socket.readyState == WebSocket.OPEN) { 117 let jsonMessage = JSON.stringify(message) 118 log.textContent += `--> ${jsonMessage}\n` 119 socket.send(jsonMessage) 120 } else { 121 log.textContent += 'NOT CONNECTED\n' 122 } 123 } 124 125 function send_at_command(command) { 126 send({ type: 'at_command', 'command': command }) 127 } 128 </script> 129 </div> 130</body> 131 132</html>