Merge branch 'master' into dey-4.0/maint

This commit is contained in:
Isaac Hermida 2022-11-03 17:24:55 +01:00
commit 0e15c8833d
22 changed files with 1944 additions and 275 deletions

View File

@ -29,9 +29,13 @@ import socketserver
import stat
import subprocess
from digi.apix.bluetooth import BluetoothException, BluetoothDevice, BluetoothProfile
from digi.apix.exceptions import DigiAPIXException
from digi.apix.network import IPMode, NetworkException, NetStatus, NetworkInterface, NetworkProfile
from digi.apix.wifi import SecurityMode, WifiException, WifiInterface, WifiProfile
from logging.handlers import SysLogHandler
from subprocess import call, TimeoutExpired
from threading import Thread, Event
from threading import Thread
# Constants.
@ -52,9 +56,15 @@ ZERO_MAC = "00:00:00:00:00:00"
ZERO_IP = "0.0.0.0"
NOT_AVAILABLE = "N/A"
ELEMENT_BLUETOOTH = "bluetooth"
ELEMENT_ETHERNET = "ethernet"
ELEMENT_WIFI = "wifi"
PREFIX_ETHERNET = "eth"
PREFIX_WIFI = "wlan"
# Variables.
log = logging.getLogger(APP_NAME)
stop_event = Event()
last_cpu_work = 0
last_cpu_total = 0
led_status = {}
@ -113,7 +123,11 @@ class RequestHandler(http.server.SimpleHTTPRequestHandler):
mca_versions = get_mca_version()
info = {
"uboot_version": read_proc_file("/proc/device-tree/digi,uboot,version"),
"kernel_version": "%s %s %s %s %s GNU/Linux" % (platform.system(), platform.node(), platform.release(), platform.version(), platform.machine()),
"kernel_version": "%s %s %s %s %s GNU/Linux" % (platform.system(),
platform.node(),
platform.release(),
platform.version(),
platform.machine()),
"dey_version": "DEY-%s-%s" % (get_dey_version(), read_file("/etc/version")),
"serial_number": read_proc_file("/proc/device-tree/digi,hwid,sn"),
"device_type": read_proc_file("/proc/device-tree/digi,machine,name"),
@ -126,14 +140,57 @@ class RequestHandler(http.server.SimpleHTTPRequestHandler):
"flash_size": get_storage_size(),
"video_resolution": get_video_resolution(),
"fw_store_path": get_fw_store_path(),
"bluetooth_mac": get_bt_mac("hci0"),
"wifi_mac": read_file("/sys/class/net/wlan0/address").strip().upper() if "wlan0" in list_net_ifaces() else ZERO_MAC,
"wifi_ip": get_iface_ip("wlan0") if "wlan0" in list_net_ifaces() else ZERO_IP,
"ethernet0_mac": read_file("/sys/class/net/eth0/address").strip().upper() if "eth0" in list_net_ifaces() else ZERO_MAC,
"ethernet0_ip": get_iface_ip("eth0") if "eth0" in list_net_ifaces() else ZERO_IP,
"ethernet1_mac": read_file("/sys/class/net/eth1/address").strip().upper() if "eth1" in list_net_ifaces() else ZERO_MAC,
"ethernet1_ip": get_iface_ip("eth1") if "eth1" in list_net_ifaces() else ZERO_IP,
"bluetooth_mac": ZERO_MAC,
"wifi_mac": ZERO_MAC,
"wifi_ip": ZERO_IP,
"ethernet0_mac": ZERO_MAC,
"ethernet0_ip": ZERO_IP,
"ethernet1_mac": ZERO_MAC,
"ethernet1_ip": ZERO_IP,
}
# Fill bluetooth data.
try:
bt_devices = BluetoothDevice.list_devices()
if bt_devices and "hci0" in bt_devices:
try:
bt_device = BluetoothDevice.get("hci0")
info["bluetooth_mac"] = mac_to_human_string(bt_device.mac)
except BluetoothException as exc2:
log.error("Error reading interface 'hci0' data: %s", str(exc2))
except DigiAPIXException as exc:
log.error("Error listing bluetooth devices: %s", str(exc))
# Fill ethernet interfaces data.
try:
interfaces = NetworkInterface.list_interfaces()
if interfaces and "eth0" in interfaces:
try:
net_iface = NetworkInterface.get("eth0")
info["ethernet0_mac"] = str(net_iface.mac)
info["ethernet0_ip"] = str(net_iface.ipv4)
except NetworkException as exc2:
log.error("Error reading interface 'eth0' data: %s", str(exc2))
if interfaces and "eth1" in interfaces:
try:
net_iface = NetworkInterface.get("eth1")
info["ethernet1_mac"] = mac_to_human_string(net_iface.mac)
info["ethernet1_ip"] = str(net_iface.ipv4)
except NetworkException as exc2:
log.error("Error reading interface 'eth1' data: %s", str(exc2))
except DigiAPIXException as exc:
log.error("Error listing network interfaces: %s", str(exc))
# Fill WiFi interfaces data.
try:
interfaces = WifiInterface.list_interfaces()
if interfaces and "wlan0" in interfaces:
try:
net_iface = WifiInterface.get("wlan0")
info["wifi_mac"] = mac_to_human_string(net_iface.mac)
info["wifi_ip"] = str(net_iface.ipv4)
except WifiException as exc2:
log.error("Error reading interface 'wlan0' data: %s", str(exc2))
except DigiAPIXException as exc:
log.error("Error listing network interfaces: %s", str(exc))
# Send the JSON value.
self.wfile.write(json.dumps(info).encode(encoding="utf_8"))
@ -147,7 +204,7 @@ class RequestHandler(http.server.SimpleHTTPRequestHandler):
mem_total = int(mem_info.get("MemTotal", "-1")) if mem_info else -1
mem_free = int(mem_info.get("MemFree", "-1")) if mem_info else -1
mem_used = (mem_total - mem_free) if (mem_total > 0 and mem_free > 0) else -1
bt_data = get_bt_data("hci0")
status = {
"system_monitor/cpu_load": get_cpu_load(),
"system_monitor/cpu_temperature": get_cpu_temp(),
@ -155,18 +212,56 @@ class RequestHandler(http.server.SimpleHTTPRequestHandler):
"system_monitor/uptime": get_uptime(),
"system_monitor/free_memory": mem_free,
"system_monitor/used_memory": mem_used,
"system_monitor/led_status": get_led_status("USER_LED"),
"system_monitor/hci0/state": bt_data.get("state", 0),
"system_monitor/hci0/rx_bytes": bt_data.get("rx_bytes", 0),
"system_monitor/hci0/tx_bytes": bt_data.get("tx_bytes", 0),
"system_monitor/led_status": get_led_status("USER_LED")
}
list_ifaces = list_net_ifaces()
for name in list_ifaces:
data = get_iface_data(name)
status["system_monitor/%s/state" % name] = data["state"]
status["system_monitor/%s/rx_bytes" % name] = data["rx_bytes"]
status["system_monitor/%s/tx_bytes" % name] = data["tx_bytes"]
# Fill bluetooth devices data.
try:
bt_devices = BluetoothDevice.list_devices() or []
for device in bt_devices:
try:
bt_device = BluetoothDevice.get(device)
statistics = bt_device.get_statistics()
status[f"system_monitor/{device}/state"] = 1 if \
bt_device.is_enabled else 0
status[f"system_monitor/{device}/rx_bytes"] = statistics.rx_bytes
status[f"system_monitor/{device}/tx_bytes"] = statistics.tx_bytes
except NetworkException as exc2:
log.error("Error reading bluetooth device '%s' data: %s", device, str(exc2))
except DigiAPIXException as exc:
log.error("Error listing bluetooth devices: %s", str(exc))
# Fill ethernet interfaces data.
try:
interfaces = NetworkInterface.list_interfaces() or []
for iface in interfaces:
try:
net_iface = NetworkInterface.get(iface)
statistics = net_iface.get_statistics()
status[f"system_monitor/{iface}/state"] = 1 if \
net_iface.status == NetStatus.CONNECTED else 0
status[f"system_monitor/{iface}/rx_bytes"] = statistics.rx_bytes
status[f"system_monitor/{iface}/tx_bytes"] = statistics.tx_bytes
except NetworkException as exc2:
log.error("Error reading interface '%s' data: %s", iface, str(exc2))
except DigiAPIXException as exc:
log.error("Error listing network interfaces: %s", str(exc))
# Fill WiFi interfaces data.
try:
interfaces = WifiInterface.list_interfaces() or []
for iface in interfaces:
try:
wifi_iface = WifiInterface.get(iface)
statistics = wifi_iface.get_statistics()
status[f"system_monitor/{iface}/state"] = 1 if \
wifi_iface.status == NetStatus.CONNECTED else 0
status[f"system_monitor/{iface}/rx_bytes"] = statistics.rx_bytes
status[f"system_monitor/{iface}/tx_bytes"] = statistics.tx_bytes
except WifiException as exc2:
log.error("Error reading interface '%s' data: %s", iface, str(exc2))
except DigiAPIXException as exc:
log.error("Error listing WiFi interfaces: %s", str(exc))
# Send the JSON value.
self.wfile.write(json.dumps(status).encode(encoding="utf_8"))
@ -196,6 +291,23 @@ class RequestHandler(http.server.SimpleHTTPRequestHandler):
return
self.wfile.write("{}".encode(encoding="utf_8"))
elif re.search("/ajax/play_music", self.path) is not None:
# Set the response headers.
self._set_headers(200)
# Get the JSON data.
data = self.rfile.read(int(self.headers["Content-Length"]))
play = json.loads(data.decode("utf-8")).get("play", None)
music_file = json.loads(data.decode("utf-8")).get("music_file", None)
log.debug("Play music: %s", play)
if music_file:
log.debug("Music file: %s", music_file)
play_music(play, music_file)
# Send the JSON value.
self.wfile.write(json.dumps({"play": play}).encode(encoding="utf_8"))
elif re.search("/ajax/set_audio_volume", self.path) is not None:
# Set the response headers.
self._set_headers(200)
@ -212,7 +324,7 @@ class RequestHandler(http.server.SimpleHTTPRequestHandler):
self.wfile.write(json.dumps({"error": error}).encode(encoding="utf_8"))
return
vol, error = set_audio_volume(value)
error = set_audio_volume(value)
# Send the JSON value.
if error:
@ -221,7 +333,7 @@ class RequestHandler(http.server.SimpleHTTPRequestHandler):
return
# Send the JSON value.
self.wfile.write(json.dumps({"value": vol}).encode(encoding="utf_8"))
self.wfile.write("{}".encode(encoding="utf_8"))
elif re.search("/ajax/fs_list_directory", self.path) is not None:
# Set the response headers.
self._set_headers(200)
@ -462,7 +574,34 @@ class RequestHandler(http.server.SimpleHTTPRequestHandler):
progress = 100
if fw_process and fw_process.poll() is None:
progress = "?"
self.wfile.write(json.dumps({"progress": progress, "message": "Updating firmare"}).encode(encoding="utf_8"))
self.wfile.write(json.dumps({"progress": progress, "message": "Updating firmware"}).encode(encoding="utf_8"))
elif re.search("/ajax/get_config", self.path) is not None:
# Set the response headers.
self._set_headers(200)
# Get the JSON data.
data = self.rfile.read(int(self.headers["Content-Length"]))
elements = json.loads(data.decode("utf-8")).get("elements", None)
# Fill configuration data.
config_data = get_elements_configuration(elements)
# Send the answer.
if "error" in config_data:
self.wfile.write(json.dumps(config_data).encode(encoding="utf_8"))
else:
self.wfile.write(json.dumps(
{"data": json.dumps(config_data)}).encode(encoding="utf_8"))
elif re.search("/ajax/set_config", self.path) is not None:
# Set the response headers.
self._set_headers(200)
# Get the JSON data.
data = self.rfile.read(int(self.headers["Content-Length"]))
configuration = json.loads(data.decode("utf-8")).get("configuration", None)
# Apply configuration.
result = set_configuration(configuration)
# Send the answer.
if "error" in result:
self.wfile.write(json.dumps(result).encode(encoding="utf_8"))
else:
self.wfile.write(json.dumps({"data": json.dumps(result)}).encode(encoding="utf_8"))
else:
# Forbidden.
self._set_headers(403)
@ -507,7 +646,7 @@ def filter_by_extension(name, filters):
if name.endswith(ext):
return True
return False;
return False
def get_uptime():
@ -652,7 +791,7 @@ def get_video_resolution():
if res == NOT_AVAILABLE:
res = read_file("/sys/class/graphics/fb0/modes")
if res == NOT_AVAILABLE:
return "-"
return "No video device found"
line = res.splitlines()[0]
if ":" in line:
@ -737,146 +876,6 @@ def get_mca_version():
return NOT_AVAILABLE, NOT_AVAILABLE
def list_net_ifaces():
"""
Returs a list with the names of the network interfaces.
Returns:
List: List of network inteface names.
"""
return os.listdir("/sys/class/net")
def get_iface_ip(iface_name):
"""
Gets the IP address of the provided interface.
Args:
iface_name (String): Name of the network interface to get its IP.
Returns:
String: The IP of the interface.
"""
res = exec_cmd("ip addr show %s" % iface_name)
if res[0] == 0:
tmp = res[1].split("inet ")
if len(tmp) > 1:
return tmp[1].split("/")[0]
log.error("Error getting IP of interface '%s': %s", iface_name, res[1])
return ZERO_IP
def get_iface_data(iface_name):
"""
Gets network interface state and statistics.
Args:
iface_name (String): Name of the interface to get data.
Returns:
Dictionary: The network interface state and statistics.
"""
data = {
"state": 0,
"rx_bytes": 0,
"tx_bytes": 0
}
state = read_file("/sys/class/net/%s/operstate" % iface_name)
if state != NOT_AVAILABLE:
data["state"] = 1 if state.strip() == "up" else 0
stats = read_file("/proc/net/dev")
if stats == NOT_AVAILABLE:
return data
for line in stats.splitlines():
if not line.strip().startswith("%s: " % iface_name):
continue
fields = line.split()
data["rx_bytes"] = fields[1]
data["tx_bytes"] = fields[9]
break
return data
def is_bt_available():
"""
Checks if Bluetooth is available on the device.
Returns:
Boolean: True if available, False otherwise.
"""
return os.path.isdir("/proc/device-tree/bluetooth")
def get_bt_mac(iface_name):
"""
Gets Bluetooth MAC address.
Args:
iface_name (String): Name of the interface to get the MAC.
Returns:
String: The Bluetooth MAC.
"""
if not is_bt_available():
return ZERO_MAC
res = exec_cmd("hciconfig %s" % iface_name)
if res[0] == 0:
return res[1].split("BD Address:")[1].split("ACL")[0].strip()
else:
log.error("Error getting MAC of Bluetooth interface '%s': %s", iface_name, res[1])
return ZERO_MAC
def get_bt_data(iface_name):
"""
Gets Bluetooth interface state and statistics.
Args:
iface_name (String): Name of the interface to get data.
Returns:
Dictionary: The Bluetooth interface state and statistics.
"""
data = {
"state": 0,
"rx_bytes": 0,
"tx_bytes": 0
}
if not is_bt_available():
return data
res = exec_cmd("hciconfig %s" % iface_name)
if res[0] == 0:
info = res[1]
else:
log.error("Error getting status of Bluetooth interface '%s': %s", iface_name, res[1])
return data
lines = info.splitlines()
if not lines:
return data
if len(lines) > 2 and re.fullmatch("(UP) .*", lines[2].strip()):
data["state"] = 1
if len(lines) > 3:
m = re.fullmatch("RX bytes:([0-9]+) .*", lines[3].strip())
data["rx_bytes"] = m.group(1) if m else 0
if len(lines) > 4:
m = re.fullmatch("TX bytes:([0-9]+) .*", lines[4].strip())
data["tx_bytes"] = m.group(1) if m else 0
return data
def get_led_status(name):
"""
Get the LED value.
@ -951,6 +950,19 @@ def get_led_by_alias(alias):
return led_loc.split(",")
def play_music(play, music_file):
"""
Sets the play music value.
Args:
play (Boolean): `True` to play music, `False` to stop it.
music_file (String): Path of the music file to play.
"""
exec_cmd("pkill -KILL -f mpg123")
if play:
exec_cmd_nowait(f"mpg123 {music_file}")
def set_audio_volume(value):
"""
Configures the audio volume.
@ -959,27 +971,277 @@ def set_audio_volume(value):
value (Integer): Volume to set in percentage.
Returns:
Tuple (Integer, String): Current volume value and error string if fails.
String: Error string if fails.
"""
res = exec_cmd("amixer set Headphone %d%%" % value)
res = exec_cmd(f"amixer set 'Speaker' {value}% && amixer set 'Headphone' {value}%")
if res[0] != 0:
return -1, res[1]
return res[1]
return None
tmp = res[1].split("Front Right:")
if len(tmp) < 1:
return -1, "Unable to get current volume"
m = re.search("\[(.+?)%\]", tmp[1])
if not m:
return -1, "Unable to get current volume"
def get_elements_configuration(elements):
"""
Gets the configuration for the given elements.
if len(m.groups()) < 1:
return -1, "Unable to get current volume"
Args:
elements (List): Elements for which to get the configuration.
Returns:
Dictionary: The elements configuration data.
"""
data = {}
for element in elements:
if element == ELEMENT_BLUETOOTH:
data[element] = get_bluetooth_element_configuration()
elif element in (ELEMENT_ETHERNET, ELEMENT_WIFI):
data[element] = get_network_element_configuration(element)
else:
data["error"] = f"Unknown element '{element}'"
return data
def get_network_element_configuration(element):
"""
Gets the configuration for the given network element.
Args:
element (String): Network element for which to get the configuration.
Returns:
Dictionary: The network element configuration data.
"""
data = {}
prefix = PREFIX_ETHERNET
if element == ELEMENT_WIFI:
prefix = PREFIX_WIFI
try:
return int(m.group(1)), ""
except ValueError:
return -1, "Unable to get current volume"
ifaces = NetworkInterface.list_interfaces() or []
for iface in ifaces:
if prefix in iface:
data[iface] = get_network_iface_configuration(iface)
except DigiAPIXException as exc:
data["error"] = f"Error listing network interfaces: '{str(exc)}'"
return data
def get_network_iface_configuration(interface):
"""
Returns the network configuration of the given interface.
Args:
interface (String): Network interface to get its configuration.
Returns:
Dictionary: dictionary with the interface configuration.
"""
data = {}
try:
net_iface = NetworkInterface.get(interface)
data["enable"] = 1 if net_iface.status == NetStatus.CONNECTED else 0
data["mac"] = mac_to_human_string(net_iface.mac)
data["type"] = 0 if net_iface.ip_mode == IPMode.STATIC else 1
data["ip"] = str(net_iface.ipv4)
data["netmask"] = str(net_iface.netmask)
data["dns1"] = str(net_iface.dns1)
data["dns2"] = str(net_iface.dns2)
data["gateway"] = str(net_iface.gateway)
if PREFIX_WIFI in interface:
try:
wifi_iface = WifiInterface.get(interface)
data["ssid"] = wifi_iface.ssid
data["frequency"] = wifi_iface.frequency
data["channel"] = wifi_iface.channel
data["sec_mode"] = 0 if wifi_iface.sec_mode == SecurityMode.UNKNOWN \
else wifi_iface.sec_mode.code
except WifiException as exc:
raise NetworkException({str(exc)}) from exc
except NetworkException as exc2:
data["error"] = f"Error reading interface data: {str(exc2)}"
return data
def set_configuration(config_data):
"""
Applies the given configuration.
Args:
config_data (Dictionary): Configuration to apply.
Returns:
Dictionary: The operation result.
"""
data = {}
for element in config_data:
if element == ELEMENT_BLUETOOTH:
data[element] = set_bluetooth_element_configuration(config_data[element])
elif element in (ELEMENT_ETHERNET, ELEMENT_WIFI):
data[element] = set_network_element_configuration(config_data[element])
else:
data["error"] = f"Unknown element '{element}'"
return data
def set_network_element_configuration(config_data):
"""
Applies the given network configuration.
Args:
config_data (Dictionary): Network configuration to apply.
Returns:
Dictionary: The operation result.
"""
data = {}
for iface in config_data:
data[iface] = set_network_iface_configuration(iface, config_data[iface])
return data
def set_network_iface_configuration(interface, config_data):
"""
Applies the given network configuration to the given interface.
Args:
interface (String): Network interface to apply configuration to.
config_data (Dictionary): Network configuration to apply.
Returns:
Dictionary: Operation result.
"""
data = {}
profile = NetworkProfile()
if PREFIX_WIFI in interface:
profile = WifiProfile()
profile.connect = config_data.get("enable", None)
profile.mode = IPMode.get(config_data["type"]) if "type" in config_data else None
profile.ipv4 = config_data.get("ip", None)
profile.netmask = config_data.get("netmask", None)
profile.gateway = config_data.get("gateway", None)
profile.dns1 = config_data.get("dns1", None)
profile.dns2 = config_data.get("dns2", None)
if PREFIX_WIFI in interface:
profile.ssid = config_data.get("ssid", None)
profile.sec_mode = (SecurityMode.get(config_data["sec_mode"])
if "sec_mode" in config_data else None)
profile.psk = config_data.get("psk", None)
try:
if PREFIX_ETHERNET in interface:
net_iface = NetworkInterface.get(interface)
elif PREFIX_WIFI in interface:
net_iface = WifiInterface.get(interface)
else:
raise DigiAPIXException(f"Unknown interface '{interface}'")
net_iface.configure(profile)
data["status"] = 0
except DigiAPIXException as exc2:
data["status"] = 1
data["desc"] = f"Error configuring interface: {str(exc2)}"
return data
def get_bluetooth_element_configuration():
"""
Gets the configuration for the bluetooth element.
Returns:
Dictionary: The bluetooth element configuration data.
"""
data = {}
try:
bt_devices = BluetoothDevice.list_devices() or []
for bt_device in bt_devices:
data[bt_device] = get_bluetooth_device_configuration(bt_device)
except DigiAPIXException as exc:
data["error"] = f"Error listing bluetooth devices: '{str(exc)}'"
return data
def get_bluetooth_device_configuration(device):
"""
Returns the configuration of the given bluetooth device.
Args:
device (String): Bluetooth device to get its configuration.
Returns:
Dictionary: dictionary with the device configuration.
"""
data = {}
try:
bt_device = BluetoothDevice.get(device)
data["device_id"] = bt_device.device_id
data["advert_name"] = str(bt_device.advert_name)
data["mac"] = mac_to_human_string(bt_device.mac)
data["enable"] = 1 if bt_device.is_enabled else 0
data["running"] = 1 if bt_device.is_running else 0
except BluetoothException as exc:
data["error"] = f"Error reading device data: {str(exc)}"
return data
def set_bluetooth_element_configuration(config_data):
"""
Applies the given bluetooth configuration.
Args:
config_data (Dictionary): Bluetooth configuration to apply.
Returns:
Dictionary: The operation result.
"""
data = {}
for device in config_data:
data[device] = set_bluetooth_device_configuration(device, config_data[device])
return data
def set_bluetooth_device_configuration(device, config_data):
"""
Applies the given bluetooth configuration to the given device.
Args:
device (String): Bluetooth device to apply configuration to.
config_data (Dictionary): Bluetooth configuration to apply.
Returns:
Dictionary: Operation result.
"""
data = {}
try:
bt_device = BluetoothDevice.get(device)
profile = BluetoothProfile()
profile.enable = config_data.get("enable", None)
profile.advert_name = config_data.get("advert_name", None)
bt_device.configure(profile)
data["status"] = 0
except DigiAPIXException as exc2:
data["status"] = 1
data["desc"] = f"Error configuring interface: {str(exc2)}"
return data
def mac_to_human_string(mac, num_bytes=6):
"""
Transforms the given MAC address into a human readable string.
Args:
mac (:class:`.MacAddress`): The MAC address to transform.
num_bytes (Integer): The number of bytes to use in the MAC Address.
Return:
String: The given MAC as human readable string.
"""
return ":".join(["%02X" % i for i in mac][8-num_bytes:]).upper()
def read_proc_file(path):
@ -1025,6 +1287,21 @@ def exec_cmd(cmd, timeout=None):
return e.returncode, e.stdout
def exec_cmd_nowait(command, *args):
"""
Executes the provided command without waiting to finish.
Args:
command (String): The command to execute.
args (List): The list of arguments.
"""
arguments = []
for arg in args:
arguments.extend(arg)
subprocess.Popen([command] + arguments, shell=True, stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, text=True)
def read_file(path):
"""
Reads the provided file path.
@ -1124,8 +1401,6 @@ def signal_handler(signal_number, _frame):
_frame: Current stack frame.
"""
log.debug("Signal received %d", signal_number)
if signal_number in (signal.SIGTERM, signal.SIGINT):
stop_event.set()
def main():
@ -1161,7 +1436,8 @@ def main():
server_thread.deamon = True
server_thread.start()
stop_event.wait()
# Wait for termination/interrupt signal.
signal.sigwait([signal.SIGTERM, signal.SIGINT])
server.shutdown()
server.server_close()

View File

@ -34,7 +34,6 @@ Digi Demo - Dashboard
<p id="banner-text">ConnectCore Demo</p>
</div>
</a>
<div class="nav-right-container">
<div>
<img src="./static/images/board.png" class="device-title-img" title="Device">
@ -69,6 +68,14 @@ Digi Demo - Dashboard
</div>
</a>
</li>
<li id="section_network">
<a data-pjax href="network.html" class="list-group-item list-group-item-action d-flex align-items-center">
<div class="d-flex w-100 justify-content-start align-items-center">
<span class="digi-menu-icon fas fa-network-wired fa-fw fa-lg mr-3"></span>
<span class="menu-collapsed">Network</span>
</div>
</a>
</li>
<li id="section_management">
<a data-pjax href="management.html" class="list-group-item list-group-item-action d-flex align-items-center">
<div class="d-flex w-100 justify-content-start align-items-center">
@ -620,6 +627,13 @@ Digi Demo - Dashboard
<span>Audio control</span>
<div class="fas fa-window-close fa-lg device-card-header-button" onclick="setInfoPanelVisible('audio', false)"></div>
</div>
<div class="device-card-content" style="padding-bottom: 0px;">
<span class="device-card-content-text" style="margin-right: 15px;">Music:</span>
<div id="play_audio_button" class="fas fa-play audio-button" onclick="playMusic(true)">
</div>
<div id="stop_audio_button" class="fas fa-stop audio-button" onclick="playMusic(false)">
</div>
</div>
<div class="device-card-content">
<div>
<span class="device-card-content-text">Volume:</span>
@ -740,12 +754,14 @@ Digi Demo - Dashboard
<!-- Local JS files and functions -->
<script type="text/javascript" src="./static/js/sidebar.js"></script>
<script type="text/javascript" src="./static/js/ccmp133-dvk.js"></script>
<script type="text/javascript" src="./static/js/ccmp157-dvk.js"></script>
<script type="text/javascript" src="./static/js/ccimx6ulsbc.js"></script>
<script type="text/javascript" src="./static/js/ccimx8mm-dvk.js"></script>
<script type="text/javascript" src="./static/js/ccimx8m-nano.js"></script>
<script type="text/javascript" src="./static/js/ccimx8x-sbc-pro.js"></script>
<script type="text/javascript" src="./static/js/dashboard.js"></script>
<script type="text/javascript" src="./static/js/network.js"></script>
<script type="text/javascript" src="./static/js/multimedia.js"></script>
<script type="text/javascript" src="./static/js/management.js"></script>
<script type="text/javascript" src="./static/js/file-system.js"></script>

View File

@ -34,13 +34,12 @@ Digi Demo - Management
<p id="banner-text">ConnectCore Demo</p>
</div>
</a>
<div class="nav-right-container">
<div>
<img src="./static/images/board.png" class="device-title-img" title="Device">
</div>
<div id="device-name">DEY DEVICE</div>
<div class="nav-right-container">
<div>
<img src="./static/images/board.png" class="device-title-img" title="Device">
</div>
<div id="device-name">DEY DEVICE</div>
</div>
</div>
</nav>
@ -69,6 +68,14 @@ Digi Demo - Management
</div>
</a>
</li>
<li id="section_network">
<a data-pjax href="network.html" class="list-group-item list-group-item-action d-flex align-items-center">
<div class="d-flex w-100 justify-content-start align-items-center">
<span class="digi-menu-icon fas fa-network-wired fa-fw fa-lg mr-3"></span>
<span class="menu-collapsed">Network</span>
</div>
</a>
</li>
<li id="section_management">
<a data-pjax href="management.html" class="list-group-item list-group-item-action d-flex align-items-center">
<div class="d-flex w-100 justify-content-start align-items-center">
@ -286,12 +293,14 @@ Digi Demo - Management
<!-- Local JS files and functions -->
<script type="text/javascript" src="./static/js/sidebar.js"></script>
<script type="text/javascript" src="./static/js/ccmp133-dvk.js"></script>
<script type="text/javascript" src="./static/js/ccmp157-dvk.js"></script>
<script type="text/javascript" src="./static/js/ccimx6ulsbc.js"></script>
<script type="text/javascript" src="./static/js/ccimx8mm-dvk.js"></script>
<script type="text/javascript" src="./static/js/ccimx8m-nano.js"></script>
<script type="text/javascript" src="./static/js/ccimx8x-sbc-pro.js"></script>
<script type="text/javascript" src="./static/js/dashboard.js"></script>
<script type="text/javascript" src="./static/js/network.js"></script>
<script type="text/javascript" src="./static/js/multimedia.js"></script>
<script type="text/javascript" src="./static/js/management.js"></script>
<script type="text/javascript" src="./static/js/file-system.js"></script>

View File

@ -34,13 +34,12 @@ Digi Demo - Multimedia
<p id="banner-text">ConnectCore Demo</p>
</div>
</a>
<div class="nav-right-container">
<div>
<img src="./static/images/board.png" class="device-title-img" title="Device">
</div>
<div id="device-name">DEY DEVICE</div>
<div class="nav-right-container">
<div>
<img src="./static/images/board.png" class="device-title-img" title="Device">
</div>
<div id="device-name">DEY DEVICE</div>
</div>
</div>
</nav>
@ -69,6 +68,14 @@ Digi Demo - Multimedia
</div>
</a>
</li>
<li id="section_network">
<a data-pjax href="network.html" class="list-group-item list-group-item-action d-flex align-items-center">
<div class="d-flex w-100 justify-content-start align-items-center">
<span class="digi-menu-icon fas fa-network-wired fa-fw fa-lg mr-3"></span>
<span class="menu-collapsed">Network</span>
</div>
</a>
</li>
<li id="section_management">
<a data-pjax href="management.html" class="list-group-item list-group-item-action d-flex align-items-center">
<div class="d-flex w-100 justify-content-start align-items-center">
@ -227,12 +234,14 @@ Digi Demo - Multimedia
<!-- Local JS files and functions -->
<script type="text/javascript" src="./static/js/sidebar.js"></script>
<script type="text/javascript" src="./static/js/ccmp133-dvk.js"></script>
<script type="text/javascript" src="./static/js/ccmp157-dvk.js"></script>
<script type="text/javascript" src="./static/js/ccimx6ulsbc.js"></script>
<script type="text/javascript" src="./static/js/ccimx8mm-dvk.js"></script>
<script type="text/javascript" src="./static/js/ccimx8m-nano.js"></script>
<script type="text/javascript" src="./static/js/ccimx8x-sbc-pro.js"></script>
<script type="text/javascript" src="./static/js/dashboard.js"></script>
<script type="text/javascript" src="./static/js/network.js"></script>
<script type="text/javascript" src="./static/js/multimedia.js"></script>
<script type="text/javascript" src="./static/js/management.js"></script>
<script type="text/javascript" src="./static/js/file-system.js"></script>

View File

@ -0,0 +1,508 @@
<!DOCTYPE html>
<html>
<head>
<title>
Digi Demo - Network
</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="./static/css/stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<link href="./static/css/cdn.jsdelivr.net/gh/gitbrent/bootstrap4-toggle@3.6.1/css/bootstrap4-toggle.min.css" rel="stylesheet">
<link href="./static/css/cdnjs.cloudflare.com/ajax/libs/bootstrap-slider/9.7.3/css/bootstrap-slider.min.css" rel="stylesheet">
<link href="./static/css/fontawesome5.15.4/all.min.css" rel="stylesheet">
<link rel="stylesheet" href="./static/css/general.css">
<link rel="stylesheet" href="./static/css/toastr.css">
<!-- JS, Popper.js, and jQuery -->
<script src="./static/js/code.jquery.com/jquery-3.5.1.min.js" integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0=" crossorigin="anonymous"></script>
<script src="./static/js/cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js" integrity="sha384-9/reFTGAW83EW2RDu2S0VKaIzap3H66lZH81PoYlFhbGU+6BZp6G7niu735Sk7lN" crossorigin="anonymous"></script>
<script src="./static/js/stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js" integrity="sha384-B4gt1jrGC7Jh4AgTPSdUtOBvfO8shuf57BaghqFfPlYxofvL8/KUEfYiJOMMV+rV" crossorigin="anonymous"></script>
<script src="./static/js/cdn.jsdelivr.net/gh/gitbrent/bootstrap4-toggle@3.6.1/js/bootstrap4-toggle.min.js"></script>
<script src="./static/js/cdnjs.cloudflare.com/ajax/libs/bootstrap-slider/9.7.3/bootstrap-slider.min.js"></script>
<script type="text/javascript" src="./static/js/common.js"></script>
<script type="text/javascript" src="./static/js/devices.js"></script>
<script type="text/javascript" src="./static/js/jquery.pjax.js"></script>
<script type="text/javascript" src="./static/js/jquery.matchHeight-min.js"></script>
<script type="text/javascript" src="./static/js/toastr.min.js"></script>
</head>
<body>
<nav id="topBar" class="navbar navbar-expand-lg navbar-light bg-white shadow-sm">
<div class="nav-container">
<a id="banner-link" class="navbar-brand align-middle" href="/">
<div class="d-flex align-items-baseline">
<img id="banner-logo" class="banner-icon" src="./static/images/Digi_logo_banner.png">
<p id="banner-text">ConnectCore Demo</p>
</div>
</a>
<div class="nav-right-container">
<div>
<img src="./static/images/board.png" class="device-title-img" title="Device">
</div>
<div id="device-name">DEY DEVICE</div>
</div>
</div>
</nav>
<div class="bg-light" id="body-row">
<!-- Sidebar https://www.codeply.com/go/3e0RAjccRO/bootstrap-4-collapsing-sidebar-menu# -->
<div id="sidebar-container" class="sidebar-expanded d-none d-md-block">
<!-- d-* hides the Sidebar in smaller devices. Its items can be kept on the Navbar 'Menu' -->
<div id="sidebar-contents">
<!-- Bootstrap List Group -->
<ul id="sections" data-pjax class="list-group">
<li id="section_dashboard">
<a data-pjax href="index.html" class="list-group-item list-group-item-action d-flex align-items-center">
<div class="d-flex w-100 justify-content-start align-items-center">
<span class="digi-menu-icon fas fa-tachometer-alt fa-fw fa-lg mr-3"></span>
<span class="menu-collapsed">Dashboard</span>
</div>
</a>
</li>
<li id="section_multimedia">
<a data-pjax href="multimedia.html" class="list-group-item list-group-item-action d-flex align-items-center">
<div class="d-flex w-100 justify-content-start align-items-center">
<span class="digi-menu-icon fas fa-film fa-fw fa-lg mr-3"></span>
<span class="menu-collapsed">Multimedia</span>
</div>
</a>
</li>
<li id="section_network">
<a data-pjax href="network.html" class="list-group-item list-group-item-action d-flex align-items-center">
<div class="d-flex w-100 justify-content-start align-items-center">
<span class="digi-menu-icon fas fa-network-wired fa-fw fa-lg mr-3"></span>
<span class="menu-collapsed">Network</span>
</div>
</a>
</li>
<li id="section_management">
<a data-pjax href="management.html" class="list-group-item list-group-item-action d-flex align-items-center">
<div class="d-flex w-100 justify-content-start align-items-center">
<span class="digi-menu-icon fas fa-cog fa-fw fa-lg mr-3"></span>
<span class="menu-collapsed">Management</span>
</div>
</a>
</li>
</ul>
<ul id="collapsator" class="list-group">
<a href="#top" data-toggle="sidebar-collapse" class="list-group-item list-group-item-action d-flex align-items-center">
<div class="d-flex w-100 justify-content-start align-items-center">
<span id="collapse-icon" class="digi-menu-icon fas fa-fw fa-lg mr-3"></span>
<span id="collapse-text" class="menu-collapsed">Collapse</span>
</div>
</a>
</ul>
</div>
</div>
<div class="container-fluid">
<div id="loading">
<img id="loading-image" src="./static/images/loading.gif" alt="Loading..." />
</div>
<div id="pjax-container">
<div class="row justify-content-lg-center">
<div class="col-lg-12 col-xl-12">
<div id="loading_popup" class="popup popup-loading shadow">
<img class="popup-item" src="./static/images/loading.gif" alt="Loading..." />
<div id="loading_popup_message" class="popup-text">Loading configuration...</div>
</div>
<div id="info_popup" class="popup popup-info shadow d-none">
<div id="info_popup_title" class="popup-title">Error</div>
<div id="info_popup_message" class="popup-text">-</div>
</div>
<div id="confirm_dialog" class="confirm-dialog d-none">
<div class="device-card-header">
<span class="fas fa-question-circle fa-lg mr-2"></span>
<span id="confirm_dialog_title"></span>
<div class="fas fa-window-close fa-lg device-card-header-button" onclick="showPopup(ID_LOADING_WRAPPER, ID_CONFIRM_DIALOG, false)"></div>
</div>
<div id="confirm_dialog_message" class="confirm-dialog-message"></div>
<div class="confirm-dialog-buttons-container">
<div id="confirm_dialog_no_button" class="device-card-button confirm-dialog-button">No</div>
<div id="confirm_dialog_yes_button" class="device-card-button confirm-dialog-button">Yes</div>
</div>
</div>
<div id="loading_wrapper" class="loading-wrapper">
<div class="card shadow-sm" style="padding: 0px">
<div id="eth0_panel_header" class="interface-header" style="cursor: pointer;" onclick="togglePanelVisibility('eth0')">
<span class="fas fa-ethernet fa-lg mr-2"></span>
<span id="eth0_title" class="card-title interface-title">Ethernet 0</span>
<div id="eth0_toggle_button" class="fas fa-caret-up fa-lg device-card-header-button"></div>
</div>
<div id="eth0_panel_container" class="interface-panel-container">
<div>Configure ethernet parameters.</div>
<div class="param-container">
<span class="param-label">MAC Address:</span>
<span id="eth0_mac" class="param-value"></span>
</div>
<div class="param-container">
<span class="param-label">Connected:</span>
<label class="switch-control">
<input id="eth0_enable" type="checkbox">
<span class="slider-control round"></span>
</label>
</div>
<div id="eth0_ip_mode_param" class="param-container">
<span class="param-label">IP mode:</span>
<select name="eth0_ip_mode" id="eth0_ip_mode" class="select-control">
<option value="static">Static</option>
<option value="dhcp" selected="selected">DHCP</option>
</select>
</div>
<div id="eth0_ip_addr_param" class="param-container">
<span class="param-label">IP address:</span>
<input id="eth0_ip_addr" class="input-control input-control-wide" type="text"/>
<div id="eth0_ip_addr_error" class="error-label"></div>
</div>
<div id="eth0_subnet_mask_param" class="param-container">
<span class="param-label">Subnet mask:</span>
<input id="eth0_subnet_mask" class="input-control input-control-wide" type="text"/>
<div id="eth0_subnet_mask_error" class="error-label"></div>
</div>
<div id="eth0_default_gateway_param" class="param-container">
<span class="param-label">Default gateway:</span>
<input id="eth0_default_gateway" class="input-control input-control-wide" type="text"/>
<div id="eth0_default_gateway_error" class="error-label"></div>
</div>
<div id="eth0_dns1_addr_param" class="param-container">
<span class="param-label">DNS1 address:</span>
<input id="eth0_dns1_addr" class="input-control input-control-wide" type="text"/>
<div id="eth0_dns1_addr_error" class="error-label"></div>
</div>
<div id="eth0_dns2_addr_param" class="param-container">
<span class="param-label">DNS2 address:</span>
<input id="eth0_dns2_addr" class="input-control input-control-wide" type="text"/>
<div id="eth0_dns2_addr_error" class="error-label"></div>
</div>
<div class="buttons-container">
<div id="eth0_refresh_button" class="device-card-button config-button" onclick="readConfiguration(['ethernet'], 'eth0')">Refresh</div>
<div id="eth0_save_button" class="device-card-button config-button config-button-disabled" onclick="saveInterface('ethernet', 'eth0')">Save</div>
</div>
</div>
</div>
<div id="eth1" class="card shadow-sm" style="padding: 0px">
<div id="eth1_panel_header" class="interface-header" style="cursor: pointer;" onclick="togglePanelVisibility('eth1')">
<span class="fas fa-ethernet fa-lg mr-2"></span>
<span id="eth1_title" class="card-title interface-title">Ethernet 1</span>
<div id="eth1_toggle_button" class="fas fa-caret-down fa-lg device-card-header-button"></div>
</div>
<div id="eth1_panel_container" class="interface-panel-container" style="display: none;">
<div>Configure ethernet 1 parameters.</div>
<div class="param-container">
<span class="param-label">MAC Address:</span>
<span id="eth1_mac" class="param-value"></span>
</div>
<div class="param-container">
<span class="param-label">Connected:</span>
<label class="switch-control">
<input id="eth1_enable" type="checkbox">
<span class="slider-control round"></span>
</label>
</div>
<div id="eth1_ip_mode_param" class="param-container">
<span class="param-label">IP mode:</span>
<select name="eth1_ip_mode" id="eth1_ip_mode" class="select-control">
<option value="static">Static</option>
<option value="dhcp" selected="selected">DHCP</option>
</select>
</div>
<div id="eth1_ip_addr_param" class="param-container">
<span class="param-label">IP address:</span>
<input id="eth1_ip_addr" class="input-control input-control-wide" type="text"/>
<div id="eth1_ip_addr_error" class="error-label"></div>
</div>
<div id="eth1_subnet_mask_param" class="param-container">
<span class="param-label">Subnet mask:</span>
<input id="eth1_subnet_mask" class="input-control input-control-wide" type="text"/>
<div id="eth1_subnet_mask_error" class="error-label"></div>
</div>
<div id="eth1_default_gateway_param" class="param-container">
<span class="param-label">Default gateway:</span>
<input id="eth1_default_gateway" class="input-control input-control-wide" type="text"/>
<div id="eth1_default_gateway_error" class="error-label"></div>
</div>
<div id="eth1_dns1_addr_param" class="param-container">
<span class="param-label">DNS1 address:</span>
<input id="eth1_dns1_addr" class="input-control input-control-wide" type="text"/>
<div id="eth1_dns1_addr_error" class="error-label"></div>
</div>
<div id="eth1_dns2_addr_param" class="param-container">
<span class="param-label">DNS2 address:</span>
<input id="eth1_dns2_addr" class="input-control input-control-wide" type="text"/>
<div id="eth1_dns2_addr_error" class="error-label"></div>
</div>
<div class="buttons-container">
<div id="eth1_refresh_button" class="device-card-button config-button" onclick="readConfiguration(['ethernet'], 'eth1')">Refresh</div>
<div id="eth1_save_button" class="device-card-button config-button config-button-disabled" onclick="saveInterface('ethernet', 'eth1')">Save</div>
</div>
</div>
</div>
<div id="wlan0" class="card shadow-sm" style="padding: 0px;">
<div id="wlan0_panel_header" class="interface-header" style="cursor: pointer;" onclick="togglePanelVisibility('wlan0')">
<span class="fas fa-wifi fa-lg mr-2"></span>
<span id="wlan0_title" class="card-title interface-title">Wi-Fi</span>
<div id="wlan0_toggle_button" class="fas fa-caret-down fa-lg device-card-header-button"></div>
</div>
<div id="wlan0_panel_container" class="interface-panel-container" style="display: none;">
<div>Configure wifi parameters.</div>
<div class="param-container">
<span class="param-label">MAC Address:</span>
<span id="wlan0_mac" class="param-value"></span>
</div>
<div class="param-container">
<span class="param-label">Connected:</span>
<label class="switch-control">
<input id="wlan0_enable" type="checkbox">
<span class="slider-control round"></span>
</label>
</div>
<div id="wlan0_ssid_param" class="param-container">
<span class="param-label">SSID:</span>
<input id="wlan0_ssid" class="input-control input-control-wide" type="text"/>
<div id="wlan0_ssid_error" class="error-label"></div>
</div>
<div id="wlan0_enc_type_param" class="param-container">
<span class="param-label">Encryption type:</span>
<select name="wlan0_enc_type" id="wlan0_enc_type" class="select-control">
<option value="0">Open</option>
<option value="1">WPA</option>
<option value="2">WPA2</option>
<option value="3">WPA3</option>
</select>
</div>
<div id="wlan0_password_param" class="param-container">
<span class="param-label">Password:</span>
<input id="wlan0_password" class="input-control input-control-wide" type="password"/>
<div id="wlan0_password_error" class="error-label"></div>
</div>
<div id="wlan0_ip_mode_param" class="param-container">
<span class="param-label">IP mode:</span>
<select name="wlan0_ip_mode" id="wlan0_ip_mode" class="select-control">
<option value="static">Static</option>
<option value="dhcp" selected="selected">DHCP</option>
</select>
</div>
<div id="wlan0_ip_addr_param" class="param-container">
<span class="param-label">IP address:</span>
<input id="wlan0_ip_addr" class="input-control input-control-wide" type="text"/>
<div id="wlan0_ip_addr_error" class="error-label"></div>
</div>
<div id="wlan0_subnet_mask_param" class="param-container">
<span class="param-label">Subnet mask:</span>
<input id="wlan0_subnet_mask" class="input-control input-control-wide" type="text"/>
<div id="wlan0_subnet_mask_error" class="error-label"></div>
</div>
<div id="wlan0_default_gateway_param" class="param-container">
<span class="param-label">Default gateway:</span>
<input id="wlan0_default_gateway" class="input-control input-control-wide" type="text"/>
<div id="wlan0_default_gateway_error" class="error-label"></div>
</div>
<div id="wlan0_dns1_addr_param" class="param-container">
<span class="param-label">DNS1 address:</span>
<input id="wlan0_dns1_addr" class="input-control input-control-wide" type="text"/>
<div id="wlan0_dns1_addr_error" class="error-label"></div>
</div>
<div id="wlan0_dns2_addr_param" class="param-container">
<span class="param-label">DNS2 address:</span>
<input id="wlan0_dns2_addr" class="input-control input-control-wide" type="text"/>
<div id="wlan0_dns2_addr_error" class="error-label"></div>
</div>
<div class="buttons-container">
<div id="wlan0_refresh_button" class="device-card-button config-button" onclick="readConfiguration(['wifi'], 'wlan0')">Refresh</div>
<div id="wlan0_save_button" class="device-card-button config-button config-button-disabled" onclick="saveInterface('wifi', 'wlan0')">Save</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
$(document).ready(function() {
// Reset variables.
readingNetworkInfo = false;
// Register input changed events.
$('#eth0_enable').click(function(){
updateInterfaceControls("eth0");
});
$("#eth0_ip_mode").on("change", function(event) {
updateInterfaceControls("eth0");
});
$("#eth0_ip_addr").on("input", function(event) {
validateInterface("eth0");
});
$("#eth0_subnet_mask").on("input", function(event) {
validateInterface("eth0");
});
$("#eth0_default_gateway").on("input", function(event) {
validateInterface("eth0");
});
$("#eth0_dns1_addr").on("input", function(event) {
validateInterface("eth0");
});
$("#eth0_dns2_addr").on("input", function(event) {
validateInterface("eth0");
});
$('#eth1_enable').click(function(){
updateInterfaceControls("eth1");
});
$("#eth1_ip_mode").on("change", function(event) {
updateInterfaceControls("eth1");
});
$("#eth1_ip_addr").on("input", function(event) {
validateInterface("eth1");
});
$("#eth1_subnet_mask").on("input", function(event) {
validateInterface("eth1");
});
$('#eth1_enable').click(function(){
updateInterfaceControls("eth1");
});
$("#eth1_ip_mode").on("change", function(event) {
updateInterfaceControls("eth1");
});
$("#eth1_ip_addr").on("input", function(event) {
validateInterface("eth1");
});
$("#eth1_subnet_mask").on("input", function(event) {
validateInterface("eth1");
});
$("#eth1_default_gateway").on("input", function(event) {
validateInterface("eth1");
});
$("#eth1_dns1_addr").on("input", function(event) {
validateInterface("eth1");
});
$("#eth1_dns2_addr").on("input", function(event) {
validateInterface("eth1");
});
$('#wlan0_enable').click(function(){
updateInterfaceControls("wlan0");
});
$("#wlan0_ssid").on("input", function(event) {
validateInterface("wlan0");
});
$("#wlan0_enc_type").on("change", function(event) {
document.getElementById("wlan0_password").value = "";
passwordChanged = true;
updateInterfaceControls("wlan0");
});
$("#wlan0_password").on("input", function(event) {
passwordChanged = true;
validateInterface("wlan0");
});
$("#wlan0_ip_mode").on("change", function(event) {
updateInterfaceControls("wlan0");
});
$("#wlan0_ip_addr").on("input", function(event) {
validateInterface("wlan0");
});
$("#wlan0_subnet_mask").on("input", function(event) {
validateInterface("wlan0");
});
$("#wlan0_default_gateway").on("input", function(event) {
validateInterface("wlan0");
});
$("#wlan0_dns1_addr").on("input", function(event) {
validateInterface("wlan0");
});
$("#wlan0_dns2_addr").on("input", function(event) {
validateInterface("wlan0");
});
// Gray out page.
document.getElementById("loading_wrapper").classList.add("element-grayed");
// Update all controls.
updateAllControls();
// Initialize page.
initializeNetworkPage();
});
</script>
</div> <!-- pjax-container -->
</div> <!-- container fluid -->
</div> <!--bg light -->
<script>
$(document).ready(function() {
$("#banner-link").on({
"mouseover" : function() {
$("#banner-logo").attr("src", "./static/images/Digi_logo_banner_gray.png");
},
"mouseout" : function() {
$("#banner-logo").attr("src", "./static/images/Digi_logo_banner.png");
}
});
});
// Enable the tooltip library.
$(function() {
$('[data-toggle="tooltip"]').tooltip();
});
</script>
<!-- Local JS files and functions -->
<script type="text/javascript" src="./static/js/sidebar.js"></script>
<script type="text/javascript" src="./static/js/ccmp157-dvk.js"></script>
<script type="text/javascript" src="./static/js/ccimx6ulsbc.js"></script>
<script type="text/javascript" src="./static/js/ccimx8mm-dvk.js"></script>
<script type="text/javascript" src="./static/js/ccimx8m-nano.js"></script>
<script type="text/javascript" src="./static/js/ccimx8x-sbc-pro.js"></script>
<script type="text/javascript" src="./static/js/dashboard.js"></script>
<script type="text/javascript" src="./static/js/network.js"></script>
<script type="text/javascript" src="./static/js/multimedia.js"></script>
<script type="text/javascript" src="./static/js/management.js"></script>
<script type="text/javascript" src="./static/js/file-system.js"></script>
<script>
$(document).ready(function() {
// Don't show the loading spinner at the beginning. Initial page
// load is full, so not relying on AJAX.
$("#loading").hide();
// Set up PJAX.
if ($.support.pjax) {
$.pjax.defaults.timeout = 20000;
$.pjax.defaults.fragment = "#pjax-container";
$(document).pjax("a[data-pjax]", "#pjax-container");
$(document).on("pjax:beforeSend", function() {
// Do not load new content if there are unsaved changes.
if ($("#save-schedule").length && !$("#save-schedule").attr("disabled") && !confirm("There are unsaved changes. Do you want to exit?"))
return false;
});
$(document).on("pjax:send", function(e) {
setSelectedSection(e.currentTarget.activeElement);
$("#pjax-container").hide();
$("#loading").show();
});
$(document).on("pjax:complete", function() {
$("#loading").hide();
$("#pjax-container").show();
});
}
// Append the URL parameters to the section links.
var params = new URLSearchParams(window.location.search).toString();
if (params) {
$("#sections li").each(function(i, n) {
n.children[0].href += "?" + params;
});
}
// Update available sections.
updateAvailableSections();
// Set the selected section.
setSelectedSection();
});
</script>
</body>
</html>

View File

@ -373,7 +373,7 @@ body {
/* POPUP */
.popup {
z-index: 999;
position: absolute;
position: fixed;
transform: translate(-50%, -50%);
background-color: white;
padding: 20px 10px;
@ -1058,11 +1058,24 @@ body {
/* AUDIO */
.audio-panel {
width: 350px;
width: 280px;
}
#audio_panel .slider-horizontal {
width: 180px;
width: 110px;
}
.audio-button {
width: 32px;
height: 32px;
font-size: 24px;
text-align: center;
z-index: 99999;
}
.audio-button:hover {
cursor: pointer;
color: var(--digi-green);
}
/* END AUDIO */
@ -1869,20 +1882,25 @@ body {
}
/* END MULTIMEDIA VIEWER */
/* MANAGEMENT */
.system-monitor-param-container {
/* CONFIG CONTROLS */
.param-container {
margin-top: 10px;
width: 100%;
padding-left: 10px;
}
.system-monitor-param-label {
.param-label {
display: inline-block;
position: relative;
width: 170px;
}
.system-monitor-input {
.param-value {
display: inline-block;
position: relative;
}
.input-control {
position: relative;
-webkit-transition: none !important;
-moz-transition: none !important;
@ -1892,13 +1910,100 @@ body {
width: 80px !important;
padding: 0px !important;
margin: 0px !important;
text-align: left !important;
padding-left: 5px !important;
}
.system-monitor-input-error {
.input-control-wide {
width: 180px !important;
}
.input-control-error {
background-color: #f3b1b1 !important;
}
.system-monitor-error {
.input-control-disabled {
background-color: transparent !important;
border: none !important;
pointer-events: none !important;
color: #939393 !important;
}
.select-control {
position: relative;
-webkit-transition: none !important;
-moz-transition: none !important;
-ms-transition: none !important;
-o-transition: none !important;
transition: none !important;
width: 80px !important;
padding: 0px !important;
margin: 0px !important;
text-align-last: left !important;
padding-left: 5px !important;
}
.switch-control {
position: relative;
display: inline-block;
width: 48px;
height: 22px;
margin-bottom: 0px;
}
.switch-control input {
opacity: 0;
width: 0;
height: 0;
}
.slider-control {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
-webkit-transition: .4s;
transition: .4s;
}
.slider-control:before {
position: absolute;
content: "";
height: 16px;
width: 16px;
left: 3px;
bottom: 3px;
background-color: white;
-webkit-transition: .4s;
transition: .4s;
}
input:checked + .slider-control {
background-color: #2196F3;
}
input:focus + .slider-control {
box-shadow: 0 0 1px #2196F3;
}
input:checked + .slider-control:before {
-webkit-transform: translateX(26px);
-ms-transform: translateX(26px);
transform: translateX(26px);
}
.slider-control.round {
border-radius: 11px;
}
.slider-control.round:before {
border-radius: 50%;
}
.error-label {
color: red;
font-size: 12px;
font-style: italic;
@ -1906,6 +2011,67 @@ body {
padding-left: 10px;
}
.buttons-container {
with: 100%;
position: relative;
}
.config-button {
padding: 5px;
cursor: pointer;
margin-bottom: 0;
margin-top: 15px;
width: 100px;
float: left;
margin-left: 10px;
}
.config-button-disabled {
cursor: default;
color: white;
background-color: #c3c3c3;
pointer-events: none;
}
input[type=text], input[type=password], select {
background-color: #f6f6f6;
border: none;
color: #0d0d0d;
padding: 12px 30px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 14px;
margin: 0px 0px 25px 0px;
width: 85%;
border: 2px solid #f6f6f6;
-webkit-transition: all 0.5s ease-in-out;
-moz-transition: all 0.5s ease-in-out;
-ms-transition: all 0.5s ease-in-out;
-o-transition: all 0.5s ease-in-out;
transition: all 0.5s ease-in-out;
-webkit-border-radius: 5px 5px 5px 5px;
border-radius: 5px 5px 5px 5px;
}
input[type=text]:focus, input[type=password]:focus, select:focus {
background-color: #fff;
border-bottom: 2px solid var(--digi-green);
}
select {
-moz-appearance:none; /* Firefox */
-webkit-appearance:none; /* Safari and Chrome */
appearance:none;
text-align-last: center;
background-image: url("../images/combo_arrow_gray.png");
background-repeat: no-repeat, repeat;
background-position: right .7em top 50%;
background-size: .65em auto;
}
/* END CONFIG CONTROLS */
/* MANAGEMENT */
.system-monitor-help {
font-size: 16px;
padding-left: 5px;
@ -1927,21 +2093,6 @@ body {
outline: none;
}
.system-monitor-save {
padding: 5px;
cursor: pointer;
margin-bottom: 0;
margin-top: 15px;
width: 100px;
}
.system-monitor-save-disabled {
cursor: default;
color: white;
background-color: #c3c3c3;
pointer-events: none;
}
.firmware-file-input {
position: relative;
margin-top: 15px;
@ -1996,13 +2147,6 @@ body {
background-color: #a72a2a;
}
.management-button-disabled {
cursor: default;
color: #c3c3c3;
background-color: #e3e3e3;
pointer-events: none;
}
.update-firmware-progress {
position: relative;
margin-top: 15px;
@ -2196,3 +2340,20 @@ body {
margin-top: 5px;
}
/* END MANAGEMENT */
/* NETWORK */
.interface-header {
padding: 15px 20px 10px 20px;
align-items: center;
font-size: 16px;
font-weight: bold;
}
.interface-panel-container {
padding: 0px 20px 15px 20px;
}
.interface-title {
font-size: 1.25em;
}
/* END NETWORK */

0
connectcore-demo-example/static/images/board.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 337 B

After

Width:  |  Height:  |  Size: 337 B

View File

Before

Width:  |  Height:  |  Size: 564 KiB

After

Width:  |  Height:  |  Size: 564 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

View File

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 1.6 MiB

0
connectcore-demo-example/static/images/led_bubble.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View File

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 11 KiB

View File

@ -110,17 +110,17 @@ class CCIMX6ULSBC extends ConnectCoreDevice {
VIDEO_COMPONENT_AREA_WIDTH_PERCENT = 21;
VIDEO_COMPONENT_AREA_HEIGHT_PERCENT = 8;
AUDIO_COMPONENT_VISIBLE = false;
AUDIO_COMPONENT_VISIBLE = true;
AUDIO_COMPONENT_HAS_PANEL = true;
AUDIO_COMPONENT_HAS_ARROW = true;
AUDIO_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
AUDIO_COMPONENT_PANEL_ORIENTATION = VALUE_BOTTOM;
AUDIO_COMPONENT_PANEL_HORIZONTAL_PERCENT = 51;
AUDIO_COMPONENT_PANEL_VERTICAL_PERCENT = 28;
AUDIO_COMPONENT_ARROW_PERCENT = 69;
AUDIO_COMPONENT_PANEL_ORIENTATION = VALUE_LEFT;
AUDIO_COMPONENT_PANEL_HORIZONTAL_PERCENT = 76.5;
AUDIO_COMPONENT_PANEL_VERTICAL_PERCENT = 76;
AUDIO_COMPONENT_ARROW_PERCENT = 81.5;
AUDIO_COMPONENT_AREA_TOP_PERCENT = 74;
AUDIO_COMPONENT_AREA_LEFT_PERCENT = 66;
AUDIO_COMPONENT_AREA_WIDTH_PERCENT = 9.3;
AUDIO_COMPONENT_AREA_WIDTH_PERCENT = 9.5;
AUDIO_COMPONENT_AREA_HEIGHT_PERCENT = 18.5;
LED_COMPONENT_VISIBLE = true;

View File

@ -0,0 +1,147 @@
/*
* Copyright 2022, Digi International Inc.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
class CCMP133 extends ConnectCoreDevice {
// Public constants.
static DEVICE_TYPE = "ccmp133-dvk";
static PLATFORM_NAME = "ConnectCore MP133";
// Variables.
BOARD_IMAGE = "ccmp133_board.png";
BOARD_IMAGE_SCALE = 82;
CPU_COMPONENT_VISIBLE = true;
CPU_COMPONENT_HAS_PANEL = true;
CPU_COMPONENT_HAS_ARROW = true;
CPU_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
CPU_COMPONENT_PANEL_ORIENTATION = VALUE_RIGHT;
CPU_COMPONENT_PANEL_HORIZONTAL_PERCENT = 68.5;
CPU_COMPONENT_PANEL_VERTICAL_PERCENT = 45;
CPU_COMPONENT_ARROW_PERCENT = 54.5;
CPU_COMPONENT_AREA_TOP_PERCENT = 50;
CPU_COMPONENT_AREA_LEFT_PERCENT = 32.9;
CPU_COMPONENT_AREA_WIDTH_PERCENT = 10;
CPU_COMPONENT_AREA_HEIGHT_PERCENT = 13;
MEMORY_COMPONENT_VISIBLE = true;
MEMORY_COMPONENT_HAS_PANEL = true;
MEMORY_COMPONENT_HAS_ARROW = true;
MEMORY_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
MEMORY_COMPONENT_PANEL_ORIENTATION = VALUE_BOTTOM;
MEMORY_COMPONENT_PANEL_HORIZONTAL_PERCENT = 25;
MEMORY_COMPONENT_PANEL_VERTICAL_PERCENT = 67.5;
MEMORY_COMPONENT_ARROW_PERCENT = 37;
MEMORY_COMPONENT_AREA_TOP_PERCENT = 34.5;
MEMORY_COMPONENT_AREA_LEFT_PERCENT = 31.1;
MEMORY_COMPONENT_AREA_WIDTH_PERCENT = 15.4;
MEMORY_COMPONENT_AREA_HEIGHT_PERCENT = 15.5;
WIFI_BT_COMPONENT_VISIBLE = true;
WIFI_BT_COMPONENT_HAS_PANEL = true;
WIFI_BT_COMPONENT_HAS_ARROW = true;
WIFI_BT_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
WIFI_BT_COMPONENT_PANEL_ORIENTATION = VALUE_LEFT;
WIFI_BT_COMPONENT_PANEL_HORIZONTAL_PERCENT = 55;
WIFI_BT_COMPONENT_PANEL_VERTICAL_PERCENT = 28;
WIFI_BT_COMPONENT_ARROW_PERCENT = 43.5;
WIFI_BT_COMPONENT_AREA_TOP_PERCENT = 41;
WIFI_BT_COMPONENT_AREA_LEFT_PERCENT = 46.7;
WIFI_BT_COMPONENT_AREA_WIDTH_PERCENT = 6.8;
WIFI_BT_COMPONENT_AREA_HEIGHT_PERCENT = 9;
ETHERNET0_COMPONENT_VISIBLE = true;
ETHERNET0_COMPONENT_HAS_PANEL = true;
ETHERNET0_COMPONENT_HAS_ARROW = true;
ETHERNET0_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
ETHERNET0_COMPONENT_PANEL_ORIENTATION = VALUE_BOTTOM;
ETHERNET0_COMPONENT_PANEL_HORIZONTAL_PERCENT = -3;
ETHERNET0_COMPONENT_PANEL_VERTICAL_PERCENT = 73;
ETHERNET0_COMPONENT_ARROW_PERCENT = 8;
ETHERNET0_COMPONENT_AREA_TOP_PERCENT = 29;
ETHERNET0_COMPONENT_AREA_LEFT_PERCENT = 3.8;
ETHERNET0_COMPONENT_AREA_WIDTH_PERCENT = 12.2;
ETHERNET0_COMPONENT_AREA_HEIGHT_PERCENT = 12.5;
CONSOLE_COMPONENT_VISIBLE = true;
CONSOLE_COMPONENT_HAS_PANEL = false;
CONSOLE_COMPONENT_HAS_ARROW = false;
CONSOLE_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
CONSOLE_COMPONENT_AREA_TOP_PERCENT = 79.9;
CONSOLE_COMPONENT_AREA_LEFT_PERCENT = 90.5;
CONSOLE_COMPONENT_AREA_WIDTH_PERCENT = 3.3;
CONSOLE_COMPONENT_AREA_HEIGHT_PERCENT = 6.2;
VIDEO_COMPONENT_VISIBLE = true;
VIDEO_COMPONENT_HAS_PANEL = true;
VIDEO_COMPONENT_HAS_ARROW = true;
VIDEO_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
VIDEO_COMPONENT_PANEL_ORIENTATION = VALUE_TOP;
VIDEO_COMPONENT_PANEL_HORIZONTAL_PERCENT = 55;
VIDEO_COMPONENT_PANEL_VERTICAL_PERCENT = 16;
VIDEO_COMPONENT_ARROW_PERCENT = 72.8;
VIDEO_COMPONENT_AREA_TOP_PERCENT = 4.8;
VIDEO_COMPONENT_AREA_LEFT_PERCENT = 70.2;
VIDEO_COMPONENT_AREA_WIDTH_PERCENT = 8.6;
VIDEO_COMPONENT_AREA_HEIGHT_PERCENT = 9.1;
AUDIO_COMPONENT_VISIBLE = true;
AUDIO_COMPONENT_HAS_PANEL = true;
AUDIO_COMPONENT_HAS_ARROW = true;
AUDIO_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
AUDIO_COMPONENT_PANEL_ORIENTATION = VALUE_TOP;
AUDIO_COMPONENT_PANEL_HORIZONTAL_PERCENT = 81;
AUDIO_COMPONENT_PANEL_VERTICAL_PERCENT = 37;
AUDIO_COMPONENT_ARROW_PERCENT = 87;
AUDIO_COMPONENT_AREA_TOP_PERCENT = 28;
AUDIO_COMPONENT_AREA_LEFT_PERCENT = 83.5;
AUDIO_COMPONENT_AREA_WIDTH_PERCENT = 10.2;
AUDIO_COMPONENT_AREA_HEIGHT_PERCENT = 7;
LED_COMPONENT_VISIBLE = true;
LED_COMPONENT_HAS_PANEL = true;
LED_COMPONENT_HAS_ARROW = false;
LED_COMPONENT_PANEL_ALWAYS_VISIBLE = true;
LED_COMPONENT_PANEL_ORIENTATION = VALUE_BOTTOM;
LED_COMPONENT_PANEL_HORIZONTAL_PERCENT = 69;
LED_COMPONENT_PANEL_VERTICAL_PERCENT = 10;
LED_COMPONENT_AREA_TOP_PERCENT = 91;
LED_COMPONENT_AREA_LEFT_PERCENT = 70.6;
LED_COMPONENT_AREA_WIDTH_PERCENT = 1.8;
LED_COMPONENT_AREA_HEIGHT_PERCENT = 4;
FLASH_MEMORY_COMPONENT_VISIBLE = true;
FLASH_MEMORY_COMPONENT_HAS_PANEL = true;
FLASH_MEMORY_COMPONENT_HAS_ARROW = true;
FLASH_MEMORY_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
FLASH_MEMORY_COMPONENT_PANEL_ORIENTATION = VALUE_TOP;
FLASH_MEMORY_COMPONENT_PANEL_HORIZONTAL_PERCENT = 27;
FLASH_MEMORY_COMPONENT_PANEL_VERTICAL_PERCENT = 65;
FLASH_MEMORY_COMPONENT_ARROW_PERCENT = 46.7;
FLASH_MEMORY_COMPONENT_AREA_TOP_PERCENT = 50;
FLASH_MEMORY_COMPONENT_AREA_LEFT_PERCENT = 43.5;
FLASH_MEMORY_COMPONENT_AREA_WIDTH_PERCENT = 10;
FLASH_MEMORY_COMPONENT_AREA_HEIGHT_PERCENT = 13;
// Capabilities
SUPPORTS_VIDEO_BRIGHTNESS = false;
SUPPORTS_DUAL_ETHERNET = false;
// Constructor.
constructor(deviceData) {
super(CCMP133.DEVICE_TYPE, CCMP133.PLATFORM_NAME, deviceData);
}
}

View File

@ -97,18 +97,18 @@ class CCMP157 extends ConnectCoreDevice {
VIDEO_COMPONENT_AREA_WIDTH_PERCENT = 8.6;
VIDEO_COMPONENT_AREA_HEIGHT_PERCENT = 9.1;
AUDIO_COMPONENT_VISIBLE = false;
AUDIO_COMPONENT_VISIBLE = true;
AUDIO_COMPONENT_HAS_PANEL = true;
AUDIO_COMPONENT_HAS_ARROW = true;
AUDIO_COMPONENT_PANEL_ALWAYS_VISIBLE = false;
AUDIO_COMPONENT_PANEL_ORIENTATION = VALUE_TOP;
AUDIO_COMPONENT_PANEL_HORIZONTAL_PERCENT = 1;
AUDIO_COMPONENT_PANEL_VERTICAL_PERCENT = 19;
AUDIO_COMPONENT_ARROW_PERCENT = 16;
AUDIO_COMPONENT_AREA_TOP_PERCENT = 7;
AUDIO_COMPONENT_AREA_LEFT_PERCENT = 14.5;
AUDIO_COMPONENT_AREA_WIDTH_PERCENT = 5.4;
AUDIO_COMPONENT_AREA_HEIGHT_PERCENT = 11;
AUDIO_COMPONENT_PANEL_HORIZONTAL_PERCENT = 81;
AUDIO_COMPONENT_PANEL_VERTICAL_PERCENT = 37;
AUDIO_COMPONENT_ARROW_PERCENT = 87;
AUDIO_COMPONENT_AREA_TOP_PERCENT = 28;
AUDIO_COMPONENT_AREA_LEFT_PERCENT = 83.5;
AUDIO_COMPONENT_AREA_WIDTH_PERCENT = 10.2;
AUDIO_COMPONENT_AREA_HEIGHT_PERCENT = 7;
LED_COMPONENT_VISIBLE = true;
LED_COMPONENT_HAS_PANEL = true;

View File

@ -42,6 +42,7 @@ const ID_CPU_TEMPERATURE = "cpu_temperature";
const ID_CPU_UPTIME = "cpu_uptime";
const ID_CURRENT_DIR = "current_dir";
const ID_DATA = "data";
const ID_DESC = "desc";
const ID_DEVICE_NAME = "device-name";
const ID_DEVICE_TYPE = "device_type";
const ID_DEVICES = "devices";
@ -133,18 +134,31 @@ const VALUE_SUCCESSFUL = "successful";
const VALUE_TOP = "top";
const VALUE_UNKNOWN = "unknown";
const CLASS_ARROW_DOWN = "fa-caret-down";
const CLASS_ARROW_UP = "fa-caret-up";
const CLASS_D_NONE = "d-none";
const CLASS_DISABLED_DIV = "disabled-div";
const CLASS_ELEMENT_GRAYED = "element-grayed";
const CLASS_INPUT_DISABLED = "input-control-disabled";
const CLASS_INPUT_ERROR = "input-control-error";
const CLASS_CONFIG_BUTTON_DISABLED = "config-button-disabled";
const CLASS_SELECTED = "selected";
const CLASS_VALUE_ANIMATION = "value-animation";
const CLASS_VALUE_UPDATED = "value-updated";
const ERROR_ABORTED = "Operation aborted";
const ERROR_BAD_REQUEST = "Bad request";
const ERROR_FIELD_EMPTY = "Field cannot be empty";
const ERROR_FORBIDDEN = "Could not perform the selected action. Make sure you have the correct access rights.";
const ERROR_URL_NOT_FOUND = "Requested URL not found";
const ERROR_SERVER_ERROR = "Internal server error";
const ERROR_TITLE = "Error";
const ERROR_UNKNOWN_ERROR = "Unknown error";
const ERROR_UNKNOWN_ERROR = "Unknown error. Make sure that the server is running.";
const IFACE_BT = "hci0";
const IFACE_ETH0 = "eth0";
const IFACE_ETH1 = "eth1";
const IFACE_WIFI = "wlan0";
const PREFIX_STREAM = "system_monitor/";
const STREAM_CPU_LOAD = PREFIX_STREAM + "cpu_load";
@ -237,8 +251,10 @@ function processAjaxErrorResponse(response) {
errorMessage = response.responseJSON[ID_ERROR];
// Show the error message (if any).
if (errorMessage == null)
errorMessage = ERROR_UNKNOWN_ERROR;
} else if (response.status == 404)
errorMessage = ERROR_BAD_REQUEST;
} else if (response.status == 403)
errorMessage = ERROR_FORBIDDEN;
else if (response.status == 404)
errorMessage = ERROR_URL_NOT_FOUND;
else if (response.status == 500)
errorMessage = ERROR_SERVER_ERROR;
@ -475,6 +491,11 @@ function isDashboardShowing() {
return window.location.pathname.indexOf("index") > -1;
}
// Returns whether the network page is showing or not.
function isNetworkShowing() {
return window.location.pathname.indexOf("network") > -1;
}
// Returns whether the management page is showing or not.
function isManagementShowing() {
return window.location.pathname.indexOf("management") > -1;
@ -522,4 +543,4 @@ function removeSection(sectionID) {
var sectionElement = document.getElementById(sectionID);
if (sectionElement != null && sectionElement != "undefined")
sectionElement.parentNode.removeChild(sectionElement);
}
}

View File

@ -12,6 +12,8 @@
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Music by https://www.bensound.com
*/
// Constants.
@ -55,6 +57,7 @@ const ID_MEMORY_PANEL_AREA = "memory_panel_area";
const ID_MEMORY_PANEL_ARROW = "memory_panel_arrow";
const ID_MEMORY_PANEL_ICON = "memory_panel_icon";
const ID_PLATFORM_NAME = "platform_name";
const ID_PLAY = "play";
const ID_VIDEO_BRIGHTNESS_CONTAINER = "video_brightness_container";
const ID_VIDEO_PANEL = "video_panel";
const ID_VIDEO_PANEL_AREA = "video_panel_area";
@ -66,36 +69,29 @@ const ID_WIFI_BT_PANEL_AREA = "wifi_bt_panel_area";
const ID_WIFI_BT_PANEL_ARROW = "wifi_bt_panel_arrow";
const ID_WIFI_BT_PANEL_ICON = "wifi_bt_panel_icon";
const IFACE_BT = "hci0/";
const IFACE_ETHERNET0 = "eth0/";
const IFACE_ETHERNET1 = "eth1/";
const IFACE_WIFI = "wlan0/";
const USER_LED = "user_led";
const STREAM_CPU_FREQUENCY = PREFIX_STREAM + "frequency";
const STREAM_CPU_TEMPERATURE = PREFIX_STREAM + "cpu_temperature";
const STREAM_CPU_UPTIME = PREFIX_STREAM + "uptime";
const STREAM_ETHERNET0_READ_BYTES = PREFIX_STREAM + IFACE_ETHERNET0 + "rx_bytes";
const STREAM_ETHERNET0_SENT_BYTES = PREFIX_STREAM + IFACE_ETHERNET0 + "tx_bytes";
const STREAM_ETHERNET0_STATE = PREFIX_STREAM + IFACE_ETHERNET0 + "state";
const STREAM_ETHERNET1_READ_BYTES = PREFIX_STREAM + IFACE_ETHERNET1 + "rx_bytes";
const STREAM_ETHERNET1_SENT_BYTES = PREFIX_STREAM + IFACE_ETHERNET1 + "tx_bytes";
const STREAM_ETHERNET1_STATE = PREFIX_STREAM + IFACE_ETHERNET1 + "state";
const STREAM_ETHERNET0_READ_BYTES = PREFIX_STREAM + IFACE_ETH0 + "/rx_bytes";
const STREAM_ETHERNET0_SENT_BYTES = PREFIX_STREAM + IFACE_ETH0 + "/tx_bytes";
const STREAM_ETHERNET0_STATE = PREFIX_STREAM + IFACE_ETH0 + "/state";
const STREAM_ETHERNET1_READ_BYTES = PREFIX_STREAM + IFACE_ETH1 + "/rx_bytes";
const STREAM_ETHERNET1_SENT_BYTES = PREFIX_STREAM + IFACE_ETH1 + "/tx_bytes";
const STREAM_ETHERNET1_STATE = PREFIX_STREAM + IFACE_ETH1 + "/state";
const STREAM_LED_STATUS = PREFIX_STREAM + "led_status";
const STREAM_MEMORY_USED = PREFIX_STREAM + "used_memory";
const STREAM_WIFI_READ_BYTES = PREFIX_STREAM + IFACE_WIFI + "rx_bytes";
const STREAM_WIFI_SENT_BYTES = PREFIX_STREAM + IFACE_WIFI + "tx_bytes";
const STREAM_WIFI_STATE = PREFIX_STREAM + IFACE_WIFI + "state";
const STREAM_BT_READ_BYTES = PREFIX_STREAM + IFACE_BT + "rx_bytes";
const STREAM_BT_SENT_BYTES = PREFIX_STREAM + IFACE_BT + "tx_bytes";
const STREAM_BT_STATE = PREFIX_STREAM + IFACE_BT + "state";
const STREAM_WIFI_READ_BYTES = PREFIX_STREAM + IFACE_WIFI + "/rx_bytes";
const STREAM_WIFI_SENT_BYTES = PREFIX_STREAM + IFACE_WIFI + "/tx_bytes";
const STREAM_WIFI_STATE = PREFIX_STREAM + IFACE_WIFI + "/state";
const STREAM_BT_READ_BYTES = PREFIX_STREAM + IFACE_BT + "/rx_bytes";
const STREAM_BT_SENT_BYTES = PREFIX_STREAM + IFACE_BT + "/tx_bytes";
const STREAM_BT_STATE = PREFIX_STREAM + IFACE_BT + "/state";
const PANEL_ARROW_WIDTH_100 = 20;
const PANEL_BOARD_WIDTH_100 = 1200;
const CLASS_ARROW_DOWN = "fa-caret-down";
const CLASS_ARROW_UP = "fa-caret-up";
const CLASS_LED_PANEL_AREA_ON = "led-panel-area-on";
const CLASS_PANEL_AREA_SELECTED = "panel-area-selected";
const CLASS_PANEL_AREA_ICON_SELECTED = "panel-area-icon-selected";
@ -103,6 +99,9 @@ const CLASS_PANEL_TOOLTIP = "panel-tooltip";
const MESSAGE_CHANGING_VIDEO_BRIGHTNESS = "Changing video brightness...";
const MESSAGE_CHANGING_AUDIO_VOLUME = "Changing audio volume...";
const MESSAGE_MUSIC_PLAYING = "Music playing..."
const MESSAGE_MUSIC_STOPPED = "Music stopped."
const MESSAGE_PLAY_MUSIC = "Setting play music value..."
const MESSAGE_READING_DEVICE_INFO = "Reading device info...";
const MESSAGE_READING_DEVICE_STATUS = "Reading device status...";
const MESSAGE_TOGGLING_LED_VALUE = "Toggling LED value...";
@ -111,6 +110,8 @@ const ERROR_LED_UNKNOWN = "LED status has not been read yet, please wait.";
const ERROR_NOT_SUPPORTED_DEVICE_MESSAGE = "The selected device type is not supported: {0}";
const ERROR_NOT_SUPPORTED_DEVICE_TITLE = "Unsupported device";
const MUSIC_FILE = "/srv/www/static/sounds/inspire.mp3"
// Variables.
var deviceInitialized = false;
var device = null;
@ -239,6 +240,7 @@ function processDeviceInfoResponse(response) {
// Position components after some time to give time to the image to load.
window.setTimeout(function () {
positionComponents();
adjustImageSize();
setInfoPanelsVisible(false);
}, 500);
// Read device status.
@ -368,6 +370,9 @@ function createDevice(deviceData) {
case CCMP157.DEVICE_TYPE:
device = new CCMP157(deviceData);
break;
case CCMP133.DEVICE_TYPE:
device = new CCMP133(deviceData);
break;
}
if (device != null) {
// Draw the device.
@ -934,6 +939,50 @@ function processSetVideoBrightnessResponse(response) {
videoSlider.enable();
}
// Handles what happens when the Play music button is pressed.
function playMusic(play) {
// Show the loading panel of the device.
showLoadingPopup(true, MESSAGE_PLAY_MUSIC);
// Send request to play music.
$.post(
"http://" + getServerAddress() + "/ajax/play_music",
JSON.stringify({
"play": play,
"music_file": MUSIC_FILE
}),
function(data) {
// Process only in the dashboard page.
if (!isDashboardShowing())
return;
// Process answer.
processPlayMusicResponse(data);
}
).fail(function(response) {
// Process only in the dashboard page.
if (!isDashboardShowing())
return;
// Process error.
processAjaxErrorResponse(response);
// Hide the loading panel of the device.
showLoadingPopup(false);
});
}
// Processes the "play music" request answer.
function processPlayMusicResponse(response) {
// Check if there was any error in the request.
if (!checkErrorResponse(response, false)) {
play = response[ID_PLAY];
// Show confirmation.
if (play)
toastr.info(MESSAGE_MUSIC_PLAYING);
else
toastr.info(MESSAGE_MUSIC_STOPPED);
}
// Hide the loading panel of the device.
showLoadingPopup(false);
}
// Processes an audio volume changed event.
function volumeChanged(newValue) {
// Show the loading panel of the device.
@ -976,10 +1025,9 @@ function processSetAudioVolumeResponse(response) {
audioSlider.setValue(volume);
} else {
// Save new volume value.
volume = response["value"];
if (volume == null)
volume = audioSlider.getValue();
audioSlider.setValue(volume);
volume = audioSlider.getValue();
// Show confirmation.
toastr.info("Volume changed to " + volume + "%")
}
// Hide the loading panel of the device.
showLoadingPopup(false);
@ -1049,6 +1097,10 @@ function processSetLEDResponse(response) {
if (!checkErrorResponse(response, false)) {
// Update the LED status.
updateLEDStatus();
if (ledStatus)
toastr.info("User LED set to ON");
else
toastr.info("User LED set to OFF");
}
// Hide the loading panel of the device.
showLoadingPopup(false);

View File

@ -325,6 +325,11 @@ class ConnectCoreDevice {
return this.#ethernetIP[index];
}
// Returns whether the device supports Wifi or not.
hasWifi() {
return this.#wifiMAC != null && this.#wifiMAC != "undefined"
}
// Returns the device WiFi MAC address.
getWifiMAC() {
return this.#wifiMAC;

View File

@ -31,7 +31,6 @@ const ID_UPDATE_RUNNING = "update_running";
const CLASS_FIRMWARE_TAB = "firmware-tab";
const CLASS_FIRMWARE_TAB_HEADER = "firmware-tab-header";
const CLASS_FIRMWARE_TAB_HEADER_ACTIVE = "firmware-tab-header-active";
const CLASS_MANAGEMENT_BUTTON_DISABLED = "management-button-disabled";
const CLASS_PROGRESS_BAR_ERROR = "update-firmware-progress-bar-error";
const CLASS_PROGRESS_BAR_INFO = "update-firmware-progress-bar-info";
const CLASS_PROGRESS_BAR_SUCCESS = "update-firmware-progress-bar-success";
@ -625,10 +624,12 @@ function enableManagementButton(buttonID, enable) {
var buttonElement = document.getElementById(buttonID);
if (buttonElement != null) {
if (enable) {
if (buttonElement.classList.contains(CLASS_MANAGEMENT_BUTTON_DISABLED))
buttonElement.classList.remove(CLASS_MANAGEMENT_BUTTON_DISABLED);
} else
buttonElement.classList.add(CLASS_MANAGEMENT_BUTTON_DISABLED);
if (buttonElement.classList.contains(CLASS_CONFIG_BUTTON_DISABLED))
buttonElement.classList.remove(CLASS_CONFIG_BUTTON_DISABLED);
} else {
if (!buttonElement.classList.contains(CLASS_CONFIG_BUTTON_DISABLED))
buttonElement.classList.add(CLASS_CONFIG_BUTTON_DISABLED);
}
}
}

View File

@ -0,0 +1,459 @@
/*
* Copyright 2022, Digi International Inc.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
// Constants.
const ELEMENT_ETHERNET = "ethernet";
const ELEMENT_WIFI = "wifi";
const FIELD_DEFAULT_GATEWAY = "_default_gateway";
const FIELD_DNS1_ADDRESS = "_dns1_addr";
const FIELD_DNS2_ADDRESS = "_dns2_addr";
const FIELD_ENABLE = "_enable";
const FIELD_ENCRYPTION_TYPE = "_enc_type";
const FIELD_ERROR = "_error";
const FIELD_MAC_ADDRESS = "_mac";
const FIELD_IP_ADDRESS = "_ip_addr";
const FIELD_IP_MODE = "_ip_mode";
const FIELD_PARAM = "_param";
const FIELD_PASSWORD = "_password";
const FIELD_SAVE_BUTTON = "_save_button";
const FIELD_SSID = "_ssid";
const FIELD_SUBNET_MASK = "_subnet_mask";
const ID_DNS1 = "dns1";
const ID_DNS2 = "dns2";
const ID_ENABLE = "enable";
const ID_ETH0_TITLE = "eth0_title";
const ID_GATEWAY = "gateway";
const ID_IP = "ip";
const ID_IP_MODE = "type";
const ID_INTERFACE = "interface";
const ID_MAC = "mac";
const ID_NETMASK = "netmask";
const ID_PANEL_CONTAINER = "_panel_container";
const ID_PASSWORD = "psk";
const ID_SECURITY_MODE = "sec_mode";
const ID_SSID = "ssid";
const ID_TOGGLE_BUTTON = "_toggle_button";
const IP_MODE_DHCP = "dhcp";
const IP_MODE_STATIC = "static";
const ERROR_IP_VALUE_FORMAT = "Value must follow this format: XXX.XXX.XXX.XXX";
const ERROR_PASSWORD_INVALID = "Password must be between 8 and 63 characters long";
const ERROR_SSID_INVALID = "SSID value is not valid";
const ERROR_UNKNOWN = "Unknown error saving configuration.";
const MESSAGE_LOADING_CONFIGURATION = "Loading configuration...";
const MESSAGE_SAVING_CONFIGURATION = "Saving configuration...";
const MESSAGE_CONFIGURATION_SAVED = "Configuration saved successfully!";
const PREFIX_ETHERNET = "eth";
const PREFIX_WIFI = "wlan";
const REGEX_IP = '^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$';
const REGEX_SSID = '^[^!#;+\\]/"\t][^+\\]/"\t]{0,31}$';
const REGEX_PASSWORD = '^[\u0020-\u007e]{8,63}$';
const ALL_ELEMENTS = "all";
// Variables.
var readingNetworkInfo = false;
var passwordChanged = false;
// Initializes the network page.
function initializeNetworkPage() {
// Sanity checks.
if (!isNetworkShowing())
return;
// Read network configuration.
readElements = [ELEMENT_ETHERNET, ELEMENT_WIFI];
readConfiguration(readElements, ALL_ELEMENTS);
}
// Gets the device configuration the given elements.
function readConfiguration(readElements, parseElement) {
// Execute only in the network page.
if (!isNetworkShowing() || readingNetworkInfo)
return;
// Flag reading variable.
readingNetworkInfo = true;
// Hide the info popup.
showInfoPopup(false);
// Show the loading popup.
showLoadingPopup(true, MESSAGE_LOADING_CONFIGURATION);
// Send request to retrieve configuration.
$.post(
"http://" + getServerAddress() + "/ajax/get_config",
JSON.stringify({
"elements": readElements
}),
function(data) {
// Process only in the network page.
if (!isNetworkShowing())
return;
// Process answer.
processReadConfigurationResponse(data, parseElement);
}
).fail(function(response) {
// Flag reading variable.
readingNetworkInfo = false;
// Clear the element being read.
elementReading = "";
// Process only in the network page.
if (!isNetworkShowing())
return;
// Hide the loading panel.
showLoadingPopup(false);
// Process error.
processAjaxErrorResponse(response);
// Update controls.
updateAllControls();
});
}
// Processes the response of the read configuration request.
function processReadConfigurationResponse(response, parseElement) {
// Check if there was any error in the request.
if (!checkErrorResponse(response, false)) {
// Fill network info.
fillNetworkInfo(JSON.parse(response[ID_DATA]), parseElement);
} else {
// Flag reading variable.
readingNetworkInfo = false;
// Hide the loading panel.
showLoadingPopup(false);
}
}
// Fills network information.
function fillNetworkInfo(response, parseElement) {
var numEthernetIfaces = 0;
var numWifiIfaces = 0;
for (const [element, elementData] of Object.entries(response)) {
if (element != ELEMENT_ETHERNET && element != ELEMENT_WIFI)
continue;
for (const [iface, ifaceData] of Object.entries(elementData)) {
if (!iface.startsWith(PREFIX_WIFI) && !iface.startsWith(PREFIX_ETHERNET))
continue;
if (parseElement != ALL_ELEMENTS && iface != parseElement)
continue;
var enabled = ifaceData[ID_ENABLE];
var ipMode = ifaceData[ID_IP_MODE];
if (iface.startsWith(PREFIX_ETHERNET))
numEthernetIfaces += 1;
else if (iface.startsWith(PREFIX_WIFI))
numWifiIfaces += 1;
// Fill MAC.
document.getElementById(iface + FIELD_MAC_ADDRESS).innerText = ifaceData[ID_MAC];
// Set enable state.
document.getElementById(iface + FIELD_ENABLE).checked = enabled;
// Set IP mode.
if (ipMode == 0)
document.getElementById(iface + FIELD_IP_MODE).value = IP_MODE_STATIC;
else
document.getElementById(iface + FIELD_IP_MODE).value = IP_MODE_DHCP;
// Fill the rest of the fields.
document.getElementById(iface + FIELD_IP_ADDRESS).value = ifaceData[ID_IP];
document.getElementById(iface + FIELD_SUBNET_MASK).value = ifaceData[ID_NETMASK];
document.getElementById(iface + FIELD_DEFAULT_GATEWAY).value = ifaceData[ID_GATEWAY];
document.getElementById(iface + FIELD_DNS1_ADDRESS).value = ifaceData[ID_DNS1];
document.getElementById(iface + FIELD_DNS2_ADDRESS).value = ifaceData[ID_DNS2];
// Specific Wifi fields.
if (iface.startsWith(PREFIX_WIFI)) {
document.getElementById(iface + FIELD_SSID).value = ifaceData[ID_SSID];
document.getElementById(iface + FIELD_ENCRYPTION_TYPE).selectedIndex = ifaceData[ID_SECURITY_MODE];
if (ifaceData[ID_SECURITY_MODE] != 0)
document.getElementById(iface + FIELD_PASSWORD).value = "dummy_password";
passwordChanged = false;
}
// Update controls.
updateInterfaceControls(iface);
}
}
// Update interfaces visibility.
if (parseElement == ALL_ELEMENTS) {
if (numEthernetIfaces == 1) {
document.getElementById(IFACE_ETH1).style.display = "none";
document.getElementById(ID_ETH0_TITLE).innerHTML = "Ethernet";
}
if (numWifiIfaces == 0)
document.getElementById(IFACE_WIFI).style.display = "none";
}
// Flag reading variable.
readingNetworkInfo = false;
// Hide the loading panel.
showLoadingPopup(false);
}
// Updates all controls of the page.
function updateAllControls() {
updateInterfaceControls(IFACE_ETH0);
updateInterfaceControls(IFACE_ETH1);
updateInterfaceControls(IFACE_WIFI);
}
// Updates the given interface controls based on its configuration.
function updateInterfaceControls(iface) {
// Initialize variables.
var ipGroup = document.getElementById(iface + FIELD_IP_ADDRESS + FIELD_PARAM);
var ipField = document.getElementById(iface + FIELD_IP_ADDRESS);
var subnetGroup = document.getElementById(iface + FIELD_SUBNET_MASK + FIELD_PARAM);
var subnetField = document.getElementById(iface + FIELD_SUBNET_MASK);
var gatewayGroup = document.getElementById(iface + FIELD_DEFAULT_GATEWAY + FIELD_PARAM);
var gatewayField = document.getElementById(iface + FIELD_DEFAULT_GATEWAY);
var dns1Group = document.getElementById(iface + FIELD_DNS1_ADDRESS + FIELD_PARAM);
var dns1Field = document.getElementById(iface + FIELD_DNS1_ADDRESS);
var dns2Group = document.getElementById(iface + FIELD_DNS2_ADDRESS + FIELD_PARAM);
var dns2Field = document.getElementById(iface + FIELD_DNS2_ADDRESS);
var ipModeGroup = document.getElementById(iface + FIELD_IP_MODE + FIELD_PARAM);
var ipModeField = document.getElementById(iface + FIELD_IP_MODE);
var enableField = document.getElementById(iface + FIELD_ENABLE);
var enabled = enableField.checked;
var ipMode = ipModeField.value;
var ssidGroup, encryptionTypeGroup, encryptionTypeField, passwordGroup, usePassword;
if (iface.startsWith(PREFIX_WIFI)) {
ssidGroup = document.getElementById(iface + FIELD_SSID + FIELD_PARAM);
encryptionTypeGroup = document.getElementById(iface + FIELD_ENCRYPTION_TYPE + FIELD_PARAM);
encryptionTypeField = document.getElementById(iface + FIELD_ENCRYPTION_TYPE);
passwordGroup = document.getElementById(iface + FIELD_PASSWORD + FIELD_PARAM);
usePassword = encryptionTypeField.value != 0;
if (usePassword)
passwordGroup.style.display = "block";
else
passwordGroup.style.display = "none";
}
// Determine if IP fields can be edited.
if (ipMode == IP_MODE_DHCP) {
if (!ipField.classList.contains(CLASS_INPUT_DISABLED))
ipField.classList.add(CLASS_INPUT_DISABLED);
if (!subnetField.classList.contains(CLASS_INPUT_DISABLED))
subnetField.classList.add(CLASS_INPUT_DISABLED);
if (!gatewayField.classList.contains(CLASS_INPUT_DISABLED))
gatewayField.classList.add(CLASS_INPUT_DISABLED);
if (!dns1Field.classList.contains(CLASS_INPUT_DISABLED))
dns1Field.classList.add(CLASS_INPUT_DISABLED);
if (!dns2Field.classList.contains(CLASS_INPUT_DISABLED))
dns2Field.classList.add(CLASS_INPUT_DISABLED);
} else if (ipMode == IP_MODE_STATIC) {
if (ipField.classList.contains(CLASS_INPUT_DISABLED))
ipField.classList.remove(CLASS_INPUT_DISABLED);
if (subnetField.classList.contains(CLASS_INPUT_DISABLED))
subnetField.classList.remove(CLASS_INPUT_DISABLED);
if (gatewayField.classList.contains(CLASS_INPUT_DISABLED))
gatewayField.classList.remove(CLASS_INPUT_DISABLED);
if (dns1Field.classList.contains(CLASS_INPUT_DISABLED))
dns1Field.classList.remove(CLASS_INPUT_DISABLED);
if (dns2Field.classList.contains(CLASS_INPUT_DISABLED))
dns2Field.classList.remove(CLASS_INPUT_DISABLED);
}
// Validate the network interface.
validateInterface(iface);
}
// Validates the given network interface.
function validateInterface(iface) {
// Initialize vars.
var valid = true;
var saveButton = document.getElementById(iface + FIELD_SAVE_BUTTON);
var enableField = document.getElementById(iface + FIELD_ENABLE);
var ipModeField = document.getElementById(iface + FIELD_IP_MODE);
var ipField = document.getElementById(iface + FIELD_IP_ADDRESS);
var subnetField = document.getElementById(iface + FIELD_SUBNET_MASK);
var gatewayField = document.getElementById(iface + FIELD_DEFAULT_GATEWAY);
var dns1Field = document.getElementById(iface + FIELD_DNS1_ADDRESS);
var dns2Field = document.getElementById(iface + FIELD_DNS2_ADDRESS);
var ipMode = ipModeField.value;
var forceValid = false;
// Validate fields.
if (ipMode == IP_MODE_DHCP)
forceValid = true;
valid &= validateIPField(iface + FIELD_IP_ADDRESS, iface + FIELD_IP_ADDRESS + FIELD_ERROR, forceValid);
valid &= validateIPField(iface + FIELD_SUBNET_MASK, iface + FIELD_SUBNET_MASK + FIELD_ERROR, forceValid);
valid &= validateIPField(iface + FIELD_DEFAULT_GATEWAY, iface + FIELD_DEFAULT_GATEWAY + FIELD_ERROR, forceValid);
valid &= validateIPField(iface + FIELD_DNS1_ADDRESS, iface + FIELD_DNS1_ADDRESS + FIELD_ERROR, forceValid);
valid &= validateIPField(iface + FIELD_DNS2_ADDRESS, iface + FIELD_DNS2_ADDRESS + FIELD_ERROR, forceValid);
if (iface.startsWith(PREFIX_WIFI)) {
valid &= validateField(iface + FIELD_SSID, iface + FIELD_SSID + FIELD_ERROR, REGEX_SSID, ERROR_SSID_INVALID, false);
if (parseInt(document.getElementById(iface + FIELD_ENCRYPTION_TYPE).value) != 0)
valid &= validateField(iface + FIELD_PASSWORD, iface + FIELD_PASSWORD + FIELD_ERROR, REGEX_PASSWORD, ERROR_PASSWORD_INVALID, false);
}
// Check errors.
if (!valid) {
if (!saveButton.classList.contains(CLASS_CONFIG_BUTTON_DISABLED))
saveButton.classList.add(CLASS_CONFIG_BUTTON_DISABLED);
} else {
if (saveButton.classList.contains(CLASS_CONFIG_BUTTON_DISABLED))
saveButton.classList.remove(CLASS_CONFIG_BUTTON_DISABLED);
}
}
// Validates the given IP field.
function validateIPField(fieldID, errorID, forceValid) {
return validateField(fieldID, errorID, REGEX_IP, ERROR_IP_VALUE_FORMAT, forceValid);
}
// Validates the given field.
function validateField(fieldID, errorID, regexPattern, errorMessage, forceValid) {
// Initialize vars.
var field = document.getElementById(fieldID);
var fieldError = document.getElementById(errorID);
var isValid = true;
var error = "";
// Sanity checks.
if (field == null || fieldError == null)
return false;
// Check if value is valid.
if (!forceValid) {
var value = field.value;
if (value.length == 0) {
isValid = false;
error = ERROR_FIELD_EMPTY;
} else if (!value.match(regexPattern)) {
isValid = false;
error = errorMessage;
}
}
// Update controls.
if (isValid) {
if (field.classList.contains(CLASS_INPUT_ERROR))
field.classList.remove(CLASS_INPUT_ERROR);
fieldError.innerHTML = "&nbsp;";
fieldError.style.display = "none";
} else {
if (!field.classList.contains(CLASS_INPUT_ERROR))
field.classList.add(CLASS_INPUT_ERROR);
fieldError.innerHTML = error;
fieldError.style.display = "block";
}
return isValid;
}
// Retrieves the given network interface form data.
function getInterfaceData(element, iface) {
// Initialize variables.
var data = {};
var ifaceData = {};
var networkData = {};
var enable = document.getElementById(iface + FIELD_ENABLE).checked;
var ipMode = document.getElementById(iface + FIELD_IP_MODE).value;
// Fill network data.
networkData[ID_ENABLE] = enable;
if (ipMode == IP_MODE_STATIC) {
networkData[ID_IP_MODE] = 0;
networkData[ID_IP] = document.getElementById(iface + FIELD_IP_ADDRESS).value;
networkData[ID_NETMASK] = document.getElementById(iface + FIELD_SUBNET_MASK).value;
networkData[ID_GATEWAY] = document.getElementById(iface + FIELD_DEFAULT_GATEWAY).value;
networkData[ID_DNS1] = document.getElementById(iface + FIELD_DNS1_ADDRESS).value;
networkData[ID_DNS2] = document.getElementById(iface + FIELD_DNS2_ADDRESS).value;
} else {
networkData[ID_IP_MODE] = 1;
}
if (iface.startsWith(PREFIX_WIFI)) {
networkData[ID_SSID] = document.getElementById(iface + FIELD_SSID).value;
networkData[ID_SECURITY_MODE] = parseInt(document.getElementById(iface + FIELD_ENCRYPTION_TYPE).value);
if (networkData[ID_SECURITY_MODE] != 0 && passwordChanged)
networkData[ID_PASSWORD] = document.getElementById(iface + FIELD_PASSWORD).value;
}
ifaceData[iface] = networkData;
data[element] = ifaceData;
return data;
}
// Saves the network settings for the given interface.
function saveInterface(element, iface) {
// Execute only in the network page.
if (!isNetworkShowing())
return;
// Hide the info popup.
showInfoPopup(false);
// Show the loading popup.
showLoadingPopup(true, MESSAGE_SAVING_CONFIGURATION);
// Send request to set new configuration.
$.post(
"http://" + getServerAddress() + "/ajax/set_config",
JSON.stringify({
"configuration": getInterfaceData(element, iface)
}),
function(data) {
// Process only in the network page.
if (!isNetworkShowing())
return;
// Process answer.
processSaveInterfaceResponse(data, element, iface);
}
).fail(function(response) {
// Process only in the network page.
if (!isNetworkShowing())
return;
// Hide the loading panel.
showLoadingPopup(false);
// Process error.
processAjaxErrorResponse(response);
});
}
// Processes the save network request response.
function processSaveInterfaceResponse(response, element, iface) {
// Check for error in the response.
if (!checkErrorResponse(response, false)) {
var statusFound = false;
// Check status in the response.
if (response[ID_DATA] != null) {
data = JSON.parse(response[ID_DATA]);
for (const [elementEntry, elementData] of Object.entries(data)) {
if (elementEntry != element)
continue;
for (const [ifaceEntry, ifaceData] of Object.entries(elementData)) {
if (ifaceEntry != iface)
continue;
if (ifaceData[ID_STATUS] != null) {
statusFound = true;
if (ifaceData[ID_STATUS] != 0)
toastr.error(ifaceData[ID_DESC]);
else
toastr.success(MESSAGE_CONFIGURATION_SAVED);
}
}
}
}
if (!statusFound)
toastr.error(ERROR_UNKNOWN);
}
// Hide the loading panel.
showLoadingPopup(false);
}
// Toggles the visibility of the given interface panel.
function togglePanelVisibility(interface) {
// Initialize variables.
var panelButton = document.getElementById(interface + ID_TOGGLE_BUTTON);
// Sanity checks.
if (panelButton == null)
return;
// Check visibility.
if (panelButton.classList.contains(CLASS_ARROW_UP)) {
$("#" + interface + ID_PANEL_CONTAINER).slideUp("fast", function() {
panelButton.classList.remove(CLASS_ARROW_UP);
panelButton.classList.add(CLASS_ARROW_DOWN);
});
} else {
$("#" + interface + ID_PANEL_CONTAINER).slideDown("fast", function() {
panelButton.classList.remove(CLASS_ARROW_DOWN);
panelButton.classList.add(CLASS_ARROW_UP);
});
}
}

View File

@ -93,5 +93,10 @@ function setSelectedSection(element=null) {
}
});
}
if (isDashboardShowing()) {
window.setTimeout(function () {
adjustImageSize();
}, 300);
}
}

Binary file not shown.