Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sonos Boost breaks the module #515

Open
pierrephi opened this issue Jun 11, 2021 · 5 comments
Open

Sonos Boost breaks the module #515

pierrephi opened this issue Jun 11, 2021 · 5 comments

Comments

@pierrephi
Copy link

pierrephi commented Jun 11, 2021

I have a Sonos Boost (bridge) in my network and whenever it is plugged in the module breaks with the following error:

[10.06.2021 22:58.30.537] [ERROR] Error: Request failed with status code 405
    at createError (/Users/pxxxx/Dropbox/Development/MagicMirror/modules/MMM-Sonos/node_modules/axios/lib/core/createError.js:16:15)
    at settle (/Users/pxxxx/Dropbox/Development/MagicMirror/modules/MMM-Sonos/node_modules/axios/lib/core/settle.js:17:12)
    at IncomingMessage.handleStreamEnd (/Users/pxxxx/Dropbox/Development/MagicMirror/modules/MMM-Sonos/node_modules/axios/lib/adapters/http.js:237:11)
    at IncomingMessage.emit (node:events:391:22)
    at endReadableNT (node:internal/streams/readable:1307:12)
    at processTicksAndRejections (node:internal/process/task_queues:81:21) {
  config: {
    url: 'http://192.168.1.162:1400/MediaRenderer/AVTransport/Control',
    method: 'post',
    data: '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:GetTransportInfo xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"><InstanceID>0</InstanceID></u:GetTransportInfo></s:Body></s:Envelope>',
    headers: {
      Accept: 'application/json, text/plain, */*',
      'Content-Type': 'text/xml; charset=utf8',
      SOAPAction: '"urn:schemas-upnp-org:service:AVTransport:1#GetTransportInfo"',
      'User-Agent': 'axios/0.19.0',
      'Content-Length': 274
    },
    transformRequest: [ [Function: transformRequest] ],
    transformResponse: [ [Function: transformResponse] ],
    timeout: 0,
    adapter: [Function: httpAdapter],
    xsrfCookieName: 'XSRF-TOKEN',
    xsrfHeaderName: 'X-XSRF-TOKEN',
    maxContentLength: -1,
    validateStatus: [Function: validateStatus]
  },
  request: <ref *1> ClientRequest {
    _events: [Object: null prototype] {
      abort: [Function (anonymous)],
      aborted: [Function (anonymous)],
      error: [Function (anonymous)],
      socket: [Function (anonymous)],
      timeout: [Function (anonymous)],
      prefinish: [Function: requestOnPrefinish]
    },
    _eventsCount: 6,
    _maxListeners: undefined,
    outputData: [],
    outputSize: 0,
    writable: true,
    destroyed: false,
    _last: true,
    chunkedEncoding: false,
    shouldKeepAlive: false,
    _defaultKeepAlive: true,
    useChunkedEncodingByDefault: true,
    sendDate: false,
    _removedConnection: false,
    _removedContLen: false,
    _removedTE: false,
    _contentLength: null,
    _hasBody: true,
    _trailer: '',
    finished: true,
    _headerSent: true,
    _closed: false,
    socket: Socket {
      connecting: false,
      _hadError: false,
      _parent: null,
      _host: null,
      _readableState: [ReadableState],
      _events: [Object: null prototype],
      _eventsCount: 8,
      _maxListeners: undefined,
      _writableState: [WritableState],
      allowHalfOpen: false,
      _sockname: null,
      _pendingData: null,
      _pendingEncoding: '',
      server: null,
      _server: null,
      parser: null,
      _httpMessage: [Circular *1],
      write: [Function: writeAfterFIN],
      [Symbol(async_id_symbol)]: 1118,
      [Symbol(kHandle)]: null,
      [Symbol(kSetNoDelay)]: false,
      [Symbol(lastWriteQueueSize)]: 0,
      [Symbol(timeout)]: null,
      [Symbol(kBuffer)]: null,
      [Symbol(kBufferCb)]: null,
      [Symbol(kBufferGen)]: null,
      [Symbol(kCapture)]: false,
      [Symbol(kBytesRead)]: 252,
      [Symbol(kBytesWritten)]: 574,
      [Symbol(RequestTimeout)]: undefined
    },
    _header: 'POST /MediaRenderer/AVTransport/Control HTTP/1.1\r\n' +
      'Accept: application/json, text/plain, */*\r\n' +
      'Content-Type: text/xml; charset=utf8\r\n' +
      'SOAPAction: "urn:schemas-upnp-org:service:AVTransport:1#GetTransportInfo"\r\n' +
      'User-Agent: axios/0.19.0\r\n' +
      'Content-Length: 274\r\n' +
      'Host: 192.168.1.162:1400\r\n' +
      'Connection: close\r\n' +
      '\r\n',
    _keepAliveTimeout: 0,
    _onPendingData: {},
    agent: Agent {
      _events: [Object: null prototype],
      _eventsCount: 2,
      _maxListeners: undefined,
      defaultPort: 80,
      protocol: 'http:',
      options: [Object],
      requests: {},
      sockets: [Object],
      freeSockets: {},
      keepAliveMsecs: 1000,
      keepAlive: false,
      maxSockets: Infinity,
      maxFreeSockets: 256,
      scheduling: 'lifo',
      maxTotalSockets: Infinity,
      totalSocketCount: 48,
      [Symbol(kCapture)]: false
    },
    socketPath: undefined,
    method: 'POST',
    maxHeaderSize: undefined,
    insecureHTTPParser: undefined,
    path: '/MediaRenderer/AVTransport/Control',
    _ended: true,
    res: IncomingMessage {
      _readableState: [ReadableState],
      _events: [Object: null prototype],
      _eventsCount: 3,
      _maxListeners: undefined,
      socket: [Socket],
      httpVersionMajor: 1,
      httpVersionMinor: 1,
      httpVersion: '1.1',
      complete: true,
      rawHeaders: [Array],
      rawTrailers: [],
      aborted: false,
      upgrade: false,
      url: '',
      method: null,
      statusCode: 405,
      statusMessage: 'Method Not Allowed',
      client: [Socket],
      _consuming: true,
      _dumped: false,
      req: [Circular *1],
      responseUrl: 'http://192.168.1.162:1400/MediaRenderer/AVTransport/Control',
      redirects: [],
      [Symbol(kCapture)]: false,
      [Symbol(kHeaders)]: [Object],
      [Symbol(kHeadersCount)]: 8,
      [Symbol(kTrailers)]: null,
      [Symbol(kTrailersCount)]: 0,
      [Symbol(RequestTimeout)]: undefined
    },
    aborted: false,
    timeoutCb: null,
    upgradeOrConnect: false,
    parser: null,
    maxHeadersCount: null,
    reusedSocket: false,
    host: '192.168.1.162',
    protocol: 'http:',
    _redirectable: Writable {
      _writableState: [WritableState],
      _events: [Object: null prototype],
      _eventsCount: 2,
      _maxListeners: undefined,
      _options: [Object],
      _redirectCount: 0,
      _redirects: [],
      _requestBodyLength: 274,
      _requestBodyBuffers: [],
      _onNativeResponse: [Function (anonymous)],
      _currentRequest: [Circular *1],
      _currentUrl: 'http://192.168.1.162:1400/MediaRenderer/AVTransport/Control',
      [Symbol(kCapture)]: false
    },
    [Symbol(kCapture)]: false,
    [Symbol(kNeedDrain)]: false,
    [Symbol(corked)]: 0,
    [Symbol(kOutHeaders)]: [Object: null prototype] {
      accept: [Array],
      'content-type': [Array],
      soapaction: [Array],
      'user-agent': [Array],
      'content-length': [Array],
      host: [Array]
    }
  },
  response: {
    status: 405,
    statusText: 'Method Not Allowed',
    headers: {
      allow: 'GET, HEAD',
      'content-type': 'text/html',
      server: 'Linux UPnP/1.0 Sonos/63.2-89260 (BR200)',
      connection: 'close'
    },
    config: {
      url: 'http://192.168.1.162:1400/MediaRenderer/AVTransport/Control',
      method: 'post',
      data: '<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"><s:Body><u:GetTransportInfo xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"><InstanceID>0</InstanceID></u:GetTransportInfo></s:Body></s:Envelope>',
      headers: [Object],
      transformRequest: [Array],
      transformResponse: [Array],
      timeout: 0,
      adapter: [Function: httpAdapter],
      xsrfCookieName: 'XSRF-TOKEN',
      xsrfHeaderName: 'X-XSRF-TOKEN',
      maxContentLength: -1,
      validateStatus: [Function: validateStatus]
    },
    request: <ref *1> ClientRequest {
      _events: [Object: null prototype],
      _eventsCount: 6,
      _maxListeners: undefined,
      outputData: [],
      outputSize: 0,
      writable: true,
      destroyed: false,
      _last: true,
      chunkedEncoding: false,
      shouldKeepAlive: false,
      _defaultKeepAlive: true,
      useChunkedEncodingByDefault: true,
      sendDate: false,
      _removedConnection: false,
      _removedContLen: false,
      _removedTE: false,
      _contentLength: null,
      _hasBody: true,
      _trailer: '',
      finished: true,
      _headerSent: true,
      _closed: false,
      socket: [Socket],
      _header: 'POST /MediaRenderer/AVTransport/Control HTTP/1.1\r\n' +
        'Accept: application/json, text/plain, */*\r\n' +
        'Content-Type: text/xml; charset=utf8\r\n' +
        'SOAPAction: "urn:schemas-upnp-org:service:AVTransport:1#GetTransportInfo"\r\n' +
        'User-Agent: axios/0.19.0\r\n' +
        'Content-Length: 274\r\n' +
        'Host: 192.168.1.162:1400\r\n' +
        'Connection: close\r\n' +
        '\r\n',
      _keepAliveTimeout: 0,
      _onPendingData: {},
      agent: [Agent],
      socketPath: undefined,
      method: 'POST',
      maxHeaderSize: undefined,
      insecureHTTPParser: undefined,
      path: '/MediaRenderer/AVTransport/Control',
      _ended: true,
      res: [IncomingMessage],
      aborted: false,
      timeoutCb: null,
      upgradeOrConnect: false,
      parser: null,
      maxHeadersCount: null,
      reusedSocket: false,
      host: '192.168.1.162',
      protocol: 'http:',
      _redirectable: [Writable],
      [Symbol(kCapture)]: false,
      [Symbol(kNeedDrain)]: false,
      [Symbol(corked)]: 0,
      [Symbol(kOutHeaders)]: [Object: null prototype]
    },
    data: '<HTML><HEAD><TITLE>Error 405</TITLE></HEAD><BODY><H1>Error 405</H1><P>Method Not Allowed</P></BODY></HTML>'
  },
  isAxiosError: true,
  toJSON: [Function (anonymous)]
}

A command is sent to the bridge which is not supported

Current Behavior

Ideally bridges should be ignored as they cannot be piloted, they are just here to manage the Sonos network

Possible Solution

I suggest filtering the bridges in the network in ZoneGroupTopology.prototype.AllZoneGroups

by returning
return groups.filter(z => {return !z.ZoneGroupMember[0].hasOwnProperty("IsZoneBridge")})

Versions (and Environment)

Node version: v15.7.0
node-sonos version: 1.12.5
OS: MacOS, Raspberry PI OS

@svrooij
Copy link
Collaborator

svrooij commented Jun 19, 2021

Why would you control a bridge?

care to create a PR for this? Can the app using this library not just filter out the boost (with the possibly good filter method above).

@pierrephi
Copy link
Author

pierrephi commented Jun 19, 2021 via email

@svrooij
Copy link
Collaborator

svrooij commented Jun 19, 2021

It would be nice to filter out non-players in most cases. But you can still rename a boost for instance. So maybe optional parameter to filter them out.

@pierrephi
Copy link
Author

yep that's why the proposal is not to filter on the name "Boost" but rather the specific property that is only present for Boost and the older brides
hasOwnProperty("IsZoneBridge")
I'll go ahead a submit a PR then

@svrooij
Copy link
Collaborator

svrooij commented Jun 19, 2021

I mean, the use case to return the boost is that you can control some things off it. Hiding them always might not be a good idea.

can you make the PR to the alpha branch?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants