├── .gitattributes ├── .gitignore ├── 6f2.py ├── README.md ├── bms.py ├── dcdc.py ├── fps.py ├── logger.py ├── logger_spc.py └── thc.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | 7 | # Standard to msysgit 8 | *.doc diff=astextplain 9 | *.DOC diff=astextplain 10 | *.docx diff=astextplain 11 | *.DOCX diff=astextplain 12 | *.dot diff=astextplain 13 | *.DOT diff=astextplain 14 | *.pdf diff=astextplain 15 | *.PDF diff=astextplain 16 | *.rtf diff=astextplain 17 | *.RTF diff=astextplain 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Windows image file caches 2 | Thumbs.db 3 | ehthumbs.db 4 | 5 | # Folder config file 6 | Desktop.ini 7 | 8 | # Recycle Bin used on file shares 9 | $RECYCLE.BIN/ 10 | 11 | # Windows Installer files 12 | *.cab 13 | *.msi 14 | *.msm 15 | *.msp 16 | 17 | # Windows shortcuts 18 | *.lnk 19 | 20 | # ========================= 21 | # Operating System Files 22 | # ========================= 23 | 24 | # OSX 25 | # ========================= 26 | 27 | .DS_Store 28 | .AppleDouble 29 | .LSOverride 30 | 31 | # Thumbnails 32 | ._* 33 | 34 | # Files that might appear in the root of a volume 35 | .DocumentRevisions-V100 36 | .fseventsd 37 | .Spotlight-V100 38 | .TemporaryItems 39 | .Trashes 40 | .VolumeIcon.icns 41 | 42 | # Directories potentially created on remote AFP share 43 | .AppleDB 44 | .AppleDesktop 45 | Network Trash Folder 46 | Temporary Items 47 | .apdisk 48 | -------------------------------------------------------------------------------- /6f2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import can 4 | import os 5 | 6 | #Global Variables 7 | frame_counter = 0 8 | MAX_NUMBER_OF_FRAMES = 6000 9 | 10 | print('Content-type: text/html\n\n') 11 | 12 | os.system("sudo /sbin/ip link set can0 up type can bitrate 500000") 13 | dev = can.interface.Bus(channel='can0', bustype='socketcan_native') 14 | 15 | volts = [] 16 | temp = [] 17 | 18 | #Run through the capture loop until the maximum number of frames is reached 19 | while frame_counter <= MAX_NUMBER_OF_FRAMES: 20 | frame_counter = frame_counter + 1 21 | message = dev.recv() 22 | 23 | #ID6F2 24 | if message.arbitration_id == 1778: 25 | if message.data[0] == 0 or len(volts) != 0: 26 | d1 = (message.data[1] | ((message.data[2] & 0x03F)<<8)) 27 | d2 = ((message.data[2]>>6) | ((message.data[3]<<2) | ((message.data[4] & 0xF)<<10))) 28 | d3 = ((message.data[4]>>4) | ((message.data[5]<<4) | ((message.data[6] & 3)<<12))) 29 | d4 = ((message.data[6]>>2) | ((message.data[7])<<6)) 30 | if message.data[0] < 24: 31 | volts.append(round(d1 * 0.000305, 3)) 32 | volts.append(round(d2 * 0.000305, 3)) 33 | volts.append(round(d3 * 0.000305, 3)) 34 | volts.append(round(d4 * 0.000305, 3)) 35 | else: 36 | temp.append(round(d1 * 0.0122, 3)) 37 | temp.append(round(d2 * 0.0122, 3)) 38 | temp.append(round(d3 * 0.0122, 3)) 39 | temp.append(round(d4 * 0.0122, 3)) 40 | if message.data[0] == 31: 41 | break 42 | # i = 0 43 | # while i < len(volts): 44 | # print("Brick " + str(i) + " " + str(volts[i])) 45 | # i += 1 46 | l_volts = len(volts) 47 | l_temp = len(temp) 48 | 49 | i = 0 50 | n = 1 51 | while i < l_volts: 52 | if (i % 6 == 0 and i + 1 != l_volts): 53 | print("
Module " + str(n) + "") 54 | n += 1 55 | print(str(volts[i]) + " V ") 56 | i += 1 57 | print("

Average: " + str(round((sum(volts) / len(volts)), 2))) 58 | print("Min: " + str(min(volts))) 59 | print("Max: " + str(max(volts))) 60 | print("


") 61 | 62 | i = 0 63 | n = 1 64 | while i < l_temp: 65 | if (i % 2 == 0 and i + 1 != l_temp): 66 | print("
Module " + str(n) + "") 67 | n += 1 68 | print(str(temp[i]) + " C ") 69 | i += 1 70 | print("

Average: " + str(round((sum(temp) / len(temp)), 2))) 71 | print("Min: " + str(min(temp))) 72 | print("Max: " + str(max(temp))) 73 | 74 | os.system("sudo /sbin/ip link set can0 down") -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## CAN3 Interfacing a Pi 3 with PiCAN2 2 | 3 | Features several scripts written in python to interface with Model S CAN Bus 3 (powertrain). 4 | I execute these scripts as CGI and output through an Apache HTTP server. -------------------------------------------------------------------------------- /bms.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import can 4 | import os 5 | import time 6 | 7 | #Global Variables 8 | frame_counter = 0 9 | timeout = time.time() + 5 10 | 11 | # battery data 12 | batt_odo = 0 13 | wh_dis_tot = 0 14 | wh_chrg_tot = 0 15 | soc_ui = 0 16 | nom_energy_remain = 0 17 | exp_energy_remain = 0 18 | ideal_energy_remain = 0 19 | nom_packfull_energy = 0 20 | energy_buffer = 0 21 | pack_volt = 0 22 | energy_till_chargedone = 0 23 | maxDischarge = 0 24 | maxRegen = 0 25 | 26 | print('Content-type: text/html\n\n') 27 | 28 | os.system("sudo /sbin/ip link set can0 up type can bitrate 500000") 29 | dev = can.interface.Bus(channel='can0', bustype='socketcan_native') 30 | 31 | while True: 32 | if time.time() > timeout: 33 | break 34 | message = dev.recv() 35 | 36 | #ID382 37 | if message.arbitration_id == 898: 38 | nom_energy_remain = ((message.data[1]>>2) + ((message.data[2] & 0x0F) * 64)) * 0.1 39 | exp_energy_remain = ((message.data[2]>>4) + ((message.data[3] & 0x3F) * 16)) * 0.1 40 | ideal_energy_remain = ((message.data[3]>>6) + ((message.data[4] & 0xFF) * 4)) * 0.1 41 | nom_packfull_energy = (message.data[0] + ((message.data[1] & 0x03)<<8)) * 0.1 42 | # energy_till_chargedone = (message.data[5] + ((message.data[6] & 0x03)<<8)) * 0.1 43 | energy_buffer = ((message.data[6]>>2) + ((message.data[7] & 0x03) * 64)) * 0.1 44 | 45 | #ID302 46 | if message.arbitration_id == 770: 47 | soc_ui = ((message.data[1]>>2) + ((message.data[2] & 0xF)<<6)) / 10 48 | 49 | #ID562 50 | # if message.arbitration_id == 1378: 51 | # batt_odo = (message.data[0] + (message.data[1]<<8) + (message.data[2]<<16) + (message.data[3]<<24))/1000 52 | 53 | #ID102 54 | # if message.arbitration_id == 546: 55 | # pack_volt = '%.2f' %(float((message.data[3]*256.0 + message.data[2])/100.0)) 56 | 57 | #ID 58 | if message.arbitration_id == 258: 59 | pack_volt = (message.data[0] | (message.data[1]<<8))/100 60 | pack_current = (((message.data[2] + ((message.data[3] & 0x3F)<<8)) - ((message.data[3] & 0x40)<<8))-10000)/10 61 | 62 | #ID232 63 | if message.arbitration_id == 562: 64 | maxDischarge = (message.data[2] + (message.data[3]<<8))/100 65 | maxRegen = (message.data[0] + (message.data[1]<<8))/100 66 | 67 | if maxDischarge != 0 and pack_volt != 0 and nom_energy_remain != 0 and soc_ui != 0: 68 | break 69 | 70 | print("Nom Pack Full Energy (kWh): " + str(nom_packfull_energy)) 71 | print("
Nom Energy Remain (kWh): " + str(nom_energy_remain)) 72 | print("
Expected Energy Remain (kWh): " + str(exp_energy_remain)) 73 | print("
Ideal Energy Remain (kWh): " + str(ideal_energy_remain)) 74 | # print("
Energy to Charge Comp (kWh): " + str(energy_till_chargedone)) 75 | print("
Energy buffer (kWh): " + str(energy_buffer)) 76 | print("

SoC UI (%): " + str(soc_ui)) 77 | print("
Max Discharge (kW): " + str(maxDischarge)) 78 | print("
Max Regen (kW): " + str(maxRegen)) 79 | print("
Pack Voltage: " + str(pack_volt)) 80 | print("
Pack Current: " + str(pack_current)) 81 | 82 | os.system("sudo /sbin/ip link set can0 down") -------------------------------------------------------------------------------- /dcdc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import can 4 | import os 5 | 6 | #Global Variables 7 | frame_counter = 0 8 | MAX_NUMBER_OF_FRAMES = 2000 9 | 10 | #DC-to-DC vars 11 | inletTemperature = 0 12 | inputPower = 0 13 | outputCurrent = 0 14 | outputPower = 0 15 | outputVoltage = 0 16 | 17 | print('Content-type: text/html\n\n') 18 | 19 | os.system("sudo /sbin/ip link set can0 up type can bitrate 500000") 20 | dev = can.interface.Bus(channel='can0', bustype='socketcan_native') 21 | 22 | while frame_counter <= MAX_NUMBER_OF_FRAMES: 23 | frame_counter = frame_counter + 1 24 | message = dev.recv() 25 | 26 | #ID0210 27 | if message.arbitration_id == 528: 28 | inputPower = message.data[3] * 16 29 | outputCurrent = message.data[4] 30 | outputVoltage = message.data[5] / 10 31 | inletTemperature = (((message.data[2] - (2 * (message.data[2] & 0x80))) * 0.5) + 40) 32 | outputPower = message.data[4] * (message.data[5] / 10) 33 | 34 | print("Input (W): " + str(inputPower)) 35 | print("
Output (A): " + str(outputCurrent)) 36 | print("
Output (V): " + str(outputVoltage)) 37 | print("
Output (W): " + str(outputPower)) 38 | print("
Temp (C): " + str(inletTemperature)) 39 | 40 | os.system("sudo /sbin/ip link set can0 down") -------------------------------------------------------------------------------- /fps.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | #Global Variables 4 | frame_counter = 0 5 | MAX_NUMBER_OF_FRAMES = 10000 6 | 7 | import RPi.GPIO as GPIO 8 | import can 9 | import time, datetime 10 | import os 11 | 12 | led = 22 13 | GPIO.setmode(GPIO.BCM) 14 | GPIO.setwarnings(False) 15 | GPIO.setup(led,GPIO.OUT) 16 | GPIO.output(led,True) 17 | 18 | # Bring up can0 interface at 500kbps 19 | os.system("sudo /sbin/ip link set can0 up type can bitrate 500000") 20 | dev = can.interface.Bus(channel='can0', bustype='socketcan_native') 21 | 22 | print('Content-type: text/html\n\n') 23 | startTime = datetime.datetime.now() 24 | 25 | while frame_counter <= MAX_NUMBER_OF_FRAMES: 26 | frame_counter = frame_counter + 1 27 | message = dev.recv() 28 | print(str(message.arbitration_id) + "
") 29 | 30 | print ("10,000 frames in " + str(datetime.datetime.now() - startTime)) 31 | 32 | GPIO.output(led,False) 33 | os.system("sudo /sbin/ip link set can0 down") -------------------------------------------------------------------------------- /logger.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # basic logging to file. 3 | 4 | print('Content-type: text/html\n\n') 5 | 6 | #Main Import 7 | import sys 8 | import glob 9 | import time, datetime 10 | import io 11 | import os 12 | import can 13 | 14 | #Logging/Viewing Settings 15 | SHOW_ALL_IDs = False 16 | WRITE_TO_FILE = True 17 | SHOW_REAR_POWER_DATA = True 18 | SHOW_FRNT_POWER_DATA = False 19 | SHOW_BATT_DATA = True 20 | LOGGING_ENABLED = False 21 | FILE_NAME = '' #Defaults to current date and time 22 | 23 | #Global Variables 24 | frame_counter = 0 25 | MAX_NUMBER_OF_FRAMES = 20000 26 | 27 | #Motor/Power Vars 28 | pDiss = 0.0 29 | mechPower = 0.0 30 | statorCurr = 0.0 31 | torqMeas = 0.0 32 | torqEst = 0.0 33 | pedalPos = 0 34 | speedMPH = 0.0 35 | mtrRPM = 0 36 | 37 | #battery data 38 | batt_odo = 0 39 | wh_dis_tot = 0 40 | wh_chrg_tot = 0 41 | soc_ui = 0 42 | nom_energy_remain = 0 43 | exp_energy_remain = 0 44 | ideal_energy_remain = 0 45 | nom_packfull_energy = 0 46 | pack_volt = 0 47 | pack_current = 0 48 | pack_temp = 0 49 | 50 | os.system("sudo /sbin/ip link set can0 up type can bitrate 500000") 51 | dev = can.interface.Bus(channel='can0', bustype='socketcan_native') 52 | 53 | 54 | if WRITE_TO_FILE == True: 55 | if FILE_NAME != '': 56 | st = FILE_NAME 57 | else: 58 | st = datetime.datetime.fromtimestamp(time.time()).strftime('%Y-%m-%d %H.%M.%S') 59 | file_ = open('../log/' + st + '.csv', 'w') 60 | print('New File Opened, now logging data. ') 61 | 62 | #Run through the capture loop until the maximum number of frames is reached 63 | while frame_counter <= MAX_NUMBER_OF_FRAMES: 64 | frame_counter = frame_counter + 1 65 | message = dev.recv() 66 | 67 | if SHOW_BATT_DATA == True: 68 | 69 | #ID 302 70 | if message.arbitration_id == 770: 71 | soc_ui = ((message.data[1]>>2) + ((message.data[2] & 0xF)<<6)) / 10 72 | 73 | if message.arbitration_id == 258: 74 | pack_volt = (message.data[0] | (message.data[1]<<8))/100 75 | # pack_current = (((message.data[2] | (message.data[3]<<8)) - ((message.data[2] | (message.data[3]<<8)) & 0x8000))-10000)/10 76 | pack_current = (((message.data[2] + ((message.data[3] & 0x3F)<<8)) - ((message.data[3] & 0x40)<<8))-10000)/10 77 | 78 | if message.arbitration_id == 1778 and message.data[0] > 23: 79 | d1 = (message.data[1] | ((message.data[2] & 0x03F)<<8)) 80 | pack_temp = (d1 * 0.0122) 81 | 82 | if SHOW_REAR_POWER_DATA == True: 83 | if message.arbitration_id == 614: 84 | #All power units in kW 85 | # pDiss = message.data[1] * 125 86 | mechPower = ((message.data[2] + ((message.data[3] & 0x7)<<8))-(512 * (message.data[3] & 0x4))) / 2 87 | statorCurr = message.data[4] + ((message.data[5] & 0x7)<<8) 88 | 89 | if message.arbitration_id == 340: 90 | #Nm 91 | torqMeas = (message.data[5] + ((message.data[6] & 0x1F)<<8)-(512 * (message.data[6] & 0x10))) * 0.25 92 | #percent 93 | pedalPos = (message.data[2] * 0.4) 94 | 95 | #ID116 96 | if message.arbitration_id == 278: 97 | speedMPH = ((message.data[2] + ((message.data[3] & 0xF)<<8))-500) / 20 98 | # torqEst = ((message.data[0] + ((message.data[1] & 0xF)<<8))-(512 * (message.data[1] & 0x8))) / 2 99 | 100 | #ID106 101 | if message.arbitration_id == 262: 102 | mtrRPM = (message.data[4] + (message.data[5]<<8))-(512 * (message.data[5]&0x80)) 103 | 104 | if WRITE_TO_FILE == True: 105 | if frame_counter == 1: 106 | write_data = ("time, msg_id, soc, temp, pedal_pos, pack_volt, pack_current, torque, mechPower, speedMPH\n") 107 | else: 108 | write_data = ("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n" % (time.time(), hex(message.arbitration_id)[2:], soc_ui, pack_temp, pedalPos, pack_volt, pack_current, torqMeas, mechPower, speedMPH)) 109 | file_.write(write_data) 110 | 111 | if WRITE_TO_FILE == True: 112 | file_.close() 113 | print("File " + st + '.csv closed. ') 114 | 115 | os.system("sudo /sbin/ip link set can0 down") 116 | print("Connection Closed") -------------------------------------------------------------------------------- /logger_spc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | # extended period logging to file. 3 | 4 | print('Content-type: text/html\n\n') 5 | 6 | #Main Import 7 | import sys 8 | import glob 9 | import time, datetime 10 | import io 11 | import os 12 | import can 13 | 14 | #Logging/Viewing Settings 15 | SHOW_ALL_IDs = False 16 | WRITE_TO_FILE = True 17 | SHOW_BATT_DATA = True 18 | FILE_NAME = '' #Defaults to current date and time 19 | 20 | #Global Variables 21 | MAX_NUMBER_OF_FRAMES = 6000 22 | loop_counter = 0 23 | SEC_BETWEEN_LOOP = 15 24 | MAX_LOOPS = 165 25 | 26 | #battery data 27 | batt_odo = 0 28 | wh_dis_tot = 0 29 | wh_chrg_tot = 0 30 | soc_ui = 0 31 | nom_energy_remain = 0 32 | exp_energy_remain = 0 33 | ideal_energy_remain = 0 34 | nom_packfull_energy = 0 35 | pack_volt = 0 36 | pack_current = 0 37 | pack_temp = 0 38 | 39 | os.system("sudo /sbin/ip link set can0 up type can bitrate 500000") 40 | dev = can.interface.Bus(channel='can0', bustype='socketcan_native') 41 | 42 | 43 | if WRITE_TO_FILE == True: 44 | if FILE_NAME != '': 45 | st = FILE_NAME 46 | else: 47 | st = datetime.datetime.fromtimestamp(time.time()).strftime('%Y-%m-%d %H.%M.%S') 48 | file_ = open('../log/' + st + '_bat_health.csv', 'w') 49 | print('New File Opened, now logging data. ') 50 | 51 | #Run through the capture loop 52 | def capture(dev, frame_counter, MAX_NUMBER_OF_FRAMES): 53 | volts = [] 54 | temp = [] 55 | 56 | while frame_counter <= MAX_NUMBER_OF_FRAMES: 57 | frame_counter = frame_counter + 1 58 | message = dev.recv() 59 | 60 | if SHOW_BATT_DATA == True: 61 | 62 | #ID 302 63 | if message.arbitration_id == 770: 64 | soc_ui = ((message.data[1]>>2) + ((message.data[2] & 0xF)<<6)) / 10 65 | 66 | if message.arbitration_id == 258: 67 | pack_volt = (message.data[0] | (message.data[1]<<8))/100 68 | # pack_current = (((message.data[2] | (message.data[3]<<8)) - ((message.data[2] | (message.data[3]<<8)) & 0x8000))-10000)/10 69 | pack_current = (((message.data[2] + ((message.data[3] & 0x3F)<<8)) - ((message.data[3] & 0x40)<<8))-10000)/10 70 | 71 | #ID6F2 72 | if message.arbitration_id == 1778: 73 | if message.data[0] == 0 or len(volts) != 0: 74 | d1 = (message.data[1] | ((message.data[2] & 0x03F)<<8)) 75 | d2 = ((message.data[2]>>6) | ((message.data[3]<<2) | ((message.data[4] & 0xF)<<10))) 76 | d3 = ((message.data[4]>>4) | ((message.data[5]<<4) | ((message.data[6] & 3)<<12))) 77 | d4 = ((message.data[6]>>2) | ((message.data[7])<<6)) 78 | if message.data[0] < 24: 79 | volts.append(round(d1 * 0.000305, 3)) 80 | volts.append(round(d2 * 0.000305, 3)) 81 | volts.append(round(d3 * 0.000305, 3)) 82 | volts.append(round(d4 * 0.000305, 3)) 83 | else: 84 | temp.append(round(d1 * 0.0122, 3)) 85 | temp.append(round(d2 * 0.0122, 3)) 86 | temp.append(round(d3 * 0.0122, 3)) 87 | temp.append(round(d4 * 0.0122, 3)) 88 | if message.data[0] == 31: 89 | break 90 | 91 | write_data = ("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s\n" % (time.time(), soc_ui, pack_volt, pack_current, round((sum(temp) / len(temp)), 2), min(temp), max(temp), round((sum(volts) / len(volts)), 2), min(volts), max(volts))) 92 | file_.write(write_data) 93 | 94 | while loop_counter < MAX_LOOPS: 95 | print("
Loop iteration: " + str(loop_counter)) 96 | loop_counter = loop_counter + 1 97 | frame_counter = 0 98 | capture(dev, frame_counter, MAX_NUMBER_OF_FRAMES) 99 | time.sleep(SEC_BETWEEN_LOOP) 100 | 101 | if WRITE_TO_FILE == True: 102 | file_.close() 103 | print("File " + st + '.csv closed. ') 104 | 105 | os.system("sudo /sbin/ip link set can0 down") 106 | print("Connection Closed") -------------------------------------------------------------------------------- /thc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python3 2 | 3 | import can 4 | import os 5 | 6 | #Global Variables 7 | frame_counter = 0 8 | MAX_NUMBER_OF_FRAMES = 2000 9 | 10 | #THC human decode 11 | THC_batteryHeaterState = "Undefined" 12 | heater_state = [] 13 | heater_state.append("Off") 14 | heater_state.append("Startup") 15 | heater_state.append("BAT_IN_HEAT_CK") 16 | heater_state.append("Run") 17 | heater_state.append("Overtemp") 18 | heater_state.append("Suspended") 19 | heater_state.append("Undefined") 20 | heater_state.append("Undefined") 21 | 22 | THC_batteryHeaterTemp = 0 23 | THC_batteryHeaterReq = 0 24 | 25 | THC_totalPowerConsumedHV = 0 26 | THC_totalPowerConsumed12V = 0 27 | THC_HVPowerLimit = 0 28 | THC_limitedBatteryHeater = 0 29 | THC_limitedCompressor = 0 30 | THC_limitedPtcHeater = 0 31 | 32 | print('Content-type: text/html\n\n') 33 | 34 | os.system("sudo /sbin/ip link set can0 up type can bitrate 500000") 35 | dev = can.interface.Bus(channel='can0', bustype='socketcan_native') 36 | 37 | while frame_counter <= MAX_NUMBER_OF_FRAMES: 38 | frame_counter = frame_counter + 1 39 | message = dev.recv() 40 | 41 | #ID26A 42 | if message.arbitration_id == 618: 43 | THC_batteryHeaterTemp = ((message.data[0] + ((message.data[1]&0x7)<<8)) * 0.125) - 40 44 | THC_batteryHeaterReq = (message.data[1] & 0x8)>>3 45 | THC_batteryHeaterState = (message.data[2] & 0x70)>>4 46 | THC_batteryHeaterState_Human = heater_state[THC_batteryHeaterState] 47 | 48 | #ID35A 49 | if message.arbitration_id == 858: 50 | THC_totalPowerConsumedHV = (message.data[2] + (message.data[3]<<8)) 51 | THC_totalPowerConsumed12V = (message.data[4] + ((message.data[5] & 0xF)<<8)) 52 | THC_HVPowerLimit = (message.data[6] + (message.data[7]<<8)) / 100 53 | THC_limitedBatteryHeater = (message.data[5] & 0x10)>>4 54 | THC_limitedCompressor = (message.data[5] & 0x20)>>5 55 | THC_limitedPtcHeater = (message.data[5] & 0x40)>>6 56 | 57 | print("Heater Temp (C): " + str(THC_batteryHeaterTemp)) 58 | print("
Active Heating Target (C): " + str(THC_batteryHeaterReq)) 59 | print("
Heater State: " + THC_batteryHeaterState_Human) 60 | print("
Total consumption HV: " + str(THC_totalPowerConsumedHV)) 61 | print("
Total consumption 12V: " + str(THC_totalPowerConsumed12V)) 62 | print("
HV Power Limit: " + str(THC_HVPowerLimit)) 63 | print("
is limited heating: " + str(THC_limitedBatteryHeater)) 64 | print("
is limited cooling: " + str(THC_limitedCompressor)) 65 | print("
is limited PTC: " + str(THC_limitedPtcHeater)) 66 | 67 | os.system("sudo /sbin/ip link set can0 down") --------------------------------------------------------------------------------