diff --git a/README.md b/README.md index 38ac4a90a..25558b010 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/bin/oref0-dexusb-cgm-loop.py b/bin/oref0-dexusb-cgm-loop.py new file mode 100644 index 000000000..25c345101 --- /dev/null +++ b/bin/oref0-dexusb-cgm-loop.py @@ -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="<>" +# export API_SECRET=<> +# 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)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) + + + diff --git a/bin/oref0-find-ti.sh b/bin/oref0-find-ti.sh new file mode 100644 index 000000000..04da1f4de --- /dev/null +++ b/bin/oref0-find-ti.sh @@ -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 diff --git a/bin/oref0-setup.sh b/bin/oref0-setup.sh index 7e8ca8071..3c58cc3a6 100755 --- a/bin/oref0-setup.sh +++ b/bin/oref0-setup.sh @@ -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 @@ -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 @@ -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 @@ -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 @@ -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 - diff --git a/bin/oref0-subg-ww-radio-parameters-timeout.sh b/bin/oref0-subg-ww-radio-parameters-timeout.sh new file mode 100644 index 000000000..b083b5fcb --- /dev/null +++ b/bin/oref0-subg-ww-radio-parameters-timeout.sh @@ -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 + diff --git a/bin/oref0-subg-ww-radio-parameters.sh b/bin/oref0-subg-ww-radio-parameters.sh new file mode 100644 index 000000000..c5b44633a --- /dev/null +++ b/bin/oref0-subg-ww-radio-parameters.sh @@ -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 diff --git a/package.json b/package.json index 73f270032..12d31f39c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "oref0", - "version": "0.3.3", + "version": "0.3.4-dev", "description": "openaps oref0 reference implementation of the reference design", "scripts": { "test": "make test", @@ -19,46 +19,49 @@ "url": "https://github.com/openaps/oref0/issues" }, "bin": { - "oref0-setup": "./bin/oref0-setup.sh", - "oref0-set-device-clocks": "./bin/oref0-set-device-clocks.sh", - "oref0-set-system-clock": "./bin/oref0-set-system-clock.sh", - "oref0-calculate-iob": "./bin/oref0-calculate-iob.js", - "oref0-find-insulin-uses": "./bin/oref0-find-insulin-uses.js", - "oref0-detect-sensitivity": "./bin/oref0-detect-sensitivity.js", - "oref0-determine-basal": "./bin/oref0-determine-basal.js", - "oref0-meal": "./bin/oref0-meal.js", - "oref0-normalize-temps": "./bin/oref0-normalize-temps.js", - "send-tempbasal-Azure": "./bin/send-tempbasal-Azure.js", - "oref0-fix-git-corruption": "bin/oref0-fix-git-corruption.sh", - "oref0-get-profile": "./bin/oref0-get-profile.js", - "oref0-mint-max-iob": "./bin/oref0-mint-max-iob.sh", - "oref0-ifttt-notify": "./bin/oref0-ifttt-notify", - "oref0-raw": "./bin/oref0-raw.js", - "oref0-reset-usb": "bin/oref0-reset-usb.sh", - "oref0-reset-git": "bin/oref0-reset-git.sh", - "oref0-truncate-git-history": "bin/oref0-truncate-git-history.sh", + "bt-pan": "./bin/bt-pan", "mm-format-ns-glucose": "./bin/mm-format-ns-glucose.sh", "mm-format-ns-profile": "./bin/mm-format-ns-profile.sh", - "mm-format-ns-treatments": "./bin/mm-format-ns-treatments.sh", "mm-format-ns-pump-history": "./bin/mm-format-ns-pump-history.sh", - "oref0": "./bin/oref0.sh", + "mm-format-ns-treatments": "./bin/mm-format-ns-treatments.sh", "mm-stick": "./bin/mm-stick.sh", - "ns-upload-entries": "./bin/ns-upload-entries.sh", - "ns-upload": "./bin/ns-upload.sh", - "ns-get": "./bin/ns-get.sh", - "ns-status": "./bin/ns-status.js", "nightscout": "./bin/nightscout.sh", "ns-dedupe-treatments": "./bin/ns-dedupe-treatments.sh", - "oref0-html": "./bin/oref0-html.js", - "oref0-template": "./bin/oref0-template.js", + "ns-get": "./bin/ns-get.sh", + "ns-status": "./bin/ns-status.js", + "ns-upload": "./bin/ns-upload.sh", + "ns-upload-entries": "./bin/ns-upload-entries.sh", + "oref0": "./bin/oref0.sh", + "oref0-calculate-iob": "./bin/oref0-calculate-iob.js", "oref0-copy-fresher": "./bin/oref0-copy-fresher", - "oref0-pebble": "./bin/oref0-pebble.js", "oref0-crun": "./bin/oref0-conditional-run.sh", + "oref0-detect-sensitivity": "./bin/oref0-detect-sensitivity.js", + "oref0-determine-basal": "./bin/oref0-determine-basal.js", "oref0-dex-is-fresh": "./bin/oref0-dex-is-fresh.sh", "oref0-dex-time-since": "./bin/oref0-dex-time-since.sh", "oref0-dex-wait-until-expected": "./bin/oref0-dex-wait-until-expected.sh", + "oref0-find-insulin-uses": "./bin/oref0-find-insulin-uses.js", + "oref0-find-ti": "./bin/oref0-find-ti.sh", + "oref0-fix-git-corruption": "bin/oref0-fix-git-corruption.sh", + "oref0-get-profile": "./bin/oref0-get-profile.js", + "oref0-html": "./bin/oref0-html.js", + "oref0-ifttt-notify": "./bin/oref0-ifttt-notify", + "oref0-meal": "./bin/oref0-meal.js", + "oref0-mint-max-iob": "./bin/oref0-mint-max-iob.sh", + "oref0-normalize-temps": "./bin/oref0-normalize-temps.js", "oref0-online": "./bin/oref0-online.sh", - "bt-pan": "./bin/bt-pan" + "oref0-pebble": "./bin/oref0-pebble.js", + "oref0-raw": "./bin/oref0-raw.js", + "oref0-reset-git": "bin/oref0-reset-git.sh", + "oref0-reset-usb": "bin/oref0-reset-usb.sh", + "oref0-set-device-clocks": "./bin/oref0-set-device-clocks.sh", + "oref0-set-system-clock": "./bin/oref0-set-system-clock.sh", + "oref0-setup": "./bin/oref0-setup.sh", + "oref0-subg-ww-radio-parameters": "./bin/oref0-subg-ww-radio-parameters.sh", + "oref0-subg-ww-radio-parameters-timeout": "./bin/oref0-subg-ww-radio-parameters-timeout.sh", + "oref0-template": "./bin/oref0-template.js", + "oref0-truncate-git-history": "bin/oref0-truncate-git-history.sh", + "send-tempbasal-Azure": "./bin/send-tempbasal-Azure.js" }, "homepage": "https://github.com/openaps/oref0", "dependencies": {