├── .gitignore ├── LICENSE ├── README.md ├── sbin ├── openwall ├── setnetwork ├── telegram └── updatewebui ├── structure.md └── www ├── a ├── bootstrap.bundle.min.js ├── bootstrap.min.css ├── bootstrap.override.css ├── logo.svg ├── main.js ├── preview.svg └── timezone.js ├── cgi-bin ├── ext-backuper.cgi ├── ext-openwall.cgi ├── ext-proxy.cgi ├── ext-telegram.cgi ├── ext-tunnel.cgi ├── fpv-wfb.cgi ├── fw-editor.cgi ├── fw-interface.cgi ├── fw-network.cgi ├── fw-reset.cgi ├── fw-restart.cgi ├── fw-restore.cgi ├── fw-settings.cgi ├── fw-system.cgi ├── fw-time.cgi ├── fw-update.cgi ├── info-kernel.cgi ├── info-majestic.cgi ├── info-overlay.cgi ├── j │ ├── locale.cgi │ ├── locale_fpv.cgi │ ├── pulse.cgi │ ├── run.cgi │ └── time.cgi ├── mj-configuration.cgi ├── mj-endpoints.cgi ├── mj-settings.cgi ├── p │ ├── address.cgi │ ├── common.cgi │ ├── footer.cgi │ ├── fpv_common.cgi │ ├── header.cgi │ ├── header_fpv.cgi │ ├── motor.cgi │ └── roi.cgi ├── preview.cgi ├── status.cgi ├── tool-console.cgi ├── tool-files.cgi └── tool-sdcard.cgi ├── favicon.ico ├── index.html └── m └── img.html /.gitignore: -------------------------------------------------------------------------------- 1 | /files 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 OpenIPC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![OpenIPC logo][1] 2 | 3 | WebUI 4 | ====== 5 | 6 | WebUI is a web interface for [OpenIPC Firmware][2], 7 | and is available on port 80 of your camera. 8 | 9 | Web interface uses system credentials for access. Default username is _root_, 10 | and password is _12345_. You will be asked to change the password at the first login. 11 | Please note that this will also affect your login via ssh! 12 | 13 | ### Support 14 | 15 | OpenIPC offers two levels of support. 16 | 17 | - Free support through the community via [chat][3]. 18 | - Paid commercial support directly from the team of developers. 19 | 20 | Please consider subscribing for paid commercial support if you intend to use our 21 | product for business. As a paid customer, you will get technical support and 22 | maintenance services directly from our skilled team. Your bug reports and 23 | feature requests will get prioritized attention and expedited solutions. It's a 24 | win-win strategy for both parties, that would contribute to the stability your 25 | business, and help core developers to work on the project full-time. 26 | 27 | If you have any specific questions concerning our project, feel free to 28 | [contact us](mailto:dev@openipc.org). 29 | 30 | ### Participating and Contribution 31 | 32 | If you like what we do, and willing to intensify the development, please 33 | consider participating. 34 | 35 | You can improve existing code and send us patches. You can add new features 36 | missing from our code. 37 | 38 | Remember that you write for embedded linux thus please keep 39 | your code as small and optimized as possible. Avoid using extra libraries like 40 | jQuery, pure JavaScript is quite enough. Use valid HTML5 code. Avoid using 41 | deprecated tags and attributes. 42 | 43 | You can help us to write a better documentation, proofread and correct our 44 | websites. 45 | 46 | You can just donate some money to cover the cost of development and long-term 47 | maintaining of what we believe is going to be the most stable, flexible, and 48 | open IP Network Camera Framework for users like yourself. 49 | 50 | You can make a financial contribution to the project at [Open Collective][4]. 51 | 52 | Thank you. 53 | 54 |

Open Collective donate button

55 | 56 | [1]: https://openipc.org/assets/openipc-logo-black.svg 57 | [2]: https://github.com/openipc/firmware 58 | [3]: https://openipc.org/#telegram-chat-groups 59 | [4]: https://opencollective.com/openipc/contribute/backer-14335/checkout 60 | -------------------------------------------------------------------------------- /sbin/openwall: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | [ -e "/etc/webui/openwall.conf" ] && source /etc/webui/openwall.conf 3 | 4 | flash_size=$(awk '{sum+=sprintf("0x%s", $2);} END{print sum/1048576;}' /proc/mtd) 5 | fw_variant=$(grep "BUILD_OPTION" /etc/os-release | cut -d= -f2 | tr -d '"') 6 | fw_version=$(grep "OPENIPC_VERSION" /etc/os-release | cut -d= -f2 | tr -d '"') 7 | 8 | network_hostname=$(hostname -s) 9 | network_interface=$(ip route | awk '/default/ {print $5}') 10 | network_macaddr=$(cat "/sys/class/net/${network_interface}/address") 11 | 12 | if [ "$(ipcinfo -v)" = "sigmastar" ]; then 13 | soc=$(fw_printenv -n soc) 14 | else 15 | soc=$(ipcinfo --chip-name) 16 | fi 17 | 18 | sensor=$(fw_printenv -n sensor) 19 | streamer=$(basename $(ipcinfo --streamer)) 20 | temperature=$(ipcinfo --temp) 21 | uptime=$(uptime | sed -r 's/^.+ up ([^,]+), .+$/\1/') 22 | 23 | if [ "$openwall_enabled" != "true" ]; then 24 | echo "Sending to Openwall is not enabled" 25 | exit 1 26 | fi 27 | 28 | if [ "$openwall_use_heif" = "true" ] && [ "$(yaml-cli -g .video0.codec)" = "h265" ]; then 29 | snapshot=/tmp/snapshot.heif 30 | wget -q -T1 localhost/image.heif -O "$snapshot" 31 | else 32 | snapshot=/tmp/snapshot.jpg 33 | wget -q -T1 localhost/image.jpg -O "$snapshot" 34 | fi 35 | 36 | if [ ! -e "$snapshot" ]; then 37 | echo "Snapshot file not found" 38 | exit 1 39 | fi 40 | 41 | if [ -z "$network_macaddr" ]; then 42 | echo "MAC address not found" 43 | exit 1 44 | fi 45 | 46 | command="curl --verbose" 47 | command="${command} --connect-timeout 100" 48 | command="${command} --max-time 100" 49 | 50 | if [ "$openwall_proxy_enabled" = "true" ] && [ -e "/etc/webui/proxy.conf" ]; then 51 | source /etc/webui/proxy.conf 52 | command="${command} --socks5-hostname ${socks5_host}:${socks5_port}" 53 | command="${command} --proxy-user ${socks5_login}:${socks5_password}" 54 | fi 55 | 56 | command="${command} --url https://openipc.org/snapshots" 57 | command="${command} -F 'mac_address=${network_macaddr}'" 58 | command="${command} -F 'firmware=${fw_version}-${fw_variant:-lite}'" 59 | command="${command} -F 'flash_size=${flash_size}'" 60 | command="${command} -F 'hostname=${network_hostname}'" 61 | command="${command} -F 'caption=${openwall_caption}'" 62 | command="${command} -F 'sensor=${sensor}'" 63 | command="${command} -F 'soc=${soc}'" 64 | command="${command} -F 'soc_temperature=${temperature}'" 65 | command="${command} -F 'streamer=${streamer}'" 66 | command="${command} -F 'uptime=${uptime}'" 67 | command="${command} -F 'file=@${snapshot}'" 68 | 69 | echo "$command" 70 | eval "$command" 71 | 72 | exit 0 73 | -------------------------------------------------------------------------------- /sbin/setnetwork: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | TEMPLATE_COMMON="iface %s inet %s\n" 3 | 4 | TEMPLATE_MAC=" hwaddress ether \$(fw_printenv -n ethaddr || echo 00:00:23:34:45:66)\n" 5 | TEMPLATE_STATIC=" address %s\n netmask %s\n" 6 | 7 | TEMPLATE_WIRELESS=" pre-up wpa_passphrase \"\$(fw_printenv -n wlanssid)\" \"\$(fw_printenv -n wlanpass)\" > /tmp/wpa_supplicant.conf 8 | pre-up sed -i 's/#psk.*/scan_ssid=1/g' /tmp/wpa_supplicant.conf 9 | pre-up wpa_supplicant -B -i wlan0 -D nl80211,wext -c /tmp/wpa_supplicant.conf 10 | post-down killall -q wpa_supplicant 11 | " 12 | 13 | show_help() { 14 | echo "Usage: $0 [OPTIONS]" 15 | echo " -i iface Network interface" 16 | echo " -m mode Mode [dhcp, static]" 17 | echo " -h name Hostname" 18 | echo 19 | echo "For wireless interface:" 20 | echo " -s SSID WiFi network SSID" 21 | echo " -p password WiFi passphrase" 22 | echo 23 | echo "For static mode:" 24 | echo " -a address Interface IP address" 25 | echo " -n netmask Network mask" 26 | echo " -g address Gateway IP address" 27 | echo " -d address DNS IP address" 28 | echo 29 | exit 0 30 | } 31 | 32 | while getopts "a:d:g:h:i:m:n:p:s:" flag; do 33 | case "$flag" in 34 | a) 35 | network_address=$OPTARG 36 | ;; 37 | 38 | d) 39 | network_nameserver=$OPTARG 40 | ;; 41 | 42 | g) 43 | network_gateway=$OPTARG 44 | ;; 45 | 46 | h) 47 | network_hostname=$OPTARG 48 | ;; 49 | 50 | i) 51 | network_interface=$OPTARG 52 | ;; 53 | 54 | m) 55 | network_mode=$OPTARG 56 | ;; 57 | 58 | n) 59 | network_netmask=$OPTARG 60 | ;; 61 | 62 | p) 63 | network_password=$OPTARG 64 | ;; 65 | 66 | s) 67 | network_ssid=$OPTARG 68 | ;; 69 | 70 | *) 71 | ;; 72 | esac 73 | done 74 | 75 | if [ $# -eq 0 ]; then 76 | show_help 77 | exit 1 78 | fi 79 | 80 | if [ -z "$network_interface" ]; then 81 | echo "Network interface is not set" 82 | exit 1 83 | fi 84 | 85 | if [ "$network_interface" = "wlan0" ]; then 86 | if [ -z "$network_ssid" ]; then 87 | echo "Wireless network SSID is not set" 88 | exit 1 89 | fi 90 | 91 | if [ -z "$network_password" ]; then 92 | echo "Wireless network passphrase is not set" 93 | exit 1 94 | fi 95 | fi 96 | 97 | if [ -z "$network_mode" ]; then 98 | echo "Network mode is not set" 99 | exit 1 100 | fi 101 | 102 | if [ "$network_mode" = "static" ]; then 103 | if [ -z "$network_address" ]; then 104 | echo "Interface IP address is not set" 105 | exit 1 106 | fi 107 | 108 | if [ -z "$network_netmask" ]; then 109 | echo "Netmask is not set" 110 | exit 1 111 | fi 112 | fi 113 | 114 | iface_file="/etc/network/interfaces.d/${network_interface}" 115 | printf "$TEMPLATE_COMMON" $network_interface $network_mode > "$iface_file" 116 | 117 | if [ "$network_interface" = "eth0" ]; then 118 | printf "$TEMPLATE_MAC" >> "$iface_file" 119 | fi 120 | 121 | if [ "$network_mode" = "static" ]; then 122 | printf "$TEMPLATE_STATIC" "$network_address" "$network_netmask" >> "$iface_file" 123 | 124 | if [ -n "$network_gateway" ]; then 125 | echo " gateway ${network_gateway}" >> "$iface_file" 126 | fi 127 | 128 | if [ -n "$network_nameserver" ]; then 129 | echo " pre-up echo nameserver ${network_nameserver} > /tmp/resolv.conf" >> "$iface_file" 130 | fi 131 | fi 132 | 133 | if [ "$network_interface" = "wlan0" ]; then 134 | fw_setenv wlanssid "$network_ssid" 135 | fw_setenv wlanpass "$network_password" 136 | printf "$TEMPLATE_WIRELESS" $network_ssid $network_password >> "$iface_file" 137 | fi 138 | 139 | if [ -n "$network_hostname" ] && [ "$network_hostname" != "$(hostname)" ]; then 140 | hostname "$network_hostname" 141 | echo "$network_hostname" > /etc/hostname 142 | echo "127.0.0.1 localhost" > /etc/hosts 143 | echo "127.0.1.1 ${network_hostname}" >> /etc/hosts 144 | fi 145 | 146 | exit 0 147 | -------------------------------------------------------------------------------- /sbin/telegram: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | [ -e "/etc/webui/telegram.conf" ] && source /etc/webui/telegram.conf 3 | 4 | if [ "$telegram_enabled" != "true" ]; then 5 | echo "Sending to Telegram is not enabled" 6 | exit 1 7 | fi 8 | 9 | if [ -z "$telegram_token" ]; then 10 | echo "Telegram token not found" 11 | exit 1 12 | fi 13 | 14 | if [ -z "$telegram_channel" ]; then 15 | echo "Telegram channel not found" 16 | exit 1 17 | fi 18 | 19 | if [ -z "$telegram_caption" ]; then 20 | telegram_message="$(hostname -s), $(date +'%F %T')" 21 | else 22 | telegram_message="$(echo "$telegram_caption" | sed "s/%hostname/$(hostname -s)/;s/%datetime/$(date +"%F %T")/;s/%soctemp/$(ipcinfo --temp)/")" 23 | fi 24 | 25 | filename="$(hostname -s | tr ' ' '-')"-"$(date +'%Y%m%d-%H%M%S')" 26 | if [ "$telegram_heif" = "true" ] && [ "$(yaml-cli -g .video0.codec)" = "h265" ]; then 27 | snapshot=/tmp/${filename}.heif 28 | wget -q -T1 localhost/image.heif -O "$snapshot" 29 | else 30 | snapshot=/tmp/${filename}.jpg 31 | wget -q -T1 localhost/image.jpg -O "$snapshot" 32 | fi 33 | 34 | if [ ! -e "$snapshot" ]; then 35 | echo "Snapshot file not found" 36 | exit 1 37 | fi 38 | 39 | command="curl --verbose" 40 | command="${command} --connect-timeout 100" 41 | command="${command} --max-time 100" 42 | 43 | if [ "$openwall_proxy_enabled" = "true" ] && [ -e "/etc/webui/proxy.conf" ]; then 44 | source /etc/webui/proxy.conf 45 | command="${command} --socks5-hostname ${socks5_host}:${socks5_port}" 46 | command="${command} --proxy-user ${socks5_login}:${socks5_password}" 47 | fi 48 | 49 | command="${command} -F 'chat_id=${telegram_channel}'" 50 | if [ -n "$telegram_thread_id" ]; then 51 | command="${command} -F 'message_thread_id=${telegram_thread_id}'" 52 | fi 53 | command="${command} --url https://api.telegram.org/bot${telegram_token}" 54 | 55 | if [ "$telegram_document" = "true" ]; then 56 | command="${command}/sendDocument" 57 | command="${command} -F 'document=@${snapshot}'" 58 | command="${command} -F 'caption=${telegram_message}'" 59 | else 60 | command="${command}/sendPhoto" 61 | command="${command} -F 'photo=@${snapshot}'" 62 | command="${command} -F 'caption=${telegram_message}'" 63 | fi 64 | 65 | echo "$command" 66 | eval "$command" 67 | rm -f "$snapshot" 68 | 69 | exit 0 70 | -------------------------------------------------------------------------------- /sbin/updatewebui: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | url="https://github.com/openipc/majestic-webui/archive/refs/heads/${1:-master}.zip" 3 | 4 | tmp_zip=$(mktemp -u) 5 | curl -s -L $url -o $tmp_zip 6 | 7 | tmp_dir=$(mktemp -d) 8 | unzip -q -o -d $tmp_dir $tmp_zip 9 | 10 | repo=$(ls $tmp_dir) 11 | rm -f $(find /var/www -type f) 12 | 13 | echo "Copy files to web directory" 14 | cp -rf $tmp_dir/$repo/sbin/* /usr/sbin 15 | cp -rf $tmp_dir/$repo/www/* /var/www 16 | 17 | echo "Delete temporary files" 18 | rm -rf $tmp_dir $tmp_zip 19 | -------------------------------------------------------------------------------- /structure.md: -------------------------------------------------------------------------------- 1 | ### Project structure 2 | 3 | ``` 4 | ├── LICENSE 5 | ├── README.md 6 | ├── structure.md # General list of files in the majestic-webui project and their description 7 | ├── sbin 8 | │   ├── openwall 9 | │   ├── setnetwork 10 | │   ├── telegram 11 | │   └── updatewebui 12 | └── www 13 | ├── a 14 | │   ├── bootstrap.bundle.min.js 15 | │   ├── bootstrap.min.css 16 | │   ├── bootstrap.override.css 17 | │   ├── logo.svg 18 | │   ├── main.js 19 | │   ├── preview.svg 20 | │   └── timezone.js 21 | ├── cgi-bin 22 | │   ├── ext-backuper.cgi 23 | │   ├── ext-openwall.cgi 24 | │   ├── ext-proxy.cgi 25 | │   ├── ext-telegram.cgi 26 | │   ├── ext-tunnel.cgi 27 | │   ├── fpv-wfb.cgi # WFB-NG editor (backwards compat with legacy wfb.conf) 28 | │   ├── fw-editor.cgi 29 | │   ├── fw-interface.cgi 30 | │   ├── fw-network.cgi 31 | │   ├── fw-reset.cgi 32 | │   ├── fw-restart.cgi 33 | │   ├── fw-restore.cgi 34 | │   ├── fw-settings.cgi 35 | │   ├── fw-system.cgi 36 | │   ├── fw-time.cgi 37 | │   ├── fw-update.cgi 38 | │   ├── info-kernel.cgi 39 | │   ├── info-majestic.cgi 40 | │   ├── info-overlay.cgi 41 | │   ├── j 42 | │   │   ├── locale.cgi 43 | │   │   ├── locale_fpv.cgi # FPV version of majestic menu 44 | │   │   ├── pulse.cgi 45 | │   │   ├── run.cgi 46 | │   │   └── time.cgi 47 | │   ├── mj-configuration.cgi 48 | │   ├── mj-endpoints.cgi 49 | │   ├── mj-settings.cgi 50 | │   ├── p 51 | │   │   ├── address.cgi 52 | │   │   ├── common.cgi 53 | │   │   ├── footer.cgi 54 | │   │   ├── header.cgi 55 | │   │   ├── header_fpv.cgi # FPV version of general menu 56 | │   │   ├── motor.cgi 57 | │   │   └── roi.cgi 58 | │   ├── preview.cgi 59 | │   ├── status.cgi 60 | │   ├── tool-console.cgi 61 | │   ├── tool-files.cgi 62 | │   └── tool-sdcard.cgi 63 | ├── favicon.ico 64 | ├── index.html 65 | └── m 66 | └── img.html 67 | ``` 68 | -------------------------------------------------------------------------------- /www/a/bootstrap.override.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --bs-font-sans-serif: 'Montserrat', sans-serif; 3 | --bs-font-monospace: 'PT Mono', monospace; 4 | } 5 | 6 | .col > h3 { 7 | color: var(--bs-secondary-color); 8 | font-size: 1.3rem; 9 | margin-bottom: 1.3rem; 10 | } 11 | 12 | .cp2cb { 13 | cursor: pointer; 14 | } 15 | 16 | .dropdown-item { 17 | font-size: 0.9rem; 18 | } 19 | 20 | .ex > h6 { 21 | font-weight: 500; 22 | color: var(--bs-tertiary-color); 23 | } 24 | 25 | .form-control::placeholder { 26 | color: #c2c2d9; 27 | } 28 | 29 | .form-label { 30 | margin-bottom: 0.125rem; 31 | } 32 | 33 | .form-range { 34 | height: 2.5rem; 35 | } 36 | 37 | .hint { 38 | font-size: 0.875rem; 39 | margin-top: 0.2rem; 40 | margin-bottom: 0; 41 | } 42 | 43 | .range span.show-value { 44 | display: block; 45 | min-width: 3.5rem; 46 | text-align: center; 47 | } 48 | 49 | .x-small { 50 | font-size: 0.8125rem; 51 | } 52 | 53 | body > main > .container > h2 { 54 | color: var(--bs-primary); 55 | margin: 2rem 0 1.5rem; 56 | } 57 | 58 | dl.list { 59 | display: flex; 60 | flex-flow: row wrap; 61 | justify-content: space-between; 62 | align-items: baseline; 63 | } 64 | 65 | dl.list dt { 66 | flex-grow: 1; 67 | width: 33%; 68 | } 69 | 70 | dl.list dd { 71 | flex-grow: 2; 72 | width: 66%; 73 | } 74 | 75 | pre { 76 | background: var(--bs-secondary-bg); 77 | font-size: 0.8125rem; 78 | padding: 1rem; 79 | } 80 | 81 | textarea { 82 | font-family: var(--bs-font-monospace); 83 | height: 60vh; 84 | white-space: pre; 85 | } 86 | 87 | #pb-memory, #pb-overlay { 88 | height: 4px; 89 | cursor: pointer; 90 | } 91 | 92 | pre#output[data-cmd] { 93 | background-color: rgb(0, 0, 0); 94 | color: rgba(170, 170, 170, 0.8); 95 | } 96 | 97 | .btn-motor { 98 | font-size: 2.3rem; 99 | --bs-btn-border-width: 0; 100 | --bs-btn-padding-x: 0; 101 | --bs-btn-padding-y: 0; 102 | } 103 | 104 | .navbar-nav { 105 | --bs-nav-link-color: white; 106 | } 107 | 108 | [data-bs-theme=light] { 109 | --bs-primary: rgb(76, 96, 216); 110 | --bs-secondary: rgb(76, 96, 216); 111 | --bs-tertiary-bg-rgb: 76, 96, 216; 112 | } 113 | 114 | [data-bs-theme=dark] { 115 | --bs-primary: rgb(76, 96, 216); 116 | --bs-secondary: rgb(138, 159, 208); 117 | } 118 | 119 | [data-bs-theme=dark] .btn-primary { 120 | --bs-btn-bg: rgba(13, 110, 253, 0.5); 121 | --bs-btn-border-color: rgba(13, 110, 253, 0.5); 122 | } 123 | -------------------------------------------------------------------------------- /www/a/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /www/a/main.js: -------------------------------------------------------------------------------- 1 | function $(n) { 2 | return document.querySelector(n) 3 | } 4 | 5 | function $$(n) { 6 | return document.querySelectorAll(n) 7 | } 8 | 9 | function refresh() { 10 | window.location.reload() 11 | } 12 | 13 | function sleep(ms) { 14 | return new Promise(resolve => setTimeout(resolve, ms)) 15 | } 16 | 17 | function setProgressBar(id, value, name) { 18 | $(id).setAttribute('aria-valuenow', value); 19 | $(id).title = name + ': ' + value + '%' 20 | const pb = $(id + ' .progress-bar'); 21 | pb.style.width = value + '%'; 22 | pb.classList = 'progress-bar'; 23 | if (value > 95) { 24 | pb.classList.add('bg-danger'); 25 | } else if (value > 90) { 26 | pb.classList.add('bg-warning'); 27 | } else { 28 | pb.classList.add('bg-success'); 29 | } 30 | } 31 | 32 | async function* makeTextFileLineIterator(url) { 33 | const td = new TextDecoder('utf-8'); 34 | const response = await fetch(url); 35 | const rd = response.body.getReader(); 36 | let { value: chunk, done: readerDone } = await rd.read(); 37 | chunk = chunk ? td.decode(chunk) : ''; 38 | const re = /\r?\n/gm; 39 | let startIndex = 0; 40 | let result; 41 | 42 | for (;;) { 43 | result = re.exec(chunk); 44 | if (!result) { 45 | if (readerDone) { 46 | break; 47 | } 48 | 49 | let remainder = chunk.substr(startIndex); 50 | ({ value: chunk, done: readerDone } = await rd.read()); 51 | chunk = remainder + (chunk ? td.decode(chunk) : ''); 52 | startIndex = re.lastIndex = 0; 53 | continue; 54 | } 55 | 56 | yield chunk.substring(startIndex, result.index); 57 | startIndex = re.lastIndex; 58 | } 59 | 60 | if (startIndex < chunk.length) { 61 | yield chunk.substr(startIndex); 62 | } 63 | 64 | if (el.dataset['reboot'] === "true") { 65 | location.href = '/cgi-bin/fw-restart.cgi' 66 | } 67 | 68 | if ($('form input[type=submit]')) { 69 | $('form input[type=submit]').disabled = false; 70 | } 71 | } 72 | 73 | async function runCmd(msg) { 74 | for await (let line of makeTextFileLineIterator('/cgi-bin/j/run.cgi?' + msg + '=' + btoa(el.dataset['cmd']))) { 75 | const regex = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g; 76 | line = line.replace(regex, ''); 77 | el.innerHTML += line + '\n'; 78 | } 79 | } 80 | 81 | function heartbeat() { 82 | fetch('/cgi-bin/j/pulse.cgi') 83 | .then((response) => response.json()) 84 | .then((json) => { 85 | if (json.soc_temp !== '') { 86 | const st = $('#soc-temp') 87 | st.textContent = json.soc_temp; 88 | st.classList.add(['text-primary','bg-white','rounded','small']); 89 | st.title = 'SoC temperature ' + json.soc_temp; 90 | } 91 | 92 | if (json.time_now !== '') { 93 | const d = new Date(json.time_now * 1000); 94 | $('#time-now').textContent = d.toLocaleString() + ' ' + json.timezone; 95 | } 96 | 97 | if (json.mem_used !== '') { 98 | setProgressBar('#pb-memory', json.mem_used, 'Memory Usage'); 99 | } 100 | 101 | if (json.overlay_used !== '') { 102 | setProgressBar('#pb-overlay', json.overlay_used, 'Overlay Usage'); 103 | } 104 | 105 | if (json.daynight_value !== '-1') { 106 | $('#daynight_value').textContent = '🌟 ' + json.daynight_value; 107 | } 108 | 109 | if (typeof(json.uptime) !== 'undefined' && json.uptime !== '') { 110 | $('#uptime').textContent = 'Uptime:️ ' + json.uptime; 111 | } 112 | }) 113 | .then(setTimeout(heartbeat, 2000)); 114 | } 115 | 116 | function initAll() { 117 | $$('form').forEach(el => el.autocomplete = 'off'); 118 | 119 | // For .warning and .danger buttons, ask confirmation on action. 120 | $$('.btn-danger, .btn-warning, .confirm').forEach(el => { 121 | // for input, find its parent form and attach listener to it submit event 122 | if (el.nodeName === "INPUT") { 123 | while (el.nodeName !== "FORM") el = el.parentNode 124 | el.addEventListener('submit', ev => (!confirm("Are you sure?")) ? ev.preventDefault() : null) 125 | } else { 126 | el.addEventListener('click', ev => (!confirm("Are you sure?")) ? ev.preventDefault() : null) 127 | } 128 | }); 129 | 130 | $$('.refresh').forEach(el => el.addEventListener('click', refresh)); 131 | 132 | // open links to external resources in a new window. 133 | $$('a[href^=http]').forEach(el => el.target = '_blank'); 134 | 135 | // add auto toggle button and value display for range elements. 136 | $$('input[type=range]').forEach(el => { 137 | el.addEventListener('input', ev => { 138 | const id = ev.target.id.replace(/-range/, ''); 139 | $('#' + id + '-show').textContent = ev.target.value; 140 | $('#' + id).value = ev.target.value; 141 | }) 142 | }); 143 | 144 | // show password when "show" checkbox is checked 145 | $$(".password input[type=checkbox]").forEach(el => { 146 | el.addEventListener('change', ev => { 147 | const pw = $('#' + ev.target.dataset['for']); 148 | pw.type = (el.checked) ? 'text' : 'password'; 149 | pw.focus(); 150 | }); 151 | }); 152 | 153 | heartbeat(); 154 | } 155 | 156 | window.addEventListener('load', initAll); 157 | -------------------------------------------------------------------------------- /www/a/preview.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /www/a/timezone.js: -------------------------------------------------------------------------------- 1 | const TZ = [ 2 | {n:'Africa/Abidjan',v:'GMT0'}, 3 | {n:'Africa/Accra',v:'GMT0'}, 4 | {n:'Africa/Addis Ababa',v:'EAT-3'}, 5 | {n:'Africa/Algiers',v:'CET-1'}, 6 | {n:'Africa/Asmara',v:'EAT-3'}, 7 | {n:'Africa/Bamako',v:'GMT0'}, 8 | {n:'Africa/Bangui',v:'WAT-1'}, 9 | {n:'Africa/Banjul',v:'GMT0'}, 10 | {n:'Africa/Bissau',v:'GMT0'}, 11 | {n:'Africa/Blantyre',v:'CAT-2'}, 12 | {n:'Africa/Brazzaville',v:'WAT-1'}, 13 | {n:'Africa/Bujumbura',v:'CAT-2'}, 14 | {n:'Africa/Cairo',v:'EET-2'}, 15 | {n:'Africa/Casablanca',v:'<+01>-1'}, 16 | {n:'Africa/Ceuta',v:'CET-1CEST,M3.5.0,M10.5.0/3'}, 17 | {n:'Africa/Conakry',v:'GMT0'}, 18 | {n:'Africa/Dakar',v:'GMT0'}, 19 | {n:'Africa/Dar es Salaam',v:'EAT-3'}, 20 | {n:'Africa/Djibouti',v:'EAT-3'}, 21 | {n:'Africa/Douala',v:'WAT-1'}, 22 | {n:'Africa/El Aaiun',v:'<+01>-1'}, 23 | {n:'Africa/Freetown',v:'GMT0'}, 24 | {n:'Africa/Gaborone',v:'CAT-2'}, 25 | {n:'Africa/Harare',v:'CAT-2'}, 26 | {n:'Africa/Johannesburg',v:'SAST-2'}, 27 | {n:'Africa/Juba',v:'CAT-2'}, 28 | {n:'Africa/Kampala',v:'EAT-3'}, 29 | {n:'Africa/Khartoum',v:'CAT-2'}, 30 | {n:'Africa/Kigali',v:'CAT-2'}, 31 | {n:'Africa/Kinshasa',v:'WAT-1'}, 32 | {n:'Africa/Lagos',v:'WAT-1'}, 33 | {n:'Africa/Libreville',v:'WAT-1'}, 34 | {n:'Africa/Lome',v:'GMT0'}, 35 | {n:'Africa/Luanda',v:'WAT-1'}, 36 | {n:'Africa/Lubumbashi',v:'CAT-2'}, 37 | {n:'Africa/Lusaka',v:'CAT-2'}, 38 | {n:'Africa/Malabo',v:'WAT-1'}, 39 | {n:'Africa/Maputo',v:'CAT-2'}, 40 | {n:'Africa/Maseru',v:'SAST-2'}, 41 | {n:'Africa/Mbabane',v:'SAST-2'}, 42 | {n:'Africa/Mogadishu',v:'EAT-3'}, 43 | {n:'Africa/Monrovia',v:'GMT0'}, 44 | {n:'Africa/Nairobi',v:'EAT-3'}, 45 | {n:'Africa/Ndjamena',v:'WAT-1'}, 46 | {n:'Africa/Niamey',v:'WAT-1'}, 47 | {n:'Africa/Nouakchott',v:'GMT0'}, 48 | {n:'Africa/Ouagadougou',v:'GMT0'}, 49 | {n:'Africa/Porto-Novo',v:'WAT-1'}, 50 | {n:'Africa/Sao Tome',v:'GMT0'}, 51 | {n:'Africa/Tripoli',v:'EET-2'}, 52 | {n:'Africa/Tunis',v:'CET-1'}, 53 | {n:'Africa/Windhoek',v:'CAT-2'}, 54 | {n:'America/Adak',v:'HST10HDT,M3.2.0,M11.1.0'}, 55 | {n:'America/Anchorage',v:'AKST9AKDT,M3.2.0,M11.1.0'}, 56 | {n:'America/Anguilla',v:'AST4'}, 57 | {n:'America/Antigua',v:'AST4'}, 58 | {n:'America/Araguaina',v:'<-03>3'}, 59 | {n:'America/Argentina/Buenos Aires',v:'<-03>3'}, 60 | {n:'America/Argentina/Catamarca',v:'<-03>3'}, 61 | {n:'America/Argentina/Cordoba',v:'<-03>3'}, 62 | {n:'America/Argentina/Jujuy',v:'<-03>3'}, 63 | {n:'America/Argentina/La Rioja',v:'<-03>3'}, 64 | {n:'America/Argentina/Mendoza',v:'<-03>3'}, 65 | {n:'America/Argentina/Rio Gallegos',v:'<-03>3'}, 66 | {n:'America/Argentina/Salta',v:'<-03>3'}, 67 | {n:'America/Argentina/San Juan',v:'<-03>3'}, 68 | {n:'America/Argentina/San Luis',v:'<-03>3'}, 69 | {n:'America/Argentina/Tucuman',v:'<-03>3'}, 70 | {n:'America/Argentina/Ushuaia',v:'<-03>3'}, 71 | {n:'America/Aruba',v:'AST4'}, 72 | {n:'America/Asuncion',v:'<-04>4<-03>,M10.1.0/0,M3.4.0/0'}, 73 | {n:'America/Atikokan',v:'EST5'}, 74 | {n:'America/Bahia',v:'<-03>3'}, 75 | {n:'America/Bahia Banderas',v:'CST6CDT,M4.1.0,M10.5.0'}, 76 | {n:'America/Barbados',v:'AST4'}, 77 | {n:'America/Belem',v:'<-03>3'}, 78 | {n:'America/Belize',v:'CST6'}, 79 | {n:'America/Blanc-Sablon',v:'AST4'}, 80 | {n:'America/Boa Vista',v:'<-04>4'}, 81 | {n:'America/Bogota',v:'<-05>5'}, 82 | {n:'America/Boise',v:'MST7MDT,M3.2.0,M11.1.0'}, 83 | {n:'America/Cambridge Bay',v:'MST7MDT,M3.2.0,M11.1.0'}, 84 | {n:'America/Campo Grande',v:'<-04>4'}, 85 | {n:'America/Cancun',v:'EST5'}, 86 | {n:'America/Caracas',v:'<-04>4'}, 87 | {n:'America/Cayenne',v:'<-03>3'}, 88 | {n:'America/Cayman',v:'EST5'}, 89 | {n:'America/Chicago',v:'CST6CDT,M3.2.0,M11.1.0'}, 90 | {n:'America/Chihuahua',v:'MST7MDT,M4.1.0,M10.5.0'}, 91 | {n:'America/Costa Rica',v:'CST6'}, 92 | {n:'America/Creston',v:'MST7'}, 93 | {n:'America/Cuiaba',v:'<-04>4'}, 94 | {n:'America/Curacao',v:'AST4'}, 95 | {n:'America/Danmarkshavn',v:'GMT0'}, 96 | {n:'America/Dawson',v:'MST7'}, 97 | {n:'America/Dawson Creek',v:'MST7'}, 98 | {n:'America/Denver',v:'MST7MDT,M3.2.0,M11.1.0'}, 99 | {n:'America/Detroit',v:'EST5EDT,M3.2.0,M11.1.0'}, 100 | {n:'America/Dominica',v:'AST4'}, 101 | {n:'America/Edmonton',v:'MST7MDT,M3.2.0,M11.1.0'}, 102 | {n:'America/Eirunepe',v:'<-05>5'}, 103 | {n:'America/El Salvador',v:'CST6'}, 104 | {n:'America/Fort Nelson',v:'MST7'}, 105 | {n:'America/Fortaleza',v:'<-03>3'}, 106 | {n:'America/Glace Bay',v:'AST4ADT,M3.2.0,M11.1.0'}, 107 | {n:'America/Goose Bay',v:'AST4ADT,M3.2.0,M11.1.0'}, 108 | {n:'America/Grand Turk',v:'EST5EDT,M3.2.0,M11.1.0'}, 109 | {n:'America/Grenada',v:'AST4'}, 110 | {n:'America/Guadeloupe',v:'AST4'}, 111 | {n:'America/Guatemala',v:'CST6'}, 112 | {n:'America/Guayaquil',v:'<-05>5'}, 113 | {n:'America/Guyana',v:'<-04>4'}, 114 | {n:'America/Halifax',v:'AST4ADT,M3.2.0,M11.1.0'}, 115 | {n:'America/Havana',v:'CST5CDT,M3.2.0/0,M11.1.0/1'}, 116 | {n:'America/Hermosillo',v:'MST7'}, 117 | {n:'America/Indiana/Indianapolis',v:'EST5EDT,M3.2.0,M11.1.0'}, 118 | {n:'America/Indiana/Knox',v:'CST6CDT,M3.2.0,M11.1.0'}, 119 | {n:'America/Indiana/Marengo',v:'EST5EDT,M3.2.0,M11.1.0'}, 120 | {n:'America/Indiana/Petersburg',v:'EST5EDT,M3.2.0,M11.1.0'}, 121 | {n:'America/Indiana/Tell City',v:'CST6CDT,M3.2.0,M11.1.0'}, 122 | {n:'America/Indiana/Vevay',v:'EST5EDT,M3.2.0,M11.1.0'}, 123 | {n:'America/Indiana/Vincennes',v:'EST5EDT,M3.2.0,M11.1.0'}, 124 | {n:'America/Indiana/Winamac',v:'EST5EDT,M3.2.0,M11.1.0'}, 125 | {n:'America/Inuvik',v:'MST7MDT,M3.2.0,M11.1.0'}, 126 | {n:'America/Iqaluit',v:'EST5EDT,M3.2.0,M11.1.0'}, 127 | {n:'America/Jamaica',v:'EST5'}, 128 | {n:'America/Juneau',v:'AKST9AKDT,M3.2.0,M11.1.0'}, 129 | {n:'America/Kentucky/Louisville',v:'EST5EDT,M3.2.0,M11.1.0'}, 130 | {n:'America/Kentucky/Monticello',v:'EST5EDT,M3.2.0,M11.1.0'}, 131 | {n:'America/Kralendijk',v:'AST4'}, 132 | {n:'America/La Paz',v:'<-04>4'}, 133 | {n:'America/Lima',v:'<-05>5'}, 134 | {n:'America/Los Angeles',v:'PST8PDT,M3.2.0,M11.1.0'}, 135 | {n:'America/Lower Princes',v:'AST4'}, 136 | {n:'America/Maceio',v:'<-03>3'}, 137 | {n:'America/Managua',v:'CST6'}, 138 | {n:'America/Manaus',v:'<-04>4'}, 139 | {n:'America/Marigot',v:'AST4'}, 140 | {n:'America/Martinique',v:'AST4'}, 141 | {n:'America/Matamoros',v:'CST6CDT,M3.2.0,M11.1.0'}, 142 | {n:'America/Mazatlan',v:'MST7MDT,M4.1.0,M10.5.0'}, 143 | {n:'America/Menominee',v:'CST6CDT,M3.2.0,M11.1.0'}, 144 | {n:'America/Merida',v:'CST6CDT,M4.1.0,M10.5.0'}, 145 | {n:'America/Metlakatla',v:'AKST9AKDT,M3.2.0,M11.1.0'}, 146 | {n:'America/Mexico City',v:'CST6CDT,M4.1.0,M10.5.0'}, 147 | {n:'America/Miquelon',v:'<-03>3<-02>,M3.2.0,M11.1.0'}, 148 | {n:'America/Moncton',v:'AST4ADT,M3.2.0,M11.1.0'}, 149 | {n:'America/Monterrey',v:'CST6CDT,M4.1.0,M10.5.0'}, 150 | {n:'America/Montevideo',v:'<-03>3'}, 151 | {n:'America/Montserrat',v:'AST4'}, 152 | {n:'America/Nassau',v:'EST5EDT,M3.2.0,M11.1.0'}, 153 | {n:'America/New York',v:'EST5EDT,M3.2.0,M11.1.0'}, 154 | {n:'America/Nipigon',v:'EST5EDT,M3.2.0,M11.1.0'}, 155 | {n:'America/Nome',v:'AKST9AKDT,M3.2.0,M11.1.0'}, 156 | {n:'America/Noronha',v:'<-02>2'}, 157 | {n:'America/North Dakota/Beulah',v:'CST6CDT,M3.2.0,M11.1.0'}, 158 | {n:'America/North Dakota/Center',v:'CST6CDT,M3.2.0,M11.1.0'}, 159 | {n:'America/North Dakota/New Salem',v:'CST6CDT,M3.2.0,M11.1.0'}, 160 | {n:'America/Nuuk',v:'<-03>3<-02>,M3.5.0/-2,M10.5.0/-1'}, 161 | {n:'America/Ojinaga',v:'MST7MDT,M3.2.0,M11.1.0'}, 162 | {n:'America/Panama',v:'EST5'}, 163 | {n:'America/Pangnirtung',v:'EST5EDT,M3.2.0,M11.1.0'}, 164 | {n:'America/Paramaribo',v:'<-03>3'}, 165 | {n:'America/Phoenix',v:'MST7'}, 166 | {n:'America/Port of Spain',v:'AST4'}, 167 | {n:'America/Port-au-Prince',v:'EST5EDT,M3.2.0,M11.1.0'}, 168 | {n:'America/Porto Velho',v:'<-04>4'}, 169 | {n:'America/Puerto Rico',v:'AST4'}, 170 | {n:'America/Punta Arenas',v:'<-03>3'}, 171 | {n:'America/Rainy River',v:'CST6CDT,M3.2.0,M11.1.0'}, 172 | {n:'America/Rankin Inlet',v:'CST6CDT,M3.2.0,M11.1.0'}, 173 | {n:'America/Recife',v:'<-03>3'}, 174 | {n:'America/Regina',v:'CST6'}, 175 | {n:'America/Resolute',v:'CST6CDT,M3.2.0,M11.1.0'}, 176 | {n:'America/Rio Branco',v:'<-05>5'}, 177 | {n:'America/Santarem',v:'<-03>3'}, 178 | {n:'America/Santiago',v:'<-04>4<-03>,M9.1.6/24,M4.1.6/24'}, 179 | {n:'America/Santo Domingo',v:'AST4'}, 180 | {n:'America/Sao Paulo',v:'<-03>3'}, 181 | {n:'America/Scoresbysund',v:'<-01>1<+00>,M3.5.0/0,M10.5.0/1'}, 182 | {n:'America/Sitka',v:'AKST9AKDT,M3.2.0,M11.1.0'}, 183 | {n:'America/St Barthelemy',v:'AST4'}, 184 | {n:'America/St Johns',v:'NST3:30NDT,M3.2.0,M11.1.0'}, 185 | {n:'America/St Kitts',v:'AST4'}, 186 | {n:'America/St Lucia',v:'AST4'}, 187 | {n:'America/St Thomas',v:'AST4'}, 188 | {n:'America/St Vincent',v:'AST4'}, 189 | {n:'America/Swift Current',v:'CST6'}, 190 | {n:'America/Tegucigalpa',v:'CST6'}, 191 | {n:'America/Thule',v:'AST4ADT,M3.2.0,M11.1.0'}, 192 | {n:'America/Thunder Bay',v:'EST5EDT,M3.2.0,M11.1.0'}, 193 | {n:'America/Tijuana',v:'PST8PDT,M3.2.0,M11.1.0'}, 194 | {n:'America/Toronto',v:'EST5EDT,M3.2.0,M11.1.0'}, 195 | {n:'America/Tortola',v:'AST4'}, 196 | {n:'America/Vancouver',v:'PST8PDT,M3.2.0,M11.1.0'}, 197 | {n:'America/Whitehorse',v:'MST7'}, 198 | {n:'America/Winnipeg',v:'CST6CDT,M3.2.0,M11.1.0'}, 199 | {n:'America/Yakutat',v:'AKST9AKDT,M3.2.0,M11.1.0'}, 200 | {n:'America/Yellowknife',v:'MST7MDT,M3.2.0,M11.1.0'}, 201 | {n:'Antarctica/Casey',v:'<+11>-11'}, 202 | {n:'Antarctica/Davis',v:'<+07>-7'}, 203 | {n:'Antarctica/DumontDUrville',v:'<+10>-10'}, 204 | {n:'Antarctica/Macquarie',v:'AEST-10AEDT,M10.1.0,M4.1.0/3'}, 205 | {n:'Antarctica/Mawson',v:'<+05>-5'}, 206 | {n:'Antarctica/McMurdo',v:'NZST-12NZDT,M9.5.0,M4.1.0/3'}, 207 | {n:'Antarctica/Palmer',v:'<-03>3'}, 208 | {n:'Antarctica/Rothera',v:'<-03>3'}, 209 | {n:'Antarctica/Syowa',v:'<+03>-3'}, 210 | {n:'Antarctica/Troll',v:'<+00>0<+02>-2,M3.5.0/1,M10.5.0/3'}, 211 | {n:'Antarctica/Vostok',v:'<+06>-6'}, 212 | {n:'Arctic/Longyearbyen',v:'CET-1CEST,M3.5.0,M10.5.0/3'}, 213 | {n:'Asia/Aden',v:'<+03>-3'}, 214 | {n:'Asia/Almaty',v:'<+06>-6'}, 215 | {n:'Asia/Amman',v:'EET-2EEST,M2.5.4/24,M10.5.5/1'}, 216 | {n:'Asia/Anadyr',v:'<+12>-12'}, 217 | {n:'Asia/Aqtau',v:'<+05>-5'}, 218 | {n:'Asia/Aqtobe',v:'<+05>-5'}, 219 | {n:'Asia/Ashgabat',v:'<+05>-5'}, 220 | {n:'Asia/Atyrau',v:'<+05>-5'}, 221 | {n:'Asia/Baghdad',v:'<+03>-3'}, 222 | {n:'Asia/Bahrain',v:'<+03>-3'}, 223 | {n:'Asia/Baku',v:'<+04>-4'}, 224 | {n:'Asia/Bangkok',v:'<+07>-7'}, 225 | {n:'Asia/Barnaul',v:'<+07>-7'}, 226 | {n:'Asia/Beirut',v:'EET-2EEST,M3.5.0/0,M10.5.0/0'}, 227 | {n:'Asia/Bishkek',v:'<+06>-6'}, 228 | {n:'Asia/Brunei',v:'<+08>-8'}, 229 | {n:'Asia/Chita',v:'<+09>-9'}, 230 | {n:'Asia/Choibalsan',v:'<+08>-8'}, 231 | {n:'Asia/Colombo',v:'<+0530>-5:30'}, 232 | {n:'Asia/Damascus',v:'EET-2EEST,M3.5.5/0,M10.5.5/0'}, 233 | {n:'Asia/Dhaka',v:'<+06>-6'}, 234 | {n:'Asia/Dili',v:'<+09>-9'}, 235 | {n:'Asia/Dubai',v:'<+04>-4'}, 236 | {n:'Asia/Dushanbe',v:'<+05>-5'}, 237 | {n:'Asia/Famagusta',v:'EET-2EEST,M3.5.0/3,M10.5.0/4'}, 238 | {n:'Asia/Gaza',v:'EET-2EEST,M3.4.4/48,M10.5.5/1'}, 239 | {n:'Asia/Hebron',v:'EET-2EEST,M3.4.4/48,M10.5.5/1'}, 240 | {n:'Asia/Ho Chi Minh',v:'<+07>-7'}, 241 | {n:'Asia/Hong Kong',v:'HKT-8'}, 242 | {n:'Asia/Hovd',v:'<+07>-7'}, 243 | {n:'Asia/Irkutsk',v:'<+08>-8'}, 244 | {n:'Asia/Jakarta',v:'WIB-7'}, 245 | {n:'Asia/Jayapura',v:'WIT-9'}, 246 | {n:'Asia/Jerusalem',v:'IST-2IDT,M3.4.4/26,M10.5.0'}, 247 | {n:'Asia/Kabul',v:'<+0430>-4:30'}, 248 | {n:'Asia/Kamchatka',v:'<+12>-12'}, 249 | {n:'Asia/Karachi',v:'PKT-5'}, 250 | {n:'Asia/Kathmandu',v:'<+0545>-5:45'}, 251 | {n:'Asia/Khandyga',v:'<+09>-9'}, 252 | {n:'Asia/Kolkata',v:'IST-5:30'}, 253 | {n:'Asia/Krasnoyarsk',v:'<+07>-7'}, 254 | {n:'Asia/Kuala Lumpur',v:'<+08>-8'}, 255 | {n:'Asia/Kuching',v:'<+08>-8'}, 256 | {n:'Asia/Kuwait',v:'<+03>-3'}, 257 | {n:'Asia/Macau',v:'CST-8'}, 258 | {n:'Asia/Magadan',v:'<+11>-11'}, 259 | {n:'Asia/Makassar',v:'WITA-8'}, 260 | {n:'Asia/Manila',v:'PST-8'}, 261 | {n:'Asia/Muscat',v:'<+04>-4'}, 262 | {n:'Asia/Nicosia',v:'EET-2EEST,M3.5.0/3,M10.5.0/4'}, 263 | {n:'Asia/Novokuznetsk',v:'<+07>-7'}, 264 | {n:'Asia/Novosibirsk',v:'<+07>-7'}, 265 | {n:'Asia/Omsk',v:'<+06>-6'}, 266 | {n:'Asia/Oral',v:'<+05>-5'}, 267 | {n:'Asia/Phnom Penh',v:'<+07>-7'}, 268 | {n:'Asia/Pontianak',v:'WIB-7'}, 269 | {n:'Asia/Pyongyang',v:'KST-9'}, 270 | {n:'Asia/Qatar',v:'<+03>-3'}, 271 | {n:'Asia/Qostanay',v:'<+06>-6'}, 272 | {n:'Asia/Qyzylorda',v:'<+05>-5'}, 273 | {n:'Asia/Riyadh',v:'<+03>-3'}, 274 | {n:'Asia/Sakhalin',v:'<+11>-11'}, 275 | {n:'Asia/Samarkand',v:'<+05>-5'}, 276 | {n:'Asia/Seoul',v:'KST-9'}, 277 | {n:'Asia/Shanghai',v:'CST-8'}, 278 | {n:'Asia/Singapore',v:'<+08>-8'}, 279 | {n:'Asia/Srednekolymsk',v:'<+11>-11'}, 280 | {n:'Asia/Taipei',v:'CST-8'}, 281 | {n:'Asia/Tashkent',v:'<+05>-5'}, 282 | {n:'Asia/Tbilisi',v:'<+04>-4'}, 283 | {n:'Asia/Tehran',v:'<+0330>-3:30<+0430>,J79/24,J263/24'}, 284 | {n:'Asia/Thimphu',v:'<+06>-6'}, 285 | {n:'Asia/Tokyo',v:'JST-9'}, 286 | {n:'Asia/Tomsk',v:'<+07>-7'}, 287 | {n:'Asia/Ulaanbaatar',v:'<+08>-8'}, 288 | {n:'Asia/Urumqi',v:'<+06>-6'}, 289 | {n:'Asia/Ust-Nera',v:'<+10>-10'}, 290 | {n:'Asia/Vientiane',v:'<+07>-7'}, 291 | {n:'Asia/Vladivostok',v:'<+10>-10'}, 292 | {n:'Asia/Yakutsk',v:'<+09>-9'}, 293 | {n:'Asia/Yangon',v:'<+0630>-6:30'}, 294 | {n:'Asia/Yekaterinburg',v:'<+05>-5'}, 295 | {n:'Asia/Yerevan',v:'<+04>-4'}, 296 | {n:'Atlantic/Azores',v:'<-01>1<+00>,M3.5.0/0,M10.5.0/1'}, 297 | {n:'Atlantic/Bermuda',v:'AST4ADT,M3.2.0,M11.1.0'}, 298 | {n:'Atlantic/Canary',v:'WET0WEST,M3.5.0/1,M10.5.0'}, 299 | {n:'Atlantic/Cape Verde',v:'<-01>1'}, 300 | {n:'Atlantic/Faroe',v:'WET0WEST,M3.5.0/1,M10.5.0'}, 301 | {n:'Atlantic/Madeira',v:'WET0WEST,M3.5.0/1,M10.5.0'}, 302 | {n:'Atlantic/Reykjavik',v:'GMT0'}, 303 | {n:'Atlantic/South Georgia',v:'<-02>2'}, 304 | {n:'Atlantic/St Helena',v:'GMT0'}, 305 | {n:'Atlantic/Stanley',v:'<-03>3'}, 306 | {n:'Australia/Adelaide',v:'ACST-9:30ACDT,M10.1.0,M4.1.0/3'}, 307 | {n:'Australia/Brisbane',v:'AEST-10'}, 308 | {n:'Australia/Broken Hill',v:'ACST-9:30ACDT,M10.1.0,M4.1.0/3'}, 309 | {n:'Australia/Darwin',v:'ACST-9:30'}, 310 | {n:'Australia/Eucla',v:'<+0845>-8:45'}, 311 | {n:'Australia/Hobart',v:'AEST-10AEDT,M10.1.0,M4.1.0/3'}, 312 | {n:'Australia/Lindeman',v:'AEST-10'}, 313 | {n:'Australia/Lord Howe',v:'<+1030>-10:30<+11>-11,M10.1.0,M4.1.0'}, 314 | {n:'Australia/Melbourne',v:'AEST-10AEDT,M10.1.0,M4.1.0/3'}, 315 | {n:'Australia/Perth',v:'AWST-8'}, 316 | {n:'Australia/Sydney',v:'AEST-10AEDT,M10.1.0,M4.1.0/3'}, 317 | {n:'Etc/GMT',v:'GMT0'}, 318 | {n:'Etc/GMT+1',v:'<-01>1'}, 319 | {n:'Etc/GMT+10',v:'<-10>10'}, 320 | {n:'Etc/GMT+11',v:'<-11>11'}, 321 | {n:'Etc/GMT+12',v:'<-12>12'}, 322 | {n:'Etc/GMT+2',v:'<-02>2'}, 323 | {n:'Etc/GMT+3',v:'<-03>3'}, 324 | {n:'Etc/GMT+4',v:'<-04>4'}, 325 | {n:'Etc/GMT+5',v:'<-05>5'}, 326 | {n:'Etc/GMT+6',v:'<-06>6'}, 327 | {n:'Etc/GMT+7',v:'<-07>7'}, 328 | {n:'Etc/GMT+8',v:'<-08>8'}, 329 | {n:'Etc/GMT+9',v:'<-09>9'}, 330 | {n:'Etc/GMT-1',v:'<+01>-1'}, 331 | {n:'Etc/GMT-10',v:'<+10>-10'}, 332 | {n:'Etc/GMT-11',v:'<+11>-11'}, 333 | {n:'Etc/GMT-12',v:'<+12>-12'}, 334 | {n:'Etc/GMT-13',v:'<+13>-13'}, 335 | {n:'Etc/GMT-14',v:'<+14>-14'}, 336 | {n:'Etc/GMT-2',v:'<+02>-2'}, 337 | {n:'Etc/GMT-3',v:'<+03>-3'}, 338 | {n:'Etc/GMT-4',v:'<+04>-4'}, 339 | {n:'Etc/GMT-5',v:'<+05>-5'}, 340 | {n:'Etc/GMT-6',v:'<+06>-6'}, 341 | {n:'Etc/GMT-7',v:'<+07>-7'}, 342 | {n:'Etc/GMT-8',v:'<+08>-8'}, 343 | {n:'Etc/GMT-9',v:'<+09>-9'}, 344 | {n:'Europe/Amsterdam',v:'CET-1CEST,M3.5.0,M10.5.0/3'}, 345 | {n:'Europe/Andorra',v:'CET-1CEST,M3.5.0,M10.5.0/3'}, 346 | {n:'Europe/Astrakhan',v:'<+04>-4'}, 347 | {n:'Europe/Athens',v:'EET-2EEST,M3.5.0/3,M10.5.0/4'}, 348 | {n:'Europe/Belgrade',v:'CET-1CEST,M3.5.0,M10.5.0/3'}, 349 | {n:'Europe/Berlin',v:'CET-1CEST,M3.5.0,M10.5.0/3'}, 350 | {n:'Europe/Bratislava',v:'CET-1CEST,M3.5.0,M10.5.0/3'}, 351 | {n:'Europe/Brussels',v:'CET-1CEST,M3.5.0,M10.5.0/3'}, 352 | {n:'Europe/Bucharest',v:'EET-2EEST,M3.5.0/3,M10.5.0/4'}, 353 | {n:'Europe/Budapest',v:'CET-1CEST,M3.5.0,M10.5.0/3'}, 354 | {n:'Europe/Busingen',v:'CET-1CEST,M3.5.0,M10.5.0/3'}, 355 | {n:'Europe/Chisinau',v:'EET-2EEST,M3.5.0,M10.5.0/3'}, 356 | {n:'Europe/Copenhagen',v:'CET-1CEST,M3.5.0,M10.5.0/3'}, 357 | {n:'Europe/Dublin',v:'IST-1GMT0,M10.5.0,M3.5.0/1'}, 358 | {n:'Europe/Gibraltar',v:'CET-1CEST,M3.5.0,M10.5.0/3'}, 359 | {n:'Europe/Guernsey',v:'GMT0BST,M3.5.0/1,M10.5.0'}, 360 | {n:'Europe/Helsinki',v:'EET-2EEST,M3.5.0/3,M10.5.0/4'}, 361 | {n:'Europe/Isle of Man',v:'GMT0BST,M3.5.0/1,M10.5.0'}, 362 | {n:'Europe/Istanbul',v:'<+03>-3'}, 363 | {n:'Europe/Jersey',v:'GMT0BST,M3.5.0/1,M10.5.0'}, 364 | {n:'Europe/Kaliningrad',v:'EET-2'}, 365 | {n:'Europe/Kiev',v:'EET-2EEST,M3.5.0/3,M10.5.0/4'}, 366 | {n:'Europe/Kirov',v:'<+03>-3'}, 367 | {n:'Europe/Lisbon',v:'WET0WEST,M3.5.0/1,M10.5.0'}, 368 | {n:'Europe/Ljubljana',v:'CET-1CEST,M3.5.0,M10.5.0/3'}, 369 | {n:'Europe/London',v:'GMT0BST,M3.5.0/1,M10.5.0'}, 370 | {n:'Europe/Luxembourg',v:'CET-1CEST,M3.5.0,M10.5.0/3'}, 371 | {n:'Europe/Madrid',v:'CET-1CEST,M3.5.0,M10.5.0/3'}, 372 | {n:'Europe/Malta',v:'CET-1CEST,M3.5.0,M10.5.0/3'}, 373 | {n:'Europe/Mariehamn',v:'EET-2EEST,M3.5.0/3,M10.5.0/4'}, 374 | {n:'Europe/Minsk',v:'<+03>-3'}, 375 | {n:'Europe/Monaco',v:'CET-1CEST,M3.5.0,M10.5.0/3'}, 376 | {n:'Europe/Moscow',v:'MSK-3'}, 377 | {n:'Europe/Oslo',v:'CET-1CEST,M3.5.0,M10.5.0/3'}, 378 | {n:'Europe/Paris',v:'CET-1CEST,M3.5.0,M10.5.0/3'}, 379 | {n:'Europe/Podgorica',v:'CET-1CEST,M3.5.0,M10.5.0/3'}, 380 | {n:'Europe/Prague',v:'CET-1CEST,M3.5.0,M10.5.0/3'}, 381 | {n:'Europe/Riga',v:'EET-2EEST,M3.5.0/3,M10.5.0/4'}, 382 | {n:'Europe/Rome',v:'CET-1CEST,M3.5.0,M10.5.0/3'}, 383 | {n:'Europe/Samara',v:'<+04>-4'}, 384 | {n:'Europe/San Marino',v:'CET-1CEST,M3.5.0,M10.5.0/3'}, 385 | {n:'Europe/Sarajevo',v:'CET-1CEST,M3.5.0,M10.5.0/3'}, 386 | {n:'Europe/Saratov',v:'<+04>-4'}, 387 | {n:'Europe/Simferopol',v:'MSK-3'}, 388 | {n:'Europe/Skopje',v:'CET-1CEST,M3.5.0,M10.5.0/3'}, 389 | {n:'Europe/Sofia',v:'EET-2EEST,M3.5.0/3,M10.5.0/4'}, 390 | {n:'Europe/Stockholm',v:'CET-1CEST,M3.5.0,M10.5.0/3'}, 391 | {n:'Europe/Tallinn',v:'EET-2EEST,M3.5.0/3,M10.5.0/4'}, 392 | {n:'Europe/Tirane',v:'CET-1CEST,M3.5.0,M10.5.0/3'}, 393 | {n:'Europe/Ulyanovsk',v:'<+04>-4'}, 394 | {n:'Europe/Uzhgorod',v:'EET-2EEST,M3.5.0/3,M10.5.0/4'}, 395 | {n:'Europe/Vaduz',v:'CET-1CEST,M3.5.0,M10.5.0/3'}, 396 | {n:'Europe/Vatican',v:'CET-1CEST,M3.5.0,M10.5.0/3'}, 397 | {n:'Europe/Vienna',v:'CET-1CEST,M3.5.0,M10.5.0/3'}, 398 | {n:'Europe/Vilnius',v:'EET-2EEST,M3.5.0/3,M10.5.0/4'}, 399 | {n:'Europe/Volgograd',v:'<+03>-3'}, 400 | {n:'Europe/Warsaw',v:'CET-1CEST,M3.5.0,M10.5.0/3'}, 401 | {n:'Europe/Zagreb',v:'CET-1CEST,M3.5.0,M10.5.0/3'}, 402 | {n:'Europe/Zaporozhye',v:'EET-2EEST,M3.5.0/3,M10.5.0/4'}, 403 | {n:'Europe/Zurich',v:'CET-1CEST,M3.5.0,M10.5.0/3'}, 404 | {n:'Indian/Antananarivo',v:'EAT-3'}, 405 | {n:'Indian/Chagos',v:'<+06>-6'}, 406 | {n:'Indian/Christmas',v:'<+07>-7'}, 407 | {n:'Indian/Cocos',v:'<+0630>-6:30'}, 408 | {n:'Indian/Comoro',v:'EAT-3'}, 409 | {n:'Indian/Kerguelen',v:'<+05>-5'}, 410 | {n:'Indian/Mahe',v:'<+04>-4'}, 411 | {n:'Indian/Maldives',v:'<+05>-5'}, 412 | {n:'Indian/Mauritius',v:'<+04>-4'}, 413 | {n:'Indian/Mayotte',v:'EAT-3'}, 414 | {n:'Indian/Reunion',v:'<+04>-4'}, 415 | {n:'Pacific/Apia',v:'<+13>-13'}, 416 | {n:'Pacific/Auckland',v:'NZST-12NZDT,M9.5.0,M4.1.0/3'}, 417 | {n:'Pacific/Bougainville',v:'<+11>-11'}, 418 | {n:'Pacific/Chatham',v:'<+1245>-12:45<+1345>,M9.5.0/2:45,M4.1.0/3:45'}, 419 | {n:'Pacific/Chuuk',v:'<+10>-10'}, 420 | {n:'Pacific/Easter',v:'<-06>6<-05>,M9.1.6/22,M4.1.6/22'}, 421 | {n:'Pacific/Efate',v:'<+11>-11'}, 422 | {n:'Pacific/Fakaofo',v:'<+13>-13'}, 423 | {n:'Pacific/Fiji',v:'<+12>-12<+13>,M11.2.0,M1.2.3/99'}, 424 | {n:'Pacific/Funafuti',v:'<+12>-12'}, 425 | {n:'Pacific/Galapagos',v:'<-06>6'}, 426 | {n:'Pacific/Gambier',v:'<-09>9'}, 427 | {n:'Pacific/Guadalcanal',v:'<+11>-11'}, 428 | {n:'Pacific/Guam',v:'ChST-10'}, 429 | {n:'Pacific/Honolulu',v:'HST10'}, 430 | {n:'Pacific/Kanton',v:'<+13>-13'}, 431 | {n:'Pacific/Kiritimati',v:'<+14>-14'}, 432 | {n:'Pacific/Kosrae',v:'<+11>-11'}, 433 | {n:'Pacific/Kwajalein',v:'<+12>-12'}, 434 | {n:'Pacific/Majuro',v:'<+12>-12'}, 435 | {n:'Pacific/Marquesas',v:'<-0930>9:30'}, 436 | {n:'Pacific/Midway',v:'SST11'}, 437 | {n:'Pacific/Nauru',v:'<+12>-12'}, 438 | {n:'Pacific/Niue',v:'<-11>11'}, 439 | {n:'Pacific/Norfolk',v:'<+11>-11<+12>,M10.1.0,M4.1.0/3'}, 440 | {n:'Pacific/Noumea',v:'<+11>-11'}, 441 | {n:'Pacific/Pago Pago',v:'SST11'}, 442 | {n:'Pacific/Palau',v:'<+09>-9'}, 443 | {n:'Pacific/Pitcairn',v:'<-08>8'}, 444 | {n:'Pacific/Pohnpei',v:'<+11>-11'}, 445 | {n:'Pacific/Port Moresby',v:'<+10>-10'}, 446 | {n:'Pacific/Rarotonga',v:'<-10>10'}, 447 | {n:'Pacific/Saipan',v:'ChST-10'}, 448 | {n:'Pacific/Tahiti',v:'<-10>10'}, 449 | {n:'Pacific/Tarawa',v:'<+12>-12'}, 450 | {n:'Pacific/Tongatapu',v:'<+13>-13'}, 451 | {n:'Pacific/Wake',v:'<+12>-12'}, 452 | {n:'Pacific/Wallis',v:'<+12>-12'} 453 | ]; 454 | -------------------------------------------------------------------------------- /www/cgi-bin/ext-backuper.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl --upload-limit=200 --upload-dir=/tmp 2 | <%in p/common.cgi %> 3 | <% 4 | config_file=/etc/webui/backup.conf 5 | 6 | backup_create() { # backup_create 7 | backup_file_name="${network_address}_${fw_version}-${fw_variant}_"`date +%Y-%m-%d_%H-%M-%S`".tgz" 8 | # http_header_tgz filename 9 | echo "Content-type: application/tar+gzip" 10 | echo "Content-Transfer-Encoding: binary" 11 | echo "Cache-Control: no-store" 12 | echo "Pragma: no-cache" 13 | echo "Content-Disposition: attachment; filename=$backup_file_name" 14 | echo 15 | 16 | files_to_backup=`grep "^#/" $config_file | tr '#' ' ' | tr '\r\n' ' '` 17 | tar c -f - $files_to_backup | gzip 18 | exit 0 19 | } 20 | 21 | # create backup 22 | if [ "$GET_backup" = "create" ]; then 23 | backup_create 24 | exit 0 25 | fi 26 | 27 | if [ "$GET_backup" = "restore" ]; then 28 | # temporary stub, until file upload is fixed 29 | redirect_back 30 | exit 0 31 | fi 32 | %> 33 | -------------------------------------------------------------------------------- /www/cgi-bin/ext-openwall.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | page_title="OpenWall" 5 | config_file=/etc/webui/openwall.conf 6 | params="enabled crontab caption interval heif proxy" 7 | 8 | if [ "$REQUEST_METHOD" = "POST" ]; then 9 | for p in $params; do 10 | eval openwall_${p}=\$POST_openwall_${p} 11 | done 12 | 13 | if [ "$openwall_enabled" = "true" ]; then 14 | [ "$openwall_interval" -lt "15" ] && set_error_flag "Keep interval at 15 minutes or longer." 15 | fi 16 | 17 | if [ -z "$error" ]; then 18 | rm -f "$config_file" 19 | for p in $params; do 20 | echo "openwall_${p}=\"$(eval echo \$openwall_${p})\"" >> "$config_file" 21 | done 22 | 23 | sed -i /openwall/d /etc/crontabs/root 24 | if [ "$openwall_enabled" = "true" ] && [ "$openwall_crontab" = "true" ]; then 25 | echo "*/${openwall_interval} * * * * /usr/sbin/openwall" >> /etc/crontabs/root 26 | fi 27 | 28 | redirect_back "success" "OpenWall config updated." 29 | fi 30 | 31 | redirect_to "$SCRIPT_NAME" 32 | fi 33 | 34 | [ -e "$config_file" ] && include $config_file 35 | [ -z "$openwall_crontab" ] && openwall_crontab="true" 36 | [ -z "$openwall_interval" ] && openwall_interval="15" 37 | %> 38 | 39 | <%in p/header.cgi %> 40 | 41 |
42 |

This extension allows you to share images from your OpenIPC camera on the Open Wall 43 | page of our website. The images you share will allow us to determine the quality of images from different cameras. 44 | We also collect your MAC address, chipset, sensor, flashsize, firmware version, and uptime.

45 |
46 | 47 |
48 | <% field_switch "openwall_enabled" "Enable OpenWall" "eval" %> 49 |
50 |
51 | <% field_string "openwall_interval" "Interval" "eval" "15 30 60 120" "Minutes between submissions." %> 52 | <% field_text "openwall_caption" "Caption" "Location or short description." %> 53 |
54 | 55 |
56 | <% field_switch "openwall_crontab" "Add to Crontab" "eval" "Send pictures timed by interval." %> 57 | <% field_switch "openwall_heif" "Use HEIF format" "eval" "Requires H265 codec on Video0." %> 58 | <% field_switch "openwall_proxy" "Use SOCKS5" "eval" "Configure proxy access." %> 59 |
60 | 61 |
62 | <% [ -e "$config_file" ] && ex "cat $config_file" %> 63 | <% ex "grep openwall /etc/crontabs/root" %> 64 |
65 |
66 | <% button_submit %> 67 |
68 | 69 | 79 | 80 | <%in p/footer.cgi %> 81 | -------------------------------------------------------------------------------- /www/cgi-bin/ext-proxy.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | page_title="Proxy" 5 | config_file=/etc/webui/proxy.conf 6 | params="host port username password" 7 | 8 | if [ "$REQUEST_METHOD" = "POST" ]; then 9 | rm -f "$config_file" 10 | for p in $params; do 11 | echo "socks5_${p}=\"$(eval echo \$POST_socks5_${p})\"" >> "$config_file" 12 | done 13 | 14 | redirect_to "$SCRIPT_NAME" 15 | fi 16 | 17 | [ -e "$config_file" ] && include $config_file 18 | %> 19 | 20 | <%in p/header.cgi %> 21 | 22 |
23 |
24 |
25 | <% field_hidden "action" "update" %> 26 | <% field_text "socks5_host" "SOCKS5 host" %> 27 | <% field_text "socks5_port" "SOCKS5 port" "1080" %> 28 | <% field_text "socks5_username" "SOCKS5 username" %> 29 | <% field_password "socks5_password" "SOCKS5 password" %> 30 | <% button_submit %> 31 |
32 |
33 | 34 |
35 | <% [ -e "$config_file" ] && ex "cat $config_file" %> 36 |
37 |
38 | 39 | <%in p/footer.cgi %> 40 | -------------------------------------------------------------------------------- /www/cgi-bin/ext-telegram.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | page_title="Telegram" 5 | config_file=/etc/webui/telegram.conf 6 | params="enabled token channel thread_id interval caption crontab document heif proxy" 7 | 8 | # webhook for remote send, returns [t|f] 9 | if [ "$GET_send" = "image" ]; then 10 | echo "Content-type: text/html; charset=UTF-8" 11 | echo 12 | telegram | grep -v curl | jsonfilter -e '@.ok' 13 | exit 0 14 | fi 15 | 16 | if [ "$REQUEST_METHOD" = "POST" ]; then 17 | for p in $params; do 18 | eval telegram_${p}=\$POST_telegram_${p} 19 | done 20 | 21 | if [ "$telegram_enabled" = "true" ]; then 22 | [ -z "$telegram_token" ] && set_error_flag "Telegram token cannot be empty." 23 | [ -z "$telegram_channel" ] && set_error_flag "Telegram channel cannot be empty." 24 | fi 25 | 26 | if [ -z "$error" ]; then 27 | rm -f "$config_file" 28 | for p in $params; do 29 | echo "telegram_${p}=\"$(eval echo \$telegram_${p})\"" >> "$config_file" 30 | done 31 | 32 | sed -i /telegram/d /etc/crontabs/root 33 | if [ "$telegram_enabled" = "true" ] && [ "$telegram_crontab" = "true" ]; then 34 | echo "*/${telegram_interval} * * * * /usr/sbin/telegram" >> /etc/crontabs/root 35 | fi 36 | 37 | redirect_back "success" "Telegram config updated." 38 | fi 39 | 40 | redirect_to "$SCRIPT_NAME" 41 | fi 42 | 43 | [ -e "$config_file" ] && include $config_file 44 | [ -z "$telegram_crontab" ] && telegram_crontab="true" 45 | [ -z "$telegram_interval" ] && telegram_interval="15" 46 | %> 47 | 48 | <%in p/header.cgi %> 49 |
50 |
51 |
http://root:12345@<%= $network_address %>/cgi-bin/ext-telegram.cgi?send=image
52 |
Use this webhook url for remote call to send image.
53 |
54 |
55 | 56 |
57 | <% field_switch "telegram_enabled" "Enable Telegram" "eval" %> 58 |
59 |
60 | <% field_text "telegram_token" "Token" "Telegram bot authentication token." %> 61 | <% field_text "telegram_channel" "Channel" "Channel to post the images to." %> 62 | <% field_text "telegram_thread_id" "Message_thread_id" "Topic to post the images to. (for forum supergroups only)" %> 63 | <% field_string "telegram_interval" "Interval" "eval" "15 30 60 120" "Minutes between submissions." %> 64 | <% field_text "telegram_caption" "Caption" "Location or short description." %> 65 |
66 | 67 |
68 | <% field_switch "telegram_crontab" "Add to Crontab" "eval" "Send pictures timed by interval." %> 69 | <% field_switch "telegram_document" "Send as document" "eval" "Attach picture as general file." %> 70 | <% field_switch "telegram_heif" "Use HEIF format" "eval" "Requires H265 codec on Video0." %> 71 | <% field_switch "telegram_proxy" "Use SOCKS5" "eval" "Configure proxy access." %> 72 |
73 | 74 |
75 | <% [ -e "$config_file" ] && ex "cat $config_file" %> 76 | <% ex "grep telegram /etc/crontabs/root" %> 77 |
78 |
79 | <% button_submit %> 80 |
81 | 82 | 92 | 93 | <%in p/footer.cgi %> 94 | -------------------------------------------------------------------------------- /www/cgi-bin/ext-tunnel.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | page_title="Tunnel" 5 | conf_file=/tmp/vtund.conf 6 | env_host=$(fw_printenv -n vtun) 7 | 8 | if [ "$REQUEST_METHOD" = "POST" ]; then 9 | if [ "$POST_action" = "reset" ]; then 10 | killall -q tunnel 11 | killall -q vtund 12 | rm -f "$conf_file" 13 | fw_setenv vtun 14 | sleep 1 15 | redirect_to "$SCRIPT_NAME" "danger" "Tunnel is down" 16 | fi 17 | 18 | if [ -n "$POST_vtun_host" ]; then 19 | fw_setenv vtun "$POST_vtun_host" 20 | /etc/init.d/S98vtun start 21 | sleep 1 22 | redirect_to "$SCRIPT_NAME" "success" "Tunnel is up" 23 | fi 24 | fi 25 | %> 26 | 27 | <%in p/header.cgi %> 28 | 29 |
30 |
31 | <% if [ -e "$conf_file" ]; then %> 32 |
33 |

