Skip to content

Commit

Permalink
feat: Add Support for device_info and device.services
Browse files Browse the repository at this point in the history
[pyatv 0.10.3 Chica](https://github.com/postlund/pyatv/releases/tag/v0.10.3) added two new fields to atvscript, `device_info` and `services`. Both fields are also supported by `node-pyatv` with this version. The methods `model()`, `modelName()`, `os()`, `version()` and `services()` are available for this purpose.
  • Loading branch information
sebbo2002 committed Aug 4, 2022
1 parent f64c0db commit 1f60980
Show file tree
Hide file tree
Showing 6 changed files with 319 additions and 20 deletions.
62 changes: 62 additions & 0 deletions src/lib/device.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
NodePyATVMediaType,
NodePyATVProtocol,
NodePyATVRepeatState,
NodePyATVService,
NodePyATVShuffleState,
NodePyATVState
} from './types.js';
Expand Down Expand Up @@ -74,6 +75,67 @@ export default class NodePyATVDevice implements EventEmitter{
return this.options.protocol;
}

/**
* Get the model identifier of the device. Only set, if the
* device was found using [[find()]]. Requires pyatv ≧ 0.10.3.
*
* @example device.model → "Gen4K"
*/
get model(): string | undefined {
return this.options.model;
}

/**
* Get the model name of the device. Only set, if the device
* was found with [[find()]]. Requires pyatv ≧ 0.10.3.
*
* @example device.modelName → "Apple TV 4K"
*/
get modelName(): string | undefined {
return this.options.modelName;
}

/**
* Get the operating system of the device. Only set, if the
* device was found with [[find()]]. Requires pyatv ≧ 0.10.3.
*
* @example device.os → "TvOS"
*/
get os(): string | undefined {
return this.options.os;
}

/**
* Get the device version. Only set, if the device was found
* during a scan using [[find()]]. Requires pyatv ≧ 0.10.3.
*
* @example device.version → "15.5.1"
*/
get version(): string | undefined {
return this.options.version;
}

/**
* Returns a list of services supported by the device. Ony set, if
* the device was found during a scan using [[find()]]. Requires
* pyatv ≧ 0.10.3.
*
* @example device.services → [
* {
* "protocol": "airplay",
* "port": 7000
* },
* {
* "protocol": "dmap",
* "port": 3689
* }
* ]
*/
get services(): NodePyATVService[] | undefined {
return this.options.services;
}


/**
* Returns true, if debugging is enabled. Returns the custom
* logging method, if one was specified. Otherwise, if debug
Expand Down
27 changes: 15 additions & 12 deletions src/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
'use strict';

export {
NodePyATVProtocol,
NodePyATVMediaType,
NodePyATVDeviceOptions,
NodePyATVDeviceState,
NodePyATVRepeatState,
NodePyATVShuffleState,
NodePyATVKeys,
NodePyATVInstanceOptions,
NodePyATVVersionResponse,
NodePyATVFindOptions,
NodePyATVEventValueType,
NodePyATVExecutableType,
NodePyATVFindAndInstanceOptions,
NodePyATVDeviceOptions,
NodePyATVFindOptions,
NodePyATVGetStateOptions,
NodePyATVState,
NodePyATVPowerState,
NodePyATVInstanceOptions,
NodePyATVKeys,
NodePyATVListenerState,
NodePyATVEventValueType,
NodePyATVMediaType,
NodePyATVPowerState,
NodePyATVProtocol,
NodePyATVRepeatState,
NodePyATVService,
NodePyATVShuffleState,
NodePyATVState,
NodePyATVVersionResponse
} from './types.js';

export {default as NodePyATVDeviceEvent} from './device-event.js';
export {default as NodePyATVDeviceEvents} from './device-events.js';
export {default as NodePyATVDevice} from './device.js';
export {default as NodePyATVInstance} from './instance.js';

export {default} from './instance.js';
10 changes: 8 additions & 2 deletions src/lib/instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
NodePyATVExecutableType,
NodePyATVFindAndInstanceOptions,
NodePyATVInstanceOptions,
NodePyATVInternalScanDevice,
NodePyATVVersionResponse
} from './types.js';

Expand Down Expand Up @@ -117,11 +118,16 @@ export default class NodePyATVInstance {
throw new Error(`Unable to parse pyatv response: ${JSON.stringify(result, null, ' ')}`);
}

const objects = result.devices.map((device: { address: string, identifier: string, name: string }) =>
const objects = result.devices.map((device: NodePyATVInternalScanDevice) =>
this.device(Object.assign({}, options, {
host: device.address,
id: device.identifier,
name: device.name
name: device.name,
model: device.device_info?.model,
modelName: device.device_info?.model_str,
os: device.device_info?.operating_system,
version: device.device_info?.version,
services: device.services
}))
);

Expand Down
26 changes: 26 additions & 0 deletions src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,12 +147,38 @@ export interface NodePyATVFindAndInstanceOptions extends NodePyATVInstanceOption
export interface NodePyATVDeviceOptions extends NodePyATVFindAndInstanceOptions {
host: string;
name: string;
model?: string;
modelName?: string;
os?: string;
version?: string;
services?: NodePyATVService[];
}

export interface NodePyATVGetStateOptions {
maxAge?: number;
}

export interface NodePyATVService {
protocol: NodePyATVProtocol;
port: number;
}

/**
* @internal
*/
export interface NodePyATVInternalScanDevice {
name: string;
address: string;
identifier: string;
device_info?: {
model: string;
model_str: string;
operating_system: string;
version: string;
};
services?: NodePyATVService[];
}

/**
* @internal
*/
Expand Down
125 changes: 124 additions & 1 deletion test/device.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
NodePyATVShuffleState
} from '../src/lib/types.js';
import NodePyATVInstance from '../src/lib/instance.js';
import {createFakeSpawn} from '../src/lib/fake-spawn.js';
import { createFakeSpawn } from '../src/lib/fake-spawn.js';

describe('NodePyATVDevice', function () {
describe('get name()', function () {
Expand Down Expand Up @@ -60,6 +60,129 @@ describe('NodePyATVDevice', function () {
});
});

describe('get model()', function () {
it('should return the model if set by scan', function () {
const device = new NodePyATVDevice({
name: 'Vardagsrum',
host: '10.0.10.81',
id: 'xxx',
model: 'Gen4K'
});

assert.strictEqual(device.model, 'Gen4K');
});
it('should return undefined otherwise', function () {
const device = new NodePyATVDevice({
name: 'Vardagsrum',
host: '10.0.10.81'
});

assert.strictEqual(device.model, undefined);
});
});

describe('get modelName()', function () {
it('should return the model name if set by scan', function () {
const device = new NodePyATVDevice({
name: 'Vardagsrum',
host: '10.0.10.81',
id: 'xxx',
modelName: 'Apple TV 4K'
});

assert.strictEqual(device.modelName, 'Apple TV 4K');
});
it('should return undefined otherwise', function () {
const device = new NodePyATVDevice({
name: 'Vardagsrum',
host: '10.0.10.81'
});

assert.strictEqual(device.modelName, undefined);
});
});

describe('get os()', function () {
it('should return the operating system if set by scan', function () {
const device = new NodePyATVDevice({
name: 'Vardagsrum',
host: '10.0.10.81',
id: 'xxx',
os: 'TvOS'
});

assert.strictEqual(device.os, 'TvOS');
});
it('should return undefined otherwise', function () {
const device = new NodePyATVDevice({
name: 'Vardagsrum',
host: '10.0.10.81'
});

assert.strictEqual(device.os, undefined);
});
});

describe('get version()', function () {
it('should return the version if set by scan', function () {
const device = new NodePyATVDevice({
name: 'Vardagsrum',
host: '10.0.10.81',
id: 'xxx',
version: '15.5.1'
});

assert.strictEqual(device.version, '15.5.1');
});
it('should return undefined otherwise', function () {
const device = new NodePyATVDevice({
name: 'Vardagsrum',
host: '10.0.10.81'
});

assert.strictEqual(device.version, undefined);
});
});

describe('get services()', function () {
it('should return the services if set by scan', function () {
const device = new NodePyATVDevice({
name: 'Vardagsrum',
host: '10.0.10.81',
id: 'xxx',
services: [
{
protocol: NodePyATVProtocol.mrp,
port: 49152
},
{
protocol: NodePyATVProtocol.airplay,
port: 7000
}
]
});

assert.deepStrictEqual(device.services, [
{
protocol: 'mrp',
port: 49152
},
{
protocol: 'airplay',
port: 7000
}
]);
});
it('should return undefined otherwise', function () {
const device = new NodePyATVDevice({
name: 'Vardagsrum',
host: '10.0.10.81'
});

assert.strictEqual(device.services, undefined);
});
});

describe('get debug()', function () {
it('should return true if set to true', function () {
const device = new NodePyATVDevice({
Expand Down
Loading

0 comments on commit 1f60980

Please sign in to comment.