├── connected_car_app ├── README.md ├── common │ ├── .gitignore │ ├── src │ │ └── main │ │ │ ├── res │ │ │ └── values │ │ │ │ └── strings.xml │ │ │ ├── AndroidManifest.xml │ │ │ └── java │ │ │ └── com │ │ │ └── trentseed │ │ │ └── bmw_rpi_ibus_controller │ │ │ └── common │ │ │ ├── ControllerMessage.java │ │ │ ├── WakeLocker.java │ │ │ ├── ConnectedThread.java │ │ │ ├── IBUSPacket.java │ │ │ ├── BluetoothInterface.java │ │ │ ├── IBUSWrapper.java │ │ │ └── VoiceCommand.java │ ├── proguard-rules.pro │ └── build.gradle ├── ibuswear │ ├── .gitignore │ ├── libs │ │ └── gson-2.2.4.jar │ ├── src │ │ └── main │ │ │ ├── res │ │ │ ├── drawable-hdpi │ │ │ │ ├── keys.png │ │ │ │ ├── bmw_emblem.png │ │ │ │ ├── button_up.png │ │ │ │ ├── button_down.png │ │ │ │ ├── button_exit.png │ │ │ │ ├── button_lock.png │ │ │ │ ├── button_unlock.png │ │ │ │ ├── button_voice.png │ │ │ │ ├── button_volume.png │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── bmw_background.png │ │ │ │ ├── button_sunroof.png │ │ │ │ ├── about_background.png │ │ │ │ ├── bmw_emblem_pressed.png │ │ │ │ ├── button_driver_seat.png │ │ │ │ ├── window_front_left.png │ │ │ │ ├── window_front_right.png │ │ │ │ ├── window_rear_left.png │ │ │ │ └── window_rear_right.png │ │ │ ├── drawable-mdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── drawable-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── drawable-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── drawable-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── values │ │ │ │ ├── dimens.xml │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ │ ├── layout │ │ │ │ ├── round.xml │ │ │ │ ├── keys.xml │ │ │ │ ├── exit.xml │ │ │ │ ├── keys_lock.xml │ │ │ │ ├── voice.xml │ │ │ │ ├── volume.xml │ │ │ │ ├── about.xml │ │ │ │ ├── activity_main.xml │ │ │ │ ├── sunroof.xml │ │ │ │ ├── window_action_up.xml │ │ │ │ ├── driver_seat.xml │ │ │ │ ├── keys_unlock.xml │ │ │ │ ├── window_action_down.xml │ │ │ │ ├── window_back_left.xml │ │ │ │ ├── window_back_right.xml │ │ │ │ ├── window_front_left.xml │ │ │ │ ├── window_front_right.xml │ │ │ │ ├── rect.xml │ │ │ │ └── welcome.xml │ │ │ ├── values-v11 │ │ │ │ └── styles.xml │ │ │ ├── values-w820dp │ │ │ │ └── dimens.xml │ │ │ ├── menu │ │ │ │ └── activity_main.xml │ │ │ └── values-v14 │ │ │ │ └── styles.xml │ │ │ ├── java │ │ │ └── com │ │ │ │ └── trentseed │ │ │ │ └── bmw_rpi_ibus_controller │ │ │ │ └── wear │ │ │ │ ├── FragmentKeys.java │ │ │ │ ├── FragmentAbout.java │ │ │ │ ├── FragmentVolume.java │ │ │ │ ├── FragmentSunroof.java │ │ │ │ ├── FragmentDriverSeat.java │ │ │ │ ├── FragmentWindowBackLeft.java │ │ │ │ ├── FragmentWindowBackRight.java │ │ │ │ ├── FragmentWindowFrontLeft.java │ │ │ │ ├── FragmentWindowFrontRight.java │ │ │ │ ├── FragmentKeysLock.java │ │ │ │ ├── FragmentKeysUnlock.java │ │ │ │ ├── FragmentExit.java │ │ │ │ ├── FragmentWindowBackLeftActionUp.java │ │ │ │ ├── FragmentWindowFrontLeftActionUp.java │ │ │ │ ├── FragmentWindowBackRightActionUp.java │ │ │ │ ├── FragmentWindowFrontRightActionUp.java │ │ │ │ ├── FragmentWindowBackLeftActionDown.java │ │ │ │ ├── FragmentWindowFrontLeftActionDown.java │ │ │ │ ├── FragmentWindowBackRightActionDown.java │ │ │ │ ├── FragmentWindowFrontRightActionDown.java │ │ │ │ ├── FragmentVolumeDown.java │ │ │ │ ├── FragmentVolumeUp.java │ │ │ │ ├── FragmentSunroofOpen.java │ │ │ │ ├── FragmentSunroofClose.java │ │ │ │ ├── FragmentDriverSeatBack.java │ │ │ │ ├── FragmentDriverSeatForward.java │ │ │ │ ├── ActivityMain.java │ │ │ │ ├── FragmentWelcome.java │ │ │ │ ├── FragmentVoiceCommand.java │ │ │ │ └── IBUSGridPagerAdapter.java │ │ │ └── AndroidManifest.xml │ ├── proguard-rules.pro │ └── build.gradle ├── settings.gradle ├── app │ ├── lint.xml │ ├── src │ │ └── main │ │ │ ├── res │ │ │ ├── drawable-hdpi │ │ │ │ ├── gear.png │ │ │ │ ├── lock.png │ │ │ │ ├── maps.png │ │ │ │ ├── media.png │ │ │ │ ├── radio.png │ │ │ │ ├── voice.png │ │ │ │ ├── arrow_up.png │ │ │ │ ├── bmw_logo.png │ │ │ │ ├── btn_off.png │ │ │ │ ├── btn_on.png │ │ │ │ ├── devices.png │ │ │ │ ├── packet.png │ │ │ │ ├── rpi_logo.png │ │ │ │ ├── unlock.png │ │ │ │ ├── view_bg.png │ │ │ │ ├── arrow_back.png │ │ │ │ ├── arrow_down.png │ │ │ │ ├── arrow_left.png │ │ │ │ ├── background.png │ │ │ │ ├── bmw_emblem.png │ │ │ │ ├── dash_icon.png │ │ │ │ ├── default_bg.jpg │ │ │ │ ├── icon_lock.png │ │ │ │ ├── tablet_bg.png │ │ │ │ ├── bus_activity.png │ │ │ │ ├── ic_launcher.png │ │ │ │ ├── icon_lights.png │ │ │ │ ├── icon_sunroof.png │ │ │ │ ├── icon_volume.png │ │ │ │ ├── default_bg_ibus.jpg │ │ │ │ ├── default_bg_old.jpg │ │ │ │ ├── icon_driverseat.png │ │ │ │ ├── arrow_back_pressed.png │ │ │ │ ├── bmw_emblem_pressed.png │ │ │ │ ├── bmw_logo_pressed.png │ │ │ │ ├── default_bg_radio.jpg │ │ │ │ ├── default_bg_status.jpg │ │ │ │ ├── default_bg_windows.jpg │ │ │ │ ├── icon_window_left.png │ │ │ │ └── icon_window_right.png │ │ │ ├── xml │ │ │ │ └── accessory_filter.xml │ │ │ ├── drawable-mdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── drawable-xhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── drawable-xxhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── drawable-xxxhdpi │ │ │ │ └── ic_launcher.png │ │ │ ├── values-sw600dp │ │ │ │ └── dimens.xml │ │ │ ├── values │ │ │ │ ├── dimens.xml │ │ │ │ ├── strings.xml │ │ │ │ └── styles.xml │ │ │ ├── drawable │ │ │ │ ├── bmw_emblem_selector.xml │ │ │ │ └── button_back_selector.xml │ │ │ ├── menu │ │ │ │ └── activity_main.xml │ │ │ ├── values-sw720dp-land │ │ │ │ └── dimens.xml │ │ │ ├── values-v11 │ │ │ │ └── styles.xml │ │ │ ├── values-v14 │ │ │ │ └── styles.xml │ │ │ └── layout │ │ │ │ ├── devices_row.xml │ │ │ │ ├── activity_devices.xml │ │ │ │ ├── activity_ibus.xml │ │ │ │ ├── activity_radio.xml │ │ │ │ └── activity_main.xml │ │ │ ├── AndroidManifest.xml │ │ │ └── java │ │ │ └── com │ │ │ └── trentseed │ │ │ └── bmw_rpi_ibus_controller │ │ │ ├── AdapterDevices.java │ │ │ ├── ActivityRadio.java │ │ │ ├── ActivityIBUS.java │ │ │ └── AdapterIBUS.java │ └── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── local.properties ├── build.gradle ├── import-summary.txt ├── gradlew.bat └── gradlew ├── connected_car_controller ├── LICENSE.txt ├── README.md ├── test │ ├── __init__.py │ └── unit │ │ ├── __init__.py │ │ ├── controllers │ │ ├── __init__.py │ │ ├── bmw │ │ │ ├── __init__.py │ │ │ └── e46_test.py │ │ └── base_test.py │ │ ├── interfaces │ │ ├── __init__.py │ │ ├── base_test.py │ │ ├── bt_test.py │ │ └── ibus_test.py │ │ └── start_controller_test.py ├── controllers │ ├── __init__.py │ ├── bmw │ │ ├── __init__.py │ │ └── e46.py │ ├── factory.py │ └── base.py ├── interfaces │ ├── __init__.py │ ├── base.py │ ├── canbus.py │ └── bt.py ├── version.py ├── requirements.txt ├── .coveragerc ├── scripts │ └── run_for_e46.sh ├── docker-compose.yml ├── etc │ └── config.ini ├── Dockerfile ├── setup.py ├── start_controller.py └── pavement.py ├── .gitignore └── README.md /connected_car_app/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /connected_car_controller/LICENSE.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /connected_car_controller/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /connected_car_controller/test/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /connected_car_app/common/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /connected_car_controller/controllers/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /connected_car_controller/interfaces/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /connected_car_controller/test/unit/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /connected_car_controller/controllers/bmw/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /connected_car_controller/test/unit/controllers/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /connected_car_controller/test/unit/interfaces/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /connected_car_controller/test/unit/controllers/bmw/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /connected_car_controller/version.py: -------------------------------------------------------------------------------- 1 | __version__ = '2.0.0' 2 | -------------------------------------------------------------------------------- /connected_car_controller/test/unit/interfaces/base_test.py: -------------------------------------------------------------------------------- 1 | import unittest -------------------------------------------------------------------------------- /connected_car_controller/test/unit/interfaces/bt_test.py: -------------------------------------------------------------------------------- 1 | import unittest -------------------------------------------------------------------------------- /connected_car_controller/test/unit/interfaces/ibus_test.py: -------------------------------------------------------------------------------- 1 | import unittest -------------------------------------------------------------------------------- /connected_car_app/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':ibuswear', ':common' 2 | -------------------------------------------------------------------------------- /connected_car_controller/test/unit/controllers/base_test.py: -------------------------------------------------------------------------------- 1 | import unittest -------------------------------------------------------------------------------- /connected_car_controller/test/unit/controllers/bmw/e46_test.py: -------------------------------------------------------------------------------- 1 | import unittest -------------------------------------------------------------------------------- /connected_car_controller/test/unit/start_controller_test.py: -------------------------------------------------------------------------------- 1 | import unittest -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Android/bin/ 2 | Android/gen/ 3 | *.pyc 4 | *.class 5 | java/bin/ 6 | -------------------------------------------------------------------------------- /connected_car_app/app/lint.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /connected_car_controller/requirements.txt: -------------------------------------------------------------------------------- 1 | pyserial==3.0.1 2 | pybluez==0.22 3 | paver==1.3.4 -------------------------------------------------------------------------------- /connected_car_controller/.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | omit = 3 | /Library/* 4 | 5 | [report] 6 | 7 | [html] -------------------------------------------------------------------------------- /connected_car_app/common/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | common 3 | 4 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/libs/gson-2.2.4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/ibuswear/libs/gson-2.2.4.jar -------------------------------------------------------------------------------- /connected_car_app/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/gear.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/gear.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/lock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/lock.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/maps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/maps.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/media.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/media.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/radio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/radio.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/voice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/voice.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/xml/accessory_filter.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/arrow_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/arrow_up.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/bmw_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/bmw_logo.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/btn_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/btn_off.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/btn_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/btn_on.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/devices.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/devices.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/packet.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/packet.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/rpi_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/rpi_logo.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/unlock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/unlock.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/view_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/view_bg.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/arrow_back.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/arrow_back.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/arrow_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/arrow_down.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/arrow_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/arrow_left.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/background.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/bmw_emblem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/bmw_emblem.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/dash_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/dash_icon.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/default_bg.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/default_bg.jpg -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/icon_lock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/icon_lock.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/tablet_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/tablet_bg.png -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/drawable-hdpi/keys.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/ibuswear/src/main/res/drawable-hdpi/keys.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/bus_activity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/bus_activity.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/icon_lights.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/icon_lights.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/icon_sunroof.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/icon_sunroof.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/icon_volume.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/icon_volume.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/default_bg_ibus.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/default_bg_ibus.jpg -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/default_bg_old.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/default_bg_old.jpg -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/icon_driverseat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/icon_driverseat.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/drawable-hdpi/bmw_emblem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/ibuswear/src/main/res/drawable-hdpi/bmw_emblem.png -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/drawable-hdpi/button_up.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/ibuswear/src/main/res/drawable-hdpi/button_up.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/arrow_back_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/arrow_back_pressed.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/bmw_emblem_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/bmw_emblem_pressed.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/bmw_logo_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/bmw_logo_pressed.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/default_bg_radio.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/default_bg_radio.jpg -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/default_bg_status.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/default_bg_status.jpg -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/default_bg_windows.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/default_bg_windows.jpg -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/icon_window_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/icon_window_left.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable-hdpi/icon_window_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/app/src/main/res/drawable-hdpi/icon_window_right.png -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/drawable-hdpi/button_down.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/ibuswear/src/main/res/drawable-hdpi/button_down.png -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/drawable-hdpi/button_exit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/ibuswear/src/main/res/drawable-hdpi/button_exit.png -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/drawable-hdpi/button_lock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/ibuswear/src/main/res/drawable-hdpi/button_lock.png -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/drawable-hdpi/button_unlock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/ibuswear/src/main/res/drawable-hdpi/button_unlock.png -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/drawable-hdpi/button_voice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/ibuswear/src/main/res/drawable-hdpi/button_voice.png -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/drawable-hdpi/button_volume.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/ibuswear/src/main/res/drawable-hdpi/button_volume.png -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/ibuswear/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/ibuswear/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/ibuswear/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/ibuswear/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/drawable-hdpi/bmw_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/ibuswear/src/main/res/drawable-hdpi/bmw_background.png -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/drawable-hdpi/button_sunroof.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/ibuswear/src/main/res/drawable-hdpi/button_sunroof.png -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/drawable-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/ibuswear/src/main/res/drawable-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/drawable-hdpi/about_background.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/ibuswear/src/main/res/drawable-hdpi/about_background.png -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/drawable-hdpi/bmw_emblem_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/ibuswear/src/main/res/drawable-hdpi/bmw_emblem_pressed.png -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/drawable-hdpi/button_driver_seat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/ibuswear/src/main/res/drawable-hdpi/button_driver_seat.png -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/drawable-hdpi/window_front_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/ibuswear/src/main/res/drawable-hdpi/window_front_left.png -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/drawable-hdpi/window_front_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/ibuswear/src/main/res/drawable-hdpi/window_front_right.png -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/drawable-hdpi/window_rear_left.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/ibuswear/src/main/res/drawable-hdpi/window_rear_left.png -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/drawable-hdpi/window_rear_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/HEAD/connected_car_app/ibuswear/src/main/res/drawable-hdpi/window_rear_right.png -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/values-sw600dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16dp 5 | 16dp 6 | 7 | 8 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16dp 5 | 16dp 6 | 7 | 8 | -------------------------------------------------------------------------------- /connected_car_app/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sun Mar 24 12:23:50 PDT 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip 7 | -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable/bmw_emblem_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/drawable/button_back_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/menu/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/values-sw720dp-land/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 128dp 8 | 9 | 10 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/layout/round.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Connected Car 5 | Settings 6 | Hello world! 7 | BMW E46 IBUS Communication 8 | 9 | 10 | -------------------------------------------------------------------------------- /connected_car_controller/scripts/run_for_e46.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Executes the core application for the vehicle controller. This process 3 | # is run in the background, and does not block the terminal. All output is 4 | # redirected to '/dev/null' 5 | echo running 'nohup python start_controller.py bmw-e46 2>/dev/null 1>/dev/null &' 6 | nohup python start_controller.py bmw-e46 2>/dev/null 1>/dev/null & 7 | -------------------------------------------------------------------------------- /connected_car_controller/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | car_controller: 5 | container_name: car_controller 6 | privileged: true 7 | network_mode: host 8 | restart: always 9 | build: 10 | context: . 11 | volumes: 12 | - "./:/opt/car-controller" 13 | - "/var/run/sdp:/var/run/sdp" 14 | devices: 15 | - "/dev/ttyUSB0:/dev/ttyUSB0" -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/values-v11/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /connected_car_app/common/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/values-v11/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /connected_car_controller/etc/config.ini: -------------------------------------------------------------------------------- 1 | [interfaces.bluetooth] 2 | service_name = ConnectedCar 3 | service_uuid = 94f39d29-7d6d-437d-973b-fba39e49d4ee 4 | read_buffer_length = 2048 5 | 6 | [interfaces.ibus] 7 | baudrate = 9600 8 | port = /dev/ttyUSB0 9 | timeout = 1 10 | read_buffer_length = 9999 11 | 12 | [interfaces.canbus] 13 | baudrate = 38400 14 | port = /dev/cu.usbserial-113010821422 15 | timeout = 1 16 | read_buffer_length = 9999 17 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Connected Car 5 | Hello world! 6 | Settings 7 | 8 | 9 | Hello blank fragment 10 | 11 | 12 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 64dp 9 | 10 | 11 | -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/values-v14/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/menu/activity_main.xml: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/values-v14/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /connected_car_controller/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.7.2-stretch 2 | 3 | MAINTAINER Trent Seed 4 | 5 | RUN apt-get -y update 6 | 7 | RUN apt-get -y install build-essential bluez bluez-tools libbluetooth-dev 8 | 9 | WORKDIR /opt/car-controller 10 | 11 | COPY requirements.txt /opt/car-controller 12 | RUN pip3 install -r /opt/car-controller/requirements.txt 13 | 14 | COPY . /opt/car-controller 15 | 16 | CMD ["python3", "/opt/car-controller/start_controller.py", "bmw-e46"] -------------------------------------------------------------------------------- /connected_car_controller/setup.py: -------------------------------------------------------------------------------- 1 | """ 2 | The setup.py module is responsible for describing the metadata necessary 3 | for building and installing the Python project. 4 | """ 5 | from distutils.core import setup 6 | from version import __version__ 7 | 8 | 9 | setup( 10 | name='ConnectedCarController', 11 | version=__version__, 12 | packages=['controllers', 'interfaces', ], 13 | license=open('LICENSE.txt').read(), 14 | author='Trent Seed', 15 | author_email='hi@trentseed.com' 16 | ) 17 | -------------------------------------------------------------------------------- /connected_car_controller/controllers/factory.py: -------------------------------------------------------------------------------- 1 | import logging 2 | 3 | 4 | from controllers.bmw.e46 import E46Controller 5 | 6 | 7 | LOGGER = logging.getLogger(__name__) 8 | 9 | 10 | class ControllerFactory(object): 11 | """Factory class to instantiate controllers provided the type.""" 12 | 13 | @staticmethod 14 | def create(controller_type): 15 | if controller_type == 'bmw-e46': 16 | return E46Controller() 17 | 18 | LOGGER.error('controller not supported - %r', controller_type) 19 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/layout/keys.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /connected_car_app/local.properties: -------------------------------------------------------------------------------- 1 | ## This file is automatically generated by Android Studio. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must *NOT* be checked into Version Control Systems, 5 | # as it contains information specific to your local configuration. 6 | # 7 | # Location of the SDK. This is only used by Gradle. 8 | # For customization when using a Version Control System, please read the 9 | # header note. 10 | #Fri Mar 22 14:35:30 PDT 2019 11 | ndk.dir=/Users/trentseed/Library/Android/sdk/ndk-bundle 12 | sdk.dir=/Users/trentseed/Library/Android/sdk 13 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/layout/exit.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/layout/keys_lock.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/layout/voice.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/layout/volume.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/layout/about.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 11 | 12 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/layout/sunroof.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/layout/window_action_up.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/layout/driver_seat.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/layout/keys_unlock.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/layout/window_action_down.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /connected_car_app/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | buildscript { 3 | repositories { 4 | jcenter() 5 | maven { 6 | url 'https://maven.google.com/' 7 | name 'Google' 8 | } 9 | } 10 | dependencies { 11 | classpath 'com.android.tools.build:gradle:3.3.2' 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | maven { 19 | url 'https://maven.google.com/' 20 | name 'Google' 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/layout/window_back_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/layout/window_back_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/layout/window_front_left.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/layout/window_front_right.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/java/com/trentseed/bmw_rpi_ibus_controller/wear/FragmentKeys.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller.wear; 2 | 3 | import android.os.Bundle; 4 | import android.app.Fragment; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | public class FragmentKeys extends Fragment { 10 | @Override 11 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 12 | Bundle savedInstanceState) { 13 | // Inflate the layout for this fragment 14 | return inflater.inflate(R.layout.keys, container, false); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/java/com/trentseed/bmw_rpi_ibus_controller/wear/FragmentAbout.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller.wear; 2 | 3 | import android.os.Bundle; 4 | import android.app.Fragment; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | public class FragmentAbout extends Fragment { 10 | @Override 11 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 12 | Bundle savedInstanceState) { 13 | 14 | // Inflate the layout for this fragment 15 | return inflater.inflate(R.layout.about, container, false); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /connected_car_app/common/src/main/java/com/trentseed/bmw_rpi_ibus_controller/common/ControllerMessage.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller.common; 2 | 3 | import com.google.gson.Gson; 4 | 5 | /** 6 | * Data structure that encapsulates ibus packets which are sent between Android and 7 | * Raspberry Pi controller. 8 | */ 9 | public class ControllerMessage { 10 | 11 | String data; 12 | 13 | public ControllerMessage(){} 14 | 15 | public IBUSPacket[] getIBUSPackets(){ 16 | try{ 17 | return new Gson().fromJson(this.data, IBUSPacket[].class); 18 | }catch(Exception e){ 19 | e.printStackTrace(); 20 | return null; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /connected_car_app/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 28 5 | 6 | defaultConfig { 7 | applicationId "com.trentseed.bmw_rpi_ibus_controller" 8 | minSdkVersion 20 9 | targetSdkVersion 26 10 | } 11 | 12 | buildTypes { 13 | release { 14 | minifyEnabled false 15 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt' 16 | } 17 | } 18 | } 19 | 20 | dependencies { 21 | implementation 'com.google.code.gson:gson:2.8.2' 22 | wearApp project(':ibuswear') 23 | implementation project(':common') 24 | implementation 'androidx.recyclerview:recyclerview:1.0.0' 25 | } 26 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/java/com/trentseed/bmw_rpi_ibus_controller/wear/FragmentVolume.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller.wear; 2 | 3 | import android.app.Fragment; 4 | import android.os.Bundle; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | public class FragmentVolume extends Fragment { 10 | @Override 11 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 12 | Bundle savedInstanceState) { 13 | // Inflate the layout for this fragment 14 | ActivityMain.parent_page_id = IBUSGridPagerAdapter.PAGE_VOLUME_LANDING; 15 | return inflater.inflate(R.layout.volume, container, false); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/java/com/trentseed/bmw_rpi_ibus_controller/wear/FragmentSunroof.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller.wear; 2 | 3 | import android.app.Fragment; 4 | import android.os.Bundle; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | public class FragmentSunroof extends Fragment { 10 | @Override 11 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 12 | Bundle savedInstanceState) { 13 | // Inflate the layout for this fragment 14 | ActivityMain.parent_page_id = IBUSGridPagerAdapter.PAGE_SUNROOF_LANDING; 15 | return inflater.inflate(R.layout.sunroof, container, false); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/java/com/trentseed/bmw_rpi_ibus_controller/wear/FragmentDriverSeat.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller.wear; 2 | 3 | import android.app.Fragment; 4 | import android.os.Bundle; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | public class FragmentDriverSeat extends Fragment { 10 | @Override 11 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 12 | Bundle savedInstanceState) { 13 | // Inflate the layout for this fragment 14 | ActivityMain.parent_page_id = IBUSGridPagerAdapter.PAGE_DRIVER_SEAT_LANDING; 15 | return inflater.inflate(R.layout.driver_seat, container, false); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/trentseed/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/java/com/trentseed/bmw_rpi_ibus_controller/wear/FragmentWindowBackLeft.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller.wear; 2 | 3 | import android.os.Bundle; 4 | import android.app.Fragment; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | public class FragmentWindowBackLeft extends Fragment { 10 | @Override 11 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 12 | Bundle savedInstanceState) { 13 | // Inflate the layout for this fragment 14 | ActivityMain.parent_page_id = IBUSGridPagerAdapter.PAGE_REAR_LEFT_LANDING; 15 | return inflater.inflate(R.layout.window_back_left, container, false); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/java/com/trentseed/bmw_rpi_ibus_controller/wear/FragmentWindowBackRight.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller.wear; 2 | 3 | import android.os.Bundle; 4 | import android.app.Fragment; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | public class FragmentWindowBackRight extends Fragment { 10 | @Override 11 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 12 | Bundle savedInstanceState) { 13 | // Inflate the layout for this fragment 14 | ActivityMain.parent_page_id = IBUSGridPagerAdapter.PAGE_REAR_RIGHT_LANDING; 15 | return inflater.inflate(R.layout.window_back_right, container, false); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/java/com/trentseed/bmw_rpi_ibus_controller/wear/FragmentWindowFrontLeft.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller.wear; 2 | 3 | import android.os.Bundle; 4 | import android.app.Fragment; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | public class FragmentWindowFrontLeft extends Fragment { 10 | @Override 11 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 12 | Bundle savedInstanceState) { 13 | // Inflate the layout for this fragment 14 | ActivityMain.parent_page_id = IBUSGridPagerAdapter.PAGE_DRIVER_LANDING; 15 | return inflater.inflate(R.layout.window_front_left, container, false); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/java/com/trentseed/bmw_rpi_ibus_controller/wear/FragmentWindowFrontRight.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller.wear; 2 | 3 | import android.os.Bundle; 4 | import android.app.Fragment; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | public class FragmentWindowFrontRight extends Fragment { 10 | @Override 11 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 12 | Bundle savedInstanceState) { 13 | // Inflate the layout for this fragment 14 | ActivityMain.parent_page_id = IBUSGridPagerAdapter.PAGE_PASSENGER_LANDING; 15 | return inflater.inflate(R.layout.window_front_right, container, false); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 14 | 15 | 16 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 14 | 15 | 16 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | 4 | android { 5 | compileSdkVersion 26 6 | 7 | defaultConfig { 8 | applicationId "com.trentseed.bmw_rpi_ibus_controller" 9 | minSdkVersion 23 10 | targetSdkVersion 26 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled false 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | implementation 'com.google.code.gson:gson:2.8.2' 24 | implementation 'com.google.android.support:wearable:2.4.0' 25 | compileOnly 'com.google.android.wearable:wearable:2.4.0' 26 | implementation project(':common') 27 | } 28 | 29 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/layout/rect.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 13 | 14 | 19 | 20 | -------------------------------------------------------------------------------- /connected_car_app/common/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /connected_car_app/common/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 26 5 | 6 | defaultConfig { 7 | minSdkVersion 20 8 | targetSdkVersion 26 9 | versionCode 1 10 | versionName "1.0" 11 | 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | 14 | } 15 | 16 | buildTypes { 17 | release { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 20 | } 21 | } 22 | 23 | } 24 | 25 | dependencies { 26 | implementation fileTree(include: ['*.jar'], dir: 'libs') 27 | implementation 'com.google.code.gson:gson:2.8.2' 28 | testImplementation 'junit:junit:4.12' 29 | androidTestImplementation 'com.android.support.test:runner:1.0.2' 30 | androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' 31 | } 32 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/res/layout/welcome.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 13 | 14 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 14 | 15 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/java/com/trentseed/bmw_rpi_ibus_controller/wear/FragmentKeysLock.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller.wear; 2 | 3 | import android.os.Bundle; 4 | import android.app.Fragment; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | 10 | import com.trentseed.bmw_rpi_ibus_controller.common.IBUSWrapper; 11 | 12 | public class FragmentKeysLock extends Fragment { 13 | 14 | ImageView imgBtnLock; 15 | 16 | @Override 17 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 18 | Bundle savedInstanceState) { 19 | // Inflate the layout for this fragment 20 | View rootView = inflater.inflate(R.layout.keys_lock, container, false); 21 | imgBtnLock = rootView.findViewById(R.id.imgBtnLock); 22 | imgBtnLock.setOnClickListener(new View.OnClickListener() { 23 | @Override 24 | public void onClick(View v) { 25 | try{ 26 | IBUSWrapper.lockCar(); 27 | } catch (Exception e){ 28 | e.printStackTrace(); 29 | } 30 | } 31 | }); 32 | return rootView; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/java/com/trentseed/bmw_rpi_ibus_controller/wear/FragmentKeysUnlock.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller.wear; 2 | 3 | import android.os.Bundle; 4 | import android.app.Fragment; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | 10 | import com.trentseed.bmw_rpi_ibus_controller.common.IBUSWrapper; 11 | 12 | public class FragmentKeysUnlock extends Fragment { 13 | 14 | ImageView imgBtnUnlock; 15 | 16 | @Override 17 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 18 | Bundle savedInstanceState) { 19 | // Inflate the layout for this fragment 20 | View rootView = inflater.inflate(R.layout.keys_unlock, container, false); 21 | imgBtnUnlock = rootView.findViewById(R.id.imgBtnUnlock); 22 | imgBtnUnlock.setOnClickListener(new View.OnClickListener() { 23 | @Override 24 | public void onClick(View v) { 25 | try{ 26 | IBUSWrapper.unlockCar(); 27 | } catch (Exception e){ 28 | e.printStackTrace(); 29 | } 30 | } 31 | }); 32 | return rootView; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/java/com/trentseed/bmw_rpi_ibus_controller/wear/FragmentExit.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller.wear; 2 | 3 | import android.app.Fragment; 4 | import android.os.Bundle; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | 10 | import com.trentseed.bmw_rpi_ibus_controller.common.BluetoothInterface; 11 | 12 | public class FragmentExit extends Fragment { 13 | 14 | ImageView imgBtnClose; 15 | 16 | @Override 17 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 18 | Bundle savedInstanceState) { 19 | 20 | // Inflate the layout for this fragment 21 | View rootView = inflater.inflate(R.layout.exit, container, false); 22 | imgBtnClose = rootView.findViewById(R.id.imgBtnExit); 23 | imgBtnClose.setOnClickListener(new View.OnClickListener() { 24 | @Override 25 | public void onClick(View v) { 26 | BluetoothInterface.disconnect(); 27 | getActivity().finish(); 28 | } 29 | }); 30 | 31 | return rootView; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/java/com/trentseed/bmw_rpi_ibus_controller/wear/FragmentWindowBackLeftActionUp.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller.wear; 2 | 3 | import android.os.Bundle; 4 | import android.app.Fragment; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | 10 | import com.trentseed.bmw_rpi_ibus_controller.common.IBUSWrapper; 11 | 12 | public class FragmentWindowBackLeftActionUp extends Fragment { 13 | 14 | ImageView imgBtnUp; 15 | 16 | @Override 17 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 18 | Bundle savedInstanceState) { 19 | // Inflate the layout for this fragment 20 | View rootView = inflater.inflate(R.layout.window_action_up, container, false); 21 | imgBtnUp = rootView.findViewById(R.id.btn_up); 22 | imgBtnUp.setOnClickListener(new View.OnClickListener() { 23 | @Override 24 | public void onClick(View v) { 25 | try{ 26 | IBUSWrapper.windowDriverRear(false); 27 | }catch (Exception e){ 28 | e.printStackTrace(); 29 | } 30 | } 31 | }); 32 | return rootView; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/java/com/trentseed/bmw_rpi_ibus_controller/wear/FragmentWindowFrontLeftActionUp.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller.wear; 2 | 3 | import android.os.Bundle; 4 | import android.app.Fragment; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | 10 | import com.trentseed.bmw_rpi_ibus_controller.common.IBUSWrapper; 11 | 12 | public class FragmentWindowFrontLeftActionUp extends Fragment { 13 | 14 | ImageView imgBtnUp; 15 | 16 | @Override 17 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 18 | Bundle savedInstanceState) { 19 | // Inflate the layout for this fragment 20 | View rootView = inflater.inflate(R.layout.window_action_up, container, false); 21 | imgBtnUp = rootView.findViewById(R.id.btn_up); 22 | imgBtnUp.setOnClickListener(new View.OnClickListener() { 23 | @Override 24 | public void onClick(View v) { 25 | try{ 26 | IBUSWrapper.windowDriverFront(false); 27 | }catch (Exception e){ 28 | e.printStackTrace(); 29 | } 30 | } 31 | }); 32 | return rootView; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/java/com/trentseed/bmw_rpi_ibus_controller/wear/FragmentWindowBackRightActionUp.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller.wear; 2 | 3 | import android.os.Bundle; 4 | import android.app.Fragment; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | 10 | import com.trentseed.bmw_rpi_ibus_controller.common.IBUSWrapper; 11 | 12 | public class FragmentWindowBackRightActionUp extends Fragment { 13 | 14 | ImageView imgBtnUp; 15 | 16 | @Override 17 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 18 | Bundle savedInstanceState) { 19 | // Inflate the layout for this fragment 20 | View rootView = inflater.inflate(R.layout.window_action_up, container, false); 21 | imgBtnUp = rootView.findViewById(R.id.btn_up); 22 | imgBtnUp.setOnClickListener(new View.OnClickListener() { 23 | @Override 24 | public void onClick(View v) { 25 | try{ 26 | IBUSWrapper.windowPassengerRear(false); 27 | }catch (Exception e){ 28 | e.printStackTrace(); 29 | } 30 | } 31 | }); 32 | return rootView; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/java/com/trentseed/bmw_rpi_ibus_controller/wear/FragmentWindowFrontRightActionUp.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller.wear; 2 | 3 | import android.os.Bundle; 4 | import android.app.Fragment; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | 10 | import com.trentseed.bmw_rpi_ibus_controller.common.IBUSWrapper; 11 | 12 | public class FragmentWindowFrontRightActionUp extends Fragment { 13 | 14 | ImageView imgBtnUp; 15 | 16 | @Override 17 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 18 | Bundle savedInstanceState) { 19 | // Inflate the layout for this fragment 20 | View rootView = inflater.inflate(R.layout.window_action_up, container, false); 21 | imgBtnUp = rootView.findViewById(R.id.btn_up); 22 | imgBtnUp.setOnClickListener(new View.OnClickListener() { 23 | @Override 24 | public void onClick(View v) { 25 | try{ 26 | IBUSWrapper.windowPassengerFront(false); 27 | }catch (Exception e){ 28 | e.printStackTrace(); 29 | } 30 | } 31 | }); 32 | return rootView; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/java/com/trentseed/bmw_rpi_ibus_controller/wear/FragmentWindowBackLeftActionDown.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller.wear; 2 | 3 | import android.os.Bundle; 4 | import android.app.Fragment; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | 10 | import com.trentseed.bmw_rpi_ibus_controller.common.IBUSWrapper; 11 | 12 | public class FragmentWindowBackLeftActionDown extends Fragment { 13 | 14 | ImageView imgBtnDown; 15 | 16 | @Override 17 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 18 | Bundle savedInstanceState) { 19 | // Inflate the layout for this fragment 20 | View rootView = inflater.inflate(R.layout.window_action_down, container, false); 21 | imgBtnDown = rootView.findViewById(R.id.btn_down); 22 | imgBtnDown.setOnClickListener(new View.OnClickListener() { 23 | @Override 24 | public void onClick(View v) { 25 | try{ 26 | IBUSWrapper.windowDriverRear(true); 27 | }catch (Exception e){ 28 | e.printStackTrace(); 29 | } 30 | } 31 | }); 32 | return rootView; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/java/com/trentseed/bmw_rpi_ibus_controller/wear/FragmentWindowFrontLeftActionDown.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller.wear; 2 | 3 | import android.os.Bundle; 4 | import android.app.Fragment; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | 10 | import com.trentseed.bmw_rpi_ibus_controller.common.IBUSWrapper; 11 | 12 | public class FragmentWindowFrontLeftActionDown extends Fragment { 13 | 14 | ImageView imgBtnDown; 15 | 16 | @Override 17 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 18 | Bundle savedInstanceState) { 19 | // Inflate the layout for this fragment 20 | View rootView = inflater.inflate(R.layout.window_action_down, container, false); 21 | imgBtnDown = rootView.findViewById(R.id.btn_down); 22 | imgBtnDown.setOnClickListener(new View.OnClickListener() { 23 | @Override 24 | public void onClick(View v) { 25 | try{ 26 | IBUSWrapper.windowDriverFront(true); 27 | }catch (Exception e){ 28 | e.printStackTrace(); 29 | } 30 | } 31 | }); 32 | return rootView; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/java/com/trentseed/bmw_rpi_ibus_controller/wear/FragmentWindowBackRightActionDown.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller.wear; 2 | 3 | import android.os.Bundle; 4 | import android.app.Fragment; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | 10 | import com.trentseed.bmw_rpi_ibus_controller.common.IBUSWrapper; 11 | 12 | public class FragmentWindowBackRightActionDown extends Fragment { 13 | 14 | ImageView imgBtnDown; 15 | 16 | @Override 17 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 18 | Bundle savedInstanceState) { 19 | // Inflate the layout for this fragment 20 | View rootView = inflater.inflate(R.layout.window_action_down, container, false); 21 | imgBtnDown = rootView.findViewById(R.id.btn_down); 22 | imgBtnDown.setOnClickListener(new View.OnClickListener() { 23 | @Override 24 | public void onClick(View v) { 25 | try{ 26 | IBUSWrapper.windowPassengerRear(true); 27 | }catch (Exception e){ 28 | e.printStackTrace(); 29 | } 30 | } 31 | }); 32 | return rootView; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/java/com/trentseed/bmw_rpi_ibus_controller/wear/FragmentWindowFrontRightActionDown.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller.wear; 2 | 3 | import android.os.Bundle; 4 | import android.app.Fragment; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | 10 | import com.trentseed.bmw_rpi_ibus_controller.common.IBUSWrapper; 11 | 12 | public class FragmentWindowFrontRightActionDown extends Fragment { 13 | 14 | ImageView imgBtnDown; 15 | 16 | @Override 17 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 18 | Bundle savedInstanceState) { 19 | // Inflate the layout for this fragment 20 | View rootView = inflater.inflate(R.layout.window_action_down, container, false); 21 | imgBtnDown = rootView.findViewById(R.id.btn_down); 22 | imgBtnDown.setOnClickListener(new View.OnClickListener() { 23 | @Override 24 | public void onClick(View v) { 25 | try{ 26 | IBUSWrapper.windowPassengerFront(true); 27 | }catch (Exception e){ 28 | e.printStackTrace(); 29 | } 30 | } 31 | }); 32 | return rootView; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/java/com/trentseed/bmw_rpi_ibus_controller/wear/FragmentVolumeDown.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller.wear; 2 | 3 | import android.app.Fragment; 4 | import android.os.Bundle; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | 10 | import com.trentseed.bmw_rpi_ibus_controller.common.IBUSWrapper; 11 | 12 | public class FragmentVolumeDown extends Fragment { 13 | 14 | ImageView imgBtnDown; 15 | 16 | @Override 17 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 18 | Bundle savedInstanceState) { 19 | // Inflate the layout for this fragment 20 | ActivityMain.parent_page_id = IBUSGridPagerAdapter.PAGE_VOLUME_DOWN; 21 | View rootView = inflater.inflate(R.layout.window_action_down, container, false); 22 | imgBtnDown = rootView.findViewById(R.id.btn_down); 23 | imgBtnDown.setOnClickListener(new View.OnClickListener() { 24 | @Override 25 | public void onClick(View v) { 26 | try{ 27 | IBUSWrapper.volumeDown(); 28 | }catch (Exception e){ 29 | e.printStackTrace(); 30 | } 31 | } 32 | }); 33 | return rootView; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/java/com/trentseed/bmw_rpi_ibus_controller/wear/FragmentVolumeUp.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller.wear; 2 | 3 | import android.app.Fragment; 4 | import android.os.Bundle; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | 10 | import com.trentseed.bmw_rpi_ibus_controller.common.IBUSWrapper; 11 | 12 | public class FragmentVolumeUp extends Fragment { 13 | 14 | ImageView imgBtnUp; 15 | 16 | @Override 17 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 18 | Bundle savedInstanceState) { 19 | // Inflate the layout for this fragment 20 | ActivityMain.parent_page_id = IBUSGridPagerAdapter.PAGE_VOLUME_UP; 21 | View rootView = inflater.inflate(R.layout.window_action_up, container, false); 22 | imgBtnUp = rootView.findViewById(R.id.btn_up); 23 | imgBtnUp.setOnClickListener(new View.OnClickListener() { 24 | @Override 25 | public void onClick(View v) { 26 | try{ 27 | IBUSWrapper.volumeUp(); 28 | }catch (Exception e){ 29 | e.printStackTrace(); 30 | } 31 | } 32 | }); 33 | return rootView; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/java/com/trentseed/bmw_rpi_ibus_controller/wear/FragmentSunroofOpen.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller.wear; 2 | 3 | import android.app.Fragment; 4 | import android.os.Bundle; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | 10 | import com.trentseed.bmw_rpi_ibus_controller.common.IBUSWrapper; 11 | 12 | public class FragmentSunroofOpen extends Fragment { 13 | 14 | ImageView imgBtnUp; 15 | 16 | @Override 17 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 18 | Bundle savedInstanceState) { 19 | // Inflate the layout for this fragment 20 | ActivityMain.parent_page_id = IBUSGridPagerAdapter.PAGE_SUNROOF_OPEN; 21 | View rootView = inflater.inflate(R.layout.window_action_up, container, false); 22 | imgBtnUp = rootView.findViewById(R.id.btn_up); 23 | imgBtnUp.setOnClickListener(new View.OnClickListener() { 24 | @Override 25 | public void onClick(View v) { 26 | try{ 27 | IBUSWrapper.toggleSunroof(true); 28 | }catch (Exception e){ 29 | e.printStackTrace(); 30 | } 31 | } 32 | }); 33 | return rootView; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/java/com/trentseed/bmw_rpi_ibus_controller/wear/FragmentSunroofClose.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller.wear; 2 | 3 | import android.app.Fragment; 4 | import android.os.Bundle; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | 10 | import com.trentseed.bmw_rpi_ibus_controller.common.IBUSWrapper; 11 | 12 | public class FragmentSunroofClose extends Fragment { 13 | 14 | ImageView imgBtnDown; 15 | 16 | @Override 17 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 18 | Bundle savedInstanceState) { 19 | // Inflate the layout for this fragment 20 | ActivityMain.parent_page_id = IBUSGridPagerAdapter.PAGE_SUNROOF_CLOSE; 21 | View rootView = inflater.inflate(R.layout.window_action_down, container, false); 22 | imgBtnDown = rootView.findViewById(R.id.btn_down); 23 | imgBtnDown.setOnClickListener(new View.OnClickListener() { 24 | @Override 25 | public void onClick(View v) { 26 | try{ 27 | IBUSWrapper.toggleSunroof(false); 28 | }catch (Exception e){ 29 | e.printStackTrace(); 30 | } 31 | } 32 | }); 33 | return rootView; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/java/com/trentseed/bmw_rpi_ibus_controller/wear/FragmentDriverSeatBack.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller.wear; 2 | 3 | import android.app.Fragment; 4 | import android.os.Bundle; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | 10 | import com.trentseed.bmw_rpi_ibus_controller.common.IBUSWrapper; 11 | 12 | public class FragmentDriverSeatBack extends Fragment { 13 | 14 | ImageView imgBtnDown; 15 | 16 | @Override 17 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 18 | Bundle savedInstanceState) { 19 | // Inflate the layout for this fragment 20 | ActivityMain.parent_page_id = IBUSGridPagerAdapter.PAGE_DRIVER_SEAT_BACK; 21 | View rootView = inflater.inflate(R.layout.window_action_down, container, false); 22 | imgBtnDown = rootView.findViewById(R.id.btn_down); 23 | imgBtnDown.setOnClickListener(new View.OnClickListener() { 24 | @Override 25 | public void onClick(View v) { 26 | try{ 27 | IBUSWrapper.moveDriverSeat(false); 28 | }catch (Exception e){ 29 | e.printStackTrace(); 30 | } 31 | } 32 | }); 33 | return rootView; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/java/com/trentseed/bmw_rpi_ibus_controller/wear/FragmentDriverSeatForward.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller.wear; 2 | 3 | import android.app.Fragment; 4 | import android.os.Bundle; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | 10 | import com.trentseed.bmw_rpi_ibus_controller.common.IBUSWrapper; 11 | 12 | public class FragmentDriverSeatForward extends Fragment { 13 | 14 | ImageView imgBtnUp; 15 | 16 | @Override 17 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 18 | Bundle savedInstanceState) { 19 | // Inflate the layout for this fragment 20 | ActivityMain.parent_page_id = IBUSGridPagerAdapter.PAGE_DRIVER_SEAT_FORWARD; 21 | View rootView = inflater.inflate(R.layout.window_action_up, container, false); 22 | imgBtnUp = rootView.findViewById(R.id.btn_up); 23 | imgBtnUp.setOnClickListener(new View.OnClickListener() { 24 | @Override 25 | public void onClick(View v) { 26 | try{ 27 | IBUSWrapper.moveDriverSeat(true); 28 | }catch (Exception e){ 29 | e.printStackTrace(); 30 | } 31 | } 32 | }); 33 | return rootView; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /connected_car_controller/controllers/base.py: -------------------------------------------------------------------------------- 1 | """ 2 | The controllers.base module contains logic common to all BaseController implementations. 3 | """ 4 | import logging 5 | import sys 6 | import signal 7 | import time 8 | 9 | 10 | LOGGER = logging.getLogger(__name__) 11 | 12 | 13 | class ControllerStates(object): 14 | """The various states that an interface can experience.""" 15 | STATE_STOPPED = 0 16 | STATE_RUNNING = 1 17 | 18 | 19 | class BaseController(object): 20 | """The base class for implementing a controller type.""" 21 | 22 | __controller_name__ = None 23 | __states__ = ControllerStates 24 | 25 | def __init__(self): 26 | self.state = self.__states__.STATE_STOPPED 27 | 28 | def start(self): 29 | """Invoked when the controller is starting.""" 30 | raise NotImplementedError 31 | 32 | def stop(self): 33 | """Invoked when the controller should stop.""" 34 | raise NotImplementedError 35 | 36 | def restart(self): 37 | """Restarts the controller to establish fresh interface connections.""" 38 | LOGGER.info('restarting the controller...') 39 | self.stop() 40 | self.start() 41 | 42 | @staticmethod 43 | def loop_until_ctrl_c(): 44 | """Performs an infinite loop, waiting for "Ctrl-C" to exit the application.""" 45 | LOGGER.info('press "ctrl-c" to exit the application...') 46 | signal.signal(signal.SIGINT, lambda x, y: sys.exit(0)) 47 | while True: 48 | time.sleep(1) 49 | 50 | 51 | -------------------------------------------------------------------------------- /connected_car_app/common/src/main/java/com/trentseed/bmw_rpi_ibus_controller/common/WakeLocker.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller.common; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.os.PowerManager; 6 | 7 | import java.lang.NullPointerException; 8 | 9 | /** 10 | * This class handles device sleep/wake lock features. Utilized 11 | * by GCMIntentService. 12 | */ 13 | public abstract class WakeLocker { 14 | 15 | private static PowerManager.WakeLock wakeLock; 16 | private final static String tag = "app:WakeLock"; 17 | 18 | /** 19 | * Acquire handle and wake device 20 | * @param context 21 | */ 22 | @SuppressWarnings("deprecation") 23 | @SuppressLint("Wakelock") 24 | public static void acquire(Context context) { 25 | if (wakeLock != null) release(); 26 | PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE); 27 | 28 | try { 29 | wakeLock = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK | 30 | PowerManager.ACQUIRE_CAUSES_WAKEUP | 31 | PowerManager.ON_AFTER_RELEASE, tag); 32 | wakeLock.acquire(); 33 | }catch (NullPointerException e){ 34 | e.printStackTrace(); 35 | } 36 | 37 | } 38 | 39 | /** 40 | * Release handle, allowing device to sleep 41 | */ 42 | private static void release() { 43 | if (wakeLock != null){ 44 | wakeLock.release(); 45 | wakeLock = null; 46 | } 47 | } 48 | } -------------------------------------------------------------------------------- /connected_car_controller/start_controller.py: -------------------------------------------------------------------------------- 1 | """ 2 | The start_controller.py module serves as the main entry point to the connected car application. 3 | When this module is run from the command line, a signal handler will be attached to Ctrl+C so 4 | we can interrupt and exit the application. 5 | 6 | Example 7 | ------- 8 | $ python3 start_controller.py bmw-e46 9 | 10 | """ 11 | import logging 12 | import sys 13 | import argparse 14 | 15 | 16 | from controllers.factory import ControllerFactory 17 | from version import __version__ 18 | 19 | 20 | LOGGER = logging.getLogger(__name__) 21 | 22 | 23 | def start_controller(controller_type): 24 | """ 25 | Responsible for initializing a controller instance, which will subsequently initialize 26 | the necessary core services for the vehicle data bus and client devices e.g. bluetooth. 27 | """ 28 | LOGGER.info('connected car controller - version: %s', __version__) 29 | controller = ControllerFactory.create(controller_type) 30 | 31 | if not controller: 32 | LOGGER.error("[ERROR] invalid controller, exiting...") 33 | sys.exit(2) 34 | 35 | controller.start() 36 | 37 | 38 | if __name__ == "__main__": 39 | # setup logging 40 | log_format = '%(asctime)s [%(levelname)s] [%(filename)s] [%(lineno)s] %(message)s' 41 | logging.basicConfig(level=logging.DEBUG, format=log_format) 42 | 43 | # parse command line arguments 44 | parser = argparse.ArgumentParser() 45 | parser.add_argument("controller_type", help="The name of the controller, for example 'bmw-e46'") 46 | args = parser.parse_args() 47 | 48 | # start the controller 49 | start_controller(args.controller_type) 50 | -------------------------------------------------------------------------------- /connected_car_controller/controllers/bmw/e46.py: -------------------------------------------------------------------------------- 1 | """ 2 | The e46.py module is responsible for BMW E46 vehicles. 3 | 4 | Car Production: March 1998 - February 2005 5 | Reference: https://en.wikipedia.org/wiki/BMW_3_Series_(E46) 6 | 7 | """ 8 | import logging 9 | 10 | from controllers.base import BaseController 11 | 12 | from interfaces.ibus import IBUSInterface 13 | from interfaces.bt import BluetoothInterface 14 | 15 | 16 | LOGGER = logging.getLogger(__name__) 17 | 18 | 19 | class E46Controller(BaseController): 20 | """Controller definition for BMW E46 Vehicles""" 21 | 22 | __controller_name__ = 'bmw-e46' 23 | 24 | def __init__(self): 25 | super(E46Controller, self).__init__() 26 | self.bluetooth = BluetoothInterface(self) # interface available for clients 27 | self.ibus = IBUSInterface(self) # interface connected to the vehicle 28 | 29 | # bind interfaces to each other 30 | self.bluetooth.bind_receive(self.ibus.send) 31 | self.ibus.bind_receive(self.bluetooth.send) 32 | 33 | def start(self): 34 | """Invoked when the controller is starting.""" 35 | LOGGER.info('starting the controller services...') 36 | 37 | # connect to the necessary interfaces 38 | self.ibus.connect() 39 | self.bluetooth.connect() 40 | self.state = self.__states__.STATE_RUNNING 41 | LOGGER.info('all services have been started') 42 | 43 | # run until "Ctrl-C" is pressed 44 | self.loop_until_ctrl_c() 45 | 46 | def stop(self): 47 | """Invoked when the controller should stop.""" 48 | LOGGER.info('ending the controller services...') 49 | self.state = self.__states__.STATE_STOPPED 50 | self.ibus.disconnect() 51 | self.bluetooth.disconnect() 52 | 53 | -------------------------------------------------------------------------------- /connected_car_controller/pavement.py: -------------------------------------------------------------------------------- 1 | """ 2 | The pavement.py module defines various Paver tasks. Tasks include unit_tests, pylint, etc. 3 | 4 | Usage 5 | ----- 6 | # execute the entire build pipeline 7 | $ paver 8 | ---> pavement.default 9 | ---> pavement.unit_tests 10 | nosetests --with-xcoverage --with-xunit --cover-package=controllers,interfaces --cover-erase 11 | ... 12 | 13 | # execute a particular task of the pipeline (method name) 14 | $ paver pylint 15 | ---> pavement.pylint 16 | pylint -f parseable controllers interfaces | tee pylint.out 17 | ... 18 | 19 | """ 20 | from paver.tasks import BuildFailure, needs, task 21 | from paver.easy import sh 22 | 23 | 24 | @task 25 | def unit_tests(): 26 | """Invoke nosetests runner for all test/unit/* unit tests.""" 27 | settings = [ 28 | '--with-xcoverage', 29 | '--with-xunit', 30 | '--cover-package=controllers,interfaces', 31 | '--cover-erase' 32 | ] 33 | sh('nosetests test/unit {}'.format(' '.join(settings))) 34 | 35 | 36 | @task 37 | def pylint(): 38 | """Invoke pylint on remote_code_block and libs packages.""" 39 | try: 40 | sh('pylint -f parseable --rcfile .pylintrc \ 41 | controllers interfaces start_controller.py | tee pylint.out') 42 | except BuildFailure: 43 | pass # pylint errors should NOT fail the build 44 | 45 | 46 | @needs('unit_tests', 'pylint') 47 | @task 48 | def default(): 49 | """The default task executed if `paver` is invoked with 0 arguments. 50 | 51 | A critical error in any of the stages will result in a FAILED build. 52 | 53 | Build Pipeline 54 | -------------- 55 | - unit tests are exercised 56 | - behavioral feature tests are exercised 57 | - pylint scores the entire codebase 58 | - a deployment artifact is created 59 | 60 | """ 61 | -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/layout/devices_row.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 19 | 20 | 28 | 29 | 36 | 37 | 43 | 44 | 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/java/com/trentseed/bmw_rpi_ibus_controller/wear/ActivityMain.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller.wear; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.support.wearable.view.GridViewPager; 6 | import android.support.wearable.view.WatchViewStub; 7 | import android.view.Window; 8 | import android.view.WindowManager; 9 | import android.widget.Toast; 10 | 11 | 12 | public class ActivityMain extends Activity { 13 | 14 | /* track parent page id of first column of options (i.e. Driver Window, Locks, etc.) */ 15 | public static int parent_page_id; 16 | 17 | @Override 18 | protected void onCreate(Bundle savedInstanceState) { 19 | super.onCreate(savedInstanceState); 20 | requestWindowFeature(Window.FEATURE_NO_TITLE); 21 | 22 | // disable action bar for swipe dismissal support 23 | getWindow().setFlags( 24 | WindowManager.LayoutParams.FLAG_FULLSCREEN, 25 | WindowManager.LayoutParams.FLAG_FULLSCREEN 26 | ); 27 | setContentView(R.layout.activity_main); 28 | 29 | // inflate the 'rectangle' or 'round' view depending on device screen 30 | final WatchViewStub stub = findViewById(R.id.watch_view_stub); 31 | stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() { 32 | @Override 33 | public void onLayoutInflated(WatchViewStub stub) { 34 | // set adapter for 2D Picker pattern 35 | final GridViewPager pager = findViewById(R.id.pager); 36 | pager.setAdapter( 37 | new IBUSGridPagerAdapter(ActivityMain.this, getFragmentManager()) 38 | ); 39 | } 40 | }); 41 | } 42 | 43 | /** 44 | * Display toast message for Toast.LENGTH_SHORT period. Uses the fragments 45 | * activity for context. 46 | * @param message content to display in toast message 47 | */ 48 | public void showToast(String message){ 49 | Toast.makeText(this, message, Toast.LENGTH_SHORT).show(); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /connected_car_app/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 16 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 32 | 33 | 35 | 37 | 39 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /connected_car_app/common/src/main/java/com/trentseed/bmw_rpi_ibus_controller/common/ConnectedThread.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller.common; 2 | 3 | import java.io.IOException; 4 | 5 | import android.util.Log; 6 | import com.google.gson.Gson; 7 | import com.google.gson.JsonParser; 8 | import com.google.gson.JsonSyntaxException; 9 | 10 | /** 11 | * Thread that handles Bluetooth RFCOMM channel reading from Raspberry Pi 12 | */ 13 | class ConnectedThread extends Thread { 14 | 15 | /** 16 | * Starts a loop responsible for continuously reading bytes from the 17 | * Bluetooth input stream, and invoking IBUSWrapper.processPacket(). 18 | */ 19 | public void run() { 20 | 21 | // start a loop that reads from the bluetooth input stream 22 | while (true) { 23 | try { 24 | // read bytes from bluetooth input stream 25 | byte[] buffer = new byte[2048]; // TODO: from config 26 | int bytes = BluetoothInterface.mBluetoothInputStream.read(buffer); 27 | if(bytes == 0) { 28 | continue; 29 | } 30 | 31 | // create String from data and validate JSON structure 32 | Log.d("BMW", "Data In = " + new String(buffer).trim()); 33 | String strBuffer = new String(buffer).trim(); 34 | if(!isJSONValid(strBuffer)) { 35 | continue; 36 | } 37 | 38 | // parse received data 39 | ControllerMessage msg = new Gson().fromJson(strBuffer, ControllerMessage.class); 40 | for(final IBUSPacket ibPacket : msg.getIBUSPackets()){ 41 | BluetoothInterface.mActivity.runOnUiThread(new Runnable() { 42 | @Override 43 | public void run() { 44 | IBUSWrapper.processPacket(ibPacket); 45 | } 46 | }); 47 | } 48 | 49 | } catch (IOException e) { 50 | Log.d("BMW", "Error reading: " + String.valueOf(e.getMessage())); 51 | break; 52 | } 53 | } 54 | } 55 | 56 | /** 57 | * Returns true or false is provided string input is JSON parsable. 58 | */ 59 | private boolean isJSONValid(String json) { 60 | try { 61 | new JsonParser().parse(json); 62 | return true; 63 | } catch (JsonSyntaxException jse) { 64 | return false; 65 | } 66 | } 67 | } 68 | 69 | -------------------------------------------------------------------------------- /connected_car_app/import-summary.txt: -------------------------------------------------------------------------------- 1 | ECLIPSE ANDROID PROJECT IMPORT SUMMARY 2 | ====================================== 3 | 4 | Ignored Files: 5 | -------------- 6 | The following files were *not* copied into the new Gradle project; you 7 | should evaluate whether these are still needed in your project and if 8 | so manually move them: 9 | 10 | * ic_launcher-web.png 11 | * proguard-project.txt 12 | 13 | Replaced Jars with Dependencies: 14 | -------------------------------- 15 | The importer recognized the following .jar files as third party 16 | libraries and replaced them with Gradle dependencies instead. This has 17 | the advantage that more explicit version information is known, and the 18 | libraries can be updated automatically. However, it is possible that 19 | the .jar file in your project was of an older version than the 20 | dependency we picked, which could render the project not compileable. 21 | You can disable the jar replacement in the import wizard and try again: 22 | 23 | android-support-v4.jar => com.android.support:support-v4:19.1.0 24 | gson-2.2.4.jar => com.google.code.gson:gson:2.2.4 25 | 26 | Potentially Missing Dependency: 27 | ------------------------------- 28 | When we replaced the following .jar files with a Gradle dependency, we 29 | inferred the dependency version number from the filename. This 30 | specific version may not actually be available from the repository. 31 | If you get a build error stating that the dependency is missing, edit 32 | the version number to for example "+" to pick up the latest version 33 | instead. (This may require you to update your code if the library APIs 34 | have changed.) 35 | 36 | gson-2.2.4.jar => version 2.2.4 in com.google.code.gson:gson:2.2.4 37 | 38 | Moved Files: 39 | ------------ 40 | Android Gradle projects use a different directory structure than ADT 41 | Eclipse projects. Here's how the projects were restructured: 42 | 43 | * AndroidManifest.xml => app\src\main\AndroidManifest.xml 44 | * lint.xml => app\lint.xml 45 | * res\ => app\src\main\res\ 46 | * src\ => app\src\main\java\ 47 | 48 | Next Steps: 49 | ----------- 50 | You can now build the project. The Gradle project needs network 51 | connectivity to download dependencies. 52 | 53 | Bugs: 54 | ----- 55 | If for some reason your project does not build, and you determine that 56 | it is due to a bug or limitation of the Eclipse to Gradle importer, 57 | please file a bug at http://b.android.com with category 58 | Component-Tools. 59 | 60 | (This import summary is for your information only, and can be deleted 61 | after import once you are satisfied with the results.) 62 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/java/com/trentseed/bmw_rpi_ibus_controller/wear/FragmentWelcome.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller.wear; 2 | 3 | import android.os.AsyncTask; 4 | import android.os.Bundle; 5 | import android.app.Fragment; 6 | import android.view.LayoutInflater; 7 | import android.view.View; 8 | import android.view.ViewGroup; 9 | import android.widget.ImageView; 10 | import android.widget.ProgressBar; 11 | 12 | import com.trentseed.bmw_rpi_ibus_controller.common.BluetoothInterface; 13 | 14 | public class FragmentWelcome extends Fragment { 15 | 16 | ImageView imgBtnReconnect; 17 | ProgressBar pbConnectionLoader; 18 | 19 | @Override 20 | public View onCreateView(LayoutInflater inflater, ViewGroup container, 21 | Bundle savedInstanceState) { 22 | 23 | // Inflate the layout for this fragment 24 | View rootView = inflater.inflate(R.layout.welcome, container, false); 25 | pbConnectionLoader = rootView.findViewById(R.id.pbConnectionLoader); 26 | imgBtnReconnect = rootView.findViewById(R.id.imgBtnEmblem); 27 | imgBtnReconnect.setOnClickListener(new View.OnClickListener() { 28 | @Override 29 | public void onClick(View v) { 30 | startReconnect(); 31 | } 32 | }); 33 | 34 | // start initial connect (if disconnected) 35 | if (!BluetoothInterface.isConnected()) startReconnect(); 36 | 37 | return rootView; 38 | } 39 | 40 | /** 41 | * Starts the bluetooth connection process in a background thread. 42 | */ 43 | public void startReconnect(){ 44 | new ConnectViaBluetooth().execute(); 45 | } 46 | 47 | /** 48 | * AsyncTask to perform the bluetooth connection. 49 | * Displays a progress bar loader to indicate progress. 50 | */ 51 | private class ConnectViaBluetooth extends AsyncTask { 52 | @Override 53 | protected Void doInBackground(Void... params) { 54 | BluetoothInterface.checkConnection(); 55 | return null; 56 | } 57 | 58 | @Override 59 | protected void onPostExecute(Void result) { 60 | ((ActivityMain)FragmentWelcome.this.getActivity()) 61 | .showToast("Connected: " + BluetoothInterface.isConnected()); 62 | pbConnectionLoader.setVisibility(View.GONE); 63 | } 64 | 65 | @Override 66 | protected void onPreExecute() { 67 | pbConnectionLoader.setVisibility(View.VISIBLE); 68 | } 69 | 70 | @Override 71 | protected void onProgressUpdate(Void... values) { 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/layout/activity_devices.xml: -------------------------------------------------------------------------------- 1 | 9 | 10 | 17 | 18 | 21 | 22 | 30 | 31 | 41 | 42 | 43 | 44 | 51 | 52 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /connected_car_app/ibuswear/src/main/java/com/trentseed/bmw_rpi_ibus_controller/wear/FragmentVoiceCommand.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller.wear; 2 | 3 | import android.app.Activity; 4 | import android.app.Fragment; 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import android.speech.RecognizerIntent; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.ImageView; 12 | 13 | import java.util.List; 14 | 15 | import com.trentseed.bmw_rpi_ibus_controller.common.VoiceCommand; 16 | 17 | /** 18 | * https://developer.android.com/training/wearables/apps/voice.html 19 | */ 20 | public class FragmentVoiceCommand extends Fragment { 21 | 22 | private static final int SPEECH_REQUEST_CODE = 0; 23 | ImageView imgVoiceCommand; 24 | 25 | @Override 26 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 27 | 28 | View rootView = inflater.inflate(R.layout.voice, container, false); 29 | imgVoiceCommand = rootView.findViewById(R.id.imgBtnExit); 30 | imgVoiceCommand.setOnClickListener(new View.OnClickListener() { 31 | @Override 32 | public void onClick(View v) { 33 | displaySpeechRecognizer(); 34 | } 35 | }); 36 | 37 | return rootView; 38 | } 39 | 40 | /** 41 | * Create an intent that can start the Speech Recognizer activity 42 | */ 43 | private void displaySpeechRecognizer() { 44 | Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH); 45 | intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, 46 | RecognizerIntent.LANGUAGE_MODEL_FREE_FORM); 47 | // Start the activity, the intent will be populated with the speech text 48 | startActivityForResult(intent, SPEECH_REQUEST_CODE); 49 | } 50 | 51 | /** 52 | * This callback is invoked when the Speech Recognizer returns. 53 | * This is where you process the intent and extract the speech text from the intent. 54 | */ 55 | @Override 56 | public void onActivityResult(int requestCode, int resultCode, Intent data) { 57 | if (requestCode == SPEECH_REQUEST_CODE && resultCode == Activity.RESULT_OK) { 58 | List results = data.getStringArrayListExtra( RecognizerIntent.EXTRA_RESULTS); 59 | String spokenText = results.get(0); 60 | String result = VoiceCommand.processSpokenText(spokenText); 61 | ((ActivityMain)this.getActivity()).showToast(result); 62 | } 63 | super.onActivityResult(requestCode, resultCode, data); 64 | } 65 | 66 | } 67 | -------------------------------------------------------------------------------- /connected_car_app/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /connected_car_app/common/src/main/java/com/trentseed/bmw_rpi_ibus_controller/common/IBUSPacket.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller.common; 2 | 3 | import java.text.Normalizer; 4 | 5 | /** 6 | * IBUS "packet" that is sent between BMW and Raspberry Pi 7 | */ 8 | public class IBUSPacket { 9 | 10 | public String source_id; 11 | public String length; 12 | public String destination_id; 13 | public String data; 14 | public String xor_checksum; 15 | public String raw; 16 | public String timestamp; 17 | 18 | public IBUSPacket(){ } 19 | 20 | public String getSourceName(){ 21 | return getDeviceName(this.source_id); 22 | } 23 | 24 | public String getDestinationName(){ 25 | return getDeviceName(this.destination_id); 26 | } 27 | 28 | private String getDeviceName(String device_id){ 29 | switch (device_id) { 30 | case "00": 31 | return "Broadcast 00"; 32 | case "18": 33 | return "CDW - CDC CD-Player"; 34 | case "3b": 35 | return "NAV Navigation/Video Module"; 36 | case "43": 37 | return "Menu Screen"; 38 | case "50": 39 | return "MFL Steering Wheel Controls"; 40 | case "60": 41 | return "PDC Park Distance Control"; 42 | case "68": 43 | return "RAD Radio"; 44 | case "6a": 45 | return "DSP Digital Sound Processor"; 46 | case "80": 47 | return "IKE Instrument Kombi Electronics"; 48 | case "bb": 49 | return "TV Module"; 50 | case "bf": 51 | return "LCM Light Control Module"; 52 | case "c0": 53 | return "MID Multi-Information Display Buttons"; 54 | case "c8": 55 | return "TEL Telephone"; 56 | case "d0": 57 | return "Navigation Location"; 58 | case "e7": 59 | return "OBC Text Bar"; 60 | case "ed": 61 | return "Lights, Wipers, Seat Memory"; 62 | case "f0": 63 | return "BMB Board Monitor Buttons"; 64 | case "ff": 65 | return "Broadcast FF"; 66 | default: 67 | return "Unknown"; 68 | } 69 | } 70 | 71 | /** 72 | * Parses hex string and returns ASCII character representation 73 | * http://www.mkyong.com/java/how-to-convert-hex-to-ascii-in-java/ 74 | * @return String 75 | */ 76 | public String getAsciiFromRaw(){ 77 | StringBuilder sb = new StringBuilder(); 78 | for( int i=0; i 8 | 9 | 18 | 19 | 26 | 27 | 30 | 31 | 39 | 40 | 50 | 51 | 63 | 64 | 65 | 66 | 71 | 72 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /connected_car_app/app/src/main/java/com/trentseed/bmw_rpi_ibus_controller/AdapterDevices.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller; 2 | 3 | import android.content.Context; 4 | import android.util.Log; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | import android.widget.ImageView; 9 | import android.widget.TextView; 10 | 11 | import java.util.List; 12 | 13 | import androidx.recyclerview.widget.RecyclerView; 14 | 15 | 16 | public class AdapterDevices extends RecyclerView.Adapter { 17 | 18 | private List mData; 19 | private LayoutInflater mInflater; 20 | 21 | AdapterDevices(Context context, List data) { 22 | this.mInflater = LayoutInflater.from(context); 23 | this.mData = data; 24 | } 25 | 26 | @Override 27 | public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 28 | View view = mInflater.inflate(R.layout.devices_row, parent, false); 29 | return new ViewHolder(view); 30 | } 31 | 32 | @Override 33 | public void onBindViewHolder(ViewHolder holder, int position) { 34 | Device device = mData.get(position); 35 | 36 | // bind text values 37 | holder.deviceName.setText(device.name); 38 | 39 | // bind image resources 40 | if (device.icon > 0) { 41 | holder.deviceIcon.setImageResource(device.icon); 42 | } 43 | if (device.imageAction1 > 0) { 44 | holder.deviceAction1.setImageResource(device.imageAction1); 45 | } 46 | if (device.imageAction2 > 0) { 47 | holder.deviceAction2.setImageResource(device.imageAction2); 48 | } 49 | 50 | // bind click events 51 | if (device.onClickListenerAction1 != null){ 52 | holder.deviceAction1.setOnClickListener(device.onClickListenerAction1); 53 | } 54 | if (device.onClickListenerAction2 != null){ 55 | holder.deviceAction2.setOnClickListener(device.onClickListenerAction2); 56 | } 57 | } 58 | 59 | @Override 60 | public int getItemCount() { 61 | return mData.size(); 62 | } 63 | 64 | 65 | // stores and recycles views as they are scrolled off screen 66 | public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { 67 | TextView deviceName; 68 | ImageView deviceIcon; 69 | ImageView deviceAction1; 70 | ImageView deviceAction2; 71 | 72 | ViewHolder(View itemView) { 73 | super(itemView); 74 | deviceName = itemView.findViewById(R.id.tvDeviceName); 75 | deviceIcon = itemView.findViewById(R.id.ivDeviceIcon); 76 | deviceAction1 = itemView.findViewById(R.id.ivDeviceAction1); 77 | deviceAction2 = itemView.findViewById(R.id.ivDeviceAction2); 78 | itemView.setOnClickListener(this); 79 | } 80 | 81 | @Override 82 | public void onClick(View view) { 83 | Log.d("BMW", "onclick occurred in viewholder"); 84 | } 85 | 86 | } 87 | 88 | public static class Device{ 89 | int icon; 90 | String name; 91 | int imageAction1; 92 | int imageAction2; 93 | View.OnClickListener onClickListenerAction1; 94 | View.OnClickListener onClickListenerAction2; 95 | 96 | public Device(String name){ 97 | this.name = name; 98 | } 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /connected_car_app/common/src/main/java/com/trentseed/bmw_rpi_ibus_controller/common/BluetoothInterface.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller.common; 2 | 3 | import java.io.InputStream; 4 | import java.io.OutputStream; 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | import java.util.UUID; 8 | 9 | import android.app.Activity; 10 | import android.bluetooth.BluetoothAdapter; 11 | import android.bluetooth.BluetoothDevice; 12 | import android.bluetooth.BluetoothSocket; 13 | import android.util.Log; 14 | import android.widget.Toast; 15 | 16 | /** 17 | * Handles Bluetooth communication with Raspberry Pi 18 | * 19 | */ 20 | public class BluetoothInterface { 21 | 22 | // bluetooth objects 23 | public static Activity mActivity; 24 | public static List mArrayListIBUSActivity = new ArrayList<>(); 25 | public static BluetoothAdapter mBluetoothAdapter; 26 | public static BluetoothDevice mBluetoothDevice; 27 | public static BluetoothSocket mBluetoothSocket; 28 | public static InputStream mBluetoothInputStream; 29 | public static OutputStream mBluetoothOutputStream; 30 | public static UUID serviceUUID = UUID.fromString("94f39d29-7d6d-437d-973b-fba39e49d4ee"); 31 | public static String remoteBluetoothAddress = "B8:27:EB:69:90:49"; 32 | public static ConnectedThread listenThread; 33 | public static Boolean isConnecting = false; 34 | 35 | /** 36 | * Connects to Raspberry Pi via Bluetooth. 37 | * Note: Python services must be running on remote device. 38 | */ 39 | public static void connectToRaspberryPi(){ 40 | Log.d("BMW", "attempting to connect to controller..."); 41 | try{ 42 | // connect to device and get input stream 43 | BluetoothInterface.isConnecting = true; 44 | mArrayListIBUSActivity = new ArrayList<>(); 45 | mBluetoothDevice = mBluetoothAdapter.getRemoteDevice(remoteBluetoothAddress); 46 | mBluetoothSocket = mBluetoothDevice.createInsecureRfcommSocketToServiceRecord(serviceUUID); 47 | mBluetoothSocket.connect(); 48 | mBluetoothInputStream = mBluetoothSocket.getInputStream(); 49 | mBluetoothOutputStream = mBluetoothSocket.getOutputStream(); 50 | BluetoothInterface.isConnecting = false; 51 | 52 | // start listening for data on new thread 53 | Log.d("BMW", "starting connected thread..."); 54 | listenThread = new ConnectedThread(); 55 | listenThread.start(); 56 | }catch(Exception e){ 57 | BluetoothInterface.isConnecting = true; 58 | Log.d("BMW", "exception connecting to controller: " + e.getMessage()); 59 | // if(mActivity != null && !mActivity.isFinishing()) { 60 | // Toast.makeText(mActivity, "Unable To Connect via Bluetooth", Toast.LENGTH_LONG).show(); 61 | // } 62 | } 63 | } 64 | 65 | /** 66 | * Determines if Bluetooth connection has been established with Raspberry Pi 67 | * @return boolean 68 | */ 69 | public static boolean isConnected(){ 70 | return mBluetoothAdapter != null && mBluetoothDevice != null && mBluetoothSocket.isConnected(); 71 | } 72 | 73 | /** 74 | * Determines if Bluetooth is in progress with establishing connection 75 | * @return boolean 76 | */ 77 | public static boolean isConnecting(){ 78 | return isConnecting; 79 | } 80 | 81 | /** 82 | * Checks Bluetooth connection, and connects if necessary. 83 | */ 84 | public static void checkConnection(){ 85 | if(!BluetoothInterface.isConnected()){ 86 | BluetoothInterface.mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); 87 | BluetoothInterface.connectToRaspberryPi(); 88 | } 89 | } 90 | 91 | /** 92 | * Disconnect Bluetooth RFCOMM connection 93 | */ 94 | public static void disconnect(){ 95 | try{ 96 | mBluetoothSocket.close(); 97 | }catch(Exception e){ 98 | Log.d("BMW", e.getMessage()); 99 | }finally { 100 | mBluetoothAdapter = null; 101 | mBluetoothDevice = null; 102 | mBluetoothSocket = null; 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /connected_car_app/app/src/main/java/com/trentseed/bmw_rpi_ibus_controller/ActivityRadio.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller; 2 | 3 | import android.app.Activity; 4 | import android.os.Bundle; 5 | import android.view.View; 6 | import android.view.Window; 7 | import android.view.WindowManager; 8 | import android.widget.Button; 9 | import android.widget.ImageView; 10 | 11 | import com.trentseed.bmw_rpi_ibus_controller.common.BluetoothInterface; 12 | import com.trentseed.bmw_rpi_ibus_controller.common.IBUSWrapper; 13 | 14 | public class ActivityRadio extends Activity { 15 | 16 | ImageView ivBack; 17 | Button btnAccept; 18 | Button btnVolUp; 19 | Button btnVolDown; 20 | Button btnRadioPower; 21 | Button btnDriverSeatForward; 22 | Button btnDriverSeatBack; 23 | Button btnSunroofOpen; 24 | Button btnSunroofClose; 25 | Button btnLock; 26 | Button btnUnlock; 27 | Button btnMode; 28 | 29 | @Override 30 | protected void onCreate(Bundle savedInstanceState) { 31 | super.onCreate(savedInstanceState); 32 | requestWindowFeature(Window.FEATURE_NO_TITLE); 33 | getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 34 | onNewIntent(getIntent()); 35 | setContentView(R.layout.activity_radio); 36 | BluetoothInterface.mActivity = this; 37 | 38 | // get layout objects 39 | ivBack = findViewById(R.id.ivBack); 40 | btnAccept = findViewById(R.id.btnAccept); 41 | btnVolUp = findViewById(R.id.btnVolUp); 42 | btnVolDown = findViewById(R.id.btnVolDown); 43 | btnRadioPower = findViewById(R.id.btnRadioPower); 44 | btnDriverSeatForward = findViewById(R.id.btnDriverSeatForward); 45 | btnDriverSeatBack = findViewById(R.id.btnDriverSeatBack); 46 | btnSunroofOpen = findViewById(R.id.btnSunroofOpen); 47 | btnSunroofClose = findViewById(R.id.btnSunroofClose); 48 | btnLock = findViewById(R.id.btnLock); 49 | btnUnlock = findViewById(R.id.btnUnlock); 50 | btnMode = findViewById(R.id.btnMode); 51 | 52 | // set click handlers 53 | ivBack.setOnClickListener(new View.OnClickListener() { 54 | @Override 55 | public void onClick(View v) { 56 | finish(); 57 | } 58 | }); 59 | btnAccept.setOnClickListener(new View.OnClickListener() { 60 | @Override 61 | public void onClick(View v) { 62 | IBUSWrapper.pressAccept(); 63 | } 64 | }); 65 | btnVolUp.setOnClickListener(new View.OnClickListener() { 66 | @Override 67 | public void onClick(View v) { 68 | IBUSWrapper.volumeUp(); 69 | } 70 | }); 71 | btnVolDown.setOnClickListener(new View.OnClickListener() { 72 | @Override 73 | public void onClick(View v) { 74 | IBUSWrapper.volumeDown(); 75 | } 76 | }); 77 | btnRadioPower.setOnClickListener(new View.OnClickListener() { 78 | @Override 79 | public void onClick(View v) { 80 | IBUSWrapper.toggleRadioPower(); 81 | } 82 | }); 83 | btnMode.setOnClickListener(new View.OnClickListener() { 84 | @Override 85 | public void onClick(View v) { 86 | IBUSWrapper.toggleMode(ActivityRadio.this); 87 | } 88 | }); 89 | btnDriverSeatForward.setOnClickListener(new View.OnClickListener() { 90 | @Override 91 | public void onClick(View v) { 92 | IBUSWrapper.moveDriverSeat(true); 93 | } 94 | }); 95 | btnDriverSeatBack.setOnClickListener(new View.OnClickListener() { 96 | @Override 97 | public void onClick(View v) { 98 | IBUSWrapper.moveDriverSeat(false); 99 | } 100 | }); 101 | btnLock.setOnClickListener(new View.OnClickListener() { 102 | @Override 103 | public void onClick(View v) { 104 | IBUSWrapper.lockCar(); 105 | } 106 | }); 107 | btnUnlock.setOnClickListener(new View.OnClickListener() { 108 | @Override 109 | public void onClick(View v) { 110 | IBUSWrapper.unlockCar(); 111 | } 112 | }); 113 | btnSunroofOpen.setOnClickListener(new View.OnClickListener() { 114 | @Override 115 | public void onClick(View v) { 116 | IBUSWrapper.toggleSunroof(true); 117 | } 118 | }); 119 | btnSunroofClose.setOnClickListener(new View.OnClickListener() { 120 | @Override 121 | public void onClick(View v) { 122 | IBUSWrapper.toggleSunroof(false); 123 | } 124 | }); 125 | } 126 | 127 | @Override 128 | protected void onResume(){ 129 | super.onResume(); 130 | BluetoothInterface.mActivity = this; 131 | BluetoothInterface.checkConnection(); 132 | } 133 | 134 | } 135 | -------------------------------------------------------------------------------- /connected_car_controller/interfaces/base.py: -------------------------------------------------------------------------------- 1 | """ 2 | The interfaces.base module contains logic common to all BaseInterface implementations. 3 | """ 4 | import logging 5 | import os 6 | from configparser import ConfigParser 7 | 8 | 9 | LOGGER = logging.getLogger(__name__) 10 | 11 | 12 | class InterfaceStates(object): 13 | """The various states that an interface can experience.""" 14 | STATE_READY = 0 15 | STATE_CONNECTING = 1 16 | STATE_CONNECTED = 2 17 | STATE_DISCONNECTING = 3 18 | 19 | 20 | class BaseInterface(object): 21 | """The base class for implementing an interface type.""" 22 | 23 | __interface_name__ = None 24 | __states__ = InterfaceStates 25 | 26 | def __init__(self): 27 | self.state = self.__states__.STATE_READY 28 | self.send_hook = None 29 | self.receive_hook = None 30 | 31 | def get_setting(self, setting, setting_type=str): 32 | """ 33 | Returns a specified setting from etc/config.ini. 34 | 35 | Parameters 36 | ---------- 37 | setting : basestring 38 | the key of the setting to return under the [interfaces.{__interface_name__}] section 39 | setting_type : type 40 | [optional] the data type for the setting e.g. int or bool. default is basestring. 41 | 42 | Returns 43 | ------- 44 | basestring 45 | string value of the setting 46 | 47 | """ 48 | path = os.path.join( 49 | os.path.dirname(os.path.abspath(__file__)), '..', 'etc', 'config.ini' 50 | ) 51 | parser = ConfigParser() # TODO: verify works; was SafeConfigParser 52 | parser.read(path) 53 | section = 'interfaces.{}'.format(self.__interface_name__) 54 | 55 | # return setting value using the specified setting_type 56 | if setting_type is int: 57 | return parser.getint(section, setting) 58 | elif setting_type is bool: 59 | return parser.getboolean(section, setting) 60 | elif setting_type is float: 61 | return parser.getfloat(section, setting) 62 | else: 63 | return parser.get(section, setting) 64 | 65 | def connect(self): 66 | """Invoked when the interface is performing a connection""" 67 | raise NotImplementedError 68 | 69 | def disconnect(self): 70 | """Invoked when the interface is being destroyed""" 71 | raise NotImplementedError 72 | 73 | def send(self, data): 74 | """Invoked when data should be sent over the interface 75 | 76 | Arguments 77 | --------- 78 | data : basestring 79 | the data to be sent via this interface 80 | 81 | """ 82 | raise NotImplementedError 83 | 84 | def receive(self, data): 85 | """Invoked when data is received from the interface 86 | 87 | Arguments 88 | --------- 89 | data : basestring 90 | incoming data received from this interface 91 | 92 | """ 93 | raise NotImplementedError 94 | 95 | def consume_bus(self): 96 | """Responsible for initiating a loop and reading from the bus.""" 97 | raise NotImplementedError 98 | 99 | def reconnect(self): 100 | """Performs a reconnect job to establish a fresh connection""" 101 | LOGGER.info('restarting interface...') 102 | self.disconnect() 103 | self.connect() 104 | 105 | def bind_receive(self, method): 106 | """Used to bind a method that will be called every time the interface receives data. 107 | 108 | Arguments 109 | --------- 110 | method : function 111 | a method to bind and invoke each time the interface receives data 112 | 113 | """ 114 | if not hasattr(method, '__call__'): 115 | LOGGER.error('error in bind_receive: method must be callable!') 116 | return 117 | 118 | self.receive_hook = method 119 | 120 | def bind_send(self, method): 121 | """Used to bind a method that will be called every time the interface sends data. 122 | 123 | Arguments 124 | --------- 125 | method : function 126 | a method to bind and invoke each time the interface sends data 127 | 128 | """ 129 | if not hasattr(method, '__call__'): 130 | LOGGER.error('error in bind_send: method must be callable!') 131 | return 132 | 133 | self.send_hook = method 134 | -------------------------------------------------------------------------------- /connected_car_app/app/src/main/java/com/trentseed/bmw_rpi_ibus_controller/ActivityIBUS.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller; 2 | 3 | import android.app.Activity; 4 | import android.app.AlertDialog; 5 | import android.content.DialogInterface; 6 | import android.os.Bundle; 7 | import android.view.View; 8 | import android.view.Window; 9 | import android.view.WindowManager; 10 | import android.view.animation.AccelerateInterpolator; 11 | import android.view.animation.AlphaAnimation; 12 | import android.view.animation.Animation; 13 | import android.view.animation.Animation.AnimationListener; 14 | import android.widget.AbsListView; 15 | import android.widget.AdapterView; 16 | import android.widget.ImageView; 17 | import android.widget.ListView; 18 | import android.widget.TextView; 19 | 20 | import com.trentseed.bmw_rpi_ibus_controller.common.BluetoothInterface; 21 | import com.trentseed.bmw_rpi_ibus_controller.common.IBUSPacket; 22 | 23 | public class ActivityIBUS extends Activity { 24 | 25 | // layout objects 26 | ImageView ivBack; 27 | ImageView ivBusActivity; 28 | ListView lvBusEvents; 29 | TextView tvNoActivity; 30 | AdapterIBUS adapter; 31 | 32 | @Override 33 | protected void onCreate(Bundle savedInstanceState) { 34 | super.onCreate(savedInstanceState); 35 | requestWindowFeature(Window.FEATURE_NO_TITLE); 36 | getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 37 | onNewIntent(getIntent()); 38 | setContentView(R.layout.activity_ibus); 39 | BluetoothInterface.mActivity = this; 40 | 41 | // get layout objects 42 | ivBack = findViewById(R.id.ivBack); 43 | ivBusActivity = findViewById(R.id.ivBusActivity); 44 | ivBusActivity.setVisibility(View.GONE); 45 | lvBusEvents = findViewById(R.id.lvBusEvents); 46 | tvNoActivity = findViewById(R.id.tvNoActivity); 47 | 48 | // set click handlers 49 | ivBack.setOnClickListener(new View.OnClickListener() { 50 | @Override 51 | public void onClick(View v) { 52 | finish(); 53 | } 54 | }); 55 | 56 | // create and set adapter 57 | adapter = new AdapterIBUS(this); 58 | lvBusEvents.setAdapter(adapter); 59 | if(adapter.getCount() > 0) tvNoActivity.setVisibility(View.GONE); 60 | lvBusEvents.setOnItemClickListener(new AbsListView.OnItemClickListener() { 61 | @Override 62 | public void onItemClick(AdapterView arg0, View arg1, int position, long arg3) { 63 | IBUSPacket ibPacket = adapter.getItem(position); 64 | AlertDialog.Builder msgBuilder = new AlertDialog.Builder(ActivityIBUS.this); 65 | msgBuilder.setTitle("IBUS Packet"); 66 | msgBuilder.setMessage("Data: " + ibPacket.raw + "\nASCII: " + ibPacket.getAsciiFromRaw()); 67 | msgBuilder.setPositiveButton("Done", new DialogInterface.OnClickListener() { 68 | @Override 69 | public void onClick(DialogInterface dialog, int which) {} 70 | }); 71 | msgBuilder.create().show(); 72 | 73 | } 74 | }); 75 | } 76 | 77 | /** 78 | * Received an IBUSPacket update, refresh ListView 79 | */ 80 | public void receivedIBUSPacket(IBUSPacket ibPacket){ 81 | adapter.notifyDataSetChanged(); 82 | flashActivity(); 83 | } 84 | 85 | /** 86 | * Indicate IBUS activity on UI by "flashing" green indicator. 87 | */ 88 | private void flashActivity(){ 89 | // fade in animation 90 | ivBusActivity.setVisibility(View.VISIBLE); 91 | Animation fadeIn = new AlphaAnimation(0, 1); 92 | fadeIn.setInterpolator(new AccelerateInterpolator()); 93 | fadeIn.setDuration(300); 94 | fadeIn.setAnimationListener(new AnimationListener(){ 95 | public void onAnimationEnd(Animation animation){ 96 | // fade out animation 97 | Animation fadeOut = new AlphaAnimation(1, 0); 98 | fadeOut.setInterpolator(new AccelerateInterpolator()); 99 | fadeOut.setDuration(300); 100 | fadeOut.setAnimationListener(new AnimationListener(){ 101 | public void onAnimationEnd(Animation animation){ 102 | ivBusActivity.setVisibility(View.GONE); 103 | } 104 | public void onAnimationRepeat(Animation animation){ } 105 | public void onAnimationStart(Animation animation){ } 106 | }); 107 | ivBusActivity.setVisibility(View.VISIBLE); 108 | ivBusActivity.startAnimation(fadeOut); 109 | } 110 | public void onAnimationRepeat(Animation animation){ } 111 | public void onAnimationStart(Animation animation){ } 112 | }); 113 | ivBusActivity.startAnimation(fadeIn); 114 | } 115 | 116 | @Override 117 | protected void onResume(){ 118 | super.onResume(); 119 | BluetoothInterface.mActivity = this; 120 | BluetoothInterface.checkConnection(); 121 | } 122 | 123 | } 124 | -------------------------------------------------------------------------------- /connected_car_controller/interfaces/canbus.py: -------------------------------------------------------------------------------- 1 | """ 2 | This module contains the implementation for CanBusInterface. 3 | 4 | TODO: complete implementation 5 | """ 6 | import logging 7 | import threading 8 | import serial 9 | 10 | 11 | from interfaces.base import BaseInterface 12 | 13 | 14 | LOGGER = logging.getLogger(__name__) 15 | 16 | 17 | class CanBusInterface(BaseInterface): 18 | """The CAN (Controller Area Network) bus interface definition for communication with vehicles.""" 19 | 20 | __interface_name__ = 'canbus' 21 | 22 | def __init__(self, controller): 23 | """ 24 | Initializes bi-directional communication with CAN bus adapter via USB 25 | 26 | Arguments 27 | --------- 28 | controller : controllers.base.BaseController 29 | the parent controller that instantiated this interface 30 | 31 | """ 32 | super(CanBusInterface, self).__init__() 33 | self.controller = controller 34 | self.baudrate = self.get_setting('baudrate', int) 35 | self.handle = None 36 | self.port = self.get_setting('port') 37 | self.timeout = self.get_setting('timeout', int) 38 | self.thread = None 39 | 40 | def connect(self): 41 | """Connect to the vehicle via serial communication.""" 42 | if not self.state == self.__states__.STATE_READY: 43 | LOGGER.error('error: interface is not STATE_READY') 44 | raise Exception('invalid interface state: %r', self.state) 45 | 46 | # initialize serial port connection 47 | try: 48 | self.state = self.__states__.STATE_CONNECTING 49 | self.handle = serial.Serial(self.port, self.baudrate, timeout=self.timeout) 50 | self.state = self.__states__.STATE_CONNECTED 51 | except serial.serialutil.SerialException: 52 | LOGGER.exception('failed to establish serial connection') 53 | return False 54 | 55 | # launch new thread for continuous processing of the bus 56 | LOGGER.info('creating thread for %s interface...', self.__interface_name__) 57 | self.thread = threading.Thread(target=self.consume_bus) 58 | self.thread.daemon = True 59 | self.thread.start() 60 | 61 | def consume_bus(self): 62 | """Starts an infinite loop on the thread that will continue to read from the bus.""" 63 | read_buffer_length = self.get_setting('read_buffer_length', int) 64 | 65 | while self.handle: 66 | data = self.handle.read(read_buffer_length) 67 | if len(data) > 0: 68 | self.receive(data) 69 | 70 | def disconnect(self): 71 | """Closes serial connection and resets the handle.""" 72 | try: 73 | LOGGER.info('destroying %s interface...', self.__interface_name__) 74 | self.state = self.__states__.STATE_DISCONNECTING 75 | if self.handle and hasattr(self.handle, 'close'): 76 | self.handle.close() 77 | except Exception as exception: 78 | LOGGER.exception('exception during %s disconnect - %r', self.__interface_name__, exception) 79 | finally: 80 | self.state = self.__states__.STATE_READY 81 | self.handle = None 82 | self.thread = None 83 | 84 | def receive(self, data): 85 | """ 86 | Processes bytes received from the interface. 87 | 88 | Arguments 89 | --------- 90 | data : basestring 91 | the bytes retrieved from the bus, encoded as a basestring 92 | 93 | """ 94 | LOGGER.info('bus dump: hex: %r', data.encode('hex')) 95 | 96 | # TODO process packets 97 | packets = [] 98 | 99 | # invoke bound method (if set) 100 | if self.receive_hook and hasattr(self.receive_hook, '__call__'): 101 | self.receive_hook(packets) 102 | 103 | def send(self, data): 104 | """ 105 | Writes the provided hex packet(s) to the bus 106 | 107 | Parameters 108 | ---------- 109 | data : basestring 110 | the data to be sent via this interface 111 | 112 | """ 113 | if self.state != self.__states__.STATE_CONNECTED: 114 | LOGGER.error('error: send() was called but state is not connected') 115 | return False 116 | 117 | if not self.handle or not hasattr(self.handle, 'write'): 118 | LOGGER.error('cannot write to %s interface', self.__interface_name__) 119 | self.reconnect() 120 | return 121 | 122 | self.handle.write(data) 123 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |                               4 | ![Python](https://img.shields.io/badge/python-v3.6+-blue.svg) 5 | ![Dependencies](https://img.shields.io/librariesio/github/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller.svg) 6 | [![GitHub Issues](https://img.shields.io/github/issues/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller.svg)](https://github.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller/issues) 7 | ![Last Updated](https://img.shields.io/github/last-commit/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller.svg) 8 | ![Contributions welcome](https://img.shields.io/badge/contributions-welcome-orange.svg) 9 |

10 | 11 | "Appify" your E46 BMW with a Raspberry Pi and your Smartphone! This repository contains the IBUS controller, as well as the Android application which supports smart phones and wearables. This is to be used with the IBUS USB interface which can be acquired from [Reslers.de](http://www.reslers.de/IBUS/), or from Amazon/eBay. 12 | 13 | Blog Series on Medium: 14 | - [Connecting a BMW to the Internet: Part One](https://medium.com/design-and-tech-co/connecting-a-bmw-to-the-internet-part-one-fbe18a54121d) 15 | - [Connecting a BMW to the Internet: Part Two](https://medium.com/@trentseed/connecting-a-bmw-to-the-internet-part-two-1ee2ea44d4a2) 16 | - [Connecting a BMW to the Internet: Part Three](https://medium.com/@trentseed/connecting-a-bmw-to-the-internet-part-three-89fb322b1dcb) 17 | 18 | ## Overview 19 | 20 | There are three main components of the solution: 21 | * Android Tablet - Primary front-end device for interacting with the car 22 | * Raspberry Pi - Mini-PC that handles communication between the IBUS adapter and the Android device 23 | * IBUS USB Adapter - USB adapter that provides USB/UART interface from physical wire in car 24 | 25 | ![Android_RPi_IBUS_Overview](https://s3-us-west-1.amazonaws.com/connected-car-static-files/connected_car_overview2.png) 26 | 27 | There is also an Android Wear (4.4W) component that allows you to control your vehicle from your smart watch! 28 | * Android Wear Device - Secondary device that provides quick interactions with the car 29 | 30 | ![Android_WEAR_IBUS_Overview](https://s3-us-west-1.amazonaws.com/connected-car-static-files/IBUS+Wear+UI+On+G+Watch.png) 31 | 32 | ## Pre-Requisites 33 | ### 1. Car Installation 34 | * Remove OEM Navigation Head Unit from BMW 35 | * Tap the 12V (red) wire, the GND (black) wire, and the IBUS (red/white/yellow) wire 36 | * Connect IBUS USB adapter to BMW (using 12V, GND, IBUS) 37 | * Install USB 12V - 5V adapter (using 12V, GND) 38 | * Install Raspberry Pi in the dash (and power w/ 5V from adapter) 39 | * Connect IBUS USB adapter to Raspberry Pi via USB cable 40 | * Connect Ethernet cable to Raspberry Pi (and wire to glove box) 41 | 42 | ### 2. Raspberry Pi 3 43 | * Install Raspbian (or another OS that supports python) 44 | * One tutorial [can be found here](http://computers.tutsplus.com/articles/how-to-flash-an-sd-card-for-raspberry-pi--mac-53600) 45 | * Pair Android device with Raspberry Pi via Bluetooth 46 | 47 | #### 2a. Running with Docker 48 | * Install docker and docker-compose 49 | * `curl -fsSL get.docker.com -o get-docker.sh && sh get-docker.sh` 50 | * `pip install docker-compose` 51 | * Download project and run with docker-compose 52 | * `git clone https://github.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller controller` 53 | * `cd controller/connected_car_controller/` 54 | * `docker-compose up --build -d` 55 | 56 | #### 2b. Running without Docker 57 | * Install packages 58 | * `apt-get install build-essential bluez bluez-tools libbluetooth-dev` 59 | * Download project 60 | * `git clone https://github.com/TrentSeed/BMW_E46_Android_RPi_IBUS_Controller controller` 61 | * `cd controller/connected_car_controller/` 62 | * Install python modules: 63 | * `pip install -r requirements.txt` 64 | * Run the project: `python3 start_controller.py bmw-e46` 65 | 66 | ### 3. Android Mobile / Tablet 67 | * Update `BluetoothInterface.remoteBluetoothAddress` of 'connected_car_app/common' with RPi Bluetooth address 68 | * Build Android project `connected_car_app/` via Android Studio 69 | * Install the applicaton 70 | * You can build and run in Android Studio by connecting your devices 71 | * You can also install by transfering the built APKs 72 | * `connected_car_app/app/build/outputs/apk/debug/app-debug.apk` 73 | * `connected_car_app/ibuswear/build/outputs/apk/debug/ibuswear-debug.apk` 74 | 75 | ## How To Get Started 76 | * Install the prerequisites above 77 | * Ensure Android device is paired with Raspberry Pi via Bluetooth 78 | * Run the controller as daemon: `docker-compose up -d` 79 | * Launch Connected Car App on your Android device or wearable -------------------------------------------------------------------------------- /connected_car_app/app/src/main/java/com/trentseed/bmw_rpi_ibus_controller/AdapterIBUS.java: -------------------------------------------------------------------------------- 1 | package com.trentseed.bmw_rpi_ibus_controller; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.Calendar; 5 | 6 | import android.annotation.SuppressLint; 7 | import android.graphics.Color; 8 | import android.util.TypedValue; 9 | import android.view.Gravity; 10 | import android.view.View; 11 | import android.view.ViewGroup; 12 | import android.view.ViewGroup.LayoutParams; 13 | import android.widget.BaseAdapter; 14 | import android.widget.GridView; 15 | import android.widget.ImageView; 16 | import android.widget.LinearLayout; 17 | import android.widget.TextView; 18 | 19 | import com.trentseed.bmw_rpi_ibus_controller.common.BluetoothInterface; 20 | import com.trentseed.bmw_rpi_ibus_controller.common.IBUSPacket; 21 | 22 | /** 23 | * Adapter that is used to display IBUS activity 24 | * @author Trent Seed 25 | */ 26 | public class AdapterIBUS extends BaseAdapter{ 27 | 28 | private ActivityIBUS thisActivity; 29 | 30 | AdapterIBUS(ActivityIBUS thisActivity){ 31 | //store context and determine enroll status 32 | this.thisActivity = thisActivity; 33 | } 34 | 35 | public int getCount() { 36 | return BluetoothInterface.mArrayListIBUSActivity.size(); 37 | } 38 | 39 | public IBUSPacket getItem(int position) { 40 | return BluetoothInterface.mArrayListIBUSActivity.get(position); 41 | } 42 | 43 | public long getItemId(int position) { 44 | return BluetoothInterface.mArrayListIBUSActivity.get(position).hashCode(); 45 | } 46 | 47 | @Override 48 | public void notifyDataSetChanged(){ 49 | super.notifyDataSetChanged(); 50 | 51 | if(this.getCount() == 0){ 52 | thisActivity.tvNoActivity.setVisibility(View.VISIBLE); 53 | }else{ 54 | thisActivity.tvNoActivity.setVisibility(View.GONE); 55 | } 56 | } 57 | 58 | public View getView(final int position, View convertView, ViewGroup parent) { 59 | // get this object 60 | IBUSPacket ibPacket = BluetoothInterface.mArrayListIBUSActivity.get(position); 61 | 62 | // create field view 63 | LinearLayout viewContainer = new LinearLayout(thisActivity); 64 | viewContainer.setOrientation(LinearLayout.HORIZONTAL); 65 | viewContainer.setGravity(Gravity.START); 66 | viewContainer.setPadding(40, 20, 20, 0); 67 | 68 | // packet image view 69 | float height = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 80 ,thisActivity.getResources().getDisplayMetrics()); 70 | ImageView ivPacket = new ImageView(thisActivity); 71 | ivPacket.setImageResource(R.drawable.packet); 72 | GridView.LayoutParams imgParams = new GridView.LayoutParams((int)height, (int)height); 73 | ivPacket.setLayoutParams(imgParams); 74 | ivPacket.setPadding(10, 10, 10, 10); 75 | 76 | // label 77 | TextView labelKey = new TextView(thisActivity); 78 | String labelText = "Source: " + ibPacket.source_id + " (" + ibPacket.getSourceName() + ") @ " 79 | + AdapterIBUS.getDate(Long.parseLong(ibPacket.timestamp), "hh:mm") + "\n" 80 | + "Destination: " + ibPacket.destination_id + " (" + ibPacket.getDestinationName() + ")\n" 81 | + "Datagram: " + ibPacket.raw; 82 | labelKey.setText(labelText); 83 | labelKey.setTextColor(Color.WHITE); 84 | GridView.LayoutParams params = new GridView.LayoutParams(LayoutParams.MATCH_PARENT, (int)height, 1); 85 | labelKey.setGravity(Gravity.CENTER_VERTICAL); 86 | labelKey.setPadding(40, 0, 0, 0); 87 | labelKey.setLayoutParams(params); 88 | labelKey.setTextSize(18.0f); 89 | 90 | // timestamp 91 | TextView tvTimestamp = new TextView(thisActivity); 92 | String labelTimestamp = ibPacket.timestamp; 93 | tvTimestamp.setText(labelTimestamp); 94 | tvTimestamp.setTextColor(Color.WHITE); 95 | GridView.LayoutParams paramsTimestamp = new GridView.LayoutParams(LayoutParams.MATCH_PARENT, (int)height, 1); 96 | tvTimestamp.setGravity(Gravity.CENTER_VERTICAL); 97 | tvTimestamp.setPadding(40, 0, 0, 0); 98 | tvTimestamp.setLayoutParams(paramsTimestamp); 99 | tvTimestamp.setTextSize(20.0f); 100 | 101 | // add sub-views to container view 102 | viewContainer.addView(ivPacket); 103 | viewContainer.addView(labelKey); 104 | //viewContainer.addView(tvTimestamp); 105 | return viewContainer; 106 | } 107 | 108 | /** 109 | * Return date in specified format. 110 | * @param milliSeconds Date in milliseconds 111 | * @param dateFormat Date format 112 | * @return String representing date in specified format 113 | */ 114 | @SuppressLint("SimpleDateFormat") 115 | private static String getDate(long milliSeconds, String dateFormat) 116 | { 117 | // Create a DateFormatter object for displaying date in specified format. 118 | SimpleDateFormat formatter = new SimpleDateFormat(dateFormat); 119 | 120 | // Create a calendar object that will convert the date and time value in milliseconds to date. 121 | Calendar calendar = Calendar.getInstance(); 122 | calendar.setTimeInMillis(milliSeconds); 123 | return formatter.format(calendar.getTime()); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /connected_car_app/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /connected_car_app/app/src/main/res/layout/activity_radio.xml: -------------------------------------------------------------------------------- 1 | 8 | 9 | 18 | 19 | 26 | 27 | 30 | 31 | 39 | 40 | 50 | 51 | 52 | 53 | 56 | 57 | 64 | 65 |