mirror of
https://github.com/home-assistant/supervisor.git
synced 2025-07-24 09:36:31 +00:00
commit
b9496e0972
22
API.md
22
API.md
@ -863,6 +863,19 @@ return:
|
||||
"version": "1",
|
||||
"latest_version": "2",
|
||||
"audio": {
|
||||
"card": [
|
||||
{
|
||||
"name": "...",
|
||||
"driver": "...",
|
||||
"profiles": [
|
||||
{
|
||||
"name": "...",
|
||||
"description": "...",
|
||||
"active": false
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"input": [
|
||||
{
|
||||
"name": "...",
|
||||
@ -931,6 +944,15 @@ return:
|
||||
}
|
||||
```
|
||||
|
||||
- POST `/audio/profile`
|
||||
|
||||
```json
|
||||
{
|
||||
"card": "...",
|
||||
"name": "..."
|
||||
}
|
||||
```
|
||||
|
||||
- GET `/audio/stats`
|
||||
|
||||
```json
|
||||
|
@ -10,7 +10,7 @@ gitpython==3.1.0
|
||||
jinja2==2.11.1
|
||||
packaging==20.1
|
||||
ptvsd==4.3.2
|
||||
pulsectl==20.2.2
|
||||
pulsectl==20.2.4
|
||||
pytz==2019.3
|
||||
pyudev==0.22.0
|
||||
ruamel.yaml==0.15.100
|
||||
|
@ -117,8 +117,11 @@ function init_dbus() {
|
||||
mkdir -p /var/lib/dbus
|
||||
cp -f /etc/machine-id /var/lib/dbus/machine-id
|
||||
|
||||
# run
|
||||
# cleanups
|
||||
mkdir -p /run/dbus
|
||||
rm -f /run/dbus/pid
|
||||
|
||||
# run
|
||||
dbus-daemon --system --print-address
|
||||
}
|
||||
|
||||
|
@ -329,6 +329,7 @@ class RestAPI(CoreSysAttributes):
|
||||
web.post("/audio/update", api_audio.update),
|
||||
web.post("/audio/restart", api_audio.restart),
|
||||
web.post("/audio/reload", api_audio.reload),
|
||||
web.post("/audio/profile", api_audio.set_profile),
|
||||
web.post("/audio/volume/{source}", api_audio.set_volume),
|
||||
web.post("/audio/default/{source}", api_audio.set_default),
|
||||
]
|
||||
|
@ -11,6 +11,7 @@ from ..const import (
|
||||
ATTR_AUDIO,
|
||||
ATTR_BLK_READ,
|
||||
ATTR_BLK_WRITE,
|
||||
ATTR_CARD,
|
||||
ATTR_CPU_PERCENT,
|
||||
ATTR_HOST,
|
||||
ATTR_INPUT,
|
||||
@ -28,7 +29,7 @@ from ..const import (
|
||||
)
|
||||
from ..coresys import CoreSysAttributes
|
||||
from ..exceptions import APIError
|
||||
from ..host.sound import SourceType
|
||||
from ..host.sound import StreamType
|
||||
from .utils import api_process, api_process_raw, api_validate
|
||||
|
||||
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
||||
@ -44,6 +45,10 @@ SCHEMA_VOLUME = vol.Schema(
|
||||
|
||||
SCHEMA_DEFAULT = vol.Schema({vol.Required(ATTR_NAME): vol.Coerce(str)})
|
||||
|
||||
SCHEMA_PROFILE = vol.Schema(
|
||||
{vol.Required(ATTR_CARD): vol.Coerce(str), vol.Required(ATTR_NAME): vol.Coerce(str)}
|
||||
)
|
||||
|
||||
|
||||
class APIAudio(CoreSysAttributes):
|
||||
"""Handle RESTful API for Audio functions."""
|
||||
@ -56,13 +61,12 @@ class APIAudio(CoreSysAttributes):
|
||||
ATTR_LATEST_VERSION: self.sys_audio.latest_version,
|
||||
ATTR_HOST: str(self.sys_docker.network.audio),
|
||||
ATTR_AUDIO: {
|
||||
ATTR_CARD: [attr.asdict(card) for card in self.sys_host.sound.cards],
|
||||
ATTR_INPUT: [
|
||||
attr.asdict(profile)
|
||||
for profile in self.sys_host.sound.input_profiles
|
||||
attr.asdict(stream) for stream in self.sys_host.sound.inputs
|
||||
],
|
||||
ATTR_OUTPUT: [
|
||||
attr.asdict(profile)
|
||||
for profile in self.sys_host.sound.output_profiles
|
||||
attr.asdict(stream) for stream in self.sys_host.sound.outputs
|
||||
],
|
||||
},
|
||||
}
|
||||
@ -110,8 +114,8 @@ class APIAudio(CoreSysAttributes):
|
||||
|
||||
@api_process
|
||||
async def set_volume(self, request: web.Request) -> None:
|
||||
"""Set Audio information."""
|
||||
source: SourceType = SourceType(request.match_info.get("source"))
|
||||
"""Set audio volume on stream."""
|
||||
source: StreamType = StreamType(request.match_info.get("source"))
|
||||
body = await api_validate(SCHEMA_VOLUME, request)
|
||||
|
||||
await asyncio.shield(
|
||||
@ -120,8 +124,17 @@ class APIAudio(CoreSysAttributes):
|
||||
|
||||
@api_process
|
||||
async def set_default(self, request: web.Request) -> None:
|
||||
"""Set Audio default sources."""
|
||||
source: SourceType = SourceType(request.match_info.get("source"))
|
||||
"""Set audio default stream."""
|
||||
source: StreamType = StreamType(request.match_info.get("source"))
|
||||
body = await api_validate(SCHEMA_DEFAULT, request)
|
||||
|
||||
await asyncio.shield(self.sys_host.sound.set_default(source, body[ATTR_NAME]))
|
||||
|
||||
@api_process
|
||||
async def set_profile(self, request: web.Request) -> None:
|
||||
"""Set audio default sources."""
|
||||
body = await api_validate(SCHEMA_DEFAULT, request)
|
||||
|
||||
await asyncio.shield(
|
||||
self.sys_host.sound.set_profile(body[ATTR_CARD], body[ATTR_NAME])
|
||||
)
|
||||
|
@ -42,11 +42,11 @@ class APIHardware(CoreSysAttributes):
|
||||
ATTR_AUDIO: {
|
||||
ATTR_INPUT: {
|
||||
profile.name: profile.description
|
||||
for profile in self.sys_host.sound.input_profiles
|
||||
for profile in self.sys_host.sound.inputs
|
||||
},
|
||||
ATTR_OUTPUT: {
|
||||
profile.name: profile.description
|
||||
for profile in self.sys_host.sound.output_profiles
|
||||
for profile in self.sys_host.sound.outputs
|
||||
},
|
||||
}
|
||||
}
|
||||
|
2
supervisor/api/panel/a1ebfa0a88593a3b571c.worker.js
Normal file
2
supervisor/api/panel/a1ebfa0a88593a3b571c.worker.js
Normal file
File diff suppressed because one or more lines are too long
BIN
supervisor/api/panel/a1ebfa0a88593a3b571c.worker.js.gz
Normal file
BIN
supervisor/api/panel/a1ebfa0a88593a3b571c.worker.js.gz
Normal file
Binary file not shown.
1
supervisor/api/panel/a1ebfa0a88593a3b571c.worker.js.map
Normal file
1
supervisor/api/panel/a1ebfa0a88593a3b571c.worker.js.map
Normal file
File diff suppressed because one or more lines are too long
2
supervisor/api/panel/chunk.1a25d23325fed5a4d90b.js
Normal file
2
supervisor/api/panel/chunk.1a25d23325fed5a4d90b.js
Normal file
File diff suppressed because one or more lines are too long
BIN
supervisor/api/panel/chunk.1a25d23325fed5a4d90b.js.gz
Normal file
BIN
supervisor/api/panel/chunk.1a25d23325fed5a4d90b.js.gz
Normal file
Binary file not shown.
1
supervisor/api/panel/chunk.1a25d23325fed5a4d90b.js.map
Normal file
1
supervisor/api/panel/chunk.1a25d23325fed5a4d90b.js.map
Normal file
File diff suppressed because one or more lines are too long
2
supervisor/api/panel/chunk.26756b56961f7bf94974.js
Normal file
2
supervisor/api/panel/chunk.26756b56961f7bf94974.js
Normal file
@ -0,0 +1,2 @@
|
||||
(self.webpackJsonp=self.webpackJsonp||[]).push([[2],{177:function(e,r,n){"use strict";n.r(r),n.d(r,"codeMirror",function(){return c}),n.d(r,"codeMirrorCss",function(){return i});var a=n(54),o=n.n(a),s=n(170),t=(n(171),n(172),n(11));o.a.commands.save=function(e){Object(t.a)(e.getWrapperElement(),"editor-save")};var c=o.a,i=s.a}}]);
|
||||
//# sourceMappingURL=chunk.26756b56961f7bf94974.js.map
|
BIN
supervisor/api/panel/chunk.26756b56961f7bf94974.js.gz
Normal file
BIN
supervisor/api/panel/chunk.26756b56961f7bf94974.js.gz
Normal file
Binary file not shown.
1
supervisor/api/panel/chunk.26756b56961f7bf94974.js.map
Normal file
1
supervisor/api/panel/chunk.26756b56961f7bf94974.js.map
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"sources":["webpack:///./src/resources/codemirror.ts"],"names":["__webpack_require__","r","__webpack_exports__","d","codeMirror","codeMirrorCss","codemirror__WEBPACK_IMPORTED_MODULE_0__","codemirror__WEBPACK_IMPORTED_MODULE_0___default","n","codemirror_lib_codemirror_css__WEBPACK_IMPORTED_MODULE_1__","_common_dom_fire_event__WEBPACK_IMPORTED_MODULE_4__","_CodeMirror","commands","save","cm","fireEvent","getWrapperElement","_codeMirrorCss"],"mappings":"sFAAAA,EAAAC,EAAAC,GAAAF,EAAAG,EAAAD,EAAA,+BAAAE,IAAAJ,EAAAG,EAAAD,EAAA,kCAAAG,IAAA,IAAAC,EAAAN,EAAA,IAAAO,EAAAP,EAAAQ,EAAAF,GAAAG,EAAAT,EAAA,KAAAU,GAAAV,EAAA,KAAAA,EAAA,KAAAA,EAAA,KAQAW,IAAYC,SAASC,KAAO,SAACC,GAC3BC,YAAUD,EAAGE,oBAAqB,gBAE7B,IAAMZ,EAAkBO,IAClBN,EAAqBY","file":"chunk.26756b56961f7bf94974.js","sourcesContent":["// @ts-ignore\nimport _CodeMirror, { Editor } from \"codemirror\";\n// @ts-ignore\nimport _codeMirrorCss from \"codemirror/lib/codemirror.css\";\nimport \"codemirror/mode/yaml/yaml\";\nimport \"codemirror/mode/jinja2/jinja2\";\nimport { fireEvent } from \"../common/dom/fire_event\";\n\n_CodeMirror.commands.save = (cm: Editor) => {\n fireEvent(cm.getWrapperElement(), \"editor-save\");\n};\nexport const codeMirror: any = _CodeMirror;\nexport const codeMirrorCss: any = _codeMirrorCss;\n"],"sourceRoot":""}
|
3
supervisor/api/panel/chunk.26be881fcb628958e718.js
Normal file
3
supervisor/api/panel/chunk.26be881fcb628958e718.js
Normal file
File diff suppressed because one or more lines are too long
10
supervisor/api/panel/chunk.26be881fcb628958e718.js.LICENSE
Normal file
10
supervisor/api/panel/chunk.26be881fcb628958e718.js.LICENSE
Normal file
@ -0,0 +1,10 @@
|
||||
/**
|
||||
@license
|
||||
Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
|
||||
This code may only be used under the BSD style license found at
|
||||
http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
|
||||
http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
|
||||
found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
|
||||
part of the polymer project is also subject to an additional IP rights grant
|
||||
found at http://polymer.github.io/PATENTS.txt
|
||||
*/
|
BIN
supervisor/api/panel/chunk.26be881fcb628958e718.js.gz
Normal file
BIN
supervisor/api/panel/chunk.26be881fcb628958e718.js.gz
Normal file
Binary file not shown.
1
supervisor/api/panel/chunk.26be881fcb628958e718.js.map
Normal file
1
supervisor/api/panel/chunk.26be881fcb628958e718.js.map
Normal file
File diff suppressed because one or more lines are too long
2
supervisor/api/panel/chunk.35929da61d769e57c884.js
Normal file
2
supervisor/api/panel/chunk.35929da61d769e57c884.js
Normal file
File diff suppressed because one or more lines are too long
BIN
supervisor/api/panel/chunk.35929da61d769e57c884.js.gz
Normal file
BIN
supervisor/api/panel/chunk.35929da61d769e57c884.js.gz
Normal file
Binary file not shown.
1
supervisor/api/panel/chunk.35929da61d769e57c884.js.map
Normal file
1
supervisor/api/panel/chunk.35929da61d769e57c884.js.map
Normal file
@ -0,0 +1 @@
|
||||
{"version":3,"sources":["webpack:///./hassio/src/ingress-view/hassio-ingress-view.ts"],"names":["customElement","HassioIngressView","property","this","_addon","html","_templateObject2","name","ingress_url","_templateObject","changedProps","_get","_getPrototypeOf","prototype","call","has","addon","route","path","substr","oldRoute","get","oldAddon","undefined","_fetchData","_callee","addonSlug","_ref","_ref2","regeneratorRuntime","wrap","_context","prev","next","Promise","all","fetchHassioAddonInfo","hass","Error","createHassioSession","sent","_slicedToArray","ingress","t0","console","error","alert","message","history","back","stop","css","_templateObject3","LitElement"],"mappings":"snSAmBCA,YAAc,0CACTC,smBACHC,kEACAA,mEACAA,4EAED,WACE,OAAKC,KAAKC,OAMHC,YAAPC,IAC0BH,KAAKC,OAAOG,KACpBJ,KAAKC,OAAOI,aAPrBH,YAAPI,0CAYJ,SAAkBC,GAGhB,GAFAC,EAAAC,EApBEX,EAoBFY,WAAA,eAAAV,MAAAW,KAAAX,KAAmBO,GAEdA,EAAaK,IAAI,SAAtB,CAIA,IAAMC,EAAQb,KAAKc,MAAMC,KAAKC,OAAO,GAE/BC,EAAWV,EAAaW,IAAI,SAC5BC,EAAWF,EAAWA,EAASF,KAAKC,OAAO,QAAKI,EAElDP,GAASA,IAAUM,GACrBnB,KAAKqB,WAAWR,0FAIpB,SAAAS,EAAyBC,GAAzB,IAAAC,EAAAC,EAAAZ,EAAA,OAAAa,mBAAAC,KAAA,SAAAC,GAAA,cAAAA,EAAAC,KAAAD,EAAAE,MAAA,cAAAF,EAAAC,KAAA,EAAAD,EAAAE,KAAA,EAE0BC,QAAQC,IAAI,CAChCC,YAAqBjC,KAAKkC,KAAMX,GAAhC,MAAiD,WAC/C,MAAM,IAAIY,MAAM,iCAElBC,YAAoBpC,KAAKkC,MAAzB,MAAqC,WACnC,MAAM,IAAIC,MAAM,2CAPxB,UAAAX,EAAAI,EAAAS,KAAAZ,EAAAa,EAAAd,EAAA,IAEWX,EAFXY,EAAA,IAWec,QAXf,CAAAX,EAAAE,KAAA,cAYY,IAAIK,MAAM,wCAZtB,OAeInC,KAAKC,OAASY,EAflBe,EAAAE,KAAA,iBAAAF,EAAAC,KAAA,GAAAD,EAAAY,GAAAZ,EAAA,SAkBIa,QAAQC,MAARd,EAAAY,IACAG,MAAMf,EAAAY,GAAII,SAAW,mCACrBC,QAAQC,OApBZ,yBAAAlB,EAAAmB,SAAAzB,EAAAtB,KAAA,yRAwBA,WACE,OAAOgD,YAAPC,UA7D4BC","file":"chunk.35929da61d769e57c884.js","sourcesContent":["import {\n LitElement,\n customElement,\n property,\n TemplateResult,\n html,\n PropertyValues,\n CSSResult,\n css,\n} from \"lit-element\";\nimport { HomeAssistant, Route } from \"../../../src/types\";\nimport { createHassioSession } from \"../../../src/data/hassio/supervisor\";\nimport {\n HassioAddonDetails,\n fetchHassioAddonInfo,\n} from \"../../../src/data/hassio/addon\";\nimport \"../../../src/layouts/hass-loading-screen\";\nimport \"../../../src/layouts/hass-subpage\";\n\n@customElement(\"hassio-ingress-view\")\nclass HassioIngressView extends LitElement {\n @property() public hass!: HomeAssistant;\n @property() public route!: Route;\n @property() private _addon?: HassioAddonDetails;\n\n protected render(): TemplateResult {\n if (!this._addon) {\n return html`\n <hass-loading-screen></hass-loading-screen>\n `;\n }\n\n return html`\n <hass-subpage .header=${this._addon.name} hassio>\n <iframe src=${this._addon.ingress_url}></iframe>\n </hass-subpage>\n `;\n }\n\n protected updated(changedProps: PropertyValues) {\n super.firstUpdated(changedProps);\n\n if (!changedProps.has(\"route\")) {\n return;\n }\n\n const addon = this.route.path.substr(1);\n\n const oldRoute = changedProps.get(\"route\") as this[\"route\"] | undefined;\n const oldAddon = oldRoute ? oldRoute.path.substr(1) : undefined;\n\n if (addon && addon !== oldAddon) {\n this._fetchData(addon);\n }\n }\n\n private async _fetchData(addonSlug: string) {\n try {\n const [addon] = await Promise.all([\n fetchHassioAddonInfo(this.hass, addonSlug).catch(() => {\n throw new Error(\"Failed to fetch add-on info\");\n }),\n createHassioSession(this.hass).catch(() => {\n throw new Error(\"Failed to create an ingress session\");\n }),\n ]);\n\n if (!addon.ingress) {\n throw new Error(\"This add-on does not support ingress\");\n }\n\n this._addon = addon;\n } catch (err) {\n // tslint:disable-next-line\n console.error(err);\n alert(err.message || \"Unknown error starting ingress.\");\n history.back();\n }\n }\n\n static get styles(): CSSResult {\n return css`\n iframe {\n display: block;\n width: 100%;\n height: 100%;\n border: 0;\n }\n paper-icon-button {\n color: var(--text-primary-color);\n }\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n \"hassio-ingress-view\": HassioIngressView;\n }\n}\n"],"sourceRoot":""}
|
3
supervisor/api/panel/chunk.541d0b76b660d8646074.js
Normal file
3
supervisor/api/panel/chunk.541d0b76b660d8646074.js
Normal file
File diff suppressed because one or more lines are too long
189
supervisor/api/panel/chunk.541d0b76b660d8646074.js.LICENSE
Normal file
189
supervisor/api/panel/chunk.541d0b76b660d8646074.js.LICENSE
Normal file
@ -0,0 +1,189 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
|
||||
* This code may only be used under the BSD style license found at
|
||||
* http://polymer.github.io/LICENSE.txt
|
||||
* The complete set of authors may be found at
|
||||
* http://polymer.github.io/AUTHORS.txt
|
||||
* The complete set of contributors may be found at
|
||||
* http://polymer.github.io/CONTRIBUTORS.txt
|
||||
* Code distributed by Google as part of the polymer project is also
|
||||
* subject to an additional IP rights grant found at
|
||||
* http://polymer.github.io/PATENTS.txt
|
||||
*/
|
||||
|
||||
/**
|
||||
@license
|
||||
Copyright (c) 2019 The Polymer Project Authors. All rights reserved.
|
||||
This code may only be used under the BSD style license found at
|
||||
http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
|
||||
http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
|
||||
found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
|
||||
part of the polymer project is also subject to an additional IP rights grant
|
||||
found at http://polymer.github.io/PATENTS.txt
|
||||
*/
|
||||
|
||||
/**
|
||||
@license
|
||||
Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
|
||||
This code may only be used under the BSD style license found at
|
||||
http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
|
||||
http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
|
||||
found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
|
||||
part of the polymer project is also subject to an additional IP rights grant
|
||||
found at http://polymer.github.io/PATENTS.txt
|
||||
*/
|
||||
|
||||
/**
|
||||
@license
|
||||
Copyright 2018 Google Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
@license
|
||||
Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
|
||||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||||
Code distributed by Google as part of the polymer project is also
|
||||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||||
*/
|
||||
|
||||
/**
|
||||
@license
|
||||
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
|
||||
This code may only be used under the BSD style license found at
|
||||
http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
|
||||
http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
|
||||
found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
|
||||
part of the polymer project is also subject to an additional IP rights grant
|
||||
found at http://polymer.github.io/PATENTS.txt
|
||||
*/
|
||||
|
||||
/*! *****************************************************************************
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
|
||||
this file except in compliance with the License. You may obtain a copy of the
|
||||
License at http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
|
||||
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
|
||||
MERCHANTABLITY OR NON-INFRINGEMENT.
|
||||
|
||||
See the Apache Version 2.0 License for specific language governing permissions
|
||||
and limitations under the License.
|
||||
***************************************************************************** */
|
||||
|
||||
/**
|
||||
* @license
|
||||
* Copyright (c) 2018 The Polymer Project Authors. All rights reserved.
|
||||
* This code may only be used under the BSD style license found at
|
||||
* http://polymer.github.io/LICENSE.txt
|
||||
* The complete set of authors may be found at
|
||||
* http://polymer.github.io/AUTHORS.txt
|
||||
* The complete set of contributors may be found at
|
||||
* http://polymer.github.io/CONTRIBUTORS.txt
|
||||
* Code distributed by Google as part of the polymer project is also
|
||||
* subject to an additional IP rights grant found at
|
||||
* http://polymer.github.io/PATENTS.txt
|
||||
*/
|
||||
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2019 Google Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2016 Google Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
@license
|
||||
Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
|
||||
This code may only be used under the BSD style license found at
|
||||
http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
|
||||
http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
|
||||
found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
|
||||
part of the polymer project is also subject to an additional IP rights grant
|
||||
found at http://polymer.github.io/PATENTS.txt
|
||||
*/
|
||||
|
||||
/**
|
||||
@license
|
||||
Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
|
||||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||||
Code distributed by Google as part of the polymer project is also
|
||||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||||
*/
|
||||
|
||||
/**
|
||||
@license
|
||||
Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
|
||||
This code may only be used under the BSD style license found at
|
||||
http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
|
||||
http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
|
||||
found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
|
||||
part of the polymer project is also subject to an additional IP rights grant
|
||||
found at http://polymer.github.io/PATENTS.txt
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Fuse.js v3.4.4 - Lightweight fuzzy-search (http://fusejs.io)
|
||||
*
|
||||
* Copyright (c) 2012-2017 Kirollos Risk (http://kiro.me)
|
||||
* All Rights Reserved. Apache Software License 2.0
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*/
|
BIN
supervisor/api/panel/chunk.541d0b76b660d8646074.js.gz
Normal file
BIN
supervisor/api/panel/chunk.541d0b76b660d8646074.js.gz
Normal file
Binary file not shown.
1
supervisor/api/panel/chunk.541d0b76b660d8646074.js.map
Normal file
1
supervisor/api/panel/chunk.541d0b76b660d8646074.js.map
Normal file
File diff suppressed because one or more lines are too long
2
supervisor/api/panel/chunk.5e32280d595be3742226.js
Normal file
2
supervisor/api/panel/chunk.5e32280d595be3742226.js
Normal file
File diff suppressed because one or more lines are too long
BIN
supervisor/api/panel/chunk.5e32280d595be3742226.js.gz
Normal file
BIN
supervisor/api/panel/chunk.5e32280d595be3742226.js.gz
Normal file
Binary file not shown.
1
supervisor/api/panel/chunk.5e32280d595be3742226.js.map
Normal file
1
supervisor/api/panel/chunk.5e32280d595be3742226.js.map
Normal file
File diff suppressed because one or more lines are too long
2
supervisor/api/panel/chunk.70a435e100109291f210.js
Normal file
2
supervisor/api/panel/chunk.70a435e100109291f210.js
Normal file
File diff suppressed because one or more lines are too long
BIN
supervisor/api/panel/chunk.70a435e100109291f210.js.gz
Normal file
BIN
supervisor/api/panel/chunk.70a435e100109291f210.js.gz
Normal file
Binary file not shown.
1
supervisor/api/panel/chunk.70a435e100109291f210.js.map
Normal file
1
supervisor/api/panel/chunk.70a435e100109291f210.js.map
Normal file
File diff suppressed because one or more lines are too long
3
supervisor/api/panel/chunk.9339f70c8bfe2cbef5ad.js
Normal file
3
supervisor/api/panel/chunk.9339f70c8bfe2cbef5ad.js
Normal file
File diff suppressed because one or more lines are too long
20
supervisor/api/panel/chunk.9339f70c8bfe2cbef5ad.js.LICENSE
Normal file
20
supervisor/api/panel/chunk.9339f70c8bfe2cbef5ad.js.LICENSE
Normal file
@ -0,0 +1,20 @@
|
||||
/**
|
||||
@license
|
||||
Copyright (c) 2017 The Polymer Project Authors. All rights reserved.
|
||||
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||||
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||||
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||||
Code distributed by Google as part of the polymer project is also
|
||||
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||||
*/
|
||||
|
||||
/**
|
||||
@license
|
||||
Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
|
||||
This code may only be used under the BSD style license found at
|
||||
http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
|
||||
http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
|
||||
found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
|
||||
part of the polymer project is also subject to an additional IP rights grant
|
||||
found at http://polymer.github.io/PATENTS.txt
|
||||
*/
|
BIN
supervisor/api/panel/chunk.9339f70c8bfe2cbef5ad.js.gz
Normal file
BIN
supervisor/api/panel/chunk.9339f70c8bfe2cbef5ad.js.gz
Normal file
Binary file not shown.
1
supervisor/api/panel/chunk.9339f70c8bfe2cbef5ad.js.map
Normal file
1
supervisor/api/panel/chunk.9339f70c8bfe2cbef5ad.js.map
Normal file
File diff suppressed because one or more lines are too long
3
supervisor/api/panel/chunk.93a8a2e1dbccae0e07fa.js
Normal file
3
supervisor/api/panel/chunk.93a8a2e1dbccae0e07fa.js
Normal file
File diff suppressed because one or more lines are too long
28
supervisor/api/panel/chunk.93a8a2e1dbccae0e07fa.js.LICENSE
Normal file
28
supervisor/api/panel/chunk.93a8a2e1dbccae0e07fa.js.LICENSE
Normal file
@ -0,0 +1,28 @@
|
||||
/**
|
||||
@license
|
||||
Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
|
||||
This code may only be used under the BSD style license found at
|
||||
http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
|
||||
http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
|
||||
found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
|
||||
part of the polymer project is also subject to an additional IP rights grant
|
||||
found at http://polymer.github.io/PATENTS.txt
|
||||
*/
|
||||
|
||||
/*!
|
||||
* The buffer module from node.js, for the browser.
|
||||
*
|
||||
* @author Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
/**
|
||||
@license
|
||||
Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
|
||||
This code may only be used under the BSD style license found at
|
||||
http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
|
||||
http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
|
||||
found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
|
||||
part of the polymer project is also subject to an additional IP rights grant
|
||||
found at http://polymer.github.io/PATENTS.txt
|
||||
*/
|
BIN
supervisor/api/panel/chunk.93a8a2e1dbccae0e07fa.js.gz
Normal file
BIN
supervisor/api/panel/chunk.93a8a2e1dbccae0e07fa.js.gz
Normal file
Binary file not shown.
1
supervisor/api/panel/chunk.93a8a2e1dbccae0e07fa.js.map
Normal file
1
supervisor/api/panel/chunk.93a8a2e1dbccae0e07fa.js.map
Normal file
File diff suppressed because one or more lines are too long
2
supervisor/api/panel/chunk.a9cf4ae83af78188e158.js
Normal file
2
supervisor/api/panel/chunk.a9cf4ae83af78188e158.js
Normal file
File diff suppressed because one or more lines are too long
BIN
supervisor/api/panel/chunk.a9cf4ae83af78188e158.js.gz
Normal file
BIN
supervisor/api/panel/chunk.a9cf4ae83af78188e158.js.gz
Normal file
Binary file not shown.
1
supervisor/api/panel/chunk.a9cf4ae83af78188e158.js.map
Normal file
1
supervisor/api/panel/chunk.a9cf4ae83af78188e158.js.map
Normal file
File diff suppressed because one or more lines are too long
2
supervisor/api/panel/chunk.af76a4db9eb1e2862aae.js
Normal file
2
supervisor/api/panel/chunk.af76a4db9eb1e2862aae.js
Normal file
File diff suppressed because one or more lines are too long
BIN
supervisor/api/panel/chunk.af76a4db9eb1e2862aae.js.gz
Normal file
BIN
supervisor/api/panel/chunk.af76a4db9eb1e2862aae.js.gz
Normal file
Binary file not shown.
1
supervisor/api/panel/chunk.af76a4db9eb1e2862aae.js.map
Normal file
1
supervisor/api/panel/chunk.af76a4db9eb1e2862aae.js.map
Normal file
File diff suppressed because one or more lines are too long
3
supervisor/api/panel/chunk.b2a892416a728ca06e9a.js
Normal file
3
supervisor/api/panel/chunk.b2a892416a728ca06e9a.js
Normal file
File diff suppressed because one or more lines are too long
10
supervisor/api/panel/chunk.b2a892416a728ca06e9a.js.LICENSE
Normal file
10
supervisor/api/panel/chunk.b2a892416a728ca06e9a.js.LICENSE
Normal file
@ -0,0 +1,10 @@
|
||||
/**
|
||||
@license
|
||||
Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
|
||||
This code may only be used under the BSD style license found at
|
||||
http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
|
||||
http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
|
||||
found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
|
||||
part of the polymer project is also subject to an additional IP rights grant
|
||||
found at http://polymer.github.io/PATENTS.txt
|
||||
*/
|
BIN
supervisor/api/panel/chunk.b2a892416a728ca06e9a.js.gz
Normal file
BIN
supervisor/api/panel/chunk.b2a892416a728ca06e9a.js.gz
Normal file
Binary file not shown.
1
supervisor/api/panel/chunk.b2a892416a728ca06e9a.js.map
Normal file
1
supervisor/api/panel/chunk.b2a892416a728ca06e9a.js.map
Normal file
File diff suppressed because one or more lines are too long
3
supervisor/api/panel/chunk.b6e61f8340c32e6904ca.js
Normal file
3
supervisor/api/panel/chunk.b6e61f8340c32e6904ca.js
Normal file
File diff suppressed because one or more lines are too long
16
supervisor/api/panel/chunk.b6e61f8340c32e6904ca.js.LICENSE
Normal file
16
supervisor/api/panel/chunk.b6e61f8340c32e6904ca.js.LICENSE
Normal file
@ -0,0 +1,16 @@
|
||||
/**
|
||||
@license
|
||||
Copyright 2018 Google Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
BIN
supervisor/api/panel/chunk.b6e61f8340c32e6904ca.js.gz
Normal file
BIN
supervisor/api/panel/chunk.b6e61f8340c32e6904ca.js.gz
Normal file
Binary file not shown.
1
supervisor/api/panel/chunk.b6e61f8340c32e6904ca.js.map
Normal file
1
supervisor/api/panel/chunk.b6e61f8340c32e6904ca.js.map
Normal file
File diff suppressed because one or more lines are too long
3
supervisor/api/panel/chunk.ea2041e4c67d4c05b0dd.js
Normal file
3
supervisor/api/panel/chunk.ea2041e4c67d4c05b0dd.js
Normal file
File diff suppressed because one or more lines are too long
10
supervisor/api/panel/chunk.ea2041e4c67d4c05b0dd.js.LICENSE
Normal file
10
supervisor/api/panel/chunk.ea2041e4c67d4c05b0dd.js.LICENSE
Normal file
@ -0,0 +1,10 @@
|
||||
/**
|
||||
@license
|
||||
Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
|
||||
This code may only be used under the BSD style license found at
|
||||
http://polymer.github.io/LICENSE.txt The complete set of authors may be found at
|
||||
http://polymer.github.io/AUTHORS.txt The complete set of contributors may be
|
||||
found at http://polymer.github.io/CONTRIBUTORS.txt Code distributed by Google as
|
||||
part of the polymer project is also subject to an additional IP rights grant
|
||||
found at http://polymer.github.io/PATENTS.txt
|
||||
*/
|
BIN
supervisor/api/panel/chunk.ea2041e4c67d4c05b0dd.js.gz
Normal file
BIN
supervisor/api/panel/chunk.ea2041e4c67d4c05b0dd.js.gz
Normal file
Binary file not shown.
1
supervisor/api/panel/chunk.ea2041e4c67d4c05b0dd.js.map
Normal file
1
supervisor/api/panel/chunk.ea2041e4c67d4c05b0dd.js.map
Normal file
File diff suppressed because one or more lines are too long
@ -1,2 +1,2 @@
|
||||
!function(e){function n(n){for(var t,o,a=n[0],i=n[1],c=0,d=[];c<a.length;c++)o=a[c],Object.prototype.hasOwnProperty.call(r,o)&&r[o]&&d.push(r[o][0]),r[o]=0;for(t in i)Object.prototype.hasOwnProperty.call(i,t)&&(e[t]=i[t]);for(u&&u(n);d.length;)d.shift()()}var t={},r={6:0};function o(n){if(t[n])return t[n].exports;var r=t[n]={i:n,l:!1,exports:{}};return e[n].call(r.exports,r,r.exports,o),r.l=!0,r.exports}o.e=function(e){var n=[],t=r[e];if(0!==t)if(t)n.push(t[2]);else{var a=new Promise(function(n,o){t=r[e]=[n,o]});n.push(t[2]=a);var i,c=document.createElement("script");c.charset="utf-8",c.timeout=120,o.nc&&c.setAttribute("nonce",o.nc),c.src=function(e){return o.p+"chunk."+{0:"87b1d37fc9b8a6f7e2a6",1:"e46c606dd9100816af4e",2:"92a11ac1b80e0d7839d2",3:"429840c83fad61bc51a8",4:"715824f4764bdbe425b1",5:"9d371c8143226d4eaaee",7:"43e40fd69686ad51301d",8:"0b82745c7bdffe5c1404",9:"990ee58006b248f55d23",10:"4d45ee0a3d852768f97e",11:"b60200a57d6f63941b30",12:"b2dce600432c76a53d8c",13:"8527374a266cecf93aa9",14:"f49e500cf58ea310d452",15:"d4931d72592ad48ba2be"}[e]+".js"}(e);var u=new Error;i=function(n){c.onerror=c.onload=null,clearTimeout(d);var t=r[e];if(0!==t){if(t){var o=n&&("load"===n.type?"missing":n.type),a=n&&n.target&&n.target.src;u.message="Loading chunk "+e+" failed.\n("+o+": "+a+")",u.name="ChunkLoadError",u.type=o,u.request=a,t[1](u)}r[e]=void 0}};var d=setTimeout(function(){i({type:"timeout",target:c})},12e4);c.onerror=c.onload=i,document.head.appendChild(c)}return Promise.all(n)},o.m=e,o.c=t,o.d=function(e,n,t){o.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:t})},o.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.t=function(e,n){if(1&n&&(e=o(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(o.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var r in e)o.d(t,r,function(n){return e[n]}.bind(null,r));return t},o.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(n,"a",n),n},o.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},o.p="/api/hassio/app/",o.oe=function(e){throw console.error(e),e};var a=self.webpackJsonp=self.webpackJsonp||[],i=a.push.bind(a);a.push=n,a=a.slice();for(var c=0;c<a.length;c++)n(a[c]);var u=i;o(o.s=0)}([function(e,n,t){window.loadES5Adapter().then(function(){t.e(12).then(t.t.bind(null,1,7)),Promise.all([t.e(1),t.e(8)]).then(t.bind(null,3)),Promise.all([t.e(1),t.e(15),t.e(10)]).then(t.bind(null,2))});var r=document.createElement("style");r.innerHTML="\nbody {\n font-family: Roboto, sans-serif;\n -moz-osx-font-smoothing: grayscale;\n -webkit-font-smoothing: antialiased;\n font-weight: 400;\n margin: 0;\n padding: 0;\n height: 100vh;\n}\n",document.head.appendChild(r)}]);
|
||||
!function(e){function n(n){for(var t,o,a=n[0],i=n[1],c=0,f=[];c<a.length;c++)o=a[c],Object.prototype.hasOwnProperty.call(r,o)&&r[o]&&f.push(r[o][0]),r[o]=0;for(t in i)Object.prototype.hasOwnProperty.call(i,t)&&(e[t]=i[t]);for(u&&u(n);f.length;)f.shift()()}var t={},r={6:0};function o(n){if(t[n])return t[n].exports;var r=t[n]={i:n,l:!1,exports:{}};return e[n].call(r.exports,r,r.exports,o),r.l=!0,r.exports}o.e=function(e){var n=[],t=r[e];if(0!==t)if(t)n.push(t[2]);else{var a=new Promise(function(n,o){t=r[e]=[n,o]});n.push(t[2]=a);var i,c=document.createElement("script");c.charset="utf-8",c.timeout=120,o.nc&&c.setAttribute("nonce",o.nc),c.src=function(e){return o.p+"chunk."+{0:"b6e61f8340c32e6904ca",1:"9339f70c8bfe2cbef5ad",2:"26756b56961f7bf94974",3:"b2a892416a728ca06e9a",4:"26be881fcb628958e718",5:"ea2041e4c67d4c05b0dd",7:"1a25d23325fed5a4d90b",8:"af76a4db9eb1e2862aae",9:"35929da61d769e57c884",10:"5e32280d595be3742226",11:"a9cf4ae83af78188e158",12:"b2dce600432c76a53d8c",13:"70a435e100109291f210",14:"93a8a2e1dbccae0e07fa",15:"541d0b76b660d8646074"}[e]+".js"}(e);var u=new Error;i=function(n){c.onerror=c.onload=null,clearTimeout(f);var t=r[e];if(0!==t){if(t){var o=n&&("load"===n.type?"missing":n.type),a=n&&n.target&&n.target.src;u.message="Loading chunk "+e+" failed.\n("+o+": "+a+")",u.name="ChunkLoadError",u.type=o,u.request=a,t[1](u)}r[e]=void 0}};var f=setTimeout(function(){i({type:"timeout",target:c})},12e4);c.onerror=c.onload=i,document.head.appendChild(c)}return Promise.all(n)},o.m=e,o.c=t,o.d=function(e,n,t){o.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:t})},o.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.t=function(e,n){if(1&n&&(e=o(e)),8&n)return e;if(4&n&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(o.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&n&&"string"!=typeof e)for(var r in e)o.d(t,r,function(n){return e[n]}.bind(null,r));return t},o.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return o.d(n,"a",n),n},o.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},o.p="/api/hassio/app/",o.oe=function(e){throw console.error(e),e};var a=self.webpackJsonp=self.webpackJsonp||[],i=a.push.bind(a);a.push=n,a=a.slice();for(var c=0;c<a.length;c++)n(a[c]);var u=i;o(o.s=0)}([function(e,n,t){window.loadES5Adapter().then(function(){t.e(12).then(t.t.bind(null,1,7)),Promise.all([t.e(1),t.e(8)]).then(t.bind(null,3)),Promise.all([t.e(1),t.e(15),t.e(10)]).then(t.bind(null,2))});var r=document.createElement("style");r.innerHTML="\nbody {\n font-family: Roboto, sans-serif;\n -moz-osx-font-smoothing: grayscale;\n -webkit-font-smoothing: antialiased;\n font-weight: 400;\n margin: 0;\n padding: 0;\n height: 100vh;\n}\n",document.head.appendChild(r)}]);
|
||||
//# sourceMappingURL=entrypoint.js.map
|
Binary file not shown.
File diff suppressed because one or more lines are too long
@ -1,43 +1,43 @@
|
||||
{
|
||||
"vendors~confirmation~hassio-addon-view.js": "/api/hassio/app/chunk.87b1d37fc9b8a6f7e2a6.js",
|
||||
"vendors~confirmation~hassio-addon-view.js.map": "/api/hassio/app/chunk.87b1d37fc9b8a6f7e2a6.js.map",
|
||||
"vendors~hassio-icons~hassio-main.js": "/api/hassio/app/chunk.e46c606dd9100816af4e.js",
|
||||
"vendors~hassio-icons~hassio-main.js.map": "/api/hassio/app/chunk.e46c606dd9100816af4e.js.map",
|
||||
"codemirror.js": "/api/hassio/app/chunk.92a11ac1b80e0d7839d2.js",
|
||||
"codemirror.js.map": "/api/hassio/app/chunk.92a11ac1b80e0d7839d2.js.map",
|
||||
"confirmation.js": "/api/hassio/app/chunk.429840c83fad61bc51a8.js",
|
||||
"confirmation.js.map": "/api/hassio/app/chunk.429840c83fad61bc51a8.js.map",
|
||||
"dialog-hassio-markdown.js": "/api/hassio/app/chunk.715824f4764bdbe425b1.js",
|
||||
"dialog-hassio-markdown.js.map": "/api/hassio/app/chunk.715824f4764bdbe425b1.js.map",
|
||||
"dialog-hassio-snapshot.js": "/api/hassio/app/chunk.9d371c8143226d4eaaee.js",
|
||||
"dialog-hassio-snapshot.js.map": "/api/hassio/app/chunk.9d371c8143226d4eaaee.js.map",
|
||||
"vendors~confirmation~hassio-addon-view.js": "/api/hassio/app/chunk.b6e61f8340c32e6904ca.js",
|
||||
"vendors~confirmation~hassio-addon-view.js.map": "/api/hassio/app/chunk.b6e61f8340c32e6904ca.js.map",
|
||||
"vendors~hassio-icons~hassio-main.js": "/api/hassio/app/chunk.9339f70c8bfe2cbef5ad.js",
|
||||
"vendors~hassio-icons~hassio-main.js.map": "/api/hassio/app/chunk.9339f70c8bfe2cbef5ad.js.map",
|
||||
"codemirror.js": "/api/hassio/app/chunk.26756b56961f7bf94974.js",
|
||||
"codemirror.js.map": "/api/hassio/app/chunk.26756b56961f7bf94974.js.map",
|
||||
"confirmation.js": "/api/hassio/app/chunk.b2a892416a728ca06e9a.js",
|
||||
"confirmation.js.map": "/api/hassio/app/chunk.b2a892416a728ca06e9a.js.map",
|
||||
"dialog-hassio-markdown.js": "/api/hassio/app/chunk.26be881fcb628958e718.js",
|
||||
"dialog-hassio-markdown.js.map": "/api/hassio/app/chunk.26be881fcb628958e718.js.map",
|
||||
"dialog-hassio-snapshot.js": "/api/hassio/app/chunk.ea2041e4c67d4c05b0dd.js",
|
||||
"dialog-hassio-snapshot.js.map": "/api/hassio/app/chunk.ea2041e4c67d4c05b0dd.js.map",
|
||||
"entrypoint.js": "/api/hassio/app/entrypoint.js",
|
||||
"entrypoint.js.map": "/api/hassio/app/entrypoint.js.map",
|
||||
"hassio-addon-view.js": "/api/hassio/app/chunk.43e40fd69686ad51301d.js",
|
||||
"hassio-addon-view.js.map": "/api/hassio/app/chunk.43e40fd69686ad51301d.js.map",
|
||||
"hassio-icons.js": "/api/hassio/app/chunk.0b82745c7bdffe5c1404.js",
|
||||
"hassio-icons.js.map": "/api/hassio/app/chunk.0b82745c7bdffe5c1404.js.map",
|
||||
"hassio-ingress-view.js": "/api/hassio/app/chunk.990ee58006b248f55d23.js",
|
||||
"hassio-ingress-view.js.map": "/api/hassio/app/chunk.990ee58006b248f55d23.js.map",
|
||||
"hassio-main.js": "/api/hassio/app/chunk.4d45ee0a3d852768f97e.js",
|
||||
"hassio-main.js.map": "/api/hassio/app/chunk.4d45ee0a3d852768f97e.js.map",
|
||||
"mdi-icons.js": "/api/hassio/app/chunk.b60200a57d6f63941b30.js",
|
||||
"mdi-icons.js.map": "/api/hassio/app/chunk.b60200a57d6f63941b30.js.map",
|
||||
"hassio-addon-view.js": "/api/hassio/app/chunk.1a25d23325fed5a4d90b.js",
|
||||
"hassio-addon-view.js.map": "/api/hassio/app/chunk.1a25d23325fed5a4d90b.js.map",
|
||||
"hassio-icons.js": "/api/hassio/app/chunk.af76a4db9eb1e2862aae.js",
|
||||
"hassio-icons.js.map": "/api/hassio/app/chunk.af76a4db9eb1e2862aae.js.map",
|
||||
"hassio-ingress-view.js": "/api/hassio/app/chunk.35929da61d769e57c884.js",
|
||||
"hassio-ingress-view.js.map": "/api/hassio/app/chunk.35929da61d769e57c884.js.map",
|
||||
"hassio-main.js": "/api/hassio/app/chunk.5e32280d595be3742226.js",
|
||||
"hassio-main.js.map": "/api/hassio/app/chunk.5e32280d595be3742226.js.map",
|
||||
"mdi-icons.js": "/api/hassio/app/chunk.a9cf4ae83af78188e158.js",
|
||||
"mdi-icons.js.map": "/api/hassio/app/chunk.a9cf4ae83af78188e158.js.map",
|
||||
"roboto.js": "/api/hassio/app/chunk.b2dce600432c76a53d8c.js",
|
||||
"roboto.js.map": "/api/hassio/app/chunk.b2dce600432c76a53d8c.js.map",
|
||||
"vendors~codemirror.js": "/api/hassio/app/chunk.8527374a266cecf93aa9.js",
|
||||
"vendors~codemirror.js.map": "/api/hassio/app/chunk.8527374a266cecf93aa9.js.map",
|
||||
"vendors~hassio-addon-view.js": "/api/hassio/app/chunk.f49e500cf58ea310d452.js",
|
||||
"vendors~hassio-addon-view.js.map": "/api/hassio/app/chunk.f49e500cf58ea310d452.js.map",
|
||||
"vendors~hassio-main.js": "/api/hassio/app/chunk.d4931d72592ad48ba2be.js",
|
||||
"vendors~hassio-main.js.map": "/api/hassio/app/chunk.d4931d72592ad48ba2be.js.map",
|
||||
"201359fd5a526afe13ef.worker.js": "/api/hassio/app/201359fd5a526afe13ef.worker.js",
|
||||
"201359fd5a526afe13ef.worker.js.map": "/api/hassio/app/201359fd5a526afe13ef.worker.js.map",
|
||||
"chunk.429840c83fad61bc51a8.js.LICENSE": "/api/hassio/app/chunk.429840c83fad61bc51a8.js.LICENSE",
|
||||
"chunk.715824f4764bdbe425b1.js.LICENSE": "/api/hassio/app/chunk.715824f4764bdbe425b1.js.LICENSE",
|
||||
"chunk.87b1d37fc9b8a6f7e2a6.js.LICENSE": "/api/hassio/app/chunk.87b1d37fc9b8a6f7e2a6.js.LICENSE",
|
||||
"chunk.9d371c8143226d4eaaee.js.LICENSE": "/api/hassio/app/chunk.9d371c8143226d4eaaee.js.LICENSE",
|
||||
"chunk.d4931d72592ad48ba2be.js.LICENSE": "/api/hassio/app/chunk.d4931d72592ad48ba2be.js.LICENSE",
|
||||
"chunk.e46c606dd9100816af4e.js.LICENSE": "/api/hassio/app/chunk.e46c606dd9100816af4e.js.LICENSE",
|
||||
"chunk.f49e500cf58ea310d452.js.LICENSE": "/api/hassio/app/chunk.f49e500cf58ea310d452.js.LICENSE"
|
||||
"vendors~codemirror.js": "/api/hassio/app/chunk.70a435e100109291f210.js",
|
||||
"vendors~codemirror.js.map": "/api/hassio/app/chunk.70a435e100109291f210.js.map",
|
||||
"vendors~hassio-addon-view.js": "/api/hassio/app/chunk.93a8a2e1dbccae0e07fa.js",
|
||||
"vendors~hassio-addon-view.js.map": "/api/hassio/app/chunk.93a8a2e1dbccae0e07fa.js.map",
|
||||
"vendors~hassio-main.js": "/api/hassio/app/chunk.541d0b76b660d8646074.js",
|
||||
"vendors~hassio-main.js.map": "/api/hassio/app/chunk.541d0b76b660d8646074.js.map",
|
||||
"a1ebfa0a88593a3b571c.worker.js": "/api/hassio/app/a1ebfa0a88593a3b571c.worker.js",
|
||||
"a1ebfa0a88593a3b571c.worker.js.map": "/api/hassio/app/a1ebfa0a88593a3b571c.worker.js.map",
|
||||
"chunk.26be881fcb628958e718.js.LICENSE": "/api/hassio/app/chunk.26be881fcb628958e718.js.LICENSE",
|
||||
"chunk.541d0b76b660d8646074.js.LICENSE": "/api/hassio/app/chunk.541d0b76b660d8646074.js.LICENSE",
|
||||
"chunk.9339f70c8bfe2cbef5ad.js.LICENSE": "/api/hassio/app/chunk.9339f70c8bfe2cbef5ad.js.LICENSE",
|
||||
"chunk.93a8a2e1dbccae0e07fa.js.LICENSE": "/api/hassio/app/chunk.93a8a2e1dbccae0e07fa.js.LICENSE",
|
||||
"chunk.b2a892416a728ca06e9a.js.LICENSE": "/api/hassio/app/chunk.b2a892416a728ca06e9a.js.LICENSE",
|
||||
"chunk.b6e61f8340c32e6904ca.js.LICENSE": "/api/hassio/app/chunk.b6e61f8340c32e6904ca.js.LICENSE",
|
||||
"chunk.ea2041e4c67d4c05b0dd.js.LICENSE": "/api/hassio/app/chunk.ea2041e4c67d4c05b0dd.js.LICENSE"
|
||||
}
|
@ -4,6 +4,7 @@ from contextlib import suppress
|
||||
import logging
|
||||
from pathlib import Path
|
||||
from typing import Awaitable, Optional
|
||||
import shutil
|
||||
|
||||
import jinja2
|
||||
|
||||
@ -18,6 +19,7 @@ from .validate import SCHEMA_AUDIO_CONFIG
|
||||
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
PULSE_CLIENT_TMPL: Path = Path(__file__).parents[0].joinpath("data/pulse-client.tmpl")
|
||||
ASOUND_TMPL: Path = Path(__file__).parents[0].joinpath("data/asound.tmpl")
|
||||
|
||||
|
||||
class Audio(JsonConfig, CoreSysAttributes):
|
||||
@ -31,9 +33,14 @@ class Audio(JsonConfig, CoreSysAttributes):
|
||||
self.client_template: Optional[jinja2.Template] = None
|
||||
|
||||
@property
|
||||
def path_extern_data(self) -> Path:
|
||||
"""Return path of pulse cookie file."""
|
||||
return self.sys_config.path_extern_audio.joinpath("external")
|
||||
def path_extern_pulse(self) -> Path:
|
||||
"""Return path of pulse socket file."""
|
||||
return self.sys_config.path_extern_audio.joinpath("external/pulse.sock")
|
||||
|
||||
@property
|
||||
def path_extern_asound(self) -> Path:
|
||||
"""Return path of default asound config file."""
|
||||
return self.sys_config.path_extern_audio.joinpath("asound")
|
||||
|
||||
@property
|
||||
def version(self) -> Optional[str]:
|
||||
@ -81,9 +88,7 @@ class Audio(JsonConfig, CoreSysAttributes):
|
||||
|
||||
# Run PulseAudio
|
||||
with suppress(AudioError):
|
||||
if await self.instance.is_running():
|
||||
await self.restart()
|
||||
else:
|
||||
if not await self.instance.is_running():
|
||||
await self.start()
|
||||
|
||||
# Initialize Client Template
|
||||
@ -92,6 +97,14 @@ class Audio(JsonConfig, CoreSysAttributes):
|
||||
except OSError as err:
|
||||
_LOGGER.error("Can't read pulse-client.tmpl: %s", err)
|
||||
|
||||
# Setup default asound config
|
||||
asound = self.sys_config.path_audio.joinpath("asound")
|
||||
if not asound.exists():
|
||||
try:
|
||||
shutil.copy(ASOUND_TMPL, asound)
|
||||
except OSError as err:
|
||||
_LOGGER.error("Can't create default asound: %s", err)
|
||||
|
||||
async def install(self) -> None:
|
||||
"""Install Audio."""
|
||||
_LOGGER.info("Setup Audio plugin")
|
||||
@ -137,8 +150,12 @@ class Audio(JsonConfig, CoreSysAttributes):
|
||||
|
||||
async def restart(self) -> None:
|
||||
"""Restart Audio plugin."""
|
||||
with suppress(DockerAPIError):
|
||||
_LOGGER.info("Restart Audio plugin")
|
||||
try:
|
||||
await self.instance.restart()
|
||||
except DockerAPIError:
|
||||
_LOGGER.error("Can't start Audio plugin")
|
||||
raise AudioError() from None
|
||||
|
||||
async def start(self) -> None:
|
||||
"""Run CoreDNS."""
|
||||
|
@ -21,6 +21,7 @@ from .dns import CoreDNS
|
||||
from .hassos import HassOS
|
||||
from .homeassistant import HomeAssistant
|
||||
from .host import HostManager
|
||||
from .hwmon import HwMonitor
|
||||
from .ingress import Ingress
|
||||
from .services import ServiceManager
|
||||
from .snapshots import SnapshotManager
|
||||
@ -57,6 +58,7 @@ async def initialize_coresys():
|
||||
coresys.addons = AddonManager(coresys)
|
||||
coresys.snapshots = SnapshotManager(coresys)
|
||||
coresys.host = HostManager(coresys)
|
||||
coresys.hwmonitor = HwMonitor(coresys)
|
||||
coresys.ingress = Ingress(coresys)
|
||||
coresys.tasks = Tasks(coresys)
|
||||
coresys.services = ServiceManager(coresys)
|
||||
|
@ -3,7 +3,7 @@ from enum import Enum
|
||||
from ipaddress import ip_network
|
||||
from pathlib import Path
|
||||
|
||||
SUPERVISOR_VERSION = "202"
|
||||
SUPERVISOR_VERSION = "203"
|
||||
|
||||
|
||||
URL_HASSIO_ADDONS = "https://github.com/home-assistant/hassio-addons"
|
||||
@ -233,6 +233,7 @@ ATTR_STAGE = "stage"
|
||||
ATTR_CLI = "cli"
|
||||
ATTR_DEFAULT = "default"
|
||||
ATTR_VOLUME = "volume"
|
||||
ATTR_CARD = "card"
|
||||
|
||||
PROVIDE_SERVICE = "provide"
|
||||
NEED_SERVICE = "need"
|
||||
|
@ -142,13 +142,16 @@ class Core(CoreSysAttributes):
|
||||
if self.sys_homeassistant.version == "landingpage":
|
||||
self.sys_create_task(self.sys_homeassistant.install())
|
||||
|
||||
# Start observe the host Hardware
|
||||
await self.sys_hwmonitor.load()
|
||||
|
||||
# Upate Host/Deivce information
|
||||
self.sys_create_task(self.sys_host.reload())
|
||||
self.sys_create_task(self.sys_updater.reload())
|
||||
|
||||
_LOGGER.info("Supervisor is up and running")
|
||||
self.state = CoreStates.RUNNING
|
||||
|
||||
# On full host boot, relaod information
|
||||
self.sys_create_task(self.sys_host.reload())
|
||||
self.sys_create_task(self.sys_updater.reload())
|
||||
|
||||
async def stop(self):
|
||||
"""Stop a running orchestration."""
|
||||
# don't process scheduler anymore
|
||||
@ -168,6 +171,7 @@ class Core(CoreSysAttributes):
|
||||
self.sys_websession_ssl.close(),
|
||||
self.sys_ingress.unload(),
|
||||
self.sys_dns.unload(),
|
||||
self.sys_hwmonitor.unload(),
|
||||
]
|
||||
)
|
||||
except asyncio.TimeoutError:
|
||||
|
@ -22,6 +22,7 @@ if TYPE_CHECKING:
|
||||
from .discovery import Discovery
|
||||
from .dns import CoreDNS
|
||||
from .hassos import HassOS
|
||||
from .hwmon import HwMonitor
|
||||
from .homeassistant import HomeAssistant
|
||||
from .host import HostManager
|
||||
from .ingress import Ingress
|
||||
@ -76,6 +77,7 @@ class CoreSys:
|
||||
self._secrets: Optional[SecretsManager] = None
|
||||
self._store: Optional[StoreManager] = None
|
||||
self._discovery: Optional[Discovery] = None
|
||||
self._hwmonitor: Optional[HwMonitor] = None
|
||||
|
||||
@property
|
||||
def machine(self) -> str:
|
||||
@ -345,6 +347,18 @@ class CoreSys:
|
||||
raise RuntimeError("HostManager already set!")
|
||||
self._host = value
|
||||
|
||||
@property
|
||||
def hwmonitor(self) -> HwMonitor:
|
||||
"""Return HwMonitor object."""
|
||||
return self._hwmonitor
|
||||
|
||||
@hwmonitor.setter
|
||||
def hwmonitor(self, value: HwMonitor):
|
||||
"""Set a HwMonitor object."""
|
||||
if self._hwmonitor:
|
||||
raise RuntimeError("HwMonitor already set!")
|
||||
self._hwmonitor = value
|
||||
|
||||
@property
|
||||
def ingress(self) -> Ingress:
|
||||
"""Return Ingress object."""
|
||||
@ -520,6 +534,11 @@ class CoreSysAttributes:
|
||||
"""Return HostManager object."""
|
||||
return self.coresys.host
|
||||
|
||||
@property
|
||||
def sys_hwmonitor(self) -> HwMonitor:
|
||||
"""Return HwMonitor object."""
|
||||
return self.coresys.hwmonitor
|
||||
|
||||
@property
|
||||
def sys_ingress(self) -> Ingress:
|
||||
"""Return Ingress object."""
|
||||
|
13
supervisor/data/asound.tmpl
Normal file
13
supervisor/data/asound.tmpl
Normal file
@ -0,0 +1,13 @@
|
||||
# Default to PulseAudio
|
||||
|
||||
pcm.!default {
|
||||
type pulse
|
||||
hint {
|
||||
show on
|
||||
description "Default ALSA Output (Home Assistant PulseAudio Sound Server)"
|
||||
}
|
||||
}
|
||||
|
||||
ctl.!default {
|
||||
type pulse
|
||||
}
|
@ -308,10 +308,14 @@ class DockerAddon(DockerInterface):
|
||||
"bind": "/etc/pulse/client.conf",
|
||||
"mode": "ro",
|
||||
},
|
||||
str(self.sys_audio.path_extern_data.joinpath("pulse.sock")): {
|
||||
str(self.sys_audio.path_extern_pulse): {
|
||||
"bind": "/run/pulse.sock",
|
||||
"mode": "rw",
|
||||
},
|
||||
str(self.sys_audio.path_extern_asound): {
|
||||
"bind": "/etc/asound.conf",
|
||||
"mode": "ro",
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
|
@ -65,7 +65,7 @@ class DockerHomeAssistant(DockerInterface):
|
||||
hostname=self.name,
|
||||
detach=True,
|
||||
privileged=True,
|
||||
init=True,
|
||||
init=False,
|
||||
network_mode="host",
|
||||
environment={
|
||||
"HASSIO": self.sys_docker.network.supervisor,
|
||||
@ -101,6 +101,7 @@ class DockerHomeAssistant(DockerInterface):
|
||||
command=command,
|
||||
privileged=True,
|
||||
init=True,
|
||||
entrypoint=[],
|
||||
detach=True,
|
||||
stdout=True,
|
||||
stderr=True,
|
||||
|
@ -1,4 +1,5 @@
|
||||
"""Pulse host control."""
|
||||
from datetime import timedelta
|
||||
from enum import Enum
|
||||
import logging
|
||||
from typing import List
|
||||
@ -8,13 +9,14 @@ from pulsectl import Pulse, PulseError, PulseIndexError, PulseOperationFailed
|
||||
|
||||
from ..coresys import CoreSys, CoreSysAttributes
|
||||
from ..exceptions import PulseAudioError
|
||||
from ..utils import AsyncThrottle
|
||||
|
||||
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
PULSE_NAME = "supervisor"
|
||||
|
||||
|
||||
class SourceType(str, Enum):
|
||||
class StreamType(str, Enum):
|
||||
"""INPUT/OUTPUT type of source."""
|
||||
|
||||
INPUT = "input"
|
||||
@ -22,7 +24,7 @@ class SourceType(str, Enum):
|
||||
|
||||
|
||||
@attr.s(frozen=True)
|
||||
class AudioProfile:
|
||||
class AudioStream:
|
||||
"""Represent a input/output profile."""
|
||||
|
||||
name: str = attr.ib()
|
||||
@ -31,101 +33,186 @@ class AudioProfile:
|
||||
default: bool = attr.ib()
|
||||
|
||||
|
||||
@attr.s(frozen=True)
|
||||
class SoundProfile:
|
||||
"""Represent a Sound Card profile."""
|
||||
|
||||
name: str = attr.ib()
|
||||
description: str = attr.ib()
|
||||
active: bool = attr.ib()
|
||||
|
||||
|
||||
@attr.s(frozen=True)
|
||||
class SoundCard:
|
||||
"""Represent a Sound Card."""
|
||||
|
||||
name: str = attr.ib()
|
||||
driver: str = attr.ib()
|
||||
profiles: List[SoundProfile] = attr.ib()
|
||||
|
||||
|
||||
class SoundControl(CoreSysAttributes):
|
||||
"""Pulse control from Host."""
|
||||
|
||||
def __init__(self, coresys: CoreSys) -> None:
|
||||
"""Initialize PulseAudio sound control."""
|
||||
self.coresys: CoreSys = coresys
|
||||
self._input: List[AudioProfile] = []
|
||||
self._output: List[AudioProfile] = []
|
||||
self._cards: List[SoundCard] = []
|
||||
self._inputs: List[AudioStream] = []
|
||||
self._outputs: List[AudioStream] = []
|
||||
|
||||
@property
|
||||
def input_profiles(self) -> List[AudioProfile]:
|
||||
"""Return a list of available input profiles."""
|
||||
return self._input
|
||||
def cards(self) -> List[SoundCard]:
|
||||
"""Return a list of available sound cards and profiles."""
|
||||
return self._cards
|
||||
|
||||
@property
|
||||
def output_profiles(self) -> List[AudioProfile]:
|
||||
"""Return a list of available output profiles."""
|
||||
return self._output
|
||||
def inputs(self) -> List[AudioStream]:
|
||||
"""Return a list of available input streams."""
|
||||
return self._inputs
|
||||
|
||||
async def set_default(self, source: SourceType, name: str) -> None:
|
||||
"""Set a profile to default input/output."""
|
||||
try:
|
||||
with Pulse(PULSE_NAME) as pulse:
|
||||
if source == SourceType.OUTPUT:
|
||||
# Get source and set it as default
|
||||
source = pulse.get_source_by_name(name)
|
||||
pulse.source_default_set(source)
|
||||
else:
|
||||
# Get sink and set it as default
|
||||
sink = pulse.get_sink_by_name(name)
|
||||
pulse.sink_default_set(sink)
|
||||
except PulseIndexError:
|
||||
_LOGGER.error("Can't find %s profile %s", source, name)
|
||||
raise PulseAudioError() from None
|
||||
except PulseError as err:
|
||||
_LOGGER.error("Can't set %s as default: %s", name, err)
|
||||
raise PulseAudioError() from None
|
||||
@property
|
||||
def outputs(self) -> List[AudioStream]:
|
||||
"""Return a list of available output streams."""
|
||||
return self._outputs
|
||||
|
||||
# Reload data
|
||||
async def set_default(self, stream_type: StreamType, name: str) -> None:
|
||||
"""Set a stream to default input/output."""
|
||||
|
||||
def _set_default():
|
||||
try:
|
||||
with Pulse(PULSE_NAME) as pulse:
|
||||
if stream_type == StreamType.INPUT:
|
||||
# Get source and set it as default
|
||||
source = pulse.get_source_by_name(name)
|
||||
pulse.source_default_set(source)
|
||||
else:
|
||||
# Get sink and set it as default
|
||||
sink = pulse.get_sink_by_name(name)
|
||||
pulse.sink_default_set(sink)
|
||||
except PulseIndexError:
|
||||
_LOGGER.error("Can't find %s profile %s", source, name)
|
||||
raise PulseAudioError() from None
|
||||
except PulseError as err:
|
||||
_LOGGER.error("Can't set %s as default: %s", name, err)
|
||||
raise PulseAudioError() from None
|
||||
|
||||
# Run and Reload data
|
||||
await self.sys_run_in_executor(_set_default)
|
||||
await self.update()
|
||||
|
||||
async def set_volume(self, source: SourceType, name: str, volume: float) -> None:
|
||||
async def set_volume(
|
||||
self, stream_type: StreamType, name: str, volume: float
|
||||
) -> None:
|
||||
"""Set a stream to volume input/output."""
|
||||
|
||||
def _set_volume():
|
||||
try:
|
||||
with Pulse(PULSE_NAME) as pulse:
|
||||
if stream_type == StreamType.INPUT:
|
||||
# Get source and set it as default
|
||||
stream = pulse.get_source_by_name(name)
|
||||
else:
|
||||
# Get sink and set it as default
|
||||
stream = pulse.get_sink_by_name(name)
|
||||
|
||||
pulse.volume_set_all_chans(stream, volume)
|
||||
except PulseIndexError:
|
||||
_LOGGER.error("Can't find %s profile %s", stream_type, name)
|
||||
raise PulseAudioError() from None
|
||||
except PulseError as err:
|
||||
_LOGGER.error("Can't set %s volume: %s", name, err)
|
||||
raise PulseAudioError() from None
|
||||
|
||||
# Run and Reload data
|
||||
await self.sys_run_in_executor(_set_volume)
|
||||
await self.update()
|
||||
|
||||
async def ativate_profile(self, card_name: str, profile_name: str) -> None:
|
||||
"""Set a profile to volume input/output."""
|
||||
try:
|
||||
with Pulse(PULSE_NAME) as pulse:
|
||||
if source == SourceType.OUTPUT:
|
||||
# Get source and set it as default
|
||||
source = pulse.get_source_by_name(name)
|
||||
else:
|
||||
# Get sink and set it as default
|
||||
source = pulse.get_sink_by_name(name)
|
||||
|
||||
pulse.volume_set_all_chans(source, volume)
|
||||
except PulseIndexError:
|
||||
_LOGGER.error("Can't find %s profile %s", source, name)
|
||||
raise PulseAudioError() from None
|
||||
except PulseError as err:
|
||||
_LOGGER.error("Can't set %s volume: %s", name, err)
|
||||
raise PulseAudioError() from None
|
||||
def _activate_profile():
|
||||
try:
|
||||
with Pulse(PULSE_NAME) as pulse:
|
||||
card = pulse.get_sink_by_name(card_name)
|
||||
pulse.card_profile_set(card, profile_name)
|
||||
|
||||
# Reload data
|
||||
except PulseIndexError:
|
||||
_LOGGER.error("Can't find %s profile %s", card_name, profile_name)
|
||||
raise PulseAudioError() from None
|
||||
except PulseError as err:
|
||||
_LOGGER.error(
|
||||
"Can't activate %s profile %s: %s", card_name, profile_name, err
|
||||
)
|
||||
raise PulseAudioError() from None
|
||||
|
||||
# Run and Reload data
|
||||
await self.sys_run_in_executor(_activate_profile)
|
||||
await self.update()
|
||||
|
||||
@AsyncThrottle(timedelta(seconds=10))
|
||||
async def update(self):
|
||||
"""Update properties over dbus."""
|
||||
_LOGGER.info("Update PulseAudio information")
|
||||
try:
|
||||
with Pulse(PULSE_NAME) as pulse:
|
||||
server = pulse.server_info()
|
||||
|
||||
# Update output
|
||||
self._output.clear()
|
||||
for sink in pulse.sink_list():
|
||||
self._output.append(
|
||||
AudioProfile(
|
||||
sink.name,
|
||||
sink.description,
|
||||
sink.volume.value_flat,
|
||||
sink.name == server.default_sink_name,
|
||||
)
|
||||
)
|
||||
def _update():
|
||||
try:
|
||||
with Pulse(PULSE_NAME) as pulse:
|
||||
server = pulse.server_info()
|
||||
|
||||
# Update input
|
||||
self._input.clear()
|
||||
for source in pulse.source_list():
|
||||
self._input.append(
|
||||
AudioProfile(
|
||||
source.name,
|
||||
source.description,
|
||||
source.volume.value_flat,
|
||||
source.name == server.default_source_name,
|
||||
# Update output
|
||||
self._outputs.clear()
|
||||
for sink in pulse.sink_list():
|
||||
self._outputs.append(
|
||||
AudioStream(
|
||||
sink.name,
|
||||
sink.description,
|
||||
sink.volume.value_flat,
|
||||
sink.name == server.default_sink_name,
|
||||
)
|
||||
)
|
||||
)
|
||||
except PulseOperationFailed as err:
|
||||
_LOGGER.error("Error while processing pulse update: %s", err)
|
||||
raise PulseAudioError() from None
|
||||
except PulseError as err:
|
||||
_LOGGER.debug("Can't update PulseAudio data: %s", err)
|
||||
|
||||
# Update input
|
||||
self._inputs.clear()
|
||||
for source in pulse.source_list():
|
||||
# Filter monitor devices out because we did not use it now
|
||||
if source.name.endswith(".monitor"):
|
||||
continue
|
||||
self._inputs.append(
|
||||
AudioStream(
|
||||
source.name,
|
||||
source.description,
|
||||
source.volume.value_flat,
|
||||
source.name == server.default_source_name,
|
||||
)
|
||||
)
|
||||
|
||||
# Update Sound Card
|
||||
self._cards.clear()
|
||||
for card in pulse.card_list():
|
||||
sound_profiles: List[SoundProfile] = []
|
||||
|
||||
# Generate profiles
|
||||
for profile in card.profile_list:
|
||||
if not profile.available:
|
||||
continue
|
||||
sound_profiles.append(
|
||||
SoundProfile(
|
||||
profile.name,
|
||||
profile.description,
|
||||
profile.name == card.profile_active.name,
|
||||
)
|
||||
)
|
||||
|
||||
self._cards.append(
|
||||
SoundCard(card.name, card.driver, sound_profiles)
|
||||
)
|
||||
|
||||
except PulseOperationFailed as err:
|
||||
_LOGGER.error("Error while processing pulse update: %s", err)
|
||||
raise PulseAudioError() from None
|
||||
except PulseError as err:
|
||||
_LOGGER.debug("Can't update PulseAudio data: %s", err)
|
||||
|
||||
# Run update from pulse server
|
||||
await self.sys_run_in_executor(_update)
|
||||
|
57
supervisor/hwmon.py
Normal file
57
supervisor/hwmon.py
Normal file
@ -0,0 +1,57 @@
|
||||
"""Supervisor Hardware monitor based on udev."""
|
||||
from datetime import timedelta
|
||||
import logging
|
||||
from pprint import pformat
|
||||
from typing import Optional
|
||||
|
||||
import pyudev
|
||||
|
||||
from .coresys import CoreSysAttributes, CoreSys
|
||||
from .utils import AsyncCallFilter
|
||||
|
||||
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class HwMonitor(CoreSysAttributes):
|
||||
"""Hardware monitor for supervisor."""
|
||||
|
||||
def __init__(self, coresys: CoreSys):
|
||||
"""Initialize Hardware Monitor object."""
|
||||
self.coresys: CoreSys = coresys
|
||||
self.context = pyudev.Context()
|
||||
self.monitor = pyudev.Monitor.from_netlink(self.context)
|
||||
self.observer: Optional[pyudev.MonitorObserver] = None
|
||||
|
||||
async def load(self) -> None:
|
||||
"""Start hardware monitor."""
|
||||
self.observer = pyudev.MonitorObserver(self.monitor, self._udev_events)
|
||||
self.observer.start()
|
||||
|
||||
_LOGGER.info("Start Supervisor hardware monitor")
|
||||
|
||||
async def unload(self) -> None:
|
||||
"""Shutdown sessions."""
|
||||
if self.observer is None:
|
||||
return
|
||||
self.observer.stop()
|
||||
_LOGGER.info("Stop Supervisor hardware monitor")
|
||||
|
||||
def _udev_events(self, action: str, device: pyudev.Device):
|
||||
"""Incomming events from udev.
|
||||
|
||||
This is inside a observe thread and need pass into our eventloop.
|
||||
"""
|
||||
_LOGGER.debug("Hardware monitor: %s - %s", action, pformat(device))
|
||||
self.sys_loop.call_soon_threadsafe(self._async_udev_events, action, device)
|
||||
|
||||
def _async_udev_events(self, action: str, device: pyudev.Device):
|
||||
"""Incomming events from udev into loop."""
|
||||
# Sound changes
|
||||
if device.subsystem == "sound":
|
||||
self._action_sound(device)
|
||||
|
||||
@AsyncCallFilter(timedelta(seconds=5))
|
||||
def _action_sound(self, device: pyudev.Device):
|
||||
"""Process sound actions."""
|
||||
_LOGGER.info("Detect changed audio hardware")
|
||||
self.sys_loop.call_later(5, self.sys_create_task, self.sys_host.sound.update())
|
@ -12,7 +12,6 @@ import pyudev
|
||||
from ..const import ATTR_DEVICES, ATTR_NAME, ATTR_TYPE, CHAN_ID, CHAN_TYPE
|
||||
from ..exceptions import HardwareNotSupportedError
|
||||
|
||||
|
||||
_LOGGER: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
ASOUND_CARDS: Path = Path("/proc/asound/cards")
|
||||
@ -133,7 +132,6 @@ class Hardware:
|
||||
def audio_devices(self) -> Dict[str, Any]:
|
||||
"""Return all available audio interfaces."""
|
||||
if not ASOUND_CARDS.exists():
|
||||
_LOGGER.info("No audio devices found")
|
||||
return {}
|
||||
|
||||
try:
|
||||
|
@ -36,7 +36,7 @@ def process_lock(method):
|
||||
class AsyncThrottle:
|
||||
"""
|
||||
Decorator that prevents a function from being called more than once every
|
||||
time period.
|
||||
time period with blocking.
|
||||
"""
|
||||
|
||||
def __init__(self, delta):
|
||||
@ -64,6 +64,32 @@ class AsyncThrottle:
|
||||
return wrapper
|
||||
|
||||
|
||||
class AsyncCallFilter:
|
||||
"""
|
||||
Decorator that prevents a function from being called more than once every
|
||||
time period.
|
||||
"""
|
||||
|
||||
def __init__(self, delta):
|
||||
"""Initialize async throttle."""
|
||||
self.throttle_period = delta
|
||||
self.time_of_last_call = datetime.min
|
||||
|
||||
def __call__(self, method):
|
||||
"""Throttle function"""
|
||||
|
||||
async def wrapper(*args, **kwargs):
|
||||
"""Throttle function wrapper"""
|
||||
now = datetime.now()
|
||||
time_since_last_call = now - self.time_of_last_call
|
||||
|
||||
if time_since_last_call > self.throttle_period:
|
||||
self.time_of_last_call = now
|
||||
return await method(*args, **kwargs)
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
def check_port(address: IPv4Address, port: int) -> bool:
|
||||
"""Check if port is mapped."""
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
|
Loading…
x
Reference in New Issue
Block a user