├── .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 |
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 | 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 | 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 |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 |Use the following credentials to set up remote access via virtual tunnel:
35 |" 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 |Reboot camera to apply new settings and reset temporary files.
703 | Restart Camera 704 |Restore the config file bundled with firmware. All changes to the default configuration will be lost!
108 | 112 |Create backup remotely, e.g. from script:
46 |Reboot camera to apply new settings and reset temporary files.
54 | Restart Camera 55 |Revert firmware to original state by resetting the overlay partition.
59 | Reset Firmware 60 |Create backup of files, listed in backuper configuration.
67 | Create Backup 68 |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
This action removes all current settings!
77 | 78 |Updating requires access to GitHub.
52 | <% fi %> 53 |Go to https://wiki.openipc.org for more information.
49 |<% echo -e "$config" %>127 |
You need to replace it with the original MAC address from your stock firmware backup or generate a random valid MAC address.
3 | 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}${t}>" 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 "${1}>" 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 "" 138 | eval "$1" | sed "s/&/\&/g;s/\</g;s/>/\>/g;s/\"/\"/g" 139 | 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 "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 "${2}" 391 | } 392 | 393 | report_error() { 394 | echo "