Merge pull request #31 from jotomo/combo-scripter-v2

16 feb
This commit is contained in:
Simon Pauwels 2018-02-16 10:06:41 +01:00 committed by GitHub
commit 4629b54a96
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 109 additions and 427 deletions

View file

@ -1,153 +0,0 @@
**This software is part of a DIY solution and is not a product, but
requires YOU to read, learn and understand the system and how to use it.
It is not something that does all your diabetes management for you, but
allows you to improve your diabetes and quality of life significantly
if you're willing to put in the time required. Don't rush into it,
but allow yourself time to learn. You alone are responsible for what
you do with it.**
Hardware requirements
---------------------
- A Roche Accu-Chek Combo (any firmware, they all work)
- A Smartpix or Realtyme device together with the 360 Configuration
Software to configure the pump.
Roche sends out Smartpix devices and the configuration software
free of charge to their customers upon request.
- A compatible phone: An Android phone with a phone running LineageOS 14.1 (formerly CyanogenMod) or Android 8.1 (Oreo).
Be aware that while Android 8.1 allows communicating with the Combo, there are still issues with AAPS on 8.1.
For advanced users, it is possible to perform the pairing on a rooted phone and transfer it to another rooted
phone to use with ruffy/AAPS, which must also be rooted. This allows using phones with Android < 8.1 but
has not been widely tested: https://github.com/gregorybel/combo-pairing/blob/master/README.md
- To build AndroidAPS with Combo support you need the latest Android Studio 3 version
Limitations
-----------
- Extended bolus and multiwave bolus are not supported.
- Only one basal profile is supported.
- Setting a basal profile other than 1 on the pump, or delivering extended boluses or multiwave
boluses from the pump interferes with TBRs and forces the loop into low-suspend only mode for 6 hours
as the the loop can't run safely under those conditions.
- It's currently not possible to set the time and date on the pump, so daylight saving times
changes have to be performed manually (disable automatic phone clock update in the evening and
update change back in the morning while also updating the pump's clock to avoid an alarm during the night).
- Currently only basal rates in the range of 0.05 to 10 U/h are supported (this also applies when modifying
a profile, e.g. when increasing to 200%, the highest basal rate must not exceed 5 U/h since it will be
doubled. Similarly, when reducing to 50%, the lowest basal rate must be at least 0.10 U/h).
- If the loop requests a running TBR to be cancelled the Combo will set a TBR of 90% or 110%
for 15 minutes instead. This is because cancelling a TBR causes an alert on the pump which
causes a lot of vibrations.
- Occasionally (every couple of days or so) AAPS might fail to automatically cancel
a TBR CANCELLED alert the user then needs to deal with (press the refresh button in AAPS
to transfer the warning to AAPS or confirm the alert on the pump).
Setup
-----
- Configure pump using 360 config software.
- Required:
- Set/leave the menu configuration as "Standard", this will show only the supported
menus/actions on the pump and hide those which are unsupported (extended/multiwave bolus,
multiple basal rates), which cause the loop functionality to be restricted when used because
it's not possible to run the loop in a safe manner when used.
- Verify the _Quick Info Text_ is set to "QUICK INFO" (without the quotes, found under _Insulin Pump Options_).
- Set maximum TBR to 500%
- Disable end of TBR alert
- Set TBR duration step-size to 15 min
- Recommended:
- Set low cartridge alarm to your liking
- Configure a max bolus suited for your therapy to protect against bugs in the software
- Similarly, configure maximum TBR duration as a safeguard. Allow at least 3 hours, since
the option to disconnect the pump for 3 hours sets a 0% for 3 hours.
- Enable key lock on the pump to prevent bolusing from the pump, esp. when the
pump was used before and quick bolusing was a habit.
- Set display timeout and menu timeout to the mininum of 5.5 and 5 respectively. This allows the AAPS to
recover more quickly from error situations and reduces the amount of vibrations that can occur during
such errors
- Install AndroidAPS as described in the wiki http://wiki.AndroidAPS.org
- Make sure to read the wiki to understand how to setup AndroidAPS.
- Select the MDI plugin in AndroidAPS, not the Combo plugin at this point to avoid the Combo
plugin from interfering with ruffy during the pairing process.
- Follow the link http://ruffy.AndroidAPS.org and clone ruffy via git. Use the same branch as you use for
AndroidAPS, which is usally `master`.
if you you want to help test the in-development version.
- Pair the pump using ruffy. If it doesn't work after multiple attempts, switch to the `pairing` branch,
pair the pump and then switch back the original branch.
If the pump is already paired and can be controlled via ruffy, installing the `master` branch is sufficient.
Note that the pairing processing is somewhat fragile (but only has to be done once)
and may need a few attempts; quickly acknowledge prompts and when starting over, remove the pump device
from the bluetooth settings beforehand. Another option to try is to go to the bluetooth menu after
initiating the pairing process (this keeps the phone's bluetooth discoverable as long as the menu is displayed)
and switch back to ruffy after confirming the pairing on the pump, when the pump displays the authorization code.
When AAPS is using ruffy, the ruffy app can't be used. The easiest way is to just
reboot the phone after the pairing process and let AAPS start ruffy in the background.
- Before enabling the Combo plugin in AAPS make sure your profile is set up
correctly and your basal profile is up to date as AAPS will sync the basal profile
to the pump. Then activate the Combo plugin.
Usage
-----
- Keep in mind that this is not a product, esp. in the beginning the user needs to monitor and understand the system,
its limitations and how it can fail. It is strongly advised NOT to use this system when the person
using it is not able to fully understand the system.
- Read the OpenAPS documentation https://openaps.org to understand the loop algorithm AndroidAPS
is based upon.
- Read in the wiki to learn about and understand AndroidAPS http://wiki.AndroidAPS.org
- This integration uses the same functionality which the meter provides that comes with the Combo.
The meter allows to mirror the pump screen and forwards button presses to the pump. The connection
to the pump and this forwarding is what the ruffy app does. A `scripter` components reads the screen
and automates inputing boluses, TBRs etc and making sure inputs are processed correctly.
AAPS then interacts with the scripter to apply loop commands and to administer boluses.
This mode has some restrictions: it's comparatively slow (but well fast enough for what it is used for),
and setting a TBR or giving a bolus causes the pump to vibrate.
- The integration of the Combo with AndroidAPS is designed with the assumption that all inputs are
made via AndroidAPS. Boluses entered on the pump directly will be detected by AAPS, but it can take
up to 25 min before AndroidAPS becomes aware of such a bolus. Reading boluses delivered directly on
the pump is a safety feature and not meant to be regularly used (the loop requires knowledge of carbs
consumed, which can't be entered on the pump, which is another reason why all inputs should be done
in AndroidAPS).
- The pump's first basal rate profile is read on application start and is updated by AAPS.
The basal rate should not be manually changed on the pump, but will be detected and corrected as a safety
measure (don't rely on safety measures by default, this is meant to detect an unintended change on the pump).
- It's recommended to enable key lock on the pump to prevent bolusing from the pump, esp. when the
pump was used before and quick bolusing was a habit.
Also, with keylock enabled, accidentally pressing a key will NOT interrupt active communication
between AAPS and pmup.
- When a BOLUS/TBR CANCELLED alert starts on the pump during bolusing or setting a TBR, this is
caused by a disconnect between pump and phone. AAPS will try to reconnect and confirm the alert
and then retry the last action (boluses are NOT retried for safety reasons). Therefore,
such an alarm shall be ignored (cancelling it is not a big issue, but will lead to the currently
active action to have to wait till the pump's display turns off before it can reconnect to the
pump). If the pump's alarm continues, the last action might have failed, in which case the user
needs to confirm the alarm.
- When a low cartridge or low battery alarm is raised during a bolus, they are confirmed and shown
as a notification in AAPS. If they occur while no connection is open to the pump, going to the
Combo tab and hitting the Refresh button will take over those alerts by confirming them and
showing a notification in AAPS.
- When AAPS fails to confirm a TBR CANCELLED alert, or one is raised for a different reason,
hitting Refresh in the Combo tab establishes a connection, confirms the alert and shows
a notification for it in AAPS. This can safely be done, since those alerts are benign - an
appropriate TBR will be set again during the next loop iteration.
- For all other alerts raised by the pump: connecting to the pump will show the alert message in
the Combo tab, e.g. "State: E4: Occlusion" as well as showing a notification on the main screen.
An error will raise an urgent notification. AAPS never confirms serious errors on the pump,
but let's the pump vibrate and ring to make sure the user is informed of a critical situation
that needs action.
- After pairing, ruffy should not be used directly (AAPS will start in the background as needed),
since using ruffy at AAPS at the same time is not supported.
- If AAPS crashes (or is stopped from the debugger) while AAPS and the pump were communicating (using
ruffy), it might be necessary to force close ruffy. Restarting AAPS will start ruffy again.
Restarting the phone is also an easy way to resolve this or you don't know how to force kill
an app.
- Don't press any buttons on the pump while AAPS communicates with the pump (Bluetooth logo is
shown on the pump).
Reporting bugs
--------------
- See https://github.com/MilosKozak/AndroidAPS/blob/master/ISSUE_TEMPLATE.md
- Note the precise time the problem occurred and describe the circumstances and steps that caused
the problem
- Note the Build version (found in the About dialog in the app, when pressing the three dots in the
upper-right corner).
- Obtain the app's log files, which can be found on the phone in
_/storage/emulated/0/Android/data/info.nightscout.androidaps/_
- Open an issue at https://github.com/MilosKozak/AndroidAPS/issues/new

View file

@ -1,142 +0,0 @@
- [x] Bugs
- [-] Pump stops to response to connect attemps every 2-20h or so, only reacting
again when physically pressing a button on the pump ...
Occassionally the pump starts to accept connections again, sometimes
after 40m, sometimes no luck even after 80m
Stuff tried without success:
- Restarting BT
- Restarting ruffy
- Restarting AAPS
- Restarting phone
- Removing rtDisconnect on failed connect attempt (RuffyScripter.ensureConnected)
- Ruffy v1 branch with minimal NPE fixes and needed menus
Observations:
- Last command run beforehand was a short one, connection time < 1m
- It's unrelated to battery voltage.
- Auto off is disabled
- Keylock makes no difference
Speculations:
Did this already happen before the whole 'basal profile' thing?
Takes ages, could that trigger some weird bug that has never
surfaced in any other scenario before?
- [-] Temp basal history shows TBRs twice, once with a 1 min
duration and then with the reminder; caused by clock not
being within ~30s of the phone.
Cancelling TBR or overriding a running one with a new one
(both cases require a TBR end record) require an end TBR record.
checkTbrMismatch causes history read and TBR is right in AAPS
so far and any TBR set on the pump is cancelled, so it works,
but isn't clean. Needs some rethink - with a fresh mind -
maybe understanding what DanaR does, how to translate it to
the Combo.
Explicit end records when adding pump history records;
and/or: logic to detect time differences and align data
Current solution works, albeit a bit ugly, but is used in rare
circumstances where clock might be off anyway, so this would
still occur.
- [x] Deleting a bolus from the history re-adds it from the pump's
history. Deleting it again, flags it as invalid at which point
it will not be added to IOB and not be re-added.
- [x] Taking over benign warnings on connect doesn't work properly
(Notification raised but not confirmed?)
- [x] Optimization reading full history doesn't seem to work
- [x] Reading full history multiple times duplicates entries shown in Stats/TDD dialog
- [x] ruffy: Accessing the quick info menu yields noMenu when cartridge is low
- [x] ruffy: Multi-digit error codes in error history aren't supported
- [-] No connection can be established anymore; ruffy issue i can't solve
- Removing the BT device's bonding (!=pairing) fixes it; nope it doesn't
- Ruffy logs in BTConnection:163 handler.fail("no connection possible: " + e.getMessage());
- When developing (and thus killing/restarting AAPS often) this is trigger more frequently, leaving
some ruffy-releated (BT) cache in disarray? Immune to wiping, only repairing seems to work so far
- [x] Timeout connecting to pump -> crash (result.state wasn't filled in case of timeout)
- [x] Bolus deleted in treatments (marked invalid?!) is re-added when pump reads history
Probably fixed through other bugfixes, irrelevant though as "pump history records" can't
be deleted in AAPS
- [x] Issue of creating TBR start date from main menu time, which might be off by a minute
when we read it as a history record. End date time might be slightly off, unless
CancelTempBasal is updated to read from history (probably not worth it).
What would happen if while setting the TBR the start time was 12:01 but then
we read a history record with a start time of 12:02, both running 30min.
Would the former be trimmed to 1m? That'd be acceptable (this edge case occurs
if between confirm the TBR and reading the main menu date, the second goes
from 59.9999 to 0)
Only in issue if TBR was set on pump. In that case the TBR is cancelled and the
resulting history record is read
- [x] Tasks
- [x] Main
- [x] On command error: recover by returning to main menu
check entry and exit points of commands
- [x] Taking over alerts
- [x] On connect
- [x] During bolusing
- Can the low warning be set as high as 280 or so? To be able to trigger it with a quick refill? yup.
- [x] Check for errors first thing in runCommand? Whenever analysing a CommandResult?
- [x] forward all warnings and errors encountered, but only confirm benign ones
- [-] Reporting back failures in UI, maybe warn if lots of errors (unreachable alert might
already be enough, since it's based on 'lastSuccessfulConnection', where a connection is
considered successful if the command during that connection succeeded.
KeepAlive triggered check suffices.
- [x] Finish ComboPlugin structure to only have to plug date setting and pump setting in later
(actually, just use stub methods)
- [-] Updating time on pump
- [x] Raise a warning if time clock is off
- [-] Ruffy: support reading date/time menus
- [x] Setting pump basal profile
- [x] Overview notification on updated/failed basal profile
- [-] Pairing (and sourcing ruffy)
- [x] Run readReservoirAndBolusLevel after SetTbr too so boluses on the pump are caught sooner?
Currently the pump gets to know such a record when bolusing or when refresh() is called
after 15m of no other command taking place. IOB will then be current with next loop
checkPumpHistory is now called every 15m the least after executing a command
- [x] Reading history
- [x] Bolus
- [x] Read
- [x] Update DB
- [x] TBRs
- [x] Read
- [x] Update DB
- [x] Alerts
- [x] Read
- [x] Update DB? No, but raise an alert if new ones are found beyond those read at startup
(Those that occurred while AAPS was not active needn't be turned into alarms,
the user had to deal with them on the pump already). (Done via "Taking over alerts")
- [x] Display in UI
- [x] TDD
- [x] Read
- [x] Update DB? No, just write to plugin cache
- [x] Display in UI
- [x] Optimize reading full history to pass timestamps of last known records to avoid reading known records
iteration.
- [x] Cleanups
- [x] TBR cancel logic
- [x] Check dynamic timeout logic in RuffyScripter.runCommand
- [x] Finish 'enacted' removal rewrite (esp. cancel tbr)
- [x] ComboPlugin, commands invocation, checks, upadting combo store/cache
- [x] Finish reconnect
- [x] Adrian says: when changing time; last treatments timestamp is updated??
- Nope, at least not with a 2014 pump (SW1.06?)
- [x] Reconnect and auto-retry for commands
- [x] Empty battery state
- [x] Integrate alarms
- [x] Remove combo alerter thread
- [x] Display errors in combo tab(?), nope notifications are better suited; also there's the alerts thing already
- [x] Option to raise overview notifications as android notification with noise (for urgent ones?)
- [ ] Next version(s)
- [ ] State in ComboPump is not safely shared among threads
- [x] Naming is messed up: pump has warnings and errors, which cause alerts; W+E are thus alerts,
e.g. pumpAlertHistory should be renamed to alertHistory
- [x] Enable BT if disabled? does DanaR does this? BT watchdog in CommandQueue takes care of it
- [-] Finish and test German translation
- [x] No clean startup/shutdown; RuffyScripter is instanciated once, idle disconnect thread never killed
- Application shut down is broken with PersistentNotification (never shut down) and WearPlugin -
Android logs it as crashed and restarts it, thereby restarting the app (or just keeping it alive,
also causes errors with the DB as there were attemtps to open a closed DB instance/ref.
Does xDrip intents start AAPS? Starts automatically (but not instantly) after boot and there's no "start on boot" setting enabled
CommandQueue now issues disconnect and the idle-disconnect-monitor has been removed.
- [ ] Check if TBRs are set to often from ConfigBuilder on high base basal rates (basalstep is 0.01; in reality larger on >1U/h base basal)
- [ ] With long running commands (e.g. setting basal rate, which can take up to 5m), multiple 'set tbr' commands
may stack up. Since setting a TBR multiple times in one minute fails, the ComboPlugin rejects such
request, letting the oldest TBR run till the net iteration. This can potentially be nicely solved
through the queue branch. However, the original problem is the amount of time the Combo can
take to execute commands, which might go away (mostly) with command mode.
- [ ] Fix display of alarms on mainscreen (increase height if needed)

View file

@ -1,111 +0,0 @@
- [ ] Pairing
- [ ] Pairing works with `combo-scripter-v2` branch
- [ ] Bolusing
- [ ] Cancelling bolus at various stages shall not yield an error but cancel the bolus. If
cancelled before delivery started, no treatment must have been added, if cancel after delivery
started, the partially delivered bolus must have been added to treatments
- [ ] Enter a bolus of 2 U and press cancel when delivery is at 1.7 (cancelling requires AAAPS
to press the up button for 3 seconds, so the cancellation attempt will not succeed because delivery
ends before those 3 seconds are elapsed). The code should handle this without giving an
error and add the full bolus to treatments.
- [ ] Recovery from connection issues during bolusing
- [ ] Pressing a button on the pump during delivery => Progress dialog freezes, then states that recovery
is in process and then closes; no error dialog, record correctly added to treatments
- [ ] Breaking the connection e.g. by moving the pump away from phone for up to a minute => same as above
- [ ] Same as above but put pump out of reach for 5 minutes => Error dialog, no record in treatments
- [ ] Starting a bolus bigger than what's left in the reservoir => Error dialog and a record in treatments with the partially delivered bolus
- [ ] When the connection breaks during bolusing, pressing the cancel button should not interfere with recovery and
the delivered bolus should be added to treatments
- [ ] Low cartridge alarm during bolus
- [ ] alarm must be confirmed by AAPS
- [ ] bolus must have been fully delivered by pump
- [ ] bolus must have been added to DB
- [ ] the confirmed pump warning must be raised as a notification in AAPS
(or as android notification on watch/smartphone if setting "use system notifications ..." is enabled
- [ ] Pressing a button on the pump, or moving the pump away from the phone to break connection
must confirm the pump alert and recover to finish the bolusing.
- [ ] If recovery fails, an error popup must be displayed
- [ ] Test bolusing a bolus bigger than what's left in the reservoir. A message to check what
was actually delivered must appear (this is a corner-case where we practically can't
check what was actually delivered).
- [ ] Pressing a button on the pump before bolus delivery started must be handled gracefully
- [ ] Same as above, but moving pump out of range
- [ ] Pressing a button on the pump after bolus delivery has started will freeze the progress bar,
initiate recovery and add the delivered bolus the treatments.
- [ ] Same as above, but moving pump out of range
- [ ] Test the highest bolus you'd ever give yourself (AAPS has a configurable limit and the pump
has a limit which can be configured with the Config SW), no timeout or other issues must show
- [ ] BT disconnect issues
- [ ] Moving pump out of reach when setting TBR causes "TBR cancelled" alarm on pump.
When putting pump close to phone, AAPS must confirm the alert and successfully
retry setting TBR (reconnects are a best-effort kind of a thing, so this might not always work)
- [ ] When a disconnect occurs, the pump's screen shows the error and the pump only accepts a connection
again when the pump's menu(?) timeout has occurred. A recovery should be quicker if that timeout is decreased.
It might be interesting to experiment with the Config software to set lower menu or display timeouts
(or whatever they're called ...) to improve recovery speed.
- [ ] AAPS start
- [ ] Starting AAPS without a reachable pump must show something sensible in the Combo tab
(not hanging indefinitely with "initializing" activity)
- [ ] Starting AAPS without a reachable pump must trigger "pump unrechable" alert after the configured threshold
- [ ] If the pump's basal profile doesn't match AAPS', the pump must be updated when AAPS starts
- [ ] Read history using Smartpix and compare with AAPS' DB (treatment tab)
Esp. those times we communication was interrupted, boluses were cancelled, ...
- [ ] Boluses
- [ ] TBR
- [ ] Alerts
- [ ] Disconnected pump (pump unreachable)
- [ ] With local alerts enabled for 'pump unreachable', an alert must be triggered within 5 minutes
after the configured threshold. (Don't set the threshold too low, e.g. 10 minutes, since
there might be no need to set a TBR within such a short time, but since there was no pump connection
within that time, the alarm would be triggered).
- [ ] Refilling cartridge
- [ ] If TBR was cancelled by refilling, AAPS must detect this and create a TBR record in AAPS
based on what the pump displays (not the full TBR duration, but what is displayed as remaining
on the main screen.
- [ ] Stress testing
- PersistentNotification plugin disabled
- Lots of comms running, like Wifi, GSM, BT audio
- AAPS running in background
- Foreground app stresses the phone's memory, CPU (like a game) (potentially) pushing AAPS out of memory
- [ ] TBR must still be set/cancelled while running in the background
- [ ] With the pump powered off or out of reach, the 'pump unreachable alert' must still
trigger
- [ ] Combo tab
- [ ] Check displayed data (state, battery, reservoir, temp basal) is the same
as on the pump
- [ ] Unsafe usage
- [ ] An active extended or multiwave bolus must raise an alert and
restrict the loop functionality to low-suspend only for the next 6h (setting maxIOB to zero)
and cancel an active TBR.
- [ ] Closed loop functionality must resume 6 h after the last ext/multiwave bolus
- [ ] If a basal rate other than profile 1 is active on start, the pump must refuse to finish
initialization and disable the loop. When setting the profile to 1 and refreshing,
the pump must finish initialization and enable the loop (the overview screen will
still show "closed loop", but the Combo and Loop tabs will say the loop is disabled
due to a constraint violation).
- [ ] When changing profile to one other than the first after AAPS has started and read the first
basal profile, a warning must be shown, the loop must be disabled and the active TBR be cancelled.
- [ ] A request to change the AAPS profil (e.g. increase to 110%) must be rejected if the pump
doesn't have profile one active.
- [ ] Reading/setting basal profile
- [ ] AAPS reads basal rate properly
- [ ] Test profile with 115% (or something like that) change to ask the
pump for basal rates like 0.812, which should then be set propely
- [ ] Updating the profile extensively (200%, shifting time) takes up to 6 minutes, but
should complete without timeout.
- [ ] Doing a profile change (to shift time or increase/decrease insulin), the pump's basal profile must be updated
- [ ] If a profile change has a duration, the pump's basal profile must be set to the original value again at the end
(this can vary a few minutes between what the overview screen shows and when the pump is updated, as the check
whether the pump is up-to-date or not is performed periodically and not at the exact minute a profile change ends)
- [ ] Taking over alerts
- [ ] If an error alert is active on the pump, pressing refresh shall display the error
in the Combo tab but NOT confirm it. Easiest error to trigger: rewind piston
and attempt to start the pump, this will trigger E11: Not primed.
- [ ] Pressing refresh while a low cartridge or low battery alarm is active
must confirm the alarm, indicate the new status in the Combo tab and
show a notification on the overview screen
- [ ] A TBR CANCELLED is now also taken over when refreshing (since it's a benign error the loop will correct
during the next iteration).
- [ ] Misc
- [ ] Pump state is correctly uploaded to Nightscout (note that reservoir level are fake numbers representing
norma/low/empty).

View file

@ -57,7 +57,7 @@ android {
targetSdkVersion 23 targetSdkVersion 23
multiDexEnabled true multiDexEnabled true
versionCode 1500 versionCode 1500
version "1.57-combo-csv2-beta-3" version "1.57-combo-csv2-beta-4"
buildConfigField "String", "VERSION", '"' + version + '"' buildConfigField "String", "VERSION", '"' + version + '"'
buildConfigField "String", "BUILDVERSION", generateGitBuild() buildConfigField "String", "BUILDVERSION", generateGitBuild()

View file

@ -43,4 +43,6 @@ public class Config {
public static final boolean logDanaBTComm = true; public static final boolean logDanaBTComm = true;
public static boolean logDanaMessageDetail = true; public static boolean logDanaMessageDetail = true;
public static final boolean logDanaSerialEngine = true; public static final boolean logDanaSerialEngine = true;
public static final boolean enableComboBetaFeatures = false;
} }

View file

@ -19,6 +19,9 @@ import android.support.v4.view.ViewPager;
import android.support.v7.app.AlertDialog; import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.PopupMenu; import android.support.v7.widget.PopupMenu;
import android.text.SpannableString;
import android.text.method.LinkMovementMethod;
import android.text.util.Linkify;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.MotionEvent; import android.view.MotionEvent;
@ -27,6 +30,7 @@ import android.view.WindowManager;
import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.InputMethodManager;
import android.widget.EditText; import android.widget.EditText;
import android.widget.ImageButton; import android.widget.ImageButton;
import android.widget.TextView;
import com.joanzapata.iconify.Iconify; import com.joanzapata.iconify.Iconify;
import com.joanzapata.iconify.fonts.FontAwesomeModule; import com.joanzapata.iconify.fonts.FontAwesomeModule;
@ -392,10 +396,14 @@ public class MainActivity extends AppCompatActivity implements View.OnClickListe
builder.setIcon(R.mipmap.blueowl); builder.setIcon(R.mipmap.blueowl);
String message = "Build: " + BuildConfig.BUILDVERSION + "\n"; String message = "Build: " + BuildConfig.BUILDVERSION + "\n";
message += MainApp.sResources.getString(R.string.configbuilder_nightscoutversion_label) + " " + ConfigBuilderPlugin.nightscoutVersionName; message += MainApp.sResources.getString(R.string.configbuilder_nightscoutversion_label) + " " + ConfigBuilderPlugin.nightscoutVersionName;
builder.setMessage(message); message += getString(R.string.about_link_urls);
final SpannableString messageSpanned = new SpannableString(message);
Linkify.addLinks(messageSpanned, Linkify.WEB_URLS);
builder.setMessage(messageSpanned);
builder.setPositiveButton(MainApp.sResources.getString(R.string.ok), null); builder.setPositiveButton(MainApp.sResources.getString(R.string.ok), null);
AlertDialog alertDialog = builder.create(); AlertDialog alertDialog = builder.create();
alertDialog.show(); alertDialog.show();
((TextView)alertDialog.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance());
break; break;
case R.id.nav_exit: case R.id.nav_exit:
log.debug("Exiting"); log.debug("Exiting");

View file

@ -600,7 +600,8 @@ public class DataService extends IntentService {
if (trJson.has("eventType") && trJson.getString("eventType").equals(CareportalEvent.ANNOUNCEMENT)) { if (trJson.has("eventType") && trJson.getString("eventType").equals(CareportalEvent.ANNOUNCEMENT)) {
long date = trJson.getLong("mills"); long date = trJson.getLong("mills");
long now = System.currentTimeMillis(); long now = System.currentTimeMillis();
if (date > now - 15 * 60 * 1000L && trJson.has("notes")) { if (date > now - 15 * 60 * 1000L && trJson.has("notes")
&& !(trJson.has("enteredBy") && trJson.getString("enteredBy").equals(SP.getString("careportal_enteredby", "AndroidAPS")))) {
Notification announcement = new Notification(Notification.NSANNOUNCEMENT, trJson.getString("notes"), Notification.ANNOUNCEMENT, 60); Notification announcement = new Notification(Notification.NSANNOUNCEMENT, trJson.getString("notes"), Notification.ANNOUNCEMENT, 60);
MainApp.bus().post(new EventNewNotification(announcement)); MainApp.bus().post(new EventNewNotification(announcement));
} }

View file

@ -5,6 +5,7 @@ import android.graphics.Color;
import com.j256.ormlite.field.DatabaseField; import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable; import com.j256.ormlite.table.DatabaseTable;
import org.apache.commons.lang3.StringUtils;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -184,7 +185,7 @@ public class CareportalEvent implements DataPointWithLabelInterface {
try { try {
JSONObject object = new JSONObject(json); JSONObject object = new JSONObject(json);
if (object.has("notes")) if (object.has("notes"))
return object.getString("notes"); return StringUtils.abbreviate(object.getString("notes"), 40);
} catch (JSONException e) { } catch (JSONException e) {
log.error("Unhandled exception", e); log.error("Unhandled exception", e);
} }

View file

@ -3,6 +3,10 @@ package info.nightscout.androidaps.plugins.Overview.Dialogs;
import android.os.Bundle; import android.os.Bundle;
import android.support.v7.app.AppCompatActivity; import android.support.v7.app.AppCompatActivity;
import info.nightscout.androidaps.R;
import info.nightscout.utils.NSUpload;
import info.nightscout.utils.SP;
public class ErrorHelperActivity extends AppCompatActivity { public class ErrorHelperActivity extends AppCompatActivity {
public ErrorHelperActivity() { public ErrorHelperActivity() {
super(); super();
@ -17,5 +21,9 @@ public class ErrorHelperActivity extends AppCompatActivity {
errorDialog.setSound(getIntent().getIntExtra("soundid", 0)); errorDialog.setSound(getIntent().getIntExtra("soundid", 0));
errorDialog.setTitle(getIntent().getStringExtra("title")); errorDialog.setTitle(getIntent().getStringExtra("title"));
errorDialog.show(this.getSupportFragmentManager(), "Error"); errorDialog.show(this.getSupportFragmentManager(), "Error");
if (SP.getBoolean(R.string.key_ns_create_announcements_from_errors, true)) {
NSUpload.uploadError(getIntent().getStringExtra("status"));
}
} }
} }

View file

@ -16,6 +16,7 @@ import com.squareup.otto.Subscribe;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import info.nightscout.androidaps.Config;
import info.nightscout.androidaps.plugins.PumpCombo.ruffyscripter.PumpState; import info.nightscout.androidaps.plugins.PumpCombo.ruffyscripter.PumpState;
import info.nightscout.androidaps.plugins.PumpCombo.ruffyscripter.history.Bolus; import info.nightscout.androidaps.plugins.PumpCombo.ruffyscripter.history.Bolus;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
@ -205,8 +206,10 @@ public class ComboFragment extends SubscriberFragment implements View.OnClickLis
if (plugin.isInitialized()) { if (plugin.isInitialized()) {
refreshButton.setVisibility(View.VISIBLE); refreshButton.setVisibility(View.VISIBLE);
if (Config.enableComboBetaFeatures) {
alertsButton.setVisibility(View.VISIBLE); alertsButton.setVisibility(View.VISIBLE);
tddsButton.setVisibility(View.VISIBLE); tddsButton.setVisibility(View.VISIBLE);
}
fullHistoryButton.setVisibility(View.VISIBLE); fullHistoryButton.setVisibility(View.VISIBLE);
// battery // battery

View file

@ -50,6 +50,7 @@ import info.nightscout.androidaps.plugins.PumpCombo.ruffyscripter.history.Bolus;
import info.nightscout.androidaps.plugins.PumpCombo.ruffyscripter.history.PumpHistory; import info.nightscout.androidaps.plugins.PumpCombo.ruffyscripter.history.PumpHistory;
import info.nightscout.androidaps.plugins.PumpCombo.ruffyscripter.history.PumpHistoryRequest; import info.nightscout.androidaps.plugins.PumpCombo.ruffyscripter.history.PumpHistoryRequest;
import info.nightscout.androidaps.queue.Callback; import info.nightscout.androidaps.queue.Callback;
import info.nightscout.androidaps.queue.CommandQueue;
import info.nightscout.utils.DateUtil; import info.nightscout.utils.DateUtil;
/** /**
@ -130,7 +131,7 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf
/** Cache of the last <=2 boluses on the pump. Used to detect changes in pump history, /** Cache of the last <=2 boluses on the pump. Used to detect changes in pump history,
* requiring reading pump more history. This is read/set in {@link #checkHistory()} when changed * requiring reading pump more history. This is read/set in {@link #checkHistory()} when changed
* pump history was detected and was read, as well as in {@link #deliverBolus(DetailedBolusInfo)} * pump history was detected and was read, as well as in {@link #deliverBolus(DetailedBolusInfo)}
* after bolus delivery. */ * after bolus delivery. Newest record is the first one. */
private volatile List<Bolus> recentBoluses = new ArrayList<>(0); private volatile List<Bolus> recentBoluses = new ArrayList<>(0);
public static ComboPlugin getPlugin() { public static ComboPlugin getPlugin() {
@ -424,6 +425,12 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf
pump.initialized = true; pump.initialized = true;
MainApp.bus().post(new EventInitializationChanged()); MainApp.bus().post(new EventInitializationChanged());
// show notification to check pump date if last bolus is older than 24 hours
if (!recentBoluses.isEmpty() && recentBoluses.get(0).timestamp < System.currentTimeMillis() - 24 * 60 * 60 * 1000) {
Notification notification = new Notification(Notification.COMBO_PUMP_ALARM, MainApp.gs(R.string.combo_check_date), Notification.URGENT);
MainApp.bus().post(new EventNewNotification(notification));
}
// ComboFragment updates state fully only after the pump has initialized, // ComboFragment updates state fully only after the pump has initialized,
// so force an update after initialization completed // so force an update after initialization completed
MainApp.bus().post(new EventComboPumpUpdateGUI()); MainApp.bus().post(new EventComboPumpUpdateGUI());
@ -1062,6 +1069,10 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf
TemporaryBasal aapsTbr = MainApp.getConfigBuilder().getTempBasalFromHistory(now); TemporaryBasal aapsTbr = MainApp.getConfigBuilder().getTempBasalFromHistory(now);
if (aapsTbr == null && state.tbrActive && state.tbrRemainingDuration > 2) { if (aapsTbr == null && state.tbrActive && state.tbrRemainingDuration > 2) {
log.debug("Creating temp basal from pump TBR"); log.debug("Creating temp basal from pump TBR");
Answers.getInstance().logCustom(new CustomEvent("ComboTbrMismatch")
.putCustomAttribute("buildversion", BuildConfig.BUILDVERSION)
.putCustomAttribute("version", BuildConfig.VERSION)
.putCustomAttribute("type", "new TBR on pump"));
TemporaryBasal newTempBasal = new TemporaryBasal(); TemporaryBasal newTempBasal = new TemporaryBasal();
newTempBasal.date = now; newTempBasal.date = now;
newTempBasal.percentRate = state.tbrPercent; newTempBasal.percentRate = state.tbrPercent;
@ -1071,6 +1082,10 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf
MainApp.getConfigBuilder().addToHistoryTempBasal(newTempBasal); MainApp.getConfigBuilder().addToHistoryTempBasal(newTempBasal);
} else if (aapsTbr != null && aapsTbr.getPlannedRemainingMinutes() > 2 && !state.tbrActive) { } else if (aapsTbr != null && aapsTbr.getPlannedRemainingMinutes() > 2 && !state.tbrActive) {
log.debug("Ending AAPS-TBR since pump has no TBR active"); log.debug("Ending AAPS-TBR since pump has no TBR active");
Answers.getInstance().logCustom(new CustomEvent("ComboTbrMismatch")
.putCustomAttribute("buildversion", BuildConfig.BUILDVERSION)
.putCustomAttribute("version", BuildConfig.VERSION)
.putCustomAttribute("type", "TBR cancelled on pump"));
TemporaryBasal tempStop = new TemporaryBasal(); TemporaryBasal tempStop = new TemporaryBasal();
tempStop.date = now; tempStop.date = now;
tempStop.durationInMinutes = 0; tempStop.durationInMinutes = 0;
@ -1080,6 +1095,10 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf
&& (aapsTbr.percentRate != state.tbrPercent || && (aapsTbr.percentRate != state.tbrPercent ||
Math.abs(aapsTbr.getPlannedRemainingMinutes() - state.tbrRemainingDuration) > 2)) { Math.abs(aapsTbr.getPlannedRemainingMinutes() - state.tbrRemainingDuration) > 2)) {
log.debug("AAPSs and pump-TBR differ; ending AAPS-TBR and creating new TBR based on pump TBR"); log.debug("AAPSs and pump-TBR differ; ending AAPS-TBR and creating new TBR based on pump TBR");
Answers.getInstance().logCustom(new CustomEvent("ComboTbrMismatch")
.putCustomAttribute("buildversion", BuildConfig.BUILDVERSION)
.putCustomAttribute("version", BuildConfig.VERSION)
.putCustomAttribute("type", "TBR on pump differs from AAPS TBR"));
TemporaryBasal tempStop = new TemporaryBasal(); TemporaryBasal tempStop = new TemporaryBasal();
tempStop.date = now - 1000; tempStop.date = now - 1000;
tempStop.durationInMinutes = 0; tempStop.durationInMinutes = 0;
@ -1096,12 +1115,7 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf
} }
} }
/** /**Reads the pump's history and updates the DB accordingly. */
* Reads the pump's history and updates the DB accordingly.
* <p>
* Only ever called by #readAllPumpData which is triggered by the user via the combo fragment
* which warns the user against doing this.
*/
private boolean readHistory(@Nullable PumpHistoryRequest request) { private boolean readHistory(@Nullable PumpHistoryRequest request) {
CommandResult historyResult = runCommand(MainApp.gs(R.string.combo_activity_reading_pump_history), 3, () -> ruffyScripter.readHistory(request)); CommandResult historyResult = runCommand(MainApp.gs(R.string.combo_activity_reading_pump_history), 3, () -> ruffyScripter.readHistory(request));
if (!historyResult.success) { if (!historyResult.success) {
@ -1158,9 +1172,14 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf
readHistory(new PumpHistoryRequest().tddHistory(PumpHistoryRequest.FULL)); readHistory(new PumpHistoryRequest().tddHistory(PumpHistoryRequest.FULL));
// } // }
// }, post); // }, post);
if (post != null) {
post.run(); post.run();
}
CommandQueue commandQueue = ConfigBuilderPlugin.getCommandQueue();
if (commandQueue.performing() == null && commandQueue.size() == 0) {
ruffyScripter.disconnect(); ruffyScripter.disconnect();
} }
}
// TODO use queue once ready // TODO use queue once ready
void readAlertData(Callback post) { void readAlertData(Callback post) {
@ -1170,9 +1189,14 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf
readHistory(new PumpHistoryRequest().pumpErrorHistory(PumpHistoryRequest.FULL)); readHistory(new PumpHistoryRequest().pumpErrorHistory(PumpHistoryRequest.FULL));
// } // }
// }, post); // }, post);
if (post != null) {
post.run(); post.run();
}
CommandQueue commandQueue = ConfigBuilderPlugin.getCommandQueue();
if (commandQueue.performing() == null && commandQueue.size() == 0) {
ruffyScripter.disconnect(); ruffyScripter.disconnect();
} }
}
// TODO use queue once ready // TODO use queue once ready
void readAllPumpData(Callback post) { void readAllPumpData(Callback post) {
@ -1189,9 +1213,14 @@ public class ComboPlugin implements PluginBase, PumpInterface, ConstraintsInterf
} }
// } // }
// }, post); // }, post);
if (post != null) {
post.run(); post.run();
}
CommandQueue commandQueue = ConfigBuilderPlugin.getCommandQueue();
if (commandQueue.performing() == null && commandQueue.size() == 0) {
ruffyScripter.disconnect(); ruffyScripter.disconnect();
} }
}
/** /**
* Reads QuickInfo to update reservoir level and determine if new boluses exist on the pump * Reads QuickInfo to update reservoir level and determine if new boluses exist on the pump

View file

@ -18,6 +18,7 @@ import info.nightscout.androidaps.plugins.ConfigBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification; import info.nightscout.androidaps.plugins.Overview.events.EventNewNotification;
import info.nightscout.androidaps.plugins.Overview.notifications.Notification; import info.nightscout.androidaps.plugins.Overview.notifications.Notification;
import info.nightscout.androidaps.receivers.KeepAliveReceiver; import info.nightscout.androidaps.receivers.KeepAliveReceiver;
import info.nightscout.utils.NSUpload;
/** /**
* Created by adrian on 17/12/17. * Created by adrian on 17/12/17.
@ -42,6 +43,9 @@ public class LocalAlertUtils {
n.soundId = R.raw.alarm; n.soundId = R.raw.alarm;
SP.putLong("nextPumpDisconnectedAlarm", System.currentTimeMillis() + pumpUnreachableThreshold()); SP.putLong("nextPumpDisconnectedAlarm", System.currentTimeMillis() + pumpUnreachableThreshold());
MainApp.bus().post(new EventNewNotification(n)); MainApp.bus().post(new EventNewNotification(n));
if (SP.getBoolean(R.string.key_ns_create_announcements_from_errors, true)) {
NSUpload.uploadError(n.text);
}
} }
} }
@ -91,6 +95,9 @@ public class LocalAlertUtils {
n.soundId = R.raw.alarm; n.soundId = R.raw.alarm;
SP.putLong("nextMissedReadingsAlarm", System.currentTimeMillis() + missedReadingsThreshold()); SP.putLong("nextMissedReadingsAlarm", System.currentTimeMillis() + missedReadingsThreshold());
MainApp.bus().post(new EventNewNotification(n)); MainApp.bus().post(new EventNewNotification(n));
if (SP.getBoolean(R.string.key_ns_create_announcements_from_errors, true)) {
NSUpload.uploadError(n.text);
}
} }
} }
} }

View file

@ -408,6 +408,7 @@ public class NSUpload {
try { try {
data.put("eventType", "Announcement"); data.put("eventType", "Announcement");
data.put("created_at", DateUtil.toISOString(new Date())); data.put("created_at", DateUtil.toISOString(new Date()));
data.put("enteredBy", SP.getString("careportal_enteredby", MainApp.gs(R.string.app_name)));
data.put("notes", error); data.put("notes", error);
data.put("isAnnouncement", true); data.put("isAnnouncement", true);
} catch (JSONException e) { } catch (JSONException e) {

View file

@ -737,7 +737,7 @@
<string name="combo_pump_activity_label">Aktivita</string> <string name="combo_pump_activity_label">Aktivita</string>
<string name="combo_no_pump_connection" formatted="false">Žádné spojení %d min</string> <string name="combo_no_pump_connection" formatted="false">Žádné spojení %d min</string>
<string name="combo_tbr_remaining" formatted="false">%d%% (%d min zbývá)</string> <string name="combo_tbr_remaining" formatted="false">%d%% (%d min zbývá)</string>
<string name="combo_pump_action_initializing">Inicializace</string> <string name="combo_pump_state_initializing">Inicializace</string>
<string name="combo_pump_state_disconnected">Odpojeno</string> <string name="combo_pump_state_disconnected">Odpojeno</string>
<string name="combo_pump_state_suspended_due_to_error">Vypnuto díky chybě</string> <string name="combo_pump_state_suspended_due_to_error">Vypnuto díky chybě</string>
<string name="combo_pump_state_suspended_by_user">Vypnuto uživatelem</string> <string name="combo_pump_state_suspended_by_user">Vypnuto uživatelem</string>

View file

@ -775,4 +775,22 @@
<string name="openapsama_link_to_preferncejson_doc_txt">Achtung! Normalerweise musst Du diese Werte nicht ändern. Bitte KLICKE HIER und LESE den Text. Verändere Werte erst, wenn Du den Inhalt des Textes verstanden hast.</string> <string name="openapsama_link_to_preferncejson_doc_txt">Achtung! Normalerweise musst Du diese Werte nicht ändern. Bitte KLICKE HIER und LESE den Text. Verändere Werte erst, wenn Du den Inhalt des Textes verstanden hast.</string>
<string name="combo_actvity_reading_basal_profile">Basalratenprofil wird gelesen</string> <string name="combo_actvity_reading_basal_profile">Basalratenprofil wird gelesen</string>
<string name="pump_basebasalrate">%.2f IE/h</string> <string name="pump_basebasalrate">%.2f IE/h</string>
<string name="combo_read_full_history_info">Drücke den Button lange, um die gesamte Historie und das Basal-Profil der Pumpe auszulesen. Dies ist eigentlich unnötig, weil die Historie regelmäßig gelesen wird. Hilfreich kann dies jedoch sein, wenn Datum und Zeit grundlegend verändert wurden oder die Pumpe ausgetauscht wurde.</string>
<string name="combo_error_no_connection_no_bolus_delivered">Keine Verbindung zur Pumpe: Es wurde kein Bolus abgegeben.</string>
<string name="extendedbolusdeliveryerror">Fehler bei der Abgabe eines verlängerten Bolus</string>
<string name="combo_bolus_rejected_due_to_pump_history_change">Nach der Berechnung des Bolus hat sich die Pumpenhistorie geändert. Daher wurde kein Bolus abgegeben. Bitte prüfe, ob überhaupt noch ein Bolus benötigt wird. Wenn die gleiche Bolusmenge erforderlich ist, warte zwei Minuten ab, denn es werden aus Sicherheitsgründen keine gleich großen Boli abgegeben, wenn sie innerhalb von zwei Minuten angefordert wurden (unabhängig davon, ob sie verabreicht wurden oder nicht).</string>
<string name="combo_error_updating_treatment_record">Der Bolus wurde erfolgreich abgegeben, aber nicht als Behandlungseintrag gespeichert. Dies kann passieren, wenn zwei kleine, gleich große Boli innerhalb von zwei Minuten verabreicht werden. Bitte überprüfe die Pumpenhistorie und Behandlungseinträge. Verwende das Careportal, um fehlende Einträge hinzuzufügen. Stelle sicher, dass keine Einträge für genau dieselbe Minute und dieselbe Menge hinzugefügt werden.</string>
<string name="combo_activity_checking_pump_state">Status wird aktualisiert</string>
<string name="combo_warning_pump_basal_rate_changed">Die Basalrate in der Pumpe hat sich geändert und wird aktualisiert</string>
<string name="combo_error_failure_reading_changed_basal_rate">Das Einlesen der geänderten Basalrate in der Pumpe schlug fehl.</string>
<string name="combo_activity_checking_for_history_changes">Änderungen der Historie werden gesucht</string>
<string name="combo_error_multiple_boluses_with_identical_timestamp">Der Import mehrerer Boli der gleichen Menge, abgegeben in der gleichen Minute, ist gescheitert: Nur ein Datensatz konnte den Behandlungen hinzugefügt werden. Bitte überprüfe die Pumpe und verwende das Careportal, um fehlende Einträge hinzuzufügen. Stelle sicher, dass keine Einträge für genau dieselbe Minute mit derselben Menge hinzugefügt werden.</string>
<string name="mute">Alarm stoppen</string>
<string name="bolusstopped">Bolus gestoppt</string>
<string name="bolusstopping">Bolus wird gestoppt</string>
<string name="basalprofilenotaligned">Basalraten beginnen nicht zur vollen Stunde: %s</string>
<string name="zerovalueinprofile">Ungültiges Profil: %s</string>
<string name="hoursago">vor %.1f h</string>
<string name="combo_high_temp_rejected_due_to_pump_history_changes">Es wurde keine hohe TBR gesetzt, da nach der Berechnung Boluseinträge in der Pumpenhistorik gefunden wurden.</string>
<string name="combo_check_date">Der letzte Bolus liegt mehr als 24 Stunden zurück. Prüfe bitte das Datum auf der Uhr.</string>
</resources> </resources>

View file

@ -781,7 +781,6 @@
<string name="combo_reservoir_level_insufficient_for_bolus">Niet genoeg insuline aanwezig in reservoir voor de bolus</string> <string name="combo_reservoir_level_insufficient_for_bolus">Niet genoeg insuline aanwezig in reservoir voor de bolus</string>
<string name="careportal_combobolus">Combinatie-Bolus</string> <string name="careportal_combobolus">Combinatie-Bolus</string>
<string name="pump_basebasalrate">%.2f E/u</string> <string name="pump_basebasalrate">%.2f E/u</string>
<string name="combo_pump_action_initializing">Laden van pomp</string>
<string name="hoursago">%.1fu geleden</string> <string name="hoursago">%.1fu geleden</string>
<string name="bolusstopped">Bolus gestopt</string> <string name="bolusstopped">Bolus gestopt</string>
<string name="bolusstopping">Stoppen van bolus</string> <string name="bolusstopping">Stoppen van bolus</string>

View file

@ -876,5 +876,10 @@
<string name="combo_activity_checking_for_history_changes">Checking for history changes</string> <string name="combo_activity_checking_for_history_changes">Checking for history changes</string>
<string name="combo_error_multiple_boluses_with_identical_timestamp">Multiple boluses with the same amount within the same minute were just imported. Only one record could be added to treatments. Please check the pump and manually add a bolus record using the Careportal tab. Make sure to create a bolus with a time no other bolus uses.</string> <string name="combo_error_multiple_boluses_with_identical_timestamp">Multiple boluses with the same amount within the same minute were just imported. Only one record could be added to treatments. Please check the pump and manually add a bolus record using the Careportal tab. Make sure to create a bolus with a time no other bolus uses.</string>
<string name="mute">Mute</string> <string name="mute">Mute</string>
<string name="about_link_urls">\n\nhttp://www.androidaps.org\nhttp://www.androidaps.de (de)\n\nfacebook:\nhttp://facebook.androidaps.org\nhttp://facebook.androidaps.de (de)</string>
<string name="combo_check_date">The last bolus is older than 24 hours. Please check the date on the pump is set correctly.</string>
<string name="key_ns_create_announcements_from_errors">ns_create_announcements_from_errors</string>
<string name="ns_create_announcements_from_errors_title">Create announcements from errors</string>
<string name="ns_create_announcements_from_errors_summary">Create Nightscout announcement for error dialogs and local alerts (also viewable in Careportal under Treatments)</string>
</resources> </resources>

View file

@ -27,6 +27,12 @@
android:key="@string/key_ns_logappstartedevent" android:key="@string/key_ns_logappstartedevent"
android:title="@string/ns_logappstartedevent" /> android:title="@string/ns_logappstartedevent" />
<SwitchPreference
android:defaultValue="true"
android:key="@string/key_ns_create_announcements_from_errors"
android:title="@string/ns_create_announcements_from_errors_title"
android:summary="@string/ns_create_announcements_from_errors_summary"/>
<SwitchPreference <SwitchPreference
android:defaultValue="true" android:defaultValue="true"
android:key="@string/key_ns_localbroadcasts" android:key="@string/key_ns_localbroadcasts"

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 121 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 110 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB