public
Last active

Interface with a polar bluetooth hrm from ruby (linux)

  • Download Gist
polar.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
require 'pp'
require 'socket'
 
module BluetoothPolarHrm
AF_BLUETOOTH=31 # these are correct for the Linux Bluez stack
BTPROTO_RFCOMM=3
class << self
def connect_bt address_str,channel=1
bytes=address_str.split(/:/).map {|x| x.to_i(16) }
s=Socket.new(AF_BLUETOOTH, :STREAM, BTPROTO_RFCOMM)
sockaddr=[AF_BLUETOOTH,0, *bytes.reverse, channel,0 ].pack("C*")
s.connect(sockaddr)
s
end
 
def decode bytes
# http://code.google.com/p/mytracks/source/browse/MyTracks/src/com/google/android/apps/mytracks/services/sensors/PolarMessageParser.java
start=bytes.index(0xfe.chr)
unless start then
warn "bad message #{bytes.inspect}"
return [nil,bytes]
end
start.zero? or bytes=bytes.slice(start..-1)
if (bytes.length < 2) || (bytes[1].ord > bytes.length)
return [nil,bytes]
end
ret={
len: bytes[1].ord,
chk: bytes[2].ord,
seq: bytes[3].ord,
status: bytes[4].ord,
hr: bytes[5].ord,
rr: [(bytes[6].ord << 8) | bytes[7].ord]
}
if ret[:chk]+ret[:len] != 255 then
warn "bad message #{bytes.inspect}"
return [nil,bytes]
end
[ret,bytes.slice(ret[:len]..-1)]
end
 
def connect(address)
Enumerator.new do |y|
pin=connect_bt(address)
buf=''
while(true) do
buf+=pin.recv(80)
data,buf=decode(buf)
if data
row=data.merge({time: Time.now})
y << row
end
end
end
end
end
end
 
# ARGV[0] should be a bluetooth address (e.g. "00:22:D0:01:ED:3B"). You can find this with
# "hcitool scan" or on probably a million other ways
 
BluetoothPolarHrm.connect(ARGV[0]).each do |d|
warn d
end

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.