94 lines
3.8 KiB
TypeScript
94 lines
3.8 KiB
TypeScript
|
|
import { expect, tap } from '@git.zone/tstest/tapbundle';
|
||
|
|
import { BoschShcIntegration } from '../../ts/integrations/bosch_shc/index.js';
|
||
|
|
import type { IBoschShcModeledCommand, IBoschShcSnapshot } from '../../ts/integrations/bosch_shc/index.js';
|
||
|
|
|
||
|
|
const snapshot: IBoschShcSnapshot = {
|
||
|
|
host: '192.168.1.10',
|
||
|
|
devices: [
|
||
|
|
{ id: 'hdm:ZigBee:plug', rootDeviceId: 'AA:BB:CC:DD:EE:FF', deviceModel: 'PSM', manufacturer: 'BOSCH', serial: 'PSM123', name: 'Kitchen Plug', status: 'AVAILABLE', profile: 'GENERIC', deviceServiceIds: ['PowerSwitch'] },
|
||
|
|
{ id: 'shutter:living', rootDeviceId: 'AA:BB:CC:DD:EE:FF', deviceModel: 'BBL', manufacturer: 'BOSCH', serial: 'BBL123', name: 'Living Shutter', status: 'AVAILABLE', profile: 'GENERIC', deviceServiceIds: ['ShutterControl'] },
|
||
|
|
],
|
||
|
|
services: [
|
||
|
|
{ id: 'PowerSwitch', deviceId: 'hdm:ZigBee:plug', state: { '@type': 'powerSwitchState', switchState: 'ON', automaticPowerOffTime: 0 } },
|
||
|
|
{ id: 'ShutterControl', deviceId: 'shutter:living', state: { '@type': 'shutterControlState', operationState: 'STOPPED', level: 0.5, calibrated: true } },
|
||
|
|
],
|
||
|
|
};
|
||
|
|
|
||
|
|
tap.test('runs modeled Bosch SHC service commands through an injected executor', async () => {
|
||
|
|
const calls: IBoschShcModeledCommand[] = [];
|
||
|
|
const runtime = await new BoschShcIntegration().setup({
|
||
|
|
host: '192.168.1.10',
|
||
|
|
snapshot,
|
||
|
|
executor: async (commandArg) => {
|
||
|
|
calls.push(commandArg);
|
||
|
|
return { ok: true };
|
||
|
|
},
|
||
|
|
}, {});
|
||
|
|
|
||
|
|
const result = await runtime.callService?.({
|
||
|
|
domain: 'switch',
|
||
|
|
service: 'turn_off',
|
||
|
|
target: { entityId: 'switch.kitchen_plug' },
|
||
|
|
});
|
||
|
|
expect(result?.success).toBeTrue();
|
||
|
|
expect(calls[0].action).toEqual('put_device_service_state');
|
||
|
|
expect(calls[0].path).toEqual('/devices/hdm:ZigBee:plug/services/PowerSwitch/state');
|
||
|
|
expect(calls[0].body).toEqual({ '@type': 'powerSwitchState', switchState: 'OFF' });
|
||
|
|
|
||
|
|
const coverResult = await runtime.callService?.({
|
||
|
|
domain: 'cover',
|
||
|
|
service: 'set_cover_position',
|
||
|
|
target: { entityId: 'cover.living_shutter' },
|
||
|
|
data: { position: 75 },
|
||
|
|
});
|
||
|
|
expect(coverResult?.success).toBeTrue();
|
||
|
|
expect(calls[1].body).toEqual({ '@type': 'shutterControlState', level: 0.75 });
|
||
|
|
await runtime.destroy();
|
||
|
|
});
|
||
|
|
|
||
|
|
tap.test('returns clear unsupported errors without executor for writes and pairing', async () => {
|
||
|
|
const runtime = await new BoschShcIntegration().setup({ host: '192.168.1.10', snapshot }, {});
|
||
|
|
const result = await runtime.callService?.({
|
||
|
|
domain: 'switch',
|
||
|
|
service: 'turn_on',
|
||
|
|
target: { entityId: 'switch.kitchen_plug' },
|
||
|
|
});
|
||
|
|
expect(result?.success).toBeFalse();
|
||
|
|
expect(result?.error).toContain('requires config.snapshot or an injected executor');
|
||
|
|
|
||
|
|
const pairResult = await runtime.callService?.({
|
||
|
|
domain: 'bosch_shc',
|
||
|
|
service: 'pair_client',
|
||
|
|
target: {},
|
||
|
|
data: { system_password: 'secret' },
|
||
|
|
});
|
||
|
|
expect(pairResult?.success).toBeFalse();
|
||
|
|
expect(pairResult?.error).toContain('pairing transport');
|
||
|
|
await runtime.destroy();
|
||
|
|
});
|
||
|
|
|
||
|
|
tap.test('models Bosch SHC pairing only through an injected executor', async () => {
|
||
|
|
const calls: IBoschShcModeledCommand[] = [];
|
||
|
|
const runtime = await new BoschShcIntegration().setup({
|
||
|
|
host: '192.168.1.10',
|
||
|
|
executor: async (commandArg) => {
|
||
|
|
calls.push(commandArg);
|
||
|
|
return { token: 'token:bosch-shc' };
|
||
|
|
},
|
||
|
|
}, {});
|
||
|
|
const result = await runtime.callService?.({
|
||
|
|
domain: 'bosch_shc',
|
||
|
|
service: 'pair_client',
|
||
|
|
target: {},
|
||
|
|
data: { system_password: 'secret', client_id: 'homeassistant', client_name: 'HomeAssistant' },
|
||
|
|
});
|
||
|
|
|
||
|
|
expect(result?.success).toBeTrue();
|
||
|
|
expect(calls[0].action).toEqual('pair_client');
|
||
|
|
expect(calls[0].sensitiveFields).toEqual(['systemPassword', 'certificatePem']);
|
||
|
|
expect(calls[0].body?.clientName).toEqual('HomeAssistant');
|
||
|
|
await runtime.destroy();
|
||
|
|
});
|
||
|
|
|
||
|
|
export default tap.start();
|