${this._renderUpdateCard(
"Home Assistant Core",
+ "core",
this.supervisor.core,
"hassio/homeassistant/update",
`https://${
@@ -72,6 +74,7 @@ export class HassioUpdate extends LitElement {
)}
${this._renderUpdateCard(
"Supervisor",
+ "supervisor",
this.supervisor.supervisor,
"hassio/supervisor/update",
`https://github.com//home-assistant/hassio/releases/tag/${this.supervisor.supervisor.version_latest}`
@@ -79,6 +82,7 @@ export class HassioUpdate extends LitElement {
${this.supervisor.host.features.includes("hassos")
? this._renderUpdateCard(
"Operating System",
+ "os",
this.supervisor.os,
"hassio/os/update",
`https://github.com//home-assistant/hassos/releases/tag/${this.supervisor.os.version_latest}`
@@ -91,6 +95,7 @@ export class HassioUpdate extends LitElement {
private _renderUpdateCard(
name: string,
+ key: string,
object: HassioHomeAssistantInfo | HassioSupervisorInfo | HassioHassOSInfo,
apiPath: string,
releaseNotesUrl: string
@@ -116,6 +121,7 @@ export class HassioUpdate extends LitElement {
@@ -142,6 +148,7 @@ export class HassioUpdate extends LitElement {
}
try {
await this.hass.callApi>("POST", item.apiPath);
+ fireEvent(this, "supervisor-store-refresh", { store: item.key });
} catch (err) {
// Only show an error if the status code was not expected (user behind proxy)
// or no status at all(connection terminated)
diff --git a/hassio/src/hassio-main.ts b/hassio/src/hassio-main.ts
index 81d736e881..31de2006d7 100644
--- a/hassio/src/hassio-main.ts
+++ b/hassio/src/hassio-main.ts
@@ -3,7 +3,9 @@ import { atLeastVersion } from "../../src/common/config/version";
import { applyThemesOnElement } from "../../src/common/dom/apply_themes_on_element";
import { fireEvent } from "../../src/common/dom/fire_event";
import { HassioPanelInfo } from "../../src/data/hassio/supervisor";
+import { supervisorStore } from "../../src/data/supervisor/supervisor";
import { makeDialogManager } from "../../src/dialogs/make-dialog-manager";
+import "../../src/layouts/hass-loading-screen";
import { HomeAssistant, Route } from "../../src/types";
import "./hassio-router";
import { SupervisorBaseElement } from "./supervisor-base-element";
@@ -71,8 +73,15 @@ export class HassioMain extends SupervisorBaseElement {
protected render() {
if (!this.supervisor || !this.hass) {
- return html``;
+ return html``;
}
+
+ if (
+ Object.keys(supervisorStore).some((store) => !this.supervisor![store])
+ ) {
+ return html``;
+ }
+
return html`
;
+ "supervisor-store-refresh": { store: SupervisorObject };
}
}
@@ -25,6 +41,20 @@ export class SupervisorBaseElement extends urlSyncMixin(
) {
@property({ attribute: false }) public supervisor?: Supervisor;
+ @internalProperty() private _unsubs: Record = {};
+
+ @internalProperty() private _collections: Record<
+ string,
+ Collection
+ > = {};
+
+ public disconnectedCallback() {
+ super.disconnectedCallback();
+ Object.keys(this._unsubs).forEach((unsub) => {
+ this._unsubs[unsub]();
+ });
+ }
+
protected _updateSupervisor(obj: Partial): void {
this.supervisor = { ...this.supervisor!, ...obj };
}
@@ -32,13 +62,59 @@ export class SupervisorBaseElement extends urlSyncMixin(
protected firstUpdated(changedProps: PropertyValues): void {
super.firstUpdated(changedProps);
this._initSupervisor();
- this.addEventListener("supervisor-update", (ev) =>
- this._updateSupervisor(ev.detail)
+ }
+
+ private async _handleSupervisorStoreRefreshEvent(ev) {
+ const store = ev.detail.store;
+ if (atLeastVersion(this.hass.config.version, 2021, 2, 4)) {
+ this._collections[store].refresh();
+ return;
+ }
+
+ const response = await this.hass.callApi>(
+ "GET",
+ `hassio${supervisorStore[store]}`
);
+ this._updateSupervisor({ [store]: response.data });
}
private async _initSupervisor(): Promise {
+ this.addEventListener(
+ "supervisor-store-refresh",
+ this._handleSupervisorStoreRefreshEvent
+ );
+
+ if (atLeastVersion(this.hass.config.version, 2021, 2, 4)) {
+ Object.keys(supervisorStore).forEach((store) => {
+ this._unsubs[store] = subscribeSupervisorEvents(
+ this.hass,
+ (data) => this._updateSupervisor({ [store]: data }),
+ store,
+ supervisorStore[store]
+ );
+ if (this._collections[store]) {
+ this._collections[store].refresh();
+ } else {
+ this._collections[store] = getSupervisorEventCollection(
+ this.hass.connection,
+ store,
+ supervisorStore[store]
+ );
+ }
+ });
+
+ if (this.supervisor === undefined) {
+ Object.keys(this._collections).forEach((collection) =>
+ this._updateSupervisor({
+ [collection]: this._collections[collection].state,
+ })
+ );
+ }
+ return;
+ }
+
const [
+ addon,
supervisor,
host,
core,
@@ -47,6 +123,7 @@ export class SupervisorBaseElement extends urlSyncMixin(
network,
resolution,
] = await Promise.all([
+ fetchHassioAddonsInfo(this.hass),
fetchHassioSupervisorInfo(this.hass),
fetchHassioHostInfo(this.hass),
fetchHassioHomeAssistantInfo(this.hass),
@@ -57,6 +134,7 @@ export class SupervisorBaseElement extends urlSyncMixin(
]);
this.supervisor = {
+ addon,
supervisor,
host,
core,
@@ -65,5 +143,9 @@ export class SupervisorBaseElement extends urlSyncMixin(
network,
resolution,
};
+
+ this.addEventListener("supervisor-update", (ev) =>
+ this._updateSupervisor(ev.detail)
+ );
}
}
diff --git a/hassio/src/system/hassio-core-info.ts b/hassio/src/system/hassio-core-info.ts
index 96c3aad65f..985a242773 100644
--- a/hassio/src/system/hassio-core-info.ts
+++ b/hassio/src/system/hassio-core-info.ts
@@ -10,6 +10,7 @@ import {
property,
TemplateResult,
} from "lit-element";
+import { fireEvent } from "../../../src/common/dom/fire_event";
import "../../../src/components/buttons/ha-progress-button";
import "../../../src/components/ha-button-menu";
import "../../../src/components/ha-card";
@@ -166,6 +167,7 @@ class HassioCoreInfo extends LitElement {
try {
await updateCore(this.hass);
+ fireEvent(this, "supervisor-store-refresh", { store: "core" });
} catch (err) {
showAlertDialog(this, {
title: "Failed to update Home Assistant Core",
diff --git a/hassio/src/system/hassio-host-info.ts b/hassio/src/system/hassio-host-info.ts
index b4fd17f9b2..69245d8663 100644
--- a/hassio/src/system/hassio-host-info.ts
+++ b/hassio/src/system/hassio-host-info.ts
@@ -13,6 +13,7 @@ import {
TemplateResult,
} from "lit-element";
import memoizeOne from "memoize-one";
+import { atLeastVersion } from "../../../src/common/config/version";
import { fireEvent } from "../../../src/common/dom/fire_event";
import "../../../src/components/buttons/ha-progress-button";
import "../../../src/components/ha-button-menu";
@@ -26,7 +27,6 @@ import { fetchHassioHardwareInfo } from "../../../src/data/hassio/hardware";
import {
changeHostOptions,
configSyncOS,
- fetchHassioHostInfo,
rebootHost,
shutdownHost,
updateOS,
@@ -340,6 +340,7 @@ class HassioHostInfo extends LitElement {
try {
await updateOS(this.hass);
+ fireEvent(this, "supervisor-store-refresh", { store: "os" });
} catch (err) {
showAlertDialog(this, {
title: "Failed to update",
@@ -368,8 +369,7 @@ class HassioHostInfo extends LitElement {
if (hostname && hostname !== curHostname) {
try {
await changeHostOptions(this.hass, { hostname });
- const host = await fetchHassioHostInfo(this.hass);
- fireEvent(this, "supervisor-update", { host });
+ fireEvent(this, "supervisor-store-refresh", { store: "host" });
} catch (err) {
showAlertDialog(this, {
title: "Setting hostname failed",
@@ -382,8 +382,7 @@ class HassioHostInfo extends LitElement {
private async _importFromUSB(): Promise {
try {
await configSyncOS(this.hass);
- const host = await fetchHassioHostInfo(this.hass);
- fireEvent(this, "supervisor-update", { host });
+ fireEvent(this, "supervisor-store-refresh", { store: "host" });
} catch (err) {
showAlertDialog(this, {
title: "Failed to import from USB",
@@ -393,8 +392,12 @@ class HassioHostInfo extends LitElement {
}
private async _loadData(): Promise {
- const network = await fetchNetworkInfo(this.hass);
- fireEvent(this, "supervisor-update", { network });
+ if (atLeastVersion(this.hass.config.version, 2021, 2, 4)) {
+ fireEvent(this, "supervisor-store-refresh", { store: "network" });
+ } else {
+ const network = await fetchNetworkInfo(this.hass);
+ fireEvent(this, "supervisor-update", { network });
+ }
}
static get styles(): CSSResult[] {
diff --git a/hassio/src/system/hassio-supervisor-info.ts b/hassio/src/system/hassio-supervisor-info.ts
index b29252d2ad..ebc96ab32a 100644
--- a/hassio/src/system/hassio-supervisor-info.ts
+++ b/hassio/src/system/hassio-supervisor-info.ts
@@ -19,7 +19,6 @@ import {
HassioStats,
} from "../../../src/data/hassio/common";
import {
- fetchHassioSupervisorInfo,
reloadSupervisor,
restartSupervisor,
setSupervisorOption,
@@ -318,8 +317,7 @@ class HassioSupervisorInfo extends LitElement {
private async _reloadSupervisor(): Promise {
await reloadSupervisor(this.hass);
- const supervisor = await fetchHassioSupervisorInfo(this.hass);
- fireEvent(this, "supervisor-update", { supervisor });
+ fireEvent(this, "supervisor-store-refresh", { store: "supervisor" });
}
private async _supervisorRestart(ev: CustomEvent): Promise {
@@ -368,6 +366,7 @@ class HassioSupervisorInfo extends LitElement {
try {
await updateSupervisor(this.hass);
+ fireEvent(this, "supervisor-store-refresh", { store: "supervisor" });
} catch (err) {
showAlertDialog(this, {
title: "Failed to update the supervisor",
diff --git a/src/common/config/version.ts b/src/common/config/version.ts
index cc6ccf7f7f..affdf9d94d 100644
--- a/src/common/config/version.ts
+++ b/src/common/config/version.ts
@@ -1,11 +1,15 @@
export const atLeastVersion = (
version: string,
major: number,
- minor: number
+ minor: number,
+ patch?: number
): boolean => {
- const [haMajor, haMinor] = version.split(".", 2);
+ const [haMajor, haMinor, haPatch] = version.split(".", 3);
return (
Number(haMajor) > major ||
- (Number(haMajor) === major && Number(haMinor) >= minor)
+ (Number(haMajor) === major && Number(haMinor) >= minor) ||
+ (patch !== undefined &&
+ Number(haMajor) === major && Number(haMinor) === minor &&
+ Number(haPatch) >= patch)
);
};
diff --git a/src/data/hassio/addon.ts b/src/data/hassio/addon.ts
index 0429734bbd..b17f327097 100644
--- a/src/data/hassio/addon.ts
+++ b/src/data/hassio/addon.ts
@@ -1,3 +1,4 @@
+import { atLeastVersion } from "../../common/config/version";
import { HaFormSchema } from "../../components/ha-form/ha-form";
import { HomeAssistant } from "../../types";
import { SupervisorArch } from "../supervisor/supervisor";
@@ -102,10 +103,28 @@ export interface HassioAddonSetOptionParams {
}
export const reloadHassioAddons = async (hass: HomeAssistant) => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ await hass.callWS({
+ type: "supervisor/api",
+ endpoint: "/addons/reload",
+ method: "post",
+ });
+ return;
+ }
await hass.callApi>("POST", `hassio/addons/reload`);
};
-export const fetchHassioAddonsInfo = async (hass: HomeAssistant) => {
+export const fetchHassioAddonsInfo = async (
+ hass: HomeAssistant
+): Promise => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ return await hass.callWS({
+ type: "supervisor/api",
+ endpoint: "/addons",
+ method: "get",
+ });
+ }
+
return hassioApiResultExtractor(
await hass.callApi>("GET", `hassio/addons`)
);
@@ -114,7 +133,15 @@ export const fetchHassioAddonsInfo = async (hass: HomeAssistant) => {
export const fetchHassioAddonInfo = async (
hass: HomeAssistant,
slug: string
-) => {
+): Promise => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ return await hass.callWS({
+ type: "supervisor/api",
+ endpoint: `/addons/${slug}/info`,
+ method: "get",
+ });
+ }
+
return hassioApiResultExtractor(
await hass.callApi>(
"GET",
@@ -149,6 +176,16 @@ export const setHassioAddonOption = async (
slug: string,
data: HassioAddonSetOptionParams
) => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ await hass.callWS({
+ type: "supervisor/api",
+ endpoint: `/addons/${slug}/options`,
+ method: "post",
+ data,
+ });
+ return;
+ }
+
await hass.callApi>(
"POST",
`hassio/addons/${slug}/options`,
@@ -159,21 +196,64 @@ export const setHassioAddonOption = async (
export const validateHassioAddonOption = async (
hass: HomeAssistant,
slug: string
-) => {
- return await hass.callApi<
- HassioResponse<{ message: string; valid: boolean }>
- >("POST", `hassio/addons/${slug}/options/validate`);
+): Promise<{ message: string; valid: boolean }> => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ return await hass.callWS({
+ type: "supervisor/api",
+ endpoint: `/addons/${slug}/options/validate`,
+ method: "post",
+ });
+ }
+
+ return (
+ await hass.callApi>(
+ "POST",
+ `hassio/addons/${slug}/options/validate`
+ )
+ ).data;
};
export const startHassioAddon = async (hass: HomeAssistant, slug: string) => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ return await hass.callWS({
+ type: "supervisor/api",
+ endpoint: `/addons/${slug}/start`,
+ method: "post",
+ timeout: null,
+ });
+ }
+
return hass.callApi("POST", `hassio/addons/${slug}/start`);
};
+export const stopHassioAddon = async (hass: HomeAssistant, slug: string) => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ return await hass.callWS({
+ type: "supervisor/api",
+ endpoint: `/addons/${slug}/stop`,
+ method: "post",
+ timeout: null,
+ });
+ }
+
+ return hass.callApi("POST", `hassio/addons/${slug}/stop`);
+};
+
export const setHassioAddonSecurity = async (
hass: HomeAssistant,
slug: string,
data: HassioAddonSetSecurityParams
) => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ await hass.callWS({
+ type: "supervisor/api",
+ endpoint: `/addons/${slug}/security`,
+ method: "post",
+ data,
+ });
+ return;
+ }
+
await hass.callApi>(
"POST",
`hassio/addons/${slug}/security`,
@@ -181,15 +261,61 @@ export const setHassioAddonSecurity = async (
);
};
-export const installHassioAddon = async (hass: HomeAssistant, slug: string) => {
- return hass.callApi>(
+export const installHassioAddon = async (
+ hass: HomeAssistant,
+ slug: string
+): Promise => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ await hass.callWS({
+ type: "supervisor/api",
+ endpoint: `/addons/${slug}/install`,
+ method: "post",
+ timeout: null,
+ });
+ return;
+ }
+
+ await hass.callApi>(
"POST",
`hassio/addons/${slug}/install`
);
};
-export const restartHassioAddon = async (hass: HomeAssistant, slug: string) => {
- return hass.callApi>(
+export const updateHassioAddon = async (
+ hass: HomeAssistant,
+ slug: string
+): Promise => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ await hass.callWS({
+ type: "supervisor/api",
+ endpoint: `/addons/${slug}/update`,
+ method: "post",
+ timeout: null,
+ });
+ return;
+ }
+
+ await hass.callApi>(
+ "POST",
+ `hassio/addons/${slug}/update`
+ );
+};
+
+export const restartHassioAddon = async (
+ hass: HomeAssistant,
+ slug: string
+): Promise => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ await hass.callWS({
+ type: "supervisor/api",
+ endpoint: `/addons/${slug}/restart`,
+ method: "post",
+ timeout: null,
+ });
+ return;
+ }
+
+ await hass.callApi>(
"POST",
`hassio/addons/${slug}/restart`
);
@@ -199,6 +325,16 @@ export const uninstallHassioAddon = async (
hass: HomeAssistant,
slug: string
) => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ await hass.callWS({
+ type: "supervisor/api",
+ endpoint: `/addons/${slug}/uninstall`,
+ method: "post",
+ timeout: null,
+ });
+ return;
+ }
+
await hass.callApi>(
"POST",
`hassio/addons/${slug}/uninstall`
diff --git a/src/data/hassio/common.ts b/src/data/hassio/common.ts
index 57a0afa59a..de6a28c68b 100644
--- a/src/data/hassio/common.ts
+++ b/src/data/hassio/common.ts
@@ -1,3 +1,4 @@
+import { atLeastVersion } from "../../common/config/version";
import { HomeAssistant } from "../../types";
export interface HassioResponse {
@@ -33,6 +34,14 @@ export const fetchHassioStats = async (
hass: HomeAssistant,
container: string
): Promise => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ return await hass.callWS({
+ type: "supervisor/api",
+ endpoint: `/${container}/stats`,
+ method: "get",
+ });
+ }
+
return hassioApiResultExtractor(
await hass.callApi>(
"GET",
diff --git a/src/data/hassio/docker.ts b/src/data/hassio/docker.ts
index 4bc9a194c5..c8884336e0 100644
--- a/src/data/hassio/docker.ts
+++ b/src/data/hassio/docker.ts
@@ -1,3 +1,4 @@
+import { atLeastVersion } from "../../common/config/version";
import { HomeAssistant } from "../../types";
import { hassioApiResultExtractor, HassioResponse } from "./common";
@@ -5,7 +6,17 @@ interface HassioDockerRegistries {
[key: string]: { username: string; password?: string };
}
-export const fetchHassioDockerRegistries = async (hass: HomeAssistant) => {
+export const fetchHassioDockerRegistries = async (
+ hass: HomeAssistant
+): Promise => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ return await hass.callWS({
+ type: "supervisor/api",
+ endpoint: `/docker/registries`,
+ method: "get",
+ });
+ }
+
return hassioApiResultExtractor(
await hass.callApi>(
"GET",
@@ -18,6 +29,16 @@ export const addHassioDockerRegistry = async (
hass: HomeAssistant,
data: HassioDockerRegistries
) => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ await hass.callWS({
+ type: "supervisor/api",
+ endpoint: `/docker/registries`,
+ method: "post",
+ data,
+ });
+ return;
+ }
+
await hass.callApi>(
"POST",
"hassio/docker/registries",
@@ -29,6 +50,15 @@ export const removeHassioDockerRegistry = async (
hass: HomeAssistant,
registry: string
) => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ await hass.callWS({
+ type: "supervisor/api",
+ endpoint: `/docker/registries/${registry}`,
+ method: "delete",
+ });
+ return;
+ }
+
await hass.callApi>(
"DELETE",
`hassio/docker/registries/${registry}`
diff --git a/src/data/hassio/hardware.ts b/src/data/hassio/hardware.ts
index 2df7a8bcdd..11e70e8b69 100644
--- a/src/data/hassio/hardware.ts
+++ b/src/data/hassio/hardware.ts
@@ -1,3 +1,4 @@
+import { atLeastVersion } from "../../common/config/version";
import { HomeAssistant } from "../../types";
import { hassioApiResultExtractor, HassioResponse } from "./common";
@@ -21,7 +22,17 @@ export interface HassioHardwareInfo {
audio: Record;
}
-export const fetchHassioHardwareAudio = async (hass: HomeAssistant) => {
+export const fetchHassioHardwareAudio = async (
+ hass: HomeAssistant
+): Promise => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ return await hass.callWS({
+ type: "supervisor/api",
+ endpoint: `/hardware/audio`,
+ method: "get",
+ });
+ }
+
return hassioApiResultExtractor(
await hass.callApi>(
"GET",
@@ -30,7 +41,17 @@ export const fetchHassioHardwareAudio = async (hass: HomeAssistant) => {
);
};
-export const fetchHassioHardwareInfo = async (hass: HomeAssistant) => {
+export const fetchHassioHardwareInfo = async (
+ hass: HomeAssistant
+): Promise => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ return await hass.callWS({
+ type: "supervisor/api",
+ endpoint: `/hardware/info`,
+ method: "get",
+ });
+ }
+
return hassioApiResultExtractor(
await hass.callApi>(
"GET",
diff --git a/src/data/hassio/host.ts b/src/data/hassio/host.ts
index 79e518b4c9..2718adbcb4 100644
--- a/src/data/hassio/host.ts
+++ b/src/data/hassio/host.ts
@@ -1,3 +1,4 @@
+import { atLeastVersion } from "../../common/config/version";
import { HomeAssistant } from "../../types";
import { hassioApiResultExtractor, HassioResponse } from "./common";
@@ -23,7 +24,17 @@ export interface HassioHassOSInfo {
version: string | null;
}
-export const fetchHassioHostInfo = async (hass: HomeAssistant) => {
+export const fetchHassioHostInfo = async (
+ hass: HomeAssistant
+): Promise => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ return await hass.callWS({
+ type: "supervisor/api",
+ endpoint: "/host/info",
+ method: "get",
+ });
+ }
+
const response = await hass.callApi>(
"GET",
"hassio/host/info"
@@ -31,7 +42,17 @@ export const fetchHassioHostInfo = async (hass: HomeAssistant) => {
return hassioApiResultExtractor(response);
};
-export const fetchHassioHassOsInfo = async (hass: HomeAssistant) => {
+export const fetchHassioHassOsInfo = async (
+ hass: HomeAssistant
+): Promise => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ return await hass.callWS({
+ type: "supervisor/api",
+ endpoint: "/os/info",
+ method: "get",
+ });
+ }
+
return hassioApiResultExtractor(
await hass.callApi>(
"GET",
@@ -41,22 +62,67 @@ export const fetchHassioHassOsInfo = async (hass: HomeAssistant) => {
};
export const rebootHost = async (hass: HomeAssistant) => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ return await hass.callWS({
+ type: "supervisor/api",
+ endpoint: "/host/reboot",
+ method: "post",
+ timeout: null,
+ });
+ }
+
return hass.callApi>("POST", "hassio/host/reboot");
};
export const shutdownHost = async (hass: HomeAssistant) => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ return await hass.callWS({
+ type: "supervisor/api",
+ endpoint: "/host/shutdown",
+ method: "post",
+ timeout: null,
+ });
+ }
+
return hass.callApi>("POST", "hassio/host/shutdown");
};
export const updateOS = async (hass: HomeAssistant) => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ return await hass.callWS({
+ type: "supervisor/api",
+ endpoint: "/os/update",
+ method: "post",
+ timeout: null,
+ });
+ }
+
return hass.callApi>("POST", "hassio/os/update");
};
export const configSyncOS = async (hass: HomeAssistant) => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ return await hass.callWS({
+ type: "supervisor/api",
+ endpoint: "os/config/sync",
+ method: "post",
+ timeout: null,
+ });
+ }
+
return hass.callApi>("POST", "hassio/os/config/sync");
};
export const changeHostOptions = async (hass: HomeAssistant, options: any) => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ return await hass.callWS({
+ type: "supervisor/api",
+ endpoint: "/host/options",
+ method: "post",
+ data: options,
+ });
+ }
+
return hass.callApi>(
"POST",
"hassio/host/options",
diff --git a/src/data/hassio/ingress.ts b/src/data/hassio/ingress.ts
index ced84a2698..83a211fc2e 100644
--- a/src/data/hassio/ingress.ts
+++ b/src/data/hassio/ingress.ts
@@ -1,26 +1,49 @@
+import { atLeastVersion } from "../../common/config/version";
import { HomeAssistant } from "../../types";
import { HassioResponse } from "./common";
import { CreateSessionResponse } from "./supervisor";
-export const createHassioSession = async (hass: HomeAssistant) => {
- const response = await hass.callApi>(
- "POST",
- "hassio/ingress/session"
- );
- document.cookie = `ingress_session=${
- response.data.session
- };path=/api/hassio_ingress/;SameSite=Strict${
+function setIngressCookie(session: string): string {
+ document.cookie = `ingress_session=${session};path=/api/hassio_ingress/;SameSite=Strict${
location.protocol === "https:" ? ";Secure" : ""
}`;
- return response.data.session;
+ return session;
+}
+
+export const createHassioSession = async (
+ hass: HomeAssistant
+): Promise => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ const wsResponse: { session: string } = await hass.callWS({
+ type: "supervisor/api",
+ endpoint: "/ingress/session",
+ method: "post",
+ });
+ return setIngressCookie(wsResponse.session);
+ }
+
+ const restResponse: { data: { session: string } } = await hass.callApi<
+ HassioResponse
+ >("POST", "hassio/ingress/session");
+ return setIngressCookie(restResponse.data.session);
};
export const validateHassioSession = async (
hass: HomeAssistant,
session: string
-) =>
- await hass.callApi>(
+): Promise => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ await hass.callWS({
+ type: "supervisor/api",
+ endpoint: "/ingress/validate_session",
+ method: "post",
+ data: session,
+ });
+ }
+
+ await hass.callApi>(
"POST",
"hassio/ingress/validate_session",
{ session }
);
+};
diff --git a/src/data/hassio/network.ts b/src/data/hassio/network.ts
index 542ee25d95..5aef6cc336 100644
--- a/src/data/hassio/network.ts
+++ b/src/data/hassio/network.ts
@@ -1,3 +1,4 @@
+import { atLeastVersion } from "../../common/config/version";
import { HomeAssistant } from "../../types";
import { hassioApiResultExtractor, HassioResponse } from "./common";
@@ -51,7 +52,17 @@ export interface NetworkInfo {
docker: DockerNetwork;
}
-export const fetchNetworkInfo = async (hass: HomeAssistant) => {
+export const fetchNetworkInfo = async (
+ hass: HomeAssistant
+): Promise => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ return await hass.callWS({
+ type: "supervisor/api",
+ endpoint: "/network/info",
+ method: "get",
+ });
+ }
+
return hassioApiResultExtractor(
await hass.callApi>(
"GET",
@@ -65,6 +76,17 @@ export const updateNetworkInterface = async (
network_interface: string,
options: Partial
) => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ await hass.callWS({
+ type: "supervisor/api",
+ endpoint: `/network/interface/${network_interface}/update`,
+ method: "post",
+ data: options,
+ timeout: null,
+ });
+ return;
+ }
+
await hass.callApi>(
"POST",
`hassio/network/interface/${network_interface}/update`,
@@ -75,7 +97,16 @@ export const updateNetworkInterface = async (
export const accesspointScan = async (
hass: HomeAssistant,
network_interface: string
-) => {
+): Promise => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ return await hass.callWS({
+ type: "supervisor/api",
+ endpoint: `/network/interface/${network_interface}/accesspoints`,
+ method: "get",
+ timeout: null,
+ });
+ }
+
return hassioApiResultExtractor(
await hass.callApi>(
"GET",
diff --git a/src/data/hassio/resolution.ts b/src/data/hassio/resolution.ts
index 677404f551..f108083cc5 100644
--- a/src/data/hassio/resolution.ts
+++ b/src/data/hassio/resolution.ts
@@ -1,3 +1,4 @@
+import { atLeastVersion } from "../../common/config/version";
import { HomeAssistant } from "../../types";
import { hassioApiResultExtractor, HassioResponse } from "./common";
@@ -8,7 +9,17 @@ export interface HassioResolution {
suggestions: string[];
}
-export const fetchHassioResolution = async (hass: HomeAssistant) => {
+export const fetchHassioResolution = async (
+ hass: HomeAssistant
+): Promise => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ return await hass.callWS({
+ type: "supervisor/api",
+ endpoint: "/resolution/info",
+ method: "get",
+ });
+ }
+
return hassioApiResultExtractor(
await hass.callApi>(
"GET",
diff --git a/src/data/hassio/snapshot.ts b/src/data/hassio/snapshot.ts
index 18157d1255..ecd82ded1c 100644
--- a/src/data/hassio/snapshot.ts
+++ b/src/data/hassio/snapshot.ts
@@ -1,3 +1,4 @@
+import { atLeastVersion } from "../../common/config/version";
import { HomeAssistant } from "../../types";
import { hassioApiResultExtractor, HassioResponse } from "./common";
@@ -33,7 +34,18 @@ export interface HassioPartialSnapshotCreateParams {
password?: string;
}
-export const fetchHassioSnapshots = async (hass: HomeAssistant) => {
+export const fetchHassioSnapshots = async (
+ hass: HomeAssistant
+): Promise => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ const data: { snapshots: HassioSnapshot[] } = await hass.callWS({
+ type: "supervisor/api",
+ endpoint: `/snapshots`,
+ method: "get",
+ });
+ return data.snapshots;
+ }
+
return hassioApiResultExtractor(
await hass.callApi>(
"GET",
@@ -45,8 +57,15 @@ export const fetchHassioSnapshots = async (hass: HomeAssistant) => {
export const fetchHassioSnapshotInfo = async (
hass: HomeAssistant,
snapshot: string
-) => {
+): Promise => {
if (hass) {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ return await hass.callWS({
+ type: "supervisor/api",
+ endpoint: `/snapshots/${snapshot}/info`,
+ method: "get",
+ });
+ }
return hassioApiResultExtractor(
await hass.callApi>(
"GET",
@@ -63,6 +82,15 @@ export const fetchHassioSnapshotInfo = async (
};
export const reloadHassioSnapshots = async (hass: HomeAssistant) => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ await hass.callWS({
+ type: "supervisor/api",
+ endpoint: "/snapshots/reload",
+ method: "post",
+ });
+ return;
+ }
+
await hass.callApi>("POST", `hassio/snapshots/reload`);
};
@@ -70,6 +98,15 @@ export const createHassioFullSnapshot = async (
hass: HomeAssistant,
data: HassioFullSnapshotCreateParams
) => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ await hass.callWS({
+ type: "supervisor/api",
+ endpoint: "/snapshots/new/full",
+ method: "post",
+ timeout: null,
+ });
+ return;
+ }
await hass.callApi>(
"POST",
`hassio/snapshots/new/full`,
@@ -81,6 +118,17 @@ export const createHassioPartialSnapshot = async (
hass: HomeAssistant,
data: HassioFullSnapshotCreateParams
) => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ await hass.callWS({
+ type: "supervisor/api",
+ endpoint: "/snapshots/new/partial",
+ method: "post",
+ timeout: null,
+ data,
+ });
+ return;
+ }
+
await hass.callApi>(
"POST",
`hassio/snapshots/new/partial`,
diff --git a/src/data/hassio/supervisor.ts b/src/data/hassio/supervisor.ts
index a21cfd1915..f7ce56a64e 100644
--- a/src/data/hassio/supervisor.ts
+++ b/src/data/hassio/supervisor.ts
@@ -1,3 +1,4 @@
+import { atLeastVersion } from "../../common/config/version";
import { HomeAssistant, PanelInfo } from "../../types";
import { SupervisorArch } from "../supervisor/supervisor";
import { HassioAddonInfo, HassioAddonRepository } from "./addon";
@@ -83,18 +84,57 @@ export interface SupervisorOptions {
}
export const reloadSupervisor = async (hass: HomeAssistant) => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ await hass.callWS({
+ type: "supervisor/api",
+ endpoint: "/supervisor/reload",
+ method: "post",
+ });
+ return;
+ }
+
await hass.callApi>("POST", `hassio/supervisor/reload`);
};
export const restartSupervisor = async (hass: HomeAssistant) => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ await hass.callWS({
+ type: "supervisor/api",
+ endpoint: "/supervisor/restart",
+ method: "post",
+ timeout: null,
+ });
+ return;
+ }
+
await hass.callApi>("POST", `hassio/supervisor/restart`);
};
export const updateSupervisor = async (hass: HomeAssistant) => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ await hass.callWS({
+ type: "supervisor/api",
+ endpoint: "/supervisor/update",
+ method: "post",
+ timeout: null,
+ });
+ return;
+ }
+
await hass.callApi>("POST", `hassio/supervisor/update`);
};
-export const fetchHassioHomeAssistantInfo = async (hass: HomeAssistant) => {
+export const fetchHassioHomeAssistantInfo = async (
+ hass: HomeAssistant
+): Promise => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ return await hass.callWS({
+ type: "supervisor/api",
+ endpoint: "/core/info",
+ method: "get",
+ });
+ }
+
return hassioApiResultExtractor(
await hass.callApi>(
"GET",
@@ -103,7 +143,17 @@ export const fetchHassioHomeAssistantInfo = async (hass: HomeAssistant) => {
);
};
-export const fetchHassioSupervisorInfo = async (hass: HomeAssistant) => {
+export const fetchHassioSupervisorInfo = async (
+ hass: HomeAssistant
+): Promise => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ return await hass.callWS({
+ type: "supervisor/api",
+ endpoint: "/supervisor/info",
+ method: "get",
+ });
+ }
+
return hassioApiResultExtractor(
await hass.callApi>(
"GET",
@@ -112,7 +162,17 @@ export const fetchHassioSupervisorInfo = async (hass: HomeAssistant) => {
);
};
-export const fetchHassioInfo = async (hass: HomeAssistant) => {
+export const fetchHassioInfo = async (
+ hass: HomeAssistant
+): Promise => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ return await hass.callWS({
+ type: "supervisor/api",
+ endpoint: "/info",
+ method: "get",
+ });
+ }
+
return hassioApiResultExtractor(
await hass.callApi>("GET", "hassio/info")
);
@@ -129,6 +189,16 @@ export const setSupervisorOption = async (
hass: HomeAssistant,
data: SupervisorOptions
) => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ await hass.callWS({
+ type: "supervisor/api",
+ endpoint: "/supervisor/options",
+ method: "post",
+ data,
+ });
+ return;
+ }
+
await hass.callApi>(
"POST",
"hassio/supervisor/options",
diff --git a/src/data/supervisor/core.ts b/src/data/supervisor/core.ts
index 611fbabd36..0191dbe278 100644
--- a/src/data/supervisor/core.ts
+++ b/src/data/supervisor/core.ts
@@ -1,3 +1,4 @@
+import { atLeastVersion } from "../../common/config/version";
import { HomeAssistant } from "../../types";
import { HassioResponse } from "../hassio/common";
@@ -6,5 +7,15 @@ export const restartCore = async (hass: HomeAssistant) => {
};
export const updateCore = async (hass: HomeAssistant) => {
+ if (atLeastVersion(hass.config.version, 2021, 2, 4)) {
+ await hass.callWS({
+ type: "supervisor/api",
+ endpoint: "/core/update",
+ method: "post",
+ timeout: null,
+ });
+ return;
+ }
+
await hass.callApi>("POST", `hassio/core/update`);
};
diff --git a/src/data/supervisor/supervisor.ts b/src/data/supervisor/supervisor.ts
index bc0161becf..1dbaecef2c 100644
--- a/src/data/supervisor/supervisor.ts
+++ b/src/data/supervisor/supervisor.ts
@@ -1,3 +1,7 @@
+import { Connection, getCollection } from "home-assistant-js-websocket";
+import { Store } from "home-assistant-js-websocket/dist/store";
+import { HomeAssistant } from "../../types";
+import { HassioAddonsInfo } from "../hassio/addon";
import { HassioHassOSInfo, HassioHostInfo } from "../hassio/host";
import { NetworkInfo } from "../hassio/network";
import { HassioResolution } from "../hassio/resolution";
@@ -7,7 +11,46 @@ import {
HassioSupervisorInfo,
} from "../hassio/supervisor";
+export const supervisorWSbaseCommand = {
+ type: "supervisor/api",
+ method: "GET",
+};
+
+export const supervisorStore = {
+ host: "/host/info",
+ supervisor: "/supervisor/info",
+ info: "/info",
+ core: "/core/info",
+ network: "/network/info",
+ resolution: "/resolution/info",
+ os: "/os/info",
+ addon: "/addons",
+};
+
export type SupervisorArch = "armhf" | "armv7" | "aarch64" | "i386" | "amd64";
+export type SupervisorObject =
+ | "host"
+ | "supervisor"
+ | "info"
+ | "core"
+ | "network"
+ | "resolution"
+ | "os"
+ | "addon";
+
+interface supervisorApiRequest {
+ endpoint: string;
+ method?: "get" | "post" | "delete" | "put";
+ force_rest?: boolean;
+ data?: any;
+}
+
+export interface SupervisorEvent {
+ event: string;
+ update_key?: SupervisorObject;
+ data?: any;
+ [key: string]: any;
+}
export interface Supervisor {
host: HassioHostInfo;
@@ -17,4 +60,77 @@ export interface Supervisor {
network: NetworkInfo;
resolution: HassioResolution;
os: HassioHassOSInfo;
+ addon: HassioAddonsInfo;
}
+
+export const supervisorApiWsRequest = (
+ conn: Connection,
+ request: supervisorApiRequest
+): Promise =>
+ conn.sendMessagePromise({ ...supervisorWSbaseCommand, ...request });
+
+async function processEvent(
+ conn: Connection,
+ store: Store,
+ event: SupervisorEvent,
+ key: string
+) {
+ if (
+ !event.data ||
+ event.data.event !== "supervisor-update" ||
+ event.data.update_key !== key
+ ) {
+ return;
+ }
+
+ if (Object.keys(event.data.data).length === 0) {
+ const data = await supervisorApiWsRequest(conn, {
+ endpoint: supervisorStore[key],
+ });
+ store.setState(data);
+ return;
+ }
+
+ const state = store.state;
+ if (state === undefined) {
+ return;
+ }
+
+ store.setState({
+ ...state,
+ ...event.data.data,
+ });
+}
+
+const subscribeSupervisorEventUpdates = (
+ conn: Connection,
+ store: Store,
+ key: string
+) =>
+ conn.subscribeEvents(
+ (event) => processEvent(conn, store, event as SupervisorEvent, key),
+ "supervisor_event"
+ );
+
+export const getSupervisorEventCollection = (
+ conn: Connection,
+ key: string,
+ endpoint: string
+) =>
+ getCollection(
+ conn,
+ `_supervisor${key}Event`,
+ () => supervisorApiWsRequest(conn, { endpoint }),
+ (connection, store) =>
+ subscribeSupervisorEventUpdates(connection, store, key)
+ );
+
+export const subscribeSupervisorEvents = (
+ hass: HomeAssistant,
+ onChange: (event) => void,
+ key: string,
+ endpoint: string
+) =>
+ getSupervisorEventCollection(hass.connection, key, endpoint).subscribe(
+ onChange
+ );
diff --git a/test-mocha/hassio/create_session.spec.ts b/test-mocha/hassio/create_session.spec.ts
index 5fb5e7f59d..e308036eef 100644
--- a/test-mocha/hassio/create_session.spec.ts
+++ b/test-mocha/hassio/create_session.spec.ts
@@ -1,20 +1,21 @@
import * as assert from "assert";
import { createHassioSession } from "../../src/data/hassio/ingress";
-const sessionID = "fhdsu73rh3io4h8f3irhjel8ousafehf8f3yh";
-
describe("Create hassio session", function () {
+ const hass = {
+ config: { version: "1.0.0" },
+ callApi: async function () {
+ return { data: { session: "fhdsu73rh3io4h8f3irhjel8ousafehf8f3yh" } };
+ },
+ };
+
it("Test create session without HTTPS", async function () {
// @ts-ignore
global.document = {};
// @ts-ignore
global.location = {};
- await createHassioSession({
- // @ts-ignore
- callApi: async function () {
- return { data: { session: sessionID } };
- },
- });
+ // @ts-ignore
+ await createHassioSession(hass);
assert.strictEqual(
// @ts-ignore
global.document.cookie,
@@ -26,12 +27,8 @@ describe("Create hassio session", function () {
global.document = {};
// @ts-ignore
global.location = { protocol: "https:" };
- await createHassioSession({
- // @ts-ignore
- callApi: async function () {
- return { data: { session: sessionID } };
- },
- });
+ // @ts-ignore
+ await createHassioSession(hass);
assert.strictEqual(
// @ts-ignore
global.document.cookie,