8000 GitHub - Arkasha18/H9-cluster: Source-available digital instrument cluster for Haval H9 (Android 9, 1920x720). · GitHub
[go: up one dir, main page]

Skip to content

About

Source-available digital instrument cluster for Haval H9 (Android 9, 1920x720).

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

13 stars

Watchers

0 watching

Forks

Latest commit

 

History

72 Commits

Folders and files

Repository files navigation

H9 Cluster 9.8.0

Иконка H9 Cluster

Android CI Latest release License: PolyForm Noncommercial

Неофициальная приборная панель для Haval H9 с головным устройством на Android 9 и дополнительным экраном Display ID 2 размером 1920×720.

  • Package name: net.adminrunet.h9cluster
  • Разработчик: admin.ru.net
  • Контакт: arkasha18@gmail.com
  • Модель распространения: source-available

Проект не связан с Great Wall Motor, Haval или производителем головного устройства и не одобрен ими. Названия и товарные знаки принадлежат их правообладателям.

Скины

Доступны восемь тем. Porcelain Fluid и APEX SPORT показаны нативным Canvas-рендером Robolectric, Sculpted Titanium — контрольным рендером с примерными данными, ION AURORA — в Demo с имитацией системных индикаторов; остальные снимки получены на реальном Display ID 2. Разрешение — 1920×720, изображения открываются по клику.

H9 Cluster Porcelain Fluid — нативный Canvas

H9 Cluster APEX SPORT — нативный Canvas

H9 Cluster Sculpted Titanium — контрольный рендер

H9 Cluster ION AURORA — Demo

Classic Sport
H9 Cluster Classic H9 Cluster Sport
Horizon Simple
H9 Cluster Horizon H9 Cluster Simple

Описание особенностей каждой темы и полноразмерная галерея приведены в документации по скинам.

Возможности

  • независимые темы Classic, Sport, Horizon, Simple, ION AURORA, Sculpted Titanium, APEX SPORT и Porcelain Fluid;
  • белая керамика с перламутровыми переливами, жидкостные приборы, бегущий свет вдоль шкал и компактные вспомогательные показания в Porcelain Fluid;
  • круглые спортивные приборы, графические указатели топлива и ОЖ, широкая карта в APEX SPORT;
  • рельефное титановое оформление с янтарной подсветкой, широким центром для карты и плавным переходом к ней в Sculpted Titanium;
  • плавный тахометр со стабилизированными цифрами в Sculpted Titanium, ION AURORA, APEX SPORT и Porcelain Fluid;
  • анимированные барабанные шкалы скорости и оборотов в ION AURORA;
  • отдельно откалиброванные по печатным делениям стрелки спидометра и тахометра в темах Classic и Sport;
  • общий выбор показаний спидометра: реальная скорость или заводской стиль +4,5% либо +5 км/ч; режим действует на все темы и меняет указатель и цифровое значение вместе;
  • скорость, обороты, пробег, топливо и запас хода;
  • общий числовой объём бака от 20 до 200 л, 80 л по умолчанию: литры и шкалы топлива во всех восьми темах учитывают выбранный объём; штатный запас хода продолжает поступать от автомобиля;
  • температура охлаждающей жидкости и наружного воздуха;
  • температура масла автоматической трансмиссии;
  • угол рулевого колеса;
  • давление в четырёх шинах;
  • четыре отдельные скорости колёс;
  • момент маховика, средний и мгновенный расход топлива и напряжение бортовой сети;
  • зелёный индикатор подключённого Wi-Fi в темах Classic, Sport, Horizon, Simple, ION AURORA, Sculpted Titanium, APEX SPORT и Porcelain Fluid;
  • часы под штатной передачей в согласованных рамках в ION AURORA, Classic и Sport; текущая дата дополнительно отображается в ION AURORA; в Sculpted Titanium время и дата расположены слева вверху;
  • выбор темы на основном экране;
  • общая галочка Номер передачи в теме во всех восьми скинах: можно скрыть дополнительную цифру, если её уже показывает штатная панель автомобиля; по умолчанию отображение включено;
  • вариант Штатная панель: приложение ничего не рисует и на Display ID 2 остаётся заводская приборная панель;
  • независимые настройки конкретной темы, если она предоставляет собственный редактор;
  • штатный QNX-блок предупреждений появляется поверх пользовательской панели через откалиброванное прозрачное окно;
  • встроенная проверка новых GitHub Releases в production-сборке с показом описания, загрузкой APK и установкой только после подтверждения пользователя;
  • ручная проверка обновления из общего экрана настроек всех тем с явным сообщением, когда установлена актуальная версия;
  • кнопка Выйти из приложения на экране настроек: панель на Display ID 2 закрывается, чтение автомобильных данных прекращается;
  • автоматический запуск панели на Display ID 2.

