registry: Speaker, StepSpeaker, EqualizerController, PlaybackController, PlaybackStateReporter, InputController, ChannelController

Seven descriptors written from their pages replace seven stubs. All are version 3; 1.5.2 announced Speaker,
StepSpeaker, EqualizerController and PlaybackStateReporter as version 1, and all but ChannelController without
a property. StepSpeaker has no properties object in discovery and PlaybackController one without fields, next
to supportedOperations; a directive for an operation the device did not list is answered with
INVALID_DIRECTIVE. The equalizer declares bands, modes or both under "configurations", a TV its inputs from
the 61 names of the page.

Not described: the lineup of ChannelController, whose discovery example the page folds away. The discovery
examples of InputController spell one key "friendNames"; the fixtures have friendlyNames, as its table does.
62 examples of the six pages are saved as fixtures. 241 tests pass, 215 before.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
David 2026-09-28 20:54:53 +00:00
parent c59cf3ff10
commit d7dfc5b122
113 changed files with 3948 additions and 47 deletions

View file

@ -0,0 +1,31 @@
{
"directive": {
"header": {
"namespace": "Alexa.ChannelController",
"name": "ChangeChannel",
"messageId": "Unique version 4 UUID",
"correlationToken": "Opaque correlation token",
"payloadVersion": "3"
},
"endpoint": {
"scope": {
"type": "BearerToken",
"token": "OAuth2.0 bearer token"
},
"endpointId": "Endpoint ID",
"cookie": {}
},
"payload": {
"channel": {
"number": "9",
"callSign": "KCTS-TV",
"affiliateCallSign": "KCTS",
"uri": "channel uri"
},
"channelMetadata": {
"name": "Alternate channel name",
"image": "url for image"
}
}
}
}

View file

@ -0,0 +1,37 @@
{
"event": {
"header": {
"namespace": "Alexa",
"name": "Response",
"messageId": "Unique identifier, preferably a version 4 UUID",
"correlationToken": "Opaque correlation token that matches the request",
"payloadVersion": "3"
},
"endpoint": {
"endpointId": "Endpoint ID"
},
"payload": {}
},
"context": {
"properties": [
{
"namespace": "Alexa.ChannelController",
"name": "channel",
"value": {
"number": "9",
"callSign": "KCTS-TV",
"affiliateCallSign": "KCTS"
},
"timeOfSample": "2017-02-03T16:20:50.52Z",
"uncertaintyInMilliseconds": 0
},
{
"namespace": "Alexa.PowerController",
"name": "powerState",
"value": "ON",
"timeOfSample": "2017-02-03T16:18:40.12Z",
"uncertaintyInMilliseconds": 500
}
]
}
}

View file

@ -0,0 +1,57 @@
{
"event": {
"header": {
"namespace": "Alexa",
"name": "ChangeReport",
"messageId": "Unique identifier, preferably a version 4 UUID",
"payloadVersion": "3"
},
"endpoint": {
"scope": {
"type": "BearerToken",
"token": "OAuth2.0 bearer token"
},
"endpointId": "Endpoint ID"
},
"payload": {
"change": {
"cause": {
"type": "VOICE_INTERACTION"
},
"properties": [
{
"namespace": "Alexa.ChannelController",
"name": "channel",
"value": {
"number": "9",
"callSign": "KCTS-TV",
"affiliateCallSign": "KCTS"
},
"timeOfSample": "2017-02-03T16:20:50.52Z",
"uncertaintyInMilliseconds": 0
}
]
}
}
},
"context": {
"properties": [
{
"namespace": "Alexa.PowerController",
"name": "powerState",
"value": "ON",
"timeOfSample": "2017-02-03T16:18:40.12Z",
"uncertaintyInMilliseconds": 500
},
{
"namespace": "Alexa.EndpointHealth",
"name": "connectivity",
"value": {
"value": "OK"
},
"timeOfSample": "2017-02-03T16:15:00.00Z",
"uncertaintyInMilliseconds": 0
}
]
}
}

View file

@ -0,0 +1,14 @@
{
"directive": {
"header": {
"namespace": "Alexa.ChannelController",
"name": "SkipChannels",
"messageId": "Unique version 4 UUID",
"correlationToken": "Opaque correlation token",
"payloadVersion": "3"
},
"payload": {
"channelCount": 1
}
}
}

View file

@ -0,0 +1,37 @@
{
"event": {
"header": {
"namespace": "Alexa",
"name": "Response",
"messageId": "Unique identifier, preferably a version 4 UUID",
"correlationToken": "Opaque correlation token that matches the request",
"payloadVersion": "3"
},
"endpoint": {
"endpointId": "Endpoint ID"
},
"payload": {}
},
"context": {
"properties": [
{
"namespace": "Alexa.ChannelController",
"name": "channel",
"value": {
"number": "7",
"callSign": "KIRO-TV",
"affiliateCallSign": "KIRO"
},
"timeOfSample": "2017-02-03T16:25:50.52Z",
"uncertaintyInMilliseconds": 0
},
{
"namespace": "Alexa.PowerController",
"name": "powerState",
"value": "ON",
"timeOfSample": "2017-02-03T16:18:40.12Z",
"uncertaintyInMilliseconds": 500
}
]
}
}

View file

@ -0,0 +1,50 @@
{
"event": {
"header": {
"namespace": "Alexa",
"name": "StateReport",
"messageId": "Unique identifier, preferably a version 4 UUID",
"correlationToken": "Opaque correlation token that matches the request",
"payloadVersion": "3"
},
"endpoint": {
"scope": {
"type": "BearerToken",
"token": "OAuth2.0 bearer token"
},
"endpointId": "Endpoint ID"
},
"payload": {}
},
"context": {
"properties": [
{
"namespace": "Alexa.ChannelController",
"name": "channel",
"value": {
"number": "7",
"callSign": "KIRO-TV",
"affiliateCallSign": "KIRO"
},
"timeOfSample": "2017-02-03T17:00:50.52Z",
"uncertaintyInMilliseconds": 0
},
{
"namespace": "Alexa.PowerController",
"name": "powerState",
"value": "ON",
"timeOfSample": "2017-02-03T16:18:40.12Z",
"uncertaintyInMilliseconds": 500
},
{
"namespace": "Alexa.EndpointHealth",
"name": "connectivity",
"value": {
"value": "OK"
},
"timeOfSample": "2017-02-03T16:15:00.00Z",
"uncertaintyInMilliseconds": 0
}
]
}
}

View file

@ -0,0 +1,8 @@
{
"name": "channel",
"value": {
"number": "9",
"callSign": "KCTS-TV",
"affiliateCallSign": "KCTS"
}
}

View file

@ -0,0 +1,69 @@
{
"event": {
"header": {
"namespace": "Alexa.Discovery",
"name": "AddOrUpdateReport",
"payloadVersion": "3",
"messageId": "Unique identifier, preferably a version 4 UUID"
},
"payload": {
"endpoints": [
{
"endpointId": "unique ID of the new endpoint",
"manufacturerName": "Manufacturer of the endpoint",
"description": "Description to be shown in the Alexa app",
"friendlyName": "Living Room TV",
"displayCategories": [
"TV"
],
"additionalAttributes": {
"manufacturer": "Manufacturer of the endpoint",
"model": "Model of the device",
"serialNumber": "Serial number of the device",
"firmwareVersion": "Firmware version of the device",
"softwareVersion": "Software version of the device"
},
"capabilities": [
{
"type": "AlexaInterface",
"interface": "Alexa.ChannelController",
"version": "3",
"properties": {
"supported": [
{
"name": "channel"
}
],
"proactivelyReported": true,
"retrievable": true
}
},
{
"type": "AlexaInterface",
"interface": "Alexa.EndpointHealth",
"version": "3.1",
"properties": {
"supported": [
{
"name": "connectivity"
}
],
"proactivelyReported": true,
"retrievable": true
}
},
{
"type": "AlexaInterface",
"interface": "Alexa",
"version": "3"
}
]
}
],
"scope": {
"type": "BearerToken",
"token": "access-token-from-Amazon"
}
}
}
}

View file

@ -0,0 +1,28 @@
{
"directive": {
"header": {
"namespace": "Alexa.EqualizerController",
"name": "AdjustBands",
"messageId": "Unique version 4 UUID",
"correlationToken": "Opaque correlation token",
"payloadVersion": "3"
},
"endpoint": {
"scope": {
"type": "BearerToken",
"token": "OAuth2.0 bearer token"
},
"endpointId": "Endpoint ID",
"cookie": {}
},
"payload": {
"bands": [
{
"name": "BASS",
"levelDelta": 3,
"levelDirection": "UP"
}
]
}
}
}

View file

@ -0,0 +1,57 @@
{
"event": {
"header": {
"namespace": "Alexa",
"name": "Response",
"messageId": "Unique identifier, preferably a version 4 UUID",
"correlationToken": "Opaque correlation token that matches the request",
"payloadVersion": "3"
},
"endpoint": {
"scope": {
"type": "BearerToken",
"token": "OAuth2.0 bearer token"
},
"endpointId": "Endpoint ID"
},
"payload": {}
},
"context": {
"properties": [
{
"namespace": "Alexa.EqualizerController",
"name": "mode",
"value": "MOVIE",
"timeOfSample": "2017-02-03T16:32:50.52Z",
"uncertaintyInMilliseconds": 0
},
{
"namespace": "Alexa.EqualizerController",
"name": "bands",
"value": [
{
"name": "BASS",
"value": 1
},
{
"name": "MIDRANGE",
"value": 3
},
{
"name": "TREBLE",
"value": 1
}
],
"timeOfSample": "2017-02-03T16:20:50.52Z",
"uncertaintyInMilliseconds": 0
},
{
"namespace": "Alexa.PowerController",
"name": "powerState",
"value": "ON",
"timeOfSample": "2017-02-03T16:18:40.12Z",
"uncertaintyInMilliseconds": 500
}
]
}
}

View file

@ -0,0 +1,64 @@
{
"event": {
"header": {
"namespace": "Alexa",
"name": "ChangeReport",
"messageId": "Unique identifier, preferably a version 4 UUID",
"payloadVersion": "3"
},
"endpoint": {
"scope": {
"type": "BearerToken",
"token": "OAuth2.0 bearer token"
},
"endpointId": "Endpoint ID"
},
"payload": {
"change": {
"cause": {
"type": "VOICE_INTERACTION"
},
"properties": [
{
"namespace": "Alexa.EqualizerController",
"name": "mode",
"value": "SPORT",
"timeOfSample": "2017-02-03T18:20:50.52Z",
"uncertaintyInMilliseconds": 0
}
]
}
}
},
"context": {
"properties": [
{
"namespace": "Alexa.EqualizerController",
"name": "bands",
"value": [
{
"name": "BASS",
"value": 0
},
{
"name": "MIDRANGE",
"value": 3
},
{
"name": "TREBLE",
"value": 1
}
],
"timeOfSample": "2017-02-03T16:20:50.52Z",
"uncertaintyInMilliseconds": 0
},
{
"namespace": "Alexa.PowerController",
"name": "powerState",
"value": "ON",
"timeOfSample": "2017-02-03T16:18:40.12Z",
"uncertaintyInMilliseconds": 500
}
]
}
}

View file

@ -0,0 +1,32 @@
{
"directive": {
"header": {
"namespace": "Alexa.EqualizerController",
"name": "ResetBands",
"messageId": "Unique version 4 UUID",
"correlationToken": "Opaque correlation token",
"payloadVersion": "3"
},
"endpoint": {
"scope": {
"type": "BearerToken",
"token": "OAuth2.0 bearer token"
},
"endpointId": "Endpoint ID",
"cookie": {}
},
"payload": {
"bands": [
{
"name": "BASS"
},
{
"name": "MIDRANGE"
},
{
"name": "TREBLE"
}
]
}
}
}

View file

@ -0,0 +1,57 @@
{
"event": {
"header": {
"namespace": "Alexa",
"name": "Response",
"messageId": "Unique identifier, preferably a version 4 UUID",
"correlationToken": "Opaque correlation token that matches the request",
"payloadVersion": "3"
},
"endpoint": {
"scope": {
"type": "BearerToken",
"token": "OAuth2.0 bearer token"
},
"endpointId": "Endpoint ID"
},
"payload": {}
},
"context": {
"properties": [
{
"namespace": "Alexa.EqualizerController",
"name": "mode",
"value": "MOVIE",
"timeOfSample": "2017-02-03T16:40:50.52Z",
"uncertaintyInMilliseconds": 0
},
{
"namespace": "Alexa.EqualizerController",
"name": "bands",
"value": [
{
"name": "BASS",
"value": 0
},
{
"name": "MIDRANGE",
"value": 3
},
{
"name": "TREBLE",
"value": 1
}
],
"timeOfSample": "2017-02-03T16:20:50.52Z",
"uncertaintyInMilliseconds": 0
},
{
"namespace": "Alexa.PowerController",
"name": "powerState",
"value": "ON",
"timeOfSample": "2017-02-03T16:18:40.12Z",
"uncertaintyInMilliseconds": 500
}
]
}
}

View file

@ -0,0 +1,27 @@
{
"directive": {
"header": {
"namespace": "Alexa.EqualizerController",
"name": "SetBands",
"messageId": "Unique version 4 UUID",
"correlationToken": "Opaque correlation token",
"payloadVersion": "3"
},
"endpoint": {
"scope": {
"type": "BearerToken",
"token": "OAuth2.0 bearer token"
},
"endpointId": "Endpoint ID",
"cookie": {}
},
"payload": {
"bands": [
{
"name": "BASS",
"value": -2
}
]
}
}
}

View file

@ -0,0 +1,57 @@
{
"event": {
"header": {
"namespace": "Alexa",
"name": "Response",
"messageId": "Unique identifier, preferably a version 4 UUID",
"correlationToken": "Opaque correlation token that matches the request",
"payloadVersion": "3"
},
"endpoint": {
"scope": {
"type": "BearerToken",
"token": "OAuth2.0 bearer token"
},
"endpointId": "Endpoint ID"
},
"payload": {}
},
"context": {
"properties": [
{
"namespace": "Alexa.EqualizerController",
"name": "mode",
"value": "MOVIE",
"timeOfSample": "2017-02-03T16:25:50.52Z",
"uncertaintyInMilliseconds": 0
},
{
"namespace": "Alexa.EqualizerController",
"name": "bands",
"value": [
{
"name": "BASS",
"value": -2
},
{
"name": "MIDRANGE",
"value": 3
},
{
"name": "TREBLE",
"value": 1
}
],
"timeOfSample": "2017-02-03T16:20:50.52Z",
"uncertaintyInMilliseconds": 0
},
{
"namespace": "Alexa.PowerController",
"name": "powerState",
"value": "ON",
"timeOfSample": "2017-02-03T16:18:40.12Z",
"uncertaintyInMilliseconds": 500
}
]
}
}

View file

@ -0,0 +1,22 @@
{
"directive": {
"header": {
"namespace": "Alexa.EqualizerController",
"name": "SetMode",
"messageId": "Unique version 4 UUID",
"correlationToken": "Opaque correlation token",
"payloadVersion": "3"
},
"endpoint": {
"scope": {
"type": "BearerToken",
"token": "OAuth2.0 bearer token"
},
"endpointId": "Endpoint ID",
"cookie": {}
},
"payload": {
"mode": "MOVIE"
}
}
}

View file

@ -0,0 +1,57 @@
{
"event": {
"header": {
"namespace": "Alexa",
"name": "Response",
"messageId": "Unique identifier, preferably a version 4 UUID",
"correlationToken": "Opaque correlation token that matches the request",
"payloadVersion": "3"
},
"endpoint": {
"scope": {
"type": "BearerToken",
"token": "OAuth2.0 bearer token"
},
"endpointId": "Endpoint ID"
},
"payload": {}
},
"context": {
"properties": [
{
"namespace": "Alexa.EqualizerController",
"name": "mode",
"value": "MOVIE",
"timeOfSample": "2017-02-03T16:20:50.52Z",
"uncertaintyInMilliseconds": 0
},
{
"namespace": "Alexa.EqualizerController",
"name": "bands",
"value": [
{
"name": "BASS",
"value": 0
},
{
"name": "MIDRANGE",
"value": 3
},
{
"name": "TREBLE",
"value": 1
}
],
"timeOfSample": "2017-02-03T16:20:30.52Z",
"uncertaintyInMilliseconds": 0
},
{
"namespace": "Alexa.PowerController",
"name": "powerState",
"value": "ON",
"timeOfSample": "2017-02-03T16:18:40.12Z",
"uncertaintyInMilliseconds": 500
}
]
}
}

View file

@ -0,0 +1,57 @@
{
"event": {
"header": {
"namespace": "Alexa",
"name": "StateReport",
"messageId": "Unique identifier, preferably a version 4 UUID",
"correlationToken": "Opaque correlation token that matches the request",
"payloadVersion": "3"
},
"endpoint": {
"scope": {
"type": "BearerToken",
"token": "OAuth2.0 bearer token"
},
"endpointId": "Endpoint ID"
},
"payload": {}
},
"context": {
"properties": [
{
"namespace": "Alexa.EqualizerController",
"name": "mode",
"value": "MOVIE",
"timeOfSample": "2017-02-03T17:50:50.52Z",
"uncertaintyInMilliseconds": 0
},
{
"namespace": "Alexa.EqualizerController",
"name": "bands",
"value": [
{
"name": "BASS",
"value": 0
},
{
"name": "MIDRANGE",
"value": 3
},
{
"name": "TREBLE",
"value": 1
}
],
"timeOfSample": "2017-02-03T16:20:50.52Z",
"uncertaintyInMilliseconds": 0
},
{
"namespace": "Alexa.PowerController",
"name": "powerState",
"value": "ON",
"timeOfSample": "2017-02-03T16:18:40.12Z",
"uncertaintyInMilliseconds": 500
}
]
}
}

View file

@ -0,0 +1,17 @@
{
"name": "bands",
"value": [
{
"name": "BASS",
"value": 0
},
{
"name": "MIDRANGE",
"value": 3
},
{
"name": "TREBLE",
"value": 1
}
]
}

View file

@ -0,0 +1,94 @@
{
"event": {
"header": {
"namespace": "Alexa.Discovery",
"name": "Discover.Response",
"payloadVersion": "3",
"messageId": "Unique identifier, preferably a version 4 UUID"
},
"payload": {
"endpoints": [
{
"endpointId": "Unique ID of the endpoint",
"manufacturerName": "Manufacturer of the endpoint",
"description": "Smart Television by Television Maker",
"friendlyName": "Living Room TV",
"displayCategories": [
"TV"
],
"cookie": {},
"capabilities": [
{
"type": "AlexaInterface",
"interface": "Alexa.EqualizerController",
"version": "3",
"properties": {
"supported": [
{
"name": "bands"
},
{
"name": "mode"
}
],
"retrievable": true,
"proactivelyReported": true
},
"configurations": {
"bands": {
"supported": [
{
"name": "BASS"
},
{
"name": "MIDRANGE"
},
{
"name": "TREBLE"
}
],
"range": {
"minimum": -6,
"maximum": 6
}
},
"modes": {
"supported": [
{
"name": "MOVIE"
},
{
"name": "MUSIC"
},
{
"name": "SPORT"
}
]
}
}
},
{
"type": "AlexaInterface",
"interface": "Alexa.PowerController",
"version": "3",
"properties": {
"supported": [
{
"name": "powerState"
}
],
"retrievable": true,
"proactivelyReported": true
}
},
{
"type": "AlexaInterface",
"interface": "Alexa",
"version": "3"
}
]
}
]
}
}
}

View file

@ -0,0 +1,4 @@
{
"name": "mode",
"value": "MOVIE"
}

View file

@ -0,0 +1,53 @@
{
"event": {
"header": {
"namespace": "Alexa",
"name": "ChangeReport",
"messageId": "Unique identifier, preferably a version 4 UUID",
"payloadVersion": "3"
},
"endpoint": {
"scope": {
"type": "BearerToken",
"token": "OAuth2.0 bearer token"
},
"endpointId": "Endpoint ID"
},
"payload": {
"change": {
"cause": {
"type": "VOICE_INTERACTION"
},
"properties": [
{
"namespace": "Alexa.InputController",
"name": "input",
"value": "HDMI 2",
"timeOfSample": "2017-02-03T16:40:50.52Z",
"uncertaintyInMilliseconds": 0
}
]
}
}
},
"context": {
"properties": [
{
"namespace": "Alexa.PowerController",
"name": "powerState",
"value": "ON",
"timeOfSample": "2017-02-03T16:18:40.12Z",
"uncertaintyInMilliseconds": 500
},
{
"namespace": "Alexa.EndpointHealth",
"name": "connectivity",
"value": {
"value": "OK"
},
"timeOfSample": "2017-02-03T16:15:40.12Z",
"uncertaintyInMilliseconds": 0
}
]
}
}

View file

@ -0,0 +1,22 @@
{
"directive": {
"header": {
"namespace": "Alexa.InputController",
"name": "SelectInput",
"messageId": "Unique version 4 UUID",
"correlationToken": "Opaque correlation token",
"payloadVersion": "3"
},
"endpoint": {
"scope": {
"type": "BearerToken",
"token": "OAuth2.0 bearer token"
},
"endpointId": "Endpoint ID",
"cookie": {}
},
"payload": {
"input": "HDMI 1"
}
}
}

View file

@ -0,0 +1,42 @@
{
"event": {
"header": {
"namespace": "Alexa",
"name": "Response",
"messageId": "Unique identifier, preferably a version 4 UUID",
"correlationToken": "Opaque correlation token that matches the request",
"payloadVersion": "3"
},
"endpoint": {
"endpointId": "Endpoint ID"
},
"payload": {}
},
"context": {
"properties": [
{
"namespace": "Alexa.InputController",
"name": "input",
"value": "HDMI 1",
"timeOfSample": "2017-02-03T16:20:50.52Z",
"uncertaintyInMilliseconds": 0
},
{
"namespace": "Alexa.PowerController",
"name": "powerState",
"value": "ON",
"timeOfSample": "2017-02-03T16:18:40.12Z",
"uncertaintyInMilliseconds": 500
},
{
"namespace": "Alexa.EndpointHealth",
"name": "connectivity",
"value": {
"value": "OK"
},
"timeOfSample": "2017-02-03T16:15:40.12Z",
"uncertaintyInMilliseconds": 0
}
]
}
}

View file

@ -0,0 +1,46 @@
{
"event": {
"header": {
"namespace": "Alexa",
"name": "StateReport",
"messageId": "Unique identifier, preferably a version 4 UUID",
"correlationToken": "Opaque correlation token that matches the request",
"payloadVersion": "3"
},
"endpoint": {
"scope": {
"type": "BearerToken",
"token": "OAuth2.0 bearer token"
},
"endpointId": "Endpoint ID"
},
"payload": {}
},
"context": {
"properties": [
{
"namespace": "Alexa.InputController",
"name": "input",
"value": "HDMI 1",
"timeOfSample": "2017-02-03T16:20:50.52Z",
"uncertaintyInMilliseconds": 0
},
{
"namespace": "Alexa.PowerController",
"name": "powerState",
"value": "ON",
"timeOfSample": "2017-02-03T16:20:50.52Z",
"uncertaintyInMilliseconds": 500
},
{
"namespace": "Alexa.EndpointHealth",
"name": "connectivity",
"value": {
"value": "OK"
},
"timeOfSample": "2017-02-03T16:20:50Z",
"uncertaintyInMilliseconds": 0
}
]
}
}

View file

@ -0,0 +1,83 @@
{
"event": {
"header": {
"namespace": "Alexa.Discovery",
"name": "AddOrUpdateReport",
"payloadVersion": "3",
"messageId": "Unique identifier, preferably a version 4 UUID"
},
"payload": {
"endpoints": [
{
"endpointId": "Unique ID of the endpoint",
"manufacturerName": "Manufacturer of the endpoint",
"description": "Smart Television by Television Maker",
"friendlyName": "Living Room TV",
"displayCategories": [
"TV"
],
"cookie": {},
"capabilities": [
{
"type": "AlexaInterface",
"interface": "Alexa.InputController",
"version": "3",
"properties": {
"supported": [
{
"name": "input"
}
],
"proactivelyReported": true,
"retrievable": true
},
"inputs": [
{
"name": "HDMI 1",
"friendlyNames": [
"AnyCompany TV"
]
},
{
"name": "HDMI 2",
"friendlyNames": [
"Cable",
"AnyCompany Cable"
]
},
{
"name": "AUX 1",
"friendlyNames": [
"DVD Player"
]
},
{
"name": "AUX 2"
}
]
},
{
"type": "AlexaInterface",
"interface": "Alexa.PowerController",
"version": "3",
"properties": {
"supported": [
{
"name": "powerState"
}
],
"proactivelyReported": true,
"retrievable": true
}
},
{
"type": "AlexaInterface",
"interface": "Alexa",
"version": "3"
}
]
}
]
}
}
}

View file

@ -0,0 +1,88 @@
{
"event": {
"header": {
"namespace": "Alexa.Discovery",
"name": "Discover.Response",
"payloadVersion": "3",
"messageId": "Unique identifier, preferably a version 4 UUID"
},
"payload": {
"endpoints": [
{
"endpointId": "Unique ID of the endpoint",
"manufacturerName": "Manufacturer name of the endpoint",
"description": "Smart Television by Television Maker",
"friendlyName": "Living Room TV",
"displayCategories": [
"TV"
],
"cookie": {},
"capabilities": [
{
"type": "AlexaInterface",
"interface": "Alexa.InputController",
"version": "3",
"properties": {
"supported": [
{
"name": "input"
}
],
"proactivelyReported": true,
"retrievable": true
},
"inputs": [
{
"name": "HDMI 1",
"friendlyNames": [
"AnyCompany TV"
]
},
{
"name": "HDMI 2",
"friendlyNames": [
"Cable",
"AnyCompany Cable"
]
}
]
},
{
"type": "AlexaInterface",
"interface": "Alexa.PowerController",
"version": "3",
"properties": {
"supported": [
{
"name": "powerState"
}
],
"proactivelyReported": true,
"retrievable": true
}
},
{
"type": "AlexaInterface",
"interface": "Alexa.EndpointHealth",
"version": "3.1",
"properties": {
"supported": [
{
"name": "connectivity"
}
],
"proactivelyReported": true,
"retrievable": true
}
},
{
"type": "AlexaInterface",
"interface": "Alexa",
"version": "3"
}
]
}
]
}
}
}

View file

@ -0,0 +1,48 @@
{
"event": {
"header": {
"namespace": "Alexa",
"name": "ChangeReport",
"messageId": "Unique identifier, preferably a version 4 UUID",
"payloadVersion": "3"
},
"endpoint": {
"scope": {
"type": "BearerToken",
"token": "OAuth2.0 bearer token"
},
"endpointId": "endpoint id"
},
"payload": {
"change": {
"cause": {
"type": "PHYSICAL_INTERACTION"
},
"properties": [
{
"namespace": "Alexa.PlaybackStateReporter",
"name": "playbackState",
"value": {
"state": "STOPPED"
},
"timeOfSample": "2021-12-01T18:20:00.00Z",
"uncertaintyInMilliseconds": 500
}
]
}
}
},
"context": {
"properties": [
{
"namespace": "Alexa.EndpointHealth",
"name": "connectivity",
"value": {
"value": "OK"
},
"timeOfSample": "2021-12-01T18:00:00.00Z",
"uncertaintyInMilliseconds": 0
}
]
}
}

View file

@ -0,0 +1,20 @@
{
"directive": {
"header": {
"namespace": "Alexa.PlaybackController",
"name": "FastForward",
"messageId": "Unique version 4 UUID",
"correlationToken": "Opaque correlation token",
"payloadVersion": "3"
},
"endpoint": {
"scope": {
"type": "BearerToken",
"token": "OAuth2.0 bearer token"
},
"endpointId": "Endpoint id",
"cookie": {}
},
"payload": {}
}
}

View file

@ -0,0 +1,37 @@
{
"event": {
"header": {
"namespace": "Alexa",
"name": "Response",
"messageId": "Unique identifier, preferably a version 4 UUID",
"correlationToken": "Opaque correlation token that matches the request",
"payloadVersion": "3"
},
"endpoint": {
"endpointId": "endpoint id"
},
"payload": {}
},
"context": {
"properties": [
{
"namespace": "Alexa.PlaybackStateReporter",
"name": "playbackState",
"value": {
"state": "PAUSED"
},
"timeOfSample": "2021-12-01T18:20:00.00Z",
"uncertaintyInMilliseconds": 0
},
{
"namespace": "Alexa.EndpointHealth",
"name": "connectivity",
"value": {
"value": "OK"
},
"timeOfSample": "2021-12-01T18:20:00.00Z",
"uncertaintyInMilliseconds": 0
}
]
}
}

View file

@ -0,0 +1,20 @@
{
"directive": {
"header": {
"namespace": "Alexa.PlaybackController",
"name": "Next",
"messageId": "Unique version 4 UUID",
"correlationToken": "Opaque correlation token",
"payloadVersion": "3"
},
"endpoint": {
"scope": {
"type": "BearerToken",
"token": "OAuth2.0 bearer token"
},
"endpointId": "Endpoint id",
"cookie": {}
},
"payload": {}
}
}

View file

@ -0,0 +1,37 @@
{
"event": {
"header": {
"namespace": "Alexa",
"name": "Response",
"messageId": "Unique identifier, preferably a version 4 UUID",
"correlationToken": "Opaque correlation token that matches the request",
"payloadVersion": "3"
},
"endpoint": {
"endpointId": "endpoint id"
},
"payload": {}
},
"context": {
"properties": [
{
"namespace": "Alexa.PlaybackStateReporter",
"name": "playbackState",
"value": {
"state": "STOPPED"
},
"timeOfSample": "2021-12-01T18:20:00.00Z",
"uncertaintyInMilliseconds": 0
},
{
"namespace": "Alexa.EndpointHealth",
"name": "connectivity",
"value": {
"value": "OK"
},
"timeOfSample": "2021-12-01T18:00:00.00Z",
"uncertaintyInMilliseconds": 0
}
]
}
}

View file

@ -0,0 +1,20 @@
{
"directive": {
"header": {
"namespace": "Alexa.PlaybackController",
"name": "Pause",
"messageId": "Unique version 4 UUID",
"correlationToken": "Opaque correlation token",
"payloadVersion": "3"
},
"endpoint": {
"scope": {
"type": "BearerToken",
"token": "OAuth2.0 bearer token"
},
"endpointId": "Endpoint id",
"cookie": {}
},
"payload": {}
}
}

View file

@ -0,0 +1,37 @@
{
"event": {
"header": {
"namespace": "Alexa",
"name": "Response",
"messageId": "Unique identifier, preferably a version 4 UUID",
"correlationToken": "Opaque correlation token that matches the request",
"payloadVersion": "3"
},
"endpoint": {
"endpointId": "endpoint id"
},
"payload": {}
},
"context": {
"properties": [
{
"namespace": "Alexa.PlaybackStateReporter",
"name": "playbackState",
"value": {
"state": "PAUSED"
},
"timeOfSample": "2021-12-01T18:20:00.00Z",
"uncertaintyInMilliseconds": 0
},
{
"namespace": "Alexa.EndpointHealth",
"name": "connectivity",
"value": {
"value": "OK"
},
"timeOfSample": "2021-12-01T18:00:00.00Z",
"uncertaintyInMilliseconds": 0
}
]
}
}

View file

@ -0,0 +1,20 @@
{
"directive": {
"header": {
"namespace": "Alexa.PlaybackController",
"name": "Play",
"messageId": "Unique version 4 UUID",
"correlationToken": "Opaque correlation token",
"payloadVersion": "3"
},
"endpoint": {
"scope": {
"type": "BearerToken",
"token": "OAuth2.0 bearer token"
},
"endpointId": "Endpoint id",
"cookie": {}
},
"payload": {}
}
}

View file

@ -0,0 +1,37 @@
{
"event": {
"header": {
"namespace": "Alexa",
"name": "Response",
"messageId": "Unique identifier, preferably a version 4 UUID",
"correlationToken": "Opaque correlation token that matches the request",
"payloadVersion": "3"
},
"endpoint": {
"endpointId": "endpoint id"
},
"payload": {}
},
"context": {
"properties": [
{
"namespace": "Alexa.PlaybackStateReporter",
"name": "playbackState",
"value": {
"state": "PLAYING"
},
"timeOfSample": "2021-12-01T18:20:00.00Z",
"uncertaintyInMilliseconds": 0
},
{
"namespace": "Alexa.EndpointHealth",
"name": "connectivity",
"value": {
"value": "OK"
},
"timeOfSample": "2021-12-01T18:00:00.00Z",
"uncertaintyInMilliseconds": 0
}
]
}
}

View file

@ -0,0 +1,20 @@
{
"directive": {
"header": {
"namespace": "Alexa.PlaybackController",
"name": "Previous",
"messageId": "Unique version 4 UUID",
"correlationToken": "Opaque correlation token",
"payloadVersion": "3"
},
"endpoint": {
"scope": {
"type": "BearerToken",
"token": "OAuth2.0 bearer token"
},
"endpointId": "Endpoint id",
"cookie": {}
},
"payload": {}
}
}

View file

@ -0,0 +1,37 @@
{
"event": {
"header": {
"namespace": "Alexa",
"name": "Response",
"messageId": "Unique identifier, preferably a version 4 UUID",
"correlationToken": "Opaque correlation token that matches the request",
"payloadVersion": "3"
},
"endpoint": {
"endpointId": "endpoint id"
},
"payload": {}
},
"context": {
"properties": [
{
"namespace": "Alexa.PlaybackStateReporter",
"name": "playbackState",
"value": {
"state": "STOPPED"
},
"timeOfSample": "2021-12-01T18:20:00.00Z",
"uncertaintyInMilliseconds": 0
},
{
"namespace": "Alexa.EndpointHealth",
"name": "connectivity",
"value": {
"value": "OK"
},
"timeOfSample": "2021-12-01T18:00:00.00Z",
"uncertaintyInMilliseconds": 0
}
]
}
}

View file

@ -0,0 +1,20 @@
{
"directive": {
"header": {
"namespace": "Alexa.PlaybackController",
"name": "Rewind",
"messageId": "Unique version 4 UUID",
"correlationToken": "Opaque correlation token",
"payloadVersion": "3"
},
"endpoint": {
"scope": {
"type": "BearerToken",
"token": "OAuth2.0 bearer token"
},
"endpointId": "Endpoint id",
"cookie": {}
},
"payload": {}
}
}

View file

@ -0,0 +1,37 @@
{
"event": {
"header": {
"namespace": "Alexa",
"name": "Response",
"messageId": "Unique identifier, preferably a version 4 UUID",
"correlationToken": "Opaque correlation token that matches the request",
"payloadVersion": "3"
},
"endpoint": {
"endpointId": "endpoint id"
},
"payload": {}
},
"context": {
"properties": [
{
"namespace": "Alexa.PlaybackStateReporter",
"name": "playbackState",
"value": {
"state": "PAUSED"
},
"timeOfSample": "2021-12-01T18:20:00.00Z",
"uncertaintyInMilliseconds": 0
},
{
"namespace": "Alexa.EndpointHealth",
"name": "connectivity",
"value": {
"value": "OK"
},
"timeOfSample": "2021-12-01T18:00:00.00Z",
"uncertaintyInMilliseconds": 0
}
]
}
}

View file

@ -0,0 +1,20 @@
{
"directive": {
"header": {
"namespace": "Alexa.PlaybackController",
"name": "StartOver",
"messageId": "Unique version 4 UUID",
"correlationToken": "Opaque correlation token",
"payloadVersion": "3"
},
"endpoint": {
"scope": {
"type": "BearerToken",
"token": "OAuth2.0 bearer token"
},
"endpointId": "Endpoint id",
"cookie": {}
},
"payload": {}
}
}

View file

@ -0,0 +1,37 @@
{
"event": {
"header": {
"namespace": "Alexa",
"name": "Response",
"messageId": "Unique identifier, preferably a version 4 UUID",
"correlationToken": "Opaque correlation token that matches the request",
"payloadVersion": "3"
},
"endpoint": {
"endpointId": "endpoint id"
},
"payload": {}
},
"context": {
"properties": [
{
"namespace": "Alexa.PlaybackStateReporter",
"name": "playbackState",
"value": {
"state": "PLAYING"
},
"timeOfSample": "2021-12-01T18:20:00.00Z",
"uncertaintyInMilliseconds": 0
},
{
"namespace": "Alexa.EndpointHealth",
"name": "connectivity",
"value": {
"value": "OK"
},
"timeOfSample": "2021-12-01T18:00:00.00Z",
"uncertaintyInMilliseconds": 0
}
]
}
}

View file

@ -0,0 +1,37 @@
{
"event": {
"header": {
"namespace": "Alexa",
"name": "StateReport",
"messageId": "Unique identifier, preferably a version 4 UUID",
"correlationToken": "Opaque correlation token that matches the request",
"payloadVersion": "3"
},
"endpoint": {
"endpointId": "endpoint id"
},
"payload": {}
},
"context": {
"properties": [
{
"namespace": "Alexa.PlaybackStateReporter",
"name": "playbackState",
"value": {
"state": "PLAYING"
},
"timeOfSample": "2021-12-01T18:20:00.00Z",
"uncertaintyInMilliseconds": 500
},
{
"namespace": "Alexa.EndpointHealth",
"name": "connectivity",
"value": {
"value": "OK"
},
"timeOfSample": "2021-12-01T18:00:00.00Z",
"uncertaintyInMilliseconds": 0
}
]
}
}

View file

@ -0,0 +1,20 @@
{
"directive": {
"header": {
"namespace": "Alexa.PlaybackController",
"name": "Stop",
"messageId": "Unique version 4 UUID",
"correlationToken": "Opaque correlation token",
"payloadVersion": "3"
},
"endpoint": {
"scope": {
"type": "BearerToken",
"token": "OAuth2.0 bearer token"
},
"endpointId": "Endpoint id",
"cookie": {}
},
"payload": {}
}
}

View file

@ -0,0 +1,37 @@
{
"event": {
"header": {
"namespace": "Alexa",
"name": "Response",
"messageId": "Unique identifier, preferably a version 4 UUID",
"correlationToken": "Opaque correlation token that matches the request",
"payloadVersion": "3"
},
"endpoint": {
"endpointId": "endpoint id"
},
"payload": {}
},
"context": {
"properties": [
{
"namespace": "Alexa.PlaybackStateReporter",
"name": "playbackState",
"value": {
"state": "STOPPED"
},
"timeOfSample": "2021-12-01T18:20:00.00Z",
"uncertaintyInMilliseconds": 0
},
{
"namespace": "Alexa.EndpointHealth",
"name": "connectivity",
"value": {
"value": "OK"
},
"timeOfSample": "2021-12-01T18:00:00.00Z",
"uncertaintyInMilliseconds": 0
}
]
}
}

View file

@ -0,0 +1,81 @@
{
"event": {
"header": {
"namespace": "Alexa.Discovery",
"name": "Discover.Response",
"payloadVersion": "3",
"messageId": "Unique identifier, preferably a version 4 UUID"
},
"payload": {
"endpoints": [
{
"endpointId": "Unique ID of the endpoint",
"manufacturerName": "Manufacturer of the endpoint",
"description": "Description to be shown in the Alexa app",
"friendlyName": "Living Room TV",
"displayCategories": [
"TV"
],
"additionalAttributes": {
"manufacturer": "Manufacturer of the endpoint",
"model": "Model of the device",
"serialNumber": "Serial number of the device",
"firmwareVersion": "Firmware version of the device",
"softwareVersion": "Software version of the device"
},
"capabilities": [
{
"type": "AlexaInterface",
"interface": "Alexa.PlaybackController",
"version": "3",
"properties": {},
"supportedOperations": [
"Play",
"Pause",
"Stop",
"Next",
"Previous",
"FastForward",
"Rewind",
"StartOver"
]
},
{
"type": "AlexaInterface",
"interface": "Alexa.PlaybackStateReporter",
"version": "3",
"properties": {
"supported": [
{
"name": "playbackState"
}
],
"proactivelyReported": true,
"retrievable": true
}
},
{
"type": "AlexaInterface",
"interface": "Alexa.EndpointHealth",
"version": "3.1",
"properties": {
"supported": [
{
"name": "connectivity"
}
],
"proactivelyReported": true,
"retrievable": true
}
},
{
"type": "AlexaInterface",
"interface": "Alexa",
"version": "3"
}
]
}
]
}
}
}

View file

@ -0,0 +1,23 @@
{
"directive": {
"header": {
"namespace": "Alexa.Speaker",
"name": "AdjustVolume",
"messageId": "Unique version 4 UUID",
"correlationToken": "Opaque correlation token",
"payloadVersion": "3"
},
"endpoint": {
"scope": {
"type": "BearerToken",
"token": "OAuth2.0 bearer token"
},
"endpointId": "Endpoint ID",
"cookie": {}
},
"payload": {
"volume": -20,
"volumeDefault": false
}
}
}

View file

@ -0,0 +1,40 @@
{
"event": {
"header": {
"namespace": "Alexa",
"name": "Response",
"messageId": "Unique identifier, preferably a version 4 UUID",
"correlationToken": "Opaque correlation token that matches the request",
"payloadVersion": "3"
},
"endpoint": {
"endpointId": "Endpoint ID"
},
"payload": {}
},
"context": {
"properties": [
{
"namespace": "Alexa.Speaker",
"name": "volume",
"value": 30,
"timeOfSample": "2017-02-03T16:20:50.52Z",
"uncertaintyInMilliseconds": 0
},
{
"namespace": "Alexa.Speaker",
"name": "muted",
"value": false,
"timeOfSample": "2017-02-03T16:20:50.52Z",
"uncertaintyInMilliseconds": 0
},
{
"namespace": "Alexa.PowerController",
"name": "powerState",
"value": "ON",
"timeOfSample": "2017-02-03T16:18:40.12Z",
"uncertaintyInMilliseconds": 500
}
]
}
}

View file

@ -0,0 +1,51 @@
{
"event": {
"header": {
"namespace": "Alexa",
"name": "ChangeReport",
"messageId": "Unique identifier, preferably a version 4 UUID",
"payloadVersion": "3"
},
"endpoint": {
"scope": {
"type": "BearerToken",
"token": "OAuth2.0 bearer token"
},
"endpointId": "Endpoint ID"
},
"payload": {
"change": {
"cause": {
"type": "VOICE_INTERACTION"
},
"properties": [
{
"namespace": "Alexa.Speaker",
"name": "volume",
"value": 40,
"timeOfSample": "2017-02-03T16:52:50.52Z",
"uncertaintyInMilliseconds": 0
}
]
}
}
},
"context": {
"properties": [
{
"namespace": "Alexa.Speaker",
"name": "muted",
"value": false,
"timeOfSample": "2017-02-03T16:20:50.52Z",
"uncertaintyInMilliseconds": 0
},
{
"namespace": "Alexa.PowerController",
"name": "powerState",
"value": "ON",
"timeOfSample": "2017-02-03T16:18:40.12Z",
"uncertaintyInMilliseconds": 500
}
]
}
}

View file

@ -0,0 +1,22 @@
{
"directive": {
"header": {
"namespace": "Alexa.Speaker",
"name": "SetMute",
"messageId": "Unique version 4 UUID",
"correlationToken": "Opaque correlation token",
"payloadVersion": "3"
},
"endpoint": {
"scope": {
"type": "BearerToken",
"token": "OAuth2.0 bearer token"
},
"endpointId": "Endpoint ID",
"cookie": {}
},
"payload": {
"mute": true
}
}
}

View file

@ -0,0 +1,40 @@
{
"event": {
"header": {
"namespace": "Alexa",
"name": "Response",
"messageId": "Unique identifier, preferably a version 4 UUID",
"correlationToken": "Opaque correlation token that matches the request",
"payloadVersion": "3"
},
"endpoint": {
"endpointId": "Endpoint ID"
},
"payload": {}
},
"context": {
"properties": [
{
"namespace": "Alexa.Speaker",
"name": "volume",
"value": 30,
"timeOfSample": "2017-02-03T16:20:50.52Z",
"uncertaintyInMilliseconds": 0
},
{
"namespace": "Alexa.Speaker",
"name": "muted",
"value": true,
"timeOfSample": "2017-02-03T16:20:50.52Z",
"uncertaintyInMilliseconds": 0
},
{
"namespace": "Alexa.PowerController",
"name": "powerState",
"value": "ON",
"timeOfSample": "2017-02-03T16:18:40.12Z",
"uncertaintyInMilliseconds": 500
}
]
}
}

View file

@ -0,0 +1,22 @@
{
"directive": {
"header": {
"namespace": "Alexa.Speaker",
"name": "SetVolume",
"messageId": "Unique version 4 UUID",
"correlationToken": "Opaque correlation token",
"payloadVersion": "3"
},
"endpoint": {
"scope": {
"type": "BearerToken",
"token": "OAuth2.0 bearer token"
},
"endpointId": "Endpoint ID",
"cookie": {}
},
"payload": {
"volume": 50
}
}
}

View file

@ -0,0 +1,40 @@
{
"event": {
"header": {
"namespace": "Alexa",
"name": "Response",
"messageId": "Unique identifier, preferably a version 4 UUID",
"correlationToken": "Opaque correlation token that matches the request",
"payloadVersion": "3"
},
"endpoint": {
"endpointId": "Endpoint ID"
},
"payload": {}
},
"context": {
"properties": [
{
"namespace": "Alexa.Speaker",
"name": "volume",
"value": 50,
"timeOfSample": "2017-02-03T16:20:50.52Z",
"uncertaintyInMilliseconds": 0
},
{
"namespace": "Alexa.Speaker",
"name": "muted",
"value": false,
"timeOfSample": "2017-02-03T16:20:50.52Z",
"uncertaintyInMilliseconds": 0
},
{
"namespace": "Alexa.PowerController",
"name": "powerState",
"value": "ON",
"timeOfSample": "2017-02-03T16:18:40.12Z",
"uncertaintyInMilliseconds": 500
}
]
}
}

View file

@ -0,0 +1,44 @@
{
"event": {
"header": {
"namespace": "Alexa",
"name": "StateReport",
"messageId": "Unique identifier, preferably a version 4 UUID",
"correlationToken": "Opaque correlation token that matches the request",
"payloadVersion": "3"
},
"endpoint": {
"scope": {
"type": "BearerToken",
"token": "OAuth2.0 bearer token"
},
"endpointId": "Endpoint ID"
},
"payload": {}
},
"context": {
"properties": [
{
"namespace": "Alexa.Speaker",
"name": "volume",
"value": 30,
"timeOfSample": "2017-02-03T16:20:50.52Z",
"uncertaintyInMilliseconds": 0
},
{
"namespace": "Alexa.Speaker",
"name": "muted",
"value": false,
"timeOfSample": "2017-02-03T16:20:50.52Z",
"uncertaintyInMilliseconds": 0
},
{
"namespace": "Alexa.PowerController",
"name": "powerState",
"value": "ON",
"timeOfSample": "2017-02-03T16:18:40.12Z",
"uncertaintyInMilliseconds": 500
}
]
}
}

View file

@ -0,0 +1,62 @@
{
"event": {
"header": {
"namespace": "Alexa.Discovery",
"name": "Discover.Response",
"payloadVersion": "3",
"messageId": "Unique identifier, preferably a version 4 UUID"
},
"payload": {
"endpoints": [
{
"endpointId": "Unique ID of the endpoint",
"manufacturerName": "Manufacturer of the endpoint",
"description": "Smart Speaker by Speaker Maker",
"friendlyName": "Computer speaker",
"displayCategories": [
"SPEAKER"
],
"cookie": {},
"capabilities": [
{
"type": "AlexaInterface",
"interface": "Alexa.Speaker",
"version": "3",
"properties": {
"supported": [
{
"name": "volume"
},
{
"name": "muted"
}
],
"retrievable": true,
"proactivelyReported": true
}
},
{
"type": "AlexaInterface",
"interface": "Alexa.PowerController",
"version": "3",
"properties": {
"supported": [
{
"name": "powerState"
}
],
"retrievable": true,
"proactivelyReported": true
}
},
{
"type": "AlexaInterface",
"interface": "Alexa",
"version": "3"
}
]
}
]
}
}
}

View file

@ -0,0 +1,4 @@
{
"name": "muted",
"value": false
}

View file

@ -0,0 +1,4 @@
{
"name": "volume",
"value": 50
}

View file

@ -0,0 +1,22 @@
{
"directive": {
"header": {
"namespace": "Alexa.StepSpeaker",
"name": "AdjustVolume",
"messageId": "Unique version 4 UUID",
"correlationToken": "Opaque correlation token",
"payloadVersion": "3"
},
"endpoint": {
"scope": {
"type": "BearerToken",
"token": "OAuth2.0 bearer token"
},
"endpointId": "Endpoint ID",
"cookie": {}
},
"payload": {
"volumeSteps": 20
}
}
}

