# What a 1.x caller can observe in 2.0 Every call shape of 1.5.2 is kept. This file lists what behaves differently: on the wire, in what a call returns, and in the types. It is the source of the migration section of the readme and of the 2.0.0 changelog. "Test" names the file under `test/` that pins the row; a row with `-` is pinned by none. The topics are unchanged: `/discover`, `/discover_r`, `//alexaDirective`, `//alexaResponce`, `//deferredResponse`, `/changeReport`. ## Discovery | Change | 1.5.2 | 2.0 | What to do | Test | |---|---|---|---|---| | The `Alexa` interface is announced | not listed | every endpoint ends with `{ "type": "AlexaInterface", "interface": "Alexa", "version": "3" }`, which Amazon requires | a test that compares the capability list gets one more entry; `new Alex2MQTT(..., { alexaInterface: false })` leaves it out. Alexa is told of every endpoint once more | `device/discovery.test.js` | | Version of `Alexa.EndpointHealth` | `3.3` | `3.1`, the version of the interface page | nothing | `discovery.test.js` | | Interfaces that 1.5.2 announced with version `1` or with no property | `Alexa.Speaker`, `Alexa.StepSpeaker`, `Alexa.EqualizerController`, `Alexa.PlaybackController`, `Alexa.PlaybackStateReporter`, `Alexa.InputController`, `Alexa.ChannelController`: version `1` and no property; `Alexa.LockController`, `Alexa.MotionSensor`, `Alexa.PowerLevelController`: no property | the version and the properties of the interface page | a caller that replaced `getJSON()` to correct the capability can drop the replacement; a replaced `getJSON()` is still what discovery lists | `registry/entertainment.test.js`, `device/discovery.test.js`, `compat/capabilities.test.js` | | `addSupportedModes(["a", "b"])` | the strings were announced as they were | `[{ "value": "a" }, { "value": "b" }]`, and a warning through the log hook | pass `{ value, modeResources }` | `device/discovery.test.js` | | `new ActionMapping(actions, name, payload)` with a string as payload | the string was announced, quoted | a JSON string is parsed, with a warning through the log hook; any other string throws a `DeclarationError` | pass the object | `compat/capabilities.test.js` | | A discovery request that arrives twice | answered twice | a request with the `messageId` of one that came in the last 60 s is dropped; a request without a `messageId` is answered every time | nothing | `transport.test.js` | | What Alexa would reject in a declaration | published as declared | published as declared, and each problem is logged once through the log hook at discovery; `device.check()` returns the lines | read the log after the first discovery | `device/validate.test.js` | ## Messages | Change | 1.5.2 | 2.0 | What to do | Test | |---|---|---|---|---| | DeferredResponse | `"context": null` | no `context` key | nothing | `compat/messages.test.js` | | ChangeReport header | `"correlationToken": ""` | no `correlationToken` | nothing; the backend builds its own header | `compat/messages.test.js` | | ChangeReport without a changed property | published, and dropped by the backend | not published: `send()` resolves `""` and the `error` event names the endpoint | add the changed property before `unchanged()`; send no report when nothing changed | `compat/messages.test.js` | | A property that is both changed and in the context of a ChangeReport | listed in both | listed in `payload.change.properties` only | nothing | `messages/build.test.js` | | Namespace of an ErrorResponse | always `Alexa` | the namespace the error type is documented under: `THERMOSTAT_IS_OFF` goes under `Alexa.ThermostatController`, `UNAUTHORIZED` under `Alexa.SecurityPanelController`, `OBSTACLE_DETECTED` under `Alexa.Safety` | `setErrorMessage(type, message, extra, { namespace })` names another | `compat/messages.test.js`, `messages/errors.test.js` | | `getErrorMessage(token).send()` without `setErrorMessage()` | an ErrorResponse with an empty payload | `INTERNAL_ERROR` with the message "the device answered with an error and did not say which" | call `setErrorMessage()` | `compat/messages.test.js` | | Order of the keys in the JSON text | `context` before `event` | `event` before `context` | compare the parsed message, not its text | - | ## Directives | Change | 1.5.2 | 2.0 | What to do | Test | |---|---|---|---|---| | Subscriptions | `/#` | `/discover` and `/+/alexaDirective` | nothing; the log hook no longer sees what the bridge itself published | `subscriptions.test.js` | | A second answer for one `correlationToken` | published | refused: `send()` resolves `""` and the `error` event says the directive was answered before. One DeferredResponse and one answer after it pass | answer once | `dispatch/dispatch.test.js` | | A directive that arrives twice | handled twice | a directive with the `messageId` of one that came for the endpoint in the last 60 s is dropped | nothing | `dispatch/dispatch.test.js` | | A directive nothing answers | Alexa waits until the backend gives up after 7 s | `INTERNAL_ERROR` after 6.5 s, and the bridge emits `unanswered` and `error` | answer in the listener, or send a DeferredResponse first; `answerWithinMs: 0` turns it off | `dispatch/dispatch.test.js` | | A listener that throws or rejects | the exception left the library and could end the process | the directive is answered with `INTERNAL_ERROR` and the `error` event carries what was thrown | nothing | `dispatch/dispatch.test.js` | | A directive for a device with no `Event` or `ReportState` listener and no handler | no answer | `INVALID_DIRECTIVE`. A device with a 1.x listener keeps the answer to itself | nothing | `dispatch/dispatch.test.js` | ## Calls and types | Change | 1.5.2 | 2.0 | What to do | Test | |---|---|---|---|---| | `registerDevice()` before `connect()` | threw | returns the device; what it sends before the bridge is connected resolves `""` and the `error` event says to call `connect()` | nothing | `connection.test.js` | | `new Device(client, ...)` | the device published through `client` | `client` is ignored. A client that is not `null` is reported once: through the log hook of the bridge, or as a `DeprecationWarning` with the code `ALEX2NODE_DEVICE_CLIENT` | make the device with `addDevice()` or `registerDevice()`, or set `device.publisher`. Removed in 3.0 | `compat/deprecations.test.js` | | `device.setMqttClient(client)` | gave the device the client of a new connection | does nothing, and says so once (code `ALEX2NODE_SET_MQTT_CLIENT`): the devices of a bridge publish over `disconnect()` and `connect()` without it | remove the call. Removed in 3.0 | `compat/deprecations.test.js` | | `new AlexaStatusMessage(token, root, endpointId, client, ...)`, `new AlexaErrorResponse(token, root, endpointId, client)` | the fourth argument was the mqtt client | it is a `Publisher`: an object with `publish(topic, message)` that resolves `{ ok, topic, error? }` | build the messages with `device.getStatusMessage()`, `getErrorMessage()` and `getChangeReport()`, which are unchanged | `compat/messages.test.js` | | Type of `AlexaStatusMessage.toJSON()` | `{ event: any; context: { properties } \| null }` | `{ event: any; context?: { properties } }` | read `context` as optional | - | | Type of `AlexaErrorResponse.toJSON()` | `{ event: any }` | `ErrorResponseMessage`, typed down to the payload | nothing | - | | `capability.on(name, handler)` without a function | - | throws a `DeclarationError` that says what it got | 2.0 API only | `dispatch/dispatch.test.js` | ## In the design, not in the code | Change | State | |---|---| | `addThermostatControllerProp` and `addTemperatureSensorProp` round the converted Celsius value to two decimals | not done: 68 °F is sent as `20`, 70 °F as `21.11111111111111`, as in 1.5.2 |