devices.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. #!/usr/bin/env python3
  2. import subprocess
  3. IGNORED_DEVICES = {
  4. "lo",
  5. "docker0",
  6. }
  7. IGNORED_PREFIXES = (
  8. "br-",
  9. "veth",
  10. "virbr",
  11. "tun",
  12. "tap",
  13. )
  14. IGNORED_TYPES = {
  15. "loopback",
  16. "bridge",
  17. }
  18. def devices() -> list:
  19. result = subprocess.run(
  20. [
  21. "nmcli",
  22. "-t",
  23. "-f",
  24. "DEVICE,TYPE,STATE,CONNECTION",
  25. "device",
  26. "status",
  27. ],
  28. text=True,
  29. capture_output=True,
  30. check=True,
  31. )
  32. devices = []
  33. for line in result.stdout.strip().splitlines():
  34. device, dev_type, state, connection = line.split(":", 3)
  35. # filter ignored device names
  36. if device in IGNORED_DEVICES:
  37. continue
  38. # filter virtual interface prefixes
  39. if any(device.startswith(prefix) for prefix in IGNORED_PREFIXES):
  40. continue
  41. # filter unwanted interface types
  42. if dev_type in IGNORED_TYPES:
  43. continue
  44. devices.append({
  45. "device": device,
  46. "type": dev_type,
  47. "state": state,
  48. "connection": None if connection == "--" else connection,
  49. })
  50. return devices
  51. def wifi_enabled() -> bool:
  52. result = subprocess.run(
  53. ["nmcli", "radio", "wifi"],
  54. text=True,
  55. capture_output=True,
  56. check=True,
  57. )
  58. return result.stdout.strip() == "enabled"
  59. def yuck() -> str:
  60. ret = r"""(box :orientation "v" :spacing 8"""
  61. ret += rf"""
  62. (box :orientation "h" :space-evenly false :spacing 16 :class "device-item"
  63. (label
  64. :class "device-icon"
  65. :text "{"airplanemode_inactive" if wifi_enabled() else "flight"}"
  66. )
  67. (box :orientation "v" :space-evenly true :spacing 2
  68. (label :class "device-name" :text "Flymodus" :xalign 0)
  69. )
  70. (box :hexpand true)
  71. (checkbox
  72. :checked {str(not wifi_enabled()).lower()}
  73. :onunchecked "nmcli radio wifi on"
  74. :onchecked "nmcli radio wifi off"
  75. )
  76. )
  77. """
  78. for device in devices():
  79. safe_name = device["device"].replace('"', r'\"')
  80. signal_icon = "settings_input_antenna" if device["type"] == "wifi" else "lan"
  81. if device["state"] == "connected":
  82. ret += rf"""
  83. (box :orientation "h" :space-evenly false :spacing 16 :class "device-item"
  84. (label :class "device-icon" :text "{signal_icon}")
  85. (box :orientation "v" :space-evenly false :spacing 2
  86. (label :class "device-name" :text "{safe_name}" :xalign 0)
  87. (label :class "device-subtext" :text "Aktiv" :xalign 0)
  88. )
  89. (box :hexpand true)
  90. (checkbox
  91. :checked true
  92. :onchecked "~/.config/eww/widgets/network/scripts/device_up.sh '{safe_name}'"
  93. :onunchecked "~/.config/eww/widgets/network/scripts/device_down.sh '{safe_name}'"
  94. )
  95. )
  96. """
  97. else:
  98. ret += rf"""
  99. (box :orientation "h" :space-evenly false :spacing 16 :class "device-item"
  100. (label :class "device-icon" :text "{signal_icon}")
  101. (box :orientation "v" :space-evenly true :spacing 2
  102. (label :class "device-name" :text "{safe_name}" :xalign 0)
  103. )
  104. (box :hexpand true)
  105. (checkbox
  106. :checked false
  107. :onchecked "~/.config/eww/widgets/network/scripts/device_up.sh '{safe_name}'"
  108. :onunchecked "~/.config/eww/widgets/network/scripts/device_down.sh '{safe_name}'"
  109. )
  110. )
  111. """
  112. return ret + ")"
  113. print(yuck())