diff --git a/.github/workflows/auto_pr_review.yaml b/.github/workflows/auto_pr_review.yaml index ec78f276a5..b9664b9066 100644 --- a/.github/workflows/auto_pr_review.yaml +++ b/.github/workflows/auto_pr_review.yaml @@ -1,7 +1,7 @@ name: "PR review" on: pull_request_target: - types: [opened, reopened, synchronize, edited] + types: [ opened, reopened, synchronize, edited ] jobs: labeler: @@ -39,7 +39,7 @@ jobs: name: Update fork's PR Labels runs-on: ubuntu-latest if: (github.event.pull_request.head.repo.fork && (contains(github.event_name, 'pull_request') && github.event.action == 'synchronize')) - env: + env: PR_LABEL: 'dev-c3' TRUST_FORK_PR_LABEL: 'trust-fork-pr' steps: @@ -64,7 +64,7 @@ jobs: core.setOutput('has-dev-c3', hasDevC3Label ? 'true' : 'false'); core.setOutput('has-trust', hasTrustLabel ? 'true' : 'false'); - + - name: Remove trust-fork-pr label if present if: steps.check-labels.outputs.has-dev-c3 == 'true' && steps.check-labels.outputs.has-trust == 'true' uses: actions/github-script@v7 @@ -72,14 +72,14 @@ jobs: github-token: ${{ secrets.GITHUB_TOKEN }} script: | const prNumber = context.payload.pull_request.number; - + await github.rest.issues.removeLabel({ owner: context.repo.owner, repo: context.repo.repo, issue_number: prNumber, name: process.env.TRUST_FORK_PR_LABEL }); - + console.log(`Removed '${process.env.TRUST_FORK_PR_LABEL}' label from PR #${prNumber} as it received new commits`); // Add a comment to the PR diff --git a/.github/workflows/lfs-maintenance.yaml b/.github/workflows/lfs-maintenance.yaml index aea918b530..8780abfbb3 100644 --- a/.github/workflows/lfs-maintenance.yaml +++ b/.github/workflows/lfs-maintenance.yaml @@ -13,7 +13,7 @@ on: pull_request: branches: - 'master' - workflow_dispatch: # enables manual triggering + workflow_dispatch: # enables manual triggering inputs: upstream_branch: default: 'master' @@ -30,7 +30,7 @@ jobs: with: repository: 'commaai/openpilot' ref: ${{ inputs.upstream_branch }} - + - name: LFS Fetch run: | git lfs fetch @@ -48,7 +48,7 @@ jobs: - name: Add GitLab public keys run: | ssh-keyscan -H gitlab.com >> ~/.ssh/known_hosts - + - name: Ensure branch run: | if git symbolic-ref -q HEAD >/dev/null; then diff --git a/.github/workflows/selfdrive_tests.yaml b/.github/workflows/selfdrive_tests.yaml index b031f2f634..6ee4f05018 100644 --- a/.github/workflows/selfdrive_tests.yaml +++ b/.github/workflows/selfdrive_tests.yaml @@ -18,7 +18,6 @@ concurrency: cancel-in-progress: true env: - REPORT_NAME: report-${{ inputs.run_number || '1' }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && 'master' || github.event.number }} PYTHONWARNINGS: error BASE_IMAGE: openpilot-base AZURE_TOKEN: ${{ secrets.AZURE_COMMADATACI_OPENPILOTCI_TOKEN }} @@ -34,8 +33,12 @@ jobs: build_release: if: github.repository == 'commaai/openpilot' # build_release blocked for the time being to only comma as we may have a different process. name: build release - runs-on: - - 'ubuntu-24.04' + runs-on: ${{ + (github.repository == 'commaai/openpilot') && + ((github.event_name != 'pull_request') || + (github.event.pull_request.head.repo.full_name == 'commaai/openpilot')) + && fromJSON('["namespace-profile-amd64-8x16", "namespace-experiments:docker.builds.local-cache=separate"]') + || fromJSON('["ubuntu-24.04"]') }} env: STRIPPED_DIR: /tmp/releasepilot steps: @@ -68,8 +71,12 @@ jobs: run: release/check-submodules.sh build: - runs-on: - - 'ubuntu-24.04' + runs-on: ${{ + (github.repository == 'commaai/openpilot') && + ((github.event_name != 'pull_request') || + (github.event.pull_request.head.repo.full_name == 'commaai/openpilot')) + && fromJSON('["namespace-profile-amd64-8x16", "namespace-experiments:docker.builds.local-cache=separate"]') + || fromJSON('["ubuntu-24.04"]') }} steps: - uses: actions/checkout@v4 with: @@ -85,6 +92,7 @@ jobs: build_mac: name: build macOS + if: false # temp disable since homebrew install is getting stuck runs-on: ${{ ((github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot'))) && 'namespace-profile-macos-8x14' || 'macos-latest' }} steps: - uses: actions/checkout@v4 @@ -130,8 +138,12 @@ jobs: static_analysis: name: static analysis - runs-on: - - 'ubuntu-latest' + runs-on: ${{ + (github.repository == 'commaai/openpilot') && + ((github.event_name != 'pull_request') || + (github.event.pull_request.head.repo.full_name == 'commaai/openpilot')) + && fromJSON('["namespace-profile-amd64-8x16", "namespace-experiments:docker.builds.local-cache=separate"]') + || fromJSON('["ubuntu-24.04"]') }} env: PYTHONWARNINGS: default steps: @@ -145,17 +157,22 @@ jobs: unit_tests: name: unit tests - runs-on: - - 'ubuntu-24.04' + runs-on: ${{ + (github.repository == 'commaai/openpilot') && + ((github.event_name != 'pull_request') || + (github.event.pull_request.head.repo.full_name == 'commaai/openpilot')) + && fromJSON('["namespace-profile-amd64-8x16", "namespace-experiments:docker.builds.local-cache=separate"]') + || fromJSON('["ubuntu-24.04"]') }} steps: - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/workflows/setup-with-retry + id: setup-step - name: Build openpilot run: ${{ env.RUN }} "scons -j$(nproc)" - name: Run unit tests - timeout-minutes: ${{ contains(runner.name, 'nsc') && 1 || 20 }} + timeout-minutes: ${{ contains(runner.name, 'nsc') && ((steps.setup-step.outputs.duration < 18) && 1 || 2) || 999 }} run: | ${{ env.RUN }} "$PYTEST --collect-only -m 'not slow' &> /dev/null && \ MAX_EXAMPLES=1 $PYTEST -m 'not slow' && \ @@ -165,14 +182,19 @@ jobs: process_replay: name: process replay - if: github.repository == 'commaai/openpilot' # disable process_replay for forks - runs-on: - - 'ubuntu-24.04' + if: false # disable process_replay for forks + runs-on: ${{ + (github.repository == 'commaai/openpilot') && + ((github.event_name != 'pull_request') || + (github.event.pull_request.head.repo.full_name == 'commaai/openpilot')) + && fromJSON('["namespace-profile-amd64-8x16", "namespace-experiments:docker.builds.local-cache=separate"]') + || fromJSON('["ubuntu-24.04"]') }} steps: - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/workflows/setup-with-retry + id: setup-step - name: Cache test routes id: dependency-cache uses: actions/cache@v4 @@ -183,7 +205,7 @@ jobs: run: | ${{ env.RUN }} "scons -j$(nproc)" - name: Run replay - timeout-minutes: ${{ contains(runner.name, 'nsc') && (steps.dependency-cache.outputs.cache-hit == 'true') && 1 || 20 }} + timeout-minutes: ${{ contains(runner.name, 'nsc') && (steps.dependency-cache.outputs.cache-hit == 'true') && ((steps.setup-step.outputs.duration < 18) && 1 || 2) || 20 }} run: | ${{ env.RUN }} "selfdrive/test/process_replay/test_processes.py -j$(nproc) && \ chmod -R 777 /tmp/comma_download_cache" @@ -208,106 +230,26 @@ jobs: ${{ env.RUN }} "ONNXCPU=1 $PYTEST selfdrive/test/process_replay/test_regen.py && \ chmod -R 777 /tmp/comma_download_cache" - test_cars: - name: cars - runs-on: - - 'ubuntu-24.04' - strategy: - fail-fast: false - matrix: - job: [0, 1, 2, 3] - steps: - - uses: actions/checkout@v4 - with: - submodules: true - - uses: ./.github/workflows/setup-with-retry - - name: Cache test routes - id: routes-cache - uses: actions/cache@v4 - with: - path: .ci_cache/comma_download_cache - key: car_models-${{ hashFiles('selfdrive/car/tests/test_models.py', 'opendbc/car/tests/routes.py') }}-${{ matrix.job }} - - name: Build openpilot - run: ${{ env.RUN }} "scons -j$(nproc)" - - name: Test car models - timeout-minutes: ${{ contains(runner.name, 'nsc') && (steps.routes-cache.outputs.cache-hit == 'true') && 1 || 6 }} - run: | - ${{ env.RUN }} "MAX_EXAMPLES=1 $PYTEST selfdrive/car/tests/test_models.py && \ - chmod -R 777 /tmp/comma_download_cache" - env: - NUM_JOBS: 4 - JOB_ID: ${{ matrix.job }} - - car_docs_diff: - name: PR comments - runs-on: ubuntu-latest - #if: github.event_name == 'pull_request' - if: false # TODO: run this in opendbc? - steps: - - uses: actions/checkout@v4 - with: - submodules: true - ref: ${{ github.event.pull_request.base.ref }} - - run: git lfs pull - - uses: ./.github/workflows/setup-with-retry - - name: Get base car info - run: | - ${{ env.RUN }} "scons -j$(nproc) && python3 selfdrive/debug/dump_car_docs.py --path /tmp/openpilot_cache/base_car_docs" - sudo chown -R $USER:$USER ${{ github.workspace }} - - uses: actions/checkout@v4 - with: - submodules: true - path: current - - run: cd current && git lfs pull - - name: Save car docs diff - id: save_diff - run: | - cd current - ${{ env.RUN }} "scons -j$(nproc)" - output=$(${{ env.RUN }} "python3 selfdrive/debug/print_docs_diff.py --path /tmp/openpilot_cache/base_car_docs") - output="${output//$'\n'/'%0A'}" - echo "::set-output name=diff::$output" - - name: Find comment - if: ${{ env.AZURE_TOKEN != '' }} - uses: peter-evans/find-comment@3eae4d37986fb5a8592848f6a574fdf654e61f9e - id: fc - with: - issue-number: ${{ github.event.pull_request.number }} - body-includes: This PR makes changes to - - name: Update comment - if: ${{ steps.save_diff.outputs.diff != '' && env.AZURE_TOKEN != '' }} - uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 - with: - comment-id: ${{ steps.fc.outputs.comment-id }} - issue-number: ${{ github.event.pull_request.number }} - body: "${{ steps.save_diff.outputs.diff }}" - edit-mode: replace - - name: Delete comment - if: ${{ steps.fc.outputs.comment-id != '' && steps.save_diff.outputs.diff == '' && env.AZURE_TOKEN != '' }} - uses: actions/github-script@v7 - with: - script: | - github.rest.issues.deleteComment({ - owner: context.repo.owner, - repo: context.repo.repo, - comment_id: ${{ steps.fc.outputs.comment-id }} - }) - simulator_driving: name: simulator driving - runs-on: - - 'ubuntu-24.04' + runs-on: ${{ + (github.repository == 'commaai/openpilot') && + ((github.event_name != 'pull_request') || + (github.event.pull_request.head.repo.full_name == 'commaai/openpilot')) + && fromJSON('["namespace-profile-amd64-8x16", "namespace-experiments:docker.builds.local-cache=separate"]') + || fromJSON('["ubuntu-24.04"]') }} if: (github.repository == 'commaai/openpilot') && ((github.event_name != 'pull_request') || (github.event.pull_request.head.repo.full_name == 'commaai/openpilot')) steps: - uses: actions/checkout@v4 with: submodules: true - uses: ./.github/workflows/setup-with-retry + id: setup-step - name: Build openpilot run: | ${{ env.RUN }} "scons -j$(nproc)" - name: Driving test - timeout-minutes: 1 + timeout-minutes: ${{ (steps.setup-step.outputs.duration < 18) && 1 || 2 }} run: | ${{ env.RUN }} "source selfdrive/test/setup_xvfb.sh && \ source selfdrive/test/setup_vsound.sh && \ @@ -316,8 +258,13 @@ jobs: create_ui_report: # This job name needs to be the same as UI_JOB_NAME in ui_preview.yaml name: Create UI Report - runs-on: - - 'ubuntu-24.04' + runs-on: ${{ + (github.repository == 'commaai/openpilot') && + ((github.event_name != 'pull_request') || + (github.event.pull_request.head.repo.full_name == 'commaai/openpilot')) + && fromJSON('["namespace-profile-amd64-8x16", "namespace-experiments:docker.builds.local-cache=separate"]') + || fromJSON('["ubuntu-24.04"]') }} + if: false # FIXME: FrameReader is broken on CI runners steps: - uses: actions/checkout@v4 with: @@ -341,5 +288,5 @@ jobs: - name: Upload Test Report uses: actions/upload-artifact@v4 with: - name: ${{ env.REPORT_NAME }} + name: report-${{ inputs.run_number || '1' }}-${{ github.event_name == 'push' && github.ref == 'refs/heads/master' && 'master' || github.event.number }} path: selfdrive/ui/tests/test_ui/report_1/screenshots diff --git a/.github/workflows/setup-with-retry/action.yaml b/.github/workflows/setup-with-retry/action.yaml index ad297403cf..98a3913600 100644 --- a/.github/workflows/setup-with-retry/action.yaml +++ b/.github/workflows/setup-with-retry/action.yaml @@ -10,9 +10,17 @@ inputs: required: false default: 30 +outputs: + duration: + description: 'Duration of the setup process in seconds' + value: ${{ steps.get_duration.outputs.duration }} + runs: using: "composite" steps: + - id: start_time + shell: bash + run: echo "START_TIME=$(date +%s)" >> $GITHUB_ENV - id: setup1 uses: ./.github/workflows/setup continue-on-error: true @@ -35,3 +43,10 @@ runs: uses: ./.github/workflows/setup with: is_retried: true + - id: get_duration + shell: bash + run: | + END_TIME=$(date +%s) + DURATION=$((END_TIME - START_TIME)) + echo "Total duration: $DURATION seconds" + echo "duration=$DURATION" >> $GITHUB_OUTPUT diff --git a/.github/workflows/sunnypilot-build-prebuilt.yaml b/.github/workflows/sunnypilot-build-prebuilt.yaml index cd785b3f56..4f52e7fa29 100644 --- a/.github/workflows/sunnypilot-build-prebuilt.yaml +++ b/.github/workflows/sunnypilot-build-prebuilt.yaml @@ -80,10 +80,10 @@ jobs: - name: Set Feature Branch Prebuilt Configuration id: set_feature_configuration if: ( - !(env.SOURCE_BRANCH == env.DEV_C3_SOURCE_BRANCH) && - !(env.SOURCE_BRANCH == env.STAGING_C3_SOURCE_BRANCH) && - !(startsWith(github.ref, 'refs/tags/')) - ) + !(env.SOURCE_BRANCH == env.DEV_C3_SOURCE_BRANCH) && + !(env.SOURCE_BRANCH == env.STAGING_C3_SOURCE_BRANCH) && + !(startsWith(github.ref, 'refs/tags/')) + ) run: | echo "NEW_BRANCH=${{ env.SOURCE_BRANCH }}${{ github.event.pull_request.head.repo.fork && '-fork' || '' }}-prebuilt" >> $GITHUB_ENV echo "VERSION=$(date '+%Y.%m.%d')-${{ github.run_number }}" >> $GITHUB_ENV @@ -91,9 +91,9 @@ jobs: - name: Set dev-c3-new prebuilt Configuration id: set_dev_configuration if: ( - steps.set_feature_configuration.outcome == 'skipped' && - env.SOURCE_BRANCH == env.DEV_C3_SOURCE_BRANCH - ) + steps.set_feature_configuration.outcome == 'skipped' && + env.SOURCE_BRANCH == env.DEV_C3_SOURCE_BRANCH + ) run: | echo "NEW_BRANCH=${{ env.DEV_TARGET_BRANCH }}" >> $GITHUB_ENV echo "VERSION=$(date '+%Y.%m.%d')-${{ github.run_number }}" >> $GITHUB_ENV @@ -102,11 +102,11 @@ jobs: - name: Set staging-c3-new prebuilt Configuration id: set_staging_configuration if: ( - steps.set_feature_configuration.outcome == 'skipped' && - !contains(github.event_name, 'pull_request') && - steps.set_dev_configuration.outcome == 'skipped' && - (env.SOURCE_BRANCH == env.STAGING_C3_SOURCE_BRANCH) - ) + steps.set_feature_configuration.outcome == 'skipped' && + !contains(github.event_name, 'pull_request') && + steps.set_dev_configuration.outcome == 'skipped' && + (env.SOURCE_BRANCH == env.STAGING_C3_SOURCE_BRANCH) + ) run: | echo "NEW_BRANCH=${{ env.STAGING_TARGET_BRANCH }}" >> $GITHUB_ENV echo "EXTRA_VERSION_IDENTIFIER=staging" >> $GITHUB_ENV @@ -115,11 +115,11 @@ jobs: - name: Set release-c3-new prebuilt Configuration id: set_tag_configuration if: ( - steps.set_feature_configuration.outcome == 'skipped' && - !contains(github.event_name, 'pull_request') && - steps.set_staging_configuration.outcome == 'skipped' && - startsWith(github.ref, 'refs/tags/') - ) + steps.set_feature_configuration.outcome == 'skipped' && + !contains(github.event_name, 'pull_request') && + steps.set_staging_configuration.outcome == 'skipped' && + startsWith(github.ref, 'refs/tags/') + ) run: | echo "NEW_BRANCH=${{ env.RELEASE_TARGET_BRANCH }}" >> $GITHUB_ENV echo "EXTRA_VERSION_IDENTIFIER=release" >> $GITHUB_ENV @@ -227,7 +227,6 @@ jobs: run: | PYTHONPATH=$PYTHONPATH:${{ github.workspace }}/ ${{ github.workspace }}/scripts/manage-powersave.py --enable - publish: concurrency: group: publish-${{ github.head_ref || github.ref_name }} @@ -268,7 +267,7 @@ jobs: "${{ needs.build.outputs.version }}" \ "https://x-access-token:${{github.token}}@github.com/sunnypilot/sunnypilot.git" \ "-${{ needs.build.outputs.extra_version_identifier }}" - + echo "" echo "---- ℹ️ To update the list of branches that auto deploy prebuilts -----" echo "" @@ -299,7 +298,7 @@ jobs: export extra_version_identifier=${{ needs.build.outputs.extra_version_identifier || github.run_number}} echo ${TEMPLATE} | envsubst | jq -c '.' | tee payload.json curl -X POST -H "Content-Type: application/json" -d @payload.json $DISCORD_WEBHOOK - + echo "" echo "---- ℹ️ To update the list of branches that notify to dev-feedback -----" echo "" @@ -307,7 +306,7 @@ jobs: echo "2. Current value: ${{ vars.DEV_FEEDBACK_NOTIFICATION_BRANCHES }}" echo "3. Update as needed (JSON array with no spaces)" shell: alpine.sh {0} - + manage-pr-labels: name: Remove prebuilt label runs-on: ubuntu-latest diff --git a/.github/workflows/sunnypilot-master-dev-c3-prep.yaml b/.github/workflows/sunnypilot-master-dev-c3-prep.yaml index 13c8d5cb37..d4c201824e 100644 --- a/.github/workflows/sunnypilot-master-dev-c3-prep.yaml +++ b/.github/workflows/sunnypilot-master-dev-c3-prep.yaml @@ -12,8 +12,8 @@ on: branches: - master pull_request_target: - types: [ labeled ] - branches: + types: [ labeled ] + branches: - 'master' workflow_dispatch: inputs: @@ -41,10 +41,10 @@ jobs: reset-and-squash: runs-on: ubuntu-latest if: ( - (github.event_name == 'workflow_dispatch') - || (github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)) - || (contains(github.event_name, 'pull_request') && ((github.event.action == 'labeled' && (github.event.label.name == 'dev-c3' || github.event.label.name == 'trust-fork-pr') && contains(github.event.pull_request.labels.*.name, 'dev-c3')))) - ) + (github.event_name == 'workflow_dispatch') + || (github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)) + || (contains(github.event_name, 'pull_request') && ((github.event.action == 'labeled' && (github.event.label.name == 'dev-c3' || github.event.label.name == 'trust-fork-pr') && contains(github.event.pull_request.labels.*.name, 'dev-c3')))) + ) steps: - uses: actions/checkout@v4 with: @@ -54,9 +54,9 @@ jobs: - name: Wait for Tests uses: ./.github/workflows/wait-for-action # Path to where you place the action if: ( - (github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)) - || (contains(github.event_name, 'pull_request') && ((github.event.action == 'labeled' && (github.event.label.name == 'dev-c3' || github.event.label.name == 'trust-fork-pr') && contains(github.event.pull_request.labels.*.name, 'dev-c3')))) - ) + (github.event_name == 'push' && github.ref == format('refs/heads/{0}', github.event.repository.default_branch)) + || (contains(github.event_name, 'pull_request') && ((github.event.action == 'labeled' && (github.event.label.name == 'dev-c3' || github.event.label.name == 'trust-fork-pr') && contains(github.event.pull_request.labels.*.name, 'dev-c3')))) + ) with: workflow: selfdrive_tests.yaml # The workflow file to monitor github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/SConstruct b/SConstruct index 6bfe6c3025..2817a46d34 100644 --- a/SConstruct +++ b/SConstruct @@ -82,7 +82,6 @@ assert arch in ["larch64", "aarch64", "x86_64", "Darwin"] lenv = { "PATH": os.environ['PATH'], - "LD_LIBRARY_PATH": [Dir(f"#third_party/acados/{arch}/lib").abspath], "PYTHONPATH": Dir("#").abspath + ':' + Dir(f"#third_party/acados").abspath, "ACADOS_SOURCE_DIR": Dir("#third_party/acados").abspath, @@ -90,7 +89,7 @@ lenv = { "TERA_PATH": Dir("#").abspath + f"/third_party/acados/{arch}/t_renderer" } -rpath = lenv["LD_LIBRARY_PATH"].copy() +rpath = [] if arch == "larch64": cpppath = [ @@ -133,7 +132,6 @@ else: f"{brew_prefix}/include", f"{brew_prefix}/opt/openssl@3.0/include", ] - lenv["DYLD_LIBRARY_PATH"] = lenv["LD_LIBRARY_PATH"] # Linux else: libpath = [ diff --git a/cereal/log.capnp b/cereal/log.capnp index 65dc243dab..1ecefa5adc 100644 --- a/cereal/log.capnp +++ b/cereal/log.capnp @@ -128,6 +128,7 @@ struct OnroadEvent @0xc4fa6047f024e718 { personalityChanged @91; aeb @92; userFlag @95; + excessiveActuation @96; soundsUnavailableDEPRECATED @47; } @@ -492,7 +493,6 @@ struct DeviceState @0xa4d8b5af2aa492eb { gpuTempC @27 :List(Float32); dspTempC @49 :Float32; memoryTempC @28 :Float32; - nvmeTempC @35 :List(Float32); modemTempC @36 :List(Float32); pmicTempC @39 :List(Float32); intakeTempC @46 :Float32; @@ -568,6 +568,7 @@ struct DeviceState @0xa4d8b5af2aa492eb { chargingDisabledDEPRECATED @18 :Bool; usbOnlineDEPRECATED @12 :Bool; ambientTempCDEPRECATED @30 :Float32; + nvmeTempCDEPRECATED @35 :List(Float32); } struct PandaState @0xa7649e2575e4591e { @@ -585,7 +586,7 @@ struct PandaState @0xa7649e2575e4591e { fanPower @28 :UInt8; fanStallCount @34 :UInt8; - spiChecksumErrorCount @33 :UInt16; + spiErrorCount @33 :UInt16; harnessStatus @21 :HarnessStatus; sbu1Voltage @35 :Float32; diff --git a/cereal/messaging/tests/test_messaging.py b/cereal/messaging/tests/test_messaging.py index 6234a11c08..2369229980 100644 --- a/cereal/messaging/tests/test_messaging.py +++ b/cereal/messaging/tests/test_messaging.py @@ -30,7 +30,7 @@ def zmq_sleep(t=1): # TODO: this should take any capnp struct and returrn a msg with random populated data def random_carstate(): - fields = ["vEgo", "aEgo", "gas", "steeringAngleDeg"] + fields = ["vEgo", "aEgo", "brake", "steeringAngleDeg"] msg = messaging.new_message("carState") cs = msg.carState for f in fields: diff --git a/common/model.h b/common/model.h index ce5482e9e1..90e8096716 100644 --- a/common/model.h +++ b/common/model.h @@ -1 +1 @@ -#define DEFAULT_MODEL "Tomb Raider 14 (Default)" +#define DEFAULT_MODEL "Space Lab 2 (Default)" diff --git a/common/params.cc b/common/params.cc index 0a8821c37a..39592cb905 100644 --- a/common/params.cc +++ b/common/params.cc @@ -103,10 +103,10 @@ Params::~Params() { assert(queue.empty()); } -std::vector Params::allKeys(ParamKeyType type) const { +std::vector Params::allKeys(ParamKeyFlag flag) const { std::vector ret; for (auto &p : keys) { - if (type == ALL || (p.second & type)) { + if (flag == ALL || (p.second.flags & flag)) { ret.push_back(p.first); } } @@ -117,8 +117,16 @@ bool Params::checkKey(const std::string &key) { return keys.find(key) != keys.end(); } +ParamKeyFlag Params::getKeyFlag(const std::string &key) { + return static_cast(keys[key].flags); +} + ParamKeyType Params::getKeyType(const std::string &key) { - return static_cast(keys[key]); + return keys[key].type; +} + +std::optional Params::getKeyDefaultValue(const std::string &key) { + return keys[key].default_value; } int Params::put(const char* key, const char* value, size_t value_size) { @@ -197,17 +205,17 @@ std::map Params::readAll() { return util::read_files_in_dir(getParamPath()); } -void Params::clearAll(ParamKeyType key_type) { +void Params::clearAll(ParamKeyFlag key_flag) { FileLock file_lock(params_path + "/.lock"); - // 1) delete params of key_type + // 1) delete params of key_flag // 2) delete files that are not defined in the keys. if (DIR *d = opendir(getParamPath().c_str())) { struct dirent *de = NULL; while ((de = readdir(d))) { if (de->d_type != DT_DIR) { auto it = keys.find(de->d_name); - if (it == keys.end() || (it->second & key_type)) { + if (it == keys.end() || (it->second.flags & key_flag)) { unlink(getParamPath(de->d_name).c_str()); } } diff --git a/common/params.h b/common/params.h index 73e21a3fee..de4f9b435f 100644 --- a/common/params.h +++ b/common/params.h @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -9,17 +10,34 @@ #include "common/queue.h" -enum ParamKeyType { +enum ParamKeyFlag { PERSISTENT = 0x02, CLEAR_ON_MANAGER_START = 0x04, CLEAR_ON_ONROAD_TRANSITION = 0x08, CLEAR_ON_OFFROAD_TRANSITION = 0x10, DONT_LOG = 0x20, DEVELOPMENT_ONLY = 0x40, - BACKUP = 0x80, + CLEAR_ON_IGNITION_ON = 0x80, + BACKUP = 0x100, ALL = 0xFFFFFFFF }; +enum ParamKeyType { + STRING = 0, // must be utf-8 decodable + BOOL = 1, + INT = 2, + FLOAT = 3, + TIME = 4, // ISO 8601 + JSON = 5, + BYTES = 6 +}; + +struct ParamKeyAttributes { + uint32_t flags; + ParamKeyType type; + std::optional default_value = std::nullopt; +}; + class Params { public: explicit Params(const std::string &path = {}); @@ -28,16 +46,18 @@ public: Params(const Params&) = delete; Params& operator=(const Params&) = delete; - std::vector allKeys(ParamKeyType type = ALL) const; + std::vector allKeys(ParamKeyFlag flag = ALL) const; bool checkKey(const std::string &key); + ParamKeyFlag getKeyFlag(const std::string &key); ParamKeyType getKeyType(const std::string &key); + std::optional getKeyDefaultValue(const std::string &key); inline std::string getParamPath(const std::string &key = {}) { return params_path + params_prefix + (key.empty() ? "" : "/" + key); } // Delete a value int remove(const std::string &key); - void clearAll(ParamKeyType type); + void clearAll(ParamKeyFlag flag); // helpers for reading values std::string get(const std::string &key, bool block = false); diff --git a/common/params.py b/common/params.py index 66808083dc..494617200f 100644 --- a/common/params.py +++ b/common/params.py @@ -1,5 +1,6 @@ -from openpilot.common.params_pyx import Params, ParamKeyType, UnknownKeyName +from openpilot.common.params_pyx import Params, ParamKeyFlag, ParamKeyType, UnknownKeyName assert Params +assert ParamKeyFlag assert ParamKeyType assert UnknownKeyName diff --git a/common/params_keys.h b/common/params_keys.h index dfcf410a51..23e938eb61 100644 --- a/common/params_keys.h +++ b/common/params_keys.h @@ -3,208 +3,215 @@ #include #include -inline static std::unordered_map keys = { - {"AccessToken", CLEAR_ON_MANAGER_START | DONT_LOG}, - {"AdbEnabled", PERSISTENT | BACKUP}, - {"AlwaysOnDM", PERSISTENT | BACKUP}, - {"ApiCache_Device", PERSISTENT}, - {"ApiCache_FirehoseStats", PERSISTENT}, - {"AssistNowToken", PERSISTENT}, - {"AthenadPid", PERSISTENT}, - {"AthenadUploadQueue", PERSISTENT}, - {"AthenadRecentlyViewedRoutes", PERSISTENT}, - {"BootCount", PERSISTENT}, - {"CalibrationParams", PERSISTENT}, - {"CameraDebugExpGain", CLEAR_ON_MANAGER_START}, - {"CameraDebugExpTime", CLEAR_ON_MANAGER_START}, - {"CarBatteryCapacity", PERSISTENT}, - {"CarParams", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, - {"CarParamsCache", CLEAR_ON_MANAGER_START}, - {"CarParamsPersistent", PERSISTENT}, - {"CarParamsPrevRoute", PERSISTENT}, - {"CompletedTrainingVersion", PERSISTENT}, - {"ControlsReady", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, - {"CurrentBootlog", PERSISTENT}, - {"CurrentRoute", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, - {"DisableLogging", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, - {"DisablePowerDown", PERSISTENT | BACKUP}, - {"DisableUpdates", PERSISTENT | BACKUP}, - {"DisengageOnAccelerator", PERSISTENT | BACKUP}, - {"DongleId", PERSISTENT}, - {"DoReboot", CLEAR_ON_MANAGER_START}, - {"DoShutdown", CLEAR_ON_MANAGER_START}, - {"DoUninstall", CLEAR_ON_MANAGER_START}, - {"AlphaLongitudinalEnabled", PERSISTENT | DEVELOPMENT_ONLY | BACKUP}, - {"ExperimentalMode", PERSISTENT | BACKUP}, - {"ExperimentalModeConfirmed", PERSISTENT | BACKUP}, - {"FirmwareQueryDone", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, - {"ForcePowerDown", PERSISTENT}, - {"GitBranch", PERSISTENT}, - {"GitCommit", PERSISTENT}, - {"GitCommitDate", PERSISTENT}, - {"GitDiff", PERSISTENT}, - {"GithubSshKeys", PERSISTENT | BACKUP}, - {"GithubUsername", PERSISTENT | BACKUP}, - {"GitRemote", PERSISTENT}, - {"GsmApn", PERSISTENT | BACKUP}, - {"GsmMetered", PERSISTENT | BACKUP}, - {"GsmRoaming", PERSISTENT | BACKUP}, - {"HardwareSerial", PERSISTENT}, - {"HasAcceptedTerms", PERSISTENT}, - {"InstallDate", PERSISTENT}, - {"IsDriverViewEnabled", CLEAR_ON_MANAGER_START}, - {"IsEngaged", PERSISTENT}, - {"IsLdwEnabled", PERSISTENT | BACKUP}, - {"IsMetric", PERSISTENT | BACKUP}, - {"IsOffroad", CLEAR_ON_MANAGER_START}, - {"IsOnroad", PERSISTENT}, - {"IsRhdDetected", PERSISTENT}, - {"IsReleaseBranch", CLEAR_ON_MANAGER_START}, - {"IsTakingSnapshot", CLEAR_ON_MANAGER_START}, - {"IsTestedBranch", CLEAR_ON_MANAGER_START}, - {"JoystickDebugMode", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, - {"LanguageSetting", PERSISTENT | BACKUP}, - {"LastAthenaPingTime", CLEAR_ON_MANAGER_START}, - {"LastGPSPosition", PERSISTENT}, - {"LastManagerExitReason", CLEAR_ON_MANAGER_START}, - {"LastOffroadStatusPacket", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, - {"LastPowerDropDetected", CLEAR_ON_MANAGER_START}, - {"LastUpdateException", CLEAR_ON_MANAGER_START}, - {"LastUpdateTime", PERSISTENT}, - {"LiveDelay", PERSISTENT | BACKUP}, - {"LiveParameters", PERSISTENT}, - {"LiveParametersV2", PERSISTENT}, - {"LiveTorqueParameters", PERSISTENT | DONT_LOG}, - {"LocationFilterInitialState", PERSISTENT}, - {"LongitudinalManeuverMode", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, - {"LongitudinalPersonality", PERSISTENT | BACKUP}, - {"NetworkMetered", PERSISTENT | BACKUP}, - {"ObdMultiplexingChanged", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, - {"ObdMultiplexingEnabled", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, - {"Offroad_BadNvme", CLEAR_ON_MANAGER_START}, - {"Offroad_CarUnrecognized", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, - {"Offroad_ConnectivityNeeded", CLEAR_ON_MANAGER_START}, - {"Offroad_ConnectivityNeededPrompt", CLEAR_ON_MANAGER_START}, - {"Offroad_IsTakingSnapshot", CLEAR_ON_MANAGER_START}, - {"Offroad_NeosUpdate", CLEAR_ON_MANAGER_START}, - {"Offroad_NoFirmware", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, - {"Offroad_Recalibration", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, - {"Offroad_StorageMissing", CLEAR_ON_MANAGER_START}, - {"Offroad_TemperatureTooHigh", CLEAR_ON_MANAGER_START}, - {"Offroad_UnofficialHardware", CLEAR_ON_MANAGER_START}, - {"Offroad_UpdateFailed", CLEAR_ON_MANAGER_START}, - {"OnroadCycleRequested", CLEAR_ON_MANAGER_START}, - {"OpenpilotEnabledToggle", PERSISTENT | BACKUP}, - {"PandaHeartbeatLost", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, - {"PandaSomResetTriggered", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, - {"PandaSignatures", CLEAR_ON_MANAGER_START}, - {"PrimeType", PERSISTENT}, - {"RecordAudio", PERSISTENT | BACKUP}, - {"RecordFront", PERSISTENT | BACKUP}, - {"RecordFrontLock", PERSISTENT}, // for the internal fleet - {"SecOCKey", PERSISTENT | DONT_LOG | BACKUP}, - {"RouteCount", PERSISTENT}, - {"SnoozeUpdate", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, - {"SshEnabled", PERSISTENT | BACKUP}, - {"TermsVersion", PERSISTENT}, - {"TrainingVersion", PERSISTENT}, - {"UbloxAvailable", PERSISTENT}, - {"UpdateAvailable", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, - {"UpdateFailedCount", CLEAR_ON_MANAGER_START}, - {"UpdaterAvailableBranches", PERSISTENT}, - {"UpdaterCurrentDescription", CLEAR_ON_MANAGER_START}, - {"UpdaterCurrentReleaseNotes", CLEAR_ON_MANAGER_START}, - {"UpdaterFetchAvailable", CLEAR_ON_MANAGER_START}, - {"UpdaterNewDescription", CLEAR_ON_MANAGER_START}, - {"UpdaterNewReleaseNotes", CLEAR_ON_MANAGER_START}, - {"UpdaterState", CLEAR_ON_MANAGER_START}, - {"UpdaterTargetBranch", CLEAR_ON_MANAGER_START}, - {"UpdaterLastFetchTime", PERSISTENT}, - {"Version", PERSISTENT}, +#include "cereal/gen/cpp/log.capnp.h" + +inline static std::unordered_map keys = { + {"AccessToken", {CLEAR_ON_MANAGER_START | DONT_LOG, STRING}}, + {"AdbEnabled", {PERSISTENT | BACKUP, BOOL}}, + {"AlwaysOnDM", {PERSISTENT | BACKUP, BOOL}}, + {"ApiCache_Device", {PERSISTENT, STRING}}, + {"ApiCache_FirehoseStats", {PERSISTENT, JSON}}, + {"AssistNowToken", {PERSISTENT, STRING}}, + {"AthenadPid", {PERSISTENT, STRING}}, + {"AthenadUploadQueue", {PERSISTENT, JSON}}, + {"AthenadRecentlyViewedRoutes", {PERSISTENT, STRING}}, + {"BootCount", {PERSISTENT, INT}}, + {"CalibrationParams", {PERSISTENT, BYTES}}, + {"CameraDebugExpGain", {CLEAR_ON_MANAGER_START, STRING}}, + {"CameraDebugExpTime", {CLEAR_ON_MANAGER_START, STRING}}, + {"CarBatteryCapacity", {PERSISTENT, INT}}, + {"CarParams", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BYTES}}, + {"CarParamsCache", {CLEAR_ON_MANAGER_START, BYTES}}, + {"CarParamsPersistent", {PERSISTENT, BYTES}}, + {"CarParamsPrevRoute", {PERSISTENT, BYTES}}, + {"CompletedTrainingVersion", {PERSISTENT, STRING, "0"}}, + {"ControlsReady", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}}, + {"CurrentBootlog", {PERSISTENT, STRING}}, + {"CurrentRoute", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, STRING}}, + {"DisableLogging", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}}, + {"DisablePowerDown", {PERSISTENT | BACKUP, BOOL}}, + {"DisableUpdates", {PERSISTENT | BACKUP, BOOL, "0"}}, + {"DisengageOnAccelerator", {PERSISTENT | BACKUP, BOOL, "0"}}, + {"DongleId", {PERSISTENT, STRING}}, + {"DoReboot", {CLEAR_ON_MANAGER_START, BOOL}}, + {"DoShutdown", {CLEAR_ON_MANAGER_START, BOOL}}, + {"DoUninstall", {CLEAR_ON_MANAGER_START, BOOL}}, + {"DriverTooDistracted", {CLEAR_ON_MANAGER_START | CLEAR_ON_IGNITION_ON, BOOL}}, + {"AlphaLongitudinalEnabled", {PERSISTENT | DEVELOPMENT_ONLY | BACKUP, BOOL}}, + {"ExperimentalMode", {PERSISTENT | BACKUP, BOOL}}, + {"ExperimentalModeConfirmed", {PERSISTENT | BACKUP, BOOL}}, + {"FirmwareQueryDone", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}}, + {"ForcePowerDown", {PERSISTENT, BOOL}}, + {"GitBranch", {PERSISTENT, STRING}}, + {"GitCommit", {PERSISTENT, STRING}}, + {"GitCommitDate", {PERSISTENT, STRING}}, + {"GitDiff", {PERSISTENT, STRING}}, + {"GithubSshKeys", {PERSISTENT | BACKUP, STRING}}, + {"GithubUsername", {PERSISTENT | BACKUP, STRING}}, + {"GitRemote", {PERSISTENT, STRING}}, + {"GsmApn", {PERSISTENT | BACKUP, STRING}}, + {"GsmMetered", {PERSISTENT | BACKUP, BOOL, "1"}}, + {"GsmRoaming", {PERSISTENT | BACKUP, BOOL}}, + {"HardwareSerial", {PERSISTENT, STRING}}, + {"HasAcceptedTerms", {PERSISTENT, STRING, "0"}}, + {"InstallDate", {PERSISTENT, TIME}}, + {"IsDriverViewEnabled", {CLEAR_ON_MANAGER_START, BOOL}}, + {"IsEngaged", {PERSISTENT, BOOL}}, + {"IsLdwEnabled", {PERSISTENT | BACKUP, BOOL}}, + {"IsMetric", {PERSISTENT | BACKUP, BOOL}}, + {"IsOffroad", {CLEAR_ON_MANAGER_START, BOOL}}, + {"IsOnroad", {PERSISTENT, BOOL}}, + {"IsRhdDetected", {PERSISTENT, BOOL}}, + {"IsReleaseBranch", {CLEAR_ON_MANAGER_START, BOOL}}, + {"IsTakingSnapshot", {CLEAR_ON_MANAGER_START, BOOL}}, + {"IsTestedBranch", {CLEAR_ON_MANAGER_START, BOOL}}, + {"JoystickDebugMode", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}}, + {"LanguageSetting", {PERSISTENT | BACKUP, STRING, "main_en"}}, + {"LastAthenaPingTime", {CLEAR_ON_MANAGER_START, INT}}, + {"LastGPSPosition", {PERSISTENT, STRING}}, + {"LastManagerExitReason", {CLEAR_ON_MANAGER_START, STRING}}, + {"LastOffroadStatusPacket", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, JSON}}, + {"LastPowerDropDetected", {CLEAR_ON_MANAGER_START, STRING}}, + {"LastUpdateException", {CLEAR_ON_MANAGER_START, STRING}}, + {"LastUpdateRouteCount", {PERSISTENT, INT}}, + {"LastUpdateTime", {PERSISTENT, TIME}}, + {"LastUpdateUptimeOnroad", {PERSISTENT, FLOAT}}, + {"LiveDelay", {PERSISTENT | BACKUP, BYTES}}, + {"LiveParameters", {PERSISTENT, JSON}}, + {"LiveParametersV2", {PERSISTENT, BYTES}}, + {"LiveTorqueParameters", {PERSISTENT | DONT_LOG, BYTES}}, + {"LocationFilterInitialState", {PERSISTENT, BYTES}}, + {"LongitudinalManeuverMode", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}}, + {"LongitudinalPersonality", {PERSISTENT | BACKUP, INT, std::to_string(static_cast(cereal::LongitudinalPersonality::STANDARD))}}, + {"NetworkMetered", {PERSISTENT | BACKUP, BOOL}}, + {"ObdMultiplexingChanged", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}}, + {"ObdMultiplexingEnabled", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}}, + {"Offroad_CarUnrecognized", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, JSON}}, + {"Offroad_ConnectivityNeeded", {CLEAR_ON_MANAGER_START, JSON}}, + {"Offroad_ConnectivityNeededPrompt", {CLEAR_ON_MANAGER_START, JSON}}, + {"Offroad_ExcessiveActuation", {PERSISTENT, JSON}}, + {"Offroad_IsTakingSnapshot", {CLEAR_ON_MANAGER_START, JSON}}, + {"Offroad_NeosUpdate", {CLEAR_ON_MANAGER_START, JSON}}, + {"Offroad_NoFirmware", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, JSON}}, + {"Offroad_Recalibration", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, JSON}}, + {"Offroad_StorageMissing", {CLEAR_ON_MANAGER_START, JSON}}, + {"Offroad_TemperatureTooHigh", {CLEAR_ON_MANAGER_START, JSON}}, + {"Offroad_UnregisteredHardware", {CLEAR_ON_MANAGER_START, JSON}}, + {"Offroad_UpdateFailed", {CLEAR_ON_MANAGER_START, JSON}}, + {"OnroadCycleRequested", {CLEAR_ON_MANAGER_START, BOOL}}, + {"OpenpilotEnabledToggle", {PERSISTENT | BACKUP, BOOL, "1"}}, + {"PandaHeartbeatLost", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}}, + {"PandaSomResetTriggered", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}}, + {"PandaSignatures", {CLEAR_ON_MANAGER_START, BYTES}}, + {"PrimeType", {PERSISTENT, INT}}, + {"RecordAudio", {PERSISTENT | BACKUP, BOOL}}, + {"RecordFront", {PERSISTENT | BACKUP, BOOL}}, + {"RecordFrontLock", {PERSISTENT, BOOL}}, // for the internal fleet + {"SecOCKey", {PERSISTENT | DONT_LOG | BACKUP, STRING}}, + {"RouteCount", {PERSISTENT, INT, "0"}}, + {"SnoozeUpdate", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, BOOL}}, + {"SshEnabled", {PERSISTENT | BACKUP, BOOL}}, + {"TermsVersion", {PERSISTENT, STRING}}, + {"TrainingVersion", {PERSISTENT, STRING}}, + {"UbloxAvailable", {PERSISTENT, BOOL}}, + {"UpdateAvailable", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BOOL}}, + {"UpdateFailedCount", {CLEAR_ON_MANAGER_START, INT}}, + {"UpdaterAvailableBranches", {PERSISTENT, STRING}}, + {"UpdaterCurrentDescription", {CLEAR_ON_MANAGER_START, STRING}}, + {"UpdaterCurrentReleaseNotes", {CLEAR_ON_MANAGER_START, BYTES}}, + {"UpdaterFetchAvailable", {CLEAR_ON_MANAGER_START, BOOL}}, + {"UpdaterNewDescription", {CLEAR_ON_MANAGER_START, STRING}}, + {"UpdaterNewReleaseNotes", {CLEAR_ON_MANAGER_START, BYTES}}, + {"UpdaterState", {CLEAR_ON_MANAGER_START, STRING}}, + {"UpdaterTargetBranch", {CLEAR_ON_MANAGER_START, STRING}}, + {"UpdaterLastFetchTime", {PERSISTENT, TIME}}, + {"UptimeOffroad", {PERSISTENT, FLOAT, "0.0"}}, + {"UptimeOnroad", {PERSISTENT, FLOAT, "0.0"}}, + {"Version", {PERSISTENT, STRING}}, // --- sunnypilot params --- // - {"ApiCache_DriveStats", PERSISTENT}, - {"AutoLaneChangeBsmDelay", PERSISTENT | BACKUP}, - {"AutoLaneChangeTimer", PERSISTENT | BACKUP}, - {"BlinkerMinLateralControlSpeed", PERSISTENT | BACKUP}, - {"BlinkerPauseLateralControl", PERSISTENT | BACKUP}, - {"Brightness", PERSISTENT | BACKUP}, - {"CarParamsSP", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, - {"CarParamsSPCache", CLEAR_ON_MANAGER_START}, - {"CarParamsSPPersistent", PERSISTENT}, - {"CarPlatformBundle", PERSISTENT | BACKUP}, - {"ChevronInfo", PERSISTENT | BACKUP}, - {"CustomAccIncrementsEnabled", PERSISTENT | BACKUP}, - {"CustomAccLongPressIncrement", PERSISTENT | BACKUP}, - {"CustomAccShortPressIncrement", PERSISTENT | BACKUP}, - {"DeviceBootMode", PERSISTENT | BACKUP}, - {"EnableGithubRunner", PERSISTENT | BACKUP}, - {"InteractivityTimeout", PERSISTENT | BACKUP}, - {"IsDevelopmentBranch", CLEAR_ON_MANAGER_START}, - {"MaxTimeOffroad", PERSISTENT | BACKUP}, - {"ModelRunnerTypeCache", CLEAR_ON_ONROAD_TRANSITION}, - {"OffroadMode", CLEAR_ON_MANAGER_START}, - {"QuickBootToggle", PERSISTENT | BACKUP}, - {"QuietMode", PERSISTENT | BACKUP}, - {"ShowAdvancedControls", PERSISTENT | BACKUP}, + {"ApiCache_DriveStats", {PERSISTENT, JSON}}, + {"AutoLaneChangeBsmDelay", {PERSISTENT | BACKUP, BOOL, "0"}}, + {"AutoLaneChangeTimer", {PERSISTENT | BACKUP, INT, "0"}}, + {"BlinkerMinLateralControlSpeed", {PERSISTENT | BACKUP, INT, "20"}}, // MPH or km/h + {"BlinkerPauseLateralControl", {PERSISTENT | BACKUP, INT, "0"}}, + {"Brightness", {PERSISTENT | BACKUP, INT, "0"}}, + {"CarParamsSP", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, BYTES}}, + {"CarParamsSPCache", {CLEAR_ON_MANAGER_START, BYTES}}, + {"CarParamsSPPersistent", {PERSISTENT, BYTES}}, + {"CarPlatformBundle", {PERSISTENT | BACKUP, STRING}}, + {"ChevronInfo", {PERSISTENT | BACKUP, INT, "4"}}, + {"CustomAccIncrementsEnabled", {PERSISTENT | BACKUP, BOOL, "0"}}, + {"CustomAccLongPressIncrement", {PERSISTENT | BACKUP, INT, "5"}}, + {"CustomAccShortPressIncrement", {PERSISTENT | BACKUP, INT, "1"}}, + {"DeviceBootMode", {PERSISTENT | BACKUP, INT, "0"}}, + {"EnableGithubRunner", {PERSISTENT | BACKUP, BOOL}}, + {"InteractivityTimeout", {PERSISTENT | BACKUP, INT, "0"}}, + {"IsDevelopmentBranch", {CLEAR_ON_MANAGER_START, BOOL}}, + {"MaxTimeOffroad", {PERSISTENT | BACKUP, INT, "1800"}}, + {"ModelRunnerTypeCache", {CLEAR_ON_ONROAD_TRANSITION, INT}}, + {"OffroadMode", {CLEAR_ON_MANAGER_START, BOOL}}, + {"QuickBootToggle", {PERSISTENT | BACKUP, BOOL, "0"}}, + {"QuietMode", {PERSISTENT | BACKUP, BOOL, "0"}}, + {"ShowAdvancedControls", {PERSISTENT | BACKUP, BOOL, "0"}}, // MADS params - {"Mads", PERSISTENT | BACKUP}, - {"MadsMainCruiseAllowed", PERSISTENT | BACKUP}, - {"MadsSteeringMode", PERSISTENT | BACKUP}, - {"MadsUnifiedEngagementMode", PERSISTENT | BACKUP}, + {"Mads", {PERSISTENT | BACKUP, BOOL, "1"}}, + {"MadsMainCruiseAllowed", {PERSISTENT | BACKUP, BOOL, "1"}}, + {"MadsSteeringMode", {PERSISTENT | BACKUP, INT, "0"}}, + {"MadsUnifiedEngagementMode", {PERSISTENT | BACKUP, BOOL, "1"}}, // Model Manager params - {"ModelManager_ActiveBundle", PERSISTENT}, - {"ModelManager_ClearCache", CLEAR_ON_MANAGER_START}, - {"ModelManager_DownloadIndex", CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION}, - {"ModelManager_LastSyncTime", CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION}, - {"ModelManager_ModelsCache", PERSISTENT | BACKUP}, + {"ModelManager_ActiveBundle", {PERSISTENT, STRING}}, + {"ModelManager_ClearCache", {CLEAR_ON_MANAGER_START, BOOL}}, + {"ModelManager_DownloadIndex", {CLEAR_ON_MANAGER_START | CLEAR_ON_ONROAD_TRANSITION, INT, "0"}}, + {"ModelManager_LastSyncTime", {CLEAR_ON_MANAGER_START | CLEAR_ON_OFFROAD_TRANSITION, INT, "0"}}, + {"ModelManager_ModelsCache", {PERSISTENT | BACKUP, STRING}}, // Neural Network Lateral Control - {"NeuralNetworkLateralControl", PERSISTENT | BACKUP}, + {"NeuralNetworkLateralControl", {PERSISTENT | BACKUP, BOOL, "0"}}, // sunnylink params - {"EnableSunnylinkUploader", PERSISTENT | BACKUP}, - {"LastSunnylinkPingTime", CLEAR_ON_MANAGER_START}, - {"SunnylinkCache_Roles", PERSISTENT}, - {"SunnylinkCache_Users", PERSISTENT}, - {"SunnylinkDongleId", PERSISTENT}, - {"SunnylinkdPid", PERSISTENT}, - {"SunnylinkEnabled", PERSISTENT}, + {"EnableSunnylinkUploader", {PERSISTENT | BACKUP, BOOL}}, + {"LastSunnylinkPingTime", {CLEAR_ON_MANAGER_START, INT}}, + {"SunnylinkCache_Roles", {PERSISTENT, STRING}}, + {"SunnylinkCache_Users", {PERSISTENT, STRING}}, + {"SunnylinkDongleId", {PERSISTENT, STRING}}, + {"SunnylinkdPid", {PERSISTENT, STRING}}, + {"SunnylinkEnabled", {PERSISTENT, BOOL}}, // Backup Manager params - {"BackupManager_CreateBackup", PERSISTENT}, - {"BackupManager_RestoreVersion", PERSISTENT}, + {"BackupManager_CreateBackup", {PERSISTENT, BOOL}}, + {"BackupManager_RestoreVersion", {PERSISTENT, STRING}}, // sunnypilot car specific params - {"HyundaiLongitudinalTuning", PERSISTENT | BACKUP}, + {"HyundaiLongitudinalTuning", {PERSISTENT | BACKUP, INT, "0"}}, - {"DynamicExperimentalControl", PERSISTENT | BACKUP}, - {"BlindSpot", PERSISTENT | BACKUP}, + {"DynamicExperimentalControl", {PERSISTENT | BACKUP, BOOL, "0"}}, + {"BlindSpot", {PERSISTENT | BACKUP, BOOL, "0"}}, // model panel params - {"LagdToggle", PERSISTENT | BACKUP}, - {"LagdToggleDesc", PERSISTENT}, - {"LagdToggledelay", PERSISTENT | BACKUP}, + {"LagdToggle", {PERSISTENT | BACKUP, BOOL, "1"}}, + {"LagdToggleDesc", {PERSISTENT, STRING}}, + {"LagdToggleDelay", {PERSISTENT | BACKUP, FLOAT, "0.2"}}, // mapd - {"MapAdvisorySpeedLimit", CLEAR_ON_ONROAD_TRANSITION}, - {"MapdVersion", PERSISTENT}, - {"MapSpeedLimit", CLEAR_ON_ONROAD_TRANSITION}, - {"NextMapSpeedLimit", CLEAR_ON_ONROAD_TRANSITION}, - {"Offroad_OSMUpdateRequired", CLEAR_ON_MANAGER_START}, - {"OsmDbUpdatesCheck", CLEAR_ON_MANAGER_START}, // mapd database update happens with device ON, reset on boot - {"OSMDownloadBounds", PERSISTENT}, - {"OsmDownloadedDate", PERSISTENT}, - {"OSMDownloadLocations", PERSISTENT}, - {"OSMDownloadProgress", CLEAR_ON_MANAGER_START}, - {"OsmLocal", PERSISTENT}, - {"OsmLocationName", PERSISTENT}, - {"OsmLocationTitle", PERSISTENT}, - {"OsmLocationUrl", PERSISTENT}, - {"OsmStateName", PERSISTENT}, - {"OsmStateTitle", PERSISTENT}, - {"OsmWayTest", PERSISTENT}, - {"RoadName", CLEAR_ON_ONROAD_TRANSITION}, + {"MapAdvisorySpeedLimit", {CLEAR_ON_ONROAD_TRANSITION, FLOAT}}, + {"MapdVersion", {PERSISTENT, STRING, ""}}, + {"MapSpeedLimit", {CLEAR_ON_ONROAD_TRANSITION, FLOAT, "0.0"}}, + {"NextMapSpeedLimit", {CLEAR_ON_ONROAD_TRANSITION, STRING}}, + {"Offroad_OSMUpdateRequired", {CLEAR_ON_MANAGER_START, JSON}}, + {"OsmDbUpdatesCheck", {CLEAR_ON_MANAGER_START, BOOL}}, // mapd database update happens with device ON, reset on boot + {"OSMDownloadBounds", {PERSISTENT, STRING}}, + {"OsmDownloadedDate", {PERSISTENT, STRING, "0.0"}}, + {"OSMDownloadLocations", {PERSISTENT, STRING}}, + {"OSMDownloadProgress", {CLEAR_ON_MANAGER_START, JSON}}, + {"OsmLocal", {PERSISTENT, BOOL}}, + {"OsmLocationName", {PERSISTENT, STRING}}, + {"OsmLocationTitle", {PERSISTENT, STRING}}, + {"OsmLocationUrl", {PERSISTENT, STRING}}, + {"OsmStateName", {PERSISTENT, STRING, "All"}}, + {"OsmStateTitle", {PERSISTENT, STRING}}, + {"OsmWayTest", {PERSISTENT, STRING}}, + {"RoadName", {CLEAR_ON_ONROAD_TRANSITION, STRING, ""}}, }; diff --git a/common/params_pyx.pyx b/common/params_pyx.pyx index e851020d83..1a3e03e7f3 100644 --- a/common/params_pyx.pyx +++ b/common/params_pyx.pyx @@ -1,19 +1,35 @@ # distutils: language = c++ # cython: language_level = 3 +import builtins +import datetime +import json from libcpp cimport bool from libcpp.string cimport string from libcpp.vector cimport vector +from libcpp.optional cimport optional + +from openpilot.common.swaglog import cloudlog cdef extern from "common/params.h": - cpdef enum ParamKeyType: + cpdef enum ParamKeyFlag: PERSISTENT CLEAR_ON_MANAGER_START CLEAR_ON_ONROAD_TRANSITION CLEAR_ON_OFFROAD_TRANSITION DEVELOPMENT_ONLY + CLEAR_ON_IGNITION_ON BACKUP ALL + cpdef enum ParamKeyType: + STRING + BOOL + INT + FLOAT + TIME + JSON + BYTES + cdef cppclass c_Params "Params": c_Params(string) except + nogil string get(string, bool) nogil @@ -24,10 +40,31 @@ cdef extern from "common/params.h": void putBoolNonBlocking(string, bool) nogil int putBool(string, bool) nogil bool checkKey(string) nogil + ParamKeyType getKeyType(string) nogil + optional[string] getKeyDefaultValue(string) nogil string getParamPath(string) nogil - void clearAll(ParamKeyType) - vector[string] allKeys(ParamKeyType) + void clearAll(ParamKeyFlag) + vector[string] allKeys(ParamKeyFlag) +PYTHON_2_CPP = { + (str, STRING): lambda v: v, + (builtins.bool, BOOL): lambda v: "1" if v else "0", + (int, INT): str, + (float, FLOAT): str, + (datetime.datetime, TIME): lambda v: v.isoformat(), + (dict, JSON): json.dumps, + (list, JSON): json.dumps, + (bytes, BYTES): lambda v: v, +} +CPP_2_PYTHON = { + STRING: lambda v: v.decode("utf-8"), + BOOL: lambda v: v == b"1", + INT: int, + FLOAT: float, + TIME: lambda v: datetime.datetime.fromisoformat(v.decode("utf-8")), + JSON: json.loads, + BYTES: lambda v: v, +} def ensure_bytes(v): return v.encode() if isinstance(v, str) else v @@ -51,8 +88,8 @@ cdef class Params: def __dealloc__(self): del self.p - def clear_all(self, tx_type=ParamKeyType.ALL): - self.p.clearAll(tx_type) + def clear_all(self, tx_flag=ParamKeyFlag.ALL): + self.p.clearAll(tx_flag) def check_key(self, key): key = ensure_bytes(key) @@ -60,21 +97,38 @@ cdef class Params: raise UnknownKeyName(key) return key - def get(self, key, bool block=False, encoding=None): + def python2cpp(self, proposed_type, expected_type, value, key): + cast = PYTHON_2_CPP.get((proposed_type, expected_type)) + if cast: + return cast(value) + raise TypeError(f"Type mismatch while writing param {key}: {proposed_type=} {expected_type=} {value=}") + + def cpp2python(self, t, value, default, key): + if value is None: + return None + try: + return CPP_2_PYTHON[t](value) + except (KeyError, TypeError, ValueError): + cloudlog.warning(f"Failed to cast param {key} with {value=} from type {t=}") + return self.cpp2python(t, default, None, key) + + def get(self, key, bool block=False, bool return_default=False): cdef string k = self.check_key(key) + cdef ParamKeyType t = self.p.getKeyType(k) + cdef optional[string] default = self.p.getKeyDefaultValue(k) cdef string val with nogil: val = self.p.get(k, block) + default_val = (default.value() if default.has_value() else None) if return_default else None if val == b"": if block: # If we got no value while running in blocked mode # it means we got an interrupt while waiting raise KeyboardInterrupt else: - return None - - return val if encoding is None else val.decode(encoding) + return self.cpp2python(t, default_val, None, key) + return self.cpp2python(t, val, default_val, key) def get_bool(self, key, bool block=False): cdef string k = self.check_key(key) @@ -83,6 +137,11 @@ cdef class Params: r = self.p.getBool(k, block) return r + def _put_cast(self, key, dat): + cdef string k = self.check_key(key) + cdef ParamKeyType t = self.p.getKeyType(k) + return ensure_bytes(self.python2cpp(type(dat), t, dat, key)) + def put(self, key, dat): """ Warning: This function blocks until the param is written to disk! @@ -91,7 +150,7 @@ cdef class Params: in general try to avoid writing params as much as possible. """ cdef string k = self.check_key(key) - cdef string dat_bytes = ensure_bytes(dat) + cdef string dat_bytes = self._put_cast(key, dat) with nogil: self.p.put(k, dat_bytes) @@ -102,7 +161,7 @@ cdef class Params: def put_nonblocking(self, key, dat): cdef string k = self.check_key(key) - cdef string dat_bytes = ensure_bytes(dat) + cdef string dat_bytes = self._put_cast(key, dat) with nogil: self.p.putNonBlocking(k, dat_bytes) @@ -120,5 +179,14 @@ cdef class Params: cdef string key_bytes = ensure_bytes(key) return self.p.getParamPath(key_bytes).decode("utf-8") - def all_keys(self, type=ParamKeyType.ALL): - return self.p.allKeys(type) + def get_type(self, key): + return self.p.getKeyType(self.check_key(key)) + + def all_keys(self, flag=ParamKeyFlag.ALL): + return self.p.allKeys(flag) + + def get_default_value(self, key): + cdef string k = self.check_key(key) + cdef ParamKeyType t = self.p.getKeyType(k) + cdef optional[string] default = self.p.getKeyDefaultValue(k) + return self.cpp2python(t, default.value(), None, key) if default.has_value() else None diff --git a/common/tests/test_params.py b/common/tests/test_params.py index 16cbc45295..1f39769c2a 100644 --- a/common/tests/test_params.py +++ b/common/tests/test_params.py @@ -1,10 +1,11 @@ import pytest +import datetime import os import threading import time import uuid -from openpilot.common.params import Params, ParamKeyType, UnknownKeyName +from openpilot.common.params import Params, ParamKeyFlag, UnknownKeyName class TestParams: def setup_method(self): @@ -12,7 +13,7 @@ class TestParams: def test_params_put_and_get(self): self.params.put("DongleId", "cb38263377b873ee") - assert self.params.get("DongleId") == b"cb38263377b873ee" + assert self.params.get("DongleId") == "cb38263377b873ee" def test_params_non_ascii(self): st = b"\xe1\x90\xff" @@ -20,7 +21,7 @@ class TestParams: assert self.params.get("CarParams") == st def test_params_get_cleared_manager_start(self): - self.params.put("CarParams", "test") + self.params.put("CarParams", b"test") self.params.put("DongleId", "cb38263377b873ee") assert self.params.get("CarParams") == b"test" @@ -29,7 +30,7 @@ class TestParams: f.write("test") assert os.path.isfile(undefined_param) - self.params.clear_all(ParamKeyType.CLEAR_ON_MANAGER_START) + self.params.clear_all(ParamKeyFlag.CLEAR_ON_MANAGER_START) assert self.params.get("CarParams") is None assert self.params.get("DongleId") is not None assert not os.path.isfile(undefined_param) @@ -37,16 +38,16 @@ class TestParams: def test_params_two_things(self): self.params.put("DongleId", "bob") self.params.put("AthenadPid", "123") - assert self.params.get("DongleId") == b"bob" - assert self.params.get("AthenadPid") == b"123" + assert self.params.get("DongleId") == "bob" + assert self.params.get("AthenadPid") == "123" def test_params_get_block(self): def _delayed_writer(): time.sleep(0.1) - self.params.put("CarParams", "test") + self.params.put("CarParams", b"test") threading.Thread(target=_delayed_writer).start() assert self.params.get("CarParams") is None - assert self.params.get("CarParams", True) == b"test" + assert self.params.get("CarParams", block=True) == b"test" def test_params_unknown_key_fails(self): with pytest.raises(UnknownKeyName): @@ -76,17 +77,17 @@ class TestParams: self.params.put_bool("IsMetric", False) assert not self.params.get_bool("IsMetric") - self.params.put("IsMetric", "1") + self.params.put("IsMetric", True) assert self.params.get_bool("IsMetric") - self.params.put("IsMetric", "0") + self.params.put("IsMetric", False) assert not self.params.get_bool("IsMetric") def test_put_non_blocking_with_get_block(self): q = Params() def _delayed_writer(): time.sleep(0.1) - Params().put_nonblocking("CarParams", "test") + Params().put_nonblocking("CarParams", b"test") threading.Thread(target=_delayed_writer).start() assert q.get("CarParams") is None assert q.get("CarParams", True) == b"test" @@ -107,3 +108,34 @@ class TestParams: assert len(keys) > 20 assert len(keys) == len(set(keys)) assert b"CarParams" in keys + + def test_params_default_value(self): + self.params.remove("LanguageSetting") + self.params.remove("LongitudinalPersonality") + self.params.remove("LiveParameters") + + assert self.params.get("LanguageSetting") is None + assert self.params.get("LanguageSetting", return_default=False) is None + assert isinstance(self.params.get("LanguageSetting", return_default=True), str) + assert isinstance(self.params.get("LongitudinalPersonality", return_default=True), int) + assert self.params.get("LiveParameters") is None + assert self.params.get("LiveParameters", return_default=True) is None + + def test_params_get_type(self): + # json + self.params.put("ApiCache_FirehoseStats", {"a": 0}) + assert self.params.get("ApiCache_FirehoseStats") == {"a": 0} + + # int + self.params.put("BootCount", 1441) + assert self.params.get("BootCount") == 1441 + + # bool + self.params.put("AdbEnabled", True) + assert self.params.get("AdbEnabled") + assert isinstance(self.params.get("AdbEnabled"), bool) + + # time + now = datetime.datetime.now(datetime.UTC) + self.params.put("InstallDate", now) + assert self.params.get("InstallDate") == now diff --git a/common/util.cc b/common/util.cc index a853faed04..3d03c96bbe 100644 --- a/common/util.cc +++ b/common/util.cc @@ -12,6 +12,7 @@ #include #include #include +#include #ifdef __linux__ #include @@ -78,8 +79,9 @@ std::string read_file(const std::string& fn) { std::ifstream f(fn, std::ios::binary | std::ios::in); if (f.is_open()) { f.seekg(0, std::ios::end); - int size = f.tellg(); - if (f.good() && size > 0) { + std::streamsize size = f.tellg(); + // seekg and tellg on a directory doesn't return pos_type(-1) but max(streamsize) + if (f.good() && size > 0 && size < std::numeric_limits::max()) { std::string result(size, '\0'); f.seekg(0, std::ios::beg); f.read(result.data(), size); diff --git a/docs/CARS.md b/docs/CARS.md index 9403f7a88b..f2be4c5c9e 100644 --- a/docs/CARS.md +++ b/docs/CARS.md @@ -4,329 +4,323 @@ A supported vehicle is one that just works when you install a comma device. All supported cars provide a better experience than any stock system. Supported vehicles reference the US market unless otherwise specified. -# 319 Supported Cars +# 313 Supported Cars |Make|Model|Supported Package|ACC|No ACC accel below|No ALC below|Steering Torque|Resume from stop|Hardware Needed
 |Video|Setup Video| |---|---|---|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:| -|Acura|ILX 2016-18|Technology Plus Package or AcuraWatch Plus|openpilot|26 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Honda Nidec connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Acura|ILX 2019|All|openpilot|26 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Honda Nidec connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Acura|RDX 2016-18|AcuraWatch Plus or Advance Package|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Honda Nidec connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Acura|RDX 2019-21|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Audi|Q3 2019-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 GM connector
- 1 comma 3X
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 GM connector
- 1 comma 3X
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Chevrolet|Equinox 2019-22|Adaptive Cruise Control (ACC)|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 GM connector
- 1 comma 3X
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[1](#footnotes)|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 GM connector
- 1 comma 3X
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Chevrolet|Trailblazer 2021-22|Adaptive Cruise Control (ACC)|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 GM connector
- 1 comma 3X
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 FCA connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 FCA connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Chrysler|Pacifica 2021-23|All|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 FCA connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Chrysler|Pacifica Hybrid 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 FCA connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Chrysler|Pacifica Hybrid 2019-24|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 FCA connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|comma|body|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|None||| -|CUPRA|Ateca 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Dodge|Durango 2020-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 FCA connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Ford|Bronco Sport 2021-24|Co-Pilot360 Assist+|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q3 connector
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Ford|Escape 2020-22|Co-Pilot360 Assist+|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Ford|Escape 2023-24|Co-Pilot360 Assist+|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q4 connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||https://www.youtube.com/watch?v=uUGkH6C_EQU| -|Ford|Escape Hybrid 2020-22|Co-Pilot360 Assist+|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Ford|Escape Hybrid 2023-24|Co-Pilot360 Assist+|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q4 connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||https://www.youtube.com/watch?v=uUGkH6C_EQU| -|Ford|Escape Plug-in Hybrid 2020-22|Co-Pilot360 Assist+|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Ford|Escape Plug-in Hybrid 2023-24|Co-Pilot360 Assist+|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q4 connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||https://www.youtube.com/watch?v=uUGkH6C_EQU| -|Ford|Expedition 2022-24|Co-Pilot360 Assist 2.0|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q4 connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||https://www.youtube.com/watch?v=MewJc9LYp9M| -|Ford|Explorer 2020-24|Co-Pilot360 Assist+|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Ford|Explorer Hybrid 2020-24|Co-Pilot360 Assist+|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Ford|F-150 2021-23|Co-Pilot360 Assist 2.0|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q4 connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||https://www.youtube.com/watch?v=MewJc9LYp9M| -|Ford|F-150 Hybrid 2021-23|Co-Pilot360 Assist 2.0|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q4 connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||https://www.youtube.com/watch?v=MewJc9LYp9M| -|Ford|Focus 2018[3](#footnotes)|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Ford|Focus Hybrid 2018[3](#footnotes)|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Ford|Kuga 2020-23|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Ford|Kuga Hybrid 2020-23|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Ford|Kuga Hybrid 2024|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q4 connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||https://www.youtube.com/watch?v=uUGkH6C_EQU| -|Ford|Kuga Plug-in Hybrid 2020-23|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Ford|Kuga Plug-in Hybrid 2024|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q4 connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||https://www.youtube.com/watch?v=uUGkH6C_EQU| -|Ford|Maverick 2022|LARIAT Luxury|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q3 connector
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Ford|Maverick 2023-24|Co-Pilot360 Assist|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q3 connector
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Ford|Maverick Hybrid 2022|LARIAT Luxury|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q3 connector
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Ford|Maverick Hybrid 2023-24|Co-Pilot360 Assist|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q3 connector
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Ford|Mustang Mach-E 2021-24|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q4 connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||https://www.youtube.com/watch?v=uUGkH6C_EQU| -|Ford|Ranger 2024|Adaptive Cruise Control with Lane Centering|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q4 connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||https://www.youtube.com/watch?v=uUGkH6C_EQU| -|Genesis|G70 2018|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai F connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Genesis|G70 2019-21|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai F connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Genesis|G70 2022-23|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai L connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Genesis|G80 2017|All|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Hyundai J connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Genesis|G80 2018-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai H connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Genesis|G80 (2.5T Advanced Trim, with HDA II) 2024[6](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai P connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Genesis|G90 2017-20|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai C connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Genesis|GV60 (Advanced Trim) 2023[6](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Genesis|GV60 (Performance Trim) 2022-23[6](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai K connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Genesis|GV70 (2.5T Trim, without HDA II) 2022-24[6](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai L connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Genesis|GV70 (3.5T Trim, without HDA II) 2022-23[6](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai M connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Genesis|GV70 Electrified (Australia Only) 2022[6](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai Q connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Genesis|GV70 Electrified (with HDA II) 2023-24[6](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai Q connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Genesis|GV80 2023[6](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai M connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|GMC|Sierra 1500 2020-21|Driver Alert Package II|openpilot available[1](#footnotes)|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 GM connector
- 1 comma 3X
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Honda|Accord 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Honda|Accord Hybrid 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Honda|Civic 2016-18|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Nidec connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Honda|Civic 2019-21|All|openpilot available[1](#footnotes)|0 mph|2 mph[5](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Honda|Civic 2022-24|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch B connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Honda|Civic Hatchback 2017-21|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Honda|Civic Hatchback 2022-24|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch B connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Honda|Civic Hatchback Hybrid 2025|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch B connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Honda|Civic Hatchback Hybrid (Europe only) 2023|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch B connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Honda|CR-V 2015-16|Touring Trim|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Honda Nidec connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Honda|CR-V 2017-22|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Honda|CR-V Hybrid 2017-22|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Honda|e 2020|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Honda|Fit 2018-20|Honda Sensing|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Honda Nidec connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Honda|Freed 2020|Honda Sensing|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Honda Nidec connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Honda|HR-V 2019-22|Honda Sensing|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Honda Nidec connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Honda|HR-V 2023-25|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch B connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Honda|Insight 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Honda|Inspire 2018|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Honda|Odyssey 2018-20|Honda Sensing|openpilot|26 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Honda Nidec connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Honda|Passport 2019-25|All|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Honda Nidec connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Honda|Pilot 2016-22|Honda Sensing|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Honda Nidec connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Honda|Ridgeline 2017-25|Honda Sensing|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Honda Nidec connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Azera 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai K connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Azera Hybrid 2019|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai C connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Azera Hybrid 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai K connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Custin 2023|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai K connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Elantra 2017-18|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Hyundai B connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Elantra 2019|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Hyundai G connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Elantra 2021-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai K connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Elantra GT 2017-20|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai E connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai K connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Hyundai J connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|i30 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai E connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Ioniq 5 (Southeast Asia and Europe only) 2022-24[6](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai Q connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Ioniq 5 (with HDA II) 2022-24[6](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai Q connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Ioniq 5 (without HDA II) 2022-24[6](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai K connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Ioniq 6 (with HDA II) 2023-24[6](#footnotes)|Highway Driving Assist II|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai P connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai C connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Ioniq Electric 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai H connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai C connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Ioniq Hybrid 2020-22|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai H connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Ioniq Plug-in Hybrid 2019|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai C connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Ioniq Plug-in Hybrid 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai H connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Kona 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|6 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Hyundai B connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Kona 2022|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai O connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai G connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Kona Electric 2022-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai O connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Kona Electric (with HDA II, Korea only) 2023[6](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai R connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai I connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Nexo 2021|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai H connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Palisade 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai H connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Santa Cruz 2022-24[6](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai N connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Santa Fe 2019-20|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai D connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Santa Fe 2021-23|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai L connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Santa Fe Hybrid 2022-23|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai L connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Santa Fe Plug-in Hybrid 2022-23|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai L connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Sonata 2018-19|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai E connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Sonata 2020-23|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Sonata Hybrid 2020-23|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Staria 2023[6](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai K connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Tucson 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Hyundai L connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Tucson 2022[6](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai N connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Tucson 2023-24[6](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai N connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai L connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Tucson Hybrid 2022-24[6](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai N connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Tucson Plug-in Hybrid 2024[6](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai N connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|Stock|5 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Hyundai E connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 FCA connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 FCA connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|Carnival 2022-24[6](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|Carnival (China only) 2023[6](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai K connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|Ceed 2019-21|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai E connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|EV6 (Southeast Asia only) 2022-24[6](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai P connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|EV6 (with HDA II) 2022-24[6](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai P connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|EV6 (without HDA II) 2022-24[6](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai L connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|6 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Hyundai G connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|Forte 2022-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai E connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|K5 2021-24|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|K5 Hybrid 2020-22|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|K8 Hybrid (with HDA II) 2023[6](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai Q connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|Niro EV 2019|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai H connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|Niro EV 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai F connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|Niro EV 2021|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai C connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|Niro EV 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai H connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|Niro EV (with HDA II) 2025[6](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai R connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|Niro EV (without HDA II) 2023-25[6](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|Niro Hybrid 2018|All|Stock|10 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Hyundai C connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|Niro Hybrid 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai D connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|Niro Hybrid 2022|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai F connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|Niro Hybrid 2023[6](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|Niro Plug-in Hybrid 2018-19|All|Stock|10 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Hyundai C connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|Niro Plug-in Hybrid 2020|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai D connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|Niro Plug-in Hybrid 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai D connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|Niro Plug-in Hybrid 2022|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai F connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|Optima 2017|Advanced Smart Cruise Control|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai B connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|Optima 2019-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai G connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|Optima Hybrid 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai H connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|Seltos 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|Sorento 2018|Advanced Smart Cruise Control & LKAS|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai E connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai E connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|Sorento 2021-23[6](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai K connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|Sorento Hybrid 2021-23[6](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|Sorento Plug-in Hybrid 2022-23[6](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|Sportage 2023-24[6](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai N connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|Sportage Hybrid 2023[6](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai N connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|Stinger 2018-20|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai C connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|Stinger 2022-23|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai K connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Kia|Telluride 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai H connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Lexus|CT Hybrid 2017-18|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Lexus|ES 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Lexus|ES 2019-25|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Lexus|ES Hybrid 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Lexus|ES Hybrid 2019-25|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Lexus|GS F 2016|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Lexus|IS 2017-19|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Lexus|IS 2022-24|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Lexus|LC 2024-25|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Lexus|NX 2018-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Lexus|NX 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Lexus|NX Hybrid 2018-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Lexus|NX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Lexus|RC 2018-20|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Lexus|RC 2023|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Lexus|RX 2016|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Lexus|RX 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Lexus|RX 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Lexus|RX Hybrid 2016|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Lexus|RX Hybrid 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Lexus|RX Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Lexus|UX Hybrid 2019-24|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Lincoln|Aviator 2020-24|Co-Pilot360 Plus|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Lincoln|Aviator Plug-in Hybrid 2020-24|Co-Pilot360 Plus|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|MAN|eTGE 2020-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|MAN|TGE 2017-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Mazda|CX-5 2022-25|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Mazda connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Mazda|CX-9 2021-23|All|Stock|0 mph|28 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Mazda connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Nissan[7](#footnotes)|Altima 2019-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Nissan B connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Nissan[7](#footnotes)|Leaf 2018-23|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Nissan A connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Nissan[7](#footnotes)|Rogue 2018-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Nissan A connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Nissan[7](#footnotes)|X-Trail 2017|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Nissan A connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Ram|1500 2019-24|Adaptive Cruise Control (ACC)|Stock|32 mph|1 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Ram connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Ram|2500 2020-24|Adaptive Cruise Control (ACC)|Stock|0 mph|36 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ram connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Ram|3500 2019-22|Adaptive Cruise Control (ACC)|Stock|0 mph|36 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ram connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Rivian|R1S 2022-24|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Rivian A connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||https://youtu.be/uaISd1j7Z4U| -|Rivian|R1T 2022-24|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Rivian A connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||https://youtu.be/uaISd1j7Z4U| -|SEAT|Ateca 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Subaru|Ascent 2019-21|All[8](#footnotes)|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Subaru A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
Tools- 1 Pry Tool
- 1 Socket Wrench 8mm or 5/16" (deep)
||| -|Subaru|Crosstrek 2018-19|EyeSight Driver Assistance[8](#footnotes)|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Subaru A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
Tools- 1 Pry Tool
- 1 Socket Wrench 8mm or 5/16" (deep)
||| -|Subaru|Crosstrek 2020-23|EyeSight Driver Assistance[8](#footnotes)|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Subaru A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
Tools- 1 Pry Tool
- 1 Socket Wrench 8mm or 5/16" (deep)
||| -|Subaru|Forester 2017-18|EyeSight Driver Assistance[8](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Subaru A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
Tools- 1 Pry Tool
- 1 Socket Wrench 8mm or 5/16" (deep)
||| -|Subaru|Forester 2019-21|All[8](#footnotes)|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Subaru A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
Tools- 1 Pry Tool
- 1 Socket Wrench 8mm or 5/16" (deep)
||| -|Subaru|Impreza 2017-19|EyeSight Driver Assistance[8](#footnotes)|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Subaru A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
Tools- 1 Pry Tool
- 1 Socket Wrench 8mm or 5/16" (deep)
||| -|Subaru|Impreza 2020-22|EyeSight Driver Assistance[8](#footnotes)|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Subaru A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
Tools- 1 Pry Tool
- 1 Socket Wrench 8mm or 5/16" (deep)
||| -|Subaru|Legacy 2015-18|EyeSight Driver Assistance[8](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Subaru A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
Tools- 1 Pry Tool
- 1 Socket Wrench 8mm or 5/16" (deep)
||| -|Subaru|Legacy 2020-22|All[8](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Subaru B connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
Tools- 1 Pry Tool
- 1 Socket Wrench 8mm or 5/16" (deep)
||| -|Subaru|Outback 2015-17|EyeSight Driver Assistance[8](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Subaru A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
Tools- 1 Pry Tool
- 1 Socket Wrench 8mm or 5/16" (deep)
||| -|Subaru|Outback 2018-19|EyeSight Driver Assistance[8](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Subaru A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
Tools- 1 Pry Tool
- 1 Socket Wrench 8mm or 5/16" (deep)
||| -|Subaru|Outback 2020-22|All[8](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Subaru B connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
Tools- 1 Pry Tool
- 1 Socket Wrench 8mm or 5/16" (deep)
||| -|Subaru|XV 2018-19|EyeSight Driver Assistance[8](#footnotes)|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Subaru A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
Tools- 1 Pry Tool
- 1 Socket Wrench 8mm or 5/16" (deep)
||| -|Subaru|XV 2020-21|EyeSight Driver Assistance[8](#footnotes)|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Subaru A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
Tools- 1 Pry Tool
- 1 Socket Wrench 8mm or 5/16" (deep)
||| -|Škoda|Fabia 2022-23[15](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[17](#footnotes)||| -|Škoda|Kamiq 2021-23[13,15](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[17](#footnotes)||| -|Škoda|Karoq 2019-23[15](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Škoda|Kodiaq 2017-23[15](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Škoda|Octavia 2015-19[15](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Škoda|Octavia RS 2016[15](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Škoda|Octavia Scout 2017-19[15](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Škoda|Scala 2020-23[15](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[17](#footnotes)||| -|Škoda|Superb 2015-22[15](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Tesla[11](#footnotes)|Model 3 (with HW3) 2019-23[10](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Tesla A connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Tesla[11](#footnotes)|Model 3 (with HW4) 2024-25[10](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Tesla B connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Tesla[11](#footnotes)|Model Y (with HW3) 2020-23[10](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Tesla A connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Tesla[11](#footnotes)|Model Y (with HW4) 2024[10](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Tesla B connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|Avalon 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|Avalon 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|Avalon 2019-21|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|Avalon 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|Avalon Hybrid 2019-21|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|Avalon Hybrid 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|C-HR 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|C-HR 2021|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|C-HR Hybrid 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|C-HR Hybrid 2021-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|Camry 2018-20|All|Stock|0 mph[12](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|Camry 2021-24|All|openpilot|0 mph[12](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|Camry Hybrid 2021-24|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|Corolla 2017-19|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|Corolla 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|Corolla Cross (Non-US only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|Corolla Cross Hybrid (Non-US only) 2020-22|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|Corolla Hatchback 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|Corolla Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|Corolla Hybrid (South America only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|Highlander 2017-19|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|Highlander 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|Highlander Hybrid 2017-19|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|Highlander Hybrid 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|Mirai 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|Prius 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|Prius 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|Prius 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|Prius Prime 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|Prius Prime 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|Prius v 2017|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|RAV4 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|RAV4 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|RAV4 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|RAV4 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|RAV4 2023-25|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|RAV4 Hybrid 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|RAV4 Hybrid 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|RAV4 Hybrid 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|RAV4 Hybrid 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|RAV4 Hybrid 2023-25|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Toyota|Sienna 2018-20|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Volkswagen|Arteon 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Volkswagen|Arteon eHybrid 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Volkswagen|Arteon R 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Volkswagen|Arteon Shooting Brake 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Volkswagen|Atlas Cross Sport 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Volkswagen|California 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Volkswagen|Crafter 2017-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Volkswagen|e-Crafter 2018-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Volkswagen|Grand California 2019-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Volkswagen|Jetta 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Volkswagen|Jetta GLI 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Volkswagen|Passat 2015-22[14](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Volkswagen|Polo 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[17](#footnotes)||| -|Volkswagen|Polo GTI 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[17](#footnotes)||| -|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[17](#footnotes)||| -|Volkswagen|T-Roc 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Volkswagen|Taos 2022-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Volkswagen|Tiguan 2018-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Volkswagen|Tiguan eHybrid 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| -|Volkswagen|Touran 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Acura|ILX 2016-18|Technology Plus Package or AcuraWatch Plus|openpilot|26 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Honda Nidec connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Acura|ILX 2019|All|openpilot|26 mph|25 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Honda Nidec connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Acura|RDX 2016-18|AcuraWatch Plus or Advance Package|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Honda Nidec connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Acura|RDX 2019-21|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Audi|A3 2014-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Audi|A3 Sportback e-tron 2017-18|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Audi|Q2 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Audi|Q3 2019-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Audi|RS3 2018|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Audi|S3 2015-17|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Chevrolet|Bolt EUV 2022-23|Premier or Premier Redline Trim without Super Cruise Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 GM connector
- 1 comma 3X
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Chevrolet|Bolt EV 2022-23|2LT Trim with Adaptive Cruise Control Package|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 GM connector
- 1 comma 3X
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Chevrolet|Equinox 2019-22|Adaptive Cruise Control (ACC)|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 GM connector
- 1 comma 3X
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Chevrolet|Silverado 1500 2020-21|Safety Package II|openpilot available[1](#footnotes)|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 GM connector
- 1 comma 3X
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Chevrolet|Trailblazer 2021-22|Adaptive Cruise Control (ACC)|openpilot available[1](#footnotes)|3 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 GM connector
- 1 comma 3X
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Chrysler|Pacifica 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 FCA connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Chrysler|Pacifica 2019-20|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 FCA connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Chrysler|Pacifica 2021-23|All|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 FCA connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Chrysler|Pacifica Hybrid 2017-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 FCA connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Chrysler|Pacifica Hybrid 2019-25|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 FCA connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|comma|body|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|None||| +|CUPRA|Ateca 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Dodge|Durango 2020-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 FCA connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Ford|Bronco Sport 2021-24|Co-Pilot360 Assist+|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q3 connector
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Ford|Escape 2020-22|Co-Pilot360 Assist+|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Ford|Escape 2023-24|Co-Pilot360 Assist+|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q4 connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Ford|Escape Hybrid 2020-22|Co-Pilot360 Assist+|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Ford|Escape Hybrid 2023-24|Co-Pilot360 Assist+|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q4 connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Ford|Escape Plug-in Hybrid 2020-22|Co-Pilot360 Assist+|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Ford|Escape Plug-in Hybrid 2023-24|Co-Pilot360 Assist+|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q4 connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Ford|Expedition 2022-24|Co-Pilot360 Assist 2.0|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q4 connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Ford|Explorer 2020-24|Co-Pilot360 Assist+|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Ford|Explorer Hybrid 2020-24|Co-Pilot360 Assist+|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Ford|F-150 2021-23|Co-Pilot360 Assist 2.0|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q4 connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Ford|F-150 Hybrid 2021-23|Co-Pilot360 Assist 2.0|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q4 connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Ford|Focus 2018[3](#footnotes)|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Ford|Focus Hybrid 2018[3](#footnotes)|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Ford|Kuga 2020-23|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Ford|Kuga Hybrid 2020-23|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Ford|Kuga Hybrid 2024|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q4 connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Ford|Kuga Plug-in Hybrid 2020-23|Adaptive Cruise Control with Lane Centering|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Ford|Kuga Plug-in Hybrid 2024|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q4 connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Ford|Maverick 2022|LARIAT Luxury|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q3 connector
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Ford|Maverick 2023-24|Co-Pilot360 Assist|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q3 connector
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Ford|Maverick Hybrid 2022|LARIAT Luxury|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q3 connector
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Ford|Maverick Hybrid 2023-24|Co-Pilot360 Assist|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q3 connector
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Ford|Mustang Mach-E 2021-24|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q4 connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Ford|Ranger 2024|Adaptive Cruise Control with Lane Centering|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q4 connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Genesis|G70 2018|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai F connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Genesis|G70 2019-21|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai F connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Genesis|G70 2022-23|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai L connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Genesis|G80 2017|All|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Hyundai J connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Genesis|G80 2018-19|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai H connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Genesis|G80 (2.5T Advanced Trim, with HDA II) 2024[6](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai P connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Genesis|G90 2017-20|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai C connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Genesis|GV60 (Advanced Trim) 2023[6](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Genesis|GV60 (Performance Trim) 2022-23[6](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai K connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Genesis|GV70 (2.5T Trim, without HDA II) 2022-24[6](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai L connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Genesis|GV70 (3.5T Trim, without HDA II) 2022-23[6](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai M connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Genesis|GV70 Electrified (Australia Only) 2022[6](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai Q connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Genesis|GV70 Electrified (with HDA II) 2023-24[6](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai Q connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Genesis|GV80 2023[6](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai M connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|GMC|Sierra 1500 2020-21|Driver Alert Package II|openpilot available[1](#footnotes)|0 mph|6 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 GM connector
- 1 comma 3X
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Honda|Accord 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Honda|Accord Hybrid 2018-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Honda|Civic 2016-18|Honda Sensing|openpilot|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Nidec connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Honda|Civic 2019-21|All|openpilot available[1](#footnotes)|0 mph|2 mph[5](#footnotes)|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Honda|Civic 2022-24|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch B connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Honda|Civic Hatchback 2017-21|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Honda|Civic Hatchback 2022-24|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch B connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Honda|Civic Hatchback Hybrid 2025|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch B connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Honda|Civic Hatchback Hybrid (Europe only) 2023|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch B connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Honda|Civic Hybrid 2025|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch B connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Honda|CR-V 2015-16|Touring Trim|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Honda Nidec connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Honda|CR-V 2017-22|Honda Sensing|openpilot available[1](#footnotes)|0 mph|15 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Honda|CR-V Hybrid 2017-22|Honda Sensing|openpilot available[1](#footnotes)|0 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Honda|e 2020|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Honda|Fit 2018-20|Honda Sensing|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Honda Nidec connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Honda|Freed 2020|Honda Sensing|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Honda Nidec connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Honda|HR-V 2019-22|Honda Sensing|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Honda Nidec connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Honda|HR-V 2023-25|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch B connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Honda|Insight 2019-22|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Honda|Inspire 2018|All|openpilot available[1](#footnotes)|0 mph|3 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Honda Bosch A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Honda|Odyssey 2018-20|Honda Sensing|openpilot|26 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Honda Nidec connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Honda|Passport 2019-25|All|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Honda Nidec connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Honda|Pilot 2016-22|Honda Sensing|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Honda Nidec connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Honda|Ridgeline 2017-25|Honda Sensing|openpilot|26 mph|12 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Honda Nidec connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Azera 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai K connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Azera Hybrid 2019|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai C connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Azera Hybrid 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai K connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Custin 2023|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai K connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Elantra 2017-18|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Hyundai B connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Elantra 2019|Smart Cruise Control (SCC)|Stock|19 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Hyundai G connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Elantra 2021-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai K connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Elantra GT 2017-20|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai E connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Elantra Hybrid 2021-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai K connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Genesis 2015-16|Smart Cruise Control (SCC)|Stock|19 mph|37 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Hyundai J connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|i30 2017-19|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai E connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Ioniq 5 (Southeast Asia and Europe only) 2022-24[6](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai Q connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Ioniq 5 (with HDA II) 2022-24[6](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai Q connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Ioniq 5 (without HDA II) 2022-24[6](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai K connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Ioniq 6 (with HDA II) 2023-24[6](#footnotes)|Highway Driving Assist II|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai P connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Ioniq Electric 2019|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai C connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Ioniq Electric 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai H connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Ioniq Hybrid 2017-19|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai C connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Ioniq Hybrid 2020-22|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai H connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Ioniq Plug-in Hybrid 2019|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai C connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Ioniq Plug-in Hybrid 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai H connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Kona 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|6 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Hyundai B connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Kona Electric 2018-21|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai G connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Kona Electric 2022-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai O connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Kona Electric (with HDA II, Korea only) 2023[6](#footnotes)|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai R connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Kona Hybrid 2020|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai I connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Nexo 2021|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai H connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Palisade 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai H connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Santa Cruz 2022-24[6](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai N connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Santa Fe 2019-20|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai D connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Santa Fe 2021-23|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai L connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Santa Fe Hybrid 2022-23|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai L connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Santa Fe Plug-in Hybrid 2022-23|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai L connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Sonata 2018-19|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai E connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Sonata 2020-23|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Sonata Hybrid 2020-23|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Staria 2023[6](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai K connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Tucson 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Hyundai L connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Tucson 2022[6](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai N connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Tucson 2023-24[6](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai N connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Tucson Diesel 2019|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai L connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Tucson Hybrid 2022-24[6](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai N connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Tucson Plug-in Hybrid 2024[6](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai N connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Hyundai|Veloster 2019-20|Smart Cruise Control (SCC)|Stock|5 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Hyundai E connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Jeep|Grand Cherokee 2016-18|Adaptive Cruise Control (ACC)|Stock|0 mph|9 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 FCA connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Jeep|Grand Cherokee 2019-21|Adaptive Cruise Control (ACC)|Stock|0 mph|39 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 FCA connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|Carnival 2022-24[6](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|Carnival (China only) 2023[6](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai K connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|Ceed 2019-21|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai E connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|EV6 (Southeast Asia only) 2022-24[6](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai P connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|EV6 (with HDA II) 2022-24[6](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai P connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|EV6 (without HDA II) 2022-24[6](#footnotes)|Highway Driving Assist|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai L connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|Forte 2019-21|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|6 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Hyundai G connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|Forte 2022-23|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai E connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|K5 2021-24|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|K5 Hybrid 2020-22|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|K8 Hybrid (with HDA II) 2023[6](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai Q connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|Niro EV 2019|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai H connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|Niro EV 2020|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai F connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|Niro EV 2021|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai C connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|Niro EV 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai H connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|Niro EV (with HDA II) 2025[6](#footnotes)|Highway Driving Assist II|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai R connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|Niro EV (without HDA II) 2023-25[6](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|Niro Hybrid 2018|Smart Cruise Control (SCC)|Stock|10 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Hyundai C connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|Niro Hybrid 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai D connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|Niro Hybrid 2022|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai F connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|Niro Hybrid 2023[6](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|Niro Plug-in Hybrid 2018-19|All|Stock|10 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Hyundai C connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|Niro Plug-in Hybrid 2020|Smart Cruise Control (SCC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai D connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|Niro Plug-in Hybrid 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai D connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|Niro Plug-in Hybrid 2022|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai F connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|Optima 2017|Advanced Smart Cruise Control|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai B connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|Optima 2019-20|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai G connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|Optima Hybrid 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai H connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|Seltos 2021|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|Sorento 2018|Advanced Smart Cruise Control & LKAS|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai E connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|Sorento 2019|Smart Cruise Control (SCC)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai E connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|Sorento 2021-23[6](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai K connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|Sorento Hybrid 2021-23[6](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|Sorento Plug-in Hybrid 2022-23[6](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|Sportage 2023-24[6](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai N connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|Sportage Hybrid 2023[6](#footnotes)|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai N connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|Stinger 2018-20|Smart Cruise Control (SCC)|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai C connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|Stinger 2022-23|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai K connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Kia|Telluride 2020-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Hyundai H connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Lexus|CT Hybrid 2017-18|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Lexus|ES 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Lexus|ES 2019-25|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Lexus|ES Hybrid 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Lexus|ES Hybrid 2019-25|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Lexus|GS F 2016|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Lexus|IS 2017-19|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Lexus|IS 2022-24|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Lexus|LC 2024-25|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Lexus|NX 2018-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Lexus|NX 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Lexus|NX Hybrid 2018-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Lexus|NX Hybrid 2020-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Lexus|RC 2018-20|All|Stock|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Lexus|RC 2023|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Lexus|RX 2016|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Lexus|RX 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Lexus|RX 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Lexus|RX Hybrid 2016|Lexus Safety System+|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Lexus|RX Hybrid 2017-19|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Lexus|RX Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Lexus|UX Hybrid 2019-24|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Lincoln|Aviator 2020-24|Co-Pilot360 Plus|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Lincoln|Aviator Plug-in Hybrid 2020-24|Co-Pilot360 Plus|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ford Q3 connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|MAN|eTGE 2020-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|MAN|TGE 2017-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Mazda|CX-5 2022-25|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Mazda connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Mazda|CX-9 2021-23|All|Stock|0 mph|28 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Mazda connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Nissan[7](#footnotes)|Altima 2019-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Nissan B connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Nissan[7](#footnotes)|Leaf 2018-23|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Nissan A connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Nissan[7](#footnotes)|Rogue 2018-20|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Nissan A connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Nissan[7](#footnotes)|X-Trail 2017|ProPILOT Assist|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Nissan A connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Ram|1500 2019-24|Adaptive Cruise Control (ACC)|Stock|0 mph|32 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Ram connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Rivian|R1S 2022-24|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Rivian A connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Rivian|R1T 2022-24|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Rivian A connector
- 1 USB-C coupler
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|SEAT|Ateca 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|SEAT|Leon 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Subaru|Ascent 2019-21|All[8](#footnotes)|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Subaru A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
Tools- 1 Pry Tool
- 1 Socket Wrench 8mm or 5/16" (deep)
||| +|Subaru|Crosstrek 2018-19|EyeSight Driver Assistance[8](#footnotes)|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Subaru A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
Tools- 1 Pry Tool
- 1 Socket Wrench 8mm or 5/16" (deep)
||| +|Subaru|Crosstrek 2020-23|EyeSight Driver Assistance[8](#footnotes)|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Subaru A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
Tools- 1 Pry Tool
- 1 Socket Wrench 8mm or 5/16" (deep)
||| +|Subaru|Forester 2019-21|All[8](#footnotes)|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Subaru A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
Tools- 1 Pry Tool
- 1 Socket Wrench 8mm or 5/16" (deep)
||| +|Subaru|Impreza 2017-19|EyeSight Driver Assistance[8](#footnotes)|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Subaru A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
Tools- 1 Pry Tool
- 1 Socket Wrench 8mm or 5/16" (deep)
||| +|Subaru|Impreza 2020-22|EyeSight Driver Assistance[8](#footnotes)|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Subaru A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
Tools- 1 Pry Tool
- 1 Socket Wrench 8mm or 5/16" (deep)
||| +|Subaru|Legacy 2020-22|All[8](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Subaru B connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
Tools- 1 Pry Tool
- 1 Socket Wrench 8mm or 5/16" (deep)
||| +|Subaru|Outback 2020-22|All[8](#footnotes)|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Subaru B connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
Tools- 1 Pry Tool
- 1 Socket Wrench 8mm or 5/16" (deep)
||| +|Subaru|XV 2018-19|EyeSight Driver Assistance[8](#footnotes)|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-empty.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Subaru A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
Tools- 1 Pry Tool
- 1 Socket Wrench 8mm or 5/16" (deep)
||| +|Subaru|XV 2020-21|EyeSight Driver Assistance[8](#footnotes)|openpilot available[1,9](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Subaru A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
Tools- 1 Pry Tool
- 1 Socket Wrench 8mm or 5/16" (deep)
||| +|Škoda|Fabia 2022-23[15](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[17](#footnotes)||| +|Škoda|Kamiq 2021-23[13,15](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[17](#footnotes)||| +|Škoda|Karoq 2019-23[15](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Škoda|Kodiaq 2017-23[15](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Škoda|Octavia 2015-19[15](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Škoda|Octavia RS 2016[15](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Škoda|Octavia Scout 2017-19[15](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Škoda|Scala 2020-23[15](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[17](#footnotes)||| +|Škoda|Superb 2015-22[15](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Tesla[11](#footnotes)|Model 3 (with HW3) 2019-23[10](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Tesla A connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Tesla[11](#footnotes)|Model 3 (with HW4) 2024-25[10](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Tesla B connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Tesla[11](#footnotes)|Model Y (with HW3) 2020-23[10](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Tesla A connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Tesla[11](#footnotes)|Model Y (with HW4) 2024[10](#footnotes)|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Tesla B connector
- 1 USB-C coupler
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|Alphard 2019-20|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|Alphard Hybrid 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|Avalon 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|Avalon 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|Avalon 2019-21|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|Avalon 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|Avalon Hybrid 2019-21|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|Avalon Hybrid 2022|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|C-HR 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|C-HR 2021|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|C-HR Hybrid 2017-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|C-HR Hybrid 2021-22|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|Camry 2018-20|All|Stock|0 mph[12](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|Camry 2021-24|All|openpilot|0 mph[12](#footnotes)|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|Camry Hybrid 2018-20|All|Stock|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|Camry Hybrid 2021-24|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|Corolla 2017-19|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|Corolla 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|Corolla Cross (Non-US only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|Corolla Cross Hybrid (Non-US only) 2020-22|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|Corolla Hatchback 2019-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|Corolla Hybrid 2020-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|Corolla Hybrid (South America only) 2020-23|All|openpilot|17 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|Highlander 2017-19|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|Highlander 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|Highlander Hybrid 2017-19|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|Highlander Hybrid 2020-23|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|Mirai 2021|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|Prius 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|Prius 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|Prius 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|Prius Prime 2017-20|All|openpilot available[2](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|Prius Prime 2021-22|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|Prius v 2017|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|RAV4 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|RAV4 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|RAV4 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|RAV4 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|RAV4 2023-25|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|RAV4 Hybrid 2016|Toyota Safety Sense P|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|RAV4 Hybrid 2017-18|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|RAV4 Hybrid 2019-21|All|openpilot|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|RAV4 Hybrid 2022|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|RAV4 Hybrid 2023-25|All|openpilot available[1](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Toyota|Sienna 2018-20|All|openpilot available[2](#footnotes)|19 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 Toyota A connector
- 1 comma 3X
- 1 comma power v3
- 1 harness box
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Volkswagen|Arteon 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Volkswagen|Arteon eHybrid 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Volkswagen|Arteon R 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Volkswagen|Arteon Shooting Brake 2020-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Volkswagen|Atlas 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Volkswagen|Atlas Cross Sport 2020-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Volkswagen|California 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Volkswagen|Caravelle 2020|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Volkswagen|CC 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Volkswagen|Crafter 2017-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Volkswagen|e-Crafter 2018-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Volkswagen|e-Golf 2014-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Volkswagen|Golf 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Volkswagen|Golf Alltrack 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Volkswagen|Golf GTD 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Volkswagen|Golf GTE 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Volkswagen|Golf GTI 2015-21|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-empty.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Volkswagen|Golf R 2015-19|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Volkswagen|Golf SportsVan 2015-20|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Volkswagen|Grand California 2019-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|31 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 angled mount (8 degrees)
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Volkswagen|Jetta 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Volkswagen|Jetta GLI 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Volkswagen|Passat 2015-22[14](#footnotes)|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Volkswagen|Passat Alltrack 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Volkswagen|Passat GTE 2015-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Volkswagen|Polo 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[17](#footnotes)||| +|Volkswagen|Polo GTI 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[17](#footnotes)||| +|Volkswagen|T-Cross 2021|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
[17](#footnotes)||| +|Volkswagen|T-Roc 2018-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Volkswagen|Taos 2022-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Volkswagen|Teramont 2018-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Volkswagen|Teramont Cross Sport 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Volkswagen|Teramont X 2021-22|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Volkswagen|Tiguan 2018-24|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Volkswagen|Tiguan eHybrid 2021-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| +|Volkswagen|Touran 2016-23|Adaptive Cruise Control (ACC) & Lane Assist|openpilot available[1,16](#footnotes)|0 mph|0 mph|[![star](assets/icon-star-full.svg)](##)|[![star](assets/icon-star-full.svg)](##)|
Parts- 1 USB-C coupler
- 1 VW J533 connector
- 1 comma 3X
- 1 harness box
- 1 long OBD-C cable (9.5 ft)
- 1 mount
- 1 right angle OBD-C cable (1.5 ft)
Buy Here
||| ### Footnotes 1openpilot Longitudinal Control (Alpha) is available behind a toggle; the toggle is only available in non-release branches such as `devel` or `nightly-dev`.
diff --git a/opendbc_repo b/opendbc_repo index 2a11f9627c..5509df5eb3 160000 --- a/opendbc_repo +++ b/opendbc_repo @@ -1 +1 @@ -Subproject commit 2a11f9627cf7e43c0d7b0ab25051b7b305f03c1f +Subproject commit 5509df5eb3e965335c04c61d4039e8378bf18718 diff --git a/panda b/panda index c597f948f9..e46680ff6f 160000 --- a/panda +++ b/panda @@ -1 +1 @@ -Subproject commit c597f948f99f09e885f5f85c7da1745e92222a6e +Subproject commit e46680ff6f8757a89ff82a5d835182725150b592 diff --git a/pyproject.toml b/pyproject.toml index bc1b2a0644..b9e2d0ecbf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,7 +26,7 @@ dependencies = [ "pycapnp", "Cython", "setuptools", - "numpy >=2.0, <2.2", # Linting issues with mypy in 2.2 + "numpy >=2.0", # body / webrtcd "aiohttp", @@ -42,7 +42,6 @@ dependencies = [ # modeld "onnx >= 1.14.0", - "llvmlite", # logging "pyzmq", @@ -86,8 +85,8 @@ testing = [ "pytest", "pytest-cpp", "pytest-subtests", - # https://github.com/pytest-dev/pytest-xdist/issues/1215 - "pytest-xdist @ git+https://github.com/sshane/pytest-xdist@909e97b49d12401c10608f9d777bfc9dab8a4413", + # https://github.com/pytest-dev/pytest-xdist/pull/1229 + "pytest-xdist @ git+https://github.com/sshane/pytest-xdist@2b4372bd62699fb412c4fe2f95bf9f01bd2018da", "pytest-timeout", "pytest-randomly", "pytest-asyncio", @@ -121,7 +120,7 @@ dev = [ tools = [ "metadrive-simulator @ https://github.com/commaai/metadrive/releases/download/MetaDrive-minimal-0.4.2.4/metadrive_simulator-0.4.2.4-py3-none-any.whl ; (platform_machine != 'aarch64')", - "rerun-sdk >= 0.18", + #"rerun-sdk >= 0.18", # this is pretty big, so only enable once we use it ] [project.urls] @@ -178,9 +177,6 @@ skip = "./third_party/*, ./tinygrad/*, ./tinygrad_repo/*, ./msgq/*, ./panda/*, . [tool.mypy] python_version = "3.11" -plugins = [ - "numpy.typing.mypy_plugin", -] exclude = [ "cereal/", "msgq/", @@ -263,6 +259,7 @@ lint.flake8-implicit-str-concat.allow-multiline = false "pytest.main".msg = "pytest.main requires special handling that is easy to mess up!" "unittest".msg = "Use pytest" "pyray.measure_text_ex".msg = "Use openpilot.system.ui.lib.text_measure" +"time.time".msg = "Use time.monotonic" [tool.ruff.format] quote-style = "preserve" diff --git a/selfdrive/car/car_specific.py b/selfdrive/car/car_specific.py index 151a8479a7..083885211f 100644 --- a/selfdrive/car/car_specific.py +++ b/selfdrive/car/car_specific.py @@ -78,7 +78,8 @@ class CarSpecificEvents: events.add(EventName.manualRestart) elif self.CP.brand == 'toyota': - events = self.create_common_events(CS, CS_prev) + # TODO: when we check for unexpected disengagement, check gear not S1, S2, S3 + events = self.create_common_events(CS, CS_prev, extra_gears=[GearShifter.sport]) if self.CP.openpilotLongitudinalControl: if CS.cruiseState.standstill and not CS.brakePressed: diff --git a/selfdrive/car/card.py b/selfdrive/car/card.py index 8448af56db..0564a4c5bb 100755 --- a/selfdrive/car/card.py +++ b/selfdrive/car/card.py @@ -107,7 +107,7 @@ class Car: with car.CarParams.from_bytes(cached_params_raw) as _cached_params: cached_params = _cached_params - fixed_fingerprint = json.loads(self.params.get("CarPlatformBundle", encoding='utf-8') or "{}").get("platform", None) + fixed_fingerprint = json.loads(self.params.get("CarPlatformBundle") or "{}").get("platform", None) self.CI = get_car(*self.can_callbacks, obd_callback(self.params), alpha_long_allowed, is_release, num_pandas, cached_params, fixed_fingerprint) sunnypilot_interfaces.setup_interfaces(self.CI, self.params) @@ -147,7 +147,7 @@ class Car: except Exception: pass - secoc_key = self.params.get("SecOCKey", encoding='utf8') + secoc_key = self.params.get("SecOCKey") if secoc_key is not None: saved_secoc_key = bytes.fromhex(secoc_key.strip()) if len(saved_secoc_key) == 16: diff --git a/selfdrive/car/tests/test_models.py b/selfdrive/car/tests/test_models.py index 0fc6716dd3..4f61ad3c35 100644 --- a/selfdrive/car/tests/test_models.py +++ b/selfdrive/car/tests/test_models.py @@ -5,7 +5,6 @@ import pytest import random import unittest # noqa: TID251 from collections import defaultdict, Counter -from functools import partial import hypothesis.strategies as st from hypothesis import Phase, given, settings from parameterized import parameterized_class @@ -23,8 +22,7 @@ from openpilot.common.basedir import BASEDIR from openpilot.selfdrive.pandad import can_capnp_to_list from openpilot.selfdrive.test.helpers import read_segment_list from openpilot.system.hardware.hw import DEFAULT_DOWNLOAD_CACHE_ROOT -from openpilot.tools.lib.logreader import LogReader, LogsUnavailable, openpilotci_source_zst, openpilotci_source, internal_source, \ - internal_source_zst, comma_api_source, auto_source +from openpilot.tools.lib.logreader import LogReader, LogsUnavailable, openpilotci_source, internal_source, comma_api_source from openpilot.tools.lib.route import SegmentName SafetyModel = car.CarParams.SafetyModel @@ -126,9 +124,8 @@ class TestCarModelBase(unittest.TestCase): segment_range = f"{cls.test_route.route}/{seg}" try: - source = partial(auto_source, sources=[internal_source, internal_source_zst] if len(INTERNAL_SEG_LIST) else \ - [openpilotci_source_zst, openpilotci_source, comma_api_source]) - lr = LogReader(segment_range, source=source, sort_by_time=True) + sources = [internal_source] if len(INTERNAL_SEG_LIST) else [openpilotci_source, comma_api_source] + lr = LogReader(segment_range, sources=sources, sort_by_time=True) return cls.get_testing_data_from_logreader(lr) except (LogsUnavailable, AssertionError): pass @@ -199,7 +196,6 @@ class TestCarModelBase(unittest.TestCase): def test_car_interface(self): # TODO: also check for checksum violations from can parser can_invalid_cnt = 0 - can_valid = False CC = structs.CarControl().as_reader() CC_SP = structs.CarControlSP() @@ -207,11 +203,8 @@ class TestCarModelBase(unittest.TestCase): CS, _ = self.CI.update(msg) self.CI.apply(CC, CC_SP, msg[0]) - if CS.canValid: - can_valid = True - # wait max of 2s for low frequency msgs to be seen - if i > 200 or can_valid: + if i > 250: can_invalid_cnt += not CS.canValid self.assertEqual(can_invalid_cnt, 0) @@ -331,7 +324,7 @@ class TestCarModelBase(unittest.TestCase): vehicle_speed_seen = self.CP.steerControlType == SteerControlType.angle and not self.CP.notCar - for dat in msgs: + for n, dat in enumerate(msgs): # due to panda updating state selectively, only edges are expected to match # TODO: warm up CarState with real CAN messages to check edge of both sources # (eg. toyota's gasPressed is the inverse of a signal being set) @@ -350,6 +343,8 @@ class TestCarModelBase(unittest.TestCase): can = [(int(time.monotonic() * 1e9), [CanData(address=address, dat=dat, src=bus)])] CS, _ = self.CI.update(can) + if n < 5: # CANParser warmup time + continue if self.safety.get_gas_pressed_prev() != prev_panda_gas: self.assertEqual(CS.gasPressed, self.safety.get_gas_pressed_prev()) @@ -369,7 +364,7 @@ class TestCarModelBase(unittest.TestCase): if self.safety.get_steering_disengage_prev() != prev_panda_steering_disengage: self.assertEqual(CS.steeringDisengage, self.safety.get_steering_disengage_prev()) - if self.safety.get_vehicle_moving() != prev_panda_vehicle_moving: + if self.safety.get_vehicle_moving() != prev_panda_vehicle_moving and not self.CP.notCar: self.assertEqual(not CS.standstill, self.safety.get_vehicle_moving()) # check vehicle speed if angle control car or available @@ -427,7 +422,7 @@ class TestCarModelBase(unittest.TestCase): # TODO: check rest of panda's carstate (steering, ACC main on, etc.) checks['gasPressed'] += CS.gasPressed != self.safety.get_gas_pressed_prev() - checks['standstill'] += CS.standstill == self.safety.get_vehicle_moving() + checks['standstill'] += (CS.standstill == self.safety.get_vehicle_moving()) and not self.CP.notCar # check vehicle speed if angle control car or available if self.safety.get_vehicle_speed_min() > 0 or self.safety.get_vehicle_speed_max() > 0: diff --git a/selfdrive/controls/controlsd.py b/selfdrive/controls/controlsd.py index 9ef985fcc4..61ad4754a6 100755 --- a/selfdrive/controls/controlsd.py +++ b/selfdrive/controls/controlsd.py @@ -164,10 +164,7 @@ class Controls(ControlsExt): CC.cruiseControl.override = CC.enabled and not CC.longActive and self.CP.openpilotLongitudinalControl CC.cruiseControl.cancel = CS.cruiseState.enabled and (not CC.enabled or not self.CP.pcmCruise) - - speeds = self.sm['longitudinalPlan'].speeds - if len(speeds): - CC.cruiseControl.resume = CC.enabled and CS.cruiseState.standstill and speeds[-1] > 0.1 + CC.cruiseControl.resume = CC.enabled and CS.cruiseState.standstill and not self.sm['longitudinalPlan'].shouldStop hudControl = CC.hudControl hudControl.setSpeed = float(CS.vCruiseCluster * CV.KPH_TO_MS) diff --git a/selfdrive/controls/lib/latcontrol_torque.py b/selfdrive/controls/lib/latcontrol_torque.py index 467f403103..d7efcbcd8d 100644 --- a/selfdrive/controls/lib/latcontrol_torque.py +++ b/selfdrive/controls/lib/latcontrol_torque.py @@ -2,6 +2,7 @@ import math import numpy as np from cereal import log +from opendbc.car import FRICTION_THRESHOLD, get_friction from opendbc.car.interfaces import LatControlInputs from opendbc.car.vehicle_model import ACCELERATION_DUE_TO_GRAVITY from openpilot.selfdrive.controls.lib.latcontrol import LatControl @@ -61,13 +62,13 @@ class LatControlTorque(LatControl): measurement = actual_lateral_accel + low_speed_factor * actual_curvature gravity_adjusted_lateral_accel = desired_lateral_accel - roll_compensation torque_from_setpoint = self.torque_from_lateral_accel(LatControlInputs(setpoint, roll_compensation, CS.vEgo, CS.aEgo), self.torque_params, - setpoint, lateral_accel_deadzone, friction_compensation=False, gravity_adjusted=False) + gravity_adjusted=False) torque_from_measurement = self.torque_from_lateral_accel(LatControlInputs(measurement, roll_compensation, CS.vEgo, CS.aEgo), self.torque_params, - measurement, lateral_accel_deadzone, friction_compensation=False, gravity_adjusted=False) + gravity_adjusted=False) pid_log.error = float(torque_from_setpoint - torque_from_measurement) ff = self.torque_from_lateral_accel(LatControlInputs(gravity_adjusted_lateral_accel, roll_compensation, CS.vEgo, CS.aEgo), self.torque_params, - desired_lateral_accel - actual_lateral_accel, lateral_accel_deadzone, friction_compensation=True, gravity_adjusted=True) + ff += get_friction(desired_lateral_accel - actual_lateral_accel, lateral_accel_deadzone, FRICTION_THRESHOLD, self.torque_params) # Lateral acceleration torque controller extension updates # Overrides stock ff and pid_log.error diff --git a/selfdrive/controls/lib/lateral_mpc_lib/SConscript b/selfdrive/controls/lib/lateral_mpc_lib/SConscript index 2c03da06a6..c9ebf89207 100644 --- a/selfdrive/controls/lib/lateral_mpc_lib/SConscript +++ b/selfdrive/controls/lib/lateral_mpc_lib/SConscript @@ -1,4 +1,4 @@ -Import('env', 'envCython', 'arch', 'msgq_python', 'common_python', 'opendbc_python', 'np_version') +Import('env', 'envCython', 'arch', 'msgq_python', 'common_python', 'np_version') gen = "c_generated_code" @@ -55,18 +55,23 @@ source_list = ['lat_mpc.py', ] lenv = env.Clone() +acados_rel_path = Dir(gen).rel_path(Dir(f"#third_party/acados/{arch}/lib")) +lenv["RPATH"] += [lenv.Literal(f'\\$$ORIGIN/{acados_rel_path}')] lenv.Clean(generated_files, Dir(gen)) generated_lat = lenv.Command(generated_files, source_list, f"cd {Dir('.').abspath} && python3 lat_mpc.py") -lenv.Depends(generated_lat, [msgq_python, common_python, opendbc_python]) +lenv.Depends(generated_lat, [msgq_python, common_python]) lenv["CFLAGS"].append("-DACADOS_WITH_QPOASES") lenv["CXXFLAGS"].append("-DACADOS_WITH_QPOASES") lenv["CCFLAGS"].append("-Wno-unused") if arch != "Darwin": lenv["LINKFLAGS"].append("-Wl,--disable-new-dtags") +else: + lenv["LINKFLAGS"].append("-Wl,-install_name,@loader_path/libacados_ocp_solver_lat.dylib") + lenv["LINKFLAGS"].append(f"-Wl,-rpath,@loader_path/{acados_rel_path}") lib_solver = lenv.SharedLibrary(f"{gen}/acados_ocp_solver_lat", build_files, LIBS=['m', 'acados', 'hpipm', 'blasfeo', 'qpOASES_e']) @@ -78,7 +83,8 @@ libacados_ocp_solver_pxd = File(f'{gen}/acados_solver.pxd') libacados_ocp_solver_c = File(f'{gen}/acados_ocp_solver_pyx.c') lenv2 = envCython.Clone() -lenv2["LINKFLAGS"] += [lib_solver[0].get_labspath()] +lenv2["LIBPATH"] += [lib_solver[0].dir.abspath] +lenv2["RPATH"] += [lenv2.Literal('\\$$ORIGIN')] lenv2.Command(libacados_ocp_solver_c, [acados_ocp_solver_pyx, acados_ocp_solver_common, libacados_ocp_solver_pxd], f'cython' + \ @@ -86,6 +92,6 @@ lenv2.Command(libacados_ocp_solver_c, f' -I {libacados_ocp_solver_pxd.get_dir().get_labspath()}' + \ f' -I {acados_ocp_solver_common.get_dir().get_labspath()}' + \ f' {acados_ocp_solver_pyx.get_labspath()}') -lib_cython = lenv2.Program(f'{gen}/acados_ocp_solver_pyx.so', [libacados_ocp_solver_c]) +lib_cython = lenv2.Program(f'{gen}/acados_ocp_solver_pyx.so', [libacados_ocp_solver_c], LIBS=['acados_ocp_solver_lat']) lenv2.Depends(lib_cython, lib_solver) lenv2.Depends(libacados_ocp_solver_c, np_version) diff --git a/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript b/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript index 2a155717c0..164b965142 100644 --- a/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript +++ b/selfdrive/controls/lib/longitudinal_mpc_lib/SConscript @@ -1,4 +1,4 @@ -Import('env', 'envCython', 'arch', 'msgq_python', 'common_python', 'opendbc_python', 'pandad_python', 'np_version') +Import('env', 'envCython', 'arch', 'msgq_python', 'common_python', 'pandad_python', 'np_version') gen = "c_generated_code" @@ -61,12 +61,13 @@ source_list = ['long_mpc.py', ] lenv = env.Clone() +acados_rel_path = Dir(gen).rel_path(Dir(f"#third_party/acados/{arch}/lib")) +lenv["RPATH"] += [lenv.Literal(f'\\$$ORIGIN/{acados_rel_path}')] lenv.Clean(generated_files, Dir(gen)) - generated_long = lenv.Command(generated_files, source_list, f"cd {Dir('.').abspath} && python3 long_mpc.py") -lenv.Depends(generated_long, [msgq_python, common_python, opendbc_python, pandad_python]) +lenv.Depends(generated_long, [msgq_python, common_python, pandad_python]) lenv["CFLAGS"].append("-DACADOS_WITH_QPOASES") lenv["CXXFLAGS"].append("-DACADOS_WITH_QPOASES") @@ -75,6 +76,7 @@ if arch != "Darwin": lenv["LINKFLAGS"].append("-Wl,--disable-new-dtags") else: lenv["LINKFLAGS"].append("-Wl,-install_name,@loader_path/libacados_ocp_solver_long.dylib") + lenv["LINKFLAGS"].append(f"-Wl,-rpath,@loader_path/{acados_rel_path}") lib_solver = lenv.SharedLibrary(f"{gen}/acados_ocp_solver_long", build_files, LIBS=['m', 'acados', 'hpipm', 'blasfeo', 'qpOASES_e']) @@ -86,7 +88,8 @@ libacados_ocp_solver_pxd = File(f'{gen}/acados_solver.pxd') libacados_ocp_solver_c = File(f'{gen}/acados_ocp_solver_pyx.c') lenv2 = envCython.Clone() -lenv2["LINKFLAGS"] += [lib_solver[0].get_labspath()] +lenv2["LIBPATH"] += [lib_solver[0].dir.abspath] +lenv2["RPATH"] += [lenv2.Literal('\\$$ORIGIN')] lenv2.Command(libacados_ocp_solver_c, [acados_ocp_solver_pyx, acados_ocp_solver_common, libacados_ocp_solver_pxd], f'cython' + \ @@ -94,6 +97,6 @@ lenv2.Command(libacados_ocp_solver_c, f' -I {libacados_ocp_solver_pxd.get_dir().get_labspath()}' + \ f' -I {acados_ocp_solver_common.get_dir().get_labspath()}' + \ f' {acados_ocp_solver_pyx.get_labspath()}') -lib_cython = lenv2.Program(f'{gen}/acados_ocp_solver_pyx.so', [libacados_ocp_solver_c]) +lib_cython = lenv2.Program(f'{gen}/acados_ocp_solver_pyx.so', [libacados_ocp_solver_c], LIBS=['acados_ocp_solver_long']) lenv2.Depends(lib_cython, lib_solver) lenv2.Depends(libacados_ocp_solver_c, np_version) diff --git a/selfdrive/debug/car/fw_versions.py b/selfdrive/debug/car/fw_versions.py index 03d066cdcb..6ae10d2fb2 100755 --- a/selfdrive/debug/car/fw_versions.py +++ b/selfdrive/debug/car/fw_versions.py @@ -47,15 +47,15 @@ if __name__ == "__main__": num_pandas = len(messaging.recv_one_retry(pandaStates_sock).pandaStates) - t = time.time() + t = time.monotonic() print("Getting vin...") set_obd_multiplexing(True) vin_rx_addr, vin_rx_bus, vin = get_vin(*can_callbacks, (0, 1)) print(f'RX: {hex(vin_rx_addr)}, BUS: {vin_rx_bus}, VIN: {vin}') - print(f"Getting VIN took {time.time() - t:.3f} s") + print(f"Getting VIN took {time.monotonic() - t:.3f} s") print() - t = time.time() + t = time.monotonic() fw_vers = get_fw_versions(*can_callbacks, set_obd_multiplexing, query_brand=args.brand, extra=extra, num_pandas=num_pandas, progress=True) _, candidates = match_fw_to_car(fw_vers, vin) @@ -71,4 +71,4 @@ if __name__ == "__main__": print() print("Possible matches:", candidates) - print(f"Getting fw took {time.time() - t:.3f} s") + print(f"Getting fw took {time.monotonic() - t:.3f} s") diff --git a/selfdrive/debug/car/vw_mqb_config.py b/selfdrive/debug/car/vw_mqb_config.py index 7ff5774a71..3c55642e40 100755 --- a/selfdrive/debug/car/vw_mqb_config.py +++ b/selfdrive/debug/car/vw_mqb_config.py @@ -40,8 +40,7 @@ if __name__ == "__main__": panda = Panda() panda.set_safety_mode(CarParams.SafetyModel.elm327) - bus = 1 if panda.has_obd() else 0 - uds_client = UdsClient(panda, MQB_EPS_CAN_ADDR, MQB_EPS_CAN_ADDR + RX_OFFSET, bus, timeout=0.2) + uds_client = UdsClient(panda, MQB_EPS_CAN_ADDR, MQB_EPS_CAN_ADDR + RX_OFFSET, 1, timeout=0.2) try: uds_client.diagnostic_session_control(SESSION_TYPE.EXTENDED_DIAGNOSTIC) diff --git a/selfdrive/debug/cpu_usage_stat.py b/selfdrive/debug/cpu_usage_stat.py index 234dfea3cc..397e9f35f5 100755 --- a/selfdrive/debug/cpu_usage_stat.py +++ b/selfdrive/debug/cpu_usage_stat.py @@ -37,8 +37,6 @@ monitored_proc_names = [ cpu_time_names = ['user', 'system', 'children_user', 'children_system'] -timer = getattr(time, 'monotonic', time.time) - def get_arg_parser(): parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter) @@ -72,7 +70,7 @@ if __name__ == "__main__": print('Add monitored proc:', k) stats[k] = {'cpu_samples': defaultdict(list), 'min': defaultdict(lambda: None), 'max': defaultdict(lambda: None), 'avg': defaultdict(float), 'last_cpu_times': None, 'last_sys_time': None} - stats[k]['last_sys_time'] = timer() + stats[k]['last_sys_time'] = time.monotonic() stats[k]['last_cpu_times'] = p.cpu_times() monitored_procs.append(p) i = 0 @@ -80,7 +78,7 @@ if __name__ == "__main__": while True: for p in monitored_procs: k = ' '.join(p.cmdline()) - cur_sys_time = timer() + cur_sys_time = time.monotonic() cur_cpu_times = p.cpu_times() cpu_times = np.subtract(cur_cpu_times, stats[k]['last_cpu_times']) / (cur_sys_time - stats[k]['last_sys_time']) stats[k]['last_sys_time'] = cur_sys_time diff --git a/selfdrive/locationd/models/car_kf.py b/selfdrive/locationd/models/car_kf.py index 349897f371..6db749b949 100755 --- a/selfdrive/locationd/models/car_kf.py +++ b/selfdrive/locationd/models/car_kf.py @@ -93,8 +93,9 @@ class CarKalman(KalmanFilter): dim_state = CarKalman.initial_x.shape[0] name = CarKalman.name - # vehicle models comes from The Science of Vehicle Dynamics: Handling, Braking, and Ride of Road and Race Cars - # Model used is in 6.15 with formula from 6.198 + # Linearized single-track lateral dynamics, equations 7.211-7.213 + # Massimo Guiggiani, The Science of Vehicle Dynamics: Handling, Braking, and Ride of Road and Race Cars + # Springer Cham, 2023. doi: https://doi.org/10.1007/978-3-031-06461-6 # globals global_vars = [sp.Symbol(name) for name in CarKalman.global_vars] diff --git a/selfdrive/locationd/paramsd.py b/selfdrive/locationd/paramsd.py index ec15f501ae..b4084fe5bc 100755 --- a/selfdrive/locationd/paramsd.py +++ b/selfdrive/locationd/paramsd.py @@ -1,6 +1,5 @@ #!/usr/bin/env python3 import os -import json import numpy as np import capnp @@ -207,12 +206,11 @@ def migrate_cached_vehicle_params_if_needed(params: Params): return try: - last_parameters_dict = json.loads(last_parameters_data_old) last_parameters_msg = messaging.new_message('liveParameters') last_parameters_msg.liveParameters.valid = True - last_parameters_msg.liveParameters.steerRatio = last_parameters_dict['steerRatio'] - last_parameters_msg.liveParameters.stiffnessFactor = last_parameters_dict['stiffnessFactor'] - last_parameters_msg.liveParameters.angleOffsetAverageDeg = last_parameters_dict['angleOffsetAverageDeg'] + last_parameters_msg.liveParameters.steerRatio = last_parameters_data_old['steerRatio'] + last_parameters_msg.liveParameters.stiffnessFactor = last_parameters_data_old['stiffnessFactor'] + last_parameters_msg.liveParameters.angleOffsetAverageDeg = last_parameters_data_old['angleOffsetAverageDeg'] params.put("LiveParametersV2", last_parameters_msg.to_bytes()) except Exception as e: cloudlog.error(f"Failed to perform parameter migration: {e}") diff --git a/selfdrive/locationd/test/test_paramsd.py b/selfdrive/locationd/test/test_paramsd.py index 2129bf4386..dd496b7675 100644 --- a/selfdrive/locationd/test/test_paramsd.py +++ b/selfdrive/locationd/test/test_paramsd.py @@ -1,6 +1,5 @@ import random import numpy as np -import json from cereal import messaging from openpilot.selfdrive.locationd.paramsd import retrieve_initial_vehicle_params, migrate_cached_vehicle_params_if_needed @@ -47,7 +46,7 @@ class TestParamsd: CP = next(m for m in lr if m.which() == "carParams").carParams msg = get_random_live_parameters(CP) - params.put("LiveParameters", json.dumps(msg.liveParameters.to_dict())) + params.put("LiveParameters", msg.liveParameters.to_dict()) params.put("CarParamsPrevRoute", CP.as_builder().to_bytes()) params.remove("LiveParametersV2") @@ -60,7 +59,7 @@ class TestParamsd: def test_read_saved_params_corrupted_old_format(self): params = Params() - params.put("LiveParameters", b'\x00\x00\x02\x00\x01\x00:F\xde\xed\xae;') + params.put("LiveParameters", {}) params.remove("LiveParametersV2") migrate_cached_vehicle_params_if_needed(params) diff --git a/selfdrive/modeld/SConscript b/selfdrive/modeld/SConscript index 0da3c24e19..6802b45e6e 100644 --- a/selfdrive/modeld/SConscript +++ b/selfdrive/modeld/SConscript @@ -50,9 +50,9 @@ def tg_compile(flags, model_name): # Compile small models for model_name in ['driving_vision', 'driving_policy', 'dmonitoring_model']: flags = { - 'larch64': 'QCOM=1', - 'Darwin': 'CPU=1 IMAGE=0 JIT=2', - }.get(arch, 'LLVM=1 LLVMOPT=1 BEAM=0 IMAGE=0 JIT=2') + 'larch64': 'DEV=QCOM', + 'Darwin': 'DEV=CPU IMAGE=0', + }.get(arch, 'DEV=LLVM IMAGE=0') tg_compile(flags, model_name) # Compile BIG model if USB GPU is available @@ -62,7 +62,7 @@ if "USBGPU" in os.environ: devs = subprocess.check_output('python3 -c "from tinygrad import Device; print(list(Device.get_available_devices()))"', shell=True, cwd=env.Dir('#').abspath) if b"AMD" in devs: print("USB GPU detected... building") - flags = "AMD=1 AMD_IFACE=USB AMD_LLVM=1 NOLOCALS=0 IMAGE=0" + flags = "DEV=AMD AMD_IFACE=USB AMD_LLVM=1 NOLOCALS=0 IMAGE=0" bp = tg_compile(flags, "big_driving_policy") bv = tg_compile(flags, "big_driving_vision") lenv.SideEffect('lock', [bp, bv]) # tg doesn't support multi-process so build serially diff --git a/selfdrive/modeld/dmonitoringmodeld.py b/selfdrive/modeld/dmonitoringmodeld.py index 7ab31ed2b4..215056e6e6 100755 --- a/selfdrive/modeld/dmonitoringmodeld.py +++ b/selfdrive/modeld/dmonitoringmodeld.py @@ -1,13 +1,9 @@ #!/usr/bin/env python3 import os from openpilot.system.hardware import TICI +os.environ['DEV'] = 'QCOM' if TICI else 'LLVM' from tinygrad.tensor import Tensor from tinygrad.dtype import dtypes -if TICI: - from openpilot.selfdrive.modeld.runners.tinygrad_helpers import qcom_tensor_from_opencl_address - os.environ['QCOM'] = '1' -else: - os.environ['LLVM'] = '1' import math import time import pickle @@ -24,6 +20,7 @@ from openpilot.common.transformations.model import dmonitoringmodel_intrinsics, from openpilot.common.transformations.camera import _ar_ox_fisheye, _os_fisheye from openpilot.selfdrive.modeld.models.commonmodel_pyx import CLContext, MonitoringModelFrame from openpilot.selfdrive.modeld.parse_model_outputs import sigmoid +from openpilot.selfdrive.modeld.runners.tinygrad_helpers import qcom_tensor_from_opencl_address MODEL_WIDTH, MODEL_HEIGHT = DM_INPUT_SIZE CALIB_LEN = 3 @@ -93,7 +90,7 @@ class ModelState: self.tensor_inputs['input_img'] = Tensor(self.frame.buffer_from_cl(input_img_cl).reshape((1, MODEL_WIDTH*MODEL_HEIGHT)), dtype=dtypes.uint8).realize() - output = self.model_run(**self.tensor_inputs).numpy().flatten() + output = self.model_run(**self.tensor_inputs).contiguous().realize().uop.base.buffer.numpy() t2 = time.perf_counter() return output, t2 - t1 diff --git a/selfdrive/modeld/modeld.py b/selfdrive/modeld/modeld.py index 31bfd707bb..5c2ce90598 100755 --- a/selfdrive/modeld/modeld.py +++ b/selfdrive/modeld/modeld.py @@ -1,16 +1,11 @@ #!/usr/bin/env python3 import os from openpilot.system.hardware import TICI +os.environ['DEV'] = 'QCOM' if TICI else 'LLVM' USBGPU = "USBGPU" in os.environ if USBGPU: - os.environ['AMD'] = '1' + os.environ['DEV'] = 'AMD' os.environ['AMD_IFACE'] = 'USB' -elif TICI: - from openpilot.selfdrive.modeld.runners.tinygrad_helpers import qcom_tensor_from_opencl_address - os.environ['QCOM'] = '1' -else: - os.environ['LLVM'] = '1' - os.environ['JIT'] = '2' from tinygrad.tensor import Tensor from tinygrad.dtype import dtypes import time @@ -34,6 +29,7 @@ from openpilot.selfdrive.modeld.parse_model_outputs import Parser from openpilot.selfdrive.modeld.fill_model_msg import fill_model_msg, fill_pose_msg, PublishState from openpilot.selfdrive.modeld.constants import ModelConstants, Plan from openpilot.selfdrive.modeld.models.commonmodel_pyx import DrivingModelFrame, CLContext +from openpilot.selfdrive.modeld.runners.tinygrad_helpers import qcom_tensor_from_opencl_address from openpilot.sunnypilot.livedelay.lagd_toggle import LagdToggle @@ -166,14 +162,14 @@ class ModelState: if prepare_only: return None - self.vision_output = self.vision_run(**self.vision_inputs).numpy().flatten() + self.vision_output = self.vision_run(**self.vision_inputs).contiguous().realize().uop.base.buffer.numpy() vision_outputs_dict = self.parser.parse_vision_outputs(self.slice_outputs(self.vision_output, self.vision_output_slices)) self.full_features_buffer[0,:-1] = self.full_features_buffer[0,1:] self.full_features_buffer[0,-1] = vision_outputs_dict['hidden_state'][0, :] self.numpy_inputs['features_buffer'][:] = self.full_features_buffer[0, self.temporal_idxs] - self.policy_output = self.policy_run(**self.policy_inputs).numpy().flatten() + self.policy_output = self.policy_run(**self.policy_inputs).contiguous().realize().uop.base.buffer.numpy() policy_outputs_dict = self.parser.parse_policy_outputs(self.slice_outputs(self.policy_output, self.policy_output_slices)) # TODO model only uses last value now diff --git a/selfdrive/modeld/models/driving_policy.onnx b/selfdrive/modeld/models/driving_policy.onnx index 2fb716997d..187a3b2ecf 100644 --- a/selfdrive/modeld/models/driving_policy.onnx +++ b/selfdrive/modeld/models/driving_policy.onnx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1741cad23f6f451782b5db6182218749ee12072e393d57eac36d8d5c55d9358a +oid sha256:22aec22a10ce09384d4a4af2a0bbff08d54af7e0c888503508f356fae4ff0e29 size 15583374 diff --git a/selfdrive/modeld/models/driving_vision.onnx b/selfdrive/modeld/models/driving_vision.onnx index fe636fb682..18f63358db 100644 --- a/selfdrive/modeld/models/driving_vision.onnx +++ b/selfdrive/modeld/models/driving_vision.onnx @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3d2bd82ba42341dba1bda5426e45c4c646db604c9ac422156eaa2b9ef26194f9 +oid sha256:c824f68646a3b94f117f01c70dc8316fb466e05fbd42ccdba440b8a8dc86914b size 46265993 diff --git a/selfdrive/modeld/parse_model_outputs.py b/selfdrive/modeld/parse_model_outputs.py index 783572d436..b89de27594 100644 --- a/selfdrive/modeld/parse_model_outputs.py +++ b/selfdrive/modeld/parse_model_outputs.py @@ -90,17 +90,17 @@ class Parser: self.parse_mdn('road_transform', outs, in_N=0, out_N=0, out_shape=(ModelConstants.POSE_WIDTH,)) self.parse_mdn('lane_lines', outs, in_N=0, out_N=0, out_shape=(ModelConstants.NUM_LANE_LINES,ModelConstants.IDX_N,ModelConstants.LANE_LINES_WIDTH)) self.parse_mdn('road_edges', outs, in_N=0, out_N=0, out_shape=(ModelConstants.NUM_ROAD_EDGES,ModelConstants.IDX_N,ModelConstants.LANE_LINES_WIDTH)) - self.parse_mdn('lead', outs, in_N=ModelConstants.LEAD_MHP_N, out_N=ModelConstants.LEAD_MHP_SELECTION, - out_shape=(ModelConstants.LEAD_TRAJ_LEN,ModelConstants.LEAD_WIDTH)) - for k in ['lead_prob', 'lane_lines_prob']: - self.parse_binary_crossentropy(k, outs) + self.parse_binary_crossentropy('lane_lines_prob', outs) self.parse_categorical_crossentropy('desire_pred', outs, out_shape=(ModelConstants.DESIRE_PRED_LEN,ModelConstants.DESIRE_PRED_WIDTH)) self.parse_binary_crossentropy('meta', outs) + self.parse_binary_crossentropy('lead_prob', outs) + self.parse_mdn('lead', outs, in_N=ModelConstants.LEAD_MHP_N, out_N=ModelConstants.LEAD_MHP_SELECTION, + out_shape=(ModelConstants.LEAD_TRAJ_LEN,ModelConstants.LEAD_WIDTH)) return outs def parse_policy_outputs(self, outs: dict[str, np.ndarray]) -> dict[str, np.ndarray]: self.parse_mdn('plan', outs, in_N=ModelConstants.PLAN_MHP_N, out_N=ModelConstants.PLAN_MHP_SELECTION, - out_shape=(ModelConstants.IDX_N,ModelConstants.PLAN_WIDTH)) + out_shape=(ModelConstants.IDX_N,ModelConstants.PLAN_WIDTH)) if 'lat_planner_solution' in outs: self.parse_mdn('lat_planner_solution', outs, in_N=0, out_N=0, out_shape=(ModelConstants.IDX_N,ModelConstants.LAT_PLANNER_SOLUTION_WIDTH)) if 'desired_curvature' in outs: diff --git a/selfdrive/monitoring/helpers.py b/selfdrive/monitoring/helpers.py index 67776994f0..9649df9a2b 100644 --- a/selfdrive/monitoring/helpers.py +++ b/selfdrive/monitoring/helpers.py @@ -6,6 +6,7 @@ import cereal.messaging as messaging from openpilot.selfdrive.selfdrived.events import Events from openpilot.common.realtime import DT_DMON from openpilot.common.filter_simple import FirstOrderFilter +from openpilot.common.params import Params from openpilot.common.stat_live import RunningStatFilter from openpilot.common.transformations.camera import DEVICE_CAMERAS @@ -159,6 +160,9 @@ class DriverMonitoring: self.threshold_pre = self.settings._DISTRACTED_PRE_TIME_TILL_TERMINAL / self.settings._DISTRACTED_TIME self.threshold_prompt = self.settings._DISTRACTED_PROMPT_TIME_TILL_TERMINAL / self.settings._DISTRACTED_TIME + self.params = Params() + self.too_distracted = self.params.get_bool("DriverTooDistracted") + self._reset_awareness() self._set_timers(active_monitoring=True) self._reset_events() @@ -305,10 +309,15 @@ class DriverMonitoring: def _update_events(self, driver_engaged, op_engaged, standstill, wrong_gear, car_speed): self._reset_events() - # Block engaging after max number of distrations or when alert active + # Block engaging until ignition cycle after max number or time of distractions if self.terminal_alert_cnt >= self.settings._MAX_TERMINAL_ALERTS or \ - self.terminal_time >= self.settings._MAX_TERMINAL_DURATION or \ - self.always_on and self.awareness <= self.threshold_prompt: + self.terminal_time >= self.settings._MAX_TERMINAL_DURATION: + if not self.too_distracted: + self.params.put_bool_nonblocking("DriverTooDistracted", True) + self.too_distracted = True + + # Always-on distraction lockout is temporary + if self.too_distracted or (self.always_on and self.awareness <= self.threshold_prompt): self.current_events.add(EventName.tooDistracted) always_on_valid = self.always_on and not wrong_gear diff --git a/selfdrive/pandad/can_list_to_can_capnp.cc b/selfdrive/pandad/can_list_to_can_capnp.cc index 6ad999da91..f2cf153453 100644 --- a/selfdrive/pandad/can_list_to_can_capnp.cc +++ b/selfdrive/pandad/can_list_to_can_capnp.cc @@ -1,5 +1,5 @@ #include "cereal/messaging/messaging.h" -#include "opendbc/can/common.h" +#include "selfdrive/pandad/can_types.h" void can_list_to_can_capnp_cpp(const std::vector &can_list, std::string &out, bool sendcan, bool valid) { MessageBuilder msg; diff --git a/selfdrive/pandad/can_types.h b/selfdrive/pandad/can_types.h new file mode 100644 index 0000000000..5fae581cfa --- /dev/null +++ b/selfdrive/pandad/can_types.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +struct CanFrame { + long src; + uint32_t address; + std::vector dat; +}; + +struct CanData { + uint64_t nanos; + std::vector frames; +}; \ No newline at end of file diff --git a/selfdrive/pandad/panda_safety.cc b/selfdrive/pandad/panda_safety.cc index 48589c4146..29e96032bf 100644 --- a/selfdrive/pandad/panda_safety.cc +++ b/selfdrive/pandad/panda_safety.cc @@ -2,9 +2,7 @@ #include "cereal/messaging/messaging.h" #include "common/swaglog.h" -void PandaSafety::configureSafetyMode() { - bool is_onroad = params_.getBool("IsOnroad"); - +void PandaSafety::configureSafetyMode(bool is_onroad) { if (is_onroad && !safety_configured_) { updateMultiplexingMode(); diff --git a/selfdrive/pandad/pandad.cc b/selfdrive/pandad/pandad.cc index af27276510..3dbfbcf089 100644 --- a/selfdrive/pandad/pandad.cc +++ b/selfdrive/pandad/pandad.cc @@ -36,8 +36,7 @@ // Ignition: // - If any of the ignition sources in any panda is high, ignition is high -#define MAX_IR_POWER 0.5f -#define MIN_IR_POWER 0.0f +#define MAX_IR_PANDA_VAL 50 #define CUTOFF_IL 400 #define SATURATE_IL 1000 @@ -169,7 +168,7 @@ void fill_panda_state(cereal::PandaState::Builder &ps, cereal::PandaState::Panda ps.setFanPower(health.fan_power); ps.setFanStallCount(health.fan_stall_count); ps.setSafetyRxChecksInvalid((bool)(health.safety_rx_checks_invalid_pkt)); - ps.setSpiChecksumErrorCount(health.spi_checksum_error_count_pkt); + ps.setSpiErrorCount(health.spi_error_count_pkt); ps.setSbu1Voltage(health.sbu1_voltage_mV / 1000.0f); ps.setSbu2Voltage(health.sbu2_voltage_mV / 1000.0f); } @@ -202,7 +201,7 @@ void fill_panda_can_state(cereal::PandaState::PandaCanState::Builder &cs, const cs.setCanCoreResetCnt(can_health.can_core_reset_cnt); } -std::optional send_panda_states(PubMaster *pm, const std::vector &pandas, bool spoofing_started, bool always_offroad) { +std::optional send_panda_states(PubMaster *pm, const std::vector &pandas, bool is_onroad, bool spoofing_started, bool always_offroad) { bool ignition_local = false; const uint32_t pandas_cnt = pandas.size(); @@ -269,8 +268,9 @@ std::optional send_panda_states(PubMaster *pm, const std::vector panda->set_power_saving(power_save_desired); } - // set safety mode to NO_OUTPUT when car is off. ELM327 is an alternative if we want to leverage athenad/connect - if (!ignition_local && (health.safety_mode_pkt != (uint8_t)(cereal::CarParams::SafetyModel::NO_OUTPUT))) { + // set safety mode to NO_OUTPUT when car is off or we're not onroad. ELM327 is an alternative if we want to leverage athenad/connect + bool should_close_relay = !ignition_local || !is_onroad; + if (should_close_relay && (health.safety_mode_pkt != (uint8_t)(cereal::CarParams::SafetyModel::NO_OUTPUT))) { panda->set_safety_model(cereal::CarParams::SafetyModel::NO_OUTPUT); } @@ -337,14 +337,14 @@ void send_peripheral_state(Panda *panda, PubMaster *pm) { pm->send("peripheralState", msg); } -void process_panda_state(std::vector &pandas, PubMaster *pm, bool engaged, bool engaged_mads, bool spoofing_started, bool always_offroad) { +void process_panda_state(std::vector &pandas, PubMaster *pm, bool engaged, bool engaged_mads, bool is_onroad, bool spoofing_started, bool always_offroad) { std::vector connected_serials; for (Panda *p : pandas) { connected_serials.push_back(p->hw_serial()); } { - auto ignition_opt = send_panda_states(pm, pandas, spoofing_started, always_offroad); + auto ignition_opt = send_panda_states(pm, pandas, is_onroad, spoofing_started, always_offroad); if (!ignition_opt) { LOGE("Failed to get ignition_opt"); return; @@ -384,8 +384,8 @@ void process_peripheral_state(Panda *panda, PubMaster *pm, bool no_fan_control) static uint64_t last_driver_camera_t = 0; static uint16_t prev_fan_speed = 999; - static uint16_t ir_pwr = 0; - static uint16_t prev_ir_pwr = 999; + static int ir_pwr = 0; + static int prev_ir_pwr = 999; static FirstOrderFilter integ_lines_filter(0, 30.0, 0.05); @@ -408,11 +408,11 @@ void process_peripheral_state(Panda *panda, PubMaster *pm, bool no_fan_control) last_driver_camera_t = event.getLogMonoTime(); if (cur_integ_lines <= CUTOFF_IL) { - ir_pwr = 100.0 * MIN_IR_POWER; + ir_pwr = 0; } else if (cur_integ_lines > SATURATE_IL) { - ir_pwr = 100.0 * MAX_IR_POWER; + ir_pwr = 100; } else { - ir_pwr = 100.0 * (MIN_IR_POWER + ((cur_integ_lines - CUTOFF_IL) * (MAX_IR_POWER - MIN_IR_POWER) / (SATURATE_IL - CUTOFF_IL))); + ir_pwr = 100 * (cur_integ_lines - CUTOFF_IL) / (SATURATE_IL - CUTOFF_IL); } } @@ -421,8 +421,9 @@ void process_peripheral_state(Panda *panda, PubMaster *pm, bool no_fan_control) ir_pwr = 0; } - if (ir_pwr != prev_ir_pwr || sm.frame % 100 == 0 || ir_pwr >= 50.0) { - panda->set_ir_pwr(ir_pwr); + if (ir_pwr != prev_ir_pwr || sm.frame % 100 == 0) { + int16_t ir_panda = util::map_val(ir_pwr, 0, 100, 0, MAX_IR_PANDA_VAL); + panda->set_ir_pwr(ir_panda); Hardware::set_ir_power(ir_pwr); prev_ir_pwr = ir_pwr; } @@ -437,6 +438,7 @@ void pandad_run(std::vector &pandas) { // Start the CAN send thread std::thread send_thread(can_send_thread, pandas, fake_send); + Params params; RateKeeper rk("pandad", 100); SubMaster sm({"selfdriveState", "selfdriveStateSP", "carParams"}); PubMaster pm({"can", "pandaStates", "peripheralState"}); @@ -444,6 +446,7 @@ void pandad_run(std::vector &pandas) { Panda *peripheral_panda = pandas[0]; bool engaged = false; bool engaged_mads = false; + bool is_onroad = false; bool always_offroad = false; // Main loop: receive CAN data and process states @@ -460,9 +463,10 @@ void pandad_run(std::vector &pandas) { sm.update(0); engaged = sm.allAliveAndValid({"selfdriveState"}) && sm["selfdriveState"].getSelfdriveState().getEnabled(); engaged_mads = process_mads_heartbeat(&sm); + is_onroad = params.getBool("IsOnroad"); always_offroad = panda_safety.getOffroadMode(); - process_panda_state(pandas, &pm, engaged, engaged_mads, spoofing_started, always_offroad); - panda_safety.configureSafetyMode(); + process_panda_state(pandas, &pm, engaged, engaged_mads, is_onroad, spoofing_started, always_offroad); + panda_safety.configureSafetyMode(is_onroad); } // Send out peripheralState at 2Hz @@ -487,7 +491,6 @@ void pandad_run(std::vector &pandas) { } // Close relay on exit to prevent a fault - const bool is_onroad = Params().getBool("IsOnroad"); if (is_onroad && !engaged) { for (auto &p : pandas) { if (p->connected()) { diff --git a/selfdrive/pandad/pandad.h b/selfdrive/pandad/pandad.h index 7b37fbe59a..cda6a16a4a 100644 --- a/selfdrive/pandad/pandad.h +++ b/selfdrive/pandad/pandad.h @@ -11,7 +11,7 @@ void pandad_main_thread(std::vector serials); class PandaSafety { public: PandaSafety(const std::vector &pandas) : pandas_(pandas) {} - void configureSafetyMode(); + void configureSafetyMode(bool is_onroad); bool getOffroadMode(); private: diff --git a/selfdrive/pandad/pandad_api_impl.pyx b/selfdrive/pandad/pandad_api_impl.pyx index 6683b843ae..aaecb8a594 100644 --- a/selfdrive/pandad/pandad_api_impl.pyx +++ b/selfdrive/pandad/pandad_api_impl.pyx @@ -6,7 +6,7 @@ from libcpp.string cimport string from libcpp cimport bool from libc.stdint cimport uint8_t, uint32_t, uint64_t -cdef extern from "opendbc/can/common.h": +cdef extern from "selfdrive/pandad/can_types.h": cdef struct CanFrame: long src uint32_t address diff --git a/selfdrive/selfdrived/alertmanager.py b/selfdrive/selfdrived/alertmanager.py index 79897404e4..86ea68809b 100644 --- a/selfdrive/selfdrived/alertmanager.py +++ b/selfdrive/selfdrived/alertmanager.py @@ -18,7 +18,7 @@ def set_offroad_alert(alert: str, show_alert: bool, extra_text: str = None) -> N if show_alert: a = copy.copy(OFFROAD_ALERTS[alert]) a['extra'] = extra_text or '' - Params().put(alert, json.dumps(a)) + Params().put(alert, a) else: Params().remove(alert) diff --git a/selfdrive/selfdrived/alerts_offroad.json b/selfdrive/selfdrived/alerts_offroad.json index 1668bf17fd..15dd064126 100644 --- a/selfdrive/selfdrived/alerts_offroad.json +++ b/selfdrive/selfdrived/alerts_offroad.json @@ -25,18 +25,14 @@ "text": "An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install.", "severity": 0 }, - "Offroad_UnofficialHardware": { - "text": "Device failed to register. It will not connect to or upload to comma.ai servers, and receives no support from comma.ai. If this is an official device, visit https://comma.ai/support.", + "Offroad_UnregisteredHardware": { + "text": "Device failed to register with the comma.ai backend. It will not connect or upload to comma.ai servers, and receives no support from comma.ai. If this is a device purchased at comma.ai/shop, open a ticket at https://comma.ai/support.", "severity": 1 }, "Offroad_StorageMissing": { "text": "NVMe drive not mounted.", "severity": 1 }, - "Offroad_BadNvme": { - "text": "Unsupported NVMe drive detected. Device may draw significantly more power and overheat due to the unsupported NVMe.", - "severity": 1 - }, "Offroad_CarUnrecognized": { "text": "sunnypilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai.", "severity": 0 @@ -48,5 +44,10 @@ "Offroad_OSMUpdateRequired": { "text": "OpenStreetMap database is out of date. New maps must be downloaded if you wish to continue using OpenStreetMap data for Enhanced Speed Control and road name display.\n\n%1", "severity": 0 + }, + "Offroad_ExcessiveActuation": { + "text": "openpilot has detected excessive %1 actuation. This may be due to a software bug. Please contact support at https://comma.ai/support.", + "severity": 1, + "_comment": "Set extra field to lateral or longitudinal." } } diff --git a/selfdrive/selfdrived/events.py b/selfdrive/selfdrived/events.py index 9bfc638db3..17e1700100 100755 --- a/selfdrive/selfdrived/events.py +++ b/selfdrive/selfdrived/events.py @@ -591,6 +591,11 @@ EVENTS: dict[int, dict[str, Alert | AlertCallbackType]] = { ET.NO_ENTRY: NoEntryAlert("Distraction Level Too High"), }, + EventName.excessiveActuation: { + ET.SOFT_DISABLE: soft_disable_alert("Excessive Actuation"), + ET.NO_ENTRY: NoEntryAlert("Excessive Actuation"), + }, + EventName.overheat: { ET.PERMANENT: overheat_alert, ET.SOFT_DISABLE: soft_disable_alert("System Overheated"), diff --git a/selfdrive/selfdrived/selfdrived.py b/selfdrive/selfdrived/selfdrived.py index 07914f90da..e203270579 100755 --- a/selfdrive/selfdrived/selfdrived.py +++ b/selfdrive/selfdrived/selfdrived.py @@ -7,6 +7,7 @@ import cereal.messaging as messaging from cereal import car, log, custom from msgq.visionipc import VisionIpcClient, VisionStreamType +from opendbc.car.interfaces import ACCEL_MIN, ACCEL_MAX from openpilot.common.params import Params @@ -15,6 +16,7 @@ from openpilot.common.swaglog import cloudlog from openpilot.common.gps import get_gps_location_service from openpilot.selfdrive.car.car_specific import CarSpecificEvents +from openpilot.selfdrive.locationd.helpers import PoseCalibrator, Pose from openpilot.selfdrive.selfdrived.events import Events, ET from openpilot.selfdrive.selfdrived.state import StateMachine from openpilot.selfdrive.selfdrived.alertmanager import AlertManager, set_offroad_alert @@ -30,7 +32,9 @@ from openpilot.sunnypilot.selfdrive.selfdrived.events import EventsSP REPLAY = "REPLAY" in os.environ SIMULATION = "SIMULATION" in os.environ TESTING_CLOSET = "TESTING_CLOSET" in os.environ + LONGITUDINAL_PERSONALITY_MAP = {v: k for k, v in log.LongitudinalPersonality.schema.enumerants.items()} +MIN_EXCESSIVE_ACTUATION_COUNT = int(0.25 / DT_CTRL) ThermalStatus = log.DeviceState.ThermalStatus State = log.SelfdriveState.OpenpilotState @@ -44,6 +48,21 @@ SafetyModel = car.CarParams.SafetyModel IGNORED_SAFETY_MODES = (SafetyModel.silent, SafetyModel.noOutput) +def check_excessive_actuation(sm: messaging.SubMaster, CS: car.CarState, calibrator: PoseCalibrator, counter: int) -> tuple[int, bool]: + # CS.aEgo can be noisy to bumps in the road, transitioning from standstill, losing traction, etc. + device_pose = Pose.from_live_pose(sm['livePose']) + calibrated_pose = calibrator.build_calibrated_pose(device_pose) + accel_calibrated = calibrated_pose.acceleration.x + + # livePose acceleration can be noisy due to bad mounting or aliased livePose measurements + accel_valid = abs(CS.aEgo - accel_calibrated) < 2 + + excessive_actuation = accel_calibrated > ACCEL_MAX * 2 or accel_calibrated < ACCEL_MIN * 2 + counter = counter + 1 if sm['carControl'].longActive and excessive_actuation and accel_valid else 0 + + return counter, counter > MIN_EXCESSIVE_ACTUATION_COUNT + + class SelfdriveD(CruiseHelper): def __init__(self, CP=None, CP_SP=None): self.params = Params() @@ -66,6 +85,7 @@ class SelfdriveD(CruiseHelper): self.CP_SP = CP_SP self.car_events = CarSpecificEvents(self.CP) + self.calibrator = PoseCalibrator() # Setup sockets self.pm = messaging.PubMaster(['selfdriveState', 'onroadEvents'] + ['selfdriveStateSP', 'onroadEventsSP']) @@ -121,8 +141,10 @@ class SelfdriveD(CruiseHelper): self.logged_comm_issue = None self.not_running_prev = None self.experimental_mode = False - self.personality = self.read_personality_param() + self.personality = self.params.get("LongitudinalPersonality", return_default=True) self.recalibrating_seen = False + self.excessive_actuation = self.params.get("Offroad_ExcessiveActuation") is not None + self.excessive_actuation_counter = 0 self.state_machine = StateMachine() self.rk = Ratekeeper(100, print_delay_threshold=None) @@ -254,6 +276,18 @@ class SelfdriveD(CruiseHelper): if self.sm['driverAssistance'].leftLaneDeparture or self.sm['driverAssistance'].rightLaneDeparture: self.events.add(EventName.ldw) + # Check for excessive (longitudinal) actuation + if self.sm.updated['liveCalibration']: + self.calibrator.feed_live_calib(self.sm['liveCalibration']) + + self.excessive_actuation_counter, excessive_actuation = check_excessive_actuation(self.sm, CS, self.calibrator, self.excessive_actuation_counter) + if not self.excessive_actuation and excessive_actuation: + set_offroad_alert("Offroad_ExcessiveActuation", True, extra_text="longitudinal") + self.excessive_actuation = True + + if self.excessive_actuation: + self.events.add(EventName.excessiveActuation) + # Handle lane change if self.sm['modelV2'].meta.laneChangeState == LaneChangeState.preLaneChange: direction = self.sm['modelV2'].meta.laneChangeDirection @@ -407,13 +441,13 @@ class SelfdriveD(CruiseHelper): if any(not be.pressed and be.type == ButtonType.gapAdjustCruise for be in CS.buttonEvents): if not self.experimental_mode_switched: self.personality = (self.personality - 1) % 3 - self.params.put_nonblocking('LongitudinalPersonality', str(self.personality)) + self.params.put_nonblocking('LongitudinalPersonality', self.personality) self.events.add(EventName.personalityChanged) self.experimental_mode_switched = False def data_sample(self): - car_state = messaging.recv_one(self.car_state_sock) - CS = car_state.carState if car_state else self.CS_prev + _car_state = messaging.recv_one(self.car_state_sock) + CS = _car_state.carState if _car_state else self.CS_prev self.sm.update(0) @@ -538,19 +572,13 @@ class SelfdriveD(CruiseHelper): self.CS_prev = CS - def read_personality_param(self): - try: - return int(self.params.get('LongitudinalPersonality')) - except (ValueError, TypeError): - return log.LongitudinalPersonality.standard - def params_thread(self, evt): while not evt.is_set(): self.is_metric = self.params.get_bool("IsMetric") self.is_ldw_enabled = self.params.get_bool("IsLdwEnabled") self.disengage_on_accelerator = self.params.get_bool("DisengageOnAccelerator") self.experimental_mode = self.params.get_bool("ExperimentalMode") and self.CP.openpilotLongitudinalControl - self.personality = self.read_personality_param() + self.personality = self.params.get("LongitudinalPersonality", return_default=True) self.mads.read_params() time.sleep(0.1) diff --git a/selfdrive/selfdrived/tests/test_alerts.py b/selfdrive/selfdrived/tests/test_alerts.py index 75365b7a52..a1867f2289 100644 --- a/selfdrive/selfdrived/tests/test_alerts.py +++ b/selfdrive/selfdrived/tests/test_alerts.py @@ -111,7 +111,7 @@ class TestAlerts: alert = copy.copy(self.offroad_alerts[a]) set_offroad_alert(a, True) alert['extra'] = '' - assert json.dumps(alert) == params.get(a, encoding='utf8') + assert alert == params.get(a) # then delete it set_offroad_alert(a, False) @@ -125,6 +125,6 @@ class TestAlerts: alert = self.offroad_alerts[a] set_offroad_alert(a, True, extra_text="a"*i) - written_alert = json.loads(params.get(a, encoding='utf8')) + written_alert = params.get(a) assert "a"*i == written_alert['extra'] assert alert["text"] == written_alert['text'] diff --git a/selfdrive/test/process_replay/ref_commit b/selfdrive/test/process_replay/ref_commit index 79c03c65a8..92669bec5c 100644 --- a/selfdrive/test/process_replay/ref_commit +++ b/selfdrive/test/process_replay/ref_commit @@ -1 +1 @@ -de16c6fbe14e121c5e74cd944ce03a0e4672540d \ No newline at end of file +c289a0359d1b1f26cf4d9e73a2c04b2bbfec840f \ No newline at end of file diff --git a/selfdrive/test/test_onroad.py b/selfdrive/test/test_onroad.py index f98e3bd88c..cd702377e7 100644 --- a/selfdrive/test/test_onroad.py +++ b/selfdrive/test/test_onroad.py @@ -147,7 +147,7 @@ class TestOnroad: while not sm.seen['carState']: sm.update(1000) - route = params.get("CurrentRoute", encoding="utf-8") + route = params.get("CurrentRoute") assert route is not None segs = list(Path(Paths.log_root()).glob(f"{route}--*")) diff --git a/selfdrive/test/test_updated.py b/selfdrive/test/test_updated.py index ea945d94c2..95365640f5 100644 --- a/selfdrive/test/test_updated.py +++ b/selfdrive/test/test_updated.py @@ -105,7 +105,7 @@ class TestUpdated: ret = None start_time = time.monotonic() while ret is None: - ret = self.params.get(key, encoding='utf8') + ret = self.params.get(key) if time.monotonic() - start_time > timeout: break time.sleep(0.01) @@ -162,8 +162,7 @@ class TestUpdated: def _check_update_state(self, update_available): # make sure LastUpdateTime is recent - t = self._read_param("LastUpdateTime") - last_update_time = datetime.datetime.fromisoformat(t) + last_update_time = self._read_param("LastUpdateTime") td = datetime.datetime.now(datetime.UTC).replace(tzinfo=None) - last_update_time assert td.total_seconds() < 10 self.params.remove("LastUpdateTime") @@ -174,7 +173,7 @@ class TestUpdated: # check params update = self._read_param("UpdateAvailable") assert update == "1" == update_available, f"UpdateAvailable: {repr(update)}" - assert self._read_param("UpdateFailedCount") == "0" + assert self._read_param("UpdateFailedCount") == 0 # TODO: check that the finalized update actually matches remote # check the .overlay_init and .overlay_consistent flags diff --git a/selfdrive/ui/SConscript b/selfdrive/ui/SConscript index d883ca5b15..5cff91b447 100644 --- a/selfdrive/ui/SConscript +++ b/selfdrive/ui/SConscript @@ -72,14 +72,10 @@ if GetOption('extras'): qt_env.SharedLibrary("qt/python_helpers", ["qt/qt_window.cc"], LIBS=qt_libs) - # setup and factory resetter - qt_env.Program("qt/setup/reset", ["qt/setup/reset.cc"], LIBS=qt_libs) + # setup qt_env.Program("qt/setup/setup", ["qt/setup/setup.cc", asset_obj], LIBS=qt_libs + ['curl', 'common']) - # build updater UI - qt_env.Program("qt/setup/updater", ["qt/setup/updater.cc", asset_obj], LIBS=qt_libs) - if arch != "Darwin": # build installers raylib_env = env.Clone() diff --git a/selfdrive/ui/layouts/home.py b/selfdrive/ui/layouts/home.py index 0fa91da552..f102481c3a 100644 --- a/selfdrive/ui/layouts/home.py +++ b/selfdrive/ui/layouts/home.py @@ -9,7 +9,7 @@ from openpilot.selfdrive.ui.widgets.prime import PrimeWidget from openpilot.selfdrive.ui.widgets.setup import SetupWidget from openpilot.system.ui.lib.text_measure import measure_text_cached from openpilot.system.ui.lib.application import gui_app, FontWeight, DEFAULT_TEXT_COLOR -from openpilot.system.ui.lib.widget import Widget +from openpilot.system.ui.widgets import Widget HEADER_HEIGHT = 80 HEAD_BUTTON_FONT_SIZE = 40 @@ -67,7 +67,7 @@ class HomeLayout(Widget): self.current_state = state def _render(self, rect: rl.Rectangle): - current_time = time.time() + current_time = time.monotonic() if current_time - self.last_refresh >= REFRESH_INTERVAL: self._refresh() self.last_refresh = current_time @@ -210,5 +210,5 @@ class HomeLayout(Widget): def _get_version_text(self) -> str: brand = "openpilot" - description = self.params.get("UpdaterCurrentDescription", encoding='utf-8') + description = self.params.get("UpdaterCurrentDescription") return f"{brand} {description}" if description else brand diff --git a/selfdrive/ui/layouts/main.py b/selfdrive/ui/layouts/main.py index a3081143f4..144d34e02f 100644 --- a/selfdrive/ui/layouts/main.py +++ b/selfdrive/ui/layouts/main.py @@ -4,9 +4,9 @@ import cereal.messaging as messaging from openpilot.selfdrive.ui.layouts.sidebar import Sidebar, SIDEBAR_WIDTH from openpilot.selfdrive.ui.layouts.home import HomeLayout from openpilot.selfdrive.ui.layouts.settings.settings import SettingsLayout, PanelType -from openpilot.selfdrive.ui.ui_state import device, ui_state from openpilot.selfdrive.ui.onroad.augmented_road_view import AugmentedRoadView -from openpilot.system.ui.lib.widget import Widget +from openpilot.selfdrive.ui.ui_state import device, ui_state +from openpilot.system.ui.widgets import Widget class MainState(IntEnum): diff --git a/selfdrive/ui/layouts/network.py b/selfdrive/ui/layouts/network.py index c227facd04..856be26e97 100644 --- a/selfdrive/ui/layouts/network.py +++ b/selfdrive/ui/layouts/network.py @@ -1,6 +1,6 @@ import pyray as rl -from openpilot.system.ui.lib.widget import Widget from openpilot.system.ui.lib.wifi_manager import WifiManagerWrapper +from openpilot.system.ui.widgets import Widget from openpilot.system.ui.widgets.network import WifiManagerUI diff --git a/selfdrive/ui/layouts/settings/developer.py b/selfdrive/ui/layouts/settings/developer.py index ce6e9e4af6..cfef0f84d1 100644 --- a/selfdrive/ui/layouts/settings/developer.py +++ b/selfdrive/ui/layouts/settings/developer.py @@ -1,8 +1,8 @@ -from openpilot.system.ui.lib.list_view import toggle_item -from openpilot.system.ui.lib.scroller import Scroller -from openpilot.system.ui.lib.widget import Widget from openpilot.common.params import Params from openpilot.selfdrive.ui.widgets.ssh_key import ssh_key_item +from openpilot.system.ui.widgets import Widget +from openpilot.system.ui.widgets.list_view import toggle_item +from openpilot.system.ui.widgets.scroller import Scroller # Description constants DESCRIPTIONS = { diff --git a/selfdrive/ui/layouts/settings/device.py b/selfdrive/ui/layouts/settings/device.py index 69b7822ba9..df8bba030c 100644 --- a/selfdrive/ui/layouts/settings/device.py +++ b/selfdrive/ui/layouts/settings/device.py @@ -5,15 +5,15 @@ from openpilot.common.basedir import BASEDIR from openpilot.common.params import Params from openpilot.selfdrive.ui.onroad.driver_camera_dialog import DriverCameraDialog from openpilot.selfdrive.ui.ui_state import ui_state +from openpilot.selfdrive.ui.widgets.pairing_dialog import PairingDialog from openpilot.system.hardware import TICI from openpilot.system.ui.lib.application import gui_app -from openpilot.system.ui.lib.list_view import text_item, button_item, dual_button_item -from openpilot.system.ui.lib.scroller import Scroller -from openpilot.system.ui.lib.widget import Widget, DialogResult -from openpilot.selfdrive.ui.widgets.pairing_dialog import PairingDialog -from openpilot.system.ui.widgets.option_dialog import MultiOptionDialog +from openpilot.system.ui.widgets import Widget, DialogResult from openpilot.system.ui.widgets.confirm_dialog import confirm_dialog, alert_dialog from openpilot.system.ui.widgets.html_render import HtmlRenderer +from openpilot.system.ui.widgets.list_view import text_item, button_item, dual_button_item +from openpilot.system.ui.widgets.option_dialog import MultiOptionDialog +from openpilot.system.ui.widgets.scroller import Scroller # Description constants DESCRIPTIONS = { @@ -41,7 +41,7 @@ class DeviceLayout(Widget): self._scroller = Scroller(items, line_separator=True, spacing=0) def _initialize_items(self): - dongle_id = self._params.get("DongleId", encoding="utf-8") or "N/A" + dongle_id = self._params.get("DongleId") or "N/A" serial = self._params.get("HardwareSerial") or "N/A" items = [ diff --git a/selfdrive/ui/layouts/settings/firehose.py b/selfdrive/ui/layouts/settings/firehose.py index 298f66e276..74a8f317d5 100644 --- a/selfdrive/ui/layouts/settings/firehose.py +++ b/selfdrive/ui/layouts/settings/firehose.py @@ -1,17 +1,16 @@ import pyray as rl -import json import time import threading from openpilot.common.api import Api, api_get from openpilot.common.params import Params from openpilot.common.swaglog import cloudlog +from openpilot.selfdrive.ui.ui_state import ui_state from openpilot.system.athena.registration import UNREGISTERED_DONGLE_ID from openpilot.system.ui.lib.application import gui_app, FontWeight -from openpilot.system.ui.lib.wrap_text import wrap_text from openpilot.system.ui.lib.scroll_panel import GuiScrollPanel -from openpilot.system.ui.lib.widget import Widget -from openpilot.selfdrive.ui.ui_state import ui_state +from openpilot.system.ui.lib.wrap_text import wrap_text +from openpilot.system.ui.widgets import Widget TITLE = "Firehose Mode" @@ -51,11 +50,11 @@ class FirehoseLayout(Widget): self.last_update_time = 0 def _get_segment_count(self) -> int: - stats = self.params.get(self.PARAM_KEY, encoding='utf8') + stats = self.params.get(self.PARAM_KEY) if not stats: return 0 try: - return int(json.loads(stats).get("firehose", 0)) + return int(stats.get("firehose", 0)) except Exception: cloudlog.exception(f"Failed to decode firehose stats: {stats}") return 0 @@ -161,7 +160,7 @@ class FirehoseLayout(Widget): def _fetch_firehose_stats(self): try: - dongle_id = self.params.get("DongleId", encoding='utf8') + dongle_id = self.params.get("DongleId") if not dongle_id or dongle_id == UNREGISTERED_DONGLE_ID: return identity_token = Api(dongle_id).get_token() @@ -169,7 +168,7 @@ class FirehoseLayout(Widget): if response.status_code == 200: data = response.json() self.segment_count = data.get("firehose", 0) - self.params.put(self.PARAM_KEY, json.dumps(data)) + self.params.put(self.PARAM_KEY, data) except Exception as e: cloudlog.error(f"Failed to fetch firehose stats: {e}") diff --git a/selfdrive/ui/layouts/settings/settings.py b/selfdrive/ui/layouts/settings/settings.py index d4dc420b7f..a322f21e80 100644 --- a/selfdrive/ui/layouts/settings/settings.py +++ b/selfdrive/ui/layouts/settings/settings.py @@ -2,6 +2,7 @@ import pyray as rl from dataclasses import dataclass from enum import IntEnum from collections.abc import Callable +from openpilot.selfdrive.ui.layouts.network import NetworkLayout from openpilot.selfdrive.ui.layouts.settings.developer import DeveloperLayout from openpilot.selfdrive.ui.layouts.settings.device import DeviceLayout from openpilot.selfdrive.ui.layouts.settings.firehose import FirehoseLayout @@ -9,12 +10,12 @@ from openpilot.selfdrive.ui.layouts.settings.software import SoftwareLayout from openpilot.selfdrive.ui.layouts.settings.toggles import TogglesLayout from openpilot.system.ui.lib.application import gui_app, FontWeight, MousePos from openpilot.system.ui.lib.text_measure import measure_text_cached -from openpilot.selfdrive.ui.layouts.network import NetworkLayout -from openpilot.system.ui.lib.widget import Widget +from openpilot.system.ui.widgets import Widget -# Import individual panels +# Settings close button +SETTINGS_CLOSE_TEXT = "×" +SETTINGS_CLOSE_TEXT_Y_OFFSET = 8 # The '×' character isn't quite vertically centered in the font so we need to offset it a bit to fully center it -SETTINGS_CLOSE_TEXT = "X" # Constants SIDEBAR_WIDTH = 500 CLOSE_BTN_SIZE = 200 @@ -62,7 +63,6 @@ class SettingsLayout(Widget): } self._font_medium = gui_app.font(FontWeight.MEDIUM) - self._font_bold = gui_app.font(FontWeight.SEMI_BOLD) # Callbacks self._close_callback: Callable | None = None @@ -84,7 +84,7 @@ class SettingsLayout(Widget): # Close button close_btn_rect = rl.Rectangle( - rect.x + (rect.width - CLOSE_BTN_SIZE) / 2, rect.y + 45, CLOSE_BTN_SIZE, CLOSE_BTN_SIZE + rect.x + (rect.width - CLOSE_BTN_SIZE) / 2, rect.y + 60, CLOSE_BTN_SIZE, CLOSE_BTN_SIZE ) pressed = (rl.is_mouse_button_down(rl.MouseButton.MOUSE_BUTTON_LEFT) and @@ -92,12 +92,12 @@ class SettingsLayout(Widget): close_color = CLOSE_BTN_PRESSED if pressed else CLOSE_BTN_COLOR rl.draw_rectangle_rounded(close_btn_rect, 1.0, 20, close_color) - close_text_size = measure_text_cached(self._font_bold, SETTINGS_CLOSE_TEXT, 140) + close_text_size = measure_text_cached(self._font_medium, SETTINGS_CLOSE_TEXT, 140) close_text_pos = rl.Vector2( close_btn_rect.x + (close_btn_rect.width - close_text_size.x) / 2, - close_btn_rect.y + (close_btn_rect.height - close_text_size.y) / 2, + close_btn_rect.y + (close_btn_rect.height - close_text_size.y) / 2 - SETTINGS_CLOSE_TEXT_Y_OFFSET, ) - rl.draw_text_ex(self._font_bold, SETTINGS_CLOSE_TEXT, close_text_pos, 140, 0, TEXT_SELECTED) + rl.draw_text_ex(self._font_medium, SETTINGS_CLOSE_TEXT, close_text_pos, 140, 0, TEXT_SELECTED) # Store close button rect for click detection self._close_btn_rect = close_btn_rect diff --git a/selfdrive/ui/layouts/settings/software.py b/selfdrive/ui/layouts/settings/software.py index b97e306ff9..4361725a1b 100644 --- a/selfdrive/ui/layouts/settings/software.py +++ b/selfdrive/ui/layouts/settings/software.py @@ -1,9 +1,9 @@ from openpilot.common.params import Params from openpilot.system.ui.lib.application import gui_app -from openpilot.system.ui.lib.list_view import button_item, text_item -from openpilot.system.ui.lib.scroller import Scroller -from openpilot.system.ui.lib.widget import Widget, DialogResult +from openpilot.system.ui.widgets import Widget, DialogResult from openpilot.system.ui.widgets.confirm_dialog import confirm_dialog +from openpilot.system.ui.widgets.list_view import button_item, text_item +from openpilot.system.ui.widgets.scroller import Scroller class SoftwareLayout(Widget): diff --git a/selfdrive/ui/layouts/settings/toggles.py b/selfdrive/ui/layouts/settings/toggles.py index 7374d0f2ae..58afcec5ef 100644 --- a/selfdrive/ui/layouts/settings/toggles.py +++ b/selfdrive/ui/layouts/settings/toggles.py @@ -1,7 +1,7 @@ -from openpilot.system.ui.lib.list_view import multiple_button_item, toggle_item -from openpilot.system.ui.lib.scroller import Scroller -from openpilot.system.ui.lib.widget import Widget from openpilot.common.params import Params +from openpilot.system.ui.widgets import Widget +from openpilot.system.ui.widgets.list_view import multiple_button_item, toggle_item +from openpilot.system.ui.widgets.scroller import Scroller # Description constants DESCRIPTIONS = { @@ -54,7 +54,7 @@ class TogglesLayout(Widget): buttons=["Aggressive", "Standard", "Relaxed"], button_width=255, callback=self._set_longitudinal_personality, - selected_index=int(self._params.get("LongitudinalPersonality") or 0), + selected_index=self._params.get("LongitudinalPersonality", return_default=True), icon="speed_limit.png" ), toggle_item( @@ -82,7 +82,7 @@ class TogglesLayout(Widget): icon="microphone.png", ), toggle_item( - "Use Metric System", DESCRIPTIONS["IsMetric"], self._params.get_bool("IsMetric"), icon="monitoring.png" + "Use Metric System", DESCRIPTIONS["IsMetric"], self._params.get_bool("IsMetric"), icon="metric.png" ), ] @@ -92,4 +92,4 @@ class TogglesLayout(Widget): self._scroller.render(rect) def _set_longitudinal_personality(self, button_index: int): - self._params.put("LongitudinalPersonality", str(button_index)) + self._params.put("LongitudinalPersonality", button_index) diff --git a/selfdrive/ui/layouts/sidebar.py b/selfdrive/ui/layouts/sidebar.py index cb8c6d472e..82d499716d 100644 --- a/selfdrive/ui/layouts/sidebar.py +++ b/selfdrive/ui/layouts/sidebar.py @@ -6,12 +6,13 @@ from cereal import log from openpilot.selfdrive.ui.ui_state import ui_state from openpilot.system.ui.lib.application import gui_app, FontWeight, MousePos from openpilot.system.ui.lib.text_measure import measure_text_cached -from openpilot.system.ui.lib.widget import Widget +from openpilot.system.ui.widgets import Widget SIDEBAR_WIDTH = 300 METRIC_HEIGHT = 126 METRIC_WIDTH = 240 METRIC_MARGIN = 30 +FONT_SIZE = 35 SETTINGS_BTN = rl.Rectangle(50, 35, 200, 117) HOME_BTN = rl.Rectangle(60, 860, 180, 180) @@ -175,7 +176,7 @@ class Sidebar(Widget): # Network type text text_y = rect.y + 247 text_pos = rl.Vector2(rect.x + 58, text_y) - rl.draw_text_ex(self._font_regular, self._net_type, text_pos, 35, 0, Colors.WHITE) + rl.draw_text_ex(self._font_regular, self._net_type, text_pos, FONT_SIZE, 0, Colors.WHITE) def _draw_metrics(self, rect: rl.Rectangle): metrics = [(self._temp_status, 338), (self._panda_status, 496), (self._connect_status, 654)] @@ -194,11 +195,14 @@ class Sidebar(Widget): # Draw border rl.draw_rectangle_rounded_lines_ex(metric_rect, 0.15, 10, 2, Colors.METRIC_BORDER) - # Draw text - text = f"{metric.label}\n{metric.value}" - text_size = measure_text_cached(self._font_bold, text, 35) - text_pos = rl.Vector2( - metric_rect.x + 22 + (metric_rect.width - 22 - text_size.x) / 2, - metric_rect.y + (metric_rect.height - text_size.y) / 2 - ) - rl.draw_text_ex(self._font_bold, text, text_pos, 35, 0, Colors.WHITE) + # Draw label and value + labels = [metric.label, metric.value] + text_y = metric_rect.y + (metric_rect.height / 2 - len(labels) * FONT_SIZE) + for text in labels: + text_size = measure_text_cached(self._font_bold, text, FONT_SIZE) + text_y += text_size.y + text_pos = rl.Vector2( + metric_rect.x + 22 + (metric_rect.width - 22 - text_size.x) / 2, + text_y + ) + rl.draw_text_ex(self._font_bold, text, text_pos, FONT_SIZE, 0, Colors.WHITE) diff --git a/selfdrive/ui/lib/prime_state.py b/selfdrive/ui/lib/prime_state.py index 6b87540f65..b6c0d88469 100644 --- a/selfdrive/ui/lib/prime_state.py +++ b/selfdrive/ui/lib/prime_state.py @@ -35,7 +35,7 @@ class PrimeState: self.start() def _load_initial_state(self) -> PrimeType: - prime_type_str = os.getenv("PRIME_TYPE") or self._params.get("PrimeType", encoding='utf8') + prime_type_str = os.getenv("PRIME_TYPE") or self._params.get("PrimeType") try: if prime_type_str is not None: return PrimeType(int(prime_type_str)) @@ -44,7 +44,7 @@ class PrimeState: return PrimeType.UNKNOWN def _fetch_prime_status(self) -> None: - dongle_id = self._params.get("DongleId", encoding='utf8') + dongle_id = self._params.get("DongleId") if not dongle_id or dongle_id == UNREGISTERED_DONGLE_ID: return @@ -63,7 +63,7 @@ class PrimeState: with self._lock: if prime_type != self.prime_type: self.prime_type = prime_type - self._params.put("PrimeType", str(int(prime_type))) + self._params.put("PrimeType", int(prime_type)) cloudlog.info(f"Prime type updated to {prime_type}") def _worker_thread(self) -> None: diff --git a/selfdrive/ui/onroad/alert_renderer.py b/selfdrive/ui/onroad/alert_renderer.py index 7a17291bbe..e8817f24b4 100644 --- a/selfdrive/ui/onroad/alert_renderer.py +++ b/selfdrive/ui/onroad/alert_renderer.py @@ -2,12 +2,15 @@ import time import pyray as rl from dataclasses import dataclass from cereal import messaging, log +from openpilot.selfdrive.ui.ui_state import ui_state from openpilot.system.hardware import TICI from openpilot.system.ui.lib.application import gui_app, FontWeight, DEFAULT_FPS -from openpilot.system.ui.lib.label import gui_text_box from openpilot.system.ui.lib.text_measure import measure_text_cached -from openpilot.system.ui.lib.widget import Widget -from openpilot.selfdrive.ui.ui_state import ui_state +from openpilot.system.ui.widgets import Widget +from openpilot.system.ui.widgets.label import gui_text_box + +AlertSize = log.SelfdriveState.AlertSize +AlertStatus = log.SelfdriveState.AlertStatus ALERT_MARGIN = 40 ALERT_PADDING = 60 @@ -23,9 +26,9 @@ SELFDRIVE_UNRESPONSIVE_TIMEOUT = 10 # Seconds # Constants ALERT_COLORS = { - log.SelfdriveState.AlertStatus.normal: rl.Color(0, 0, 0, 235), # Black - log.SelfdriveState.AlertStatus.userPrompt: rl.Color(0xFE, 0x8C, 0x34, 235), # Orange - log.SelfdriveState.AlertStatus.critical: rl.Color(0xC9, 0x22, 0x31, 235), # Red + AlertStatus.normal: rl.Color(0, 0, 0, 235), # Black + AlertStatus.userPrompt: rl.Color(0xFE, 0x8C, 0x34, 235), # Orange + AlertStatus.critical: rl.Color(0xC9, 0x22, 0x31, 235), # Red } @@ -41,22 +44,22 @@ class Alert: ALERT_STARTUP_PENDING = Alert( text1="openpilot Unavailable", text2="Waiting to start", - size=log.SelfdriveState.AlertSize.mid, - status=log.SelfdriveState.AlertStatus.normal, + size=AlertSize.mid, + status=AlertStatus.normal, ) ALERT_CRITICAL_TIMEOUT = Alert( text1="TAKE CONTROL IMMEDIATELY", text2="System Unresponsive", - size=log.SelfdriveState.AlertSize.full, - status=log.SelfdriveState.AlertStatus.critical, + size=AlertSize.full, + status=AlertStatus.critical, ) ALERT_CRITICAL_REBOOT = Alert( text1="System Unresponsive", text2="Reboot Device", - size=log.SelfdriveState.AlertSize.full, - status=log.SelfdriveState.AlertStatus.critical, + size=AlertSize.full, + status=AlertStatus.critical, ) @@ -93,7 +96,7 @@ class AlertRenderer(Widget): return None # Return current alert - return Alert(text1=ss.alertText1, text2=ss.alertText2, size=ss.alertSize, status=ss.alertStatus) + return Alert(text1=ss.alertText1, text2=ss.alertText2, size=ss.alertSize.raw, status=ss.alertStatus.raw) def _render(self, rect: rl.Rectangle) -> bool: alert = self.get_alert(ui_state.sm) @@ -113,10 +116,10 @@ class AlertRenderer(Widget): return True def _get_alert_rect(self, rect: rl.Rectangle, size: int) -> rl.Rectangle: - if size == log.SelfdriveState.AlertSize.full: + if size == AlertSize.full: return rect - height = (ALERT_FONT_MEDIUM + 2 * ALERT_PADDING if size == log.SelfdriveState.AlertSize.small else + height = (ALERT_FONT_MEDIUM + 2 * ALERT_PADDING if size == AlertSize.small else ALERT_FONT_BIG + ALERT_LINE_SPACING + ALERT_FONT_SMALL + 2 * ALERT_PADDING) return rl.Rectangle( @@ -127,19 +130,19 @@ class AlertRenderer(Widget): ) def _draw_background(self, rect: rl.Rectangle, alert: Alert) -> None: - color = ALERT_COLORS.get(alert.status, ALERT_COLORS[log.SelfdriveState.AlertStatus.normal]) + color = ALERT_COLORS.get(alert.status, ALERT_COLORS[AlertStatus.normal]) - if alert.size != log.SelfdriveState.AlertSize.full: + if alert.size != AlertSize.full: roundness = ALERT_BORDER_RADIUS / (min(rect.width, rect.height) / 2) rl.draw_rectangle_rounded(rect, roundness, 10, color) else: rl.draw_rectangle_rec(rect, color) def _draw_text(self, rect: rl.Rectangle, alert: Alert) -> None: - if alert.size == log.SelfdriveState.AlertSize.small: + if alert.size == AlertSize.small: self._draw_centered(alert.text1, rect, self.font_bold, ALERT_FONT_MEDIUM) - elif alert.size == log.SelfdriveState.AlertSize.mid: + elif alert.size == AlertSize.mid: self._draw_centered(alert.text1, rect, self.font_bold, ALERT_FONT_BIG, center_y=False) rect.y += ALERT_FONT_BIG + ALERT_LINE_SPACING self._draw_centered(alert.text2, rect, self.font_regular, ALERT_FONT_SMALL, center_y=False) diff --git a/selfdrive/ui/onroad/cameraview.py b/selfdrive/ui/onroad/cameraview.py index 33f1961d2b..cc2c6b4fe7 100644 --- a/selfdrive/ui/onroad/cameraview.py +++ b/selfdrive/ui/onroad/cameraview.py @@ -2,12 +2,12 @@ import platform import numpy as np import pyray as rl -from openpilot.system.hardware import TICI from msgq.visionipc import VisionIpcClient, VisionStreamType, VisionBuf from openpilot.common.swaglog import cloudlog +from openpilot.system.hardware import TICI from openpilot.system.ui.lib.application import gui_app from openpilot.system.ui.lib.egl import init_egl, create_egl_image, destroy_egl_image, bind_egl_image_to_texture, EGLImage -from openpilot.system.ui.lib.widget import Widget +from openpilot.system.ui.widgets import Widget CONNECTION_RETRY_INTERVAL = 0.2 # seconds between connection attempts @@ -179,6 +179,9 @@ class CameraView(Widget): transform = self._calc_frame_matrix(rect) src_rect = rl.Rectangle(0, 0, float(self.frame.width), float(self.frame.height)) + # Flip driver camera horizontally + if self._stream_type == VisionStreamType.VISION_STREAM_DRIVER: + src_rect.width = -src_rect.width # Calculate scale scale_x = rect.width * transform[0, 0] # zx diff --git a/selfdrive/ui/onroad/driver_camera_dialog.py b/selfdrive/ui/onroad/driver_camera_dialog.py index 40c72f292b..c8b4e62030 100644 --- a/selfdrive/ui/onroad/driver_camera_dialog.py +++ b/selfdrive/ui/onroad/driver_camera_dialog.py @@ -5,7 +5,7 @@ from openpilot.selfdrive.ui.onroad.cameraview import CameraView from openpilot.selfdrive.ui.onroad.driver_state import DriverStateRenderer from openpilot.selfdrive.ui.ui_state import ui_state from openpilot.system.ui.lib.application import gui_app, FontWeight -from openpilot.system.ui.lib.label import gui_label +from openpilot.system.ui.widgets.label import gui_label class DriverCameraDialog(CameraView): diff --git a/selfdrive/ui/onroad/driver_state.py b/selfdrive/ui/onroad/driver_state.py index 8d5fb951d0..a25d9bd316 100644 --- a/selfdrive/ui/onroad/driver_state.py +++ b/selfdrive/ui/onroad/driver_state.py @@ -3,7 +3,7 @@ import pyray as rl from dataclasses import dataclass from openpilot.selfdrive.ui.ui_state import ui_state, UI_BORDER_SIZE from openpilot.system.ui.lib.application import gui_app -from openpilot.system.ui.lib.widget import Widget +from openpilot.system.ui.widgets import Widget # Default 3D coordinates for face keypoints as a NumPy array DEFAULT_FACE_KPTS_3D = np.array([ diff --git a/selfdrive/ui/onroad/exp_button.py b/selfdrive/ui/onroad/exp_button.py index 8c835090d0..e6748e4e09 100644 --- a/selfdrive/ui/onroad/exp_button.py +++ b/selfdrive/ui/onroad/exp_button.py @@ -1,9 +1,9 @@ import time import pyray as rl +from openpilot.common.params import Params from openpilot.selfdrive.ui.ui_state import ui_state from openpilot.system.ui.lib.application import gui_app -from openpilot.system.ui.lib.widget import Widget -from openpilot.common.params import Params +from openpilot.system.ui.widgets import Widget class ExpButton(Widget): @@ -41,7 +41,7 @@ class ExpButton(Widget): # Hold new state temporarily self._held_mode = new_mode - self._hold_end_time = time.time() + self._hold_duration + self._hold_end_time = time.monotonic() + self._hold_duration return True return False @@ -58,7 +58,7 @@ class ExpButton(Widget): rl.draw_texture(texture, center_x - texture.width // 2, center_y - texture.height // 2, self._white_color) def _held_or_actual_mode(self): - now = time.time() + now = time.monotonic() if self._hold_end_time and now < self._hold_end_time: return self._held_mode diff --git a/selfdrive/ui/onroad/hud_renderer.py b/selfdrive/ui/onroad/hud_renderer.py index da292d38d5..a74d309e02 100644 --- a/selfdrive/ui/onroad/hud_renderer.py +++ b/selfdrive/ui/onroad/hud_renderer.py @@ -1,11 +1,11 @@ import pyray as rl from dataclasses import dataclass -from openpilot.selfdrive.ui.ui_state import ui_state, UIStatus +from openpilot.common.conversions import Conversions as CV from openpilot.selfdrive.ui.onroad.exp_button import ExpButton +from openpilot.selfdrive.ui.ui_state import ui_state, UIStatus from openpilot.system.ui.lib.application import gui_app, FontWeight from openpilot.system.ui.lib.text_measure import measure_text_cached -from openpilot.common.conversions import Conversions as CV -from openpilot.system.ui.lib.widget import Widget +from openpilot.system.ui.widgets import Widget # Constants SET_SPEED_NA = 255 diff --git a/selfdrive/ui/onroad/model_renderer.py b/selfdrive/ui/onroad/model_renderer.py index ab2b7aaefb..4439141a40 100644 --- a/selfdrive/ui/onroad/model_renderer.py +++ b/selfdrive/ui/onroad/model_renderer.py @@ -4,11 +4,11 @@ import pyray as rl from cereal import messaging, car from dataclasses import dataclass, field from openpilot.common.params import Params +from openpilot.selfdrive.locationd.calibrationd import HEIGHT_INIT from openpilot.selfdrive.ui.ui_state import ui_state from openpilot.system.ui.lib.application import DEFAULT_FPS from openpilot.system.ui.lib.shader_polygon import draw_polygon -from openpilot.system.ui.lib.widget import Widget -from openpilot.selfdrive.locationd.calibrationd import HEIGHT_INIT +from openpilot.system.ui.widgets import Widget CLIP_MARGIN = 500 MIN_DRAW_DISTANCE = 10.0 diff --git a/selfdrive/ui/qt/setup/reset.cc b/selfdrive/ui/qt/setup/reset.cc deleted file mode 100644 index 82fd5a7820..0000000000 --- a/selfdrive/ui/qt/setup/reset.cc +++ /dev/null @@ -1,141 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include "selfdrive/ui/qt/qt_window.h" -#include "selfdrive/ui/qt/setup/reset.h" - -#define NVME "/dev/nvme0n1" -#define USERDATA "/dev/disk/by-partlabel/userdata" - -void Reset::doErase() { - // best effort to wipe nvme - std::system("sudo umount " NVME); - std::system("yes | sudo mkfs.ext4 " NVME); - - int rm = std::system("sudo rm -rf /data/*"); - std::system("sudo umount " USERDATA); - int fmt = std::system("yes | sudo mkfs.ext4 " USERDATA); - - if (rm == 0 || fmt == 0) { - std::system("sudo reboot"); - } - body->setText(tr("Reset failed. Reboot to try again.")); - rebootBtn->show(); -} - -void Reset::startReset() { - body->setText(tr("Resetting device...\nThis may take up to a minute.")); - rejectBtn->hide(); - rebootBtn->hide(); - confirmBtn->hide(); -#ifdef __aarch64__ - QTimer::singleShot(100, this, &Reset::doErase); -#endif -} - -void Reset::confirm() { - const QString confirm_txt = tr("Are you sure you want to reset your device?"); - if (body->text() != confirm_txt) { - body->setText(confirm_txt); - } else { - startReset(); - } -} - -Reset::Reset(ResetMode mode, QWidget *parent) : QWidget(parent) { - QVBoxLayout *main_layout = new QVBoxLayout(this); - main_layout->setContentsMargins(45, 220, 45, 45); - main_layout->setSpacing(0); - - QLabel *title = new QLabel(tr("System Reset")); - title->setStyleSheet("font-size: 90px; font-weight: 600;"); - main_layout->addWidget(title, 0, Qt::AlignTop | Qt::AlignLeft); - - main_layout->addSpacing(60); - - body = new QLabel(tr("System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot.")); - body->setWordWrap(true); - body->setStyleSheet("font-size: 80px; font-weight: light;"); - main_layout->addWidget(body, 1, Qt::AlignTop | Qt::AlignLeft); - - QHBoxLayout *blayout = new QHBoxLayout(); - main_layout->addLayout(blayout); - blayout->setSpacing(50); - - rejectBtn = new QPushButton(tr("Cancel")); - blayout->addWidget(rejectBtn); - QObject::connect(rejectBtn, &QPushButton::clicked, QCoreApplication::instance(), &QCoreApplication::quit); - - rebootBtn = new QPushButton(tr("Reboot")); - blayout->addWidget(rebootBtn); -#ifdef __aarch64__ - QObject::connect(rebootBtn, &QPushButton::clicked, [=]{ - std::system("sudo reboot"); - }); -#endif - - confirmBtn = new QPushButton(tr("Confirm")); - confirmBtn->setStyleSheet(R"( - QPushButton { - background-color: #465BEA; - } - QPushButton:pressed { - background-color: #3049F4; - } - )"); - blayout->addWidget(confirmBtn); - QObject::connect(confirmBtn, &QPushButton::clicked, this, &Reset::confirm); - - bool recover = mode == ResetMode::RECOVER; - rejectBtn->setVisible(!recover); - rebootBtn->setVisible(recover); - if (recover) { - body->setText(tr("Unable to mount data partition. Partition may be corrupted. Press confirm to erase and reset your device.")); - } - - // automatically start if we're just finishing up an ABL reset - if (mode == ResetMode::FORMAT) { - startReset(); - } - - setStyleSheet(R"( - * { - font-family: Inter; - color: white; - background-color: black; - } - QLabel { - margin-left: 140; - } - QPushButton { - height: 160; - font-size: 55px; - font-weight: 400; - border-radius: 10px; - background-color: #333333; - } - QPushButton:pressed { - background-color: #444444; - } - )"); -} - -int main(int argc, char *argv[]) { - ResetMode mode = ResetMode::USER_RESET; - if (argc > 1) { - if (strcmp(argv[1], "--recover") == 0) { - mode = ResetMode::RECOVER; - } else if (strcmp(argv[1], "--format") == 0) { - mode = ResetMode::FORMAT; - } - } - - QApplication a(argc, argv); - Reset reset(mode); - setMainWindow(&reset); - return a.exec(); -} diff --git a/selfdrive/ui/qt/setup/reset.h b/selfdrive/ui/qt/setup/reset.h deleted file mode 100644 index 2e0784cdc9..0000000000 --- a/selfdrive/ui/qt/setup/reset.h +++ /dev/null @@ -1,27 +0,0 @@ -#include -#include -#include - -enum ResetMode { - USER_RESET, // user initiated a factory reset from openpilot - RECOVER, // userdata is corrupt for some reason, give a chance to recover - FORMAT, // finish up a factory reset from a tool that doesn't flash an empty partition to userdata -}; - -class Reset : public QWidget { - Q_OBJECT - -public: - explicit Reset(ResetMode mode, QWidget *parent = 0); - -private: - QLabel *body; - QPushButton *rejectBtn; - QPushButton *rebootBtn; - QPushButton *confirmBtn; - void doErase(); - void startReset(); - -private slots: - void confirm(); -}; diff --git a/selfdrive/ui/qt/setup/updater.cc b/selfdrive/ui/qt/setup/updater.cc deleted file mode 100644 index ed47590aa3..0000000000 --- a/selfdrive/ui/qt/setup/updater.cc +++ /dev/null @@ -1,186 +0,0 @@ -#include -#include -#include - -#include "system/hardware/hw.h" -#include "selfdrive/ui/qt/util.h" -#include "selfdrive/ui/qt/qt_window.h" -#include "selfdrive/ui/qt/setup/updater.h" -#include "selfdrive/ui/qt/network/networking.h" - -Updater::Updater(const QString &updater_path, const QString &manifest_path, QWidget *parent) - : updater(updater_path), manifest(manifest_path), QStackedWidget(parent) { - - assert(updater.size()); - assert(manifest.size()); - - // initial prompt screen - prompt = new QWidget; - { - QVBoxLayout *layout = new QVBoxLayout(prompt); - layout->setContentsMargins(100, 250, 100, 100); - - QLabel *title = new QLabel(tr("Update Required")); - title->setStyleSheet("font-size: 80px; font-weight: bold;"); - layout->addWidget(title); - - layout->addSpacing(75); - - QLabel *desc = new QLabel(tr("An operating system update is required. Connect your device to Wi-Fi for the fastest update experience. The download size is approximately 1GB.")); - desc->setWordWrap(true); - desc->setStyleSheet("font-size: 65px;"); - layout->addWidget(desc); - - layout->addStretch(); - - QHBoxLayout *hlayout = new QHBoxLayout; - hlayout->setSpacing(30); - layout->addLayout(hlayout); - - QPushButton *connect = new QPushButton(tr("Connect to Wi-Fi")); - connect->setObjectName("navBtn"); - QObject::connect(connect, &QPushButton::clicked, [=]() { - setCurrentWidget(wifi); - }); - hlayout->addWidget(connect); - - QPushButton *install = new QPushButton(tr("Install")); - install->setObjectName("navBtn"); - install->setStyleSheet(R"( - QPushButton { - background-color: #465BEA; - } - QPushButton:pressed { - background-color: #3049F4; - } - )"); - QObject::connect(install, &QPushButton::clicked, this, &Updater::installUpdate); - hlayout->addWidget(install); - } - - // wifi connection screen - wifi = new QWidget; - { - QVBoxLayout *layout = new QVBoxLayout(wifi); - layout->setContentsMargins(100, 100, 100, 100); - - Networking *networking = new Networking(this, false); - networking->setStyleSheet("Networking { background-color: #292929; border-radius: 13px; }"); - layout->addWidget(networking, 1); - - QPushButton *back = new QPushButton(tr("Back")); - back->setObjectName("navBtn"); - back->setStyleSheet("padding-left: 60px; padding-right: 60px;"); - QObject::connect(back, &QPushButton::clicked, [=]() { - setCurrentWidget(prompt); - }); - layout->addWidget(back, 0, Qt::AlignLeft); - } - - // progress screen - progress = new QWidget; - { - QVBoxLayout *layout = new QVBoxLayout(progress); - layout->setContentsMargins(150, 330, 150, 150); - layout->setSpacing(0); - - text = new QLabel(tr("Loading...")); - text->setStyleSheet("font-size: 90px; font-weight: 600;"); - layout->addWidget(text, 0, Qt::AlignTop); - - layout->addSpacing(100); - - bar = new QProgressBar(); - bar->setRange(0, 100); - bar->setTextVisible(false); - bar->setFixedHeight(72); - layout->addWidget(bar, 0, Qt::AlignTop); - - layout->addStretch(); - - reboot = new QPushButton(tr("Reboot")); - reboot->setObjectName("navBtn"); - reboot->setStyleSheet("padding-left: 60px; padding-right: 60px;"); - QObject::connect(reboot, &QPushButton::clicked, [=]() { - Hardware::reboot(); - }); - layout->addWidget(reboot, 0, Qt::AlignLeft); - reboot->hide(); - - layout->addStretch(); - } - - addWidget(prompt); - addWidget(wifi); - addWidget(progress); - - setStyleSheet(R"( - * { - color: white; - outline: none; - font-family: Inter; - } - Updater { - color: white; - background-color: black; - } - QPushButton#navBtn { - height: 160; - font-size: 55px; - font-weight: 400; - border-radius: 10px; - background-color: #333333; - } - QPushButton#navBtn:pressed { - background-color: #444444; - } - QProgressBar { - border: none; - background-color: #292929; - } - QProgressBar::chunk { - background-color: #364DEF; - } - )"); -} - -void Updater::installUpdate() { - setCurrentWidget(progress); - QObject::connect(&proc, &QProcess::readyReadStandardOutput, this, &Updater::readProgress); - QObject::connect(&proc, QOverload::of(&QProcess::finished), this, &Updater::updateFinished); - proc.setProcessChannelMode(QProcess::ForwardedErrorChannel); - proc.start(updater, {"--swap", manifest}); -} - -void Updater::readProgress() { - auto lines = QString(proc.readAllStandardOutput()); - for (const QString &line : lines.trimmed().split("\n")) { - auto parts = line.split(":"); - if (parts.size() == 2) { - text->setText(parts[0]); - bar->setValue((int)parts[1].toDouble()); - } else { - qDebug() << line; - } - } - update(); -} - -void Updater::updateFinished(int exitCode, QProcess::ExitStatus exitStatus) { - qDebug() << "finished with " << exitCode; - if (exitCode == 0) { - Hardware::reboot(); - } else { - text->setText(tr("Update failed")); - reboot->show(); - } -} - -int main(int argc, char *argv[]) { - initApp(argc, argv); - QApplication a(argc, argv); - Updater updater(argv[1], argv[2]); - setMainWindow(&updater); - a.installEventFilter(&updater); - return a.exec(); -} diff --git a/selfdrive/ui/qt/setup/updater.h b/selfdrive/ui/qt/setup/updater.h deleted file mode 100644 index ce46c0aabd..0000000000 --- a/selfdrive/ui/qt/setup/updater.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include -#include - -class Updater : public QStackedWidget { - Q_OBJECT - -public: - explicit Updater(const QString &updater_path, const QString &manifest_path, QWidget *parent = 0); - -private slots: - void installUpdate(); - void readProgress(); - void updateFinished(int exitCode, QProcess::ExitStatus exitStatus); - -private: - QProcess proc; - QString updater, manifest; - - QLabel *text; - QProgressBar *bar; - QPushButton *reboot; - QWidget *prompt, *wifi, *progress; -}; diff --git a/selfdrive/ui/qt/util.cc b/selfdrive/ui/qt/util.cc index dedc59f0e4..9af76e4aea 100644 --- a/selfdrive/ui/qt/util.cc +++ b/selfdrive/ui/qt/util.cc @@ -18,6 +18,7 @@ #include #include "common/swaglog.h" +#include "common/util.h" #include "system/hardware/hw.h" QString getVersion() { @@ -57,6 +58,10 @@ QMap getSupportedLanguages() { } QString timeAgo(const QDateTime &date) { + if (!util::system_time_valid()) { + return date.date().toString(); + } + int diff = date.secsTo(QDateTime::currentDateTimeUtc()); QString s; diff --git a/selfdrive/ui/qt/widgets/offroad_alerts.cc b/selfdrive/ui/qt/widgets/offroad_alerts.cc index f630875978..3a4828a2a8 100644 --- a/selfdrive/ui/qt/widgets/offroad_alerts.cc +++ b/selfdrive/ui/qt/widgets/offroad_alerts.cc @@ -32,15 +32,19 @@ AbstractAlert::AbstractAlert(bool hasRebootBtn, QWidget *parent) : QFrame(parent footer_layout->addWidget(dismiss_btn, 0, Qt::AlignBottom | Qt::AlignLeft); QObject::connect(dismiss_btn, &QPushButton::clicked, this, &AbstractAlert::dismiss); - snooze_btn = new QPushButton(tr("Snooze Update")); - snooze_btn->setVisible(false); - snooze_btn->setFixedSize(550, 125); - footer_layout->addWidget(snooze_btn, 0, Qt::AlignBottom | Qt::AlignRight); - QObject::connect(snooze_btn, &QPushButton::clicked, [=]() { - params.putBool("SnoozeUpdate", true); + action_btn = new QPushButton(); + action_btn->setVisible(false); + action_btn->setFixedHeight(125); + footer_layout->addWidget(action_btn, 0, Qt::AlignBottom | Qt::AlignRight); + QObject::connect(action_btn, &QPushButton::clicked, [=]() { + if (!alerts["Offroad_ExcessiveActuation"]->text().isEmpty()) { + params.remove("Offroad_ExcessiveActuation"); + } else { + params.putBool("SnoozeUpdate", true); + } }); - QObject::connect(snooze_btn, &QPushButton::clicked, this, &AbstractAlert::dismiss); - snooze_btn->setStyleSheet(R"(color: white; background-color: #4F4F4F;)"); + QObject::connect(action_btn, &QPushButton::clicked, this, &AbstractAlert::dismiss); + action_btn->setStyleSheet("color: white; background-color: #4F4F4F; padding-left: 60px; padding-right: 60px;"); if (hasRebootBtn) { QPushButton *rebootBtn = new QPushButton(tr("Reboot and Update")); @@ -107,7 +111,14 @@ int OffroadAlert::refresh() { label->setVisible(!text.isEmpty()); alertCount += !text.isEmpty(); } - snooze_btn->setVisible(!alerts["Offroad_ConnectivityNeeded"]->text().isEmpty()); + + action_btn->setVisible(!alerts["Offroad_ExcessiveActuation"]->text().isEmpty() || !alerts["Offroad_ConnectivityNeeded"]->text().isEmpty()); + if (!alerts["Offroad_ExcessiveActuation"]->text().isEmpty()) { + action_btn->setText(tr("Acknowledge Excessive Actuation")); + } else { + action_btn->setText(tr("Snooze Update")); + } + return alertCount; } diff --git a/selfdrive/ui/qt/widgets/offroad_alerts.h b/selfdrive/ui/qt/widgets/offroad_alerts.h index ace2e75456..2dcf4f9d8c 100644 --- a/selfdrive/ui/qt/widgets/offroad_alerts.h +++ b/selfdrive/ui/qt/widgets/offroad_alerts.h @@ -15,9 +15,10 @@ class AbstractAlert : public QFrame { protected: AbstractAlert(bool hasRebootBtn, QWidget *parent = nullptr); - QPushButton *snooze_btn; + QPushButton *action_btn; QVBoxLayout *scrollable_layout; Params params; + std::map alerts; signals: void dismiss(); @@ -40,7 +41,4 @@ class OffroadAlert : public AbstractAlert { public: explicit OffroadAlert(QWidget *parent = 0) : AbstractAlert(false, parent) {} int refresh(); - -private: - std::map alerts; }; diff --git a/selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.cc b/selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.cc index 23d4c4f87b..45a22d7e04 100644 --- a/selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.cc +++ b/selfdrive/ui/sunnypilot/qt/offroad/settings/models_panel.cc @@ -102,13 +102,13 @@ ModelsPanel::ModelsPanel(QWidget *parent) : QWidget(parent) { list->addItem(lagd_toggle_control); // Software delay control - delay_control = new OptionControlSP("LagdToggledelay", tr("Adjust Software Delay"), + delay_control = new OptionControlSP("LagdToggleDelay", tr("Adjust Software Delay"), tr("Adjust the software delay when Live Learning Steer Delay is toggled off." "\nThe default software delay value is 0.2"), "", {5, 30}, 1, false, nullptr, true, true); connect(delay_control, &OptionControlSP::updateLabels, [=]() { - float value = QString::fromStdString(params.get("LagdToggledelay")).toFloat(); + float value = QString::fromStdString(params.get("LagdToggleDelay")).toFloat(); delay_control->setLabel(QString::number(value, 'f', 2) + "s"); }); connect(lagd_toggle_control, &ParamControlSP::toggleFlipped, [=](bool state) { @@ -369,7 +369,7 @@ void ModelsPanel::updateLabels() { delay_control->setVisible(!params.getBool("LagdToggle")); if (delay_control->isVisible()) { - float value = QString::fromStdString(params.get("LagdToggledelay")).toFloat(); + float value = QString::fromStdString(params.get("LagdToggleDelay")).toFloat(); delay_control->setLabel(QString::number(value, 'f', 2) + "s"); } diff --git a/selfdrive/ui/tests/test_ui/run.py b/selfdrive/ui/tests/test_ui/run.py index b263e28297..33f33f98dd 100755 --- a/selfdrive/ui/tests/test_ui/run.py +++ b/selfdrive/ui/tests/test_ui/run.py @@ -408,9 +408,9 @@ def create_screenshots(): params.put("DongleId", "123456789012345") params.put("SunnylinkDongleId", "123456789012345") if name == 'prime': - params.put('PrimeType', '1') + params.put('PrimeType', 1) elif name == 'pair_device': - params.put('ApiCache_Device', '{"is_paired":0, "prime_type":-1}') + params.put('ApiCache_Device', {"is_paired":0, "prime_type":-1}) t.test_ui(name, setup) diff --git a/selfdrive/ui/translations/main_ar.ts b/selfdrive/ui/translations/main_ar.ts index 61eb36f4c3..7d3d9edd05 100644 --- a/selfdrive/ui/translations/main_ar.ts +++ b/selfdrive/ui/translations/main_ar.ts @@ -7,10 +7,6 @@ Close إغلاق - - Snooze Update - تأخير التحديث - Reboot and Update إعادة التشغيل والتحديث @@ -107,53 +103,6 @@ - - AutoLaneChangeTimer - - Auto Lane Change by Blinker - - - - Set a timer to delay the auto lane change operation when the blinker is used. No nudge on the steering wheel is required to auto lane change if a timer is set. Default is Nudge. -Please use caution when using this feature. Only use the blinker when traffic and road conditions permit. - - - - s - - - - Off - - - - Nudge - - - - Nudgeless - - - - - Brightness - - Brightness - - - - Overrides the brightness of the device. - - - - Auto (Dark) - - - - Auto - - - ConfirmationDialog @@ -168,8 +117,8 @@ Please use caution when using this feature. Only use the blinker when traffic an DeclinePage - You must accept the Terms and Conditions in order to use sunnypilot. - يجب عليك قبول الشروط والأحكام من أجل استخدام sunnypilot. + You must accept the Terms and Conditions in order to use openpilot. + يجب عليك قبول الشروط والأحكام من أجل استخدام openpilot. Back @@ -190,6 +139,18 @@ Please use caution when using this feature. Only use the blinker when traffic an Longitudinal Maneuver Mode وضع المناورة الطولية + + openpilot Longitudinal Control (Alpha) + التحكم الطولي openpilot (ألفا) + + + WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). + تحذير: التحكم الطولي في openpilot في المرحلة ألفا لهذه السيارة، وسيقوم بتعطيل مكابح الطوارئ الآلية (AEB). + + + On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. + في هذه السيارة يعمل openpilot افتراضياً بالشكل المدمج في التحكم التكيفي في السرعة بدلاً من التحكم الطولي. قم بتمكين هذا الخيار من أجل الانتقال إلى التحكم الطولي. يوصى بتمكين الوضع التجريبي عند استخدام وضع التحكم الطولي ألفا من openpilot. + Enable ADB تمكين ADB @@ -198,62 +159,6 @@ Please use caution when using this feature. Only use the blinker when traffic an ADB (Android Debug Bridge) allows connecting to your device over USB or over the network. See https://docs.comma.ai/how-to/connect-to-comma for more info. أداة ADB (Android Debug Bridge) تسمح بالاتصال بجهازك عبر USB أو عبر الشبكة. راجع هذا الرابط: https://docs.comma.ai/how-to/connect-to-comma لمزيد من المعلومات. - - openpilot Longitudinal Control (Alpha) - - - - WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). - - - - On this car, sunnypilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. - - - - - DeveloperPanelSP - - Show Advanced Controls - - - - Toggle visibility of advanced sunnypilot controls. -This only toggles the visibility of the controls; it does not toggle the actual control enabled/disabled state. - - - - Enable GitHub runner service - - - - Enables or disables the github runner service. - - - - Enable Quickboot Mode - - - - Error Log - - - - VIEW - عرض - - - View the error log for sunnypilot crashes. - - - - When toggled on, this creates a prebuilt file to allow accelerated boot times. When toggled off, it immediately removes the prebuilt file so compilation of locally edited cpp files can be made. <br><br><b>To edit C++ files locally on device, you MUST first turn off this toggle so the changes can recompile.</b> - - - - Quickboot mode requires updates to be disabled.<br>Enable 'Disable Updates' in the Software panel first. - - DevicePanel @@ -302,8 +207,8 @@ This only toggles the visibility of the controls; it does not toggle the actual مراجعة - Review the rules, features, and limitations of sunnypilot - مراجعة الأدوار والميزات والقيود في sunnypilot + Review the rules, features, and limitations of openpilot + مراجعة الأدوار والميزات والقيود في openpilot Are you sure you want to review the training guide? @@ -398,7 +303,11 @@ This only toggles the visibility of the controls; it does not toggle the actual - sunnypilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. + openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. + + + + openpilot is continuously calibrating, resetting is rarely required. Resetting calibration will restart openpilot if the car is powered on. @@ -421,149 +330,6 @@ Steering lag calibration is complete. Steering torque response calibration is complete. - - openpilot is continuously calibrating, resetting is rarely required. Resetting calibration will restart openpilot if the car is powered on. - - - - - DevicePanelSP - - Driver Camera Preview - - - - Training Guide - - - - Regulatory - التنظيمية - - - Language - - - - Are you sure you want to review the training guide? - هل أنت متأكد أنك تريد مراجعة دليل التدريب؟ - - - Review - مراجعة - - - Select a language - اختر لغة - - - Reboot - إعادة التشغيل - - - Power Off - إيقاف التشغيل - - - Offroad Mode - - - - Are you sure you want to exit Always Offroad mode? - - - - Confirm - تأكيد - - - Are you sure you want to enter Always Offroad mode? - - - - Disengage to Enter Always Offroad Mode - - - - Exit Always Offroad - - - - Always Offroad - - - - Quiet Mode - - - - Reset Settings - - - - Are you sure you want to reset all sunnypilot settings to default? Once the settings are reset, there is no going back. - - - - Reset - إعادة الضبط - - - The reset cannot be undone. You have been warned. - - - - Wake-Up Behavior - - - - Interactivity Timeout - - - - Apply a custom timeout for settings UI. -This is the time after which settings UI closes automatically if user is not interacting with the screen. - - - - ⁍ Default: Device will boot/wake-up normally & will be ready to engage. - - - - ⁍ Offroad: Device will be in Always Offroad mode after boot/wake-up. - - - - Controls state of the device after boot/sleep. - - - - - DriveStats - - Drives - - - - Hours - - - - ALL TIME - - - - PAST WEEK - - - - KM - - - - Miles - - DriverViewWindow @@ -572,21 +338,6 @@ This is the time after which settings UI closes automatically if user is not int بدء تشغيل الكاميرا - - ExitOffroadButton - - Are you sure you want to exit Always Offroad mode? - - - - Confirm - تأكيد - - - EXIT ALWAYS OFFROAD MODE - - - ExperimentalModeButton @@ -600,6 +351,14 @@ This is the time after which settings UI closes automatically if user is not int FirehosePanel + + openpilot learns to drive by watching humans, like you, drive. + +Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode. + يتعلم تطبيق openpilot كيفية القيادة من خلال مشاهدة البشر، مثلك، أثناء القيادة. + +يتيح لك وضع خرطوم الحريق زيادة تحميلات بيانات التدريب لتحسين نماذج القيادة في OpenPilot. كلما زادت البيانات، زادت النماذج، مما يعني وضعًا تجريبيًا أفضل. + Firehose Mode: ACTIVE وضع خرطوم الحريق: نشط @@ -609,8 +368,8 @@ This is the time after which settings UI closes automatically if user is not int نشط - For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream sunnypilot (and particular forks) are able to be used for training. - للحصول على أقصى فعالية، أحضر جهازك إلى الداخل واتصل بمحول USB-C جيد وشبكة Wi-Fi أسبوعياً.<br><br>يمكن أن يعمل وضع خرطوم الحريق أيضاً أثناء القيادة إذا كنت متصلاً بنقطة اتصال أو ببطاقة SIM غير محدودة.<br><br><br><b>الأسئلة المتكررة</b><br><br><i>هل يهم كيف أو أين أقود؟</i> لا، فقط قد كما تفعل عادة.<br><br><i>هل يتم سحب كل مقاطع رحلاتي في وضع خرطوم الحريق؟</i> لا، نقوم بسحب مجموعة مختارة من مقاطع رحلاتك.<br><br><i>ما هو محول USB-C الجيد؟</i> أي شاحن سريع للهاتف أو اللابتوب يجب أن يكون مناسباً.<br><br><i>هل يهم أي برنامج أستخدم؟</i> نعم، فقط النسخة الأصلية من sunnypilot (وأفرع معينة) يمكن استخدامها للتدريب. + For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training. + للحصول على أقصى فعالية، أحضر جهازك إلى الداخل واتصل بمحول USB-C جيد وشبكة Wi-Fi أسبوعياً.<br><br>يمكن أن يعمل وضع خرطوم الحريق أيضاً أثناء القيادة إذا كنت متصلاً بنقطة اتصال أو ببطاقة SIM غير محدودة.<br><br><br><b>الأسئلة المتكررة</b><br><br><i>هل يهم كيف أو أين أقود؟</i> لا، فقط قد كما تفعل عادة.<br><br><i>هل يتم سحب كل مقاطع رحلاتي في وضع خرطوم الحريق؟</i> لا، نقوم بسحب مجموعة مختارة من مقاطع رحلاتك.<br><br><i>ما هو محول USB-C الجيد؟</i> أي شاحن سريع للهاتف أو اللابتوب يجب أن يكون مناسباً.<br><br><i>هل يهم أي برنامج أستخدم؟</i> نعم، فقط النسخة الأصلية من openpilot (وأفرع معينة) يمكن استخدامها للتدريب. <b>%n segment(s)</b> of your driving is in the training dataset so far. @@ -623,12 +382,6 @@ This is the time after which settings UI closes automatically if user is not int حتى الآن، يوجد </b>%n مقطع<b>%n من قيادتك في مجموعة بيانات التدريب. - - sunnypilot learns to drive by watching humans, like you, drive. - -Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode. - - <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to an unmetered network @@ -653,49 +406,6 @@ Firehose Mode allows you to maximize your training data uploads to improve openp MAX - - HyundaiSettings - - Off - - - - Dynamic - - - - Predictive - - - - Custom Longitudinal Tuning - - - - This feature can only be used with openpilot longitudinal control enabled. - - - - Enable "Always Offroad" in Device panel, or turn vehicle off to select an option. - - - - Off: Uses default tuning - - - - Dynamic: Adjusts acceleration limits based on current speed - - - - Predictive: Uses future trajectory data to anticipate needed adjustments - - - - Fine-tune your driving experience by adjusting acceleration smoothness with openpilot longitudinal control. - - - InputDialog @@ -714,321 +424,6 @@ Firehose Mode allows you to maximize your training data uploads to improve openp - - LaneChangeSettings - - Back - السابق - - - Auto Lane Change: Delay with Blind Spot - - - - Toggle to enable a delay timer for seamless lane changes when blind spot monitoring (BSM) detects a obstructing vehicle, ensuring safe maneuvering. - - - - - LateralPanel - - Modular Assistive Driving System (MADS) - - - - Enable the beloved MADS feature. Disable toggle to revert back to stock sunnypilot engagement/disengagement. - - - - Customize MADS - - - - Customize Lane Change - - - - Enables independent engagements of Automatic Lane Centering (ALC) and Adaptive Cruise Control (ACC). - - - - Start the vehicle to check vehicle compatibility. - - - - This platform supports all MADS settings. - - - - This platform supports limited MADS settings. - - - - Pause Lateral Control with Blinker - - - - Pause lateral control with blinker when traveling below the desired speed selected. - - - - - LongitudinalPanel - - Custom ACC Speed Increments - - - - Enable custom Short & Long press increments for cruise speed increase/decrease. - - - - This feature can only be used with openpilot longitudinal control enabled. - - - - This feature is not supported on this platform due to vehicle limitations. - - - - Start the vehicle to check vehicle compatibility. - - - - - MadsSettings - - Toggle with Main Cruise - - - - Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement. - - - - Unified Engagement Mode (UEM) - - - - Engage lateral and longitudinal control with cruise control engagement. - - - - Note: Once lateral control is engaged via UEM, it will remain engaged until it is manually disabled via the MADS button or car shut off. - - - - Remain Active - - - - Disengage - - - - Steering Mode on Brake Pedal - - - - Start the vehicle to check vehicle compatibility. - - - - This feature defaults to OFF, and does not allow selection due to vehicle limitations. - - - - This feature defaults to ON, and does not allow selection due to vehicle limitations. - - - - This platform only supports Disengage mode due to vehicle limitations. - - - - Remain Active: ALC will remain active when the brake pedal is pressed. - - - - Pause - - - - Pause: ALC will pause when the brake pedal is pressed. - - - - Disengage: ALC will disengage when the brake pedal is pressed. - - - - Choose how Automatic Lane Centering (ALC) behaves after the brake pedal is manually pressed in sunnypilot. - - - - - MaxTimeOffroad - - Max Time Offroad - - - - Device will automatically shutdown after set time once the engine is turned off.<br/>(30h is the default) - - - - Always On - - - - h - - - - m - - - - (default) - - - - - ModelsPanel - - Current Model - - - - SELECT - اختيار - - - downloaded - - - - ready - - - - from cache - - - - Fetching models... - - - - Select a Model - - - - Default - - - - Model download has started in the background. - - - - We STRONGLY suggest you to reset calibration. - - - - Would you like to do that now? - - - - Reset Calibration - إعادة ضبط المعايرة - - - Driving Model Selector - - - - Warning: You are on a metered connection! - - - - Continue - متابعة - - - on Metered - - - - Cancel - إلغاء - - - Clear Model Cache - - - - CLEAR - - - - Driving Model - - - - Navigation Model - - - - Vision Model - - - - Policy Model - - - - Live Learning Steer Delay - - - - Adjust Software Delay - - - - Adjust the software delay when Live Learning Steer Delay is toggled off. -The default software delay value is 0.2 - - - - %1 - %2 - - - - download failed - %1 - - - - pending - %1 - - - - Enable this for the car to learn and adapt its steering response time. Disable to use a fixed steering response time. Keeping this on provides the stock openpilot experience. The Current value is updated automatically when the vehicle is Onroad. - - - - Current: - - - - This will delete ALL downloaded models from the cache<br/><u>except the currently active model</u>.<br/><br/>Are you sure you want to continue? - - - - Clear Cache - - - MultiOptionDialog @@ -1059,76 +454,6 @@ The default software delay value is 0.2 كلمة مرور خاطئة - - NetworkingSP - - Scan - - - - Scanning... - - - - - NeuralNetworkLateralControl - - Neural Network Lateral Control (NNLC) - - - - NNLC is currently not available on this platform. - - - - Start the car to check car compatibility - - - - NNLC Not Loaded - - - - NNLC Loaded - - - - Match - - - - Exact - - - - Fuzzy - - - - Match: "Exact" is ideal, but "Fuzzy" is fine too. - - - - Formerly known as <b>"NNFF"</b>, this replaces the lateral <b>"torque"</b> controller, with one using a neural network trained on each car's (actually, each separate EPS firmware) driving data for increased controls accuracy. - - - - Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server - - - - with feedback, or to provide log data for your car if your car is currently unsupported: - - - - if there are any issues: - - - - and donate logs to get NNLC loaded for your car: - - - OffroadAlert @@ -1136,12 +461,12 @@ The default software delay value is 0.2 درجة حرارة الجهاز مرتفعة جداً. يقوم النظام بالتبريد قبل البدء. درجة الحرارة الحالية للمكونات الداخلية: %1 - Immediately connect to the internet to check for updates. If you do not connect to the internet, sunnypilot won't engage in %1 - اتصل فوراً بالإنترنت للتحقق من وجود تحديثات. إذا لم تكم متصلاً بالإنترنت فإن sunnypilot لن يساهم في %1 + Immediately connect to the internet to check for updates. If you do not connect to the internet, openpilot won't engage in %1 + اتصل فوراً بالإنترنت للتحقق من وجود تحديثات. إذا لم تكم متصلاً بالإنترنت فإن openpilot لن يساهم في %1 - Connect to internet to check for updates. sunnypilot won't automatically start until it connects to internet to check for updates. - اتصل بالإنترنت للتحقق من وجود تحديثات. لا يعمل sunnypilot تلقائياً إلا إذا اتصل بالإنترنت من أجل التحقق من التحديثات. + Connect to internet to check for updates. openpilot won't automatically start until it connects to internet to check for updates. + اتصل بالإنترنت للتحقق من وجود تحديثات. لا يعمل openpilot تلقائياً إلا إذا اتصل بالإنترنت من أجل التحقق من التحديثات. Unable to download updates @@ -1157,30 +482,32 @@ The default software delay value is 0.2 An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. يتم تنزيل تحديث لنظام تشغيل جهازك في الخلفية. سيطلَب منك التحديث عندما يصبح جاهزاً للتثبيت. - - Device failed to register. It will not connect to or upload to comma.ai servers, and receives no support from comma.ai. If this is an official device, visit https://comma.ai/support. - فشل تسجيل الجهاز. لن يقوم بالاتصال أو تحميل خوادم comma.ai، ولا تلقي الدعم من comma.ai. إذا كان هذا الجهاز نظامياً فيرجى زيارة الموقع https://comma.ai/support. - NVMe drive not mounted. محرك NVMe غير مثبَّت. - Unsupported NVMe drive detected. Device may draw significantly more power and overheat due to the unsupported NVMe. - تم اكتشاف محرك NVMe غير مدعوم. قد يستهلك الجهاز قدراً أكبر بكثير من الطاقة، وزيادة في ارتفاع درجة الحرارة بسبب وجود NVMe غير مدعوم. + openpilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. + لم يكن openpilot قادراً على تحديد سيارتك. إما أن تكون سيارتك غير مدعومة أو أنه لم يتم التعرف على وحدة التحكم الإلكتروني (ECUs) فيها. يرجى تقديم طلب سحب من أجل إضافة نسخ برمجيات ثابتة إلى السيارة المناسبة. هل تحتاج إلى أي مساعدة؟ لا تتردد في التواصل مع doscord.comma.ai. - sunnypilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. - لم يكن sunnypilot قادراً على تحديد سيارتك. إما أن تكون سيارتك غير مدعومة أو أنه لم يتم التعرف على وحدة التحكم الإلكتروني (ECUs) فيها. يرجى تقديم طلب سحب من أجل إضافة نسخ برمجيات ثابتة إلى السيارة المناسبة. هل تحتاج إلى أي مساعدة؟ لا تتردد في التواصل مع doscord.comma.ai. + openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. + لقد اكتشف openpilot تغييراً في موقع تركيب الجهاز. تأكد من تثبيت الجهاز بشكل كامل في موقعه وتثبيته بإحكام على الزجاج الأمامي. - sunnypilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. - لقد اكتشف sunnypilot تغييراً في موقع تركيب الجهاز. تأكد من تثبيت الجهاز بشكل كامل في موقعه وتثبيته بإحكام على الزجاج الأمامي. + Device failed to register with the comma.ai backend. It will not connect or upload to comma.ai servers, and receives no support from comma.ai. If this is a device purchased at comma.ai/shop, open a ticket at https://comma.ai/support. + - OpenStreetMap database is out of date. New maps must be downloaded if you wish to continue using OpenStreetMap data for Enhanced Speed Control and road name display. - -%1 + Acknowledge Excessive Actuation + + + + Snooze Update + تأخير التحديث + + + openpilot has detected excessive %1 actuation. This may be due to a software bug. Please contact support at https://comma.ai/support. @@ -1199,18 +526,11 @@ The default software delay value is 0.2 تنبيه - - OffroadHomeSP - - ALWAYS OFFROAD ACTIVE - - - OnroadAlerts - sunnypilot Unavailable - sunnypilot غير متوفر + openpilot Unavailable + openpilot غير متوفر TAKE CONTROL IMMEDIATELY @@ -1229,137 +549,6 @@ The default software delay value is 0.2 النظام لا يستجيب - - OsmPanel - - Mapd Version - - - - Offline Maps ETA - - - - Time Elapsed - - - - Downloaded Maps - - - - DELETE - - - - This will delete ALL downloaded maps - -Are you sure you want to delete all the maps? - - - - Yes, delete all the maps. - - - - Database Update - - - - CHECK - التحقق - - - Country - - - - SELECT - اختيار - - - Fetching Country list... - - - - State - - - - Fetching State list... - - - - All - - - - REFRESH - - - - UPDATE - تحديث - - - Download starting... - - - - Error: Invalid download. Retry. - - - - Download complete! - - - - - -Warning: You are on a metered connection! - - - - This will start the download process and it might take a while to complete. - - - - Continue on Metered - - - - Start Download - - - - m - - - - s - - - - Calculating... - - - - Downloaded - - - - Calculating ETA... - - - - Ready - - - - Time remaining: - - - PairingPopup @@ -1394,96 +583,6 @@ Warning: You are on a metered connection! إلغاء - - ParamControlSP - - Enable - تمكين - - - Cancel - إلغاء - - - - PlatformSelector - - Vehicle - - - - SEARCH - - - - Search your vehicle - - - - Enter model year (e.g., 2021) and model name (Toyota Corolla): - - - - SEARCHING - - - - REMOVE - إزالة - - - This setting will take effect immediately. - - - - This setting will take effect once the device enters offroad state. - - - - Vehicle Selector - - - - Confirm - تأكيد - - - Cancel - إلغاء - - - No vehicles found for query: %1 - - - - Select a vehicle - - - - Unrecognized Vehicle - - - - Fingerprinted automatically - - - - Manually selected - - - - Not fingerprinted or manually selected - - - - Select vehicle to force fingerprint manually. - - - - Colors represent fingerprint status: - - - PrimeAdWidget @@ -1529,8 +628,8 @@ Warning: You are on a metered connection! QObject - sunnypilot - sunnypilot + openpilot + openpilot %n minute(s) ago @@ -1570,47 +669,6 @@ Warning: You are on a metered connection! الآن - - Reset - - Reset failed. Reboot to try again. - فشل إعاة الضبط. أعد التشغيل للمحاولة من جديد. - - - Are you sure you want to reset your device? - هل أنت متأكد أنك تريد إعادة ضبط جهازك؟ - - - System Reset - إعادة ضبط النظام - - - Cancel - إلغاء - - - Reboot - إعادة التشغيل - - - Confirm - تأكيد - - - Resetting device... -This may take up to a minute. - يتم إعادة ضبط الجهاز... -قد يستغرق الأمر حوالي الدقيقة. - - - Unable to mount data partition. Partition may be corrupted. Press confirm to erase and reset your device. - غير قادر على تحميل جزء البيانات. قد يكون الجزء تالفاً. اضغط على تأكيد لمسح جهازك وإعادة ضبطه. - - - System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot. - تم تفعيل إعادة ضبط النظام. اضغط على تأكيد لمسح جميع المحتويات والإعدادات. اضغط على إلغاء لاستئناف التمهيد. - - SettingsWindow @@ -1642,69 +700,6 @@ This may take up to a minute. خرطوم الحريق - - SettingsWindowSP - - × - × - - - Device - الجهاز - - - Network - الشبكة - - - sunnylink - - - - Toggles - المثبتتات - - - Software - البرنامج - - - Trips - - - - Vehicle - - - - Developer - المطور - - - Firehose - خرطوم الحريق - - - Steering - - - - Models - - - - Cruise - - - - Visuals - - - - OSM - - - Setup @@ -1792,8 +787,8 @@ This may take up to a minute. اختر البرنامج للتثبيت - sunnypilot - sunnypilot + openpilot + openpilot Custom Software @@ -1900,33 +895,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 5G - - SidebarSP - - DISABLED - - - - OFFLINE - غير متصل - - - REGIST... - - - - ONLINE - متصل - - - ERROR - خطأ - - - SUNNYLINK - - - SoftwarePanel @@ -2002,49 +970,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device أحدث نسخة، آخر تحقق %1 - - SoftwarePanelSP - - Search Branch - - - - Enter search keywords, or leave blank to list all branches. - - - - No branches found for keywords: %1 - - - - Select a branch - اختر فرعاً - - - Disable Updates - - - - When enabled, software updates will be disabled. <b>This requires a reboot to take effect.</b> - - - - %1 updates requires a reboot.<br>Reboot now? - - - - Reboot - إعادة التشغيل - - - When enabled, software updates will be disabled.<br><b>This requires a reboot to take effect.</b> - - - - Please enable always offroad mode or turn off vehicle to adjust these toggles - - - SshControl @@ -2091,168 +1016,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device تمكين SSH - - SunnylinkPanel - - This is the master switch, it will allow you to cutoff any sunnylink requests should you want to do that. - - - - Enable sunnylink - - - - 🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀 - - - - 👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉. - - - - Device ID - - - - N/A - غير متاح - - - Sponsor Status - - - - SPONSOR - - - - Become a sponsor of sunnypilot to get early access to sunnylink features when they become available. - - - - Pair GitHub Account - - - - PAIR - إقران - - - Pair your GitHub account to grant your device sponsor benefits, including API access on sunnylink. - - - - sunnylink Dongle ID not found. This may be due to weak internet connection or sunnylink registration issue. Please reboot and try again. - - - - Not Sponsor - - - - Paired - - - - Not Paired - - - - THANKS ♥ - - - - Backup Settings - - - - Are you sure you want to backup sunnypilot settings? - - - - Back Up - - - - Restore Settings - - - - Are you sure you want to restore the last backed up sunnypilot settings? - - - - Restore - - - - Backup in progress %1% - - - - Backup Failed - - - - Settings backup completed. - - - - Restore in progress %1% - - - - Restore Failed - - - - Unable to restore the settings, try again later. - - - - Settings restored. Confirm to restart the interface. - - - - - SunnylinkSponsorPopup - - Scan the QR code to login to your GitHub account - - - - Follow the prompts to complete the pairing process - - - - Re-enter the "sunnylink" panel to verify sponsorship status - - - - If sponsorship status was not updated, please contact a moderator on Discord at https://discord.gg/sunnypilot - - - - Scan the QR code to visit sunnyhaibin's GitHub Sponsors page - - - - Choose your sponsorship tier and confirm your support - - - - Join our community on Discord at https://discord.gg/sunnypilot and reach out to a moderator to confirm your sponsor status - - - - Pair your GitHub account - - - - Early Access: Become a sunnypilot Sponsor - - - TermsPage @@ -2264,16 +1027,20 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device أوافق - Welcome to sunnypilot - مرحباً بكم في sunnypilot + Welcome to openpilot + مرحباً بكم في openpilot - You must accept the Terms and Conditions to use sunnypilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing. - يجب عليك قبول الشروط والأحكام لاستخدام sunnypilot. اقرأ أحدث الشروط على <span style='color: #465BEA;'>https://comma.ai/terms</span> قبل الاستمرار. + You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing. + يجب عليك قبول الشروط والأحكام لاستخدام openpilot. اقرأ أحدث الشروط على <span style='color: #465BEA;'>https://comma.ai/terms</span> قبل الاستمرار. TogglesPanel + + Enable openpilot + تمكين openpilot + Enable Lane Departure Warnings قم بتمكين تحذيرات مغادرة المسار @@ -2303,8 +1070,8 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device فك الارتباط عن دواسة الوقود - When enabled, pressing the accelerator pedal will disengage sunnypilot. - عند تمكين هذه الميزة، فإن الضغط على دواسة الوقود سيؤدي إلى فك ارتباط sunnypilot. + When enabled, pressing the accelerator pedal will disengage openpilot. + عند تمكين هذه الميزة، فإن الضغط على دواسة الوقود سيؤدي إلى فك ارتباط openpilot. Experimental Mode @@ -2327,16 +1094,16 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device شخصية القيادة - sunnypilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: - يتم وضع sunnypilot بشكل قياسي في <b>وضعية الراحة</b>. يمكن الوضع التجريبي <b>ميزات المستوى ألفا</b> التي لا تكون جاهزة في وضع الراحة: + openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: + يتم وضع openpilot بشكل قياسي في <b>وضعية الراحة</b>. يمكن الوضع التجريبي <b>ميزات المستوى ألفا</b> التي لا تكون جاهزة في وضع الراحة: End-to-End Longitudinal Control التحكم الطولي من طرف إلى طرف - Let the driving model control the gas and brakes. sunnypilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. - دع نظام القيادة يتحكم بالوقود والمكابح. سيقوم sunnypilot بالقيادة كما لو أنه كائن بشري، بما في ذلك التوقف عند الإشارة الحمراء، وإشارات التوقف. وبما أن نمط القيادة يحدد سرعة القيادة، فإن السرعة المضبوطة تشكل الحد الأقصى فقط. هذه خاصية الجودة ألفا، فيجب توقع حدوث الأخطاء. + Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. + دع نظام القيادة يتحكم بالوقود والمكابح. سيقوم openpilot بالقيادة كما لو أنه كائن بشري، بما في ذلك التوقف عند الإشارة الحمراء، وإشارات التوقف. وبما أن نمط القيادة يحدد سرعة القيادة، فإن السرعة المضبوطة تشكل الحد الأقصى فقط. هذه خاصية الجودة ألفا، فيجب توقع حدوث الأخطاء. New Driving Visualization @@ -2347,16 +1114,20 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device الوضع التجريبي غير متوفر حالياً في هذه السيارة نظراً لاستخدام رصيد التحكم التكيفي بالسرعة من أجل التحكم الطولي. - An alpha version of sunnypilot longitudinal control can be tested, along with Experimental mode, on non-release branches. - يمكن اختبار نسخة ألفا من التحكم الطولي من sunnypilot، مع الوضع التجريبي، لكن على الفروع غير المطلقة. + openpilot longitudinal control may come in a future update. + قد يتم الحصول على التحكم الطولي في openpilot في عمليات التحديث المستقبلية. - Enable the sunnypilot longitudinal control (alpha) toggle to allow Experimental mode. - تمكين التحكم الطولي من sunnypilot (ألفا) للسماح بالوضع التجريبي. + An alpha version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + يمكن اختبار نسخة ألفا من التحكم الطولي من openpilot، مع الوضع التجريبي، لكن على الفروع غير المطلقة. - Standard is recommended. In aggressive mode, sunnypilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode sunnypilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. - يوصى بالمعيار. في الوضع العدواني، سيتبع الطيار المفتوح السيارات الرائدة بشكل أقرب ويكون أكثر عدوانية مع البنزين والفرامل. في الوضع المريح، سيبقى sunnypilot بعيدًا عن السيارات الرائدة. في السيارات المدعومة، يمكنك التنقل بين هذه الشخصيات باستخدام زر مسافة عجلة القيادة. + Enable the openpilot longitudinal control (alpha) toggle to allow Experimental mode. + تمكين التحكم الطولي من openpilot (ألفا) للسماح بالوضع التجريبي. + + + Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. + يوصى بالمعيار. في الوضع العدواني، سيتبع الطيار المفتوح السيارات الرائدة بشكل أقرب ويكون أكثر عدوانية مع البنزين والفرامل. في الوضع المريح، سيبقى openpilot بعيدًا عن السيارات الرائدة. في السيارات المدعومة، يمكنك التنقل بين هذه الشخصيات باستخدام زر مسافة عجلة القيادة. The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. @@ -2367,33 +1138,17 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device مراقبة السائق المستمرة - Enable driver monitoring even when sunnypilot is not engaged. + Enable driver monitoring even when openpilot is not engaged. تمكين مراقبة السائق حتى عندما لا يكون نظام OpenPilot مُفعّلاً. - Enable Dynamic Experimental Control - - - - Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal. - - - - Enable sunnypilot - تمكين sunnypilot - - - Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. + Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting will restart openpilot if the car is powered on. - - openpilot longitudinal control may come in a future update. - - Record and Upload Microphone Audio @@ -2403,95 +1158,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device - - TreeOptionDialog - - Select - اختيار - - - Cancel - إلغاء - - - - Updater - - Update Required - التحديث مطلوب - - - An operating system update is required. Connect your device to Wi-Fi for the fastest update experience. The download size is approximately 1GB. - تحديث نظام التشغيل مطلوب. قم بوصل جهازك بشبكة واي فاي من أجل تحديث أسرع. حجم التحميل حوالي 1 غيغا بايت تقريباً. - - - Connect to Wi-Fi - الاتصال بشبكة الواي فاي - - - Install - تثبيت - - - Back - السابق - - - Loading... - يتم التحميل... - - - Reboot - إعادة التشغيل - - - Update failed - فشل التحديث - - - - VisualsPanel - - Show Blind Spot Warnings - - - - Enabling this will display warnings when a vehicle is detected in your blind spot as long as your car has BSM supported. - - - - Changing this setting will restart openpilot if the car is powered on. - - - - Off - - - - Distance - - - - Speed - - - - Time - - - - All - - - - Display Metrics Below Chevron - - - - Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control). - - - WiFiPromptWidget @@ -2499,12 +1165,12 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device انفتح - <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span> - <span style='font-family: "Noto Color Emoji";'>🔥</span> وضع خرطوم الحريق <span style='font-family: Noto Color Emoji;'>🔥</span> + Maximize your training data uploads to improve openpilot's driving models. + قم بزيادة تحميلات بيانات التدريب الخاصة بك لتحسين نماذج القيادة الخاصة بـ openpilot. - Maximize your training data uploads to improve openpilot's driving models. - + <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span> + <span style='font-family: "Noto Color Emoji";'>🔥</span> وضع خرطوم الحريق <span style='font-family: Noto Color Emoji;'>🔥</span> diff --git a/selfdrive/ui/translations/main_de.ts b/selfdrive/ui/translations/main_de.ts index dbde9c280a..3489b4860e 100644 --- a/selfdrive/ui/translations/main_de.ts +++ b/selfdrive/ui/translations/main_de.ts @@ -7,10 +7,6 @@ Close Schließen - - Snooze Update - Update pausieren - Reboot and Update Aktualisieren und neu starten @@ -107,53 +103,6 @@ - - AutoLaneChangeTimer - - Auto Lane Change by Blinker - - - - Set a timer to delay the auto lane change operation when the blinker is used. No nudge on the steering wheel is required to auto lane change if a timer is set. Default is Nudge. -Please use caution when using this feature. Only use the blinker when traffic and road conditions permit. - - - - s - - - - Off - - - - Nudge - - - - Nudgeless - - - - - Brightness - - Brightness - - - - Overrides the brightness of the device. - - - - Auto (Dark) - - - - Auto - - - ConfirmationDialog @@ -167,6 +116,10 @@ Please use caution when using this feature. Only use the blinker when traffic an DeclinePage + + You must accept the Terms and Conditions in order to use openpilot. + Du musst die Nutzungsbedingungen akzeptieren, um Openpilot zu benutzen. + Back Zurück @@ -175,10 +128,6 @@ Please use caution when using this feature. Only use the blinker when traffic an Decline, uninstall %1 Ablehnen, deinstallieren %1 - - You must accept the Terms and Conditions in order to use sunnypilot. - - DeveloperPanel @@ -198,6 +147,10 @@ Please use caution when using this feature. Only use the blinker when traffic an WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). WARNUNG: Die openpilot Längsregelung befindet sich für dieses Fahrzeug im Alpha-Stadium und deaktiviert das automatische Notbremsen (AEB). + + On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. + Bei diesem Fahrzeug verwendet openpilot standardmäßig den eingebauten Tempomaten anstelle der openpilot Längsregelung. Aktiviere diese Option, um auf die openpilot Längsregelung umzuschalten. Es wird empfohlen, den experimentellen Modus zu aktivieren, wenn die openpilot Längsregelung (Alpha) aktiviert wird. + Enable ADB ADB aktivieren @@ -206,54 +159,6 @@ Please use caution when using this feature. Only use the blinker when traffic an ADB (Android Debug Bridge) allows connecting to your device over USB or over the network. See https://docs.comma.ai/how-to/connect-to-comma for more info. ADB (Android Debug Bridge) ermöglicht die Verbindung zu deinem Gerät über USB oder Netzwerk. Siehe https://docs.comma.ai/how-to/connect-to-comma für weitere Informationen. - - On this car, sunnypilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. - - - - - DeveloperPanelSP - - Show Advanced Controls - - - - Toggle visibility of advanced sunnypilot controls. -This only toggles the visibility of the controls; it does not toggle the actual control enabled/disabled state. - - - - Enable GitHub runner service - - - - Enables or disables the github runner service. - - - - Enable Quickboot Mode - - - - Error Log - - - - VIEW - ANSEHEN - - - View the error log for sunnypilot crashes. - - - - When toggled on, this creates a prebuilt file to allow accelerated boot times. When toggled off, it immediately removes the prebuilt file so compilation of locally edited cpp files can be made. <br><br><b>To edit C++ files locally on device, you MUST first turn off this toggle so the changes can recompile.</b> - - - - Quickboot mode requires updates to be disabled.<br>Enable 'Disable Updates' in the Software panel first. - - DevicePanel @@ -301,6 +206,10 @@ This only toggles the visibility of the controls; it does not toggle the actual REVIEW TRAINING + + Review the rules, features, and limitations of openpilot + Wiederhole die Regeln, Fähigkeiten und Limitierungen von Openpilot + Are you sure you want to review the training guide? Bist du sicher, dass du die Trainingsanleitung wiederholen möchtest? @@ -394,11 +303,11 @@ This only toggles the visibility of the controls; it does not toggle the actual - Review the rules, features, and limitations of sunnypilot + openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. - sunnypilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. + openpilot is continuously calibrating, resetting is rarely required. Resetting calibration will restart openpilot if the car is powered on. @@ -421,149 +330,6 @@ Steering lag calibration is complete. Steering torque response calibration is complete. - - openpilot is continuously calibrating, resetting is rarely required. Resetting calibration will restart openpilot if the car is powered on. - - - - - DevicePanelSP - - Quiet Mode - - - - Driver Camera Preview - - - - Training Guide - - - - Regulatory - Rechtliche Hinweise - - - Language - - - - Reset Settings - - - - Are you sure you want to review the training guide? - Bist du sicher, dass du die Trainingsanleitung wiederholen möchtest? - - - Review - Überprüfen - - - Select a language - Sprache wählen - - - Reboot - Neustart - - - Power Off - Ausschalten - - - Offroad Mode - - - - Are you sure you want to exit Always Offroad mode? - - - - Confirm - Bestätigen - - - Are you sure you want to enter Always Offroad mode? - - - - Disengage to Enter Always Offroad Mode - - - - Are you sure you want to reset all sunnypilot settings to default? Once the settings are reset, there is no going back. - - - - Reset - Zurücksetzen - - - The reset cannot be undone. You have been warned. - - - - Exit Always Offroad - - - - Always Offroad - - - - Wake-Up Behavior - - - - Interactivity Timeout - - - - Apply a custom timeout for settings UI. -This is the time after which settings UI closes automatically if user is not interacting with the screen. - - - - ⁍ Default: Device will boot/wake-up normally & will be ready to engage. - - - - ⁍ Offroad: Device will be in Always Offroad mode after boot/wake-up. - - - - Controls state of the device after boot/sleep. - - - - - DriveStats - - Drives - - - - Hours - - - - ALL TIME - - - - PAST WEEK - - - - KM - - - - Miles - - DriverViewWindow @@ -572,21 +338,6 @@ This is the time after which settings UI closes automatically if user is not int Kamera startet - - ExitOffroadButton - - Are you sure you want to exit Always Offroad mode? - - - - Confirm - Bestätigen - - - EXIT ALWAYS OFFROAD MODE - - - ExperimentalModeButton @@ -600,6 +351,14 @@ This is the time after which settings UI closes automatically if user is not int FirehosePanel + + openpilot learns to drive by watching humans, like you, drive. + +Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode. + openpilot lernt das Fahren, indem es Menschen wie dir beim Fahren zuschaut. + +Der Firehose-Modus ermöglicht es dir, deine Trainingsdaten-Uploads zu maximieren, um die Fahrmodelle von openpilot zu verbessern. Mehr Daten bedeuten größere Modelle, was zu einem besseren Experimentellen Modus führt. + Firehose Mode: ACTIVE Firehose-Modus: AKTIV @@ -608,6 +367,10 @@ This is the time after which settings UI closes automatically if user is not int ACTIVE AKTIV + + For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training. + Für maximale Effektivität bring dein Gerät jede Woche nach drinnen und verbinde es mit einem guten USB-C-Adapter und WLAN.<br><br>Der Firehose-Modus funktioniert auch während der Fahrt, wenn das Gerät mit einem Hotspot oder einer ungedrosselten SIM-Karte verbunden ist.<br><br><br><b>Häufig gestellte Fragen</b><br><br><i>Spielt es eine Rolle, wie oder wo ich fahre?</i> Nein, fahre einfach wie gewohnt.<br><br><i>Werden im Firehose-Modus alle meine Segmente hochgeladen?</i> Nein, wir wählen selektiv nur einen Teil deiner Segmente aus.<br><br><i>Welcher USB-C-Adapter ist gut?</i> Jedes Schnellladegerät für Handy oder Laptop sollte ausreichen.<br><br><i>Spielt es eine Rolle, welche Software ich nutze?</i> Ja, nur das offizielle Upstream‑openpilot (und bestimmte Forks) kann für das Training verwendet werden. + <b>%n segment(s)</b> of your driving is in the training dataset so far. @@ -619,16 +382,6 @@ This is the time after which settings UI closes automatically if user is not int <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to an unmetered network <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INAKTIV</span>: Verbinde dich mit einem ungedrosselten Netzwerk - - sunnypilot learns to drive by watching humans, like you, drive. - -Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode. - - - - For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream sunnypilot (and particular forks) are able to be used for training. - - Firehose Mode @@ -649,49 +402,6 @@ Firehose Mode allows you to maximize your training data uploads to improve openp MAX - - HyundaiSettings - - Off - - - - Dynamic - - - - Predictive - - - - Custom Longitudinal Tuning - - - - This feature can only be used with openpilot longitudinal control enabled. - - - - Enable "Always Offroad" in Device panel, or turn vehicle off to select an option. - - - - Off: Uses default tuning - - - - Dynamic: Adjusts acceleration limits based on current speed - - - - Predictive: Uses future trajectory data to anticipate needed adjustments - - - - Fine-tune your driving experience by adjusting acceleration smoothness with openpilot longitudinal control. - - - InputDialog @@ -706,321 +416,6 @@ Firehose Mode allows you to maximize your training data uploads to improve openp - - LaneChangeSettings - - Back - Zurück - - - Auto Lane Change: Delay with Blind Spot - - - - Toggle to enable a delay timer for seamless lane changes when blind spot monitoring (BSM) detects a obstructing vehicle, ensuring safe maneuvering. - - - - - LateralPanel - - Modular Assistive Driving System (MADS) - - - - Enable the beloved MADS feature. Disable toggle to revert back to stock sunnypilot engagement/disengagement. - - - - Customize MADS - - - - Customize Lane Change - - - - Enables independent engagements of Automatic Lane Centering (ALC) and Adaptive Cruise Control (ACC). - - - - Start the vehicle to check vehicle compatibility. - - - - This platform supports all MADS settings. - - - - This platform supports limited MADS settings. - - - - Pause Lateral Control with Blinker - - - - Pause lateral control with blinker when traveling below the desired speed selected. - - - - - LongitudinalPanel - - Custom ACC Speed Increments - - - - Enable custom Short & Long press increments for cruise speed increase/decrease. - - - - This feature can only be used with openpilot longitudinal control enabled. - - - - This feature is not supported on this platform due to vehicle limitations. - - - - Start the vehicle to check vehicle compatibility. - - - - - MadsSettings - - Toggle with Main Cruise - - - - Unified Engagement Mode (UEM) - - - - Steering Mode on Brake Pedal - - - - Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement. - - - - Engage lateral and longitudinal control with cruise control engagement. - - - - Note: Once lateral control is engaged via UEM, it will remain engaged until it is manually disabled via the MADS button or car shut off. - - - - Start the vehicle to check vehicle compatibility. - - - - This feature defaults to OFF, and does not allow selection due to vehicle limitations. - - - - This feature defaults to ON, and does not allow selection due to vehicle limitations. - - - - This platform only supports Disengage mode due to vehicle limitations. - - - - Remain Active - - - - Remain Active: ALC will remain active when the brake pedal is pressed. - - - - Pause - - - - Pause: ALC will pause when the brake pedal is pressed. - - - - Disengage - - - - Disengage: ALC will disengage when the brake pedal is pressed. - - - - Choose how Automatic Lane Centering (ALC) behaves after the brake pedal is manually pressed in sunnypilot. - - - - - MaxTimeOffroad - - Max Time Offroad - - - - Device will automatically shutdown after set time once the engine is turned off.<br/>(30h is the default) - - - - Always On - - - - h - - - - m - - - - (default) - - - - - ModelsPanel - - Current Model - - - - SELECT - AUSWÄHLEN - - - downloaded - - - - ready - - - - from cache - - - - Fetching models... - - - - Select a Model - - - - Default - - - - Model download has started in the background. - - - - We STRONGLY suggest you to reset calibration. - - - - Would you like to do that now? - - - - Reset Calibration - Neu kalibrieren - - - Driving Model Selector - - - - Warning: You are on a metered connection! - - - - Continue - Fortsetzen - - - on Metered - - - - Cancel - Abbrechen - - - Clear Model Cache - - - - CLEAR - - - - Driving Model - - - - Navigation Model - - - - Vision Model - - - - Policy Model - - - - Live Learning Steer Delay - - - - Adjust Software Delay - - - - Adjust the software delay when Live Learning Steer Delay is toggled off. -The default software delay value is 0.2 - - - - %1 - %2 - - - - download failed - %1 - - - - pending - %1 - - - - Enable this for the car to learn and adapt its steering response time. Disable to use a fixed steering response time. Keeping this on provides the stock openpilot experience. The Current value is updated automatically when the vehicle is Onroad. - - - - Current: - - - - This will delete ALL downloaded models from the cache<br/><u>except the currently active model</u>.<br/><br/>Are you sure you want to continue? - - - - Clear Cache - - - MultiOptionDialog @@ -1051,78 +446,16 @@ The default software delay value is 0.2 Falsches Passwort - - NetworkingSP - - Scan - - - - Scanning... - - - - - NeuralNetworkLateralControl - - Neural Network Lateral Control (NNLC) - - - - NNLC is currently not available on this platform. - - - - Start the car to check car compatibility - - - - NNLC Not Loaded - - - - NNLC Loaded - - - - Match - - - - Exact - - - - Fuzzy - - - - Match: "Exact" is ideal, but "Fuzzy" is fine too. - - - - Formerly known as <b>"NNFF"</b>, this replaces the lateral <b>"torque"</b> controller, with one using a neural network trained on each car's (actually, each separate EPS firmware) driving data for increased controls accuracy. - - - - Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server - - - - with feedback, or to provide log data for your car if your car is currently unsupported: - - - - if there are any issues: - - - - and donate logs to get NNLC loaded for your car: - - - OffroadAlert + + Immediately connect to the internet to check for updates. If you do not connect to the internet, openpilot won't engage in %1 + Stelle sofort eine Internetverbindung her, um nach Updates zu suchen. Wenn du keine Verbindung herstellst, kann openpilot in %1 nicht mehr aktiviert werden. + + + Connect to internet to check for updates. openpilot won't automatically start until it connects to internet to check for updates. + Verbinde dich mit dem Internet, um nach Updates zu suchen. openpilot startet nicht automatisch, bis eine Internetverbindung besteht und nach Updates gesucht wurde. + Unable to download updates %1 @@ -1137,42 +470,36 @@ The default software delay value is 0.2 An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. Ein Update für das Betriebssystem deines Geräts wird im Hintergrund heruntergeladen. Du wirst aufgefordert, das Update zu installieren, sobald es bereit ist. - - Device failed to register. It will not connect to or upload to comma.ai servers, and receives no support from comma.ai. If this is an official device, visit https://comma.ai/support. - Gerät konnte nicht registriert werden. Es wird keine Verbindung zu den comma.ai-Servern herstellen oder Daten hochladen und erhält keinen Support von comma.ai. Wenn dies ein offizielles Gerät ist, besuche https://comma.ai/support. - NVMe drive not mounted. NVMe-Laufwerk nicht gemounted. - Unsupported NVMe drive detected. Device may draw significantly more power and overheat due to the unsupported NVMe. - Nicht unterstütztes NVMe-Laufwerk erkannt. Das Gerät kann dadurch deutlich mehr Strom verbrauchen und überhitzen. + openpilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. + openpilot konnte dein Auto nicht identifizieren. Dein Auto wird entweder nicht unterstützt oder die Steuergeräte (ECUs) werden nicht erkannt. Bitte reiche einen Pull Request ein, um die Firmware-Versionen für das richtige Fahrzeug hinzuzufügen. Hilfe findest du auf discord.comma.ai. + + + openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. + openpilot hat eine Änderung der Montageposition des Geräts erkannt. Stelle sicher, dass das Gerät vollständig in der Halterung sitzt und die Halterung fest an der Windschutzscheibe befestigt ist. Device temperature too high. System cooling down before starting. Current internal component temperature: %1 Gerätetemperatur zu hoch. Das System kühlt ab, bevor es startet. Aktuelle interne Komponententemperatur: %1 - Immediately connect to the internet to check for updates. If you do not connect to the internet, sunnypilot won't engage in %1 + Device failed to register with the comma.ai backend. It will not connect or upload to comma.ai servers, and receives no support from comma.ai. If this is a device purchased at comma.ai/shop, open a ticket at https://comma.ai/support. - Connect to internet to check for updates. sunnypilot won't automatically start until it connects to internet to check for updates. + Acknowledge Excessive Actuation - sunnypilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. - + Snooze Update + Update pausieren - sunnypilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. - - - - OpenStreetMap database is out of date. New maps must be downloaded if you wish to continue using OpenStreetMap data for Enhanced Speed Control and road name display. - -%1 + openpilot has detected excessive %1 actuation. This may be due to a software bug. Please contact support at https://comma.ai/support. @@ -1191,15 +518,12 @@ The default software delay value is 0.2 HINWEIS - - OffroadHomeSP - - ALWAYS OFFROAD ACTIVE - - - OnroadAlerts + + openpilot Unavailable + openpilot nicht verfügbar + TAKE CONTROL IMMEDIATELY ÜBERNIMM SOFORT DIE KONTROLLE @@ -1216,141 +540,6 @@ The default software delay value is 0.2 System Unresponsive System reagiert nicht - - sunnypilot Unavailable - - - - - OsmPanel - - Mapd Version - - - - Offline Maps ETA - - - - Time Elapsed - - - - Downloaded Maps - - - - DELETE - - - - This will delete ALL downloaded maps - -Are you sure you want to delete all the maps? - - - - Yes, delete all the maps. - - - - Database Update - - - - CHECK - ÜBERPRÜFEN - - - Country - - - - SELECT - AUSWÄHLEN - - - Fetching Country list... - - - - State - - - - Fetching State list... - - - - All - - - - REFRESH - - - - UPDATE - Aktualisieren - - - Download starting... - - - - Error: Invalid download. Retry. - - - - Download complete! - - - - - -Warning: You are on a metered connection! - - - - This will start the download process and it might take a while to complete. - - - - Continue on Metered - - - - Start Download - - - - m - - - - s - - - - Calculating... - - - - Downloaded - - - - Calculating ETA... - - - - Ready - - - - Time remaining: - - PairingPopup @@ -1386,96 +575,6 @@ Warning: You are on a metered connection! Aktivieren - - ParamControlSP - - Enable - Aktivieren - - - Cancel - Abbrechen - - - - PlatformSelector - - Vehicle - - - - SEARCH - - - - Search your vehicle - - - - Enter model year (e.g., 2021) and model name (Toyota Corolla): - - - - SEARCHING - - - - REMOVE - LÖSCHEN - - - This setting will take effect immediately. - - - - This setting will take effect once the device enters offroad state. - - - - Vehicle Selector - - - - Confirm - Bestätigen - - - Cancel - Abbrechen - - - No vehicles found for query: %1 - - - - Select a vehicle - - - - Unrecognized Vehicle - - - - Fingerprinted automatically - - - - Manually selected - - - - Not fingerprinted or manually selected - - - - Select vehicle to force fingerprint manually. - - - - Colors represent fingerprint status: - - - PrimeAdWidget @@ -1520,6 +619,10 @@ Warning: You are on a metered connection! QObject + + openpilot + openpilot + %n minute(s) ago @@ -1545,51 +648,6 @@ Warning: You are on a metered connection! now jetzt - - sunnypilot - - - - - Reset - - Reset failed. Reboot to try again. - Zurücksetzen fehlgeschlagen. Starte das Gerät neu und versuche es wieder. - - - Are you sure you want to reset your device? - Bist du sicher, dass du das Gerät auf Werkseinstellungen zurücksetzen möchtest? - - - System Reset - System auf Werkseinstellungen zurücksetzen - - - Cancel - Abbrechen - - - Reboot - Neustart - - - Confirm - Bestätigen - - - Unable to mount data partition. Partition may be corrupted. Press confirm to erase and reset your device. - Datenpartition konnte nicht gemounted werden. Die Partition ist möglicherweise beschädigt. Drücke Bestätigen, um das Gerät zu löschen und zurückzusetzen. - - - Resetting device... -This may take up to a minute. - Gerät wird zurückgesetzt... -Dies kann bis zu einer Minute dauern. - - - System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot. - System-Reset ausgelöst. Drücke Bestätigen, um alle Inhalte und Einstellungen zu löschen. Drücke Abbrechen, um den Startvorgang fortzusetzen. - SettingsWindow @@ -1622,69 +680,6 @@ Dies kann bis zu einer Minute dauern. Firehose - - SettingsWindowSP - - × - x - - - Device - Gerät - - - Network - Netzwerk - - - sunnylink - - - - Toggles - Schalter - - - Software - Software - - - Models - - - - Steering - - - - Cruise - - - - Trips - - - - Vehicle - - - - Firehose - Firehose - - - Developer - Entwickler - - - Visuals - - - - OSM - - - Setup @@ -1772,12 +767,12 @@ Dies kann bis zu einer Minute dauern. Wähle die zu installierende Software - Custom Software - Benutzerdefinierte Software + openpilot + openpilot - sunnypilot - + Custom Software + Benutzerdefinierte Software WARNING: Custom Software @@ -1881,33 +876,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 5G - - SidebarSP - - DISABLED - - - - OFFLINE - OFFLINE - - - REGIST... - - - - ONLINE - ONLINE - - - ERROR - FEHLER - - - SUNNYLINK - - - SoftwarePanel @@ -1984,49 +952,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device nie - - SoftwarePanelSP - - Search Branch - - - - Enter search keywords, or leave blank to list all branches. - - - - No branches found for keywords: %1 - - - - Select a branch - Wähle einen Branch - - - Disable Updates - - - - When enabled, software updates will be disabled. <b>This requires a reboot to take effect.</b> - - - - %1 updates requires a reboot.<br>Reboot now? - - - - Reboot - Neustart - - - When enabled, software updates will be disabled.<br><b>This requires a reboot to take effect.</b> - - - - Please enable always offroad mode or turn off vehicle to adjust these toggles - - - SshControl @@ -2073,168 +998,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device SSH aktivieren - - SunnylinkPanel - - This is the master switch, it will allow you to cutoff any sunnylink requests should you want to do that. - - - - Enable sunnylink - - - - Sponsor Status - - - - SPONSOR - - - - Become a sponsor of sunnypilot to get early access to sunnylink features when they become available. - - - - Pair GitHub Account - - - - PAIR - KOPPELN - - - Pair your GitHub account to grant your device sponsor benefits, including API access on sunnylink. - - - - N/A - Nicht verfügbar - - - sunnylink Dongle ID not found. This may be due to weak internet connection or sunnylink registration issue. Please reboot and try again. - - - - 🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀 - - - - 👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉. - - - - Backup Settings - - - - Are you sure you want to backup sunnypilot settings? - - - - Back Up - - - - Restore Settings - - - - Are you sure you want to restore the last backed up sunnypilot settings? - - - - Restore - - - - Backup in progress %1% - - - - Backup Failed - - - - Settings backup completed. - - - - Restore in progress %1% - - - - Restore Failed - - - - Unable to restore the settings, try again later. - - - - Settings restored. Confirm to restart the interface. - - - - Device ID - - - - THANKS ♥ - - - - Not Sponsor - - - - Paired - - - - Not Paired - - - - - SunnylinkSponsorPopup - - Scan the QR code to login to your GitHub account - - - - Follow the prompts to complete the pairing process - - - - Re-enter the "sunnylink" panel to verify sponsorship status - - - - If sponsorship status was not updated, please contact a moderator on Discord at https://discord.gg/sunnypilot - - - - Scan the QR code to visit sunnyhaibin's GitHub Sponsors page - - - - Choose your sponsorship tier and confirm your support - - - - Join our community on Discord at https://discord.gg/sunnypilot and reach out to a moderator to confirm your sponsor status - - - - Pair your GitHub account - - - - Early Access: Become a sunnypilot Sponsor - - - TermsPage @@ -2246,16 +1009,20 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device Zustimmen - Welcome to sunnypilot - + Welcome to openpilot + Willkommen bei openpilot - You must accept the Terms and Conditions to use sunnypilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing. - + You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing. + Du musst die Nutzungsbedingungen akzeptieren, um openpilot zu verwenden. Lies die aktuellen Bedingungen unter <span style='color: #465BEA;'>https://comma.ai/terms</span>, bevor du fortfährst. TogglesPanel + + Enable openpilot + Openpilot aktivieren + Enable Lane Departure Warnings Spurverlassenswarnungen aktivieren @@ -2280,6 +1047,10 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device Upload data from the driver facing camera and help improve the driver monitoring algorithm. Lade Daten der Fahreraufmerksamkeitsüberwachungskamera hoch, um die Fahreraufmerksamkeitsüberwachungsalgorithmen zu verbessern. + + When enabled, pressing the accelerator pedal will disengage openpilot. + Wenn aktiviert, deaktiviert sich Openpilot sobald das Gaspedal betätigt wird. + Experimental Mode Experimenteller Modus @@ -2288,6 +1059,14 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device Disengage on Accelerator Pedal Bei Gasbetätigung ausschalten + + openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: + Openpilot fährt standardmäßig im <b>entspannten Modus</b>. Der Experimentelle Modus aktiviert<b>Alpha-level Funktionen</b>, die noch nicht für den entspannten Modus bereit sind. Die experimentellen Funktionen sind die Folgenden: + + + Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. + Lass das Fahrmodell Gas und Bremse kontrollieren. Openpilot wird so fahren, wie es dies von einem Menschen erwarten würde; inklusive des Anhaltens für Ampeln und Stoppschildern. Da das Fahrmodell entscheidet wie schnell es fährt stellt die gesetzte Geschwindigkeit lediglich das obere Limit dar. Dies ist ein Alpha-level Funktion. Fehler sind zu erwarten. + New Driving Visualization Neue Fahrvisualisierung @@ -2320,6 +1099,18 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device openpilot longitudinal control may come in a future update. Die openpilot Längsregelung könnte in einem zukünftigen Update verfügbar sein. + + An alpha version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + Eine Alpha-Version der openpilot Längsregelung kann zusammen mit dem Experimentellen Modus auf non-stable Branches getestet werden. + + + Enable the openpilot longitudinal control (alpha) toggle to allow Experimental mode. + Aktiviere den Schalter für openpilot Längsregelung (Alpha), um den Experimentellen Modus zu erlauben. + + + Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. + Standard wird empfohlen. Im aggressiven Modus folgt openpilot vorausfahrenden Fahrzeugen enger und ist beim Gasgeben und Bremsen aggressiver. Im entspannten Modus hält openpilot mehr Abstand zu vorausfahrenden Fahrzeugen. Bei unterstützten Fahrzeugen kannst du mit der Abstandstaste am Lenkrad zwischen diesen Fahrstilen wechseln. + The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. Die Fahrvisualisierung wechselt bei niedrigen Geschwindigkeiten auf die nach vorne gerichtete Weitwinkelkamera, um Kurven besser darzustellen. Das Logo des Experimentellen Modus wird außerdem oben rechts angezeigt. @@ -2329,53 +1120,17 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device Dauerhaft aktive Fahrerüberwachung - Enable sunnypilot - + Enable driver monitoring even when openpilot is not engaged. + Fahrerüberwachung auch aktivieren, wenn openpilot nicht aktiv ist. - Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. - - - - Enable Dynamic Experimental Control - - - - Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal. - - - - When enabled, pressing the accelerator pedal will disengage sunnypilot. - - - - Enable driver monitoring even when sunnypilot is not engaged. - - - - Standard is recommended. In aggressive mode, sunnypilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode sunnypilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. + Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting will restart openpilot if the car is powered on. - - sunnypilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: - - - - Let the driving model control the gas and brakes. sunnypilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. - - - - An alpha version of sunnypilot longitudinal control can be tested, along with Experimental mode, on non-release branches. - - - - Enable the sunnypilot longitudinal control (alpha) toggle to allow Experimental mode. - - Record and Upload Microphone Audio @@ -2385,95 +1140,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device - - TreeOptionDialog - - Select - Auswählen - - - Cancel - Abbrechen - - - - Updater - - Update Required - Aktualisierung notwendig - - - An operating system update is required. Connect your device to Wi-Fi for the fastest update experience. The download size is approximately 1GB. - Eine Aktualisierung des Betriebssystems ist notwendig. Verbinde dein Gerät mit WLAN für ein schnelleres Update. Die Download Größe ist ungefähr 1GB. - - - Connect to Wi-Fi - Mit WLAN verbinden - - - Install - Installieren - - - Back - Zurück - - - Loading... - Laden... - - - Reboot - Neustart - - - Update failed - Aktualisierung fehlgeschlagen - - - - VisualsPanel - - Show Blind Spot Warnings - - - - Enabling this will display warnings when a vehicle is detected in your blind spot as long as your car has BSM supported. - - - - Changing this setting will restart openpilot if the car is powered on. - - - - Off - - - - Distance - - - - Speed - - - - Time - - - - All - - - - Display Metrics Below Chevron - - - - Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control). - - - WiFiPromptWidget diff --git a/selfdrive/ui/translations/main_es.ts b/selfdrive/ui/translations/main_es.ts index ed84ab0f42..5807accb92 100644 --- a/selfdrive/ui/translations/main_es.ts +++ b/selfdrive/ui/translations/main_es.ts @@ -7,10 +7,6 @@ Close Cerrar - - Snooze Update - Posponer Actualización - Reboot and Update Reiniciar y Actualizar @@ -84,74 +80,27 @@ Prevent large data uploads when on a metered cellular connection - + Evite cargas de grandes cantidades de datos cuando utilice una conexión celular medida default - + por defecto metered - + medido unmetered - + sin medidor Wi-Fi Network Metered - + Red Wi-Fi medida Prevent large data uploads when on a metered Wi-Fi connection - - - - - AutoLaneChangeTimer - - Auto Lane Change by Blinker - - - - Set a timer to delay the auto lane change operation when the blinker is used. No nudge on the steering wheel is required to auto lane change if a timer is set. Default is Nudge. -Please use caution when using this feature. Only use the blinker when traffic and road conditions permit. - - - - s - - - - Off - - - - Nudge - - - - Nudgeless - - - - - Brightness - - Brightness - - - - Overrides the brightness of the device. - - - - Auto (Dark) - - - - Auto - + Evite cargas de grandes cantidades de datos cuando esté en una conexión Wi-Fi medida @@ -168,8 +117,8 @@ Please use caution when using this feature. Only use the blinker when traffic an DeclinePage - You must accept the Terms and Conditions in order to use sunnypilot. - Debe aceptar los términos y condiciones para poder utilizar sunnypilot. + You must accept the Terms and Conditions in order to use openpilot. + Debe aceptar los términos y condiciones para poder utilizar openpilot. Back @@ -190,69 +139,25 @@ Please use caution when using this feature. Only use the blinker when traffic an Longitudinal Maneuver Mode Modo de maniobra longitudinal - - Enable ADB - - - - ADB (Android Debug Bridge) allows connecting to your device over USB or over the network. See https://docs.comma.ai/how-to/connect-to-comma for more info. - - openpilot Longitudinal Control (Alpha) - + Control longitudinal de openpilot (fase experimental) WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). - + AVISO: el control longitudinal de openpilot está en fase experimental para este automóvil y desactivará el Frenado Automático de Emergencia (AEB). - On this car, sunnypilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. - - - - - DeveloperPanelSP - - Show Advanced Controls - + On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. + En este automóvil, openpilot se configura de manera predeterminada con el Autocrucero Adaptativo (ACC) incorporado en el automóvil en lugar del control longitudinal de openpilot. Habilita esta opción para cambiar al control longitudinal de openpilot. Se recomienda activar el modo experimental al habilitar el control longitudinal de openpilot (aún en fase experimental). - Toggle visibility of advanced sunnypilot controls. -This only toggles the visibility of the controls; it does not toggle the actual control enabled/disabled state. - + Enable ADB + Activar ADB - Enable GitHub runner service - - - - Enables or disables the github runner service. - - - - Enable Quickboot Mode - - - - Error Log - - - - VIEW - VER - - - View the error log for sunnypilot crashes. - - - - When toggled on, this creates a prebuilt file to allow accelerated boot times. When toggled off, it immediately removes the prebuilt file so compilation of locally edited cpp files can be made. <br><br><b>To edit C++ files locally on device, you MUST first turn off this toggle so the changes can recompile.</b> - - - - Quickboot mode requires updates to be disabled.<br>Enable 'Disable Updates' in the Software panel first. - + ADB (Android Debug Bridge) allows connecting to your device over USB or over the network. See https://docs.comma.ai/how-to/connect-to-comma for more info. + ADB (Android Debug Bridge) permite conectar a su dispositivo por USB o por red. Visite https://docs.comma.ai/how-to/connect-to-comma para más información. @@ -318,8 +223,8 @@ This only toggles the visibility of the controls; it does not toggle the actual REVISAR - Review the rules, features, and limitations of sunnypilot - Revisar las reglas, características y limitaciones de sunnypilot + Review the rules, features, and limitations of openpilot + Revisar las reglas, características y limitaciones de openpilot Are you sure you want to review the training guide? @@ -395,174 +300,39 @@ This only toggles the visibility of the controls; it does not toggle the actual Disengage to Reset Calibration - + Desactivar para restablecer la calibración - sunnypilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. - + openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. + openpilot requiere que el dispositivo esté montado dentro de los 4° hacia la izquierda o la derecha y dentro de los 5° hacia arriba o 9° hacia abajo. + + + openpilot is continuously calibrating, resetting is rarely required. Resetting calibration will restart openpilot if the car is powered on. + Openpilot se calibra continuamente, por lo que rara vez es necesario reiniciarlo. Restablecer la calibración reiniciará Openpilot si el automóvil está encendido. Steering lag calibration is %1% complete. - + + +La calibración del retraso de dirección está %1% completada. Steering lag calibration is complete. - + + +La calibración del retraso de la dirección está completa. Steering torque response calibration is %1% complete. - + La calibración de la respuesta del par de dirección está %1% completada. Steering torque response calibration is complete. - - - - openpilot is continuously calibrating, resetting is rarely required. Resetting calibration will restart openpilot if the car is powered on. - - - - - DevicePanelSP - - Driver Camera Preview - - - - Training Guide - - - - Regulatory - Regulador - - - Language - - - - Are you sure you want to review the training guide? - ¿Seguro que quiere revisar la guía de entrenamiento? - - - Review - Revisar - - - Select a language - - - - Reboot - Reiniciar - - - Power Off - Apagar - - - Offroad Mode - - - - Are you sure you want to exit Always Offroad mode? - - - - Confirm - Confirmar - - - Are you sure you want to enter Always Offroad mode? - - - - Disengage to Enter Always Offroad Mode - - - - Exit Always Offroad - - - - Always Offroad - - - - Quiet Mode - - - - Reset Settings - - - - Are you sure you want to reset all sunnypilot settings to default? Once the settings are reset, there is no going back. - - - - Reset - Formatear - - - The reset cannot be undone. You have been warned. - - - - Wake-Up Behavior - - - - Interactivity Timeout - - - - Apply a custom timeout for settings UI. -This is the time after which settings UI closes automatically if user is not interacting with the screen. - - - - ⁍ Default: Device will boot/wake-up normally & will be ready to engage. - - - - ⁍ Offroad: Device will be in Always Offroad mode after boot/wake-up. - - - - Controls state of the device after boot/sleep. - - - - - DriveStats - - Drives - - - - Hours - - - - ALL TIME - - - - PAST WEEK - - - - KM - - - - Miles - + La calibración de la respuesta del par de dirección está completa. @@ -572,21 +342,6 @@ This is the time after which settings UI closes automatically if user is not int iniciando cámara - - ExitOffroadButton - - Are you sure you want to exit Always Offroad mode? - - - - Confirm - Confirmar - - - EXIT ALWAYS OFFROAD MODE - - - ExperimentalModeButton @@ -600,38 +355,40 @@ This is the time after which settings UI closes automatically if user is not int FirehosePanel + + openpilot learns to drive by watching humans, like you, drive. + +Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode. + openpilot aprende a conducir observando a humanos, como tú, conducir. + +El Modo Firehose te permite maximizar las subidas de datos de entrenamiento para mejorar los modelos de conducción de openpilot. Más datos significan modelos más grandes, lo que significa un mejor Modo Experimental. + Firehose Mode: ACTIVE - + Modo Firehose: ACTIVO ACTIVE - + ACTIVO - For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream sunnypilot (and particular forks) are able to be used for training. - + For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training. + Para máxima efectividad, traiga su dispositivo adentro y conéctelo a un buen adaptador USB-C y Wi-Fi semanalmente.<br><br>El Modo Firehose también puede funcionar mientras conduce si está conectado a un punto de acceso o tarjeta SIM ilimitada.<br><br><br><b>Preguntas Frecuentes</b><br><br><i>¿Importa cómo o dónde conduzco?</i> No, solo conduzca como lo haría normalmente.<br><br><i>¿Se extraen todos mis segmentos en el Modo Firehose?</i> No, seleccionamos selectivamente un subconjunto de sus segmentos.<br><br><i>¿Qué es un buen adaptador USB-C?</i> Cualquier cargador rápido de teléfono o portátil debería funcionar.<br><br><i>¿Importa qué software ejecuto?</i> Sí, solo el openpilot original (y forks específicos) pueden usarse para el entrenamiento. <b>%n segment(s)</b> of your driving is in the training dataset so far. - - - + + <b>%n segmento</b> de tu conducción está en el conjunto de datos de entrenamiento hasta ahora. + <b>%n segmentos</b> de tu conducción están en el conjunto de datos de entrenamiento hasta ahora. - - sunnypilot learns to drive by watching humans, like you, drive. - -Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode. - - <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to an unmetered network - + <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVO</span>: conéctate a una red sin límite de datos Firehose Mode - + Modo manguera contra incendios @@ -649,49 +406,6 @@ Firehose Mode allows you to maximize your training data uploads to improve openp MAX - - HyundaiSettings - - Off - - - - Dynamic - - - - Predictive - - - - Custom Longitudinal Tuning - - - - This feature can only be used with openpilot longitudinal control enabled. - - - - Enable "Always Offroad" in Device panel, or turn vehicle off to select an option. - - - - Off: Uses default tuning - - - - Dynamic: Adjusts acceleration limits based on current speed - - - - Predictive: Uses future trajectory data to anticipate needed adjustments - - - - Fine-tune your driving experience by adjusting acceleration smoothness with openpilot longitudinal control. - - - InputDialog @@ -706,321 +420,6 @@ Firehose Mode allows you to maximize your training data uploads to improve openp - - LaneChangeSettings - - Back - - - - Auto Lane Change: Delay with Blind Spot - - - - Toggle to enable a delay timer for seamless lane changes when blind spot monitoring (BSM) detects a obstructing vehicle, ensuring safe maneuvering. - - - - - LateralPanel - - Modular Assistive Driving System (MADS) - - - - Enable the beloved MADS feature. Disable toggle to revert back to stock sunnypilot engagement/disengagement. - - - - Customize MADS - - - - Customize Lane Change - - - - Enables independent engagements of Automatic Lane Centering (ALC) and Adaptive Cruise Control (ACC). - - - - Start the vehicle to check vehicle compatibility. - - - - This platform supports all MADS settings. - - - - This platform supports limited MADS settings. - - - - Pause Lateral Control with Blinker - - - - Pause lateral control with blinker when traveling below the desired speed selected. - - - - - LongitudinalPanel - - Custom ACC Speed Increments - - - - Enable custom Short & Long press increments for cruise speed increase/decrease. - - - - This feature can only be used with openpilot longitudinal control enabled. - - - - This feature is not supported on this platform due to vehicle limitations. - - - - Start the vehicle to check vehicle compatibility. - - - - - MadsSettings - - Toggle with Main Cruise - - - - Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement. - - - - Unified Engagement Mode (UEM) - - - - Engage lateral and longitudinal control with cruise control engagement. - - - - Note: Once lateral control is engaged via UEM, it will remain engaged until it is manually disabled via the MADS button or car shut off. - - - - Remain Active - - - - Disengage - - - - Steering Mode on Brake Pedal - - - - Start the vehicle to check vehicle compatibility. - - - - This feature defaults to OFF, and does not allow selection due to vehicle limitations. - - - - This feature defaults to ON, and does not allow selection due to vehicle limitations. - - - - This platform only supports Disengage mode due to vehicle limitations. - - - - Remain Active: ALC will remain active when the brake pedal is pressed. - - - - Pause - - - - Pause: ALC will pause when the brake pedal is pressed. - - - - Disengage: ALC will disengage when the brake pedal is pressed. - - - - Choose how Automatic Lane Centering (ALC) behaves after the brake pedal is manually pressed in sunnypilot. - - - - - MaxTimeOffroad - - Max Time Offroad - - - - Device will automatically shutdown after set time once the engine is turned off.<br/>(30h is the default) - - - - Always On - - - - h - - - - m - - - - (default) - - - - - ModelsPanel - - Current Model - - - - SELECT - SELECCIONAR - - - downloaded - - - - ready - - - - from cache - - - - Fetching models... - - - - Select a Model - - - - Default - - - - Model download has started in the background. - - - - We STRONGLY suggest you to reset calibration. - - - - Would you like to do that now? - - - - Reset Calibration - Formatear Calibración - - - Driving Model Selector - - - - Warning: You are on a metered connection! - - - - Continue - Continuar - - - on Metered - - - - Cancel - Cancelar - - - Clear Model Cache - - - - CLEAR - - - - Driving Model - - - - Navigation Model - - - - Vision Model - - - - Policy Model - - - - Live Learning Steer Delay - - - - Adjust Software Delay - - - - Adjust the software delay when Live Learning Steer Delay is toggled off. -The default software delay value is 0.2 - - - - %1 - %2 - - - - download failed - %1 - - - - pending - %1 - - - - Enable this for the car to learn and adapt its steering response time. Disable to use a fixed steering response time. Keeping this on provides the stock openpilot experience. The Current value is updated automatically when the vehicle is Onroad. - - - - Current: - - - - This will delete ALL downloaded models from the cache<br/><u>except the currently active model</u>.<br/><br/>Are you sure you want to continue? - - - - Clear Cache - - - MultiOptionDialog @@ -1051,76 +450,6 @@ The default software delay value is 0.2 Contraseña incorrecta - - NetworkingSP - - Scan - - - - Scanning... - - - - - NeuralNetworkLateralControl - - Neural Network Lateral Control (NNLC) - - - - NNLC is currently not available on this platform. - - - - Start the car to check car compatibility - - - - NNLC Not Loaded - - - - NNLC Loaded - - - - Match - - - - Exact - - - - Fuzzy - - - - Match: "Exact" is ideal, but "Fuzzy" is fine too. - - - - Formerly known as <b>"NNFF"</b>, this replaces the lateral <b>"torque"</b> controller, with one using a neural network trained on each car's (actually, each separate EPS firmware) driving data for increased controls accuracy. - - - - Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server - - - - with feedback, or to provide log data for your car if your car is currently unsupported: - - - - if there are any issues: - - - - and donate logs to get NNLC loaded for your car: - - - OffroadAlert @@ -1128,12 +457,12 @@ The default software delay value is 0.2 La temperatura del dispositivo es muy alta. El sistema se está enfriando antes de iniciar. Temperatura actual del componente interno: %1 - Immediately connect to the internet to check for updates. If you do not connect to the internet, sunnypilot won't engage in %1 - Conéctese inmediatamente al internet para buscar actualizaciones. Si no se conecta al internet, sunnypilot no iniciará en %1 + Immediately connect to the internet to check for updates. If you do not connect to the internet, openpilot won't engage in %1 + Conéctese inmediatamente al internet para buscar actualizaciones. Si no se conecta al internet, openpilot no iniciará en %1 - Connect to internet to check for updates. sunnypilot won't automatically start until it connects to internet to check for updates. - Conectese al internet para buscar actualizaciones. sunnypilot no iniciará automáticamente hasta conectarse al internet para buscar actualizaciones. + Connect to internet to check for updates. openpilot won't automatically start until it connects to internet to check for updates. + Conectese al internet para buscar actualizaciones. openpilot no iniciará automáticamente hasta conectarse al internet para buscar actualizaciones. Unable to download updates @@ -1149,30 +478,32 @@ The default software delay value is 0.2 An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. Se está descargando una actualización del sistema operativo de su dispositivo en segundo plano. Se le pedirá que actualice cuando esté listo para instalarse. - - Device failed to register. It will not connect to or upload to comma.ai servers, and receives no support from comma.ai. If this is an official device, visit https://comma.ai/support. - El dispositivo no pudo registrarse. No se conectará ni subirá datos a los servidores de comma.ai y no recibe soporte de comma.ai. Si este es un dispositivo oficial, visite https://comma.ai/support. - NVMe drive not mounted. Unidad NVMe no montada. - Unsupported NVMe drive detected. Device may draw significantly more power and overheat due to the unsupported NVMe. - Se detectó una unidad NVMe incompatible. El dispositivo puede consumir mucha más energía y sobrecalentarse debido a esto. + openpilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. + openpilot no pudo identificar su automóvil. Su automóvil no es compatible o no se reconocen sus ECU. Por favor haga un pull request para agregar las versiones de firmware del vehículo adecuado. ¿Necesita ayuda? Únase a discord.comma.ai. - sunnypilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. - sunnypilot no pudo identificar su automóvil. Su automóvil no es compatible o no se reconocen sus ECU. Por favor haga un pull request para agregar las versiones de firmware del vehículo adecuado. ¿Necesita ayuda? Únase a discord.comma.ai. + openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. + openpilot detectó un cambio en la posición de montaje del dispositivo. Asegúrese de que el dispositivo esté completamente asentado en el soporte y que el soporte esté firmemente asegurado al parabrisas. - sunnypilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. - sunnypilot detectó un cambio en la posición de montaje del dispositivo. Asegúrese de que el dispositivo esté completamente asentado en el soporte y que el soporte esté firmemente asegurado al parabrisas. + Device failed to register with the comma.ai backend. It will not connect or upload to comma.ai servers, and receives no support from comma.ai. If this is a device purchased at comma.ai/shop, open a ticket at https://comma.ai/support. + - OpenStreetMap database is out of date. New maps must be downloaded if you wish to continue using OpenStreetMap data for Enhanced Speed Control and road name display. - -%1 + Acknowledge Excessive Actuation + + + + Snooze Update + Posponer Actualización + + + openpilot has detected excessive %1 actuation. This may be due to a software bug. Please contact support at https://comma.ai/support. @@ -1191,18 +522,11 @@ The default software delay value is 0.2 ALERTA - - OffroadHomeSP - - ALWAYS OFFROAD ACTIVE - - - OnroadAlerts - sunnypilot Unavailable - sunnypilot no disponible + openpilot Unavailable + openpilot no disponible TAKE CONTROL IMMEDIATELY @@ -1221,137 +545,6 @@ The default software delay value is 0.2 Systema no responde - - OsmPanel - - Mapd Version - - - - Offline Maps ETA - - - - Time Elapsed - - - - Downloaded Maps - - - - DELETE - - - - This will delete ALL downloaded maps - -Are you sure you want to delete all the maps? - - - - Yes, delete all the maps. - - - - Database Update - - - - CHECK - VERIFICAR - - - Country - - - - SELECT - SELECCIONAR - - - Fetching Country list... - - - - State - - - - Fetching State list... - - - - All - - - - REFRESH - - - - UPDATE - ACTUALIZAR - - - Download starting... - - - - Error: Invalid download. Retry. - - - - Download complete! - - - - - -Warning: You are on a metered connection! - - - - This will start the download process and it might take a while to complete. - - - - Continue on Metered - - - - Start Download - - - - m - - - - s - - - - Calculating... - - - - Downloaded - - - - Calculating ETA... - - - - Ready - - - - Time remaining: - - - PairingPopup @@ -1386,96 +579,6 @@ Warning: You are on a metered connection! Cancelar - - ParamControlSP - - Enable - Activar - - - Cancel - Cancelar - - - - PlatformSelector - - Vehicle - - - - SEARCH - - - - Search your vehicle - - - - Enter model year (e.g., 2021) and model name (Toyota Corolla): - - - - SEARCHING - - - - REMOVE - ELIMINAR - - - This setting will take effect immediately. - - - - This setting will take effect once the device enters offroad state. - - - - Vehicle Selector - - - - Confirm - Confirmar - - - Cancel - Cancelar - - - No vehicles found for query: %1 - - - - Select a vehicle - - - - Unrecognized Vehicle - - - - Fingerprinted automatically - - - - Manually selected - - - - Not fingerprinted or manually selected - - - - Select vehicle to force fingerprint manually. - - - - Colors represent fingerprint status: - - - PrimeAdWidget @@ -1521,8 +624,8 @@ Warning: You are on a metered connection! QObject - sunnypilot - sunnypilot + openpilot + openpilot now @@ -1550,47 +653,6 @@ Warning: You are on a metered connection! - - Reset - - Reset failed. Reboot to try again. - Formateo fallido. Reinicie para reintentar. - - - Resetting device... -This may take up to a minute. - formateando dispositivo... -Esto puede tardar un minuto. - - - Are you sure you want to reset your device? - ¿Seguro que quiere formatear su dispositivo? - - - System Reset - Formatear Sistema - - - System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot. - Formateo del sistema activado. Presione confirmar para borrar todo el contenido y la configuración. Presione cancelar para reanudar el inicio. - - - Cancel - Cancelar - - - Reboot - Reiniciar - - - Confirm - Confirmar - - - Unable to mount data partition. Partition may be corrupted. Press confirm to erase and reset your device. - No es posible montar una partición de datos. La partición podría estar corrompida. Confirme para borrar y formatear su dispositivo. - - SettingsWindow @@ -1619,70 +681,7 @@ Esto puede tardar un minuto. Firehose - - - - - SettingsWindowSP - - × - × - - - Device - Dispositivo - - - Network - Red - - - sunnylink - - - - Toggles - Ajustes - - - Software - Software - - - Trips - - - - Vehicle - - - - Developer - Desarrollador - - - Firehose - - - - Steering - - - - Models - - - - Cruise - - - - Visuals - - - - OSM - + Firehose @@ -1744,8 +743,8 @@ Esto puede tardar un minuto. Elija el software a instalar - sunnypilot - sunnypilot + openpilot + openpilot Custom Software @@ -1781,13 +780,15 @@ Esto puede tardar un minuto. WARNING: Custom Software - + ADVERTENCIA: Software personalizado Use caution when installing third-party software. Third-party software has not been tested by comma, and may cause damage to your device and/or vehicle. If you'd like to proceed, use https://flash.comma.ai to restore your device to a factory state later. - + Tenga cuidado al instalar software de terceros. El software de terceros no ha sido probado por comma y puede causar daños a su dispositivo y/o vehículo. + +Si desea continuar, utilice https://flash.comma.ai para restaurar su dispositivo a un estado de fábrica más tarde. @@ -1880,33 +881,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 5G - - SidebarSP - - DISABLED - - - - OFFLINE - OFFLINE - - - REGIST... - - - - ONLINE - EN LÍNEA - - - ERROR - ERROR - - - SUNNYLINK - - - SoftwarePanel @@ -1982,49 +956,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device actualizado, último chequeo %1 - - SoftwarePanelSP - - Search Branch - - - - Enter search keywords, or leave blank to list all branches. - - - - No branches found for keywords: %1 - - - - Select a branch - Selecione una rama - - - Disable Updates - - - - When enabled, software updates will be disabled. <b>This requires a reboot to take effect.</b> - - - - %1 updates requires a reboot.<br>Reboot now? - - - - Reboot - Reiniciar - - - When enabled, software updates will be disabled.<br><b>This requires a reboot to take effect.</b> - - - - Please enable always offroad mode or turn off vehicle to adjust these toggles - - - SshControl @@ -2071,168 +1002,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device Habilitar SSH - - SunnylinkPanel - - This is the master switch, it will allow you to cutoff any sunnylink requests should you want to do that. - - - - Enable sunnylink - - - - 🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀 - - - - 👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉. - - - - Device ID - - - - N/A - N/A - - - Sponsor Status - Estado de patrocinio - - - SPONSOR - PATROCINADOR - - - Become a sponsor of sunnypilot to get early access to sunnylink features when they become available. - Conviértete en patrocinador de sunnypilot para obtener acceso anticipado a las funciones de sunnylink cuando estén disponibles. - - - Pair GitHub Account - Emparejar cuenta de GitHub - - - PAIR - EMPAREJAR - - - Pair your GitHub account to grant your device sponsor benefits, including API access on sunnylink. - Empareja tu cuenta de GitHub para otorgar a tu dispositivo beneficios de patrocinador, incluido acceso a la API en sunnylink. - - - sunnylink Dongle ID not found. This may be due to weak internet connection or sunnylink registration issue. Please reboot and try again. - ID del dongle de sunnylink no encontrado. Esto puede deberse a una conexión débil o a un problema de registro en sunnylink. Por favor, reinicia y vuelve a intentarlo. - - - Not Sponsor - No patrocinador - - - Paired - Emparejado - - - Not Paired - No emparejado - - - THANKS ♥ - GRACIAS ♥ - - - Backup Settings - - - - Are you sure you want to backup sunnypilot settings? - - - - Back Up - - - - Restore Settings - - - - Are you sure you want to restore the last backed up sunnypilot settings? - - - - Restore - - - - Backup in progress %1% - - - - Backup Failed - - - - Settings backup completed. - - - - Restore in progress %1% - - - - Restore Failed - - - - Unable to restore the settings, try again later. - - - - Settings restored. Confirm to restart the interface. - - - - - SunnylinkSponsorPopup - - Scan the QR code to login to your GitHub account - Escanea el código QR para iniciar sesión en tu cuenta de GitHub - - - Follow the prompts to complete the pairing process - Sigue las indicaciones para completar el proceso de emparejamiento - - - Re-enter the "sunnylink" panel to verify sponsorship status - Vuelve a ingresar al panel de "sunnylink" para verificar el estado de patrocinio - - - If sponsorship status was not updated, please contact a moderator on Discord at https://discord.gg/sunnypilot - Si el estado de patrocinio no se actualizó, por favor contacta a un moderador en Discord en https://discord.gg/sunnypilot - - - Scan the QR code to visit sunnyhaibin's GitHub Sponsors page - Escanea el código QR para visitar la página de GitHub Sponsors de sunnyhaibin - - - Choose your sponsorship tier and confirm your support - Elige tu nivel de patrocinio y confirma tu apoyo - - - Join our community on Discord at https://discord.gg/sunnypilot and reach out to a moderator to confirm your sponsor status - Únete a nuestra comunidad en Discord en https://discord.gg/sunnypilot y contacta a un moderador para confirmar tu estado de patrocinio - - - Pair your GitHub account - Empareja tu cuenta de GitHub - - - Early Access: Become a sunnypilot Sponsor - Acceso temprano: conviértete en patrocinador de sunnypilot - - TermsPage @@ -2244,16 +1013,20 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device Aceptar - Welcome to sunnypilot - + Welcome to openpilot + Bienvenido a openpilot - You must accept the Terms and Conditions to use sunnypilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing. - + You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing. + Debe aceptar los Términos y Condiciones para usar openpilot. Lea los términos más recientes en <span style='color: #465BEA;'>https://comma.ai/terms</span> antes de continuar. TogglesPanel + + Enable openpilot + Activar openpilot + Experimental Mode Modo Experimental @@ -2263,8 +1036,8 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device Desactivar con el Acelerador - When enabled, pressing the accelerator pedal will disengage sunnypilot. - Cuando esté activado, presionar el acelerador deshabilitará sunnypilot. + When enabled, pressing the accelerator pedal will disengage openpilot. + Cuando esté activado, presionar el acelerador deshabilitará openpilot. Enable Lane Departure Warnings @@ -2279,7 +1052,7 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device Monitoreo Permanente del Conductor - Enable driver monitoring even when sunnypilot is not engaged. + Enable driver monitoring even when openpilot is not engaged. Habilitar el monitoreo del conductor incluso cuando Openpilot no esté activado. @@ -2315,20 +1088,20 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device Personalidad de conducción - Standard is recommended. In aggressive mode, sunnypilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode sunnypilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. - Se recomienda el modo estándar. En el modo agresivo, sunnypilot seguirá más cerca a los autos delante suyo y será más agresivo con el acelerador y el freno. En modo relajado, sunnypilot se mantendrá más alejado de los autos delante suyo. En automóviles compatibles, puede recorrer estas personalidades con el botón de distancia del volante. + Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. + Se recomienda el modo estándar. En el modo agresivo, openpilot seguirá más cerca a los autos delante suyo y será más agresivo con el acelerador y el freno. En modo relajado, openpilot se mantendrá más alejado de los autos delante suyo. En automóviles compatibles, puede recorrer estas personalidades con el botón de distancia del volante. - sunnypilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: - sunnypilot por defecto conduce en <b>modo chill</b>. El modo Experimental activa <b>funcionalidades en fase experimental</b>, que no están listas para el modo chill. Las funcionalidades del modo expeimental están listados abajo: + openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: + openpilot por defecto conduce en <b>modo chill</b>. El modo Experimental activa <b>funcionalidades en fase experimental</b>, que no están listas para el modo chill. Las funcionalidades del modo expeimental están listados abajo: End-to-End Longitudinal Control Control Longitudinal de Punta a Punta - Let the driving model control the gas and brakes. sunnypilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. - Dajar que el modelo de conducción controle la aceleración y el frenado. sunnypilot conducirá como piensa que lo haría una persona, incluiyendo parar en los semáforos en rojo y las señales de alto. Dado que el modelo decide la velocidad de conducción, la velocidad de crucero establecida solo actuará como el límite superior. Este recurso aún está en fase experimental; deberían esperarse errores. + Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. + Dajar que el modelo de conducción controle la aceleración y el frenado. openpilot conducirá como piensa que lo haría una persona, incluiyendo parar en los semáforos en rojo y las señales de alto. Dado que el modelo decide la velocidad de conducción, la velocidad de crucero establecida solo actuará como el límite superior. Este recurso aún está en fase experimental; deberían esperarse errores. New Driving Visualization @@ -2343,148 +1116,47 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device El modo Experimental no está disponible actualmente para este auto, ya que el ACC default del auto está siendo usado para el control longitudinal. - An alpha version of sunnypilot longitudinal control can be tested, along with Experimental mode, on non-release branches. - Se puede probar una versión experimental del control longitudinal sunnypilot, junto con el modo Experimental, en ramas no liberadas. + openpilot longitudinal control may come in a future update. + El control longitudinal de openpilot podrá llegar en futuras actualizaciones. - Enable the sunnypilot longitudinal control (alpha) toggle to allow Experimental mode. + An alpha version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + Se puede probar una versión experimental del control longitudinal openpilot, junto con el modo Experimental, en ramas no liberadas. + + + Enable the openpilot longitudinal control (alpha) toggle to allow Experimental mode. Activar el control longitudinal (fase experimental) para permitir el modo Experimental. - Enable Dynamic Experimental Control - - - - Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal. - - - - Enable sunnypilot - Activar sunnypilot - - - Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. - + Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. + Utilice el sistema openpilot para el control de crucero adaptativo y la asistencia al conductor para mantenerse en el carril. Se requiere su atención en todo momento para utilizar esta función. Changing this setting will restart openpilot if the car is powered on. - - - - openpilot longitudinal control may come in a future update. - + Cambiar esta configuración reiniciará Openpilot si el automóvil está encendido. Record and Upload Microphone Audio - + Grabar y cargar audio de micrófono Record and store microphone audio while driving. The audio will be included in the dashcam video in comma connect. - - - - - TreeOptionDialog - - Select - Seleccionar - - - Cancel - Cancelar - - - - Updater - - Update Required - Actualización Requerida - - - An operating system update is required. Connect your device to Wi-Fi for the fastest update experience. The download size is approximately 1GB. - Es necesario la actualización del sistema operativo. Conecte su dispositivo al Wi-Fi para una actualización rápida. El tamaño de descarga es de aproximadamente 1GB. - - - Connect to Wi-Fi - Conectarse a la Wi-Fi - - - Install - Instalar - - - Back - Volver - - - Loading... - Cargando... - - - Reboot - Reiniciar - - - Update failed - Actualización fallida - - - - VisualsPanel - - Show Blind Spot Warnings - - - - Enabling this will display warnings when a vehicle is detected in your blind spot as long as your car has BSM supported. - - - - Changing this setting will restart openpilot if the car is powered on. - - - - Off - - - - Distance - - - - Speed - - - - Time - - - - All - - - - Display Metrics Below Chevron - - - - Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control). - + Graba y almacena el audio del micrófono mientras conduces. El audio se incluirá en el video de la cámara del tablero en comma connect. WiFiPromptWidget Open - - - - <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span> - + Abrir Maximize your training data uploads to improve openpilot's driving models. - + Maximice sus cargas de datos de entrenamiento para mejorar los modelos de conducción de openpilot. + + + <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span> + <span style='font-family: "Noto Color Emoji";'>🔥</span> Modo Firehose <span style='font-family: Noto Color Emoji;'>🔥</span> diff --git a/selfdrive/ui/translations/main_fr.ts b/selfdrive/ui/translations/main_fr.ts index 5b11081b0c..ba1eb93b30 100644 --- a/selfdrive/ui/translations/main_fr.ts +++ b/selfdrive/ui/translations/main_fr.ts @@ -7,10 +7,6 @@ Close Fermer - - Snooze Update - Reporter la mise à jour - Reboot and Update Redémarrer et mettre à jour @@ -107,53 +103,6 @@ - - AutoLaneChangeTimer - - Auto Lane Change by Blinker - - - - Set a timer to delay the auto lane change operation when the blinker is used. No nudge on the steering wheel is required to auto lane change if a timer is set. Default is Nudge. -Please use caution when using this feature. Only use the blinker when traffic and road conditions permit. - - - - s - - - - Off - - - - Nudge - - - - Nudgeless - - - - - Brightness - - Brightness - - - - Overrides the brightness of the device. - - - - Auto (Dark) - - - - Auto - - - ConfirmationDialog @@ -168,8 +117,8 @@ Please use caution when using this feature. Only use the blinker when traffic an DeclinePage - You must accept the Terms and Conditions in order to use sunnypilot. - Vous devez accepter les conditions générales pour utiliser sunnypilot. + You must accept the Terms and Conditions in order to use openpilot. + Vous devez accepter les conditions générales pour utiliser openpilot. Back @@ -190,6 +139,18 @@ Please use caution when using this feature. Only use the blinker when traffic an Longitudinal Maneuver Mode Mode manœuvre longitudinale + + openpilot Longitudinal Control (Alpha) + Contrôle longitudinal openpilot (Alpha) + + + WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). + ATTENTION : le contrôle longitudinal openpilot est en alpha pour cette voiture et désactivera le freinage d'urgence automatique (AEB). + + + On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. + Sur cette voiture, openpilot utilise par défaut le régulateur de vitesse adaptatif intégré à la voiture plutôt que le contrôle longitudinal d'openpilot. Activez ceci pour passer au contrôle longitudinal openpilot. Il est recommandé d'activer le mode expérimental lors de l'activation du contrôle longitudinal openpilot alpha. + Enable ADB @@ -198,62 +159,6 @@ Please use caution when using this feature. Only use the blinker when traffic an ADB (Android Debug Bridge) allows connecting to your device over USB or over the network. See https://docs.comma.ai/how-to/connect-to-comma for more info. - - openpilot Longitudinal Control (Alpha) - - - - WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). - - - - On this car, sunnypilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. - - - - - DeveloperPanelSP - - Show Advanced Controls - - - - Toggle visibility of advanced sunnypilot controls. -This only toggles the visibility of the controls; it does not toggle the actual control enabled/disabled state. - - - - Enable GitHub runner service - - - - Enables or disables the github runner service. - - - - Enable Quickboot Mode - - - - Error Log - - - - VIEW - VOIR - - - View the error log for sunnypilot crashes. - - - - When toggled on, this creates a prebuilt file to allow accelerated boot times. When toggled off, it immediately removes the prebuilt file so compilation of locally edited cpp files can be made. <br><br><b>To edit C++ files locally on device, you MUST first turn off this toggle so the changes can recompile.</b> - - - - Quickboot mode requires updates to be disabled.<br>Enable 'Disable Updates' in the Software panel first. - - DevicePanel @@ -306,8 +211,8 @@ This only toggles the visibility of the controls; it does not toggle the actual REVOIR - Review the rules, features, and limitations of sunnypilot - Revoir les règles, fonctionnalités et limitations d'sunnypilot + Review the rules, features, and limitations of openpilot + Revoir les règles, fonctionnalités et limitations d'openpilot Are you sure you want to review the training guide? @@ -398,7 +303,11 @@ This only toggles the visibility of the controls; it does not toggle the actual - sunnypilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. + openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. + + + + openpilot is continuously calibrating, resetting is rarely required. Resetting calibration will restart openpilot if the car is powered on. @@ -421,149 +330,6 @@ Steering lag calibration is complete. Steering torque response calibration is complete. - - openpilot is continuously calibrating, resetting is rarely required. Resetting calibration will restart openpilot if the car is powered on. - - - - - DevicePanelSP - - Driver Camera Preview - - - - Training Guide - - - - Regulatory - Réglementaire - - - Language - - - - Are you sure you want to review the training guide? - Êtes-vous sûr de vouloir revoir le guide de formation ? - - - Review - Revoir - - - Select a language - Choisir une langue - - - Reboot - Redémarrer - - - Power Off - Éteindre - - - Offroad Mode - - - - Are you sure you want to exit Always Offroad mode? - - - - Confirm - Confirmer - - - Are you sure you want to enter Always Offroad mode? - - - - Disengage to Enter Always Offroad Mode - - - - Exit Always Offroad - - - - Always Offroad - - - - Quiet Mode - - - - Reset Settings - - - - Are you sure you want to reset all sunnypilot settings to default? Once the settings are reset, there is no going back. - - - - Reset - Réinitialiser - - - The reset cannot be undone. You have been warned. - - - - Wake-Up Behavior - - - - Interactivity Timeout - - - - Apply a custom timeout for settings UI. -This is the time after which settings UI closes automatically if user is not interacting with the screen. - - - - ⁍ Default: Device will boot/wake-up normally & will be ready to engage. - - - - ⁍ Offroad: Device will be in Always Offroad mode after boot/wake-up. - - - - Controls state of the device after boot/sleep. - - - - - DriveStats - - Drives - - - - Hours - - - - ALL TIME - - - - PAST WEEK - - - - KM - - - - Miles - - DriverViewWindow @@ -572,21 +338,6 @@ This is the time after which settings UI closes automatically if user is not int démarrage de la caméra - - ExitOffroadButton - - Are you sure you want to exit Always Offroad mode? - - - - Confirm - Confirmer - - - EXIT ALWAYS OFFROAD MODE - - - ExperimentalModeButton @@ -600,6 +351,12 @@ This is the time after which settings UI closes automatically if user is not int FirehosePanel + + openpilot learns to drive by watching humans, like you, drive. + +Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode. + + Firehose Mode: ACTIVE @@ -609,7 +366,7 @@ This is the time after which settings UI closes automatically if user is not int - For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream sunnypilot (and particular forks) are able to be used for training. + For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training. @@ -619,12 +376,6 @@ This is the time after which settings UI closes automatically if user is not int - - sunnypilot learns to drive by watching humans, like you, drive. - -Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode. - - <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to an unmetered network @@ -649,49 +400,6 @@ Firehose Mode allows you to maximize your training data uploads to improve openp MAX - - HyundaiSettings - - Off - - - - Dynamic - - - - Predictive - - - - Custom Longitudinal Tuning - - - - This feature can only be used with openpilot longitudinal control enabled. - - - - Enable "Always Offroad" in Device panel, or turn vehicle off to select an option. - - - - Off: Uses default tuning - - - - Dynamic: Adjusts acceleration limits based on current speed - - - - Predictive: Uses future trajectory data to anticipate needed adjustments - - - - Fine-tune your driving experience by adjusting acceleration smoothness with openpilot longitudinal control. - - - InputDialog @@ -706,321 +414,6 @@ Firehose Mode allows you to maximize your training data uploads to improve openp - - LaneChangeSettings - - Back - Retour - - - Auto Lane Change: Delay with Blind Spot - - - - Toggle to enable a delay timer for seamless lane changes when blind spot monitoring (BSM) detects a obstructing vehicle, ensuring safe maneuvering. - - - - - LateralPanel - - Modular Assistive Driving System (MADS) - - - - Enable the beloved MADS feature. Disable toggle to revert back to stock sunnypilot engagement/disengagement. - - - - Customize MADS - - - - Customize Lane Change - - - - Enables independent engagements of Automatic Lane Centering (ALC) and Adaptive Cruise Control (ACC). - - - - Start the vehicle to check vehicle compatibility. - - - - This platform supports all MADS settings. - - - - This platform supports limited MADS settings. - - - - Pause Lateral Control with Blinker - - - - Pause lateral control with blinker when traveling below the desired speed selected. - - - - - LongitudinalPanel - - Custom ACC Speed Increments - - - - Enable custom Short & Long press increments for cruise speed increase/decrease. - - - - This feature can only be used with openpilot longitudinal control enabled. - - - - This feature is not supported on this platform due to vehicle limitations. - - - - Start the vehicle to check vehicle compatibility. - - - - - MadsSettings - - Toggle with Main Cruise - - - - Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement. - - - - Unified Engagement Mode (UEM) - - - - Engage lateral and longitudinal control with cruise control engagement. - - - - Note: Once lateral control is engaged via UEM, it will remain engaged until it is manually disabled via the MADS button or car shut off. - - - - Remain Active - - - - Disengage - - - - Steering Mode on Brake Pedal - - - - Start the vehicle to check vehicle compatibility. - - - - This feature defaults to OFF, and does not allow selection due to vehicle limitations. - - - - This feature defaults to ON, and does not allow selection due to vehicle limitations. - - - - This platform only supports Disengage mode due to vehicle limitations. - - - - Remain Active: ALC will remain active when the brake pedal is pressed. - - - - Pause - - - - Pause: ALC will pause when the brake pedal is pressed. - - - - Disengage: ALC will disengage when the brake pedal is pressed. - - - - Choose how Automatic Lane Centering (ALC) behaves after the brake pedal is manually pressed in sunnypilot. - - - - - MaxTimeOffroad - - Max Time Offroad - - - - Device will automatically shutdown after set time once the engine is turned off.<br/>(30h is the default) - - - - Always On - - - - h - - - - m - - - - (default) - - - - - ModelsPanel - - Current Model - - - - SELECT - SÉLECTIONNER - - - downloaded - - - - ready - - - - from cache - - - - Fetching models... - - - - Select a Model - - - - Default - - - - Model download has started in the background. - - - - We STRONGLY suggest you to reset calibration. - - - - Would you like to do that now? - - - - Reset Calibration - Réinitialiser la calibration - - - Driving Model Selector - - - - Warning: You are on a metered connection! - - - - Continue - Continuer - - - on Metered - - - - Cancel - Annuler - - - Clear Model Cache - - - - CLEAR - - - - Driving Model - - - - Navigation Model - - - - Vision Model - - - - Policy Model - - - - Live Learning Steer Delay - - - - Adjust Software Delay - - - - Adjust the software delay when Live Learning Steer Delay is toggled off. -The default software delay value is 0.2 - - - - %1 - %2 - - - - download failed - %1 - - - - pending - %1 - - - - Enable this for the car to learn and adapt its steering response time. Disable to use a fixed steering response time. Keeping this on provides the stock openpilot experience. The Current value is updated automatically when the vehicle is Onroad. - - - - Current: - - - - This will delete ALL downloaded models from the cache<br/><u>except the currently active model</u>.<br/><br/>Are you sure you want to continue? - - - - Clear Cache - - - MultiOptionDialog @@ -1051,76 +444,6 @@ The default software delay value is 0.2 Mot de passe incorrect - - NetworkingSP - - Scan - - - - Scanning... - - - - - NeuralNetworkLateralControl - - Neural Network Lateral Control (NNLC) - - - - NNLC is currently not available on this platform. - - - - Start the car to check car compatibility - - - - NNLC Not Loaded - - - - NNLC Loaded - - - - Match - - - - Exact - - - - Fuzzy - - - - Match: "Exact" is ideal, but "Fuzzy" is fine too. - - - - Formerly known as <b>"NNFF"</b>, this replaces the lateral <b>"torque"</b> controller, with one using a neural network trained on each car's (actually, each separate EPS firmware) driving data for increased controls accuracy. - - - - Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server - - - - with feedback, or to provide log data for your car if your car is currently unsupported: - - - - if there are any issues: - - - - and donate logs to get NNLC loaded for your car: - - - OffroadAlert @@ -1128,12 +451,12 @@ The default software delay value is 0.2 Température de l'appareil trop élevée. Le système doit refroidir avant de démarrer. Température actuelle de l'appareil : %1 - Immediately connect to the internet to check for updates. If you do not connect to the internet, sunnypilot won't engage in %1 - Connectez-vous immédiatement à internet pour vérifier les mises à jour. Si vous ne vous connectez pas à internet, sunnypilot ne s'engagera pas dans %1 + Immediately connect to the internet to check for updates. If you do not connect to the internet, openpilot won't engage in %1 + Connectez-vous immédiatement à internet pour vérifier les mises à jour. Si vous ne vous connectez pas à internet, openpilot ne s'engagera pas dans %1 - Connect to internet to check for updates. sunnypilot won't automatically start until it connects to internet to check for updates. - Connectez l'appareil à internet pour vérifier les mises à jour. sunnypilot ne démarrera pas automatiquement tant qu'il ne se connecte pas à internet pour vérifier les mises à jour. + Connect to internet to check for updates. openpilot won't automatically start until it connects to internet to check for updates. + Connectez l'appareil à internet pour vérifier les mises à jour. openpilot ne démarrera pas automatiquement tant qu'il ne se connecte pas à internet pour vérifier les mises à jour. Unable to download updates @@ -1149,30 +472,32 @@ The default software delay value is 0.2 An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. Une mise à jour du système d'exploitation de votre appareil est en cours de téléchargement en arrière-plan. Vous serez invité à effectuer la mise à jour lorsqu'elle sera prête à être installée. - - Device failed to register. It will not connect to or upload to comma.ai servers, and receives no support from comma.ai. If this is an official device, visit https://comma.ai/support. - L'appareil n'a pas réussi à s'enregistrer. Il ne se connectera pas aux serveurs de comma.ai, n'enverra rien et ne recevra aucune assistance de comma.ai. S'il s'agit d'un appareil officiel, visitez https://comma.ai/support. - NVMe drive not mounted. Le disque NVMe n'est pas monté. - Unsupported NVMe drive detected. Device may draw significantly more power and overheat due to the unsupported NVMe. - Disque NVMe non supporté détecté. L'appareil peut consommer beaucoup plus d'énergie et surchauffer en raison du NVMe non supporté. + openpilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. + openpilot n'a pas pu identifier votre voiture. Votre voiture n'est pas supportée ou ses ECUs ne sont pas reconnues. Veuillez soumettre un pull request pour ajouter les versions de firmware au véhicule approprié. Besoin d'aide ? Rejoignez discord.comma.ai. - sunnypilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. - sunnypilot n'a pas pu identifier votre voiture. Votre voiture n'est pas supportée ou ses ECUs ne sont pas reconnues. Veuillez soumettre un pull request pour ajouter les versions de firmware au véhicule approprié. Besoin d'aide ? Rejoignez discord.comma.ai. + openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. + openpilot a détecté un changement dans la position de montage de l'appareil. Assurez-vous que l'appareil est totalement inséré dans le support et que le support est fermement fixé au pare-brise. - sunnypilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. - sunnypilot a détecté un changement dans la position de montage de l'appareil. Assurez-vous que l'appareil est totalement inséré dans le support et que le support est fermement fixé au pare-brise. + Device failed to register with the comma.ai backend. It will not connect or upload to comma.ai servers, and receives no support from comma.ai. If this is a device purchased at comma.ai/shop, open a ticket at https://comma.ai/support. + - OpenStreetMap database is out of date. New maps must be downloaded if you wish to continue using OpenStreetMap data for Enhanced Speed Control and road name display. - -%1 + Acknowledge Excessive Actuation + + + + Snooze Update + Reporter la mise à jour + + + openpilot has detected excessive %1 actuation. This may be due to a software bug. Please contact support at https://comma.ai/support. @@ -1191,18 +516,11 @@ The default software delay value is 0.2 ALERTE - - OffroadHomeSP - - ALWAYS OFFROAD ACTIVE - - - OnroadAlerts - sunnypilot Unavailable - sunnypilot indisponible + openpilot Unavailable + openpilot indisponible TAKE CONTROL IMMEDIATELY @@ -1221,137 +539,6 @@ The default software delay value is 0.2 Système inopérant - - OsmPanel - - Mapd Version - - - - Offline Maps ETA - - - - Time Elapsed - - - - Downloaded Maps - - - - DELETE - - - - This will delete ALL downloaded maps - -Are you sure you want to delete all the maps? - - - - Yes, delete all the maps. - - - - Database Update - - - - CHECK - VÉRIFIER - - - Country - - - - SELECT - SÉLECTIONNER - - - Fetching Country list... - - - - State - - - - Fetching State list... - - - - All - - - - REFRESH - - - - UPDATE - MISE À JOUR - - - Download starting... - - - - Error: Invalid download. Retry. - - - - Download complete! - - - - - -Warning: You are on a metered connection! - - - - This will start the download process and it might take a while to complete. - - - - Continue on Metered - - - - Start Download - - - - m - - - - s - - - - Calculating... - - - - Downloaded - - - - Calculating ETA... - - - - Ready - - - - Time remaining: - - - PairingPopup @@ -1386,96 +573,6 @@ Warning: You are on a metered connection! Annuler - - ParamControlSP - - Enable - Activer - - - Cancel - Annuler - - - - PlatformSelector - - Vehicle - - - - SEARCH - - - - Search your vehicle - - - - Enter model year (e.g., 2021) and model name (Toyota Corolla): - - - - SEARCHING - - - - REMOVE - SUPPRIMER - - - This setting will take effect immediately. - - - - This setting will take effect once the device enters offroad state. - - - - Vehicle Selector - - - - Confirm - Confirmer - - - Cancel - Annuler - - - No vehicles found for query: %1 - - - - Select a vehicle - - - - Unrecognized Vehicle - - - - Fingerprinted automatically - - - - Manually selected - - - - Not fingerprinted or manually selected - - - - Select vehicle to force fingerprint manually. - - - - Colors represent fingerprint status: - - - PrimeAdWidget @@ -1521,8 +618,8 @@ Warning: You are on a metered connection! QObject - sunnypilot - sunnypilot + openpilot + openpilot %n minute(s) ago @@ -1550,47 +647,6 @@ Warning: You are on a metered connection! maintenant - - Reset - - Reset failed. Reboot to try again. - Réinitialisation échouée. Redémarrez pour réessayer. - - - Resetting device... -This may take up to a minute. - Réinitialisation de l'appareil... -Cela peut prendre jusqu'à une minute. - - - Are you sure you want to reset your device? - Êtes-vous sûr de vouloir réinitialiser votre appareil ? - - - System Reset - Réinitialisation du système - - - Cancel - Annuler - - - Reboot - Redémarrer - - - Confirm - Confirmer - - - Unable to mount data partition. Partition may be corrupted. Press confirm to erase and reset your device. - Impossible de monter la partition data. La partition peut être corrompue. Appuyez sur confirmer pour effacer et réinitialiser votre appareil. - - - System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot. - Réinitialisation système déclenchée. Appuyez sur confirmer pour effacer tout le contenu et les paramètres. Appuyez sur annuler pour reprendre le démarrage. - - SettingsWindow @@ -1622,69 +678,6 @@ Cela peut prendre jusqu'à une minute. - - SettingsWindowSP - - × - × - - - Device - Appareil - - - Network - Réseau - - - sunnylink - - - - Toggles - Options - - - Software - Logiciel - - - Trips - - - - Vehicle - - - - Developer - Dév. - - - Firehose - - - - Steering - - - - Models - - - - Cruise - - - - Visuals - - - - OSM - - - Setup @@ -1772,8 +765,8 @@ Cela peut prendre jusqu'à une minute. Choisir le logiciel à installer - sunnypilot - sunnypilot + openpilot + openpilot Custom Software @@ -1880,33 +873,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 5G - - SidebarSP - - DISABLED - - - - OFFLINE - HORS LIGNE - - - REGIST... - - - - ONLINE - EN LIGNE - - - ERROR - ERREUR - - - SUNNYLINK - - - SoftwarePanel @@ -1982,49 +948,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device à jour, dernière vérification %1 - - SoftwarePanelSP - - Search Branch - - - - Enter search keywords, or leave blank to list all branches. - - - - No branches found for keywords: %1 - - - - Select a branch - Sélectionner une branche - - - Disable Updates - - - - When enabled, software updates will be disabled. <b>This requires a reboot to take effect.</b> - - - - %1 updates requires a reboot.<br>Reboot now? - - - - Reboot - Redémarrer - - - When enabled, software updates will be disabled.<br><b>This requires a reboot to take effect.</b> - - - - Please enable always offroad mode or turn off vehicle to adjust these toggles - - - SshControl @@ -2071,168 +994,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device Activer SSH - - SunnylinkPanel - - This is the master switch, it will allow you to cutoff any sunnylink requests should you want to do that. - - - - Enable sunnylink - - - - 🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀 - - - - 👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉. - - - - Device ID - - - - N/A - N/A - - - Sponsor Status - - - - SPONSOR - - - - Become a sponsor of sunnypilot to get early access to sunnylink features when they become available. - - - - Pair GitHub Account - - - - PAIR - ASSOCIER - - - Pair your GitHub account to grant your device sponsor benefits, including API access on sunnylink. - - - - sunnylink Dongle ID not found. This may be due to weak internet connection or sunnylink registration issue. Please reboot and try again. - - - - Not Sponsor - - - - Paired - - - - Not Paired - - - - THANKS ♥ - - - - Backup Settings - - - - Are you sure you want to backup sunnypilot settings? - - - - Back Up - - - - Restore Settings - - - - Are you sure you want to restore the last backed up sunnypilot settings? - - - - Restore - - - - Backup in progress %1% - - - - Backup Failed - - - - Settings backup completed. - - - - Restore in progress %1% - - - - Restore Failed - - - - Unable to restore the settings, try again later. - - - - Settings restored. Confirm to restart the interface. - - - - - SunnylinkSponsorPopup - - Scan the QR code to login to your GitHub account - - - - Follow the prompts to complete the pairing process - - - - Re-enter the "sunnylink" panel to verify sponsorship status - - - - If sponsorship status was not updated, please contact a moderator on Discord at https://discord.gg/sunnypilot - - - - Scan the QR code to visit sunnyhaibin's GitHub Sponsors page - - - - Choose your sponsorship tier and confirm your support - - - - Join our community on Discord at https://discord.gg/sunnypilot and reach out to a moderator to confirm your sponsor status - - - - Pair your GitHub account - - - - Early Access: Become a sunnypilot Sponsor - - - TermsPage @@ -2244,16 +1005,20 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device Accepter - Welcome to sunnypilot + Welcome to openpilot - You must accept the Terms and Conditions to use sunnypilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing. + You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing. TogglesPanel + + Enable openpilot + Activer openpilot + Experimental Mode Mode expérimental @@ -2263,8 +1028,8 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device Désengager avec la pédale d'accélérateur - When enabled, pressing the accelerator pedal will disengage sunnypilot. - Lorsqu'il est activé, appuyer sur la pédale d'accélérateur désengagera sunnypilot. + When enabled, pressing the accelerator pedal will disengage openpilot. + Lorsqu'il est activé, appuyer sur la pédale d'accélérateur désengagera openpilot. Enable Lane Departure Warnings @@ -2307,12 +1072,12 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device Personnalité de conduite - sunnypilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: - Par défaut, sunnypilot conduit en <b>mode détente</b>. Le mode expérimental permet d'activer des <b>fonctionnalités alpha</b> qui ne sont pas prêtes pour le mode détente. Les fonctionnalités expérimentales sont listées ci-dessous : + openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: + Par défaut, openpilot conduit en <b>mode détente</b>. Le mode expérimental permet d'activer des <b>fonctionnalités alpha</b> qui ne sont pas prêtes pour le mode détente. Les fonctionnalités expérimentales sont listées ci-dessous : - Let the driving model control the gas and brakes. sunnypilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. - Laissez le modèle de conduite contrôler l'accélérateur et les freins. sunnypilot conduira comme il pense qu'un humain le ferait, y compris s'arrêter aux feux rouges et aux panneaux stop. Comme le modèle de conduite décide de la vitesse à adopter, la vitesse définie ne servira que de limite supérieure. Cette fonctionnalité est de qualité alpha ; des erreurs sont à prévoir. + Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. + Laissez le modèle de conduite contrôler l'accélérateur et les freins. openpilot conduira comme il pense qu'un humain le ferait, y compris s'arrêter aux feux rouges et aux panneaux stop. Comme le modèle de conduite décide de la vitesse à adopter, la vitesse définie ne servira que de limite supérieure. Cette fonctionnalité est de qualité alpha ; des erreurs sont à prévoir. New Driving Visualization @@ -2323,20 +1088,24 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device Le mode expérimental est actuellement indisponible pour cette voiture car le régulateur de vitesse adaptatif d'origine est utilisé pour le contrôle longitudinal. - An alpha version of sunnypilot longitudinal control can be tested, along with Experimental mode, on non-release branches. - Une version alpha du contrôle longitudinal sunnypilot peut être testée, avec le mode expérimental, sur des branches non publiées. + openpilot longitudinal control may come in a future update. + Le contrôle longitudinal openpilot pourrait être disponible dans une future mise à jour. + + + An alpha version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + Une version alpha du contrôle longitudinal openpilot peut être testée, avec le mode expérimental, sur des branches non publiées. End-to-End Longitudinal Control Contrôle longitudinal de bout en bout - Enable the sunnypilot longitudinal control (alpha) toggle to allow Experimental mode. - Activer le contrôle longitudinal d'sunnypilot (en alpha) pour autoriser le mode expérimental. + Enable the openpilot longitudinal control (alpha) toggle to allow Experimental mode. + Activer le contrôle longitudinal d'openpilot (en alpha) pour autoriser le mode expérimental. - Standard is recommended. In aggressive mode, sunnypilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode sunnypilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. - Le mode Standard est recommandé. En mode Agressif, sunnypilot suivra les véhicules de plus près et sera plus dynamique avec l'accélérateur et le frein. En mode Détendu, sunnypilot maintiendra une distance plus importante avec les véhicules qui précèdent. Sur les véhicules compatibles, vous pouvez alterner entre ces personnalités à l'aide du bouton de distance au volant. + Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. + Le mode Standard est recommandé. En mode Agressif, openpilot suivra les véhicules de plus près et sera plus dynamique avec l'accélérateur et le frein. En mode Détendu, openpilot maintiendra une distance plus importante avec les véhicules qui précèdent. Sur les véhicules compatibles, vous pouvez alterner entre ces personnalités à l'aide du bouton de distance au volant. The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. @@ -2347,33 +1116,17 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device Surveillance continue du conducteur - Enable driver monitoring even when sunnypilot is not engaged. - Activer la surveillance conducteur lorsque sunnypilot n'est pas actif. + Enable driver monitoring even when openpilot is not engaged. + Activer la surveillance conducteur lorsque openpilot n'est pas actif. - Enable Dynamic Experimental Control - - - - Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal. - - - - Enable sunnypilot - Activer sunnypilot - - - Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. + Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting will restart openpilot if the car is powered on. - - openpilot longitudinal control may come in a future update. - - Record and Upload Microphone Audio @@ -2383,95 +1136,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device - - TreeOptionDialog - - Select - Sélectionner - - - Cancel - Annuler - - - - Updater - - Update Required - Mise à jour requise - - - An operating system update is required. Connect your device to Wi-Fi for the fastest update experience. The download size is approximately 1GB. - Une mise à jour du système d'exploitation est requise. Connectez votre appareil au Wi-Fi pour une mise à jour plus rapide. La taille du téléchargement est d'environ 1 Go. - - - Connect to Wi-Fi - Se connecter au Wi-Fi - - - Install - Installer - - - Back - Retour - - - Loading... - Chargement... - - - Reboot - Redémarrer - - - Update failed - Échec de la mise à jour - - - - VisualsPanel - - Show Blind Spot Warnings - - - - Enabling this will display warnings when a vehicle is detected in your blind spot as long as your car has BSM supported. - - - - Changing this setting will restart openpilot if the car is powered on. - - - - Off - - - - Distance - - - - Speed - - - - Time - - - - All - - - - Display Metrics Below Chevron - - - - Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control). - - - WiFiPromptWidget @@ -2479,11 +1143,11 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device - <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span> + Maximize your training data uploads to improve openpilot's driving models. - Maximize your training data uploads to improve openpilot's driving models. + <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span> diff --git a/selfdrive/ui/translations/main_ja.ts b/selfdrive/ui/translations/main_ja.ts index dae752b14c..fea6e51c07 100644 --- a/selfdrive/ui/translations/main_ja.ts +++ b/selfdrive/ui/translations/main_ja.ts @@ -7,10 +7,6 @@ Close 閉じる - - Snooze Update - 更新の一時停止 - Reboot and Update 再起動してアップデート @@ -84,74 +80,27 @@ Prevent large data uploads when on a metered cellular connection - + モバイルデータ回線を使用しているときは大容量データをアップロードしません default - + 標準設定 metered - + 従量制 unmetered - + 定額制 Wi-Fi Network Metered - + 従量制のWi-Fiネットワーク Prevent large data uploads when on a metered Wi-Fi connection - - - - - AutoLaneChangeTimer - - Auto Lane Change by Blinker - - - - Set a timer to delay the auto lane change operation when the blinker is used. No nudge on the steering wheel is required to auto lane change if a timer is set. Default is Nudge. -Please use caution when using this feature. Only use the blinker when traffic and road conditions permit. - - - - s - - - - Off - - - - Nudge - - - - Nudgeless - - - - - Brightness - - Brightness - - - - Overrides the brightness of the device. - - - - Auto (Dark) - - - - Auto - + 通信制限のあるWi-Fi接続では大容量データをアップロードしません @@ -168,8 +117,8 @@ Please use caution when using this feature. Only use the blinker when traffic an DeclinePage - You must accept the Terms and Conditions in order to use sunnypilot. - sunnypilotを使用するためには利用規約に同意する必要があります + You must accept the Terms and Conditions in order to use openpilot. + openpilotを使用するためには利用規約に同意する必要があります Back @@ -190,6 +139,18 @@ Please use caution when using this feature. Only use the blinker when traffic an Longitudinal Maneuver Mode アクセル制御マニューバー + + openpilot Longitudinal Control (Alpha) + openpilotアクセル制御(Alpha) + + + WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). + この車ではopenpilotのアクセル制御はアルファ版であり、自動緊急ブレーキ(AEB)が無効化されます。 + + + On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. + この車では、openpilotは車両内蔵のACC(アダプティブクルーズコントロール)をデフォルトとして使用し、openpilotのアクセル制御は無効化されています。アクセル制御をopenpilotに切り替えるにはこの設定を有効にしてください。また同時にExperimentalモードを推奨します。 + Enable ADB ADBを有効にする @@ -198,62 +159,6 @@ Please use caution when using this feature. Only use the blinker when traffic an ADB (Android Debug Bridge) allows connecting to your device over USB or over the network. See https://docs.comma.ai/how-to/connect-to-comma for more info. ADB(Android Debug Bridge)により、USBまたはネットワーク経由でデバイスに接続できます。詳細は、https://docs.comma.ai/how-to/connect-to-comma を参照してください。 - - openpilot Longitudinal Control (Alpha) - - - - WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). - - - - On this car, sunnypilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. - - - - - DeveloperPanelSP - - Show Advanced Controls - - - - Toggle visibility of advanced sunnypilot controls. -This only toggles the visibility of the controls; it does not toggle the actual control enabled/disabled state. - - - - Enable GitHub runner service - - - - Enables or disables the github runner service. - - - - Enable Quickboot Mode - - - - Error Log - - - - VIEW - 確認 - - - View the error log for sunnypilot crashes. - - - - When toggled on, this creates a prebuilt file to allow accelerated boot times. When toggled off, it immediately removes the prebuilt file so compilation of locally edited cpp files can be made. <br><br><b>To edit C++ files locally on device, you MUST first turn off this toggle so the changes can recompile.</b> - - - - Quickboot mode requires updates to be disabled.<br>Enable 'Disable Updates' in the Software panel first. - - DevicePanel @@ -302,8 +207,8 @@ This only toggles the visibility of the controls; it does not toggle the actual 確認 - Review the rules, features, and limitations of sunnypilot - sunnypilotのルール、機能、および制限を確認してください + Review the rules, features, and limitations of openpilot + openpilotのルール、機能、および制限を確認してください Are you sure you want to review the training guide? @@ -395,174 +300,39 @@ This only toggles the visibility of the controls; it does not toggle the actual Disengage to Reset Calibration - + キャリブレーションをリセットするには運転支援を解除して下さい。 - sunnypilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. - + openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. + openpilotの本体は左右4°以内、上5°下9°以内の角度で取付ける必要があります。 + + + openpilot is continuously calibrating, resetting is rarely required. Resetting calibration will restart openpilot if the car is powered on. + openpilot は継続的にキャリブレーションを行っており、リセットが必要になることはほとんどありません。キャリブレーションをリセットすると、車の電源が入っている場合はopenpilotが再起動します。 Steering lag calibration is %1% complete. - + + +ステアリング遅延のキャリブレーションが%1%完了。 Steering lag calibration is complete. - + + +ステアリング遅延のキャリブレーション完了。 Steering torque response calibration is %1% complete. - + ステアリングトルク応答のキャリブレーションが%1%完了。 Steering torque response calibration is complete. - - - - openpilot is continuously calibrating, resetting is rarely required. Resetting calibration will restart openpilot if the car is powered on. - - - - - DevicePanelSP - - Driver Camera Preview - - - - Training Guide - - - - Regulatory - 規約 - - - Language - - - - Are you sure you want to review the training guide? - トレーニングガイドを始めてもよろしいですか? - - - Review - 見る - - - Select a language - 言語を選択 - - - Reboot - 再起動 - - - Power Off - パワーオフ - - - Offroad Mode - - - - Are you sure you want to exit Always Offroad mode? - - - - Confirm - 確認 - - - Are you sure you want to enter Always Offroad mode? - - - - Disengage to Enter Always Offroad Mode - - - - Exit Always Offroad - - - - Always Offroad - - - - Quiet Mode - - - - Reset Settings - - - - Are you sure you want to reset all sunnypilot settings to default? Once the settings are reset, there is no going back. - - - - Reset - リセット - - - The reset cannot be undone. You have been warned. - - - - Wake-Up Behavior - - - - Interactivity Timeout - - - - Apply a custom timeout for settings UI. -This is the time after which settings UI closes automatically if user is not interacting with the screen. - - - - ⁍ Default: Device will boot/wake-up normally & will be ready to engage. - - - - ⁍ Offroad: Device will be in Always Offroad mode after boot/wake-up. - - - - Controls state of the device after boot/sleep. - - - - - DriveStats - - Drives - - - - Hours - - - - ALL TIME - - - - PAST WEEK - - - - KM - - - - Miles - + ステアリングトルク応答のキャリブレーション完了。 @@ -572,21 +342,6 @@ This is the time after which settings UI closes automatically if user is not int カメラ起動中 - - ExitOffroadButton - - Are you sure you want to exit Always Offroad mode? - - - - Confirm - 確認 - - - EXIT ALWAYS OFFROAD MODE - - - ExperimentalModeButton @@ -600,37 +355,39 @@ This is the time after which settings UI closes automatically if user is not int FirehosePanel + + openpilot learns to drive by watching humans, like you, drive. + +Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode. + openpilotは人間であるあなたの運転から学び、AI学習します。 + +Firehoseモードを有効にすると学習データを最大限アップロードし、openpilotの運転モデルを改善することができます。より多くのデータはより大きなモデルとなり、Experimentalモードの精度を向上させます。 + Firehose Mode: ACTIVE - + Firehoseモード: 作動中 ACTIVE - + 動作中 - For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream sunnypilot (and particular forks) are able to be used for training. - + For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training. + 最大の効果を得るためにはデバイスを屋内に持ち込み、大容量のUSB-C充電器とWi-Fiに毎週接続してください。<br><br>Firehoseモードは公衆無線LANや大容量契約のSIMカードに接続していれば、運転中でも動作します。<br><br><br><b>よくある質問(FAQ)</b><br><br><i>運転のやり方や走る場所は重要ですか?</i> いいえ、普段どおりに運転するだけで大丈夫です。<br><br><i>Firehoseモードでは全てのデータがアップロードされますか?</i> いいえ、アップロードするデータを選ぶことができます。<br><br><i>大容量のUSB-C充電器とは何ですか?</i> スマートフォンやノートパソコンを高速に充電できるものを使って下さい。<br><br><i>どのフォークを使うかは重要ですか?</i>はい、トレーニングには公式のopenpilot(および特定のフォーク)のみが使用できます。 <b>%n segment(s)</b> of your driving is in the training dataset so far. - - + + あなたの運転の<b>%nセグメント</b>がこれまでのトレーニングデータに含まれています。 - - sunnypilot learns to drive by watching humans, like you, drive. - -Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode. - - <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to an unmetered network <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>動作停止</span>: 大容量のネットワークに接続してください Firehose Mode - + Firehoseモード @@ -648,49 +405,6 @@ Firehose Mode allows you to maximize your training data uploads to improve openp 最大速度 - - HyundaiSettings - - Off - - - - Dynamic - - - - Predictive - - - - Custom Longitudinal Tuning - - - - This feature can only be used with openpilot longitudinal control enabled. - - - - Enable "Always Offroad" in Device panel, or turn vehicle off to select an option. - - - - Off: Uses default tuning - - - - Dynamic: Adjusts acceleration limits based on current speed - - - - Predictive: Uses future trajectory data to anticipate needed adjustments - - - - Fine-tune your driving experience by adjusting acceleration smoothness with openpilot longitudinal control. - - - InputDialog @@ -704,321 +418,6 @@ Firehose Mode allows you to maximize your training data uploads to improve openp - - LaneChangeSettings - - Back - 戻る - - - Auto Lane Change: Delay with Blind Spot - - - - Toggle to enable a delay timer for seamless lane changes when blind spot monitoring (BSM) detects a obstructing vehicle, ensuring safe maneuvering. - - - - - LateralPanel - - Modular Assistive Driving System (MADS) - - - - Enable the beloved MADS feature. Disable toggle to revert back to stock sunnypilot engagement/disengagement. - - - - Customize MADS - - - - Customize Lane Change - - - - Enables independent engagements of Automatic Lane Centering (ALC) and Adaptive Cruise Control (ACC). - - - - Start the vehicle to check vehicle compatibility. - - - - This platform supports all MADS settings. - - - - This platform supports limited MADS settings. - - - - Pause Lateral Control with Blinker - - - - Pause lateral control with blinker when traveling below the desired speed selected. - - - - - LongitudinalPanel - - Custom ACC Speed Increments - - - - Enable custom Short & Long press increments for cruise speed increase/decrease. - - - - This feature can only be used with openpilot longitudinal control enabled. - - - - This feature is not supported on this platform due to vehicle limitations. - - - - Start the vehicle to check vehicle compatibility. - - - - - MadsSettings - - Toggle with Main Cruise - - - - Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement. - - - - Unified Engagement Mode (UEM) - - - - Engage lateral and longitudinal control with cruise control engagement. - - - - Note: Once lateral control is engaged via UEM, it will remain engaged until it is manually disabled via the MADS button or car shut off. - - - - Remain Active - - - - Disengage - - - - Steering Mode on Brake Pedal - - - - Start the vehicle to check vehicle compatibility. - - - - This feature defaults to OFF, and does not allow selection due to vehicle limitations. - - - - This feature defaults to ON, and does not allow selection due to vehicle limitations. - - - - This platform only supports Disengage mode due to vehicle limitations. - - - - Remain Active: ALC will remain active when the brake pedal is pressed. - - - - Pause - - - - Pause: ALC will pause when the brake pedal is pressed. - - - - Disengage: ALC will disengage when the brake pedal is pressed. - - - - Choose how Automatic Lane Centering (ALC) behaves after the brake pedal is manually pressed in sunnypilot. - - - - - MaxTimeOffroad - - Max Time Offroad - - - - Device will automatically shutdown after set time once the engine is turned off.<br/>(30h is the default) - - - - Always On - - - - h - - - - m - - - - (default) - - - - - ModelsPanel - - Current Model - - - - SELECT - 選択 - - - downloaded - - - - ready - - - - from cache - - - - Fetching models... - - - - Select a Model - - - - Default - - - - Model download has started in the background. - - - - We STRONGLY suggest you to reset calibration. - - - - Would you like to do that now? - - - - Reset Calibration - キャリブレーションリセット - - - Driving Model Selector - - - - Warning: You are on a metered connection! - - - - Continue - 続ける - - - on Metered - - - - Cancel - キャンセル - - - Clear Model Cache - - - - CLEAR - - - - Driving Model - - - - Navigation Model - - - - Vision Model - - - - Policy Model - - - - Live Learning Steer Delay - - - - Adjust Software Delay - - - - Adjust the software delay when Live Learning Steer Delay is toggled off. -The default software delay value is 0.2 - - - - %1 - %2 - - - - download failed - %1 - - - - pending - %1 - - - - Enable this for the car to learn and adapt its steering response time. Disable to use a fixed steering response time. Keeping this on provides the stock openpilot experience. The Current value is updated automatically when the vehicle is Onroad. - - - - Current: - - - - This will delete ALL downloaded models from the cache<br/><u>except the currently active model</u>.<br/><br/>Are you sure you want to continue? - - - - Clear Cache - - - MultiOptionDialog @@ -1049,85 +448,15 @@ The default software delay value is 0.2 パスワードが違います - - NetworkingSP - - Scan - - - - Scanning... - - - - - NeuralNetworkLateralControl - - Neural Network Lateral Control (NNLC) - - - - NNLC is currently not available on this platform. - - - - Start the car to check car compatibility - - - - NNLC Not Loaded - - - - NNLC Loaded - - - - Match - - - - Exact - - - - Fuzzy - - - - Match: "Exact" is ideal, but "Fuzzy" is fine too. - - - - Formerly known as <b>"NNFF"</b>, this replaces the lateral <b>"torque"</b> controller, with one using a neural network trained on each car's (actually, each separate EPS firmware) driving data for increased controls accuracy. - - - - Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server - - - - with feedback, or to provide log data for your car if your car is currently unsupported: - - - - if there are any issues: - - - - and donate logs to get NNLC loaded for your car: - - - OffroadAlert - Immediately connect to the internet to check for updates. If you do not connect to the internet, sunnypilot won't engage in %1 - インターネットへ接続してアップデートを確認してください。未接続のままではsunnypilotを使用できなくなります。あと[%1] + Immediately connect to the internet to check for updates. If you do not connect to the internet, openpilot won't engage in %1 + インターネットへ接続してアップデートを確認してください。未接続のままではopenpilotを使用できなくなります。あと[%1] - Connect to internet to check for updates. sunnypilot won't automatically start until it connects to internet to check for updates. - インターネットに接続してアップデートを確認してください。接続するまでsunnypilotは使用できません。 + Connect to internet to check for updates. openpilot won't automatically start until it connects to internet to check for updates. + インターネットに接続してアップデートを確認してください。接続するまでopenpilotは使用できません。 Unable to download updates @@ -1143,35 +472,37 @@ The default software delay value is 0.2 An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. オペレーティングシステムがバックグラウンドでダウンロードされています。インストールの準備が整うと更新を促されます。 - - Device failed to register. It will not connect to or upload to comma.ai servers, and receives no support from comma.ai. If this is an official device, visit https://comma.ai/support. - 登録に失敗しました。このデバイスはcomma.aiのサーバーに接続したりデータをアップロードしたりできません。またcomma.aiのサポートも受けられません。公式デバイスである場合は https://comma.ai/support に問い合わせて下さい。 - NVMe drive not mounted. SSDドライブ(NVMe)がマウントされていません。 - Unsupported NVMe drive detected. Device may draw significantly more power and overheat due to the unsupported NVMe. - 非サポートのSSDドライブ(NVMe)が検出されました。このドライブを使用するとデバイスが多大な電力を消費し過熱する可能性があります。 + openpilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. + openpilotが車両を識別できませんでした。車が未対応またはECUが認識されていない可能性があります。該当車両のファームウェアバージョンを追加するためにプルリクエストしてください。サポートが必要な場合は discord.comma.ai に参加することができます。 - sunnypilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. - sunnypilotが車両を識別できませんでした。車が未対応またはECUが認識されていない可能性があります。該当車両のファームウェアバージョンを追加するためにプルリクエストしてください。サポートが必要な場合は discord.comma.ai に参加することができます。 - - - sunnypilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. - sunnypilotがデバイスの取り付け位置にずれを検出しました。デバイスの固定とマウントがフロントガラスにしっかりと取り付けられていることを確認してください。 + openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. + openpilotがデバイスの取り付け位置にずれを検出しました。デバイスの固定とマウントがフロントガラスにしっかりと取り付けられていることを確認してください。 Device temperature too high. System cooling down before starting. Current internal component temperature: %1 デバイスの温度が高すぎるためシステム起動前の冷却中です。現在のデバイス内部温度: %1 - OpenStreetMap database is out of date. New maps must be downloaded if you wish to continue using OpenStreetMap data for Enhanced Speed Control and road name display. - -%1 - + Device failed to register with the comma.ai backend. It will not connect or upload to comma.ai servers, and receives no support from comma.ai. If this is a device purchased at comma.ai/shop, open a ticket at https://comma.ai/support. + 製品のcomma.aiへの登録に失敗しました。このデバイスはcomma.aiのサーバーに接続したりアップロードを行ったりすることはできず、comma.aiからのサポートも受けられません。もしcomma.ai/shopで購入した場合は、https://comma.ai/support にてサポートチケットをご提出ください。 + + + Acknowledge Excessive Actuation + 過剰な作動の検知 + + + Snooze Update + また後で更新する + + + openpilot has detected excessive %1 actuation. This may be due to a software bug. Please contact support at https://comma.ai/support. + openpilotが過剰な%1の作動を検出しました。ソフトウェアの不具合の可能性があります。https://comma.ai/support からサポートへご連絡下さい。 @@ -1189,18 +520,11 @@ The default software delay value is 0.2 警告 - - OffroadHomeSP - - ALWAYS OFFROAD ACTIVE - - - OnroadAlerts - sunnypilot Unavailable - sunnypilotは使用できません + openpilot Unavailable + openpilotは使用できません TAKE CONTROL IMMEDIATELY @@ -1219,137 +543,6 @@ The default software delay value is 0.2 システムが応答しません - - OsmPanel - - Mapd Version - - - - Offline Maps ETA - - - - Time Elapsed - - - - Downloaded Maps - - - - DELETE - - - - This will delete ALL downloaded maps - -Are you sure you want to delete all the maps? - - - - Yes, delete all the maps. - - - - Database Update - - - - CHECK - 確認 - - - Country - - - - SELECT - 選択 - - - Fetching Country list... - - - - State - - - - Fetching State list... - - - - All - - - - REFRESH - - - - UPDATE - 更新 - - - Download starting... - - - - Error: Invalid download. Retry. - - - - Download complete! - - - - - -Warning: You are on a metered connection! - - - - This will start the download process and it might take a while to complete. - - - - Continue on Metered - - - - Start Download - - - - m - - - - s - - - - Calculating... - - - - Downloaded - - - - Calculating ETA... - - - - Ready - - - - Time remaining: - - - PairingPopup @@ -1384,96 +577,6 @@ Warning: You are on a metered connection! 有効にする - - ParamControlSP - - Enable - 有効にする - - - Cancel - キャンセル - - - - PlatformSelector - - Vehicle - - - - SEARCH - - - - Search your vehicle - - - - Enter model year (e.g., 2021) and model name (Toyota Corolla): - - - - SEARCHING - - - - REMOVE - 削除 - - - This setting will take effect immediately. - - - - This setting will take effect once the device enters offroad state. - - - - Vehicle Selector - - - - Confirm - 確認 - - - Cancel - キャンセル - - - No vehicles found for query: %1 - - - - Select a vehicle - - - - Unrecognized Vehicle - - - - Fingerprinted automatically - - - - Manually selected - - - - Not fingerprinted or manually selected - - - - Select vehicle to force fingerprint manually. - - - - Colors represent fingerprint status: - - - PrimeAdWidget @@ -1519,8 +622,8 @@ Warning: You are on a metered connection! QObject - sunnypilot - sunnypilot + openpilot + openpilot %n minute(s) ago @@ -1545,47 +648,6 @@ Warning: You are on a metered connection! たった今 - - Reset - - Reset failed. Reboot to try again. - 初期化に失敗しました。再起動後に再試行してください。 - - - Are you sure you want to reset your device? - 初期化してもよろしいですか? - - - System Reset - システムを初期化 - - - Cancel - キャンセル - - - Reboot - 再起動 - - - Confirm - 確認 - - - Unable to mount data partition. Partition may be corrupted. Press confirm to erase and reset your device. - Dataパーティションをマウントできません。パーティションが破損している可能性があります。デバイスを消去してリセットしますので確認を押して下さい。 - - - Resetting device... -This may take up to a minute. - デバイスをリセットしています… -この処理には最大で1分ほどかかる場合があります。 - - - System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot. - システムリセットの準備が整いました。すべてのデータと設定を消去するには「確認」を押してください。「キャンセル」を押すとブートを再開します。 - - SettingsWindow @@ -1617,69 +679,6 @@ This may take up to a minute. データ学習 - - SettingsWindowSP - - × - × - - - Device - デバイス - - - Network - ネット - - - sunnylink - - - - Toggles - 機能 - - - Software - ソフト - - - Trips - - - - Vehicle - - - - Developer - 開発 - - - Firehose - データ学習 - - - Steering - - - - Models - - - - Cruise - - - - Visuals - - - - OSM - - - Setup @@ -1767,8 +766,8 @@ This may take up to a minute. インストールするソフトウェアを選択してください。 - sunnypilot - sunnypilot + openpilot + openpilot Custom Software @@ -1776,13 +775,15 @@ This may take up to a minute. WARNING: Custom Software - + 警告: カスタムソフトウェア Use caution when installing third-party software. Third-party software has not been tested by comma, and may cause damage to your device and/or vehicle. If you'd like to proceed, use https://flash.comma.ai to restore your device to a factory state later. - + サードパーティ製ソフトウェアをインストールする際は注意してください。サードパーティ製ソフトウェアはcommaによってテストされておらず、あなたのデバイスや車両に損害を与える可能性があります。 + +続行したい場合は、後でデバイスを工場出荷時の状態に戻すために https://flash.comma.ai を使用してください。 @@ -1875,33 +876,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 5G - - SidebarSP - - DISABLED - - - - OFFLINE - オフライン - - - REGIST... - - - - ONLINE - オンライン - - - ERROR - エラー - - - SUNNYLINK - - - SoftwarePanel @@ -1977,49 +951,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 無効 - - SoftwarePanelSP - - Search Branch - - - - Enter search keywords, or leave blank to list all branches. - - - - No branches found for keywords: %1 - - - - Select a branch - ブランチを選択 - - - Disable Updates - - - - When enabled, software updates will be disabled. <b>This requires a reboot to take effect.</b> - - - - %1 updates requires a reboot.<br>Reboot now? - - - - Reboot - 再起動 - - - When enabled, software updates will be disabled.<br><b>This requires a reboot to take effect.</b> - - - - Please enable always offroad mode or turn off vehicle to adjust these toggles - - - SshControl @@ -2028,7 +959,7 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device Warning: This grants SSH access to all public keys in your GitHub settings. Never enter a GitHub username other than your own. A comma employee will NEVER ask you to add their GitHub username. - 警告: これは、GitHub の設定にあるすべての公開鍵への SSH アクセスを許可するものです。自分以外の GitHub のユーザー名を入力しないでください。commaのスタッフが GitHub のユーザー名を追加するようお願いすることはありません。 + 警告: これはGitHubの設定にあるすべての公開鍵への SSH アクセスを許可するものです。自分以外のGitHubユーザー名を入力しないでください。commaのスタッフがGitHubのユーザー名を追加するようお願いすることはありません。 ADD @@ -2036,7 +967,7 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device Enter your GitHub username - GitHub のユーザー名を入力してください + GitHubのユーザー名を入力してください LOADING @@ -2066,168 +997,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device SSHの有効化 - - SunnylinkPanel - - This is the master switch, it will allow you to cutoff any sunnylink requests should you want to do that. - - - - Enable sunnylink - - - - 🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀 - - - - 👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉. - - - - Device ID - - - - N/A - 該当なし - - - Sponsor Status - - - - SPONSOR - - - - Become a sponsor of sunnypilot to get early access to sunnylink features when they become available. - - - - Pair GitHub Account - - - - PAIR - OK - - - Pair your GitHub account to grant your device sponsor benefits, including API access on sunnylink. - - - - sunnylink Dongle ID not found. This may be due to weak internet connection or sunnylink registration issue. Please reboot and try again. - - - - Not Sponsor - - - - Paired - - - - Not Paired - - - - THANKS ♥ - - - - Backup Settings - - - - Are you sure you want to backup sunnypilot settings? - - - - Back Up - - - - Restore Settings - - - - Are you sure you want to restore the last backed up sunnypilot settings? - - - - Restore - - - - Backup in progress %1% - - - - Backup Failed - - - - Settings backup completed. - - - - Restore in progress %1% - - - - Restore Failed - - - - Unable to restore the settings, try again later. - - - - Settings restored. Confirm to restart the interface. - - - - - SunnylinkSponsorPopup - - Scan the QR code to login to your GitHub account - - - - Follow the prompts to complete the pairing process - - - - Re-enter the "sunnylink" panel to verify sponsorship status - - - - If sponsorship status was not updated, please contact a moderator on Discord at https://discord.gg/sunnypilot - - - - Scan the QR code to visit sunnyhaibin's GitHub Sponsors page - - - - Choose your sponsorship tier and confirm your support - - - - Join our community on Discord at https://discord.gg/sunnypilot and reach out to a moderator to confirm your sponsor status - - - - Pair your GitHub account - - - - Early Access: Become a sunnypilot Sponsor - - - TermsPage @@ -2239,19 +1008,23 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 同意 - Welcome to sunnypilot - + Welcome to openpilot + openpilotへようこそ - You must accept the Terms and Conditions to use sunnypilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing. - + You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing. + openpilotを使用するには利用規約に同意する必要があります。続行する前に最新の規約を以下でご確認ください: <span style='color: #465BEA;'>https://comma.ai/terms</span> TogglesPanel + + Enable openpilot + openpilotを有効化 + Enable Lane Departure Warnings - 車線逸脱警報機能の有効化 + 車線逸脱警報の有効化 Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h). @@ -2278,20 +1051,20 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device アクセルを踏むと運転サポートを中断 - When enabled, pressing the accelerator pedal will disengage sunnypilot. - この機能を有効化すると、sunnypilotを利用中にアクセルを踏むとsunnypilotによる運転サポートを中断します。 + When enabled, pressing the accelerator pedal will disengage openpilot. + この機能を有効化すると、openpilotを利用中にアクセルを踏むとopenpilotによる運転サポートを中断します。 Experimental Mode Experimentalモード - sunnypilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: - sunnypilotは標準ではゆっくりとくつろげる運転を提供します。このExperimental(実験)モードを有効にすると、以下のアグレッシブな開発中の機能を利用する事ができます。 + openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: + openpilotは標準ではゆっくりとくつろげる運転を提供します。このExperimental(実験)モードを有効にすると、以下のアグレッシブな開発中の機能を利用する事ができます。 - Let the driving model control the gas and brakes. sunnypilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. - sunnypilotにアクセルとブレーキを任せます。sunnypilotは赤信号や一時停止サインでの停止を含み、人間と同じように考えて運転を行います。sunnypilotが運転速度を決定するため、あなたが設定する速度は上限速度になります。この機能は実験段階のため、sunnypilotの運転ミスに常に備えて注意してください。 + Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. + openpilotにアクセルとブレーキを任せます。openpilotは赤信号や一時停止サインでの停止を含み、人間と同じように考えて運転を行います。openpilotが運転速度を決定するため、あなたが設定する速度は上限速度になります。この機能は実験段階のため、openpilotの運転ミスに常に備えて注意してください。 New Driving Visualization @@ -2322,16 +1095,20 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device End-to-Endアクセル制御 - An alpha version of sunnypilot longitudinal control can be tested, along with Experimental mode, on non-release branches. - sunnypilotのアルファ版アクセル制御は、Experimentalモードと共に非リリースのブランチでテストすることができます。 + openpilot longitudinal control may come in a future update. + openpilotのアクセル制御は将来のアップデートで利用できる可能性があります。 - Enable the sunnypilot longitudinal control (alpha) toggle to allow Experimental mode. - sunnypilotのアクセル制御機能(アルファ)を有効にして、Experimentalモードを許可してください。 + An alpha version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + openpilotのアルファ版アクセル制御は、Experimentalモードと共に非リリースのブランチでテストすることができます。 - Standard is recommended. In aggressive mode, sunnypilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode sunnypilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. - 標準モードが推奨されます。アグレッシブモードではsunnypilotは先行車に近づいて追従し、アクセルとブレーキがより強気になります。リラックスモードではsunnypilotは先行車から距離を取って走行します。サポートされている車両ではステアリングホイールの距離ボタンでこれらのモードを切り替えることができます。 + Enable the openpilot longitudinal control (alpha) toggle to allow Experimental mode. + openpilotのアクセル制御機能(アルファ)を有効にして、Experimentalモードを許可してください。 + + + Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. + 標準モードが推奨されます。アグレッシブモードではopenpilotは先行車に近づいて追従し、アクセルとブレーキがより強気になります。リラックスモードではopenpilotは先行車から距離を取って走行します。サポートされている車両ではステアリングホイールの距離ボタンでこれらのモードを切り替えることができます。 The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. @@ -2342,129 +1119,24 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 運転者の常時モニタリング - Enable driver monitoring even when sunnypilot is not engaged. - sunnypilotが作動していない場合でも運転者モニタリングを有効にする。 + Enable driver monitoring even when openpilot is not engaged. + openpilotが作動していない場合でも運転者モニタリングを有効にする。 - Enable Dynamic Experimental Control - - - - Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal. - - - - Enable sunnypilot - sunnypilot を有効化 - - - Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. - + Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. + openpilotシステムを使用してアダプティブクルーズコントロールおよび車線維持支援を行います。システム使用中は常にドライバーが事故を起こさないように注意を払ってください。 Changing this setting will restart openpilot if the car is powered on. - - - - openpilot longitudinal control may come in a future update. - + この設定を変更すると車の電源が入っている場合はopenpilotが再起動します。 Record and Upload Microphone Audio - + マイク音声の録音とアップロード Record and store microphone audio while driving. The audio will be included in the dashcam video in comma connect. - - - - - TreeOptionDialog - - Select - 選択 - - - Cancel - キャンセル - - - - Updater - - Update Required - アップデートが必要です - - - An operating system update is required. Connect your device to Wi-Fi for the fastest update experience. The download size is approximately 1GB. - OSのアップデートが必要です。Wi-Fiに接続してアップデートする事をお勧めします。ダウンロードサイズは約1GBです。 - - - Connect to Wi-Fi - Wi-Fiに接続 - - - Install - インストール - - - Back - 戻る - - - Loading... - 読み込み中... - - - Reboot - 再起動 - - - Update failed - 更新失敗 - - - - VisualsPanel - - Show Blind Spot Warnings - - - - Enabling this will display warnings when a vehicle is detected in your blind spot as long as your car has BSM supported. - - - - Changing this setting will restart openpilot if the car is powered on. - - - - Off - - - - Distance - - - - Speed - - - - Time - - - - All - - - - Display Metrics Below Chevron - - - - Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control). - + 運転中にマイク音声を録音・保存します。音声は comma connect のドライブレコーダー映像に含まれます。 @@ -2474,12 +1146,12 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 開く - <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span> - <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehoseモード <span style='font-family: Noto Color Emoji;'>🔥</span> + Maximize your training data uploads to improve openpilot's driving models. + openpilotの運転モデルを改善するために、大容量の学習データをアップロードして下さい。 - Maximize your training data uploads to improve openpilot's driving models. - + <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span> + <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehoseモード <span style='font-family: Noto Color Emoji;'>🔥</span> diff --git a/selfdrive/ui/translations/main_ko.ts b/selfdrive/ui/translations/main_ko.ts index 86c8e10e26..aaefdb92b0 100644 --- a/selfdrive/ui/translations/main_ko.ts +++ b/selfdrive/ui/translations/main_ko.ts @@ -7,10 +7,6 @@ Close 닫기 - - Snooze Update - 업데이트 일시 중지 - Reboot and Update 업데이트 및 재부팅 @@ -60,7 +56,7 @@ Cellular Metered - 데이터 요금제 + 모바일 데이터 종량제 Hidden Network @@ -84,74 +80,27 @@ Prevent large data uploads when on a metered cellular connection - + 모바일 데이터 종량제 사용 시 대용량 데이터 업로드 방지 default - + 기본 metered - + 종량제 unmetered - + 무제한 Wi-Fi Network Metered - + 제한된 Wi-Fi 네트워크 Prevent large data uploads when on a metered Wi-Fi connection - - - - - AutoLaneChangeTimer - - Auto Lane Change by Blinker - - - - Set a timer to delay the auto lane change operation when the blinker is used. No nudge on the steering wheel is required to auto lane change if a timer is set. Default is Nudge. -Please use caution when using this feature. Only use the blinker when traffic and road conditions permit. - - - - s - - - - Off - - - - Nudge - - - - Nudgeless - - - - - Brightness - - Brightness - - - - Overrides the brightness of the device. - - - - Auto (Dark) - - - - Auto - + 제한된 Wi-Fi 사용 시 대용량 데이터 업로드 방지 @@ -168,8 +117,8 @@ Please use caution when using this feature. Only use the blinker when traffic an DeclinePage - You must accept the Terms and Conditions in order to use sunnypilot. - sunnypilot을 사용하려면 이용약관에 동의해야 합니다. + You must accept the Terms and Conditions in order to use openpilot. + 오픈파일럿을 사용하려면 이용약관에 동의해야 합니다. Back @@ -188,7 +137,19 @@ Please use caution when using this feature. Only use the blinker when traffic an Longitudinal Maneuver Mode - 롱컨 제어 모드 + 가감속 제어 조작 모드 + + + openpilot Longitudinal Control (Alpha) + 오픈파일럿 가감속 제어 (알파) + + + WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). + 경고: 오픈파일럿 가감속 제어는 알파 기능으로 차량의 자동긴급제동(AEB)기능이 작동하지 않습니다. + + + On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. + 이 차량에서 오픈파일럿은 오픈파일럿 가감속 제어 대신 기본적으로 차량의 ACC로 가감속을 제어합니다. 오픈파일럿 가감속 제어로 전환하려면 이 기능을 활성화하세요. 오픈파일럿 가감속 제어 알파 기능을 활성화하는 경우 실험 모드 활성화를 권장합니다. Enable ADB @@ -198,62 +159,6 @@ Please use caution when using this feature. Only use the blinker when traffic an ADB (Android Debug Bridge) allows connecting to your device over USB or over the network. See https://docs.comma.ai/how-to/connect-to-comma for more info. ADB (안드로이드 디버그 브릿지) USB 또는 네트워크를 통해 장치에 연결할 수 있습니다. 자세한 내용은 https://docs.comma.ai/how-to/connect-to-comma를 참조하세요. - - openpilot Longitudinal Control (Alpha) - - - - WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). - - - - On this car, sunnypilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. - - - - - DeveloperPanelSP - - Show Advanced Controls - - - - Toggle visibility of advanced sunnypilot controls. -This only toggles the visibility of the controls; it does not toggle the actual control enabled/disabled state. - - - - Enable GitHub runner service - - - - Enables or disables the github runner service. - - - - Enable Quickboot Mode - - - - Error Log - - - - VIEW - 보기 - - - View the error log for sunnypilot crashes. - - - - When toggled on, this creates a prebuilt file to allow accelerated boot times. When toggled off, it immediately removes the prebuilt file so compilation of locally edited cpp files can be made. <br><br><b>To edit C++ files locally on device, you MUST first turn off this toggle so the changes can recompile.</b> - - - - Quickboot mode requires updates to be disabled.<br>Enable 'Disable Updates' in the Software panel first. - - DevicePanel @@ -302,8 +207,8 @@ This only toggles the visibility of the controls; it does not toggle the actual 다시보기 - Review the rules, features, and limitations of sunnypilot - sunnypilot의 규칙, 기능 및 제한 다시 확인 + Review the rules, features, and limitations of openpilot + 오픈파일럿의 규칙, 기능 및 제한 다시 확인 Are you sure you want to review the training guide? @@ -395,174 +300,39 @@ This only toggles the visibility of the controls; it does not toggle the actual Disengage to Reset Calibration - + 캘리브레이션을 재설정하려면 해제하세요 - sunnypilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. - + openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. + 오픈파일럿 장치는 좌우측으로는 4° 또는 위로는 5° 아래로는 9° 이내에 장착해야합니다. + + + openpilot is continuously calibrating, resetting is rarely required. Resetting calibration will restart openpilot if the car is powered on. + 오픈파일럿은 지속적으로 갤리브레이션되어 재설정이 거의 필요하지 않습니다. 차량과 연결된 경우 캘리브레이션 재설정이 오픈파일럿을 재시작합니다. Steering lag calibration is %1% complete. - + + +조향 지연 캘리브레이션이 %1% 진행되었습니다. Steering lag calibration is complete. - + + +조향 지연 캘리브레이션이 완료되었습니다. Steering torque response calibration is %1% complete. - + 조향 토크 응답 캘리브레이션이 %1% 진행되었습니다. Steering torque response calibration is complete. - - - - openpilot is continuously calibrating, resetting is rarely required. Resetting calibration will restart openpilot if the car is powered on. - - - - - DevicePanelSP - - Driver Camera Preview - - - - Training Guide - - - - Regulatory - 규제 - - - Language - - - - Are you sure you want to review the training guide? - 트레이닝 가이드를 다시 확인하시겠습니까? - - - Review - 다시보기 - - - Select a language - 언어를 선택하세요 - - - Reboot - 재부팅 - - - Power Off - 전원 끄기 - - - Offroad Mode - - - - Are you sure you want to exit Always Offroad mode? - - - - Confirm - 확인 - - - Are you sure you want to enter Always Offroad mode? - - - - Disengage to Enter Always Offroad Mode - - - - Exit Always Offroad - - - - Always Offroad - - - - Quiet Mode - - - - Reset Settings - - - - Are you sure you want to reset all sunnypilot settings to default? Once the settings are reset, there is no going back. - - - - Reset - 초기화 - - - The reset cannot be undone. You have been warned. - - - - Wake-Up Behavior - - - - Interactivity Timeout - - - - Apply a custom timeout for settings UI. -This is the time after which settings UI closes automatically if user is not interacting with the screen. - - - - ⁍ Default: Device will boot/wake-up normally & will be ready to engage. - - - - ⁍ Offroad: Device will be in Always Offroad mode after boot/wake-up. - - - - Controls state of the device after boot/sleep. - - - - - DriveStats - - Drives - - - - Hours - - - - ALL TIME - - - - PAST WEEK - - - - KM - - - - Miles - + 조향 토크 응답 캘리브레이션이 완료되었습니다. @@ -572,21 +342,6 @@ This is the time after which settings UI closes automatically if user is not int 카메라 시작 중 - - ExitOffroadButton - - Are you sure you want to exit Always Offroad mode? - - - - Confirm - 확인 - - - EXIT ALWAYS OFFROAD MODE - - - ExperimentalModeButton @@ -600,37 +355,39 @@ This is the time after which settings UI closes automatically if user is not int FirehosePanel + + openpilot learns to drive by watching humans, like you, drive. + +Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode. + 오픈파일럿은 여러분과 같은 사람이 운전하는 모습을 보면서 운전하는 법을 배웁니다. + +파이어호스 모드를 사용하면 학습 데이터 업로드를 최대화하여 오픈파일럿의 주행 모델을 개선할 수 있습니다. 더 많은 데이터는 더 큰 모델을 의미하며, 이는 더 나은 실험 모드를 의미합니다. + Firehose Mode: ACTIVE 파이어호스 모드: 활성화 ACTIVE - 활성화 + 활성 상태 - For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream sunnypilot (and particular forks) are able to be used for training. - 최대한의 효과를 얻으려면 매주 장치를 실내로 가져와 좋은 USB-C 케이블에 연결하고 Wi-Fi에 연결하세요.<br><br>파이어호스 모드는 핫스팟 또는 무제한 SIM 카드에 연결된 경우에는 운전 중에도 작동할 수 있습니다.<br><br><br><b>자주 묻는 질문</b><br><br><i>운전 방법이나 장소가 중요한가요?</i> 아니요, 평소처럼 운전하시면 됩니다.<br><br><i>파이어호스 모드에서 제 모든 구간을 가져오나요?.<br><br><i> 아니요, 저희는 여러분의 구간 중 일부를 선별적으로 가져옵니다.<br><br><i>좋은 USB-C 케이블은 무엇인가요?</i> 휴대폰이나 노트북 고속 충전기가 있으면 됩니다.<br><br><i>어떤 소프트웨어를 실행하는지가 중요한가요?</i> 예, 오직 공식 sunnypilot의 특정 포크만 트레이닝에 사용할 수 있습니다. + For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training. + 최대한의 효과를 얻으려면 매주 장치를 실내로 가져와 좋은 USB-C 충전기와 Wi-Fi에 연결하세요.<br><br>파이어호스 모드는 핫스팟 또는 무제한 네트워크에 연결된 경우 주행 중에도 작동할 수 있습니다.<br><br><br><b>자주 묻는 질문</b><br><br><i>운전 방법이나 장소가 중요한가요?</i> 아니요, 평소처럼 운전하시면 됩니다.<br><br><i>파이어호스 모드에서 제 모든 구간을 가져오나요?<br><br><i> 아니요, 저희는 여러분의 구간 중 일부를 선별적으로 가져옵니다.<br><br><i>좋은 USB-C 충전기는 무엇인가요?</i> 휴대폰이나 노트북충전이 가능한 고속 충전기이면 괜찮습니다.<br><br><i>어떤 소프트웨어를 실행하는지가 중요한가요?</i> 예, 오직 공식 오픈파일럿의 특정 포크만 트레이닝에 사용할 수 있습니다. <b>%n segment(s)</b> of your driving is in the training dataset so far. - - + + <b>%n 구간</b> 의 운전이 지금까지의 학습 데이터셋에 포함되어 있습니다. - - sunnypilot learns to drive by watching humans, like you, drive. - -Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode. - - <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to an unmetered network - + <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>비활성 상태</span>: 무제한 네트워크에 연결 하세요 Firehose Mode - + 파이어호스 모드 @@ -648,49 +405,6 @@ Firehose Mode allows you to maximize your training data uploads to improve openp MAX - - HyundaiSettings - - Off - - - - Dynamic - - - - Predictive - - - - Custom Longitudinal Tuning - - - - This feature can only be used with openpilot longitudinal control enabled. - - - - Enable "Always Offroad" in Device panel, or turn vehicle off to select an option. - - - - Off: Uses default tuning - - - - Dynamic: Adjusts acceleration limits based on current speed - - - - Predictive: Uses future trajectory data to anticipate needed adjustments - - - - Fine-tune your driving experience by adjusting acceleration smoothness with openpilot longitudinal control. - - - InputDialog @@ -704,321 +418,6 @@ Firehose Mode allows you to maximize your training data uploads to improve openp - - LaneChangeSettings - - Back - 뒤로 - - - Auto Lane Change: Delay with Blind Spot - - - - Toggle to enable a delay timer for seamless lane changes when blind spot monitoring (BSM) detects a obstructing vehicle, ensuring safe maneuvering. - - - - - LateralPanel - - Modular Assistive Driving System (MADS) - - - - Enable the beloved MADS feature. Disable toggle to revert back to stock sunnypilot engagement/disengagement. - - - - Customize MADS - - - - Customize Lane Change - - - - Enables independent engagements of Automatic Lane Centering (ALC) and Adaptive Cruise Control (ACC). - - - - Start the vehicle to check vehicle compatibility. - - - - This platform supports all MADS settings. - - - - This platform supports limited MADS settings. - - - - Pause Lateral Control with Blinker - - - - Pause lateral control with blinker when traveling below the desired speed selected. - - - - - LongitudinalPanel - - Custom ACC Speed Increments - - - - Enable custom Short & Long press increments for cruise speed increase/decrease. - - - - This feature can only be used with openpilot longitudinal control enabled. - - - - This feature is not supported on this platform due to vehicle limitations. - - - - Start the vehicle to check vehicle compatibility. - - - - - MadsSettings - - Toggle with Main Cruise - - - - Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement. - - - - Unified Engagement Mode (UEM) - - - - Engage lateral and longitudinal control with cruise control engagement. - - - - Note: Once lateral control is engaged via UEM, it will remain engaged until it is manually disabled via the MADS button or car shut off. - - - - Remain Active - - - - Disengage - - - - Steering Mode on Brake Pedal - - - - Start the vehicle to check vehicle compatibility. - - - - This feature defaults to OFF, and does not allow selection due to vehicle limitations. - - - - This feature defaults to ON, and does not allow selection due to vehicle limitations. - - - - This platform only supports Disengage mode due to vehicle limitations. - - - - Remain Active: ALC will remain active when the brake pedal is pressed. - - - - Pause - - - - Pause: ALC will pause when the brake pedal is pressed. - - - - Disengage: ALC will disengage when the brake pedal is pressed. - - - - Choose how Automatic Lane Centering (ALC) behaves after the brake pedal is manually pressed in sunnypilot. - - - - - MaxTimeOffroad - - Max Time Offroad - - - - Device will automatically shutdown after set time once the engine is turned off.<br/>(30h is the default) - - - - Always On - - - - h - - - - m - - - - (default) - - - - - ModelsPanel - - Current Model - - - - SELECT - 선택 - - - downloaded - - - - ready - - - - from cache - - - - Fetching models... - - - - Select a Model - - - - Default - - - - Model download has started in the background. - - - - We STRONGLY suggest you to reset calibration. - - - - Would you like to do that now? - - - - Reset Calibration - 캘리브레이션 - - - Driving Model Selector - - - - Warning: You are on a metered connection! - - - - Continue - 계속 - - - on Metered - - - - Cancel - 취소 - - - Clear Model Cache - - - - CLEAR - - - - Driving Model - - - - Navigation Model - - - - Vision Model - - - - Policy Model - - - - Live Learning Steer Delay - - - - Adjust Software Delay - - - - Adjust the software delay when Live Learning Steer Delay is toggled off. -The default software delay value is 0.2 - - - - %1 - %2 - - - - download failed - %1 - - - - pending - %1 - - - - Enable this for the car to learn and adapt its steering response time. Disable to use a fixed steering response time. Keeping this on provides the stock openpilot experience. The Current value is updated automatically when the vehicle is Onroad. - - - - Current: - - - - This will delete ALL downloaded models from the cache<br/><u>except the currently active model</u>.<br/><br/>Are you sure you want to continue? - - - - Clear Cache - - - MultiOptionDialog @@ -1049,85 +448,15 @@ The default software delay value is 0.2 비밀번호가 틀렸습니다 - - NetworkingSP - - Scan - - - - Scanning... - - - - - NeuralNetworkLateralControl - - Neural Network Lateral Control (NNLC) - - - - NNLC is currently not available on this platform. - - - - Start the car to check car compatibility - - - - NNLC Not Loaded - - - - NNLC Loaded - - - - Match - - - - Exact - - - - Fuzzy - - - - Match: "Exact" is ideal, but "Fuzzy" is fine too. - - - - Formerly known as <b>"NNFF"</b>, this replaces the lateral <b>"torque"</b> controller, with one using a neural network trained on each car's (actually, each separate EPS firmware) driving data for increased controls accuracy. - - - - Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server - - - - with feedback, or to provide log data for your car if your car is currently unsupported: - - - - if there are any issues: - - - - and donate logs to get NNLC loaded for your car: - - - OffroadAlert - Immediately connect to the internet to check for updates. If you do not connect to the internet, sunnypilot won't engage in %1 - 즉시 인터넷에 연결하여 업데이트를 확인하세요. 인터넷에 연결되어 있지 않으면 %1 이후에는 sunnypilot이 활성화되지 않습니다. + Immediately connect to the internet to check for updates. If you do not connect to the internet, openpilot won't engage in %1 + 즉시 인터넷에 연결하여 업데이트를 확인하세요. 인터넷에 연결되어 있지 않으면 %1 이후에는 오픈파일럿이 활성화되지 않습니다. - Connect to internet to check for updates. sunnypilot won't automatically start until it connects to internet to check for updates. - 업데이트를 확인하려면 인터넷에 연결하세요. sunnypilot은 업데이트를 확인하기 위해 인터넷에 연결할 때까지 자동으로 시작되지 않습니다. + Connect to internet to check for updates. openpilot won't automatically start until it connects to internet to check for updates. + 업데이트 확인을 위해 인터넷 연결이 필요합니다. 오픈파일럿은 업데이트 확인을 위해 인터넷에 연결될 때까지 자동으로 시작되지 않습니다. Unable to download updates @@ -1143,35 +472,37 @@ The default software delay value is 0.2 An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. 백그라운드에서 운영 체제에 대한 업데이트가 다운로드되고 있습니다. 설치가 준비되면 업데이트 메시지가 표시됩니다. - - Device failed to register. It will not connect to or upload to comma.ai servers, and receives no support from comma.ai. If this is an official device, visit https://comma.ai/support. - 장치를 등록하지 못했습니다. comma.ai 서버에 연결하거나 데이터를 업로드하지 않으며 comma.ai에서 지원을 받지 않습니다. 공식 장치인 경우 https://comma.ai/support 에 방문하여 문의하세요. - NVMe drive not mounted. NVMe 드라이브가 마운트되지 않았습니다. - Unsupported NVMe drive detected. Device may draw significantly more power and overheat due to the unsupported NVMe. - 지원되지 않는 NVMe 드라이브가 감지되었습니다. 지원되지 않는 NVMe 드라이브는 많은 전력을 소비하고 장치를 과열시킬 수 있습니다. + openpilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. + 오픈파일럿이 차량을 식별할 수 없습니다. 지원되지 않는 차량이거나 ECU가 인식되지 않습니다. 해당 차량에 맞는 펌웨어 버전을 추가하려면 PR을 제출하세요. 도움이 필요하시면 discord.comma.ai에 참여하세요. - sunnypilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. - sunnypilot이 차량을 식별할 수 없습니다. 지원되지 않는 차량이거나 ECU가 인식되지 않습니다. 해당 차량에 맞는 펌웨어 버전을 추가하려면 PR을 제출하세요. 도움이 필요하시면 discord.comma.ai에 가입하세요. - - - sunnypilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. - sunnypilot 장치의 장착 위치가 변경되었습니다. 장치가 마운트에 완전히 장착되고 마운트가 앞유리에 단단히 고정되었는지 확인하세요. + openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. + 오픈파일럿 장치의 장착 위치가 변경되었습니다. 장치가 마운트에 완전히 장착되고 마운트가 앞유리에 단단히 고정되었는지 확인하세요. Device temperature too high. System cooling down before starting. Current internal component temperature: %1 - 장치의 온도가 너무 높습니다. 시작 전에 온도를 낮춰주세요. 현재 내부 구성 요소 온도: %1 + 장치 온도가 너무 높습니다. 시작하기 전에 시스템을 냉각하고 있습니다. 현재 내부 구성 요소 온도: %1 - OpenStreetMap database is out of date. New maps must be downloaded if you wish to continue using OpenStreetMap data for Enhanced Speed Control and road name display. - -%1 - + Device failed to register with the comma.ai backend. It will not connect or upload to comma.ai servers, and receives no support from comma.ai. If this is a device purchased at comma.ai/shop, open a ticket at https://comma.ai/support. + 장치를 comma.ai 백엔드에 등록하지 못했습니다. comma.ai 서버에 연결하거나 업로드하지 않으며 comma.ai로부터 지원을받지 않습니다. comma.ai shop에서 구매 한 장치 인 경우 https://comma.ai/support에서 티켓을 여십시오. + + + Acknowledge Excessive Actuation + 과도한 작동을 인정하십시오 + + + Snooze Update + 업데이트 일시 중지 + + + openpilot has detected excessive %1 actuation. This may be due to a software bug. Please contact support at https://comma.ai/support. + 오픈파일럿은 과도한 %1 작동을 감지했습니다. 소프트웨어 버그 때문일 수 있습니다. https://comma.ai/support 에 문의하여 지원받으세요. @@ -1189,17 +520,10 @@ The default software delay value is 0.2 알림 - - OffroadHomeSP - - ALWAYS OFFROAD ACTIVE - - - OnroadAlerts - sunnypilot Unavailable + openpilot Unavailable 오픈파일럿을 사용할수없습니다 @@ -1219,137 +543,6 @@ The default software delay value is 0.2 시스템이 응답하지않습니다 - - OsmPanel - - Mapd Version - - - - Offline Maps ETA - - - - Time Elapsed - - - - Downloaded Maps - - - - DELETE - - - - This will delete ALL downloaded maps - -Are you sure you want to delete all the maps? - - - - Yes, delete all the maps. - - - - Database Update - - - - CHECK - 확인 - - - Country - - - - SELECT - 선택 - - - Fetching Country list... - - - - State - - - - Fetching State list... - - - - All - - - - REFRESH - - - - UPDATE - 업데이트 - - - Download starting... - - - - Error: Invalid download. Retry. - - - - Download complete! - - - - - -Warning: You are on a metered connection! - - - - This will start the download process and it might take a while to complete. - - - - Continue on Metered - - - - Start Download - - - - m - - - - s - - - - Calculating... - - - - Downloaded - - - - Calculating ETA... - - - - Ready - - - - Time remaining: - - - PairingPopup @@ -1384,96 +577,6 @@ Warning: You are on a metered connection! 활성화 - - ParamControlSP - - Enable - 활성화 - - - Cancel - 취소 - - - - PlatformSelector - - Vehicle - - - - SEARCH - - - - Search your vehicle - - - - Enter model year (e.g., 2021) and model name (Toyota Corolla): - - - - SEARCHING - - - - REMOVE - 삭제 - - - This setting will take effect immediately. - - - - This setting will take effect once the device enters offroad state. - - - - Vehicle Selector - - - - Confirm - 확인 - - - Cancel - 취소 - - - No vehicles found for query: %1 - - - - Select a vehicle - - - - Unrecognized Vehicle - - - - Fingerprinted automatically - - - - Manually selected - - - - Not fingerprinted or manually selected - - - - Select vehicle to force fingerprint manually. - - - - Colors represent fingerprint status: - - - PrimeAdWidget @@ -1482,7 +585,7 @@ Warning: You are on a metered connection! Become a comma prime member at connect.comma.ai - connect.comma.ai에 접속하여 comma prime 회원으로 등록하세요 + connect.comma.ai에서 comma prime 사용자로 등록하세요 PRIME FEATURES: @@ -1498,7 +601,7 @@ Warning: You are on a metered connection! 1 year of drive storage - 1년간 드라이브 로그 저장 + 1년간 주행 로그 저장 Remote snapshots @@ -1519,8 +622,8 @@ Warning: You are on a metered connection! QObject - sunnypilot - sunnypilot + openpilot + 오픈파일럿 %n minute(s) ago @@ -1545,47 +648,6 @@ Warning: You are on a metered connection! now - - Reset - - Reset failed. Reboot to try again. - 초기화 실패. 재부팅 후 다시 시도하세요. - - - Are you sure you want to reset your device? - 장치를 초기화하시겠습니까? - - - System Reset - 장치 초기화 - - - Cancel - 취소 - - - Reboot - 재부팅 - - - Confirm - 확인 - - - Unable to mount data partition. Partition may be corrupted. Press confirm to erase and reset your device. - 데이터 파티션을 마운트할 수 없습니다. 파티션이 손상되었을 수 있습니다. 모든 설정을 삭제하고 장치를 초기화하려면 확인을 누르세요. - - - Resetting device... -This may take up to a minute. - 장치를 초기화하는 중... -최대 1분이 소요될 수 있습니다. - - - System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot. - 시스템 재설정이 시작되었습니다. 모든 콘텐츠와 설정을 지우려면 확인을 누르시고 부팅을 재개하려면 취소를 누르세요. - - SettingsWindow @@ -1617,69 +679,6 @@ This may take up to a minute. 파이어호스 - - SettingsWindowSP - - × - × - - - Device - 장치 - - - Network - 네트워크 - - - sunnylink - - - - Toggles - 토글 - - - Software - 소프트웨어 - - - Trips - - - - Vehicle - - - - Developer - 개발자 - - - Firehose - 파이어호스 - - - Steering - - - - Models - - - - Cruise - - - - Visuals - - - - OSM - - - Setup @@ -1767,8 +766,8 @@ This may take up to a minute. 설치할 소프트웨어 선택 - sunnypilot - sunnypilot + openpilot + 오픈파일럿 Custom Software @@ -1776,13 +775,15 @@ This may take up to a minute. WARNING: Custom Software - + 경고: 커스텀 소프트웨어 Use caution when installing third-party software. Third-party software has not been tested by comma, and may cause damage to your device and/or vehicle. If you'd like to proceed, use https://flash.comma.ai to restore your device to a factory state later. - + 타사 소프트웨어를 설치할 때는 주의하십시오. 타사 소프트웨어는 comma에 의해 테스트되지 않았으며 장치나 차량에 손상을 줄 수 있습니다. + +진행하려면 https://flash.comma.ai를 사용하여 나중에 장치를 공장 초기화하세요. @@ -1875,33 +876,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 5G - - SidebarSP - - DISABLED - - - - OFFLINE - 연결 안됨 - - - REGIST... - - - - ONLINE - 온라인 - - - ERROR - 오류 - - - SUNNYLINK - - - SoftwarePanel @@ -1977,49 +951,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 업데이트 안함 - - SoftwarePanelSP - - Search Branch - - - - Enter search keywords, or leave blank to list all branches. - - - - No branches found for keywords: %1 - - - - Select a branch - 브랜치 선택 - - - Disable Updates - - - - When enabled, software updates will be disabled. <b>This requires a reboot to take effect.</b> - - - - %1 updates requires a reboot.<br>Reboot now? - - - - Reboot - 재부팅 - - - When enabled, software updates will be disabled.<br><b>This requires a reboot to take effect.</b> - - - - Please enable always offroad mode or turn off vehicle to adjust these toggles - - - SshControl @@ -2066,168 +997,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device SSH 사용 - - SunnylinkPanel - - This is the master switch, it will allow you to cutoff any sunnylink requests should you want to do that. - - - - Enable sunnylink - - - - 🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀 - - - - 👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉. - - - - Device ID - - - - N/A - N/A - - - Sponsor Status - - - - SPONSOR - - - - Become a sponsor of sunnypilot to get early access to sunnylink features when they become available. - - - - Pair GitHub Account - - - - PAIR - 동기화 - - - Pair your GitHub account to grant your device sponsor benefits, including API access on sunnylink. - - - - sunnylink Dongle ID not found. This may be due to weak internet connection or sunnylink registration issue. Please reboot and try again. - - - - Not Sponsor - - - - Paired - - - - Not Paired - - - - THANKS ♥ - - - - Backup Settings - - - - Are you sure you want to backup sunnypilot settings? - - - - Back Up - - - - Restore Settings - - - - Are you sure you want to restore the last backed up sunnypilot settings? - - - - Restore - - - - Backup in progress %1% - - - - Backup Failed - - - - Settings backup completed. - - - - Restore in progress %1% - - - - Restore Failed - - - - Unable to restore the settings, try again later. - - - - Settings restored. Confirm to restart the interface. - - - - - SunnylinkSponsorPopup - - Scan the QR code to login to your GitHub account - - - - Follow the prompts to complete the pairing process - - - - Re-enter the "sunnylink" panel to verify sponsorship status - - - - If sponsorship status was not updated, please contact a moderator on Discord at https://discord.gg/sunnypilot - - - - Scan the QR code to visit sunnyhaibin's GitHub Sponsors page - - - - Choose your sponsorship tier and confirm your support - - - - Join our community on Discord at https://discord.gg/sunnypilot and reach out to a moderator to confirm your sponsor status - - - - Pair your GitHub account - - - - Early Access: Become a sunnypilot Sponsor - - - TermsPage @@ -2239,16 +1008,20 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 동의 - Welcome to sunnypilot - 오픈 파일럿에 오신 것을 환영합니다. + Welcome to openpilot + 오픈파일럿에 오신 것을 환영합니다. - You must accept the Terms and Conditions to use sunnypilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing. + You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing. 오픈파일럿을 사용하려면 이용약관에 동의해야 합니다. 최신 약관은 <span style='color: #465BEA;'>https://comma.ai/terms</span> 에서 최신 약관을 읽은 후 계속하세요. TogglesPanel + + Enable openpilot + 오픈파일럿 사용 + Enable Lane Departure Warnings 차선 이탈 경고 활성화 @@ -2278,20 +1051,20 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 가속페달 조작 시 해제 - When enabled, pressing the accelerator pedal will disengage sunnypilot. - 활성화된 경우 가속 페달을 밟으면 sunnypilot이 해제됩니다. + When enabled, pressing the accelerator pedal will disengage openpilot. + 활성화된 경우 가속 페달을 밟으면 오픈파일럿이 해제됩니다. Experimental Mode 실험 모드 - sunnypilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: - sunnypilot은 기본적으로 <b>안정 모드</b>로 주행합니다. 실험 모드는 안정화되지 않은 <b>알파 수준의 기능</b>을 활성화합니다. 실험 모드의 기능은 아래와 같습니다: + openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: + 오픈파일럿은 기본적으로 <b>안정 모드</b>로 주행합니다. 실험 모드는 안정화되지 않은 <b>알파 수준의 기능</b>을 활성화합니다. 실험 모드의 기능은 아래와 같습니다: - Let the driving model control the gas and brakes. sunnypilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. - sunnypilot의 주행모델이 가감속을 제어합니다. sunnypilot은 신호등과 정지 표지판을 보고 멈추는 것을 포함하여 인간이 운전하는 것처럼 생각하고 주행합니다. 주행 모델이 주행할 속도를 결정하므로 설정된 속도는 최대 주행 속도로만 기능합니다. 이 기능은 알파 수준이므로 사용에 각별히 주의해야 합니다. + Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. + 주행모델이 가감속을 제어하도록 합니다. 오픈파일럿은 빨간불과 정지신호를 보고 정지하는것을 포함하여 사람이 운전하는 방식대로 작동하며 주행 모델이 속도를 결정하므로 설정 속도는 최대 제한 속도로만 작동합니다. 이는 알파 수준의 기능이며 오류가 발생할수있으니 사용에 주의해야 합니다. New Driving Visualization @@ -2299,7 +1072,11 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. - 차량에 장착된 ACC로 가감속을 제어하기 때문에 현재 이 차량에서는 실험 모드를 사용할 수 없습니다. + 차량의 ACC가 가감속 제어에 사용되기 때문에, 이 차량에서는 실험 모드를 사용할 수 없습니다. + + + openpilot longitudinal control may come in a future update. + 오픈파일럿 가감속 제어는 향후 업데이트에서 지원될 수 있습니다. Aggressive @@ -2318,20 +1095,20 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 주행 모드 - An alpha version of sunnypilot longitudinal control can be tested, along with Experimental mode, on non-release branches. - sunnypilot 가감속 제어 알파 버전은 비 릴리즈 브랜치에서 실험 모드와 함께 테스트할 수 있습니다. + An alpha version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + 오픈파일럿 가감속 제어 알파 버전은 비 릴리즈 브랜치에서 실험 모드와 함께 테스트할 수 있습니다. - Enable the sunnypilot longitudinal control (alpha) toggle to allow Experimental mode. - 실험 모드를 사용하려면 sunnypilot E2E 가감속 제어 (알파) 토글을 활성화하세요. + Enable the openpilot longitudinal control (alpha) toggle to allow Experimental mode. + 실험 모드를 사용하려면 오픈파일럿 E2E 가감속 제어 (알파) 토글을 활성화하세요. End-to-End Longitudinal Control E2E 가감속 제어 - Standard is recommended. In aggressive mode, sunnypilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode sunnypilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. - 표준 모드를 권장합니다. 공격적 모드의 sunnypilot은 선두 차량을 더 가까이 따라가고 가감속제어를 사용하여 더욱 공격적으로 움직입니다. 편안한 모드의 sunnypilot은 선두 차량으로부터 더 멀리 떨어져 있습니다. 지원되는 차량에서는 스티어링 휠 거리 버튼을 사용하여 이러한 특성을 순환할 수 있습니다. + Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. + 표준 모드를 권장합니다. 공격적 모드의 오픈파일럿은 선두 차량을 더 가까이 따라가고 가감속제어를 사용하여 더욱 공격적으로 움직입니다. 편안한 모드의 오픈파일럿은 선두 차량으로부터 더 멀리 떨어져 있습니다. 지원되는 차량에서는 차간거리 버튼을 사용하여 이러한 특성을 순환할 수 있습니다. The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. @@ -2342,129 +1119,24 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 상시 운전자 모니터링 - Enable driver monitoring even when sunnypilot is not engaged. - sunnypilot이 활성화되지 않은 경우에도 드라이버 모니터링을 활성화합니다. + Enable driver monitoring even when openpilot is not engaged. + 오픈파일럿이 활성화되지 않은 경우에도 드라이버 모니터링을 활성화합니다. - Enable Dynamic Experimental Control - - - - Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal. - - - - Enable sunnypilot - sunnypilot 사용 - - - Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. - + Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. + ACC 및 차선 유지 지원을 위해 오픈파일럿 시스템을 사용하십시오. 이 기능을 사용하려면 항상주의를 기울여야합니다. Changing this setting will restart openpilot if the car is powered on. - - - - openpilot longitudinal control may come in a future update. - + 이 설정을 변경하면 차량이 재가동된후 오픈파일럿이 시작됩니다. Record and Upload Microphone Audio - + 마이크 오디오 녹음 및 업로드 Record and store microphone audio while driving. The audio will be included in the dashcam video in comma connect. - - - - - TreeOptionDialog - - Select - 선택 - - - Cancel - 취소 - - - - Updater - - Update Required - 업데이트 필요 - - - An operating system update is required. Connect your device to Wi-Fi for the fastest update experience. The download size is approximately 1GB. - OS 업데이트가 필요합니다. 장치를 Wi-Fi에 연결하면 가장 빠르게 업데이트할 수 있습니다. 다운로드 크기는 약 1GB입니다. - - - Connect to Wi-Fi - Wi-Fi 연결 - - - Install - 설치 - - - Back - 뒤로 - - - Loading... - 로딩 중... - - - Reboot - 재부팅 - - - Update failed - 업데이트 실패 - - - - VisualsPanel - - Show Blind Spot Warnings - - - - Enabling this will display warnings when a vehicle is detected in your blind spot as long as your car has BSM supported. - - - - Changing this setting will restart openpilot if the car is powered on. - - - - Off - - - - Distance - - - - Speed - - - - Time - - - - All - - - - Display Metrics Below Chevron - - - - Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control). - + 운전 중에 마이크 오디오를 녹음하고 저장하십시오. 오디오는 comma connect의 대시캠 비디오에 포함됩니다. @@ -2474,12 +1146,12 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 열기 - <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span> - <span style='font-family: "Noto Color Emoji";'>🔥</span> 파이어호스 모드 <span style='font-family: Noto Color Emoji;'>🔥</span> + Maximize your training data uploads to improve openpilot's driving models. + 오픈파일럿의 주행 모델 개선을 위해 학습 데이터 업로드를 최대화하세요. - Maximize your training data uploads to improve openpilot's driving models. - + <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span> + <span style='font-family: "Noto Color Emoji";'>🔥</span> 파이어호스 모드 <span style='font-family: Noto Color Emoji;'>🔥</span> diff --git a/selfdrive/ui/translations/main_pt-BR.ts b/selfdrive/ui/translations/main_pt-BR.ts index 503441c467..976fc711db 100644 --- a/selfdrive/ui/translations/main_pt-BR.ts +++ b/selfdrive/ui/translations/main_pt-BR.ts @@ -7,10 +7,6 @@ Close Fechar - - Snooze Update - Adiar Atualização - Reboot and Update Reiniciar e Atualizar @@ -84,74 +80,27 @@ Prevent large data uploads when on a metered cellular connection - + Previna o envio de grandes volumes de dados em conexões de celular com franquia de limite de dados default - + padrão metered - + limitada unmetered - + ilimitada Wi-Fi Network Metered - + Rede Wi-Fi com Franquia Prevent large data uploads when on a metered Wi-Fi connection - - - - - AutoLaneChangeTimer - - Auto Lane Change by Blinker - - - - Set a timer to delay the auto lane change operation when the blinker is used. No nudge on the steering wheel is required to auto lane change if a timer is set. Default is Nudge. -Please use caution when using this feature. Only use the blinker when traffic and road conditions permit. - - - - s - - - - Off - - - - Nudge - - - - Nudgeless - - - - - Brightness - - Brightness - - - - Overrides the brightness of the device. - - - - Auto (Dark) - - - - Auto - + Previna o envio de grandes volumes de dados em conexões Wi-Fi com franquia de limite de dados @@ -168,8 +117,8 @@ Please use caution when using this feature. Only use the blinker when traffic an DeclinePage - You must accept the Terms and Conditions in order to use sunnypilot. - Você precisa aceitar os Termos e Condições para utilizar sunnypilot. + You must accept the Terms and Conditions in order to use openpilot. + Você precisa aceitar os Termos e Condições para utilizar openpilot. Back @@ -190,6 +139,18 @@ Please use caution when using this feature. Only use the blinker when traffic an Longitudinal Maneuver Mode Modo Longitudinal Maneuver + + openpilot Longitudinal Control (Alpha) + Controle Longitudinal openpilot (Embrionário) + + + WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). + AVISO: o controle longitudinal openpilot está em estado embrionário para este carro e desativará a Frenagem Automática de Emergência (AEB). + + + On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. + Neste carro, o openpilot tem como padrão o ACC embutido do carro em vez do controle longitudinal do openpilot. Habilite isso para alternar para o controle longitudinal openpilot. Recomenda-se ativar o modo Experimental ao ativar o embrionário controle longitudinal openpilot. + Enable ADB Habilitar ADB @@ -198,62 +159,6 @@ Please use caution when using this feature. Only use the blinker when traffic an ADB (Android Debug Bridge) allows connecting to your device over USB or over the network. See https://docs.comma.ai/how-to/connect-to-comma for more info. ADB (Android Debug Bridge) permite conectar ao seu dispositivo por meio do USB ou através da rede. Veja https://docs.comma.ai/how-to/connect-to-comma para maiores informações. - - openpilot Longitudinal Control (Alpha) - - - - WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). - - - - On this car, sunnypilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. - - - - - DeveloperPanelSP - - Show Advanced Controls - - - - Toggle visibility of advanced sunnypilot controls. -This only toggles the visibility of the controls; it does not toggle the actual control enabled/disabled state. - - - - Enable GitHub runner service - - - - Enables or disables the github runner service. - - - - Enable Quickboot Mode - - - - Error Log - - - - VIEW - VER - - - View the error log for sunnypilot crashes. - - - - When toggled on, this creates a prebuilt file to allow accelerated boot times. When toggled off, it immediately removes the prebuilt file so compilation of locally edited cpp files can be made. <br><br><b>To edit C++ files locally on device, you MUST first turn off this toggle so the changes can recompile.</b> - - - - Quickboot mode requires updates to be disabled.<br>Enable 'Disable Updates' in the Software panel first. - - DevicePanel @@ -302,8 +207,8 @@ This only toggles the visibility of the controls; it does not toggle the actual REVISAR - Review the rules, features, and limitations of sunnypilot - Revisar regras, aprimoramentos e limitações do sunnypilot + Review the rules, features, and limitations of openpilot + Revisar regras, aprimoramentos e limitações do openpilot Are you sure you want to review the training guide? @@ -395,174 +300,39 @@ This only toggles the visibility of the controls; it does not toggle the actual Disengage to Reset Calibration - + Desacione para Resetar a Calibração - sunnypilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. - + openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. + O openpilot exige que o dispositivo seja montado dentro de 4° para a esquerda ou direita e dentro de 5° para cima ou 9° para baixo. + + + openpilot is continuously calibrating, resetting is rarely required. Resetting calibration will restart openpilot if the car is powered on. + O openpilot está em constante calibração, raramente sendo necessário redefini-lo. Redefinir a calibração reiniciará o openpilot se o carro estiver ligado. Steering lag calibration is %1% complete. - + + +A calibração do atraso da direção está %1% concluída. Steering lag calibration is complete. - + + +A calibração do atraso da direção foi concluída. Steering torque response calibration is %1% complete. - + A calibração da resposta de torque da direção está %1% concluída. Steering torque response calibration is complete. - - - - openpilot is continuously calibrating, resetting is rarely required. Resetting calibration will restart openpilot if the car is powered on. - - - - - DevicePanelSP - - Driver Camera Preview - - - - Training Guide - - - - Regulatory - Regulatório - - - Language - - - - Are you sure you want to review the training guide? - Tem certeza que quer rever o treinamento? - - - Review - Revisar - - - Select a language - Selecione o Idioma - - - Reboot - Reiniciar - - - Power Off - Desligar - - - Offroad Mode - - - - Are you sure you want to exit Always Offroad mode? - - - - Confirm - Confirmar - - - Are you sure you want to enter Always Offroad mode? - - - - Disengage to Enter Always Offroad Mode - - - - Exit Always Offroad - - - - Always Offroad - - - - Quiet Mode - - - - Reset Settings - - - - Are you sure you want to reset all sunnypilot settings to default? Once the settings are reset, there is no going back. - - - - Reset - Resetar - - - The reset cannot be undone. You have been warned. - - - - Wake-Up Behavior - - - - Interactivity Timeout - - - - Apply a custom timeout for settings UI. -This is the time after which settings UI closes automatically if user is not interacting with the screen. - - - - ⁍ Default: Device will boot/wake-up normally & will be ready to engage. - - - - ⁍ Offroad: Device will be in Always Offroad mode after boot/wake-up. - - - - Controls state of the device after boot/sleep. - - - - - DriveStats - - Drives - - - - Hours - - - - ALL TIME - - - - PAST WEEK - - - - KM - - - - Miles - + A calibração da resposta do torque da direção foi concluída. @@ -572,21 +342,6 @@ This is the time after which settings UI closes automatically if user is not int câmera iniciando - - ExitOffroadButton - - Are you sure you want to exit Always Offroad mode? - - - - Confirm - Confirmar - - - EXIT ALWAYS OFFROAD MODE - - - ExperimentalModeButton @@ -600,6 +355,14 @@ This is the time after which settings UI closes automatically if user is not int FirehosePanel + + openpilot learns to drive by watching humans, like you, drive. + +Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode. + O openpilot aprende a dirigir observando humanos, como você, dirigirem. + +O Modo Firehose permite maximizar o envio de dados de treinamento para melhorar os modelos de direção do openpilot. Mais dados significam modelos maiores, o que resulta em um Modo Experimental melhor. + Firehose Mode: ACTIVE Modo Firehose: ATIVO @@ -609,8 +372,8 @@ This is the time after which settings UI closes automatically if user is not int ATIVO - For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream sunnypilot (and particular forks) are able to be used for training. - Para maior eficácia, leve seu dispositivo para dentro de casa e conecte-o a um bom adaptador USB-C e Wi-Fi semanalmente.<br><br>O Modo Firehose também pode funcionar enquanto você dirige, se estiver conectado a um hotspot ou a um chip SIM com dados ilimitados.<br><br><br><b>Perguntas Frequentes</b><br><br><i>Importa como ou onde eu dirijo?</i> Não, basta dirigir normalmente.<br><br><i>Todos os meus segmentos são enviados no Modo Firehose?</i> Não, selecionamos apenas um subconjunto dos seus segmentos.<br><br><i>Qual é um bom adaptador USB-C?</i> Qualquer carregador rápido de telefone ou laptop deve ser suficiente.<br><br><i>Importa qual software eu uso?</i> Sim, apenas o sunnypilot oficial (e alguns forks específicos) podem ser usados para treinamento. + For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training. + Para maior eficácia, leve seu dispositivo para dentro de casa e conecte-o a um bom adaptador USB-C e Wi-Fi semanalmente.<br><br>O Modo Firehose também pode funcionar enquanto você dirige, se estiver conectado a um hotspot ou a um chip SIM com dados ilimitados.<br><br><br><b>Perguntas Frequentes</b><br><br><i>Importa como ou onde eu dirijo?</i> Não, basta dirigir normalmente.<br><br><i>Todos os meus segmentos são enviados no Modo Firehose?</i> Não, selecionamos apenas um subconjunto dos seus segmentos.<br><br><i>Qual é um bom adaptador USB-C?</i> Qualquer carregador rápido de telefone ou laptop deve ser suficiente.<br><br><i>Importa qual software eu uso?</i> Sim, apenas o openpilot oficial (e alguns forks específicos) podem ser usados para treinamento. <b>%n segment(s)</b> of your driving is in the training dataset so far. @@ -619,19 +382,13 @@ This is the time after which settings UI closes automatically if user is not int <b>%n segmentos</b> da sua direção estão no conjunto de dados de treinamento até agora. - - sunnypilot learns to drive by watching humans, like you, drive. - -Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode. - - <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to an unmetered network <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INATIVO</span>: conecte-se a uma rede sem limite <br> de dados Firehose Mode - + Modo Firehose @@ -649,49 +406,6 @@ Firehose Mode allows you to maximize your training data uploads to improve openp LIMITE - - HyundaiSettings - - Off - - - - Dynamic - - - - Predictive - - - - Custom Longitudinal Tuning - - - - This feature can only be used with openpilot longitudinal control enabled. - - - - Enable "Always Offroad" in Device panel, or turn vehicle off to select an option. - - - - Off: Uses default tuning - - - - Dynamic: Adjusts acceleration limits based on current speed - - - - Predictive: Uses future trajectory data to anticipate needed adjustments - - - - Fine-tune your driving experience by adjusting acceleration smoothness with openpilot longitudinal control. - - - InputDialog @@ -706,321 +420,6 @@ Firehose Mode allows you to maximize your training data uploads to improve openp - - LaneChangeSettings - - Back - Voltar - - - Auto Lane Change: Delay with Blind Spot - - - - Toggle to enable a delay timer for seamless lane changes when blind spot monitoring (BSM) detects a obstructing vehicle, ensuring safe maneuvering. - - - - - LateralPanel - - Modular Assistive Driving System (MADS) - - - - Enable the beloved MADS feature. Disable toggle to revert back to stock sunnypilot engagement/disengagement. - - - - Customize MADS - - - - Customize Lane Change - - - - Enables independent engagements of Automatic Lane Centering (ALC) and Adaptive Cruise Control (ACC). - - - - Start the vehicle to check vehicle compatibility. - - - - This platform supports all MADS settings. - - - - This platform supports limited MADS settings. - - - - Pause Lateral Control with Blinker - - - - Pause lateral control with blinker when traveling below the desired speed selected. - - - - - LongitudinalPanel - - Custom ACC Speed Increments - - - - Enable custom Short & Long press increments for cruise speed increase/decrease. - - - - This feature can only be used with openpilot longitudinal control enabled. - - - - This feature is not supported on this platform due to vehicle limitations. - - - - Start the vehicle to check vehicle compatibility. - - - - - MadsSettings - - Toggle with Main Cruise - - - - Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement. - - - - Unified Engagement Mode (UEM) - - - - Engage lateral and longitudinal control with cruise control engagement. - - - - Note: Once lateral control is engaged via UEM, it will remain engaged until it is manually disabled via the MADS button or car shut off. - - - - Remain Active - - - - Disengage - - - - Steering Mode on Brake Pedal - - - - Start the vehicle to check vehicle compatibility. - - - - This feature defaults to OFF, and does not allow selection due to vehicle limitations. - - - - This feature defaults to ON, and does not allow selection due to vehicle limitations. - - - - This platform only supports Disengage mode due to vehicle limitations. - - - - Remain Active: ALC will remain active when the brake pedal is pressed. - - - - Pause - - - - Pause: ALC will pause when the brake pedal is pressed. - - - - Disengage: ALC will disengage when the brake pedal is pressed. - - - - Choose how Automatic Lane Centering (ALC) behaves after the brake pedal is manually pressed in sunnypilot. - - - - - MaxTimeOffroad - - Max Time Offroad - - - - Device will automatically shutdown after set time once the engine is turned off.<br/>(30h is the default) - - - - Always On - - - - h - - - - m - - - - (default) - - - - - ModelsPanel - - Current Model - - - - SELECT - SELECIONE - - - downloaded - - - - ready - - - - from cache - - - - Fetching models... - - - - Select a Model - - - - Default - - - - Model download has started in the background. - - - - We STRONGLY suggest you to reset calibration. - - - - Would you like to do that now? - - - - Reset Calibration - Reinicializar Calibragem - - - Driving Model Selector - - - - Warning: You are on a metered connection! - - - - Continue - Continuar - - - on Metered - - - - Cancel - Cancelar - - - Clear Model Cache - - - - CLEAR - - - - Driving Model - - - - Navigation Model - - - - Vision Model - - - - Policy Model - - - - Live Learning Steer Delay - - - - Adjust Software Delay - - - - Adjust the software delay when Live Learning Steer Delay is toggled off. -The default software delay value is 0.2 - - - - %1 - %2 - - - - download failed - %1 - - - - pending - %1 - - - - Enable this for the car to learn and adapt its steering response time. Disable to use a fixed steering response time. Keeping this on provides the stock openpilot experience. The Current value is updated automatically when the vehicle is Onroad. - - - - Current: - - - - This will delete ALL downloaded models from the cache<br/><u>except the currently active model</u>.<br/><br/>Are you sure you want to continue? - - - - Clear Cache - - - MultiOptionDialog @@ -1051,85 +450,15 @@ The default software delay value is 0.2 Senha incorreta - - NetworkingSP - - Scan - - - - Scanning... - - - - - NeuralNetworkLateralControl - - Neural Network Lateral Control (NNLC) - - - - NNLC is currently not available on this platform. - - - - Start the car to check car compatibility - - - - NNLC Not Loaded - - - - NNLC Loaded - - - - Match - - - - Exact - - - - Fuzzy - - - - Match: "Exact" is ideal, but "Fuzzy" is fine too. - - - - Formerly known as <b>"NNFF"</b>, this replaces the lateral <b>"torque"</b> controller, with one using a neural network trained on each car's (actually, each separate EPS firmware) driving data for increased controls accuracy. - - - - Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server - - - - with feedback, or to provide log data for your car if your car is currently unsupported: - - - - if there are any issues: - - - - and donate logs to get NNLC loaded for your car: - - - OffroadAlert - Immediately connect to the internet to check for updates. If you do not connect to the internet, sunnypilot won't engage in %1 - Conecte-se imediatamente à internet para verificar se há atualizações. Se você não se conectar à internet em %1 não será possível acionar o sunnypilot. + Immediately connect to the internet to check for updates. If you do not connect to the internet, openpilot won't engage in %1 + Conecte-se imediatamente à internet para verificar se há atualizações. Se você não se conectar à internet em %1 não será possível acionar o openpilot. - Connect to internet to check for updates. sunnypilot won't automatically start until it connects to internet to check for updates. - Conecte-se à internet para verificar se há atualizações. O sunnypilot não será iniciado automaticamente até que ele se conecte à internet para verificar se há atualizações. + Connect to internet to check for updates. openpilot won't automatically start until it connects to internet to check for updates. + Conecte-se à internet para verificar se há atualizações. O openpilot não será iniciado automaticamente até que ele se conecte à internet para verificar se há atualizações. Unable to download updates @@ -1145,35 +474,37 @@ The default software delay value is 0.2 An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. Uma atualização para o sistema operacional do seu dispositivo está sendo baixada em segundo plano. Você será solicitado a atualizar quando estiver pronto para instalar. - - Device failed to register. It will not connect to or upload to comma.ai servers, and receives no support from comma.ai. If this is an official device, visit https://comma.ai/support. - Falha ao registrar o dispositivo. Ele não se conectará ou fará upload para os servidores comma.ai e não receberá suporte da comma.ai. Se este for um dispositivo oficial, visite https://comma.ai/support. - NVMe drive not mounted. Unidade NVMe não montada. - Unsupported NVMe drive detected. Device may draw significantly more power and overheat due to the unsupported NVMe. - Unidade NVMe não suportada detectada. O dispositivo pode consumir significativamente mais energia e superaquecimento devido ao NVMe não suportado. + openpilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. + O openpilot não conseguiu identificar o seu carro. Seu carro não é suportado ou seus ECUs não são reconhecidos. Envie um pull request para adicionar as versões de firmware ao veículo adequado. Precisa de ajuda? Junte-se discord.comma.ai. - sunnypilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. - O sunnypilot não conseguiu identificar o seu carro. Seu carro não é suportado ou seus ECUs não são reconhecidos. Envie um pull request para adicionar as versões de firmware ao veículo adequado. Precisa de ajuda? Junte-se discord.comma.ai. - - - sunnypilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. - O sunnypilot detectou uma mudança na posição de montagem do dispositivo. Verifique se o dispositivo está totalmente encaixado no suporte e se o suporte está firmemente preso ao para-brisa. + openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. + O openpilot detectou uma mudança na posição de montagem do dispositivo. Verifique se o dispositivo está totalmente encaixado no suporte e se o suporte está firmemente preso ao para-brisa. Device temperature too high. System cooling down before starting. Current internal component temperature: %1 Temperatura do dispositivo muito alta. O sistema está sendo resfriado antes de iniciar. A temperatura atual do componente interno é: %1 - OpenStreetMap database is out of date. New maps must be downloaded if you wish to continue using OpenStreetMap data for Enhanced Speed Control and road name display. - -%1 - + Device failed to register with the comma.ai backend. It will not connect or upload to comma.ai servers, and receives no support from comma.ai. If this is a device purchased at comma.ai/shop, open a ticket at https://comma.ai/support. + O dispositivo não conseguiu se registrar no backend da comma.ai. Ele não se conecta nem faz upload para os servidores da comma.ai e não recebe suporte da comma.ai. Se este for um dispositivo adquirido em comma.ai/shop, abra um ticket em https://comma.ai/support. + + + Acknowledge Excessive Actuation + Reconhecer Atuação Excessiva + + + Snooze Update + Adiar Atualização + + + openpilot has detected excessive %1 actuation. This may be due to a software bug. Please contact support at https://comma.ai/support. + O openpilot detectou uma atuação excessiva de %1. Isso pode ser causado por uma falha no software. Por favor, entre em contato com o suporte em https://comma.ai/support. @@ -1191,18 +522,11 @@ The default software delay value is 0.2 ALERTA - - OffroadHomeSP - - ALWAYS OFFROAD ACTIVE - - - OnroadAlerts - sunnypilot Unavailable - sunnypilot Indisponível + openpilot Unavailable + openpilot Indisponível TAKE CONTROL IMMEDIATELY @@ -1221,137 +545,6 @@ The default software delay value is 0.2 Sistema sem Resposta - - OsmPanel - - Mapd Version - - - - Offline Maps ETA - - - - Time Elapsed - - - - Downloaded Maps - - - - DELETE - - - - This will delete ALL downloaded maps - -Are you sure you want to delete all the maps? - - - - Yes, delete all the maps. - - - - Database Update - - - - CHECK - VERIFICAR - - - Country - - - - SELECT - SELECIONE - - - Fetching Country list... - - - - State - - - - Fetching State list... - - - - All - - - - REFRESH - - - - UPDATE - ATUALIZAÇÃO - - - Download starting... - - - - Error: Invalid download. Retry. - - - - Download complete! - - - - - -Warning: You are on a metered connection! - - - - This will start the download process and it might take a while to complete. - - - - Continue on Metered - - - - Start Download - - - - m - - - - s - - - - Calculating... - - - - Downloaded - - - - Calculating ETA... - - - - Ready - - - - Time remaining: - - - PairingPopup @@ -1386,96 +579,6 @@ Warning: You are on a metered connection! Ativar - - ParamControlSP - - Enable - Ativar - - - Cancel - Cancelar - - - - PlatformSelector - - Vehicle - - - - SEARCH - - - - Search your vehicle - - - - Enter model year (e.g., 2021) and model name (Toyota Corolla): - - - - SEARCHING - - - - REMOVE - REMOVER - - - This setting will take effect immediately. - - - - This setting will take effect once the device enters offroad state. - - - - Vehicle Selector - - - - Confirm - Confirmar - - - Cancel - Cancelar - - - No vehicles found for query: %1 - - - - Select a vehicle - - - - Unrecognized Vehicle - - - - Fingerprinted automatically - - - - Manually selected - - - - Not fingerprinted or manually selected - - - - Select vehicle to force fingerprint manually. - - - - Colors represent fingerprint status: - - - PrimeAdWidget @@ -1521,8 +624,8 @@ Warning: You are on a metered connection! QObject - sunnypilot - sunnypilot + openpilot + openpilot %n minute(s) ago @@ -1550,47 +653,6 @@ Warning: You are on a metered connection! agora - - Reset - - Reset failed. Reboot to try again. - Reset falhou. Reinicie para tentar novamente. - - - Are you sure you want to reset your device? - Tem certeza que quer resetar seu dispositivo? - - - System Reset - Resetar Sistema - - - Cancel - Cancelar - - - Reboot - Reiniciar - - - Confirm - Confirmar - - - Unable to mount data partition. Partition may be corrupted. Press confirm to erase and reset your device. - Não é possível montar a partição de dados. Partição corrompida. Confirme para apagar e redefinir o dispositivo. - - - Resetting device... -This may take up to a minute. - Redefinindo o dispositivo -Isso pode levar até um minuto. - - - System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot. - Reinicialização do sistema acionada. Pressione confirmar para apagar todo o conteúdo e configurações. Pressione cancel para retomar a inicialização. - - SettingsWindow @@ -1622,69 +684,6 @@ Isso pode levar até um minuto. Firehose - - SettingsWindowSP - - × - × - - - Device - Dispositivo - - - Network - Rede - - - sunnylink - - - - Toggles - Ajustes - - - Software - Software - - - Trips - - - - Vehicle - - - - Developer - Desenvdor - - - Firehose - Firehose - - - Steering - - - - Models - - - - Cruise - - - - Visuals - - - - OSM - - - Setup @@ -1772,8 +771,8 @@ Isso pode levar até um minuto. Escolha o Software a ser Instalado - sunnypilot - sunnypilot + openpilot + openpilot Custom Software @@ -1781,13 +780,15 @@ Isso pode levar até um minuto. WARNING: Custom Software - + AVISO: Software Personalizado Use caution when installing third-party software. Third-party software has not been tested by comma, and may cause damage to your device and/or vehicle. If you'd like to proceed, use https://flash.comma.ai to restore your device to a factory state later. - + Tenha cuidado ao instalar software de terceiros. Softwares de terceiros não foram testados pela comma e podem causar danos ao seu dispositivo e/ou veículo. + +Se quiser continuar, use https://flash.comma.ai para restaurar seu dispositivo ao estado de fábrica mais tarde. @@ -1880,33 +881,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 5G - - SidebarSP - - DISABLED - - - - OFFLINE - OFFLINE - - - REGIST... - - - - ONLINE - ONLINE - - - ERROR - ERRO - - - SUNNYLINK - - - SoftwarePanel @@ -1982,49 +956,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device nunca - - SoftwarePanelSP - - Search Branch - - - - Enter search keywords, or leave blank to list all branches. - - - - No branches found for keywords: %1 - - - - Select a branch - Selecione uma branch - - - Disable Updates - - - - When enabled, software updates will be disabled. <b>This requires a reboot to take effect.</b> - - - - %1 updates requires a reboot.<br>Reboot now? - - - - Reboot - Reiniciar - - - When enabled, software updates will be disabled.<br><b>This requires a reboot to take effect.</b> - - - - Please enable always offroad mode or turn off vehicle to adjust these toggles - - - SshControl @@ -2071,168 +1002,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device Habilitar SSH - - SunnylinkPanel - - This is the master switch, it will allow you to cutoff any sunnylink requests should you want to do that. - - - - Enable sunnylink - - - - 🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀 - - - - 👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉. - - - - Device ID - - - - N/A - N/A - - - Sponsor Status - - - - SPONSOR - - - - Become a sponsor of sunnypilot to get early access to sunnylink features when they become available. - - - - Pair GitHub Account - - - - PAIR - PAREAR - - - Pair your GitHub account to grant your device sponsor benefits, including API access on sunnylink. - - - - sunnylink Dongle ID not found. This may be due to weak internet connection or sunnylink registration issue. Please reboot and try again. - - - - Not Sponsor - - - - Paired - - - - Not Paired - - - - THANKS ♥ - - - - Backup Settings - - - - Are you sure you want to backup sunnypilot settings? - - - - Back Up - - - - Restore Settings - - - - Are you sure you want to restore the last backed up sunnypilot settings? - - - - Restore - - - - Backup in progress %1% - - - - Backup Failed - - - - Settings backup completed. - - - - Restore in progress %1% - - - - Restore Failed - - - - Unable to restore the settings, try again later. - - - - Settings restored. Confirm to restart the interface. - - - - - SunnylinkSponsorPopup - - Scan the QR code to login to your GitHub account - - - - Follow the prompts to complete the pairing process - - - - Re-enter the "sunnylink" panel to verify sponsorship status - - - - If sponsorship status was not updated, please contact a moderator on Discord at https://discord.gg/sunnypilot - - - - Scan the QR code to visit sunnyhaibin's GitHub Sponsors page - - - - Choose your sponsorship tier and confirm your support - - - - Join our community on Discord at https://discord.gg/sunnypilot and reach out to a moderator to confirm your sponsor status - - - - Pair your GitHub account - - - - Early Access: Become a sunnypilot Sponsor - - - TermsPage @@ -2244,16 +1013,20 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device Concordo - Welcome to sunnypilot - Bem vindo ao sunnypilot + Welcome to openpilot + Bem vindo ao openpilot - You must accept the Terms and Conditions to use sunnypilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing. - Você deve aceitar os Termos e Condições para usar o sunnypilot. Leia os termos mais recentes em <span style='color: #465BEA;'>https://comma.ai/terms</span> antes de continuar. + You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing. + Você deve aceitar os Termos e Condições para usar o openpilot. Leia os termos mais recentes em <span style='color: #465BEA;'>https://comma.ai/terms</span> antes de continuar. TogglesPanel + + Enable openpilot + Ativar openpilot + Enable Lane Departure Warnings Ativar Avisos de Saída de Faixa @@ -2283,20 +1056,20 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device Desacionar com Pedal do Acelerador - When enabled, pressing the accelerator pedal will disengage sunnypilot. - Quando ativado, pressionar o pedal do acelerador desacionará o sunnypilot. + When enabled, pressing the accelerator pedal will disengage openpilot. + Quando ativado, pressionar o pedal do acelerador desacionará o openpilot. Experimental Mode Modo Experimental - sunnypilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: - sunnypilot por padrão funciona em <b>modo chill</b>. modo Experimental ativa <b>recursos de nível-embrionário</b> que não estão prontos para o modo chill. Recursos experimentais estão listados abaixo: + openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: + openpilot por padrão funciona em <b>modo chill</b>. modo Experimental ativa <b>recursos de nível-embrionário</b> que não estão prontos para o modo chill. Recursos experimentais estão listados abaixo: - Let the driving model control the gas and brakes. sunnypilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. - Deixe o modelo de IA controlar o acelerador e os freios. O sunnypilot irá dirigir como pensa que um humano faria, incluindo parar em sinais vermelhos e sinais de parada. Uma vez que o modelo de condução decide a velocidade a conduzir, a velocidade definida apenas funcionará como um limite superior. Este é um recurso de qualidade embrionária; erros devem ser esperados. + Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. + Deixe o modelo de IA controlar o acelerador e os freios. O openpilot irá dirigir como pensa que um humano faria, incluindo parar em sinais vermelhos e sinais de parada. Uma vez que o modelo de condução decide a velocidade a conduzir, a velocidade definida apenas funcionará como um limite superior. Este é um recurso de qualidade embrionária; erros devem ser esperados. New Driving Visualization @@ -2306,6 +1079,10 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. O modo Experimental está atualmente indisponível para este carro já que o ACC original do carro é usado para controle longitudinal. + + openpilot longitudinal control may come in a future update. + O controle longitudinal openpilot poderá vir em uma atualização futura. + Aggressive Disputa @@ -2323,20 +1100,20 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device Temperamento de Direção - An alpha version of sunnypilot longitudinal control can be tested, along with Experimental mode, on non-release branches. - Uma versão embrionária do controle longitudinal sunnypilot pode ser testada em conjunto com o modo Experimental, em branches que não sejam de produção. + An alpha version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + Uma versão embrionária do controle longitudinal openpilot pode ser testada em conjunto com o modo Experimental, em branches que não sejam de produção. - Enable the sunnypilot longitudinal control (alpha) toggle to allow Experimental mode. - Habilite o controle longitudinal (embrionário) sunnypilot para permitir o modo Experimental. + Enable the openpilot longitudinal control (alpha) toggle to allow Experimental mode. + Habilite o controle longitudinal (embrionário) openpilot para permitir o modo Experimental. End-to-End Longitudinal Control Controle Longitudinal de Ponta a Ponta - Standard is recommended. In aggressive mode, sunnypilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode sunnypilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. - Neutro é o recomendado. No modo disputa o sunnypilot seguirá o carro da frente mais de perto e será mais agressivo com a aceleração e frenagem. No modo calmo o sunnypilot se manterá mais longe do carro da frente. Em carros compatíveis, você pode alternar esses temperamentos com o botão de distância do volante. + Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. + Neutro é o recomendado. No modo disputa o openpilot seguirá o carro da frente mais de perto e será mais agressivo com a aceleração e frenagem. No modo calmo o openpilot se manterá mais longe do carro da frente. Em carros compatíveis, você pode alternar esses temperamentos com o botão de distância do volante. The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. @@ -2347,129 +1124,24 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device Monitoramento do Motorista Sempre Ativo - Enable driver monitoring even when sunnypilot is not engaged. - Habilite o monitoramento do motorista mesmo quando o sunnypilot não estiver acionado. + Enable driver monitoring even when openpilot is not engaged. + Habilite o monitoramento do motorista mesmo quando o openpilot não estiver acionado. - Enable Dynamic Experimental Control - - - - Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal. - - - - Enable sunnypilot - Ativar sunnypilot - - - Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. - + Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. + Use o sistema openpilot para controle de cruzeiro adaptativo e assistência ao motorista de manutenção de faixa. Sua atenção é necessária o tempo todo para usar esse recurso. Changing this setting will restart openpilot if the car is powered on. - - - - openpilot longitudinal control may come in a future update. - + Alterar esta configuração fará com que o openpilot reinicie se o carro estiver ligado. Record and Upload Microphone Audio - + Gravar e Fazer Upload do Áudio do Microfone Record and store microphone audio while driving. The audio will be included in the dashcam video in comma connect. - - - - - TreeOptionDialog - - Select - Selecione - - - Cancel - Cancelar - - - - Updater - - Update Required - Atualização Necessária - - - An operating system update is required. Connect your device to Wi-Fi for the fastest update experience. The download size is approximately 1GB. - Uma atualização do sistema operacional é necessária. Conecte seu dispositivo ao Wi-Fi para a experiência de atualização mais rápida. O tamanho do download é de aproximadamente 1GB. - - - Connect to Wi-Fi - Conecte-se ao Wi-Fi - - - Install - Instalar - - - Back - Voltar - - - Loading... - Carregando... - - - Reboot - Reiniciar - - - Update failed - Falha na atualização - - - - VisualsPanel - - Show Blind Spot Warnings - - - - Enabling this will display warnings when a vehicle is detected in your blind spot as long as your car has BSM supported. - - - - Changing this setting will restart openpilot if the car is powered on. - - - - Off - - - - Distance - - - - Speed - - - - Time - - - - All - - - - Display Metrics Below Chevron - - - - Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control). - + Grave e armazene o áudio do microfone enquanto estiver dirigindo. O áudio será incluído ao vídeo dashcam no comma connect. @@ -2479,12 +1151,12 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device Abrir - <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span> - <span style='font-family: "Noto Color Emoji";'>🔥</span> Modo Firehose <span style='font-family: Noto Color Emoji;'>🔥</span> + Maximize your training data uploads to improve openpilot's driving models. + Maximize seus envios de dados de treinamento para melhorar os modelos de direção do openpilot. - Maximize your training data uploads to improve openpilot's driving models. - + <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span> + <span style='font-family: "Noto Color Emoji";'>🔥</span> Modo Firehose <span style='font-family: Noto Color Emoji;'>🔥</span> diff --git a/selfdrive/ui/translations/main_th.ts b/selfdrive/ui/translations/main_th.ts index a3a65e9e03..3821b3b806 100644 --- a/selfdrive/ui/translations/main_th.ts +++ b/selfdrive/ui/translations/main_th.ts @@ -7,10 +7,6 @@ Close ปิด - - Snooze Update - เลื่อนการอัปเดต - Reboot and Update รีบูตและอัปเดต @@ -107,53 +103,6 @@ - - AutoLaneChangeTimer - - Auto Lane Change by Blinker - - - - Set a timer to delay the auto lane change operation when the blinker is used. No nudge on the steering wheel is required to auto lane change if a timer is set. Default is Nudge. -Please use caution when using this feature. Only use the blinker when traffic and road conditions permit. - - - - s - - - - Off - - - - Nudge - - - - Nudgeless - - - - - Brightness - - Brightness - - - - Overrides the brightness of the device. - - - - Auto (Dark) - - - - Auto - - - ConfirmationDialog @@ -168,8 +117,8 @@ Please use caution when using this feature. Only use the blinker when traffic an DeclinePage - You must accept the Terms and Conditions in order to use sunnypilot. - คุณต้องยอมรับเงื่อนไขและข้อตกลง เพื่อใช้งาน sunnypilot + You must accept the Terms and Conditions in order to use openpilot. + คุณต้องยอมรับเงื่อนไขและข้อตกลง เพื่อใช้งาน openpilot Back @@ -184,75 +133,31 @@ Please use caution when using this feature. Only use the blinker when traffic an DeveloperPanel Joystick Debug Mode - + โหมดดีบักจอยสติ๊ก Longitudinal Maneuver Mode - - - - Enable ADB - - - - ADB (Android Debug Bridge) allows connecting to your device over USB or over the network. See https://docs.comma.ai/how-to/connect-to-comma for more info. - + โหมดการควบคุมการเร่ง/เบรค openpilot Longitudinal Control (Alpha) - + ระบบควบคุมการเร่ง/เบรคโดย openpilot (Alpha) WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). - + คำเตือน: การควบคุมการเร่ง/เบรคโดย openpilot สำหรับรถคันนี้ยังอยู่ในสถานะ alpha และระบบเบรคฉุกเฉินอัตโนมัติ (AEB) จะถูกปิด - On this car, sunnypilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. - - - - - DeveloperPanelSP - - Show Advanced Controls - + On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. + โดยปกติสำหรับรถคันนี้ openpilot จะควบคุมการเร่ง/เบรคด้วยระบบ ACC จากโรงงาน แทนการควยคุมโดย openpilot เปิดสวิตซ์นี้เพื่อให้ openpilot ควบคุมการเร่ง/เบรค แนะนำให้เปิดโหมดทดลองเมื่อต้องการให้ openpilot ควบคุมการเร่ง/เบรค ซึ่งอยู่ในสถานะ alpha - Toggle visibility of advanced sunnypilot controls. -This only toggles the visibility of the controls; it does not toggle the actual control enabled/disabled state. - + Enable ADB + เปิด ADB - Enable GitHub runner service - - - - Enables or disables the github runner service. - - - - Enable Quickboot Mode - - - - Error Log - - - - VIEW - ดู - - - View the error log for sunnypilot crashes. - - - - When toggled on, this creates a prebuilt file to allow accelerated boot times. When toggled off, it immediately removes the prebuilt file so compilation of locally edited cpp files can be made. <br><br><b>To edit C++ files locally on device, you MUST first turn off this toggle so the changes can recompile.</b> - - - - Quickboot mode requires updates to be disabled.<br>Enable 'Disable Updates' in the Software panel first. - + ADB (Android Debug Bridge) allows connecting to your device over USB or over the network. See https://docs.comma.ai/how-to/connect-to-comma for more info. + ADB (Android Debug Bridge) อนุญาตให้เชื่อมต่ออุปกรณ์ของคุณผ่าน USB หรือผ่านเครือข่าย ดูข้อมูลเพิ่มเติมที่ https://docs.comma.ai/how-to/connect-to-comma @@ -302,8 +207,8 @@ This only toggles the visibility of the controls; it does not toggle the actual ทบทวน - Review the rules, features, and limitations of sunnypilot - ตรวจสอบกฎ คุณสมบัติ และข้อจำกัดของ sunnypilot + Review the rules, features, and limitations of openpilot + ตรวจสอบกฎ คุณสมบัติ และข้อจำกัดของ openpilot Are you sure you want to review the training guide? @@ -398,7 +303,11 @@ This only toggles the visibility of the controls; it does not toggle the actual - sunnypilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. + openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. + + + + openpilot is continuously calibrating, resetting is rarely required. Resetting calibration will restart openpilot if the car is powered on. @@ -421,149 +330,6 @@ Steering lag calibration is complete. Steering torque response calibration is complete. - - openpilot is continuously calibrating, resetting is rarely required. Resetting calibration will restart openpilot if the car is powered on. - - - - - DevicePanelSP - - Driver Camera Preview - - - - Training Guide - - - - Regulatory - ระเบียบข้อบังคับ - - - Language - - - - Are you sure you want to review the training guide? - คุณแน่ใจหรือไม่ว่าต้องการทบทวนคู่มือการใช้งาน? - - - Review - ทบทวน - - - Select a language - เลือกภาษา - - - Reboot - รีบูต - - - Power Off - ปิดเครื่อง - - - Offroad Mode - - - - Are you sure you want to exit Always Offroad mode? - - - - Confirm - ยืนยัน - - - Are you sure you want to enter Always Offroad mode? - - - - Disengage to Enter Always Offroad Mode - - - - Exit Always Offroad - - - - Always Offroad - - - - Quiet Mode - - - - Reset Settings - - - - Are you sure you want to reset all sunnypilot settings to default? Once the settings are reset, there is no going back. - - - - Reset - รีเซ็ต - - - The reset cannot be undone. You have been warned. - - - - Wake-Up Behavior - - - - Interactivity Timeout - - - - Apply a custom timeout for settings UI. -This is the time after which settings UI closes automatically if user is not interacting with the screen. - - - - ⁍ Default: Device will boot/wake-up normally & will be ready to engage. - - - - ⁍ Offroad: Device will be in Always Offroad mode after boot/wake-up. - - - - Controls state of the device after boot/sleep. - - - - - DriveStats - - Drives - - - - Hours - - - - ALL TIME - - - - PAST WEEK - - - - KM - - - - Miles - - DriverViewWindow @@ -572,21 +338,6 @@ This is the time after which settings UI closes automatically if user is not int กำลังเปิดกล้อง - - ExitOffroadButton - - Are you sure you want to exit Always Offroad mode? - - - - Confirm - ยืนยัน - - - EXIT ALWAYS OFFROAD MODE - - - ExperimentalModeButton @@ -600,33 +351,35 @@ This is the time after which settings UI closes automatically if user is not int FirehosePanel + + openpilot learns to drive by watching humans, like you, drive. + +Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode. + openpilot เรียนรู้วิธีขับรถจากการเฝ้าดูการขับขี่ของมนุษย์เช่นคุณ + +โหมดสายยางดับเพลิงช่วยให้คุณอัปโหลดข้อมูลการฝึกฝนได้มากที่สุด เพื่อนำไปพัฒนาโมเดลการขับขี่ของ openpilot ข้อมูลที่มากขึ้นหมายถึงโมเดลที่ใหญ่ขึ้น และนั่นหมายถึงโหมดทดลองที่ดีขึ้น + Firehose Mode: ACTIVE - + โหมดสายยางดับเพลิง: เปิดใช้งาน ACTIVE - + เปิดใช้งาน - For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream sunnypilot (and particular forks) are able to be used for training. - + For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training. + เพื่อประสิทธิภาพสูงสุด ควรนำอุปกรณ์เข้ามาข้างใน เชื่อมต่อกับอะแดปเตอร์ USB-C คุณภาพดี และ Wi-Fi สัปดาห์ละครั้ง<br><br>โหมดสายยางดับเพลิงยังสามารถทำงานระหว่างขับรถได้ หากเชื่อมต่อกับฮอตสปอตหรือซิมการ์ดที่มีเน็ตไม่จำกัด<br><br><br><b>คำถามที่พบบ่อย</b><br><br><i>วิธีการขับหรือสถานที่ขับขี่มีผลหรือไม่?</i>ไม่มีผล แค่ขับขี่ตามปกติของคุณ<br><br><i>เซกเมนต์ทั้งหมดของฉันจะถูกดึงข้อมูลในโหมดสายยางดับเพลิงหรือไม่?</i>ไม่ใช่ เราจะเลือกดึงข้อมูลเพียงบางส่วนจากเซกเมนต์ของคุณ<br><br><i>อะแดปเตอร์ USB-C แบบไหนดี?</i>ที่ชาร์จเร็วของโทรศัพท์หรือแล็ปท็อปแบบใดก็ได้ สามารถใช้ได้<br><br><i>ซอฟต์แวร์ที่ใช้มีผลหรือไม่?</i>มีผล เฉพาะ openpilot ตัวหลัก (และ fork เฉพาะบางตัว) เท่านั้น ที่สามารถนำข้อมูลไปใช้ฝึกฝนโมเดลได้ <b>%n segment(s)</b> of your driving is in the training dataset so far. - - + + มีการขับขี่ของคุณ <b>%n เซกเมนต์</b> อยู่ในชุดข้อมูลการฝึกฝนแล้วในขณะนี้ - - sunnypilot learns to drive by watching humans, like you, drive. - -Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode. - - <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to an unmetered network - + <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>ไม่เปิดใช้งาน</span>: เชื่อมต่อกับเครือข่ายที่ไม่จำกัดข้อมูล Firehose Mode @@ -648,49 +401,6 @@ Firehose Mode allows you to maximize your training data uploads to improve openp สูงสุด - - HyundaiSettings - - Off - - - - Dynamic - - - - Predictive - - - - Custom Longitudinal Tuning - - - - This feature can only be used with openpilot longitudinal control enabled. - - - - Enable "Always Offroad" in Device panel, or turn vehicle off to select an option. - - - - Off: Uses default tuning - - - - Dynamic: Adjusts acceleration limits based on current speed - - - - Predictive: Uses future trajectory data to anticipate needed adjustments - - - - Fine-tune your driving experience by adjusting acceleration smoothness with openpilot longitudinal control. - - - InputDialog @@ -704,321 +414,6 @@ Firehose Mode allows you to maximize your training data uploads to improve openp - - LaneChangeSettings - - Back - ย้อนกลับ - - - Auto Lane Change: Delay with Blind Spot - - - - Toggle to enable a delay timer for seamless lane changes when blind spot monitoring (BSM) detects a obstructing vehicle, ensuring safe maneuvering. - - - - - LateralPanel - - Modular Assistive Driving System (MADS) - - - - Enable the beloved MADS feature. Disable toggle to revert back to stock sunnypilot engagement/disengagement. - - - - Customize MADS - - - - Customize Lane Change - - - - Enables independent engagements of Automatic Lane Centering (ALC) and Adaptive Cruise Control (ACC). - - - - Start the vehicle to check vehicle compatibility. - - - - This platform supports all MADS settings. - - - - This platform supports limited MADS settings. - - - - Pause Lateral Control with Blinker - - - - Pause lateral control with blinker when traveling below the desired speed selected. - - - - - LongitudinalPanel - - Custom ACC Speed Increments - - - - Enable custom Short & Long press increments for cruise speed increase/decrease. - - - - This feature can only be used with openpilot longitudinal control enabled. - - - - This feature is not supported on this platform due to vehicle limitations. - - - - Start the vehicle to check vehicle compatibility. - - - - - MadsSettings - - Toggle with Main Cruise - - - - Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement. - - - - Unified Engagement Mode (UEM) - - - - Engage lateral and longitudinal control with cruise control engagement. - - - - Note: Once lateral control is engaged via UEM, it will remain engaged until it is manually disabled via the MADS button or car shut off. - - - - Remain Active - - - - Disengage - - - - Steering Mode on Brake Pedal - - - - Start the vehicle to check vehicle compatibility. - - - - This feature defaults to OFF, and does not allow selection due to vehicle limitations. - - - - This feature defaults to ON, and does not allow selection due to vehicle limitations. - - - - This platform only supports Disengage mode due to vehicle limitations. - - - - Remain Active: ALC will remain active when the brake pedal is pressed. - - - - Pause - - - - Pause: ALC will pause when the brake pedal is pressed. - - - - Disengage: ALC will disengage when the brake pedal is pressed. - - - - Choose how Automatic Lane Centering (ALC) behaves after the brake pedal is manually pressed in sunnypilot. - - - - - MaxTimeOffroad - - Max Time Offroad - - - - Device will automatically shutdown after set time once the engine is turned off.<br/>(30h is the default) - - - - Always On - - - - h - - - - m - - - - (default) - - - - - ModelsPanel - - Current Model - - - - SELECT - เลือก - - - downloaded - - - - ready - - - - from cache - - - - Fetching models... - - - - Select a Model - - - - Default - - - - Model download has started in the background. - - - - We STRONGLY suggest you to reset calibration. - - - - Would you like to do that now? - - - - Reset Calibration - รีเซ็ตการคาลิเบรท - - - Driving Model Selector - - - - Warning: You are on a metered connection! - - - - Continue - ดำเนินการต่อ - - - on Metered - - - - Cancel - ยกเลิก - - - Clear Model Cache - - - - CLEAR - - - - Driving Model - - - - Navigation Model - - - - Vision Model - - - - Policy Model - - - - Live Learning Steer Delay - - - - Adjust Software Delay - - - - Adjust the software delay when Live Learning Steer Delay is toggled off. -The default software delay value is 0.2 - - - - %1 - %2 - - - - download failed - %1 - - - - pending - %1 - - - - Enable this for the car to learn and adapt its steering response time. Disable to use a fixed steering response time. Keeping this on provides the stock openpilot experience. The Current value is updated automatically when the vehicle is Onroad. - - - - Current: - - - - This will delete ALL downloaded models from the cache<br/><u>except the currently active model</u>.<br/><br/>Are you sure you want to continue? - - - - Clear Cache - - - MultiOptionDialog @@ -1049,76 +444,6 @@ The default software delay value is 0.2 รหัสผ่านผิด - - NetworkingSP - - Scan - - - - Scanning... - - - - - NeuralNetworkLateralControl - - Neural Network Lateral Control (NNLC) - - - - NNLC is currently not available on this platform. - - - - Start the car to check car compatibility - - - - NNLC Not Loaded - - - - NNLC Loaded - - - - Match - - - - Exact - - - - Fuzzy - - - - Match: "Exact" is ideal, but "Fuzzy" is fine too. - - - - Formerly known as <b>"NNFF"</b>, this replaces the lateral <b>"torque"</b> controller, with one using a neural network trained on each car's (actually, each separate EPS firmware) driving data for increased controls accuracy. - - - - Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server - - - - with feedback, or to provide log data for your car if your car is currently unsupported: - - - - if there are any issues: - - - - and donate logs to get NNLC loaded for your car: - - - OffroadAlert @@ -1126,12 +451,12 @@ The default software delay value is 0.2 อุณหภูมิของอุปกรณ์สูงเกินไป ระบบกำลังทำความเย็นก่อนเริ่ม อุณหภูมิของชิ้นส่วนภายในปัจจุบัน: %1 - Immediately connect to the internet to check for updates. If you do not connect to the internet, sunnypilot won't engage in %1 - กรุณาเชื่อมต่ออินเตอร์เน็ตเพื่อตรวจสอบอัปเดทเดี๋ยวนี้ ถ้าคุณไม่เชื่อมต่ออินเตอร์เน็ต sunnypilot จะไม่ทำงานในอีก %1 + Immediately connect to the internet to check for updates. If you do not connect to the internet, openpilot won't engage in %1 + กรุณาเชื่อมต่ออินเตอร์เน็ตเพื่อตรวจสอบอัปเดทเดี๋ยวนี้ ถ้าคุณไม่เชื่อมต่ออินเตอร์เน็ต openpilot จะไม่ทำงานในอีก %1 - Connect to internet to check for updates. sunnypilot won't automatically start until it connects to internet to check for updates. - กรุณาเชื่อมต่ออินเตอร์เน็ตเพื่อตรวจสอบอัปเดท sunnypilot จะไม่เริ่มทำงานอัตโนมัติจนกว่าจะได้เชื่อมต่อกับอินเตอร์เน็ตเพื่อตรวจสอบอัปเดท + Connect to internet to check for updates. openpilot won't automatically start until it connects to internet to check for updates. + กรุณาเชื่อมต่ออินเตอร์เน็ตเพื่อตรวจสอบอัปเดท openpilot จะไม่เริ่มทำงานอัตโนมัติจนกว่าจะได้เชื่อมต่อกับอินเตอร์เน็ตเพื่อตรวจสอบอัปเดท Unable to download updates @@ -1147,30 +472,32 @@ The default software delay value is 0.2 An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. กำลังดาวน์โหลดอัปเดทสำหรับระบบปฏิบัติการอยู่เบื้องหลัง คุณจะได้รับการแจ้งเตือนเมื่อระบบพร้อมสำหรับการติดตั้ง - - Device failed to register. It will not connect to or upload to comma.ai servers, and receives no support from comma.ai. If this is an official device, visit https://comma.ai/support. - ไม่สามารถลงทะเบียนอุปกรณ์ได้ อุปกรณ์จะไม่สามารถเชื่อมต่อหรืออัปโหลดไปยังเซิร์ฟเวอร์ของ comma.ai ได้และจะไม่ได้รับการสนับสนุนจาก comma.ai ถ้านี่คืออุปกรณ์อย่างเป็นทางการ กรุณาติดต่อ https://comma.ai/support - NVMe drive not mounted. ไม่ได้ติดตั้งไดร์ฟ NVMe - Unsupported NVMe drive detected. Device may draw significantly more power and overheat due to the unsupported NVMe. - ตรวจพบไดร์ฟ NVMe ที่ไม่รองรับ อุปกรณ์อาจใช้พลังงานมากขึ้นและร้อนเกินไปเนื่องจากไดร์ฟ NVMe ที่ไม่รองรับ + openpilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. + openpilot ไม่สามารถระบุรถยนต์ของคุณได้ ระบบอาจไม่รองรับรถยนต์ของคุณหรือไม่รู้จัก ECU กรุณาส่ง pull request เพื่อเพิ่มรุ่นของเฟิร์มแวร์ให้กับรถยนต์ที่เหมาะสม หากต้องการความช่วยเหลือให้เข้าร่วม discord.comma.ai - sunnypilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. - sunnypilot ไม่สามารถระบุรถยนต์ของคุณได้ ระบบอาจไม่รองรับรถยนต์ของคุณหรือไม่รู้จัก ECU กรุณาส่ง pull request เพื่อเพิ่มรุ่นของเฟิร์มแวร์ให้กับรถยนต์ที่เหมาะสม หากต้องการความช่วยเหลือให้เข้าร่วม discord.comma.ai + openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. + openpilot ตรวจพบการเปลี่ยนแปลงของตำแหน่งที่ติดตั้ง กรุณาตรวจสอบว่าได้เลื่อนอุปกรณ์เข้ากับจุดติดตั้งจนสุดแล้ว และจุดติดตั้งได้ยึดติดกับกระจกหน้าอย่างแน่นหนา - sunnypilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. - sunnypilot ตรวจพบการเปลี่ยนแปลงของตำแหน่งที่ติดตั้ง กรุณาตรวจสอบว่าได้เลื่อนอุปกรณ์เข้ากับจุดติดตั้งจนสุดแล้ว และจุดติดตั้งได้ยึดติดกับกระจกหน้าอย่างแน่นหนา + Device failed to register with the comma.ai backend. It will not connect or upload to comma.ai servers, and receives no support from comma.ai. If this is a device purchased at comma.ai/shop, open a ticket at https://comma.ai/support. + - OpenStreetMap database is out of date. New maps must be downloaded if you wish to continue using OpenStreetMap data for Enhanced Speed Control and road name display. - -%1 + Acknowledge Excessive Actuation + + + + Snooze Update + เลื่อนการอัปเดต + + + openpilot has detected excessive %1 actuation. This may be due to a software bug. Please contact support at https://comma.ai/support. @@ -1189,18 +516,11 @@ The default software delay value is 0.2 การแจ้งเตือน - - OffroadHomeSP - - ALWAYS OFFROAD ACTIVE - - - OnroadAlerts - sunnypilot Unavailable - sunnypilot ไม่สามารถใช้งานได้ + openpilot Unavailable + openpilot ไม่สามารถใช้งานได้ TAKE CONTROL IMMEDIATELY @@ -1212,142 +532,11 @@ The default software delay value is 0.2 Waiting to start - + รอเริ่มทำงาน System Unresponsive - - - - - OsmPanel - - Mapd Version - - - - Offline Maps ETA - - - - Time Elapsed - - - - Downloaded Maps - - - - DELETE - - - - This will delete ALL downloaded maps - -Are you sure you want to delete all the maps? - - - - Yes, delete all the maps. - - - - Database Update - - - - CHECK - ตรวจสอบ - - - Country - - - - SELECT - เลือก - - - Fetching Country list... - - - - State - - - - Fetching State list... - - - - All - - - - REFRESH - - - - UPDATE - อัปเดต - - - Download starting... - - - - Error: Invalid download. Retry. - - - - Download complete! - - - - - -Warning: You are on a metered connection! - - - - This will start the download process and it might take a while to complete. - - - - Continue on Metered - - - - Start Download - - - - m - - - - s - - - - Calculating... - - - - Downloaded - - - - Calculating ETA... - - - - Ready - - - - Time remaining: - + ระบบไม่ตอบสนอง @@ -1370,7 +559,7 @@ Warning: You are on a metered connection! Please connect to Wi-Fi to complete initial pairing - + กรุณาเชื่อมต่อ Wi-Fi เพื่อทำการจับคู่ครั้งแรกให้เสร็จสิ้น @@ -1384,96 +573,6 @@ Warning: You are on a metered connection! ยกเลิก - - ParamControlSP - - Enable - เปิดใช้งาน - - - Cancel - ยกเลิก - - - - PlatformSelector - - Vehicle - - - - SEARCH - - - - Search your vehicle - - - - Enter model year (e.g., 2021) and model name (Toyota Corolla): - - - - SEARCHING - - - - REMOVE - ลบ - - - This setting will take effect immediately. - - - - This setting will take effect once the device enters offroad state. - - - - Vehicle Selector - - - - Confirm - ยืนยัน - - - Cancel - ยกเลิก - - - No vehicles found for query: %1 - - - - Select a vehicle - - - - Unrecognized Vehicle - - - - Fingerprinted automatically - - - - Manually selected - - - - Not fingerprinted or manually selected - - - - Select vehicle to force fingerprint manually. - - - - Colors represent fingerprint status: - - - PrimeAdWidget @@ -1502,7 +601,7 @@ Warning: You are on a metered connection! Remote snapshots - + ภาพถ่ายระยะไกล @@ -1519,8 +618,8 @@ Warning: You are on a metered connection! QObject - sunnypilot - sunnypilot + openpilot + openpilot %n minute(s) ago @@ -1545,47 +644,6 @@ Warning: You are on a metered connection! ตอนนี้ - - Reset - - Reset failed. Reboot to try again. - การรีเซ็ตล้มเหลว รีบูตเพื่อลองอีกครั้ง - - - Are you sure you want to reset your device? - คุณแน่ใจหรือไม่ว่าต้องการรีเซ็ตอุปกรณ์? - - - System Reset - รีเซ็ตระบบ - - - Cancel - ยกเลิก - - - Reboot - รีบูต - - - Confirm - ยืนยัน - - - Resetting device... -This may take up to a minute. - กำลังรีเซ็ตอุปกรณ์... -อาจใช้เวลาถึงหนึ่งนาที - - - Unable to mount data partition. Partition may be corrupted. Press confirm to erase and reset your device. - ไม่สามารถเมานต์พาร์ติชั่นข้อมูลได้ พาร์ติชั่นอาจเสียหาย กดยืนยันเพื่อลบและรีเซ็ตอุปกรณ์ของคุณ - - - System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot. - ระบบถูกรีเซ็ต กดยืนยันเพื่อลบข้อมูลและการตั้งค่าทั้งหมด กดยกเลิกเพื่อบูตต่อ - - SettingsWindow @@ -1610,74 +668,11 @@ This may take up to a minute. Developer - + นักพัฒนา Firehose - - - - - SettingsWindowSP - - × - × - - - Device - อุปกรณ์ - - - Network - เครือข่าย - - - sunnylink - - - - Toggles - ตัวเลือก - - - Software - ซอฟต์แวร์ - - - Trips - - - - Vehicle - - - - Developer - - - - Firehose - - - - Steering - - - - Models - - - - Cruise - - - - Visuals - - - - OSM - + สายยางดับเพลิง @@ -1767,8 +762,8 @@ This may take up to a minute. เลือกซอฟต์แวร์ที่จะติดตั้ง - sunnypilot - sunnypilot + openpilot + openpilot Custom Software @@ -1875,33 +870,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 5G - - SidebarSP - - DISABLED - - - - OFFLINE - ออฟไลน์ - - - REGIST... - - - - ONLINE - ออนไลน์ - - - ERROR - เกิดข้อผิดพลาด - - - SUNNYLINK - - - SoftwarePanel @@ -1977,49 +945,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device ล่าสุดแล้ว ตรวจสอบครั้งสุดท้ายเมื่อ %1 - - SoftwarePanelSP - - Search Branch - - - - Enter search keywords, or leave blank to list all branches. - - - - No branches found for keywords: %1 - - - - Select a branch - เลือก Branch - - - Disable Updates - - - - When enabled, software updates will be disabled. <b>This requires a reboot to take effect.</b> - - - - %1 updates requires a reboot.<br>Reboot now? - - - - Reboot - รีบูต - - - When enabled, software updates will be disabled.<br><b>This requires a reboot to take effect.</b> - - - - Please enable always offroad mode or turn off vehicle to adjust these toggles - - - SshControl @@ -2066,168 +991,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device เปิดใช้งาน SSH - - SunnylinkPanel - - This is the master switch, it will allow you to cutoff any sunnylink requests should you want to do that. - - - - Enable sunnylink - - - - 🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀 - - - - 👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉. - - - - Device ID - - - - N/A - ไม่มี - - - Sponsor Status - - - - SPONSOR - - - - Become a sponsor of sunnypilot to get early access to sunnylink features when they become available. - - - - Pair GitHub Account - - - - PAIR - จับคู่ - - - Pair your GitHub account to grant your device sponsor benefits, including API access on sunnylink. - - - - sunnylink Dongle ID not found. This may be due to weak internet connection or sunnylink registration issue. Please reboot and try again. - - - - Not Sponsor - - - - Paired - - - - Not Paired - - - - THANKS ♥ - - - - Backup Settings - - - - Are you sure you want to backup sunnypilot settings? - - - - Back Up - - - - Restore Settings - - - - Are you sure you want to restore the last backed up sunnypilot settings? - - - - Restore - - - - Backup in progress %1% - - - - Backup Failed - - - - Settings backup completed. - - - - Restore in progress %1% - - - - Restore Failed - - - - Unable to restore the settings, try again later. - - - - Settings restored. Confirm to restart the interface. - - - - - SunnylinkSponsorPopup - - Scan the QR code to login to your GitHub account - - - - Follow the prompts to complete the pairing process - - - - Re-enter the "sunnylink" panel to verify sponsorship status - - - - If sponsorship status was not updated, please contact a moderator on Discord at https://discord.gg/sunnypilot - - - - Scan the QR code to visit sunnyhaibin's GitHub Sponsors page - - - - Choose your sponsorship tier and confirm your support - - - - Join our community on Discord at https://discord.gg/sunnypilot and reach out to a moderator to confirm your sponsor status - - - - Pair your GitHub account - - - - Early Access: Become a sunnypilot Sponsor - - - TermsPage @@ -2239,16 +1002,20 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device ยอมรับ - Welcome to sunnypilot - + Welcome to openpilot + ยินดีต้อนรับสู่ openpilot - You must accept the Terms and Conditions to use sunnypilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing. - + You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing. + คุณต้องยอมรับข้อกำหนดและเงื่อนไขเพื่อใช้งาน openpilot อ่านข้อกำหนดล่าสุดได้ที่ <span style='color: #465BEA;'>https://comma.ai/terms</span> ก่อนดำเนินการต่อ TogglesPanel + + Enable openpilot + เปิดใช้งาน openpilot + Enable Lane Departure Warnings เปิดใช้งานการเตือนการออกนอกเลน @@ -2278,20 +1045,20 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device ยกเลิกระบบช่วยขับเมื่อเหยียบคันเร่ง - When enabled, pressing the accelerator pedal will disengage sunnypilot. - เมื่อเปิดใช้งาน การกดแป้นคันเร่งจะเป็นการยกเลิกระบบช่วยขับโดย sunnypilot + When enabled, pressing the accelerator pedal will disengage openpilot. + เมื่อเปิดใช้งาน การกดแป้นคันเร่งจะเป็นการยกเลิกระบบช่วยขับโดย openpilot Experimental Mode โหมดทดลอง - sunnypilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: - โดยปกติ sunnypilot จะขับใน<b>โหมดชิล</b> เปิดโหมดทดลองเพื่อใช้<b>ความสามารถในขั้นพัฒนา</b> ซึ่งยังไม่พร้อมสำหรับโหมดชิล ความสามารถในขั้นพัฒนามีดังนี้: + openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: + โดยปกติ openpilot จะขับใน<b>โหมดชิล</b> เปิดโหมดทดลองเพื่อใช้<b>ความสามารถในขั้นพัฒนา</b> ซึ่งยังไม่พร้อมสำหรับโหมดชิล ความสามารถในขั้นพัฒนามีดังนี้: - Let the driving model control the gas and brakes. sunnypilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. - ให้ sunnypilot ควบคุมการเร่ง/เบรค โดย sunnypilot จะขับอย่างที่มนุษย์คิด รวมถึงการหยุดที่ไฟแดง และป้ายหยุดรถ เนื่องจาก sunnypilot จะกำหนดความเร็วในการขับด้วยตัวเอง การตั้งความเร็วจะเป็นเพียงการกำหนดความเร็วสูงสูดเท่านั้น ความสามารถนี้ยังอยู่ในขั้นพัฒนา อาจเกิดข้อผิดพลาดขึ้นได้ + Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. + ให้ openpilot ควบคุมการเร่ง/เบรค โดย openpilot จะขับอย่างที่มนุษย์คิด รวมถึงการหยุดที่ไฟแดง และป้ายหยุดรถ เนื่องจาก openpilot จะกำหนดความเร็วในการขับด้วยตัวเอง การตั้งความเร็วจะเป็นเพียงการกำหนดความเร็วสูงสูดเท่านั้น ความสามารถนี้ยังอยู่ในขั้นพัฒนา อาจเกิดข้อผิดพลาดขึ้นได้ New Driving Visualization @@ -2301,6 +1068,10 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. ขณะนี้โหมดทดลองไม่สามารถใช้งานได้ในรถคันนี้ เนื่องจากเปิดใช้ระบบควบคุมการเร่ง/เบรคของรถที่ติดตั้งจากโรงงานอยู่ + + openpilot longitudinal control may come in a future update. + ระบบควบคุมการเร่ง/เบรคโดย openpilot อาจมาในการอัปเดตในอนาคต + Aggressive ดุดัน @@ -2318,20 +1089,20 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device บุคลิกการขับขี่ - An alpha version of sunnypilot longitudinal control can be tested, along with Experimental mode, on non-release branches. - ระบบควบคุมการเร่ง/เบรคโดย sunnypilot เวอร์ชัน alpha สามารถทดสอบได้พร้อมกับโหมดการทดลอง บน branch ที่กำลังพัฒนา + An alpha version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + ระบบควบคุมการเร่ง/เบรคโดย openpilot เวอร์ชัน alpha สามารถทดสอบได้พร้อมกับโหมดการทดลอง บน branch ที่กำลังพัฒนา End-to-End Longitudinal Control ควบคุมเร่ง/เบรคแบบ End-to-End - Enable the sunnypilot longitudinal control (alpha) toggle to allow Experimental mode. - เปิดระบบควบคุมการเร่ง/เบรคโดย sunnypilot (alpha) เพื่อเปิดใช้งานโหมดทดลอง + Enable the openpilot longitudinal control (alpha) toggle to allow Experimental mode. + เปิดระบบควบคุมการเร่ง/เบรคโดย openpilot (alpha) เพื่อเปิดใช้งานโหมดทดลอง - Standard is recommended. In aggressive mode, sunnypilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode sunnypilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. - แนะนำให้ใช้แบบมาตรฐาน ในโหมดดุดัน sunnypilot จะตามรถคันหน้าใกล้ขึ้นและเร่งและเบรคแบบดุดันมากขึ้น ในโหมดผ่อนคลาย sunnypilot จะอยู่ห่างจากรถคันหน้ามากขึ้น ในรถรุ่นที่รองรับคุณสามารถเปลี่ยนบุคลิกไปแบบต่าง ๆ โดยใช้ปุ่มปรับระยะห่างบนพวงมาลัย + Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. + แนะนำให้ใช้แบบมาตรฐาน ในโหมดดุดัน openpilot จะตามรถคันหน้าใกล้ขึ้นและเร่งและเบรคแบบดุดันมากขึ้น ในโหมดผ่อนคลาย openpilot จะอยู่ห่างจากรถคันหน้ามากขึ้น ในรถรุ่นที่รองรับคุณสามารถเปลี่ยนบุคลิกไปแบบต่าง ๆ โดยใช้ปุ่มปรับระยะห่างบนพวงมาลัย The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. @@ -2339,36 +1110,20 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device Always-On Driver Monitoring - + การเฝ้าระวังผู้ขับขี่ตลอดเวลา - Enable driver monitoring even when sunnypilot is not engaged. - + Enable driver monitoring even when openpilot is not engaged. + เปิดใช้งานการเฝ้าระวังผู้ขับขี่แม้เมื่อ openpilot ไม่ได้เข้าควบคุมอยู่ - Enable Dynamic Experimental Control - - - - Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal. - - - - Enable sunnypilot - เปิดใช้งาน sunnypilot - - - Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. + Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting will restart openpilot if the car is powered on. - - openpilot longitudinal control may come in a future update. - - Record and Upload Microphone Audio @@ -2378,108 +1133,19 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device - - TreeOptionDialog - - Select - เลือก - - - Cancel - ยกเลิก - - - - Updater - - Update Required - จำเป็นต้องอัปเดต - - - An operating system update is required. Connect your device to Wi-Fi for the fastest update experience. The download size is approximately 1GB. - จำเป็นต้องมีการอัปเดตระบบปฏิบัติการ เชื่อมต่ออุปกรณ์ของคุณกับ Wi-Fi เพื่อประสบการณ์การอัปเดตที่เร็วที่สุด ขนาดดาวน์โหลดประมาณ 1GB - - - Connect to Wi-Fi - เชื่อมต่อกับ Wi-Fi - - - Install - ติดตั้ง - - - Back - ย้อนกลับ - - - Loading... - กำลังโหลด... - - - Reboot - รีบูต - - - Update failed - การอัปเดตล้มเหลว - - - - VisualsPanel - - Show Blind Spot Warnings - - - - Enabling this will display warnings when a vehicle is detected in your blind spot as long as your car has BSM supported. - - - - Changing this setting will restart openpilot if the car is powered on. - - - - Off - - - - Distance - - - - Speed - - - - Time - - - - All - - - - Display Metrics Below Chevron - - - - Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control). - - - WiFiPromptWidget Open - - - - <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span> - + เปิด Maximize your training data uploads to improve openpilot's driving models. - + อัปโหลดข้อมูลการฝึกฝนให้ได้มากที่สุด เพื่อพัฒนาโมเดลการขับขี่ของ openpilot + + + <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span> + <span style='font-family: "Noto Color Emoji";'>🔥</span> โหมดสายยางดับเพลิง <span style='font-family: Noto Color Emoji;'>🔥</span> diff --git a/selfdrive/ui/translations/main_tr.ts b/selfdrive/ui/translations/main_tr.ts index 3677ba0329..6cafb1dffc 100644 --- a/selfdrive/ui/translations/main_tr.ts +++ b/selfdrive/ui/translations/main_tr.ts @@ -7,10 +7,6 @@ Close Kapat - - Snooze Update - Güncellemeyi sessize al - Reboot and Update Güncelle ve Yeniden başlat @@ -107,53 +103,6 @@ - - AutoLaneChangeTimer - - Auto Lane Change by Blinker - - - - Set a timer to delay the auto lane change operation when the blinker is used. No nudge on the steering wheel is required to auto lane change if a timer is set. Default is Nudge. -Please use caution when using this feature. Only use the blinker when traffic and road conditions permit. - - - - s - - - - Off - - - - Nudge - - - - Nudgeless - - - - - Brightness - - Brightness - - - - Overrides the brightness of the device. - - - - Auto (Dark) - - - - Auto - - - ConfirmationDialog @@ -168,7 +117,7 @@ Please use caution when using this feature. Only use the blinker when traffic an DeclinePage - You must accept the Terms and Conditions in order to use sunnypilot. + You must accept the Terms and Conditions in order to use openpilot. Openpilotu kullanmak için Kullanıcı Koşullarını kabul etmelisiniz. @@ -190,14 +139,6 @@ Please use caution when using this feature. Only use the blinker when traffic an Longitudinal Maneuver Mode - - Enable ADB - - - - ADB (Android Debug Bridge) allows connecting to your device over USB or over the network. See https://docs.comma.ai/how-to/connect-to-comma for more info. - - openpilot Longitudinal Control (Alpha) @@ -207,51 +148,15 @@ Please use caution when using this feature. Only use the blinker when traffic an - On this car, sunnypilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. - - - - - DeveloperPanelSP - - Show Advanced Controls + On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. - Toggle visibility of advanced sunnypilot controls. -This only toggles the visibility of the controls; it does not toggle the actual control enabled/disabled state. + Enable ADB - Enable GitHub runner service - - - - Enables or disables the github runner service. - - - - Enable Quickboot Mode - - - - Error Log - - - - VIEW - BAK - - - View the error log for sunnypilot crashes. - - - - When toggled on, this creates a prebuilt file to allow accelerated boot times. When toggled off, it immediately removes the prebuilt file so compilation of locally edited cpp files can be made. <br><br><b>To edit C++ files locally on device, you MUST first turn off this toggle so the changes can recompile.</b> - - - - Quickboot mode requires updates to be disabled.<br>Enable 'Disable Updates' in the Software panel first. + ADB (Android Debug Bridge) allows connecting to your device over USB or over the network. See https://docs.comma.ai/how-to/connect-to-comma for more info. @@ -302,8 +207,8 @@ This only toggles the visibility of the controls; it does not toggle the actual GÖZDEN GEÇİR - Review the rules, features, and limitations of sunnypilot - sunnypilot sisteminin kurallarını ve sınırlamalarını gözden geçirin. + Review the rules, features, and limitations of openpilot + openpilot sisteminin kurallarını ve sınırlamalarını gözden geçirin. Are you sure you want to review the training guide? @@ -398,7 +303,11 @@ This only toggles the visibility of the controls; it does not toggle the actual - sunnypilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. + openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. + + + + openpilot is continuously calibrating, resetting is rarely required. Resetting calibration will restart openpilot if the car is powered on. @@ -421,149 +330,6 @@ Steering lag calibration is complete. Steering torque response calibration is complete. - - openpilot is continuously calibrating, resetting is rarely required. Resetting calibration will restart openpilot if the car is powered on. - - - - - DevicePanelSP - - Driver Camera Preview - - - - Training Guide - - - - Regulatory - Mevzuat - - - Language - - - - Are you sure you want to review the training guide? - Eğitim kılavuzunu incelemek istediğinizden emin misiniz? - - - Review - - - - Select a language - Dil seçin - - - Reboot - Yeniden başlat - - - Power Off - Sistemi kapat - - - Offroad Mode - - - - Are you sure you want to exit Always Offroad mode? - - - - Confirm - Onayla - - - Are you sure you want to enter Always Offroad mode? - - - - Disengage to Enter Always Offroad Mode - - - - Exit Always Offroad - - - - Always Offroad - - - - Quiet Mode - - - - Reset Settings - - - - Are you sure you want to reset all sunnypilot settings to default? Once the settings are reset, there is no going back. - - - - Reset - - - - The reset cannot be undone. You have been warned. - - - - Wake-Up Behavior - - - - Interactivity Timeout - - - - Apply a custom timeout for settings UI. -This is the time after which settings UI closes automatically if user is not interacting with the screen. - - - - ⁍ Default: Device will boot/wake-up normally & will be ready to engage. - - - - ⁍ Offroad: Device will be in Always Offroad mode after boot/wake-up. - - - - Controls state of the device after boot/sleep. - - - - - DriveStats - - Drives - - - - Hours - - - - ALL TIME - - - - PAST WEEK - - - - KM - - - - Miles - - DriverViewWindow @@ -572,21 +338,6 @@ This is the time after which settings UI closes automatically if user is not int kamera başlatılıyor - - ExitOffroadButton - - Are you sure you want to exit Always Offroad mode? - - - - Confirm - Onayla - - - EXIT ALWAYS OFFROAD MODE - - - ExperimentalModeButton @@ -600,6 +351,12 @@ This is the time after which settings UI closes automatically if user is not int FirehosePanel + + openpilot learns to drive by watching humans, like you, drive. + +Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode. + + Firehose Mode: ACTIVE @@ -609,7 +366,7 @@ This is the time after which settings UI closes automatically if user is not int - For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream sunnypilot (and particular forks) are able to be used for training. + For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training. @@ -618,12 +375,6 @@ This is the time after which settings UI closes automatically if user is not int - - sunnypilot learns to drive by watching humans, like you, drive. - -Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode. - - <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to an unmetered network @@ -648,49 +399,6 @@ Firehose Mode allows you to maximize your training data uploads to improve openp MAX - - HyundaiSettings - - Off - - - - Dynamic - - - - Predictive - - - - Custom Longitudinal Tuning - - - - This feature can only be used with openpilot longitudinal control enabled. - - - - Enable "Always Offroad" in Device panel, or turn vehicle off to select an option. - - - - Off: Uses default tuning - - - - Dynamic: Adjusts acceleration limits based on current speed - - - - Predictive: Uses future trajectory data to anticipate needed adjustments - - - - Fine-tune your driving experience by adjusting acceleration smoothness with openpilot longitudinal control. - - - InputDialog @@ -704,321 +412,6 @@ Firehose Mode allows you to maximize your training data uploads to improve openp - - LaneChangeSettings - - Back - - - - Auto Lane Change: Delay with Blind Spot - - - - Toggle to enable a delay timer for seamless lane changes when blind spot monitoring (BSM) detects a obstructing vehicle, ensuring safe maneuvering. - - - - - LateralPanel - - Modular Assistive Driving System (MADS) - - - - Enable the beloved MADS feature. Disable toggle to revert back to stock sunnypilot engagement/disengagement. - - - - Customize MADS - - - - Customize Lane Change - - - - Enables independent engagements of Automatic Lane Centering (ALC) and Adaptive Cruise Control (ACC). - - - - Start the vehicle to check vehicle compatibility. - - - - This platform supports all MADS settings. - - - - This platform supports limited MADS settings. - - - - Pause Lateral Control with Blinker - - - - Pause lateral control with blinker when traveling below the desired speed selected. - - - - - LongitudinalPanel - - Custom ACC Speed Increments - - - - Enable custom Short & Long press increments for cruise speed increase/decrease. - - - - This feature can only be used with openpilot longitudinal control enabled. - - - - This feature is not supported on this platform due to vehicle limitations. - - - - Start the vehicle to check vehicle compatibility. - - - - - MadsSettings - - Toggle with Main Cruise - - - - Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement. - - - - Unified Engagement Mode (UEM) - - - - Engage lateral and longitudinal control with cruise control engagement. - - - - Note: Once lateral control is engaged via UEM, it will remain engaged until it is manually disabled via the MADS button or car shut off. - - - - Remain Active - - - - Disengage - - - - Steering Mode on Brake Pedal - - - - Start the vehicle to check vehicle compatibility. - - - - This feature defaults to OFF, and does not allow selection due to vehicle limitations. - - - - This feature defaults to ON, and does not allow selection due to vehicle limitations. - - - - This platform only supports Disengage mode due to vehicle limitations. - - - - Remain Active: ALC will remain active when the brake pedal is pressed. - - - - Pause - - - - Pause: ALC will pause when the brake pedal is pressed. - - - - Disengage: ALC will disengage when the brake pedal is pressed. - - - - Choose how Automatic Lane Centering (ALC) behaves after the brake pedal is manually pressed in sunnypilot. - - - - - MaxTimeOffroad - - Max Time Offroad - - - - Device will automatically shutdown after set time once the engine is turned off.<br/>(30h is the default) - - - - Always On - - - - h - - - - m - - - - (default) - - - - - ModelsPanel - - Current Model - - - - SELECT - - - - downloaded - - - - ready - - - - from cache - - - - Fetching models... - - - - Select a Model - - - - Default - - - - Model download has started in the background. - - - - We STRONGLY suggest you to reset calibration. - - - - Would you like to do that now? - - - - Reset Calibration - Kalibrasyonu sıfırla - - - Driving Model Selector - - - - Warning: You are on a metered connection! - - - - Continue - Devam et - - - on Metered - - - - Cancel - - - - Clear Model Cache - - - - CLEAR - - - - Driving Model - - - - Navigation Model - - - - Vision Model - - - - Policy Model - - - - Live Learning Steer Delay - - - - Adjust Software Delay - - - - Adjust the software delay when Live Learning Steer Delay is toggled off. -The default software delay value is 0.2 - - - - %1 - %2 - - - - download failed - %1 - - - - pending - %1 - - - - Enable this for the car to learn and adapt its steering response time. Disable to use a fixed steering response time. Keeping this on provides the stock openpilot experience. The Current value is updated automatically when the vehicle is Onroad. - - - - Current: - - - - This will delete ALL downloaded models from the cache<br/><u>except the currently active model</u>.<br/><br/>Are you sure you want to continue? - - - - Clear Cache - - - MultiOptionDialog @@ -1049,76 +442,6 @@ The default software delay value is 0.2 Yalnış parola - - NetworkingSP - - Scan - - - - Scanning... - - - - - NeuralNetworkLateralControl - - Neural Network Lateral Control (NNLC) - - - - NNLC is currently not available on this platform. - - - - Start the car to check car compatibility - - - - NNLC Not Loaded - - - - NNLC Loaded - - - - Match - - - - Exact - - - - Fuzzy - - - - Match: "Exact" is ideal, but "Fuzzy" is fine too. - - - - Formerly known as <b>"NNFF"</b>, this replaces the lateral <b>"torque"</b> controller, with one using a neural network trained on each car's (actually, each separate EPS firmware) driving data for increased controls accuracy. - - - - Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server - - - - with feedback, or to provide log data for your car if your car is currently unsupported: - - - - if there are any issues: - - - - and donate logs to get NNLC loaded for your car: - - - OffroadAlert @@ -1126,11 +449,11 @@ The default software delay value is 0.2 - Immediately connect to the internet to check for updates. If you do not connect to the internet, sunnypilot won't engage in %1 + Immediately connect to the internet to check for updates. If you do not connect to the internet, openpilot won't engage in %1 - Connect to internet to check for updates. sunnypilot won't automatically start until it connects to internet to check for updates. + Connect to internet to check for updates. openpilot won't automatically start until it connects to internet to check for updates. @@ -1146,30 +469,32 @@ The default software delay value is 0.2 An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. - - Device failed to register. It will not connect to or upload to comma.ai servers, and receives no support from comma.ai. If this is an official device, visit https://comma.ai/support. - - NVMe drive not mounted. - Unsupported NVMe drive detected. Device may draw significantly more power and overheat due to the unsupported NVMe. + openpilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. - sunnypilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. + openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. - sunnypilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. + Device failed to register with the comma.ai backend. It will not connect or upload to comma.ai servers, and receives no support from comma.ai. If this is a device purchased at comma.ai/shop, open a ticket at https://comma.ai/support. - OpenStreetMap database is out of date. New maps must be downloaded if you wish to continue using OpenStreetMap data for Enhanced Speed Control and road name display. - -%1 + Acknowledge Excessive Actuation + + + + Snooze Update + Güncellemeyi sessize al + + + openpilot has detected excessive %1 actuation. This may be due to a software bug. Please contact support at https://comma.ai/support. @@ -1188,17 +513,10 @@ The default software delay value is 0.2 UYARI - - OffroadHomeSP - - ALWAYS OFFROAD ACTIVE - - - OnroadAlerts - sunnypilot Unavailable + openpilot Unavailable @@ -1218,137 +536,6 @@ The default software delay value is 0.2 - - OsmPanel - - Mapd Version - - - - Offline Maps ETA - - - - Time Elapsed - - - - Downloaded Maps - - - - DELETE - - - - This will delete ALL downloaded maps - -Are you sure you want to delete all the maps? - - - - Yes, delete all the maps. - - - - Database Update - - - - CHECK - KONTROL ET - - - Country - - - - SELECT - - - - Fetching Country list... - - - - State - - - - Fetching State list... - - - - All - - - - REFRESH - - - - UPDATE - GÜNCELLE - - - Download starting... - - - - Error: Invalid download. Retry. - - - - Download complete! - - - - - -Warning: You are on a metered connection! - - - - This will start the download process and it might take a while to complete. - - - - Continue on Metered - - - - Start Download - - - - m - - - - s - - - - Calculating... - - - - Downloaded - - - - Calculating ETA... - - - - Ready - - - - Time remaining: - - - PairingPopup @@ -1383,96 +570,6 @@ Warning: You are on a metered connection! - - ParamControlSP - - Enable - - - - Cancel - - - - - PlatformSelector - - Vehicle - - - - SEARCH - - - - Search your vehicle - - - - Enter model year (e.g., 2021) and model name (Toyota Corolla): - - - - SEARCHING - - - - REMOVE - KALDIR - - - This setting will take effect immediately. - - - - This setting will take effect once the device enters offroad state. - - - - Vehicle Selector - - - - Confirm - Onayla - - - Cancel - - - - No vehicles found for query: %1 - - - - Select a vehicle - - - - Unrecognized Vehicle - - - - Fingerprinted automatically - - - - Manually selected - - - - Not fingerprinted or manually selected - - - - Select vehicle to force fingerprint manually. - - - - Colors represent fingerprint status: - - - PrimeAdWidget @@ -1518,8 +615,8 @@ Warning: You are on a metered connection! QObject - sunnypilot - sunnypilot + openpilot + openpilot %n minute(s) ago @@ -1544,46 +641,6 @@ Warning: You are on a metered connection! - - Reset - - Reset failed. Reboot to try again. - Sıfırlama başarız oldu. Cihazı yeniden başlatın ve tekrar deneyin. - - - Are you sure you want to reset your device? - Cihazı sıfırlamak istediğinizden eminmisiniz ? - - - System Reset - Sistemi sıfırla - - - Cancel - İptal - - - Reboot - Yeniden başlat - - - Confirm - Onayla - - - Resetting device... -This may take up to a minute. - - - - Unable to mount data partition. Partition may be corrupted. Press confirm to erase and reset your device. - - - - System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot. - - - SettingsWindow @@ -1615,69 +672,6 @@ This may take up to a minute. - - SettingsWindowSP - - × - x - - - Device - Cihaz - - - Network - - - - sunnylink - - - - Toggles - Değiştirme - - - Software - Yazılım - - - Trips - - - - Vehicle - - - - Developer - - - - Firehose - - - - Steering - - - - Models - - - - Cruise - - - - Visuals - - - - OSM - - - Setup @@ -1765,8 +759,8 @@ This may take up to a minute. - sunnypilot - sunnypilot + openpilot + openpilot Custom Software @@ -1873,33 +867,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 5G - - SidebarSP - - DISABLED - - - - OFFLINE - ÇEVRİMDIŞI - - - REGIST... - - - - ONLINE - ÇEVRİMİÇİ - - - ERROR - HATA - - - SUNNYLINK - - - SoftwarePanel @@ -1975,49 +942,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device - - SoftwarePanelSP - - Search Branch - - - - Enter search keywords, or leave blank to list all branches. - - - - No branches found for keywords: %1 - - - - Select a branch - - - - Disable Updates - - - - When enabled, software updates will be disabled. <b>This requires a reboot to take effect.</b> - - - - %1 updates requires a reboot.<br>Reboot now? - - - - Reboot - Yeniden başlat - - - When enabled, software updates will be disabled.<br><b>This requires a reboot to take effect.</b> - - - - Please enable always offroad mode or turn off vehicle to adjust these toggles - - - SshControl @@ -2064,168 +988,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device SSH aç - - SunnylinkPanel - - This is the master switch, it will allow you to cutoff any sunnylink requests should you want to do that. - - - - Enable sunnylink - - - - 🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀 - - - - 👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉. - - - - Device ID - - - - N/A - N/A - - - Sponsor Status - - - - SPONSOR - - - - Become a sponsor of sunnypilot to get early access to sunnylink features when they become available. - - - - Pair GitHub Account - - - - PAIR - - - - Pair your GitHub account to grant your device sponsor benefits, including API access on sunnylink. - - - - sunnylink Dongle ID not found. This may be due to weak internet connection or sunnylink registration issue. Please reboot and try again. - - - - Not Sponsor - - - - Paired - - - - Not Paired - - - - THANKS ♥ - - - - Backup Settings - - - - Are you sure you want to backup sunnypilot settings? - - - - Back Up - - - - Restore Settings - - - - Are you sure you want to restore the last backed up sunnypilot settings? - - - - Restore - - - - Backup in progress %1% - - - - Backup Failed - - - - Settings backup completed. - - - - Restore in progress %1% - - - - Restore Failed - - - - Unable to restore the settings, try again later. - - - - Settings restored. Confirm to restart the interface. - - - - - SunnylinkSponsorPopup - - Scan the QR code to login to your GitHub account - - - - Follow the prompts to complete the pairing process - - - - Re-enter the "sunnylink" panel to verify sponsorship status - - - - If sponsorship status was not updated, please contact a moderator on Discord at https://discord.gg/sunnypilot - - - - Scan the QR code to visit sunnyhaibin's GitHub Sponsors page - - - - Choose your sponsorship tier and confirm your support - - - - Join our community on Discord at https://discord.gg/sunnypilot and reach out to a moderator to confirm your sponsor status - - - - Pair your GitHub account - - - - Early Access: Become a sunnypilot Sponsor - - - TermsPage @@ -2237,16 +999,20 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device Kabul et - Welcome to sunnypilot + Welcome to openpilot - You must accept the Terms and Conditions to use sunnypilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing. + You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing. TogglesPanel + + Enable openpilot + openpilot'u aktifleştir + Enable Lane Departure Warnings Şerit ihlali uyarı alın @@ -2272,8 +1038,8 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device Sürücüye bakan kamera verisini yükleyin ve Cihazın algoritmasını geliştirmemize yardımcı olun. - When enabled, pressing the accelerator pedal will disengage sunnypilot. - Aktifleştirilirse eğer gaz pedalına basınca sunnypilot devre dışı kalır. + When enabled, pressing the accelerator pedal will disengage openpilot. + Aktifleştirilirse eğer gaz pedalına basınca openpilot devre dışı kalır. Experimental Mode @@ -2300,7 +1066,7 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device - sunnypilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: + openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: @@ -2308,7 +1074,7 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device - Let the driving model control the gas and brakes. sunnypilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. + Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. @@ -2320,15 +1086,19 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device - An alpha version of sunnypilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + openpilot longitudinal control may come in a future update. - Enable the sunnypilot longitudinal control (alpha) toggle to allow Experimental mode. + An alpha version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. - Standard is recommended. In aggressive mode, sunnypilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode sunnypilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. + Enable the openpilot longitudinal control (alpha) toggle to allow Experimental mode. + + + + Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. @@ -2340,33 +1110,17 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device - Enable driver monitoring even when sunnypilot is not engaged. + Enable driver monitoring even when openpilot is not engaged. - Enable Dynamic Experimental Control - - - - Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal. - - - - Enable sunnypilot - sunnypilot'u aktifleştir - - - Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. + Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting will restart openpilot if the car is powered on. - - openpilot longitudinal control may come in a future update. - - Record and Upload Microphone Audio @@ -2376,95 +1130,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device - - TreeOptionDialog - - Select - Seç - - - Cancel - - - - - Updater - - Update Required - Güncelleme yapılması gerekli - - - An operating system update is required. Connect your device to Wi-Fi for the fastest update experience. The download size is approximately 1GB. - İşletim sistemi güncellemesi gerekmektedir. Lütfen Cihazı daha hızlı günceleyebilmesi için bir sonraki başlatılışında çekilir. Wi-Fi ağına bağlayın. Dosyanın boyutu yaklaşık 1GB dır. - - - Connect to Wi-Fi - Wi-Fi ağına bağlan - - - Install - Yükle - - - Back - Geri - - - Loading... - Yükleniyor... - - - Reboot - Yeniden başlat - - - Update failed - Güncelleme başarız oldu - - - - VisualsPanel - - Show Blind Spot Warnings - - - - Enabling this will display warnings when a vehicle is detected in your blind spot as long as your car has BSM supported. - - - - Changing this setting will restart openpilot if the car is powered on. - - - - Off - - - - Distance - - - - Speed - - - - Time - - - - All - - - - Display Metrics Below Chevron - - - - Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control). - - - WiFiPromptWidget @@ -2472,11 +1137,11 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device - <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span> + Maximize your training data uploads to improve openpilot's driving models. - Maximize your training data uploads to improve openpilot's driving models. + <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span> diff --git a/selfdrive/ui/translations/main_zh-CHS.ts b/selfdrive/ui/translations/main_zh-CHS.ts index 987d42a7f7..5e5b9da311 100644 --- a/selfdrive/ui/translations/main_zh-CHS.ts +++ b/selfdrive/ui/translations/main_zh-CHS.ts @@ -7,10 +7,6 @@ Close 关闭 - - Snooze Update - 暂停更新 - Reboot and Update 重启并更新 @@ -40,7 +36,7 @@ IP Address - IP地址 + IP 地址 Enable Roaming @@ -48,11 +44,11 @@ APN Setting - APN设置 + APN 设置 Enter APN - 输入APN + 输入 APN leave blank for automatic configuration @@ -84,74 +80,27 @@ Prevent large data uploads when on a metered cellular connection - + 在按流量计费的移动网络上,防止上传大数据 default - + 默认 metered - + 按流量计费 unmetered - + 不按流量计费 Wi-Fi Network Metered - + 按流量计费的 WLAN 网络 Prevent large data uploads when on a metered Wi-Fi connection - - - - - AutoLaneChangeTimer - - Auto Lane Change by Blinker - - - - Set a timer to delay the auto lane change operation when the blinker is used. No nudge on the steering wheel is required to auto lane change if a timer is set. Default is Nudge. -Please use caution when using this feature. Only use the blinker when traffic and road conditions permit. - - - - s - - - - Off - - - - Nudge - - - - Nudgeless - - - - - Brightness - - Brightness - - - - Overrides the brightness of the device. - - - - Auto (Dark) - - - - Auto - + 在按流量计费的 WLAN 网络上,防止上传大数据 @@ -168,8 +117,8 @@ Please use caution when using this feature. Only use the blinker when traffic an DeclinePage - You must accept the Terms and Conditions in order to use sunnypilot. - 您必须接受条款和条件以使用sunnypilot。 + You must accept the Terms and Conditions in order to use openpilot. + 您必须接受条款和条件以使用openpilot。 Back @@ -190,6 +139,18 @@ Please use caution when using this feature. Only use the blinker when traffic an Longitudinal Maneuver Mode 纵向操控测试模式 + + openpilot Longitudinal Control (Alpha) + openpilot纵向控制(Alpha 版) + + + WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). + 警告:此车辆的 openpilot 纵向控制功能目前处于Alpha版本,使用此功能将会停用自动紧急制动(AEB)功能。 + + + On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. + 在这辆车上,openpilot 默认使用车辆内建的主动巡航控制(ACC),而非 openpilot 的纵向控制。启用此项功能可切换至 openpilot 的纵向控制。当启用 openpilot 纵向控制 Alpha 版本时,建议同时启用实验性模式(Experimental mode)。 + Enable ADB 启用 ADB @@ -198,62 +159,6 @@ Please use caution when using this feature. Only use the blinker when traffic an ADB (Android Debug Bridge) allows connecting to your device over USB or over the network. See https://docs.comma.ai/how-to/connect-to-comma for more info. ADB(Android调试桥接)允许通过USB或网络连接到您的设备。更多信息请参见 [https://docs.comma.ai/how-to/connect-to-comma](https://docs.comma.ai/how-to/connect-to-comma)。 - - openpilot Longitudinal Control (Alpha) - - - - WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). - - - - On this car, sunnypilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. - - - - - DeveloperPanelSP - - Show Advanced Controls - - - - Toggle visibility of advanced sunnypilot controls. -This only toggles the visibility of the controls; it does not toggle the actual control enabled/disabled state. - - - - Enable GitHub runner service - - - - Enables or disables the github runner service. - - - - Enable Quickboot Mode - - - - Error Log - - - - VIEW - 查看 - - - View the error log for sunnypilot crashes. - - - - When toggled on, this creates a prebuilt file to allow accelerated boot times. When toggled off, it immediately removes the prebuilt file so compilation of locally edited cpp files can be made. <br><br><b>To edit C++ files locally on device, you MUST first turn off this toggle so the changes can recompile.</b> - - - - Quickboot mode requires updates to be disabled.<br>Enable 'Disable Updates' in the Software panel first. - - DevicePanel @@ -302,8 +207,8 @@ This only toggles the visibility of the controls; it does not toggle the actual 查看 - Review the rules, features, and limitations of sunnypilot - 查看 sunnypilot 的使用规则,以及其功能和限制 + Review the rules, features, and limitations of openpilot + 查看 openpilot 的使用规则,以及其功能和限制 Are you sure you want to review the training guide? @@ -363,7 +268,7 @@ This only toggles the visibility of the controls; it does not toggle the actual Disengage to Reboot - 取消sunnypilot以重新启动 + 取消openpilot以重新启动 Are you sure you want to power off? @@ -371,7 +276,7 @@ This only toggles the visibility of the controls; it does not toggle the actual Disengage to Power Off - 取消sunnypilot以关机 + 取消openpilot以关机 Reset @@ -395,174 +300,39 @@ This only toggles the visibility of the controls; it does not toggle the actual Disengage to Reset Calibration - + 解除以重置校准 - sunnypilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. - + openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. + openpilot 要求设备的安装角度:左右偏移需在 4° 以内,上下俯仰角度需在向上 5° 至向下 9° 的范围内。 + + + openpilot is continuously calibrating, resetting is rarely required. Resetting calibration will restart openpilot if the car is powered on. + openpilot 会持续进行校准,因此很少需要重置。如果车辆电源已开启,重置校准会重新启动 openpilot。 Steering lag calibration is %1% complete. - + + +转向延迟校准已完成 %1%。 Steering lag calibration is complete. - + + +转向延迟校准已完成。 Steering torque response calibration is %1% complete. - + 转向扭矩响应校准已完成 %1%。 Steering torque response calibration is complete. - - - - openpilot is continuously calibrating, resetting is rarely required. Resetting calibration will restart openpilot if the car is powered on. - - - - - DevicePanelSP - - Driver Camera Preview - - - - Training Guide - - - - Regulatory - 监管信息 - - - Language - - - - Are you sure you want to review the training guide? - 您确定要查看新手指南吗? - - - Review - 预览 - - - Select a language - 选择语言 - - - Reboot - 重启 - - - Power Off - 关机 - - - Offroad Mode - - - - Are you sure you want to exit Always Offroad mode? - - - - Confirm - 确认 - - - Are you sure you want to enter Always Offroad mode? - - - - Disengage to Enter Always Offroad Mode - - - - Exit Always Offroad - - - - Always Offroad - - - - Quiet Mode - - - - Reset Settings - - - - Are you sure you want to reset all sunnypilot settings to default? Once the settings are reset, there is no going back. - - - - Reset - 重置 - - - The reset cannot be undone. You have been warned. - - - - Wake-Up Behavior - - - - Interactivity Timeout - - - - Apply a custom timeout for settings UI. -This is the time after which settings UI closes automatically if user is not interacting with the screen. - - - - ⁍ Default: Device will boot/wake-up normally & will be ready to engage. - - - - ⁍ Offroad: Device will be in Always Offroad mode after boot/wake-up. - - - - Controls state of the device after boot/sleep. - - - - - DriveStats - - Drives - - - - Hours - - - - ALL TIME - - - - PAST WEEK - - - - KM - - - - Miles - + 转向扭矩响应校准已完成。 @@ -572,21 +342,6 @@ This is the time after which settings UI closes automatically if user is not int 正在启动相机 - - ExitOffroadButton - - Are you sure you want to exit Always Offroad mode? - - - - Confirm - 确认 - - - EXIT ALWAYS OFFROAD MODE - - - ExperimentalModeButton @@ -600,17 +355,25 @@ This is the time after which settings UI closes automatically if user is not int FirehosePanel + + openpilot learns to drive by watching humans, like you, drive. + +Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode. + openpilot 通过观察人类驾驶(包括您)来学习如何驾驶。 + +“Firehose 模式”允许您最大化上传训练数据,以改进 openpilot 的驾驶模型。更多数据意味着更强大的模型,也就意味着更优秀的“实验模式”。 + Firehose Mode: ACTIVE - 训练数据上传模式:激活中 + Firehose 模式:激活中 ACTIVE 激活中 - For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream sunnypilot (and particular forks) are able to be used for training. - 为了达到最佳效果,请每周将您的设备带回室内,并连接到优质的 USB-C 充电器和 Wi-Fi。<br><br>Firehose 模式在行驶时也能运行,但需连接到移动热点或使用不限流量的 SIM 卡。<br><br><br><b>常见问题</b><br><br><i>我开车的方式或地点有影响吗?</i>不会,请像平常一样驾驶即可。<br><br><i>Firehose 模式会上传所有的驾驶片段吗?</i>不会,我们会选择性地上传部分片段。<br><br><i>什么是好的 USB-C 充电器?</i>任何快速手机或笔记本电脑充电器都应该适用。<br><br><i>我使用的软件版本有影响吗?</i>有的,只有官方 sunnypilot(以及特定的分支)可以用于训练。 + For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training. + 为了达到最佳效果,请每周将您的设备带回室内,并连接到优质的 USB-C 充电器和 Wi-Fi。<br><br>Firehose 模式在行驶时也能运行,但需连接到移动热点或使用不限流量的 SIM 卡。<br><br><br><b>常见问题</b><br><br><i>我开车的方式或地点有影响吗?</i>不会,请像平常一样驾驶即可。<br><br><i>Firehose 模式会上传所有的驾驶片段吗?</i>不会,我们会选择性地上传部分片段。<br><br><i>什么是好的 USB-C 充电器?</i>任何快速手机或笔记本电脑充电器都应该适用。<br><br><i>我使用的软件版本有影响吗?</i>有的,只有官方 openpilot(以及特定的分支)可以用于训练。 <b>%n segment(s)</b> of your driving is in the training dataset so far. @@ -618,19 +381,13 @@ This is the time after which settings UI closes automatically if user is not int <b>目前已有 %n 段</b> 您的驾驶数据被纳入训练数据集。 - - sunnypilot learns to drive by watching humans, like you, drive. - -Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode. - - <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to an unmetered network <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>闲置</span>:请连接到不限流量的网络 Firehose Mode - + Firehose 模式 @@ -648,49 +405,6 @@ Firehose Mode allows you to maximize your training data uploads to improve openp 最高定速 - - HyundaiSettings - - Off - - - - Dynamic - - - - Predictive - - - - Custom Longitudinal Tuning - - - - This feature can only be used with openpilot longitudinal control enabled. - - - - Enable "Always Offroad" in Device panel, or turn vehicle off to select an option. - - - - Off: Uses default tuning - - - - Dynamic: Adjusts acceleration limits based on current speed - - - - Predictive: Uses future trajectory data to anticipate needed adjustments - - - - Fine-tune your driving experience by adjusting acceleration smoothness with openpilot longitudinal control. - - - InputDialog @@ -704,321 +418,6 @@ Firehose Mode allows you to maximize your training data uploads to improve openp - - LaneChangeSettings - - Back - 返回 - - - Auto Lane Change: Delay with Blind Spot - - - - Toggle to enable a delay timer for seamless lane changes when blind spot monitoring (BSM) detects a obstructing vehicle, ensuring safe maneuvering. - - - - - LateralPanel - - Modular Assistive Driving System (MADS) - - - - Enable the beloved MADS feature. Disable toggle to revert back to stock sunnypilot engagement/disengagement. - - - - Customize MADS - - - - Customize Lane Change - - - - Enables independent engagements of Automatic Lane Centering (ALC) and Adaptive Cruise Control (ACC). - - - - Start the vehicle to check vehicle compatibility. - - - - This platform supports all MADS settings. - - - - This platform supports limited MADS settings. - - - - Pause Lateral Control with Blinker - - - - Pause lateral control with blinker when traveling below the desired speed selected. - - - - - LongitudinalPanel - - Custom ACC Speed Increments - - - - Enable custom Short & Long press increments for cruise speed increase/decrease. - - - - This feature can only be used with openpilot longitudinal control enabled. - - - - This feature is not supported on this platform due to vehicle limitations. - - - - Start the vehicle to check vehicle compatibility. - - - - - MadsSettings - - Toggle with Main Cruise - - - - Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement. - - - - Unified Engagement Mode (UEM) - - - - Engage lateral and longitudinal control with cruise control engagement. - - - - Note: Once lateral control is engaged via UEM, it will remain engaged until it is manually disabled via the MADS button or car shut off. - - - - Remain Active - - - - Disengage - - - - Steering Mode on Brake Pedal - - - - Start the vehicle to check vehicle compatibility. - - - - This feature defaults to OFF, and does not allow selection due to vehicle limitations. - - - - This feature defaults to ON, and does not allow selection due to vehicle limitations. - - - - This platform only supports Disengage mode due to vehicle limitations. - - - - Remain Active: ALC will remain active when the brake pedal is pressed. - - - - Pause - - - - Pause: ALC will pause when the brake pedal is pressed. - - - - Disengage: ALC will disengage when the brake pedal is pressed. - - - - Choose how Automatic Lane Centering (ALC) behaves after the brake pedal is manually pressed in sunnypilot. - - - - - MaxTimeOffroad - - Max Time Offroad - - - - Device will automatically shutdown after set time once the engine is turned off.<br/>(30h is the default) - - - - Always On - - - - h - - - - m - - - - (default) - - - - - ModelsPanel - - Current Model - - - - SELECT - 选择 - - - downloaded - - - - ready - - - - from cache - - - - Fetching models... - - - - Select a Model - - - - Default - - - - Model download has started in the background. - - - - We STRONGLY suggest you to reset calibration. - - - - Would you like to do that now? - - - - Reset Calibration - 重置设备校准 - - - Driving Model Selector - - - - Warning: You are on a metered connection! - - - - Continue - 继续 - - - on Metered - - - - Cancel - 取消 - - - Clear Model Cache - - - - CLEAR - - - - Driving Model - - - - Navigation Model - - - - Vision Model - - - - Policy Model - - - - Live Learning Steer Delay - - - - Adjust Software Delay - - - - Adjust the software delay when Live Learning Steer Delay is toggled off. -The default software delay value is 0.2 - - - - %1 - %2 - - - - download failed - %1 - - - - pending - %1 - - - - Enable this for the car to learn and adapt its steering response time. Disable to use a fixed steering response time. Keeping this on provides the stock openpilot experience. The Current value is updated automatically when the vehicle is Onroad. - - - - Current: - - - - This will delete ALL downloaded models from the cache<br/><u>except the currently active model</u>.<br/><br/>Are you sure you want to continue? - - - - Clear Cache - - - MultiOptionDialog @@ -1049,85 +448,15 @@ The default software delay value is 0.2 密码错误 - - NetworkingSP - - Scan - - - - Scanning... - - - - - NeuralNetworkLateralControl - - Neural Network Lateral Control (NNLC) - - - - NNLC is currently not available on this platform. - - - - Start the car to check car compatibility - - - - NNLC Not Loaded - - - - NNLC Loaded - - - - Match - - - - Exact - - - - Fuzzy - - - - Match: "Exact" is ideal, but "Fuzzy" is fine too. - - - - Formerly known as <b>"NNFF"</b>, this replaces the lateral <b>"torque"</b> controller, with one using a neural network trained on each car's (actually, each separate EPS firmware) driving data for increased controls accuracy. - - - - Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server - - - - with feedback, or to provide log data for your car if your car is currently unsupported: - - - - if there are any issues: - - - - and donate logs to get NNLC loaded for your car: - - - OffroadAlert - Immediately connect to the internet to check for updates. If you do not connect to the internet, sunnypilot won't engage in %1 - 请立即连接网络检查更新。如果不连接网络,sunnypilot 将在 %1 后便无法使用 + Immediately connect to the internet to check for updates. If you do not connect to the internet, openpilot won't engage in %1 + 请立即连接网络检查更新。如果不连接网络,openpilot 将在 %1 后便无法使用 - Connect to internet to check for updates. sunnypilot won't automatically start until it connects to internet to check for updates. - 请连接至互联网以检查更新。在连接至互联网并完成更新检查之前,sunnypilot 将不会自动启动。 + Connect to internet to check for updates. openpilot won't automatically start until it connects to internet to check for updates. + 请连接至互联网以检查更新。在连接至互联网并完成更新检查之前,openpilot 将不会自动启动。 Unable to download updates @@ -1143,34 +472,36 @@ The default software delay value is 0.2 An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. 一个针对您设备的操作系统更新正在后台下载中。当更新准备好安装时,您将收到提示进行更新。 - - Device failed to register. It will not connect to or upload to comma.ai servers, and receives no support from comma.ai. If this is an official device, visit https://comma.ai/support. - 设备注册失败。它将无法连接或上传至 comma.ai 服务器,并且无法获得 comma.ai 的支持。如果这是一个官方设备,请访问 https://comma.ai/support。 - NVMe drive not mounted. NVMe固态硬盘未被挂载。 - Unsupported NVMe drive detected. Device may draw significantly more power and overheat due to the unsupported NVMe. - 检测到不支持的 NVMe 固态硬盘。您的设备因为使用了不支持的 NVMe 固态硬盘可能会消耗更多电力并更易过热。 + openpilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. + openpilot 无法识别您的车辆。您的车辆可能未被支持,或是其电控单元 (ECU) 未被识别。请提交一个 Pull Request 为您的车辆添加正确的固件版本。需要帮助吗?请加入 discord.comma.ai。 - sunnypilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. - sunnypilot 无法识别您的车辆。您的车辆可能未被支持,或是其电控单元 (ECU) 未被识别。请提交一个 Pull Request 为您的车辆添加正确的固件版本。需要帮助吗?请加入 discord.comma.ai。 - - - sunnypilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. - sunnypilot 检测到设备的安装位置发生变化。请确保设备完全安装在支架上,并确保支架牢固地固定在挡风玻璃上。 + openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. + openpilot 检测到设备的安装位置发生变化。请确保设备完全安装在支架上,并确保支架牢固地固定在挡风玻璃上。 Device temperature too high. System cooling down before starting. Current internal component temperature: %1 设备温度过高。系统正在冷却中,等冷却完毕后才会启动。目前内部组件温度:%1 - OpenStreetMap database is out of date. New maps must be downloaded if you wish to continue using OpenStreetMap data for Enhanced Speed Control and road name display. - -%1 + Device failed to register with the comma.ai backend. It will not connect or upload to comma.ai servers, and receives no support from comma.ai. If this is a device purchased at comma.ai/shop, open a ticket at https://comma.ai/support. + 设备未能注册到 comma.ai 后端。该设备将无法连接或上传数据到 comma.ai 服务器,也无法获得 comma.ai 的支持。如果该设备是在 comma.ai/shop 购买的,请访问 https://comma.ai/support 提交工单。 + + + Acknowledge Excessive Actuation + + + + Snooze Update + 暂停更新 + + + openpilot has detected excessive %1 actuation. This may be due to a software bug. Please contact support at https://comma.ai/support. @@ -1189,18 +520,11 @@ The default software delay value is 0.2 警报 - - OffroadHomeSP - - ALWAYS OFFROAD ACTIVE - - - OnroadAlerts - sunnypilot Unavailable - 无法使用 sunnypilot + openpilot Unavailable + 无法使用 openpilot TAKE CONTROL IMMEDIATELY @@ -1219,137 +543,6 @@ The default software delay value is 0.2 系统无响应 - - OsmPanel - - Mapd Version - - - - Offline Maps ETA - - - - Time Elapsed - - - - Downloaded Maps - - - - DELETE - - - - This will delete ALL downloaded maps - -Are you sure you want to delete all the maps? - - - - Yes, delete all the maps. - - - - Database Update - - - - CHECK - 查看 - - - Country - - - - SELECT - 选择 - - - Fetching Country list... - - - - State - - - - Fetching State list... - - - - All - - - - REFRESH - - - - UPDATE - 更新 - - - Download starting... - - - - Error: Invalid download. Retry. - - - - Download complete! - - - - - -Warning: You are on a metered connection! - - - - This will start the download process and it might take a while to complete. - - - - Continue on Metered - - - - Start Download - - - - m - - - - s - - - - Calculating... - - - - Downloaded - - - - Calculating ETA... - - - - Ready - - - - Time remaining: - - - PairingPopup @@ -1384,96 +577,6 @@ Warning: You are on a metered connection! 启用 - - ParamControlSP - - Enable - 启用 - - - Cancel - 取消 - - - - PlatformSelector - - Vehicle - - - - SEARCH - - - - Search your vehicle - - - - Enter model year (e.g., 2021) and model name (Toyota Corolla): - - - - SEARCHING - - - - REMOVE - 删除 - - - This setting will take effect immediately. - - - - This setting will take effect once the device enters offroad state. - - - - Vehicle Selector - - - - Confirm - 确认 - - - Cancel - 取消 - - - No vehicles found for query: %1 - - - - Select a vehicle - - - - Unrecognized Vehicle - - - - Fingerprinted automatically - - - - Manually selected - - - - Not fingerprinted or manually selected - - - - Select vehicle to force fingerprint manually. - - - - Colors represent fingerprint status: - - - PrimeAdWidget @@ -1519,8 +622,8 @@ Warning: You are on a metered connection! QObject - sunnypilot - sunnypilot + openpilot + openpilot %n minute(s) ago @@ -1545,47 +648,6 @@ Warning: You are on a metered connection! 现在 - - Reset - - Reset failed. Reboot to try again. - 重置失败。 重新启动以重试。 - - - Are you sure you want to reset your device? - 您确定要重置您的设备吗? - - - System Reset - 恢复出厂设置 - - - Cancel - 取消 - - - Reboot - 重启 - - - Confirm - 确认 - - - Unable to mount data partition. Partition may be corrupted. Press confirm to erase and reset your device. - 无法挂载数据分区。分区可能已经损坏。请确认是否要删除并重新设置。 - - - Resetting device... -This may take up to a minute. - 设备重置中… -这可能需要一分钟的时间。 - - - System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot. - 系统重置已触发。按下“确认”以清除所有内容和设置,按下“取消”以继续启动。 - - SettingsWindow @@ -1614,70 +676,7 @@ This may take up to a minute. Firehose - 训练上传 - - - - SettingsWindowSP - - × - × - - - Device - 设备 - - - Network - 网络 - - - sunnylink - - - - Toggles - 设定 - - - Software - 软件 - - - Trips - - - - Vehicle - - - - Developer - 开发人员 - - - Firehose - 训练上传 - - - Steering - - - - Models - - - - Cruise - - - - Visuals - - - - OSM - + Firehose @@ -1767,8 +766,8 @@ This may take up to a minute. 选择要安装的软件 - sunnypilot - sunnypilot + openpilot + openpilot Custom Software @@ -1776,13 +775,15 @@ This may take up to a minute. WARNING: Custom Software - + 警告:自定义软件 Use caution when installing third-party software. Third-party software has not been tested by comma, and may cause damage to your device and/or vehicle. If you'd like to proceed, use https://flash.comma.ai to restore your device to a factory state later. - + 请谨慎安装第三方软件。第三方软件未经 comma 测试,可能会损害您的设备和车辆。 + +如果您决定继续,后续可通过 https://flash.comma.ai 将设备恢复到出厂状态。 @@ -1875,33 +876,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 5G - - SidebarSP - - DISABLED - - - - OFFLINE - 离线 - - - REGIST... - - - - ONLINE - 在线 - - - ERROR - 连接出错 - - - SUNNYLINK - - - SoftwarePanel @@ -1977,49 +951,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 从未更新 - - SoftwarePanelSP - - Search Branch - - - - Enter search keywords, or leave blank to list all branches. - - - - No branches found for keywords: %1 - - - - Select a branch - 选择分支 - - - Disable Updates - - - - When enabled, software updates will be disabled. <b>This requires a reboot to take effect.</b> - - - - %1 updates requires a reboot.<br>Reboot now? - - - - Reboot - 重启 - - - When enabled, software updates will be disabled.<br><b>This requires a reboot to take effect.</b> - - - - Please enable always offroad mode or turn off vehicle to adjust these toggles - - - SshControl @@ -2066,168 +997,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 启用SSH - - SunnylinkPanel - - This is the master switch, it will allow you to cutoff any sunnylink requests should you want to do that. - - - - Enable sunnylink - - - - 🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀 - - - - 👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉. - - - - Device ID - - - - N/A - N/A - - - Sponsor Status - - - - SPONSOR - - - - Become a sponsor of sunnypilot to get early access to sunnylink features when they become available. - - - - Pair GitHub Account - - - - PAIR - 配对 - - - Pair your GitHub account to grant your device sponsor benefits, including API access on sunnylink. - - - - sunnylink Dongle ID not found. This may be due to weak internet connection or sunnylink registration issue. Please reboot and try again. - - - - Not Sponsor - - - - Paired - - - - Not Paired - - - - THANKS ♥ - - - - Backup Settings - - - - Are you sure you want to backup sunnypilot settings? - - - - Back Up - - - - Restore Settings - - - - Are you sure you want to restore the last backed up sunnypilot settings? - - - - Restore - - - - Backup in progress %1% - - - - Backup Failed - - - - Settings backup completed. - - - - Restore in progress %1% - - - - Restore Failed - - - - Unable to restore the settings, try again later. - - - - Settings restored. Confirm to restart the interface. - - - - - SunnylinkSponsorPopup - - Scan the QR code to login to your GitHub account - - - - Follow the prompts to complete the pairing process - - - - Re-enter the "sunnylink" panel to verify sponsorship status - - - - If sponsorship status was not updated, please contact a moderator on Discord at https://discord.gg/sunnypilot - - - - Scan the QR code to visit sunnyhaibin's GitHub Sponsors page - - - - Choose your sponsorship tier and confirm your support - - - - Join our community on Discord at https://discord.gg/sunnypilot and reach out to a moderator to confirm your sponsor status - - - - Pair your GitHub account - - - - Early Access: Become a sunnypilot Sponsor - - - TermsPage @@ -2239,16 +1008,20 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 同意 - Welcome to sunnypilot - 欢迎使用 sunnypilot + Welcome to openpilot + 欢迎使用 openpilot - You must accept the Terms and Conditions to use sunnypilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing. - 您必须接受《条款与条件》才能使用 sunnypilot。在继续之前,请先阅读最新条款:<span style='color: #465BEA;'>https://comma.ai/terms</span>。 + You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing. + 您必须接受《条款与条件》才能使用 openpilot。在继续之前,请先阅读最新条款:<span style='color: #465BEA;'>https://comma.ai/terms</span>。 TogglesPanel + + Enable openpilot + 启用openpilot + Enable Lane Departure Warnings 启用车道偏离警告 @@ -2278,20 +1051,20 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 踩油门时取消控制 - When enabled, pressing the accelerator pedal will disengage sunnypilot. - 启用后,踩下油门踏板将取消sunnypilot。 + When enabled, pressing the accelerator pedal will disengage openpilot. + 启用后,踩下油门踏板将取消openpilot。 Experimental Mode 测试模式 - sunnypilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: - sunnypilot 默认 <b>轻松模式</b>驾驶车辆。试验模式启用一些轻松模式之外的 <b>试验性功能</b>。试验性功能包括: + openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: + openpilot 默认 <b>轻松模式</b>驾驶车辆。试验模式启用一些轻松模式之外的 <b>试验性功能</b>。试验性功能包括: - Let the driving model control the gas and brakes. sunnypilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. - 允许驾驶模型控制加速和制动,sunnypilot将模仿人类驾驶车辆,包括在红灯和停车让行标识前停车。鉴于驾驶模型确定行驶车速,所设定的车速仅作为上限。此功能尚处于早期测试状态,有可能会出现操作错误。 + Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. + 允许驾驶模型控制加速和制动,openpilot将模仿人类驾驶车辆,包括在红灯和停车让行标识前停车。鉴于驾驶模型确定行驶车速,所设定的车速仅作为上限。此功能尚处于早期测试状态,有可能会出现操作错误。 New Driving Visualization @@ -2301,6 +1074,10 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. 由于此车辆使用自带的ACC纵向控制,当前无法使用试验模式。 + + openpilot longitudinal control may come in a future update. + openpilot纵向控制可能会在未来的更新中提供。 + Aggressive 积极 @@ -2318,20 +1095,20 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 驾驶风格 - An alpha version of sunnypilot longitudinal control can be tested, along with Experimental mode, on non-release branches. - 在正式(release)版本以外的分支上,可以测试 sunnypilot 纵向控制的 Alpha 版本以及实验模式。 + An alpha version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + 在正式(release)版本以外的分支上,可以测试 openpilot 纵向控制的 Alpha 版本以及实验模式。 - Enable the sunnypilot longitudinal control (alpha) toggle to allow Experimental mode. - 启用 sunnypilot 纵向控制(alpha)开关以允许实验模式。 + Enable the openpilot longitudinal control (alpha) toggle to allow Experimental mode. + 启用 openpilot 纵向控制(alpha)开关以允许实验模式。 End-to-End Longitudinal Control 端到端纵向控制 - Standard is recommended. In aggressive mode, sunnypilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode sunnypilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. - 推荐使用标准模式。在积极模式下,sunnypilot 会更靠近前方车辆,并在油门和刹车方面更加激进。在放松模式下,sunnypilot 会与前方车辆保持更远距离。在支持的车型上,你可以使用方向盘上的距离按钮来循环切换这些驾驶风格。 + Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. + 推荐使用标准模式。在积极模式下,openpilot 会更靠近前方车辆,并在油门和刹车方面更加激进。在放松模式下,openpilot 会与前方车辆保持更远距离。在支持的车型上,你可以使用方向盘上的距离按钮来循环切换这些驾驶风格。 The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. @@ -2342,129 +1119,24 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 驾驶员监控常开 - Enable driver monitoring even when sunnypilot is not engaged. - 即使在sunnypilot未激活时也启用驾驶员监控。 + Enable driver monitoring even when openpilot is not engaged. + 即使在openpilot未激活时也启用驾驶员监控。 - Enable Dynamic Experimental Control - - - - Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal. - - - - Enable sunnypilot - 启用sunnypilot - - - Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. - + Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. + openpilot 系统提供“自适应巡航”和“车道保持”驾驶辅助功能。使用此功能时,您需要时刻保持专注。 Changing this setting will restart openpilot if the car is powered on. - - - - openpilot longitudinal control may come in a future update. - + 如果车辆已通电,更改此设置将会重新启动 openpilot。 Record and Upload Microphone Audio - + 录制并上传麦克风音频 Record and store microphone audio while driving. The audio will be included in the dashcam video in comma connect. - - - - - TreeOptionDialog - - Select - 选择 - - - Cancel - 取消 - - - - Updater - - Update Required - 需要更新 - - - An operating system update is required. Connect your device to Wi-Fi for the fastest update experience. The download size is approximately 1GB. - 操作系统需要更新。请将您的设备连接到WiFi以获取更快的更新体验。下载大小约为1GB。 - - - Connect to Wi-Fi - 连接到WiFi - - - Install - 安装 - - - Back - 返回 - - - Loading... - 正在加载…… - - - Reboot - 重启 - - - Update failed - 更新失败 - - - - VisualsPanel - - Show Blind Spot Warnings - - - - Enabling this will display warnings when a vehicle is detected in your blind spot as long as your car has BSM supported. - - - - Changing this setting will restart openpilot if the car is powered on. - - - - Off - - - - Distance - - - - Speed - - - - Time - - - - All - - - - Display Metrics Below Chevron - - - - Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control). - + 在驾驶时录制并存储麦克风音频。该音频将会包含在 comma connect 的行车记录仪视频中。 @@ -2474,12 +1146,12 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 开启 - <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span> - <span style='font-family: "Noto Color Emoji";'>🔥</span> 训练数据上传模式 <span style='font-family: Noto Color Emoji;'>🔥</span> + Maximize your training data uploads to improve openpilot's driving models. + 最大化您的训练数据上传,以改善 openpilot 的驾驶模型。 - Maximize your training data uploads to improve openpilot's driving models. - + <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span> + <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose 模式 <span style='font-family: Noto Color Emoji;'>🔥</span> diff --git a/selfdrive/ui/translations/main_zh-CHT.ts b/selfdrive/ui/translations/main_zh-CHT.ts index c9692be62b..630dbf2a08 100644 --- a/selfdrive/ui/translations/main_zh-CHT.ts +++ b/selfdrive/ui/translations/main_zh-CHT.ts @@ -7,10 +7,6 @@ Close 關閉 - - Snooze Update - 暫停更新 - Reboot and Update 重啟並更新 @@ -60,7 +56,7 @@ Cellular Metered - 行動網路 + 計費的行動網路 Hidden Network @@ -84,74 +80,27 @@ Prevent large data uploads when on a metered cellular connection - + 在使用計費行動網路時,防止上傳大量數據 default - + 預設 metered - + 計費 unmetered - + 非計費 Wi-Fi Network Metered - + 計費 Wi-Fi 網路 Prevent large data uploads when on a metered Wi-Fi connection - - - - - AutoLaneChangeTimer - - Auto Lane Change by Blinker - - - - Set a timer to delay the auto lane change operation when the blinker is used. No nudge on the steering wheel is required to auto lane change if a timer is set. Default is Nudge. -Please use caution when using this feature. Only use the blinker when traffic and road conditions permit. - - - - s - - - - Off - - - - Nudge - - - - Nudgeless - - - - - Brightness - - Brightness - - - - Overrides the brightness of the device. - - - - Auto (Dark) - - - - Auto - + 在使用計費 Wi-Fi 網路時,防止上傳大量數據 @@ -168,8 +117,8 @@ Please use caution when using this feature. Only use the blinker when traffic an DeclinePage - You must accept the Terms and Conditions in order to use sunnypilot. - 您必須先接受條款和條件才能使用 sunnypilot。 + You must accept the Terms and Conditions in order to use openpilot. + 您必須先接受條款和條件才能使用 openpilot。 Back @@ -190,6 +139,18 @@ Please use caution when using this feature. Only use the blinker when traffic an Longitudinal Maneuver Mode 縱向操控測試模式 + + openpilot Longitudinal Control (Alpha) + openpilot 縱向控制 (Alpha 版) + + + WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). + 警告:此車輛的 openpilot 縱向控制功能目前處於 Alpha 版本,使用此功能將會停用自動緊急煞車(AEB)功能。 + + + On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. + 在這輛車上,openpilot 預設使用車輛內建的主動巡航控制(ACC),而非 openpilot 的縱向控制。啟用此項功能可切換至 openpilot 的縱向控制。當啟用 openpilot 縱向控制 Alpha 版本時,建議同時啟用實驗性模式(Experimental mode)。 + Enable ADB 啟用 ADB @@ -198,62 +159,6 @@ Please use caution when using this feature. Only use the blinker when traffic an ADB (Android Debug Bridge) allows connecting to your device over USB or over the network. See https://docs.comma.ai/how-to/connect-to-comma for more info. ADB(Android 調試橋接)允許通過 USB 或網絡連接到您的設備。更多信息請參見 [https://docs.comma.ai/how-to/connect-to-comma](https://docs.comma.ai/how-to/connect-to-comma)。 - - openpilot Longitudinal Control (Alpha) - - - - WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB). - - - - On this car, sunnypilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha. - - - - - DeveloperPanelSP - - Show Advanced Controls - - - - Toggle visibility of advanced sunnypilot controls. -This only toggles the visibility of the controls; it does not toggle the actual control enabled/disabled state. - - - - Enable GitHub runner service - - - - Enables or disables the github runner service. - - - - Enable Quickboot Mode - - - - Error Log - - - - VIEW - 觀看 - - - View the error log for sunnypilot crashes. - - - - When toggled on, this creates a prebuilt file to allow accelerated boot times. When toggled off, it immediately removes the prebuilt file so compilation of locally edited cpp files can be made. <br><br><b>To edit C++ files locally on device, you MUST first turn off this toggle so the changes can recompile.</b> - - - - Quickboot mode requires updates to be disabled.<br>Enable 'Disable Updates' in the Software panel first. - - DevicePanel @@ -302,8 +207,8 @@ This only toggles the visibility of the controls; it does not toggle the actual 觀看 - Review the rules, features, and limitations of sunnypilot - 觀看 sunnypilot 的使用規則、功能和限制 + Review the rules, features, and limitations of openpilot + 觀看 openpilot 的使用規則、功能和限制 Are you sure you want to review the training guide? @@ -395,174 +300,39 @@ This only toggles the visibility of the controls; it does not toggle the actual Disengage to Reset Calibration - + 解除以重設校準 - sunnypilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. - + openpilot requires the device to be mounted within 4° left or right and within 5° up or 9° down. + openpilot 要求裝置的安裝角度,左右偏移須在 4° 以內,上下角度則須介於仰角 5° 至俯角 9° 之間。 + + + openpilot is continuously calibrating, resetting is rarely required. Resetting calibration will restart openpilot if the car is powered on. + openpilot 會持續進行校準,因此很少需要重設。若車輛電源開啟,重設校準將會重新啟動 openpilot。 Steering lag calibration is %1% complete. - + + +轉向延遲校準已完成 %1%。 Steering lag calibration is complete. - + + +轉向延遲校準已完成。 Steering torque response calibration is %1% complete. - + 轉向扭矩反應校準已完成 %1%。 Steering torque response calibration is complete. - - - - openpilot is continuously calibrating, resetting is rarely required. Resetting calibration will restart openpilot if the car is powered on. - - - - - DevicePanelSP - - Driver Camera Preview - - - - Training Guide - - - - Regulatory - 法規/監管 - - - Language - - - - Are you sure you want to review the training guide? - 您確定要觀看使用教學嗎? - - - Review - 回顧 - - - Select a language - 選擇語言 - - - Reboot - 重新啟動 - - - Power Off - 關機 - - - Offroad Mode - - - - Are you sure you want to exit Always Offroad mode? - - - - Confirm - 確認 - - - Are you sure you want to enter Always Offroad mode? - - - - Disengage to Enter Always Offroad Mode - - - - Exit Always Offroad - - - - Always Offroad - - - - Quiet Mode - - - - Reset Settings - - - - Are you sure you want to reset all sunnypilot settings to default? Once the settings are reset, there is no going back. - - - - Reset - 重設 - - - The reset cannot be undone. You have been warned. - - - - Wake-Up Behavior - - - - Interactivity Timeout - - - - Apply a custom timeout for settings UI. -This is the time after which settings UI closes automatically if user is not interacting with the screen. - - - - ⁍ Default: Device will boot/wake-up normally & will be ready to engage. - - - - ⁍ Offroad: Device will be in Always Offroad mode after boot/wake-up. - - - - Controls state of the device after boot/sleep. - - - - - DriveStats - - Drives - - - - Hours - - - - ALL TIME - - - - PAST WEEK - - - - KM - - - - Miles - + 轉向扭矩反應校準已完成。 @@ -572,21 +342,6 @@ This is the time after which settings UI closes automatically if user is not int 開啟相機中 - - ExitOffroadButton - - Are you sure you want to exit Always Offroad mode? - - - - Confirm - 確認 - - - EXIT ALWAYS OFFROAD MODE - - - ExperimentalModeButton @@ -600,17 +355,25 @@ This is the time after which settings UI closes automatically if user is not int FirehosePanel + + openpilot learns to drive by watching humans, like you, drive. + +Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode. + openpilot 透過觀察人類駕駛(包括您)來學習如何駕駛。 + +「Firehose 模式」可讓您最大化上傳訓練數據,以改進 openpilot 的駕駛模型。更多數據代表更強大的模型,也就意味著更優秀的「實驗模式」。 + Firehose Mode: ACTIVE - 訓練資料上傳模式:啟用中 + Firehose 模式:啟用中 ACTIVE 啟用中 - For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream sunnypilot (and particular forks) are able to be used for training. - 為了達到最佳效果,請每週將您的裝置帶回室內,並連接至優質的 USB-C 充電器與 Wi-Fi。<br><br>訓練資料上傳模式在行駛時也能運作,但需連接至行動熱點或使用不限流量的 SIM 卡。<br><br><br><b>常見問題</b><br><br><i>我開車的方式或地點有影響嗎?</i> 不會,請像平常一樣駕駛即可。<br><br><i>訓練資料上傳模式會上傳所有的駕駛片段嗎?</i>不會,我們會選擇性地上傳部分片段。<br><br><i>什麼是好的 USB-C 充電器?</i>任何快速手機或筆電充電器都應該適用。<br><br><i>我使用的軟體版本有影響嗎?</i>有的,只有官方 sunnypilot(以及特定的分支)可以用於訓練。 + For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.<br><br>Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.<br><br><br><b>Frequently Asked Questions</b><br><br><i>Does it matter how or where I drive?</i> Nope, just drive as you normally would.<br><br><i>Do all of my segments get pulled in Firehose Mode?</i> No, we selectively pull a subset of your segments.<br><br><i>What's a good USB-C adapter?</i> Any fast phone or laptop charger should be fine.<br><br><i>Does it matter which software I run?</i> Yes, only upstream openpilot (and particular forks) are able to be used for training. + 為了達到最佳效果,請每週將您的裝置帶回室內,並連接至優質的 USB-C 充電器與 Wi-Fi。<br><br>訓練資料上傳模式在行駛時也能運作,但需連接至行動熱點或使用不限流量的 SIM 卡。<br><br><br><b>常見問題</b><br><br><i>我開車的方式或地點有影響嗎?</i> 不會,請像平常一樣駕駛即可。<br><br><i>Firehose 模式會上傳所有的駕駛片段嗎?</i>不會,我們會選擇性地上傳部分片段。<br><br><i>什麼是好的 USB-C 充電器?</i>任何快速手機或筆電充電器都應該適用。<br><br><i>我使用的軟體版本有影響嗎?</i>有的,只有官方 openpilot(以及特定的分支)可以用於訓練。 <b>%n segment(s)</b> of your driving is in the training dataset so far. @@ -618,19 +381,13 @@ This is the time after which settings UI closes automatically if user is not int <b>目前已有 %n 段</b> 您的駕駛數據被納入訓練資料集。 - - sunnypilot learns to drive by watching humans, like you, drive. - -Firehose Mode allows you to maximize your training data uploads to improve openpilot's driving models. More data means bigger models, which means better Experimental Mode. - - <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>INACTIVE</span>: connect to an unmetered network - <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>閒置中</span>:請連接到不按流量計費的網絡 + <span stylesheet='font-size: 60px; font-weight: bold; color: #e74c3c;'>閒置中</span>:請連接到不按流量計費的網絡 Firehose Mode - + Firehose 模式 @@ -648,49 +405,6 @@ Firehose Mode allows you to maximize your training data uploads to improve openp 最高 - - HyundaiSettings - - Off - - - - Dynamic - - - - Predictive - - - - Custom Longitudinal Tuning - - - - This feature can only be used with openpilot longitudinal control enabled. - - - - Enable "Always Offroad" in Device panel, or turn vehicle off to select an option. - - - - Off: Uses default tuning - - - - Dynamic: Adjusts acceleration limits based on current speed - - - - Predictive: Uses future trajectory data to anticipate needed adjustments - - - - Fine-tune your driving experience by adjusting acceleration smoothness with openpilot longitudinal control. - - - InputDialog @@ -704,321 +418,6 @@ Firehose Mode allows you to maximize your training data uploads to improve openp - - LaneChangeSettings - - Back - 回上頁 - - - Auto Lane Change: Delay with Blind Spot - - - - Toggle to enable a delay timer for seamless lane changes when blind spot monitoring (BSM) detects a obstructing vehicle, ensuring safe maneuvering. - - - - - LateralPanel - - Modular Assistive Driving System (MADS) - - - - Enable the beloved MADS feature. Disable toggle to revert back to stock sunnypilot engagement/disengagement. - - - - Customize MADS - - - - Customize Lane Change - - - - Enables independent engagements of Automatic Lane Centering (ALC) and Adaptive Cruise Control (ACC). - - - - Start the vehicle to check vehicle compatibility. - - - - This platform supports all MADS settings. - - - - This platform supports limited MADS settings. - - - - Pause Lateral Control with Blinker - - - - Pause lateral control with blinker when traveling below the desired speed selected. - - - - - LongitudinalPanel - - Custom ACC Speed Increments - - - - Enable custom Short & Long press increments for cruise speed increase/decrease. - - - - This feature can only be used with openpilot longitudinal control enabled. - - - - This feature is not supported on this platform due to vehicle limitations. - - - - Start the vehicle to check vehicle compatibility. - - - - - MadsSettings - - Toggle with Main Cruise - - - - Note: For vehicles without LFA/LKAS button, disabling this will prevent lateral control engagement. - - - - Unified Engagement Mode (UEM) - - - - Engage lateral and longitudinal control with cruise control engagement. - - - - Note: Once lateral control is engaged via UEM, it will remain engaged until it is manually disabled via the MADS button or car shut off. - - - - Remain Active - - - - Disengage - - - - Steering Mode on Brake Pedal - - - - Start the vehicle to check vehicle compatibility. - - - - This feature defaults to OFF, and does not allow selection due to vehicle limitations. - - - - This feature defaults to ON, and does not allow selection due to vehicle limitations. - - - - This platform only supports Disengage mode due to vehicle limitations. - - - - Remain Active: ALC will remain active when the brake pedal is pressed. - - - - Pause - - - - Pause: ALC will pause when the brake pedal is pressed. - - - - Disengage: ALC will disengage when the brake pedal is pressed. - - - - Choose how Automatic Lane Centering (ALC) behaves after the brake pedal is manually pressed in sunnypilot. - - - - - MaxTimeOffroad - - Max Time Offroad - - - - Device will automatically shutdown after set time once the engine is turned off.<br/>(30h is the default) - - - - Always On - - - - h - - - - m - - - - (default) - - - - - ModelsPanel - - Current Model - - - - SELECT - 選取 - - - downloaded - - - - ready - - - - from cache - - - - Fetching models... - - - - Select a Model - - - - Default - - - - Model download has started in the background. - - - - We STRONGLY suggest you to reset calibration. - - - - Would you like to do that now? - - - - Reset Calibration - 重設校準 - - - Driving Model Selector - - - - Warning: You are on a metered connection! - - - - Continue - 繼續 - - - on Metered - - - - Cancel - 取消 - - - Clear Model Cache - - - - CLEAR - - - - Driving Model - - - - Navigation Model - - - - Vision Model - - - - Policy Model - - - - Live Learning Steer Delay - - - - Adjust Software Delay - - - - Adjust the software delay when Live Learning Steer Delay is toggled off. -The default software delay value is 0.2 - - - - %1 - %2 - - - - download failed - %1 - - - - pending - %1 - - - - Enable this for the car to learn and adapt its steering response time. Disable to use a fixed steering response time. Keeping this on provides the stock openpilot experience. The Current value is updated automatically when the vehicle is Onroad. - - - - Current: - - - - This will delete ALL downloaded models from the cache<br/><u>except the currently active model</u>.<br/><br/>Are you sure you want to continue? - - - - Clear Cache - - - MultiOptionDialog @@ -1049,85 +448,15 @@ The default software delay value is 0.2 密碼錯誤 - - NetworkingSP - - Scan - - - - Scanning... - - - - - NeuralNetworkLateralControl - - Neural Network Lateral Control (NNLC) - - - - NNLC is currently not available on this platform. - - - - Start the car to check car compatibility - - - - NNLC Not Loaded - - - - NNLC Loaded - - - - Match - - - - Exact - - - - Fuzzy - - - - Match: "Exact" is ideal, but "Fuzzy" is fine too. - - - - Formerly known as <b>"NNFF"</b>, this replaces the lateral <b>"torque"</b> controller, with one using a neural network trained on each car's (actually, each separate EPS firmware) driving data for increased controls accuracy. - - - - Reach out to the sunnypilot team in the following channel at the sunnypilot Discord server - - - - with feedback, or to provide log data for your car if your car is currently unsupported: - - - - if there are any issues: - - - - and donate logs to get NNLC loaded for your car: - - - OffroadAlert - Immediately connect to the internet to check for updates. If you do not connect to the internet, sunnypilot won't engage in %1 - 請立即連接網路檢查更新。如果不連接網路,sunnypilot 將在 %1 後便無法使用 + Immediately connect to the internet to check for updates. If you do not connect to the internet, openpilot won't engage in %1 + 請立即連接網路檢查更新。如果不連接網路,openpilot 將在 %1 後便無法使用 - Connect to internet to check for updates. sunnypilot won't automatically start until it connects to internet to check for updates. - 請連接至網際網路以檢查更新。在連接至網際網路並完成更新檢查之前,sunnypilot 將不會自動啟動。 + Connect to internet to check for updates. openpilot won't automatically start until it connects to internet to check for updates. + 請連接至網際網路以檢查更新。在連接至網際網路並完成更新檢查之前,openpilot 將不會自動啟動。 Unable to download updates @@ -1143,34 +472,36 @@ The default software delay value is 0.2 An update to your device's operating system is downloading in the background. You will be prompted to update when it's ready to install. 一個有關操作系統的更新正在後台下載中。當更新準備好安裝時,您將收到提示進行更新。 - - Device failed to register. It will not connect to or upload to comma.ai servers, and receives no support from comma.ai. If this is an official device, visit https://comma.ai/support. - 裝置註冊失敗。它將無法連接或上傳至 comma.ai 伺服器,並且無法獲得 comma.ai 的支援。如果這是一個官方裝置,請訪問 https://comma.ai/support 。 - NVMe drive not mounted. NVMe 固態硬碟未被掛載。 - Unsupported NVMe drive detected. Device may draw significantly more power and overheat due to the unsupported NVMe. - 檢測到不支援的 NVMe 固態硬碟。您的裝置因為使用了不支援的 NVMe 固態硬碟可能會消耗更多電力並更易過熱。 + openpilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. + openpilot 無法識別您的車輛。您的車輛可能未被支援,或是其電控單元 (ECU) 未被識別。請提交一個 Pull Request 為您的車輛添加正確的韌體版本。需要幫助嗎?請加入 discord.comma.ai 。 - sunnypilot was unable to identify your car. Your car is either unsupported or its ECUs are not recognized. Please submit a pull request to add the firmware versions to the proper vehicle. Need help? Join discord.comma.ai. - sunnypilot 無法識別您的車輛。您的車輛可能未被支援,或是其電控單元 (ECU) 未被識別。請提交一個 Pull Request 為您的車輛添加正確的韌體版本。需要幫助嗎?請加入 discord.comma.ai 。 - - - sunnypilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. - sunnypilot 偵測到裝置的安裝位置發生變化。請確保裝置完全安裝在支架上,並確保支架牢固地固定在擋風玻璃上。 + openpilot detected a change in the device's mounting position. Ensure the device is fully seated in the mount and the mount is firmly secured to the windshield. + openpilot 偵測到裝置的安裝位置發生變化。請確保裝置完全安裝在支架上,並確保支架牢固地固定在擋風玻璃上。 Device temperature too high. System cooling down before starting. Current internal component temperature: %1 裝置溫度過高。系統正在冷卻中,等冷卻完畢後才會啟動。目前內部組件溫度:%1 - OpenStreetMap database is out of date. New maps must be downloaded if you wish to continue using OpenStreetMap data for Enhanced Speed Control and road name display. - -%1 + Device failed to register with the comma.ai backend. It will not connect or upload to comma.ai servers, and receives no support from comma.ai. If this is a device purchased at comma.ai/shop, open a ticket at https://comma.ai/support. + 裝置註冊 comma.ai 後端失敗。此裝置將無法連線或上傳資料至 comma.ai 伺服器,也無法獲得 comma.ai 的支援。若此裝置購自 comma.ai/shop,請至 https://comma.ai/support 建立支援請求。 + + + Acknowledge Excessive Actuation + + + + Snooze Update + 暫停更新 + + + openpilot has detected excessive %1 actuation. This may be due to a software bug. Please contact support at https://comma.ai/support. @@ -1189,18 +520,11 @@ The default software delay value is 0.2 提醒 - - OffroadHomeSP - - ALWAYS OFFROAD ACTIVE - - - OnroadAlerts - sunnypilot Unavailable - 無法使用 sunnypilot + openpilot Unavailable + 無法使用 openpilot TAKE CONTROL IMMEDIATELY @@ -1219,137 +543,6 @@ The default software delay value is 0.2 系統無回應 - - OsmPanel - - Mapd Version - - - - Offline Maps ETA - - - - Time Elapsed - - - - Downloaded Maps - - - - DELETE - - - - This will delete ALL downloaded maps - -Are you sure you want to delete all the maps? - - - - Yes, delete all the maps. - - - - Database Update - - - - CHECK - 檢查 - - - Country - - - - SELECT - 選取 - - - Fetching Country list... - - - - State - - - - Fetching State list... - - - - All - - - - REFRESH - - - - UPDATE - 更新 - - - Download starting... - - - - Error: Invalid download. Retry. - - - - Download complete! - - - - - -Warning: You are on a metered connection! - - - - This will start the download process and it might take a while to complete. - - - - Continue on Metered - - - - Start Download - - - - m - - - - s - - - - Calculating... - - - - Downloaded - - - - Calculating ETA... - - - - Ready - - - - Time remaining: - - - PairingPopup @@ -1384,96 +577,6 @@ Warning: You are on a metered connection! 啟用 - - ParamControlSP - - Enable - 啟用 - - - Cancel - 取消 - - - - PlatformSelector - - Vehicle - - - - SEARCH - - - - Search your vehicle - - - - Enter model year (e.g., 2021) and model name (Toyota Corolla): - - - - SEARCHING - - - - REMOVE - 移除 - - - This setting will take effect immediately. - - - - This setting will take effect once the device enters offroad state. - - - - Vehicle Selector - - - - Confirm - 確認 - - - Cancel - 取消 - - - No vehicles found for query: %1 - - - - Select a vehicle - - - - Unrecognized Vehicle - - - - Fingerprinted automatically - - - - Manually selected - - - - Not fingerprinted or manually selected - - - - Select vehicle to force fingerprint manually. - - - - Colors represent fingerprint status: - - - PrimeAdWidget @@ -1519,8 +622,8 @@ Warning: You are on a metered connection! QObject - sunnypilot - sunnypilot + openpilot + openpilot %n minute(s) ago @@ -1545,47 +648,6 @@ Warning: You are on a metered connection! 現在 - - Reset - - Reset failed. Reboot to try again. - 重設失敗。請重新啟動後再試。 - - - Are you sure you want to reset your device? - 您確定要重設你的裝置嗎? - - - System Reset - 系統重設 - - - Cancel - 取消 - - - Reboot - 重新啟動 - - - Confirm - 確認 - - - Unable to mount data partition. Partition may be corrupted. Press confirm to erase and reset your device. - 無法掛載資料分割區。分割區可能已經毀損。請確認是否要刪除並重置。 - - - Resetting device... -This may take up to a minute. - 重置中… -這可能需要一分鐘的時間。 - - - System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot. - 系統重設已啟動。按下「確認」以清除所有內容和設定,或按下「取消」以繼續開機。 - - SettingsWindow @@ -1614,70 +676,7 @@ This may take up to a minute. Firehose - 訓練上傳 - - - - SettingsWindowSP - - × - × - - - Device - 裝置 - - - Network - 網路 - - - sunnylink - - - - Toggles - 設定 - - - Software - 軟體 - - - Trips - - - - Vehicle - - - - Developer - 開發人員 - - - Firehose - 訓練上傳 - - - Steering - - - - Models - - - - Cruise - - - - Visuals - - - - OSM - + Firehose @@ -1767,8 +766,8 @@ This may take up to a minute. 選擇要安裝的軟體 - sunnypilot - sunnypilot + openpilot + openpilot Custom Software @@ -1776,13 +775,15 @@ This may take up to a minute. WARNING: Custom Software - + 警告:自訂軟體 Use caution when installing third-party software. Third-party software has not been tested by comma, and may cause damage to your device and/or vehicle. If you'd like to proceed, use https://flash.comma.ai to restore your device to a factory state later. - + 請謹慎安裝第三方軟體。第三方軟體未經 comma 測試,可能會損壞您的裝置及車輛。 + +若您仍要繼續,日後可使用 https://flash.comma.ai 將您的裝置恢復至出廠狀態。 @@ -1875,33 +876,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 5G - - SidebarSP - - DISABLED - - - - OFFLINE - 已離線 - - - REGIST... - - - - ONLINE - 已連線 - - - ERROR - 錯誤 - - - SUNNYLINK - - - SoftwarePanel @@ -1977,49 +951,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 從未更新 - - SoftwarePanelSP - - Search Branch - - - - Enter search keywords, or leave blank to list all branches. - - - - No branches found for keywords: %1 - - - - Select a branch - 選取一個分支 - - - Disable Updates - - - - When enabled, software updates will be disabled. <b>This requires a reboot to take effect.</b> - - - - %1 updates requires a reboot.<br>Reboot now? - - - - Reboot - 重新啟動 - - - When enabled, software updates will be disabled.<br><b>This requires a reboot to take effect.</b> - - - - Please enable always offroad mode or turn off vehicle to adjust these toggles - - - SshControl @@ -2066,168 +997,6 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 啟用 SSH 服務 - - SunnylinkPanel - - This is the master switch, it will allow you to cutoff any sunnylink requests should you want to do that. - - - - Enable sunnylink - - - - 🎉Welcome back! We're excited to see you've enabled sunnylink again! 🚀 - - - - 👋Not going to lie, it's sad to see you disabled sunnylink 😢, but we'll be here when you're ready to come back 🎉. - - - - Device ID - - - - N/A - 無法使用 - - - Sponsor Status - - - - SPONSOR - - - - Become a sponsor of sunnypilot to get early access to sunnylink features when they become available. - - - - Pair GitHub Account - - - - PAIR - 配對 - - - Pair your GitHub account to grant your device sponsor benefits, including API access on sunnylink. - - - - sunnylink Dongle ID not found. This may be due to weak internet connection or sunnylink registration issue. Please reboot and try again. - - - - Not Sponsor - - - - Paired - - - - Not Paired - - - - THANKS ♥ - - - - Backup Settings - - - - Are you sure you want to backup sunnypilot settings? - - - - Back Up - - - - Restore Settings - - - - Are you sure you want to restore the last backed up sunnypilot settings? - - - - Restore - - - - Backup in progress %1% - - - - Backup Failed - - - - Settings backup completed. - - - - Restore in progress %1% - - - - Restore Failed - - - - Unable to restore the settings, try again later. - - - - Settings restored. Confirm to restart the interface. - - - - - SunnylinkSponsorPopup - - Scan the QR code to login to your GitHub account - - - - Follow the prompts to complete the pairing process - - - - Re-enter the "sunnylink" panel to verify sponsorship status - - - - If sponsorship status was not updated, please contact a moderator on Discord at https://discord.gg/sunnypilot - - - - Scan the QR code to visit sunnyhaibin's GitHub Sponsors page - - - - Choose your sponsorship tier and confirm your support - - - - Join our community on Discord at https://discord.gg/sunnypilot and reach out to a moderator to confirm your sponsor status - - - - Pair your GitHub account - - - - Early Access: Become a sunnypilot Sponsor - - - TermsPage @@ -2239,16 +1008,20 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 接受 - Welcome to sunnypilot - 歡迎使用 sunnypilot + Welcome to openpilot + 歡迎使用 openpilot - You must accept the Terms and Conditions to use sunnypilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing. - 您必須接受《條款與條件》才能使用 sunnypilot。在繼續之前,請先閱讀最新條款:<span style='color: #465BEA;'>https://comma.ai/terms</span>。 + You must accept the Terms and Conditions to use openpilot. Read the latest terms at <span style='color: #465BEA;'>https://comma.ai/terms</span> before continuing. + 您必須接受《條款與條件》才能使用 openpilot。在繼續之前,請先閱讀最新條款:<span style='color: #465BEA;'>https://comma.ai/terms</span>。 TogglesPanel + + Enable openpilot + 啟用 openpilot + Enable Lane Departure Warnings 啟用車道偏離警告 @@ -2278,20 +1051,20 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 油門取消控車 - When enabled, pressing the accelerator pedal will disengage sunnypilot. - 啟用後,踩踏油門將會取消 sunnypilot 控制。 + When enabled, pressing the accelerator pedal will disengage openpilot. + 啟用後,踩踏油門將會取消 openpilot 控制。 Experimental Mode 實驗模式 - sunnypilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: - sunnypilot 預設以 <b>輕鬆模式</b> 駕駛。 實驗模式啟用了尚未準備好進入輕鬆模式的 <b>alpha 級功能</b>。實驗功能如下: + openpilot defaults to driving in <b>chill mode</b>. Experimental mode enables <b>alpha-level features</b> that aren't ready for chill mode. Experimental features are listed below: + openpilot 預設以 <b>輕鬆模式</b> 駕駛。 實驗模式啟用了尚未準備好進入輕鬆模式的 <b>alpha 級功能</b>。實驗功能如下: - Let the driving model control the gas and brakes. sunnypilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. - 讓駕駛模型來控制油門及煞車。sunnypilot將會模擬人類的駕駛行為,包含在看見紅燈及停止標示時停車。由於車速將由駕駛模型決定,因此您設定的時速將成為速度上限。本功能仍在早期實驗階段,請預期模型有犯錯的可能性。 + Let the driving model control the gas and brakes. openpilot will drive as it thinks a human would, including stopping for red lights and stop signs. Since the driving model decides the speed to drive, the set speed will only act as an upper bound. This is an alpha quality feature; mistakes should be expected. + 讓駕駛模型來控制油門及煞車。openpilot將會模擬人類的駕駛行為,包含在看見紅燈及停止標示時停車。由於車速將由駕駛模型決定,因此您設定的時速將成為速度上限。本功能仍在早期實驗階段,請預期模型有犯錯的可能性。 New Driving Visualization @@ -2301,6 +1074,10 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control. 因車輛使用內建ACC系統,無法在本車輛上啟動實驗模式。 + + openpilot longitudinal control may come in a future update. + openpilot 縱向控制可能會在未來的更新中提供。 + Aggressive 積極 @@ -2318,20 +1095,20 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 駕駛風格 - An alpha version of sunnypilot longitudinal control can be tested, along with Experimental mode, on non-release branches. - 在正式 (release) 版以外的分支上可以測試 sunnypilot 縱向控制的 Alpha 版本以及實驗模式。 + An alpha version of openpilot longitudinal control can be tested, along with Experimental mode, on non-release branches. + 在正式 (release) 版以外的分支上可以測試 openpilot 縱向控制的 Alpha 版本以及實驗模式。 - Enable the sunnypilot longitudinal control (alpha) toggle to allow Experimental mode. - 啟用 sunnypilot 縱向控制(alpha)切換以允許實驗模式。 + Enable the openpilot longitudinal control (alpha) toggle to allow Experimental mode. + 啟用 openpilot 縱向控制(alpha)切換以允許實驗模式。 End-to-End Longitudinal Control 端到端縱向控制 - Standard is recommended. In aggressive mode, sunnypilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode sunnypilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. - 建議使用標準模式。在積極模式下,sunnypilot 會更接近前車並更積極地使用油門和剎車。在輕鬆模式下,sunnypilot 會與前車保持較遠距離。對於支援的汽車,您可以使用方向盤上的距離按鈕來切換這些駕駛風格。 + Standard is recommended. In aggressive mode, openpilot will follow lead cars closer and be more aggressive with the gas and brake. In relaxed mode openpilot will stay further away from lead cars. On supported cars, you can cycle through these personalities with your steering wheel distance button. + 建議使用標準模式。在積極模式下,openpilot 會更接近前車並更積極地使用油門和剎車。在輕鬆模式下,openpilot 會與前車保持較遠距離。對於支援的汽車,您可以使用方向盤上的距離按鈕來切換這些駕駛風格。 The driving visualization will transition to the road-facing wide-angle camera at low speeds to better show some turns. The Experimental mode logo will also be shown in the top right corner. @@ -2342,129 +1119,24 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 駕駛監控常開 - Enable driver monitoring even when sunnypilot is not engaged. - 即使在sunnypilot未激活時也啟用駕駛監控。 + Enable driver monitoring even when openpilot is not engaged. + 即使在openpilot未激活時也啟用駕駛監控。 - Enable Dynamic Experimental Control - - - - Enable toggle to allow the model to determine when to use sunnypilot ACC or sunnypilot End to End Longitudinal. - - - - Enable sunnypilot - 啟用 sunnypilot - - - Use the sunnypilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. - + Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. + openpilot 系統提供「主動式巡航」與「車道維持」等駕駛輔助功能。使用這些功能時,您必須隨時保持專注。 Changing this setting will restart openpilot if the car is powered on. - - - - openpilot longitudinal control may come in a future update. - + 若車輛電源為開啟狀態,變更此設定將會重新啟動 openpilot。 Record and Upload Microphone Audio - + 錄製並上傳麥克風音訊 Record and store microphone audio while driving. The audio will be included in the dashcam video in comma connect. - - - - - TreeOptionDialog - - Select - 選擇 - - - Cancel - 取消 - - - - Updater - - Update Required - 系統更新 - - - An operating system update is required. Connect your device to Wi-Fi for the fastest update experience. The download size is approximately 1GB. - 需要進行作業系統更新。建議將您的裝置連接上 Wi-Fi 獲得更快的更新下載。下載大小約為 1GB。 - - - Connect to Wi-Fi - 連接到無線網路 - - - Install - 安裝 - - - Back - 回上頁 - - - Loading... - 載入中… - - - Reboot - 重新啟動 - - - Update failed - 更新失敗 - - - - VisualsPanel - - Show Blind Spot Warnings - - - - Enabling this will display warnings when a vehicle is detected in your blind spot as long as your car has BSM supported. - - - - Changing this setting will restart openpilot if the car is powered on. - - - - Off - - - - Distance - - - - Speed - - - - Time - - - - All - - - - Display Metrics Below Chevron - - - - Display useful metrics below the chevron that tracks the lead car (only applicable to cars with openpilot longitudinal control). - + 在駕駛時錄製並儲存麥克風音訊。此音訊將會收錄在 comma connect 的行車記錄器影片中。 @@ -2474,12 +1146,12 @@ If you'd like to proceed, use https://flash.comma.ai to restore your device 開啟 - <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span> - <span style='font-family: "Noto Color Emoji";'>🔥</span> 訓練資料上傳模式 <span style='font-family: Noto Color Emoji;'>🔥</span> + Maximize your training data uploads to improve openpilot's driving models. + 最大化您的訓練數據上傳,以改善 openpilot 的駕駛模型。 - Maximize your training data uploads to improve openpilot's driving models. - + <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose Mode <span style='font-family: Noto Color Emoji;'>🔥</span> + <span style='font-family: "Noto Color Emoji";'>🔥</span> Firehose 模式 <span style='font-family: Noto Color Emoji;'>🔥</span> diff --git a/selfdrive/ui/widgets/exp_mode_button.py b/selfdrive/ui/widgets/exp_mode_button.py index 83caf413d1..be50c59d06 100644 --- a/selfdrive/ui/widgets/exp_mode_button.py +++ b/selfdrive/ui/widgets/exp_mode_button.py @@ -1,7 +1,7 @@ import pyray as rl from openpilot.common.params import Params from openpilot.system.ui.lib.application import gui_app, FontWeight -from openpilot.system.ui.lib.widget import Widget +from openpilot.system.ui.widgets import Widget class ExperimentalModeButton(Widget): diff --git a/selfdrive/ui/widgets/offroad_alerts.py b/selfdrive/ui/widgets/offroad_alerts.py index aba07139db..f54bd9116c 100644 --- a/selfdrive/ui/widgets/offroad_alerts.py +++ b/selfdrive/ui/widgets/offroad_alerts.py @@ -5,11 +5,11 @@ from collections.abc import Callable from dataclasses import dataclass from openpilot.common.params import Params from openpilot.system.hardware import HARDWARE -from openpilot.system.ui.lib.scroll_panel import GuiScrollPanel -from openpilot.system.ui.lib.wrap_text import wrap_text -from openpilot.system.ui.lib.text_measure import measure_text_cached from openpilot.system.ui.lib.application import gui_app, FontWeight -from openpilot.system.ui.lib.widget import Widget +from openpilot.system.ui.lib.scroll_panel import GuiScrollPanel +from openpilot.system.ui.lib.text_measure import measure_text_cached +from openpilot.system.ui.lib.wrap_text import wrap_text +from openpilot.system.ui.widgets import Widget class AlertColors: @@ -190,14 +190,10 @@ class OffroadAlert(AbstractAlert): for alert_data in self.sorted_alerts: text = "" - bytes_data = self.params.get(alert_data.key) + alert_json = self.params.get(alert_data.key) - if bytes_data: - try: - alert_json = json.loads(bytes_data) - text = alert_json.get("text", "").replace("{}", alert_json.get("extra", "")) - except json.JSONDecodeError: - text = "" + if alert_json: + text = alert_json.get("text", "").replace("{}", alert_json.get("extra", "")) alert_data.text = text alert_data.visible = bool(text) @@ -296,7 +292,7 @@ class UpdateAlert(AbstractAlert): def refresh(self) -> bool: update_available: bool = self.params.get_bool("UpdateAvailable") if update_available: - self.release_notes = self.params.get("UpdaterNewReleaseNotes", encoding='utf-8') + self.release_notes = self.params.get("UpdaterNewReleaseNotes") self._cached_content_height = 0 return update_available diff --git a/selfdrive/ui/widgets/pairing_dialog.py b/selfdrive/ui/widgets/pairing_dialog.py index 2cb1499499..63298914ea 100644 --- a/selfdrive/ui/widgets/pairing_dialog.py +++ b/selfdrive/ui/widgets/pairing_dialog.py @@ -23,7 +23,7 @@ class PairingDialog: def _get_pairing_url(self) -> str: try: - dongle_id = self.params.get("DongleId", encoding='utf8') or "" + dongle_id = self.params.get("DongleId") or "" token = Api(dongle_id).get_token() except Exception as e: cloudlog.warning(f"Failed to get pairing token: {e}") @@ -55,7 +55,7 @@ class PairingDialog: self.qr_texture = None def _check_qr_refresh(self) -> None: - current_time = time.time() + current_time = time.monotonic() if current_time - self.last_qr_generation >= self.QR_REFRESH_INTERVAL: self._generate_qr_code() self.last_qr_generation = current_time diff --git a/selfdrive/ui/widgets/prime.py b/selfdrive/ui/widgets/prime.py index afdfa33e7a..86234ee149 100644 --- a/selfdrive/ui/widgets/prime.py +++ b/selfdrive/ui/widgets/prime.py @@ -2,10 +2,10 @@ import pyray as rl from openpilot.selfdrive.ui.ui_state import ui_state from openpilot.system.ui.lib.application import gui_app, FontWeight -from openpilot.system.ui.lib.label import gui_label -from openpilot.system.ui.lib.wrap_text import wrap_text from openpilot.system.ui.lib.text_measure import measure_text_cached -from openpilot.system.ui.lib.widget import Widget +from openpilot.system.ui.lib.wrap_text import wrap_text +from openpilot.system.ui.widgets import Widget +from openpilot.system.ui.widgets.label import gui_label class PrimeWidget(Widget): diff --git a/selfdrive/ui/widgets/setup.py b/selfdrive/ui/widgets/setup.py index 4fd56aa522..35a7c4101c 100644 --- a/selfdrive/ui/widgets/setup.py +++ b/selfdrive/ui/widgets/setup.py @@ -1,11 +1,11 @@ import pyray as rl from openpilot.selfdrive.ui.lib.prime_state import PrimeType -from openpilot.selfdrive.ui.widgets.pairing_dialog import PairingDialog from openpilot.selfdrive.ui.ui_state import ui_state +from openpilot.selfdrive.ui.widgets.pairing_dialog import PairingDialog from openpilot.system.ui.lib.application import gui_app, FontWeight -from openpilot.system.ui.lib.button import gui_button, ButtonStyle from openpilot.system.ui.lib.wrap_text import wrap_text -from openpilot.system.ui.lib.widget import Widget +from openpilot.system.ui.widgets import Widget +from openpilot.system.ui.widgets.button import gui_button, ButtonStyle class SetupWidget(Widget): diff --git a/selfdrive/ui/widgets/ssh_key.py b/selfdrive/ui/widgets/ssh_key.py index 418867c86f..4f4a8dcdff 100644 --- a/selfdrive/ui/widgets/ssh_key.py +++ b/selfdrive/ui/widgets/ssh_key.py @@ -6,8 +6,12 @@ from enum import Enum from openpilot.common.params import Params from openpilot.system.ui.lib.application import gui_app, FontWeight -from openpilot.system.ui.lib.button import gui_button, ButtonStyle -from openpilot.system.ui.lib.list_view import ( +from openpilot.system.ui.lib.text_measure import measure_text_cached +from openpilot.system.ui.widgets import DialogResult +from openpilot.system.ui.widgets.button import gui_button, ButtonStyle +from openpilot.system.ui.widgets.confirm_dialog import alert_dialog +from openpilot.system.ui.widgets.keyboard import Keyboard +from openpilot.system.ui.widgets.list_view import ( ItemAction, ListItem, BUTTON_HEIGHT, @@ -15,10 +19,6 @@ from openpilot.system.ui.lib.list_view import ( BUTTON_FONT_SIZE, BUTTON_WIDTH, ) -from openpilot.system.ui.lib.text_measure import measure_text_cached -from openpilot.system.ui.lib.widget import DialogResult -from openpilot.system.ui.widgets.confirm_dialog import alert_dialog -from openpilot.system.ui.widgets.keyboard import Keyboard class SshKeyActionState(Enum): @@ -42,7 +42,7 @@ class SshKeyAction(ItemAction): self._refresh_state() def _refresh_state(self): - self._username = self._params.get("GithubUsername", "") + self._username = self._params.get("GithubUsername") self._state = SshKeyActionState.REMOVE if self._params.get("GithubSshKeys") else SshKeyActionState.ADD def _render(self, rect: rl.Rectangle) -> bool: diff --git a/sunnypilot/livedelay/lagd_toggle.py b/sunnypilot/livedelay/lagd_toggle.py index cc2f1e2504..ee135fb877 100644 --- a/sunnypilot/livedelay/lagd_toggle.py +++ b/sunnypilot/livedelay/lagd_toggle.py @@ -16,7 +16,7 @@ class LagdToggle: @property def software_delay(self): - return float(self.params.get("LagdToggledelay", encoding='utf8')) + return self.params.get("LagdToggleDelay") def _maybe_update_desc(self, desc): if desc != self._last_desc: diff --git a/sunnypilot/mads/helpers.py b/sunnypilot/mads/helpers.py index 4b1095c63e..70b590a8b2 100644 --- a/sunnypilot/mads/helpers.py +++ b/sunnypilot/mads/helpers.py @@ -25,10 +25,7 @@ def read_steering_mode_param(CP: structs.CarParams, params: Params): if get_mads_limited_brands(CP): return MadsSteeringModeOnBrake.DISENGAGE - try: - return int(params.get("MadsSteeringMode")) - except (ValueError, TypeError): - return MadsSteeringModeOnBrake.REMAIN_ACTIVE + return params.get("MadsSteeringMode", return_default=True) def set_alternative_experience(CP: structs.CarParams, params: Params): @@ -59,6 +56,6 @@ def set_car_specific_params(CP: structs.CarParams, CP_SP: structs.CarParamsSP, p # TODO-SP: To enable MADS full support for Rivian/Tesla, identify consistent signals for MADS toggling mads_partial_support = get_mads_limited_brands(CP) if mads_partial_support: - params.put("MadsSteeringMode", "2") + params.put("MadsSteeringMode", 2) params.put_bool("MadsUnifiedEngagementMode", True) params.remove("MadsMainCruiseAllowed") diff --git a/sunnypilot/mapd/live_map_data/osm_map_data.py b/sunnypilot/mapd/live_map_data/osm_map_data.py index 5f74a5d011..84b3aa9955 100644 --- a/sunnypilot/mapd/live_map_data/osm_map_data.py +++ b/sunnypilot/mapd/live_map_data/osm_map_data.py @@ -31,13 +31,13 @@ class OsmMapData(BaseMapData): self.mem_params.put("LastGPSPosition", json.dumps(params)) def get_current_speed_limit(self) -> float: - return float(self.mem_params.get("MapSpeedLimit", encoding='utf8') or 0.0) + return float(self.mem_params.get("MapSpeedLimit") or 0.0) def get_current_road_name(self) -> str: - return self.mem_params.get("RoadName", encoding='utf8') or "" + return str(self.mem_params.get("RoadName")) def get_next_speed_limit_and_distance(self) -> tuple[float, float]: - next_speed_limit_section_str = self.mem_params.get("NextMapSpeedLimit", encoding='utf8') + next_speed_limit_section_str = self.mem_params.get("NextMapSpeedLimit") next_speed_limit_section = json.loads(next_speed_limit_section_str) if next_speed_limit_section_str else {} next_speed_limit = next_speed_limit_section.get('speedlimit', 0.0) next_speed_limit_latitude = next_speed_limit_section.get('latitude') diff --git a/sunnypilot/mapd/mapd_installer.py b/sunnypilot/mapd/mapd_installer.py index c337b50c5f..4cfb5ebbbf 100755 --- a/sunnypilot/mapd/mapd_installer.py +++ b/sunnypilot/mapd/mapd_installer.py @@ -90,7 +90,7 @@ class MapdInstallManager: logging.error("Failed to download file after all retries") def get_installed_version(self) -> str: - return self._params.get("MapdVersion", encoding="utf-8") or "" + return str(self._params.get("MapdVersion")) def wait_for_internet_connection(self, return_on_failure: bool = False) -> bool: max_retries = 10 diff --git a/sunnypilot/mapd/mapd_manager.py b/sunnypilot/mapd/mapd_manager.py index 0cb0df23f0..4e61ffe837 100755 --- a/sunnypilot/mapd/mapd_manager.py +++ b/sunnypilot/mapd/mapd_manager.py @@ -56,7 +56,7 @@ def cleanup_old_osm_data(files_to_remove: list[str]) -> None: def request_refresh_osm_location_data(nations: list[str], states: list[str] = None) -> None: - params.put("OsmDownloadedDate", str(time.time())) + params.put("OsmDownloadedDate", str(time.monotonic())) params.put_bool("OsmDbUpdatesCheck", False) osm_download_locations = json.dumps({ @@ -98,12 +98,12 @@ def filter_nations_and_states(nations: list[str], states: list[str] = None) -> t def update_osm_db() -> None: - # last_downloaded_date = float(params.get('OsmDownloadedDate', encoding='utf-8') or 0.0) - # if params.get_bool("OsmDbUpdatesCheck") or time.time() - last_downloaded_date >= 604800: # 7 days * 24 hours/day * 60 + # last_downloaded_date = params.get("OsmDownloadedDate", return_default=True) + # if params.get_bool("OsmDbUpdatesCheck") or time.monotonic() - last_downloaded_date >= 604800: # 7 days * 24 hours/day * 60 if params.get_bool("OsmDbUpdatesCheck"): cleanup_old_osm_data(get_files_for_cleanup()) - country = params.get('OsmLocationName', encoding='utf-8') - state = params.get('OsmStateName', encoding='utf-8') or "All" + country = params.get("OsmLocationName", return_default=True) + state = params.get("OsmStateName", return_default=True) filtered_nations, filtered_states = filter_nations_and_states([country], [state]) request_refresh_osm_location_data(filtered_nations, filtered_states) diff --git a/sunnypilot/models/fetcher.py b/sunnypilot/models/fetcher.py index 9d0f4e318d..c96fa75c9d 100644 --- a/sunnypilot/models/fetcher.py +++ b/sunnypilot/models/fetcher.py @@ -88,8 +88,8 @@ class ModelCache: def _is_expired(self) -> bool: """Checks if the cache has expired""" current_time = int(time.monotonic() * 1e9) - last_sync = int(self.params.get(self._LAST_SYNC_KEY, encoding="utf-8") or 0) - return last_sync == 0 or (current_time - last_sync) >= self.cache_timeout + last_sync = self.params.get(self._LAST_SYNC_KEY) or 0 + return bool(last_sync == 0) or (current_time - last_sync) >= self.cache_timeout def get(self) -> tuple[dict, bool]: """ @@ -98,7 +98,7 @@ class ModelCache: If no cached data exists or on error, returns an empty dict """ try: - cached_data = self.params.get(self._CACHE_KEY, encoding="utf-8") + cached_data = self.params.get(self._CACHE_KEY) if not cached_data: cloudlog.warning("No cached model data available") return {}, True @@ -110,7 +110,7 @@ class ModelCache: def set(self, data: dict) -> None: """Updates the cache with new model data""" self.params.put(self._CACHE_KEY, json.dumps(data)) - self.params.put(self._LAST_SYNC_KEY, str(int(time.monotonic() * 1e9))) + self.params.put(self._LAST_SYNC_KEY, int(time.monotonic() * 1e9)) class ModelFetcher: diff --git a/sunnypilot/models/helpers.py b/sunnypilot/models/helpers.py index 01069cddb4..40fcf13ec0 100644 --- a/sunnypilot/models/helpers.py +++ b/sunnypilot/models/helpers.py @@ -64,6 +64,7 @@ def is_bundle_version_compatible(bundle: dict) -> bool: """ return bool(REQUIRED_MIN_SELECTOR_VERSION <= bundle.get("minimumSelectorVersion", 0) <= CURRENT_SELECTOR_VERSION) + def get_active_bundle(params: Params = None) -> custom.ModelManagerSP.ModelBundle: """Gets the active model bundle from cache""" if params is None: @@ -111,7 +112,7 @@ def get_active_model_runner(params: Params = None, force_check=False) -> custom. runner_type = active_bundle.runner.raw if cached_runner_type != runner_type: - params.put("ModelRunnerTypeCache", str(int(runner_type))) + params.put("ModelRunnerTypeCache", int(runner_type)) return runner_type diff --git a/sunnypilot/models/manager.py b/sunnypilot/models/manager.py index 8913135203..bdcec64c71 100644 --- a/sunnypilot/models/manager.py +++ b/sunnypilot/models/manager.py @@ -169,16 +169,16 @@ class ModelManagerSP: self.available_models = self.model_fetcher.get_available_bundles() self.active_bundle = get_active_bundle(self.params) - if index_to_download := self.params.get("ModelManager_DownloadIndex", block=False, encoding="utf-8"): - if model_to_download := next((model for model in self.available_models if model.index == int(index_to_download)), None): + if index_to_download := self.params.get("ModelManager_DownloadIndex"): + if model_to_download := next((model for model in self.available_models if model.index == index_to_download), None): try: self.download(model_to_download, Paths.model_root()) except Exception as e: cloudlog.exception(e) finally: - self.params.put("ModelManager_DownloadIndex", "") + self.params.remove("ModelManager_DownloadIndex") - if self.params.get("ModelManager_ClearCache", block=False, encoding="utf-8"): + if self.params.get("ModelManager_ClearCache"): self.clear_model_cache() self.params.remove("ModelManager_ClearCache") diff --git a/sunnypilot/models/tests/model_hash b/sunnypilot/models/tests/model_hash index 6df03c31d1..d104e049b7 100644 --- a/sunnypilot/models/tests/model_hash +++ b/sunnypilot/models/tests/model_hash @@ -1 +1 @@ -61bb1f3077ef8219a44c8c627d5345d1a96e7f859b850bed6215eec91090becb \ No newline at end of file +71c14a02af81857565e5fcffaaddb57a76fe80b283fe3292da830dbc92e211b7 \ No newline at end of file diff --git a/sunnypilot/selfdrive/car/cruise_ext.py b/sunnypilot/selfdrive/car/cruise_ext.py index 6f0419ed14..f443aeee0e 100644 --- a/sunnypilot/selfdrive/car/cruise_ext.py +++ b/sunnypilot/selfdrive/car/cruise_ext.py @@ -17,19 +17,13 @@ class VCruiseHelperSP: self.params = Params() self.custom_acc_enabled = self.params.get_bool("CustomAccIncrementsEnabled") - self.short_increment = self.read_int_param("CustomAccShortPressIncrement", 1) - self.long_increment = self.read_int_param("CustomAccLongPressIncrement", 5) - - def read_int_param(self, key: str, default: int = 0) -> int: - try: - return int(self.params.get(key, encoding='utf8')) - except (ValueError, TypeError): - return default + self.short_increment = self.params.get("CustomAccShortPressIncrement", return_default=True) + self.long_increment = self.params.get("CustomAccLongPressIncrement", return_default=True) def read_custom_set_speed_params(self) -> None: self.custom_acc_enabled = self.params.get_bool("CustomAccIncrementsEnabled") - self.short_increment = self.read_int_param("CustomAccShortPressIncrement", 1) - self.long_increment = self.read_int_param("CustomAccLongPressIncrement", 5) + self.short_increment = self.params.get("CustomAccShortPressIncrement", return_default=True) + self.long_increment = self.params.get("CustomAccLongPressIncrement", return_default=True) def update_v_cruise_delta(self, long_press: bool, v_cruise_delta: float) -> tuple[bool, float]: if not self.custom_acc_enabled: diff --git a/sunnypilot/selfdrive/car/interfaces.py b/sunnypilot/selfdrive/car/interfaces.py index e2a232a3ef..28bae4a0dd 100644 --- a/sunnypilot/selfdrive/car/interfaces.py +++ b/sunnypilot/selfdrive/car/interfaces.py @@ -30,7 +30,7 @@ def _initialize_custom_longitudinal_tuning(CI: CarInterfaceBase, CP: structs.Car # Hyundai Custom Longitudinal Tuning if CP.brand == 'hyundai': - hyundai_longitudinal_tuning = int(params.get("HyundaiLongitudinalTuning", encoding="utf8") or 0) + hyundai_longitudinal_tuning = params.get("HyundaiLongitudinalTuning") if hyundai_longitudinal_tuning == LongitudinalTuningType.DYNAMIC: CP_SP.flags |= HyundaiFlagsSP.LONG_TUNING_DYNAMIC.value if hyundai_longitudinal_tuning == LongitudinalTuningType.PREDICTIVE: diff --git a/sunnypilot/selfdrive/car/tests/test_custom_cruise.py b/sunnypilot/selfdrive/car/tests/test_custom_cruise.py index 2f9d976847..4b7f9b819b 100644 --- a/sunnypilot/selfdrive/car/tests/test_custom_cruise.py +++ b/sunnypilot/selfdrive/car/tests/test_custom_cruise.py @@ -21,8 +21,8 @@ class TestCustomAccIncrements(TestVCruiseHelper): def reset_custom_params(self) -> None: """Reset to default custom ACC parameters""" self.params.put_bool("CustomAccIncrementsEnabled", False) - self.params.put("CustomAccShortPressIncrement", "1") - self.params.put("CustomAccLongPressIncrement", "5") + self.params.put("CustomAccShortPressIncrement", 1) + self.params.put("CustomAccLongPressIncrement", 5) self.v_cruise_helper.read_custom_set_speed_params() def press_button_short(self, button_type: car.CarState.ButtonEvent.Type) -> None: @@ -51,8 +51,8 @@ class TestCustomAccIncrements(TestVCruiseHelper): def set_custom_increments(self, enabled: bool, short_inc: int, long_inc: int) -> None: """Set custom ACC increment parameters""" self.params.put_bool("CustomAccIncrementsEnabled", enabled) - self.params.put("CustomAccShortPressIncrement", str(short_inc)) - self.params.put("CustomAccLongPressIncrement", str(long_inc)) + self.params.put("CustomAccShortPressIncrement", short_inc) + self.params.put("CustomAccLongPressIncrement", long_inc) self.v_cruise_helper.read_custom_set_speed_params() def test_default_behavior_when_disabled(self): diff --git a/sunnypilot/selfdrive/controls/lib/auto_lane_change.py b/sunnypilot/selfdrive/controls/lib/auto_lane_change.py index 29056d5ac5..cf8de2a1b2 100644 --- a/sunnypilot/selfdrive/controls/lib/auto_lane_change.py +++ b/sunnypilot/selfdrive/controls/lib/auto_lane_change.py @@ -42,7 +42,7 @@ class AutoLaneChangeController: self.param_read_counter = 0 self.lane_change_delay = 0.0 - self.lane_change_set_timer = AutoLaneChangeMode.NUDGE + self.lane_change_set_timer = self.params.get("AutoLaneChangeTimer", return_default=True) self.lane_change_bsm_delay = False self.prev_brake_pressed = False @@ -61,10 +61,7 @@ class AutoLaneChangeController: def read_params(self) -> None: self.lane_change_bsm_delay = self.params.get_bool("AutoLaneChangeBsmDelay") - try: - self.lane_change_set_timer = int(self.params.get("AutoLaneChangeTimer", encoding="utf8")) - except (ValueError, TypeError): - self.lane_change_set_timer = AutoLaneChangeMode.NUDGE + self.lane_change_set_timer = self.params.get("AutoLaneChangeTimer", return_default=True) def update_params(self) -> None: if self.param_read_counter % 50 == 0: diff --git a/sunnypilot/selfdrive/controls/lib/blinker_pause_lateral.py b/sunnypilot/selfdrive/controls/lib/blinker_pause_lateral.py index fb86280358..6f8d99b755 100644 --- a/sunnypilot/selfdrive/controls/lib/blinker_pause_lateral.py +++ b/sunnypilot/selfdrive/controls/lib/blinker_pause_lateral.py @@ -21,7 +21,7 @@ class BlinkerPauseLateral: def get_params(self) -> None: self.enabled = self.params.get_bool("BlinkerPauseLateralControl") self.is_metric = self.params.get_bool("IsMetric") - self.min_speed = int(self.params.get("BlinkerMinLateralControlSpeed", encoding='utf8')) + self.min_speed = self.params.get("BlinkerMinLateralControlSpeed") def update(self, CS: car.CarState) -> bool: if not self.enabled: diff --git a/sunnypilot/selfdrive/controls/lib/latcontrol_torque_ext_base.py b/sunnypilot/selfdrive/controls/lib/latcontrol_torque_ext_base.py index 1127619221..43d652e8b7 100644 --- a/sunnypilot/selfdrive/controls/lib/latcontrol_torque_ext_base.py +++ b/sunnypilot/selfdrive/controls/lib/latcontrol_torque_ext_base.py @@ -49,7 +49,7 @@ class LatControlTorqueExtBase(LagdToggle): self.model_v2 = None self.model_valid = False self.torque_params = lac_torque.torque_params - self.use_steering_angle = lac_torque.torque_params.useSteeringAngle + self.use_steering_angle = True # FIXME-SP: deprecated in upstream self.actual_lateral_jerk: float = 0.0 self.lateral_jerk_setpoint: float = 0.0 diff --git a/sunnypilot/selfdrive/controls/lib/nnlc/nnlc.py b/sunnypilot/selfdrive/controls/lib/nnlc/nnlc.py index 2f89594c8f..4872f5c88c 100644 --- a/sunnypilot/selfdrive/controls/lib/nnlc/nnlc.py +++ b/sunnypilot/selfdrive/controls/lib/nnlc/nnlc.py @@ -126,8 +126,7 @@ class NeuralNetworkLateralControl(LatControlTorqueExtBase): self._ff = self.model.evaluate(nn_input) # apply friction override for cars with low NN friction response + # TODO-SP: verify with twilsonco if this change is appropriate if self.model.friction_override: self._pid_log.error += self.torque_from_lateral_accel(LatControlInputs(0.0, 0.0, CS.vEgo, CS.aEgo), self.torque_params, - friction_input, - self._lateral_accel_deadzone, friction_compensation=True, gravity_adjusted=False) diff --git a/sunnypilot/selfdrive/controls/lib/param_store.py b/sunnypilot/selfdrive/controls/lib/param_store.py index 5ec2a1c8c9..fae221bb74 100644 --- a/sunnypilot/selfdrive/controls/lib/param_store.py +++ b/sunnypilot/selfdrive/controls/lib/param_store.py @@ -26,7 +26,7 @@ class ParamStore: def update(self, params: Params) -> None: old_values = dict(self.values) - self.values = {k: params.get(k, encoding='utf8') or "0" for k in self.keys} + self.values = {k: params.get(k) or "0" for k in self.keys} if old_values != self.values: self.cached_params_list = None diff --git a/sunnypilot/sunnylink/api.py b/sunnypilot/sunnylink/api.py index eb9343af9a..942a994b98 100644 --- a/sunnypilot/sunnylink/api.py +++ b/sunnypilot/sunnylink/api.py @@ -46,8 +46,8 @@ class SunnylinkApi(BaseApi): time.sleep(0.5) def _resolve_dongle_ids(self): - sunnylink_dongle_id = self.params.get("SunnylinkDongleId", encoding='utf-8') - comma_dongle_id = self.dongle_id or self.params.get("DongleId", encoding='utf-8') + sunnylink_dongle_id = self.params.get("SunnylinkDongleId") + comma_dongle_id = self.dongle_id or self.params.get("DongleId") return sunnylink_dongle_id, comma_dongle_id def _resolve_imeis(self): @@ -63,7 +63,7 @@ class SunnylinkApi(BaseApi): return imei1, imei2 def _resolve_serial(self): - return (self.params.get("HardwareSerial", encoding='utf8') + return (self.params.get("HardwareSerial") or HARDWARE.get_serial()) def register_device(self, spinner=None, timeout=60, verbose=False): diff --git a/sunnypilot/sunnylink/athena/sunnylinkd.py b/sunnypilot/sunnylink/athena/sunnylinkd.py index a675820628..42b7d779e3 100755 --- a/sunnypilot/sunnylink/athena/sunnylinkd.py +++ b/sunnypilot/sunnylink/athena/sunnylinkd.py @@ -31,7 +31,7 @@ SUNNYLINK_RECONNECT_TIMEOUT_S = 70 # FYI changing this will also would require DISALLOW_LOG_UPLOAD = threading.Event() params = Params() -sunnylink_dongle_id = params.get("SunnylinkDongleId", encoding='utf-8') +sunnylink_dongle_id = params.get("SunnylinkDongleId") sunnylink_api = SunnylinkApi(sunnylink_dongle_id) @@ -68,7 +68,7 @@ def handle_long_poll(ws: WebSocket, exit_event: threading.Event | None) -> None: end_event.set() comma_prime_cellular_end_event.set() - prime_type = params.get("PrimeType", encoding='utf-8') or 0 + prime_type = params.get("PrimeType") or 0 metered = sm['deviceState'].networkMetered if DISALLOW_LOG_UPLOAD.is_set() and not comma_prime_cellular_end_event.is_set(): @@ -103,7 +103,7 @@ def ws_recv(ws: WebSocket, end_event: threading.Event) -> None: elif opcode in (ABNF.OPCODE_PING, ABNF.OPCODE_PONG): cloudlog.debug("sunnylinkd.ws_recv.pong") last_ping = int(time.monotonic() * 1e9) - Params().put("LastSunnylinkPingTime", str(last_ping)) + Params().put("LastSunnylinkPingTime", last_ping) except WebSocketTimeoutException: ns_since_last_ping = int(time.monotonic() * 1e9) - last_ping if ns_since_last_ping > SUNNYLINK_RECONNECT_TIMEOUT_S * 1e9: diff --git a/sunnypilot/sunnylink/backups/manager.py b/sunnypilot/sunnylink/backups/manager.py index d6408d7ba7..5110782a1c 100644 --- a/sunnypilot/sunnylink/backups/manager.py +++ b/sunnypilot/sunnylink/backups/manager.py @@ -32,7 +32,7 @@ class BackupManagerSP: def __init__(self): self.params = Params() - self.device_id = self.params.get("SunnylinkDongleId", encoding="utf8") + self.device_id = self.params.get("SunnylinkDongleId") self.api = SunnylinkApi(self.device_id) self.pm = messaging.PubMaster(["backupManagerSP"]) @@ -253,7 +253,7 @@ class BackupManagerSP: self.params.remove("BackupManager_CreateBackup") # Check for restore command - restore_version = self.params.get("BackupManager_RestoreVersion", encoding="utf8") + restore_version = self.params.get("BackupManager_RestoreVersion") if restore_version: try: version = int(restore_version) if restore_version.isdigit() else None diff --git a/sunnypilot/sunnylink/uploader.py b/sunnypilot/sunnylink/uploader.py index 69ef2cfd8a..b9117f2866 100755 --- a/sunnypilot/sunnylink/uploader.py +++ b/sunnypilot/sunnylink/uploader.py @@ -92,7 +92,7 @@ class Uploader: self.immediate_priority = {"qlog": 0, "qlog.bz2": 0, "qcamera.ts": 1} def list_upload_files(self, metered: bool) -> Iterator[tuple[str, str, str]]: - r = self.params.get("AthenadRecentlyViewedRoutes", encoding="utf8") + r = self.params.get("AthenadRecentlyViewedRoutes") requested_routes = [] if r is None else r.split(",") for logdir in listdir_by_creation(self.root): @@ -250,7 +250,7 @@ def main(exit_event: threading.Event = None) -> None: clear_locks(Paths.log_root()) params = Params() - dongle_id = params.get("SunnylinkDongleId", encoding='utf8') + dongle_id = params.get("SunnylinkDongleId") offroad_transition_prev = 0. offroad_last = False diff --git a/sunnypilot/sunnylink/utils.py b/sunnypilot/sunnylink/utils.py index 55b1f6f285..35714eafe3 100644 --- a/sunnypilot/sunnylink/utils.py +++ b/sunnypilot/sunnylink/utils.py @@ -7,7 +7,7 @@ def get_sunnylink_status(params=None) -> tuple[bool, bool]: """Get the status of Sunnylink on the device. Returns a tuple of (is_sunnylink_enabled, is_registered).""" params = params or Params() is_sunnylink_enabled = params.get_bool("SunnylinkEnabled") - is_registered = params.get("SunnylinkDongleId", encoding='utf-8') not in (None, UNREGISTERED_SUNNYLINK_DONGLE_ID) + is_registered = params.get("SunnylinkDongleId") not in (None, UNREGISTERED_SUNNYLINK_DONGLE_ID) return is_sunnylink_enabled, is_registered @@ -51,7 +51,7 @@ def register_sunnylink(): def get_api_token(): """Get the API token for the device.""" params = Params() - sunnylink_dongle_id = params.get("SunnylinkDongleId", encoding='utf-8') + sunnylink_dongle_id = params.get("SunnylinkDongleId") sunnylink_api = SunnylinkApi(sunnylink_dongle_id) token = sunnylink_api.get_token() print(f"API Token: {token}") diff --git a/system/athena/athenad.py b/system/athena/athenad.py index 244f841e36..f97b8e55bb 100755 --- a/system/athena/athenad.py +++ b/system/athena/athenad.py @@ -153,7 +153,7 @@ class UploadQueueCache: try: upload_queue_json = Params().get("AthenadUploadQueue") if upload_queue_json is not None: - for item in json.loads(upload_queue_json): + for item in upload_queue_json: upload_queue.put(UploadItem.from_dict(item)) except Exception: cloudlog.exception("athena.UploadQueueCache.initialize.exception") @@ -163,7 +163,7 @@ class UploadQueueCache: try: queue: list[UploadItem | None] = list(upload_queue.queue) items = [asdict(i) for i in queue if i is not None and (i.id not in cancelled_uploads)] - Params().put("AthenadUploadQueue", json.dumps(items)) + Params().put("AthenadUploadQueue", items) except Exception: cloudlog.exception("athena.UploadQueueCache.cache.exception") @@ -441,7 +441,7 @@ def uploadFilesToUrls(files_data: list[UploadFileDict]) -> UploadFilesToUrlRespo path=path, url=file.url, headers=file.headers, - created_at=int(time.time() * 1000), + created_at=int(time.time() * 1000), # noqa: TID251 id=None, allow_cellular=file.allow_cellular, priority=file.priority, @@ -485,7 +485,7 @@ def setRouteViewed(route: str) -> dict[str, int | str]: # maintain a list of the last 10 routes viewed in connect params = Params() - r = params.get("AthenadRecentlyViewedRoutes", encoding="utf8") + r = params.get("AthenadRecentlyViewedRoutes") routes = [] if r is None else r.split(",") routes.append(route) @@ -498,7 +498,7 @@ def setRouteViewed(route: str) -> dict[str, int | str]: def startLocalProxy(global_end_event: threading.Event, remote_ws_uri: str, local_port: int) -> dict[str, int]: cloudlog.debug("athena.startLocalProxy.starting") - dongle_id = Params().get("DongleId").decode('utf8') + dongle_id = Params().get("DongleId") identity_token = Api(dongle_id).get_token() ws = create_connection(remote_ws_uri, cookie="jwt=" + identity_token, enable_multithread=True) @@ -551,12 +551,12 @@ def getPublicKey() -> str | None: @dispatcher.add_method def getSshAuthorizedKeys() -> str: - return Params().get("GithubSshKeys", encoding='utf8') or '' + return cast(str, Params().get("GithubSshKeys") or "") @dispatcher.add_method def getGithubUsername() -> str: - return Params().get("GithubUsername", encoding='utf8') or '' + return cast(str, Params().get("GithubUsername") or "") @dispatcher.add_method def getSimInfo(): @@ -599,7 +599,7 @@ def takeSnapshot() -> str | dict[str, str] | None: def get_logs_to_send_sorted(log_attr_name=LOG_ATTR_NAME) -> list[str]: # TODO: scan once then use inotify to detect file creation/deletion - curr_time = int(time.time()) + curr_time = int(time.time()) # noqa: TID251 logs = [] for log_entry in os.listdir(Paths.swaglog_root()): log_path = os.path.join(Paths.swaglog_root(), log_entry) @@ -697,7 +697,7 @@ def log_handler(end_event: threading.Event, log_attr_name=LOG_ATTR_NAME) -> None log_entry = log_files.pop() # newest log file cloudlog.debug(f"athena.log_handler.forward_request {log_entry}") try: - curr_time = int(time.time()) + curr_time = int(time.time()) # noqa: TID251 log_path = os.path.join(Paths.swaglog_root(), log_entry) setxattr(log_path, log_attr_name, int.to_bytes(curr_time, 4, sys.byteorder)) @@ -820,7 +820,7 @@ def ws_recv(ws: WebSocket, end_event: threading.Event) -> None: recv_queue.put_nowait(data) elif opcode == ABNF.OPCODE_PING: last_ping = int(time.monotonic() * 1e9) - Params().put("LastAthenaPingTime", str(last_ping)) + Params().put("LastAthenaPingTime", last_ping) except WebSocketTimeoutException: ns_since_last_ping = int(time.monotonic() * 1e9) - last_ping if ns_since_last_ping > RECONNECT_TIMEOUT_S * 1e9: @@ -885,7 +885,7 @@ def main(exit_event: threading.Event = None): cloudlog.exception("failed to set core affinity") params = Params() - dongle_id = params.get("DongleId", encoding='utf-8') + dongle_id = params.get("DongleId") UploadQueueCache.initialize(upload_queue) ws_uri = ATHENA_HOST + "/ws/v2/" + dongle_id diff --git a/system/athena/manage_athenad.py b/system/athena/manage_athenad.py index 7158cd9220..98557db06a 100755 --- a/system/athena/manage_athenad.py +++ b/system/athena/manage_athenad.py @@ -18,7 +18,7 @@ def main(): def manage_athenad(dongle_id_param, pid_param, process_name, target): params = Params() - dongle_id = params.get(dongle_id_param, encoding='utf-8') + dongle_id = params.get(dongle_id_param) build_metadata = get_build_metadata() cloudlog.bind_global(dongle_id=dongle_id, diff --git a/system/athena/registration.py b/system/athena/registration.py index fce984c03a..2c099c4bce 100755 --- a/system/athena/registration.py +++ b/system/athena/registration.py @@ -17,7 +17,7 @@ from openpilot.common.swaglog import cloudlog UNREGISTERED_DONGLE_ID = "UnregisteredDevice" def is_registered_device() -> bool: - dongle = Params().get("DongleId", encoding='utf-8') + dongle = Params().get("DongleId") return dongle not in (None, UNREGISTERED_DONGLE_ID) @@ -33,7 +33,7 @@ def register(show_spinner=False) -> str | None: """ params = Params() - dongle_id: str | None = params.get("DongleId", encoding='utf8') + dongle_id: str | None = params.get("DongleId") if dongle_id is None and Path(Paths.persist_root()+"/comma/dongle_id").is_file(): # not all devices will have this; added early in comma 3X production (2/28/24) with open(Paths.persist_root()+"/comma/dongle_id") as f: @@ -98,7 +98,7 @@ def register(show_spinner=False) -> str | None: if dongle_id: params.put("DongleId", dongle_id) - set_offroad_alert("Offroad_UnofficialHardware", (dongle_id == UNREGISTERED_DONGLE_ID) and not PC) + set_offroad_alert("Offroad_UnregisteredHardware", (dongle_id == UNREGISTERED_DONGLE_ID) and not PC) return dongle_id diff --git a/system/athena/tests/test_athenad.py b/system/athena/tests/test_athenad.py index e559e0c05c..99ac3b1c6b 100644 --- a/system/athena/tests/test_athenad.py +++ b/system/athena/tests/test_athenad.py @@ -66,9 +66,9 @@ class TestAthenadMethods: def setup_method(self): self.default_params = { "DongleId": "0000000000000000", - "GithubSshKeys": b"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC307aE+nuHzTAgaJhzSf5v7ZZQW9gaperjhCmyPyl4PzY7T1mDGenTlVTN7yoVFZ9UfO9oMQqo0n1OwDIiqbIFxqnhrHU0cYfj88rI85m5BEKlNu5RdaVTj1tcbaPpQc5kZEolaI1nDDjzV0lwS7jo5VYDHseiJHlik3HH1SgtdtsuamGR2T80q1SyW+5rHoMOJG73IH2553NnWuikKiuikGHUYBd00K1ilVAK2xSiMWJp55tQfZ0ecr9QjEsJ+J/efL4HqGNXhffxvypCXvbUYAFSddOwXUPo5BTKevpxMtH+2YrkpSjocWA04VnTYFiPG6U4ItKmbLOTFZtPzoez private", # noqa: E501 - "GithubUsername": b"commaci", - "AthenadUploadQueue": '[]', + "GithubSshKeys": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC307aE+nuHzTAgaJhzSf5v7ZZQW9gaperjhCmyPyl4PzY7T1mDGenTlVTN7yoVFZ9UfO9oMQqo0n1OwDIiqbIFxqnhrHU0cYfj88rI85m5BEKlNu5RdaVTj1tcbaPpQc5kZEolaI1nDDjzV0lwS7jo5VYDHseiJHlik3HH1SgtdtsuamGR2T80q1SyW+5rHoMOJG73IH2553NnWuikKiuikGHUYBd00K1ilVAK2xSiMWJp55tQfZ0ecr9QjEsJ+J/efL4HqGNXhffxvypCXvbUYAFSddOwXUPo5BTKevpxMtH+2YrkpSjocWA04VnTYFiPG6U4ItKmbLOTFZtPzoez private", # noqa: E501 + "GithubUsername": "commaci", + "AthenadUploadQueue": [], } self.params = Params() @@ -91,8 +91,8 @@ class TestAthenadMethods: @staticmethod def _wait_for_upload(): - now = time.time() - while time.time() - now < 5: + now = time.monotonic() + while time.monotonic() - now < 5: if athenad.upload_queue.qsize() == 0: break @@ -190,11 +190,11 @@ class TestAthenadMethods: fn = self._create_file('qlog', data=os.urandom(10000 * 1024)) upload_fn = fn + ('.zst' if compress else '') - item = athenad.UploadItem(path=upload_fn, url="http://localhost:1238", headers={}, created_at=int(time.time()*1000), id='') + item = athenad.UploadItem(path=upload_fn, url="http://localhost:1238", headers={}, created_at=int(time.time()*1000), id='') # noqa: TID251 with pytest.raises(requests.exceptions.ConnectionError): athenad._do_upload(item) - item = athenad.UploadItem(path=upload_fn, url=f"{host}/qlog.zst", headers={}, created_at=int(time.time()*1000), id='') + item = athenad.UploadItem(path=upload_fn, url=f"{host}/qlog.zst", headers={}, created_at=int(time.time()*1000), id='') # noqa: TID251 resp = athenad._do_upload(item) assert resp.status_code == 201 @@ -226,7 +226,7 @@ class TestAthenadMethods: @with_upload_handler def test_upload_handler(self, host): fn = self._create_file('qlog.zst') - item = athenad.UploadItem(path=fn, url=f"{host}/qlog.zst", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True) + item = athenad.UploadItem(path=fn, url=f"{host}/qlog.zst", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True) # noqa: TID251 athenad.upload_queue.put_nowait(item) self._wait_for_upload() @@ -242,7 +242,7 @@ class TestAthenadMethods: mock_put = mocker.patch('openpilot.system.athena.athenad.UPLOAD_SESS.put') mock_put.return_value.__enter__.return_value.status_code = status fn = self._create_file('qlog.zst') - item = athenad.UploadItem(path=fn, url=f"{host}/qlog.zst", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True) + item = athenad.UploadItem(path=fn, url=f"{host}/qlog.zst", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True) # noqa: TID251 athenad.upload_queue.put_nowait(item) self._wait_for_upload() @@ -257,7 +257,7 @@ class TestAthenadMethods: def test_upload_handler_timeout(self): """When an upload times out or fails to connect it should be placed back in the queue""" fn = self._create_file('qlog.zst') - item = athenad.UploadItem(path=fn, url="http://localhost:44444/qlog.zst", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True) + item = athenad.UploadItem(path=fn, url="http://localhost:44444/qlog.zst", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True) # noqa: TID251 item_no_retry = replace(item, retry_count=MAX_RETRY_COUNT) athenad.upload_queue.put_nowait(item_no_retry) @@ -278,7 +278,7 @@ class TestAthenadMethods: @with_upload_handler def test_cancel_upload(self): item = athenad.UploadItem(path="qlog.zst", url="http://localhost:44444/qlog.zst", headers={}, - created_at=int(time.time()*1000), id='id', allow_cellular=True) + created_at=int(time.time()*1000), id='id', allow_cellular=True) # noqa: TID251 athenad.upload_queue.put_nowait(item) dispatcher["cancelUpload"](item.id) @@ -312,7 +312,7 @@ class TestAthenadMethods: @with_upload_handler def test_list_upload_queue_current(self, host: str): fn = self._create_file('qlog.zst') - item = athenad.UploadItem(path=fn, url=f"{host}/qlog.zst", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True) + item = athenad.UploadItem(path=fn, url=f"{host}/qlog.zst", headers={}, created_at=int(time.time()*1000), id='', allow_cellular=True) # noqa: TID251 athenad.upload_queue.put_nowait(item) self._wait_for_upload() @@ -331,7 +331,7 @@ class TestAthenadMethods: path=fp, url=f"http://localhost:44444/{fn}", headers={}, - created_at=int(time.time()*1000), + created_at=int(time.time()*1000), # noqa: TID251 id='', allow_cellular=True, priority=i @@ -343,7 +343,7 @@ class TestAthenadMethods: def test_list_upload_queue(self): item = athenad.UploadItem(path="qlog.zst", url="http://localhost:44444/qlog.zst", headers={}, - created_at=int(time.time()*1000), id='id', allow_cellular=True) + created_at=int(time.time()*1000), id='id', allow_cellular=True) # noqa: TID251 athenad.upload_queue.put_nowait(item) items = dispatcher["listUploadQueue"]() @@ -356,8 +356,8 @@ class TestAthenadMethods: assert len(items) == 0 def test_upload_queue_persistence(self): - item1 = athenad.UploadItem(path="_", url="_", headers={}, created_at=int(time.time()), id='id1') - item2 = athenad.UploadItem(path="_", url="_", headers={}, created_at=int(time.time()), id='id2') + item1 = athenad.UploadItem(path="_", url="_", headers={}, created_at=int(time.time()), id='id1') # noqa: TID251 + item2 = athenad.UploadItem(path="_", url="_", headers={}, created_at=int(time.time()), id='id2') # noqa: TID251 athenad.upload_queue.put_nowait(item1) athenad.upload_queue.put_nowait(item2) @@ -400,11 +400,11 @@ class TestAthenadMethods: def test_get_ssh_authorized_keys(self): keys = dispatcher["getSshAuthorizedKeys"]() - assert keys == self.default_params["GithubSshKeys"].decode('utf-8') + assert keys == self.default_params["GithubSshKeys"] def test_get_github_username(self): keys = dispatcher["getGithubUsername"]() - assert keys == self.default_params["GithubUsername"].decode('utf-8') + assert keys == self.default_params["GithubUsername"] def test_get_version(self): resp = dispatcher["getVersion"]() diff --git a/system/athena/tests/test_athenad_ping.py b/system/athena/tests/test_athenad_ping.py index 025df7d614..8ff1e37a5d 100644 --- a/system/athena/tests/test_athenad_ping.py +++ b/system/athena/tests/test_athenad_ping.py @@ -28,7 +28,7 @@ class TestAthenadPing: exit_event: threading.Event def _get_ping_time(self) -> str | None: - return cast(str | None, self.params.get("LastAthenaPingTime", encoding="utf-8")) + return cast(str | None, self.params.get("LastAthenaPingTime")) def _clear_ping_time(self) -> None: self.params.remove("LastAthenaPingTime") @@ -42,7 +42,7 @@ class TestAthenadPing: def setup_method(self) -> None: self.params = Params() - self.dongle_id = self.params.get("DongleId", encoding="utf-8") + self.dongle_id = self.params.get("DongleId") wifi_radio(True) self._clear_ping_time() diff --git a/system/athena/tests/test_registration.py b/system/athena/tests/test_registration.py index c1dabb78ec..c20722659a 100644 --- a/system/athena/tests/test_registration.py +++ b/system/athena/tests/test_registration.py @@ -49,7 +49,7 @@ class TestRegistration: dongle = register() assert m.call_count == 0 assert dongle == UNREGISTERED_DONGLE_ID - assert self.params.get("DongleId", encoding='utf-8') == dongle + assert self.params.get("DongleId") == dongle def test_missing_cache(self, mocker): # keys exist but no dongle id @@ -63,7 +63,7 @@ class TestRegistration: # call again, shouldn't hit the API this time assert register() == dongle assert m.call_count == 1 - assert self.params.get("DongleId", encoding='utf-8') == dongle + assert self.params.get("DongleId") == dongle def test_unregistered(self, mocker): # keys exist, but unregistered @@ -73,4 +73,4 @@ class TestRegistration: dongle = register() assert m.call_count == 1 assert dongle == UNREGISTERED_DONGLE_ID - assert self.params.get("DongleId", encoding='utf-8') == dongle + assert self.params.get("DongleId") == dongle diff --git a/system/camerad/test/test_camerad.py b/system/camerad/test/test_camerad.py index ab76985972..1f3f97b082 100644 --- a/system/camerad/test/test_camerad.py +++ b/system/camerad/test/test_camerad.py @@ -84,7 +84,10 @@ class TestCamerad: # logMonoTime > SOF assert np.all((ts[c]['t'] - ts[c]['timestampSof']/1e9) > 1e-7) - assert np.all((ts[c]['t'] - ts[c]['timestampEof']/1e9) > 1e-7) + + # logMonoTime > EOF, needs some tolerance since EOF is (SOF + readout time) but there is noise in the SOF timestamping (done via IRQ) + assert np.mean((ts[c]['t'] - ts[c]['timestampEof']/1e9) > 1e-7) > 0.7 # should be mostly logMonoTime > EOF + assert np.all((ts[c]['t'] - ts[c]['timestampEof']/1e9) > -0.10) # when EOF > logMonoTime, it should never be more than two frames def test_stress_test(self): os.environ['SPECTRA_ERROR_PROB'] = '0.008' diff --git a/system/camerad/test/test_exposure.py b/system/camerad/test/test_exposure.py index f431c03410..b853b0f2f2 100644 --- a/system/camerad/test/test_exposure.py +++ b/system/camerad/test/test_exposure.py @@ -33,8 +33,8 @@ class TestCamerad: @with_processes(['camerad']) def test_camera_operation(self): passed = 0 - start = time.time() - while time.time() - start < TEST_TIME and passed < REPEAT: + start = time.monotonic() + while time.monotonic() - start < TEST_TIME and passed < REPEAT: rpic, dpic = get_snapshots(frame="roadCameraState", front_frame="driverCameraState") wpic, _ = get_snapshots(frame="wideRoadCameraState") diff --git a/system/hardware/base.py b/system/hardware/base.py index 3506be5145..b457ea4e17 100644 --- a/system/hardware/base.py +++ b/system/hardware/base.py @@ -199,9 +199,6 @@ class HardwareBase(ABC): def get_modem_temperatures(self): pass - @abstractmethod - def get_nvme_temperatures(self): - pass @abstractmethod def initialize_hardware(self): diff --git a/system/hardware/hardwared.py b/system/hardware/hardwared.py index 223faeaafd..7f9d971fbf 100755 --- a/system/hardware/hardwared.py +++ b/system/hardware/hardwared.py @@ -1,7 +1,6 @@ #!/usr/bin/env python3 import fcntl import os -import json import queue import struct import threading @@ -19,13 +18,14 @@ from openpilot.common.filter_simple import FirstOrderFilter from openpilot.common.params import Params from openpilot.common.realtime import DT_HW from openpilot.selfdrive.selfdrived.alertmanager import set_offroad_alert -from openpilot.system.hardware import HARDWARE, TICI, AGNOS +from openpilot.system.hardware import HARDWARE, TICI, AGNOS, PC from openpilot.system.loggerd.config import get_available_percent from openpilot.system.statsd import statlog from openpilot.common.swaglog import cloudlog from openpilot.system.hardware.power_monitoring import PowerMonitoring from openpilot.system.hardware.fan_controller import TiciFanController from openpilot.system.version import terms_version, training_version +from openpilot.system.athena.registration import UNREGISTERED_DONGLE_ID ThermalStatus = log.DeviceState.ThermalStatus NetworkType = log.DeviceState.NetworkType @@ -38,7 +38,7 @@ ONROAD_CYCLE_TIME = 1 # seconds to wait offroad after requesting an onroad cycl ThermalBand = namedtuple("ThermalBand", ['min_temp', 'max_temp']) HardwareState = namedtuple("HardwareState", ['network_type', 'network_info', 'network_strength', 'network_stats', - 'network_metered', 'nvme_temps', 'modem_temps']) + 'network_metered', 'modem_temps']) # List of thermal bands. We will stay within this region as long as we are within the bounds. # When exiting the bounds, we'll jump to the lower or higher band. Bands are ordered in the dict. @@ -141,7 +141,6 @@ def hw_state_thread(end_event, hw_queue): network_strength=HARDWARE.get_network_strength(network_type), network_stats={'wwanTx': tx, 'wwanRx': rx}, network_metered=HARDWARE.get_network_metered(network_type), - nvme_temps=HARDWARE.get_nvme_temperatures(), modem_temps=modem_temps, ) @@ -172,6 +171,7 @@ def hardware_thread(end_event, hw_queue) -> None: onroad_conditions: dict[str, bool] = { "ignition": False, "not_onroad_cycle": True, + "device_temp_good": True, } startup_conditions: dict[str, bool] = {} startup_conditions_prev: dict[str, bool] = {} @@ -188,7 +188,6 @@ def hardware_thread(end_event, hw_queue) -> None: network_metered=False, network_strength=NetworkStrength.unknown, network_stats={'wwanTx': -1, 'wwanRx': -1}, - nvme_temps=[], modem_temps=[], ) @@ -202,6 +201,10 @@ def hardware_thread(end_event, hw_queue) -> None: params = Params() power_monitor = PowerMonitoring() + uptime_offroad: float = params.get("UptimeOffroad", return_default=True) + uptime_onroad: float = params.get("UptimeOnroad", return_default=True) + last_uptime_ts: float = time.monotonic() + HARDWARE.initialize_hardware() thermal_config = HARDWARE.get_thermal_config() @@ -267,7 +270,6 @@ def hardware_thread(end_event, hw_queue) -> None: if last_hw_state.network_info is not None: msg.deviceState.networkInfo = last_hw_state.network_info - msg.deviceState.nvmeTempC = last_hw_state.nvme_temps msg.deviceState.modemTempC = last_hw_state.modem_temps msg.deviceState.screenBrightnessPercent = HARDWARE.get_screen_brightness() @@ -304,6 +306,7 @@ def hardware_thread(end_event, hw_queue) -> None: # **** starting logic **** startup_conditions["up_to_date"] = params.get("Offroad_ConnectivityNeeded") is None or params.get_bool("DisableUpdates") or params.get_bool("SnoozeUpdate") + startup_conditions["no_excessive_actuation"] = params.get("Offroad_ExcessiveActuation") is None startup_conditions["not_uninstalling"] = not params.get_bool("DoUninstall") startup_conditions["accepted_terms"] = params.get("HasAcceptedTerms") == terms_version @@ -330,21 +333,17 @@ def hardware_thread(end_event, hw_queue) -> None: show_alert = (not onroad_conditions["device_temp_good"] or not startup_conditions["device_temp_engageable"]) and onroad_conditions["ignition"] set_offroad_alert_if_changed("Offroad_TemperatureTooHigh", show_alert, extra_text=extra_text) + # *** registration check *** + if not PC: + # we enforce this for our software, but you are welcome + # to make a different decision in your software + startup_conditions["registered_device"] = PC or (params.get("DongleId") != UNREGISTERED_DONGLE_ID) + # TODO: this should move to TICI.initialize_hardware, but we currently can't import params there if TICI and HARDWARE.get_device_type() == "tici": if not os.path.isfile("/persist/comma/living-in-the-moment"): if not Path("/data/media").is_mount(): set_offroad_alert_if_changed("Offroad_StorageMissing", True) - else: - # check for bad NVMe - try: - with open("/sys/block/nvme0n1/device/model") as f: - model = f.read().strip() - if not model.startswith("Samsung SSD 980") and params.get("Offroad_BadNvme") is None: - set_offroad_alert_if_changed("Offroad_BadNvme", True) - cloudlog.event("Unsupported NVMe", model=model, error=True) - except Exception: - pass # Handle offroad/onroad transition should_start = all(onroad_conditions.values()) @@ -411,7 +410,7 @@ def hardware_thread(end_event, hw_queue) -> None: last_ping = params.get("LastAthenaPingTime") if last_ping is not None: - msg.deviceState.lastAthenaPingTime = int(last_ping) + msg.deviceState.lastAthenaPingTime = last_ping msg.deviceState.thermalStatus = thermal_status pm.send("deviceState", msg) @@ -429,8 +428,6 @@ def hardware_thread(end_event, hw_queue) -> None: statlog.gauge("memory_temperature", msg.deviceState.memoryTempC) for i, temp in enumerate(msg.deviceState.pmicTempC): statlog.gauge(f"pmic{i}_temperature", temp) - for i, temp in enumerate(last_hw_state.nvme_temps): - statlog.gauge(f"nvme_temperature{i}", temp) for i, temp in enumerate(last_hw_state.modem_temps): statlog.gauge(f"modem_temperature{i}", temp) statlog.gauge("fan_speed_percent_desired", msg.deviceState.fanSpeedPercentDesired) @@ -451,12 +448,23 @@ def hardware_thread(end_event, hw_queue) -> None: # save last one before going onroad if rising_edge_started: try: - params.put("LastOffroadStatusPacket", json.dumps(dat)) + params.put("LastOffroadStatusPacket", dat) except Exception: cloudlog.exception("failed to save offroad status") params.put_bool_nonblocking("NetworkMetered", msg.deviceState.networkMetered) + now_ts = time.monotonic() + if off_ts: + uptime_offroad += now_ts - max(last_uptime_ts, off_ts) + elif started_ts: + uptime_onroad += now_ts - max(last_uptime_ts, started_ts) + last_uptime_ts = now_ts + + if (count % int(60. / DT_HW)) == 0: + params.put("UptimeOffroad", uptime_offroad) + params.put("UptimeOnroad", uptime_onroad) + count += 1 should_start_prev = should_start diff --git a/system/hardware/pc/hardware.py b/system/hardware/pc/hardware.py index 9a80f10bed..6c11896390 100644 --- a/system/hardware/pc/hardware.py +++ b/system/hardware/pc/hardware.py @@ -70,8 +70,6 @@ class Pc(HardwareBase): def get_modem_temperatures(self): return [] - def get_nvme_temperatures(self): - return [] def initialize_hardware(self): pass diff --git a/system/hardware/power_monitoring.py b/system/hardware/power_monitoring.py index 952aebd9d7..d0a1e623a7 100644 --- a/system/hardware/power_monitoring.py +++ b/system/hardware/power_monitoring.py @@ -29,12 +29,10 @@ class PowerMonitoring: self.car_voltage_instant_mV = 12e3 # Last value of peripheralState voltage self.integration_lock = threading.Lock() - car_battery_capacity_uWh = self.params.get("CarBatteryCapacity") - if car_battery_capacity_uWh is None: - car_battery_capacity_uWh = 0 + car_battery_capacity_uWh = self.params.get("CarBatteryCapacity") or 0 # Reset capacity if it's low - self.car_battery_capacity_uWh = max((CAR_BATTERY_CAPACITY_uWh / 10), int(car_battery_capacity_uWh)) + self.car_battery_capacity_uWh = max((CAR_BATTERY_CAPACITY_uWh / 10), car_battery_capacity_uWh) # Calculation tick def calculate(self, voltage: int | None, ignition: bool): @@ -58,7 +56,7 @@ class PowerMonitoring: self.car_battery_capacity_uWh = max(self.car_battery_capacity_uWh, 0) self.car_battery_capacity_uWh = min(self.car_battery_capacity_uWh, CAR_BATTERY_CAPACITY_uWh) if now - self.last_save_time >= 10: - self.params.put_nonblocking("CarBatteryCapacity", str(int(self.car_battery_capacity_uWh))) + self.params.put_nonblocking("CarBatteryCapacity", int(self.car_battery_capacity_uWh)) self.last_save_time = now # First measurement, set integration time @@ -114,15 +112,14 @@ class PowerMonitoring: :return: True if the max time offroad has been exceeded, False otherwise """ try: - param = self.params.get("MaxTimeOffroad", encoding="utf8") - sp_max_time_val_s = int(param) * 60 if param is not None and int(param) >= 0 else MAX_TIME_OFFROAD_S + param = self.params.get("MaxTimeOffroad") + sp_max_time_val_s = param * 60 if param is not None and param >= 0 else MAX_TIME_OFFROAD_S except Exception: sp_max_time_val_s = MAX_TIME_OFFROAD_S - return sp_max_time_val_s > 0 and offroad_time >= sp_max_time_val_s + return 0 < sp_max_time_val_s <= offroad_time - -# See if we need to shutdown + # See if we need to shutdown def should_shutdown(self, ignition: bool, in_car: bool, offroad_timestamp: float | None, started_seen: bool): if offroad_timestamp is None: return False diff --git a/system/hardware/tests/test_power_monitoring.py b/system/hardware/tests/test_power_monitoring.py index 3eec13dc4c..451efcd735 100644 --- a/system/hardware/tests/test_power_monitoring.py +++ b/system/hardware/tests/test_power_monitoring.py @@ -206,18 +206,18 @@ class TestPowerMonitoring: (None, MAX_TIME_OFFROAD_S + 1, True), # exceeds 30h (1800+ mins) # Valid max time values (in minutes) - ("60", 59, False), # under limit - ("60", 120, True), # over limit - ("10", 8, False), # under limit - ("10", 11, True), # over limit + (60, 59, False), # under limit + (60, 120, True), # over limit + (10, 8, False), # under limit + (10, 11, True), # over limit # Edge case: max time is zero → no limit enforced - ("0", 0, False), - ("0", 400, False), + (0, 0, False), + (0, 400, False), # Invalid max time formats or negative values → fallback to 30 hours - ("invalid", 100, False), # should fallback to 30h - ("-1", MAX_TIME_OFFROAD_S + 1, True), # should fallback to 30h, and exceed it + (-100, 100, False), # should fallback to 30h + (-1, MAX_TIME_OFFROAD_S + 1, True), # should fallback to 30h, and exceed it ] ) def test_max_time_offroad_exceeded(self, max_time_offroad, offroad_time_min, expected_result): diff --git a/system/hardware/tici/hardware.h b/system/hardware/tici/hardware.h index 179ef54a9b..ae1087fa73 100644 --- a/system/hardware/tici/hardware.h +++ b/system/hardware/tici/hardware.h @@ -75,7 +75,7 @@ public: return; } - int value = util::map_val(std::clamp(percent, 0, 100), 0, 100, 0, 255); + int value = util::map_val(std::clamp(percent, 0, 100), 0, 100, 0, 300); std::ofstream("/sys/class/leds/led:switch_2/brightness") << 0 << "\n"; std::ofstream("/sys/class/leds/led:torch_2/brightness") << value << "\n"; std::ofstream("/sys/class/leds/led:switch_2/brightness") << value << "\n"; diff --git a/system/hardware/tici/hardware.py b/system/hardware/tici/hardware.py index 20a23bd67e..35f9916c31 100644 --- a/system/hardware/tici/hardware.py +++ b/system/hardware/tici/hardware.py @@ -1,4 +1,3 @@ -import json import math import os import subprocess @@ -291,15 +290,6 @@ class Tici(HardwareBase): except Exception: return [] - def get_nvme_temperatures(self): - ret = [] - try: - out = subprocess.check_output("sudo smartctl -aj /dev/nvme0", shell=True) - dat = json.loads(out) - ret = list(map(int, dat["nvme_smart_health_information_log"]["temperature_sensors"])) - except Exception: - pass - return ret def get_current_power_draw(self): return (self.read_param_file("/sys/class/hwmon/hwmon1/power1_input", int) / 1e6) diff --git a/system/loggerd/bootlog.cc b/system/loggerd/bootlog.cc index a7b1ae8244..1b87ce394f 100644 --- a/system/loggerd/bootlog.cc +++ b/system/loggerd/bootlog.cc @@ -31,9 +31,6 @@ static kj::Array build_boot_log() { "[ -x \"$(command -v journalctl)\" ] && journalctl -o short-monotonic", }; - if (Hardware::TICI()) { - bootlog_commands.push_back("[ -e /dev/nvme0 ] && sudo nvme smart-log --output-format=json /dev/nvme0"); - } auto commands = boot.initCommands().initEntries(bootlog_commands.size()); for (int j = 0; j < bootlog_commands.size(); j++) { diff --git a/system/loggerd/encoder/ffmpeg_encoder.cc b/system/loggerd/encoder/ffmpeg_encoder.cc index 4e6946363f..091c2fb2dd 100644 --- a/system/loggerd/encoder/ffmpeg_encoder.cc +++ b/system/loggerd/encoder/ffmpeg_encoder.cc @@ -1,5 +1,3 @@ -#pragma clang diagnostic ignored "-Wdeprecated-declarations" - #include "system/loggerd/encoder/ffmpeg_encoder.h" #include @@ -119,8 +117,7 @@ int FfmpegEncoder::encode_frame(VisionBuf* buf, VisionIpcBufExtra *extra) { ret = -1; } - AVPacket pkt; - av_init_packet(&pkt); + AVPacket pkt = {}; pkt.data = NULL; pkt.size = 0; while (ret >= 0) { diff --git a/system/loggerd/logger.cc b/system/loggerd/logger.cc index f07aee1596..0ebe323939 100644 --- a/system/loggerd/logger.cc +++ b/system/loggerd/logger.cc @@ -59,7 +59,7 @@ kj::Array logger_build_init_data() { for (auto& [key, value] : params_map) { auto lentry = lparams[j]; lentry.setKey(key); - if ( !(params.getKeyType(key) & DONT_LOG) ) { + if ( !(params.getKeyFlag(key) & DONT_LOG) ) { lentry.setValue(capnp::Data::Reader((const kj::byte*)value.data(), value.size())); } j++; diff --git a/system/loggerd/tests/loggerd_tests_common.py b/system/loggerd/tests/loggerd_tests_common.py index 15fd997eb8..87c3da65c2 100644 --- a/system/loggerd/tests/loggerd_tests_common.py +++ b/system/loggerd/tests/loggerd_tests_common.py @@ -76,7 +76,7 @@ class UploaderTestCase: self.seg_dir = self.seg_format.format(self.seg_num) self.params = Params() - self.params.put("IsOffroad", "1") + self.params.put("IsOffroad", True) self.params.put("DongleId", "0000000000000000") def make_file_with_data(self, f_dir: str, fn: str, size_mb: float = .1, lock: bool = False, diff --git a/system/loggerd/tests/test_loggerd.py b/system/loggerd/tests/test_loggerd.py index 8e2f52a731..8f9d92e104 100644 --- a/system/loggerd/tests/test_loggerd.py +++ b/system/loggerd/tests/test_loggerd.py @@ -182,7 +182,7 @@ class TestLoggerd: @pytest.mark.xdist_group("camera_encoder_tests") # setting xdist group ensures tests are run in same worker, prevents encoderd from crashing def test_rotation(self): - Params().put("RecordFront", "1") + Params().put("RecordFront", True) expected_files = {"rlog.zst", "qlog.zst", "qcamera.ts", "fcamera.hevc", "dcamera.hevc", "ecamera.hevc"} diff --git a/system/loggerd/uploader.py b/system/loggerd/uploader.py index 6e6df6114e..38fc0e9209 100755 --- a/system/loggerd/uploader.py +++ b/system/loggerd/uploader.py @@ -88,7 +88,7 @@ class Uploader: self.immediate_priority = {"qlog": 0, "qlog.zst": 0, "qcamera.ts": 1} def list_upload_files(self, metered: bool) -> Iterator[tuple[str, str, str]]: - r = self.params.get("AthenadRecentlyViewedRoutes", encoding="utf8") + r = self.params.get("AthenadRecentlyViewedRoutes") requested_routes = [] if r is None else [route for route in r.split(",") if route] for logdir in listdir_by_creation(self.root): @@ -238,7 +238,7 @@ def main(exit_event: threading.Event = None) -> None: clear_locks(Paths.log_root()) params = Params() - dongle_id = params.get("DongleId", encoding='utf8') + dongle_id = params.get("DongleId") if dongle_id is None: cloudlog.info("uploader missing dongle_id") diff --git a/system/loggerd/video_writer.cc b/system/loggerd/video_writer.cc index 68e870982f..1b47a8fceb 100644 --- a/system/loggerd/video_writer.cc +++ b/system/loggerd/video_writer.cc @@ -1,4 +1,3 @@ -#pragma clang diagnostic ignored "-Wdeprecated-declarations" #include #include "system/loggerd/video_writer.h" @@ -114,8 +113,7 @@ void VideoWriter::write(uint8_t *data, int len, long long timestamp, bool codecc // input timestamps are in microseconds AVRational in_timebase = {1, 1000000}; - AVPacket pkt; - av_init_packet(&pkt); + AVPacket pkt = {}; pkt.data = data; pkt.size = len; pkt.stream_index = this->out_stream->index; @@ -200,10 +198,23 @@ void VideoWriter::encode_and_write_audio_frame(AVFrame* frame) { audio_pts += audio_codec_ctx->frame_size; } +void VideoWriter::process_remaining_audio() { + // Process remaining audio samples by padding with silence + if (audio_buffer.size() > 0 && audio_buffer.size() < audio_codec_ctx->frame_size) { + audio_buffer.resize(audio_codec_ctx->frame_size, 0.0f); + + // Encode final frame + audio_frame->pts = audio_pts; + float *f_samples = reinterpret_cast(audio_frame->data[0]); + std::copy(audio_buffer.begin(), audio_buffer.end(), f_samples); + encode_and_write_audio_frame(audio_frame); + } +} VideoWriter::~VideoWriter() { if (this->remuxing) { if (this->audio_codec_ctx) { + process_remaining_audio(); encode_and_write_audio_frame(NULL); // flush encoder avcodec_free_context(&this->audio_codec_ctx); } diff --git a/system/loggerd/video_writer.h b/system/loggerd/video_writer.h index 25e6484d58..e973c5d811 100644 --- a/system/loggerd/video_writer.h +++ b/system/loggerd/video_writer.h @@ -21,6 +21,7 @@ public: private: void initialize_audio(int sample_rate); void encode_and_write_audio_frame(AVFrame* frame); + void process_remaining_audio(); std::string vid_path, lock_path; FILE *of = nullptr; diff --git a/system/manager/manager.py b/system/manager/manager.py index c59f0118aa..a567c30f8f 100755 --- a/system/manager/manager.py +++ b/system/manager/manager.py @@ -8,7 +8,7 @@ import traceback from cereal import log import cereal.messaging as messaging import openpilot.system.sentry as sentry -from openpilot.common.params import Params, ParamKeyType +from openpilot.common.params import Params, ParamKeyFlag from openpilot.common.text_window import TextWindow from openpilot.system.hardware import HARDWARE from openpilot.system.manager.helpers import unblock_stdout, write_onroad_params, save_bootlog @@ -19,8 +19,6 @@ from openpilot.common.swaglog import cloudlog, add_file_handler from openpilot.system.version import get_build_metadata, terms_version, training_version from openpilot.system.hardware.hw import Paths -from openpilot.sunnypilot.mapd.mapd_installer import VERSION - def manager_init() -> None: save_bootlog() @@ -28,65 +26,25 @@ def manager_init() -> None: build_metadata = get_build_metadata() params = Params() - params.clear_all(ParamKeyType.CLEAR_ON_MANAGER_START) - params.clear_all(ParamKeyType.CLEAR_ON_ONROAD_TRANSITION) - params.clear_all(ParamKeyType.CLEAR_ON_OFFROAD_TRANSITION) + params.clear_all(ParamKeyFlag.CLEAR_ON_MANAGER_START) + params.clear_all(ParamKeyFlag.CLEAR_ON_ONROAD_TRANSITION) + params.clear_all(ParamKeyFlag.CLEAR_ON_OFFROAD_TRANSITION) + params.clear_all(ParamKeyFlag.CLEAR_ON_IGNITION_ON) if build_metadata.release_channel: - params.clear_all(ParamKeyType.DEVELOPMENT_ONLY) - - default_params: list[tuple[str, str | bytes]] = [ - ("CompletedTrainingVersion", "0"), - ("DisengageOnAccelerator", "0"), - ("GsmMetered", "1"), - ("HasAcceptedTerms", "0"), - ("LanguageSetting", "main_en"), - ("OpenpilotEnabledToggle", "1"), - ("LongitudinalPersonality", str(log.LongitudinalPersonality.standard)), - ] - - sunnypilot_default_params: list[tuple[str, str | bytes]] = [ - ("AutoLaneChangeTimer", "0"), - ("AutoLaneChangeBsmDelay", "0"), - ("BlindSpot", "0"), - ("BlinkerMinLateralControlSpeed", "20"), # MPH or km/h - ("BlinkerPauseLateralControl", "0"), - ("Brightness", "0"), - ("ChevronInfo", "4"), - ("CustomAccIncrementsEnabled", "0"), - ("CustomAccLongPressIncrement", "5"), - ("CustomAccShortPressIncrement", "1"), - ("DeviceBootMode", "0"), - ("DisableUpdates", "0"), - ("DynamicExperimentalControl", "0"), - ("HyundaiLongitudinalTuning", "0"), - ("InteractivityTimeout", "0"), - ("LagdToggle", "1"), - ("LagdToggledelay", "0.2"), - ("Mads", "1"), - ("MadsMainCruiseAllowed", "1"), - ("MadsSteeringMode", "0"), - ("MadsUnifiedEngagementMode", "1"), - ("MapdVersion", f"{VERSION}"), - ("MaxTimeOffroad", "1800"), - ("ModelManager_LastSyncTime", "0"), - ("ModelManager_ModelsCache", ""), - ("NeuralNetworkLateralControl", "0"), - ("QuickBootToggle", "0"), - ("QuietMode", "0"), - ("ShowAdvancedControls", "0" if build_metadata.tested_channel else "1"), - ] + params.clear_all(ParamKeyFlag.DEVELOPMENT_ONLY) # device boot mode - if params.get("DeviceBootMode") == b"1": # start in always offroad mode + if params.get("DeviceBootMode") == 1: # start in Always Offroad mode params.put_bool("OffroadMode", True) if params.get_bool("RecordFrontLock"): params.put_bool("RecordFront", True) - # set unset params - for k, v in (default_params + sunnypilot_default_params): - if params.get(k) is None: - params.put(k, v) + # set unset params to their default value + for k in params.all_keys(): + default_value = params.get_default_value(k) + if default_value and params.get(k) is None: + params.put(k, default_value) # Create folders needed for msgq try: @@ -159,19 +117,20 @@ def manager_thread() -> None: params = Params() ignore: list[str] = [] - if params.get("DongleId", encoding='utf8') in (None, UNREGISTERED_DONGLE_ID): + if params.get("DongleId") in (None, UNREGISTERED_DONGLE_ID): ignore += ["manage_athenad", "uploader"] if os.getenv("NOBOARD") is not None: ignore.append("pandad") ignore += [x for x in os.getenv("BLOCK", "").split(",") if len(x) > 0] - sm = messaging.SubMaster(['deviceState', 'carParams'], poll='deviceState') + sm = messaging.SubMaster(['deviceState', 'carParams', 'pandaStates'], poll='deviceState') pm = messaging.PubMaster(['managerState']) write_onroad_params(False, params) ensure_running(managed_processes.values(), False, params=params, CP=sm['carParams'], not_run=ignore) started_prev = False + ignition_prev = False while True: sm.update(1000) @@ -179,15 +138,20 @@ def manager_thread() -> None: started = sm['deviceState'].started if started and not started_prev: - params.clear_all(ParamKeyType.CLEAR_ON_ONROAD_TRANSITION) + params.clear_all(ParamKeyFlag.CLEAR_ON_ONROAD_TRANSITION) elif not started and started_prev: - params.clear_all(ParamKeyType.CLEAR_ON_OFFROAD_TRANSITION) + params.clear_all(ParamKeyFlag.CLEAR_ON_OFFROAD_TRANSITION) + + ignition = any(ps.ignitionLine or ps.ignitionCan for ps in sm['pandaStates'] if ps.pandaType != log.PandaState.PandaType.unknown) + if ignition and not ignition_prev: + params.clear_all(ParamKeyFlag.CLEAR_ON_IGNITION_ON) # update onroad params, which drives pandad's safety setter thread if started != started_prev: write_onroad_params(started, params) started_prev = started + ignition_prev = ignition ensure_running(managed_processes.values(), started, params=params, CP=sm['carParams'], not_run=ignore) diff --git a/system/manager/process.py b/system/manager/process.py index 0ebddae049..c83cc46e0d 100644 --- a/system/manager/process.py +++ b/system/manager/process.py @@ -251,7 +251,7 @@ class DaemonProcess(ManagerProcess): if self.params is None: self.params = Params() - pid = self.params.get(self.param_name, encoding='utf-8') + pid = self.params.get(self.param_name) if pid is not None: try: os.kill(int(pid), 0) diff --git a/system/manager/test/test_manager.py b/system/manager/test/test_manager.py index 9c0b664006..5e55648283 100644 --- a/system/manager/test/test_manager.py +++ b/system/manager/test/test_manager.py @@ -38,6 +38,18 @@ class TestManager: # TODO: ensure there are blacklisted procs until we have a dedicated test assert len(BLACKLIST_PROCS), "No blacklisted procs to test not_run" + def test_set_params_with_default_value(self): + params = Params() + params.clear_all() + + os.environ['PREPAREONLY'] = '1' + manager.main() + for k in params.all_keys(): + default_value = params.get_default_value(k) + if default_value: + assert params.get(k) == default_value + assert params.get("OpenpilotEnabledToggle") + @pytest.mark.skip("this test is flaky the way it's currently written, should be moved to test_onroad") def test_clean_exit(self, subtests): """ diff --git a/system/qcomgpsd/qcomgpsd.py b/system/qcomgpsd/qcomgpsd.py index 3a9e3585ba..819b17f113 100755 --- a/system/qcomgpsd/qcomgpsd.py +++ b/system/qcomgpsd/qcomgpsd.py @@ -286,7 +286,7 @@ def main() -> NoReturn: continue if DEBUG: - print(f"{time.time():.4f}: got log: {log_type} len {len(log_payload)}") + print(f"{time.time():.4f}: got log: {log_type} len {len(log_payload)}") # noqa: TID251 if log_type == LOG_GNSS_OEMDRE_MEASUREMENT_REPORT: msg = messaging.new_message('qcomGnss', valid=True) diff --git a/system/sentry.py b/system/sentry.py index 2f918ebc49..a1fb604dea 100644 --- a/system/sentry.py +++ b/system/sentry.py @@ -106,10 +106,10 @@ def set_user() -> None: def get_properties() -> tuple[str, str, str]: params = Params() - hardware_serial: str = params.get("HardwareSerial", encoding='utf-8') or "" - git_username: str = params.get("GithubUsername", encoding='utf-8') or "" - dongle_id: str = params.get("DongleId", encoding='utf-8') or f"{UNREGISTERED_DONGLE_ID}-{hardware_serial}" - sunnylink_dongle_id: str = params.get("SunnylinkDongleId", encoding='utf-8') or UNREGISTERED_SUNNYLINK_DONGLE_ID + hardware_serial: str = params.get("HardwareSerial") or "" + git_username: str = params.get("GithubUsername") or "" + dongle_id: str = params.get("DongleId") or f"{UNREGISTERED_DONGLE_ID}-{hardware_serial}" + sunnylink_dongle_id: str = params.get("SunnylinkDongleId") or UNREGISTERED_SUNNYLINK_DONGLE_ID return dongle_id, git_username, sunnylink_dongle_id diff --git a/system/statsd.py b/system/statsd.py index b8a7f2c661..d60064fc91 100755 --- a/system/statsd.py +++ b/system/statsd.py @@ -61,7 +61,7 @@ class StatLog: def main() -> NoReturn: - dongle_id = Params().get("DongleId", encoding='utf-8') + dongle_id = Params().get("DongleId") def get_influxdb_line(measurement: str, value: float | dict[str, float], timestamp: datetime, tags: dict) -> str: res = f"{measurement}" for k, v in tags.items(): diff --git a/system/ubloxd/pigeond.py b/system/ubloxd/pigeond.py index e6a03ffbdf..e458a9d65f 100755 --- a/system/ubloxd/pigeond.py +++ b/system/ubloxd/pigeond.py @@ -41,7 +41,7 @@ def add_ubx_checksum(msg: bytes) -> bytes: B = (B + A) % 256 return msg + bytes([A, B]) -def get_assistnow_messages(token: bytes) -> list[bytes]: +def get_assistnow_messages(token: str) -> list[bytes]: # make request # TODO: implement adding the last known location r = requests.get("https://online-live2.services.u-blox.com/GetOnlineData.ashx", params=urllib.parse.urlencode({ @@ -157,7 +157,7 @@ def init_baudrate(pigeon: TTYPigeon): pigeon.set_baud(460800) -def initialize_pigeon(pigeon: TTYPigeon) -> bool: +def init_pigeon(pigeon: TTYPigeon) -> bool: # try initializing a few times for _ in range(10): try: @@ -250,8 +250,6 @@ def initialize_pigeon(pigeon: TTYPigeon) -> bool: return True def deinitialize_and_exit(pigeon: TTYPigeon | None): - cloudlog.warning("Storing almanac in ublox flash") - if pigeon is not None: # controlled GNSS stop pigeon.send(b"\xB5\x62\x06\x04\x04\x00\x00\x00\x08\x00\x16\x74") @@ -260,12 +258,9 @@ def deinitialize_and_exit(pigeon: TTYPigeon | None): set_power(False) sys.exit(0) -def create_pigeon() -> tuple[TTYPigeon, messaging.PubMaster]: - pigeon = None - +def init(pigeon: TTYPigeon) -> None: # register exit handler signal.signal(signal.SIGINT, lambda sig, frame: deinitialize_and_exit(pigeon)) - pm = messaging.PubMaster(['ubloxRaw']) # power cycle ublox set_power(False) @@ -273,23 +268,23 @@ def create_pigeon() -> tuple[TTYPigeon, messaging.PubMaster]: set_power(True) time.sleep(0.5) - pigeon = TTYPigeon() - return pigeon, pm + init_baudrate(pigeon) + init_pigeon(pigeon) -def run_receiving(pigeon: TTYPigeon, pm: messaging.PubMaster, duration: int = 0): +def run_receiving(duration: int = 0): + pm = messaging.PubMaster(['ubloxRaw']) + + pigeon = TTYPigeon() + init(pigeon) start_time = time.monotonic() - def end_condition(): - return True if duration == 0 else time.monotonic() - start_time < duration - last_almanac_save = time.monotonic() - while end_condition(): + while (duration == 0) or (time.monotonic() - start_time < duration): dat = pigeon.receive() if len(dat) > 0: if dat[0] == 0x00: cloudlog.warning("received invalid data from ublox, re-initing!") - init_baudrate(pigeon) - initialize_pigeon(pigeon) + init(pigeon) continue # send out to socket @@ -308,13 +303,7 @@ def run_receiving(pigeon: TTYPigeon, pm: messaging.PubMaster, duration: int = 0) def main(): assert TICI, "unsupported hardware for pigeond" - - pigeon, pm = create_pigeon() - init_baudrate(pigeon) - initialize_pigeon(pigeon) - - # start receiving data - run_receiving(pigeon, pm) + run_receiving() if __name__ == "__main__": main() diff --git a/system/ui/README.md b/system/ui/README.md index 85d32bfd6c..b124ae4d85 100644 --- a/system/ui/README.md +++ b/system/ui/README.md @@ -8,3 +8,8 @@ Quick start: * set `SCALE=1.5` to scale the entire UI by 1.5x * https://www.raylib.com/cheatsheet/cheatsheet.html * https://electronstudio.github.io/raylib-python-cffi/README.html#quickstart + +Style guide: +* All graphical elements should subclass [`Widget`](/system/ui/widgets/__init__.py). + * Prefer a stateful widget over a function for easy migration from QT +* All internal class variables and functions should be prefixed with `_` diff --git a/system/ui/lib/application.py b/system/ui/lib/application.py index 12d825b99f..c7fe39adf9 100644 --- a/system/ui/lib/application.py +++ b/system/ui/lib/application.py @@ -7,7 +7,7 @@ import threading from collections.abc import Callable from collections import deque from dataclasses import dataclass -from enum import IntEnum +from enum import StrEnum from typing import NamedTuple from importlib.resources import as_file, files from openpilot.common.swaglog import cloudlog @@ -33,16 +33,16 @@ ASSETS_DIR = files("openpilot.selfdrive").joinpath("assets") FONT_DIR = ASSETS_DIR.joinpath("fonts") -class FontWeight(IntEnum): - THIN = 0 - EXTRA_LIGHT = 1 - LIGHT = 2 - NORMAL = 3 - MEDIUM = 4 - SEMI_BOLD = 5 - BOLD = 6 - EXTRA_BOLD = 7 - BLACK = 8 +class FontWeight(StrEnum): + THIN = "Inter-Thin.ttf" + EXTRA_LIGHT = "Inter-ExtraLight.ttf" + LIGHT = "Inter-Light.ttf" + NORMAL = "Inter-Regular.ttf" + MEDIUM = "Inter-Medium.ttf" + SEMI_BOLD = "Inter-SemiBold.ttf" + BOLD = "Inter-Bold.ttf" + EXTRA_BOLD = "Inter-ExtraBold.ttf" + BLACK = "Inter-Black.ttf" @dataclass @@ -312,34 +312,23 @@ class GuiApplication: return self._height def _load_fonts(self): - font_files = ( - "Inter-Thin.ttf", - "Inter-ExtraLight.ttf", - "Inter-Light.ttf", - "Inter-Regular.ttf", - "Inter-Medium.ttf", - "Inter-SemiBold.ttf", - "Inter-Bold.ttf", - "Inter-ExtraBold.ttf", - "Inter-Black.ttf", - ) - # Create a character set from our keyboard layouts from openpilot.system.ui.widgets.keyboard import KEYBOARD_LAYOUTS + all_chars = set() for layout in KEYBOARD_LAYOUTS.values(): all_chars.update(key for row in layout for key in row) all_chars = "".join(all_chars) - all_chars += "–✓°" + all_chars += "–✓×°" codepoint_count = rl.ffi.new("int *", 1) codepoints = rl.load_codepoints(all_chars, codepoint_count) - for index, font_file in enumerate(font_files): - with as_file(FONT_DIR.joinpath(font_file)) as fspath: + for font_weight_file in FontWeight: + with as_file(FONT_DIR.joinpath(font_weight_file)) as fspath: font = rl.load_font_ex(fspath.as_posix(), 200, codepoints, codepoint_count[0]) rl.set_texture_filter(font.texture, rl.TextureFilter.TEXTURE_FILTER_BILINEAR) - self._fonts[index] = font + self._fonts[font_weight_file] = font rl.unload_codepoints(codepoints) rl.gui_set_font(self._fonts[FontWeight.NORMAL]) diff --git a/system/ui/lib/wifi_manager.py b/system/ui/lib/wifi_manager.py index 75d1bdbfd3..e4ee224d53 100644 --- a/system/ui/lib/wifi_manager.py +++ b/system/ui/lib/wifi_manager.py @@ -91,7 +91,7 @@ class WifiManager: # Set tethering ssid as "weedle" + first 4 characters of a dongle id self._tethering_ssid = "weedle" if Params is not None: - dongle_id = Params().get("DongleId", encoding="utf-8") + dongle_id = Params().get("DongleId") if dongle_id: self._tethering_ssid += "-" + dongle_id[:4] self.running: bool = True diff --git a/system/ui/reset.py b/system/ui/reset.py index c0dbd1d956..7c9500c7cf 100755 --- a/system/ui/reset.py +++ b/system/ui/reset.py @@ -1,18 +1,21 @@ #!/usr/bin/env python3 import os -import pyray as rl import sys import threading +import time from enum import IntEnum +import pyray as rl + from openpilot.system.hardware import PC from openpilot.system.ui.lib.application import gui_app, FontWeight -from openpilot.system.ui.lib.button import gui_button, ButtonStyle -from openpilot.system.ui.lib.label import gui_label, gui_text_box -from openpilot.system.ui.lib.widget import Widget +from openpilot.system.ui.widgets import Widget +from openpilot.system.ui.widgets.button import Button, ButtonStyle +from openpilot.system.ui.widgets.label import gui_label, gui_text_box NVME = "/dev/nvme0n1" USERDATA = "/dev/disk/by-partlabel/userdata" +TIMEOUT = 3*60 class ResetMode(IntEnum): @@ -31,8 +34,16 @@ class ResetState(IntEnum): class Reset(Widget): def __init__(self, mode): super().__init__() - self.mode = mode - self.reset_state = ResetState.NONE + self._mode = mode + self._previous_reset_state = None + self._reset_state = ResetState.NONE + self._cancel_button = Button("Cancel", self._cancel_callback) + self._confirm_button = Button("Confirm", self._confirm, button_style=ButtonStyle.PRIMARY) + self._reboot_button = Button("Reboot", lambda: os.system("sudo reboot")) + self._render_status = True + + def _cancel_callback(self): + self._render_status = False def _do_erase(self): if PC: @@ -50,53 +61,56 @@ class Reset(Widget): if rm == 0 or fmt == 0: os.system("sudo reboot") else: - self.reset_state = ResetState.FAILED + self._reset_state = ResetState.FAILED def start_reset(self): - self.reset_state = ResetState.RESETTING + self._reset_state = ResetState.RESETTING threading.Timer(0.1, self._do_erase).start() + def _update_state(self): + if self._reset_state != self._previous_reset_state: + self._previous_reset_state = self._reset_state + self._timeout_st = time.monotonic() + elif self._reset_state != ResetState.RESETTING and (time.monotonic() - self._timeout_st) > TIMEOUT: + exit(0) + def _render(self, rect: rl.Rectangle): label_rect = rl.Rectangle(rect.x + 140, rect.y, rect.width - 280, 100) gui_label(label_rect, "System Reset", 100, font_weight=FontWeight.BOLD) text_rect = rl.Rectangle(rect.x + 140, rect.y + 140, rect.width - 280, rect.height - 90 - 100) - gui_text_box(text_rect, self.get_body_text(), 90) + gui_text_box(text_rect, self._get_body_text(), 90) button_height = 160 button_spacing = 50 button_top = rect.y + rect.height - button_height button_width = (rect.width - button_spacing) / 2.0 - if self.reset_state != ResetState.RESETTING: - if self.mode == ResetMode.RECOVER or self.reset_state == ResetState.FAILED: - if gui_button(rl.Rectangle(rect.x, button_top, button_width, button_height), "Reboot"): - os.system("sudo reboot") - elif self.mode == ResetMode.USER_RESET: - if gui_button(rl.Rectangle(rect.x, button_top, button_width, button_height), "Cancel"): - return False + if self._reset_state != ResetState.RESETTING: + if self._mode == ResetMode.RECOVER or self._reset_state == ResetState.FAILED: + self._reboot_button.render(rl.Rectangle(rect.x, button_top, rect.width, button_height)) + elif self._mode == ResetMode.USER_RESET: + self._cancel_button.render(rl.Rectangle(rect.x, button_top, button_width, button_height)) - if self.reset_state != ResetState.FAILED: - if gui_button(rl.Rectangle(rect.x + button_width + 50, button_top, button_width, button_height), - "Confirm", button_style=ButtonStyle.PRIMARY): - self.confirm() + if self._reset_state != ResetState.FAILED: + self._confirm_button.render(rl.Rectangle(rect.x + button_width + 50, button_top, button_width, button_height)) - return True + return self._render_status - def confirm(self): - if self.reset_state == ResetState.CONFIRM: + def _confirm(self): + if self._reset_state == ResetState.CONFIRM: self.start_reset() else: - self.reset_state = ResetState.CONFIRM + self._reset_state = ResetState.CONFIRM - def get_body_text(self): - if self.reset_state == ResetState.CONFIRM: + def _get_body_text(self): + if self._reset_state == ResetState.CONFIRM: return "Are you sure you want to reset your device?" - if self.reset_state == ResetState.RESETTING: + if self._reset_state == ResetState.RESETTING: return "Resetting device...\nThis may take up to a minute." - if self.reset_state == ResetState.FAILED: + if self._reset_state == ResetState.FAILED: return "Reset failed. Reboot to try again." - if self.mode == ResetMode.RECOVER: + if self._mode == ResetMode.RECOVER: return "Unable to mount data partition. Partition may be corrupted. Press confirm to erase and reset your device." return "System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot." diff --git a/system/ui/setup.py b/system/ui/setup.py index 4d9d269480..060d8cf4e3 100755 --- a/system/ui/setup.py +++ b/system/ui/setup.py @@ -10,11 +10,11 @@ import pyray as rl from cereal import log from openpilot.system.hardware import HARDWARE from openpilot.system.ui.lib.application import gui_app, FontWeight -from openpilot.system.ui.lib.button import gui_button, ButtonStyle -from openpilot.system.ui.lib.label import gui_label, gui_text_box -from openpilot.system.ui.lib.widget import Widget -from openpilot.system.ui.widgets.network import WifiManagerUI, WifiManagerWrapper +from openpilot.system.ui.widgets import Widget +from openpilot.system.ui.widgets.button import gui_button, ButtonStyle from openpilot.system.ui.widgets.keyboard import Keyboard +from openpilot.system.ui.widgets.label import gui_label, gui_text_box +from openpilot.system.ui.widgets.network import WifiManagerUI, WifiManagerWrapper NetworkType = log.DeviceState.NetworkType diff --git a/system/ui/spinner.py b/system/ui/spinner.py index 279ddf034d..dd7fadc538 100755 --- a/system/ui/spinner.py +++ b/system/ui/spinner.py @@ -5,8 +5,8 @@ import sys from openpilot.system.ui.lib.application import gui_app from openpilot.system.ui.lib.text_measure import measure_text_cached -from openpilot.system.ui.lib.widget import Widget from openpilot.system.ui.text import wrap_text +from openpilot.system.ui.widgets import Widget from openpilot.system.ui.sunnypilot.lib.application import gui_app_sp diff --git a/system/ui/text.py b/system/ui/text.py index 01a580a12b..61ac043b72 100755 --- a/system/ui/text.py +++ b/system/ui/text.py @@ -3,11 +3,11 @@ import re import sys import pyray as rl from openpilot.system.hardware import HARDWARE, PC -from openpilot.system.ui.lib.text_measure import measure_text_cached -from openpilot.system.ui.lib.button import gui_button, ButtonStyle -from openpilot.system.ui.lib.scroll_panel import GuiScrollPanel from openpilot.system.ui.lib.application import gui_app -from openpilot.system.ui.lib.widget import Widget +from openpilot.system.ui.lib.scroll_panel import GuiScrollPanel +from openpilot.system.ui.lib.text_measure import measure_text_cached +from openpilot.system.ui.widgets import Widget +from openpilot.system.ui.widgets.button import gui_button, ButtonStyle MARGIN = 50 SPACING = 40 diff --git a/system/ui/updater.py b/system/ui/updater.py index 3fd60cfb1d..31799d3628 100755 --- a/system/ui/updater.py +++ b/system/ui/updater.py @@ -7,10 +7,10 @@ from enum import IntEnum from openpilot.system.hardware import HARDWARE from openpilot.system.ui.lib.application import gui_app, FontWeight -from openpilot.system.ui.lib.button import gui_button, ButtonStyle -from openpilot.system.ui.lib.label import gui_text_box, gui_label from openpilot.system.ui.lib.wifi_manager import WifiManagerWrapper -from openpilot.system.ui.lib.widget import Widget +from openpilot.system.ui.widgets import Widget +from openpilot.system.ui.widgets.button import gui_button, ButtonStyle +from openpilot.system.ui.widgets.label import gui_text_box, gui_label from openpilot.system.ui.widgets.network import WifiManagerUI # Constants diff --git a/system/ui/lib/widget.py b/system/ui/widgets/__init__.py similarity index 100% rename from system/ui/lib/widget.py rename to system/ui/widgets/__init__.py diff --git a/system/ui/lib/button.py b/system/ui/widgets/button.py similarity index 75% rename from system/ui/lib/button.py rename to system/ui/widgets/button.py index 121e7f86fa..2be56e6dd5 100644 --- a/system/ui/lib/button.py +++ b/system/ui/widgets/button.py @@ -1,7 +1,11 @@ -import pyray as rl +from collections.abc import Callable from enum import IntEnum -from openpilot.system.ui.lib.application import gui_app, FontWeight + +import pyray as rl + +from openpilot.system.ui.lib.application import gui_app, FontWeight, MousePos from openpilot.system.ui.lib.text_measure import measure_text_cached +from openpilot.system.ui.widgets import Widget class ButtonStyle(IntEnum): @@ -54,6 +58,8 @@ BUTTON_PRESSED_BACKGROUND_COLORS = { _pressed_buttons: set[str] = set() # Track mouse press state globally +# TODO: This should be a Widget class + def gui_button( rect: rl.Rectangle, text: str, @@ -146,3 +152,44 @@ def gui_button( rl.draw_text_ex(font, text, text_pos, font_size, 0, color) return result + + +class Button(Widget): + def __init__(self, + text: str, + click_callback: Callable[[], None] = None, + font_size: int = DEFAULT_BUTTON_FONT_SIZE, + font_weight: FontWeight = FontWeight.MEDIUM, + button_style: ButtonStyle = ButtonStyle.NORMAL, + border_radius: int = 10, + ): + + super().__init__() + self._text = text + self._click_callback = click_callback + self._label_font = gui_app.font(FontWeight.SEMI_BOLD) + self._button_style = button_style + self._font_size = font_size + self._border_radius = border_radius + self._font_size = font_size + self._text_color = BUTTON_TEXT_COLOR[button_style] + self._text_size = measure_text_cached(gui_app.font(font_weight), text, font_size) + + def _handle_mouse_release(self, mouse_pos: MousePos): + if self._click_callback: + print(f"Button clicked: {self._text}") + self._click_callback() + + def _get_background_color(self) -> rl.Color: + if self._is_pressed: + return BUTTON_PRESSED_BACKGROUND_COLORS[self._button_style] + else: + return BUTTON_BACKGROUND_COLORS[self._button_style] + + def _render(self, _): + roundness = self._border_radius / (min(self._rect.width, self._rect.height) / 2) + rl.draw_rectangle_rounded(self._rect, roundness, 10, self._get_background_color()) + + text_pos = rl.Vector2(0, self._rect.y + (self._rect.height - self._text_size.y) // 2) + text_pos.x = self._rect.x + (self._rect.width - self._text_size.x) // 2 + rl.draw_text_ex(self._label_font, self._text, text_pos, self._font_size, 0, self._text_color) diff --git a/system/ui/widgets/confirm_dialog.py b/system/ui/widgets/confirm_dialog.py index 00361905d6..647a455d68 100644 --- a/system/ui/widgets/confirm_dialog.py +++ b/system/ui/widgets/confirm_dialog.py @@ -1,8 +1,8 @@ import pyray as rl from openpilot.system.ui.lib.application import gui_app, FontWeight -from openpilot.system.ui.lib.button import gui_button, ButtonStyle -from openpilot.system.ui.lib.label import gui_text_box -from openpilot.system.ui.lib.widget import DialogResult +from openpilot.system.ui.widgets import DialogResult +from openpilot.system.ui.widgets.button import gui_button, ButtonStyle +from openpilot.system.ui.widgets.label import gui_text_box DIALOG_WIDTH = 1520 DIALOG_HEIGHT = 600 diff --git a/system/ui/widgets/html_render.py b/system/ui/widgets/html_render.py index 07741af456..247b7a5492 100644 --- a/system/ui/widgets/html_render.py +++ b/system/ui/widgets/html_render.py @@ -4,10 +4,10 @@ from dataclasses import dataclass from enum import Enum from typing import Any from openpilot.system.ui.lib.application import gui_app, FontWeight -from openpilot.system.ui.lib.wrap_text import wrap_text from openpilot.system.ui.lib.scroll_panel import GuiScrollPanel -from openpilot.system.ui.lib.widget import Widget, DialogResult -from openpilot.system.ui.lib.button import gui_button, ButtonStyle +from openpilot.system.ui.lib.wrap_text import wrap_text +from openpilot.system.ui.widgets import Widget, DialogResult +from openpilot.system.ui.widgets.button import gui_button, ButtonStyle class ElementType(Enum): diff --git a/system/ui/lib/inputbox.py b/system/ui/widgets/inputbox.py similarity index 99% rename from system/ui/lib/inputbox.py rename to system/ui/widgets/inputbox.py index ccf718ba56..65428479bf 100644 --- a/system/ui/lib/inputbox.py +++ b/system/ui/widgets/inputbox.py @@ -2,7 +2,7 @@ import pyray as rl import time from openpilot.system.ui.lib.application import gui_app from openpilot.system.ui.lib.text_measure import measure_text_cached -from openpilot.system.ui.lib.widget import Widget +from openpilot.system.ui.widgets import Widget PASSWORD_MASK_CHAR = "•" PASSWORD_MASK_DELAY = 1.5 # Seconds to show character before masking diff --git a/system/ui/widgets/keyboard.py b/system/ui/widgets/keyboard.py index 338706e73d..432d9b3cf3 100644 --- a/system/ui/widgets/keyboard.py +++ b/system/ui/widgets/keyboard.py @@ -2,10 +2,10 @@ import time from typing import Literal import pyray as rl from openpilot.system.ui.lib.application import gui_app, FontWeight -from openpilot.system.ui.lib.button import ButtonStyle, gui_button -from openpilot.system.ui.lib.inputbox import InputBox -from openpilot.system.ui.lib.label import gui_label -from openpilot.system.ui.lib.widget import Widget +from openpilot.system.ui.widgets import Widget +from openpilot.system.ui.widgets.button import ButtonStyle, gui_button +from openpilot.system.ui.widgets.inputbox import InputBox +from openpilot.system.ui.widgets.label import gui_label KEY_FONT_SIZE = 96 DOUBLE_CLICK_THRESHOLD = 0.5 # seconds diff --git a/system/ui/lib/label.py b/system/ui/widgets/label.py similarity index 98% rename from system/ui/lib/label.py rename to system/ui/widgets/label.py index c3d0e0303a..e840e8586a 100644 --- a/system/ui/lib/label.py +++ b/system/ui/widgets/label.py @@ -4,6 +4,8 @@ from openpilot.system.ui.lib.text_measure import measure_text_cached from openpilot.system.ui.lib.utils import GuiStyleContext +# TODO: This should be a Widget class + def gui_label( rect: rl.Rectangle, text: str, diff --git a/system/ui/lib/list_view.py b/system/ui/widgets/list_view.py similarity index 98% rename from system/ui/lib/list_view.py rename to system/ui/widgets/list_view.py index 4b6f434de3..aa2fdb845d 100644 --- a/system/ui/lib/list_view.py +++ b/system/ui/widgets/list_view.py @@ -5,9 +5,9 @@ from abc import ABC from openpilot.system.ui.lib.application import gui_app, FontWeight, MousePos from openpilot.system.ui.lib.text_measure import measure_text_cached from openpilot.system.ui.lib.wrap_text import wrap_text -from openpilot.system.ui.lib.button import gui_button, ButtonStyle -from openpilot.system.ui.lib.toggle import Toggle, WIDTH as TOGGLE_WIDTH, HEIGHT as TOGGLE_HEIGHT -from openpilot.system.ui.lib.widget import Widget +from openpilot.system.ui.widgets import Widget +from openpilot.system.ui.widgets.button import gui_button, ButtonStyle +from openpilot.system.ui.widgets.toggle import Toggle, WIDTH as TOGGLE_WIDTH, HEIGHT as TOGGLE_HEIGHT ITEM_BASE_WIDTH = 600 ITEM_BASE_HEIGHT = 170 diff --git a/system/ui/widgets/network.py b/system/ui/widgets/network.py index 0613bb1f12..63e26f0cc6 100644 --- a/system/ui/widgets/network.py +++ b/system/ui/widgets/network.py @@ -4,13 +4,13 @@ from typing import Literal import pyray as rl from openpilot.system.ui.lib.application import gui_app -from openpilot.system.ui.lib.button import ButtonStyle, gui_button -from openpilot.system.ui.lib.label import gui_label from openpilot.system.ui.lib.scroll_panel import GuiScrollPanel from openpilot.system.ui.lib.wifi_manager import NetworkInfo, WifiManagerCallbacks, WifiManagerWrapper, SecurityType -from openpilot.system.ui.widgets.keyboard import Keyboard +from openpilot.system.ui.widgets import Widget +from openpilot.system.ui.widgets.button import ButtonStyle, gui_button from openpilot.system.ui.widgets.confirm_dialog import confirm_dialog -from openpilot.system.ui.lib.widget import Widget +from openpilot.system.ui.widgets.keyboard import Keyboard +from openpilot.system.ui.widgets.label import gui_label NM_DEVICE_STATE_NEED_AUTH = 60 MIN_PASSWORD_LENGTH = 8 diff --git a/system/ui/widgets/option_dialog.py b/system/ui/widgets/option_dialog.py index a2958ee1f4..3140f419f5 100644 --- a/system/ui/widgets/option_dialog.py +++ b/system/ui/widgets/option_dialog.py @@ -1,9 +1,9 @@ import pyray as rl from openpilot.system.ui.lib.application import FontWeight -from openpilot.system.ui.lib.button import gui_button, ButtonStyle, TextAlignment -from openpilot.system.ui.lib.label import gui_label from openpilot.system.ui.lib.scroll_panel import GuiScrollPanel -from openpilot.system.ui.lib.widget import Widget +from openpilot.system.ui.widgets import Widget +from openpilot.system.ui.widgets.button import gui_button, ButtonStyle, TextAlignment +from openpilot.system.ui.widgets.label import gui_label # Constants MARGIN = 50 diff --git a/system/ui/lib/scroller.py b/system/ui/widgets/scroller.py similarity index 97% rename from system/ui/lib/scroller.py rename to system/ui/widgets/scroller.py index 8a10221772..f7304bf6a6 100644 --- a/system/ui/lib/scroller.py +++ b/system/ui/widgets/scroller.py @@ -1,6 +1,6 @@ import pyray as rl -from openpilot.system.ui.lib.widget import Widget from openpilot.system.ui.lib.scroll_panel import GuiScrollPanel +from openpilot.system.ui.widgets import Widget ITEM_SPACING = 40 LINE_COLOR = rl.GRAY diff --git a/system/ui/lib/toggle.py b/system/ui/widgets/toggle.py similarity index 97% rename from system/ui/lib/toggle.py rename to system/ui/widgets/toggle.py index 2edf2ff11c..3f7f463916 100644 --- a/system/ui/lib/toggle.py +++ b/system/ui/widgets/toggle.py @@ -1,6 +1,6 @@ import pyray as rl from openpilot.system.ui.lib.application import MousePos -from openpilot.system.ui.lib.widget import Widget +from openpilot.system.ui.widgets import Widget ON_COLOR = rl.Color(51, 171, 76, 255) OFF_COLOR = rl.Color(0x39, 0x39, 0x39, 255) diff --git a/system/updated/tests/test_base.py b/system/updated/tests/test_base.py index 52287c58f9..699a0f0bd3 100644 --- a/system/updated/tests/test_base.py +++ b/system/updated/tests/test_base.py @@ -132,8 +132,8 @@ class TestBaseUpdate: class ParamsBaseUpdateTest(TestBaseUpdate): def _test_finalized_update(self, branch, version, agnos_version, release_notes): - assert self.params.get("UpdaterNewDescription", encoding="utf-8").startswith(f"{version} / {branch}") - assert self.params.get("UpdaterNewReleaseNotes", encoding="utf-8") == f"{release_notes}\n" + assert self.params.get("UpdaterNewDescription").startswith(f"{version} / {branch}") + assert self.params.get("UpdaterNewReleaseNotes") == f"{release_notes}\n" super()._test_finalized_update(branch, version, agnos_version, release_notes) def send_check_for_updates_signal(self, updated: ManagerProcess): @@ -143,16 +143,16 @@ class ParamsBaseUpdateTest(TestBaseUpdate): updated.signal(signal.SIGHUP.value) def _test_params(self, branch, fetch_available, update_available): - assert self.params.get("UpdaterTargetBranch", encoding="utf-8") == branch + assert self.params.get("UpdaterTargetBranch") == branch assert self.params.get_bool("UpdaterFetchAvailable") == fetch_available assert self.params.get_bool("UpdateAvailable") == update_available def wait_for_idle(self): - self.wait_for_condition(lambda: self.params.get("UpdaterState", encoding="utf-8") == "idle") + self.wait_for_condition(lambda: self.params.get("UpdaterState") == "idle") def wait_for_failed(self): - self.wait_for_condition(lambda: self.params.get("UpdateFailedCount", encoding="utf-8") is not None and \ - int(self.params.get("UpdateFailedCount", encoding="utf-8")) > 0) + self.wait_for_condition(lambda: self.params.get("UpdateFailedCount") is not None and \ + self.params.get("UpdateFailedCount") > 0) def wait_for_fetch_available(self): self.wait_for_condition(lambda: self.params.get_bool("UpdaterFetchAvailable")) diff --git a/system/updated/updated.py b/system/updated/updated.py index 0759c0a7aa..1fd9e8b717 100755 --- a/system/updated/updated.py +++ b/system/updated/updated.py @@ -31,8 +31,13 @@ FINALIZED = os.path.join(STAGING_ROOT, "finalized") OVERLAY_INIT = Path(os.path.join(BASEDIR, ".overlay_init")) -DAYS_NO_CONNECTIVITY_MAX = 14 # do not allow to engage after this many days -DAYS_NO_CONNECTIVITY_PROMPT = 10 # send an offroad prompt after this many days +# do not allow to engage after this many hours onroad and this many routes +HOURS_NO_CONNECTIVITY_MAX = 27 +ROUTES_NO_CONNECTIVITY_MAX = 84 +# send an offroad prompt after this many hours onroad and this many routes +HOURS_NO_CONNECTIVITY_PROMPT = 23 +ROUTES_NO_CONNECTIVITY_PROMPT = 80 + class UserRequest: NONE = 0 @@ -61,15 +66,7 @@ class WaitTimeHelper: def write_time_to_param(params, param) -> None: t = datetime.datetime.now(datetime.UTC).replace(tzinfo=None) - params.put(param, t.isoformat().encode('utf8')) - -def read_time_from_param(params, param) -> datetime.datetime | None: - t = params.get(param, encoding='utf8') - try: - return datetime.datetime.fromisoformat(t) - except (TypeError, ValueError): - pass - return None + params.put(param, t) def run(cmd: list[str], cwd: str = None) -> str: return subprocess.check_output(cmd, cwd=cwd, stderr=subprocess.STDOUT, encoding='utf8') @@ -242,7 +239,7 @@ class Updater: @property def target_branch(self) -> str: - b: str | None = self.params.get("UpdaterTargetBranch", encoding='utf-8') + b: str | None = self.params.get("UpdaterTargetBranch") if b is None: b = self.get_branch(BASEDIR) return b @@ -272,20 +269,22 @@ class Updater: return run(["git", "rev-parse", "HEAD"], path).rstrip() def set_params(self, update_success: bool, failed_count: int, exception: str | None) -> None: - self.params.put("UpdateFailedCount", str(failed_count)) + self.params.put("UpdateFailedCount", failed_count) self.params.put("UpdaterTargetBranch", self.target_branch) self.params.put_bool("UpdaterFetchAvailable", self.update_available) if len(self.branches): self.params.put("UpdaterAvailableBranches", ','.join(self.branches.keys())) - last_update = datetime.datetime.now(datetime.UTC).replace(tzinfo=None) + last_uptime_onroad = self.params.get("UptimeOnroad", return_default=True) + last_route_count = self.params.get("RouteCount", return_default=True) if update_success: - write_time_to_param(self.params, "LastUpdateTime") + self.params.put("LastUpdateTime", datetime.datetime.now(datetime.UTC).replace(tzinfo=None)) + self.params.put("LastUpdateUptimeOnroad", last_uptime_onroad) + self.params.put("LastUpdateRouteCount", last_route_count) else: - t = read_time_from_param(self.params, "LastUpdateTime") - if t is not None: - last_update = t + last_uptime_onroad = self.params.get("LastUpdateUptimeOnroad") or last_uptime_onroad + last_route_count = self.params.get("LastUpdateRouteCount") or last_route_count if exception is None: self.params.remove("LastUpdateException") @@ -323,8 +322,8 @@ class Updater: for alert in ("Offroad_UpdateFailed", "Offroad_ConnectivityNeeded", "Offroad_ConnectivityNeededPrompt"): set_offroad_alert(alert, False) - now = datetime.datetime.now(datetime.UTC).replace(tzinfo=None) - dt = now - last_update + dt_uptime_onroad = (self.params.get("UptimeOnroad", return_default=True) - last_uptime_onroad) / (60*60) + dt_route_count = self.params.get("RouteCount", return_default=True) - last_route_count build_metadata = get_build_metadata() if failed_count > 15 and exception is not None and self.has_internet: if build_metadata.tested_channel: @@ -333,11 +332,11 @@ class Updater: extra_text = exception set_offroad_alert("Offroad_UpdateFailed", True, extra_text=extra_text) elif failed_count > 0: - if dt.days > DAYS_NO_CONNECTIVITY_MAX: + if dt_uptime_onroad > HOURS_NO_CONNECTIVITY_MAX and dt_route_count > ROUTES_NO_CONNECTIVITY_MAX: set_offroad_alert("Offroad_ConnectivityNeeded", True) - elif dt.days > DAYS_NO_CONNECTIVITY_PROMPT: - remaining = max(DAYS_NO_CONNECTIVITY_MAX - dt.days, 1) - set_offroad_alert("Offroad_ConnectivityNeededPrompt", True, extra_text=f"{remaining} day{'' if remaining == 1 else 's'}.") + elif dt_uptime_onroad > HOURS_NO_CONNECTIVITY_PROMPT and dt_route_count > ROUTES_NO_CONNECTIVITY_PROMPT: + remaining = max(HOURS_NO_CONNECTIVITY_MAX - dt_uptime_onroad, 1) + set_offroad_alert("Offroad_ConnectivityNeededPrompt", True, extra_text=f"{remaining} hour{'' if remaining == 1 else 's'}.") def check_for_update(self) -> None: cloudlog.info("checking for updates") @@ -429,8 +428,8 @@ def main() -> None: cloudlog.event("update installed") if not params.get("InstallDate"): - t = datetime.datetime.now(datetime.UTC).replace(tzinfo=None).isoformat() - params.put("InstallDate", t.encode('utf8')) + t = datetime.datetime.now(datetime.UTC).replace(tzinfo=None) + params.put("InstallDate", t) updater = Updater() update_failed_count = 0 # TODO: Load from param? @@ -468,7 +467,7 @@ def main() -> None: updater.check_for_update() # download update - last_fetch = read_time_from_param(params, "UpdaterLastFetchTime") + last_fetch = params.get("UpdaterLastFetchTime") timed_out = last_fetch is None or (datetime.datetime.now(datetime.UTC).replace(tzinfo=None) - last_fetch > datetime.timedelta(days=3)) user_requested_fetch = wait_helper.user_request == UserRequest.FETCH if params.get_bool("NetworkMetered") and not timed_out and not user_requested_fetch: diff --git a/system/version.py b/system/version.py index 34c9ade24d..9bf8855a28 100755 --- a/system/version.py +++ b/system/version.py @@ -18,8 +18,8 @@ TESTED_BRANCHES = RELEASE_BRANCHES + ['devel', 'devel-staging', 'nightly-dev'] + BUILD_METADATA_FILENAME = "build.json" -training_version: bytes = b"0.2.0" -terms_version: bytes = b"2" +training_version: str = "0.2.0" +terms_version: str = "2" def get_version(path: str = BASEDIR) -> str: diff --git a/tinygrad_repo b/tinygrad_repo index 7737cbb2a0..1bef2d80c1 160000 --- a/tinygrad_repo +++ b/tinygrad_repo @@ -1 +1 @@ -Subproject commit 7737cbb2a0635fce95a9085fb1b53d5bea1093f8 +Subproject commit 1bef2d80c18a8313dadb5f5c6379e67ef574a4d2 diff --git a/tools/cabana/SConscript b/tools/cabana/SConscript index c8e6093b86..91edfafe00 100644 --- a/tools/cabana/SConscript +++ b/tools/cabana/SConscript @@ -29,7 +29,8 @@ cabana_lib = cabana_env.Library("cabana_lib", ['mainwin.cc', 'streams/socketcans 'streams/routes.cc', 'dbc/dbc.cc', 'dbc/dbcfile.cc', 'dbc/dbcmanager.cc', 'utils/export.cc', 'utils/util.cc', 'chart/chartswidget.cc', 'chart/chart.cc', 'chart/signalselector.cc', 'chart/tiplabel.cc', 'chart/sparkline.cc', - 'commands.cc', 'messageswidget.cc', 'streamselector.cc', 'settings.cc', 'detailwidget.cc', 'tools/findsimilarbits.cc', 'tools/findsignal.cc', 'tools/routeinfo.cc'], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) + 'commands.cc', 'messageswidget.cc', 'streamselector.cc', 'settings.cc', + 'cameraview.cc', 'detailwidget.cc', 'tools/findsimilarbits.cc', 'tools/findsignal.cc', 'tools/routeinfo.cc'], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) cabana_env.Program('cabana', ['cabana.cc', cabana_lib, assets], LIBS=cabana_libs, FRAMEWORKS=base_frameworks) if GetOption('extras'): diff --git a/tools/cabana/cameraview.cc b/tools/cabana/cameraview.cc new file mode 100644 index 0000000000..13c838efd8 --- /dev/null +++ b/tools/cabana/cameraview.cc @@ -0,0 +1,261 @@ +#include "tools/cabana/cameraview.h" + +#ifdef __APPLE__ +#include +#else +#include +#endif + +#include + +namespace { + +const char frame_vertex_shader[] = +#ifdef __APPLE__ + "#version 330 core\n" +#else + "#version 300 es\n" +#endif + "layout(location = 0) in vec4 aPosition;\n" + "layout(location = 1) in vec2 aTexCoord;\n" + "uniform mat4 uTransform;\n" + "out vec2 vTexCoord;\n" + "void main() {\n" + " gl_Position = uTransform * aPosition;\n" + " vTexCoord = aTexCoord;\n" + "}\n"; + +const char frame_fragment_shader[] = +#ifdef __APPLE__ + "#version 330 core\n" +#else + "#version 300 es\n" + "precision mediump float;\n" +#endif + "uniform sampler2D uTextureY;\n" + "uniform sampler2D uTextureUV;\n" + "in vec2 vTexCoord;\n" + "out vec4 colorOut;\n" + "void main() {\n" + " float y = texture(uTextureY, vTexCoord).r;\n" + " vec2 uv = texture(uTextureUV, vTexCoord).rg - 0.5;\n" + " float r = y + 1.402 * uv.y;\n" + " float g = y - 0.344 * uv.x - 0.714 * uv.y;\n" + " float b = y + 1.772 * uv.x;\n" + " colorOut = vec4(r, g, b, 1.0);\n" + "}\n"; + +} // namespace + +CameraWidget::CameraWidget(std::string stream_name, VisionStreamType type, QWidget* parent) : + stream_name(stream_name), active_stream_type(type), requested_stream_type(type), QOpenGLWidget(parent) { + setAttribute(Qt::WA_OpaquePaintEvent); + qRegisterMetaType>("availableStreams"); + QObject::connect(this, &CameraWidget::vipcThreadConnected, this, &CameraWidget::vipcConnected, Qt::BlockingQueuedConnection); + QObject::connect(this, &CameraWidget::vipcThreadFrameReceived, this, &CameraWidget::vipcFrameReceived, Qt::QueuedConnection); + QObject::connect(this, &CameraWidget::vipcAvailableStreamsUpdated, this, &CameraWidget::availableStreamsUpdated, Qt::QueuedConnection); + QObject::connect(QApplication::instance(), &QCoreApplication::aboutToQuit, this, &CameraWidget::stopVipcThread); +} + +CameraWidget::~CameraWidget() { + makeCurrent(); + stopVipcThread(); + if (isValid()) { + glDeleteVertexArrays(1, &frame_vao); + glDeleteBuffers(1, &frame_vbo); + glDeleteBuffers(1, &frame_ibo); + glDeleteTextures(2, textures); + shader_program_.reset(); + } + doneCurrent(); +} + +void CameraWidget::initializeGL() { + initializeOpenGLFunctions(); + + shader_program_ = std::make_unique(context()); + shader_program_->addShaderFromSourceCode(QOpenGLShader::Vertex, frame_vertex_shader); + shader_program_->addShaderFromSourceCode(QOpenGLShader::Fragment, frame_fragment_shader); + shader_program_->link(); + + GLint frame_pos_loc = shader_program_->attributeLocation("aPosition"); + GLint frame_texcoord_loc = shader_program_->attributeLocation("aTexCoord"); + + auto [x1, x2, y1, y2] = requested_stream_type == VISION_STREAM_DRIVER ? std::tuple(0.f, 1.f, 1.f, 0.f) : std::tuple(1.f, 0.f, 1.f, 0.f); + const uint8_t frame_indicies[] = {0, 1, 2, 0, 2, 3}; + const float frame_coords[4][4] = { + {-1.0, -1.0, x2, y1}, // bl + {-1.0, 1.0, x2, y2}, // tl + { 1.0, 1.0, x1, y2}, // tr + { 1.0, -1.0, x1, y1}, // br + }; + + glGenVertexArrays(1, &frame_vao); + glBindVertexArray(frame_vao); + glGenBuffers(1, &frame_vbo); + glBindBuffer(GL_ARRAY_BUFFER, frame_vbo); + glBufferData(GL_ARRAY_BUFFER, sizeof(frame_coords), frame_coords, GL_STATIC_DRAW); + glEnableVertexAttribArray(frame_pos_loc); + glVertexAttribPointer(frame_pos_loc, 2, GL_FLOAT, GL_FALSE, + sizeof(frame_coords[0]), (const void *)0); + glEnableVertexAttribArray(frame_texcoord_loc); + glVertexAttribPointer(frame_texcoord_loc, 2, GL_FLOAT, GL_FALSE, + sizeof(frame_coords[0]), (const void *)(sizeof(float) * 2)); + glGenBuffers(1, &frame_ibo); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, frame_ibo); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(frame_indicies), frame_indicies, GL_STATIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindVertexArray(0); + + glGenTextures(2, textures); + + shader_program_->bind(); + shader_program_->setUniformValue("uTextureY", 0); + shader_program_->setUniformValue("uTextureUV", 1); + shader_program_->release(); +} + +void CameraWidget::showEvent(QShowEvent *event) { + if (!vipc_thread) { + clearFrames(); + vipc_thread = new QThread(); + connect(vipc_thread, &QThread::started, [=]() { vipcThread(); }); + connect(vipc_thread, &QThread::finished, vipc_thread, &QObject::deleteLater); + vipc_thread->start(); + } +} + +void CameraWidget::stopVipcThread() { + makeCurrent(); + if (vipc_thread) { + vipc_thread->requestInterruption(); + vipc_thread->quit(); + vipc_thread->wait(); + vipc_thread = nullptr; + } +} + +void CameraWidget::availableStreamsUpdated(std::set streams) { + available_streams = streams; +} + +void CameraWidget::paintGL() { + glClearColor(bg.redF(), bg.greenF(), bg.blueF(), bg.alphaF()); + glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + + std::lock_guard lk(frame_lock); + if (!current_frame_) return; + + // Scale for aspect ratio + float widget_ratio = (float)width() / height(); + float frame_ratio = (float)stream_width / stream_height; + float scale_x = std::min(frame_ratio / widget_ratio, 1.0f); + float scale_y = std::min(widget_ratio / frame_ratio, 1.0f); + + glViewport(0, 0, width() * devicePixelRatio(), height() * devicePixelRatio()); + + shader_program_->bind(); + QMatrix4x4 transform; + transform.scale(scale_x, scale_y, 1.0f); + shader_program_->setUniformValue("uTransform", transform); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + + glPixelStorei(GL_UNPACK_ROW_LENGTH, stream_stride); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, textures[0]); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, stream_width, stream_height, GL_RED, GL_UNSIGNED_BYTE, current_frame_->y); + + glPixelStorei(GL_UNPACK_ROW_LENGTH, stream_stride/2); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, textures[1]); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, stream_width/2, stream_height/2, GL_RG, GL_UNSIGNED_BYTE, current_frame_->uv); + + glBindVertexArray(frame_vao); + glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, nullptr); + glBindVertexArray(0); + + // Reset both texture units + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, 0); + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + + shader_program_->release(); +} + +void CameraWidget::vipcConnected(VisionIpcClient *vipc_client) { + makeCurrent(); + stream_width = vipc_client->buffers[0].width; + stream_height = vipc_client->buffers[0].height; + stream_stride = vipc_client->buffers[0].stride; + + glBindTexture(GL_TEXTURE_2D, textures[0]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, stream_width, stream_height, 0, GL_RED, GL_UNSIGNED_BYTE, nullptr); + assert(glGetError() == GL_NO_ERROR); + + glBindTexture(GL_TEXTURE_2D, textures[1]); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RG8, stream_width/2, stream_height/2, 0, GL_RG, GL_UNSIGNED_BYTE, nullptr); + assert(glGetError() == GL_NO_ERROR); +} + +void CameraWidget::vipcFrameReceived() { + update(); +} + +void CameraWidget::vipcThread() { + VisionStreamType cur_stream = requested_stream_type; + std::unique_ptr vipc_client; + VisionIpcBufExtra frame_meta = {}; + + while (!QThread::currentThread()->isInterruptionRequested()) { + if (!vipc_client || cur_stream != requested_stream_type) { + clearFrames(); + qDebug().nospace() << "connecting to stream " << requested_stream_type << ", was connected to " << cur_stream; + cur_stream = requested_stream_type; + vipc_client.reset(new VisionIpcClient(stream_name, cur_stream, false)); + } + active_stream_type = cur_stream; + + if (!vipc_client->connected) { + clearFrames(); + auto streams = VisionIpcClient::getAvailableStreams(stream_name, false); + if (streams.empty()) { + QThread::msleep(100); + continue; + } + emit vipcAvailableStreamsUpdated(streams); + + if (!vipc_client->connect(false)) { + QThread::msleep(100); + continue; + } + emit vipcThreadConnected(vipc_client.get()); + } + + if (VisionBuf *buf = vipc_client->recv(&frame_meta, 100)) { + { + std::lock_guard lk(frame_lock); + current_frame_ = buf; + frame_meta_ = frame_meta; + } + emit vipcThreadFrameReceived(); + } + } +} + +void CameraWidget::clearFrames() { + std::lock_guard lk(frame_lock); + current_frame_ = nullptr; + available_streams.clear(); +} diff --git a/tools/cabana/cameraview.h b/tools/cabana/cameraview.h new file mode 100644 index 0000000000..930b13d82c --- /dev/null +++ b/tools/cabana/cameraview.h @@ -0,0 +1,64 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "msgq/visionipc/visionipc_client.h" + +class CameraWidget : public QOpenGLWidget, protected QOpenGLFunctions { + Q_OBJECT + +public: + using QOpenGLWidget::QOpenGLWidget; + explicit CameraWidget(std::string stream_name, VisionStreamType stream_type, QWidget* parent = nullptr); + ~CameraWidget(); + void setStreamType(VisionStreamType type) { requested_stream_type = type; } + VisionStreamType getStreamType() { return active_stream_type; } + void stopVipcThread(); + +signals: + void clicked(); + void vipcThreadConnected(VisionIpcClient *); + void vipcThreadFrameReceived(); + void vipcAvailableStreamsUpdated(std::set); + +protected: + void paintGL() override; + void initializeGL() override; + void showEvent(QShowEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override { emit clicked(); } + void vipcThread(); + void clearFrames(); + + GLuint frame_vao, frame_vbo, frame_ibo; + GLuint textures[2]; + std::unique_ptr shader_program_; + QColor bg = Qt::black; + + std::string stream_name; + int stream_width = 0; + int stream_height = 0; + int stream_stride = 0; + std::atomic active_stream_type; + std::atomic requested_stream_type; + std::set available_streams; + QThread *vipc_thread = nullptr; + std::recursive_mutex frame_lock; + VisionBuf* current_frame_ = nullptr; + VisionIpcBufExtra frame_meta_ = {}; + +protected slots: + void vipcConnected(VisionIpcClient *vipc_client); + void vipcFrameReceived(); + void availableStreamsUpdated(std::set streams); +}; + +Q_DECLARE_METATYPE(std::set); diff --git a/tools/cabana/chart/chart.cc b/tools/cabana/chart/chart.cc index 3588c5edc6..505b2b8053 100644 --- a/tools/cabana/chart/chart.cc +++ b/tools/cabana/chart/chart.cc @@ -45,7 +45,7 @@ ChartView::ChartView(const std::pair &x_range, ChartsWidget *par createToolButtons(); setRubberBand(QChartView::HorizontalRubberBand); setMouseTracking(true); - setTheme(settings.theme == DARK_THEME ? QChart::QChart::ChartThemeDark : QChart::ChartThemeLight); + setTheme(utils::isDarkTheme() ? QChart::QChart::ChartThemeDark : QChart::ChartThemeLight); signal_value_font.setPointSize(9); QObject::connect(axis_y, &QValueAxis::rangeChanged, this, &ChartView::resetChartCache); @@ -747,7 +747,7 @@ void ChartView::drawTimeline(QPainter *painter) { QRectF time_str_rect(QPointF(x - time_str_size.width() / 2.0, plot_area.bottom() + AXIS_X_TOP_MARGIN), time_str_size); QPainterPath path; path.addRoundedRect(time_str_rect, 3, 3); - painter->fillPath(path, settings.theme == DARK_THEME ? Qt::darkGray : Qt::gray); + painter->fillPath(path, utils::isDarkTheme() ? Qt::darkGray : Qt::gray); painter->setPen(palette().color(QPalette::BrightText)); painter->setFont(axis_x->labelsFont()); painter->drawText(time_str_rect, Qt::AlignCenter, time_str); diff --git a/tools/cabana/chart/chartswidget.cc b/tools/cabana/chart/chartswidget.cc index 08840f4663..3e9e452b90 100644 --- a/tools/cabana/chart/chartswidget.cc +++ b/tools/cabana/chart/chartswidget.cc @@ -254,7 +254,7 @@ void ChartsWidget::settingChanged() { if (std::exchange(current_theme, settings.theme) != current_theme) { undo_zoom_action->setIcon(utils::icon("arrow-counterclockwise")); redo_zoom_action->setIcon(utils::icon("arrow-clockwise")); - auto theme = settings.theme == DARK_THEME ? QChart::QChart::ChartThemeDark : QChart::ChartThemeLight; + auto theme = utils::isDarkTheme() ? QChart::QChart::ChartThemeDark : QChart::ChartThemeLight; for (auto c : charts) { c->setTheme(theme); } diff --git a/tools/cabana/chart/sparkline.cc b/tools/cabana/chart/sparkline.cc index 09f86a095a..91435cd5ac 100644 --- a/tools/cabana/chart/sparkline.cc +++ b/tools/cabana/chart/sparkline.cc @@ -4,51 +4,97 @@ #include #include -void Sparkline::update(const MessageId &msg_id, const cabana::Signal *sig, double last_msg_ts, int range, QSize size) { - points.clear(); - double value = 0; - auto [first, last] = can->eventsInRange(msg_id, std::make_pair(last_msg_ts -range, last_msg_ts)); - for (auto it = first; it != last; ++it) { - if (sig->getValue((*it)->dat, (*it)->size, &value)) { - points.emplace_back(((*it)->mono_time - (*first)->mono_time) / 1e9, value); - } - } - - if (points.empty() || size.isEmpty()) { +void Sparkline::update(const cabana::Signal *sig, CanEventIter first, CanEventIter last, int range, QSize size) { + if (first == last || size.isEmpty()) { pixmap = QPixmap(); return; } - const auto [min, max] = std::minmax_element(points.begin(), points.end(), - [](auto &l, auto &r) { return l.y() < r.y(); }); - min_val = min->y() == max->y() ? min->y() - 1 : min->y(); - max_val = min->y() == max->y() ? max->y() + 1 : max->y(); - freq_ = points.size() / std::max(points.back().x() - points.front().x(), 1.0); + points_.clear(); + min_val = std::numeric_limits::max(); + max_val = std::numeric_limits::lowest(); + points_.reserve(std::distance(first, last)); + + uint64_t start_time = (*first)->mono_time; + double value = 0.0; + for (auto it = first; it != last; ++it) { + if (sig->getValue((*it)->dat, (*it)->size, &value)) { + min_val = std::min(min_val, value); + max_val = std::max(max_val, value); + points_.emplace_back(((*it)->mono_time - start_time) / 1e9, value); + } + } + + if (points_.empty()) { + pixmap = QPixmap(); + return; + } + + freq_ = points_.size() / std::max(points_.back().x() - points_.front().x(), 1.0); render(sig->color, range, size); } void Sparkline::render(const QColor &color, int range, QSize size) { - const double xscale = (size.width() - 1) / (double)range; - const double yscale = (size.height() - 3) / (max_val - min_val); - for (auto &v : points) { - v = QPoint(v.x() * xscale, 1 + std::abs(v.y() - max_val) * yscale); + // Adjust for flat lines + bool is_flat_line = min_val == max_val; + if (is_flat_line) { + min_val -= 1.0; + max_val += 1.0; } + // Calculate scaling + const double xscale = (size.width() - 1) / (double)range; + const double yscale = (size.height() - 3) / (max_val - min_val); + bool draw_individual_points = (points_.back().x() * xscale / points_.size()) > 8.0; + + // Transform or downsample points + render_points_.reserve(points_.size()); + render_points_.clear(); + if (draw_individual_points) { + for (const auto &p : points_) { + render_points_.emplace_back(p.x() * xscale, 1.0 + (max_val - p.y()) * yscale); + } + } else if (is_flat_line) { + double y = size.height() / 2.0; + render_points_.emplace_back(0.0, y); + render_points_.emplace_back(points_.back().x() * xscale, y); + } else { + double prev_y = points_.front().y(); + render_points_.emplace_back(points_.front().x() * xscale, 1.0 + (max_val - prev_y) * yscale); + bool in_flat = false; + + for (size_t i = 1; i < points_.size(); ++i) { + const auto &p = points_[i]; + double y = p.y(); + if (std::abs(y - prev_y) < 1e-6) { + in_flat = true; + } else { + if (in_flat) render_points_.emplace_back(points_[i - 1].x() * xscale, 1.0 + (max_val - prev_y) * yscale); + render_points_.emplace_back(p.x() * xscale, 1.0 + (max_val - y) * yscale); + in_flat = false; + } + prev_y = y; + } + if (in_flat) render_points_.emplace_back(points_.back().x() * xscale, 1.0 + (max_val - prev_y) * yscale); + } + + // Render to pixmap qreal dpr = qApp->devicePixelRatio(); - size *= dpr; - if (size != pixmap.size()) { - pixmap = QPixmap(size); + const QSize pixmap_size = size * dpr; + if (pixmap.size() != pixmap_size) { + pixmap = QPixmap(pixmap_size); } pixmap.setDevicePixelRatio(dpr); pixmap.fill(Qt::transparent); QPainter painter(&pixmap); - painter.setRenderHint(QPainter::Antialiasing, points.size() < 500); + painter.setRenderHint(QPainter::Antialiasing, render_points_.size() <= 500); painter.setPen(color); - painter.drawPolyline(points.data(), points.size()); + painter.drawPolyline(render_points_.data(), render_points_.size()); + painter.setPen(QPen(color, 3)); - if ((points.back().x() - points.front().x()) / points.size() > 8) { - painter.drawPoints(points.data(), points.size()); + if (draw_individual_points) { + painter.drawPoints(render_points_.data(), render_points_.size()); } else { - painter.drawPoint(points.back()); + painter.drawPoint(render_points_.back()); } } diff --git a/tools/cabana/chart/sparkline.h b/tools/cabana/chart/sparkline.h index 806f0a61eb..7f30047d0d 100644 --- a/tools/cabana/chart/sparkline.h +++ b/tools/cabana/chart/sparkline.h @@ -9,7 +9,7 @@ class Sparkline { public: - void update(const MessageId &msg_id, const cabana::Signal *sig, double last_msg_ts, int range, QSize size); + void update(const cabana::Signal *sig, CanEventIter first, CanEventIter last, int range, QSize size); inline double freq() const { return freq_; } bool isEmpty() const { return pixmap.isNull(); } @@ -20,6 +20,7 @@ public: private: void render(const QColor &color, int range, QSize size); - std::vector points; + std::vector points_; + std::vector render_points_; double freq_ = 0; }; diff --git a/tools/cabana/chart/tiplabel.cc b/tools/cabana/chart/tiplabel.cc index be71602838..233fa80373 100644 --- a/tools/cabana/chart/tiplabel.cc +++ b/tools/cabana/chart/tiplabel.cc @@ -7,6 +7,7 @@ #include #include "tools/cabana/settings.h" +#include "tools/cabana/utils/util.h" TipLabel::TipLabel(QWidget *parent) : QLabel(parent, Qt::ToolTip | Qt::FramelessWindowHint) { setAttribute(Qt::WA_ShowWithoutActivating); @@ -19,7 +20,7 @@ TipLabel::TipLabel(QWidget *parent) : QLabel(parent, Qt::ToolTip | Qt::Frameless font.setPointSizeF(8.34563465); setFont(font); auto palette = QToolTip::palette(); - if (settings.theme != DARK_THEME) { + if (!utils::isDarkTheme()) { palette.setColor(QPalette::ToolTipBase, QApplication::palette().color(QPalette::Base)); palette.setColor(QPalette::ToolTipText, QRgb(0x404044)); // same color as chart label brush } diff --git a/tools/cabana/dbc/dbc.cc b/tools/cabana/dbc/dbc.cc index e9c869fce7..9b0de92218 100644 --- a/tools/cabana/dbc/dbc.cc +++ b/tools/cabana/dbc/dbc.cc @@ -109,7 +109,7 @@ void cabana::Msg::update() { mask[i] |= ((1ULL << sz) - 1) << shift; - bits -= size; + bits -= sz; i = sig->is_little_endian ? i - 1 : i + 1; } } diff --git a/tools/cabana/historylog.cc b/tools/cabana/historylog.cc index 7e73da55f0..3dbdf5a7cd 100644 --- a/tools/cabana/historylog.cc +++ b/tools/cabana/historylog.cc @@ -153,7 +153,7 @@ void HeaderView::paintSection(QPainter *painter, const QRect &rect, int logicalI painter->fillRect(rect, bg_role.value()); } QString text = model()->headerData(logicalIndex, Qt::Horizontal, Qt::DisplayRole).toString(); - painter->setPen(palette().color(settings.theme == DARK_THEME ? QPalette::BrightText : QPalette::Text)); + painter->setPen(palette().color(utils::isDarkTheme() ? QPalette::BrightText : QPalette::Text)); painter->drawText(rect.adjusted(5, 3, -5, -3), defaultAlignment(), text.replace(QChar('_'), ' ')); } diff --git a/tools/cabana/signalview.cc b/tools/cabana/signalview.cc index 9fe70c3ee8..35537d75e3 100644 --- a/tools/cabana/signalview.cc +++ b/tools/cabana/signalview.cc @@ -634,11 +634,12 @@ void SignalView::updateState(const std::set *msgs) { QSize size(available_width - value_width, delegate->button_size.height() - style()->pixelMetric(QStyle::PM_FocusFrameVMargin) * 2); + auto [first, last] = can->eventsInRange(model->msg_id, std::make_pair(last_msg.ts -settings.sparkline_range, last_msg.ts)); QFutureSynchronizer synchronizer; for (int i = first_visible.row(); i <= last_visible.row(); ++i) { auto item = model->getItem(model->index(i, 1)); synchronizer.addFuture(QtConcurrent::run( - &item->sparkline, &Sparkline::update, model->msg_id, item->sig, last_msg.ts, settings.sparkline_range, size)); + &item->sparkline, &Sparkline::update, item->sig, first, last, settings.sparkline_range, size)); } synchronizer.waitForFinished(); } diff --git a/tools/cabana/utils/util.cc b/tools/cabana/utils/util.cc index 4556f90850..f27df4bf1e 100644 --- a/tools/cabana/utils/util.cc +++ b/tools/cabana/utils/util.cc @@ -191,8 +191,15 @@ DoubleValidator::DoubleValidator(QObject *parent) : QDoubleValidator(parent) { } namespace utils { + +bool isDarkTheme() { + QColor windowColor = QApplication::palette().color(QPalette::Window); + return windowColor.lightness() < 128; +} + QPixmap icon(const QString &id) { - bool dark_theme = settings.theme == DARK_THEME; + bool dark_theme = isDarkTheme(); + QPixmap pm; QString key = "bootstrap_" % id % (dark_theme ? "1" : "0"); if (!QPixmapCache::find(key, &pm)) { diff --git a/tools/cabana/utils/util.h b/tools/cabana/utils/util.h index 1aad3103db..5c1cbe2d69 100644 --- a/tools/cabana/utils/util.h +++ b/tools/cabana/utils/util.h @@ -98,7 +98,9 @@ public: }; namespace utils { + QPixmap icon(const QString &id); +bool isDarkTheme(); void setTheme(int theme); QString formatSeconds(double sec, bool include_milliseconds = false, bool absolute_time = false); inline void drawStaticText(QPainter *p, const QRect &r, const QStaticText &text) { diff --git a/tools/cabana/videowidget.cc b/tools/cabana/videowidget.cc index 3d715b0319..b817ae1208 100644 --- a/tools/cabana/videowidget.cc +++ b/tools/cabana/videowidget.cc @@ -261,14 +261,23 @@ void Slider::paintEvent(QPaintEvent *ev) { QStyleOptionSlider opt; initStyleOption(&opt); - QRect r = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderGroove, this); - p.fillRect(r, timeline_colors[(int)TimelineType::None]); + QRect handle_rect = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderHandle, this); + QRect groove_rect = style()->subControlRect(QStyle::CC_Slider, &opt, QStyle::SC_SliderGroove, this); + + // Adjust groove height to match handle height + int handle_height = handle_rect.height(); + groove_rect.setHeight(handle_height * 0.5); + groove_rect.moveCenter(QPoint(groove_rect.center().x(), rect().center().y())); + + p.fillRect(groove_rect, timeline_colors[(int)TimelineType::None]); double min = minimum() / factor; double max = maximum() / factor; auto fillRange = [&](double begin, double end, const QColor &color) { if (begin > max || end < min) return; + + QRect r = groove_rect; r.setLeft(((std::max(min, begin) - min) / (max - min)) * width()); r.setRight(((std::min(max, end) - min) / (max - min)) * width()); p.fillRect(r, color); diff --git a/tools/cabana/videowidget.h b/tools/cabana/videowidget.h index 6f756448c0..6da0023123 100644 --- a/tools/cabana/videowidget.h +++ b/tools/cabana/videowidget.h @@ -11,7 +11,7 @@ #include #include -#include "selfdrive/ui/qt/widgets/cameraview.h" +#include "tools/cabana/cameraview.h" #include "tools/cabana/utils/util.h" #include "tools/replay/logreader.h" #include "tools/cabana/streams/replaystream.h" diff --git a/tools/camerastream/compressed_vipc.py b/tools/camerastream/compressed_vipc.py index 8c773f9dfe..b25b8b0cb7 100755 --- a/tools/camerastream/compressed_vipc.py +++ b/tools/camerastream/compressed_vipc.py @@ -62,7 +62,7 @@ def decoder(addr, vipc_server, vst, nvidia, W, H, debug=False): print("waiting for iframe") continue time_q.append(time.monotonic()) - network_latency = (int(time.time()*1e9) - evta.unixTimestampNanos)/1e6 + network_latency = (int(time.time()*1e9) - evta.unixTimestampNanos)/1e6 # noqa: TID251 frame_latency = ((evta.idx.timestampEof/1e9) - (evta.idx.timestampSof/1e9))*1000 process_latency = ((evt.logMonoTime/1e9) - (evta.idx.timestampEof/1e9))*1000 diff --git a/tools/car_porting/examples/find_segments_with_message.ipynb b/tools/car_porting/examples/find_segments_with_message.ipynb index 4e688cc65b..af17bde52b 100644 --- a/tools/car_porting/examples/find_segments_with_message.ipynb +++ b/tools/car_porting/examples/find_segments_with_message.ipynb @@ -76,7 +76,7 @@ " if platform not in database:\n", " print(f\"No segments available for {platform}\")\n", " continue\n", - " \n", + "\n", " all_segments = database[platform]\n", " NUM_SEGMENTS = min(len(all_segments), MAX_SEGS_PER_PLATFORM)\n", " TEST_SEGMENTS.extend(random.sample(all_segments, NUM_SEGMENTS))\n", @@ -147,7 +147,7 @@ } ], "source": [ - "from openpilot.tools.lib.logreader import LogReader\n", + "from openpilot.tools.lib.logreader import LogReader, comma_car_segments_source\n", "from tqdm.notebook import tqdm, tnrange\n", "\n", "# Example search for CAN ignition messages\n", @@ -169,7 +169,7 @@ "progress_bar = tnrange(len(TEST_SEGMENTS), desc=\"segments searched\")\n", "\n", "for segment in TEST_SEGMENTS:\n", - " lr = LogReader(segment)\n", + " lr = LogReader(segment, sources=[comma_car_segments_source])\n", " CP = lr.first(\"carParams\")\n", " if CP is None:\n", " progress_bar.update()\n", diff --git a/tools/car_porting/examples/ford_vin_fingerprint.ipynb b/tools/car_porting/examples/ford_vin_fingerprint.ipynb index 7b0dd656da..6b806d22d2 100644 --- a/tools/car_porting/examples/ford_vin_fingerprint.ipynb +++ b/tools/car_porting/examples/ford_vin_fingerprint.ipynb @@ -20,7 +20,7 @@ "source": [ "\"\"\"In this example, we use the public comma car segments database to check if vin fingerprinting is feasible for ford.\"\"\"\n", "\n", - "from openpilot.tools.lib.logreader import LogReader\n", + "from openpilot.tools.lib.logreader import LogReader, comma_car_segments_source\n", "from openpilot.tools.lib.comma_car_segments import get_comma_car_segments_database\n", "from opendbc.car.ford.values import CAR\n", "\n", @@ -100,7 +100,7 @@ " if platform not in database:\n", " print(f\"Skipping platform: {platform}, no data available\")\n", " continue\n", - " \n", + "\n", " all_segments = database[platform]\n", "\n", " NUM_SEGMENTS = min(len(all_segments), MAX_SEGS_PER_PLATFORM)\n", @@ -110,7 +110,7 @@ " segments = random.sample(all_segments, NUM_SEGMENTS)\n", "\n", " for segment in segments:\n", - " lr = LogReader(segment)\n", + " lr = LogReader(segment, sources=[comma_car_segments_source])\n", " CP = lr.first(\"carParams\")\n", " if \"FORD\" not in CP.carFingerprint:\n", " print(segment, CP.carFingerprint)\n", diff --git a/tools/car_porting/examples/hkg_canfd_gear_message.ipynb b/tools/car_porting/examples/hkg_canfd_gear_message.ipynb index 5fdbdda684..f0bca8decc 100644 --- a/tools/car_porting/examples/hkg_canfd_gear_message.ipynb +++ b/tools/car_porting/examples/hkg_canfd_gear_message.ipynb @@ -72,7 +72,7 @@ " #if platform not in database:\n", " # print(f\"Skipping platform: {platform}, no data available\")\n", " # continue\n", - " \n", + "\n", " all_segments = database[platform]\n", "\n", " NUM_SEGMENTS = min(len(all_segments), MAX_SEGS_PER_PLATFORM)\n", @@ -198,12 +198,12 @@ "from opendbc.car.hyundai.hyundaicanfd import CanBus\n", "\n", "from openpilot.selfdrive.pandad import can_capnp_to_list\n", - "from openpilot.tools.lib.logreader import LogReader\n", + "from openpilot.tools.lib.logreader import LogReader, comma_car_segments_source\n", "\n", "message_names = [\"GEAR_SHIFTER\", \"ACCELERATOR\", \"GEAR\", \"GEAR_ALT\", \"GEAR_ALT_2\"]\n", "\n", "for segment in TEST_SEGMENTS:\n", - " lr = LogReader(segment)\n", + " lr = LogReader(segment, sources=[comma_car_segments_source])\n", " CP = lr.first(\"carParams\")\n", " if CP is None:\n", " continue\n", diff --git a/tools/lib/api.py b/tools/lib/api.py index c2e1b1a8cd..c6e2d98914 100644 --- a/tools/lib/api.py +++ b/tools/lib/api.py @@ -2,6 +2,8 @@ import os import requests API_HOST = os.getenv('API_HOST', 'https://api.commadotai.com') +# TODO: this should be merged into common.api + class CommaApi: def __init__(self, token=None): self.session = requests.Session() diff --git a/tools/lib/comma_car_segments.py b/tools/lib/comma_car_segments.py index fe9c350a9b..cd19356d66 100644 --- a/tools/lib/comma_car_segments.py +++ b/tools/lib/comma_car_segments.py @@ -14,7 +14,8 @@ def get_comma_car_segments_database(): ret = {} for platform in database: - ret[MIGRATION.get(platform, platform)] = database[platform] + # TODO: remove this when commaCarSegments is updated to remove selector + ret[MIGRATION.get(platform, platform)] = [s.rstrip('/s') for s in database[platform]] return ret @@ -86,5 +87,5 @@ def get_repo_url(path): return get_repo_raw_url(path) -def get_url(route, segment, file="rlog.bz2"): +def get_url(route, segment, file="rlog.zst"): return get_repo_url(f"segments/{route.replace('|', '/')}/{segment}/{file}") diff --git a/tools/lib/filereader.py b/tools/lib/filereader.py index 0bb4abd2fa..02f5fd1b95 100644 --- a/tools/lib/filereader.py +++ b/tools/lib/filereader.py @@ -1,6 +1,8 @@ import os import posixpath import socket +from functools import cache +from openpilot.common.retry import retry from urllib.parse import urlparse from openpilot.tools.lib.url_file import URLFile @@ -8,14 +10,16 @@ from openpilot.tools.lib.url_file import URLFile DATA_ENDPOINT = os.getenv("DATA_ENDPOINT", "http://data-raw.comma.internal/") -def internal_source_available(url=DATA_ENDPOINT): +@cache +@retry(delay=0.0) +def internal_source_available(url: str) -> bool: if os.path.isdir(url): return True try: hostname = urlparse(url).hostname port = urlparse(url).port or 80 - with socket.socket(socket.AF_INET,socket.SOCK_STREAM) as s: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.settimeout(0.5) s.connect((hostname, port)) return True @@ -30,6 +34,7 @@ def resolve_name(fn): return fn +@cache def file_exists(fn): fn = resolve_name(fn) if fn.startswith(("http://", "https://")): diff --git a/tools/lib/framereader.py b/tools/lib/framereader.py index 8f7f723c28..30ce1f80fe 100644 --- a/tools/lib/framereader.py +++ b/tools/lib/framereader.py @@ -56,6 +56,7 @@ def decompress_video_data(rawdat, w, h, pix_fmt="rgb24", vid_fmt='hevc') -> np.n "-"] dat = subprocess.check_output(args, input=rawdat) + ret: np.ndarray if pix_fmt == "rgb24": ret = np.frombuffer(dat, dtype=np.uint8).reshape(-1, h, w, 3) elif pix_fmt in ["nv12", "yuv420p"]: diff --git a/tools/lib/helpers.py b/tools/lib/helpers.py index 7c34e17cb1..8c976e7ecc 100644 --- a/tools/lib/helpers.py +++ b/tools/lib/helpers.py @@ -9,7 +9,7 @@ class RE: INDEX = r'-?[0-9]+' SLICE = fr'(?P{INDEX})?:?(?P{INDEX})?:?(?P{INDEX})?' - SEGMENT_RANGE = fr'{ROUTE_NAME}(?:(--|/)(?P({SLICE})))?(?:/(?P([qras])))?' + SEGMENT_RANGE = fr'{ROUTE_NAME}(?:(--|/)(?P({SLICE})))?(?:/(?P([qra])))?' BOOTLOG_NAME = ROUTE_NAME diff --git a/tools/lib/logreader.py b/tools/lib/logreader.py index 34d3e5ea9f..1075bd2f08 100755 --- a/tools/lib/logreader.py +++ b/tools/lib/logreader.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 import bz2 -from functools import cache, partial +from functools import partial import multiprocessing import capnp import enum @@ -13,14 +13,16 @@ import warnings import zstandard as zstd from collections.abc import Callable, Iterable, Iterator +from typing import cast from urllib.parse import parse_qs, urlparse from cereal import log as capnp_log from openpilot.common.swaglog import cloudlog from openpilot.tools.lib.comma_car_segments import get_url as get_comma_segments_url from openpilot.tools.lib.openpilotci import get_url -from openpilot.tools.lib.filereader import FileReader, file_exists, internal_source_available -from openpilot.tools.lib.route import Route, SegmentRange +from openpilot.tools.lib.filereader import DATA_ENDPOINT, FileReader, file_exists, internal_source_available +from openpilot.tools.lib.route import QCAMERA_FILENAMES, CAMERA_FILENAMES, DCAMERA_FILENAMES, \ + ECAMERA_FILENAMES, BOOTLOG_FILENAMES, Route, SegmentRange from openpilot.tools.lib.log_time_series import msgs_to_time_series LogMessage = type[capnp._DynamicStructReader] @@ -96,14 +98,23 @@ class _LogFileReader: class ReadMode(enum.StrEnum): RLOG = "r" # only read rlogs QLOG = "q" # only read qlogs - SANITIZED = "s" # read from the commaCarSegments database AUTO = "a" # default to rlogs, fallback to qlogs AUTO_INTERACTIVE = "i" # default to rlogs, fallback to qlogs with a prompt from the user +class FileName(enum.Enum): + #TODO use the ones from route.py + RLOG = ("rlog.zst", "rlog.bz2") + QLOG = ("qlog.zst", "qlog.bz2") + QCAMERA = QCAMERA_FILENAMES + FCAMERA = CAMERA_FILENAMES + ECAMERA = ECAMERA_FILENAMES + DCAMERA = DCAMERA_FILENAMES + BOOTLOG = BOOTLOG_FILENAMES + + LogPath = str | None -ValidFileCallable = Callable[[LogPath], bool] -Source = Callable[[SegmentRange, ReadMode], list[LogPath]] +Source = Callable[[SegmentRange, FileName], list[LogPath]] InternalUnavailableException = Exception("Internal source not available") @@ -112,139 +123,129 @@ class LogsUnavailable(Exception): pass -@cache -def default_valid_file(fn: LogPath) -> bool: - return fn is not None and file_exists(fn) - - -def auto_strategy(rlog_paths: list[LogPath], qlog_paths: list[LogPath], interactive: bool, valid_file: ValidFileCallable) -> list[LogPath]: - # auto select logs based on availability - missing_rlogs = [rlog is None or not valid_file(rlog) for rlog in rlog_paths].count(True) - if missing_rlogs != 0: - if interactive: - if input(f"{missing_rlogs}/{len(rlog_paths)} rlogs were not found, would you like to fallback to qlogs for those segments? (y/n) ").lower() != "y": - return rlog_paths - else: - cloudlog.warning(f"{missing_rlogs}/{len(rlog_paths)} rlogs were not found, falling back to qlogs for those segments...") - - return [rlog if valid_file(rlog) else (qlog if valid_file(qlog) else None) - for (rlog, qlog) in zip(rlog_paths, qlog_paths, strict=True)] - return rlog_paths - - -def apply_strategy(mode: ReadMode, rlog_paths: list[LogPath], qlog_paths: list[LogPath], valid_file: ValidFileCallable = default_valid_file) -> list[LogPath]: - if mode == ReadMode.RLOG: - return rlog_paths - elif mode == ReadMode.QLOG: - return qlog_paths - elif mode == ReadMode.AUTO: - return auto_strategy(rlog_paths, qlog_paths, False, valid_file) - elif mode == ReadMode.AUTO_INTERACTIVE: - return auto_strategy(rlog_paths, qlog_paths, True, valid_file) - raise ValueError(f"invalid mode: {mode}") - - -def comma_api_source(sr: SegmentRange, mode: ReadMode) -> list[LogPath]: +def comma_api_source(sr: SegmentRange, fns: FileName) -> list[LogPath]: route = Route(sr.route_name) - rlog_paths = [route.log_paths()[seg] for seg in sr.seg_idxs] - qlog_paths = [route.qlog_paths()[seg] for seg in sr.seg_idxs] - # comma api will have already checked if the file exists - def valid_file(fn): - return fn is not None - - return apply_strategy(mode, rlog_paths, qlog_paths, valid_file=valid_file) + if fns == FileName.RLOG: + return [route.log_paths()[seg] for seg in sr.seg_idxs] + else: + return [route.qlog_paths()[seg] for seg in sr.seg_idxs] -def internal_source(sr: SegmentRange, mode: ReadMode, file_ext: str = "bz2") -> list[LogPath]: - if not internal_source_available(): +def internal_source(sr: SegmentRange, fns: FileName, endpoint_url: str = DATA_ENDPOINT) -> list[LogPath]: + if not internal_source_available(endpoint_url): raise InternalUnavailableException def get_internal_url(sr: SegmentRange, seg, file): - return f"cd:/{sr.dongle_id}/{sr.log_id}/{seg}/{file}.{file_ext}" + return f"{endpoint_url.rstrip('/')}/{sr.dongle_id}/{sr.log_id}/{seg}/{file}" - # TODO: list instead of using static URLs to support routes with multiple file extensions - rlog_paths = [get_internal_url(sr, seg, "rlog") for seg in sr.seg_idxs] - qlog_paths = [get_internal_url(sr, seg, "qlog") for seg in sr.seg_idxs] - - return apply_strategy(mode, rlog_paths, qlog_paths) + return eval_source([[get_internal_url(sr, seg, fn) for fn in fns.value] for seg in sr.seg_idxs]) -def internal_source_zst(sr: SegmentRange, mode: ReadMode, file_ext: str = "zst") -> list[LogPath]: - return internal_source(sr, mode, file_ext) +def openpilotci_source(sr: SegmentRange, fns: FileName) -> list[LogPath]: + return eval_source([[get_url(sr.route_name, seg, fn) for fn in fns.value] for seg in sr.seg_idxs]) -def openpilotci_source(sr: SegmentRange, mode: ReadMode, file_ext: str = "bz2") -> list[LogPath]: - rlog_paths = [get_url(sr.route_name, seg, f"rlog.{file_ext}") for seg in sr.seg_idxs] - qlog_paths = [get_url(sr.route_name, seg, f"qlog.{file_ext}") for seg in sr.seg_idxs] - - return apply_strategy(mode, rlog_paths, qlog_paths) +def comma_car_segments_source(sr: SegmentRange, fns: FileName) -> list[LogPath]: + return eval_source([get_comma_segments_url(sr.route_name, seg) for seg in sr.seg_idxs]) -def openpilotci_source_zst(sr: SegmentRange, mode: ReadMode) -> list[LogPath]: - return openpilotci_source(sr, mode, "zst") - - -def comma_car_segments_source(sr: SegmentRange, mode=ReadMode.RLOG) -> list[LogPath]: - return [get_comma_segments_url(sr.route_name, seg) for seg in sr.seg_idxs] - - -def testing_closet_source(sr: SegmentRange, mode=ReadMode.RLOG) -> list[LogPath]: - if not internal_source_available('http://testing.comma.life'): - raise InternalUnavailableException - return [f"http://testing.comma.life/download/{sr.route_name.replace('|', '/')}/{seg}/rlog" for seg in sr.seg_idxs] - - -def direct_source(file_or_url: str) -> list[LogPath]: +def direct_source(file_or_url: str) -> list[str]: return [file_or_url] -def get_invalid_files(files): - for f in files: - if f is None or not file_exists(f): - yield f +def eval_source(files: list[list[str] | str]) -> list[LogPath]: + # Returns valid file URLs given a list of possible file URLs for each segment (e.g. rlog.bz2, rlog.zst) + valid_files: list[LogPath] = [] + + for urls in files: + if isinstance(urls, str): + urls = [urls] + + for url in urls: + if file_exists(url): + valid_files.append(url) + break + else: + valid_files.append(None) + + return valid_files -def check_source(source: Source, *args) -> list[LogPath]: - files = source(*args) - assert len(files) > 0, "No files on source" - assert next(get_invalid_files(files), False) is False, "Some files are invalid" - return files - - -def auto_source(sr: SegmentRange, mode=ReadMode.RLOG, sources: list[Source] = None) -> list[LogPath]: - if mode == ReadMode.SANITIZED: - return comma_car_segments_source(sr, mode) - - if sources is None: - sources = [internal_source, internal_source_zst, openpilotci_source, openpilotci_source_zst, - comma_api_source, comma_car_segments_source, testing_closet_source] +def auto_source(identifier: str, sources: list[Source], default_mode: ReadMode) -> list[str]: exceptions = {} - # for automatic fallback modes, auto_source needs to first check if rlogs exist for any source - if mode in [ReadMode.AUTO, ReadMode.AUTO_INTERACTIVE]: + sr = SegmentRange(identifier) + mode = default_mode if sr.selector is None else ReadMode(sr.selector) + + if mode == ReadMode.QLOG: + try_fns = [FileName.QLOG] + else: + try_fns = [FileName.RLOG] + + # If selector allows it, fallback to qlogs + if mode in (ReadMode.AUTO, ReadMode.AUTO_INTERACTIVE): + try_fns.append(FileName.QLOG) + + # Build a dict of valid files as we evaluate each source. May contain mix of rlogs, qlogs, and None. + # This function only returns when we've sourced all files, or throws an exception + valid_files: dict[int, LogPath] = {} + for fn in try_fns: for source in sources: try: - return check_source(source, sr, ReadMode.RLOG) - except Exception: - pass + files = source(sr, fn) - # Automatically determine viable source - for source in sources: - try: - return check_source(source, sr, mode) - except Exception as e: - exceptions[source.__name__] = e + # Check every source returns an expected number of files + assert len(files) == len(valid_files) or len(valid_files) == 0, f"Source {source.__name__} returned unexpected number of files" - raise LogsUnavailable("auto_source could not find any valid source, exceptions for sources:\n - " + - "\n - ".join([f"{k}: {repr(v)}" for k, v in exceptions.items()])) + # Build a dict of valid files + for idx, f in enumerate(files): + if valid_files.get(idx) is None: + valid_files[idx] = f + + # We've found all files, return them + if all(f is not None for f in valid_files.values()): + return cast(list[str], list(valid_files.values())) + + except Exception as e: + exceptions[source.__name__] = e + + if fn == try_fns[0]: + missing_logs = list(valid_files.values()).count(None) + if mode == ReadMode.AUTO: + cloudlog.warning(f"{missing_logs}/{len(valid_files)} rlogs were not found, falling back to qlogs for those segments...") + elif mode == ReadMode.AUTO_INTERACTIVE: + if input(f"{missing_logs}/{len(valid_files)} rlogs were not found, would you like to fallback to qlogs for those segments? (y/N) ").lower() != "y": + break + + missing_logs = list(valid_files.values()).count(None) + raise LogsUnavailable(f"{missing_logs}/{len(valid_files)} logs were not found, please ensure all logs " + + "are uploaded. You can fall back to qlogs with '/a' selector at the end of the route name.\n\n" + + "Exceptions for sources:\n - " + "\n - ".join([f"{k}: {repr(v)}" for k, v in exceptions.items()])) def parse_indirect(identifier: str) -> str: if "useradmin.comma.ai" in identifier: query = parse_qs(urlparse(identifier).query) - return query["onebox"][0] + identifier = query["onebox"][0] + elif "connect.comma.ai" in identifier: + path = urlparse(identifier).path.strip("/").split("/") + path = ['/'.join(path[:2]), *path[2:]] # recombine log id + + identifier = path[0] + if len(path) > 2: + # convert url with seconds to segments + start, end = int(path[1]) // 60, int(path[2]) // 60 + 1 + identifier = f"{identifier}/{start}:{end}" + + # add selector if it exists + if len(path) > 3: + identifier += f"/{path[3]}" + else: + # add selector if it exists + identifier = "/".join(path) + return identifier @@ -255,7 +256,7 @@ def parse_direct(identifier: str): class LogReader: - def _parse_identifier(self, identifier: str) -> list[LogPath]: + def _parse_identifier(self, identifier: str) -> list[str]: # useradmin, etc. identifier = parse_indirect(identifier) @@ -264,20 +265,16 @@ class LogReader: if direct_parsed is not None: return direct_source(identifier) - sr = SegmentRange(identifier) - mode = self.default_mode if sr.selector is None else ReadMode(sr.selector) - - identifiers = self.source(sr, mode) - - invalid_count = len(list(get_invalid_files(identifiers))) - assert invalid_count == 0, (f"{invalid_count}/{len(identifiers)} invalid log(s) found, please ensure all logs " + - "are uploaded or auto fallback to qlogs with '/a' selector at the end of the route name.") + identifiers = auto_source(identifier, self.sources, self.default_mode) return identifiers def __init__(self, identifier: str | list[str], default_mode: ReadMode = ReadMode.RLOG, - source: Source = auto_source, sort_by_time=False, only_union_types=False): + sources: list[Source] = None, sort_by_time=False, only_union_types=False): + if sources is None: + sources = [internal_source, openpilotci_source, comma_api_source, comma_car_segments_source] + self.default_mode = default_mode - self.source = source + self.sources = sources self.identifier = identifier if isinstance(identifier, str): self.identifier = [identifier] diff --git a/tools/lib/route.py b/tools/lib/route.py index 0a4700f083..55ea956c5f 100644 --- a/tools/lib/route.py +++ b/tools/lib/route.py @@ -10,12 +10,13 @@ from openpilot.tools.lib.auth_config import get_token from openpilot.tools.lib.api import APIError, CommaApi from openpilot.tools.lib.helpers import RE -QLOG_FILENAMES = ['qlog', 'qlog.bz2', 'qlog.zst'] -QCAMERA_FILENAMES = ['qcamera.ts'] -LOG_FILENAMES = ['rlog', 'rlog.bz2', 'raw_log.bz2', 'rlog.zst'] -CAMERA_FILENAMES = ['fcamera.hevc', 'video.hevc'] -DCAMERA_FILENAMES = ['dcamera.hevc'] -ECAMERA_FILENAMES = ['ecamera.hevc'] +QLOG_FILENAMES = ('qlog.bz2', 'qlog.zst', 'qlog') +QCAMERA_FILENAMES = ('qcamera.ts',) +LOG_FILENAMES = ('rlog.bz2', 'raw_log.bz2', 'rlog.zst', 'rlog') +CAMERA_FILENAMES = ('fcamera.hevc', 'video.hevc') +DCAMERA_FILENAMES = ('dcamera.hevc',) +ECAMERA_FILENAMES = ('ecamera.hevc',) +BOOTLOG_FILENAMES = ('bootlog.zst', 'bootlog.bz2', 'bootlog') class Route: @@ -215,12 +216,20 @@ class RouteName: @property def dongle_id(self) -> str: return self._dongle_id + @property + def log_id(self) -> str: return self._time_str + @property def time_str(self) -> str: return self._time_str + @property + def azure_prefix(self): + return f'{self.dongle_id}/{self.log_id}' + def __str__(self) -> str: return self._canonical_name + class SegmentName: # TODO: add constructor that takes dongle_id, time_str, segment_num and then create instances # of this class instead of manually constructing a segment name (use canonical_name prop instead) @@ -241,12 +250,23 @@ class SegmentName: @property def canonical_name(self) -> str: return self._canonical_name + #TODO should only use one name + @property + def data_name(self) -> str: return f"{self._route_name.canonical_name}/{self._num}" + + @property + def azure_prefix(self): + return f'{self.dongle_id}/{self.log_id}/{self._num}' + @property def dongle_id(self) -> str: return self._route_name.dongle_id @property def time_str(self) -> str: return self._route_name.time_str + @property + def log_id(self) -> str: return self._route_name.time_str + @property def segment_num(self) -> int: return self._num @@ -258,6 +278,29 @@ class SegmentName: def __str__(self) -> str: return self._canonical_name + @staticmethod + def from_file_name(file_name): + # ??????/xxxxxxxxxxxxxxxx|1111-11-11-11--11-11-11/1/rlog.bz2 + dongle_id, route_name, segment_num = file_name.replace('|','/').split('/')[-4:-1] + return SegmentName(dongle_id + "|" + route_name + "--" + segment_num) + + @staticmethod + def from_device_key(dongle_id, key): + # 2018-05-07--18-56-13--5/rlog.bz2 + segment_name = key.split('/')[0] + return SegmentName(dongle_id + "|" + segment_name) + + @staticmethod + def from_file_key(key): + # 38c52c217150700f/2018-05-07--18-56-13/5/rlog.bz2 + az_prefix = '/'.join(key.split('/')[:3]) + return SegmentName.from_azure_prefix(az_prefix) + + @staticmethod + def from_azure_prefix(prefix): + # xxxxxxxx/1111-11-11-11--11-11-11/0 + dongle_id, route_name, segment_num = prefix.split("/") + return SegmentName(dongle_id + "|" + route_name + "--" + segment_num) @cache def get_max_seg_number_cached(sr: 'SegmentRange') -> int: @@ -320,3 +363,4 @@ class SegmentRange: def __repr__(self) -> str: return self.__str__() + diff --git a/tools/lib/tests/test_logreader.py b/tools/lib/tests/test_logreader.py index 230b6a65ea..11bdd33ccf 100644 --- a/tools/lib/tests/test_logreader.py +++ b/tools/lib/tests/test_logreader.py @@ -10,7 +10,7 @@ import requests from parameterized import parameterized from cereal import log as capnp_log -from openpilot.tools.lib.logreader import LogIterable, LogReader, comma_api_source, parse_indirect, ReadMode, InternalUnavailableException +from openpilot.tools.lib.logreader import LogsUnavailable, LogIterable, LogReader, comma_api_source, parse_indirect, ReadMode, InternalUnavailableException from openpilot.tools.lib.route import SegmentRange from openpilot.tools.lib.url_file import URLFileException @@ -193,17 +193,17 @@ class TestLogReader: with subtests.test("interactive_yes"): mocker.patch("sys.stdin", new=io.StringIO("y\n")) - lr = LogReader(f"{TEST_ROUTE}/0", default_mode=ReadMode.AUTO_INTERACTIVE, source=comma_api_source) + lr = LogReader(f"{TEST_ROUTE}/0", default_mode=ReadMode.AUTO_INTERACTIVE, sources=[comma_api_source]) log_len = len(list(lr)) assert qlog_len == log_len with subtests.test("interactive_no"): mocker.patch("sys.stdin", new=io.StringIO("n\n")) - with pytest.raises(AssertionError): - lr = LogReader(f"{TEST_ROUTE}/0", default_mode=ReadMode.AUTO_INTERACTIVE, source=comma_api_source) + with pytest.raises(LogsUnavailable): + lr = LogReader(f"{TEST_ROUTE}/0", default_mode=ReadMode.AUTO_INTERACTIVE, sources=[comma_api_source]) with subtests.test("non_interactive"): - lr = LogReader(f"{TEST_ROUTE}/0", default_mode=ReadMode.AUTO, source=comma_api_source) + lr = LogReader(f"{TEST_ROUTE}/0", default_mode=ReadMode.AUTO, sources=[comma_api_source]) log_len = len(list(lr)) assert qlog_len == log_len diff --git a/tools/lib/url_file.py b/tools/lib/url_file.py index b2a11dc77b..204726363d 100644 --- a/tools/lib/url_file.py +++ b/tools/lib/url_file.py @@ -131,13 +131,13 @@ class URLFile: download_range = True if self._debug: - t1 = time.time() + t1 = time.monotonic() response = self._request('GET', self._url, headers=headers) ret = response.data if self._debug: - t2 = time.time() + t2 = time.monotonic() if t2 - t1 > 0.1: print(f"get {self._url} {headers!r} {t2 - t1:.3f} slow") diff --git a/tools/op.sh b/tools/op.sh index 9142d50a18..e83b46b2d2 100755 --- a/tools/op.sh +++ b/tools/op.sh @@ -231,7 +231,7 @@ function op_setup() { echo "Getting git submodules..." st="$(date +%s)" - if ! git submodule update --filter=blob:none --jobs 4 --init --recursive; then + if ! git submodule update --jobs 4 --init --recursive; then echo -e " ↳ [${RED}✗${NC}] Getting git submodules failed!" loge "ERROR_GIT_SUBMODULES" return 1 @@ -287,6 +287,11 @@ function op_adb() { op_run_command tools/scripts/adb_ssh.sh } +function op_ssh() { + op_before_cmd + op_run_command tools/scripts/ssh.py "$@" +} + function op_check() { VERBOSE=1 op_before_cmd @@ -412,6 +417,7 @@ function op_default() { echo -e " ${BOLD}cabana${NC} Run Cabana" echo -e " ${BOLD}clip${NC} Run clip (linux only)" echo -e " ${BOLD}adb${NC} Run adb shell" + echo -e " ${BOLD}ssh${NC} comma prime SSH helper" echo "" echo -e "${BOLD}${UNDERLINE}Commands [Testing]:${NC}" echo -e " ${BOLD}sim${NC} Run openpilot in a simulator" @@ -471,6 +477,7 @@ function _op() { restart ) shift 1; op_restart "$@" ;; post-commit ) shift 1; op_install_post_commit "$@" ;; adb ) shift 1; op_adb "$@" ;; + ssh ) shift 1; op_ssh "$@" ;; * ) op_default "$@" ;; esac } diff --git a/tools/replay/framereader.cc b/tools/replay/framereader.cc index 690645aca9..ed88626be3 100644 --- a/tools/replay/framereader.cc +++ b/tools/replay/framereader.cc @@ -80,7 +80,13 @@ bool FrameReader::loadFromFile(CameraType type, const std::string &file, bool no } input_ctx->probesize = 10 * 1024 * 1024; // 10MB - decoder_ = decoder_manager.acquire(type, input_ctx->streams[0]->codecpar, !no_hw_decoder); + video_stream_idx_ = av_find_best_stream(input_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0); + if (video_stream_idx_ < 0) { + rError("No video stream found in file"); + return false; + } + + decoder_ = decoder_manager.acquire(type, input_ctx->streams[video_stream_idx_]->codecpar, !no_hw_decoder); if (!decoder_) { return false; } @@ -90,7 +96,9 @@ bool FrameReader::loadFromFile(CameraType type, const std::string &file, bool no AVPacket pkt; packets_info.reserve(60 * 20); // 20fps, one minute while (!(abort && *abort) && av_read_frame(input_ctx, &pkt) == 0) { - packets_info.emplace_back(PacketInfo{.flags = pkt.flags, .pos = pkt.pos}); + if (pkt.stream_index == video_stream_idx_) { + packets_info.emplace_back(PacketInfo{.flags = pkt.flags, .pos = pkt.pos}); + } av_packet_unref(&pkt); } avio_seek(input_ctx->pb, 0, SEEK_SET); @@ -168,17 +176,17 @@ bool VideoDecoder::initHardwareDecoder(AVHWDeviceType hw_device_type) { } bool VideoDecoder::decode(FrameReader *reader, int idx, VisionBuf *buf) { - int from_idx = idx; + int current_idx = idx; if (idx != reader->prev_idx + 1) { // seeking to the nearest key frame for (int i = idx; i >= 0; --i) { if (reader->packets_info[i].flags & AV_PKT_FLAG_KEY) { - from_idx = i; + current_idx = i; break; } } - auto pos = reader->packets_info[from_idx].pos; + auto pos = reader->packets_info[current_idx].pos; int ret = avformat_seek_file(reader->input_ctx, 0, pos, pos, pos, AVSEEK_FLAG_BYTE); if (ret < 0) { rError("Failed to seek to byte position %lld: %d", pos, AVERROR(ret)); @@ -188,18 +196,27 @@ bool VideoDecoder::decode(FrameReader *reader, int idx, VisionBuf *buf) { } reader->prev_idx = idx; - bool result = false; AVPacket pkt; - for (int i = from_idx; i <= idx; ++i) { - if (av_read_frame(reader->input_ctx, &pkt) == 0) { - AVFrame *f = decodeFrame(&pkt); - if (f && i == idx) { - result = copyBuffer(f, buf); - } + while (av_read_frame(reader->input_ctx, &pkt) >= 0) { + // Skip non-video packets + if (pkt.stream_index != reader->video_stream_idx_) { av_packet_unref(&pkt); + continue; + } + + AVFrame *frame = decodeFrame(&pkt); + av_packet_unref(&pkt); + if (!frame) { + rError("Failed to decode frame at index %d", current_idx); + return false; + } + + if (current_idx++ == idx) { + return copyBuffer(frame, buf); } } - return result; + rError("Failed to find frame at index %d", idx); + return false; } AVFrame *VideoDecoder::decodeFrame(AVPacket *pkt) { diff --git a/tools/replay/framereader.h b/tools/replay/framereader.h index 03ea5be8b2..a15847e311 100644 --- a/tools/replay/framereader.h +++ b/tools/replay/framereader.h @@ -28,6 +28,7 @@ public: VideoDecoder *decoder_ = nullptr; AVFormatContext *input_ctx = nullptr; + int video_stream_idx_ = -1; int prev_idx = -1; struct PacketInfo { int flags; diff --git a/tools/replay/unlog_ci_segment.py b/tools/replay/unlog_ci_segment.py index 6ddc1b298a..e5a7a3ffde 100755 --- a/tools/replay/unlog_ci_segment.py +++ b/tools/replay/unlog_ci_segment.py @@ -42,7 +42,7 @@ def replay(route, segment, loop): msg = msgs[i].as_builder() next_msg = msgs[i + 1] - start_time = time.time() + start_time = time.monotonic() w = msg.which() if w == 'roadCameraState': @@ -63,7 +63,7 @@ def replay(route, segment, loop): socks[w] = None lag += (next_msg.logMonoTime - msg.logMonoTime) / 1e9 - lag -= time.time() - start_time + lag -= time.monotonic() - start_time dt = max(lag, 0.0) lag -= dt diff --git a/tools/scripts/ssh.py b/tools/scripts/ssh.py new file mode 100755 index 0000000000..0429799a2e --- /dev/null +++ b/tools/scripts/ssh.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python3 +import os +import sys +import argparse +import re + +from openpilot.common.basedir import BASEDIR +from openpilot.tools.lib.auth_config import get_token +from openpilot.tools.lib.api import CommaApi + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="A helper for connecting to devices over the comma prime SSH proxy.\ + Adding your SSH key to your SSH config is recommended for more convenient use; see https://docs.comma.ai/how-to/connect-to-comma/.") + parser.add_argument("device", help="device name or dongle id") + parser.add_argument("--host", help="ssh jump server host", default="ssh.comma.ai") + parser.add_argument("--port", help="ssh jump server port", default=22, type=int) + parser.add_argument("--key", help="ssh key", default=os.path.join(BASEDIR, "system/hardware/tici/id_rsa")) + parser.add_argument("--debug", help="enable debug output", action="store_true") + args = parser.parse_args() + + r = CommaApi(get_token()).get("v1/me/devices") + devices = {x['dongle_id']: x['alias'] for x in r} + + if not re.match("[0-9a-zA-Z]{16}", args.device): + user_input = args.device.replace(" ", "").lower() + matches = { k: v for k, v in devices.items() if isinstance(v, str) and user_input in v.replace(" ", "").lower() } + if len(matches) == 1: + dongle_id = list(matches.keys())[0] + else: + print(f"failed to look up dongle id for \"{args.device}\"", file=sys.stderr) + if len(matches) > 1: + print("found multiple matches:", file=sys.stderr) + for k, v in matches.items(): + print(f" \"{v}\" ({k})", file=sys.stderr) + exit(1) + else: + dongle_id = args.device + + name = dongle_id + if dongle_id in devices: + name = f"{devices[dongle_id]} ({dongle_id})" + print(f"connecting to {name} through {args.host}:{args.port} ...") + + command = [ + "ssh", + "-i", args.key, + "-o", f"ProxyCommand=ssh -i {args.key} -W %h:%p -p %p %h@{args.host}", + "-p", str(args.port), + ] + if args.debug: + command += ["-v"] + command += [ + f"comma@{dongle_id}", + ] + if args.debug: + print(" ".join([f"'{c}'" if " " in c else c for c in command])) + os.execvp(command[0], command) diff --git a/tools/sim/lib/simulated_sensors.py b/tools/sim/lib/simulated_sensors.py index e78f984736..a8374a00cd 100644 --- a/tools/sim/lib/simulated_sensors.py +++ b/tools/sim/lib/simulated_sensors.py @@ -53,7 +53,7 @@ class SimulatedSensors: for _ in range(10): dat = messaging.new_message('gpsLocationExternal', valid=True) dat.gpsLocationExternal = { - "unixTimestampMillis": int(time.time() * 1000), + "unixTimestampMillis": int(time.time() * 1000), # noqa: TID251 "flags": 1, # valid fix "horizontalAccuracy": 1.0, "verticalAccuracy": 1.0, @@ -109,7 +109,7 @@ class SimulatedSensors: self.camerad.cam_send_yuv_wide_road(yuv) def update(self, simulator_state: 'SimulatorState', world: 'World'): - now = time.time() + now = time.monotonic() self.send_imu_message(simulator_state) self.send_gps_message(simulator_state) diff --git a/uv.lock b/uv.lock index 05a6746369..3b8de83bd1 100644 --- a/uv.lock +++ b/uv.lock @@ -1,6 +1,14 @@ version = 1 revision = 2 requires-python = ">=3.11, <3.13" +resolution-markers = [ + "python_full_version >= '3.12' and sys_platform == 'darwin'", + "python_full_version >= '3.12' and platform_machine == 'aarch64' and sys_platform == 'linux'", + "(python_full_version >= '3.12' and platform_machine != 'aarch64' and sys_platform == 'linux') or (python_full_version >= '3.12' and sys_platform != 'darwin' and sys_platform != 'linux')", + "python_full_version < '3.12' and sys_platform == 'darwin'", + "python_full_version < '3.12' and platform_machine == 'aarch64' and sys_platform == 'linux'", + "(python_full_version < '3.12' and platform_machine != 'aarch64' and sys_platform == 'linux') or (python_full_version < '3.12' and sys_platform != 'darwin' and sys_platform != 'linux')", +] [[package]] name = "aiohappyeyeballs" @@ -13,7 +21,7 @@ wheels = [ [[package]] name = "aiohttp" -version = "3.12.14" +version = "3.12.15" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "aiohappyeyeballs" }, @@ -24,42 +32,42 @@ dependencies = [ { name = "propcache" }, { name = "yarl" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/e6/0b/e39ad954107ebf213a2325038a3e7a506be3d98e1435e1f82086eec4cde2/aiohttp-3.12.14.tar.gz", hash = "sha256:6e06e120e34d93100de448fd941522e11dafa78ef1a893c179901b7d66aa29f2", size = 7822921, upload-time = "2025-07-10T13:05:33.968Z" } +sdist = { url = "https://files.pythonhosted.org/packages/9b/e7/d92a237d8802ca88483906c388f7c201bbe96cd80a165ffd0ac2f6a8d59f/aiohttp-3.12.15.tar.gz", hash = "sha256:4fc61385e9c98d72fcdf47e6dd81833f47b2f77c114c29cd64a361be57a763a2", size = 7823716, upload-time = "2025-07-29T05:52:32.215Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/53/e1/8029b29316971c5fa89cec170274582619a01b3d82dd1036872acc9bc7e8/aiohttp-3.12.14-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f4552ff7b18bcec18b60a90c6982049cdb9dac1dba48cf00b97934a06ce2e597", size = 709960, upload-time = "2025-07-10T13:03:11.936Z" }, - { url = "https://files.pythonhosted.org/packages/96/bd/4f204cf1e282041f7b7e8155f846583b19149e0872752711d0da5e9cc023/aiohttp-3.12.14-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8283f42181ff6ccbcf25acaae4e8ab2ff7e92b3ca4a4ced73b2c12d8cd971393", size = 482235, upload-time = "2025-07-10T13:03:14.118Z" }, - { url = "https://files.pythonhosted.org/packages/d6/0f/2a580fcdd113fe2197a3b9df30230c7e85bb10bf56f7915457c60e9addd9/aiohttp-3.12.14-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:040afa180ea514495aaff7ad34ec3d27826eaa5d19812730fe9e529b04bb2179", size = 470501, upload-time = "2025-07-10T13:03:16.153Z" }, - { url = "https://files.pythonhosted.org/packages/38/78/2c1089f6adca90c3dd74915bafed6d6d8a87df5e3da74200f6b3a8b8906f/aiohttp-3.12.14-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b413c12f14c1149f0ffd890f4141a7471ba4b41234fe4fd4a0ff82b1dc299dbb", size = 1740696, upload-time = "2025-07-10T13:03:18.4Z" }, - { url = "https://files.pythonhosted.org/packages/4a/c8/ce6c7a34d9c589f007cfe064da2d943b3dee5aabc64eaecd21faf927ab11/aiohttp-3.12.14-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:1d6f607ce2e1a93315414e3d448b831238f1874b9968e1195b06efaa5c87e245", size = 1689365, upload-time = "2025-07-10T13:03:20.629Z" }, - { url = "https://files.pythonhosted.org/packages/18/10/431cd3d089de700756a56aa896faf3ea82bee39d22f89db7ddc957580308/aiohttp-3.12.14-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:565e70d03e924333004ed101599902bba09ebb14843c8ea39d657f037115201b", size = 1788157, upload-time = "2025-07-10T13:03:22.44Z" }, - { url = "https://files.pythonhosted.org/packages/fa/b2/26f4524184e0f7ba46671c512d4b03022633bcf7d32fa0c6f1ef49d55800/aiohttp-3.12.14-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4699979560728b168d5ab63c668a093c9570af2c7a78ea24ca5212c6cdc2b641", size = 1827203, upload-time = "2025-07-10T13:03:24.628Z" }, - { url = "https://files.pythonhosted.org/packages/e0/30/aadcdf71b510a718e3d98a7bfeaea2396ac847f218b7e8edb241b09bd99a/aiohttp-3.12.14-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad5fdf6af93ec6c99bf800eba3af9a43d8bfd66dce920ac905c817ef4a712afe", size = 1729664, upload-time = "2025-07-10T13:03:26.412Z" }, - { url = "https://files.pythonhosted.org/packages/67/7f/7ccf11756ae498fdedc3d689a0c36ace8fc82f9d52d3517da24adf6e9a74/aiohttp-3.12.14-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4ac76627c0b7ee0e80e871bde0d376a057916cb008a8f3ffc889570a838f5cc7", size = 1666741, upload-time = "2025-07-10T13:03:28.167Z" }, - { url = "https://files.pythonhosted.org/packages/6b/4d/35ebc170b1856dd020c92376dbfe4297217625ef4004d56587024dc2289c/aiohttp-3.12.14-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:798204af1180885651b77bf03adc903743a86a39c7392c472891649610844635", size = 1715013, upload-time = "2025-07-10T13:03:30.018Z" }, - { url = "https://files.pythonhosted.org/packages/7b/24/46dc0380146f33e2e4aa088b92374b598f5bdcde1718c77e8d1a0094f1a4/aiohttp-3.12.14-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:4f1205f97de92c37dd71cf2d5bcfb65fdaed3c255d246172cce729a8d849b4da", size = 1710172, upload-time = "2025-07-10T13:03:31.821Z" }, - { url = "https://files.pythonhosted.org/packages/2f/0a/46599d7d19b64f4d0fe1b57bdf96a9a40b5c125f0ae0d8899bc22e91fdce/aiohttp-3.12.14-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:76ae6f1dd041f85065d9df77c6bc9c9703da9b5c018479d20262acc3df97d419", size = 1690355, upload-time = "2025-07-10T13:03:34.754Z" }, - { url = "https://files.pythonhosted.org/packages/08/86/b21b682e33d5ca317ef96bd21294984f72379454e689d7da584df1512a19/aiohttp-3.12.14-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a194ace7bc43ce765338ca2dfb5661489317db216ea7ea700b0332878b392cab", size = 1783958, upload-time = "2025-07-10T13:03:36.53Z" }, - { url = "https://files.pythonhosted.org/packages/4f/45/f639482530b1396c365f23c5e3b1ae51c9bc02ba2b2248ca0c855a730059/aiohttp-3.12.14-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:16260e8e03744a6fe3fcb05259eeab8e08342c4c33decf96a9dad9f1187275d0", size = 1804423, upload-time = "2025-07-10T13:03:38.504Z" }, - { url = "https://files.pythonhosted.org/packages/7e/e5/39635a9e06eed1d73671bd4079a3caf9cf09a49df08490686f45a710b80e/aiohttp-3.12.14-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8c779e5ebbf0e2e15334ea404fcce54009dc069210164a244d2eac8352a44b28", size = 1717479, upload-time = "2025-07-10T13:03:40.158Z" }, - { url = "https://files.pythonhosted.org/packages/51/e1/7f1c77515d369b7419c5b501196526dad3e72800946c0099594c1f0c20b4/aiohttp-3.12.14-cp311-cp311-win32.whl", hash = "sha256:a289f50bf1bd5be227376c067927f78079a7bdeccf8daa6a9e65c38bae14324b", size = 427907, upload-time = "2025-07-10T13:03:41.801Z" }, - { url = "https://files.pythonhosted.org/packages/06/24/a6bf915c85b7a5b07beba3d42b3282936b51e4578b64a51e8e875643c276/aiohttp-3.12.14-cp311-cp311-win_amd64.whl", hash = "sha256:0b8a69acaf06b17e9c54151a6c956339cf46db4ff72b3ac28516d0f7068f4ced", size = 452334, upload-time = "2025-07-10T13:03:43.485Z" }, - { url = "https://files.pythonhosted.org/packages/c3/0d/29026524e9336e33d9767a1e593ae2b24c2b8b09af7c2bd8193762f76b3e/aiohttp-3.12.14-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a0ecbb32fc3e69bc25efcda7d28d38e987d007096cbbeed04f14a6662d0eee22", size = 701055, upload-time = "2025-07-10T13:03:45.59Z" }, - { url = "https://files.pythonhosted.org/packages/0a/b8/a5e8e583e6c8c1056f4b012b50a03c77a669c2e9bf012b7cf33d6bc4b141/aiohttp-3.12.14-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0400f0ca9bb3e0b02f6466421f253797f6384e9845820c8b05e976398ac1d81a", size = 475670, upload-time = "2025-07-10T13:03:47.249Z" }, - { url = "https://files.pythonhosted.org/packages/29/e8/5202890c9e81a4ec2c2808dd90ffe024952e72c061729e1d49917677952f/aiohttp-3.12.14-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a56809fed4c8a830b5cae18454b7464e1529dbf66f71c4772e3cfa9cbec0a1ff", size = 468513, upload-time = "2025-07-10T13:03:49.377Z" }, - { url = "https://files.pythonhosted.org/packages/23/e5/d11db8c23d8923d3484a27468a40737d50f05b05eebbb6288bafcb467356/aiohttp-3.12.14-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27f2e373276e4755691a963e5d11756d093e346119f0627c2d6518208483fb6d", size = 1715309, upload-time = "2025-07-10T13:03:51.556Z" }, - { url = "https://files.pythonhosted.org/packages/53/44/af6879ca0eff7a16b1b650b7ea4a827301737a350a464239e58aa7c387ef/aiohttp-3.12.14-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ca39e433630e9a16281125ef57ece6817afd1d54c9f1bf32e901f38f16035869", size = 1697961, upload-time = "2025-07-10T13:03:53.511Z" }, - { url = "https://files.pythonhosted.org/packages/bb/94/18457f043399e1ec0e59ad8674c0372f925363059c276a45a1459e17f423/aiohttp-3.12.14-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9c748b3f8b14c77720132b2510a7d9907a03c20ba80f469e58d5dfd90c079a1c", size = 1753055, upload-time = "2025-07-10T13:03:55.368Z" }, - { url = "https://files.pythonhosted.org/packages/26/d9/1d3744dc588fafb50ff8a6226d58f484a2242b5dd93d8038882f55474d41/aiohttp-3.12.14-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0a568abe1b15ce69d4cc37e23020720423f0728e3cb1f9bcd3f53420ec3bfe7", size = 1799211, upload-time = "2025-07-10T13:03:57.216Z" }, - { url = "https://files.pythonhosted.org/packages/73/12/2530fb2b08773f717ab2d249ca7a982ac66e32187c62d49e2c86c9bba9b4/aiohttp-3.12.14-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9888e60c2c54eaf56704b17feb558c7ed6b7439bca1e07d4818ab878f2083660", size = 1718649, upload-time = "2025-07-10T13:03:59.469Z" }, - { url = "https://files.pythonhosted.org/packages/b9/34/8d6015a729f6571341a311061b578e8b8072ea3656b3d72329fa0faa2c7c/aiohttp-3.12.14-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3006a1dc579b9156de01e7916d38c63dc1ea0679b14627a37edf6151bc530088", size = 1634452, upload-time = "2025-07-10T13:04:01.698Z" }, - { url = "https://files.pythonhosted.org/packages/ff/4b/08b83ea02595a582447aeb0c1986792d0de35fe7a22fb2125d65091cbaf3/aiohttp-3.12.14-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:aa8ec5c15ab80e5501a26719eb48a55f3c567da45c6ea5bb78c52c036b2655c7", size = 1695511, upload-time = "2025-07-10T13:04:04.165Z" }, - { url = "https://files.pythonhosted.org/packages/b5/66/9c7c31037a063eec13ecf1976185c65d1394ded4a5120dd5965e3473cb21/aiohttp-3.12.14-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:39b94e50959aa07844c7fe2206b9f75d63cc3ad1c648aaa755aa257f6f2498a9", size = 1716967, upload-time = "2025-07-10T13:04:06.132Z" }, - { url = "https://files.pythonhosted.org/packages/ba/02/84406e0ad1acb0fb61fd617651ab6de760b2d6a31700904bc0b33bd0894d/aiohttp-3.12.14-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:04c11907492f416dad9885d503fbfc5dcb6768d90cad8639a771922d584609d3", size = 1657620, upload-time = "2025-07-10T13:04:07.944Z" }, - { url = "https://files.pythonhosted.org/packages/07/53/da018f4013a7a179017b9a274b46b9a12cbeb387570f116964f498a6f211/aiohttp-3.12.14-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:88167bd9ab69bb46cee91bd9761db6dfd45b6e76a0438c7e884c3f8160ff21eb", size = 1737179, upload-time = "2025-07-10T13:04:10.182Z" }, - { url = "https://files.pythonhosted.org/packages/49/e8/ca01c5ccfeaafb026d85fa4f43ceb23eb80ea9c1385688db0ef322c751e9/aiohttp-3.12.14-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:791504763f25e8f9f251e4688195e8b455f8820274320204f7eafc467e609425", size = 1765156, upload-time = "2025-07-10T13:04:12.029Z" }, - { url = "https://files.pythonhosted.org/packages/22/32/5501ab525a47ba23c20613e568174d6c63aa09e2caa22cded5c6ea8e3ada/aiohttp-3.12.14-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2785b112346e435dd3a1a67f67713a3fe692d288542f1347ad255683f066d8e0", size = 1724766, upload-time = "2025-07-10T13:04:13.961Z" }, - { url = "https://files.pythonhosted.org/packages/06/af/28e24574801fcf1657945347ee10df3892311c2829b41232be6089e461e7/aiohttp-3.12.14-cp312-cp312-win32.whl", hash = "sha256:15f5f4792c9c999a31d8decf444e79fcfd98497bf98e94284bf390a7bb8c1729", size = 422641, upload-time = "2025-07-10T13:04:16.018Z" }, - { url = "https://files.pythonhosted.org/packages/98/d5/7ac2464aebd2eecac38dbe96148c9eb487679c512449ba5215d233755582/aiohttp-3.12.14-cp312-cp312-win_amd64.whl", hash = "sha256:3b66e1a182879f579b105a80d5c4bd448b91a57e8933564bf41665064796a338", size = 449316, upload-time = "2025-07-10T13:04:18.289Z" }, + { url = "https://files.pythonhosted.org/packages/20/19/9e86722ec8e835959bd97ce8c1efa78cf361fa4531fca372551abcc9cdd6/aiohttp-3.12.15-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d3ce17ce0220383a0f9ea07175eeaa6aa13ae5a41f30bc61d84df17f0e9b1117", size = 711246, upload-time = "2025-07-29T05:50:15.937Z" }, + { url = "https://files.pythonhosted.org/packages/71/f9/0a31fcb1a7d4629ac9d8f01f1cb9242e2f9943f47f5d03215af91c3c1a26/aiohttp-3.12.15-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:010cc9bbd06db80fe234d9003f67e97a10fe003bfbedb40da7d71c1008eda0fe", size = 483515, upload-time = "2025-07-29T05:50:17.442Z" }, + { url = "https://files.pythonhosted.org/packages/62/6c/94846f576f1d11df0c2e41d3001000527c0fdf63fce7e69b3927a731325d/aiohttp-3.12.15-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3f9d7c55b41ed687b9d7165b17672340187f87a773c98236c987f08c858145a9", size = 471776, upload-time = "2025-07-29T05:50:19.568Z" }, + { url = "https://files.pythonhosted.org/packages/f8/6c/f766d0aaafcee0447fad0328da780d344489c042e25cd58fde566bf40aed/aiohttp-3.12.15-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bc4fbc61bb3548d3b482f9ac7ddd0f18c67e4225aaa4e8552b9f1ac7e6bda9e5", size = 1741977, upload-time = "2025-07-29T05:50:21.665Z" }, + { url = "https://files.pythonhosted.org/packages/17/e5/fb779a05ba6ff44d7bc1e9d24c644e876bfff5abe5454f7b854cace1b9cc/aiohttp-3.12.15-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7fbc8a7c410bb3ad5d595bb7118147dfbb6449d862cc1125cf8867cb337e8728", size = 1690645, upload-time = "2025-07-29T05:50:23.333Z" }, + { url = "https://files.pythonhosted.org/packages/37/4e/a22e799c2035f5d6a4ad2cf8e7c1d1bd0923192871dd6e367dafb158b14c/aiohttp-3.12.15-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:74dad41b3458dbb0511e760fb355bb0b6689e0630de8a22b1b62a98777136e16", size = 1789437, upload-time = "2025-07-29T05:50:25.007Z" }, + { url = "https://files.pythonhosted.org/packages/28/e5/55a33b991f6433569babb56018b2fb8fb9146424f8b3a0c8ecca80556762/aiohttp-3.12.15-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3b6f0af863cf17e6222b1735a756d664159e58855da99cfe965134a3ff63b0b0", size = 1828482, upload-time = "2025-07-29T05:50:26.693Z" }, + { url = "https://files.pythonhosted.org/packages/c6/82/1ddf0ea4f2f3afe79dffed5e8a246737cff6cbe781887a6a170299e33204/aiohttp-3.12.15-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b5b7fe4972d48a4da367043b8e023fb70a04d1490aa7d68800e465d1b97e493b", size = 1730944, upload-time = "2025-07-29T05:50:28.382Z" }, + { url = "https://files.pythonhosted.org/packages/1b/96/784c785674117b4cb3877522a177ba1b5e4db9ce0fd519430b5de76eec90/aiohttp-3.12.15-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6443cca89553b7a5485331bc9bedb2342b08d073fa10b8c7d1c60579c4a7b9bd", size = 1668020, upload-time = "2025-07-29T05:50:30.032Z" }, + { url = "https://files.pythonhosted.org/packages/12/8a/8b75f203ea7e5c21c0920d84dd24a5c0e971fe1e9b9ebbf29ae7e8e39790/aiohttp-3.12.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6c5f40ec615e5264f44b4282ee27628cea221fcad52f27405b80abb346d9f3f8", size = 1716292, upload-time = "2025-07-29T05:50:31.983Z" }, + { url = "https://files.pythonhosted.org/packages/47/0b/a1451543475bb6b86a5cfc27861e52b14085ae232896a2654ff1231c0992/aiohttp-3.12.15-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:2abbb216a1d3a2fe86dbd2edce20cdc5e9ad0be6378455b05ec7f77361b3ab50", size = 1711451, upload-time = "2025-07-29T05:50:33.989Z" }, + { url = "https://files.pythonhosted.org/packages/55/fd/793a23a197cc2f0d29188805cfc93aa613407f07e5f9da5cd1366afd9d7c/aiohttp-3.12.15-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:db71ce547012a5420a39c1b744d485cfb823564d01d5d20805977f5ea1345676", size = 1691634, upload-time = "2025-07-29T05:50:35.846Z" }, + { url = "https://files.pythonhosted.org/packages/ca/bf/23a335a6670b5f5dfc6d268328e55a22651b440fca341a64fccf1eada0c6/aiohttp-3.12.15-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:ced339d7c9b5030abad5854aa5413a77565e5b6e6248ff927d3e174baf3badf7", size = 1785238, upload-time = "2025-07-29T05:50:37.597Z" }, + { url = "https://files.pythonhosted.org/packages/57/4f/ed60a591839a9d85d40694aba5cef86dde9ee51ce6cca0bb30d6eb1581e7/aiohttp-3.12.15-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:7c7dd29c7b5bda137464dc9bfc738d7ceea46ff70309859ffde8c022e9b08ba7", size = 1805701, upload-time = "2025-07-29T05:50:39.591Z" }, + { url = "https://files.pythonhosted.org/packages/85/e0/444747a9455c5de188c0f4a0173ee701e2e325d4b2550e9af84abb20cdba/aiohttp-3.12.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:421da6fd326460517873274875c6c5a18ff225b40da2616083c5a34a7570b685", size = 1718758, upload-time = "2025-07-29T05:50:41.292Z" }, + { url = "https://files.pythonhosted.org/packages/36/ab/1006278d1ffd13a698e5dd4bfa01e5878f6bddefc296c8b62649753ff249/aiohttp-3.12.15-cp311-cp311-win32.whl", hash = "sha256:4420cf9d179ec8dfe4be10e7d0fe47d6d606485512ea2265b0d8c5113372771b", size = 428868, upload-time = "2025-07-29T05:50:43.063Z" }, + { url = "https://files.pythonhosted.org/packages/10/97/ad2b18700708452400278039272032170246a1bf8ec5d832772372c71f1a/aiohttp-3.12.15-cp311-cp311-win_amd64.whl", hash = "sha256:edd533a07da85baa4b423ee8839e3e91681c7bfa19b04260a469ee94b778bf6d", size = 453273, upload-time = "2025-07-29T05:50:44.613Z" }, + { url = "https://files.pythonhosted.org/packages/63/97/77cb2450d9b35f517d6cf506256bf4f5bda3f93a66b4ad64ba7fc917899c/aiohttp-3.12.15-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:802d3868f5776e28f7bf69d349c26fc0efadb81676d0afa88ed00d98a26340b7", size = 702333, upload-time = "2025-07-29T05:50:46.507Z" }, + { url = "https://files.pythonhosted.org/packages/83/6d/0544e6b08b748682c30b9f65640d006e51f90763b41d7c546693bc22900d/aiohttp-3.12.15-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f2800614cd560287be05e33a679638e586a2d7401f4ddf99e304d98878c29444", size = 476948, upload-time = "2025-07-29T05:50:48.067Z" }, + { url = "https://files.pythonhosted.org/packages/3a/1d/c8c40e611e5094330284b1aea8a4b02ca0858f8458614fa35754cab42b9c/aiohttp-3.12.15-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8466151554b593909d30a0a125d638b4e5f3836e5aecde85b66b80ded1cb5b0d", size = 469787, upload-time = "2025-07-29T05:50:49.669Z" }, + { url = "https://files.pythonhosted.org/packages/38/7d/b76438e70319796bfff717f325d97ce2e9310f752a267bfdf5192ac6082b/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e5a495cb1be69dae4b08f35a6c4579c539e9b5706f606632102c0f855bcba7c", size = 1716590, upload-time = "2025-07-29T05:50:51.368Z" }, + { url = "https://files.pythonhosted.org/packages/79/b1/60370d70cdf8b269ee1444b390cbd72ce514f0d1cd1a715821c784d272c9/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6404dfc8cdde35c69aaa489bb3542fb86ef215fc70277c892be8af540e5e21c0", size = 1699241, upload-time = "2025-07-29T05:50:53.628Z" }, + { url = "https://files.pythonhosted.org/packages/a3/2b/4968a7b8792437ebc12186db31523f541943e99bda8f30335c482bea6879/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3ead1c00f8521a5c9070fcb88f02967b1d8a0544e6d85c253f6968b785e1a2ab", size = 1754335, upload-time = "2025-07-29T05:50:55.394Z" }, + { url = "https://files.pythonhosted.org/packages/fb/c1/49524ed553f9a0bec1a11fac09e790f49ff669bcd14164f9fab608831c4d/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6990ef617f14450bc6b34941dba4f12d5613cbf4e33805932f853fbd1cf18bfb", size = 1800491, upload-time = "2025-07-29T05:50:57.202Z" }, + { url = "https://files.pythonhosted.org/packages/de/5e/3bf5acea47a96a28c121b167f5ef659cf71208b19e52a88cdfa5c37f1fcc/aiohttp-3.12.15-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd736ed420f4db2b8148b52b46b88ed038d0354255f9a73196b7bbce3ea97545", size = 1719929, upload-time = "2025-07-29T05:50:59.192Z" }, + { url = "https://files.pythonhosted.org/packages/39/94/8ae30b806835bcd1cba799ba35347dee6961a11bd507db634516210e91d8/aiohttp-3.12.15-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c5092ce14361a73086b90c6efb3948ffa5be2f5b6fbcf52e8d8c8b8848bb97c", size = 1635733, upload-time = "2025-07-29T05:51:01.394Z" }, + { url = "https://files.pythonhosted.org/packages/7a/46/06cdef71dd03acd9da7f51ab3a9107318aee12ad38d273f654e4f981583a/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:aaa2234bb60c4dbf82893e934d8ee8dea30446f0647e024074237a56a08c01bd", size = 1696790, upload-time = "2025-07-29T05:51:03.657Z" }, + { url = "https://files.pythonhosted.org/packages/02/90/6b4cfaaf92ed98d0ec4d173e78b99b4b1a7551250be8937d9d67ecb356b4/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:6d86a2fbdd14192e2f234a92d3b494dd4457e683ba07e5905a0b3ee25389ac9f", size = 1718245, upload-time = "2025-07-29T05:51:05.911Z" }, + { url = "https://files.pythonhosted.org/packages/2e/e6/2593751670fa06f080a846f37f112cbe6f873ba510d070136a6ed46117c6/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a041e7e2612041a6ddf1c6a33b883be6a421247c7afd47e885969ee4cc58bd8d", size = 1658899, upload-time = "2025-07-29T05:51:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/8f/28/c15bacbdb8b8eb5bf39b10680d129ea7410b859e379b03190f02fa104ffd/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:5015082477abeafad7203757ae44299a610e89ee82a1503e3d4184e6bafdd519", size = 1738459, upload-time = "2025-07-29T05:51:09.56Z" }, + { url = "https://files.pythonhosted.org/packages/00/de/c269cbc4faa01fb10f143b1670633a8ddd5b2e1ffd0548f7aa49cb5c70e2/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:56822ff5ddfd1b745534e658faba944012346184fbfe732e0d6134b744516eea", size = 1766434, upload-time = "2025-07-29T05:51:11.423Z" }, + { url = "https://files.pythonhosted.org/packages/52/b0/4ff3abd81aa7d929b27d2e1403722a65fc87b763e3a97b3a2a494bfc63bc/aiohttp-3.12.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b2acbbfff69019d9014508c4ba0401822e8bae5a5fdc3b6814285b71231b60f3", size = 1726045, upload-time = "2025-07-29T05:51:13.689Z" }, + { url = "https://files.pythonhosted.org/packages/71/16/949225a6a2dd6efcbd855fbd90cf476052e648fb011aa538e3b15b89a57a/aiohttp-3.12.15-cp312-cp312-win32.whl", hash = "sha256:d849b0901b50f2185874b9a232f38e26b9b3d4810095a7572eacea939132d4e1", size = 423591, upload-time = "2025-07-29T05:51:15.452Z" }, + { url = "https://files.pythonhosted.org/packages/2b/d8/fa65d2a349fe938b76d309db1a56a75c4fb8cc7b17a398b698488a939903/aiohttp-3.12.15-cp312-cp312-win_amd64.whl", hash = "sha256:b390ef5f62bb508a9d67cb3bba9b8356e23b3996da7062f1a57ce1a79d2b3d34", size = 450266, upload-time = "2025-07-29T05:51:17.239Z" }, ] [[package]] @@ -471,7 +479,7 @@ version = "0.2" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "python-xlib", marker = "sys_platform == 'linux'" }, - { name = "typing-extensions" }, + { name = "typing-extensions", marker = "sys_platform != 'darwin'" }, ] wheels = [ { url = "https://files.pythonhosted.org/packages/2f/3a/46ca34abf0725a754bc44ef474ad34aedcc3ea23b052d97b18b76715a6a9/EWMHlib-0.2-py3-none-any.whl", hash = "sha256:f5b07d8cfd4c7734462ee744c32d490f2f3233fa7ab354240069344208d2f6f5", size = 46657, upload-time = "2024-04-17T08:15:56.338Z" }, @@ -756,24 +764,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/94/6d/344a164d32d65d503ffe9201cd74cf13a020099dc446554d1e50b07f167b/libusb1-3.3.1-py3-none-win_amd64.whl", hash = "sha256:6e21b772d80d6487fbb55d3d2141218536db302da82f1983754e96c72781c102", size = 141080, upload-time = "2025-03-24T05:36:46.594Z" }, ] -[[package]] -name = "llvmlite" -version = "0.44.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/89/6a/95a3d3610d5c75293d5dbbb2a76480d5d4eeba641557b69fe90af6c5b84e/llvmlite-0.44.0.tar.gz", hash = "sha256:07667d66a5d150abed9157ab6c0b9393c9356f229784a4385c02f99e94fc94d4", size = 171880, upload-time = "2025-01-20T11:14:41.342Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b5/e2/86b245397052386595ad726f9742e5223d7aea999b18c518a50e96c3aca4/llvmlite-0.44.0-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:eed7d5f29136bda63b6d7804c279e2b72e08c952b7c5df61f45db408e0ee52f3", size = 28132305, upload-time = "2025-01-20T11:12:53.936Z" }, - { url = "https://files.pythonhosted.org/packages/ff/ec/506902dc6870249fbe2466d9cf66d531265d0f3a1157213c8f986250c033/llvmlite-0.44.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ace564d9fa44bb91eb6e6d8e7754977783c68e90a471ea7ce913bff30bd62427", size = 26201090, upload-time = "2025-01-20T11:12:59.847Z" }, - { url = "https://files.pythonhosted.org/packages/99/fe/d030f1849ebb1f394bb3f7adad5e729b634fb100515594aca25c354ffc62/llvmlite-0.44.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c5d22c3bfc842668168a786af4205ec8e3ad29fb1bc03fd11fd48460d0df64c1", size = 42361858, upload-time = "2025-01-20T11:13:07.623Z" }, - { url = "https://files.pythonhosted.org/packages/d7/7a/ce6174664b9077fc673d172e4c888cb0b128e707e306bc33fff8c2035f0d/llvmlite-0.44.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f01a394e9c9b7b1d4e63c327b096d10f6f0ed149ef53d38a09b3749dcf8c9610", size = 41184200, upload-time = "2025-01-20T11:13:20.058Z" }, - { url = "https://files.pythonhosted.org/packages/5f/c6/258801143975a6d09a373f2641237992496e15567b907a4d401839d671b8/llvmlite-0.44.0-cp311-cp311-win_amd64.whl", hash = "sha256:d8489634d43c20cd0ad71330dde1d5bc7b9966937a263ff1ec1cebb90dc50955", size = 30331193, upload-time = "2025-01-20T11:13:26.976Z" }, - { url = "https://files.pythonhosted.org/packages/15/86/e3c3195b92e6e492458f16d233e58a1a812aa2bfbef9bdd0fbafcec85c60/llvmlite-0.44.0-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:1d671a56acf725bf1b531d5ef76b86660a5ab8ef19bb6a46064a705c6ca80aad", size = 28132297, upload-time = "2025-01-20T11:13:32.57Z" }, - { url = "https://files.pythonhosted.org/packages/d6/53/373b6b8be67b9221d12b24125fd0ec56b1078b660eeae266ec388a6ac9a0/llvmlite-0.44.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5f79a728e0435493611c9f405168682bb75ffd1fbe6fc360733b850c80a026db", size = 26201105, upload-time = "2025-01-20T11:13:38.744Z" }, - { url = "https://files.pythonhosted.org/packages/cb/da/8341fd3056419441286c8e26bf436923021005ece0bff5f41906476ae514/llvmlite-0.44.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0143a5ef336da14deaa8ec26c5449ad5b6a2b564df82fcef4be040b9cacfea9", size = 42361901, upload-time = "2025-01-20T11:13:46.711Z" }, - { url = "https://files.pythonhosted.org/packages/53/ad/d79349dc07b8a395a99153d7ce8b01d6fcdc9f8231355a5df55ded649b61/llvmlite-0.44.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d752f89e31b66db6f8da06df8b39f9b91e78c5feea1bf9e8c1fba1d1c24c065d", size = 41184247, upload-time = "2025-01-20T11:13:56.159Z" }, - { url = "https://files.pythonhosted.org/packages/e2/3b/a9a17366af80127bd09decbe2a54d8974b6d8b274b39bf47fbaedeec6307/llvmlite-0.44.0-cp312-cp312-win_amd64.whl", hash = "sha256:eae7e2d4ca8f88f89d315b48c6b741dcb925d6a1042da694aa16ab3dd4cbd3a1", size = 30332380, upload-time = "2025-01-20T11:14:02.442Z" }, -] - [[package]] name = "lxml" version = "6.0.0" @@ -1118,30 +1108,39 @@ wheels = [ [[package]] name = "numpy" -version = "2.1.3" +version = "2.3.2" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/25/ca/1166b75c21abd1da445b97bf1fa2f14f423c6cfb4fc7c4ef31dccf9f6a94/numpy-2.1.3.tar.gz", hash = "sha256:aa08e04e08aaf974d4458def539dece0d28146d866a39da5639596f4921fd761", size = 20166090, upload-time = "2024-11-02T17:48:55.832Z" } +sdist = { url = "https://files.pythonhosted.org/packages/37/7d/3fec4199c5ffb892bed55cff901e4f39a58c81df9c44c280499e92cad264/numpy-2.3.2.tar.gz", hash = "sha256:e0486a11ec30cdecb53f184d496d1c6a20786c81e55e41640270130056f8ee48", size = 20489306, upload-time = "2025-07-24T21:32:07.553Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/ad/81/c8167192eba5247593cd9d305ac236847c2912ff39e11402e72ae28a4985/numpy-2.1.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4d1167c53b93f1f5d8a139a742b3c6f4d429b54e74e6b57d0eff40045187b15d", size = 21156252, upload-time = "2024-11-02T17:34:01.372Z" }, - { url = "https://files.pythonhosted.org/packages/da/74/5a60003fc3d8a718d830b08b654d0eea2d2db0806bab8f3c2aca7e18e010/numpy-2.1.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c80e4a09b3d95b4e1cac08643f1152fa71a0a821a2d4277334c88d54b2219a41", size = 13784119, upload-time = "2024-11-02T17:34:23.809Z" }, - { url = "https://files.pythonhosted.org/packages/47/7c/864cb966b96fce5e63fcf25e1e4d957fe5725a635e5f11fe03f39dd9d6b5/numpy-2.1.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:576a1c1d25e9e02ed7fa5477f30a127fe56debd53b8d2c89d5578f9857d03ca9", size = 5352978, upload-time = "2024-11-02T17:34:34.001Z" }, - { url = "https://files.pythonhosted.org/packages/09/ac/61d07930a4993dd9691a6432de16d93bbe6aa4b1c12a5e573d468eefc1ca/numpy-2.1.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:973faafebaae4c0aaa1a1ca1ce02434554d67e628b8d805e61f874b84e136b09", size = 6892570, upload-time = "2024-11-02T17:34:45.401Z" }, - { url = "https://files.pythonhosted.org/packages/27/2f/21b94664f23af2bb52030653697c685022119e0dc93d6097c3cb45bce5f9/numpy-2.1.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:762479be47a4863e261a840e8e01608d124ee1361e48b96916f38b119cfda04a", size = 13896715, upload-time = "2024-11-02T17:35:06.564Z" }, - { url = "https://files.pythonhosted.org/packages/7a/f0/80811e836484262b236c684a75dfc4ba0424bc670e765afaa911468d9f39/numpy-2.1.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc6f24b3d1ecc1eebfbf5d6051faa49af40b03be1aaa781ebdadcbc090b4539b", size = 16339644, upload-time = "2024-11-02T17:35:30.888Z" }, - { url = "https://files.pythonhosted.org/packages/fa/81/ce213159a1ed8eb7d88a2a6ef4fbdb9e4ffd0c76b866c350eb4e3c37e640/numpy-2.1.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:17ee83a1f4fef3c94d16dc1802b998668b5419362c8a4f4e8a491de1b41cc3ee", size = 16712217, upload-time = "2024-11-02T17:35:56.703Z" }, - { url = "https://files.pythonhosted.org/packages/7d/84/4de0b87d5a72f45556b2a8ee9fc8801e8518ec867fc68260c1f5dcb3903f/numpy-2.1.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:15cb89f39fa6d0bdfb600ea24b250e5f1a3df23f901f51c8debaa6a5d122b2f0", size = 14399053, upload-time = "2024-11-02T17:36:22.3Z" }, - { url = "https://files.pythonhosted.org/packages/7e/1c/e5fabb9ad849f9d798b44458fd12a318d27592d4bc1448e269dec070ff04/numpy-2.1.3-cp311-cp311-win32.whl", hash = "sha256:d9beb777a78c331580705326d2367488d5bc473b49a9bc3036c154832520aca9", size = 6534741, upload-time = "2024-11-02T17:36:33.552Z" }, - { url = "https://files.pythonhosted.org/packages/1e/48/a9a4b538e28f854bfb62e1dea3c8fea12e90216a276c7777ae5345ff29a7/numpy-2.1.3-cp311-cp311-win_amd64.whl", hash = "sha256:d89dd2b6da69c4fff5e39c28a382199ddedc3a5be5390115608345dec660b9e2", size = 12869487, upload-time = "2024-11-02T17:36:52.909Z" }, - { url = "https://files.pythonhosted.org/packages/8a/f0/385eb9970309643cbca4fc6eebc8bb16e560de129c91258dfaa18498da8b/numpy-2.1.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f55ba01150f52b1027829b50d70ef1dafd9821ea82905b63936668403c3b471e", size = 20849658, upload-time = "2024-11-02T17:37:23.919Z" }, - { url = "https://files.pythonhosted.org/packages/54/4a/765b4607f0fecbb239638d610d04ec0a0ded9b4951c56dc68cef79026abf/numpy-2.1.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:13138eadd4f4da03074851a698ffa7e405f41a0845a6b1ad135b81596e4e9958", size = 13492258, upload-time = "2024-11-02T17:37:45.252Z" }, - { url = "https://files.pythonhosted.org/packages/bd/a7/2332679479c70b68dccbf4a8eb9c9b5ee383164b161bee9284ac141fbd33/numpy-2.1.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:a6b46587b14b888e95e4a24d7b13ae91fa22386c199ee7b418f449032b2fa3b8", size = 5090249, upload-time = "2024-11-02T17:37:54.252Z" }, - { url = "https://files.pythonhosted.org/packages/c1/67/4aa00316b3b981a822c7a239d3a8135be2a6945d1fd11d0efb25d361711a/numpy-2.1.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:0fa14563cc46422e99daef53d725d0c326e99e468a9320a240affffe87852564", size = 6621704, upload-time = "2024-11-02T17:38:05.127Z" }, - { url = "https://files.pythonhosted.org/packages/5e/da/1a429ae58b3b6c364eeec93bf044c532f2ff7b48a52e41050896cf15d5b1/numpy-2.1.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8637dcd2caa676e475503d1f8fdb327bc495554e10838019651b76d17b98e512", size = 13606089, upload-time = "2024-11-02T17:38:25.997Z" }, - { url = "https://files.pythonhosted.org/packages/9e/3e/3757f304c704f2f0294a6b8340fcf2be244038be07da4cccf390fa678a9f/numpy-2.1.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2312b2aa89e1f43ecea6da6ea9a810d06aae08321609d8dc0d0eda6d946a541b", size = 16043185, upload-time = "2024-11-02T17:38:51.07Z" }, - { url = "https://files.pythonhosted.org/packages/43/97/75329c28fea3113d00c8d2daf9bc5828d58d78ed661d8e05e234f86f0f6d/numpy-2.1.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a38c19106902bb19351b83802531fea19dee18e5b37b36454f27f11ff956f7fc", size = 16410751, upload-time = "2024-11-02T17:39:15.801Z" }, - { url = "https://files.pythonhosted.org/packages/ad/7a/442965e98b34e0ae9da319f075b387bcb9a1e0658276cc63adb8c9686f7b/numpy-2.1.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:02135ade8b8a84011cbb67dc44e07c58f28575cf9ecf8ab304e51c05528c19f0", size = 14082705, upload-time = "2024-11-02T17:39:38.274Z" }, - { url = "https://files.pythonhosted.org/packages/ac/b6/26108cf2cfa5c7e03fb969b595c93131eab4a399762b51ce9ebec2332e80/numpy-2.1.3-cp312-cp312-win32.whl", hash = "sha256:e6988e90fcf617da2b5c78902fe8e668361b43b4fe26dbf2d7b0f8034d4cafb9", size = 6239077, upload-time = "2024-11-02T17:39:49.299Z" }, - { url = "https://files.pythonhosted.org/packages/a6/84/fa11dad3404b7634aaab50733581ce11e5350383311ea7a7010f464c0170/numpy-2.1.3-cp312-cp312-win_amd64.whl", hash = "sha256:0d30c543f02e84e92c4b1f415b7c6b5326cbe45ee7882b6b77db7195fb971e3a", size = 12566858, upload-time = "2024-11-02T17:40:08.851Z" }, + { url = "https://files.pythonhosted.org/packages/96/26/1320083986108998bd487e2931eed2aeedf914b6e8905431487543ec911d/numpy-2.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:852ae5bed3478b92f093e30f785c98e0cb62fa0a939ed057c31716e18a7a22b9", size = 21259016, upload-time = "2025-07-24T20:24:35.214Z" }, + { url = "https://files.pythonhosted.org/packages/c4/2b/792b341463fa93fc7e55abbdbe87dac316c5b8cb5e94fb7a59fb6fa0cda5/numpy-2.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7a0e27186e781a69959d0230dd9909b5e26024f8da10683bd6344baea1885168", size = 14451158, upload-time = "2025-07-24T20:24:58.397Z" }, + { url = "https://files.pythonhosted.org/packages/b7/13/e792d7209261afb0c9f4759ffef6135b35c77c6349a151f488f531d13595/numpy-2.3.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:f0a1a8476ad77a228e41619af2fa9505cf69df928e9aaa165746584ea17fed2b", size = 5379817, upload-time = "2025-07-24T20:25:07.746Z" }, + { url = "https://files.pythonhosted.org/packages/49/ce/055274fcba4107c022b2113a213c7287346563f48d62e8d2a5176ad93217/numpy-2.3.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:cbc95b3813920145032412f7e33d12080f11dc776262df1712e1638207dde9e8", size = 6913606, upload-time = "2025-07-24T20:25:18.84Z" }, + { url = "https://files.pythonhosted.org/packages/17/f2/e4d72e6bc5ff01e2ab613dc198d560714971900c03674b41947e38606502/numpy-2.3.2-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f75018be4980a7324edc5930fe39aa391d5734531b1926968605416ff58c332d", size = 14589652, upload-time = "2025-07-24T20:25:40.356Z" }, + { url = "https://files.pythonhosted.org/packages/c8/b0/fbeee3000a51ebf7222016e2939b5c5ecf8000a19555d04a18f1e02521b8/numpy-2.3.2-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20b8200721840f5621b7bd03f8dcd78de33ec522fc40dc2641aa09537df010c3", size = 16938816, upload-time = "2025-07-24T20:26:05.721Z" }, + { url = "https://files.pythonhosted.org/packages/a9/ec/2f6c45c3484cc159621ea8fc000ac5a86f1575f090cac78ac27193ce82cd/numpy-2.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f91e5c028504660d606340a084db4b216567ded1056ea2b4be4f9d10b67197f", size = 16370512, upload-time = "2025-07-24T20:26:30.545Z" }, + { url = "https://files.pythonhosted.org/packages/b5/01/dd67cf511850bd7aefd6347aaae0956ed415abea741ae107834aae7d6d4e/numpy-2.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:fb1752a3bb9a3ad2d6b090b88a9a0ae1cd6f004ef95f75825e2f382c183b2097", size = 18884947, upload-time = "2025-07-24T20:26:58.24Z" }, + { url = "https://files.pythonhosted.org/packages/a7/17/2cf60fd3e6a61d006778735edf67a222787a8c1a7842aed43ef96d777446/numpy-2.3.2-cp311-cp311-win32.whl", hash = "sha256:4ae6863868aaee2f57503c7a5052b3a2807cf7a3914475e637a0ecd366ced220", size = 6599494, upload-time = "2025-07-24T20:27:09.786Z" }, + { url = "https://files.pythonhosted.org/packages/d5/03/0eade211c504bda872a594f045f98ddcc6caef2b7c63610946845e304d3f/numpy-2.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:240259d6564f1c65424bcd10f435145a7644a65a6811cfc3201c4a429ba79170", size = 13087889, upload-time = "2025-07-24T20:27:29.558Z" }, + { url = "https://files.pythonhosted.org/packages/13/32/2c7979d39dafb2a25087e12310fc7f3b9d3c7d960df4f4bc97955ae0ce1d/numpy-2.3.2-cp311-cp311-win_arm64.whl", hash = "sha256:4209f874d45f921bde2cff1ffcd8a3695f545ad2ffbef6d3d3c6768162efab89", size = 10459560, upload-time = "2025-07-24T20:27:46.803Z" }, + { url = "https://files.pythonhosted.org/packages/00/6d/745dd1c1c5c284d17725e5c802ca4d45cfc6803519d777f087b71c9f4069/numpy-2.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:bc3186bea41fae9d8e90c2b4fb5f0a1f5a690682da79b92574d63f56b529080b", size = 20956420, upload-time = "2025-07-24T20:28:18.002Z" }, + { url = "https://files.pythonhosted.org/packages/bc/96/e7b533ea5740641dd62b07a790af5d9d8fec36000b8e2d0472bd7574105f/numpy-2.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2f4f0215edb189048a3c03bd5b19345bdfa7b45a7a6f72ae5945d2a28272727f", size = 14184660, upload-time = "2025-07-24T20:28:39.522Z" }, + { url = "https://files.pythonhosted.org/packages/2b/53/102c6122db45a62aa20d1b18c9986f67e6b97e0d6fbc1ae13e3e4c84430c/numpy-2.3.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:8b1224a734cd509f70816455c3cffe13a4f599b1bf7130f913ba0e2c0b2006c0", size = 5113382, upload-time = "2025-07-24T20:28:48.544Z" }, + { url = "https://files.pythonhosted.org/packages/2b/21/376257efcbf63e624250717e82b4fae93d60178f09eb03ed766dbb48ec9c/numpy-2.3.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:3dcf02866b977a38ba3ec10215220609ab9667378a9e2150615673f3ffd6c73b", size = 6647258, upload-time = "2025-07-24T20:28:59.104Z" }, + { url = "https://files.pythonhosted.org/packages/91/ba/f4ebf257f08affa464fe6036e13f2bf9d4642a40228781dc1235da81be9f/numpy-2.3.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:572d5512df5470f50ada8d1972c5f1082d9a0b7aa5944db8084077570cf98370", size = 14281409, upload-time = "2025-07-24T20:40:30.298Z" }, + { url = "https://files.pythonhosted.org/packages/59/ef/f96536f1df42c668cbacb727a8c6da7afc9c05ece6d558927fb1722693e1/numpy-2.3.2-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8145dd6d10df13c559d1e4314df29695613575183fa2e2d11fac4c208c8a1f73", size = 16641317, upload-time = "2025-07-24T20:40:56.625Z" }, + { url = "https://files.pythonhosted.org/packages/f6/a7/af813a7b4f9a42f498dde8a4c6fcbff8100eed00182cc91dbaf095645f38/numpy-2.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:103ea7063fa624af04a791c39f97070bf93b96d7af7eb23530cd087dc8dbe9dc", size = 16056262, upload-time = "2025-07-24T20:41:20.797Z" }, + { url = "https://files.pythonhosted.org/packages/8b/5d/41c4ef8404caaa7f05ed1cfb06afe16a25895260eacbd29b4d84dff2920b/numpy-2.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fc927d7f289d14f5e037be917539620603294454130b6de200091e23d27dc9be", size = 18579342, upload-time = "2025-07-24T20:41:50.753Z" }, + { url = "https://files.pythonhosted.org/packages/a1/4f/9950e44c5a11636f4a3af6e825ec23003475cc9a466edb7a759ed3ea63bd/numpy-2.3.2-cp312-cp312-win32.whl", hash = "sha256:d95f59afe7f808c103be692175008bab926b59309ade3e6d25009e9a171f7036", size = 6320610, upload-time = "2025-07-24T20:42:01.551Z" }, + { url = "https://files.pythonhosted.org/packages/7c/2f/244643a5ce54a94f0a9a2ab578189c061e4a87c002e037b0829dd77293b6/numpy-2.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:9e196ade2400c0c737d93465327d1ae7c06c7cb8a1756121ebf54b06ca183c7f", size = 12786292, upload-time = "2025-07-24T20:42:20.738Z" }, + { url = "https://files.pythonhosted.org/packages/54/cd/7b5f49d5d78db7badab22d8323c1b6ae458fbf86c4fdfa194ab3cd4eb39b/numpy-2.3.2-cp312-cp312-win_arm64.whl", hash = "sha256:ee807923782faaf60d0d7331f5e86da7d5e3079e28b291973c545476c2b00d07", size = 10194071, upload-time = "2025-07-24T20:42:36.657Z" }, + { url = "https://files.pythonhosted.org/packages/cf/ea/50ebc91d28b275b23b7128ef25c3d08152bc4068f42742867e07a870a42a/numpy-2.3.2-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:14a91ebac98813a49bc6aa1a0dfc09513dcec1d97eaf31ca21a87221a1cdcb15", size = 21130338, upload-time = "2025-07-24T20:57:54.37Z" }, + { url = "https://files.pythonhosted.org/packages/9f/57/cdd5eac00dd5f137277355c318a955c0d8fb8aa486020c22afd305f8b88f/numpy-2.3.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:71669b5daae692189540cffc4c439468d35a3f84f0c88b078ecd94337f6cb0ec", size = 14375776, upload-time = "2025-07-24T20:58:16.303Z" }, + { url = "https://files.pythonhosted.org/packages/83/85/27280c7f34fcd305c2209c0cdca4d70775e4859a9eaa92f850087f8dea50/numpy-2.3.2-pp311-pypy311_pp73-macosx_14_0_arm64.whl", hash = "sha256:69779198d9caee6e547adb933941ed7520f896fd9656834c300bdf4dd8642712", size = 5304882, upload-time = "2025-07-24T20:58:26.199Z" }, + { url = "https://files.pythonhosted.org/packages/48/b4/6500b24d278e15dd796f43824e69939d00981d37d9779e32499e823aa0aa/numpy-2.3.2-pp311-pypy311_pp73-macosx_14_0_x86_64.whl", hash = "sha256:2c3271cc4097beb5a60f010bcc1cc204b300bb3eafb4399376418a83a1c6373c", size = 6818405, upload-time = "2025-07-24T20:58:37.341Z" }, + { url = "https://files.pythonhosted.org/packages/9b/c9/142c1e03f199d202da8e980c2496213509291b6024fd2735ad28ae7065c7/numpy-2.3.2-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8446acd11fe3dc1830568c941d44449fd5cb83068e5c70bd5a470d323d448296", size = 14419651, upload-time = "2025-07-24T20:58:59.048Z" }, + { url = "https://files.pythonhosted.org/packages/8b/95/8023e87cbea31a750a6c00ff9427d65ebc5fef104a136bfa69f76266d614/numpy-2.3.2-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:aa098a5ab53fa407fded5870865c6275a5cd4101cfdef8d6fafc48286a96e981", size = 16760166, upload-time = "2025-07-24T21:28:56.38Z" }, + { url = "https://files.pythonhosted.org/packages/78/e3/6690b3f85a05506733c7e90b577e4762517404ea78bab2ca3a5cb1aeb78d/numpy-2.3.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:6936aff90dda378c09bea075af0d9c675fe3a977a9d2402f95a87f440f59f619", size = 12977811, upload-time = "2025-07-24T21:29:18.234Z" }, ] [[package]] @@ -1171,19 +1170,19 @@ wheels = [ [[package]] name = "opencv-python-headless" -version = "4.12.0.88" +version = "4.11.0.86" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/a4/63/6861102ec149c3cd298f4d1ea7ce9d6adbc7529221606ff1dab991a19adb/opencv-python-headless-4.12.0.88.tar.gz", hash = "sha256:cfdc017ddf2e59b6c2f53bc12d74b6b0be7ded4ec59083ea70763921af2b6c09", size = 95379675, upload-time = "2025-07-07T09:21:06.815Z" } +sdist = { url = "https://files.pythonhosted.org/packages/36/2f/5b2b3ba52c864848885ba988f24b7f105052f68da9ab0e693cc7c25b0b30/opencv-python-headless-4.11.0.86.tar.gz", hash = "sha256:996eb282ca4b43ec6a3972414de0e2331f5d9cda2b41091a49739c19fb843798", size = 95177929, upload-time = "2025-01-16T13:53:40.22Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f7/7d/414e243c5c8216a5277afd104a319cc1291c5e23f5eeef512db5629ee7f4/opencv_python_headless-4.12.0.88-cp37-abi3-macosx_13_0_arm64.whl", hash = "sha256:1e58d664809b3350c1123484dd441e1667cd7bed3086db1b9ea1b6f6cb20b50e", size = 37877864, upload-time = "2025-07-07T09:14:41.693Z" }, - { url = "https://files.pythonhosted.org/packages/05/14/7e162714beed1cd5e7b5eb66fcbcba2f065c51b1d9da2463024c84d2f7c0/opencv_python_headless-4.12.0.88-cp37-abi3-macosx_13_0_x86_64.whl", hash = "sha256:365bb2e486b50feffc2d07a405b953a8f3e8eaa63865bc650034e5c71e7a5154", size = 57326608, upload-time = "2025-07-07T09:14:51.885Z" }, - { url = "https://files.pythonhosted.org/packages/69/4e/116720df7f1f7f3b59abc608ca30fbec9d2b3ae810afe4e4d26483d9dfa0/opencv_python_headless-4.12.0.88-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:aeb4b13ecb8b4a0beb2668ea07928160ea7c2cd2d9b5ef571bbee6bafe9cc8d0", size = 33145800, upload-time = "2025-07-07T09:15:00.367Z" }, - { url = "https://files.pythonhosted.org/packages/89/53/e19c21e0c4eb1275c3e2c97b081103b6dfb3938172264d283a519bf728b9/opencv_python_headless-4.12.0.88-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:236c8df54a90f4d02076e6f9c1cc763d794542e886c576a6fee46ec8ff75a7a9", size = 54023419, upload-time = "2025-07-07T09:15:10.164Z" }, - { url = "https://files.pythonhosted.org/packages/bf/9c/a76fd5414de6ec9f21f763a600058a0c3e290053cea87e0275692b1375c0/opencv_python_headless-4.12.0.88-cp37-abi3-win32.whl", hash = "sha256:fde2cf5c51e4def5f2132d78e0c08f9c14783cd67356922182c6845b9af87dbd", size = 30225230, upload-time = "2025-07-07T09:15:17.045Z" }, - { url = "https://files.pythonhosted.org/packages/f2/35/0858e9e71b36948eafbc5e835874b63e515179dc3b742cbe3d76bc683439/opencv_python_headless-4.12.0.88-cp37-abi3-win_amd64.whl", hash = "sha256:86b413bdd6c6bf497832e346cd5371995de148e579b9774f8eba686dee3f5528", size = 38923559, upload-time = "2025-07-07T09:15:25.229Z" }, + { url = "https://files.pythonhosted.org/packages/dc/53/2c50afa0b1e05ecdb4603818e85f7d174e683d874ef63a6abe3ac92220c8/opencv_python_headless-4.11.0.86-cp37-abi3-macosx_13_0_arm64.whl", hash = "sha256:48128188ade4a7e517237c8e1e11a9cdf5c282761473383e77beb875bb1e61ca", size = 37326460, upload-time = "2025-01-16T13:52:57.015Z" }, + { url = "https://files.pythonhosted.org/packages/3b/43/68555327df94bb9b59a1fd645f63fafb0762515344d2046698762fc19d58/opencv_python_headless-4.11.0.86-cp37-abi3-macosx_13_0_x86_64.whl", hash = "sha256:a66c1b286a9de872c343ee7c3553b084244299714ebb50fbdcd76f07ebbe6c81", size = 56723330, upload-time = "2025-01-16T13:55:45.731Z" }, + { url = "https://files.pythonhosted.org/packages/45/be/1438ce43ebe65317344a87e4b150865c5585f4c0db880a34cdae5ac46881/opencv_python_headless-4.11.0.86-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6efabcaa9df731f29e5ea9051776715b1bdd1845d7c9530065c7951d2a2899eb", size = 29487060, upload-time = "2025-01-16T13:51:59.625Z" }, + { url = "https://files.pythonhosted.org/packages/dd/5c/c139a7876099916879609372bfa513b7f1257f7f1a908b0bdc1c2328241b/opencv_python_headless-4.11.0.86-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e0a27c19dd1f40ddff94976cfe43066fbbe9dfbb2ec1907d66c19caef42a57b", size = 49969856, upload-time = "2025-01-16T13:53:29.654Z" }, + { url = "https://files.pythonhosted.org/packages/95/dd/ed1191c9dc91abcc9f752b499b7928aacabf10567bb2c2535944d848af18/opencv_python_headless-4.11.0.86-cp37-abi3-win32.whl", hash = "sha256:f447d8acbb0b6f2808da71fddd29c1cdd448d2bc98f72d9bb78a7a898fc9621b", size = 29324425, upload-time = "2025-01-16T13:52:49.048Z" }, + { url = "https://files.pythonhosted.org/packages/86/8a/69176a64335aed183529207ba8bc3d329c2999d852b4f3818027203f50e6/opencv_python_headless-4.11.0.86-cp37-abi3-win_amd64.whl", hash = "sha256:6c304df9caa7a6a5710b91709dd4786bf20a74d57672b3c31f7033cc638174ca", size = 39402386, upload-time = "2025-01-16T13:52:56.418Z" }, ] [[package]] @@ -1201,7 +1200,6 @@ dependencies = [ { name = "inputs" }, { name = "json-rpc" }, { name = "libusb1" }, - { name = "llvmlite" }, { name = "numpy" }, { name = "onnx" }, { name = "psutil" }, @@ -1272,7 +1270,6 @@ testing = [ ] tools = [ { name = "metadrive-simulator", marker = "platform_machine != 'aarch64'" }, - { name = "rerun-sdk" }, ] [package.metadata] @@ -1295,13 +1292,12 @@ requires-dist = [ { name = "jinja2", marker = "extra == 'docs'" }, { name = "json-rpc" }, { name = "libusb1" }, - { name = "llvmlite" }, { name = "matplotlib", marker = "extra == 'dev'" }, { name = "metadrive-simulator", marker = "platform_machine != 'aarch64' and extra == 'tools'", url = "https://github.com/commaai/metadrive/releases/download/MetaDrive-minimal-0.4.2.4/metadrive_simulator-0.4.2.4-py3-none-any.whl" }, { name = "mkdocs", marker = "extra == 'docs'" }, { name = "mypy", marker = "extra == 'testing'" }, { name = "natsort", marker = "extra == 'docs'" }, - { name = "numpy", specifier = ">=2.0,<2.2" }, + { name = "numpy", specifier = ">=2.0" }, { name = "onnx", specifier = ">=1.14.0" }, { name = "opencv-python-headless", marker = "extra == 'dev'" }, { name = "parameterized", marker = "extra == 'dev'", specifier = ">=0.8,<0.9" }, @@ -1325,14 +1321,13 @@ requires-dist = [ { name = "pytest-repeat", marker = "extra == 'testing'" }, { name = "pytest-subtests", marker = "extra == 'testing'" }, { name = "pytest-timeout", marker = "extra == 'testing'" }, - { name = "pytest-xdist", marker = "extra == 'testing'", git = "https://github.com/sshane/pytest-xdist?rev=909e97b49d12401c10608f9d777bfc9dab8a4413" }, + { name = "pytest-xdist", marker = "extra == 'testing'", git = "https://github.com/sshane/pytest-xdist?rev=2b4372bd62699fb412c4fe2f95bf9f01bd2018da" }, { name = "pytools", marker = "platform_machine != 'aarch64' and extra == 'dev'", specifier = "<2024.1.11" }, { name = "pywinctl", marker = "extra == 'dev'" }, { name = "pyzmq" }, { name = "qrcode" }, { name = "raylib", marker = "extra == 'dev'" }, { name = "requests" }, - { name = "rerun-sdk", marker = "extra == 'tools'", specifier = ">=0.18" }, { name = "ruff", marker = "extra == 'testing'" }, { name = "scons" }, { name = "sentry-sdk" }, @@ -1566,28 +1561,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/50/1b/6921afe68c74868b4c9fa424dad3be35b095e16687989ebbb50ce4fceb7c/psutil-7.0.0-cp37-abi3-win_amd64.whl", hash = "sha256:4cf3d4eb1aa9b348dec30105c55cd9b7d4629285735a102beb4441e38db90553", size = 244885, upload-time = "2025-02-13T21:54:37.486Z" }, ] -[[package]] -name = "pyarrow" -version = "21.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ef/c2/ea068b8f00905c06329a3dfcd40d0fcc2b7d0f2e355bdb25b65e0a0e4cd4/pyarrow-21.0.0.tar.gz", hash = "sha256:5051f2dccf0e283ff56335760cbc8622cf52264d67e359d5569541ac11b6d5bc", size = 1133487, upload-time = "2025-07-18T00:57:31.761Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/94/dc/80564a3071a57c20b7c32575e4a0120e8a330ef487c319b122942d665960/pyarrow-21.0.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:c077f48aab61738c237802836fc3844f85409a46015635198761b0d6a688f87b", size = 31243234, upload-time = "2025-07-18T00:55:03.812Z" }, - { url = "https://files.pythonhosted.org/packages/ea/cc/3b51cb2db26fe535d14f74cab4c79b191ed9a8cd4cbba45e2379b5ca2746/pyarrow-21.0.0-cp311-cp311-macosx_12_0_x86_64.whl", hash = "sha256:689f448066781856237eca8d1975b98cace19b8dd2ab6145bf49475478bcaa10", size = 32714370, upload-time = "2025-07-18T00:55:07.495Z" }, - { url = "https://files.pythonhosted.org/packages/24/11/a4431f36d5ad7d83b87146f515c063e4d07ef0b7240876ddb885e6b44f2e/pyarrow-21.0.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:479ee41399fcddc46159a551705b89c05f11e8b8cb8e968f7fec64f62d91985e", size = 41135424, upload-time = "2025-07-18T00:55:11.461Z" }, - { url = "https://files.pythonhosted.org/packages/74/dc/035d54638fc5d2971cbf1e987ccd45f1091c83bcf747281cf6cc25e72c88/pyarrow-21.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:40ebfcb54a4f11bcde86bc586cbd0272bac0d516cfa539c799c2453768477569", size = 42823810, upload-time = "2025-07-18T00:55:16.301Z" }, - { url = "https://files.pythonhosted.org/packages/2e/3b/89fced102448a9e3e0d4dded1f37fa3ce4700f02cdb8665457fcc8015f5b/pyarrow-21.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8d58d8497814274d3d20214fbb24abcad2f7e351474357d552a8d53bce70c70e", size = 43391538, upload-time = "2025-07-18T00:55:23.82Z" }, - { url = "https://files.pythonhosted.org/packages/fb/bb/ea7f1bd08978d39debd3b23611c293f64a642557e8141c80635d501e6d53/pyarrow-21.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:585e7224f21124dd57836b1530ac8f2df2afc43c861d7bf3d58a4870c42ae36c", size = 45120056, upload-time = "2025-07-18T00:55:28.231Z" }, - { url = "https://files.pythonhosted.org/packages/6e/0b/77ea0600009842b30ceebc3337639a7380cd946061b620ac1a2f3cb541e2/pyarrow-21.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:555ca6935b2cbca2c0e932bedd853e9bc523098c39636de9ad4693b5b1df86d6", size = 26220568, upload-time = "2025-07-18T00:55:32.122Z" }, - { url = "https://files.pythonhosted.org/packages/ca/d4/d4f817b21aacc30195cf6a46ba041dd1be827efa4a623cc8bf39a1c2a0c0/pyarrow-21.0.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:3a302f0e0963db37e0a24a70c56cf91a4faa0bca51c23812279ca2e23481fccd", size = 31160305, upload-time = "2025-07-18T00:55:35.373Z" }, - { url = "https://files.pythonhosted.org/packages/a2/9c/dcd38ce6e4b4d9a19e1d36914cb8e2b1da4e6003dd075474c4cfcdfe0601/pyarrow-21.0.0-cp312-cp312-macosx_12_0_x86_64.whl", hash = "sha256:b6b27cf01e243871390474a211a7922bfbe3bda21e39bc9160daf0da3fe48876", size = 32684264, upload-time = "2025-07-18T00:55:39.303Z" }, - { url = "https://files.pythonhosted.org/packages/4f/74/2a2d9f8d7a59b639523454bec12dba35ae3d0a07d8ab529dc0809f74b23c/pyarrow-21.0.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:e72a8ec6b868e258a2cd2672d91f2860ad532d590ce94cdf7d5e7ec674ccf03d", size = 41108099, upload-time = "2025-07-18T00:55:42.889Z" }, - { url = "https://files.pythonhosted.org/packages/ad/90/2660332eeb31303c13b653ea566a9918484b6e4d6b9d2d46879a33ab0622/pyarrow-21.0.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:b7ae0bbdc8c6674259b25bef5d2a1d6af5d39d7200c819cf99e07f7dfef1c51e", size = 42829529, upload-time = "2025-07-18T00:55:47.069Z" }, - { url = "https://files.pythonhosted.org/packages/33/27/1a93a25c92717f6aa0fca06eb4700860577d016cd3ae51aad0e0488ac899/pyarrow-21.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:58c30a1729f82d201627c173d91bd431db88ea74dcaa3885855bc6203e433b82", size = 43367883, upload-time = "2025-07-18T00:55:53.069Z" }, - { url = "https://files.pythonhosted.org/packages/05/d9/4d09d919f35d599bc05c6950095e358c3e15148ead26292dfca1fb659b0c/pyarrow-21.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:072116f65604b822a7f22945a7a6e581cfa28e3454fdcc6939d4ff6090126623", size = 45133802, upload-time = "2025-07-18T00:55:57.714Z" }, - { url = "https://files.pythonhosted.org/packages/71/30/f3795b6e192c3ab881325ffe172e526499eb3780e306a15103a2764916a2/pyarrow-21.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:cf56ec8b0a5c8c9d7021d6fd754e688104f9ebebf1bf4449613c9531f5346a18", size = 26203175, upload-time = "2025-07-18T00:56:01.364Z" }, -] - [[package]] name = "pyaudio" version = "0.2.14" @@ -1793,164 +1766,164 @@ name = "pyobjc" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-accessibility", marker = "platform_release >= '20.0'" }, - { name = "pyobjc-framework-accounts", marker = "platform_release >= '12.0'" }, - { name = "pyobjc-framework-addressbook" }, - { name = "pyobjc-framework-adservices", marker = "platform_release >= '20.0'" }, - { name = "pyobjc-framework-adsupport", marker = "platform_release >= '18.0'" }, - { name = "pyobjc-framework-applescriptkit" }, - { name = "pyobjc-framework-applescriptobjc", marker = "platform_release >= '10.0'" }, - { name = "pyobjc-framework-applicationservices" }, - { name = "pyobjc-framework-apptrackingtransparency", marker = "platform_release >= '20.0'" }, - { name = "pyobjc-framework-audiovideobridging", marker = "platform_release >= '12.0'" }, - { name = "pyobjc-framework-authenticationservices", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-automaticassessmentconfiguration", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-automator" }, - { name = "pyobjc-framework-avfoundation", marker = "platform_release >= '11.0'" }, - { name = "pyobjc-framework-avkit", marker = "platform_release >= '13.0'" }, - { name = "pyobjc-framework-avrouting", marker = "platform_release >= '22.0'" }, - { name = "pyobjc-framework-backgroundassets", marker = "platform_release >= '22.0'" }, - { name = "pyobjc-framework-browserenginekit", marker = "platform_release >= '23.4'" }, - { name = "pyobjc-framework-businesschat", marker = "platform_release >= '18.0'" }, - { name = "pyobjc-framework-calendarstore", marker = "platform_release >= '9.0'" }, - { name = "pyobjc-framework-callkit", marker = "platform_release >= '20.0'" }, - { name = "pyobjc-framework-carbon" }, - { name = "pyobjc-framework-cfnetwork" }, - { name = "pyobjc-framework-cinematic", marker = "platform_release >= '23.0'" }, - { name = "pyobjc-framework-classkit", marker = "platform_release >= '20.0'" }, - { name = "pyobjc-framework-cloudkit", marker = "platform_release >= '14.0'" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-collaboration", marker = "platform_release >= '9.0'" }, - { name = "pyobjc-framework-colorsync", marker = "platform_release >= '17.0'" }, - { name = "pyobjc-framework-contacts", marker = "platform_release >= '15.0'" }, - { name = "pyobjc-framework-contactsui", marker = "platform_release >= '15.0'" }, - { name = "pyobjc-framework-coreaudio" }, - { name = "pyobjc-framework-coreaudiokit" }, - { name = "pyobjc-framework-corebluetooth", marker = "platform_release >= '14.0'" }, - { name = "pyobjc-framework-coredata" }, - { name = "pyobjc-framework-corehaptics", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-corelocation", marker = "platform_release >= '10.0'" }, - { name = "pyobjc-framework-coremedia", marker = "platform_release >= '11.0'" }, - { name = "pyobjc-framework-coremediaio", marker = "platform_release >= '11.0'" }, - { name = "pyobjc-framework-coremidi" }, - { name = "pyobjc-framework-coreml", marker = "platform_release >= '17.0'" }, - { name = "pyobjc-framework-coremotion", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-coreservices" }, - { name = "pyobjc-framework-corespotlight", marker = "platform_release >= '17.0'" }, - { name = "pyobjc-framework-coretext" }, - { name = "pyobjc-framework-corewlan", marker = "platform_release >= '10.0'" }, - { name = "pyobjc-framework-cryptotokenkit", marker = "platform_release >= '14.0'" }, - { name = "pyobjc-framework-datadetection", marker = "platform_release >= '21.0'" }, - { name = "pyobjc-framework-devicecheck", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-devicediscoveryextension", marker = "platform_release >= '24.0'" }, - { name = "pyobjc-framework-dictionaryservices", marker = "platform_release >= '9.0'" }, - { name = "pyobjc-framework-discrecording" }, - { name = "pyobjc-framework-discrecordingui" }, - { name = "pyobjc-framework-diskarbitration" }, - { name = "pyobjc-framework-dvdplayback" }, - { name = "pyobjc-framework-eventkit", marker = "platform_release >= '12.0'" }, - { name = "pyobjc-framework-exceptionhandling" }, - { name = "pyobjc-framework-executionpolicy", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-extensionkit", marker = "platform_release >= '22.0'" }, - { name = "pyobjc-framework-externalaccessory", marker = "platform_release >= '17.0'" }, - { name = "pyobjc-framework-fileprovider", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-fileproviderui", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-findersync", marker = "platform_release >= '14.0'" }, - { name = "pyobjc-framework-fsevents", marker = "platform_release >= '9.0'" }, - { name = "pyobjc-framework-fskit", marker = "platform_release >= '24.4'" }, - { name = "pyobjc-framework-gamecenter", marker = "platform_release >= '12.0'" }, - { name = "pyobjc-framework-gamecontroller", marker = "platform_release >= '13.0'" }, - { name = "pyobjc-framework-gamekit", marker = "platform_release >= '12.0'" }, - { name = "pyobjc-framework-gameplaykit", marker = "platform_release >= '15.0'" }, - { name = "pyobjc-framework-healthkit", marker = "platform_release >= '22.0'" }, - { name = "pyobjc-framework-imagecapturecore", marker = "platform_release >= '10.0'" }, - { name = "pyobjc-framework-inputmethodkit", marker = "platform_release >= '9.0'" }, - { name = "pyobjc-framework-installerplugins" }, - { name = "pyobjc-framework-instantmessage", marker = "platform_release >= '9.0'" }, - { name = "pyobjc-framework-intents", marker = "platform_release >= '16.0'" }, - { name = "pyobjc-framework-intentsui", marker = "platform_release >= '21.0'" }, - { name = "pyobjc-framework-iobluetooth" }, - { name = "pyobjc-framework-iobluetoothui" }, - { name = "pyobjc-framework-iosurface", marker = "platform_release >= '10.0'" }, - { name = "pyobjc-framework-ituneslibrary", marker = "platform_release >= '10.0'" }, - { name = "pyobjc-framework-kernelmanagement", marker = "platform_release >= '20.0'" }, - { name = "pyobjc-framework-latentsemanticmapping" }, - { name = "pyobjc-framework-launchservices" }, - { name = "pyobjc-framework-libdispatch", marker = "platform_release >= '12.0'" }, - { name = "pyobjc-framework-libxpc", marker = "platform_release >= '12.0'" }, - { name = "pyobjc-framework-linkpresentation", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-localauthentication", marker = "platform_release >= '14.0'" }, - { name = "pyobjc-framework-localauthenticationembeddedui", marker = "platform_release >= '21.0'" }, - { name = "pyobjc-framework-mailkit", marker = "platform_release >= '21.0'" }, - { name = "pyobjc-framework-mapkit", marker = "platform_release >= '13.0'" }, - { name = "pyobjc-framework-mediaaccessibility", marker = "platform_release >= '13.0'" }, - { name = "pyobjc-framework-mediaextension", marker = "platform_release >= '24.0'" }, - { name = "pyobjc-framework-medialibrary", marker = "platform_release >= '13.0'" }, - { name = "pyobjc-framework-mediaplayer", marker = "platform_release >= '16.0'" }, - { name = "pyobjc-framework-mediatoolbox", marker = "platform_release >= '13.0'" }, - { name = "pyobjc-framework-metal", marker = "platform_release >= '15.0'" }, - { name = "pyobjc-framework-metalfx", marker = "platform_release >= '22.0'" }, - { name = "pyobjc-framework-metalkit", marker = "platform_release >= '15.0'" }, - { name = "pyobjc-framework-metalperformanceshaders", marker = "platform_release >= '17.0'" }, - { name = "pyobjc-framework-metalperformanceshadersgraph", marker = "platform_release >= '20.0'" }, - { name = "pyobjc-framework-metrickit", marker = "platform_release >= '21.0'" }, - { name = "pyobjc-framework-mlcompute", marker = "platform_release >= '20.0'" }, - { name = "pyobjc-framework-modelio", marker = "platform_release >= '15.0'" }, - { name = "pyobjc-framework-multipeerconnectivity", marker = "platform_release >= '14.0'" }, - { name = "pyobjc-framework-naturallanguage", marker = "platform_release >= '18.0'" }, - { name = "pyobjc-framework-netfs", marker = "platform_release >= '10.0'" }, - { name = "pyobjc-framework-network", marker = "platform_release >= '18.0'" }, - { name = "pyobjc-framework-networkextension", marker = "platform_release >= '15.0'" }, - { name = "pyobjc-framework-notificationcenter", marker = "platform_release >= '14.0'" }, - { name = "pyobjc-framework-opendirectory", marker = "platform_release >= '10.0'" }, - { name = "pyobjc-framework-osakit" }, - { name = "pyobjc-framework-oslog", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-passkit", marker = "platform_release >= '20.0'" }, - { name = "pyobjc-framework-pencilkit", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-phase", marker = "platform_release >= '21.0'" }, - { name = "pyobjc-framework-photos", marker = "platform_release >= '15.0'" }, - { name = "pyobjc-framework-photosui", marker = "platform_release >= '15.0'" }, - { name = "pyobjc-framework-preferencepanes" }, - { name = "pyobjc-framework-pushkit", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-quartz" }, - { name = "pyobjc-framework-quicklookthumbnailing", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-replaykit", marker = "platform_release >= '20.0'" }, - { name = "pyobjc-framework-safariservices", marker = "platform_release >= '16.0'" }, - { name = "pyobjc-framework-safetykit", marker = "platform_release >= '22.0'" }, - { name = "pyobjc-framework-scenekit", marker = "platform_release >= '11.0'" }, - { name = "pyobjc-framework-screencapturekit", marker = "platform_release >= '21.4'" }, - { name = "pyobjc-framework-screensaver" }, - { name = "pyobjc-framework-screentime", marker = "platform_release >= '20.0'" }, - { name = "pyobjc-framework-scriptingbridge", marker = "platform_release >= '9.0'" }, - { name = "pyobjc-framework-searchkit" }, - { name = "pyobjc-framework-security" }, - { name = "pyobjc-framework-securityfoundation" }, - { name = "pyobjc-framework-securityinterface" }, - { name = "pyobjc-framework-securityui", marker = "platform_release >= '24.4'" }, - { name = "pyobjc-framework-sensitivecontentanalysis", marker = "platform_release >= '23.0'" }, - { name = "pyobjc-framework-servicemanagement", marker = "platform_release >= '10.0'" }, - { name = "pyobjc-framework-sharedwithyou", marker = "platform_release >= '22.0'" }, - { name = "pyobjc-framework-sharedwithyoucore", marker = "platform_release >= '22.0'" }, - { name = "pyobjc-framework-shazamkit", marker = "platform_release >= '21.0'" }, - { name = "pyobjc-framework-social", marker = "platform_release >= '12.0'" }, - { name = "pyobjc-framework-soundanalysis", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-speech", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-spritekit", marker = "platform_release >= '13.0'" }, - { name = "pyobjc-framework-storekit", marker = "platform_release >= '11.0'" }, - { name = "pyobjc-framework-symbols", marker = "platform_release >= '23.0'" }, - { name = "pyobjc-framework-syncservices" }, - { name = "pyobjc-framework-systemconfiguration" }, - { name = "pyobjc-framework-systemextensions", marker = "platform_release >= '19.0'" }, - { name = "pyobjc-framework-threadnetwork", marker = "platform_release >= '22.0'" }, - { name = "pyobjc-framework-uniformtypeidentifiers", marker = "platform_release >= '20.0'" }, - { name = "pyobjc-framework-usernotifications", marker = "platform_release >= '18.0'" }, - { name = "pyobjc-framework-usernotificationsui", marker = "platform_release >= '20.0'" }, - { name = "pyobjc-framework-videosubscriberaccount", marker = "platform_release >= '18.0'" }, - { name = "pyobjc-framework-videotoolbox", marker = "platform_release >= '12.0'" }, - { name = "pyobjc-framework-virtualization", marker = "platform_release >= '20.0'" }, - { name = "pyobjc-framework-vision", marker = "platform_release >= '17.0'" }, - { name = "pyobjc-framework-webkit" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-accessibility", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-accounts", marker = "platform_release >= '12.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-addressbook", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-adservices", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-adsupport", marker = "platform_release >= '18.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-applescriptkit", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-applescriptobjc", marker = "platform_release >= '10.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-applicationservices", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-apptrackingtransparency", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-audiovideobridging", marker = "platform_release >= '12.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-authenticationservices", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-automaticassessmentconfiguration", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-automator", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-avfoundation", marker = "platform_release >= '11.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-avkit", marker = "platform_release >= '13.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-avrouting", marker = "platform_release >= '22.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-backgroundassets", marker = "platform_release >= '22.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-browserenginekit", marker = "platform_release >= '23.4' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-businesschat", marker = "platform_release >= '18.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-calendarstore", marker = "platform_release >= '9.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-callkit", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-carbon", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cfnetwork", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cinematic", marker = "platform_release >= '23.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-classkit", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cloudkit", marker = "platform_release >= '14.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-collaboration", marker = "platform_release >= '9.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-colorsync", marker = "platform_release >= '17.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-contacts", marker = "platform_release >= '15.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-contactsui", marker = "platform_release >= '15.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coreaudio", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coreaudiokit", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-corebluetooth", marker = "platform_release >= '14.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coredata", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-corehaptics", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-corelocation", marker = "platform_release >= '10.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coremedia", marker = "platform_release >= '11.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coremediaio", marker = "platform_release >= '11.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coremidi", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coreml", marker = "platform_release >= '17.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coremotion", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coreservices", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-corespotlight", marker = "platform_release >= '17.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coretext", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-corewlan", marker = "platform_release >= '10.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cryptotokenkit", marker = "platform_release >= '14.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-datadetection", marker = "platform_release >= '21.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-devicecheck", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-devicediscoveryextension", marker = "platform_release >= '24.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-dictionaryservices", marker = "platform_release >= '9.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-discrecording", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-discrecordingui", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-diskarbitration", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-dvdplayback", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-eventkit", marker = "platform_release >= '12.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-exceptionhandling", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-executionpolicy", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-extensionkit", marker = "platform_release >= '22.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-externalaccessory", marker = "platform_release >= '17.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-fileprovider", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-fileproviderui", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-findersync", marker = "platform_release >= '14.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-fsevents", marker = "platform_release >= '9.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-fskit", marker = "platform_release >= '24.4' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-gamecenter", marker = "platform_release >= '12.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-gamecontroller", marker = "platform_release >= '13.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-gamekit", marker = "platform_release >= '12.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-gameplaykit", marker = "platform_release >= '15.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-healthkit", marker = "platform_release >= '22.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-imagecapturecore", marker = "platform_release >= '10.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-inputmethodkit", marker = "platform_release >= '9.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-installerplugins", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-instantmessage", marker = "platform_release >= '9.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-intents", marker = "platform_release >= '16.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-intentsui", marker = "platform_release >= '21.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-iobluetooth", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-iobluetoothui", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-iosurface", marker = "platform_release >= '10.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-ituneslibrary", marker = "platform_release >= '10.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-kernelmanagement", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-latentsemanticmapping", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-launchservices", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-libdispatch", marker = "platform_release >= '12.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-libxpc", marker = "platform_release >= '12.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-linkpresentation", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-localauthentication", marker = "platform_release >= '14.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-localauthenticationembeddedui", marker = "platform_release >= '21.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-mailkit", marker = "platform_release >= '21.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-mapkit", marker = "platform_release >= '13.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-mediaaccessibility", marker = "platform_release >= '13.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-mediaextension", marker = "platform_release >= '24.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-medialibrary", marker = "platform_release >= '13.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-mediaplayer", marker = "platform_release >= '16.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-mediatoolbox", marker = "platform_release >= '13.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-metal", marker = "platform_release >= '15.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-metalfx", marker = "platform_release >= '22.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-metalkit", marker = "platform_release >= '15.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-metalperformanceshaders", marker = "platform_release >= '17.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-metalperformanceshadersgraph", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-metrickit", marker = "platform_release >= '21.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-mlcompute", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-modelio", marker = "platform_release >= '15.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-multipeerconnectivity", marker = "platform_release >= '14.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-naturallanguage", marker = "platform_release >= '18.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-netfs", marker = "platform_release >= '10.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-network", marker = "platform_release >= '18.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-networkextension", marker = "platform_release >= '15.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-notificationcenter", marker = "platform_release >= '14.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-opendirectory", marker = "platform_release >= '10.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-osakit", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-oslog", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-passkit", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-pencilkit", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-phase", marker = "platform_release >= '21.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-photos", marker = "platform_release >= '15.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-photosui", marker = "platform_release >= '15.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-preferencepanes", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-pushkit", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quicklookthumbnailing", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-replaykit", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-safariservices", marker = "platform_release >= '16.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-safetykit", marker = "platform_release >= '22.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-scenekit", marker = "platform_release >= '11.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-screencapturekit", marker = "platform_release >= '21.4' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-screensaver", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-screentime", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-scriptingbridge", marker = "platform_release >= '9.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-searchkit", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-security", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-securityfoundation", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-securityinterface", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-securityui", marker = "platform_release >= '24.4' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-sensitivecontentanalysis", marker = "platform_release >= '23.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-servicemanagement", marker = "platform_release >= '10.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-sharedwithyou", marker = "platform_release >= '22.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-sharedwithyoucore", marker = "platform_release >= '22.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-shazamkit", marker = "platform_release >= '21.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-social", marker = "platform_release >= '12.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-soundanalysis", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-speech", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-spritekit", marker = "platform_release >= '13.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-storekit", marker = "platform_release >= '11.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-symbols", marker = "platform_release >= '23.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-syncservices", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-systemconfiguration", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-systemextensions", marker = "platform_release >= '19.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-threadnetwork", marker = "platform_release >= '22.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-uniformtypeidentifiers", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-usernotifications", marker = "platform_release >= '18.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-usernotificationsui", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-videosubscriberaccount", marker = "platform_release >= '18.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-videotoolbox", marker = "platform_release >= '12.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-virtualization", marker = "platform_release >= '20.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-vision", marker = "platform_release >= '17.0' and sys_platform == 'darwin'" }, + { name = "pyobjc-framework-webkit", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/db/5e/16bc372806790d295c76b5c7851767cc9ee3787b3e581f5d7cc44158e4e0/pyobjc-11.1.tar.gz", hash = "sha256:a71b14389657811d658526ba4d5faba4ef7eadbddcf9fe8bf4fb3a6261effba3", size = 11161, upload-time = "2025-06-14T20:56:32.819Z" } wheels = [ @@ -1972,9 +1945,9 @@ name = "pyobjc-framework-accessibility" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/78/b4/10c16e9d48568a68da2f61866b19468d4ac7129c377d4b1333ee936ae5d0/pyobjc_framework_accessibility-11.1.tar.gz", hash = "sha256:c0fa5f1e00906ec002f582c7d3d80463a46d19f672bf5ec51144f819eeb40656", size = 45098, upload-time = "2025-06-14T20:56:35.287Z" } wheels = [ @@ -1987,8 +1960,8 @@ name = "pyobjc-framework-accounts" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/12/45/ca21003f68ad0f13b5a9ac1761862ad2ddd83224b4314a2f7d03ca437c8d/pyobjc_framework_accounts-11.1.tar.gz", hash = "sha256:384fec156e13ff75253bb094339013f4013464f6dfd47e2f7de3e2ae7441c030", size = 17086, upload-time = "2025-06-14T20:56:36.035Z" } wheels = [ @@ -2000,8 +1973,8 @@ name = "pyobjc-framework-addressbook" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/eb/d3/f5bb5c72be5c6e52224f43e23e5a44e86d2c35ee9af36939e5514c6c7a0f/pyobjc_framework_addressbook-11.1.tar.gz", hash = "sha256:ce2db3be4a3128bf79d5c41319a6d16b73754785ce75ac694d0d658c690922fc", size = 97609, upload-time = "2025-06-14T20:56:37.324Z" } wheels = [ @@ -2014,8 +1987,8 @@ name = "pyobjc-framework-adservices" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/2a/3f/af76eab6eee0a405a4fdee172e7181773040158476966ecd757b0a98bfc5/pyobjc_framework_adservices-11.1.tar.gz", hash = "sha256:44c72f8163705c9aa41baca938fdb17dde257639e5797e6a5c3a2b2d8afdade9", size = 12473, upload-time = "2025-06-14T20:56:38.147Z" } wheels = [ @@ -2027,8 +2000,8 @@ name = "pyobjc-framework-adsupport" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7f/03/9c51edd964796a97def4e1433d76a128dd7059b685fb4366081bf4e292ba/pyobjc_framework_adsupport-11.1.tar.gz", hash = "sha256:78b9667c275785df96219d205bd4309731869c3298d0931e32aed83bede29096", size = 12556, upload-time = "2025-06-14T20:56:38.741Z" } wheels = [ @@ -2040,8 +2013,8 @@ name = "pyobjc-framework-applescriptkit" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/bc/63/1bcfcdca53bf5bba3a7b4d73d24232ae1721a378a32fd4ebc34a35549df2/pyobjc_framework_applescriptkit-11.1.tar.gz", hash = "sha256:477707352eaa6cc4a5f8c593759dc3227a19d5958481b1482f0d59394a4601c3", size = 12392, upload-time = "2025-06-14T20:56:39.331Z" } wheels = [ @@ -2053,8 +2026,8 @@ name = "pyobjc-framework-applescriptobjc" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a3/27/687b55b575367df045879b786f358355e40e41f847968e557d0718a6c4a4/pyobjc_framework_applescriptobjc-11.1.tar.gz", hash = "sha256:c8a0ec975b64411a4f16a1280c5ea8dbe949fd361e723edd343102f0f95aba6e", size = 12445, upload-time = "2025-06-14T20:56:39.976Z" } wheels = [ @@ -2066,10 +2039,10 @@ name = "pyobjc-framework-applicationservices" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coretext" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coretext", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/be/3f/b33ce0cecc3a42f6c289dcbf9ff698b0d9e85f5796db2e9cb5dadccffbb9/pyobjc_framework_applicationservices-11.1.tar.gz", hash = "sha256:03fcd8c0c600db98fa8b85eb7b3bc31491701720c795e3f762b54e865138bbaf", size = 224842, upload-time = "2025-06-14T20:56:40.648Z" } wheels = [ @@ -2082,8 +2055,8 @@ name = "pyobjc-framework-apptrackingtransparency" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/49/68/7aa3afffd038dd6e5af764336bca734eb910121013ca71030457b61e5b99/pyobjc_framework_apptrackingtransparency-11.1.tar.gz", hash = "sha256:796cc5f83346c10973806cfb535d4200b894a5d2626ff2eeb1972d594d14fed4", size = 13135, upload-time = "2025-06-14T20:56:41.494Z" } wheels = [ @@ -2095,8 +2068,8 @@ name = "pyobjc-framework-audiovideobridging" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c3/25/6c5a7b1443d30139cc722029880284ea9dfa575f0436471b9364fcd499f5/pyobjc_framework_audiovideobridging-11.1.tar.gz", hash = "sha256:12756b3aa35083b8ad5c9139b6a0e2f4792e217096b5bf6b702d499038203991", size = 72913, upload-time = "2025-06-14T20:56:42.128Z" } wheels = [ @@ -2109,8 +2082,8 @@ name = "pyobjc-framework-authenticationservices" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/8f/b7/3e9ad0ed3625dc02e495615ea5dbf55ca95cbd25b3e31f25092f5caad640/pyobjc_framework_authenticationservices-11.1.tar.gz", hash = "sha256:8fd801cdb53d426b4e678b0a8529c005d0c44f5a17ccd7052a7c3a1a87caed6a", size = 115266, upload-time = "2025-06-14T20:56:42.889Z" } wheels = [ @@ -2123,8 +2096,8 @@ name = "pyobjc-framework-automaticassessmentconfiguration" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/3d/39/d4c94e0245d290b83919854c4f205851cc0b2603f843448fdfb8e74aad71/pyobjc_framework_automaticassessmentconfiguration-11.1.tar.gz", hash = "sha256:70eadbf8600101901a56fcd7014d8941604e14f3b3728bc4fb0178a9a9420032", size = 24933, upload-time = "2025-06-14T20:56:43.984Z" } wheels = [ @@ -2137,8 +2110,8 @@ name = "pyobjc-framework-automator" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/63/9f/097ed9f4de9e9491a1b08bb7d85d35a95d726c9e9f5f5bf203b359a436b6/pyobjc_framework_automator-11.1.tar.gz", hash = "sha256:9b46c55a4f9ae2b3c39ff560f42ced66bdd18c093188f0b5fc4060ad911838e4", size = 201439, upload-time = "2025-06-14T20:56:44.767Z" } wheels = [ @@ -2151,11 +2124,11 @@ name = "pyobjc-framework-avfoundation" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coreaudio" }, - { name = "pyobjc-framework-coremedia" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coreaudio", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coremedia", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/3c/1f/90cdbce1d3b4861cbb17c12adf57daeec32477eb1df8d3f9ab8551bdadfb/pyobjc_framework_avfoundation-11.1.tar.gz", hash = "sha256:6663056cc6ca49af8de6d36a7fff498f51e1a9a7f1bde7afba718a8ceaaa7377", size = 832178, upload-time = "2025-06-14T20:56:46.329Z" } wheels = [ @@ -2168,9 +2141,9 @@ name = "pyobjc-framework-avkit" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/61/ff/9f41f2b8de786871184b48c4e5052cb7c9fcc204e7fee06687fa32b08bed/pyobjc_framework_avkit-11.1.tar.gz", hash = "sha256:d948204a7b94e0e878b19a909f9b33342e19d9ea519571d66a21fce8f72e3263", size = 46825, upload-time = "2025-06-14T20:56:47.494Z" } wheels = [ @@ -2183,8 +2156,8 @@ name = "pyobjc-framework-avrouting" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/cf/42/94bc18b968a4ee8b6427257f907ffbfc97f8ba6a6202953da149b649d638/pyobjc_framework_avrouting-11.1.tar.gz", hash = "sha256:7db1291d9f53cc58d34b2a826feb721a85f50ceb5e71952e8762baacd3db3fc0", size = 21069, upload-time = "2025-06-14T20:56:48.57Z" } wheels = [ @@ -2197,8 +2170,8 @@ name = "pyobjc-framework-backgroundassets" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/08/76/21e1632a212f997d7a5f26d53eb997951978916858039b79f43ebe3d10b2/pyobjc_framework_backgroundassets-11.1.tar.gz", hash = "sha256:2e14b50539d96d5fca70c49f21b69fdbad81a22549e3630f5e4f20d5c0204fc2", size = 24803, upload-time = "2025-06-14T20:56:49.566Z" } wheels = [ @@ -2211,11 +2184,11 @@ name = "pyobjc-framework-browserenginekit" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coreaudio" }, - { name = "pyobjc-framework-coremedia" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coreaudio", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coremedia", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/30/75/087270d9f81e913b57c7db58eaff8691fa0574b11faf9302340b3b8320f1/pyobjc_framework_browserenginekit-11.1.tar.gz", hash = "sha256:918440cefb10480024f645169de3733e30ede65e41267fa12c7b90c264a0a479", size = 31944, upload-time = "2025-06-14T20:56:50.195Z" } wheels = [ @@ -2228,8 +2201,8 @@ name = "pyobjc-framework-businesschat" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/85/be/9d9d9d9383c411a58323ea510d768443287ca21610af652b815b3205ea80/pyobjc_framework_businesschat-11.1.tar.gz", hash = "sha256:69589d2f0cb4e7892e5ecc6aed79b1abd1ec55c099a7faacae6a326bc921259d", size = 12698, upload-time = "2025-06-14T20:56:51.173Z" } wheels = [ @@ -2241,8 +2214,8 @@ name = "pyobjc-framework-calendarstore" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/41/df/7ca8ee65b16d5fc862d7e8664289472eed918cf4d76921de6bdaa1461c65/pyobjc_framework_calendarstore-11.1.tar.gz", hash = "sha256:858ee00e6a380d9c086c2d7db82c116a6c406234038e0ec8fc2ad02e385dc437", size = 68215, upload-time = "2025-06-14T20:56:51.799Z" } wheels = [ @@ -2254,8 +2227,8 @@ name = "pyobjc-framework-callkit" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/51/d5/4f0b62ab35be619e8c8d96538a03cf56fde6fd53540e1837e0fa588b3f6c/pyobjc_framework_callkit-11.1.tar.gz", hash = "sha256:b84d5ea38dff0cbe0754f5f9f6f33c742e216f12e7166179a8ec2cf4b0bfca94", size = 46648, upload-time = "2025-06-14T20:56:52.579Z" } wheels = [ @@ -2268,8 +2241,8 @@ name = "pyobjc-framework-carbon" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/39/a4/d751851865d9a78405cfec0c8b2931b1e96b9914e9788cd441fa4e8290d0/pyobjc_framework_carbon-11.1.tar.gz", hash = "sha256:047f098535479efa3ab89da1ebdf3cf9ec0b439a33a4f32806193886e9fcea71", size = 37291, upload-time = "2025-06-14T20:56:53.642Z" } wheels = [ @@ -2281,8 +2254,8 @@ name = "pyobjc-framework-cfnetwork" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6f/49/7b24172e3d6eb0ddffc33a7498a2bea264aa2958c3fecaeb463bef88f0b8/pyobjc_framework_cfnetwork-11.1.tar.gz", hash = "sha256:ad600163eeadb7bf71abc51a9b6f2b5462a018d3f9bb1510c5ce3fdf2f22959d", size = 79069, upload-time = "2025-06-14T20:56:54.615Z" } wheels = [ @@ -2295,11 +2268,11 @@ name = "pyobjc-framework-cinematic" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-avfoundation" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coremedia" }, - { name = "pyobjc-framework-metal" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-avfoundation", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coremedia", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-metal", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/57/6f/c2d0b49e01e654496a1781bafb9da72a6fbd00f5abb39dc4a3a0045167c7/pyobjc_framework_cinematic-11.1.tar.gz", hash = "sha256:efde39a6a2379e1738dbc5434b2470cd187cf3114ffb81390b3b1abda470b382", size = 25522, upload-time = "2025-06-14T20:56:55.379Z" } wheels = [ @@ -2311,8 +2284,8 @@ name = "pyobjc-framework-classkit" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7a/8b/5150b4faddd15d5dd795bc62b2256c4f7dafc983cfa694fcf88121ea0016/pyobjc_framework_classkit-11.1.tar.gz", hash = "sha256:ee1e26395eb00b3ed5442e3234cdbfe925d2413185af38eca0477d7166651df4", size = 39831, upload-time = "2025-06-14T20:56:56.036Z" } wheels = [ @@ -2325,11 +2298,11 @@ name = "pyobjc-framework-cloudkit" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-accounts" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coredata" }, - { name = "pyobjc-framework-corelocation" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-accounts", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coredata", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-corelocation", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/58/a6/bfe5be55ed95704efca0e86b218155a9c801735107cedba3af8ea4580a05/pyobjc_framework_cloudkit-11.1.tar.gz", hash = "sha256:40d2dc4bf28c5be9b836b01e4d267a15d847d756c2a65530e1fcd79b2825e86d", size = 122778, upload-time = "2025-06-14T20:56:56.73Z" } wheels = [ @@ -2341,7 +2314,7 @@ name = "pyobjc-framework-cocoa" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/4b/c5/7a866d24bc026f79239b74d05e2cf3088b03263da66d53d1b4cf5207f5ae/pyobjc_framework_cocoa-11.1.tar.gz", hash = "sha256:87df76b9b73e7ca699a828ff112564b59251bb9bbe72e610e670a4dc9940d038", size = 5565335, upload-time = "2025-06-14T20:56:59.683Z" } wheels = [ @@ -2354,8 +2327,8 @@ name = "pyobjc-framework-collaboration" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/66/49/9dbe8407d5dd663747267c1234d1b914bab66e1878d22f57926261a3063b/pyobjc_framework_collaboration-11.1.tar.gz", hash = "sha256:4564e3931bfc51773623d4f57f2431b58a39b75cb964ae5c48d27ee4dde2f4ea", size = 16839, upload-time = "2025-06-14T20:57:01.101Z" } wheels = [ @@ -2367,8 +2340,8 @@ name = "pyobjc-framework-colorsync" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b5/97/7613b6041f62c52f972e42dd5d79476b56b84d017a8b5e4add4d9cfaca36/pyobjc_framework_colorsync-11.1.tar.gz", hash = "sha256:7a346f71f34b2ccd1b020a34c219b85bf8b6f6e05283d503185aeb7767a269dd", size = 38999, upload-time = "2025-06-14T20:57:01.761Z" } wheels = [ @@ -2380,8 +2353,8 @@ name = "pyobjc-framework-contacts" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a6/85/34868b6447d552adf8674bac226b55c2baacacee0d67ee031e33805d6faa/pyobjc_framework_contacts-11.1.tar.gz", hash = "sha256:752036e7d8952a4122296d7772f274170a5f35a53ee6454a27f3e1d9603222cc", size = 84814, upload-time = "2025-06-14T20:57:02.582Z" } wheels = [ @@ -2394,9 +2367,9 @@ name = "pyobjc-framework-contactsui" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-contacts" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-contacts", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/3f/57/8765b54a30edaa2a56df62e11e7c32e41b6ea300513256adffa191689368/pyobjc_framework_contactsui-11.1.tar.gz", hash = "sha256:5bc29ea2b10a342018e1b96be6b140c10ebe3cfb6417278770feef5e88026a1f", size = 20031, upload-time = "2025-06-14T20:57:03.603Z" } wheels = [ @@ -2409,8 +2382,8 @@ name = "pyobjc-framework-coreaudio" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/39/c0/4ab6005cf97e534725b0c14b110d4864b367c282b1c5b0d8f42aad74a83f/pyobjc_framework_coreaudio-11.1.tar.gz", hash = "sha256:b7b89540ae7efc6c1e3208ac838ef2acfc4d2c506dd629d91f6b3b3120e55c1b", size = 141032, upload-time = "2025-06-14T20:57:04.348Z" } wheels = [ @@ -2423,9 +2396,9 @@ name = "pyobjc-framework-coreaudiokit" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coreaudio" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coreaudio", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f1/4e/c49b26c60047c511727efe994b412276c487dfe90f1ee0fced0bddbdf8a3/pyobjc_framework_coreaudiokit-11.1.tar.gz", hash = "sha256:0b461c3d6123fda4da6b6aaa022efc918c1de2e126a5cf07d2189d63fa54ba40", size = 21955, upload-time = "2025-06-14T20:57:05.218Z" } wheels = [ @@ -2438,8 +2411,8 @@ name = "pyobjc-framework-corebluetooth" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/3d/fe/2081dfd9413b7b4d719935c33762fbed9cce9dc06430f322d1e2c9dbcd91/pyobjc_framework_corebluetooth-11.1.tar.gz", hash = "sha256:1deba46e3fcaf5e1c314f4bbafb77d9fe49ec248c493ad00d8aff2df212d6190", size = 60337, upload-time = "2025-06-14T20:57:05.919Z" } wheels = [ @@ -2452,8 +2425,8 @@ name = "pyobjc-framework-coredata" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/00/e3/af497da7a7c895b6ff529d709d855a783f34afcc4b87ab57a1a2afb3f876/pyobjc_framework_coredata-11.1.tar.gz", hash = "sha256:fe9fd985f8e06c70c0fb1e6bbea5b731461f9e76f8f8d8e89c7c72667cdc6adf", size = 260628, upload-time = "2025-06-14T20:57:06.729Z" } wheels = [ @@ -2466,8 +2439,8 @@ name = "pyobjc-framework-corehaptics" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5f/83/cc997ec4687a68214dd3ad1bdf64353305f5c7e827fad211adac4c28b39f/pyobjc_framework_corehaptics-11.1.tar.gz", hash = "sha256:e5da3a97ed6aca9b7268c8c5196c0a339773a50baa72d1502d3435dc1a2a80f1", size = 42722, upload-time = "2025-06-14T20:57:08.019Z" } wheels = [ @@ -2479,8 +2452,8 @@ name = "pyobjc-framework-corelocation" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/95/ef/fbd2e01ec137208af7bfefe222773748d27f16f845b0efa950d65e2bd719/pyobjc_framework_corelocation-11.1.tar.gz", hash = "sha256:46a67b99925ee3d53914331759c6ee110b31bb790b74b05915acfca41074c206", size = 104508, upload-time = "2025-06-14T20:57:08.731Z" } wheels = [ @@ -2493,8 +2466,8 @@ name = "pyobjc-framework-coremedia" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/95/5d/81513acd219df77a89176f1574d936b81ad6f6002225cabb64d55efb7e8d/pyobjc_framework_coremedia-11.1.tar.gz", hash = "sha256:82cdc087f61e21b761e677ea618a575d4c0dbe00e98230bf9cea540cff931db3", size = 216389, upload-time = "2025-06-14T20:57:09.546Z" } wheels = [ @@ -2507,8 +2480,8 @@ name = "pyobjc-framework-coremediaio" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/64/68/9cef2aefba8e69916049ff43120e8794df8051bdf1f690a55994bbe4eb57/pyobjc_framework_coremediaio-11.1.tar.gz", hash = "sha256:bccd69712578b177144ded398f4695d71a765ef61204da51a21f0c90b4ad4c64", size = 108326, upload-time = "2025-06-14T20:57:10.435Z" } wheels = [ @@ -2521,8 +2494,8 @@ name = "pyobjc-framework-coremidi" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/06/ca/2ae5149966ccd78290444f88fa62022e2b96ed2fddd47e71d9fd249a9f82/pyobjc_framework_coremidi-11.1.tar.gz", hash = "sha256:095030c59d50c23aa53608777102bc88744ff8b10dfb57afe24b428dcd12e376", size = 107817, upload-time = "2025-06-14T20:57:11.245Z" } wheels = [ @@ -2535,8 +2508,8 @@ name = "pyobjc-framework-coreml" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0d/5d/4309f220981d769b1a2f0dcb2c5c104490d31389a8ebea67e5595ce1cb74/pyobjc_framework_coreml-11.1.tar.gz", hash = "sha256:775923eefb9eac2e389c0821b10564372de8057cea89f1ea1cdaf04996c970a7", size = 82005, upload-time = "2025-06-14T20:57:12.004Z" } wheels = [ @@ -2549,8 +2522,8 @@ name = "pyobjc-framework-coremotion" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a5/95/e469dc7100ea6b9c29a074a4f713d78b32a78d7ec5498c25c83a56744fc2/pyobjc_framework_coremotion-11.1.tar.gz", hash = "sha256:5884a568521c0836fac39d46683a4dea3d259a23837920897042ffb922d9ac3e", size = 67050, upload-time = "2025-06-14T20:57:12.705Z" } wheels = [ @@ -2563,9 +2536,9 @@ name = "pyobjc-framework-coreservices" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-fsevents" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-fsevents", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a8/a9/141d18019a25776f507992f9e7ffc051ca5a734848d8ea8d848f7c938efc/pyobjc_framework_coreservices-11.1.tar.gz", hash = "sha256:cf8eb5e272c60a96d025313eca26ff2487dcd02c47034cc9db39f6852d077873", size = 1245086, upload-time = "2025-06-14T20:57:13.914Z" } wheels = [ @@ -2578,8 +2551,8 @@ name = "pyobjc-framework-corespotlight" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/31/c7/b67ebfb63b7ccbfda780d583056d1fd4b610ba3839c8ebe3435b86122c61/pyobjc_framework_corespotlight-11.1.tar.gz", hash = "sha256:4dd363c8d3ff7619659b63dd31400f135b03e32435b5d151459ecdacea14e0f2", size = 87161, upload-time = "2025-06-14T20:57:14.934Z" } wheels = [ @@ -2592,9 +2565,9 @@ name = "pyobjc-framework-coretext" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/65/e9/d3231c4f87d07b8525401fd6ad3c56607c9e512c5490f0a7a6abb13acab6/pyobjc_framework_coretext-11.1.tar.gz", hash = "sha256:a29bbd5d85c77f46a8ee81d381b847244c88a3a5a96ac22f509027ceceaffaf6", size = 274702, upload-time = "2025-06-14T20:57:16.059Z" } wheels = [ @@ -2607,8 +2580,8 @@ name = "pyobjc-framework-corewlan" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c6/d8/03aff3c75485fc999e260946ef1e9adf17640a6e08d7bf603d31cfcf73fc/pyobjc_framework_corewlan-11.1.tar.gz", hash = "sha256:4a8afea75393cc0a6fe696e136233aa0ed54266f35a47b55a3583f4cb078e6ce", size = 65792, upload-time = "2025-06-14T20:57:16.931Z" } wheels = [ @@ -2621,8 +2594,8 @@ name = "pyobjc-framework-cryptotokenkit" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/eb/92/7fab6fcc6bb659d6946cfb2f670058180bcc4ca1626878b0f7c95107abf0/pyobjc_framework_cryptotokenkit-11.1.tar.gz", hash = "sha256:5f82f44d9ab466c715a7c8ad4d5ec47c68aacd78bd67b5466a7b8215a2265328", size = 59223, upload-time = "2025-06-14T20:57:17.658Z" } wheels = [ @@ -2635,8 +2608,8 @@ name = "pyobjc-framework-datadetection" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7d/4d/65c61d8878b44689e28d5729be9edbb73e20b1b0500d1095172cfd24aea6/pyobjc_framework_datadetection-11.1.tar.gz", hash = "sha256:cbe0080b51e09b2f91eaf2a9babec3dcf2883d7966bc0abd8393ef7abfcfc5db", size = 13485, upload-time = "2025-06-14T20:57:18.829Z" } wheels = [ @@ -2648,8 +2621,8 @@ name = "pyobjc-framework-devicecheck" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f3/f2/b1d263f8231f815a9eeff15809f4b7428dacdc0a6aa267db5ed907445066/pyobjc_framework_devicecheck-11.1.tar.gz", hash = "sha256:8b05973eb2673571144d81346336e749a21cec90bd7fcaade76ffd3b147a0741", size = 13954, upload-time = "2025-06-14T20:57:19.782Z" } wheels = [ @@ -2661,8 +2634,8 @@ name = "pyobjc-framework-devicediscoveryextension" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/9a/b8/102863bfa2f1e414c88bb9f51151a9a58b99c268a841b59d46e0dcc5fe6d/pyobjc_framework_devicediscoveryextension-11.1.tar.gz", hash = "sha256:ae160ea40f25d3ee5e7ce80ac9c1b315f94d0a4c7ccb86920396f71c6bf799a0", size = 14298, upload-time = "2025-06-14T20:57:20.738Z" } wheels = [ @@ -2674,8 +2647,8 @@ name = "pyobjc-framework-dictionaryservices" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-coreservices" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coreservices", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d6/13/c46f6db61133fee15e3471f33a679da2af10d63fa2b4369e0cd476988721/pyobjc_framework_dictionaryservices-11.1.tar.gz", hash = "sha256:39c24452d0ddd037afeb73a1742614c94535f15b1c024a8a6cc7ff081e1d22e7", size = 10578, upload-time = "2025-06-14T20:57:21.392Z" } wheels = [ @@ -2687,8 +2660,8 @@ name = "pyobjc-framework-discrecording" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a5/b2/d8d1a28643c2ab681b517647bacb68496c98886336ffbd274f0b2ad28cdc/pyobjc_framework_discrecording-11.1.tar.gz", hash = "sha256:37585458e363b20bb28acdb5cc265dfca934d8a07b7baed2584953c11c927a87", size = 123004, upload-time = "2025-06-14T20:57:22.01Z" } wheels = [ @@ -2701,9 +2674,9 @@ name = "pyobjc-framework-discrecordingui" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-discrecording" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-discrecording", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/25/53/d71717f00332b8fc3d8a5c7234fdc270adadfeb5ca9318a55986f5c29c44/pyobjc_framework_discrecordingui-11.1.tar.gz", hash = "sha256:a9f10e2e7ee19582c77f0755ae11a64e3d61c652cbd8a5bf52756f599be24797", size = 19370, upload-time = "2025-06-14T20:57:22.791Z" } wheels = [ @@ -2715,8 +2688,8 @@ name = "pyobjc-framework-diskarbitration" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/da/2a/68fa0c99e04ec1ec24b0b7d6f5b7ec735d5e8a73277c5c0671438a69a403/pyobjc_framework_diskarbitration-11.1.tar.gz", hash = "sha256:a933efc6624779a393fafe0313e43378bcae2b85d6d15cff95ac30048c1ef490", size = 19866, upload-time = "2025-06-14T20:57:23.435Z" } wheels = [ @@ -2728,8 +2701,8 @@ name = "pyobjc-framework-dvdplayback" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b8/76/77046325b1957f0cbcdf4f96667496d042ed4758f3413f1d21df5b085939/pyobjc_framework_dvdplayback-11.1.tar.gz", hash = "sha256:b44c36a62c8479e649133216e22941859407cca5796b5f778815ef9340a838f4", size = 64558, upload-time = "2025-06-14T20:57:24.118Z" } wheels = [ @@ -2741,8 +2714,8 @@ name = "pyobjc-framework-eventkit" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b4/c4/cbba8f2dce13b9be37ecfd423ba2b92aa3f209dbb58ede6c4ce3b242feee/pyobjc_framework_eventkit-11.1.tar.gz", hash = "sha256:5643150f584243681099c5e9435efa833a913e93fe9ca81f62007e287349b561", size = 75177, upload-time = "2025-06-14T20:57:24.81Z" } wheels = [ @@ -2754,8 +2727,8 @@ name = "pyobjc-framework-exceptionhandling" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/19/0d/c72a885b40d28a99b586447f9ea6f400589f13d554fcd6f13a2c841bb6d2/pyobjc_framework_exceptionhandling-11.1.tar.gz", hash = "sha256:e010f56bf60ab4e9e3225954ebb53e9d7135d37097043ac6dd2a3f35770d4efa", size = 17890, upload-time = "2025-06-14T20:57:25.521Z" } wheels = [ @@ -2767,8 +2740,8 @@ name = "pyobjc-framework-executionpolicy" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0b/cf/54431846508c5d5bb114a415ebb96187da5847105918169e42f4ca3b00e6/pyobjc_framework_executionpolicy-11.1.tar.gz", hash = "sha256:3280ad2f4c5eaf45901f310cee0c52db940c0c63e959ad082efb8df41055d986", size = 13496, upload-time = "2025-06-14T20:57:26.173Z" } wheels = [ @@ -2780,8 +2753,8 @@ name = "pyobjc-framework-extensionkit" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ce/7d/89adf16c7de4246477714dce8fcffae4242778aecd0c5f0ad9904725f42c/pyobjc_framework_extensionkit-11.1.tar.gz", hash = "sha256:c114a96f13f586dbbab8b6219a92fa4829896a645c8cd15652a6215bc8ff5409", size = 19766, upload-time = "2025-06-14T20:57:27.106Z" } wheels = [ @@ -2794,8 +2767,8 @@ name = "pyobjc-framework-externalaccessory" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d9/a3/519242e6822e1ddc9e64e21f717529079dbc28a353474420da8315d0a8b1/pyobjc_framework_externalaccessory-11.1.tar.gz", hash = "sha256:50887e948b78a1d94646422c243ac2a9e40761675e38b9184487870a31e83371", size = 23123, upload-time = "2025-06-14T20:57:27.845Z" } wheels = [ @@ -2808,8 +2781,8 @@ name = "pyobjc-framework-fileprovider" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/1b/80/3ebba2c1e5e3aeae989fe038c259a93e7e7e18fd56666ece514d000d38ea/pyobjc_framework_fileprovider-11.1.tar.gz", hash = "sha256:748ca1c75f84afdf5419346a24bf8eec44dca071986f31f00071dc191b3e9ca8", size = 91696, upload-time = "2025-06-14T20:57:28.546Z" } wheels = [ @@ -2822,8 +2795,8 @@ name = "pyobjc-framework-fileproviderui" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-fileprovider" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-fileprovider", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/75/ed/0f5af06869661822c4a70aacd674da5d1e6b6661240e2883bbc7142aa525/pyobjc_framework_fileproviderui-11.1.tar.gz", hash = "sha256:162a23e67f59e1bb247e84dda88d513d7944d815144901a46be6fe051b6c7970", size = 13163, upload-time = "2025-06-14T20:57:29.568Z" } wheels = [ @@ -2835,8 +2808,8 @@ name = "pyobjc-framework-findersync" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/2a/82/c6b670494ac0c4cf14cf2db0dfbe0df71925d20595404939383ddbcc56d3/pyobjc_framework_findersync-11.1.tar.gz", hash = "sha256:692364937f418f0e4e4abd395a09a7d4a0cdd55fd4e0184de85ee59642defb6e", size = 15045, upload-time = "2025-06-14T20:57:30.173Z" } wheels = [ @@ -2848,8 +2821,8 @@ name = "pyobjc-framework-fsevents" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/8e/83/ec0b9ba355dbc34f27ed748df9df4eb6dbfdd9bbd614b0f193752f36f419/pyobjc_framework_fsevents-11.1.tar.gz", hash = "sha256:d29157d04124503c4dfa9dcbbdc8c34d3bab134d3db3a48d96d93f26bd94c14d", size = 29587, upload-time = "2025-06-14T20:57:30.796Z" } wheels = [ @@ -2862,8 +2835,8 @@ name = "pyobjc-framework-fskit" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/46/47/d1f04c6115fa78936399a389cc5e0e443f8341c9a6c1c0df7f6fdbe51286/pyobjc_framework_fskit-11.1.tar.gz", hash = "sha256:9ded1eab19b4183cb04381e554bbbe679c1213fd58599d6fc6e135e93b51136f", size = 42091, upload-time = "2025-06-14T20:57:31.504Z" } wheels = [ @@ -2876,8 +2849,8 @@ name = "pyobjc-framework-gamecenter" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/1b/8e/b594fd1dc32a59462fc68ad502be2bd87c70e6359b4e879a99bcc4beaf5b/pyobjc_framework_gamecenter-11.1.tar.gz", hash = "sha256:a1c4ed54e11a6e4efba6f2a21ace92bcf186e3fe5c74a385b31f6b1a515ec20c", size = 31981, upload-time = "2025-06-14T20:57:32.192Z" } wheels = [ @@ -2890,8 +2863,8 @@ name = "pyobjc-framework-gamecontroller" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/70/4c/1dd62103092a182f2ab8904c8a8e3922d2b0a80a7adab0c20e5fd0207d75/pyobjc_framework_gamecontroller-11.1.tar.gz", hash = "sha256:4d5346faf90e1ebe5602c0c480afbf528a35a7a1ad05f9b49991fdd2a97f105b", size = 115783, upload-time = "2025-06-14T20:57:32.879Z" } wheels = [ @@ -2904,9 +2877,9 @@ name = "pyobjc-framework-gamekit" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5b/7b/ba141ec0f85ca816f493d1f6fe68c72d01092e5562e53c470a0111d9c34b/pyobjc_framework_gamekit-11.1.tar.gz", hash = "sha256:9b8db075da8866c4ef039a165af227bc29393dc11a617a40671bf6b3975ae269", size = 165397, upload-time = "2025-06-14T20:57:33.711Z" } wheels = [ @@ -2919,9 +2892,9 @@ name = "pyobjc-framework-gameplaykit" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-spritekit" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-spritekit", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e0/07/f38b1d83eac10ea4f75c605ffc4850585740db89b90842d311e586ee36cd/pyobjc_framework_gameplaykit-11.1.tar.gz", hash = "sha256:9ae2bee69b0cc1afa0e210b4663c7cdbb3cc94be1374808df06f98f992e83639", size = 73399, upload-time = "2025-06-14T20:57:34.538Z" } wheels = [ @@ -2934,8 +2907,8 @@ name = "pyobjc-framework-healthkit" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/af/66/fa76f7c8e36e4c10677d42d91a8e220c135c610a06b759571db1abe26a32/pyobjc_framework_healthkit-11.1.tar.gz", hash = "sha256:20f59bd9e1ffafe5893b4eff5867fdfd20bd46c3d03bc4009219d82fc6815f76", size = 202009, upload-time = "2025-06-14T20:57:35.285Z" } wheels = [ @@ -2948,8 +2921,8 @@ name = "pyobjc-framework-imagecapturecore" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7b/3b/f4edbc58a8c7394393f8d00d0e764f655545e743ee4e33917f27b8c68e7b/pyobjc_framework_imagecapturecore-11.1.tar.gz", hash = "sha256:a610ceb6726e385b132a1481a68ce85ccf56f94667b6d6e1c45a2cfab806a624", size = 100398, upload-time = "2025-06-14T20:57:36.503Z" } wheels = [ @@ -2962,8 +2935,8 @@ name = "pyobjc-framework-inputmethodkit" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/02/32/6a90bba682a31960ba1fc2d3b263e9be26043c4fb7aed273c13647c8b7d9/pyobjc_framework_inputmethodkit-11.1.tar.gz", hash = "sha256:7037579524041dcee71a649293c2660f9359800455a15e6a2f74a17b46d78496", size = 27203, upload-time = "2025-06-14T20:57:37.246Z" } wheels = [ @@ -2976,8 +2949,8 @@ name = "pyobjc-framework-installerplugins" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/4d/89/9a881e466476ca21f3ff3e8e87ccfba1aaad9b88f7eea4be6d3f05b07107/pyobjc_framework_installerplugins-11.1.tar.gz", hash = "sha256:363e59c7e05553d881f0facd41884f17b489ff443d7856e33dd0312064c746d9", size = 27451, upload-time = "2025-06-14T20:57:37.915Z" } wheels = [ @@ -2989,9 +2962,9 @@ name = "pyobjc-framework-instantmessage" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/9f/b9/5cec4dd0053b5f63c01211a60a286c47464d9f3e0c81bd682e6542dbff00/pyobjc_framework_instantmessage-11.1.tar.gz", hash = "sha256:c222aa61eb009704b333f6e63df01a0e690136e7e495907e5396882779bf9525", size = 33774, upload-time = "2025-06-14T20:57:38.553Z" } wheels = [ @@ -3003,8 +2976,8 @@ name = "pyobjc-framework-intents" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/4c/af/d7f260d06b79acca8028e373c2fe30bf0be014388ba612f538f40597d929/pyobjc_framework_intents-11.1.tar.gz", hash = "sha256:13185f206493f45d6bd2d4903c2136b1c4f8b9aa37628309ace6ff4a906b4695", size = 448459, upload-time = "2025-06-14T20:57:39.589Z" } wheels = [ @@ -3017,8 +2990,8 @@ name = "pyobjc-framework-intentsui" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-intents" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-intents", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/86/46/20aae4a71efb514b096f36273a6129b48b01535bf501e5719d4a97fcb3a5/pyobjc_framework_intentsui-11.1.tar.gz", hash = "sha256:c8182155af4dce369c18d6e6ed9c25bbd8110c161ed5f1b4fb77cf5cdb99d135", size = 21305, upload-time = "2025-06-14T20:57:40.477Z" } wheels = [ @@ -3031,8 +3004,8 @@ name = "pyobjc-framework-iobluetooth" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/93/e0/74b7b10c567b66c5f38b45ab240336325a4c889f43072d90f2b90aaeb7c0/pyobjc_framework_iobluetooth-11.1.tar.gz", hash = "sha256:094fd4be60cd1371b17cb4b33a3894e0d88a11b36683912be0540a7d51de76f1", size = 300992, upload-time = "2025-06-14T20:57:41.256Z" } wheels = [ @@ -3045,8 +3018,8 @@ name = "pyobjc-framework-iobluetoothui" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-iobluetooth" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-iobluetooth", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/dd/32/872272faeab6fe471eac6962c75db72ce65c3556e00b4edebdb41aaab7cb/pyobjc_framework_iobluetoothui-11.1.tar.gz", hash = "sha256:060c721f1cd8af4452493e8153b72b572edcd2a7e3b635d79d844f885afee860", size = 22835, upload-time = "2025-06-14T20:57:42.119Z" } wheels = [ @@ -3058,8 +3031,8 @@ name = "pyobjc-framework-iosurface" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c5/ce/38ec17d860d0ee040bb737aad8ca7c7ff46bef6c9cffa47382d67682bb2d/pyobjc_framework_iosurface-11.1.tar.gz", hash = "sha256:a468b3a31e8cd70a2675a3ddc7176ab13aa521c035f11188b7a3af8fff8b148b", size = 20275, upload-time = "2025-06-14T20:57:42.742Z" } wheels = [ @@ -3071,8 +3044,8 @@ name = "pyobjc-framework-ituneslibrary" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ee/43/aebefed774b434965752f9001685af0b19c02353aa7a12d2918af0948181/pyobjc_framework_ituneslibrary-11.1.tar.gz", hash = "sha256:e2212a9340e4328056ade3c2f9d4305c71f3f6af050204a135f9fa9aa3ba9c5e", size = 47388, upload-time = "2025-06-14T20:57:43.383Z" } wheels = [ @@ -3084,8 +3057,8 @@ name = "pyobjc-framework-kernelmanagement" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/1a/b6/708f10ac16425834cb5f8b71efdbe39b42c3b1009ac0c1796a42fc98cd36/pyobjc_framework_kernelmanagement-11.1.tar.gz", hash = "sha256:e934d1638cd89e38d6c6c5d4d9901b4295acee2d39cbfe0bd91aae9832961b44", size = 12543, upload-time = "2025-06-14T20:57:44.046Z" } wheels = [ @@ -3097,8 +3070,8 @@ name = "pyobjc-framework-latentsemanticmapping" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/db/8a/4e54ee2bc77d59d770b287daf73b629e2715a2b3b31264d164398131cbad/pyobjc_framework_latentsemanticmapping-11.1.tar.gz", hash = "sha256:c6c3142301e4d375c24a47dfaeebc2f3d0fc33128a1c0a755794865b9a371145", size = 17444, upload-time = "2025-06-14T20:57:44.643Z" } wheels = [ @@ -3110,8 +3083,8 @@ name = "pyobjc-framework-launchservices" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-coreservices" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coreservices", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/2b/0a/a76b13109b8ab563fdb2d7182ca79515f132f82ac6e1c52351a6b02896a8/pyobjc_framework_launchservices-11.1.tar.gz", hash = "sha256:80b55368b1e208d6c2c58395cc7bc12a630a2a402e00e4930493e9bace22b7bb", size = 20446, upload-time = "2025-06-14T20:57:45.258Z" } wheels = [ @@ -3123,8 +3096,8 @@ name = "pyobjc-framework-libdispatch" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/be/89/7830c293ba71feb086cb1551455757f26a7e2abd12f360d375aae32a4d7d/pyobjc_framework_libdispatch-11.1.tar.gz", hash = "sha256:11a704e50a0b7dbfb01552b7d686473ffa63b5254100fdb271a1fe368dd08e87", size = 53942, upload-time = "2025-06-14T20:57:45.903Z" } wheels = [ @@ -3137,8 +3110,8 @@ name = "pyobjc-framework-libxpc" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6a/c9/7e15e38ac23f5bfb4e82bdf3b7ef88e2f56a8b4ad884009bc2d5267d2e1f/pyobjc_framework_libxpc-11.1.tar.gz", hash = "sha256:8fd7468aa520ff19915f6d793070b84be1498cb87224bee2bad1f01d8375273a", size = 49135, upload-time = "2025-06-14T20:57:46.59Z" } wheels = [ @@ -3151,9 +3124,9 @@ name = "pyobjc-framework-linkpresentation" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b9/76/22873be73f12a3a11ae57af13167a1d2379e4e7eef584de137156a00f5ef/pyobjc_framework_linkpresentation-11.1.tar.gz", hash = "sha256:a785f393b01fdaada6d7d6d8de46b7173babba205b13b44f1dc884b3695c2fc9", size = 14987, upload-time = "2025-06-14T20:57:47.277Z" } wheels = [ @@ -3165,9 +3138,9 @@ name = "pyobjc-framework-localauthentication" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-security" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-security", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e5/27/9e3195f3561574140e9b9071a36f7e0ebd18f50ade9261d23b5b9df8fccd/pyobjc_framework_localauthentication-11.1.tar.gz", hash = "sha256:3cd48907c794bd414ac68b8ac595d83c7e1453b63fc2cfc2d2035b690d31eaa1", size = 40700, upload-time = "2025-06-14T20:57:47.931Z" } wheels = [ @@ -3180,9 +3153,9 @@ name = "pyobjc-framework-localauthenticationembeddedui" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-localauthentication" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-localauthentication", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/29/7b/08c1e52487b07e9aee4c24a78f7c82a46695fa883113e3eece40f8e32d40/pyobjc_framework_localauthenticationembeddedui-11.1.tar.gz", hash = "sha256:22baf3aae606e5204e194f02bb205f244e27841ea7b4a4431303955475b4fa56", size = 14076, upload-time = "2025-06-14T20:57:48.557Z" } wheels = [ @@ -3194,8 +3167,8 @@ name = "pyobjc-framework-mailkit" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7e/7e/f22d733897e7618bd70a658b0353f5f897c583df04e7c5a2d68b99d43fbb/pyobjc_framework_mailkit-11.1.tar.gz", hash = "sha256:bf97dc44cb09b9eb9d591660dc0a41f077699976144b954caa4b9f0479211fd7", size = 32012, upload-time = "2025-06-14T20:57:49.173Z" } wheels = [ @@ -3207,10 +3180,10 @@ name = "pyobjc-framework-mapkit" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-corelocation" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-corelocation", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/57/f0/505e074f49c783f2e65ca82174fd2d4348568f3f7281c1b81af816cf83bb/pyobjc_framework_mapkit-11.1.tar.gz", hash = "sha256:f3a5016f266091be313a118a42c0ea4f951c399b5259d93639eb643dacc626f1", size = 165614, upload-time = "2025-06-14T20:57:50.362Z" } wheels = [ @@ -3223,8 +3196,8 @@ name = "pyobjc-framework-mediaaccessibility" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/8d/81/60412b423c121de0fa0aa3ef679825e1e2fe8b00fceddec7d72333ef564b/pyobjc_framework_mediaaccessibility-11.1.tar.gz", hash = "sha256:52479a998fec3d079d2d4590a945fc78c41fe7ac8c76f1964c9d8156880565a4", size = 18440, upload-time = "2025-06-14T20:57:51.126Z" } wheels = [ @@ -3236,10 +3209,10 @@ name = "pyobjc-framework-mediaextension" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-avfoundation" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coremedia" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-avfoundation", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coremedia", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e1/09/fd214dc0cf3f3bc3f528815af4799c0cb7b4bf4032703b19ea63486a132b/pyobjc_framework_mediaextension-11.1.tar.gz", hash = "sha256:85a1c8a94e9175fb364c453066ef99b95752343fd113f08a3805cad56e2fa709", size = 58489, upload-time = "2025-06-14T20:57:51.796Z" } wheels = [ @@ -3252,9 +3225,9 @@ name = "pyobjc-framework-medialibrary" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/2b/06/11ff622fb5fbdd557998a45cedd2b0a1c7ea5cc6c5cb015dd6e42ebd1c41/pyobjc_framework_medialibrary-11.1.tar.gz", hash = "sha256:102f4326f789734b7b2dfe689abd3840ca75a76fb8058bd3e4f85398ae2ce29d", size = 18706, upload-time = "2025-06-14T20:57:52.474Z" } wheels = [ @@ -3266,8 +3239,8 @@ name = "pyobjc-framework-mediaplayer" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-avfoundation" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-avfoundation", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/80/d5/daba26eb8c70af1f3823acfd7925356acc4dd75eeac4fc86dc95d94d0e15/pyobjc_framework_mediaplayer-11.1.tar.gz", hash = "sha256:d07a634b98e1b9eedd82d76f35e616525da096bd341051ea74f0971e0f2f2ddd", size = 93749, upload-time = "2025-06-14T20:57:53.165Z" } wheels = [ @@ -3279,8 +3252,8 @@ name = "pyobjc-framework-mediatoolbox" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e1/68/cc230d2dfdeb974fdcfa828de655a43ce2bf4962023fd55bbb7ab0970100/pyobjc_framework_mediatoolbox-11.1.tar.gz", hash = "sha256:97834addc5179b3165c0d8cd74cc97ad43ed4c89547724216426348aca3b822a", size = 23568, upload-time = "2025-06-14T20:57:53.913Z" } wheels = [ @@ -3293,8 +3266,8 @@ name = "pyobjc-framework-metal" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/af/cf/29fea96fd49bf72946c5dac4c43ef50f26c15e9f76edd6f15580d556aa23/pyobjc_framework_metal-11.1.tar.gz", hash = "sha256:f9fd3b7574a824632ee9b7602973da30f172d2b575dd0c0f5ef76b44cfe9f6f9", size = 446549, upload-time = "2025-06-14T20:57:54.731Z" } wheels = [ @@ -3307,8 +3280,8 @@ name = "pyobjc-framework-metalfx" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-metal" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-metal", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/10/20/4c839a356b534c161fb97e06589f418fc78cc5a0808362bdecf4f9a61a8d/pyobjc_framework_metalfx-11.1.tar.gz", hash = "sha256:555c1b895d4ba31be43930f45e219a5d7bb0e531d148a78b6b75b677cc588fd8", size = 27002, upload-time = "2025-06-14T20:57:55.949Z" } wheels = [ @@ -3321,9 +3294,9 @@ name = "pyobjc-framework-metalkit" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-metal" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-metal", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/45/cb/7e01bc61625c7a6fea9c9888c9ed35aa6bbc47cda2fcd02b6525757bc2b8/pyobjc_framework_metalkit-11.1.tar.gz", hash = "sha256:8811cd81ee9583b9330df4f2499a73dcc53f3359cb92767b409acaec9e4faa1e", size = 45135, upload-time = "2025-06-14T20:57:56.601Z" } wheels = [ @@ -3336,8 +3309,8 @@ name = "pyobjc-framework-metalperformanceshaders" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-metal" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-metal", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d0/11/5df398a158a6efe2c87ac5cae121ef2788242afe5d4302d703147b9fcd91/pyobjc_framework_metalperformanceshaders-11.1.tar.gz", hash = "sha256:8a312d090a0f51651e63d9001e6cc7c1aa04ceccf23b494cbf84b7fd3d122071", size = 302113, upload-time = "2025-06-14T20:57:57.407Z" } wheels = [ @@ -3350,8 +3323,8 @@ name = "pyobjc-framework-metalperformanceshadersgraph" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-metalperformanceshaders" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-metalperformanceshaders", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/32/c3/8d98661f7eecd1f1b0d80a80961069081b88efd3a82fbbed2d7e6050c0ad/pyobjc_framework_metalperformanceshadersgraph-11.1.tar.gz", hash = "sha256:d25225aab4edc6f786b29fe3d9badc4f3e2d0caeab1054cd4f224258c1b6dbe2", size = 105098, upload-time = "2025-06-14T20:57:58.273Z" } wheels = [ @@ -3363,8 +3336,8 @@ name = "pyobjc-framework-metrickit" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/bd/48/8ae969a51a91864000e39c1de74627b12ff587b1dbad9406f7a30dfe71f8/pyobjc_framework_metrickit-11.1.tar.gz", hash = "sha256:a79d37575489916c35840e6a07edd958be578d3be7a3d621684d028d721f0b85", size = 40952, upload-time = "2025-06-14T20:57:58.996Z" } wheels = [ @@ -3377,8 +3350,8 @@ name = "pyobjc-framework-mlcompute" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/8b/e6/f064dec650fb1209f41aba0c3074416cb9b975a7cf4d05d93036e3d917f0/pyobjc_framework_mlcompute-11.1.tar.gz", hash = "sha256:f6c4c3ea6a62e4e3927abf9783c40495aa8bb9a8c89def744b0822da58c2354b", size = 89021, upload-time = "2025-06-14T20:57:59.997Z" } wheels = [ @@ -3390,9 +3363,9 @@ name = "pyobjc-framework-modelio" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a0/27/140bf75706332729de252cc4141e8c8afe16a0e9e5818b5a23155aa3473c/pyobjc_framework_modelio-11.1.tar.gz", hash = "sha256:fad0fa2c09d468ac7e49848e144f7bbce6826f2178b3120add8960a83e5bfcb7", size = 123203, upload-time = "2025-06-14T20:58:01.035Z" } wheels = [ @@ -3405,8 +3378,8 @@ name = "pyobjc-framework-multipeerconnectivity" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/73/99/75bf6170e282d9e546b353b65af7859de8b1b27ddc431fc4afbf15423d01/pyobjc_framework_multipeerconnectivity-11.1.tar.gz", hash = "sha256:a3dacca5e6e2f1960dd2d1107d98399ff81ecf54a9852baa8ec8767dbfdbf54b", size = 26149, upload-time = "2025-06-14T20:58:01.793Z" } wheels = [ @@ -3419,8 +3392,8 @@ name = "pyobjc-framework-naturallanguage" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a2/e9/5352fbf09c5d5360405dea49fb77e53ed55acd572a94ce9a0d05f64d2b70/pyobjc_framework_naturallanguage-11.1.tar.gz", hash = "sha256:ab1fc711713aa29c32719774fc623bf2d32168aed21883970d4896e901ff4b41", size = 46120, upload-time = "2025-06-14T20:58:02.808Z" } wheels = [ @@ -3432,8 +3405,8 @@ name = "pyobjc-framework-netfs" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/68/5d/d68cc59a1c1ea61f227ed58e7b185a444d560655320b53ced155076f5b78/pyobjc_framework_netfs-11.1.tar.gz", hash = "sha256:9c49f050c8171dc37e54d05dd12a63979c8b6b565c10f05092923a2250446f50", size = 15910, upload-time = "2025-06-14T20:58:03.811Z" } wheels = [ @@ -3445,8 +3418,8 @@ name = "pyobjc-framework-network" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/0a/ee/5ea93e48eca341b274027e1532bd8629fd55d609cd9c39c2c3acf26158c3/pyobjc_framework_network-11.1.tar.gz", hash = "sha256:f6df7a58a1279bbc976fd7e2efe813afbbb18427df40463e6e2ee28fba07d2df", size = 124670, upload-time = "2025-06-14T20:58:05.491Z" } wheels = [ @@ -3459,8 +3432,8 @@ name = "pyobjc-framework-networkextension" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/71/30/d1eee738d702bbca78effdaa346a2b05359ab8a96d961b7cb44838e236ca/pyobjc_framework_networkextension-11.1.tar.gz", hash = "sha256:2b74b430ca651293e5aa90a1e7571b200d0acbf42803af87306ac8a1c70b0d4b", size = 217252, upload-time = "2025-06-14T20:58:06.311Z" } wheels = [ @@ -3473,8 +3446,8 @@ name = "pyobjc-framework-notificationcenter" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a8/4a/d3529b9bd7aae2c89d258ebc234673c5435e217a5136abd8c0aba37b916b/pyobjc_framework_notificationcenter-11.1.tar.gz", hash = "sha256:0b938053f2d6b1cea9db79313639d7eb9ddd5b2a5436a346be0887e75101e717", size = 23389, upload-time = "2025-06-14T20:58:07.136Z" } wheels = [ @@ -3487,8 +3460,8 @@ name = "pyobjc-framework-opendirectory" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/9d/02/ac56c56fdfbc24cdf87f4a624f81bbe2e371d0983529b211a18c6170e932/pyobjc_framework_opendirectory-11.1.tar.gz", hash = "sha256:319ac3424ed0350be458b78148914468a8fc13a069d62e7869e3079108e4f118", size = 188880, upload-time = "2025-06-14T20:58:08.003Z" } wheels = [ @@ -3500,8 +3473,8 @@ name = "pyobjc-framework-osakit" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/56/22/f9cdfb5de255b335f99e61a3284be7cb1552a43ed1dfe7c22cc868c23819/pyobjc_framework_osakit-11.1.tar.gz", hash = "sha256:920987da78b67578367c315d208f87e8fab01dd35825d72242909f29fb43c820", size = 22290, upload-time = "2025-06-14T20:58:09.103Z" } wheels = [ @@ -3513,10 +3486,10 @@ name = "pyobjc-framework-oslog" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coremedia" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coremedia", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/79/93/3feb7f6150b50165524750a424f5434448392123420cb4673db766c3f54a/pyobjc_framework_oslog-11.1.tar.gz", hash = "sha256:b2af409617e6b68fa1f1467c5a5679ebf59afd0cdc4b4528e1616059959a7979", size = 24689, upload-time = "2025-06-14T20:58:09.739Z" } wheels = [ @@ -3529,8 +3502,8 @@ name = "pyobjc-framework-passkit" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5c/05/063db500e7df70e39cbb5518a5a03c2acc06a1ca90b057061daea00129f3/pyobjc_framework_passkit-11.1.tar.gz", hash = "sha256:d2408b58960fca66607b483353c1ffbd751ef0bef394a1853ec414a34029566f", size = 144859, upload-time = "2025-06-14T20:58:10.761Z" } wheels = [ @@ -3543,8 +3516,8 @@ name = "pyobjc-framework-pencilkit" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/75/d0/bbbe9dadcfc37e33a63d43b381a8d9a64eca27559df38efb74d524fa6260/pyobjc_framework_pencilkit-11.1.tar.gz", hash = "sha256:9c173e0fe70179feadc3558de113a8baad61b584fe70789b263af202bfa4c6be", size = 22570, upload-time = "2025-06-14T20:58:11.538Z" } wheels = [ @@ -3556,8 +3529,8 @@ name = "pyobjc-framework-phase" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-avfoundation" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-avfoundation", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c6/d2/e9384b5b3fbcc79e8176cb39fcdd48b77f60cd1cb64f9ee4353762b037dc/pyobjc_framework_phase-11.1.tar.gz", hash = "sha256:a940d81ac5c393ae3da94144cf40af33932e0a9731244e2cfd5c9c8eb851e3fc", size = 58986, upload-time = "2025-06-14T20:58:12.196Z" } wheels = [ @@ -3569,8 +3542,8 @@ name = "pyobjc-framework-photos" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/78/b0/576652ecd05c26026ab4e75e0d81466edd570d060ce7df3d6bd812eb90d0/pyobjc_framework_photos-11.1.tar.gz", hash = "sha256:c8c3b25b14a2305047f72c7c081ff3655b3d051f7ed531476c03246798f8156d", size = 92569, upload-time = "2025-06-14T20:58:12.939Z" } wheels = [ @@ -3583,8 +3556,8 @@ name = "pyobjc-framework-photosui" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/20/bb/e6de720efde2e9718677c95c6ae3f97047be437cda7a0f050cd1d6d2a434/pyobjc_framework_photosui-11.1.tar.gz", hash = "sha256:1c7ffab4860ce3e2b50feeed4f1d84488a9e38546db0bec09484d8d141c650df", size = 48443, upload-time = "2025-06-14T20:58:13.626Z" } wheels = [ @@ -3597,8 +3570,8 @@ name = "pyobjc-framework-preferencepanes" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/34/ac/9324602daf9916308ebf1935b8a4b91c93b9ae993dcd0da731c0619c2836/pyobjc_framework_preferencepanes-11.1.tar.gz", hash = "sha256:6e4a55195ec9fc921e0eaad6b3038d0ab91f0bb2f39206aa6fccd24b14a0f1d8", size = 26212, upload-time = "2025-06-14T20:58:14.361Z" } wheels = [ @@ -3610,8 +3583,8 @@ name = "pyobjc-framework-pushkit" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/9f/f0/92d0eb26bf8af8ebf6b5b88df77e70b807de11f01af0162e0a429fcfb892/pyobjc_framework_pushkit-11.1.tar.gz", hash = "sha256:540769a4aadc3c9f08beca8496fe305372501eb28fdbca078db904a07b8e10f4", size = 21362, upload-time = "2025-06-14T20:58:15.642Z" } wheels = [ @@ -3624,8 +3597,8 @@ name = "pyobjc-framework-quartz" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c7/ac/6308fec6c9ffeda9942fef72724f4094c6df4933560f512e63eac37ebd30/pyobjc_framework_quartz-11.1.tar.gz", hash = "sha256:a57f35ccfc22ad48c87c5932818e583777ff7276605fef6afad0ac0741169f75", size = 3953275, upload-time = "2025-06-14T20:58:17.924Z" } wheels = [ @@ -3638,9 +3611,9 @@ name = "pyobjc-framework-quicklookthumbnailing" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/aa/98/6e87f360c2dfc870ae7870b8a25fdea8ddf1d62092c755686cebe7ec1a07/pyobjc_framework_quicklookthumbnailing-11.1.tar.gz", hash = "sha256:1614dc108c1d45bbf899ea84b8691288a5b1d25f2d6f0c57dfffa962b7a478c3", size = 16527, upload-time = "2025-06-14T20:58:20.811Z" } wheels = [ @@ -3652,8 +3625,8 @@ name = "pyobjc-framework-replaykit" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c8/4f/014e95f0fd6842d7fcc3d443feb6ee65ac69d06c66ffa9327fc33ceb7c27/pyobjc_framework_replaykit-11.1.tar.gz", hash = "sha256:6919baa123a6d8aad769769fcff87369e13ee7bae11b955a8185a406a651061b", size = 26132, upload-time = "2025-06-14T20:58:21.853Z" } wheels = [ @@ -3666,8 +3639,8 @@ name = "pyobjc-framework-safariservices" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/1a/fc/c47d2abf3c1de6db21d685cace76a0931d594aa369e3d090260295273f6e/pyobjc_framework_safariservices-11.1.tar.gz", hash = "sha256:39a17df1a8e1c339457f3acbff0dc0eae4681d158f9d783a11995cf484aa9cd0", size = 34905, upload-time = "2025-06-14T20:58:22.492Z" } wheels = [ @@ -3680,9 +3653,9 @@ name = "pyobjc-framework-safetykit" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/28/cc/f6aa5d6f45179bd084416511be4e5b0dd0752cb76daa93869e6edb806096/pyobjc_framework_safetykit-11.1.tar.gz", hash = "sha256:c6b44e0cf69e27584ac3ef3d8b771d19a7c2ccd9c6de4138d091358e036322d4", size = 21240, upload-time = "2025-06-14T20:58:23.132Z" } wheels = [ @@ -3695,9 +3668,9 @@ name = "pyobjc-framework-scenekit" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/64/cf/2d89777120d2812e7ee53c703bf6fc8968606c29ddc1351bc63f0a2a5692/pyobjc_framework_scenekit-11.1.tar.gz", hash = "sha256:82941f1e5040114d6e2c9fd35507244e102ef561c637686091b71a7ad0f31306", size = 214118, upload-time = "2025-06-14T20:58:24.003Z" } wheels = [ @@ -3710,9 +3683,9 @@ name = "pyobjc-framework-screencapturekit" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coremedia" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coremedia", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/32/a5/9bd1f1ad1773a1304ccde934ff39e0f0a0b0034441bf89166aea649606de/pyobjc_framework_screencapturekit-11.1.tar.gz", hash = "sha256:11443781a30ed446f2d892c9e6642ca4897eb45f1a1411136ca584997fa739e0", size = 53548, upload-time = "2025-06-14T20:58:24.837Z" } wheels = [ @@ -3725,8 +3698,8 @@ name = "pyobjc-framework-screensaver" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7c/f6/f2d48583b29fc67b64aa1f415fd51faf003d045cdb1f3acab039b9a3f59f/pyobjc_framework_screensaver-11.1.tar.gz", hash = "sha256:d5fbc9dc076cc574ead183d521840b56be0c160415e43cb8e01cfddd6d6372c2", size = 24302, upload-time = "2025-06-14T20:58:25.52Z" } wheels = [ @@ -3739,8 +3712,8 @@ name = "pyobjc-framework-screentime" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/82/33/ebed70a1de134de936bb9a12d5c76f24e1e335ff4964f9bb0af9b09607f1/pyobjc_framework_screentime-11.1.tar.gz", hash = "sha256:9bb8269456bbb674e1421182efe49f9168ceefd4e7c497047c7bf63e2f510a34", size = 14875, upload-time = "2025-06-14T20:58:26.179Z" } wheels = [ @@ -3752,8 +3725,8 @@ name = "pyobjc-framework-scriptingbridge" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/8e/c1/5b1dd01ff173df4c6676f97405113458918819cb2064c1735b61948e8800/pyobjc_framework_scriptingbridge-11.1.tar.gz", hash = "sha256:604445c759210a35d86d3e0dfcde0aac8e5e3e9d9e35759e0723952138843699", size = 23155, upload-time = "2025-06-14T20:58:26.812Z" } wheels = [ @@ -3766,8 +3739,8 @@ name = "pyobjc-framework-searchkit" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-coreservices" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coreservices", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/6e/20/61b73fddae0d1a94f5defb0cd4b4f391ec03bfcce7ebe830cb827d5e208a/pyobjc_framework_searchkit-11.1.tar.gz", hash = "sha256:13a194eefcf1359ce9972cd92f2aadddf103f3efb1b18fd578ba5367dff3c10c", size = 30918, upload-time = "2025-06-14T20:58:27.447Z" } wheels = [ @@ -3779,8 +3752,8 @@ name = "pyobjc-framework-security" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ee/6f/ba50ed2d9c1192c67590a7cfefa44fc5f85c776d1e25beb224dec32081f6/pyobjc_framework_security-11.1.tar.gz", hash = "sha256:dabcee6987c6bae575e2d1ef0fcbe437678c4f49f1c25a4b131a5e960f31a2da", size = 302291, upload-time = "2025-06-14T20:58:28.506Z" } wheels = [ @@ -3793,9 +3766,9 @@ name = "pyobjc-framework-securityfoundation" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-security" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-security", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/5c/d4/19591dd0938a45b6d8711ef9ae5375b87c37a55b45d79c52d6f83a8d991f/pyobjc_framework_securityfoundation-11.1.tar.gz", hash = "sha256:b3c4cf70735a93e9df40f3a14478143959c415778f27be8c0dc9ae0c5b696b92", size = 13270, upload-time = "2025-06-14T20:58:29.304Z" } wheels = [ @@ -3807,9 +3780,9 @@ name = "pyobjc-framework-securityinterface" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-security" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-security", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a1/be/c846651c3e7f38a637c40ae1bcda9f14237c2395637c3a188df4f733c727/pyobjc_framework_securityinterface-11.1.tar.gz", hash = "sha256:e7aa6373e525f3ae05d71276e821a6348c53fec9f812b90eec1dbadfcb507bc9", size = 37648, upload-time = "2025-06-14T20:58:29.932Z" } wheels = [ @@ -3822,9 +3795,9 @@ name = "pyobjc-framework-securityui" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-security" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-security", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/07/5b/3b5585d56e0bcaba82e0661224bbc7aaf29fba6b10498971dbe08b2b490a/pyobjc_framework_securityui-11.1.tar.gz", hash = "sha256:e80c93e8a56bf89e4c0333047b9f8219752dd6de290681e9e2e2b2e26d69e92d", size = 12179, upload-time = "2025-06-14T20:58:30.928Z" } wheels = [ @@ -3836,9 +3809,9 @@ name = "pyobjc-framework-sensitivecontentanalysis" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/56/7b/e28f6b30d99e9d464427a07ada82b33cd3292f310bf478a1824051d066b9/pyobjc_framework_sensitivecontentanalysis-11.1.tar.gz", hash = "sha256:5b310515c7386f7afaf13e4632d7d9590688182bb7b563f8026c304bdf317308", size = 12796, upload-time = "2025-06-14T20:58:31.488Z" } wheels = [ @@ -3850,8 +3823,8 @@ name = "pyobjc-framework-servicemanagement" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/20/c6/32e11599d9d232311607b79eb2d1d21c52eaaf001599ea85f8771a933fa2/pyobjc_framework_servicemanagement-11.1.tar.gz", hash = "sha256:90a07164da49338480e0e135b445acc6ae7c08549a2037d1e512d2605fedd80a", size = 16645, upload-time = "2025-06-14T20:58:32.062Z" } wheels = [ @@ -3863,8 +3836,8 @@ name = "pyobjc-framework-sharedwithyou" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-sharedwithyoucore" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-sharedwithyoucore", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/fe/a5/e299fbd0c13d4fac9356459f21372f6eef4279d0fbc99ba316d88dfbbfb4/pyobjc_framework_sharedwithyou-11.1.tar.gz", hash = "sha256:ece3a28a3083d0bcad0ac95b01f0eb699b9d2d0c02c61305bfd402678753ff6e", size = 34216, upload-time = "2025-06-14T20:58:32.75Z" } wheels = [ @@ -3877,8 +3850,8 @@ name = "pyobjc-framework-sharedwithyoucore" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/79/a3/1ca6ff1b785772c7c5a38a7c017c6f971b1eda638d6a0aab3bbde18ac086/pyobjc_framework_sharedwithyoucore-11.1.tar.gz", hash = "sha256:790050d25f47bda662a9f008b17ca640ac2460f2559a56b17995e53f2f44ed73", size = 29459, upload-time = "2025-06-14T20:58:33.422Z" } wheels = [ @@ -3891,8 +3864,8 @@ name = "pyobjc-framework-shazamkit" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/de/08/ba739b97f1e441653bae8da5dd1e441bbbfa43940018d21edb60da7dd163/pyobjc_framework_shazamkit-11.1.tar.gz", hash = "sha256:c6e3c9ab8744d9319a89b78ae6f185bb5704efb68509e66d77bcd1f84a9446d6", size = 25797, upload-time = "2025-06-14T20:58:34.086Z" } wheels = [ @@ -3905,8 +3878,8 @@ name = "pyobjc-framework-social" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/07/2e/cc7707b7a40df392c579087947049f3e1f0e00597e7151ec411f654d8bef/pyobjc_framework_social-11.1.tar.gz", hash = "sha256:fbc09d7b00dad45b547f9b2329f4dcee3f5a50e2348de1870de0bd7be853a5b7", size = 14540, upload-time = "2025-06-14T20:58:35.116Z" } wheels = [ @@ -3918,8 +3891,8 @@ name = "pyobjc-framework-soundanalysis" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e0/d4/b9497dbb57afdf0d22f61bb6e776a6f46cf9294c890448acde5b46dd61f3/pyobjc_framework_soundanalysis-11.1.tar.gz", hash = "sha256:42cd25b7e0f343d8b59367f72b5dae96cf65696bdb8eeead8d7424ed37aa1434", size = 16539, upload-time = "2025-06-14T20:58:35.813Z" } wheels = [ @@ -3931,8 +3904,8 @@ name = "pyobjc-framework-speech" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/67/76/2a1fd7637b2c662349ede09806e159306afeebfba18fb062ad053b41d811/pyobjc_framework_speech-11.1.tar.gz", hash = "sha256:d382977208c3710eacea89e05eae4578f1638bb5a7b667c06971e3d34e96845c", size = 41179, upload-time = "2025-06-14T20:58:36.43Z" } wheels = [ @@ -3945,9 +3918,9 @@ name = "pyobjc-framework-spritekit" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/16/02/2e253ba4f7fad6efe05fd5fcf44aede093f6c438d608d67c6c6623a1846d/pyobjc_framework_spritekit-11.1.tar.gz", hash = "sha256:914da6e846573cac8db5e403dec9a3e6f6edf5211f9b7e429734924d00f65108", size = 130297, upload-time = "2025-06-14T20:58:37.113Z" } wheels = [ @@ -3960,8 +3933,8 @@ name = "pyobjc-framework-storekit" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/44/a0/58cab9ebc9ac9282e1d4734b1987d1c3cd652b415ec3e678fcc5e735d279/pyobjc_framework_storekit-11.1.tar.gz", hash = "sha256:85acc30c0bfa120b37c3c5ac693fe9ad2c2e351ee7a1f9ea6f976b0c311ff164", size = 76421, upload-time = "2025-06-14T20:58:37.86Z" } wheels = [ @@ -3974,8 +3947,8 @@ name = "pyobjc-framework-symbols" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/cd/af/7191276204bd3e7db1d0a3e490a869956606f77f7a303a04d92a5d0c3f7b/pyobjc_framework_symbols-11.1.tar.gz", hash = "sha256:0e09b7813ef2ebdca7567d3179807444dd60f3f393202b35b755d4e1baf99982", size = 13377, upload-time = "2025-06-14T20:58:38.542Z" } wheels = [ @@ -3987,9 +3960,9 @@ name = "pyobjc-framework-syncservices" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coredata" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coredata", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/69/45/cd9fa83ed1d75be7130fb8e41c375f05b5d6621737ec37e9d8da78676613/pyobjc_framework_syncservices-11.1.tar.gz", hash = "sha256:0f141d717256b98c17ec2eddbc983c4bd39dfa00dc0c31b4174742e73a8447fe", size = 57996, upload-time = "2025-06-14T20:58:39.146Z" } wheels = [ @@ -4002,8 +3975,8 @@ name = "pyobjc-framework-systemconfiguration" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e2/3d/41590c0afc72e93d911348fbde0c9c1071ff53c6f86df42df64b21174bb9/pyobjc_framework_systemconfiguration-11.1.tar.gz", hash = "sha256:f30ed0e9a8233fecb06522e67795918ab230ddcc4a18e15494eff7532f4c3ae1", size = 143410, upload-time = "2025-06-14T20:58:39.917Z" } wheels = [ @@ -4016,8 +3989,8 @@ name = "pyobjc-framework-systemextensions" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b4/57/4609fd9183383616b1e643c2489ad774335f679523a974b9ce346a6d4d5b/pyobjc_framework_systemextensions-11.1.tar.gz", hash = "sha256:8ff9f0aad14dcdd07dd47545c1dd20df7a286306967b0a0232c81fcc382babe6", size = 23062, upload-time = "2025-06-14T20:58:40.686Z" } wheels = [ @@ -4030,8 +4003,8 @@ name = "pyobjc-framework-threadnetwork" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e7/a4/5400a222ced0e4f077a8f4dd0188e08e2af4762e72ed0ed39f9d27feefc9/pyobjc_framework_threadnetwork-11.1.tar.gz", hash = "sha256:73a32782f44b61ca0f8a4a9811c36b1ca1cdcf96c8a3ba4de35d8e8e58a86ad5", size = 13572, upload-time = "2025-06-14T20:58:41.311Z" } wheels = [ @@ -4043,8 +4016,8 @@ name = "pyobjc-framework-uniformtypeidentifiers" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c5/4f/066ed1c69352ccc29165f45afb302f8c9c2b5c6f33ee3abfa41b873c07e5/pyobjc_framework_uniformtypeidentifiers-11.1.tar.gz", hash = "sha256:86c499bec8953aeb0c95af39b63f2592832384f09f12523405650b5d5f1ed5e9", size = 20599, upload-time = "2025-06-14T20:58:41.945Z" } wheels = [ @@ -4056,8 +4029,8 @@ name = "pyobjc-framework-usernotifications" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b4/4c/e7e180fcd06c246c37f218bcb01c40ea0213fde5ace3c09d359e60dcaafd/pyobjc_framework_usernotifications-11.1.tar.gz", hash = "sha256:38fc763afa7854b41ddfca8803f679a7305d278af8a7ad02044adc1265699996", size = 55428, upload-time = "2025-06-14T20:58:42.572Z" } wheels = [ @@ -4070,9 +4043,9 @@ name = "pyobjc-framework-usernotificationsui" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-usernotifications" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-usernotifications", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/d2/c4/03d97bd3adcee9b857533cb42967df0d019f6a034adcdbcfca2569d415b2/pyobjc_framework_usernotificationsui-11.1.tar.gz", hash = "sha256:18e0182bddd10381884530d6a28634ebb3280912592f8f2ad5bac2a9308c6a65", size = 14123, upload-time = "2025-06-14T20:58:43.267Z" } wheels = [ @@ -4084,8 +4057,8 @@ name = "pyobjc-framework-videosubscriberaccount" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/aa/00/cd9d93d06204bbb7fe68fb97022b0dd4ecdf8af3adb6d70a41e22c860d55/pyobjc_framework_videosubscriberaccount-11.1.tar.gz", hash = "sha256:2dd78586260fcee51044e129197e8bf2e157176e02babeec2f873afa4235d8c6", size = 28856, upload-time = "2025-06-14T20:58:43.903Z" } wheels = [ @@ -4097,10 +4070,10 @@ name = "pyobjc-framework-videotoolbox" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coremedia" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coremedia", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e5/e3/df9096f54ae1f27cab8f922ee70cbda5d80f8c1d12734c38580829858133/pyobjc_framework_videotoolbox-11.1.tar.gz", hash = "sha256:a27985656e1b639cdb102fcc727ebc39f71bb1a44cdb751c8c80cc9fe938f3a9", size = 88551, upload-time = "2025-06-14T20:58:44.566Z" } wheels = [ @@ -4113,8 +4086,8 @@ name = "pyobjc-framework-virtualization" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/f1/ff/57214e8f42755eeaad516a7e673dae4341b8742005d368ecc22c7a790b0b/pyobjc_framework_virtualization-11.1.tar.gz", hash = "sha256:4221ee5eb669e43a2ff46e04178bec149af2d65205deb5d4db5fa62ea060e022", size = 78633, upload-time = "2025-06-14T20:58:45.358Z" } wheels = [ @@ -4127,10 +4100,10 @@ name = "pyobjc-framework-vision" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, - { name = "pyobjc-framework-coreml" }, - { name = "pyobjc-framework-quartz" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-coreml", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-quartz", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/40/a8/7128da4d0a0103cabe58910a7233e2f98d18c590b1d36d4b3efaaedba6b9/pyobjc_framework_vision-11.1.tar.gz", hash = "sha256:26590512ee7758da3056499062a344b8a351b178be66d4b719327884dde4216b", size = 133721, upload-time = "2025-06-14T20:58:46.095Z" } wheels = [ @@ -4143,8 +4116,8 @@ name = "pyobjc-framework-webkit" version = "11.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "pyobjc-core" }, - { name = "pyobjc-framework-cocoa" }, + { name = "pyobjc-core", marker = "sys_platform == 'darwin'" }, + { name = "pyobjc-framework-cocoa", marker = "sys_platform == 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/92/04/fb3d0b68994f7e657ef00c1ac5fc1c04ae2fc7ea581d647f5ae1f6739b14/pyobjc_framework_webkit-11.1.tar.gz", hash = "sha256:27e701c7aaf4f24fc7e601a128e2ef14f2773f4ab071b9db7438dc5afb5053ae", size = 717102, upload-time = "2025-06-14T20:58:47.461Z" } wheels = [ @@ -4335,8 +4308,8 @@ wheels = [ [[package]] name = "pytest-xdist" -version = "3.7.1.dev3+g909e97b" -source = { git = "https://github.com/sshane/pytest-xdist?rev=909e97b49d12401c10608f9d777bfc9dab8a4413#909e97b49d12401c10608f9d777bfc9dab8a4413" } +version = "3.7.1.dev24+g2b4372b" +source = { git = "https://github.com/sshane/pytest-xdist?rev=2b4372bd62699fb412c4fe2f95bf9f01bd2018da#2b4372bd62699fb412c4fe2f95bf9f01bd2018da" } dependencies = [ { name = "execnet" }, { name = "pytest" }, @@ -4359,7 +4332,7 @@ name = "python-xlib" version = "0.33" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "six" }, + { name = "six", marker = "sys_platform != 'darwin'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/86/f5/8c0653e5bb54e0cbdfe27bf32d41f27bc4e12faa8742778c17f2a71be2c0/python-xlib-0.33.tar.gz", hash = "sha256:55af7906a2c75ce6cb280a584776080602444f75815a7aff4d287bb2d7018b32", size = 269068, upload-time = "2022-12-25T18:53:00.824Z" } wheels = [ @@ -4562,25 +4535,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" }, ] -[[package]] -name = "rerun-sdk" -version = "0.24.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "attrs" }, - { name = "numpy" }, - { name = "pillow" }, - { name = "pyarrow" }, - { name = "typing-extensions" }, -] -wheels = [ - { url = "https://files.pythonhosted.org/packages/bd/c8/c001c855e91fbc09ba7340839070f7452cd6dfd56e40e38a1a6cc826424c/rerun_sdk-0.24.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:3d3f0e63f0a26c3f058d28d6267958d4d7bf03f63e2a16a45cb6ef4161dcb55e", size = 84079586, upload-time = "2025-07-17T15:21:39.835Z" }, - { url = "https://files.pythonhosted.org/packages/f2/df/751bda39d62304f22776b30edf8efcfb8920b4e8c6a388ee12ccd7c6e88f/rerun_sdk-0.24.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:35ee215d186bc410f4c38c7dc9f260604e857695cd9df996510326107d73c238", size = 78344845, upload-time = "2025-07-17T15:21:45.002Z" }, - { url = "https://files.pythonhosted.org/packages/30/0f/e0d37550744d76968eb5affc2aff748cf06a93e90e013fe127ede831f98d/rerun_sdk-0.24.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:a0f8ac65ab0da000c9f23ef13440581050fa05f071ed23653cd10f134945479d", size = 86327955, upload-time = "2025-07-17T15:21:50.016Z" }, - { url = "https://files.pythonhosted.org/packages/25/6d/94dc5388c0223b33843c1ae7dae6627caf543faf5d49c4f7ebfbdc3e4f0e/rerun_sdk-0.24.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:a4e5c7452df556fc5f64667cb3974ddcf01e3fc03374748348de6855f2919397", size = 90706767, upload-time = "2025-07-17T15:21:54.994Z" }, - { url = "https://files.pythonhosted.org/packages/00/88/f3c738ae799423fe0615fb6e6b94d2c02e28a090bea0db260e38ff1113ed/rerun_sdk-0.24.0-cp39-abi3-win_amd64.whl", hash = "sha256:4c5049f04f4b224cc342d831384b510d157bd7eff79aa267a88b546d0d12b36e", size = 72867282, upload-time = "2025-07-17T15:22:01.032Z" }, -] - [[package]] name = "ruamel-yaml" version = "0.18.14" @@ -4630,27 +4584,27 @@ wheels = [ [[package]] name = "ruff" -version = "0.12.5" +version = "0.12.7" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/30/cd/01015eb5034605fd98d829c5839ec2c6b4582b479707f7c1c2af861e8258/ruff-0.12.5.tar.gz", hash = "sha256:b209db6102b66f13625940b7f8c7d0f18e20039bb7f6101fbdac935c9612057e", size = 5170722, upload-time = "2025-07-24T13:26:37.456Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a1/81/0bd3594fa0f690466e41bd033bdcdf86cba8288345ac77ad4afbe5ec743a/ruff-0.12.7.tar.gz", hash = "sha256:1fc3193f238bc2d7968772c82831a4ff69252f673be371fb49663f0068b7ec71", size = 5197814, upload-time = "2025-07-29T22:32:35.877Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d4/de/ad2f68f0798ff15dd8c0bcc2889558970d9a685b3249565a937cd820ad34/ruff-0.12.5-py3-none-linux_armv6l.whl", hash = "sha256:1de2c887e9dec6cb31fcb9948299de5b2db38144e66403b9660c9548a67abd92", size = 11819133, upload-time = "2025-07-24T13:25:56.369Z" }, - { url = "https://files.pythonhosted.org/packages/f8/fc/c6b65cd0e7fbe60f17e7ad619dca796aa49fbca34bb9bea5f8faf1ec2643/ruff-0.12.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:d1ab65e7d8152f519e7dea4de892317c9da7a108da1c56b6a3c1d5e7cf4c5e9a", size = 12501114, upload-time = "2025-07-24T13:25:59.471Z" }, - { url = "https://files.pythonhosted.org/packages/c5/de/c6bec1dce5ead9f9e6a946ea15e8d698c35f19edc508289d70a577921b30/ruff-0.12.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:962775ed5b27c7aa3fdc0d8f4d4433deae7659ef99ea20f783d666e77338b8cf", size = 11716873, upload-time = "2025-07-24T13:26:01.496Z" }, - { url = "https://files.pythonhosted.org/packages/a1/16/cf372d2ebe91e4eb5b82a2275c3acfa879e0566a7ac94d331ea37b765ac8/ruff-0.12.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:73b4cae449597e7195a49eb1cdca89fd9fbb16140c7579899e87f4c85bf82f73", size = 11958829, upload-time = "2025-07-24T13:26:03.721Z" }, - { url = "https://files.pythonhosted.org/packages/25/bf/cd07e8f6a3a6ec746c62556b4c4b79eeb9b0328b362bb8431b7b8afd3856/ruff-0.12.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8b13489c3dc50de5e2d40110c0cce371e00186b880842e245186ca862bf9a1ac", size = 11626619, upload-time = "2025-07-24T13:26:06.118Z" }, - { url = "https://files.pythonhosted.org/packages/d8/c9/c2ccb3b8cbb5661ffda6925f81a13edbb786e623876141b04919d1128370/ruff-0.12.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f1504fea81461cf4841778b3ef0a078757602a3b3ea4b008feb1308cb3f23e08", size = 13221894, upload-time = "2025-07-24T13:26:08.292Z" }, - { url = "https://files.pythonhosted.org/packages/6b/58/68a5be2c8e5590ecdad922b2bcd5583af19ba648f7648f95c51c3c1eca81/ruff-0.12.5-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:c7da4129016ae26c32dfcbd5b671fe652b5ab7fc40095d80dcff78175e7eddd4", size = 14163909, upload-time = "2025-07-24T13:26:10.474Z" }, - { url = "https://files.pythonhosted.org/packages/bd/d1/ef6b19622009ba8386fdb792c0743f709cf917b0b2f1400589cbe4739a33/ruff-0.12.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ca972c80f7ebcfd8af75a0f18b17c42d9f1ef203d163669150453f50ca98ab7b", size = 13583652, upload-time = "2025-07-24T13:26:13.381Z" }, - { url = "https://files.pythonhosted.org/packages/62/e3/1c98c566fe6809a0c83751d825a03727f242cdbe0d142c9e292725585521/ruff-0.12.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8dbbf9f25dfb501f4237ae7501d6364b76a01341c6f1b2cd6764fe449124bb2a", size = 12700451, upload-time = "2025-07-24T13:26:15.488Z" }, - { url = "https://files.pythonhosted.org/packages/24/ff/96058f6506aac0fbc0d0fc0d60b0d0bd746240a0594657a2d94ad28033ba/ruff-0.12.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c47dea6ae39421851685141ba9734767f960113d51e83fd7bb9958d5be8763a", size = 12937465, upload-time = "2025-07-24T13:26:17.808Z" }, - { url = "https://files.pythonhosted.org/packages/eb/d3/68bc5e7ab96c94b3589d1789f2dd6dd4b27b263310019529ac9be1e8f31b/ruff-0.12.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:c5076aa0e61e30f848846f0265c873c249d4b558105b221be1828f9f79903dc5", size = 11771136, upload-time = "2025-07-24T13:26:20.422Z" }, - { url = "https://files.pythonhosted.org/packages/52/75/7356af30a14584981cabfefcf6106dea98cec9a7af4acb5daaf4b114845f/ruff-0.12.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:a5a4c7830dadd3d8c39b1cc85386e2c1e62344f20766be6f173c22fb5f72f293", size = 11601644, upload-time = "2025-07-24T13:26:22.928Z" }, - { url = "https://files.pythonhosted.org/packages/c2/67/91c71d27205871737cae11025ee2b098f512104e26ffd8656fd93d0ada0a/ruff-0.12.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:46699f73c2b5b137b9dc0fc1a190b43e35b008b398c6066ea1350cce6326adcb", size = 12478068, upload-time = "2025-07-24T13:26:26.134Z" }, - { url = "https://files.pythonhosted.org/packages/34/04/b6b00383cf2f48e8e78e14eb258942fdf2a9bf0287fbf5cdd398b749193a/ruff-0.12.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:5a655a0a0d396f0f072faafc18ebd59adde8ca85fb848dc1b0d9f024b9c4d3bb", size = 12991537, upload-time = "2025-07-24T13:26:28.533Z" }, - { url = "https://files.pythonhosted.org/packages/3e/b9/053d6445dc7544fb6594785056d8ece61daae7214859ada4a152ad56b6e0/ruff-0.12.5-py3-none-win32.whl", hash = "sha256:dfeb2627c459b0b78ca2bbdc38dd11cc9a0a88bf91db982058b26ce41714ffa9", size = 11751575, upload-time = "2025-07-24T13:26:30.835Z" }, - { url = "https://files.pythonhosted.org/packages/bc/0f/ab16e8259493137598b9149734fec2e06fdeda9837e6f634f5c4e35916da/ruff-0.12.5-py3-none-win_amd64.whl", hash = "sha256:ae0d90cf5f49466c954991b9d8b953bd093c32c27608e409ae3564c63c5306a5", size = 12882273, upload-time = "2025-07-24T13:26:32.929Z" }, - { url = "https://files.pythonhosted.org/packages/00/db/c376b0661c24cf770cb8815268190668ec1330eba8374a126ceef8c72d55/ruff-0.12.5-py3-none-win_arm64.whl", hash = "sha256:48cdbfc633de2c5c37d9f090ba3b352d1576b0015bfc3bc98eaf230275b7e805", size = 11951564, upload-time = "2025-07-24T13:26:34.994Z" }, + { url = "https://files.pythonhosted.org/packages/e1/d2/6cb35e9c85e7a91e8d22ab32ae07ac39cc34a71f1009a6f9e4a2a019e602/ruff-0.12.7-py3-none-linux_armv6l.whl", hash = "sha256:76e4f31529899b8c434c3c1dede98c4483b89590e15fb49f2d46183801565303", size = 11852189, upload-time = "2025-07-29T22:31:41.281Z" }, + { url = "https://files.pythonhosted.org/packages/63/5b/a4136b9921aa84638f1a6be7fb086f8cad0fde538ba76bda3682f2599a2f/ruff-0.12.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:789b7a03e72507c54fb3ba6209e4bb36517b90f1a3569ea17084e3fd295500fb", size = 12519389, upload-time = "2025-07-29T22:31:54.265Z" }, + { url = "https://files.pythonhosted.org/packages/a8/c9/3e24a8472484269b6b1821794141f879c54645a111ded4b6f58f9ab0705f/ruff-0.12.7-py3-none-macosx_11_0_arm64.whl", hash = "sha256:2e1c2a3b8626339bb6369116e7030a4cf194ea48f49b64bb505732a7fce4f4e3", size = 11743384, upload-time = "2025-07-29T22:31:59.575Z" }, + { url = "https://files.pythonhosted.org/packages/26/7c/458dd25deeb3452c43eaee853c0b17a1e84169f8021a26d500ead77964fd/ruff-0.12.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32dec41817623d388e645612ec70d5757a6d9c035f3744a52c7b195a57e03860", size = 11943759, upload-time = "2025-07-29T22:32:01.95Z" }, + { url = "https://files.pythonhosted.org/packages/7f/8b/658798472ef260ca050e400ab96ef7e85c366c39cf3dfbef4d0a46a528b6/ruff-0.12.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:47ef751f722053a5df5fa48d412dbb54d41ab9b17875c6840a58ec63ff0c247c", size = 11654028, upload-time = "2025-07-29T22:32:04.367Z" }, + { url = "https://files.pythonhosted.org/packages/a8/86/9c2336f13b2a3326d06d39178fd3448dcc7025f82514d1b15816fe42bfe8/ruff-0.12.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a828a5fc25a3efd3e1ff7b241fd392686c9386f20e5ac90aa9234a5faa12c423", size = 13225209, upload-time = "2025-07-29T22:32:06.952Z" }, + { url = "https://files.pythonhosted.org/packages/76/69/df73f65f53d6c463b19b6b312fd2391dc36425d926ec237a7ed028a90fc1/ruff-0.12.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:5726f59b171111fa6a69d82aef48f00b56598b03a22f0f4170664ff4d8298efb", size = 14182353, upload-time = "2025-07-29T22:32:10.053Z" }, + { url = "https://files.pythonhosted.org/packages/58/1e/de6cda406d99fea84b66811c189b5ea139814b98125b052424b55d28a41c/ruff-0.12.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:74e6f5c04c4dd4aba223f4fe6e7104f79e0eebf7d307e4f9b18c18362124bccd", size = 13631555, upload-time = "2025-07-29T22:32:12.644Z" }, + { url = "https://files.pythonhosted.org/packages/6f/ae/625d46d5164a6cc9261945a5e89df24457dc8262539ace3ac36c40f0b51e/ruff-0.12.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d0bfe4e77fba61bf2ccadf8cf005d6133e3ce08793bbe870dd1c734f2699a3e", size = 12667556, upload-time = "2025-07-29T22:32:15.312Z" }, + { url = "https://files.pythonhosted.org/packages/55/bf/9cb1ea5e3066779e42ade8d0cd3d3b0582a5720a814ae1586f85014656b6/ruff-0.12.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06bfb01e1623bf7f59ea749a841da56f8f653d641bfd046edee32ede7ff6c606", size = 12939784, upload-time = "2025-07-29T22:32:17.69Z" }, + { url = "https://files.pythonhosted.org/packages/55/7f/7ead2663be5627c04be83754c4f3096603bf5e99ed856c7cd29618c691bd/ruff-0.12.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e41df94a957d50083fd09b916d6e89e497246698c3f3d5c681c8b3e7b9bb4ac8", size = 11771356, upload-time = "2025-07-29T22:32:20.134Z" }, + { url = "https://files.pythonhosted.org/packages/17/40/a95352ea16edf78cd3a938085dccc55df692a4d8ba1b3af7accbe2c806b0/ruff-0.12.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:4000623300563c709458d0ce170c3d0d788c23a058912f28bbadc6f905d67afa", size = 11612124, upload-time = "2025-07-29T22:32:22.645Z" }, + { url = "https://files.pythonhosted.org/packages/4d/74/633b04871c669e23b8917877e812376827c06df866e1677f15abfadc95cb/ruff-0.12.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:69ffe0e5f9b2cf2b8e289a3f8945b402a1b19eff24ec389f45f23c42a3dd6fb5", size = 12479945, upload-time = "2025-07-29T22:32:24.765Z" }, + { url = "https://files.pythonhosted.org/packages/be/34/c3ef2d7799c9778b835a76189c6f53c179d3bdebc8c65288c29032e03613/ruff-0.12.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:a07a5c8ffa2611a52732bdc67bf88e243abd84fe2d7f6daef3826b59abbfeda4", size = 12998677, upload-time = "2025-07-29T22:32:27.022Z" }, + { url = "https://files.pythonhosted.org/packages/77/ab/aca2e756ad7b09b3d662a41773f3edcbd262872a4fc81f920dc1ffa44541/ruff-0.12.7-py3-none-win32.whl", hash = "sha256:c928f1b2ec59fb77dfdf70e0419408898b63998789cc98197e15f560b9e77f77", size = 11756687, upload-time = "2025-07-29T22:32:29.381Z" }, + { url = "https://files.pythonhosted.org/packages/b4/71/26d45a5042bc71db22ddd8252ca9d01e9ca454f230e2996bb04f16d72799/ruff-0.12.7-py3-none-win_amd64.whl", hash = "sha256:9c18f3d707ee9edf89da76131956aba1270c6348bfee8f6c647de841eac7194f", size = 12912365, upload-time = "2025-07-29T22:32:31.517Z" }, + { url = "https://files.pythonhosted.org/packages/4c/9b/0b8aa09817b63e78d94b4977f18b1fcaead3165a5ee49251c5d5c245bb2d/ruff-0.12.7-py3-none-win_arm64.whl", hash = "sha256:dfce05101dbd11833a0776716d5d1578641b7fddb537fe7fa956ab85d1769b69", size = 11982083, upload-time = "2025-07-29T22:32:33.881Z" }, ] [[package]] @@ -4664,15 +4618,15 @@ wheels = [ [[package]] name = "sentry-sdk" -version = "2.33.2" +version = "2.34.0" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "certifi" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/b0/82/dfe4a91fd38e048fbb55ca6c072710408e8802015aa27cde18e8684bb1e9/sentry_sdk-2.33.2.tar.gz", hash = "sha256:e85002234b7b8efac9b74c2d91dbd4f8f3970dc28da8798e39530e65cb740f94", size = 335804, upload-time = "2025-07-22T10:41:18.578Z" } +sdist = { url = "https://files.pythonhosted.org/packages/b3/05/546f8b9baa303b9e9b38feab79222935d0a279f0ed4d2e2cb6e5a0963055/sentry_sdk-2.34.0.tar.gz", hash = "sha256:a024baf3bb229d4b482cb58e9755c212a157813a655f186060533e75a72240ea", size = 336952, upload-time = "2025-07-29T12:47:26.59Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/c2/dc/4d825d5eb6e924dfcc6a91c8185578a7b0a5c41fd2416a6f49c8226d6ef9/sentry_sdk-2.33.2-py2.py3-none-any.whl", hash = "sha256:8d57a3b4861b243aa9d558fda75509ad487db14f488cbdb6c78c614979d77632", size = 356692, upload-time = "2025-07-22T10:41:16.531Z" }, + { url = "https://files.pythonhosted.org/packages/24/d4/999d63debd1e53f18c95861ae425dcd4fca1e8ec1934c5906ca8da44e867/sentry_sdk-2.34.0-py2.py3-none-any.whl", hash = "sha256:1c9856d0666c112f3a7a749aba09821e79871b3e7d322833840e9358b8c71a60", size = 357707, upload-time = "2025-07-29T12:47:24.599Z" }, ] [[package]]