connectcore-demo-example: dashboard: implement get device status and info
https://onedigi.atlassian.net/browse/DEL-7742 Signed-off-by: Tatiana Leon <Tatiana.Leon@digi.com>
This commit is contained in:
parent
0e6d64b499
commit
0943812956
|
|
@ -0,0 +1,641 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
# Copyright (c) 2022, Digi International, Inc.
|
||||
#
|
||||
# Permission to use, copy, modify, and/or distribute this software for any
|
||||
# purpose with or without fee is hereby granted, provided that the above
|
||||
# copyright notice and this permission notice appear in all copies.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import argparse
|
||||
import http.server
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import platform
|
||||
import re
|
||||
import signal
|
||||
import socketserver
|
||||
import stat
|
||||
import subprocess
|
||||
|
||||
from logging.handlers import SysLogHandler
|
||||
from subprocess import call, TimeoutExpired
|
||||
from threading import Thread, Event
|
||||
|
||||
|
||||
# Constants.
|
||||
APP_NAME = "Demo server"
|
||||
|
||||
PORT = 9090
|
||||
|
||||
SIZE_KB = "KB"
|
||||
SIZE_MB = "MB"
|
||||
SIZE_GB = "GB"
|
||||
|
||||
DIVIDERS = {SIZE_KB : 1, SIZE_MB: 2, SIZE_GB: 3}
|
||||
|
||||
ZERO_MAC = "00:00:00:00:00:00"
|
||||
ZERO_IP = "0.0.0.0"
|
||||
NOT_AVAILABLE = "N/A"
|
||||
|
||||
# Variables.
|
||||
log = logging.getLogger(APP_NAME)
|
||||
stop_event = Event()
|
||||
last_cpu_work = 0
|
||||
last_cpu_total = 0
|
||||
|
||||
|
||||
class RequestHandler(http.server.SimpleHTTPRequestHandler):
|
||||
"""
|
||||
Custom HTTP request handler class.
|
||||
"""
|
||||
|
||||
def do_OPTIONS(self):
|
||||
"""
|
||||
Override.
|
||||
"""
|
||||
self.send_response(200, "ok")
|
||||
self.end_headers()
|
||||
|
||||
def do_GET(self):
|
||||
"""
|
||||
Override.
|
||||
"""
|
||||
# Forbidden.
|
||||
self._set_headers(403)
|
||||
|
||||
def do_POST(self):
|
||||
"""
|
||||
Override.
|
||||
"""
|
||||
if re.search("/ajax/get_device_info", self.path) is not None:
|
||||
# Set the response headers.
|
||||
self._set_headers(200)
|
||||
|
||||
log.debug("Get device info")
|
||||
|
||||
# Generate the JSON information.
|
||||
mem_info = get_mem_info()
|
||||
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()),
|
||||
"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"),
|
||||
"module_variant": read_proc_file("/proc/device-tree/digi,hwid,variant"),
|
||||
"board_variant": read_proc_file("/proc/device-tree/digi,carrierboard,version"),
|
||||
"board_id": read_proc_file("/proc/device-tree/digi,carrierboard,id"),
|
||||
"mca_hw_version": mca_versions[1],
|
||||
"mca_fw_version": mca_versions[0],
|
||||
"memory_total": mem_info.get("MemTotal", NOT_AVAILABLE) if mem_info else NOT_AVAILABLE,
|
||||
"flash_size": get_storage_size(),
|
||||
"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,
|
||||
"ethernet_mac": read_file("/sys/class/net/eth0/address").strip().upper() if "eth0" in list_net_ifaces() else ZERO_MAC,
|
||||
"ethernet_ip": get_iface_ip("eth0") if "eth0" in list_net_ifaces() else ZERO_IP,
|
||||
}
|
||||
|
||||
# Send the JSON value.
|
||||
self.wfile.write(json.dumps(info).encode(encoding="utf_8"))
|
||||
elif re.search("/ajax/get_device_status", self.path) is not None:
|
||||
# Set the response headers.
|
||||
self._set_headers(200)
|
||||
|
||||
log.debug("Get device status")
|
||||
|
||||
mem_info = get_mem_info()
|
||||
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(),
|
||||
"system_monitor/frequency": read_file("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_cur_freq").strip(),
|
||||
"system_monitor/uptime": get_uptime(),
|
||||
"system_monitor/free_memory": mem_free,
|
||||
"system_monitor/used_memory": mem_used,
|
||||
"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),
|
||||
}
|
||||
|
||||
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"]
|
||||
|
||||
# Send the JSON value.
|
||||
self.wfile.write(json.dumps(status).encode(encoding="utf_8"))
|
||||
else:
|
||||
# Forbidden.
|
||||
self._set_headers(403)
|
||||
|
||||
def end_headers(self):
|
||||
"""
|
||||
Override.
|
||||
"""
|
||||
self.send_header("Access-Control-Allow-Methods", "POST, GET, OPTIONS")
|
||||
self.send_header("Access-Control-Allow-Headers", "X-Requested-With")
|
||||
self.send_header("Access-Control-Allow-Headers", "Content-Type")
|
||||
self.send_header("Access-Control-Allow-Origin", "*")
|
||||
http.server.SimpleHTTPRequestHandler.end_headers(self)
|
||||
|
||||
def _set_headers(self, status):
|
||||
"""
|
||||
Sets the status and heders of the response.
|
||||
|
||||
Args:
|
||||
status (Integer): The status code of the response.
|
||||
"""
|
||||
self.send_response(status)
|
||||
self.send_header("Content-type", "application/json")
|
||||
self.end_headers()
|
||||
|
||||
|
||||
def get_uptime():
|
||||
"""
|
||||
Gets the system uptime in seconds.
|
||||
|
||||
Returns:
|
||||
Float: The system uptime, -1 if fails.
|
||||
"""
|
||||
uptime = read_proc_file("/proc/uptime").strip()
|
||||
if uptime == NOT_AVAILABLE:
|
||||
return -1
|
||||
|
||||
uptime = uptime.split()
|
||||
try:
|
||||
val = float(uptime[0]) if len(uptime) > 0 else -1
|
||||
return int(val)
|
||||
except ValueError:
|
||||
return -1
|
||||
|
||||
|
||||
def get_cpu_temp():
|
||||
"""
|
||||
Gets the CPU temperature in Celsius.
|
||||
|
||||
Returns:
|
||||
Float: The CPU temperature, -1 if fails.
|
||||
"""
|
||||
temp = read_file("/sys/class/thermal/thermal_zone0/temp").strip()
|
||||
if temp == NOT_AVAILABLE:
|
||||
return -1
|
||||
try:
|
||||
return int(int(temp) / 1000)
|
||||
except ValueError:
|
||||
return -1
|
||||
|
||||
|
||||
def get_cpu_load():
|
||||
"""
|
||||
Gets the CPU load of the system in percentage.
|
||||
|
||||
Returns:
|
||||
Float: The CPU load, -1 if fails.
|
||||
"""
|
||||
global last_cpu_work
|
||||
global last_cpu_total
|
||||
|
||||
stat_info = read_proc_file("/proc/stat")
|
||||
if stat_info == NOT_AVAILABLE:
|
||||
return -1
|
||||
|
||||
lines = stat_info.splitlines()
|
||||
if not lines:
|
||||
return -1
|
||||
|
||||
fields = lines[0].split()
|
||||
if not fields or len(fields) < 5:
|
||||
return -1
|
||||
|
||||
work = 0
|
||||
for i in range(1, 4):
|
||||
work += int(fields[i])
|
||||
total = 0
|
||||
for i in range(1, len(fields) - 1): # Remove first
|
||||
total += int(fields[i])
|
||||
|
||||
if not last_cpu_work and not last_cpu_total:
|
||||
usage = 0
|
||||
else:
|
||||
usage = (work - last_cpu_work) * 100.0 / (total - last_cpu_total)
|
||||
|
||||
last_cpu_total = total
|
||||
last_cpu_work = work
|
||||
|
||||
return usage
|
||||
|
||||
|
||||
def get_storage_size():
|
||||
"""
|
||||
Gets the internal storage size in kB.
|
||||
|
||||
Returns:
|
||||
Integer: The internal storage size, -1 if fails.
|
||||
"""
|
||||
size = read_file("/sys/class/mmc_host/mmc0/mmc0:0001/block/mmcblk0/size")
|
||||
if size == NOT_AVAILABLE:
|
||||
return -1
|
||||
try:
|
||||
return int(resize_to(int(size) * 512, SIZE_KB))
|
||||
except ValueError:
|
||||
return -1
|
||||
|
||||
|
||||
def get_mem_info():
|
||||
"""
|
||||
Gets a dictionary with memory info.
|
||||
|
||||
Returns:
|
||||
Dictionary: A dictionary with memory information, None if fails.
|
||||
"""
|
||||
mem_info = read_file("/proc/meminfo")
|
||||
if mem_info == NOT_AVAILABLE:
|
||||
return None
|
||||
|
||||
return dict((line.split()[0].rstrip(':'), int(line.split()[1])) for line in mem_info.splitlines())
|
||||
|
||||
|
||||
def get_dey_version():
|
||||
"""
|
||||
Gets the DEY version.
|
||||
|
||||
Returns:
|
||||
String: DEY version, "N/A" if it fails.
|
||||
"""
|
||||
build_info = read_file("/etc/build")
|
||||
if build_info == NOT_AVAILABLE:
|
||||
return NOT_AVAILABLE
|
||||
for line in build_info.splitlines():
|
||||
m = re.search("DISTRO_VERSION = (.*)", line)
|
||||
if m:
|
||||
return m.group(1)
|
||||
|
||||
return NOT_AVAILABLE
|
||||
|
||||
|
||||
def get_mca_version():
|
||||
"""
|
||||
Gets MCA firmware and hardware versions.
|
||||
|
||||
Returns:
|
||||
Tuple(String, String): Tuple with firmware and hardware versions.
|
||||
"""
|
||||
fw_version = None
|
||||
hw_version = None
|
||||
for dir_path, _, file_names in os.walk("/sys/devices"):
|
||||
for name in file_names:
|
||||
if name == "fw_version":
|
||||
fw_version = read_file(os.path.join(dir_path, name))
|
||||
elif name == "hw_version":
|
||||
hw_version = read_file(os.path.join(dir_path, name))
|
||||
if fw_version and hw_version:
|
||||
return fw_version, hw_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 read_proc_file(path):
|
||||
"""
|
||||
Gets contents of a proc file.
|
||||
Reads the file and eliminates the last NULL character.
|
||||
|
||||
Args:
|
||||
path (String): Absolute path of the file to read.
|
||||
|
||||
Returns:
|
||||
String: The U-Boot version.
|
||||
"""
|
||||
data = read_file(path)
|
||||
if data == NOT_AVAILABLE:
|
||||
return data
|
||||
|
||||
if data[len(data) - 1] == '\0':
|
||||
data = data[:len(data) - 1]
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def exec_cmd(cmd, timeout=None):
|
||||
"""
|
||||
Executes the provided command and waits for it.
|
||||
|
||||
Args:
|
||||
cmd (String, List): The command to execute.
|
||||
timeout (Float, optional, default=None): Timeout to wait for termination.
|
||||
|
||||
Returns:
|
||||
Tuple (Integer, String): A tuple with the return code and the result
|
||||
output or error.
|
||||
"""
|
||||
try:
|
||||
result = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
|
||||
timeout=timeout, shell=True, check=True, text=True)
|
||||
return result.returncode, result.stdout
|
||||
except subprocess.TimeoutExpired as e:
|
||||
return -1, e.stdout
|
||||
except subprocess.CalledProcessError as e:
|
||||
return e.returncode, e.stdout
|
||||
|
||||
|
||||
def read_file(path):
|
||||
"""
|
||||
Reads the provided file path.
|
||||
|
||||
Args:
|
||||
path (String): Absolute path of the file to read.
|
||||
|
||||
Returns:
|
||||
String: Contents of the file, 'N/A' if any error occurs.
|
||||
"""
|
||||
try:
|
||||
with open(path) as f:
|
||||
return f.read()
|
||||
except OSError as e:
|
||||
if e.errno == errno.ENOENT:
|
||||
log.error("File '%s' does not exist (errno: %d)", path, e.errno)
|
||||
else:
|
||||
log.error("Cannot open file '%s' (errno: %d)", path, e.errno)
|
||||
|
||||
return NOT_AVAILABLE
|
||||
|
||||
|
||||
def resize_to(value, to, divider=1024):
|
||||
"""
|
||||
Resizes the given value.
|
||||
|
||||
Args:
|
||||
value (Integer): The value to resize.
|
||||
to (Integer): The divider scale.
|
||||
divider (Integer, Optional): The base divider.
|
||||
|
||||
Returns:
|
||||
Float: The resized value.
|
||||
"""
|
||||
r = float(value)
|
||||
return r / (divider ** DIVIDERS[to])
|
||||
|
||||
|
||||
def init_log(log_level, log_console):
|
||||
"""
|
||||
Initialize console and syslog loggers.
|
||||
|
||||
Args:
|
||||
log_level (String): The file logger level.
|
||||
log_console (Boolean): `True` to log to console, `False` otherwise.
|
||||
"""
|
||||
log_format = "%(name)s: %(message)s"
|
||||
level = logging.INFO
|
||||
handlers = []
|
||||
|
||||
if log_level == "D":
|
||||
level = logging.DEBUG
|
||||
elif log_level == "I":
|
||||
level = logging.INFO
|
||||
elif log_level == "W":
|
||||
level = logging.WARNING
|
||||
elif log_level == "E":
|
||||
level = logging.ERROR
|
||||
|
||||
def configure_handler(log_handler, name, fmt, handlers_list):
|
||||
log_handler.name = name
|
||||
log_handler.setFormatter(
|
||||
logging.Formatter(fmt=fmt, datefmt='%Y-%m-%d,%H:%M:%S'))
|
||||
log_handler.setLevel(level)
|
||||
handlers_list.append(log_handler)
|
||||
|
||||
if log_console:
|
||||
log_console_format = "%(asctime)s %(name)s: %(message)s"
|
||||
configure_handler(logging.StreamHandler(), "%s console handler",
|
||||
log_console_format, handlers)
|
||||
configure_handler(SysLogHandler(address='/dev/log'), "%s syslog handler",
|
||||
log_format, handlers)
|
||||
|
||||
log.disabled = False
|
||||
log.setLevel(level)
|
||||
for handler in handlers:
|
||||
log.addHandler(handler)
|
||||
|
||||
|
||||
def disable_logger():
|
||||
"""
|
||||
Disables the logger and removes all handlers.
|
||||
"""
|
||||
log.disabled = True
|
||||
|
||||
for hdl in log.handlers:
|
||||
hdl.close()
|
||||
log.removeHandler(hdl)
|
||||
|
||||
|
||||
def signal_handler(signal_number, _frame):
|
||||
"""
|
||||
Signal handler function.
|
||||
|
||||
Args:
|
||||
signal_number (Integer): Received signal.
|
||||
_frame: Current stack frame.
|
||||
"""
|
||||
log.debug("Signal received %d", signal_number)
|
||||
if signal_number in (signal.SIGTERM, signal.SIGINT):
|
||||
stop_event.set()
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
Main function to listen to XBee status changes.
|
||||
"""
|
||||
parser = argparse.ArgumentParser(description='Device demo server',
|
||||
add_help=True,
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
parser.add_argument("-p", "--port", metavar="<port>", nargs=1, default=PORT,
|
||||
type=int, help="Server port")
|
||||
parser.add_argument("--log", metavar="<D, I, W, E>", default='I',
|
||||
choices=['D', 'I', 'W', 'E'],
|
||||
help="Log level: debug, info, warning, error")
|
||||
parser.add_argument("--log-console", action='store_true',
|
||||
dest="log_console",
|
||||
help="Enable log to standard output")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
init_log(args.log, args.log_console)
|
||||
|
||||
# Create the HTTP server and start it.
|
||||
socketserver.ThreadingTCPServer.allow_reuse_address = True
|
||||
server = socketserver.ThreadingTCPServer(("", args.port), RequestHandler)
|
||||
|
||||
signal.signal(signal.SIGTERM, signal_handler)
|
||||
signal.signal(signal.SIGINT, signal_handler)
|
||||
|
||||
log.info("Serving at port %s" % args.port)
|
||||
|
||||
server_thread = Thread(target=server.serve_forever)
|
||||
server_thread.deamon = True
|
||||
server_thread.start()
|
||||
|
||||
stop_event.wait()
|
||||
|
||||
server.shutdown()
|
||||
server.server_close()
|
||||
log.info("Sever stopped")
|
||||
disable_logger()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
||||
|
|
@ -40,7 +40,7 @@ Digi Demo - Dashboard
|
|||
<div>
|
||||
<img src="./static/images/board.png" class="device-title-img" title="Device">
|
||||
</div>
|
||||
<div id="device-name"></div>
|
||||
<div id="device-name">DEY DEVICE</div>
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
|
|
@ -54,7 +54,7 @@ Digi Demo - Dashboard
|
|||
|
||||
<ul id="sections" data-pjax class="list-group">
|
||||
<li>
|
||||
<a data-pjax href="/dashboard/" class="list-group-item list-group-item-action d-flex align-items-center">
|
||||
<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>
|
||||
|
|
@ -62,7 +62,7 @@ Digi Demo - Dashboard
|
|||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a data-pjax href="/history/" class="list-group-item list-group-item-action d-flex align-items-center">
|
||||
<a data-pjax href="history.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-chart-area fa-fw fa-lg mr-3"></span>
|
||||
<span class="menu-collapsed">Historical data</span>
|
||||
|
|
@ -70,7 +70,7 @@ Digi Demo - Dashboard
|
|||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a data-pjax href="/management/" class="list-group-item list-group-item-action d-flex align-items-center">
|
||||
<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>
|
||||
|
|
@ -276,7 +276,7 @@ Digi Demo - Dashboard
|
|||
<span class="device-card-content-text">Temperature:</span>
|
||||
</td>
|
||||
<td>
|
||||
<span id="cpu_temperature" class="device-card-content-value">-</span> ºC
|
||||
<span id="cpu_temperature" class="device-card-content-value">-</span> C
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
|
@ -805,9 +805,12 @@ Digi Demo - Dashboard
|
|||
|
||||
// Set the selected section.
|
||||
setSelectedSection();
|
||||
});
|
||||
|
||||
// Set the name of the selected device.
|
||||
$("#device-name").html("DEY device".toUpperCase());
|
||||
// Callback executed when the page loads.
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
// Start the timer that updates device status.
|
||||
var statsTimer = setInterval(readDeviceStatus, 5000);
|
||||
});
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -42,7 +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_DEVICE_NAME = "device_name";
|
||||
const ID_DEVICE_NAME = "device-name";
|
||||
const ID_DEVICE_TYPE = "device_type";
|
||||
const ID_DEVICES = "devices";
|
||||
const ID_DEY_VERSION = "dey_version";
|
||||
|
|
|
|||
|
|
@ -60,6 +60,8 @@ 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 PORT = "9090";
|
||||
|
||||
const IFACE_BT = "hci0/";
|
||||
const IFACE_ETHERNET = "eth0/";
|
||||
const IFACE_WIFI = "wlan0/";
|
||||
|
|
@ -196,7 +198,7 @@ function readDeviceInfo() {
|
|||
showLoadingPopup(true, MESSAGE_READING_DEVICE_INFO);
|
||||
// Send request to retrieve device information.
|
||||
$.post(
|
||||
"../ajax/get_device_info",
|
||||
"http://" + getServerAddress() + "/ajax/get_device_info",
|
||||
function(data) {
|
||||
// Process only in the dashboard page.
|
||||
if (!isDashboardShowing()) {
|
||||
|
|
@ -250,8 +252,8 @@ function readDeviceStatus() {
|
|||
// Show the loading popup.
|
||||
showLoadingPopup(true, MESSAGE_READING_DEVICE_STATUS);
|
||||
// Send request to retrieve device status.
|
||||
/*$.post(
|
||||
"../ajax/get_device_status",
|
||||
$.post(
|
||||
"http://" + getServerAddress() + "/ajax/get_device_status",
|
||||
function(data) {
|
||||
// Process only in the dashboard page.
|
||||
if (!isDashboardShowing()) {
|
||||
|
|
@ -269,7 +271,7 @@ function readDeviceStatus() {
|
|||
return;
|
||||
// Process error.
|
||||
processAjaxErrorResponse(response);
|
||||
});*/
|
||||
});
|
||||
// Hide the loading panel of the device.
|
||||
showLoadingPopup(false);
|
||||
// Hide the info panel of the device.
|
||||
|
|
@ -312,8 +314,6 @@ function createDevice(deviceData) {
|
|||
if (device != null) {
|
||||
// Draw the device.
|
||||
drawDevice();
|
||||
// Automatically receive updates.
|
||||
//subscribeDataPoints();
|
||||
// Set device as initialized.
|
||||
deviceInitialized = true;
|
||||
// Device created successfully.
|
||||
|
|
@ -544,6 +544,8 @@ function positionComponent(component, boardWidth, boardHeight, headerHeight, das
|
|||
|
||||
// Updates the device information values.
|
||||
function updateInfoValues() {
|
||||
// Set the device type.
|
||||
updateFieldValue("device-name", device.getDeviceType().toUpperCase());
|
||||
// Set serial number.
|
||||
updateFieldValue(ID_SERIAL_NUMBER, device.getSerialNumber());
|
||||
// Set DEY version.
|
||||
|
|
@ -820,7 +822,7 @@ function brightnessChanged(newValue) {
|
|||
videoSlider.disable();
|
||||
// Send request to change the video brightness value.
|
||||
$.post(
|
||||
"../ajax/set_video_brightness",
|
||||
"http://" + getServerAddress() + "/ajax/set_video_brightness",
|
||||
JSON.stringify({
|
||||
"value": newValue
|
||||
}),
|
||||
|
|
@ -870,7 +872,7 @@ function volumeChanged(newValue) {
|
|||
audioSlider.disable();
|
||||
// Send request to change the audio volume value.
|
||||
$.post(
|
||||
"../ajax/set_audio_volume",
|
||||
"http://" + getServerAddress() + "/ajax/set_audio_volume",
|
||||
JSON.stringify({
|
||||
"value": newValue
|
||||
}),
|
||||
|
|
@ -934,7 +936,7 @@ function setLEDValue(ledName, ledValue) {
|
|||
showLoadingPopup(true, MESSAGE_TOGGLING_LED_VALUE);
|
||||
// Send request to change the LED status.
|
||||
$.post(
|
||||
"../ajax/set_led_value",
|
||||
"http://" + getServerAddress() + "/ajax/set_led_value",
|
||||
JSON.stringify({
|
||||
"led_name": ledName,
|
||||
"value": ledValue
|
||||
|
|
@ -1005,24 +1007,11 @@ function changeSampleRate() {
|
|||
window.open("../management/?device_id=" + getDeviceID() + "&device_name=" + getDeviceName(), "_self");
|
||||
}
|
||||
|
||||
// Subscribes to any datapoint change.
|
||||
function subscribeDataPoints() {
|
||||
// Sanity checks.
|
||||
if (dataPointsSocket != null)
|
||||
return;
|
||||
// Create the web socket.
|
||||
var socketPrefix = window.location.protocol == "https:" ? "wss" : "ws";
|
||||
dataPointsSocket = new WebSocket(socketPrefix + "://" + window.location.host + "/ws/datapoints/" + device.getDeviceID());
|
||||
// Define the callback to be notified when data is received in the web socket.
|
||||
dataPointsSocket.onmessage = function(e) {
|
||||
if (isDashboardShowing()) {
|
||||
// Initialize variables.
|
||||
var event = JSON.parse(e.data);
|
||||
var stream = event[ID_STREAM];
|
||||
var value = event[ID_VALUE];
|
||||
// Update the datapoint value.
|
||||
updateDataPointValue(stream, value);
|
||||
}
|
||||
};
|
||||
}
|
||||
// Returns the server address.
|
||||
function getServerAddress() {
|
||||
var host = window.location.hostname;
|
||||
if (!Boolean(host))
|
||||
host = "127.0.0.1";
|
||||
|
||||
return host + ":" + PORT;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue