Merge pull request #634 from dermotduffy/diagnostics
Add a way to get diagnostics for issue reports.
This commit is contained in:
+56
-2
@@ -1,5 +1,10 @@
|
|||||||
import { getLovelace, HomeAssistant, LovelaceCardEditor } from 'custom-card-helpers';
|
import { getLovelace, HomeAssistant, LovelaceCardEditor } from 'custom-card-helpers';
|
||||||
import { CSSResultGroup, html, LitElement, PropertyValues, TemplateResult, unsafeCSS } from 'lit';
|
import {
|
||||||
|
CSSResultGroup,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
PropertyValues, TemplateResult, unsafeCSS
|
||||||
|
} from 'lit';
|
||||||
import { customElement, property, state } from 'lit/decorators.js';
|
import { customElement, property, state } from 'lit/decorators.js';
|
||||||
import { classMap } from 'lit/directives/class-map.js';
|
import { classMap } from 'lit/directives/class-map.js';
|
||||||
import { createRef, ref, Ref } from 'lit/directives/ref.js';
|
import { createRef, ref, Ref } from 'lit/directives/ref.js';
|
||||||
@@ -77,6 +82,7 @@ import {
|
|||||||
sideLoadHomeAssistantElements
|
sideLoadHomeAssistantElements
|
||||||
} from './utils/ha';
|
} from './utils/ha';
|
||||||
import { getEventID } from './utils/ha/browse-media.js';
|
import { getEventID } from './utils/ha/browse-media.js';
|
||||||
|
import { DeviceList, getAllDevices } from './utils/ha/device-registry.js';
|
||||||
import {
|
import {
|
||||||
ExtendedEntityCache,
|
ExtendedEntityCache,
|
||||||
getAllEntities,
|
getAllEntities,
|
||||||
@@ -146,6 +152,7 @@ export class FrigateCard extends LitElement {
|
|||||||
// card-mod.
|
// card-mod.
|
||||||
@state()
|
@state()
|
||||||
protected _config!: FrigateCardConfig;
|
protected _config!: FrigateCardConfig;
|
||||||
|
protected _rawConfig?: RawFrigateCardConfig;
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
protected _overriddenConfig?: FrigateCardConfig;
|
protected _overriddenConfig?: FrigateCardConfig;
|
||||||
@@ -344,6 +351,9 @@ export class FrigateCard extends LitElement {
|
|||||||
tap_action: FrigateCardMenu.isHidingMenu(this._getConfig().menu)
|
tap_action: FrigateCardMenu.isHidingMenu(this._getConfig().menu)
|
||||||
? (createFrigateCardCustomAction('menu_toggle') as FrigateCardCustomAction)
|
? (createFrigateCardCustomAction('menu_toggle') as FrigateCardCustomAction)
|
||||||
: (createFrigateCardCustomAction('default') as FrigateCardCustomAction),
|
: (createFrigateCardCustomAction('default') as FrigateCardCustomAction),
|
||||||
|
hold_action: createFrigateCardCustomAction(
|
||||||
|
'diagnostics',
|
||||||
|
) as FrigateCardCustomAction,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this._cameras && this._cameras.size > 1) {
|
if (this._cameras && this._cameras.size > 1) {
|
||||||
@@ -860,6 +870,7 @@ export class FrigateCard extends LitElement {
|
|||||||
getLovelace().setEditMode(true);
|
getLovelace().setEditMode(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._rawConfig = inputConfig;
|
||||||
this._config = config;
|
this._config = config;
|
||||||
this._overriddenConfig = undefined;
|
this._overriddenConfig = undefined;
|
||||||
this._cameras = undefined;
|
this._cameras = undefined;
|
||||||
@@ -1014,7 +1025,7 @@ export class FrigateCard extends LitElement {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine if the scan mode is currently triggered.
|
* Determine if the scan mode is currently triggered.
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
protected _isTriggered(): boolean {
|
protected _isTriggered(): boolean {
|
||||||
return !!this._triggers.size || !!this._untriggerTimerID;
|
return !!this._triggers.size || !!this._untriggerTimerID;
|
||||||
@@ -1296,11 +1307,54 @@ export class FrigateCard extends LitElement {
|
|||||||
frigateCardAction.media_player_action,
|
frigateCardAction.media_player_action,
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
|
case 'diagnostics':
|
||||||
|
this._diagnostics();
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
console.warn(`Frigate card received unknown card action: ${action}`);
|
console.warn(`Frigate card received unknown card action: ${action}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate diagnostics for issue reports.
|
||||||
|
*/
|
||||||
|
protected async _diagnostics(): Promise<void> {
|
||||||
|
if (this._hass) {
|
||||||
|
let devices: DeviceList = [];
|
||||||
|
try {
|
||||||
|
devices = await getAllDevices(this._hass);
|
||||||
|
} catch (e) {
|
||||||
|
// Pass. This is optional.
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the Frigate devices in order to extract the Frigate integration and
|
||||||
|
// server version numbers.
|
||||||
|
const frigateDevices = devices.filter(
|
||||||
|
(device) => device.manufacturer === 'Frigate',
|
||||||
|
);
|
||||||
|
const frigateVersionMap: Map<string, string> = new Map();
|
||||||
|
frigateDevices.forEach((device) => {
|
||||||
|
device.config_entries.forEach((configEntry) => {
|
||||||
|
if (device.model) {
|
||||||
|
frigateVersionMap.set(configEntry, device.model);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
this._setMessageAndUpdate({
|
||||||
|
message: localize('error.diagnostics'),
|
||||||
|
type: 'info',
|
||||||
|
icon: 'mdi:information',
|
||||||
|
context: {
|
||||||
|
ha_version: this._hass.config.version,
|
||||||
|
card_version: CARD_VERSION,
|
||||||
|
frigate_version: Object.fromEntries(frigateVersionMap),
|
||||||
|
...(this._rawConfig && { config: this._rawConfig }),
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the Frigate UI URL from context.
|
* Get the Frigate UI URL from context.
|
||||||
* @returns The URL or null if unavailable.
|
* @returns The URL or null if unavailable.
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ export function renderProgressIndicator(message?: string): TemplateResult {
|
|||||||
* @param icon An optional icon to attach to the message.
|
* @param icon An optional icon to attach to the message.
|
||||||
*/
|
*/
|
||||||
export function dispatchMessageEvent(
|
export function dispatchMessageEvent(
|
||||||
element: HTMLElement,
|
element: EventTarget,
|
||||||
message: string,
|
message: string,
|
||||||
icon?: string,
|
icon?: string,
|
||||||
context?: unknown,
|
context?: unknown,
|
||||||
@@ -130,7 +130,7 @@ export function dispatchMessageEvent(
|
|||||||
* @param message The message to show.
|
* @param message The message to show.
|
||||||
*/
|
*/
|
||||||
export function dispatchErrorMessageEvent(
|
export function dispatchErrorMessageEvent(
|
||||||
element: HTMLElement,
|
element: EventTarget,
|
||||||
message: string,
|
message: string,
|
||||||
context?: unknown,
|
context?: unknown,
|
||||||
): void {
|
): void {
|
||||||
@@ -147,7 +147,7 @@ export function dispatchErrorMessageEvent(
|
|||||||
* @param message The message to show.
|
* @param message The message to show.
|
||||||
*/
|
*/
|
||||||
export function dispatchFrigateCardErrorEvent(
|
export function dispatchFrigateCardErrorEvent(
|
||||||
element: HTMLElement,
|
element: EventTarget,
|
||||||
error: FrigateCardError
|
error: FrigateCardError
|
||||||
): void {
|
): void {
|
||||||
dispatchFrigateCardEvent<Message>(element, 'message', {
|
dispatchFrigateCardEvent<Message>(element, 'message', {
|
||||||
|
|||||||
@@ -306,6 +306,7 @@
|
|||||||
"no_thumbnail": "No thumbnail available"
|
"no_thumbnail": "No thumbnail available"
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
|
"diagnostics": "Card diagnostics. Please review for confidential information prior to sharing",
|
||||||
"undecodable_response": "Could not decode response from Home Assistant for request",
|
"undecodable_response": "Could not decode response from Home Assistant for request",
|
||||||
"empty_response": "Received empty response from Home Assistant for request",
|
"empty_response": "Received empty response from Home Assistant for request",
|
||||||
"invalid_response": "Received invalid response from Home Assistant for request",
|
"invalid_response": "Received invalid response from Home Assistant for request",
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ div.message {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding: 10%;
|
padding: 20px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -204,6 +204,7 @@ const FRIGATE_CARD_GENERAL_ACTIONS = [
|
|||||||
'frigate_ui',
|
'frigate_ui',
|
||||||
'fullscreen',
|
'fullscreen',
|
||||||
'menu_toggle',
|
'menu_toggle',
|
||||||
|
'diagnostics',
|
||||||
] as const;
|
] as const;
|
||||||
const FRIGATE_CARD_ACTIONS = [
|
const FRIGATE_CARD_ACTIONS = [
|
||||||
...FRIGATE_CARD_GENERAL_ACTIONS,
|
...FRIGATE_CARD_GENERAL_ACTIONS,
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
import { HomeAssistant } from 'custom-card-helpers';
|
||||||
|
import { z } from 'zod';
|
||||||
|
import { homeAssistantWSRequest } from '.';
|
||||||
|
|
||||||
|
const deviceSchema = z.object({
|
||||||
|
model: z.string().nullable(),
|
||||||
|
config_entries: z.string().array(),
|
||||||
|
manufacturer: z.string().nullable(),
|
||||||
|
})
|
||||||
|
export const deviceListSchema = deviceSchema.array();
|
||||||
|
export type DeviceList = z.infer<typeof deviceListSchema>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a list of all entities from the entity registry. May throw.
|
||||||
|
* @param hass The Home Assistant object.
|
||||||
|
* @returns An entity list object.
|
||||||
|
*/
|
||||||
|
export const getAllDevices = async (hass: HomeAssistant): Promise<DeviceList> => {
|
||||||
|
return await homeAssistantWSRequest<DeviceList>(hass, deviceListSchema, {
|
||||||
|
type: 'config/device_registry/list',
|
||||||
|
});
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user