Add native local device integrations
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
import { expect, tap } from '@git.zone/tstest/tapbundle';
|
||||
import { DsmrConfigFlow, createDsmrDiscoveryDescriptor } from '../../ts/integrations/dsmr/index.js';
|
||||
|
||||
tap.test('matches manual DSMR network entries', async () => {
|
||||
const descriptor = createDsmrDiscoveryDescriptor();
|
||||
const matcher = descriptor.getMatchers()[0];
|
||||
const result = await matcher.matches({ host: 'p1-reader.local', port: 2001, name: 'DSMR P1 bridge', metadata: { dsmr: true, dsmrVersion: '5' } }, {});
|
||||
|
||||
expect(result.matched).toBeTrue();
|
||||
expect(result.candidate?.integrationDomain).toEqual('dsmr');
|
||||
expect(result.candidate?.metadata?.connectionType).toEqual('network');
|
||||
expect(result.candidate?.metadata?.liveValidation).toBeFalse();
|
||||
});
|
||||
|
||||
tap.test('matches manual DSMR serial entries and validates candidates', async () => {
|
||||
const descriptor = createDsmrDiscoveryDescriptor();
|
||||
const matcher = descriptor.getMatchers()[0];
|
||||
const result = await matcher.matches({ serialPort: '/dev/ttyUSB0', name: 'DSMR P1 cable', metadata: { p1: true } }, {});
|
||||
const validator = descriptor.getValidators()[0];
|
||||
const validation = await validator.validate(result.candidate!, {});
|
||||
|
||||
expect(result.matched).toBeTrue();
|
||||
expect(result.candidate?.metadata?.connectionType).toEqual('serial');
|
||||
expect(validation.matched).toBeTrue();
|
||||
expect(validation.reason).toContain('live communication is not assumed');
|
||||
});
|
||||
|
||||
tap.test('config flow creates network config without claiming connection success', async () => {
|
||||
const flow = new DsmrConfigFlow();
|
||||
const step = await flow.start({ source: 'manual', id: 'p1-reader', host: 'p1-reader.local', port: 2001, metadata: { connectionType: 'network', dsmrVersion: '5' } }, {});
|
||||
const result = await step.submit!({ connectionType: 'network', host: 'p1-reader.local', port: 2001, dsmrVersion: '5', protocol: 'dsmr_protocol', liveRead: false });
|
||||
|
||||
expect(result.kind).toEqual('done');
|
||||
expect(result.config?.connectionType).toEqual('network');
|
||||
expect(result.config?.connected).toBeFalse();
|
||||
expect(result.config?.liveRead).toBeFalse();
|
||||
});
|
||||
|
||||
export default tap.start();
|
||||
@@ -0,0 +1,73 @@
|
||||
import { expect, tap } from '@git.zone/tstest/tapbundle';
|
||||
import { DsmrClient, DsmrMapper, DsmrTelegramParser, type IDsmrConfig } from '../../ts/integrations/dsmr/index.js';
|
||||
|
||||
const sampleTelegram = `/ISk5\\2MT382-1000
|
||||
1-3:0.2.8(50)
|
||||
0-0:1.0.0(240101120000W)
|
||||
0-0:96.1.1(453030333630303337383931323334)
|
||||
1-0:1.8.1(00123.456*kWh)
|
||||
1-0:1.8.2(00234.567*kWh)
|
||||
1-0:2.8.1(00012.345*kWh)
|
||||
1-0:2.8.2(00023.456*kWh)
|
||||
0-0:96.14.0(0002)
|
||||
1-0:1.7.0(01.193*kW)
|
||||
1-0:2.7.0(00.000*kW)
|
||||
1-0:21.7.0(00.378*kW)
|
||||
1-0:41.7.0(00.400*kW)
|
||||
1-0:61.7.0(00.415*kW)
|
||||
0-1:24.1.0(003)
|
||||
0-1:96.1.0(473030333930303137)
|
||||
0-1:24.2.1(240101110000W)(00024.123*m3)
|
||||
!ABCD`;
|
||||
|
||||
tap.test('parses DSMR telegrams and maps energy gas and power sensors', async () => {
|
||||
const snapshot = DsmrTelegramParser.parseTelegram(sampleTelegram, { config: { dsmrVersion: '5', connectionType: 'serial', serialPort: '/dev/ttyUSB0' } });
|
||||
const entities = DsmrMapper.toEntities(snapshot);
|
||||
const devices = DsmrMapper.toDevices(snapshot);
|
||||
|
||||
expect(snapshot.connected).toBeTrue();
|
||||
expect(snapshot.telegram?.objects.some((objectArg) => objectArg.obisCode === '1-0:1.7.0')).toBeTrue();
|
||||
expect(snapshot.sensors.find((sensorArg) => sensorArg.key === 'current_electricity_usage')?.value).toEqual(1.193);
|
||||
expect(snapshot.sensors.find((sensorArg) => sensorArg.key === 'electricity_used_tariff_1')?.value).toEqual(123.456);
|
||||
expect(snapshot.sensors.find((sensorArg) => sensorArg.key === 'electricity_active_tariff')?.value).toEqual('normal');
|
||||
expect(snapshot.sensors.find((sensorArg) => sensorArg.key === 'hourly_gas_meter_reading')?.value).toEqual(24.123);
|
||||
expect(entities.find((entityArg) => entityArg.attributes?.key === 'current_electricity_usage')?.attributes?.unitOfMeasurement).toEqual('kW');
|
||||
expect(entities.find((entityArg) => entityArg.attributes?.key === 'hourly_gas_meter_reading')?.deviceId).toContain('dsmr.gas');
|
||||
expect(devices.some((deviceArg) => deviceArg.id.startsWith('dsmr.electricity.'))).toBeTrue();
|
||||
expect(devices.some((deviceArg) => deviceArg.id.startsWith('dsmr.gas.'))).toBeTrue();
|
||||
});
|
||||
|
||||
tap.test('maps status snapshots without raw telegrams', async () => {
|
||||
const config: IDsmrConfig = {
|
||||
id: 'meter-status',
|
||||
dsmrVersion: '5',
|
||||
status: {
|
||||
meter: { serialId: 'E123', serialIdGas: 'G123' },
|
||||
values: {
|
||||
current_electricity_usage: { value: 0.456, unit: 'kW' },
|
||||
electricity_used_tariff_1: { value: 12.3, unit: 'kWh' },
|
||||
hourly_gas_meter_reading: { value: 4.2, unit: 'm3' },
|
||||
},
|
||||
},
|
||||
};
|
||||
const snapshot = await new DsmrClient(config).getSnapshot();
|
||||
const entities = DsmrMapper.toEntities(snapshot);
|
||||
|
||||
expect(snapshot.source).toEqual('status');
|
||||
expect(entities.find((entityArg) => entityArg.attributes?.key === 'current_electricity_usage')?.state).toEqual(0.456);
|
||||
expect(entities.find((entityArg) => entityArg.attributes?.key === 'electricity_used_tariff_1')?.attributes?.stateClass).toEqual('total_increasing');
|
||||
expect(entities.find((entityArg) => entityArg.attributes?.key === 'hourly_gas_meter_reading')?.state).toEqual(4.2);
|
||||
});
|
||||
|
||||
tap.test('does not fake live serial refresh success without a telegram source', async () => {
|
||||
const client = new DsmrClient({ connectionType: 'serial', serialPort: '/dev/ttyUSB0', port: '/dev/ttyUSB0', dsmrVersion: '5' });
|
||||
const snapshot = await client.getSnapshot();
|
||||
const result = await client.refresh();
|
||||
|
||||
expect(snapshot.connected).toBeFalse();
|
||||
expect(snapshot.sensors.length).toEqual(0);
|
||||
expect(result.success).toBeFalse();
|
||||
expect(result.error).toContain('telegramProvider');
|
||||
});
|
||||
|
||||
export default tap.start();
|
||||
Reference in New Issue
Block a user