diff --git a/cliparser/src/main/java/com/jwoglom/pumpx2/cliparser/Main.java b/cliparser/src/main/java/com/jwoglom/pumpx2/cliparser/Main.java index 2febbb0e..291477aa 100644 --- a/cliparser/src/main/java/com/jwoglom/pumpx2/cliparser/Main.java +++ b/cliparser/src/main/java/com/jwoglom/pumpx2/cliparser/Main.java @@ -253,7 +253,11 @@ private static Set filterKnownPossibilities(String rawHex, int o ) { possibilities = ImmutableSet.of(Characteristic.CURRENT_STATUS); } else if ( - (opCode == 37 && len == 148) // InitiateBolusRequest + (opCode == 37 && len == 148) || // InitiateBolusRequest + (opCode == -92 && len == 78) || // SetTempRateRequest + (opCode == -91 && len == 70) || // SetTempRateResponse + (opCode == -90 && len == 66) || // StopTempRateRequest + (opCode == -89 && len == 68) // StopTempRateResponse ) { possibilities = ImmutableSet.of(Characteristic.CONTROL); } else if ( diff --git a/messages/src/main/java/com/jwoglom/pumpx2/pump/messages/Messages.java b/messages/src/main/java/com/jwoglom/pumpx2/pump/messages/Messages.java index 3480d2d3..4f3d345a 100644 --- a/messages/src/main/java/com/jwoglom/pumpx2/pump/messages/Messages.java +++ b/messages/src/main/java/com/jwoglom/pumpx2/pump/messages/Messages.java @@ -146,6 +146,10 @@ import com.jwoglom.pumpx2.pump.messages.response.control.SetModesResponse; import com.jwoglom.pumpx2.pump.messages.request.control.SetSleepScheduleRequest; import com.jwoglom.pumpx2.pump.messages.response.control.SetSleepScheduleResponse; +import com.jwoglom.pumpx2.pump.messages.request.control.SetTempRateRequest; +import com.jwoglom.pumpx2.pump.messages.response.control.SetTempRateResponse; +import com.jwoglom.pumpx2.pump.messages.request.control.StopTempRateRequest; +import com.jwoglom.pumpx2.pump.messages.response.control.StopTempRateResponse; // IMPORT_END import com.jwoglom.pumpx2.shared.L; @@ -229,6 +233,8 @@ public enum Messages { UNKNOWN_MOBI_OPCODE_NEG124(UnknownMobiOpcodeNeg124Request.class, UnknownMobiOpcodeNeg124Response.class), SET_MODES(SetModesRequest.class, SetModesResponse.class), SET_SLEEP_SCHEDULE(SetSleepScheduleRequest.class, SetSleepScheduleResponse.class), + SET_TEMP_RATE(SetTempRateRequest.class, SetTempRateResponse.class), + STOP_TEMP_RATE(StopTempRateRequest.class, StopTempRateResponse.class), // MESSAGES_END ; diff --git a/messages/src/main/java/com/jwoglom/pumpx2/pump/messages/bluetooth/TronMessageWrapper.java b/messages/src/main/java/com/jwoglom/pumpx2/pump/messages/bluetooth/TronMessageWrapper.java index 2423f30a..c91ce528 100644 --- a/messages/src/main/java/com/jwoglom/pumpx2/pump/messages/bluetooth/TronMessageWrapper.java +++ b/messages/src/main/java/com/jwoglom/pumpx2/pump/messages/bluetooth/TronMessageWrapper.java @@ -19,6 +19,9 @@ public TronMessageWrapper(Message requestMessage, byte currentTxId) { String authKey = ""; if (requestMessage.signed()) { + if (PumpStateSupplier.authenticationKey == null) { + throw new RuntimeException("PumpStateSupplier.authenticationKey is not set, and a signed message was given to TronMessageWrapper"); + } authKey = PumpStateSupplier.authenticationKey.get(); } this.packets = Packetize.packetize(requestMessage, authKey, currentTxId); diff --git a/messages/src/main/java/com/jwoglom/pumpx2/pump/messages/request/control/SetTempRateRequest.java b/messages/src/main/java/com/jwoglom/pumpx2/pump/messages/request/control/SetTempRateRequest.java new file mode 100644 index 00000000..263f207d --- /dev/null +++ b/messages/src/main/java/com/jwoglom/pumpx2/pump/messages/request/control/SetTempRateRequest.java @@ -0,0 +1,47 @@ +package com.jwoglom.pumpx2.pump.messages.request.control; + +import com.google.common.base.Preconditions; +import com.jwoglom.pumpx2.pump.messages.bluetooth.Characteristic; +import com.jwoglom.pumpx2.pump.messages.helpers.Bytes; +import com.jwoglom.pumpx2.pump.messages.Message; +import com.jwoglom.pumpx2.pump.messages.MessageType; +import com.jwoglom.pumpx2.pump.messages.annotations.MessageProps; +import com.jwoglom.pumpx2.pump.messages.models.KnownApiVersion; +import com.jwoglom.pumpx2.pump.messages.models.SupportedDevices; +import com.jwoglom.pumpx2.pump.messages.response.control.SetTempRateResponse; + +@MessageProps( + opCode=-92, + size=6, // 30 with signed + type=MessageType.REQUEST, + characteristic=Characteristic.CONTROL, + signed=true, + minApi=KnownApiVersion.MOBI_API_V3_5, + supportedDevices=SupportedDevices.MOBI_ONLY, + response=SetTempRateResponse.class +) +public class SetTempRateRequest extends Message { + + public SetTempRateRequest() {} + + public SetTempRateRequest(byte[] raw) { + parse(raw); + + } + + public void parse(byte[] raw) { + raw = this.removeSignedRequestHmacBytes(raw); + Preconditions.checkArgument(raw.length == props().size()); + this.cargo = raw; + + } + + + public static byte[] buildCargo(int rate) { + return Bytes.combine( + new byte[]{0,0,0,0,0,0} + ); + } + + +} \ No newline at end of file diff --git a/messages/src/main/java/com/jwoglom/pumpx2/pump/messages/request/control/StopTempRateRequest.java b/messages/src/main/java/com/jwoglom/pumpx2/pump/messages/request/control/StopTempRateRequest.java new file mode 100644 index 00000000..5344b239 --- /dev/null +++ b/messages/src/main/java/com/jwoglom/pumpx2/pump/messages/request/control/StopTempRateRequest.java @@ -0,0 +1,36 @@ +package com.jwoglom.pumpx2.pump.messages.request.control; + +import com.google.common.base.Preconditions; +import com.jwoglom.pumpx2.pump.messages.bluetooth.Characteristic; +import com.jwoglom.pumpx2.pump.messages.helpers.Bytes; +import com.jwoglom.pumpx2.pump.messages.Message; +import com.jwoglom.pumpx2.pump.messages.MessageType; +import com.jwoglom.pumpx2.pump.messages.annotations.MessageProps; +import com.jwoglom.pumpx2.pump.messages.models.KnownApiVersion; +import com.jwoglom.pumpx2.pump.messages.models.SupportedDevices; +import com.jwoglom.pumpx2.pump.messages.response.control.StopTempRateResponse; + +@MessageProps( + opCode=-90, + size=0, + type=MessageType.REQUEST, + characteristic=Characteristic.CONTROL, + signed=true, + minApi=KnownApiVersion.MOBI_API_V3_5, + supportedDevices=SupportedDevices.MOBI_ONLY, + response=StopTempRateResponse.class +) +public class StopTempRateRequest extends Message { + public StopTempRateRequest() { + this.cargo = EMPTY; + } + + public void parse(byte[] raw) { + raw = this.removeSignedRequestHmacBytes(raw); + Preconditions.checkArgument(raw.length == props().size()); + this.cargo = raw; + + } + + +} \ No newline at end of file diff --git a/messages/src/main/java/com/jwoglom/pumpx2/pump/messages/request/template.j2 b/messages/src/main/java/com/jwoglom/pumpx2/pump/messages/request/template.j2 index b04a5345..cbba2340 100644 --- a/messages/src/main/java/com/jwoglom/pumpx2/pump/messages/request/template.j2 +++ b/messages/src/main/java/com/jwoglom/pumpx2/pump/messages/request/template.j2 @@ -31,7 +31,8 @@ public class {{requestName}} extends Message { {% for arg in requestArgs %} {% endfor %}{% endif %} } - public void parse(byte[] raw) { + public void parse(byte[] raw) { {% if catUuid == "CONTROL" %} + raw = this.removeSignedRequestHmacBytes(raw);{% endif %} Preconditions.checkArgument(raw.length == props().size()); this.cargo = raw; {% for arg in requestArgs %}this.{{ arg.name }} = {% if arg.size == 1 %}raw[{{ arg.index }}]{% if arg.type == "boolean" %} != 0{% endif %}; diff --git a/messages/src/main/java/com/jwoglom/pumpx2/pump/messages/response/control/SetTempRateResponse.java b/messages/src/main/java/com/jwoglom/pumpx2/pump/messages/response/control/SetTempRateResponse.java new file mode 100644 index 00000000..8e31c239 --- /dev/null +++ b/messages/src/main/java/com/jwoglom/pumpx2/pump/messages/response/control/SetTempRateResponse.java @@ -0,0 +1,49 @@ +package com.jwoglom.pumpx2.pump.messages.response.control; + +import com.google.common.base.Preconditions; +import com.jwoglom.pumpx2.pump.messages.bluetooth.Characteristic; +import com.jwoglom.pumpx2.pump.messages.helpers.Bytes; +import com.jwoglom.pumpx2.pump.messages.Message; +import com.jwoglom.pumpx2.pump.messages.MessageType; +import com.jwoglom.pumpx2.pump.messages.annotations.MessageProps; +import com.jwoglom.pumpx2.pump.messages.models.KnownApiVersion; +import com.jwoglom.pumpx2.pump.messages.models.SupportedDevices; +import com.jwoglom.pumpx2.pump.messages.request.control.SetTempRateRequest; + +import java.math.BigInteger; + +@MessageProps( + opCode=-91, + size=4, + type=MessageType.RESPONSE, + characteristic=Characteristic.CONTROL, + signed=true, + minApi=KnownApiVersion.MOBI_API_V3_5, + supportedDevices=SupportedDevices.MOBI_ONLY, + request=SetTempRateRequest.class +) +public class SetTempRateResponse extends Message { + + + public SetTempRateResponse() {} + + public SetTempRateResponse(byte[] raw) { + this.cargo = buildCargo(raw); + + } + + public void parse(byte[] raw) { + raw = this.removeSignedRequestHmacBytes(raw); + Preconditions.checkArgument(raw.length == props().size()); + this.cargo = raw; + + } + + + public static byte[] buildCargo(byte[] raw) { + return Bytes.combine( + raw); + } + + +} \ No newline at end of file diff --git a/messages/src/main/java/com/jwoglom/pumpx2/pump/messages/response/control/StopTempRateResponse.java b/messages/src/main/java/com/jwoglom/pumpx2/pump/messages/response/control/StopTempRateResponse.java new file mode 100644 index 00000000..7cf7b61a --- /dev/null +++ b/messages/src/main/java/com/jwoglom/pumpx2/pump/messages/response/control/StopTempRateResponse.java @@ -0,0 +1,59 @@ +package com.jwoglom.pumpx2.pump.messages.response.control; + +import com.google.common.base.Preconditions; +import com.jwoglom.pumpx2.pump.messages.bluetooth.Characteristic; +import com.jwoglom.pumpx2.pump.messages.helpers.Bytes; +import com.jwoglom.pumpx2.pump.messages.Message; +import com.jwoglom.pumpx2.pump.messages.MessageType; +import com.jwoglom.pumpx2.pump.messages.annotations.MessageProps; +import com.jwoglom.pumpx2.pump.messages.models.KnownApiVersion; +import com.jwoglom.pumpx2.pump.messages.models.SupportedDevices; +import com.jwoglom.pumpx2.pump.messages.request.control.StopTempRateRequest; + +import java.math.BigInteger; + +@MessageProps( + opCode=-89, + size=3, + type=MessageType.RESPONSE, + characteristic=Characteristic.CONTROL, + signed=true, + minApi=KnownApiVersion.MOBI_API_V3_5, + supportedDevices=SupportedDevices.MOBI_ONLY, + request=StopTempRateRequest.class +) +public class StopTempRateResponse extends Message { + + private int bit1; + private int bit2; + private int bit3; + + public StopTempRateResponse() { + } + + public StopTempRateResponse(byte[] raw) { + parse(raw); + } + + public void parse(byte[] raw) { + raw = this.removeSignedRequestHmacBytes(raw); + Preconditions.checkArgument(raw.length == props().size()); + this.cargo = raw; + this.bit1 = raw[0]; + this.bit2 = raw[1]; + this.bit3 = raw[2]; + + } + + public int getBit1() { + return bit1; + } + + public int getBit2() { + return bit2; + } + + public int getBit3() { + return bit3; + } +} \ No newline at end of file diff --git a/messages/src/main/java/com/jwoglom/pumpx2/pump/messages/response/template.j2 b/messages/src/main/java/com/jwoglom/pumpx2/pump/messages/response/template.j2 index 9c558c99..33fe316a 100644 --- a/messages/src/main/java/com/jwoglom/pumpx2/pump/messages/response/template.j2 +++ b/messages/src/main/java/com/jwoglom/pumpx2/pump/messages/response/template.j2 @@ -35,7 +35,7 @@ public class {{responseName}} extends Message { {% endif %}{% endfor %}{% endif %} } - public void parse(byte[] raw) {{% if catUuid == "CONTROL" %} + public void parse(byte[] raw) { {% if catUuid == "CONTROL" %} raw = this.removeSignedRequestHmacBytes(raw);{% endif %} Preconditions.checkArgument(raw.length == props().size()); this.cargo = raw; diff --git a/messages/src/test/java/com/jwoglom/pumpx2/pump/messages/request/control/SetTempRateRequestTest.java b/messages/src/test/java/com/jwoglom/pumpx2/pump/messages/request/control/SetTempRateRequestTest.java new file mode 100644 index 00000000..bcda7350 --- /dev/null +++ b/messages/src/test/java/com/jwoglom/pumpx2/pump/messages/request/control/SetTempRateRequestTest.java @@ -0,0 +1,37 @@ +package com.jwoglom.pumpx2.pump.messages.request.control; + +import static com.jwoglom.pumpx2.pump.messages.MessageTester.assertHexEquals; +import static com.jwoglom.pumpx2.pump.messages.MessageTester.initPumpState; + +import com.jwoglom.pumpx2.pump.messages.MessageTester; +import com.jwoglom.pumpx2.pump.messages.PacketArrayList; +import com.jwoglom.pumpx2.pump.messages.bluetooth.CharacteristicUUID; + +import org.apache.commons.codec.DecoderException; +import org.junit.Test; + +public class SetTempRateRequestTest { + @Test + public void testSetTempRateRequest_95pct_15min() throws DecoderException { + // TimeSinceResetResponse[currentTime=512443560,pumpTimeSinceReset=1906112,cargo={-88,68,-117,30,-64,21,29,0}] + initPumpState(PacketArrayList.IGNORE_INVALID_HMAC, 1906112L); + + // Temp Rate 95% for 15m + SetTempRateRequest expected = new SetTempRateRequest( + new byte[]{-96,-69,13,0,95,0} + ); + + SetTempRateRequest parsedReq = (SetTempRateRequest) MessageTester.test( + // Untitled_2_Live_-_Humans_iPhone 2 + // 2024-03-28T00:26:21.525000+00:00 + "0122a4221ea0bb0d005f001c998b1e37eacb5339", + 34, + 1, + CharacteristicUUID.CONTROL_CHARACTERISTICS, + expected, + "00227c57675fc47f8c9bf5dec1f0d31d42a4b7" + ); + + assertHexEquals(expected.getCargo(), parsedReq.getCargo()); + } +} \ No newline at end of file diff --git a/messages/src/test/java/com/jwoglom/pumpx2/pump/messages/request/control/StopTempRateRequestTest.java b/messages/src/test/java/com/jwoglom/pumpx2/pump/messages/request/control/StopTempRateRequestTest.java new file mode 100644 index 00000000..e92c91a7 --- /dev/null +++ b/messages/src/test/java/com/jwoglom/pumpx2/pump/messages/request/control/StopTempRateRequestTest.java @@ -0,0 +1,34 @@ +package com.jwoglom.pumpx2.pump.messages.request.control; + +import static com.jwoglom.pumpx2.pump.messages.MessageTester.assertHexEquals; +import static com.jwoglom.pumpx2.pump.messages.MessageTester.initPumpState; + +import com.jwoglom.pumpx2.pump.messages.MessageTester; +import com.jwoglom.pumpx2.pump.messages.PacketArrayList; +import com.jwoglom.pumpx2.pump.messages.bluetooth.CharacteristicUUID; +import com.jwoglom.pumpx2.pump.messages.request.control.StopTempRateRequest; + +import org.apache.commons.codec.DecoderException; +import org.junit.Test; + +public class StopTempRateRequestTest { + @Test + public void testStopTempRateRequest() throws DecoderException { + // TimeSinceResetResponse[currentTime=512443560,pumpTimeSinceReset=1906112,cargo={-88,68,-117,30,-64,21,29,0}] + initPumpState(PacketArrayList.IGNORE_INVALID_HMAC, 1906112L); + + // empty cargo + StopTempRateRequest expected = new StopTempRateRequest(); + + StopTempRateRequest parsedReq = (StopTempRateRequest) MessageTester.test( + "012ca62c182c998b1e92605660ce66863620411d", + 44, + 2, + CharacteristicUUID.CONTROL_CHARACTERISTICS, + expected, + "002c0d420615066cb0f317766c" + ); + + assertHexEquals(expected.getCargo(), parsedReq.getCargo()); + } +} \ No newline at end of file diff --git a/messages/src/test/java/com/jwoglom/pumpx2/pump/messages/request/template.j2 b/messages/src/test/java/com/jwoglom/pumpx2/pump/messages/request/template.j2 index c566af54..35300551 100644 --- a/messages/src/test/java/com/jwoglom/pumpx2/pump/messages/request/template.j2 +++ b/messages/src/test/java/com/jwoglom/pumpx2/pump/messages/request/template.j2 @@ -19,7 +19,7 @@ public class {{requestName}}Test { "xxxx", 3, 1, - CharacteristicUUID.CURRENT_STATUS_CHARACTERISTICS, + CharacteristicUUID.{{catUuid}}_CHARACTERISTICS, expected ); diff --git a/messages/src/test/java/com/jwoglom/pumpx2/pump/messages/response/control/SetTempRateResponseTest.java b/messages/src/test/java/com/jwoglom/pumpx2/pump/messages/response/control/SetTempRateResponseTest.java new file mode 100644 index 00000000..161e711e --- /dev/null +++ b/messages/src/test/java/com/jwoglom/pumpx2/pump/messages/response/control/SetTempRateResponseTest.java @@ -0,0 +1,31 @@ +package com.jwoglom.pumpx2.pump.messages.response.control; + +import static com.jwoglom.pumpx2.pump.messages.MessageTester.assertHexEquals; +import static com.jwoglom.pumpx2.pump.messages.MessageTester.initPumpState; + +import com.jwoglom.pumpx2.pump.messages.MessageTester; +import com.jwoglom.pumpx2.pump.messages.bluetooth.CharacteristicUUID; + +import org.apache.commons.codec.DecoderException; +import org.junit.Test; + +public class SetTempRateResponseTest { + @Test + public void testSetTempRateResponse() throws DecoderException { + initPumpState("authenticationKey", 0L); + + SetTempRateResponse expected = new SetTempRateResponse( + // byte[] raw + ); + + SetTempRateResponse parsedRes = (SetTempRateResponse) MessageTester.test( + "xxxx", + 3, + 1, + CharacteristicUUID.CONTROL_CHARACTERISTICS, + expected + ); + + assertHexEquals(expected.getCargo(), parsedRes.getCargo()); + } +} \ No newline at end of file diff --git a/messages/src/test/java/com/jwoglom/pumpx2/pump/messages/response/control/StopTempRateResponseTest.java b/messages/src/test/java/com/jwoglom/pumpx2/pump/messages/response/control/StopTempRateResponseTest.java new file mode 100644 index 00000000..501b5dc4 --- /dev/null +++ b/messages/src/test/java/com/jwoglom/pumpx2/pump/messages/response/control/StopTempRateResponseTest.java @@ -0,0 +1,33 @@ +package com.jwoglom.pumpx2.pump.messages.response.control; + +import static com.jwoglom.pumpx2.pump.messages.MessageTester.assertHexEquals; +import static com.jwoglom.pumpx2.pump.messages.MessageTester.initPumpState; + +import com.jwoglom.pumpx2.pump.messages.MessageTester; +import com.jwoglom.pumpx2.pump.messages.PacketArrayList; +import com.jwoglom.pumpx2.pump.messages.bluetooth.CharacteristicUUID; + +import org.apache.commons.codec.DecoderException; +import org.junit.Test; + +public class StopTempRateResponseTest { + @Test + public void testStopTempRateResponse() throws DecoderException { + // TimeSinceResetResponse[currentTime=512443560,pumpTimeSinceReset=1906112,cargo={-88,68,-117,30,-64,21,29,0}] + initPumpState(PacketArrayList.IGNORE_INVALID_HMAC, 1906112L); + + StopTempRateResponse expected = new StopTempRateResponse( + new byte[]{0, 9, 0} + ); + + StopTempRateResponse parsedRes = (StopTempRateResponse) MessageTester.test( + "002ca72c1b000900d9448b1ea1dcb10f6cd0a00465d9091bad121938e17e51d4c3c9", + 44, + 1, + CharacteristicUUID.CONTROL_CHARACTERISTICS, + expected + ); + + assertHexEquals(expected.getCargo(), parsedRes.getCargo()); + } +} \ No newline at end of file