Compare commits

...

3 Commits

Author SHA1 Message Date
Zack Arnett
1c3fd73738 Change OG back 2021-11-19 13:18:09 -06:00
Zack Arnett
8b81174395 Updates to Strategy 2021-11-19 13:11:40 -06:00
Zack Arnett
f3d018f047 Commiting Strategy 2021-11-17 20:17:03 -06:00
4 changed files with 294 additions and 2 deletions

View File

@@ -86,10 +86,22 @@ const splitByAreas = (
export const computeCards = (
states: Array<[string, HassEntity?]>,
entityCardOptions: Partial<EntitiesCardConfig>
entityCardOptions: Partial<EntitiesCardConfig>,
dedicated?: boolean
): LovelaceCardConfig[] => {
const cards: LovelaceCardConfig[] = [];
const sensorGrid: { type: string; cards: LovelaceCardConfig[] } = {
type: "grid",
columns: 2,
square: false,
cards: [],
};
const toggleGrid: { type: string; cards: LovelaceCardConfig[] } = {
type: "grid",
columns: 2,
square: false,
cards: [],
};
// For entity card
const entities: Array<string | LovelaceRowConfig> = [];
@@ -148,6 +160,39 @@ export const computeCards = (
stateObj?.attributes.device_class === SENSOR_DEVICE_CLASS_BATTERY
) {
// Do nothing.
} else if (dedicated) {
if (domain === "binary_sensor") {
const cardConfig = {
type: "entity",
entity: entityId,
};
sensorGrid.cards.push(cardConfig);
} else if (domain === "sensor") {
const cardConfig = {
type: "sensor",
entity: entityId,
graph: "line",
};
sensorGrid.cards.push(cardConfig);
} else if (domain === "switch") {
const cardConfig = {
type: "button",
entity: entityId,
};
toggleGrid.cards.push(cardConfig);
} else if (domain === "fan") {
const cardConfig = {
type: "button",
entity: entityId,
};
toggleGrid.cards.push(cardConfig);
} else if (domain === "light") {
const cardConfig = {
type: "light",
entity: entityId,
};
toggleGrid.cards.push(cardConfig);
}
} else {
let name: string | undefined;
const entityConf =
@@ -176,6 +221,14 @@ export const computeCards = (
});
}
if (sensorGrid.cards.length > 0) {
cards.push(sensorGrid);
}
if (toggleGrid.cards.length > 0) {
cards.push(toggleGrid);
}
return cards;
};
@@ -409,3 +462,59 @@ export const generateDefaultViewConfig = (
return config;
};
export const generateAreaViewConfig = (
area: AreaRegistryEntry,
deviceEntries: DeviceRegistryEntry[],
entityEntries: EntityRegistryEntry[],
entities: HassEntities,
localize: LocalizeFunc
): LovelaceViewConfig => {
const states = computeDefaultViewStates(entities, entityEntries);
const path = "default_view";
const title = "Home";
const icon = undefined;
// In the case of a default view, we want to use the group order attribute
const groupOrders = {};
Object.keys(states).forEach((entityId) => {
const stateObj = states[entityId];
if (stateObj.attributes.order) {
groupOrders[entityId] = stateObj.attributes.order;
}
});
const splittedByAreas = splitByAreas(
[area],
deviceEntries,
entityEntries,
states
);
const config = generateViewConfig(
localize,
path,
title,
icon,
{},
groupOrders
);
const areaCards: LovelaceCardConfig[] = [];
splittedByAreas.areasWithEntities.forEach(([a, areaEntities]) => {
areaCards.push(
...computeCards(
areaEntities.map((entity) => [entity.entity_id, entity]),
{
title: a.name,
},
true
)
);
});
config.cards!.unshift(...areaCards);
return config;
};

View File

@@ -0,0 +1,80 @@
import { STATE_NOT_RUNNING } from "home-assistant-js-websocket";
import { subscribeOne } from "../../../common/util/subscribe-one";
import { subscribeAreaRegistry } from "../../../data/area_registry";
import { subscribeDeviceRegistry } from "../../../data/device_registry";
import { subscribeEntityRegistry } from "../../../data/entity_registry";
import { LovelaceViewConfig } from "../../../data/lovelace";
import {
LovelaceDashboardStrategy,
LovelaceViewStrategy,
} from "./get-strategy";
let subscribedRegistries = false;
export class AreaOverviewStrategy {
static async generateView(
info: Parameters<LovelaceViewStrategy["generateView"]>[0]
): ReturnType<LovelaceViewStrategy["generateView"]> {
const hass = info.hass;
const view: LovelaceViewConfig = { cards: [] };
if (hass.config.state === STATE_NOT_RUNNING) {
return {
cards: [{ type: "starting" }],
};
}
if (hass.config.safe_mode) {
return {
cards: [{ type: "safe-mode" }],
};
}
// We leave this here so we always have the freshest data.
if (!subscribedRegistries) {
subscribedRegistries = true;
subscribeAreaRegistry(hass.connection, () => undefined);
subscribeDeviceRegistry(hass.connection, () => undefined);
subscribeEntityRegistry(hass.connection, () => undefined);
}
const [areaEntries] = await Promise.all([
subscribeOne(hass.connection, subscribeAreaRegistry),
]);
areaEntries.forEach((area) => {
view.cards?.push({
type: "area",
area: area.area_id,
});
});
return view;
}
static async generateDashboard(
info: Parameters<LovelaceDashboardStrategy["generateDashboard"]>[0]
): ReturnType<LovelaceDashboardStrategy["generateDashboard"]> {
const [areaEntries] = await Promise.all([
subscribeOne(info.hass.connection, subscribeAreaRegistry),
]);
const areaViews = areaEntries.map((area) => ({
strategy: {
type: "area",
options: { area_id: area.area_id },
},
title: area.name,
}));
return {
title: info.hass.config.location_name,
views: [
{
strategy: { type: "area-overview" },
title: "Overview",
},
...areaViews,
],
};
}
}

View File

@@ -0,0 +1,100 @@
import { STATE_NOT_RUNNING } from "home-assistant-js-websocket";
import { subscribeOne } from "../../../common/util/subscribe-one";
import {
AreaRegistryEntry,
subscribeAreaRegistry,
} from "../../../data/area_registry";
import {
DeviceRegistryEntry,
subscribeDeviceRegistry,
} from "../../../data/device_registry";
import { subscribeEntityRegistry } from "../../../data/entity_registry";
import { generateAreaViewConfig } from "../common/generate-lovelace-config";
import {
LovelaceDashboardStrategy,
LovelaceViewStrategy,
} from "./get-strategy";
let subscribedRegistries = false;
export class AreaStrategy {
static async generateView(
info: Parameters<LovelaceViewStrategy["generateView"]>[0]
): ReturnType<LovelaceViewStrategy["generateView"]> {
const hass = info.hass;
const areaId = info.view.strategy?.options?.area_id;
if (hass.config.state === STATE_NOT_RUNNING) {
return {
cards: [{ type: "starting" }],
};
}
if (hass.config.safe_mode) {
return {
cards: [{ type: "safe-mode" }],
};
}
let areaEntry: AreaRegistryEntry | undefined;
let deviceEntries: DeviceRegistryEntry[] | undefined;
// We leave this here so we always have the freshest data.
if (!subscribedRegistries) {
subscribedRegistries = true;
subscribeAreaRegistry(hass.connection, (areas) => {
areaEntry = areas.find((area) => area.area_id === areaId);
});
subscribeDeviceRegistry(hass.connection, (devices) => {
deviceEntries = devices.filter((device) => device.area_id === areaId);
});
subscribeEntityRegistry(hass.connection, () => undefined);
}
// eslint-disable-next-line unused-imports/no-unused-vars
const [localize, entityEntries] = await Promise.all([
hass.loadBackendTranslation("title"),
subscribeOne(hass.connection, subscribeEntityRegistry),
subscribeOne(hass.connection, subscribeAreaRegistry),
subscribeOne(hass.connection, subscribeDeviceRegistry),
]);
if (!areaEntry) {
return {
cards: [{ type: "error" }],
};
}
// User can override default view. If they didn't, we will add one
// that contains all entities.
const view = generateAreaViewConfig(
areaEntry,
deviceEntries || [],
entityEntries,
hass.states,
localize
);
// User has no entities
if (view.cards!.length === 0) {
view.cards!.push({
type: "empty-state",
});
}
return view;
}
static async generateDashboard(
info: Parameters<LovelaceDashboardStrategy["generateDashboard"]>[0]
): ReturnType<LovelaceDashboardStrategy["generateDashboard"]> {
return {
title: info.hass.config.location_name,
views: [
{
strategy: { type: "area" },
},
],
};
}
}

View File

@@ -29,6 +29,9 @@ const strategies: Record<
(await import("./original-states-strategy")).OriginalStatesStrategy,
energy: async () =>
(await import("../../energy/strategies/energy-strategy")).EnergyStrategy,
"area-overview": async () =>
(await import("./area-overview-strategy")).AreaOverviewStrategy,
area: async () => (await import("./area-strategy")).AreaStrategy,
};
const getLovelaceStrategy = async <