Cleanup and reorg.

This commit is contained in:
Christoph Giesche
2023-01-11 23:56:18 +01:00
parent 4dc1d4bffc
commit 7f61b2b566
10 changed files with 4562 additions and 53 deletions

View File

@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2021 Christoph Giesche
Copyright (c) 2023 Christoph Giesche
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

4483
doc/services.json Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -47,7 +47,7 @@
<b-form-group
label="Domain"
label-for="domain"
description="The domain of the entity you want to configure">
description="The domain of the entity you want to display">
<b-form-select size="sm" id="domain" v-on:change="service = null; entity = null" v-model="domain"
:options="availableEntityDomains"></b-form-select>
</b-form-group>
@@ -55,12 +55,13 @@
<b-form-group
label="Entity"
label-for="entity"
description="The id of the entity you want to configure"
description="The entity you want to display"
v-if="domainEntities.length > 0">
<b-form-select size="sm" id="entity" v-on:change="service = null; serviceLongPress = null;" v-model="entity"
:options="domainEntities"
value-field="value.entityId"
text-field="text"></b-form-select>
text-field="title"
value-field="entityId">
</b-form-select>
</b-form-group>
<b-form-checkbox
@@ -125,7 +126,8 @@ Line 4 (may overlap with title)">
<b-form-group
label="Service domain"
label-for="serviceDomain">
<b-form-select size="sm" id="serviceDomain" v-on:change="service = null; serviceData = null;" v-model="serviceDomain"
<b-form-select size="sm" id="serviceDomain" v-on:change="service = null; serviceData = null;"
v-model="serviceDomain"
:options="availableServiceDomains"></b-form-select>
</b-form-group>
@@ -135,7 +137,8 @@ Line 4 (may overlap with title)">
description="(Optional) Service that should be called when the stream deck button is pressed."
v-if="serviceDomainServices.length > 0">
<b-input-group>
<b-form-select size="sm" id="service" v-model="service" :options="serviceDomainServices" value-field="serviceId"
<b-form-select size="sm" id="service" v-model="service" :options="serviceDomainServices"
value-field="serviceId"
text-field="serviceId"></b-form-select>
<b-input-group-append>
<b-button size="sm" v-on:click="service = null">Clear</b-button>
@@ -164,7 +167,8 @@ Line 4 (may overlap with title)">
<b-form-group
label="Service (long press) domain"
label-for="serviceLongPressDomain">
<b-form-select size="sm" id="serviceLongPressDomain" v-on:change="service = null;" v-model="serviceLongPressDomain"
<b-form-select size="sm" id="serviceLongPressDomain" v-on:change="service = null;"
v-model="serviceLongPressDomain"
:options="availableServiceDomains"></b-form-select>
</b-form-group>
@@ -174,7 +178,8 @@ Line 4 (may overlap with title)">
description="(Optional) Service that will be called when the stream deck button is pressed and held for longer than 300ms."
v-if="serviceLongPressDomainServices.length > 0">
<b-input-group>
<b-form-select size="sm" id="serviceLongPress" v-model="serviceLongPress" :options="serviceLongPressDomainServices"
<b-form-select size="sm" id="serviceLongPress" v-model="serviceLongPress"
:options="serviceLongPressDomainServices"
value-field="serviceId"
text-field="serviceId"></b-form-select>
<b-input-group-append>
@@ -268,7 +273,7 @@ import StreamDeck from "@/modules/common/streamdeck";
import {ObjectUtils} from "@/modules/common/utils";
import {Homeassistant} from "@/modules/homeassistant/homeassistant";
import {Settings} from "@/modules/common/settings";
import {Entity} from "@/modules/homeassistant/entity";
import {Entity} from "@/modules/pi/entity";
export default {
name: 'PiComponent',
@@ -421,12 +426,11 @@ export default {
},
domainEntities: function () {
return this.availableEntities
.filter((entityInfo) => entityInfo.value.domain === this.domain)
return this.availableEntities.filter((entity) => entity.domain === this.domain)
},
entityAttributes: function () {
let currentEntityState = this.currentStates.find((state) => state.entity.entityId === this.entity)
let currentEntityState = this.currentStates.find((state) => state.entityId === this.entity)
if (currentEntityState && currentEntityState.attributes) {
return "{{state}}, " + currentEntityState.attributes
.map(attribute => `{{${attribute}}}`)
@@ -448,24 +452,22 @@ export default {
this.haConnected = true;
this.$HA.getStates((states) => {
this.availableEntityDomains = Array.from(states
.map(state => new Entity(state.entity_id).domain)
.map(state => state.entity_id.split('.')[0])
.reduce((acc, curr) => acc.add(curr), new Set()))
.sort();
this.availableEntities = states
.map((state) => {
return {
value: new Entity(state.entity_id),
text: state.attributes.friendly_name || state.entity_id
}
let splittedId = state.entity_id.split('.');
return new Entity(splittedId[0], splittedId[1], state.attributes.friendly_name || state.entity_id)
}
)
.sort((a, b) => (a.text.toLowerCase() > b.text.toLowerCase()) ? 1 : ((b.text.toLowerCase() > a.text.toLowerCase()) ? -1 : 0))
.sort((a, b) => (a.title.toLowerCase() > b.title.toLowerCase()) ? 1 : ((b.title.toLowerCase() > a.title.toLowerCase()) ? -1 : 0))
this.currentStates = states
.map((state) => {
return {
entity: new Entity(state.entity_id),
entityId: state.entity_id,
attributes: ObjectUtils.paths(state.attributes)
}
})

View File

@@ -8,7 +8,6 @@ import {Homeassistant} from "@/modules/homeassistant/homeassistant";
import {EntityButtonImageFactory, EntityConfigFactory} from "@/modules/plugin/entityButtonImageFactory";
import nunjucks from "nunjucks"
import {Settings} from "@/modules/common/settings";
import {Entity} from "@/modules/homeassistant/entity";
export default {
name: 'PluginComponent',
@@ -130,11 +129,10 @@ export default {
if (this.$HA) {
if (serviceToCall) {
try {
const entity = new Entity(settings.display.entityId);
const serviceData = serviceToCall.data ? JSON.parse(serviceToCall.data) : {};
// add default entity_id if not specified
if (!serviceData.entity_id) {
serviceData.entity_id = entity.entityId;
serviceData.entity_id = settings.display.entityId;
}
this.$HA.callService(serviceToCall.name, serviceToCall.domain, serviceData)
} catch (e) {
@@ -167,15 +165,15 @@ export default {
}
const updateState = (stateMessage) => {
let entity = new Entity(stateMessage.entity_id)
let changedContexts = Object.keys(this.actionSettings).filter(key => this.actionSettings[key].display.entityId === entity.entityId)
let domain = stateMessage.entity_id.split('.')[0]
let changedContexts = Object.keys(this.actionSettings).filter(key => this.actionSettings[key].display.entityId === stateMessage.entity_id)
changedContexts.forEach(context => {
try {
if(stateMessage.last_updated != null) stateMessage.attributes["last_updated"] = new Date(stateMessage.last_updated).toLocaleTimeString();
if(stateMessage.last_changed != null) stateMessage.attributes["last_changed"] = new Date(stateMessage.last_changed).toLocaleTimeString();
updateContextState(context, entity, stateMessage);
updateContextState(context, domain, stateMessage);
} catch (e) {
console.error(e)
this.$SD.setImage(context, null);
@@ -184,14 +182,14 @@ export default {
})
}
const updateContextState = (currentContext, entity, stateObject) => {
const updateContextState = (currentContext, domain, stateObject) => {
let contextSettings = this.actionSettings[currentContext]
let labelTemplates = null;
if (contextSettings.display.useCustomButtonLabels && contextSettings.display.buttonLabels) {
labelTemplates = contextSettings.display.buttonLabels.split("\n");
}
let entityConfig = this.entityConfigFactory.determineConfig(entity.domain, stateObject, labelTemplates)
let entityConfig = this.entityConfigFactory.determineConfig(domain, stateObject, labelTemplates)
entityConfig.isAction = contextSettings.button.service.name && (contextSettings.display.enableServiceIndicator === undefined || contextSettings.display.enableServiceIndicator) // undefined = on by default
entityConfig.isMultiAction = contextSettings.button.serviceLongPress.name && (contextSettings.display.enableServiceIndicator === undefined || contextSettings.display.enableServiceIndicator) // undefined = on by default

View File

@@ -1,21 +0,0 @@
export class Entity {
#entityId
constructor(entityId) {
this.#entityId = entityId
}
get domain() {
return this.#entityId.split(".")[0]
}
get name() {
return this.#entityId.split(".")[1];
}
get entityId() {
return this.#entityId;
}
}

29
src/modules/pi/entity.js Normal file
View File

@@ -0,0 +1,29 @@
export class Entity {
#domain
#name
#title
constructor(domain, name, title) {
this.#domain = domain
this.#name = name
this.#title = title
}
get entityId() {
return `${this.#domain}.${this.#name}`;
}
get domain() {
return this.#domain
}
get name() {
return this.#name
}
get title() {
return this.#title
}
}

12
src/modules/pi/service.js Normal file
View File

@@ -0,0 +1,12 @@
export class Service {
#domain
#id
#name
constructor(domain, id, name) {
this.#domain = domain;
this.#id = id;
this.#name = name;
}
}

View File

@@ -1,5 +1,5 @@
import Vue from 'vue'
import PiComponent from "@/PiComponent.vue";
import PiComponent from "@/components/PiComponent.vue";
import { BootstrapVue, IconsPlugin } from 'bootstrap-vue'
import 'bootstrap/dist/css/bootstrap.css'

View File

@@ -1,5 +1,5 @@
import Vue from 'vue'
import PluginComponent from '../PluginComponent.vue'
import PluginComponent from './components/PluginComponent.vue'
Vue.config.productionTip = false
Vue.config.devtools = true;

View File

@@ -10,8 +10,14 @@ module.exports = {
config.resolve.alias.set("snapsvg", "snapsvg/dist/snap.svg.js");
},
pages: {
plugin: 'src/plugin/main.js',
pi: 'src/pi/main.js'
plugin: {
entry: 'src/plugin.js',
template: 'public/plugin.html'
},
pi: {
entry: 'src/pi.js',
template: 'public/pi.html'
}
},
publicPath: './'
}