Add support for unit in meter values.
authorJérôme Benoit <jerome.benoit@sap.com>
Sat, 12 Jun 2021 19:23:46 +0000 (21:23 +0200)
committerJérôme Benoit <jerome.benoit@sap.com>
Sat, 12 Jun 2021 19:23:46 +0000 (21:23 +0200)
Signed-off-by: Jérôme Benoit <jerome.benoit@sap.com>
README.md
package-lock.json
package.json
src/charging-station/ChargingStation.ts
src/charging-station/ocpp/1.6/OCPP16RequestService.ts
src/charging-station/ocpp/1.6/OCPP16ServiceUtils.ts
src/types/Connectors.ts

index 148665b43b17557293178b8fb7a70eec4a34386b..c544417a63b20a7d13ac4e4b9b58f43366f49749 100644 (file)
--- a/README.md
+++ b/README.md
@@ -53,7 +53,7 @@ chargePointModel | | '' | string | charging stations model
 chargePointVendor | | '' | string | charging stations vendor
 chargeBoxSerialNumberPrefix | | '' | string | charging stations serial number prefix
 firmwareVersion | | '' | string | charging stations firmware version
-power | | | integer\|integer[] | charging stations maximum power value(s)
+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
index 102dd164d17b43de3e239b73a2de73a9aa404f4f..0be6e913bf84dae6ef3fa76773c8c18620ff733d 100644 (file)
       }
     },
     "@octokit/core": {
-      "version": "3.4.0",
-      "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.4.0.tgz",
-      "integrity": "sha512-6/vlKPP8NF17cgYXqucdshWqmMZGXkuvtcrWCgU5NOI0Pl2GjlmZyWgBMrU8zJ3v2MJlM6++CiB45VKYmhiWWg==",
+      "version": "3.5.0",
+      "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.5.0.tgz",
+      "integrity": "sha512-IKcyllVQe6KPwPPFIaKdbhNNQhmmHIj69PXOseBF6/NglXoKHVe79syEfZj0bz7sP87MOl5jLZadV3slgdZ1vQ==",
       "dev": true,
       "requires": {
         "@octokit/auth-token": "^2.4.4",
         "@octokit/graphql": "^4.5.8",
-        "@octokit/request": "^5.4.12",
+        "@octokit/request": "^5.6.0",
         "@octokit/request-error": "^2.0.5",
         "@octokit/types": "^6.0.3",
         "before-after-hook": "^2.2.0",
       }
     },
     "@octokit/endpoint": {
-      "version": "6.0.11",
-      "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.11.tgz",
-      "integrity": "sha512-fUIPpx+pZyoLW4GCs3yMnlj2LfoXTWDUVPTC4V3MUEKZm48W+XYpeWSZCv+vYF1ZABUm2CqnDVf1sFtIYrj7KQ==",
+      "version": "6.0.12",
+      "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz",
+      "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==",
       "dev": true,
       "requires": {
         "@octokit/types": "^6.0.3",
       }
     },
     "@octokit/graphql": {
-      "version": "4.6.2",
-      "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.6.2.tgz",
-      "integrity": "sha512-WmsIR1OzOr/3IqfG9JIczI8gMJUMzzyx5j0XXQ4YihHtKlQc+u35VpVoOXhlKAlaBntvry1WpAzPl/a+s3n89Q==",
+      "version": "4.6.4",
+      "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.6.4.tgz",
+      "integrity": "sha512-SWTdXsVheRmlotWNjKzPOb6Js6tjSqA2a8z9+glDJng0Aqjzti8MEWOtuT8ZSu6wHnci7LZNuarE87+WJBG4vg==",
       "dev": true,
       "requires": {
-        "@octokit/request": "^5.3.0",
+        "@octokit/request": "^5.6.0",
         "@octokit/types": "^6.0.3",
         "universal-user-agent": "^6.0.0"
       }
     },
     "@octokit/openapi-types": {
-      "version": "7.2.3",
-      "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-7.2.3.tgz",
-      "integrity": "sha512-V1ycxkR19jqbIl3evf2RQiMRBvTNRi+Iy9h20G5OP5dPfEF6GJ1DPlUeiZRxo2HJxRr+UA4i0H1nn4btBDPFrw==",
+      "version": "7.3.2",
+      "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-7.3.2.tgz",
+      "integrity": "sha512-oJhK/yhl9Gt430OrZOzAl2wJqR0No9445vmZ9Ey8GjUZUpwuu/vmEFP0TDhDXdpGDoxD6/EIFHJEcY8nHXpDTA==",
       "dev": true
     },
     "@octokit/plugin-paginate-rest": {
-      "version": "2.13.3",
-      "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.13.3.tgz",
-      "integrity": "sha512-46lptzM9lTeSmIBt/sVP/FLSTPGx6DCzAdSX3PfeJ3mTf4h9sGC26WpaQzMEq/Z44cOcmx8VsOhO+uEgE3cjYg==",
+      "version": "2.13.5",
+      "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.13.5.tgz",
+      "integrity": "sha512-3WSAKBLa1RaR/7GG+LQR/tAZ9fp9H9waE9aPXallidyci9oZsfgsLn5M836d3LuDC6Fcym+2idRTBpssHZePVg==",
       "dev": true,
       "requires": {
-        "@octokit/types": "^6.11.0"
+        "@octokit/types": "^6.13.0"
       }
     },
     "@octokit/plugin-request-log": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.3.tgz",
-      "integrity": "sha512-4RFU4li238jMJAzLgAwkBAw+4Loile5haQMQr+uhFq27BmyJXcXSKvoQKqh0agsZEiUlW6iSv3FAgvmGkur7OQ==",
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz",
+      "integrity": "sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA==",
       "dev": true
     },
     "@octokit/plugin-rest-endpoint-methods": {
       }
     },
     "@octokit/request": {
-      "version": "5.5.0",
-      "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.5.0.tgz",
-      "integrity": "sha512-jxbMLQdQ3heFMZUaTLSCqcKs2oAHEYh7SnLLXyxbZmlULExZ/RXai7QUWWFKowcGGPlCZuKTZg0gSKHWrfYEoQ==",
+      "version": "5.6.0",
+      "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.0.tgz",
+      "integrity": "sha512-4cPp/N+NqmaGQwbh3vUsYqokQIzt7VjsgTYVXiwpUP2pxd5YiZB2XuTedbb0SPtv9XS7nzAKjAuQxmY8/aZkiA==",
       "dev": true,
       "requires": {
         "@octokit/endpoint": "^6.0.1",
-        "@octokit/request-error": "^2.0.0",
+        "@octokit/request-error": "^2.1.0",
         "@octokit/types": "^6.16.1",
         "is-plain-object": "^5.0.0",
         "node-fetch": "^2.6.1",
       }
     },
     "@octokit/request-error": {
-      "version": "2.0.5",
-      "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.0.5.tgz",
-      "integrity": "sha512-T/2wcCFyM7SkXzNoyVNWjyVlUwBvW3igM3Btr/eKYiPmucXTtkxt2RBsf6gn3LTzaLSLTQtNmvg+dGsOxQrjZg==",
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz",
+      "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==",
       "dev": true,
       "requires": {
         "@octokit/types": "^6.0.3",
       }
     },
     "@octokit/types": {
-      "version": "6.16.2",
-      "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.16.2.tgz",
-      "integrity": "sha512-wWPSynU4oLy3i4KGyk+J1BLwRKyoeW2TwRHgwbDz17WtVFzSK2GOErGliruIx8c+MaYtHSYTx36DSmLNoNbtgA==",
+      "version": "6.16.4",
+      "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.16.4.tgz",
+      "integrity": "sha512-UxhWCdSzloULfUyamfOg4dJxV9B+XjgrIZscI0VCbp4eNrjmorGEw+4qdwcpTsu6DIrm9tQsFQS2pK5QkqQ04A==",
       "dev": true,
       "requires": {
-        "@octokit/openapi-types": "^7.2.3"
+        "@octokit/openapi-types": "^7.3.2"
       }
     },
     "@rollup/plugin-json": {
       "dev": true
     },
     "release-it": {
-      "version": "14.8.0",
-      "resolved": "https://registry.npmjs.org/release-it/-/release-it-14.8.0.tgz",
-      "integrity": "sha512-XCw4kzJqdKgtis97HcNZ45r5dx+tZhcG1Yu2IEBKym1SceXiLBbycLsfqJQ8z+VLimClKpDeBdJkU03Vo/yFqw==",
+      "version": "14.9.0",
+      "resolved": "https://registry.npmjs.org/release-it/-/release-it-14.9.0.tgz",
+      "integrity": "sha512-Pn9GH60jKkL+dUkVxCyyiIhA9oySu/Q+8F9aExCggcppxfZbhRCxMgmk/iFh+/oejdzQq9zCZSudA2CmWOSKxQ==",
       "dev": true,
       "requires": {
         "@iarna/toml": "2.2.5",
           }
         },
         "cacheable-request": {
-          "version": "7.0.1",
-          "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.1.tgz",
-          "integrity": "sha512-lt0mJ6YAnsrBErpTMWeu5kl/tg9xMAWjavYTN6VQXM1A/teBITuNcccXsCxF0tDQQJf9DfAaX5O4e0zp0KlfZw==",
+          "version": "7.0.2",
+          "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.2.tgz",
+          "integrity": "sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==",
           "dev": true,
           "requires": {
             "clone-response": "^1.0.2",
             "http-cache-semantics": "^4.0.0",
             "keyv": "^4.0.0",
             "lowercase-keys": "^2.0.0",
-            "normalize-url": "^4.1.0",
+            "normalize-url": "^6.0.1",
             "responselike": "^2.0.0"
           },
           "dependencies": {
           "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
           "dev": true
         },
+        "normalize-url": {
+          "version": "6.0.1",
+          "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.0.1.tgz",
+          "integrity": "sha512-VU4pzAuh7Kip71XEmO9aNREYAdMHFGTVj/i+CaTImS8x0i1d3jUZkXhqluy/PRgjPLMgsLQulYY3PJ/aSbSjpQ==",
+          "dev": true
+        },
         "npm-run-path": {
           "version": "4.0.1",
           "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
               "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==",
               "dev": true
             },
+            "normalize-url": {
+              "version": "4.5.1",
+              "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz",
+              "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==",
+              "dev": true
+            },
             "p-cancelable": {
               "version": "1.1.0",
               "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz",
       }
     },
     "tslib": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
