Skip to content

Instantly share code, notes, and snippets.

@birkir
Last active February 11, 2020 21:57
Show Gist options
  • Save birkir/e2010a37917b9cd4e9f9bf693880cdc4 to your computer and use it in GitHub Desktop.
Save birkir/e2010a37917b9cd4e9f9bf693880cdc4 to your computer and use it in GitHub Desktop.
GPS Plugin for BMW ibus interface
/**
* This plugin will emit events with GPS coordinates
*
* const gps = new GPSPlugin();
* gps.on('gps', ({ lat, lng, alt }) => console.log(lat, lng, alt));
* MINI.addPlugin(gps);
*/
class GPSPlugin {
/**
* @var {bool} Flag determines if GPS has a fix or not.
*/
isFixed = false;
/**
* @var {object} List of attached events.
*/
events = {
gps: () => {},
};
/**
* Attach a event listener
*
* @todo Use event emitter
* @param {string} Name of event
* @param {function} Callback function
*/
on(name, cb) {
this.events[name] = cb;
}
/**
* Check if last bit in byte is true
*
* 0000 0101 -> true
* 1100 -> false
*
* @param {byte}
* @return {bool}
*/
toBool(byte) {
return Boolean(+(byte >>> 0).toString(2).split('').pop());
}
/**
* Convert 5 bytes to a single coordinate
*
* 00 36 42 06 61 = 0036°42'06.6" = -36.88516666666666
*
* @param {array} Bytes of [deg0, deg1, minutes, fragment+signed]
* @return {float} /-?0+\.0+/
*/
toDD(bytes) {
const deg = Number(bytes.slice(0, 2).map(d => d.toString(16)).join(''));
const min = Number(bytes[2].toString(16));
const frag = String(bytes[4].toString(16))[0] / 10;
const sec = Number(bytes[3].toString(16)) + frag;
const signed = this.toBool(bytes[4].toString(16));
const dd = deg + min / 60 + sec / (60 * 60);
console.log(deg, min, sec, frag, signed, dd);
return signed ? -dd : dd;
}
/**
* Convert three bytes to UTC Date
* 06 13 49 = 06:13:49 (hh:mm:ss)
* @param {array}
* @return {Date}
*/
toUTC([hh, mm, ss]) {
const date = new Date();
date.setHours(hh.toString(16));
date.setMinutes(mm.toString(16));
date.setSeconds(ss.toString(16));
return date;
}
/**
* Fired from ibus driver.
* @param {object} IBus message
* @return {void}
*/
onMessage({ src, dst, msg }) {
if (src === 0x7F && dst === 0xC8) {
if (msg[0] === 0xA2) {
// Check if GPS has a fix or not
this.isFixed = this.toBool(msg[1]);
// Parse latitude
const lat = this.toDD(msg.slice(2, 7));
// Parse longitude
const lng = this.toDD(msg.slice(7, 12));
// Cast two bytes to 16 bit integer
const alt = (msg[12] << 8) + msg[13];
// Parse UTC date
const utc = this.toUTC(msg.slice(15, 18));
// Dispatch the event
this.events.gps({ lat, lng, alt, utc });
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment