├── .all-contributorsrc ├── .github ├── CODE-OF-CONDUCT.md ├── CONTRIBUTING.md ├── Funding.yml ├── ISSUE_TEMPLATE │ ├── config.yml │ ├── documentation.md │ └── template.md ├── pull_request_template.md └── workflows │ ├── generator.yml │ ├── json-validation.yml │ └── linter.yml ├── .gitignore ├── .markdownlint.json ├── .yamllint.yml ├── LICENSE ├── README.md ├── docs ├── .gitignore ├── 404.html ├── Gemfile ├── Gemfile.lock ├── _config.yml ├── _data │ ├── colors.json │ ├── metadata.json │ └── projects.json ├── _includes │ ├── apps.html │ ├── libraries.html │ └── project-card.html ├── _sass │ └── custom │ │ └── custom.scss ├── developers.md ├── docker-compose.yml ├── documentation.json ├── index.md ├── metadata.md ├── music-services.json ├── music-services.md ├── projects.md ├── schema │ ├── author.json │ ├── documentation.json │ ├── metadata.json │ ├── projects.json │ └── template.json ├── services │ ├── alarm-clock.md │ ├── audio-in.md │ ├── av-transport.md │ ├── connection-manager.md │ ├── content-directory.md │ ├── device-properties.md │ ├── group-management.md │ ├── group-rendering-control.md │ ├── ht-control.md │ ├── index.md │ ├── music-services.md │ ├── q-play.md │ ├── queue.md │ ├── rendering-control.md │ ├── system-properties.md │ ├── virtual-line-in.md │ └── zone-group-topology.md └── sonos-communication.md └── generator └── sonos-docs ├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .gitignore ├── README.md ├── bin ├── run └── run.cmd ├── data ├── sonos-S1-2.json ├── sonos-S13-2.json ├── sonos-S14-2.json ├── sonos-S18-2.json ├── sonos-S19-2.json ├── sonos-S21-2.json ├── sonos-S27-2.json ├── sonos-S3-2.json ├── sonos-S33-2.json ├── sonos-S38-2.json ├── sonos-S5-1.json ├── sonos-S6-2.json ├── sonos-S9-2.json └── sonos-Sub-2.json ├── package-lock.json ├── package.json ├── src ├── commands │ ├── combine.ts │ ├── generate.ts │ ├── musicservices.ts │ └── services.ts ├── helpers │ ├── array-helper.ts │ └── string-helper.ts ├── index.ts └── models │ ├── author.ts │ ├── extended-sonos-description.ts │ ├── sonos-device.ts │ ├── sonos-discovery-info.ts │ ├── sonos-service-action.ts │ ├── sonos-service-documentation.ts │ ├── sonos-service-error.ts │ ├── sonos-service.ts │ ├── sonos-state-variable.ts │ └── template.ts ├── templates ├── docs │ ├── service.hbs │ ├── services-index.hbs │ └── template.json └── node │ ├── README.md │ ├── service.hbs │ └── template.json └── tsconfig.json /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "projectName": "sonos-api-docs", 3 | "projectOwner": "svrooij", 4 | "repoType": "github", 5 | "repoHost": "https://github.com", 6 | "files": [ 7 | "README.md", 8 | "docs/index.md" 9 | ], 10 | "imageSize": 100, 11 | "commit": true, 12 | "commitConvention": "eslint", 13 | "contributors": [ 14 | { 15 | "login": "svrooij", 16 | "name": "Stephan van Rooij", 17 | "avatar_url": "https://avatars2.githubusercontent.com/u/1292510?v=4", 18 | "profile": "https://svrooij.nl", 19 | "contributions": [ 20 | "code", 21 | "doc", 22 | "ideas", 23 | "maintenance" 24 | ] 25 | }, 26 | { 27 | "login": "hklages", 28 | "name": "H. Klages", 29 | "avatar_url": "https://avatars3.githubusercontent.com/u/17273119?v=4", 30 | "profile": "https://github.com/hklages", 31 | "contributions": [ 32 | "doc" 33 | ] 34 | }, 35 | { 36 | "login": "sschuberth", 37 | "name": "Sebastian Schuberth", 38 | "avatar_url": "https://avatars0.githubusercontent.com/u/349154?v=4", 39 | "profile": "https://github.com/sschuberth", 40 | "contributions": [ 41 | "doc" 42 | ] 43 | }, 44 | { 45 | "login": "jkossis", 46 | "name": "Jason Kossis", 47 | "avatar_url": "https://avatars.githubusercontent.com/u/1247832?v=4", 48 | "profile": "https://github.com/jkossis", 49 | "contributions": [ 50 | "doc" 51 | ] 52 | } 53 | ], 54 | "contributorsPerLine": 7, 55 | "skipCi": true 56 | } 57 | -------------------------------------------------------------------------------- /.github/CODE-OF-CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Code of Conduct 2 | 3 | ## Our Standards 4 | 5 | Examples of behavior that contributes to creating a positive environment 6 | include: 7 | 8 | * Using welcoming and inclusive language 9 | * Being respectful of differing viewpoints and experiences 10 | * Gracefully accepting constructive criticism 11 | * Focusing on what is best for the community 12 | * Showing empathy towards other community members 13 | 14 | Examples of unacceptable behavior by participants include: 15 | 16 | * The use of sexualized language or imagery and unwelcome sexual attention or 17 | advances 18 | * Trolling, insulting/derogatory comments, and personal or political attacks 19 | * Public or private harassment 20 | * Publishing others' private information, such as a physical or electronic 21 | address, without explicit permission 22 | * Other conduct which could reasonably be considered inappropriate in a 23 | professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable 28 | behavior and are expected to take appropriate and fair corrective action in 29 | response to any instances of unacceptable behavior. 30 | 31 | Project maintainers have the right and responsibility to remove, edit, or 32 | reject comments, commits, code, wiki edits, issues, and other contributions 33 | that are not aligned to this Code of Conduct, or to ban temporarily or 34 | permanently any contributor for other behaviors that they deem inappropriate, 35 | threatening, offensive, or harmful. 36 | 37 | ## Scope 38 | 39 | This Code of Conduct applies both within project spaces and in public spaces 40 | when an individual is representing the project or its community. Examples of 41 | representing a project or community include using an official project e-mail 42 | address, posting via an official social media account, or acting as an appointed 43 | representative at an online or offline event. Representation of a project may be 44 | further defined and clarified by project maintainers. 45 | 46 | ## Enforcement 47 | 48 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 49 | reported by contacting the project team at sonos [no-spam] svrooij.io. All 50 | complaints will be reviewed and investigated and will result in a response that 51 | is deemed necessary and appropriate to the circumstances. The project team is 52 | obligated to maintain confidentiality with regard to the reporter of an incident. 53 | Further details of specific enforcement policies may be posted separately. 54 | 55 | Project maintainers who do not follow or enforce the Code of Conduct in good 56 | faith may face temporary or permanent repercussions as determined by other 57 | members of the project's leadership. 58 | 59 | ## Attribution 60 | 61 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 62 | available at [contributor-covenant.org/version/1/4/code-of-conduct.html](https://www.contributor-covenant.org/version/1/4/code-of-conduct.html) 63 | 64 | [homepage]: https://www.contributor-covenant.org 65 | 66 | For answers to common questions about this code of conduct, see 67 | [contributor-covenant.org/faq](https://www.contributor-covenant.org/faq) 68 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Sonos API Docs 2 | 3 | A big welcome and thank you for considering contributing to this open source documentation on Sonos! It’s people like you that make it a reality for users in our community. 4 | 5 | Reading and following these guidelines will help us make the contribution process easy and effective for everyone involved. It also communicates that you agree to respect the time of the developers managing and developing these open source projects. In return, we will reciprocate that respect by addressing your issue, assessing changes, and helping you finalize your pull requests. 6 | 7 | ## Quicklinks 8 | 9 | * [Code of Conduct](#code-of-conduct) 10 | * [Getting Started](#getting-started) 11 | - [Issues](#issues) 12 | - [Pull Requests](#pull-requests) 13 | * [Getting Help](#getting-help) 14 | * [Sponsoring](sponsoring) 15 | 16 | ## Code of Conduct 17 | 18 | We take our open source community seriously and hold ourselves and other contributors to high standards of communication. By participating and contributing to this project, you agree to uphold our [Code of Conduct](https://github.com/svrooij/sonos-api-docs/blob/main/.github/CODE-OF-CONDUCT.md). 19 | 20 | ## Getting Started 21 | 22 | Contributions are made to this repo via Issues and Pull Requests (PRs). A few general guidelines that cover both: 23 | 24 | - Search for existing Issues and PRs before creating your own. 25 | - We work hard to makes sure issues are handled in a timely manner but, depending on the impact, it could take a while to investigate the root cause. A friendly ping in the comment thread to the submitter or a contributor can help draw attention if your issue is blocking. 26 | - If you've never contributed before, see [the first timer's guide on our blog](https://auth0.com/blog/a-first-timers-guide-to-an-open-source-project/) for resources and tips on how to get started. 27 | 28 | ### Issues 29 | 30 | Issues should be used to report problems with the documentation, request a new feature, or to discuss potential changes before a PR is created. 31 | 32 | 33 | 34 | If you find an Issue that addresses the problem you're having, please add your own reproduction information to the existing issue rather than creating a new one. Adding a [reaction](https://github.blog/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) can also help be indicating to our maintainers that a particular problem is affecting more than just the reporter. 35 | 36 | ### Pull Requests 37 | 38 | PRs to our libraries are always welcome and can be a quick way to get your fix or improvement slated for the next release. In general, PRs should: 39 | 40 | - Only fix/add the functionality in question **OR** address wide-spread whitespace/style issues, not both. 41 | - If you changed the [documentation.json](https://sonos.svrooij.io/developers.html#documentationjson) or any device discovery files, be sure to also [regenerate](https://sonos.svrooij.io/developers.html#regenerate-documentation) the services. 42 | - Be sure to [preview](https://sonos.svrooij.io/developers.html#live-preview-on-local-machine) your changes in the resulting webpage. 43 | - Be accompanied by a complete Pull Request template (loaded automatically when a PR is created). 44 | 45 | For changes that address core functionality or would require breaking changes (e.g. a major release), it's best to open an Issue to discuss your proposal first. This is not required but can save time creating and reviewing changes. 46 | 47 | In general, we follow the ["fork-and-pull" Git workflow](https://github.com/susam/gitpr) 48 | 49 | 1. Fork the repository to your own Github account 50 | 2. Clone the project to your machine 51 | 3. Create a branch locally with a succinct but descriptive name 52 | 4. Commit changes to the branch 53 | 5. Following any formatting and testing guidelines specific to this repo 54 | 6. Push changes to your fork 55 | 7. Open a PR in our repository and follow the PR template so that we can efficiently review the changes. 56 | 57 | ## Sponsoring 58 | 59 | [![Support me on Github][badge_sponsor]][link_sponsor] 60 | 61 | You cannot only contribute by spending some time to document stuff or the help users with his/her issues, you can also sponsor me, so I can spend time on my open-source projects like these. 62 | 63 | [badge_issues]: https://img.shields.io/github/issues/svrooij/sonos-api-docs 64 | [badge_sponsor]: https://img.shields.io/badge/Sponsor-on%20Github-red 65 | 66 | [link_sponsor]: https://github.com/sponsors/svrooij 67 | [link_issues]: https://github.com/svrooij/sonos-api-docs/issues 68 | -------------------------------------------------------------------------------- /.github/Funding.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | github: svrooij 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Questions 4 | url: https://github.com/svrooij/sonos-api-docs/discussions/categories/q-a 5 | about: Please ask and answer questions here. 6 | - name: All discussions 7 | url: https://github.com/svrooij/sonos-api-docs/discussions 8 | about: General discussions about the Sonos API. -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/documentation.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Documenation improvement 3 | about: Use this if some action isn't documented correctly 4 | title: 'Documentation: ' 5 | labels: docs 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### System info 11 | 12 | - Sonos version (S1 or S2): 13 | - Software version: 14 | 15 | ### Service details 16 | 17 | 18 | 19 | - Service name: 20 | - Action name(s): 21 | 22 | ### Link to current documentation 23 | 24 | 25 | 26 | ### Proposed change 27 | 28 | 29 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/template.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Template improvement 3 | about: Use this if you want to suggest a change to a template 4 | title: 'Template: ' 5 | labels: template 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### Template details 11 | 12 | 19 | 20 | - What template (`sonos-ts` / `docs`): 21 | - What part of the template: 22 | - Current source URL: 23 | - Current output URL: 24 | 25 | ### Proposed change 26 | 27 | 28 | 29 | ### Additional context 30 | 31 | 32 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Your title here 2 | 3 | ## Description 4 | 5 | Please describe your pull request. 6 | 7 | ## Your checklist for this pull request 8 | 9 | 🚨 Please review the [guidelines for contributing](https://github.com/svrooij/sonos-api-docs/blob/main/.github/CONTRIBUTING.md) to this repository. 10 | 11 | - [ ] Make sure you are requesting to **pull a topic/feature/bugfix branch** (right side). Don't request your main! 12 | - [ ] Make sure you are making a pull request against the **main branch** (left side). Also you should start *your branch* off *svrooij/sonos-api-docs/main*. 13 | - [ ] Check your code additions will fail neither code linting checks nor unit test. (mine sometimes also fail, will probably ignore the lint failures) 14 | - [ ] If you changed the **documentation.json** be sure to also [regenerate](https://sonos.svrooij.io/developers.html#regenerate-documentation) the services files. 15 | - [ ] The `docs/services/index.md` and the `docs/services/*.md` files should not be manually changed, only with the generator. 16 | 17 | 💔 Thank you! -------------------------------------------------------------------------------- /.github/workflows/generator.yml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_dispatch: 3 | push: 4 | branches: 5 | - main 6 | - ci-build 7 | paths: 8 | - '.github/workflows/generator.yml' 9 | - 'generator/sonos-docs/src/**/*.ts' 10 | - 'generator/sonos-docs/.releaserc' 11 | 12 | pull_request: 13 | branches: 14 | - main 15 | paths: 16 | - '.github/workflows/generator.yml' 17 | - 'generator/sonos-docs/src/**/*.ts' 18 | 19 | jobs: 20 | test: 21 | name: 'Build and test on Node v${{ matrix.node }}' 22 | runs-on: ubuntu-latest 23 | strategy: 24 | matrix: 25 | node: [16, 18] 26 | defaults: 27 | run: 28 | working-directory: generator/sonos-docs 29 | steps: 30 | - uses: actions/checkout@v4 31 | - uses: actions/setup-node@v4 32 | with: 33 | node-version: ${{ matrix.node }} 34 | - name: Install depencencies 35 | run: npm ci 36 | - name: Build library 37 | run: npm run prepack 38 | 39 | release: 40 | name: 'Release generator' 41 | needs: [test] 42 | runs-on: ubuntu-latest 43 | if: github.event_name != 'pull_request' 44 | defaults: 45 | run: 46 | working-directory: generator/sonos-docs 47 | steps: 48 | - uses: actions/checkout@v4 49 | - uses: actions/setup-node@v4 50 | with: 51 | node-version: 16 52 | - name: Install depencencies 53 | run: npm ci 54 | - name: Semantic Release 55 | uses: cycjimmy/semantic-release-action@v4 56 | id: semantic 57 | with: 58 | working_directory: generator/sonos-docs 59 | env: 60 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 61 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 62 | - name: Setup node for Github Registry 63 | if: steps.semantic.outputs.new_release_published == 'true' 64 | uses: actions/setup-node@v4 65 | with: 66 | node-version: 16 67 | registry-url: 'https://npm.pkg.github.com' 68 | scope: 'svrooij' 69 | - name: Publish To GitHub Package Registry 70 | if: steps.semantic.outputs.new_release_published == 'true' 71 | run: | 72 | npm publish 73 | env: 74 | NODE_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}} 75 | -------------------------------------------------------------------------------- /.github/workflows/json-validation.yml: -------------------------------------------------------------------------------- 1 | name: JSON validation 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - beta 8 | paths: 9 | - 'docs/schema/*.json' 10 | - 'docs/documentation.json' 11 | - 'docs/_data/projects.json' 12 | - 'generator/sonos-docs/templates/**/template.json' 13 | - '.github/workflows/json-validation.yml' 14 | pull_request: 15 | branches: 16 | - main 17 | 18 | jobs: 19 | validate-docs: 20 | name: Validate JSON files 21 | runs-on: ubuntu-latest 22 | steps: 23 | - name: Checkout Code 24 | uses: actions/checkout@v4 25 | - name: Use node 16 26 | uses: actions/setup-node@v4 27 | with: 28 | node-version: 16 29 | - name: Install ajv-cli 30 | run: npm i -g ajv-cli 31 | - name: Validate docs/_data/projects.json 32 | run: ajv validate -d ./docs/_data/projects.json -s ./docs/schema/projects.json -r ./docs/schema/author.json 33 | - name: Validate docs/documentation.json 34 | run: ajv validate -s ./docs/schema/documentation.json -d ./docs/documentation.json 35 | - name: Validate template json files 36 | run: ajv validate -s ./docs/schema/template.json -d "./generator/sonos-docs/templates/**/template.json" -r ./docs/schema/author.json 37 | -------------------------------------------------------------------------------- /.github/workflows/linter.yml: -------------------------------------------------------------------------------- 1 | --- 2 | ########################### 3 | ########################### 4 | ## Linter GitHub Actions ## 5 | ########################### 6 | ########################### 7 | name: Lint Code Base 8 | 9 | # 10 | # Documentation: 11 | # https://help.github.com/en/articles/workflow-syntax-for-github-actions 12 | # 13 | 14 | ############################# 15 | # Start the job on all push # 16 | ############################# 17 | on: 18 | push: 19 | #branches-ignore: [master] 20 | # Remove the line above to run when pushing to master 21 | pull_request: 22 | branches: [main] 23 | 24 | ############### 25 | # Set the Job # 26 | ############### 27 | jobs: 28 | build: 29 | # Name the Job 30 | name: Lint Code Base 31 | # Set the agent to run on 32 | runs-on: ubuntu-latest 33 | 34 | ################## 35 | # Load all steps # 36 | ################## 37 | steps: 38 | ########################## 39 | # Checkout the code base # 40 | ########################## 41 | - name: Checkout Code 42 | uses: actions/checkout@v4 43 | with: 44 | # Full git history is needed to get list of changed files 45 | fetch-depth: 0 46 | 47 | ################################ 48 | # Run Linter against code base # 49 | ################################ 50 | - name: Lint Code Base 51 | uses: github/super-linter/slim@v5 52 | env: 53 | VALIDATE_ALL_CODEBASE: false 54 | VALIDATE_JAVASCRIPT_STANDARD: false 55 | VALIDATE_TYPESCRIPT_STANDARD: false 56 | VALIDATE_JSCPD: false 57 | VALIDATE_HTML: false 58 | FILTER_REGEX_EXCLUDE: .*docs/services/*.md 59 | DEFAULT_BRANCH: main 60 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 61 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Directory for instrumented libs generated by jscoverage/JSCover 19 | lib-cov 20 | 21 | # Coverage directory used by tools like istanbul 22 | coverage 23 | *.lcov 24 | 25 | # nyc test coverage 26 | .nyc_output 27 | 28 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 29 | .grunt 30 | 31 | # Bower dependency directory (https://bower.io/) 32 | bower_components 33 | 34 | # node-waf configuration 35 | .lock-wscript 36 | 37 | # Compiled binary addons (https://nodejs.org/api/addons.html) 38 | build/Release 39 | 40 | # Dependency directories 41 | node_modules/ 42 | jspm_packages/ 43 | 44 | # TypeScript v1 declaration files 45 | typings/ 46 | 47 | # TypeScript cache 48 | *.tsbuildinfo 49 | 50 | # Optional npm cache directory 51 | .npm 52 | 53 | # Optional eslint cache 54 | .eslintcache 55 | 56 | # Microbundle cache 57 | .rpt2_cache/ 58 | .rts2_cache_cjs/ 59 | .rts2_cache_es/ 60 | .rts2_cache_umd/ 61 | 62 | # Optional REPL history 63 | .node_repl_history 64 | 65 | # Output of 'npm pack' 66 | *.tgz 67 | 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | 71 | # dotenv environment variables file 72 | .env 73 | .env.test 74 | 75 | # parcel-bundler cache (https://parceljs.org/) 76 | .cache 77 | 78 | # Next.js build output 79 | .next 80 | 81 | # Nuxt.js build / generate output 82 | .nuxt 83 | dist 84 | 85 | # Gatsby files 86 | .cache/ 87 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 88 | # https://nextjs.org/blog/next-9-1#public-directory-support 89 | # public 90 | 91 | # vuepress build output 92 | .vuepress/dist 93 | 94 | # Serverless directories 95 | .serverless/ 96 | 97 | # FuseBox cache 98 | .fusebox/ 99 | 100 | # DynamoDB Local files 101 | .dynamodb/ 102 | 103 | # TernJS port file 104 | .tern-port 105 | 106 | # .new-version file used in Github workflow 107 | .new-version 108 | -------------------------------------------------------------------------------- /.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/DavidAnson/markdownlint/main/schema/markdownlint-config-schema.json", 3 | "fenced-code-language": false, 4 | "MD013": false, 5 | "MD025": false 6 | } 7 | -------------------------------------------------------------------------------- /.yamllint.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | extends: default 4 | 5 | rules: 6 | document-start: disable # don't bother me with this rule 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Stephan van Rooij 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Unofficial Sonos docs 2 | 3 | [![Sonos API documentation][badge_sonos-docs]][link_sonos-docs] 4 | [![Github Issues][badge_issues]][link_issues] 5 | [![Sonos2mqtt][badge_sonos-mqtt]][link_sonos-mqtt] 6 | [![Sonos cli][badge_sonos-cli]][link_sonos-cli] 7 | [![Sonos typescript this library][badge_sonos-typescript]][link_sonos-typescript] 8 | 9 | [![Support me on Github][badge_sponsor]][link_sponsor] 10 | [![Follow on Twitter][badge_twitter]][link_twitter] 11 | 12 | Sonos API documentation for the local UPNP API and a [generator](https://github.com/svrooij/sonos-api-docs/tree/main/generator/sonos-docs) to generate clients and documentation based on service discovery 13 | 14 | This library is in no way connected to [Sonos](//en.wikipedia.org/wiki/Sonos). It's just a set of text files to document a hidden and **unsupported** API. 15 | 16 | ## Documentation 17 | 18 | Check-out the (generated) documentation about all the SONOS UPNP services [svrooij.io/sonos-api-docs/services/](https://sonos.svrooij.io/services/) 19 | 20 | [![Sonos API documentation][badge_sonos-docs]][link_sonos-docs] 21 | 22 | [Read documentation](https://sonos.svrooij.io/) 23 | 24 | ### Manually documented 25 | 26 | The [sonos services](https://sonos.svrooij.io/services/) have no documentation, that is why we manually created a [documentation.json](https://github.com/svrooij/sonos-api-docs/blob/main/docs/documentation.json) file. To easily add documentation to all services (that are generated with the generator). And it's json so you can easily use it yourself. 27 | 28 | ### Device discovery files 29 | 30 | You can use the generator to generate your own discovery files, but we also have the files available for download. 31 | 32 | | Player | Discovery file(s) | 33 | | ------ | ----------------- | 34 | | Sonos Play:1 | [S2](https://github.com/svrooij/sonos-api-docs/raw/main/generator/sonos-docs/data/sonos-S1-2.json) | 35 | | Sonos Play:3 | [S2](https://github.com/svrooij/sonos-api-docs/raw/main/generator/sonos-docs/data/sonos-S3-2.json) | 36 | | Sonos Play:5 (new) | [S2](https://github.com/svrooij/sonos-api-docs/raw/main/generator/sonos-docs/data/sonos-S6-2.json) | 37 | | Sonos Playbar | [S2](https://github.com/svrooij/sonos-api-docs/raw/main/generator/sonos-docs/data/sonos-S9-2.json) | 38 | | Sonos One | [S2](https://github.com/svrooij/sonos-api-docs/raw/main/generator/sonos-docs/data/sonos-S13-2.json) | 39 | | Sonos One (mic) | [S2](https://github.com/svrooij/sonos-api-docs/raw/main/generator/sonos-docs/data/sonos-S18-2.json) | 40 | | Sonos Beam | [S2](https://github.com/svrooij/sonos-api-docs/raw/main/generator/sonos-docs/data/sonos-S14-2.json) | 41 | | Sonos Roam | [S2](https://github.com/svrooij/sonos-api-docs/raw/main/generator/sonos-docs/data/sonos-S27-2.json) | 42 | | Sonos Sub | [S2](https://github.com/svrooij/sonos-api-docs/raw/main/generator/sonos-docs/data/sonos-Sub-2.json) | 43 | | SYMFONISK Bookshelf| [S2](https://github.com/svrooij/sonos-api-docs/raw/main/generator/sonos-docs/data/sonos-S21-2.json) | 44 | | Sonos Play:5 (old) | [S1](https://github.com/svrooij/sonos-api-docs/raw/main/generator/sonos-docs/data/sonos-S5-1.json) | 45 | 46 | These files together with the documentation file, are combined to a extensive JSON file, that is used as an input for the generator. 47 | 48 | ## Community 49 | 50 | If you have any [questions](https://github.com/svrooij/sonos-api-docs/discussions/categories/q-a) or you want to [show](https://github.com/svrooij/sonos-api-docs/discussions/categories/show-and-tell) your Sonos integration. Please join us in the [discussions](https://github.com/svrooij/sonos-api-docs/discussions) tab on this repository. 51 | 52 | ## Contributors ✨ 53 | 54 | 55 | [![All Contributors](https://img.shields.io/badge/all_contributors-4-orange.svg?style=flat-square)](#contributors-) 56 | 57 | 58 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 |

Stephan van Rooij

💻 📖 🤔 🚧

H. Klages

📖

Sebastian Schuberth

📖

Jason Kossis

📖
71 | 72 | 73 | 74 | 75 | 76 | 77 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) 78 | specification. Contributions of any kind welcome! 79 | 80 | [badge_issues]: https://img.shields.io/github/issues/svrooij/sonos-api-docs?style=for-the-badge 81 | [badge_sonos-cli]: https://img.shields.io/badge/sonos-cli-blue?style=for-the-badge 82 | [badge_sonos-docs]: https://img.shields.io/badge/sonos-api-blue?style=for-the-badge 83 | [badge_sonos-mqtt]: https://img.shields.io/badge/sonos-mqtt-blue?style=for-the-badge 84 | [badge_sonos-typescript]: https://img.shields.io/badge/sonos-typescript-blue?style=for-the-badge 85 | [badge_sponsor]: https://img.shields.io/github/sponsors/svrooij?logo=github&style=for-the-badge 86 | [badge_twitter]: https://img.shields.io/twitter/follow/svrooij?logo=twitter&style=for-the-badge 87 | 88 | [link_sponsor]: https://github.com/sponsors/svrooij 89 | [link_issues]: https://github.com/svrooij/sonos-api-docs/issues 90 | [link_sonos-cli]: https://github.com/svrooij/sonos-cli 91 | [link_sonos-docs]: https://sonos.svrooij.io/ 92 | [link_sonos-mqtt]: https://sonos2mqtt.svrooij.io/ 93 | [link_sonos-typescript]: https://sonos-ts.svrooij.io/ 94 | [link_twitter]: https://twitter.com/svrooij 95 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | _site 2 | .sass-cache 3 | .jekyll-metadata 4 | vendor -------------------------------------------------------------------------------- /docs/404.html: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | --- 4 | 5 | 18 | 19 |
20 |

404

21 | 22 |

Page not found :(

23 |

The requested page could not be found.

24 |
25 | -------------------------------------------------------------------------------- /docs/Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | # Hello! This is where you manage which Jekyll version is used to run. 4 | # When you want to use a different version, change it below, save the 5 | # file and run `bundle install`. Run Jekyll with `bundle exec`, like so: 6 | # 7 | # bundle exec jekyll serve 8 | # 9 | # This will help ensure the proper Jekyll version is running. 10 | # Happy Jekylling! 11 | # gem "jekyll", "~> 3.8.5" 12 | 13 | # If you want to use GitHub Pages, remove the "gem "jekyll"" above and 14 | # uncomment the line below. To upgrade, run `bundle update github-pages`. 15 | gem "github-pages", group: :jekyll_plugins 16 | 17 | # If you have any plugins, put them here! 18 | group :jekyll_plugins do 19 | gem "jekyll-feed", "~> 0.6" 20 | end 21 | 22 | # Windows does not include zoneinfo files, so bundle the tzinfo-data gem 23 | gem "tzinfo-data", platforms: [:mingw, :mswin, :x64_mingw, :jruby] 24 | 25 | # Performance-booster for watching directories on Windows 26 | gem "wdm", "~> 0.1.0" if Gem.win_platform? 27 | 28 | gem "just-the-docs", "0.3.3" 29 | gem "jekyll-octicons" 30 | gem "jemoji" 31 | -------------------------------------------------------------------------------- /docs/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | activesupport (6.1.7.6) 5 | concurrent-ruby (~> 1.0, >= 1.0.2) 6 | i18n (>= 1.6, < 2) 7 | minitest (>= 5.1) 8 | tzinfo (~> 2.0) 9 | zeitwerk (~> 2.3) 10 | addressable (2.8.6) 11 | public_suffix (>= 2.0.2, < 6.0) 12 | base64 (0.2.0) 13 | coffee-script (2.4.1) 14 | coffee-script-source 15 | execjs 16 | coffee-script-source (1.12.2) 17 | colorator (1.1.0) 18 | commonmarker (0.23.10) 19 | concurrent-ruby (1.2.3) 20 | dnsruby (1.70.0) 21 | simpleidn (~> 0.2.1) 22 | em-websocket (0.5.3) 23 | eventmachine (>= 0.12.9) 24 | http_parser.rb (~> 0) 25 | ethon (0.16.0) 26 | ffi (>= 1.15.0) 27 | eventmachine (1.2.7) 28 | execjs (2.9.1) 29 | faraday (2.8.1) 30 | base64 31 | faraday-net_http (>= 2.0, < 3.1) 32 | ruby2_keywords (>= 0.0.4) 33 | faraday-net_http (3.0.2) 34 | ffi (1.16.3) 35 | forwardable-extended (2.6.0) 36 | gemoji (4.1.0) 37 | github-pages (229) 38 | github-pages-health-check (= 1.18.2) 39 | jekyll (= 3.9.4) 40 | jekyll-avatar (= 0.8.0) 41 | jekyll-coffeescript (= 1.2.2) 42 | jekyll-commonmark-ghpages (= 0.4.0) 43 | jekyll-default-layout (= 0.1.5) 44 | jekyll-feed (= 0.17.0) 45 | jekyll-gist (= 1.5.0) 46 | jekyll-github-metadata (= 2.16.1) 47 | jekyll-include-cache (= 0.2.1) 48 | jekyll-mentions (= 1.6.0) 49 | jekyll-optional-front-matter (= 0.3.2) 50 | jekyll-paginate (= 1.1.0) 51 | jekyll-readme-index (= 0.3.0) 52 | jekyll-redirect-from (= 0.16.0) 53 | jekyll-relative-links (= 0.7.0) 54 | jekyll-remote-theme (= 0.4.3) 55 | jekyll-sass-converter (= 1.5.2) 56 | jekyll-seo-tag (= 2.8.0) 57 | jekyll-sitemap (= 1.4.0) 58 | jekyll-swiss (= 1.0.0) 59 | jekyll-theme-architect (= 0.2.0) 60 | jekyll-theme-cayman (= 0.2.0) 61 | jekyll-theme-dinky (= 0.2.0) 62 | jekyll-theme-hacker (= 0.2.0) 63 | jekyll-theme-leap-day (= 0.2.0) 64 | jekyll-theme-merlot (= 0.2.0) 65 | jekyll-theme-midnight (= 0.2.0) 66 | jekyll-theme-minimal (= 0.2.0) 67 | jekyll-theme-modernist (= 0.2.0) 68 | jekyll-theme-primer (= 0.6.0) 69 | jekyll-theme-slate (= 0.2.0) 70 | jekyll-theme-tactile (= 0.2.0) 71 | jekyll-theme-time-machine (= 0.2.0) 72 | jekyll-titles-from-headings (= 0.5.3) 73 | jemoji (= 0.13.0) 74 | kramdown (= 2.4.0) 75 | kramdown-parser-gfm (= 1.1.0) 76 | liquid (= 4.0.4) 77 | mercenary (~> 0.3) 78 | minima (= 2.5.1) 79 | nokogiri (>= 1.13.6, < 2.0) 80 | rouge (= 3.30.0) 81 | terminal-table (~> 1.4) 82 | github-pages-health-check (1.18.2) 83 | addressable (~> 2.3) 84 | dnsruby (~> 1.60) 85 | octokit (>= 4, < 8) 86 | public_suffix (>= 3.0, < 6.0) 87 | typhoeus (~> 1.3) 88 | html-pipeline (2.14.3) 89 | activesupport (>= 2) 90 | nokogiri (>= 1.4) 91 | http_parser.rb (0.8.0) 92 | i18n (1.14.1) 93 | concurrent-ruby (~> 1.0) 94 | jekyll (3.9.4) 95 | addressable (~> 2.4) 96 | colorator (~> 1.0) 97 | em-websocket (~> 0.5) 98 | i18n (>= 0.7, < 2) 99 | jekyll-sass-converter (~> 1.0) 100 | jekyll-watch (~> 2.0) 101 | kramdown (>= 1.17, < 3) 102 | liquid (~> 4.0) 103 | mercenary (~> 0.3.3) 104 | pathutil (~> 0.9) 105 | rouge (>= 1.7, < 4) 106 | safe_yaml (~> 1.0) 107 | jekyll-avatar (0.8.0) 108 | jekyll (>= 3.0, < 5.0) 109 | jekyll-coffeescript (1.2.2) 110 | coffee-script (~> 2.2) 111 | coffee-script-source (~> 1.12) 112 | jekyll-commonmark (1.4.0) 113 | commonmarker (~> 0.22) 114 | jekyll-commonmark-ghpages (0.4.0) 115 | commonmarker (~> 0.23.7) 116 | jekyll (~> 3.9.0) 117 | jekyll-commonmark (~> 1.4.0) 118 | rouge (>= 2.0, < 5.0) 119 | jekyll-default-layout (0.1.5) 120 | jekyll (>= 3.0, < 5.0) 121 | jekyll-feed (0.17.0) 122 | jekyll (>= 3.7, < 5.0) 123 | jekyll-gist (1.5.0) 124 | octokit (~> 4.2) 125 | jekyll-github-metadata (2.16.1) 126 | jekyll (>= 3.4, < 5.0) 127 | octokit (>= 4, < 7, != 4.4.0) 128 | jekyll-include-cache (0.2.1) 129 | jekyll (>= 3.7, < 5.0) 130 | jekyll-mentions (1.6.0) 131 | html-pipeline (~> 2.3) 132 | jekyll (>= 3.7, < 5.0) 133 | jekyll-octicons (19.8.0) 134 | jekyll (>= 3.6, < 5.0) 135 | octicons (= 19.8.0) 136 | jekyll-optional-front-matter (0.3.2) 137 | jekyll (>= 3.0, < 5.0) 138 | jekyll-paginate (1.1.0) 139 | jekyll-readme-index (0.3.0) 140 | jekyll (>= 3.0, < 5.0) 141 | jekyll-redirect-from (0.16.0) 142 | jekyll (>= 3.3, < 5.0) 143 | jekyll-relative-links (0.7.0) 144 | jekyll (>= 3.3, < 5.0) 145 | jekyll-remote-theme (0.4.3) 146 | addressable (~> 2.0) 147 | jekyll (>= 3.5, < 5.0) 148 | jekyll-sass-converter (>= 1.0, <= 3.0.0, != 2.0.0) 149 | rubyzip (>= 1.3.0, < 3.0) 150 | jekyll-sass-converter (1.5.2) 151 | sass (~> 3.4) 152 | jekyll-seo-tag (2.8.0) 153 | jekyll (>= 3.8, < 5.0) 154 | jekyll-sitemap (1.4.0) 155 | jekyll (>= 3.7, < 5.0) 156 | jekyll-swiss (1.0.0) 157 | jekyll-theme-architect (0.2.0) 158 | jekyll (> 3.5, < 5.0) 159 | jekyll-seo-tag (~> 2.0) 160 | jekyll-theme-cayman (0.2.0) 161 | jekyll (> 3.5, < 5.0) 162 | jekyll-seo-tag (~> 2.0) 163 | jekyll-theme-dinky (0.2.0) 164 | jekyll (> 3.5, < 5.0) 165 | jekyll-seo-tag (~> 2.0) 166 | jekyll-theme-hacker (0.2.0) 167 | jekyll (> 3.5, < 5.0) 168 | jekyll-seo-tag (~> 2.0) 169 | jekyll-theme-leap-day (0.2.0) 170 | jekyll (> 3.5, < 5.0) 171 | jekyll-seo-tag (~> 2.0) 172 | jekyll-theme-merlot (0.2.0) 173 | jekyll (> 3.5, < 5.0) 174 | jekyll-seo-tag (~> 2.0) 175 | jekyll-theme-midnight (0.2.0) 176 | jekyll (> 3.5, < 5.0) 177 | jekyll-seo-tag (~> 2.0) 178 | jekyll-theme-minimal (0.2.0) 179 | jekyll (> 3.5, < 5.0) 180 | jekyll-seo-tag (~> 2.0) 181 | jekyll-theme-modernist (0.2.0) 182 | jekyll (> 3.5, < 5.0) 183 | jekyll-seo-tag (~> 2.0) 184 | jekyll-theme-primer (0.6.0) 185 | jekyll (> 3.5, < 5.0) 186 | jekyll-github-metadata (~> 2.9) 187 | jekyll-seo-tag (~> 2.0) 188 | jekyll-theme-slate (0.2.0) 189 | jekyll (> 3.5, < 5.0) 190 | jekyll-seo-tag (~> 2.0) 191 | jekyll-theme-tactile (0.2.0) 192 | jekyll (> 3.5, < 5.0) 193 | jekyll-seo-tag (~> 2.0) 194 | jekyll-theme-time-machine (0.2.0) 195 | jekyll (> 3.5, < 5.0) 196 | jekyll-seo-tag (~> 2.0) 197 | jekyll-titles-from-headings (0.5.3) 198 | jekyll (>= 3.3, < 5.0) 199 | jekyll-watch (2.2.1) 200 | listen (~> 3.0) 201 | jemoji (0.13.0) 202 | gemoji (>= 3, < 5) 203 | html-pipeline (~> 2.2) 204 | jekyll (>= 3.0, < 5.0) 205 | just-the-docs (0.3.3) 206 | jekyll (>= 3.8.5) 207 | jekyll-seo-tag (~> 2.0) 208 | rake (>= 12.3.1, < 13.1.0) 209 | kramdown (2.4.0) 210 | rexml 211 | kramdown-parser-gfm (1.1.0) 212 | kramdown (~> 2.0) 213 | liquid (4.0.4) 214 | listen (3.8.0) 215 | rb-fsevent (~> 0.10, >= 0.10.3) 216 | rb-inotify (~> 0.9, >= 0.9.10) 217 | mercenary (0.3.6) 218 | mini_portile2 (2.8.5) 219 | minima (2.5.1) 220 | jekyll (>= 3.5, < 5.0) 221 | jekyll-feed (~> 0.9) 222 | jekyll-seo-tag (~> 2.1) 223 | minitest (5.22.1) 224 | nokogiri (1.13.10) 225 | mini_portile2 (~> 2.8.0) 226 | racc (~> 1.4) 227 | octicons (19.8.0) 228 | octokit (4.25.1) 229 | faraday (>= 1, < 3) 230 | sawyer (~> 0.9) 231 | pathutil (0.16.2) 232 | forwardable-extended (~> 2.6) 233 | public_suffix (5.0.4) 234 | racc (1.7.3) 235 | rake (13.0.6) 236 | rb-fsevent (0.11.2) 237 | rb-inotify (0.10.1) 238 | ffi (~> 1.0) 239 | rexml (3.2.6) 240 | rouge (3.30.0) 241 | ruby2_keywords (0.0.5) 242 | rubyzip (2.3.2) 243 | safe_yaml (1.0.5) 244 | sass (3.7.4) 245 | sass-listen (~> 4.0.0) 246 | sass-listen (4.0.0) 247 | rb-fsevent (~> 0.9, >= 0.9.4) 248 | rb-inotify (~> 0.9, >= 0.9.7) 249 | sawyer (0.9.2) 250 | addressable (>= 2.3.5) 251 | faraday (>= 0.17.3, < 3) 252 | simpleidn (0.2.1) 253 | unf (~> 0.1.4) 254 | terminal-table (1.8.0) 255 | unicode-display_width (~> 1.1, >= 1.1.1) 256 | typhoeus (1.4.1) 257 | ethon (>= 0.9.0) 258 | tzinfo (2.0.6) 259 | concurrent-ruby (~> 1.0) 260 | unf (0.1.4) 261 | unf_ext 262 | unf_ext (0.0.9.1) 263 | unicode-display_width (1.8.0) 264 | zeitwerk (2.6.13) 265 | 266 | PLATFORMS 267 | ruby 268 | 269 | DEPENDENCIES 270 | github-pages 271 | jekyll-feed (~> 0.6) 272 | jekyll-octicons 273 | jemoji 274 | just-the-docs (= 0.3.3) 275 | tzinfo-data 276 | 277 | BUNDLED WITH 278 | 2.0.2 279 | -------------------------------------------------------------------------------- /docs/_config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | title: Sonos API 4 | email: 1292510+svrooij@users.noreply.github.com 5 | 6 | baseurl: "/sonos-api-docs" 7 | url: "https://svrooij.io" 8 | twitter_username: svrooij 9 | github_username: svrooij 10 | repository: svrooij/sonos-api-docs 11 | 12 | # Build settings 13 | markdown: kramdown 14 | remote_theme: svrooij/just-the-docs@plausible 15 | plugins: 16 | - jekyll-feed 17 | - jekyll-octicons 18 | - jemoji 19 | 20 | # Enable or disable heading anchors 21 | heading_anchors: true 22 | 23 | # Aux links for the upper right navigation 24 | aux_links: 25 | "Repository": 26 | - "//github.com/svrooij/sonos-api-docs" 27 | "Sponsor @svrooij": 28 | - "//github.com/sponsors/svrooij/" 29 | 30 | # Footer content appears at the bottom of every page's main content 31 | footer_content: > 32 | Copyright © 2022 Stephan van Rooij. 33 | Distributed under 35 | MIT license. 36 | 37 | toc: 38 | max_levels: 2 39 | 40 | # Footer "Edit this page on GitHub" link text 41 | gh_edit_link: true # show or hide edit this page link 42 | gh_edit_link_text: "Source on Github" 43 | gh_edit_repository: "https://github.com/svrooij/sonos-api-docs" 44 | gh_edit_branch: "main/docs" # the branch that your docs is served from 45 | gh_edit_view_mode: "tree" # "tree" or "edit" 46 | 47 | plausible_domain: "sonos.svrooij.io" 48 | -------------------------------------------------------------------------------- /docs/_data/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://sonos.svrooij.io/schema/metadata.json", 3 | "metadata": [ 4 | { 5 | "service": 9, 6 | "name": "Spotify Album", 7 | "identifier": "spotify:album:{id}", 8 | "uri": "x-rincon-cpcontainer:1004206cspotify:album:{id}?sid=9&flags=8300&sn=7", 9 | "metadata": { 10 | "id": "0004206cspotify:album:{id}", 11 | "class": "object.container.album.musicAlbum", 12 | "didlDescription": "SA_RINCON2311_X_#Svc2311-0-Token" 13 | } 14 | }, 15 | { 16 | "service": 9, 17 | "name": "Spotify Artist Radio", 18 | "identifier": "spotify:artistRadio:{id}", 19 | "uri": "x-sonosapi-radio:spotify:artistRadio:{id}?sid=9&flags=8300&sn=7", 20 | "metadata": { 21 | "id": "100c206cspotify:artistRadio:{id}", 22 | "title": "Artist Radio", 23 | "parentId": "10052064spotify:artist:{id}", 24 | "class": "object.item.audioItem.audioBroadcast.#artistRadio", 25 | "didlDescription": "SA_RINCON2311_X_#Svc2311-0-Token" 26 | }, 27 | "sampleId": "72qVrKXRp9GeFQOesj0Pmv" 28 | }, 29 | { 30 | "service": 9, 31 | "name": "Spotify Artist Top Tracks", 32 | "identifier": "spotify:artistTopTracks:{id}", 33 | "uri": "x-rincon-cpcontainer:100e206cspotify:artistTopTracks:{id}?sid=9&flags=8300&sn=7", 34 | "metadata": { 35 | "id": "100c206cspotify:artistTopTracks:{id}", 36 | "parentId": "10052064spotify:artist:{id}", 37 | "class": "object.container.playlistContainer", 38 | "didlDescription": "SA_RINCON2311_X_#Svc2311-0-Token" 39 | } 40 | }, 41 | { 42 | "service": 9, 43 | "name": "Spotify Playlist", 44 | "identifier": "spotify:playlist:{id}", 45 | "uri": "x-rincon-cpcontainer:1006206cspotify:playlist:{id}?sid=9&flags=8300&sn=7", 46 | "metadata": { 47 | "id": "1006206cspotify:playlist:{id}", 48 | "parentId": "10fe2664playlists", 49 | "class": "object.container.playlistContainer", 50 | "didlDescription": "SA_RINCON2311_X_#Svc2311-0-Token" 51 | }, 52 | "sampleId": "5HllTKEvYoHAwODZdwKw9W" 53 | }, 54 | { 55 | "service": 9, 56 | "name": "Spotify Track", 57 | "identifier": "spotify:track:{id}", 58 | "uri": "x-sonos-spotify:spotify:track:{id}?sid=9&flags=8224&sn=7", 59 | "metadata": { 60 | "id": "spotify:track:{id}", 61 | "title": "", 62 | "class": "object.item.audioItem.musicTrack", 63 | "didlDescription": "SA_RINCON2311_X_#Svc2311-0-Token" 64 | }, 65 | "sampleId": "3nDZHJ43uRF3fZGEMIjZ0b" 66 | }, 67 | { 68 | "service": 9, 69 | "name": "Spotify User Playlist", 70 | "identifier": "spotify:user:{id}", 71 | "uri": "x-rincon-cpcontainer:1004206cspotify:user:{id}?sid=9&flags=8300&sn=7", 72 | "metadata": { 73 | "id": "10062a6cspotify:user:{id}", 74 | "parentId": "10082664playlists", 75 | "title": "User's playlist", 76 | "class": "object.container.playlistContainer", 77 | "didlDescription": "SA_RINCON2311_X_#Svc2311-0-Token" 78 | } 79 | } 80 | 81 | ] 82 | } -------------------------------------------------------------------------------- /docs/_data/projects.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://sonos.svrooij.io/schema/projects.json", 3 | "apps": [ 4 | { 5 | "name": "sonos2mqtt", 6 | "description": "Control sonos speakers from your mqtt server", 7 | "link": "https://sonos2mqtt.svrooij.io/", 8 | "language": "TypeScript", 9 | "repository": "https://github.com/svrooij/sonos2mqtt", 10 | "tags": ["mqtt", "home-automation"], 11 | "author": { 12 | "name": "Stephan van Rooij", 13 | "link": "https://svrooij.io/" 14 | }, 15 | "usesGenerator": true 16 | }, 17 | { 18 | "name": "sonos cli", 19 | "description": "Control your sonos speakers from the console.", 20 | "language": "TypeScript", 21 | "repository": "https://github.com/svrooij/sonos-cli", 22 | "tags": ["cli"], 23 | "author": { 24 | "name": "Stephan van Rooij", 25 | "link": "https://svrooij.io/" 26 | }, 27 | "usesGenerator": true 28 | }, 29 | { 30 | "name": "FHEM-sonos", 31 | "description": "GERMAN LANGUAGE: FHEM integration", 32 | "tags": ["FHEM"], 33 | "link": "https://wiki.fhem.de/wiki/SONOS", 34 | "usesGenerator": false 35 | }, 36 | { 37 | "name": "Noson", 38 | "description": "(unofficial) Sonos controller for Linux", 39 | "tags": ["Noson", "Linux"], 40 | "language": "C++", 41 | "author": { 42 | "name": "Jean-Luc Barrière", 43 | "link": "https://github.com/janbar" 44 | }, 45 | "link": "http://janbar.github.io/noson-app/", 46 | "repository": "https://github.com/janbar/noson-app", 47 | "usesGenerator": false 48 | }, 49 | { 50 | "name": "Ronor - cli (cloud based)", 51 | "description": "Sonos CLI that uses the cloud, written in Rust", 52 | "link": "https://github.com/mlang/ronor", 53 | "tags": ["cli", "Ronor"], 54 | "language": "Rust", 55 | "author": { 56 | "name": "Mario Lang", 57 | "link": "https://github.com/mlang" 58 | }, 59 | "repository": "https://github.com/mlang/ronor", 60 | "usesGenerator": false 61 | }, 62 | { 63 | "name": "ioBroker.sonos", 64 | "description": "Sonos support for ioBroker", 65 | "link": "https://github.com/ioBroker/ioBroker.sonos", 66 | "repository": "https://github.com/ioBroker/ioBroker.sonos", 67 | "tags": ["ioBroker"], 68 | "language": "JavaScript", 69 | "usesGenerator": false 70 | }, 71 | { 72 | "name": "Bonob", 73 | "description": "Custom sonos music service for self-hosted Navidrome", 74 | "link": "https://github.com/simojenki/bonob", 75 | "repository": "https://github.com/simojenki/bonob", 76 | "author": { 77 | "name": "Simon J", 78 | "link": "https://github.com/simojenki" 79 | }, 80 | "tags": ["Navidrome"], 81 | "language": "TypeScript", 82 | "usesGenerator": false 83 | }, 84 | { 85 | "name": "SoCo CLI", 86 | "description": "Powerful command line controller for Sonos", 87 | "link": "https://github.com/avantrec/soco-cli", 88 | "repository": "https://github.com/avantrec/soco-cli", 89 | "tags": ["cli"], 90 | "language": "Python", 91 | "usesGenerator": false 92 | } 93 | ], 94 | "libraries": [ 95 | { 96 | "name": "@svrooij/sonos", 97 | "description": "The most feature complete sonos library for node and TypeScript, since it uses a generator to create all the service classes", 98 | "link": "http://sonos-ts.svrooij.io/", 99 | "repository": "https://github.com/svrooij/node-sonos-ts", 100 | "language": "TypeScript", 101 | "tags": ["typescript", "node"], 102 | "author": { 103 | "name": "Stephan van Rooij", 104 | "link": "https://svrooij.io/" 105 | }, 106 | "usesGenerator": true 107 | }, 108 | { 109 | "name": "Sonos-net", 110 | "description": "Sonos library for dotnet core, it uses the generator to create all the service classes", 111 | "repository": "https://github.com/svrooij/sonos-net", 112 | "language": "C#", 113 | "tags": ["dotnet", "csharp"], 114 | "author": { 115 | "name": "Stephan van Rooij", 116 | "link": "https://svrooij.io/" 117 | }, 118 | "usesGenerator": true 119 | }, 120 | { 121 | "name": "sonos", 122 | "description": "Node library to control your sonos speakers.", 123 | "repository": "https://github.com/bencevans/node-sonos", 124 | "language": "JavaScript", 125 | "author": { 126 | "name": "Ben Evans", 127 | "link": "https://github.com/bencevans/" 128 | }, 129 | "usesGenerator": false 130 | }, 131 | { 132 | "name": "SoCo", 133 | "description": "Python library to control your sonos speakers", 134 | "link": "https://soco.readthedocs.io/en/latest/index.html", 135 | "repository": "https://github.com/SoCo/SoCo", 136 | "language": "Python", 137 | "author": { 138 | "name": "Rahim Sonawalla", 139 | "link": "https://github.com/rahims" 140 | }, 141 | "usesGenerator": false 142 | }, 143 | { 144 | "name": "duncan3dc-php-sonos", 145 | "description": "PHP library for interacting with Sonos speakers.", 146 | "repository": "https://github.com/duncan3dc/sonos", 147 | "language": "PHP", 148 | "author": { 149 | "name": "Craig Duncan", 150 | "link": "https://github.com/duncan3dc" 151 | }, 152 | "usesGenerator": false 153 | }, 154 | { 155 | "name": "gotwalt-ruby-sonos", 156 | "description": "Control Sonos speakers with Ruby.", 157 | "repository": "https://github.com/gotwalt/sonos", 158 | "language": "Ruby", 159 | "author": { 160 | "name": "Aaron Gotwalt", 161 | "link": "https://github.com/gotwalt" 162 | }, 163 | "usesGenerator": false 164 | }, 165 | { 166 | "name": "Liver64-php-sonos", 167 | "description": "GERMAN LANGUAGE: sonos2 ist eine Sammlung von Befehlen welche die php class PHPSonos nutzt um Sonos player via http Befehle von Loxone aus zu steuern.", 168 | "repository": "https://github.com/Liver64/PHP-Sonos-and-Loxone", 169 | "language": "PHP", 170 | "tags": ["loxone", "german"], 171 | "author": { 172 | "name": "Liver64", 173 | "link": "https://github.com/Liver64" 174 | }, 175 | "usesGenerator": false 176 | }, 177 | { 178 | "name": "Coollision-go-sonos", 179 | "description": "Golang package for controlling Sonoses", 180 | "link": "https://pkg.go.dev/github.com/Coollision/sonos#section-documentation", 181 | "repository": "https://github.com/Coollision/sonos", 182 | "language": "Go", 183 | "author": { 184 | "name": "Coollision", 185 | "link": "https://github.com/Coollision" 186 | }, 187 | "usesGenerator": false 188 | }, 189 | { 190 | "name": "ianr0bkny-go-sonos", 191 | "description": "A Go-language library for accessing UPnP AV devices", 192 | "repository": "https://github.com/ianr0bkny/go-sonos", 193 | "language": "Go", 194 | "author": { 195 | "name": "Ian T Richards", 196 | "link": "https://github.com/ianr0bkny" 197 | }, 198 | "usesGenerator": false 199 | }, 200 | { 201 | "name": "Sonos for IP-Symcon", 202 | "description": "IP-Symcon PHP Modul um Sonos Lautsprecher zu steuern", 203 | "repository": "https://github.com/tkugelberg/Sonos", 204 | "language": "PHP", 205 | "author": { 206 | "name": "Thorsten Kugelberg", 207 | "link": "https://github.com/tkugelberg" 208 | }, 209 | "usesGenerator": false 210 | }, 211 | { 212 | "name": "Sonos API in Java", 213 | "repository": "https://github.com/vmichalak/sonos-controller", 214 | "language":"Java", 215 | "author": { 216 | "name": "Valentin Michalak", 217 | "link": "https://github.com/vmichalak" 218 | }, 219 | "usesGenerator": false 220 | }, 221 | { 222 | "name": "Gonos", 223 | "description": "A Go module for controlling Sonos devices", 224 | "repository": "https://github.com/HandyGold75/Gonos", 225 | "language":"Go", 226 | "author": { 227 | "name": "HandyGold75", 228 | "link": "https://github.com/HandyGold75" 229 | }, 230 | "usesGenerator": false 231 | } 232 | ] 233 | } 234 | -------------------------------------------------------------------------------- /docs/_includes/apps.html: -------------------------------------------------------------------------------- 1 |

Apps

2 |

Open source apps talking to sonos speakers

3 |
4 | 5 | {% assign generated_apps = site.data.projects.apps | where:'usesGenerator', true | sort: 'name' %} 6 | {% assign other_apps = site.data.projects.apps | where:'usesGenerator', false | sort: 'name' %} 7 | 8 | {% for project in generated_apps %} 9 | 10 |
11 | {% include project-card.html %} 12 |
13 | 14 | {% endfor %} 15 | 16 | {% for project in other_apps %} 17 | 18 |
19 | {% include project-card.html %} 20 |
21 | 22 | {% endfor %} 23 |
24 | -------------------------------------------------------------------------------- /docs/_includes/libraries.html: -------------------------------------------------------------------------------- 1 |

Libraries

2 |

Open source libraries for controlling sonos speakers

3 |
4 | 5 | {% assign generated_libraries = site.data.projects.libraries | where:'usesGenerator', true | sort: 'name' %} 6 | {% assign other_libraries = site.data.projects.libraries | where:'usesGenerator', false | sort: 'name' %} 7 | 8 | {% for project in generated_libraries %} 9 | 10 |
11 | {% include project-card.html %} 12 |
13 | 14 | {% endfor %} 15 | 16 | {% for project in other_libraries %} 17 | 18 |
19 | {% include project-card.html %} 20 |
21 | 22 | {% endfor %} 23 |
24 | -------------------------------------------------------------------------------- /docs/_includes/project-card.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |

5 | 6 | {{ project.name }} 7 | 8 |

9 | {% if project.usesGenerator %}{% octicon star-fill height:20 class:"mr-1 v-align-middle" fill:"#586069" aria-label:repo title:"This project uses the generator" %}{% endif %} 10 |
11 |
{{ project.description }}
12 |

{% for tag in project.tags %}{{tag}}{% if forloop.last == false %} {% endif %}{% endfor %}

13 |
14 |
15 | {% if project.language %} 16 | 17 | {{ project.language }} 18 | {% endif %} 19 | {% if project.author %} 20 | 21 | {% octicon person height:16 class:"mr-1 v-align-middle" fill:"#586069" aria-label:repo %} 22 | {{ project.author.name }} 23 | 24 | {% endif %} 25 | {% if project.repository %} 26 | 27 | {% octicon repo height:16 class:"mr-1 v-align-middle" fill:"#586069" aria-label:repo %} 28 | 29 | {% endif %} 30 | 31 |
32 |
33 | -------------------------------------------------------------------------------- /docs/_sass/custom/custom.scss: -------------------------------------------------------------------------------- 1 | @import url("https://unpkg.com/primer/build/build.css"); 2 | // .highlight{width:100%;overflow:auto;background:#ffffff} 3 | .highlight .c{color:#998;font-style:italic} 4 | // .highlight .err{color:#a61717;background-color:#e3d2d2} 5 | .highlight .k{font-weight:bold} 6 | .highlight .o{font-weight:bold} 7 | .highlight .cm{color:#999988;font-style:italic} 8 | .highlight .cp{color:#999999;font-weight:bold} 9 | .highlight .c1{color:#999988;font-style:italic} 10 | .highlight .cs{color:#999999;font-weight:bold;font-style:italic} 11 | .highlight .gd{color:#000000;background-color:#fdd} 12 | .highlight .gd .x{color:#000000;background-color:#faa} 13 | .highlight .ge{font-style:italic} 14 | .highlight .gr{color:#a00} 15 | .highlight .gh{color:#999} 16 | .highlight .gi{color:#000000;background-color:#dfd} 17 | .highlight .gi .x{color:#000000;background-color:#afa} 18 | .highlight .go{color:#888} 19 | .highlight .gp{color:#555} 20 | .highlight .gs{font-weight:bold} 21 | .highlight .gu{color:#aaa} 22 | .highlight .gt{color:#a00} 23 | .highlight .kc{font-weight:bold} 24 | .highlight .kd{font-weight:bold} 25 | .highlight .kp{font-weight:bold} 26 | .highlight .kr{font-weight:bold} 27 | .highlight .kt{color:#445588;font-weight:bold} 28 | .highlight .m{color:#099} 29 | .highlight .s{color:#d14} 30 | .highlight .na{color:teal} 31 | .highlight .nb{color:#0086B3} 32 | .highlight .nc{color:#445588;font-weight:bold} 33 | .highlight .no{color:teal} 34 | .highlight .ni{color:purple} 35 | .highlight .ne{color:#990000;font-weight:bold} 36 | .highlight .nf{color:#990000;font-weight:bold} 37 | .highlight .nn{color:#555} 38 | .highlight .nt{color:navy} 39 | .highlight .nv{color:teal} 40 | .highlight .ow{font-weight:bold} 41 | .highlight .w{color:#bbb} 42 | .highlight .mf{color:#099} 43 | .highlight .mh{color:#099} 44 | .highlight .mi{color:#099} 45 | .highlight .mo{color:#099} 46 | .highlight .sb{color:#d14} 47 | .highlight .sc{color:#d14} 48 | .highlight .sd{color:#d14} 49 | .highlight .s2{color:#d14} 50 | .highlight .se{color:#d14} 51 | .highlight .sh{color:#d14} 52 | .highlight .si{color:#d14} 53 | .highlight .sx{color:#d14} 54 | .highlight .sr{color:#009926} 55 | .highlight .s1{color:#d14} 56 | .highlight .ss{color:#990073} 57 | .highlight .bp{color:#999} 58 | .highlight .vc{color:teal} 59 | .highlight .vg{color:teal} 60 | .highlight .vi{color:teal} 61 | .highlight .il{color:#099} 62 | .highlight .lineno{-webkit-user-select:none;-moz-user-select:none;-o-user-select:none} 63 | .lineno::-moz-selection{background-color:transparent} 64 | .lineno::selection{background-color:transparent} 65 | .github-component{font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol !important} 66 | .repo-language-color{filter:brightness(125%) !important;border-radius:50%;display:inline-block;height:12px;position:relative;top:2px;width:12px} 67 | .emoji{width:18px;height:auto;vertical-align:middle} 68 | .article h1,.article h2,.article h3,.article h4,.article .highlight{margin-bottom:16px} 69 | .article blockquote{color:#6a737d;border-left:2px solid #959da5;padding-left:16px;margin-bottom:16px} 70 | .article ul,.article ol{padding-left:32px;margin-bottom:16px}.article li ul,.article li ol{padding-left:16px;margin-bottom:0px} 71 | .min-height-full{min-height:100vh} 72 | .badge-primary{color:#fff;background-color:#007bff} 73 | .badge{display:inline-block;padding:.25em .6em;font-size:75%;font-weight:700;line-height:1;text-align:center;white-space:nowrap;vertical-align:baseline;border-radius:10rem} 74 | a.link-gray:hover { text-decoration: none;} 75 | -------------------------------------------------------------------------------- /docs/developers.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Developers 4 | nav_order: 21 5 | --- 6 | 7 | # Development of unofficial Sonos Documentation 8 | 9 | A lot of the files you see in this repository are generated with a custom build [generator](https://github.com/svrooij/sonos-api-docs/tree/main/generator/sonos-docs). 10 | This page describes how everything works together. 11 | 12 | ## Live preview on local machine 13 | 14 | We created a `docker-compose.yml` file so you can really easy see the resulting webpage on your local machine. Go to the `docs` folder and start the docker container that will compile the document source to a webpage on every save. 15 | 16 | ```bash 17 | cd ./docs 18 | 19 | # Run container (in foreground, will stop with CTRL+C) 20 | docker-compose up docs 21 | ``` 22 | 23 | Once you have this running it will show some output about installing some ruby packages (inside the container, no worries). And then show the following message, this means the page is now available at `http://localhost:4000`: 24 | 25 | ```text 26 | docs_1 | Configuration file: /srv/jekyll/_config.yml 27 | docs_1 | Source: /srv/jekyll 28 | docs_1 | Destination: /srv/jekyll/_site 29 | docs_1 | Incremental build: enabled 30 | docs_1 | Generating... 31 | docs_1 | Remote Theme: Using theme svrooij/just-the-docs 32 | docs_1 | Jekyll Feed: Generating feed for posts 33 | docs_1 | GitHub Metadata: No GitHub API authentication could be found. Some fields may be missing or have incorrect data. 34 | docs_1 | done in 4.873 seconds. 35 | docs_1 | Auto-regeneration may not work on some Windows versions. 36 | docs_1 | Please see: https://github.com/Microsoft/BashOnWindows/issues/216 37 | docs_1 | If it does not work, please upgrade Bash on Windows or run Jekyll with --no-watch. 38 | docs_1 | Auto-regeneration: enabled for '/srv/jekyll' 39 | docs_1 | LiveReload address: http://0.0.0.0:35729 40 | docs_1 | Server address: http://0.0.0.0:4000// 41 | docs_1 | Server running... press ctrl-c to stop. 42 | docs_1 | LiveReload: Browser connected 43 | ``` 44 | 45 | ## documentation.json 46 | 47 | The [documentation.json](https://github.com/svrooij/sonos-api-docs/blob/main/docs/documentation.json) file is where we could use some help. You don't need to know programming to describe all the actions sonos has. 48 | 49 | This file is used as one of the inputs for the generator. 50 | It allows us to set a nice description for each service and action. It also offers a way to describe each input/output parameter. 51 | 52 | For example [this part](https://github.com/svrooij/sonos-api-docs/blob/25aad3a3a25c029514669869705597df03c2b5d2/docs/documentation.json#L6-L37) is the source for the documentation you see on [this page]({{ '/services/alarm-clock.html' | relative_url }}). 53 | 54 | ## Custom generator 55 | 56 | We build a custom [generator](https://github.com/svrooij/sonos-api-docs/tree/main/generator/sonos-docs) to do several things. 57 | 58 | ### Discover services from Sonos speaker 59 | 60 | You can use the generator to generate [device discovery files]({{ '/#device-discovery-files' | relative_url }}). For each model we generated a discovery json, as available on main page. We generate this file by parsing the device discovery document available at `http://{sonos_ip}:1400/xml/device_description.xml`. Not every model has the same services, but it seems that if a service is available it's the same as all other models that have that service. 61 | 62 | (Re)generate discovery files: 63 | 64 | ```bash 65 | # Fork the repository 66 | # Clone to local folder 67 | # Go to folder 68 | cd /generator/sonos-docs 69 | # Install required packages 70 | npm install 71 | # on Windows 72 | .\bin\run services {sonos-ip} 73 | # on Unix/Mac 74 | ./bin/run services {sonos-ip} 75 | ``` 76 | 77 | Please help us out occasionally by running this command on your own Sonos speaker and send us the resulting file. This way we can keep the discovery files up to date. This command will automatically update the discovery files in the `data` folder. These files are used as an input for the generator. Having up to date discovery files will help us to keep the documentation up to date. All personal identifiable information is removed from the discovery files. 78 | 79 | ### Combine discovery files and documentation 80 | 81 | If you changed the [documentation.json](./documentation.json) file or if you added/updated discovery files, you need to combine the two into one file, the **.cache/combined.json** file. 82 | 83 | This file is the result of the the manual documentation and the device discovery files. This file is almost 8000 lines of json at the moment, which is why it is ignored in git. 84 | Being able to inspect this json file should really help in debugging the generator. 85 | 86 | You can generate this file by running the following command: 87 | 88 | ```bash 89 | # Fork the repository 90 | # Clone to local folder 91 | # Go to folder 92 | cd /generator/sonos-docs 93 | # Install required packages 94 | npm install 95 | # on windows short for .\\bin\\run combine --docsFile=../../docs/documentation.json --folder=data 96 | npm run intermediate-win 97 | # on Unix/mac short for ./bin/run combine --docsFile=../../docs/documentation.json --folder=data 98 | npm run intermediate 99 | 100 | # or with npx from the root directory 101 | npx @svrooij/sonos-docs combine --docsFile=./docs/documentation.json --folder=./generator/sonos-docs/data --out=./generator/sonos-docs/.cache/combined.json 102 | ``` 103 | 104 | ### Regenerate documentation 105 | 106 | Once you generated the **combined.json** file, you can use the generator to (re)generate the [service documentation]({{ '/services' | relative_url }}). This step is mandatory if you changed either the **documentation.json** or if you added/updated one of the discovery files. 107 | 108 | The resulting files, are **not to be changed manually**, since changes will get lost upon the next generation. 109 | 110 | | Template | Resulting file(s) | 111 | |-----------|------------------| 112 | | [services-index.hbs](https://github.com/svrooij/sonos-api-docs/blob/main/generator/sonos-docs/templates/docs/services-index.hbs)| [docs/services/index.md](https://github.com/svrooij/sonos-api-docs/blob/main/docs/services/index.md) | 113 | | [service.hbs](https://github.com/svrooij/sonos-api-docs/blob/main/generator/sonos-docs/templates/docs/service.hbs) | [docs/services/*.md](https://github.com/svrooij/sonos-api-docs/tree/main/docs/services) | 114 | 115 | Regenerate documentation: 116 | 117 | ```bash 118 | # Fork, clone, go to '/generator/sonos-docs' and run npm install 119 | # generate combined.json, see above 120 | 121 | # Regenerate documentation 122 | # on windows, short for .\\bin\\run generate docs ../../docs 123 | npm run docs-win 124 | # on unix/mac, short for ./bin/run generate docs ../../docs 125 | npm run docs 126 | 127 | # or with npx (from root folder) 128 | npx @svrooij/sonos-docs generate docs ./docs -i ./generator/sonos-docs/.cache/combined.json 129 | ``` 130 | 131 | ### Use generator for other library 132 | 133 | The generator uses [Handlebars](https://handlebarsjs.com/) templates. A template is actually a folder with at least a [template.json](https://github.com/svrooij/sonos-api-docs/blob/main/generator/sonos-docs/templates/docs/template.json) file and one or more [template files](https://github.com/svrooij/sonos-api-docs/blob/main/generator/sonos-docs/templates/docs/services-index.hbs). 134 | 135 | The template.json file gives some basic information about the template, the author of that template and which files to use. 136 | 137 | 1. File usage `index`, will use the data from intermediate.json as input to produce **one file**. 138 | 2. File usage `service`, will use the data from each service to produce **one file per service**, be sure to use `{snService}` or `{service}` in the **outputFile**. 139 | 140 | Be sure to check out the [docs template](https://github.com/svrooij/sonos-api-docs/tree/main/generator/sonos-docs/templates/docs) to get started. Or the [ts template](https://github.com/svrooij/node-sonos-ts/tree/master/.generator/ts), which is used to generate [Sonos typescript](https://sonos-ts.svrooij.io/). 141 | 142 | 143 | ```bash 144 | # Fork, clone, go to '/generator/sonos-docs' and run npm install 145 | # generate combined.json, see above 146 | 147 | # generate library 148 | # [template-folder] can either be a folder relative to the current location, a full path to a template folder or the name of the folder inside the generator folder. 149 | # [root-output-folder] in what folder (relative or full path) should the resulting files be placed. 150 | # on windows 151 | .\bin\run generate [template-folder] [root-output-folder] 152 | # on unix/mac 153 | ./bin/run generate [template-folder] [root-output-folder] 154 | 155 | # or with npx 156 | npx @svrooij/sonos-docs generate [template-folder] [root-output-folder] -i ./generator/sonos-docs/.cache/combined.json 157 | ``` 158 | -------------------------------------------------------------------------------- /docs/docker-compose.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | version: "3.8" 4 | services: 5 | docs: 6 | image: jekyll/jekyll:3.8.5 7 | volumes: 8 | - "./:/srv/jekyll" 9 | ports: 10 | - "0.0.0.0:4000:4000" 11 | - "0.0.0.0:35729:35729" 12 | command: ["jekyll", "serve", "--livereload", "--watch", "--force_polling", "--incremental", "-b", "/"] 13 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | # Feel free to add content and custom Front Matter to this file. 3 | # To modify the layout, see https://jekyllrb.com/docs/themes/#overriding-theme-defaults 4 | 5 | layout: default 6 | title: Home 7 | nav_order: 1 8 | permalink: / 9 | --- 10 | 11 | # Unofficial Sonos Docs 12 | 13 | [![Sonos api documentation][badge_sonos-docs]][link_sonos-docs] 14 | [![Github Issues][badge_issues]][link_issues] 15 | [![Sonos2mqtt][badge_sonos-mqtt]][link_sonos-mqtt] 16 | [![Sonos cli][badge_sonos-cli]][link_sonos-cli] 17 | [![Sonos typescript this library][badge_sonos-typescript]][link_sonos-typescript] 18 | 19 | [![Support me on Github][badge_sponsor]][link_sponsor] 20 | [![Follow on Twitter][badge_twitter]][link_twitter] 21 | 22 | Sonos api documentation for the local UPNP api and a [generator](https://github.com/svrooij/sonos-api-docs/tree/main/generator/sonos-docs) to generate clients and documentation based on service discovery 23 | 24 | This library is in no way connected to [Sonos](//en.wikipedia.org/wiki/Sonos). It's just a set of text files to document a hidden and **unsupported** api. 25 | 26 | ## Documentation 27 | 28 | Check-out the (generated) documentation about all the [SONOS UPNP services]({{'services/' | relative_url }}) 29 | 30 | ### Manually documented 31 | 32 | The [sonos services]({{'/services/' | relative_url }}) have no documentation, that is way we manually created a [documentation.json]({{ '/documentation.json' | relative_url }}) file. To easily add documentation to all services (that are generated with the generator). And it's json so you can easily use it yourself. 33 | 34 | - View/edit source [source documentation.json](https://github.com/svrooij/sonos-api-docs/blob/main/docs/documentation.json) 35 | - Download [documentation.json](http://sonos.svrooij.io/documentation.json) 36 | 37 | This file has a [documentation json schema](https://sonos.svrooij.io/schema/documentation.json) which means VS Code will guide you when editing this file. 38 | 39 | ### Update documentation 40 | 41 | If you change the [documentation](#manually-documented) file or if you did service discovery for a new device. You can update the documentation files with the following commands: 42 | 43 | ```shell 44 | # Go to generation folder 45 | cd generator/sonos-docs 46 | 47 | # Generate intermediate file 48 | npm run intermediate 49 | # or ./bin/run combine --docsFile=../../docs/documentation.json --folder=data 50 | 51 | # Generate documentation 52 | npm run docs 53 | # or ./bin/run generate docs ../../docs 54 | ``` 55 | 56 | ## Generator 57 | 58 | You can find the generator [here](https://github.com/svrooij/sonos-api-docs/tree/main/generator/sonos-docs) and use it to generate your own Sonos client in your preferred language. 59 | 60 | ### Device discovery files 61 | 62 | You can use the generator to generate your own discovery files, but we also have the files available for download. 63 | 64 | | Player | Discovery file(s) | 65 | | ------ | ----------------- | 66 | | Sonos Play:1 | [S2](https://github.com/svrooij/sonos-api-docs/raw/main/generator/sonos-docs/data/sonos-S1-2.json) | 67 | | Sonos Play:3 | [S2](https://github.com/svrooij/sonos-api-docs/raw/main/generator/sonos-docs/data/sonos-S3-2.json) | 68 | | Sonos Play:5 (old) | [S1](https://github.com/svrooij/sonos-api-docs/raw/main/generator/sonos-docs/data/sonos-S5-1.json) | 69 | | Sonos Play:5 (new) | [S2](https://github.com/svrooij/sonos-api-docs/raw/main/generator/sonos-docs/data/sonos-S6-2.json) | 70 | | Sonos Playbar | [S2](https://github.com/svrooij/sonos-api-docs/raw/main/generator/sonos-docs/data/sonos-S9-2.json) | 71 | | Sonos One | [S2](https://github.com/svrooij/sonos-api-docs/raw/main/generator/sonos-docs/data/sonos-S13-2.json) | 72 | | Sonos Beam | [S2](https://github.com/svrooij/sonos-api-docs/raw/main/generator/sonos-docs/data/sonos-S14-2.json) | 73 | | Sonos Roam | [S2](https://github.com/svrooij/sonos-api-docs/raw/main/generator/sonos-docs/data/sonos-S27-2.json) | 74 | | Sonos Sub | [S2](https://github.com/svrooij/sonos-api-docs/raw/main/generator/sonos-docs/data/sonos-Sub-2.json) | 75 | 76 | These files toghether with the documentation file, are combined to a extensive JSON file, that is used as an input for the generator. 77 | 78 | ### Templates 79 | 80 | The generator uses [handlebars.js templates](https://handlebarsjs.com/) to generate the documentation/strong typed clients. Check-out the [docs template](https://github.com/svrooij/sonos-api-docs/tree/main/generator/sonos-docs/templates/docs) as a sample to develop your own templates. 81 | 82 | A template is a folder with a [template.json](https://github.com/svrooij/sonos-api-docs/tree/main/generator/sonos-docs/templates/docs/template.json) file, that describes the template and specifies what templates should be used to either generate an index (all services in a single file), or a seperate file for each service. 83 | The template.json also has a [json schema](https://svrooij.io/sonos-api-docs/schema/template.json) so VS Code will guide you when creating your own template. 84 | 85 | ## Community 86 | 87 | If you have any [questions](https://github.com/svrooij/sonos-api-docs/discussions/categories/q-a) or you want to [show](https://github.com/svrooij/sonos-api-docs/discussions/categories/show-and-tell) your Sonos integration. Please join us in the [discussions](https://github.com/svrooij/sonos-api-docs/discussions) tab on this repository. 88 | 89 | ## Contributors ✨ 90 | 91 | 92 | [![All Contributors](https://img.shields.io/badge/all_contributors-4-orange.svg?style=flat-square)](#contributors-) 93 | 94 | 95 | Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 |

Stephan van Rooij

💻 📖 🤔 🚧

H. Klages

📖

Sebastian Schuberth

📖

Jason Kossis

📖
108 | 109 | 110 | 111 | 112 | 113 | 114 | This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) 115 | specification. Contributions of any kind welcome! 116 | 117 | [badge_issues]: https://img.shields.io/github/issues/svrooij/sonos-api-docs?style=for-the-badge 118 | [badge_sonos-cli]: https://img.shields.io/badge/sonos-cli-blue?style=for-the-badge 119 | [badge_sonos-docs]: https://img.shields.io/badge/sonos-api-blue?style=for-the-badge 120 | [badge_sonos-mqtt]: https://img.shields.io/badge/sonos-mqtt-blue?style=for-the-badge 121 | [badge_sonos-typescript]: https://img.shields.io/badge/sonos-typescript-blue?style=for-the-badge 122 | [badge_sponsor]: https://img.shields.io/github/sponsors/svrooij?logo=github&style=for-the-badge 123 | [badge_twitter]: https://img.shields.io/twitter/follow/svrooij?logo=twitter&style=for-the-badge 124 | 125 | [link_sponsor]: https://github.com/sponsors/svrooij 126 | [link_issues]: https://github.com/svrooij/sonos-api-docs/issues 127 | [link_sonos-cli]: https://github.com/svrooij/sonos-cli 128 | [link_sonos-docs]: https://sonos.svrooij.io/ 129 | [link_sonos-mqtt]: https://sonos2mqtt.svrooij.io/ 130 | [link_sonos-typescript]: https://sonos-ts.svrooij.io/ 131 | [link_twitter]: https://twitter.com/svrooij 132 | -------------------------------------------------------------------------------- /docs/metadata.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Metadata 4 | nav_order: 6 5 | --- 6 | 7 | ## Metadata explained 8 | 9 | A lot of requests to sonos require Metadata. This metadata is an xml describing the requested song. 10 | 11 | The metadata for an item can usually be fetched from a [remote music service](./music-services.md), but talking to those is hard. 12 | 13 | ## Known metadata 14 | 15 | Some metadata can be guessed based on common URLs. 16 | 17 | {% assign metadatas = site.data.metadata.metadata | sort: 'name' %} 18 | {% for meta in metadatas %} 19 | 20 | ### {{meta.name}} 21 | 22 | - Identifier: `{{meta.identifier}}` 23 | - Track URI: `{{meta.uri}}` 24 | {% if meta.sampleId %}- Sample ID: `{{meta.sampleId}}`{% endif %} 25 | 26 | ```xml 27 | 29 | 30 | {{meta.metadata.class}} 31 | {{meta.metadata.didlDescription}} 32 | {% if meta.metadata.title %} {{meta.metadata.title}} 33 | {% endif -%} 34 | 35 | 36 | ``` 37 | 38 | {% endfor %} 39 | 40 | ## Contribute 41 | 42 | This page is generated from [metadata.json](https://github.com/svrooij/sonos-api-docs/blob/main/docs/_data/metadata.json), which you can download [here](https://raw.githubusercontent.com/svrooij/sonos-api-docs/main/docs/_data/metadata.json). 43 | -------------------------------------------------------------------------------- /docs/projects.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Apps and libraries 4 | nav_order: 8 5 | --- 6 | 7 | {% include apps.html %} 8 | 9 | {% include libraries.html %} 10 | 11 | ### Auto generated 12 | 13 | This page is generated from [projects.json](https://github.com/svrooij/sonos-api-docs/blob/main/docs/_data/projects.json) if you want a project added to this list, send us a PR. Projects are ordered alphabetical, but projects that use the generator are displayed first. 14 | 15 | When you edit this file in VSCode, it's automatically checked for following the schema. You can also validate the **projects.json** from the command-line file before submitting your PR: 16 | 17 | ```shell 18 | npx ajv-cli -d ./docs/_data/projects.json -s ./docs/schema/projects.json -r ./docs/schema/author.json 19 | ``` 20 | -------------------------------------------------------------------------------- /docs/schema/author.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "$id": "https://sonos.svrooij.io/schema/author.json", 4 | "title": "Author of specific item", 5 | "properties": { 6 | "link": { 7 | "type": "string" 8 | }, 9 | "mail": { 10 | "type": "string" 11 | }, 12 | "name": { 13 | "type": "string" 14 | } 15 | }, 16 | "type": "object", 17 | "required": [ 18 | "name" 19 | ] 20 | } -------------------------------------------------------------------------------- /docs/schema/documentation.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "$id": "https://sonos.svrooij.io/schema/documentation.json", 4 | "definitions": { 5 | "SonosServiceDocumentation": { 6 | "title": "Service name", 7 | "description": "The name of the service should match exactly to the name in the Service Discovery", 8 | "properties": { 9 | "actions": { 10 | "title": "Actions in this service", 11 | "additionalProperties": { 12 | "$ref": "#/definitions/SonosServiceDocumentationAction" 13 | }, 14 | "type": "object" 15 | }, 16 | "description": { 17 | "type": "string" 18 | }, 19 | "errors": { 20 | "title": "Custom errors for this service", 21 | "type": "array", 22 | "items": { 23 | "$ref": "#/definitions/SonosCustomError" 24 | } 25 | }, 26 | "variables": { 27 | "title": "Service variables", 28 | "type": "array", 29 | "items": { 30 | "$ref": "#/definitions/SonosServiceVariable" 31 | } 32 | } 33 | }, 34 | "type": "object", 35 | "required": ["description"] 36 | }, 37 | "SonosServiceDocumentationAction": { 38 | "title": "Action name", 39 | "description": "The name of the action should match exactly with the Service Discovery", 40 | "properties": { 41 | "description": { 42 | "title": "Short description of action", 43 | "type": "string" 44 | }, 45 | "params": { 46 | "title": "Action parameters", 47 | "additionalProperties": { 48 | "title": "Parameter description", 49 | "description": "Describe a single input/output argument, by it name as key", 50 | "type": "string" 51 | }, 52 | "type": "object" 53 | }, 54 | "sample": { 55 | "title": "Sample values", 56 | "description": "Sample values for the parameters", 57 | "additionalProperties": { 58 | "title": "Value", 59 | "description": "Working value, by it name as key", 60 | "type": "string" 61 | }, 62 | "type": "object" 63 | }, 64 | "remarks": { 65 | "title": "Action remarks", 66 | "description": "Remarks about this action", 67 | "type": "string" 68 | } 69 | }, 70 | "type": "object", 71 | "required": ["description"] 72 | }, 73 | "SonosCustomError": { 74 | "title": "Custom error", 75 | "description": "Sonos defined custom errors per UPNP Service.", 76 | "properties": { 77 | "code": { 78 | "title": "Error code", 79 | "type": "number" 80 | }, 81 | "description": { 82 | "title": "Error description", 83 | "type":"string" 84 | } 85 | }, 86 | "default": { 87 | "code": 0, 88 | "description": "" 89 | }, 90 | "type": "object", 91 | "required": ["code", "description"] 92 | }, 93 | "SonosServiceVariable": { 94 | "title": "Service variable", 95 | "description": "Used for variable description and additional event properties", 96 | "type": "object", 97 | "properties": { 98 | "name": { 99 | "title": "Name of the event", 100 | "type": "string" 101 | }, 102 | "dataType": { 103 | "type": "string", 104 | "enum": ["string", "boolean", "ui2", "i4", "ui4"] 105 | }, 106 | "description": { 107 | "type":"string", 108 | "title": "Optional description" 109 | } 110 | }, 111 | "required": ["name", "dataType"] 112 | } 113 | }, 114 | "properties": { 115 | "license": { 116 | "title": "License of the current documentation, MIT is required to be included into the generator", 117 | "type": "string", 118 | "default": "MIT" 119 | }, 120 | "language": { 121 | "type": "string", 122 | "title": "Language of the current documentation" 123 | }, 124 | "services": { 125 | "title": "Each service is added with it's name as key", 126 | "additionalProperties": { 127 | "$ref": "#/definitions/SonosServiceDocumentation" 128 | }, 129 | "type": "object" 130 | }, 131 | "errors": { 132 | "title": "Default errors", 133 | "description": "These errors are used in all services.", 134 | "type": "array", 135 | "items": { 136 | "$ref": "#/definitions/SonosCustomError" 137 | } 138 | } 139 | }, 140 | "type": "object", 141 | "required": ["license", "services", "language"] 142 | } -------------------------------------------------------------------------------- /docs/schema/metadata.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "$id": "https://sonos.svrooij.io/schema/metadata.json", 4 | "definitions": { 5 | "MetadataObject": { 6 | "default": { 7 | "service": -1, 8 | "name": "{ServiceName} {Kind}", 9 | "identifier": "service:track:{id}", 10 | "uri": "...{id}...", 11 | "metadata": { 12 | "id": "service:track:{id}", 13 | "class": "object.item.audioItem.musicTrack", 14 | "didlDescription": "SA_RINCON2311_X_#Svc2311-0-Token" 15 | } 16 | }, 17 | "properties": { 18 | "service": { 19 | "title": "Service Identifier", 20 | "type": "integer", 21 | "default": -1 22 | }, 23 | "name": { 24 | "type":"string", 25 | "title": "Metadata name", 26 | "description": "Name is used in documentation and logging", 27 | "default": "{ServiceName} {Kind}" 28 | }, 29 | "identifier": { 30 | "title": "Item Identifier (lookup value)", 31 | "type": "string", 32 | "description": "Should include '{id}', which will be extracted", 33 | "default": "service:kind:{id}" 34 | }, 35 | "uri": { 36 | "title": "Item URI", 37 | "description": "Full Item URI", 38 | "type":"string" 39 | }, 40 | "sampleId": { 41 | "title": "Sample ID", 42 | "type":"string", 43 | "description": "Can be used to test this metadata" 44 | }, 45 | "metadata": { 46 | "$ref": "#/definitions/Metadata" 47 | } 48 | }, 49 | "type": "object", 50 | "required": [ 51 | "service", 52 | "identifier", 53 | "uri", 54 | "name", 55 | "metadata" 56 | ] 57 | }, 58 | "Metadata": { 59 | "properties": { 60 | "id": { 61 | "type": "string", 62 | "title": "Item ID" 63 | }, 64 | "class": { 65 | "type": "string", 66 | "title": "UpnpClass" 67 | }, 68 | "didlDescription": { 69 | "type":"string", 70 | "title": "DidlDescription", 71 | "description": "Service specific CdUdn, like 'SA_RINCON2311_X_#Svc2311-0-Token' for Spotify" 72 | }, 73 | "title": { 74 | "type": "string", 75 | "title": "Item Title (not required)" 76 | }, 77 | "parentId": { 78 | "type":"string", 79 | "title": "Parent ID (not required)" 80 | } 81 | }, 82 | "type":"object", 83 | "required": [ 84 | "id", 85 | "class", 86 | "didlDescription" 87 | ] 88 | } 89 | }, 90 | "title": "Collection of lookup values for Sonos Speakers", 91 | "properties": { 92 | "metadata": { 93 | "items": { 94 | "$ref": "#/definitions/MetadataObject" 95 | }, 96 | "type": "array", 97 | "minItems": 1 98 | } 99 | }, 100 | "type": "object" 101 | } 102 | -------------------------------------------------------------------------------- /docs/schema/projects.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "$id": "https://sonos.svrooij.io/schema/projects.json", 4 | "definitions": { 5 | "Project": { 6 | "default": { 7 | "name": "", 8 | "repository": "", 9 | "usesGenerator": false 10 | }, 11 | "properties": { 12 | "author": { 13 | "$ref": "author.json" 14 | }, 15 | "name": { 16 | "title": "Project name", 17 | "type": "string" 18 | }, 19 | "description": { 20 | "title": "Project description", 21 | "type": "string" 22 | }, 23 | "language": { 24 | "title": "Used language", 25 | "description": "The language where this project is written in, or can be used with", 26 | "type":"string" 27 | }, 28 | "link": { 29 | "title": "Link to project page", 30 | "type": "string" 31 | }, 32 | "repository": { 33 | "title": "Link to repository page", 34 | "type": "string" 35 | }, 36 | "tags": { 37 | "title": "Tags associated with this project", 38 | "type":"array" 39 | }, 40 | "usesGenerator": { 41 | "title": "Project generated with provided generator?", 42 | "type":"boolean" 43 | } 44 | }, 45 | "type": "object", 46 | "required": [ 47 | "name", 48 | "usesGenerator" 49 | ], 50 | "anyOf": [ 51 | { "required": ["link"]}, 52 | { "required": ["repository"]} 53 | ] 54 | } 55 | }, 56 | "title": "List of known projects using the local sonos api", 57 | "properties": { 58 | "apps": { 59 | "items": { 60 | "$ref": "#/definitions/Project" 61 | }, 62 | "type": "array", 63 | "minItems": 1 64 | }, 65 | "libraries": { 66 | "items": { 67 | "$ref": "#/definitions/Project" 68 | }, 69 | "type": "array", 70 | "minItems": 1 71 | } 72 | }, 73 | "type": "object" 74 | } 75 | -------------------------------------------------------------------------------- /docs/schema/template.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "$id": "https://sonos.svrooij.io/schema/template.json", 4 | "definitions": { 5 | "TemplateFile": { 6 | "properties": { 7 | "file": { 8 | "title": "Template filename", 9 | "type": "string" 10 | }, 11 | "outputFile": { 12 | "title": "Output filename", 13 | "description": "How to output the file(s), '{service}' is replaced by the serviceName, '{snService}' is replaced by snakecase service name", 14 | "type": "string" 15 | }, 16 | "usage": { 17 | "title": "Template use", 18 | "description": "Is this template used for all services combined of per service", 19 | "type": "string", 20 | "enum": [ 21 | "index", 22 | "service" 23 | ] 24 | } 25 | }, 26 | "required": [ 27 | "file", 28 | "outputFile", 29 | "usage" 30 | ], 31 | "type": "object" 32 | } 33 | }, 34 | "title": "Template configuration", 35 | "properties": { 36 | "author": { 37 | "$ref": "author.json" 38 | }, 39 | "files": { 40 | "title": "Templates to process", 41 | "items": { 42 | "$ref": "#/definitions/TemplateFile" 43 | }, 44 | "type": "array", 45 | "minItems": 1 46 | }, 47 | "name": { 48 | "title": "Name of the template", 49 | "type": "string" 50 | }, 51 | "slug": { 52 | "title": "Slug of the template", 53 | "description": "Slug has to be unique and match the tempalte folder, to be included into the generator", 54 | "type": "string" 55 | }, 56 | "dataTypes": { 57 | "title": "Replace data types, original type as key, new type as value", 58 | "additionalProperties": { 59 | "type":"string" 60 | }, 61 | "type":"object" 62 | }, 63 | "serviceData": { 64 | "title": "Add data to each service, to use in your templates", 65 | "additionalProperties": { 66 | "title": "Use the exact service name as key", 67 | "type":"object" 68 | }, 69 | "type":"object" 70 | }, 71 | "license": { 72 | "title": "License of the template", 73 | "description": "'MIT' is required to be included into the generator", 74 | "default": "MIT", 75 | "type":"string" 76 | }, 77 | "repository": { 78 | "title": "Code repositry", 79 | "description": "The repository where the resulting code is used", 80 | "type":"string" 81 | } 82 | }, 83 | "required": [ 84 | "author", 85 | "files", 86 | "slug" 87 | ], 88 | "type": "object" 89 | } -------------------------------------------------------------------------------- /docs/services/audio-in.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: AudioIn 4 | parent: Sonos Services 5 | --- 6 | # AudioIn service 7 | {: .no_toc } 8 | 9 | Control line in 10 | 11 | The AudioIn service is available on these models: `Sonos Play:5 (S6) S2`. 12 | 13 | 1. TOC 14 | {:toc} 15 | 16 | --- 17 | 18 | ## Service data 19 | {: .no_toc } 20 | 21 | | name | value | 22 | |:-----|:------| 23 | | **Control URL** | `http://192.168.x.x:1400/AudioIn/Control` | 24 | | **Event subscription URL** | `http://192.168.x.x:1400/AudioIn/Event` | 25 | | **Discovery URL** | `http://192.168.x.x:1400/xml/AudioIn1.xml` | 26 | | **Service ID** | `urn:upnp-org:serviceId:AudioIn` | 27 | | **Service type** | `urn:schemas-upnp-org:service:AudioIn:1` | 28 | 29 | ### Sample request 30 | {: .no_toc } 31 | 32 | ```text 33 | POST /AudioIn/Control 34 | Host: 192.168.x.x:1400 35 | soapaction: "urn:schemas-upnp-org:service:AudioIn:1#{ActionName}" 36 | Content-Type: text/xml; charset="utf-8" 37 | 38 | 39 | 40 | 41 | {ActionBodyHere} 42 | 43 | 44 | ``` 45 | 46 | --- 47 | 48 | ## Available actions 49 | 50 | ### GetAudioInputAttributes 51 | 52 | Action body: 53 | 54 | ```xml 55 | 56 | 57 | ``` 58 | 59 | No input arguments 60 | 61 | Outputs: 62 | 63 | | parameter | type | description | 64 | |:----------|:-----|:------------| 65 | | **CurrentName** | `string` | | 66 | | **CurrentIcon** | `string` | | 67 | 68 | ### GetLineInLevel 69 | 70 | Action body: 71 | 72 | ```xml 73 | 74 | 75 | ``` 76 | 77 | No input arguments 78 | 79 | Outputs: 80 | 81 | | parameter | type | description | 82 | |:----------|:-----|:------------| 83 | | **CurrentLeftLineInLevel** | `i4` | | 84 | | **CurrentRightLineInLevel** | `i4` | | 85 | 86 | ### SelectAudio 87 | 88 | Action body: 89 | 90 | ```xml 91 | 92 | string 93 | 94 | ``` 95 | 96 | Inputs: 97 | 98 | | parameter | type | description | 99 | |:----------|:-----|:------------| 100 | | **ObjectID** | `string` | | 101 | 102 | ### SetAudioInputAttributes 103 | 104 | Action body: 105 | 106 | ```xml 107 | 108 | string 109 | string 110 | 111 | ``` 112 | 113 | Inputs: 114 | 115 | | parameter | type | description | 116 | |:----------|:-----|:------------| 117 | | **DesiredName** | `string` | | 118 | | **DesiredIcon** | `string` | | 119 | 120 | ### SetLineInLevel 121 | 122 | Action body: 123 | 124 | ```xml 125 | 126 | i4 127 | i4 128 | 129 | ``` 130 | 131 | Inputs: 132 | 133 | | parameter | type | description | 134 | |:----------|:-----|:------------| 135 | | **DesiredLeftLineInLevel** | `i4` | | 136 | | **DesiredRightLineInLevel** | `i4` | | 137 | 138 | ### StartTransmissionToGroup 139 | 140 | Action body: 141 | 142 | ```xml 143 | 144 | string 145 | 146 | ``` 147 | 148 | Inputs: 149 | 150 | | parameter | type | description | 151 | |:----------|:-----|:------------| 152 | | **CoordinatorID** | `string` | | 153 | 154 | Outputs: 155 | 156 | | parameter | type | description | 157 | |:----------|:-----|:------------| 158 | | **CurrentTransportSettings** | `string` | | 159 | 160 | ### StopTransmissionToGroup 161 | 162 | Action body: 163 | 164 | ```xml 165 | 166 | string 167 | 168 | ``` 169 | 170 | Inputs: 171 | 172 | | parameter | type | description | 173 | |:----------|:-----|:------------| 174 | | **CoordinatorID** | `string` | | 175 | 176 | ## Events 177 | 178 | The AudioInService has variables that might be emitted if you subscribe to events. 179 | 180 | ### Subscribe to events 181 | 182 | ```text 183 | SUBSCRIBE /AudioIn/Event 184 | Host: 192.168.x.x:1400 185 | callback: 186 | NT: upnp:event 187 | Timeout: Second-3600 188 | ``` 189 | 190 | ### Event variables 191 | 192 | | Variable | Sends events* | type | possible values | 193 | |:---------|:-------------|:-----|:----------------| 194 | | AudioInputName | ✔ | `string` | | 195 | | Icon | ✔ | `string` | | 196 | | LeftLineInLevel | ✔ | `i4` | | 197 | | LineInConnected | ✔ | `boolean` | `1` for true and `0` for false | 198 | | Playing | ✔ | `boolean` | `1` for true and `0` for false | 199 | | RightLineInLevel | ✔ | `i4` | | 200 | 201 | If the variable has a `✔` in the Sends events column, the service discovery specifies this variable emits events. Other properties might be send as a part of `LastChange` 202 | 203 | --- 204 | 205 | This file is automatically generated with [@svrooij/sonos-docs](https://github.com/svrooij/sonos-api-docs/tree/main/generator/sonos-docs), do not edit manually. 206 | 207 | | Device | Software generation | Software version | Discovery date | 208 | |:-------|:--------------------|:-----------------|:---------------| 209 | | `Sonos Play:5 (S6)` | S2 | 64.3-19080 | 2021-08-18T06:06:35.970Z | 210 | -------------------------------------------------------------------------------- /docs/services/connection-manager.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: ConnectionManager 4 | parent: Sonos Services 5 | --- 6 | # ConnectionManager service 7 | {: .no_toc } 8 | 9 | Services related to connections and protocols 10 | 11 | The ConnectionManager service is available on these models: `Sonos Play:1 (S1) S2` / `Sonos One (S13) S2` / `Sonos Beam (S14) S2` / `Sonos One (S18) S2` / `SYMFONISK Bookshelf (S21) S2` / `Sonos Roam (S27) S2` / `Sonos Play:3 (S3) S2` / `SYMFONISK Bookshelf (S33) S2` / `Sonos One SL (S38) S2` / `Sonos Play:5 (S6) S2` / `Sonos Playbar (S9) S2` / `Sonos Sub (Sub) S2`. 12 | 13 | 1. TOC 14 | {:toc} 15 | 16 | --- 17 | 18 | ## Service data 19 | {: .no_toc } 20 | 21 | | name | value | 22 | |:-----|:------| 23 | | **Control URL** | `http://192.168.x.x:1400/MediaRenderer/ConnectionManager/Control` | 24 | | **Event subscription URL** | `http://192.168.x.x:1400/MediaRenderer/ConnectionManager/Event` | 25 | | **Discovery URL** | `http://192.168.x.x:1400/xml/ConnectionManager1.xml` | 26 | | **Service ID** | `urn:upnp-org:serviceId:ConnectionManager` | 27 | | **Service type** | `urn:schemas-upnp-org:service:ConnectionManager:1` | 28 | 29 | ### Sample request 30 | {: .no_toc } 31 | 32 | ```text 33 | POST /MediaRenderer/ConnectionManager/Control 34 | Host: 192.168.x.x:1400 35 | soapaction: "urn:schemas-upnp-org:service:ConnectionManager:1#{ActionName}" 36 | Content-Type: text/xml; charset="utf-8" 37 | 38 | 39 | 40 | 41 | {ActionBodyHere} 42 | 43 | 44 | ``` 45 | 46 | --- 47 | 48 | ## Available actions 49 | 50 | ### GetCurrentConnectionIDs 51 | 52 | Action body: 53 | 54 | ```xml 55 | 56 | 57 | ``` 58 | 59 | No input arguments 60 | 61 | Outputs: 62 | 63 | | parameter | type | description | 64 | |:----------|:-----|:------------| 65 | | **ConnectionIDs** | `string` | | 66 | 67 | ### GetCurrentConnectionInfo 68 | 69 | Action body: 70 | 71 | ```xml 72 | 73 | i4 74 | 75 | ``` 76 | 77 | Inputs: 78 | 79 | | parameter | type | description | 80 | |:----------|:-----|:------------| 81 | | **ConnectionID** | `i4` | | 82 | 83 | Outputs: 84 | 85 | | parameter | type | description | 86 | |:----------|:-----|:------------| 87 | | **RcsID** | `i4` | | 88 | | **AVTransportID** | `i4` | | 89 | | **ProtocolInfo** | `string` | | 90 | | **PeerConnectionManager** | `string` | | 91 | | **PeerConnectionID** | `i4` | | 92 | | **Direction** | `string` | Possible values: `Input` / `Output` | 93 | | **Status** | `string` | Possible values: `OK` / `ContentFormatMismatch` / `InsufficientBandwidth` / `UnreliableChannel` / `Unknown` | 94 | 95 | ### GetProtocolInfo 96 | 97 | Action body: 98 | 99 | ```xml 100 | 101 | 102 | ``` 103 | 104 | No input arguments 105 | 106 | Outputs: 107 | 108 | | parameter | type | description | 109 | |:----------|:-----|:------------| 110 | | **Source** | `string` | | 111 | | **Sink** | `string` | | 112 | 113 | ## Events 114 | 115 | The ConnectionManagerService has variables that might be emitted if you subscribe to events. 116 | 117 | ### Subscribe to events 118 | 119 | ```text 120 | SUBSCRIBE /MediaRenderer/ConnectionManager/Event 121 | Host: 192.168.x.x:1400 122 | callback: 123 | NT: upnp:event 124 | Timeout: Second-3600 125 | ``` 126 | 127 | ### Event variables 128 | 129 | | Variable | Sends events* | type | possible values | 130 | |:---------|:-------------|:-----|:----------------| 131 | | CurrentConnectionIDs | ✔ | `string` | | 132 | | SinkProtocolInfo | ✔ | `string` | | 133 | | SourceProtocolInfo | ✔ | `string` | | 134 | 135 | If the variable has a `✔` in the Sends events column, the service discovery specifies this variable emits events. Other properties might be send as a part of `LastChange` 136 | 137 | --- 138 | 139 | This file is automatically generated with [@svrooij/sonos-docs](https://github.com/svrooij/sonos-api-docs/tree/main/generator/sonos-docs), do not edit manually. 140 | 141 | | Device | Software generation | Software version | Discovery date | 142 | |:-------|:--------------------|:-----------------|:---------------| 143 | | `Sonos Play:1 (S1)` | S2 | 77.4-49290 | 2024-02-13T15:56:06.184Z | 144 | | `Sonos One (S13)` | S2 | 63.2-90210 | 2021-07-21T23:31:19.273Z | 145 | | `Sonos Beam (S14)` | S2 | 64.3-19080 | 2021-08-18T06:04:08.308Z | 146 | | `Sonos One (S18)` | S2 | 77.4-49290 | 2024-02-13T15:55:36.464Z | 147 | | `SYMFONISK Bookshelf (S21)` | S2 | 66.4-23300 | 2022-01-01T11:41:01.361Z | 148 | | `Sonos Roam (S27)` | S2 | 63.2-90210 | 2021-07-21T23:31:31.207Z | 149 | | `Sonos Play:3 (S3)` | S2 | 64.3-19080 | 2021-08-18T06:09:36.692Z | 150 | | `SYMFONISK Bookshelf (S33)` | S2 | 77.4-49290 | 2024-02-13T15:55:24.423Z | 151 | | `Sonos One SL (S38)` | S2 | 72.2-40060 | 2023-05-22T16:39:25.503Z | 152 | | `Sonos Play:5 (S6)` | S2 | 64.3-19080 | 2021-08-18T06:06:35.970Z | 153 | | `Sonos Playbar (S9)` | S2 | 77.4-49290 | 2024-02-13T15:55:46.307Z | 154 | | `Sonos Sub (Sub)` | S2 | 63.2-90210 | 2021-07-21T23:31:40.304Z | 155 | -------------------------------------------------------------------------------- /docs/services/group-management.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: GroupManagement 4 | parent: Sonos Services 5 | --- 6 | # GroupManagement service 7 | {: .no_toc } 8 | 9 | Services related to groups 10 | 11 | The GroupManagement service is available on these models: `Sonos Play:1 (S1) S2` / `Sonos One (S13) S2` / `Sonos Beam (S14) S2` / `Sonos One (S18) S2` / `SYMFONISK Bookshelf (S21) S2` / `Sonos Roam (S27) S2` / `Sonos Play:3 (S3) S2` / `SYMFONISK Bookshelf (S33) S2` / `Sonos One SL (S38) S2` / `Sonos Play:5 (S6) S2` / `Sonos Playbar (S9) S2` / `Sonos Sub (Sub) S2`. 12 | 13 | 1. TOC 14 | {:toc} 15 | 16 | --- 17 | 18 | ## Service data 19 | {: .no_toc } 20 | 21 | | name | value | 22 | |:-----|:------| 23 | | **Control URL** | `http://192.168.x.x:1400/GroupManagement/Control` | 24 | | **Event subscription URL** | `http://192.168.x.x:1400/GroupManagement/Event` | 25 | | **Discovery URL** | `http://192.168.x.x:1400/xml/GroupManagement1.xml` | 26 | | **Service ID** | `urn:upnp-org:serviceId:GroupManagement` | 27 | | **Service type** | `urn:schemas-upnp-org:service:GroupManagement:1` | 28 | 29 | ### Sample request 30 | {: .no_toc } 31 | 32 | ```text 33 | POST /GroupManagement/Control 34 | Host: 192.168.x.x:1400 35 | soapaction: "urn:schemas-upnp-org:service:GroupManagement:1#{ActionName}" 36 | Content-Type: text/xml; charset="utf-8" 37 | 38 | 39 | 40 | 41 | {ActionBodyHere} 42 | 43 | 44 | ``` 45 | 46 | --- 47 | 48 | ## Available actions 49 | 50 | ### AddMember 51 | 52 | Action body: 53 | 54 | ```xml 55 | 56 | string 57 | ui4 58 | 59 | ``` 60 | 61 | Inputs: 62 | 63 | | parameter | type | description | 64 | |:----------|:-----|:------------| 65 | | **MemberID** | `string` | | 66 | | **BootSeq** | `ui4` | | 67 | 68 | Outputs: 69 | 70 | | parameter | type | description | 71 | |:----------|:-----|:------------| 72 | | **CurrentTransportSettings** | `string` | | 73 | | **CurrentURI** | `string` | | 74 | | **GroupUUIDJoined** | `string` | | 75 | | **ResetVolumeAfter** | `boolean` | `1` for true and `0` for false | 76 | | **VolumeAVTransportURI** | `string` | | 77 | 78 | ### RemoveMember 79 | 80 | Action body: 81 | 82 | ```xml 83 | 84 | string 85 | 86 | ``` 87 | 88 | Inputs: 89 | 90 | | parameter | type | description | 91 | |:----------|:-----|:------------| 92 | | **MemberID** | `string` | | 93 | 94 | ### ReportTrackBufferingResult 95 | 96 | Action body: 97 | 98 | ```xml 99 | 100 | string 101 | i4 102 | 103 | ``` 104 | 105 | Inputs: 106 | 107 | | parameter | type | description | 108 | |:----------|:-----|:------------| 109 | | **MemberID** | `string` | | 110 | | **ResultCode** | `i4` | | 111 | 112 | ### SetSourceAreaIds 113 | 114 | Action body: 115 | 116 | ```xml 117 | 118 | string 119 | 120 | ``` 121 | 122 | Inputs: 123 | 124 | | parameter | type | description | 125 | |:----------|:-----|:------------| 126 | | **DesiredSourceAreaIds** | `string` | | 127 | 128 | ## Events 129 | 130 | The GroupManagementService has variables that might be emitted if you subscribe to events. 131 | 132 | ### Subscribe to events 133 | 134 | ```text 135 | SUBSCRIBE /GroupManagement/Event 136 | Host: 192.168.x.x:1400 137 | callback: 138 | NT: upnp:event 139 | Timeout: Second-3600 140 | ``` 141 | 142 | ### Event variables 143 | 144 | | Variable | Sends events* | type | possible values | 145 | |:---------|:-------------|:-----|:----------------| 146 | | GroupCoordinatorIsLocal | ✔ | `boolean` | `1` for true and `0` for false | 147 | | LocalGroupUUID | ✔ | `string` | | 148 | | ResetVolumeAfter | ✔ | `boolean` | `1` for true and `0` for false | 149 | | SourceAreaIds | | `string` | | 150 | | VirtualLineInGroupID | ✔ | `string` | | 151 | | VolumeAVTransportURI | ✔ | `string` | | 152 | 153 | If the variable has a `✔` in the Sends events column, the service discovery specifies this variable emits events. Other properties might be send as a part of `LastChange` 154 | 155 | --- 156 | 157 | This file is automatically generated with [@svrooij/sonos-docs](https://github.com/svrooij/sonos-api-docs/tree/main/generator/sonos-docs), do not edit manually. 158 | 159 | | Device | Software generation | Software version | Discovery date | 160 | |:-------|:--------------------|:-----------------|:---------------| 161 | | `Sonos Play:1 (S1)` | S2 | 77.4-49290 | 2024-02-13T15:56:06.184Z | 162 | | `Sonos One (S13)` | S2 | 63.2-90210 | 2021-07-21T23:31:19.273Z | 163 | | `Sonos Beam (S14)` | S2 | 64.3-19080 | 2021-08-18T06:04:08.308Z | 164 | | `Sonos One (S18)` | S2 | 77.4-49290 | 2024-02-13T15:55:36.464Z | 165 | | `SYMFONISK Bookshelf (S21)` | S2 | 66.4-23300 | 2022-01-01T11:41:01.361Z | 166 | | `Sonos Roam (S27)` | S2 | 63.2-90210 | 2021-07-21T23:31:31.207Z | 167 | | `Sonos Play:3 (S3)` | S2 | 64.3-19080 | 2021-08-18T06:09:36.692Z | 168 | | `SYMFONISK Bookshelf (S33)` | S2 | 77.4-49290 | 2024-02-13T15:55:24.423Z | 169 | | `Sonos One SL (S38)` | S2 | 72.2-40060 | 2023-05-22T16:39:25.503Z | 170 | | `Sonos Play:5 (S6)` | S2 | 64.3-19080 | 2021-08-18T06:06:35.970Z | 171 | | `Sonos Playbar (S9)` | S2 | 77.4-49290 | 2024-02-13T15:55:46.307Z | 172 | | `Sonos Sub (Sub)` | S2 | 63.2-90210 | 2021-07-21T23:31:40.304Z | 173 | -------------------------------------------------------------------------------- /docs/services/group-rendering-control.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: GroupRenderingControl 4 | parent: Sonos Services 5 | --- 6 | # GroupRenderingControl service 7 | {: .no_toc } 8 | 9 | Volume related controls for groups 10 | 11 | The GroupRenderingControl service is available on these models: `Sonos Play:1 (S1) S2` / `Sonos One (S13) S2` / `Sonos Beam (S14) S2` / `Sonos One (S18) S2` / `SYMFONISK Bookshelf (S21) S2` / `Sonos Roam (S27) S2` / `Sonos Play:3 (S3) S2` / `SYMFONISK Bookshelf (S33) S2` / `Sonos One SL (S38) S2` / `Sonos Play:5 (S6) S2` / `Sonos Playbar (S9) S2` / `Sonos Sub (Sub) S2`. 12 | 13 | 1. TOC 14 | {:toc} 15 | 16 | --- 17 | 18 | ## Service data 19 | {: .no_toc } 20 | 21 | | name | value | 22 | |:-----|:------| 23 | | **Control URL** | `http://192.168.x.x:1400/MediaRenderer/GroupRenderingControl/Control` | 24 | | **Event subscription URL** | `http://192.168.x.x:1400/MediaRenderer/GroupRenderingControl/Event` | 25 | | **Discovery URL** | `http://192.168.x.x:1400/xml/GroupRenderingControl1.xml` | 26 | | **Service ID** | `urn:upnp-org:serviceId:GroupRenderingControl` | 27 | | **Service type** | `urn:schemas-upnp-org:service:GroupRenderingControl:1` | 28 | 29 | ### Sample request 30 | {: .no_toc } 31 | 32 | ```text 33 | POST /MediaRenderer/GroupRenderingControl/Control 34 | Host: 192.168.x.x:1400 35 | soapaction: "urn:schemas-upnp-org:service:GroupRenderingControl:1#{ActionName}" 36 | Content-Type: text/xml; charset="utf-8" 37 | 38 | 39 | 40 | 41 | {ActionBodyHere} 42 | 43 | 44 | ``` 45 | 46 | --- 47 | 48 | ## Available actions 49 | 50 | ### GetGroupMute 51 | 52 | Get the group mute state. 53 | 54 | Action body: 55 | 56 | ```xml 57 | 58 | ui4 59 | 60 | ``` 61 | 62 | Inputs: 63 | 64 | | parameter | type | description | 65 | |:----------|:-----|:------------| 66 | | **InstanceID** | `ui4` | InstanceID should always be `0` | 67 | 68 | Outputs: 69 | 70 | | parameter | type | description | 71 | |:----------|:-----|:------------| 72 | | **CurrentMute** | `boolean` | `1` for true and `0` for false | 73 | 74 | **Remarks** Should be send to coordinator only 75 | 76 | ### GetGroupVolume 77 | 78 | Get the group volume. 79 | 80 | Action body: 81 | 82 | ```xml 83 | 84 | ui4 85 | 86 | ``` 87 | 88 | Inputs: 89 | 90 | | parameter | type | description | 91 | |:----------|:-----|:------------| 92 | | **InstanceID** | `ui4` | InstanceID should always be `0` | 93 | 94 | Outputs: 95 | 96 | | parameter | type | description | 97 | |:----------|:-----|:------------| 98 | | **CurrentVolume** | `ui2` | | 99 | 100 | **Remarks** Should be send to coordinator only 101 | 102 | ### SetGroupMute 103 | 104 | (Un-/)Mute the entire group 105 | 106 | Action body: 107 | 108 | ```xml 109 | 110 | ui4 111 | boolean 112 | 113 | ``` 114 | 115 | Inputs: 116 | 117 | | parameter | type | description | 118 | |:----------|:-----|:------------| 119 | | **InstanceID** | `ui4` | InstanceID should always be `0` | 120 | | **DesiredMute** | `boolean` | Allowed values: `1` (= true) / `0` (= false) | 121 | 122 | **Remarks** Should be send to coordinator only 123 | 124 | ### SetGroupVolume 125 | 126 | Change group volume. Players volume will be changed proportionally based on last snapshot 127 | 128 | Action body: 129 | 130 | ```xml 131 | 132 | ui4 133 | ui2 134 | 135 | ``` 136 | 137 | Inputs: 138 | 139 | | parameter | type | description | 140 | |:----------|:-----|:------------| 141 | | **InstanceID** | `ui4` | InstanceID should always be `0` | 142 | | **DesiredVolume** | `ui2` | New volume between 0 and 100 | 143 | 144 | **Remarks** Should be send to coordinator only 145 | 146 | ### SetRelativeGroupVolume 147 | 148 | Relatively change group volume - returns final group volume. Players volume will be changed proportionally based on last snapshot 149 | 150 | Action body: 151 | 152 | ```xml 153 | 154 | ui4 155 | i4 156 | 157 | ``` 158 | 159 | Inputs: 160 | 161 | | parameter | type | description | 162 | |:----------|:-----|:------------| 163 | | **InstanceID** | `ui4` | InstanceID should always be `0` | 164 | | **Adjustment** | `i4` | Number between -100 and +100 | 165 | 166 | Outputs: 167 | 168 | | parameter | type | description | 169 | |:----------|:-----|:------------| 170 | | **NewVolume** | `ui2` | | 171 | 172 | **Remarks** Should be send to coordinator only 173 | 174 | ### SnapshotGroupVolume 175 | 176 | Creates a new group volume snapshot, the volume ratio between all players. It is used by SetGroupVolume and SetRelativeGroupVolume 177 | 178 | Action body: 179 | 180 | ```xml 181 | 182 | ui4 183 | 184 | ``` 185 | 186 | Inputs: 187 | 188 | | parameter | type | description | 189 | |:----------|:-----|:------------| 190 | | **InstanceID** | `ui4` | InstanceID should always be `0` | 191 | 192 | **Remarks** Should be send to coordinator only 193 | 194 | ## Events 195 | 196 | The GroupRenderingControlService has variables that might be emitted if you subscribe to events. 197 | 198 | ### Subscribe to events 199 | 200 | ```text 201 | SUBSCRIBE /MediaRenderer/GroupRenderingControl/Event 202 | Host: 192.168.x.x:1400 203 | callback: 204 | NT: upnp:event 205 | Timeout: Second-3600 206 | ``` 207 | 208 | ### Event variables 209 | 210 | | Variable | Sends events* | type | possible values | 211 | |:---------|:-------------|:-----|:----------------| 212 | | GroupMute | ✔ | `boolean` | `1` for true and `0` for false | 213 | | GroupVolume | ✔ | `ui2` | | 214 | | GroupVolumeChangeable | ✔ | `boolean` | `1` for true and `0` for false | 215 | 216 | If the variable has a `✔` in the Sends events column, the service discovery specifies this variable emits events. Other properties might be send as a part of `LastChange` 217 | 218 | ## Custom errors 219 | 220 | The GroupRenderingControlService has the following known custom errors. 221 | 222 | | Error code | Description | 223 | |:-----------|:------------| 224 | | `701` | Player isn't the coordinator | 225 | 226 | --- 227 | 228 | This file is automatically generated with [@svrooij/sonos-docs](https://github.com/svrooij/sonos-api-docs/tree/main/generator/sonos-docs), do not edit manually. 229 | 230 | | Device | Software generation | Software version | Discovery date | 231 | |:-------|:--------------------|:-----------------|:---------------| 232 | | `Sonos Play:1 (S1)` | S2 | 77.4-49290 | 2024-02-13T15:56:06.184Z | 233 | | `Sonos One (S13)` | S2 | 63.2-90210 | 2021-07-21T23:31:19.273Z | 234 | | `Sonos Beam (S14)` | S2 | 64.3-19080 | 2021-08-18T06:04:08.308Z | 235 | | `Sonos One (S18)` | S2 | 77.4-49290 | 2024-02-13T15:55:36.464Z | 236 | | `SYMFONISK Bookshelf (S21)` | S2 | 66.4-23300 | 2022-01-01T11:41:01.361Z | 237 | | `Sonos Roam (S27)` | S2 | 63.2-90210 | 2021-07-21T23:31:31.207Z | 238 | | `Sonos Play:3 (S3)` | S2 | 64.3-19080 | 2021-08-18T06:09:36.692Z | 239 | | `SYMFONISK Bookshelf (S33)` | S2 | 77.4-49290 | 2024-02-13T15:55:24.423Z | 240 | | `Sonos One SL (S38)` | S2 | 72.2-40060 | 2023-05-22T16:39:25.503Z | 241 | | `Sonos Play:5 (S6)` | S2 | 64.3-19080 | 2021-08-18T06:06:35.970Z | 242 | | `Sonos Playbar (S9)` | S2 | 77.4-49290 | 2024-02-13T15:55:46.307Z | 243 | | `Sonos Sub (Sub)` | S2 | 63.2-90210 | 2021-07-21T23:31:40.304Z | 244 | -------------------------------------------------------------------------------- /docs/services/ht-control.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: HTControl 4 | parent: Sonos Services 5 | --- 6 | # HTControl service 7 | {: .no_toc } 8 | 9 | Service related to the TV remote control 10 | 11 | The HTControl service is available on these models: `Sonos Beam (S14) S2` / `Sonos Playbar (S9) S2`. 12 | 13 | 1. TOC 14 | {:toc} 15 | 16 | --- 17 | 18 | ## Service data 19 | {: .no_toc } 20 | 21 | | name | value | 22 | |:-----|:------| 23 | | **Control URL** | `http://192.168.x.x:1400/HTControl/Control` | 24 | | **Event subscription URL** | `http://192.168.x.x:1400/HTControl/Event` | 25 | | **Discovery URL** | `http://192.168.x.x:1400/xml/HTControl1.xml` | 26 | | **Service ID** | `urn:upnp-org:serviceId:HTControl` | 27 | | **Service type** | `urn:schemas-upnp-org:service:HTControl:1` | 28 | 29 | ### Sample request 30 | {: .no_toc } 31 | 32 | ```text 33 | POST /HTControl/Control 34 | Host: 192.168.x.x:1400 35 | soapaction: "urn:schemas-upnp-org:service:HTControl:1#{ActionName}" 36 | Content-Type: text/xml; charset="utf-8" 37 | 38 | 39 | 40 | 41 | {ActionBodyHere} 42 | 43 | 44 | ``` 45 | 46 | --- 47 | 48 | ## Available actions 49 | 50 | ### CommitLearnedIRCodes 51 | 52 | Action body: 53 | 54 | ```xml 55 | 56 | string 57 | 58 | ``` 59 | 60 | Inputs: 61 | 62 | | parameter | type | description | 63 | |:----------|:-----|:------------| 64 | | **Name** | `string` | | 65 | 66 | ### GetIRRepeaterState 67 | 68 | Action body: 69 | 70 | ```xml 71 | 72 | 73 | ``` 74 | 75 | No input arguments 76 | 77 | Outputs: 78 | 79 | | parameter | type | description | 80 | |:----------|:-----|:------------| 81 | | **CurrentIRRepeaterState** | `string` | Possible values: `On` / `Off` / `Disabled` | 82 | 83 | ### GetLEDFeedbackState 84 | 85 | Action body: 86 | 87 | ```xml 88 | 89 | 90 | ``` 91 | 92 | No input arguments 93 | 94 | Outputs: 95 | 96 | | parameter | type | description | 97 | |:----------|:-----|:------------| 98 | | **LEDFeedbackState** | `string` | Possible values: `On` / `Off` | 99 | 100 | ### IdentifyIRRemote 101 | 102 | Action body: 103 | 104 | ```xml 105 | 106 | ui4 107 | 108 | ``` 109 | 110 | Inputs: 111 | 112 | | parameter | type | description | 113 | |:----------|:-----|:------------| 114 | | **Timeout** | `ui4` | | 115 | 116 | ### IsRemoteConfigured 117 | 118 | Action body: 119 | 120 | ```xml 121 | 122 | 123 | ``` 124 | 125 | No input arguments 126 | 127 | Outputs: 128 | 129 | | parameter | type | description | 130 | |:----------|:-----|:------------| 131 | | **RemoteConfigured** | `boolean` | `1` for true and `0` for false | 132 | 133 | ### LearnIRCode 134 | 135 | Action body: 136 | 137 | ```xml 138 | 139 | string 140 | ui4 141 | 142 | ``` 143 | 144 | Inputs: 145 | 146 | | parameter | type | description | 147 | |:----------|:-----|:------------| 148 | | **IRCode** | `string` | | 149 | | **Timeout** | `ui4` | | 150 | 151 | ### SetIRRepeaterState 152 | 153 | Action body: 154 | 155 | ```xml 156 | 157 | string 158 | 159 | ``` 160 | 161 | Inputs: 162 | 163 | | parameter | type | description | 164 | |:----------|:-----|:------------| 165 | | **DesiredIRRepeaterState** | `string` | Allowed values: `On` / `Off` / `Disabled` | 166 | 167 | ### SetLEDFeedbackState 168 | 169 | Action body: 170 | 171 | ```xml 172 | 173 | string 174 | 175 | ``` 176 | 177 | Inputs: 178 | 179 | | parameter | type | description | 180 | |:----------|:-----|:------------| 181 | | **LEDFeedbackState** | `string` | Allowed values: `On` / `Off` | 182 | 183 | ## Events 184 | 185 | The HTControlService has variables that might be emitted if you subscribe to events. 186 | 187 | ### Subscribe to events 188 | 189 | ```text 190 | SUBSCRIBE /HTControl/Event 191 | Host: 192.168.x.x:1400 192 | callback: 193 | NT: upnp:event 194 | Timeout: Second-3600 195 | ``` 196 | 197 | ### Event variables 198 | 199 | | Variable | Sends events* | type | possible values | 200 | |:---------|:-------------|:-----|:----------------| 201 | | IRRepeaterState | ✔ | `string` | `On` / `Off` / `Disabled` | 202 | | LEDFeedbackState | | `string` | `On` / `Off` | 203 | | RemoteConfigured | | `boolean` | `1` for true and `0` for false | 204 | | TOSLinkConnected | ✔ | `boolean` | `1` for true and `0` for false | 205 | 206 | If the variable has a `✔` in the Sends events column, the service discovery specifies this variable emits events. Other properties might be send as a part of `LastChange` 207 | 208 | --- 209 | 210 | This file is automatically generated with [@svrooij/sonos-docs](https://github.com/svrooij/sonos-api-docs/tree/main/generator/sonos-docs), do not edit manually. 211 | 212 | | Device | Software generation | Software version | Discovery date | 213 | |:-------|:--------------------|:-----------------|:---------------| 214 | | `Sonos Beam (S14)` | S2 | 64.3-19080 | 2021-08-18T06:04:08.308Z | 215 | | `Sonos Playbar (S9)` | S2 | 77.4-49290 | 2024-02-13T15:55:46.307Z | 216 | -------------------------------------------------------------------------------- /docs/services/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Sonos Services 4 | has_children: true 5 | nav_order: 5 6 | has_toc: false 7 | --- 8 | 9 | # Sonos SOAP Services 10 | {: .no_toc } 11 | 12 | Every sonos speaker has several soap services. Each service has one or more actions you can call. 13 | 14 | ## UPNP specifications 15 | 16 | Sonos speaker follow the [MediaServer:4 and MediaRenderer:3 specifications](https://openconnectivity.org/developer/specifications/upnp-resources/upnp/mediaserver4-and-mediarenderer3/) by the [Open Connectivity Foundation](https://openconnectivity.org/). 17 | These documents can provide you with some extra guidelines. More details can be found at [Sonos communication]({{'/sonos-communication.html' | relative_url }}), which show you how to exactly do a call to the sonos speakers. 18 | 19 | ## All available services 20 | {: .no_toc } 21 | 22 | | Service | Description | 23 | |:--------|:------------| 24 | | [**AlarmClock**](alarm-clock.html) | Control the sonos alarms and times | 25 | | [**AudioIn**](audio-in.html) | Control line in | 26 | | [**AVTransport**](av-transport.html) | Service that controls stuff related to transport (play/pause/next/special URLs) | 27 | | [**ConnectionManager**](connection-manager.html) | Services related to connections and protocols | 28 | | [**ContentDirectory**](content-directory.html) | Browse for local content | 29 | | [**DeviceProperties**](device-properties.html) | Modify device properties, like LED status and stereo pairs | 30 | | [**GroupManagement**](group-management.html) | Services related to groups | 31 | | [**GroupRenderingControl**](group-rendering-control.html) | Volume related controls for groups | 32 | | [**HTControl**](ht-control.html) | Service related to the TV remote control | 33 | | [**MusicServices**](music-services.html) | Access to external music services, like Spotify or Youtube Music | 34 | | [**QPlay**](q-play.html) | Services related to Chinese Tencent Qplay service | 35 | | [**Queue**](queue.html) | Modify and browse queues | 36 | | [**RenderingControl**](rendering-control.html) | Volume related controls | 37 | | [**SystemProperties**](system-properties.html) | Manage system-wide settings, mainly account stuff | 38 | | [**VirtualLineIn**](virtual-line-in.html) | | 39 | | [**ZoneGroupTopology**](zone-group-topology.html) | Zone config stuff, eg getting all the configured sonos zones | 40 | 41 | ## UPNP errors 42 | 43 | These are the default UPNP errors. 44 | 45 | | Error code | Description | 46 | |:-----------|:------------| 47 | | `400` | Bad request | 48 | | `401` | Invalid action | 49 | | `402` | Invalid args | 50 | | `404` | Invalid var | 51 | | `412` | Precondition failed | 52 | | `501` | Action failed | 53 | | `600` | Argument value invalid | 54 | | `601` | Argument value out of range | 55 | | `602` | Optional action not implemented | 56 | | `603` | Out of memory | 57 | | `604` | Human intervention required | 58 | | `605` | String argument too long | 59 | | `606` | Action not authorized | 60 | | `607` | Signature failure | 61 | | `608` | Signature missing | 62 | | `609` | Not encrypted | 63 | | `610` | Invalid sequence | 64 | | `611` | Invalid control URL | 65 | | `612` | No such session | 66 | 67 | --- 68 | 69 | This file is automatically generated with [@svrooij/sonos-docs](https://github.com/svrooij/sonos-api-docs/tree/main/generator/sonos-docs), do not edit manually. 70 | 71 | | Device | Software generation | Software version | Discovery date | 72 | |:-------|:--------------------|:-----------------|:---------------| 73 | | `Sonos Play:1 (S1)` | S2 | 77.4-49290 | 2024-02-13T15:56:06.184Z | 74 | | `Sonos One (S13)` | S2 | 63.2-90210 | 2021-07-21T23:31:19.273Z | 75 | | `Sonos Beam (S14)` | S2 | 64.3-19080 | 2021-08-18T06:04:08.308Z | 76 | | `Sonos One (S18)` | S2 | 77.4-49290 | 2024-02-13T15:55:36.464Z | 77 | | `SYMFONISK Bookshelf (S21)` | S2 | 66.4-23300 | 2022-01-01T11:41:01.361Z | 78 | | `Sonos Roam (S27)` | S2 | 63.2-90210 | 2021-07-21T23:31:31.207Z | 79 | | `Sonos Play:3 (S3)` | S2 | 64.3-19080 | 2021-08-18T06:09:36.692Z | 80 | | `SYMFONISK Bookshelf (S33)` | S2 | 77.4-49290 | 2024-02-13T15:55:24.423Z | 81 | | `Sonos One SL (S38)` | S2 | 72.2-40060 | 2023-05-22T16:39:25.503Z | 82 | | `Sonos Play:5 (S6)` | S2 | 64.3-19080 | 2021-08-18T06:06:35.970Z | 83 | | `Sonos Playbar (S9)` | S2 | 77.4-49290 | 2024-02-13T15:55:46.307Z | 84 | | `Sonos Sub (Sub)` | S2 | 63.2-90210 | 2021-07-21T23:31:40.304Z | 85 | -------------------------------------------------------------------------------- /docs/services/music-services.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: MusicServices 4 | parent: Sonos Services 5 | --- 6 | # MusicServices service 7 | {: .no_toc } 8 | 9 | Access to external music services, like Spotify or Youtube Music 10 | 11 | The MusicServices service is available on these models: `Sonos Play:1 (S1) S2` / `Sonos One (S13) S2` / `Sonos Beam (S14) S2` / `Sonos One (S18) S2` / `SYMFONISK Bookshelf (S21) S2` / `Sonos Roam (S27) S2` / `Sonos Play:3 (S3) S2` / `SYMFONISK Bookshelf (S33) S2` / `Sonos One SL (S38) S2` / `Sonos Play:5 (S6) S2` / `Sonos Playbar (S9) S2` / `Sonos Sub (Sub) S2`. 12 | 13 | 1. TOC 14 | {:toc} 15 | 16 | --- 17 | 18 | ## Service data 19 | {: .no_toc } 20 | 21 | | name | value | 22 | |:-----|:------| 23 | | **Control URL** | `http://192.168.x.x:1400/MusicServices/Control` | 24 | | **Event subscription URL** | `http://192.168.x.x:1400/MusicServices/Event` | 25 | | **Discovery URL** | `http://192.168.x.x:1400/xml/MusicServices1.xml` | 26 | | **Service ID** | `urn:upnp-org:serviceId:MusicServices` | 27 | | **Service type** | `urn:schemas-upnp-org:service:MusicServices:1` | 28 | 29 | ### Sample request 30 | {: .no_toc } 31 | 32 | ```text 33 | POST /MusicServices/Control 34 | Host: 192.168.x.x:1400 35 | soapaction: "urn:schemas-upnp-org:service:MusicServices:1#{ActionName}" 36 | Content-Type: text/xml; charset="utf-8" 37 | 38 | 39 | 40 | 41 | {ActionBodyHere} 42 | 43 | 44 | ``` 45 | 46 | --- 47 | 48 | ## Available actions 49 | 50 | ### GetSessionId 51 | 52 | Action body: 53 | 54 | ```xml 55 | 56 | ui4 57 | string 58 | 59 | ``` 60 | 61 | Inputs: 62 | 63 | | parameter | type | description | 64 | |:----------|:-----|:------------| 65 | | **ServiceId** | `ui4` | | 66 | | **Username** | `string` | | 67 | 68 | Outputs: 69 | 70 | | parameter | type | description | 71 | |:----------|:-----|:------------| 72 | | **SessionId** | `string` | | 73 | 74 | ### ListAvailableServices 75 | 76 | Load music service list as xml 77 | 78 | Action body: 79 | 80 | ```xml 81 | 82 | 83 | ``` 84 | 85 | No input arguments 86 | 87 | Outputs: 88 | 89 | | parameter | type | description | 90 | |:----------|:-----|:------------| 91 | | **AvailableServiceDescriptorList** | `string` | | 92 | | **AvailableServiceTypeList** | `string` | | 93 | | **AvailableServiceListVersion** | `string` | | 94 | 95 | **Remarks** Some libraries also support ListAndParseAvailableServices 96 | 97 | ### UpdateAvailableServices 98 | 99 | Action body: 100 | 101 | ```xml 102 | 103 | 104 | ``` 105 | 106 | No input arguments 107 | 108 | ## Events 109 | 110 | The MusicServicesService has variables that might be emitted if you subscribe to events. 111 | 112 | ### Subscribe to events 113 | 114 | ```text 115 | SUBSCRIBE /MusicServices/Event 116 | Host: 192.168.x.x:1400 117 | callback: 118 | NT: upnp:event 119 | Timeout: Second-3600 120 | ``` 121 | 122 | ### Event variables 123 | 124 | | Variable | Sends events* | type | possible values | 125 | |:---------|:-------------|:-----|:----------------| 126 | | ServiceId | | `ui4` | | 127 | | ServiceListVersion | ✔ | `string` | | 128 | | SessionId | | `string` | | 129 | | Username | | `string` | | 130 | 131 | If the variable has a `✔` in the Sends events column, the service discovery specifies this variable emits events. Other properties might be send as a part of `LastChange` 132 | 133 | --- 134 | 135 | This file is automatically generated with [@svrooij/sonos-docs](https://github.com/svrooij/sonos-api-docs/tree/main/generator/sonos-docs), do not edit manually. 136 | 137 | | Device | Software generation | Software version | Discovery date | 138 | |:-------|:--------------------|:-----------------|:---------------| 139 | | `Sonos Play:1 (S1)` | S2 | 77.4-49290 | 2024-02-13T15:56:06.184Z | 140 | | `Sonos One (S13)` | S2 | 63.2-90210 | 2021-07-21T23:31:19.273Z | 141 | | `Sonos Beam (S14)` | S2 | 64.3-19080 | 2021-08-18T06:04:08.308Z | 142 | | `Sonos One (S18)` | S2 | 77.4-49290 | 2024-02-13T15:55:36.464Z | 143 | | `SYMFONISK Bookshelf (S21)` | S2 | 66.4-23300 | 2022-01-01T11:41:01.361Z | 144 | | `Sonos Roam (S27)` | S2 | 63.2-90210 | 2021-07-21T23:31:31.207Z | 145 | | `Sonos Play:3 (S3)` | S2 | 64.3-19080 | 2021-08-18T06:09:36.692Z | 146 | | `SYMFONISK Bookshelf (S33)` | S2 | 77.4-49290 | 2024-02-13T15:55:24.423Z | 147 | | `Sonos One SL (S38)` | S2 | 72.2-40060 | 2023-05-22T16:39:25.503Z | 148 | | `Sonos Play:5 (S6)` | S2 | 64.3-19080 | 2021-08-18T06:06:35.970Z | 149 | | `Sonos Playbar (S9)` | S2 | 77.4-49290 | 2024-02-13T15:55:46.307Z | 150 | | `Sonos Sub (Sub)` | S2 | 63.2-90210 | 2021-07-21T23:31:40.304Z | 151 | -------------------------------------------------------------------------------- /docs/services/q-play.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: QPlay 4 | parent: Sonos Services 5 | --- 6 | # QPlay service 7 | {: .no_toc } 8 | 9 | Services related to Chinese Tencent Qplay service 10 | 11 | The QPlay service is available on these models: `Sonos Play:1 (S1) S2` / `Sonos One (S13) S2` / `Sonos Beam (S14) S2` / `Sonos One (S18) S2` / `SYMFONISK Bookshelf (S21) S2` / `Sonos Roam (S27) S2` / `Sonos Play:3 (S3) S2` / `SYMFONISK Bookshelf (S33) S2` / `Sonos One SL (S38) S2` / `Sonos Play:5 (S6) S2` / `Sonos Playbar (S9) S2` / `Sonos Sub (Sub) S2`. 12 | 13 | 1. TOC 14 | {:toc} 15 | 16 | --- 17 | 18 | ## Service data 19 | {: .no_toc } 20 | 21 | | name | value | 22 | |:-----|:------| 23 | | **Control URL** | `http://192.168.x.x:1400/QPlay/Control` | 24 | | **Event subscription URL** | `http://192.168.x.x:1400/QPlay/Event` | 25 | | **Discovery URL** | `http://192.168.x.x:1400/xml/QPlay1.xml` | 26 | | **Service ID** | `urn:tencent-com:serviceId:QPlay` | 27 | | **Service type** | `urn:schemas-tencent-com:service:QPlay:1` | 28 | 29 | ### Sample request 30 | {: .no_toc } 31 | 32 | ```text 33 | POST /QPlay/Control 34 | Host: 192.168.x.x:1400 35 | soapaction: "urn:schemas-tencent-com:service:QPlay:1#{ActionName}" 36 | Content-Type: text/xml; charset="utf-8" 37 | 38 | 39 | 40 | 41 | {ActionBodyHere} 42 | 43 | 44 | ``` 45 | 46 | --- 47 | 48 | ## Available actions 49 | 50 | ### QPlayAuth 51 | 52 | Action body: 53 | 54 | ```xml 55 | 56 | string 57 | 58 | ``` 59 | 60 | Inputs: 61 | 62 | | parameter | type | description | 63 | |:----------|:-----|:------------| 64 | | **Seed** | `string` | | 65 | 66 | Outputs: 67 | 68 | | parameter | type | description | 69 | |:----------|:-----|:------------| 70 | | **Code** | `string` | | 71 | | **MID** | `string` | | 72 | | **DID** | `string` | | 73 | 74 | 75 | --- 76 | 77 | This file is automatically generated with [@svrooij/sonos-docs](https://github.com/svrooij/sonos-api-docs/tree/main/generator/sonos-docs), do not edit manually. 78 | 79 | | Device | Software generation | Software version | Discovery date | 80 | |:-------|:--------------------|:-----------------|:---------------| 81 | | `Sonos Play:1 (S1)` | S2 | 77.4-49290 | 2024-02-13T15:56:06.184Z | 82 | | `Sonos One (S13)` | S2 | 63.2-90210 | 2021-07-21T23:31:19.273Z | 83 | | `Sonos Beam (S14)` | S2 | 64.3-19080 | 2021-08-18T06:04:08.308Z | 84 | | `Sonos One (S18)` | S2 | 77.4-49290 | 2024-02-13T15:55:36.464Z | 85 | | `SYMFONISK Bookshelf (S21)` | S2 | 66.4-23300 | 2022-01-01T11:41:01.361Z | 86 | | `Sonos Roam (S27)` | S2 | 63.2-90210 | 2021-07-21T23:31:31.207Z | 87 | | `Sonos Play:3 (S3)` | S2 | 64.3-19080 | 2021-08-18T06:09:36.692Z | 88 | | `SYMFONISK Bookshelf (S33)` | S2 | 77.4-49290 | 2024-02-13T15:55:24.423Z | 89 | | `Sonos One SL (S38)` | S2 | 72.2-40060 | 2023-05-22T16:39:25.503Z | 90 | | `Sonos Play:5 (S6)` | S2 | 64.3-19080 | 2021-08-18T06:06:35.970Z | 91 | | `Sonos Playbar (S9)` | S2 | 77.4-49290 | 2024-02-13T15:55:46.307Z | 92 | | `Sonos Sub (Sub)` | S2 | 63.2-90210 | 2021-07-21T23:31:40.304Z | 93 | -------------------------------------------------------------------------------- /docs/services/queue.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Queue 4 | parent: Sonos Services 5 | --- 6 | # Queue service 7 | {: .no_toc } 8 | 9 | Modify and browse queues 10 | 11 | The Queue service is available on these models: `Sonos Play:1 (S1) S2` / `Sonos One (S13) S2` / `Sonos Beam (S14) S2` / `Sonos One (S18) S2` / `SYMFONISK Bookshelf (S21) S2` / `Sonos Roam (S27) S2` / `Sonos Play:3 (S3) S2` / `SYMFONISK Bookshelf (S33) S2` / `Sonos One SL (S38) S2` / `Sonos Play:5 (S6) S2` / `Sonos Playbar (S9) S2` / `Sonos Sub (Sub) S2`. 12 | 13 | 1. TOC 14 | {:toc} 15 | 16 | --- 17 | 18 | ## Service data 19 | {: .no_toc } 20 | 21 | | name | value | 22 | |:-----|:------| 23 | | **Control URL** | `http://192.168.x.x:1400/MediaRenderer/Queue/Control` | 24 | | **Event subscription URL** | `http://192.168.x.x:1400/MediaRenderer/Queue/Event` | 25 | | **Discovery URL** | `http://192.168.x.x:1400/xml/Queue1.xml` | 26 | | **Service ID** | `urn:sonos-com:serviceId:Queue` | 27 | | **Service type** | `urn:schemas-sonos-com:service:Queue:1` | 28 | 29 | ### Sample request 30 | {: .no_toc } 31 | 32 | ```text 33 | POST /MediaRenderer/Queue/Control 34 | Host: 192.168.x.x:1400 35 | soapaction: "urn:schemas-sonos-com:service:Queue:1#{ActionName}" 36 | Content-Type: text/xml; charset="utf-8" 37 | 38 | 39 | 40 | 41 | {ActionBodyHere} 42 | 43 | 44 | ``` 45 | 46 | --- 47 | 48 | ## Available actions 49 | 50 | ### AddMultipleURIs 51 | 52 | Action body: 53 | 54 | ```xml 55 | 56 | ui4 57 | ui4 58 | string 59 | string 60 | ui4 61 | boolean 62 | ui4 63 | string 64 | 65 | ``` 66 | 67 | Inputs: 68 | 69 | | parameter | type | description | 70 | |:----------|:-----|:------------| 71 | | **QueueID** | `ui4` | | 72 | | **UpdateID** | `ui4` | | 73 | | **ContainerURI** | `string` | | 74 | | **ContainerMetaData** | `string` | Embedded XML | 75 | | **DesiredFirstTrackNumberEnqueued** | `ui4` | | 76 | | **EnqueueAsNext** | `boolean` | Allowed values: `1` (= true) / `0` (= false) | 77 | | **NumberOfURIs** | `ui4` | | 78 | | **EnqueuedURIsAndMetaData** | `string` | Embedded XML | 79 | 80 | Outputs: 81 | 82 | | parameter | type | description | 83 | |:----------|:-----|:------------| 84 | | **FirstTrackNumberEnqueued** | `ui4` | | 85 | | **NumTracksAdded** | `ui4` | | 86 | | **NewQueueLength** | `ui4` | | 87 | | **NewUpdateID** | `ui4` | | 88 | 89 | ### AddURI 90 | 91 | Action body: 92 | 93 | ```xml 94 | 95 | ui4 96 | ui4 97 | string 98 | string 99 | ui4 100 | boolean 101 | 102 | ``` 103 | 104 | Inputs: 105 | 106 | | parameter | type | description | 107 | |:----------|:-----|:------------| 108 | | **QueueID** | `ui4` | | 109 | | **UpdateID** | `ui4` | | 110 | | **EnqueuedURI** | `string` | | 111 | | **EnqueuedURIMetaData** | `string` | Embedded XML | 112 | | **DesiredFirstTrackNumberEnqueued** | `ui4` | | 113 | | **EnqueueAsNext** | `boolean` | Allowed values: `1` (= true) / `0` (= false) | 114 | 115 | Outputs: 116 | 117 | | parameter | type | description | 118 | |:----------|:-----|:------------| 119 | | **FirstTrackNumberEnqueued** | `ui4` | | 120 | | **NumTracksAdded** | `ui4` | | 121 | | **NewQueueLength** | `ui4` | | 122 | | **NewUpdateID** | `ui4` | | 123 | 124 | ### AttachQueue 125 | 126 | Action body: 127 | 128 | ```xml 129 | 130 | string 131 | 132 | ``` 133 | 134 | Inputs: 135 | 136 | | parameter | type | description | 137 | |:----------|:-----|:------------| 138 | | **QueueOwnerID** | `string` | | 139 | 140 | Outputs: 141 | 142 | | parameter | type | description | 143 | |:----------|:-----|:------------| 144 | | **QueueID** | `ui4` | | 145 | | **QueueOwnerContext** | `string` | | 146 | 147 | ### Backup 148 | 149 | Action body: 150 | 151 | ```xml 152 | 153 | 154 | ``` 155 | 156 | No input arguments 157 | 158 | ### Browse 159 | 160 | Action body: 161 | 162 | ```xml 163 | 164 | ui4 165 | ui4 166 | ui4 167 | 168 | ``` 169 | 170 | Inputs: 171 | 172 | | parameter | type | description | 173 | |:----------|:-----|:------------| 174 | | **QueueID** | `ui4` | | 175 | | **StartingIndex** | `ui4` | | 176 | | **RequestedCount** | `ui4` | | 177 | 178 | Outputs: 179 | 180 | | parameter | type | description | 181 | |:----------|:-----|:------------| 182 | | **Result** | `string` | | 183 | | **NumberReturned** | `ui4` | | 184 | | **TotalMatches** | `ui4` | | 185 | | **UpdateID** | `ui4` | | 186 | 187 | ### CreateQueue 188 | 189 | Action body: 190 | 191 | ```xml 192 | 193 | string 194 | string 195 | string 196 | 197 | ``` 198 | 199 | Inputs: 200 | 201 | | parameter | type | description | 202 | |:----------|:-----|:------------| 203 | | **QueueOwnerID** | `string` | | 204 | | **QueueOwnerContext** | `string` | | 205 | | **QueuePolicy** | `string` | | 206 | 207 | Outputs: 208 | 209 | | parameter | type | description | 210 | |:----------|:-----|:------------| 211 | | **QueueID** | `ui4` | | 212 | 213 | ### RemoveAllTracks 214 | 215 | Action body: 216 | 217 | ```xml 218 | 219 | ui4 220 | ui4 221 | 222 | ``` 223 | 224 | Inputs: 225 | 226 | | parameter | type | description | 227 | |:----------|:-----|:------------| 228 | | **QueueID** | `ui4` | | 229 | | **UpdateID** | `ui4` | | 230 | 231 | Outputs: 232 | 233 | | parameter | type | description | 234 | |:----------|:-----|:------------| 235 | | **NewUpdateID** | `ui4` | | 236 | 237 | ### RemoveTrackRange 238 | 239 | Action body: 240 | 241 | ```xml 242 | 243 | ui4 244 | ui4 245 | ui4 246 | ui4 247 | 248 | ``` 249 | 250 | Inputs: 251 | 252 | | parameter | type | description | 253 | |:----------|:-----|:------------| 254 | | **QueueID** | `ui4` | | 255 | | **UpdateID** | `ui4` | | 256 | | **StartingIndex** | `ui4` | | 257 | | **NumberOfTracks** | `ui4` | | 258 | 259 | Outputs: 260 | 261 | | parameter | type | description | 262 | |:----------|:-----|:------------| 263 | | **NewUpdateID** | `ui4` | | 264 | 265 | ### ReorderTracks 266 | 267 | Action body: 268 | 269 | ```xml 270 | 271 | ui4 272 | ui4 273 | ui4 274 | ui4 275 | ui4 276 | 277 | ``` 278 | 279 | Inputs: 280 | 281 | | parameter | type | description | 282 | |:----------|:-----|:------------| 283 | | **QueueID** | `ui4` | | 284 | | **StartingIndex** | `ui4` | | 285 | | **NumberOfTracks** | `ui4` | | 286 | | **InsertBefore** | `ui4` | | 287 | | **UpdateID** | `ui4` | | 288 | 289 | Outputs: 290 | 291 | | parameter | type | description | 292 | |:----------|:-----|:------------| 293 | | **NewUpdateID** | `ui4` | | 294 | 295 | ### ReplaceAllTracks 296 | 297 | Action body: 298 | 299 | ```xml 300 | 301 | ui4 302 | ui4 303 | string 304 | string 305 | ui4 306 | string 307 | ui4 308 | string 309 | 310 | ``` 311 | 312 | Inputs: 313 | 314 | | parameter | type | description | 315 | |:----------|:-----|:------------| 316 | | **QueueID** | `ui4` | | 317 | | **UpdateID** | `ui4` | | 318 | | **ContainerURI** | `string` | | 319 | | **ContainerMetaData** | `string` | Embedded XML | 320 | | **CurrentTrackIndex** | `ui4` | | 321 | | **NewCurrentTrackIndices** | `string` | | 322 | | **NumberOfURIs** | `ui4` | | 323 | | **EnqueuedURIsAndMetaData** | `string` | Embedded XML | 324 | 325 | Outputs: 326 | 327 | | parameter | type | description | 328 | |:----------|:-----|:------------| 329 | | **NewQueueLength** | `ui4` | | 330 | | **NewUpdateID** | `ui4` | | 331 | 332 | ### SaveAsSonosPlaylist 333 | 334 | Action body: 335 | 336 | ```xml 337 | 338 | ui4 339 | string 340 | string 341 | 342 | ``` 343 | 344 | Inputs: 345 | 346 | | parameter | type | description | 347 | |:----------|:-----|:------------| 348 | | **QueueID** | `ui4` | | 349 | | **Title** | `string` | | 350 | | **ObjectID** | `string` | | 351 | 352 | Outputs: 353 | 354 | | parameter | type | description | 355 | |:----------|:-----|:------------| 356 | | **AssignedObjectID** | `string` | | 357 | 358 | ## Events 359 | 360 | The QueueService has variables that might be emitted if you subscribe to events. 361 | 362 | ### Subscribe to events 363 | 364 | ```text 365 | SUBSCRIBE /MediaRenderer/Queue/Event 366 | Host: 192.168.x.x:1400 367 | callback: 368 | NT: upnp:event 369 | Timeout: Second-3600 370 | ``` 371 | 372 | ### Event variables 373 | 374 | | Variable | Sends events* | type | possible values | 375 | |:---------|:-------------|:-----|:----------------| 376 | | Curated | | `boolean` | `1` for true and `0` for false | 377 | | LastChange | ✔ | `string` | | 378 | | UpdateID | | `ui4` | | 379 | 380 | If the variable has a `✔` in the Sends events column, the service discovery specifies this variable emits events. Other properties might be send as a part of `LastChange` 381 | 382 | --- 383 | 384 | This file is automatically generated with [@svrooij/sonos-docs](https://github.com/svrooij/sonos-api-docs/tree/main/generator/sonos-docs), do not edit manually. 385 | 386 | | Device | Software generation | Software version | Discovery date | 387 | |:-------|:--------------------|:-----------------|:---------------| 388 | | `Sonos Play:1 (S1)` | S2 | 77.4-49290 | 2024-02-13T15:56:06.184Z | 389 | | `Sonos One (S13)` | S2 | 63.2-90210 | 2021-07-21T23:31:19.273Z | 390 | | `Sonos Beam (S14)` | S2 | 64.3-19080 | 2021-08-18T06:04:08.308Z | 391 | | `Sonos One (S18)` | S2 | 77.4-49290 | 2024-02-13T15:55:36.464Z | 392 | | `SYMFONISK Bookshelf (S21)` | S2 | 66.4-23300 | 2022-01-01T11:41:01.361Z | 393 | | `Sonos Roam (S27)` | S2 | 63.2-90210 | 2021-07-21T23:31:31.207Z | 394 | | `Sonos Play:3 (S3)` | S2 | 64.3-19080 | 2021-08-18T06:09:36.692Z | 395 | | `SYMFONISK Bookshelf (S33)` | S2 | 77.4-49290 | 2024-02-13T15:55:24.423Z | 396 | | `Sonos One SL (S38)` | S2 | 72.2-40060 | 2023-05-22T16:39:25.503Z | 397 | | `Sonos Play:5 (S6)` | S2 | 64.3-19080 | 2021-08-18T06:06:35.970Z | 398 | | `Sonos Playbar (S9)` | S2 | 77.4-49290 | 2024-02-13T15:55:46.307Z | 399 | | `Sonos Sub (Sub)` | S2 | 63.2-90210 | 2021-07-21T23:31:40.304Z | 400 | -------------------------------------------------------------------------------- /docs/services/virtual-line-in.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: VirtualLineIn 4 | parent: Sonos Services 5 | --- 6 | # VirtualLineIn service 7 | {: .no_toc } 8 | 9 | The VirtualLineIn service is available on these models: `Sonos Play:1 (S1) S2` / `Sonos One (S13) S2` / `Sonos Beam (S14) S2` / `Sonos One (S18) S2` / `SYMFONISK Bookshelf (S21) S2` / `Sonos Roam (S27) S2` / `Sonos Play:3 (S3) S2` / `SYMFONISK Bookshelf (S33) S2` / `Sonos One SL (S38) S2` / `Sonos Play:5 (S6) S2` / `Sonos Playbar (S9) S2` / `Sonos Sub (Sub) S2`. 10 | 11 | 1. TOC 12 | {:toc} 13 | 14 | --- 15 | 16 | ## Service data 17 | {: .no_toc } 18 | 19 | | name | value | 20 | |:-----|:------| 21 | | **Control URL** | `http://192.168.x.x:1400/MediaRenderer/VirtualLineIn/Control` | 22 | | **Event subscription URL** | `http://192.168.x.x:1400/MediaRenderer/VirtualLineIn/Event` | 23 | | **Discovery URL** | `http://192.168.x.x:1400/xml/VirtualLineIn1.xml` | 24 | | **Service ID** | `urn:upnp-org:serviceId:VirtualLineIn` | 25 | | **Service type** | `urn:schemas-upnp-org:service:VirtualLineIn:1` | 26 | 27 | ### Sample request 28 | {: .no_toc } 29 | 30 | ```text 31 | POST /MediaRenderer/VirtualLineIn/Control 32 | Host: 192.168.x.x:1400 33 | soapaction: "urn:schemas-upnp-org:service:VirtualLineIn:1#{ActionName}" 34 | Content-Type: text/xml; charset="utf-8" 35 | 36 | 37 | 38 | 39 | {ActionBodyHere} 40 | 41 | 42 | ``` 43 | 44 | --- 45 | 46 | ## Available actions 47 | 48 | ### Next 49 | 50 | Action body: 51 | 52 | ```xml 53 | 54 | ui4 55 | 56 | ``` 57 | 58 | Inputs: 59 | 60 | | parameter | type | description | 61 | |:----------|:-----|:------------| 62 | | **InstanceID** | `ui4` | | 63 | 64 | ### Pause 65 | 66 | Action body: 67 | 68 | ```xml 69 | 70 | ui4 71 | 72 | ``` 73 | 74 | Inputs: 75 | 76 | | parameter | type | description | 77 | |:----------|:-----|:------------| 78 | | **InstanceID** | `ui4` | | 79 | 80 | ### Play 81 | 82 | Action body: 83 | 84 | ```xml 85 | 86 | ui4 87 | string 88 | 89 | ``` 90 | 91 | Inputs: 92 | 93 | | parameter | type | description | 94 | |:----------|:-----|:------------| 95 | | **InstanceID** | `ui4` | | 96 | | **Speed** | `string` | | 97 | 98 | ### Previous 99 | 100 | Action body: 101 | 102 | ```xml 103 | 104 | ui4 105 | 106 | ``` 107 | 108 | Inputs: 109 | 110 | | parameter | type | description | 111 | |:----------|:-----|:------------| 112 | | **InstanceID** | `ui4` | | 113 | 114 | ### SetVolume 115 | 116 | Action body: 117 | 118 | ```xml 119 | 120 | ui4 121 | ui2 122 | 123 | ``` 124 | 125 | Inputs: 126 | 127 | | parameter | type | description | 128 | |:----------|:-----|:------------| 129 | | **InstanceID** | `ui4` | | 130 | | **DesiredVolume** | `ui2` | | 131 | 132 | ### StartTransmission 133 | 134 | Action body: 135 | 136 | ```xml 137 | 138 | ui4 139 | string 140 | 141 | ``` 142 | 143 | Inputs: 144 | 145 | | parameter | type | description | 146 | |:----------|:-----|:------------| 147 | | **InstanceID** | `ui4` | | 148 | | **CoordinatorID** | `string` | | 149 | 150 | Outputs: 151 | 152 | | parameter | type | description | 153 | |:----------|:-----|:------------| 154 | | **CurrentTransportSettings** | `string` | | 155 | 156 | ### Stop 157 | 158 | Action body: 159 | 160 | ```xml 161 | 162 | ui4 163 | 164 | ``` 165 | 166 | Inputs: 167 | 168 | | parameter | type | description | 169 | |:----------|:-----|:------------| 170 | | **InstanceID** | `ui4` | | 171 | 172 | ### StopTransmission 173 | 174 | Action body: 175 | 176 | ```xml 177 | 178 | ui4 179 | string 180 | 181 | ``` 182 | 183 | Inputs: 184 | 185 | | parameter | type | description | 186 | |:----------|:-----|:------------| 187 | | **InstanceID** | `ui4` | | 188 | | **CoordinatorID** | `string` | | 189 | 190 | ## Events 191 | 192 | The VirtualLineInService has variables that might be emitted if you subscribe to events. 193 | 194 | ### Subscribe to events 195 | 196 | ```text 197 | SUBSCRIBE /MediaRenderer/VirtualLineIn/Event 198 | Host: 192.168.x.x:1400 199 | callback: 200 | NT: upnp:event 201 | Timeout: Second-3600 202 | ``` 203 | 204 | ### Event variables 205 | 206 | | Variable | Sends events* | type | possible values | 207 | |:---------|:-------------|:-----|:----------------| 208 | | AVTransportURIMetaData | | `string` | Embedded XML | 209 | | CurrentTrackMetaData | ✔ | `string` | Embedded XML | 210 | | CurrentTransportActions | | `string` | | 211 | | EnqueuedTransportURIMetaData | | `string` | Embedded XML | 212 | | LastChange | ✔ | `string` | | 213 | 214 | If the variable has a `✔` in the Sends events column, the service discovery specifies this variable emits events. Other properties might be send as a part of `LastChange` 215 | 216 | --- 217 | 218 | This file is automatically generated with [@svrooij/sonos-docs](https://github.com/svrooij/sonos-api-docs/tree/main/generator/sonos-docs), do not edit manually. 219 | 220 | | Device | Software generation | Software version | Discovery date | 221 | |:-------|:--------------------|:-----------------|:---------------| 222 | | `Sonos Play:1 (S1)` | S2 | 77.4-49290 | 2024-02-13T15:56:06.184Z | 223 | | `Sonos One (S13)` | S2 | 63.2-90210 | 2021-07-21T23:31:19.273Z | 224 | | `Sonos Beam (S14)` | S2 | 64.3-19080 | 2021-08-18T06:04:08.308Z | 225 | | `Sonos One (S18)` | S2 | 77.4-49290 | 2024-02-13T15:55:36.464Z | 226 | | `SYMFONISK Bookshelf (S21)` | S2 | 66.4-23300 | 2022-01-01T11:41:01.361Z | 227 | | `Sonos Roam (S27)` | S2 | 63.2-90210 | 2021-07-21T23:31:31.207Z | 228 | | `Sonos Play:3 (S3)` | S2 | 64.3-19080 | 2021-08-18T06:09:36.692Z | 229 | | `SYMFONISK Bookshelf (S33)` | S2 | 77.4-49290 | 2024-02-13T15:55:24.423Z | 230 | | `Sonos One SL (S38)` | S2 | 72.2-40060 | 2023-05-22T16:39:25.503Z | 231 | | `Sonos Play:5 (S6)` | S2 | 64.3-19080 | 2021-08-18T06:06:35.970Z | 232 | | `Sonos Playbar (S9)` | S2 | 77.4-49290 | 2024-02-13T15:55:46.307Z | 233 | | `Sonos Sub (Sub)` | S2 | 63.2-90210 | 2021-07-21T23:31:40.304Z | 234 | -------------------------------------------------------------------------------- /docs/services/zone-group-topology.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: ZoneGroupTopology 4 | parent: Sonos Services 5 | --- 6 | # ZoneGroupTopology service 7 | {: .no_toc } 8 | 9 | Zone config stuff, eg getting all the configured sonos zones 10 | 11 | The ZoneGroupTopology service is available on these models: `Sonos Play:1 (S1) S2` / `Sonos One (S13) S2` / `Sonos Beam (S14) S2` / `Sonos One (S18) S2` / `SYMFONISK Bookshelf (S21) S2` / `Sonos Roam (S27) S2` / `Sonos Play:3 (S3) S2` / `SYMFONISK Bookshelf (S33) S2` / `Sonos One SL (S38) S2` / `Sonos Play:5 (S6) S2` / `Sonos Playbar (S9) S2` / `Sonos Sub (Sub) S2`. 12 | 13 | 1. TOC 14 | {:toc} 15 | 16 | --- 17 | 18 | ## Service data 19 | {: .no_toc } 20 | 21 | | name | value | 22 | |:-----|:------| 23 | | **Control URL** | `http://192.168.x.x:1400/ZoneGroupTopology/Control` | 24 | | **Event subscription URL** | `http://192.168.x.x:1400/ZoneGroupTopology/Event` | 25 | | **Discovery URL** | `http://192.168.x.x:1400/xml/ZoneGroupTopology1.xml` | 26 | | **Service ID** | `urn:upnp-org:serviceId:ZoneGroupTopology` | 27 | | **Service type** | `urn:schemas-upnp-org:service:ZoneGroupTopology:1` | 28 | 29 | ### Sample request 30 | {: .no_toc } 31 | 32 | ```text 33 | POST /ZoneGroupTopology/Control 34 | Host: 192.168.x.x:1400 35 | soapaction: "urn:schemas-upnp-org:service:ZoneGroupTopology:1#{ActionName}" 36 | Content-Type: text/xml; charset="utf-8" 37 | 38 | 39 | 40 | 41 | {ActionBodyHere} 42 | 43 | 44 | ``` 45 | 46 | --- 47 | 48 | ## Available actions 49 | 50 | ### BeginSoftwareUpdate 51 | 52 | Action body: 53 | 54 | ```xml 55 | 56 | string 57 | ui4 58 | string 59 | 60 | ``` 61 | 62 | Inputs: 63 | 64 | | parameter | type | description | 65 | |:----------|:-----|:------------| 66 | | **UpdateURL** | `string` | | 67 | | **Flags** | `ui4` | | 68 | | **ExtraOptions** | `string` | | 69 | 70 | ### CheckForUpdate 71 | 72 | Action body: 73 | 74 | ```xml 75 | 76 | string 77 | boolean 78 | string 79 | 80 | ``` 81 | 82 | Inputs: 83 | 84 | | parameter | type | description | 85 | |:----------|:-----|:------------| 86 | | **UpdateType** | `string` | Allowed values: `All` / `Software` | 87 | | **CachedOnly** | `boolean` | Allowed values: `1` (= true) / `0` (= false) | 88 | | **Version** | `string` | | 89 | 90 | Outputs: 91 | 92 | | parameter | type | description | 93 | |:----------|:-----|:------------| 94 | | **UpdateItem** | `string` | | 95 | 96 | ### GetZoneGroupAttributes 97 | 98 | Get information about the current Zone 99 | 100 | Action body: 101 | 102 | ```xml 103 | 104 | 105 | ``` 106 | 107 | No input arguments 108 | 109 | Outputs: 110 | 111 | | parameter | type | description | 112 | |:----------|:-----|:------------| 113 | | **CurrentZoneGroupName** | `string` | | 114 | | **CurrentZoneGroupID** | `string` | | 115 | | **CurrentZonePlayerUUIDsInGroup** | `string` | | 116 | | **CurrentMuseHouseholdId** | `string` | | 117 | 118 | ### GetZoneGroupState 119 | 120 | Get all the Sonos groups, (as XML) 121 | 122 | Action body: 123 | 124 | ```xml 125 | 126 | 127 | ``` 128 | 129 | No input arguments 130 | 131 | Outputs: 132 | 133 | | parameter | type | description | 134 | |:----------|:-----|:------------| 135 | | **ZoneGroupState** | `string` | xml string, see remarks | 136 | 137 | **Remarks** Some libraries also support GetParsedZoneGroupState that parses the xml for you. 138 | 139 | ### RegisterMobileDevice 140 | 141 | Action body: 142 | 143 | ```xml 144 | 145 | string 146 | string 147 | string 148 | 149 | ``` 150 | 151 | Inputs: 152 | 153 | | parameter | type | description | 154 | |:----------|:-----|:------------| 155 | | **MobileDeviceName** | `string` | | 156 | | **MobileDeviceUDN** | `string` | | 157 | | **MobileIPAndPort** | `string` | | 158 | 159 | ### ReportAlarmStartedRunning 160 | 161 | Action body: 162 | 163 | ```xml 164 | 165 | 166 | ``` 167 | 168 | No input arguments 169 | 170 | ### ReportUnresponsiveDevice 171 | 172 | Action body: 173 | 174 | ```xml 175 | 176 | string 177 | string 178 | 179 | ``` 180 | 181 | Inputs: 182 | 183 | | parameter | type | description | 184 | |:----------|:-----|:------------| 185 | | **DeviceUUID** | `string` | | 186 | | **DesiredAction** | `string` | Allowed values: `Remove` / `TopologyMonitorProbe` / `VerifyThenRemoveSystemwide` | 187 | 188 | ### SubmitDiagnostics 189 | 190 | Action body: 191 | 192 | ```xml 193 | 194 | boolean 195 | string 196 | 197 | ``` 198 | 199 | Inputs: 200 | 201 | | parameter | type | description | 202 | |:----------|:-----|:------------| 203 | | **IncludeControllers** | `boolean` | Allowed values: `1` (= true) / `0` (= false) | 204 | | **Type** | `string` | | 205 | 206 | Outputs: 207 | 208 | | parameter | type | description | 209 | |:----------|:-----|:------------| 210 | | **DiagnosticID** | `ui4` | | 211 | 212 | ## Events 213 | 214 | The ZoneGroupTopologyService has variables that might be emitted if you subscribe to events. 215 | 216 | ### Subscribe to events 217 | 218 | ```text 219 | SUBSCRIBE /ZoneGroupTopology/Event 220 | Host: 192.168.x.x:1400 221 | callback: 222 | NT: upnp:event 223 | Timeout: Second-3600 224 | ``` 225 | 226 | ### Event variables 227 | 228 | | Variable | Sends events* | type | possible values | 229 | |:---------|:-------------|:-----|:----------------| 230 | | AlarmRunSequence | ✔ | `string` | | 231 | | AreasUpdateID | ✔ | `string` | | 232 | | AvailableSoftwareUpdate | ✔ | `string` | | 233 | | DiagnosticID | | `ui4` | | 234 | | MuseHouseholdId | ✔ | `string` | | 235 | | NetsettingsUpdateID | ✔ | `string` | | 236 | | SourceAreasUpdateID | ✔ | `string` | | 237 | | ThirdPartyMediaServersX | ✔ | `string` | | 238 | | ZoneGroupID | ✔ | `string` | | 239 | | ZoneGroupName | ✔ | `string` | | 240 | | ZoneGroupState | ✔ | `string` | | 241 | | ZonePlayerUUIDsInGroup | ✔ | `string` | | 242 | 243 | If the variable has a `✔` in the Sends events column, the service discovery specifies this variable emits events. Other properties might be send as a part of `LastChange` 244 | 245 | --- 246 | 247 | This file is automatically generated with [@svrooij/sonos-docs](https://github.com/svrooij/sonos-api-docs/tree/main/generator/sonos-docs), do not edit manually. 248 | 249 | | Device | Software generation | Software version | Discovery date | 250 | |:-------|:--------------------|:-----------------|:---------------| 251 | | `Sonos Play:1 (S1)` | S2 | 77.4-49290 | 2024-02-13T15:56:06.184Z | 252 | | `Sonos One (S13)` | S2 | 63.2-90210 | 2021-07-21T23:31:19.273Z | 253 | | `Sonos Beam (S14)` | S2 | 64.3-19080 | 2021-08-18T06:04:08.308Z | 254 | | `Sonos One (S18)` | S2 | 77.4-49290 | 2024-02-13T15:55:36.464Z | 255 | | `SYMFONISK Bookshelf (S21)` | S2 | 66.4-23300 | 2022-01-01T11:41:01.361Z | 256 | | `Sonos Roam (S27)` | S2 | 63.2-90210 | 2021-07-21T23:31:31.207Z | 257 | | `Sonos Play:3 (S3)` | S2 | 64.3-19080 | 2021-08-18T06:09:36.692Z | 258 | | `SYMFONISK Bookshelf (S33)` | S2 | 77.4-49290 | 2024-02-13T15:55:24.423Z | 259 | | `Sonos One SL (S38)` | S2 | 72.2-40060 | 2023-05-22T16:39:25.503Z | 260 | | `Sonos Play:5 (S6)` | S2 | 64.3-19080 | 2021-08-18T06:06:35.970Z | 261 | | `Sonos Playbar (S9)` | S2 | 77.4-49290 | 2024-02-13T15:55:46.307Z | 262 | | `Sonos Sub (Sub)` | S2 | 63.2-90210 | 2021-07-21T23:31:40.304Z | 263 | -------------------------------------------------------------------------------- /docs/sonos-communication.md: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Sonos communication 4 | nav_order: 4 5 | has_toc: false 6 | --- 7 | 8 | # Sonos communication 9 | 10 | To communicate with your Sonos speakers on your local network use: 11 | 12 | - SOAP to call the SONOS services at port 1400 and subscribe to events [see services](#sonos-services) 13 | - HTTP requests at port 1400 to scrape the UPnP service information or get a simple device status information [see http requests](#http-endpoints) 14 | - UDP Datagram and Simple Service Discovery Protocol (SSDP) at port 1900 to discover SONOS player [see auto discovery](#auto-discovery) 15 | - New secure RestURL at `https://{ip}:1443/api` (not covered in this documentation) 16 | 17 | ## Sonos Services 18 | 19 | Each sonos speaker has [several soap services]({{'services/' | relative_url }}) defined. All which have several actions that can be executed. The documentation of these services is scraped from the discovery file that every sonos speaker has available at `http://{ip}:1400/xml/device_description.xml`. 20 | 21 | ## Sonos SOAP remarks 22 | 23 | - Sonos communicates booleans as `1` for true and `0` for false. This is something to keep in mind if you see **boolean** somewhere. 24 | - Some actions (like [ListAlarms]({{'services/alarm-clock.html#listalarms' | relative_url }})) return encoded xml as string. Before you can read these, you'll have to decode them and then parse them as XML. Libraries like [node-sonos-ts](https://sonos-ts.svrooij.io/sonos-device/services/alarm-clock-service.html#listalarms) provide a way that already parses the the output so you don't have to. 25 | 26 | ## SOAP call 27 | 28 | A SOAP call is just a http request, with some special headers and some xml formatted body. Each request is a `POST` request to some endpoint. 29 | 30 | In this sample we described the [SetMute]({{ '/services/rendering-control.html#setmute' | relative_url }}) command. 31 | 32 | | What | Sample | 33 | | ---- | ------ | 34 | | IP of speaker | `192.168.0.31` | 35 | | [Control endpoint]({{'/services/rendering-control.html#service-data' | relative_url }}) | `/MediaRenderer/RenderingControl/Control` | 36 | | Service type | `urn:schemas-upnp-org:service:RenderingControl:1` | 37 | 38 | You can find this information on the page describing one of [many sonos services]({{'/services/' | relative_url }}). 39 | 40 | ### SOAP call Rendering control - SetMute 41 | 42 | You do a HTTP `POST` request to the [control endpoint]({{'/services/rendering-control.html#service-data' | relative_url }}) of the `RenderingControlService`. This service has a service type of `urn:schemas-upnp-org:service:RenderingControl:1` which is needed in the `soapaction` http header and in the soap body. Where you also specify the name of the action `SetMute` in this case. 43 | 44 | URL `http://192.168.0.31:1400/MediaRenderer/RenderingControl/Control` 45 | 46 | Required HTTP headers: 47 | 48 | ```txt 49 | soapaction: "urn:schemas-upnp-org:service:RenderingControl:1#SetMute" 50 | Content-Type: text/xml; charset="utf-8" 51 | ``` 52 | 53 | The body of the request has to be specified as XML. We also added the correct action body for the `SetMute` action. As you see below, booleans are converted to `1` for true and `0` for false. This is just how Sonos works. 54 | 55 | ```xml 56 | 57 | 58 | 59 | 60 | 0 61 | Master 62 | 1 63 | 64 | 65 | 66 | ``` 67 | 68 | ### SOAP response 69 | 70 | All calls to sonos will return a xml object. Either with a success message of with a failure. 71 | 72 | Success message (without output parameters) to above command: 73 | 74 | ```xml 75 | 76 | 77 | 78 | 79 | 80 | ``` 81 | 82 | Generic error (when deleting an alarm that doesn't exists) body (HTTP status code 500): 83 | 84 | ```xml 85 | 86 | 87 | 88 | s:Client 89 | UPnPError 90 | 91 | 92 | 800 93 | 94 | 95 | 96 | 97 | 98 | ``` 99 | 100 | Sometimes you're getting a more specific error code, we tried describing all of them in the [documentation.json](https://github.com/svrooij/sonos-api-docs/blob/main/docs/documentation.json) 101 | 102 | ## HTTP Endpoints 103 | 104 | Apart from the soap services, sonos also has some http endpoints available where you can get extra information: 105 | 106 | | URL | Description | 107 | | --- | ----------- | 108 | | `http://{ip}:1400/status/info` | playerId, serialNumber, groupId, householdId, capabilities, versions and more (JSON format) | 109 | | `http://{ip}:1400/status` | several additional connection information | 110 | | `http://{ip}:1400/status/batterystatus` | battery status for devices with battery (JSON format) | 111 | | `http://{ip}:1400/region.htm` | to select a Wifi region out of USA/Canada, EU, CHINA, JAPAN, ISRAEL, RUSSIA, SOUTH KOREA | 112 | | `http://{ip}:1400/support/review` | a list of all players with playerID and links to more information | 113 | | `http://{ip}:1400/xml/device_description.xml` | Sonos services description, used by the [generator](https://github.com/svrooij/sonos-api-docs/tree/main/generator/sonos-docs) | 114 | 115 | ## Auto discovery 116 | 117 | Each sonos speaker can be discovered by the [SSDP](https://en.wikipedia.org/wiki/Simple_Service_Discovery_Protocol) or **Simple Service Discovery Protocol**. 118 | In short each speaker listens for a `ssdp:discovery` command. 119 | 120 | Which is actually just a simple UDP packet send to port `1900` on multicast address `239.255.255.250` and `255.255.255.255` with the following body: 121 | 122 | ```text 123 | M-SEARCH * HTTP/1.1 124 | HOST: 239.255.255.250:1900 125 | MAN: ssdp:discover 126 | MX: 1 127 | ST: urn:schemas-upnp-org:device:ZonePlayer:1 128 | ``` 129 | 130 | By sending a this UDP multicast packet, you will get a response from all speakers available on your network. See [sonos-device-discovery.ts](https://github.com/svrooij/node-sonos-ts/blob/master/src/sonos-device-discovery.ts) for a sample on how to do that in TypeScript/Node. That should give you some pointers on how to do that in another language. 131 | -------------------------------------------------------------------------------- /generator/sonos-docs/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | charset = utf-8 7 | trim_trailing_whitespace = true 8 | insert_final_newline = true 9 | 10 | [*.md] 11 | trim_trailing_whitespace = false 12 | -------------------------------------------------------------------------------- /generator/sonos-docs/.eslintignore: -------------------------------------------------------------------------------- 1 | /lib 2 | -------------------------------------------------------------------------------- /generator/sonos-docs/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "oclif", 4 | "oclif-typescript" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /generator/sonos-docs/.gitignore: -------------------------------------------------------------------------------- 1 | *-debug.log 2 | *-error.log 3 | /.nyc_output 4 | /dist 5 | /lib 6 | /tmp 7 | /yarn.lock 8 | node_modules 9 | /data/intermediate.json 10 | /.cache/combined.json -------------------------------------------------------------------------------- /generator/sonos-docs/README.md: -------------------------------------------------------------------------------- 1 | # Sonos client generator `@svrooij/sonos-docs` 2 | 3 | 4 | CLI tool to generate documentation for the undocumented sonos api 5 | 6 | [![oclif](https://img.shields.io/badge/cli-oclif-brightgreen.svg)](https://oclif.io) 7 | [![Version](https://img.shields.io/npm/v/@svrooij/sonos-docs.svg)](https://www.npmjs.com/package/@svrooij/sonos-docs) 8 | [![Downloads/week](https://img.shields.io/npm/dw/@svrooij/sonos-docs.svg)](https://www.npmjs.com/package/@svrooij/sonos-docs) 9 | [![License](https://img.shields.io/npm/l/@svrooij/sonos-docs.svg)](https://github.com/svrooij/sonos-api-docs/blob/master/generator/sonos-docs/package.json) 10 | 11 | 12 | * [Sonos client generator `@svrooij/sonos-docs`](#sonos-client-generator-svrooijsonos-docs) 13 | * [🏗 Usage](#-usage) 14 | * [🔨 Commands](#-commands) 15 | 16 | # 🏗 Usage 17 | 18 | ```sh-session 19 | $ npm install -g @svrooij/sonos-docs 20 | $ sonos-docs COMMAND 21 | running command... 22 | $ sonos-docs (-v|--version|version) 23 | @svrooij/sonos-docs/0.0.0 win32-x64 node-v16.8.0 24 | $ sonos-docs --help [COMMAND] 25 | USAGE 26 | $ sonos-docs COMMAND 27 | ... 28 | ``` 29 | 30 | 31 | # 🔨 Commands 32 | 33 | 34 | * [`sonos-docs combine`](#sonos-docs-combine) 35 | * [`sonos-docs generate TEMPLATE OUTPUT`](#sonos-docs-generate-template-output) 36 | * [`sonos-docs help [COMMAND]`](#sonos-docs-help-command) 37 | * [`sonos-docs musicservices IP`](#sonos-docs-musicservices-ip) 38 | * [`sonos-docs services IP`](#sonos-docs-services-ip) 39 | 40 | ## `sonos-docs combine` 41 | 42 | Generate combined.json file by combining the documentation file and the discovered services. 43 | 44 | ``` 45 | USAGE 46 | $ sonos-docs combine 47 | 48 | OPTIONS 49 | -h, --help show CLI help 50 | 51 | --discoveryUrl=discoveryUrl [default: https://github.com/svrooij/sonos-api-docs/raw/main/generator/sonos-docs/data/] 52 | Base url to load the discovery files from 53 | 54 | --docsFile=docsFile File location of documenation, instead of url. 55 | 56 | --docsUrl=docsUrl [default: https://raw.githubusercontent.com/svrooij/sonos-api-docs/main/docs/documentation.json] The url of the 57 | documentation, this is just to override the documentation url 58 | 59 | --folder=folder Load discovered services from this folder. Loaded from repository if empty 60 | 61 | --models=models [default: S1-1,S5-1,S9-1,S3-2,S6-2,S13-2,S14-2,S27-2,Sub-2] Models to use, separated by 62 | comma. as {model}-{softwareGen} 63 | 64 | --out=out [default: .cache/combined.json] Output filename 65 | ``` 66 | 67 | _See code: [src\commands\combine.ts](https://github.com/svrooij/sonos-api-docs/blob/v0.0.0/src\commands\combine.ts)_ 68 | 69 | ## `sonos-docs generate TEMPLATE OUTPUT` 70 | 71 | Generate files based on the intermediate file and a template. 72 | 73 | ``` 74 | USAGE 75 | $ sonos-docs generate TEMPLATE OUTPUT 76 | 77 | ARGUMENTS 78 | TEMPLATE The template to use, either a folder relative to the current or a folder an included in the generator 79 | OUTPUT The root directory where the files should be generated 80 | 81 | OPTIONS 82 | -h, --help show CLI help 83 | -i, --intermediate=intermediate [default: data/intermediate.json] intermediate file to use. generate with 'combine' 84 | ``` 85 | 86 | _See code: [src\commands\generate.ts](https://github.com/svrooij/sonos-api-docs/blob/v0.0.0/src\commands\generate.ts)_ 87 | 88 | ## `sonos-docs help [COMMAND]` 89 | 90 | display help for sonos-docs 91 | 92 | ``` 93 | USAGE 94 | $ sonos-docs help [COMMAND] 95 | 96 | ARGUMENTS 97 | COMMAND command to show help for 98 | 99 | OPTIONS 100 | --all see all commands in CLI 101 | ``` 102 | 103 | _See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v3.2.0/src\commands\help.ts)_ 104 | 105 | ## `sonos-docs musicservices IP` 106 | 107 | describe the command here 108 | 109 | ``` 110 | USAGE 111 | $ sonos-docs musicservices IP 112 | 113 | ARGUMENTS 114 | IP The IP of the sonos speaker to load the music services 115 | 116 | OPTIONS 117 | -x, --extended show extra columns 118 | --columns=columns only show provided columns (comma-separated) 119 | --csv output is csv format [alias: --output=csv] 120 | --docs Show a markdown table 121 | --filter=filter filter property by partial string matching, ex: name=foo 122 | --no-header hide table header from output 123 | --no-truncate do not truncate output to fit screen 124 | --output=csv|json|yaml output in a more machine friendly format 125 | --saveJson=saveJson If set, save music services as json 126 | --show Show the music services 127 | --sort=sort property to sort by (prepend '-' for descending) 128 | ``` 129 | 130 | _See code: [src\commands\musicservices.ts](https://github.com/svrooij/sonos-api-docs/blob/v0.0.0/src\commands\musicservices.ts)_ 131 | 132 | ## `sonos-docs services IP` 133 | 134 | Fetch device discovery document and generate json file 135 | 136 | ``` 137 | USAGE 138 | $ sonos-docs services IP 139 | 140 | ARGUMENTS 141 | IP The IP of the sonos to do service discovery for. 142 | 143 | OPTIONS 144 | -d, --dryRun 145 | -f, --folder=folder [default: data] Folder to write discovered services. 146 | -h, --help show CLI help 147 | ``` 148 | 149 | _See code: [src\commands\services.ts](https://github.com/svrooij/sonos-api-docs/blob/v0.0.0/src\commands\services.ts)_ 150 | 151 | * [`sonos-docs combine`](#sonos-docs-combine) 152 | * [`sonos-docs generate TEMPLATE OUTPUT`](#sonos-docs-generate-template-output) 153 | * [`sonos-docs help [COMMAND]`](#sonos-docs-help-command) 154 | * [`sonos-docs musicservices IP`](#sonos-docs-musicservices-ip) 155 | * [`sonos-docs services IP`](#sonos-docs-services-ip) 156 | 157 | ## `sonos-docs combine` 158 | 159 | Generate intermediate json file by combining the documentation file and the discovered services. 160 | 161 | ``` 162 | USAGE 163 | $ sonos-docs combine 164 | 165 | OPTIONS 166 | -h, --help show CLI help 167 | 168 | --discoveryUrl=discoveryUrl [default: https://github.com/svrooij/sonos-api-docs/raw/main/generator/sonos-docs/data/] 169 | Base url to load the discovery files from 170 | 171 | --docsFile=docsFile File location of documenation, instead of url. 172 | 173 | --docsUrl=docsUrl [default: https://svrooij.io/sonos-api-docs/documentation.json] The url of the 174 | documentation, this is just to override the documentation url 175 | 176 | --folder=folder Load discovered services from this folder. Loaded from repository if empty 177 | 178 | --models=models [default: S1-1,S5-1,S9-1,S3-2,S6-2,S13-2,S14-2,S27-2,Sub-2] Models to use, separated by 179 | comma. as {model}-{softwareGen} 180 | 181 | --out=out [default: data/intermediate.json] Output filename 182 | ``` 183 | 184 | _See code: [src/commands/combine.ts](https://github.com/svrooij/sonos-api-docs/blob/v0.0.0/src/commands/combine.ts)_ 185 | 186 | ## `sonos-docs generate TEMPLATE OUTPUT` 187 | 188 | Generate files based on the intermediate file and a template. 189 | 190 | ``` 191 | USAGE 192 | $ sonos-docs generate TEMPLATE OUTPUT 193 | 194 | ARGUMENTS 195 | TEMPLATE The template to use, either a folder relative to the current or a folder an included in the generator 196 | OUTPUT The root directory where the files should be generated 197 | 198 | OPTIONS 199 | -h, --help show CLI help 200 | -i, --combined=combined [default: .cache/combined.json] combined documentation file to use. generate with 'combine' 201 | ``` 202 | 203 | _See code: [src/commands/generate.ts](https://github.com/svrooij/sonos-api-docs/blob/v1.0.0/src/commands/generate.ts)_ 204 | 205 | ## `sonos-docs help [COMMAND]` 206 | 207 | display help for sonos-docs 208 | 209 | ``` 210 | USAGE 211 | $ sonos-docs help [COMMAND] 212 | 213 | ARGUMENTS 214 | COMMAND command to show help for 215 | 216 | OPTIONS 217 | --all see all commands in CLI 218 | ``` 219 | 220 | _See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v3.2.3/src/commands/help.ts)_ 221 | 222 | ## `sonos-docs musicservices IP` 223 | 224 | describe the command here 225 | 226 | ``` 227 | USAGE 228 | $ sonos-docs musicservices IP 229 | 230 | ARGUMENTS 231 | IP The IP of the sonos speaker to load the music services 232 | 233 | OPTIONS 234 | -x, --extended show extra columns 235 | --columns=columns only show provided columns (comma-separated) 236 | --csv output is csv format [alias: --output=csv] 237 | --docs Show a markdown table 238 | --filter=filter filter property by partial string matching, ex: name=foo 239 | --no-header hide table header from output 240 | --no-truncate do not truncate output to fit screen 241 | --output=csv|json|yaml output in a more machine friendly format 242 | --saveJson=saveJson If set, save music services as json 243 | --show Show the music services 244 | --sort=sort property to sort by (prepend '-' for descending) 245 | ``` 246 | 247 | _See code: [src/commands/musicservices.ts](https://github.com/svrooij/sonos-api-docs/blob/v1.0.0/src/commands/musicservices.ts)_ 248 | 249 | ## `sonos-docs services IP` 250 | 251 | Fetch device discovery document and generate json file 252 | 253 | ``` 254 | USAGE 255 | $ sonos-docs services IP 256 | 257 | ARGUMENTS 258 | IP The IP of the sonos to do service discovery for. 259 | 260 | OPTIONS 261 | -d, --dryRun 262 | -f, --folder=folder [default: data] Folder to write discovered services. 263 | -h, --help show CLI help 264 | ``` 265 | 266 | _See code: [src/commands/services.ts](https://github.com/svrooij/sonos-api-docs/blob/v1.0.0/src/commands/services.ts)_ 267 | 268 | -------------------------------------------------------------------------------- /generator/sonos-docs/bin/run: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | require('@oclif/command').run() 4 | .then(require('@oclif/command/flush')) 5 | .catch(require('@oclif/errors/handle')) 6 | -------------------------------------------------------------------------------- /generator/sonos-docs/bin/run.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | node "%~dp0\run" %* 4 | -------------------------------------------------------------------------------- /generator/sonos-docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@svrooij/sonos-docs", 3 | "description": "CLI tool to generate documentation for the undocumented sonos api", 4 | "version": "0.0.0-development", 5 | "author": "Stephan van Rooij (https://svrooij.io)", 6 | "bin": { 7 | "sonos-docs": "./bin/run" 8 | }, 9 | "bugs": "https://github.com/svrooij/sonos-api-docs/issues", 10 | "dependencies": { 11 | "@oclif/command": "^1.8.0", 12 | "@oclif/config": "^1.17.0", 13 | "@oclif/plugin-help": "^3.2.3", 14 | "@svrooij/sonos": "2.4.1", 15 | "cli-ux": "^5.6.3", 16 | "fast-xml-parser": "^3.17.4", 17 | "handlebars": "^4.7.7", 18 | "node-fetch": "^2.6.2", 19 | "tslib": "^1.14.1" 20 | }, 21 | "devDependencies": { 22 | "@oclif/dev-cli": "^1.26.0", 23 | "@types/debug": "^4.1.7", 24 | "@types/node": "^16.9.6", 25 | "@types/node-fetch": "^2.5.7", 26 | "eslint": "^5.16.0", 27 | "eslint-config-oclif": "^3.1.0", 28 | "eslint-config-oclif-typescript": "^0.1.0", 29 | "globby": "^10.0.2", 30 | "rimraf": "^3.0.2", 31 | "semantic-release": "^18.0.0", 32 | "ts-node": "^10.2.1", 33 | "typescript": "^3.9.7" 34 | }, 35 | "engines": { 36 | "node": ">=8.0.0" 37 | }, 38 | "files": [ 39 | "/bin", 40 | "/lib", 41 | "/templates", 42 | "/npm-shrinkwrap.json", 43 | "/oclif.manifest.json" 44 | ], 45 | "homepage": "https://github.com/svrooij/sonos-api-docs/generator/sonos-docs", 46 | "keywords": [ 47 | "oclif" 48 | ], 49 | "license": "MIT", 50 | "main": "lib/index.js", 51 | "oclif": { 52 | "commands": "./lib/commands", 53 | "bin": "sonos-docs", 54 | "plugins": [ 55 | "@oclif/plugin-help" 56 | ] 57 | }, 58 | "repository": "https://github.com/svrooij/sonos-api-docs", 59 | "scripts": { 60 | "postpack": "rimraf oclif.manifest.json", 61 | "posttest": "eslint . --ext .ts --config .eslintrc", 62 | "prepack": "rimraf lib && tsc -b && oclif-dev manifest && oclif-dev readme", 63 | "test": "echo NO TESTS", 64 | "version": "oclif-dev readme && git add README.md", 65 | "intermediate": "./bin/run combine --docsFile=../../docs/documentation.json --folder=data", 66 | "intermediate-win": ".\\bin\\run combine --docsFile=../../docs/documentation.json --folder=data", 67 | "combine-win": ".\\bin\\run combine --docsFile=../../docs/documentation.json --folder=data", 68 | "docs": "./bin/run generate docs ../../docs", 69 | "docs-win": ".\\bin\\run generate docs ../../docs" 70 | }, 71 | "types": "lib/index.d.ts", 72 | "release": { 73 | "branches": [ 74 | "+([0-9])?(.{+([0-9]),x}).x", 75 | "main", 76 | "next", 77 | { 78 | "name": "beta", 79 | "prerelease": true 80 | }, 81 | { 82 | "name": "ci-build", 83 | "prerelease": true 84 | } 85 | ] 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /generator/sonos-docs/src/commands/generate.ts: -------------------------------------------------------------------------------- 1 | import {Command, flags} from '@oclif/command' 2 | import {cli} from 'cli-ux' 3 | 4 | import * as path from 'path' 5 | import * as fs from 'fs' 6 | import * as handlebars from 'handlebars' 7 | 8 | import SonosDevice from '../models/sonos-device' 9 | import {Template} from '../models/template' 10 | import {SonosService} from '../models/sonos-service' 11 | import StringHelper from '../helpers/string-helper' 12 | import SonosStateVariable from '../models/sonos-state-variable' 13 | import {SonosServiceActionArgument} from '../models/sonos-service-action' 14 | import ExtendedSonosDescription from '../models/extended-sonos-description' 15 | 16 | export default class Generate extends Command { 17 | static description = 'Generate files based on the intermediate file and a template.' 18 | 19 | static flags = { 20 | help: flags.help({char: 'h'}), 21 | combined: flags.string({char: 'i', description: 'combined documentation file to use. generate with \'combine\'', default: '.cache/combined.json'}), 22 | } 23 | 24 | static args = [ 25 | { 26 | name: 'template', 27 | required: true, 28 | description: 'The template to use, either a folder relative to the current or a folder an included in the generator', 29 | }, 30 | { 31 | name: 'output', 32 | required: true, 33 | description: 'The root directory where the files should be generated', 34 | }, 35 | ] 36 | 37 | async run() { 38 | const {args, flags} = this.parse(Generate) 39 | this.log('Starting generator with template \'%s\'', args.template) 40 | 41 | const outputTemplate = this.getTemplate(args.template) 42 | const deviceDescription = this.getDeviceDescription(flags.combined, outputTemplate?.dataTypes ?? {}, outputTemplate?.serviceData) 43 | 44 | const outputBase = this.getFullPathAndCreateDirectory(args.output, true) 45 | 46 | if (outputTemplate === undefined || deviceDescription === undefined) { 47 | // This should never be reached, since it will already throw an error earlier. 48 | return 49 | } 50 | 51 | // Register helpers 52 | // {{lower var}} for lowercase 53 | handlebars.registerHelper('lower', (input: any) => { 54 | if (typeof input === 'string') { 55 | return input.toLowerCase() 56 | } 57 | return input 58 | }) 59 | // {{kebab var}} for kebab case 60 | handlebars.registerHelper('kebab', (input: any) => { 61 | if (typeof input === 'string') { 62 | return StringHelper.camelToKebab(input) 63 | } 64 | return input 65 | }) 66 | // unless val 67 | handlebars.registerHelper('are_equal', function (input?: string, compareTo?: string) { 68 | if (arguments.length !== 3) { 69 | throw new handlebars.Exception('same requires exactly two argument') 70 | } 71 | // console.log('Compare items', arguments); 72 | return input === compareTo 73 | }) 74 | handlebars.registerHelper('or', function (condition1: boolean, condition2: boolean) { 75 | if (arguments.length !== 3) { 76 | throw new handlebars.Exception('or requires exactly two argument') 77 | } 78 | return condition1 || condition2 79 | }) 80 | handlebars.registerHelper('sonos_if_only_instance_id', function (input?: Array, defaultParams?: string) { 81 | if (input !== undefined && defaultParams !== undefined && input.length === 1 && input[0].name === 'InstanceID') { 82 | return defaultParams 83 | } 84 | return null 85 | }) 86 | handlebars.registerHelper('ends_with', function (input?: string, endsWith?: string) { 87 | if (arguments.length !== 3) { 88 | throw new handlebars.Exception('same requires exactly two argument') 89 | } 90 | if (endsWith === undefined) { 91 | throw new handlebars.Exception('2nd parameter has to be a string') 92 | } 93 | 94 | return input?.endsWith(endsWith) == true; 95 | }) 96 | 97 | outputTemplate?.files.forEach(t => { 98 | if (t.usage === 'index') { 99 | cli.action.start(`Creating '${t.outputFile}' from template ${t.file}`) 100 | const template = this.getHandlebarTemplate(outputTemplate.folder, t.file) 101 | const result = template(deviceDescription) 102 | const outputfile = path.join(outputBase, t.outputFile) 103 | fs.writeFileSync(outputfile, result) 104 | cli.action.stop() 105 | } else { 106 | cli.action.start(`Creating services '${t.outputFile}' from template '${t.file}'`) 107 | const template = this.getHandlebarTemplate(outputTemplate.folder, t.file) 108 | deviceDescription.services.forEach(s => { 109 | const outputfile = path.join(outputBase, t.outputFile.replace('{snService}', s.kebabName ?? '').replace('{service}', s.name)) 110 | const folder = path.dirname(outputfile) 111 | if (!fs.existsSync(folder)) { 112 | fs.mkdirSync(folder, {recursive: true}) 113 | } 114 | const result = template(s) 115 | fs.writeFileSync(outputfile, result) 116 | }) 117 | cli.action.stop() 118 | } 119 | }) 120 | } 121 | 122 | private getFullPathAndCreateDirectory(location: string, createFolder = false) { 123 | const filename = path.isAbsolute(location) ? location : path.join(process.cwd(), location) 124 | const folder = path.dirname(filename) 125 | if (createFolder && !fs.existsSync(folder)) { 126 | fs.mkdirSync(folder, {recursive: true}) 127 | } 128 | 129 | return filename 130 | } 131 | 132 | private getTemplate(name: string): Template | undefined | never { 133 | // Template relative to current folder; 134 | let folder = path.isAbsolute(name) ? name : path.join(process.cwd(), name) 135 | let filename = path.join(folder, 'template.json') 136 | if (fs.existsSync(filename)) { 137 | const template = JSON.parse(fs.readFileSync(filename).toString()) as Template 138 | template.folder = folder 139 | this.log('Using local template: \'%s\' from: %s ', template.name ?? template.slug, folder) 140 | return template 141 | } 142 | 143 | folder = path.join(__dirname, '..', '..', 'templates', name) 144 | filename = path.join(folder, 'template.json') 145 | 146 | if (fs.existsSync(filename)) { 147 | const template = JSON.parse(fs.readFileSync(filename).toString()) as Template 148 | template.folder = folder 149 | this.log('Using packaged template: \'%s\'', template.name ?? template.slug) 150 | return template 151 | } 152 | 153 | return this.error('Template %s not found, use folder name or packaged template name', {exit: 20}) 154 | } 155 | 156 | private postProcess(input: string): string { 157 | // Do some post-processing on the template. HandlebarsJS doesn't support Outputting these chars '{' and '}' 158 | return input.replace(/-{-/g, '{').replace(/-}-/g, '}') 159 | } 160 | 161 | private getDeviceDescription(location: string, dataTypes: { [key: string]: string }, serviceData?: { [key: string]: any }): ExtendedSonosDescription | undefined | never { 162 | const intermediateFile = this.getFullPathAndCreateDirectory(location) 163 | if (!fs.existsSync(intermediateFile)) { 164 | return this.error('Combined documentation file doesn\'t exist, generate with \'combine\' command first.', {exit: 10}) 165 | } 166 | 167 | // Set relatedStateVariables to correct value. 168 | const intermediate = JSON.parse(fs.readFileSync(intermediateFile).toString()) as ExtendedSonosDescription 169 | intermediate.services.forEach(service => { 170 | service.kebabName = StringHelper.camelToKebab(service.name.replace('AV', 'Av').replace('HT', 'Ht')) 171 | if (typeof (service.stateVariables) !== undefined) { 172 | // Replace datatypes as specified in the template 173 | if (dataTypes !== undefined) { 174 | service.stateVariables?.forEach(v => { 175 | v.dataType = this.getCorrectDataType(v.name, dataTypes) ?? dataTypes[v.dataType] ?? v.dataType 176 | }) 177 | } 178 | service.eventVariables = service.stateVariables?.filter((v: SonosStateVariable) => !v.name.startsWith('A_ARG_TYPE')).sort((a, b) => a.name.localeCompare(b.name)) 179 | } 180 | if (typeof (service.stateVariables) !== undefined && typeof (service.actions) !== undefined) { 181 | service.outputVariables = {} 182 | service.actions?.forEach(a => { 183 | a.inputs?.forEach(i => { 184 | i.relatedStateVariable = service.stateVariables?.find(v => v.name === i.relatedStateVariableName) 185 | }) 186 | a.outputs?.forEach(o => { 187 | o.relatedStateVariable = service.stateVariables?.find(v => v.name === o.relatedStateVariableName) 188 | if (o.relatedStateVariable) { 189 | // @ts-ignore 190 | service.outputVariables[o.name] = this.getCorrectDataType(o.relatedStateVariable.name, dataTypes) ?? dataTypes[o.relatedStateVariable.dataType] ?? o.relatedStateVariable.dataType; 191 | } 192 | }) 193 | }) 194 | if (Object.keys(service.outputVariables).length === 0) { 195 | delete service.outputVariables 196 | } 197 | } 198 | if (serviceData !== undefined) { 199 | service.data = serviceData[service.serviceName] 200 | } 201 | }) 202 | intermediate.services = intermediate.services.sort((a, b) => a.name.localeCompare(b.name)) 203 | return intermediate 204 | } 205 | 206 | private getHandlebarTemplate(folder: string | undefined, file: string): HandlebarsTemplateDelegate | never { 207 | if (folder === undefined) { 208 | return this.error('Template isn\'t loaded correctly', {exit: 1}) 209 | } 210 | 211 | const filename = path.join(folder, file) 212 | if (!fs.existsSync(filename)) { 213 | return this.error(`Template file ${file} could not be loaded`, {exit: 30}) 214 | } 215 | return handlebars.compile(fs.readFileSync(filename).toString()) 216 | } 217 | 218 | private getCorrectDataType(name: string, dataTypes: { [key: string]: string }): string | undefined { 219 | const type = Object.entries(dataTypes).find(e => name.endsWith(e[0])) 220 | if (type !== undefined) { 221 | return type[1] 222 | } 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /generator/sonos-docs/src/commands/musicservices.ts: -------------------------------------------------------------------------------- 1 | import {Command, flags} from '@oclif/command' 2 | import {cli} from 'cli-ux' 3 | import { SonosDevice } from '@svrooij/sonos' 4 | import * as path from 'path' 5 | import * as fs from 'fs' 6 | 7 | export default class Musicservices extends Command { 8 | static description = 'List music services available on a Sonos speaker' 9 | 10 | static flags = { 11 | ...cli.table.flags(), 12 | show: flags.boolean({ description: 'Show the music services' }), 13 | docs: flags.boolean({ description: 'Show a markdown table' }), 14 | saveJson: flags.string({ description: 'If set, save music services as json' }) 15 | } 16 | 17 | static args = [{name: 'ip', description: 'The IP of the sonos speaker to load the music services', required: true }] 18 | 19 | async run() { 20 | const {args, flags} = this.parse(Musicservices) 21 | cli.action.start(`Loading music services from ${args.ip}`) 22 | const device = new SonosDevice(args.ip); 23 | 24 | const musicServices = await device.MusicServicesService.ListAndParseAvailableServices() 25 | cli.action.stop(); 26 | 27 | if(flags.saveJson !== undefined) { 28 | cli.action.start(`Saving music services to ${flags.saveJson}`) 29 | const filename = this.getFullPathAndCreateDirectory(flags.saveJson); 30 | fs.writeFileSync(filename, JSON.stringify(musicServices, null, 2)) 31 | cli.action.stop(); 32 | } 33 | 34 | if(flags.docs) { 35 | console.log('| Id | Name | Auth | Url |\r\n|:----|:--------------------------|:-----------|:----|'); 36 | musicServices.forEach(m => { 37 | console.log(`| ${m.Id.toString().padStart(3, ' ')} | ${m.Name.padEnd(25, ' ')} | ${m.Policy.Auth.padEnd(10, ' ')} | \`${m.SecureUri}\` |`); 38 | }) 39 | } 40 | 41 | if(flags.show){ 42 | cli.table(musicServices, { 43 | Id: {}, 44 | Name: {}, 45 | Authentication: { 46 | get: row => row.Policy.Auth 47 | }, 48 | Capabilities: {}, 49 | Uri: { extended: true, get: row => row.SecureUri } 50 | }, { 51 | ...flags 52 | }) 53 | } 54 | 55 | 56 | } 57 | 58 | private getFullPathAndCreateDirectory(location: string, createFolder = false) { 59 | const filename = path.isAbsolute(location) ? location : path.join(process.cwd(), location) 60 | const folder = path.dirname(filename) 61 | if (createFolder && !fs.existsSync(folder)) { 62 | fs.mkdirSync(folder, {recursive: true}) 63 | } 64 | 65 | return filename 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /generator/sonos-docs/src/commands/services.ts: -------------------------------------------------------------------------------- 1 | import {Command, flags} from '@oclif/command' 2 | import fetch from 'node-fetch' 3 | import {parse} from 'fast-xml-parser' 4 | import * as path from 'path' 5 | import * as fs from 'fs' 6 | 7 | import SonosDevice from '../models/sonos-device' 8 | import {SonosService} from '../models/sonos-service' 9 | import SonosStateVariable from '../models/sonos-state-variable' 10 | import ArrayHelper from '../helpers/array-helper' 11 | import {SonosServiceAction, SonosServiceActionArgument} from '../models/sonos-service-action' 12 | 13 | export default class Services extends Command { 14 | static description = 'Fetch device discovery document and generate json file' 15 | 16 | static flags = { 17 | help: flags.help({char: 'h'}), 18 | folder: flags.string({char: 'f', description: 'Folder to write discovered services.', default: 'data'}), 19 | dryRun: flags.boolean({char: 'd'}), 20 | } 21 | 22 | static args = [ 23 | { name: 'ip', required: true, description: 'The IP of the sonos to do service discovery for.' }, 24 | ] 25 | 26 | async run() { 27 | const {args, flags} = this.parse(Services) 28 | 29 | this.log(`Discovering UPNP services from ${args.ip}`) 30 | const description = await this.loadDescription(args.ip) 31 | this.debug('Sonos device loaded', description) 32 | const folder = path.isAbsolute(flags.folder) ? flags.folder : path.join(process.cwd(), flags.folder) 33 | const file = path.join(folder, `sonos-${description.model}-${description.softwareGeneration}.json`) 34 | this.log('Saving discovered services to ', file) 35 | if (!fs.existsSync(folder)) { 36 | this.log('Output folder doesn\'t exists') 37 | fs.mkdirSync(folder, {recursive: true}) 38 | } 39 | 40 | fs.writeFileSync(file, JSON.stringify(description, undefined, 2)) 41 | } 42 | 43 | private createUrl(ip: string, path: string): string { 44 | return `http://${ip}:1400${path}` 45 | } 46 | 47 | private async loadDescription(ip: string): Promise { 48 | const resp = await this.fetchAndParse(this.createUrl(ip, '/xml/device_description.xml')) 49 | 50 | const desc = resp.root.device 51 | this.log(`Discovering services from ${desc.modelDescription}`) 52 | 53 | // this.log(desc.deviceList.device) 54 | const serviceDescriptions: Array = desc.serviceList.service 55 | desc.deviceList.device.forEach((d: any) => { 56 | d.serviceList.service.forEach((s: any) => { 57 | serviceDescriptions.push(s) 58 | }) 59 | }) 60 | 61 | // This service is duplicated in the device discovery 62 | const serviceToSkip = '/MediaServer/ConnectionManager/Control' 63 | 64 | const services = await Promise.all(serviceDescriptions 65 | .filter((serviceDescription: any) => serviceDescription.controlURL !== serviceToSkip) 66 | .map((service: any) => this.loadService(ip, service))) 67 | 68 | return { 69 | model: desc.modelNumber, 70 | modelDescription: desc.modelDescription, 71 | softwareGeneration: desc.swGen, 72 | softwareVersion: desc.softwareVersion, 73 | discoveryDate: new Date(), 74 | services: services.sort((a, b) => a.name.localeCompare(b.name)), 75 | } 76 | } 77 | 78 | private async loadService(ip: string, service: any): Promise { 79 | const name = service.serviceId.substring(service.serviceId.lastIndexOf(':') + 1) 80 | const resp = await this.fetchAndParse(this.createUrl(ip, service.SCPDURL)) 81 | const desc = resp.scpd 82 | // this.log('Parsing service'); 83 | // this.log(desc.actionList.action); 84 | return { 85 | name: name, 86 | serviceName: `${name}Service`, 87 | discoveryUri: service.SCPDURL, 88 | serviceId: service.serviceId, 89 | serviceType: service.serviceType, 90 | controlURL: service.controlURL, 91 | eventSubURL: service.eventSubURL, 92 | stateVariables: ArrayHelper.forceArray(desc.serviceStateTable.stateVariable).map((v: any): SonosStateVariable => { 93 | return { 94 | name: v.name, 95 | dataType: v.dataType, 96 | sendEvents: v._sendEvents === 'yes', // This probably is incorrect, sonos doesnt specify if it sends events for all properties. 97 | allowedValues: v.allowedValueList?.allowedValue, 98 | } 99 | }), 100 | actions: ArrayHelper.forceArray(desc.actionList.action).map((action: any): SonosServiceAction => { 101 | const sonosArgs = ArrayHelper.forceArray(action.argumentList?.argument ?? []).map((a: any): SonosServiceActionArgument => { 102 | return { 103 | name: a.name, 104 | direction: a.direction, 105 | relatedStateVariableName: a.relatedStateVariable, 106 | } 107 | }) 108 | const inputs = sonosArgs.filter(a => a.direction === 'in') 109 | const outputs = sonosArgs.filter(a => a.direction === 'out') 110 | return { 111 | name: action.name, 112 | inputs: inputs.length > 0 ? inputs : undefined, 113 | outputs: outputs.length > 0 ? outputs : undefined, 114 | } 115 | }), 116 | } 117 | } 118 | 119 | private async fetchAndParse(url: string): Promise { 120 | return fetch(url) 121 | .then(resp => { 122 | if (resp.ok) { 123 | return resp.text() 124 | } 125 | 126 | throw new Error(`Error loading ${url} ${resp.status} ${resp.statusText}`) 127 | }) 128 | .then(resp => parse(resp, {ignoreAttributes: false, attributeNamePrefix: '_'})) 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /generator/sonos-docs/src/helpers/array-helper.ts: -------------------------------------------------------------------------------- 1 | export default class ArrayHelper { 2 | static forceArray(input: TResponse | Array): Array { 3 | return Array.isArray(input) ? input : [input]; 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /generator/sonos-docs/src/helpers/string-helper.ts: -------------------------------------------------------------------------------- 1 | export default class StringHelper { 2 | public static camelToKebab(input: string): string { 3 | return `${input[0].toLowerCase()}${input.slice(1)}`.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2').toLowerCase(); 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /generator/sonos-docs/src/index.ts: -------------------------------------------------------------------------------- 1 | export {run} from '@oclif/command' 2 | -------------------------------------------------------------------------------- /generator/sonos-docs/src/models/author.ts: -------------------------------------------------------------------------------- 1 | export default interface Author { 2 | name: string; 3 | mail?: string; 4 | link?: string; 5 | } 6 | -------------------------------------------------------------------------------- /generator/sonos-docs/src/models/extended-sonos-description.ts: -------------------------------------------------------------------------------- 1 | import SonosDevice from './sonos-device' 2 | import SonosDiscoveryInfo from './sonos-discovery-info' 3 | 4 | export default interface ExtendedSonosDescription extends SonosDevice { 5 | deviceInfo: SonosDiscoveryInfo[]; 6 | } 7 | -------------------------------------------------------------------------------- /generator/sonos-docs/src/models/sonos-device.ts: -------------------------------------------------------------------------------- 1 | import {SonosService} from './sonos-service'; 2 | import SonosServiceError from './sonos-service-error'; 3 | 4 | export default interface SonosDevice { 5 | model: string; 6 | modelDescription: string; 7 | softwareGeneration: number; 8 | softwareVersion: string; 9 | discoveryDate: Date; 10 | services: SonosService[]; 11 | errors?: SonosServiceError[]; 12 | } 13 | -------------------------------------------------------------------------------- /generator/sonos-docs/src/models/sonos-discovery-info.ts: -------------------------------------------------------------------------------- 1 | export default interface SonosDiscoveryInfo { 2 | discoveryDate: Date; 3 | model: string; 4 | modelDescription: string; 5 | softwareGeneration: number; 6 | softwareVersion: string; 7 | } 8 | -------------------------------------------------------------------------------- /generator/sonos-docs/src/models/sonos-service-action.ts: -------------------------------------------------------------------------------- 1 | import SonosStateVariable from "./sonos-state-variable"; 2 | 3 | export interface SonosServiceAction { 4 | name: string; 5 | inputs?: SonosServiceActionArgument[]; 6 | outputs?: SonosServiceActionArgument[]; 7 | description?: string; 8 | remarks?: string; 9 | availableAt?: string[]; 10 | } 11 | 12 | export interface SonosServiceActionArgument { 13 | name: string; 14 | direction: 'in' | 'out'; 15 | relatedStateVariableName: string; 16 | relatedStateVariable?: SonosStateVariable; 17 | description?: string; 18 | sample?: unknown; 19 | } 20 | -------------------------------------------------------------------------------- /generator/sonos-docs/src/models/sonos-service-documentation.ts: -------------------------------------------------------------------------------- 1 | import SonosServiceError from './sonos-service-error'; 2 | import SonosStateVariable from './sonos-state-variable'; 3 | 4 | export interface SonosServicesDocumentation { 5 | services: { [key: string]: SonosServiceDocumentation }; 6 | errors?: SonosServiceError[]; 7 | } 8 | 9 | export interface SonosServiceDocumentation { 10 | description?: string; 11 | files?: { [key: string]: string}; 12 | actions?: { [key: string]: SonosServiceDocumentationAction }; 13 | customTypes?: { [key: string]: { [key: string]: string } }; 14 | errors?: SonosServiceError[]; 15 | variables?: SonosStateVariable[]; 16 | } 17 | 18 | export interface SonosServiceDocumentationAction { 19 | description?: string; 20 | remarks?: string; 21 | params?: { [key: string]: string }; 22 | sample?: { [key: string]: string }; 23 | } 24 | -------------------------------------------------------------------------------- /generator/sonos-docs/src/models/sonos-service-error.ts: -------------------------------------------------------------------------------- 1 | export default interface SonosServiceError { 2 | code: number; 3 | description: string; 4 | } 5 | -------------------------------------------------------------------------------- /generator/sonos-docs/src/models/sonos-service.ts: -------------------------------------------------------------------------------- 1 | import SonosDiscoveryInfo from './sonos-discovery-info' 2 | import {SonosServiceAction} from './sonos-service-action' 3 | import SonosServiceError from './sonos-service-error' 4 | import SonosStateVariable from './sonos-state-variable' 5 | 6 | export interface SonosService { 7 | name: string; 8 | kebabName?: string; 9 | serviceName: string; 10 | discoveryUri: string; 11 | 12 | serviceId: string; 13 | serviceType: string; 14 | controlURL: string; 15 | eventSubURL: string; 16 | 17 | description?: string; 18 | availableAt?: string[]; 19 | 20 | stateVariables?: SonosStateVariable[]; 21 | actions?: SonosServiceAction[]; 22 | eventVariables?: SonosStateVariable[]; 23 | outputVariables?: {[key: string]: string}; 24 | data?: { [key: string]: any }; 25 | 26 | errors?: SonosServiceError[]; 27 | deviceInfo?: SonosDiscoveryInfo[]; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /generator/sonos-docs/src/models/sonos-state-variable.ts: -------------------------------------------------------------------------------- 1 | export default interface SonosStateVariable { 2 | name: string; 3 | sendEvents: boolean; 4 | dataType: string; 5 | allowedValues?: string[]; 6 | description?: string; 7 | } 8 | -------------------------------------------------------------------------------- /generator/sonos-docs/src/models/template.ts: -------------------------------------------------------------------------------- 1 | import Author from './author'; 2 | 3 | export interface Template { 4 | author: Author; 5 | files: TemplateFile[]; 6 | name?: string; 7 | slug: string; 8 | license: string; 9 | folder?: string; 10 | dataTypes?: { [key: string]: string } 11 | serviceData?: { [key: string]: any } 12 | } 13 | 14 | export interface TemplateFile { 15 | file: string; 16 | outputFile: string; 17 | usage: 'index' | 'service'; 18 | } 19 | -------------------------------------------------------------------------------- /generator/sonos-docs/templates/docs/service.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: {{name}} 4 | parent: Sonos Services 5 | --- 6 | # {{name}} service 7 | {: .no_toc } 8 | {{#if description}} 9 | 10 | {{{description}}} 11 | {{/if}} 12 | 13 | {{#if availableAt}} 14 | The {{name}} service is available on these models: {{#each deviceInfo}}`{{modelDescription}} ({{model}}) S{{softwareGeneration}}`{{#unless @last}} / {{/unless}}{{/each}}. 15 | {{/if}} 16 | 17 | 1. TOC 18 | {:toc} 19 | 20 | --- 21 | 22 | ## Service data 23 | {: .no_toc } 24 | 25 | | name | value | 26 | |:-----|:------| 27 | | **Control URL** | `http://192.168.x.x:1400{{controlURL}}` | 28 | | **Event subscription URL** | `http://192.168.x.x:1400{{eventSubURL}}` | 29 | | **Discovery URL** | `http://192.168.x.x:1400{{discoveryUri}}` | 30 | | **Service ID** | `{{serviceId}}` | 31 | | **Service type** | `{{serviceType}}` | 32 | 33 | ### Sample request 34 | {: .no_toc } 35 | 36 | ```text 37 | POST {{controlURL}} 38 | Host: 192.168.x.x:1400 39 | soapaction: "{{serviceType}}#{ActionName}" 40 | Content-Type: text/xml; charset="utf-8" 41 | 42 | 43 | 44 | 45 | {ActionBodyHere} 46 | 47 | 48 | ``` 49 | 50 | --- 51 | 52 | ## Available actions 53 | 54 | {{#each actions}} 55 | ### {{name}} 56 | {{#if description}} 57 | 58 | {{{description}}} 59 | {{/if}} 60 | 61 | Action body: 62 | 63 | ```xml 64 | 65 | {{#each inputs}} 66 | <{{name}}>{{#if sample}}{{sample}}{{else}}{{relatedStateVariable.dataType}}{{/if}} 67 | {{/each}} 68 | 69 | ``` 70 | {{#if inputs}} 71 | 72 | Inputs: 73 | 74 | | parameter | type | description | 75 | |:----------|:-----|:------------| 76 | {{#each inputs}} 77 | | **{{name}}** | `{{relatedStateVariable.dataType}}` | {{{description}}}{{#if (are_equal relatedStateVariable.dataType 'boolean')}} Allowed values: `1` (= true) / `0` (= false) {{/if}}{{#if relatedStateVariable.allowedValues}} Allowed values: {{#each relatedStateVariable.allowedValues}}`{{this}}`{{#unless @last}} / {{/unless}}{{/each}}{{/if}}{{#if (ends_with name 'MetaData')}} Embedded XML{{/if}} | 78 | {{/each}} 79 | {{else}} 80 | 81 | No input arguments 82 | {{/if}} 83 | {{#if outputs}} 84 | 85 | Outputs: 86 | 87 | | parameter | type | description | 88 | |:----------|:-----|:------------| 89 | {{#each outputs}} 90 | | **{{name}}** | `{{relatedStateVariable.dataType}}` | {{{description}}}{{#if (are_equal relatedStateVariable.dataType 'boolean')}} `1` for true and `0` for false {{/if}}{{#if relatedStateVariable.allowedValues}} Possible values: {{#each relatedStateVariable.allowedValues}}`{{this}}`{{#unless @last}} / {{/unless}}{{/each}}{{/if}}{{#if (ends_with name 'MetaData')}} Embedded XML{{/if}} | 91 | {{/each}} 92 | {{/if}} 93 | {{#if remarks}} 94 | 95 | **Remarks** {{{remarks}}} 96 | {{/if}} 97 | 98 | {{/each}} 99 | {{#if eventVariables}} 100 | ## Events 101 | 102 | The {{serviceName}} has variables that might be emitted if you subscribe to events. 103 | 104 | ### Subscribe to events 105 | 106 | ```text 107 | SUBSCRIBE {{eventSubURL}} 108 | Host: 192.168.x.x:1400 109 | callback: 110 | NT: upnp:event 111 | Timeout: Second-3600 112 | ``` 113 | 114 | ### Event variables 115 | 116 | | Variable | Sends events* | type | possible values | 117 | |:---------|:-------------|:-----|:----------------| 118 | {{#each eventVariables}} 119 | | {{name}} | {{#if sendEvents}}✔{{/if}} | `{{dataType}}` | {{#if (are_equal dataType 'boolean')}} `1` for true and `0` for false {{/if}}{{#each allowedValues}}`{{this}}`{{#unless @last}} / {{/unless}}{{/each}}{{#if (ends_with name 'MetaData')}} Embedded XML{{/if}} | 120 | {{/each}} 121 | 122 | If the variable has a `✔` in the Sends events column, the service discovery specifies this variable emits events. Other properties might be send as a part of `LastChange` 123 | {{/if}} 124 | {{#if errors}} 125 | 126 | ## Custom errors 127 | 128 | The {{serviceName}} has the following known custom errors. 129 | 130 | | Error code | Description | 131 | |:-----------|:------------| 132 | {{#each errors}} 133 | | `{{code}}` | {{{description}}} | 134 | {{/each}} 135 | {{/if}} 136 | 137 | --- 138 | 139 | This file is automatically generated with [@svrooij/sonos-docs](https://github.com/svrooij/sonos-api-docs/tree/main/generator/sonos-docs), do not edit manually. 140 | 141 | | Device | Software generation | Software version | Discovery date | 142 | |:-------|:--------------------|:-----------------|:---------------| 143 | {{#each deviceInfo}} 144 | | `{{modelDescription}} ({{model}})` | S{{softwareGeneration}} | {{softwareVersion}} | {{discoveryDate}} | 145 | {{/each}} 146 | -------------------------------------------------------------------------------- /generator/sonos-docs/templates/docs/services-index.hbs: -------------------------------------------------------------------------------- 1 | --- 2 | layout: default 3 | title: Sonos Services 4 | has_children: true 5 | nav_order: 5 6 | has_toc: false 7 | --- 8 | 9 | # Sonos SOAP Services 10 | {: .no_toc } 11 | 12 | Every sonos speaker has several soap services. Each service has one or more actions you can call. 13 | 14 | ## UPNP specifications 15 | 16 | Sonos speaker follow the [MediaServer:4 and MediaRenderer:3 specifications](https://openconnectivity.org/developer/specifications/upnp-resources/upnp/mediaserver4-and-mediarenderer3/) by the [Open Connectivity Foundation](https://openconnectivity.org/). 17 | These documents can provide you with some extra guidelines. More details can be found at [Sonos communication](\{{'/sonos-communication.html' | relative_url }}), which show you how to exactly do a call to the sonos speakers. 18 | 19 | ## All available services 20 | {: .no_toc } 21 | 22 | | Service | Description | 23 | |:--------|:------------| 24 | {{#each services}} 25 | | [**{{name}}**]({{kebabName}}.html) | {{description}} | 26 | {{/each}} 27 | {{#if errors}} 28 | 29 | ## UPNP errors 30 | 31 | These are the default UPNP errors. 32 | 33 | | Error code | Description | 34 | |:-----------|:------------| 35 | {{#each errors}} 36 | | `{{code}}` | {{description}} | 37 | {{/each}} 38 | {{/if}} 39 | 40 | --- 41 | 42 | This file is automatically generated with [@svrooij/sonos-docs](https://github.com/svrooij/sonos-api-docs/tree/main/generator/sonos-docs), do not edit manually. 43 | 44 | | Device | Software generation | Software version | Discovery date | 45 | |:-------|:--------------------|:-----------------|:---------------| 46 | {{#each deviceInfo}} 47 | | `{{modelDescription}} ({{model}})` | S{{softwareGeneration}} | {{softwareVersion}} | {{discoveryDate}} | 48 | {{/each}} 49 | -------------------------------------------------------------------------------- /generator/sonos-docs/templates/docs/template.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://svrooij.io/sonos-api-docs/schema/template.json", 3 | "name": "Sonos local UPNP documentation", 4 | "slug": "docs", 5 | "author": { 6 | "name": "svrooij", 7 | "link": "https://svrooij.io" 8 | }, 9 | "files": [ 10 | { 11 | "file": "service.hbs", 12 | "outputFile": "services/{snService}.md", 13 | "usage":"service" 14 | }, 15 | { 16 | "file": "services-index.hbs", 17 | "outputFile": "services/index.md", 18 | "usage": "index" 19 | } 20 | ], 21 | "license": "MIT" 22 | } -------------------------------------------------------------------------------- /generator/sonos-docs/templates/node/README.md: -------------------------------------------------------------------------------- 1 | # node-sonos template 2 | 3 | This folder contains the template files for [node-sonos](://github.com/bencevans/node-sonos), and is not used in the actual library just yet. 4 | 5 | ## Folder content 6 | 7 | | File | Description | Remarks | 8 | |:-----|:------------|:--------| 9 | | [service](./service.hbs) | Single service | Strong type service template | 10 | 11 | ## Use this template 12 | 13 | To use this template you'll need both this generator and node-sonos checked out. 14 | 15 | ```shell 16 | # generate the intermediate file (this will take the online documentation file) 17 | ./generator/sonos-docs/bin/run combine 18 | 19 | # Make sure you don't have any changes in node-sonos, that makes it unclear what the generator changed 20 | # generate the service files (set the correct root folder for node-sonos) 21 | ./generator/sonos-docs/bin/run generate node ../node-sonos 22 | ``` 23 | 24 | ## Generator 25 | 26 | See the generator documentation [here](https://github.com/svrooij/sonos-api-docs/tree/main/generator/sonos-docs). 27 | -------------------------------------------------------------------------------- /generator/sonos-docs/templates/node/service.hbs: -------------------------------------------------------------------------------- 1 | const Service = require('./Service') 2 | /** 3 | * Sonos {{serviceName}} 4 | {{#if description}} 5 | * 6 | * {{description}} 7 | {{/if}} 8 | * 9 | * @author Stephan van Rooij - https://svrooij.io 10 | * @remarks This file is generated, do not edit manually. https://svrooij.io/sonos-api-docs 11 | * @export 12 | * @class {{serviceName}} 13 | * @extends {Service} 14 | */ 15 | class {{serviceName}} extends Service { 16 | constructor (host, port) { 17 | super() 18 | this.name = '{{name}}' 19 | this.host = host 20 | this.port = port || 1400 21 | this.controlURL = '{{controlURL}}' 22 | this.eventSubURL = '{{eventSubURL}}' 23 | this.SCPDURL = '{{discoveryUri}}' 24 | } 25 | 26 | // #region actions 27 | {{#each actions}} 28 | /** 29 | * {{name}}{{#if description}} - {{description}}{{/if}} 30 | {{#if inputs}} 31 | * 32 | * @param {Object} [options] - An object with the following properties 33 | {{/if}} 34 | {{#each inputs}} 35 | * @param { {{~ relatedStateVariable.dataType ~}} } options.{{name}}{{#if description}} - {{{description}}}{{/if}}{{#if relatedStateVariable.allowedValues}} [ {{#each relatedStateVariable.allowedValues}}'{{this}}'{{#unless @last}} / {{/unless}}{{/each}} ]{{/if}} 36 | {{/each}} 37 | {{#if remarks}} 38 | * @remarks {{{remarks}}} 39 | {{/if}} 40 | {{#if outputs}} 41 | * @returns {Object} response object, with these properties {{#each outputs}}'{{name}}'{{#unless @last}}, {{/unless}}{{/each}} 42 | {{/if}} 43 | */ 44 | {{#if inputs}} 45 | async {{name}} (options{{{sonos_if_only_instance_id inputs ' = { InstanceID: 0 }'}}}) { return this._request('{{name}}', options) } 46 | {{else}} 47 | async {{name}} () { return this._request('{{name}}') } 48 | {{/if}} 49 | {{#unless @last}} 50 | 51 | {{/unless}} 52 | {{/each}} 53 | // #endregion 54 | } 55 | 56 | module.exports = {{serviceName}} 57 | -------------------------------------------------------------------------------- /generator/sonos-docs/templates/node/template.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://svrooij.io/sonos-api-docs/schema/template.json", 3 | "name": "Node sonos", 4 | "slug": "node", 5 | "repository": "https://github.com/bencevans/node-sonos/", 6 | "author": { 7 | "name": "svrooij", 8 | "link": "https://svrooij.io" 9 | }, 10 | "files": [ 11 | { 12 | "file": "service.hbs", 13 | "outputFile": "lib/services/{snService}.service.js", 14 | "usage":"service" 15 | } 16 | ], 17 | "dataTypes": { 18 | "ui4": "number", 19 | "i4": "number", 20 | "ui2": "number", 21 | "i2": "number", 22 | "MetaData": "string", 23 | "ZoneGroupState": "string" 24 | }, 25 | "serviceData": { 26 | 27 | }, 28 | "license": "MIT" 29 | } 30 | -------------------------------------------------------------------------------- /generator/sonos-docs/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "declaration": true, 4 | "importHelpers": true, 5 | "module": "commonjs", 6 | "outDir": "lib", 7 | "rootDir": "src", 8 | "strict": true, 9 | "target": "es2017", 10 | "sourceMap": true 11 | }, 12 | "include": [ 13 | "src/**/*" 14 | ] 15 | } 16 | --------------------------------------------------------------------------------