Merge pull request #1627 from TebbeUbben/insight-dev

Insight: Trial to improve connection stability
This commit is contained in:
AdrianLxM 2019-02-13 07:31:25 +01:00 committed by GitHub
commit 65c5aebbda
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 108 additions and 32 deletions

View file

@ -17,6 +17,10 @@ import android.os.Looper;
import android.os.Vibrator; import android.os.Vibrator;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.PumpInsightLocal.activities.InsightAlertActivity; import info.nightscout.androidaps.plugins.PumpInsightLocal.activities.InsightAlertActivity;
import info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.remote_control.ConfirmAlertMessage; import info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.remote_control.ConfirmAlertMessage;
import info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.remote_control.SnoozeAlertMessage; import info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.remote_control.SnoozeAlertMessage;
@ -26,10 +30,14 @@ import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.Alert;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.AlertStatus; import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.AlertStatus;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.AlertType; import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.AlertType;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.InsightState; import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.InsightState;
import info.nightscout.androidaps.plugins.PumpInsightLocal.exceptions.InsightException;
import info.nightscout.androidaps.plugins.PumpInsightLocal.exceptions.app_layer_errors.AppLayerErrorException;
import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.ExceptionTranslator; import info.nightscout.androidaps.plugins.PumpInsightLocal.utils.ExceptionTranslator;
public class InsightAlertService extends Service implements InsightConnectionService.StateCallback { public class InsightAlertService extends Service implements InsightConnectionService.StateCallback {
private static Logger log = LoggerFactory.getLogger(L.PUMPCOMM);
private LocalBinder localBinder = new LocalBinder(); private LocalBinder localBinder = new LocalBinder();
private boolean connectionRequested; private boolean connectionRequested;
private final Object $alertLock = new Object[0]; private final Object $alertLock = new Object[0];
@ -164,7 +172,12 @@ public class InsightAlertService extends Service implements InsightConnectionSer
} catch (InterruptedException ignored) { } catch (InterruptedException ignored) {
connectionService.withdrawConnectionRequest(thread); connectionService.withdrawConnectionRequest(thread);
break; break;
} catch (Exception ignored) { } catch (AppLayerErrorException e) {
log.info("Exception while fetching alert: " + e.getClass().getCanonicalName() + " (" + e.getErrorCode() + ")");
} catch (InsightException e) {
log.info("Exception while fetching alert: " + e.getClass().getSimpleName());
} catch (Exception e) {
log.error("Exception while fetching alert", e);
} }
try { try {
Thread.sleep(1000); Thread.sleep(1000);
@ -207,7 +220,14 @@ public class InsightAlertService extends Service implements InsightConnectionSer
SnoozeAlertMessage snoozeAlertMessage = new SnoozeAlertMessage(); SnoozeAlertMessage snoozeAlertMessage = new SnoozeAlertMessage();
snoozeAlertMessage.setAlertID(alert.getAlertId()); snoozeAlertMessage.setAlertID(alert.getAlertId());
connectionService.requestMessage(snoozeAlertMessage).await(); connectionService.requestMessage(snoozeAlertMessage).await();
} catch (AppLayerErrorException e) {
log.info("Exception while muting alert: " + e.getClass().getCanonicalName() + " (" + e.getErrorCode() + ")");
ExceptionTranslator.makeToast(InsightAlertService.this, e);
} catch (InsightException e) {
log.info("Exception while muting alert: " + e.getClass().getSimpleName());
ExceptionTranslator.makeToast(InsightAlertService.this, e);
} catch (Exception e) { } catch (Exception e) {
log.error("Exception while muting alert", e);
ExceptionTranslator.makeToast(InsightAlertService.this, e); ExceptionTranslator.makeToast(InsightAlertService.this, e);
} }
}).start(); }).start();
@ -219,7 +239,14 @@ public class InsightAlertService extends Service implements InsightConnectionSer
ConfirmAlertMessage confirmAlertMessage = new ConfirmAlertMessage(); ConfirmAlertMessage confirmAlertMessage = new ConfirmAlertMessage();
confirmAlertMessage.setAlertID(alert.getAlertId()); confirmAlertMessage.setAlertID(alert.getAlertId());
connectionService.requestMessage(confirmAlertMessage).await(); connectionService.requestMessage(confirmAlertMessage).await();
} catch (AppLayerErrorException e) {
log.info("Exception while confirming alert: " + e.getClass().getCanonicalName() + " (" + e.getErrorCode() + ")");
ExceptionTranslator.makeToast(InsightAlertService.this, e);
} catch (InsightException e) {
log.info("Exception while confirming alert: " + e.getClass().getSimpleName());
ExceptionTranslator.makeToast(InsightAlertService.this, e);
} catch (Exception e) { } catch (Exception e) {
log.error("Exception while confirming alert", e);
ExceptionTranslator.makeToast(InsightAlertService.this, e); ExceptionTranslator.makeToast(InsightAlertService.this, e);
} }
}).start(); }).start();

View file

@ -27,6 +27,7 @@ import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.ActiveBas
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.ActiveBolus; import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.ActiveBolus;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.ActiveTBR; import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.ActiveTBR;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.CartridgeStatus; import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.CartridgeStatus;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.InsightState;
import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.TotalDailyDose; import info.nightscout.androidaps.plugins.PumpInsightLocal.descriptors.TotalDailyDose;
import info.nightscout.androidaps.queue.Callback; import info.nightscout.androidaps.queue.Callback;
import info.nightscout.utils.DateUtil; import info.nightscout.utils.DateUtil;
@ -169,7 +170,8 @@ public class LocalInsightFragment extends SubscriberFragment implements View.OnC
private void getConnectionStatusItem(List<View> statusItems) { private void getConnectionStatusItem(List<View> statusItems) {
int string = 0; int string = 0;
switch (LocalInsightPlugin.getInstance().getConnectionService().getState()) { InsightState state = LocalInsightPlugin.getInstance().getConnectionService().getState();
switch (state) {
case NOT_PAIRED: case NOT_PAIRED:
string = R.string.not_paired; string = R.string.not_paired;
break; break;
@ -199,6 +201,9 @@ public class LocalInsightFragment extends SubscriberFragment implements View.OnC
break; break;
} }
statusItems.add(getStatusItem(MainApp.gs(R.string.insight_status), MainApp.gs(string))); statusItems.add(getStatusItem(MainApp.gs(R.string.insight_status), MainApp.gs(string)));
if (state == InsightState.RECOVERING) {
statusItems.add(getStatusItem(MainApp.gs(R.string.recovery_duration), LocalInsightPlugin.getInstance().getConnectionService().getRecoveryDuration() / 1000 + "s"));
}
} }
private void getLastConnectedItem(List<View> statusItems) { private void getLastConnectedItem(List<View> statusItems) {

View file

@ -116,6 +116,7 @@ public class InsightConnectionService extends Service implements ConnectionEstab
private List<info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.Service> activatedServices = new ArrayList<>(); private List<info.nightscout.androidaps.plugins.PumpInsightLocal.app_layer.Service> activatedServices = new ArrayList<>();
private long lastDataTime; private long lastDataTime;
private long lastConnected; private long lastConnected;
private long recoveryDuration = 0;
KeyPair getKeyPair() { KeyPair getKeyPair() {
if (keyPair == null) keyPair = Cryptograph.generateRSAKey(); if (keyPair == null) keyPair = Cryptograph.generateRSAKey();
@ -130,6 +131,22 @@ public class InsightConnectionService extends Service implements ConnectionEstab
return randomBytes; return randomBytes;
} }
public synchronized long getRecoveryDuration() {
return recoveryDuration;
}
private void increaseRecoveryDuration() {
long maxRecoveryDuration = SP.getInt("insight_max_recovery_duration", 20);
maxRecoveryDuration = Math.min(maxRecoveryDuration, 20);
maxRecoveryDuration = Math.max(maxRecoveryDuration, 0);
long minRecoveryDuration = SP.getInt("insight_min_recovery_duration", 5);
minRecoveryDuration = Math.min(minRecoveryDuration, 20);
minRecoveryDuration = Math.max(minRecoveryDuration, 0);
recoveryDuration += 1000;
recoveryDuration = Math.max(recoveryDuration, minRecoveryDuration * 1000);
recoveryDuration = Math.min(recoveryDuration, maxRecoveryDuration * 1000);
}
public long getLastConnected() { public long getLastConnected() {
return lastConnected; return lastConnected;
} }
@ -255,7 +272,10 @@ public class InsightConnectionService extends Service implements ConnectionEstab
disconnectTimer.interrupt(); disconnectTimer.interrupt();
disconnectTimer = null; disconnectTimer = null;
} }
if (state == InsightState.DISCONNECTED && pairingDataStorage.isPaired()) connect(); if (state == InsightState.DISCONNECTED && pairingDataStorage.isPaired()) {
recoveryDuration = 0;
connect();
}
} }
public synchronized void withdrawConnectionRequest(Object lock) { public synchronized void withdrawConnectionRequest(Object lock) {
@ -266,12 +286,12 @@ public class InsightConnectionService extends Service implements ConnectionEstab
recoveryTimer.interrupt(); recoveryTimer.interrupt();
recoveryTimer = null; recoveryTimer = null;
setState(InsightState.DISCONNECTED); setState(InsightState.DISCONNECTED);
cleanup(); cleanup(true);
} else if (state != InsightState.DISCONNECTED) { } else if (state != InsightState.DISCONNECTED) {
long disconnectTimeout = SP.getInt("insight_disconnect_delay", 5); long disconnectTimeout = SP.getInt("insight_disconnect_delay", 5);
disconnectTimeout = Math.min(disconnectTimeout, 15); disconnectTimeout = Math.min(disconnectTimeout, 15);
disconnectTimeout = Math.max(disconnectTimeout, 0); disconnectTimeout = Math.max(disconnectTimeout, 0);
log.info("Last connection lock released, will disconnect " + disconnectTimeout + " seconds"); log.info("Last connection lock released, will disconnect in " + disconnectTimeout + " seconds");
disconnectTimer = DelayedActionThread.runDelayed("Disconnect Timer", disconnectTimeout * 1000, this::disconnect); disconnectTimer = DelayedActionThread.runDelayed("Disconnect Timer", disconnectTimeout * 1000, this::disconnect);
} }
} }
@ -281,7 +301,7 @@ public class InsightConnectionService extends Service implements ConnectionEstab
return connectionRequests.contains(lock); return connectionRequests.contains(lock);
} }
private void cleanup() { private void cleanup(boolean closeSocket) {
messageQueue.completeActiveRequest(new ConnectionLostException()); messageQueue.completeActiveRequest(new ConnectionLostException());
messageQueue.completePendingRequests(new ConnectionLostException()); messageQueue.completePendingRequests(new ConnectionLostException());
if (recoveryTimer != null) { if (recoveryTimer != null) {
@ -301,10 +321,12 @@ public class InsightConnectionService extends Service implements ConnectionEstab
outputStreamWriter = null; outputStreamWriter = null;
} }
if (connectionEstablisher != null) { if (connectionEstablisher != null) {
connectionEstablisher.close(); if (closeSocket) {
connectionEstablisher.close(closeSocket);
bluetoothSocket = null;
}
connectionEstablisher = null; connectionEstablisher = null;
} }
bluetoothSocket = null;
if (timeoutTimer != null) { if (timeoutTimer != null) {
timeoutTimer.interrupt(); timeoutTimer.interrupt();
timeoutTimer = null; timeoutTimer = null;
@ -331,27 +353,30 @@ public class InsightConnectionService extends Service implements ConnectionEstab
log.info("Exception occurred: " + e.getClass().getSimpleName()); log.info("Exception occurred: " + e.getClass().getSimpleName());
if (pairingDataStorage.isPaired()) { if (pairingDataStorage.isPaired()) {
setState(connectionRequests.size() != 0 ? InsightState.RECOVERING : InsightState.DISCONNECTED); setState(connectionRequests.size() != 0 ? InsightState.RECOVERING : InsightState.DISCONNECTED);
cleanup(); if (e instanceof ConnectionFailedException) {
cleanup(((ConnectionFailedException) e).getDurationOfConnectionAttempt() <= 1000);
} else cleanup(true);
messageQueue.completeActiveRequest(e); messageQueue.completeActiveRequest(e);
messageQueue.completePendingRequests(e); messageQueue.completePendingRequests(e);
if (connectionRequests.size() != 0) { if (connectionRequests.size() != 0) {
if (!(e instanceof ConnectionFailedException)) { if (!(e instanceof ConnectionFailedException)) {
connect(); connect();
} else { } else {
int recoveryDuration = SP.getInt("insight_recovery_duration", 5); increaseRecoveryDuration();
recoveryDuration = Math.min(recoveryDuration, 20); if (recoveryDuration == 0) connect();
recoveryDuration = Math.max(recoveryDuration, 0); else {
recoveryTimer = DelayedActionThread.runDelayed("RecoveryTimer", recoveryDuration * 1000, () -> { recoveryTimer = DelayedActionThread.runDelayed("RecoveryTimer", recoveryDuration, () -> {
recoveryTimer = null; recoveryTimer = null;
synchronized (InsightConnectionService.this) { synchronized (InsightConnectionService.this) {
if (!Thread.currentThread().isInterrupted()) connect(); if (!Thread.currentThread().isInterrupted()) connect();
} }
}); });
}
} }
} }
} else { } else {
setState(InsightState.NOT_PAIRED); setState(InsightState.NOT_PAIRED);
cleanup(); cleanup(true);
} }
for (ExceptionCallback exceptionCallback : exceptionCallbacks) for (ExceptionCallback exceptionCallback : exceptionCallbacks)
exceptionCallback.onExceptionOccur(e); exceptionCallback.onExceptionOccur(e);
@ -362,7 +387,7 @@ public class InsightConnectionService extends Service implements ConnectionEstab
sendAppLayerMessage(new DisconnectMessage()); sendAppLayerMessage(new DisconnectMessage());
sendSatlMessageAndWait(new info.nightscout.androidaps.plugins.PumpInsightLocal.satl.DisconnectMessage()); sendSatlMessageAndWait(new info.nightscout.androidaps.plugins.PumpInsightLocal.satl.DisconnectMessage());
} }
cleanup(); cleanup(true);
setState(pairingDataStorage.isPaired() ? InsightState.DISCONNECTED : InsightState.NOT_PAIRED); setState(pairingDataStorage.isPaired() ? InsightState.DISCONNECTED : InsightState.NOT_PAIRED);
} }
@ -377,7 +402,7 @@ public class InsightConnectionService extends Service implements ConnectionEstab
if (connectionRequests.size() == 0) if (connectionRequests.size() == 0)
throw new IllegalStateException("A connection lock must be hold for pairing"); throw new IllegalStateException("A connection lock must be hold for pairing");
log.info("Pairing initiated"); log.info("Pairing initiated");
cleanup(); cleanup(true);
pairingDataStorage.setMacAddress(macAddress); pairingDataStorage.setMacAddress(macAddress);
connect(); connect();
} }
@ -398,6 +423,7 @@ public class InsightConnectionService extends Service implements ConnectionEstab
@Override @Override
public synchronized void onConnectionSucceed() { public synchronized void onConnectionSucceed() {
try { try {
recoveryDuration = 0;
inputStreamReader = new InputStreamReader(bluetoothSocket.getInputStream(), this); inputStreamReader = new InputStreamReader(bluetoothSocket.getInputStream(), this);
outputStreamWriter = new OutputStreamWriter(bluetoothSocket.getOutputStream(), this); outputStreamWriter = new OutputStreamWriter(bluetoothSocket.getOutputStream(), this);
inputStreamReader.start(); inputStreamReader.start();
@ -743,8 +769,8 @@ public class InsightConnectionService extends Service implements ConnectionEstab
} }
@Override @Override
public synchronized void onConnectionFail(Exception e) { public synchronized void onConnectionFail(Exception e, long duration) {
handleException(new ConnectionFailedException()); handleException(new ConnectionFailedException(duration));
} }
@Override @Override

View file

@ -2,4 +2,13 @@ package info.nightscout.androidaps.plugins.PumpInsightLocal.exceptions;
public class ConnectionFailedException extends InsightException { public class ConnectionFailedException extends InsightException {
private long durationOfConnectionAttempt;
public ConnectionFailedException(long durationOfConnectionAttempt) {
this.durationOfConnectionAttempt = durationOfConnectionAttempt;
}
public long getDurationOfConnectionAttempt() {
return durationOfConnectionAttempt;
}
} }

View file

@ -39,7 +39,7 @@ public class ConnectionEstablisher extends Thread {
Method removeBond = bluetoothDevice.getClass().getMethod("removeBond", (Class[]) null); Method removeBond = bluetoothDevice.getClass().getMethod("removeBond", (Class[]) null);
removeBond.invoke(bluetoothDevice, (Object[]) null); removeBond.invoke(bluetoothDevice, (Object[]) null);
} catch (ReflectiveOperationException e) { } catch (ReflectiveOperationException e) {
if (!isInterrupted()) callback.onConnectionFail(e); if (!isInterrupted()) callback.onConnectionFail(e, 0);
return; return;
} }
} }
@ -49,21 +49,22 @@ public class ConnectionEstablisher extends Thread {
callback.onSocketCreated(socket); callback.onSocketCreated(socket);
} }
} catch (IOException e) { } catch (IOException e) {
if (!isInterrupted()) callback.onConnectionFail(e); if (!isInterrupted()) callback.onConnectionFail(e, 0);
return; return;
} }
long connectionStart = System.currentTimeMillis();
try { try {
socket.connect(); socket.connect();
if (!isInterrupted()) callback.onConnectionSucceed(); if (!isInterrupted()) callback.onConnectionSucceed();
} catch (IOException e) { } catch (IOException e) {
if (!isInterrupted()) callback.onConnectionFail(e); if (!isInterrupted()) callback.onConnectionFail(e, System.currentTimeMillis() - connectionStart);
} }
} }
public void close() { public void close(boolean closeSocket) {
try { try {
interrupt(); interrupt();
if (socket != null && socket.isConnected()) socket.close(); if (closeSocket && socket != null && socket.isConnected()) socket.close();
} catch (IOException ignored) { } catch (IOException ignored) {
} }
} }
@ -73,6 +74,6 @@ public class ConnectionEstablisher extends Thread {
void onConnectionSucceed(); void onConnectionSucceed();
void onConnectionFail(Exception e); void onConnectionFail(Exception e, long duration);
} }
} }

View file

@ -1250,7 +1250,6 @@
<string name="log_alerts">Log alerts</string> <string name="log_alerts">Log alerts</string>
<string name="enable_tbr_emulation">Enable TBR emulation</string> <string name="enable_tbr_emulation">Enable TBR emulation</string>
<string name="enable_tbr_emulation_summary">Use extended boluses instead of TBRs to bypass the 250% limit</string> <string name="enable_tbr_emulation_summary">Use extended boluses instead of TBRs to bypass the 250% limit</string>
<string name="recovery_duration">Recovery duration [s]</string>
<string name="disconnect_delay">Disconnect delay [s]</string> <string name="disconnect_delay">Disconnect delay [s]</string>
<string name="serial_number">Serial number</string> <string name="serial_number">Serial number</string>
<string name="release_software_version">Release software version</string> <string name="release_software_version">Release software version</string>
@ -1293,6 +1292,9 @@
<string name="short_status_tdd">TDD: %1$.2f</string> <string name="short_status_tdd">TDD: %1$.2f</string>
<string name="short_status_reservoir">Reser.: %1$.2fU</string> <string name="short_status_reservoir">Reser.: %1$.2fU</string>
<string name="short_status_battery">Batt.: %1$d%%</string> <string name="short_status_battery">Batt.: %1$d%%</string>
<string name="max_recovery_duration">Max. recovery duration [s]</string>
<string name="min_recovery_duration">Min. recovery duration [s]</string>
<string name="recovery_duration">Recovery duration</string>
<string name="profile_total">== ∑ %1$s U</string> <string name="profile_total">== ∑ %1$s U</string>
<string name="profile_ins_units_per_hout">U/h</string> <string name="profile_ins_units_per_hout">U/h</string>

View file

@ -40,8 +40,14 @@
<EditTextPreference <EditTextPreference
android:defaultValue="5" android:defaultValue="5"
android:inputType="number" android:inputType="number"
android:key="insight_recovery_duration" android:key="insight_min_recovery_duration"
android:title="@string/recovery_duration" /> android:title="@string/min_recovery_duration" />
<EditTextPreference
android:defaultValue="20"
android:inputType="number"
android:key="insight_max_recovery_duration"
android:title="@string/max_recovery_duration" />
<EditTextPreference <EditTextPreference
android:defaultValue="5" android:defaultValue="5"