Add native camera and media service integrations

This commit is contained in:
2026-05-05 17:13:54 +00:00
parent 489d9d5243
commit e7441844c9
112 changed files with 18608 additions and 327 deletions
@@ -0,0 +1,32 @@
import { expect, tap } from '@git.zone/tstest/tapbundle';
import { createRainbirdDiscoveryDescriptor } from '../../ts/integrations/rainbird/index.js';
tap.test('matches manual Rain Bird setup entries', async () => {
const descriptor = createRainbirdDiscoveryDescriptor();
const matcher = descriptor.getMatchers().find((matcherArg) => matcherArg.id === 'rainbird-manual-match');
const result = await matcher!.matches({
host: '192.168.1.40',
protocol: 'http',
macAddress: 'AA:BB:CC:12:34:56',
model: 'Rain Bird ESP-TM2',
}, {});
expect(result.matched).toBeTrue();
expect(result.normalizedDeviceId).toEqual('aabbcc123456');
expect(result.candidate?.integrationDomain).toEqual('rainbird');
expect(result.candidate?.port).toEqual(80);
});
tap.test('validates Rain Bird candidates', async () => {
const descriptor = createRainbirdDiscoveryDescriptor();
const validator = descriptor.getValidators()[0];
const result = await validator.validate({
source: 'manual',
integrationDomain: 'rainbird',
host: 'rainbird.local',
manufacturer: 'Rain Bird',
}, {});
expect(result.matched).toBeTrue();
expect(result.candidate?.manufacturer).toEqual('Rain Bird');
});
export default tap.start();
@@ -0,0 +1,68 @@
import { expect, tap } from '@git.zone/tstest/tapbundle';
import { RainbirdMapper, type IRainbirdSnapshot } from '../../ts/integrations/rainbird/index.js';
const snapshot: IRainbirdSnapshot = {
controller: {
id: 'aabbcc123456',
name: 'Backyard Controller',
manufacturer: 'Rain Bird',
modelName: 'ESP-TM2',
macAddress: 'aabbcc123456',
rainSensorActive: false,
rainDelayDays: 2,
host: '192.168.1.40',
},
zones: [
{ id: 1, name: 'Front Lawn', active: true, defaultDurationMinutes: 10 },
{ id: 2, name: 'Back Beds', active: false, defaultDurationMinutes: 8 },
],
programs: [{
id: 0,
name: 'PGM A',
enabled: true,
starts: ['06:00'],
frequency: 'custom',
zoneDurations: [{ zoneId: 1, durationMinutes: 10 }, { zoneId: 2, durationMinutes: 8 }],
}],
events: [],
connected: true,
updatedAt: '2026-01-01T00:00:00.000Z',
};
tap.test('maps Rain Bird zones and programs to canonical devices and entities', async () => {
const devices = RainbirdMapper.toDevices(snapshot);
const entities = RainbirdMapper.toEntities(snapshot);
expect(devices.some((deviceArg) => deviceArg.id === 'rainbird.controller.aabbcc123456')).toBeTrue();
expect(devices.some((deviceArg) => deviceArg.id === 'rainbird.zone.aabbcc123456.1')).toBeTrue();
expect(devices.some((deviceArg) => deviceArg.id === 'rainbird.program.aabbcc123456.0')).toBeTrue();
expect(entities.some((entityArg) => entityArg.id === 'switch.front_lawn' && entityArg.state === 'on')).toBeTrue();
expect(entities.some((entityArg) => entityArg.id === 'sensor.pgm_a')).toBeTrue();
expect(entities.some((entityArg) => entityArg.id === 'sensor.raindelay' && entityArg.state === 2)).toBeTrue();
});
tap.test('maps Rain Bird services to controller commands', async () => {
const startCommand = RainbirdMapper.commandForService(snapshot, {
domain: 'rainbird',
service: 'start_zone',
target: {},
data: { zoneId: 2, duration: 7 },
});
expect(startCommand).toEqual({ type: 'start_zone', zoneId: 2, durationMinutes: 7, entityId: undefined, deviceId: undefined });
const switchCommand = RainbirdMapper.commandForService(snapshot, {
domain: 'switch',
service: 'turn_off',
target: { entityId: 'switch.front_lawn' },
});
expect(switchCommand).toEqual({ type: 'stop_zone', zoneId: 1, entityId: 'switch.front_lawn', deviceId: undefined });
const rainDelayCommand = RainbirdMapper.commandForService(snapshot, {
domain: 'rainbird',
service: 'set_rain_delay',
target: {},
data: { duration: 4 },
});
expect(rainDelayCommand).toEqual({ type: 'set_rain_delay', days: 4, entityId: undefined, deviceId: undefined });
});
export default tap.start();