Virtual Tunnel is up

34 |

Use the following credentials to set up remote access via virtual tunnel:

35 |
36 |
Tunnel ID
37 |
<%= ${network_macaddr//:/} | tr a-z A-Z %>
38 |
Password
39 |
<% grep password $conf_file | xargs | cut -d' ' -f2 | sed 's/;$//' %> 40 |
41 |
42 | <% fi %> 43 | 44 |

Settings

45 |
46 | <% if [ -n "$env_host" ]; then %> 47 | <% field_hidden "action" "reset" %> 48 | <% button_submit "Reset configuration" %> 49 | <% else %> 50 | <% field_text "vtun_host" "Virtual Tunnel address" %> 51 | <% button_submit %> 52 | <% fi %> 53 |
54 |
55 | 56 |
57 |

Configuration

58 | <% 59 | [ -e "$conf_file" ] && ex "cat $conf_file" 60 | [ -n "$env_host" ] && ex "fw_printenv | grep vtun" 61 | ex "pgrep -a vtund" 62 | %> 63 |
64 |
65 | 66 | <%in p/footer.cgi %> 67 | -------------------------------------------------------------------------------- /www/cgi-bin/fpv-wfb.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <%in p/fpv_common.cgi %> 4 | <% 5 | set -x 6 | 7 | 8 | # Set page title and determine active tab 9 | page_title="WFB Settings" 10 | label="$GET_tab" 11 | [ -z "$label" ] && label="wireless" 12 | 13 | # Check if we're using YAML or legacy configuration 14 | using_yaml_config=0 15 | if is_using_yaml; then 16 | using_yaml_config=1 17 | fi 18 | 19 | # Debug function to log form submission data 20 | debug_log() { 21 | echo "$1" >> /tmp/wfb_debug.log 22 | } 23 | 24 | # Function to determine if a channel is in the 2.4GHz range 25 | is_24ghz_channel() { 26 | local channel="$1" 27 | # Channels 1-14 are in the 2.4GHz range 28 | if [ "$channel" -ge 1 ] && [ "$channel" -le 14 ]; then 29 | return 0 # True 30 | else 31 | return 1 # False 32 | fi 33 | } 34 | 35 | # Function to get the correct TX power based on channel frequency 36 | get_tx_power_for_channel() { 37 | local channel="$1" 38 | 39 | if [ "$using_yaml_config" = "1" ]; then 40 | # For YAML, always use the txpower field 41 | yaml_get_nested "$WFB_YAML" "wireless" "txpower" 42 | else 43 | # For legacy config, use different fields based on channel 44 | if is_24ghz_channel "$channel"; then 45 | # 2.4GHz channel - use txpower 46 | legacy_get_value "$WFB_CONF" "txpower" 47 | else 48 | # 5.8GHz channel - use driver_txpower_override 49 | legacy_get_value "$WFB_CONF" "driver_txpower_override" 50 | fi 51 | fi 52 | } 53 | 54 | # Function to set the correct TX power based on channel frequency 55 | set_tx_power_for_channel() { 56 | local channel="$1" 57 | local power_value="$2" 58 | 59 | debug_log "Setting TX power: channel=$channel, power_value=$power_value" 60 | 61 | if [ "$using_yaml_config" = "1" ]; then 62 | # For YAML, always use the txpower field 63 | yaml_set_value "$WFB_YAML" "wireless" "txpower" "$power_value" 64 | debug_log "Updated wireless.txpower: $power_value" 65 | else 66 | # For legacy config, use different fields based on channel 67 | if is_24ghz_channel "$channel"; then 68 | # 2.4GHz channel - use txpower 69 | legacy_set_value "$WFB_CONF" "txpower" "$power_value" 70 | debug_log "Updated wfb.conf:txpower: $power_value (2.4GHz channel)" 71 | else 72 | # 5.8GHz channel - use driver_txpower_override 73 | legacy_set_value "$WFB_CONF" "driver_txpower_override" "$power_value" 74 | debug_log "Updated wfb.conf:driver_txpower_override: $power_value (5GHz channel)" 75 | fi 76 | fi 77 | } 78 | 79 | # Function to update all WFB values - handles both YAML and legacy formats 80 | update_wfbinfo() { 81 | # Initialize variables with default values 82 | wfb_txpower="1" 83 | wfb_channel="161" 84 | wfb_width="20" 85 | wfb_frequency="" 86 | wfb_mcs_index="1" 87 | wfb_tun_index="1" 88 | wfb_fec_k="8" 89 | wfb_fec_n="12" 90 | wfb_stbc="0" 91 | wfb_ldpc="0" 92 | wfb_link_id="7669206" 93 | wfb_router="mavfwd" 94 | wfb_serial="/dev/ttyS2" 95 | wfb_osd_fps="20" 96 | 97 | if [ "$using_yaml_config" = "1" ]; then 98 | # Using YAML configuration - get values from WFB_YAML 99 | debug_log "Reading from YAML configuration: $WFB_YAML" 100 | 101 | # Get Wireless Values 102 | yaml_txpower=$(yaml_get_value "$WFB_YAML" "wireless" "txpower") 103 | yaml_channel=$(yaml_get_value "$WFB_YAML" "wireless" "channel") 104 | yaml_width=$(yaml_get_value "$WFB_YAML" "wireless" "width") 105 | yaml_frequency=$(yaml_get_value "$WFB_YAML" "wireless" "frequency") 106 | 107 | # Get Broadcast Values 108 | yaml_mcs_index=$(yaml_get_value "$WFB_YAML" "broadcast" "mcs_index") 109 | yaml_tun_index=$(yaml_get_value "$WFB_YAML" "broadcast" "tun_index") 110 | yaml_fec_k=$(yaml_get_value "$WFB_YAML" "broadcast" "fec_k") 111 | yaml_fec_n=$(yaml_get_value "$WFB_YAML" "broadcast" "fec_n") 112 | yaml_stbc=$(yaml_get_value "$WFB_YAML" "broadcast" "stbc") 113 | yaml_ldpc=$(yaml_get_value "$WFB_YAML" "broadcast" "ldpc") 114 | yaml_link_id=$(yaml_get_value "$WFB_YAML" "broadcast" "link_id") 115 | 116 | # Get Telemetry Values 117 | yaml_router=$(yaml_get_value "$WFB_YAML" "telemetry" "router") 118 | yaml_serial=$(yaml_get_value "$WFB_YAML" "telemetry" "serial") 119 | yaml_osd_fps=$(yaml_get_value "$WFB_YAML" "telemetry" "osd_fps") 120 | 121 | # Update variables with values from YAML if they exist 122 | [ -n "$yaml_txpower" ] && wfb_txpower="$yaml_txpower" 123 | [ -n "$yaml_channel" ] && wfb_channel="$yaml_channel" 124 | [ -n "$yaml_width" ] && wfb_width="$yaml_width" 125 | [ -n "$yaml_frequency" ] && wfb_frequency="$yaml_frequency" 126 | [ -n "$yaml_mcs_index" ] && wfb_mcs_index="$yaml_mcs_index" 127 | [ -n "$yaml_tun_index" ] && wfb_tun_index="$yaml_tun_index" 128 | [ -n "$yaml_fec_k" ] && wfb_fec_k="$yaml_fec_k" 129 | [ -n "$yaml_fec_n" ] && wfb_fec_n="$yaml_fec_n" 130 | [ -n "$yaml_stbc" ] && wfb_stbc="$yaml_stbc" 131 | [ -n "$yaml_ldpc" ] && wfb_ldpc="$yaml_ldpc" 132 | [ -n "$yaml_link_id" ] && wfb_link_id="$yaml_link_id" 133 | [ -n "$yaml_router" ] && wfb_router="$yaml_router" 134 | [ -n "$yaml_serial" ] && wfb_serial="$yaml_serial" 135 | [ -n "$yaml_osd_fps" ] && wfb_osd_fps="$yaml_osd_fps" 136 | else 137 | # Using legacy configuration - get values from conf files 138 | debug_log "Reading from legacy configuration files" 139 | 140 | # Get values from wfb.conf 141 | conf_channel=$(legacy_get_value "$WFB_CONF" "channel") 142 | conf_bandwidth=$(legacy_get_value "$WFB_CONF" "bandwidth") 143 | conf_frequency=$(legacy_get_value "$WFB_CONF" "frequency") 144 | conf_stbc=$(legacy_get_value "$WFB_CONF" "stbc") 145 | conf_ldpc=$(legacy_get_value "$WFB_CONF" "ldpc") 146 | conf_mcs_index=$(legacy_get_value "$WFB_CONF" "mcs_index") 147 | conf_tun_index=$(legacy_get_value "$WFB_CONF" "tun_index") # Added TUN index 148 | conf_link_id=$(legacy_get_value "$WFB_CONF" "link_id") 149 | conf_fec_k=$(legacy_get_value "$WFB_CONF" "fec_k") 150 | conf_fec_n=$(legacy_get_value "$WFB_CONF" "fec_n") 151 | 152 | # Get TX power based on channel frequency 153 | if [ -n "$conf_channel" ]; then 154 | # Get TX power from appropriate field based on channel 155 | conf_txpower=$(get_tx_power_for_channel "$conf_channel") 156 | debug_log "Read TX power for channel $conf_channel: $conf_txpower" 157 | else 158 | # Fallback if channel not set 159 | conf_txpower=$(legacy_get_value "$WFB_CONF" "txpower") 160 | debug_log "Read fallback TX power: $conf_txpower" 161 | fi 162 | 163 | # Get values from telemetry.conf 164 | tel_router=$(legacy_get_value "$TELEMETRY_CONF" "router") 165 | tel_serial=$(legacy_get_value "$TELEMETRY_CONF" "serial") 166 | tel_fps=$(legacy_get_value "$TELEMETRY_CONF" "fps") 167 | 168 | # Update variables with values from conf files if they exist 169 | [ -n "$conf_channel" ] && wfb_channel="$conf_channel" 170 | [ -n "$conf_txpower" ] && wfb_txpower="$conf_txpower" 171 | [ -n "$conf_bandwidth" ] && wfb_width="$conf_bandwidth" 172 | [ -n "$conf_frequency" ] && wfb_frequency="$conf_frequency" 173 | [ -n "$conf_mcs_index" ] && wfb_mcs_index="$conf_mcs_index" 174 | [ -n "$conf_tun_index" ] && wfb_tun_index="$conf_tun_index" # Use TUN index if available 175 | [ -n "$conf_stbc" ] && wfb_stbc="$conf_stbc" 176 | [ -n "$conf_ldpc" ] && wfb_ldpc="$conf_ldpc" 177 | [ -n "$conf_link_id" ] && wfb_link_id="$conf_link_id" 178 | [ -n "$conf_fec_k" ] && wfb_fec_k="$conf_fec_k" 179 | [ -n "$conf_fec_n" ] && wfb_fec_n="$conf_fec_n" 180 | 181 | debug_log "Loaded wfb_txpower = $wfb_txpower" 182 | 183 | # Map router numeric value to string representation for the UI 184 | if [ -n "$tel_router" ]; then 185 | wfb_router=$(map_router_value "$tel_router") 186 | fi 187 | 188 | [ -n "$tel_serial" ] && wfb_serial="$tel_serial" 189 | [ -n "$tel_fps" ] && wfb_osd_fps="$tel_fps" 190 | fi 191 | 192 | # Export for use in haserl 193 | export wfb_txpower wfb_channel wfb_width wfb_frequency 194 | export wfb_mcs_index wfb_tun_index wfb_fec_k wfb_fec_n wfb_stbc wfb_ldpc wfb_link_id 195 | export wfb_router wfb_serial wfb_osd_fps 196 | 197 | # Export section names for the tab labels 198 | export wfb_wireless="Wireless" 199 | export wfb_broadcast="Broadcast" 200 | export wfb_telemetry="Telemetry" 201 | } 202 | 203 | # Map numeric router value to string for UI display 204 | map_router_value() { 205 | local numeric_value="$1" 206 | case "$numeric_value" in 207 | 0) echo "mavfwd" ;; 208 | 1) echo "mavrouter" ;; 209 | 2) echo "msposd" ;; 210 | 3) echo "ground" ;; 211 | *) echo "$numeric_value" ;; # Return as-is if not a recognized code 212 | esac 213 | } 214 | 215 | # Map router string back to numeric value for legacy conf files 216 | map_router_to_numeric() { 217 | local string_value="$1" 218 | case "$string_value" in 219 | mavfwd) echo "0" ;; 220 | mavrouter) echo "1" ;; 221 | msposd) echo "2" ;; 222 | *) echo "$string_value" ;; # Return as-is if not a recognized string 223 | esac 224 | } 225 | 226 | # Define available wireless channels 227 | channels="1 2 3 4 5 6 7 8 9 10 11 12 13 14 36 40 44 48 52 56 60 64 100 104 108 112 116 120 124 128 132 136 140 149 153 157 161 165 169 173 177" 228 | 229 | # Define corresponding frequencies 230 | frequencies="2412 2417 2422 2427 2432 2437 2442 2447 2452 2457 2462 2467 2472 2484 5180 5200 5220 5240 5260 5280 5300 5320 5500 5520 5540 5560 5580 5600 5620 5640 5660 5680 5700 5745 5765 5785 5805 5825 5845 5865 5885" 231 | 232 | # Function to get the frequency for a given channel 233 | get_frequency() { 234 | local channel="$1" 235 | local index=0 236 | for c in $channels; do 237 | if [ "$c" = "$channel" ]; then 238 | # Get the corresponding frequency 239 | frequency=$(echo "$frequencies" | awk "{print \$$((index+1))}") 240 | echo "$frequency" 241 | return 242 | fi 243 | index=$((index+1)) 244 | done 245 | echo "Unknown" # Return "Unknown" if channel not found 246 | } 247 | 248 | # Function to create a label with tooltip 249 | tooltip_label() { 250 | local name="$1" 251 | local label="$2" 252 | local tooltip="$3" 253 | 254 | echo "" 259 | } 260 | 261 | # Function to generate channel options with channel-frequency pairs 262 | field_channel_select() { 263 | local name="$1" 264 | local label="$2" 265 | local selected="$3" 266 | local tooltip="$4" 267 | 268 | echo "

" 269 | tooltip_label "$name" "$label" "$tooltip" 270 | echo "

" 282 | } 283 | 284 | # Function for select with tooltip 285 | field_select_tooltip() { 286 | local name="$1" 287 | local label="$2" 288 | local selected="$3" 289 | local tooltip="$4" 290 | local min="$5" 291 | local max="$6" 292 | local step="$7" 293 | 294 | echo "

" 295 | tooltip_label "$name" "$label" "$tooltip" 296 | echo "

" 307 | } 308 | 309 | # Custom function for boolean switches that uses numeric values (0/1) 310 | field_numeric_switch_tooltip() { 311 | local name="$1" 312 | local label="$2" 313 | local value="$3" 314 | local tooltip="$4" 315 | 316 | local checked="" 317 | [ "$value" = "1" ] && checked="checked" 318 | 319 | echo "

" 320 | echo "" 321 | echo "" 322 | tooltip_label "$name" "$label" "$tooltip" 323 | echo "

" 324 | } 325 | 326 | # Function for text input with tooltip 327 | field_string_tooltip() { 328 | local name="$1" 329 | local label="$2" 330 | local value="$3" 331 | local tooltip="$4" 332 | local options="$5" 333 | 334 | echo "

" 335 | tooltip_label "$name" "$label" "$tooltip" 336 | 337 | if [ -n "$options" ]; then 338 | echo "" 345 | else 346 | echo "" 347 | fi 348 | echo "

" 349 | } 350 | 351 | # Handle form submission 352 | if [ "$REQUEST_METHOD" = "POST" ]; then 353 | # Create a debug log entry for form submission 354 | debug_log "Form submitted with action: $POST_action" 355 | debug_log "Current tab: $label" 356 | 357 | case "$POST_action" in 358 | update) 359 | # Log all POST variables for debugging 360 | for var in $(set | grep ^POST_ | cut -d= -f1); do 361 | val=$(eval echo \$$var) 362 | debug_log "$var = $val" 363 | done 364 | 365 | # Process all form fields regardless of current tab 366 | if [ "$using_yaml_config" = "1" ]; then 367 | # Update YAML configuration 368 | debug_log "Updating YAML configuration" 369 | 370 | # Wireless settings 371 | if [ -n "$POST_txpower" ]; then 372 | yaml_set_value "$WFB_YAML" "wireless" "txpower" "$POST_txpower" 373 | debug_log "Updated wireless.txpower: $POST_txpower" 374 | fi 375 | 376 | if [ -n "$POST_channel" ]; then 377 | yaml_set_value "$WFB_YAML" "wireless" "channel" "$POST_channel" 378 | debug_log "Updated wireless.channel: $POST_channel" 379 | fi 380 | 381 | if [ -n "$POST_frequency" ]; then 382 | yaml_set_value "$WFB_YAML" "wireless" "frequency" "$POST_frequency" 383 | debug_log "Updated wireless.frequency: $POST_frequency" 384 | fi 385 | 386 | if [ -n "$POST_width" ]; then 387 | yaml_set_value "$WFB_YAML" "wireless" "width" "$POST_width" 388 | debug_log "Updated wireless.width: $POST_width" 389 | fi 390 | 391 | # Broadcast settings 392 | if [ -n "$POST_mcs_index" ]; then 393 | yaml_set_value "$WFB_YAML" "broadcast" "mcs_index" "$POST_mcs_index" 394 | debug_log "Updated broadcast.mcs_index: $POST_mcs_index" 395 | fi 396 | 397 | if [ -n "$POST_tun_index" ]; then 398 | yaml_set_value "$WFB_YAML" "broadcast" "tun_index" "$POST_tun_index" 399 | debug_log "Updated broadcast.tun_index: $POST_tun_index" 400 | fi 401 | 402 | if [ -n "$POST_fec_k" ]; then 403 | yaml_set_value "$WFB_YAML" "broadcast" "fec_k" "$POST_fec_k" 404 | debug_log "Updated broadcast.fec_k: $POST_fec_k" 405 | fi 406 | 407 | if [ -n "$POST_fec_n" ]; then 408 | yaml_set_value "$WFB_YAML" "broadcast" "fec_n" "$POST_fec_n" 409 | debug_log "Updated broadcast.fec_n: $POST_fec_n" 410 | fi 411 | 412 | # Handle the stbc switch - directly use numeric value (0 or 1) 413 | if [ -n "$POST_stbc" ]; then 414 | yaml_set_value "$WFB_YAML" "broadcast" "stbc" "$POST_stbc" 415 | debug_log "Updated broadcast.stbc: $POST_stbc" 416 | fi 417 | 418 | # Handle the ldpc switch - directly use numeric value (0 or 1) 419 | if [ -n "$POST_ldpc" ]; then 420 | yaml_set_value "$WFB_YAML" "broadcast" "ldpc" "$POST_ldpc" 421 | debug_log "Updated broadcast.ldpc: $POST_ldpc" 422 | fi 423 | 424 | if [ -n "$POST_link_id" ]; then 425 | yaml_set_value "$WFB_YAML" "broadcast" "link_id" "$POST_link_id" 426 | debug_log "Updated broadcast.link_id: $POST_link_id" 427 | fi 428 | 429 | # Telemetry settings 430 | if [ -n "$POST_router" ]; then 431 | yaml_set_value "$WFB_YAML" "telemetry" "router" "$POST_router" 432 | debug_log "Updated telemetry.router: $POST_router" 433 | fi 434 | 435 | if [ -n "$POST_serial" ]; then 436 | yaml_set_value "$WFB_YAML" "telemetry" "serial" "$POST_serial" 437 | debug_log "Updated telemetry.serial: $POST_serial" 438 | fi 439 | if [ -n "$POST_osd_fps" ]; then 440 | yaml_set_value "$WFB_YAML" "telemetry" "osd_fps" "$POST_osd_fps" 441 | debug_log "Updated telemetry.osd_fps: $POST_osd_fps" 442 | fi 443 | 444 | else 445 | # Update legacy configuration files 446 | debug_log "Updating legacy configuration files" 447 | 448 | # First, get the current or new channel to determine which field to use for TX power 449 | current_channel="$wfb_channel" 450 | [ -n "$POST_channel" ] && current_channel="$POST_channel" 451 | debug_log "Using channel $current_channel for TX power field determination" 452 | 453 | # Handle TX power updates - must be done BEFORE channel changes 454 | if [ -n "$POST_txpower" ]; then 455 | debug_log "Updating TX power to: $POST_txpower" 456 | set_tx_power_for_channel "$current_channel" "$POST_txpower" 457 | fi 458 | 459 | # Now handle channel changes 460 | if [ -n "$POST_channel" ]; then 461 | # The channel has changed, which might affect where TX power is stored 462 | old_channel="$wfb_channel" 463 | 464 | # Update the channel 465 | legacy_set_value "$WFB_CONF" "channel" "$POST_channel" 466 | debug_log "Updated wfb.conf:channel: $POST_channel" 467 | 468 | # Check if we're crossing the 2.4GHz/5GHz boundary 469 | old_is_24ghz=$(is_24ghz_channel "$old_channel" && echo "1" || echo "0") 470 | new_is_24ghz=$(is_24ghz_channel "$POST_channel" && echo "1" || echo "0") 471 | 472 | if [ "$old_is_24ghz" != "$new_is_24ghz" ]; then 473 | debug_log "Channel frequency band changed from $old_channel to $POST_channel" 474 | 475 | # We must clear the old field to avoid confusion 476 | if [ "$new_is_24ghz" = "1" ]; then 477 | # Moving from 5GHz to 2.4GHz, clear driver_txpower_override 478 | legacy_set_value "$WFB_CONF" "driver_txpower_override" "" 479 | debug_log "Cleared driver_txpower_override (moved to txpower)" 480 | else 481 | # Moving from 2.4GHz to 5GHz, clear txpower 482 | legacy_set_value "$WFB_CONF" "txpower" "" 483 | debug_log "Cleared txpower (moved to driver_txpower_override)" 484 | fi 485 | fi 486 | fi 487 | 488 | # Handle frequency updates 489 | if [ -n "$POST_frequency" ]; then 490 | legacy_set_value "$WFB_CONF" "frequency" "$POST_frequency" 491 | debug_log "Updated wfb.conf:frequency: $POST_frequency" 492 | fi 493 | 494 | # Other wireless settings in wfb.conf 495 | if [ -n "$POST_width" ]; then 496 | legacy_set_value "$WFB_CONF" "bandwidth" "$POST_width" 497 | debug_log "Updated wfb.conf:bandwidth: $POST_width" 498 | fi 499 | 500 | # Broadcast settings in wfb.conf 501 | if [ -n "$POST_mcs_index" ]; then 502 | legacy_set_value "$WFB_CONF" "mcs_index" "$POST_mcs_index" 503 | debug_log "Updated wfb.conf:mcs_index: $POST_mcs_index" 504 | fi 505 | 506 | #if [ -n "$POST_tun_index" ]; then 507 | # legacy_set_value "$WFB_CONF" "tun_index" "$POST_tun_index" 508 | # debug_log "Updated wfb.conf:tun_index: $POST_tun_index" 509 | #fi 510 | 511 | if [ -n "$POST_fec_k" ]; then 512 | legacy_set_value "$WFB_CONF" "fec_k" "$POST_fec_k" 513 | debug_log "Updated wfb.conf:fec_k: $POST_fec_k" 514 | fi 515 | 516 | if [ -n "$POST_fec_n" ]; then 517 | legacy_set_value "$WFB_CONF" "fec_n" "$POST_fec_n" 518 | debug_log "Updated wfb.conf:fec_n: $POST_fec_n" 519 | fi 520 | 521 | # Handle the stbc switch in wfb.conf 522 | if [ -n "$POST_stbc" ]; then 523 | legacy_set_value "$WFB_CONF" "stbc" "$POST_stbc" 524 | debug_log "Updated wfb.conf:stbc: $POST_stbc" 525 | fi 526 | 527 | # Handle the ldpc switch in wfb.conf 528 | if [ -n "$POST_ldpc" ]; then 529 | legacy_set_value "$WFB_CONF" "ldpc" "$POST_ldpc" 530 | debug_log "Updated wfb.conf:ldpc: $POST_ldpc" 531 | fi 532 | 533 | if [ -n "$POST_link_id" ]; then 534 | legacy_set_value "$WFB_CONF" "link_id" "$POST_link_id" 535 | debug_log "Updated wfb.conf:link_id: $POST_link_id" 536 | fi 537 | 538 | # Telemetry settings in telemetry.conf 539 | if [ -n "$POST_router" ]; then 540 | # Map the string router value to numeric value for legacy config 541 | router_numeric=$(map_router_to_numeric "$POST_router") 542 | legacy_set_value "$TELEMETRY_CONF" "router" "$router_numeric" 543 | debug_log "Updated telemetry.conf:router: $router_numeric (from $POST_router)" 544 | fi 545 | 546 | if [ -n "$POST_serial" ]; then 547 | legacy_set_value "$TELEMETRY_CONF" "serial" "$POST_serial" 548 | debug_log "Updated telemetry.conf:serial: $POST_serial" 549 | fi 550 | if [ -n "$POST_osd_fps" ]; then 551 | legacy_set_value "$TELEMETRY_CONF" "fps" "$POST_osd_fps" 552 | debug_log "Updated telemetry.conf:fps: $POST_osd_fps" 553 | fi 554 | 555 | fi 556 | 557 | # Update local variables with new values 558 | update_wfbinfo 559 | # Redirect with success message 560 | redirect_back "success" "WFB settings updated." 561 | ;; 562 | esac 563 | fi 564 | 565 | # Call function to update local variables 566 | update_wfbinfo 567 | 568 | %> 569 | <%in p/header.cgi %> 570 | 579 | 580 | 581 | 598 | 599 |
600 |
601 | 602 |
603 | <% field_hidden "action" "update" %> 604 | <% field_hidden "current_tab" "$label" %> 605 | 606 | 607 | <% if [ "$using_yaml_config" = "1" ]; then %> 608 |
609 | Using YAML Configuration: This device is using the new YAML configuration format. 610 |
611 | <% else %> 612 |
613 | Using Legacy Configuration: This device is using the legacy .conf configuration format. 614 | <% if is_24ghz_channel "$wfb_channel"; then %> 615 | (2.4GHz channel - TX power stored in txpower) 616 | <% else %> 617 | (5GHz channel - TX power stored in driver_txpower_override) 618 | <% fi %> 619 |
620 | <% fi %> 621 | 622 | <% if [ "$label" = "wireless" ]; then %> 623 |
624 |

Wireless

625 | 626 | <% field_channel_select "channel" "Wireless Channel" "$wfb_channel" "WiFi channel used for transmission. 2.4GHz (1-14) have better penetration, 5GHz (36-165) have less interference. Choose based on local conditions and regulations." %> 627 | 628 |

629 | <% tooltip_label "txpower" "TX Power" "Transmit power in dBm. Higher values increase range but consume more power and may cause interference. Check local regulations for maximum allowed values." %> 630 | 631 | 632 | 633 | <%= $wfb_txpower %> 634 | 635 |

636 | 637 |

638 | <% tooltip_label "width" "Bandwidth" "Channel width in MHz. Wider channels (40/80) provide higher throughput but are more susceptible to interference. 20MHz is most reliable for long-range links." %> 639 | 643 |

644 | 645 |
646 | <% elif [ "$label" = "broadcast" ]; then %> 647 |

Broadcast

648 | 649 | <% field_select_tooltip "mcs_index" "MCS Index" "$wfb_mcs_index" "MCS (Modulation and Coding Scheme) index determines bitrate and robustness. Lower values are more reliable in poor conditions but have lower throughput." 1 10 1 %> 650 | 651 | <% if [ "$using_yaml_config" = "1" ]; then %> 652 | <% field_select_tooltip "tun_index" "TUN Index" "$wfb_tun_index" "Tunnel interface index for wifibroadcast. Multiple interfaces allow multiple video streams. Most setups use index 1 for the primary video." 1 10 1 %> 653 | <% fi %> 654 | 655 | <% field_select_tooltip "fec_k" "FEC K" "$wfb_fec_k" "Forward Error Correction K parameter - number of data packets per FEC block. Lower values provide better redundancy but lower efficiency." 1 15 1 %> 656 | 657 | <% field_select_tooltip "fec_n" "FEC N" "$wfb_fec_n" "Forward Error Correction N parameter - total number of packets per FEC block. The difference (N-K) determines redundant packets. Higher difference provides better error correction." 1 15 1 %> 658 | 659 | <% field_numeric_switch_tooltip "stbc" "STBC Enabled" "$wfb_stbc" "Space-Time Block Coding improves signal reliability in challenging environments by using multiple antennas. Enable for better range and resilience against interference." %> 660 | 661 | <% field_numeric_switch_tooltip "ldpc" "LDPC Enabled" "$wfb_ldpc" "Low-Density Parity-Check coding provides better error correction than standard coding. Enable for improved link quality at longer ranges." %> 662 | 663 | <% field_string_tooltip "link_id" "Link ID" "$wfb_link_id" "Unique identifier for this link. Must match between transmitter and receiver. Use different values for separate links to avoid interference." "" %> 664 | 665 | <% elif [ "$label" = "telemetry" ]; then %> 666 |

Telemetry

667 | <% if [ "$using_yaml_config" = "1" ]; then %> 668 | <% field_string_tooltip "router" "Router" "$wfb_router" "Telemetry router type: mavfwd (basic forwarding), mavrouter (routing between interfaces), msposd (MultiWii Serial Protocol for OSD), or ground" "mavfwd mavrouter msposd ground" %> 669 | <% else %> 670 | 671 |

672 | <% tooltip_label "router" "Router" "Telemetry router type: mavfwd (basic forwarding, 0), mavrouter (routing between interfaces, 1), or msposd (MultiWii Serial Protocol for OSD, 2)" %> 673 | 679 |

680 | <% fi %> 681 | 682 | <% field_string_tooltip "serial" "Serial Port" "$wfb_serial" "Serial port for telemetry data (e.g., ttyS0, ttyS1, ttyS2, ttyAMA0). Check your hardware documentation for the correct port." "" %> 683 | 684 |

685 | <% tooltip_label "osd_fps" "OSD FPS" "On-Screen Display refresh rate. Higher values provide smoother OSD updates but use more bandwidth. 20-30 FPS is suitable for most applications." %> 686 | 693 |

694 | <% fi %> 695 | 696 | <% button_submit %> 697 | 698 |
699 |
700 |
701 |

Restart Camera

702 |

Reboot camera to apply new settings and reset temporary files.

703 | Restart Camera 704 |
705 |
706 | 707 |
708 |

Current Configuration

709 | <% if [ "$using_yaml_config" = "1" ]; then %> 710 | <% ex "cat $WFB_YAML" %> 711 | <% else %> 712 | <% if [ "$label" = "wireless" ] || [ "$label" = "broadcast" ]; then %> 713 |
WFB Config
714 | <% ex "cat $WFB_CONF" %> 715 | <% elif [ "$label" = "telemetry" ]; then %> 716 |
Telemetry Config
717 | <% ex "cat $TELEMETRY_CONF" %> 718 | <% fi %> 719 | <% fi %> 720 |
721 |
722 | 723 | 724 | 744 | 745 | <%in p/footer.cgi %> -------------------------------------------------------------------------------- /www/cgi-bin/fw-editor.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | page_title="Text Editor" 5 | 6 | if [ "$REQUEST_METHOD" = "POST" ]; then 7 | editor_file="$POST_editor_file" 8 | editor_text="$POST_editor_text" 9 | 10 | # strip carriage return (\u000D) characters 11 | editor_text=$(echo "$editor_text" | sed s/\\r//g) 12 | 13 | case "$POST_action" in 14 | save) 15 | if [ -z "$editor_text" ]; then 16 | log_create "warning" "Empty payload. File not saved!" 17 | else 18 | [ -f "${editor_file}.backup" ] && rm "${editor_file}.backup" 19 | echo "$editor_text" > "$editor_file" 20 | redirect_to "${SCRIPT_NAME}?f=${editor_file}" "success" "File saved." 21 | fi 22 | ;; 23 | 24 | *) 25 | log_create "danger" "UNKNOWN ACTION: $POST_action" 26 | ;; 27 | esac 28 | else 29 | editor_file="$GET_f" 30 | if [ ! -f "$editor_file" ]; then 31 | log_create "danger" "File not found!" 32 | elif [ -n "$editor_file" ]; then 33 | if [ "b" = "$( (cat -v "$editor_file" | grep -q "\^@") && echo "b" )" ]; then 34 | log_create "danger" "Not a text file!" 35 | elif [ "$(stat -c%s $editor_file)" -gt "102400" ]; then 36 | log_create "danger" "Uploaded file is too large!" 37 | else 38 | editor_text="$(cat $editor_file)" 39 | fi 40 | fi 41 | fi 42 | %> 43 | 44 | <%in p/header.cgi %> 45 |
46 | <% field_hidden "action" "save" %> 47 | <% field_hidden "editor_file" "$editor_file" %> 48 | <% field_textedit "editor_text" "File content" "$editor_file" %> 49 | <% button_submit %> 50 |
51 | 52 | <%in p/footer.cgi %> 53 | -------------------------------------------------------------------------------- /www/cgi-bin/fw-interface.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl --upload-limit=100 --upload-dir=/tmp 2 | <%in p/common.cgi %> 3 | <% 4 | page_title="Interface Settings" 5 | config_file="/etc/webui/webui.conf" 6 | 7 | if [ "$REQUEST_METHOD" = "POST" ]; then 8 | case "$POST_action" in 9 | access) 10 | password_default="$POST_password_default" 11 | if [ -z "$password_default" ]; then 12 | redirect_to "$SCRIPT_NAME" "danger" "Password cannot be empty!" 13 | fi 14 | 15 | password_confirm="$POST_password_confirm" 16 | if [ "$password_default" != "$password_confirm" ]; then 17 | redirect_to "$SCRIPT_NAME" "danger" "Password does not match!" 18 | fi 19 | 20 | echo "root:${password_default}" | chpasswd 21 | update_caminfo 22 | redirect_to "/" "success" "Password updated." 23 | ;; 24 | 25 | theme) 26 | eval webui_theme=\$POST_webui_theme 27 | echo webui_theme=\"$webui_theme\" > $config_file 28 | update_caminfo 29 | redirect_back "success" "Settings updated." 30 | ;; 31 | 32 | *) 33 | redirect_to "$SCRIPT_NAME" "danger" "UNKNOWN ACTION: $POST_action" 34 | ;; 35 | esac 36 | fi 37 | 38 | ui_username="$USER" 39 | %> 40 | 41 | <%in p/header.cgi %> 42 | 43 |
44 |
45 |

Access

46 |
47 | <% field_hidden "action" "access" %> 48 |

49 | 50 | 51 |

52 | <% field_password "password_default" "Password" %> 53 | <% field_password "password_confirm" "Confirm Password" %> 54 | <% button_submit %> 55 |
56 |
57 | 58 |
59 |

Theme

60 |
61 | <% field_hidden "action" "theme" %> 62 | <% field_string "webui_theme" "Theme" "eval" "dark light" %> 63 | <% button_submit %> 64 |
65 |
66 |
67 | 68 | <%in p/footer.cgi %> 69 | -------------------------------------------------------------------------------- /www/cgi-bin/fw-network.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | 4 | <% 5 | page_title="Network Settings" 6 | params="address dhcp gateway hostname nameserver netmask interface wlan_ssid wlan_password" 7 | 8 | network_list="$(ls /sys/class/net | grep -e eth0 -e wlan0)" 9 | network_nameserver="$(cat /etc/resolv.conf | grep nameserver | cut -d' ' -f2)" 10 | network_netmask="$(ifconfig ${network_interface} | grep Mask | cut -d: -f4)" 11 | network_dhcp="$(cat /etc/network/interfaces.d/${network_interface} | grep -q dhcp && echo true)" 12 | 13 | network_wlan_ssid="$(fw_printenv -n wlanssid)" 14 | network_wlan_password="$(fw_printenv -n wlanpass)" 15 | 16 | if [ "$REQUEST_METHOD" = "POST" ]; then 17 | case "$POST_action" in 18 | changemac) 19 | if echo "$POST_mac_address" | grep -Eiq '^([0-9a-f]{2}[:-]){5}([0-9a-f]{2})$'; then 20 | fw_setenv ethaddr "$POST_mac_address" 21 | update_caminfo 22 | touch /tmp/system-reboot 23 | redirect_back "success" "MAC address updated." 24 | else 25 | if [ -z "$POST_mac_address" ]; then 26 | redirect_back "warning" "Empty MAC address." 27 | else 28 | redirect_back "warning" "Invalid MAC address: ${POST_mac_address}" 29 | fi 30 | fi 31 | ;; 32 | 33 | reset) 34 | rm -f /etc/network/interfaces.d/* 35 | cp -f /rom/etc/network/interfaces.d/* /etc/network/interfaces.d 36 | redirect_back 37 | ;; 38 | 39 | update) 40 | for p in $params; do 41 | eval network_${p}=\$POST_network_${p} 42 | done 43 | 44 | [ -z "$network_interface" ] && set_error_flag "Default network interface cannot be empty." 45 | if [ "$network_interface" = "wlan0" ]; then 46 | [ -z "$network_wlan_ssid" ] && set_error_flag"WLAN SSID cannot be empty." 47 | [ -z "$network_wlan_password" ] && set_error_flag "WLAN Password cannot be empty." 48 | fi 49 | 50 | if [ "$network_dhcp" = "false" ]; then 51 | network_mode="static" 52 | [ -z "$network_address" ] && set_error_flag "IP address cannot be empty." 53 | [ -z "$network_netmask" ] && set_error_flag "Networking mask cannot be empty." 54 | else 55 | network_mode="dhcp" 56 | fi 57 | 58 | if [ -z "$error" ]; then 59 | command="setnetwork" 60 | command="${command} -i $network_interface" 61 | command="${command} -m $network_mode" 62 | command="${command} -h $network_hostname" 63 | 64 | if [ "$network_interface" = "wlan0" ]; then 65 | command="${command} -s $network_wlan_ssid" 66 | command="${command} -p $network_wlan_password" 67 | fi 68 | 69 | if [ "$network_mode" != "dhcp" ]; then 70 | command="${command} -a $network_address" 71 | command="${command} -n $network_netmask" 72 | [ -n "$network_gateway" ] && command="${command} -g $network_gateway" 73 | [ -n "$network_nameserver" ] && command="${command} -d $network_nameserver" 74 | fi 75 | 76 | echo "$command" >> /tmp/webui.log 77 | eval "$command" > /dev/null 2>&1 78 | 79 | update_caminfo 80 | redirect_back "success" "Network settings updated." 81 | fi 82 | ;; 83 | esac 84 | fi 85 | %> 86 | <%in p/header.cgi %> 87 | 88 |
89 |
90 |
91 | <% field_hidden "action" "update" %> 92 | <% field_text "network_hostname" "Hostname" %> 93 | <% field_string "network_interface" "Network interface" "eval" "$network_list" %> 94 | <% field_text "network_wlan_ssid" "WLAN SSID" %> 95 | <% field_text "network_wlan_password" "WLAN Password" %> 96 | 97 | <% field_switch "network_dhcp" "Use DHCP" "eval" %> 98 | <% field_text "network_address" "IP Address" %> 99 | <% field_text "network_netmask" "IP Netmask" %> 100 | <% field_text "network_gateway" "Gateway" %> 101 | <% field_text "network_nameserver" "DNS" %> 102 | <% button_submit %> 103 |
104 | 105 |
106 |
Reset network configuration
107 |

Restore the config file bundled with firmware. All changes to the default configuration will be lost!

108 |
109 | <% field_hidden "action" "reset" %> 110 | <% button_submit "Reset config" "danger" %> 111 |
112 |
113 |
114 | 115 |
116 | <% for dev in $network_list; do %> 117 | <% ex "cat /etc/network/interfaces.d/$dev" %> 118 | <% done %> 119 | <% if [ -n "$(fw_printenv -n wlandev)" ]; then %> 120 | <% ex "fw_printenv | grep wlan" %> 121 | <% fi %> 122 | <% ex "ifconfig" %> 123 |
124 |
125 | 126 | 152 | 153 | <%in p/footer.cgi %> 154 | -------------------------------------------------------------------------------- /www/cgi-bin/fw-reset.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | page_title="Erasing Overlay" 5 | c="/usr/sbin/sysupgrade -s -n -x" 6 | r="true" 7 | %> 8 | 9 | <%in p/header.cgi %> 10 |

DO NOT CLOSE, REFRESH, OR NAVIGATE AWAY FROM THIS PAGE UNTIL THE PROCESS IS FINISHED!

11 |

12 | 
13 | 
17 | <%in p/footer.cgi %>
18 | 


--------------------------------------------------------------------------------
/www/cgi-bin/fw-restart.cgi:
--------------------------------------------------------------------------------
 1 | #!/usr/bin/haserl
 2 | Content-type: text/html; charset=UTF-8
 3 | Cache-Control: no-store
 4 | Pragma: no-cache
 5 | 
 6 | 
 7 | 
 8 | 
 9 | 	
10 | 	
11 | 	Restart - OpenIPC
12 | 	
13 | 	
41 | 
42 | 
43 | 
44 | 	
45 |

OpenIPC

46 |

Restarting. Please wait...

47 | 48 |
49 | 50 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /www/cgi-bin/fw-restore.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | [ -z "$GET_f" ] && set_error_flag "Nothing to restore." 5 | 6 | file=$GET_f 7 | [ ! -f "/rom/${file}" ] && set_error_flag "File /rom/${file} not found!" 8 | [ -n "$error" ] && redirect_back 9 | 10 | cp "/rom/${file}" "${file}" 11 | if [ $? -eq 0 ]; then 12 | redirect_back "success" "File ${file} restored to firmware defaults." 13 | else 14 | redirect_back "danger" "Cannot restore ${file}!" 15 | fi 16 | %> 17 | -------------------------------------------------------------------------------- /www/cgi-bin/fw-settings.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% page_title="Firmware Settings & Backuper" %> 4 | <%in p/header.cgi %> 5 | <% config_file=/etc/webui/backup.conf 6 | 7 | config_create() { # config_create 8 | echo " 9 | #=== OpenIPC webui backuper config, 10 | #=== <- this is comment line 11 | #=== FILES you need to backup, one per line, full path, line begins from # 12 | #/etc/webui/ 13 | #/etc/majestic.yaml 14 | #/etc/fstab 15 | #/usr/sbin/motion.sh 16 | 17 | #=== COMMANDS, one per liine, to be executed AFTER restoring from backup 18 | cli -s .audio.enabled true 19 | cli -s .audio.speakerPin 64 20 | cli -s .audio.codec opus 21 | cli -s .audio.srate 48000 22 | cli -s .audio.volume 40 23 | cli -s .audio.outputEnabled true 24 | cli -s .audio.outputVolume 80 25 | " > $config_file # config finish 26 | } 27 | if [ ! -f $config_file ]; then # check & create config_file 28 | config_create 29 | fi 30 | 31 | if [ "$REQUEST_METHOD" = "POST" ]; then 32 | case "$POST_action" in 33 | save) 34 | editor_text=$(echo "$POST_editor_text" | sed s/\\r//g) 35 | echo "$editor_text" > "$config_file" 36 | redirect_to "$SCRIPT_NAME" 37 | ;; 38 | esac 39 | 40 | redirect_to "$HTTP_REFERER" 41 | fi 42 | %> 43 | 44 |
45 |

Create backup remotely, e.g. from script:

46 |
wget --content-disposition http://root:12345@<%= $network_address %>/cgi-bin/ext-backuper.cgi?backup=create
47 |
48 | 49 |
50 |
51 |
52 |

Restart Camera

53 |

Reboot camera to apply new settings and reset temporary files.

54 | Restart Camera 55 |
56 |
57 |

Reset Firmware

58 |

Revert firmware to original state by resetting the overlay partition.

59 | Reset Firmware 60 |
61 |
62 | 63 |
64 |
65 |

Backup files

66 |

Create backup of files, listed in backuper configuration.

67 | Create Backup 68 |
69 |
70 |

Restore from a backup

71 |

Currently, only manual recovery is available.

72 |

To restore files from a previously created backup to the camera, follow these steps:

73 |

1. place the _backup_.tgz file in /tmp on the camera

74 |

2. run:
75 | cd / && zcat /tmp/_backup_.tgz | tar x --overwrite && sh /etc/webui/backup.conf

76 |

This action removes all current settings!

77 | 78 |
79 |
80 | 81 |
82 |

Backuper configuration

83 | <% [ -e "$config_file" ] && ex "cat $config_file" %> 84 |

Edit Configuration

85 |
86 |
87 |
88 | 89 | <%in p/footer.cgi %> 90 | -------------------------------------------------------------------------------- /www/cgi-bin/fw-system.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | page_title="System Upgrade" 5 | c="/usr/sbin/sysupgrade -s" 6 | [ "$POST_fw_kernel" = "true" ] && c="${c} -k" 7 | [ "$POST_fw_rootfs" = "true" ] && c="${c} -r" 8 | [ "$POST_fw_reboot" != "true" ] && c="${c} -x" 9 | [ "$POST_fw_reset" = "true" ] && c="${c} -n" 10 | [ "$POST_fw_force" = "true" ] && c="${c} --force_ver" 11 | %> 12 | 13 | <%in p/header.cgi %> 14 |

DO NOT CLOSE, REFRESH, OR NAVIGATE AWAY FROM THIS PAGE UNTIL THE PROCESS IS FINISHED!

15 |

16 | 
17 | 
21 | <%in p/footer.cgi %>
22 | 


--------------------------------------------------------------------------------
/www/cgi-bin/fw-time.cgi:
--------------------------------------------------------------------------------
  1 | #!/usr/bin/haserl
  2 | <%in p/common.cgi %>
  3 | <%
  4 | page_title="Time Settings"
  5 | tz_data=$(cat /etc/TZ)
  6 | tz_name=$(cat /etc/timezone)
  7 | 
  8 | if [ "$REQUEST_METHOD" = "POST" ]; then
  9 | 	case "$POST_action" in
 10 | 		update)
 11 | 			[ -z "$POST_tz_name" ] && redirect_to "$SCRIPT_NAME" "warning" "Empty timezone name. Skipping."
 12 | 			[ -z "$POST_tz_data" ] && redirect_to "$SCRIPT_NAME" "warning" "Empty timezone value. Skipping."
 13 | 			[ "$tz_data" != "$POST_tz_data" ] && echo "${POST_tz_data}" > /etc/TZ
 14 | 			[ "$tz_name" != "$POST_tz_name" ] && echo "${POST_tz_name}" > /etc/timezone
 15 | 
 16 | 			rm -f /etc/ntp.conf
 17 | 			for i in $(seq 0 3); do
 18 | 				eval ntp="\$POST_server_${i}"
 19 | 				[ -n "$ntp" ] && echo "server $ntp iburst" >> /etc/ntp.conf
 20 | 			done
 21 | 			redirect_back "success" "Configuration updated."
 22 | 			;;
 23 | 	esac
 24 | 
 25 | 	update_caminfo
 26 | 	redirect_to "$SCRIPT_NAME" "success" "Timezone updated."
 27 | fi
 28 | %>
 29 | 
 30 | <%in p/header.cgi %>
 31 | 
 32 | 	<% field_hidden "action" "update" %>
 33 | 	
34 |
35 |

Time Zone

36 | 37 |

38 | 39 | 40 | Type the name of the nearest large city. 41 |

42 |

43 | 44 | 45 | Control string of the timezone selected above. 46 |

47 |

Pick up timezone from browser

48 |
49 | 50 |
51 |

Synchronization

52 | <% 53 | for i in $(seq 0 3); do 54 | eval server_${i}=$(sed -n $((i + 1))p /etc/ntp.conf | awk '{print $2}') 55 | field_text "server_${i}" "Server $((i + 1))" 56 | done 57 | %> 58 |

Sync time

59 |
60 | 61 |
62 |

Configuration

63 | <% ex "cat /etc/timezone" %> 64 | <% ex "cat /etc/TZ" %> 65 | <% ex "cat /etc/ntp.conf" %> 66 |
67 |
68 | <% button_submit %> 69 | 70 | 71 | 72 | 130 | 131 | <%in p/footer.cgi %> 132 | -------------------------------------------------------------------------------- /www/cgi-bin/fw-update.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | page_title="Firmware Update" 5 | if [ -n "$network_gateway" ]; then 6 | fw_soc=$soc 7 | if [ "$soc_vendor" = "ingenic" ]; then 8 | fw_soc=$soc_family 9 | fi 10 | 11 | builder=$(fw_printenv -n upgrade) 12 | url="https://github.com/openipc/firmware/releases/download/latest/openipc.${fw_soc}-${flash_type}-${fw_variant}.tgz" 13 | ver=$(curl -m5 -ILs "${builder:-$url}" | grep Last-Modified | cut -d' ' -f2-) 14 | fi 15 | 16 | if [ -n "$ver" ]; then 17 | fw_date=$(date -D "%a, %d %b %Y %T GMT" +"$(date +%y | sed 's/.$/.&/').%m.%d" --date "$ver") 18 | else 19 | fw_date="- no access to GitHub -" 20 | fi 21 | 22 | fw_kernel="true" 23 | fw_rootfs="true" 24 | fw_reboot="true" 25 | %> 26 | <%in p/header.cgi %> 27 | 28 |
29 |
30 |

Version

31 |
32 |
Installed
33 |
<%= $fw_version %>
34 |
On GitHub
35 |
<%= $fw_date %>
36 |
37 |
38 | 39 |
40 |

Upgrade

41 | <% if [ -n "$ver" ]; then %> 42 |
43 | <% field_switch "fw_kernel" "Upgrade kernel." "eval" %> 44 | <% field_switch "fw_rootfs" "Upgrade rootfs." "eval" %> 45 | <% field_switch "fw_reboot" "Restart after upgrade." "eval" %> 46 | <% field_switch "fw_reset" "Reset firmware." "eval" %> 47 | <% field_switch "fw_force" "Reflash installed version." "eval" %> 48 | <% button_submit "Install update from GitHub" "warning" %> 49 |
50 | <% else %> 51 |

Updating requires access to GitHub.

52 | <% fi %> 53 |
54 |
55 | 56 | <%in p/footer.cgi %> 57 | -------------------------------------------------------------------------------- /www/cgi-bin/info-kernel.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% page_title="Kernel Messages" %> 4 | <%in p/header.cgi %> 5 | <% ex "dmesg" %> 6 | <%in p/footer.cgi %> 7 | -------------------------------------------------------------------------------- /www/cgi-bin/info-majestic.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% page_title="Majestic Messages" %> 4 | <%in p/header.cgi %> 5 | <% ex "logread | grep -o majestic.*" %> 6 | <%in p/footer.cgi %> 7 | -------------------------------------------------------------------------------- /www/cgi-bin/info-overlay.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | s=$(df | grep /overlay | xargs | cut -d' ' -f5) 5 | page_title="Overlay Partition" 6 | %> 7 | <%in p/header.cgi %> 8 |
9 |
Overlay partition is <%= $s %> full.
10 | <% progressbar "${s/%/}" %> 11 |
12 | <% ex "ls -Rl /overlay" %> 13 | <%in p/footer.cgi %> 14 | -------------------------------------------------------------------------------- /www/cgi-bin/j/locale.cgi: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | mj_audio=Audio 3 | mj_cloud=Cloud 4 | mj_hls=HLS 5 | mj_image=Image 6 | mj_ipeye=IPEYE 7 | mj_isp=ISP 8 | mj_jpeg=JPEG 9 | mj_motionDetect=Motion 10 | mj_netip=NETIP 11 | mj_nightMode=Night 12 | mj_onvif=ONVIF 13 | mj_osd=OSD 14 | mj_outgoing=Outgoing 15 | mj_records=Record 16 | mj_rtsp=RTSP 17 | mj_system=System 18 | mj_video0=Video0 19 | mj_video1=Video1 20 | mj_watchdog=Watchdog 21 | # mj_youtube=Youtube 22 | -------------------------------------------------------------------------------- /www/cgi-bin/j/locale_fpv.cgi: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | mj_audio=Audio 3 | mj_cloud=Cloud 4 | #mj_hls=HLS 5 | mj_image=Image 6 | #mj_ipeye=IPEYE 7 | mj_isp=ISP 8 | mj_jpeg=JPEG 9 | #mj_motionDetect=Motion 10 | #mj_netip=NETIP 11 | #mj_nightMode=Night 12 | #mj_onvif=ONVIF 13 | #mj_osd=OSD 14 | mj_outgoing=Outgoing 15 | mj_records=Record 16 | mj_rtsp=RTSP 17 | mj_system=System 18 | mj_video0=Video0 19 | mj_video1=Video1 20 | mj_watchdog=Watchdog 21 | # mj_youtube=Youtube 22 | -------------------------------------------------------------------------------- /www/cgi-bin/j/pulse.cgi: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | web=$(pidof majestic) 3 | temp=$(ipcinfo -t 2> /dev/null) 4 | 5 | if [ -n "$web" ]; then 6 | daynight_value=$(wget -q -T1 localhost/metrics/isp?value=isp_again -O -) 7 | fi 8 | 9 | if [ -n "$temp" ]; then 10 | soc_temp="${temp%.*}°C" 11 | fi 12 | 13 | mem_total=$(awk '/MemTotal/ {print $2}' /proc/meminfo) 14 | mem_free=$(awk '/MemFree/ {print $2}' /proc/meminfo) 15 | mem_used=$(( 100 - (mem_free / (mem_total / 100)) )) 16 | overlay_used=$(df | grep /overlay | xargs | cut -d' ' -f5) 17 | uptime=$(awk '{m=$1/60; h=m/60; printf "%sd %sh %sm %ss\n", int(h/24), int(h%24), int(m%60), int($1%60) }' /proc/uptime) 18 | payload=$(printf '{"soc_temp":"%s","time_now":"%s","timezone":"%s","mem_used":"%d","overlay_used":"%d","daynight_value":"%d","uptime":"%s"}' \ 19 | "${soc_temp}" "$(date +%s)" "$(cat /etc/timezone)" "${mem_used}" "${overlay_used//%/}" "${daynight_value:=-1}" "$uptime") 20 | 21 | echo "HTTP/1.1 200 OK 22 | Content-type: application/json 23 | Pragma: no-cache 24 | 25 | ${payload} 26 | " 27 | -------------------------------------------------------------------------------- /www/cgi-bin/j/run.cgi: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | echo "HTTP/1.1 200 OK 3 | Content-type: text/html; charset=UTF-8 4 | Cache-Control: no-store 5 | Pragma: no-cache 6 | " 7 | 8 | [ -n "$QUERY_STRING" ] && eval $(echo "$QUERY_STRING" | sed "s/&/;/g") 9 | [ -n "$cmd" ] && c=$(echo $cmd | base64 -d) 10 | [ -n "$web" ] && c=$(echo $web | base64 -d) && t="timeout 3" 11 | [ -z "$c" ] && echo "No command!" && exit 1 12 | 13 | prompt() { 14 | echo "$(whoami)@$(hostname):$PWD# ${1}" 15 | } 16 | 17 | export PATH=/usr/local/bin:/usr/local/sbin:/bin:/sbin:/usr/bin:/usr/sbin 18 | cd /tmp || return 19 | 20 | prompt "$c" 21 | eval "$t $c" 2>&1 22 | prompt 23 | 24 | exit 0 25 | -------------------------------------------------------------------------------- /www/cgi-bin/j/time.cgi: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | if ntpd -n -q -N; then 3 | payload='{"result":"success","message":"Camera time synchronized with NTP server."}' 4 | else 5 | payload='{"result":"danger","message":"Synchronization failed!"}' 6 | fi 7 | 8 | echo "HTTP/1.1 200 OK 9 | Content-type: application/json 10 | Pragma: no-cache 11 | 12 | ${payload} 13 | " 14 | -------------------------------------------------------------------------------- /www/cgi-bin/mj-configuration.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% page_title="Majestic Configuration" %> 4 | <%in p/header.cgi %> 5 | 6 |
7 | <% ex "cat $(get_config)" %> 8 |
9 | <% 10 | diff $(get_config /rom) $(get_config) > /tmp/majestic.patch 11 | ex "cat /tmp/majestic.patch" 12 | %> 13 | 17 |
18 |
19 | 20 | <%in p/footer.cgi %> 21 | -------------------------------------------------------------------------------- /www/cgi-bin/mj-endpoints.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% page_title="Majestic Endpoints" %> 4 | 5 | <%in p/header.cgi %> 6 | 7 |
8 |
9 |

Video

10 |
11 |
rtsp://root:12345@<%= $network_address %>/stream=0
12 |
RTSP main stream.
13 |
rtsp://root:12345@<%= $network_address %>/stream=1
14 |
RTSP sub stream.
15 |
rtsp://root:12345@<%= $network_address %>/stream=2
16 |
RTSP JPEG stream.
17 |
http://<%= $network_address %>/mjpeg
18 |
MJPEG video stream.
19 |
http://<%= $network_address %>/video.mp4
20 |
MP4 video stream.
21 |
http://<%= $network_address %>/hls
22 |
HLS live-streaming in web browser.
23 |
http://<%= $network_address %>/mjpeg.html
24 |
MJPEG live-streaming in web browser.
25 |
26 |
27 | 28 |
29 |

Audio

30 |
31 |
http://<%= $network_address %>/audio.opus
32 |
Opus audio stream.
33 |
http://<%= $network_address %>/audio.m4a
34 |
AAC audio stream.
35 |
http://<%= $network_address %>/audio.pcm
36 |
Raw PCM audio stream.
37 |
http://<%= $network_address %>/audio.alaw
38 |
A-law compressed audio stream.
39 |
http://<%= $network_address %>/audio.ulaw
40 |
μ-law compressed audio stream.
41 |
http://<%= $network_address %>/audio.g711a
42 |
G.711 A-law audio stream.
43 |
http://<%= $network_address %>/play_audio
44 |
Play audio file on camera speaker.
45 |
46 |
47 | 48 |
49 |

Images

50 |
51 |
http://<%= $network_address %>/image.jpg
52 |
Snapshot in JPEG format.
53 |
http://<%= $network_address %>/image.heif
54 |
Snapshot in HEIF format.
55 |
http://<%= $network_address %>/image.yuv420
56 |
Snapshot in YUV420 format.
57 |
58 |
59 | 60 |
61 |

Night

62 |
63 |
http://<%= $network_address %>/night/on
64 |
Turn on night mode.
65 |
http://<%= $network_address %>/night/off
66 |
Turn off night mode.
67 |
http://<%= $network_address %>/night/toggle
68 |
Toggle night mode.
69 |
http://<%= $network_address %>/night/ircut
70 |
Toggle camera ircut.
71 |
http://<%= $network_address %>/night/light
72 |
Toggle camera light.
73 |
74 |
75 | 76 |
77 |

Monitoring

78 |
79 |
http://<%= $network_address %>/api/v1/config.json
80 |
Default Majestic config in JSON format.
81 |
http://<%= $network_address %>/api/v1/config.schema.json
82 |
Available Majestic settings in JSON format.
83 |
https://github.com/openipc/wiki
84 |
Available Majestic settings in YAML format.
85 |
http://<%= $network_address %>/metrics
86 |
Node exporter for Prometheus.
87 |
88 |
89 |
90 | 91 | 122 | <%in p/footer.cgi %> 123 | -------------------------------------------------------------------------------- /www/cgi-bin/mj-settings.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | 4 | <% 5 | page_title="Majestic Settings" 6 | label="$GET_tab" 7 | [ -z "$label" ] && label="system" 8 | 9 | json_conf=$(wget -q -T1 localhost/api/v1/config.json -O -) 10 | json_schema=$(cat $(get_schema) | jsonfilter -e "@.properties.$label") 11 | json_load "$json_schema" 12 | 13 | if [ "$REQUEST_METHOD" = "POST" ]; then 14 | case "$POST_action" in 15 | restart) 16 | killall -1 majestic 17 | ;; 18 | 19 | update) 20 | OIFS=$IFS 21 | IFS=$'\n' 22 | for yaml_param in $(printenv | grep POST__ | sort); do 23 | param=$(echo ${yaml_param#POST_} | cut -d= -f1) 24 | newval=$(echo ${yaml_param#POST_} | cut -d= -f2) 25 | setting=${param//_/.} 26 | oldval=$(yaml-cli -g "$setting") 27 | 28 | if [ -z "$newval" ] && [ -n "$oldval" ]; then 29 | yaml-cli -d "$setting" 30 | elif [ "$newval" != "$oldval" ]; then 31 | yaml-cli -s "$setting" "$newval" 32 | fi 33 | done 34 | IFS=$OIFS 35 | ;; 36 | esac 37 | 38 | redirect_to "$HTTP_REFERER" 39 | fi 40 | %> 41 | 42 | <%in p/header.cgi %> 43 | 44 | <% if [ -z "$(pidof majestic)" ]; then %> 45 | 46 |
47 |

Majestic is not running.

48 |

Go to https://wiki.openipc.org for more information.

49 |
50 | 51 | <% else %> 52 | 53 | 67 | 68 | <% if [ -n "$title" ]; then %> 69 | 70 |
71 |
72 |

<%= $title %>

73 |
74 |
75 | <% 76 | json_select "properties" 77 | json_get_keys "keys" 78 | for key in $keys; do 79 | json_select "$key" 80 | json_get_var "desc" "description" 81 | json_get_var "type" "type" 82 | json_get_values "enum" "enum" 83 | json_get_var "min" "minimum" 84 | json_get_var "max" "maximum" 85 | json_select .. 86 | 87 | param="_${label}_${key}" 88 | setting=${param//_/.} 89 | [ -e j/exclude.lst ] && grep -q "$setting" j/exclude.lst && continue 90 | value=$(yaml-cli -g "$setting") 91 | default=${value:-$(echo "$json_conf" | jsonfilter -e "@$setting")} 92 | config="${config}\n$(echo $setting: $value)" 93 | 94 | case "$type" in 95 | boolean) 96 | field_switch "$param" "$desc" "$default" 97 | ;; 98 | 99 | integer) 100 | if [ -n "$max" ] && [ "$max" -le "100" ]; then 101 | field_range "$param" "$desc" "$default" "$min" "$max" 102 | else 103 | field_integer "$param" "$desc" "$default" "$min" "$max" 104 | fi 105 | ;; 106 | 107 | string) 108 | field_string "$param" "$desc" "$default" "$enum" 109 | ;; 110 | esac 111 | done 112 | %> 113 | 114 | <% button_submit %> 115 |
116 | 117 |
118 | 119 | <% button_submit "Restart Majestic" "secondary" %> 120 |
121 |
122 |
123 | 124 |
125 |

Related Settings

126 |
<% echo -e "$config" %>
127 |
128 | 129 |
130 |

Quick Links

131 |

Majestic Configuration

132 |

Majestic Endpoints

133 |
134 |
135 | 136 | <% if [ "$label" = "motionDetect" ]; then %> 137 | <%in p/roi.cgi %> 138 | <% fi %> 139 | 140 | <% else %> 141 | 142 |
143 |

Setting is not available.

144 |

Majestic Settings

145 |
146 | 147 | <% fi %> 148 | <% fi %> 149 | 150 | 169 | 170 | <%in p/footer.cgi %> 171 | -------------------------------------------------------------------------------- /www/cgi-bin/p/address.cgi: -------------------------------------------------------------------------------- 1 |

This camera uses MAC address 00:00:23:34:45:66 which is a placeholder.

2 |

You need to replace it with the original MAC address from your stock firmware backup or generate a random valid MAC address.

3 |
4 | 5 |
6 |
7 |
8 |
9 |

Please note that the new MAC address will most likely give the camera a new IP address assigned by the DHCP server!

10 | 11 | 39 | -------------------------------------------------------------------------------- /www/cgi-bin/p/common.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <% 3 | IFS_ORIG=$IFS 4 | 5 | # tag "text" "classes" "extras" 6 | div() { 7 | tag "div" "$1" "$2" "$3" 8 | } 9 | 10 | # tag "tag" "text" "css" "extras" 11 | tag() { 12 | local t="$1" 13 | local n="$2" 14 | local c="$3" 15 | [ -n "$c" ] && c=" class=\"${c}\"" 16 | local x="$4" 17 | [ -n "$x" ] && x=" ${x}" 18 | echo "<${t}${c}${x}>${n}" 19 | } 20 | 21 | # A "tag" "classes" "extras" 22 | A() { 23 | local c="$2" 24 | [ -n "$c" ] && c=" class=\"${c}\"" 25 | local x="$3" 26 | [ -n "$x" ] && x=" ${x}" 27 | echo "<${1}${c}${x}>" 28 | } 29 | 30 | Z() { 31 | echo "" 32 | } 33 | 34 | d() { 35 | echo "$1" >&2 36 | } 37 | 38 | e() { 39 | echo -e -n "$1" 40 | } 41 | 42 | h1() { 43 | tag "h1" "$1" "$2" "$3" 44 | } 45 | 46 | h2() { 47 | tag "h2" "$1" "$2" "$3" 48 | } 49 | 50 | h3() { 51 | tag "h3" "$1" "$2" "$3" 52 | } 53 | 54 | h4() { 55 | tag "h4" "$1" "$2" "$3" 56 | } 57 | 58 | h5() { 59 | tag "h5" "$1" "$2" "$3" 60 | } 61 | 62 | h6() { 63 | tag "h6" "$1" "$2" "$3" 64 | } 65 | 66 | label() { 67 | tag "label" "$1" "$2" "$3" 68 | } 69 | 70 | li() { 71 | tag "li" "$1" "$2" "$3" 72 | } 73 | 74 | p() { 75 | tag "p" "$1" "$2" "$3" 76 | } 77 | 78 | span() { 79 | tag "span" "$1" "$2" "$3" 80 | } 81 | 82 | div_() { 83 | A "div" "$1" "$2" 84 | } 85 | 86 | _div() { 87 | Z "div" 88 | } 89 | 90 | row_() { 91 | echo "
" 92 | } 93 | 94 | _row() { 95 | echo "
" 96 | } 97 | 98 | row() { 99 | row_ "$2" 100 | echo "$1" 101 | _row 102 | } 103 | 104 | span_() { 105 | A "span" "$1" "$2" 106 | } 107 | 108 | _span() { 109 | Z "span" 110 | } 111 | 112 | # alert "text" "type" "extras" 113 | alert() { 114 | echo "
${1}
" 115 | } 116 | 117 | # button_submit "text" "type" "extras" 118 | button_submit() { 119 | local t="$1" 120 | [ -z "$t" ] && t="Save Changes" 121 | local c="$2" 122 | [ -z "$c" ] && c="primary" 123 | local x="$3" 124 | [ -z "$x" ] && x=" ${x}" 125 | echo "
" 126 | } 127 | 128 | check_password() { 129 | local p="/cgi-bin/fw-interface.cgi" 130 | [ -z "$SCRIPT_NAME" ] || [ "$SCRIPT_NAME" = "${p}" ] && return 131 | if [ ! -f /etc/shadow- ] || [ -z $(grep root /etc/shadow- | cut -d: -f2) ]; then 132 | redirect_to "${p}" "danger" "You must set your own secure password!" 133 | fi 134 | } 135 | 136 | ex() { 137 | echo "
# ${1}
"
138 | 	eval "$1" | sed "s/&/\&/g;s//\>/g;s/\"/\"/g"
139 | 	echo "
" 140 | } 141 | 142 | # field_hidden "name" "value" 143 | field_hidden() { 144 | local n="$1" 145 | local v="$2" 146 | echo "" 147 | } 148 | 149 | # field_integer "name" "label" "value" "min" "max" "hint" 150 | field_integer() { 151 | local n="$1" 152 | local l="$2" 153 | local v="$3" 154 | local x="$4" 155 | local y="$5" 156 | local h="$6" 157 | echo "

" \ 158 | "" \ 159 | "" 160 | echo "" \ 161 | "" 162 | [ -n "$h" ] && echo "${h}" 163 | echo "

" 164 | } 165 | 166 | # field_password "name" "label" "hint" 167 | field_password() { 168 | local n="$1" 169 | local l="$2" 170 | local h="$3" 171 | local v=$(t_value "$n") 172 | echo "

" \ 173 | "" \ 174 | "" \ 175 | "" 178 | [ -n "$h" ] && echo "${h}" 179 | echo "

" 180 | } 181 | 182 | # field_range "name" "label" "value" "min" "max" "hint" 183 | field_range() { 184 | local n="$1" 185 | local l="$2" 186 | local v="$3" 187 | local x="$4" 188 | local y="$5" 189 | local h="$6" 190 | echo "

" \ 191 | "" \ 192 | "" 193 | echo "" 194 | echo "" 195 | echo "${v}" 196 | [ -n "$h" ] && echo "${h}" 197 | echo "

" 198 | } 199 | 200 | # field_switch "name" "label" "value" "hint" 201 | field_switch() { 202 | local n="$1" 203 | local l="$2" 204 | local v="$3" 205 | local h="$4" 206 | [ "$v" = "eval" ] && v=$(t_value "$n") 207 | [ "$v" = "true" ] && v="checked" 208 | echo "

" \ 209 | "" \ 210 | "" \ 211 | "" 212 | [ -n "$h" ] && echo "${h}" 213 | echo "

" 214 | } 215 | 216 | # field_string "name" "label" "value" "enum" "hint" 217 | field_string() { 218 | local n="$1" 219 | local l="$2" 220 | local v="$3" 221 | local e="$4" 222 | local h="$5" 223 | [ "$v" = "eval" ] && v=$(t_value "$n") 224 | if [ -n "$e" ]; then 225 | echo "

" \ 226 | "" \ 227 | "" 234 | else 235 | echo "

" \ 236 | "" \ 237 | "" 238 | fi 239 | [ -n "$h" ] && echo "${h}" 240 | echo "

" 241 | } 242 | 243 | # field_text "name" "label" "hint" 244 | field_text() { 245 | local n="$1" 246 | local l="$2" 247 | local h="$3" 248 | local v=$(t_value "$n") 249 | echo "

" \ 250 | "" \ 251 | "" 252 | [ -n "$h" ] && echo "${h}" 253 | echo "

" 254 | } 255 | 256 | # field_textedit "name" "label" "file" 257 | field_textedit() { 258 | local n="$1" 259 | local l="$2" 260 | local v=$(cat "$3") 261 | echo "

" \ 262 | "" \ 263 | "" 264 | echo "

" 265 | } 266 | 267 | get_config() { 268 | echo ${1}/etc/majestic.yaml 269 | } 270 | 271 | get_metrics() { 272 | local m=$(pidof majestic) 273 | if [ -z "$m" ]; then 274 | echo 0 275 | else 276 | wget -q -T1 localhost/metrics/night?value=${1} -O - 277 | fi 278 | } 279 | 280 | get_schema() { 281 | local m=/tmp/webui/schema.json 282 | if [ ! -e "$m" ]; then 283 | wget -q -T1 localhost/api/v1/config.schema.json -O "$m" 284 | fi 285 | echo "$m" 286 | } 287 | 288 | get_night() { 289 | local m=$(pidof majestic) 290 | local v=$(yaml-cli -g .nightMode.$1) 291 | if [ -n "$m" ] && [ -n "$v" ] && [ "$v" != "false" ]; then 292 | echo true 293 | else 294 | echo false 295 | fi 296 | } 297 | 298 | log_create() { 299 | echo "${1}:${2}" > "$log_file" 300 | } 301 | 302 | log_read() { 303 | [ ! -f "$log_file" ] && return 304 | [ -z "$(cat $log_file)" ] && return 305 | local c 306 | local m 307 | local l 308 | OIFS="$IFS" 309 | IFS=$'\n' 310 | for l in $(cat "$log_file"); do 311 | c="$(echo $l | cut -d':' -f1)" 312 | m="$(echo $l | cut -d':' -f2-)" 313 | echo "
${m}" \ 314 | "" \ 315 | "
" 316 | done 317 | IFS=$OIFS 318 | rm -f "$log_file" 319 | } 320 | 321 | set_error_flag() { 322 | echo "danger:${1}" >> "$log_file" 323 | error=1 324 | } 325 | 326 | html_title() { 327 | [ -n "$page_title" ] && echo -n "$page_title" 328 | [ -n "$title" ] && echo -n ": $title" 329 | echo -n " - OpenIPC" 330 | } 331 | 332 | include() { 333 | [ -f "$1" ] && . "$1" 334 | } 335 | 336 | # label "name" "classes" "extras" "units" 337 | label() { 338 | local c="form-label" 339 | [ -n "$2" ] && c="${c} ${2}" 340 | local l="$(t_label "$1")" 341 | [ -z "$l" ] && l="$1" && c="${c} bg-warning" 342 | local x="$3" 343 | [ -n "$x" ] && x=" ${x}" 344 | local u="$4" 345 | [ -n "$u" ] && l="${l}, $u" 346 | echo "" 347 | } 348 | 349 | # pre "text" "classes" "extras" 350 | pre() { 351 | # replace <, >, &, ", and ' with HTML entities 352 | tag "pre" "$(echo -e "$1" | sed "s/&/\&/g;s//\>/g;s/\"/\"/g")" "$2" "$3" 353 | } 354 | 355 | preview() { 356 | if [ "true" = "$(yaml-cli -g .jpeg.enabled)" ]; then 357 | echo "" 358 | else 359 | echo "

Enable JPEG support to see the preview.

" 360 | fi 361 | } 362 | 363 | progressbar() { 364 | local c="primary" 365 | [ "$1" -ge "75" ] && c="danger" 366 | echo "
" \ 367 | "
" \ 368 | "
" 369 | } 370 | 371 | # redirect_back "flash class" "flash text" 372 | redirect_back() { 373 | redirect_to "${HTTP_REFERER:-/}" "$1" "$2" 374 | } 375 | 376 | # redirect_to "url" "flash class" "flash text" 377 | redirect_to() { 378 | [ -n "$3" ] && log_create "$2" "$3" 379 | echo "HTTP/1.1 303 See Other" 380 | echo "Content-type: text/html; charset=UTF-8" 381 | echo "Cache-Control: no-store" 382 | echo "Pragma: no-cache" 383 | echo "Location: $1" 384 | echo 385 | exit 0 386 | } 387 | 388 | report_command() { 389 | echo "

# ${1}

" 390 | echo "
${2}
" 391 | } 392 | 393 | report_error() { 394 | echo "

Oops. Something happened.

" 395 | alert "$1" "danger" 396 | } 397 | 398 | # report_log "text" "extras" 399 | report_log() { 400 | pre "$1" "small" "$2" 401 | } 402 | 403 | generate_signature() { 404 | echo "${soc} (${soc_family} family), $sensor, ${flash_size} MB ${flash_type} flash, ${fw_version}-${fw_variant}, ${network_hostname}, ${network_macaddr}" > $signature_file 405 | } 406 | 407 | signature() { 408 | [ ! -f "$signature_file" ] && generate_signature 409 | cat $signature_file 410 | } 411 | 412 | t_label() { 413 | eval "echo \$tL_${1}" 414 | } 415 | 416 | t_value() { 417 | eval "echo \$${1}" 418 | } 419 | 420 | update_caminfo() { 421 | flash_type=$(ipcinfo --flash-type) 422 | mtd_size=$(grep -E "nor|nand" $(ls /sys/class/mtd/mtd*/type) | sed -E "s|type.+|size|g") 423 | flash_size=$(awk '{sum+=$1} END{print sum/1024/1024}' $mtd_size) 424 | 425 | sensor=$(fw_printenv -n sensor) 426 | [ -z "$sensor" ] && sensor="unknown" 427 | 428 | soc_vendor=$(ipcinfo --vendor) 429 | soc_family=$(ipcinfo --family) 430 | 431 | soc=$(ipcinfo --chip-name) 432 | if [ -z "$soc" ] || [ "$soc_vendor" = "sigmastar" ]; then 433 | soc=$(fw_printenv -n soc) 434 | fi 435 | 436 | soc_temp=$(ipcinfo --temp 2> /dev/null) 437 | if [ -n "$soc_temp" ]; then 438 | soc_has_temp="true" 439 | else 440 | soc_has_temp="false" 441 | fi 442 | 443 | # Firmware 444 | fw_version=$(grep "OPENIPC_VERSION" /etc/os-release | cut -d= -f2 | tr -d '"') 445 | fw_variant=$(grep "BUILD_OPTION" /etc/os-release | cut -d= -f2 | tr -d '"') 446 | fw_build=$(grep "GITHUB_VERSION" /etc/os-release | cut -d= -f2 | tr -d '"') 447 | mj_version=$($mj_bin_file -v) 448 | uboot_version=$(fw_printenv -n ver) 449 | 450 | # WebUI 451 | ui_password=$(grep root /etc/shadow | cut -d: -f2) 452 | ptz_support=$(fw_printenv -n ptz) 453 | 454 | # Network 455 | network_interface=$(ip route | awk '/default/ {print $5}' | head -n1) 456 | network_address=$(ip route | grep ${network_interface:-eth0} | awk '/src/ {print $7}') 457 | network_gateway=$(ip route | awk '/default/ {print $3}') 458 | network_hostname=$(hostname -s) 459 | network_macaddr=$(cat /sys/class/net/${network_interface:-eth0}/address) 460 | 461 | # Overlay 462 | overlay_root="/overlay" 463 | 464 | # Default timezone is GMT 465 | tz_data=$(cat /etc/TZ) 466 | tz_name=$(cat /etc/timezone) 467 | if [ -z "$tz_data" ] || [ -z "$tz_name" ]; then 468 | tz_data="GMT0"; echo "$tz_data" > /etc/TZ 469 | tz_name="Etc/GMT"; echo "$tz_name" > /etc/timezone 470 | fi 471 | 472 | local variables="flash_size flash_type fw_build fw_variant fw_version mj_version network_address 473 | network_gateway network_hostname network_interface network_macaddr overlay_root ptz_support 474 | sensor soc soc_family soc_has_temp soc_vendor tz_data tz_name uboot_version ui_password" 475 | rm -f ${sysinfo_file} 476 | 477 | local v 478 | for v in $variables; do 479 | eval "echo ${v}=\'\$${v}\' >> ${sysinfo_file}" 480 | done 481 | 482 | generate_signature 483 | } 484 | 485 | mj_bin_file=/usr/bin/majestic 486 | log_file=/tmp/webui/logfile.txt 487 | signature_file=/tmp/webui/signature.txt 488 | sysinfo_file=/tmp/webui/sysinfo.txt 489 | 490 | [ ! -d /etc/webui ] && mkdir -p /etc/webui 491 | [ ! -d /tmp/webui ] && mkdir -p /tmp/webui 492 | 493 | [ ! -f $sysinfo_file ] && update_caminfo 494 | include $sysinfo_file 495 | 496 | pagename=$(basename "$SCRIPT_NAME") 497 | pagename="${pagename%%.*}" 498 | 499 | include /etc/webui/webui.conf 500 | include /usr/share/libubox/jshn.sh 501 | 502 | check_password 503 | %> 504 | -------------------------------------------------------------------------------- /www/cgi-bin/p/footer.cgi: -------------------------------------------------------------------------------- 1 | 2 | 3 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /www/cgi-bin/p/fpv_common.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <% 3 | # fpv_common.cgi 4 | # Haserl CGI script for handling OpenIPC configuration 5 | # Supports both YAML configuration and legacy conf files 6 | 7 | # Debug logging function 8 | log_debug() { 9 | if [ "${CONFIG_DEBUG:-0}" = "1" ]; then 10 | echo "[CONFIG-UTILS] $1" >> /tmp/config-utils.log 11 | fi 12 | } 13 | 14 | # Enable debug by setting CONFIG_DEBUG=1 15 | CONFIG_DEBUG=${CONFIG_DEBUG:-0} 16 | 17 | # Config file locations 18 | WFB_YAML="/etc/wfb.yaml" 19 | WFB_CONF="/etc/wfb.conf" 20 | TELEMETRY_CONF="/etc/telemetry.conf" 21 | DATALINK_CONF="/etc/datalink.conf" 22 | MAJESTIC_YAML="/etc/majestic.yaml" 23 | 24 | # Ensure directory exists 25 | ensure_directory() { 26 | local dir_path="$1" 27 | 28 | # Check if directory exists 29 | if [ ! -d "$dir_path" ]; then 30 | # Create directory if it doesn't exist 31 | mkdir -p "$dir_path" 32 | 33 | # Return success/failure 34 | if [ $? -eq 0 ]; then 35 | log_debug "Directory created: $dir_path" 36 | return 0 37 | else 38 | log_debug "Failed to create directory: $dir_path" 39 | return 1 40 | fi 41 | else 42 | # Directory already exists 43 | log_debug "Directory already exists: $dir_path" 44 | return 0 45 | fi 46 | } 47 | 48 | # Check if we're using the YAML or legacy configuration 49 | is_using_yaml() { 50 | if [ -f "$WFB_YAML" ]; then 51 | log_debug "Using YAML configuration (wfb.yaml exists)" 52 | return 0 # True in shell 53 | else 54 | log_debug "Using legacy configuration (wfb.conf)" 55 | return 1 # False in shell 56 | fi 57 | } 58 | 59 | # Get config value - automatically determines source and handles both YAML and conf formats 60 | get_config_value() { 61 | local key="$1" 62 | local default_value="$2" 63 | local value="" 64 | 65 | log_debug "Getting config value for key: $key" 66 | 67 | if is_using_yaml; then 68 | # Get from YAML 69 | value=$(yaml_get_value "$WFB_YAML" "$key") 70 | else 71 | # Try to get from legacy conf files 72 | case "$key" in 73 | # WFB settings 74 | unit|wlan|region|channel|frequency|txpower|driver_txpower_override|bandwidth|stbc|ldpc|mcs_index|stream|link_id|udp_port|rcv_buf|frame_type|fec_k|fec_n|pool_timeout|guard_interval) 75 | value=$(legacy_get_value "$WFB_CONF" "$key") 76 | ;; 77 | 78 | # Telemetry settings 79 | serial|baud|router|stream_rx|stream_tx|port_rx|port_tx|one_way|aggregate|channels|fps|ahi) 80 | value=$(legacy_get_value "$TELEMETRY_CONF" "$key") 81 | ;; 82 | 83 | # Datalink settings 84 | daemon|telemetry|tunnel|usb_modem|gs_ipaddr|gs_port|use_zt|zt_netid) 85 | value=$(legacy_get_value "$DATALINK_CONF" "$key") 86 | ;; 87 | 88 | # Majestic settings - these would normally come from majestic.yaml but covering legacy case 89 | bitrate|resolution|*) 90 | # Default case - try each file 91 | value=$(legacy_get_value "$WFB_CONF" "$key") 92 | 93 | if [ -z "$value" ]; then 94 | value=$(legacy_get_value "$TELEMETRY_CONF" "$key") 95 | fi 96 | 97 | if [ -z "$value" ]; then 98 | value=$(legacy_get_value "$DATALINK_CONF" "$key") 99 | fi 100 | ;; 101 | esac 102 | fi 103 | 104 | # Return the found value or default 105 | if [ -n "$value" ]; then 106 | echo "$value" 107 | else 108 | echo "$default_value" 109 | fi 110 | } 111 | 112 | # Set a configuration value for a given key 113 | set_config_value() { 114 | local key="$1" 115 | local value="$2" 116 | 117 | log_debug "Setting config value for key: $key = $value" 118 | 119 | if is_using_yaml; then 120 | # Set in YAML 121 | yaml_set_value "$WFB_YAML" "$key" "$value" 122 | else 123 | # Set in legacy conf files 124 | case "$key" in 125 | # WFB settings 126 | unit|wlan|region|channel|frequency|txpower|driver_txpower_override|bandwidth|stbc|ldpc|mcs_index|stream|link_id|udp_port|rcv_buf|frame_type|fec_k|fec_n|pool_timeout|guard_interval) 127 | legacy_set_value "$WFB_CONF" "$key" "$value" 128 | ;; 129 | 130 | # Telemetry settings 131 | serial|baud|router|stream_rx|stream_tx|port_rx|port_tx|one_way|aggregate|channels|fps|ahi) 132 | legacy_set_value "$TELEMETRY_CONF" "$key" "$value" 133 | ;; 134 | 135 | # Datalink settings 136 | daemon|telemetry|tunnel|usb_modem|gs_ipaddr|gs_port|use_zt|zt_netid) 137 | legacy_set_value "$DATALINK_CONF" "$key" "$value" 138 | ;; 139 | 140 | # Majestic settings or unknown - add to WFB 141 | *) 142 | legacy_set_value "$WFB_CONF" "$key" "$value" 143 | ;; 144 | esac 145 | fi 146 | } 147 | 148 | # Check if yaml-cli exists 149 | has_yaml_cli() { 150 | command -v yaml-cli >/dev/null 2>&1 151 | } 152 | 153 | # Check if wifibroadcast cli exists 154 | has_wifibroadcast_cli() { 155 | command -v wifibroadcast >/dev/null 2>&1 156 | } 157 | 158 | # Retrieve a value from a YAML file 159 | yaml_get_value() { 160 | local file="$1" 161 | local key="$2" 162 | local item="$3" 163 | 164 | # Create file if it doesn't exist 165 | if [ ! -f "$file" ]; then 166 | ensure_directory "$(dirname "$file")" 167 | touch "$file" 168 | return 1 169 | fi 170 | 171 | if has_wifibroadcast_cli; then 172 | # Use wifibroadcast cli with dot notation 173 | log_debug "using **** get YAML value using wifibroadcast cli, key: $key, item: $item" 174 | wifibroadcast cli -g ".$key.$item" 2>/dev/null 175 | else 176 | # Fallback to basic implementation for basic YAML using grep/sed 177 | log_debug "yaml-cli not available, using fallback method" 178 | grep "^$key:" "$file" 2>/dev/null | sed 's/^[^:]*:[[:space:]]*//' 179 | fi 180 | } 181 | 182 | # Set a value in a YAML file 183 | yaml_set_value() { 184 | local file="$1" 185 | local key="$2" 186 | local item="$3" 187 | local value="$4" 188 | 189 | # Create file if it doesn't exist 190 | if [ ! -f "$file" ]; then 191 | ensure_directory "$(dirname "$file")" 192 | touch "$file" 193 | fi 194 | 195 | if has_wifibroadcast_cli; then 196 | # Use yaml-cli to set value 197 | log_debug "***** Set YAML value using wifibroadcast: $key = $value" 198 | wifibroadcast cli -s ".$key.$item" "$value" 2>/dev/null 199 | else 200 | # Fallback to basic implementation 201 | log_debug "yaml-cli not available, using fallback method" 202 | 203 | # Check if key exists 204 | if grep -q "^$key:" "$file" 2>/dev/null; then 205 | # Update existing value 206 | sed -i "s|^$key:.*|$key: $value|" "$file" 207 | else 208 | # Add new key-value pair 209 | echo "$key: $value" >> "$file" 210 | fi 211 | fi 212 | } 213 | 214 | # Read a value from legacy conf file (key=value format) 215 | legacy_get_value() { 216 | local file="$1" 217 | local key="$2" 218 | 219 | [ -f "$file" ] || return 1 220 | 221 | # Handle comments and extract value 222 | grep "^[[:space:]]*$key=" "$file" 2>/dev/null | \ 223 | grep -v "^#" | cut -d'=' -f2- | head -n 1 224 | } 225 | 226 | # Set a value in legacy conf file (key=value format) 227 | legacy_set_value() { 228 | local file="$1" 229 | local key="$2" 230 | local value="$3" 231 | 232 | # Create file if it doesn't exist 233 | if [ ! -f "$file" ]; then 234 | ensure_directory "$(dirname "$file")" 235 | touch "$file" 236 | fi 237 | 238 | if grep -q "^[[:space:]]*$key=" "$file" 2>/dev/null; then 239 | # Update existing value 240 | sed -i "s|^[[:space:]]*$key=.*|$key=$value|" "$file" 241 | else 242 | # Add new key-value pair 243 | echo "$key=$value" >> "$file" 244 | fi 245 | } 246 | 247 | # Apply preset file 248 | apply_preset_file() { 249 | local preset_file="$1" # Source file from preset 250 | local target_file="$2" # Destination system config 251 | local file_type="$3" # yaml or conf 252 | 253 | log_debug "Applying preset file: $preset_file to $target_file (type: $file_type)" 254 | 255 | # Ensure target directory exists 256 | local target_dir=$(dirname "$target_file") 257 | ensure_directory "$target_dir" 258 | 259 | # If target file doesn't exist, just copy it 260 | if [ ! -f "$target_file" ]; then 261 | cp "$preset_file" "$target_file" 262 | return $? 263 | fi 264 | 265 | # Apply based on file type 266 | case "$file_type" in 267 | yaml) 268 | # For YAML files 269 | if has_yaml_cli; then 270 | log_debug "Using yaml-cli to merge preset YAML" 271 | 272 | # We need to process the yaml file key by key using yaml-cli 273 | # First get all top-level keys from the preset file 274 | tmp_keys=$(mktemp) 275 | grep -E '^[a-zA-Z0-9_-]+:' "$preset_file" | sed 's/:.*//' > "$tmp_keys" 276 | 277 | # Apply each key 278 | while read -r key; do 279 | value=$(yaml-cli --get "$key" --input "$preset_file" 2>/dev/null) 280 | if [ -n "$value" ]; then 281 | yaml-cli --set "$key=$value" --input "$target_file" --output "$target_file" 2>/dev/null 282 | log_debug "Applied setting $key=$value from preset to target YAML" 283 | fi 284 | done < "$tmp_keys" 285 | 286 | rm -f "$tmp_keys" 287 | else 288 | log_debug "yaml-cli not available, using basic method to merge YAML" 289 | # Simple line-by-line processing for basic YAML 290 | while IFS=': ' read -r key value; do 291 | # Skip empty lines and comments 292 | [ -z "$key" ] || [ "${key:0:1}" = "#" ] && continue 293 | # Skip lines without a value or section headers 294 | [ -z "$value" ] && continue 295 | 296 | # Clean up key/value 297 | key=$(echo "$key" | tr -d ' ') 298 | 299 | # Set the value 300 | yaml_set_value "$target_file" "$key" "$value" 301 | done < "$preset_file" 302 | fi 303 | ;; 304 | 305 | conf) 306 | # For conf files, apply line by line 307 | while IFS='=' read -r key value; do 308 | # Skip empty lines and comments 309 | [ -z "$key" ] || [ "${key:0:1}" = "#" ] && continue 310 | 311 | # Clean up key 312 | key=$(echo "$key" | tr -d ' ') 313 | 314 | # Set the value 315 | legacy_set_value "$target_file" "$key" "$value" 316 | done < "$preset_file" 317 | ;; 318 | 319 | *) 320 | log_debug "Unknown file type: $file_type" 321 | return 1 322 | ;; 323 | esac 324 | 325 | return 0 326 | } 327 | 328 | # Apply entire preset (handles multiple files) 329 | apply_preset() { 330 | local preset_dir="$1" # Directory containing preset files 331 | 332 | log_debug "Applying preset from directory: $preset_dir" 333 | 334 | # Check if using YAML or legacy config and apply appropriate files 335 | if is_using_yaml; then 336 | # Apply YAML configs 337 | [ -f "$preset_dir/wfb.yaml" ] && apply_preset_file "$preset_dir/wfb.yaml" "$WFB_YAML" "yaml" 338 | [ -f "$preset_dir/majestic.yaml" ] && apply_preset_file "$preset_dir/majestic.yaml" "$MAJESTIC_YAML" "yaml" 339 | 340 | # If the preset only has legacy files but we're in YAML mode, 341 | # we need to apply the legacy files to maintain preset functionality 342 | if [ ! -f "$preset_dir/wfb.yaml" ] && [ -f "$preset_dir/wfb.conf" ]; then 343 | log_debug "Preset contains only legacy files but system uses YAML format" 344 | 345 | # Create a temporary YAML file to hold the converted settings 346 | tmp_yaml="/tmp/wfb_preset_temp.yaml" 347 | > "$tmp_yaml" 348 | 349 | # Process legacy config files and extract settings to temp YAML 350 | for conf_file in "$preset_dir/wfb.conf" "$preset_dir/telemetry.conf" "$preset_dir/datalink.conf"; do 351 | if [ -f "$conf_file" ]; then 352 | log_debug "Processing legacy file for YAML mode: $conf_file" 353 | while IFS='=' read -r key value; do 354 | # Skip empty lines and comments 355 | [ -z "$key" ] || [ "${key:0:1}" = "#" ] && continue 356 | # Clean up key 357 | key=$(echo "$key" | tr -d ' ') 358 | # Add to temp YAML 359 | yaml_set_value "$tmp_yaml" "$key" "$value" 360 | done < "$conf_file" 361 | fi 362 | done 363 | 364 | # Apply the temp YAML to the real YAML config 365 | apply_preset_file "$tmp_yaml" "$WFB_YAML" "yaml" 366 | rm -f "$tmp_yaml" 367 | fi 368 | else 369 | # Apply legacy configs 370 | [ -f "$preset_dir/wfb.conf" ] && apply_preset_file "$preset_dir/wfb.conf" "$WFB_CONF" "conf" 371 | [ -f "$preset_dir/telemetry.conf" ] && apply_preset_file "$preset_dir/telemetry.conf" "$TELEMETRY_CONF" "conf" 372 | [ -f "$preset_dir/datalink.conf" ] && apply_preset_file "$preset_dir/datalink.conf" "$DATALINK_CONF" "conf" 373 | fi 374 | 375 | return 0 376 | } 377 | 378 | # Helper function to get list of supported values for a setting 379 | get_allowed_values() { 380 | local setting="$1" 381 | 382 | case "$setting" in 383 | unit) 384 | echo "drone gs" 385 | ;; 386 | region) 387 | echo "00 US EU CN" 388 | ;; 389 | bandwidth) 390 | echo "20 40" 391 | ;; 392 | stbc|ldpc) 393 | echo "0 1" 394 | ;; 395 | guard_interval) 396 | echo "long short" 397 | ;; 398 | one_way) 399 | echo "true false" 400 | ;; 401 | *) 402 | echo "" 403 | ;; 404 | esac 405 | } 406 | 407 | # Get a human-readable description for a setting 408 | get_setting_description() { 409 | local setting="$1" 410 | 411 | case "$setting" in 412 | unit) 413 | echo "Device role (drone or ground station)" 414 | ;; 415 | wlan) 416 | echo "WiFi interface name" 417 | ;; 418 | region) 419 | echo "WiFi regulatory domain (00=worldwide, US=United States, etc.)" 420 | ;; 421 | channel) 422 | echo "WiFi channel number" 423 | ;; 424 | frequency) 425 | echo "WiFi frequency in MHz (overrides channel if set)" 426 | ;; 427 | txpower) 428 | echo "WiFi transmission power level" 429 | ;; 430 | driver_txpower_override) 431 | echo "Override driver TX power settings" 432 | ;; 433 | bandwidth) 434 | echo "WiFi channel bandwidth in MHz" 435 | ;; 436 | stbc) 437 | echo "Space-Time Block Coding (improves range at expense of throughput)" 438 | ;; 439 | ldpc) 440 | echo "Low-Density Parity-Check coding (error correction)" 441 | ;; 442 | mcs_index) 443 | echo "Modulation and Coding Scheme index (higher=more speed, less range)" 444 | ;; 445 | stream) 446 | echo "Number of spatial streams" 447 | ;; 448 | link_id) 449 | echo "Unique link identifier to avoid interference" 450 | ;; 451 | udp_port) 452 | echo "UDP port for video stream" 453 | ;; 454 | rcv_buf) 455 | echo "UDP receive buffer size in bytes" 456 | ;; 457 | frame_type) 458 | echo "WiFi frame type (data or ieee80211)" 459 | ;; 460 | fec_k) 461 | echo "FEC parameter K (number of packets)" 462 | ;; 463 | fec_n) 464 | echo "FEC parameter N (total packets including redundant)" 465 | ;; 466 | pool_timeout) 467 | echo "Packet pool timeout in milliseconds" 468 | ;; 469 | guard_interval) 470 | echo "WiFi guard interval (long or short)" 471 | ;; 472 | serial) 473 | echo "Serial port for telemetry" 474 | ;; 475 | baud) 476 | echo "Serial baudrate" 477 | ;; 478 | router) 479 | echo "Telemetry router type (0=mavfwd, 1=mavlink-routerd, 2=msposd)" 480 | ;; 481 | stream_rx) 482 | echo "Telemetry receiving stream ID" 483 | ;; 484 | stream_tx) 485 | echo "Telemetry transmitting stream ID" 486 | ;; 487 | port_rx) 488 | echo "Telemetry receiving UDP port" 489 | ;; 490 | port_tx) 491 | echo "Telemetry transmitting UDP port" 492 | ;; 493 | one_way) 494 | echo "Enable one-way telemetry mode" 495 | ;; 496 | aggregate) 497 | echo "Telemetry packet aggregation level" 498 | ;; 499 | channels) 500 | echo "Number of RC channels to parse" 501 | ;; 502 | fps) 503 | echo "OSD frames per second" 504 | ;; 505 | ahi) 506 | echo "Artificial horizon indicator setting" 507 | ;; 508 | daemon) 509 | echo "Run as daemon" 510 | ;; 511 | telemetry) 512 | echo "Enable telemetry" 513 | ;; 514 | tunnel) 515 | echo "Enable IP tunnel" 516 | ;; 517 | usb_modem) 518 | echo "Use USB modem (LTE firmware only)" 519 | ;; 520 | gs_ipaddr) 521 | echo "Ground station IP address" 522 | ;; 523 | gs_port) 524 | echo "Ground station port" 525 | ;; 526 | use_zt) 527 | echo "Use ZeroTier (LTE/ultimate builds only)" 528 | ;; 529 | zt_netid) 530 | echo "ZeroTier network ID" 531 | ;; 532 | *) 533 | echo "$setting configuration" 534 | ;; 535 | esac 536 | } 537 | 538 | # Process form input 539 | process_form() { 540 | if [ "${REQUEST_METHOD}" = "POST" ]; then 541 | # Handle form submission 542 | if [ -n "${FORM_action}" ]; then 543 | case "${FORM_action}" in 544 | save_config) 545 | # Save configuration changes 546 | for param in ${FORM_param_*}; do 547 | key=$(echo "$param" | sed 's/FORM_param_//') 548 | value=$(eval echo \$"$param") 549 | set_config_value "$key" "$value" 550 | done 551 | result_message="Configuration saved successfully" 552 | ;; 553 | 554 | apply_preset) 555 | # Apply a preset configuration 556 | if [ -n "${FORM_preset_dir}" ]; then 557 | apply_preset "${FORM_preset_dir}" 558 | result_message="Preset applied successfully" 559 | else 560 | result_message="Error: No preset directory specified" 561 | fi 562 | ;; 563 | 564 | reboot) 565 | # Reboot the device 566 | result_message="Device is rebooting..." 567 | echo "" 568 | sync 569 | reboot & 570 | ;; 571 | 572 | *) 573 | result_message="Unknown action: ${FORM_action}" 574 | ;; 575 | esac 576 | fi 577 | fi 578 | } 579 | 580 | # Display available settings 581 | display_settings() { 582 | echo "

Current Configuration

" 583 | echo "
" 584 | echo "" 585 | echo "" 586 | echo "" 587 | 588 | # Display common settings first 589 | for setting in unit wlan region channel frequency txpower bandwidth; do 590 | value=$(get_config_value "$setting" "") 591 | description=$(get_setting_description "$setting") 592 | allowed_values=$(get_allowed_values "$setting") 593 | 594 | echo "" 595 | echo "" 596 | 597 | # If we have allowed values, show as dropdown 598 | if [ -n "$allowed_values" ]; then 599 | echo "" 608 | else 609 | echo "" 610 | fi 611 | 612 | echo "" 613 | echo "" 614 | done 615 | 616 | # Advanced WFB settings 617 | echo "" 618 | for setting in stbc ldpc mcs_index stream link_id udp_port rcv_buf frame_type fec_k fec_n pool_timeout guard_interval; do 619 | value=$(get_config_value "$setting" "") 620 | description=$(get_setting_description "$setting") 621 | allowed_values=$(get_allowed_values "$setting") 622 | 623 | echo "" 624 | echo "" 625 | 626 | # If we have allowed values, show as dropdown 627 | if [ -n "$allowed_values" ]; then 628 | echo "" 637 | else 638 | echo "" 639 | fi 640 | 641 | echo "" 642 | echo "" 643 | done 644 | 645 | # Telemetry settings 646 | echo "" 647 | for setting in serial baud router stream_rx stream_tx port_rx port_tx one_way aggregate channels fps ahi; do 648 | value=$(get_config_value "$setting" "") 649 | description=$(get_setting_description "$setting") 650 | allowed_values=$(get_allowed_values "$setting") 651 | 652 | echo "" 653 | echo "" 654 | 655 | # If we have allowed values, show as dropdown 656 | if [ -n "$allowed_values" ]; then 657 | echo "" 666 | else 667 | echo "" 668 | fi 669 | 670 | echo "" 671 | echo "" 672 | done 673 | 674 | # Datalink settings 675 | echo "" 676 | for setting in daemon telemetry tunnel usb_modem gs_ipaddr gs_port use_zt zt_netid; do 677 | value=$(get_config_value "$setting" "") 678 | description=$(get_setting_description "$setting") 679 | allowed_values=$(get_allowed_values "$setting") 680 | 681 | echo "" 682 | echo "" 683 | 684 | # If we have allowed values, show as dropdown 685 | if [ -n "$allowed_values" ]; then 686 | echo "" 695 | else 696 | echo "" 697 | fi 698 | 699 | echo "" 700 | echo "" 701 | done 702 | 703 | echo "
SettingValueDescription
$setting$description
Advanced WiFi Broadcast Settings
$setting$description
Telemetry Settings
$setting$description
Datalink Settings
$setting$description
" 704 | echo "
" 705 | echo "" 706 | echo "
" 707 | echo "
" 708 | } 709 | 710 | # Display presets section 711 | display_presets() { 712 | echo "

