import { expect, tap } from '@git.zone/tstest/tapbundle'; import { RflinkClient, RflinkMapper } from '../../ts/integrations/rflink/index.js'; import type { IRflinkSnapshot } from '../../ts/integrations/rflink/index.js'; const snapshot: IRflinkSnapshot = { gateway: { id: 'rflink-gateway', name: 'Nodo RFLink', connectionType: 'tcp', host: '192.168.1.34', port: 1234, firmware: 'RFLink Gateway', version: '1.1', revision: '46', online: true, }, connected: true, updatedAt: '2026-05-05T00:00:00.000Z', devices: [], events: [], entities: [ { id: 'newkaku_0000c6c2_1', platform: 'light', name: 'Kitchen Lamp', type: 'hybrid', state: 'on', brightness: 170, aliases: ['kaku_000001_a'] }, { id: 'conrad_00785c_0a', platform: 'switch', name: 'Ceiling Fan', state: 'off' }, { id: 'alectov1_0334_temp', platform: 'sensor', name: 'Outdoor Temperature', sensorType: 'temperature', value: 7.4, unitOfMeasurement: '°C' }, { id: 'pt2262_00174754_0', platform: 'binary_sensor', name: 'PIR Entrance', deviceClass: 'motion', state: 'on' }, { id: 'newkaku_0a8720_0', platform: 'cover', name: 'Office Blind', type: 'inverted', state: 'closed' }, ], }; tap.test('maps RFLink snapshots to gateway and RF device definitions', async () => { const devices = RflinkMapper.toDevices(snapshot); expect(devices.length).toEqual(6); expect(devices[0].id).toEqual('rflink.gateway.rflink_gateway'); expect(devices.find((deviceArg) => deviceArg.id === 'rflink.light.newkaku_0000c6c2_1')?.features.some((featureArg) => featureArg.id === 'brightness')).toBeTrue(); expect(devices.find((deviceArg) => deviceArg.id === 'rflink.sensor.alectov1_0334_temp')?.state[0].value).toEqual(7.4); }); tap.test('maps RFLink entities to Home Assistant-style platforms', async () => { const entities = RflinkMapper.toEntities(snapshot); expect(entities.map((entityArg) => entityArg.platform)).toContain('light'); expect(entities.map((entityArg) => entityArg.platform)).toContain('switch'); expect(entities.map((entityArg) => entityArg.platform)).toContain('sensor'); expect(entities.map((entityArg) => entityArg.platform)).toContain('binary_sensor'); expect(entities.map((entityArg) => entityArg.platform)).toContain('cover'); expect(entities.find((entityArg) => entityArg.id === 'sensor.outdoor_temperature')?.attributes?.unitOfMeasurement).toEqual('°C'); expect(entities.find((entityArg) => entityArg.id === 'cover.office_blind')?.state).toEqual('closed'); }); tap.test('maps RFLink services to line protocol commands', async () => { const closeCommand = RflinkMapper.commandForService(snapshot, { domain: 'cover', service: 'close_cover', target: { entityId: 'cover.office_blind' }, data: {}, }); expect(closeCommand?.rflinkCommand).toEqual('UP'); expect(RflinkClient.commandShape(closeCommand?.deviceId || '', closeCommand?.rflinkCommand || '').line).toEqual('10;newkaku;0a8720;0;UP;'); const dimCommand = RflinkMapper.commandForService(snapshot, { domain: 'light', service: 'turn_on', target: { entityId: 'light.kitchen_lamp' }, data: { brightness: 128 }, }); expect(dimCommand?.type).toEqual('set_value'); expect(dimCommand?.rflinkCommand).toEqual('7'); }); tap.test('decodes RFLink sensor line packets into events', async () => { const packet = RflinkClient.decodeLine('20;00;Alecto V1;ID=0334;TEMP=004a;HUM=26;BAT=OK;'); const events = packet ? RflinkClient.eventsFromPacket(packet) : []; expect(events.find((eventArg) => eventArg.id === 'alectov1_0334_temp')?.value).toEqual(7.4); expect(events.find((eventArg) => eventArg.id === 'alectov1_0334_hum')?.value).toEqual(26); }); export default tap.start();