Hackear autobus CAN para control de voz



Un automóvil moderno no es solo un medio de transporte, sino también un dispositivo avanzado con funciones multimedia y un sistema de control electrónico para unidades y un montón de sensores. Muchos fabricantes de automóviles ofrecen las funciones de asistentes de movimiento, asistentes de estacionamiento, monitoreo y control de automóviles desde un teléfono. Esto es posible debido al uso de un bus CAN en el automóvil al que están conectados todos los sistemas: motor, sistema de frenos, volante, multimedia, clima, etc.

Mi auto es Skoda Octavia 2011. No ofrece capacidades de control desde el teléfono, así que decidí solucionar este inconveniente y al mismo tiempo agregar la función de control por voz. Como puerta de enlace entre el bus CAN y el teléfono, uso la Raspberry Pi con el escudo CAN BUS y el enrutador WiFi TP-Link. El protocolo de comunicación de los agregados automáticos está cerrado, y Volkswagen respondió a todas mis cartas con la documentación del protocolo. Por lo tanto, la única forma de descubrir cómo se comunican los dispositivos en los automóviles y aprender a administrarlos es mediante ingeniería inversa del protocolo CAN del bus VW.

Actué por etapas:

  1. Desarrollo de escudo CAN para Raspberry Pi
  2. Instalación de software para trabajar con el bus CAN
  3. Conexión al bus CAN de un automóvil
  4. Desarrollo de un sniffer y estudio del protocolo del bus CAN.
  5. Desarrollo de aplicaciones telefónicas
  6. Control por voz con Homekit y Siri

Al final de la ventana de control de voz de video.

Desarrollo de escudo CAN para Raspberry Pi


Aquí, el esquema de protección fue tomado por lnxpps.de/rpie , también hay una descripción de las conclusiones, 2 microcircuitos MCP2515 y MCP2551 se utilizan para comunicarse con CAN. 2 cables CAN-High y CAN-Low están conectados a la pantalla. En SprintLayout 6 extiendo el tablero, ¿alguien puede ser útil CANBoardRPi.lay (en la foto del título el prototipo del escudo en el tablero).





Instalación de software para trabajar con el bus CAN


En Raspbian de 2 años, necesitaba parchear bcm2708.c para agregar soporte CAN (tal vez esto no sea necesario ahora). Para trabajar con el bus CAN, debe instalar el paquete de utilidades can-utils desde github.com/linux-can/can-utils , luego cargar los módulos y elevar la interfaz can:

# initialize
insmod spi-bcm2708
insmod can
insmod can-dev
insmod can-raw
insmod can-bcm
insmod mcp251x
# Maerklin Gleisbox (60112 and 60113) uses 250000
# loopback mode for testing
ip link set can0 type can bitrate 125000 loopback on
ifconfig can0 up

Verificamos que la interfaz CAN ha aumentado con el comando ifconfig :



puede verificar que todo funcione enviando el comando y recibiéndolo.

En una terminal escuchamos:

root@raspberrypi ~ # candump any,0:0,#FFFFFFFF

En otra terminal, enviamos:

root@raspberrypi ~ # cansend can0 123#deadbeef

Aquí se describe un proceso de instalación más detallado en lnxpps.de/rpie .

Conexión al bus CAN de un automóvil


Después de un pequeño estudio de la documentación abierta sobre el bus VW CAN, descubrí que uso 2 buses.

El bus CAN de la unidad de potencia , que transmite datos a una velocidad de 500 kbit / s, conecta todas las unidades de control que sirven a esta unidad.

Por ejemplo, los siguientes dispositivos se pueden conectar al bus CAN de una unidad de alimentación:

  • unidad de control del motor
  • Unidad de control de ABS
  • unidad de control de estabilización del curso,
  • unidad de control de caja de cambios,
  • unidad de control de airbag,
  • cuadro de instrumentos.

El bus CAN del sistema Comfort y el sistema de comando de información , que permite transferir datos a una velocidad de 100 kbit / s entre las unidades de control que sirven a estos sistemas.

Por ejemplo, los
siguientes dispositivos se pueden conectar al bus CAN del sistema Comfort y al sistema de comando <información :

  • Unidad de control climatrónico o sistema de aire acondicionado,
  • unidades de control en las puertas del automóvil,
  • Unidad de control del sistema de confort,
  • Unidad de control con pantalla para radio y sistema de navegación.

Al tener acceso al primero, puede controlar el tráfico (en mi versión sobre la mecánica, al menos puede controlar el control de crucero), al tener acceso al segundo, puede controlar la radio, el clima, el cierre centralizado, las ventanas eléctricas, los faros, etc.

Ambos autobuses están conectados a través de la puerta de enlace, que se encuentra en el área debajo del volante, el conector OBD2 de diagnóstico también está conectado a la puerta de enlace, desafortunadamente el tráfico de ambos buses no se puede escuchar a través del conector OBD2, solo puede enviar un comando y solicitar un estado. Decidí que solo trabajaría con el bus Comfort, y el conector en la puerta del conductor resultó ser el lugar más conveniente para conectarse al bus.



Ahora puedo escuchar todo lo que sucede en Comfort CAN y enviar comandos.

Desarrollo de un sniffer y estudio del protocolo del bus CAN.




Después de tener acceso para escuchar el bus CAN, necesito descifrar quién pasa a quién y qué. El formato del paquete CAN se muestra en la figura.



Todas las utilidades del conjunto de can-utils pueden analizar los paquetes CAN y dar solo información útil, a saber:

  • ID
  • Longitud de datos
  • Datos

Los datos se transmiten de forma no encriptada, esto facilitó el estudio del protocolo. En Raspberry Pi, escribí un pequeño servidor que redirige los datos de candump a TCP / IP para analizar el flujo de datos en la computadora y mostrarlo maravillosamente.

Para macOS, escribí una aplicación simple que para cada dirección de dispositivo agrega una celda a la tableta y en esta celda ya puedo ver qué datos están cambiando.



Presioné el botón de la ventana de encendido, encontré una celda en la que cambian los datos, luego determiné qué comandos corresponden a presionar hacia abajo, presionar hacia arriba, mantener presionado, mantener presionado.

Puede verificar que el comando funciona enviándolo desde la terminal, por ejemplo, el comando para levantar el cristal izquierdo:

cansend can0 181#0200

Equipos que transmiten dispositivos a través del bus CAN en automóviles VAG (Skoda Octavia 2011), recibidos por ingeniería inversa:

// Front Left Glass Up
181#0200
// Front Left Glass Down
181#0800
// Front Right Glass Up
181#2000
// Front Right Glass Down
181#8000
// Back Left Glass Up
181#0002
// Back Left Glass Down
181#0008
// Back Right Glass Up
181#0020
// Back Right Glass Down
181#0080
// Central Lock Open
291#09AA020000
// Central Lock Close
291#0955040000
// Update Light status of central lock (   /          ,       ,    )
291#0900000000

Era demasiado vago para estudiar todos los demás dispositivos, así que en esta lista, solo lo que me interesaba.

Desarrollo de aplicaciones telefónicas


Usando los comandos recibidos, escribí una aplicación para el iPhone que abre / cierra ventanas y controla el bloqueo central.

En Raspberry Pi, lancé 2 servidores pequeños, el primero envía datos desde candump a TCP / IP, el segundo recibe comandos del iPhone y los envía de manera inmediata.


Fuentes de aplicación de control automático para iOS
//
//  FirstViewController.m
//  Car Control
//
//  Created by Vitaliy Yurkin on 17.05.15.
//  Copyright (c) 2015 Vitaliy Yurkin. All rights reserved.
//

#import "FirstViewController.h"
#import "DataConnection.h"
#import "CommandConnection.h"

@interface FirstViewController () <DataConnectionDelegate>
@property (nonatomic, strong) DataConnection *dataConnection;
@property (nonatomic, strong) CommandConnection *commandConnection;
@property (weak, nonatomic) IBOutlet UILabel *Door_1;
@property (weak, nonatomic) IBOutlet UILabel *Door_2;
@property (weak, nonatomic) IBOutlet UILabel *Door_3;
@property (weak, nonatomic) IBOutlet UILabel *Door_4;
@property (weak, nonatomic) IBOutlet UIButton *CentralLock;
- (IBAction)lockUnlock:(UIButton *)sender;
@end

@implementation FirstViewController

- (void)viewDidLoad {
    self.dataConnection = [DataConnection new];
    self.dataConnection.delegate = self;
    [self.dataConnection connectToCanBus];
    
    self.commandConnection = [CommandConnection new];
    [self.commandConnection connectToCanBus];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (void)doorStatusChanged:(char)value {
    /*
     1 - Front Left Door
     2 - Front Right Door
     4 - Back Left Door
     8 - Back Right Door
     
     3 - Front Left&Right Door = 1 + 3
     5 - Front& Back left Door = 1 + 4
     */
    
    // Front Left Door
    if (value & 1) {
        self.Door_1.backgroundColor = [UIColor yellowColor];
        self.Door_1.text = @"";
        NSLog(@"1");
    }
    else {
        self.Door_1.backgroundColor = [UIColor lightGrayColor];
        self.Door_1.text = @"";
    }
    
    // Front Right Door
    if (value & 2) {
        self.Door_2.backgroundColor = [UIColor yellowColor];
        self.Door_2.text = @"";
        NSLog(@"2");
    }
    else {
        self.Door_2.backgroundColor = [UIColor lightGrayColor];
        self.Door_2.text = @"";
    }
    
    // Back Left Door
    if (value & 4) {
        self.Door_3.backgroundColor = [UIColor yellowColor];
        self.Door_3.text = @"";
        NSLog(@"4");
    }
    else {
        self.Door_3.backgroundColor = [UIColor lightGrayColor];
        self.Door_3.text = @"";
    }
    
    // Back Right Door
    if (value & 8) {
        self.Door_4.backgroundColor = [UIColor yellowColor];
        self.Door_4.text = @"";
        NSLog(@"8");
    }
    else {
        self.Door_4.backgroundColor = [UIColor lightGrayColor];
        self.Door_4.text = @"";
    }
}

BOOL firstStatusChange = YES;
BOOL lastStatus;

-(void) centralLockStatusChanged:(BOOL)status {
    // At first status changes set lastStatus variable
    if (firstStatusChange) {
        firstStatusChange = NO;
        // Invert status, to pass the next test
        lastStatus = !status;
    }
    
    // Change Lock image only if status changed
    if (!(lastStatus == status)) {
        // Check status
        if (status) {
            [self.CentralLock setBackgroundImage:[UIImage imageNamed:@"lock_close"] forState:UIControlStateNormal];
        }
        else {
            [self.CentralLock setBackgroundImage:[UIImage imageNamed:@"lock_open"] forState:UIControlStateNormal];
        }
        lastStatus = status;
    }
}


// Front Left Glass
- (IBAction)frontLeftUp:(UIButton *)sender {
    [self.commandConnection sendMessage:@"cansend can0 181#0200"];
}
- (IBAction)frontLeftDown:(id)sender {
    [self.commandConnection sendMessage:@"cansend can0 181#0800"];
}

// Front Right Glass
- (IBAction)frontRightUp:(UIButton *)sender {
    [self.commandConnection sendMessage:@"cansend can0 181#2000"];
}
- (IBAction)frontRightDown:(id)sender {
    [self.commandConnection sendMessage:@"cansend can0 181#8000"];
}

// Back Left Glass
- (IBAction)backLeftUp:(UIButton *)sender {
    [self.commandConnection sendMessage:@"cansend can0 181#0002"];
}
- (IBAction)backLeftDown:(id)sender {
    [self.commandConnection sendMessage:@"cansend can0 181#0008"];
}

// Back Right Glass
- (IBAction)backRightUp:(UIButton *)sender {
    [self.commandConnection sendMessage:@"cansend can0 181#0020"];
}
- (IBAction)backtRightDown:(id)sender {
    [self.commandConnection sendMessage:@"cansend can0 181#0080"];
}

- (IBAction)lockUnlock:(UIButton *)sender {
    // If central lock closed
    if (lastStatus) {
        // Open
        [self.commandConnection sendMessage:@"cansend can0 291#09AA020000"];

        int64_t delayInSeconds = 1; // 1 sec
        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
        dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
            [self.commandConnection sendMessage:@"cansend can0 291#0900000000"];
        });
        
    }
    else {
        // Close
        [self.commandConnection sendMessage:@"cansend can0 291#0955040000"];
        int64_t delayInSeconds = 1; // 1 sec
        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
        dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
            [self.commandConnection sendMessage:@"cansend can0 291#0900000000"];
        });
    }
    
}
@end


Hay una manera de no escribir su aplicación para el teléfono, pero para aprovechar las ventajas del mundo de las casas inteligentes, solo necesita instalar el sistema de automatización Z-Way en la Raspberry Pi con el comando:

wget -q -O - razberry.z-wave.me/install | sudo bash

Después de eso, agregamos nuestros dispositivos CAN al sistema de automatización Z-Way.


Y controlamos el


regulador de la ventana como un interruptor normal: aplicaciones móviles para Z-Way: ZWay Home Control y ZWay Control.

Control por voz con Homekit y Siri


En uno de mis artículos, describí el proceso de instalación de Homebridge en una Raspberry Pi para el control por voz del sistema de automatización del hogar Z-Way . Después de instalar Homebridge, podrá controlar la voz con Siri. Estoy seguro de que para Android hay muchas aplicaciones que permiten que la voz envíe solicitudes HTTP para controlar Z-Way.

Adjunto el video al control por voz del regulador de la ventana.

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


All Articles