]> code.delx.au - monosys/blob - bt-dun-connect
lib-ext-backup: set fs mountpoint and permissions
[monosys] / bt-dun-connect
1 #!/usr/bin/env python3
2
3 import dbus
4 import json
5 import os
6 import subprocess
7 import sys
8 import tempfile
9 import time
10
11 """
12 Instructions!
13 1. Pair your bluetooth device, use bluetoothctl
14 2. Use 'sdptool search DUN' to find the bluetooth channel
15 3. Save your configuration to ~/.config/bt-dun-connect.json
16 4. Run bt-dun-connect
17
18
19 Example configuration:
20 {
21 "apn": "internet",
22 "bluetooth_addr": "DE:AD:BE:EE:EE:EF",
23 "bluetooth_channel": "22"
24 }
25
26 """
27
28
29 class DiallerException(Exception):
30 pass
31
32 class BluetoothDialler(object):
33 def __init__(self, rfcomm_id, bt_addr, bt_channel, apn):
34 self.rfcomm_id = rfcomm_id
35 self.bt_addr = bt_addr
36 self.bt_channel = bt_channel
37 self.apn = apn
38
39 self.rfcomm = None
40 self.wvdial = None
41 self.wvdial_conf_name = None
42 self.dbus_system = None
43
44 def release(self):
45 if self.wvdial:
46 try:
47 self.wvdial.terminate()
48 self.wvdial.wait()
49 except Exception as e:
50 print(e)
51
52 if self.rfcomm:
53 try:
54 self.rfcomm.terminate()
55 self.rfcomm.wait()
56 except Exception as e:
57 print(e)
58
59 if self.wvdial_conf_name:
60 try:
61 os.unlink(self.wvdial_conf_name)
62 except Exception as e:
63 print(e)
64
65 try:
66 reset_rfcomm(self.rfcomm_id)
67 except Exception as e:
68 print(e)
69
70 if self.dbus_system:
71 try:
72 self.disconnect_bluetooth()
73 except Exception as e:
74 print(e)
75
76
77 def setup_dbus(self):
78 self.dbus_system = dbus.SystemBus()
79
80 def enable_bluetooth(self):
81 bluez = self.dbus_system.get_object("org.bluez", "/org/bluez/hci0")
82 iprops = dbus.Interface(bluez, "org.freedesktop.DBus.Properties")
83 iprops.Set("org.bluez.Adapter1", "Powered", True)
84
85 def disconnect_bluetooth(self):
86 path = self.bt_addr.upper().replace(":", "_")
87 bluez_dev = self.dbus_system.get_object("org.bluez", "/org/bluez/hci0/dev_" + path)
88 idev = dbus.Interface(bluez_dev, "org.bluez.Device1")
89 idev.Disconnect()
90
91 def connect_rfcomm(self):
92 self.rfcomm = subprocess.Popen([
93 "rfcomm",
94 "connect",
95 self.rfcomm_id,
96 self.bt_addr,
97 self.bt_channel,
98 ])
99
100 # poll until connected
101 start = time.time()
102 while time.time() - start < 10:
103 if self.is_rfcomm_connected():
104 return
105 time.sleep(0.1)
106 raise DiallerException("Timeout connecting rfcomm")
107
108 def is_rfcomm_connected(self):
109 output = subprocess.check_output(["rfcomm", "-a"])
110 for line in output.decode("ascii").split("\n"):
111 if not line.startswith("rfcomm%s:" % self.rfcomm_id):
112 continue
113 if line.find(" connected ") >= 0:
114 return True
115 return False
116
117 def write_wvdial_conf(self):
118 fd, self.wvdial_conf_name = tempfile.mkstemp()
119 f = os.fdopen(fd, "w")
120 f.write("""
121 [Dialer Defaults]
122 Modem = /dev/rfcomm0
123 Baud = 115200
124 Init = ATZ
125 Init2 = AT+CGDCONT=1,"IP","%s"
126 Phone = *99#
127 Username = dummy
128 Password = dummy
129 """ % self.apn)
130 f.close()
131
132 def connect_wvdial(self):
133 self.wvdial = subprocess.Popen([
134 "wvdial", "-C", self.wvdial_conf_name
135 ])
136 self.wvdial.wait()
137
138
139 def run(self):
140 try:
141 self.setup_dbus()
142
143 print("Enabling bluetooth...")
144 self.enable_bluetooth()
145
146 print("Connecting rfcomm...")
147 self.connect_rfcomm()
148 self.write_wvdial_conf()
149
150 print("Dialling...")
151 self.connect_wvdial()
152
153 except KeyboardInterrupt as e:
154 print("Exiting...")
155 except DiallerException as e:
156 print(e)
157 finally:
158 self.release()
159
160
161 def get_next_rfcomm_id():
162 # for now always use rfcomm0
163 reset_rfcomm("all")
164 return "0"
165
166 def reset_rfcomm(rfcomm_id):
167 subprocess.call(["rfcomm", "release", rfcomm_id], stderr=open("/dev/null"))
168
169 def read_config(filename):
170 try:
171 config = open(os.path.expanduser(filename))
172 except OSError as e:
173 print("Failed to open config file: %s" % e)
174 sys.exit(1)
175
176 try:
177 return json.load(config)
178 except ValueError as e:
179 print("Failed to parse config file %s: %s" % (filename, e))
180 sys.exit(1)
181
182
183 def main():
184 rfcomm_id = get_next_rfcomm_id()
185 config = read_config("~/.config/bt-dun-connect.json")
186 dialler = BluetoothDialler(
187 rfcomm_id=rfcomm_id,
188 bt_addr=config["bluetooth_addr"],
189 bt_channel=config["bluetooth_channel"],
190 apn=config["apn"],
191 )
192 dialler.run()
193
194
195 if __name__ == "__main__":
196 main()
197
198
199