public Parser(MainActivity mainActivity, CustomAdapter adapter) { this.adapter = adapter; this.mainActivity = mainActivity; items = new ConcurrentDictionary <string, ListElement>(); packets = new SortedList <int, Packet>(); time = SystemClock.ElapsedRealtime() + 1000; /* tags: * p: performance * t: trip * b: battery * c: temperature * f: front drive unit * s: startup (app will wait until these packets are found before starting 'normal' mode) * i: imperial * m: metric * i: ignore (in trip tabs, with slow/ELM adapters) * z: BMS * x: Cells * e: efficiency */ Packet p; /*packets.Add(0x256, p = new Packet(0x256, this)); * p.AddValue("Metric", "bool", "s", (bytes) => { * metric = Convert.ToBoolean(bytes[3] & 0x80); * if (metric) { * foreach (var packet in packets) * foreach (var v in packet.Value.values) * if (v.tag.Contains("i")) * packet.Value.values.Remove(v); * } else { * foreach (var packet in packets) * foreach (var v in packet.Value.values) * if (v.tag.Contains("m")) * packet.Value.values.Remove(v); * } * return metric ? 1 : 0; * });*/ packets.Add(0x102, p = new Packet(0x102, this)); p.AddValue("Battery voltage", " V", "bpr", (bytes) => volt = bytes.Count() >= 6 ? (bytes[0] + (bytes[1] << 8)) / 100.0 : bytes[100]); // deliberately throws outofrangeexception if bytes.Count()<=4 p.AddValue("Battery current", " A", "b", (bytes) => amp = bytes.Count() < 9 ? 1000 - ((Int16)((((bytes[3] & 0x7F) << 8) + bytes[2]) << 1)) / 20.0 : bytes[100]); p.AddValue("Battery power", " kW", "bpe", (bytes) => power = amp * volt / 1000.0); //p.AddValue("cell average", "Vc", "bp", (bytes) => numCells > 70 ? volt / numCells : bytes[100]); //p.AddValue("negative terminal", "C", (bytes) => ((bytes[6] + ((bytes[7] & 0x07) << 8))) * 0.1 - 10); packets.Add(0x210, p = new Packet(0x210, this)); p.AddValue("DC-DC current", "A12", "b", (bytes) => bytes[4]); p.AddValue("DC-DC voltage", "V12", "b", (bytes) => bytes[5] / 10.0); p.AddValue("DC-DC coolant inlet", "C", "c", (bytes) => ((bytes[2] - (2 * (bytes[2] & 0x80))) * 0.5) + 40); p.AddValue("DC-DC input power", "W", "b", (bytes) => dcIn = (bytes[3] * 16)); p.AddValue("12v systems", "W", "e", (bytes) => dcIn = (bytes[3] * 16)); p.AddValue("DC-DC output power", "W", "b", (bytes) => dcOut = (bytes[4] * bytes[5] / 10.0)); p.AddValue("DC-DC efficiency", "%", "e", (bytes) => dcOut / dcIn * 100.0); p.AddValue("400V systems", " kW", "e", (bytes) => power - dcIn / 1000.0); p.AddValue("Heating/cooling", "kW", "eh", (bytes) => { if (dissipationUpdated || SystemClock.ElapsedRealtime() > dissipationTimeStamp + 2000) { hvacPower = (power - (rInput + fInput) - (dcIn / 1000.0)); dissipationUpdated = false; return(hvacPower); } else { return(bytes[100]); } }, new int[] { 0x102, 0x266, 0x2E5 }); packets.Add(0x1D4, p = new Packet(0x1D4, this)); p.AddValue("Fr torque measured", "Nm", "pf", (bytes) => frTorque = (bytes[5] + ((bytes[6] & 0x1F) << 8) - (512 * (bytes[6] & 0x10))) * 0.25); p.AddValue("Rr/Fr torque bias", "%", "pf", (bytes) => Math.Abs(frTorque) > Math.Abs(torque) ? 0 : Math.Abs(torque) / (Math.Abs(frTorque) + Math.Abs(torque)) * 100); packets.Add(0x154, p = new Packet(0x154, this)); p.AddValue("Rr torque measured", "Nm", "p", (bytes) => torque = (bytes[5] + ((bytes[6] & 0x1F) << 8) - (512 * (bytes[6] & 0x10))) * 0.25); //p.AddValue("Pedal position A", "%", "", (bytes) => bytes[2] * 0.4); p.AddValue("Watt pedal", "%", "i", (bytes) => bytes[3] * 0.4); /*p.AddValue("HP 'measured'", "HP", "p", * (bytes) => (torque * rpm / 9549 * kw_to_hp));*/ packets.Add(0x2E5, p = new Packet(0x2E5, this)); p.AddValue("Fr mech power", " kW", "f", (bytes) => fMechPower = ((bytes[2] + ((bytes[3] & 0x7) << 8)) - (512 * (bytes[3] & 0x4))) / 2.0); p.AddValue("Fr dissipation", " kW", "f", (bytes) => fDissipation = bytes[1] * 125.0 / 1000.0 - 0.5); p.AddValue("Fr input power", " kW", "", (bytes) => fInput = fMechPower + fDissipation); p.AddValue("Fr mech power HP", "HP", "pf", (bytes) => fMechPower * kw_to_hp); p.AddValue("Fr stator current", "A", "f", (bytes) => bytes[4] + ((bytes[5] & 0x7) << 8)); p.AddValue("Fr drive power max", " kW", "b", (bytes) => drivePowerMax = (((bytes[6] & 0x3F) << 5) + ((bytes[5] & 0xF0) >> 3)) + 1); p.AddValue("Mech power combined", " kW", "f", (bytes) => combinedMechPower = mechPower + fMechPower, new int[] { 0x266 }); p.AddValue("HP combined", "HP", "pf", (bytes) => (mechPower + fMechPower) * kw_to_hp, new int[] { 0x266 }); p.AddValue("Fr efficiency", "%", "e", (bytes) => fDissipation > 0.0 ? Math.Abs(fMechPower) / (Math.Abs(fMechPower) + fDissipation + 0.5) * 100.0 : bytes[100]); //p.AddValue("Fr+Rr efficiency", "%", "e", (bytes) => Math.Abs(mechPower+fMechPower) / (Math.Abs(mechPower+fMechPower) + fDissipation + rDissipation) * 100.0); packets.Add(0x266, p = new Packet(0x266, this)); p.AddValue("Rr inverter 12V", "V12", "", (bytes) => bytes[0] / 10.0); p.AddValue("Rr mech power", " kW", "", (bytes) => mechPower = ((bytes[2] + ((bytes[3] & 0x7) << 8)) - (512 * (bytes[3] & 0x4))) / 2.0); p.AddValue("Rr dissipation", " kW", "", (bytes) => { rDissipation = bytes[1] * 125.0 / 1000.0 - 0.5; dissipationUpdated = true; dissipationTimeStamp = Android.OS.SystemClock.ElapsedRealtime(); return(rDissipation); }); p.AddValue("Rr input power", " kW", "", (bytes) => rInput = mechPower + rDissipation); p.AddValue("Propulsion", " kW", "e", (bytes) => rInput + fInput); p.AddValue("Rr mech power HP", "HP", "p", (bytes) => mechPower * kw_to_hp); p.AddValue("Rr stator current", "A", "", (bytes) => bytes[4] + ((bytes[5] & 0x7) << 8)); p.AddValue("Rr regen power max", "KW", "b", (bytes) => (bytes[7] * 4) - 200); p.AddValue("Rr drive power max", "KW", "b", (bytes) => drivePowerMax = (((bytes[6] & 0x3F) << 5) + ((bytes[5] & 0xF0) >> 3)) + 1); p.AddValue("Rr efficiency", "%", "e", (bytes) => rDissipation > 0.0 ? Math.Abs(mechPower) / (Math.Abs(mechPower) + rDissipation + 0.5) * 100.0 : bytes[100]); //p.AddValue("Non-propulsive", "kW", "e", (bytes) => power - (rInput+fInput)); /*p.AddValue("Car efficiency", "%", "e", (bytes) => { * //if (Math.Abs(mechPower + fMechPower) > Math.Abs(power)) * //return 100.0; * //if Math.Abs(mechPower + fMechPower) < Math.Abs(power) * //return 0.0;*/ /*return Math.Abs(mechPower + fMechPower) / Math.Abs(power) * 100.0; * });*/ packets.Add(0x145, p = new Packet(0x145, this)); p.AddValue("Fr torque estimate", "Nm", "f", (bytes) => ((bytes[0] + ((bytes[1] & 0xF) << 8)) - (512 * (bytes[1] & 0x8))) / 2); packets.Add(0x116, p = new Packet(0x116, this)); p.AddValue("Rr torque estimate", "Nm", "", (bytes) => ((bytes[0] + ((bytes[1] & 0xF) << 8)) - (512 * (bytes[1] & 0x8))) / 2); p.AddValue("Speed", "km|h", "e", (bytes) => speed = ((bytes[2] + ((bytes[3] & 0xF) << 8)) - 500) / 20.0 * miles_to_km); p.AddValue("Consumption", "wh|km", "p", (bytes) => power / speed * 1000, new int[] { 0x102 }); packets.Add(0x306, p = new Packet(0x306, this)); p.AddValue("Rr coolant inlet", "C", "c", (bytes) => bytes[5] == 0 ? bytes[100] : bytes[5] - 40); p.AddValue("Rr inverter PCB", "C", "", (bytes) => bytes[0] - 40); p.AddValue("Rr stator", "C", "cp", (bytes) => bytes[2] - 40); p.AddValue("Rr DC capacitor", "C", "", (bytes) => bytes[3] - 40); p.AddValue("Rr heat sink", "C", "c", (bytes) => bytes[4] - 40); p.AddValue("Rr inverter", "C", "c", (bytes) => bytes[1] - 40); packets.Add(0x382, p = new Packet(0x382, this)); p.AddValue("Nominal full pack", "kWh", "br", (bytes) => nominalFullPackEnergy = (bytes[0] + ((bytes[1] & 0x03) << 8)) * 0.1); p.AddValue("Nominal remaining", "kWh", "br", (bytes) => nominalRemaining = ((bytes[1] >> 2) + ((bytes[2] & 0x0F) * 64)) * 0.1); p.AddValue("Expected remaining", "kWh", "r", (bytes) => ((bytes[2] >> 4) + ((bytes[3] & 0x3F) * 16)) * 0.1); p.AddValue("Ideal remaining", "kWh", "r", (bytes) => ((bytes[3] >> 6) + ((bytes[4] & 0xFF) * 4)) * 0.1); p.AddValue("To charge complete", "kWh", "", (bytes) => (bytes[5] + ((bytes[6] & 0x03) << 8)) * 0.1); p.AddValue("Energy buffer", "kWh", "br", (bytes) => buffer = ((bytes[6] >> 2) + ((bytes[7] & 0x03) * 64)) * 0.1); //p.AddValue("SOC nominal", "%", "br", (bytes) => nominalRemaining / nominalFullPackEnergy * 100.0); p.AddValue("SOC", "%", "br", (bytes) => soc = (nominalRemaining - buffer) / (nominalFullPackEnergy - buffer) * 100.0); p.AddValue("Usable full pack", "kWh", "br", (bytes) => (nominalFullPackEnergy - buffer)); p.AddValue("Usable remaining", "kWh", "br", (bytes) => (nominalRemaining - buffer)); packets.Add(0x302, p = new Packet(0x302, this)); //p.AddValue("SOC Min", "%", "br", (bytes) => (bytes[0] + ((bytes[1] & 0x3) << 8)) / 10.0); //p.AddValue("SOC UI", "%", "br", (bytes) => ((bytes[1] >> 2) + ((bytes[2] & 0xF) << 6)) / 10.0); p.AddValue("DC Charge total", "kWH", "bs", (bytes) => { if (bytes[2] >> 4 == 0) { dcChargeTotal = (bytes[4] + (bytes[5] << 8) + (bytes[6] << 16) + (bytes[7] << 24)) / 1000.0; if (mainActivity.currentTab.trip.dcChargeStart == 0) { mainActivity.currentTab.trip.dcChargeStart = dcChargeTotal; } dcCharge = dcChargeTotal - mainActivity.currentTab.trip.dcChargeStart; return(dcChargeTotal); } else { return(bytes[100]); } }); p.AddValue("AC Charge total", "kWH", "bs", (bytes) => { if (bytes[2] >> 4 == 1) { acChargeTotal = (bytes[4] + (bytes[5] << 8) + (bytes[6] << 16) + (bytes[7] << 24)) / 1000.0; if (mainActivity.currentTab.trip.acChargeStart == 0) { mainActivity.currentTab.trip.acChargeStart = acChargeTotal; } acCharge = acChargeTotal - mainActivity.currentTab.trip.acChargeStart; return(acChargeTotal); } else { return(bytes[100]); } }); p.AddValue("DC Charge", "kWh", "ti", (bytes) => dcChargeTotal - mainActivity.currentTab.trip.dcChargeStart); p.AddValue("AC Charge", "kWh", "ti", (bytes) => acChargeTotal - mainActivity.currentTab.trip.acChargeStart); packets.Add(0x3D2, p = new Packet(0x3D2, this)); p.AddValue("Charge total", "kWH", "bs", (bytes) => { chargeTotal = (bytes[0] + (bytes[1] << 8) + (bytes[2] << 16) + (bytes[3] << 24)) / 1000.0; if (mainActivity.currentTab.trip.chargeStart == 0) { mainActivity.currentTab.trip.chargeStart = chargeTotal; } charge = chargeTotal - mainActivity.currentTab.trip.chargeStart; return(chargeTotal); }); p.AddValue("Discharge total", "kWH", "b", (bytes) => { dischargeTotal = (bytes[4] + (bytes[5] << 8) + (bytes[6] << 16) + (bytes[7] << 24)) / 1000.0; if (mainActivity.currentTab.trip.dischargeStart == 0) { mainActivity.currentTab.trip.dischargeStart = dischargeTotal; } discharge = dischargeTotal - mainActivity.currentTab.trip.dischargeStart; return(dischargeTotal); }); p.AddValue("Regenerated", "kWh", "tr", (bytes) => regen = charge - acCharge - dcCharge); p.AddValue("Energy", "kWh", "tr", (bytes) => energy = discharge - regen); p.AddValue("Discharge", "kWh", "r", (bytes) => discharge); p.AddValue("Charge", "kWh", "r", (bytes) => charge); p.AddValue("Regen total", "kWH", "b", (bytes) => regenTotal = chargeTotal - acChargeTotal - dcChargeTotal, new int[] { 0x302 }); p.AddValue("Regen %", "% ", "tr", (bytes) => energy > 0 ? regen / discharge * 100 : bytes[100]);//, //new int[] { 0x302 }); p.AddValue("Discharge cycles", "x", "b", (bytes) => nominalFullPackEnergy > 0 ? dischargeTotal / nominalFullPackEnergy : bytes[100], new int[] { 0x382 }); p.AddValue("Charge cycles", "x", "b", (bytes) => nominalFullPackEnergy > 0 ? chargeTotal / nominalFullPackEnergy : bytes[100], new int[] { 0x382 }); packets.Add(0x562, p = new Packet(0x562, this)); p.AddValue("Odometer", "Km", "b", (bytes) => odometer = (bytes[0] + (bytes[1] << 8) + (bytes[2] << 16) + (bytes[3] << 24)) / 1000.0 * miles_to_km); p.AddValue("Distance", "km", "tsr", (bytes) => { if (mainActivity.currentTab.trip.odometerStart == 0) { mainActivity.currentTab.trip.odometerStart = odometer; } return(tripDistance = odometer - mainActivity.currentTab.trip.odometerStart); }); p.AddValue("Trip consumption", "wh|km", "tr", (bytes) => tripDistance > 0 ? energy / tripDistance * 1000 : bytes[100], new int[] { 0x3D2 }); /*p.AddValue("Lifetime consumption", "wh/km", "bt", * (bytes) => odometer > 0 ? dischargeTotal / odometer * 1000 : bytes[100]);*/ packets.Add(0x115, p = new Packet(0x115, this)); p.AddValue("Fr motor RPM", "RPM", "", (bytes) => frpm = (bytes[4] + (bytes[5] << 8)) - (512 * (bytes[5] & 0x80))); // 0x115 --- DIS_motorRPM = (data[4] + (data[5]<<8)) - (512 * (data[5]&0x80)); packets.Add(0x106, p = new Packet(0x106, this)); p.AddValue("Rr motor RPM", "RPM", "", (bytes) => rrpm = (bytes[4] + (bytes[5] << 8)) - (512 * (bytes[5] & 0x80))); packets.Add(0x232, p = new Packet(0x232, this)); p.AddValue("BMS max discharge", "KW", "b", (bytes) => (bytes[2] + (bytes[3] << 8)) / 100.0); p.AddValue("BMS max charge", "KW", "b", (bytes) => (bytes[0] + (bytes[1] << 8)) / 100.0); packets.Add(0x168, p = new Packet(0x168, this)); p.AddValue("Brake pedal", "%", "", (bytes) => (bytes[0] + (bytes[1] << 8)) - 3239); packets.Add(0x00E, p = new Packet(0x00E, this)); p.AddValue("Steering angle", "deg", "", (bytes) => (((bytes[0] << 8) + bytes[1] - 8200.0) / 10.0)); packets.Add(0x338, p = new Packet(0x338, this)); p.AddValue("Rated range", "km", "br", (bytes) => (bytes[0] + (bytes[1] << 8)) * miles_to_km); p.AddValue("Typical range", "km", "br", (bytes) => (bytes[2] + (bytes[3] << 8)) * miles_to_km); p.AddValue("Full rated range", "km", "br", (bytes) => (bytes[0] + (bytes[1] << 8)) * miles_to_km / (soc == 0.0 ? 100.0 : soc) * 100.0); p.AddValue("Full typical range", "km", "br", (bytes) => (bytes[2] + (bytes[3] << 8)) * miles_to_km / (soc == 0.0 ? 100.0 : soc) * 100.0); packets.Add(0x6F2, p = new Packet(0x6F2, this)); p.AddValue("Last cell block updated", "xb", "", (bytes) => { Int64 data = BitConverter.ToInt64(bytes, 0); if (bytes[0] < 24) { int cell = 0; for (int i = 0; i < 4; i++) { UpdateItem("Cell " + (cell = ((bytes[0]) * 4 + i + 1)).ToString().PadLeft(2) + " voltage" , "zVC" , "z" , (bytes[0]) * 4 + i + 2000 , ((data >> ((14 * i) + 8)) & 0x3FFF) * 0.000305 , 0x6F2); } if (cell > numCells) { numCells = cell; } } else { for (int i = 0; i < 4; i++) { UpdateItem("Cell " + ((bytes[0] - 24) * 4 + i + 1).ToString().PadLeft(2) + " temp" , "zCC" , "c" , ((bytes[0] - 24) * 4 + i) * 4 + 3 + 2000 , ((Int16)(((data >> ((14 * i) + 6)) & 0xFFFC)) * 0.0122 / 4.0) , 0x6F2); } } return(bytes[0]); }); // these are a bit stupid, but they are placeholders for the filters to be generated correctly. p.AddValue("Cell temp min", "C", "bz", null, null, 1001); p.AddValue("Cell temp avg", "C", "bcpz", null, null, 1002); p.AddValue("Cell temp max", "C", "bz", null, null, 1003); p.AddValue("Cell temp diff", "Cd", "bz", null, null, 1004); p.AddValue("Cell min", "Vc", "bz", null, null, 1005); p.AddValue("Cell avg", "Vc", "bprzx", null, null, 1006); p.AddValue("Cell max", "Vc", "bz", null, null, 1007); p.AddValue("Cell diff", "Vcd", "bzx", null, null, 1008); for (int i = 1; i <= 96; i++) { p.AddValue("Cell " + i.ToString().PadLeft(2) + " voltage" , "zVC" , "zx" , null , null , i + 2000); } for (int i = 1; i <= 32; i++) { p.AddValue("Cell " + i.ToString().PadLeft(2) + " temp" , "zCC" , "zc" , null , null , i * 3 + 2000); } /*packets.Add(0x222, p = new Packet(0x222, this)); * p.AddValue("Charge rate", "??", "e", * (bytes) => (bytes[0] + (bytes[1] << 8)) / 100.0); * p.AddValue("Charger volt", "V", "e", * (bytes) => (bytes[2] + (bytes[3] << 8)) / 100.0);*/ packets.Add(0x2A8, p = new Packet(0x2A8, this)); p.AddValue("Front left", "WRPM", "", (bytes) => fl = (bytes[4] + (bytes[3] << 8)) * 0.7371875 / 9.73); p.AddValue("Front right", "WRPM", "", (bytes) => fr = (bytes[6] + (bytes[5] << 8)) * 0.7371875 / 9.73); p.AddValue("Front drive ratio", ":1", "", (bytes) => frpm > 1000 ? frpm / ((fl + fr) / 2) : bytes[100], new int[] { 0x115 }); packets.Add(0x288, p = new Packet(0x288, this)); p.AddValue("Rear left", "WRPM", "", (bytes) => rl = (bytes[4] + (bytes[3] << 8)) * 0.7371875 / 9.73); p.AddValue("Rear right", "WRPM", "", (bytes) => rr = (bytes[7] + (bytes[6] << 8)) * 0.7371875 / 9.73); p.AddValue("Rear drive ratio", ":1", "", (bytes) => rrpm > 1000 ? rrpm / ((rl + rr) / 2) : bytes[100], new int[] { 0x106 }); packets.Add(0x318, p = new Packet(0x318, this)); p.AddValue("Outside temp", " C", "h", (bytes) => (bytes[0] / 2.0 - 40)); p.AddValue("Outside temp filtered", " C", "", (bytes) => (bytes[1] / 2.0 - 40)); p.AddValue("Inside temp", " C", "h", (bytes) => (bytes[2] / 2.0 - 40)); p.AddValue("A/C air temp", " C", "h", (bytes) => (bytes[4] / 2.0 - 40)); //318 - temperaturer. 0, 1, 2, 4: / 2 - 40 = C packets.Add(0x3F8, p = new Packet(0x3F8, this)); p.AddValue("Floor vent L", " C", "h", (bytes) => ((bytes[4] + (bytes[5] << 8)) / 10.0) - 40); p.AddValue("Floor vent R", " C", "h", (bytes) => ((bytes[6] + (bytes[7] << 8)) / 10.0) - 40); p.AddValue("Mid vent L", " C", "h", (bytes) => ((bytes[0] + (bytes[1] << 8)) / 10.0) - 40); p.AddValue("Mid vent R", " C", "h", (bytes) => ((bytes[2] + (bytes[3] << 8)) / 10.0) - 40); //3F8 - as int. tror dette er 4 tempavlesninger evt innblåstemperatur, F / 10->C /*packets.Add(0x388, p = new Packet(0x388, this)); * p.AddValue("Floor L", " C", "h", * (bytes) => (bytes[1] / 2.0 - 20)); * p.AddValue("Floor R", " C", "h", * (bytes) => (bytes[0] / 2.0 - 20)); * p.AddValue("Temp 1", " C", "h", * (bytes) => (bytes[2] / 2.0 - 20)); * p.AddValue("Temp 2", " C", "h", * (bytes) => (bytes[3] / 2.0 - 20)); * p.AddValue("Temp 3", " C", "h", * (bytes) => (bytes[4] / 2.0 - 20)); * p.AddValue("Temp 4", " C", "h", * (bytes) => (bytes[5] / 2.0 - 20));*/ //388 - temperaturer!0 - 1: / 4 = C, 2,3,4,5: / 2 - 40 = C packets.Add(0x308, p = new Packet(0x308, this)); p.AddValue("Louver 1", "b", "h", (bytes) => bytes[0] > 0 ? bytes[0] : bytes[100]); p.AddValue("Louver 2", "b", "h", (bytes) => bytes[1] > 0 ? bytes[1] : bytes[100]); p.AddValue("Louver 3", "b", "h", (bytes) => bytes[2] > 0 ? bytes[2] : bytes[100]); p.AddValue("Louver 4", "b", "h", (bytes) => bytes[3] > 0 ? bytes[3] : bytes[100]); p.AddValue("Louver 5", "b", "h", (bytes) => bytes[4] > 0 ? bytes[4] : bytes[100]); p.AddValue("Louver 6", "b", "h", (bytes) => bytes[5] > 0 ? bytes[5] : bytes[100]); p.AddValue("Louver 7", "b", "h", (bytes) => bytes[6] > 0 ? bytes[6] : bytes[100]); p.AddValue("Louver 8", "b", "h", (bytes) => bytes[7] > 0 ? bytes[7] : bytes[100]); //388 - temperaturer!0 - 1: / 4 = C, 2,3,4,5: / 2 - 40 = C packets.Add(0x2AA, p = new Packet(0x2AA, this)); p.AddValue("HVAC floor", "0", "h", (bytes) => { var set1 = bytes[2] & 0x07; feet = false; seat = false; win = false; switch (set1) { case 1: seat = true; break; case 2: feet = true; seat = true; break; case 3: feet = true; break; case 4: feet = true; win = true; break; case 5: win = true; break; case 6: feet = true; seat = true; win = true; break; case 7: seat = true; win = true; break; } return(feet ? 1 : 0); }); p.AddValue("HVAC mid", "0", "h", (bytes) => seat ? 1 : 0); p.AddValue("HVAC window", "0", "h", (bytes) => win ? 1 : 0); /*p.AddValue("HVAC recycle", "0", "eh", * (bytes) => { * return (bytes[3] & 0x10) >> 4; * }); * p.AddValue("HVAC recycle2", "0", "eh", * (bytes) => { * return (bytes[3] & 0x8) >> 3; * });*/ p.AddValue("HVAC A/C", "0", "h", (bytes) => { var set3 = bytes[4] & 0x01; return(set3); }); p.AddValue("HVAC on/off", "0", "h", (bytes) => (bytes[3] & 0x10) >> 4 == 0 ? 1 : 0); p.AddValue("HVAC fan speed", "X", "h", (bytes) => (bytes[2] & 0xf0) >> 4); p.AddValue("HVAC temp left", " C", "h", (bytes) => bytes[0] / 2.0); p.AddValue("HVAC temp right", " C", "h", (bytes) => bytes[1] / 2.0); }