mirror of
https://github.com/cgiesche/streamdeck-homeassistant.git
synced 2026-01-09 14:08:09 -05:00
Cleanup and reorg.
This commit is contained in:
2
LICENSE
2
LICENSE
@@ -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
4483
doc/services.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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)
|
||||
}
|
||||
})
|
||||
@@ -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
|
||||
@@ -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
29
src/modules/pi/entity.js
Normal 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
12
src/modules/pi/service.js
Normal file
@@ -0,0 +1,12 @@
|
||||
export class Service {
|
||||
|
||||
#domain
|
||||
#id
|
||||
#name
|
||||
|
||||
constructor(domain, id, name) {
|
||||
this.#domain = domain;
|
||||
this.#id = id;
|
||||
this.#name = name;
|
||||
}
|
||||
}
|
||||
@@ -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'
|
||||
@@ -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;
|
||||
@@ -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: './'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user