From 5a799812428f1a3dde39aee4d604e9187f23d522 Mon Sep 17 00:00:00 2001 From: Markus Heberling Date: Sat, 10 Jun 2023 19:52:35 +0200 Subject: [PATCH] added battery heater --- ASN.1 schema/v3_0/ApplicationData.asn1 | 10 +++ .../ismart/mqtt/MqttGatewayTopics.java | 1 + .../heberling/ismart/mqtt/VehicleHandler.java | 80 +++++++++++++++++++ .../heberling/ismart/mqtt/VehicleState.java | 7 ++ 4 files changed, 98 insertions(+) diff --git a/ASN.1 schema/v3_0/ApplicationData.asn1 b/ASN.1 schema/v3_0/ApplicationData.asn1 index de2de0fb..59464716 100644 --- a/ASN.1 schema/v3_0/ApplicationData.asn1 +++ b/ASN.1 schema/v3_0/ApplicationData.asn1 @@ -67,6 +67,16 @@ OTA_ChrgMangDataResp ::= SEQUENCE chargeStatus RvsChargingStatus(1), bmsAdpPubChrgSttnDspCmd INTEGER(0..255) } +OTA_ChrgHeatReq ::= SEQUENCE +{ + ptcHeatReq INTEGER(0..255) +} +OTA_ChrgHeatResp ::= SEQUENCE +{ + ptcHeatReqDspCmd INTEGER(0..255), + ptcHeatResp INTEGER(0..255), + rvcReqSts OCTET STRING(SIZE(1)) +} RvsChargingStatus ::= SEQUENCE { realtimePower INTEGER(0..65535), diff --git a/saic-java-mqtt-gateway/src/main/java/net/heberling/ismart/mqtt/MqttGatewayTopics.java b/saic-java-mqtt-gateway/src/main/java/net/heberling/ismart/mqtt/MqttGatewayTopics.java index 80ebd54e..34f14a10 100644 --- a/saic-java-mqtt-gateway/src/main/java/net/heberling/ismart/mqtt/MqttGatewayTopics.java +++ b/saic-java-mqtt-gateway/src/main/java/net/heberling/ismart/mqtt/MqttGatewayTopics.java @@ -22,6 +22,7 @@ public class MqttGatewayTopics { public static final String DRIVETRAIN_CHARGING_TYPE = DRIVETRAIN + "/chargingType"; public static final String DRIVETRAIN_CURRENT = DRIVETRAIN + "/current"; public static final String DRIVETRAIN_HV_BATTERY_ACTIVE = DRIVETRAIN + "/hvBatteryActive"; + public static final String DRIVETRAIN_HV_BATTERY_HEATING = DRIVETRAIN + "/hvBatteryHeating"; public static final String DRIVETRAIN_MILEAGE = DRIVETRAIN + "/mileage"; public static final String DRIVETRAIN_POWER = DRIVETRAIN + "/power"; public static final String DRIVETRAIN_RANGE = DRIVETRAIN + "/range"; diff --git a/saic-java-mqtt-gateway/src/main/java/net/heberling/ismart/mqtt/VehicleHandler.java b/saic-java-mqtt-gateway/src/main/java/net/heberling/ismart/mqtt/VehicleHandler.java index 396cb238..3ceb77d6 100644 --- a/saic-java-mqtt-gateway/src/main/java/net/heberling/ismart/mqtt/VehicleHandler.java +++ b/saic-java-mqtt-gateway/src/main/java/net/heberling/ismart/mqtt/VehicleHandler.java @@ -23,6 +23,8 @@ import net.heberling.ismart.asn1.v3_0.Message; import net.heberling.ismart.asn1.v3_0.entity.OTA_ChrgCtrlReq; import net.heberling.ismart.asn1.v3_0.entity.OTA_ChrgCtrlStsResp; +import net.heberling.ismart.asn1.v3_0.entity.OTA_ChrgHeatReq; +import net.heberling.ismart.asn1.v3_0.entity.OTA_ChrgHeatResp; import net.heberling.ismart.asn1.v3_0.entity.OTA_ChrgMangDataResp; import org.bn.coders.IASN1PreparedElement; import org.eclipse.paho.client.mqttv3.IMqttClient; @@ -431,6 +433,72 @@ private void sendCharging(boolean state) SaicMqttGateway.anonymized(otaRvcStatus25857MessageCoder, sendCommandReqestMessage))); } + private void sendChargeHeating(boolean state) + throws URISyntaxException, + ExecutionException, + InterruptedException, + TimeoutException, + MqttException, + IOException { + net.heberling.ismart.asn1.v3_0.MessageCoder otaRvcReqMessageCoder = + new net.heberling.ismart.asn1.v3_0.MessageCoder<>(OTA_ChrgHeatReq.class); + + // we send a command end expect the car to wake up + vehicleState.notifyCarActivityTime(OffsetDateTime.now(), false); + + OTA_ChrgHeatReq req = new OTA_ChrgHeatReq(); + req.setPtcHeatReq(state ? 1 : 2); + + Message sendCommandRequest = + otaRvcReqMessageCoder.initializeMessage(uid, token, vinInfo.getVin(), "516", 768, 9, req); + + String sendCommandRequestMessage = otaRvcReqMessageCoder.encodeRequest(sendCommandRequest); + + String sendCommandResponseMessage = + Client.sendRequest(saicUri.resolve("/TAP.Web/ota.mpv30"), sendCommandRequestMessage); + + final net.heberling.ismart.asn1.v3_0.MessageCoder + otaRvcStatus25857MessageCoder = + new net.heberling.ismart.asn1.v3_0.MessageCoder<>(OTA_ChrgHeatResp.class); + net.heberling.ismart.asn1.v3_0.Message sendCommandReqestMessage = + otaRvcStatus25857MessageCoder.decodeResponse(sendCommandResponseMessage); + + // ... use that to request the data again, until we have it + // TODO: check for real errors (result!=0 and/or errorMessagePresent) + while (sendCommandReqestMessage.getApplicationData() == null) { + if (sendCommandReqestMessage.getBody().isErrorMessagePresent()) { + if (sendCommandReqestMessage.getBody().getResult() == 2) { + // TODO: + // getBridgeHandler().relogin(); + } + throw new TimeoutException( + new String(sendCommandReqestMessage.getBody().getErrorMessage())); + } + SaicMqttGateway.fillReserved(sendCommandRequest.getReserved()); + + if (sendCommandReqestMessage.getBody().getResult() == 0) { + // we get an eventId back... + sendCommandRequest.getBody().setEventID(sendCommandReqestMessage.getBody().getEventID()); + } else { + // try a fresh eventId + sendCommandRequest.getBody().setEventID(0); + } + + sendCommandRequestMessage = otaRvcReqMessageCoder.encodeRequest(sendCommandRequest); + + sendCommandResponseMessage = + Client.sendRequest(saicUri.resolve("/TAP.Web/ota.mpv30"), sendCommandRequestMessage); + + sendCommandReqestMessage = + otaRvcStatus25857MessageCoder.decodeResponse(sendCommandResponseMessage); + } + + LOGGER.debug( + "Got SendCommand Response message: {}", + SaicMqttGateway.toJSON( + SaicMqttGateway.anonymized(otaRvcStatus25857MessageCoder, sendCommandReqestMessage))); + } + public void handleMQTTCommand(String topic, MqttMessage message) throws MqttException { try { if (message.isRetained()) { @@ -449,6 +517,18 @@ public void handleMQTTCommand(String topic, MqttMessage message) throws MqttExce throw new MqttGatewayException("Unsupported payload " + message); } break; + case DRIVETRAIN_HV_BATTERY_HEATING: + switch (message.toString().toLowerCase()) { + case "true": + sendChargeHeating(true); + break; + case "false": + sendChargeHeating(false); + break; + default: + throw new MqttGatewayException("Unsupported payload " + message); + } + break; case DRIVETRAIN_CHARGING: switch (message.toString().toLowerCase()) { case "true": diff --git a/saic-java-mqtt-gateway/src/main/java/net/heberling/ismart/mqtt/VehicleState.java b/saic-java-mqtt-gateway/src/main/java/net/heberling/ismart/mqtt/VehicleState.java index 83596022..b8e00fad 100644 --- a/saic-java-mqtt-gateway/src/main/java/net/heberling/ismart/mqtt/VehicleState.java +++ b/saic-java-mqtt-gateway/src/main/java/net/heberling/ismart/mqtt/VehicleState.java @@ -425,6 +425,13 @@ public void handleChargeStatusMessage( msg.setRetained(true); client.publish(mqttVINPrefix + "/" + DRIVETRAIN_VOLTAGE, msg); + boolean batteryHeating = + chargingStatusResponseMessage.getApplicationData().getBmsPTCHeatReqDspCmd() == 1; + msg = new MqttMessage((String.valueOf(batteryHeating)).getBytes(StandardCharsets.UTF_8)); + msg.setQos(0); + msg.setRetained(true); + client.publish(mqttVINPrefix + "/" + DRIVETRAIN_HV_BATTERY_HEATING, msg); + double power = current * voltage / 1000d; msg = new MqttMessage((String.valueOf(power)).getBytes(StandardCharsets.UTF_8)); msg.setQos(0);