Configuration Presets

" 713 | echo "
" 714 | echo "" 715 | 716 | echo "
" 717 | 718 | # Find all preset directories 719 | presets_dir="/etc/openipc/presets" 720 | if [ -d "$presets_dir" ]; then 721 | for preset in $(ls -1 "$presets_dir"); do 722 | if [ -d "$presets_dir/$preset" ]; then 723 | # Check if this preset has a description file 724 | preset_name="$preset" 725 | preset_desc="" 726 | if [ -f "$presets_dir/$preset/description.txt" ]; then 727 | preset_desc=$(cat "$presets_dir/$preset/description.txt") 728 | fi 729 | 730 | echo "
" 731 | echo "" 732 | echo "" 733 | if [ -n "$preset_desc" ]; then 734 | echo "
$preset_desc
" 735 | fi 736 | echo "
" 737 | fi 738 | done 739 | 740 | echo "
" 741 | echo "" 742 | echo "
" 743 | else 744 | echo "

No presets available.

" 745 | fi 746 | 747 | echo "
" 748 | echo "
" 749 | } 750 | 751 | # System actions 752 | display_system_actions() { 753 | echo "

System Actions

" 754 | echo "
" 755 | echo "" 756 | echo "
" 757 | echo "" 758 | echo "
" 759 | echo "
" 760 | } 761 | 762 | # Determine if using YAML or legacy format 763 | config_format="Legacy configuration format" 764 | if is_using_yaml; then 765 | config_format="YAML configuration format" 766 | fi 767 | 768 | check_password 769 | 770 | %> -------------------------------------------------------------------------------- /www/cgi-bin/p/header.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | Content-type: text/html; charset=UTF-8 3 | Cache-Control: no-store 4 | Pragma: no-cache 5 | 6 | 7 | 8 | 9 | 10 | 11 | <% html_title %> 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 82 | 83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 | 91 |
92 | <%= $(signature) %> 93 |
94 | 95 |
96 |
97 |
98 |
99 |
100 |
101 | 102 | <% if [ -z "$network_gateway" ]; then %> 103 |
104 |

