Package: pyraceview
PyRaceview is a package for parsing messages used to powerNASCAR Raceview.  From these messages, detailed data such as GPS position, throttle, and steering input can be extracted.Currently, PyRaceview does not provide client code to retrieve raw data from the Raceview websocket, but may in a future release.RequirementsPython 3.7+Installationpip install pyraceviewExampleEach Raceview message starts with a 7-byte header containing some metadata>>>frompyraceview.messagesimportMsgHeader>>>msg_raw=(b'\xab\xcd\x00\x00\x01\xe5W(\x03\x1e\x9e\xb4\x01\xf9L\x83h\xc0\xcc\xf0\x12\xff\x00\x00\x02\xf8\x83\xc3#\xf0\xcd\x10\x0e\xff`'b'\x00\x04\xf9\xa8\x03\x86P\xcc\xf0\x14\xff\x00\x00\x06\xf8\x0f\xc2\xfc0\xcd\x10\x0c\xff@\x00\x08\xf7Z\xc2\xbeP\xcd0\x12\xff'b'\x00\x00\x0c\xf8m\xc3\x1c\xcd\x10\x0c\xff@\x00\x0e\xf9d\x03pP\xcc\xf0\x12\xff\x00\x00\x12\xf7.B\xaf\xcd0\x14\xff\x00\x00'b'\x14\xfaV\x03\xaa\xf0\xcd\xb0\n\xff@\x00\x16\xf7\x03B\xa0@\xcd0\x12\xff\x00\x00\x18\xf7\x18\x82\xa7\xa0\xcd0\x14\xff\x00\x00'b'\x1a\xf8\xf3\x83J\x00\xcc\xf0\x10\xff\x00\x1c\xf7\xb6\x02\xdd0\xcd0\x0e\xff\x00"\xf7\x9e\x82\xd5\x00\xcd0\x10\xff\x00$\xf7'b'\xe4\xc2\xed\x00\xcd\x10\x0e\xff\x00&\xf8V\x83\x14\x10\xcd\x10\x0c\xff@\x00(\xf7\x87B\xcc\xf0\xcd0\x10\xff\x00*\xf8>\x83\x0c@'b'\xcd\x10\x0c\xff@\x00,\xf7D\xc2\xb6\xb0\xcd0\x12\xff\x00\x00.\xf9\xfb\x83\x9b\xa0\xcd\x10\x14\xfe\xe0\x000\xf9\xdc\x03\x95\x10'b'\xcc\xf0\x14\xfe\xe0\x00>\xf7\xf9\xc2\xf4\xf0\xcd\x10\x0c\xff@\x00@\xfa7C\xa5\xf0\xcd\x90\x1b\x00\x00\x00D\xf8\xdd\x83BP\xcc'b'\xf0\x10\xff\x00J\xf8\xc6\x03;\x10\xcc\xf0\x10\xff\x00L\xf8(C\x04`\xcd\x10\x0c\xff@\x00R\xf7\xcdB\xe50\xcd\x10\x0e\xff\x00T'b'\xfaw\x83\xaf\xa0\xcd\xb0\x0c\xff`\x00V\xf7r\x02\xc6\x10\xcd0\x12\xff\x00\x00^\xf8\x9a\xc3+0\xcd\x10\x0e\xff\x00`\xfa\x1b\x03\xa1@'b'\xcd0\x1b\x00\x00\x00f\xf9yCw\x80\xcc\xf0\x12\xff\x00\x00|\xf9\x1e\x83X\xb0\xcc\xf0\x10\xff\x00\x84\xfa\xb8\xc3\xb9\xc0\xcd\xd0\x08'b'\xfe\xe0\x00\x90\xf9\xc1C\x8d\xb0\xcc\xf0\x14\xff\x00\x00\x9c\xf9\x08\x83Qp\xcc\xf0\x10\xff\x00\xb0\xf6\xed\x82\x98\xc0\xcd0\x12'b'\xff\x00\x00\xb8\xfa\x97C\xb4P\xcd\xd0\x0e\xff@\x00\xbe\xf95C`p\xcc\xf0\x12\xff\x00\x00\xc0\xf9\x91C\x7f`\xcc\xf0\x14\xff\x00\x00')>>>hdr=MsgHeader(msg_raw)>>>print(hdr)Sync:43981,Clock:0,Size:485,Type:WIn order to parse the entire message, we must use the header to lookup the correct message parser>>>frompyraceview.messagesimport_parsers>>>_parsers{'a':pyraceview.messages.MsgCarStats.MsgCarStats,'b':pyraceview.messages.MsgPitLaneExtended.MsgPitLaneExtended,'d':pyraceview.messages.MsgPitLaneExtended.MsgPitLaneExtended,'C':pyraceview.messages.MsgCupInfo.MsgCupInfo,'F':pyraceview.messages.MsgPitWindow.MsgPitWindow,'l':pyraceview.messages.MsgLapInfo.MsgLapInfo,'O':pyraceview.messages.MsgTrackConfig.MsgTrackConfig,'P':pyraceview.messages.MsgPitLaneEvent.MsgPitLaneEvent,'s':pyraceview.messages.MsgRaceStatus.MsgRaceStatus,'V':pyraceview.messages.MsgVitcToLap.MsgVitcToLap,'W':pyraceview.messages.MsgCarPosition.MsgCarPosition}>>>parser=_parsers[hdr.byte_type]>>>msg=parser(msg_raw)>>>msg<pyraceview.messages.MsgCarPosition.MsgCarPositionat0x117763550>Messages, such asMsgCarPosition, have attributes with metadata about the message>>>msg.num_cars40>>>msg.timecode52338356Additionally, some messages contain a list of data per car>>>len(msg.car_data)40>>>type(msg.car_data[0])pyraceview.percar.PerCarPositionData.PerCarPositionDataClasses containing data per car, such asPerCarPositionData, will have an integercar_idattribute>>>car_0=msg.car_data[0]>>>car_0.car_id1To properly identify a car by "number", Raceview uses an algorithm to convert the integercar_idto a string value.  In this case, id of value 1 is the '00', a valid NASCAR car number>>>frompyraceview.utilimportid_to_num>>>id_to_num(car_0.car_id)'00'PerCarPositionDataalso contains the GPS position of the car>>>car_0.pos_x,car_0.pos_y,car_0.pos_z(-686.2,1396.4,81.95)To automatically parse many messages (e.g. as read from a websocket or from a file), PyRaceview provides theMsgFactoryclass which contains an internal buffer>>>frompyraceview.messagesimportMsgFactory>>>msg_raw=(b'\xab\xcd\x00\x00\x01\x95a\x03\x1egH(\xb0\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x16\x00\x0e\x00\x00\x00\x00\x00\x00\x00'b'\x18\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x12\x00\x0e\x00\x00\x00\x00\x00\x00\x00,\x00\x0e\x00\x00\x00\x00\x00\x00\x00'b'\x08\x00\x15\x00\x00\x00\x00\x00\x00\x00V\x00\x07\x00\x00\x00\x00\x00\x00\x00(\x00\x0e\x00\x00\x00\x00\x00\x00\x00"\x00'b'\x07\x00\x00\x00\x00\x00\x00\x00\x1c\x00\x15\x00\x00\x00\x00\x00\x00\x00R\x00\x0e\x00\x00\x00\x00\x00\x00\x00$\x00\x0e'b'\x00\x00\x00\x00\x00\x00\x00>\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x06\x00\x0e\x00\x00\x00\x00\x00\x00\x00L\x00\x0e\x00'b'\x00\x00\x00\x00\x00\x00*\x00\x0e\x00\x00\x00\x00\x00\x00\x00&\x00\x15\x00\x00\x00\x00\x00\x00\x00\x0c\x00\x07\x00\x00'b'\x00\x00\x00\x00\x00\x02\x00\x07\x00\x00\x00\x00\x00\x00\x00^\x00\x0e\x00\x00\x00\x00\x00\x00\x00J\x00\x0e\x00\x00\x00'b'\x00\x00\x00\x00D\x00\x07\x00\x00\x00\x00\x00\x00\x00\x1a\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x9c\x00\x0e\x00\x00\x00'b'\x00\x00\x00\x00|\x00\x0e\x00\x00\x00\x00\x00\x00\x00\xbe\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x01\x00\x15\x00\x00\x00'b'\x00\x00\x00\x00\x0e\x00\x0e\x00\x00\x00\x00\x00\x00\x00f\x00\x1b\x00\x00\x00\x00\x00\x00\x00\xc0\x00\x15\x00\x00\x00'b'\x00\x00\x00\x00\x04\x00\x0e\x00\x00\x00\x00\x00\x00\x00\x90\x00\x07\x00\x00\x00\x00\x00\x00\x000\x00\x0e\x00\x00\x00'b'\x00\x00\x00\x00.\x00\x0e\x00\x00\x00\x00\x00\x00\x00`\x00\x0e\x00\x00\x00\x00\x00\x00\x00@\x00\x0e\x00\x00\x00\x00\x00'b'\x00\x00\x14\x00\x15\x00\x00\x00\x00\x00\x00\x00T\x00\x1b\x00\x00\x00\x00\x00\x00\x00\xb8\x00\x0e\x00\x00\x00\x00\x00'b'\x00\x00\x84\x00\x0e\x00\x00\x00\x00\x00\x00\x00\xab\xcd\x00\x00\x00zC2(\x01\x00\x00\x02\x00\x00\x04\x00\x00\x06\x00'b'\x00\x08\x00\x00\x0c\x00\x00\x0e\x00\x00\x12\x00\x00\x14\x00\x00\x16\x00\x00\x18\x00\x00\x1a\x00\x00\x1c\x00\x00"\x00'b'\x00$\x00\x00&\x00\x00(\x00\x00*\x00\x00,\x00\x00.\x00\x000\x00\x00>\x00\x00@\x00\x00D\x00\x00J\x00\x00L\x00\x00R\x00'b'\x00T\x00\x00V\x00\x00^\x00\x00`\x00\x00f\x00\x00|\x00\x00\x84\x00\x00\x90\x00\x00\x9c\x00\x00\xb0\x00\x00\xb8\x00\x00'b'\xbe\x00\x00\xc0\x00\x00\xab\xcd\x00\x02\x00\x14O\x00\t\xad~\x00\x1a\xe9\x08\xff\xff\xff\xcadaytona\x00')>>>factory=MsgFactory(msg_raw)>>>factory.has_message()TrueRead all the messages that were pushed to the factory>>>whilefactory.has_message():>>>print(factory.get_message())<pyraceview.messages.MsgCarStats.MsgCarStatsobjectat0x11777f400><pyraceview.messages.MsgCupInfo.MsgCupInfoobjectat0x11777f4a8><pyraceview.messages.MsgTrackConfig.MsgTrackConfigobjectat0x11777f550>Push more data>>>factory.push_data(b'\xab\xcd\x00\x00\x01\xd9W\'\x03\x1ejg\x01\xf9L\x83h\xc0\xcc\xf0\x12\xff\x00\x00\x02\xf8\x83\xc3#\xf0\xcd\x10'b'\x0e\xff`\x00\x04\xf9\xa8\x03\x86P\xcc\xf0\x14\xff\x00\x00\x08\xf7Z\xc2\xbeP\xcd0\x12\xff\x00\x00\x0c\xf8m\xc3'b'\x1c\xcd\x10\x0c\xff@\x00\x0e\xf9d\x03pP\xcc\xf0\x12\xff\x00\x00\x12\xf7.B\xaf\xcd0\x14\xff\x00\x00\x14\xfaV'b'\x03\xaa\xf0\xcd\xb0\n\xff@\x00\x16\xf7\x03B\xa0@\xcd0\x12\xff\x00\x00\x18\xf7\x18\x82\xa7\xa0\xcd0\x14\xff\x00'b'\x00\x1a\xf8\xf3\x83J\x00\xcc\xf0\x10\xff\x00\x1c\xf7\xb6\x02\xdd0\xcd0\x0e\xff\x00"\xf7\x9e\x82\xd5\x00\xcd0'b'\x10\xff\x00$\xf7\xe4\xc2\xed\x00\xcd\x10\x0e\xff\x00&\xf8V\x83\x14\x10\xcd\x10\x0c\xff@\x00(\xf7\x87B\xcc\xf0'b'\xcd0\x10\xff\x00*\xf8>\x83\x0c@\xcd\x10\x0c\xff@\x00,\xf7D\xc2\xb6\xb0\xcd0\x12\xff\x00\x00.\xf9\xfb\x83\x9b'b'\xa0\xcd\x10\x14\xfe\xe0\x000\xf9\xdc\x03\x95\x10\xcc\xf0\x14\xfe\xe0\x00>\xf7\xf9\x82\xf4\xe0\xcd\x10\x0c\xff@'b'\x00@\xfa7C\xa5\xf0\xcd\x90\x1b\x00\x00\x00D\xf8\xdd\x83BP\xcc\xf0\x10\xff\x00J\xf8\xc6\x03;\x10\xcc\xf0\x10'b'\xff\x00L\xf8(C\x04`\xcd\x10\x0c\xff@\x00R\xf7\xcdB\xe50\xcd\x10\x0e\xff\x00T\xfaw\x83\xaf\xa0\xcd\xb0\x0c\xff`'b'\x00V\xf7r\x02\xc6\x10\xcd0\x12\xff\x00\x00^\xf8\x9a\xc3+0\xcd\x10\x0e\xff\x00`\xfa\x1b\x03\xa1@\xcd0\x1b\x00'b'\x00\x00f\xf9y\x03w\x80\xcc\xf0\x12\xff\x00\x00|\xf9\x1e\x83X\xb0\xcc\xf0\x10\xff\x00\x84\xfa\xb8\xc3\xb9\xc0'b'\xcd\xd0\x08\xfe\xe0\x00\x90\xf9\xc1C\x8d\xb0\xcc\xf0\x14\xff\x00\x00\x9c\xf9\x08\x83Qp\xcc\xf0\x10\xff\x00\xb0'b'\xf6\xed\x82\x98\xc0\xcd0\x12\xff\x00\x00\xb8\xfa\x97C\xb4P\xcd\xd0\x0e\xff@\x00\xbe\xf95C`p\xcc\xf0\x12\xff\x00'b'\x00\xc0\xf9\x91C\x7f`\xcc\xf0\x14\xff\x00\x00')>>>factory.get_message()<pyraceview.messages.MsgCarPosition.MsgCarPositionat0x11777f6a0>