├── .github ├── CODEOWNERS ├── ISSUE_TEMPLATE.md ├── ISSUE_TEMPLATE │ ├── bug.yml │ ├── feature_request.yml │ └── general_question.yml ├── dependabot.yaml ├── pull_request_template.md └── workflows │ ├── autogen.yaml │ ├── docker-publish.yml │ ├── release.yml │ └── test.yaml ├── .gitignore ├── .mockery.yaml ├── LICENSE ├── Makefile ├── README.md ├── docker-compose.test.yaml ├── example ├── 1.6 │ ├── cp │ │ ├── Dockerfile │ │ ├── charge_point_sim.go │ │ ├── config.go │ │ └── handler.go │ ├── create-test-certificates.sh │ ├── cs │ │ ├── Dockerfile │ │ ├── central_system_sim.go │ │ └── handler.go │ ├── docker-compose.tls.yml │ ├── docker-compose.yml │ ├── openssl-cp.conf │ └── openssl-cs.conf └── 2.0.1 │ ├── chargingstation │ ├── Dockerfile │ ├── authorization_handler.go │ ├── availability_handler.go │ ├── charging_station_sim.go │ ├── config.go │ ├── data_handler.go │ ├── diagnostics_handler.go │ ├── display_handler.go │ ├── firmware_handler.go │ ├── handler.go │ ├── iso15118_handler.go │ ├── localauth_handler.go │ ├── provisioning_handler.go │ ├── remotecontrol_handler.go │ ├── reservation_handler.go │ ├── smartcharging_handler.go │ ├── tariffcost_handler.go │ └── transactions_handler.go │ ├── create-test-certificates.sh │ ├── csms │ ├── Dockerfile │ ├── authorization_handler.go │ ├── availability_handler.go │ ├── csms_sim.go │ ├── data_handler.go │ ├── diagnostics_handler.go │ ├── display_handler.go │ ├── firmware_handler.go │ ├── handler.go │ ├── iso15118_handler.go │ ├── meter_handler.go │ ├── provisioning_handler.go │ ├── reservation_handler.go │ ├── security_handler.go │ ├── smartcharging_handler.go │ └── transactions_handler.go │ ├── docker-compose.tls.yml │ ├── docker-compose.yml │ ├── openssl-chargingstation.conf │ └── openssl-csms.conf ├── go.mod ├── go.sum ├── internal └── callbackqueue │ └── callbackqueue.go ├── logging └── log.go ├── ocpp └── ocpp.go ├── ocpp1.6 ├── central_system.go ├── certificates │ ├── certificates.go │ ├── delete_certificate.go │ ├── get_installed_certificates.go │ └── install_certificate.go ├── charge_point.go ├── core │ ├── authorize.go │ ├── boot_notification.go │ ├── change_availability.go │ ├── change_configuration.go │ ├── clear_cache.go │ ├── core.go │ ├── data_transfer.go │ ├── get_configuration.go │ ├── heartbeat.go │ ├── meter_values.go │ ├── remote_start_transaction.go │ ├── remote_stop_transaction.go │ ├── reset.go │ ├── start_transaction.go │ ├── status_notification.go │ ├── stop_transaction.go │ └── unlock_connector.go ├── extendedtriggermessage │ ├── extended_trigger_message.go │ └── trigger_message.go ├── firmware │ ├── diagnostics_status_notification.go │ ├── firmware.go │ ├── firmware_status_notification.go │ ├── get_diagnostics.go │ └── update_firmware.go ├── localauth │ ├── get_local_list_version.go │ ├── local_auth_list.go │ └── send_local_list.go ├── logging │ ├── get_log.go │ ├── log.go │ └── log_status_notification.go ├── remotetrigger │ ├── remote_trigger.go │ └── trigger_message.go ├── reservation │ ├── cancel_reservation.go │ ├── reservation.go │ └── reserve_now.go ├── securefirmware │ ├── secure_firmware.go │ ├── signed_update_firmware.go │ └── signed_update_firmware_status_notitfication.go ├── security │ ├── certificate_signed.go │ ├── security.go │ ├── security_event_notification.go │ └── sign_certificate.go ├── smartcharging │ ├── clear_charging_profile.go │ ├── get_composite_schedule.go │ ├── set_charging_profile.go │ └── smart_charging.go ├── types │ ├── datetime.go │ ├── security_extension.go │ └── types.go └── v16.go ├── ocpp1.6_test ├── authorize_test.go ├── boot_notification_test.go ├── cancel_reservation_test.go ├── certificate_signed_test.go ├── change_availability_test.go ├── change_configuration_test.go ├── clear_cache_test.go ├── clear_charging_profile_test.go ├── common_test.go ├── data_transfer_test.go ├── delete_certificate_test.go ├── diagnostics_status_notification_test.go ├── firmware_status_notification_test.go ├── get_composite_schedule_test.go ├── get_configuration_test.go ├── get_diagnostics_test.go ├── get_installed_certificate_ids_test.go ├── get_local_list_version_test.go ├── heartbeat_test.go ├── install_certificate_test.go ├── meter_values_test.go ├── mocks │ ├── mock_certificates_charge_point_handler.go │ ├── mock_core_central_system_handler.go │ ├── mock_core_charge_point_handler.go │ ├── mock_extended_trigger_message_charge_point_handler.go │ ├── mock_firmware_central_system_handler.go │ ├── mock_firmware_charge_point_handler.go │ ├── mock_local_auth_list_central_system_handler.go │ ├── mock_local_auth_list_charge_point_handler.go │ ├── mock_logging_central_system_handler.go │ ├── mock_logging_charge_point_handler.go │ ├── mock_ocpp16.go │ ├── mock_remote_trigger_central_system_handler.go │ ├── mock_remote_trigger_charge_point_handler.go │ ├── mock_reservation_central_system_handler.go │ ├── mock_reservation_charge_point_handler.go │ ├── mock_secure_firmware_CentralSystemHandler.go │ ├── mock_secure_firmware_ChargePointHandler.go │ ├── mock_security_central_system_handler.go │ ├── mock_security_charge_point_handler.go │ ├── mock_smart_charging_central_system_handler.go │ └── mock_smart_charging_charge_point_handler.go ├── ocpp16_extension_test.go ├── ocpp16_test.go ├── proto_test.go ├── remote_start_transaction_test.go ├── remote_stop_transaction_test.go ├── reserve_now_test.go ├── reset_test.go ├── send_local_list_test.go ├── set_charging_profile_test.go ├── sign_certificate_test.go ├── signed_update_firmware_test.go ├── start_transaction_test.go ├── status_notification_test.go ├── stop_transaction_test.go ├── trigger_message_test.go ├── unlock_connector_test.go └── update_firmware_test.go ├── ocpp2.0.1 ├── authorization │ ├── authorization.go │ ├── authorize.go │ └── clear_cache.go ├── availability │ ├── availability.go │ ├── change_availability.go │ ├── heartbeat.go │ └── status_notification.go ├── charging_station.go ├── csms.go ├── data │ ├── data.go │ └── data_transfer.go ├── diagnostics │ ├── clear_variable_monitoring.go │ ├── customer_information.go │ ├── diagnostics.go │ ├── get_log.go │ ├── get_monitoring_report.go │ ├── log_status_notification.go │ ├── notify_customer_information.go │ ├── notify_event.go │ ├── notify_monitoring_report.go │ ├── set_monitoring_base.go │ ├── set_monitoring_level.go │ ├── set_variable_monitoring.go │ └── types.go ├── display │ ├── clear_display_message.go │ ├── display.go │ ├── get_display_messages.go │ ├── notify_display_messages.go │ ├── set_display_message.go │ └── types.go ├── firmware │ ├── firmware.go │ ├── firmware_status_notification.go │ ├── publish_firmware.go │ ├── publish_firmware_status_notification.go │ ├── unpublish_firmware.go │ └── update_firmware.go ├── iso15118 │ ├── delete_certificate.go │ ├── get_15118ev_certificate.go │ ├── get_certificate_status.go │ ├── get_installed_certificate_ids.go │ ├── install_certificate.go │ └── iso_15118.go ├── localauth │ ├── get_local_list_version.go │ ├── local_auth_list.go │ └── send_local_list.go ├── meter │ ├── meter.go │ └── meter_values.go ├── provisioning │ ├── boot_notification.go │ ├── get_base_report.go │ ├── get_report.go │ ├── get_variables.go │ ├── notify_report.go │ ├── provisioning.go │ ├── reset.go │ ├── set_network_profile.go │ └── set_variables.go ├── remotecontrol │ ├── remote_control.go │ ├── request_start_transaction.go │ ├── request_stop_transaction.go │ ├── trigger_message.go │ └── unlock_connector.go ├── reservation │ ├── cancel_reservation.go │ ├── reservation.go │ ├── reservation_status_update.go │ └── reserve_now.go ├── security │ ├── certificate_signed.go │ ├── security.go │ ├── security_event_notification.go │ └── sign_certificate.go ├── smartcharging │ ├── clear_charging_profile.go │ ├── cleared_charging_limit.go │ ├── get_charging_profiles.go │ ├── get_composite_schedule.go │ ├── notify_charging_limit.go │ ├── notify_ev_charging_needs.go │ ├── notify_ev_charging_schedule.go │ ├── report_charging_profiles.go │ ├── set_charging_profile.go │ └── smart_charging.go ├── tariffcost │ ├── cost_updated.go │ └── tariff_cost.go ├── transactions │ ├── get_transaction_status.go │ ├── transaction_event.go │ └── transactions.go ├── types │ ├── datetime.go │ └── types.go └── v2.go ├── ocpp2.0.1_test ├── authorize_test.go ├── boot_notification_test.go ├── cancel_reservation_test.go ├── certificate_signed_test.go ├── change_availability_test.go ├── clear_cache_test.go ├── clear_charging_profile_test.go ├── clear_display_message_test.go ├── clear_variable_monitoring_test.go ├── cleared_charging_limit_test.go ├── common_test.go ├── cost_updated_test.go ├── customer_information_test.go ├── data_transfer_test.go ├── delete_certificate_test.go ├── firmware_status_notification_test.go ├── get_15118ev_certificate_test.go ├── get_base_report_test.go ├── get_certificate_status_test.go ├── get_charging_profiles_test.go ├── get_composite_schedule_test.go ├── get_display_messages_test.go ├── get_installed_certificate_ids_test.go ├── get_local_list_version_test.go ├── get_log_test.go ├── get_monitoring_report_test.go ├── get_report_test.go ├── get_transaction_status_test.go ├── get_variables_test.go ├── heartbeat_test.go ├── install_certificate_test.go ├── log_status_notification_test.go ├── meter_values_test.go ├── notify_charging_limit_test.go ├── notify_customer_information_test.go ├── notify_display_messages_test.go ├── notify_ev_charging_needs_test.go ├── notify_ev_charging_schedule_test.go ├── notify_event_test.go ├── notify_monitoring_report_test.go ├── notify_report_test.go ├── ocpp2_test.go ├── proto_test.go ├── publish_firmware_status_notification_test.go ├── publish_firmware_test.go ├── report_charging_profiles_test.go ├── request_start_transaction_test.go ├── request_stop_transaction_test.go ├── reservation_status_update_test.go ├── reserve_now_test.go ├── reset_test.go ├── security_event_notification_test.go ├── send_local_list_test.go ├── set_charging_profile_test.go ├── set_display_message_test.go ├── set_monitoring_base_test.go ├── set_monitoring_level_test.go ├── set_network_profile_test.go ├── set_variable_monitoring_test.go ├── set_variables_test.go ├── sign_certificate_test.go ├── status_notification_test.go ├── transaction_event_test.go ├── trigger_message_test.go ├── unlock_connector_test.go ├── unpublish_firmware_test.go └── update_firmware_test.go ├── ocppj ├── central_system_test.go ├── charge_point_test.go ├── client.go ├── dispatcher.go ├── dispatcher_test.go ├── mocks │ ├── mock_CanceledRequestHandler.go │ ├── mock_ClientDispatcher.go │ ├── mock_ClientHandler.go │ ├── mock_ClientState.go │ ├── mock_ErrorHandler.go │ ├── mock_InvalidMessageHook.go │ ├── mock_Message.go │ ├── mock_RequestHandler.go │ ├── mock_RequestQueue.go │ ├── mock_ResponseHandler.go │ ├── mock_ServerDispatcher.go │ ├── mock_ServerQueueMap.go │ ├── mock_ServerState.go │ └── mock_dialector.go ├── ocppj.go ├── ocppj_test.go ├── queue.go ├── queue_test.go ├── server.go ├── state.go └── state_test.go └── ws ├── client.go ├── mocks ├── mock_Channel.go ├── mock_CheckClientHandler.go ├── mock_Client.go ├── mock_ClientOpt.go ├── mock_ConnectedHandler.go ├── mock_DisconnectedHandler.go ├── mock_ErrorHandler.go ├── mock_MessageHandler.go ├── mock_Server.go ├── mock_ServerOpt.go ├── mock_WsClient.go └── mock_WsServer.go ├── network_test.go ├── server.go ├── toxiproxy.service ├── websocket.go └── websocket_test.go /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @lorenzodonini 2 | ocpp1.6/certificates @xBlaz3kx 3 | ocpp1.6/securefirmware @xBlaz3kx 4 | ocpp1.6/security @xBlaz3kx 5 | ocpp1.6/logging @xBlaz3kx 6 | ocpp1.6/extendedtriggermessage @xBlaz3kx -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | **OCPP version:** 4 | [x] **1.6** 5 | [ ] **2.0.1** 6 | 7 | **I'm submitting a ...** 8 | 9 | [ ] bug report 10 | [ ] feature request 11 | 12 | **Current behavior:** 13 | 14 | 15 | **Expected behavior:** 16 | 17 | 18 | **Steps to reproduce:** 19 | 20 | 21 | **Related code:** 22 | 23 | 30 | 31 | ``` 32 | insert short code snippets here 33 | ``` 34 | 35 | **Other information:** 36 | 37 | 38 | ``` 39 | insert the output here 40 | ``` -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug.yml: -------------------------------------------------------------------------------- 1 | name: '🐛 Bug Report' 2 | description: 'Submit a bug report' 3 | title: '🐛 Bug: ' 4 | labels: [ 'type: bug' ] 5 | body: 6 | - type: textarea 7 | id: description 8 | validations: 9 | required: true 10 | attributes: 11 | label: '📜 Description' 12 | description: 'A clear and concise description of what the bug is.' 13 | placeholder: 'It bugs out when ...' 14 | - type: textarea 15 | id: steps-to-reproduce 16 | validations: 17 | required: true 18 | attributes: 19 | label: '👟 Reproduction steps' 20 | description: 'How do you trigger this bug? Please walk us through it step by step.' 21 | placeholder: "Charge point sends a BootNotification request to the Central System." 22 | - type: textarea 23 | id: expected-behavior 24 | validations: 25 | required: true 26 | attributes: 27 | label: '👍 Expected behavior' 28 | description: 'What did you think should happen?' 29 | placeholder: 'It should ...' 30 | - type: textarea 31 | id: actual-behavior 32 | validations: 33 | required: true 34 | attributes: 35 | label: '👎 Actual Behavior' 36 | description: 'What did actually happen? Add screenshots, if applicable.' 37 | placeholder: 'It actually ...' 38 | - type: checkboxes 39 | id: ocpp-version 40 | attributes: 41 | label: 'What OCPP version are you using?' 42 | options: 43 | - label: "OCPP 1.6" 44 | required: false 45 | - label: "OCPP 2.0.1" 46 | required: false 47 | - type: checkboxes 48 | id: ocpp-extensions 49 | attributes: 50 | label: 'Are you using any OCPP extensions?' 51 | options: 52 | - label: "OCPP 1.6 Security" 53 | required: false 54 | - label: "OCPP 1.6 Plug and Charge" 55 | required: false 56 | - type: input 57 | id: release-version 58 | validations: 59 | required: false 60 | attributes: 61 | label: release version 62 | description: Mention the release version of the software you are using. 63 | placeholder: v0.18.0 64 | - type: textarea 65 | id: additional-context 66 | validations: 67 | required: false 68 | attributes: 69 | label: '📃 Provide any additional context for the Bug.' 70 | description: 'Add any other context about the problem here.' 71 | placeholder: 'It actually ...' 72 | - type: checkboxes 73 | id: no-duplicate-issues 74 | attributes: 75 | label: '👀 Have you spent some time to check if this bug has been found before?' 76 | options: 77 | - label: "I checked and didn't find a similar issue" 78 | required: true -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: 🚀 Feature 2 | description: 'Submit a proposal for a new feature' 3 | title: '🚀 Feature: ' 4 | labels: [ feature ] 5 | body: 6 | - type: textarea 7 | id: feature-description 8 | validations: 9 | required: true 10 | attributes: 11 | label: '🔖 Feature description' 12 | description: 'A clear and concise description of what the feature is.' 13 | placeholder: 'You should add ...' 14 | - type: textarea 15 | id: pitch 16 | validations: 17 | required: true 18 | attributes: 19 | label: '🎤 Why is this feature needed ?' 20 | description: 'Please explain why this feature should be implemented and how it would be used. Add examples, if 21 | applicable.' 22 | placeholder: 'In my use-case, ...' 23 | - type: textarea 24 | id: solution 25 | validations: 26 | required: true 27 | attributes: 28 | label: '✌️ How do you aim to achieve this?' 29 | description: 'A clear and concise description of what you want to happen.' 30 | placeholder: 'I want this feature to, ...' 31 | - type: textarea 32 | id: alternative 33 | validations: 34 | required: false 35 | attributes: 36 | label: '🔄️ Additional Information' 37 | description: "A clear and concise description of any alternative solutions or additional solutions you've considered." 38 | placeholder: 'I tried, ...' 39 | - type: checkboxes 40 | id: no-duplicate-issues 41 | attributes: 42 | label: '👀 Have you spent some time to check if this feature request has been raised before?' 43 | options: 44 | - label: "I checked and didn't find similar issue" 45 | required: true -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/general_question.yml: -------------------------------------------------------------------------------- 1 | name: '❔ Question' 2 | description: 'Submit a general question to the community.' 3 | title: '❔ Question: ' 4 | labels: [ 'type: question' ] 5 | body: 6 | - type: textarea 7 | id: description 8 | validations: 9 | required: true 10 | attributes: 11 | label: '❔ What is your question?' 12 | description: 'The stage is yours. Ask away! Try to provide as much context as possible.' 13 | placeholder: 'What is the best way to ...' 14 | - type: checkboxes 15 | id: ocpp-version 16 | attributes: 17 | label: 'Which OCPP version referring to?' 18 | options: 19 | - label: "OCPP 1.6" 20 | required: false 21 | - label: "OCPP 2.0.1" 22 | required: false 23 | - type: checkboxes 24 | id: ocpp-extensions 25 | attributes: 26 | label: 'Are you using any OCPP extensions?' 27 | options: 28 | - label: "OCPP 1.6 Security" 29 | required: false 30 | - label: "OCPP 1.6 Plug and Charge" 31 | required: false 32 | - type: checkboxes 33 | id: no-duplicate-issues 34 | attributes: 35 | label: '👀 Have you spent some time to check if this question has been asked before?' 36 | options: 37 | - label: "I checked and didn't find a similar issue" 38 | required: true -------------------------------------------------------------------------------- /.github/dependabot.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "monthly" 7 | reviewers: 8 | - "lorenzodonini" 9 | 10 | - package-ecosystem: "docker" 11 | directory: "/example/" 12 | schedule: 13 | interval: "monthly" 14 | reviewers: 15 | - "lorenzodonini" 16 | 17 | - package-ecosystem: "gomod" 18 | directory: "/" 19 | schedule: 20 | interval: "monthly" 21 | reviewers: 22 | - "lorenzodonini" -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Proposed changes 2 | 3 | Describe the big picture of your changes here to communicate to the maintainers why we should accept this pull request. 4 | If it fixes a bug or resolves a feature request, be sure to link to that issue. 5 | 6 | ## Types of changes 7 | 8 | What types of changes does your code introduce? 9 | _Put an `x` in the boxes that apply_ 10 | 11 | - [ ] Bugfix (non-breaking change which fixes an issue) 12 | - [ ] New feature (non-breaking change which adds functionality) 13 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 14 | - [ ] Documentation Update (if none of the other choices apply) 15 | 16 | ## Checklist 17 | 18 | _Put an `x` in the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of 19 | them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before 20 | merging your code._ 21 | 22 | - [ ] I have read the [CONTRIBUTING](https://github.com/xBlaz3kx/ocppManager-go/blob/master/CONTRIBUTING.md) doc 23 | - [ ] I have signed the CLA 24 | - [ ] Lint and unit tests pass locally with my changes 25 | - [ ] I have added tests that prove my fix is effective or that my feature works 26 | - [ ] I have added necessary documentation (if appropriate) 27 | - [ ] Any dependent changes have been merged and published in downstream modules 28 | 29 | ## Further comments 30 | 31 | If this is a relatively large or complex change, kick off the discussion by explaining why you chose the solution you 32 | did and what alternatives you considered, etc... -------------------------------------------------------------------------------- /.github/workflows/autogen.yaml: -------------------------------------------------------------------------------- 1 | name: Autogenerate 2 | on: 3 | # Note: When testing with nektos/act, the workflow_dispatch does not work as of version 0.2.63 4 | workflow_dispatch: 5 | 6 | pull_request: 7 | paths-ignore: 8 | - '*.md' 9 | 10 | jobs: 11 | mockery: 12 | name: Generate mocks 13 | runs-on: ubuntu-latest 14 | 15 | # Permissions are needed to push the changes back to the repository 16 | permissions: 17 | contents: write 18 | 19 | steps: 20 | - name: Checkout code 21 | uses: actions/checkout@v4 22 | with: 23 | ref: ${{ github.head_ref }} 24 | 25 | - name: Setup Go 26 | uses: actions/setup-go@v5 27 | with: 28 | go-version: 1.17 29 | 30 | - name: Install Mockery 31 | uses: jaxxstorm/action-install-gh-release@v1.10.0 32 | with: # Grab a specific tag 33 | repo: vektra/mockery 34 | tag: v2.51.0 35 | 36 | - name: Generate mocks 37 | run: mockery 38 | 39 | # Commit all changed files back to the repository 40 | - uses: stefanzweifel/git-auto-commit-action@v5 41 | #with: 42 | # commit_message: [ Autogen ] Generated mocks 43 | # # Mockery can generate new files, so we need to add them to the commit as well 44 | # add_options: '$(git ls-files -o --exclude-standard)' 45 | # file_pattern: '*.go' # Only commit changes to Go files 46 | # # Only create a branch when the workflow is triggered manually 47 | # create_branch: ${{ github.event_name == 'workflow_dispatch' }} 48 | -------------------------------------------------------------------------------- /.github/workflows/docker-publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish examples 2 | on: 3 | push: 4 | paths-ignore: 5 | - "**.md" 6 | branches: 7 | - master 8 | jobs: 9 | publish_latest: 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout code 13 | uses: actions/checkout@v4.2.2 14 | - name: Setup QEMU 15 | uses: docker/setup-qemu-action@v3 16 | - uses: docker/setup-buildx-action@v3 17 | - name: Login to DockerHub 18 | uses: docker/login-action@v3 19 | with: 20 | username: ${{ secrets.DOCKER_USERNAME }} 21 | password: ${{ secrets.DOCKER_PASSWORD }} 22 | - name: Build Central System 1.6 example 23 | uses: docker/build-push-action@v6 24 | with: 25 | push: true 26 | tags: ldonini/ocpp1.6-central-system:latest 27 | file: example/1.6/cs/Dockerfile 28 | platforms: linux/amd64,linux/arm64 29 | context: . 30 | - name: Build Charge Point 1.6 example 31 | uses: docker/build-push-action@v6 32 | with: 33 | push: true 34 | tags: ldonini/ocpp1.6-charge-point:latest 35 | file: example/1.6/cp/Dockerfile 36 | platforms: linux/amd64,linux/arm64 37 | context: . 38 | - name: Build CSMS 2.0.1 example 39 | uses: docker/build-push-action@v6 40 | with: 41 | push: true 42 | tags: ldonini/ocpp2.0.1-csms:latest 43 | file: example/2.0.1/csms/Dockerfile 44 | platforms: linux/amd64,linux/arm64 45 | context: . 46 | - name: Build Charging Station 2.0.1 example 47 | uses: docker/build-push-action@v6 48 | with: 49 | push: true 50 | tags: ldonini/ocpp2.0.1-charging-station:latest 51 | file: example/2.0.1/chargingstation/Dockerfile 52 | platforms: linux/amd64,linux/arm64 53 | context: . 54 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release examples 2 | on: 3 | release: 4 | types: [published,prereleased] 5 | jobs: 6 | release_tag: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Checkout code 10 | uses: actions/checkout@v4.2.2 11 | - name: Setup QEMU 12 | uses: docker/setup-qemu-action@v3 13 | - uses: docker/setup-buildx-action@v3 14 | - name: Login to DockerHub 15 | uses: docker/login-action@v3 16 | with: 17 | username: ${{ secrets.DOCKER_USERNAME }} 18 | password: ${{ secrets.DOCKER_PASSWORD }} 19 | - name: Release Central System 1.6 example 20 | uses: docker/build-push-action@v6 21 | with: 22 | push: true 23 | tags: ldonini/ocpp1.6-central-system:${{ github.event.release.tag_name }} 24 | file: example/1.6/cs/Dockerfile 25 | context: . 26 | - name: Release Charge Point 1.6 example 27 | uses: docker/build-push-action@v6 28 | with: 29 | push: true 30 | tags: ldonini/ocpp1.6-charge-point:${{ github.event.release.tag_name }} 31 | file: example/1.6/cp/Dockerfile 32 | context: . 33 | - name: Release CSMS 2.0.1 example 34 | uses: docker/build-push-action@v6 35 | with: 36 | push: true 37 | tags: ldonini/ocpp2.0.1-csms:${{ github.event.release.tag_name }} 38 | file: example/2.0.1/csms/Dockerfile 39 | platforms: linux/amd64,linux/arm64 40 | context: . 41 | - name: Release charging station 2.0.1 example 42 | uses: docker/build-push-action@v6 43 | with: 44 | push: true 45 | tags: ldonini/ocpp2.0.1-charging-station:${{ github.event.release.tag_name }} 46 | file: example/2.0.1/chargingstation/Dockerfile 47 | platforms: linux/amd64,linux/arm64 48 | context: . 49 | -------------------------------------------------------------------------------- /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | name: Test 2 | on: 3 | push: 4 | paths-ignore: 5 | - "**.md" 6 | - LICENSE 7 | 8 | pull_request: 9 | paths-ignore: 10 | - "**.md" 11 | - LICENSE 12 | 13 | workflow_dispatch: 14 | 15 | jobs: 16 | unit: 17 | runs-on: ubuntu-latest 18 | name: Unit tests 19 | steps: 20 | - name: Checkout code 21 | uses: actions/checkout@v4.2.2 22 | - name: Run tests 23 | run: | 24 | docker compose -f docker-compose.test.yaml up unit_test --abort-on-container-exit 25 | - name: Archive code coverage results 26 | uses: actions/upload-artifact@v4 27 | with: 28 | name: unit_coverage_${{ github.sha }} 29 | path: ./coverage.out 30 | 31 | integration: 32 | name: Integration tests 33 | runs-on: ubuntu-latest 34 | needs: unit 35 | steps: 36 | - name: Checkout code 37 | uses: actions/checkout@v4.2.2 38 | - name: Download coverage from unit tests 39 | uses: actions/download-artifact@v4 40 | with: 41 | name: unit_coverage_${{ github.sha }} 42 | - name: Run integration tests 43 | run: | 44 | docker compose -f docker-compose.test.yaml up integration_test --abort-on-container-exit 45 | - name: Merge coverage 46 | run: | 47 | sed '1d;$d' integration_coverage.out >> coverage.out 48 | - name: Archive code coverage results 49 | uses: actions/upload-artifact@v4 50 | with: 51 | name: coverage_${{ github.sha }} 52 | path: ./coverage.out 53 | 54 | publish_coverage: 55 | runs-on: ubuntu-latest 56 | # Unit and integration tests must be run before publishing coverage 57 | needs: [ unit, integration ] 58 | name: Publish coverage 59 | steps: 60 | - name: Checkout code 61 | uses: actions/checkout@v4.2.2 62 | - name: Download coverage from tests 63 | uses: actions/download-artifact@v4 64 | with: 65 | name: coverage_${{ github.sha }} 66 | - name: Publish 67 | uses: shogo82148/actions-goveralls@v1 68 | with: 69 | path-to-profile: coverage.out 70 | env: 71 | COVERALLS_TOKEN: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, build with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Idea 15 | .idea/* 16 | 17 | # Project-specific 18 | certs/ 19 | 20 | central_system_sim 21 | charge_point_sim -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | docker compose -f docker-compose.test.yaml up toxiproxy integration_test --abort-on-container-exit 3 | -------------------------------------------------------------------------------- /docker-compose.test.yaml: -------------------------------------------------------------------------------- 1 | version: "3.9" 2 | services: 3 | toxiproxy: 4 | image: ghcr.io/shopify/toxiproxy:2.11.0 5 | hostname: toxiproxy 6 | 7 | unit_test: 8 | # The tests might require permissions to write to coverage out files. 9 | # If you encounter issues with permissions, you can try running the container as root. 10 | user: root 11 | image: cimg/go:1.22.5 12 | working_dir: /etc/ocpp-go 13 | volumes: 14 | - .:/etc/ocpp-go:rw 15 | command: 16 | - /bin/bash 17 | - -c 18 | - | 19 | go test -v -covermode=count -coverprofile=coverage.out ./ocppj 20 | go test -v -covermode=count -coverprofile=ocpp16.out -coverpkg=github.com/lorenzodonini/ocpp-go/ocpp1.6/... github.com/lorenzodonini/ocpp-go/ocpp1.6_test 21 | go test -v -covermode=count -coverprofile=ocpp201.out -coverpkg=github.com/lorenzodonini/ocpp-go/ocpp2.0.1/... github.com/lorenzodonini/ocpp-go/ocpp2.0.1_test 22 | sed '1d;$d' ocpp16.out >> coverage.out 23 | sed '1d;$d' ocpp201.out >> coverage.out 24 | 25 | integration_test: 26 | image: cimg/go:1.22.5 27 | # The tests might require permissions to write to coverage out files. 28 | # If you encounter issues with permissions, you can try running the container as root. 29 | user: root 30 | working_dir: /etc/ocpp-go 31 | environment: 32 | - TOXIPROXY_HOST=toxiproxy 33 | - TOXIPROXY_PORT=8474 34 | - PROXY_OCPP_LISTENER=toxiproxy:8886 35 | - PROXY_OCPP_UPSTREAM=integration_test:8887 36 | depends_on: 37 | - toxiproxy 38 | command: 39 | - /bin/bash 40 | - -c 41 | - go test ./ws -v -covermode=count -coverprofile=integration_coverage.out 42 | volumes: 43 | - .:/etc/ocpp-go:rw -------------------------------------------------------------------------------- /example/1.6/cp/Dockerfile: -------------------------------------------------------------------------------- 1 | ############################ 2 | # STEP 1 build executable binary 3 | ############################ 4 | FROM golang:alpine AS builder 5 | 6 | ENV GO111MODULE on 7 | WORKDIR $GOPATH/src/github.com/lorenzodonini/ocpp-go 8 | COPY . . 9 | # Fetch dependencies. 10 | RUN go mod download 11 | # Build the binary. 12 | RUN go build -ldflags="-w -s" -o /go/bin/charge_point example/1.6/cp/*.go 13 | 14 | ############################ 15 | # STEP 2 build a small image 16 | ############################ 17 | FROM alpine 18 | 19 | COPY --from=builder /go/bin/charge_point /bin/charge_point 20 | 21 | # Add CA certificates 22 | # It currently throws a warning on alpine: WARNING: ca-certificates.crt does not contain exactly one certificate or CRL: skipping. 23 | # Ignore the warning. 24 | RUN apk update && apk add ca-certificates && rm -rf /var/cache/apk/* && update-ca-certificates 25 | 26 | CMD [ "charge_point" ] 27 | -------------------------------------------------------------------------------- /example/1.6/create-test-certificates.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | mkdir -p certs/cs 4 | mkdir -p certs/cp 5 | cd certs 6 | # Create CA 7 | openssl req -new -x509 -nodes -sha256 -days 120 -extensions v3_ca -keyout ca.key -out ca.crt -subj "/CN=ocpp-go-example" 8 | # Generate self-signed central-system certificate 9 | openssl genrsa -out cs/central-system.key 4096 10 | openssl req -new -out cs/central-system.csr -key cs/central-system.key -config ../openssl-cs.conf -sha256 11 | openssl x509 -req -in cs/central-system.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out cs/central-system.crt -days 120 -extensions req_ext -extfile ../openssl-cs.conf -sha256 12 | # Generate self-signed charge-point certificate 13 | openssl genrsa -out cp/charge-point.key 4096 14 | openssl req -new -out cp/charge-point.csr -key cp/charge-point.key -config ../openssl-cp.conf -sha256 15 | openssl x509 -req -in cp/charge-point.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out cp/charge-point.crt -days 120 -extensions req_ext -extfile ../openssl-cp.conf -sha256 16 | -------------------------------------------------------------------------------- /example/1.6/cs/Dockerfile: -------------------------------------------------------------------------------- 1 | ############################ 2 | # STEP 1 build executable binary 3 | ############################ 4 | FROM golang:alpine AS builder 5 | 6 | ENV GO111MODULE on 7 | WORKDIR $GOPATH/src/github.com/lorenzodonini/ocpp-go 8 | COPY . . 9 | # Fetch dependencies. 10 | RUN go mod download 11 | # Build the binary. 12 | RUN go build -ldflags="-w -s" -o /go/bin/central_system example/1.6/cs/*.go 13 | 14 | ############################ 15 | # STEP 2 build a small image 16 | ############################ 17 | FROM alpine 18 | 19 | COPY --from=builder /go/bin/central_system /bin/central_system 20 | 21 | # Ports on which the service may be exposed. 22 | EXPOSE 8887 23 | EXPOSE 443 24 | 25 | CMD [ "central_system" ] 26 | -------------------------------------------------------------------------------- /example/1.6/docker-compose.tls.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | central-system: 4 | build: 5 | context: ../.. 6 | dockerfile: cs/Dockerfile 7 | image: ldonini/ocpp1.6-central-system:latest 8 | container_name: central-system 9 | volumes: 10 | - ./certs/cs:/usr/local/share/certs 11 | - ./certs/ca.crt:/usr/local/share/certs/ca.crt 12 | environment: 13 | - SERVER_LISTEN_PORT=443 14 | - TLS_ENABLED=true 15 | - CA_CERTIFICATE_PATH=/usr/local/share/certs/ca.crt 16 | - SERVER_CERTIFICATE_PATH=/usr/local/share/certs/central-system.crt 17 | - SERVER_CERTIFICATE_KEY_PATH=/usr/local/share/certs/central-system.key 18 | ports: 19 | - "443:443" 20 | networks: 21 | - sim 22 | tty: true 23 | charge-point: 24 | build: 25 | context: ../.. 26 | dockerfile: cp/Dockerfile 27 | image: ldonini/ocpp1.6-charge-point:latest 28 | container_name: charge-point 29 | volumes: 30 | - ./certs/cp:/usr/local/share/certs 31 | - ./certs/ca.crt:/usr/local/share/certs/ca.crt 32 | environment: 33 | - CLIENT_ID=chargePointSim 34 | - CENTRAL_SYSTEM_URL=wss://central-system:443 35 | - TLS_ENABLED=true 36 | - CA_CERTIFICATE_PATH=/usr/local/share/certs/ca.crt 37 | - CLIENT_CERTIFICATE_PATH=/usr/local/share/certs/charge-point.crt 38 | - CLIENT_CERTIFICATE_KEY_PATH=/usr/local/share/certs/charge-point.key 39 | networks: 40 | - sim 41 | tty: true 42 | 43 | networks: 44 | sim: 45 | driver: bridge 46 | -------------------------------------------------------------------------------- /example/1.6/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | central-system: 4 | build: 5 | context: ../.. 6 | dockerfile: cs/Dockerfile 7 | image: ldonini/ocpp1.6-central-system:latest 8 | container_name: central-system 9 | environment: 10 | - SERVER_LISTEN_PORT=8887 11 | ports: 12 | - "8887:8887" 13 | networks: 14 | - sim 15 | tty: true 16 | charge-point: 17 | depends_on: 18 | central-system: 19 | condition: service_started 20 | build: 21 | context: ../.. 22 | dockerfile: cp/Dockerfile 23 | image: ldonini/ocpp1.6-charge-point:latest 24 | container_name: charge-point 25 | environment: 26 | - CLIENT_ID=chargePointSim 27 | - CENTRAL_SYSTEM_URL=ws://central-system:8887 28 | networks: 29 | - sim 30 | tty: true 31 | 32 | networks: 33 | sim: 34 | driver: bridge 35 | -------------------------------------------------------------------------------- /example/1.6/openssl-cp.conf: -------------------------------------------------------------------------------- 1 | [req] 2 | distinguished_name = req_dn 3 | req_extensions = req_ext 4 | prompt = no 5 | [req_dn] 6 | CN = charge-point 7 | [req_ext] 8 | basicConstraints = CA:FALSE 9 | subjectKeyIdentifier = hash 10 | keyUsage = digitalSignature, keyEncipherment 11 | extendedKeyUsage = clientAuth 12 | subjectAltName = @alt_names 13 | [alt_names] 14 | DNS.1 = charge-point -------------------------------------------------------------------------------- /example/1.6/openssl-cs.conf: -------------------------------------------------------------------------------- 1 | [req] 2 | distinguished_name = req_dn 3 | req_extensions = req_ext 4 | prompt = no 5 | [req_dn] 6 | CN = central-system 7 | [req_ext] 8 | basicConstraints = CA:FALSE 9 | subjectKeyIdentifier = hash 10 | keyUsage = digitalSignature, keyEncipherment, dataEncipherment 11 | extendedKeyUsage = serverAuth 12 | subjectAltName = @alt_names 13 | [alt_names] 14 | DNS.1 = central-system -------------------------------------------------------------------------------- /example/2.0.1/chargingstation/Dockerfile: -------------------------------------------------------------------------------- 1 | ############################ 2 | # STEP 1 build executable binary 3 | ############################ 4 | FROM golang:alpine AS builder 5 | 6 | ENV GO111MODULE on 7 | WORKDIR $GOPATH/src/github.com/lorenzodonini/ocpp-go 8 | COPY . . 9 | # Fetch dependencies. 10 | RUN go mod download 11 | # Build the binary. 12 | RUN go build -ldflags="-w -s" -o /go/bin/charging_station example/2.0.1/chargingstation/*.go 13 | 14 | ############################ 15 | # STEP 2 build a small image 16 | ############################ 17 | FROM alpine 18 | 19 | COPY --from=builder /go/bin/charging_station /bin/charging_station 20 | 21 | # Add CA certificates 22 | # It currently throws a warning on alpine: WARNING: ca-certificates.crt does not contain exactly one certificate or CRL: skipping. 23 | # Ignore the warning. 24 | RUN apk update && apk add ca-certificates && rm -rf /var/cache/apk/* && update-ca-certificates 25 | 26 | CMD [ "charging_station" ] 27 | -------------------------------------------------------------------------------- /example/2.0.1/chargingstation/authorization_handler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/authorization" 5 | ) 6 | 7 | func (handler *ChargingStationHandler) OnClearCache(request *authorization.ClearCacheRequest) (response *authorization.ClearCacheResponse, err error) { 8 | logDefault(request.GetFeatureName()).Infof("cleared mocked cache") 9 | return authorization.NewClearCacheResponse(authorization.ClearCacheStatusAccepted), nil 10 | } 11 | -------------------------------------------------------------------------------- /example/2.0.1/chargingstation/availability_handler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/availability" 5 | ) 6 | 7 | func (handler *ChargingStationHandler) OnChangeAvailability(request *availability.ChangeAvailabilityRequest) (response *availability.ChangeAvailabilityResponse, err error) { 8 | if request.Evse == nil { 9 | // Changing availability for the entire charging station 10 | handler.availability = request.OperationalStatus 11 | // TODO: recursively update the availability for all evse/connectors 12 | response = availability.NewChangeAvailabilityResponse(availability.ChangeAvailabilityStatusAccepted) 13 | return 14 | } 15 | reqEvse := request.Evse 16 | if e, ok := handler.evse[reqEvse.ID]; ok { 17 | // Changing availability for a specific EVSE 18 | if reqEvse.ConnectorID != nil { 19 | // Changing availability for a specific connector 20 | if !e.hasConnector(*reqEvse.ConnectorID) { 21 | response = availability.NewChangeAvailabilityResponse(availability.ChangeAvailabilityStatusRejected) 22 | } else { 23 | connector := e.connectors[*reqEvse.ConnectorID] 24 | connector.availability = request.OperationalStatus 25 | e.connectors[*reqEvse.ConnectorID] = connector 26 | response = availability.NewChangeAvailabilityResponse(availability.ChangeAvailabilityStatusAccepted) 27 | } 28 | return 29 | } 30 | e.availability = request.OperationalStatus 31 | response = availability.NewChangeAvailabilityResponse(availability.ChangeAvailabilityStatusAccepted) 32 | return 33 | } 34 | // No EVSE with such ID found 35 | response = availability.NewChangeAvailabilityResponse(availability.ChangeAvailabilityStatusRejected) 36 | return 37 | } 38 | -------------------------------------------------------------------------------- /example/2.0.1/chargingstation/config.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "crypto/rand" 5 | "fmt" 6 | ) 7 | 8 | // Generates a pseudo UUID. Not RFC 4122 compliant, but useful for this example. 9 | func pseudoUUID() (uuid string) { 10 | b := make([]byte, 16) 11 | _, err := rand.Read(b) 12 | if err != nil { 13 | fmt.Println("Error: ", err) 14 | return 15 | } 16 | uuid = fmt.Sprintf("%X-%X-%X-%X-%X", b[0:4], b[4:6], b[6:8], b[8:10], b[10:]) 17 | return 18 | } 19 | -------------------------------------------------------------------------------- /example/2.0.1/chargingstation/data_handler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/data" 6 | ) 7 | 8 | type DataSample struct { 9 | SampleString string `json:"sample_string"` 10 | SampleValue float64 `json:"sample_value"` 11 | } 12 | 13 | func (handler *ChargingStationHandler) OnDataTransfer(request *data.DataTransferRequest) (response *data.DataTransferResponse, err error) { 14 | var dataSample DataSample 15 | err = json.Unmarshal(request.Data.([]byte), &dataSample) 16 | if err != nil { 17 | logDefault(request.GetFeatureName()). 18 | Errorf("invalid data received: %v", request.Data) 19 | return nil, err 20 | } 21 | logDefault(request.GetFeatureName()). 22 | Infof("data received: %v, %v", dataSample.SampleString, dataSample.SampleValue) 23 | return data.NewDataTransferResponse(data.DataTransferStatusAccepted), nil 24 | } 25 | -------------------------------------------------------------------------------- /example/2.0.1/chargingstation/display_handler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/display" 4 | 5 | func (handler *ChargingStationHandler) OnClearDisplay(request *display.ClearDisplayRequest) (response *display.ClearDisplayResponse, err error) { 6 | logDefault(request.GetFeatureName()).Infof("cleared display message %v", request.ID) 7 | response = display.NewClearDisplayResponse(display.ClearMessageStatusAccepted) 8 | return 9 | } 10 | 11 | func (handler *ChargingStationHandler) OnGetDisplayMessages(request *display.GetDisplayMessagesRequest) (response *display.GetDisplayMessagesResponse, err error) { 12 | logDefault(request.GetFeatureName()).Infof("request %v to send display messages ignored", request.RequestID) 13 | response = display.NewGetDisplayMessagesResponse(display.MessageStatusUnknown) 14 | return 15 | } 16 | 17 | func (handler *ChargingStationHandler) OnSetDisplayMessage(request *display.SetDisplayMessageRequest) (response *display.SetDisplayMessageResponse, err error) { 18 | logDefault(request.GetFeatureName()).Infof("accepted request to display message %v: %v", request.Message.ID, request.Message.Message.Content) 19 | response = display.NewSetDisplayMessageResponse(display.DisplayMessageStatusAccepted) 20 | return 21 | } 22 | -------------------------------------------------------------------------------- /example/2.0.1/chargingstation/firmware_handler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/lorenzodonini/ocpp-go/ocpp" 5 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/firmware" 6 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/types" 7 | "github.com/lorenzodonini/ocpp-go/ocppj" 8 | "io" 9 | "net/http" 10 | "os" 11 | "time" 12 | ) 13 | 14 | func (handler *ChargingStationHandler) OnPublishFirmware(request *firmware.PublishFirmwareRequest) (response *firmware.PublishFirmwareResponse, err error) { 15 | logDefault(request.GetFeatureName()).Warnf("Unsupported feature") 16 | return nil, ocpp.NewHandlerError(ocppj.NotSupported, "Not supported") 17 | } 18 | 19 | func (handler *ChargingStationHandler) OnUnpublishFirmware(request *firmware.UnpublishFirmwareRequest) (response *firmware.UnpublishFirmwareResponse, err error) { 20 | logDefault(request.GetFeatureName()).Warnf("Unsupported feature") 21 | return nil, ocpp.NewHandlerError(ocppj.NotSupported, "Not supported") 22 | } 23 | 24 | func (handler *ChargingStationHandler) OnUpdateFirmware(request *firmware.UpdateFirmwareRequest) (response *firmware.UpdateFirmwareResponse, err error) { 25 | retries := 0 26 | retryInterval := 30 27 | if request.Retries != nil { 28 | retries = *request.Retries 29 | } 30 | if request.RetryInterval != nil { 31 | retryInterval = *request.RetryInterval 32 | } 33 | logDefault(request.GetFeatureName()).Infof("starting update firmware procedure") 34 | go updateFirmware(request.Firmware.Location, request.Firmware.RetrieveDateTime, request.Firmware.InstallDateTime, retries, retryInterval) 35 | return firmware.NewUpdateFirmwareResponse(firmware.UpdateFirmwareStatusAccepted), nil 36 | } 37 | 38 | func updateFirmwareStatus(status firmware.FirmwareStatus, props ...func(request *firmware.FirmwareStatusNotificationRequest)) { 39 | statusConfirmation, err := chargingStation.FirmwareStatusNotification(status, props...) 40 | checkError(err) 41 | logDefault(statusConfirmation.GetFeatureName()).Infof("firmware status updated to %v", status) 42 | } 43 | 44 | // Retrieve data and install date are ignored for this test function. 45 | func updateFirmware(location string, retrieveDate *types.DateTime, installDate *types.DateTime, retries int, retryInterval int) { 46 | updateFirmwareStatus(firmware.FirmwareStatusDownloading) 47 | err := downloadFile("/tmp/out.bin", location) 48 | if err != nil { 49 | logDefault(firmware.UpdateFirmwareFeatureName).Errorf("error while downloading file %v", err) 50 | updateFirmwareStatus(firmware.FirmwareStatusDownloadFailed) 51 | return 52 | } 53 | updateFirmwareStatus(firmware.FirmwareStatusDownloaded) 54 | // Simulate installation 55 | updateFirmwareStatus(firmware.FirmwareStatusInstalling) 56 | time.Sleep(time.Second * 5) 57 | // Notify completion 58 | updateFirmwareStatus(firmware.FirmwareStatusInstalled) 59 | } 60 | 61 | func downloadFile(filepath string, url string) error { 62 | resp, err := http.Get(url) 63 | if err != nil { 64 | return err 65 | } 66 | defer resp.Body.Close() 67 | 68 | out, err := os.Create(filepath) 69 | if err != nil { 70 | return err 71 | } 72 | defer out.Close() 73 | 74 | _, err = io.Copy(out, resp.Body) 75 | return err 76 | } 77 | -------------------------------------------------------------------------------- /example/2.0.1/chargingstation/iso15118_handler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/lorenzodonini/ocpp-go/ocpp" 5 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/iso15118" 6 | "github.com/lorenzodonini/ocpp-go/ocppj" 7 | ) 8 | 9 | func (handler *ChargingStationHandler) OnDeleteCertificate(request *iso15118.DeleteCertificateRequest) (response *iso15118.DeleteCertificateResponse, err error) { 10 | logDefault(request.GetFeatureName()).Warnf("Unsupported feature") 11 | return nil, ocpp.NewHandlerError(ocppj.NotSupported, "Not supported") 12 | } 13 | 14 | func (handler *ChargingStationHandler) OnGetInstalledCertificateIds(request *iso15118.GetInstalledCertificateIdsRequest) (response *iso15118.GetInstalledCertificateIdsResponse, err error) { 15 | logDefault(request.GetFeatureName()).Warnf("Unsupported feature") 16 | return nil, ocpp.NewHandlerError(ocppj.NotSupported, "Not supported") 17 | } 18 | 19 | func (handler *ChargingStationHandler) OnInstallCertificate(request *iso15118.InstallCertificateRequest) (response *iso15118.InstallCertificateResponse, err error) { 20 | logDefault(request.GetFeatureName()).Warnf("Unsupported feature") 21 | return nil, ocpp.NewHandlerError(ocppj.NotSupported, "Not supported") 22 | } 23 | -------------------------------------------------------------------------------- /example/2.0.1/chargingstation/localauth_handler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/localauth" 4 | 5 | func (handler *ChargingStationHandler) OnGetLocalListVersion(request *localauth.GetLocalListVersionRequest) (response *localauth.GetLocalListVersionResponse, err error) { 6 | logDefault(request.GetFeatureName()).Infof("returning current local list version: %v", handler.localAuthListVersion) 7 | return localauth.NewGetLocalListVersionResponse(handler.localAuthListVersion), nil 8 | } 9 | 10 | func (handler *ChargingStationHandler) OnSendLocalList(request *localauth.SendLocalListRequest) (response *localauth.SendLocalListResponse, err error) { 11 | if request.VersionNumber <= handler.localAuthListVersion { 12 | logDefault(request.GetFeatureName()). 13 | Errorf("requested listVersion %v is lower/equal than the current list version %v", request.VersionNumber, handler.localAuthListVersion) 14 | return localauth.NewSendLocalListResponse(localauth.SendLocalListStatusVersionMismatch), nil 15 | } 16 | if request.UpdateType == localauth.UpdateTypeFull { 17 | handler.localAuthList = request.LocalAuthorizationList 18 | handler.localAuthListVersion = request.VersionNumber 19 | } else if request.UpdateType == localauth.UpdateTypeDifferential { 20 | handler.localAuthList = append(handler.localAuthList, request.LocalAuthorizationList...) 21 | handler.localAuthListVersion = request.VersionNumber 22 | } 23 | logDefault(request.GetFeatureName()).Errorf("accepted new local authorization list %v, %v", 24 | request.VersionNumber, request.UpdateType) 25 | return localauth.NewSendLocalListResponse(localauth.SendLocalListStatusAccepted), nil 26 | } 27 | -------------------------------------------------------------------------------- /example/2.0.1/chargingstation/smartcharging_handler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/lorenzodonini/ocpp-go/ocpp" 5 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/smartcharging" 6 | "github.com/lorenzodonini/ocpp-go/ocppj" 7 | ) 8 | 9 | func (handler *ChargingStationHandler) OnClearChargingProfile(request *smartcharging.ClearChargingProfileRequest) (response *smartcharging.ClearChargingProfileResponse, err error) { 10 | logDefault(request.GetFeatureName()).Warnf("Unsupported feature") 11 | return nil, ocpp.NewHandlerError(ocppj.NotSupported, "Not supported") 12 | } 13 | 14 | func (handler *ChargingStationHandler) OnGetChargingProfiles(request *smartcharging.GetChargingProfilesRequest) (response *smartcharging.GetChargingProfilesResponse, err error) { 15 | logDefault(request.GetFeatureName()).Warnf("Unsupported feature") 16 | return nil, ocpp.NewHandlerError(ocppj.NotSupported, "Not supported") 17 | } 18 | 19 | func (handler *ChargingStationHandler) OnGetCompositeSchedule(request *smartcharging.GetCompositeScheduleRequest) (response *smartcharging.GetCompositeScheduleResponse, err error) { 20 | logDefault(request.GetFeatureName()).Warnf("Unsupported feature") 21 | return nil, ocpp.NewHandlerError(ocppj.NotSupported, "Not supported") 22 | } 23 | 24 | func (handler *ChargingStationHandler) OnSetChargingProfile(request *smartcharging.SetChargingProfileRequest) (response *smartcharging.SetChargingProfileResponse, err error) { 25 | logDefault(request.GetFeatureName()).Warnf("Unsupported feature") 26 | return nil, ocpp.NewHandlerError(ocppj.NotSupported, "Not supported") 27 | } 28 | -------------------------------------------------------------------------------- /example/2.0.1/chargingstation/tariffcost_handler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/tariffcost" 5 | ) 6 | 7 | func (handler *ChargingStationHandler) OnCostUpdated(request *tariffcost.CostUpdatedRequest) (response *tariffcost.CostUpdatedResponse, err error) { 8 | logDefault(request.GetFeatureName()).Infof("accepted request to display cost for transaction %v: %v", request.TransactionID, request.TotalCost) 9 | // TODO: update internal display to show updated cost for transaction 10 | return tariffcost.NewCostUpdatedResponse(), nil 11 | } 12 | -------------------------------------------------------------------------------- /example/2.0.1/chargingstation/transactions_handler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/lorenzodonini/ocpp-go/ocpp" 5 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/transactions" 6 | "github.com/lorenzodonini/ocpp-go/ocppj" 7 | ) 8 | 9 | func (handler *ChargingStationHandler) OnGetTransactionStatus(request *transactions.GetTransactionStatusRequest) (response *transactions.GetTransactionStatusResponse, err error) { 10 | logDefault(request.GetFeatureName()).Warnf("Unsupported feature") 11 | return nil, ocpp.NewHandlerError(ocppj.NotSupported, "Not supported") 12 | } 13 | -------------------------------------------------------------------------------- /example/2.0.1/create-test-certificates.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | mkdir -p certs/csms 4 | mkdir -p certs/chargingstation 5 | cd certs 6 | # Create CA 7 | openssl req -new -x509 -nodes -sha256 -days 120 -extensions v3_ca -keyout ca.key -out ca.crt -subj "/CN=ocpp-go-example" 8 | # Generate self-signed CSMS certificate 9 | openssl genrsa -out csms/csms.key 4096 10 | openssl req -new -out csms/csms.csr -key csms/csms.key -config ../openssl-csms.conf -sha256 11 | openssl x509 -req -in csms/csms.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out csms/csms.crt -days 120 -extensions req_ext -extfile ../openssl-csms.conf -sha256 12 | # Generate self-signed charging-station certificate 13 | openssl genrsa -out chargingstation/charging-station.key 4096 14 | openssl req -new -out chargingstation/charging-station.csr -key chargingstation/charging-station.key -config ../openssl-chargingstation.conf -sha256 15 | openssl x509 -req -in chargingstation/charging-station.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out chargingstation/charging-station.crt -days 120 -extensions req_ext -extfile ../openssl-chargingstation.conf -sha256 16 | -------------------------------------------------------------------------------- /example/2.0.1/csms/Dockerfile: -------------------------------------------------------------------------------- 1 | ############################ 2 | # STEP 1 build executable binary 3 | ############################ 4 | FROM golang:alpine AS builder 5 | 6 | ENV GO111MODULE on 7 | WORKDIR $GOPATH/src/github.com/lorenzodonini/ocpp-go 8 | COPY . . 9 | # Fetch dependencies. 10 | RUN go mod download 11 | # Build the binary. 12 | RUN go build -ldflags="-w -s" -o /go/bin/csms example/2.0.1/csms/*.go 13 | 14 | ############################ 15 | # STEP 2 build a small image 16 | ############################ 17 | FROM alpine 18 | 19 | COPY --from=builder /go/bin/csms /bin/csms 20 | 21 | # Ports on which the service may be exposed. 22 | EXPOSE 8887 23 | EXPOSE 443 24 | 25 | CMD [ "csms" ] 26 | -------------------------------------------------------------------------------- /example/2.0.1/csms/authorization_handler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/authorization" 5 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/types" 6 | ) 7 | 8 | func (c *CSMSHandler) OnAuthorize(chargingStationID string, request *authorization.AuthorizeRequest) (response *authorization.AuthorizeResponse, err error) { 9 | logDefault(chargingStationID, request.GetFeatureName()).Infof("client with token %v authorized", request.IdToken) 10 | response = authorization.NewAuthorizationResponse(*types.NewIdTokenInfo(types.AuthorizationStatusAccepted)) 11 | return 12 | } 13 | -------------------------------------------------------------------------------- /example/2.0.1/csms/availability_handler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/availability" 6 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/types" 7 | "time" 8 | ) 9 | 10 | func (c *CSMSHandler) OnHeartbeat(chargingStationID string, request *availability.HeartbeatRequest) (response *availability.HeartbeatResponse, err error) { 11 | logDefault(chargingStationID, request.GetFeatureName()).Infof("heartbeat handled") 12 | response = availability.NewHeartbeatResponse(types.DateTime{Time: time.Now()}) 13 | return 14 | } 15 | 16 | func (c *CSMSHandler) OnStatusNotification(chargingStationID string, request *availability.StatusNotificationRequest) (response *availability.StatusNotificationResponse, err error) { 17 | info, ok := c.chargingStations[chargingStationID] 18 | if !ok { 19 | return nil, fmt.Errorf("unknown charging station %v", chargingStationID) 20 | } 21 | if request.ConnectorID > 0 { 22 | connectorInfo := info.getConnector(request.ConnectorID) 23 | connectorInfo.status = request.ConnectorStatus 24 | logDefault(chargingStationID, request.GetFeatureName()).Infof("connector %v updated status to %v", request.ConnectorID, request.ConnectorStatus) 25 | } else { 26 | logDefault(chargingStationID, request.GetFeatureName()).Infof("couldn't update status for invalid connector %v", request.ConnectorID) 27 | } 28 | response = availability.NewStatusNotificationResponse() 29 | return 30 | } 31 | -------------------------------------------------------------------------------- /example/2.0.1/csms/data_handler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/data" 6 | ) 7 | 8 | type DataSample struct { 9 | SampleString string `json:"sample_string"` 10 | SampleValue float64 `json:"sample_value"` 11 | } 12 | 13 | func (c *CSMSHandler) OnDataTransfer(chargingStationID string, request *data.DataTransferRequest) (response *data.DataTransferResponse, err error) { 14 | var dataSample DataSample 15 | err = json.Unmarshal(request.Data.([]byte), &dataSample) 16 | if err != nil { 17 | logDefault(chargingStationID, request.GetFeatureName()). 18 | Errorf("invalid data received: %v", request.Data) 19 | return nil, err 20 | } 21 | logDefault(chargingStationID, request.GetFeatureName()). 22 | Infof("data received: %v, %v", dataSample.SampleString, dataSample.SampleValue) 23 | return data.NewDataTransferResponse(data.DataTransferStatusAccepted), nil 24 | } 25 | -------------------------------------------------------------------------------- /example/2.0.1/csms/diagnostics_handler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/diagnostics" 4 | 5 | func (c *CSMSHandler) OnLogStatusNotification(chargingStationID string, request *diagnostics.LogStatusNotificationRequest) (response *diagnostics.LogStatusNotificationResponse, err error) { 6 | logDefault(chargingStationID, request.GetFeatureName()).Infof("log upload status: %v", request.Status) 7 | response = diagnostics.NewLogStatusNotificationResponse() 8 | return 9 | } 10 | 11 | func (c *CSMSHandler) OnNotifyCustomerInformation(chargingStationID string, request *diagnostics.NotifyCustomerInformationRequest) (response *diagnostics.NotifyCustomerInformationResponse, err error) { 12 | logDefault(chargingStationID, request.GetFeatureName()).Infof("data report for request %v: %v", request.RequestID, request.Data) 13 | response = diagnostics.NewNotifyCustomerInformationResponse() 14 | return 15 | } 16 | 17 | func (c *CSMSHandler) OnNotifyEvent(chargingStationID string, request *diagnostics.NotifyEventRequest) (response *diagnostics.NotifyEventResponse, err error) { 18 | logDefault(chargingStationID, request.GetFeatureName()).Infof("report part %v for events:\n", request.SeqNo) 19 | for _, ed := range request.EventData { 20 | logDefault(chargingStationID, request.GetFeatureName()).Infof("%v", ed) 21 | } 22 | response = diagnostics.NewNotifyEventResponse() 23 | return 24 | } 25 | 26 | func (c *CSMSHandler) OnNotifyMonitoringReport(chargingStationID string, request *diagnostics.NotifyMonitoringReportRequest) (response *diagnostics.NotifyMonitoringReportResponse, err error) { 27 | logDefault(chargingStationID, request.GetFeatureName()).Infof("report part %v for monitored variables:\n", request.SeqNo) 28 | for _, md := range request.Monitor { 29 | logDefault(chargingStationID, request.GetFeatureName()).Infof("%v", md) 30 | } 31 | response = diagnostics.NewNotifyMonitoringReportResponse() 32 | return 33 | } 34 | -------------------------------------------------------------------------------- /example/2.0.1/csms/display_handler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/display" 5 | ) 6 | 7 | func (c *CSMSHandler) OnNotifyDisplayMessages(chargingStationID string, request *display.NotifyDisplayMessagesRequest) (response *display.NotifyDisplayMessagesResponse, err error) { 8 | logDefault(chargingStationID, request.GetFeatureName()).Infof("received display messages for request %v:\n", request.RequestID) 9 | for _, msg := range request.MessageInfo { 10 | logDefault(chargingStationID, request.GetFeatureName()).Printf("%v", msg) 11 | } 12 | response = display.NewNotifyDisplayMessagesResponse() 13 | return 14 | } 15 | -------------------------------------------------------------------------------- /example/2.0.1/csms/firmware_handler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/firmware" 6 | ) 7 | 8 | func (c *CSMSHandler) OnFirmwareStatusNotification(chargingStationID string, request *firmware.FirmwareStatusNotificationRequest) (response *firmware.FirmwareStatusNotificationResponse, err error) { 9 | info, ok := c.chargingStations[chargingStationID] 10 | if !ok { 11 | err = fmt.Errorf("unknown charging station %v", chargingStationID) 12 | return 13 | } 14 | info.firmwareStatus = request.Status 15 | logDefault(chargingStationID, request.GetFeatureName()).Infof("updated firmware status to %v", request.Status) 16 | response = firmware.NewFirmwareStatusNotificationResponse() 17 | return 18 | } 19 | 20 | func (c *CSMSHandler) OnPublishFirmwareStatusNotification(chargingStationID string, request *firmware.PublishFirmwareStatusNotificationRequest) (response *firmware.PublishFirmwareStatusNotificationResponse, err error) { 21 | if len(request.Location) > 0 { 22 | logDefault(chargingStationID, request.GetFeatureName()).Infof("firmware download status on local controller: %v, download locations: %v", request.Status, request.Location) 23 | } else { 24 | logDefault(chargingStationID, request.GetFeatureName()).Infof("firmware download status on local controller: %v", request.Status) 25 | } 26 | response = firmware.NewPublishFirmwareStatusNotificationResponse() 27 | return 28 | } 29 | -------------------------------------------------------------------------------- /example/2.0.1/csms/handler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/sirupsen/logrus" 5 | 6 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/availability" 7 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/firmware" 8 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/types" 9 | ) 10 | 11 | // TransactionInfo contains info about a transaction 12 | type TransactionInfo struct { 13 | id int 14 | startTime *types.DateTime 15 | endTime *types.DateTime 16 | startMeter int 17 | endMeter int 18 | connectorID int 19 | idTag string 20 | } 21 | 22 | func (ti *TransactionInfo) hasTransactionEnded() bool { 23 | return ti.endTime != nil && !ti.endTime.IsZero() 24 | } 25 | 26 | // ConnectorInfo contains status and ongoing transaction ID for a connector 27 | type ConnectorInfo struct { 28 | status availability.ConnectorStatus 29 | currentTransaction int 30 | } 31 | 32 | func (ci *ConnectorInfo) hasTransactionInProgress() bool { 33 | return ci.currentTransaction >= 0 34 | } 35 | 36 | // ChargingStationState contains some simple state for a connected charging station 37 | type ChargingStationState struct { 38 | status availability.ChangeAvailabilityStatus 39 | firmwareStatus firmware.FirmwareStatus 40 | connectors map[int]*ConnectorInfo 41 | transactions map[int]*TransactionInfo 42 | } 43 | 44 | func (s *ChargingStationState) getConnector(id int) *ConnectorInfo { 45 | ci, ok := s.connectors[id] 46 | if !ok { 47 | ci = &ConnectorInfo{currentTransaction: -1} 48 | s.connectors[id] = ci 49 | } 50 | return ci 51 | } 52 | 53 | // CSMSHandler contains some simple state that a CSMS may want to keep. 54 | // In production this will typically be replaced by database/API calls. 55 | type CSMSHandler struct { 56 | chargingStations map[string]*ChargingStationState 57 | } 58 | 59 | // Utility functions 60 | func logDefault(chargingStationID string, feature string) *logrus.Entry { 61 | return log.WithFields(logrus.Fields{"client": chargingStationID, "message": feature}) 62 | } 63 | -------------------------------------------------------------------------------- /example/2.0.1/csms/iso15118_handler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/lorenzodonini/ocpp-go/ocpp" 5 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/iso15118" 6 | "github.com/lorenzodonini/ocpp-go/ocppj" 7 | ) 8 | 9 | func (c *CSMSHandler) OnGet15118EVCertificate(chargingStationID string, request *iso15118.Get15118EVCertificateRequest) (response *iso15118.Get15118EVCertificateResponse, err error) { 10 | logDefault(chargingStationID, request.GetFeatureName()).Warnf("Unsupported feature") 11 | return nil, ocpp.NewHandlerError(ocppj.NotSupported, "Not supported") 12 | } 13 | 14 | func (c *CSMSHandler) OnGetCertificateStatus(chargingStationID string, request *iso15118.GetCertificateStatusRequest) (response *iso15118.GetCertificateStatusResponse, err error) { 15 | logDefault(chargingStationID, request.GetFeatureName()).Warnf("Unsupported feature") 16 | return nil, ocpp.NewHandlerError(ocppj.NotSupported, "Not supported") 17 | } 18 | -------------------------------------------------------------------------------- /example/2.0.1/csms/meter_handler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/meter" 4 | 5 | func (c *CSMSHandler) OnMeterValues(chargingStationID string, request *meter.MeterValuesRequest) (response *meter.MeterValuesResponse, err error) { 6 | logDefault(chargingStationID, request.GetFeatureName()).Infof("received meter values for EVSE %v. Meter values:\n", request.EvseID) 7 | for _, mv := range request.MeterValue { 8 | logDefault(chargingStationID, request.GetFeatureName()).Printf("%v", mv) 9 | } 10 | response = meter.NewMeterValuesResponse() 11 | return 12 | } 13 | -------------------------------------------------------------------------------- /example/2.0.1/csms/provisioning_handler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/provisioning" 5 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/types" 6 | "time" 7 | ) 8 | 9 | func (c *CSMSHandler) OnBootNotification(chargingStationID string, request *provisioning.BootNotificationRequest) (response *provisioning.BootNotificationResponse, err error) { 10 | logDefault(chargingStationID, request.GetFeatureName()).Infof("boot confirmed for %v %v, serial: %v, firmare version: %v, reason: %v", 11 | request.ChargingStation.VendorName, request.ChargingStation.Model, request.ChargingStation.SerialNumber, request.ChargingStation.FirmwareVersion, request.Reason) 12 | response = provisioning.NewBootNotificationResponse(types.NewDateTime(time.Now()), defaultHeartbeatInterval, provisioning.RegistrationStatusAccepted) 13 | return 14 | } 15 | 16 | func (c *CSMSHandler) OnNotifyReport(chargingStationID string, request *provisioning.NotifyReportRequest) (response *provisioning.NotifyReportResponse, err error) { 17 | logDefault(chargingStationID, request.GetFeatureName()).Infof("data report %v, seq. %v:\n", request.RequestID, request.SeqNo) 18 | for _, d := range request.ReportData { 19 | logDefault(chargingStationID, request.GetFeatureName()).Printf("%v", d) 20 | } 21 | response = provisioning.NewNotifyReportResponse() 22 | return 23 | } 24 | -------------------------------------------------------------------------------- /example/2.0.1/csms/reservation_handler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/reservation" 4 | 5 | func (c *CSMSHandler) OnReservationStatusUpdate(chargingStationID string, request *reservation.ReservationStatusUpdateRequest) (response *reservation.ReservationStatusUpdateResponse, err error) { 6 | logDefault(chargingStationID, request.GetFeatureName()).Infof("updated status of reservation %v to: %v", request.ReservationID, request.Status) 7 | response = reservation.NewReservationStatusUpdateResponse() 8 | return 9 | } 10 | -------------------------------------------------------------------------------- /example/2.0.1/csms/security_handler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/lorenzodonini/ocpp-go/ocpp" 5 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/security" 6 | "github.com/lorenzodonini/ocpp-go/ocppj" 7 | ) 8 | 9 | func (c *CSMSHandler) OnSecurityEventNotification(chargingStationID string, request *security.SecurityEventNotificationRequest) (response *security.SecurityEventNotificationResponse, err error) { 10 | logDefault(chargingStationID, request.GetFeatureName()).Infof("type: %s, info: %s", request.Type, request.TechInfo) 11 | response = security.NewSecurityEventNotificationResponse() 12 | return 13 | } 14 | 15 | func (c *CSMSHandler) OnSignCertificate(chargingStationID string, request *security.SignCertificateRequest) (response *security.SignCertificateResponse, err error) { 16 | logDefault(chargingStationID, request.GetFeatureName()).Warnf("Unsupported feature") 17 | return nil, ocpp.NewHandlerError(ocppj.NotSupported, "Not supported") 18 | } 19 | -------------------------------------------------------------------------------- /example/2.0.1/csms/smartcharging_handler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/lorenzodonini/ocpp-go/ocpp" 5 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/smartcharging" 6 | "github.com/lorenzodonini/ocpp-go/ocppj" 7 | ) 8 | 9 | func (c *CSMSHandler) OnClearedChargingLimit(chargingStationID string, request *smartcharging.ClearedChargingLimitRequest) (response *smartcharging.ClearedChargingLimitResponse, err error) { 10 | logDefault(chargingStationID, request.GetFeatureName()).Warnf("Unsupported feature") 11 | return nil, ocpp.NewHandlerError(ocppj.NotSupported, "Not supported") 12 | } 13 | 14 | func (c *CSMSHandler) OnNotifyChargingLimit(chargingStationID string, request *smartcharging.NotifyChargingLimitRequest) (response *smartcharging.NotifyChargingLimitResponse, err error) { 15 | logDefault(chargingStationID, request.GetFeatureName()).Warnf("Unsupported feature") 16 | return nil, ocpp.NewHandlerError(ocppj.NotSupported, "Not supported") 17 | } 18 | 19 | func (c *CSMSHandler) OnNotifyEVChargingNeeds(chargingStationID string, request *smartcharging.NotifyEVChargingNeedsRequest) (response *smartcharging.NotifyEVChargingNeedsResponse, err error) { 20 | logDefault(chargingStationID, request.GetFeatureName()).Warnf("Unsupported feature") 21 | return nil, ocpp.NewHandlerError(ocppj.NotSupported, "Not supported") 22 | } 23 | 24 | func (c *CSMSHandler) OnNotifyEVChargingSchedule(chargingStationID string, request *smartcharging.NotifyEVChargingScheduleRequest) (response *smartcharging.NotifyEVChargingScheduleResponse, err error) { 25 | logDefault(chargingStationID, request.GetFeatureName()).Warnf("Unsupported feature") 26 | return nil, ocpp.NewHandlerError(ocppj.NotSupported, "Not supported") 27 | } 28 | 29 | func (c *CSMSHandler) OnReportChargingProfiles(chargingStationID string, request *smartcharging.ReportChargingProfilesRequest) (response *smartcharging.ReportChargingProfilesResponse, err error) { 30 | logDefault(chargingStationID, request.GetFeatureName()).Warnf("Unsupported feature") 31 | return nil, ocpp.NewHandlerError(ocppj.NotSupported, "Not supported") 32 | } 33 | -------------------------------------------------------------------------------- /example/2.0.1/csms/transactions_handler.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/transactions" 4 | 5 | func (c *CSMSHandler) OnTransactionEvent(chargingStationID string, request *transactions.TransactionEventRequest) (response *transactions.TransactionEventResponse, err error) { 6 | switch request.EventType { 7 | case transactions.TransactionEventStarted: 8 | logDefault(chargingStationID, request.GetFeatureName()).Infof("transaction %v started, reason: %v, state: %v", request.TransactionInfo.TransactionID, request.TriggerReason, request.TransactionInfo.ChargingState) 9 | case transactions.TransactionEventUpdated: 10 | logDefault(chargingStationID, request.GetFeatureName()).Infof("transaction %v updated, reason: %v, state: %v\n", request.TransactionInfo.TransactionID, request.TriggerReason, request.TransactionInfo.ChargingState) 11 | for _, mv := range request.MeterValue { 12 | logDefault(chargingStationID, request.GetFeatureName()).Printf("%v", mv) 13 | } 14 | case transactions.TransactionEventEnded: 15 | logDefault(chargingStationID, request.GetFeatureName()).Infof("transaction %v stopped, reason: %v, state: %v\n", request.TransactionInfo.TransactionID, request.TriggerReason, request.TransactionInfo.ChargingState) 16 | } 17 | response = transactions.NewTransactionEventResponse() 18 | return 19 | } 20 | -------------------------------------------------------------------------------- /example/2.0.1/docker-compose.tls.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | csms: 4 | build: 5 | context: ../.. 6 | dockerfile: csms/Dockerfile 7 | image: ldonini/ocpp2.0.1-csms:latest 8 | container_name: csms 9 | volumes: 10 | - ./certs/csms:/usr/local/share/certs 11 | - ./certs/ca.crt:/usr/local/share/certs/ca.crt 12 | environment: 13 | - SERVER_LISTEN_PORT=443 14 | - TLS_ENABLED=true 15 | - CA_CERTIFICATE_PATH=/usr/local/share/certs/ca.crt 16 | - SERVER_CERTIFICATE_PATH=/usr/local/share/certs/csms.crt 17 | - SERVER_CERTIFICATE_KEY_PATH=/usr/local/share/certs/csms.key 18 | ports: 19 | - "443:443" 20 | networks: 21 | - sim 22 | tty: true 23 | charging-station: 24 | build: 25 | context: ../.. 26 | dockerfile: chargingstation/Dockerfile 27 | image: ldonini/ocpp2.0.1-chargingstation:latest 28 | container_name: charging-station 29 | volumes: 30 | - ./certs/chargingstation:/usr/local/share/certs 31 | - ./certs/ca.crt:/usr/local/share/certs/ca.crt 32 | environment: 33 | - CLIENT_ID=chargingStationSim 34 | - CSMS_URL=wss://csms:443 35 | - TLS_ENABLED=true 36 | - CA_CERTIFICATE_PATH=/usr/local/share/certs/ca.crt 37 | - CLIENT_CERTIFICATE_PATH=/usr/local/share/certs/charging-station.crt 38 | - CLIENT_CERTIFICATE_KEY_PATH=/usr/local/share/certs/charging-station.key 39 | networks: 40 | - sim 41 | tty: true 42 | 43 | networks: 44 | sim: 45 | driver: bridge 46 | -------------------------------------------------------------------------------- /example/2.0.1/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | services: 3 | csms: 4 | build: 5 | context: ../.. 6 | dockerfile: csms/Dockerfile 7 | image: ldonini/ocpp2.0.1-csms:latest 8 | container_name: csms 9 | environment: 10 | - SERVER_LISTEN_PORT=8887 11 | ports: 12 | - "8887:8887" 13 | networks: 14 | - sim 15 | tty: true 16 | charging-station: 17 | build: 18 | context: ../.. 19 | dockerfile: chargingstation/Dockerfile 20 | image: ldonini/ocpp2.0.1-chargingstation:latest 21 | container_name: charging-station 22 | environment: 23 | - CLIENT_ID=chargingStationSim 24 | - CSMS_URL=ws://csms:8887 25 | networks: 26 | - sim 27 | tty: true 28 | 29 | networks: 30 | sim: 31 | driver: bridge 32 | -------------------------------------------------------------------------------- /example/2.0.1/openssl-chargingstation.conf: -------------------------------------------------------------------------------- 1 | [req] 2 | distinguished_name = req_dn 3 | req_extensions = req_ext 4 | prompt = no 5 | [req_dn] 6 | CN = charging-station 7 | [req_ext] 8 | basicConstraints = CA:FALSE 9 | subjectKeyIdentifier = hash 10 | keyUsage = digitalSignature, keyEncipherment 11 | extendedKeyUsage = clientAuth 12 | subjectAltName = @alt_names 13 | [alt_names] 14 | DNS.1 = charging-station -------------------------------------------------------------------------------- /example/2.0.1/openssl-csms.conf: -------------------------------------------------------------------------------- 1 | [req] 2 | distinguished_name = req_dn 3 | req_extensions = req_ext 4 | prompt = no 5 | [req_dn] 6 | CN = csms 7 | [req_ext] 8 | basicConstraints = CA:FALSE 9 | subjectKeyIdentifier = hash 10 | keyUsage = digitalSignature, keyEncipherment, dataEncipherment 11 | extendedKeyUsage = serverAuth 12 | subjectAltName = @alt_names 13 | [alt_names] 14 | DNS.1 = csms -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/lorenzodonini/ocpp-go 2 | 3 | go 1.16 4 | 5 | require ( 6 | github.com/Shopify/toxiproxy v2.1.4+incompatible 7 | github.com/caarlos0/env/v11 v11.3.1 8 | github.com/go-playground/locales v0.12.1 // indirect 9 | github.com/go-playground/universal-translator v0.16.0 10 | github.com/gorilla/mux v1.8.1 11 | github.com/gorilla/websocket v1.5.3 12 | github.com/kr/pretty v0.1.0 // indirect 13 | github.com/leodido/go-urn v1.1.0 // indirect 14 | github.com/relvacode/iso8601 v1.6.0 15 | github.com/sirupsen/logrus v1.4.2 16 | github.com/stretchr/testify v1.8.0 17 | golang.org/x/sys v0.0.0-20220804214406-8e32c043e418 // indirect 18 | gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect 19 | gopkg.in/go-playground/assert.v1 v1.2.1 // indirect 20 | gopkg.in/go-playground/validator.v9 v9.30.0 21 | ) 22 | -------------------------------------------------------------------------------- /internal/callbackqueue/callbackqueue.go: -------------------------------------------------------------------------------- 1 | package callbackqueue 2 | 3 | import ( 4 | "sync" 5 | 6 | "github.com/lorenzodonini/ocpp-go/ocpp" 7 | ) 8 | 9 | type CallbackQueue struct { 10 | callbacksMutex sync.RWMutex 11 | callbacks map[string][]func(confirmation ocpp.Response, err error) 12 | } 13 | 14 | func New() CallbackQueue { 15 | return CallbackQueue{ 16 | callbacks: make(map[string][]func(confirmation ocpp.Response, err error)), 17 | } 18 | } 19 | 20 | func (cq *CallbackQueue) TryQueue(id string, try func() error, callback func(confirmation ocpp.Response, err error)) error { 21 | cq.callbacksMutex.Lock() 22 | defer cq.callbacksMutex.Unlock() 23 | 24 | cq.callbacks[id] = append(cq.callbacks[id], callback) 25 | 26 | if err := try(); err != nil { 27 | // pop off last element 28 | callbacks := cq.callbacks[id] 29 | cq.callbacks[id] = callbacks[:len(callbacks)-1] 30 | if len(cq.callbacks[id]) == 0 { 31 | delete(cq.callbacks, id) 32 | } 33 | 34 | return err 35 | } 36 | 37 | return nil 38 | } 39 | 40 | func (cq *CallbackQueue) Dequeue(id string) (func(confirmation ocpp.Response, err error), bool) { 41 | cq.callbacksMutex.Lock() 42 | defer cq.callbacksMutex.Unlock() 43 | 44 | callbacks, ok := cq.callbacks[id] 45 | if !ok { 46 | return nil, false 47 | } 48 | 49 | if len(callbacks) == 0 { 50 | panic("Internal CallbackQueue inconsistency") 51 | } 52 | 53 | callback := callbacks[0] 54 | 55 | if len(callbacks) == 1 { 56 | delete(cq.callbacks, id) 57 | } else { 58 | cq.callbacks[id] = callbacks[1:] 59 | } 60 | 61 | return callback, ok 62 | } 63 | -------------------------------------------------------------------------------- /logging/log.go: -------------------------------------------------------------------------------- 1 | package logging 2 | 3 | // Logger is the adapter interface that needs to be implemented, if the library should internally print logs. 4 | // 5 | // This allows to hook up your logger of choice. 6 | type Logger interface { 7 | Debug(args ...interface{}) 8 | Debugf(format string, args ...interface{}) 9 | Info(args ...interface{}) 10 | Infof(format string, args ...interface{}) 11 | Error(args ...interface{}) 12 | Errorf(format string, args ...interface{}) 13 | } 14 | 15 | // VoidLogger is an empty implementation of the Logger interface, which doesn't actually process any logs. 16 | // It may be used as a dummy implementation, if no logs should be visible. 17 | type VoidLogger struct{} 18 | 19 | func (l *VoidLogger) Debug(args ...interface{}) {} 20 | func (l *VoidLogger) Debugf(format string, args ...interface{}) {} 21 | func (l *VoidLogger) Info(args ...interface{}) {} 22 | func (l *VoidLogger) Infof(format string, args ...interface{}) {} 23 | func (l *VoidLogger) Error(args ...interface{}) {} 24 | func (l *VoidLogger) Errorf(format string, args ...interface{}) {} 25 | -------------------------------------------------------------------------------- /ocpp1.6/certificates/certificates.go: -------------------------------------------------------------------------------- 1 | // The diagnostics functional block contains OCPP 2.0 features than enable remote diagnostics of problems with a charging station. 2 | package certificates 3 | 4 | import "github.com/lorenzodonini/ocpp-go/ocpp" 5 | 6 | // Needs to be implemented by Charging stations for handling messages part of the OCPP 1.6j security extension. 7 | type ChargePointHandler interface { 8 | // OnDeleteCertificate is called on a charging station whenever a DeleteCertificateRequest is received from the CSMS. 9 | OnDeleteCertificate(request *DeleteCertificateRequest) (response *DeleteCertificateResponse, err error) 10 | // OnGetInstalledCertificateIds is called on a charging station whenever a GetInstalledCertificateIdsRequest is received from the CSMS. 11 | OnGetInstalledCertificateIds(request *GetInstalledCertificateIdsRequest) (response *GetInstalledCertificateIdsResponse, err error) 12 | // OnInstallCertificate is called on a charging station whenever an InstallCertificateRequest is received from the CSMS. 13 | OnInstallCertificate(request *InstallCertificateRequest) (response *InstallCertificateResponse, err error) 14 | } 15 | 16 | const ProfileName = "Certificates" 17 | 18 | var Profile = ocpp.NewProfile( 19 | ProfileName, 20 | InstallCertificateFeature{}, 21 | DeleteCertificateFeature{}, 22 | GetInstalledCertificateIdsFeature{}, 23 | ) 24 | -------------------------------------------------------------------------------- /ocpp1.6/core/authorize.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "github.com/lorenzodonini/ocpp-go/ocpp1.6/types" 5 | "reflect" 6 | ) 7 | 8 | // -------------------- Authorize (CP -> CS) -------------------- 9 | 10 | const AuthorizeFeatureName = "Authorize" 11 | 12 | // The field definition of the Authorize request payload sent by the Charge Point to the Central System. 13 | type AuthorizeRequest struct { 14 | IdTag string `json:"idTag" validate:"required,max=20"` 15 | } 16 | 17 | // This field definition of the Authorize confirmation payload, sent by the Charge Point to the Central System in response to an AuthorizeRequest. 18 | // In case the request was invalid, or couldn't be processed, an error will be sent instead. 19 | type AuthorizeConfirmation struct { 20 | IdTagInfo *types.IdTagInfo `json:"idTagInfo" validate:"required"` 21 | } 22 | 23 | // Before the owner of an electric vehicle can start or stop charging, the Charge Point has to authorize the operation. 24 | // Upon receipt of an AuthorizeRequest, the Central System SHALL respond with an AuthorizeConfirmation. 25 | // This response payload SHALL indicate whether or not the idTag is accepted by the Central System. 26 | // If the Central System accepts the idTag then the response payload MAY include a parentIdTag and MUST include an authorization status value indicating acceptance or a reason for rejection. 27 | // A Charge Point MAY authorize identifier locally without involving the Central System, as described in Local Authorization List. 28 | // The Charge Point SHALL only supply energy after authorization. 29 | type AuthorizeFeature struct{} 30 | 31 | func (f AuthorizeFeature) GetFeatureName() string { 32 | return AuthorizeFeatureName 33 | } 34 | 35 | func (f AuthorizeFeature) GetRequestType() reflect.Type { 36 | return reflect.TypeOf(AuthorizeRequest{}) 37 | } 38 | 39 | func (f AuthorizeFeature) GetResponseType() reflect.Type { 40 | return reflect.TypeOf(AuthorizeConfirmation{}) 41 | } 42 | 43 | func (r AuthorizeRequest) GetFeatureName() string { 44 | return AuthorizeFeatureName 45 | } 46 | 47 | func (c AuthorizeConfirmation) GetFeatureName() string { 48 | return AuthorizeFeatureName 49 | } 50 | 51 | // Creates a new AuthorizeRequest, containing all required fields. There are no optional fields for this message. 52 | func NewAuthorizationRequest(idTag string) *AuthorizeRequest { 53 | return &AuthorizeRequest{IdTag: idTag} 54 | } 55 | 56 | // Creates a new AuthorizeConfirmation. There are no optional fields for this message. 57 | func NewAuthorizationConfirmation(idTagInfo *types.IdTagInfo) *AuthorizeConfirmation { 58 | return &AuthorizeConfirmation{IdTagInfo: idTagInfo} 59 | } 60 | -------------------------------------------------------------------------------- /ocpp1.6/core/clear_cache.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "github.com/lorenzodonini/ocpp-go/ocpp1.6/types" 5 | "gopkg.in/go-playground/validator.v9" 6 | "reflect" 7 | ) 8 | 9 | // -------------------- Clear Cache (CS -> CP) -------------------- 10 | 11 | const ClearCacheFeatureName = "ClearCache" 12 | 13 | // Status returned in response to ClearCacheRequest. 14 | type ClearCacheStatus string 15 | 16 | const ( 17 | ClearCacheStatusAccepted ClearCacheStatus = "Accepted" 18 | ClearCacheStatusRejected ClearCacheStatus = "Rejected" 19 | ) 20 | 21 | func isValidClearCacheStatus(fl validator.FieldLevel) bool { 22 | status := ClearCacheStatus(fl.Field().String()) 23 | switch status { 24 | case ClearCacheStatusAccepted, ClearCacheStatusRejected: 25 | return true 26 | default: 27 | return false 28 | } 29 | } 30 | 31 | // The field definition of the ClearCache request payload sent by the Central System to the Charge Point. 32 | type ClearCacheRequest struct { 33 | } 34 | 35 | // This field definition of the ClearCache confirmation payload, sent by the Charge Point to the Central System in response to a ClearCacheRequest. 36 | // In case the request was invalid, or couldn't be processed, an error will be sent instead. 37 | type ClearCacheConfirmation struct { 38 | Status ClearCacheStatus `json:"status" validate:"required,cacheStatus16"` 39 | } 40 | 41 | // Central System can request a Charge Point to clear its Authorization Cache. 42 | // The Central System SHALL send a ClearCacheRequest PDU for clearing the Charge Point’s Authorization Cache. 43 | // Upon receipt of a ClearCacheRequest, the Charge Point SHALL respond with a ClearCacheConfirmation PDU. 44 | // The response PDU SHALL indicate whether the Charge Point was able to clear its Authorization Cache. 45 | type ClearCacheFeature struct{} 46 | 47 | func (f ClearCacheFeature) GetFeatureName() string { 48 | return ClearCacheFeatureName 49 | } 50 | 51 | func (f ClearCacheFeature) GetRequestType() reflect.Type { 52 | return reflect.TypeOf(ClearCacheRequest{}) 53 | } 54 | 55 | func (f ClearCacheFeature) GetResponseType() reflect.Type { 56 | return reflect.TypeOf(ClearCacheConfirmation{}) 57 | } 58 | 59 | func (r ClearCacheRequest) GetFeatureName() string { 60 | return ClearCacheFeatureName 61 | } 62 | 63 | func (c ClearCacheConfirmation) GetFeatureName() string { 64 | return ClearCacheFeatureName 65 | } 66 | 67 | // Creates a new ClearCacheRequest, which doesn't contain any required or optional fields. 68 | func NewClearCacheRequest() *ClearCacheRequest { 69 | return &ClearCacheRequest{} 70 | } 71 | 72 | // Creates a new ClearCacheConfirmation, containing all required fields. There are no optional fields for this message. 73 | func NewClearCacheConfirmation(status ClearCacheStatus) *ClearCacheConfirmation { 74 | return &ClearCacheConfirmation{Status: status} 75 | } 76 | 77 | func init() { 78 | _ = types.Validate.RegisterValidation("cacheStatus16", isValidClearCacheStatus) 79 | } 80 | -------------------------------------------------------------------------------- /ocpp1.6/core/core.go: -------------------------------------------------------------------------------- 1 | // Contains the Basic Charge Point functionality comparable with OCPP 1.5. 2 | package core 3 | 4 | import ( 5 | "github.com/lorenzodonini/ocpp-go/ocpp" 6 | ) 7 | 8 | // Needs to be implemented by Central systems for handling messages part of the OCPP 1.6 Core profile. 9 | type CentralSystemHandler interface { 10 | OnAuthorize(chargePointId string, request *AuthorizeRequest) (confirmation *AuthorizeConfirmation, err error) 11 | OnBootNotification(chargePointId string, request *BootNotificationRequest) (confirmation *BootNotificationConfirmation, err error) 12 | OnDataTransfer(chargePointId string, request *DataTransferRequest) (confirmation *DataTransferConfirmation, err error) 13 | OnHeartbeat(chargePointId string, request *HeartbeatRequest) (confirmation *HeartbeatConfirmation, err error) 14 | OnMeterValues(chargePointId string, request *MeterValuesRequest) (confirmation *MeterValuesConfirmation, err error) 15 | OnStatusNotification(chargePointId string, request *StatusNotificationRequest) (confirmation *StatusNotificationConfirmation, err error) 16 | OnStartTransaction(chargePointId string, request *StartTransactionRequest) (confirmation *StartTransactionConfirmation, err error) 17 | OnStopTransaction(chargePointId string, request *StopTransactionRequest) (confirmation *StopTransactionConfirmation, err error) 18 | } 19 | 20 | // Needs to be implemented by Charge points for handling messages part of the OCPP 1.6 Core profile. 21 | type ChargePointHandler interface { 22 | OnChangeAvailability(request *ChangeAvailabilityRequest) (confirmation *ChangeAvailabilityConfirmation, err error) 23 | OnChangeConfiguration(request *ChangeConfigurationRequest) (confirmation *ChangeConfigurationConfirmation, err error) 24 | OnClearCache(request *ClearCacheRequest) (confirmation *ClearCacheConfirmation, err error) 25 | OnDataTransfer(request *DataTransferRequest) (confirmation *DataTransferConfirmation, err error) 26 | OnGetConfiguration(request *GetConfigurationRequest) (confirmation *GetConfigurationConfirmation, err error) 27 | OnRemoteStartTransaction(request *RemoteStartTransactionRequest) (confirmation *RemoteStartTransactionConfirmation, err error) 28 | OnRemoteStopTransaction(request *RemoteStopTransactionRequest) (confirmation *RemoteStopTransactionConfirmation, err error) 29 | OnReset(request *ResetRequest) (confirmation *ResetConfirmation, err error) 30 | OnUnlockConnector(request *UnlockConnectorRequest) (confirmation *UnlockConnectorConfirmation, err error) 31 | } 32 | 33 | // THe profile name 34 | var ProfileName = "Core" 35 | 36 | // Provides support for Basic Charge Point functionality comparable with OCPP 1.5. 37 | var Profile = ocpp.NewProfile( 38 | ProfileName, 39 | BootNotificationFeature{}, 40 | AuthorizeFeature{}, 41 | ChangeAvailabilityFeature{}, 42 | ChangeConfigurationFeature{}, 43 | ClearCacheFeature{}, 44 | DataTransferFeature{}, 45 | GetConfigurationFeature{}, 46 | HeartbeatFeature{}, 47 | MeterValuesFeature{}, 48 | RemoteStartTransactionFeature{}, 49 | RemoteStopTransactionFeature{}, 50 | StartTransactionFeature{}, 51 | StopTransactionFeature{}, 52 | StatusNotificationFeature{}, 53 | ResetFeature{}, 54 | UnlockConnectorFeature{}) 55 | -------------------------------------------------------------------------------- /ocpp1.6/core/remote_stop_transaction.go: -------------------------------------------------------------------------------- 1 | package core 2 | 3 | import ( 4 | "reflect" 5 | 6 | "github.com/lorenzodonini/ocpp-go/ocpp1.6/types" 7 | ) 8 | 9 | // -------------------- Remote Stop Transaction (CS -> CP) -------------------- 10 | 11 | const RemoteStopTransactionFeatureName = "RemoteStopTransaction" 12 | 13 | // The field definition of the RemoteStopTransaction request payload sent by the Central System to the Charge Point. 14 | type RemoteStopTransactionRequest struct { 15 | TransactionId int `json:"transactionId"` 16 | } 17 | 18 | // This field definition of the RemoteStopTransaction confirmation payload, sent by the Charge Point to the Central System in response to a RemoteStopTransactionRequest. 19 | // In case the request was invalid, or couldn't be processed, an error will be sent instead. 20 | type RemoteStopTransactionConfirmation struct { 21 | Status types.RemoteStartStopStatus `json:"status" validate:"required,remoteStartStopStatus16"` 22 | } 23 | 24 | // Central System can request a Charge Point to stop a transaction by sending a RemoteStopTransactionRequest to Charge Point with the identifier of the transaction. 25 | // Charge Point SHALL reply with RemoteStopTransactionConfirmation and a status indicating whether it has accepted the request and a transaction with the given transactionId is ongoing and will be stopped. 26 | // This remote request to stop a transaction is equal to a local action to stop a transaction. 27 | // Therefore, the transaction SHALL be stopped, The Charge Point SHALL send a StopTransactionRequest and, if applicable, unlock the connector. 28 | // The following two main use cases are the reason for Remote Stop Transaction: 29 | // • Enable a CPO operator to help an EV driver that has problems stopping a transaction. 30 | // • Enable mobile apps to control charging transactions via the Central System. 31 | type RemoteStopTransactionFeature struct{} 32 | 33 | func (f RemoteStopTransactionFeature) GetFeatureName() string { 34 | return RemoteStopTransactionFeatureName 35 | } 36 | 37 | func (f RemoteStopTransactionFeature) GetRequestType() reflect.Type { 38 | return reflect.TypeOf(RemoteStopTransactionRequest{}) 39 | } 40 | 41 | func (f RemoteStopTransactionFeature) GetResponseType() reflect.Type { 42 | return reflect.TypeOf(RemoteStopTransactionConfirmation{}) 43 | } 44 | 45 | func (r RemoteStopTransactionRequest) GetFeatureName() string { 46 | return RemoteStopTransactionFeatureName 47 | } 48 | 49 | func (c RemoteStopTransactionConfirmation) GetFeatureName() string { 50 | return RemoteStopTransactionFeatureName 51 | } 52 | 53 | // Creates a new RemoteStopTransactionRequest, containing all required fields. There are no optional fields for this message. 54 | func NewRemoteStopTransactionRequest(transactionId int) *RemoteStopTransactionRequest { 55 | return &RemoteStopTransactionRequest{TransactionId: transactionId} 56 | } 57 | 58 | // Creates a new RemoteStopTransactionConfirmation, containing all required fields. There are no optional fields for this message. 59 | func NewRemoteStopTransactionConfirmation(status types.RemoteStartStopStatus) *RemoteStopTransactionConfirmation { 60 | return &RemoteStopTransactionConfirmation{Status: status} 61 | } 62 | -------------------------------------------------------------------------------- /ocpp1.6/extendedtriggermessage/trigger_message.go: -------------------------------------------------------------------------------- 1 | // The diagnostics functional block contains OCPP 2.0 features than enable remote diagnostics of problems with a charging station. 2 | package extendedtriggermessage 3 | 4 | import "github.com/lorenzodonini/ocpp-go/ocpp" 5 | 6 | // Needs to be implemented by Charging stations for handling messages part of the OCPP 1.6j security extension. 7 | type ChargePointHandler interface { 8 | // OnExtendedTriggerMessage is called on a charging station whenever a ExtendedTriggerMessageRequest is received from the CSMS. 9 | OnExtendedTriggerMessage(request *ExtendedTriggerMessageRequest) (response *ExtendedTriggerMessageResponse, err error) 10 | } 11 | 12 | const ProfileName = "ExtendedTriggerMessage" 13 | 14 | var Profile = ocpp.NewProfile( 15 | ProfileName, 16 | ExtendedTriggerMessageFeature{}, 17 | ) 18 | -------------------------------------------------------------------------------- /ocpp1.6/firmware/firmware.go: -------------------------------------------------------------------------------- 1 | // Contains support for firmware update management and diagnostic log file download. 2 | package firmware 3 | 4 | import ( 5 | "github.com/lorenzodonini/ocpp-go/ocpp" 6 | ) 7 | 8 | // Needs to be implemented by Central systems for handling messages part of the OCPP 1.6 FirmwareManagement profile. 9 | type CentralSystemHandler interface { 10 | OnDiagnosticsStatusNotification(chargePointId string, request *DiagnosticsStatusNotificationRequest) (confirmation *DiagnosticsStatusNotificationConfirmation, err error) 11 | OnFirmwareStatusNotification(chargePointId string, request *FirmwareStatusNotificationRequest) (confirmation *FirmwareStatusNotificationConfirmation, err error) 12 | } 13 | 14 | // Needs to be implemented by Charge points for handling messages part of the OCPP 1.6 FirmwareManagement profile. 15 | type ChargePointHandler interface { 16 | OnGetDiagnostics(request *GetDiagnosticsRequest) (confirmation *GetDiagnosticsConfirmation, err error) 17 | OnUpdateFirmware(request *UpdateFirmwareRequest) (confirmation *UpdateFirmwareConfirmation, err error) 18 | } 19 | 20 | // The profile name 21 | const ProfileName = "FirmwareManagement" 22 | 23 | // Provides support for firmware update management and diagnostic log file download. 24 | var Profile = ocpp.NewProfile( 25 | ProfileName, 26 | GetDiagnosticsFeature{}, 27 | DiagnosticsStatusNotificationFeature{}, 28 | FirmwareStatusNotificationFeature{}, 29 | UpdateFirmwareFeature{}) 30 | -------------------------------------------------------------------------------- /ocpp1.6/localauth/get_local_list_version.go: -------------------------------------------------------------------------------- 1 | package localauth 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | // -------------------- Get Local List Version (CS -> CP) -------------------- 8 | 9 | const GetLocalListVersionFeatureName = "GetLocalListVersion" 10 | 11 | // The field definition of the GetLocalListVersion request payload sent by the Central System to the Charge Point. 12 | type GetLocalListVersionRequest struct { 13 | } 14 | 15 | // This field definition of the GetLocalListVersion confirmation payload, sent by the Charge Point to the Central System in response to a GetLocalListVersionRequest. 16 | // In case the request was invalid, or couldn't be processed, an error will be sent instead. 17 | type GetLocalListVersionConfirmation struct { 18 | ListVersion int `json:"listVersion" validate:"gte=-1"` 19 | } 20 | 21 | // Central System can request a Charge Point for the version number of the Local Authorization List. 22 | // The Central System SHALL send a GetLocalListVersionRequest to request this value. 23 | // Upon receipt of a GetLocalListVersionRequest, the Charge Point SHALL respond with a GetLocalListVersionConfirmation. 24 | // The response payload SHALL contain the version number of its Local Authorization List. 25 | // A version number of 0 (zero) SHALL be used to indicate that the local authorization list is empty, and a version number of -1 SHALL be used to indicate that the Charge Point does not support Local Authorization Lists. 26 | type GetLocalListVersionFeature struct{} 27 | 28 | func (f GetLocalListVersionFeature) GetFeatureName() string { 29 | return GetLocalListVersionFeatureName 30 | } 31 | 32 | func (f GetLocalListVersionFeature) GetRequestType() reflect.Type { 33 | return reflect.TypeOf(GetLocalListVersionRequest{}) 34 | } 35 | 36 | func (f GetLocalListVersionFeature) GetResponseType() reflect.Type { 37 | return reflect.TypeOf(GetLocalListVersionConfirmation{}) 38 | } 39 | 40 | func (r GetLocalListVersionRequest) GetFeatureName() string { 41 | return GetLocalListVersionFeatureName 42 | } 43 | 44 | func (c GetLocalListVersionConfirmation) GetFeatureName() string { 45 | return GetLocalListVersionFeatureName 46 | } 47 | 48 | // Creates a new GetLocalListVersionRequest, which doesn't contain any required or optional fields. 49 | func NewGetLocalListVersionRequest() *GetLocalListVersionRequest { 50 | return &GetLocalListVersionRequest{} 51 | } 52 | 53 | // Creates a new GetLocalListVersionConfirmation, containing all required fields. There are no optional fields for this message. 54 | func NewGetLocalListVersionConfirmation(version int) *GetLocalListVersionConfirmation { 55 | return &GetLocalListVersionConfirmation{ListVersion: version} 56 | } 57 | -------------------------------------------------------------------------------- /ocpp1.6/localauth/local_auth_list.go: -------------------------------------------------------------------------------- 1 | // Contains features to manage the local authorization list in Charge Points. 2 | package localauth 3 | 4 | import "github.com/lorenzodonini/ocpp-go/ocpp" 5 | 6 | // Needs to be implemented by Central systems for handling messages part of the OCPP 1.6 LocalAuthList profile. 7 | type CentralSystemHandler interface { 8 | } 9 | 10 | // Needs to be implemented by Charge points for handling messages part of the OCPP 1.6 LocalAuthList profile. 11 | type ChargePointHandler interface { 12 | OnGetLocalListVersion(request *GetLocalListVersionRequest) (confirmation *GetLocalListVersionConfirmation, err error) 13 | OnSendLocalList(request *SendLocalListRequest) (confirmation *SendLocalListConfirmation, err error) 14 | } 15 | 16 | // The profile name 17 | const ProfileName = "LocalAuthListManagement" 18 | 19 | // Provides support for managing the local authorization list in Charge Points. 20 | var Profile = ocpp.NewProfile( 21 | ProfileName, 22 | GetLocalListVersionFeature{}, 23 | SendLocalListFeature{}) 24 | -------------------------------------------------------------------------------- /ocpp1.6/logging/log.go: -------------------------------------------------------------------------------- 1 | // The diagnostics functional block contains OCPP 2.0 features than enable remote diagnostics of problems with a charging station. 2 | package logging 3 | 4 | import "github.com/lorenzodonini/ocpp-go/ocpp" 5 | 6 | // Needs to be implemented by a CSMS for handling messages part of the OCPP 1.6j security extension. 7 | type CentralSystemHandler interface { 8 | // OnLogStatusNotification is called on the CSMS whenever a LogStatusNotificationRequest is received from a Charging Station. 9 | OnLogStatusNotification(chargingStationID string, request *LogStatusNotificationRequest) (response *LogStatusNotificationResponse, err error) 10 | } 11 | 12 | // Needs to be implemented by Charging stations for handling messages part of the OCPP 1.6j security extension. 13 | type ChargePointHandler interface { 14 | // OnGetLog is called on a charging station whenever a GetLogRequest is received from the CSMS. 15 | OnGetLog(request *GetLogRequest) (response *GetLogResponse, err error) 16 | } 17 | 18 | const ProfileName = "Log" 19 | 20 | var Profile = ocpp.NewProfile( 21 | ProfileName, 22 | GetLogFeature{}, 23 | LogStatusNotificationFeature{}, 24 | ) 25 | -------------------------------------------------------------------------------- /ocpp1.6/remotetrigger/remote_trigger.go: -------------------------------------------------------------------------------- 1 | // Contains support for remote triggering of Charge Point initiated messages. 2 | package remotetrigger 3 | 4 | import "github.com/lorenzodonini/ocpp-go/ocpp" 5 | 6 | // Needs to be implemented by Central systems for handling messages part of the OCPP 1.6 RemoteTrigger profile. 7 | type CentralSystemHandler interface { 8 | } 9 | 10 | // Needs to be implemented by Charge points for handling messages part of the OCPP 1.6 RemoteTrigger profile. 11 | type ChargePointHandler interface { 12 | OnTriggerMessage(request *TriggerMessageRequest) (confirmation *TriggerMessageConfirmation, err error) 13 | } 14 | 15 | // The profile name 16 | const ProfileName = "RemoteTrigger" 17 | 18 | // Provides support for remote triggering of Charge Point initiated messages. 19 | var Profile = ocpp.NewProfile( 20 | ProfileName, 21 | TriggerMessageFeature{}) 22 | -------------------------------------------------------------------------------- /ocpp1.6/reservation/reservation.go: -------------------------------------------------------------------------------- 1 | // Contains support for reservation of a Charge Point. 2 | package reservation 3 | 4 | import "github.com/lorenzodonini/ocpp-go/ocpp" 5 | 6 | // Needs to be implemented by Central systems for handling messages part of the OCPP 1.6 Reservation profile. 7 | type CentralSystemHandler interface { 8 | } 9 | 10 | // Needs to be implemented by Charge points for handling messages part of the OCPP 1.6 Reservation profile. 11 | type ChargePointHandler interface { 12 | OnReserveNow(request *ReserveNowRequest) (confirmation *ReserveNowConfirmation, err error) 13 | OnCancelReservation(request *CancelReservationRequest) (confirmation *CancelReservationConfirmation, err error) 14 | } 15 | 16 | // The profile name 17 | const ProfileName = "Reservation" 18 | 19 | // Provides support for for reservation of a Charge Point. 20 | var Profile = ocpp.NewProfile( 21 | ProfileName, 22 | ReserveNowFeature{}, 23 | CancelReservationFeature{}) 24 | -------------------------------------------------------------------------------- /ocpp1.6/securefirmware/secure_firmware.go: -------------------------------------------------------------------------------- 1 | // The diagnostics functional block contains OCPP 1.6J extension features than enable remote firmware updates on charging stations. 2 | package securefirmware 3 | 4 | import "github.com/lorenzodonini/ocpp-go/ocpp" 5 | 6 | type CentralSystemHandler interface { 7 | OnSignedFirmwareStatusNotification(chargingStationID string, request *SignedFirmwareStatusNotificationRequest) (response *SignedFirmwareStatusNotificationResponse, err error) 8 | } 9 | 10 | // Needs to be implemented by Charging stations for handling messages part of the OCPP 1.6j security extension. 11 | type ChargePointHandler interface { 12 | OnSignedUpdateFirmware(request *SignedUpdateFirmwareRequest) (response *SignedUpdateFirmwareResponse, err error) 13 | } 14 | 15 | const ProfileName = "SecureFirmwareUpdate" 16 | 17 | var Profile = ocpp.NewProfile( 18 | ProfileName, 19 | SignedFirmwareStatusNotificationFeature{}, 20 | SignedUpdateFirmwareFeature{}, 21 | ) 22 | -------------------------------------------------------------------------------- /ocpp1.6/security/security.go: -------------------------------------------------------------------------------- 1 | // The security functional block contains OCPP 2.0 features aimed at providing E2E security between a CSMS and a Charging station. 2 | package security 3 | 4 | import "github.com/lorenzodonini/ocpp-go/ocpp" 5 | 6 | // Needs to be implemented by a CSMS for handling messages part of the OCPP 2.0 Security profile. 7 | type CentralSystemHandler interface { 8 | // OnSecurityEventNotification is called on the CSMS whenever a SecurityEventNotificationRequest is received from a charging station. 9 | OnSecurityEventNotification(chargingStationID string, request *SecurityEventNotificationRequest) (response *SecurityEventNotificationResponse, err error) 10 | // OnSignCertificate is called on the CSMS whenever a SignCertificateRequest is received from a charging station. 11 | OnSignCertificate(chargingStationID string, request *SignCertificateRequest) (response *SignCertificateResponse, err error) 12 | } 13 | 14 | // Needs to be implemented by Charging stations for handling messages part of the OCPP 2.0 Security profile. 15 | type ChargePointHandler interface { 16 | // OnCertificateSigned is called on a charging station whenever a CertificateSignedRequest is received from the CSMS. 17 | OnCertificateSigned(request *CertificateSignedRequest) (response *CertificateSignedResponse, err error) 18 | } 19 | 20 | const ProfileName = "Security" 21 | 22 | var Profile = ocpp.NewProfile( 23 | ProfileName, 24 | CertificateSignedFeature{}, 25 | SecurityEventNotificationFeature{}, 26 | SignCertificateFeature{}, 27 | ) 28 | -------------------------------------------------------------------------------- /ocpp1.6/security/security_event_notification.go: -------------------------------------------------------------------------------- 1 | package security 2 | 3 | import ( 4 | "reflect" 5 | 6 | "github.com/lorenzodonini/ocpp-go/ocpp1.6/types" 7 | ) 8 | 9 | // -------------------- Security Event Notification Status (CS -> CSMS) -------------------- 10 | 11 | const SecurityEventNotificationFeatureName = "SecurityEventNotification" 12 | 13 | // The field definition of the SecurityEventNotification request payload sent by the Charging Station to the CSMS. 14 | type SecurityEventNotificationRequest struct { 15 | Type string `json:"type" validate:"required,max=50"` // Type of the security event. This value should be taken from the Security events list. 16 | Timestamp *types.DateTime `json:"timestamp" validate:"required"` // Date and time at which the event occurred. 17 | TechInfo string `json:"techInfo,omitempty" validate:"omitempty,max=255"` // Additional information about the occurred security event. 18 | } 19 | 20 | // This field definition of the SecurityEventNotification response payload, sent by the CSMS to the Charging Station in response to a SecurityEventNotificationRequest. 21 | // In case the request was invalid, or couldn't be processed, an error will be sent instead. 22 | type SecurityEventNotificationResponse struct { 23 | } 24 | 25 | // In case of critical security events, a Charging Station may immediately inform the CSMS of such events, 26 | // via a SecurityEventNotificationRequest. 27 | // The CSMS responds with a SecurityEventNotificationResponse to the Charging Station. 28 | type SecurityEventNotificationFeature struct{} 29 | 30 | func (f SecurityEventNotificationFeature) GetFeatureName() string { 31 | return SecurityEventNotificationFeatureName 32 | } 33 | 34 | func (f SecurityEventNotificationFeature) GetRequestType() reflect.Type { 35 | return reflect.TypeOf(SecurityEventNotificationRequest{}) 36 | } 37 | 38 | func (f SecurityEventNotificationFeature) GetResponseType() reflect.Type { 39 | return reflect.TypeOf(SecurityEventNotificationResponse{}) 40 | } 41 | 42 | func (r SecurityEventNotificationRequest) GetFeatureName() string { 43 | return SecurityEventNotificationFeatureName 44 | } 45 | 46 | func (c SecurityEventNotificationResponse) GetFeatureName() string { 47 | return SecurityEventNotificationFeatureName 48 | } 49 | 50 | // Creates a new SecurityEventNotificationRequest, containing all required fields. Optional fields may be set afterwards. 51 | func NewSecurityEventNotificationRequest(typ string, timestamp *types.DateTime) *SecurityEventNotificationRequest { 52 | return &SecurityEventNotificationRequest{Type: typ, Timestamp: timestamp} 53 | } 54 | 55 | // Creates a new SecurityEventNotificationResponse, which doesn't contain any required or optional fields. 56 | func NewSecurityEventNotificationResponse() *SecurityEventNotificationResponse { 57 | return &SecurityEventNotificationResponse{} 58 | } 59 | -------------------------------------------------------------------------------- /ocpp1.6/security/sign_certificate.go: -------------------------------------------------------------------------------- 1 | package security 2 | 3 | import ( 4 | "reflect" 5 | 6 | "github.com/lorenzodonini/ocpp-go/ocpp1.6/types" 7 | ) 8 | 9 | // -------------------- Sign Certificate (CS -> CSMS) -------------------- 10 | 11 | const SignCertificateFeatureName = "SignCertificate" 12 | 13 | // The field definition of the SignCertificate request payload sent by the Charging Station to the CSMS. 14 | type SignCertificateRequest struct { 15 | CSR string `json:"csr" validate:"required,max=5500"` // The Charging Station SHALL send the public key in form of a Certificate Signing Request (CSR) as described in RFC 2986 and then PEM encoded. 16 | CertificateType types.CertificateSigningUse `json:"certificateType,omitempty" validate:"omitempty,certificateSigningUse16"` // Indicates the type of certificate that is to be signed. 17 | } 18 | 19 | // This field definition of the SignCertificate response payload, sent by the CSMS to the Charging Station in response to a SignCertificateRequest. 20 | // In case the request was invalid, or couldn't be processed, an error will be sent instead. 21 | type SignCertificateResponse struct { 22 | Status types.GenericStatus `json:"status" validate:"required,genericStatus16"` // Specifies whether the CSMS can process the request. 23 | } 24 | 25 | // If a Charging Station detected, that its certificate is due to expire, it will generate a new public/private key pair, 26 | // then send a SignCertificateRequest to the CSMS containing a valid Certificate Signing Request. 27 | // 28 | // The CSMS responds with a SignCertificateResponse and will then forward the CSR to a CA server. 29 | // Once the CA has issues a valid certificate, the CSMS will send a CertificateSignedRequest to the 30 | // charging station (asynchronously). 31 | type SignCertificateFeature struct{} 32 | 33 | func (f SignCertificateFeature) GetFeatureName() string { 34 | return SignCertificateFeatureName 35 | } 36 | 37 | func (f SignCertificateFeature) GetRequestType() reflect.Type { 38 | return reflect.TypeOf(SignCertificateRequest{}) 39 | } 40 | 41 | func (f SignCertificateFeature) GetResponseType() reflect.Type { 42 | return reflect.TypeOf(SignCertificateResponse{}) 43 | } 44 | 45 | func (r SignCertificateRequest) GetFeatureName() string { 46 | return SignCertificateFeatureName 47 | } 48 | 49 | func (c SignCertificateResponse) GetFeatureName() string { 50 | return SignCertificateFeatureName 51 | } 52 | 53 | // Creates a new SignCertificateRequest, containing all required fields. Optional fields may be set afterwards. 54 | func NewSignCertificateRequest(csr string) *SignCertificateRequest { 55 | return &SignCertificateRequest{CSR: csr} 56 | } 57 | 58 | // Creates a new SignCertificateResponse, containing all required fields. Optional fields may be set afterwards. 59 | func NewSignCertificateResponse(status types.GenericStatus) *SignCertificateResponse { 60 | return &SignCertificateResponse{Status: status} 61 | } 62 | -------------------------------------------------------------------------------- /ocpp1.6/smartcharging/smart_charging.go: -------------------------------------------------------------------------------- 1 | // Contains support for basic Smart Charging, for instance using control pilot. 2 | package smartcharging 3 | 4 | import "github.com/lorenzodonini/ocpp-go/ocpp" 5 | 6 | // Needs to be implemented by Central systems for handling messages part of the OCPP 1.6 SmartCharging profile. 7 | type CentralSystemHandler interface { 8 | } 9 | 10 | // Needs to be implemented by Charge points for handling messages part of the OCPP 1.6 SmartCharging profile. 11 | type ChargePointHandler interface { 12 | OnSetChargingProfile(request *SetChargingProfileRequest) (confirmation *SetChargingProfileConfirmation, err error) 13 | OnClearChargingProfile(request *ClearChargingProfileRequest) (confirmation *ClearChargingProfileConfirmation, err error) 14 | OnGetCompositeSchedule(request *GetCompositeScheduleRequest) (confirmation *GetCompositeScheduleConfirmation, err error) 15 | } 16 | 17 | // The profile name 18 | const ProfileName = "SmartCharging" 19 | 20 | // Provides support for basic Smart Charging, for instance using control pilot. 21 | var Profile = ocpp.NewProfile( 22 | ProfileName, 23 | SetChargingProfileFeature{}, 24 | ClearChargingProfileFeature{}, 25 | GetCompositeScheduleFeature{}) 26 | -------------------------------------------------------------------------------- /ocpp1.6/types/datetime.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "time" 7 | 8 | "github.com/relvacode/iso8601" 9 | ) 10 | 11 | // DateTimeFormat to be used when serializing all OCPP messages. 12 | // 13 | // The default dateTime format is RFC3339. 14 | // Change this if another format is desired. 15 | var DateTimeFormat = time.RFC3339 16 | 17 | // DateTime wraps a time.Time struct, allowing for improved dateTime JSON compatibility. 18 | type DateTime struct { 19 | time.Time 20 | } 21 | 22 | // Creates a new DateTime struct, embedding a time.Time struct. 23 | func NewDateTime(time time.Time) *DateTime { 24 | return &DateTime{Time: time} 25 | } 26 | 27 | // Creates a new DateTime struct, containing a time.Now() value. 28 | func Now() *DateTime { 29 | return &DateTime{Time: time.Now()} 30 | } 31 | 32 | func null(b []byte) bool { 33 | if len(b) != 4 { 34 | return false 35 | } 36 | if b[0] != 'n' && b[1] != 'u' && b[2] != 'l' && b[3] != 'l' { 37 | return false 38 | } 39 | return true 40 | } 41 | 42 | func (dt *DateTime) UnmarshalJSON(input []byte) error { 43 | // Do not parse null timestamps 44 | if null(input) { 45 | return nil 46 | } 47 | // Assert that timestamp is a string 48 | if len(input) > 0 && input[0] == '"' && input[len(input)-1] == '"' { 49 | input = input[1 : len(input)-1] 50 | } else { 51 | return errors.New("timestamp not enclosed in double quotes") 52 | } 53 | // Parse ISO8601 54 | var err error 55 | dt.Time, err = iso8601.Parse(input) 56 | return err 57 | } 58 | 59 | func (dt *DateTime) MarshalJSON() ([]byte, error) { 60 | if DateTimeFormat == "" { 61 | return json.Marshal(dt.Time) 62 | } 63 | timeStr := dt.FormatTimestamp() 64 | return json.Marshal(timeStr) 65 | } 66 | 67 | // Formats the UTC timestamp using the DateTimeFormat setting. 68 | // This function is used during JSON marshaling as well. 69 | func (dt *DateTime) FormatTimestamp() string { 70 | return dt.UTC().Format(DateTimeFormat) 71 | } 72 | 73 | func FormatTimestamp(t time.Time) string { 74 | return t.UTC().Format(DateTimeFormat) 75 | } 76 | 77 | // DateTime Validation 78 | 79 | func DateTimeIsNull(dateTime *DateTime) bool { 80 | return dateTime != nil && dateTime.IsZero() 81 | } 82 | -------------------------------------------------------------------------------- /ocpp1.6_test/clear_cache_test.go: -------------------------------------------------------------------------------- 1 | package ocpp16_test 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/lorenzodonini/ocpp-go/ocpp1.6/core" 7 | "github.com/stretchr/testify/assert" 8 | "github.com/stretchr/testify/mock" 9 | "github.com/stretchr/testify/require" 10 | ) 11 | 12 | // Test 13 | func (suite *OcppV16TestSuite) TestClearCacheRequestValidation() { 14 | t := suite.T() 15 | var requestTable = []GenericTestEntry{ 16 | {core.ClearCacheRequest{}, true}, 17 | } 18 | ExecuteGenericTestTable(t, requestTable) 19 | } 20 | 21 | func (suite *OcppV16TestSuite) TestClearCacheConfirmationValidation() { 22 | t := suite.T() 23 | var confirmationTable = []GenericTestEntry{ 24 | {core.ClearCacheConfirmation{Status: core.ClearCacheStatusAccepted}, true}, 25 | {core.ClearCacheConfirmation{Status: core.ClearCacheStatusRejected}, true}, 26 | {core.ClearCacheConfirmation{Status: "invalidClearCacheStatus"}, false}, 27 | {core.ClearCacheConfirmation{}, false}, 28 | } 29 | ExecuteGenericTestTable(t, confirmationTable) 30 | } 31 | 32 | func (suite *OcppV16TestSuite) TestClearCacheE2EMocked() { 33 | t := suite.T() 34 | wsId := "test_id" 35 | messageId := defaultMessageId 36 | wsUrl := "someUrl" 37 | status := core.ClearCacheStatusAccepted 38 | requestJson := fmt.Sprintf(`[2,"%v","%v",{}]`, messageId, core.ClearCacheFeatureName) 39 | responseJson := fmt.Sprintf(`[3,"%v",{"status":"%v"}]`, messageId, status) 40 | clearCacheConfirmation := core.NewClearCacheConfirmation(status) 41 | channel := NewMockWebSocket(wsId) 42 | 43 | coreListener := &MockChargePointCoreListener{} 44 | coreListener.On("OnClearCache", mock.Anything).Return(clearCacheConfirmation, nil) 45 | setupDefaultCentralSystemHandlers(suite, nil, expectedCentralSystemOptions{clientId: wsId, rawWrittenMessage: []byte(requestJson), forwardWrittenMessage: true}) 46 | setupDefaultChargePointHandlers(suite, coreListener, expectedChargePointOptions{serverUrl: wsUrl, clientId: wsId, createChannelOnStart: true, channel: channel, rawWrittenMessage: []byte(responseJson), forwardWrittenMessage: true}) 47 | // Run Test 48 | suite.centralSystem.Start(8887, "somePath") 49 | err := suite.chargePoint.Start(wsUrl) 50 | require.Nil(t, err) 51 | resultChannel := make(chan bool, 1) 52 | err = suite.centralSystem.ClearCache(wsId, func(confirmation *core.ClearCacheConfirmation, err error) { 53 | require.Nil(t, err) 54 | require.NotNil(t, confirmation) 55 | assert.Equal(t, status, confirmation.Status) 56 | resultChannel <- true 57 | }) 58 | require.Nil(t, err) 59 | result := <-resultChannel 60 | assert.True(t, result) 61 | } 62 | 63 | func (suite *OcppV16TestSuite) TestClearCacheInvalidEndpoint() { 64 | messageId := defaultMessageId 65 | clearCacheRequest := core.NewClearCacheRequest() 66 | requestJson := fmt.Sprintf(`[2,"%v","%v",{}]`, messageId, core.ClearCacheFeatureName) 67 | testUnsupportedRequestFromChargePoint(suite, clearCacheRequest, requestJson, messageId) 68 | } 69 | -------------------------------------------------------------------------------- /ocpp1.6_test/heartbeat_test.go: -------------------------------------------------------------------------------- 1 | package ocpp16_test 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | "github.com/lorenzodonini/ocpp-go/ocpp1.6/core" 8 | "github.com/lorenzodonini/ocpp-go/ocpp1.6/types" 9 | "github.com/stretchr/testify/mock" 10 | "github.com/stretchr/testify/require" 11 | ) 12 | 13 | // Test 14 | func (suite *OcppV16TestSuite) TestHeartbeatRequestValidation() { 15 | t := suite.T() 16 | var requestTable = []GenericTestEntry{ 17 | {core.HeartbeatRequest{}, true}, 18 | } 19 | ExecuteGenericTestTable(t, requestTable) 20 | } 21 | 22 | func (suite *OcppV16TestSuite) TestHeartbeatConfirmationValidation() { 23 | t := suite.T() 24 | var confirmationTable = []GenericTestEntry{ 25 | {core.HeartbeatConfirmation{CurrentTime: types.NewDateTime(time.Now())}, true}, 26 | {core.HeartbeatConfirmation{}, false}, 27 | } 28 | ExecuteGenericTestTable(t, confirmationTable) 29 | } 30 | 31 | func (suite *OcppV16TestSuite) TestHeartbeatE2EMocked() { 32 | t := suite.T() 33 | wsId := "test_id" 34 | messageId := defaultMessageId 35 | wsUrl := "someUrl" 36 | currentTime := types.NewDateTime(time.Now()) 37 | requestJson := fmt.Sprintf(`[2,"%v","%v",{}]`, messageId, core.HeartbeatFeatureName) 38 | responseJson := fmt.Sprintf(`[3,"%v",{"currentTime":"%v"}]`, messageId, currentTime.FormatTimestamp()) 39 | heartbeatConfirmation := core.NewHeartbeatConfirmation(currentTime) 40 | channel := NewMockWebSocket(wsId) 41 | 42 | coreListener := &MockCentralSystemCoreListener{} 43 | coreListener.On("OnHeartbeat", mock.AnythingOfType("string"), mock.Anything).Return(heartbeatConfirmation, nil).Run(func(args mock.Arguments) { 44 | request, ok := args.Get(1).(*core.HeartbeatRequest) 45 | require.NotNil(t, request) 46 | require.True(t, ok) 47 | }) 48 | setupDefaultCentralSystemHandlers(suite, coreListener, expectedCentralSystemOptions{clientId: wsId, rawWrittenMessage: []byte(responseJson), forwardWrittenMessage: true}) 49 | setupDefaultChargePointHandlers(suite, nil, expectedChargePointOptions{serverUrl: wsUrl, clientId: wsId, createChannelOnStart: true, channel: channel, rawWrittenMessage: []byte(requestJson), forwardWrittenMessage: true}) 50 | // Run Test 51 | suite.centralSystem.Start(8887, "somePath") 52 | err := suite.chargePoint.Start(wsUrl) 53 | require.Nil(t, err) 54 | confirmation, err := suite.chargePoint.Heartbeat() 55 | require.Nil(t, err) 56 | require.NotNil(t, confirmation) 57 | assertDateTimeEquality(t, *currentTime, *confirmation.CurrentTime) 58 | } 59 | 60 | func (suite *OcppV16TestSuite) TestHeartbeatInvalidEndpoint() { 61 | messageId := defaultMessageId 62 | heartbeatRequest := core.NewHeartbeatRequest() 63 | requestJson := fmt.Sprintf(`[2,"%v","%v",{}]`, messageId, core.HeartbeatFeatureName) 64 | testUnsupportedRequestFromCentralSystem(suite, heartbeatRequest, requestJson, messageId) 65 | } 66 | -------------------------------------------------------------------------------- /ocpp1.6_test/mocks/mock_local_auth_list_central_system_handler.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.51.0. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import mock "github.com/stretchr/testify/mock" 6 | 7 | // MockLocalAuthListCentralSystemHandler is an autogenerated mock type for the CentralSystemHandler type 8 | type MockLocalAuthListCentralSystemHandler struct { 9 | mock.Mock 10 | } 11 | 12 | type MockLocalAuthListCentralSystemHandler_Expecter struct { 13 | mock *mock.Mock 14 | } 15 | 16 | func (_m *MockLocalAuthListCentralSystemHandler) EXPECT() *MockLocalAuthListCentralSystemHandler_Expecter { 17 | return &MockLocalAuthListCentralSystemHandler_Expecter{mock: &_m.Mock} 18 | } 19 | 20 | // NewMockLocalAuthListCentralSystemHandler creates a new instance of MockLocalAuthListCentralSystemHandler. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. 21 | // The first argument is typically a *testing.T value. 22 | func NewMockLocalAuthListCentralSystemHandler(t interface { 23 | mock.TestingT 24 | Cleanup(func()) 25 | }) *MockLocalAuthListCentralSystemHandler { 26 | mock := &MockLocalAuthListCentralSystemHandler{} 27 | mock.Mock.Test(t) 28 | 29 | t.Cleanup(func() { mock.AssertExpectations(t) }) 30 | 31 | return mock 32 | } 33 | -------------------------------------------------------------------------------- /ocpp1.6_test/mocks/mock_ocpp16.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.51.0. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | ocpp16 "github.com/lorenzodonini/ocpp-go/ocpp1.6" 7 | mock "github.com/stretchr/testify/mock" 8 | ) 9 | 10 | // MockChargePointConnectionHandler is an autogenerated mock type for the ChargePointConnectionHandler type 11 | type MockChargePointConnectionHandler struct { 12 | mock.Mock 13 | } 14 | 15 | type MockChargePointConnectionHandler_Expecter struct { 16 | mock *mock.Mock 17 | } 18 | 19 | func (_m *MockChargePointConnectionHandler) EXPECT() *MockChargePointConnectionHandler_Expecter { 20 | return &MockChargePointConnectionHandler_Expecter{mock: &_m.Mock} 21 | } 22 | 23 | // Execute provides a mock function with given fields: chargePoint 24 | func (_m *MockChargePointConnectionHandler) Execute(chargePoint ocpp16.ChargePointConnection) { 25 | _m.Called(chargePoint) 26 | } 27 | 28 | // MockChargePointConnectionHandler_Execute_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Execute' 29 | type MockChargePointConnectionHandler_Execute_Call struct { 30 | *mock.Call 31 | } 32 | 33 | // Execute is a helper method to define mock.On call 34 | // - chargePoint ocpp16.ChargePointConnection 35 | func (_e *MockChargePointConnectionHandler_Expecter) Execute(chargePoint interface{}) *MockChargePointConnectionHandler_Execute_Call { 36 | return &MockChargePointConnectionHandler_Execute_Call{Call: _e.mock.On("Execute", chargePoint)} 37 | } 38 | 39 | func (_c *MockChargePointConnectionHandler_Execute_Call) Run(run func(chargePoint ocpp16.ChargePointConnection)) *MockChargePointConnectionHandler_Execute_Call { 40 | _c.Call.Run(func(args mock.Arguments) { 41 | run(args[0].(ocpp16.ChargePointConnection)) 42 | }) 43 | return _c 44 | } 45 | 46 | func (_c *MockChargePointConnectionHandler_Execute_Call) Return() *MockChargePointConnectionHandler_Execute_Call { 47 | _c.Call.Return() 48 | return _c 49 | } 50 | 51 | func (_c *MockChargePointConnectionHandler_Execute_Call) RunAndReturn(run func(ocpp16.ChargePointConnection)) *MockChargePointConnectionHandler_Execute_Call { 52 | _c.Run(run) 53 | return _c 54 | } 55 | 56 | // NewMockChargePointConnectionHandler creates a new instance of MockChargePointConnectionHandler. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. 57 | // The first argument is typically a *testing.T value. 58 | func NewMockChargePointConnectionHandler(t interface { 59 | mock.TestingT 60 | Cleanup(func()) 61 | }) *MockChargePointConnectionHandler { 62 | mock := &MockChargePointConnectionHandler{} 63 | mock.Mock.Test(t) 64 | 65 | t.Cleanup(func() { mock.AssertExpectations(t) }) 66 | 67 | return mock 68 | } 69 | -------------------------------------------------------------------------------- /ocpp1.6_test/mocks/mock_remote_trigger_central_system_handler.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.51.0. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import mock "github.com/stretchr/testify/mock" 6 | 7 | // MockRemoteTriggerCentralSystemHandler is an autogenerated mock type for the CentralSystemHandler type 8 | type MockRemoteTriggerCentralSystemHandler struct { 9 | mock.Mock 10 | } 11 | 12 | type MockRemoteTriggerCentralSystemHandler_Expecter struct { 13 | mock *mock.Mock 14 | } 15 | 16 | func (_m *MockRemoteTriggerCentralSystemHandler) EXPECT() *MockRemoteTriggerCentralSystemHandler_Expecter { 17 | return &MockRemoteTriggerCentralSystemHandler_Expecter{mock: &_m.Mock} 18 | } 19 | 20 | // NewMockRemoteTriggerCentralSystemHandler creates a new instance of MockRemoteTriggerCentralSystemHandler. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. 21 | // The first argument is typically a *testing.T value. 22 | func NewMockRemoteTriggerCentralSystemHandler(t interface { 23 | mock.TestingT 24 | Cleanup(func()) 25 | }) *MockRemoteTriggerCentralSystemHandler { 26 | mock := &MockRemoteTriggerCentralSystemHandler{} 27 | mock.Mock.Test(t) 28 | 29 | t.Cleanup(func() { mock.AssertExpectations(t) }) 30 | 31 | return mock 32 | } 33 | -------------------------------------------------------------------------------- /ocpp1.6_test/mocks/mock_reservation_central_system_handler.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.51.0. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import mock "github.com/stretchr/testify/mock" 6 | 7 | // MockReservationCentralSystemHandler is an autogenerated mock type for the CentralSystemHandler type 8 | type MockReservationCentralSystemHandler struct { 9 | mock.Mock 10 | } 11 | 12 | type MockReservationCentralSystemHandler_Expecter struct { 13 | mock *mock.Mock 14 | } 15 | 16 | func (_m *MockReservationCentralSystemHandler) EXPECT() *MockReservationCentralSystemHandler_Expecter { 17 | return &MockReservationCentralSystemHandler_Expecter{mock: &_m.Mock} 18 | } 19 | 20 | // NewMockReservationCentralSystemHandler creates a new instance of MockReservationCentralSystemHandler. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. 21 | // The first argument is typically a *testing.T value. 22 | func NewMockReservationCentralSystemHandler(t interface { 23 | mock.TestingT 24 | Cleanup(func()) 25 | }) *MockReservationCentralSystemHandler { 26 | mock := &MockReservationCentralSystemHandler{} 27 | mock.Mock.Test(t) 28 | 29 | t.Cleanup(func() { mock.AssertExpectations(t) }) 30 | 31 | return mock 32 | } 33 | -------------------------------------------------------------------------------- /ocpp1.6_test/mocks/mock_smart_charging_central_system_handler.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.51.0. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import mock "github.com/stretchr/testify/mock" 6 | 7 | // MockSmartChargingCentralSystemHandler is an autogenerated mock type for the CentralSystemHandler type 8 | type MockSmartChargingCentralSystemHandler struct { 9 | mock.Mock 10 | } 11 | 12 | type MockSmartChargingCentralSystemHandler_Expecter struct { 13 | mock *mock.Mock 14 | } 15 | 16 | func (_m *MockSmartChargingCentralSystemHandler) EXPECT() *MockSmartChargingCentralSystemHandler_Expecter { 17 | return &MockSmartChargingCentralSystemHandler_Expecter{mock: &_m.Mock} 18 | } 19 | 20 | // NewMockSmartChargingCentralSystemHandler creates a new instance of MockSmartChargingCentralSystemHandler. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. 21 | // The first argument is typically a *testing.T value. 22 | func NewMockSmartChargingCentralSystemHandler(t interface { 23 | mock.TestingT 24 | Cleanup(func()) 25 | }) *MockSmartChargingCentralSystemHandler { 26 | mock := &MockSmartChargingCentralSystemHandler{} 27 | mock.Mock.Test(t) 28 | 29 | t.Cleanup(func() { mock.AssertExpectations(t) }) 30 | 31 | return mock 32 | } 33 | -------------------------------------------------------------------------------- /ocpp1.6_test/ocpp16_extension_test.go: -------------------------------------------------------------------------------- 1 | package ocpp16_test 2 | 3 | import ( 4 | "strings" 5 | ) 6 | 7 | // Generates a new dummy string of the specified length. 8 | func newLongString(length int) string { 9 | reps := length / 32 10 | s := strings.Repeat("................................", reps) 11 | for i := len(s); i < length; i++ { 12 | s += "." 13 | } 14 | return s 15 | } 16 | -------------------------------------------------------------------------------- /ocpp2.0.1/authorization/authorization.go: -------------------------------------------------------------------------------- 1 | // The authorization functional block contains OCPP 2.0 authorization-related features. It contains different ways of authorizing a user, online and/or offline . 2 | package authorization 3 | 4 | import "github.com/lorenzodonini/ocpp-go/ocpp" 5 | 6 | // Needs to be implemented by a CSMS for handling messages part of the OCPP 2.0 Authorization profile. 7 | type CSMSHandler interface { 8 | // OnAuthorize is called on the CSMS whenever an AuthorizeRequest is received from a charging station. 9 | OnAuthorize(chargingStationID string, request *AuthorizeRequest) (confirmation *AuthorizeResponse, err error) 10 | } 11 | 12 | // Needs to be implemented by Charging stations for handling messages part of the OCPP 2.0 Authorization profile. 13 | type ChargingStationHandler interface { 14 | // OnClearCache is called on a charging station whenever a ClearCacheRequest is received from the CSMS. 15 | OnClearCache(request *ClearCacheRequest) (confirmation *ClearCacheResponse, err error) 16 | } 17 | 18 | const ProfileName = "authorization" 19 | 20 | var Profile = ocpp.NewProfile( 21 | ProfileName, 22 | AuthorizeFeature{}, 23 | ClearCacheFeature{}, 24 | ) 25 | -------------------------------------------------------------------------------- /ocpp2.0.1/authorization/clear_cache.go: -------------------------------------------------------------------------------- 1 | package authorization 2 | 3 | import ( 4 | "reflect" 5 | 6 | "gopkg.in/go-playground/validator.v9" 7 | 8 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/types" 9 | ) 10 | 11 | // -------------------- Clear Cache (CSMS -> CS) -------------------- 12 | 13 | const ClearCacheFeatureName = "ClearCache" 14 | 15 | // Status returned in response to ClearCacheRequest. 16 | type ClearCacheStatus string 17 | 18 | const ( 19 | ClearCacheStatusAccepted ClearCacheStatus = "Accepted" 20 | ClearCacheStatusRejected ClearCacheStatus = "Rejected" 21 | ) 22 | 23 | func isValidClearCacheStatus(fl validator.FieldLevel) bool { 24 | status := ClearCacheStatus(fl.Field().String()) 25 | switch status { 26 | case ClearCacheStatusAccepted, ClearCacheStatusRejected: 27 | return true 28 | default: 29 | return false 30 | } 31 | } 32 | 33 | // The field definition of the ClearCache request payload sent by the CSMS to the Charging Station. 34 | type ClearCacheRequest struct { 35 | } 36 | 37 | // This field definition of the ClearCache response payload, sent by the Charging Station to the CSMS in response to a ClearCacheRequest. 38 | // In case the request was invalid, or couldn't be processed, an error will be sent instead. 39 | type ClearCacheResponse struct { 40 | Status ClearCacheStatus `json:"status" validate:"required,cacheStatus201"` 41 | StatusInfo *types.StatusInfo `json:"statusInfo,omitempty" validate:"omitempty"` 42 | } 43 | 44 | // CSMS can request a Charging Station to clear its Authorization Cache. 45 | // The CSMS SHALL send a ClearCacheRequest payload for clearing the Charging Station’s Authorization Cache. 46 | // Upon receipt of a ClearCacheRequest, the Charging Station SHALL respond with a ClearCacheResponse payload. 47 | // The response payload SHALL indicate whether the Charging Station was able to clear its Authorization Cache. 48 | type ClearCacheFeature struct{} 49 | 50 | func (f ClearCacheFeature) GetFeatureName() string { 51 | return ClearCacheFeatureName 52 | } 53 | 54 | func (f ClearCacheFeature) GetRequestType() reflect.Type { 55 | return reflect.TypeOf(ClearCacheRequest{}) 56 | } 57 | 58 | func (f ClearCacheFeature) GetResponseType() reflect.Type { 59 | return reflect.TypeOf(ClearCacheResponse{}) 60 | } 61 | 62 | func (r ClearCacheRequest) GetFeatureName() string { 63 | return ClearCacheFeatureName 64 | } 65 | 66 | func (c ClearCacheResponse) GetFeatureName() string { 67 | return ClearCacheFeatureName 68 | } 69 | 70 | // Creates a new ClearCacheRequest, which doesn't contain any required or optional fields. 71 | func NewClearCacheRequest() *ClearCacheRequest { 72 | return &ClearCacheRequest{} 73 | } 74 | 75 | // Creates a new ClearCacheResponse, containing all required fields. There are no optional fields for this message. 76 | func NewClearCacheResponse(status ClearCacheStatus) *ClearCacheResponse { 77 | return &ClearCacheResponse{Status: status} 78 | } 79 | 80 | func init() { 81 | _ = types.Validate.RegisterValidation("cacheStatus201", isValidClearCacheStatus) 82 | } 83 | -------------------------------------------------------------------------------- /ocpp2.0.1/availability/availability.go: -------------------------------------------------------------------------------- 1 | // The availability functional block contains OCPP 2.0 features for notifying the CSMS of availability and status changes. 2 | // A CSMS can also instruct a charging station to change its availability. 3 | package availability 4 | 5 | import "github.com/lorenzodonini/ocpp-go/ocpp" 6 | 7 | // Needs to be implemented by a CSMS for handling messages part of the OCPP 2.0 Availability profile. 8 | type CSMSHandler interface { 9 | // OnHeartbeat is called on the CSMS whenever a HeartbeatResponse is received from a charging station. 10 | OnHeartbeat(chargingStationID string, request *HeartbeatRequest) (response *HeartbeatResponse, err error) 11 | // OnStatusNotification is called on the CSMS whenever a StatusNotificationRequest is received from a charging station. 12 | OnStatusNotification(chargingStationID string, request *StatusNotificationRequest) (response *StatusNotificationResponse, err error) 13 | } 14 | 15 | // Needs to be implemented by Charging stations for handling messages part of the OCPP 2.0 Availability profile. 16 | type ChargingStationHandler interface { 17 | // OnChangeAvailability is called on a charging station whenever a ChangeAvailabilityRequest is received from the CSMS. 18 | OnChangeAvailability(request *ChangeAvailabilityRequest) (response *ChangeAvailabilityResponse, err error) 19 | } 20 | 21 | const ProfileName = "availability" 22 | 23 | var Profile = ocpp.NewProfile( 24 | ProfileName, 25 | ChangeAvailabilityFeature{}, 26 | HeartbeatFeature{}, 27 | StatusNotificationFeature{}, 28 | ) 29 | -------------------------------------------------------------------------------- /ocpp2.0.1/availability/heartbeat.go: -------------------------------------------------------------------------------- 1 | package availability 2 | 3 | import ( 4 | "reflect" 5 | 6 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/types" 7 | "gopkg.in/go-playground/validator.v9" 8 | ) 9 | 10 | // -------------------- Heartbeat (CS -> CSMS) -------------------- 11 | 12 | const HeartbeatFeatureName = "Heartbeat" 13 | 14 | // The field definition of the Heartbeat request payload sent by the Charging Station to the CSMS. 15 | type HeartbeatRequest struct { 16 | } 17 | 18 | // This field definition of the Heartbeat response payload, sent by the CSMS to the Charging Station in response to a HeartbeatRequest. 19 | // In case the request was invalid, or couldn't be processed, an error will be sent instead. 20 | type HeartbeatResponse struct { 21 | CurrentTime types.DateTime `json:"currentTime" validate:"required"` 22 | } 23 | 24 | // A Charging Station may send a heartbeat to let the CSMS know the Charging Station is still connected, after a configurable time interval. 25 | // 26 | // Upon receipt of HeartbeatRequest, the CSMS responds with HeartbeatResponse. 27 | // The response message contains the current time of the CSMS, which the Charging Station MAY use to synchronize its internal clock. 28 | type HeartbeatFeature struct{} 29 | 30 | func (f HeartbeatFeature) GetFeatureName() string { 31 | return HeartbeatFeatureName 32 | } 33 | 34 | func (f HeartbeatFeature) GetRequestType() reflect.Type { 35 | return reflect.TypeOf(HeartbeatRequest{}) 36 | } 37 | 38 | func (f HeartbeatFeature) GetResponseType() reflect.Type { 39 | return reflect.TypeOf(HeartbeatResponse{}) 40 | } 41 | 42 | func (r HeartbeatRequest) GetFeatureName() string { 43 | return HeartbeatFeatureName 44 | } 45 | 46 | func (c HeartbeatResponse) GetFeatureName() string { 47 | return HeartbeatFeatureName 48 | } 49 | 50 | // Creates a new HeartbeatRequest, which doesn't contain any required or optional fields. 51 | func NewHeartbeatRequest() *HeartbeatRequest { 52 | return &HeartbeatRequest{} 53 | } 54 | 55 | // Creates a new HeartbeatResponse, containing all required fields. There are no optional fields for this message. 56 | func NewHeartbeatResponse(currentTime types.DateTime) *HeartbeatResponse { 57 | return &HeartbeatResponse{CurrentTime: currentTime} 58 | } 59 | 60 | func validateHeartbeatResponse(sl validator.StructLevel) { 61 | response := sl.Current().Interface().(HeartbeatResponse) 62 | if types.DateTimeIsNull(&response.CurrentTime) { 63 | sl.ReportError(response.CurrentTime, "CurrentTime", "currentTime", "required", "") 64 | } 65 | } 66 | 67 | func init() { 68 | types.Validate.RegisterStructValidation(validateHeartbeatResponse, HeartbeatResponse{}) 69 | } 70 | -------------------------------------------------------------------------------- /ocpp2.0.1/data/data.go: -------------------------------------------------------------------------------- 1 | // The data transfer functional block enables parties to add custom commands and extensions to OCPP 2.0. 2 | package data 3 | 4 | import "github.com/lorenzodonini/ocpp-go/ocpp" 5 | 6 | // Needs to be implemented by a CSMS for handling messages part of the OCPP 2.0 Data transfer profile. 7 | type CSMSHandler interface { 8 | // OnDataTransfer is called on the CSMS whenever a DataTransferRequest is received from a charging station. 9 | OnDataTransfer(chargingStationID string, request *DataTransferRequest) (confirmation *DataTransferResponse, err error) 10 | } 11 | 12 | // Needs to be implemented by Charging stations for handling messages part of the OCPP 2.0 Data transfer profile. 13 | type ChargingStationHandler interface { 14 | // OnDataTransfer is called on a charging station whenever a DataTransferRequest is received from the CSMS. 15 | OnDataTransfer(request *DataTransferRequest) (confirmation *DataTransferResponse, err error) 16 | } 17 | 18 | const ProfileName = "data" 19 | 20 | var Profile = ocpp.NewProfile( 21 | ProfileName, 22 | DataTransferFeature{}, 23 | ) 24 | -------------------------------------------------------------------------------- /ocpp2.0.1/diagnostics/types.go: -------------------------------------------------------------------------------- 1 | package diagnostics 2 | 3 | import ( 4 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/types" 5 | "gopkg.in/go-playground/validator.v9" 6 | ) 7 | 8 | // MonitorType specifies the type of this monitor. 9 | type MonitorType string 10 | 11 | const ( 12 | MonitorUpperThreshold MonitorType = "UpperThreshold" // Triggers an event notice when the actual value of the Variable rises above monitorValue. 13 | MonitorLowerThreshold MonitorType = "LowerThreshold" // Triggers an event notice when the actual value of the Variable drops below monitorValue. 14 | MonitorDelta MonitorType = "Delta" // Triggers an event notice when the actual value has changed more than plus or minus monitorValue since the time that this monitor was set or since the last time this event notice was sent, whichever was last. 15 | MonitorPeriodic MonitorType = "Periodic" // Triggers an event notice every monitorValue seconds interval, starting from the time that this monitor was set. 16 | MonitorPeriodicClockAligned MonitorType = "PeriodicClockAligned" // Triggers an event notice every monitorValue seconds interval, starting from the nearest clock-aligned interval after this monitor was set. 17 | ) 18 | 19 | func isValidMonitorType(fl validator.FieldLevel) bool { 20 | status := MonitorType(fl.Field().String()) 21 | switch status { 22 | case MonitorUpperThreshold, MonitorLowerThreshold, MonitorDelta, MonitorPeriodic, MonitorPeriodicClockAligned: 23 | return true 24 | default: 25 | return false 26 | } 27 | } 28 | 29 | func init() { 30 | _ = types.Validate.RegisterValidation("monitorType", isValidMonitorType) 31 | } 32 | -------------------------------------------------------------------------------- /ocpp2.0.1/display/display.go: -------------------------------------------------------------------------------- 1 | // The display functional block contains OCPP 2.0 features for managing message that get displayed on a charging station. 2 | package display 3 | 4 | import "github.com/lorenzodonini/ocpp-go/ocpp" 5 | 6 | // Needs to be implemented by a CSMS for handling messages part of the OCPP 2.0 Display profile. 7 | type CSMSHandler interface { 8 | // OnNotifyDisplayMessages is called on the CSMS whenever a NotifyDisplayMessagesRequest is received from a Charging Station. 9 | OnNotifyDisplayMessages(chargingStationID string, request *NotifyDisplayMessagesRequest) (response *NotifyDisplayMessagesResponse, err error) 10 | } 11 | 12 | // Needs to be implemented by Charging stations for handling messages part of the OCPP 2.0 Display profile. 13 | type ChargingStationHandler interface { 14 | // OnClearDisplay is called on a charging station whenever a ClearDisplayRequest is received from the CSMS. 15 | OnClearDisplay(request *ClearDisplayRequest) (confirmation *ClearDisplayResponse, err error) 16 | // OnGetDisplayMessages is called on a charging station whenever a GetDisplayMessagesRequest is received from the CSMS. 17 | OnGetDisplayMessages(request *GetDisplayMessagesRequest) (confirmation *GetDisplayMessagesResponse, err error) 18 | // OnSetDisplayMessage is called on a charging station whenever a SetDisplayMessageRequest is received from the CSMS. 19 | OnSetDisplayMessage(request *SetDisplayMessageRequest) (response *SetDisplayMessageResponse, err error) 20 | } 21 | 22 | const ProfileName = "display" 23 | 24 | var Profile = ocpp.NewProfile( 25 | ProfileName, 26 | ClearDisplayFeature{}, 27 | GetDisplayMessagesFeature{}, 28 | NotifyDisplayMessagesFeature{}, 29 | SetDisplayMessageFeature{}, 30 | ) 31 | -------------------------------------------------------------------------------- /ocpp2.0.1/display/get_display_messages.go: -------------------------------------------------------------------------------- 1 | package display 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | // -------------------- Get Display Messages (CSMS -> CS) -------------------- 8 | 9 | const GetDisplayMessagesFeatureName = "GetDisplayMessages" 10 | 11 | // The field definition of the GetDisplayMessages request payload sent by the CSMS to the Charging Station. 12 | type GetDisplayMessagesRequest struct { 13 | RequestID int `json:"requestId" validate:"gte=0"` 14 | Priority MessagePriority `json:"priority,omitempty" validate:"omitempty,messagePriority"` 15 | State MessageState `json:"state,omitempty" validate:"omitempty,messageState"` 16 | ID []int `json:"id,omitempty" validate:"omitempty,dive,gte=0"` 17 | } 18 | 19 | // This field definition of the GetDisplayMessages response payload, sent by the Charging Station to the CSMS in response to a GetDisplayMessagesRequest. 20 | // In case the request was invalid, or couldn't be processed, an error will be sent instead. 21 | type GetDisplayMessagesResponse struct { 22 | Status MessageStatus `json:"status" validate:"required,messageStatus"` 23 | } 24 | 25 | // A Charging Station can remove messages when they are out-dated, or transactions have ended. It can be very useful for a CSO to be able to view to current list of messages, so the CSO knows which messages are (still) configured. 26 | // 27 | // A CSO MAY request all the installed DisplayMessages configured via OCPP in a Charging Station. For this the CSO asks the CSMS to retrieve all messages. 28 | // The CSMS sends a GetDisplayMessagesRequest message to the Charging Station. 29 | // The Charging Station responds with a GetDisplayMessagesResponse Accepted, indicating it has configured messages and will send them. 30 | // 31 | // The Charging Station asynchronously sends one or more NotifyDisplayMessagesRequest messages to the 32 | // CSMS (depending on the amount of messages to be sent). 33 | type GetDisplayMessagesFeature struct{} 34 | 35 | func (f GetDisplayMessagesFeature) GetFeatureName() string { 36 | return GetDisplayMessagesFeatureName 37 | } 38 | 39 | func (f GetDisplayMessagesFeature) GetRequestType() reflect.Type { 40 | return reflect.TypeOf(GetDisplayMessagesRequest{}) 41 | } 42 | 43 | func (f GetDisplayMessagesFeature) GetResponseType() reflect.Type { 44 | return reflect.TypeOf(GetDisplayMessagesResponse{}) 45 | } 46 | 47 | func (r GetDisplayMessagesRequest) GetFeatureName() string { 48 | return GetDisplayMessagesFeatureName 49 | } 50 | 51 | func (c GetDisplayMessagesResponse) GetFeatureName() string { 52 | return GetDisplayMessagesFeatureName 53 | } 54 | 55 | // Creates a new GetDisplayMessagesRequest, containing all required fields. Optional fields may be set afterwards. 56 | func NewGetDisplayMessagesRequest(requestId int) *GetDisplayMessagesRequest { 57 | return &GetDisplayMessagesRequest{RequestID: requestId} 58 | } 59 | 60 | // Creates a new GetDisplayMessagesResponse, containing all required fields. There are no optional fields for this message. 61 | func NewGetDisplayMessagesResponse(status MessageStatus) *GetDisplayMessagesResponse { 62 | return &GetDisplayMessagesResponse{Status: status} 63 | } 64 | -------------------------------------------------------------------------------- /ocpp2.0.1/display/notify_display_messages.go: -------------------------------------------------------------------------------- 1 | package display 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | // -------------------- Notify Display Messages (CS -> CSMS) -------------------- 8 | 9 | const NotifyDisplayMessagesFeatureName = "NotifyDisplayMessages" 10 | 11 | // The field definition of the NotifyDisplayMessages request payload sent by the CSMS to the Charging Station. 12 | type NotifyDisplayMessagesRequest struct { 13 | RequestID int `json:"requestId" validate:"gte=0"` // The id of the GetDisplayMessagesRequest that requested this message. 14 | Tbc bool `json:"tbc,omitempty" validate:"omitempty"` // "to be continued" indicator. Indicates whether another part of the report follows in an upcoming NotifyDisplayMessagesRequest message. Default value when omitted is false. 15 | MessageInfo []MessageInfo `json:"messageInfo,omitempty" validate:"omitempty,dive"` // The requested display message as configured in the Charging Station. 16 | } 17 | 18 | // This field definition of the NotifyDisplayMessages response payload, sent by the Charging Station to the CSMS in response to a NotifyDisplayMessagesRequest. 19 | // In case the request was invalid, or couldn't be processed, an error will be sent instead. 20 | type NotifyDisplayMessagesResponse struct { 21 | } 22 | 23 | // A CSO MAY request all the installed DisplayMessages configured via OCPP in a Charging Station. For this the CSO asks the CSMS to retrieve all messages (see GetDisplayMessagesFeature). 24 | // If the Charging Station responded with a status Accepted, it will then send these messages asynchronously to the CSMS. 25 | // 26 | // The Charging Station sends one or more NotifyDisplayMessagesRequest message to the CSMS (depending on the amount of messages to be send). 27 | // The CSMS responds to every notification with a NotifyDisplayMessagesResponse message. 28 | type NotifyDisplayMessagesFeature struct{} 29 | 30 | func (f NotifyDisplayMessagesFeature) GetFeatureName() string { 31 | return NotifyDisplayMessagesFeatureName 32 | } 33 | 34 | func (f NotifyDisplayMessagesFeature) GetRequestType() reflect.Type { 35 | return reflect.TypeOf(NotifyDisplayMessagesRequest{}) 36 | } 37 | 38 | func (f NotifyDisplayMessagesFeature) GetResponseType() reflect.Type { 39 | return reflect.TypeOf(NotifyDisplayMessagesResponse{}) 40 | } 41 | 42 | func (r NotifyDisplayMessagesRequest) GetFeatureName() string { 43 | return NotifyDisplayMessagesFeatureName 44 | } 45 | 46 | func (c NotifyDisplayMessagesResponse) GetFeatureName() string { 47 | return NotifyDisplayMessagesFeatureName 48 | } 49 | 50 | // Creates a new NotifyDisplayMessagesRequest, containing all required fields. Optional fields may be set afterwards. 51 | func NewNotifyDisplayMessagesRequest(requestID int) *NotifyDisplayMessagesRequest { 52 | return &NotifyDisplayMessagesRequest{RequestID: requestID} 53 | } 54 | 55 | // Creates a new NotifyDisplayMessagesResponse, which doesn't contain any required or optional fields. 56 | func NewNotifyDisplayMessagesResponse() *NotifyDisplayMessagesResponse { 57 | return &NotifyDisplayMessagesResponse{} 58 | } 59 | -------------------------------------------------------------------------------- /ocpp2.0.1/firmware/firmware.go: -------------------------------------------------------------------------------- 1 | // The firmware functional block contains OCPP 2.0 features that enable firmware updates on a charging station. 2 | package firmware 3 | 4 | import "github.com/lorenzodonini/ocpp-go/ocpp" 5 | 6 | // Needs to be implemented by a CSMS for handling messages part of the OCPP 2.0 Firmware profile. 7 | type CSMSHandler interface { 8 | // OnFirmwareStatusNotification is called on the CSMS whenever a FirmwareStatusNotificationRequest is received from a charging station. 9 | OnFirmwareStatusNotification(chargingStationID string, request *FirmwareStatusNotificationRequest) (response *FirmwareStatusNotificationResponse, err error) 10 | // OnPublishFirmwareStatusNotification is called on the CSMS whenever a PublishFirmwareStatusNotificationRequest is received from a local controller. 11 | OnPublishFirmwareStatusNotification(chargingStationID string, request *PublishFirmwareStatusNotificationRequest) (response *PublishFirmwareStatusNotificationResponse, err error) 12 | } 13 | 14 | // Needs to be implemented by Charging stations for handling messages part of the OCPP 2.0 Firmware profile. 15 | type ChargingStationHandler interface { 16 | // OnPublishFirmware is called on a charging station whenever a PublishFirmwareRequest is received from the CSMS. 17 | OnPublishFirmware(request *PublishFirmwareRequest) (response *PublishFirmwareResponse, err error) 18 | // OnUnpublishFirmware is called on a charging station whenever a UnpublishFirmwareRequest is received from the CSMS. 19 | OnUnpublishFirmware(request *UnpublishFirmwareRequest) (response *UnpublishFirmwareResponse, err error) 20 | // OnUpdateFirmware is called on a charging station whenever a UpdateFirmwareRequest is received from the CSMS. 21 | OnUpdateFirmware(request *UpdateFirmwareRequest) (response *UpdateFirmwareResponse, err error) 22 | } 23 | 24 | const ProfileName = "firmware" 25 | 26 | var Profile = ocpp.NewProfile( 27 | ProfileName, 28 | FirmwareStatusNotificationFeature{}, 29 | PublishFirmwareFeature{}, 30 | PublishFirmwareStatusNotificationFeature{}, 31 | UnpublishFirmwareFeature{}, 32 | UpdateFirmwareFeature{}, 33 | ) 34 | -------------------------------------------------------------------------------- /ocpp2.0.1/iso15118/get_certificate_status.go: -------------------------------------------------------------------------------- 1 | package iso15118 2 | 3 | import ( 4 | "reflect" 5 | 6 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/types" 7 | ) 8 | 9 | // -------------------- Get Certificate Status (CS -> CSMS) -------------------- 10 | 11 | const GetCertificateStatusFeatureName = "GetCertificateStatus" 12 | 13 | // The field definition of the GetCertificateStatus request payload sent by the Charging Station to the CSMS. 14 | type GetCertificateStatusRequest struct { 15 | OcspRequestData types.OCSPRequestDataType `json:"ocspRequestData" validate:"required"` 16 | } 17 | 18 | // This field definition of the GetCertificateStatus response payload, sent by the CSMS to the Charging Station in response to a GetCertificateStatusRequest. 19 | // In case the request was invalid, or couldn't be processed, an error will be sent instead. 20 | type GetCertificateStatusResponse struct { 21 | Status types.GenericStatus `json:"status" validate:"required,genericStatus"` 22 | OcspResult string `json:"ocspResult,omitempty" validate:"omitempty,max=5500"` 23 | StatusInfo *types.StatusInfo `json:"statusInfo,omitempty" validate:"omitempty"` 24 | } 25 | 26 | // For 15118 certificate installation on EVs, the Charging Station requests the CSMS to provide the OCSP certificate 27 | // status for its 15118 certificates. 28 | // The CSMS responds with a GetCertificateStatusResponse, containing the OCSP certificate status. 29 | // The status indicator in the GetCertificateStatusResponse indicates whether or not the CSMS was successful in retrieving the certificate status. 30 | // It does NOT indicate the validity of the certificate. 31 | type GetCertificateStatusFeature struct{} 32 | 33 | func (f GetCertificateStatusFeature) GetFeatureName() string { 34 | return GetCertificateStatusFeatureName 35 | } 36 | 37 | func (f GetCertificateStatusFeature) GetRequestType() reflect.Type { 38 | return reflect.TypeOf(GetCertificateStatusRequest{}) 39 | } 40 | 41 | func (f GetCertificateStatusFeature) GetResponseType() reflect.Type { 42 | return reflect.TypeOf(GetCertificateStatusResponse{}) 43 | } 44 | 45 | func (r GetCertificateStatusRequest) GetFeatureName() string { 46 | return GetCertificateStatusFeatureName 47 | } 48 | 49 | func (c GetCertificateStatusResponse) GetFeatureName() string { 50 | return GetCertificateStatusFeatureName 51 | } 52 | 53 | // Creates a new GetCertificateStatusRequest, containing all required fields. There are no optional fields for this message. 54 | func NewGetCertificateStatusRequest(ocspRequestData types.OCSPRequestDataType) *GetCertificateStatusRequest { 55 | return &GetCertificateStatusRequest{OcspRequestData: ocspRequestData} 56 | } 57 | 58 | // Creates a new GetCertificateStatusResponse, containing all required fields. Optional fields may be set afterwards. 59 | func NewGetCertificateStatusResponse(status types.GenericStatus) *GetCertificateStatusResponse { 60 | return &GetCertificateStatusResponse{Status: status} 61 | } 62 | -------------------------------------------------------------------------------- /ocpp2.0.1/iso15118/iso_15118.go: -------------------------------------------------------------------------------- 1 | // The ISO 15118 functional block contains OCPP 2.0 features that allow: 2 | // 3 | // - communication between EV and an EVSE 4 | // 5 | // - support for certificate-based authentication and authorization at the charging station, i.e. plug and charge 6 | package iso15118 7 | 8 | import "github.com/lorenzodonini/ocpp-go/ocpp" 9 | 10 | // Needs to be implemented by a CSMS for handling messages part of the OCPP 2.0 ISO 15118 profile. 11 | type CSMSHandler interface { 12 | // OnGet15118EVCertificate is called on the CSMS whenever a Get15118EVCertificateRequest is received from a charging station. 13 | OnGet15118EVCertificate(chargingStationID string, request *Get15118EVCertificateRequest) (response *Get15118EVCertificateResponse, err error) 14 | // OnGetCertificateStatus is called on the CSMS whenever a GetCertificateStatusRequest is received from a charging station. 15 | OnGetCertificateStatus(chargingStationID string, request *GetCertificateStatusRequest) (response *GetCertificateStatusResponse, err error) 16 | } 17 | 18 | // Needs to be implemented by Charging stations for handling messages part of the OCPP 2.0 ISO 15118 profile. 19 | type ChargingStationHandler interface { 20 | // OnDeleteCertificate is called on a charging station whenever a DeleteCertificateRequest is received from the CSMS. 21 | OnDeleteCertificate(request *DeleteCertificateRequest) (response *DeleteCertificateResponse, err error) 22 | // OnGetInstalledCertificateIds is called on a charging station whenever a GetInstalledCertificateIdsRequest is received from the CSMS. 23 | OnGetInstalledCertificateIds(request *GetInstalledCertificateIdsRequest) (response *GetInstalledCertificateIdsResponse, err error) 24 | // OnInstallCertificate is called on a charging station whenever an InstallCertificateRequest is received from the CSMS. 25 | OnInstallCertificate(request *InstallCertificateRequest) (response *InstallCertificateResponse, err error) 26 | } 27 | 28 | const ProfileName = "iso15118" 29 | 30 | var Profile = ocpp.NewProfile( 31 | ProfileName, 32 | DeleteCertificateFeature{}, 33 | Get15118EVCertificateFeature{}, 34 | GetCertificateStatusFeature{}, 35 | GetInstalledCertificateIdsFeature{}, 36 | InstallCertificateFeature{}, 37 | ) 38 | -------------------------------------------------------------------------------- /ocpp2.0.1/localauth/get_local_list_version.go: -------------------------------------------------------------------------------- 1 | package localauth 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | // -------------------- Get Local List Version (CSMS -> CS) -------------------- 8 | 9 | const GetLocalListVersionFeatureName = "GetLocalListVersion" 10 | 11 | // The field definition of the GetLocalListVersion request payload sent by the CSMS to the Charging Station. 12 | type GetLocalListVersionRequest struct { 13 | } 14 | 15 | // This field definition of the GetLocalListVersion response payload, sent by the Charging Station to the CSMS in response to a GetLocalListVersionRequest. 16 | // In case the request was invalid, or couldn't be processed, an error will be sent instead. 17 | type GetLocalListVersionResponse struct { 18 | VersionNumber int `json:"versionNumber" validate:"gte=0"` 19 | } 20 | 21 | // The CSMS can request a Charging Station for the version number of the Local Authorization List by sending a GetLocalListVersionRequest. 22 | // Upon receipt of the GetLocalListVersionRequest Charging Station responds with a GetLocalListVersionResponse containing the version number of its Local Authorization List. 23 | // The Charging Station SHALL use a version number of 0 (zero) to indicate that the Local Authorization List is empty. 24 | type GetLocalListVersionFeature struct{} 25 | 26 | func (f GetLocalListVersionFeature) GetFeatureName() string { 27 | return GetLocalListVersionFeatureName 28 | } 29 | 30 | func (f GetLocalListVersionFeature) GetRequestType() reflect.Type { 31 | return reflect.TypeOf(GetLocalListVersionRequest{}) 32 | } 33 | 34 | func (f GetLocalListVersionFeature) GetResponseType() reflect.Type { 35 | return reflect.TypeOf(GetLocalListVersionResponse{}) 36 | } 37 | 38 | func (r GetLocalListVersionRequest) GetFeatureName() string { 39 | return GetLocalListVersionFeatureName 40 | } 41 | 42 | func (c GetLocalListVersionResponse) GetFeatureName() string { 43 | return GetLocalListVersionFeatureName 44 | } 45 | 46 | // Creates a new GetLocalListVersionRequest, which doesn't contain any required or optional fields. 47 | func NewGetLocalListVersionRequest() *GetLocalListVersionRequest { 48 | return &GetLocalListVersionRequest{} 49 | } 50 | 51 | // Creates a new GetLocalListVersionResponse, containing all required fields. There are no optional fields for this message. 52 | func NewGetLocalListVersionResponse(version int) *GetLocalListVersionResponse { 53 | return &GetLocalListVersionResponse{VersionNumber: version} 54 | } 55 | -------------------------------------------------------------------------------- /ocpp2.0.1/localauth/local_auth_list.go: -------------------------------------------------------------------------------- 1 | // The Local authorization list functional block contains OCPP 2.0 features for synchronizing local authorization lists between CSMS and charging station. 2 | // Local lists are used for offline and generally optimized authorization. 3 | package localauth 4 | 5 | import "github.com/lorenzodonini/ocpp-go/ocpp" 6 | 7 | // Needs to be implemented by a CSMS for handling messages part of the OCPP 2.0 Local Authorization List profile. 8 | type CSMSHandler interface { 9 | } 10 | 11 | // Needs to be implemented by Charging stations for handling messages part of the OCPP 2.0 Local Authorization List profile. 12 | type ChargingStationHandler interface { 13 | // OnGetLocalListVersion is called on a charging station whenever a GetLocalListVersionRequest is received from the CSMS. 14 | OnGetLocalListVersion(request *GetLocalListVersionRequest) (response *GetLocalListVersionResponse, err error) 15 | // OnSendLocalList is called on a charging station whenever a SendLocalListRequest is received from the CSMS. 16 | OnSendLocalList(request *SendLocalListRequest) (response *SendLocalListResponse, err error) 17 | } 18 | 19 | const ProfileName = "localAuthList" 20 | 21 | var Profile = ocpp.NewProfile( 22 | ProfileName, 23 | GetLocalListVersionFeature{}, 24 | SendLocalListFeature{}, 25 | ) 26 | -------------------------------------------------------------------------------- /ocpp2.0.1/meter/meter.go: -------------------------------------------------------------------------------- 1 | // The Meter values functional block contains OCPP 2.0 features for sending meter values to the CSMS. 2 | package meter 3 | 4 | import "github.com/lorenzodonini/ocpp-go/ocpp" 5 | 6 | // Needs to be implemented by a CSMS for handling messages part of the OCPP 2.0 Meter values profile. 7 | type CSMSHandler interface { 8 | // OnMeterValues is called on the CSMS whenever a MeterValuesRequest is received from a charging station. 9 | OnMeterValues(chargingStationID string, request *MeterValuesRequest) (response *MeterValuesResponse, err error) 10 | } 11 | 12 | // Needs to be implemented by Charging stations for handling messages part of the OCPP 2.0 Meter values profile. 13 | type ChargingStationHandler interface { 14 | } 15 | 16 | const ProfileName = "meter" 17 | 18 | var Profile = ocpp.NewProfile( 19 | ProfileName, 20 | MeterValuesFeature{}, 21 | ) 22 | -------------------------------------------------------------------------------- /ocpp2.0.1/meter/meter_values.go: -------------------------------------------------------------------------------- 1 | package meter 2 | 3 | import ( 4 | "reflect" 5 | 6 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/types" 7 | ) 8 | 9 | // -------------------- Meter Values (CS -> CSMS) -------------------- 10 | 11 | const MeterValuesFeatureName = "MeterValues" 12 | 13 | // The field definition of the MeterValues request payload sent by the Charge Point to the Central System. 14 | type MeterValuesRequest struct { 15 | EvseID int `json:"evseId" validate:"gte=0"` // This contains a number (>0) designating an EVSE of the Charging Station. ‘0’ (zero) is used to designate the main power meter. 16 | MeterValue []types.MeterValue `json:"meterValue" validate:"required,min=1,dive"` 17 | } 18 | 19 | // This field definition of the Authorize confirmation payload, sent by the Charge Point to the Central System in response to an AuthorizeRequest. 20 | // In case the request was invalid, or couldn't be processed, an error will be sent instead. 21 | type MeterValuesResponse struct { 22 | } 23 | 24 | // The message is used to sample the electrical meter or other sensor/transducer hardware to provide information about the Charging Stations' Meter Values, outside of a transaction. 25 | // The Charging Station is configured to send Meter values every XX seconds. 26 | // 27 | // The Charging Station samples the electrical meter or other sensor/transducer hardware to provide information about its Meter Values. 28 | // Depending on configuration settings, the Charging Station MAY send a MeterValues request, for offloading Meter Values to the CSMS. 29 | // Upon receipt of a MeterValuesRequest message, the CSMS responds with a MeterValuesResponse message 30 | // 31 | // The MeterValuesRequest and MeterValuesResponse messages are deprecated in OCPP 2.0. 32 | // It is advised to start using Device Management Monitoring instead, see the diagnostics functional block. 33 | type MeterValuesFeature struct{} 34 | 35 | func (f MeterValuesFeature) GetFeatureName() string { 36 | return MeterValuesFeatureName 37 | } 38 | 39 | func (f MeterValuesFeature) GetRequestType() reflect.Type { 40 | return reflect.TypeOf(MeterValuesRequest{}) 41 | } 42 | 43 | func (f MeterValuesFeature) GetResponseType() reflect.Type { 44 | return reflect.TypeOf(MeterValuesResponse{}) 45 | } 46 | 47 | func (r MeterValuesRequest) GetFeatureName() string { 48 | return MeterValuesFeatureName 49 | } 50 | 51 | func (c MeterValuesResponse) GetFeatureName() string { 52 | return MeterValuesFeatureName 53 | } 54 | 55 | // Creates a new MeterValuesRequest, containing all required fields. Optional fields may be set afterwards. 56 | func NewMeterValuesRequest(evseID int, meterValues []types.MeterValue) *MeterValuesRequest { 57 | return &MeterValuesRequest{EvseID: evseID, MeterValue: meterValues} 58 | } 59 | 60 | // Creates a new MeterValuesResponse, which doesn't contain any required or optional fields. 61 | func NewMeterValuesResponse() *MeterValuesResponse { 62 | return &MeterValuesResponse{} 63 | } 64 | -------------------------------------------------------------------------------- /ocpp2.0.1/provisioning/provisioning.go: -------------------------------------------------------------------------------- 1 | // The provisioning functional block contains features that help a CSO to provision their Charging Stations, allowing them on their network and retrieving configuration information from these Charging Stations. 2 | // Additionally, it contains features for retrieving information about the configuration of Charging Stations, make changes to the configuration, resetting it etc. 3 | package provisioning 4 | 5 | import "github.com/lorenzodonini/ocpp-go/ocpp" 6 | 7 | // Needs to be implemented by a CSMS for handling messages part of the OCPP 2.0 Provisioning profile. 8 | type CSMSHandler interface { 9 | // OnBootNotification is called on the CSMS whenever a BootNotificationRequest is received from a charging station. 10 | OnBootNotification(chargingStationID string, request *BootNotificationRequest) (response *BootNotificationResponse, err error) 11 | // OnNotifyReport is called on the CSMS whenever a NotifyReportRequest is received from a charging station. 12 | OnNotifyReport(chargingStationID string, request *NotifyReportRequest) (response *NotifyReportResponse, err error) 13 | } 14 | 15 | // Needs to be implemented by Charging stations for handling messages part of the OCPP 2.0 Provisioning profile. 16 | type ChargingStationHandler interface { 17 | // OnGetBaseReport is called on a charging station whenever a GetBaseReportRequest is received from the CSMS. 18 | OnGetBaseReport(request *GetBaseReportRequest) (response *GetBaseReportResponse, err error) 19 | // OnGetReport is called on a charging station whenever a GetReportRequest is received from the CSMS. 20 | OnGetReport(request *GetReportRequest) (response *GetReportResponse, err error) 21 | // OnGetVariables is called on a charging station whenever a GetVariablesRequest is received from the CSMS. 22 | OnGetVariables(request *GetVariablesRequest) (response *GetVariablesResponse, err error) 23 | // OnReset is called on a charging station whenever a ResetRequest is received from the CSMS. 24 | OnReset(request *ResetRequest) (response *ResetResponse, err error) 25 | // OnSetNetworkProfile is called on a charging station whenever a SetNetworkProfileRequest is received from the CSMS. 26 | OnSetNetworkProfile(request *SetNetworkProfileRequest) (response *SetNetworkProfileResponse, err error) 27 | // OnSetVariables is called on a charging station whenever a SetVariablesRequest is received from the CSMS. 28 | OnSetVariables(request *SetVariablesRequest) (response *SetVariablesResponse, err error) 29 | } 30 | 31 | const ProfileName = "provisioning" 32 | 33 | var Profile = ocpp.NewProfile( 34 | ProfileName, 35 | BootNotificationFeature{}, 36 | GetBaseReportFeature{}, 37 | GetReportFeature{}, 38 | GetVariablesFeature{}, 39 | NotifyReportFeature{}, 40 | ResetFeature{}, 41 | SetNetworkProfileFeature{}, 42 | SetVariablesFeature{}, 43 | ) 44 | -------------------------------------------------------------------------------- /ocpp2.0.1/remotecontrol/remote_control.go: -------------------------------------------------------------------------------- 1 | // The Remote control functional block contains OCPP 2.0 features for remote-control management from the CSMS. 2 | package remotecontrol 3 | 4 | import "github.com/lorenzodonini/ocpp-go/ocpp" 5 | 6 | // Needs to be implemented by a CSMS for handling messages part of the OCPP 2.0 Remote control profile. 7 | type CSMSHandler interface { 8 | } 9 | 10 | // Needs to be implemented by Charging stations for handling messages part of the OCPP 2.0 Remote control profile. 11 | type ChargingStationHandler interface { 12 | // OnRequestStartTransaction is called on a charging station whenever a RequestStartTransactionRequest is received from the CSMS. 13 | OnRequestStartTransaction(request *RequestStartTransactionRequest) (response *RequestStartTransactionResponse, err error) 14 | // OnRequestStopTransaction is called on a charging station whenever a RequestStopTransactionRequest is received from the CSMS. 15 | OnRequestStopTransaction(request *RequestStopTransactionRequest) (response *RequestStopTransactionResponse, err error) 16 | // OnTriggerMessage is called on a charging station whenever a TriggerMessageRequest is received from the CSMS. 17 | OnTriggerMessage(request *TriggerMessageRequest) (response *TriggerMessageResponse, err error) 18 | // OnUnlockConnector is called on a charging station whenever a UnlockConnectorRequest is received from the CSMS. 19 | OnUnlockConnector(request *UnlockConnectorRequest) (response *UnlockConnectorResponse, err error) 20 | } 21 | 22 | const ProfileName = "remoteControl" 23 | 24 | var Profile = ocpp.NewProfile( 25 | ProfileName, 26 | RequestStartTransactionFeature{}, 27 | RequestStopTransactionFeature{}, 28 | TriggerMessageFeature{}, 29 | UnlockConnectorFeature{}, 30 | ) 31 | -------------------------------------------------------------------------------- /ocpp2.0.1/remotecontrol/request_stop_transaction.go: -------------------------------------------------------------------------------- 1 | package remotecontrol 2 | 3 | import ( 4 | "reflect" 5 | 6 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/types" 7 | ) 8 | 9 | // -------------------- Request Start Transaction (CSMS -> CS) -------------------- 10 | 11 | const RequestStopTransactionFeatureName = "RequestStopTransaction" 12 | 13 | // The field definition of the RequestStopTransaction request payload sent by the CSMS to the Charging Station. 14 | type RequestStopTransactionRequest struct { 15 | TransactionID string `json:"transactionId" validate:"required,max=36"` 16 | } 17 | 18 | // This field definition of the RequestStopTransaction response payload, sent by the Charging Station to the CSMS in response to a RequestStopTransactionRequest. 19 | // In case the request was invalid, or couldn't be processed, an error will be sent instead. 20 | type RequestStopTransactionResponse struct { 21 | Status RequestStartStopStatus `json:"status" validate:"required,requestStartStopStatus"` 22 | StatusInfo *types.StatusInfo `json:"statusInfo,omitempty"` 23 | } 24 | 25 | // The CSMS may remotely stop an ongoing transaction for a user. 26 | // This functionality may be triggered by: 27 | // - a CSO, to help out a user, that is having trouble stopping a transaction 28 | // - a third-party event (e.g. mobile app) 29 | // - the ISO15118-1 use-case F2 30 | // 31 | // The CSMS sends a RequestStopTransactionRequest to the Charging Station. 32 | // The Charging Stations will reply with a RequestStopTransactionResponse. 33 | type RequestStopTransactionFeature struct{} 34 | 35 | func (f RequestStopTransactionFeature) GetFeatureName() string { 36 | return RequestStopTransactionFeatureName 37 | } 38 | 39 | func (f RequestStopTransactionFeature) GetRequestType() reflect.Type { 40 | return reflect.TypeOf(RequestStopTransactionRequest{}) 41 | } 42 | 43 | func (f RequestStopTransactionFeature) GetResponseType() reflect.Type { 44 | return reflect.TypeOf(RequestStopTransactionResponse{}) 45 | } 46 | 47 | func (r RequestStopTransactionRequest) GetFeatureName() string { 48 | return RequestStopTransactionFeatureName 49 | } 50 | 51 | func (c RequestStopTransactionResponse) GetFeatureName() string { 52 | return RequestStopTransactionFeatureName 53 | } 54 | 55 | // Creates a new RequestStopTransactionRequest, containing all required fields. There are no optional fields for this message. 56 | func NewRequestStopTransactionRequest(transactionID string) *RequestStopTransactionRequest { 57 | return &RequestStopTransactionRequest{TransactionID: transactionID} 58 | } 59 | 60 | // Creates a new RequestStopTransactionResponse, containing all required fields. Optional fields may be set afterwards. 61 | func NewRequestStopTransactionResponse(status RequestStartStopStatus) *RequestStopTransactionResponse { 62 | return &RequestStopTransactionResponse{Status: status} 63 | } 64 | -------------------------------------------------------------------------------- /ocpp2.0.1/reservation/reservation.go: -------------------------------------------------------------------------------- 1 | // The reservation functional block contains OCPP 2.0 features that enable EV drivers to make and manage reservations of charging stations. 2 | package reservation 3 | 4 | import ( 5 | "github.com/lorenzodonini/ocpp-go/ocpp" 6 | ) 7 | 8 | // Needs to be implemented by a CSMS for handling messages part of the OCPP 2.0 Reservation profile. 9 | type CSMSHandler interface { 10 | // OnReservationStatusUpdate is called on the CSMS whenever a ReservationStatusUpdateRequest is received from a charging station. 11 | OnReservationStatusUpdate(chargingStationID string, request *ReservationStatusUpdateRequest) (resp *ReservationStatusUpdateResponse, err error) 12 | } 13 | 14 | // Needs to be implemented by Charging stations for handling messages part of the OCPP 2.0 Reservation profile. 15 | type ChargingStationHandler interface { 16 | // OnCancelReservation is called on a charging station whenever a CancelReservationRequest is received from the CSMS. 17 | OnCancelReservation(request *CancelReservationRequest) (resp *CancelReservationResponse, err error) 18 | // OnReserveNow is called on a charging station whenever a ReserveNowRequest is received from the CSMS. 19 | OnReserveNow(request *ReserveNowRequest) (resp *ReserveNowResponse, err error) 20 | } 21 | 22 | const ProfileName = "reservation" 23 | 24 | var Profile = ocpp.NewProfile( 25 | ProfileName, 26 | CancelReservationFeature{}, 27 | ReservationStatusUpdateFeature{}, 28 | ReserveNowFeature{}, 29 | ) 30 | -------------------------------------------------------------------------------- /ocpp2.0.1/security/security.go: -------------------------------------------------------------------------------- 1 | // The security functional block contains OCPP 2.0 features aimed at providing E2E security between a CSMS and a Charging station. 2 | package security 3 | 4 | import "github.com/lorenzodonini/ocpp-go/ocpp" 5 | 6 | // Needs to be implemented by a CSMS for handling messages part of the OCPP 2.0 Security profile. 7 | type CSMSHandler interface { 8 | // OnSecurityEventNotification is called on the CSMS whenever a SecurityEventNotificationRequest is received from a charging station. 9 | OnSecurityEventNotification(chargingStationID string, request *SecurityEventNotificationRequest) (response *SecurityEventNotificationResponse, err error) 10 | // OnSignCertificate is called on the CSMS whenever a SignCertificateRequest is received from a charging station. 11 | OnSignCertificate(chargingStationID string, request *SignCertificateRequest) (response *SignCertificateResponse, err error) 12 | } 13 | 14 | // Needs to be implemented by Charging stations for handling messages part of the OCPP 2.0 Security profile. 15 | type ChargingStationHandler interface { 16 | // OnCertificateSigned is called on a charging station whenever a CertificateSignedRequest is received from the CSMS. 17 | OnCertificateSigned(request *CertificateSignedRequest) (response *CertificateSignedResponse, err error) 18 | } 19 | 20 | const ProfileName = "security" 21 | 22 | var Profile = ocpp.NewProfile( 23 | ProfileName, 24 | CertificateSignedFeature{}, 25 | SecurityEventNotificationFeature{}, 26 | SignCertificateFeature{}, 27 | ) 28 | -------------------------------------------------------------------------------- /ocpp2.0.1/security/security_event_notification.go: -------------------------------------------------------------------------------- 1 | package security 2 | 3 | import ( 4 | "reflect" 5 | 6 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/types" 7 | ) 8 | 9 | // -------------------- Security Event Notification Status (CS -> CSMS) -------------------- 10 | 11 | const SecurityEventNotificationFeatureName = "SecurityEventNotification" 12 | 13 | // The field definition of the SecurityEventNotification request payload sent by the Charging Station to the CSMS. 14 | type SecurityEventNotificationRequest struct { 15 | Type string `json:"type" validate:"required,max=50"` // Type of the security event. This value should be taken from the Security events list. 16 | Timestamp *types.DateTime `json:"timestamp" validate:"required"` // Date and time at which the event occurred. 17 | TechInfo string `json:"techInfo,omitempty" validate:"omitempty,max=255"` // Additional information about the occurred security event. 18 | } 19 | 20 | // This field definition of the SecurityEventNotification response payload, sent by the CSMS to the Charging Station in response to a SecurityEventNotificationRequest. 21 | // In case the request was invalid, or couldn't be processed, an error will be sent instead. 22 | type SecurityEventNotificationResponse struct { 23 | } 24 | 25 | // In case of critical security events, a Charging Station may immediately inform the CSMS of such events, 26 | // via a SecurityEventNotificationRequest. 27 | // The CSMS responds with a SecurityEventNotificationResponse to the Charging Station. 28 | type SecurityEventNotificationFeature struct{} 29 | 30 | func (f SecurityEventNotificationFeature) GetFeatureName() string { 31 | return SecurityEventNotificationFeatureName 32 | } 33 | 34 | func (f SecurityEventNotificationFeature) GetRequestType() reflect.Type { 35 | return reflect.TypeOf(SecurityEventNotificationRequest{}) 36 | } 37 | 38 | func (f SecurityEventNotificationFeature) GetResponseType() reflect.Type { 39 | return reflect.TypeOf(SecurityEventNotificationResponse{}) 40 | } 41 | 42 | func (r SecurityEventNotificationRequest) GetFeatureName() string { 43 | return SecurityEventNotificationFeatureName 44 | } 45 | 46 | func (c SecurityEventNotificationResponse) GetFeatureName() string { 47 | return SecurityEventNotificationFeatureName 48 | } 49 | 50 | // Creates a new SecurityEventNotificationRequest, containing all required fields. Optional fields may be set afterwards. 51 | func NewSecurityEventNotificationRequest(typ string, timestamp *types.DateTime) *SecurityEventNotificationRequest { 52 | return &SecurityEventNotificationRequest{Type: typ, Timestamp: timestamp} 53 | } 54 | 55 | // Creates a new SecurityEventNotificationResponse, which doesn't contain any required or optional fields. 56 | func NewSecurityEventNotificationResponse() *SecurityEventNotificationResponse { 57 | return &SecurityEventNotificationResponse{} 58 | } 59 | -------------------------------------------------------------------------------- /ocpp2.0.1/security/sign_certificate.go: -------------------------------------------------------------------------------- 1 | package security 2 | 3 | import ( 4 | "reflect" 5 | 6 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/types" 7 | ) 8 | 9 | // -------------------- Sign Certificate (CS -> CSMS) -------------------- 10 | 11 | const SignCertificateFeatureName = "SignCertificate" 12 | 13 | // The field definition of the SignCertificate request payload sent by the Charging Station to the CSMS. 14 | type SignCertificateRequest struct { 15 | CSR string `json:"csr" validate:"required,max=5500"` // The Charging Station SHALL send the public key in form of a Certificate Signing Request (CSR) as described in RFC 2986 and then PEM encoded. 16 | CertificateType types.CertificateSigningUse `json:"certificateType,omitempty" validate:"omitempty,certificateSigningUse"` // Indicates the type of certificate that is to be signed. 17 | } 18 | 19 | // This field definition of the SignCertificate response payload, sent by the CSMS to the Charging Station in response to a SignCertificateRequest. 20 | // In case the request was invalid, or couldn't be processed, an error will be sent instead. 21 | type SignCertificateResponse struct { 22 | Status types.GenericStatus `json:"status" validate:"required,genericStatus"` // Specifies whether the CSMS can process the request. 23 | StatusInfo *types.StatusInfo `json:"statusInfo,omitempty" validate:"omitempty"` // Detailed status information. 24 | } 25 | 26 | // If a Charging Station detected, that its certificate is due to expire, it will generate a new public/private key pair, 27 | // then send a SignCertificateRequest to the CSMS containing a valid Certificate Signing Request. 28 | // 29 | // The CSMS responds with a SignCertificateResponse and will then forward the CSR to a CA server. 30 | // Once the CA has issues a valid certificate, the CSMS will send a CertificateSignedRequest to the 31 | // charging station (asynchronously). 32 | type SignCertificateFeature struct{} 33 | 34 | func (f SignCertificateFeature) GetFeatureName() string { 35 | return SignCertificateFeatureName 36 | } 37 | 38 | func (f SignCertificateFeature) GetRequestType() reflect.Type { 39 | return reflect.TypeOf(SignCertificateRequest{}) 40 | } 41 | 42 | func (f SignCertificateFeature) GetResponseType() reflect.Type { 43 | return reflect.TypeOf(SignCertificateResponse{}) 44 | } 45 | 46 | func (r SignCertificateRequest) GetFeatureName() string { 47 | return SignCertificateFeatureName 48 | } 49 | 50 | func (c SignCertificateResponse) GetFeatureName() string { 51 | return SignCertificateFeatureName 52 | } 53 | 54 | // Creates a new SignCertificateRequest, containing all required fields. Optional fields may be set afterwards. 55 | func NewSignCertificateRequest(csr string) *SignCertificateRequest { 56 | return &SignCertificateRequest{CSR: csr} 57 | } 58 | 59 | // Creates a new SignCertificateResponse, containing all required fields. Optional fields may be set afterwards. 60 | func NewSignCertificateResponse(status types.GenericStatus) *SignCertificateResponse { 61 | return &SignCertificateResponse{Status: status} 62 | } 63 | -------------------------------------------------------------------------------- /ocpp2.0.1/smartcharging/cleared_charging_limit.go: -------------------------------------------------------------------------------- 1 | package smartcharging 2 | 3 | import ( 4 | "reflect" 5 | 6 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/types" 7 | ) 8 | 9 | // -------------------- Cleared Charging Limit (CS -> CSMS) -------------------- 10 | 11 | const ClearedChargingLimitFeatureName = "ClearedChargingLimit" 12 | 13 | // The field definition of the ClearedChargingLimit request payload sent by the Charging Station to the CSMS. 14 | type ClearedChargingLimitRequest struct { 15 | ChargingLimitSource types.ChargingLimitSourceType `json:"chargingLimitSource" validate:"required,chargingLimitSource"` 16 | EvseID *int `json:"evseId,omitempty" validate:"omitempty,gte=0"` 17 | } 18 | 19 | // This field definition of the ClearedChargingLimit response payload, sent by the CSMS to the Charging Station in response to a ClearedChargingLimitRequest. 20 | // In case the request was invalid, or couldn't be processed, an error will be sent instead. 21 | type ClearedChargingLimitResponse struct { 22 | } 23 | 24 | // When an external control system sends a signal to release a previously imposed charging limit to a Charging Station, 25 | // the Charging Station sends a ClearedChargingLimitRequest to notify the CSMS about this. 26 | // The CSMS acknowledges with a ClearedChargingLimitResponse to the Charging Station. 27 | // When the change has impact on an ongoing charging transaction and is more than: LimitChangeSignificance, 28 | // the Charging Station needs to send a TransactionEventRequest to notify the CSMS. 29 | type ClearedChargingLimitFeature struct{} 30 | 31 | func (f ClearedChargingLimitFeature) GetFeatureName() string { 32 | return ClearedChargingLimitFeatureName 33 | } 34 | 35 | func (f ClearedChargingLimitFeature) GetRequestType() reflect.Type { 36 | return reflect.TypeOf(ClearedChargingLimitRequest{}) 37 | } 38 | 39 | func (f ClearedChargingLimitFeature) GetResponseType() reflect.Type { 40 | return reflect.TypeOf(ClearedChargingLimitResponse{}) 41 | } 42 | 43 | func (r ClearedChargingLimitRequest) GetFeatureName() string { 44 | return ClearedChargingLimitFeatureName 45 | } 46 | 47 | func (c ClearedChargingLimitResponse) GetFeatureName() string { 48 | return ClearedChargingLimitFeatureName 49 | } 50 | 51 | // Creates a new ClearedChargingLimitRequest, containing all required fields. Optional fields may be set afterwards. 52 | func NewClearedChargingLimitRequest(chargingLimitSource types.ChargingLimitSourceType) *ClearedChargingLimitRequest { 53 | return &ClearedChargingLimitRequest{ChargingLimitSource: chargingLimitSource} 54 | } 55 | 56 | // Creates a new ClearedChargingLimitResponse, which doesn't contain any required or optional fields. 57 | func NewClearedChargingLimitResponse() *ClearedChargingLimitResponse { 58 | return &ClearedChargingLimitResponse{} 59 | } 60 | -------------------------------------------------------------------------------- /ocpp2.0.1/smartcharging/notify_ev_charging_schedule.go: -------------------------------------------------------------------------------- 1 | package smartcharging 2 | 3 | import ( 4 | "reflect" 5 | 6 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/types" 7 | ) 8 | 9 | // -------------------- Notify EV Charging Schedule (CS -> CSMS) -------------------- 10 | 11 | const NotifyEVChargingScheduleFeatureName = "NotifyEVChargingSchedule" 12 | 13 | // The field definition of the NotifyEVChargingSchedule request payload sent by the Charging Station to the CSMS. 14 | type NotifyEVChargingScheduleRequest struct { 15 | TimeBase *types.DateTime `json:"timeBase" validate:"required"` 16 | EvseID int `json:"evseId" validate:"gt=0"` 17 | ChargingSchedule types.ChargingSchedule `json:"chargingSchedule" validate:"required,dive"` 18 | } 19 | 20 | // This field definition of the NotifyEVChargingSchedule response payload, sent by the CSMS to the Charging Station in response to a NotifyEVChargingScheduleRequest. 21 | // In case the request was invalid, or couldn't be processed, an error will be sent instead. 22 | type NotifyEVChargingScheduleResponse struct { 23 | Status types.GenericStatus `json:"status" validate:"required,genericStatus"` 24 | StatusInfo *types.StatusInfo `json:"statusInfo,omitempty" validate:"omitempty,dive"` // Detailed status information. 25 | } 26 | 27 | // A power renegotiation, either initiated by the EV or by the CSMS, may involve the EV providing a power profile. 28 | // If a charging profile was provided, after receiving a PowerDeliveryResponse from the CSMS, 29 | // the Charging Station will send a NotifyEVChargingScheduleRequest to the CSMS. 30 | // 31 | // The CSMS replies to the Charging Station with a NotifyEVChargingScheduleResponse. 32 | type NotifyEVChargingScheduleFeature struct{} 33 | 34 | func (f NotifyEVChargingScheduleFeature) GetFeatureName() string { 35 | return NotifyEVChargingScheduleFeatureName 36 | } 37 | 38 | func (f NotifyEVChargingScheduleFeature) GetRequestType() reflect.Type { 39 | return reflect.TypeOf(NotifyEVChargingScheduleRequest{}) 40 | } 41 | 42 | func (f NotifyEVChargingScheduleFeature) GetResponseType() reflect.Type { 43 | return reflect.TypeOf(NotifyEVChargingScheduleResponse{}) 44 | } 45 | 46 | func (r NotifyEVChargingScheduleRequest) GetFeatureName() string { 47 | return NotifyEVChargingScheduleFeatureName 48 | } 49 | 50 | func (c NotifyEVChargingScheduleResponse) GetFeatureName() string { 51 | return NotifyEVChargingScheduleFeatureName 52 | } 53 | 54 | // Creates a new NotifyEVChargingScheduleRequest, containing all required fields. Optional fields may be set afterwards. 55 | func NewNotifyEVChargingScheduleRequest(timeBase *types.DateTime, evseID int, chargingSchedule types.ChargingSchedule) *NotifyEVChargingScheduleRequest { 56 | return &NotifyEVChargingScheduleRequest{TimeBase: timeBase, EvseID: evseID, ChargingSchedule: chargingSchedule} 57 | } 58 | 59 | // Creates a new NotifyEVChargingScheduleResponse, containing all required fields. Optional fields may be set afterwards. 60 | func NewNotifyEVChargingScheduleResponse(status types.GenericStatus) *NotifyEVChargingScheduleResponse { 61 | return &NotifyEVChargingScheduleResponse{Status: status} 62 | } 63 | -------------------------------------------------------------------------------- /ocpp2.0.1/tariffcost/cost_updated.go: -------------------------------------------------------------------------------- 1 | package tariffcost 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | // -------------------- Cost Updated (CSMS -> CS) -------------------- 8 | 9 | const CostUpdatedFeatureName = "CostUpdated" 10 | 11 | // The field definition of the CostUpdated request payload sent by the CSMS to the Charging Station. 12 | type CostUpdatedRequest struct { 13 | TotalCost float64 `json:"totalCost" validate:"required"` 14 | TransactionID string `json:"transactionId" validate:"required,max=36"` 15 | } 16 | 17 | // This field definition of the CostUpdated response payload, sent by the Charging Station to the CSMS in response to a CostUpdatedRequest. 18 | // In case the request was invalid, or couldn't be processed, an error will be sent instead. 19 | type CostUpdatedResponse struct { 20 | } 21 | 22 | // The driver wants to know how much the running total cost is, updated at a relevant interval, while a transaction is ongoing. 23 | // To fulfill this requirement, the CSMS sends a CostUpdatedRequest to the Charging Station to update the current total cost, every Y seconds. 24 | // Upon receipt of the CostUpdatedRequest, the Charging Station responds with a CostUpdatedResponse, then shows the updated cost to the driver. 25 | type CostUpdatedFeature struct{} 26 | 27 | func (f CostUpdatedFeature) GetFeatureName() string { 28 | return CostUpdatedFeatureName 29 | } 30 | 31 | func (f CostUpdatedFeature) GetRequestType() reflect.Type { 32 | return reflect.TypeOf(CostUpdatedRequest{}) 33 | } 34 | 35 | func (f CostUpdatedFeature) GetResponseType() reflect.Type { 36 | return reflect.TypeOf(CostUpdatedResponse{}) 37 | } 38 | 39 | func (r CostUpdatedRequest) GetFeatureName() string { 40 | return CostUpdatedFeatureName 41 | } 42 | 43 | func (c CostUpdatedResponse) GetFeatureName() string { 44 | return CostUpdatedFeatureName 45 | } 46 | 47 | // Creates a new CostUpdatedRequest, containing all required fields. There are no optional fields for this message. 48 | func NewCostUpdatedRequest(totalCost float64, transactionID string) *CostUpdatedRequest { 49 | return &CostUpdatedRequest{TotalCost: totalCost, TransactionID: transactionID} 50 | } 51 | 52 | // Creates a new CostUpdatedResponse, which doesn't contain any required or optional fields. 53 | func NewCostUpdatedResponse() *CostUpdatedResponse { 54 | return &CostUpdatedResponse{} 55 | } 56 | -------------------------------------------------------------------------------- /ocpp2.0.1/tariffcost/tariff_cost.go: -------------------------------------------------------------------------------- 1 | // The authorization functional block contains OCPP 2.0 features that show tariff and costs to an EV driver, when supported by the charging station. 2 | package tariffcost 3 | 4 | import "github.com/lorenzodonini/ocpp-go/ocpp" 5 | 6 | // Needs to be implemented by a CSMS for handling messages part of the OCPP 2.0 Tariff and cost profile. 7 | type CSMSHandler interface { 8 | } 9 | 10 | // Needs to be implemented by Charging stations for handling messages part of the OCPP 2.0 Tariff and cost profile. 11 | type ChargingStationHandler interface { 12 | // OnCostUpdated is called on a charging station whenever a CostUpdatedRequest is received from the CSMS. 13 | OnCostUpdated(request *CostUpdatedRequest) (confirmation *CostUpdatedResponse, err error) 14 | } 15 | 16 | const ProfileName = "tariffCost" 17 | 18 | var Profile = ocpp.NewProfile( 19 | ProfileName, 20 | CostUpdatedFeature{}, 21 | ) 22 | -------------------------------------------------------------------------------- /ocpp2.0.1/transactions/get_transaction_status.go: -------------------------------------------------------------------------------- 1 | package transactions 2 | 3 | import ( 4 | "reflect" 5 | ) 6 | 7 | // -------------------- Clear Cache (CSMS -> CS) -------------------- 8 | 9 | const GetTransactionStatusFeatureName = "GetTransactionStatus" 10 | 11 | // The field definition of the GetTransactionStatus request payload sent by the CSMS to the Charging Station. 12 | type GetTransactionStatusRequest struct { 13 | TransactionID string `json:"transactionId,omitempty" validate:"omitempty,max=36"` 14 | } 15 | 16 | // This field definition of the GetTransactionStatus response payload, sent by the Charging Station to the CSMS in response to a GetTransactionStatusRequest. 17 | // In case the request was invalid, or couldn't be processed, an error will be sent instead. 18 | type GetTransactionStatusResponse struct { 19 | OngoingIndicator *bool `json:"ongoingIndicator,omitempty" validate:"omitempty"` 20 | MessagesInQueue bool `json:"messagesInQueue"` 21 | } 22 | 23 | // In some scenarios a CSMS needs to know whether there are still messages for a transaction that need to be delivered. 24 | // The CSMS shall ask if the Charging Station has still messages in the queue for this transaction with the GetTransactionStatusRequest. 25 | // It may optionally specify a transactionId, to know if a transaction is still ongoing. 26 | // Upon receiving a GetTransactionStatusRequest, the Charging Station shall respond with a GetTransactionStatusResponse payload. 27 | type GetTransactionStatusFeature struct{} 28 | 29 | func (f GetTransactionStatusFeature) GetFeatureName() string { 30 | return GetTransactionStatusFeatureName 31 | } 32 | 33 | func (f GetTransactionStatusFeature) GetRequestType() reflect.Type { 34 | return reflect.TypeOf(GetTransactionStatusRequest{}) 35 | } 36 | 37 | func (f GetTransactionStatusFeature) GetResponseType() reflect.Type { 38 | return reflect.TypeOf(GetTransactionStatusResponse{}) 39 | } 40 | 41 | func (r GetTransactionStatusRequest) GetFeatureName() string { 42 | return GetTransactionStatusFeatureName 43 | } 44 | 45 | func (c GetTransactionStatusResponse) GetFeatureName() string { 46 | return GetTransactionStatusFeatureName 47 | } 48 | 49 | // Creates a new GetTransactionStatusRequest, which doesn't contain any required or optional fields. 50 | func NewGetTransactionStatusRequest() *GetTransactionStatusRequest { 51 | return &GetTransactionStatusRequest{} 52 | } 53 | 54 | // Creates a new GetTransactionStatusResponse, containing all required fields. There are no optional fields for this message. 55 | func NewGetTransactionStatusResponse(messagesInQueue bool) *GetTransactionStatusResponse { 56 | return &GetTransactionStatusResponse{MessagesInQueue: messagesInQueue} 57 | } 58 | -------------------------------------------------------------------------------- /ocpp2.0.1/transactions/transactions.go: -------------------------------------------------------------------------------- 1 | // The transactions functional block contains OCPP 2.0 features related to OCPP transactions. 2 | package transactions 3 | 4 | import "github.com/lorenzodonini/ocpp-go/ocpp" 5 | 6 | // Needs to be implemented by a CSMS for handling messages part of the OCPP 2.0 Transactions profile. 7 | type CSMSHandler interface { 8 | // OnTransactionEvent is called on the CSMS whenever a TransactionEventRequest is received from a charging station. 9 | OnTransactionEvent(chargingStationID string, request *TransactionEventRequest) (response *TransactionEventResponse, err error) 10 | } 11 | 12 | // Needs to be implemented by Charging stations for handling messages part of the OCPP 2.0 Transactions profile. 13 | type ChargingStationHandler interface { 14 | // OnGetTransactionStatusResponse is called on a charging station whenever a OnGetTransactionStatusRequest is received from the CSMS. 15 | OnGetTransactionStatus(request *GetTransactionStatusRequest) (response *GetTransactionStatusResponse, err error) 16 | } 17 | 18 | const ProfileName = "transactions" 19 | 20 | var Profile = ocpp.NewProfile( 21 | ProfileName, 22 | GetTransactionStatusFeature{}, 23 | TransactionEventFeature{}, 24 | ) 25 | -------------------------------------------------------------------------------- /ocpp2.0.1/types/datetime.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "encoding/json" 5 | "errors" 6 | "time" 7 | 8 | "github.com/relvacode/iso8601" 9 | ) 10 | 11 | // DateTimeFormat to be used when serializing all OCPP messages. 12 | // 13 | // The default dateTime format is RFC3339. 14 | // Change this if another format is desired. 15 | var DateTimeFormat = time.RFC3339 16 | 17 | // DateTime wraps a time.Time struct, allowing for improved dateTime JSON compatibility. 18 | type DateTime struct { 19 | time.Time 20 | } 21 | 22 | // Creates a new DateTime struct, embedding a time.Time struct. 23 | func NewDateTime(time time.Time) *DateTime { 24 | return &DateTime{Time: time} 25 | } 26 | 27 | // Creates a new DateTime struct, containing a time.Now() value. 28 | func Now() *DateTime { 29 | return &DateTime{Time: time.Now()} 30 | } 31 | 32 | func null(b []byte) bool { 33 | if len(b) != 4 { 34 | return false 35 | } 36 | if b[0] != 'n' && b[1] != 'u' && b[2] != 'l' && b[3] != 'l' { 37 | return false 38 | } 39 | return true 40 | } 41 | 42 | func (dt *DateTime) UnmarshalJSON(input []byte) error { 43 | // Do not parse null timestamps 44 | if null(input) { 45 | return nil 46 | } 47 | // Assert that timestamp is a string 48 | if len(input) > 0 && input[0] == '"' && input[len(input)-1] == '"' { 49 | input = input[1 : len(input)-1] 50 | } else { 51 | return errors.New("timestamp not enclosed in double quotes") 52 | } 53 | // Parse ISO8601 54 | var err error 55 | dt.Time, err = iso8601.Parse(input) 56 | return err 57 | } 58 | 59 | func (dt *DateTime) MarshalJSON() ([]byte, error) { 60 | if DateTimeFormat == "" { 61 | return json.Marshal(dt.Time) 62 | } 63 | timeStr := dt.FormatTimestamp() 64 | return json.Marshal(timeStr) 65 | } 66 | 67 | // Formats the UTC timestamp using the DateTimeFormat setting. 68 | // This function is used during JSON marshaling as well. 69 | func (dt *DateTime) FormatTimestamp() string { 70 | return dt.UTC().Format(DateTimeFormat) 71 | } 72 | 73 | func FormatTimestamp(t time.Time) string { 74 | return t.UTC().Format(DateTimeFormat) 75 | } 76 | 77 | // DateTime Validation 78 | 79 | func DateTimeIsNull(dateTime *DateTime) bool { 80 | return dateTime != nil && dateTime.IsZero() 81 | } 82 | -------------------------------------------------------------------------------- /ocpp2.0.1_test/get_local_list_version_test.go: -------------------------------------------------------------------------------- 1 | package ocpp2_test 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/stretchr/testify/assert" 7 | "github.com/stretchr/testify/mock" 8 | "github.com/stretchr/testify/require" 9 | 10 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/localauth" 11 | ) 12 | 13 | // Test 14 | func (suite *OcppV2TestSuite) TestGetLocalListVersionRequestValidation() { 15 | t := suite.T() 16 | var requestTable = []GenericTestEntry{ 17 | {localauth.GetLocalListVersionRequest{}, true}, 18 | } 19 | ExecuteGenericTestTable(t, requestTable) 20 | } 21 | 22 | func (suite *OcppV2TestSuite) TestGetLocalListVersionConfirmationValidation() { 23 | t := suite.T() 24 | var confirmationTable = []GenericTestEntry{ 25 | {localauth.GetLocalListVersionResponse{VersionNumber: 1}, true}, 26 | {localauth.GetLocalListVersionResponse{VersionNumber: 0}, true}, 27 | {localauth.GetLocalListVersionResponse{}, true}, 28 | {localauth.GetLocalListVersionResponse{VersionNumber: -1}, false}, 29 | } 30 | ExecuteGenericTestTable(t, confirmationTable) 31 | } 32 | 33 | func (suite *OcppV2TestSuite) TestGetLocalListVersionE2EMocked() { 34 | t := suite.T() 35 | wsId := "test_id" 36 | messageId := defaultMessageId 37 | wsUrl := "someUrl" 38 | listVersion := 1 39 | requestJson := fmt.Sprintf(`[2,"%v","%v",{}]`, messageId, localauth.GetLocalListVersionFeatureName) 40 | responseJson := fmt.Sprintf(`[3,"%v",{"versionNumber":%v}]`, messageId, listVersion) 41 | localListVersionConfirmation := localauth.NewGetLocalListVersionResponse(listVersion) 42 | channel := NewMockWebSocket(wsId) 43 | 44 | handler := &MockChargingStationLocalAuthHandler{} 45 | handler.On("OnGetLocalListVersion", mock.Anything).Return(localListVersionConfirmation, nil) 46 | setupDefaultCSMSHandlers(suite, expectedCSMSOptions{clientId: wsId, rawWrittenMessage: []byte(requestJson), forwardWrittenMessage: true}) 47 | setupDefaultChargingStationHandlers(suite, expectedChargingStationOptions{serverUrl: wsUrl, clientId: wsId, createChannelOnStart: true, channel: channel, rawWrittenMessage: []byte(responseJson), forwardWrittenMessage: true}, handler) 48 | // Run Test 49 | suite.csms.Start(8887, "somePath") 50 | err := suite.chargingStation.Start(wsUrl) 51 | assert.Nil(t, err) 52 | resultChannel := make(chan bool, 1) 53 | err = suite.csms.GetLocalListVersion(wsId, func(confirmation *localauth.GetLocalListVersionResponse, err error) { 54 | assert.Nil(t, err) 55 | require.NotNil(t, confirmation) 56 | assert.Equal(t, listVersion, confirmation.VersionNumber) 57 | resultChannel <- true 58 | }) 59 | assert.Nil(t, err) 60 | if err == nil { 61 | result := <-resultChannel 62 | assert.True(t, result) 63 | } 64 | } 65 | 66 | func (suite *OcppV2TestSuite) TestGetLocalListVersionInvalidEndpoint() { 67 | messageId := defaultMessageId 68 | localListVersionRequest := localauth.NewGetLocalListVersionRequest() 69 | requestJson := fmt.Sprintf(`[2,"%v","%v",{}]`, messageId, localauth.GetLocalListVersionFeatureName) 70 | testUnsupportedRequestFromChargingStation(suite, localListVersionRequest, requestJson, messageId) 71 | } 72 | -------------------------------------------------------------------------------- /ocpp2.0.1_test/heartbeat_test.go: -------------------------------------------------------------------------------- 1 | package ocpp2_test 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "github.com/stretchr/testify/mock" 9 | "github.com/stretchr/testify/require" 10 | 11 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/availability" 12 | "github.com/lorenzodonini/ocpp-go/ocpp2.0.1/types" 13 | ) 14 | 15 | // Test 16 | func (suite *OcppV2TestSuite) TestHeartbeatRequestValidation() { 17 | t := suite.T() 18 | var requestTable = []GenericTestEntry{ 19 | {availability.HeartbeatRequest{}, true}, 20 | } 21 | ExecuteGenericTestTable(t, requestTable) 22 | } 23 | 24 | func (suite *OcppV2TestSuite) TestHeartbeatResponseValidation() { 25 | t := suite.T() 26 | var confirmationTable = []GenericTestEntry{ 27 | {availability.HeartbeatResponse{CurrentTime: *types.NewDateTime(time.Now())}, true}, 28 | {availability.HeartbeatResponse{}, false}, 29 | } 30 | ExecuteGenericTestTable(t, confirmationTable) 31 | } 32 | 33 | func (suite *OcppV2TestSuite) TestHeartbeatE2EMocked() { 34 | t := suite.T() 35 | wsId := "test_id" 36 | messageId := defaultMessageId 37 | wsUrl := "someUrl" 38 | currentTime := types.NewDateTime(time.Now()) 39 | requestJson := fmt.Sprintf(`[2,"%v","%v",{}]`, messageId, availability.HeartbeatFeatureName) 40 | responseJson := fmt.Sprintf(`[3,"%v",{"currentTime":"%v"}]`, messageId, currentTime.FormatTimestamp()) 41 | heartbeatResponse := availability.NewHeartbeatResponse(*currentTime) 42 | channel := NewMockWebSocket(wsId) 43 | 44 | handler := &MockCSMSAvailabilityHandler{} 45 | handler.On("OnHeartbeat", mock.AnythingOfType("string"), mock.Anything).Return(heartbeatResponse, nil).Run(func(args mock.Arguments) { 46 | request, ok := args.Get(1).(*availability.HeartbeatRequest) 47 | require.True(t, ok) 48 | require.NotNil(t, request) 49 | }) 50 | setupDefaultCSMSHandlers(suite, expectedCSMSOptions{clientId: wsId, rawWrittenMessage: []byte(responseJson), forwardWrittenMessage: true}, handler) 51 | setupDefaultChargingStationHandlers(suite, expectedChargingStationOptions{serverUrl: wsUrl, clientId: wsId, createChannelOnStart: true, channel: channel, rawWrittenMessage: []byte(requestJson), forwardWrittenMessage: true}) 52 | // Run Test 53 | suite.csms.Start(8887, "somePath") 54 | err := suite.chargingStation.Start(wsUrl) 55 | assert.Nil(t, err) 56 | response, err := suite.chargingStation.Heartbeat() 57 | assert.Nil(t, err) 58 | assert.NotNil(t, response) 59 | assertDateTimeEquality(t, currentTime, &response.CurrentTime) 60 | } 61 | 62 | func (suite *OcppV2TestSuite) TestHeartbeatInvalidEndpoint() { 63 | messageId := defaultMessageId 64 | heartbeatRequest := availability.NewHeartbeatRequest() 65 | requestJson := fmt.Sprintf(`[2,"%v","%v",{}]`, messageId, availability.HeartbeatFeatureName) 66 | testUnsupportedRequestFromCentralSystem(suite, heartbeatRequest, requestJson, messageId) 67 | } 68 | -------------------------------------------------------------------------------- /ocppj/mocks/mock_CanceledRequestHandler.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.51.0. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | ocpp "github.com/lorenzodonini/ocpp-go/ocpp" 7 | mock "github.com/stretchr/testify/mock" 8 | ) 9 | 10 | // MockCanceledRequestHandler is an autogenerated mock type for the CanceledRequestHandler type 11 | type MockCanceledRequestHandler struct { 12 | mock.Mock 13 | } 14 | 15 | type MockCanceledRequestHandler_Expecter struct { 16 | mock *mock.Mock 17 | } 18 | 19 | func (_m *MockCanceledRequestHandler) EXPECT() *MockCanceledRequestHandler_Expecter { 20 | return &MockCanceledRequestHandler_Expecter{mock: &_m.Mock} 21 | } 22 | 23 | // Execute provides a mock function with given fields: clientID, requestID, request, err 24 | func (_m *MockCanceledRequestHandler) Execute(clientID string, requestID string, request ocpp.Request, err *ocpp.Error) { 25 | _m.Called(clientID, requestID, request, err) 26 | } 27 | 28 | // MockCanceledRequestHandler_Execute_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Execute' 29 | type MockCanceledRequestHandler_Execute_Call struct { 30 | *mock.Call 31 | } 32 | 33 | // Execute is a helper method to define mock.On call 34 | // - clientID string 35 | // - requestID string 36 | // - request ocpp.Request 37 | // - err *ocpp.Error 38 | func (_e *MockCanceledRequestHandler_Expecter) Execute(clientID interface{}, requestID interface{}, request interface{}, err interface{}) *MockCanceledRequestHandler_Execute_Call { 39 | return &MockCanceledRequestHandler_Execute_Call{Call: _e.mock.On("Execute", clientID, requestID, request, err)} 40 | } 41 | 42 | func (_c *MockCanceledRequestHandler_Execute_Call) Run(run func(clientID string, requestID string, request ocpp.Request, err *ocpp.Error)) *MockCanceledRequestHandler_Execute_Call { 43 | _c.Call.Run(func(args mock.Arguments) { 44 | run(args[0].(string), args[1].(string), args[2].(ocpp.Request), args[3].(*ocpp.Error)) 45 | }) 46 | return _c 47 | } 48 | 49 | func (_c *MockCanceledRequestHandler_Execute_Call) Return() *MockCanceledRequestHandler_Execute_Call { 50 | _c.Call.Return() 51 | return _c 52 | } 53 | 54 | func (_c *MockCanceledRequestHandler_Execute_Call) RunAndReturn(run func(string, string, ocpp.Request, *ocpp.Error)) *MockCanceledRequestHandler_Execute_Call { 55 | _c.Run(run) 56 | return _c 57 | } 58 | 59 | // NewMockCanceledRequestHandler creates a new instance of MockCanceledRequestHandler. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. 60 | // The first argument is typically a *testing.T value. 61 | func NewMockCanceledRequestHandler(t interface { 62 | mock.TestingT 63 | Cleanup(func()) 64 | }) *MockCanceledRequestHandler { 65 | mock := &MockCanceledRequestHandler{} 66 | mock.Mock.Test(t) 67 | 68 | t.Cleanup(func() { mock.AssertExpectations(t) }) 69 | 70 | return mock 71 | } 72 | -------------------------------------------------------------------------------- /ocppj/mocks/mock_ClientHandler.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.51.0. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | mock "github.com/stretchr/testify/mock" 7 | 8 | ws "github.com/lorenzodonini/ocpp-go/ws" 9 | ) 10 | 11 | // MockClientHandler is an autogenerated mock type for the ClientHandler type 12 | type MockClientHandler struct { 13 | mock.Mock 14 | } 15 | 16 | type MockClientHandler_Expecter struct { 17 | mock *mock.Mock 18 | } 19 | 20 | func (_m *MockClientHandler) EXPECT() *MockClientHandler_Expecter { 21 | return &MockClientHandler_Expecter{mock: &_m.Mock} 22 | } 23 | 24 | // Execute provides a mock function with given fields: client 25 | func (_m *MockClientHandler) Execute(client ws.Channel) { 26 | _m.Called(client) 27 | } 28 | 29 | // MockClientHandler_Execute_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Execute' 30 | type MockClientHandler_Execute_Call struct { 31 | *mock.Call 32 | } 33 | 34 | // Execute is a helper method to define mock.On call 35 | // - client ws.Channel 36 | func (_e *MockClientHandler_Expecter) Execute(client interface{}) *MockClientHandler_Execute_Call { 37 | return &MockClientHandler_Execute_Call{Call: _e.mock.On("Execute", client)} 38 | } 39 | 40 | func (_c *MockClientHandler_Execute_Call) Run(run func(client ws.Channel)) *MockClientHandler_Execute_Call { 41 | _c.Call.Run(func(args mock.Arguments) { 42 | run(args[0].(ws.Channel)) 43 | }) 44 | return _c 45 | } 46 | 47 | func (_c *MockClientHandler_Execute_Call) Return() *MockClientHandler_Execute_Call { 48 | _c.Call.Return() 49 | return _c 50 | } 51 | 52 | func (_c *MockClientHandler_Execute_Call) RunAndReturn(run func(ws.Channel)) *MockClientHandler_Execute_Call { 53 | _c.Run(run) 54 | return _c 55 | } 56 | 57 | // NewMockClientHandler creates a new instance of MockClientHandler. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. 58 | // The first argument is typically a *testing.T value. 59 | func NewMockClientHandler(t interface { 60 | mock.TestingT 61 | Cleanup(func()) 62 | }) *MockClientHandler { 63 | mock := &MockClientHandler{} 64 | mock.Mock.Test(t) 65 | 66 | t.Cleanup(func() { mock.AssertExpectations(t) }) 67 | 68 | return mock 69 | } 70 | -------------------------------------------------------------------------------- /ocppj/mocks/mock_ErrorHandler.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.51.0. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | ocpp "github.com/lorenzodonini/ocpp-go/ocpp" 7 | mock "github.com/stretchr/testify/mock" 8 | 9 | ws "github.com/lorenzodonini/ocpp-go/ws" 10 | ) 11 | 12 | // MockErrorHandler is an autogenerated mock type for the ErrorHandler type 13 | type MockErrorHandler struct { 14 | mock.Mock 15 | } 16 | 17 | type MockErrorHandler_Expecter struct { 18 | mock *mock.Mock 19 | } 20 | 21 | func (_m *MockErrorHandler) EXPECT() *MockErrorHandler_Expecter { 22 | return &MockErrorHandler_Expecter{mock: &_m.Mock} 23 | } 24 | 25 | // Execute provides a mock function with given fields: client, err, details 26 | func (_m *MockErrorHandler) Execute(client ws.Channel, err *ocpp.Error, details interface{}) { 27 | _m.Called(client, err, details) 28 | } 29 | 30 | // MockErrorHandler_Execute_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Execute' 31 | type MockErrorHandler_Execute_Call struct { 32 | *mock.Call 33 | } 34 | 35 | // Execute is a helper method to define mock.On call 36 | // - client ws.Channel 37 | // - err *ocpp.Error 38 | // - details interface{} 39 | func (_e *MockErrorHandler_Expecter) Execute(client interface{}, err interface{}, details interface{}) *MockErrorHandler_Execute_Call { 40 | return &MockErrorHandler_Execute_Call{Call: _e.mock.On("Execute", client, err, details)} 41 | } 42 | 43 | func (_c *MockErrorHandler_Execute_Call) Run(run func(client ws.Channel, err *ocpp.Error, details interface{})) *MockErrorHandler_Execute_Call { 44 | _c.Call.Run(func(args mock.Arguments) { 45 | run(args[0].(ws.Channel), args[1].(*ocpp.Error), args[2].(interface{})) 46 | }) 47 | return _c 48 | } 49 | 50 | func (_c *MockErrorHandler_Execute_Call) Return() *MockErrorHandler_Execute_Call { 51 | _c.Call.Return() 52 | return _c 53 | } 54 | 55 | func (_c *MockErrorHandler_Execute_Call) RunAndReturn(run func(ws.Channel, *ocpp.Error, interface{})) *MockErrorHandler_Execute_Call { 56 | _c.Run(run) 57 | return _c 58 | } 59 | 60 | // NewMockErrorHandler creates a new instance of MockErrorHandler. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. 61 | // The first argument is typically a *testing.T value. 62 | func NewMockErrorHandler(t interface { 63 | mock.TestingT 64 | Cleanup(func()) 65 | }) *MockErrorHandler { 66 | mock := &MockErrorHandler{} 67 | mock.Mock.Test(t) 68 | 69 | t.Cleanup(func() { mock.AssertExpectations(t) }) 70 | 71 | return mock 72 | } 73 | -------------------------------------------------------------------------------- /ocppj/mocks/mock_RequestHandler.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.51.0. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | ocpp "github.com/lorenzodonini/ocpp-go/ocpp" 7 | mock "github.com/stretchr/testify/mock" 8 | 9 | ws "github.com/lorenzodonini/ocpp-go/ws" 10 | ) 11 | 12 | // MockRequestHandler is an autogenerated mock type for the RequestHandler type 13 | type MockRequestHandler struct { 14 | mock.Mock 15 | } 16 | 17 | type MockRequestHandler_Expecter struct { 18 | mock *mock.Mock 19 | } 20 | 21 | func (_m *MockRequestHandler) EXPECT() *MockRequestHandler_Expecter { 22 | return &MockRequestHandler_Expecter{mock: &_m.Mock} 23 | } 24 | 25 | // Execute provides a mock function with given fields: client, request, requestId, action 26 | func (_m *MockRequestHandler) Execute(client ws.Channel, request ocpp.Request, requestId string, action string) { 27 | _m.Called(client, request, requestId, action) 28 | } 29 | 30 | // MockRequestHandler_Execute_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Execute' 31 | type MockRequestHandler_Execute_Call struct { 32 | *mock.Call 33 | } 34 | 35 | // Execute is a helper method to define mock.On call 36 | // - client ws.Channel 37 | // - request ocpp.Request 38 | // - requestId string 39 | // - action string 40 | func (_e *MockRequestHandler_Expecter) Execute(client interface{}, request interface{}, requestId interface{}, action interface{}) *MockRequestHandler_Execute_Call { 41 | return &MockRequestHandler_Execute_Call{Call: _e.mock.On("Execute", client, request, requestId, action)} 42 | } 43 | 44 | func (_c *MockRequestHandler_Execute_Call) Run(run func(client ws.Channel, request ocpp.Request, requestId string, action string)) *MockRequestHandler_Execute_Call { 45 | _c.Call.Run(func(args mock.Arguments) { 46 | run(args[0].(ws.Channel), args[1].(ocpp.Request), args[2].(string), args[3].(string)) 47 | }) 48 | return _c 49 | } 50 | 51 | func (_c *MockRequestHandler_Execute_Call) Return() *MockRequestHandler_Execute_Call { 52 | _c.Call.Return() 53 | return _c 54 | } 55 | 56 | func (_c *MockRequestHandler_Execute_Call) RunAndReturn(run func(ws.Channel, ocpp.Request, string, string)) *MockRequestHandler_Execute_Call { 57 | _c.Run(run) 58 | return _c 59 | } 60 | 61 | // NewMockRequestHandler creates a new instance of MockRequestHandler. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. 62 | // The first argument is typically a *testing.T value. 63 | func NewMockRequestHandler(t interface { 64 | mock.TestingT 65 | Cleanup(func()) 66 | }) *MockRequestHandler { 67 | mock := &MockRequestHandler{} 68 | mock.Mock.Test(t) 69 | 70 | t.Cleanup(func() { mock.AssertExpectations(t) }) 71 | 72 | return mock 73 | } 74 | -------------------------------------------------------------------------------- /ocppj/mocks/mock_ResponseHandler.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.51.0. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | ocpp "github.com/lorenzodonini/ocpp-go/ocpp" 7 | mock "github.com/stretchr/testify/mock" 8 | 9 | ws "github.com/lorenzodonini/ocpp-go/ws" 10 | ) 11 | 12 | // MockResponseHandler is an autogenerated mock type for the ResponseHandler type 13 | type MockResponseHandler struct { 14 | mock.Mock 15 | } 16 | 17 | type MockResponseHandler_Expecter struct { 18 | mock *mock.Mock 19 | } 20 | 21 | func (_m *MockResponseHandler) EXPECT() *MockResponseHandler_Expecter { 22 | return &MockResponseHandler_Expecter{mock: &_m.Mock} 23 | } 24 | 25 | // Execute provides a mock function with given fields: client, response, requestId 26 | func (_m *MockResponseHandler) Execute(client ws.Channel, response ocpp.Response, requestId string) { 27 | _m.Called(client, response, requestId) 28 | } 29 | 30 | // MockResponseHandler_Execute_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Execute' 31 | type MockResponseHandler_Execute_Call struct { 32 | *mock.Call 33 | } 34 | 35 | // Execute is a helper method to define mock.On call 36 | // - client ws.Channel 37 | // - response ocpp.Response 38 | // - requestId string 39 | func (_e *MockResponseHandler_Expecter) Execute(client interface{}, response interface{}, requestId interface{}) *MockResponseHandler_Execute_Call { 40 | return &MockResponseHandler_Execute_Call{Call: _e.mock.On("Execute", client, response, requestId)} 41 | } 42 | 43 | func (_c *MockResponseHandler_Execute_Call) Run(run func(client ws.Channel, response ocpp.Response, requestId string)) *MockResponseHandler_Execute_Call { 44 | _c.Call.Run(func(args mock.Arguments) { 45 | run(args[0].(ws.Channel), args[1].(ocpp.Response), args[2].(string)) 46 | }) 47 | return _c 48 | } 49 | 50 | func (_c *MockResponseHandler_Execute_Call) Return() *MockResponseHandler_Execute_Call { 51 | _c.Call.Return() 52 | return _c 53 | } 54 | 55 | func (_c *MockResponseHandler_Execute_Call) RunAndReturn(run func(ws.Channel, ocpp.Response, string)) *MockResponseHandler_Execute_Call { 56 | _c.Run(run) 57 | return _c 58 | } 59 | 60 | // NewMockResponseHandler creates a new instance of MockResponseHandler. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. 61 | // The first argument is typically a *testing.T value. 62 | func NewMockResponseHandler(t interface { 63 | mock.TestingT 64 | Cleanup(func()) 65 | }) *MockResponseHandler { 66 | mock := &MockResponseHandler{} 67 | mock.Mock.Test(t) 68 | 69 | t.Cleanup(func() { mock.AssertExpectations(t) }) 70 | 71 | return mock 72 | } 73 | -------------------------------------------------------------------------------- /ocppj/mocks/mock_dialector.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.51.0. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | ocpp "github.com/lorenzodonini/ocpp-go/ocpp" 7 | mock "github.com/stretchr/testify/mock" 8 | ) 9 | 10 | // Mockdialector is an autogenerated mock type for the dialector type 11 | type Mockdialector struct { 12 | mock.Mock 13 | } 14 | 15 | type Mockdialector_Expecter struct { 16 | mock *mock.Mock 17 | } 18 | 19 | func (_m *Mockdialector) EXPECT() *Mockdialector_Expecter { 20 | return &Mockdialector_Expecter{mock: &_m.Mock} 21 | } 22 | 23 | // Dialect provides a mock function with no fields 24 | func (_m *Mockdialector) Dialect() ocpp.Dialect { 25 | ret := _m.Called() 26 | 27 | if len(ret) == 0 { 28 | panic("no return value specified for Dialect") 29 | } 30 | 31 | var r0 ocpp.Dialect 32 | if rf, ok := ret.Get(0).(func() ocpp.Dialect); ok { 33 | r0 = rf() 34 | } else { 35 | r0 = ret.Get(0).(ocpp.Dialect) 36 | } 37 | 38 | return r0 39 | } 40 | 41 | // Mockdialector_Dialect_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Dialect' 42 | type Mockdialector_Dialect_Call struct { 43 | *mock.Call 44 | } 45 | 46 | // Dialect is a helper method to define mock.On call 47 | func (_e *Mockdialector_Expecter) Dialect() *Mockdialector_Dialect_Call { 48 | return &Mockdialector_Dialect_Call{Call: _e.mock.On("Dialect")} 49 | } 50 | 51 | func (_c *Mockdialector_Dialect_Call) Run(run func()) *Mockdialector_Dialect_Call { 52 | _c.Call.Run(func(args mock.Arguments) { 53 | run() 54 | }) 55 | return _c 56 | } 57 | 58 | func (_c *Mockdialector_Dialect_Call) Return(_a0 ocpp.Dialect) *Mockdialector_Dialect_Call { 59 | _c.Call.Return(_a0) 60 | return _c 61 | } 62 | 63 | func (_c *Mockdialector_Dialect_Call) RunAndReturn(run func() ocpp.Dialect) *Mockdialector_Dialect_Call { 64 | _c.Call.Return(run) 65 | return _c 66 | } 67 | 68 | // NewMockdialector creates a new instance of Mockdialector. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. 69 | // The first argument is typically a *testing.T value. 70 | func NewMockdialector(t interface { 71 | mock.TestingT 72 | Cleanup(func()) 73 | }) *Mockdialector { 74 | mock := &Mockdialector{} 75 | mock.Mock.Test(t) 76 | 77 | t.Cleanup(func() { mock.AssertExpectations(t) }) 78 | 79 | return mock 80 | } 81 | -------------------------------------------------------------------------------- /ws/mocks/mock_CheckClientHandler.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.51.0. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | http "net/http" 7 | 8 | mock "github.com/stretchr/testify/mock" 9 | ) 10 | 11 | // MockCheckClientHandler is an autogenerated mock type for the CheckClientHandler type 12 | type MockCheckClientHandler struct { 13 | mock.Mock 14 | } 15 | 16 | type MockCheckClientHandler_Expecter struct { 17 | mock *mock.Mock 18 | } 19 | 20 | func (_m *MockCheckClientHandler) EXPECT() *MockCheckClientHandler_Expecter { 21 | return &MockCheckClientHandler_Expecter{mock: &_m.Mock} 22 | } 23 | 24 | // Execute provides a mock function with given fields: id, r 25 | func (_m *MockCheckClientHandler) Execute(id string, r *http.Request) bool { 26 | ret := _m.Called(id, r) 27 | 28 | if len(ret) == 0 { 29 | panic("no return value specified for Execute") 30 | } 31 | 32 | var r0 bool 33 | if rf, ok := ret.Get(0).(func(string, *http.Request) bool); ok { 34 | r0 = rf(id, r) 35 | } else { 36 | r0 = ret.Get(0).(bool) 37 | } 38 | 39 | return r0 40 | } 41 | 42 | // MockCheckClientHandler_Execute_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Execute' 43 | type MockCheckClientHandler_Execute_Call struct { 44 | *mock.Call 45 | } 46 | 47 | // Execute is a helper method to define mock.On call 48 | // - id string 49 | // - r *http.Request 50 | func (_e *MockCheckClientHandler_Expecter) Execute(id interface{}, r interface{}) *MockCheckClientHandler_Execute_Call { 51 | return &MockCheckClientHandler_Execute_Call{Call: _e.mock.On("Execute", id, r)} 52 | } 53 | 54 | func (_c *MockCheckClientHandler_Execute_Call) Run(run func(id string, r *http.Request)) *MockCheckClientHandler_Execute_Call { 55 | _c.Call.Run(func(args mock.Arguments) { 56 | run(args[0].(string), args[1].(*http.Request)) 57 | }) 58 | return _c 59 | } 60 | 61 | func (_c *MockCheckClientHandler_Execute_Call) Return(_a0 bool) *MockCheckClientHandler_Execute_Call { 62 | _c.Call.Return(_a0) 63 | return _c 64 | } 65 | 66 | func (_c *MockCheckClientHandler_Execute_Call) RunAndReturn(run func(string, *http.Request) bool) *MockCheckClientHandler_Execute_Call { 67 | _c.Call.Return(run) 68 | return _c 69 | } 70 | 71 | // NewMockCheckClientHandler creates a new instance of MockCheckClientHandler. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. 72 | // The first argument is typically a *testing.T value. 73 | func NewMockCheckClientHandler(t interface { 74 | mock.TestingT 75 | Cleanup(func()) 76 | }) *MockCheckClientHandler { 77 | mock := &MockCheckClientHandler{} 78 | mock.Mock.Test(t) 79 | 80 | t.Cleanup(func() { mock.AssertExpectations(t) }) 81 | 82 | return mock 83 | } 84 | -------------------------------------------------------------------------------- /ws/mocks/mock_ClientOpt.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.51.0. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import mock "github.com/stretchr/testify/mock" 6 | 7 | // MockClientOpt is an autogenerated mock type for the ClientOpt type 8 | type MockClientOpt struct { 9 | mock.Mock 10 | } 11 | 12 | type MockClientOpt_Expecter struct { 13 | mock *mock.Mock 14 | } 15 | 16 | func (_m *MockClientOpt) EXPECT() *MockClientOpt_Expecter { 17 | return &MockClientOpt_Expecter{mock: &_m.Mock} 18 | } 19 | 20 | // Execute provides a mock function with given fields: c 21 | func (_m *MockClientOpt) Execute(c *ws.client) { 22 | _m.Called(c) 23 | } 24 | 25 | // MockClientOpt_Execute_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Execute' 26 | type MockClientOpt_Execute_Call struct { 27 | *mock.Call 28 | } 29 | 30 | // Execute is a helper method to define mock.On call 31 | // - c *ws.client 32 | func (_e *MockClientOpt_Expecter) Execute(c interface{}) *MockClientOpt_Execute_Call { 33 | return &MockClientOpt_Execute_Call{Call: _e.mock.On("Execute", c)} 34 | } 35 | 36 | func (_c *MockClientOpt_Execute_Call) Run(run func(c *ws.client)) *MockClientOpt_Execute_Call { 37 | _c.Call.Run(func(args mock.Arguments) { 38 | run(args[0].(*ws.client)) 39 | }) 40 | return _c 41 | } 42 | 43 | func (_c *MockClientOpt_Execute_Call) Return() *MockClientOpt_Execute_Call { 44 | _c.Call.Return() 45 | return _c 46 | } 47 | 48 | func (_c *MockClientOpt_Execute_Call) RunAndReturn(run func(*ws.client)) *MockClientOpt_Execute_Call { 49 | _c.Run(run) 50 | return _c 51 | } 52 | 53 | // NewMockClientOpt creates a new instance of MockClientOpt. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. 54 | // The first argument is typically a *testing.T value. 55 | func NewMockClientOpt(t interface { 56 | mock.TestingT 57 | Cleanup(func()) 58 | }) *MockClientOpt { 59 | mock := &MockClientOpt{} 60 | mock.Mock.Test(t) 61 | 62 | t.Cleanup(func() { mock.AssertExpectations(t) }) 63 | 64 | return mock 65 | } 66 | -------------------------------------------------------------------------------- /ws/mocks/mock_ConnectedHandler.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.51.0. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | ws "github.com/lorenzodonini/ocpp-go/ws" 7 | mock "github.com/stretchr/testify/mock" 8 | ) 9 | 10 | // MockConnectedHandler is an autogenerated mock type for the ConnectedHandler type 11 | type MockConnectedHandler struct { 12 | mock.Mock 13 | } 14 | 15 | type MockConnectedHandler_Expecter struct { 16 | mock *mock.Mock 17 | } 18 | 19 | func (_m *MockConnectedHandler) EXPECT() *MockConnectedHandler_Expecter { 20 | return &MockConnectedHandler_Expecter{mock: &_m.Mock} 21 | } 22 | 23 | // Execute provides a mock function with given fields: c 24 | func (_m *MockConnectedHandler) Execute(c ws.Channel) { 25 | _m.Called(c) 26 | } 27 | 28 | // MockConnectedHandler_Execute_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Execute' 29 | type MockConnectedHandler_Execute_Call struct { 30 | *mock.Call 31 | } 32 | 33 | // Execute is a helper method to define mock.On call 34 | // - c ws.Channel 35 | func (_e *MockConnectedHandler_Expecter) Execute(c interface{}) *MockConnectedHandler_Execute_Call { 36 | return &MockConnectedHandler_Execute_Call{Call: _e.mock.On("Execute", c)} 37 | } 38 | 39 | func (_c *MockConnectedHandler_Execute_Call) Run(run func(c ws.Channel)) *MockConnectedHandler_Execute_Call { 40 | _c.Call.Run(func(args mock.Arguments) { 41 | run(args[0].(ws.Channel)) 42 | }) 43 | return _c 44 | } 45 | 46 | func (_c *MockConnectedHandler_Execute_Call) Return() *MockConnectedHandler_Execute_Call { 47 | _c.Call.Return() 48 | return _c 49 | } 50 | 51 | func (_c *MockConnectedHandler_Execute_Call) RunAndReturn(run func(ws.Channel)) *MockConnectedHandler_Execute_Call { 52 | _c.Run(run) 53 | return _c 54 | } 55 | 56 | // NewMockConnectedHandler creates a new instance of MockConnectedHandler. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. 57 | // The first argument is typically a *testing.T value. 58 | func NewMockConnectedHandler(t interface { 59 | mock.TestingT 60 | Cleanup(func()) 61 | }) *MockConnectedHandler { 62 | mock := &MockConnectedHandler{} 63 | mock.Mock.Test(t) 64 | 65 | t.Cleanup(func() { mock.AssertExpectations(t) }) 66 | 67 | return mock 68 | } 69 | -------------------------------------------------------------------------------- /ws/mocks/mock_DisconnectedHandler.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.51.0. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | ws "github.com/lorenzodonini/ocpp-go/ws" 7 | mock "github.com/stretchr/testify/mock" 8 | ) 9 | 10 | // MockDisconnectedHandler is an autogenerated mock type for the DisconnectedHandler type 11 | type MockDisconnectedHandler struct { 12 | mock.Mock 13 | } 14 | 15 | type MockDisconnectedHandler_Expecter struct { 16 | mock *mock.Mock 17 | } 18 | 19 | func (_m *MockDisconnectedHandler) EXPECT() *MockDisconnectedHandler_Expecter { 20 | return &MockDisconnectedHandler_Expecter{mock: &_m.Mock} 21 | } 22 | 23 | // Execute provides a mock function with given fields: c, err 24 | func (_m *MockDisconnectedHandler) Execute(c ws.Channel, err error) { 25 | _m.Called(c, err) 26 | } 27 | 28 | // MockDisconnectedHandler_Execute_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Execute' 29 | type MockDisconnectedHandler_Execute_Call struct { 30 | *mock.Call 31 | } 32 | 33 | // Execute is a helper method to define mock.On call 34 | // - c ws.Channel 35 | // - err error 36 | func (_e *MockDisconnectedHandler_Expecter) Execute(c interface{}, err interface{}) *MockDisconnectedHandler_Execute_Call { 37 | return &MockDisconnectedHandler_Execute_Call{Call: _e.mock.On("Execute", c, err)} 38 | } 39 | 40 | func (_c *MockDisconnectedHandler_Execute_Call) Run(run func(c ws.Channel, err error)) *MockDisconnectedHandler_Execute_Call { 41 | _c.Call.Run(func(args mock.Arguments) { 42 | run(args[0].(ws.Channel), args[1].(error)) 43 | }) 44 | return _c 45 | } 46 | 47 | func (_c *MockDisconnectedHandler_Execute_Call) Return() *MockDisconnectedHandler_Execute_Call { 48 | _c.Call.Return() 49 | return _c 50 | } 51 | 52 | func (_c *MockDisconnectedHandler_Execute_Call) RunAndReturn(run func(ws.Channel, error)) *MockDisconnectedHandler_Execute_Call { 53 | _c.Run(run) 54 | return _c 55 | } 56 | 57 | // NewMockDisconnectedHandler creates a new instance of MockDisconnectedHandler. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. 58 | // The first argument is typically a *testing.T value. 59 | func NewMockDisconnectedHandler(t interface { 60 | mock.TestingT 61 | Cleanup(func()) 62 | }) *MockDisconnectedHandler { 63 | mock := &MockDisconnectedHandler{} 64 | mock.Mock.Test(t) 65 | 66 | t.Cleanup(func() { mock.AssertExpectations(t) }) 67 | 68 | return mock 69 | } 70 | -------------------------------------------------------------------------------- /ws/mocks/mock_ErrorHandler.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.51.0. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | ws "github.com/lorenzodonini/ocpp-go/ws" 7 | mock "github.com/stretchr/testify/mock" 8 | ) 9 | 10 | // MockErrorHandler is an autogenerated mock type for the ErrorHandler type 11 | type MockErrorHandler struct { 12 | mock.Mock 13 | } 14 | 15 | type MockErrorHandler_Expecter struct { 16 | mock *mock.Mock 17 | } 18 | 19 | func (_m *MockErrorHandler) EXPECT() *MockErrorHandler_Expecter { 20 | return &MockErrorHandler_Expecter{mock: &_m.Mock} 21 | } 22 | 23 | // Execute provides a mock function with given fields: c, err 24 | func (_m *MockErrorHandler) Execute(c ws.Channel, err error) { 25 | _m.Called(c, err) 26 | } 27 | 28 | // MockErrorHandler_Execute_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Execute' 29 | type MockErrorHandler_Execute_Call struct { 30 | *mock.Call 31 | } 32 | 33 | // Execute is a helper method to define mock.On call 34 | // - c ws.Channel 35 | // - err error 36 | func (_e *MockErrorHandler_Expecter) Execute(c interface{}, err interface{}) *MockErrorHandler_Execute_Call { 37 | return &MockErrorHandler_Execute_Call{Call: _e.mock.On("Execute", c, err)} 38 | } 39 | 40 | func (_c *MockErrorHandler_Execute_Call) Run(run func(c ws.Channel, err error)) *MockErrorHandler_Execute_Call { 41 | _c.Call.Run(func(args mock.Arguments) { 42 | run(args[0].(ws.Channel), args[1].(error)) 43 | }) 44 | return _c 45 | } 46 | 47 | func (_c *MockErrorHandler_Execute_Call) Return() *MockErrorHandler_Execute_Call { 48 | _c.Call.Return() 49 | return _c 50 | } 51 | 52 | func (_c *MockErrorHandler_Execute_Call) RunAndReturn(run func(ws.Channel, error)) *MockErrorHandler_Execute_Call { 53 | _c.Run(run) 54 | return _c 55 | } 56 | 57 | // NewMockErrorHandler creates a new instance of MockErrorHandler. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. 58 | // The first argument is typically a *testing.T value. 59 | func NewMockErrorHandler(t interface { 60 | mock.TestingT 61 | Cleanup(func()) 62 | }) *MockErrorHandler { 63 | mock := &MockErrorHandler{} 64 | mock.Mock.Test(t) 65 | 66 | t.Cleanup(func() { mock.AssertExpectations(t) }) 67 | 68 | return mock 69 | } 70 | -------------------------------------------------------------------------------- /ws/mocks/mock_MessageHandler.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.51.0. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import ( 6 | ws "github.com/lorenzodonini/ocpp-go/ws" 7 | mock "github.com/stretchr/testify/mock" 8 | ) 9 | 10 | // MockMessageHandler is an autogenerated mock type for the MessageHandler type 11 | type MockMessageHandler struct { 12 | mock.Mock 13 | } 14 | 15 | type MockMessageHandler_Expecter struct { 16 | mock *mock.Mock 17 | } 18 | 19 | func (_m *MockMessageHandler) EXPECT() *MockMessageHandler_Expecter { 20 | return &MockMessageHandler_Expecter{mock: &_m.Mock} 21 | } 22 | 23 | // Execute provides a mock function with given fields: c, data 24 | func (_m *MockMessageHandler) Execute(c ws.Channel, data []byte) error { 25 | ret := _m.Called(c, data) 26 | 27 | if len(ret) == 0 { 28 | panic("no return value specified for Execute") 29 | } 30 | 31 | var r0 error 32 | if rf, ok := ret.Get(0).(func(ws.Channel, []byte) error); ok { 33 | r0 = rf(c, data) 34 | } else { 35 | r0 = ret.Error(0) 36 | } 37 | 38 | return r0 39 | } 40 | 41 | // MockMessageHandler_Execute_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Execute' 42 | type MockMessageHandler_Execute_Call struct { 43 | *mock.Call 44 | } 45 | 46 | // Execute is a helper method to define mock.On call 47 | // - c ws.Channel 48 | // - data []byte 49 | func (_e *MockMessageHandler_Expecter) Execute(c interface{}, data interface{}) *MockMessageHandler_Execute_Call { 50 | return &MockMessageHandler_Execute_Call{Call: _e.mock.On("Execute", c, data)} 51 | } 52 | 53 | func (_c *MockMessageHandler_Execute_Call) Run(run func(c ws.Channel, data []byte)) *MockMessageHandler_Execute_Call { 54 | _c.Call.Run(func(args mock.Arguments) { 55 | run(args[0].(ws.Channel), args[1].([]byte)) 56 | }) 57 | return _c 58 | } 59 | 60 | func (_c *MockMessageHandler_Execute_Call) Return(_a0 error) *MockMessageHandler_Execute_Call { 61 | _c.Call.Return(_a0) 62 | return _c 63 | } 64 | 65 | func (_c *MockMessageHandler_Execute_Call) RunAndReturn(run func(ws.Channel, []byte) error) *MockMessageHandler_Execute_Call { 66 | _c.Call.Return(run) 67 | return _c 68 | } 69 | 70 | // NewMockMessageHandler creates a new instance of MockMessageHandler. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. 71 | // The first argument is typically a *testing.T value. 72 | func NewMockMessageHandler(t interface { 73 | mock.TestingT 74 | Cleanup(func()) 75 | }) *MockMessageHandler { 76 | mock := &MockMessageHandler{} 77 | mock.Mock.Test(t) 78 | 79 | t.Cleanup(func() { mock.AssertExpectations(t) }) 80 | 81 | return mock 82 | } 83 | -------------------------------------------------------------------------------- /ws/mocks/mock_ServerOpt.go: -------------------------------------------------------------------------------- 1 | // Code generated by mockery v2.51.0. DO NOT EDIT. 2 | 3 | package mocks 4 | 5 | import mock "github.com/stretchr/testify/mock" 6 | 7 | // MockServerOpt is an autogenerated mock type for the ServerOpt type 8 | type MockServerOpt struct { 9 | mock.Mock 10 | } 11 | 12 | type MockServerOpt_Expecter struct { 13 | mock *mock.Mock 14 | } 15 | 16 | func (_m *MockServerOpt) EXPECT() *MockServerOpt_Expecter { 17 | return &MockServerOpt_Expecter{mock: &_m.Mock} 18 | } 19 | 20 | // Execute provides a mock function with given fields: s 21 | func (_m *MockServerOpt) Execute(s *ws.server) { 22 | _m.Called(s) 23 | } 24 | 25 | // MockServerOpt_Execute_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'Execute' 26 | type MockServerOpt_Execute_Call struct { 27 | *mock.Call 28 | } 29 | 30 | // Execute is a helper method to define mock.On call 31 | // - s *ws.server 32 | func (_e *MockServerOpt_Expecter) Execute(s interface{}) *MockServerOpt_Execute_Call { 33 | return &MockServerOpt_Execute_Call{Call: _e.mock.On("Execute", s)} 34 | } 35 | 36 | func (_c *MockServerOpt_Execute_Call) Run(run func(s *ws.server)) *MockServerOpt_Execute_Call { 37 | _c.Call.Run(func(args mock.Arguments) { 38 | run(args[0].(*ws.server)) 39 | }) 40 | return _c 41 | } 42 | 43 | func (_c *MockServerOpt_Execute_Call) Return() *MockServerOpt_Execute_Call { 44 | _c.Call.Return() 45 | return _c 46 | } 47 | 48 | func (_c *MockServerOpt_Execute_Call) RunAndReturn(run func(*ws.server)) *MockServerOpt_Execute_Call { 49 | _c.Run(run) 50 | return _c 51 | } 52 | 53 | // NewMockServerOpt creates a new instance of MockServerOpt. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. 54 | // The first argument is typically a *testing.T value. 55 | func NewMockServerOpt(t interface { 56 | mock.TestingT 57 | Cleanup(func()) 58 | }) *MockServerOpt { 59 | mock := &MockServerOpt{} 60 | mock.Mock.Test(t) 61 | 62 | t.Cleanup(func() { mock.AssertExpectations(t) }) 63 | 64 | return mock 65 | } 66 | -------------------------------------------------------------------------------- /ws/toxiproxy.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=TCP proxy to simulate network and system conditions 3 | After=network-online.target firewalld.service 4 | Wants=network-online.target 5 | 6 | [Service] 7 | Type=simple 8 | Environment=HOST=localhost 9 | Environment=PORT=8474 10 | ExecStart=/usr/bin/toxiproxy-server -port $PORT -host $HOST 11 | Restart=on-failure 12 | 13 | [Install] 14 | WantedBy=multi-user.target 15 | --------------------------------------------------------------------------------