Use signed path for camera snapshot (#3138)

This commit is contained in:
Paulus Schoutsen 2019-04-29 11:27:40 -07:00 committed by GitHub
parent 1e85880d7b
commit 73ef03e33f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 58 additions and 42 deletions

View File

@ -6,7 +6,7 @@ import "@polymer/paper-icon-button/paper-icon-button";
import "@polymer/paper-input/paper-input"; import "@polymer/paper-input/paper-input";
import { html } from "@polymer/polymer/lib/utils/html-tag"; import { html } from "@polymer/polymer/lib/utils/html-tag";
import { PolymerElement } from "@polymer/polymer/polymer-element"; import { PolymerElement } from "@polymer/polymer/polymer-element";
import { getSignedPath } from "../../../../src/auth/data"; import { getSignedPath } from "../../../../src/data/auth";
import "../../../../src/resources/ha-style"; import "../../../../src/resources/ha-style";
import "../../../../src/components/dialog/ha-paper-dialog"; import "../../../../src/components/dialog/ha-paper-dialog";

View File

@ -1,7 +0,0 @@
import { HomeAssistant } from "../types";
import { SignedPath } from "./types";
export const getSignedPath = (
hass: HomeAssistant,
path: string
): Promise<SignedPath> => hass.callWS({ type: "auth/sign_path", path });

View File

@ -1,3 +0,0 @@
export interface SignedPath {
path: string;
}

View File

@ -5,6 +5,7 @@ import { PolymerElement } from "@polymer/polymer/polymer-element";
import computeStateName from "../common/entity/compute_state_name"; import computeStateName from "../common/entity/compute_state_name";
import EventsMixin from "../mixins/events-mixin"; import EventsMixin from "../mixins/events-mixin";
import LocalizeMixin from "../mixins/localize-mixin"; import LocalizeMixin from "../mixins/localize-mixin";
import { fetchThumbnailUrlWithCache } from "../data/camera";
const UPDATE_INTERVAL = 10000; // ms const UPDATE_INTERVAL = 10000; // ms
/* /*
@ -54,6 +55,8 @@ class HaCameraCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
src="[[cameraFeedSrc]]" src="[[cameraFeedSrc]]"
class="camera-feed" class="camera-feed"
alt="[[_computeStateName(stateObj)]]" alt="[[_computeStateName(stateObj)]]"
on-load="_imageLoaded"
on-error="_imageError"
/> />
</template> </template>
<div class="caption"> <div class="caption">
@ -98,23 +101,23 @@ class HaCameraCard extends LocalizeMixin(EventsMixin(PolymerElement)) {
clearInterval(this.timer); clearInterval(this.timer);
} }
_imageLoaded() {
this.imageLoaded = true;
}
_imageError() {
this.imageLoaded = false;
}
cardTapped() { cardTapped() {
this.fire("hass-more-info", { entityId: this.stateObj.entity_id }); this.fire("hass-more-info", { entityId: this.stateObj.entity_id });
} }
async updateCameraFeedSrc() { async updateCameraFeedSrc() {
try { this.cameraFeedSrc = await fetchThumbnailUrlWithCache(
const { content_type: contentType, content } = await this.hass.callWS({ this.hass,
type: "camera_thumbnail", this.stateObj.entity_id
entity_id: this.stateObj.entity_id, );
});
this.setProperties({
imageLoaded: true,
cameraFeedSrc: `data:${contentType};base64, ${content}`,
});
} catch (err) {
this.imageLoaded = false;
}
} }
_computeStateName(stateObj) { _computeStateName(stateObj) {

View File

@ -1,3 +1,5 @@
import { HomeAssistant } from "../types";
export interface AuthProvider { export interface AuthProvider {
name: string; name: string;
id: string; id: string;
@ -7,3 +9,12 @@ export interface AuthProvider {
export interface Credential { export interface Credential {
type: string; type: string;
} }
export interface SignedPath {
path: string;
}
export const getSignedPath = (
hass: HomeAssistant,
path: string
): Promise<SignedPath> => hass.callWS({ type: "auth/sign_path", path });

View File

@ -1,5 +1,6 @@
import { HomeAssistant, CameraEntity } from "../types"; import { HomeAssistant, CameraEntity } from "../types";
import { timeCachePromiseFunc } from "../common/util/time-cache-function-promise"; import { timeCachePromiseFunc } from "../common/util/time-cache-function-promise";
import { getSignedPath } from "./auth";
export const CAMERA_SUPPORT_ON_OFF = 1; export const CAMERA_SUPPORT_ON_OFF = 1;
export const CAMERA_SUPPORT_STREAM = 2; export const CAMERA_SUPPORT_STREAM = 2;
@ -22,16 +23,29 @@ export const computeMJPEGStreamUrl = (entity: CameraEntity) =>
entity.attributes.access_token entity.attributes.access_token
}`; }`;
export const fetchThumbnailWithCache = ( export const fetchThumbnailUrlWithCache = (
hass: HomeAssistant, hass: HomeAssistant,
entityId: string entityId: string
) => timeCachePromiseFunc("_cameraTmb", 9000, fetchThumbnail, hass, entityId); ) =>
timeCachePromiseFunc(
"_cameraTmbUrl",
9000,
fetchThumbnailUrl,
hass,
entityId
);
export const fetchThumbnail = (hass: HomeAssistant, entityId: string) => export const fetchThumbnailUrl = (hass: HomeAssistant, entityId: string) =>
hass.callWS<CameraThumbnail>({ getSignedPath(hass, `/api/camera_proxy/${entityId}`).then(({ path }) => path);
export const fetchThumbnail = (hass: HomeAssistant, entityId: string) => {
// tslint:disable-next-line: no-console
console.warn("This method has been deprecated.");
return hass.callWS<CameraThumbnail>({
type: "camera_thumbnail", type: "camera_thumbnail",
entity_id: entityId, entity_id: entityId,
}); });
};
export const fetchStreamUrl = ( export const fetchStreamUrl = (
hass: HomeAssistant, hass: HomeAssistant,

View File

@ -17,8 +17,7 @@ import {
import { HomeAssistant, CameraEntity } from "../../../types"; import { HomeAssistant, CameraEntity } from "../../../types";
import { styleMap } from "lit-html/directives/style-map"; import { styleMap } from "lit-html/directives/style-map";
import { classMap } from "lit-html/directives/class-map"; import { classMap } from "lit-html/directives/class-map";
import { b64toBlob } from "../../../common/file/b64-to-blob"; import { fetchThumbnailUrlWithCache } from "../../../data/camera";
import { fetchThumbnailWithCache } from "../../../data/camera";
const UPDATE_INTERVAL = 10000; const UPDATE_INTERVAL = 10000;
const DEFAULT_FILTER = "grayscale(100%)"; const DEFAULT_FILTER = "grayscale(100%)";
@ -197,21 +196,20 @@ export class HuiImage extends LitElement {
if (!this.hass || !this.cameraImage) { if (!this.hass || !this.cameraImage) {
return; return;
} }
try {
const { const cameraState = this.hass.states[this.cameraImage] as
content_type: contentType, | CameraEntity
content, | undefined;
} = await fetchThumbnailWithCache(this.hass, this.cameraImage);
if (this._cameraImageSrc) { if (!cameraState) {
URL.revokeObjectURL(this._cameraImageSrc);
}
this._cameraImageSrc = URL.createObjectURL(
b64toBlob(content, contentType)
);
this._onImageLoad();
} catch (err) {
this._onImageError(); this._onImageError();
return;
} }
this._cameraImageSrc = await fetchThumbnailUrlWithCache(
this.hass,
this.cameraImage
);
} }
static get styles(): CSSResult { static get styles(): CSSResult {