Internet connection not available, please check your network settings.

105 |
106 | <% fi %> 107 | 108 | <% if [ "$network_macaddr" = "00:00:23:34:45:66" ] && [ -f /etc/shadow- ] && [ -n $(grep root /etc/shadow- | cut -d: -f2) ]; then %> 109 |
110 | <%in p/address.cgi %> 111 |
112 | <% fi %> 113 | 114 | <% if [ ! -e $(get_config) ]; then %> 115 |
116 |

Majestic configuration not found, please check your Majestic settings.

117 |
118 | <% fi %> 119 | 120 | <% if [ "$(cat /etc/TZ)" != "$TZ" ] || [ -e /tmp/system-reboot ]; then %> 121 |
122 |

Warning.

123 |

System settings have been updated, restart to apply pending changes.

124 | 125 | Restart camera 126 | 127 |
128 | <% fi %> 129 | 130 |

<%= $page_title %>

131 | <% log_read %> 132 | -------------------------------------------------------------------------------- /www/cgi-bin/p/header_fpv.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | Content-type: text/html; charset=UTF-8 3 | Cache-Control: no-store 4 | Pragma: no-cache 5 | 6 | 7 | 8 | 9 | 10 | 11 | <% html_title %> 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 91 | 92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 | 100 |
101 | <%= $(signature) %> 102 |
103 | 104 |
105 |
106 |
107 |
108 |
109 |
110 | 111 | <% if [ -z "$network_gateway" ]; then %> 112 |
113 |

Internet connection not available, please check your network settings.

114 |
115 | <% fi %> 116 | 117 | <% if [ "$network_macaddr" = "00:00:23:34:45:66" ] && [ -f /etc/shadow- ] && [ -n $(grep root /etc/shadow- | cut -d: -f2) ]; then %> 118 |
119 | <%in p/address.cgi %> 120 |
121 | <% fi %> 122 | 123 | <% if [ ! -e $(get_config) ]; then %> 124 |
125 |

Majestic configuration not found, please check your Majestic settings.

126 |
127 | <% fi %> 128 | 129 | <% if [ "$(cat /etc/TZ)" != "$TZ" ] || [ -e /tmp/system-reboot ]; then %> 130 |
131 |

Warning.

132 |

System settings have been updated, restart to apply pending changes.

133 | 134 | Restart camera 135 | 136 |
137 | <% fi %> 138 | 139 |

<%= $page_title %>

140 | <% log_read %> 141 | -------------------------------------------------------------------------------- /www/cgi-bin/p/motor.cgi: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 | 6 | 7 |
8 |
9 | 10 | 11 | 12 |
13 |
14 | 15 | 16 | 17 |
18 |
19 | 20 | 33 | -------------------------------------------------------------------------------- /www/cgi-bin/p/roi.cgi: -------------------------------------------------------------------------------- 1 |
2 |

Visual editor

3 |
4 | 5 |
6 |
7 |
8 | 9 |
10 |
11 |
12 | 13 | 19 | -------------------------------------------------------------------------------- /www/cgi-bin/preview.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | 4 | <% page_title="Camera Preview" %> 5 | <%in p/header.cgi %> 6 | 7 |
8 |
9 | <% preview %> 10 |

Majestic Endpoints

11 |
12 | 13 |
14 | <% if [ "$(get_night lightMonitor)" = "true" ]; then %> 15 |

Light monitor active

16 | <% fi %> 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | <% if [ -n "$ptz_support" ]; then %> 29 | <%in p/motor.cgi %> 30 | <% fi %> 31 |
32 |
33 |
34 | 35 | 68 | 69 | <%in p/footer.cgi %> 70 | -------------------------------------------------------------------------------- /www/cgi-bin/status.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | 4 | <% page_title="Device Status" %> 5 | <%in p/header.cgi %> 6 | 7 |
8 |
9 |

Hardware

10 |
11 |
Processor
12 |
<%= $soc %>
13 |
Family
14 |
<%= $soc_family %>
15 |
Sensor
16 |
<%= $sensor %>
17 |
Flash
18 |
<%= $flash_size %> MB
19 |
20 |
21 | 22 |
23 |

Firmware

24 |
25 |
Version
26 |
<%= "${fw_version}-${fw_variant}" %>
27 |
Build
28 |
<%= $fw_build %>
29 |
Majestic
30 |
<%= $mj_version %>
31 | <% if [ -n "$uboot_version" ]; then %> 32 |
U-Boot
33 |
<%= $uboot_version %>
34 | <% fi %> 35 |
36 |
37 |
38 | 39 |
40 |
41 |

Resources

42 | <% ex "uptime" %> 43 | <% ex "df -hT" %> 44 | <% ex "free -h" %> 45 |
46 |
47 | 48 | <%in p/footer.cgi %> 49 | -------------------------------------------------------------------------------- /www/cgi-bin/tool-console.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% 4 | page_title="Console" 5 | %> 6 | 7 | <%in p/header.cgi %> 8 |
9 |
10 |
11 | <% field_text "command" "Enter command:" %> 12 |
13 |
14 | <% button_submit "Run" "secondary" %> 15 |
16 |
17 |
18 |
19 |
20 |
21 | 22 | 40 | 41 | <%in p/footer.cgi %> 42 | -------------------------------------------------------------------------------- /www/cgi-bin/tool-files.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | <% page_title="Files" %> 4 | <% 5 | [ -n "$GET_cd" ] && dir=${GET_cd} 6 | dir=$(cd ${dir:-/}; pwd | sed s#^//#/#) 7 | back=$(cd ${dir}/..; pwd | sed s#^//#/#) 8 | %> 9 | 10 | <%in p/header.cgi %> 11 |

<%= $dir %>

12 | <% 13 | echo "
" 14 | echo ".." 15 | echo "
" 16 | 17 | filename=$(ls --group-directories-first $dir) 18 | for line in $filename; do 19 | path=$(echo "${dir}/${line}" | sed s!^//!/!) 20 | [ "$path" = "/proc" ] || [ "$path" = "/sys" ] && continue 21 | 22 | echo "
" 23 | echo "
" 24 | if [ -d "${path}" ]; then 25 | echo "${line}" 26 | else 27 | echo "${line}" 28 | fi 29 | 30 | fileinfo=$(stat -c "%s.%a.%z" $path) 31 | filesize=$(echo $fileinfo | cut -d. -f1) 32 | permission=$(echo $fileinfo | cut -d. -f2) 33 | timestamp=$(echo $fileinfo | cut -d. -f3) 34 | 35 | echo "
" 36 | echo "
${filesize}
" 37 | echo "
${permission}
" 38 | echo "
${timestamp}
" 39 | echo "
" 40 | done 41 | %> 42 | 43 | <%in p/footer.cgi %> 44 | -------------------------------------------------------------------------------- /www/cgi-bin/tool-sdcard.cgi: -------------------------------------------------------------------------------- 1 | #!/usr/bin/haserl 2 | <%in p/common.cgi %> 3 | 4 | <% page_title="SDcard" %> 5 | <%in p/header.cgi %> 6 | 7 | <% if [ ! -e /dev/mmcblk0 ]; then %> 8 | 9 |
10 |

SDcard is not available.

11 |

Make sure the card is correctly inserted.

12 |
13 | 14 | <% else %> 15 | 16 | <% 17 | card_device="/dev/mmcblk0" 18 | card_partition="${card_device}p1" 19 | mount_point="${card_partition//dev/mnt}" 20 | error="" 21 | _o="" 22 | %> 23 | 24 | <% if [ -n "$POST_doFormatCard" ]; then %> 25 | 26 |
27 |

SDcard formatting takes time.

28 |

Please do not refresh this page. Wait until partition formatting is finished!

29 |
30 | 31 | <% 32 | if [ "$(grep $card_partition /etc/mtab)" ]; then 33 | _c="umount $card_partition" 34 | _o="${_o}\n${_c}\n$($_c 2>&1)" 35 | [ $? -ne 0 ] && error="Cannot unmount SDcard partition." 36 | fi 37 | 38 | if [ -z "$error" ]; then 39 | _c="mkfs.vfat $card_partition" 40 | _o="${_o}\n${_c}\n$($_c 2>&1)" 41 | [ $? -ne 0 ] && error="Cannot format SDcard partition." 42 | fi 43 | 44 | if [ -z "$error" ] && [ ! -d "$mount_point" ]; then 45 | _c="mkdir -p $mount_point" 46 | _o="${_o}\n${_c}\n$($_c 2>&1)" 47 | [ $? -ne 0 ] && error="Cannot create SDcard mount point." 48 | fi 49 | 50 | if [ -z "$error" ]; then 51 | _c="mount -t vfat $card_partition $mount_point" 52 | _o="${_o}\n${_c}\n$($_c 2>&1)" 53 | [ $? -ne 0 ] && error="Cannot remount SDcard partition." 54 | fi 55 | 56 | if [ -n "$error" ]; then 57 | report_error "$error" 58 | [ -n "$_c" ] && report_command "$_c" "$_o" 59 | else 60 | report_log "$_o" 61 | fi 62 | %> 63 | 64 | Return 65 | 66 | <% else %> 67 | 68 |

SDcard partitions

69 | <% 70 | partitions=$(df -h | grep 'dev/mmc') 71 | echo "
${partitions}
" 72 | %> 73 | 74 | <% if [ -n "$partitions" ]; then %> 75 | 76 |

Browse files on these partitions

77 |
78 | <% 79 | IFS=$'\n' 80 | for i in $partitions; do 81 | _mount=$(echo $i | awk '{print $6}') 82 | echo "${_mount}" 83 | unset _mount 84 | done 85 | IFS=$IFS_ORIG 86 | unset _partitions 87 | %> 88 |
89 | 90 | <% fi %> 91 | 92 |

Format SDcard

93 |
94 |

ATTENTION! Formatting will destroy all data on the SDcard.

95 |

Make sure you have a backup copy if you are going to use the data in the future.

96 |
97 | <% field_hidden "doFormatCard" "true" %> 98 | <% button_submit "Format SDcard" "danger" %> 99 |
100 |
101 | 102 | <% fi %> 103 | <% fi %> 104 | 105 | <%in p/footer.cgi %> 106 | -------------------------------------------------------------------------------- /www/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenIPC/majestic-webui/9f3de99a17f18f372c8355ac1256e59f59e8728f/www/favicon.ico -------------------------------------------------------------------------------- /www/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | OpenIPC 8 | 9 | 10 | -------------------------------------------------------------------------------- /www/m/img.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 12 | 13 |
14 | 15 | 114 | 115 | 116 | --------------------------------------------------------------------------------