Skip to content

Commit

Permalink
Merge branch 'dev' into flat-config
Browse files Browse the repository at this point in the history
  • Loading branch information
silamon authored Oct 6, 2024
2 parents a312dcd + b8889a1 commit 057a446
Show file tree
Hide file tree
Showing 9 changed files with 768 additions and 791 deletions.
14 changes: 7 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
"license": "Apache-2.0",
"type": "module",
"dependencies": {
"@babel/runtime": "7.25.6",
"@babel/runtime": "7.25.7",
"@braintree/sanitize-url": "7.1.0",
"@codemirror/autocomplete": "6.18.1",
"@codemirror/commands": "6.6.2",
Expand Down Expand Up @@ -104,7 +104,7 @@
"core-js": "3.38.1",
"cropperjs": "1.6.2",
"date-fns": "4.1.0",
"date-fns-tz": "3.1.3",
"date-fns-tz": "3.2.0",
"deep-clone-simple": "1.1.1",
"deep-freeze": "0.0.1",
"dialog-polyfill": "0.5.6",
Expand Down Expand Up @@ -151,12 +151,12 @@
"xss": "1.0.15"
},
"devDependencies": {
"@babel/core": "7.25.2",
"@babel/core": "7.25.7",
"@babel/helper-define-polyfill-provider": "0.6.2",
"@babel/plugin-proposal-decorators": "7.24.7",
"@babel/plugin-transform-runtime": "7.25.4",
"@babel/preset-env": "7.25.4",
"@babel/preset-typescript": "7.24.7",
"@babel/plugin-proposal-decorators": "7.25.7",
"@babel/plugin-transform-runtime": "7.25.7",
"@babel/preset-env": "7.25.7",
"@babel/preset-typescript": "7.25.7",
"@bundle-stats/plugin-webpack-filter": "4.15.1",
"@koa/cors": "5.0.0",
"@lokalise/node-api": "12.7.0",
Expand Down
47 changes: 37 additions & 10 deletions src/components/ha-web-rtc-player.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable no-console */
import {
css,
CSSResultGroup,
Expand All @@ -6,12 +7,13 @@ import {
PropertyValues,
TemplateResult,
} from "lit";
import { customElement, property, state, query } from "lit/decorators";
import { customElement, property, query, state } from "lit/decorators";
import { ifDefined } from "lit/directives/if-defined";
import { fireEvent } from "../common/dom/fire_event";
import {
fetchWebRtcClientConfiguration,
handleWebRtcOffer,
WebRtcAnswer,
fetchWebRtcClientConfiguration,
} from "../data/camera";
import type { HomeAssistant } from "../types";
import "./ha-alert";
Expand Down Expand Up @@ -39,12 +41,11 @@ class HaWebRtcPlayer extends LitElement {
@property({ type: Boolean, attribute: "playsinline" })
public playsInline = false;

@property() public posterUrl!: string;
@property({ attribute: "poster-url" }) public posterUrl?: string;

@state() private _error?: string;

// don't cache this, as we remove it on disconnects
@query("#remote-stream") private _videoEl!: HTMLVideoElement;
@query("#remote-stream", true) private _videoEl!: HTMLVideoElement;

private _peerConnection?: RTCPeerConnection;

Expand All @@ -61,7 +62,7 @@ class HaWebRtcPlayer extends LitElement {
.muted=${this.muted}
?playsinline=${this.playsInline}
?controls=${this.controls}
.poster=${this.posterUrl}
poster=${ifDefined(this.posterUrl)}
@loadeddata=${this._loadedData}
></video>
`;
Expand All @@ -83,20 +84,23 @@ class HaWebRtcPlayer extends LitElement {
if (!changedProperties.has("entityid")) {
return;
}
if (!this._videoEl) {
return;
}
this._startWebRtc();
}

private async _startWebRtc(): Promise<void> {
console.time("WebRTC");

this._error = undefined;

console.timeLog("WebRTC", "start clientConfig");

const clientConfig = await fetchWebRtcClientConfiguration(
this.hass,
this.entityid
);

console.timeLog("WebRTC", "end clientConfig", clientConfig);

const peerConnection = new RTCPeerConnection(clientConfig.configuration);

if (clientConfig.dataChannel) {
Expand All @@ -111,30 +115,48 @@ class HaWebRtcPlayer extends LitElement {
offerToReceiveAudio: true,
offerToReceiveVideo: true,
};

console.timeLog("WebRTC", "start createOffer", offerOptions);

const offer: RTCSessionDescriptionInit =
await peerConnection.createOffer(offerOptions);

console.timeLog("WebRTC", "end createOffer", offer);

console.timeLog("WebRTC", "start setLocalDescription");

await peerConnection.setLocalDescription(offer);

console.timeLog("WebRTC", "end setLocalDescription");

console.timeLog("WebRTC", "start iceResolver");

let candidates = ""; // Build an Offer SDP string with ice candidates
const iceResolver = new Promise<void>((resolve) => {
peerConnection.addEventListener("icecandidate", async (event) => {
peerConnection.addEventListener("icecandidate", (event) => {
if (!event.candidate?.candidate) {
resolve(); // Gathering complete
return;
}
console.timeLog("WebRTC", "iceResolver candidate", event.candidate);
candidates += `a=${event.candidate.candidate}\r\n`;
});
});
await iceResolver;

console.timeLog("WebRTC", "end iceResolver", candidates);

const offer_sdp = offer.sdp! + candidates;

let webRtcAnswer: WebRtcAnswer;
try {
console.timeLog("WebRTC", "start WebRTCOffer", offer_sdp);
webRtcAnswer = await handleWebRtcOffer(
this.hass,
this.entityid,
offer_sdp
);
console.timeLog("WebRTC", "end webRtcOffer", webRtcAnswer);
} catch (err: any) {
this._error = "Failed to start WebRTC stream: " + err.message;
peerConnection.close();
Expand All @@ -144,6 +166,7 @@ class HaWebRtcPlayer extends LitElement {
// Setup callbacks to render remote stream once media tracks are discovered.
const remoteStream = new MediaStream();
peerConnection.addEventListener("track", (event) => {
console.timeLog("WebRTC", "track", event);
remoteStream.addTrack(event.track);
this._videoEl.srcObject = remoteStream;
});
Expand All @@ -155,7 +178,9 @@ class HaWebRtcPlayer extends LitElement {
sdp: webRtcAnswer.answer,
});
try {
console.timeLog("WebRTC", "start setRemoteDescription", remoteDesc);
await peerConnection.setRemoteDescription(remoteDesc);
console.timeLog("WebRTC", "end setRemoteDescription");
} catch (err: any) {
this._error = "Failed to connect WebRTC stream: " + err.message;
peerConnection.close();
Expand All @@ -182,6 +207,8 @@ class HaWebRtcPlayer extends LitElement {
}

private _loadedData() {
console.timeLog("WebRTC", "loadedData");
console.timeEnd("WebRTC");
// @ts-ignore
fireEvent(this, "load");
}
Expand Down
81 changes: 9 additions & 72 deletions src/dialogs/config-flow/dialog-data-entry-flow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,15 @@ import {
html,
nothing,
} from "lit";
import { customElement, state } from "lit/decorators";
import { customElement, property, state } from "lit/decorators";
import { HASSDomEvent, fireEvent } from "../../common/dom/fire_event";
import "../../components/ha-circular-progress";
import "../../components/ha-dialog";
import "../../components/ha-icon-button";
import {
AreaRegistryEntry,
subscribeAreaRegistry,
} from "../../data/area_registry";
import {
DataEntryFlowStep,
subscribeDataEntryFlowProgressed,
} from "../../data/data_entry_flow";
import {
DeviceRegistryEntry,
subscribeDeviceRegistry,
} from "../../data/device_registry";
import { haStyleDialog } from "../../resources/styles";
import type { HomeAssistant } from "../../types";
import { documentationUrl } from "../../util/documentation-url";
Expand Down Expand Up @@ -62,7 +54,7 @@ declare global {

@customElement("dialog-data-entry-flow")
class DataEntryFlowDialog extends LitElement {
public hass!: HomeAssistant;
@property({ attribute: false }) public hass!: HomeAssistant;

@state() private _params?: DataEntryFlowDialogParams;

Expand All @@ -76,16 +68,8 @@ class DataEntryFlowDialog extends LitElement {
// Null means we need to pick a config flow
| null;

@state() private _devices?: DeviceRegistryEntry[];

@state() private _areas?: AreaRegistryEntry[];

@state() private _handler?: string;

private _unsubAreas?: UnsubscribeFunc;

private _unsubDevices?: UnsubscribeFunc;

private _unsubDataEntryFlowProgressed?: Promise<UnsubscribeFunc>;

public async showDialog(params: DataEntryFlowDialogParams): Promise<void> {
Expand Down Expand Up @@ -183,16 +167,7 @@ class DataEntryFlowDialog extends LitElement {
this._loading = undefined;
this._step = undefined;
this._params = undefined;
this._devices = undefined;
this._handler = undefined;
if (this._unsubAreas) {
this._unsubAreas();
this._unsubAreas = undefined;
}
if (this._unsubDevices) {
this._unsubDevices();
this._unsubDevices = undefined;
}
if (this._unsubDataEntryFlowProgressed) {
this._unsubDataEntryFlowProgressed.then((unsub) => {
unsub();
Expand Down Expand Up @@ -309,25 +284,13 @@ class DataEntryFlowDialog extends LitElement {
.hass=${this.hass}
></step-flow-menu>
`
: this._devices === undefined ||
this._areas === undefined
? // When it's a create entry result, we will fetch device & area registry
html`
<step-flow-loading
.flowConfig=${this._params.flowConfig}
.hass=${this.hass}
loadingReason="loading_devices_areas"
></step-flow-loading>
`
: html`
<step-flow-create-entry
.flowConfig=${this._params.flowConfig}
.step=${this._step}
.hass=${this.hass}
.devices=${this._devices}
.areas=${this._areas}
></step-flow-create-entry>
`}
: html`
<step-flow-create-entry
.flowConfig=${this._params.flowConfig}
.step=${this._step}
.hass=${this.hass}
></step-flow-create-entry>
`}
`}
</div>
</ha-dialog>
Expand All @@ -351,32 +314,6 @@ class DataEntryFlowDialog extends LitElement {
// external and progress step will send update event from the backend, so we should subscribe to them
this._subscribeDataEntryFlowProgressed();
}
if (this._step.type === "create_entry") {
if (this._step.result && this._params!.flowConfig.loadDevicesAndAreas) {
this._fetchDevices(this._step.result.entry_id);
this._fetchAreas();
} else {
this._devices = [];
this._areas = [];
}
}
}

private async _fetchDevices(configEntryId) {
this._unsubDevices = subscribeDeviceRegistry(
this.hass.connection,
(devices) => {
this._devices = devices.filter((device) =>
device.config_entries.includes(configEntryId)
);
}
);
}

private async _fetchAreas() {
this._unsubAreas = subscribeAreaRegistry(this.hass.connection, (areas) => {
this._areas = areas;
});
}

private async _processStep(
Expand Down
2 changes: 1 addition & 1 deletion src/dialogs/config-flow/show-dialog-config-flow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export const showConfigFlowDialog = (
): void =>
showFlowDialog(element, dialogParams, {
flowType: "config_flow",
loadDevicesAndAreas: true,
showDevices: true,
createFlow: async (hass, handler) => {
const [step] = await Promise.all([
createConfigFlow(hass, handler, dialogParams.entryId),
Expand Down
5 changes: 2 additions & 3 deletions src/dialogs/config-flow/show-dialog-data-entry-flow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import type { HomeAssistant } from "../../types";
export interface FlowConfig {
flowType: FlowType;

loadDevicesAndAreas: boolean;
showDevices: boolean;

createFlow(hass: HomeAssistant, handler: string): Promise<DataEntryFlowStep>;

Expand Down Expand Up @@ -134,8 +134,7 @@ export interface FlowConfig {
export type LoadingReason =
| "loading_handlers"
| "loading_flow"
| "loading_step"
| "loading_devices_areas";
| "loading_step";

export interface DataEntryFlowDialogParams {
startFlowHandler?: string;
Expand Down
2 changes: 1 addition & 1 deletion src/dialogs/config-flow/show-dialog-options-flow.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ export const showOptionsFlowDialog = (
},
{
flowType: "options_flow",
loadDevicesAndAreas: false,
showDevices: false,
createFlow: async (hass, handler) => {
const [step] = await Promise.all([
createOptionsFlow(hass, handler),
Expand Down
Loading

0 comments on commit 057a446

Please sign in to comment.