summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Cady <d@jerkface.net>2017-04-08 17:03:16 +0000
committerAndrew Cady <d@jerkface.net>2017-04-08 17:03:16 +0000
commit3b97e9fe5d905a53a339b2bd46c6c776dc13fed1 (patch)
treecac49cde5dccd559c021307bf24e75b07b23bd33
parent532a7e1b52805b087afdc2dcbeb8b33799799a50 (diff)
parent17984a16a763dee4b1f20f3383b2f39721cfeb95 (diff)
Merge branch 'master' of fifty.local:src/dexcom_reader
-rw-r--r--dexcom_reader/devicer.py72
-rwxr-xr-xdexcom_reader/dexcom_dumper.py92
2 files changed, 127 insertions, 37 deletions
diff --git a/dexcom_reader/devicer.py b/dexcom_reader/devicer.py
new file mode 100644
index 0000000..79a0a72
--- /dev/null
+++ b/dexcom_reader/devicer.py
@@ -0,0 +1,72 @@
1import pyudev
2import threading
3
4class DevicePoller:
5 def __init__(self, dev):
6 self.device_added = threading.Event()
7 self.device_removed = threading.Event()
8 self.device = dev
9 self.wait_add = self.device_added.wait
10 self.wait_remove = self.device_removed.wait
11 self.have = self.device_added.is_set
12
13 if dev:
14 self.device_added.set()
15
16 def launch_observer(self, monitor, device_match):
17
18 if not monitor:
19 monitor = pyudev.Monitor.from_netlink(pyudev.Context())
20
21 def handle_event(action, device):
22 if action == 'add' and device_match(device):
23 self.device = device
24 self.device_removed.clear()
25 self.device_added.set()
26 elif action == 'remove' and device == self.device:
27 self.device = None
28 self.device_added.clear()
29 self.device_removed.set()
30
31 self.observer = pyudev.MonitorObserver(monitor, handle_event)
32 self.observer.start()
33
34 def stop_observer():
35 self.observer.stop()
36
37def simple_devicer(subsystem, predicate):
38 dev = None
39 context = pyudev.Context()
40 for try_dev in context.list_devices(subsystem=subsystem):
41 if predicate(try_dev):
42 dev = try_dev
43 break
44
45 monitor = pyudev.Monitor.from_netlink(context)
46 monitor.filter_by(subsystem)
47
48 devicer = DevicePoller(dev)
49 devicer.launch_observer(monitor, predicate)
50
51 return devicer
52
53if __name__ == '__main__':
54
55 dexcom_g5_product = '22a3/47/100'
56
57 def is_dexcom_g5(dev):
58 try: return dev.parent.get('PRODUCT') == dexcom_g5_product
59 except: return False
60
61 devicer = simple_devicer('tty', is_dexcom_g5)
62
63 while True:
64 print("waiting for device")
65 devicer.wait_add()
66 while devicer.have():
67 print("poll device {0}".format(devicer.device))
68 print("sleep(5)")
69 if devicer.wait_remove(5):
70 print("device removed")
71
72 devicer.stop_observer()
diff --git a/dexcom_reader/dexcom_dumper.py b/dexcom_reader/dexcom_dumper.py
index 6cfc720..ca85b0b 100755
--- a/dexcom_reader/dexcom_dumper.py
+++ b/dexcom_reader/dexcom_dumper.py
@@ -4,6 +4,7 @@ import readdata
4import sys 4import sys
5import json 5import json
6import traceback 6import traceback
7from devicer import simple_devicer
7# import requests # As this takes SEVEN SECONDS, it's delayed until needed 8# import requests # As this takes SEVEN SECONDS, it's delayed until needed
8from sys import stdout, stderr 9from sys import stdout, stderr
9from datetime import timedelta, datetime 10from datetime import timedelta, datetime
@@ -52,7 +53,10 @@ def get_dexcom_reader():
52 dd = readdata.Dexcom.FindDevice() 53 dd = readdata.Dexcom.FindDevice()
53 return readdata.Dexcom(dd) 54 return readdata.Dexcom(dd)
54 55
55dr = get_dexcom_reader() 56dr = None
57
58if command is not 'poll':
59 dr = get_dexcom_reader()
56 60
57def parseable_record_types(): 61def parseable_record_types():
58 unparseable = ['FIRMWARE_PARAMETER_DATA', 'RECEIVER_LOG_DATA', 'USER_SETTING_DATA', 'MAX_VALUE'] 62 unparseable = ['FIRMWARE_PARAMETER_DATA', 'RECEIVER_LOG_DATA', 'USER_SETTING_DATA', 'MAX_VALUE']
@@ -156,38 +160,10 @@ def print_cgm_bg(now, r):
156 print '%s: %s %s' % (format_times(now, r.system_time), r.glucose, r.trend_arrow) 160 print '%s: %s %s' % (format_times(now, r.system_time), r.glucose, r.trend_arrow)
157 stdout.flush() 161 stdout.flush()
158 162
159def dexcom_reconnect():
160 global dr
161 dr = get_dexcom_reader()
162
163def poll():
164 print_verbose('Started dexcom_dumper.')
165 while True:
166 try:
167 poll_remote() if HOST else poll_stdout()
168
169 except constants.SerialPortError:
170 connected(False)
171 dexcom_reconnect()
172 sleep_verbose(10)
173 except KeyboardInterrupt:
174 print_verbose('Exiting.')
175 return
176 except:
177 # Check for requests.ConnectionError without necessarily importing requests
178 if (str(sys.exc_info()[0]) == "<class 'requests.exceptions.ConnectionError'>"):
179 print_verbose('Error: could not connect to remote host.')
180 else:
181 print_verbose('Exception: %s' % str(sys.exc_info()[0]))
182 traceback.print_exc()
183 dexcom_reconnect()
184 sleep_verbose(10)
185
186def poll_remote(): 163def poll_remote():
187 (n, r) = remote_update('EGV_DATA') 164 (n, r) = remote_update('EGV_DATA')
188 connected(True)
189 if n is None: 165 if n is None:
190 sleep_verbose(10) 166 return 10
191 else: 167 else:
192 now = dr.ReadSystemTime() 168 now = dr.ReadSystemTime()
193 if n == 0: 169 if n == 0:
@@ -200,20 +176,62 @@ def poll_remote():
200 except: 176 except:
201 traceback.print_exc() 177 traceback.print_exc()
202 next_reading = (r.system_time - now + timedelta(minutes=5, seconds=2)).total_seconds() 178 next_reading = (r.system_time - now + timedelta(minutes=5, seconds=2)).total_seconds()
203 sleep_verbose(max(10, next_reading)) 179 return max(10, next_reading)
204 else: 180 else:
205 sleep_verbose(10) 181 return 10
182
183def poll():
184 print_verbose('Started dexcom_dumper.')
185 poll_once = poll_remote if HOST else poll_stdout
186
187 dexcom_g5_product = '22a3/47/100'
188
189 def is_dexcom_g5(dev):
190 try: return dev.parent.get('PRODUCT') == dexcom_g5_product
191 except: return False
192
193 devicer = simple_devicer('tty', is_dexcom_g5)
194
195 while True:
196 try:
197 print_verbose("Waiting for device.")
198 if not devicer.wait_add(600):
199 # This does not really need to time out, but if there
200 # is no timeout, then keyboard interrupt does not work.
201 # Might as well use the opportunity to print more
202 # garbage into the log, though.
203 continue
204 print_verbose("Device found.")
205
206 global dr
207 if dr:
208 dr.Disconnect()
209 dr = readdata.DexcomG5(devicer.device.device_node)
210
211 print("Device opened.")
212 while devicer.have():
213 print_verbose("Polling device.")
214 try:
215 sleeptime = poll_once()
216 except:
217 sleeptime = 10
218
219 if devicer.wait_remove(sleeptime):
220 print_verbose("Device unplugged.")
221 dr.Disconnect()
222 dr = None
223 except KeyboardInterrupt:
224 break
206 225
207def poll_stdout(): 226def poll_stdout():
208 (r, now) = read_recent_egv_data() 227 (r, now) = read_recent_egv_data()
209 connected(True)
210 if r is None: 228 if r is None:
211 sleep_verbose(10) 229 return 10
212 else: 230 else:
213 print_cgm_bg(now, r) 231 print_cgm_bg(now, r)
214 next_reading = (r.system_time - now + timedelta(minutes=5, seconds=2)).total_seconds() 232 next_reading = (r.system_time - now + timedelta(minutes=5, seconds=2)).total_seconds()
215 if (next_reading > 0): 233 return next_reading if (next_reading > 0) else 10
216 sleep_verbose(next_reading) 234
217 235
218def since(when, rectype): 236def since(when, rectype):
219 filt = lambda r: (r.system_time > when) if when else True 237 filt = lambda r: (r.system_time > when) if when else True
@@ -357,5 +375,5 @@ def toJSON(o):
357{"dump_everything": dump_everything, 375{"dump_everything": dump_everything,
358 "dump_cgm": dump_cgm, 376 "dump_cgm": dump_cgm,
359 "poll": poll, 377 "poll": poll,
360 "test": test, 378 "test": poll,
361}[command]() 379}[command]()