Skip to content

Commit

Permalink
Dexusb cgm loop (#282)
Browse files Browse the repository at this point in the history
* Merge remote-tracking branch 'refs/remotes/origin/oref0-setup' into openaps/oref0-setup

merge

* make oref0-find-ti work on edison explorer board out of the box, required for ww pump

rename files, add to package.json

* fix json tabs and comma's

* use oref0-find-ti (because it also works on explorer board)

* fix dexusb and oref0-find-ti issue

* remove stdin by default

* create .profile  and dexusb fixes

* fix oref0 install docs

as suggested by @scottleibrand on issue
#261 (comment)

* apply changes because of scott's review

fix things a scott suggested on 28-12-2016

* sort files under bin in package.json. increment version number and use semver to indicate dev version

* run subg-ww-radio-parameters script on mmtune

* append radio_locale to pump.ini for ww pumps

temporary workaround for
oskarpearson/mmeowlink#55

* fix add radio_locale if it's not there workaround

oops, grep -q returns 0 if found, we want to add radio_locale if it's
not there so && instead of ||
  • Loading branch information
PieterGit authored and scottleibrand committed Dec 29, 2016
1 parent 9241e94 commit 65da6ed
Show file tree
Hide file tree
Showing 7 changed files with 345 additions and 33 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Dev code coverage: [![Coverage Status](https://coveralls.io/repos/github/openaps

Install tools globally:

`sudo npm install -g oref0`
`npm run global-install`

## Usage

Expand Down
170 changes: 170 additions & 0 deletions bin/oref0-dexusb-cgm-loop.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,170 @@
#!/usr/bin/python

# This script will create a cgm-loop that will feed the cgm data
# to the OpenAPS environment and will rezone it and upload it to
# Nightscout
# Tested with Dexcom G4 non share
#
# Released under MIT license. See the accompanying LICENSE.txt file for
# full terms and conditions
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

from __future__ import print_function
import json
import time
import subprocess
import datetime
import dateutil.parser
import sys

# How to integrate with openaps.
# Step 1. Add the following lines to your ~/.profile
# export NIGHTSCOUT_HOST="<<url>>"
# export API_SECRET=<<apisecret>>
# use a new shell, or use source ~/.profile
#
# Step 2. Edit your crontab with `crontab -e` and append the following line:
# @reboot echo cgm-loop ; cd /home/pi/openapsdir && python oref0-dexusb-cgm-loop.py >> /var/log/openaps/cgm-loop2.log
# this will start this python script at reboot, and log to /var/log/openaps/cgm-loop2.log
#
# Step 3. Disable the default cgm loop in crontab, because this script will invoke openaps get-bg
#
# Step 4. Reboot

HOURS=24
CMD_GET_GLUCOSE="openaps use cgm oref0_glucose --hours %d --threshold 100"
CMD_DESCRIBE_CLOCKS="openaps use cgm DescribeClocks"
DEST="raw-cgm/raw-entries.json"
CMD_NS_UPLOAD_ENTRIES="ns-upload-entries %s" % DEST
CMD_OPENAPS_GET_BG="openaps get-bg"
WAIT=5*60+1 # wait 5 minutes and 1 second
CGMPER24H=288*2 # 24 hours = 288 * 5 minutes. For raw values multiply by 2

# Redirect stdin file descriptor. Otherwise it will not start without a terminal
sys.stdin = open('/dev/null', 'r')

# limit list to maxlen items
def limitlist(l,maxlen):
if len(l)<maxlen:
return l
else:
return l[:maxlen]

# execute a command, print

def gettimestatusoutput(command):
print( "Executing command %s" % command, end="")
t1=datetime.datetime.now()
try:
data = subprocess.check_output(command, shell=True, universal_newlines=True, stderr=subprocess.STDOUT)
status = 0
except subprocess.CalledProcessError as ex:
data = ex.output
status = ex.returncode
if data[-1:] == '\n':
data = data[:-1]
t2=datetime.datetime.now()
deltat=(t2-t1).microseconds/1e6
print(" in %.2f seconds (exitcode=%d)" % (deltat,status))
if status!=0:
print("Error: %s" % data)
return (deltat, status, data)

def hours_since(dt):
if dt==-1:
return HOURS
current_dt=datetime.datetime.now()
cgm_dt=dateutil.parser.parse(dt)
delta_t=current_dt-cgm_dt
delta_hours=int(delta_t.days*24 + delta_t.seconds//3600)
if delta_hours<1:
delta_hours=1
if delta_hours>24:
delta_hours=24
return delta_hours

def calculate_wait_until_next_cgm(dt):
if dt==-1:
return 60
# will implement automatic waiting for next cgm reading later, for now check every minute
return 60

# First iteration: get a lot of egv data
iteration=1
status=-1
output=""
hours=HOURS
most_recent_cgm_display_time=-1
most_recent_cgm_system_time=datetime.datetime.now()

print("Starting loop")
while (status!=0):
(t, status, output) = gettimestatusoutput(CMD_GET_GLUCOSE % hours)
if status==0:
break
iteration=iteration+1
print("Iteration: %d. Sleeping %d seconds" % (iteration, WAIT))
time.sleep(WAIT)

print("Writing output of '%s' to %s" % (CMD_GET_GLUCOSE, DEST))
f = open(DEST, 'w')
f.write(output)
f.close()

j1=json.loads(output)

print("Rezoning and feeding to openaps")
(t,status, output) = gettimestatusoutput(CMD_OPENAPS_GET_BG)

print("Uploading to nightscout")
(t,status, output) = gettimestatusoutput(CMD_NS_UPLOAD_ENTRIES)

display_time_list=[]
for d in j1:
display_time_list.append(d["display_time"])
len_j1=len(j1)

print("Read %d records"% len_j1)
sliding24h=j1
most_recent_cgm=display_time_list[0]
print("Most recent cgm display time: %s" % most_recent_cgm)

while (True):
iteration=iteration+1
wait=calculate_wait_until_next_cgm(most_recent_cgm)
print("Round: %d. Sleeping %d seconds" % (iteration, wait))
time.sleep(wait)
new=[]
hours=hours_since(most_recent_cgm)
(t, status, output) = gettimestatusoutput(CMD_GET_GLUCOSE % hours)
if status==0:
j2=json.loads(output)
for d in j2:
dt=d["display_time"]
if not (dt in display_time_list):
print("New: %s" % dt)
display_time_list.append(dt)
new.append(d)
most_recent_cgm=dt

if len(new)>0: # only do stuff if we have new cgm records
new=limitlist(new+sliding24h, CGMPER24H)
sliding24h=new
f = open(DEST, 'w')
f.write(json.dumps(sliding24h, sort_keys=True, indent=4, separators=(',', ': ')))
f.close()
print("Rezoning and feeding to openaps")
(t,status, output) = gettimestatusoutput(CMD_OPENAPS_GET_BG)

print("Uploading to nightscout")
(t,status, output) = gettimestatusoutput(CMD_NS_UPLOAD_ENTRIES)



47 changes: 47 additions & 0 deletions bin/oref0-find-ti.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#!/bin/sh

#use this to bypass the automatic detection
#for example when you have slice of radio/EMF or TI-stick with Intel/Sparx Breakout board with Edison
#echo /dev/ttyAMA0
#exit 0

# Assume Explorerboard when /dev/spidev5.1 exists. This is not always true (e.g. Intel Edison with Intel/Sparx breakout board)
# if there is a better way to detect an Explorer board please fix
EXPLORER=/dev/spidev5.1
if [ -c $EXPLORER ]; then
echo $EXPLORER
exit 0
fi

# see if a TI-stick is available
A=`lsusb -d 1d50:8001 | wc -l`

if [ "$A" -eq "0" ]; then
echo No TI stick, USB device idVendor=1d50, idProduct=8001 is found
exit 1
fi

usbid=`dmesg | grep "idVendor=1d50, idProduct=8001" | tail -n 1 | sed -e 's/^.*usb \([0-9\.\-]*\):.*$/\1/g'`

if [ -z "$usbid" ]; then
echo Could not find TI stick, USB device idVendor=1d50, idProduct=8001
lsusb -d 1d50:8001
exit 1
fi

device=/dev/`dmesg | grep "cdc_acm $usbid" | tail -n 1 | sed -e 's/^.*: \(tty[A-Z0-9]*\): USB.*$/\1/g'`

echo $device
if [ -c $device ]; then
A=`lsusb -d 1d50:8001 | wc -l`
# see if TI-stick is still connected
if [ "$A" -gt "0" ]; then
exit 0
else
exit 1
fi
else
exit 0
fi

exit 1
26 changes: 23 additions & 3 deletions bin/oref0-setup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ if ! ( git config -l | grep -q user.name ); then
git config --global user.name $NAME
fi
if [[ -z "$DIR" || -z "$serial" ]]; then
echo "Usage: oref0-setup.sh <--dir=directory> <--serial=pump_serial_#> [--tty=/dev/ttySOMETHING] [--max_iob=0] [--ns-host=https://mynightscout.azurewebsites.net] [--api-secret=myplaintextsecret] [--cgm=(G4|shareble|G5|MDT)] [--bleserial=SM123456] [--blemac=FE:DC:BA:98:76:54] [--btmac=AB:CD:EF:01:23:45] [--enable='autosens meal'] [--radio_locale=WW]"
echo "Usage: oref0-setup.sh <--dir=directory> <--serial=pump_serial_#> [--tty=/dev/ttySOMETHING] [--max_iob=0] [--ns-host=https://mynightscout.azurewebsites.net] [--api-secret=myplaintextsecret] [--cgm=(G4|shareble|G5|MDT|xdrip)] [--bleserial=SM123456] [--blemac=FE:DC:BA:98:76:54] [--btmac=AB:CD:EF:01:23:45] [--enable='autosens meal dexusb'] [--radio_locale=(WW|US)]"
read -p "Start interactive setup? [Y]/n " -r
if [[ $REPLY =~ ^[Nn]$ ]]; then
exit
Expand Down Expand Up @@ -237,10 +237,12 @@ cd $directory || die "Can't cd $directory"
mkdir -p monitor || die "Can't mkdir monitor"
mkdir -p raw-cgm || die "Can't mkdir raw-cgm"
mkdir -p cgm || die "Can't mkdir cgm"
mkdir -p xdrip || die "Can't mkdir xdrip"
mkdir -p settings || die "Can't mkdir settings"
mkdir -p enact || die "Can't mkdir enact"
mkdir -p upload || die "Can't mkdir upload"
if [[ ${CGM,,} =~ "xdrip" ]]; then
mkdir -p xdrip || die "Can't mkdir xdrip"
fi

mkdir -p $HOME/src/
if [ -d "$HOME/src/oref0/" ]; then
Expand Down Expand Up @@ -440,9 +442,18 @@ if [[ -z "$ttyport" ]]; then
openaps alias add wait-for-long-silence 'report invoke monitor/temp_basal.json'
openaps alias add mmtune 'report invoke monitor/temp_basal.json'
else
# radio_locale requires openaps 0.1.6-dev or later
openaps device add pump mmeowlink subg_rfspy $ttyport $serial $radio_locale || die "Can't add pump"
openaps alias add wait-for-silence '! bash -c "(mmeowlink-any-pump-comms.py --port '$ttyport' --wait-for 1 | grep -q comms && echo -n Radio ok, || openaps mmtune) && echo -n \" Listening: \"; for i in $(seq 1 100); do echo -n .; mmeowlink-any-pump-comms.py --port '$ttyport' --wait-for 30 2>/dev/null | egrep -v subg | egrep No && break; done"'
openaps alias add wait-for-long-silence '! bash -c "echo -n \"Listening: \"; for i in $(seq 1 200); do echo -n .; mmeowlink-any-pump-comms.py --port '$ttyport' --wait-for 45 2>/dev/null | egrep -v subg | egrep No && break; done"'
if [[ ${radio_locale,,} =~ "WW" ]]; then
# add subg-ww-radio-parameters script to mmtune for WW pump. See https://github.com/oskarpearson/mmeowlink/issues/51 or https://github.com/oskarpearson/mmeowlink/wiki/Non-USA-pump-settings for details
sed -i"" 's/^\(mmtune.*\); \(echo -n .*mmtune:\)/\1; echo -n subg-ww-radio-parameters:; \/usr\/local\/bin\/oref0-subg-ww-radio-parameters-timeout; \2/g' openaps.ini

# Hack to check if radio_locale has been set in pump.ini. This is a temporary workaround for https://github.com/oskarpearson/mmeowlink/issues/55
# It will remove empty line at the end of pump.ini and then append radio_locale if it's not there yet
grep -q radio_locale pump.ini && echo "$(< pump.ini)" > pump.ini ; echo "radio_locale=$radio_locale" >> pump.ini
fi
fi

# Medtronic CGM
Expand Down Expand Up @@ -503,6 +514,13 @@ fi
echo Running: openaps report add enact/suggested.json text determine-basal shell monitor/iob.json monitor/temp_basal.json monitor/glucose.json settings/profile.json $EXTRAS
openaps report add enact/suggested.json text determine-basal shell monitor/iob.json monitor/temp_basal.json monitor/glucose.json settings/profile.json $EXTRAS

# Create ~/.profile so that openaps commands can be executed from the command line
# as long as we still use enivorement variables it's easy that the openaps commands work from both crontab and from a common shell
# TODO: remove API_SECRET and NIGHTSCOUT_HOST (see https://github.com/openaps/oref0/issues/299)
echo Add NIGHTSCOUT_HOST and API_SECRET to $HOME/.profile
(cat $HOME/.profile | grep -q "NIGHTSCOUT_HOST" || echo export NIGHTSCOUT_HOST="$NIGHTSCOUT_HOST") >> $HOME/.profile
(cat $HOME/.profile | grep -q "API_SECRET" || echo export API_SECRET="`nightscout hash-api-secret $API_SECRET`") >> $HOME/.profile

echo
if [[ "$ttyport" =~ "spi" ]]; then
echo Resetting spi_serial
Expand Down Expand Up @@ -530,7 +548,9 @@ if [[ ${CGM,,} =~ "shareble" ]]; then
elif [[ ${CGM,,} =~ "xdrip" ]]; then
(crontab -l; crontab -l | grep -q "cd $directory && ps aux | grep -v grep | grep -q 'openaps monitor-xdrip'" || echo "* * * * * cd $directory && ps aux | grep -v grep | grep -q 'openaps monitor-xdrip' || ( date; openaps monitor-xdrip) | tee -a /var/log/openaps/xdrip-loop.log; cp -up $directory/xdrip/glucose.json $directory/monitor/glucose.json") | crontab -
(crontab -l; crontab -l | grep -q "xDripAPS.py" || echo "@reboot python $HOME/.xDripAPS/xDripAPS.py") | crontab -
elif ! [[ ${CGM,,} =~ "mdt" ]]; then
elif [[ $ENABLE =~ dexusb ]]; then
(crontab -l; crontab -l | grep -q "@reboot /usr/bin/python" || echo "@reboot /usr/bin/python /usr/local/bin/oref0-dexusb-cgm-loop.py >> /var/log/openaps/cgm-dexusb-loop.log 2>&1" ) | crontab -
elif ! [[ ${CGM,,} =~ "mdt" ]]; then # use nightscout for cgm
(crontab -l; crontab -l | grep -q "cd $directory && ps aux | grep -v grep | grep -q 'openaps get-bg'" || echo "* * * * * cd $directory && ps aux | grep -v grep | grep -q 'openaps get-bg' || ( date; openaps get-bg ; cat cgm/glucose.json | json -a sgv dateString | head -1 ) | tee -a /var/log/openaps/cgm-loop.log") | crontab -
fi
(crontab -l; crontab -l | grep -q "cd $directory && ps aux | grep -v grep | grep -q 'openaps ns-loop'" || echo "* * * * * cd $directory && ps aux | grep -v grep | grep -q 'openaps ns-loop' || openaps ns-loop | tee -a /var/log/openaps/ns-loop.log") | crontab -
Expand Down
13 changes: 13 additions & 0 deletions bin/oref0-subg-ww-radio-parameters-timeout.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/bin/sh
# based on http://unix.stackexchange.com/questions/58304/is-there-a-way-to-call-a-command-with-a-set-time-limit-and-kill-it-when-that-tim

timeout_f () {
echo running $1 for max $2 seconds
$1 &
sleep $2
kill $! # ends somecommand if still running
}

timeout_f '/usr/local/bin/oref0-subg-ww-radio-parameters' 30 && #need 2 &'s
echo "forked.." # happens immediately

59 changes: 59 additions & 0 deletions bin/oref0-subg-ww-radio-parameters.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#!/bin/bash

# Set this to the serial port that your device is on: eg /dev/ttyACM0 or /dev/ttyMFD1
# use oref0-find-ti-usb-device.sh to autodetect the ACM device of the TI USB stick
SERIAL_PORT=`/usr/local/bin/oref0-find-ti`
#SERIAL_PORT="/dev/ttyS0"
echo Your TI-stick is located at $SERIAL_PORT

# Set this to the directory where you've run this. By default:
# cd ~
# git clone https://github.com/ps2/subg_rfspy.git
#
SUBG_RFSPY_DIR=$HOME/src/subg_rfspy

# If you're on an ERF, set this to 0:
# export RFSPY_RTSCTS=0

################################################################################
set -e
set -x

cd $SUBG_RFSPY_DIR/tools

#disabled killing openaps, because we want it to be able to use this with openaps mmtune
#echo -n "Killing running openaps processes... "
#killall -g openaps
#echo

# Reset to defaults
./reset.py $SERIAL_PORT

sleep 2

./change_setting.py $SERIAL_PORT 0x06 0x00 # CHANNR

sleep 0.5

./change_setting.py $SERIAL_PORT 0x0C 0x59 # MDMCFG4
sleep 0.5
./change_setting.py $SERIAL_PORT 0x0D 0x66 # MDMCFG3
sleep 0.5
./change_setting.py $SERIAL_PORT 0x0E 0x33 # MDMCFG2
sleep 0.5
./change_setting.py $SERIAL_PORT 0x0F 0x62 # MDMCFG1
sleep 0.5
./change_setting.py $SERIAL_PORT 0x10 0x1A # MDMCFG0
sleep 0.5

./change_setting.py $SERIAL_PORT 0x11 0x13 # DEVIATN
sleep 0.5

./change_setting.py $SERIAL_PORT 0x09 0x24 # FREQ2
sleep 0.5
./change_setting.py $SERIAL_PORT 0x0A 0x2E # FREQ1
sleep 0.5
./change_setting.py $SERIAL_PORT 0x0B 0x38 # FREQ0
sleep 0.5

exit 0
Loading

0 comments on commit 65da6ed

Please sign in to comment.