diff --git a/blueman/gui/manager/ManagerDeviceList.py b/blueman/gui/manager/ManagerDeviceList.py
index 7b67f700c..4ba2b5a23 100644
--- a/blueman/gui/manager/ManagerDeviceList.py
+++ b/blueman/gui/manager/ManagerDeviceList.py
@@ -1,5 +1,5 @@
from gettext import gettext as _
-from typing import Optional, TYPE_CHECKING, List, Any, cast, Callable, Set
+from typing import Optional, TYPE_CHECKING, List, Any, cast, Callable
import html
import logging
import cairo
@@ -16,12 +16,10 @@
from blueman.Sdp import ServiceUUID, OBEX_OBJPUSH_SVCLASS_ID, BATTERY_SERVICE_SVCLASS_ID
from blueman.gui.GtkAnimation import TreeRowFade, CellFade, AnimBase
from blueman.main.Config import Config
-from _blueman import ConnInfoReadError, conn_info
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
-from gi.repository import GLib
from gi.repository import Gdk
from gi.repository import GdkPixbuf
from gi.repository import Pango
@@ -47,9 +45,6 @@ def __init__(self, adapter: Optional[str] = None, inst: Optional["Blueman"] = No
{"id": "rssi_pb", "type": GdkPixbuf.Pixbuf, "renderer": Gtk.CellRendererPixbuf(),
"render_attrs": {}, "view_props": {"spacing": 0},
"celldata_func": (self._set_cell_data, "rssi")},
- {"id": "lq_pb", "type": GdkPixbuf.Pixbuf, "renderer": Gtk.CellRendererPixbuf(),
- "render_attrs": {}, "view_props": {"spacing": 0},
- "celldata_func": (self._set_cell_data, "lq")},
{"id": "tpl_pb", "type": GdkPixbuf.Pixbuf, "renderer": Gtk.CellRendererPixbuf(),
"render_attrs": {}, "view_props": {"spacing": 0},
"celldata_func": (self._set_cell_data, "tpl")},
@@ -60,7 +55,6 @@ def __init__(self, adapter: Optional[str] = None, inst: Optional["Blueman"] = No
{"id": "objpush", "type": bool}, # used to set Send File button
{"id": "battery", "type": float},
{"id": "rssi", "type": float},
- {"id": "lq", "type": float},
{"id": "tpl", "type": float},
{"id": "icon_info", "type": Gtk.IconInfo},
{"id": "cell_fader", "type": CellFade},
@@ -73,8 +67,6 @@ def __init__(self, adapter: Optional[str] = None, inst: Optional["Blueman"] = No
self.props.has_tooltip = True
self.Blueman = inst
- self._monitored_devices: Set[str] = set()
-
self.Config = Config("org.blueman.general")
self.Config.connect('changed', self._on_settings_changed)
# Set the correct sorting
@@ -326,48 +318,6 @@ def row_setup_event(self, tree_iter: Gtk.TreeIter, device: Device) -> None:
except Exception as e:
logging.exception(e)
- if device["Connected"]:
- self._monitor_power_levels(tree_iter, device)
-
- def _monitor_power_levels(self, tree_iter: Gtk.TreeIter, device: Device) -> None:
- if device["Address"] in self._monitored_devices:
- return
-
- assert self.Adapter is not None
- cinfo = conn_info(device["Address"], os.path.basename(self.Adapter.get_object_path()))
- try:
- cinfo.init()
- except ConnInfoReadError:
- logging.warning("Failed to get power levels, probably a LE device.")
-
- model = self.get_model()
- assert isinstance(model, Gtk.TreeModel)
- r = Gtk.TreeRowReference.new(model, model.get_path(tree_iter))
- self._update_power_levels(tree_iter, device, cinfo)
- GLib.timeout_add(1000, self._check_power_levels, r, cinfo, device["Address"])
- self._monitored_devices.add(device["Address"])
-
- def _check_power_levels(self, row_ref: Gtk.TreeRowReference, cinfo: conn_info, address: str) -> bool:
- if not row_ref.valid():
- logging.warning("stopping monitor (row does not exist)")
- cinfo.deinit()
- self._monitored_devices.remove(address)
- return False
-
- tree_iter = self.get_iter(row_ref.get_path())
- assert tree_iter is not None
-
- device = self.get(tree_iter, "device")["device"]
-
- if device["Connected"]:
- self._update_power_levels(tree_iter, device, cinfo)
- return True
- else:
- cinfo.deinit()
- self._disable_power_levels(tree_iter)
- self._monitored_devices.remove(address)
- return False
-
def row_update_event(self, tree_iter: Gtk.TreeIter, key: str, value: Any) -> None:
logging.info(f"{key} {value}")
@@ -392,62 +342,50 @@ def row_update_event(self, tree_iter: Gtk.TreeIter, key: str, value: Any) -> Non
device = self.get(tree_iter, "device")["device"]
has_objpush = self._has_objpush(device)
self.set(tree_iter, objpush=has_objpush)
+ self._check_battery(tree_iter, device)
elif key == "Connected":
self.set(tree_iter, connected=value)
- if value:
- self._monitor_power_levels(tree_iter, self.get(tree_iter, "device")["device"])
- else:
+ if not value:
self._disable_power_levels(tree_iter)
- def _update_power_levels(self, tree_iter: Gtk.TreeIter, device: Device, cinfo: conn_info) -> None:
- row = self.get(tree_iter, "cell_fader", "battery", "rssi", "lq", "tpl")
+ elif key == "RSSI":
+ self._update_bar(tree_iter, "rssi", 50 if value is None else max(50 + float(value) / 127 * 50, 10))
- bars = {}
+ elif key == "TxPower":
+ self._update_bar(tree_iter, "tpl", 0 if value is None else max(float(value) / 127 * 100, 10))
+ elif key == "ServicesResolved":
+ self._check_battery(tree_iter, self.get(tree_iter, "device")["device"])
+
+ def _check_battery(self, tree_iter: Gtk.TreeIter, device: Device) -> None:
if device["ServicesResolved"] and any(ServiceUUID(uuid).short_uuid == BATTERY_SERVICE_SVCLASS_ID
for uuid in device["UUIDs"]):
- bars["battery"] = Battery(obj_path=device.get_object_path())["Percentage"]
+ self._update_bar(tree_iter, "battery", Battery(obj_path=device.get_object_path())["Percentage"])
- # cinfo init may fail for bluetooth devices version 4 and up
- # FIXME Workaround is horrible and we should show something better
- if cinfo.failed:
- if not bars:
- bars = {"rssi": 100.0, "tpl": 100.0, "lq": 100.0}
- else:
- try:
- bars["rssi"] = max(50 + float(cinfo.get_rssi()) / 127 * 50, 10)
- except ConnInfoReadError:
- bars["rssi"] = 50
- try:
- bars["lq"] = max(float(cinfo.get_lq()) / 255 * 100, 10)
- except ConnInfoReadError:
- bars["lq"] = 10
- try:
- bars["tpl"] = max(50 + float(cinfo.get_tpl()) / 127 * 50, 10)
- except ConnInfoReadError:
- bars["tpl"] = 50
-
- if row["battery"] == row["rssi"] == row["tpl"] == row["lq"] == 0:
+ def _update_bar(self, tree_iter: Gtk.TreeIter, name: str, perc: float) -> None:
+ row = self.get(tree_iter, "cell_fader", "battery", "rssi", "tpl")
+ row[name] = perc
+
+ if row["battery"] == row["rssi"] == row["tpl"] == 0:
self._prepare_fader(row["cell_fader"]).animate(start=0.0, end=1.0, duration=400)
w = 14 * self.get_scale_factor()
h = 48 * self.get_scale_factor()
- for (name, perc) in bars.items():
- if round(row[name], -1) != round(perc, -1):
- icon_name = f"blueman-{name}-{int(round(perc, -1))}.png"
- icon = GdkPixbuf.Pixbuf.new_from_file_at_scale(os.path.join(PIXMAP_PATH, icon_name), w, h, True)
- self.set(tree_iter, **{name: perc, f"{name}_pb": icon})
+ if round(row[name], -1) != round(perc, -1):
+ icon_name = f"blueman-{name}-{int(round(perc, -1))}.png"
+ icon = GdkPixbuf.Pixbuf.new_from_file_at_scale(os.path.join(PIXMAP_PATH, icon_name), w, h, True)
+ self.set(tree_iter, **{name: perc, f"{name}_pb": icon})
def _disable_power_levels(self, tree_iter: Gtk.TreeIter) -> None:
- row = self.get(tree_iter, "cell_fader", "battery", "rssi", "lq", "tpl")
- if row["battery"] == row["rssi"] == row["tpl"] == row["lq"] == 0:
+ row = self.get(tree_iter, "cell_fader", "battery", "rssi", "tpl")
+ if row["battery"] == row["rssi"] == row["tpl"] == 0:
return
- self.set(tree_iter, rssi=0, lq=0, tpl=0)
- self._prepare_fader(row["cell_fader"], lambda: self.set(tree_iter, rssi_pb=None, lq_pb=None, tpl_pb=None))\
+ self.set(tree_iter, rssi=0, tpl=0)
+ self._prepare_fader(row["cell_fader"], lambda: self.set(tree_iter, rssi_pb=None, tpl_pb=None))\
.animate(start=1.0, end=0.0, duration=400)
def _prepare_fader(self, fader: AnimBase, callback: Optional[Callable[[], None]] = None) -> AnimBase:
@@ -493,7 +431,6 @@ def tooltip_query(self, _tw: Gtk.Widget, x: int, y: int, _kb: bool, tooltip: Gtk
elif path[1] == self.columns["battery_pb"] \
or path[1] == self.columns["tpl_pb"] \
- or path[1] == self.columns["lq_pb"] \
or path[1] == self.columns["rssi_pb"]:
tree_iter = self.get_iter(path[0])
assert tree_iter is not None
@@ -506,7 +443,6 @@ def tooltip_query(self, _tw: Gtk.Widget, x: int, y: int, _kb: bool, tooltip: Gtk
battery = self.get(tree_iter, "battery")["battery"]
rssi = self.get(tree_iter, "rssi")["rssi"]
- lq = self.get(tree_iter, "lq")["lq"]
tpl = self.get(tree_iter, "tpl")["tpl"]
if battery != 0:
@@ -534,12 +470,6 @@ def tooltip_query(self, _tw: Gtk.Widget, x: int, y: int, _kb: bool, tooltip: Gtk
lines.append(_("Received Signal Strength: %(rssi)u%% (%(rssi_state)s)") %
{"rssi": rssi, "rssi_state": rssi_state})
- if lq != 0:
- if path[1] == self.columns["lq_pb"]:
- lines.append(_("Link Quality: %(lq)u%%") % {"lq": lq})
- else:
- lines.append(_("Link Quality: %(lq)u%%") % {"lq": lq})
-
if tpl != 0:
if tpl < 30:
tpl_state = _("Low")
diff --git a/data/icons/pixmaps/Makefile.am b/data/icons/pixmaps/Makefile.am
index 2536c1f64..2adbd512d 100644
--- a/data/icons/pixmaps/Makefile.am
+++ b/data/icons/pixmaps/Makefile.am
@@ -11,16 +11,6 @@ pixmaps_DATA = \
blueman-battery-80.png \
blueman-battery-90.png \
blueman-battery-100.png \
- blueman-lq-10.png \
- blueman-lq-20.png \
- blueman-lq-30.png \
- blueman-lq-40.png \
- blueman-lq-50.png \
- blueman-lq-60.png \
- blueman-lq-70.png \
- blueman-lq-80.png \
- blueman-lq-90.png \
- blueman-lq-100.png \
blueman-rssi-10.png \
blueman-rssi-20.png \
blueman-rssi-30.png \
diff --git a/data/icons/pixmaps/blueman-lq-10.png b/data/icons/pixmaps/blueman-lq-10.png
deleted file mode 100644
index 71c2b2ed9..000000000
Binary files a/data/icons/pixmaps/blueman-lq-10.png and /dev/null differ
diff --git a/data/icons/pixmaps/blueman-lq-100.png b/data/icons/pixmaps/blueman-lq-100.png
deleted file mode 100644
index 99b4ffb85..000000000
Binary files a/data/icons/pixmaps/blueman-lq-100.png and /dev/null differ
diff --git a/data/icons/pixmaps/blueman-lq-20.png b/data/icons/pixmaps/blueman-lq-20.png
deleted file mode 100644
index a354ff059..000000000
Binary files a/data/icons/pixmaps/blueman-lq-20.png and /dev/null differ
diff --git a/data/icons/pixmaps/blueman-lq-30.png b/data/icons/pixmaps/blueman-lq-30.png
deleted file mode 100644
index cc496198b..000000000
Binary files a/data/icons/pixmaps/blueman-lq-30.png and /dev/null differ
diff --git a/data/icons/pixmaps/blueman-lq-40.png b/data/icons/pixmaps/blueman-lq-40.png
deleted file mode 100644
index 8fb5bb554..000000000
Binary files a/data/icons/pixmaps/blueman-lq-40.png and /dev/null differ
diff --git a/data/icons/pixmaps/blueman-lq-50.png b/data/icons/pixmaps/blueman-lq-50.png
deleted file mode 100644
index 5818da81e..000000000
Binary files a/data/icons/pixmaps/blueman-lq-50.png and /dev/null differ
diff --git a/data/icons/pixmaps/blueman-lq-60.png b/data/icons/pixmaps/blueman-lq-60.png
deleted file mode 100644
index 72846ae56..000000000
Binary files a/data/icons/pixmaps/blueman-lq-60.png and /dev/null differ
diff --git a/data/icons/pixmaps/blueman-lq-70.png b/data/icons/pixmaps/blueman-lq-70.png
deleted file mode 100644
index f7adc7df4..000000000
Binary files a/data/icons/pixmaps/blueman-lq-70.png and /dev/null differ
diff --git a/data/icons/pixmaps/blueman-lq-80.png b/data/icons/pixmaps/blueman-lq-80.png
deleted file mode 100644
index 892b74e77..000000000
Binary files a/data/icons/pixmaps/blueman-lq-80.png and /dev/null differ
diff --git a/data/icons/pixmaps/blueman-lq-90.png b/data/icons/pixmaps/blueman-lq-90.png
deleted file mode 100644
index 1d425e53d..000000000
Binary files a/data/icons/pixmaps/blueman-lq-90.png and /dev/null differ
diff --git a/meson.build b/meson.build
index 53d5abd5d..32921100b 100644
--- a/meson.build
+++ b/meson.build
@@ -100,16 +100,6 @@ install_data(
'data/icons/pixmaps/blueman-battery-80.png',
'data/icons/pixmaps/blueman-battery-90.png',
'data/icons/pixmaps/blueman-battery-100.png',
- 'data/icons/pixmaps/blueman-lq-10.png',
- 'data/icons/pixmaps/blueman-lq-20.png',
- 'data/icons/pixmaps/blueman-lq-30.png',
- 'data/icons/pixmaps/blueman-lq-40.png',
- 'data/icons/pixmaps/blueman-lq-50.png',
- 'data/icons/pixmaps/blueman-lq-60.png',
- 'data/icons/pixmaps/blueman-lq-70.png',
- 'data/icons/pixmaps/blueman-lq-80.png',
- 'data/icons/pixmaps/blueman-lq-90.png',
- 'data/icons/pixmaps/blueman-lq-100.png',
'data/icons/pixmaps/blueman-rssi-10.png',
'data/icons/pixmaps/blueman-rssi-20.png',
'data/icons/pixmaps/blueman-rssi-30.png',
diff --git a/module/_blueman.pyx b/module/_blueman.pyx
index 428b75917..e28ea8143 100644
--- a/module/_blueman.pyx
+++ b/module/_blueman.pyx
@@ -72,16 +72,6 @@ cdef extern from "bluetooth/rfcomm.h":
cdef extern from "libblueman.h":
- cdef struct conn_info_handles:
- unsigned int handle
- int dd
-
-
- cdef int connection_init(int dev_id, char *addr, conn_info_handles *ci)
- cdef int connection_get_rssi(conn_info_handles *ci, signed char *ret_rssi)
- cdef int connection_get_lq(conn_info_handles *ci, unsigned char *ret_lq)
- cdef int connection_get_tpl(conn_info_handles *ci, signed char *ret_tpl, unsigned char type)
- cdef int connection_close(conn_info_handles *ci)
cdef int c_get_rfcomm_channel "get_rfcomm_channel" (unsigned short service_class, char* btd_addr)
cdef int get_rfcomm_list(rfcomm_dev_list_req **ret)
cdef int c_create_rfcomm_device "create_rfcomm_device" (char *local_address, char *remote_address, int channel)
@@ -95,12 +85,6 @@ class RFCOMMError(Exception):
ERR = {
-1:"Can't allocate memory",
- -2:"HCI device open failed",
- -3:"Not connected",
- -4:"Get connection info failed",
- -5:"Read RSSI failed",
- -6:"Read transmit power level request failed",
- -7:"Read Link quality failed",
-8:"Getting rfcomm list failed",
-9:"ERR_SOCKET_FAILED",
-12: "Can't bind RFCOMM socket",
@@ -207,63 +191,6 @@ def destroy_bridge(py_name="pan1"):
if err < 0:
raise BridgeException(-err)
-
-class ConnInfoReadError(Exception):
- pass
-
-cdef class conn_info:
- cdef conn_info_handles ci
- cdef int hci
- cdef char* addr
- cdef public bint failed
-
- def __init__(self, py_addr, py_hci_name="hci0"):
- self.failed = False
- py_bytes_addr = py_addr.encode("UTF-8")
- cdef char* addr = py_bytes_addr
-
- py_bytes_hci_name = py_hci_name.encode("UTF-8")
- cdef char* hci_name = py_bytes_hci_name
-
-
- self.hci = int(hci_name[3:])
- self.addr = addr
-
- def init(self):
- res = connection_init(self.hci, self.addr, & self.ci)
- if res < 0:
- self.failed = True
- raise ConnInfoReadError(ERR[res])
-
- def deinit(self):
- if self.failed:
- return
- connection_close(&self.ci)
-
- def get_rssi(self):
- cdef signed char rssi
- res = connection_get_rssi(&self.ci, &rssi)
- if res < 0:
- raise ConnInfoReadError(ERR[res])
-
- return rssi
-
- def get_lq(self):
- cdef unsigned char lq
- res = connection_get_lq(&self.ci, &lq)
- if res < 0:
- raise ConnInfoReadError(ERR[res])
-
- return lq
-
- def get_tpl(self, tp=0):
- cdef signed char tpl
- res = connection_get_tpl(&self.ci, &tpl, tp)
- if res < 0:
- raise ConnInfoReadError(ERR[res])
-
- return tpl
-
def device_info(py_hci_name="hci0"):
py_bytes_hci_name = py_hci_name.encode("UTF-8")
cdef char* hci_name = py_bytes_hci_name
diff --git a/module/libblueman.c b/module/libblueman.c
index 69c1fbfeb..ddd5c09ba 100644
--- a/module/libblueman.c
+++ b/module/libblueman.c
@@ -35,8 +35,6 @@
#include
#include
-#include
-#include
#include
#include
#include
@@ -132,119 +130,6 @@ int _destroy_bridge(const char* name) {
return 0;
}
-static int find_conn(int s, int dev_id, long arg)
-{
- struct hci_conn_list_req *cl;
- struct hci_conn_info *ci;
- int i;
- int ret = 0;
-
- if (!(cl = malloc(10 * sizeof(*ci) + sizeof(*cl))))
- goto out;
-
- cl->dev_id = dev_id;
- cl->conn_num = 10;
- ci = cl->conn_info;
-
- if (ioctl(s, HCIGETCONNLIST, (void *) cl))
- goto out;
-
- for (i = 0; i < cl->conn_num; i++, ci++)
- if (!bacmp((bdaddr_t *) arg, &ci->bdaddr)) {
- ret = 1;
- goto out;
- }
-
-out:
- free(cl);
- return ret;
-}
-
-
-
-int connection_init(int dev_id, char *addr, struct conn_info_handles *ci)
-{
- struct hci_conn_info_req *cr = NULL;
- bdaddr_t bdaddr;
-
- int dd;
- int ret = 1;
-
- str2ba(addr, &bdaddr);
-
- if (dev_id < 0) {
- dev_id = hci_for_each_dev(HCI_UP, find_conn, (long) &bdaddr);
- if (dev_id < 0) {
- ret = ERR_NOT_CONNECTED;
- goto out;
- }
- }
-
- dd = hci_open_dev(dev_id);
- if (dd < 0) {
- ret = ERR_HCI_DEV_OPEN_FAILED;
- goto out;
- }
-
- cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));
- if (!cr) {
- ret = ERR_CANNOT_ALLOCATE;
- goto out;
- }
-
- bacpy(&cr->bdaddr, &bdaddr);
- cr->type = ACL_LINK;
- if (ioctl(dd, HCIGETCONNINFO, (unsigned long) cr) < 0) {
- ret = ERR_GET_CONN_INFO_FAILED;
- goto out;
- }
-
- ci->dd = dd;
- ci->handle = cr->conn_info->handle;
-
-out:
- if (cr)
- free(cr);
-
- return ret;
-}
-
-int connection_get_rssi(struct conn_info_handles *ci, int8_t *ret_rssi)
-{
- int8_t rssi;
- if (hci_read_rssi(ci->dd, htobs(ci->handle), &rssi, 1000) < 0) {
- return ERR_READ_RSSI_FAILED;
- }
- *ret_rssi = rssi;
- return 1;
-
-}
-
-int connection_get_lq(struct conn_info_handles *ci, uint8_t *ret_lq)
-{
- uint8_t lq;
- if (hci_read_link_quality(ci->dd, htobs(ci->handle), &lq, 1000) < 0) {
- return ERR_READ_LQ_FAILED;
- }
- *ret_lq = lq;
- return 1;
-}
-
-int connection_get_tpl(struct conn_info_handles *ci, int8_t *ret_tpl, uint8_t type)
-{
- int8_t level;
- if (hci_read_transmit_power_level(ci->dd, htobs(ci->handle), type, &level, 1000) < 0) {
- return ERR_READ_TPL_FAILED;
- }
- *ret_tpl = level;
- return 1;
-}
-
-int connection_close(struct conn_info_handles *ci)
-{
- hci_close_dev(ci->dd);
- return 1;
-}
int
get_rfcomm_channel(uint16_t service_class, char* btd_addr) {
diff --git a/module/libblueman.h b/module/libblueman.h
index fd0f2f44b..9ad6bfb7f 100644
--- a/module/libblueman.h
+++ b/module/libblueman.h
@@ -1,11 +1,5 @@
#pragma once
#define ERR_CANNOT_ALLOCATE -1
-#define ERR_HCI_DEV_OPEN_FAILED -2
-#define ERR_NOT_CONNECTED -3
-#define ERR_GET_CONN_INFO_FAILED -4
-#define ERR_READ_RSSI_FAILED -5
-#define ERR_READ_TPL_FAILED -6
-#define ERR_READ_LQ_FAILED -7
#define ERR_GET_RFCOMM_LIST_FAILED -8
#define ERR_SOCKET_FAILED -9
#define ERR_BIND_FAILED -12
@@ -13,16 +7,6 @@
#define ERR_CREATE_DEV_FAILED -14
#define ERR_RELEASE_DEV_FAILED -15
-struct conn_info_handles {
- unsigned int handle;
- int dd;
-};
-
-int connection_init(int dev_id, char *addr, struct conn_info_handles *ci);
-int connection_get_rssi(struct conn_info_handles *ci, int8_t *ret_rssi);
-int connection_get_lq(struct conn_info_handles *ci, uint8_t *ret_lq);
-int connection_get_tpl(struct conn_info_handles *ci, int8_t *ret_tpl, uint8_t type);
-int connection_close(struct conn_info_handles *ci);
int get_rfcomm_channel(uint16_t uuid, char* btd_addr);
int get_rfcomm_list(struct rfcomm_dev_list_req **result);
int create_rfcomm_device(char *local_address, char *remote_address, int channel);
diff --git a/stubs/_blueman.pyi b/stubs/_blueman.pyi
index 03a3ee711..8bf0b645f 100644
--- a/stubs/_blueman.pyi
+++ b/stubs/_blueman.pyi
@@ -35,19 +35,8 @@ class BridgeException(Exception):
errno: int
def __init__(self, errno: int) -> None: ...
-class ConnInfoReadError(Exception): ...
-
class RFCOMMError(Exception): ...
-class conn_info:
- failed: bool
- def __init__(self, addr: str, hci_name: str) -> None: ...
- def deinit(self) -> None: ...
- def get_lq(self) -> int: ...
- def get_rssi(self) -> int: ...
- def get_tpl(self) -> int: ...
- def init(self) -> None: ...
-
def create_bridge(name: str = "pan1") -> None: ...
def create_rfcomm_device(local_address: str, remote_address: str, channel: int) -> int: ...
def destroy_bridge(name: str = "pan1") -> None: ...