рд╣реИрдХрд┐рдВрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ рдСрдЯреЛ рдСрдЯреЛред рд╡рд░реНрдЪреБрдЕрд▓ рдбреИрд╢рдмреЛрд░реНрдб



рдкрд╣рд▓реЗ рд▓реЗрдЦ рдореЗрдВ, "рд╡реЙрдпрд╕ рдХрдВрдЯреНрд░реЛрд▓ рдХреЗ рд▓рд┐рдП рдХрд╛рд░ рдХреЗ рд▓рд┐рдП рдХреИрди рдмрд╕ рдХреЛ рд╣реИрдХ рдХрд░рдирд╛", рдореИрдВ рдЕрдкрдиреА рдХрд╛рд░ рдХреЗ рджрд░рд╡рд╛рдЬреЗ рдореЗрдВ рдХрдВрдлрд░реНрдЯ рдХреИрди рдмрд╕ рд╕реЗ рд╕реАрдзреЗ рдЬреБрдбрд╝рд╛ рдФрд░ рдкрд╛рд╕рд┐рдВрдЧ рдЯреНрд░реИрдлрд┐рдХ рдХреА рдЬрд╛рдВрдЪ рдХреА, рдЗрд╕рд╕реЗ рдореБрдЭреЗ рд╡рд┐рдВрдбреЛрдЬрд╝, рд╕реЗрдВрдЯреНрд░рд▓ рд▓реЙрдХрд┐рдВрдЧ рдЖрджрд┐ рдХреЛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрдорд╛рдВрдб рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рдорд┐рд▓реАред

рдЗрд╕ рд▓реЗрдЦ рдореЗрдВ рдореИрдВ рдЖрдкрдХреЛ рдмрддрд╛рдКрдВрдЧрд╛ рдХрд┐ рдХреИрд╕реЗ рдЕрдкрдиреЗ рд╕реНрд╡рдпрдВ рдХреЗ рдЕрдиреВрдареЗ рдЖрднрд╛рд╕реА рдпрд╛ рдбрд┐рдЬрд┐рдЯрд▓ рдбреИрд╢рдмреЛрд░реНрдб рдХреЛ рдЗрдХрдЯреНрдард╛ рдХрд░реЗрдВ рдФрд░ VAG рдХрд╛рд░реЛрдВ (рд╡реЛрдХреНрд╕рд╡реИрдЧрди, рдСрдбреА, рд╕реАрдЯ, рд╕реНрдХреЛрдбрд╛) рдореЗрдВ рдХрд┐рд╕реА рднреА рд╕реЗрдВрд╕рд░ рд╕реЗ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВред

рдореИрдВрдиреЗ MCP2515 TJA1050 рдирд░реЗрди рдореЙрдбреНрдпреВрд▓ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рд░рд╛рд╕реНрдкрдмреЗрд░реА рдкрд╛рдИ рдХреЗ рд▓рд┐рдП рдПрдХ рдирдпрд╛ рдХреИрди рд╕реНрдирд┐рдлрд░ рдФрд░ рдХреИрди рдХреЛ рдврд╛рд▓ рд╕рдХрддрд╛ рд╣реИ, рдЙрдирдХреЗ рд╕рд╛рде рдкреНрд░рд╛рдкреНрдд рдбреЗрдЯрд╛ рдореИрдВрдиреЗ рд░рд╛рд╕реНрдкрдмреЗрд░реА рдкрд╛рдИ рдХреЗ рд▓рд┐рдП 7 for рдбрд┐рд╕реНрдкреНрд▓реЗ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдбрд┐рдЬрд┐рдЯрд▓ рдЗрдВрд╕реНрдЯреНрд░реВрдореЗрдВрдЯ рдкреИрдирд▓ рдХреЗ рд╡рд┐рдХрд╛рд╕ рдореЗрдВ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ред рдЬрд╛рдирдХрд╛рд░реА рдХреЗ рдПрдХ рд╕рд╛рдзрд╛рд░рдг рдкреНрд░рджрд░реНрд╢рди рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдбрд┐рдЬрд┐рдЯрд▓ рдкреИрдирд▓ рд╕реНрдЯреАрдпрд░рд┐рдВрдЧ рдХреЙрд▓рдо рд╕реНрд╡рд┐рдЪ рдФрд░ рдХрд╛рд░ рдореЗрдВ рдЕрдиреНрдп рдШрдЯрдирд╛рдУрдВ рдХреЗ рдмрдЯрди рдкрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХрд░рддрд╛ рд╣реИред

рдбреНрд░рд╛рдЗрдВрдЧ рдЙрдкрдХрд░рдгреЛрдВ рдХреЗ рд▓рд┐рдП рдПрдХ рд░реВрдкрд░реЗрдЦрд╛ рдХреЗ рд░реВрдк рдореЗрдВ, рдкрд╛рдпрдерди рдХреЗ рд▓рд┐рдП рдХреАрд╡реА рдорд╣рд╛рди рдерд╛ред рдпрд╣ рдПрдХреНрд╕ рдХреЗ рдмрд┐рдирд╛ рдХрд╛рдо рдХрд░рддрд╛ рд╣реИ рдФрд░ рдЧреНрд░рд╛рдлрд┐рдХреНрд╕ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЬреАрдПрд▓ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддрд╛ рд╣реИред

  1. Arduino Uno рд╕реЗ рд╕реНрдирд┐рдлрд░ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ
  2. VAG-COM рдбрд╛рдпрдЧреНрдиреЛрд╕реНрдЯрд┐рдХ рд╕рд┐рд╕реНрдЯрдо (VCDS) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рд╕реБрдирдирд╛
  3. рд░рд╛рд╕реНрдкрдмреЗрд░реА рдкрд╛рдИ рдФрд░ 7 based рдбрд┐рд╕реНрдкреНрд▓реЗ рдХреЗ рдЖрдзрд╛рд░ рдкрд░ рдбреИрд╢рдмреЛрд░реНрдб рдХрд╛ рд╡рд┐рдХрд╛рд╕
  4. рдкрд╛рдпрдерди рдФрд░ рдХрд┐рд╡реА (рдпреВрдЖрдИ рдлреНрд░реЗрдорд╡рд░реНрдХ) рдореЗрдВ рдбреИрд╢рдмреЛрд░реНрдб рд╕реЙрдлреНрдЯрд╡реЗрдпрд░
  5. рд░рд╛рд╕реНрдкрдмреЗрд░реА рдкрд╛рдИ рдкрд░ рдЖрдзрд╛рд░рд┐рдд рдбрд┐рдЬрд┐рдЯрд▓ рдЗрдВрд╕реНрдЯреНрд░реВрдореЗрдВрдЯ рдкреИрдирд▓ рдХрд╛ рд╡реАрдбрд┐рдпреЛ

рдХрдЯреМрддреА рдХреЗ рддрд╣рдд, рдкрд░рд┐рдпреЛрдЬрдирд╛ рдХрд╛ рдкреВрд░рд╛ рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рджрд┐рд▓рдЪрд╕реНрдк рд╣реЛрдЧрд╛!


рдбреНрд░рд╛рдЗрд╡рд░ рдХрд╛ рджрд░рд╡рд╛рдЬрд╛ рдЦреБрд▓рд╛ рд╣реИ

Arduino Uno рд╕реЗ рд╕реНрдирд┐рдлрд░ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВ


рд╡реАрд╕реАрдбреАрдПрд╕ рдХреИрди рдмрд╕ рдХреЛ рдХреНрдпрд╛ рднреЗрдЬрддрд╛ рд╣реИ, рдпрд╣ рд╕реБрдирдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ Arduino рдФрд░ MCP2515 TJA1050 рдирд░реЗрди рдореЙрдбреНрдпреВрд▓ рд╕реЗ рдмреНрд░реЗрдбрдмреЛрд░реНрдб рдкрд░ рдПрдХ рд╕реНрдирд┐рдлрд╝рд░ рдЗрдХрдЯреНрдард╛ рдХрд┐рдпрд╛ред



рдХрдиреЗрдХреНрд╢рди рдЖрд░реЗрдЦ рдЗрд╕ рдкреНрд░рдХрд╛рд░ рд╣реИ:


рдЯреНрд░реИрдлрд╝рд┐рдХ рдХреЛ рд╕реБрдирдиреЗ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ Arduino рдХреЗ рд▓рд┐рдП CanHackerV2 рд╡рд┐рд╢реНрд▓реЗрд╖рдХ рдФрд░ arduino-canhacker рдлрд░реНрдорд╡реЗрдпрд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛, рдЬреЛ рдЗрд╕ рдХрд╛рд░реНрдпрдХреНрд░рдо рдХреЗ рд╕рд╛рде рд╕рдВрдЧрдд API рдХреЛ рд▓рд╛рдЧреВ рдХрд░рддрд╛ рд╣реИред Git рдореЗрдВ рдлрд░реНрдорд╡реЗрдпрд░ https://github.com/autowp/arduino-canhacker

CanHackerV2 рдЖрдкрдХреЛ рдПрдХ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдЕрдВрддрд░рд╛рд▓ рдкрд░ рдЯреНрд░реИрдлрд╝рд┐рдХ, рд░рд┐рдХреЙрд░реНрдб рдФрд░ рдЖрджреЗрд╢реЛрдВ рдХреЛ рджреЗрдЦрдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ, рдЬреЛ рдбреЗрдЯрд╛ рд╡рд┐рд╢реНрд▓реЗрд╖рдг рдореЗрдВ рдмрд╣реБрдд рдорджрдж рдХрд░рддрд╛ рд╣реИред



VAG-COM рдбрд╛рдпрдЧреНрдиреЛрд╕реНрдЯрд┐рдХ рд╕рд┐рд╕реНрдЯрдо (VCDS) рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдЕрдиреБрд░реЛрдзреЛрдВ рдХреЛ рд╕реБрдирдирд╛


рдЖрдзрд┐рдХрд╛рд░рд┐рдХ рд╡реЗрдмрд╕рд╛рдЗрдЯ ru.ross-tech.com рд╕реЗ рд╡реАрд╕реАрдбреАрдПрд╕ рдХрд╛ рд╡рд┐рд╡рд░рдг :

VCDS рд╣рд╛рд░реНрдбрд╡реЗрдпрд░-рд╕реЙрдлреНрдЯрд╡реЗрдпрд░ рд╕реНрдХреИрдирд░ VAG рд╡рд╛рд╣рдиреЛрдВ рдкрд░ рд╕реНрдерд╛рдкрд┐рдд рдЗрд▓реЗрдХреНрдЯреНрд░реЙрдирд┐рдХ рдирд┐рдпрдВрддреНрд░рдг рдкреНрд░рдгрд╛рд▓рд┐рдпреЛрдВ рдХреЗ рдирд┐рджрд╛рди рдХреЗ рд▓рд┐рдП рдмрдирд╛рдпрд╛ рдЧрдпрд╛ рд╣реИред рд╕рднреА рдкреНрд░рдгрд╛рд▓рд┐рдпреЛрдВ рддрдХ рдкрд╣реБрдВрдЪ: рдЗрдВрдЬрди, рдПрд╕реАрдкреА, рдПрдмреАрдПрд╕, рдХреНрд▓рд╛рдЗрдореЗрдЯ рдХрдВрдЯреНрд░реЛрд▓, рдмреЙрдбреА рдЗрд▓реЗрдХреНрдЯреНрд░реЙрдирд┐рдХреНрд╕ рдЗрддреНрдпрд╛рджрд┐, рдкрдврд╝рдиреЗ рдФрд░ рдорд┐рдЯрд╛рдиреЗ рд╡рд╛рд▓реЗ рдХреЛрдбреНрд╕, рд╡рд░реНрддрдорд╛рди рдорд╛рдкрджрдВрдбреЛрдВ, рд╕рдХреНрд░рд┐рдпрдг, рдмреБрдирд┐рдпрд╛рджреА рд╕реЗрдЯрд┐рдВрдЧреНрд╕, рдЕрдиреБрдХреВрд▓рди, рдХреЛрдбрд┐рдВрдЧ рдЖрджрд┐ рдХреЛ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддреЗ рд╣реИрдВред



рдиреИрджрд╛рдирд┐рдХ тАЛтАЛрд╕реНрдЯреНрд░рд┐рдВрдЧ рдореЗрдВ рд╕реНрдиреАрдлрд░ рдХреЛ CAN_L рдФрд░ CAN_H рд▓рд╛рдЗрдиреЛрдВ рд╕реЗ рдЬреЛрдбрд╝рдХрд░, рдореИрдВ рдпрд╣ рджреЗрдЦрдиреЗ рдореЗрдВ рд╕рдХреНрд╖рдо рдерд╛ рдХрд┐ рд╡реАрд╕реАрдбреАрдПрд╕ рдХреНрдпрд╛ рдЕрдиреБрд░реЛрдз рдХрд░рддрд╛ рд╣реИ рдФрд░ рдХрд╛рд░ рдХреНрдпрд╛ рдЬрд╡рд╛рдм рджреЗрддреА рд╣реИред



VAG рдСрдЯреЛ рд╕рдореВрд╣ рдХреА рдЦрд╝рд╛рд╕рд┐рдпрдд рдпрд╣ рд╣реИ рдХрд┐ OBD2 рдХрдиреЗрдХреНрдЯрд░ рдХреЛ рдЧреЗрдЯрд╡реЗ рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ CAN рдмрд╕ рд╕реЗ рдЬреЛрдбрд╝рд╛ рдЬрд╛рддрд╛ рд╣реИ рдФрд░ рдЧреЗрдЯрд╡реЗ рдиреЗрдЯрд╡рд░реНрдХ рд╕реЗ рдЪрд▓рдиреЗ рд╡рд╛рд▓реЗ рд╕рднреА рдЯреНрд░реИрдлрд╝рд┐рдХ рдХреЛ рдкрд╛рд╕ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рдЕрд░реНрдерд╛рддред рдпрджрд┐ рдЖрдк рдПрдХ рд╕реНрдирд┐рдлрд░ рдХреЗ рд╕рд╛рде OBD2 рдХрдиреЗрдХреНрдЯрд░ рд╕реЗ рдХрдиреЗрдХреНрдЯ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдЖрдкрдХреЛ рдХреБрдЫ рднреА рджрд┐рдЦрд╛рдИ рдирд╣реАрдВ рджреЗрдЧрд╛ред OBD2 рдХрдиреЗрдХреНрдЯрд░ рдореЗрдВ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдЖрдкрдХреЛ рдЧреЗрдЯрд╡реЗ рдкрд░ рд╡рд┐рд╢реЗрд╖ рдЕрдиреБрд░реЛрдз рднреЗрдЬрдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред рд╡реАрд╕реАрдбреАрдПрд╕ рд╕реЗ рдЯреНрд░реИрдлрд╝рд┐рдХ рд╕реБрдирддреЗ рд╕рдордп рдпреЗ рдЕрдиреБрд░реЛрдз рдФрд░ рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛рдПрдБ рджрд┐рдЦрд╛рдИ рджреЗрддреА рд╣реИрдВред рдЙрджрд╛рд╣рд░рдг рдХреЗ рд▓рд┐рдП, рдЖрдк рдЗрд╕ рддрд░рд╣ рд╕реЗ рдПрдХ рд░рди рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред


рд╡реАрд╕реАрдбреАрдПрд╕ рдореЗрдВ, рдЖрдк рдХрд╛рд░ рдореЗрдВ рд▓рдЧрднрдЧ рдХрд┐рд╕реА рднреА рд╕реЗрдВрд╕рд░ рд╕реЗ рдЬрд╛рдирдХрд╛рд░реА рдкреНрд░рд╛рдкреНрдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ, рдореБрдЭреЗ рдРрд╕реА рдЬрд╛рдирдХрд╛рд░реА рдореЗрдВ рджрд┐рд▓рдЪрд╕реНрдкреА рдереА, рдЬреЛ рдЖрдорддреМрд░ рдкрд░ рдореЗрд░реА рдЪреБрд╕реНрдд-рджреБрд░реБрд╕реНрдд рдирд╣реАрдВ рд╣реЛрддреА, рдпрд╣ рд╣реИ:

  • рддреЗрд▓ рдХрд╛ рддрд╛рдкрдорд╛рди
  • рдХреМрди рд╕рд╛ рджрд░рд╡рд╛рдЬрд╛ рдЦреБрд▓рд╛ рд╣реИ

рдореБрдЭреЗ рдЧрддрд┐, рдХреНрд░рд╛рдВрддрд┐рдпрд╛рдБ, рд╢реАрддрд▓рдХ рддрд╛рдкрдорд╛рди, рдорд╛рдЗрд▓реЗрдЬ, рдкреНрд░рд╡рд╛рд╣, рдЯреИрдВрдХ рд╕реНрдерд╛рди рдФрд░ рдЕрдиреНрдп рдЕрдиреБрд░реЛрдз рднреА рдорд┐рд▓реЗ, рдореИрдВ рдЗрд╕реЗ рд╕рдВрджрд░реНрдн рдХреЗ рд▓рд┐рдП рдкреЛрд╕реНрдЯ рдХрд░реВрдБрдЧрд╛ред

// 
714 03 22 22 0D 55 55 55 55
77E 05 62 22 0D 55 65 AA AA -  
77E 05 62 22 0D 00 65 AA AA -  
77E 05 62 22 0D 54 65 AA AA -  
77E 05 62 22 0D 51 65 AA AA -  
77E 05 62 22 0D 50 65 AA AA -    
77E 05 62 22 0D 45 65 AA AA -   
77E 05 62 22 0D 15 65 AA AA -   
77E 05 62 22 0D 44 65 AA AA -     
77E 05 62 22 0D 40 65 AA AA - , ,   
01010101 = 0x55 ( )
0  - 
2  - 
4  -  
6  -  

// 
714 03 22 22 05 55 55 55 55
77E 05 62 22 05 21 AA AA AA - 
77E 05 62 22 05 20 AA AA AA -  

//  
714 03 22 22 0 55 55 55 55
77E 04 62 22 0C 55 AA AA AA - -7.5┬░
77E 04 62 22 0C 65 AA AA AA - 0.5 101┬░
77E 04 62 22 0C 66 AA AA AA - 1 = 102┬░
77E 04 62 22 0C 68 AA AA AA - 2 = 104┬░

//   
714 03 22 10 14 55 55 55 55
77E 04 62 10 14 84 AA AA AA - 16┬░

//  
714 03 22 22 94 55 55 55 55
77E 05 62 22 94 00 8E AA AA - 142

//  
714 03 22 22 06 55 55 55 55
77E 04 62 22 06 2C AA AA AA - 44
77E 04 62 22 06 16 AA AA AA - 22

//     
714 03 22 22 96 55 55 55 55
77E 05 62 22 96 01 9A AA AA - 41.0┬░

//  
714 03 22 F4 05 55 55 55 55
77E 04 62 F4 05 85 AA AA AA - 52.5┬░
77E 04 62 F4 05 87 AA AA AA - 54┬░
77E 04 62 F4 05 5 AA AA AA - 100.5┬░

//  
714 03 22 F4 0C 55 55 55 55
77E 05 62 F4 0C 0B C6 AA AA - 753.5 /; 0BC6 = 3014/4 = 753
77E 05 62 F4 0C 0B DC AA AA - 759 /; 0BDC = 3036
77E 05 62 F4 0C 0B E8 AA AA - 762 /; 0BE8 = 3048
77E 05 62 F4 0C 1C 32 AA AA - 1804.5 /

//  
714 03 22 20 2F 55 55 55 55
77E 04 62 20 2F 36 AA AA AA - -4┬░
77E 04 62 20 2F 67 AA AA AA - 45┬░
77E 04 62 20 2F 68 AA AA AA - 46┬░

//    
746 03 22 26 13 55 55 55 55
7B0 05 62 26 13 00 5B AA AA - 9.1, 91 == 0x5B
7B0 05 62 26 13 00 5C AA AA - 9.2┬░
7B0 05 62 26 13 00 5D AA AA - 9.3┬░

// 
714 03 22 22 16 55 55 55 55
77E 05 62 22 16 11 1E AA AA - 17:30

//   
714 03 22 22 1B 55 55 55 55
77E 05 62 22 1B 80 AA AA AA -  
77E 05 62 22 1B 81 AA AA AA -  
77E 05 62 22 1B 84 AA AA AA -  

//   2
714 03 22 22 99 55 55 55 55
77E 03 62 22 99 00 91 AA AA - 14.5/100

//  
714 03 22 22 98 55 55 55 55
77E 05 62 22 98 00 00 AA AA - 0.0/100

// 
714 03 22 22 03 55 55 55 55
77E 05 62 22 03 24 0 AA AA - 94080  0x240 * 10

Raspberry Pi 7тА│


Raspberry Pi. Android , , Raspberry Pi . 7тА│ , CAN TJA1050 Niren.



OBD2 ELM327 .



: CAN_L, CAN_H, +12, GND.



. , Raspberry Pi , , .



, . .



, . , 3D .



Python Kivy (UI framework)


. .




. , , - 80-.




- .




, Linux . , : , , nodejs, . Qt PySide2 , , .. . Kivy тАФ Python, .

Kivy , , OpenGL. 10 .

import can
import os
import sys
from threading import Thread
import time

os.environ['KIVY_GL_BACKEND'] = 'gl'
os.environ['KIVY_WINDOW'] = 'egl_rpi'

from kivy.app import App
from kivy.properties import NumericProperty
from kivy.properties import BoundedNumericProperty
from kivy.properties import StringProperty
from kivy.uix.label import Label
from kivy.uix.image import Image
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.widget import Widget
from kivy.uix.scatter import Scatter
from kivy.animation import Animation

messageCommands = {
    'GET_DOORS_COMMAND': 0x220D,
    'GET_OIL_TEMPERATURE' : 0x202F,
    'GET_OUTDOOR_TEMPERATURE' : 0x220C,
    'GET_INDOOR_TEMPERATURE' : 0x2613,
    'GET_COOLANT_TEMPERATURE' : 0xF405,
    'GET_SPEED' : 0xF40D,
    'GET_RPM' : 0xF40C,
    'GET_KM_LEFT': 0x2294,
    'GET_FUEL_LEFT': 0x2206,
    'GET_TIME': 0x2216
}

bus = can.interface.Bus(channel='can0', bustype='socketcan')

python
# -*- coding: utf-8 -*-

import can
import os
import sys
from threading import Thread
import time

os.environ['KIVY_GL_BACKEND'] = 'gl'
os.environ['KIVY_WINDOW'] = 'egl_rpi'

from kivy.app import App
from kivy.properties import NumericProperty
from kivy.properties import BoundedNumericProperty
from kivy.properties import StringProperty
from kivy.uix.label import Label
from kivy.uix.image import Image
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.widget import Widget
from kivy.uix.scatter import Scatter
from kivy.animation import Animation

messageCommands = {
    'GET_DOORS_COMMAND': 0x220D,
    'GET_OIL_TEMPERATURE' : 0x202F,
    'GET_OUTDOOR_TEMPERATURE' : 0x220C,
    'GET_INDOOR_TEMPERATURE' : 0x2613,
    'GET_COOLANT_TEMPERATURE' : 0xF405,
    'GET_SPEED' : 0xF40D,
    'GET_RPM' : 0xF40C,
    'GET_KM_LEFT': 0x2294,
    'GET_FUEL_LEFT': 0x2206,
    'GET_TIME': 0x2216
}

bus = can.interface.Bus(channel='can0', bustype='socketcan')

class PropertyState:
    def __init__(self, last, current):
        self.last = last
        self.current = current

    def lastIsNotNow(self):
        return self.last is not self.current

