diff --git a/.github/workflows/compile-all-batteries.yml b/.github/workflows/compile-all-batteries.yml deleted file mode 100644 index edfa7f6a..00000000 --- a/.github/workflows/compile-all-batteries.yml +++ /dev/null @@ -1,121 +0,0 @@ -# This is the name of the workflow, visible on GitHub UI. -name: 🔋 Compile All Batteries - -# Here we tell GitHub when to run the workflow. -on: - # The workflow is run when a commit is pushed or for a - # Pull Request. - - push - - pull_request - -# This is the list of jobs that will be run concurrently. -jobs: - # This pre-job is run to skip workflows in case a workflow is already run, i.e. because the workflow is triggered by both push and pull_request - skip-duplicate-actions: - runs-on: ubuntu-latest - # Map a step output to a job output - outputs: - should_skip: ${{ steps.skip_check.outputs.should_skip }} - steps: - - id: skip_check - uses: fkirc/skip-duplicate-actions@v5 - with: - # All of these options are optional, so you can remove them if you are happy with the defaults - concurrent_skipping: 'never' - skip_after_successful_duplicate: 'true' - do_not_skip: '["pull_request", "workflow_dispatch", "schedule"]' - - # Since we use a build matrix, the actual number of jobs - # started depends on how many configurations the matrix - # will produce. - build-batteries: - needs: skip-duplicate-actions - if: needs.skip-duplicate-actions.outputs.should_skip != 'true' - - # Here we tell GitHub that the jobs must be determined - # dynamically depending on a matrix configuration. - strategy: - # The matrix will produce one job for each combination of parameters. - matrix: - # This is the development board hardware for which the code will be compiled. - # FBQN stands for "fully qualified board name", and is used by Arduino to define the hardware to compile for. - fqbn: - - esp32:esp32:esp32 - # further ESP32 chips - #- esp32:esp32:esp32c3 - #- esp32:esp32:esp32c2 - #- esp32:esp32:esp32c6 - #- esp32:esp32:esp32h2 - #- esp32:esp32:esp32s3 - # These are the batteries for which the code will be compiled. - battery: - - BMW_I3_BATTERY - - BMW_IX_BATTERY - - BMW_PHEV_BATTERY - - BYD_ATTO_3_BATTERY - - CELLPOWER_BMS - - CHADEMO_BATTERY - - CMFA_EV_BATTERY - - DALY_BMS - - FOXESS_BATTERY - - GEELY_GEOMETRY_C_BATTERY - - HYUNDAI_IONIQ_28_BATTERY - - IMIEV_CZERO_ION_BATTERY - - JAGUAR_IPACE_BATTERY - - KIA_E_GMP_BATTERY - - KIA_HYUNDAI_64_BATTERY - - KIA_HYUNDAI_HYBRID_BATTERY - - MEB_BATTERY - - MG_5_BATTERY - - NISSAN_LEAF_BATTERY - - ORION_BMS - - PYLON_BATTERY - - RJXZS_BMS - - RANGE_ROVER_PHEV_BATTERY - - RENAULT_KANGOO_BATTERY - - RENAULT_TWIZY_BATTERY - - RENAULT_ZOE_GEN1_BATTERY - - RENAULT_ZOE_GEN2_BATTERY - - SANTA_FE_PHEV_BATTERY - - STELLANTIS_ECMP_BATTERY - - TESLA_MODEL_3Y_BATTERY - - TESLA_MODEL_SX_BATTERY - - VOLVO_SPA_BATTERY - - TEST_FAKE_BATTERY - # These are the emulated inverter communication protocols for which the code will be compiled. - inverter: - - BYD_CAN - # These are the supported hardware platforms for which the code will be compiled. - hardware: - - HW_LILYGO - - # This is the platform GitHub will use to run our workflow. - runs-on: ubuntu-latest - - # This is the list of steps this job will run. - steps: - # First we clone the repo using the `checkout` action. - - name: Checkout - uses: actions/checkout@v4 - - # Copy USER_SECRETS.TEMPLATE.h to USER_SECRETS.h - - name: Copy USER_SECRETS.TEMPLATE.h to USER_SECRETS.h - run: cp ./Software/USER_SECRETS.TEMPLATE.h ./Software/USER_SECRETS.h - - # We use the `arduino/setup-arduino-cli` action to install and - # configure the Arduino CLI on the system. - - name: Setup Arduino CLI - uses: arduino/setup-arduino-cli@v2 - - # We then install the platform. - - name: Install platform - run: | - arduino-cli core update-index - arduino-cli core install esp32:esp32 - - # Finally, we compile the sketch, using the FQBN that was set - # in the build matrix, and using build flags to define the - # battery and inverter set in the build matrix. - - name: Compile Sketch - run: arduino-cli compile --fqbn ${{ matrix.fqbn }} --build-property build.partitions=min_spiffs --build-property upload.maximum_size=1966080 --build-property "build.extra_flags=-Wall -Wextra -Wpedantic -Werror -DESP32 -D${{ matrix.battery}} -D${{ matrix.inverter}} -D${{ matrix.hardware}}" ./Software - \ No newline at end of file diff --git a/.github/workflows/compile-all-combinations.yml b/.github/workflows/compile-all-combinations.yml deleted file mode 100644 index 57e4860d..00000000 --- a/.github/workflows/compile-all-combinations.yml +++ /dev/null @@ -1,291 +0,0 @@ -# This is the name of the workflow, visible on GitHub UI. -name: 🔌🔋💫 Compile All Combinations - -# Here we tell GitHub when to run the workflow. -on: - # This allows you to run this workflow manually from the - # GitHub Actions tab. - workflow_dispatch: - # The workflow is run upon creating, editing, - # pre-releasing, releasing and publishing a release - release: - types: [published] - -# This is the list of jobs that will be run concurrently. -jobs: - # This pre-job is run to skip workflows in case a workflow is already run, i.e. because the workflow is triggered by both push and pull_request - skip-duplicate-actions: - runs-on: ubuntu-latest - # Map a step output to a job output - outputs: - should_skip: ${{ steps.skip_check.outputs.should_skip }} - steps: - - id: skip_check - uses: fkirc/skip-duplicate-actions@v5 - with: - # All of these options are optional, so you can remove them if you are happy with the defaults - concurrent_skipping: 'never' - skip_after_successful_duplicate: 'true' - do_not_skip: '["pull_request", "workflow_dispatch", "schedule"]' - - # Since we use a build matrix, the actual number of jobs - # started depends on how many configurations the matrix - # will produce. - - # This is the name of the job. - build-matrix-batteries-A-to-J: # we split this matrix into multiple parts, to prevent en error that is triggered when the matrix expansion exeeds 255 - needs: skip-duplicate-actions - if: needs.skip-duplicate-actions.outputs.should_skip != 'true' - - # Here we tell GitHub that the jobs must be determined - # dynamically depending on a matrix configuration. - strategy: - # The matrix will produce one job for each combination of parameters. - matrix: - # This is the development board hardware for which the code will be compiled. - # FBQN stands for "fully qualified board name", and is used by Arduino to define the hardware to compile for. - fqbn: - - esp32:esp32:esp32 - # further ESP32 chips - #- esp32:esp32:esp32c3 - #- esp32:esp32:esp32c2 - #- esp32:esp32:esp32c6 - #- esp32:esp32:esp32h2 - #- esp32:esp32:esp32s3 - # These are the batteries for which the code will be compiled. - battery: - - BMW_I3_BATTERY - - BMW_IX_BATTERY - - BMW_PHEV_BATTERY - - BYD_ATTO_3_BATTERY - - CELLPOWER_BMS - - CHADEMO_BATTERY - - FOXESS_BATTERY - - IMIEV_CZERO_ION_BATTERY - - JAGUAR_IPACE_BATTERY - # These are the emulated inverter communication protocols for which the code will be compiled. - inverter: - - AFORE_CAN - - BYD_CAN - - BYD_KOSTAL_RS485 - - BYD_MODBUS - - FERROAMP_CAN - - FOXESS_CAN - - GROWATT_HV_CAN - - GROWATT_LV_CAN - - PYLON_CAN - - PYLON_LV_CAN - - SCHNEIDER_CAN - - SMA_BYD_H_CAN - - SMA_BYD_HVS_CAN - - SMA_LV_CAN - - SMA_TRIPOWER_CAN - - SOFAR_CAN - - SOLAX_CAN - - SUNGROW_CAN - # These are the supported hardware platforms for which the code will be compiled. - hardware: - - HW_LILYGO - - # This is the platform GitHub will use to run our workflow. - runs-on: ubuntu-latest - - # This is the list of steps this job will run. - steps: - # First we clone the repo using the `checkout` action. - - name: Checkout - uses: actions/checkout@v4 - - # Copy USER_SECRETS.TEMPLATE.h to USER_SECRETS.h - - name: Copy USER_SECRETS.TEMPLATE.h to USER_SECRETS.h - run: cp ./Software/USER_SECRETS.TEMPLATE.h ./Software/USER_SECRETS.h - - # We use the `arduino/setup-arduino-cli` action to install and - # configure the Arduino CLI on the system. - - name: Setup Arduino CLI - uses: arduino/setup-arduino-cli@v2 - - # We then install the platform. - - name: Install platform - run: | - arduino-cli core update-index - arduino-cli core install esp32:esp32 - - # Finally, we compile the sketch, using the FQBN that was set - # in the build matrix, and using build flags to define the - # battery and inverter set in the build matrix. - - name: Compile Sketch - run: arduino-cli compile --fqbn ${{ matrix.fqbn }} --build-property "build.extra_flags=-Wall -Wextra -Wpedantic -Werror -DESP32 -D${{ matrix.battery}} -D${{ matrix.inverter}} -D${{ matrix.hardware}}" ./Software - - - # This is the name of the job. - build-matrix-batteries-K-to-P: - needs: skip-duplicate-actions - if: needs.skip-duplicate-actions.outputs.should_skip != 'true' - - # Here we tell GitHub that the jobs must be determined - # dynamically depending on a matrix configuration. - strategy: - # The matrix will produce one job for each combination of parameters. - matrix: - # This is the development board hardware for which the code will be compiled. - # FBQN stands for "fully qualified board name", and is used by Arduino to define the hardware to compile for. - fqbn: - - esp32:esp32:esp32 - # further ESP32 chips - #- esp32:esp32:esp32c3 - #- esp32:esp32:esp32c2 - #- esp32:esp32:esp32c6 - #- esp32:esp32:esp32h2 - #- esp32:esp32:esp32s3 - # These are the batteries for which the code will be compiled. - battery: - - KIA_E_GMP_BATTERY - - KIA_HYUNDAI_64_BATTERY - - KIA_HYUNDAI_HYBRID_BATTERY - - MEB_BATTERY - - MG_5_BATTERY - - NISSAN_LEAF_BATTERY - - ORION_BMS - - PYLON_BATTERY - # These are the emulated inverter communication protocols for which the code will be compiled. - inverter: - - AFORE_CAN - - BYD_CAN - - BYD_KOSTAL_RS485 - - BYD_MODBUS - - FERROAMP_CAN - - FOXESS_CAN - - GROWATT_HV_CAN - - GROWATT_LV_CAN - - PYLON_CAN - - PYLON_LV_CAN - - SCHNEIDER_CAN - - SMA_BYD_H_CAN - - SMA_BYD_HVS_CAN - - SMA_LV_CAN - - SMA_TRIPOWER_CAN - - SOFAR_CAN - - SOLAX_CAN - - SUNGROW_CAN - # These are the supported hardware platforms for which the code will be compiled. - hardware: - - HW_LILYGO - - # This is the platform GitHub will use to run our workflow. - runs-on: ubuntu-latest - - # This is the list of steps this job will run. - steps: - # First we clone the repo using the `checkout` action. - - name: Checkout - uses: actions/checkout@v4 - - # Copy USER_SECRETS.TEMPLATE.h to USER_SECRETS.h - - name: Copy USER_SECRETS.TEMPLATE.h to USER_SECRETS.h - run: cp ./Software/USER_SECRETS.TEMPLATE.h ./Software/USER_SECRETS.h - - # We use the `arduino/setup-arduino-cli` action to install and - # configure the Arduino CLI on the system. - - name: Setup Arduino CLI - uses: arduino/setup-arduino-cli@v2 - - # We then install the platform. - - name: Install platform - run: | - arduino-cli core update-index - arduino-cli core install esp32:esp32 - - # Finally, we compile the sketch, using the FQBN that was set - # in the build matrix, and using build flags to define the - # battery and inverter set in the build matrix. - - name: Compile Sketch - run: arduino-cli compile --fqbn ${{ matrix.fqbn }} --build-property "build.extra_flags=-Wall -Wextra -Wpedantic -Werror -DESP32 -D${{ matrix.battery}} -D${{ matrix.inverter}} -D${{ matrix.hardware}}" ./Software - - # This is the name of the job. - build-matrix-batteries-R-to-Z: - needs: skip-duplicate-actions - if: needs.skip-duplicate-actions.outputs.should_skip != 'true' - - # Here we tell GitHub that the jobs must be determined - # dynamically depending on a matrix configuration. - strategy: - # The matrix will produce one job for each combination of parameters. - matrix: - # This is the development board hardware for which the code will be compiled. - # FBQN stands for "fully qualified board name", and is used by Arduino to define the hardware to compile for. - fqbn: - - esp32:esp32:esp32 - # further ESP32 chips - #- esp32:esp32:esp32c3 - #- esp32:esp32:esp32c2 - #- esp32:esp32:esp32c6 - #- esp32:esp32:esp32h2 - #- esp32:esp32:esp32s3 - # These are the batteries for which the code will be compiled. - battery: - - RANGE_ROVER_PHEV_BATTERY - - RENAULT_KANGOO_BATTERY - - RENAULT_TWIZY_BATTERY - - RENAULT_ZOE_GEN1_BATTERY - - RENAULT_ZOE_GEN2_BATTERY - - RJXZS_BMS - - SANTA_FE_PHEV_BATTERY - - STELLANTIS_ECMP_BATTERY - - TESLA_MODEL_3Y_BATTERY - - TESLA_MODEL_SX_BATTERY - - VOLVO_SPA_BATTERY - - TEST_FAKE_BATTERY - # These are the emulated inverter communication protocols for which the code will be compiled. - inverter: - - AFORE_CAN - - BYD_CAN - - BYD_KOSTAL_RS485 - - BYD_MODBUS - - FERROAMP_CAN - - FOXESS_CAN - - GROWATT_HV_CAN - - GROWATT_LV_CAN - - PYLON_CAN - - PYLON_LV_CAN - - SCHNEIDER_CAN - - SMA_BYD_H_CAN - - SMA_BYD_HVS_CAN - - SMA_LV_CAN - - SMA_TRIPOWER_CAN - - SOFAR_CAN - - SOLAX_CAN - - SUNGROW_CAN - # These are the supported hardware platforms for which the code will be compiled. - hardware: - - HW_LILYGO - - # This is the platform GitHub will use to run our workflow. - runs-on: ubuntu-latest - - # This is the list of steps this job will run. - steps: - # First we clone the repo using the `checkout` action. - - name: Checkout - uses: actions/checkout@v4 - - # Copy USER_SECRETS.TEMPLATE.h to USER_SECRETS.h - - name: Copy USER_SECRETS.TEMPLATE.h to USER_SECRETS.h - run: cp ./Software/USER_SECRETS.TEMPLATE.h ./Software/USER_SECRETS.h - - # We use the `arduino/setup-arduino-cli` action to install and - # configure the Arduino CLI on the system. - - name: Setup Arduino CLI - uses: arduino/setup-arduino-cli@v2 - - # We then install the platform. - - name: Install platform - run: | - arduino-cli core update-index - arduino-cli core install esp32:esp32 - - # Finally, we compile the sketch, using the FQBN that was set - # in the build matrix, and using build flags to define the - # battery and inverter set in the build matrix. - - name: Compile Sketch - run: arduino-cli compile --fqbn ${{ matrix.fqbn }} --build-property build.partitions=min_spiffs --build-property upload.maximum_size=1966080 --build-property "build.extra_flags=-Wall -Wextra -Wpedantic -Werror -DESP32 -D${{ matrix.battery}} -D${{ matrix.inverter}} -D${{ matrix.hardware}}" ./Software diff --git a/.github/workflows/compile-all-double-batteries.yml b/.github/workflows/compile-all-double-batteries.yml deleted file mode 100644 index f5807acf..00000000 --- a/.github/workflows/compile-all-double-batteries.yml +++ /dev/null @@ -1,94 +0,0 @@ -# This is the name of the workflow, visible on GitHub UI. -name: 🔋🔋 Compile All Double Batteries - -# Here we tell GitHub when to run the workflow. -on: - # The workflow is run when a commit is pushed or for a - # Pull Request. - - push - - pull_request - -# This is the list of jobs that will be run concurrently. -jobs: - # This pre-job is run to skip workflows in case a workflow is already run, i.e. because the workflow is triggered by both push and pull_request - skip-duplicate-actions: - runs-on: ubuntu-latest - # Map a step output to a job output - outputs: - should_skip: ${{ steps.skip_check.outputs.should_skip }} - steps: - - id: skip_check - uses: fkirc/skip-duplicate-actions@v5 - with: - # All of these options are optional, so you can remove them if you are happy with the defaults - concurrent_skipping: 'never' - skip_after_successful_duplicate: 'true' - do_not_skip: '["pull_request", "workflow_dispatch", "schedule"]' - - # Since we use a build matrix, the actual number of jobs - # started depends on how many configurations the matrix - # will produce. - build-batteries: - needs: skip-duplicate-actions - if: needs.skip-duplicate-actions.outputs.should_skip != 'true' - - # Here we tell GitHub that the jobs must be determined - # dynamically depending on a matrix configuration. - strategy: - # The matrix will produce one job for each combination of parameters. - matrix: - # This is the development board hardware for which the code will be compiled. - # FBQN stands for "fully qualified board name", and is used by Arduino to define the hardware to compile for. - fqbn: - - esp32:esp32:esp32 - # further ESP32 chips - #- esp32:esp32:esp32c3 - #- esp32:esp32:esp32c2 - #- esp32:esp32:esp32c6 - #- esp32:esp32:esp32h2 - #- esp32:esp32:esp32s3 - # These are the batteries for which the code will be compiled. - battery: - - BMW_I3_BATTERY - - BYD_ATTO_3_BATTERY - - KIA_HYUNDAI_64_BATTERY - - PYLON_BATTERY - - SANTA_FE_PHEV_BATTERY - - TEST_FAKE_BATTERY - # These are the emulated inverter communication protocols for which the code will be compiled. - inverter: - - BYD_CAN - # These are the supported hardware platforms for which the code will be compiled. - hardware: - - HW_LILYGO - - # This is the platform GitHub will use to run our workflow. - runs-on: ubuntu-latest - - # This is the list of steps this job will run. - steps: - # First we clone the repo using the `checkout` action. - - name: Checkout - uses: actions/checkout@v4 - - # Copy USER_SECRETS.TEMPLATE.h to USER_SECRETS.h - - name: Copy USER_SECRETS.TEMPLATE.h to USER_SECRETS.h - run: cp ./Software/USER_SECRETS.TEMPLATE.h ./Software/USER_SECRETS.h - - # We use the `arduino/setup-arduino-cli` action to install and - # configure the Arduino CLI on the system. - - name: Setup Arduino CLI - uses: arduino/setup-arduino-cli@v2 - - # We then install the platform. - - name: Install platform - run: | - arduino-cli core update-index - arduino-cli core install esp32:esp32 - - # Finally, we compile the sketch, using the FQBN that was set - # in the build matrix, and using build flags to define the - # battery and inverter set in the build matrix. - - name: Compile Sketch - run: arduino-cli compile --fqbn ${{ matrix.fqbn }} --build-property build.partitions=min_spiffs --build-property upload.maximum_size=1966080 --build-property "build.extra_flags=-Wall -Wextra -Wpedantic -Werror -DESP32 -DDOUBLE_BATTERY -D${{ matrix.battery}} -D${{ matrix.inverter}} -D${{ matrix.hardware}}" ./Software - diff --git a/.github/workflows/compile-all-inverters.yml b/.github/workflows/compile-all-inverters.yml deleted file mode 100644 index 2bd79df2..00000000 --- a/.github/workflows/compile-all-inverters.yml +++ /dev/null @@ -1,108 +0,0 @@ -# This is the name of the workflow, visible on GitHub UI. -name: 🔌 Compile All Inverters - -# Here we tell GitHub when to run the workflow. -on: - # The workflow is run when a commit is pushed or for a - # Pull Request. - - push - - pull_request - -# This is the list of jobs that will be run concurrently. -jobs: - # This pre-job is run to skip workflows in case a workflow is already run, i.e. because the workflow is triggered by both push and pull_request - skip-duplicate-actions: - runs-on: ubuntu-latest - # Map a step output to a job output - outputs: - should_skip: ${{ steps.skip_check.outputs.should_skip }} - steps: - - id: skip_check - uses: fkirc/skip-duplicate-actions@v5 - with: - # All of these options are optional, so you can remove them if you are happy with the defaults - concurrent_skipping: 'never' - skip_after_successful_duplicate: 'true' - do_not_skip: '["pull_request", "workflow_dispatch", "schedule"]' - - # Since we use a build matrix, the actual number of jobs - # started depends on how many configurations the matrix - # will produce. - - # This is the name of the job. - build-inverters: - needs: skip-duplicate-actions - if: needs.skip-duplicate-actions.outputs.should_skip != 'true' - - # Here we tell GitHub that the jobs must be determined - # dynamically depending on a matrix configuration. - strategy: - # The matrix will produce one job for each combination of parameters. - matrix: - # This is the development board hardware for which the code will be compiled. - # FBQN stands for "fully qualified board name", and is used by Arduino to define the hardware to compile for. - fqbn: - - esp32:esp32:esp32 - # further ESP32 chips - #- esp32:esp32:esp32c3 - #- esp32:esp32:esp32c2 - #- esp32:esp32:esp32c6 - #- esp32:esp32:esp32h2 - #- esp32:esp32:esp32s3 - # These are the batteries for which the code will be compiled. - battery: - - NISSAN_LEAF_BATTERY - # These are the emulated inverter communication protocols for which the code will be compiled. - inverter: - - AFORE_CAN - - BYD_CAN - - BYD_KOSTAL_RS485 - - BYD_MODBUS - - FERROAMP_CAN - - FOXESS_CAN - - GROWATT_HV_CAN - - GROWATT_LV_CAN - - PYLON_CAN - - PYLON_LV_CAN - - SCHNEIDER_CAN - - SMA_BYD_H_CAN - - SMA_BYD_HVS_CAN - - SMA_LV_CAN - - SMA_TRIPOWER_CAN - - SOFAR_CAN - - SOLAX_CAN - - SUNGROW_CAN - - NISSANLEAF_CHARGER # Last element is not an inverter, but good to also test if the charger compiles - # These are the supported hardware platforms for which the code will be compiled. - hardware: - - HW_LILYGO - - # This is the platform GitHub will use to run our workflow. - runs-on: ubuntu-latest - - # This is the list of steps this job will run. - steps: - # First we clone the repo using the `checkout` action. - - name: Checkout - uses: actions/checkout@v4 - - # Copy USER_SECRETS.TEMPLATE.h to USER_SECRETS.h - - name: Copy USER_SECRETS.TEMPLATE.h to USER_SECRETS.h - run: cp ./Software/USER_SECRETS.TEMPLATE.h ./Software/USER_SECRETS.h - - # We use the `arduino/setup-arduino-cli` action to install and - # configure the Arduino CLI on the system. - - name: Setup Arduino CLI - uses: arduino/setup-arduino-cli@v2 - - # We then install the platform. - - name: Install platform - run: | - arduino-cli core update-index - arduino-cli core install esp32:esp32 - - # Finally, we compile the sketch, using the FQBN that was set - # in the build matrix, and using build flags to define the - # battery and inverter set in the build matrix. - - name: Compile Sketch - run: arduino-cli compile --fqbn ${{ matrix.fqbn }} --build-property build.partitions=min_spiffs --build-property upload.maximum_size=1966080 --build-property "build.extra_flags=-Wall -Wextra -Wpedantic -Werror -DESP32 -D${{ matrix.battery}} -D${{ matrix.inverter}} -D${{ matrix.hardware}}" ./Software diff --git a/.github/workflows/compile-common-image-lilygo-logging.yml b/.github/workflows/compile-common-image-lilygo-logging.yml deleted file mode 100644 index a84381e5..00000000 --- a/.github/workflows/compile-common-image-lilygo-logging.yml +++ /dev/null @@ -1,58 +0,0 @@ -# This is the name of the workflow, visible on GitHub UI. -name: 🔋 Compile Common Image for Lilygo with debug logging - -# Here we tell GitHub when to run the workflow. -on: - # The workflow is run when a commit is pushed or for a - # Pull Request. - - push - - pull_request - -# This is the list of jobs that will be run concurrently. -jobs: - # This pre-job is run to skip workflows in case a workflow is already run, i.e. because the workflow is triggered by both push and pull_request - skip-duplicate-actions: - runs-on: ubuntu-latest - # Map a step output to a job output - outputs: - should_skip: ${{ steps.skip_check.outputs.should_skip }} - steps: - - id: skip_check - uses: fkirc/skip-duplicate-actions@v5 - with: - # All of these options are optional, so you can remove them if you are happy with the defaults - concurrent_skipping: 'never' - skip_after_successful_duplicate: 'true' - do_not_skip: '["pull_request", "workflow_dispatch", "schedule"]' - - build-common-image: - # This is the platform GitHub will use to run our workflow. - runs-on: ubuntu-latest - - steps: - - name: Checkout - uses: actions/checkout@v4 - - # Copy USER_SECRETS.TEMPLATE.h to USER_SECRETS.h - - name: Copy USER_SECRETS.TEMPLATE.h to USER_SECRETS.h - run: cp ./Software/USER_SECRETS.TEMPLATE.h ./Software/USER_SECRETS.h - - # We use the `arduino/setup-arduino-cli` action to install and - # configure the Arduino CLI on the system. - - name: Setup Arduino CLI - uses: arduino/setup-arduino-cli@v2 - - # We then install the platform. - - name: Install platform - run: | - arduino-cli core update-index - arduino-cli core install esp32:esp32 - - - name: Compile Sketch - run: arduino-cli compile --output-dir ./ --fqbn esp32:esp32:esp32 --build-property build.partitions=min_spiffs --build-property upload.maximum_size=1966080 --build-property "build.extra_flags=-Wall -Wextra -Wpedantic -Werror -DESP32 -DDEBUG_VIA_USB -DCOMMON_IMAGE -DHW_LILYGO" ./Software - - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: battery-emulator-lilygo-debug.bin - path: Software.ino.bin diff --git a/.github/workflows/compile-common-image-lilygo.yml b/.github/workflows/compile-common-image-lilygo.yml index 02fd25f5..33c3e5ba 100644 --- a/.github/workflows/compile-common-image-lilygo.yml +++ b/.github/workflows/compile-common-image-lilygo.yml @@ -1,7 +1,5 @@ -# This is the name of the workflow, visible on GitHub UI. name: 🔋 Compile Common Image for Lilygo -# Here we tell GitHub when to run the workflow. on: # The workflow is run when a commit is pushed or for a # Pull Request. @@ -30,29 +28,31 @@ jobs: runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v4 - + - uses: actions/checkout@v4 + name: Checkout code + + - uses: actions/cache@v4 + with: + path: | + ~/.cache/pip + ~/.platformio/.cache + key: ${{ runner.os }}-pio + + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: Install PlatformIO Core + run: pip install --upgrade platformio + # Copy USER_SECRETS.TEMPLATE.h to USER_SECRETS.h - - name: Copy USER_SECRETS.TEMPLATE.h to USER_SECRETS.h - run: cp ./Software/USER_SECRETS.TEMPLATE.h ./Software/USER_SECRETS.h + - name: Copy USER_SECRETS.TEMPLATE.h to USER_SECRETS.h + run: cp ./Software/USER_SECRETS.TEMPLATE.h ./Software/USER_SECRETS.h - # We use the `arduino/setup-arduino-cli` action to install and - # configure the Arduino CLI on the system. - - name: Setup Arduino CLI - uses: arduino/setup-arduino-cli@v2 + - name: Build image for Lilygo + run: pio run -e lilygo_330 - # We then install the platform. - - name: Install platform - run: | - arduino-cli core update-index - arduino-cli core install esp32:esp32 - - - name: Compile Sketch - run: arduino-cli compile --output-dir ./ --fqbn esp32:esp32:esp32 --build-property build.partitions=min_spiffs --build-property upload.maximum_size=1966080 --build-property "build.extra_flags=-Wall -Wextra -Wpedantic -Werror -DESP32 -DCOMMON_IMAGE -DHW_LILYGO" ./Software - - - name: Upload artifact - uses: actions/upload-artifact@v4 - with: - name: battery-emulator-lilygo.bin - path: Software.ino.bin + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: battery-emulator-lilygo.bin + path: .pio/build/lilygo_330/firmware.bin diff --git a/.github/workflows/compile-common-image-stark.yml b/.github/workflows/compile-common-image-stark.yml new file mode 100644 index 00000000..00b2c01c --- /dev/null +++ b/.github/workflows/compile-common-image-stark.yml @@ -0,0 +1,58 @@ +name: 🔋 Compile Common Image for Stark CMR + +on: + # The workflow is run when a commit is pushed or for a + # Pull Request. + - push + - pull_request + +# This is the list of jobs that will be run concurrently. +jobs: + # This pre-job is run to skip workflows in case a workflow is already run, i.e. because the workflow is triggered by both push and pull_request + skip-duplicate-actions: + runs-on: ubuntu-latest + # Map a step output to a job output + outputs: + should_skip: ${{ steps.skip_check.outputs.should_skip }} + steps: + - id: skip_check + uses: fkirc/skip-duplicate-actions@v5 + with: + # All of these options are optional, so you can remove them if you are happy with the defaults + concurrent_skipping: 'never' + skip_after_successful_duplicate: 'true' + do_not_skip: '["pull_request", "workflow_dispatch", "schedule"]' + + build-common-image: + # This is the platform GitHub will use to run our workflow. + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + name: Checkout code + + - uses: actions/cache@v4 + with: + path: | + ~/.cache/pip + ~/.platformio/.cache + key: ${{ runner.os }}-pio + + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + - name: Install PlatformIO Core + run: pip install --upgrade platformio + + # Copy USER_SECRETS.TEMPLATE.h to USER_SECRETS.h + - name: Copy USER_SECRETS.TEMPLATE.h to USER_SECRETS.h + run: cp ./Software/USER_SECRETS.TEMPLATE.h ./Software/USER_SECRETS.h + + - name: Build image for Stark CMR + run: pio run -e stark_330 + + - name: Upload artifact + uses: actions/upload-artifact@v4 + with: + name: battery-emulator-stark.bin + path: .pio/build/stark_330/firmware.bin diff --git a/README.md b/README.md index 2184126e..b441253f 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ ![GitHub release (with filter)](https://img.shields.io/github/v/release/dalathegreat/BYD-Battery-Emulator-For-Gen24?color=%23008000) ![GitHub Repo stars](https://img.shields.io/github/stars/dalathegreat/Battery-Emulator?style=flat&color=%23128512) ![GitHub forks](https://img.shields.io/github/forks/dalathegreat/Battery-Emulator?style=flat&color=%23128512) -![GitHub actions](https://img.shields.io/github/actions/workflow/status/dalathegreat/BYD-Battery-Emulator-For-Gen24/compile-all-batteries.yml?color=0E810E) +![GitHub actions](https://img.shields.io/github/actions/workflow/status/dalathegreat/BYD-Battery-Emulator-For-Gen24/compile-common-image-lilygo.yml?color=0E810E) ![Static Badge](https://img.shields.io/badge/made-with_love-blue?color=%23008000) ## What is Battery Emulator? diff --git a/Software/USER_SETTINGS.h b/Software/USER_SETTINGS.h index 474908de..b806ef90 100644 --- a/Software/USER_SETTINGS.h +++ b/Software/USER_SETTINGS.h @@ -40,6 +40,7 @@ //#define RENAULT_ZOE_GEN1_BATTERY //#define RENAULT_ZOE_GEN2_BATTERY //#define SONO_BATTERY +//#define SAMSUNG_SDI_LV_BATTERY //#define SANTA_FE_PHEV_BATTERY //#define SIMPBMS_BATTERY //#define STELLANTIS_ECMP_BATTERY diff --git a/Software/src/battery/BATTERIES.cpp b/Software/src/battery/BATTERIES.cpp index 0eb67d1e..354a4686 100644 --- a/Software/src/battery/BATTERIES.cpp +++ b/Software/src/battery/BATTERIES.cpp @@ -116,6 +116,8 @@ const char* name_for_battery_type(BatteryType type) { return RenaultZoeGen1Battery::Name; case BatteryType::RenaultZoe2: return RenaultZoeGen2Battery::Name; + case BatteryType::SamsungSdiLv: + return SamsungSdiLVBattery::Name; case BatteryType::SantaFePhev: return SantaFePhevBattery::Name; case BatteryType::SimpBms: @@ -215,6 +217,8 @@ Battery* create_battery(BatteryType type) { return new RenaultZoeGen1Battery(); case BatteryType::RenaultZoe2: return new RenaultZoeGen2Battery(); + case BatteryType::SamsungSdiLv: + return new SamsungSdiLVBattery(); case BatteryType::SantaFePhev: return new SantaFePhevBattery(); case BatteryType::SimpBms: diff --git a/Software/src/battery/BATTERIES.h b/Software/src/battery/BATTERIES.h index b7fe961e..1f357a93 100644 --- a/Software/src/battery/BATTERIES.h +++ b/Software/src/battery/BATTERIES.h @@ -44,6 +44,7 @@ void setup_can_shunt(); #include "RENAULT-ZOE-GEN1-BATTERY.h" #include "RENAULT-ZOE-GEN2-BATTERY.h" #include "RJXZS-BMS.h" +#include "SAMSUNG-SDI-LV-BATTERY.h" #include "SANTA-FE-PHEV-BATTERY.h" #include "SIMPBMS-BATTERY.h" #include "SONO-BATTERY.h" diff --git a/Software/src/battery/Battery.h b/Software/src/battery/Battery.h index e0fd42e5..7f556188 100644 --- a/Software/src/battery/Battery.h +++ b/Software/src/battery/Battery.h @@ -43,7 +43,8 @@ enum class BatteryType { VolvoSpa = 35, VolvoSpaHybrid = 36, MgHsPhev = 37, - HyundaiIoniq28 = 38, + SamsungSdiLv = 38, + HyundaiIoniq28 = 39, Highest }; diff --git a/Software/src/battery/ECMP-BATTERY.cpp b/Software/src/battery/ECMP-BATTERY.cpp index 4b25c079..536f4b90 100644 --- a/Software/src/battery/ECMP-BATTERY.cpp +++ b/Software/src/battery/ECMP-BATTERY.cpp @@ -123,6 +123,7 @@ void EcmpBattery::update_values() { datalayer_extended.stellantisECMP.pid_time_spent_over_55c = pid_time_spent_over_55c; datalayer_extended.stellantisECMP.pid_contactor_closing_counter = pid_contactor_closing_counter; datalayer_extended.stellantisECMP.pid_date_of_manufacture = pid_date_of_manufacture; + datalayer_extended.stellantisECMP.pid_SOH_cell_1 = pid_SOH_cell_1; if (battery_InterlockOpen) { set_event(EVENT_HVIL_FAILURE, 0); @@ -135,6 +136,12 @@ void EcmpBattery::update_values() { } else { clear_event(EVENT_12V_LOW); } + + if (pid_reason_open == 7) { //Invalid status + set_event(EVENT_CONTACTOR_OPEN, 0); + } else { + clear_event(EVENT_CONTACTOR_OPEN); + } } void EcmpBattery::handle_incoming_can_frame(CAN_frame rx_frame) { @@ -578,8 +585,7 @@ void EcmpBattery::handle_incoming_can_frame(CAN_frame rx_frame) { (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]); break; case PID_ENERGY_CAPACITY: - pid_energy_capacity = ((rx_frame.data.u8[4] << 24) | (rx_frame.data.u8[5] << 16) | - (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]); + pid_energy_capacity = (rx_frame.data.u8[4] << 16) | (rx_frame.data.u8[5] << 8) | (rx_frame.data.u8[6]); break; case PID_HIGH_CELL_NUM: pid_highest_cell_voltage_num = (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]; @@ -720,6 +726,33 @@ void EcmpBattery::handle_incoming_can_frame(CAN_frame rx_frame) { switch (incoming_poll) //Multiframe responses { + case PID_ALL_CELL_SOH: + switch (rx_frame.data.u8[0]) { + case 0x10: + pid_SOH_cell_1 = ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6]); + break; + case 0x21: + break; + case 0x22: + break; + case 0x23: + break; + case 0x24: + break; + case 0x25: + break; + case 0x26: + break; + case 0x27: + break; + case 0x28: + break; + case 0x29: + break; + default: + break; + } + break; case PID_ALL_CELL_VOLTAGES: switch (rx_frame.data.u8[0]) { case 0x10: @@ -1291,6 +1324,11 @@ void EcmpBattery::transmit_can(unsigned long currentMillis) { case PID_DATE_OF_MANUFACTURE: ECMP_POLL.data.u8[2] = (uint8_t)((PID_DATE_OF_MANUFACTURE & 0xFF00) >> 8); ECMP_POLL.data.u8[3] = (uint8_t)(PID_DATE_OF_MANUFACTURE & 0x00FF); + poll_state = PID_ALL_CELL_SOH; + break; + case PID_ALL_CELL_SOH: + ECMP_POLL.data.u8[2] = (uint8_t)((PID_ALL_CELL_SOH & 0xFF00) >> 8); + ECMP_POLL.data.u8[3] = (uint8_t)(PID_ALL_CELL_SOH & 0x00FF); poll_state = PID_WELD_CHECK; // Loop back to beginning break; default: diff --git a/Software/src/battery/ECMP-BATTERY.h b/Software/src/battery/ECMP-BATTERY.h index 2003d5cd..66219b7c 100644 --- a/Software/src/battery/ECMP-BATTERY.h +++ b/Software/src/battery/ECMP-BATTERY.h @@ -136,6 +136,7 @@ class EcmpBattery : public CanBattery { uint32_t pid_time_spent_over_55c = NOT_SAMPLED_YET; uint32_t pid_contactor_closing_counter = NOT_SAMPLED_YET; uint32_t pid_date_of_manufacture = NOT_SAMPLED_YET; + uint16_t pid_SOH_cell_1 = NOT_SAMPLED_YET; unsigned long previousMillis10 = 0; // will store last time a 10ms CAN Message was sent unsigned long previousMillis20 = 0; // will store last time a 20ms CAN Message was sent @@ -197,7 +198,7 @@ class EcmpBattery : public CanBattery { static const uint16_t PID_SW_VERSION_NUM = 0xF195; //Not supported on all batteris static const uint16_t PID_FACTORY_MODE_CONTROL = 0xD900; static const uint16_t PID_BATTERY_SERIAL = 0xD901; - static const uint16_t PID_ALL_CELL_SOH = 0xD4B5; //Very long message reply, too much data for this integration + static const uint16_t PID_ALL_CELL_SOH = 0xD4B5; static const uint16_t PID_AUX_FUSE_STATE = 0xD86C; static const uint16_t PID_BATTERY_STATE = 0xD811; static const uint16_t PID_PRECHARGE_SHORT_CIRCUIT = 0xD4D8; diff --git a/Software/src/battery/ECMP-HTML.h b/Software/src/battery/ECMP-HTML.h index 7a98a42a..3a43427f 100644 --- a/Software/src/battery/ECMP-HTML.h +++ b/Software/src/battery/ECMP-HTML.h @@ -376,6 +376,11 @@ class EcmpHtmlRenderer : public BatteryHtmlRenderer { ? "N/A" : String(datalayer_extended.stellantisECMP.pid_contactor_closing_counter)) + " cycles"; + content += "

State of Health Cell-1: " + + (datalayer_extended.stellantisECMP.pid_SOH_cell_1 == 255 + ? "N/A" + : String(datalayer_extended.stellantisECMP.pid_SOH_cell_1)) + + "

"; return content; } diff --git a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp index 4b0cb2f6..bc499862 100644 --- a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp +++ b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.cpp @@ -48,66 +48,19 @@ void KiaHyundai64Battery:: datalayer_battery_extended->batteryManagementMode = batteryManagementMode; datalayer_battery_extended->BMS_ign = BMS_ign; datalayer_battery_extended->batteryRelay = batteryRelay; - - //Perform logging if configured to do so -#ifdef DEBUG_LOG - logging.println(); //sepatator - logging.println("Values from battery: "); - logging.print("SOC BMS: "); - logging.print((uint16_t)SOC_BMS / 10.0, 1); - logging.print("% | SOC Display: "); - logging.print((uint16_t)SOC_Display / 10.0, 1); - logging.print("% | SOH "); - logging.print((uint16_t)batterySOH / 10.0, 1); - logging.println("%"); - logging.print((int16_t)batteryAmps / 10.0, 1); - logging.print(" Amps | "); - logging.print((uint16_t)batteryVoltage / 10.0, 1); - logging.print(" Volts | "); - logging.print((int16_t)datalayer_battery->status.active_power_W); - logging.println(" Watts"); - logging.print("Allowed Charge "); - logging.print((uint16_t)allowedChargePower * 10); - logging.print(" W | Allowed Discharge "); - logging.print((uint16_t)allowedDischargePower * 10); - logging.println(" W"); - logging.print("MaxCellVolt "); - logging.print(CellVoltMax_mV); - logging.print(" mV No "); - logging.print(CellVmaxNo); - logging.print(" | MinCellVolt "); - logging.print(CellVoltMin_mV); - logging.print(" mV No "); - logging.println(CellVminNo); - logging.print("TempHi "); - logging.print((int16_t)temperatureMax); - logging.print("°C TempLo "); - logging.print((int16_t)temperatureMin); - logging.print("°C WaterInlet "); - logging.print((int8_t)temperature_water_inlet); - logging.print("°C PowerRelay "); - logging.print((int8_t)powerRelayTemperature * 2); - logging.println("°C"); - logging.print("Aux12volt: "); - logging.print((int16_t)leadAcidBatteryVoltage / 10.0, 1); - logging.println("V | "); - logging.print("BmsManagementMode "); - logging.print((uint8_t)batteryManagementMode, BIN); - if (bitRead((uint8_t)BMS_ign, 2) == 1) { - logging.print(" | BmsIgnition ON"); - } else { - logging.print(" | BmsIgnition OFF"); - } - - if (bitRead((uint8_t)batteryRelay, 0) == 1) { - logging.print(" | PowerRelay ON"); - } else { - logging.print(" | PowerRelay OFF"); - } - logging.print(" | Inverter "); - logging.print(inverterVoltage); - logging.println(" Volts"); -#endif + datalayer_battery_extended->inverterVoltage = inverterVoltage; + memcpy(datalayer_battery_extended->ecu_serial_number, ecu_serial_number, sizeof(ecu_serial_number)); + memcpy(datalayer_battery_extended->ecu_version_number, ecu_version_number, sizeof(ecu_version_number)); + datalayer_battery_extended->cumulative_charge_current_ah = cumulative_charge_current_ah; + datalayer_battery_extended->cumulative_discharge_current_ah = cumulative_discharge_current_ah; + datalayer_battery_extended->cumulative_energy_charged_kWh = cumulative_energy_charged_kWh; + datalayer_battery_extended->cumulative_energy_discharged_kWh = cumulative_energy_discharged_kWh; + datalayer_battery_extended->powered_on_total_time = powered_on_total_time; + datalayer_battery_extended->isolation_resistance_kOhm = isolation_resistance_kOhm; + datalayer_battery_extended->number_of_standard_charging_sessions = number_of_standard_charging_sessions; + datalayer_battery_extended->number_of_fastcharging_sessions = number_of_fastcharging_sessions; + datalayer_battery_extended->accumulated_normal_charging_energy_kWh = accumulated_normal_charging_energy_kWh; + datalayer_battery_extended->accumulated_fastcharging_energy_kWh = accumulated_fastcharging_energy_kWh; } void KiaHyundai64Battery::update_number_of_cells() { @@ -129,6 +82,7 @@ void KiaHyundai64Battery::update_number_of_cells() { void KiaHyundai64Battery::handle_incoming_can_frame(CAN_frame rx_frame) { switch (rx_frame.ID) { case 0x4DE: + datalayer_battery->status.CAN_battery_still_alive = CAN_STILL_ALIVE; startedUp = true; break; case 0x542: //BMS SOC @@ -168,65 +122,118 @@ void KiaHyundai64Battery::handle_incoming_can_frame(CAN_frame rx_frame) { case 0x5D8: startedUp = true; - //PID data is polled after last message sent from battery every other time: + //PID data is polled after last message sent from battery every other time this 0x5D8 message arrives: if (holdPidCounter == true) { holdPidCounter = false; } else { holdPidCounter = true; - if (poll_data_pid >= 6) { //polling one of six PIDs at 100ms*2, resolution = 1200ms - poll_data_pid = 0; - } + poll_data_pid++; if (poll_data_pid == 1) { - transmit_can_frame(&KIA64_7E4_id1); + KIA64_7E4_poll.data.u8[2] = (uint8_t)((POLL_GROUP_1 & 0xFF00) >> 8); + KIA64_7E4_poll.data.u8[3] = (uint8_t)(POLL_GROUP_1 & 0x00FF); } else if (poll_data_pid == 2) { - transmit_can_frame(&KIA64_7E4_id2); + KIA64_7E4_poll.data.u8[2] = (uint8_t)((POLL_GROUP_2 & 0xFF00) >> 8); + KIA64_7E4_poll.data.u8[3] = (uint8_t)(POLL_GROUP_2 & 0x00FF); } else if (poll_data_pid == 3) { - transmit_can_frame(&KIA64_7E4_id3); + KIA64_7E4_poll.data.u8[2] = (uint8_t)((POLL_GROUP_3 & 0xFF00) >> 8); + KIA64_7E4_poll.data.u8[3] = (uint8_t)(POLL_GROUP_3 & 0x00FF); } else if (poll_data_pid == 4) { - transmit_can_frame(&KIA64_7E4_id4); + KIA64_7E4_poll.data.u8[2] = (uint8_t)((POLL_GROUP_4 & 0xFF00) >> 8); + KIA64_7E4_poll.data.u8[3] = (uint8_t)(POLL_GROUP_4 & 0x00FF); } else if (poll_data_pid == 5) { - transmit_can_frame(&KIA64_7E4_id5); + KIA64_7E4_poll.data.u8[2] = (uint8_t)((POLL_GROUP_5 & 0xFF00) >> 8); + KIA64_7E4_poll.data.u8[3] = (uint8_t)(POLL_GROUP_5 & 0x00FF); } else if (poll_data_pid == 6) { - transmit_can_frame(&KIA64_7E4_id6); + KIA64_7E4_poll.data.u8[2] = (uint8_t)((POLL_GROUP_6 & 0xFF00) >> 8); + KIA64_7E4_poll.data.u8[3] = (uint8_t)(POLL_GROUP_6 & 0x00FF); + } else if (poll_data_pid == 7) { + KIA64_7E4_poll.data.u8[2] = (uint8_t)((POLL_GROUP_11 & 0xFF00) >> 8); + KIA64_7E4_poll.data.u8[3] = (uint8_t)(POLL_GROUP_11 & 0x00FF); + } else if (poll_data_pid == 8) { + KIA64_7E4_poll.data.u8[2] = (uint8_t)((POLL_ECU_SERIAL & 0xFF00) >> 8); + KIA64_7E4_poll.data.u8[3] = (uint8_t)(POLL_ECU_SERIAL & 0x00FF); + } else if (poll_data_pid == 9) { + KIA64_7E4_poll.data.u8[2] = (uint8_t)((POLL_ECU_VERSION & 0xFF00) >> 8); + KIA64_7E4_poll.data.u8[3] = (uint8_t)(POLL_ECU_VERSION & 0x00FF); + poll_data_pid = 0; } + transmit_can_frame(&KIA64_7E4_poll); } break; case 0x7EC: //Data From polled PID group, BigEndian - switch (rx_frame.data.u8[0]) { - case 0x10: //"PID Header" - if (rx_frame.data.u8[4] == poll_data_pid) { - transmit_can_frame(&KIA64_7E4_ack); //Send ack to BMS if the same frame is sent as polled + + if (rx_frame.data.u8[0] < 0x10) { //One line response + pid_reply = (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]; + } + + if (rx_frame.data.u8[0] == 0x10) { //Multiframe response, send ACK + transmit_can_frame(&KIA64_7E4_ack); + pid_reply = (rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]; + } + + switch (rx_frame.data.u8[0]) { //Multiframe responses + case 0x10: //Header frame sometimes has data + if (pid_reply == POLL_ECU_SERIAL) { + ecu_serial_number[0] = rx_frame.data.u8[5]; + ecu_serial_number[1] = rx_frame.data.u8[6]; + ecu_serial_number[2] = rx_frame.data.u8[7]; + } else if (pid_reply == POLL_ECU_VERSION) { + ecu_version_number[0] = rx_frame.data.u8[5]; + ecu_version_number[1] = rx_frame.data.u8[6]; + ecu_version_number[2] = rx_frame.data.u8[7]; } break; case 0x21: //First frame in PID group - if (poll_data_pid == 1) { + if (pid_reply == POLL_GROUP_1) { batteryRelay = rx_frame.data.u8[7]; - } else if (poll_data_pid == 2) { + } else if (pid_reply == POLL_GROUP_2) { cellvoltages_mv[0] = (rx_frame.data.u8[2] * 20); cellvoltages_mv[1] = (rx_frame.data.u8[3] * 20); cellvoltages_mv[2] = (rx_frame.data.u8[4] * 20); cellvoltages_mv[3] = (rx_frame.data.u8[5] * 20); cellvoltages_mv[4] = (rx_frame.data.u8[6] * 20); cellvoltages_mv[5] = (rx_frame.data.u8[7] * 20); - } else if (poll_data_pid == 3) { + } else if (pid_reply == POLL_GROUP_3) { cellvoltages_mv[32] = (rx_frame.data.u8[2] * 20); cellvoltages_mv[33] = (rx_frame.data.u8[3] * 20); cellvoltages_mv[34] = (rx_frame.data.u8[4] * 20); cellvoltages_mv[35] = (rx_frame.data.u8[5] * 20); cellvoltages_mv[36] = (rx_frame.data.u8[6] * 20); cellvoltages_mv[37] = (rx_frame.data.u8[7] * 20); - } else if (poll_data_pid == 4) { + } else if (pid_reply == POLL_GROUP_4) { cellvoltages_mv[64] = (rx_frame.data.u8[2] * 20); cellvoltages_mv[65] = (rx_frame.data.u8[3] * 20); cellvoltages_mv[66] = (rx_frame.data.u8[4] * 20); cellvoltages_mv[67] = (rx_frame.data.u8[5] * 20); cellvoltages_mv[68] = (rx_frame.data.u8[6] * 20); cellvoltages_mv[69] = (rx_frame.data.u8[7] * 20); + } else if (pid_reply == POLL_GROUP_11) { + number_of_standard_charging_sessions = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + } else if (pid_reply == POLL_ECU_SERIAL) { + ecu_serial_number[3] = rx_frame.data.u8[1]; + ecu_serial_number[4] = rx_frame.data.u8[2]; + ecu_serial_number[5] = rx_frame.data.u8[3]; + ecu_serial_number[6] = rx_frame.data.u8[4]; + ecu_serial_number[7] = rx_frame.data.u8[5]; + ecu_serial_number[8] = rx_frame.data.u8[6]; + ecu_serial_number[9] = rx_frame.data.u8[7]; + } else if (pid_reply == POLL_ECU_VERSION) { + ecu_version_number[3] = rx_frame.data.u8[1]; + ecu_version_number[4] = rx_frame.data.u8[2]; + ecu_version_number[5] = rx_frame.data.u8[3]; + ecu_version_number[6] = rx_frame.data.u8[4]; + ecu_version_number[7] = rx_frame.data.u8[5]; + ecu_version_number[8] = rx_frame.data.u8[6]; + ecu_version_number[9] = rx_frame.data.u8[7]; } break; case 0x22: //Second datarow in PID group - if (poll_data_pid == 2) { + if (pid_reply == POLL_GROUP_1) { + //battery_max_temperature = rx_frame.data.u8[5]; + //battery_min_temperature = rx_frame.data.u8[6]; + //module_1_temperature = rx_frame.data.u8[7]; + } else if (pid_reply == POLL_GROUP_2) { cellvoltages_mv[6] = (rx_frame.data.u8[1] * 20); cellvoltages_mv[7] = (rx_frame.data.u8[2] * 20); cellvoltages_mv[8] = (rx_frame.data.u8[3] * 20); @@ -234,7 +241,7 @@ void KiaHyundai64Battery::handle_incoming_can_frame(CAN_frame rx_frame) { cellvoltages_mv[10] = (rx_frame.data.u8[5] * 20); cellvoltages_mv[11] = (rx_frame.data.u8[6] * 20); cellvoltages_mv[12] = (rx_frame.data.u8[7] * 20); - } else if (poll_data_pid == 3) { + } else if (pid_reply == POLL_GROUP_3) { cellvoltages_mv[38] = (rx_frame.data.u8[1] * 20); cellvoltages_mv[39] = (rx_frame.data.u8[2] * 20); cellvoltages_mv[40] = (rx_frame.data.u8[3] * 20); @@ -242,7 +249,7 @@ void KiaHyundai64Battery::handle_incoming_can_frame(CAN_frame rx_frame) { cellvoltages_mv[42] = (rx_frame.data.u8[5] * 20); cellvoltages_mv[43] = (rx_frame.data.u8[6] * 20); cellvoltages_mv[44] = (rx_frame.data.u8[7] * 20); - } else if (poll_data_pid == 4) { + } else if (pid_reply == POLL_GROUP_4) { cellvoltages_mv[70] = (rx_frame.data.u8[1] * 20); cellvoltages_mv[71] = (rx_frame.data.u8[2] * 20); cellvoltages_mv[72] = (rx_frame.data.u8[3] * 20); @@ -250,15 +257,35 @@ void KiaHyundai64Battery::handle_incoming_can_frame(CAN_frame rx_frame) { cellvoltages_mv[74] = (rx_frame.data.u8[5] * 20); cellvoltages_mv[75] = (rx_frame.data.u8[6] * 20); cellvoltages_mv[76] = (rx_frame.data.u8[7] * 20); - } else if (poll_data_pid == 6) { + } else if (pid_reply == POLL_GROUP_6) { batteryManagementMode = rx_frame.data.u8[5]; + } else if (pid_reply == POLL_GROUP_11) { + number_of_fastcharging_sessions = ((rx_frame.data.u8[1] << 8) | rx_frame.data.u8[2]); + accumulated_normal_charging_energy_kWh = ((rx_frame.data.u8[5] << 8) | rx_frame.data.u8[6]); + } else if (pid_reply == POLL_ECU_SERIAL) { + ecu_serial_number[10] = rx_frame.data.u8[1]; + ecu_serial_number[11] = rx_frame.data.u8[2]; + ecu_serial_number[12] = rx_frame.data.u8[3]; + ecu_serial_number[13] = rx_frame.data.u8[4]; + ecu_serial_number[14] = rx_frame.data.u8[5]; + ecu_serial_number[15] = rx_frame.data.u8[6]; + } else if (pid_reply == POLL_ECU_VERSION) { + ecu_version_number[10] = rx_frame.data.u8[1]; + ecu_version_number[11] = rx_frame.data.u8[2]; + ecu_version_number[12] = rx_frame.data.u8[3]; + ecu_version_number[13] = rx_frame.data.u8[4]; + ecu_version_number[14] = rx_frame.data.u8[5]; + ecu_version_number[15] = rx_frame.data.u8[6]; } break; case 0x23: //Third datarow in PID group - if (poll_data_pid == 1) { + if (pid_reply == POLL_GROUP_1) { + //module_2_temperature = rx_frame.data.u8[1]; + //module_3_temperature = rx_frame.data.u8[2]; + //module_4_temperature = rx_frame.data.u8[3]; temperature_water_inlet = rx_frame.data.u8[6]; CellVoltMax_mV = (rx_frame.data.u8[7] * 20); //(volts *50) *20 =mV - } else if (poll_data_pid == 2) { + } else if (pid_reply == POLL_GROUP_2) { cellvoltages_mv[13] = (rx_frame.data.u8[1] * 20); cellvoltages_mv[14] = (rx_frame.data.u8[2] * 20); cellvoltages_mv[15] = (rx_frame.data.u8[3] * 20); @@ -266,7 +293,7 @@ void KiaHyundai64Battery::handle_incoming_can_frame(CAN_frame rx_frame) { cellvoltages_mv[17] = (rx_frame.data.u8[5] * 20); cellvoltages_mv[18] = (rx_frame.data.u8[6] * 20); cellvoltages_mv[19] = (rx_frame.data.u8[7] * 20); - } else if (poll_data_pid == 3) { + } else if (pid_reply == POLL_GROUP_3) { cellvoltages_mv[45] = (rx_frame.data.u8[1] * 20); cellvoltages_mv[46] = (rx_frame.data.u8[2] * 20); cellvoltages_mv[47] = (rx_frame.data.u8[3] * 20); @@ -274,7 +301,7 @@ void KiaHyundai64Battery::handle_incoming_can_frame(CAN_frame rx_frame) { cellvoltages_mv[49] = (rx_frame.data.u8[5] * 20); cellvoltages_mv[50] = (rx_frame.data.u8[6] * 20); cellvoltages_mv[51] = (rx_frame.data.u8[7] * 20); - } else if (poll_data_pid == 4) { + } else if (pid_reply == POLL_GROUP_4) { cellvoltages_mv[77] = (rx_frame.data.u8[1] * 20); cellvoltages_mv[78] = (rx_frame.data.u8[2] * 20); cellvoltages_mv[79] = (rx_frame.data.u8[3] * 20); @@ -282,16 +309,18 @@ void KiaHyundai64Battery::handle_incoming_can_frame(CAN_frame rx_frame) { cellvoltages_mv[81] = (rx_frame.data.u8[5] * 20); cellvoltages_mv[82] = (rx_frame.data.u8[6] * 20); cellvoltages_mv[83] = (rx_frame.data.u8[7] * 20); - } else if (poll_data_pid == 5) { + } else if (pid_reply == POLL_GROUP_5) { heatertemp = rx_frame.data.u8[7]; + } else if (pid_reply == POLL_GROUP_11) { + accumulated_fastcharging_energy_kWh = ((rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]); } break; case 0x24: //Fourth datarow in PID group - if (poll_data_pid == 1) { + if (pid_reply == POLL_GROUP_1) { CellVmaxNo = rx_frame.data.u8[1]; CellVminNo = rx_frame.data.u8[3]; CellVoltMin_mV = (rx_frame.data.u8[2] * 20); //(volts *50) *20 =mV - } else if (poll_data_pid == 2) { + } else if (pid_reply == POLL_GROUP_2) { cellvoltages_mv[20] = (rx_frame.data.u8[1] * 20); cellvoltages_mv[21] = (rx_frame.data.u8[2] * 20); cellvoltages_mv[22] = (rx_frame.data.u8[3] * 20); @@ -299,7 +328,7 @@ void KiaHyundai64Battery::handle_incoming_can_frame(CAN_frame rx_frame) { cellvoltages_mv[24] = (rx_frame.data.u8[5] * 20); cellvoltages_mv[25] = (rx_frame.data.u8[6] * 20); cellvoltages_mv[26] = (rx_frame.data.u8[7] * 20); - } else if (poll_data_pid == 3) { + } else if (pid_reply == POLL_GROUP_3) { cellvoltages_mv[52] = (rx_frame.data.u8[1] * 20); cellvoltages_mv[53] = (rx_frame.data.u8[2] * 20); cellvoltages_mv[54] = (rx_frame.data.u8[3] * 20); @@ -307,7 +336,7 @@ void KiaHyundai64Battery::handle_incoming_can_frame(CAN_frame rx_frame) { cellvoltages_mv[56] = (rx_frame.data.u8[5] * 20); cellvoltages_mv[57] = (rx_frame.data.u8[6] * 20); cellvoltages_mv[58] = (rx_frame.data.u8[7] * 20); - } else if (poll_data_pid == 4) { + } else if (pid_reply == POLL_GROUP_4) { cellvoltages_mv[84] = (rx_frame.data.u8[1] * 20); cellvoltages_mv[85] = (rx_frame.data.u8[2] * 20); cellvoltages_mv[86] = (rx_frame.data.u8[3] * 20); @@ -317,25 +346,30 @@ void KiaHyundai64Battery::handle_incoming_can_frame(CAN_frame rx_frame) { if (rx_frame.data.u8[7] > 4) { // Data only valid on 98S cellvoltages_mv[90] = (rx_frame.data.u8[7] * 20); // Perform extra checks } - } else if (poll_data_pid == 5) { + } else if (pid_reply == POLL_GROUP_5) { batterySOH = ((rx_frame.data.u8[2] << 8) + rx_frame.data.u8[3]); } break; case 0x25: //Fifth datarow in PID group - if (poll_data_pid == 2) { + if (pid_reply == POLL_GROUP_1) { + cumulative_charge_current_ah = + ((rx_frame.data.u8[1] << 16) | (rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]); + cumulative_discharge_current_ah = + ((rx_frame.data.u8[5] << 16) | (rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]); + } else if (pid_reply == POLL_GROUP_2) { cellvoltages_mv[27] = (rx_frame.data.u8[1] * 20); cellvoltages_mv[28] = (rx_frame.data.u8[2] * 20); cellvoltages_mv[29] = (rx_frame.data.u8[3] * 20); cellvoltages_mv[30] = (rx_frame.data.u8[4] * 20); cellvoltages_mv[31] = (rx_frame.data.u8[5] * 20); - } else if (poll_data_pid == 3) { + } else if (pid_reply == POLL_GROUP_3) { cellvoltages_mv[59] = (rx_frame.data.u8[1] * 20); cellvoltages_mv[60] = (rx_frame.data.u8[2] * 20); cellvoltages_mv[61] = (rx_frame.data.u8[3] * 20); cellvoltages_mv[62] = (rx_frame.data.u8[4] * 20); cellvoltages_mv[63] = (rx_frame.data.u8[5] * 20); - } else if (poll_data_pid == 4) { // Data only valid on 98S - if (rx_frame.data.u8[1] > 4) { // Perform extra checks + } else if (pid_reply == POLL_GROUP_4) { // Data only valid on 98S + if (rx_frame.data.u8[1] > 4) { // Perform extra checks cellvoltages_mv[91] = (rx_frame.data.u8[1] * 20); } if (rx_frame.data.u8[2] > 4) { // Perform extra checks @@ -350,8 +384,8 @@ void KiaHyundai64Battery::handle_incoming_can_frame(CAN_frame rx_frame) { if (rx_frame.data.u8[5] > 4) { // Perform extra checks cellvoltages_mv[95] = (rx_frame.data.u8[5] * 20); } - } else if (poll_data_pid == 5) { // Data only valid on 98S - if (rx_frame.data.u8[4] > 4) { // Perform extra checks + } else if (pid_reply == POLL_GROUP_5) { // Data only valid on 98S + if (rx_frame.data.u8[4] > 4) { // Perform extra checks cellvoltages_mv[96] = (rx_frame.data.u8[4] * 20); } if (rx_frame.data.u8[5] > 4) { // Perform extra checks @@ -360,7 +394,11 @@ void KiaHyundai64Battery::handle_incoming_can_frame(CAN_frame rx_frame) { } break; case 0x26: //Sixth datarow in PID group - if (poll_data_pid == 5) { + if (pid_reply == POLL_GROUP_1) { + cumulative_energy_charged_kWh = + ((rx_frame.data.u8[2] << 16) | (rx_frame.data.u8[3] << 8) | rx_frame.data.u8[4]); + cumulative_energy_discharged_HIGH_BYTE = ((rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]); + } else if (pid_reply == POLL_GROUP_5) { //We have read all cells, check that content is valid: for (uint8_t i = 85; i < 97; ++i) { if (cellvoltages_mv[i] < 300) { // Zero the value if it's below 300 @@ -374,17 +412,24 @@ void KiaHyundai64Battery::handle_incoming_can_frame(CAN_frame rx_frame) { } break; case 0x27: //Seventh datarow in PID group - if (poll_data_pid == 1) { + if (pid_reply == POLL_GROUP_1) { + cumulative_energy_discharged_kWh = ((cumulative_energy_discharged_HIGH_BYTE << 8) | rx_frame.data.u8[1]); + powered_on_total_time = ((rx_frame.data.u8[2] << 24) | (rx_frame.data.u8[3] << 16) | + (rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); BMS_ign = rx_frame.data.u8[6]; inverterVoltageFrameHigh = rx_frame.data.u8[7]; } break; case 0x28: //Eighth datarow in PID group - if (poll_data_pid == 1) { + if (pid_reply == POLL_GROUP_1) { inverterVoltage = (inverterVoltageFrameHigh << 8) + rx_frame.data.u8[1]; + isolation_resistance_kOhm = ((rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]); } break; + default: + break; } + break; default: break; @@ -401,7 +446,8 @@ void KiaHyundai64Battery::transmit_can(unsigned long currentMillis) { if (currentMillis - previousMillis100 >= INTERVAL_100_MS) { previousMillis100 = currentMillis; - if (contactor_closing_allowed == nullptr || *contactor_closing_allowed) { + if ((contactor_closing_allowed == nullptr || *contactor_closing_allowed) && + datalayer.system.status.inverter_allows_contactor_closing) { transmit_can_frame(&KIA64_553); transmit_can_frame(&KIA64_57F); transmit_can_frame(&KIA64_2A1); @@ -412,7 +458,8 @@ void KiaHyundai64Battery::transmit_can(unsigned long currentMillis) { if (currentMillis - previousMillis10 >= INTERVAL_10_MS) { previousMillis10 = currentMillis; - if (contactor_closing_allowed == nullptr || *contactor_closing_allowed) { + if ((contactor_closing_allowed == nullptr || *contactor_closing_allowed) && + datalayer.system.status.inverter_allows_contactor_closing) { switch (counter_200) { case 0: diff --git a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.h b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.h index 60505cb6..7f8e6e06 100644 --- a/Software/src/battery/KIA-HYUNDAI-64-BATTERY.h +++ b/Software/src/battery/KIA-HYUNDAI-64-BATTERY.h @@ -79,7 +79,8 @@ class KiaHyundai64Battery : public CanBattery { int16_t batteryAmps = 0; int16_t temperatureMax = 0; int16_t temperatureMin = 0; - int16_t poll_data_pid = 0; + uint8_t poll_data_pid = 0; + uint16_t pid_reply = 0; bool holdPidCounter = false; uint8_t CellVmaxNo = 0; uint8_t CellVminNo = 0; @@ -92,6 +93,19 @@ class KiaHyundai64Battery : public CanBattery { int8_t heatertemp = 0; int8_t powerRelayTemperature = 0; bool startedUp = false; + uint8_t ecu_serial_number[16] = {0}; + uint8_t ecu_version_number[16] = {0}; + uint32_t cumulative_charge_current_ah = 0; + uint32_t cumulative_discharge_current_ah = 0; + uint32_t cumulative_energy_charged_kWh = 0; + uint16_t cumulative_energy_discharged_HIGH_BYTE = 0; + uint32_t cumulative_energy_discharged_kWh = 0; + uint32_t powered_on_total_time = 0; + uint16_t isolation_resistance_kOhm = 0; + uint16_t number_of_standard_charging_sessions = 0; + uint16_t number_of_fastcharging_sessions = 0; + uint16_t accumulated_normal_charging_energy_kWh = 0; + uint16_t accumulated_fastcharging_energy_kWh = 0; CAN_frame KIA_HYUNDAI_200 = {.FD = false, .ext_ID = false, @@ -126,42 +140,26 @@ class KiaHyundai64Battery : public CanBattery { .DLC = 8, .ID = 0x2A1, .data = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; - CAN_frame KIA64_7E4_id1 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x7E4, - .data = {0x03, 0x22, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00}}; //Poll PID 03 22 01 01 - CAN_frame KIA64_7E4_id2 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x7E4, - .data = {0x03, 0x22, 0x01, 0x02, 0x00, 0x00, 0x00, 0x00}}; //Poll PID 03 22 01 02 - CAN_frame KIA64_7E4_id3 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x7E4, - .data = {0x03, 0x22, 0x01, 0x03, 0x00, 0x00, 0x00, 0x00}}; //Poll PID 03 22 01 03 - CAN_frame KIA64_7E4_id4 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x7E4, - .data = {0x03, 0x22, 0x01, 0x04, 0x00, 0x00, 0x00, 0x00}}; //Poll PID 03 22 01 04 - CAN_frame KIA64_7E4_id5 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x7E4, - .data = {0x03, 0x22, 0x01, 0x05, 0x00, 0x00, 0x00, 0x00}}; //Poll PID 03 22 01 05 - CAN_frame KIA64_7E4_id6 = {.FD = false, - .ext_ID = false, - .DLC = 8, - .ID = 0x7E4, - .data = {0x03, 0x22, 0x01, 0x06, 0x00, 0x00, 0x00, 0x00}}; //Poll PID 03 22 01 06 + CAN_frame KIA64_7E4_poll = {.FD = false, + .ext_ID = false, + .DLC = 8, + .ID = 0x7E4, + .data = {0x03, 0x22, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00}}; CAN_frame KIA64_7E4_ack = { .FD = false, .ext_ID = false, .DLC = 8, .ID = 0x7E4, - .data = {0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}; //Ack frame, correct PID is returned + .data = {0x30, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00}}; //Ack frame, correct PID is returned + static const int POLL_GROUP_1 = 0x0101; + static const int POLL_GROUP_2 = 0x0102; + static const int POLL_GROUP_3 = 0x0103; + static const int POLL_GROUP_4 = 0x0104; + static const int POLL_GROUP_5 = 0x0105; + static const int POLL_GROUP_6 = 0x0106; + static const int POLL_GROUP_11 = 0x0111; + static const int POLL_ECU_SERIAL = 0xF18C; + static const int POLL_ECU_VERSION = 0xF191; }; #endif diff --git a/Software/src/battery/KIA-HYUNDAI-64-HTML.h b/Software/src/battery/KIA-HYUNDAI-64-HTML.h index 23d5916e..d96c447a 100644 --- a/Software/src/battery/KIA-HYUNDAI-64-HTML.h +++ b/Software/src/battery/KIA-HYUNDAI-64-HTML.h @@ -11,16 +11,45 @@ class KiaHyundai64HtmlRenderer : public BatteryHtmlRenderer { String get_status_html() { String content; - auto print_hyundai = [&content](DATALAYER_INFO_KIAHYUNDAI64& data) { - content += "

Cells: " + String(data.total_cell_count) + "S

"; - content += "

12V voltage: " + String(data.battery_12V / 10.0, 1) + "

"; - content += "

Waterleakage: " + String(data.waterleakageSensor) + "

"; - content += "

Temperature, water inlet: " + String(data.temperature_water_inlet) + "

"; - content += "

Temperature, power relay: " + String(data.powerRelayTemperature) + "

"; + char readableSerialNumber[17]; // One extra space for null terminator + memcpy(readableSerialNumber, data.ecu_serial_number, sizeof(data.ecu_serial_number)); + readableSerialNumber[16] = '\0'; // Null terminate the string + char readableVersionNumber[17]; // One extra space for null terminator + memcpy(readableVersionNumber, data.ecu_version_number, sizeof(data.ecu_version_number)); + readableVersionNumber[16] = '\0'; // Null terminate the string + + content += "

BMS serial number: " + String(readableSerialNumber) + "

"; + content += "

BMS software version: " + String(readableVersionNumber) + "

"; + content += "

Cells: " + String(data.total_cell_count) + " S

"; + content += "

12V voltage: " + String(data.battery_12V / 10.0, 1) + " V

"; + content += "

Waterleakage: "; + if (data.waterleakageSensor == 0) { + content += " LEAK DETECTED

"; + } else if (data.waterleakageSensor == 164) { + content += " No leakage"; + } else { + content += String(data.waterleakageSensor) + ""; + } + content += "

Temperature, water inlet: " + String(data.temperature_water_inlet) + " °C

"; + content += "

Temperature, power relay: " + String(data.powerRelayTemperature) + " °C

"; content += "

Batterymanagement mode: " + String(data.batteryManagementMode) + "

"; content += "

BMS ignition: " + String(data.BMS_ign) + "

"; content += "

Battery relay: " + String(data.batteryRelay) + "

"; + content += "

Inverter voltage: " + String(data.inverterVoltage) + " V

"; + content += "

Isolation resistance: " + String(data.isolation_resistance_kOhm) + " kOhm

"; + content += "

Power on total time: " + String(data.powered_on_total_time) + " s

"; + content += "

Fastcharging sessions: " + String(data.number_of_fastcharging_sessions) + " x

"; + content += "

Slowcharging sessions: " + String(data.number_of_standard_charging_sessions) + " x

"; + content += + "

Normal charged energy amount: " + String(data.accumulated_normal_charging_energy_kWh) + " kWh

"; + content += "

Fastcharged energy amount: " + String(data.accumulated_fastcharging_energy_kWh) + " kWh

"; + content += "

Total amount charged energy: " + String(data.cumulative_energy_charged_kWh / 10.0) + " kWh

"; + content += + "

Total amount discharged energy: " + String(data.cumulative_energy_discharged_kWh / 10.0) + " kWh

"; + content += "

Cumulative charge current: " + String(data.cumulative_charge_current_ah / 10.0) + " Ah

"; + content += + "

Cumulative discharge current: " + String(data.cumulative_discharge_current_ah / 10.0) + " Ah

"; }; print_hyundai(*kia_datalayer); diff --git a/Software/src/battery/SAMSUNG-SDI-LV-BATTERY.cpp b/Software/src/battery/SAMSUNG-SDI-LV-BATTERY.cpp new file mode 100644 index 00000000..06149f3e --- /dev/null +++ b/Software/src/battery/SAMSUNG-SDI-LV-BATTERY.cpp @@ -0,0 +1,102 @@ +#include "SAMSUNG-SDI-LV-BATTERY.h" +#include "../communication/can/comm_can.h" +#include "../datalayer/datalayer.h" +#include "../devboard/utils/events.h" + +/* +- Baud rate: 500kbps +- Format: CAN2.0A 11 bit identifier +- Data Length: 8byte +- CAN data is transmitted with encoding in little endian – low byte first – unless stated otherwise. +- Broadcasting period: 500ms + +TODO: Implement the error bit handling for easier visualization if the battery stops operating +- alarms_frame0 +- alarms_frame1 +- protection_frame2 +- protection_frame3 + +*/ + +void SamsungSdiLVBattery::update_values() { + + datalayer.battery.status.real_soc = system_SOC * 100; + + datalayer.battery.status.remaining_capacity_Wh = static_cast( + (static_cast(datalayer.battery.status.real_soc) / 10000) * datalayer.battery.info.total_capacity_Wh); + + datalayer.battery.status.soh_pptt = system_SOH * 100; + + datalayer.battery.status.voltage_dV = system_voltage / 10; + + datalayer.battery.status.current_dA = system_current * 10; + + datalayer.battery.status.max_charge_power_W = system_voltage * charge_current_limit; + + datalayer.battery.status.max_discharge_power_W = system_voltage * discharge_current_limit; + + datalayer.battery.status.temperature_min_dC = (int16_t)(minimum_cell_temperature * 10); + + datalayer.battery.status.temperature_max_dC = (int16_t)(maximum_cell_temperature * 10); + + datalayer.battery.status.cell_max_voltage_mV = maximum_cell_voltage; + + datalayer.battery.status.cell_min_voltage_mV = minimum_cell_voltage; + + datalayer.battery.info.max_design_voltage_dV = battery_charge_voltage; + + datalayer.battery.info.min_design_voltage_dV = battery_discharge_voltage; +} + +void SamsungSdiLVBattery::handle_incoming_can_frame(CAN_frame rx_frame) { + switch (rx_frame.ID) { + case 0x500: //Voltage, current, SOC, SOH + datalayer.battery.status.CAN_battery_still_alive = CAN_STILL_ALIVE; + system_voltage = ((rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]); + system_current = ((rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]); + system_SOC = rx_frame.data.u8[4]; + system_SOH = rx_frame.data.u8[5]; + break; + case 0x501: + alarms_frame0 = rx_frame.data.u8[0]; + alarms_frame1 = rx_frame.data.u8[1]; + protection_frame2 = rx_frame.data.u8[2]; + protection_frame3 = rx_frame.data.u8[3]; + break; + case 0x502: + battery_charge_voltage = ((rx_frame.data.u8[0] << 8) | rx_frame.data.u8[1]); + charge_current_limit = ((rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]); + discharge_current_limit = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + battery_discharge_voltage = ((rx_frame.data.u8[6] << 8) | rx_frame.data.u8[7]); + break; + case 0x503: + maximum_cell_voltage = ((rx_frame.data.u8[2] << 8) | rx_frame.data.u8[3]); + minimum_cell_voltage = ((rx_frame.data.u8[4] << 8) | rx_frame.data.u8[5]); + break; + case 0x504: + maximum_cell_temperature = rx_frame.data.u8[5]; + minimum_cell_temperature = rx_frame.data.u8[6]; + break; + case 0x505: + system_permanent_failure_status_dry_contact = rx_frame.data.u8[2]; + system_permanent_failure_status_fuse_open = rx_frame.data.u8[3]; + break; + default: + break; + } +} + +void SamsungSdiLVBattery::transmit_can(unsigned long currentMillis) { + //No periodic sending required +} + +void SamsungSdiLVBattery::setup(void) { // Performs one time setup at startup + strncpy(datalayer.system.info.battery_protocol, Name, 63); + datalayer.system.info.battery_protocol[63] = '\0'; + datalayer.system.status.battery_allows_contactor_closing = true; + datalayer.battery.info.max_design_voltage_dV = MAX_PACK_VOLTAGE_DV; + datalayer.battery.info.min_design_voltage_dV = MIN_PACK_VOLTAGE_DV; + datalayer.battery.info.max_cell_voltage_mV = MAX_CELL_VOLTAGE_MV; + datalayer.battery.info.min_cell_voltage_mV = MIN_CELL_VOLTAGE_MV; + datalayer.battery.info.total_capacity_Wh = 5000; +} diff --git a/Software/src/battery/SAMSUNG-SDI-LV-BATTERY.h b/Software/src/battery/SAMSUNG-SDI-LV-BATTERY.h new file mode 100644 index 00000000..61da5b9f --- /dev/null +++ b/Software/src/battery/SAMSUNG-SDI-LV-BATTERY.h @@ -0,0 +1,46 @@ +#ifndef SAMSUNG_SDI_LV_BATTERY_H +#define SAMSUNG_SDI_LV_BATTERY_H +#include +#include "../datalayer/datalayer.h" +#include "CanBattery.h" + +#ifdef SAMSUNG_SDI_LV_BATTERY +#define SELECTED_BATTERY_CLASS SamsungSdiLVBattery +#endif + +class SamsungSdiLVBattery : public CanBattery { + public: + virtual void setup(void); + virtual void handle_incoming_can_frame(CAN_frame rx_frame); + virtual void update_values(); + virtual void transmit_can(unsigned long currentMillis); + static constexpr const char* Name = "Samsung SDI LV Battery"; + + private: + static const int MAX_PACK_VOLTAGE_DV = 600; //5000 = 500.0V + static const int MIN_PACK_VOLTAGE_DV = 300; + static const int MAX_CELL_DEVIATION_MV = 250; + static const int MAX_CELL_VOLTAGE_MV = 4200; + static const int MIN_CELL_VOLTAGE_MV = 3000; + + uint16_t system_voltage = 50000; + int16_t system_current = 0; + uint8_t system_SOC = 50; + uint8_t system_SOH = 99; + uint16_t battery_charge_voltage = 9999; + uint16_t charge_current_limit = 0; + uint16_t discharge_current_limit = 0; + uint16_t battery_discharge_voltage = 0; + uint8_t alarms_frame0 = 0; + uint8_t alarms_frame1 = 0; + uint8_t protection_frame2 = 0; + uint8_t protection_frame3 = 0; + uint16_t maximum_cell_voltage = 3700; + uint16_t minimum_cell_voltage = 3700; + int8_t maximum_cell_temperature = 0; + int8_t minimum_cell_temperature = 0; + uint8_t system_permanent_failure_status_dry_contact = 0; + uint8_t system_permanent_failure_status_fuse_open = 0; +}; + +#endif diff --git a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp index d0e62216..ac38a525 100644 --- a/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp +++ b/Software/src/communication/contactorcontrol/comm_contactorcontrol.cpp @@ -75,7 +75,6 @@ unsigned long currentTime = 0; unsigned long lastPowerRemovalTime = 0; unsigned long bmsPowerOnTime = 0; const unsigned long powerRemovalInterval = 24 * 60 * 60 * 1000; // 24 hours in milliseconds -const unsigned long powerRemovalDuration = 30000; // 30 seconds in milliseconds const unsigned long bmsWarmupDuration = 3000; void set(uint8_t pin, bool direction, uint32_t pwm_freq = 0xFFFF) { @@ -306,8 +305,9 @@ void handle_BMSpower() { } } - // If power has been removed for 30 seconds, restore the power - if (datalayer.system.status.BMS_reset_in_progress && currentTime - lastPowerRemovalTime >= powerRemovalDuration) { + // If power has been removed for user configured interval (1-59 seconds), restore the power + if (datalayer.system.status.BMS_reset_in_progress && + currentTime - lastPowerRemovalTime >= datalayer.battery.settings.user_set_bms_reset_duration_ms) { // Reapply power to the BMS digitalWrite(bms_power_pin, HIGH); bmsPowerOnTime = currentTime; diff --git a/Software/src/communication/nvm/comm_nvm.cpp b/Software/src/communication/nvm/comm_nvm.cpp index 8fbe85a9..a7ec7e2d 100644 --- a/Software/src/communication/nvm/comm_nvm.cpp +++ b/Software/src/communication/nvm/comm_nvm.cpp @@ -79,6 +79,10 @@ void init_stored_settings() { if (temp < 16) { datalayer.battery.settings.sofar_user_specified_battery_id = temp; } + temp = settings.getUInt("BMSRESETDUR", false); + if (temp != 0) { + datalayer.battery.settings.user_set_bms_reset_duration_ms = temp; + } #ifdef COMMON_IMAGE user_selected_battery_type = (BatteryType)settings.getUInt("BATTTYPE", (int)BatteryType::None); @@ -187,6 +191,9 @@ void store_settings() { if (!settings.putUInt("SOFAR_ID", datalayer.battery.settings.sofar_user_specified_battery_id)) { set_event(EVENT_PERSISTENT_SAVE_INFO, 12); } + if (!settings.putUInt("BMSRESETDUR", datalayer.battery.settings.sofar_user_specified_battery_id)) { + set_event(EVENT_PERSISTENT_SAVE_INFO, 13); + } settings.end(); // Close preferences handle } diff --git a/Software/src/datalayer/datalayer.h b/Software/src/datalayer/datalayer.h index 6f6b6c2b..af524267 100644 --- a/Software/src/datalayer/datalayer.h +++ b/Software/src/datalayer/datalayer.h @@ -139,6 +139,9 @@ typedef struct { /** The user specified maximum allowed discharge voltage, in deciVolt. 3000 = 300.0 V */ uint16_t max_user_set_discharge_voltage_dV = BATTERY_MAX_DISCHARGE_VOLTAGE; + /** The user specified BMS reset period. Keeps track on how many milliseconds should we keep power off during daily BMS reset */ + uint16_t user_set_bms_reset_duration_ms = 30000; + /** Parameters for keeping track of the limiting factor in the system */ bool user_settings_limit_discharge = false; bool user_settings_limit_charge = false; diff --git a/Software/src/datalayer/datalayer_extended.h b/Software/src/datalayer/datalayer_extended.h index d4ad098e..5b0a26ac 100644 --- a/Software/src/datalayer/datalayer_extended.h +++ b/Software/src/datalayer/datalayer_extended.h @@ -312,6 +312,7 @@ typedef struct { uint32_t pid_time_spent_over_55c = 0; uint32_t pid_contactor_closing_counter = 0; uint32_t pid_date_of_manufacture = 0; + uint16_t pid_SOH_cell_1 = 0; } DATALAYER_INFO_ECMP; typedef struct { @@ -350,6 +351,19 @@ typedef struct { uint8_t batteryManagementMode = 0; uint8_t BMS_ign = 0; uint8_t batteryRelay = 0; + uint16_t inverterVoltage = 0; + uint8_t ecu_serial_number[16] = {0}; + uint8_t ecu_version_number[16] = {0}; + uint32_t cumulative_charge_current_ah = 0; + uint32_t cumulative_discharge_current_ah = 0; + uint32_t cumulative_energy_charged_kWh = 0; + uint32_t cumulative_energy_discharged_kWh = 0; + uint32_t powered_on_total_time = 0; + uint16_t isolation_resistance_kOhm = 0; + uint16_t number_of_standard_charging_sessions = 0; + uint16_t number_of_fastcharging_sessions = 0; + uint16_t accumulated_normal_charging_energy_kWh = 0; + uint16_t accumulated_fastcharging_energy_kWh = 0; } DATALAYER_INFO_KIAHYUNDAI64; typedef struct { @@ -750,7 +764,7 @@ typedef struct { uint16_t BECMsupplyVoltage = 0; uint16_t BECMBatteryVoltage = 0; - uint16_t BECMBatteryCurrent = 0; + int16_t BECMBatteryCurrent = 0; uint16_t BECMUDynMaxLim = 0; uint16_t BECMUDynMinLim = 0; diff --git a/Software/src/devboard/hal/hal.h b/Software/src/devboard/hal/hal.h index 1bb48d97..b96fc574 100644 --- a/Software/src/devboard/hal/hal.h +++ b/Software/src/devboard/hal/hal.h @@ -59,16 +59,31 @@ class Esp32Hal { return alloc_pins(name, pins[Is]...); } + // Base case: no more pins + inline bool alloc_pins_ignore_unused_impl(const char* name) { + return alloc_pins(name); // Call with 0 pins + } + + // Recursive case: process one pin at a time + template + bool alloc_pins_ignore_unused_impl(const char* name, gpio_num_t first, Rest... rest) { + if (first == GPIO_NUM_NC) { + return alloc_pins_ignore_unused_impl(name, rest...); + } else { + return call_alloc_pins_filtered(name, first, rest...); + } + } + + // This helper just forwards pins after filtering is done + template + bool call_alloc_pins_filtered(const char* name, Pins... pins) { + return alloc_pins(name, pins...); + } + + // Entry point template bool alloc_pins_ignore_unused(const char* name, Pins... pins) { - std::vector valid_pins; - for (gpio_num_t pin : std::vector{static_cast(pins)...}) { - if (pin != GPIO_NUM_NC) { - valid_pins.push_back(pin); - } - } - - return alloc_pins_from_vector(name, valid_pins, std::make_index_sequence{}); + return alloc_pins_ignore_unused_impl(name, static_cast(pins)...); } virtual bool always_enable_bms_power() { return false; } diff --git a/Software/src/devboard/safety/safety.cpp b/Software/src/devboard/safety/safety.cpp index ea98e94c..36137fba 100644 --- a/Software/src/devboard/safety/safety.cpp +++ b/Software/src/devboard/safety/safety.cpp @@ -130,7 +130,8 @@ void update_machineryprotection() { // Battery is fully charged. Dont allow any more power into it // Normally the BMS will send 0W allowed, but this acts as an additional layer of safety - if (datalayer.battery.status.reported_soc == 10000) //Scaled SOC% value is 100.00% + if (datalayer.battery.status.reported_soc == 10000 || + datalayer.battery.status.real_soc == 10000) //Either Scaled OR Real SOC% value is 100.00% { if (!battery_full_event_fired) { set_event(EVENT_BATTERY_FULL, 0); @@ -145,7 +146,8 @@ void update_machineryprotection() { // Battery is empty. Do not allow further discharge. // Normally the BMS will send 0W allowed, but this acts as an additional layer of safety if (datalayer.battery.status.bms_status == ACTIVE) { - if (datalayer.battery.status.reported_soc == 0) { //Scaled SOC% value is 0.00% + if (datalayer.battery.status.reported_soc == 0 || + datalayer.battery.status.real_soc == 0) { //Either Scaled OR Real SOC% value is 0.00%, time to stop if (!battery_empty_event_fired) { set_event(EVENT_BATTERY_EMPTY, 0); battery_empty_event_fired = true; diff --git a/Software/src/devboard/utils/events.cpp b/Software/src/devboard/utils/events.cpp index f4c62038..12a6e0d3 100644 --- a/Software/src/devboard/utils/events.cpp +++ b/Software/src/devboard/utils/events.cpp @@ -40,6 +40,7 @@ void init_events(void) { events.entries[EVENT_CAN_CHARGER_MISSING].level = EVENT_LEVEL_INFO; events.entries[EVENT_CAN_INVERTER_MISSING].level = EVENT_LEVEL_WARNING; events.entries[EVENT_CONTACTOR_WELDED].level = EVENT_LEVEL_WARNING; + events.entries[EVENT_CONTACTOR_OPEN].level = EVENT_LEVEL_WARNING; events.entries[EVENT_CPU_OVERHEATING].level = EVENT_LEVEL_WARNING; events.entries[EVENT_CPU_OVERHEATED].level = EVENT_LEVEL_ERROR; events.entries[EVENT_WATER_INGRESS].level = EVENT_LEVEL_ERROR; @@ -191,6 +192,8 @@ String get_event_message_string(EVENTS_ENUM_TYPE event) { return "Inverter not sending messages via CAN for the last 60 seconds. Check wiring!"; case EVENT_CONTACTOR_WELDED: return "Contactors sticking/welded. Inspect battery with caution!"; + case EVENT_CONTACTOR_OPEN: + return "Battery decided to open contactors. Inspect battery!"; case EVENT_CPU_OVERHEATING: return "Battery-Emulator CPU overheating! Increase airflow/cooling to increase hardware lifespan!"; case EVENT_CPU_OVERHEATED: diff --git a/Software/src/devboard/utils/events.h b/Software/src/devboard/utils/events.h index 3dc6f147..3b26cf04 100644 --- a/Software/src/devboard/utils/events.h +++ b/Software/src/devboard/utils/events.h @@ -22,6 +22,7 @@ XX(EVENT_CAN_NATIVE_TX_FAILURE) \ XX(EVENT_CHARGE_LIMIT_EXCEEDED) \ XX(EVENT_CONTACTOR_WELDED) \ + XX(EVENT_CONTACTOR_OPEN) \ XX(EVENT_CPU_OVERHEATING) \ XX(EVENT_CPU_OVERHEATED) \ XX(EVENT_DISCHARGE_LIMIT_EXCEEDED) \ diff --git a/Software/src/devboard/utils/logging.h b/Software/src/devboard/utils/logging.h index dcc53340..f76dc3ff 100644 --- a/Software/src/devboard/utils/logging.h +++ b/Software/src/devboard/utils/logging.h @@ -2,6 +2,7 @@ #define __LOGGING_H__ #include +#include "../../../USER_SETTINGS.h" #include "Print.h" #include "types.h" diff --git a/Software/src/devboard/webserver/debug_logging_html.cpp b/Software/src/devboard/webserver/debug_logging_html.cpp index eff74dd4..f9657f9a 100644 --- a/Software/src/devboard/webserver/debug_logging_html.cpp +++ b/Software/src/devboard/webserver/debug_logging_html.cpp @@ -4,8 +4,45 @@ #include "index_html.h" #if defined(DEBUG_VIA_WEB) || defined(LOG_TO_SD) +char* strnchr(const char* s, int c, size_t n) { + // Like strchr, but only searches the first 'n' bytes of the string. + + if (s == NULL) { + return NULL; + } + + // Iterate through the string up to 'n' characters or until a null terminator is found. + for (size_t i = 0; i < n && s[i] != '\0'; ++i) { + if (s[i] == c) { + // Character found, return a pointer to it. + return (char*)&s[i]; + } + } + + // If the character to be found is the null terminator, and we haven't exceeded + // 'n' bytes, check if the null terminator is at the current position. + if (c == '\0') { + for (size_t i = 0; i < n; ++i) { + if (s[i] == '\0') { + return (char*)&s[i]; + } + } + } + + // Character not found within the first 'n' bytes. + return NULL; +} + String debug_logger_processor(void) { - String content = String(index_html_header); + String content = String(); + // Reserve enough space for the content to avoid reallocations. + if (!content.reserve(1000 + sizeof(datalayer.system.info.logged_can_messages))) { + if (content.reserve(15)) { + content += "Out of memory."; + } + return content; + } + content += index_html_header; // Page format content += "