View file

@ -0,0 +1,26 @@
{
"event": {
"header": {
"namespace": "Alexa",
"name": "Response",
"messageId": "Unique identifier, preferably a version 4 UUID",
"correlationToken": "Opaque correlation token that matches the request",
"payloadVersion": "3"
},
"endpoint": {
"endpointId": "Endpoint ID"
},
"payload": {}
},
"context": {
"properties": [
{
"namespace": "Alexa.PowerController",
"name": "powerState",
"value": "ON",
"timeOfSample": "2017-02-03T16:20:50.52Z",
"uncertaintyInMilliseconds": 500
}
]
}
}

View file

@ -0,0 +1,22 @@
{
"directive": {
"header": {
"namespace": "Alexa.StepSpeaker",
"name": "SetMute",
"messageId": "Unique version 4 UUID",
"correlationToken": "Opaque correlation token",
"payloadVersion": "3"
},
"endpoint": {
"scope": {
"type": "BearerToken",
"token": "OAuth2.0 bearer token"
},
"endpointId": "Endpoint ID",
"cookie": {}
},
"payload": {
"mute": true
}
}
}

View file

@ -0,0 +1,26 @@
{
"event": {
"header": {
"namespace": "Alexa",
"name": "Response",
"messageId": "Unique identifier, preferably a version 4 UUID",
"correlationToken": "Opaque correlation token that matches the request",
"payloadVersion": "3"
},
"endpoint": {
"endpointId": "Endpoint ID"
},
"payload": {}
},
"context": {
"properties": [
{
"namespace": "Alexa.PowerController",
"name": "powerState",
"value": "ON",
"timeOfSample": "2017-02-03T16:20:50.52Z",
"uncertaintyInMilliseconds": 500
}
]
}
}

View file

@ -0,0 +1,50 @@
{
"event": {
"header": {
"namespace": "Alexa.Discovery",
"name": "Discover.Response",
"payloadVersion": "3",
"messageId": "Unique identifier, preferably a version 4 UUID"
},
"payload": {
"endpoints": [
{
"endpointId": "Unique ID of the endpoint",
"manufacturerName": "Manufacturer of the endpoint",
"description": "Smart Speaker by Speaker Maker",
"friendlyName": "Computer speaker",
"displayCategories": [
"SPEAKER"
],
"cookie": {},
"capabilities": [
{
"type": "AlexaInterface",
"interface": "Alexa.StepSpeaker",
"version": "3"
},
{
"type": "AlexaInterface",
"interface": "Alexa.PowerController",
"version": "3",
"properties": {
"supported": [
{
"name": "powerState"
}
],
"retrievable": true,
"proactivelyReported": true
}
},
{
"type": "AlexaInterface",
"interface": "Alexa",
"version": "3"
}
]
}
]
}
}
}

View file

@ -27,6 +27,18 @@ const inThreeLanguages = (english, spanish, french) => [text(english, "en-US"),
module.exports = [
{ namespace: "Alexa", page: "alexa-interface", declared: [{ options: {}, example: "discovery" }] },
{
namespace: "Alexa.ChannelController",
page: "alexa-channelcontroller",
// The page folds its two discovery examples away; the one of its AddOrUpdateReport has the same endpoint
declared: [{ options: reported, example: "discovery-addOrUpdateReport" }],
refused: [
["ChangeChannel", { channel: { number: 9 } }, "payload.channel.number: expected a string, got 9"],
["ChangeChannel", { channel: "KCTS" }, 'payload.channel: expected an object with number, callSign, affiliateCallSign, uri, got "KCTS"'],
["SkipChannels", { channelCount: 1.5 }, "payload.channelCount: expected an integer, got 1.5"],
],
unfit: [["channel", "9"], ["channel", { number: 9 }]],
},
{ namespace: "Alexa.BrightnessController", page: "alexa-brightnesscontroller", declared: [{ options: reported, example: "discovery" }] },
{
namespace: "Alexa.ColorController",
@ -50,7 +62,44 @@ module.exports = [
},
{ namespace: "Alexa.ContactSensor", page: "alexa-contactsensor", declared, unfit: [["detectionState", "OPEN"], ["detectionState", true]] },
{ namespace: "Alexa.EndpointHealth", page: "alexa-endpointhealth", declared: [{ options: reported, example: "discovery" }] },
{
namespace: "Alexa.EqualizerController",
page: "alexa-equalizercontroller",
declared: [{
example: "discovery",
options: {
...reported,
bands: { supported: ["BASS", "MIDRANGE", "TREBLE"], range: { minimum: -6, maximum: 6 } },
modes: ["MOVIE", "MUSIC", "SPORT"],
},
}],
refused: [
["SetMode", { mode: "OPERA" }, 'payload.mode: expected MOVIE | MUSIC | NIGHT | SPORT | TV, got "OPERA"'],
["SetBands", { bands: [{ name: "BASS", value: 1.5 }] }, "payload.bands[0].value: expected an integer, got 1.5"],
["AdjustBands", { bands: [{ name: "BASS", levelDelta: 3 }] }, "payload.bands[0].levelDirection: expected UP | DOWN, got nothing"],
["ResetBands", { bands: [] }, "payload.bands: expected a list with 1 or more entries, got []"],
],
unfit: [["mode", "OPERA"], ["bands", { name: "BASS", value: 0 }], ["bands", [{ name: "SUB", value: 0 }]]],
},
{ namespace: "Alexa.HumiditySensor", page: "alexa-humiditysensor", declared, unfit: [["relativeHumidity", 45], ["relativeHumidity", { value: 101 }]] },
{
namespace: "Alexa.InputController",
page: "alexa-inputcontroller",
// The two discovery examples of the page spell the friendlyNames of HDMI 1 "friendNames". The fixtures have the
// name of the table of the page.
declared: [{
example: "discovery",
options: {
...reported,
inputs: [{ name: "HDMI 1", friendlyNames: ["AnyCompany TV"] }, { name: "HDMI 2", friendlyNames: ["Cable", "AnyCompany Cable"] }],
},
}],
refused: [
["SelectInput", { input: "HDMI 11" }, 'payload.input: expected an input like HDMI 1, got "HDMI 11"'],
["SelectInput", {}, "payload.input: expected an input like HDMI 1, got nothing"],
],
unfit: [["input", "hdmi 1"], ["input", 1]],
},
{
namespace: "Alexa.LockController",
page: "alexa-lockcontroller",
@ -70,6 +119,21 @@ module.exports = [
],
unfit: [["percentage", -1], ["percentage", 50.5]],
},
{
namespace: "Alexa.PlaybackController",
page: "alexa-playbackcontroller",
declared: [{
example: "discovery",
options: { supportedOperations: ["Play", "Pause", "Stop", "Next", "Previous", "FastForward", "Rewind", "StartOver"] },
}],
refused: [["Play", "now", 'payload: expected an object, got "now"']],
},
{
namespace: "Alexa.PlaybackStateReporter",
page: "alexa-playbackcontroller",
declared,
unfit: [["playbackState", "PLAYING"], ["playbackState", { state: "REWINDING" }]],
},
{ namespace: "Alexa.PowerController", page: "alexa-powercontroller", declared: [{ options: reported, example: "discovery" }] },
{
namespace: "Alexa.PowerLevelController",
@ -132,6 +196,26 @@ module.exports = [
],
unfit: [["armState", "ARMED"], ["burglaryAlarm", "ALARM"], ["fireAlarm", { value: "FIRE" }]],
},
{
namespace: "Alexa.Speaker",
page: "alexa-speaker",
declared,
refused: [
["SetVolume", { volume: 101 }, "payload.volume: expected an integer from 0 to 100, got 101"],
["AdjustVolume", { volume: -20 }, "payload.volumeDefault: expected true or false, got nothing"],
["SetMute", { mute: "yes" }, 'payload.mute: expected true or false, got "yes"'],
],
unfit: [["volume", 50.5], ["volume", -1], ["muted", "no"]],
},
{
namespace: "Alexa.StepSpeaker",
page: "alexa-stepspeaker",
declared: [{ options: {}, example: "discovery" }],
refused: [
["AdjustVolume", { volumeSteps: 101 }, "payload.volumeSteps: expected an integer from -100 to 100, got 101"],
["SetMute", {}, "payload.mute: expected true or false, got nothing"],
],
},
{ namespace: "Alexa.TemperatureSensor", page: "alexa-temperaturesensor", declared: [{ options: reported, example: "discovery" }] },
{
namespace: "Alexa.ThermostatController",

View file

@ -42,7 +42,8 @@ for (const { namespace, page, declared, unfit = [], chosen = false, folded = []
for (const capability of capabilities(from, namespace, example)) {
assert.equal(capability.version, descriptor.version, `${example}: version`);
assert.equal("instance" in capability, descriptor.instanced, `${example}: instance`);
const supported = capability.properties ? capability.properties.supported.map((property) => property.name) : [];
// Without a properties object, or with one without fields as the PlaybackController has: no property
const supported = ((capability.properties || {}).supported || []).map((property) => property.name);
const known = Object.keys(descriptor.properties);
assert.deepEqual(supported, chosen ? known.filter((name) => supported.includes(name)) : known, `${example}: properties`);
}

View file

@ -0,0 +1,108 @@
"use strict";
// The interfaces of a TV and a speaker: what the examples of their pages do not show. The examples themselves are
// run by descriptors.test.js, device/discovery.test.js and dispatch/interfaces.test.js.
const { test } = require("node:test");
const assert = require("node:assert/strict");
const {
Alex2MQTT, AlexaInterfaceType, DeclarationError, EqualizerController, InputController, Inputs, MemoryPublisher,
PlaybackController, PlaybackStateReporter, Speaker, StepSpeaker,
} = require("alex2node");
const { endpoint } = require("../helpers/endpoint.js");
const { directive } = require("../helpers/harness.js");
const tv = () => endpoint("tv-1", "TV", ["TV"]);
const refused = (descriptor, options, message) => assert.throws(
() => tv().add(descriptor, options),
(err) => err instanceof DeclarationError && err.message === `tv-1: ${descriptor.namespace}: ${message}`
);
test("1.x declarations: the version and the properties are those of the pages, where 1.5.2 had version 1 and no property", () => {
const T = AlexaInterfaceType;
const announced = (type) => {
const { version, properties } = tv().addCapability(type).getJSON();
return [version, properties && properties.supported];
};
assert.deepEqual(announced(T.SPEAKER), ["3", [{ name: "volume" }, { name: "muted" }]]);
assert.deepEqual(announced(T.STEP_SPEAKER), ["3", undefined]);
assert.deepEqual(announced(T.EQUALIZER_CONTROLLER), ["3", [{ name: "bands" }, { name: "mode" }]]);
assert.deepEqual(announced(T.PLAYBACK_CONTROLLER), ["3", undefined]);
assert.deepEqual(announced(T.PLAYBACK_STATE_REPORTER), ["3", [{ name: "playbackState" }]]);
assert.deepEqual(announced(T.INPUT_CONTROLLER), ["3", [{ name: "input" }]]);
assert.deepEqual(announced(T.CHANNEL_CONTROLLER), ["3", [{ name: "channel" }]]);
});
test("1.x declarations of an equalizer and of inputs have no way to say what the device has: check() says it", () => {
const device = tv();
device.addCapability(AlexaInterfaceType.EQUALIZER_CONTROLLER);
device.addCapability(AlexaInterfaceType.INPUT_CONTROLLER);
device.addCapability(AlexaInterfaceType.SPEAKER);
assert.deepEqual(device.check(), [
"tv-1: Alexa.EqualizerController: needs bands, modes or both: declare what the equalizer has",
"tv-1: Alexa.InputController: inputs: expected a list with 1 or more entries, got nothing",
]);
});
test("Speaker and StepSpeaker: neither has options, and the StepSpeaker has no properties object", () => {
assert.deepEqual(tv().add(StepSpeaker).toJSON(), { type: "AlexaInterface", interface: "Alexa.StepSpeaker", version: "3" });
refused(Speaker, { maximum: 11 }, "maximum: not an option of the interface");
assert.deepEqual(Object.keys(PlaybackStateReporter.directives), []);
});
test("EqualizerController: a device with bands, with modes or with both lists the property of what it has", () => {
const bands = { supported: ["BASS", "TREBLE"], range: { minimum: -10, maximum: 10 } };
const onlyBands = tv().add(EqualizerController, { bands }).toJSON();
assert.deepEqual(onlyBands.properties.supported, [{ name: "bands" }]);
assert.deepEqual(onlyBands.configurations, { bands: { supported: [{ name: "BASS" }, { name: "TREBLE" }], range: bands.range } });
const onlyModes = tv().add(EqualizerController, { modes: ["NIGHT", "TV"] }).toJSON();
assert.deepEqual(onlyModes.properties.supported, [{ name: "mode" }]);
assert.deepEqual(onlyModes.configurations, { modes: { supported: [{ name: "NIGHT" }, { name: "TV" }] } });
assert.equal("configuration" in onlyModes, false, "the interface spells it configurations");
refused(EqualizerController, {}, "needs bands, modes or both: declare what the equalizer has");
refused(EqualizerController, { bands: { ...bands, range: { minimum: 6, maximum: -6 } } }, "bands.range.maximum -6 is not above bands.range.minimum 6");
refused(EqualizerController, { bands: { ...bands, supported: ["BASS", "BASS"] } }, "BASS is listed twice");
refused(EqualizerController, { modes: ["CINEMA"] }, 'modes[0]: expected MOVIE | MUSIC | NIGHT | SPORT | TV, got "CINEMA"');
});
test("PlaybackController: all eight operations unless the declaration lists some, and only those reach the handler", async () => {
assert.deepEqual(tv().add(PlaybackController).toJSON().supportedOperations, Object.keys(PlaybackController.directives));
refused(
PlaybackController,
{ supportedOperations: ["Eject"] },
'supportedOperations[0]: expected Play | Pause | Stop | Next | Previous | FastForward | Rewind | StartOver, got "Eject"'
);
const sent = new MemoryPublisher();
const bridge = new Alex2MQTT("u", "p", "root", false, { publisher: sent, log: () => {} });
const player = bridge.addDevice({ endpointId: "player-1", name: "Player", categories: ["STREAMING_DEVICE"] });
const state = player.add(PlaybackStateReporter);
const seen = [];
player.add(PlaybackController, { supportedOperations: ["Play", "Pause"] }).on("*", (ctx) => {
seen.push(ctx.name);
return ctx.respond((s) => s.set(state, "playbackState", { state: ctx.name === "Play" ? "PLAYING" : "PAUSED" }));
});
for (const [name, token] of [["Play", "ct-1"], ["Rewind", "ct-2"], ["Pause", "ct-3"]]) {
await bridge.receive("root/player-1/alexaDirective", JSON.stringify(directive("Alexa.PlaybackController", name, "player-1", token)));
}
assert.deepEqual(seen, ["Play", "Pause"]);
const answers = sent.published.map(({ message: { event, context } }) => [
event.header.name,
context ? context.properties.filter(({ name }) => name === "playbackState").map(({ value }) => value.state) : event.payload.type,
]);
assert.deepEqual(answers, [["Response", ["PLAYING"]], ["ErrorResponse", "INVALID_DIRECTIVE"], ["Response", ["PAUSED"]]]);
});
test("InputController: the inputs are on the capability, each name and friendly name stands for one input", () => {
assert.equal(Inputs.length, 61);
assert.equal(new Set(Inputs).size, 61);
const inputs = [{ name: "HDMI 1", friendlyNames: ["Console"] }, { name: "TUNER" }];
assert.deepEqual(tv().add(InputController, { inputs }).toJSON().inputs, inputs);
refused(InputController, { inputs: [] }, "inputs: expected a list with 1 or more entries, got []");
refused(InputController, { inputs: [{ name: "SCART" }] }, 'inputs[0].name: expected an input like HDMI 1, got "SCART"');
refused(InputController, { inputs: [{ name: "TV" }, { name: "TV" }] }, "TV is listed twice, a name stands for one input");
refused(
InputController,
{ inputs: [{ name: "HDMI 1", friendlyNames: ["Console"] }, { name: "HDMI 2", friendlyNames: ["Console"] }] },
"Console is listed twice, a name stands for one input"
);
});