From 4943fa138dd8b1f7b972dcb1d6d83e2e0c79db51 Mon Sep 17 00:00:00 2001 From: Brett-S-OWB Date: Mon, 5 Oct 2026 08:48:49 +0200 Subject: [PATCH 01/17] consumers and counters not in HV --- .../energyFlowChart/EnergyFlowChart.vue | 43 +++++++++--- .../koala/source/src/stores/mqtt-store.ts | 70 +++++++++++++++++++ 2 files changed, 105 insertions(+), 8 deletions(-) diff --git a/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue b/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue index fd54d0b0ed..6c28db5be0 100644 --- a/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue +++ b/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue @@ -11,6 +11,7 @@ import HouseIcon from 'src/assets/icons/owbHouse.svg?component'; import VehicleIcon from 'src/assets/icons/owbVehicle.svg?component'; import ChargePointIcon from 'src/assets/icons/owbChargePoint_2.svg?component'; import ConsumerIcon from 'src/assets/icons/owbConsumer.svg?component'; +import CounterIcon from 'src/assets/icons/owbCounter.svg?component'; const mqttStore = useMqttStore(); const $q = useQuasar(); @@ -103,9 +104,26 @@ const homeConsumption = computed(() => Number(homePower.value.value) > 0); const homeProduction = computed(() => Number(homePower.value.value) < 0); const consumerPower = computed( - () => mqttStore.consumerSumPower('object') as ValueObject, + () => mqttStore.notInHomeConsumptionPower('object') as ValueObject, +); +const consumerConsumption = computed( + () => Number(consumerPower.value.value) > 0, +); +const consumerProduction = computed( + () => Number(consumerPower.value.value) < 0, +); + +const countersNotInHome = computed( + () => mqttStore.notInHomeConsumption.counterIds.length > 0, +); +const showConsumerPower = computed( + () => + mqttStore.notInHomeConsumption.consumerIds.length > 0 || + countersNotInHome.value || + // e.g. SmartHome devices excluded from the home consumption + consumerConsumption.value || + consumerProduction.value, ); -const showConsumerPower = computed(() => mqttStore.consumerIds.length > 0); const pvPower = computed(() => mqttStore.pvPowerTotal('object') as ValueObject); const pvProduction = computed(() => { @@ -387,18 +405,20 @@ const svgComponents = computed((): FlowComponent[] => { components.push({ id: 'consumer', class: { - base: 'consumer', - valueLabelColor: 'var(--q-consumer)', - animatedReverse: Number(consumerPower.value.value) > 0, + base: countersNotInHome.value ? 'not-in-home' : 'consumer', + animated: consumerProduction.value, + animatedReverse: consumerConsumption.value, }, position: { row: 0, column: 1 }, label: [ - 'Verbraucher', + countersNotInHome.value ? 'Sonstige' : 'Verbraucher', absoluteValueObject(consumerPower.value).textValue, ], powerValue: Number(consumerPower.value.value), - iconComponent: ConsumerIcon, - iconColor: 'var(--q-consumer)', + iconComponent: countersNotInHome.value ? CounterIcon : ConsumerIcon, + iconColor: countersNotInHome.value + ? 'var(--q-secondary-counter-stroke)' + : 'var(--q-consumer)', }); } @@ -980,11 +1000,18 @@ path.animatedReverse.home { animation-duration: v-bind('animationDurations.home'); } +path.animated.consumer, path.animatedReverse.consumer { color: var(--q-consumer); animation-duration: v-bind('animationDurations.consumer'); } +path.animated.not-in-home, +path.animatedReverse.not-in-home { + color: var(--q-secondary-counter-stroke); + animation-duration: v-bind('animationDurations.consumer'); +} + path.animated.pv, path.animatedReverse.pv { color: var(--q-pv-stroke); diff --git a/packages/modules/web_themes/koala/source/src/stores/mqtt-store.ts b/packages/modules/web_themes/koala/source/src/stores/mqtt-store.ts index 443400c0d1..2c04819251 100644 --- a/packages/modules/web_themes/koala/source/src/stores/mqtt-store.ts +++ b/packages/modules/web_themes/koala/source/src/stores/mqtt-store.ts @@ -4385,6 +4385,74 @@ export const useMqttStore = defineStore('mqtt', () => { return result; }); + /** + * Get the consumers and counters that are not counted in the home + * consumption. + * @returns object with the ids of the consumers and counters + */ + const notInHomeConsumption = computed(() => { + const AUTO = 'auto_home_consumption'; + const NOT_HOME = 'no_home_consumption'; + const result = { consumerIds: [] as number[], counterIds: [] as number[] }; + function walk(nodes: Hierarchy[] | undefined, parentMode: string) { + if (nodes === undefined) { + return; + } + nodes.forEach((node) => { + if (node.type === 'counter') { + const own = getValue.value( + `openWB/counter/${node.id}/config/is_home_consumption_counter`, + undefined, + AUTO, + ) as string | undefined; + const mode = own && own !== AUTO ? own : parentMode; + if (mode === NOT_HOME) { + result.counterIds.push(node.id); + } + walk(node.children, mode); + } else if (node.type === 'consumer') { + const own = getValue.value( + `openWB/consumer/${node.id}/config`, + 'is_home_consumption_consumer', + AUTO, + ) as string | undefined; + if ((own && own !== AUTO ? own : parentMode) === NOT_HOME) { + result.consumerIds.push(node.id); + } + } else { + walk(node.children, parentMode); + } + }); + } + walk( + getValue.value('openWB/counter/get/hierarchy') as Hierarchy[], + 'home_consumption', + ); + return result; + }); + + /** + * Get the summed power of all consumers and counters that are not counted + * in the home consumption. + * @param returnType type of return value, 'textValue', 'value', 'scaledValue', 'scaledUnit' or 'object' + * @returns string | number | ValueObject + */ + const notInHomeConsumptionPower = computed(() => { + return (returnType: string = 'textValue') => { + const power = getValue.value( + 'openWB/counter/set/not_in_home_consumption', + ) as number | undefined; + const valueObject = getValueObject.value(power); + if (Object.hasOwn(valueObject, returnType)) { + return valueObject[returnType as keyof ValueObject]; + } + if (returnType == 'object') { + return valueObject; + } + console.error('returnType not found!', returnType, power); + }; + }); + /** * Get pv power * @param returnType type of return value, 'textValue', 'value', 'scaledValue', 'scaledUnit' or 'object' @@ -4756,6 +4824,8 @@ export const useMqttStore = defineStore('mqtt', () => { // PV data pvConfigured, hybridInverters, + notInHomeConsumption, + notInHomeConsumptionPower, pvPowerTotal, pvDailyExported, pvIds, From 7180cd4871db5ca9ca94a3eef6671d3b9b712b0b Mon Sep 17 00:00:00 2001 From: Brett-S-OWB Date: Mon, 5 Oct 2026 09:59:45 +0200 Subject: [PATCH 02/17] add info badge --- .../energyFlowChart/EnergyFlowChart.vue | 40 ++++++++++++++- .../energy-flow-chart-models.ts | 1 + .../koala/source/src/stores/mqtt-store.ts | 51 +++++++++++++++---- 3 files changed, 81 insertions(+), 11 deletions(-) diff --git a/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue b/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue index 6c28db5be0..31d069e3f3 100644 --- a/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue +++ b/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue @@ -52,6 +52,12 @@ const svgViewBox = computed( // the inset leaves a visible gap between circle and pill edge. const iconCircleRadius = computed(() => svgSize.value.circleRadius - 2); +const infoBadgeRadius = 4.0; +const infoIconRadius = 2.7; +const infoBadgeOffset = computed( + () => (iconCircleRadius.value + 1) * Math.SQRT1_2, +); + const svgIconWidth = computed(() => svgSize.value.circleRadius); const svgIconHeight = computed(() => svgSize.value.circleRadius); @@ -112,10 +118,14 @@ const consumerConsumption = computed( const consumerProduction = computed( () => Number(consumerPower.value.value) < 0, ); - const countersNotInHome = computed( () => mqttStore.notInHomeConsumption.counterIds.length > 0, ); +const homeHasDetails = computed( + () => + mqttStore.inHomeConsumption.consumerIds.length > 0 || + mqttStore.inHomeConsumption.counterIds.length > 0, +); const showConsumerPower = computed( () => mqttStore.notInHomeConsumption.consumerIds.length > 0 || @@ -398,6 +408,7 @@ const svgComponents = computed((): FlowComponent[] => { powerValue: Number(homePower.value.value), iconComponent: HouseIcon, iconColor: 'var(--q-home-stroke)', + showInfo: homeHasDetails.value, }); } @@ -922,6 +933,21 @@ const labelClipPath = computed(() => { :style="{ color: component.iconColor }" /> + + + + + + @@ -1086,6 +1112,18 @@ circle:not(.soc) { fill: var(--q-card-background); } +.info-badge circle.info-icon { + stroke: var(--q-text); + stroke-width: 0.4; +} + +.info-badge path { + fill: none; + stroke: var(--q-text); + stroke-width: 0.55; + stroke-linecap: round; +} + rect { fill: var(--q-card-background); } diff --git a/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/energy-flow-chart-models.ts b/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/energy-flow-chart-models.ts index 9db5e13293..ddbce62a49 100644 --- a/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/energy-flow-chart-models.ts +++ b/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/energy-flow-chart-models.ts @@ -35,4 +35,5 @@ export interface FlowComponent { soc?: number; iconComponent?: Component; iconColor?: string; + showInfo?: boolean; } diff --git a/packages/modules/web_themes/koala/source/src/stores/mqtt-store.ts b/packages/modules/web_themes/koala/source/src/stores/mqtt-store.ts index 2c04819251..ebcbe0d95d 100644 --- a/packages/modules/web_themes/koala/source/src/stores/mqtt-store.ts +++ b/packages/modules/web_themes/koala/source/src/stores/mqtt-store.ts @@ -4386,15 +4386,22 @@ export const useMqttStore = defineStore('mqtt', () => { }); /** - * Get the consumers and counters that are not counted in the home - * consumption. - * @returns object with the ids of the consumers and counters + * Sort the consumers and sub-counters by whether they are counted in the + * home consumption. */ - const notInHomeConsumption = computed(() => { + const homeConsumptionAssignment = computed(() => { const AUTO = 'auto_home_consumption'; const NOT_HOME = 'no_home_consumption'; - const result = { consumerIds: [] as number[], counterIds: [] as number[] }; - function walk(nodes: Hierarchy[] | undefined, parentMode: string) { + const ids = () => ({ + consumerIds: [] as number[], + counterIds: [] as number[], + }); + const result = { inHome: ids(), notInHome: ids() }; + function walk( + nodes: Hierarchy[] | undefined, + parentMode: string, + isRoot: boolean, + ) { if (nodes === undefined) { return; } @@ -4407,9 +4414,11 @@ export const useMqttStore = defineStore('mqtt', () => { ) as string | undefined; const mode = own && own !== AUTO ? own : parentMode; if (mode === NOT_HOME) { - result.counterIds.push(node.id); + result.notInHome.counterIds.push(node.id); + } else if (!isRoot) { + result.inHome.counterIds.push(node.id); } - walk(node.children, mode); + walk(node.children, mode, false); } else if (node.type === 'consumer') { const own = getValue.value( `openWB/consumer/${node.id}/config`, @@ -4417,20 +4426,41 @@ export const useMqttStore = defineStore('mqtt', () => { AUTO, ) as string | undefined; if ((own && own !== AUTO ? own : parentMode) === NOT_HOME) { - result.consumerIds.push(node.id); + result.notInHome.consumerIds.push(node.id); + } else { + result.inHome.consumerIds.push(node.id); } } else { - walk(node.children, parentMode); + walk(node.children, parentMode, false); } }); } walk( getValue.value('openWB/counter/get/hierarchy') as Hierarchy[], 'home_consumption', + true, ); return result; }); + /** + * Get the consumers and sub-counters that are counted in the home + * consumption. + * @returns object with the ids of the consumers and counters + */ + const inHomeConsumption = computed( + () => homeConsumptionAssignment.value.inHome, + ); + + /** + * Get the consumers and counters that are not counted in the home + * consumption. + * @returns object with the ids of the consumers and counters + */ + const notInHomeConsumption = computed( + () => homeConsumptionAssignment.value.notInHome, + ); + /** * Get the summed power of all consumers and counters that are not counted * in the home consumption. @@ -4824,6 +4854,7 @@ export const useMqttStore = defineStore('mqtt', () => { // PV data pvConfigured, hybridInverters, + inHomeConsumption, notInHomeConsumption, notInHomeConsumptionPower, pvPowerTotal, From 4405921d1d167b80b9d7d987cf5fe428fdf61c44 Mon Sep 17 00:00:00 2001 From: Brett-S-OWB Date: Mon, 5 Oct 2026 14:23:23 +0200 Subject: [PATCH 03/17] add info dialog --- .../energyFlowChart/EnergyFlowChart.vue | 4 + .../HomeConsumptionDetailsDialog.vue | 106 ++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/HomeConsumptionDetailsDialog.vue diff --git a/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue b/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue index 31d069e3f3..21b95f8563 100644 --- a/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue +++ b/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue @@ -12,6 +12,7 @@ import VehicleIcon from 'src/assets/icons/owbVehicle.svg?component'; import ChargePointIcon from 'src/assets/icons/owbChargePoint_2.svg?component'; import ConsumerIcon from 'src/assets/icons/owbConsumer.svg?component'; import CounterIcon from 'src/assets/icons/owbCounter.svg?component'; +import HomeConsumptionDetailsDialog from './HomeConsumptionDetailsDialog.vue'; const mqttStore = useMqttStore(); const $q = useQuasar(); @@ -121,6 +122,7 @@ const consumerProduction = computed( const countersNotInHome = computed( () => mqttStore.notInHomeConsumption.counterIds.length > 0, ); +const homeDetailsVisible = ref(false); const homeHasDetails = computed( () => mqttStore.inHomeConsumption.consumerIds.length > 0 || @@ -938,6 +940,7 @@ const labelClipPath = computed(() => { v-if="component.showInfo" class="info-badge cursor-pointer" :transform="`translate(${-infoBadgeOffset}, ${-infoBadgeOffset})`" + @click.stop="homeDetailsVisible = true" > { + diff --git a/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/HomeConsumptionDetailsDialog.vue b/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/HomeConsumptionDetailsDialog.vue new file mode 100644 index 0000000000..0a4894dcfb --- /dev/null +++ b/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/HomeConsumptionDetailsDialog.vue @@ -0,0 +1,106 @@ + + + + + From 26b40d6850350fbf6a6283660c1ea1ae168cb7a4 Mon Sep 17 00:00:00 2001 From: Brett-S-OWB Date: Mon, 5 Oct 2026 14:27:52 +0200 Subject: [PATCH 04/17] update list background --- .../charts/energyFlowChart/HomeConsumptionDetailsDialog.vue | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/HomeConsumptionDetailsDialog.vue b/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/HomeConsumptionDetailsDialog.vue index 0a4894dcfb..db51eab0ef 100644 --- a/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/HomeConsumptionDetailsDialog.vue +++ b/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/HomeConsumptionDetailsDialog.vue @@ -103,4 +103,8 @@ const items = computed((): DetailsItem[] => { width: 28px; height: 28px; } + +.q-list { + background-color: transparent; +} From 855e0733a4fa4540b9ef5bdeaf467ce74a100939 Mon Sep 17 00:00:00 2001 From: Brett-S-OWB Date: Mon, 5 Oct 2026 14:50:39 +0200 Subject: [PATCH 05/17] info click area larger --- .../charts/energyFlowChart/EnergyFlowChart.vue | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue b/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue index 21b95f8563..d0f4cebb06 100644 --- a/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue +++ b/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue @@ -123,6 +123,14 @@ const countersNotInHome = computed( () => mqttStore.notInHomeConsumption.counterIds.length > 0, ); const homeDetailsVisible = ref(false); + +const openDetails = (event: MouseEvent, component: FlowComponent) => { + if (!component.showInfo) { + return; + } + event.stopPropagation(); + homeDetailsVisible.value = true; +}; const homeHasDetails = computed( () => mqttStore.inHomeConsumption.consumerIds.length > 0 || @@ -906,6 +914,8 @@ const labelClipPath = computed(() => { { Date: Mon, 5 Oct 2026 15:19:33 +0200 Subject: [PATCH 06/17] add info dialog for consumers and secondary counters --- .../charts/energyFlowChart/EnergyFlowChart.vue | 17 ++++++++++++++--- .../HomeConsumptionDetailsDialog.vue | 14 ++++++++++++-- 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue b/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue index d0f4cebb06..6606a555c7 100644 --- a/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue +++ b/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue @@ -122,20 +122,27 @@ const consumerProduction = computed( const countersNotInHome = computed( () => mqttStore.notInHomeConsumption.counterIds.length > 0, ); -const homeDetailsVisible = ref(false); +const detailsVisible = ref(false); +const detailsScope = ref<'inHome' | 'notInHome'>('inHome'); const openDetails = (event: MouseEvent, component: FlowComponent) => { if (!component.showInfo) { return; } event.stopPropagation(); - homeDetailsVisible.value = true; + detailsScope.value = component.id === 'home' ? 'inHome' : 'notInHome'; + detailsVisible.value = true; }; const homeHasDetails = computed( () => mqttStore.inHomeConsumption.consumerIds.length > 0 || mqttStore.inHomeConsumption.counterIds.length > 0, ); +const notInHomeHasDetails = computed( + () => + mqttStore.notInHomeConsumption.consumerIds.length > 0 || + mqttStore.notInHomeConsumption.counterIds.length > 0, +); const showConsumerPower = computed( () => mqttStore.notInHomeConsumption.consumerIds.length > 0 || @@ -440,6 +447,7 @@ const svgComponents = computed((): FlowComponent[] => { iconColor: countersNotInHome.value ? 'var(--q-secondary-counter-stroke)' : 'var(--q-consumer)', + showInfo: notInHomeHasDetails.value, }); } @@ -964,7 +972,10 @@ const labelClipPath = computed(() => { - + diff --git a/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/HomeConsumptionDetailsDialog.vue b/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/HomeConsumptionDetailsDialog.vue index db51eab0ef..30ea94b1c6 100644 --- a/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/HomeConsumptionDetailsDialog.vue +++ b/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/HomeConsumptionDetailsDialog.vue @@ -3,7 +3,7 @@
-
Im Hausverbrauch enthalten:
+
{{ title }}
(); const emit = defineEmits<{ @@ -69,8 +70,17 @@ const visible = computed({ }); const isSmallScreen = computed(() => Screen.lt.sm); +const title = computed(() => + props.scope === 'inHome' + ? 'Im Hausverbrauch enthalten:' + : 'Nicht im Hausverbrauch enthalten:', +); + const items = computed((): DetailsItem[] => { - const { consumerIds, counterIds } = mqttStore.inHomeConsumption; + const { consumerIds, counterIds } = + props.scope === 'inHome' + ? mqttStore.inHomeConsumption + : mqttStore.notInHomeConsumption; return [ ...consumerIds.map((id) => ({ key: `consumer-${id}`, From 668d8f5ba87e99d2350818184ed81d97fbf7970c Mon Sep 17 00:00:00 2001 From: Brett-S-OWB Date: Mon, 5 Oct 2026 16:08:47 +0200 Subject: [PATCH 07/17] info icon color & size --- .../charts/energyFlowChart/EnergyFlowChart.vue | 9 +++++---- .../koala/source/src/css/quasar.variables.scss | 4 ++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue b/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue index 6606a555c7..383e050244 100644 --- a/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue +++ b/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue @@ -53,8 +53,8 @@ const svgViewBox = computed( // the inset leaves a visible gap between circle and pill edge. const iconCircleRadius = computed(() => svgSize.value.circleRadius - 2); -const infoBadgeRadius = 4.0; -const infoIconRadius = 2.7; +const infoBadgeRadius = 3.6; +const infoIconRadius = 3; const infoBadgeOffset = computed( () => (iconCircleRadius.value + 1) * Math.SQRT1_2, ); @@ -1137,13 +1137,14 @@ circle:not(.soc) { } .info-badge circle.info-icon { - stroke: var(--q-text); + fill: var(--q-flow-chart-info); + stroke: var(--q-flow-chart-info); stroke-width: 0.4; } .info-badge path { fill: none; - stroke: var(--q-text); + stroke: var(--q-white); stroke-width: 0.55; stroke-linecap: round; } diff --git a/packages/modules/web_themes/koala/source/src/css/quasar.variables.scss b/packages/modules/web_themes/koala/source/src/css/quasar.variables.scss index 98a8961276..4879c786e3 100644 --- a/packages/modules/web_themes/koala/source/src/css/quasar.variables.scss +++ b/packages/modules/web_themes/koala/source/src/css/quasar.variables.scss @@ -61,6 +61,7 @@ $chart-shadow: $secondary; // energy flow chart: shadow behind the pills and the icon circles $flow-chart-shadow: #000000; $flow-chart-shadow-opacity: 0.12; +$flow-chart-info: #2aa8ff; $consumer: #7d42f5; // Light theme (default) :root { @@ -80,6 +81,7 @@ $consumer: #7d42f5; --q-chart-shadow: #{$chart-shadow}; --q-flow-chart-shadow: #{$flow-chart-shadow}; --q-flow-chart-shadow-opacity: #{$flow-chart-shadow-opacity}; + --q-flow-chart-info: #{$flow-chart-info}; --q-text: #{$light-text}; --q-white: #{$white}; --q-grey: #{$grey}; @@ -245,6 +247,7 @@ $dark-chart-shadow: #000000; // energy flow chart: shadow behind the pills and the icon circles $dark-flow-chart-shadow: #000000; $dark-flow-chart-shadow-opacity: 0.45; +$dark-flow-chart-info: #2aa8ff; $dark-accent: #546e7a; $dark-positive: #3e8f5e; $dark-negative: #c54d57; @@ -282,6 +285,7 @@ $dark-table-hover: #ffffff12; --q-chart-shadow: #{$dark-chart-shadow}; --q-flow-chart-shadow: #{$dark-flow-chart-shadow}; --q-flow-chart-shadow-opacity: #{$dark-flow-chart-shadow-opacity}; + --q-flow-chart-info: #{$dark-flow-chart-info}; --q-text: #{$dark-text}; --q-white: #{$white}; --q-grey: #{$grey}; From 0a5956d812c3a7079736de1d6c457c6541c2bfda Mon Sep 17 00:00:00 2001 From: Brett-S-OWB Date: Mon, 5 Oct 2026 17:02:51 +0200 Subject: [PATCH 08/17] use svg info icon --- .../src/assets/icons/owbInformation.svg | 1 + .../energyFlowChart/EnergyFlowChart.vue | 29 +++++++++---------- 2 files changed, 15 insertions(+), 15 deletions(-) create mode 100644 packages/modules/web_themes/koala/source/src/assets/icons/owbInformation.svg diff --git a/packages/modules/web_themes/koala/source/src/assets/icons/owbInformation.svg b/packages/modules/web_themes/koala/source/src/assets/icons/owbInformation.svg new file mode 100644 index 0000000000..c7f64746bf --- /dev/null +++ b/packages/modules/web_themes/koala/source/src/assets/icons/owbInformation.svg @@ -0,0 +1 @@ + diff --git a/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue b/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue index 383e050244..0d69ed32b5 100644 --- a/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue +++ b/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue @@ -12,6 +12,7 @@ import VehicleIcon from 'src/assets/icons/owbVehicle.svg?component'; import ChargePointIcon from 'src/assets/icons/owbChargePoint_2.svg?component'; import ConsumerIcon from 'src/assets/icons/owbConsumer.svg?component'; import CounterIcon from 'src/assets/icons/owbCounter.svg?component'; +import InfoIcon from 'src/assets/icons/owbInformation.svg?component'; import HomeConsumptionDetailsDialog from './HomeConsumptionDetailsDialog.vue'; const mqttStore = useMqttStore(); @@ -53,8 +54,8 @@ const svgViewBox = computed( // the inset leaves a visible gap between circle and pill edge. const iconCircleRadius = computed(() => svgSize.value.circleRadius - 2); -const infoBadgeRadius = 3.6; -const infoIconRadius = 3; +const infoBadgeRadius = 3.2; +const infoIconSize = 6; const infoBadgeOffset = computed( () => (iconCircleRadius.value + 1) * Math.SQRT1_2, ); @@ -965,8 +966,15 @@ const labelClipPath = computed(() => { :r="infoBadgeRadius" filter="url(#flow-box-shadow)" /> - - + + + @@ -1136,17 +1144,8 @@ circle:not(.soc) { fill: var(--q-card-background); } -.info-badge circle.info-icon { - fill: var(--q-flow-chart-info); - stroke: var(--q-flow-chart-info); - stroke-width: 0.4; -} - -.info-badge path { - fill: none; - stroke: var(--q-white); - stroke-width: 0.55; - stroke-linecap: round; +.info-badge .info-icon { + color: var(--q-flow-chart-info); } rect { From bf259352b758fc97bbac8d15063bbb3cc84706bd Mon Sep 17 00:00:00 2001 From: Brett-S-OWB Date: Tue, 6 Oct 2026 08:56:13 +0200 Subject: [PATCH 09/17] Documentation --- .../modules/web_themes/koala/source/src/stores/mqtt-store.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/modules/web_themes/koala/source/src/stores/mqtt-store.ts b/packages/modules/web_themes/koala/source/src/stores/mqtt-store.ts index ebcbe0d95d..33d6e8a54a 100644 --- a/packages/modules/web_themes/koala/source/src/stores/mqtt-store.ts +++ b/packages/modules/web_themes/koala/source/src/stores/mqtt-store.ts @@ -4387,7 +4387,9 @@ export const useMqttStore = defineStore('mqtt', () => { /** * Sort the consumers and sub-counters by whether they are counted in the - * home consumption. + * home consumption. The root counter is only listed if it is excluded. + * @returns object with the keys inHome and notInHome, each holding the ids + * of the consumers and counters */ const homeConsumptionAssignment = computed(() => { const AUTO = 'auto_home_consumption'; From 491bc7c2978f3df5c4b11f0091fee4780b04d1f7 Mon Sep 17 00:00:00 2001 From: Brett-S-OWB Date: Tue, 6 Oct 2026 08:57:15 +0200 Subject: [PATCH 10/17] Add info icon to dialog - formatting --- .../HomeConsumptionDetailsDialog.vue | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/HomeConsumptionDetailsDialog.vue b/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/HomeConsumptionDetailsDialog.vue index 30ea94b1c6..34f7fd2223 100644 --- a/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/HomeConsumptionDetailsDialog.vue +++ b/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/HomeConsumptionDetailsDialog.vue @@ -2,7 +2,8 @@ -
+
+
{{ title }}
- + Screen.lt.sm); const title = computed(() => props.scope === 'inHome' - ? 'Im Hausverbrauch enthalten:' - : 'Nicht im Hausverbrauch enthalten:', + ? 'Im Hausverbrauch:' + : 'Nicht im Hausverbrauch:', ); const items = computed((): DetailsItem[] => { @@ -109,10 +111,18 @@ const items = computed((): DetailsItem[] => { height: 2.5em; width: 2.5em; } +.title-icon, .item-icon { width: 28px; height: 28px; } +.title-icon { + flex-shrink: 0; + color: var(--q-flow-chart-info); +} +.q-item__section--avatar { + min-width: 0; +} .q-list { background-color: transparent; From 3f6dc9acb585d1dd8f0d316a566244a2efa83216 Mon Sep 17 00:00:00 2001 From: Brett-S-OWB Date: Tue, 6 Oct 2026 13:49:22 +0200 Subject: [PATCH 11/17] component names and icons --- .../src/assets/icons/owbMiscDevices.svg | 28 +++++++++++++ .../energyFlowChart/EnergyFlowChart.vue | 39 ++++++++++++++++--- 2 files changed, 61 insertions(+), 6 deletions(-) create mode 100644 packages/modules/web_themes/koala/source/src/assets/icons/owbMiscDevices.svg diff --git a/packages/modules/web_themes/koala/source/src/assets/icons/owbMiscDevices.svg b/packages/modules/web_themes/koala/source/src/assets/icons/owbMiscDevices.svg new file mode 100644 index 0000000000..863b457dcf --- /dev/null +++ b/packages/modules/web_themes/koala/source/src/assets/icons/owbMiscDevices.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + diff --git a/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue b/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue index 0d69ed32b5..d17f00b221 100644 --- a/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue +++ b/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue @@ -13,6 +13,7 @@ import ChargePointIcon from 'src/assets/icons/owbChargePoint_2.svg?component'; import ConsumerIcon from 'src/assets/icons/owbConsumer.svg?component'; import CounterIcon from 'src/assets/icons/owbCounter.svg?component'; import InfoIcon from 'src/assets/icons/owbInformation.svg?component'; +import MiscDevicesIcon from 'src/assets/icons/owbMiscDevices.svg?component'; import HomeConsumptionDetailsDialog from './HomeConsumptionDetailsDialog.vue'; const mqttStore = useMqttStore(); @@ -123,6 +124,34 @@ const consumerProduction = computed( const countersNotInHome = computed( () => mqttStore.notInHomeConsumption.counterIds.length > 0, ); +const notInHomeVariants = { + consumer: { + label: 'Verbraucher', + class: 'consumer', + iconComponent: ConsumerIcon, + iconColor: 'var(--q-consumer)', + }, + counter: { + label: 'Zähler', + class: 'not-in-home', + iconComponent: CounterIcon, + iconColor: 'var(--q-secondary-counter-stroke)', + }, + mixed: { + label: 'Sonstiges', + class: 'not-in-home', + iconComponent: MiscDevicesIcon, + iconColor: 'var(--q-secondary-counter-stroke)', + }, +}; +const notInHomeVariant = computed(() => { + if (!countersNotInHome.value) { + return notInHomeVariants.consumer; + } + return mqttStore.notInHomeConsumption.consumerIds.length > 0 + ? notInHomeVariants.mixed + : notInHomeVariants.counter; +}); const detailsVisible = ref(false); const detailsScope = ref<'inHome' | 'notInHome'>('inHome'); @@ -434,20 +463,18 @@ const svgComponents = computed((): FlowComponent[] => { components.push({ id: 'consumer', class: { - base: countersNotInHome.value ? 'not-in-home' : 'consumer', + base: notInHomeVariant.value.class, animated: consumerProduction.value, animatedReverse: consumerConsumption.value, }, position: { row: 0, column: 1 }, label: [ - countersNotInHome.value ? 'Sonstige' : 'Verbraucher', + notInHomeVariant.value.label, absoluteValueObject(consumerPower.value).textValue, ], powerValue: Number(consumerPower.value.value), - iconComponent: countersNotInHome.value ? CounterIcon : ConsumerIcon, - iconColor: countersNotInHome.value - ? 'var(--q-secondary-counter-stroke)' - : 'var(--q-consumer)', + iconComponent: notInHomeVariant.value.iconComponent, + iconColor: notInHomeVariant.value.iconColor, showInfo: notInHomeHasDetails.value, }); } From 1d838c538fcbff9e4d8e2d7ae897d9550343c058 Mon Sep 17 00:00:00 2001 From: Brett-S-OWB Date: Tue, 6 Oct 2026 13:51:02 +0200 Subject: [PATCH 12/17] display component power value in dialog --- .../energyFlowChart/HomeConsumptionDetailsDialog.vue | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/HomeConsumptionDetailsDialog.vue b/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/HomeConsumptionDetailsDialog.vue index 34f7fd2223..102f5bb1fa 100644 --- a/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/HomeConsumptionDetailsDialog.vue +++ b/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/HomeConsumptionDetailsDialog.vue @@ -28,7 +28,10 @@ /> - {{ item.name }} +
+
{{ item.name }}
+
{{ item.power }}
+
@@ -53,6 +56,7 @@ interface DetailsItem { name: string; icon: Component; color: string; + power: string; } const props = defineProps<{ @@ -89,6 +93,7 @@ const items = computed((): DetailsItem[] => { name: mqttStore.consumerName(id) || `Verbraucher ${id}`, icon: ConsumerIcon, color: mqttStore.consumerColor(id) || 'var(--q-consumer)', + power: mqttStore.consumerPower(id, 'textValue') as string, })), ...counterIds.map((id) => ({ key: `counter-${id}`, @@ -97,6 +102,7 @@ const items = computed((): DetailsItem[] => { color: mqttStore.secondaryCounterColor(id) || 'var(--q-secondary-counter-stroke)', + power: mqttStore.counterPower('textValue', id) as string, })), ]; }); From 7285b304e98dd55a2a0b1dc2cc8230a489665871 Mon Sep 17 00:00:00 2001 From: Brett-S-OWB Date: Tue, 6 Oct 2026 14:47:45 +0200 Subject: [PATCH 13/17] rename dialog titles - don't blur background --- .../charts/energyFlowChart/EnergyFlowChart.vue | 6 ++++++ .../energyFlowChart/HomeConsumptionDetailsDialog.vue | 11 ++--------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue b/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue index d17f00b221..87d43d1f44 100644 --- a/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue +++ b/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/EnergyFlowChart.vue @@ -154,6 +154,11 @@ const notInHomeVariant = computed(() => { }); const detailsVisible = ref(false); const detailsScope = ref<'inHome' | 'notInHome'>('inHome'); +const detailsTitle = computed(() => + detailsScope.value === 'inHome' + ? 'Im Hausverbrauch enthalten:' + : notInHomeVariant.value.label, +); const openDetails = (event: MouseEvent, component: FlowComponent) => { if (!component.showInfo) { @@ -1010,6 +1015,7 @@ const labelClipPath = computed(() => {
diff --git a/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/HomeConsumptionDetailsDialog.vue b/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/HomeConsumptionDetailsDialog.vue index 102f5bb1fa..cdd520158a 100644 --- a/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/HomeConsumptionDetailsDialog.vue +++ b/packages/modules/web_themes/koala/source/src/components/charts/energyFlowChart/HomeConsumptionDetailsDialog.vue @@ -1,5 +1,5 @@