Skip to content

Instantly share code, notes, and snippets.

@knockshore
Created October 1, 2022 07:04
Show Gist options
  • Save knockshore/a1e41bf5539666020303f7d49cf77cbc to your computer and use it in GitHub Desktop.
Save knockshore/a1e41bf5539666020303f7d49cf77cbc to your computer and use it in GitHub Desktop.
pikvm
#!/usr/bin/env python3
# ========================================================================== #
# #
# KVMD-OLED - Small OLED daemon for Pi-KVM. #
# #
# Copyright (C) 2018 Maxim Devaev <mdevaev@gmail.com> #
# #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation, either version 3 of the License, or #
# (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
# #
# ========================================================================== #
# Replaces /usr/bin/kvmd-oled
# Place 'i2c-dev' at the end of /etc/modules-load.d/kvmd.conf
# Place 'dtparam=i2c_arm=on' at the end of /boot/config.txt
# Run 'systemctl enable --now kvmd-oled'
# Reboot
import sys
import socket
import logging
import datetime
import time
import os
from typing import Tuple
import netifaces
import psutil
from luma.core import cmdline
from luma.core.render import canvas
from PIL import ImageFont
# =====
_logger = logging.getLogger("oled")
# =====
def _get_ip() -> Tuple[str, str]:
try:
gws = netifaces.gateways()
if "default" not in gws:
raise RuntimeError(f"No default gateway: {gws}")
iface = ""
for proto in [socket.AF_INET, socket.AF_INET6]:
if proto in gws["default"]:
iface = gws["default"][proto][1]
break
else:
raise RuntimeError(f"No iface for the gateway {gws['default']}")
for addr in netifaces.ifaddresses(iface).get(proto, []):
return (iface, addr["addr"])
except Exception:
# _logger.exception("Can't get iface/IP")
return ("<no-iface>", "<no-ip>")
def _get_uptime() -> str:
uptime = datetime.timedelta(seconds=int(time.time() - psutil.boot_time()))
pl = {"days": uptime.days}
(pl["hours"], rem) = divmod(uptime.seconds, 3600)
(pl["mins"], pl["secs"]) = divmod(rem, 60)
return "{days}d {hours}h {mins}m".format(**pl)
# =====
def main() -> None:
logging.basicConfig(level=logging.INFO, format="%(message)s")
logging.getLogger("PIL").setLevel(logging.ERROR)
parser = cmdline.create_parser(description="Display FQDN and IP on the OLED")
parser.add_argument("--font", default="/usr/share/fonts/TTF/ProggyTiny.ttf", help="Font path")
parser.add_argument("--font-size", default=16, type=int, help="Font size")
parser.add_argument("--interval", default=5, type=int, help="Screens interval")
options = parser.parse_args(sys.argv[1:])
if options.config:
config = cmdline.load_config(options.config)
options = parser.parse_args(config + sys.argv[1:])
device = cmdline.create_device(options)
font = ImageFont.truetype(options.font, options.font_size)
display_types = cmdline.get_display_types()
if options.display not in cmdline.get_display_types()["emulator"]:
_logger.info("Iface: %s", options.interface)
_logger.info("Display: %s", options.display)
_logger.info("Size: %dx%d", device.width, device.height)
try:
with canvas(device) as draw:
text = f"=====================\n Welcome to Pi-KVM \n====================="
draw.multiline_text((0, 0), text, font=font, fill="white")
time.sleep(options.interval)
summary = 0
while True:
with canvas(device) as draw:
summary = summary % 4
if summary == 0:
var = os.popen(" pistat | grep 'CPU temp' | cut -d ' ' -f 3 | cut -d '.' -f 1 ")
ctemp = var.read().replace('\n', '')
var = os.popen(" pistat | grep 'GPU temp' | cut -d ' ' -f 3 | cut -d '.' -f 1 ")
gtemp = var.read().replace('\n', '')
text = f"Hostname: {socket.getfqdn()}\n Uptime: {_get_uptime().upper()}\nCPU: {ctemp}'C GPU: {gtemp}'C"
elif summary == 1:
var = os.popen(" v=$( ip -o a show | grep 'eth0' | grep 'inet ' | cut -d ' ' -f 7 | cut -d '/' -f 1 ); if [[ \"$v\" != \"\" ]]; then printf ' ETH: '$v; count+=1; else echo \'No Ethernet connected\'; fi ")
eth = var.read().replace('\n', '')
var = os.popen(" v=$( ip -o a show | grep 'wlan0' | grep 'inet ' | cut -d ' ' -f 7 | cut -d '/' -f 1 ); if [[ \"$v\" != \"\" ]]; then printf 'WLAN: '$v; count+=1; else echo \'No Wi-Fi connected\'; fi ")
wlan = var.read().replace('\n', '')
var = os.popen(" v=$( netctl-auto list | grep '*' | cut -d '-' -f 2 ); if [[ \"$v\" != \"\" ]]; then printf 'SSID: '$v; count+=1; else echo \''; fi ")
ssid = var.read().replace('\n', '')
text = f"{eth}\n{wlan}\n{ssid}" # Pi 4
#text = f"{wlan}\n{ssid}" # Pi Zero
elif summary == 2:
time.sleep(options.interval)
var = os.popen(" pistat | grep Pi | cut -d ' ' -f 2,3,4,6 ") # Pi 4
#var = os.popen(" pistat | grep Pi | cut -d ' ' -f 2,3,4,5 ") # Pi Zero
rpi = var.read().replace('\n', '')
var = os.popen(" pacman -Q | grep 'kvmd ' | cut -d '-' -f 1 ")
kvmd = var.read().replace('\n', '').upper()
var = os.popen(" pacman -Q | grep kvmd-platform | cut -d '-' -f 3 ")
plat = var.read().replace('\n', '').upper()
var = os.popen(" pacman -Q | grep kvmd-platform | cut -d '-' -f 4 ")
hdmi = var.read().replace('\n', '').upper()
var = os.popen(" pistat | grep 'Throttled past' | cut -d ' ' -f 3 ")
ovht = var.read().replace('\n', '').upper()
var = os.popen(" pistat | grep 'Undervoltage past' | cut -d ' ' -f 3 ")
undv = var.read().replace('\n', '').upper()
text = f"{rpi}\n{kvmd} {plat} {hdmi}\nOVHT: {ovht:<3} UNDV: {undv:<3}"
else:
var = os.popen(" free -h --si | grep 'Mem' | tr -s ' ' | cut -d ' ' -f 2 ")
ramtot = var.read().replace('\n', '')
var = os.popen(" free -h --si | grep 'Mem' | tr -s ' ' | cut -d ' ' -f 3 ")
ramuse = var.read().replace('\n', '')
var = os.popen(" free -h --si | grep 'Mem' | tr -s ' ' | cut -d ' ' -f 4 ")
ramfre = var.read().replace('\n', '')
var = os.popen(" df -h --total | grep 'total' | tr -s ' ' | cut -d ' ' -f 2 ")
hddtot = var.read().replace('\n', '')
var = os.popen(" df -h --total | grep 'total' | tr -s ' ' | cut -d ' ' -f 3 ")
hdduse = var.read().replace('\n', '')
var = os.popen(" df -h --total | grep 'total' | tr -s ' ' | cut -d ' ' -f 4 ")
hddfre = var.read().replace('\n', '')
text = f" Used Free \n RAM: {ramuse:>6} {ramfre:>6} \n HDD: {hdduse:>6} {hddfre:>6} \n"
draw.multiline_text((0, 0), text, font=font, fill="white")
summary += 1
time.sleep(options.interval)
except (SystemExit, KeyboardInterrupt):
pass
if __name__ == "__main__":
main()
@knockshore
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment