mirror of
https://github.com/fusion44/blitz_api.git
synced 2026-08-18 12:27:50 +02:00
Merge pull request #59 from fusion44/raspiblitz-hw-codepath
Implement hardware status fetching on RaspiBlitz platform
This commit is contained in:
commit
77db3a16cb
5 changed files with 174 additions and 76 deletions
12
.env_sample
12
.env_sample
|
|
@ -11,17 +11,29 @@ login_password=12345678
|
|||
# JWT token.
|
||||
# enable_local_cookie_auth = false
|
||||
|
||||
# Platform tells the backend on what kind of system it is running on.
|
||||
# Different platforms might use different data sources and might yield
|
||||
# different kinds of data. E.g.: If set to "raspiblitz",then hardware
|
||||
# information will be fetched from Redis instead of the native python
|
||||
# implementation and the returned data is different.
|
||||
# supported values: raspiblitz, native_python
|
||||
# default: raspiblitz
|
||||
# platform=raspiblitz
|
||||
|
||||
# Amount of seconds the app will wait until it'll
|
||||
# send another hardware update
|
||||
# only applies when platform=native_python
|
||||
gather_hw_info_interval = 2
|
||||
|
||||
# Amount of seconds the app will gather CPU usage data for each update
|
||||
# The resulting CPU usage is averaged over this period of time.
|
||||
# To get realistic results at least 0.1 seconds is recommended
|
||||
# must be less than and not equal to gather_hw_info_interval
|
||||
# only applies when platform=native_python
|
||||
cpu_usage_averaging_period = 0.5
|
||||
|
||||
# Poll interval in seconds to gather lightning information and push it via SSE
|
||||
# only applies when platform=native_python
|
||||
gather_ln_info_interval = 5.0
|
||||
|
||||
# Path to the shell script root folder
|
||||
|
|
|
|||
74
app/repositories/hardware_impl/native_python.py
Normal file
74
app/repositories/hardware_impl/native_python.py
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
import psutil
|
||||
from decouple import config
|
||||
|
||||
|
||||
SLEEP_TIME = config("gather_hw_info_interval", default=2, cast=float)
|
||||
CPU_AVG_PERIOD = config("cpu_usage_averaging_period", default=0.5, cast=float)
|
||||
HW_INFO_YIELD_TIME = SLEEP_TIME + CPU_AVG_PERIOD
|
||||
|
||||
|
||||
async def get_hardware_info_impl() -> map:
|
||||
info = {}
|
||||
|
||||
info["cpu_overall_percent"] = psutil.cpu_percent(interval=CPU_AVG_PERIOD)
|
||||
info["cpu_per_cpu_percent"] = psutil.cpu_percent(
|
||||
interval=CPU_AVG_PERIOD, percpu=True
|
||||
)
|
||||
|
||||
v = psutil.virtual_memory()
|
||||
info["vram_total_bytes"] = v.total
|
||||
info["vram_available_bytes"] = v.available
|
||||
info["vram_used_bytes"] = v.used
|
||||
info["vram_usage_percent"] = v.percent
|
||||
|
||||
s = psutil.swap_memory()
|
||||
info["swap_ram_total_bytes"] = s.total
|
||||
info["swap_used_bytes"] = s.used
|
||||
info["swap_usage_bytes"] = s.percent
|
||||
|
||||
info["temperatures_celsius"] = psutil.sensors_temperatures()
|
||||
info["boot_time_timestamp"] = psutil.boot_time()
|
||||
|
||||
disk_io = psutil.disk_io_counters()
|
||||
info["disk_io_read_count"] = disk_io.read_count
|
||||
info["disk_io_write_count"] = disk_io.write_count
|
||||
info["disk_io_read_bytes"] = disk_io.read_bytes
|
||||
info["disk_io_write_bytes"] = disk_io.write_bytes
|
||||
|
||||
disks = []
|
||||
partitions = psutil.disk_partitions()
|
||||
for partition in partitions:
|
||||
p = {}
|
||||
p["device"] = partition.device
|
||||
p["mountpoint"] = partition.mountpoint
|
||||
p["filesystem_type"] = partition.fstype
|
||||
|
||||
try:
|
||||
usage = psutil.disk_usage(partition.mountpoint)
|
||||
p["partition_total_bytes"] = usage.total
|
||||
p["partition_used_bytes"] = usage.used
|
||||
p["partition_free_bytes"] = usage.free
|
||||
p["partition_percent"] = usage.percent
|
||||
except PermissionError:
|
||||
continue
|
||||
disks.append(p)
|
||||
info["disks"] = disks
|
||||
|
||||
nets = []
|
||||
addresses = psutil.net_if_addrs()
|
||||
for name, address in addresses.items():
|
||||
net = {}
|
||||
nets.append(net)
|
||||
net["interface_name"] = name
|
||||
for a in address:
|
||||
if str(a.family) == "AddressFamily.AF_INET":
|
||||
net["address"] = a.address
|
||||
elif str(a.family) == "AddressFamily.AF_PACKET":
|
||||
net["mac_address"] = a.address
|
||||
|
||||
net_io = psutil.net_io_counters()
|
||||
info["networks"] = nets
|
||||
info["networks_bytes_sent"] = net_io.bytes_sent
|
||||
info["networks_bytes_received"] = net_io.bytes_recv
|
||||
|
||||
return info
|
||||
63
app/repositories/hardware_impl/raspiblitz.py
Normal file
63
app/repositories/hardware_impl/raspiblitz.py
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
import time
|
||||
|
||||
HW_INFO_YIELD_TIME = 2
|
||||
|
||||
|
||||
from fastapi_plugins import redis_plugin as r
|
||||
|
||||
|
||||
async def _redis_get(key: str) -> str:
|
||||
v = await r.redis.get(key)
|
||||
return v.decode("utf-8")
|
||||
|
||||
|
||||
async def get_hardware_info_impl() -> map:
|
||||
info = {}
|
||||
|
||||
loads = (await _redis_get("system_cpu_load")).split(",")
|
||||
iloads = []
|
||||
total = 0
|
||||
for l in loads:
|
||||
value = float(l)
|
||||
total += value
|
||||
iloads.append(value)
|
||||
info["cpu_overall_percent"] = total / len(loads)
|
||||
info["cpu_per_cpu_percent"] = iloads
|
||||
|
||||
info["vram_total_bytes"] = int(await _redis_get("system_ram_mb")) * 1000 * 1000
|
||||
|
||||
info["vram_available_bytes"] = (
|
||||
int(await _redis_get("system_ram_available_mb")) * 1000 * 1000
|
||||
)
|
||||
|
||||
info["vram_used_bytes"] = info["vram_total_bytes"] - info["vram_available_bytes"]
|
||||
info["vram_usage_percent"] = (100 / info["vram_total_bytes"]) * info[
|
||||
"vram_used_bytes"
|
||||
]
|
||||
|
||||
info["temperatures_celsius"] = {
|
||||
"system_temp": float(await _redis_get("system_temp_celsius")),
|
||||
"coretemp": [],
|
||||
}
|
||||
|
||||
now = time.time()
|
||||
boot = float(await _redis_get("system_up"))
|
||||
info["boot_time_timestamp"] = now - boot
|
||||
|
||||
total = int(await _redis_get("hdd_capacity_bytes"))
|
||||
free = int(await _redis_get("hdd_free_bytes"))
|
||||
info["hdd"] = {
|
||||
"hdd_capacity_bytes": total,
|
||||
"hdd_free_bytes": free,
|
||||
"hdd_free_percent": (100 / total) * free,
|
||||
}
|
||||
|
||||
info["networks"] = {
|
||||
"public_ip": await _redis_get("publicIP"),
|
||||
"internet_online": await _redis_get("internet_online"),
|
||||
"tor_web_addr": await _redis_get("tor_web_addr"),
|
||||
"internet_localip=": await _redis_get("internet_localip"),
|
||||
"internet_localiprange": await _redis_get("internet_localiprange"),
|
||||
}
|
||||
|
||||
return info
|
||||
|
|
@ -1,16 +1,28 @@
|
|||
import asyncio
|
||||
from os import path
|
||||
|
||||
import psutil
|
||||
from app.models.system import RawDebugLogData, SystemInfo
|
||||
from app.repositories.lightning import get_ln_info
|
||||
from app.utils import SSE, send_sse_message
|
||||
from decouple import config
|
||||
from fastapi import HTTPException, Request, status
|
||||
|
||||
SLEEP_TIME = config("gather_hw_info_interval", default=2, cast=float)
|
||||
CPU_AVG_PERIOD = config("cpu_usage_averaging_period", default=0.5, cast=float)
|
||||
HW_INFO_YIELD_TIME = SLEEP_TIME + CPU_AVG_PERIOD
|
||||
PLATFORM = config("platform")
|
||||
if PLATFORM == None:
|
||||
PLATFORM = "raspiblitz"
|
||||
|
||||
if PLATFORM == "raspiblitz":
|
||||
from app.repositories.hardware_impl.raspiblitz import (
|
||||
HW_INFO_YIELD_TIME,
|
||||
get_hardware_info_impl,
|
||||
)
|
||||
elif PLATFORM == "native_python":
|
||||
from app.repositories.hardware_impl.native_python import (
|
||||
HW_INFO_YIELD_TIME,
|
||||
get_hardware_info_impl,
|
||||
)
|
||||
else:
|
||||
raise RuntimeError(f"Unknown platform {PLATFORM}")
|
||||
|
||||
SHELL_SCRIPT_PATH = config("shell_script_path")
|
||||
GET_DEBUG_LOG_SCRIPT = path.join(SHELL_SCRIPT_PATH, "config.scripts", "blitz.debug.sh")
|
||||
|
|
@ -37,80 +49,17 @@ async def get_system_info() -> SystemInfo:
|
|||
raise HTTPException(status.HTTP_501_NOT_IMPLEMENTED, detail=r.args[0])
|
||||
|
||||
|
||||
async def get_hardware_info() -> map:
|
||||
return await get_hardware_info_impl()
|
||||
|
||||
|
||||
async def subscribe_hardware_info(request: Request):
|
||||
while True:
|
||||
if await request.is_disconnected():
|
||||
# stop if client disconnects
|
||||
break
|
||||
yield get_hardware_info()
|
||||
await asyncio.sleep(SLEEP_TIME)
|
||||
|
||||
|
||||
def get_hardware_info() -> map:
|
||||
info = {}
|
||||
|
||||
info["cpu_overall_percent"] = psutil.cpu_percent(interval=CPU_AVG_PERIOD)
|
||||
info["cpu_per_cpu_percent"] = psutil.cpu_percent(
|
||||
interval=CPU_AVG_PERIOD, percpu=True
|
||||
)
|
||||
|
||||
v = psutil.virtual_memory()
|
||||
info["vram_total_bytes"] = v.total
|
||||
info["vram_available_bytes"] = v.available
|
||||
info["vram_used_bytes"] = v.used
|
||||
info["vram_usage_percent"] = v.percent
|
||||
|
||||
s = psutil.swap_memory()
|
||||
info["swap_ram_total_bytes"] = s.total
|
||||
info["swap_used_bytes"] = s.used
|
||||
info["swap_usage_bytes"] = s.percent
|
||||
|
||||
info["temperatures_celsius"] = psutil.sensors_temperatures()
|
||||
info["boot_time_timestamp"] = psutil.boot_time()
|
||||
|
||||
disk_io = psutil.disk_io_counters()
|
||||
info["disk_io_read_count"] = disk_io.read_count
|
||||
info["disk_io_write_count"] = disk_io.write_count
|
||||
info["disk_io_read_bytes"] = disk_io.read_bytes
|
||||
info["disk_io_write_bytes"] = disk_io.write_bytes
|
||||
|
||||
disks = []
|
||||
partitions = psutil.disk_partitions()
|
||||
for partition in partitions:
|
||||
p = {}
|
||||
p["device"] = partition.device
|
||||
p["mountpoint"] = partition.mountpoint
|
||||
p["filesystem_type"] = partition.fstype
|
||||
|
||||
try:
|
||||
usage = psutil.disk_usage(partition.mountpoint)
|
||||
p["partition_total_bytes"] = usage.total
|
||||
p["partition_used_bytes"] = usage.used
|
||||
p["partition_free_bytes"] = usage.free
|
||||
p["partition_percent"] = usage.percent
|
||||
except PermissionError:
|
||||
continue
|
||||
disks.append(p)
|
||||
info["disks"] = disks
|
||||
|
||||
nets = []
|
||||
addresses = psutil.net_if_addrs()
|
||||
for name, address in addresses.items():
|
||||
net = {}
|
||||
nets.append(net)
|
||||
net["interface_name"] = name
|
||||
for a in address:
|
||||
if str(a.family) == "AddressFamily.AF_INET":
|
||||
net["address"] = a.address
|
||||
elif str(a.family) == "AddressFamily.AF_PACKET":
|
||||
net["mac_address"] = a.address
|
||||
|
||||
net_io = psutil.net_io_counters()
|
||||
info["networks"] = nets
|
||||
info["networks_bytes_sent"] = net_io.bytes_sent
|
||||
info["networks_bytes_received"] = net_io.bytes_recv
|
||||
|
||||
return info
|
||||
yield await get_hardware_info()
|
||||
await asyncio.sleep(HW_INFO_YIELD_TIME)
|
||||
|
||||
|
||||
async def get_debug_logs_raw() -> RawDebugLogData:
|
||||
|
|
@ -144,7 +93,7 @@ f"[{cmd!r} exited with {proc.returncode}]"\n
|
|||
async def _handle_gather_hardware_info():
|
||||
last_info = {}
|
||||
while True:
|
||||
info = get_hardware_info()
|
||||
info = await get_hardware_info()
|
||||
if last_info != info:
|
||||
await send_sse_message(SSE.HARDWARE_INFO, info)
|
||||
last_info = info
|
||||
|
|
|
|||
|
|
@ -80,8 +80,8 @@ async def get_system_info_path():
|
|||
dependencies=[Depends(JWTBearer())],
|
||||
status_code=status.HTTP_200_OK,
|
||||
)
|
||||
def hw_info() -> map:
|
||||
return get_hardware_info()
|
||||
async def hw_info() -> map:
|
||||
return await get_hardware_info()
|
||||
|
||||
|
||||
@router.get(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue