Apply prettier formating
authorJérôme Benoit <jerome.benoit@sap.com>
Fri, 4 Mar 2022 21:34:42 +0000 (22:34 +0100)
committerJérôme Benoit <jerome.benoit@sap.com>
Fri, 4 Mar 2022 21:34:42 +0000 (22:34 +0100)
Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
83 files changed:
.eslintrc
.github/ISSUE_TEMPLATE/bug_report.yml
.github/ISSUE_TEMPLATE/feature_request.yml
.github/workflows/ci.yml
.github/workflows/codeql-analysis.yml
.mocharc.json
.nycrc.json
.vscode/launch.json
CODE_OF_CONDUCT.md
README.md
docker/buildspec.yml
docker/config.json
manifest-cf-template.yml
mikro-orm.config-template.ts
package-lock.json
package.json
rollup.config.js
src/assets/authorization-tags-template.json
src/assets/config-template.json
src/charging-station/AutomaticTransactionGenerator.ts
src/charging-station/Bootstrap.ts
src/charging-station/ChargingStation.ts
src/charging-station/ChargingStationWorker.ts
src/charging-station/UIWebSocketServer.ts
src/charging-station/ocpp/1.6/OCPP16IncomingRequestService.ts
src/charging-station/ocpp/1.6/OCPP16RequestService.ts
src/charging-station/ocpp/1.6/OCPP16ResponseService.ts
src/charging-station/ocpp/1.6/OCPP16ServiceUtils.ts
src/charging-station/ocpp/OCPPIncomingRequestService.ts
src/charging-station/ocpp/OCPPRequestService.ts
src/charging-station/ocpp/OCPPResponseService.ts
src/charging-station/ui-websocket-services/AbstractUIService.ts
src/charging-station/ui-websocket-services/UIService001.ts
src/charging-station/ui-websocket-services/UIServiceFactory.ts
src/charging-station/ui-websocket-services/UIServiceUtils.ts
src/exception/BaseError.ts
src/exception/OCPPError.ts
src/performance/PerformanceStatistics.ts
src/performance/storage/JsonFileStorage.ts
src/performance/storage/MikroOrmStorage.ts
src/performance/storage/MongoDBStorage.ts
src/performance/storage/Storage.ts
src/scripts/deleteChargingStations.js
src/scripts/scriptConfig-template.json
src/scripts/setCSPublicFlag.js
src/start.ts
src/types/ChargingStationTemplate.ts
src/types/ChargingStationWorker.ts
src/types/Storage.ts
src/types/UIProtocol.ts
src/types/WebSocket.ts
src/types/Worker.ts
src/types/ocpp/1.6/ChargePointErrorCode.ts
src/types/ocpp/1.6/Configuration.ts
src/types/ocpp/1.6/DiagnosticsStatus.ts
src/types/ocpp/1.6/MeterValues.ts
src/types/ocpp/1.6/Requests.ts
src/types/ocpp/1.6/Responses.ts
src/types/ocpp/1.6/Transaction.ts
src/types/ocpp/ChargePointErrorCode.ts
src/types/ocpp/ChargePointStatus.ts
src/types/ocpp/Configuration.ts
src/types/ocpp/MeterValues.ts
src/types/ocpp/Requests.ts
src/types/ocpp/Responses.ts
src/types/ocpp/Transaction.ts
src/types/orm/entities/PerformanceData.ts
src/types/orm/entities/PerformanceRecord.ts
src/utils/CircularArray.ts
src/utils/Configuration.ts
src/utils/Constants.ts
src/utils/FileUtils.ts
src/utils/Logger.ts
src/utils/Utils.ts
src/worker/WorkerAbstract.ts
src/worker/WorkerDynamicPool.ts
src/worker/WorkerFactory.ts
src/worker/WorkerSet.ts
src/worker/WorkerStaticPool.ts
test/robohydra/config.json
test/robohydra/plugins/wsServer/index.js
test/utils/CircularArrayTest.ts
tsconfig.json

index 2153335c5ebfd5164e4f1b88eded5fc72bd0ff11..6d8714d77aad69508da20e66ad34406a37a87f57 100644 (file)
--- a/.eslintrc
+++ b/.eslintrc
     "plugin:import/errors",
     "plugin:import/warnings",
     "plugin:import/typescript",
-    "plugin:jsdoc/recommended"
-  ],
-  "plugins": [
-    "import",
-    "jsdoc",
-    "@typescript-eslint"
+    "plugin:jsdoc/recommended",
+    "prettier"
   ],
+  "plugins": ["import", "jsdoc", "@typescript-eslint"],
   "settings": {
     "jsdoc": {
       "mode": "typescript"
     ],
     "@typescript-eslint/array-type": "off",
     "semi": "off",
-    "@typescript-eslint/semi": [
-      "error",
-      "always"
-    ],
-    "space-before-blocks": [
-      "error",
-      "always"
-    ],
+    "@typescript-eslint/semi": ["error", "always"],
+    "space-before-blocks": ["error", "always"],
     "@typescript-eslint/no-empty-function": [
       "warn",
       {
-        "allow": [
-          "arrowFunctions",
-          "methods"
-        ]
+        "allow": ["arrowFunctions", "methods"]
       }
     ],
     "@typescript-eslint/member-ordering": "error",
     "@typescript-eslint/no-misused-promises": "error",
     "curly": "error",
     "brace-style": "error",
-    "eqeqeq": [
-      "error",
-      "always"
-    ],
+    "eqeqeq": ["error", "always"],
     "no-else-return": "error",
     "no-eq-null": "error",
     "no-undefined": "error",
     "no-lone-blocks": "error",
     "no-multi-spaces": "error",
     "no-empty": "error",
-    "no-return-assign": [
-      "error",
-      "always"
-    ],
+    "no-return-assign": ["error", "always"],
     "no-useless-catch": "error",
     "no-useless-return": "error",
     "no-shadow": "off", // This one is generating false positive no-shadow errors on exported/const enums
     //     "ignorePattern": "pragma|ignored"
     //   }
     // ],
-    "eol-last": [
-      "error",
-      "always"
-    ],
-    "consistent-this": [
-      "error",
-      "self"
-    ],
-    "func-call-spacing": [
-      "error",
-      "never"
-    ],
-    "keyword-spacing": [
-      "error"
-    ],
+    "eol-last": ["error", "always"],
+    "consistent-this": ["error", "self"],
+    "func-call-spacing": ["error", "never"],
+    "keyword-spacing": ["error"],
     "id-blacklist": [
       "error",
       "any",
       "Symbol",
       "symbol"
     ],
-    "linebreak-style": [
-      "error",
-      "unix"
-    ],
+    "linebreak-style": ["error", "unix"],
     "max-len": [
       "warn",
       {
         "asyncArrow": "always"
       }
     ],
-    "space-in-parens": [
-      "error",
-      "never"
-    ],
+    "space-in-parens": ["error", "never"],
     "space-infix-ops": "error",
     "space-unary-ops": "error",
-    "spaced-comment": [
-      "error",
-      "always"
-    ],
+    "spaced-comment": ["error", "always"],
     "switch-colon-spacing": "error",
-    "arrow-body-style": [
-      "error",
-      "as-needed"
-    ],
-    "arrow-parens": [
-      "error",
-      "always"
-    ],
+    "arrow-body-style": ["error", "as-needed"],
+    "arrow-parens": ["error", "always"],
     "arrow-spacing": "error",
     "no-duplicate-imports": "error",
     "no-var": "error",
         "ignoreCase": false,
         "ignoreDeclarationSort": false,
         "ignoreMemberSort": false,
-        "memberSyntaxSortOrder": [
-          "none",
-          "all",
-          "multiple",
-          "single"
-        ]
+        "memberSyntaxSortOrder": ["none", "all", "multiple", "single"]
       }
     ],
-    "object-curly-spacing": [
-      "error",
-      "always"
-    ],
+    "object-curly-spacing": ["error", "always"],
     "lines-between-class-members": [
       "error",
       "always",
         "exceptAfterSingleLine": true
       }
     ],
-    "quotes": [
-      "error",
-      "single"
-    ]
+    "quotes": ["error", "single"]
   },
   "overrides": [
     {
-      "files": [
-        "*.js"
-      ],
+      "files": ["*.js"],
       "extends": "plugin:node/recommended",
       "rules": {
         "node/shebang": "off",
index 585fec0cd8ff8adb61943a580a6514ff8a20927c..5e484fc62f1c9b9d42b4781f7296c44234a0f5c3 100644 (file)
@@ -13,15 +13,13 @@ body:
   - type: checkboxes
     attributes:
       options:
-        - label:
-            I've searched for any related issues and avoided creating a
+        - label: I've searched for any related issues and avoided creating a
             duplicate issue.
           required: true
   - type: textarea
     attributes:
       label: Description
-      description:
-        Description of the bug.
+      description: Description of the bug.
   - type: input
     attributes:
       label: charging-stations-simulator version
index 07e10fd56d4c16bf1a3edcf6528c3e22e99608c5..c61e58c9f9c58cf971983d8cf4bddb6ccc06da35 100644 (file)
@@ -11,15 +11,13 @@ body:
   - type: checkboxes
     attributes:
       options:
-        - label:
-            I've searched for any related issues and avoided creating a
+        - label: I've searched for any related issues and avoided creating a
             duplicate issue.
           required: true
   - type: textarea
     attributes:
       label: Description
-      description:
-        A clear and concise description of the feature.
+      description: A clear and concise description of the feature.
   - type: textarea
     attributes:
       label: Attachments
index 3e7ea8b88e67fc03fed14da532d32e71c1376a30..e5c359c09f3fc54ee368a3ac5445fc6789211aad 100644 (file)
@@ -12,38 +12,38 @@ jobs:
       matrix:
         node-version: ['14.x', '16.x', '17.x']
     steps:
-    - uses: actions/checkout@v2
-      with:
-        fetch-depth: 0  # Shallow clones should be disabled for a better relevancy of analysis
-    - name: Use Node.js ${{ matrix.node-version }}
-      uses: actions/setup-node@v2
-      with:
-        node-version: ${{ matrix.node-version }}
-    - name: npm install
-      run: npm ci
-    - name: npm run lint
-      run: npm run lint
-      continue-on-error: true
-    - name: npm run build
-      run: npm run build
-    - name: npm test
-      run: npm test
-    - name: npm run coverage
-      run: npm run coverage
-    - name: SonarCloud Scan
-      if: "github.repository == 'jerome-benoit/charging-stations-simulator' && matrix.node-version == '16.x'"
-      uses: sonarsource/sonarcloud-github-action@master
-      env:
-        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}  # Needed to get PR information, if any
-        SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
+      - uses: actions/checkout@v2
+        with:
+          fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
+      - name: Use Node.js ${{ matrix.node-version }}
+        uses: actions/setup-node@v2
+        with:
+          node-version: ${{ matrix.node-version }}
+      - name: npm install
+        run: npm ci
+      - name: npm run lint
+        run: npm run lint
+        continue-on-error: true
+      - name: npm run build
+        run: npm run build
+      - name: npm test
+        run: npm test
+      - name: npm run coverage
+        run: npm run coverage
+      - name: SonarCloud Scan
+        if: "github.repository == 'jerome-benoit/charging-stations-simulator' && matrix.node-version == '16.x'"
+        uses: sonarsource/sonarcloud-github-action@master
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
+          SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
   build-docker:
     runs-on: ubuntu-latest
     steps:
-    - uses: actions/checkout@v2
-    - name: Set up Docker Buildx
-      id: buildx
-      uses: docker/setup-buildx-action@v1
-    - name: Build docker image
-      run: |
-        cd docker
-        make SUBMODULES_INIT=false
+      - uses: actions/checkout@v2
+      - name: Set up Docker Buildx
+        id: buildx
+        uses: docker/setup-buildx-action@v1
+      - name: Build docker image
+        run: |
+          cd docker
+          make SUBMODULES_INIT=false
index d234d2f442f350752a539c8411a9eb1c42cf55a1..5acc1366725098f518a9ad64a50cab6f21b4c8bb 100644 (file)
@@ -9,14 +9,14 @@
 # the `language` matrix defined below to confirm you have the correct set of
 # supported CodeQL languages.
 #
-name: "CodeQL"
+name: 'CodeQL'
 
 on:
   push:
-    branches: [ master ]
+    branches: [master]
   pull_request:
     # The branches below must be a subset of the branches above
-    branches: [ master ]
+    branches: [master]
   schedule:
     - cron: '17 15 * * 1'
 
@@ -32,40 +32,40 @@ jobs:
     strategy:
       fail-fast: false
       matrix:
-        language: [ 'javascript' ]
+        language: ['javascript']
         # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ]
         # Learn more:
         # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
 
     steps:
-    - name: Checkout repository
-      uses: actions/checkout@v2
+      - name: Checkout repository
+        uses: actions/checkout@v2
 
-    # Initializes the CodeQL tools for scanning.
-    - name: Initialize CodeQL
-      uses: github/codeql-action/init@v1
-      with:
-        languages: ${{ matrix.language }}
-        # If you wish to specify custom queries, you can do so here or in a config file.
-        # By default, queries listed here will override any specified in a config file.
-        # Prefix the list here with "+" to use these queries and those in the config file.
-        # queries: ./path/to/local/query, your-org/your-repo/queries@main
+      # Initializes the CodeQL tools for scanning.
+      - name: Initialize CodeQL
+        uses: github/codeql-action/init@v1
+        with:
+          languages: ${{ matrix.language }}
+          # If you wish to specify custom queries, you can do so here or in a config file.
+          # By default, queries listed here will override any specified in a config file.
+          # Prefix the list here with "+" to use these queries and those in the config file.
+          # queries: ./path/to/local/query, your-org/your-repo/queries@main
 
-    # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).
-    # If this step fails, then you should remove it and run the build manually (see below)
-    - name: Autobuild
-      uses: github/codeql-action/autobuild@v1
+      # Autobuild attempts to build any compiled languages  (C/C++, C#, or Java).
+      # If this step fails, then you should remove it and run the build manually (see below)
+      - name: Autobuild
+        uses: github/codeql-action/autobuild@v1
 
-    # ℹ️ Command-line programs to run using the OS shell.
-    # 📚 https://git.io/JvXDl
+      # ℹ️ Command-line programs to run using the OS shell.
+      # 📚 https://git.io/JvXDl
 
-    # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
-    #    and modify them (or add more) to build your code if your project
-    #    uses a compiled language
+      # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
+      #    and modify them (or add more) to build your code if your project
+      #    uses a compiled language
 
-    #- run: |
-    #   make bootstrap
-    #   make release
+      #- run: |
+      #   make bootstrap
+      #   make release
 
-    - name: Perform CodeQL Analysis
-      uses: github/codeql-action/analyze@v1
+      - name: Perform CodeQL Analysis
+        uses: github/codeql-action/analyze@v1
index 88465baf32a54cbc4b3eb60c3ad15fedcd2d35be..6bab7faa18f3b10859b4d2aaedfd0093b64010fd 100644 (file)
@@ -2,9 +2,7 @@
   "parallel": true,
   "diff": true,
   "recursive": true,
-  "extension": [
-    "ts"
-  ],
+  "extension": ["ts"],
   "package": "./package.json",
   "reporter": "mochawesome",
   "reporter-options": "reportDir=outputs/mochawesome-report,json=false",
@@ -13,8 +11,5 @@
   "ui": "bdd",
   "full-trace": true,
   "exit": true,
-  "require": [
-    "ts-node/register",
-    "mochawesome/register"
-  ]
+  "require": ["ts-node/register", "mochawesome/register"]
 }
index a83f2f91bdda5f629ff8abb619049733835aa71f..be58771984ce7329dc820735b8c53a9ec2fac2ca 100644 (file)
@@ -1,7 +1,5 @@
 {
   "extends": "@istanbuljs/nyc-config-typescript",
   "all": true,
-  "include": [
-    "src/**/*.ts"
-  ]
+  "include": ["src/**/*.ts"]
 }
index 5c8aa82b4f96dcd045bf6d9fc96aa11a2422d5d1..e8114e91ee9ddd1d6edd267ae445b675318045c0 100644 (file)
       "cwd": "${workspaceFolder}",
       "preLaunchTask": "Build",
       "runtimeExecutable": "npm",
-      "runtimeArgs": [
-        "run-script",
-        "start:debug"
-      ],
-      "skipFiles": [
-        "<node_internals>/**"
-      ],
+      "runtimeArgs": ["run-script", "start:debug"],
+      "skipFiles": ["<node_internals>/**"],
       "stopOnEntry": true
     },
     {
       "name": "Debug Simulator Development Build via npm",
       "cwd": "${workspaceFolder}",
       "runtimeExecutable": "npm",
-      "runtimeArgs": [
-        "run-script",
-        "start:dev:debug"
-      ],
-      "skipFiles": [
-        "<node_internals>/**"
-      ],
+      "runtimeArgs": ["run-script", "start:dev:debug"],
+      "skipFiles": ["<node_internals>/**"],
       "stopOnEntry": true
     }
   ]
index b7f754422f6aa284a117ff593c549902e0a52ab9..4bae87e29240dcc1f8877465be19a60f235ece60 100644 (file)
@@ -17,23 +17,23 @@ diverse, inclusive, and healthy community.
 Examples of behavior that contributes to a positive environment for our
 community include:
 
-* Demonstrating empathy and kindness toward other people
-* Being respectful of differing opinions, viewpoints, and experiences
-* Giving and gracefully accepting constructive feedback
-* Accepting responsibility and apologizing to those affected by our mistakes,
+- Demonstrating empathy and kindness toward other people
+- Being respectful of differing opinions, viewpoints, and experiences
+- Giving and gracefully accepting constructive feedback
+- Accepting responsibility and apologizing to those affected by our mistakes,
   and learning from the experience
-* Focusing on what is best not just for us as individuals, but for the
+- Focusing on what is best not just for us as individuals, but for the
   overall community
 
 Examples of unacceptable behavior include:
 
-* The use of sexualized language or imagery, and sexual attention or
+- The use of sexualized language or imagery, and sexual attention or
   advances of any kind
-* Trolling, insulting or derogatory comments, and personal or political attacks
-* Public or private harassment
-* Publishing others' private information, such as a physical or email
+- Trolling, insulting or derogatory comments, and personal or political attacks
+- Public or private harassment
+- Publishing others' private information, such as a physical or email
   address, without their explicit permission
-* Other conduct which could reasonably be considered inappropriate in a
+- Other conduct which could reasonably be considered inappropriate in a
   professional setting
 
 ## Enforcement Responsibilities
@@ -106,7 +106,7 @@ Violating these terms may lead to a permanent ban.
 ### 4. Permanent Ban
 
 **Community Impact**: Demonstrating a pattern of violation of community
-standards, including sustained inappropriate behavior,  harassment of an
+standards, including sustained inappropriate behavior, harassment of an
 individual, or aggression toward or disparagement of classes of individuals.
 
 **Consequence**: A permanent ban from any sort of public interaction within
index 16bad1120a31acbf8087a4b48bf010dd2fc64fa2..fb393f9b1d0c91af4f01f456eb229d1962553263 100644 (file)
--- a/README.md
+++ b/README.md
@@ -8,7 +8,7 @@ Simple [node.js](https://nodejs.org/) program to simulate a set of charging stat
 
 ### Windows
 
-* [Chocolatey](https://chocolatey.org/):
+- [Chocolatey](https://chocolatey.org/):
 
 ```powershell
 choco install -y nodejs-lts
@@ -16,19 +16,19 @@ choco install -y nodejs-lts
 
 ### MacOSX
 
-* [Homebrew](https://brew.sh/):
+- [Homebrew](https://brew.sh/):
 
 ```shell
 brew install node@14
 ```
 
-### GNU/Linux: 
+### GNU/Linux:
 
-* [NodeSource](https://github.com/nodesource/distributions) Node.js Binary Distributions for version 14.X
+- [NodeSource](https://github.com/nodesource/distributions) Node.js Binary Distributions for version 14.X
 
 ## Configuration syntax
 
-All configuration files are in the JSON standard format.  
+All configuration files are in the JSON standard format.
 
 The charging stations simulator's main configuration parameters must be within the `src/assets/config.json` file. A configuration template file is available at [src/assets/config-template.json](src/assets/config-template.json).
 
@@ -36,97 +36,98 @@ All charging station templates are in the directory [src/assets/station-template
 
 A list of RFID tags must be defined for the automatic transaction generator with the default location and name `src/assets/authorization-tags.json`. A template file is available at [src/assets/authorization-tags-template.json](src/assets/authorization-tags-template.json).
 
-The charging stations simulator have an automatic configuration files reload feature at change for: 
-* main configuration;
-* charging station templates; 
-* authorization RFID tags.
+The charging stations simulator have an automatic configuration files reload feature at change for:
 
-But the modifications to test have to be done to the files in the build result directory [dist/assets](dist/assets). Once the modifications are finished, they have to be reported or copied to the matching files in the build source directory [src/assets](src/assets) to ensure they will be taken into account at next build. 
+- main configuration;
+- charging station templates;
+- authorization RFID tags.
 
-### Main configuration 
+But the modifications to test have to be done to the files in the build result directory [dist/assets](dist/assets). Once the modifications are finished, they have to be reported or copied to the matching files in the build source directory [src/assets](src/assets) to ensure they will be taken into account at next build.
+
+### Main configuration
 
 **src/assets/config.json**:
 
-Key | Value(s) | Default Value | Value type | Description 
---- | -------| --------------| ---------- | ------------
-supervisionUrls | | [] | string \| string[] | string or array of global connection URIs to OCPP-J servers
-supervisionUrlDistribution | round-robin/random/sequential | round-robin | boolean | supervision urls distribution policy to simulated charging stations
-workerProcess | workerSet/staticPool/dynamicPool | workerSet | string | worker threads process type
-workerStartDelay | | 500 | integer | milliseconds to wait at worker threads startup (only for workerSet threads process type)
-elementStartDelay | | 0 | integer | milliseconds to wait at charging station startup
-workerPoolMinSize | | 4 | integer | worker threads pool minimum number of threads
-workerPoolMaxSize | | 16 | integer | worker threads pool maximum number of threads
-workerPoolStrategy | ROUND_ROBIN/LESS_RECENTLY_USED/... | [poolifier](https://github.com/poolifier/poolifier) default: ROUND_ROBBIN | string | worker threads pool [poolifier](https://github.com/poolifier/poolifier) worker choice strategy
-chargingStationsPerWorker | | 1 | integer | number of charging stations per worker threads for the `workerSet` process type
-logStatisticsInterval | | 60 | integer | seconds between charging stations statistics output in the logs 
-logConsole | true/false | false | boolean | output logs on the console 
-logFormat | | simple | string | winston log format
-logRotate | true/false | true | boolean | enable daily log files rotation
-logMaxFiles | | 7 | integer | maximum number of log files to keep
-logLevel | emerg/alert/crit/error/warning/notice/info/debug | info | string | winston logging level
-logFile | | combined.log | string | log file relative path
-logErrorFile | | error.log | string | error log file relative path
-uiWebSocketServer | | { "enabled": true, "options": { "host: "localhost", "port": 8080 } } | { enabled: boolean; options: ServerOptions; } | UI WebSocket server configuration section 
-performanceStorage | | { "enabled": false, "type": "jsonfile", "file:///performanceRecords.json" } | { enabled: boolean; type: string; URI: string; } where type can be 'jsonfile' or 'mongodb' | performance storage configuration section
-stationTemplateUrls | | {}[] | { file: string; numberOfStations: number; }[] | array of charging station templates URIs configuration section (template file name and number of stations)
-
-#### Worker process model: 
+| Key                        | Value(s)                                         | Default Value                                                               | Value type                                                                                 | Description                                                                                                |
+| -------------------------- | ------------------------------------------------ | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------- |
+| supervisionUrls            |                                                  | []                                                                          | string \| string[]                                                                         | string or array of global connection URIs to OCPP-J servers                                                |
+| supervisionUrlDistribution | round-robin/random/sequential                    | round-robin                                                                 | boolean                                                                                    | supervision urls distribution policy to simulated charging stations                                        |
+| workerProcess              | workerSet/staticPool/dynamicPool                 | workerSet                                                                   | string                                                                                     | worker threads process type                                                                                |
+| workerStartDelay           |                                                  | 500                                                                         | integer                                                                                    | milliseconds to wait at worker threads startup (only for workerSet threads process type)                   |
+| elementStartDelay          |                                                  | 0                                                                           | integer                                                                                    | milliseconds to wait at charging station startup                                                           |
+| workerPoolMinSize          |                                                  | 4                                                                           | integer                                                                                    | worker threads pool minimum number of threads                                                              |
+| workerPoolMaxSize          |                                                  | 16                                                                          | integer                                                                                    | worker threads pool maximum number of threads                                                              |
+| workerPoolStrategy         | ROUND_ROBIN/LESS_RECENTLY_USED/...               | [poolifier](https://github.com/poolifier/poolifier) default: ROUND_ROBBIN   | string                                                                                     | worker threads pool [poolifier](https://github.com/poolifier/poolifier) worker choice strategy             |
+| chargingStationsPerWorker  |                                                  | 1                                                                           | integer                                                                                    | number of charging stations per worker threads for the `workerSet` process type                            |
+| logStatisticsInterval      |                                                  | 60                                                                          | integer                                                                                    | seconds between charging stations statistics output in the logs                                            |
+| logConsole                 | true/false                                       | false                                                                       | boolean                                                                                    | output logs on the console                                                                                 |
+| logFormat                  |                                                  | simple                                                                      | string                                                                                     | winston log format                                                                                         |
+| logRotate                  | true/false                                       | true                                                                        | boolean                                                                                    | enable daily log files rotation                                                                            |
+| logMaxFiles                |                                                  | 7                                                                           | integer                                                                                    | maximum number of log files to keep                                                                        |
+| logLevel                   | emerg/alert/crit/error/warning/notice/info/debug | info                                                                        | string                                                                                     | winston logging level                                                                                      |
+| logFile                    |                                                  | combined.log                                                                | string                                                                                     | log file relative path                                                                                     |
+| logErrorFile               |                                                  | error.log                                                                   | string                                                                                     | error log file relative path                                                                               |
+| uiWebSocketServer          |                                                  | { "enabled": true, "options": { "host: "localhost", "port": 8080 } }        | { enabled: boolean; options: ServerOptions; }                                              | UI WebSocket server configuration section                                                                  |
+| performanceStorage         |                                                  | { "enabled": false, "type": "jsonfile", "file:///performanceRecords.json" } | { enabled: boolean; type: string; URI: string; } where type can be 'jsonfile' or 'mongodb' | performance storage configuration section                                                                  |
+| stationTemplateUrls        |                                                  | {}[]                                                                        | { file: string; numberOfStations: number; }[]                                              | array of charging station templates URIs configuration section (template file name and number of stations) |
+
+#### Worker process model:
 
 - **workerSet**:
   Worker set executing each a static number (chargingStationsPerWorker) of simulated charging stations from the total
 
 - **staticPool**:
-  Statically sized worker pool executing a static total number of simulated charging stations    
+  Statically sized worker pool executing a static total number of simulated charging stations
 
 - **dynamicPool**:
-  Dynamically sized worker pool executing a static total number of simulated charging stations 
+  Dynamically sized worker pool executing a static total number of simulated charging stations
 
 ### Charging station template
 
-Key | Value(s) | Default Value | Value type | Description 
---- | -------| --------------| ---------- | ------------
-supervisionUrls | | '' | string\|string[] | string or array of connection URIs to OCPP-J servers. It has priority over the global configuration parameter
-supervisionUser | | '' | string | basic HTTP authentication user to OCPP-J server
-supervisionPassword | | '' | string | basic HTTP authentication password to OCPP-J server
-supervisionUrlOcppConfiguration | true/false | false | boolean | Allow supervision URL configuration via a vendor OCPP parameter key
-supervisionUrlOcppKey | | 'ConnectionUrl' | string | The vendor string that will be used as a vendor OCPP parameter key to set the supervision URL
-ocppVersion | 1.6 | 1.6 | string | OCPP version 
-ocppProtocol | json | json | string | OCPP protocol
-ocppStrictCompliance | true/false | true | boolean | Strict adherence to the OCPP version and protocol specifications
-wsOptions | | {} | ClientOptions & ClientRequestArgs | [ws](https://github.com/websockets/ws) and node.js [http](https://nodejs.org/api/http.html) clients options intersection
-authorizationFile | | '' | string | RFID tags list file relative to src/assets path
-baseName | | '' | string | base name to build charging stations name
-nameSuffix | | '' | string | name suffix to build charging stations name
-fixedName | true/false | false | boolean | use the baseName as the charging stations unique name
-chargePointModel | | '' | string | charging stations model
-chargePointVendor | | '' | string | charging stations vendor
-chargeBoxSerialNumberPrefix | | '' | string | charging stations serial number prefix
-firmwareVersion | | '' | string | charging stations firmware version
-power | | | float\|float[] | charging stations maximum power value(s)
-powerSharedByConnectors | true/false | false | boolean | charging stations power shared by its connectors
-powerUnit | W/kW | W | string | charging stations power unit
-currentOutType | AC/DC | AC | string | charging stations current out type
-voltageOut | | AC:230/DC:400 | integer | charging stations voltage out
-numberOfPhases | 0/1/3 | AC:3/DC:0 | integer | charging stations number of phase(s) 
-numberOfConnectors | | | integer\|integer[] | charging stations number of connector(s)
-useConnectorId0 | true/false | true | boolean | use connector id 0 definition from the template
-randomConnectors | true/false | false | boolean | randomize runtime connector id affectation from the connector id definition in template
-resetTime | | 60 | integer | seconds to wait before the charging stations come back at reset
-autoRegister | true/false | false | boolean | set the charging station as registered at boot notification for testing purpose
-autoReconnectMaxRetries | | -1 (unlimited) | integer | connection retries to the OCPP-J server
-reconnectExponentialDelay | true/false | false | boolean | connection delay retry to the OCPP-J server
-registrationMaxRetries | | -1 (unlimited) | integer | charging stations boot notification retries
-enableStatistics | true/false | true | boolean | enable charging stations statistics
-mayAuthorizeAtRemoteStart | true/false | true | boolean | always send authorize at remote start transaction when AuthorizeRemoteTxRequests is enabled
-beginEndMeterValues | true/false | false | boolean | enable Transaction.{Begin,End} MeterValues
-outOfOrderEndMeterValues | true/false | false | boolean | send Transaction.End MeterValues out of order. Need to relax OCPP specifications strict compliance ('ocppStrictCompliance' parameter)
-meteringPerTransaction | true/false | true | boolean | enable metering history on a per transaction basis
-transactionDataMeterValues | true/false | false | boolean | enable transaction data MeterValues at stop transaction
-mainVoltageMeterValues | true/false | true | boolean | include charging station main voltage MeterValues on three phased charging stations
-phaseLineToLineVoltageMeterValues | true/false | true | boolean | include charging station line to line voltage MeterValues on three phased charging stations
-Configuration | | | ChargingStationConfiguration | charging stations OCPP parameters configuration section
-AutomaticTransactionGenerator | | | AutomaticTransactionGenerator | charging stations ATG configuration section
-Connectors | | | Connectors | charging stations connectors configuration section
+| Key                               | Value(s)   | Default Value   | Value type                        | Description                                                                                                                           |
+| --------------------------------- | ---------- | --------------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
+| supervisionUrls                   |            | ''              | string\|string[]                  | string or array of connection URIs to OCPP-J servers. It has priority over the global configuration parameter                         |
+| supervisionUser                   |            | ''              | string                            | basic HTTP authentication user to OCPP-J server                                                                                       |
+| supervisionPassword               |            | ''              | string                            | basic HTTP authentication password to OCPP-J server                                                                                   |
+| supervisionUrlOcppConfiguration   | true/false | false           | boolean                           | Allow supervision URL configuration via a vendor OCPP parameter key                                                                   |
+| supervisionUrlOcppKey             |            | 'ConnectionUrl' | string                            | The vendor string that will be used as a vendor OCPP parameter key to set the supervision URL                                         |
+| ocppVersion                       | 1.6        | 1.6             | string                            | OCPP version                                                                                                                          |
+| ocppProtocol                      | json       | json            | string                            | OCPP protocol                                                                                                                         |
+| ocppStrictCompliance              | true/false | true            | boolean                           | Strict adherence to the OCPP version and protocol specifications                                                                      |
+| wsOptions                         |            | {}              | ClientOptions & ClientRequestArgs | [ws](https://github.com/websockets/ws) and node.js [http](https://nodejs.org/api/http.html) clients options intersection              |
+| authorizationFile                 |            | ''              | string                            | RFID tags list file relative to src/assets path                                                                                       |
+| baseName                          |            | ''              | string                            | base name to build charging stations name                                                                                             |
+| nameSuffix                        |            | ''              | string                            | name suffix to build charging stations name                                                                                           |
+| fixedName                         | true/false | false           | boolean                           | use the baseName as the charging stations unique name                                                                                 |
+| chargePointModel                  |            | ''              | string                            | charging stations model                                                                                                               |
+| chargePointVendor                 |            | ''              | string                            | charging stations vendor                                                                                                              |
+| chargeBoxSerialNumberPrefix       |            | ''              | string                            | charging stations serial number prefix                                                                                                |
+| firmwareVersion                   |            | ''              | string                            | charging stations firmware version                                                                                                    |
+| power                             |            |                 | float\|float[]                    | charging stations maximum power value(s)                                                                                              |
+| powerSharedByConnectors           | true/false | false           | boolean                           | charging stations power shared by its connectors                                                                                      |
+| powerUnit                         | W/kW       | W               | string                            | charging stations power unit                                                                                                          |
+| currentOutType                    | AC/DC      | AC              | string                            | charging stations current out type                                                                                                    |
+| voltageOut                        |            | AC:230/DC:400   | integer                           | charging stations voltage out                                                                                                         |
+| numberOfPhases                    | 0/1/3      | AC:3/DC:0       | integer                           | charging stations number of phase(s)                                                                                                  |
+| numberOfConnectors                |            |                 | integer\|integer[]                | charging stations number of connector(s)                                                                                              |
+| useConnectorId0                   | true/false | true            | boolean                           | use connector id 0 definition from the template                                                                                       |
+| randomConnectors                  | true/false | false           | boolean                           | randomize runtime connector id affectation from the connector id definition in template                                               |
+| resetTime                         |            | 60              | integer                           | seconds to wait before the charging stations come back at reset                                                                       |
+| autoRegister                      | true/false | false           | boolean                           | set the charging station as registered at boot notification for testing purpose                                                       |
+| autoReconnectMaxRetries           |            | -1 (unlimited)  | integer                           | connection retries to the OCPP-J server                                                                                               |
+| reconnectExponentialDelay         | true/false | false           | boolean                           | connection delay retry to the OCPP-J server                                                                                           |
+| registrationMaxRetries            |            | -1 (unlimited)  | integer                           | charging stations boot notification retries                                                                                           |
+| enableStatistics                  | true/false | true            | boolean                           | enable charging stations statistics                                                                                                   |
+| mayAuthorizeAtRemoteStart         | true/false | true            | boolean                           | always send authorize at remote start transaction when AuthorizeRemoteTxRequests is enabled                                           |
+| beginEndMeterValues               | true/false | false           | boolean                           | enable Transaction.{Begin,End} MeterValues                                                                                            |
+| outOfOrderEndMeterValues          | true/false | false           | boolean                           | send Transaction.End MeterValues out of order. Need to relax OCPP specifications strict compliance ('ocppStrictCompliance' parameter) |
+| meteringPerTransaction            | true/false | true            | boolean                           | enable metering history on a per transaction basis                                                                                    |
+| transactionDataMeterValues        | true/false | false           | boolean                           | enable transaction data MeterValues at stop transaction                                                                               |
+| mainVoltageMeterValues            | true/false | true            | boolean                           | include charging station main voltage MeterValues on three phased charging stations                                                   |
+| phaseLineToLineVoltageMeterValues | true/false | true            | boolean                           | include charging station line to line voltage MeterValues on three phased charging stations                                           |
+| Configuration                     |            |                 | ChargingStationConfiguration      | charging stations OCPP parameters configuration section                                                                               |
+| AutomaticTransactionGenerator     |            |                 | AutomaticTransactionGenerator     | charging stations ATG configuration section                                                                                           |
+| Connectors                        |            |                 | Connectors                        | charging stations connectors configuration section                                                                                    |
 
 #### Configuration section
 
@@ -169,6 +170,7 @@ Connectors | | | Connectors | charging stations connectors configuration section
     "requireAuthorize": true
   }
 ```
+
 #### Connectors section
 
 ```json
@@ -270,7 +272,7 @@ make SUBMODULES_INIT=true
 
 ## OCPP-J standard parameters supported
 
-All kind of OCPP parameters are supported in a charging station template. The list here mention the standard ones also handled automatically in the simulator. 
+All kind of OCPP parameters are supported in a charging station template. The list here mention the standard ones also handled automatically in the simulator.
 
 ### Version 1.6
 
@@ -301,7 +303,7 @@ All kind of OCPP parameters are supported in a charging station template. The li
 
 #### Firmware Management Profile
 
-- *none*
+- _none_
 
 #### Local Auth List Management Profile
 
@@ -311,7 +313,7 @@ All kind of OCPP parameters are supported in a charging station template. The li
 
 #### Reservation Profile
 
-- *none*
+- _none_
 
 #### Smart Charging Profile
 
@@ -322,7 +324,7 @@ All kind of OCPP parameters are supported in a charging station template. The li
 
 #### Remote Trigger Profile
 
-- *none*
+- _none_
 
 ## License
 
index a4f881775288fffc085d03edce8a32ded8a8bc68..9a4c6acb8de7ec03ea6608a70a13549ea70b0b3a 100644 (file)
@@ -1,6 +1,6 @@
 version: 0.2
 parameter-store:
-  build_ssh_key: "/CodeBuild/emobility_build_ssh_key"
+  build_ssh_key: '/CodeBuild/emobility_build_ssh_key'
 phases:
   install:
     runtime-versions:
index 292f8b628f743b943164db71b47b4b376c928a44..9c4efe3a8843fa0cc52f15282bfa9aa9cd95a637 100644 (file)
@@ -1,7 +1,5 @@
 {
-  "supervisionUrls": [
-    "ws://server:8010/OCPP16/5c866e81a2d9593de43efdb4"
-  ],
+  "supervisionUrls": ["ws://server:8010/OCPP16/5c866e81a2d9593de43efdb4"],
   "distributeStationsToTenantsEqually": true,
   "workerProcess": "workerSet",
   "workerPoolMinSize": 4,
index e5f15405915d91a4dc03b3d1cff6925e0072a905..aeb21df7a726832c077be2e7768d2a727b255cd1 100644 (file)
@@ -1,14 +1,14 @@
 applications:
-- name: charging-stations-simulator
-  memory: 1G
-  disk_quota: 1G
-  instances: 1
-  buildpacks:
-  - https://github.com/cloudfoundry/nodejs-buildpack
-  no-route: true
-  health-check-type: process
-  health-check-invocation-timeout: 10
-  command: node -r source-map-support/register dist/start.js
-  env:
-    # OPTIMIZE_MEMORY: true
-    NODE_OPTIONS: --stack-trace-limit=1024 --max-old-space-size=768
+  - name: charging-stations-simulator
+    memory: 1G
+    disk_quota: 1G
+    instances: 1
+    buildpacks:
+      - https://github.com/cloudfoundry/nodejs-buildpack
+    no-route: true
+    health-check-type: process
+    health-check-invocation-timeout: 10
+    command: node -r source-map-support/register dist/start.js
+    env:
+      # OPTIMIZE_MEMORY: true
+      NODE_OPTIONS: --stack-trace-limit=1024 --max-old-space-size=768
index 0c24f054f655e1509d681dac4f3856d8442d8bf5..ab28c40a42d05baff18a1d4834a6a25ae35f965c 100644 (file)
@@ -8,5 +8,8 @@ export default {
   metadataProvider: TsMorphMetadataProvider,
   entities: [PerformanceRecord, PerformanceData],
   type: 'sqlite',
-  clientUrl: `file://${path.join(path.resolve(__dirname), `${Constants.DEFAULT_PERFORMANCE_RECORDS_DB_NAME}.db`)}`
+  clientUrl: `file://${path.join(
+    path.resolve(__dirname),
+    `${Constants.DEFAULT_PERFORMANCE_RECORDS_DB_NAME}.db`
+  )}`,
 };
index 03b68e6a3a3bdc6cd9ce43a77f35ee1089494463..eb81da6e3385a23487b1e78cf84622fc8474d44f 100644 (file)
@@ -43,6 +43,7 @@
         "clinic": "^11.1.0",
         "cross-env": "^7.0.3",
         "eslint": "^8.10.0",
+        "eslint-config-prettier": "^8.5.0",
         "eslint-plugin-import": "^2.25.4",
         "eslint-plugin-jsdoc": "^37.9.6",
         "eslint-plugin-node": "^11.1.0",
@@ -51,6 +52,7 @@
         "mochawesome": "^7.1.1",
         "npm-check": "^5.9.2",
         "nyc": "^15.1.0",
+        "prettier": "^2.5.1",
         "release-it": "^14.12.5",
         "robohydra": "^0.6.9",
         "rollup": "^2.69.0",
         "url": "https://opencollective.com/eslint"
       }
     },
+    "node_modules/eslint-config-prettier": {
+      "version": "8.5.0",
+      "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz",
+      "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==",
+      "dev": true,
+      "bin": {
+        "eslint-config-prettier": "bin/cli.js"
+      },
+      "peerDependencies": {
+        "eslint": ">=7.0.0"
+      }
+    },
     "node_modules/eslint-import-resolver-node": {
       "version": "0.3.6",
       "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz",
         "node": ">=0.10.0"
       }
     },
+    "node_modules/prettier": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz",
+      "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==",
+      "dev": true,
+      "bin": {
+        "prettier": "bin-prettier.js"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
     "node_modules/pretty-bytes": {
       "version": "5.6.0",
       "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz",
         }
       }
     },
+    "eslint-config-prettier": {
+      "version": "8.5.0",
+      "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz",
+      "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==",
+      "dev": true,
+      "requires": {}
+    },
     "eslint-import-resolver-node": {
       "version": "0.3.6",
       "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz",
       "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=",
       "dev": true
     },
+    "prettier": {
+      "version": "2.5.1",
+      "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz",
+      "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==",
+      "dev": true
+    },
     "pretty-bytes": {
       "version": "5.6.0",
       "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz",
index 0056f899ce2bc4d30a03fbfaa6f80dac384dcb17..d1589d37e4540e5073c124211dfcffdebb1cf344 100644 (file)
@@ -53,6 +53,7 @@
     "build:dev:watch": "npm run rollup -- --environment BUILD:development --watch",
     "lint": "cross-env TIMING=1 eslint --ext .js,.ts src",
     "lint:fix": "cross-env TIMING=1 eslint --fix --ext .js,.ts src",
+    "format": "prettier --write .",
     "import-sort": "npx import-sort-cli --write 'src/**/*.ts{,x}'",
     "test": "cross-env TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\"}' nyc mocha test/**/*Test.ts",
     "coverage": "nyc report --reporter=lcov",
     "clinic": "^11.1.0",
     "cross-env": "^7.0.3",
     "eslint": "^8.10.0",
+    "eslint-config-prettier": "^8.5.0",
     "eslint-plugin-import": "^2.25.4",
     "eslint-plugin-jsdoc": "^37.9.6",
     "eslint-plugin-node": "^11.1.0",
     "mochawesome": "^7.1.1",
     "npm-check": "^5.9.2",
     "nyc": "^15.1.0",
+    "prettier": "^2.5.1",
     "release-it": "^14.12.5",
     "robohydra": "^0.6.9",
     "rollup": "^2.69.0",
index 3900559c0e016c2a482f2a7b56a5acc450402b5e..b1114284ea7bbe9d5d596fd46d04ce11f3a8a2e4 100644 (file)
@@ -10,32 +10,50 @@ const isDevelopmentBuild = process.env.BUILD === 'development';
 
 export default {
   input: ['src/start.ts', 'src/charging-station/ChargingStationWorker.ts'],
-  output:
-  {
+  output: {
     dir: 'dist',
     format: 'cjs',
     exports: 'auto',
     sourcemap: true,
     preserveModules: true,
     preserveModulesRoot: 'src',
-    ...!isDevelopmentBuild && { plugins: [terser({ numWorkers: 2 })] }
+    ...(!isDevelopmentBuild && { plugins: [terser({ numWorkers: 2 })] }),
   },
-  external: ['basic-ftp', 'chalk', 'crypto', 'fs', '@mikro-orm/core', '@mikro-orm/reflection', 'mongodb', 'path', 'perf_hooks', 'poolifier', 'proper-lockfile', 'reflect-metadata', 'tar', 'url', 'uuid', 'ws', 'winston-daily-rotate-file', 'winston/lib/winston/transports', 'winston', 'worker_threads'],
+  external: [
+    'basic-ftp',
+    'chalk',
+    'crypto',
+    'fs',
+    '@mikro-orm/core',
+    '@mikro-orm/reflection',
+    'mongodb',
+    'path',
+    'perf_hooks',
+    'poolifier',
+    'proper-lockfile',
+    'reflect-metadata',
+    'tar',
+    'url',
+    'uuid',
+    'ws',
+    'winston-daily-rotate-file',
+    'winston/lib/winston/transports',
+    'winston',
+    'worker_threads',
+  ],
   plugins: [
     json(),
     ts({
       tsconfig: 'tsconfig.json',
-      browserslist: false
+      browserslist: false,
     }),
     isDevelopmentBuild && istanbul(),
     del({
-      targets: 'dist/*'
+      targets: 'dist/*',
     }),
     copy({
-      targets: [
-        { src: 'src/assets', dest: 'dist/' }
-      ]
+      targets: [{ src: 'src/assets', dest: 'dist/' }],
     }),
-    isDevelopmentBuild && analyze()
-  ]
+    isDevelopmentBuild && analyze(),
+  ],
 };
index 25c39854d441c31b1e039018e8af3b409f06c409..f4264f02cf2403604f236af095d880383420a820 100644 (file)
@@ -1,4 +1 @@
-[
-  "UNDEFINED",
-  "BB2TBR09"
-]
+["UNDEFINED", "BB2TBR09"]
index 4520a2d49fed76f6c21143dd08c4f96551154c2c..839750ac56f5673256ead64c5fbd11580a902b42 100644 (file)
@@ -1,7 +1,5 @@
 {
-  "supervisionUrls": [
-    "ws://localhost:8010/OCPP16/5be7fb271014d90008992f06"
-  ],
+  "supervisionUrls": ["ws://localhost:8010/OCPP16/5be7fb271014d90008992f06"],
   "supervisionUrlDistribution": "sequential",
   "performanceStorage": {
     "enabled": true,
index 0e0982a201dd7165f39212dc3acaba7b8e893002..b9d3f1d0f24f8b0898551bb0bf8c68be378afb49 100644 (file)
@@ -1,6 +1,12 @@
 // Partial Copyright Jerome Benoit. 2021. All Rights Reserved.
 
-import { AuthorizationStatus, AuthorizeResponse, StartTransactionResponse, StopTransactionReason, StopTransactionResponse } from '../types/ocpp/Transaction';
+import {
+  AuthorizationStatus,
+  AuthorizeResponse,
+  StartTransactionResponse,
+  StopTransactionReason,
+  StopTransactionResponse,
+} from '../types/ocpp/Transaction';
 
 import type ChargingStation from './ChargingStation';
 import Constants from '../utils/Constants';
@@ -10,7 +16,10 @@ import Utils from '../utils/Utils';
 import logger from '../utils/Logger';
 
 export default class AutomaticTransactionGenerator {
-  private static readonly instances: Map<string, AutomaticTransactionGenerator> = new Map<string, AutomaticTransactionGenerator>();
+  private static readonly instances: Map<string, AutomaticTransactionGenerator> = new Map<
+    string,
+    AutomaticTransactionGenerator
+  >();
   public started: boolean;
   private readonly chargingStation: ChargingStation;
   private readonly connectorsStatus: Map<number, Status>;
@@ -24,7 +33,10 @@ export default class AutomaticTransactionGenerator {
 
   public static getInstance(chargingStation: ChargingStation): AutomaticTransactionGenerator {
     if (!AutomaticTransactionGenerator.instances.has(chargingStation.id)) {
-      AutomaticTransactionGenerator.instances.set(chargingStation.id, new AutomaticTransactionGenerator(chargingStation));
+      AutomaticTransactionGenerator.instances.set(
+        chargingStation.id,
+        new AutomaticTransactionGenerator(chargingStation)
+      );
     }
     return AutomaticTransactionGenerator.instances.get(chargingStation.id);
   }
@@ -48,7 +60,10 @@ export default class AutomaticTransactionGenerator {
   }
 
   private startConnectors(): void {
-    if (this.connectorsStatus?.size > 0 && this.connectorsStatus.size !== this.chargingStation.getNumberOfConnectors()) {
+    if (
+      this.connectorsStatus?.size > 0 &&
+      this.connectorsStatus.size !== this.chargingStation.getNumberOfConnectors()
+    ) {
       this.connectorsStatus.clear();
     }
     for (const connectorId of this.chargingStation.connectors.keys()) {
@@ -68,39 +83,69 @@ export default class AutomaticTransactionGenerator {
 
   private async internalStartConnector(connectorId: number): Promise<void> {
     this.initStartConnectorStatus(connectorId);
-    logger.info(this.logPrefix(connectorId) + ' started on connector and will run for ' + Utils.formatDurationMilliSeconds(this.connectorsStatus.get(connectorId).stopDate.getTime() - this.connectorsStatus.get(connectorId).startDate.getTime()));
+    logger.info(
+      this.logPrefix(connectorId) +
+        ' started on connector and will run for ' +
+        Utils.formatDurationMilliSeconds(
+          this.connectorsStatus.get(connectorId).stopDate.getTime() -
+            this.connectorsStatus.get(connectorId).startDate.getTime()
+        )
+    );
     while (this.connectorsStatus.get(connectorId).start) {
-      if ((new Date()) > this.connectorsStatus.get(connectorId).stopDate) {
+      if (new Date() > this.connectorsStatus.get(connectorId).stopDate) {
         this.stopConnector(connectorId);
         break;
       }
       if (!this.chargingStation.isInAcceptedState()) {
-        logger.error(this.logPrefix(connectorId) + ' entered in transaction loop while the charging station is not in accepted state');
+        logger.error(
+          this.logPrefix(connectorId) +
+            ' entered in transaction loop while the charging station is not in accepted state'
+        );
         this.stopConnector(connectorId);
         break;
       }
       if (!this.chargingStation.isChargingStationAvailable()) {
-        logger.info(this.logPrefix(connectorId) + ' entered in transaction loop while the charging station is unavailable');
+        logger.info(
+          this.logPrefix(connectorId) +
+            ' entered in transaction loop while the charging station is unavailable'
+        );
         this.stopConnector(connectorId);
         break;
       }
       if (!this.chargingStation.isConnectorAvailable(connectorId)) {
-        logger.info(`${this.logPrefix(connectorId)} entered in transaction loop while the connector ${connectorId} is unavailable`);
+        logger.info(
+          `${this.logPrefix(
+            connectorId
+          )} entered in transaction loop while the connector ${connectorId} is unavailable`
+        );
         this.stopConnector(connectorId);
         break;
       }
       if (!this.chargingStation?.ocppRequestService) {
-        logger.info(`${this.logPrefix(connectorId)} transaction loop waiting for charging station service to be initialized`);
+        logger.info(
+          `${this.logPrefix(
+            connectorId
+          )} transaction loop waiting for charging station service to be initialized`
+        );
         do {
           await Utils.sleep(Constants.CHARGING_STATION_ATG_INITIALIZATION_TIME);
         } while (!this.chargingStation?.ocppRequestService);
       }
-      const wait = Utils.getRandomInteger(this.chargingStation.stationInfo.AutomaticTransactionGenerator.maxDelayBetweenTwoTransactions,
-        this.chargingStation.stationInfo.AutomaticTransactionGenerator.minDelayBetweenTwoTransactions) * 1000;
-      logger.info(this.logPrefix(connectorId) + ' waiting for ' + Utils.formatDurationMilliSeconds(wait));
+      const wait =
+        Utils.getRandomInteger(
+          this.chargingStation.stationInfo.AutomaticTransactionGenerator
+            .maxDelayBetweenTwoTransactions,
+          this.chargingStation.stationInfo.AutomaticTransactionGenerator
+            .minDelayBetweenTwoTransactions
+        ) * 1000;
+      logger.info(
+        this.logPrefix(connectorId) + ' waiting for ' + Utils.formatDurationMilliSeconds(wait)
+      );
       await Utils.sleep(wait);
       const start = Utils.secureRandom();
-      if (start < this.chargingStation.stationInfo.AutomaticTransactionGenerator.probabilityOfStart) {
+      if (
+        start < this.chargingStation.stationInfo.AutomaticTransactionGenerator.probabilityOfStart
+      ) {
         this.connectorsStatus.get(connectorId).skippedConsecutiveTransactions = 0;
         // Start transaction
         const startResponse = await this.startTransaction(connectorId);
@@ -110,60 +155,113 @@ export default class AutomaticTransactionGenerator {
           this.connectorsStatus.get(connectorId).rejectedStartTransactionRequests++;
         } else {
           // Wait until end of transaction
-          const waitTrxEnd = Utils.getRandomInteger(this.chargingStation.stationInfo.AutomaticTransactionGenerator.maxDuration,
-            this.chargingStation.stationInfo.AutomaticTransactionGenerator.minDuration) * 1000;
-          logger.info(this.logPrefix(connectorId) + ' transaction ' + this.chargingStation.getConnectorStatus(connectorId).transactionId.toString() + ' started and will stop in ' + Utils.formatDurationMilliSeconds(waitTrxEnd));
+          const waitTrxEnd =
+            Utils.getRandomInteger(
+              this.chargingStation.stationInfo.AutomaticTransactionGenerator.maxDuration,
+              this.chargingStation.stationInfo.AutomaticTransactionGenerator.minDuration
+            ) * 1000;
+          logger.info(
+            this.logPrefix(connectorId) +
+              ' transaction ' +
+              this.chargingStation.getConnectorStatus(connectorId).transactionId.toString() +
+              ' started and will stop in ' +
+              Utils.formatDurationMilliSeconds(waitTrxEnd)
+          );
           this.connectorsStatus.get(connectorId).acceptedStartTransactionRequests++;
           await Utils.sleep(waitTrxEnd);
           // Stop transaction
-          logger.info(this.logPrefix(connectorId) + ' stop transaction ' + this.chargingStation.getConnectorStatus(connectorId).transactionId.toString());
+          logger.info(
+            this.logPrefix(connectorId) +
+              ' stop transaction ' +
+              this.chargingStation.getConnectorStatus(connectorId).transactionId.toString()
+          );
           await this.stopTransaction(connectorId);
         }
       } else {
         this.connectorsStatus.get(connectorId).skippedConsecutiveTransactions++;
         this.connectorsStatus.get(connectorId).skippedTransactions++;
-        logger.info(this.logPrefix(connectorId) + ' skipped consecutively ' + this.connectorsStatus.get(connectorId).skippedConsecutiveTransactions.toString() + '/' + this.connectorsStatus.get(connectorId).skippedTransactions.toString() + ' transaction(s)');
+        logger.info(
+          this.logPrefix(connectorId) +
+            ' skipped consecutively ' +
+            this.connectorsStatus.get(connectorId).skippedConsecutiveTransactions.toString() +
+            '/' +
+            this.connectorsStatus.get(connectorId).skippedTransactions.toString() +
+            ' transaction(s)'
+        );
       }
       this.connectorsStatus.get(connectorId).lastRunDate = new Date();
     }
     await this.stopTransaction(connectorId);
     this.connectorsStatus.get(connectorId).stoppedDate = new Date();
-    logger.info(this.logPrefix(connectorId) + ' stopped on connector and lasted for ' + Utils.formatDurationMilliSeconds(this.connectorsStatus.get(connectorId).stoppedDate.getTime() - this.connectorsStatus.get(connectorId).startDate.getTime()));
-    logger.debug(`${this.logPrefix(connectorId)} connector status %j`, this.connectorsStatus.get(connectorId));
+    logger.info(
+      this.logPrefix(connectorId) +
+        ' stopped on connector and lasted for ' +
+        Utils.formatDurationMilliSeconds(
+          this.connectorsStatus.get(connectorId).stoppedDate.getTime() -
+            this.connectorsStatus.get(connectorId).startDate.getTime()
+        )
+    );
+    logger.debug(
+      `${this.logPrefix(connectorId)} connector status %j`,
+      this.connectorsStatus.get(connectorId)
+    );
   }
 
   private startConnector(connectorId: number): void {
     // Avoid hogging the event loop with a busy loop
     setImmediate(() => {
-      this.internalStartConnector(connectorId).catch(() => { /* This is intentional */ });
+      this.internalStartConnector(connectorId).catch(() => {
+        /* This is intentional */
+      });
     });
   }
 
   private stopConnector(connectorId: number): void {
-    this.connectorsStatus.set(connectorId, { ...this.connectorsStatus.get(connectorId), start: false });
+    this.connectorsStatus.set(connectorId, {
+      ...this.connectorsStatus.get(connectorId),
+      start: false,
+    });
   }
 
   private initStartConnectorStatus(connectorId: number): void {
-    this.connectorsStatus.get(connectorId).authorizeRequests = this?.connectorsStatus.get(connectorId)?.authorizeRequests ?? 0;
-    this.connectorsStatus.get(connectorId).acceptedAuthorizeRequests = this?.connectorsStatus.get(connectorId)?.acceptedAuthorizeRequests ?? 0;
-    this.connectorsStatus.get(connectorId).rejectedAuthorizeRequests = this?.connectorsStatus.get(connectorId)?.rejectedAuthorizeRequests ?? 0;
-    this.connectorsStatus.get(connectorId).startTransactionRequests = this?.connectorsStatus.get(connectorId)?.startTransactionRequests ?? 0;
-    this.connectorsStatus.get(connectorId).acceptedStartTransactionRequests = this?.connectorsStatus.get(connectorId)?.acceptedStartTransactionRequests ?? 0;
-    this.connectorsStatus.get(connectorId).rejectedStartTransactionRequests = this?.connectorsStatus.get(connectorId)?.rejectedStartTransactionRequests ?? 0;
-    this.connectorsStatus.get(connectorId).stopTransactionRequests = this?.connectorsStatus.get(connectorId)?.stopTransactionRequests ?? 0;
+    this.connectorsStatus.get(connectorId).authorizeRequests =
+      this?.connectorsStatus.get(connectorId)?.authorizeRequests ?? 0;
+    this.connectorsStatus.get(connectorId).acceptedAuthorizeRequests =
+      this?.connectorsStatus.get(connectorId)?.acceptedAuthorizeRequests ?? 0;
+    this.connectorsStatus.get(connectorId).rejectedAuthorizeRequests =
+      this?.connectorsStatus.get(connectorId)?.rejectedAuthorizeRequests ?? 0;
+    this.connectorsStatus.get(connectorId).startTransactionRequests =
+      this?.connectorsStatus.get(connectorId)?.startTransactionRequests ?? 0;
+    this.connectorsStatus.get(connectorId).acceptedStartTransactionRequests =
+      this?.connectorsStatus.get(connectorId)?.acceptedStartTransactionRequests ?? 0;
+    this.connectorsStatus.get(connectorId).rejectedStartTransactionRequests =
+      this?.connectorsStatus.get(connectorId)?.rejectedStartTransactionRequests ?? 0;
+    this.connectorsStatus.get(connectorId).stopTransactionRequests =
+      this?.connectorsStatus.get(connectorId)?.stopTransactionRequests ?? 0;
     this.connectorsStatus.get(connectorId).skippedConsecutiveTransactions = 0;
-    this.connectorsStatus.get(connectorId).skippedTransactions = this?.connectorsStatus.get(connectorId)?.skippedTransactions ?? 0;
-    const previousRunDuration = (this?.connectorsStatus.get(connectorId)?.startDate && this?.connectorsStatus.get(connectorId)?.lastRunDate)
-      ? (this.connectorsStatus.get(connectorId).lastRunDate.getTime() - this.connectorsStatus.get(connectorId).startDate.getTime())
-      : 0;
+    this.connectorsStatus.get(connectorId).skippedTransactions =
+      this?.connectorsStatus.get(connectorId)?.skippedTransactions ?? 0;
+    const previousRunDuration =
+      this?.connectorsStatus.get(connectorId)?.startDate &&
+      this?.connectorsStatus.get(connectorId)?.lastRunDate
+        ? this.connectorsStatus.get(connectorId).lastRunDate.getTime() -
+          this.connectorsStatus.get(connectorId).startDate.getTime()
+        : 0;
     this.connectorsStatus.get(connectorId).startDate = new Date();
-    this.connectorsStatus.get(connectorId).stopDate = new Date(this.connectorsStatus.get(connectorId).startDate.getTime()
-      + (this.chargingStation.stationInfo?.AutomaticTransactionGenerator?.stopAfterHours ?? Constants.CHARGING_STATION_ATG_DEFAULT_STOP_AFTER_HOURS) * 3600 * 1000
-      - previousRunDuration);
+    this.connectorsStatus.get(connectorId).stopDate = new Date(
+      this.connectorsStatus.get(connectorId).startDate.getTime() +
+        (this.chargingStation.stationInfo?.AutomaticTransactionGenerator?.stopAfterHours ??
+          Constants.CHARGING_STATION_ATG_DEFAULT_STOP_AFTER_HOURS) *
+          3600 *
+          1000 -
+        previousRunDuration
+    );
     this.connectorsStatus.get(connectorId).start = true;
   }
 
-  private async startTransaction(connectorId: number): Promise<StartTransactionResponse | AuthorizeResponse> {
+  private async startTransaction(
+    connectorId: number
+  ): Promise<StartTransactionResponse | AuthorizeResponse> {
     const measureId = 'StartTransaction with ATG';
     const beginId = PerformanceStatistics.beginMeasure(measureId);
     let startResponse: StartTransactionResponse;
@@ -171,13 +269,19 @@ export default class AutomaticTransactionGenerator {
       const idTag = this.chargingStation.getRandomIdTag();
       if (this.chargingStation.getAutomaticTransactionGeneratorRequireAuthorize()) {
         // Authorize idTag
-        const authorizeResponse = await this.chargingStation.ocppRequestService.sendAuthorize(connectorId, idTag);
+        const authorizeResponse = await this.chargingStation.ocppRequestService.sendAuthorize(
+          connectorId,
+          idTag
+        );
         this.connectorsStatus.get(connectorId).authorizeRequests++;
         if (authorizeResponse?.idTagInfo?.status === AuthorizationStatus.ACCEPTED) {
           this.connectorsStatus.get(connectorId).acceptedAuthorizeRequests++;
           logger.info(this.logPrefix(connectorId) + ' start transaction for idTag ' + idTag);
           // Start transaction
-          startResponse = await this.chargingStation.ocppRequestService.sendStartTransaction(connectorId, idTag);
+          startResponse = await this.chargingStation.ocppRequestService.sendStartTransaction(
+            connectorId,
+            idTag
+          );
           PerformanceStatistics.endMeasure(measureId, beginId);
           return startResponse;
         }
@@ -187,7 +291,10 @@ export default class AutomaticTransactionGenerator {
       }
       logger.info(this.logPrefix(connectorId) + ' start transaction for idTag ' + idTag);
       // Start transaction
-      startResponse = await this.chargingStation.ocppRequestService.sendStartTransaction(connectorId, idTag);
+      startResponse = await this.chargingStation.ocppRequestService.sendStartTransaction(
+        connectorId,
+        idTag
+      );
       PerformanceStatistics.endMeasure(measureId, beginId);
       return startResponse;
     }
@@ -197,20 +304,29 @@ export default class AutomaticTransactionGenerator {
     return startResponse;
   }
 
-  private async stopTransaction(connectorId: number, reason: StopTransactionReason = StopTransactionReason.NONE): Promise<StopTransactionResponse> {
+  private async stopTransaction(
+    connectorId: number,
+    reason: StopTransactionReason = StopTransactionReason.NONE
+  ): Promise<StopTransactionResponse> {
     const measureId = 'StopTransaction with ATG';
     const beginId = PerformanceStatistics.beginMeasure(measureId);
     let transactionId = 0;
     let stopResponse: StopTransactionResponse;
     if (this.chargingStation.getConnectorStatus(connectorId)?.transactionStarted) {
       transactionId = this.chargingStation.getConnectorStatus(connectorId).transactionId;
-      stopResponse = await this.chargingStation.ocppRequestService.sendStopTransaction(transactionId,
+      stopResponse = await this.chargingStation.ocppRequestService.sendStopTransaction(
+        transactionId,
         this.chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId),
         this.chargingStation.getTransactionIdTag(transactionId),
-        reason);
+        reason
+      );
       this.connectorsStatus.get(connectorId).stopTransactionRequests++;
     } else {
-      logger.warn(`${this.logPrefix(connectorId)} trying to stop a not started transaction${transactionId ? ' ' + transactionId.toString() : ''}`);
+      logger.warn(
+        `${this.logPrefix(connectorId)} trying to stop a not started transaction${
+          transactionId ? ' ' + transactionId.toString() : ''
+        }`
+      );
     }
     PerformanceStatistics.endMeasure(measureId, beginId);
     return stopResponse;
@@ -218,7 +334,13 @@ export default class AutomaticTransactionGenerator {
 
   private logPrefix(connectorId?: number): string {
     if (connectorId) {
-      return Utils.logPrefix(' ' + this.chargingStation.stationInfo.chargingStationId + ' | ATG on connector #' + connectorId.toString() + ':');
+      return Utils.logPrefix(
+        ' ' +
+          this.chargingStation.stationInfo.chargingStationId +
+          ' | ATG on connector #' +
+          connectorId.toString() +
+          ':'
+      );
     }
     return Utils.logPrefix(' ' + this.chargingStation.stationInfo.chargingStationId + ' | ATG:');
   }
index fa8f73ebda6b40e238fd8e09ab8d77e8d558ef7b..d39c705c89e19334dd95d8654e5126fc40228406 100644 (file)
@@ -1,6 +1,10 @@
 // Partial Copyright Jerome Benoit. 2021. All Rights Reserved.
 
-import { ChargingStationWorkerData, ChargingStationWorkerMessage, ChargingStationWorkerMessageEvents } from '../types/ChargingStationWorker';
+import {
+  ChargingStationWorkerData,
+  ChargingStationWorkerMessage,
+  ChargingStationWorkerMessageEvents,
+} from '../types/ChargingStationWorker';
 
 import Configuration from '../utils/Configuration';
 import { StationTemplateUrl } from '../types/ConfigurationData';
@@ -29,16 +33,23 @@ export default class Bootstrap {
 
   private constructor() {
     this.started = false;
-    this.workerScript = path.join(path.resolve(__dirname, '../'), 'charging-station', 'ChargingStationWorker.js');
+    this.workerScript = path.join(
+      path.resolve(__dirname, '../'),
+      'charging-station',
+      'ChargingStationWorker.js'
+    );
     this.initWorkerImplementation();
-    Configuration.getUIWebSocketServer().enabled && (this.uiWebSocketServer = new UIWebSocketServer({
-      ...Configuration.getUIWebSocketServer().options, handleProtocols: UIServiceUtils.handleProtocols
-    }));
-    Configuration.getPerformanceStorage().enabled && (this.storage = StorageFactory.getStorage(
-      Configuration.getPerformanceStorage().type,
-      Configuration.getPerformanceStorage().uri,
-      this.logPrefix()
-    ));
+    Configuration.getUIWebSocketServer().enabled &&
+      (this.uiWebSocketServer = new UIWebSocketServer({
+        ...Configuration.getUIWebSocketServer().options,
+        handleProtocols: UIServiceUtils.handleProtocols,
+      }));
+    Configuration.getPerformanceStorage().enabled &&
+      (this.storage = StorageFactory.getStorage(
+        Configuration.getPerformanceStorage().type,
+        Configuration.getPerformanceStorage().uri,
+        this.logPrefix()
+      ));
     Configuration.setConfigurationChangeCallback(async () => Bootstrap.getInstance().restart());
   }
 
@@ -66,16 +77,39 @@ export default class Bootstrap {
                 await this.startChargingStation(index, stationTemplateUrl);
               }
             } catch (error) {
-              console.error(chalk.red('Charging station start with template file ' + stationTemplateUrl.file + ' error '), error);
+              console.error(
+                chalk.red(
+                  'Charging station start with template file ' + stationTemplateUrl.file + ' error '
+                ),
+                error
+              );
             }
           }
         } else {
           console.warn(chalk.yellow('No stationTemplateUrls defined in configuration, exiting'));
         }
         if (this.numberOfChargingStations === 0) {
-          console.warn(chalk.yellow('No charging station template enabled in configuration, exiting'));
+          console.warn(
+            chalk.yellow('No charging station template enabled in configuration, exiting')
+          );
         } else {
-          console.log(chalk.green(`Charging stations simulator ${this.version} started with ${this.numberOfChargingStations.toString()} charging station(s) and ${Utils.workerDynamicPoolInUse() ? `${Configuration.getWorkerPoolMinSize().toString()}/` : ''}${this.workerImplementation.size}${Utils.workerPoolInUse() ? `/${Configuration.getWorkerPoolMaxSize().toString()}` : ''} worker(s) concurrently running in '${Configuration.getWorkerProcess()}' mode${this.workerImplementation.maxElementsPerWorker ? ` (${this.workerImplementation.maxElementsPerWorker} charging station(s) per worker)` : ''}`));
+          console.log(
+            chalk.green(
+              `Charging stations simulator ${
+                this.version
+              } started with ${this.numberOfChargingStations.toString()} charging station(s) and ${
+                Utils.workerDynamicPoolInUse()
+                  ? `${Configuration.getWorkerPoolMinSize().toString()}/`
+                  : ''
+              }${this.workerImplementation.size}${
+                Utils.workerPoolInUse() ? `/${Configuration.getWorkerPoolMaxSize().toString()}` : ''
+              } worker(s) concurrently running in '${Configuration.getWorkerProcess()}' mode${
+                this.workerImplementation.maxElementsPerWorker
+                  ? ` (${this.workerImplementation.maxElementsPerWorker} charging station(s) per worker)`
+                  : ''
+              }`
+            )
+          );
         }
         this.started = true;
       } catch (error) {
@@ -104,7 +138,9 @@ export default class Bootstrap {
   }
 
   private initWorkerImplementation(): void {
-    this.workerImplementation = WorkerFactory.getWorkerImplementation<ChargingStationWorkerData>(this.workerScript, Configuration.getWorkerProcess(),
+    this.workerImplementation = WorkerFactory.getWorkerImplementation<ChargingStationWorkerData>(
+      this.workerScript,
+      Configuration.getWorkerProcess(),
       {
         workerStartDelay: Configuration.getWorkerStartDelay(),
         elementStartDelay: Configuration.getElementStartDelay(),
@@ -112,7 +148,7 @@ export default class Bootstrap {
         poolMinSize: Configuration.getWorkerPoolMinSize(),
         elementsPerWorker: Configuration.getChargingStationsPerWorker(),
         poolOptions: {
-          workerChoiceStrategy: Configuration.getWorkerPoolStrategy()
+          workerChoiceStrategy: Configuration.getWorkerPoolStrategy(),
         },
         messageHandler: async (msg: ChargingStationWorkerMessage) => {
           if (msg.id === ChargingStationWorkerMessageEvents.STARTED) {
@@ -122,14 +158,23 @@ export default class Bootstrap {
           } else if (msg.id === ChargingStationWorkerMessageEvents.PERFORMANCE_STATISTICS) {
             await this.storage.storePerformanceStatistics(msg.data as unknown as Statistics);
           }
-        }
-      });
+        },
+      }
+    );
   }
 
-  private async startChargingStation(index: number, stationTemplateUrl: StationTemplateUrl): Promise<void> {
+  private async startChargingStation(
+    index: number,
+    stationTemplateUrl: StationTemplateUrl
+  ): Promise<void> {
     const workerData: ChargingStationWorkerData = {
       index,
-      templateFile: path.join(path.resolve(__dirname, '../'), 'assets', 'station-templates', path.basename(stationTemplateUrl.file))
+      templateFile: path.join(
+        path.resolve(__dirname, '../'),
+        'assets',
+        'station-templates',
+        path.basename(stationTemplateUrl.file)
+      ),
     };
     await this.workerImplementation.addElement(workerData);
     this.numberOfChargingStations++;
index f7e654f94108ad41b1678695a56465e2ca113578..8d5cac1d7a2a886b553e5cb563eb22540e585fcf 100644 (file)
@@ -1,10 +1,28 @@
 // Partial Copyright Jerome Benoit. 2021. All Rights Reserved.
 
-import { AvailabilityType, BootNotificationRequest, CachedRequest, IncomingRequest, IncomingRequestCommand, RequestCommand } from '../types/ocpp/Requests';
+import {
+  AvailabilityType,
+  BootNotificationRequest,
+  CachedRequest,
+  IncomingRequest,
+  IncomingRequestCommand,
+  RequestCommand,
+} from '../types/ocpp/Requests';
 import { BootNotificationResponse, RegistrationStatus } from '../types/ocpp/Responses';
-import ChargingStationConfiguration, { ConfigurationKey } from '../types/ChargingStationConfiguration';
-import ChargingStationTemplate, { CurrentType, PowerUnits, Voltage } from '../types/ChargingStationTemplate';
-import { ConnectorPhaseRotation, StandardParametersKey, SupportedFeatureProfiles, VendorDefaultParametersKey } from '../types/ocpp/Configuration';
+import ChargingStationConfiguration, {
+  ConfigurationKey,
+} from '../types/ChargingStationConfiguration';
+import ChargingStationTemplate, {
+  CurrentType,
+  PowerUnits,
+  Voltage,
+} from '../types/ChargingStationTemplate';
+import {
+  ConnectorPhaseRotation,
+  StandardParametersKey,
+  SupportedFeatureProfiles,
+  VendorDefaultParametersKey,
+} from '../types/ocpp/Configuration';
 import { MeterValueMeasurand, MeterValuePhase } from '../types/ocpp/MeterValues';
 import { WSError, WebSocketCloseEventStatusCode } from '../types/WebSocket';
 import WebSocket, { ClientOptions, Data, OPEN } from 'ws';
@@ -81,7 +99,15 @@ export default class ChargingStation {
   }
 
   get wsConnectionUrl(): URL {
-    return this.getSupervisionUrlOcppConfiguration() ? new URL(this.getConfigurationKey(this.stationInfo.supervisionUrlOcppKey ?? VendorDefaultParametersKey.ConnectionUrl).value + '/' + this.stationInfo.chargingStationId) : this.wsConfiguredConnectionUrl;
+    return this.getSupervisionUrlOcppConfiguration()
+      ? new URL(
+          this.getConfigurationKey(
+            this.stationInfo.supervisionUrlOcppKey ?? VendorDefaultParametersKey.ConnectionUrl
+          ).value +
+            '/' +
+            this.stationInfo.chargingStationId
+        )
+      : this.wsConfiguredConnectionUrl;
   }
 
   public logPrefix(): string {
@@ -102,7 +128,9 @@ export default class ChargingStation {
   }
 
   public getEnableStatistics(): boolean | undefined {
-    return !Utils.isUndefined(this.stationInfo.enableStatistics) ? this.stationInfo.enableStatistics : true;
+    return !Utils.isUndefined(this.stationInfo.enableStatistics)
+      ? this.stationInfo.enableStatistics
+      : true;
   }
 
   public getMayAuthorizeAtRemoteStart(): boolean | undefined {
@@ -112,7 +140,9 @@ export default class ChargingStation {
   public getNumberOfPhases(): number | undefined {
     switch (this.getCurrentOutType()) {
       case CurrentType.AC:
-        return !Utils.isUndefined(this.stationInfo.numberOfPhases) ? this.stationInfo.numberOfPhases : 3;
+        return !Utils.isUndefined(this.stationInfo.numberOfPhases)
+          ? this.stationInfo.numberOfPhases
+          : 3;
       case CurrentType.DC:
         return 0;
     }
@@ -171,7 +201,9 @@ export default class ChargingStation {
   }
 
   public getVoltageOut(): number | undefined {
-    const errMsg = `${this.logPrefix()} Unknown ${this.getCurrentOutType()} currentOutType in template file ${this.stationTemplateFile}, cannot define default voltage out`;
+    const errMsg = `${this.logPrefix()} Unknown ${this.getCurrentOutType()} currentOutType in template file ${
+      this.stationTemplateFile
+    }, cannot define default voltage out`;
     let defaultVoltageOut: number;
     switch (this.getCurrentOutType()) {
       case CurrentType.AC:
@@ -184,7 +216,9 @@ export default class ChargingStation {
         logger.error(errMsg);
         throw new Error(errMsg);
     }
-    return !Utils.isUndefined(this.stationInfo.voltageOut) ? this.stationInfo.voltageOut : defaultVoltageOut;
+    return !Utils.isUndefined(this.stationInfo.voltageOut)
+      ? this.stationInfo.voltageOut
+      : defaultVoltageOut;
   }
 
   public getTransactionIdTag(transactionId: number): string | undefined {
@@ -222,7 +256,10 @@ export default class ChargingStation {
   public getEnergyActiveImportRegisterByTransactionId(transactionId: number): number | undefined {
     if (this.getMeteringPerTransaction()) {
       for (const connectorId of this.connectors.keys()) {
-        if (connectorId > 0 && this.getConnectorStatus(connectorId).transactionId === transactionId) {
+        if (
+          connectorId > 0 &&
+          this.getConnectorStatus(connectorId).transactionId === transactionId
+        ) {
           return this.getConnectorStatus(connectorId).transactionEnergyActiveImportRegisterValue;
         }
       }
@@ -242,12 +279,18 @@ export default class ChargingStation {
   }
 
   public getAuthorizeRemoteTxRequests(): boolean {
-    const authorizeRemoteTxRequests = this.getConfigurationKey(StandardParametersKey.AuthorizeRemoteTxRequests);
-    return authorizeRemoteTxRequests ? Utils.convertToBoolean(authorizeRemoteTxRequests.value) : false;
+    const authorizeRemoteTxRequests = this.getConfigurationKey(
+      StandardParametersKey.AuthorizeRemoteTxRequests
+    );
+    return authorizeRemoteTxRequests
+      ? Utils.convertToBoolean(authorizeRemoteTxRequests.value)
+      : false;
   }
 
   public getLocalAuthListEnabled(): boolean {
-    const localAuthListEnabled = this.getConfigurationKey(StandardParametersKey.LocalAuthListEnabled);
+    const localAuthListEnabled = this.getConfigurationKey(
+      StandardParametersKey.LocalAuthListEnabled
+    );
     return localAuthListEnabled ? Utils.convertToBoolean(localAuthListEnabled.value) : false;
   }
 
@@ -258,29 +301,70 @@ export default class ChargingStation {
     this.startWebSocketPing();
   }
 
-  public getSampledValueTemplate(connectorId: number, measurand: MeterValueMeasurand = MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER,
-      phase?: MeterValuePhase): SampledValueTemplate | undefined {
+  public getSampledValueTemplate(
+    connectorId: number,
+    measurand: MeterValueMeasurand = MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER,
+    phase?: MeterValuePhase
+  ): SampledValueTemplate | undefined {
     const onPhaseStr = phase ? `on phase ${phase} ` : '';
     if (!Constants.SUPPORTED_MEASURANDS.includes(measurand)) {
-      logger.warn(`${this.logPrefix()} Trying to get unsupported MeterValues measurand '${measurand}' ${onPhaseStr}in template on connectorId ${connectorId}`);
+      logger.warn(
+        `${this.logPrefix()} Trying to get unsupported MeterValues measurand '${measurand}' ${onPhaseStr}in template on connectorId ${connectorId}`
+      );
       return;
     }
-    if (measurand !== MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER && !this.getConfigurationKey(StandardParametersKey.MeterValuesSampledData).value.includes(measurand)) {
-      logger.debug(`${this.logPrefix()} Trying to get MeterValues measurand '${measurand}' ${onPhaseStr}in template on connectorId ${connectorId} not found in '${StandardParametersKey.MeterValuesSampledData}' OCPP parameter`);
+    if (
+      measurand !== MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER &&
+      !this.getConfigurationKey(StandardParametersKey.MeterValuesSampledData).value.includes(
+        measurand
+      )
+    ) {
+      logger.debug(
+        `${this.logPrefix()} Trying to get MeterValues measurand '${measurand}' ${onPhaseStr}in template on connectorId ${connectorId} not found in '${
+          StandardParametersKey.MeterValuesSampledData
+        }' OCPP parameter`
+      );
       return;
     }
-    const sampledValueTemplates: SampledValueTemplate[] = this.getConnectorStatus(connectorId).MeterValues;
-    for (let index = 0; !Utils.isEmptyArray(sampledValueTemplates) && index < sampledValueTemplates.length; index++) {
-      if (!Constants.SUPPORTED_MEASURANDS.includes(sampledValueTemplates[index]?.measurand ?? MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER)) {
-        logger.warn(`${this.logPrefix()} Unsupported MeterValues measurand '${measurand}' ${onPhaseStr}in template on connectorId ${connectorId}`);
-      } else if (phase && sampledValueTemplates[index]?.phase === phase && sampledValueTemplates[index]?.measurand === measurand
-        && this.getConfigurationKey(StandardParametersKey.MeterValuesSampledData).value.includes(measurand)) {
+    const sampledValueTemplates: SampledValueTemplate[] =
+      this.getConnectorStatus(connectorId).MeterValues;
+    for (
+      let index = 0;
+      !Utils.isEmptyArray(sampledValueTemplates) && index < sampledValueTemplates.length;
+      index++
+    ) {
+      if (
+        !Constants.SUPPORTED_MEASURANDS.includes(
+          sampledValueTemplates[index]?.measurand ??
+            MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
+        )
+      ) {
+        logger.warn(
+          `${this.logPrefix()} Unsupported MeterValues measurand '${measurand}' ${onPhaseStr}in template on connectorId ${connectorId}`
+        );
+      } else if (
+        phase &&
+        sampledValueTemplates[index]?.phase === phase &&
+        sampledValueTemplates[index]?.measurand === measurand &&
+        this.getConfigurationKey(StandardParametersKey.MeterValuesSampledData).value.includes(
+          measurand
+        )
+      ) {
         return sampledValueTemplates[index];
-      } else if (!phase && !sampledValueTemplates[index].phase && sampledValueTemplates[index]?.measurand === measurand
-        && this.getConfigurationKey(StandardParametersKey.MeterValuesSampledData).value.includes(measurand)) {
+      } else if (
+        !phase &&
+        !sampledValueTemplates[index].phase &&
+        sampledValueTemplates[index]?.measurand === measurand &&
+        this.getConfigurationKey(StandardParametersKey.MeterValuesSampledData).value.includes(
+          measurand
+        )
+      ) {
         return sampledValueTemplates[index];
-      } else if (measurand === MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
-        && (!sampledValueTemplates[index].measurand || sampledValueTemplates[index].measurand === measurand)) {
+      } else if (
+        measurand === MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER &&
+        (!sampledValueTemplates[index].measurand ||
+          sampledValueTemplates[index].measurand === measurand)
+      ) {
         return sampledValueTemplates[index];
       }
     }
@@ -289,7 +373,9 @@ export default class ChargingStation {
       logger.error(errorMsg);
       throw new Error(errorMsg);
     }
-    logger.debug(`${this.logPrefix()} No MeterValues for measurand '${measurand}' ${onPhaseStr}in template on connectorId ${connectorId}`);
+    logger.debug(
+      `${this.logPrefix()} No MeterValues for measurand '${measurand}' ${onPhaseStr}in template on connectorId ${connectorId}`
+    );
   }
 
   public getAutomaticTransactionGeneratorRequireAuthorize(): boolean {
@@ -297,16 +383,34 @@ export default class ChargingStation {
   }
 
   public startHeartbeat(): void {
-    if (this.getHeartbeatInterval() && this.getHeartbeatInterval() > 0 && !this.heartbeatSetInterval) {
+    if (
+      this.getHeartbeatInterval() &&
+      this.getHeartbeatInterval() > 0 &&
+      !this.heartbeatSetInterval
+    ) {
       // eslint-disable-next-line @typescript-eslint/no-misused-promises
       this.heartbeatSetInterval = setInterval(async (): Promise<void> => {
         await this.ocppRequestService.sendHeartbeat();
       }, this.getHeartbeatInterval());
-      logger.info(this.logPrefix() + ' Heartbeat started every ' + Utils.formatDurationMilliSeconds(this.getHeartbeatInterval()));
+      logger.info(
+        this.logPrefix() +
+          ' Heartbeat started every ' +
+          Utils.formatDurationMilliSeconds(this.getHeartbeatInterval())
+      );
     } else if (this.heartbeatSetInterval) {
-      logger.info(this.logPrefix() + ' Heartbeat already started every ' + Utils.formatDurationMilliSeconds(this.getHeartbeatInterval()));
+      logger.info(
+        this.logPrefix() +
+          ' Heartbeat already started every ' +
+          Utils.formatDurationMilliSeconds(this.getHeartbeatInterval())
+      );
     } else {
-      logger.error(`${this.logPrefix()} Heartbeat interval set to ${this.getHeartbeatInterval() ? Utils.formatDurationMilliSeconds(this.getHeartbeatInterval()) : this.getHeartbeatInterval()}, not starting the heartbeat`);
+      logger.error(
+        `${this.logPrefix()} Heartbeat interval set to ${
+          this.getHeartbeatInterval()
+            ? Utils.formatDurationMilliSeconds(this.getHeartbeatInterval())
+            : this.getHeartbeatInterval()
+        }, not starting the heartbeat`
+      );
     }
   }
 
@@ -319,27 +423,51 @@ export default class ChargingStation {
 
   public startMeterValues(connectorId: number, interval: number): void {
     if (connectorId === 0) {
-      logger.error(`${this.logPrefix()} Trying to start MeterValues on connector Id ${connectorId.toString()}`);
+      logger.error(
+        `${this.logPrefix()} Trying to start MeterValues on connector Id ${connectorId.toString()}`
+      );
       return;
     }
     if (!this.getConnectorStatus(connectorId)) {
-      logger.error(`${this.logPrefix()} Trying to start MeterValues on non existing connector Id ${connectorId.toString()}`);
+      logger.error(
+        `${this.logPrefix()} Trying to start MeterValues on non existing connector Id ${connectorId.toString()}`
+      );
       return;
     }
     if (!this.getConnectorStatus(connectorId)?.transactionStarted) {
-      logger.error(`${this.logPrefix()} Trying to start MeterValues on connector Id ${connectorId} with no transaction started`);
+      logger.error(
+        `${this.logPrefix()} Trying to start MeterValues on connector Id ${connectorId} with no transaction started`
+      );
       return;
-    } else if (this.getConnectorStatus(connectorId)?.transactionStarted && !this.getConnectorStatus(connectorId)?.transactionId) {
-      logger.error(`${this.logPrefix()} Trying to start MeterValues on connector Id ${connectorId} with no transaction id`);
+    } else if (
+      this.getConnectorStatus(connectorId)?.transactionStarted &&
+      !this.getConnectorStatus(connectorId)?.transactionId
+    ) {
+      logger.error(
+        `${this.logPrefix()} Trying to start MeterValues on connector Id ${connectorId} with no transaction id`
+      );
       return;
     }
     if (interval > 0) {
       // eslint-disable-next-line @typescript-eslint/no-misused-promises
-      this.getConnectorStatus(connectorId).transactionSetInterval = setInterval(async (): Promise<void> => {
-        await this.ocppRequestService.sendMeterValues(connectorId, this.getConnectorStatus(connectorId).transactionId, interval);
-      }, interval);
+      this.getConnectorStatus(connectorId).transactionSetInterval = setInterval(
+        async (): Promise<void> => {
+          await this.ocppRequestService.sendMeterValues(
+            connectorId,
+            this.getConnectorStatus(connectorId).transactionId,
+            interval
+          );
+        },
+        interval
+      );
     } else {
-      logger.error(`${this.logPrefix()} Charging station ${StandardParametersKey.MeterValueSampleInterval} configuration set to ${interval ? Utils.formatDurationMilliSeconds(interval) : interval}, not sending MeterValues`);
+      logger.error(
+        `${this.logPrefix()} Charging station ${
+          StandardParametersKey.MeterValueSampleInterval
+        } configuration set to ${
+          interval ? Utils.formatDurationMilliSeconds(interval) : interval
+        }, not sending MeterValues`
+      );
     }
   }
 
@@ -364,7 +492,10 @@ export default class ChargingStation {
     this.wsConnection.on('ping', this.onPing.bind(this));
     // Handle WebSocket pong
     this.wsConnection.on('pong', this.onPong.bind(this));
-    parentPort.postMessage({ id: ChargingStationWorkerMessageEvents.STARTED, data: { id: this.stationInfo.chargingStationId } });
+    parentPort.postMessage({
+      id: ChargingStationWorkerMessageEvents.STARTED,
+      data: { id: this.stationInfo.chargingStationId },
+    });
   }
 
   public async stop(reason: StopTransactionReason = StopTransactionReason.NONE): Promise<void> {
@@ -372,7 +503,10 @@ export default class ChargingStation {
     await this.stopMessageSequence(reason);
     for (const connectorId of this.connectors.keys()) {
       if (connectorId > 0) {
-        await this.ocppRequestService.sendStatusNotification(connectorId, ChargePointStatus.UNAVAILABLE);
+        await this.ocppRequestService.sendStatusNotification(
+          connectorId,
+          ChargePointStatus.UNAVAILABLE
+        );
         this.getConnectorStatus(connectorId).status = ChargePointStatus.UNAVAILABLE;
       }
     }
@@ -383,11 +517,17 @@ export default class ChargingStation {
       this.performanceStatistics.stop();
     }
     this.bootNotificationResponse = null;
-    parentPort.postMessage({ id: ChargingStationWorkerMessageEvents.STOPPED, data: { id: this.stationInfo.chargingStationId } });
+    parentPort.postMessage({
+      id: ChargingStationWorkerMessageEvents.STOPPED,
+      data: { id: this.stationInfo.chargingStationId },
+    });
     this.stopped = true;
   }
 
-  public getConfigurationKey(key: string | StandardParametersKey, caseInsensitive = false): ConfigurationKey | undefined {
+  public getConfigurationKey(
+    key: string | StandardParametersKey,
+    caseInsensitive = false
+  ): ConfigurationKey | undefined {
     return this.configuration.configurationKey.find((configElement) => {
       if (caseInsensitive) {
         return configElement.key.toLowerCase() === key.toLowerCase();
@@ -396,7 +536,15 @@ export default class ChargingStation {
     });
   }
 
-  public addConfigurationKey(key: string | StandardParametersKey, value: string, options: { readonly?: boolean, visible?: boolean, reboot?: boolean } = { readonly: false, visible: true, reboot: false }): void {
+  public addConfigurationKey(
+    key: string | StandardParametersKey,
+    value: string,
+    options: { readonly?: boolean; visible?: boolean; reboot?: boolean } = {
+      readonly: false,
+      visible: true,
+      reboot: false,
+    }
+  ): void {
     const keyFound = this.getConfigurationKey(key);
     const readonly = options.readonly;
     const visible = options.visible;
@@ -410,7 +558,10 @@ export default class ChargingStation {
         reboot,
       });
     } else {
-      logger.error(`${this.logPrefix()} Trying to add an already existing configuration key: %j`, keyFound);
+      logger.error(
+        `${this.logPrefix()} Trying to add an already existing configuration key: %j`,
+        keyFound
+      );
     }
   }
 
@@ -420,20 +571,28 @@ export default class ChargingStation {
       const keyIndex = this.configuration.configurationKey.indexOf(keyFound);
       this.configuration.configurationKey[keyIndex].value = value;
     } else {
-      logger.error(`${this.logPrefix()} Trying to set a value on a non existing configuration key: %j`, { key, value });
+      logger.error(
+        `${this.logPrefix()} Trying to set a value on a non existing configuration key: %j`,
+        { key, value }
+      );
     }
   }
 
   public setChargingProfile(connectorId: number, cp: ChargingProfile): void {
     let cpReplaced = false;
     if (!Utils.isEmptyArray(this.getConnectorStatus(connectorId).chargingProfiles)) {
-      this.getConnectorStatus(connectorId).chargingProfiles?.forEach((chargingProfile: ChargingProfile, index: number) => {
-        if (chargingProfile.chargingProfileId === cp.chargingProfileId
-          || (chargingProfile.stackLevel === cp.stackLevel && chargingProfile.chargingProfilePurpose === cp.chargingProfilePurpose)) {
-          this.getConnectorStatus(connectorId).chargingProfiles[index] = cp;
-          cpReplaced = true;
+      this.getConnectorStatus(connectorId).chargingProfiles?.forEach(
+        (chargingProfile: ChargingProfile, index: number) => {
+          if (
+            chargingProfile.chargingProfileId === cp.chargingProfileId ||
+            (chargingProfile.stackLevel === cp.stackLevel &&
+              chargingProfile.chargingProfilePurpose === cp.chargingProfilePurpose)
+          ) {
+            this.getConnectorStatus(connectorId).chargingProfiles[index] = cp;
+            cpReplaced = true;
+          }
         }
-      });
+      );
     }
     !cpReplaced && this.getConnectorStatus(connectorId).chargingProfiles?.push(cp);
   }
@@ -474,7 +633,15 @@ export default class ChargingStation {
     // In case of multiple instances: add instance index to charging station id
     const instanceIndex = process.env.CF_INSTANCE_INDEX ?? 0;
     const idSuffix = stationTemplate.nameSuffix ?? '';
-    return stationTemplate.fixedName ? stationTemplate.baseName : stationTemplate.baseName + '-' + instanceIndex.toString() + ('000000000' + this.index.toString()).substr(('000000000' + this.index.toString()).length - 4) + idSuffix;
+    return stationTemplate.fixedName
+      ? stationTemplate.baseName
+      : stationTemplate.baseName +
+          '-' +
+          instanceIndex.toString() +
+          ('000000000' + this.index.toString()).substr(
+            ('000000000' + this.index.toString()).length - 4
+          ) +
+          idSuffix;
   }
 
   private buildStationInfo(): ChargingStationInfo {
@@ -482,33 +649,51 @@ export default class ChargingStation {
     try {
       // Load template file
       const fileDescriptor = fs.openSync(this.stationTemplateFile, 'r');
-      stationTemplateFromFile = JSON.parse(fs.readFileSync(fileDescriptor, 'utf8')) as ChargingStationTemplate;
+      stationTemplateFromFile = JSON.parse(
+        fs.readFileSync(fileDescriptor, 'utf8')
+      ) as ChargingStationTemplate;
       fs.closeSync(fileDescriptor);
     } catch (error) {
-      FileUtils.handleFileException(this.logPrefix(), 'Template', this.stationTemplateFile, error as NodeJS.ErrnoException);
+      FileUtils.handleFileException(
+        this.logPrefix(),
+        'Template',
+        this.stationTemplateFile,
+        error as NodeJS.ErrnoException
+      );
     }
     const chargingStationId = this.getChargingStationId(stationTemplateFromFile);
     // Deprecation template keys section
-    this.warnDeprecatedTemplateKey(stationTemplateFromFile, 'supervisionUrl', chargingStationId, 'Use \'supervisionUrls\' instead');
+    this.warnDeprecatedTemplateKey(
+      stationTemplateFromFile,
+      'supervisionUrl',
+      chargingStationId,
+      "Use 'supervisionUrls' instead"
+    );
     this.convertDeprecatedTemplateKey(stationTemplateFromFile, 'supervisionUrl', 'supervisionUrls');
-    const stationInfo: ChargingStationInfo = stationTemplateFromFile ?? {} as ChargingStationInfo;
+    const stationInfo: ChargingStationInfo = stationTemplateFromFile ?? ({} as ChargingStationInfo);
     stationInfo.wsOptions = stationTemplateFromFile?.wsOptions ?? {};
     if (!Utils.isEmptyArray(stationTemplateFromFile.power)) {
       stationTemplateFromFile.power = stationTemplateFromFile.power as number[];
-      const powerArrayRandomIndex = Math.floor(Utils.secureRandom() * stationTemplateFromFile.power.length);
-      stationInfo.maxPower = stationTemplateFromFile.powerUnit === PowerUnits.KILO_WATT
-        ? stationTemplateFromFile.power[powerArrayRandomIndex] * 1000
-        : stationTemplateFromFile.power[powerArrayRandomIndex];
+      const powerArrayRandomIndex = Math.floor(
+        Utils.secureRandom() * stationTemplateFromFile.power.length
+      );
+      stationInfo.maxPower =
+        stationTemplateFromFile.powerUnit === PowerUnits.KILO_WATT
+          ? stationTemplateFromFile.power[powerArrayRandomIndex] * 1000
+          : stationTemplateFromFile.power[powerArrayRandomIndex];
     } else {
       stationTemplateFromFile.power = stationTemplateFromFile.power as number;
-      stationInfo.maxPower = stationTemplateFromFile.powerUnit === PowerUnits.KILO_WATT
-        ? stationTemplateFromFile.power * 1000
-        : stationTemplateFromFile.power;
+      stationInfo.maxPower =
+        stationTemplateFromFile.powerUnit === PowerUnits.KILO_WATT
+          ? stationTemplateFromFile.power * 1000
+          : stationTemplateFromFile.power;
     }
     delete stationInfo.power;
     delete stationInfo.powerUnit;
     stationInfo.chargingStationId = chargingStationId;
-    stationInfo.resetTime = stationTemplateFromFile.resetTime ? stationTemplateFromFile.resetTime * 1000 : Constants.CHARGING_STATION_DEFAULT_RESET_TIME;
+    stationInfo.resetTime = stationTemplateFromFile.resetTime
+      ? stationTemplateFromFile.resetTime * 1000
+      : Constants.CHARGING_STATION_DEFAULT_RESET_TIME;
     return stationInfo;
   }
 
@@ -517,7 +702,9 @@ export default class ChargingStation {
   }
 
   private handleUnsupportedVersion(version: OCPPVersion) {
-    const errMsg = `${this.logPrefix()} Unsupported protocol version '${version}' configured in template file ${this.stationTemplateFile}`;
+    const errMsg = `${this.logPrefix()} Unsupported protocol version '${version}' configured in template file ${
+      this.stationTemplateFile
+    }`;
     logger.error(errMsg);
     throw new Error(errMsg);
   }
@@ -529,37 +716,72 @@ export default class ChargingStation {
     this.bootNotificationRequest = {
       chargePointModel: this.stationInfo.chargePointModel,
       chargePointVendor: this.stationInfo.chargePointVendor,
-      ...!Utils.isUndefined(this.stationInfo.chargeBoxSerialNumberPrefix) && { chargeBoxSerialNumber: this.stationInfo.chargeBoxSerialNumberPrefix },
-      ...!Utils.isUndefined(this.stationInfo.firmwareVersion) && { firmwareVersion: this.stationInfo.firmwareVersion },
+      ...(!Utils.isUndefined(this.stationInfo.chargeBoxSerialNumberPrefix) && {
+        chargeBoxSerialNumber: this.stationInfo.chargeBoxSerialNumberPrefix,
+      }),
+      ...(!Utils.isUndefined(this.stationInfo.firmwareVersion) && {
+        firmwareVersion: this.stationInfo.firmwareVersion,
+      }),
     };
     // Build connectors if needed
     const maxConnectors = this.getMaxNumberOfConnectors();
     if (maxConnectors <= 0) {
-      logger.warn(`${this.logPrefix()} Charging station template ${this.stationTemplateFile} with ${maxConnectors} connectors`);
+      logger.warn(
+        `${this.logPrefix()} Charging station template ${
+          this.stationTemplateFile
+        } with ${maxConnectors} connectors`
+      );
     }
     const templateMaxConnectors = this.getTemplateMaxNumberOfConnectors();
     if (templateMaxConnectors <= 0) {
-      logger.warn(`${this.logPrefix()} Charging station template ${this.stationTemplateFile} with no connector configuration`);
+      logger.warn(
+        `${this.logPrefix()} Charging station template ${
+          this.stationTemplateFile
+        } with no connector configuration`
+      );
     }
     if (!this.stationInfo.Connectors[0]) {
-      logger.warn(`${this.logPrefix()} Charging station template ${this.stationTemplateFile} with no connector Id 0 configuration`);
+      logger.warn(
+        `${this.logPrefix()} Charging station template ${
+          this.stationTemplateFile
+        } with no connector Id 0 configuration`
+      );
     }
     // Sanity check
-    if (maxConnectors > (this.stationInfo.Connectors[0] ? templateMaxConnectors - 1 : templateMaxConnectors) && !this.stationInfo.randomConnectors) {
-      logger.warn(`${this.logPrefix()} Number of connectors exceeds the number of connector configurations in template ${this.stationTemplateFile}, forcing random connector configurations affectation`);
+    if (
+      maxConnectors >
+        (this.stationInfo.Connectors[0] ? templateMaxConnectors - 1 : templateMaxConnectors) &&
+      !this.stationInfo.randomConnectors
+    ) {
+      logger.warn(
+        `${this.logPrefix()} Number of connectors exceeds the number of connector configurations in template ${
+          this.stationTemplateFile
+        }, forcing random connector configurations affectation`
+      );
       this.stationInfo.randomConnectors = true;
     }
-    const connectorsConfigHash = crypto.createHash('sha256').update(JSON.stringify(this.stationInfo.Connectors) + maxConnectors.toString()).digest('hex');
-    const connectorsConfigChanged = this.connectors?.size !== 0 && this.connectorsConfigurationHash !== connectorsConfigHash;
+    const connectorsConfigHash = crypto
+      .createHash('sha256')
+      .update(JSON.stringify(this.stationInfo.Connectors) + maxConnectors.toString())
+      .digest('hex');
+    const connectorsConfigChanged =
+      this.connectors?.size !== 0 && this.connectorsConfigurationHash !== connectorsConfigHash;
     if (this.connectors?.size === 0 || connectorsConfigChanged) {
-      connectorsConfigChanged && (this.connectors.clear());
+      connectorsConfigChanged && this.connectors.clear();
       this.connectorsConfigurationHash = connectorsConfigHash;
       // Add connector Id 0
       let lastConnector = '0';
       for (lastConnector in this.stationInfo.Connectors) {
         const lastConnectorId = Utils.convertToInt(lastConnector);
-        if (lastConnectorId === 0 && this.getUseConnectorId0() && this.stationInfo.Connectors[lastConnector]) {
-          this.connectors.set(lastConnectorId, Utils.cloneObject<ConnectorStatus>(this.stationInfo.Connectors[lastConnector]));
+        if (
+          lastConnectorId === 0 &&
+          this.getUseConnectorId0() &&
+          this.stationInfo.Connectors[lastConnector]
+        ) {
+          this.connectors.set(
+            lastConnectorId,
+            Utils.cloneObject<ConnectorStatus>(this.stationInfo.Connectors[lastConnector])
+          );
           this.getConnectorStatus(lastConnectorId).availability = AvailabilityType.OPERATIVE;
           if (Utils.isUndefined(this.getConnectorStatus(lastConnectorId)?.chargingProfiles)) {
             this.getConnectorStatus(lastConnectorId).chargingProfiles = [];
@@ -567,10 +789,17 @@ export default class ChargingStation {
         }
       }
       // Generate all connectors
-      if ((this.stationInfo.Connectors[0] ? templateMaxConnectors - 1 : templateMaxConnectors) > 0) {
+      if (
+        (this.stationInfo.Connectors[0] ? templateMaxConnectors - 1 : templateMaxConnectors) > 0
+      ) {
         for (let index = 1; index <= maxConnectors; index++) {
-          const randConnectorId = this.stationInfo.randomConnectors ? Utils.getRandomInteger(Utils.convertToInt(lastConnector), 1) : index;
-          this.connectors.set(index, Utils.cloneObject<ConnectorStatus>(this.stationInfo.Connectors[randConnectorId]));
+          const randConnectorId = this.stationInfo.randomConnectors
+            ? Utils.getRandomInteger(Utils.convertToInt(lastConnector), 1)
+            : index;
+          this.connectors.set(
+            index,
+            Utils.cloneObject<ConnectorStatus>(this.stationInfo.Connectors[randConnectorId])
+          );
           this.getConnectorStatus(index).availability = AvailabilityType.OPERATIVE;
           if (Utils.isUndefined(this.getConnectorStatus(index)?.chargingProfiles)) {
             this.getConnectorStatus(index).chargingProfiles = [];
@@ -586,11 +815,17 @@ export default class ChargingStation {
         this.initializeConnectorStatus(connectorId);
       }
     }
-    this.wsConfiguredConnectionUrl = new URL(this.getConfiguredSupervisionUrl().href + '/' + this.stationInfo.chargingStationId);
+    this.wsConfiguredConnectionUrl = new URL(
+      this.getConfiguredSupervisionUrl().href + '/' + this.stationInfo.chargingStationId
+    );
     switch (this.getOcppVersion()) {
       case OCPPVersion.VERSION_16:
-        this.ocppIncomingRequestService = OCPP16IncomingRequestService.getInstance<OCPP16IncomingRequestService>(this);
-        this.ocppRequestService = OCPP16RequestService.getInstance<OCPP16RequestService>(this, OCPP16ResponseService.getInstance<OCPP16ResponseService>(this));
+        this.ocppIncomingRequestService =
+          OCPP16IncomingRequestService.getInstance<OCPP16IncomingRequestService>(this);
+        this.ocppRequestService = OCPP16RequestService.getInstance<OCPP16RequestService>(
+          this,
+          OCPP16ResponseService.getInstance<OCPP16ResponseService>(this)
+        );
         break;
       default:
         this.handleUnsupportedVersion(this.getOcppVersion());
@@ -602,25 +837,48 @@ export default class ChargingStation {
       this.bootNotificationResponse = {
         currentTime: new Date().toISOString(),
         interval: this.getHeartbeatInterval() / 1000,
-        status: RegistrationStatus.ACCEPTED
+        status: RegistrationStatus.ACCEPTED,
       };
     }
     this.stationInfo.powerDivider = this.getPowerDivider();
     if (this.getEnableStatistics()) {
-      this.performanceStatistics = PerformanceStatistics.getInstance(this.id, this.stationInfo.chargingStationId, this.wsConnectionUrl);
+      this.performanceStatistics = PerformanceStatistics.getInstance(
+        this.id,
+        this.stationInfo.chargingStationId,
+        this.wsConnectionUrl
+      );
     }
   }
 
   private initOcppParameters(): void {
-    if (this.getSupervisionUrlOcppConfiguration() && !this.getConfigurationKey(this.stationInfo.supervisionUrlOcppKey ?? VendorDefaultParametersKey.ConnectionUrl)) {
-      this.addConfigurationKey(VendorDefaultParametersKey.ConnectionUrl, this.getConfiguredSupervisionUrl().href, { reboot: true });
+    if (
+      this.getSupervisionUrlOcppConfiguration() &&
+      !this.getConfigurationKey(
+        this.stationInfo.supervisionUrlOcppKey ?? VendorDefaultParametersKey.ConnectionUrl
+      )
+    ) {
+      this.addConfigurationKey(
+        VendorDefaultParametersKey.ConnectionUrl,
+        this.getConfiguredSupervisionUrl().href,
+        { reboot: true }
+      );
     }
     if (!this.getConfigurationKey(StandardParametersKey.SupportedFeatureProfiles)) {
-      this.addConfigurationKey(StandardParametersKey.SupportedFeatureProfiles, `${SupportedFeatureProfiles.Core},${SupportedFeatureProfiles.Local_Auth_List_Management},${SupportedFeatureProfiles.Smart_Charging}`);
-    }
-    this.addConfigurationKey(StandardParametersKey.NumberOfConnectors, this.getNumberOfConnectors().toString(), { readonly: true });
+      this.addConfigurationKey(
+        StandardParametersKey.SupportedFeatureProfiles,
+        `${SupportedFeatureProfiles.Core},${SupportedFeatureProfiles.Local_Auth_List_Management},${SupportedFeatureProfiles.Smart_Charging}`
+      );
+    }
+    this.addConfigurationKey(
+      StandardParametersKey.NumberOfConnectors,
+      this.getNumberOfConnectors().toString(),
+      { readonly: true }
+    );
     if (!this.getConfigurationKey(StandardParametersKey.MeterValuesSampledData)) {
-      this.addConfigurationKey(StandardParametersKey.MeterValuesSampledData, MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER);
+      this.addConfigurationKey(
+        StandardParametersKey.MeterValuesSampledData,
+        MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
+      );
     }
     if (!this.getConfigurationKey(StandardParametersKey.ConnectorPhaseRotation)) {
       const connectorPhaseRotation = [];
@@ -630,40 +888,64 @@ export default class ChargingStation {
           connectorPhaseRotation.push(`${connectorId}.${ConnectorPhaseRotation.RST}`);
         } else if (connectorId > 0 && this.getNumberOfPhases() === 0) {
           connectorPhaseRotation.push(`${connectorId}.${ConnectorPhaseRotation.NotApplicable}`);
-        // AC
+          // AC
         } else if (connectorId > 0 && this.getNumberOfPhases() === 1) {
           connectorPhaseRotation.push(`${connectorId}.${ConnectorPhaseRotation.NotApplicable}`);
         } else if (connectorId > 0 && this.getNumberOfPhases() === 3) {
           connectorPhaseRotation.push(`${connectorId}.${ConnectorPhaseRotation.RST}`);
         }
       }
-      this.addConfigurationKey(StandardParametersKey.ConnectorPhaseRotation, connectorPhaseRotation.toString());
+      this.addConfigurationKey(
+        StandardParametersKey.ConnectorPhaseRotation,
+        connectorPhaseRotation.toString()
+      );
     }
     if (!this.getConfigurationKey(StandardParametersKey.AuthorizeRemoteTxRequests)) {
       this.addConfigurationKey(StandardParametersKey.AuthorizeRemoteTxRequests, 'true');
     }
-    if (!this.getConfigurationKey(StandardParametersKey.LocalAuthListEnabled)
-      && this.getConfigurationKey(StandardParametersKey.SupportedFeatureProfiles).value.includes(SupportedFeatureProfiles.Local_Auth_List_Management)) {
+    if (
+      !this.getConfigurationKey(StandardParametersKey.LocalAuthListEnabled) &&
+      this.getConfigurationKey(StandardParametersKey.SupportedFeatureProfiles).value.includes(
+        SupportedFeatureProfiles.Local_Auth_List_Management
+      )
+    ) {
       this.addConfigurationKey(StandardParametersKey.LocalAuthListEnabled, 'false');
     }
     if (!this.getConfigurationKey(StandardParametersKey.ConnectionTimeOut)) {
-      this.addConfigurationKey(StandardParametersKey.ConnectionTimeOut, Constants.DEFAULT_CONNECTION_TIMEOUT.toString());
+      this.addConfigurationKey(
+        StandardParametersKey.ConnectionTimeOut,
+        Constants.DEFAULT_CONNECTION_TIMEOUT.toString()
+      );
     }
   }
 
   private async onOpen(): Promise<void> {
-    logger.info(`${this.logPrefix()} Connected to OCPP server through ${this.wsConnectionUrl.toString()}`);
+    logger.info(
+      `${this.logPrefix()} Connected to OCPP server through ${this.wsConnectionUrl.toString()}`
+    );
     if (!this.isInAcceptedState()) {
       // Send BootNotification
       let registrationRetryCount = 0;
       do {
-        this.bootNotificationResponse = await this.ocppRequestService.sendBootNotification(this.bootNotificationRequest.chargePointModel,
-          this.bootNotificationRequest.chargePointVendor, this.bootNotificationRequest.chargeBoxSerialNumber, this.bootNotificationRequest.firmwareVersion);
+        this.bootNotificationResponse = await this.ocppRequestService.sendBootNotification(
+          this.bootNotificationRequest.chargePointModel,
+          this.bootNotificationRequest.chargePointVendor,
+          this.bootNotificationRequest.chargeBoxSerialNumber,
+          this.bootNotificationRequest.firmwareVersion
+        );
         if (!this.isInAcceptedState()) {
           this.getRegistrationMaxRetries() !== -1 && registrationRetryCount++;
-          await Utils.sleep(this.bootNotificationResponse?.interval ? this.bootNotificationResponse.interval * 1000 : Constants.OCPP_DEFAULT_BOOT_NOTIFICATION_INTERVAL);
+          await Utils.sleep(
+            this.bootNotificationResponse?.interval
+              ? this.bootNotificationResponse.interval * 1000
+              : Constants.OCPP_DEFAULT_BOOT_NOTIFICATION_INTERVAL
+          );
         }
-      } while (!this.isInAcceptedState() && (registrationRetryCount <= this.getRegistrationMaxRetries() || this.getRegistrationMaxRetries() === -1));
+      } while (
+        !this.isInAcceptedState() &&
+        (registrationRetryCount <= this.getRegistrationMaxRetries() ||
+          this.getRegistrationMaxRetries() === -1)
+      );
     }
     if (this.isInAcceptedState()) {
       await this.startMessageSequence();
@@ -672,7 +954,9 @@ export default class ChargingStation {
         this.flushMessageBuffer();
       }
     } else {
-      logger.error(`${this.logPrefix()} Registration failure: max retries reached (${this.getRegistrationMaxRetries()}) or retry disabled (${this.getRegistrationMaxRetries()})`);
+      logger.error(
+        `${this.logPrefix()} Registration failure: max retries reached (${this.getRegistrationMaxRetries()}) or retry disabled (${this.getRegistrationMaxRetries()})`
+      );
     }
     this.autoReconnectRetryCount = 0;
     this.wsConnectionRestarted = false;
@@ -683,20 +967,37 @@ export default class ChargingStation {
       // Normal close
       case WebSocketCloseEventStatusCode.CLOSE_NORMAL:
       case WebSocketCloseEventStatusCode.CLOSE_NO_STATUS:
-        logger.info(`${this.logPrefix()} WebSocket normally closed with status '${Utils.getWebSocketCloseEventStatusString(code)}' and reason '${reason}'`);
+        logger.info(
+          `${this.logPrefix()} WebSocket normally closed with status '${Utils.getWebSocketCloseEventStatusString(
+            code
+          )}' and reason '${reason}'`
+        );
         this.autoReconnectRetryCount = 0;
         break;
       // Abnormal close
       default:
-        logger.error(`${this.logPrefix()} WebSocket abnormally closed with status '${Utils.getWebSocketCloseEventStatusString(code)}' and reason '${reason}'`);
+        logger.error(
+          `${this.logPrefix()} WebSocket abnormally closed with status '${Utils.getWebSocketCloseEventStatusString(
+            code
+          )}' and reason '${reason}'`
+        );
         await this.reconnect(code);
         break;
     }
   }
 
   private async onMessage(data: Data): Promise<void> {
-    let [messageType, messageId, commandName, commandPayload, errorDetails]: IncomingRequest = [0, '', '' as IncomingRequestCommand, {}, {}];
-    let responseCallback: (payload: JsonType | string, requestPayload: JsonType | OCPPError) => void;
+    let [messageType, messageId, commandName, commandPayload, errorDetails]: IncomingRequest = [
+      0,
+      '',
+      '' as IncomingRequestCommand,
+      {},
+      {},
+    ];
+    let responseCallback: (
+      payload: JsonType | string,
+      requestPayload: JsonType | OCPPError
+    ) => void;
     let rejectCallback: (error: OCPPError, requestStatistic?: boolean) => void;
     let requestCommandName: RequestCommand | IncomingRequestCommand;
     let requestPayload: JsonType | OCPPError;
@@ -708,7 +1009,11 @@ export default class ChargingStation {
         // Parse the message
         [messageType, messageId, commandName, commandPayload, errorDetails] = request;
       } else {
-        throw new OCPPError(ErrorType.PROTOCOL_ERROR, 'Incoming request is not iterable', commandName);
+        throw new OCPPError(
+          ErrorType.PROTOCOL_ERROR,
+          'Incoming request is not iterable',
+          commandName
+        );
       }
       // Check the Type of message
       switch (messageType) {
@@ -718,7 +1023,11 @@ export default class ChargingStation {
             this.performanceStatistics.addRequestStatistic(commandName, messageType);
           }
           // Process the call
-          await this.ocppIncomingRequestService.handleRequest(messageId, commandName, commandPayload);
+          await this.ocppIncomingRequestService.handleRequest(
+            messageId,
+            commandName,
+            commandPayload
+          );
           break;
         // Outcome Message
         case MessageType.CALL_RESULT_MESSAGE:
@@ -727,11 +1036,19 @@ export default class ChargingStation {
           if (Utils.isIterable(cachedRequest)) {
             [responseCallback, , , requestPayload] = cachedRequest;
           } else {
-            throw new OCPPError(ErrorType.PROTOCOL_ERROR, `Cached request for message id ${messageId} response is not iterable`, commandName);
+            throw new OCPPError(
+              ErrorType.PROTOCOL_ERROR,
+              `Cached request for message id ${messageId} response is not iterable`,
+              commandName
+            );
           }
           if (!responseCallback) {
             // Error
-            throw new OCPPError(ErrorType.INTERNAL_ERROR, `Response for unknown message id ${messageId}`, commandName);
+            throw new OCPPError(
+              ErrorType.INTERNAL_ERROR,
+              `Response for unknown message id ${messageId}`,
+              commandName
+            );
           }
           responseCallback(commandName, requestPayload);
           break;
@@ -741,13 +1058,22 @@ export default class ChargingStation {
           if (Utils.isIterable(cachedRequest)) {
             [, rejectCallback, requestCommandName] = cachedRequest;
           } else {
-            throw new OCPPError(ErrorType.PROTOCOL_ERROR, `Cached request for message id ${messageId} error response is not iterable`);
+            throw new OCPPError(
+              ErrorType.PROTOCOL_ERROR,
+              `Cached request for message id ${messageId} error response is not iterable`
+            );
           }
           if (!rejectCallback) {
             // Error
-            throw new OCPPError(ErrorType.INTERNAL_ERROR, `Error response for unknown message id ${messageId}`, requestCommandName);
+            throw new OCPPError(
+              ErrorType.INTERNAL_ERROR,
+              `Error response for unknown message id ${messageId}`,
+              requestCommandName
+            );
           }
-          rejectCallback(new OCPPError(commandName, commandPayload.toString(), requestCommandName, errorDetails));
+          rejectCallback(
+            new OCPPError(commandName, commandPayload.toString(), requestCommandName, errorDetails)
+          );
           break;
         // Error
         default:
@@ -757,9 +1083,16 @@ export default class ChargingStation {
       }
     } catch (error) {
       // Log
-      logger.error('%s Incoming OCPP message %j matching cached request %j processing error %j', this.logPrefix(), data.toString(), this.requests.get(messageId), error);
+      logger.error(
+        '%s Incoming OCPP message %j matching cached request %j processing error %j',
+        this.logPrefix(),
+        data.toString(),
+        this.requests.get(messageId),
+        error
+      );
       // Send error
-      messageType === MessageType.CALL_MESSAGE && await this.ocppRequestService.sendError(messageId, error as OCPPError, commandName);
+      messageType === MessageType.CALL_MESSAGE &&
+        (await this.ocppRequestService.sendError(messageId, error as OCPPError, commandName));
     }
   }
 
@@ -781,11 +1114,18 @@ export default class ChargingStation {
   }
 
   private getTemplateChargingStationConfiguration(): ChargingStationConfiguration {
-    return this.stationInfo.Configuration ?? {} as ChargingStationConfiguration;
+    return this.stationInfo.Configuration ?? ({} as ChargingStationConfiguration);
   }
 
   private getAuthorizationFile(): string | undefined {
-    return this.stationInfo.authorizationFile && path.join(path.resolve(__dirname, '../'), 'assets', path.basename(this.stationInfo.authorizationFile));
+    return (
+      this.stationInfo.authorizationFile &&
+      path.join(
+        path.resolve(__dirname, '../'),
+        'assets',
+        path.basename(this.stationInfo.authorizationFile)
+      )
+    );
   }
 
   private getAuthorizedTags(): string[] {
@@ -798,16 +1138,27 @@ export default class ChargingStation {
         authorizedTags = JSON.parse(fs.readFileSync(fileDescriptor, 'utf8')) as string[];
         fs.closeSync(fileDescriptor);
       } catch (error) {
-        FileUtils.handleFileException(this.logPrefix(), 'Authorization', authorizationFile, error as NodeJS.ErrnoException);
+        FileUtils.handleFileException(
+          this.logPrefix(),
+          'Authorization',
+          authorizationFile,
+          error as NodeJS.ErrnoException
+        );
       }
     } else {
-      logger.info(this.logPrefix() + ' No authorization file given in template file ' + this.stationTemplateFile);
+      logger.info(
+        this.logPrefix() +
+          ' No authorization file given in template file ' +
+          this.stationTemplateFile
+      );
     }
     return authorizedTags;
   }
 
   private getUseConnectorId0(): boolean | undefined {
-    return !Utils.isUndefined(this.stationInfo.useConnectorId0) ? this.stationInfo.useConnectorId0 : true;
+    return !Utils.isUndefined(this.stationInfo.useConnectorId0)
+      ? this.stationInfo.useConnectorId0
+      : true;
   }
 
   private getNumberOfRunningTransactions(): number {
@@ -823,7 +1174,10 @@ export default class ChargingStation {
   // 0 for disabling
   private getConnectionTimeout(): number | undefined {
     if (this.getConfigurationKey(StandardParametersKey.ConnectionTimeOut)) {
-      return parseInt(this.getConfigurationKey(StandardParametersKey.ConnectionTimeOut).value) ?? Constants.DEFAULT_CONNECTION_TIMEOUT;
+      return (
+        parseInt(this.getConfigurationKey(StandardParametersKey.ConnectionTimeOut).value) ??
+        Constants.DEFAULT_CONNECTION_TIMEOUT
+      );
     }
     return Constants.DEFAULT_CONNECTION_TIMEOUT;
   }
@@ -868,15 +1222,21 @@ export default class ChargingStation {
     } else if (!Utils.isUndefined(this.stationInfo.numberOfConnectors)) {
       maxConnectors = this.stationInfo.numberOfConnectors as number;
     } else {
-      maxConnectors = this.stationInfo.Connectors[0] ? this.getTemplateMaxNumberOfConnectors() - 1 : this.getTemplateMaxNumberOfConnectors();
+      maxConnectors = this.stationInfo.Connectors[0]
+        ? this.getTemplateMaxNumberOfConnectors() - 1
+        : this.getTemplateMaxNumberOfConnectors();
     }
     return maxConnectors;
   }
 
   private async startMessageSequence(): Promise<void> {
     if (this.stationInfo.autoRegister) {
-      await this.ocppRequestService.sendBootNotification(this.bootNotificationRequest.chargePointModel,
-        this.bootNotificationRequest.chargePointVendor, this.bootNotificationRequest.chargeBoxSerialNumber, this.bootNotificationRequest.firmwareVersion);
+      await this.ocppRequestService.sendBootNotification(
+        this.bootNotificationRequest.chargePointModel,
+        this.bootNotificationRequest.chargePointVendor,
+        this.bootNotificationRequest.chargeBoxSerialNumber,
+        this.bootNotificationRequest.firmwareVersion
+      );
     }
     // Start WebSocket ping
     this.startWebSocketPing();
@@ -886,20 +1246,42 @@ export default class ChargingStation {
     for (const connectorId of this.connectors.keys()) {
       if (connectorId === 0) {
         continue;
-      } else if (!this.stopped && !this.getConnectorStatus(connectorId)?.status && this.getConnectorStatus(connectorId)?.bootStatus) {
+      } else if (
+        !this.stopped &&
+        !this.getConnectorStatus(connectorId)?.status &&
+        this.getConnectorStatus(connectorId)?.bootStatus
+      ) {
         // Send status in template at startup
-        await this.ocppRequestService.sendStatusNotification(connectorId, this.getConnectorStatus(connectorId).bootStatus);
-        this.getConnectorStatus(connectorId).status = this.getConnectorStatus(connectorId).bootStatus;
-      } else if (this.stopped && this.getConnectorStatus(connectorId)?.status && this.getConnectorStatus(connectorId)?.bootStatus) {
+        await this.ocppRequestService.sendStatusNotification(
+          connectorId,
+          this.getConnectorStatus(connectorId).bootStatus
+        );
+        this.getConnectorStatus(connectorId).status =
+          this.getConnectorStatus(connectorId).bootStatus;
+      } else if (
+        this.stopped &&
+        this.getConnectorStatus(connectorId)?.status &&
+        this.getConnectorStatus(connectorId)?.bootStatus
+      ) {
         // Send status in template after reset
-        await this.ocppRequestService.sendStatusNotification(connectorId, this.getConnectorStatus(connectorId).bootStatus);
-        this.getConnectorStatus(connectorId).status = this.getConnectorStatus(connectorId).bootStatus;
+        await this.ocppRequestService.sendStatusNotification(
+          connectorId,
+          this.getConnectorStatus(connectorId).bootStatus
+        );
+        this.getConnectorStatus(connectorId).status =
+          this.getConnectorStatus(connectorId).bootStatus;
       } else if (!this.stopped && this.getConnectorStatus(connectorId)?.status) {
         // Send previous status at template reload
-        await this.ocppRequestService.sendStatusNotification(connectorId, this.getConnectorStatus(connectorId).status);
+        await this.ocppRequestService.sendStatusNotification(
+          connectorId,
+          this.getConnectorStatus(connectorId).status
+        );
       } else {
         // Send default status
-        await this.ocppRequestService.sendStatusNotification(connectorId, ChargePointStatus.AVAILABLE);
+        await this.ocppRequestService.sendStatusNotification(
+          connectorId,
+          ChargePointStatus.AVAILABLE
+        );
         this.getConnectorStatus(connectorId).status = ChargePointStatus.AVAILABLE;
       }
     }
@@ -918,41 +1300,70 @@ export default class ChargingStation {
     }
   }
 
-  private async stopMessageSequence(reason: StopTransactionReason = StopTransactionReason.NONE): Promise<void> {
+  private async stopMessageSequence(
+    reason: StopTransactionReason = StopTransactionReason.NONE
+  ): Promise<void> {
     // Stop WebSocket ping
     this.stopWebSocketPing();
     // Stop heartbeat
     this.stopHeartbeat();
     // Stop the ATG
-    if (this.stationInfo.AutomaticTransactionGenerator.enable &&
-      this.automaticTransactionGenerator?.started) {
+    if (
+      this.stationInfo.AutomaticTransactionGenerator.enable &&
+      this.automaticTransactionGenerator?.started
+    ) {
       this.automaticTransactionGenerator.stop();
     } else {
       for (const connectorId of this.connectors.keys()) {
         if (connectorId > 0 && this.getConnectorStatus(connectorId)?.transactionStarted) {
           const transactionId = this.getConnectorStatus(connectorId).transactionId;
-          await this.ocppRequestService.sendStopTransaction(transactionId, this.getEnergyActiveImportRegisterByTransactionId(transactionId),
-            this.getTransactionIdTag(transactionId), reason);
+          await this.ocppRequestService.sendStopTransaction(
+            transactionId,
+            this.getEnergyActiveImportRegisterByTransactionId(transactionId),
+            this.getTransactionIdTag(transactionId),
+            reason
+          );
         }
       }
     }
   }
 
   private startWebSocketPing(): void {
-    const webSocketPingInterval: number = this.getConfigurationKey(StandardParametersKey.WebSocketPingInterval)
-      ? Utils.convertToInt(this.getConfigurationKey(StandardParametersKey.WebSocketPingInterval).value)
+    const webSocketPingInterval: number = this.getConfigurationKey(
+      StandardParametersKey.WebSocketPingInterval
+    )
+      ? Utils.convertToInt(
+          this.getConfigurationKey(StandardParametersKey.WebSocketPingInterval).value
+        )
       : 0;
     if (webSocketPingInterval > 0 && !this.webSocketPingSetInterval) {
       this.webSocketPingSetInterval = setInterval(() => {
         if (this.isWebSocketConnectionOpened()) {
-          this.wsConnection.ping((): void => { /* This is intentional */ });
+          this.wsConnection.ping((): void => {
+            /* This is intentional */
+          });
         }
       }, webSocketPingInterval * 1000);
-      logger.info(this.logPrefix() + ' WebSocket ping started every ' + Utils.formatDurationSeconds(webSocketPingInterval));
+      logger.info(
+        this.logPrefix() +
+          ' WebSocket ping started every ' +
+          Utils.formatDurationSeconds(webSocketPingInterval)
+      );
     } else if (this.webSocketPingSetInterval) {
-      logger.info(this.logPrefix() + ' WebSocket ping every ' + Utils.formatDurationSeconds(webSocketPingInterval) + ' already started');
+      logger.info(
+        this.logPrefix() +
+          ' WebSocket ping every ' +
+          Utils.formatDurationSeconds(webSocketPingInterval) +
+          ' already started'
+      );
     } else {
-      logger.error(`${this.logPrefix()} WebSocket ping interval set to ${webSocketPingInterval ? Utils.formatDurationSeconds(webSocketPingInterval) : webSocketPingInterval}, not starting the WebSocket ping`);
+      logger.error(
+        `${this.logPrefix()} WebSocket ping interval set to ${
+          webSocketPingInterval
+            ? Utils.formatDurationSeconds(webSocketPingInterval)
+            : webSocketPingInterval
+        }, not starting the WebSocket ping`
+      );
     }
   }
 
@@ -962,13 +1373,27 @@ export default class ChargingStation {
     }
   }
 
-  private warnDeprecatedTemplateKey(template: ChargingStationTemplate, key: string, chargingStationId: string, logMsgToAppend = ''): void {
+  private warnDeprecatedTemplateKey(
+    template: ChargingStationTemplate,
+    key: string,
+    chargingStationId: string,
+    logMsgToAppend = ''
+  ): void {
     if (!Utils.isUndefined(template[key])) {
-      logger.warn(`${Utils.logPrefix(` ${chargingStationId} |`)} Deprecated template key '${key}' usage in file '${this.stationTemplateFile}'${logMsgToAppend && '. ' + logMsgToAppend}`);
+      const logPrefixStr = ` ${chargingStationId} |`;
+      logger.warn(
+        `${Utils.logPrefix(logPrefixStr)} Deprecated template key '${key}' usage in file '${
+          this.stationTemplateFile
+        }'${logMsgToAppend && '. ' + logMsgToAppend}`
+      );
     }
   }
 
-  private convertDeprecatedTemplateKey(template: ChargingStationTemplate, deprecatedKey: string, key: string): void {
+  private convertDeprecatedTemplateKey(
+    template: ChargingStationTemplate,
+    deprecatedKey: string,
+    key: string
+  ): void {
     if (!Utils.isUndefined(template[deprecatedKey])) {
       // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
       template[key] = template[deprecatedKey];
@@ -977,7 +1402,9 @@ export default class ChargingStation {
   }
 
   private getConfiguredSupervisionUrl(): URL {
-    const supervisionUrls = Utils.cloneObject<string | string[]>(this.stationInfo.supervisionUrls ?? Configuration.getSupervisionUrls());
+    const supervisionUrls = Utils.cloneObject<string | string[]>(
+      this.stationInfo.supervisionUrls ?? Configuration.getSupervisionUrls()
+    );
     if (!Utils.isEmptyArray(supervisionUrls)) {
       let urlIndex = 0;
       switch (Configuration.getSupervisionUrlDistribution()) {
@@ -992,11 +1419,17 @@ export default class ChargingStation {
           if (this.index <= supervisionUrls.length) {
             urlIndex = this.index - 1;
           } else {
-            logger.warn(`${this.logPrefix()} No more configured supervision urls available, using the first one`);
+            logger.warn(
+              `${this.logPrefix()} No more configured supervision urls available, using the first one`
+            );
           }
           break;
         default:
-          logger.error(`${this.logPrefix()} Unknown supervision url distribution '${Configuration.getSupervisionUrlDistribution()}' from values '${SupervisionUrlDistribution.toString()}', defaulting to ${SupervisionUrlDistribution.ROUND_ROBIN}`);
+          logger.error(
+            `${this.logPrefix()} Unknown supervision url distribution '${Configuration.getSupervisionUrlDistribution()}' from values '${SupervisionUrlDistribution.toString()}', defaulting to ${
+              SupervisionUrlDistribution.ROUND_ROBIN
+            }`
+          );
           urlIndex = (this.index - 1) % supervisionUrls.length;
           break;
       }
@@ -1014,7 +1447,12 @@ export default class ChargingStation {
     if (HeartBeatInterval) {
       return Utils.convertToInt(HeartBeatInterval.value) * 1000;
     }
-    !this.stationInfo.autoRegister && logger.warn(`${this.logPrefix()} Heartbeat interval configuration key not set, using default value: ${Constants.DEFAULT_HEARTBEAT_INTERVAL}`);
+    !this.stationInfo.autoRegister &&
+      logger.warn(
+        `${this.logPrefix()} Heartbeat interval configuration key not set, using default value: ${
+          Constants.DEFAULT_HEARTBEAT_INTERVAL
+        }`
+      );
     return Constants.DEFAULT_HEARTBEAT_INTERVAL;
   }
 
@@ -1024,9 +1462,15 @@ export default class ChargingStation {
     }
   }
 
-  private openWSConnection(options: ClientOptions & ClientRequestArgs = this.stationInfo.wsOptions, forceCloseOpened = false): void {
+  private openWSConnection(
+    options: ClientOptions & ClientRequestArgs = this.stationInfo.wsOptions,
+    forceCloseOpened = false
+  ): void {
     options.handshakeTimeout = options?.handshakeTimeout ?? this.getConnectionTimeout() * 1000;
-    if (!Utils.isNullOrUndefined(this.stationInfo.supervisionUser) && !Utils.isNullOrUndefined(this.stationInfo.supervisionPassword)) {
+    if (
+      !Utils.isNullOrUndefined(this.stationInfo.supervisionUser) &&
+      !Utils.isNullOrUndefined(this.stationInfo.supervisionPassword)
+    ) {
       options.auth = `${this.stationInfo.supervisionUser}:${this.stationInfo.supervisionPassword}`;
     }
     if (this.isWebSocketConnectionOpened() && forceCloseOpened) {
@@ -1042,7 +1486,9 @@ export default class ChargingStation {
         break;
     }
     this.wsConnection = new WebSocket(this.wsConnectionUrl, protocol, options);
-    logger.info(this.logPrefix() + ' Open OCPP connection to URL ' + this.wsConnectionUrl.toString());
+    logger.info(
+      this.logPrefix() + ' Open OCPP connection to URL ' + this.wsConnectionUrl.toString()
+    );
   }
 
   private stopMeterValues(connectorId: number) {
@@ -1058,7 +1504,12 @@ export default class ChargingStation {
         fs.watch(authorizationFile, (event, filename) => {
           if (filename && event === 'change') {
             try {
-              logger.debug(this.logPrefix() + ' Authorization file ' + authorizationFile + ' have changed, reload');
+              logger.debug(
+                this.logPrefix() +
+                  ' Authorization file ' +
+                  authorizationFile +
+                  ' have changed, reload'
+              );
               // Initialize authorizedTags
               this.authorizedTags = this.getAuthorizedTags();
             } catch (error) {
@@ -1067,10 +1518,20 @@ export default class ChargingStation {
           }
         });
       } catch (error) {
-        FileUtils.handleFileException(this.logPrefix(), 'Authorization', authorizationFile, error as NodeJS.ErrnoException);
+        FileUtils.handleFileException(
+          this.logPrefix(),
+          'Authorization',
+          authorizationFile,
+          error as NodeJS.ErrnoException
+        );
       }
     } else {
-      logger.info(this.logPrefix() + ' No authorization file given in template file ' + this.stationTemplateFile + '. Not monitoring changes');
+      logger.info(
+        this.logPrefix() +
+          ' No authorization file given in template file ' +
+          this.stationTemplateFile +
+          '. Not monitoring changes'
+      );
     }
   }
 
@@ -1079,12 +1540,19 @@ export default class ChargingStation {
       fs.watch(this.stationTemplateFile, (event, filename): void => {
         if (filename && event === 'change') {
           try {
-            logger.debug(this.logPrefix() + ' Template file ' + this.stationTemplateFile + ' have changed, reload');
+            logger.debug(
+              this.logPrefix() +
+                ' Template file ' +
+                this.stationTemplateFile +
+                ' have changed, reload'
+            );
             // Initialize
             this.initialize();
             // Restart the ATG
-            if (!this.stationInfo.AutomaticTransactionGenerator.enable &&
-              this.automaticTransactionGenerator) {
+            if (
+              !this.stationInfo.AutomaticTransactionGenerator.enable &&
+              this.automaticTransactionGenerator
+            ) {
               this.automaticTransactionGenerator.stop();
             }
             this.startAutomaticTransactionGenerator();
@@ -1095,17 +1563,27 @@ export default class ChargingStation {
             }
             // FIXME?: restart heartbeat and WebSocket ping when their interval values have changed
           } catch (error) {
-            logger.error(this.logPrefix() + ' Charging station template file monitoring error: %j', error);
+            logger.error(
+              this.logPrefix() + ' Charging station template file monitoring error: %j',
+              error
+            );
           }
         }
       });
     } catch (error) {
-      FileUtils.handleFileException(this.logPrefix(), 'Template', this.stationTemplateFile, error as NodeJS.ErrnoException);
+      FileUtils.handleFileException(
+        this.logPrefix(),
+        'Template',
+        this.stationTemplateFile,
+        error as NodeJS.ErrnoException
+      );
     }
   }
 
   private getReconnectExponentialDelay(): boolean | undefined {
-    return !Utils.isUndefined(this.stationInfo.reconnectExponentialDelay) ? this.stationInfo.reconnectExponentialDelay : false;
+    return !Utils.isUndefined(this.stationInfo.reconnectExponentialDelay)
+      ? this.stationInfo.reconnectExponentialDelay
+      : false;
   }
 
   private async reconnect(code: number): Promise<void> {
@@ -1114,22 +1592,45 @@ export default class ChargingStation {
     // Stop heartbeat
     this.stopHeartbeat();
     // Stop the ATG if needed
-    if (this.stationInfo.AutomaticTransactionGenerator.enable &&
+    if (
+      this.stationInfo.AutomaticTransactionGenerator.enable &&
       this.stationInfo.AutomaticTransactionGenerator.stopOnConnectionFailure &&
-      this.automaticTransactionGenerator?.started) {
+      this.automaticTransactionGenerator?.started
+    ) {
       this.automaticTransactionGenerator.stop();
     }
-    if (this.autoReconnectRetryCount < this.getAutoReconnectMaxRetries() || this.getAutoReconnectMaxRetries() === -1) {
+    if (
+      this.autoReconnectRetryCount < this.getAutoReconnectMaxRetries() ||
+      this.getAutoReconnectMaxRetries() === -1
+    ) {
       this.autoReconnectRetryCount++;
-      const reconnectDelay = (this.getReconnectExponentialDelay() ? Utils.exponentialDelay(this.autoReconnectRetryCount) : this.getConnectionTimeout() * 1000);
-      const reconnectTimeout = (reconnectDelay - 100) > 0 && reconnectDelay;
-      logger.error(`${this.logPrefix()} WebSocket: connection retry in ${Utils.roundTo(reconnectDelay, 2)}ms, timeout ${reconnectTimeout}ms`);
+      const reconnectDelay = this.getReconnectExponentialDelay()
+        ? Utils.exponentialDelay(this.autoReconnectRetryCount)
+        : this.getConnectionTimeout() * 1000;
+      const reconnectTimeout = reconnectDelay - 100 > 0 && reconnectDelay;
+      logger.error(
+        `${this.logPrefix()} WebSocket: connection retry in ${Utils.roundTo(
+          reconnectDelay,
+          2
+        )}ms, timeout ${reconnectTimeout}ms`
+      );
       await Utils.sleep(reconnectDelay);
-      logger.error(this.logPrefix() + ' WebSocket: reconnecting try #' + this.autoReconnectRetryCount.toString());
-      this.openWSConnection({ ...this.stationInfo.wsOptions, handshakeTimeout: reconnectTimeout }, true);
+      logger.error(
+        this.logPrefix() +
+          ' WebSocket: reconnecting try #' +
+          this.autoReconnectRetryCount.toString()
+      );
+      this.openWSConnection(
+        { ...this.stationInfo.wsOptions, handshakeTimeout: reconnectTimeout },
+        true
+      );
       this.wsConnectionRestarted = true;
     } else if (this.getAutoReconnectMaxRetries() !== -1) {
-      logger.error(`${this.logPrefix()} WebSocket reconnect failure: max retries reached (${this.autoReconnectRetryCount}) or retry disabled (${this.getAutoReconnectMaxRetries()})`);
+      logger.error(
+        `${this.logPrefix()} WebSocket reconnect failure: max retries reached (${
+          this.autoReconnectRetryCount
+        }) or retry disabled (${this.getAutoReconnectMaxRetries()})`
+      );
     }
   }
 
@@ -1142,4 +1643,3 @@ export default class ChargingStation {
     this.getConnectorStatus(connectorId).transactionEnergyActiveImportRegisterValue = 0;
   }
 }
-
index cc0f62726a174350095ade3fd4805a0204c753bd..84ce450eb2cfa65784aa70da7165aab0e8b43df1 100644 (file)
@@ -1,6 +1,10 @@
 // Partial Copyright Jerome Benoit. 2021. All Rights Reserved.
 
-import { ChargingStationWorkerData, ChargingStationWorkerMessage, ChargingStationWorkerMessageEvents } from '../types/ChargingStationWorker';
+import {
+  ChargingStationWorkerData,
+  ChargingStationWorkerMessage,
+  ChargingStationWorkerMessageEvents,
+} from '../types/ChargingStationWorker';
 import { parentPort, workerData } from 'worker_threads';
 
 import ChargingStation from './ChargingStation';
@@ -11,12 +15,18 @@ import Utils from '../utils/Utils';
 // Conditionally export ThreadWorker instance for pool usage
 export let threadWorker: ThreadWorker;
 if (Utils.workerPoolInUse()) {
-  threadWorker = new ThreadWorker<ChargingStationWorkerData>(startChargingStation, { maxInactiveTime: Constants.WORKER_POOL_MAX_INACTIVE_TIME, async: false });
+  threadWorker = new ThreadWorker<ChargingStationWorkerData>(startChargingStation, {
+    maxInactiveTime: Constants.WORKER_POOL_MAX_INACTIVE_TIME,
+    async: false,
+  });
 } else {
   // Add message listener to start charging station from main thread
   addMessageListener();
   if (!Utils.isUndefined(workerData)) {
-    startChargingStation({ index: workerData.index as number, templateFile: workerData.templateFile as string });
+    startChargingStation({
+      index: workerData.index as number,
+      templateFile: workerData.templateFile as string,
+    });
   }
 }
 
index 96e9a96896be609ff4a09760c33900886e3aa473..5ffc9e0c640320a36f22fb3658afe7478747f32b 100644 (file)
@@ -34,9 +34,13 @@ export default class UIWebSocketServer extends Server {
   public start(): void {
     this.on('connection', (socket: WebSocket, request: IncomingMessage): void => {
       const protocolIndex = socket.protocol.indexOf(Protocol.UI);
-      const version = socket.protocol.substring(protocolIndex + Protocol.UI.length) as ProtocolVersion;
+      const version = socket.protocol.substring(
+        protocolIndex + Protocol.UI.length
+      ) as ProtocolVersion;
       if (!this.uiServices.has(version)) {
-        throw new BaseError(`Could not find a UI service implementation for UI protocol version ${version}`);
+        throw new BaseError(
+          `Could not find a UI service implementation for UI protocol version ${version}`
+        );
       }
       // FIXME: check connection validity
       socket.on('message', (messageData) => {
@@ -47,9 +51,16 @@ export default class UIWebSocketServer extends Server {
         } else {
           throw new BaseError('UI protocol request is not iterable');
         }
-        this.uiServices.get(version).handleMessage(command, payload).catch(() => {
-          logger.error(`${this.logPrefix()} Error while handling command %s message: %j`, command, payload);
-        });
+        this.uiServices
+          .get(version)
+          .handleMessage(command, payload)
+          .catch(() => {
+            logger.error(
+              `${this.logPrefix()} Error while handling command %s message: %j`,
+              command,
+              payload
+            );
+          });
       });
       socket.on('error', (error) => {
         logger.error(`${this.logPrefix()} Error on WebSocket: %j`, error);
index a9b79c134af9999f7dd64de9d5eec96e140de7c3..ef1c7db2e8d96b8c8dfb57edad7976e82a455a21 100644 (file)
@@ -1,10 +1,41 @@
 // Partial Copyright Jerome Benoit. 2021. All Rights Reserved.
 
-import { ChangeAvailabilityRequest, ChangeConfigurationRequest, ClearChargingProfileRequest, GetConfigurationRequest, GetDiagnosticsRequest, MessageTrigger, OCPP16AvailabilityType, OCPP16IncomingRequestCommand, OCPP16RequestCommand, OCPP16TriggerMessageRequest, RemoteStartTransactionRequest, RemoteStopTransactionRequest, ResetRequest, SetChargingProfileRequest, UnlockConnectorRequest } from '../../../types/ocpp/1.6/Requests';
-import { ChangeAvailabilityResponse, ChangeConfigurationResponse, ClearChargingProfileResponse, GetConfigurationResponse, GetDiagnosticsResponse, OCPP16TriggerMessageResponse, SetChargingProfileResponse, UnlockConnectorResponse } from '../../../types/ocpp/1.6/Responses';
-import { ChargingProfilePurposeType, OCPP16ChargingProfile } from '../../../types/ocpp/1.6/ChargingProfile';
+import {
+  ChangeAvailabilityRequest,
+  ChangeConfigurationRequest,
+  ClearChargingProfileRequest,
+  GetConfigurationRequest,
+  GetDiagnosticsRequest,
+  MessageTrigger,
+  OCPP16AvailabilityType,
+  OCPP16IncomingRequestCommand,
+  OCPP16RequestCommand,
+  OCPP16TriggerMessageRequest,
+  RemoteStartTransactionRequest,
+  RemoteStopTransactionRequest,
+  ResetRequest,
+  SetChargingProfileRequest,
+  UnlockConnectorRequest,
+} from '../../../types/ocpp/1.6/Requests';
+import {
+  ChangeAvailabilityResponse,
+  ChangeConfigurationResponse,
+  ClearChargingProfileResponse,
+  GetConfigurationResponse,
+  GetDiagnosticsResponse,
+  OCPP16TriggerMessageResponse,
+  SetChargingProfileResponse,
+  UnlockConnectorResponse,
+} from '../../../types/ocpp/1.6/Responses';
+import {
+  ChargingProfilePurposeType,
+  OCPP16ChargingProfile,
+} from '../../../types/ocpp/1.6/ChargingProfile';
 import { Client, FTPResponse } from 'basic-ftp';
-import { OCPP16AuthorizationStatus, OCPP16StopTransactionReason } from '../../../types/ocpp/1.6/Transaction';
+import {
+  OCPP16AuthorizationStatus,
+  OCPP16StopTransactionReason,
+} from '../../../types/ocpp/1.6/Transaction';
 
 import type ChargingStation from '../../ChargingStation';
 import Constants from '../../../utils/Constants';
@@ -39,25 +70,65 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
       [OCPP16IncomingRequestCommand.RESET, this.handleRequestReset.bind(this)],
       [OCPP16IncomingRequestCommand.CLEAR_CACHE, this.handleRequestClearCache.bind(this)],
       [OCPP16IncomingRequestCommand.UNLOCK_CONNECTOR, this.handleRequestUnlockConnector.bind(this)],
-      [OCPP16IncomingRequestCommand.GET_CONFIGURATION, this.handleRequestGetConfiguration.bind(this)],
-      [OCPP16IncomingRequestCommand.CHANGE_CONFIGURATION, this.handleRequestChangeConfiguration.bind(this)],
-      [OCPP16IncomingRequestCommand.SET_CHARGING_PROFILE, this.handleRequestSetChargingProfile.bind(this)],
-      [OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE, this.handleRequestClearChargingProfile.bind(this)],
-      [OCPP16IncomingRequestCommand.CHANGE_AVAILABILITY, this.handleRequestChangeAvailability.bind(this)],
-      [OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION, this.handleRequestRemoteStartTransaction.bind(this)],
-      [OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION, this.handleRequestRemoteStopTransaction.bind(this)],
+      [
+        OCPP16IncomingRequestCommand.GET_CONFIGURATION,
+        this.handleRequestGetConfiguration.bind(this),
+      ],
+      [
+        OCPP16IncomingRequestCommand.CHANGE_CONFIGURATION,
+        this.handleRequestChangeConfiguration.bind(this),
+      ],
+      [
+        OCPP16IncomingRequestCommand.SET_CHARGING_PROFILE,
+        this.handleRequestSetChargingProfile.bind(this),
+      ],
+      [
+        OCPP16IncomingRequestCommand.CLEAR_CHARGING_PROFILE,
+        this.handleRequestClearChargingProfile.bind(this),
+      ],
+      [
+        OCPP16IncomingRequestCommand.CHANGE_AVAILABILITY,
+        this.handleRequestChangeAvailability.bind(this),
+      ],
+      [
+        OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION,
+        this.handleRequestRemoteStartTransaction.bind(this),
+      ],
+      [
+        OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION,
+        this.handleRequestRemoteStopTransaction.bind(this),
+      ],
       [OCPP16IncomingRequestCommand.GET_DIAGNOSTICS, this.handleRequestGetDiagnostics.bind(this)],
-      [OCPP16IncomingRequestCommand.TRIGGER_MESSAGE, this.handleRequestTriggerMessage.bind(this)]
+      [OCPP16IncomingRequestCommand.TRIGGER_MESSAGE, this.handleRequestTriggerMessage.bind(this)],
     ]);
   }
 
-  public async handleRequest(messageId: string, commandName: OCPP16IncomingRequestCommand, commandPayload: JsonType): Promise<void> {
+  public async handleRequest(
+    messageId: string,
+    commandName: OCPP16IncomingRequestCommand,
+    commandPayload: JsonType
+  ): Promise<void> {
     let result: JsonType;
-    if (this.chargingStation.getOcppStrictCompliance() && (this.chargingStation.isInPendingState()
-      && (commandName === OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION || commandName === OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION))) {
-      throw new OCPPError(ErrorType.SECURITY_ERROR, `${commandName} cannot be issued to handle request payload ${JSON.stringify(commandPayload, null, 2)} while the charging station is in pending state on the central server`, commandName);
+    if (
+      this.chargingStation.getOcppStrictCompliance() &&
+      this.chargingStation.isInPendingState() &&
+      (commandName === OCPP16IncomingRequestCommand.REMOTE_START_TRANSACTION ||
+        commandName === OCPP16IncomingRequestCommand.REMOTE_STOP_TRANSACTION)
+    ) {
+      throw new OCPPError(
+        ErrorType.SECURITY_ERROR,
+        `${commandName} cannot be issued to handle request payload ${JSON.stringify(
+          commandPayload,
+          null,
+          2
+        )} while the charging station is in pending state on the central server`,
+        commandName
+      );
     }
-    if (this.chargingStation.isRegistered() || (!this.chargingStation.getOcppStrictCompliance() && this.chargingStation.isInUnknownState())) {
+    if (
+      this.chargingStation.isRegistered() ||
+      (!this.chargingStation.getOcppStrictCompliance() && this.chargingStation.isInUnknownState())
+    ) {
       if (this.incomingRequestHandlers.has(commandName)) {
         try {
           // Call the method to build the result
@@ -69,10 +140,26 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
         }
       } else {
         // Throw exception
-        throw new OCPPError(ErrorType.NOT_IMPLEMENTED, `${commandName} is not implemented to handle request payload ${JSON.stringify(commandPayload, null, 2)}`, commandName);
+        throw new OCPPError(
+          ErrorType.NOT_IMPLEMENTED,
+          `${commandName} is not implemented to handle request payload ${JSON.stringify(
+            commandPayload,
+            null,
+            2
+          )}`,
+          commandName
+        );
       }
     } else {
-      throw new OCPPError(ErrorType.SECURITY_ERROR, `${commandName} cannot be issued to handle request payload ${JSON.stringify(commandPayload, null, 2)} while the charging station is not registered on the central server.`, commandName);
+      throw new OCPPError(
+        ErrorType.SECURITY_ERROR,
+        `${commandName} cannot be issued to handle request payload ${JSON.stringify(
+          commandPayload,
+          null,
+          2
+        )} while the charging station is not registered on the central server.`,
+        commandName
+      );
     }
     // Send the built result
     await this.chargingStation.ocppRequestService.sendResult(messageId, result, commandName);
@@ -82,11 +169,19 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
   private handleRequestReset(commandPayload: ResetRequest): DefaultResponse {
     // eslint-disable-next-line @typescript-eslint/no-misused-promises
     setImmediate(async (): Promise<void> => {
-      await this.chargingStation.stop(commandPayload.type + 'Reset' as OCPP16StopTransactionReason);
+      await this.chargingStation.stop(
+        (commandPayload.type + 'Reset') as OCPP16StopTransactionReason
+      );
       await Utils.sleep(this.chargingStation.stationInfo.resetTime);
       this.chargingStation.start();
     });
-    logger.info(`${this.chargingStation.logPrefix()} ${commandPayload.type} reset command received, simulating it. The station will be back online in ${Utils.formatDurationMilliSeconds(this.chargingStation.stationInfo.resetTime)}`);
+    logger.info(
+      `${this.chargingStation.logPrefix()} ${
+        commandPayload.type
+      } reset command received, simulating it. The station will be back online in ${Utils.formatDurationMilliSeconds(
+        this.chargingStation.stationInfo.resetTime
+      )}`
+    );
     return Constants.OCPP_RESPONSE_ACCEPTED;
   }
 
@@ -94,29 +189,40 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
     return Constants.OCPP_RESPONSE_ACCEPTED;
   }
 
-  private async handleRequestUnlockConnector(commandPayload: UnlockConnectorRequest): Promise<UnlockConnectorResponse> {
+  private async handleRequestUnlockConnector(
+    commandPayload: UnlockConnectorRequest
+  ): Promise<UnlockConnectorResponse> {
     const connectorId = commandPayload.connectorId;
     if (connectorId === 0) {
-      logger.error(this.chargingStation.logPrefix() + ' Trying to unlock connector ' + connectorId.toString());
+      logger.error(
+        this.chargingStation.logPrefix() + ' Trying to unlock connector ' + connectorId.toString()
+      );
       return Constants.OCPP_RESPONSE_UNLOCK_NOT_SUPPORTED;
     }
     if (this.chargingStation.getConnectorStatus(connectorId)?.transactionStarted) {
       const transactionId = this.chargingStation.getConnectorStatus(connectorId).transactionId;
-      const stopResponse = await this.chargingStation.ocppRequestService.sendStopTransaction(transactionId,
+      const stopResponse = await this.chargingStation.ocppRequestService.sendStopTransaction(
+        transactionId,
         this.chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId),
         this.chargingStation.getTransactionIdTag(transactionId),
-        OCPP16StopTransactionReason.UNLOCK_COMMAND);
+        OCPP16StopTransactionReason.UNLOCK_COMMAND
+      );
       if (stopResponse.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) {
         return Constants.OCPP_RESPONSE_UNLOCKED;
       }
       return Constants.OCPP_RESPONSE_UNLOCK_FAILED;
     }
-    await this.chargingStation.ocppRequestService.sendStatusNotification(connectorId, OCPP16ChargePointStatus.AVAILABLE);
+    await this.chargingStation.ocppRequestService.sendStatusNotification(
+      connectorId,
+      OCPP16ChargePointStatus.AVAILABLE
+    );
     this.chargingStation.getConnectorStatus(connectorId).status = OCPP16ChargePointStatus.AVAILABLE;
     return Constants.OCPP_RESPONSE_UNLOCKED;
   }
 
-  private handleRequestGetConfiguration(commandPayload: GetConfigurationRequest): GetConfigurationResponse {
+  private handleRequestGetConfiguration(
+    commandPayload: GetConfigurationRequest
+  ): GetConfigurationResponse {
     const configurationKey: OCPPConfigurationKey[] = [];
     const unknownKey: string[] = [];
     if (Utils.isEmptyArray(commandPayload.key)) {
@@ -159,13 +265,25 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
     };
   }
 
-  private handleRequestChangeConfiguration(commandPayload: ChangeConfigurationRequest): ChangeConfigurationResponse {
+  private handleRequestChangeConfiguration(
+    commandPayload: ChangeConfigurationRequest
+  ): ChangeConfigurationResponse {
     // JSON request fields type sanity check
     if (!Utils.isString(commandPayload.key)) {
-      logger.error(`${this.chargingStation.logPrefix()} ${OCPP16RequestCommand.CHANGE_CONFIGURATION} request key field is not a string:`, commandPayload);
+      logger.error(
+        `${this.chargingStation.logPrefix()} ${
+          OCPP16RequestCommand.CHANGE_CONFIGURATION
+        } request key field is not a string:`,
+        commandPayload
+      );
     }
     if (!Utils.isString(commandPayload.value)) {
-      logger.error(`${this.chargingStation.logPrefix()} ${OCPP16RequestCommand.CHANGE_CONFIGURATION} request value field is not a string:`, commandPayload);
+      logger.error(
+        `${this.chargingStation.logPrefix()} ${
+          OCPP16RequestCommand.CHANGE_CONFIGURATION
+        } request value field is not a string:`,
+        commandPayload
+      );
     }
     const keyToChange = this.chargingStation.getConfigurationKey(commandPayload.key, true);
     if (!keyToChange) {
@@ -175,17 +293,25 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
     } else if (keyToChange && !keyToChange.readonly) {
       const keyIndex = this.chargingStation.configuration.configurationKey.indexOf(keyToChange);
       let valueChanged = false;
-      if (this.chargingStation.configuration.configurationKey[keyIndex].value !== commandPayload.value) {
+      if (
+        this.chargingStation.configuration.configurationKey[keyIndex].value !== commandPayload.value
+      ) {
         this.chargingStation.configuration.configurationKey[keyIndex].value = commandPayload.value;
         valueChanged = true;
       }
       let triggerHeartbeatRestart = false;
       if (keyToChange.key === OCPP16StandardParametersKey.HeartBeatInterval && valueChanged) {
-        this.chargingStation.setConfigurationKeyValue(OCPP16StandardParametersKey.HeartbeatInterval, commandPayload.value);
+        this.chargingStation.setConfigurationKeyValue(
+          OCPP16StandardParametersKey.HeartbeatInterval,
+          commandPayload.value
+        );
         triggerHeartbeatRestart = true;
       }
       if (keyToChange.key === OCPP16StandardParametersKey.HeartbeatInterval && valueChanged) {
-        this.chargingStation.setConfigurationKeyValue(OCPP16StandardParametersKey.HeartBeatInterval, commandPayload.value);
+        this.chargingStation.setConfigurationKeyValue(
+          OCPP16StandardParametersKey.HeartBeatInterval,
+          commandPayload.value
+        );
         triggerHeartbeatRestart = true;
       }
       if (triggerHeartbeatRestart) {
@@ -201,56 +327,110 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
     }
   }
 
-  private handleRequestSetChargingProfile(commandPayload: SetChargingProfileRequest): SetChargingProfileResponse {
+  private handleRequestSetChargingProfile(
+    commandPayload: SetChargingProfileRequest
+  ): SetChargingProfileResponse {
     if (!this.chargingStation.getConnectorStatus(commandPayload.connectorId)) {
-      logger.error(`${this.chargingStation.logPrefix()} Trying to set charging profile(s) to a non existing connector Id ${commandPayload.connectorId}`);
+      logger.error(
+        `${this.chargingStation.logPrefix()} Trying to set charging profile(s) to a non existing connector Id ${
+          commandPayload.connectorId
+        }`
+      );
       return Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED;
     }
-    if (commandPayload.csChargingProfiles.chargingProfilePurpose === ChargingProfilePurposeType.CHARGE_POINT_MAX_PROFILE && commandPayload.connectorId !== 0) {
+    if (
+      commandPayload.csChargingProfiles.chargingProfilePurpose ===
+        ChargingProfilePurposeType.CHARGE_POINT_MAX_PROFILE &&
+      commandPayload.connectorId !== 0
+    ) {
       return Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED;
     }
-    if (commandPayload.csChargingProfiles.chargingProfilePurpose === ChargingProfilePurposeType.TX_PROFILE && (commandPayload.connectorId === 0 || !this.chargingStation.getConnectorStatus(commandPayload.connectorId)?.transactionStarted)) {
+    if (
+      commandPayload.csChargingProfiles.chargingProfilePurpose ===
+        ChargingProfilePurposeType.TX_PROFILE &&
+      (commandPayload.connectorId === 0 ||
+        !this.chargingStation.getConnectorStatus(commandPayload.connectorId)?.transactionStarted)
+    ) {
       return Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED;
     }
-    this.chargingStation.setChargingProfile(commandPayload.connectorId, commandPayload.csChargingProfiles);
-    logger.debug(`${this.chargingStation.logPrefix()} Charging profile(s) set, dump their stack: %j`, this.chargingStation.getConnectorStatus(commandPayload.connectorId).chargingProfiles);
+    this.chargingStation.setChargingProfile(
+      commandPayload.connectorId,
+      commandPayload.csChargingProfiles
+    );
+    logger.debug(
+      `${this.chargingStation.logPrefix()} Charging profile(s) set, dump their stack: %j`,
+      this.chargingStation.getConnectorStatus(commandPayload.connectorId).chargingProfiles
+    );
     return Constants.OCPP_SET_CHARGING_PROFILE_RESPONSE_ACCEPTED;
   }
 
-  private handleRequestClearChargingProfile(commandPayload: ClearChargingProfileRequest): ClearChargingProfileResponse {
+  private handleRequestClearChargingProfile(
+    commandPayload: ClearChargingProfileRequest
+  ): ClearChargingProfileResponse {
     if (!this.chargingStation.getConnectorStatus(commandPayload.connectorId)) {
-      logger.error(`${this.chargingStation.logPrefix()} Trying to clear a charging profile(s) to a non existing connector Id ${commandPayload.connectorId}`);
+      logger.error(
+        `${this.chargingStation.logPrefix()} Trying to clear a charging profile(s) to a non existing connector Id ${
+          commandPayload.connectorId
+        }`
+      );
       return Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN;
     }
-    if (commandPayload.connectorId && !Utils.isEmptyArray(this.chargingStation.getConnectorStatus(commandPayload.connectorId).chargingProfiles)) {
+    if (
+      commandPayload.connectorId &&
+      !Utils.isEmptyArray(
+        this.chargingStation.getConnectorStatus(commandPayload.connectorId).chargingProfiles
+      )
+    ) {
       this.chargingStation.getConnectorStatus(commandPayload.connectorId).chargingProfiles = [];
-      logger.debug(`${this.chargingStation.logPrefix()} Charging profile(s) cleared, dump their stack: %j`, this.chargingStation.getConnectorStatus(commandPayload.connectorId).chargingProfiles);
+      logger.debug(
+        `${this.chargingStation.logPrefix()} Charging profile(s) cleared, dump their stack: %j`,
+        this.chargingStation.getConnectorStatus(commandPayload.connectorId).chargingProfiles
+      );
       return Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_ACCEPTED;
     }
     if (!commandPayload.connectorId) {
       let clearedCP = false;
       for (const connectorId of this.chargingStation.connectors.keys()) {
-        if (!Utils.isEmptyArray(this.chargingStation.getConnectorStatus(connectorId).chargingProfiles)) {
-          this.chargingStation.getConnectorStatus(connectorId).chargingProfiles?.forEach((chargingProfile: OCPP16ChargingProfile, index: number) => {
-            let clearCurrentCP = false;
-            if (chargingProfile.chargingProfileId === commandPayload.id) {
-              clearCurrentCP = true;
-            }
-            if (!commandPayload.chargingProfilePurpose && chargingProfile.stackLevel === commandPayload.stackLevel) {
-              clearCurrentCP = true;
-            }
-            if (!chargingProfile.stackLevel && chargingProfile.chargingProfilePurpose === commandPayload.chargingProfilePurpose) {
-              clearCurrentCP = true;
-            }
-            if (chargingProfile.stackLevel === commandPayload.stackLevel && chargingProfile.chargingProfilePurpose === commandPayload.chargingProfilePurpose) {
-              clearCurrentCP = true;
-            }
-            if (clearCurrentCP) {
-              this.chargingStation.getConnectorStatus(commandPayload.connectorId).chargingProfiles[index] = {} as OCPP16ChargingProfile;
-              logger.debug(`${this.chargingStation.logPrefix()} Charging profile(s) cleared, dump their stack: %j`, this.chargingStation.getConnectorStatus(commandPayload.connectorId).chargingProfiles);
-              clearedCP = true;
-            }
-          });
+        if (
+          !Utils.isEmptyArray(this.chargingStation.getConnectorStatus(connectorId).chargingProfiles)
+        ) {
+          this.chargingStation
+            .getConnectorStatus(connectorId)
+            .chargingProfiles?.forEach((chargingProfile: OCPP16ChargingProfile, index: number) => {
+              let clearCurrentCP = false;
+              if (chargingProfile.chargingProfileId === commandPayload.id) {
+                clearCurrentCP = true;
+              }
+              if (
+                !commandPayload.chargingProfilePurpose &&
+                chargingProfile.stackLevel === commandPayload.stackLevel
+              ) {
+                clearCurrentCP = true;
+              }
+              if (
+                !chargingProfile.stackLevel &&
+                chargingProfile.chargingProfilePurpose === commandPayload.chargingProfilePurpose
+              ) {
+                clearCurrentCP = true;
+              }
+              if (
+                chargingProfile.stackLevel === commandPayload.stackLevel &&
+                chargingProfile.chargingProfilePurpose === commandPayload.chargingProfilePurpose
+              ) {
+                clearCurrentCP = true;
+              }
+              if (clearCurrentCP) {
+                this.chargingStation.getConnectorStatus(
+                  commandPayload.connectorId
+                ).chargingProfiles[index] = {} as OCPP16ChargingProfile;
+                logger.debug(
+                  `${this.chargingStation.logPrefix()} Charging profile(s) cleared, dump their stack: %j`,
+                  this.chargingStation.getConnectorStatus(commandPayload.connectorId)
+                    .chargingProfiles
+                );
+                clearedCP = true;
+              }
+            });
         }
       }
       if (clearedCP) {
@@ -260,15 +440,20 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
     return Constants.OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN;
   }
 
-  private async handleRequestChangeAvailability(commandPayload: ChangeAvailabilityRequest): Promise<ChangeAvailabilityResponse> {
+  private async handleRequestChangeAvailability(
+    commandPayload: ChangeAvailabilityRequest
+  ): Promise<ChangeAvailabilityResponse> {
     const connectorId: number = commandPayload.connectorId;
     if (!this.chargingStation.getConnectorStatus(connectorId)) {
-      logger.error(`${this.chargingStation.logPrefix()} Trying to change the availability of a non existing connector Id ${connectorId.toString()}`);
+      logger.error(
+        `${this.chargingStation.logPrefix()} Trying to change the availability of a non existing connector Id ${connectorId.toString()}`
+      );
       return Constants.OCPP_AVAILABILITY_RESPONSE_REJECTED;
     }
-    const chargePointStatus: OCPP16ChargePointStatus = commandPayload.type === OCPP16AvailabilityType.OPERATIVE
-      ? OCPP16ChargePointStatus.AVAILABLE
-      : OCPP16ChargePointStatus.UNAVAILABLE;
+    const chargePointStatus: OCPP16ChargePointStatus =
+      commandPayload.type === OCPP16AvailabilityType.OPERATIVE
+        ? OCPP16ChargePointStatus.AVAILABLE
+        : OCPP16ChargePointStatus.UNAVAILABLE;
     if (connectorId === 0) {
       let response: ChangeAvailabilityResponse = Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED;
       for (const id of this.chargingStation.connectors.keys()) {
@@ -277,184 +462,390 @@ export default class OCPP16IncomingRequestService extends OCPPIncomingRequestSer
         }
         this.chargingStation.getConnectorStatus(id).availability = commandPayload.type;
         if (response === Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED) {
-          await this.chargingStation.ocppRequestService.sendStatusNotification(id, chargePointStatus);
+          await this.chargingStation.ocppRequestService.sendStatusNotification(
+            id,
+            chargePointStatus
+          );
           this.chargingStation.getConnectorStatus(id).status = chargePointStatus;
         }
       }
       return response;
-    } else if (connectorId > 0 && (this.chargingStation.getConnectorStatus(0).availability === OCPP16AvailabilityType.OPERATIVE || (this.chargingStation.getConnectorStatus(0).availability === OCPP16AvailabilityType.INOPERATIVE && commandPayload.type === OCPP16AvailabilityType.INOPERATIVE))) {
+    } else if (
+      connectorId > 0 &&
+      (this.chargingStation.getConnectorStatus(0).availability ===
+        OCPP16AvailabilityType.OPERATIVE ||
+        (this.chargingStation.getConnectorStatus(0).availability ===
+          OCPP16AvailabilityType.INOPERATIVE &&
+          commandPayload.type === OCPP16AvailabilityType.INOPERATIVE))
+    ) {
       if (this.chargingStation.getConnectorStatus(connectorId)?.transactionStarted) {
         this.chargingStation.getConnectorStatus(connectorId).availability = commandPayload.type;
         return Constants.OCPP_AVAILABILITY_RESPONSE_SCHEDULED;
       }
       this.chargingStation.getConnectorStatus(connectorId).availability = commandPayload.type;
-      await this.chargingStation.ocppRequestService.sendStatusNotification(connectorId, chargePointStatus);
+      await this.chargingStation.ocppRequestService.sendStatusNotification(
+        connectorId,
+        chargePointStatus
+      );
       this.chargingStation.getConnectorStatus(connectorId).status = chargePointStatus;
       return Constants.OCPP_AVAILABILITY_RESPONSE_ACCEPTED;
     }
     return Constants.OCPP_AVAILABILITY_RESPONSE_REJECTED;
   }
 
-  private async handleRequestRemoteStartTransaction(commandPayload: RemoteStartTransactionRequest): Promise<DefaultResponse> {
+  private async handleRequestRemoteStartTransaction(
+    commandPayload: RemoteStartTransactionRequest
+  ): Promise<DefaultResponse> {
     const transactionConnectorId: number = commandPayload.connectorId;
     if (transactionConnectorId) {
-      await this.chargingStation.ocppRequestService.sendStatusNotification(transactionConnectorId, OCPP16ChargePointStatus.PREPARING);
-      this.chargingStation.getConnectorStatus(transactionConnectorId).status = OCPP16ChargePointStatus.PREPARING;
-      if (this.chargingStation.isChargingStationAvailable() && this.chargingStation.isConnectorAvailable(transactionConnectorId)) {
+      await this.chargingStation.ocppRequestService.sendStatusNotification(
+        transactionConnectorId,
+        OCPP16ChargePointStatus.PREPARING
+      );
+      this.chargingStation.getConnectorStatus(transactionConnectorId).status =
+        OCPP16ChargePointStatus.PREPARING;
+      if (
+        this.chargingStation.isChargingStationAvailable() &&
+        this.chargingStation.isConnectorAvailable(transactionConnectorId)
+      ) {
         // Check if authorized
         if (this.chargingStation.getAuthorizeRemoteTxRequests()) {
           let authorized = false;
-          if (this.chargingStation.getLocalAuthListEnabled() && this.chargingStation.hasAuthorizedTags()
-            && this.chargingStation.authorizedTags.find((value) => value === commandPayload.idTag)) {
-            this.chargingStation.getConnectorStatus(transactionConnectorId).localAuthorizeIdTag = commandPayload.idTag;
-            this.chargingStation.getConnectorStatus(transactionConnectorId).idTagLocalAuthorized = true;
+          if (
+            this.chargingStation.getLocalAuthListEnabled() &&
+            this.chargingStation.hasAuthorizedTags() &&
+            this.chargingStation.authorizedTags.find((value) => value === commandPayload.idTag)
+          ) {
+            this.chargingStation.getConnectorStatus(transactionConnectorId).localAuthorizeIdTag =
+              commandPayload.idTag;
+            this.chargingStation.getConnectorStatus(transactionConnectorId).idTagLocalAuthorized =
+              true;
             authorized = true;
           } else if (this.chargingStation.getMayAuthorizeAtRemoteStart()) {
-            const authorizeResponse = await this.chargingStation.ocppRequestService.sendAuthorize(transactionConnectorId, commandPayload.idTag);
+            const authorizeResponse = await this.chargingStation.ocppRequestService.sendAuthorize(
+              transactionConnectorId,
+              commandPayload.idTag
+            );
             if (authorizeResponse?.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) {
               authorized = true;
             }
           } else {
-            logger.warn(`${this.chargingStation.logPrefix()} The charging station configuration expects authorize at remote start transaction but local authorization or authorize isn't enabled`);
+            logger.warn(
+              `${this.chargingStation.logPrefix()} The charging station configuration expects authorize at remote start transaction but local authorization or authorize isn't enabled`
+            );
           }
           if (authorized) {
             // Authorization successful, start transaction
-            if (this.setRemoteStartTransactionChargingProfile(transactionConnectorId, commandPayload.chargingProfile)) {
-              this.chargingStation.getConnectorStatus(transactionConnectorId).transactionRemoteStarted = true;
-              if ((await this.chargingStation.ocppRequestService.sendStartTransaction(transactionConnectorId, commandPayload.idTag)).idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED) {
-                logger.debug(this.chargingStation.logPrefix() + ' Transaction remotely STARTED on ' + this.chargingStation.stationInfo.chargingStationId + '#' + transactionConnectorId.toString() + ' for idTag ' + commandPayload.idTag);
+            if (
+              this.setRemoteStartTransactionChargingProfile(
+                transactionConnectorId,
+                commandPayload.chargingProfile
+              )
+            ) {
+              this.chargingStation.getConnectorStatus(
+                transactionConnectorId
+              ).transactionRemoteStarted = true;
+              if (
+                (
+                  await this.chargingStation.ocppRequestService.sendStartTransaction(
+                    transactionConnectorId,
+                    commandPayload.idTag
+                  )
+                ).idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED
+              ) {
+                logger.debug(
+                  this.chargingStation.logPrefix() +
+                    ' Transaction remotely STARTED on ' +
+                    this.chargingStation.stationInfo.chargingStationId +
+                    '#' +
+                    transactionConnectorId.toString() +
+                    ' for idTag ' +
+                    commandPayload.idTag
+                );
                 return Constants.OCPP_RESPONSE_ACCEPTED;
               }
-              return this.notifyRemoteStartTransactionRejected(transactionConnectorId, commandPayload.idTag);
+              return this.notifyRemoteStartTransactionRejected(
+                transactionConnectorId,
+                commandPayload.idTag
+              );
             }
-            return this.notifyRemoteStartTransactionRejected(transactionConnectorId, commandPayload.idTag);
+            return this.notifyRemoteStartTransactionRejected(
+              transactionConnectorId,
+              commandPayload.idTag
+            );
           }
-          return this.notifyRemoteStartTransactionRejected(transactionConnectorId, commandPayload.idTag);
+          return this.notifyRemoteStartTransactionRejected(
+            transactionConnectorId,
+            commandPayload.idTag
+          );
         }
         // No authorization check required, start transaction
-        if (this.setRemoteStartTransactionChargingProfile(transactionConnectorId, commandPayload.chargingProfile)) {
-          this.chargingStation.getConnectorStatus(transactionConnectorId).transactionRemoteStarted = true;
-          if ((await this.chargingStation.ocppRequestService.sendStartTransaction(transactionConnectorId, commandPayload.idTag)).idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED) {
-            logger.debug(this.chargingStation.logPrefix() + ' Transaction remotely STARTED on ' + this.chargingStation.stationInfo.chargingStationId + '#' + transactionConnectorId.toString() + ' for idTag ' + commandPayload.idTag);
+        if (
+          this.setRemoteStartTransactionChargingProfile(
+            transactionConnectorId,
+            commandPayload.chargingProfile
+          )
+        ) {
+          this.chargingStation.getConnectorStatus(transactionConnectorId).transactionRemoteStarted =
+            true;
+          if (
+            (
+              await this.chargingStation.ocppRequestService.sendStartTransaction(
+                transactionConnectorId,
+                commandPayload.idTag
+              )
+            ).idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED
+          ) {
+            logger.debug(
+              this.chargingStation.logPrefix() +
+                ' Transaction remotely STARTED on ' +
+                this.chargingStation.stationInfo.chargingStationId +
+                '#' +
+                transactionConnectorId.toString() +
+                ' for idTag ' +
+                commandPayload.idTag
+            );
             return Constants.OCPP_RESPONSE_ACCEPTED;
           }
-          return this.notifyRemoteStartTransactionRejected(transactionConnectorId, commandPayload.idTag);
+          return this.notifyRemoteStartTransactionRejected(
+            transactionConnectorId,
+            commandPayload.idTag
+          );
         }
-        return this.notifyRemoteStartTransactionRejected(transactionConnectorId, commandPayload.idTag);
+        return this.notifyRemoteStartTransactionRejected(
+          transactionConnectorId,
+          commandPayload.idTag
+        );
       }
-      return this.notifyRemoteStartTransactionRejected(transactionConnectorId, commandPayload.idTag);
+      return this.notifyRemoteStartTransactionRejected(
+        transactionConnectorId,
+        commandPayload.idTag
+      );
     }
     return this.notifyRemoteStartTransactionRejected(transactionConnectorId, commandPayload.idTag);
   }
 
-  private async notifyRemoteStartTransactionRejected(connectorId: number, idTag: string): Promise<DefaultResponse> {
-    if (this.chargingStation.getConnectorStatus(connectorId).status !== OCPP16ChargePointStatus.AVAILABLE) {
-      await this.chargingStation.ocppRequestService.sendStatusNotification(connectorId, OCPP16ChargePointStatus.AVAILABLE);
-      this.chargingStation.getConnectorStatus(connectorId).status = OCPP16ChargePointStatus.AVAILABLE;
+  private async notifyRemoteStartTransactionRejected(
+    connectorId: number,
+    idTag: string
+  ): Promise<DefaultResponse> {
+    if (
+      this.chargingStation.getConnectorStatus(connectorId).status !==
+      OCPP16ChargePointStatus.AVAILABLE
+    ) {
+      await this.chargingStation.ocppRequestService.sendStatusNotification(
+        connectorId,
+        OCPP16ChargePointStatus.AVAILABLE
+      );
+      this.chargingStation.getConnectorStatus(connectorId).status =
+        OCPP16ChargePointStatus.AVAILABLE;
     }
-    logger.warn(this.chargingStation.logPrefix() + ' Remote starting transaction REJECTED on connector Id ' + connectorId.toString() + ', idTag ' + idTag + ', availability ' + this.chargingStation.getConnectorStatus(connectorId).availability + ', status ' + this.chargingStation.getConnectorStatus(connectorId).status);
+    logger.warn(
+      this.chargingStation.logPrefix() +
+        ' Remote starting transaction REJECTED on connector Id ' +
+        connectorId.toString() +
+        ', idTag ' +
+        idTag +
+        ', availability ' +
+        this.chargingStation.getConnectorStatus(connectorId).availability +
+        ', status ' +
+        this.chargingStation.getConnectorStatus(connectorId).status
+    );
     return Constants.OCPP_RESPONSE_REJECTED;
   }
 
-  private setRemoteStartTransactionChargingProfile(connectorId: number, cp: OCPP16ChargingProfile): boolean {
+  private setRemoteStartTransactionChargingProfile(
+    connectorId: number,
+    cp: OCPP16ChargingProfile
+  ): boolean {
     if (cp && cp.chargingProfilePurpose === ChargingProfilePurposeType.TX_PROFILE) {
       this.chargingStation.setChargingProfile(connectorId, cp);
-      logger.debug(`${this.chargingStation.logPrefix()} Charging profile(s) set at remote start transaction, dump their stack: %j`, this.chargingStation.getConnectorStatus(connectorId).chargingProfiles);
+      logger.debug(
+        `${this.chargingStation.logPrefix()} Charging profile(s) set at remote start transaction, dump their stack: %j`,
+        this.chargingStation.getConnectorStatus(connectorId).chargingProfiles
+      );
       return true;
     } else if (cp && cp.chargingProfilePurpose !== ChargingProfilePurposeType.TX_PROFILE) {
-      logger.warn(`${this.chargingStation.logPrefix()} Not allowed to set ${cp.chargingProfilePurpose} charging profile(s) at remote start transaction`);
+      logger.warn(
+        `${this.chargingStation.logPrefix()} Not allowed to set ${
+          cp.chargingProfilePurpose
+        } charging profile(s) at remote start transaction`
+      );
       return false;
     } else if (!cp) {
       return true;
     }
   }
 
-  private async handleRequestRemoteStopTransaction(commandPayload: RemoteStopTransactionRequest): Promise<DefaultResponse> {
+  private async handleRequestRemoteStopTransaction(
+    commandPayload: RemoteStopTransactionRequest
+  ): Promise<DefaultResponse> {
     const transactionId = commandPayload.transactionId;
     for (const connectorId of this.chargingStation.connectors.keys()) {
-      if (connectorId > 0 && this.chargingStation.getConnectorStatus(connectorId)?.transactionId === transactionId) {
-        await this.chargingStation.ocppRequestService.sendStatusNotification(connectorId, OCPP16ChargePointStatus.FINISHING);
-        this.chargingStation.getConnectorStatus(connectorId).status = OCPP16ChargePointStatus.FINISHING;
-        await this.chargingStation.ocppRequestService.sendStopTransaction(transactionId, this.chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId),
-          this.chargingStation.getTransactionIdTag(transactionId));
+      if (
+        connectorId > 0 &&
+        this.chargingStation.getConnectorStatus(connectorId)?.transactionId === transactionId
+      ) {
+        await this.chargingStation.ocppRequestService.sendStatusNotification(
+          connectorId,
+          OCPP16ChargePointStatus.FINISHING
+        );
+        this.chargingStation.getConnectorStatus(connectorId).status =
+          OCPP16ChargePointStatus.FINISHING;
+        await this.chargingStation.ocppRequestService.sendStopTransaction(
+          transactionId,
+          this.chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId),
+          this.chargingStation.getTransactionIdTag(transactionId)
+        );
         return Constants.OCPP_RESPONSE_ACCEPTED;
       }
     }
-    logger.info(this.chargingStation.logPrefix() + ' Trying to remote stop a non existing transaction ' + transactionId.toString());
+    logger.info(
+      this.chargingStation.logPrefix() +
+        ' Trying to remote stop a non existing transaction ' +
+        transactionId.toString()
+    );
     return Constants.OCPP_RESPONSE_REJECTED;
   }
 
-  private async handleRequestGetDiagnostics(commandPayload: GetDiagnosticsRequest): Promise<GetDiagnosticsResponse> {
-    logger.debug(this.chargingStation.logPrefix() + ' ' + OCPP16IncomingRequestCommand.GET_DIAGNOSTICS + ' request received: %j', commandPayload);
+  private async handleRequestGetDiagnostics(
+    commandPayload: GetDiagnosticsRequest
+  ): Promise<GetDiagnosticsResponse> {
+    logger.debug(
+      this.chargingStation.logPrefix() +
+        ' ' +
+        OCPP16IncomingRequestCommand.GET_DIAGNOSTICS +
+        ' request received: %j',
+      commandPayload
+    );
     const uri = new URL(commandPayload.location);
     if (uri.protocol.startsWith('ftp:')) {
       let ftpClient: Client;
       try {
-        const logFiles = fs.readdirSync(path.resolve(__dirname, '../../../../')).filter((file) => file.endsWith('.log')).map((file) => path.join('./', file));
-        const diagnosticsArchive = this.chargingStation.stationInfo.chargingStationId + '_logs.tar.gz';
+        const logFiles = fs
+          .readdirSync(path.resolve(__dirname, '../../../../'))
+          .filter((file) => file.endsWith('.log'))
+          .map((file) => path.join('./', file));
+        const diagnosticsArchive =
+          this.chargingStation.stationInfo.chargingStationId + '_logs.tar.gz';
         tar.create({ gzip: true }, logFiles).pipe(fs.createWriteStream(diagnosticsArchive));
         ftpClient = new Client();
         const accessResponse = await ftpClient.access({
           host: uri.host,
-          ...(uri.port !== '') && { port: Utils.convertToInt(uri.port) },
-          ...(uri.username !== '') && { user: uri.username },
-          ...(uri.password !== '') && { password: uri.password },
+          ...(uri.port !== '' && { port: Utils.convertToInt(uri.port) }),
+          ...(uri.username !== '' && { user: uri.username }),
+          ...(uri.password !== '' && { password: uri.password }),
         });
         let uploadResponse: FTPResponse;
         if (accessResponse.code === 220) {
           // eslint-disable-next-line @typescript-eslint/no-misused-promises
           ftpClient.trackProgress(async (info) => {
-            logger.info(`${this.chargingStation.logPrefix()} ${info.bytes / 1024} bytes transferred from diagnostics archive ${info.name}`);
-            await this.chargingStation.ocppRequestService.sendDiagnosticsStatusNotification(OCPP16DiagnosticsStatus.Uploading);
+            logger.info(
+              `${this.chargingStation.logPrefix()} ${
+                info.bytes / 1024
+              } bytes transferred from diagnostics archive ${info.name}`
+            );
+            await this.chargingStation.ocppRequestService.sendDiagnosticsStatusNotification(
+              OCPP16DiagnosticsStatus.Uploading
+            );
           });
-          uploadResponse = await ftpClient.uploadFrom(path.join(path.resolve(__dirname, '../../../../'), diagnosticsArchive), uri.pathname + diagnosticsArchive);
+          uploadResponse = await ftpClient.uploadFrom(
+            path.join(path.resolve(__dirname, '../../../../'), diagnosticsArchive),
+            uri.pathname + diagnosticsArchive
+          );
           if (uploadResponse.code === 226) {
-            await this.chargingStation.ocppRequestService.sendDiagnosticsStatusNotification(OCPP16DiagnosticsStatus.Uploaded);
+            await this.chargingStation.ocppRequestService.sendDiagnosticsStatusNotification(
+              OCPP16DiagnosticsStatus.Uploaded
+            );
             if (ftpClient) {
               ftpClient.close();
             }
             return { fileName: diagnosticsArchive };
           }
-          throw new OCPPError(ErrorType.GENERIC_ERROR, `Diagnostics transfer failed with error code ${accessResponse.code.toString()}${uploadResponse?.code && '|' + uploadResponse?.code.toString()}`, OCPP16IncomingRequestCommand.GET_DIAGNOSTICS);
+          throw new OCPPError(
+            ErrorType.GENERIC_ERROR,
+            `Diagnostics transfer failed with error code ${accessResponse.code.toString()}${
+              uploadResponse?.code && '|' + uploadResponse?.code.toString()
+            }`,
+            OCPP16IncomingRequestCommand.GET_DIAGNOSTICS
+          );
         }
-        throw new OCPPError(ErrorType.GENERIC_ERROR, `Diagnostics transfer failed with error code ${accessResponse.code.toString()}${uploadResponse?.code && '|' + uploadResponse?.code.toString()}`, OCPP16IncomingRequestCommand.GET_DIAGNOSTICS);
+        throw new OCPPError(
+          ErrorType.GENERIC_ERROR,
+          `Diagnostics transfer failed with error code ${accessResponse.code.toString()}${
+            uploadResponse?.code && '|' + uploadResponse?.code.toString()
+          }`,
+          OCPP16IncomingRequestCommand.GET_DIAGNOSTICS
+        );
       } catch (error) {
-        await this.chargingStation.ocppRequestService.sendDiagnosticsStatusNotification(OCPP16DiagnosticsStatus.UploadFailed);
+        await this.chargingStation.ocppRequestService.sendDiagnosticsStatusNotification(
+          OCPP16DiagnosticsStatus.UploadFailed
+        );
         if (ftpClient) {
           ftpClient.close();
         }
-        return this.handleIncomingRequestError(OCPP16IncomingRequestCommand.GET_DIAGNOSTICS, error as Error, { errorResponse: Constants.OCPP_RESPONSE_EMPTY });
+        return this.handleIncomingRequestError(
+          OCPP16IncomingRequestCommand.GET_DIAGNOSTICS,
+          error as Error,
+          { errorResponse: Constants.OCPP_RESPONSE_EMPTY }
+        );
       }
     } else {
-      logger.error(`${this.chargingStation.logPrefix()} Unsupported protocol ${uri.protocol} to transfer the diagnostic logs archive`);
-      await this.chargingStation.ocppRequestService.sendDiagnosticsStatusNotification(OCPP16DiagnosticsStatus.UploadFailed);
+      logger.error(
+        `${this.chargingStation.logPrefix()} Unsupported protocol ${
+          uri.protocol
+        } to transfer the diagnostic logs archive`
+      );
+      await this.chargingStation.ocppRequestService.sendDiagnosticsStatusNotification(
+        OCPP16DiagnosticsStatus.UploadFailed
+      );
       return Constants.OCPP_RESPONSE_EMPTY;
     }
   }
 
-  private handleRequestTriggerMessage(commandPayload: OCPP16TriggerMessageRequest): OCPP16TriggerMessageResponse {
+  private handleRequestTriggerMessage(
+    commandPayload: OCPP16TriggerMessageRequest
+  ): OCPP16TriggerMessageResponse {
     try {
       switch (commandPayload.requestedMessage) {
         case MessageTrigger.BootNotification:
           setTimeout(() => {
-            this.chargingStation.ocppRequestService.sendBootNotification(this.chargingStation.getBootNotificationRequest().chargePointModel,
-              this.chargingStation.getBootNotificationRequest().chargePointVendor, this.chargingStation.getBootNotificationRequest().chargeBoxSerialNumber,
-              this.chargingStation.getBootNotificationRequest().firmwareVersion, this.chargingStation.getBootNotificationRequest().chargePointSerialNumber,
-              this.chargingStation.getBootNotificationRequest().iccid, this.chargingStation.getBootNotificationRequest().imsi,
-              this.chargingStation.getBootNotificationRequest().meterSerialNumber, this.chargingStation.getBootNotificationRequest().meterType,
-              { triggerMessage: true }).catch(() => { /* This is intentional */ });
+            this.chargingStation.ocppRequestService
+              .sendBootNotification(
+                this.chargingStation.getBootNotificationRequest().chargePointModel,
+                this.chargingStation.getBootNotificationRequest().chargePointVendor,
+                this.chargingStation.getBootNotificationRequest().chargeBoxSerialNumber,
+                this.chargingStation.getBootNotificationRequest().firmwareVersion,
+                this.chargingStation.getBootNotificationRequest().chargePointSerialNumber,
+                this.chargingStation.getBootNotificationRequest().iccid,
+                this.chargingStation.getBootNotificationRequest().imsi,
+                this.chargingStation.getBootNotificationRequest().meterSerialNumber,
+                this.chargingStation.getBootNotificationRequest().meterType,
+                { triggerMessage: true }
+              )
+              .catch(() => {
+                /* This is intentional */
+              });
           }, Constants.OCPP_TRIGGER_MESSAGE_DELAY);
           return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED;
         case MessageTrigger.Heartbeat:
           setTimeout(() => {
-            this.chargingStation.ocppRequestService.sendHeartbeat({ triggerMessage: true }).catch(() => { /* This is intentional */ });
+            this.chargingStation.ocppRequestService
+              .sendHeartbeat({ triggerMessage: true })
+              .catch(() => {
+                /* This is intentional */
+              });
           }, Constants.OCPP_TRIGGER_MESSAGE_DELAY);
           return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED;
         default:
           return Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_NOT_IMPLEMENTED;
       }
     } catch (error) {
-      return this.handleIncomingRequestError(OCPP16IncomingRequestCommand.TRIGGER_MESSAGE, error as Error, { errorResponse: Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_REJECTED });
+      return this.handleIncomingRequestError(
+        OCPP16IncomingRequestCommand.TRIGGER_MESSAGE,
+        error as Error,
+        { errorResponse: Constants.OCPP_TRIGGER_MESSAGE_RESPONSE_REJECTED }
+      );
     }
   }
 }
index c97ee4bf5be9db8e3e2034a312ca3bcf865d36fb..0e50589a51f9b8c539f8e438f8912c7ddf1e3be9 100644 (file)
@@ -1,10 +1,30 @@
 // Partial Copyright Jerome Benoit. 2021. All Rights Reserved.
 
 import { ACElectricUtils, DCElectricUtils } from '../../../utils/ElectricUtils';
-import { AuthorizeRequest, OCPP16AuthorizeResponse, OCPP16StartTransactionResponse, OCPP16StopTransactionReason, OCPP16StopTransactionResponse, StartTransactionRequest, StopTransactionRequest } from '../../../types/ocpp/1.6/Transaction';
+import {
+  AuthorizeRequest,
+  OCPP16AuthorizeResponse,
+  OCPP16StartTransactionResponse,
+  OCPP16StopTransactionReason,
+  OCPP16StopTransactionResponse,
+  StartTransactionRequest,
+  StopTransactionRequest,
+} from '../../../types/ocpp/1.6/Transaction';
 import { CurrentType, Voltage } from '../../../types/ChargingStationTemplate';
-import { DiagnosticsStatusNotificationRequest, HeartbeatRequest, OCPP16BootNotificationRequest, OCPP16RequestCommand, StatusNotificationRequest } from '../../../types/ocpp/1.6/Requests';
-import { MeterValueUnit, MeterValuesRequest, OCPP16MeterValue, OCPP16MeterValueMeasurand, OCPP16MeterValuePhase } from '../../../types/ocpp/1.6/MeterValues';
+import {
+  DiagnosticsStatusNotificationRequest,
+  HeartbeatRequest,
+  OCPP16BootNotificationRequest,
+  OCPP16RequestCommand,
+  StatusNotificationRequest,
+} from '../../../types/ocpp/1.6/Requests';
+import {
+  MeterValueUnit,
+  MeterValuesRequest,
+  OCPP16MeterValue,
+  OCPP16MeterValueMeasurand,
+  OCPP16MeterValuePhase,
+} from '../../../types/ocpp/1.6/MeterValues';
 
 import type ChargingStation from '../../ChargingStation';
 import Constants from '../../../utils/Constants';
@@ -38,26 +58,42 @@ export default class OCPP16RequestService extends OCPPRequestService {
     await this.sendMessage(Utils.generateUUID(), payload, OCPP16RequestCommand.HEARTBEAT, params);
   }
 
-  public async sendBootNotification(chargePointModel: string, chargePointVendor: string, chargeBoxSerialNumber?: string, firmwareVersion?: string,
-      chargePointSerialNumber?: string, iccid?: string, imsi?: string, meterSerialNumber?: string, meterType?: string,
-      params?: SendParams): Promise<OCPP16BootNotificationResponse> {
+  public async sendBootNotification(
+    chargePointModel: string,
+    chargePointVendor: string,
+    chargeBoxSerialNumber?: string,
+    firmwareVersion?: string,
+    chargePointSerialNumber?: string,
+    iccid?: string,
+    imsi?: string,
+    meterSerialNumber?: string,
+    meterType?: string,
+    params?: SendParams
+  ): Promise<OCPP16BootNotificationResponse> {
     const payload: OCPP16BootNotificationRequest = {
       chargePointModel,
       chargePointVendor,
-      ...!Utils.isUndefined(chargeBoxSerialNumber) && { chargeBoxSerialNumber },
-      ...!Utils.isUndefined(chargePointSerialNumber) && { chargePointSerialNumber },
-      ...!Utils.isUndefined(firmwareVersion) && { firmwareVersion },
-      ...!Utils.isUndefined(iccid) && { iccid },
-      ...!Utils.isUndefined(imsi) && { imsi },
-      ...!Utils.isUndefined(meterSerialNumber) && { meterSerialNumber },
-      ...!Utils.isUndefined(meterType) && { meterType }
+      ...(!Utils.isUndefined(chargeBoxSerialNumber) && { chargeBoxSerialNumber }),
+      ...(!Utils.isUndefined(chargePointSerialNumber) && { chargePointSerialNumber }),
+      ...(!Utils.isUndefined(firmwareVersion) && { firmwareVersion }),
+      ...(!Utils.isUndefined(iccid) && { iccid }),
+      ...(!Utils.isUndefined(imsi) && { imsi }),
+      ...(!Utils.isUndefined(meterSerialNumber) && { meterSerialNumber }),
+      ...(!Utils.isUndefined(meterType) && { meterType }),
     };
-    return await this.sendMessage(Utils.generateUUID(), payload, OCPP16RequestCommand.BOOT_NOTIFICATION,
-      { ...params, skipBufferingOnError: true }) as OCPP16BootNotificationResponse;
+    return (await this.sendMessage(
+      Utils.generateUUID(),
+      payload,
+      OCPP16RequestCommand.BOOT_NOTIFICATION,
+      { ...params, skipBufferingOnError: true }
+    )) as OCPP16BootNotificationResponse;
   }
 
-  public async sendStatusNotification(connectorId: number, status: OCPP16ChargePointStatus,
-      errorCode: OCPP16ChargePointErrorCode = OCPP16ChargePointErrorCode.NO_ERROR): Promise<void> {
+  public async sendStatusNotification(
+    connectorId: number,
+    status: OCPP16ChargePointStatus,
+    errorCode: OCPP16ChargePointErrorCode = OCPP16ChargePointErrorCode.NO_ERROR
+  ): Promise<void> {
     const payload: StatusNotificationRequest = {
       connectorId,
       errorCode,
@@ -66,26 +102,44 @@ export default class OCPP16RequestService extends OCPPRequestService {
     await this.sendMessage(Utils.generateUUID(), payload, OCPP16RequestCommand.STATUS_NOTIFICATION);
   }
 
-  public async sendAuthorize(connectorId: number, idTag?: string): Promise<OCPP16AuthorizeResponse> {
+  public async sendAuthorize(
+    connectorId: number,
+    idTag?: string
+  ): Promise<OCPP16AuthorizeResponse> {
     const payload: AuthorizeRequest = {
-      ...!Utils.isUndefined(idTag) ? { idTag } : { idTag: Constants.DEFAULT_IDTAG },
+      ...(!Utils.isUndefined(idTag) ? { idTag } : { idTag: Constants.DEFAULT_IDTAG }),
     };
     this.chargingStation.getConnectorStatus(connectorId).authorizeIdTag = idTag;
-    return await this.sendMessage(Utils.generateUUID(), payload, OCPP16RequestCommand.AUTHORIZE) as OCPP16AuthorizeResponse;
+    return (await this.sendMessage(
+      Utils.generateUUID(),
+      payload,
+      OCPP16RequestCommand.AUTHORIZE
+    )) as OCPP16AuthorizeResponse;
   }
 
-  public async sendStartTransaction(connectorId: number, idTag?: string): Promise<OCPP16StartTransactionResponse> {
+  public async sendStartTransaction(
+    connectorId: number,
+    idTag?: string
+  ): Promise<OCPP16StartTransactionResponse> {
     const payload: StartTransactionRequest = {
       connectorId,
-      ...!Utils.isUndefined(idTag) ? { idTag } : { idTag: Constants.DEFAULT_IDTAG },
+      ...(!Utils.isUndefined(idTag) ? { idTag } : { idTag: Constants.DEFAULT_IDTAG }),
       meterStart: this.chargingStation.getEnergyActiveImportRegisterByConnectorId(connectorId),
       timestamp: new Date().toISOString(),
     };
-    return await this.sendMessage(Utils.generateUUID(), payload, OCPP16RequestCommand.START_TRANSACTION) as OCPP16StartTransactionResponse;
+    return (await this.sendMessage(
+      Utils.generateUUID(),
+      payload,
+      OCPP16RequestCommand.START_TRANSACTION
+    )) as OCPP16StartTransactionResponse;
   }
 
-  public async sendStopTransaction(transactionId: number, meterStop: number, idTag?: string,
-      reason: OCPP16StopTransactionReason = OCPP16StopTransactionReason.NONE): Promise<OCPP16StopTransactionResponse> {
+  public async sendStopTransaction(
+    transactionId: number,
+    meterStop: number,
+    idTag?: string,
+    reason: OCPP16StopTransactionReason = OCPP16StopTransactionReason.NONE
+  ): Promise<OCPP16StopTransactionResponse> {
     let connectorId: number;
     for (const id of this.chargingStation.connectors.keys()) {
       if (id > 0 && this.chargingStation.getConnectorStatus(id)?.transactionId === transactionId) {
@@ -93,229 +147,595 @@ export default class OCPP16RequestService extends OCPPRequestService {
         break;
       }
     }
-    const transactionEndMeterValue = OCPP16ServiceUtils.buildTransactionEndMeterValue(this.chargingStation, connectorId, meterStop);
+    const transactionEndMeterValue = OCPP16ServiceUtils.buildTransactionEndMeterValue(
+      this.chargingStation,
+      connectorId,
+      meterStop
+    );
     // FIXME: should be a callback, each OCPP commands implementation must do only one job
-    (this.chargingStation.getBeginEndMeterValues() && this.chargingStation.getOcppStrictCompliance() && !this.chargingStation.getOutOfOrderEndMeterValues())
-        && await this.sendTransactionEndMeterValues(connectorId, transactionId, transactionEndMeterValue);
+    this.chargingStation.getBeginEndMeterValues() &&
+      this.chargingStation.getOcppStrictCompliance() &&
+      !this.chargingStation.getOutOfOrderEndMeterValues() &&
+      (await this.sendTransactionEndMeterValues(
+        connectorId,
+        transactionId,
+        transactionEndMeterValue
+      ));
     const payload: StopTransactionRequest = {
       transactionId,
-      ...!Utils.isUndefined(idTag) && { idTag },
+      ...(!Utils.isUndefined(idTag) && { idTag }),
       meterStop,
       timestamp: new Date().toISOString(),
-      ...reason && { reason },
-      ...this.chargingStation.getTransactionDataMeterValues() && { transactionData: OCPP16ServiceUtils.buildTransactionDataMeterValues(this.chargingStation.getConnectorStatus(connectorId).transactionBeginMeterValue, transactionEndMeterValue) },
+      ...(reason && { reason }),
+      ...(this.chargingStation.getTransactionDataMeterValues() && {
+        transactionData: OCPP16ServiceUtils.buildTransactionDataMeterValues(
+          this.chargingStation.getConnectorStatus(connectorId).transactionBeginMeterValue,
+          transactionEndMeterValue
+        ),
+      }),
     };
-    return await this.sendMessage(Utils.generateUUID(), payload, OCPP16RequestCommand.STOP_TRANSACTION) as OCPP16StartTransactionResponse;
+    return (await this.sendMessage(
+      Utils.generateUUID(),
+      payload,
+      OCPP16RequestCommand.STOP_TRANSACTION
+    )) as OCPP16StartTransactionResponse;
   }
 
-  public async sendMeterValues(connectorId: number, transactionId: number, interval: number, debug = false): Promise<void> {
+  public async sendMeterValues(
+    connectorId: number,
+    transactionId: number,
+    interval: number,
+    debug = false
+  ): Promise<void> {
     const meterValue: OCPP16MeterValue = {
       timestamp: new Date().toISOString(),
       sampledValue: [],
     };
     const connector = this.chargingStation.getConnectorStatus(connectorId);
     // SoC measurand
-    const socSampledValueTemplate = this.chargingStation.getSampledValueTemplate(connectorId, OCPP16MeterValueMeasurand.STATE_OF_CHARGE);
+    const socSampledValueTemplate = this.chargingStation.getSampledValueTemplate(
+      connectorId,
+      OCPP16MeterValueMeasurand.STATE_OF_CHARGE
+    );
     if (socSampledValueTemplate) {
       const socSampledValueTemplateValue = socSampledValueTemplate.value
-        ? Utils.getRandomFloatFluctuatedRounded(parseInt(socSampledValueTemplate.value), socSampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT)
+        ? Utils.getRandomFloatFluctuatedRounded(
+            parseInt(socSampledValueTemplate.value),
+            socSampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT
+          )
         : Utils.getRandomInteger(100);
-      meterValue.sampledValue.push(OCPP16ServiceUtils.buildSampledValue(socSampledValueTemplate, socSampledValueTemplateValue));
+      meterValue.sampledValue.push(
+        OCPP16ServiceUtils.buildSampledValue(socSampledValueTemplate, socSampledValueTemplateValue)
+      );
       const sampledValuesIndex = meterValue.sampledValue.length - 1;
       if (Utils.convertToInt(meterValue.sampledValue[sampledValuesIndex].value) > 100 || debug) {
-        logger.error(`${this.chargingStation.logPrefix()} MeterValues measurand ${meterValue.sampledValue[sampledValuesIndex].measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${meterValue.sampledValue[sampledValuesIndex].value}/100`);
+        logger.error(
+          `${this.chargingStation.logPrefix()} MeterValues measurand ${
+            meterValue.sampledValue[sampledValuesIndex].measurand ??
+            OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
+          }: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${
+            meterValue.sampledValue[sampledValuesIndex].value
+          }/100`
+        );
       }
     }
     // Voltage measurand
-    const voltageSampledValueTemplate = this.chargingStation.getSampledValueTemplate(connectorId, OCPP16MeterValueMeasurand.VOLTAGE);
+    const voltageSampledValueTemplate = this.chargingStation.getSampledValueTemplate(
+      connectorId,
+      OCPP16MeterValueMeasurand.VOLTAGE
+    );
     if (voltageSampledValueTemplate) {
-      const voltageSampledValueTemplateValue = voltageSampledValueTemplate.value ? parseInt(voltageSampledValueTemplate.value) : this.chargingStation.getVoltageOut();
-      const fluctuationPercent = voltageSampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT;
-      const voltageMeasurandValue = Utils.getRandomFloatFluctuatedRounded(voltageSampledValueTemplateValue, fluctuationPercent);
-      if (this.chargingStation.getNumberOfPhases() !== 3 || (this.chargingStation.getNumberOfPhases() === 3 && this.chargingStation.getMainVoltageMeterValues())) {
-        meterValue.sampledValue.push(OCPP16ServiceUtils.buildSampledValue(voltageSampledValueTemplate, voltageMeasurandValue));
+      const voltageSampledValueTemplateValue = voltageSampledValueTemplate.value
+        ? parseInt(voltageSampledValueTemplate.value)
+        : this.chargingStation.getVoltageOut();
+      const fluctuationPercent =
+        voltageSampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT;
+      const voltageMeasurandValue = Utils.getRandomFloatFluctuatedRounded(
+        voltageSampledValueTemplateValue,
+        fluctuationPercent
+      );
+      if (
+        this.chargingStation.getNumberOfPhases() !== 3 ||
+        (this.chargingStation.getNumberOfPhases() === 3 &&
+          this.chargingStation.getMainVoltageMeterValues())
+      ) {
+        meterValue.sampledValue.push(
+          OCPP16ServiceUtils.buildSampledValue(voltageSampledValueTemplate, voltageMeasurandValue)
+        );
       }
-      for (let phase = 1; this.chargingStation.getNumberOfPhases() === 3 && phase <= this.chargingStation.getNumberOfPhases(); phase++) {
+      for (
+        let phase = 1;
+        this.chargingStation.getNumberOfPhases() === 3 &&
+        phase <= this.chargingStation.getNumberOfPhases();
+        phase++
+      ) {
         const phaseLineToNeutralValue = `L${phase}-N`;
-        const voltagePhaseLineToNeutralSampledValueTemplate = this.chargingStation.getSampledValueTemplate(connectorId, OCPP16MeterValueMeasurand.VOLTAGE,
-          phaseLineToNeutralValue as OCPP16MeterValuePhase);
+        const voltagePhaseLineToNeutralSampledValueTemplate =
+          this.chargingStation.getSampledValueTemplate(
+            connectorId,
+            OCPP16MeterValueMeasurand.VOLTAGE,
+            phaseLineToNeutralValue as OCPP16MeterValuePhase
+          );
         let voltagePhaseLineToNeutralMeasurandValue: number;
         if (voltagePhaseLineToNeutralSampledValueTemplate) {
-          const voltagePhaseLineToNeutralSampledValueTemplateValue = voltagePhaseLineToNeutralSampledValueTemplate.value ? parseInt(voltagePhaseLineToNeutralSampledValueTemplate.value) : this.chargingStation.getVoltageOut();
-          const fluctuationPhaseToNeutralPercent = voltagePhaseLineToNeutralSampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT;
-          voltagePhaseLineToNeutralMeasurandValue = Utils.getRandomFloatFluctuatedRounded(voltagePhaseLineToNeutralSampledValueTemplateValue, fluctuationPhaseToNeutralPercent);
+          const voltagePhaseLineToNeutralSampledValueTemplateValue =
+            voltagePhaseLineToNeutralSampledValueTemplate.value
+              ? parseInt(voltagePhaseLineToNeutralSampledValueTemplate.value)
+              : this.chargingStation.getVoltageOut();
+          const fluctuationPhaseToNeutralPercent =
+            voltagePhaseLineToNeutralSampledValueTemplate.fluctuationPercent ??
+            Constants.DEFAULT_FLUCTUATION_PERCENT;
+          voltagePhaseLineToNeutralMeasurandValue = Utils.getRandomFloatFluctuatedRounded(
+            voltagePhaseLineToNeutralSampledValueTemplateValue,
+            fluctuationPhaseToNeutralPercent
+          );
         }
-        meterValue.sampledValue.push(OCPP16ServiceUtils.buildSampledValue(voltagePhaseLineToNeutralSampledValueTemplate ?? voltageSampledValueTemplate,
-          voltagePhaseLineToNeutralMeasurandValue ?? voltageMeasurandValue, null, phaseLineToNeutralValue as OCPP16MeterValuePhase));
+        meterValue.sampledValue.push(
+          OCPP16ServiceUtils.buildSampledValue(
+            voltagePhaseLineToNeutralSampledValueTemplate ?? voltageSampledValueTemplate,
+            voltagePhaseLineToNeutralMeasurandValue ?? voltageMeasurandValue,
+            null,
+            phaseLineToNeutralValue as OCPP16MeterValuePhase
+          )
+        );
         if (this.chargingStation.getPhaseLineToLineVoltageMeterValues()) {
-          const phaseLineToLineValue = `L${phase}-L${(phase + 1) % this.chargingStation.getNumberOfPhases() !== 0 ? (phase + 1) % this.chargingStation.getNumberOfPhases() : this.chargingStation.getNumberOfPhases()}`;
-          const voltagePhaseLineToLineSampledValueTemplate = this.chargingStation.getSampledValueTemplate(connectorId, OCPP16MeterValueMeasurand.VOLTAGE, phaseLineToLineValue as OCPP16MeterValuePhase);
+          const phaseLineToLineValue = `L${phase}-L${
+            (phase + 1) % this.chargingStation.getNumberOfPhases() !== 0
+              ? (phase + 1) % this.chargingStation.getNumberOfPhases()
+              : this.chargingStation.getNumberOfPhases()
+          }`;
+          const voltagePhaseLineToLineSampledValueTemplate =
+            this.chargingStation.getSampledValueTemplate(
+              connectorId,
+              OCPP16MeterValueMeasurand.VOLTAGE,
+              phaseLineToLineValue as OCPP16MeterValuePhase
+            );
           let voltagePhaseLineToLineMeasurandValue: number;
           if (voltagePhaseLineToLineSampledValueTemplate) {
-            const voltagePhaseLineToLineSampledValueTemplateValue = voltagePhaseLineToLineSampledValueTemplate.value ? parseInt(voltagePhaseLineToLineSampledValueTemplate.value) : Voltage.VOLTAGE_400;
-            const fluctuationPhaseLineToLinePercent = voltagePhaseLineToLineSampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT;
-            voltagePhaseLineToLineMeasurandValue = Utils.getRandomFloatFluctuatedRounded(voltagePhaseLineToLineSampledValueTemplateValue, fluctuationPhaseLineToLinePercent);
+            const voltagePhaseLineToLineSampledValueTemplateValue =
+              voltagePhaseLineToLineSampledValueTemplate.value
+                ? parseInt(voltagePhaseLineToLineSampledValueTemplate.value)
+                : Voltage.VOLTAGE_400;
+            const fluctuationPhaseLineToLinePercent =
+              voltagePhaseLineToLineSampledValueTemplate.fluctuationPercent ??
+              Constants.DEFAULT_FLUCTUATION_PERCENT;
+            voltagePhaseLineToLineMeasurandValue = Utils.getRandomFloatFluctuatedRounded(
+              voltagePhaseLineToLineSampledValueTemplateValue,
+              fluctuationPhaseLineToLinePercent
+            );
           }
-          const defaultVoltagePhaseLineToLineMeasurandValue = Utils.getRandomFloatFluctuatedRounded(Voltage.VOLTAGE_400, fluctuationPercent);
-          meterValue.sampledValue.push(OCPP16ServiceUtils.buildSampledValue(voltagePhaseLineToLineSampledValueTemplate ?? voltageSampledValueTemplate,
-            voltagePhaseLineToLineMeasurandValue ?? defaultVoltagePhaseLineToLineMeasurandValue, null, phaseLineToLineValue as OCPP16MeterValuePhase));
+          const defaultVoltagePhaseLineToLineMeasurandValue = Utils.getRandomFloatFluctuatedRounded(
+            Voltage.VOLTAGE_400,
+            fluctuationPercent
+          );
+          meterValue.sampledValue.push(
+            OCPP16ServiceUtils.buildSampledValue(
+              voltagePhaseLineToLineSampledValueTemplate ?? voltageSampledValueTemplate,
+              voltagePhaseLineToLineMeasurandValue ?? defaultVoltagePhaseLineToLineMeasurandValue,
+              null,
+              phaseLineToLineValue as OCPP16MeterValuePhase
+            )
+          );
         }
       }
     }
     // Power.Active.Import measurand
-    const powerSampledValueTemplate = this.chargingStation.getSampledValueTemplate(connectorId, OCPP16MeterValueMeasurand.POWER_ACTIVE_IMPORT);
+    const powerSampledValueTemplate = this.chargingStation.getSampledValueTemplate(
+      connectorId,
+      OCPP16MeterValueMeasurand.POWER_ACTIVE_IMPORT
+    );
     let powerPerPhaseSampledValueTemplates: MeasurandPerPhaseSampledValueTemplates = {};
     if (this.chargingStation.getNumberOfPhases() === 3) {
       powerPerPhaseSampledValueTemplates = {
-        L1: this.chargingStation.getSampledValueTemplate(connectorId, OCPP16MeterValueMeasurand.POWER_ACTIVE_IMPORT, OCPP16MeterValuePhase.L1_N),
-        L2: this.chargingStation.getSampledValueTemplate(connectorId, OCPP16MeterValueMeasurand.POWER_ACTIVE_IMPORT, OCPP16MeterValuePhase.L2_N),
-        L3: this.chargingStation.getSampledValueTemplate(connectorId, OCPP16MeterValueMeasurand.POWER_ACTIVE_IMPORT, OCPP16MeterValuePhase.L3_N),
+        L1: this.chargingStation.getSampledValueTemplate(
+          connectorId,
+          OCPP16MeterValueMeasurand.POWER_ACTIVE_IMPORT,
+          OCPP16MeterValuePhase.L1_N
+        ),
+        L2: this.chargingStation.getSampledValueTemplate(
+          connectorId,
+          OCPP16MeterValueMeasurand.POWER_ACTIVE_IMPORT,
+          OCPP16MeterValuePhase.L2_N
+        ),
+        L3: this.chargingStation.getSampledValueTemplate(
+          connectorId,
+          OCPP16MeterValueMeasurand.POWER_ACTIVE_IMPORT,
+          OCPP16MeterValuePhase.L3_N
+        ),
       };
     }
     if (powerSampledValueTemplate) {
-      OCPP16ServiceUtils.checkMeasurandPowerDivider(this.chargingStation, powerSampledValueTemplate.measurand);
-      const errMsg = `${this.chargingStation.logPrefix()} MeterValues measurand ${powerSampledValueTemplate.measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: Unknown ${this.chargingStation.getCurrentOutType()} currentOutType in template file ${this.chargingStation.stationTemplateFile}, cannot calculate ${powerSampledValueTemplate.measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER} measurand value`;
+      OCPP16ServiceUtils.checkMeasurandPowerDivider(
+        this.chargingStation,
+        powerSampledValueTemplate.measurand
+      );
+      const errMsg = `${this.chargingStation.logPrefix()} MeterValues measurand ${
+        powerSampledValueTemplate.measurand ??
+        OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
+      }: Unknown ${this.chargingStation.getCurrentOutType()} currentOutType in template file ${
+        this.chargingStation.stationTemplateFile
+      }, cannot calculate ${
+        powerSampledValueTemplate.measurand ??
+        OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
+      } measurand value`;
       const powerMeasurandValues = {} as MeasurandValues;
       const unitDivider = powerSampledValueTemplate?.unit === MeterValueUnit.KILO_WATT ? 1000 : 1;
-      const maxPower = Math.round(this.chargingStation.stationInfo.maxPower / this.chargingStation.stationInfo.powerDivider);
-      const maxPowerPerPhase = Math.round((this.chargingStation.stationInfo.maxPower / this.chargingStation.stationInfo.powerDivider) / this.chargingStation.getNumberOfPhases());
+      const maxPower = Math.round(
+        this.chargingStation.stationInfo.maxPower / this.chargingStation.stationInfo.powerDivider
+      );
+      const maxPowerPerPhase = Math.round(
+        this.chargingStation.stationInfo.maxPower /
+          this.chargingStation.stationInfo.powerDivider /
+          this.chargingStation.getNumberOfPhases()
+      );
       switch (this.chargingStation.getCurrentOutType()) {
         case CurrentType.AC:
           if (this.chargingStation.getNumberOfPhases() === 3) {
-            const defaultFluctuatedPowerPerPhase = powerSampledValueTemplate.value
-                && Utils.getRandomFloatFluctuatedRounded(parseInt(powerSampledValueTemplate.value) / this.chargingStation.getNumberOfPhases(), powerSampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT);
-            const phase1FluctuatedValue = powerPerPhaseSampledValueTemplates?.L1?.value
-                && Utils.getRandomFloatFluctuatedRounded(parseInt(powerPerPhaseSampledValueTemplates.L1.value), powerPerPhaseSampledValueTemplates.L1.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT);
-            const phase2FluctuatedValue = powerPerPhaseSampledValueTemplates?.L2?.value
-                && Utils.getRandomFloatFluctuatedRounded(parseInt(powerPerPhaseSampledValueTemplates.L2.value), powerPerPhaseSampledValueTemplates.L2.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT);
-            const phase3FluctuatedValue = powerPerPhaseSampledValueTemplates?.L3?.value
-                && Utils.getRandomFloatFluctuatedRounded(parseInt(powerPerPhaseSampledValueTemplates.L3.value), powerPerPhaseSampledValueTemplates.L3.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT);
-            powerMeasurandValues.L1 = (phase1FluctuatedValue ?? defaultFluctuatedPowerPerPhase) ?? Utils.getRandomFloatRounded(maxPowerPerPhase / unitDivider);
-            powerMeasurandValues.L2 = (phase2FluctuatedValue ?? defaultFluctuatedPowerPerPhase) ?? Utils.getRandomFloatRounded(maxPowerPerPhase / unitDivider);
-            powerMeasurandValues.L3 = (phase3FluctuatedValue ?? defaultFluctuatedPowerPerPhase) ?? Utils.getRandomFloatRounded(maxPowerPerPhase / unitDivider);
+            const defaultFluctuatedPowerPerPhase =
+              powerSampledValueTemplate.value &&
+              Utils.getRandomFloatFluctuatedRounded(
+                parseInt(powerSampledValueTemplate.value) /
+                  this.chargingStation.getNumberOfPhases(),
+                powerSampledValueTemplate.fluctuationPercent ??
+                  Constants.DEFAULT_FLUCTUATION_PERCENT
+              );
+            const phase1FluctuatedValue =
+              powerPerPhaseSampledValueTemplates?.L1?.value &&
+              Utils.getRandomFloatFluctuatedRounded(
+                parseInt(powerPerPhaseSampledValueTemplates.L1.value),
+                powerPerPhaseSampledValueTemplates.L1.fluctuationPercent ??
+                  Constants.DEFAULT_FLUCTUATION_PERCENT
+              );
+            const phase2FluctuatedValue =
+              powerPerPhaseSampledValueTemplates?.L2?.value &&
+              Utils.getRandomFloatFluctuatedRounded(
+                parseInt(powerPerPhaseSampledValueTemplates.L2.value),
+                powerPerPhaseSampledValueTemplates.L2.fluctuationPercent ??
+                  Constants.DEFAULT_FLUCTUATION_PERCENT
+              );
+            const phase3FluctuatedValue =
+              powerPerPhaseSampledValueTemplates?.L3?.value &&
+              Utils.getRandomFloatFluctuatedRounded(
+                parseInt(powerPerPhaseSampledValueTemplates.L3.value),
+                powerPerPhaseSampledValueTemplates.L3.fluctuationPercent ??
+                  Constants.DEFAULT_FLUCTUATION_PERCENT
+              );
+            powerMeasurandValues.L1 =
+              phase1FluctuatedValue ??
+              defaultFluctuatedPowerPerPhase ??
+              Utils.getRandomFloatRounded(maxPowerPerPhase / unitDivider);
+            powerMeasurandValues.L2 =
+              phase2FluctuatedValue ??
+              defaultFluctuatedPowerPerPhase ??
+              Utils.getRandomFloatRounded(maxPowerPerPhase / unitDivider);
+            powerMeasurandValues.L3 =
+              phase3FluctuatedValue ??
+              defaultFluctuatedPowerPerPhase ??
+              Utils.getRandomFloatRounded(maxPowerPerPhase / unitDivider);
           } else {
             powerMeasurandValues.L1 = powerSampledValueTemplate.value
-              ? Utils.getRandomFloatFluctuatedRounded(parseInt(powerSampledValueTemplate.value), powerSampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT)
+              ? Utils.getRandomFloatFluctuatedRounded(
+                  parseInt(powerSampledValueTemplate.value),
+                  powerSampledValueTemplate.fluctuationPercent ??
+                    Constants.DEFAULT_FLUCTUATION_PERCENT
+                )
               : Utils.getRandomFloatRounded(maxPower / unitDivider);
             powerMeasurandValues.L2 = 0;
             powerMeasurandValues.L3 = 0;
           }
-          powerMeasurandValues.allPhases = Utils.roundTo(powerMeasurandValues.L1 + powerMeasurandValues.L2 + powerMeasurandValues.L3, 2);
+          powerMeasurandValues.allPhases = Utils.roundTo(
+            powerMeasurandValues.L1 + powerMeasurandValues.L2 + powerMeasurandValues.L3,
+            2
+          );
           break;
         case CurrentType.DC:
           powerMeasurandValues.allPhases = powerSampledValueTemplate.value
-            ? Utils.getRandomFloatFluctuatedRounded(parseInt(powerSampledValueTemplate.value), powerSampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT)
+            ? Utils.getRandomFloatFluctuatedRounded(
+                parseInt(powerSampledValueTemplate.value),
+                powerSampledValueTemplate.fluctuationPercent ??
+                  Constants.DEFAULT_FLUCTUATION_PERCENT
+              )
             : Utils.getRandomFloatRounded(maxPower / unitDivider);
           break;
         default:
           logger.error(errMsg);
           throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, OCPP16RequestCommand.METER_VALUES);
       }
-      meterValue.sampledValue.push(OCPP16ServiceUtils.buildSampledValue(powerSampledValueTemplate, powerMeasurandValues.allPhases));
+      meterValue.sampledValue.push(
+        OCPP16ServiceUtils.buildSampledValue(
+          powerSampledValueTemplate,
+          powerMeasurandValues.allPhases
+        )
+      );
       const sampledValuesIndex = meterValue.sampledValue.length - 1;
       const maxPowerRounded = Utils.roundTo(maxPower / unitDivider, 2);
-      if (Utils.convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) > maxPowerRounded || debug) {
-        logger.error(`${this.chargingStation.logPrefix()} MeterValues measurand ${meterValue.sampledValue[sampledValuesIndex].measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${meterValue.sampledValue[sampledValuesIndex].value}/${maxPowerRounded}`);
+      if (
+        Utils.convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) > maxPowerRounded ||
+        debug
+      ) {
+        logger.error(
+          `${this.chargingStation.logPrefix()} MeterValues measurand ${
+            meterValue.sampledValue[sampledValuesIndex].measurand ??
+            OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
+          }: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${
+            meterValue.sampledValue[sampledValuesIndex].value
+          }/${maxPowerRounded}`
+        );
       }
-      for (let phase = 1; this.chargingStation.getNumberOfPhases() === 3 && phase <= this.chargingStation.getNumberOfPhases(); phase++) {
+      for (
+        let phase = 1;
+        this.chargingStation.getNumberOfPhases() === 3 &&
+        phase <= this.chargingStation.getNumberOfPhases();
+        phase++
+      ) {
         const phaseValue = `L${phase}-N`;
-        meterValue.sampledValue.push(OCPP16ServiceUtils.buildSampledValue(powerPerPhaseSampledValueTemplates[`L${phase}`] ?? powerSampledValueTemplate, powerMeasurandValues[`L${phase}`], null,
-          phaseValue as OCPP16MeterValuePhase));
+        meterValue.sampledValue.push(
+          OCPP16ServiceUtils.buildSampledValue(
+            powerPerPhaseSampledValueTemplates[`L${phase}`] ?? powerSampledValueTemplate,
+            powerMeasurandValues[`L${phase}`],
+            null,
+            phaseValue as OCPP16MeterValuePhase
+          )
+        );
         const sampledValuesPerPhaseIndex = meterValue.sampledValue.length - 1;
         const maxPowerPerPhaseRounded = Utils.roundTo(maxPowerPerPhase / unitDivider, 2);
-        if (Utils.convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value) > maxPowerPerPhaseRounded || debug) {
-          logger.error(`${this.chargingStation.logPrefix()} MeterValues measurand ${meterValue.sampledValue[sampledValuesPerPhaseIndex].measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: phase ${meterValue.sampledValue[sampledValuesPerPhaseIndex].phase}, connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${meterValue.sampledValue[sampledValuesPerPhaseIndex].value}/${maxPowerPerPhaseRounded}`);
+        if (
+          Utils.convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value) >
+            maxPowerPerPhaseRounded ||
+          debug
+        ) {
+          logger.error(
+            `${this.chargingStation.logPrefix()} MeterValues measurand ${
+              meterValue.sampledValue[sampledValuesPerPhaseIndex].measurand ??
+              OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
+            }: phase ${
+              meterValue.sampledValue[sampledValuesPerPhaseIndex].phase
+            }, connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${
+              meterValue.sampledValue[sampledValuesPerPhaseIndex].value
+            }/${maxPowerPerPhaseRounded}`
+          );
         }
       }
     }
     // Current.Import measurand
-    const currentSampledValueTemplate = this.chargingStation.getSampledValueTemplate(connectorId, OCPP16MeterValueMeasurand.CURRENT_IMPORT);
+    const currentSampledValueTemplate = this.chargingStation.getSampledValueTemplate(
+      connectorId,
+      OCPP16MeterValueMeasurand.CURRENT_IMPORT
+    );
     let currentPerPhaseSampledValueTemplates: MeasurandPerPhaseSampledValueTemplates = {};
     if (this.chargingStation.getNumberOfPhases() === 3) {
       currentPerPhaseSampledValueTemplates = {
-        L1: this.chargingStation.getSampledValueTemplate(connectorId, OCPP16MeterValueMeasurand.CURRENT_IMPORT, OCPP16MeterValuePhase.L1),
-        L2: this.chargingStation.getSampledValueTemplate(connectorId, OCPP16MeterValueMeasurand.CURRENT_IMPORT, OCPP16MeterValuePhase.L2),
-        L3: this.chargingStation.getSampledValueTemplate(connectorId, OCPP16MeterValueMeasurand.CURRENT_IMPORT, OCPP16MeterValuePhase.L3),
+        L1: this.chargingStation.getSampledValueTemplate(
+          connectorId,
+          OCPP16MeterValueMeasurand.CURRENT_IMPORT,
+          OCPP16MeterValuePhase.L1
+        ),
+        L2: this.chargingStation.getSampledValueTemplate(
+          connectorId,
+          OCPP16MeterValueMeasurand.CURRENT_IMPORT,
+          OCPP16MeterValuePhase.L2
+        ),
+        L3: this.chargingStation.getSampledValueTemplate(
+          connectorId,
+          OCPP16MeterValueMeasurand.CURRENT_IMPORT,
+          OCPP16MeterValuePhase.L3
+        ),
       };
     }
     if (currentSampledValueTemplate) {
-      OCPP16ServiceUtils.checkMeasurandPowerDivider(this.chargingStation, currentSampledValueTemplate.measurand);
-      const errMsg = `${this.chargingStation.logPrefix()} MeterValues measurand ${currentSampledValueTemplate.measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: Unknown ${this.chargingStation.getCurrentOutType()} currentOutType in template file ${this.chargingStation.stationTemplateFile}, cannot calculate ${currentSampledValueTemplate.measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER} measurand value`;
+      OCPP16ServiceUtils.checkMeasurandPowerDivider(
+        this.chargingStation,
+        currentSampledValueTemplate.measurand
+      );
+      const errMsg = `${this.chargingStation.logPrefix()} MeterValues measurand ${
+        currentSampledValueTemplate.measurand ??
+        OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
+      }: Unknown ${this.chargingStation.getCurrentOutType()} currentOutType in template file ${
+        this.chargingStation.stationTemplateFile
+      }, cannot calculate ${
+        currentSampledValueTemplate.measurand ??
+        OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
+      } measurand value`;
       const currentMeasurandValues: MeasurandValues = {} as MeasurandValues;
       let maxAmperage: number;
       switch (this.chargingStation.getCurrentOutType()) {
         case CurrentType.AC:
-          maxAmperage = ACElectricUtils.amperagePerPhaseFromPower(this.chargingStation.getNumberOfPhases(), this.chargingStation.stationInfo.maxPower / this.chargingStation.stationInfo.powerDivider, this.chargingStation.getVoltageOut());
+          maxAmperage = ACElectricUtils.amperagePerPhaseFromPower(
+            this.chargingStation.getNumberOfPhases(),
+            this.chargingStation.stationInfo.maxPower /
+              this.chargingStation.stationInfo.powerDivider,
+            this.chargingStation.getVoltageOut()
+          );
           if (this.chargingStation.getNumberOfPhases() === 3) {
-            const defaultFluctuatedAmperagePerPhase = currentSampledValueTemplate.value
-                && Utils.getRandomFloatFluctuatedRounded(parseInt(currentSampledValueTemplate.value), currentSampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT);
-            const phase1FluctuatedValue = currentPerPhaseSampledValueTemplates?.L1?.value
-                && Utils.getRandomFloatFluctuatedRounded(parseInt(currentPerPhaseSampledValueTemplates.L1.value), currentPerPhaseSampledValueTemplates.L1.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT);
-            const phase2FluctuatedValue = currentPerPhaseSampledValueTemplates?.L2?.value
-                && Utils.getRandomFloatFluctuatedRounded(parseInt(currentPerPhaseSampledValueTemplates.L2.value), currentPerPhaseSampledValueTemplates.L2.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT);
-            const phase3FluctuatedValue = currentPerPhaseSampledValueTemplates?.L3?.value
-                && Utils.getRandomFloatFluctuatedRounded(parseInt(currentPerPhaseSampledValueTemplates.L3.value), currentPerPhaseSampledValueTemplates.L3.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT);
-            currentMeasurandValues.L1 = (phase1FluctuatedValue ?? defaultFluctuatedAmperagePerPhase) ?? Utils.getRandomFloatRounded(maxAmperage);
-            currentMeasurandValues.L2 = (phase2FluctuatedValue ?? defaultFluctuatedAmperagePerPhase) ?? Utils.getRandomFloatRounded(maxAmperage);
-            currentMeasurandValues.L3 = (phase3FluctuatedValue ?? defaultFluctuatedAmperagePerPhase) ?? Utils.getRandomFloatRounded(maxAmperage);
+            const defaultFluctuatedAmperagePerPhase =
+              currentSampledValueTemplate.value &&
+              Utils.getRandomFloatFluctuatedRounded(
+                parseInt(currentSampledValueTemplate.value),
+                currentSampledValueTemplate.fluctuationPercent ??
+                  Constants.DEFAULT_FLUCTUATION_PERCENT
+              );
+            const phase1FluctuatedValue =
+              currentPerPhaseSampledValueTemplates?.L1?.value &&
+              Utils.getRandomFloatFluctuatedRounded(
+                parseInt(currentPerPhaseSampledValueTemplates.L1.value),
+                currentPerPhaseSampledValueTemplates.L1.fluctuationPercent ??
+                  Constants.DEFAULT_FLUCTUATION_PERCENT
+              );
+            const phase2FluctuatedValue =
+              currentPerPhaseSampledValueTemplates?.L2?.value &&
+              Utils.getRandomFloatFluctuatedRounded(
+                parseInt(currentPerPhaseSampledValueTemplates.L2.value),
+                currentPerPhaseSampledValueTemplates.L2.fluctuationPercent ??
+                  Constants.DEFAULT_FLUCTUATION_PERCENT
+              );
+            const phase3FluctuatedValue =
+              currentPerPhaseSampledValueTemplates?.L3?.value &&
+              Utils.getRandomFloatFluctuatedRounded(
+                parseInt(currentPerPhaseSampledValueTemplates.L3.value),
+                currentPerPhaseSampledValueTemplates.L3.fluctuationPercent ??
+                  Constants.DEFAULT_FLUCTUATION_PERCENT
+              );
+            currentMeasurandValues.L1 =
+              phase1FluctuatedValue ??
+              defaultFluctuatedAmperagePerPhase ??
+              Utils.getRandomFloatRounded(maxAmperage);
+            currentMeasurandValues.L2 =
+              phase2FluctuatedValue ??
+              defaultFluctuatedAmperagePerPhase ??
+              Utils.getRandomFloatRounded(maxAmperage);
+            currentMeasurandValues.L3 =
+              phase3FluctuatedValue ??
+              defaultFluctuatedAmperagePerPhase ??
+              Utils.getRandomFloatRounded(maxAmperage);
           } else {
             currentMeasurandValues.L1 = currentSampledValueTemplate.value
-              ? Utils.getRandomFloatFluctuatedRounded(parseInt(currentSampledValueTemplate.value), currentSampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT)
+              ? Utils.getRandomFloatFluctuatedRounded(
+                  parseInt(currentSampledValueTemplate.value),
+                  currentSampledValueTemplate.fluctuationPercent ??
+                    Constants.DEFAULT_FLUCTUATION_PERCENT
+                )
               : Utils.getRandomFloatRounded(maxAmperage);
             currentMeasurandValues.L2 = 0;
             currentMeasurandValues.L3 = 0;
           }
-          currentMeasurandValues.allPhases = Utils.roundTo((currentMeasurandValues.L1 + currentMeasurandValues.L2 + currentMeasurandValues.L3) / this.chargingStation.getNumberOfPhases(), 2);
+          currentMeasurandValues.allPhases = Utils.roundTo(
+            (currentMeasurandValues.L1 + currentMeasurandValues.L2 + currentMeasurandValues.L3) /
+              this.chargingStation.getNumberOfPhases(),
+            2
+          );
           break;
         case CurrentType.DC:
-          maxAmperage = DCElectricUtils.amperage(this.chargingStation.stationInfo.maxPower / this.chargingStation.stationInfo.powerDivider, this.chargingStation.getVoltageOut());
+          maxAmperage = DCElectricUtils.amperage(
+            this.chargingStation.stationInfo.maxPower /
+              this.chargingStation.stationInfo.powerDivider,
+            this.chargingStation.getVoltageOut()
+          );
           currentMeasurandValues.allPhases = currentSampledValueTemplate.value
-            ? Utils.getRandomFloatFluctuatedRounded(parseInt(currentSampledValueTemplate.value), currentSampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT)
+            ? Utils.getRandomFloatFluctuatedRounded(
+                parseInt(currentSampledValueTemplate.value),
+                currentSampledValueTemplate.fluctuationPercent ??
+                  Constants.DEFAULT_FLUCTUATION_PERCENT
+              )
             : Utils.getRandomFloatRounded(maxAmperage);
           break;
         default:
           logger.error(errMsg);
           throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, OCPP16RequestCommand.METER_VALUES);
       }
-      meterValue.sampledValue.push(OCPP16ServiceUtils.buildSampledValue(currentSampledValueTemplate, currentMeasurandValues.allPhases));
+      meterValue.sampledValue.push(
+        OCPP16ServiceUtils.buildSampledValue(
+          currentSampledValueTemplate,
+          currentMeasurandValues.allPhases
+        )
+      );
       const sampledValuesIndex = meterValue.sampledValue.length - 1;
-      if (Utils.convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) > maxAmperage || debug) {
-        logger.error(`${this.chargingStation.logPrefix()} MeterValues measurand ${meterValue.sampledValue[sampledValuesIndex].measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${meterValue.sampledValue[sampledValuesIndex].value}/${maxAmperage}`);
+      if (
+        Utils.convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) > maxAmperage ||
+        debug
+      ) {
+        logger.error(
+          `${this.chargingStation.logPrefix()} MeterValues measurand ${
+            meterValue.sampledValue[sampledValuesIndex].measurand ??
+            OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
+          }: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${
+            meterValue.sampledValue[sampledValuesIndex].value
+          }/${maxAmperage}`
+        );
       }
-      for (let phase = 1; this.chargingStation.getNumberOfPhases() === 3 && phase <= this.chargingStation.getNumberOfPhases(); phase++) {
+      for (
+        let phase = 1;
+        this.chargingStation.getNumberOfPhases() === 3 &&
+        phase <= this.chargingStation.getNumberOfPhases();
+        phase++
+      ) {
         const phaseValue = `L${phase}`;
-        meterValue.sampledValue.push(OCPP16ServiceUtils.buildSampledValue(currentPerPhaseSampledValueTemplates[phaseValue] ?? currentSampledValueTemplate,
-          currentMeasurandValues[phaseValue], null, phaseValue as OCPP16MeterValuePhase));
+        meterValue.sampledValue.push(
+          OCPP16ServiceUtils.buildSampledValue(
+            currentPerPhaseSampledValueTemplates[phaseValue] ?? currentSampledValueTemplate,
+            currentMeasurandValues[phaseValue],
+            null,
+            phaseValue as OCPP16MeterValuePhase
+          )
+        );
         const sampledValuesPerPhaseIndex = meterValue.sampledValue.length - 1;
-        if (Utils.convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value) > maxAmperage || debug) {
-          logger.error(`${this.chargingStation.logPrefix()} MeterValues measurand ${meterValue.sampledValue[sampledValuesPerPhaseIndex].measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: phase ${meterValue.sampledValue[sampledValuesPerPhaseIndex].phase}, connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${meterValue.sampledValue[sampledValuesPerPhaseIndex].value}/${maxAmperage}`);
+        if (
+          Utils.convertToFloat(meterValue.sampledValue[sampledValuesPerPhaseIndex].value) >
+            maxAmperage ||
+          debug
+        ) {
+          logger.error(
+            `${this.chargingStation.logPrefix()} MeterValues measurand ${
+              meterValue.sampledValue[sampledValuesPerPhaseIndex].measurand ??
+              OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
+            }: phase ${
+              meterValue.sampledValue[sampledValuesPerPhaseIndex].phase
+            }, connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${
+              meterValue.sampledValue[sampledValuesPerPhaseIndex].value
+            }/${maxAmperage}`
+          );
         }
       }
     }
     // Energy.Active.Import.Register measurand (default)
     const energySampledValueTemplate = this.chargingStation.getSampledValueTemplate(connectorId);
     if (energySampledValueTemplate) {
-      OCPP16ServiceUtils.checkMeasurandPowerDivider(this.chargingStation, energySampledValueTemplate.measurand);
-      const unitDivider = energySampledValueTemplate?.unit === MeterValueUnit.KILO_WATT_HOUR ? 1000 : 1;
-      const maxEnergyRounded = Utils.roundTo(((this.chargingStation.stationInfo.maxPower / this.chargingStation.stationInfo.powerDivider) * interval) / (3600 * 1000), 2);
+      OCPP16ServiceUtils.checkMeasurandPowerDivider(
+        this.chargingStation,
+        energySampledValueTemplate.measurand
+      );
+      const unitDivider =
+        energySampledValueTemplate?.unit === MeterValueUnit.KILO_WATT_HOUR ? 1000 : 1;
+      const maxEnergyRounded = Utils.roundTo(
+        ((this.chargingStation.stationInfo.maxPower /
+          this.chargingStation.stationInfo.powerDivider) *
+          interval) /
+          (3600 * 1000),
+        2
+      );
       const energyValueRounded = energySampledValueTemplate.value
-      // Cumulate the fluctuated value around the static one
-        ? Utils.getRandomFloatFluctuatedRounded(parseInt(energySampledValueTemplate.value), energySampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT)
+        ? // Cumulate the fluctuated value around the static one
+          Utils.getRandomFloatFluctuatedRounded(
+            parseInt(energySampledValueTemplate.value),
+            energySampledValueTemplate.fluctuationPercent ?? Constants.DEFAULT_FLUCTUATION_PERCENT
+          )
         : Utils.getRandomFloatRounded(maxEnergyRounded);
-        // Persist previous value on connector
-      if (connector && !Utils.isNullOrUndefined(connector.energyActiveImportRegisterValue) && connector.energyActiveImportRegisterValue >= 0 &&
-          !Utils.isNullOrUndefined(connector.transactionEnergyActiveImportRegisterValue) && connector.transactionEnergyActiveImportRegisterValue >= 0) {
+      // Persist previous value on connector
+      if (
+        connector &&
+        !Utils.isNullOrUndefined(connector.energyActiveImportRegisterValue) &&
+        connector.energyActiveImportRegisterValue >= 0 &&
+        !Utils.isNullOrUndefined(connector.transactionEnergyActiveImportRegisterValue) &&
+        connector.transactionEnergyActiveImportRegisterValue >= 0
+      ) {
         connector.energyActiveImportRegisterValue += energyValueRounded;
         connector.transactionEnergyActiveImportRegisterValue += energyValueRounded;
       } else {
         connector.energyActiveImportRegisterValue = 0;
         connector.transactionEnergyActiveImportRegisterValue = 0;
       }
-      meterValue.sampledValue.push(OCPP16ServiceUtils.buildSampledValue(energySampledValueTemplate,
-        Utils.roundTo(this.chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId) / unitDivider, 2)));
+      meterValue.sampledValue.push(
+        OCPP16ServiceUtils.buildSampledValue(
+          energySampledValueTemplate,
+          Utils.roundTo(
+            this.chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId) /
+              unitDivider,
+            2
+          )
+        )
+      );
       const sampledValuesIndex = meterValue.sampledValue.length - 1;
       if (energyValueRounded > maxEnergyRounded || debug) {
-        logger.error(`${this.chargingStation.logPrefix()} MeterValues measurand ${meterValue.sampledValue[sampledValuesIndex].measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${energyValueRounded}/${maxEnergyRounded}, duration: ${Utils.roundTo(interval / (3600 * 1000), 4)}h`);
+        logger.error(
+          `${this.chargingStation.logPrefix()} MeterValues measurand ${
+            meterValue.sampledValue[sampledValuesIndex].measurand ??
+            OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
+          }: connectorId ${connectorId}, transaction ${
+            connector.transactionId
+          }, value: ${energyValueRounded}/${maxEnergyRounded}, duration: ${Utils.roundTo(
+            interval / (3600 * 1000),
+            4
+          )}h`
+        );
       }
     }
     const payload: MeterValuesRequest = {
@@ -326,7 +746,11 @@ export default class OCPP16RequestService extends OCPPRequestService {
     await this.sendMessage(Utils.generateUUID(), payload, OCPP16RequestCommand.METER_VALUES);
   }
 
-  public async sendTransactionBeginMeterValues(connectorId: number, transactionId: number, beginMeterValue: OCPP16MeterValue): Promise<void> {
+  public async sendTransactionBeginMeterValues(
+    connectorId: number,
+    transactionId: number,
+    beginMeterValue: OCPP16MeterValue
+  ): Promise<void> {
     const payload: MeterValuesRequest = {
       connectorId,
       transactionId,
@@ -335,7 +759,11 @@ export default class OCPP16RequestService extends OCPPRequestService {
     await this.sendMessage(Utils.generateUUID(), payload, OCPP16RequestCommand.METER_VALUES);
   }
 
-  public async sendTransactionEndMeterValues(connectorId: number, transactionId: number, endMeterValue: OCPP16MeterValue): Promise<void> {
+  public async sendTransactionEndMeterValues(
+    connectorId: number,
+    transactionId: number,
+    endMeterValue: OCPP16MeterValue
+  ): Promise<void> {
     const payload: MeterValuesRequest = {
       connectorId,
       transactionId,
@@ -344,10 +772,16 @@ export default class OCPP16RequestService extends OCPPRequestService {
     await this.sendMessage(Utils.generateUUID(), payload, OCPP16RequestCommand.METER_VALUES);
   }
 
-  public async sendDiagnosticsStatusNotification(diagnosticsStatus: OCPP16DiagnosticsStatus): Promise<void> {
+  public async sendDiagnosticsStatusNotification(
+    diagnosticsStatus: OCPP16DiagnosticsStatus
+  ): Promise<void> {
     const payload: DiagnosticsStatusNotificationRequest = {
-      status: diagnosticsStatus
+      status: diagnosticsStatus,
     };
-    await this.sendMessage(Utils.generateUUID(), payload, OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION);
+    await this.sendMessage(
+      Utils.generateUUID(),
+      payload,
+      OCPP16RequestCommand.DIAGNOSTICS_STATUS_NOTIFICATION
+    );
   }
 }
index 7f1217fa45d1791b1337cc673440188dbc190b47..79064f1c48d9deec97e583da6679fd4b2a600d86 100644 (file)
@@ -1,8 +1,25 @@
 // Partial Copyright Jerome Benoit. 2021. All Rights Reserved.
 
-import { AuthorizeRequest, OCPP16AuthorizationStatus, OCPP16AuthorizeResponse, OCPP16StartTransactionResponse, OCPP16StopTransactionResponse, StartTransactionRequest, StopTransactionRequest } from '../../../types/ocpp/1.6/Transaction';
-import { HeartbeatRequest, OCPP16RequestCommand, StatusNotificationRequest } from '../../../types/ocpp/1.6/Requests';
-import { HeartbeatResponse, OCPP16BootNotificationResponse, OCPP16RegistrationStatus, StatusNotificationResponse } from '../../../types/ocpp/1.6/Responses';
+import {
+  AuthorizeRequest,
+  OCPP16AuthorizationStatus,
+  OCPP16AuthorizeResponse,
+  OCPP16StartTransactionResponse,
+  OCPP16StopTransactionResponse,
+  StartTransactionRequest,
+  StopTransactionRequest,
+} from '../../../types/ocpp/1.6/Transaction';
+import {
+  HeartbeatRequest,
+  OCPP16RequestCommand,
+  StatusNotificationRequest,
+} from '../../../types/ocpp/1.6/Requests';
+import {
+  HeartbeatResponse,
+  OCPP16BootNotificationResponse,
+  OCPP16RegistrationStatus,
+  StatusNotificationResponse,
+} from '../../../types/ocpp/1.6/Responses';
 import { MeterValuesRequest, MeterValuesResponse } from '../../../types/ocpp/1.6/MeterValues';
 
 import type ChargingStation from '../../ChargingStation';
@@ -34,65 +51,134 @@ export default class OCPP16ResponseService extends OCPPResponseService {
       [OCPP16RequestCommand.START_TRANSACTION, this.handleResponseStartTransaction.bind(this)],
       [OCPP16RequestCommand.STOP_TRANSACTION, this.handleResponseStopTransaction.bind(this)],
       [OCPP16RequestCommand.STATUS_NOTIFICATION, this.handleResponseStatusNotification.bind(this)],
-      [OCPP16RequestCommand.METER_VALUES, this.handleResponseMeterValues.bind(this)]
+      [OCPP16RequestCommand.METER_VALUES, this.handleResponseMeterValues.bind(this)],
     ]);
   }
 
-  public async handleResponse(commandName: OCPP16RequestCommand, payload: JsonType | string, requestPayload: JsonType): Promise<void> {
-    if (this.chargingStation.isRegistered() || commandName === OCPP16RequestCommand.BOOT_NOTIFICATION) {
+  public async handleResponse(
+    commandName: OCPP16RequestCommand,
+    payload: JsonType | string,
+    requestPayload: JsonType
+  ): Promise<void> {
+    if (
+      this.chargingStation.isRegistered() ||
+      commandName === OCPP16RequestCommand.BOOT_NOTIFICATION
+    ) {
       if (this.responseHandlers.has(commandName)) {
         try {
           await this.responseHandlers.get(commandName)(payload, requestPayload);
         } catch (error) {
-          logger.error(this.chargingStation.logPrefix() + ' Handle request response error: %j', error);
+          logger.error(
+            this.chargingStation.logPrefix() + ' Handle request response error: %j',
+            error
+          );
           throw error;
         }
       } else {
         // Throw exception
-        throw new OCPPError(ErrorType.NOT_IMPLEMENTED, `${commandName} is not implemented to handle request response payload ${JSON.stringify(payload, null, 2)}`, commandName);
+        throw new OCPPError(
+          ErrorType.NOT_IMPLEMENTED,
+          `${commandName} is not implemented to handle request response payload ${JSON.stringify(
+            payload,
+            null,
+            2
+          )}`,
+          commandName
+        );
       }
     } else {
-      throw new OCPPError(ErrorType.SECURITY_ERROR, `${commandName} cannot be issued to handle request response payload ${JSON.stringify(payload, null, 2)} while the charging station is not registered on the central server. `, commandName);
+      throw new OCPPError(
+        ErrorType.SECURITY_ERROR,
+        `${commandName} cannot be issued to handle request response payload ${JSON.stringify(
+          payload,
+          null,
+          2
+        )} while the charging station is not registered on the central server. `,
+        commandName
+      );
     }
   }
 
   private handleResponseBootNotification(payload: OCPP16BootNotificationResponse): void {
     if (payload.status === OCPP16RegistrationStatus.ACCEPTED) {
-      this.chargingStation.addConfigurationKey(OCPP16StandardParametersKey.HeartBeatInterval, payload.interval.toString());
-      this.chargingStation.addConfigurationKey(OCPP16StandardParametersKey.HeartbeatInterval, payload.interval.toString(), { visible: false });
-      this.chargingStation.heartbeatSetInterval ? this.chargingStation.restartHeartbeat() : this.chargingStation.startHeartbeat();
+      this.chargingStation.addConfigurationKey(
+        OCPP16StandardParametersKey.HeartBeatInterval,
+        payload.interval.toString()
+      );
+      this.chargingStation.addConfigurationKey(
+        OCPP16StandardParametersKey.HeartbeatInterval,
+        payload.interval.toString(),
+        { visible: false }
+      );
+      this.chargingStation.heartbeatSetInterval
+        ? this.chargingStation.restartHeartbeat()
+        : this.chargingStation.startHeartbeat();
     }
     if (Object.values(OCPP16RegistrationStatus).includes(payload.status)) {
-      const logMsg = `${this.chargingStation.logPrefix()} Charging station in '${payload.status}' state on the central server`;
-      payload.status === OCPP16RegistrationStatus.REJECTED ? logger.warn(logMsg) : logger.info(logMsg);
+      const logMsg = `${this.chargingStation.logPrefix()} Charging station in '${
+        payload.status
+      }' state on the central server`;
+      payload.status === OCPP16RegistrationStatus.REJECTED
+        ? logger.warn(logMsg)
+        : logger.info(logMsg);
     } else {
-      logger.error(this.chargingStation.logPrefix() + ' Charging station boot notification response received: %j with undefined registration status', payload);
+      logger.error(
+        this.chargingStation.logPrefix() +
+          ' Charging station boot notification response received: %j with undefined registration status',
+        payload
+      );
     }
   }
 
-  private handleResponseHeartbeat(payload: HeartbeatResponse, requestPayload: HeartbeatRequest): void {
-    logger.debug(this.chargingStation.logPrefix() + ' Heartbeat response received: %j to Heartbeat request: %j', payload, requestPayload);
+  private handleResponseHeartbeat(
+    payload: HeartbeatResponse,
+    requestPayload: HeartbeatRequest
+  ): void {
+    logger.debug(
+      this.chargingStation.logPrefix() +
+        ' Heartbeat response received: %j to Heartbeat request: %j',
+      payload,
+      requestPayload
+    );
   }
 
-  private handleResponseAuthorize(payload: OCPP16AuthorizeResponse, requestPayload: AuthorizeRequest): void {
+  private handleResponseAuthorize(
+    payload: OCPP16AuthorizeResponse,
+    requestPayload: AuthorizeRequest
+  ): void {
     let authorizeConnectorId: number;
     for (const connectorId of this.chargingStation.connectors.keys()) {
-      if (connectorId > 0 && this.chargingStation.getConnectorStatus(connectorId)?.authorizeIdTag === requestPayload.idTag) {
+      if (
+        connectorId > 0 &&
+        this.chargingStation.getConnectorStatus(connectorId)?.authorizeIdTag ===
+          requestPayload.idTag
+      ) {
         authorizeConnectorId = connectorId;
         break;
       }
     }
     if (payload.idTagInfo.status === OCPP16AuthorizationStatus.ACCEPTED) {
       this.chargingStation.getConnectorStatus(authorizeConnectorId).idTagAuthorized = true;
-      logger.debug(`${this.chargingStation.logPrefix()} IdTag ${requestPayload.idTag} authorized on connector ${authorizeConnectorId}`);
+      logger.debug(
+        `${this.chargingStation.logPrefix()} IdTag ${
+          requestPayload.idTag
+        } authorized on connector ${authorizeConnectorId}`
+      );
     } else {
       this.chargingStation.getConnectorStatus(authorizeConnectorId).idTagAuthorized = false;
       delete this.chargingStation.getConnectorStatus(authorizeConnectorId).authorizeIdTag;
-      logger.debug(`${this.chargingStation.logPrefix()} IdTag ${requestPayload.idTag} refused with status ${payload.idTagInfo.status} on connector ${authorizeConnectorId}`);
+      logger.debug(
+        `${this.chargingStation.logPrefix()} IdTag ${requestPayload.idTag} refused with status ${
+          payload.idTagInfo.status
+        } on connector ${authorizeConnectorId}`
+      );
     }
   }
 
-  private async handleResponseStartTransaction(payload: OCPP16StartTransactionResponse, requestPayload: StartTransactionRequest): Promise<void> {
+  private async handleResponseStartTransaction(
+    payload: OCPP16StartTransactionResponse,
+    requestPayload: StartTransactionRequest
+  ): Promise<void> {
     const connectorId = requestPayload.connectorId;
 
     let transactionConnectorId: number;
@@ -103,44 +189,109 @@ export default class OCPP16ResponseService extends OCPPResponseService {
       }
     }
     if (!transactionConnectorId) {
-      logger.error(this.chargingStation.logPrefix() + ' Trying to start a transaction on a non existing connector Id ' + connectorId.toString());
+      logger.error(
+        this.chargingStation.logPrefix() +
+          ' Trying to start a transaction on a non existing connector Id ' +
+          connectorId.toString()
+      );
       return;
     }
-    if (this.chargingStation.getConnectorStatus(connectorId).transactionRemoteStarted && this.chargingStation.getAuthorizeRemoteTxRequests()
-      && this.chargingStation.getLocalAuthListEnabled() && this.chargingStation.hasAuthorizedTags() && !this.chargingStation.getConnectorStatus(connectorId).idTagLocalAuthorized) {
-      logger.error(this.chargingStation.logPrefix() + ' Trying to start a transaction with a not local authorized idTag ' + this.chargingStation.getConnectorStatus(connectorId).localAuthorizeIdTag + ' on connector Id ' + connectorId.toString());
+    if (
+      this.chargingStation.getConnectorStatus(connectorId).transactionRemoteStarted &&
+      this.chargingStation.getAuthorizeRemoteTxRequests() &&
+      this.chargingStation.getLocalAuthListEnabled() &&
+      this.chargingStation.hasAuthorizedTags() &&
+      !this.chargingStation.getConnectorStatus(connectorId).idTagLocalAuthorized
+    ) {
+      logger.error(
+        this.chargingStation.logPrefix() +
+          ' Trying to start a transaction with a not local authorized idTag ' +
+          this.chargingStation.getConnectorStatus(connectorId).localAuthorizeIdTag +
+          ' on connector Id ' +
+          connectorId.toString()
+      );
       await this.resetConnectorOnStartTransactionError(connectorId);
       return;
     }
-    if (this.chargingStation.getConnectorStatus(connectorId).transactionRemoteStarted && this.chargingStation.getAuthorizeRemoteTxRequests()
-      && this.chargingStation.getMayAuthorizeAtRemoteStart() && !this.chargingStation.getConnectorStatus(connectorId).idTagLocalAuthorized
-      && !this.chargingStation.getConnectorStatus(connectorId).idTagAuthorized) {
-      logger.error(this.chargingStation.logPrefix() + ' Trying to start a transaction with a not authorized idTag ' + this.chargingStation.getConnectorStatus(connectorId).authorizeIdTag + ' on connector Id ' + connectorId.toString());
+    if (
+      this.chargingStation.getConnectorStatus(connectorId).transactionRemoteStarted &&
+      this.chargingStation.getAuthorizeRemoteTxRequests() &&
+      this.chargingStation.getMayAuthorizeAtRemoteStart() &&
+      !this.chargingStation.getConnectorStatus(connectorId).idTagLocalAuthorized &&
+      !this.chargingStation.getConnectorStatus(connectorId).idTagAuthorized
+    ) {
+      logger.error(
+        this.chargingStation.logPrefix() +
+          ' Trying to start a transaction with a not authorized idTag ' +
+          this.chargingStation.getConnectorStatus(connectorId).authorizeIdTag +
+          ' on connector Id ' +
+          connectorId.toString()
+      );
       await this.resetConnectorOnStartTransactionError(connectorId);
       return;
     }
-    if (this.chargingStation.getConnectorStatus(connectorId).idTagAuthorized && this.chargingStation.getConnectorStatus(connectorId).authorizeIdTag !== requestPayload.idTag) {
-      logger.error(this.chargingStation.logPrefix() + ' Trying to start a transaction with an idTag ' + requestPayload.idTag + ' different from the authorize request one ' + this.chargingStation.getConnectorStatus(connectorId).authorizeIdTag + ' on connector Id ' + connectorId.toString());
+    if (
+      this.chargingStation.getConnectorStatus(connectorId).idTagAuthorized &&
+      this.chargingStation.getConnectorStatus(connectorId).authorizeIdTag !== requestPayload.idTag
+    ) {
+      logger.error(
+        this.chargingStation.logPrefix() +
+          ' Trying to start a transaction with an idTag ' +
+          requestPayload.idTag +
+          ' different from the authorize request one ' +
+          this.chargingStation.getConnectorStatus(connectorId).authorizeIdTag +
+          ' on connector Id ' +
+          connectorId.toString()
+      );
       await this.resetConnectorOnStartTransactionError(connectorId);
       return;
     }
-    if (this.chargingStation.getConnectorStatus(connectorId).idTagLocalAuthorized
-      && this.chargingStation.getConnectorStatus(connectorId).localAuthorizeIdTag !== requestPayload.idTag) {
-      logger.error(this.chargingStation.logPrefix() + ' Trying to start a transaction with an idTag ' + requestPayload.idTag + ' different from the local authorized one ' + this.chargingStation.getConnectorStatus(connectorId).localAuthorizeIdTag + ' on connector Id ' + connectorId.toString());
+    if (
+      this.chargingStation.getConnectorStatus(connectorId).idTagLocalAuthorized &&
+      this.chargingStation.getConnectorStatus(connectorId).localAuthorizeIdTag !==
+        requestPayload.idTag
+    ) {
+      logger.error(
+        this.chargingStation.logPrefix() +
+          ' Trying to start a transaction with an idTag ' +
+          requestPayload.idTag +
+          ' different from the local authorized one ' +
+          this.chargingStation.getConnectorStatus(connectorId).localAuthorizeIdTag +
+          ' on connector Id ' +
+          connectorId.toString()
+      );
       await this.resetConnectorOnStartTransactionError(connectorId);
       return;
     }
     if (this.chargingStation.getConnectorStatus(connectorId)?.transactionStarted) {
-      logger.debug(this.chargingStation.logPrefix() + ' Trying to start a transaction on an already used connector ' + connectorId.toString() + ': %j', this.chargingStation.getConnectorStatus(connectorId));
+      logger.debug(
+        this.chargingStation.logPrefix() +
+          ' Trying to start a transaction on an already used connector ' +
+          connectorId.toString() +
+          ': %j',
+        this.chargingStation.getConnectorStatus(connectorId)
+      );
       return;
     }
-    if (this.chargingStation.getConnectorStatus(connectorId)?.status !== OCPP16ChargePointStatus.AVAILABLE
-      && this.chargingStation.getConnectorStatus(connectorId)?.status !== OCPP16ChargePointStatus.PREPARING) {
-      logger.error(`${this.chargingStation.logPrefix()} Trying to start a transaction on connector ${connectorId.toString()} with status ${this.chargingStation.getConnectorStatus(connectorId)?.status}`);
+    if (
+      this.chargingStation.getConnectorStatus(connectorId)?.status !==
+        OCPP16ChargePointStatus.AVAILABLE &&
+      this.chargingStation.getConnectorStatus(connectorId)?.status !==
+        OCPP16ChargePointStatus.PREPARING
+    ) {
+      logger.error(
+        `${this.chargingStation.logPrefix()} Trying to start a transaction on connector ${connectorId.toString()} with status ${
+          this.chargingStation.getConnectorStatus(connectorId)?.status
+        }`
+      );
       return;
     }
     if (!Number.isInteger(payload.transactionId)) {
-      logger.warn(`${this.chargingStation.logPrefix()} Trying to start a transaction on connector ${connectorId.toString()} with a non integer transaction Id ${payload.transactionId}, converting to integer`);
+      logger.warn(
+        `${this.chargingStation.logPrefix()} Trying to start a transaction on connector ${connectorId.toString()} with a non integer transaction Id ${
+          payload.transactionId
+        }, converting to integer`
+      );
       payload.transactionId = Utils.convertToInt(payload.transactionId);
     }
 
@@ -148,71 +299,178 @@ export default class OCPP16ResponseService extends OCPPResponseService {
       this.chargingStation.getConnectorStatus(connectorId).transactionStarted = true;
       this.chargingStation.getConnectorStatus(connectorId).transactionId = payload.transactionId;
       this.chargingStation.getConnectorStatus(connectorId).transactionIdTag = requestPayload.idTag;
-      this.chargingStation.getConnectorStatus(connectorId).transactionEnergyActiveImportRegisterValue = 0;
-      this.chargingStation.getConnectorStatus(connectorId).transactionBeginMeterValue = OCPP16ServiceUtils.buildTransactionBeginMeterValue(this.chargingStation, connectorId,
-        requestPayload.meterStart);
-      this.chargingStation.getBeginEndMeterValues() && await this.chargingStation.ocppRequestService.sendTransactionBeginMeterValues(connectorId, payload.transactionId,
-        this.chargingStation.getConnectorStatus(connectorId).transactionBeginMeterValue);
-      await this.chargingStation.ocppRequestService.sendStatusNotification(connectorId, OCPP16ChargePointStatus.CHARGING);
-      this.chargingStation.getConnectorStatus(connectorId).status = OCPP16ChargePointStatus.CHARGING;
-      logger.info(this.chargingStation.logPrefix() + ' Transaction ' + payload.transactionId.toString() + ' STARTED on ' + this.chargingStation.stationInfo.chargingStationId + '#' + connectorId.toString() + ' for idTag ' + requestPayload.idTag);
+      this.chargingStation.getConnectorStatus(
+        connectorId
+      ).transactionEnergyActiveImportRegisterValue = 0;
+      this.chargingStation.getConnectorStatus(connectorId).transactionBeginMeterValue =
+        OCPP16ServiceUtils.buildTransactionBeginMeterValue(
+          this.chargingStation,
+          connectorId,
+          requestPayload.meterStart
+        );
+      this.chargingStation.getBeginEndMeterValues() &&
+        (await this.chargingStation.ocppRequestService.sendTransactionBeginMeterValues(
+          connectorId,
+          payload.transactionId,
+          this.chargingStation.getConnectorStatus(connectorId).transactionBeginMeterValue
+        ));
+      await this.chargingStation.ocppRequestService.sendStatusNotification(
+        connectorId,
+        OCPP16ChargePointStatus.CHARGING
+      );
+      this.chargingStation.getConnectorStatus(connectorId).status =
+        OCPP16ChargePointStatus.CHARGING;
+      logger.info(
+        this.chargingStation.logPrefix() +
+          ' Transaction ' +
+          payload.transactionId.toString() +
+          ' STARTED on ' +
+          this.chargingStation.stationInfo.chargingStationId +
+          '#' +
+          connectorId.toString() +
+          ' for idTag ' +
+          requestPayload.idTag
+      );
       if (this.chargingStation.stationInfo.powerSharedByConnectors) {
         this.chargingStation.stationInfo.powerDivider++;
       }
-      const configuredMeterValueSampleInterval = this.chargingStation.getConfigurationKey(OCPP16StandardParametersKey.MeterValueSampleInterval);
-      this.chargingStation.startMeterValues(connectorId, configuredMeterValueSampleInterval ? Utils.convertToInt(configuredMeterValueSampleInterval.value) * 1000 : 60000);
+      const configuredMeterValueSampleInterval = this.chargingStation.getConfigurationKey(
+        OCPP16StandardParametersKey.MeterValueSampleInterval
+      );
+      this.chargingStation.startMeterValues(
+        connectorId,
+        configuredMeterValueSampleInterval
+          ? Utils.convertToInt(configuredMeterValueSampleInterval.value) * 1000
+          : 60000
+      );
     } else {
-      logger.warn(this.chargingStation.logPrefix() + ' Starting transaction id ' + payload.transactionId.toString() + ' REJECTED with status ' + payload?.idTagInfo?.status + ', idTag ' + requestPayload.idTag);
+      logger.warn(
+        this.chargingStation.logPrefix() +
+          ' Starting transaction id ' +
+          payload.transactionId.toString() +
+          ' REJECTED with status ' +
+          payload?.idTagInfo?.status +
+          ', idTag ' +
+          requestPayload.idTag
+      );
       await this.resetConnectorOnStartTransactionError(connectorId);
     }
   }
 
   private async resetConnectorOnStartTransactionError(connectorId: number): Promise<void> {
     this.chargingStation.resetConnectorStatus(connectorId);
-    if (this.chargingStation.getConnectorStatus(connectorId).status !== OCPP16ChargePointStatus.AVAILABLE) {
-      await this.chargingStation.ocppRequestService.sendStatusNotification(connectorId, OCPP16ChargePointStatus.AVAILABLE);
-      this.chargingStation.getConnectorStatus(connectorId).status = OCPP16ChargePointStatus.AVAILABLE;
+    if (
+      this.chargingStation.getConnectorStatus(connectorId).status !==
+      OCPP16ChargePointStatus.AVAILABLE
+    ) {
+      await this.chargingStation.ocppRequestService.sendStatusNotification(
+        connectorId,
+        OCPP16ChargePointStatus.AVAILABLE
+      );
+      this.chargingStation.getConnectorStatus(connectorId).status =
+        OCPP16ChargePointStatus.AVAILABLE;
     }
   }
 
-  private async handleResponseStopTransaction(payload: OCPP16StopTransactionResponse, requestPayload: StopTransactionRequest): Promise<void> {
+  private async handleResponseStopTransaction(
+    payload: OCPP16StopTransactionResponse,
+    requestPayload: StopTransactionRequest
+  ): Promise<void> {
     let transactionConnectorId: number;
     for (const connectorId of this.chargingStation.connectors.keys()) {
-      if (connectorId > 0 && this.chargingStation.getConnectorStatus(connectorId)?.transactionId === requestPayload.transactionId) {
+      if (
+        connectorId > 0 &&
+        this.chargingStation.getConnectorStatus(connectorId)?.transactionId ===
+          requestPayload.transactionId
+      ) {
         transactionConnectorId = connectorId;
         break;
       }
     }
     if (!transactionConnectorId) {
-      logger.error(this.chargingStation.logPrefix() + ' Trying to stop a non existing transaction ' + requestPayload.transactionId.toString());
+      logger.error(
+        this.chargingStation.logPrefix() +
+          ' Trying to stop a non existing transaction ' +
+          requestPayload.transactionId.toString()
+      );
       return;
     }
     if (payload.idTagInfo?.status === OCPP16AuthorizationStatus.ACCEPTED) {
-      (this.chargingStation.getBeginEndMeterValues() && !this.chargingStation.getOcppStrictCompliance() && this.chargingStation.getOutOfOrderEndMeterValues())
-        && await this.chargingStation.ocppRequestService.sendTransactionEndMeterValues(transactionConnectorId, requestPayload.transactionId,
-          OCPP16ServiceUtils.buildTransactionEndMeterValue(this.chargingStation, transactionConnectorId, requestPayload.meterStop));
-      if (!this.chargingStation.isChargingStationAvailable() || !this.chargingStation.isConnectorAvailable(transactionConnectorId)) {
-        await this.chargingStation.ocppRequestService.sendStatusNotification(transactionConnectorId, OCPP16ChargePointStatus.UNAVAILABLE);
-        this.chargingStation.getConnectorStatus(transactionConnectorId).status = OCPP16ChargePointStatus.UNAVAILABLE;
+      this.chargingStation.getBeginEndMeterValues() &&
+        !this.chargingStation.getOcppStrictCompliance() &&
+        this.chargingStation.getOutOfOrderEndMeterValues() &&
+        (await this.chargingStation.ocppRequestService.sendTransactionEndMeterValues(
+          transactionConnectorId,
+          requestPayload.transactionId,
+          OCPP16ServiceUtils.buildTransactionEndMeterValue(
+            this.chargingStation,
+            transactionConnectorId,
+            requestPayload.meterStop
+          )
+        ));
+      if (
+        !this.chargingStation.isChargingStationAvailable() ||
+        !this.chargingStation.isConnectorAvailable(transactionConnectorId)
+      ) {
+        await this.chargingStation.ocppRequestService.sendStatusNotification(
+          transactionConnectorId,
+          OCPP16ChargePointStatus.UNAVAILABLE
+        );
+        this.chargingStation.getConnectorStatus(transactionConnectorId).status =
+          OCPP16ChargePointStatus.UNAVAILABLE;
       } else {
-        await this.chargingStation.ocppRequestService.sendStatusNotification(transactionConnectorId, OCPP16ChargePointStatus.AVAILABLE);
-        this.chargingStation.getConnectorStatus(transactionConnectorId).status = OCPP16ChargePointStatus.AVAILABLE;
+        await this.chargingStation.ocppRequestService.sendStatusNotification(
+          transactionConnectorId,
+          OCPP16ChargePointStatus.AVAILABLE
+        );
+        this.chargingStation.getConnectorStatus(transactionConnectorId).status =
+          OCPP16ChargePointStatus.AVAILABLE;
       }
       if (this.chargingStation.stationInfo.powerSharedByConnectors) {
         this.chargingStation.stationInfo.powerDivider--;
       }
-      logger.info(this.chargingStation.logPrefix() + ' Transaction ' + requestPayload.transactionId.toString() + ' STOPPED on ' + this.chargingStation.stationInfo.chargingStationId + '#' + transactionConnectorId.toString());
+      logger.info(
+        this.chargingStation.logPrefix() +
+          ' Transaction ' +
+          requestPayload.transactionId.toString() +
+          ' STOPPED on ' +
+          this.chargingStation.stationInfo.chargingStationId +
+          '#' +
+          transactionConnectorId.toString()
+      );
       this.chargingStation.resetConnectorStatus(transactionConnectorId);
     } else {
-      logger.warn(this.chargingStation.logPrefix() + ' Stopping transaction id ' + requestPayload.transactionId.toString() + ' REJECTED with status ' + payload.idTagInfo?.status);
+      logger.warn(
+        this.chargingStation.logPrefix() +
+          ' Stopping transaction id ' +
+          requestPayload.transactionId.toString() +
+          ' REJECTED with status ' +
+          payload.idTagInfo?.status
+      );
     }
   }
 
-  private handleResponseStatusNotification(payload: StatusNotificationRequest, requestPayload: StatusNotificationResponse): void {
-    logger.debug(this.chargingStation.logPrefix() + ' Status notification response received: %j to StatusNotification request: %j', payload, requestPayload);
+  private handleResponseStatusNotification(
+    payload: StatusNotificationRequest,
+    requestPayload: StatusNotificationResponse
+  ): void {
+    logger.debug(
+      this.chargingStation.logPrefix() +
+        ' Status notification response received: %j to StatusNotification request: %j',
+      payload,
+      requestPayload
+    );
   }
 
-  private handleResponseMeterValues(payload: MeterValuesRequest, requestPayload: MeterValuesResponse): void {
-    logger.debug(this.chargingStation.logPrefix() + ' MeterValues response received: %j to MeterValues request: %j', payload, requestPayload);
+  private handleResponseMeterValues(
+    payload: MeterValuesRequest,
+    requestPayload: MeterValuesResponse
+  ): void {
+    logger.debug(
+      this.chargingStation.logPrefix() +
+        ' MeterValues response received: %j to MeterValues request: %j',
+      payload,
+      requestPayload
+    );
   }
 }
index cacbe38914654e903e7e38f494499ae9e0da8fd0..d112270a6aa6e99124931ed66682b08c458ddde8 100644 (file)
@@ -1,6 +1,14 @@
 // Partial Copyright Jerome Benoit. 2021. All Rights Reserved.
 
-import { MeterValueContext, MeterValueLocation, MeterValueUnit, OCPP16MeterValue, OCPP16MeterValueMeasurand, OCPP16MeterValuePhase, OCPP16SampledValue } from '../../../types/ocpp/1.6/MeterValues';
+import {
+  MeterValueContext,
+  MeterValueLocation,
+  MeterValueUnit,
+  OCPP16MeterValue,
+  OCPP16MeterValueMeasurand,
+  OCPP16MeterValuePhase,
+  OCPP16SampledValue,
+} from '../../../types/ocpp/1.6/MeterValues';
 
 import type ChargingStation from '../../ChargingStation';
 import { ErrorType } from '../../../types/ocpp/ErrorType';
@@ -11,34 +19,54 @@ import Utils from '../../../utils/Utils';
 import logger from '../../../utils/Logger';
 
 export class OCPP16ServiceUtils {
-  public static checkMeasurandPowerDivider(chargingStation: ChargingStation, measurandType: OCPP16MeterValueMeasurand): void {
+  public static checkMeasurandPowerDivider(
+    chargingStation: ChargingStation,
+    measurandType: OCPP16MeterValueMeasurand
+  ): void {
     if (Utils.isUndefined(chargingStation.stationInfo.powerDivider)) {
-      const errMsg = `${chargingStation.logPrefix()} MeterValues measurand ${measurandType ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: powerDivider is undefined`;
+      const errMsg = `${chargingStation.logPrefix()} MeterValues measurand ${
+        measurandType ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
+      }: powerDivider is undefined`;
       logger.error(errMsg);
       throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, RequestCommand.METER_VALUES);
     } else if (chargingStation.stationInfo?.powerDivider <= 0) {
-      const errMsg = `${chargingStation.logPrefix()} MeterValues measurand ${measurandType ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: powerDivider have zero or below value ${chargingStation.stationInfo.powerDivider}`;
+      const errMsg = `${chargingStation.logPrefix()} MeterValues measurand ${
+        measurandType ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
+      }: powerDivider have zero or below value ${chargingStation.stationInfo.powerDivider}`;
       logger.error(errMsg);
       throw new OCPPError(ErrorType.INTERNAL_ERROR, errMsg, RequestCommand.METER_VALUES);
     }
   }
 
-  public static buildSampledValue(sampledValueTemplate: SampledValueTemplate, value: number, context?: MeterValueContext, phase?: OCPP16MeterValuePhase): OCPP16SampledValue {
-    const sampledValueValue = value ?? (sampledValueTemplate?.value ?? null);
-    const sampledValueContext = context ?? (sampledValueTemplate?.context ?? null);
-    const sampledValueLocation = sampledValueTemplate?.location ?? OCPP16ServiceUtils.getMeasurandDefaultLocation(sampledValueTemplate?.measurand ?? null);
-    const sampledValuePhase = phase ?? (sampledValueTemplate?.phase ?? null);
+  public static buildSampledValue(
+    sampledValueTemplate: SampledValueTemplate,
+    value: number,
+    context?: MeterValueContext,
+    phase?: OCPP16MeterValuePhase
+  ): OCPP16SampledValue {
+    const sampledValueValue = value ?? sampledValueTemplate?.value ?? null;
+    const sampledValueContext = context ?? sampledValueTemplate?.context ?? null;
+    const sampledValueLocation =
+      sampledValueTemplate?.location ??
+      OCPP16ServiceUtils.getMeasurandDefaultLocation(sampledValueTemplate?.measurand ?? null);
+    const sampledValuePhase = phase ?? sampledValueTemplate?.phase ?? null;
     return {
-      ...!Utils.isNullOrUndefined(sampledValueTemplate.unit) && { unit: sampledValueTemplate.unit },
-      ...!Utils.isNullOrUndefined(sampledValueContext) && { context: sampledValueContext },
-      ...!Utils.isNullOrUndefined(sampledValueTemplate.measurand) && { measurand: sampledValueTemplate.measurand },
-      ...!Utils.isNullOrUndefined(sampledValueLocation) && { location: sampledValueLocation },
-      ...!Utils.isNullOrUndefined(sampledValueValue) && { value: sampledValueValue.toString() },
-      ...!Utils.isNullOrUndefined(sampledValuePhase) && { phase: sampledValuePhase },
+      ...(!Utils.isNullOrUndefined(sampledValueTemplate.unit) && {
+        unit: sampledValueTemplate.unit,
+      }),
+      ...(!Utils.isNullOrUndefined(sampledValueContext) && { context: sampledValueContext }),
+      ...(!Utils.isNullOrUndefined(sampledValueTemplate.measurand) && {
+        measurand: sampledValueTemplate.measurand,
+      }),
+      ...(!Utils.isNullOrUndefined(sampledValueLocation) && { location: sampledValueLocation }),
+      ...(!Utils.isNullOrUndefined(sampledValueValue) && { value: sampledValueValue.toString() }),
+      ...(!Utils.isNullOrUndefined(sampledValuePhase) && { phase: sampledValuePhase }),
     };
   }
 
-  public static getMeasurandDefaultUnit(measurandType: OCPP16MeterValueMeasurand): MeterValueUnit | undefined {
+  public static getMeasurandDefaultUnit(
+    measurandType: OCPP16MeterValueMeasurand
+  ): MeterValueUnit | undefined {
     switch (measurandType) {
       case OCPP16MeterValueMeasurand.CURRENT_EXPORT:
       case OCPP16MeterValueMeasurand.CURRENT_IMPORT:
@@ -58,14 +86,20 @@ export class OCPP16ServiceUtils {
     }
   }
 
-  public static getMeasurandDefaultLocation(measurandType: OCPP16MeterValueMeasurand): MeterValueLocation | undefined {
+  public static getMeasurandDefaultLocation(
+    measurandType: OCPP16MeterValueMeasurand
+  ): MeterValueLocation | undefined {
     switch (measurandType) {
       case OCPP16MeterValueMeasurand.STATE_OF_CHARGE:
         return MeterValueLocation.EV;
     }
   }
 
-  public static buildTransactionBeginMeterValue(chargingStation: ChargingStation, connectorId: number, meterBegin: number): OCPP16MeterValue {
+  public static buildTransactionBeginMeterValue(
+    chargingStation: ChargingStation,
+    connectorId: number,
+    meterBegin: number
+  ): OCPP16MeterValue {
     const meterValue: OCPP16MeterValue = {
       timestamp: new Date().toISOString(),
       sampledValue: [],
@@ -73,11 +107,21 @@ export class OCPP16ServiceUtils {
     // Energy.Active.Import.Register measurand (default)
     const sampledValueTemplate = chargingStation.getSampledValueTemplate(connectorId);
     const unitDivider = sampledValueTemplate?.unit === MeterValueUnit.KILO_WATT_HOUR ? 1000 : 1;
-    meterValue.sampledValue.push(OCPP16ServiceUtils.buildSampledValue(sampledValueTemplate, Utils.roundTo(meterBegin / unitDivider, 4), MeterValueContext.TRANSACTION_BEGIN));
+    meterValue.sampledValue.push(
+      OCPP16ServiceUtils.buildSampledValue(
+        sampledValueTemplate,
+        Utils.roundTo(meterBegin / unitDivider, 4),
+        MeterValueContext.TRANSACTION_BEGIN
+      )
+    );
     return meterValue;
   }
 
-  public static buildTransactionEndMeterValue(chargingStation: ChargingStation, connectorId: number, meterEnd: number): OCPP16MeterValue {
+  public static buildTransactionEndMeterValue(
+    chargingStation: ChargingStation,
+    connectorId: number,
+    meterEnd: number
+  ): OCPP16MeterValue {
     const meterValue: OCPP16MeterValue = {
       timestamp: new Date().toISOString(),
       sampledValue: [],
@@ -85,11 +129,20 @@ export class OCPP16ServiceUtils {
     // Energy.Active.Import.Register measurand (default)
     const sampledValueTemplate = chargingStation.getSampledValueTemplate(connectorId);
     const unitDivider = sampledValueTemplate?.unit === MeterValueUnit.KILO_WATT_HOUR ? 1000 : 1;
-    meterValue.sampledValue.push(OCPP16ServiceUtils.buildSampledValue(sampledValueTemplate, Utils.roundTo(meterEnd / unitDivider, 4), MeterValueContext.TRANSACTION_END));
+    meterValue.sampledValue.push(
+      OCPP16ServiceUtils.buildSampledValue(
+        sampledValueTemplate,
+        Utils.roundTo(meterEnd / unitDivider, 4),
+        MeterValueContext.TRANSACTION_END
+      )
+    );
     return meterValue;
   }
 
-  public static buildTransactionDataMeterValues(transactionBeginMeterValue: OCPP16MeterValue, transactionEndMeterValue: OCPP16MeterValue): OCPP16MeterValue[] {
+  public static buildTransactionDataMeterValues(
+    transactionBeginMeterValue: OCPP16MeterValue,
+    transactionEndMeterValue: OCPP16MeterValue
+  ): OCPP16MeterValue[] {
     const meterValues: OCPP16MeterValue[] = [];
     meterValues.push(transactionBeginMeterValue);
     meterValues.push(transactionEndMeterValue);
index 5fadfb95d5ee5227327fe8fc0304a1aee2998f9b..0d56ebe84e502cc717d44e2229ac3702f039e18d 100644 (file)
@@ -5,22 +5,36 @@ import { JsonType } from '../../types/JsonType';
 import logger from '../../utils/Logger';
 
 export default abstract class OCPPIncomingRequestService {
-  private static readonly instances: Map<string, OCPPIncomingRequestService> = new Map<string, OCPPIncomingRequestService>();
+  private static readonly instances: Map<string, OCPPIncomingRequestService> = new Map<
+    string,
+    OCPPIncomingRequestService
+  >();
   protected chargingStation: ChargingStation;
 
   protected constructor(chargingStation: ChargingStation) {
     this.chargingStation = chargingStation;
   }
 
-  public static getInstance<T extends OCPPIncomingRequestService>(this: new (chargingStation: ChargingStation) => T, chargingStation: ChargingStation): T {
+  public static getInstance<T extends OCPPIncomingRequestService>(
+    this: new (chargingStation: ChargingStation) => T,
+    chargingStation: ChargingStation
+  ): T {
     if (!OCPPIncomingRequestService.instances.has(chargingStation.id)) {
       OCPPIncomingRequestService.instances.set(chargingStation.id, new this(chargingStation));
     }
     return OCPPIncomingRequestService.instances.get(chargingStation.id) as T;
   }
 
-  protected handleIncomingRequestError<T>(commandName: IncomingRequestCommand, error: Error, params: HandleErrorParams<T> = { throwError: true }): T {
-    logger.error(this.chargingStation.logPrefix() + ' Incoming request command %s error: %j', commandName, error);
+  protected handleIncomingRequestError<T>(
+    commandName: IncomingRequestCommand,
+    error: Error,
+    params: HandleErrorParams<T> = { throwError: true }
+  ): T {
+    logger.error(
+      this.chargingStation.logPrefix() + ' Incoming request command %s error: %j',
+      commandName,
+      error
+    );
     if (!params?.throwError && params?.errorResponse) {
       return params?.errorResponse;
     }
@@ -32,5 +46,9 @@ export default abstract class OCPPIncomingRequestService {
     }
   }
 
-  public abstract handleRequest(messageId: string, commandName: IncomingRequestCommand, commandPayload: JsonType): Promise<void>;
+  public abstract handleRequest(
+    messageId: string,
+    commandName: IncomingRequestCommand,
+    commandPayload: JsonType
+  ): Promise<void>;
 }
index 2ecc32ead8608248fac7b697d1c130cb8f0e4bd8..04cd508aa8903d805d6bda28d882d12d0db62e8a 100644 (file)
@@ -1,5 +1,16 @@
-import { AuthorizeResponse, StartTransactionResponse, StopTransactionReason, StopTransactionResponse } from '../../types/ocpp/Transaction';
-import { DiagnosticsStatus, IncomingRequestCommand, RequestCommand, ResponseType, SendParams } from '../../types/ocpp/Requests';
+import {
+  AuthorizeResponse,
+  StartTransactionResponse,
+  StopTransactionReason,
+  StopTransactionResponse,
+} from '../../types/ocpp/Transaction';
+import {
+  DiagnosticsStatus,
+  IncomingRequestCommand,
+  RequestCommand,
+  ResponseType,
+  SendParams,
+} from '../../types/ocpp/Requests';
 
 import { BootNotificationResponse } from '../../types/ocpp/Responses';
 import { ChargePointErrorCode } from '../../types/ocpp/ChargePointErrorCode';
@@ -19,146 +30,264 @@ import Utils from '../../utils/Utils';
 import logger from '../../utils/Logger';
 
 export default abstract class OCPPRequestService {
-  private static readonly instances: Map<string, OCPPRequestService> = new Map<string, OCPPRequestService>();
+  private static readonly instances: Map<string, OCPPRequestService> = new Map<
+    string,
+    OCPPRequestService
+  >();
   protected readonly chargingStation: ChargingStation;
   private readonly ocppResponseService: OCPPResponseService;
 
-  protected constructor(chargingStation: ChargingStation, ocppResponseService: OCPPResponseService) {
+  protected constructor(
+    chargingStation: ChargingStation,
+    ocppResponseService: OCPPResponseService
+  ) {
     this.chargingStation = chargingStation;
     this.ocppResponseService = ocppResponseService;
   }
 
-  public static getInstance<T extends OCPPRequestService>(this: new (chargingStation: ChargingStation, ocppResponseService: OCPPResponseService) => T, chargingStation: ChargingStation, ocppResponseService: OCPPResponseService): T {
+  public static getInstance<T extends OCPPRequestService>(
+    this: new (chargingStation: ChargingStation, ocppResponseService: OCPPResponseService) => T,
+    chargingStation: ChargingStation,
+    ocppResponseService: OCPPResponseService
+  ): T {
     if (!OCPPRequestService.instances.has(chargingStation.id)) {
-      OCPPRequestService.instances.set(chargingStation.id, new this(chargingStation, ocppResponseService));
+      OCPPRequestService.instances.set(
+        chargingStation.id,
+        new this(chargingStation, ocppResponseService)
+      );
     }
     return OCPPRequestService.instances.get(chargingStation.id) as T;
   }
 
-  public async sendResult(messageId: string, messagePayload: JsonType, commandName: IncomingRequestCommand): Promise<ResponseType> {
+  public async sendResult(
+    messageId: string,
+    messagePayload: JsonType,
+    commandName: IncomingRequestCommand
+  ): Promise<ResponseType> {
     try {
       // Send result message
-      return await this.internalSendMessage(messageId, messagePayload, MessageType.CALL_RESULT_MESSAGE, commandName);
+      return await this.internalSendMessage(
+        messageId,
+        messagePayload,
+        MessageType.CALL_RESULT_MESSAGE,
+        commandName
+      );
     } catch (error) {
       this.handleRequestError(commandName, error as Error);
     }
   }
 
-  public async sendError(messageId: string, ocppError: OCPPError, commandName: IncomingRequestCommand): Promise<ResponseType> {
+  public async sendError(
+    messageId: string,
+    ocppError: OCPPError,
+    commandName: IncomingRequestCommand
+  ): Promise<ResponseType> {
     try {
       // Send error message
-      return await this.internalSendMessage(messageId, ocppError, MessageType.CALL_ERROR_MESSAGE, commandName);
+      return await this.internalSendMessage(
+        messageId,
+        ocppError,
+        MessageType.CALL_ERROR_MESSAGE,
+        commandName
+      );
     } catch (error) {
       this.handleRequestError(commandName, error as Error);
     }
   }
 
-  protected async sendMessage(messageId: string, messagePayload: JsonType, commandName: RequestCommand, params: SendParams = {
-    skipBufferingOnError: false,
-    triggerMessage: false
-  }): Promise<ResponseType> {
+  protected async sendMessage(
+    messageId: string,
+    messagePayload: JsonType,
+    commandName: RequestCommand,
+    params: SendParams = {
+      skipBufferingOnError: false,
+      triggerMessage: false,
+    }
+  ): Promise<ResponseType> {
     try {
-      return await this.internalSendMessage(messageId, messagePayload, MessageType.CALL_MESSAGE, commandName, params);
+      return await this.internalSendMessage(
+        messageId,
+        messagePayload,
+        MessageType.CALL_MESSAGE,
+        commandName,
+        params
+      );
     } catch (error) {
       this.handleRequestError(commandName, error as Error, { throwError: false });
     }
   }
 
-  private async internalSendMessage(messageId: string, messagePayload: JsonType | OCPPError, messageType: MessageType, commandName?: RequestCommand | IncomingRequestCommand,
-      params: SendParams = {
-        skipBufferingOnError: false,
-        triggerMessage: false
-      }): Promise<ResponseType> {
-    if ((this.chargingStation.isInUnknownState() && commandName === RequestCommand.BOOT_NOTIFICATION)
-      || (!this.chargingStation.getOcppStrictCompliance() && this.chargingStation.isInUnknownState())
-      || this.chargingStation.isInAcceptedState() || (this.chargingStation.isInPendingState() && params.triggerMessage)) {
+  private async internalSendMessage(
+    messageId: string,
+    messagePayload: JsonType | OCPPError,
+    messageType: MessageType,
+    commandName?: RequestCommand | IncomingRequestCommand,
+    params: SendParams = {
+      skipBufferingOnError: false,
+      triggerMessage: false,
+    }
+  ): Promise<ResponseType> {
+    if (
+      (this.chargingStation.isInUnknownState() &&
+        commandName === RequestCommand.BOOT_NOTIFICATION) ||
+      (!this.chargingStation.getOcppStrictCompliance() &&
+        this.chargingStation.isInUnknownState()) ||
+      this.chargingStation.isInAcceptedState() ||
+      (this.chargingStation.isInPendingState() && params.triggerMessage)
+    ) {
       // eslint-disable-next-line @typescript-eslint/no-this-alias
       const self = this;
       // Send a message through wsConnection
-      return Utils.promiseWithTimeout(new Promise((resolve, reject) => {
-        const messageToSend = this.buildMessageToSend(messageId, messagePayload, messageType, commandName, responseCallback, rejectCallback);
-        if (this.chargingStation.getEnableStatistics()) {
-          this.chargingStation.performanceStatistics.addRequestStatistic(commandName, messageType);
-        }
-        // Check if wsConnection opened
-        if (this.chargingStation.isWebSocketConnectionOpened()) {
-          // Yes: Send Message
-          const beginId = PerformanceStatistics.beginMeasure(commandName);
-          // FIXME: Handle sending error
-          this.chargingStation.wsConnection.send(messageToSend);
-          PerformanceStatistics.endMeasure(commandName, beginId);
-        } else if (!params.skipBufferingOnError) {
-          // Buffer it
-          this.chargingStation.bufferMessage(messageToSend);
-          const ocppError = new OCPPError(ErrorType.GENERIC_ERROR, `WebSocket closed for buffered message id '${messageId}' with content '${messageToSend}'`, commandName, messagePayload?.details as JsonType ?? {});
-          if (messageType === MessageType.CALL_MESSAGE) {
-            // Reject it but keep the request in the cache
-            return reject(ocppError);
+      return Utils.promiseWithTimeout(
+        new Promise((resolve, reject) => {
+          const messageToSend = this.buildMessageToSend(
+            messageId,
+            messagePayload,
+            messageType,
+            commandName,
+            responseCallback,
+            rejectCallback
+          );
+          if (this.chargingStation.getEnableStatistics()) {
+            this.chargingStation.performanceStatistics.addRequestStatistic(
+              commandName,
+              messageType
+            );
           }
-          return rejectCallback(ocppError, false);
-        } else {
-          // Reject it
-          return rejectCallback(new OCPPError(ErrorType.GENERIC_ERROR, `WebSocket closed for non buffered message id '${messageId}' with content '${messageToSend}'`, commandName, messagePayload?.details as JsonType ?? {}), false);
-        }
-        // Response?
-        if (messageType !== MessageType.CALL_MESSAGE) {
-          // Yes: send Ok
-          return resolve(messagePayload);
-        }
-
-        /**
-         * Function that will receive the request's response
-         *
-         * @param payload
-         * @param requestPayload
-         */
-        async function responseCallback(payload: JsonType | string, requestPayload: JsonType): Promise<void> {
-          if (self.chargingStation.getEnableStatistics()) {
-            self.chargingStation.performanceStatistics.addRequestStatistic(commandName, MessageType.CALL_RESULT_MESSAGE);
+          // Check if wsConnection opened
+          if (this.chargingStation.isWebSocketConnectionOpened()) {
+            // Yes: Send Message
+            const beginId = PerformanceStatistics.beginMeasure(commandName);
+            // FIXME: Handle sending error
+            this.chargingStation.wsConnection.send(messageToSend);
+            PerformanceStatistics.endMeasure(commandName, beginId);
+          } else if (!params.skipBufferingOnError) {
+            // Buffer it
+            this.chargingStation.bufferMessage(messageToSend);
+            const ocppError = new OCPPError(
+              ErrorType.GENERIC_ERROR,
+              `WebSocket closed for buffered message id '${messageId}' with content '${messageToSend}'`,
+              commandName,
+              (messagePayload?.details as JsonType) ?? {}
+            );
+            if (messageType === MessageType.CALL_MESSAGE) {
+              // Reject it but keep the request in the cache
+              return reject(ocppError);
+            }
+            return rejectCallback(ocppError, false);
+          } else {
+            // Reject it
+            return rejectCallback(
+              new OCPPError(
+                ErrorType.GENERIC_ERROR,
+                `WebSocket closed for non buffered message id '${messageId}' with content '${messageToSend}'`,
+                commandName,
+                (messagePayload?.details as JsonType) ?? {}
+              ),
+              false
+            );
           }
-          // Handle the request's response
-          try {
-            await self.ocppResponseService.handleResponse(commandName as RequestCommand, payload, requestPayload);
-            resolve(payload);
-          } catch (error) {
-            reject(error);
-            throw error;
-          } finally {
-            self.chargingStation.requests.delete(messageId);
+          // Response?
+          if (messageType !== MessageType.CALL_MESSAGE) {
+            // Yes: send Ok
+            return resolve(messagePayload);
+          }
+
+          /**
+           * Function that will receive the request's response
+           *
+           * @param payload
+           * @param requestPayload
+           */
+          async function responseCallback(
+            payload: JsonType | string,
+            requestPayload: JsonType
+          ): Promise<void> {
+            if (self.chargingStation.getEnableStatistics()) {
+              self.chargingStation.performanceStatistics.addRequestStatistic(
+                commandName,
+                MessageType.CALL_RESULT_MESSAGE
+              );
+            }
+            // Handle the request's response
+            try {
+              await self.ocppResponseService.handleResponse(
+                commandName as RequestCommand,
+                payload,
+                requestPayload
+              );
+              resolve(payload);
+            } catch (error) {
+              reject(error);
+              throw error;
+            } finally {
+              self.chargingStation.requests.delete(messageId);
+            }
           }
-        }
 
-        /**
-         * Function that will receive the request's error response
-         *
-         * @param error
-         * @param requestStatistic
-         */
-        function rejectCallback(error: OCPPError, requestStatistic = true): void {
-          if (requestStatistic && self.chargingStation.getEnableStatistics()) {
-            self.chargingStation.performanceStatistics.addRequestStatistic(commandName, MessageType.CALL_ERROR_MESSAGE);
+          /**
+           * Function that will receive the request's error response
+           *
+           * @param error
+           * @param requestStatistic
+           */
+          function rejectCallback(error: OCPPError, requestStatistic = true): void {
+            if (requestStatistic && self.chargingStation.getEnableStatistics()) {
+              self.chargingStation.performanceStatistics.addRequestStatistic(
+                commandName,
+                MessageType.CALL_ERROR_MESSAGE
+              );
+            }
+            logger.error(
+              `${self.chargingStation.logPrefix()} Error %j occurred when calling command %s with message data %j`,
+              error,
+              commandName,
+              messagePayload
+            );
+            self.chargingStation.requests.delete(messageId);
+            reject(error);
           }
-          logger.error(`${self.chargingStation.logPrefix()} Error %j occurred when calling command %s with message data %j`, error, commandName, messagePayload);
-          self.chargingStation.requests.delete(messageId);
-          reject(error);
+        }),
+        Constants.OCPP_WEBSOCKET_TIMEOUT,
+        new OCPPError(
+          ErrorType.GENERIC_ERROR,
+          `Timeout for message id '${messageId}'`,
+          commandName,
+          (messagePayload?.details as JsonType) ?? {}
+        ),
+        () => {
+          messageType === MessageType.CALL_MESSAGE &&
+            this.chargingStation.requests.delete(messageId);
         }
-      }), Constants.OCPP_WEBSOCKET_TIMEOUT, new OCPPError(ErrorType.GENERIC_ERROR, `Timeout for message id '${messageId}'`, commandName, messagePayload?.details as JsonType ?? {}), () => {
-        messageType === MessageType.CALL_MESSAGE && this.chargingStation.requests.delete(messageId);
-      });
+      );
     }
-    throw new OCPPError(ErrorType.SECURITY_ERROR, `Cannot send command ${commandName} payload when the charging station is in ${this.chargingStation.getRegistrationStatus()} state on the central server`, commandName);
+    throw new OCPPError(
+      ErrorType.SECURITY_ERROR,
+      `Cannot send command ${commandName} payload when the charging station is in ${this.chargingStation.getRegistrationStatus()} state on the central server`,
+      commandName
+    );
   }
 
-  private buildMessageToSend(messageId: string, messagePayload: JsonType | OCPPError, messageType: MessageType, commandName?: RequestCommand | IncomingRequestCommand,
-      responseCallback?: (payload: JsonType | string, requestPayload: JsonType) => Promise<void>,
-      rejectCallback?: (error: OCPPError, requestStatistic?: boolean) => void): string {
+  private buildMessageToSend(
+    messageId: string,
+    messagePayload: JsonType | OCPPError,
+    messageType: MessageType,
+    commandName?: RequestCommand | IncomingRequestCommand,
+    responseCallback?: (payload: JsonType | string, requestPayload: JsonType) => Promise<void>,
+    rejectCallback?: (error: OCPPError, requestStatistic?: boolean) => void
+  ): string {
     let messageToSend: string;
     // Type of message
     switch (messageType) {
       // Request
       case MessageType.CALL_MESSAGE:
         // Build request
-        this.chargingStation.requests.set(messageId, [responseCallback, rejectCallback, commandName, messagePayload]);
+        this.chargingStation.requests.set(messageId, [
+          responseCallback,
+          rejectCallback,
+          commandName,
+          messagePayload,
+        ]);
         messageToSend = JSON.stringify([messageType, messageId, commandName, messagePayload]);
         break;
       // Response
@@ -169,27 +298,78 @@ export default abstract class OCPPRequestService {
       // Error Message
       case MessageType.CALL_ERROR_MESSAGE:
         // Build Error Message
-        messageToSend = JSON.stringify([messageType, messageId, messagePayload?.code ?? ErrorType.GENERIC_ERROR, messagePayload?.message ?? '', messagePayload?.details ?? { commandName }]);
+        messageToSend = JSON.stringify([
+          messageType,
+          messageId,
+          messagePayload?.code ?? ErrorType.GENERIC_ERROR,
+          messagePayload?.message ?? '',
+          messagePayload?.details ?? { commandName },
+        ]);
         break;
     }
     return messageToSend;
   }
 
-  private handleRequestError(commandName: RequestCommand | IncomingRequestCommand, error: Error, params: HandleErrorParams<EmptyObject> = { throwError: true }): void {
-    logger.error(this.chargingStation.logPrefix() + ' Request command %s error: %j', commandName, error);
+  private handleRequestError(
+    commandName: RequestCommand | IncomingRequestCommand,
+    error: Error,
+    params: HandleErrorParams<EmptyObject> = { throwError: true }
+  ): void {
+    logger.error(
+      this.chargingStation.logPrefix() + ' Request command %s error: %j',
+      commandName,
+      error
+    );
     if (params?.throwError) {
       throw error;
     }
   }
 
   public abstract sendHeartbeat(params?: SendParams): Promise<void>;
-  public abstract sendBootNotification(chargePointModel: string, chargePointVendor: string, chargeBoxSerialNumber?: string, firmwareVersion?: string, chargePointSerialNumber?: string, iccid?: string, imsi?: string, meterSerialNumber?: string, meterType?: string, params?: SendParams): Promise<BootNotificationResponse>;
-  public abstract sendStatusNotification(connectorId: number, status: ChargePointStatus, errorCode?: ChargePointErrorCode): Promise<void>;
+  public abstract sendBootNotification(
+    chargePointModel: string,
+    chargePointVendor: string,
+    chargeBoxSerialNumber?: string,
+    firmwareVersion?: string,
+    chargePointSerialNumber?: string,
+    iccid?: string,
+    imsi?: string,
+    meterSerialNumber?: string,
+    meterType?: string,
+    params?: SendParams
+  ): Promise<BootNotificationResponse>;
+  public abstract sendStatusNotification(
+    connectorId: number,
+    status: ChargePointStatus,
+    errorCode?: ChargePointErrorCode
+  ): Promise<void>;
   public abstract sendAuthorize(connectorId: number, idTag?: string): Promise<AuthorizeResponse>;
-  public abstract sendStartTransaction(connectorId: number, idTag?: string): Promise<StartTransactionResponse>;
-  public abstract sendStopTransaction(transactionId: number, meterStop: number, idTag?: string, reason?: StopTransactionReason): Promise<StopTransactionResponse>;
-  public abstract sendMeterValues(connectorId: number, transactionId: number, interval: number): Promise<void>;
-  public abstract sendTransactionBeginMeterValues(connectorId: number, transactionId: number, beginMeterValue: MeterValue): Promise<void>;
-  public abstract sendTransactionEndMeterValues(connectorId: number, transactionId: number, endMeterValue: MeterValue): Promise<void>;
-  public abstract sendDiagnosticsStatusNotification(diagnosticsStatus: DiagnosticsStatus): Promise<void>;
+  public abstract sendStartTransaction(
+    connectorId: number,
+    idTag?: string
+  ): Promise<StartTransactionResponse>;
+  public abstract sendStopTransaction(
+    transactionId: number,
+    meterStop: number,
+    idTag?: string,
+    reason?: StopTransactionReason
+  ): Promise<StopTransactionResponse>;
+  public abstract sendMeterValues(
+    connectorId: number,
+    transactionId: number,
+    interval: number
+  ): Promise<void>;
+  public abstract sendTransactionBeginMeterValues(
+    connectorId: number,
+    transactionId: number,
+    beginMeterValue: MeterValue
+  ): Promise<void>;
+  public abstract sendTransactionEndMeterValues(
+    connectorId: number,
+    transactionId: number,
+    endMeterValue: MeterValue
+  ): Promise<void>;
+  public abstract sendDiagnosticsStatusNotification(
+    diagnosticsStatus: DiagnosticsStatus
+  ): Promise<void>;
 }
index c0dd3f767ea14ff8546195556c48daf3aec3dc0c..2fa0112c70c6d42fc29958da64007576824b6285 100644 (file)
@@ -3,19 +3,29 @@ import { JsonType } from '../../types/JsonType';
 import { RequestCommand } from '../../types/ocpp/Requests';
 
 export default abstract class OCPPResponseService {
-  private static readonly instances: Map<string, OCPPResponseService> = new Map<string, OCPPResponseService>();
+  private static readonly instances: Map<string, OCPPResponseService> = new Map<
+    string,
+    OCPPResponseService
+  >();
   protected readonly chargingStation: ChargingStation;
 
   protected constructor(chargingStation: ChargingStation) {
     this.chargingStation = chargingStation;
   }
 
-  public static getInstance<T extends OCPPResponseService>(this: new (chargingStation: ChargingStation) => T, chargingStation: ChargingStation): T {
+  public static getInstance<T extends OCPPResponseService>(
+    this: new (chargingStation: ChargingStation) => T,
+    chargingStation: ChargingStation
+  ): T {
     if (!OCPPResponseService.instances.has(chargingStation.id)) {
       OCPPResponseService.instances.set(chargingStation.id, new this(chargingStation));
     }
     return OCPPResponseService.instances.get(chargingStation.id) as T;
   }
 
-  public abstract handleResponse(commandName: RequestCommand, payload: JsonType | string, requestPayload: JsonType): Promise<void>;
+  public abstract handleResponse(
+    commandName: RequestCommand,
+    payload: JsonType | string,
+    requestPayload: JsonType
+  ): Promise<void>;
 }
index 2dd6a2008465dbf29a336b7e010156bbb676f33b..0bc34bd99772f6e2f5cde37d397717af5d69668e 100644 (file)
@@ -21,7 +21,7 @@ export default abstract class AbstractUIService {
     if (this.messageHandlers.has(command)) {
       try {
         // Call the method to build the message response
-        messageResponse = await this.messageHandlers.get(command)(payload) as JsonType;
+        messageResponse = (await this.messageHandlers.get(command)(payload)) as JsonType;
       } catch (error) {
         // Log
         logger.error(this.uiWebSocketServer.logPrefix() + ' Handle message error: %j', error);
@@ -29,16 +29,19 @@ export default abstract class AbstractUIService {
       }
     } else {
       // Throw exception
-      throw new BaseError(`${command} is not implemented to handle message payload ${JSON.stringify(payload, null, 2)}`);
+      throw new BaseError(
+        `${command} is not implemented to handle message payload ${JSON.stringify(
+          payload,
+          null,
+          2
+        )}`
+      );
     }
     // Send the built message response
     this.uiWebSocketServer.broadcastToClients(this.buildProtocolMessage(command, messageResponse));
   }
 
-  protected buildProtocolMessage(
-      command: ProtocolCommand,
-      payload: JsonType,
-  ): string {
+  protected buildProtocolMessage(command: ProtocolCommand, payload: JsonType): string {
     return JSON.stringify([command, payload]);
   }
 
index a9bc401c98f2f92895620bf57ca21b3e8f15b50c..18fb66a9d4a08589883bcb3569622bccac817034 100644 (file)
@@ -7,10 +7,16 @@ import UIWebSocketServer from '../UIWebSocketServer';
 export default class UIService001 extends AbstractUIService {
   constructor(uiWebSocketServer: UIWebSocketServer) {
     super(uiWebSocketServer);
-    this.messageHandlers.set(ProtocolCommand.START_TRANSACTION, this.handleStartTransaction.bind(this) as ProtocolRequestHandler);
-    this.messageHandlers.set(ProtocolCommand.STOP_TRANSACTION, this.handleStopTransaction.bind(this) as ProtocolRequestHandler);
+    this.messageHandlers.set(
+      ProtocolCommand.START_TRANSACTION,
+      this.handleStartTransaction.bind(this) as ProtocolRequestHandler
+    );
+    this.messageHandlers.set(
+      ProtocolCommand.STOP_TRANSACTION,
+      this.handleStopTransaction.bind(this) as ProtocolRequestHandler
+    );
   }
 
-  private handleStartTransaction(payload: JsonType): void { }
-  private handleStopTransaction(payload: JsonType): void { }
+  private handleStartTransaction(payload: JsonType): void {}
+  private handleStopTransaction(payload: JsonType): void {}
 }
index 108a113f7558b07cccf351c22582baa5f205103c..d6a87cdb1b69429d3852175d0fa56be30682bbe9 100644 (file)
@@ -8,7 +8,10 @@ export default class UIServiceFactory {
     // This is intentional
   }
 
-  public static getUIServiceImplementation(version: ProtocolVersion, uiWebSocketServer: UIWebSocketServer): AbstractUIService | null {
+  public static getUIServiceImplementation(
+    version: ProtocolVersion,
+    uiWebSocketServer: UIWebSocketServer
+  ): AbstractUIService | null {
     switch (version) {
       case ProtocolVersion['0.0.1']:
         return new UIService001(uiWebSocketServer);
index 2c37e80a4f9b2cc743a7b468b0d96fa9d284290b..9427c08e5aa61b466a77e6caa5f111e3af8147ed 100644 (file)
@@ -5,19 +5,32 @@ import Utils from '../../utils/Utils';
 import logger from '../../utils/Logger';
 
 export class UIServiceUtils {
-  public static handleProtocols = (protocols: Set<string>, request: IncomingMessage): string | false => {
+  public static handleProtocols = (
+    protocols: Set<string>,
+    request: IncomingMessage
+  ): string | false => {
     let protocolIndex: number;
     let protocol: Protocol;
     let version: ProtocolVersion;
     for (const fullProtocol of protocols) {
       protocolIndex = fullProtocol.indexOf(Protocol.UI);
-      protocol = fullProtocol.substring(protocolIndex, protocolIndex + Protocol.UI.length) as Protocol;
+      protocol = fullProtocol.substring(
+        protocolIndex,
+        protocolIndex + Protocol.UI.length
+      ) as Protocol;
       version = fullProtocol.substring(protocolIndex + Protocol.UI.length) as ProtocolVersion;
-      if (Object.values(Protocol).includes(protocol) && Object.values(ProtocolVersion).includes(version)) {
+      if (
+        Object.values(Protocol).includes(protocol) &&
+        Object.values(ProtocolVersion).includes(version)
+      ) {
         return fullProtocol;
       }
     }
-    logger.error(`${Utils.logPrefix(' UI WebSocket Server:')} Unsupported protocol: ${protocol} or protocol version: ${version}`);
+    logger.error(
+      `${Utils.logPrefix(
+        ' UI WebSocket Server:'
+      )} Unsupported protocol: ${protocol} or protocol version: ${version}`
+    );
     return false;
   };
 }
index ad78e261cfe1e0e0561cd4cf0562f7a2690f3468..1471844cf4cf109e0df3895061b586d6c6c510c2 100644 (file)
@@ -3,7 +3,7 @@ export default class BaseError extends Error {
     super(message);
     this.name = new.target.name;
     Object.setPrototypeOf(this, new.target.prototype);
-    Error.captureStackTrace ? (Error.captureStackTrace(this, this.constructor)) : (this.createStack());
+    Error.captureStackTrace ? Error.captureStackTrace(this, this.constructor) : this.createStack();
   }
 
   private createStack(): void {
index 8b108aec535255e746ee6d2c7e630ff49581b43d..9f2b22623dc65085fac88b4c9191d3a3c86e9061 100644 (file)
@@ -11,7 +11,12 @@ export default class OCPPError extends BaseError {
   command?: RequestCommand | IncomingRequestCommand;
   details?: JsonType;
 
-  constructor(code: ErrorType | IncomingRequestCommand, message: string, command?: RequestCommand | IncomingRequestCommand, details?: JsonType) {
+  constructor(
+    code: ErrorType | IncomingRequestCommand,
+    message: string,
+    command?: RequestCommand | IncomingRequestCommand,
+    details?: JsonType
+  ) {
     super(message);
 
     this.code = code ?? ErrorType.GENERIC_ERROR;
index b9fa14905d2e5cfb1c9e613f1a8367f41cde075c..bec0f62e28099597ab5e4a46dc75c360cf4f408a 100644 (file)
@@ -14,7 +14,10 @@ import logger from '../utils/Logger';
 import { parentPort } from 'worker_threads';
 
 export default class PerformanceStatistics {
-  private static readonly instances: Map<string, PerformanceStatistics> = new Map<string, PerformanceStatistics>();
+  private static readonly instances: Map<string, PerformanceStatistics> = new Map<
+    string,
+    PerformanceStatistics
+  >();
   private readonly objId: string;
   private readonly objName: string;
   private performanceObserver: PerformanceObserver;
@@ -25,7 +28,13 @@ export default class PerformanceStatistics {
     this.objId = objId;
     this.objName = objName;
     this.initializePerformanceObserver();
-    this.statistics = { id: this.objId ?? 'Object id not specified', name: this.objName ?? 'Object name not specified', uri: uri.toString(), createdAt: new Date(), statisticsData: new Map<string, Partial<StatisticsData>>() };
+    this.statistics = {
+      id: this.objId ?? 'Object id not specified',
+      name: this.objName ?? 'Object name not specified',
+      uri: uri.toString(),
+      createdAt: new Date(),
+      statisticsData: new Map<string, Partial<StatisticsData>>(),
+    };
   }
 
   public static getInstance(objId: string, objName: string, uri: URL): PerformanceStatistics {
@@ -46,27 +55,48 @@ export default class PerformanceStatistics {
     performance.clearMarks(markId);
   }
 
-  public addRequestStatistic(command: RequestCommand | IncomingRequestCommand, messageType: MessageType): void {
+  public addRequestStatistic(
+    command: RequestCommand | IncomingRequestCommand,
+    messageType: MessageType
+  ): void {
     switch (messageType) {
       case MessageType.CALL_MESSAGE:
-        if (this.statistics.statisticsData.has(command) && this.statistics.statisticsData.get(command)?.countRequest) {
+        if (
+          this.statistics.statisticsData.has(command) &&
+          this.statistics.statisticsData.get(command)?.countRequest
+        ) {
           this.statistics.statisticsData.get(command).countRequest++;
         } else {
-          this.statistics.statisticsData.set(command, Object.assign({ countRequest: 1 }, this.statistics.statisticsData.get(command)));
+          this.statistics.statisticsData.set(
+            command,
+            Object.assign({ countRequest: 1 }, this.statistics.statisticsData.get(command))
+          );
         }
         break;
       case MessageType.CALL_RESULT_MESSAGE:
-        if (this.statistics.statisticsData.has(command) && this.statistics.statisticsData.get(command)?.countResponse) {
+        if (
+          this.statistics.statisticsData.has(command) &&
+          this.statistics.statisticsData.get(command)?.countResponse
+        ) {
           this.statistics.statisticsData.get(command).countResponse++;
         } else {
-          this.statistics.statisticsData.set(command, Object.assign({ countResponse: 1 }, this.statistics.statisticsData.get(command)));
+          this.statistics.statisticsData.set(
+            command,
+            Object.assign({ countResponse: 1 }, this.statistics.statisticsData.get(command))
+          );
         }
         break;
       case MessageType.CALL_ERROR_MESSAGE:
-        if (this.statistics.statisticsData.has(command) && this.statistics.statisticsData.get(command)?.countError) {
+        if (
+          this.statistics.statisticsData.has(command) &&
+          this.statistics.statisticsData.get(command)?.countError
+        ) {
           this.statistics.statisticsData.get(command).countError++;
         } else {
-          this.statistics.statisticsData.set(command, Object.assign({ countError: 1 }, this.statistics.statisticsData.get(command)));
+          this.statistics.statisticsData.set(
+            command,
+            Object.assign({ countError: 1 }, this.statistics.statisticsData.get(command))
+          );
         }
         break;
       default:
@@ -78,7 +108,11 @@ export default class PerformanceStatistics {
   public start(): void {
     this.startLogStatisticsInterval();
     if (Configuration.getPerformanceStorage().enabled) {
-      logger.info(`${this.logPrefix()} storage enabled: type ${Configuration.getPerformanceStorage().type}, uri: ${Configuration.getPerformanceStorage().uri}`);
+      logger.info(
+        `${this.logPrefix()} storage enabled: type ${
+          Configuration.getPerformanceStorage().type
+        }, uri: ${Configuration.getPerformanceStorage().uri}`
+      );
     }
   }
 
@@ -99,7 +133,10 @@ export default class PerformanceStatistics {
     this.performanceObserver = new PerformanceObserver((list) => {
       const lastPerformanceEntry = list.getEntries()[0];
       this.addPerformanceEntryToStatistics(lastPerformanceEntry);
-      logger.debug(`${this.logPrefix()} '${lastPerformanceEntry.name}' performance entry: %j`, lastPerformanceEntry);
+      logger.debug(
+        `${this.logPrefix()} '${lastPerformanceEntry.name}' performance entry: %j`,
+        lastPerformanceEntry
+      );
     });
     this.performanceObserver.observe({ entryTypes: ['measure'] });
   }
@@ -113,9 +150,18 @@ export default class PerformanceStatistics {
       this.displayInterval = setInterval(() => {
         this.logStatistics();
       }, Configuration.getLogStatisticsInterval() * 1000);
-      logger.info(this.logPrefix() + ' logged every ' + Utils.formatDurationSeconds(Configuration.getLogStatisticsInterval()));
+      logger.info(
+        this.logPrefix() +
+          ' logged every ' +
+          Utils.formatDurationSeconds(Configuration.getLogStatisticsInterval())
+      );
     } else {
-      logger.info(this.logPrefix() + ' log interval is set to ' + Configuration.getLogStatisticsInterval().toString() + '. Not logging statistics');
+      logger.info(
+        this.logPrefix() +
+          ' log interval is set to ' +
+          Configuration.getLogStatisticsInterval().toString() +
+          '. Not logging statistics'
+      );
     }
   }
 
@@ -123,12 +169,12 @@ export default class PerformanceStatistics {
     if (Array.isArray(dataSet) && dataSet.length === 1) {
       return dataSet[0];
     }
-    const sortedDataSet = dataSet.slice().sort((a, b) => (a - b));
+    const sortedDataSet = dataSet.slice().sort((a, b) => a - b);
     const middleIndex = Math.floor(sortedDataSet.length / 2);
     if (sortedDataSet.length % 2) {
       return sortedDataSet[middleIndex / 2];
     }
-    return (sortedDataSet[(middleIndex - 1)] + sortedDataSet[middleIndex]) / 2;
+    return (sortedDataSet[middleIndex - 1] + sortedDataSet[middleIndex]) / 2;
   }
 
   // TODO: use order statistics tree https://en.wikipedia.org/wiki/Order_statistic_tree
@@ -139,14 +185,14 @@ export default class PerformanceStatistics {
     if (Utils.isEmptyArray(dataSet)) {
       return 0;
     }
-    const sortedDataSet = dataSet.slice().sort((a, b) => (a - b));
+    const sortedDataSet = dataSet.slice().sort((a, b) => a - b);
     if (percentile === 0) {
       return sortedDataSet[0];
     }
     if (percentile === 100) {
       return sortedDataSet[sortedDataSet.length - 1];
     }
-    const percentileIndex = ((percentile / 100) * sortedDataSet.length) - 1;
+    const percentileIndex = (percentile / 100) * sortedDataSet.length - 1;
     if (Number.isInteger(percentileIndex)) {
       return (sortedDataSet[percentileIndex] + sortedDataSet[percentileIndex + 1]) / 2;
     }
@@ -180,28 +226,61 @@ export default class PerformanceStatistics {
     }
     // Update current statistics
     this.statistics.updatedAt = new Date();
-    this.statistics.statisticsData.get(entryName).countTimeMeasurement = this.statistics.statisticsData.get(entryName)?.countTimeMeasurement
-      ? this.statistics.statisticsData.get(entryName).countTimeMeasurement + 1
-      : 1;
+    this.statistics.statisticsData.get(entryName).countTimeMeasurement =
+      this.statistics.statisticsData.get(entryName)?.countTimeMeasurement
+        ? this.statistics.statisticsData.get(entryName).countTimeMeasurement + 1
+        : 1;
     this.statistics.statisticsData.get(entryName).currentTimeMeasurement = entry.duration;
-    this.statistics.statisticsData.get(entryName).minTimeMeasurement = this.statistics.statisticsData.get(entryName)?.minTimeMeasurement
-      ? (this.statistics.statisticsData.get(entryName).minTimeMeasurement > entry.duration ? entry.duration : this.statistics.statisticsData.get(entryName).minTimeMeasurement)
-      : entry.duration;
-    this.statistics.statisticsData.get(entryName).maxTimeMeasurement = this.statistics.statisticsData.get(entryName)?.maxTimeMeasurement
-      ? (this.statistics.statisticsData.get(entryName).maxTimeMeasurement < entry.duration ? entry.duration : this.statistics.statisticsData.get(entryName).maxTimeMeasurement)
-      : entry.duration;
-    this.statistics.statisticsData.get(entryName).totalTimeMeasurement = this.statistics.statisticsData.get(entryName)?.totalTimeMeasurement
-      ? this.statistics.statisticsData.get(entryName).totalTimeMeasurement + entry.duration
-      : entry.duration;
-    this.statistics.statisticsData.get(entryName).avgTimeMeasurement = this.statistics.statisticsData.get(entryName).totalTimeMeasurement / this.statistics.statisticsData.get(entryName).countTimeMeasurement;
+    this.statistics.statisticsData.get(entryName).minTimeMeasurement =
+      this.statistics.statisticsData.get(entryName)?.minTimeMeasurement
+        ? this.statistics.statisticsData.get(entryName).minTimeMeasurement > entry.duration
+          ? entry.duration
+          : this.statistics.statisticsData.get(entryName).minTimeMeasurement
+        : entry.duration;
+    this.statistics.statisticsData.get(entryName).maxTimeMeasurement =
+      this.statistics.statisticsData.get(entryName)?.maxTimeMeasurement
+        ? this.statistics.statisticsData.get(entryName).maxTimeMeasurement < entry.duration
+          ? entry.duration
+          : this.statistics.statisticsData.get(entryName).maxTimeMeasurement
+        : entry.duration;
+    this.statistics.statisticsData.get(entryName).totalTimeMeasurement =
+      this.statistics.statisticsData.get(entryName)?.totalTimeMeasurement
+        ? this.statistics.statisticsData.get(entryName).totalTimeMeasurement + entry.duration
+        : entry.duration;
+    this.statistics.statisticsData.get(entryName).avgTimeMeasurement =
+      this.statistics.statisticsData.get(entryName).totalTimeMeasurement /
+      this.statistics.statisticsData.get(entryName).countTimeMeasurement;
     Array.isArray(this.statistics.statisticsData.get(entryName).timeMeasurementSeries)
-      ? this.statistics.statisticsData.get(entryName).timeMeasurementSeries.push({ timestamp: entry.startTime, value: entry.duration })
-      : this.statistics.statisticsData.get(entryName).timeMeasurementSeries = new CircularArray<TimeSeries>(DEFAULT_CIRCULAR_ARRAY_SIZE, { timestamp: entry.startTime, value: entry.duration });
-    this.statistics.statisticsData.get(entryName).medTimeMeasurement = this.median(this.extractTimeSeriesValues(this.statistics.statisticsData.get(entryName).timeMeasurementSeries));
-    this.statistics.statisticsData.get(entryName).ninetyFiveThPercentileTimeMeasurement = this.percentile(this.extractTimeSeriesValues(this.statistics.statisticsData.get(entryName).timeMeasurementSeries), 95);
-    this.statistics.statisticsData.get(entryName).stdDevTimeMeasurement = this.stdDeviation(this.extractTimeSeriesValues(this.statistics.statisticsData.get(entryName).timeMeasurementSeries));
+      ? this.statistics.statisticsData
+          .get(entryName)
+          .timeMeasurementSeries.push({ timestamp: entry.startTime, value: entry.duration })
+      : (this.statistics.statisticsData.get(entryName).timeMeasurementSeries =
+          new CircularArray<TimeSeries>(DEFAULT_CIRCULAR_ARRAY_SIZE, {
+            timestamp: entry.startTime,
+            value: entry.duration,
+          }));
+    this.statistics.statisticsData.get(entryName).medTimeMeasurement = this.median(
+      this.extractTimeSeriesValues(
+        this.statistics.statisticsData.get(entryName).timeMeasurementSeries
+      )
+    );
+    this.statistics.statisticsData.get(entryName).ninetyFiveThPercentileTimeMeasurement =
+      this.percentile(
+        this.extractTimeSeriesValues(
+          this.statistics.statisticsData.get(entryName).timeMeasurementSeries
+        ),
+        95
+      );
+    this.statistics.statisticsData.get(entryName).stdDevTimeMeasurement = this.stdDeviation(
+      this.extractTimeSeriesValues(
+        this.statistics.statisticsData.get(entryName).timeMeasurementSeries
+      )
+    );
     if (Configuration.getPerformanceStorage().enabled) {
-      parentPort.postMessage({ id: ChargingStationWorkerMessageEvents.PERFORMANCE_STATISTICS, data: this.statistics });
+      parentPort.postMessage({
+        id: ChargingStationWorkerMessageEvents.PERFORMANCE_STATISTICS,
+        data: this.statistics,
+      });
     }
   }
 
index 9b016f0637bad0c15cbfa9b18700c6c10801ceaa..8a8808e9baa7af069a2834a2afe14a796ccaca1d 100644 (file)
@@ -17,33 +17,45 @@ export class JsonFileStorage extends Storage {
 
   public storePerformanceStatistics(performanceStatistics: Statistics): void {
     this.checkPerformanceRecordsFile();
-    lockfile.lock(this.dbName, { stale: 5000, retries: 3 })
+    lockfile
+      .lock(this.dbName, { stale: 5000, retries: 3 })
       .then(async (release) => {
         try {
           const fileData = fs.readFileSync(this.dbName, 'utf8');
-          const performanceRecords: Statistics[] = fileData ? JSON.parse(fileData) as Statistics[] : [];
+          const performanceRecords: Statistics[] = fileData
+            ? (JSON.parse(fileData) as Statistics[])
+            : [];
           performanceRecords.push(performanceStatistics);
           fs.writeFileSync(
             this.dbName,
-            JSON.stringify(performanceRecords,
+            JSON.stringify(
+              performanceRecords,
               (key, value) => {
                 if (value instanceof Map) {
                   return {
                     dataType: 'Map',
-                    value: [...value]
+                    value: [...value],
                   };
                 }
                 return value as Statistics;
               },
-              2),
+              2
+            ),
             'utf8'
           );
         } catch (error) {
-          FileUtils.handleFileException(this.logPrefix, Constants.PERFORMANCE_RECORDS_FILETYPE, this.dbName, error as NodeJS.ErrnoException);
+          FileUtils.handleFileException(
+            this.logPrefix,
+            Constants.PERFORMANCE_RECORDS_FILETYPE,
+            this.dbName,
+            error as NodeJS.ErrnoException
+          );
         }
         await release();
       })
-      .catch(() => { /* This is intentional */ });
+      .catch(() => {
+        /* This is intentional */
+      });
   }
 
   public open(): void {
@@ -52,7 +64,12 @@ export class JsonFileStorage extends Storage {
         this.fd = fs.openSync(this.dbName, 'a+');
       }
     } catch (error) {
-      FileUtils.handleFileException(this.logPrefix, Constants.PERFORMANCE_RECORDS_FILETYPE, this.dbName, error as NodeJS.ErrnoException);
+      FileUtils.handleFileException(
+        this.logPrefix,
+        Constants.PERFORMANCE_RECORDS_FILETYPE,
+        this.dbName,
+        error as NodeJS.ErrnoException
+      );
     }
   }
 
@@ -63,13 +80,20 @@ export class JsonFileStorage extends Storage {
         this.fd = null;
       }
     } catch (error) {
-      FileUtils.handleFileException(this.logPrefix, Constants.PERFORMANCE_RECORDS_FILETYPE, this.dbName, error as NodeJS.ErrnoException);
+      FileUtils.handleFileException(
+        this.logPrefix,
+        Constants.PERFORMANCE_RECORDS_FILETYPE,
+        this.dbName,
+        error as NodeJS.ErrnoException
+      );
     }
   }
 
   private checkPerformanceRecordsFile(): void {
     if (!this?.fd) {
-      throw new Error(`${this.logPrefix} Performance records '${this.dbName}' file descriptor not found`);
+      throw new Error(
+        `${this.logPrefix} Performance records '${this.dbName}' file descriptor not found`
+      );
     }
   }
 }
index 82bdd23419fde02c82419952c17b2597a5c7c75f..1953491adb698692172c7595ac57e28016cc7360 100644 (file)
@@ -54,15 +54,20 @@ export class MikroOrmStorage extends Storage {
     if (this.storageType === StorageType.SQLITE) {
       return `${Constants.DEFAULT_PERFORMANCE_RECORDS_DB_NAME}.db`;
     }
-    return this.storageUri.pathname.replace(/(?:^\/)|(?:\/$)/g, '') ?? Constants.DEFAULT_PERFORMANCE_RECORDS_DB_NAME;
+    return (
+      this.storageUri.pathname.replace(/(?:^\/)|(?:\/$)/g, '') ??
+      Constants.DEFAULT_PERFORMANCE_RECORDS_DB_NAME
+    );
   }
 
-  private getOptions(): Configuration<IDatabaseDriver<Connection>> | Options<IDatabaseDriver<Connection>> {
+  private getOptions():
+    | Configuration<IDatabaseDriver<Connection>>
+    | Options<IDatabaseDriver<Connection>> {
     return {
       metadataProvider: TsMorphMetadataProvider,
       entities: [PerformanceRecord, PerformanceData],
       type: this.storageType as MikroORMDBType,
-      clientUrl: this.getClientUrl()
+      clientUrl: this.getClientUrl(),
     };
   }
 
@@ -75,4 +80,3 @@ export class MikroOrmStorage extends Storage {
     }
   }
 }
-
index 6bc43bbb8d16e15850aceda9a9b503cd6e1af00b..cefab6f39a4b1cadb4f5681e51218adc592b81a6 100644 (file)
@@ -14,13 +14,18 @@ export class MongoDBStorage extends Storage {
     super(storageUri, logPrefix);
     this.client = new MongoClient(this.storageUri.toString());
     this.connected = false;
-    this.dbName = this.storageUri.pathname.replace(/(?:^\/)|(?:\/$)/g, '') ?? Constants.DEFAULT_PERFORMANCE_RECORDS_DB_NAME;
+    this.dbName =
+      this.storageUri.pathname.replace(/(?:^\/)|(?:\/$)/g, '') ??
+      Constants.DEFAULT_PERFORMANCE_RECORDS_DB_NAME;
   }
 
   public async storePerformanceStatistics(performanceStatistics: Statistics): Promise<void> {
     try {
       this.checkDBConnection();
-      await this.client.db(this.dbName).collection<Statistics>(Constants.PERFORMANCE_RECORDS_TABLE).insertOne(performanceStatistics);
+      await this.client
+        .db(this.dbName)
+        .collection<Statistics>(Constants.PERFORMANCE_RECORDS_TABLE)
+        .insertOne(performanceStatistics);
     } catch (error) {
       this.handleDBError(StorageType.MONGO_DB, error as Error, Constants.PERFORMANCE_RECORDS_TABLE);
     }
@@ -50,10 +55,18 @@ export class MongoDBStorage extends Storage {
 
   private checkDBConnection() {
     if (!this?.client) {
-      throw new Error(`${this.logPrefix} ${this.getDBNameFromStorageType(StorageType.MONGO_DB)} client initialization failed while trying to issue a request`);
+      throw new Error(
+        `${this.logPrefix} ${this.getDBNameFromStorageType(
+          StorageType.MONGO_DB
+        )} client initialization failed while trying to issue a request`
+      );
     }
     if (!this.connected) {
-      throw new Error(`${this.logPrefix} ${this.getDBNameFromStorageType(StorageType.MONGO_DB)} connection not opened while trying to issue a request`);
+      throw new Error(
+        `${this.logPrefix} ${this.getDBNameFromStorageType(
+          StorageType.MONGO_DB
+        )} connection not opened while trying to issue a request`
+      );
     }
   }
 }
index c4a0ce9c5669d2516554d161b11f8234a8e08c09..266d934177886eec06ca97b19a8ba07db11a5c42 100644 (file)
@@ -19,8 +19,18 @@ export abstract class Storage {
     this.logPrefix = logPrefix;
   }
 
-  protected handleDBError(type: StorageType, error: Error, table?: string, params: HandleErrorParams<EmptyObject> = { throwError: false }): void {
-    logger.error(`${this.logPrefix} ${this.getDBNameFromStorageType(type)} error '${error.message}'${(!Utils.isNullOrUndefined(table) || !table) && ` in table or collection '${table}'`}: %j`, error);
+  protected handleDBError(
+    type: StorageType,
+    error: Error,
+    table?: string,
+    params: HandleErrorParams<EmptyObject> = { throwError: false }
+  ): void {
+    logger.error(
+      `${this.logPrefix} ${this.getDBNameFromStorageType(type)} error '${error.message}'${
+        (!Utils.isNullOrUndefined(table) || !table) && ` in table or collection '${table}'`
+      }: %j`,
+      error
+    );
     if (params?.throwError) {
       throw error;
     }
@@ -41,5 +51,7 @@ export abstract class Storage {
 
   public abstract open(): void | Promise<void>;
   public abstract close(): void | Promise<void>;
-  public abstract storePerformanceStatistics(performanceStatistics: Statistics): void | Promise<void>;
+  public abstract storePerformanceStatistics(
+    performanceStatistics: Statistics
+  ): void | Promise<void>;
 }
index 3ebeb0942a1d007a18db7324cc12504088639816..ca5875d383e650d418eed97651496a4ba74933d4 100755 (executable)
@@ -14,14 +14,18 @@ const config = JSON.parse(fs.readFileSync('scriptConfig.json', 'utf8'));
 
 // Mongo Connection and Query
 if (config && config.mongoConnectionString) {
-  MongoClient.connect(config.mongoConnectionString, async function(err, client) {
+  MongoClient.connect(config.mongoConnectionString, async function (err, client) {
     const db = client.db();
 
     for await (const tenantID of config.tenantIDs) {
-      const response = await db.collection(tenantID + '.chargingstations').deleteMany(
-        { _id: { '$regex': config.idPattern } }
+      const response = await db
+        .collection(tenantID + '.chargingstations')
+        .deleteMany({ _id: { $regex: config.idPattern } });
+      console.log(
+        response.deletedCount,
+        `Charging Stations with id = %${config.idPattern}% deleted. TenantID =`,
+        tenantID
       );
-      console.log(response.deletedCount, `Charging Stations with id = %${config.idPattern}% deleted. TenantID =`, tenantID);
     }
     client.close();
   });
index f30b37ad30fd1fc4180f07987333c7d9e9714bf2..fb911ff30d23f20dc837b216829a9f9b40c3b4f3 100644 (file)
@@ -1,8 +1,6 @@
 {
   "publicFlag": true,
-  "tenantIDs": [
-    ""
-  ],
+  "tenantIDs": [""],
   "idPattern": "",
   "mongoConnectionString": "mongodb://..."
 }
index 5cd7a6469a6bc8ba752963edf859bc1ebab11d9a..0b334c1ad9fa024821c59633433c6c6bf970bc68 100755 (executable)
@@ -15,15 +15,18 @@ const config = JSON.parse(fs.readFileSync('scriptConfig.json', 'utf8'));
 
 // Mongo Connection and Query
 if (config && config.mongoConnectionString) {
-  MongoClient.connect(config.mongoConnectionString, async function(err, client) {
+  MongoClient.connect(config.mongoConnectionString, async function (err, client) {
     const db = client.db();
 
     for await (const tenantID of config.tenantIDs) {
-      const response = await db.collection(tenantID + '.chargingstations').updateMany(
-        { _id: { '$regex': config.idPattern } },
-        { $set: { public: config.publicFlag } }
+      const response = await db
+        .collection(tenantID + '.chargingstations')
+        .updateMany({ _id: { $regex: config.idPattern } }, { $set: { public: config.publicFlag } });
+      console.log(
+        response.modifiedCount,
+        `Charging Stations with id = %${config.idPattern}% updated. TenantID =`,
+        tenantID
       );
-      console.log(response.modifiedCount, `Charging Stations with id = %${config.idPattern}% updated. TenantID =`, tenantID);
     }
     client.close();
   });
index a3c14ffa44f26c530bef3766d21731f8c76c1622..ebad51ef634a01df62a540b3fe1d8c086813e727 100644 (file)
@@ -3,8 +3,8 @@
 import Bootstrap from './charging-station/Bootstrap';
 import chalk from 'chalk';
 
-Bootstrap.getInstance().start().catch(
-  (error) => {
+Bootstrap.getInstance()
+  .start()
+  .catch((error) => {
     console.error(chalk.red(error));
-  }
-);
+  });
index 309120b6dff966e77eb18c3065dc13406f878846..eabe60d09ff3930b4303e0edda4e2854608a5daf 100644 (file)
@@ -19,7 +19,7 @@ export enum Voltage {
   VOLTAGE_110 = 110,
   VOLTAGE_230 = 230,
   VOLTAGE_400 = 400,
-  VOLTAGE_800 = 800
+  VOLTAGE_800 = 800,
 }
 
 export interface AutomaticTransactionGenerator {
@@ -31,7 +31,7 @@ export interface AutomaticTransactionGenerator {
   probabilityOfStart: number;
   stopAfterHours: number;
   stopOnConnectionFailure: boolean;
-  requireAuthorize?: boolean
+  requireAuthorize?: boolean;
 }
 
 export default interface ChargingStationTemplate {
index 155a353a0d61efb84bf894de867a86fb8c233a03..f5a0206da23247bde4805f7ce87b7f2316027bb4 100644 (file)
@@ -15,17 +15,19 @@ export interface ChargingStationWorkerData extends WorkerData {
 enum InternalChargingStationWorkerMessageEvents {
   STARTED = 'started',
   STOPPED = 'stopped',
-  PERFORMANCE_STATISTICS = 'performanceStatistics'
+  PERFORMANCE_STATISTICS = 'performanceStatistics',
 }
 
-export type ChargingStationWorkerMessageEvents = WorkerMessageEvents | InternalChargingStationWorkerMessageEvents;
+export type ChargingStationWorkerMessageEvents =
+  | WorkerMessageEvents
+  | InternalChargingStationWorkerMessageEvents;
 
 export const ChargingStationWorkerMessageEvents = {
   ...WorkerMessageEvents,
-  ...InternalChargingStationWorkerMessageEvents
+  ...InternalChargingStationWorkerMessageEvents,
 };
 
-
-export interface ChargingStationWorkerMessage extends Omit<WorkerMessage<ChargingStationWorkerData>, 'id'> {
+export interface ChargingStationWorkerMessage
+  extends Omit<WorkerMessage<ChargingStationWorkerData>, 'id'> {
   id: ChargingStationWorkerMessageEvents;
 }
index bad6fc8c38651d3f2cde19b55b05f8b3f3d7a0e7..1d674edfa3d5d7d9fdd8e430c2e25dc3b72f141f 100644 (file)
@@ -7,13 +7,12 @@ export enum StorageType {
   MONGO_DB = 'mongodb',
   MYSQL = 'mysql',
   MARIA_DB = 'mariadb',
-  SQLITE = 'sqlite'
+  SQLITE = 'sqlite',
 }
 
 export enum DBName {
   MONGO_DB = 'MongoDB',
   MYSQL = 'MySQL',
   MARIA_DB = 'MariaDB',
-  SQLITE = 'SQLite'
+  SQLITE = 'SQLite',
 }
-
index ea01b4fc77558063716b3837e20715dc3a25285b..6d2478924285e3b97dfa67c1de04b28c0272bee5 100644 (file)
@@ -17,4 +17,6 @@ export enum ProtocolCommand {
 
 export type ProtocolRequest = [ProtocolCommand, JsonType];
 
-export type ProtocolRequestHandler = (payload: JsonType) => void | Promise<void> | JsonType | Promise<JsonType>;
+export type ProtocolRequestHandler = (
+  payload: JsonType
+) => void | Promise<void> | JsonType | Promise<JsonType>;
index 60b2f681ef1464b960e26ba783688067149e7e62..7d028afea0543ca4acf70f4c0864ca1a9357b16a 100644 (file)
@@ -1,21 +1,22 @@
-export const WebSocketCloseEventStatusString: Record<WebSocketCloseEventStatusCode, string> = Object.freeze({
-  1000: 'Normal Closure',
-  1001: 'Going Away',
-  1002: 'Protocol Error',
-  1003: 'Unsupported Frame Data',
-  1004: 'Reserved',
-  1005: 'No Status Received',
-  1006: 'Abnormal Closure',
-  1007: 'Invalid Frame Payload Data',
-  1008: 'Policy Violation',
-  1009: 'Message Too Large',
-  1010: 'Missing Extension',
-  1011: 'Server Internal Error',
-  1012: 'Service Restart',
-  1013: 'Try Again Later',
-  1014: 'Bad Gateway',
-  1015: 'TLS Handshake'
-});
+export const WebSocketCloseEventStatusString: Record<WebSocketCloseEventStatusCode, string> =
+  Object.freeze({
+    1000: 'Normal Closure',
+    1001: 'Going Away',
+    1002: 'Protocol Error',
+    1003: 'Unsupported Frame Data',
+    1004: 'Reserved',
+    1005: 'No Status Received',
+    1006: 'Abnormal Closure',
+    1007: 'Invalid Frame Payload Data',
+    1008: 'Policy Violation',
+    1009: 'Message Too Large',
+    1010: 'Missing Extension',
+    1011: 'Server Internal Error',
+    1012: 'Service Restart',
+    1013: 'Try Again Later',
+    1014: 'Bad Gateway',
+    1015: 'TLS Handshake',
+  });
 
 export enum WebSocketCloseEventStatusCode {
   CLOSE_NORMAL = 1000,
@@ -33,9 +34,9 @@ export enum WebSocketCloseEventStatusCode {
   CLOSE_SERVICE_RESTART = 1012,
   CLOSE_TRY_AGAIN_LATER = 1013,
   CLOSE_BAD_GATEWAY = 1014,
-  CLOSE_TLS_HANDSHAKE = 1015
+  CLOSE_TLS_HANDSHAKE = 1015,
 }
 
 export interface WSError extends Error {
-  code?: string
+  code?: string;
 }
index aca1922e02a1df88e098068f12f295ab9f16fe1e..83d62f3f9082554203f007f7ae170a29e2626689 100644 (file)
@@ -5,7 +5,7 @@ import { Worker } from 'worker_threads';
 export enum WorkerProcessType {
   WORKER_SET = 'workerSet',
   DYNAMIC_POOL = 'dynamicPool',
-  STATIC_POOL = 'staticPool'
+  STATIC_POOL = 'staticPool',
 }
 
 export interface WorkerOptions {
@@ -32,6 +32,5 @@ export interface WorkerMessage<T extends WorkerData> {
 
 export enum WorkerMessageEvents {
   START_WORKER_ELEMENT = 'startWorkerElement',
-  STOP_WORKER_ELEMENT = 'stopWorkerElement'
+  STOP_WORKER_ELEMENT = 'stopWorkerElement',
 }
-
index db06d0c9da53758e055398531fd549906b0b045a..4255cd059c8a8c22623b08f756a01c29c6145380 100644 (file)
@@ -14,5 +14,5 @@ export enum OCPP16ChargePointErrorCode {
   READER_FAILURE = 'ReaderFailure',
   RESET_FAILURE = 'ResetFailure',
   UNDER_VOLTAGE = 'UnderVoltage',
-  WEAK_SIGNAL = 'WeakSignal'
+  WEAK_SIGNAL = 'WeakSignal',
 }
index 474c691ffee14c787681b9b8e8fefde48aff7dbb..8e4f58fecfa54d121d7c70b7a9ab2f3194109772 100644 (file)
@@ -4,7 +4,7 @@ export enum OCPP16SupportedFeatureProfiles {
   Local_Auth_List_Management = 'LocalAuthListManagement',
   Reservation = 'Reservation',
   Smart_Charging = 'SmartCharging',
-  Remote_Trigger = 'RemoteTrigger'
+  Remote_Trigger = 'RemoteTrigger',
 }
 
 export enum OCPP16StandardParametersKey {
@@ -51,9 +51,9 @@ export enum OCPP16StandardParametersKey {
   ChargingScheduleAllowedChargingRateUnit = 'ChargingScheduleAllowedChargingRateUnit',
   ChargingScheduleMaxPeriods = 'ChargingScheduleMaxPeriods',
   ConnectorSwitch3to1PhaseSupported = 'ConnectorSwitch3to1PhaseSupported',
-  MaxChargingProfilesInstalled = 'MaxChargingProfilesInstalled'
+  MaxChargingProfilesInstalled = 'MaxChargingProfilesInstalled',
 }
 
 export enum OCPP16VendorDefaultParametersKey {
-  ConnectionUrl = 'ConnectionUrl'
+  ConnectionUrl = 'ConnectionUrl',
 }
index c9feccea5f91a34789f9ced610338d6644e2387d..c8c2c8905d5423a8f81df56117ab9211bf9535f4 100644 (file)
@@ -2,5 +2,5 @@ export enum OCPP16DiagnosticsStatus {
   Idle = 'Idle',
   Uploaded = 'Uploaded',
   UploadFailed = 'UploadFailed',
-  Uploading = 'Uploading'
+  Uploading = 'Uploading',
 }
index 97a7d24c9fd3396a1d7d364fec63c77fa6a347c1..282df11a9ea5d827d8ef40c360f08358d5156220 100644 (file)
@@ -17,7 +17,7 @@ export enum MeterValueUnit {
   TEMP_CELSIUS = 'Celsius',
   TEMP_FAHRENHEIT = 'Fahrenheit',
   TEMP_KELVIN = 'K',
-  PERCENT = 'Percent'
+  PERCENT = 'Percent',
 }
 
 export enum MeterValueContext {
@@ -28,7 +28,7 @@ export enum MeterValueContext {
   SAMPLE_PERIODIC = 'Sample.Periodic',
   TRANSACTION_BEGIN = 'Transaction.Begin',
   TRANSACTION_END = 'Transaction.End',
-  TRIGGER = 'Trigger'
+  TRIGGER = 'Trigger',
 }
 
 export enum OCPP16MeterValueMeasurand {
@@ -53,7 +53,7 @@ export enum OCPP16MeterValueMeasurand {
   FAN_RPM = 'RPM',
   STATE_OF_CHARGE = 'SoC',
   TEMPERATURE = 'Temperature',
-  VOLTAGE = 'Voltage'
+  VOLTAGE = 'Voltage',
 }
 
 export enum MeterValueLocation {
@@ -61,7 +61,7 @@ export enum MeterValueLocation {
   CABLE = 'Cable',
   EV = 'EV',
   INLET = 'Inlet',
-  OUTLET = 'Outlet'
+  OUTLET = 'Outlet',
 }
 
 export enum OCPP16MeterValuePhase {
@@ -74,7 +74,7 @@ export enum OCPP16MeterValuePhase {
   L3_N = 'L3-N',
   L1_L2 = 'L1-L2',
   L2_L3 = 'L2-L3',
-  L3_L1 = 'L3-L1'
+  L3_L1 = 'L3-L1',
 }
 
 export enum MeterValueFormat {
@@ -104,4 +104,3 @@ export interface MeterValuesRequest extends JsonType {
 }
 
 export type MeterValuesResponse = EmptyObject;
-
index 97b5d756e440b9478c573e48762aa9f6a7205456..4b5ff45ca22bb396b1563c5eca7b2fb1ff324798 100644 (file)
@@ -16,7 +16,7 @@ export enum OCPP16RequestCommand {
   START_TRANSACTION = 'StartTransaction',
   STOP_TRANSACTION = 'StopTransaction',
   METER_VALUES = 'MeterValues',
-  DIAGNOSTICS_STATUS_NOTIFICATION = 'DiagnosticsStatusNotification'
+  DIAGNOSTICS_STATUS_NOTIFICATION = 'DiagnosticsStatusNotification',
 }
 
 export enum OCPP16IncomingRequestCommand {
@@ -31,7 +31,7 @@ export enum OCPP16IncomingRequestCommand {
   REMOTE_START_TRANSACTION = 'RemoteStartTransaction',
   REMOTE_STOP_TRANSACTION = 'RemoteStopTransaction',
   GET_DIAGNOSTICS = 'GetDiagnostics',
-  TRIGGER_MESSAGE = 'TriggerMessage'
+  TRIGGER_MESSAGE = 'TriggerMessage',
 }
 
 export type HeartbeatRequest = EmptyObject;
@@ -83,7 +83,7 @@ export interface GetConfigurationRequest extends JsonType {
 
 export enum ResetType {
   HARD = 'Hard',
-  SOFT = 'Soft'
+  SOFT = 'Soft',
 }
 
 export interface ResetRequest extends JsonType {
@@ -97,7 +97,7 @@ export interface SetChargingProfileRequest extends JsonType {
 
 export enum OCPP16AvailabilityType {
   INOPERATIVE = 'Inoperative',
-  OPERATIVE = 'Operative'
+  OPERATIVE = 'Operative',
 }
 
 export interface ChangeAvailabilityRequest extends JsonType {
@@ -121,7 +121,7 @@ export interface GetDiagnosticsRequest extends JsonType {
 }
 
 export interface DiagnosticsStatusNotificationRequest extends JsonType {
-  status: OCPP16DiagnosticsStatus
+  status: OCPP16DiagnosticsStatus;
 }
 
 export enum MessageTrigger {
@@ -130,10 +130,10 @@ export enum MessageTrigger {
   FirmwareStatusNotification = 'FirmwareStatusNotification',
   Heartbeat = 'Heartbeat',
   MeterValues = 'MeterValues',
-  StatusNotification = 'StatusNotification'
+  StatusNotification = 'StatusNotification',
 }
 
 export interface OCPP16TriggerMessageRequest extends JsonType {
   requestedMessage: MessageTrigger;
-  connectorId?: number
+  connectorId?: number;
 }
index 7d3487ba1f8bdc4549e2c9f298a9a111bc4c2a71..d6a5d3470dcd9d07c7385f4ae09cb66f6a3b2291 100644 (file)
@@ -9,7 +9,7 @@ export interface HeartbeatResponse extends JsonType {
 export enum OCPP16UnlockStatus {
   UNLOCKED = 'Unlocked',
   UNLOCK_FAILED = 'UnlockFailed',
-  NOT_SUPPORTED = 'NotSupported'
+  NOT_SUPPORTED = 'NotSupported',
 }
 
 export interface UnlockConnectorResponse extends JsonType {
@@ -20,7 +20,7 @@ export enum OCPP16ConfigurationStatus {
   ACCEPTED = 'Accepted',
   REJECTED = 'Rejected',
   REBOOT_REQUIRED = 'RebootRequired',
-  NOT_SUPPORTED = 'NotSupported'
+  NOT_SUPPORTED = 'NotSupported',
 }
 
 export interface ChangeConfigurationResponse extends JsonType {
@@ -30,7 +30,7 @@ export interface ChangeConfigurationResponse extends JsonType {
 export enum OCPP16RegistrationStatus {
   ACCEPTED = 'Accepted',
   PENDING = 'Pending',
-  REJECTED = 'Rejected'
+  REJECTED = 'Rejected',
 }
 
 export interface OCPP16BootNotificationResponse extends JsonType {
@@ -59,7 +59,7 @@ export interface SetChargingProfileResponse extends JsonType {
 export enum OCPP16AvailabilityStatus {
   ACCEPTED = 'Accepted',
   REJECTED = 'Rejected',
-  SCHEDULED = 'Scheduled'
+  SCHEDULED = 'Scheduled',
 }
 
 export interface ChangeAvailabilityResponse extends JsonType {
@@ -68,7 +68,7 @@ export interface ChangeAvailabilityResponse extends JsonType {
 
 export enum OCPP16ClearChargingProfileStatus {
   ACCEPTED = 'Accepted',
-  UNKNOWN = 'Unknown'
+  UNKNOWN = 'Unknown',
 }
 
 export interface ClearChargingProfileResponse extends JsonType {
@@ -84,9 +84,9 @@ export type DiagnosticsStatusNotificationResponse = EmptyObject;
 export enum OCPP16TriggerMessageStatus {
   ACCEPTED = 'Accepted',
   REJECTED = 'Rejected',
-  NOT_IMPLEMENTED = 'NotImplemented'
+  NOT_IMPLEMENTED = 'NotImplemented',
 }
 
 export interface OCPP16TriggerMessageResponse extends JsonType {
-  status: OCPP16TriggerMessageStatus
+  status: OCPP16TriggerMessageStatus;
 }
index bf2377778bb21e0c6096cb1f33267672f5fe8444..1b921d4ec01cd7aef1d771f8d2917e6038e12496 100644 (file)
@@ -13,7 +13,7 @@ export enum OCPP16StopTransactionReason {
   REMOTE = 'Remote',
   SOFT_RESET = 'SoftReset',
   UNLOCK_COMMAND = 'UnlockCommand',
-  DE_AUTHORIZED = 'DeAuthorized'
+  DE_AUTHORIZED = 'DeAuthorized',
 }
 
 export enum OCPP16AuthorizationStatus {
@@ -21,7 +21,7 @@ export enum OCPP16AuthorizationStatus {
   BLOCKED = 'Blocked',
   EXPIRED = 'Expired',
   INVALID = 'Invalid',
-  CONCURRENT_TX = 'ConcurrentTx'
+  CONCURRENT_TX = 'ConcurrentTx',
 }
 
 export interface IdTagInfo extends JsonType {
index 016e51d9d5d16569b6f775c765497c3cad602f5e..75c5c482982096723c8e69f4aef8ccd91fbfb8d5 100644 (file)
@@ -3,5 +3,5 @@ import { OCPP16ChargePointErrorCode } from './1.6/ChargePointErrorCode';
 export type ChargePointErrorCode = OCPP16ChargePointErrorCode;
 
 export const ChargePointErrorCode = {
-  ...OCPP16ChargePointErrorCode
+  ...OCPP16ChargePointErrorCode,
 };
index daa9779bed14bc3819e855e50e03157ec52565a2..c28fd6efaf7ec69f575130f5391905e6616b2cbb 100644 (file)
@@ -3,5 +3,5 @@ import { OCPP16ChargePointStatus } from './1.6/ChargePointStatus';
 export type ChargePointStatus = OCPP16ChargePointStatus;
 
 export const ChargePointStatus = {
-  ...OCPP16ChargePointStatus
+  ...OCPP16ChargePointStatus,
 };
index b13a24ba2be17c6c04f5c65f10eef3b5c2ed4828..5747663c42d9a414fa252c46800e6c90c5e7e1ca 100644 (file)
@@ -1,23 +1,27 @@
-import { OCPP16StandardParametersKey, OCPP16SupportedFeatureProfiles, OCPP16VendorDefaultParametersKey } from './1.6/Configuration';
+import {
+  OCPP16StandardParametersKey,
+  OCPP16SupportedFeatureProfiles,
+  OCPP16VendorDefaultParametersKey,
+} from './1.6/Configuration';
 
 import { JsonType } from '../JsonType';
 
 export type StandardParametersKey = OCPP16StandardParametersKey;
 
 export const StandardParametersKey = {
-  ...OCPP16StandardParametersKey
+  ...OCPP16StandardParametersKey,
 };
 
 export type VendorDefaultParametersKey = OCPP16VendorDefaultParametersKey;
 
 export const VendorDefaultParametersKey = {
-  ...OCPP16VendorDefaultParametersKey
+  ...OCPP16VendorDefaultParametersKey,
 };
 
 export type SupportedFeatureProfiles = OCPP16SupportedFeatureProfiles;
 
 export const SupportedFeatureProfiles = {
-  ...OCPP16SupportedFeatureProfiles
+  ...OCPP16SupportedFeatureProfiles,
 };
 
 export enum ConnectorPhaseRotation {
@@ -28,7 +32,7 @@ export enum ConnectorPhaseRotation {
   SRT = 'SRT',
   STR = 'STR',
   TRS = 'TRS',
-  TSR = 'TSR'
+  TSR = 'TSR',
 }
 
 export interface OCPPConfigurationKey extends JsonType {
index f2e6e9c05c11dc9c5b03166c1dfd49b6ac7b9f11..2172ec1f925762826eba130ef579abcc7587230a 100644 (file)
@@ -1,15 +1,20 @@
-import { OCPP16MeterValue, OCPP16MeterValueMeasurand, OCPP16MeterValuePhase, OCPP16SampledValue } from './1.6/MeterValues';
+import {
+  OCPP16MeterValue,
+  OCPP16MeterValueMeasurand,
+  OCPP16MeterValuePhase,
+  OCPP16SampledValue,
+} from './1.6/MeterValues';
 
 export type MeterValueMeasurand = OCPP16MeterValueMeasurand;
 
 export const MeterValueMeasurand = {
-  ...OCPP16MeterValueMeasurand
+  ...OCPP16MeterValueMeasurand,
 };
 
 export type MeterValuePhase = OCPP16MeterValuePhase;
 
 export const MeterValuePhase = {
-  ...OCPP16MeterValuePhase
+  ...OCPP16MeterValuePhase,
 };
 
 export type SampledValue = OCPP16SampledValue;
index 1a0d0ffbde9cfb2bd76e36cb8c9afcf565f3ec85..c5c813f22f154ef8349cb854d9718696e3e6956d 100644 (file)
@@ -1,4 +1,9 @@
-import { OCPP16AvailabilityType, OCPP16BootNotificationRequest, OCPP16IncomingRequestCommand, OCPP16RequestCommand } from './1.6/Requests';
+import {
+  OCPP16AvailabilityType,
+  OCPP16BootNotificationRequest,
+  OCPP16IncomingRequestCommand,
+  OCPP16RequestCommand,
+} from './1.6/Requests';
 
 import { JsonType } from '../JsonType';
 import { MessageType } from './MessageType';
@@ -6,8 +11,8 @@ import { OCPP16DiagnosticsStatus } from './1.6/DiagnosticsStatus';
 import OCPPError from '../../exception/OCPPError';
 
 export interface SendParams {
-  skipBufferingOnError?: boolean,
-  triggerMessage?: boolean
+  skipBufferingOnError?: boolean;
+  triggerMessage?: boolean;
 }
 
 export type IncomingRequestHandler = (commandPayload: JsonType) => JsonType | Promise<JsonType>;
@@ -19,29 +24,34 @@ export type BootNotificationRequest = OCPP16BootNotificationRequest;
 export type AvailabilityType = OCPP16AvailabilityType;
 
 export const AvailabilityType = {
-  ...OCPP16AvailabilityType
+  ...OCPP16AvailabilityType,
 };
 
 export type RequestCommand = OCPP16RequestCommand;
 
 export const RequestCommand = {
-  ...OCPP16RequestCommand
+  ...OCPP16RequestCommand,
 };
 
 export type IncomingRequestCommand = OCPP16IncomingRequestCommand;
 
 export const IncomingRequestCommand = {
-  ...OCPP16IncomingRequestCommand
+  ...OCPP16IncomingRequestCommand,
 };
 
 export type DiagnosticsStatus = OCPP16DiagnosticsStatus;
 
 export const DiagnosticsStatus = {
-  ...OCPP16DiagnosticsStatus
+  ...OCPP16DiagnosticsStatus,
 };
 
 export type Request = [MessageType, string, RequestCommand, JsonType, JsonType];
 
 export type IncomingRequest = [MessageType, string, IncomingRequestCommand, JsonType, JsonType];
 
-export type CachedRequest = [(payload: JsonType, requestPayload: JsonType) => void, (error: OCPPError, requestStatistic?: boolean) => void, RequestCommand | IncomingRequestCommand, JsonType | OCPPError];
+export type CachedRequest = [
+  (payload: JsonType, requestPayload: JsonType) => void,
+  (error: OCPPError, requestStatistic?: boolean) => void,
+  RequestCommand | IncomingRequestCommand,
+  JsonType | OCPPError
+];
index 21ddd903aa142cd39f11077879d2352ed2fc3233..50f1d2b134f9b71867ac7eb02b92ae4b11fac827 100644 (file)
@@ -1,14 +1,26 @@
-import { OCPP16AvailabilityStatus, OCPP16BootNotificationResponse, OCPP16ChargingProfileStatus, OCPP16ClearChargingProfileStatus, OCPP16ConfigurationStatus, OCPP16RegistrationStatus, OCPP16TriggerMessageStatus, OCPP16UnlockStatus } from './1.6/Responses';
+import {
+  OCPP16AvailabilityStatus,
+  OCPP16BootNotificationResponse,
+  OCPP16ChargingProfileStatus,
+  OCPP16ClearChargingProfileStatus,
+  OCPP16ConfigurationStatus,
+  OCPP16RegistrationStatus,
+  OCPP16TriggerMessageStatus,
+  OCPP16UnlockStatus,
+} from './1.6/Responses';
 
 import { JsonType } from '../JsonType';
 
-export type ResponseHandler = (payload: JsonType | string, requestPayload?: JsonType) => void | Promise<void>;
+export type ResponseHandler = (
+  payload: JsonType | string,
+  requestPayload?: JsonType
+) => void | Promise<void>;
 
 export type BootNotificationResponse = OCPP16BootNotificationResponse;
 
 export enum DefaultStatus {
   ACCEPTED = 'Accepted',
-  REJECTED = 'Rejected'
+  REJECTED = 'Rejected',
 }
 
 export interface DefaultResponse {
@@ -18,41 +30,41 @@ export interface DefaultResponse {
 export type RegistrationStatus = OCPP16RegistrationStatus;
 
 export const RegistrationStatus = {
-  ...OCPP16RegistrationStatus
+  ...OCPP16RegistrationStatus,
 };
 
 export type AvailabilityStatus = OCPP16AvailabilityStatus;
 
 export const AvailabilityStatus = {
-  ...OCPP16AvailabilityStatus
+  ...OCPP16AvailabilityStatus,
 };
 
 export type ChargingProfileStatus = OCPP16ChargingProfileStatus;
 
 export const ChargingProfileStatus = {
-  ...OCPP16ChargingProfileStatus
+  ...OCPP16ChargingProfileStatus,
 };
 
 export type ClearChargingProfileStatus = OCPP16ClearChargingProfileStatus;
 
 export const ClearChargingProfileStatus = {
-  ...OCPP16ClearChargingProfileStatus
+  ...OCPP16ClearChargingProfileStatus,
 };
 
 export type ConfigurationStatus = OCPP16ConfigurationStatus;
 
 export const ConfigurationStatus = {
-  ...OCPP16ConfigurationStatus
+  ...OCPP16ConfigurationStatus,
 };
 
 export type UnlockStatus = OCPP16UnlockStatus;
 
 export const UnlockStatus = {
-  ...OCPP16UnlockStatus
+  ...OCPP16UnlockStatus,
 };
 
 export type TriggerMessageStatus = OCPP16TriggerMessageStatus;
 
 export const TriggerMessageStatus = {
-  ...OCPP16TriggerMessageStatus
+  ...OCPP16TriggerMessageStatus,
 };
index 83764a21f73e9eb4b8187ccc9fd46eaf50f3e4b1..cee8f3cf6d2663c48f8c78fbd57b843269182757 100644 (file)
@@ -1,4 +1,10 @@
-import { OCPP16AuthorizationStatus, OCPP16AuthorizeResponse, OCPP16StartTransactionResponse, OCPP16StopTransactionReason, OCPP16StopTransactionResponse } from './1.6/Transaction';
+import {
+  OCPP16AuthorizationStatus,
+  OCPP16AuthorizeResponse,
+  OCPP16StartTransactionResponse,
+  OCPP16StopTransactionReason,
+  OCPP16StopTransactionResponse,
+} from './1.6/Transaction';
 
 export type AuthorizationStatus = OCPP16AuthorizationStatus;
 
index a37fa37418fb68014436fa00b3aae59f931f4599..2622fa7217869e20e08ba7ffcc1fbf405cca8869 100644 (file)
@@ -6,49 +6,34 @@ import { PerformanceRecord } from './PerformanceRecord';
 export class PerformanceData {
   // @PrimaryKey()
   // pk!: number;
-
   // @Property()
   // commandName!: string;
-
   // @Property()
   // countRequest!: number;
-
   // @Property()
   // countResponse!: number;
-
   // @Property()
   // countError!: number;
-
   // @Property()
   // countTimeMeasurement!: number;
-
   // @Property()
   // timeMeasurementSeries!: number[];
-
   // @Property()
   // currentTimeMeasurement!: number;
-
   // @Property()
   // minTimeMeasurement!: number;
-
   // @Property()
   // maxTimeMeasurement!: number;
-
   // @Property()
   // totalTimeMeasurement!: number;
-
   // @Property()
   // avgTimeMeasurement!: number;
-
   // @Property()
   // medTimeMeasurement!: number;
-
   // @Property()
   // ninetyFiveThPercentileTimeMeasurement!: number;
-
   // @Property()
   // stdDevTimeMeasurement!: number;
-
   // @ManyToOne('PerformanceRecord')
   // performanceRecord!: PerformanceRecord;
 }
index c0d2ab800d3ab63b5d09fc851f397a506cd0b714..81ee84b7f6002aa0b4de5e90e237a4acbf8d2dac 100644 (file)
@@ -6,20 +6,14 @@ import { PerformanceData } from './PerformanceData';
 export class PerformanceRecord {
   // @PrimaryKey()
   // pk!: number;
-
   // @Property()
   // id!: string;
-
   // @Property()
   // URI!: string;
-
   // @Property()
   // createdAt!: Date;
-
   // @Property()
   // updatedAt?: Date;
-
   // @OneToMany('PerformanceData', 'performanceRecord')
   // performanceData?= new Collection<PerformanceData>(this);
 }
-
index feb5e3e2b66fb99aef38c6d24db1a6c5eafccfe1..0eccfa47e37a525ecb9b8b234dc0270f9110990c 100644 (file)
@@ -32,9 +32,7 @@ export class CircularArray<T> extends Array<T> {
   }
 
   public concat(...items: (T | ConcatArray<T>)[]): CircularArray<T> {
-    const concatenatedCircularArray = super.concat(
-      items as T[]
-    ) as CircularArray<T>;
+    const concatenatedCircularArray = super.concat(items as T[]) as CircularArray<T>;
     concatenatedCircularArray.size = this.size;
     if (concatenatedCircularArray.length > concatenatedCircularArray.size) {
       concatenatedCircularArray.splice(
index 57d17c8fa349feca795e97ebec538baac1815c30..5770d76e35ae546150ba2bf6cfe6951d5055aca1 100644 (file)
@@ -1,4 +1,9 @@
-import ConfigurationData, { StationTemplateUrl, StorageConfiguration, SupervisionUrlDistribution, UIWebSocketServerConfiguration } from '../types/ConfigurationData';
+import ConfigurationData, {
+  StationTemplateUrl,
+  StorageConfiguration,
+  SupervisionUrlDistribution,
+  UIWebSocketServerConfiguration,
+} from '../types/ConfigurationData';
 
 import Constants from './Constants';
 import { EmptyObject } from '../types/EmptyObject';
@@ -12,7 +17,11 @@ import fs from 'fs';
 import path from 'path';
 
 export default class Configuration {
-  private static configurationFilePath = path.join(path.resolve(__dirname, '../'), 'assets', 'config.json');
+  private static configurationFilePath = path.join(
+    path.resolve(__dirname, '../'),
+    'assets',
+    'config.json'
+  );
   private static configurationFileWatcher: fs.FSWatcher;
   private static configuration: ConfigurationData | null = null;
   private static configurationChangeCallback: () => Promise<void>;
@@ -22,61 +31,101 @@ export default class Configuration {
   }
 
   static getLogStatisticsInterval(): number {
-    Configuration.warnDeprecatedConfigurationKey('statisticsDisplayInterval', null, 'Use \'logStatisticsInterval\' instead');
+    Configuration.warnDeprecatedConfigurationKey(
+      'statisticsDisplayInterval',
+      null,
+      "Use 'logStatisticsInterval' instead"
+    );
     // Read conf
-    return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'logStatisticsInterval') ? Configuration.getConfig().logStatisticsInterval : 60;
+    return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'logStatisticsInterval')
+      ? Configuration.getConfig().logStatisticsInterval
+      : 60;
   }
 
   static getUIWebSocketServer(): UIWebSocketServerConfiguration {
     let options: ServerOptions = {
       host: Constants.DEFAULT_UI_WEBSOCKET_SERVER_HOST,
-      port: Constants.DEFAULT_UI_WEBSOCKET_SERVER_PORT
+      port: Constants.DEFAULT_UI_WEBSOCKET_SERVER_PORT,
     };
     let uiWebSocketServerConfiguration: UIWebSocketServerConfiguration = {
       enabled: true,
-      options
+      options,
     };
     if (Configuration.objectHasOwnProperty(Configuration.getConfig(), 'uiWebSocketServer')) {
-      if (Configuration.objectHasOwnProperty(Configuration.getConfig().uiWebSocketServer, 'options')) {
+      if (
+        Configuration.objectHasOwnProperty(Configuration.getConfig().uiWebSocketServer, 'options')
+      ) {
         options = {
           ...options,
-          ...Configuration.objectHasOwnProperty(Configuration.getConfig().uiWebSocketServer.options, 'host') && { host: Configuration.getConfig().uiWebSocketServer.options.host },
-          ...Configuration.objectHasOwnProperty(Configuration.getConfig().uiWebSocketServer.options, 'port') && { port: Configuration.getConfig().uiWebSocketServer.options.port }
+          ...(Configuration.objectHasOwnProperty(
+            Configuration.getConfig().uiWebSocketServer.options,
+            'host'
+          ) && { host: Configuration.getConfig().uiWebSocketServer.options.host }),
+          ...(Configuration.objectHasOwnProperty(
+            Configuration.getConfig().uiWebSocketServer.options,
+            'port'
+          ) && { port: Configuration.getConfig().uiWebSocketServer.options.port }),
         };
       }
-      uiWebSocketServerConfiguration =
-      {
+      uiWebSocketServerConfiguration = {
         ...uiWebSocketServerConfiguration,
-        ...Configuration.objectHasOwnProperty(Configuration.getConfig().uiWebSocketServer, 'enabled') && { enabled: Configuration.getConfig().uiWebSocketServer.enabled },
-        options
+        ...(Configuration.objectHasOwnProperty(
+          Configuration.getConfig().uiWebSocketServer,
+          'enabled'
+        ) && { enabled: Configuration.getConfig().uiWebSocketServer.enabled }),
+        options,
       };
     }
     return uiWebSocketServerConfiguration;
   }
 
   static getPerformanceStorage(): StorageConfiguration {
-    Configuration.warnDeprecatedConfigurationKey('URI', 'performanceStorage', 'Use \'uri\' instead');
+    Configuration.warnDeprecatedConfigurationKey('URI', 'performanceStorage', "Use 'uri' instead");
     let storageConfiguration: StorageConfiguration = {
       enabled: false,
       type: StorageType.JSON_FILE,
-      uri: this.getDefaultPerformanceStorageUri(StorageType.JSON_FILE)
+      uri: this.getDefaultPerformanceStorageUri(StorageType.JSON_FILE),
     };
     if (Configuration.objectHasOwnProperty(Configuration.getConfig(), 'performanceStorage')) {
-      storageConfiguration =
-      {
+      storageConfiguration = {
         ...storageConfiguration,
-        ...Configuration.objectHasOwnProperty(Configuration.getConfig().performanceStorage, 'enabled') && { enabled: Configuration.getConfig().performanceStorage.enabled },
-        ...Configuration.objectHasOwnProperty(Configuration.getConfig().performanceStorage, 'type') && { type: Configuration.getConfig().performanceStorage.type },
-        ...Configuration.objectHasOwnProperty(Configuration.getConfig().performanceStorage, 'uri') && { uri: this.getDefaultPerformanceStorageUri(Configuration.getConfig()?.performanceStorage?.type ?? StorageType.JSON_FILE) }
+        ...(Configuration.objectHasOwnProperty(
+          Configuration.getConfig().performanceStorage,
+          'enabled'
+        ) && { enabled: Configuration.getConfig().performanceStorage.enabled }),
+        ...(Configuration.objectHasOwnProperty(
+          Configuration.getConfig().performanceStorage,
+          'type'
+        ) && { type: Configuration.getConfig().performanceStorage.type }),
+        ...(Configuration.objectHasOwnProperty(
+          Configuration.getConfig().performanceStorage,
+          'uri'
+        ) && {
+          uri: this.getDefaultPerformanceStorageUri(
+            Configuration.getConfig()?.performanceStorage?.type ?? StorageType.JSON_FILE
+          ),
+        }),
       };
     }
     return storageConfiguration;
   }
 
   static getAutoReconnectMaxRetries(): number {
-    Configuration.warnDeprecatedConfigurationKey('autoReconnectTimeout', null, 'Use \'ConnectionTimeOut\' OCPP parameter in charging station template instead');
-    Configuration.warnDeprecatedConfigurationKey('connectionTimeout', null, 'Use \'ConnectionTimeOut\' OCPP parameter in charging station template instead');
-    Configuration.warnDeprecatedConfigurationKey('autoReconnectMaxRetries', null, 'Use it in charging station template instead');
+    Configuration.warnDeprecatedConfigurationKey(
+      'autoReconnectTimeout',
+      null,
+      "Use 'ConnectionTimeOut' OCPP parameter in charging station template instead"
+    );
+    Configuration.warnDeprecatedConfigurationKey(
+      'connectionTimeout',
+      null,
+      "Use 'ConnectionTimeOut' OCPP parameter in charging station template instead"
+    );
+    Configuration.warnDeprecatedConfigurationKey(
+      'autoReconnectMaxRetries',
+      null,
+      'Use it in charging station template instead'
+    );
     // Read conf
     if (Configuration.objectHasOwnProperty(Configuration.getConfig(), 'autoReconnectMaxRetries')) {
       return Configuration.getConfig().autoReconnectMaxRetries;
@@ -84,11 +133,22 @@ export default class Configuration {
   }
 
   static getStationTemplateUrls(): StationTemplateUrl[] {
-    Configuration.warnDeprecatedConfigurationKey('stationTemplateURLs', null, 'Use \'stationTemplateUrls\' instead');
-    !Configuration.isUndefined(Configuration.getConfig()['stationTemplateURLs']) && (Configuration.getConfig().stationTemplateUrls = Configuration.getConfig()['stationTemplateURLs'] as StationTemplateUrl[]);
+    Configuration.warnDeprecatedConfigurationKey(
+      'stationTemplateURLs',
+      null,
+      "Use 'stationTemplateUrls' instead"
+    );
+    !Configuration.isUndefined(Configuration.getConfig()['stationTemplateURLs']) &&
+      (Configuration.getConfig().stationTemplateUrls = Configuration.getConfig()[
+        'stationTemplateURLs'
+      ] as StationTemplateUrl[]);
     Configuration.getConfig().stationTemplateUrls.forEach((stationUrl: StationTemplateUrl) => {
       if (!Configuration.isUndefined(stationUrl['numberOfStation'])) {
-        console.error(chalk`{green ${Configuration.logPrefix()}} {red Deprecated configuration key 'numberOfStation' usage for template file '${stationUrl.file}' in 'stationTemplateUrls'. Use 'numberOfStations' instead}`);
+        console.error(
+          chalk`{green ${Configuration.logPrefix()}} {red Deprecated configuration key 'numberOfStation' usage for template file '${
+            stationUrl.file
+          }' in 'stationTemplateUrls'. Use 'numberOfStations' instead}`
+        );
       }
     });
     // Read conf
@@ -96,25 +156,43 @@ export default class Configuration {
   }
 
   static getWorkerProcess(): WorkerProcessType {
-    Configuration.warnDeprecatedConfigurationKey('useWorkerPool;', null, 'Use \'workerProcess\' to define the type of worker process to use instead');
-    return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'workerProcess') ? Configuration.getConfig().workerProcess : WorkerProcessType.WORKER_SET;
+    Configuration.warnDeprecatedConfigurationKey(
+      'useWorkerPool;',
+      null,
+      "Use 'workerProcess' to define the type of worker process to use instead"
+    );
+    return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'workerProcess')
+      ? Configuration.getConfig().workerProcess
+      : WorkerProcessType.WORKER_SET;
   }
 
   static getWorkerStartDelay(): number {
-    return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'workerStartDelay') ? Configuration.getConfig().workerStartDelay : Constants.WORKER_START_DELAY;
+    return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'workerStartDelay')
+      ? Configuration.getConfig().workerStartDelay
+      : Constants.WORKER_START_DELAY;
   }
 
   static getElementStartDelay(): number {
-    return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'elementStartDelay') ? Configuration.getConfig().elementStartDelay : Constants.ELEMENT_START_DELAY;
+    return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'elementStartDelay')
+      ? Configuration.getConfig().elementStartDelay
+      : Constants.ELEMENT_START_DELAY;
   }
 
   static getWorkerPoolMinSize(): number {
-    return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'workerPoolMinSize') ? Configuration.getConfig().workerPoolMinSize : Constants.DEFAULT_WORKER_POOL_MIN_SIZE;
+    return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'workerPoolMinSize')
+      ? Configuration.getConfig().workerPoolMinSize
+      : Constants.DEFAULT_WORKER_POOL_MIN_SIZE;
   }
 
   static getWorkerPoolMaxSize(): number {
-    Configuration.warnDeprecatedConfigurationKey('workerPoolSize;', null, 'Use \'workerPoolMaxSize\' instead');
-    return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'workerPoolMaxSize') ? Configuration.getConfig().workerPoolMaxSize : Constants.DEFAULT_WORKER_POOL_MAX_SIZE;
+    Configuration.warnDeprecatedConfigurationKey(
+      'workerPoolSize;',
+      null,
+      "Use 'workerPoolMaxSize' instead"
+    );
+    return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'workerPoolMaxSize')
+      ? Configuration.getConfig().workerPoolMaxSize
+      : Constants.DEFAULT_WORKER_POOL_MAX_SIZE;
   }
 
   static getWorkerPoolStrategy(): WorkerChoiceStrategy {
@@ -122,62 +200,117 @@ export default class Configuration {
   }
 
   static getChargingStationsPerWorker(): number {
-    return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'chargingStationsPerWorker') ? Configuration.getConfig().chargingStationsPerWorker : Constants.DEFAULT_CHARGING_STATIONS_PER_WORKER;
+    return Configuration.objectHasOwnProperty(
+      Configuration.getConfig(),
+      'chargingStationsPerWorker'
+    )
+      ? Configuration.getConfig().chargingStationsPerWorker
+      : Constants.DEFAULT_CHARGING_STATIONS_PER_WORKER;
   }
 
   static getLogConsole(): boolean {
-    Configuration.warnDeprecatedConfigurationKey('consoleLog', null, 'Use \'logConsole\' instead');
-    return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'logConsole') ? Configuration.getConfig().logConsole : false;
+    Configuration.warnDeprecatedConfigurationKey('consoleLog', null, "Use 'logConsole' instead");
+    return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'logConsole')
+      ? Configuration.getConfig().logConsole
+      : false;
   }
 
   static getLogFormat(): string {
-    return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'logFormat') ? Configuration.getConfig().logFormat : 'simple';
+    return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'logFormat')
+      ? Configuration.getConfig().logFormat
+      : 'simple';
   }
 
   static getLogRotate(): boolean {
-    return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'logRotate') ? Configuration.getConfig().logRotate : true;
+    return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'logRotate')
+      ? Configuration.getConfig().logRotate
+      : true;
   }
 
   static getLogMaxFiles(): number {
-    return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'logMaxFiles') ? Configuration.getConfig().logMaxFiles : 7;
+    return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'logMaxFiles')
+      ? Configuration.getConfig().logMaxFiles
+      : 7;
   }
 
   static getLogLevel(): string {
-    return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'logLevel') ? Configuration.getConfig().logLevel.toLowerCase() : 'info';
+    return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'logLevel')
+      ? Configuration.getConfig().logLevel.toLowerCase()
+      : 'info';
   }
 
   static getLogFile(): string {
-    return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'logFile') ? Configuration.getConfig().logFile : 'combined.log';
+    return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'logFile')
+      ? Configuration.getConfig().logFile
+      : 'combined.log';
   }
 
   static getLogErrorFile(): string {
-    Configuration.warnDeprecatedConfigurationKey('errorFile', null, 'Use \'logErrorFile\' instead');
-    return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'logErrorFile') ? Configuration.getConfig().logErrorFile : 'error.log';
+    Configuration.warnDeprecatedConfigurationKey('errorFile', null, "Use 'logErrorFile' instead");
+    return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'logErrorFile')
+      ? Configuration.getConfig().logErrorFile
+      : 'error.log';
   }
 
   static getSupervisionUrls(): string | string[] {
-    Configuration.warnDeprecatedConfigurationKey('supervisionURLs', null, 'Use \'supervisionUrls\' instead');
-    !Configuration.isUndefined(Configuration.getConfig()['supervisionURLs']) && (Configuration.getConfig().supervisionUrls = Configuration.getConfig()['supervisionURLs'] as string[]);
+    Configuration.warnDeprecatedConfigurationKey(
+      'supervisionURLs',
+      null,
+      "Use 'supervisionUrls' instead"
+    );
+    !Configuration.isUndefined(Configuration.getConfig()['supervisionURLs']) &&
+      (Configuration.getConfig().supervisionUrls = Configuration.getConfig()[
+        'supervisionURLs'
+      ] as string[]);
     // Read conf
     return Configuration.getConfig().supervisionUrls;
   }
 
   static getSupervisionUrlDistribution(): SupervisionUrlDistribution {
-    Configuration.warnDeprecatedConfigurationKey('distributeStationToTenantEqually', null, 'Use \'supervisionUrlDistribution\' instead');
-    Configuration.warnDeprecatedConfigurationKey('distributeStationsToTenantsEqually', null, 'Use \'supervisionUrlDistribution\' instead');
-    return Configuration.objectHasOwnProperty(Configuration.getConfig(), 'supervisionUrlDistribution') ? Configuration.getConfig().supervisionUrlDistribution : SupervisionUrlDistribution.ROUND_ROBIN;
+    Configuration.warnDeprecatedConfigurationKey(
+      'distributeStationToTenantEqually',
+      null,
+      "Use 'supervisionUrlDistribution' instead"
+    );
+    Configuration.warnDeprecatedConfigurationKey(
+      'distributeStationsToTenantsEqually',
+      null,
+      "Use 'supervisionUrlDistribution' instead"
+    );
+    return Configuration.objectHasOwnProperty(
+      Configuration.getConfig(),
+      'supervisionUrlDistribution'
+    )
+      ? Configuration.getConfig().supervisionUrlDistribution
+      : SupervisionUrlDistribution.ROUND_ROBIN;
   }
 
   private static logPrefix(): string {
     return new Date().toLocaleString() + ' Simulator configuration |';
   }
 
-  private static warnDeprecatedConfigurationKey(key: string, sectionName?: string, logMsgToAppend = '') {
+  private static warnDeprecatedConfigurationKey(
+    key: string,
+    sectionName?: string,
+    logMsgToAppend = ''
+  ) {
     // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
-    if (sectionName && !Configuration.isUndefined(Configuration.getConfig()[sectionName]) && !Configuration.isUndefined(Configuration.getConfig()[sectionName][key])) {
-      console.error(chalk`{green ${Configuration.logPrefix()}} {red Deprecated configuration key '${key}' usage in section '${sectionName}'${logMsgToAppend && '. ' + logMsgToAppend}}`);
+    if (
+      sectionName &&
+      !Configuration.isUndefined(Configuration.getConfig()[sectionName]) &&
+      !Configuration.isUndefined(Configuration.getConfig()[sectionName][key])
+    ) {
+      console.error(
+        chalk`{green ${Configuration.logPrefix()}} {red Deprecated configuration key '${key}' usage in section '${sectionName}'${
+          logMsgToAppend && '. ' + logMsgToAppend
+        }}`
+      );
     } else if (!Configuration.isUndefined(Configuration.getConfig()[key])) {
-      console.error(chalk`{green ${Configuration.logPrefix()}} {red Deprecated configuration key '${key}' usage${logMsgToAppend && '. ' + logMsgToAppend}}`);
+      console.error(
+        chalk`{green ${Configuration.logPrefix()}} {red Deprecated configuration key '${key}' usage${
+          logMsgToAppend && '. ' + logMsgToAppend
+        }}`
+      );
     }
   }
 
@@ -185,9 +318,16 @@ export default class Configuration {
   private static getConfig(): ConfigurationData {
     if (!Configuration.configuration) {
       try {
-        Configuration.configuration = JSON.parse(fs.readFileSync(Configuration.configurationFilePath, 'utf8')) as ConfigurationData;
+        Configuration.configuration = JSON.parse(
+          fs.readFileSync(Configuration.configurationFilePath, 'utf8')
+        ) as ConfigurationData;
       } catch (error) {
-        Configuration.handleFileException(Configuration.logPrefix(), 'Configuration', Configuration.configurationFilePath, error);
+        Configuration.handleFileException(
+          Configuration.logPrefix(),
+          'Configuration',
+          Configuration.configurationFilePath,
+          error
+        );
       }
       if (!Configuration.configurationFileWatcher) {
         Configuration.configurationFileWatcher = Configuration.getConfigurationFileWatcher();
@@ -210,7 +350,12 @@ export default class Configuration {
         }
       });
     } catch (error) {
-      Configuration.handleFileException(Configuration.logPrefix(), 'Configuration', Configuration.configurationFilePath, error as Error);
+      Configuration.handleFileException(
+        Configuration.logPrefix(),
+        'Configuration',
+        Configuration.configurationFilePath,
+        error as Error
+      );
     }
   }
 
@@ -218,7 +363,10 @@ export default class Configuration {
     const SQLiteFileName = `${Constants.DEFAULT_PERFORMANCE_RECORDS_DB_NAME}.db`;
     switch (storageType) {
       case StorageType.JSON_FILE:
-        return `file://${path.join(path.resolve(__dirname, '../../'), Constants.DEFAULT_PERFORMANCE_RECORDS_FILENAME)}`;
+        return `file://${path.join(
+          path.resolve(__dirname, '../../'),
+          Constants.DEFAULT_PERFORMANCE_RECORDS_FILENAME
+        )}`;
       case StorageType.SQLITE:
         return `file://${path.join(path.resolve(__dirname, '../../'), SQLiteFileName)}`;
       default:
@@ -234,17 +382,34 @@ export default class Configuration {
     return typeof obj === 'undefined';
   }
 
-  private static handleFileException(logPrefix: string, fileType: string, filePath: string, error: NodeJS.ErrnoException,
-      params: HandleErrorParams<EmptyObject> = { throwError: true }): void {
+  private static handleFileException(
+    logPrefix: string,
+    fileType: string,
+    filePath: string,
+    error: NodeJS.ErrnoException,
+    params: HandleErrorParams<EmptyObject> = { throwError: true }
+  ): void {
     const prefix = logPrefix.length !== 0 ? logPrefix + ' ' : '';
     if (error.code === 'ENOENT') {
-      console.error(chalk.green(prefix) + chalk.red(fileType + ' file ' + filePath + ' not found: '), error);
+      console.error(
+        chalk.green(prefix) + chalk.red(fileType + ' file ' + filePath + ' not found: '),
+        error
+      );
     } else if (error.code === 'EEXIST') {
-      console.error(chalk.green(prefix) + chalk.red(fileType + ' file ' + filePath + ' already exists: '), error);
+      console.error(
+        chalk.green(prefix) + chalk.red(fileType + ' file ' + filePath + ' already exists: '),
+        error
+      );
     } else if (error.code === 'EACCES') {
-      console.error(chalk.green(prefix) + chalk.red(fileType + ' file ' + filePath + ' access denied: '), error);
+      console.error(
+        chalk.green(prefix) + chalk.red(fileType + ' file ' + filePath + ' access denied: '),
+        error
+      );
     } else {
-      console.error(chalk.green(prefix) + chalk.red(fileType + ' file ' + filePath + ' error: '), error);
+      console.error(
+        chalk.green(prefix) + chalk.red(fileType + ' file ' + filePath + ' error: '),
+        error
+      );
     }
     if (params?.throwError) {
       throw error;
index 59a419971c5de0810565e6b607b83f7160a96c8d..968de2d031ab1e20fbe1e5093291a21a6328905b 100644 (file)
@@ -1,4 +1,12 @@
-import { AvailabilityStatus, ChargingProfileStatus, ClearChargingProfileStatus, ConfigurationStatus, DefaultStatus, TriggerMessageStatus, UnlockStatus } from '../types/ocpp/Responses';
+import {
+  AvailabilityStatus,
+  ChargingProfileStatus,
+  ClearChargingProfileStatus,
+  ConfigurationStatus,
+  DefaultStatus,
+  TriggerMessageStatus,
+  UnlockStatus,
+} from '../types/ocpp/Responses';
 
 import { MeterValueMeasurand } from '../types/ocpp/MeterValues';
 
@@ -6,24 +14,58 @@ export default class Constants {
   static readonly OCPP_RESPONSE_EMPTY = Object.freeze({});
   static readonly OCPP_RESPONSE_ACCEPTED = Object.freeze({ status: DefaultStatus.ACCEPTED });
   static readonly OCPP_RESPONSE_REJECTED = Object.freeze({ status: DefaultStatus.REJECTED });
-  static readonly OCPP_CONFIGURATION_RESPONSE_ACCEPTED = Object.freeze({ status: ConfigurationStatus.ACCEPTED });
-  static readonly OCPP_CONFIGURATION_RESPONSE_REJECTED = Object.freeze({ status: ConfigurationStatus.REJECTED });
-  static readonly OCPP_CONFIGURATION_RESPONSE_REBOOT_REQUIRED = Object.freeze({ status: ConfigurationStatus.REBOOT_REQUIRED });
-  static readonly OCPP_CONFIGURATION_RESPONSE_NOT_SUPPORTED = Object.freeze({ status: ConfigurationStatus.NOT_SUPPORTED });
-  static readonly OCPP_SET_CHARGING_PROFILE_RESPONSE_ACCEPTED = Object.freeze({ status: ChargingProfileStatus.ACCEPTED });
-  static readonly OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED = Object.freeze({ status: ChargingProfileStatus.REJECTED });
-  static readonly OCPP_SET_CHARGING_PROFILE_RESPONSE_NOT_SUPPORTED = Object.freeze({ status: ChargingProfileStatus.NOT_SUPPORTED });
-  static readonly OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_ACCEPTED = Object.freeze({ status: ClearChargingProfileStatus.ACCEPTED });
-  static readonly OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN = Object.freeze({ status: ClearChargingProfileStatus.UNKNOWN });
+  static readonly OCPP_CONFIGURATION_RESPONSE_ACCEPTED = Object.freeze({
+    status: ConfigurationStatus.ACCEPTED,
+  });
+  static readonly OCPP_CONFIGURATION_RESPONSE_REJECTED = Object.freeze({
+    status: ConfigurationStatus.REJECTED,
+  });
+  static readonly OCPP_CONFIGURATION_RESPONSE_REBOOT_REQUIRED = Object.freeze({
+    status: ConfigurationStatus.REBOOT_REQUIRED,
+  });
+  static readonly OCPP_CONFIGURATION_RESPONSE_NOT_SUPPORTED = Object.freeze({
+    status: ConfigurationStatus.NOT_SUPPORTED,
+  });
+  static readonly OCPP_SET_CHARGING_PROFILE_RESPONSE_ACCEPTED = Object.freeze({
+    status: ChargingProfileStatus.ACCEPTED,
+  });
+  static readonly OCPP_SET_CHARGING_PROFILE_RESPONSE_REJECTED = Object.freeze({
+    status: ChargingProfileStatus.REJECTED,
+  });
+  static readonly OCPP_SET_CHARGING_PROFILE_RESPONSE_NOT_SUPPORTED = Object.freeze({
+    status: ChargingProfileStatus.NOT_SUPPORTED,
+  });
+  static readonly OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_ACCEPTED = Object.freeze({
+    status: ClearChargingProfileStatus.ACCEPTED,
+  });
+  static readonly OCPP_CLEAR_CHARGING_PROFILE_RESPONSE_UNKNOWN = Object.freeze({
+    status: ClearChargingProfileStatus.UNKNOWN,
+  });
   static readonly OCPP_RESPONSE_UNLOCKED = Object.freeze({ status: UnlockStatus.UNLOCKED });
-  static readonly OCPP_RESPONSE_UNLOCK_FAILED = Object.freeze({ status: UnlockStatus.UNLOCK_FAILED });
-  static readonly OCPP_RESPONSE_UNLOCK_NOT_SUPPORTED = Object.freeze({ status: UnlockStatus.NOT_SUPPORTED });
-  static readonly OCPP_AVAILABILITY_RESPONSE_ACCEPTED = Object.freeze({ status: AvailabilityStatus.ACCEPTED });
-  static readonly OCPP_AVAILABILITY_RESPONSE_REJECTED = Object.freeze({ status: AvailabilityStatus.REJECTED });
-  static readonly OCPP_AVAILABILITY_RESPONSE_SCHEDULED = Object.freeze({ status: AvailabilityStatus.SCHEDULED });
-  static readonly OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED = Object.freeze({ status: TriggerMessageStatus.ACCEPTED });
-  static readonly OCPP_TRIGGER_MESSAGE_RESPONSE_REJECTED = Object.freeze({ status: TriggerMessageStatus.REJECTED });
-  static readonly OCPP_TRIGGER_MESSAGE_RESPONSE_NOT_IMPLEMENTED = Object.freeze({ status: TriggerMessageStatus.NOT_IMPLEMENTED });
+  static readonly OCPP_RESPONSE_UNLOCK_FAILED = Object.freeze({
+    status: UnlockStatus.UNLOCK_FAILED,
+  });
+  static readonly OCPP_RESPONSE_UNLOCK_NOT_SUPPORTED = Object.freeze({
+    status: UnlockStatus.NOT_SUPPORTED,
+  });
+  static readonly OCPP_AVAILABILITY_RESPONSE_ACCEPTED = Object.freeze({
+    status: AvailabilityStatus.ACCEPTED,
+  });
+  static readonly OCPP_AVAILABILITY_RESPONSE_REJECTED = Object.freeze({
+    status: AvailabilityStatus.REJECTED,
+  });
+  static readonly OCPP_AVAILABILITY_RESPONSE_SCHEDULED = Object.freeze({
+    status: AvailabilityStatus.SCHEDULED,
+  });
+  static readonly OCPP_TRIGGER_MESSAGE_RESPONSE_ACCEPTED = Object.freeze({
+    status: TriggerMessageStatus.ACCEPTED,
+  });
+  static readonly OCPP_TRIGGER_MESSAGE_RESPONSE_REJECTED = Object.freeze({
+    status: TriggerMessageStatus.REJECTED,
+  });
+  static readonly OCPP_TRIGGER_MESSAGE_RESPONSE_NOT_IMPLEMENTED = Object.freeze({
+    status: TriggerMessageStatus.NOT_IMPLEMENTED,
+  });
 
   static readonly OCPP_DEFAULT_BOOT_NOTIFICATION_INTERVAL = 60000; // Ms
   static readonly OCPP_WEBSOCKET_TIMEOUT = 60000; // Ms
@@ -51,7 +93,7 @@ export default class Constants {
     MeterValueMeasurand.VOLTAGE,
     MeterValueMeasurand.POWER_ACTIVE_IMPORT,
     MeterValueMeasurand.CURRENT_IMPORT,
-    MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER
+    MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER,
   ]);
 
   static readonly DEFAULT_FLUCTUATION_PERCENT = 5;
index 014ebbdece21cf9a3c9b512573faf95c741693f1..0e8efc61e38cf593143a085631adb5f2b8db2efe 100644 (file)
@@ -4,30 +4,47 @@ import chalk from 'chalk';
 import logger from './Logger';
 
 export default class FileUtils {
-  static handleFileException(logPrefix: string, fileType: string, filePath: string, error: NodeJS.ErrnoException,
-      params: HandleErrorParams<EmptyObject> = { throwError: true, consoleOut: false }): void {
+  static handleFileException(
+    logPrefix: string,
+    fileType: string,
+    filePath: string,
+    error: NodeJS.ErrnoException,
+    params: HandleErrorParams<EmptyObject> = { throwError: true, consoleOut: false }
+  ): void {
     const prefix = logPrefix.length !== 0 ? logPrefix + ' ' : '';
     if (error.code === 'ENOENT') {
       if (params?.consoleOut) {
-        console.warn(chalk.green(prefix) + chalk.yellow(fileType + ' file ' + filePath + ' not found: '), error);
+        console.warn(
+          chalk.green(prefix) + chalk.yellow(fileType + ' file ' + filePath + ' not found: '),
+          error
+        );
       } else {
         logger.warn(prefix + fileType + ' file ' + filePath + ' not found: %j', error);
       }
     } else if (error.code === 'EEXIST') {
       if (params?.consoleOut) {
-        console.warn(chalk.green(prefix) + chalk.yellow(fileType + ' file ' + filePath + ' already exists: '), error);
+        console.warn(
+          chalk.green(prefix) + chalk.yellow(fileType + ' file ' + filePath + ' already exists: '),
+          error
+        );
       } else {
         logger.warn(prefix + fileType + ' file ' + filePath + ' already exists: %j', error);
       }
     } else if (error.code === 'EACCES') {
       if (params?.consoleOut) {
-        console.warn(chalk.green(prefix) + chalk.yellow(fileType + ' file ' + filePath + ' access denied: '), error);
+        console.warn(
+          chalk.green(prefix) + chalk.yellow(fileType + ' file ' + filePath + ' access denied: '),
+          error
+        );
       } else {
         logger.warn(prefix + fileType + ' file ' + filePath + ' access denied: %j', error);
       }
     } else {
       if (params?.consoleOut) {
-        console.warn(chalk.green(prefix) + chalk.yellow(fileType + ' file ' + filePath + ' error: '), error);
+        console.warn(
+          chalk.green(prefix) + chalk.yellow(fileType + ' file ' + filePath + ' error: '),
+          error
+        );
       } else {
         logger.warn(prefix + fileType + ' file ' + filePath + ' error: %j', error);
       }
index ccbc63cade75a2753793c4669b4fbcfb49dafafc..a72bcbe6db3bfbbb8042afd93b64ba91a3546224 100644 (file)
@@ -9,8 +9,23 @@ let transports: transport[];
 if (Configuration.getLogRotate()) {
   const logMaxFiles = Configuration.getLogMaxFiles();
   transports = [
-    new DailyRotateFile({ filename: Utils.insertAt(Configuration.getLogErrorFile(), '-%DATE%', Configuration.getLogErrorFile().indexOf('.log')), level: 'error', maxFiles: logMaxFiles }),
-    new DailyRotateFile({ filename: Utils.insertAt(Configuration.getLogFile(), '-%DATE%', Configuration.getLogFile().indexOf('.log')), maxFiles: logMaxFiles }),
+    new DailyRotateFile({
+      filename: Utils.insertAt(
+        Configuration.getLogErrorFile(),
+        '-%DATE%',
+        Configuration.getLogErrorFile().indexOf('.log')
+      ),
+      level: 'error',
+      maxFiles: logMaxFiles,
+    }),
+    new DailyRotateFile({
+      filename: Utils.insertAt(
+        Configuration.getLogFile(),
+        '-%DATE%',
+        Configuration.getLogFile().indexOf('.log')
+      ),
+      maxFiles: logMaxFiles,
+    }),
   ];
 } else {
   transports = [
@@ -30,9 +45,11 @@ const logger: Logger = createLogger({
 // `${info.level}: ${info.message} JSON.stringify({ ...rest }) `
 //
 if (Configuration.getLogConsole()) {
-  logger.add(new Console({
-    format: format.combine(format.splat(), format[Configuration.getLogFormat()]()),
-  }));
+  logger.add(
+    new Console({
+      format: format.combine(format.splat(), format[Configuration.getLogFormat()]()),
+    })
+  );
 }
 
 export default logger;
index fb8aebfe0dae72f3415c3ab9f7c9d3cb08e68471..4fb2ce7bd2e5482a431b608f777e6b05475035f9 100644 (file)
@@ -20,8 +20,8 @@ export default class Utils {
   public static formatDurationMilliSeconds(duration: number): string {
     duration = Utils.convertToInt(duration);
     const hours = Math.floor(duration / (3600 * 1000));
-    const minutes = Math.floor((duration / 1000 - (hours * 3600)) / 60);
-    const seconds = duration / 1000 - (hours * 3600) - (minutes * 60);
+    const minutes = Math.floor((duration / 1000 - hours * 3600) / 60);
+    const seconds = duration / 1000 - hours * 3600 - minutes * 60;
     let hoursStr = hours.toString();
     let minutesStr = minutes.toString();
     let secondsStr = seconds.toString();
@@ -93,7 +93,7 @@ export default class Utils {
         result = value;
       } else {
         // Convert
-        result = (value === 'true');
+        result = value === 'true';
       }
     }
     return result;
@@ -104,7 +104,7 @@ export default class Utils {
       throw new RangeError('Invalid interval');
     }
     const randomPositiveFloat = crypto.randomBytes(4).readUInt32LE() / 0xffffffff;
-    const sign = (negative && randomPositiveFloat < 0.5) ? -1 : 1;
+    const sign = negative && randomPositiveFloat < 0.5 ? -1 : 1;
     return sign * (randomPositiveFloat * (max - min) + min);
   }
 
@@ -140,12 +140,20 @@ export default class Utils {
     return Utils.roundTo(Utils.getRandomFloat(max), scale);
   }
 
-  public static getRandomFloatFluctuatedRounded(staticValue: number, fluctuationPercent: number, scale = 2): number {
+  public static getRandomFloatFluctuatedRounded(
+    staticValue: number,
+    fluctuationPercent: number,
+    scale = 2
+  ): number {
     if (fluctuationPercent === 0) {
       return Utils.roundTo(staticValue, scale);
     }
     const fluctuationRatio = fluctuationPercent / 100;
-    return Utils.getRandomFloatRounded(staticValue * (1 + fluctuationRatio), staticValue * (1 - fluctuationRatio), scale);
+    return Utils.getRandomFloatRounded(
+      staticValue * (1 + fluctuationRatio),
+      staticValue * (1 - fluctuationRatio),
+      scale
+    );
   }
 
   public static cloneObject<T>(object: T): T {
@@ -189,7 +197,8 @@ export default class Utils {
     return !Object.keys(obj).length;
   }
 
-  public static insertAt = (str: string, subStr: string, pos: number): string => `${str.slice(0, pos)}${subStr}${str.slice(pos)}`;
+  public static insertAt = (str: string, subStr: string, pos: number): string =>
+    `${str.slice(0, pos)}${subStr}${str.slice(pos)}`;
 
   /**
    * @param [retryNumber=0]
@@ -228,7 +237,9 @@ export default class Utils {
   }
 
   public static workerPoolInUse(): boolean {
-    return [WorkerProcessType.DYNAMIC_POOL, WorkerProcessType.STATIC_POOL].includes(Configuration.getWorkerProcess());
+    return [WorkerProcessType.DYNAMIC_POOL, WorkerProcessType.STATIC_POOL].includes(
+      Configuration.getWorkerProcess()
+    );
   }
 
   public static workerDynamicPoolInUse(): boolean {
@@ -236,10 +247,12 @@ export default class Utils {
   }
 
   public static async promiseWithTimeout<T>(
-      promise: Promise<T>,
-      timeoutMs: number,
-      timeoutError: Error,
-      timeoutCallback: () => void = () => { /* This is intentional */ }
+    promise: Promise<T>,
+    timeoutMs: number,
+    timeoutError: Error,
+    timeoutCallback: () => void = () => {
+      /* This is intentional */
+    }
   ): Promise<T> {
     // Create a timeout promise that rejects in timeout milliseconds
     const timeoutPromise = new Promise<never>((_, reject) => {
index 12cc7c735f257ed624c8de35d5198865361edec7..c3e0ed88e9ae6fa4581b6e99b65bffa20931a546 100644 (file)
@@ -14,15 +14,20 @@ export default abstract class WorkerAbstract<T extends WorkerData> {
    * @param workerScript
    * @param workerOptions
    */
-  constructor(workerScript: string, workerOptions: WorkerOptions = {
-    workerStartDelay: Constants.WORKER_START_DELAY,
-    elementStartDelay: Constants.ELEMENT_START_DELAY,
-    poolMinSize: Constants.DEFAULT_WORKER_POOL_MIN_SIZE,
-    poolMaxSize: Constants.DEFAULT_WORKER_POOL_MAX_SIZE,
-    elementsPerWorker: Constants.DEFAULT_CHARGING_STATIONS_PER_WORKER,
-    poolOptions: {},
-    messageHandler: () => { /* This is intentional */ }
-  }) {
+  constructor(
+    workerScript: string,
+    workerOptions: WorkerOptions = {
+      workerStartDelay: Constants.WORKER_START_DELAY,
+      elementStartDelay: Constants.ELEMENT_START_DELAY,
+      poolMinSize: Constants.DEFAULT_WORKER_POOL_MIN_SIZE,
+      poolMaxSize: Constants.DEFAULT_WORKER_POOL_MAX_SIZE,
+      elementsPerWorker: Constants.DEFAULT_CHARGING_STATIONS_PER_WORKER,
+      poolOptions: {},
+      messageHandler: () => {
+        /* This is intentional */
+      },
+    }
+  ) {
     this.workerScript = workerScript;
     this.workerOptions = workerOptions;
   }
index a263335c1bd59682220be9ebcfdc281c0e067d6d..dfa344231edf56e019d0a1192b720aa493eec018 100644 (file)
@@ -16,8 +16,14 @@ export default class WorkerDynamicPool extends WorkerAbstract<WorkerData> {
    */
   constructor(workerScript: string, workerOptions?: WorkerOptions) {
     super(workerScript, workerOptions);
-    this.workerOptions.poolOptions.exitHandler = this.workerOptions?.poolOptions?.exitHandler ?? WorkerUtils.defaultExitHandler;
-    this.pool = new DynamicThreadPool<WorkerData>(this.workerOptions.poolMinSize, this.workerOptions.poolMaxSize, this.workerScript, this.workerOptions.poolOptions);
+    this.workerOptions.poolOptions.exitHandler =
+      this.workerOptions?.poolOptions?.exitHandler ?? WorkerUtils.defaultExitHandler;
+    this.pool = new DynamicThreadPool<WorkerData>(
+      this.workerOptions.poolMinSize,
+      this.workerOptions.poolMaxSize,
+      this.workerScript,
+      this.workerOptions.poolOptions
+    );
   }
 
   get size(): number {
@@ -55,6 +61,7 @@ export default class WorkerDynamicPool extends WorkerAbstract<WorkerData> {
   public async addElement(elementData: WorkerData): Promise<void> {
     await this.pool.execute(elementData);
     // Start element sequentially to optimize memory at startup
-    this.workerOptions.elementStartDelay > 0 && await Utils.sleep(this.workerOptions.elementStartDelay);
+    this.workerOptions.elementStartDelay > 0 &&
+      (await Utils.sleep(this.workerOptions.elementStartDelay));
   }
 }
index debd3f6a21342797ac15a6ae23eb5f0e664edce5..1c4b81c8ad6ab5d7c0e35a9b89e46d39b4f19c7e 100644 (file)
@@ -13,28 +13,39 @@ export default class WorkerFactory {
     // This is intentional
   }
 
-  public static getWorkerImplementation<T extends WorkerData>(workerScript: string, workerProcessType: WorkerProcessType, workerOptions?: WorkerOptions): WorkerAbstract<T> | null {
+  public static getWorkerImplementation<T extends WorkerData>(
+    workerScript: string,
+    workerProcessType: WorkerProcessType,
+    workerOptions?: WorkerOptions
+  ): WorkerAbstract<T> | null {
     if (!isMainThread) {
       throw new Error('Trying to get a worker implementation outside the main thread');
     }
-    workerOptions = workerOptions ?? {} as WorkerOptions;
-    workerOptions.workerStartDelay = workerOptions?.workerStartDelay ?? Constants.WORKER_START_DELAY;
-    workerOptions.elementStartDelay = workerOptions?.elementStartDelay ?? Constants.ELEMENT_START_DELAY;
-    workerOptions.poolOptions = workerOptions?.poolOptions ?? {} as PoolOptions<Worker>;
-    workerOptions?.messageHandler && (workerOptions.poolOptions.messageHandler = workerOptions.messageHandler);
+    workerOptions = workerOptions ?? ({} as WorkerOptions);
+    workerOptions.workerStartDelay =
+      workerOptions?.workerStartDelay ?? Constants.WORKER_START_DELAY;
+    workerOptions.elementStartDelay =
+      workerOptions?.elementStartDelay ?? Constants.ELEMENT_START_DELAY;
+    workerOptions.poolOptions = workerOptions?.poolOptions ?? ({} as PoolOptions<Worker>);
+    workerOptions?.messageHandler &&
+      (workerOptions.poolOptions.messageHandler = workerOptions.messageHandler);
     let workerImplementation: WorkerAbstract<T> = null;
     switch (workerProcessType) {
       case WorkerProcessType.WORKER_SET:
-        workerOptions.elementsPerWorker = workerOptions?.elementsPerWorker ?? Constants.DEFAULT_CHARGING_STATIONS_PER_WORKER;
+        workerOptions.elementsPerWorker =
+          workerOptions?.elementsPerWorker ?? Constants.DEFAULT_CHARGING_STATIONS_PER_WORKER;
         workerImplementation = new WorkerSet(workerScript, workerOptions);
         break;
       case WorkerProcessType.STATIC_POOL:
-        workerOptions.poolMaxSize = workerOptions?.poolMaxSize ?? Constants.DEFAULT_WORKER_POOL_MAX_SIZE;
+        workerOptions.poolMaxSize =
+          workerOptions?.poolMaxSize ?? Constants.DEFAULT_WORKER_POOL_MAX_SIZE;
         workerImplementation = new WorkerStaticPool(workerScript, workerOptions);
         break;
       case WorkerProcessType.DYNAMIC_POOL:
-        workerOptions.poolMinSize = workerOptions?.poolMinSize ?? Constants.DEFAULT_WORKER_POOL_MIN_SIZE;
-        workerOptions.poolMaxSize = workerOptions?.poolMaxSize ?? Constants.DEFAULT_WORKER_POOL_MAX_SIZE;
+        workerOptions.poolMinSize =
+          workerOptions?.poolMinSize ?? Constants.DEFAULT_WORKER_POOL_MIN_SIZE;
+        workerOptions.poolMaxSize =
+          workerOptions?.poolMaxSize ?? Constants.DEFAULT_WORKER_POOL_MAX_SIZE;
         workerImplementation = new WorkerDynamicPool(workerScript, workerOptions);
         break;
       default:
index 5bc399189e5b079f9bad7cd4b7ab49c3353c10d0..6e890902d8f8c769e726a262e5c013c39334b604 100644 (file)
@@ -20,7 +20,11 @@ export default class WorkerSet extends WorkerAbstract<WorkerData> {
   constructor(workerScript: string, workerOptions?: WorkerOptions) {
     super(workerScript, workerOptions);
     this.workerSet = new Set<WorkerSetElement>();
-    this.messageHandler = workerOptions?.messageHandler ?? (() => { /* This is intentional */ });
+    this.messageHandler =
+      workerOptions?.messageHandler ??
+      (() => {
+        /* This is intentional */
+      });
   }
 
   get size(): number {
@@ -39,14 +43,16 @@ export default class WorkerSet extends WorkerAbstract<WorkerData> {
    */
   public async addElement(elementData: WorkerData): Promise<void> {
     if (!this.workerSet) {
-      throw new Error('Cannot add a WorkerSet element: workers\' set does not exist');
+      throw new Error("Cannot add a WorkerSet element: workers' set does not exist");
     }
-    if (this.getLastWorkerSetElement().numberOfWorkerElements >= this.workerOptions.elementsPerWorker) {
+    if (
+      this.getLastWorkerSetElement().numberOfWorkerElements >= this.workerOptions.elementsPerWorker
+    ) {
       await this.startWorker();
     }
     this.getLastWorker().postMessage({
       id: WorkerMessageEvents.START_WORKER_ELEMENT,
-      data: elementData
+      data: elementData,
     });
     this.getLastWorkerSetElement().numberOfWorkerElements++;
     // Start element sequentially to optimize memory at startup
@@ -85,21 +91,28 @@ export default class WorkerSet extends WorkerAbstract<WorkerData> {
     worker.on('message', (msg) => {
       (async () => {
         await this.messageHandler(msg);
-      })().catch(() => { /* This is intentional */ });
+      })().catch(() => {
+        /* This is intentional */
+      });
+    });
+    worker.on('error', () => {
+      /* This is intentional */
     });
-    worker.on('error', () => { /* This is intentional */ });
     worker.on('exit', (code) => {
       WorkerUtils.defaultExitHandler(code);
       this.workerSet.delete(this.getWorkerSetElementByWorker(worker));
     });
     this.workerSet.add({ worker, numberOfWorkerElements: 0 });
     // Start worker sequentially to optimize memory at startup
-    this.workerOptions.workerStartDelay > 0 && await Utils.sleep(this.workerOptions.workerStartDelay);
+    this.workerOptions.workerStartDelay > 0 &&
+      (await Utils.sleep(this.workerOptions.workerStartDelay));
   }
 
   private getLastWorkerSetElement(): WorkerSetElement {
     let workerSetElement: WorkerSetElement;
-    for (workerSetElement of this.workerSet) { /* This is intentional */ }
+    for (workerSetElement of this.workerSet) {
+      /* This is intentional */
+    }
     return workerSetElement;
   }
 
index 818fd21af48f1c466b9e8dc8920ed94bb73a915a..3eaffff4b48a7c11e4c6c5fa3026b4c9f042b551 100644 (file)
@@ -16,8 +16,13 @@ export default class WorkerStaticPool extends WorkerAbstract<WorkerData> {
    */
   constructor(workerScript: string, workerOptions?: WorkerOptions) {
     super(workerScript, workerOptions);
-    this.workerOptions.poolOptions.exitHandler = this.workerOptions?.poolOptions?.exitHandler ?? WorkerUtils.defaultExitHandler;
-    this.pool = new FixedThreadPool(this.workerOptions.poolMaxSize, this.workerScript, this.workerOptions.poolOptions);
+    this.workerOptions.poolOptions.exitHandler =
+      this.workerOptions?.poolOptions?.exitHandler ?? WorkerUtils.defaultExitHandler;
+    this.pool = new FixedThreadPool(
+      this.workerOptions.poolMaxSize,
+      this.workerScript,
+      this.workerOptions.poolOptions
+    );
   }
 
   get size(): number {
@@ -55,6 +60,7 @@ export default class WorkerStaticPool extends WorkerAbstract<WorkerData> {
   public async addElement(elementData: WorkerData): Promise<void> {
     await this.pool.execute(elementData);
     // Start element sequentially to optimize memory at startup
-    this.workerOptions.elementStartDelay > 0 && await Utils.sleep(this.workerOptions.elementStartDelay);
+    this.workerOptions.elementStartDelay > 0 &&
+      (await Utils.sleep(this.workerOptions.elementStartDelay));
   }
 }
index 71e532fdccdce845962a2e7dbb43efab47575189..abd684f87660cb67c3e4b5d5a96fe02bb63e4fc0 100644 (file)
@@ -1,9 +1,4 @@
 {
-  "pluginLoadPaths": [
-    "test/robohydra/plugins"
-  ],
-  "plugins": [
-    "logger",
-    "wsServer"
-  ]
+  "pluginLoadPaths": ["test/robohydra/plugins"],
+  "plugins": ["logger", "wsServer"]
 }
index d4ab6b8dfad79f4f1bb319265d0a59171b0913d0..485ee19ef720ce29fad8f5006b6e84588fba2514 100644 (file)
@@ -2,7 +2,7 @@ const RoboHydraHead = require('robohydra').heads.RoboHydraHead;
 const RoboHydraWebSocketHead = require('robohydra').heads.RoboHydraWebSocketHead;
 const RoboHydraWebSocketHeadProxy = require('robohydra').heads.RoboHydraWebSocketHeadProxy;
 
-exports.getBodyParts = function(conf) {
+exports.getBodyParts = function (conf) {
   let wsSocket;
   return {
     heads: [
@@ -10,7 +10,7 @@ exports.getBodyParts = function(conf) {
         name: 'message',
         path: '/message',
         method: 'POST',
-        handler: function(req, res) {
+        handler: function (req, res) {
           const msg = JSON.stringify(req.body);
           if (wsSocket) {
             wsSocket.send(msg);
@@ -18,42 +18,42 @@ exports.getBodyParts = function(conf) {
           } else {
             res.send('Cannot send message, no opened websocket found');
           }
-        }
+        },
       }),
 
       new RoboHydraHead({
         name: 'close',
         path: '/close',
         method: 'GET',
-        handler: function(req, res) {
+        handler: function (req, res) {
           if (wsSocket) {
             wsSocket.close();
             res.send('Websocket closed');
           } else {
             res.send('Cannot close websocket, no opened websocket found');
           }
-        }
+        },
       }),
 
       new RoboHydraWebSocketHeadProxy({
         name: 'proxy',
         mountPath: '/proxy',
         proxyTo: 'ws://server.example.com',
-        preProcessor: function(data) {
+        preProcessor: function (data) {
           console.log('From the client: ' + data);
         },
-        postProcessor: function(data) {
+        postProcessor: function (data) {
           console.log('From the server: ' + data);
-        }
+        },
       }),
 
       new RoboHydraWebSocketHead({
         name: 'WS Server',
         path: '/.*',
-        handler: function(req, socket) {
+        handler: function (req, socket) {
           wsSocket = socket;
-        }
-      })
-    ]
+        },
+      }),
+    ],
   };
 };
index db1e529e8f0105082cc9defe26978478cc72b618..d17df344b1c3d5c13675035ad7ca54410b1d6911 100644 (file)
@@ -26,10 +26,8 @@ describe('Circular array test suite', () => {
     expect(circularArray.length).toBe(4);
   });
 
-  it('Verify that circular array size can\'t be negative at instance creation', () => {
-    expect(() => new CircularArray(-1)).toThrowError(
-      new RangeError('Invalid circular array size')
-    );
+  it("Verify that circular array size can't be negative at instance creation", () => {
+    expect(() => new CircularArray(-1)).toThrowError(new RangeError('Invalid circular array size'));
   });
 
   it('Verify that circular array empty works as intended', () => {
index ecd539c57ebce0b74025e495cc507ac59e2aefcf..a0c7e1629f61d538a2f732b817d31636179d5228 100644 (file)
@@ -6,9 +6,7 @@
     // "incremental": true,                   /* Enable incremental compilation */
     "target": "es2020",                       /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
     "module": "es2020",                       /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
-    "lib": [
-      "es2020"
-    ],                                        /* Specify library files to be included in the compilation. */
+    "lib": ["es2020"],                        /* Specify library files to be included in the compilation. */
     // "allowJs": true,                       /* Allow javascript files to be compiled. */
     // "checkJs": true,                       /* Report errors in .js files. */
     // "jsx": "preserve",                     /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */