Add native local bus integrations
This commit is contained in:
@@ -0,0 +1,44 @@
|
||||
import { expect, tap } from '@git.zone/tstest/tapbundle';
|
||||
import { createModbusDiscoveryDescriptor } from '../../ts/integrations/modbus/index.js';
|
||||
|
||||
tap.test('matches manual Modbus TCP entries', async () => {
|
||||
const descriptor = createModbusDiscoveryDescriptor();
|
||||
const matcher = descriptor.getMatchers().find((matcherArg) => matcherArg.id === 'modbus-manual-tcp-match');
|
||||
const result = await matcher!.matches({
|
||||
host: '192.168.1.50',
|
||||
port: 502,
|
||||
type: 'tcp',
|
||||
name: 'Heat pump Modbus',
|
||||
unitId: 2,
|
||||
}, {});
|
||||
expect(result.matched).toBeTrue();
|
||||
expect(result.candidate?.integrationDomain).toEqual('modbus');
|
||||
expect(result.candidate?.port).toEqual(502);
|
||||
expect(result.candidate?.metadata?.unitId).toEqual(2);
|
||||
});
|
||||
|
||||
tap.test('does not guess serial RTU ports', async () => {
|
||||
const descriptor = createModbusDiscoveryDescriptor();
|
||||
const matcher = descriptor.getMatchers().find((matcherArg) => matcherArg.id === 'modbus-manual-tcp-match');
|
||||
const result = await matcher!.matches({
|
||||
type: 'serial',
|
||||
host: '/dev/ttyUSB0',
|
||||
name: 'RS485 adapter',
|
||||
}, {});
|
||||
expect(result.matched).toBeFalse();
|
||||
expect(result.reason).toContain('Serial RTU');
|
||||
});
|
||||
|
||||
tap.test('validates Modbus TCP candidates', async () => {
|
||||
const descriptor = createModbusDiscoveryDescriptor();
|
||||
const validator = descriptor.getValidators()[0];
|
||||
const result = await validator.validate({
|
||||
source: 'manual',
|
||||
integrationDomain: 'modbus',
|
||||
host: 'plc.local',
|
||||
}, {});
|
||||
expect(result.matched).toBeTrue();
|
||||
expect(result.candidate?.port).toEqual(502);
|
||||
});
|
||||
|
||||
export default tap.start();
|
||||
@@ -0,0 +1,102 @@
|
||||
import { expect, tap } from '@git.zone/tstest/tapbundle';
|
||||
import { ModbusClient, ModbusMapper, type IModbusConfig } from '../../ts/integrations/modbus/index.js';
|
||||
|
||||
const config: IModbusConfig = {
|
||||
hubs: [{
|
||||
name: 'plant_hub',
|
||||
type: 'tcp',
|
||||
host: '192.168.1.50',
|
||||
port: 502,
|
||||
registers: [{
|
||||
name: 'Supply Temp',
|
||||
address: 100,
|
||||
slave: 2,
|
||||
dataType: 'int16',
|
||||
registers: [215],
|
||||
scale: 0.1,
|
||||
precision: 1,
|
||||
unitOfMeasurement: 'C',
|
||||
}],
|
||||
numbers: [{
|
||||
name: 'Setpoint',
|
||||
address: 101,
|
||||
slave: 2,
|
||||
dataType: 'uint16',
|
||||
value: 22,
|
||||
min: 10,
|
||||
max: 30,
|
||||
step: 0.5,
|
||||
writable: true,
|
||||
}],
|
||||
coils: [{
|
||||
name: 'Pump Running',
|
||||
address: 5,
|
||||
slave: 2,
|
||||
value: true,
|
||||
}],
|
||||
switches: [{
|
||||
name: 'Pump Enable',
|
||||
address: 6,
|
||||
slave: 2,
|
||||
writeType: 'coil',
|
||||
value: false,
|
||||
commandOn: 1,
|
||||
commandOff: 0,
|
||||
}],
|
||||
}],
|
||||
};
|
||||
|
||||
tap.test('maps configured Modbus registers and coils to devices and entities', async () => {
|
||||
const snapshot = await new ModbusClient(config).getSnapshot();
|
||||
const devices = ModbusMapper.toDevices(snapshot);
|
||||
const entities = ModbusMapper.toEntities(snapshot);
|
||||
|
||||
expect(devices.some((deviceArg) => deviceArg.id === 'modbus.hub.plant_hub')).toBeTrue();
|
||||
expect(devices.some((deviceArg) => deviceArg.id === 'modbus.slave.plant_hub.2')).toBeTrue();
|
||||
expect(entities.find((entityArg) => entityArg.id === 'sensor.supply_temp')?.state).toEqual(21.5);
|
||||
expect(entities.find((entityArg) => entityArg.id === 'binary_sensor.pump_running')?.state).toEqual('on');
|
||||
expect(entities.find((entityArg) => entityArg.id === 'switch.pump_enable')?.state).toEqual('off');
|
||||
expect(entities.find((entityArg) => entityArg.id === 'number.setpoint')?.state).toEqual(22);
|
||||
});
|
||||
|
||||
tap.test('maps Modbus services to coil and register commands', async () => {
|
||||
const snapshot = await new ModbusClient(config).getSnapshot();
|
||||
const switchCommand = ModbusMapper.commandForService(snapshot, {
|
||||
domain: 'switch',
|
||||
service: 'turn_on',
|
||||
target: { entityId: 'switch.pump_enable' },
|
||||
});
|
||||
expect(switchCommand).toEqual({
|
||||
type: 'write_coil',
|
||||
hub: 'plant_hub',
|
||||
hubId: 'plant_hub',
|
||||
unitId: 2,
|
||||
entityId: 'switch.pump_enable',
|
||||
deviceId: undefined,
|
||||
uniqueId: 'modbus_plant_hub_slave_2_switch_6',
|
||||
address: 6,
|
||||
value: 1,
|
||||
});
|
||||
|
||||
const readCommand = ModbusMapper.commandForService(snapshot, {
|
||||
domain: 'modbus',
|
||||
service: 'read_register',
|
||||
target: {},
|
||||
data: { hub: 'plant_hub', slave: 2, address: 100, count: 1, inputType: 'holding' },
|
||||
});
|
||||
expect(readCommand).toEqual({
|
||||
type: 'read_register',
|
||||
hub: 'plant_hub',
|
||||
hubId: 'plant_hub',
|
||||
unitId: 2,
|
||||
entityId: undefined,
|
||||
deviceId: undefined,
|
||||
uniqueId: undefined,
|
||||
address: 100,
|
||||
count: 1,
|
||||
inputType: 'holding',
|
||||
dataType: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
export default tap.start();
|
||||
Reference in New Issue
Block a user