@mcu Ah. Das war mein erster Ansatz. Bin dann auf getObjects umgestiegen, da getEnum nicht verfügbar war.
Danke für's Issue aufmachen.
@mcu Ah. Das war mein erster Ansatz. Bin dann auf getObjects umgestiegen, da getEnum nicht verfügbar war.
Danke für's Issue aufmachen.
Algemeine function um das richtige Element zu finden und eine Klasse "button-pressed" zu setzen oder wieder zu entfernen:
Wird mit der Value des Button, der deviceId und einem Device spezifischen Mapping aufgerufen.
function styleButtonGroup(val, deviceId, mapping){
//console.log(`val: ${val} deviceId: ${deviceId}`)
var buttons = null
var button = null
var icons = null
// see whether there is a widget containing a listItem with a ButtonGroupAction that has a listItemBody containing a hidden label that matches our deviceId
var listItems = document.querySelectorAll('.jarvis-StateListItem:has(.jarvis-ButtonGroupAction)')
//console.log(listItems)
listItems?.forEach((listItem) => {
//console.log(listItem)
var label = listItem.querySelector('.jarvis-StateListItem-Body .q-item__label.q-item__label--caption')
console.log(label)
if(label?.textContent === deviceId) {
buttons = listItem.querySelectorAll('.jarvis-ButtonGroupAction button')
//console.log(buttons)
buttons?.forEach((button) => {
//console.log(button)
if(button.classList.contains('jarvis-ButtonGroupAction-' + mapping[val])) {
button.classList.add('button-pressed')
}
else{
button.classList.remove('button-pressed')
}
})
icons = listItem.querySelectorAll('.jarvis-ButtonGroupAction .icon')
//console.log(icon)
icons?.forEach((icon) => {
//console.log(icon)
for (const scene in mapping) {
const sceneName = mapping[scene]
//console.log(sceneName)
if(icon.classList.contains('jarvis-ButtonGroupAction-' + sceneName)) {
icon.classList.add(sceneName)
}
}
})
}
})
}
// AutoMation Mapping
const autoOnOffMapping = {
"AUTO":"AUTO",
"ON":"ON",
"OFF":"OFF"
}
// Wir vom Device aus aufgerufen
function styleMotionLightButtonGroup(val, deviceId){
styleButtonGroup(val, deviceId, autoOnOffMapping)
}
Und jetzt noch die zugehörigen styles:
/*
ButtonGroupAction icon definitiions
*/
.AUTO {
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M12.68 6h-1.36L7 16h2l.73-2h4.54l.73 2h2zm-2.38 6.5L12 8l1.7 4.5zm7.1 7.9L19 22h-5v-5l2 2c2.39-1.39 4-4.05 4-7c0-4.41-3.59-8-8-8s-8 3.59-8 8c0 2.95 1.61 5.53 4 6.92v2.24C4.47 19.61 2 16.1 2 12C2 6.5 6.5 2 12 2s10 4.5 10 10c0 3.53-1.83 6.62-4.6 8.4'/%3E%3C/svg%3E");
-webkit-mask-image: var(--svg);
mask-image: var(--svg);
}
.ON {
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='m16.56 5.44l-1.45 1.45A5.969 5.969 0 0 1 18 12a6 6 0 0 1-6 6a6 6 0 0 1-6-6c0-2.17 1.16-4.06 2.88-5.12L7.44 5.44A7.961 7.961 0 0 0 4 12a8 8 0 0 0 8 8a8 8 0 0 0 8-8c0-2.72-1.36-5.12-3.44-6.56M13 3h-2v10h2'/%3E%3C/svg%3E");
-webkit-mask-image: var(--svg);
mask-image: var(--svg);
}
.OFF {
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M12 3a9 9 0 0 0-9 9a9 9 0 0 0 9 9a9 9 0 0 0 9-9a9 9 0 0 0-9-9m0 16a7 7 0 0 1-7-7a7 7 0 0 1 7-7a7 7 0 0 1 7 7a7 7 0 0 1-7 7'/%3E%3C/svg%3E");
-webkit-mask-image: var(--svg);
mask-image: var(--svg);
}
/*
handle ButtonGroupActions
*/
/*
Allow the Group to expand to max-content instead of the default 60%
*/
.jarvis-StateListItem-Action:has(.jarvis-ButtonGroupAction) {
/* Styles for ListAction when it contains GroupAction */
max-width: 100% !important;
}
.jarvis-StateListItem:has(.jarvis-ButtonGroupAction) .jarvis-StateListItem-Body .q-item__label.q-item__label--caption {
color: var(--q-primary);
margin-top: -1px;
height: 0px !important;
visibility: hidden;
}
/*
jarvis-ButtonGroupAction gets the class with the background icon via java script
and here we define the common styles for this
*/
.jarvis-StateListItem:has(.jarvis-ButtonGroupAction) .q-btn__content .icon {
background-color: white !important;
display: inline-block;
width: 16px;
height: 16px;
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-size: 100% 100%;
mask-size: 100% 100%;
}
/*
normally the content of the button is a text lablel, which we want to hide here
*/
.jarvis-StateListItem:has(.jarvis-ButtonGroupAction) .q-btn__content:has(.icon)>:not(.icon) {
display: none;
}
/*
highlight the button representing the current state
*/
:root {
--q-primary: #1976d2;
--q-primary-red: 25;
--q-primary-green: 118;
--q-primary-blue: 210;
}
.q-btn-group>.q-btn-item.button-pressed {
background-color: rgba(var(--q-primary-red), var(--q-primary-green), var(--q-primary-blue), 0.5) !important;
border: 1px solid grey;
}
Das Widget dazu sieht so aus:
Und das zugehörige Device so:
Der Trick ist, dass im CustomTextBody die deviceId steckt und das dadurch erzeugte Element hidden ist. Damit kann man das richtige device im Dom finden und dann modifizieren.
In den State Properties steht dann der Aufruf der function styleButtonGroup in Script.
Damit kann man auch Hue Scenen auf Buttons legen:
@mcu Gerne.
in der 3.1.8 funktioniert das ganz gut. in der 3.2.x ist auch hier das Problem, dass das Script nicht immer aufgerufen wird und die Button Icons dann nicht angezeigt werden. Z.B.
nach Seite neu laden:
nach klick auf einen Button:
beim ersten Popup aufruf:
beim nächsten Popup aufruf:
hinter dem control mode device liegt ein device in 0.userdata....
und im server seitigen script wird dann die MotionLightAutomation behandelt.
Zum testen sollten die styles, das script und das device in 0.userdata zum halten des button status aber reichen.
Wenn du mehr brauchst, dann kann ich dir nächste Woche noch was liefern oder Fragen beantworten.
@mcu In der 3.1.8 wird button-pressed initial gesetzt.
In der 3.2.x wird initial zwar die Funktion styleButton… aufgerufen, schlägt aber fehl, da das Script noch nicht geladen ist. Wenn du einen Button klickst ändert sich val und die Funktion wird wieder aufgerufen. Da das Script nun geladen ist funktioniert es.
IsOff steht immer da bei ButtonGroupAction und hat keine Funktion. Vielleicht tatsächlich ein bug in Jarvis.
@mcu dann würden auch die BlindButtons funktionieren - da hab ich was ähnliches gebaut um den gedrückten Button zu highlighten.
Danke für den Tipp mit der SVG.
@mcu funktioniert dann auch das highlighten des zuletzt gedrückten Buttons?
@mcu In der 3.1.8 wird button-pressed initial gesetzt.
In der 3.2.x wird initial zwar die Funktion styleButton… aufgerufen, schlägt aber fehl, da das Script noch nicht geladen ist. Wenn du einen Button klickst ändert sich val und die Funktion wird wieder aufgerufen. Da das Script nun geladen ist funktioniert es.
IsOff steht immer da bei ButtonGroupAction und hat keine Funktion. Vielleicht tatsächlich ein bug in Jarvis.
@mcu ok. Gleiches Verhalten wie bei mir.
Danke für’s ausprobieren.
@mcu sieht gut aus! Ist aber 3.1.8 oder?
@mcu sorry, hab mich grad falsch erinnert.
Schau mal im post den Screenshot vom device an.
In der DisplayVariant ist ein JSON das 3 Buttons definiert. Du musst allerdings bei der Definition der ButtonGroupAction noch einstellen, dass Du die DisplayVariant für die Buttons verwenden willst. Key wird jeweils von Jarvis and die Klasse angehängt. Um von mir später mit mapping[val] im Script abgefragt. Value wird jeweils als Text angezeigt, auf dem Button der in der Standard Implementierung von Jarvis. Bis dahin brauchst du meine scripte und Sykes nicht. Die sind nur dazu da statt Text auf dem Button ein Icon anzuzeigen.
Cool wäre natürlich wenn man die vorhandene Jarvis implementierung so erweitern könnte, dass sie auch Icons erlaubt. Dann müsste ich nicht solche Verrenkungen machen (war aber ein schönes Experiment, hab viel dabei úber Jarvis gelernt)
@mcu es gibt auch in 3.1.x keine direkte Möglichkeit weitere Buttons zur ButtonGroupAction hinzuzufügen. Mehrere Buttons gehen nur über die Display Eigenschaften des Geräts. Die Funktionen zum hinzufügen der Klassen etc. Hab ich selbst geschrieben - sind in meinem Post mit drin, da man damit nur Textbuttons hinzufügen kann aber keine icons.
@mcu Gerne.
in der 3.1.8 funktioniert das ganz gut. in der 3.2.x ist auch hier das Problem, dass das Script nicht immer aufgerufen wird und die Button Icons dann nicht angezeigt werden. Z.B.
nach Seite neu laden:
nach klick auf einen Button:
beim ersten Popup aufruf:
beim nächsten Popup aufruf:
hinter dem control mode device liegt ein device in 0.userdata....
und im server seitigen script wird dann die MotionLightAutomation behandelt.
Zum testen sollten die styles, das script und das device in 0.userdata zum halten des button status aber reichen.
Wenn du mehr brauchst, dann kann ich dir nächste Woche noch was liefern oder Fragen beantworten.
Algemeine function um das richtige Element zu finden und eine Klasse "button-pressed" zu setzen oder wieder zu entfernen:
Wird mit der Value des Button, der deviceId und einem Device spezifischen Mapping aufgerufen.
function styleButtonGroup(val, deviceId, mapping){
//console.log(`val: ${val} deviceId: ${deviceId}`)
var buttons = null
var button = null
var icons = null
// see whether there is a widget containing a listItem with a ButtonGroupAction that has a listItemBody containing a hidden label that matches our deviceId
var listItems = document.querySelectorAll('.jarvis-StateListItem:has(.jarvis-ButtonGroupAction)')
//console.log(listItems)
listItems?.forEach((listItem) => {
//console.log(listItem)
var label = listItem.querySelector('.jarvis-StateListItem-Body .q-item__label.q-item__label--caption')
console.log(label)
if(label?.textContent === deviceId) {
buttons = listItem.querySelectorAll('.jarvis-ButtonGroupAction button')
//console.log(buttons)
buttons?.forEach((button) => {
//console.log(button)
if(button.classList.contains('jarvis-ButtonGroupAction-' + mapping[val])) {
button.classList.add('button-pressed')
}
else{
button.classList.remove('button-pressed')
}
})
icons = listItem.querySelectorAll('.jarvis-ButtonGroupAction .icon')
//console.log(icon)
icons?.forEach((icon) => {
//console.log(icon)
for (const scene in mapping) {
const sceneName = mapping[scene]
//console.log(sceneName)
if(icon.classList.contains('jarvis-ButtonGroupAction-' + sceneName)) {
icon.classList.add(sceneName)
}
}
})
}
})
}
// AutoMation Mapping
const autoOnOffMapping = {
"AUTO":"AUTO",
"ON":"ON",
"OFF":"OFF"
}
// Wir vom Device aus aufgerufen
function styleMotionLightButtonGroup(val, deviceId){
styleButtonGroup(val, deviceId, autoOnOffMapping)
}
Und jetzt noch die zugehörigen styles:
/*
ButtonGroupAction icon definitiions
*/
.AUTO {
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M12.68 6h-1.36L7 16h2l.73-2h4.54l.73 2h2zm-2.38 6.5L12 8l1.7 4.5zm7.1 7.9L19 22h-5v-5l2 2c2.39-1.39 4-4.05 4-7c0-4.41-3.59-8-8-8s-8 3.59-8 8c0 2.95 1.61 5.53 4 6.92v2.24C4.47 19.61 2 16.1 2 12C2 6.5 6.5 2 12 2s10 4.5 10 10c0 3.53-1.83 6.62-4.6 8.4'/%3E%3C/svg%3E");
-webkit-mask-image: var(--svg);
mask-image: var(--svg);
}
.ON {
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='m16.56 5.44l-1.45 1.45A5.969 5.969 0 0 1 18 12a6 6 0 0 1-6 6a6 6 0 0 1-6-6c0-2.17 1.16-4.06 2.88-5.12L7.44 5.44A7.961 7.961 0 0 0 4 12a8 8 0 0 0 8 8a8 8 0 0 0 8-8c0-2.72-1.36-5.12-3.44-6.56M13 3h-2v10h2'/%3E%3C/svg%3E");
-webkit-mask-image: var(--svg);
mask-image: var(--svg);
}
.OFF {
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M12 3a9 9 0 0 0-9 9a9 9 0 0 0 9 9a9 9 0 0 0 9-9a9 9 0 0 0-9-9m0 16a7 7 0 0 1-7-7a7 7 0 0 1 7-7a7 7 0 0 1 7 7a7 7 0 0 1-7 7'/%3E%3C/svg%3E");
-webkit-mask-image: var(--svg);
mask-image: var(--svg);
}
/*
handle ButtonGroupActions
*/
/*
Allow the Group to expand to max-content instead of the default 60%
*/
.jarvis-StateListItem-Action:has(.jarvis-ButtonGroupAction) {
/* Styles for ListAction when it contains GroupAction */
max-width: 100% !important;
}
.jarvis-StateListItem:has(.jarvis-ButtonGroupAction) .jarvis-StateListItem-Body .q-item__label.q-item__label--caption {
color: var(--q-primary);
margin-top: -1px;
height: 0px !important;
visibility: hidden;
}
/*
jarvis-ButtonGroupAction gets the class with the background icon via java script
and here we define the common styles for this
*/
.jarvis-StateListItem:has(.jarvis-ButtonGroupAction) .q-btn__content .icon {
background-color: white !important;
display: inline-block;
width: 16px;
height: 16px;
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-size: 100% 100%;
mask-size: 100% 100%;
}
/*
normally the content of the button is a text lablel, which we want to hide here
*/
.jarvis-StateListItem:has(.jarvis-ButtonGroupAction) .q-btn__content:has(.icon)>:not(.icon) {
display: none;
}
/*
highlight the button representing the current state
*/
:root {
--q-primary: #1976d2;
--q-primary-red: 25;
--q-primary-green: 118;
--q-primary-blue: 210;
}
.q-btn-group>.q-btn-item.button-pressed {
background-color: rgba(var(--q-primary-red), var(--q-primary-green), var(--q-primary-blue), 0.5) !important;
border: 1px solid grey;
}
Das Widget dazu sieht so aus:
Und das zugehörige Device so:
Der Trick ist, dass im CustomTextBody die deviceId steckt und das dadurch erzeugte Element hidden ist. Damit kann man das richtige device im Dom finden und dann modifizieren.
In den State Properties steht dann der Aufruf der function styleButtonGroup in Script.
Damit kann man auch Hue Scenen auf Buttons legen:
@mcu Das würde natürlich funktionieren. Da das JSON die Rohdaten enthält und ich es eh per server script erzeuge, könnte ich natürlich auf ein formatierte Version erzeugen für das widget. Das mach Sinn.
Ich hab noch einen anderen Anwendungsfall. Ich erzeuge mit styles und client seitigem script aus einer ButtonGroupAction eine ToggelButtonListe die mir auch noch anzeigt, was gerade aktiv ist.
Im obigen Fall ein Umschalten zwischen Automatik, Manuell AN, Manuell AUS
Das geht nur durch direkte DOM manipulation also nicht serverseitig lösbar.