package com.openvehicles.OVMS.entities; import android.content.Context; import android.util.Log; import com.google.gson.Gson; import com.openvehicles.OVMS.BaseApp; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStreamReader; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.TimeZone; /** * Created by balzer on 28.03.15. */ public class BatteryData { private static final transient String TAG = "BatteryData"; /** * Note: this is currently tailored to the Twizy battery * which consists of only one pack. For other pack structures * this should be extended as needed. */ static public class PackStatus { public Date timeStamp; public int voltAlert, tempAlert; public float soc, socMin, socMax; public float volt, voltMin, voltMax, voltDevMax; public float temp, tempMin, tempMax, tempDevMax; public long maxDrivePwr, maxRecupPwr; public ArrayList<CellStatus> cells; public boolean isNewSection(PackStatus previous) { return ((previous != null) && (voltMin > previous.voltMin || tempMin > previous.tempMin || socMax < previous.socMax)); } } static public class CellStatus { public int voltAlert, tempAlert; public float volt, voltMin, voltMax, voltDevMax; public float temp, tempMin, tempMax, tempDevMax; } // // System environment: // private transient static final Context context = BaseApp.getApp(); private transient static final Gson gson = new Gson(); // // Storage data: // public String vehicleId; public ArrayList<PackStatus> packHistory; // // Methods // public BatteryData() { vehicleId = ""; packHistory = new ArrayList<PackStatus>(24*60); } public static BatteryData loadFile(String vehicleId) { FileInputStream inputStream; String filename = "batterydata-" + vehicleId + "-default.json"; Log.v(TAG, "loading from file: " + filename); try { inputStream = context.openFileInput(filename); InputStreamReader isr = new InputStreamReader(inputStream); BufferedReader bufferedReader = new BufferedReader(isr); StringBuilder sb = new StringBuilder(); String line; while ((line = bufferedReader.readLine()) != null) { sb.append(line); } String json = sb.toString(); return gson.fromJson(json, BatteryData.class); } catch (Exception e) { e.printStackTrace(); return null; } } public boolean saveFile(String vehicleId) { FileOutputStream outputStream; String filename = "batterydata-" + vehicleId + "-default.json"; Log.v(TAG, "saving to file: " + filename); this.vehicleId = vehicleId; String json = gson.toJson(this); try { outputStream = context.openFileOutput(filename, Context.MODE_PRIVATE); outputStream.write(json.getBytes()); outputStream.close(); return true; } catch (Exception e) { e.printStackTrace(); return false; } } public void processCmdResults(CmdSeries cmdSeries) { int recNr, recCnt; String recType; Date timeStamp; SimpleDateFormat serverTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); serverTime.setTimeZone(TimeZone.getTimeZone("UTC")); PackStatus packStatus = null; ArrayList<CellStatus> cells = null; CellStatus cellStatus; int nrCell, nrPack = 0; for (int i=0; i < cmdSeries.size(); i++) { CmdSeries.Cmd cmd = cmdSeries.get(i); if (cmd.commandCode != 32) continue; // init: if (cmd.command.equals("32,RT-BAT-P")) { packHistory.clear(); } else if (cmd.command.equals("32,RT-BAT-C")) { // check BattPack result: if (packHistory.size() == 0) continue; // "BattCell" only transmits changed cells, so create complete group storage: cells = new ArrayList<CellStatus>(14); for (int j=0; j < 14; j++) { cellStatus = new CellStatus(); cells.add(cellStatus); } // get first pack status: nrPack = 0; packStatus = packHistory.get(0); } for (int resNr=0; resNr < cmd.results.size(); resNr++) { String result[] = cmd.results.get(resNr); if (result[2].equals("No historical data available")) continue; try { recNr = Integer.parseInt(result[2]); recCnt = Integer.parseInt(result[3]); recType = result[4]; timeStamp = serverTime.parse(result[5]); Log.v(TAG, "processing recType " + recType + " entryNr " + recNr + "/" + recCnt); if (recType.equals("RT-BAT-P")) { try { // create record: packStatus = new PackStatus(); packStatus.timeStamp = timeStamp; packStatus.voltAlert = Integer.parseInt(result[7]); packStatus.tempAlert = Integer.parseInt(result[8]); packStatus.soc = (float) Integer.parseInt(result[9]) / 100; packStatus.socMin = (float) Integer.parseInt(result[10]) / 100; packStatus.socMax = (float) Integer.parseInt(result[11]) / 100; packStatus.volt = (float) Integer.parseInt(result[12]) / 10; packStatus.voltMin = (float) Integer.parseInt(result[13]) / 10; packStatus.voltMax = (float) Integer.parseInt(result[14]) / 10; packStatus.temp = Integer.parseInt(result[15]); packStatus.tempMin = Integer.parseInt(result[16]); packStatus.tempMax = Integer.parseInt(result[17]); packStatus.voltDevMax = (float) Integer.parseInt(result[18]) / 100; packStatus.tempDevMax = Integer.parseInt(result[19]); packStatus.maxDrivePwr = Integer.parseInt(result[20]) * 100; packStatus.maxRecupPwr = Integer.parseInt(result[21]) * 100; // store record: packHistory.add(packStatus); } catch (Exception e) { // invalid record: skip Log.e(TAG, "BattPack skip: " + e.getMessage()); } } else if (recType.equals("RT-BAT-C")) { try { nrCell = Integer.parseInt(result[6]); // Pack record(s) complete? // (while handles Pack records without Cell records, // 3000 ms covers server timestamp offsets for cells) while ((timeStamp.getTime() - packStatus.timeStamp.getTime()) > 3000) { // set pack cells: packStatus.cells = new ArrayList<CellStatus>(cells); // get next pack: packStatus = packHistory.get(++nrPack); if (packStatus.timeStamp.compareTo(timeStamp) != 0) { Log.w(TAG, "timeStamp differ: pack=" + packStatus.timeStamp + " / cell=" + timeStamp); } } // create new record: cellStatus = new CellStatus(); cellStatus.voltAlert = Integer.parseInt(result[7]); cellStatus.tempAlert = Integer.parseInt(result[8]); cellStatus.volt = (float) Integer.parseInt(result[9]) / 1000; cellStatus.voltMin = (float) Integer.parseInt(result[10]) / 1000; cellStatus.voltMax = (float) Integer.parseInt(result[11]) / 1000; cellStatus.voltDevMax = (float) Integer.parseInt(result[12]) / 1000; cellStatus.temp = Integer.parseInt(result[13]); cellStatus.tempMin = Integer.parseInt(result[14]); cellStatus.tempMax = Integer.parseInt(result[15]); cellStatus.tempDevMax = Integer.parseInt(result[16]); // store record: cells.set(nrCell-1, cellStatus); } catch (Exception e) { // invalid record: skip Log.e(TAG, "BattCell skip: " + e.getMessage()); } } } catch (Exception e) { // most probably parse error, skip row e.printStackTrace(); } } // no more results: finish if (cmd.command.equals("32,RT-BAT-C")) { try { // set last cell collection into remaining pack records: while (nrPack < packHistory.size()) { packStatus = packHistory.get(nrPack++); packStatus.cells = new ArrayList<CellStatus>(cells); } } catch (Exception e) { Log.e(TAG, "BattCell finish error: " + e.getMessage()); } } } Log.v(TAG, "processCmdResults done"); } }