Источники данных и безопасность

Основные автомобильные данные читаются через штатный Binder-сервис:

com.gwm.android.adapter.server.GwmAdapterService

Приложение использует только операции чтения, регистрацию слушателя и снятие регистрации. Команды управления автомобилем, запись параметров и активные диагностические запросы не выполняются.

Для высокочастотного чтения оборотов и накопительного счётчика топлива 8000 ECM2 используется read-only подписка на svc://fdbus_mcu_ipc. Из изменения счётчика приложение рассчитывает мгновенный расход: в литрах в час на месте и в литрах на 100 км в движении. Необходимые ARM64-библиотеки из штатной системы головного устройства находятся в app/src/main/jniLibs/arm64-v8a/ и включаются в APK. Это сторонние бинарные компоненты; лицензия проекта на них не распространяется. Подробности приведены в THIRD_PARTY_NOTICES.md.

Если совместимые нативные библиотеки отсутствуют или не загружаются, приложение автоматически продолжает работу и получает RPM через Binder; тахометр при этом может обновляться реже, а мгновенный расход может быть недоступен.

Production-сборка при открытии экрана настроек проверяет последний релиз через GitHub API. Новая версия скачивается только после подтверждения пользователя. Перед передачей APK системному установщику приложение проверяет ожидаемое имя и HTTPS-адрес GitHub, имя пакета, увеличение versionCode и совпадение сертификата подписи с уже установленной версией. В Debug- и Demo-сборках проверка отключена.

Температура масла АКПП и независимые статусы двигателя/Park читаются без CAN-команд и UDS-запросов из уже обновляемого штатным ПО снимка /dev/shm/can_data_collect на TBOX. Приложение подключается к TBOX только для выполнения команды чтения; firewall, файлы и настройки TBOX не изменяются.

Пароль TBOX не хранится в репозитории. Перед production-сборкой передайте его как Gradle property либо переменную окружения:

H9_TBOX_PASSWORD='...' ./gradlew assembleRelease

Для GitHub Actions используйте Repository Secret H9_TBOX_PASSWORD. Во время сборки пароль преобразуется в две случайно маскированные последовательности, поэтому открытой строки в DEX нет. Без секрета APK собирается нормально, но источник температуры АКПП остаётся отключённым.

Маскирование защищает только от простого поиска строки и не является криптографическим хранилищем: автономный APK технически содержит всё необходимое для восстановления секрета во время работы. Не используйте в публичных сборках пароль, применяемый для других систем.

Значение для интерфейса приходит в общем ClusterState:

  • transmissionTemperatureC — температура в градусах Цельсия;
  • hasTransmissionTemperature() — false, пока первое значение не получено;
  • transmissionTemperatureUpdatedAtMs — время последнего обновления по SystemClock.elapsedRealtime().

Для разовой проверки масштаба одометра и среднего расхода поездки на машине есть отдельный безопасный и ограниченный по частоте тег. По умолчанию он выключен во всех сборках, включая release, и включается только явным opt-in:

adb shell setprop log.tag.H9TripTelemetry DEBUG
adb logcat -s H9TripTelemetry:D

Он выводит только числовые значения текущего счётчика поездки, преобразованного расстояния, среднего расхода cur_journey_avg_fuel_consumption_a с признаками валидности, оборотов, скорости и monotonic timestamp — не чаще одного раза в секунду. Этот диагностический лог не выводит мгновенный расход. На голове car.basic.instant_fuel_consumption отдаёт NaN, поэтому интерфейс получает мгновенный расход отдельно из read-only счётчика ECM2.

Чтобы снова выключить лог:

adb shell setprop log.tag.H9TripTelemetry ""

Перед публикацией фрагментов logcat убедитесь, что в них нет других тегов с VIN, координатами или служебными данными автомобиля.

Отправка журнала поддержки

Production-версия ведёт отдельный структурированный кольцевой журнал для редких проблем завершения поездки и источников автомобильных данных. В нём фиксируются жизненный цикл панели, решение детектора двигателя, состояние FLAG_KEEP_SCREEN_ON, доступность сигналов GWM Adapter, переключение скорости между Binder и MCU, статистика FDBus, а также подключение, чтение и разбор температуры, двигателя, Park и EPB из TBOX. Сырые CAN/FDBus-пакеты и пароль TBOX не записываются. Для диагностики недоступной температуры сохраняются только метка поколения снимка и десять производных 8-битных температурных кодов без остальных байтов записей; событие пишется при смене статуса и в редкой периодической сводке. Чтение ограничено 4097 байтами, чтобы определить фактический размер альтернативного формата без неограниченного дампа.

На экране настроек показан код вида H9-XXXXX-XXXXX. Приложение пытается получить VIN только через штатную read-only операцию GET_DATA, строит из него короткий хеш-код и сразу отбрасывает исходное значение. VIN не сохраняется и не отправляется. Пока VIN недоступен, интерфейс явно показывает резервный код установки; после успешного чтения он автоматически заменяется VIN-кодом.

Кнопка Отправить логи вручную передаёт на https://logs.admin.ru.net/api/v1/uploads только последние 24 часа. Локальное кольцо ограничено 2 МиБ, gzip-запрос — 1 МиБ. После успешной отправки водитель сообщает показанный код машины, по которому оператор находит журнал. Debug и Demo не показывают кнопку и ничего автоматически не отправляют.

Чтобы журнал не создавал постоянную нагрузку, периодические срезы источников и состояния панели записываются не чаще одного раза в минуту, а успешное чтение TBOX — не чаще одного раза в пять минут. Ошибки, восстановления и переходы завершения поездки фиксируются сразу. Фоновой отправки, очереди и повторных сетевых попыток нет.

Карточка ATF выводится во всех зарегистрированных темах справа от защищённой зоны штатного правого поворотника. Если значение не получено либо не обновлялось более 15 секунд, интерфейс показывает — °C.

Цвет числа и рамки карточки помогает заметить рост температуры:

  • до 99 °C — штатный белый цвет;
  • 100–109 °C — жёлтый;
  • 110–119 °C — оранжевый;
  • от 120 °C — красный.

Для защиты от переключения цветов около границы используется гистерезис: возврат из красного диапазона происходит ниже 115 °C, из оранжевого — ниже 107 °C, из жёлтого — ниже 97 °C. Это информационные пороги интерфейса, а не замена штатному индикатору перегрева и требованиям руководства автомобиля.

Карточка GEAR показывает положение селектора: P — паркинг, R — задний ход, N — нейтраль. В положении движения вперёд и в ручном режиме к букве добавляется номер включённой ступени, например D3 и M2; пока номер не получен, остаётся одна буква. Числовые коды положений, которые отдаёт штатный адаптер, сняты на автомобиле и перечислены в GearSelector.

Исключение — темы Simple, ION AURORA, Classic и Sport: они рисуют только номер ступени 1–8 в положении D. В остальных положениях поле пустое, чтобы не дублировать заводскую надпись рядом с этим местом.

Сборка

Воспроизводимая Docker-сборка

Docker-образ содержит JDK 17, Android SDK 35 и Python-зависимости инструментов создания тем. Исходники, APK и ключи подписи в образ не копируются.

На компьютерах Apple Silicon также указывайте linux/amd64, поскольку Android Build Tools внутри контейнера рассчитаны на эту архитектуру:

docker build --platform linux/amd64 -t h9-cluster-build .
docker run --rm --platform linux/amd64 \
  -v "$PWD:/workspace" -w /workspace \
  h9-cluster-build

По умолчанию контейнер выполняет assembleDebug и lint. Готовый образ из GitHub Container Registry можно использовать без локальной сборки:

docker pull --platform linux/amd64 \
  ghcr.io/arkasha18/h9-cluster-build:android35-jdk17
docker run --rm --platform linux/amd64 \
  -v "$PWD:/workspace" -w /workspace \
  ghcr.io/arkasha18/h9-cluster-build:android35-jdk17

Локальная сборка

Требуются:

  • JDK 17;
  • Android SDK Platform 35;
  • Android SDK Build Tools 35;
  • ARM64-устройство с Android 9 для проверки в автомобиле.

Debug APK собирается без ключей:

./gradlew assembleDebug

Результат:

app/build/outputs/apk/debug/app-debug.apk

Автономный Demo APK с автоматически меняющимися тестовыми значениями:

./gradlew assembleDemo

Результат:

app/build/outputs/apk/demo/app-demo.apk

Demo не подключается к GWM Adapter, FDBus, CAN или TBOX. Для проверки на одном экране эмулятора:

adb shell settings delete global overlay_display_devices
adb shell wm size 1920x720
adb shell wm density 240
./gradlew installDemo
adb shell am start -W \
  -n net.adminrunet.h9cluster.demo/net.adminrunet.h9cluster.SettingsActivity

Кнопка сохранения откроет приборную панель на том же экране. Чтобы проверить экран итогов поездки:

  1. подождите не менее секунды, пока будет подтверждён запуск двигателя;
  2. нажмите на левый спидометр;
  3. подождите 1,5 секунды подтверждения остановки;
  4. проверьте расстояние, средний расход и длительность;
  5. нажмите на экран итогов, чтобы вернуться к настройкам.

Клик вне левого спидометра и системная кнопка Back также возвращают настройки. Чтобы вернуть стандартный размер эмулятора:

adb shell wm size reset
adb shell wm density reset

Для двухэкранной проверки:

adb shell settings put global overlay_display_devices '1920x720/240'
adb shell am force-stop net.adminrunet.h9cluster.demo
adb shell am start -W \
  -n net.adminrunet.h9cluster.demo/net.adminrunet.h9cluster.SettingsActivity

При наличии Display ID 2 приборная панель автоматически откроется на нём.

Для воспроизводимой проверки недоступного расхода можно напрямую запустить Demo preview с тестовым параметром:

adb shell am start -W \
  -n net.adminrunet.h9cluster.demo/net.adminrunet.h9cluster.PreviewActivity \
  --ez demo_invalid_consumption true

После остановки средний расход и израсходованное топливо будут показаны как —, а расстояние и длительность останутся числовыми.

Итоги поездки считаются только по двум штатным read-only сигналам: car.basic.cur_journey_odometer для расстояния и car.basic.cur_journey_avg_fuel_consumption_a для среднего расхода, откуда получается израсходованное топливо. Показатель car.basic.avg_fuel_consumption (индикатор B) используется только шкалой приборки и никогда не подменяет A в итогах: если A недоступен, невалиден или источник перестал публиковать значение, расход и топливо показываются как —.

Поездка завершается после 1,5 секунды непрерывного подтверждения одним из двух read-only путей: фактически полученный RPM ≤ 50 с нулевой скоростью либо свежие состояния TBOX engine stopped + Park. Последняя нулевая скорость сохраняется до 60 секунд, чтобы принять запаздывающий нулевой RPM после затихания шины; новое движение сразу отменяет её. Свежий TBOX-статус не-Park защищает оба пути от ложного завершения при работе start-stop в D/N. Само по себе отсутствие обновлений RPM остановкой двигателя не считается.

При удалённом запуске неизменившийся ноль может не публиковаться ни GWM, ни событийным ABS3. Пока измеренная скорость недоступна, все темы показывают 0 только при свежем сочетании TBOX engine running + Park. Это исключительно визуальная подстановка: внутри источника остаётся speedKph=-1, и детектор поездки не получает ложного подтверждения остановки.

Даже если H9_TBOX_PASSWORD настроен локально, Demo variant принудительно оставляет поля секрета пустыми. Проверка unit-контракта, APK и lint:

./gradlew testDemoUnitTest lintDemo assembleDemo
tools/verify_demo_apk_secrets.sh \
  app/build/outputs/apk/demo/app-demo.apk

Для локальной контрольной release-сборки используйте production-ключ из пользовательского ~/.gradle/gradle.properties, который находится за пределами репозитория:

H9_CLUSTER_STORE_FILE=/absolute/path/to/your-release-key.p12
H9_CLUSTER_STORE_TYPE=PKCS12
H9_CLUSTER_STORE_PASSWORD=your-password
H9_CLUSTER_KEY_ALIAS=your-key-alias
H9_CLUSTER_KEY_PASSWORD=your-password

После этого:

./gradlew assembleRelease

Файлы ключей, локальные свойства, APK/AAB и каталоги сборки исключены через .gitignore. Автоматическая публикация использует отдельный защищённый GitHub Environment release: ключ выдаётся только signing job после личного подтверждения владельца, не передаётся Gradle/Docker и не попадает в checkout или Actions artifacts.

Порядок выпуска подписанной версии приведён в docs/RELEASING_RU.md.

Непрерывная интеграция

GitHub Actions для каждого Pull Request:

  1. собирает зафиксированный Docker toolchain;
  2. проверяет генерацию Forum Kit и обработку графики темы;
  3. тестирует, проверяет lint и собирает Debug и Demo variants;
  4. проверяет отсутствие TBOX secret material в Demo APK;
  5. сохраняет Debug и Demo APK отдельными временными Actions artifacts;
  6. после попадания проверенного commit в main публикует toolchain в GHCR.

Отдельный workflow Production release никогда не запускается от обычного коммита в main. Только Arkasha18 может вручную проверить либо опубликовать точную версию и полный commit SHA. Production-сборка, подпись, сверка сертификата и создание Immutable Release выполняются раздельными job; перед доступом к signing secrets требуется подтверждение Environment release.

Установка

adb install -r app/build/outputs/apk/debug/app-debug.apk
adb shell am start -W -n net.adminrunet.h9cluster/.SettingsActivity
adb shell am start --display 2 -W \
  -n net.adminrunet.h9cluster/.PreviewActivity

Проверка подключения к штатному Adapter и TBOX:

adb logcat -s GwmClusterDataSource FdbusRpmReader TransmissionTemp

Для успешного Binder- и TBOX-подключения в журнале появляются:

GWM adapter connected; live listener active
Connected to read-only TBOX temperature source

Выход из приложения

На экране настроек внизу расположена кнопка Выйти из приложения. После подтверждения закрывается окно панели на Display ID 2, останавливается чтение автомобильных данных и закрывается сам экран настроек. adb shell am force-stop для этого больше не нужен.

Выход запоминается: после перезагрузки головного устройства панель не запускается автоматически. Автозапуск восстанавливается, как только приложение открывается вручную.

Сохранённая тема и её настройки при выходе не изменяются. Если нужно убрать наложение, но оставить приложение работающим, выберите тему Штатная панель.

Что намеренно не публикуется

В репозиторий не входят:

  • ключи подписи и пароли;
  • собранные APK/AAB;
  • дампы автомобиля и сетевые снимки;
  • заводские APK, ODEX/VDEX и конфигурации;
  • декомпилированный smali-код;
  • TBOX-бинарники и диагностические инструменты;
  • локальные исследовательские отчёты и исходные диагностические материалы.

Эти материалы не нужны для компиляции рабочего приложения. Соответствующие локальные каталоги перечислены в .gitignore.

Документация и создание тем

Каталог docs/ содержит:

  • инструкцию подготовки JDK, Android SDK, Python и локального Codex;
  • процесс «компоновка → оформление и подгонка → нативный Demo → реальные данные», полный состав показаний и готовые задания для разработки темы;
  • актуальный шаблон 1920×720 с откалиброванной на автомобиле чёрной подложкой и точными полями v2.4: строгие нижние левые зоны отделены от полей, под которыми разрешён декор; есть цветное наложение и system_fields.json (каталог, ZIP);
  • учебный автономный Demo v8.0.7 в H9_Cluster_Dashboard_Demo_Base_Source_v3.zip; для нового скина используйте build type demo текущего репозитория, чтобы сохранить актуальный контракт;
  • H9_Cluster_Codex_Forum_Kit_v3.zip для передачи полного комплекта другому разработчику.

Каталог tools/ содержит воспроизводимые Python-инструменты:

  • build_forum_design_template.py — пересобирает актуальный комплект шаблона без изменения публичных имён файлов;
  • package_skin_design_kit.py — синхронизирует три публичных ZIP с документацией и шаблоном; --check проверяет содержимое без записи;
  • edit_classic_background.py — формирует подложку и независимый overlay Classic с утверждённой геометрией.

Для запуска инструментов нужны Python 3, Pillow и NumPy:

python3 -m venv .venv
.venv/bin/python -m pip install -r requirements-tools.txt

Подробный процесс описан в docs/FORUM_DESIGN_PROMPTS_RU.md.

Участие и поддержка

Перед отправкой изменений ознакомьтесь с правилами сообщества. В Pull Request автоматически проверяются сборка и Android Lint.

Сторонние компоненты

Шрифты, Gradle Wrapper и нативные .so являются сторонними компонентами и не переводятся под PolyForm. Полный перечень приведён в THIRD_PARTY_NOTICES.md.

Лицензия

Код и оригинальные ресурсы проекта, права на которые принадлежат admin.ru.net, доступны по PolyForm Noncommercial License 1.0.0.

Некоммерческое использование, изменение и распространение разрешены бесплатно на условиях лицензии. Коммерческое использование требует отдельного письменного соглашения с правообладателем: arkasha18@gmail.com.

Это source-available, а не OSI Open Source проект. Сторонние компоненты остаются под собственными лицензиями.

Отказ от гарантий

Программное обеспечение предоставляется «как есть». Использование приложения в автомобиле выполняется на риск пользователя. Перед поездкой необходимо убедиться, что панель не мешает штатным предупреждениям и обязательным индикаторам автомобиля.

About

Source-available digital instrument cluster for Haval H9 (Android 9, 1920x720).

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

13 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages

0