I show how to collect detailed CAN bus data from a Tesla Model S, and display it in the car's own web browser!
Complete Raspberry Pi with CAN bus shield and 12V buck converter: http://copperhilltech.com/raspberry-pi-3-system-with-can-bus-interface/
Tesla diagnostic connector: https://www.panjo.com/buy/tesla-diagnostic-cable-for-ms-mx-sept-2015-and-up-bare-wire-version-308125
RPi CAN bus tutorial: http://www.cowfishstudios.com/blog/canned-pi-part1
Get node.js installed on the RPi: http://thisdavej.com/beginners-guide-to-installing-node-js-on-a-raspberry-pi/
I used socket.io, which is a module that installs into node.js: https://www.npmjs.com/package/socket.io
Diagnostic connector pinout (scroll through the images):
http://store.evtv.me/proddetail.php?prod=TeslaCANKit
Tesla CAN bus reverse engineering: https://skie.net/skynet/downloads
Basic sequence to setup the server on the Pi:
sudo ip link set can0 type can bitrate 500000 listen-only on
sudo ip link set can0 up
candump -cae can0,0:0,#FFFFFFFF
candump -cae can0,0:0,#FFFFFFFF | grep 106 | awk -Winteractive '{ print $10}' | node app.js
I will post the node.js code on my blog:
Support Applied Science on Patreon:
https://www.patreon.com/AppliedScience
app.js:
var readline = require('readline');
var rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
terminal: false
});
pipedata = '';
rl.on('line', function(line){
console.log(line);
pipedata = line;
});
var http = require('http'),
fs = require('fs'),
// NEVER use a Sync function except at start-up!
index = fs.readFileSync(__dirname + '/index.html');
// Send index.html to all requests
var app = http.createServer(function(req, res) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(index);
});
// Socket.io server listens to our app
var io = require('socket.io').listen(app);
// Send current time to all connected clients
function sendTime() {
// io.emit('time', { time: new Date().toJSON() });
io.emit('time', pipedata);
}
// Send current time every 10 secs
setInterval(sendTime, 100);
// Emit welcome message on connection
io.on('connection', function(socket) {
// Use socket to communicate with this particular client only, sending it it's own id
socket.emit('welcome', { message: 'Welcome!', id: socket.id });
socket.on('i am client', console.log);
});
app.listen(8080);
index.html:
<!doctype html>
<html>
<head>
<script src='/socket.io/socket.io.js'></script>
<script>
var socket = io();
socket.on('welcome', function(data) {
addMessage(data.message);
// Respond with a message including this clients' id sent from the server
socket.emit('i am client', {data: 'foo!', id: data.id});
});
socket.on('time', function(data) {
addMessage(data);
});
socket.on('error', console.error.bind(console));
socket.on('message', console.log.bind(console));
function addMessage(message) {
// var text = document.createTextNode(message);
document.getElementById('messages').textContent = message;
// el = document.createElement('li'),
// messages = document.getElementById('messages');
// el.appendChild(text);
// messages.appendChild(el);
}
</script>
<style>
p.sansserif { font-family: Arial, Helvtica, sans-serif; font-size:300%;}
</style>
</head>
<body>
<p class = "sansserif" id='messages'>Hello</p>
</body>
</html>
Thanks for sharing.
ReplyDeleteCould you by any chance also share som snippets of canbus data?
I have done some development for the center console browser before, and would like to play around with it.
I think D3 would be a nice fit for this kind of project of streaming data, and live updates. D3 is an open source javascript library for manipulating documents/graphics based on data. It has great documentation, lots of examples and a solid community.
85D owner from Tromsø/Norway.
Thanks for this! I've just purchased the hardware and cannot wait to see what you are able to make of this.
ReplyDeleteUm, what happened to the semiconductor fabrication tools that you were making a while back?
ReplyDeleteThank for share, for me this is new knowledge. My basic is nutrition.
ReplyDeleteAny idea what those spikes on the scope display are coming from? Surely that can't be a feature of CAN? It almost looks like the scope's ground wire is not connected.
ReplyDeleteThe scope ground was definitely connected, however I agree that those spikes look pretty gnarly. The scope was being powered from 110VAC from an inexpensive 12V inverter with a three-prong plug. So, it is likely the scope chassis was grounded to the car's earth, and there were possibly parallel ground paths. I noticed that the scope was able to decode the data with no problem, so I ignored the spikes.
DeleteNot to be too picky but i think you said odb2 should be obd2 (on board idagnostics..)
ReplyDeleteThis is so cool. I hoped for someone to do this. Looking forward to your updates! Maybe you can sell a ready-to-use kit sometime in the future? I would buy that in a heartbeat!
ReplyDeleteWhat version of the Model S did you go with, Ben?
ReplyDeleteP100D :) The next video on this topic should show some really extreme automotive physics experiments.
DeleteHave you looked into a grafana and influxdb setup?
ReplyDeleteThis comment has been removed by the author.
ReplyDeleteHi Ben, is there a private way to contact you?
ReplyDeleteConnector is widely availible. Here is Mouser page of connector shell http://www.mouser.com/search/ProductDetail.aspx?r=571-173851-2
ReplyDeletepins: http://www.mouser.com/search/ProductDetail.aspx?r=571-173630-6
Thanks! This may be for pre-2015 cars. Mouser shows this as a 12-position connector, and the 2015 and later cars have a larger 18 position connector.
DeleteHello Ben. Firstly, I would like to thank you for sharing this example.
ReplyDeleteI have a question though - why did you use those pipes "grep 106 | awk -Winteractive '{ print $10}'" before executing node app?
What do they mean?
I am asking because I can't get any data to be printed on the webpage, but candump works while executed standalone.
Grep 106 - this shows only candump packets with ID 106. (it just looks for lines of text that contain 106, and drops all others)
Deleteawk -Winteractive '{ print $10}' - any packet containing 106 is dumped into awk that pulls out the 10th field in the line. In this case, it's the last hex byte of data from the can 106 packet.
The reason you may not see any data, is because you don't have any canbus ID 106 packets.
This comment has been removed by the author.
ReplyDeleteI had some issues with buffering, on raspbian. Here's what I had to do to get the output to run smoothly.
ReplyDeletecandump -cae vcan0,0:0,#FFFFFFFF | grep 0D1 --line-buffered | mawk -W interactive '{ print $4; system("")}' | node app.js
I started building an app to take all this can bus data and quickly reached the limitations of piping raw data into the node server.
DeleteInstead you can use this to use node to spawn a child process to capture data. It's much more responsive
var spawn = require('child_process').spawn,
candump = spawn('candump',['vcan0']);
var io = require('socket.io').listen(app);
candump.stdout.on('data', function (data) {
$pipedat = data.toString().split("\n"); // data comes in multiple lines
$pipedat.forEach(function (e) {
if (e !== "") { // last line is usually empty, ignore
$o = e.split(" "); // split line data by spaces (alt to awk)
$msgline = [$o[4],$o.slice(9).join("")]; // output in "123 DEADBEEF12345678" format
//console.log('\033[2J'); // cls
$rt = nodelib.addMessage($msgline[0],$msgline[1]);
io.emit('data', $rt);
//console.log($rt.engine.RPM);
}
});
});
app.listen(8088);