class CanListener(can.Listener):
    def __init__(self, dashboard):
        self.dashboard = dashboard
        self.speedStates = PropertyState(None,None)
        self.rpmStates = PropertyState(None,None)
        self.kmLeftStates = PropertyState(None,None)
        self.coolantTemperatureStates = PropertyState(None,None)
        self.oilTempratureStates = PropertyState(None,None)
        self.timeStates = PropertyState(None,None)
        self.outDoorTemperatureStates = PropertyState(None,None)
        self.doorsStates = PropertyState(None,None)
        self.carMinimized = True

    def on_message_received(self, message):
	 messageCommand = message.data[3] | message.data[2] << 8

        if message.arbitration_id == 0x77E and messageCommand == messageCommands['GET_SPEED']:
            self.speedStates.current = message.data[4]
            if self.speedStates.lastIsNotNow():
                self.dashboard.speedometer.text = str(self.speedStates.current)
                self.speedStates.last = self.speedStates.current

        if message.arbitration_id == 0x77E and messageCommand == messageCommands['GET_RPM']:
            self.rpmStates.current = message.data[5] | message.data[4] << 8
            if self.rpmStates.lastIsNotNow():
                self.dashboard.rpm.value = self.rpmStates.current/4
                self.rpmStates.last = self.rpmStates.current
        if message.arbitration_id == 0x35B:
            self.rpmStates.current = message.data[2] | message.data[1] << 8
            if self.rpmStates.lastIsNotNow():
                self.dashboard.rpm.value = self.rpmStates.current/4
                self.rpmStates.last = self.rpmStates.current

        if message.arbitration_id == 0x77E and messageCommand == messageCommands['GET_KM_LEFT']:
            self.kmLeftStates.current = message.data[5] | message.data[4] << 8
            if self.kmLeftStates.lastIsNotNow():
                self.dashboard.kmLeftLabel.text = str(self.kmLeftStates.current)
                self.kmLeftStates.last = self.kmLeftStates.current

        if message.arbitration_id == 0x77E and messageCommand == messageCommands['GET_COOLANT_TEMPERATURE']:
            self.coolantTemperatureStates.current = message.data[4]
            if self.coolantTemperatureStates.lastIsNotNow():
                self.dashboard.coolantLabel.text = str(self.coolantTemperatureStates.current-81)
                self.coolantTemperatureStates.last = self.coolantTemperatureStates.current

        if message.arbitration_id == 0x77E and messageCommand == messageCommands['GET_OIL_TEMPERATURE']:
            self.oilTempratureStates.current = message.data[4]
            if self.oilTempratureStates.lastIsNotNow():
                self.dashboard.oilLabel.text = str(self.oilTempratureStates.current-58)
                self.oilTempratureStates.last = self.oilTempratureStates.current

        if message.arbitration_id == 0x77E and messageCommand == messageCommands['GET_TIME']:
            self.timeStates.current = message.data[5] | message.data[4] << 8
            if self.timeStates.lastIsNotNow():
                self.dashboard.clock.text = str(message.data[4]) + ":" + str(message.data[5])
                self.timeStates.last = self.timeStates.current

        if message.arbitration_id == 0x77E and messageCommand == messageCommands['GET_OUTDOOR_TEMPERATURE']:
            self.outDoorTemperatureStates.current = float(message.data[4])
            if self.outDoorTemperatureStates.lastIsNotNow():
                self.dashboard.outDoorTemperatureLabel.text = str((self.outDoorTemperatureStates.current - 100)/2)
                self.outDoorTemperatureStates.last = self.outDoorTemperatureStates.current

        if message.arbitration_id == 0x77E and messageCommand == messageCommands['GET_DOORS_COMMAND']:
            self.doorsStates.current = message.data[4]
            if self.doorsStates.lastIsNotNow():
                self.doorsStates.last = self.doorsStates.current
                self.dashboard.car.doorsStates=message.data[4]

                # all doors closed -> minimize car
                if self.doorsStates.current == 0x55:
                    self.dashboard.minimizeCar()
                    self.carMinimized = True
                else:
                    if self.carMinimized:
                        self.dashboard.maximizeCar()
                        self.carMinimized = False
          
class Dashboard(FloatLayout):
    def __init__(self,**kwargs):
        super(Dashboard,self).__init__(**kwargs)

        # Background
        self.backgroundImage = Image(source='bg.png')
        self.add_widget(self.backgroundImage)

        # RPM
        self.rpm = Gauge(file_gauge = "gauge512.png", unit = 0.023, value=0, size_gauge=512, pos=(0,0))
        self.add_widget(self.rpm)
        self.rpm.value = -200

        # Speedometer
        self.speedometer = Label(text='0', font_size=80, font_name='hemi_head_bd_it.ttf', pos=(0,-15))
        self.add_widget(self.speedometer)

        # KM LEFT
        self.kmLeftLabel = Label(text='000', font_name='Avenir.ttc', halign="right", text_size=self.size, font_size=25, pos=(278,233))
        self.add_widget(self.kmLeftLabel)

        # COOLANT TEMPEARATURE
        self.coolantLabel = Label(text='00', font_name='hemi_head_bd_it.ttf', halign="right", text_size=self.size, font_size=27, pos=(295,-168))
        self.add_widget(self.coolantLabel)

        # OIL TEMPERATURE
        self.oilLabel = Label(text='00', font_name='hemi_head_bd_it.ttf', halign="right", text_size=self.size, font_size=27, pos=(-385,-168))
        self.add_widget(self.oilLabel)

        # CLOCK
        self.clock = Label(text='00:00', font_name='Avenir.ttc', font_size=27, pos=(-116,-202))
        self.add_widget(self.clock)

        # OUTDOOR TEMPERATURE
        self.outDoorTemperatureLabel = Label(text='00.0', font_name='Avenir.ttc', halign="right", text_size=self.size, font_size=27, pos=(76,-169))
        self.add_widget(self.outDoorTemperatureLabel)

        # CAR DOORS
        self.car = Car(pos=(257,84))
        self.add_widget(self.car)

    def minimizeCar(self, *args):
        print("min")
        anim = Animation(scale=0.5, opacity = 0, x = 400, y = 240, t='linear', duration=0.5)
        anim.start(self.car)

        animRpm = Animation(scale=1, opacity = 1, x = 80, y = -5, t='linear', duration=0.5)
        animRpm.start(self.rpm)

    def maximizeCar(self, *args):
        print("max")
        anim = Animation(scale=1, opacity = 1, x=257, y=84, t='linear', duration=0.5)
        anim.start(self.car)

        animRpm = Animation(scale=0.5, opacity = 0, x = 80, y = -5, t='linear', duration=0.5)
        animRpm.start(self.rpm)


class Car(Scatter):
    carImage = StringProperty("car362/car.png")

    driverDoorClosedImage = StringProperty("car362/driverClosedDoor.png")
    driverDoorOpenedImage = StringProperty("car362/driverOpenedDoor.png")

    passangerDoorClosedImage = StringProperty("car362/passangerClosedDoor.png")
    passangerDoorOpenedImage = StringProperty("car362/passangerOpenedDoor.png")

    leftDoorClosedImage = StringProperty("car362/leftClosedDoor.png")
    leftDoorOpenedImage = StringProperty("car362/leftOpenedDoor.png")

    rightDoorClosedImage = StringProperty("car362/rightClosedDoor.png")
    rightDoorOpenedImage = StringProperty("car362/rightOpenedDoor.png")

    doorsStates = NumericProperty(0)

    size = (286, 362)

    def __init__(self, **kwargs):
        super(Car, self).__init__(**kwargs)

        _car = Image(source=self.carImage, size=self.size)

        self.driverDoorOpened = Image(source=self.driverDoorOpenedImage, size=self.size)
        self.passangerDoorOpened = Image(source=self.passangerDoorOpenedImage, size=self.size)
        self.leftDoorOpened = Image(source=self.leftDoorOpenedImage, size=self.size)
        self.rightDoorOpened = Image(source=self.rightDoorOpenedImage, size=self.size)

        self.driverDoorClosed = Image(source=self.driverDoorClosedImage, size=self.size)
        self.passangerDoorClosed = Image(source=self.passangerDoorClosedImage, size=self.size)
        self.leftDoorClosed = Image(source=self.leftDoorClosedImage, size=self.size)
        self.rightDoorClosed = Image(source=self.rightDoorClosedImage, size=self.size)

        self.add_widget(_car)
        self.add_widget(self.driverDoorOpened)
        self.add_widget(self.passangerDoorOpened)
        self.add_widget(self.leftDoorOpened)
        self.add_widget(self.rightDoorOpened)

        self.bind(doorsStates=self._update)

    def _update(self, *args):
        driverDoorStates = self.doorsStates&1
        passangerDoorStates = self.doorsStates&4
        leftDoorStates = self.doorsStates&16
        rightDoorStates = self.doorsStates&64
        if driverDoorStates != 0:
            try:
                self.remove_widget(self.driverDoorOpened)
                self.add_widget(self.driverDoorClosed)
            except:
                pass
        else:
            try:
                self.remove_widget(self.driverDoorClosed)
                self.add_widget(self.driverDoorOpened)
            except:
                pass
        if passangerDoorStates != 0:
            try:
                self.remove_widget(self.passangerDoorOpened)
                self.add_widget(self.passangerDoorClosed)
            except:
                pass
        else:
            try:
                self.remove_widget(self.passangerDoorClosed)
                self.add_widget(self.passangerDoorOpened)
            except:
                pass
        if leftDoorStates != 0:
            try:
                self.remove_widget(self.leftDoorOpened)
                self.add_widget(self.leftDoorClosed)
            except:
                pass
        else:
            try:
                self.remove_widget(self.leftDoorClosed)
                self.add_widget(self.leftDoorOpened)
            except:
                pass
        if rightDoorStates != 0:
            try:
                self.remove_widget(self.rightDoorOpened)
                self.add_widget(self.rightDoorClosed)
            except:
                pass
        else:
            try:
                self.remove_widget(self.rightDoorClosed)
                self.add_widget(self.rightDoorOpened)
            except:
                pass

class Gauge(Scatter):
    unit = NumericProperty(1.125)
    zero = NumericProperty(116)
    value = NumericProperty(10) #BoundedNumericProperty(0, min=0, max=360, errorvalue=0)
    size_gauge = BoundedNumericProperty(512, min=128, max=512, errorvalue=128)
    size_text = NumericProperty(10)
    file_gauge = StringProperty("")

    def __init__(self, **kwargs):
        super(Gauge, self).__init__(**kwargs)

        self._gauge = Scatter(
            size=(self.size_gauge, self.size_gauge),
            do_rotation=False, 
            do_scale=False,
            do_translation=False
            )

        _img_gauge = Image(source=self.file_gauge, size=(self.size_gauge, self.size_gauge))

        self._needle = Scatter(
            size=(self.size_gauge, self.size_gauge),
            do_rotation=False,
            do_scale=False,
            do_translation=False
            )

        _img_needle = Image(source="arrow512.png", size=(self.size_gauge, self.size_gauge))


        self._gauge.add_widget(_img_gauge)
        self._needle.add_widget(_img_needle)

        self.add_widget(self._gauge)
        self.add_widget(self._needle)

        self.bind(pos=self._update)
        self.bind(size=self._update)
        self.bind(value=self._turn)

    def _update(self, *args):
        self._gauge.pos = self.pos
        self._needle.pos = (self.x, self.y)
        self._needle.center = self._gauge.center

    def _turn(self, *args):
        self._needle.center_x = self._gauge.center_x
        self._needle.center_y = self._gauge.center_y
        a = Animation(rotation=-self.value*self.unit + self.zero, t='in_out_quad',duration=0.05)
        a.start(self._needle)

class requestsLoop(Thread):
    def __init__(self):
        Thread.__init__(self)
        self.daemon = True
        self.start()

    canCommands = [
        can.Message(arbitration_id=0x714, data=[0x03, 0x22, messageCommands['GET_DOORS_COMMAND'] >> 8, messageCommands['GET_DOORS_COMMAND'] & 0xff, 0x55, 0x55, 0x55, 0x55], extended_id=False),
        can.Message(arbitration_id=0x714, data=[0x03, 0x22, messageCommands['GET_SPEED'] >> 8, messageCommands['GET_SPEED'] & 0xff, 0x55, 0x55, 0x55, 0x55], extended_id=False),
        can.Message(arbitration_id=0x714, data=[0x03, 0x22, messageCommands['GET_KM_LEFT'] >> 8, messageCommands['GET_KM_LEFT'] & 0xff, 0x55, 0x55, 0x55, 0x55], extended_id=False),
        can.Message(arbitration_id=0x714, data=[0x03, 0x22, messageCommands['GET_RPM'] >> 8, messageCommands['GET_RPM'] & 0xff, 0x55, 0x55, 0x55, 0x55], extended_id=False),
        can.Message(arbitration_id=0x714, data=[0x03, 0x22, messageCommands['GET_OIL_TEMPERATURE'] >> 8, messageCommands['GET_OIL_TEMPERATURE'] & 0xff, 0x55, 0x55, 0x55, 0x55], extended_id=False),
        can.Message(arbitration_id=0x714, data=[0x03, 0x22, messageCommands['GET_FUEL_LEFT'] >> 8, messageCommands['GET_FUEL_LEFT'] & 0xff, 0x55, 0x55, 0x55, 0x55], extended_id=False),
        can.Message(arbitration_id=0x714, data=[0x03, 0x22, messageCommands['GET_OUTDOOR_TEMPERATURE'] >> 8, messageCommands['GET_OUTDOOR_TEMPERATURE'] & 0xff, 0x55, 0x55, 0x55, 0x55], extended_id=False),
        can.Message(arbitration_id=0x746, data=[0x03, 0x22, messageCommands['GET_INDOOR_TEMPERATURE'] >> 8, messageCommands['GET_INDOOR_TEMPERATURE'] & 0xff, 0x55, 0x55, 0x55, 0x55], extended_id=False),
        can.Message(arbitration_id=0x714, data=[0x03, 0x22, messageCommands['GET_COOLANT_TEMPERATURE'] >> 8, messageCommands['GET_COOLANT_TEMPERATURE'] & 0xff, 0x55, 0x55, 0x55, 0x55], extended_id=False),
        can.Message(arbitration_id=0x714, data=[0x03, 0x22, messageCommands['GET_TIME'] >> 8, messageCommands['GET_TIME'] & 0xff, 0x55, 0x55, 0x55, 0x55], extended_id=False)
    ]

    def run(self):
        while True:
            for command in self.canCommands:
                bus.send(command)
                time.sleep(0.005)

class BoxApp(App):
    def build(self):
        dashboard = Dashboard();
        listener = CanListener(dashboard)
        can.Notifier(bus, [listener])

        return dashboard
        
if __name__ == "__main__":
    # Send requests
    requestsLoop()

    _old_excepthook = sys.excepthook
    def myexcepthook(exctype, value, traceback):
        if exctype == KeyboardInterrupt:
            print "Handler code goes here"
        else:
            _old_excepthook(exctype, value, traceback)
    sys.excepthook = myexcepthook

    # Show dashboard
    BoxApp().run()


, 3 :

  1. (, , , )
  2. 5
  3. CAN ,

, . iOS, .

. !

https://github.com/aivs/blackCockpit

Raspberry Pi




24.06.2019




тАФ , ELM327 Wi-Fi . OBD2 , CAN Wi-Fi.


VAG Virtual Cockpit AppStore. , iPhone/iPad, Android . .
, , !
VAG Virtual Cockpit


Source: https://habr.com/ru/post/hi442184/


All Articles