-      "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w=="
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz",
+      "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
     },
     "tsutils": {
       "version": "3.21.0",
index 87c4f8dd0fc37b14b2adcb79fa5bc8cbe10a9025..f8b51b3a26ab464013ccdac1523b8943a71a304d 100644 (file)
@@ -60,7 +60,7 @@
     "mongodb": "^3.6.9",
     "poolifier": "^2.0.2",
     "source-map-support": "^0.5.19",
-    "tslib": "^2.2.0",
+    "tslib": "^2.3.0",
     "uuid": "^8.3.2",
     "winston": "^3.3.3",
     "winston-daily-rotate-file": "^4.5.5",
@@ -93,7 +93,7 @@
     "mochawesome": "^6.2.2",
     "npm-check": "^5.9.2",
     "nyc": "^15.1.0",
-    "release-it": "^14.8.0",
+    "release-it": "^14.9.0",
     "rollup": "^2.51.2",
     "rollup-plugin-analyzer": "^4.0.0",
     "rollup-plugin-copy": "^3.4.0",
index ac704ea8097dcbf245d7d6f1c358a11275445dad..6dce9a374d008e6562fb8aabe9d580c3ea160e26 100644 (file)
@@ -561,7 +561,6 @@ export default class ChargingStation {
     try {
       // Parse the message
       [messageType, messageId, commandName, commandPayload, errorDetails] = JSON.parse(messageEvent.toString()) as IncomingRequest;
-
       // Check the Type of message
       switch (messageType) {
         // Incoming Message
index 4f2cac67ebb4442977aea2cf443ae8cecbae2068..3c01d452f5bb7cee69b836b3d10e837619769327 100644 (file)
@@ -1,8 +1,8 @@
+import { ACElectricUtils, DCElectricUtils } from '../../../utils/ElectricUtils';
 import { AuthorizeRequest, OCPP16AuthorizeResponse, OCPP16StartTransactionResponse, OCPP16StopTransactionReason, OCPP16StopTransactionResponse, StartTransactionRequest, StopTransactionRequest } from '../../../types/ocpp/1.6/Transaction';
 import { HeartbeatRequest, OCPP16BootNotificationRequest, OCPP16IncomingRequestCommand, OCPP16RequestCommand, StatusNotificationRequest } from '../../../types/ocpp/1.6/Requests';
-import { MeterValue, MeterValueContext, MeterValuePhase, MeterValuesRequest, OCPP16MeterValueMeasurand, OCPP16SampledValue } from '../../../types/ocpp/1.6/MeterValues';
+import { MeterValue, MeterValueContext, MeterValuePhase, MeterValueUnit, MeterValuesRequest, OCPP16MeterValueMeasurand, OCPP16SampledValue } from '../../../types/ocpp/1.6/MeterValues';
 
-import { ACElectricUtils } from '../../../utils/ElectricUtils';
 import Constants from '../../../utils/Constants';
 import { CurrentOutType } from '../../../types/ChargingStationTemplate';
 import MeasurandValues from '../../../types/MeasurandValues';
@@ -145,24 +145,25 @@ export default class OCPP16RequestService extends OCPPRequestService {
           OCPP16ServiceUtils.checkMeasurandPowerDivider(self.chargingStation, meterValuesTemplate[index].measurand);
           const errMsg = `${self.chargingStation.logPrefix()} MeterValues measurand ${meterValuesTemplate[index].measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: Unknown ${self.chargingStation.getCurrentOutType()} currentOutType in template file ${self.chargingStation.stationTemplateFile}, cannot calculate ${meterValuesTemplate[index].measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER} measurand value`;
           const powerMeasurandValues = {} as MeasurandValues;
+          const unitDivider = meterValuesTemplate[index]?.unit === MeterValueUnit.KILO_WATT ? 1000 : 1;
           const maxPower = Math.round(self.chargingStation.stationInfo.maxPower / self.chargingStation.stationInfo.powerDivider);
           const maxPowerPerPhase = Math.round((self.chargingStation.stationInfo.maxPower / self.chargingStation.stationInfo.powerDivider) / self.chargingStation.getNumberOfPhases());
           switch (self.chargingStation.getCurrentOutType()) {
             case CurrentOutType.AC:
               if (Utils.isUndefined(meterValuesTemplate[index].value)) {
-                powerMeasurandValues.L1 = Utils.getRandomFloatRounded(maxPowerPerPhase);
+                powerMeasurandValues.L1 = Utils.getRandomFloatRounded(maxPowerPerPhase / unitDivider);
                 powerMeasurandValues.L2 = 0;
                 powerMeasurandValues.L3 = 0;
                 if (self.chargingStation.getNumberOfPhases() === 3) {
-                  powerMeasurandValues.L2 = Utils.getRandomFloatRounded(maxPowerPerPhase);
-                  powerMeasurandValues.L3 = Utils.getRandomFloatRounded(maxPowerPerPhase);
+                  powerMeasurandValues.L2 = Utils.getRandomFloatRounded(maxPowerPerPhase / unitDivider);
+                  powerMeasurandValues.L3 = Utils.getRandomFloatRounded(maxPowerPerPhase / unitDivider);
                 }
                 powerMeasurandValues.allPhases = Utils.roundTo(powerMeasurandValues.L1 + powerMeasurandValues.L2 + powerMeasurandValues.L3, 2);
               }
               break;
             case CurrentOutType.DC:
               if (Utils.isUndefined(meterValuesTemplate[index].value)) {
-                powerMeasurandValues.allPhases = Utils.getRandomFloatRounded(maxPower);
+                powerMeasurandValues.allPhases = Utils.getRandomFloatRounded(maxPower / unitDivider);
               }
               break;
             default:
@@ -171,8 +172,9 @@ export default class OCPP16RequestService extends OCPPRequestService {
           }
           meterValue.sampledValue.push(OCPP16ServiceUtils.buildSampledValue(meterValuesTemplate[index], powerMeasurandValues.allPhases));
           const sampledValuesIndex = meterValue.sampledValue.length - 1;
-          if (Utils.convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) > maxPower || debug) {
-            logger.error(`${self.chargingStation.logPrefix()} MeterValues measurand ${meterValue.sampledValue[sampledValuesIndex].measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${meterValue.sampledValue[sampledValuesIndex].value}/${maxPower}`);
+          const maxPowerRounded = Utils.roundTo(maxPower / unitDivider, 2);
+          if (Utils.convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) > maxPowerRounded || debug) {
+            logger.error(`${self.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; self.chargingStation.getNumberOfPhases() === 3 && phase <= self.chargingStation.getNumberOfPhases(); phase++) {
             const phaseValue = `L${phase}-N`;
@@ -200,7 +202,7 @@ export default class OCPP16RequestService extends OCPPRequestService {
               }
               break;
             case CurrentOutType.DC:
-              maxAmperage = ACElectricUtils.amperageTotalFromPower(self.chargingStation.stationInfo.maxPower / self.chargingStation.stationInfo.powerDivider, self.chargingStation.getVoltageOut());
+              maxAmperage = DCElectricUtils.amperage(self.chargingStation.stationInfo.maxPower / self.chargingStation.stationInfo.powerDivider, self.chargingStation.getVoltageOut());
               if (Utils.isUndefined(meterValuesTemplate[index].value)) {
                 currentMeasurandValues.allPhases = Utils.getRandomFloatRounded(maxAmperage);
               }
@@ -222,24 +224,26 @@ export default class OCPP16RequestService extends OCPPRequestService {
         // Energy.Active.Import.Register measurand (default)
         } else if (!meterValuesTemplate[index].measurand || meterValuesTemplate[index].measurand === OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER) {
           OCPP16ServiceUtils.checkMeasurandPowerDivider(self.chargingStation, meterValuesTemplate[index].measurand);
+          const unitDivider = meterValuesTemplate[index]?.unit === MeterValueUnit.KILO_WATT_HOUR ? 1000 : 1;
           if (Utils.isUndefined(meterValuesTemplate[index].value)) {
-            const measurandValue = Utils.getRandomInt(self.chargingStation.stationInfo.maxPower / (self.chargingStation.stationInfo.powerDivider * 3600000) * interval);
+            const energyMeasurandValue = Utils.getRandomInt(self.chargingStation.stationInfo.maxPower / (self.chargingStation.stationInfo.powerDivider * 3600000) * interval);
             // Persist previous value in connector
             if (connector && !Utils.isNullOrUndefined(connector.energyActiveImportRegisterValue) && connector.energyActiveImportRegisterValue >= 0 &&
                 !Utils.isNullOrUndefined(connector.transactionEnergyActiveImportRegisterValue) && connector.transactionEnergyActiveImportRegisterValue >= 0) {
-              connector.energyActiveImportRegisterValue += measurandValue;
-              connector.transactionEnergyActiveImportRegisterValue += measurandValue;
+              connector.energyActiveImportRegisterValue += energyMeasurandValue;
+              connector.transactionEnergyActiveImportRegisterValue += energyMeasurandValue;
             } else {
               connector.energyActiveImportRegisterValue = 0;
               connector.transactionEnergyActiveImportRegisterValue = 0;
             }
           }
           meterValue.sampledValue.push(OCPP16ServiceUtils.buildSampledValue(meterValuesTemplate[index],
-            self.chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId)));
+            Utils.roundTo(self.chargingStation.getEnergyActiveImportRegisterByTransactionId(transactionId) / unitDivider, 4)));
           const sampledValuesIndex = meterValue.sampledValue.length - 1;
-          const maxConsumption = Math.round(self.chargingStation.stationInfo.maxPower * 3600 / (self.chargingStation.stationInfo.powerDivider * interval));
-          if (Utils.convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) > maxConsumption || debug) {
-            logger.error(`${self.chargingStation.logPrefix()} MeterValues measurand ${meterValue.sampledValue[sampledValuesIndex].measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${meterValue.sampledValue[sampledValuesIndex].value}/${maxConsumption}`);
+          const maxEnergy = Math.round(self.chargingStation.stationInfo.maxPower * 3600 / (self.chargingStation.stationInfo.powerDivider * interval));
+          const maxEnergyRounded = Utils.roundTo(maxEnergy / unitDivider, 4);
+          if (Utils.convertToFloat(meterValue.sampledValue[sampledValuesIndex].value) > maxEnergyRounded || debug) {
+            logger.error(`${self.chargingStation.logPrefix()} MeterValues measurand ${meterValue.sampledValue[sampledValuesIndex].measurand ?? OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER}: connectorId ${connectorId}, transaction ${connector.transactionId}, value: ${meterValue.sampledValue[sampledValuesIndex].value}/${maxEnergyRounded}`);
           }
         // Unsupported measurand
         } else {
@@ -266,7 +270,9 @@ export default class OCPP16RequestService extends OCPPRequestService {
     for (let index = 0; index < meterValuesTemplate.length; index++) {
       // Energy.Active.Import.Register measurand (default)
       if (!meterValuesTemplate[index].measurand || meterValuesTemplate[index].measurand === OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER) {
-        meterValue.sampledValue.push(OCPP16ServiceUtils.buildSampledValue(meterValuesTemplate[index], meterBegin, MeterValueContext.TRANSACTION_BEGIN));
+        const unitDivider = meterValuesTemplate[index]?.unit === MeterValueUnit.KILO_WATT_HOUR ? 1000 : 1;
+        meterValue.sampledValue.push(OCPP16ServiceUtils.buildSampledValue(meterValuesTemplate[index],
+          Utils.roundTo(meterBegin / unitDivider, 4), MeterValueContext.TRANSACTION_BEGIN));
       }
     }
     const payload: MeterValuesRequest = {
@@ -286,7 +292,8 @@ export default class OCPP16RequestService extends OCPPRequestService {
     for (let index = 0; index < meterValuesTemplate.length; index++) {
       // Energy.Active.Import.Register measurand (default)
       if (!meterValuesTemplate[index].measurand || meterValuesTemplate[index].measurand === OCPP16MeterValueMeasurand.ENERGY_ACTIVE_IMPORT_REGISTER) {
-        meterValue.sampledValue.push(OCPP16ServiceUtils.buildSampledValue(meterValuesTemplate[index], meterEnd, MeterValueContext.TRANSACTION_END));
+        const unitDivider = meterValuesTemplate[index]?.unit === MeterValueUnit.KILO_WATT_HOUR ? 1000 : 1;
+        meterValue.sampledValue.push(OCPP16ServiceUtils.buildSampledValue(meterValuesTemplate[index], Utils.roundTo(meterEnd / unitDivider, 4), MeterValueContext.TRANSACTION_END));
       }
     }
     const payload: MeterValuesRequest = {
index 5a2bfa9cfa3233b7a715775984a84ee484c3d808..853b46aaf932e28822ead86de0ed534b9f975f0c 100644 (file)
@@ -33,7 +33,7 @@ export class OCPP16ServiceUtils {
     };
   }
 
-  public static getMeasurandDefaultUnit(measurandType: OCPP16MeterValueMeasurand): MeterValueUnit {
+  public static getMeasurandDefaultUnit(measurandType: OCPP16MeterValueMeasurand): MeterValueUnit | undefined {
     switch (measurandType) {
       case OCPP16MeterValueMeasurand.CURRENT_EXPORT:
       case OCPP16MeterValueMeasurand.CURRENT_IMPORT:
@@ -53,7 +53,7 @@ export class OCPP16ServiceUtils {
     }
   }
 
-  public static getMeasurandDefaultLocation(measurandType: OCPP16MeterValueMeasurand): MeterValueLocation {
+  public static getMeasurandDefaultLocation(measurandType: OCPP16MeterValueMeasurand): MeterValueLocation | undefined {
     switch (measurandType) {
       case OCPP16MeterValueMeasurand.STATE_OF_CHARGE:
         return MeterValueLocation.EV;
index 0a2a6f3949052eb23a0c47bc92a22cd2a3fdd315..14415180b7c53331b3bbefc79328961c63406d8c 100644 (file)
@@ -12,8 +12,8 @@ export interface Connector {
   transactionId?: number;
   transactionSetInterval?: NodeJS.Timeout;
   idTag?: string;
-  energyActiveImportRegisterValue?: number;
-  transactionEnergyActiveImportRegisterValue?: number;
+  energyActiveImportRegisterValue?: number; // In Wh
+  transactionEnergyActiveImportRegisterValue?: number; // In Wh
   chargingProfiles?: ChargingProfile[]
 }