116 lines
4.3 KiB
Markdown
116 lines
4.3 KiB
Markdown
# Device Manager - Implementation Notes
|
|
|
|
## Architecture Overview
|
|
|
|
The device manager uses a **UniversalDevice** architecture with composable features.
|
|
|
|
### Key Concepts
|
|
|
|
- **UniversalDevice**: A single device class that can have multiple features attached
|
|
- **Features**: Composable capabilities (scan, print, playback, volume, power, snmp, smart home, etc.)
|
|
- **Protocols**: Low-level protocol implementations (eSCL, SANE, IPP, SNMP, NUT, UPnP, Home Assistant)
|
|
|
|
## Key Files
|
|
|
|
### Core (`ts/`)
|
|
- `devicemanager.classes.devicemanager.ts` - Main DeviceManager class with discovery and device registry
|
|
- `device/device.classes.device.ts` - UniversalDevice class with feature management
|
|
|
|
### Features (`ts/features/`)
|
|
- `feature.abstract.ts` - Base Feature class with connection management and retry logic
|
|
- `feature.scan.ts` - Scanning via eSCL/SANE protocols
|
|
- `feature.print.ts` - Printing via IPP protocol
|
|
- `feature.playback.ts` - Media playback (Sonos, AirPlay, Chromecast, DLNA)
|
|
- `feature.volume.ts` - Volume control (separate from playback)
|
|
- `feature.power.ts` - UPS/power monitoring via NUT/SNMP
|
|
- `feature.snmp.ts` - SNMP queries
|
|
- `feature.light.ts` - Smart light control
|
|
- `feature.switch.ts` - Smart switch control
|
|
- `feature.sensor.ts` - Smart sensors
|
|
- `feature.climate.ts` - Climate/HVAC control
|
|
- `feature.cover.ts` - Blinds, garage doors
|
|
- `feature.lock.ts` - Smart locks
|
|
- `feature.fan.ts` - Fan control
|
|
- `feature.camera.ts` - Camera control
|
|
|
|
### Protocols (`ts/protocols/`)
|
|
- `protocol.escl.ts` - eSCL/AirScan scanner protocol
|
|
- `protocol.sane.ts` - SANE network scanner protocol
|
|
- `protocol.ipp.ts` - IPP printer protocol
|
|
- `protocol.snmp.ts` - SNMP queries
|
|
- `protocol.nut.ts` - Network UPS Tools protocol
|
|
- `protocol.upnp.ts` - UPnP/SOAP client
|
|
- `protocol.upssnmp.ts` - UPS-specific SNMP
|
|
- `protocol.homeassistant.ts` - Home Assistant WebSocket API
|
|
|
|
### Discovery (`ts/discovery/`)
|
|
- `discovery.classes.mdns.ts` - mDNS discovery (Bonjour)
|
|
- `discovery.classes.ssdp.ts` - SSDP/UPnP discovery
|
|
- `discovery.classes.networkscanner.ts` - Active network scanning
|
|
- `discovery.classes.homeassistant.ts` - Home Assistant instance discovery
|
|
|
|
### Factories (`ts/factories/`)
|
|
- `index.ts` - Device factory functions for creating pre-configured devices:
|
|
- `createScanner`, `createPrinter`, `createSpeaker`, `createDlnaRenderer`
|
|
- `createSnmpDevice`, `createUpsDevice`
|
|
- Smart home: `createSmartLight`, `createSmartSwitch`, `createSmartSensor`, etc.
|
|
|
|
### Interfaces (`ts/interfaces/`)
|
|
- `feature.interfaces.ts` - All feature-related types and interfaces
|
|
- `smarthome.interfaces.ts` - Smart home specific interfaces
|
|
- `homeassistant.interfaces.ts` - Home Assistant API types
|
|
- `index.ts` - Re-exports all interfaces
|
|
|
|
## Feature Types
|
|
|
|
```typescript
|
|
type TFeatureType =
|
|
| 'scan' | 'print' | 'fax' | 'copy'
|
|
| 'playback' | 'volume' | 'power' | 'snmp'
|
|
| 'dlna-render' | 'dlna-serve'
|
|
| 'light' | 'climate' | 'sensor' | 'camera'
|
|
| 'cover' | 'switch' | 'lock' | 'fan';
|
|
```
|
|
|
|
## DeviceManager API
|
|
|
|
```typescript
|
|
// Query by features
|
|
dm.getDevices(); // All devices
|
|
dm.getDevices({ hasFeature: 'scan' }); // Devices with scan feature
|
|
dm.getDevices({ name: 'Brother' }); // Devices matching name
|
|
dm.getDevicesWithFeatures(['scan', 'print']); // Devices with ALL features
|
|
dm.getDevicesWithAnyFeature(['playback', 'volume']); // Devices with ANY feature
|
|
|
|
// Select (throws if not found)
|
|
dm.selectDevice({ address: '192.168.1.100' });
|
|
|
|
// Discovery
|
|
dm.discoverScanners('192.168.1.0/24');
|
|
dm.discoverPrinters('192.168.1.0/24');
|
|
dm.scanNetwork({ ipRange: '...', probeEscl: true, ... });
|
|
dm.startDiscovery(); // mDNS/SSDP
|
|
dm.stopDiscovery();
|
|
```
|
|
|
|
## UniversalDevice API
|
|
|
|
```typescript
|
|
// Feature access
|
|
device.hasFeature('scan');
|
|
device.getFeature<ScanFeature>('scan'); // Returns undefined if not found
|
|
device.selectFeature<ScanFeature>('scan'); // Throws if not found
|
|
device.getFeatureTypes(); // ['scan', 'print', ...]
|
|
|
|
// Connection
|
|
await device.connect(); // Connect all features
|
|
await device.disconnect(); // Disconnect all features
|
|
```
|
|
|
|
## Testing Notes
|
|
|
|
- Test files use `@git.zone/tstest` with tap-based assertions
|
|
- Import `expect` from `@git.zone/tstest/tapbundle`
|
|
- Tests are in `test/` directory
|
|
- Run with `pnpm test` or `tstest test/test.some.ts --verbose`
|