From bcb21a59907b2ab0841956fe2c50f8bd2be8619a Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=B4me=20Benoit?= Date: Sat, 18 Apr 2026 00:33:34 +0200 Subject: [PATCH] feat(ui-cli): add registration and connector columns to station list, fix command semantics Station list improvements: - Add Registration column (Accepted/Pending/Rejected) after Hash ID - Add Connectors column with per-connector status letters (1:A 2:O etc.) - Two-letter abbreviations for ambiguous statuses (Fi/F, SE/SS) - Remove dead countConnectors function, replace with formatConnectors - Replace countConnectors tests with formatConnectors tests (7 tests) Command description semantics: - All OCPP: 'Send OCPP X' -> 'Request station(s) to send OCPP X' - Connection: 'Open/Close WebSocket connection' -> '... to CSMS on station(s)' - Connector: 'Lock/Unlock a connector' -> '... connector on station(s)' - Transaction: 'Start/Stop a transaction' -> '... on station(s)' - SKILL.md: 'send OCPP messages' -> 'trigger OCPP messages from stations to the CSMS' - README: updated accordingly --- ui/cli/README.md | 14 +- ui/cli/skills/evse-simulator/SKILL.md | 6 +- ui/cli/src/commands/connection.ts | 4 +- ui/cli/src/commands/connector.ts | 4 +- ui/cli/src/commands/ocpp.ts | 44 ++-- ui/cli/src/commands/transaction.ts | 4 +- ui/cli/src/output/format.ts | 33 +-- ui/cli/src/output/renderers.ts | 20 +- ui/cli/tests/format.test.ts | 309 +++++++++++++------------- 9 files changed, 233 insertions(+), 205 deletions(-) diff --git a/ui/cli/README.md b/ui/cli/README.md index 2ff767b2..cd180d5e 100644 --- a/ui/cli/README.md +++ b/ui/cli/README.md @@ -201,15 +201,15 @@ evse-cli transaction stop --transaction-id [hashId...] #### ocpp -Send OCPP commands directly to charging stations: +Request charging station(s) to send OCPP messages to the CSMS: ```shell -evse-cli ocpp heartbeat [hashId...] -evse-cli ocpp authorize --id-tag [hashId...] -evse-cli ocpp boot-notification [hashId...] -evse-cli ocpp status-notification --connector-id --error-code --status [hashId...] -evse-cli ocpp meter-values --connector-id [hashId...] -evse-cli ocpp data-transfer --vendor-id [--message-id ] [--data ] [hashId...] +evse-cli ocpp heartbeat [hashId...] # Heartbeat +evse-cli ocpp authorize --id-tag [hashId...] # Authorize +evse-cli ocpp boot-notification [hashId...] # BootNotification +evse-cli ocpp status-notification --connector-id --error-code --status [hashId...] # StatusNotification +evse-cli ocpp meter-values --connector-id [hashId...] # MeterValues +evse-cli ocpp data-transfer --vendor-id [--message-id ] [--data ] [hashId...] # DataTransfer ``` Other OCPP commands (no extra options): `diagnostics-status-notification`, `firmware-status-notification`, `get-15118-ev-certificate`, `get-certificate-status`, `log-status-notification`, `notify-customer-information`, `notify-report`, `security-event-notification`, `sign-certificate`, `transaction-event`. diff --git a/ui/cli/skills/evse-simulator/SKILL.md b/ui/cli/skills/evse-simulator/SKILL.md index ec457048..af5af761 100644 --- a/ui/cli/skills/evse-simulator/SKILL.md +++ b/ui/cli/skills/evse-simulator/SKILL.md @@ -1,6 +1,6 @@ --- name: evse-simulator -description: Control and monitor an OCPP charging station simulator via CLI. Use when users ask to manage charging stations, send OCPP messages, start/stop the simulator or ATG, list stations or templates, or check simulator state. +description: Control and monitor an OCPP charging station simulator via CLI. Use when users ask to manage charging stations, trigger OCPP messages from stations to the CSMS, start/stop the simulator or ATG, list stations or templates, or check simulator state. license: Apache-2.0 compatibility: Requires the simulator UI server to be running with WebSocket enabled. metadata: @@ -105,6 +105,8 @@ evse-cli transaction stop --transaction-id [hashId...] ### OCPP Messages +Request station(s) to send OCPP messages to the CSMS: + ```shell evse-cli ocpp heartbeat [hashId...] evse-cli ocpp boot-notification [hashId...] @@ -162,7 +164,7 @@ evse-cli station add -t keba-ocpp2.station-template -n 3 --auto-start evse-cli atg start ``` -### Send OCPP heartbeat to all stations +### Request all stations to send OCPP Heartbeat ```shell evse-cli ocpp heartbeat diff --git a/ui/cli/src/commands/connection.ts b/ui/cli/src/commands/connection.ts index fcf6c538..b9ccd9a9 100644 --- a/ui/cli/src/commands/connection.ts +++ b/ui/cli/src/commands/connection.ts @@ -9,7 +9,7 @@ export const createConnectionCommands = (program: Command): Command => { cmd .command('open [hashIds...]') - .description('Open WebSocket connection') + .description('Open WebSocket connection to CSMS on station(s)') .action(async (hashIds: string[]) => { const payload: RequestPayload = buildHashIdsPayload(hashIds) await runAction(program, ProcedureName.OPEN_CONNECTION, payload) @@ -17,7 +17,7 @@ export const createConnectionCommands = (program: Command): Command => { cmd .command('close [hashIds...]') - .description('Close WebSocket connection') + .description('Close WebSocket connection to CSMS on station(s)') .action(async (hashIds: string[]) => { const payload: RequestPayload = buildHashIdsPayload(hashIds) await runAction(program, ProcedureName.CLOSE_CONNECTION, payload) diff --git a/ui/cli/src/commands/connector.ts b/ui/cli/src/commands/connector.ts index 25ffadf9..17f41e0e 100644 --- a/ui/cli/src/commands/connector.ts +++ b/ui/cli/src/commands/connector.ts @@ -9,7 +9,7 @@ export const createConnectorCommands = (program: Command): Command => { cmd .command('lock [hashIds...]') - .description('Lock a connector') + .description('Lock connector on station(s)') .requiredOption('--connector-id ', 'connector ID', parseInteger) .action(async (hashIds: string[], options: { connectorId: number }) => { const payload: RequestPayload = { @@ -21,7 +21,7 @@ export const createConnectorCommands = (program: Command): Command => { cmd .command('unlock [hashIds...]') - .description('Unlock a connector') + .description('Unlock connector on station(s)') .requiredOption('--connector-id ', 'connector ID', parseInteger) .action(async (hashIds: string[], options: { connectorId: number }) => { const payload: RequestPayload = { diff --git a/ui/cli/src/commands/ocpp.ts b/ui/cli/src/commands/ocpp.ts index 4f46731a..17ea825a 100644 --- a/ui/cli/src/commands/ocpp.ts +++ b/ui/cli/src/commands/ocpp.ts @@ -9,7 +9,7 @@ export const createOcppCommands = (program: Command): Command => { cmd .command('authorize [hashIds...]') - .description('Send OCPP Authorize') + .description('Request station(s) to send OCPP Authorize') .requiredOption('--id-tag ', 'RFID tag for authorization') .action(async (hashIds: string[], options: { idTag: string }) => { const payload: RequestPayload = { @@ -21,7 +21,7 @@ export const createOcppCommands = (program: Command): Command => { cmd .command('data-transfer [hashIds...]') - .description('Send OCPP DataTransfer') + .description('Request station(s) to send OCPP DataTransfer') .option('--vendor-id ', 'vendor identifier') .option('--message-id ', 'message identifier') .option('--data ', 'data payload (JSON string)') @@ -44,7 +44,7 @@ export const createOcppCommands = (program: Command): Command => { cmd .command('meter-values [hashIds...]') - .description('Send OCPP MeterValues') + .description('Request station(s) to send OCPP MeterValues') .requiredOption('--connector-id ', 'connector ID', parseInteger) .action(async (hashIds: string[], options: { connectorId: number }) => { const payload: RequestPayload = { @@ -56,7 +56,7 @@ export const createOcppCommands = (program: Command): Command => { cmd .command('status-notification [hashIds...]') - .description('Send OCPP StatusNotification') + .description('Request station(s) to send OCPP StatusNotification') .requiredOption('--connector-id ', 'connector ID', parseInteger) .requiredOption('--error-code ', 'connector error code') .requiredOption('--status ', 'connector status') @@ -76,46 +76,58 @@ export const createOcppCommands = (program: Command): Command => { ) const simpleOcppCommands: [string, string, ProcedureName][] = [ - ['boot-notification', 'Send OCPP BootNotification', ProcedureName.BOOT_NOTIFICATION], + [ + 'boot-notification', + 'Request station(s) to send OCPP BootNotification', + ProcedureName.BOOT_NOTIFICATION, + ], [ 'diagnostics-status-notification', - 'Send OCPP DiagnosticsStatusNotification', + 'Request station(s) to send OCPP DiagnosticsStatusNotification', ProcedureName.DIAGNOSTICS_STATUS_NOTIFICATION, ], [ 'firmware-status-notification', - 'Send OCPP FirmwareStatusNotification', + 'Request station(s) to send OCPP FirmwareStatusNotification', ProcedureName.FIRMWARE_STATUS_NOTIFICATION, ], [ 'get-15118-ev-certificate', - 'Send OCPP Get15118EVCertificate', + 'Request station(s) to send OCPP Get15118EVCertificate', ProcedureName.GET_15118_EV_CERTIFICATE, ], [ 'get-certificate-status', - 'Send OCPP GetCertificateStatus', + 'Request station(s) to send OCPP GetCertificateStatus', ProcedureName.GET_CERTIFICATE_STATUS, ], - ['heartbeat', 'Send OCPP Heartbeat', ProcedureName.HEARTBEAT], + ['heartbeat', 'Request station(s) to send OCPP Heartbeat', ProcedureName.HEARTBEAT], [ 'log-status-notification', - 'Send OCPP LogStatusNotification', + 'Request station(s) to send OCPP LogStatusNotification', ProcedureName.LOG_STATUS_NOTIFICATION, ], [ 'notify-customer-information', - 'Send OCPP NotifyCustomerInformation', + 'Request station(s) to send OCPP NotifyCustomerInformation', ProcedureName.NOTIFY_CUSTOMER_INFORMATION, ], - ['notify-report', 'Send OCPP NotifyReport', ProcedureName.NOTIFY_REPORT], + ['notify-report', 'Request station(s) to send OCPP NotifyReport', ProcedureName.NOTIFY_REPORT], [ 'security-event-notification', - 'Send OCPP SecurityEventNotification', + 'Request station(s) to send OCPP SecurityEventNotification', ProcedureName.SECURITY_EVENT_NOTIFICATION, ], - ['sign-certificate', 'Send OCPP SignCertificate', ProcedureName.SIGN_CERTIFICATE], - ['transaction-event', 'Send OCPP TransactionEvent', ProcedureName.TRANSACTION_EVENT], + [ + 'sign-certificate', + 'Request station(s) to send OCPP SignCertificate', + ProcedureName.SIGN_CERTIFICATE, + ], + [ + 'transaction-event', + 'Request station(s) to send OCPP TransactionEvent', + ProcedureName.TRANSACTION_EVENT, + ], ] for (const [name, description, procedureName] of simpleOcppCommands) { diff --git a/ui/cli/src/commands/transaction.ts b/ui/cli/src/commands/transaction.ts index 59bfdae0..ec9fe992 100644 --- a/ui/cli/src/commands/transaction.ts +++ b/ui/cli/src/commands/transaction.ts @@ -9,7 +9,7 @@ export const createTransactionCommands = (program: Command): Command => { cmd .command('start [hashIds...]') - .description('Start a transaction') + .description('Start a transaction on station(s)') .requiredOption('--connector-id ', 'connector ID', parseInteger) .requiredOption('--id-tag ', 'RFID tag for authorization') .action(async (hashIds: string[], options: { connectorId: number; idTag: string }) => { @@ -23,7 +23,7 @@ export const createTransactionCommands = (program: Command): Command => { cmd .command('stop [hashIds...]') - .description('Stop a transaction') + .description('Stop a transaction on station(s)') .requiredOption('--transaction-id ', 'transaction ID', parseInteger) .action(async (hashIds: string[], options: { transactionId: number }) => { const payload: RequestPayload = { diff --git a/ui/cli/src/output/format.ts b/ui/cli/src/output/format.ts index b3a057f2..b7bcf229 100644 --- a/ui/cli/src/output/format.ts +++ b/ui/cli/src/output/format.ts @@ -1,6 +1,6 @@ import chalk from 'chalk' import Table from 'cli-table3' -import { type ConnectorEntry, type EvseEntry, OCPP16ChargePointStatus } from 'ui-common' +import { type ConnectorEntry, type EvseEntry } from 'ui-common' const NO_BORDER = { bottom: '', @@ -49,22 +49,26 @@ export const wsIcon = (wsState: number | undefined): string => { } } -export const countConnectors = ( - evses: EvseEntry[], - connectors: ConnectorEntry[] -): { available: number; total: number } => { - let total = 0 - let available = 0 +const STATUS_ABBREVIATIONS: Record = { + Finishing: 'Fi', + SuspendedEV: 'SE', + SuspendedEVSE: 'SS', +} + +const statusLetter = (status: string | undefined): string => { + if (status == null || status.length === 0) return '?' + return STATUS_ABBREVIATIONS[status] ?? status.charAt(0).toUpperCase() +} + +export const formatConnectors = (evses: EvseEntry[], connectors: ConnectorEntry[]): string => { + const entries: string[] = [] if (evses.length > 0) { for (const evse of evses) { if (evse.evseId > 0) { for (const c of evse.evseStatus.connectors) { if (c.connectorId > 0) { - total++ - if (c.connectorStatus.status === OCPP16ChargePointStatus.AVAILABLE) { - available++ - } + entries.push(`${c.connectorId.toString()}:${statusLetter(c.connectorStatus.status)}`) } } } @@ -72,15 +76,12 @@ export const countConnectors = ( } else { for (const c of connectors) { if (c.connectorId > 0) { - total++ - if (c.connectorStatus.status === OCPP16ChargePointStatus.AVAILABLE) { - available++ - } + entries.push(`${c.connectorId.toString()}:${statusLetter(c.connectorStatus.status)}`) } } } - return { available, total } + return entries.length > 0 ? chalk.dim(entries.join(' ')) : chalk.dim('–') } export const fuzzyTime = (ts: number | undefined): string => { diff --git a/ui/cli/src/output/renderers.ts b/ui/cli/src/output/renderers.ts index 982046b0..5755ebfe 100644 --- a/ui/cli/src/output/renderers.ts +++ b/ui/cli/src/output/renderers.ts @@ -7,7 +7,7 @@ import type { StationListPayload } from '../types.js' import { borderlessTable, - countConnectors, + formatConnectors, fuzzyTime, statusIcon, truncateId, @@ -127,15 +127,27 @@ const renderStationList = (payload: StationListPayload): void => { return } - const table = borderlessTable(['', 'Name', 'Hash ID', 'WS', 'OCPP', 'Template', 'Updated']) + const table = borderlessTable([ + '', + 'Name', + 'Hash ID', + 'Reg', + 'WS', + 'Connectors', + 'OCPP', + 'Template', + 'Updated', + ]) for (const cs of stations) { const si = cs.stationInfo - const { available, total } = countConnectors(cs.evses ?? [], cs.connectors ?? []) + const reg = cs.bootNotificationResponse?.status table.push([ statusIcon(cs.started), si.chargingStationId, chalk.dim(truncateId(si.hashId)), - `${wsIcon(cs.wsState)} ${chalk.dim(`${available.toString()}/${total.toString()}`)}`, + reg ?? chalk.dim('–'), + wsIcon(cs.wsState), + formatConnectors(cs.evses ?? [], cs.connectors ?? []), chalk.dim(si.ocppVersion ?? '–'), chalk.dim(si.templateName.replace('.station-template', '')), fuzzyTime(cs.timestamp), diff --git a/ui/cli/tests/format.test.ts b/ui/cli/tests/format.test.ts index 2212e007..9508eadd 100644 --- a/ui/cli/tests/format.test.ts +++ b/ui/cli/tests/format.test.ts @@ -3,7 +3,13 @@ import assert from 'node:assert' import { describe, it } from 'node:test' import { OCPP16AvailabilityType, OCPP16ChargePointStatus } from 'ui-common' -import { countConnectors, fuzzyTime, statusIcon, truncateId, wsIcon } from '../src/output/format.js' +import { + formatConnectors, + fuzzyTime, + statusIcon, + truncateId, + wsIcon, +} from '../src/output/format.js' await describe('format helpers', async () => { await describe('truncateId', async () => { @@ -90,183 +96,178 @@ await describe('format helpers', async () => { }) }) - await describe('countConnectors', async () => { - await it('counts from evses when evses present (evseId > 0, connectorId > 0)', () => { - const evses = [ - { - evseId: 1, - evseStatus: { - availability: OCPP16AvailabilityType.OPERATIVE, - connectors: [ - { - connectorId: 1, - connectorStatus: { - availability: OCPP16AvailabilityType.OPERATIVE, - status: OCPP16ChargePointStatus.AVAILABLE, + await describe('formatConnectors', async () => { + await it('formats connectors from evses', () => { + const result = formatConnectors( + [ + { + evseId: 1, + evseStatus: { + availability: OCPP16AvailabilityType.OPERATIVE, + connectors: [ + { + connectorId: 1, + connectorStatus: { + availability: OCPP16AvailabilityType.OPERATIVE, + status: OCPP16ChargePointStatus.AVAILABLE, + }, }, - }, - { - connectorId: 2, - connectorStatus: { - availability: OCPP16AvailabilityType.OPERATIVE, - status: OCPP16ChargePointStatus.CHARGING, + { + connectorId: 2, + connectorStatus: { + availability: OCPP16AvailabilityType.OPERATIVE, + status: OCPP16ChargePointStatus.OCCUPIED, + }, }, - }, - ], + ], + }, }, - }, - ] - const result = countConnectors(evses, []) - assert.deepStrictEqual(result, { available: 1, total: 2 }) + ], + [] + ) + assert.ok(result.includes('1:A')) + assert.ok(result.includes('2:O')) }) await it('skips evseId 0', () => { - const evses = [ - { - evseId: 0, - evseStatus: { - availability: OCPP16AvailabilityType.OPERATIVE, - connectors: [ - { - connectorId: 1, - connectorStatus: { - availability: OCPP16AvailabilityType.OPERATIVE, - status: OCPP16ChargePointStatus.AVAILABLE, + const result = formatConnectors( + [ + { + evseId: 0, + evseStatus: { + availability: OCPP16AvailabilityType.OPERATIVE, + connectors: [ + { + connectorId: 1, + connectorStatus: { + availability: OCPP16AvailabilityType.OPERATIVE, + status: OCPP16ChargePointStatus.AVAILABLE, + }, }, - }, - ], + ], + }, }, - }, - { - evseId: 1, - evseStatus: { - availability: OCPP16AvailabilityType.OPERATIVE, - connectors: [ - { - connectorId: 1, - connectorStatus: { - availability: OCPP16AvailabilityType.OPERATIVE, - status: OCPP16ChargePointStatus.AVAILABLE, - }, - }, - ], - }, - }, - ] - const result = countConnectors(evses, []) - assert.deepStrictEqual(result, { available: 1, total: 1 }) + ], + [] + ) + assert.ok(result.includes('–')) }) - await it('skips connectorId 0 within evses', () => { - const evses = [ - { - evseId: 1, - evseStatus: { - availability: OCPP16AvailabilityType.OPERATIVE, - connectors: [ - { - connectorId: 0, - connectorStatus: { - availability: OCPP16AvailabilityType.OPERATIVE, - status: OCPP16ChargePointStatus.AVAILABLE, + await it('skips connectorId 0', () => { + const result = formatConnectors( + [ + { + evseId: 1, + evseStatus: { + availability: OCPP16AvailabilityType.OPERATIVE, + connectors: [ + { + connectorId: 0, + connectorStatus: { + availability: OCPP16AvailabilityType.OPERATIVE, + status: OCPP16ChargePointStatus.AVAILABLE, + }, }, - }, - { - connectorId: 1, - connectorStatus: { - availability: OCPP16AvailabilityType.OPERATIVE, - status: OCPP16ChargePointStatus.AVAILABLE, + { + connectorId: 1, + connectorStatus: { + availability: OCPP16AvailabilityType.OPERATIVE, + status: OCPP16ChargePointStatus.AVAILABLE, + }, }, - }, - ], + ], + }, }, - }, - ] - const result = countConnectors(evses, []) - assert.deepStrictEqual(result, { available: 1, total: 1 }) - }) - - await it('counts available connectors (status === AVAILABLE)', () => { - const evses = [ - { - evseId: 1, - evseStatus: { - availability: OCPP16AvailabilityType.OPERATIVE, - connectors: [ - { - connectorId: 1, - connectorStatus: { - availability: OCPP16AvailabilityType.OPERATIVE, - status: OCPP16ChargePointStatus.AVAILABLE, - }, - }, - { - connectorId: 2, - connectorStatus: { - availability: OCPP16AvailabilityType.OPERATIVE, - status: OCPP16ChargePointStatus.UNAVAILABLE, - }, - }, - { - connectorId: 3, - connectorStatus: { - availability: OCPP16AvailabilityType.OPERATIVE, - status: OCPP16ChargePointStatus.FAULTED, - }, - }, - ], - }, - }, - ] - const result = countConnectors(evses, []) - assert.deepStrictEqual(result, { available: 1, total: 3 }) + ], + [] + ) + assert.ok(result.includes('1:A')) + assert.ok(!result.includes('0:')) }) await it('falls back to connectors array when evses empty', () => { - const connectors = [ - { - connectorId: 1, - connectorStatus: { - availability: OCPP16AvailabilityType.OPERATIVE, - status: OCPP16ChargePointStatus.AVAILABLE, + const result = formatConnectors( + [], + [ + { + connectorId: 1, + connectorStatus: { + availability: OCPP16AvailabilityType.OPERATIVE, + status: OCPP16ChargePointStatus.AVAILABLE, + }, }, - }, - { - connectorId: 2, - connectorStatus: { - availability: OCPP16AvailabilityType.OPERATIVE, - status: OCPP16ChargePointStatus.CHARGING, + { + connectorId: 2, + connectorStatus: { + availability: OCPP16AvailabilityType.OPERATIVE, + status: OCPP16ChargePointStatus.CHARGING, + }, }, - }, - ] - const result = countConnectors([], connectors) - assert.deepStrictEqual(result, { available: 1, total: 2 }) + ] + ) + assert.ok(result.includes('1:A')) + assert.ok(result.includes('2:C')) + }) + + await it('returns dash for empty arrays', () => { + const result = formatConnectors([], []) + assert.ok(result.includes('–')) }) - await it('skips connectorId 0 in connectors fallback', () => { - const connectors = [ - { - connectorId: 0, - connectorStatus: { - availability: OCPP16AvailabilityType.OPERATIVE, - status: OCPP16ChargePointStatus.AVAILABLE, + await it('uses two-letter abbreviations for ambiguous statuses', () => { + const result = formatConnectors( + [], + [ + { + connectorId: 1, + connectorStatus: { + availability: OCPP16AvailabilityType.OPERATIVE, + status: OCPP16ChargePointStatus.SUSPENDED_EV, + }, }, - }, - { - connectorId: 1, - connectorStatus: { - availability: OCPP16AvailabilityType.OPERATIVE, - status: OCPP16ChargePointStatus.AVAILABLE, + { + connectorId: 2, + connectorStatus: { + availability: OCPP16AvailabilityType.OPERATIVE, + status: OCPP16ChargePointStatus.SUSPENDED_EVSE, + }, }, - }, - ] - const result = countConnectors([], connectors) - assert.deepStrictEqual(result, { available: 1, total: 1 }) + { + connectorId: 3, + connectorStatus: { + availability: OCPP16AvailabilityType.OPERATIVE, + status: OCPP16ChargePointStatus.FINISHING, + }, + }, + { + connectorId: 4, + connectorStatus: { + availability: OCPP16AvailabilityType.OPERATIVE, + status: OCPP16ChargePointStatus.FAULTED, + }, + }, + ] + ) + assert.ok(result.includes('1:SE')) + assert.ok(result.includes('2:SS')) + assert.ok(result.includes('3:Fi')) + assert.ok(result.includes('4:F')) }) - await it('returns {available: 0, total: 0} for empty arrays', () => { - const result = countConnectors([], []) - assert.deepStrictEqual(result, { available: 0, total: 0 }) + await it('handles undefined status', () => { + const result = formatConnectors( + [], + [ + { + connectorId: 1, + connectorStatus: { + availability: OCPP16AvailabilityType.OPERATIVE, + status: undefined as unknown as OCPP16ChargePointStatus, + }, + }, + ] + ) + assert.ok(result.includes('1:?')) }) }) -- 2.43.0