├── .github
├── FUNDING.yml
└── workflows
│ ├── automerge.yaml
│ ├── hacs.yaml
│ ├── hassfest.yaml
│ └── release.yaml
├── LICENSE
├── README.md
├── custom_components
└── smartthings_soundbar
│ ├── __init__.py
│ ├── api.py
│ ├── manifest.json
│ └── media_player.py
└── hacs.json
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | ko_fi: piotrmachowski
2 | custom: ["buycoffee.to/piotrmachowski", "paypal.me/PiMachowski", "revolut.me/314ma"]
3 |
--------------------------------------------------------------------------------
/.github/workflows/automerge.yaml:
--------------------------------------------------------------------------------
1 | name: 'Automatically merge master -> dev'
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 |
8 | jobs:
9 | build:
10 | name: Automatically merge master to dev
11 | runs-on: ubuntu-latest
12 | steps:
13 | - uses: actions/checkout@v3
14 | name: Git checkout
15 | with:
16 | fetch-depth: 0
17 | - name: Merge master -> dev
18 | run: |
19 | git config user.name "GitHub Actions"
20 | git config user.email "PiotrMachowski@users.noreply.github.com"
21 | if (git checkout dev)
22 | then
23 | git merge --ff-only master || git merge --no-commit master
24 | git commit -m "Automatically merge master -> dev" || echo "No commit needed"
25 | git push origin dev
26 | else
27 | echo "No dev branch"
28 | fi
--------------------------------------------------------------------------------
/.github/workflows/hacs.yaml:
--------------------------------------------------------------------------------
1 | name: Validate HACS
2 | on:
3 | push:
4 | pull_request:
5 | jobs:
6 | ci:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - uses: actions/checkout@v2
10 | name: Download repo
11 | with:
12 | fetch-depth: 0
13 |
14 | - uses: actions/setup-python@v2
15 | name: Setup Python
16 | with:
17 | python-version: '3.13.x'
18 |
19 | - uses: actions/cache@v2
20 | name: Cache
21 | with:
22 | path: |
23 | ~/.cache/pip
24 | key: custom-component-ci
25 |
26 | - name: HACS Action
27 | uses: hacs/action@main
28 | with:
29 | CATEGORY: integration
30 | ignore: brands
31 |
--------------------------------------------------------------------------------
/.github/workflows/hassfest.yaml:
--------------------------------------------------------------------------------
1 | name: Validate with hassfest
2 |
3 | on:
4 | push:
5 | pull_request:
6 |
7 | jobs:
8 | validate:
9 | runs-on: "ubuntu-latest"
10 | steps:
11 | - uses: "actions/checkout@v2"
12 | - uses: home-assistant/actions/hassfest@master
13 |
--------------------------------------------------------------------------------
/.github/workflows/release.yaml:
--------------------------------------------------------------------------------
1 | name: Release
2 |
3 | on:
4 | release:
5 | types: [published]
6 |
7 | env:
8 | COMPONENT_NAME: smartthings_soundbar
9 |
10 | jobs:
11 | release:
12 | name: Prepare release
13 | runs-on: ubuntu-latest
14 | permissions:
15 | contents: write
16 | id-token: write
17 | steps:
18 | - name: Download repo
19 | uses: actions/checkout@v4.2.2
20 |
21 | - name: Adjust version number
22 | shell: bash
23 | run: |
24 | version="${{ github.event.release.tag_name }}"
25 | yq e -P -o=json \
26 | -i ".version = \"${version}\"" \
27 | "${{ github.workspace }}/custom_components/${{ env.COMPONENT_NAME }}/manifest.json"
28 |
29 | - name: Zip ${{ env.COMPONENT_NAME }} dir
30 | run: |
31 | cd "${{ github.workspace }}/custom_components/${{ env.COMPONENT_NAME }}"
32 | zip ${{ env.COMPONENT_NAME }}.zip -r ./
33 |
34 |
35 | - name: Upload zip to release
36 | uses: softprops/action-gh-release@v2.1.0
37 | with:
38 | files: ${{ github.workspace }}/custom_components/${{ env.COMPONENT_NAME }}/${{ env.COMPONENT_NAME }}.zip
39 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Piotr Machowski
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 | [![HACS Custom][hacs_shield]][hacs]
2 | [![GitHub Latest Release][releases_shield]][latest_release]
3 | [![GitHub All Releases][downloads_total_shield]][releases]
4 | [![Ko-Fi][ko_fi_shield]][ko_fi]
5 | [![buycoffee.to][buycoffee_to_shield]][buycoffee_to]
6 | [![PayPal.Me][paypal_me_shield]][paypal_me]
7 | [![Revolut.Me][revolut_me_shield]][revolut_me]
8 |
9 |
10 |
11 | [hacs_shield]: https://img.shields.io/static/v1.svg?label=HACS&message=Custom&style=popout&color=orange&labelColor=41bdf5&logo=HomeAssistantCommunityStore&logoColor=white
12 | [hacs]: https://hacs.xyz/docs/faq/custom_repositories
13 |
14 | [latest_release]: https://github.com/PiotrMachowski/Home-Assistant-custom-components-SmartThings-Soundbar/releases/latest
15 | [releases_shield]: https://img.shields.io/github/release/PiotrMachowski/Home-Assistant-custom-components-SmartThings-Soundbar.svg?style=popout
16 |
17 | [releases]: https://github.com/PiotrMachowski/Home-Assistant-custom-components-SmartThings-Soundbar/releases
18 | [downloads_total_shield]: https://img.shields.io/github/downloads/PiotrMachowski/Home-Assistant-custom-components-SmartThings-Soundbar/total
19 |
20 |
21 | # SmartThings Soundbar
22 |
23 | Adds support for SmartThings enabled Soundbar
24 |
25 | ## Features
26 |
27 | - Turn on/off
28 | - Set volume
29 | - Step volume up/down
30 | - Mute/unmute
31 | - Select source
32 | - Show current volume level
33 | - Show current state: on/off/playing/paused/idle
34 | - Show if muted/unmuted
35 | - Show current source
36 |
37 |
38 | ## Configuration options
39 |
40 | | Key | Type | Required | Default | Description |
41 | | --- | --- | --- | --- | --- |
42 | | `name` | `string` | `False` | `SmartThings Soundbar` | Name of soundbar |
43 | | `api_key` | `string` | `True` | - | SmartThings API key (see: [here](https://github.com/PiotrMachowski/Home-Assistant-custom-components-SmartThings-Soundbar#getting-api-key-and-device-id)) |
44 | | `device_id` | `string` | `True` | - | SmartThings device id (see: [here](https://github.com/PiotrMachowski/Home-Assistant-custom-components-SmartThings-Soundbar#getting-api-key-and-device-id)) |
45 | | `max_volume` | `positive integer` | `False` | 100 | Volume level that will be used as a maximum level in Home Assistant |
46 |
47 | ## Example usage
48 |
49 | ```yaml
50 | media_player:
51 | - platform: smartthings_soundbar
52 | name: Soundbar
53 | api_key: "YOUR API KEY"
54 | device_id: "YOUR DEVICE ID"
55 | max_volume: 30
56 | ```
57 |
58 |
59 | ## Getting API key and device id
60 |
61 | Make sure your device is connected to your SmartThings account.
62 |
63 | Obtain an API key by following [these steps](https://www.home-assistant.io/integrations/smartthings/#personal-access-token-pat).
64 |
65 | Once you're signed in on that page, go to https://api.smartthings.com/v1/devices to see a list of your devices and their device IDs.
66 |
67 | ## Installation
68 |
69 | ### Using [HACS](https://hacs.xyz/) (recommended)
70 |
71 | This integration can be added to HACS as a [custom repository](https://hacs.xyz/docs/faq/custom_repositories):
72 | * URL: `https://github.com/PiotrMachowski/Home-Assistant-custom-components-SmartThings-Soundbar`
73 | * Category: `Integration`
74 |
75 | After adding a custom repository you can use HACS to install this integration using user interface.
76 |
77 | ### Manual
78 |
79 | To install this integration manually you have to download [*smartthings_soundbar.zip*](https://github.com/PiotrMachowski/Home-Assistant-custom-components-SmartThings-Soundbar/releases/latest/download/smartthings_soundbar.zip) and extract its contents to `config/custom_components/smartthings_soundbar` directory:
80 | ```bash
81 | mkdir -p custom_components/smartthings_soundbar
82 | cd custom_components/smartthings_soundbar
83 | wget https://github.com/PiotrMachowski/Home-Assistant-custom-components-SmartThings-Soundbar/releases/latest/download/smartthings_soundbar.zip
84 | unzip smartthings_soundbar.zip
85 | rm smartthings_soundbar.zip
86 | ```
87 |
88 | ### Known problems
89 |
90 | * If you have config validation issues after installing this component you have to follow these steps:
91 | * Install custom component
92 | * Restart Home Assistant
93 | * Add configuration
94 | * Restart Home Assistant again
95 |
96 | ## Supported devices
97 |
98 | This integration was confirmed to work with following devices:
99 |
100 | - Samsung HW-N950
101 | - Samsung HW-Q800B
102 | - Samsung HW-Q800T
103 | - Samsung HW-Q950T
104 | - Samsung HW-Q990B
105 | - Samsung HW-Q990C
106 | - Samsung HW-Q90R
107 | - Samsung HW-Q80R
108 | - Samsung HW-Q70R
109 | - Samsung HW-S60T
110 | - Samsung HW-S61T
111 |
112 |
113 |
114 |
115 |
116 | ## Support
117 |
118 | If you want to support my work with a donation you can use one of the following platforms:
119 |
120 |
121 |
122 | Platform |
123 | Payment methods |
124 | Link |
125 | Comment |
126 |
127 |
128 | Ko-fi |
129 |
130 | PayPal
131 | Credit card
132 | |
133 |
134 |
135 | |
136 |
137 | No fees
138 | Single or monthly payment
139 | |
140 |
141 |
142 | buycoffee.to |
143 |
144 | BLIK
145 | Bank transfer
146 | |
147 |
148 |
149 | |
150 | |
151 |
152 |
153 | PayPal |
154 |
155 | PayPal
156 | |
157 |
158 |
159 | |
160 |
161 | No fees
162 | |
163 |
164 |
165 | Revolut |
166 |
167 | Revolut
168 | Credit Card
169 | |
170 |
171 |
172 | |
173 |
174 | No fees
175 | |
176 |
177 |
178 |
179 | ### Powered by
180 | [](https://jb.gg/OpenSourceSupport)
181 |
182 |
183 | [ko_fi_shield]: https://img.shields.io/static/v1.svg?label=%20&message=Ko-Fi&color=F16061&logo=ko-fi&logoColor=white
184 |
185 | [ko_fi]: https://ko-fi.com/piotrmachowski
186 |
187 | [buycoffee_to_shield]: https://shields.io/badge/buycoffee.to-white?style=flat&labelColor=white&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABhmlDQ1BJQ0MgcHJvZmlsZQAAKJF9kT1Iw1AUhU9TpaIVh1YQcchQnayIijhKFYtgobQVWnUweemP0KQhSXFxFFwLDv4sVh1cnHV1cBUEwR8QVxcnRRcp8b6k0CLGC4/3cd49h/fuA4R6malmxzigapaRisfEbG5FDLzChxB6MIZ+iZl6Ir2QgWd93VM31V2UZ3n3/Vm9St5kgE8knmW6YRGvE09vWjrnfeIwK0kK8TnxqEEXJH7kuuzyG+eiwwLPDBuZ1BxxmFgstrHcxqxkqMRTxBFF1ShfyLqscN7irJarrHlP/sJgXltOc53WEOJYRAJJiJBRxQbKsBClXSPFRIrOYx7+QcefJJdMrg0wcsyjAhWS4wf/g9+zNQuTE25SMAZ0vtj2xzAQ2AUaNdv+PrbtxgngfwautJa/UgdmPkmvtbTIEdC3DVxctzR5D7jcAQaedMmQHMlPSygUgPcz+qYcELoFulfduTXPcfoAZGhWSzfAwSEwUqTsNY93d7XP7d+e5vx+AIahcq//o+yoAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH5wETCy4vFNqLzwAAAVpJREFUOMvd0rFLVXEYxvHPOedKJnKJhrDLuUFREULE7YDCMYj+AydpsCWiaKu29hZxiP4Al4aWwC1EdFI4Q3hqEmkIBI8ZChWXKNLLvS0/Qcza84V3enm/7/s878t/HxGkeTaIGziP+EB918nawu7Dq1d0e1+2J2bepnk2jFEUVVF+qKV51o9neBCaugfge70keoxxUbSWjrQ+4SUyzKZ5NlnDZdzGG7w4DIh+dtZEFntDA98l8S0MYwctNGrYz9WqKJePFLq80g5Sr+EHlnATp+NA+4qLaZ7FfzMrzbMBjGEdq8GrJMZnvAvFC/8wfAwjWMQ8XmMzaW9sdevNRgd3MFhvNpbaG1u/Dk2/hOc4gadVUa7Um425qii/7Z+xH9O4jwW8Cqv24Tru4hyeVEU588cfBMgpPMI9nMFe0BkFzVOYrYqycyQgQJLwTC2cDZCPeF8V5Y7jGb8BUpRicy7OU5MAAAAASUVORK5CYII=
188 |
189 | [buycoffee_to]: https://buycoffee.to/piotrmachowski
190 |
191 | [buy_me_a_coffee_shield]: https://img.shields.io/static/v1.svg?label=%20&message=Buy%20me%20a%20coffee&color=6f4e37&logo=buy%20me%20a%20coffee&logoColor=white
192 |
193 | [buy_me_a_coffee]: https://www.buymeacoffee.com/PiotrMachowski
194 |
195 | [paypal_me_shield]: https://img.shields.io/static/v1.svg?label=%20&message=PayPal.Me&logo=paypal
196 |
197 | [paypal_me]: https://paypal.me/PiMachowski
198 |
199 | [revolut_me_shield]: https://img.shields.io/static/v1.svg?label=%20&message=Revolut&logo=revolut
200 |
201 | [revolut_me]: https://revolut.me/314ma
202 |
203 |
--------------------------------------------------------------------------------
/custom_components/smartthings_soundbar/__init__.py:
--------------------------------------------------------------------------------
1 | """SmartThings Soundbar"""
--------------------------------------------------------------------------------
/custom_components/smartthings_soundbar/api.py:
--------------------------------------------------------------------------------
1 | import json
2 |
3 | import requests
4 | from homeassistant.const import (STATE_OFF, STATE_ON, STATE_PAUSED, STATE_PLAYING, STATE_UNAVAILABLE)
5 |
6 | API_BASEURL = "https://api.smartthings.com/v1"
7 | API_DEVICES = API_BASEURL + "/devices/"
8 | COMMAND_POWER_ON = "{'commands': [{'component': 'main','capability': 'switch','command': 'on'}]}"
9 | COMMAND_POWER_OFF = "{'commands': [{'component': 'main','capability': 'switch','command': 'off'}]}"
10 | COMMAND_REFRESH = "{'commands':[{'component': 'main','capability': 'refresh','command': 'refresh'}]}"
11 | COMMAND_PAUSE = "{'commands':[{'component': 'main','capability': 'mediaPlayback','command': 'pause'}]}"
12 | COMMAND_MUTE = "{'commands':[{'component': 'main','capability': 'audioMute','command': 'mute'}]}"
13 | COMMAND_UNMUTE = "{'commands':[{'component': 'main','capability': 'audioMute','command': 'unmute'}]}"
14 | COMMAND_PLAY = "{'commands':[{'component': 'main','capability': 'mediaPlayback','command': 'play'}]}"
15 | COMMAND_STOP = "{'commands':[{'component': 'main','capability': 'mediaPlayback','command': 'stop'}]}"
16 | COMMAND_REWIND = "{'commands':[{'component': 'main','capability': 'mediaPlayback','command': 'rewind'}]}"
17 | COMMAND_FAST_FORWARD = "{'commands':[{'component': 'main','capability': 'mediaPlayback','command': 'fastForward'}]}"
18 |
19 | CONTROLLABLE_SOURCES = ["bluetooth", "wifi"]
20 |
21 |
22 | class SoundbarApi:
23 |
24 | @staticmethod
25 | def device_update(entity):
26 | API_KEY = entity._api_key
27 | REQUEST_HEADERS = {"Authorization": "Bearer " + API_KEY}
28 | DEVICE_ID = entity._device_id
29 | API_DEVICE = API_DEVICES + DEVICE_ID
30 | API_DEVICE_STATUS = API_DEVICE + "/states"
31 | API_COMMAND = API_DEVICE + "/commands"
32 | cmdurl = requests.post(API_COMMAND, data=COMMAND_REFRESH, headers=REQUEST_HEADERS)
33 | resp = requests.get(API_DEVICE_STATUS, headers=REQUEST_HEADERS)
34 | data = resp.json()
35 |
36 | switch_state = SoundbarApi.extractor(data, "main.switch.value")
37 | if switch_state is None:
38 | entity._state = STATE_UNAVAILABLE
39 | return
40 | playback_state = SoundbarApi.extractor(data, "main.playbackStatus.value")
41 | device_source = SoundbarApi.extractor(data, "main.inputSource.value")
42 | device_all_sources = json.loads(SoundbarApi.extractor(data, "main.supportedInputSources.value"))
43 | device_muted = SoundbarApi.extractor(data, "main.mute.value") != "unmuted"
44 | device_volume = SoundbarApi.extractor(data, "main.volume.value")
45 | device_volume = min(int(device_volume) / entity._max_volume, 1)
46 |
47 | if switch_state == "on":
48 | if device_source.lower() in CONTROLLABLE_SOURCES:
49 | if playback_state == "playing":
50 | entity._state = STATE_PLAYING
51 | elif playback_state == "paused":
52 | entity._state = STATE_PAUSED
53 | else:
54 | entity._state = STATE_ON
55 | else:
56 | entity._state = STATE_ON
57 | else:
58 | entity._state = STATE_OFF
59 | entity._volume = device_volume
60 | entity._source_list = device_all_sources if type(device_all_sources) is list else device_all_sources["value"]
61 | entity._muted = device_muted
62 | entity._source = device_source
63 | if entity._state in [STATE_PLAYING, STATE_PAUSED] and 'trackDescription' in data['main']:
64 | entity._media_title = SoundbarApi.extractor(data, "main.trackDescription.value")
65 | else:
66 | entity._media_title = None
67 |
68 | @staticmethod
69 | def send_command(entity, argument, cmdtype):
70 | API_KEY = entity._api_key
71 | REQUEST_HEADERS = {"Authorization": "Bearer " + API_KEY}
72 | DEVICE_ID = entity._device_id
73 | API_DEVICES = API_BASEURL + "/devices/"
74 | API_DEVICE = API_DEVICES + DEVICE_ID
75 | API_COMMAND = API_DEVICE + "/commands"
76 |
77 | if cmdtype == "setvolume": # sets volume
78 | API_COMMAND_DATA = "{'commands':[{'component': 'main','capability': 'audioVolume','command': 'setVolume','arguments': "
79 | volume = int(argument * entity._max_volume)
80 | API_COMMAND_ARG = "[{}]}}]}}".format(volume)
81 | API_FULL = API_COMMAND_DATA + API_COMMAND_ARG
82 | cmdurl = requests.post(API_COMMAND, data=API_FULL, headers=REQUEST_HEADERS)
83 | elif cmdtype == "stepvolume": # steps volume up or down
84 | if argument == "up":
85 | API_COMMAND_DATA = "{'commands':[{'component': 'main','capability': 'audioVolume','command': 'volumeUp'}]}"
86 | cmdurl = requests.post(API_COMMAND, data=API_COMMAND_DATA, headers=REQUEST_HEADERS)
87 | else:
88 | API_COMMAND_DATA = "{'commands':[{'component': 'main','capability': 'audioVolume','command': 'volumeDown'}]}"
89 | cmdurl = requests.post(API_COMMAND, data=API_COMMAND_DATA, headers=REQUEST_HEADERS)
90 | elif cmdtype == "audiomute": # mutes audio
91 | if entity._muted == False:
92 | cmdurl = requests.post(API_COMMAND, data=COMMAND_MUTE, headers=REQUEST_HEADERS)
93 | else:
94 | cmdurl = requests.post(API_COMMAND, data=COMMAND_UNMUTE, headers=REQUEST_HEADERS)
95 | elif cmdtype == "switch_off": # turns off
96 | cmdurl = requests.post(API_COMMAND, data=COMMAND_POWER_OFF, headers=REQUEST_HEADERS)
97 | elif cmdtype == "switch_on": # turns on
98 | cmdurl = requests.post(API_COMMAND, data=COMMAND_POWER_ON, headers=REQUEST_HEADERS)
99 | elif cmdtype == "play": # play
100 | cmdurl = requests.post(API_COMMAND, data=COMMAND_PLAY, headers=REQUEST_HEADERS)
101 | elif cmdtype == "pause": # pause
102 | cmdurl = requests.post(API_COMMAND, data=COMMAND_PAUSE, headers=REQUEST_HEADERS)
103 | elif cmdtype == "selectsource": # changes source
104 | API_COMMAND_DATA = "{'commands':[{'component': 'main','capability': 'mediaInputSource','command': 'setInputSource', 'arguments': "
105 | API_COMMAND_ARG = "['{}']}}]}}".format(argument)
106 | API_FULL = API_COMMAND_DATA + API_COMMAND_ARG
107 | cmdurl = requests.post(API_COMMAND, data=API_FULL, headers=REQUEST_HEADERS)
108 | elif cmdtype == "selectsoundmode":
109 | API_COMMAND_DATA = f"""{{
110 | "commands":[
111 | {{
112 | "component":"main",
113 | "capability":"execute",
114 | "command":"execute",
115 | "arguments":[
116 | "/sec/networkaudio/soundmode",
117 | {{
118 | "x.com.samsung.networkaudio.soundmode":"{argument}"
119 | }}
120 | ]
121 | }}
122 | ]
123 | }}"""
124 | cmdurl = requests.post(API_COMMAND, data=API_COMMAND_DATA, headers=REQUEST_HEADERS)
125 | entity.schedule_update_ha_state()
126 |
127 | @staticmethod
128 | def extractor(json, path):
129 | def extractor_arr(json_obj, path_array):
130 | if path_array[0] not in json_obj:
131 | return None
132 | if len(path_array) > 1:
133 | return extractor_arr(json_obj[path_array[0]], path_array[1:])
134 | return json_obj[path_array[0]]
135 | try:
136 | return extractor_arr(json, path.split("."))
137 | except:
138 | return None
--------------------------------------------------------------------------------
/custom_components/smartthings_soundbar/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "domain": "smartthings_soundbar",
3 | "name": "SmartThings Soundbar",
4 | "codeowners": [
5 | "@PiotrMachowski"
6 | ],
7 | "dependencies": [],
8 | "documentation": "https://github.com/PiotrMachowski/Home-Assistant-custom-components-SmartThings-Soundbar",
9 | "iot_class": "cloud_polling",
10 | "issue_tracker": "https://github.com/PiotrMachowski/Home-Assistant-custom-components-SmartThings-Soundbar/issues",
11 | "requirements": [],
12 | "version": "v0.0.0"
13 | }
14 |
--------------------------------------------------------------------------------
/custom_components/smartthings_soundbar/media_player.py:
--------------------------------------------------------------------------------
1 | import logging
2 | import voluptuous as vol
3 |
4 | from .api import SoundbarApi
5 |
6 | from homeassistant.components.media_player import (
7 | MediaPlayerEntity,
8 | MediaPlayerEntityFeature,
9 | MediaPlayerDeviceClass,
10 | PLATFORM_SCHEMA,
11 | )
12 | from homeassistant.const import (
13 | CONF_NAME, CONF_API_KEY, CONF_DEVICE_ID
14 | )
15 | import homeassistant.helpers.config_validation as cv
16 |
17 | _LOGGER = logging.getLogger(__name__)
18 |
19 | DEFAULT_NAME = "SmartThings Soundbar"
20 | CONF_MAX_VOLUME = "max_volume"
21 |
22 | SUPPORT_SMARTTHINGS_SOUNDBAR = (
23 | MediaPlayerEntityFeature.PAUSE
24 | | MediaPlayerEntityFeature.VOLUME_STEP
25 | | MediaPlayerEntityFeature.VOLUME_MUTE
26 | | MediaPlayerEntityFeature.VOLUME_SET
27 | | MediaPlayerEntityFeature.SELECT_SOURCE
28 | | MediaPlayerEntityFeature.TURN_OFF
29 | | MediaPlayerEntityFeature.TURN_ON
30 | | MediaPlayerEntityFeature.PLAY
31 | | MediaPlayerEntityFeature.SELECT_SOUND_MODE
32 | )
33 |
34 | PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend(
35 | {
36 | vol.Required(CONF_API_KEY): cv.string,
37 | vol.Optional(CONF_NAME, default=DEFAULT_NAME): cv.string,
38 | vol.Optional(CONF_DEVICE_ID): cv.string,
39 | vol.Optional(CONF_MAX_VOLUME, default=100): cv.positive_int,
40 | }
41 | )
42 |
43 |
44 | def setup_platform(hass, config, add_entities, discovery_info=None):
45 | name = config.get(CONF_NAME)
46 | api_key = config.get(CONF_API_KEY)
47 | device_id = config.get(CONF_DEVICE_ID)
48 | max_volume = config.get(CONF_MAX_VOLUME)
49 | add_entities([SmartThingsSoundbarMediaPlayer(name, api_key, device_id, max_volume)])
50 |
51 |
52 | class SmartThingsSoundbarMediaPlayer(MediaPlayerEntity):
53 |
54 | def __init__(self, name, api_key, device_id, max_volume):
55 | self._name = name
56 | self._device_id = device_id
57 | self._api_key = api_key
58 | self._max_volume = max_volume
59 | self._volume = 1
60 | self._muted = False
61 | self._playing = True
62 | self._state = "on"
63 | self._source = ""
64 | self._source_list = []
65 | self._media_title = ""
66 |
67 | def update(self):
68 | SoundbarApi.device_update(self)
69 |
70 | @property
71 | def unique_id(self) -> str | None:
72 | return f"SmartThings_Soundbar_{self._device_id}"
73 |
74 | def turn_off(self):
75 | arg = ""
76 | cmdtype = "switch_off"
77 | SoundbarApi.send_command(self, arg, cmdtype)
78 |
79 | def turn_on(self):
80 | arg = ""
81 | cmdtype = "switch_on"
82 | SoundbarApi.send_command(self, arg, cmdtype)
83 |
84 | def set_volume_level(self, arg, cmdtype="setvolume"):
85 | SoundbarApi.send_command(self, arg, cmdtype)
86 |
87 | def mute_volume(self, mute, cmdtype="audiomute"):
88 | SoundbarApi.send_command(self, mute, cmdtype)
89 |
90 | def volume_up(self, cmdtype="stepvolume"):
91 | arg = "up"
92 | SoundbarApi.send_command(self, arg, cmdtype)
93 |
94 | def volume_down(self, cmdtype="stepvolume"):
95 | arg = ""
96 | SoundbarApi.send_command(self, arg, cmdtype)
97 |
98 | def select_source(self, source, cmdtype="selectsource"):
99 | SoundbarApi.send_command(self, source, cmdtype)
100 |
101 | def select_sound_mode(self, sound_mode):
102 | SoundbarApi.send_command(self, sound_mode, "selectsoundmode")
103 |
104 | @property
105 | def device_class(self):
106 | return MediaPlayerDeviceClass.SPEAKER
107 |
108 | @property
109 | def supported_features(self):
110 | return SUPPORT_SMARTTHINGS_SOUNDBAR
111 |
112 | @property
113 | def name(self):
114 | return self._name
115 |
116 | @property
117 | def media_title(self):
118 | return self._media_title
119 |
120 | def media_play(self):
121 | arg = ""
122 | cmdtype = "play"
123 | SoundbarApi.send_command(self, arg, cmdtype)
124 |
125 | def media_pause(self):
126 | arg = ""
127 | cmdtype = "pause"
128 | SoundbarApi.send_command(self, arg, cmdtype)
129 |
130 | @property
131 | def state(self):
132 | return self._state
133 |
134 | @property
135 | def is_volume_muted(self):
136 | return self._muted
137 |
138 | @property
139 | def volume_level(self):
140 | return self._volume
141 |
142 | @property
143 | def source(self):
144 | return self._source
145 |
146 | @property
147 | def source_list(self):
148 | return self._source_list
149 |
--------------------------------------------------------------------------------
/hacs.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "SmartThings Soundbar",
3 | "render_readme": true,
4 | "zip_release": true,
5 | "filename": "smartthings_soundbar.zip"
6 | }
--------------------------------------------------------------------------------