uid: fronius_energy_flow_v4 tags: - energy - fronius - solar props: parameters: - default: Fronius Power Flow label: Title name: title required: false type: TEXT groupName: design - default: "0.68" description: "Exponent for the scale (default: 0.68; 1=linear, reasonable values range from 0.5 to 2)" label: Exponent name: exponent required: true type: DECIMAL groupName: design advanced: true - default: "20" description: Minimum value for any power flow to be regarded active. Power below this value will be displayed, but regarded inactive and no power flow will be shown. This allows for ignoring energy meter misreadings. label: Mininum power value name: power_min required: true type: DECIMAL groupName: design advanced: true - description: If enabled, applies a color gradient to all energy flow dots, from source color to target color. label: Enable dot gradient name: use_dot_gradient required: true type: BOOLEAN groupName: design advanced: true - default: gold description: CSS color name or hex value (#xxxxxx) for the solar plant label: Solar plant color name: color_solar required: true type: TEXT groupName: color advanced: true - default: limegreen description: CSS color name or hex value (#xxxxxx) for the solar battery label: Battery color name: color_battery required: true type: TEXT groupName: color advanced: true - default: red description: CSS color name or hex value (#xxxxxx) for the solar inverter label: Solar inverter color name: color_inverter required: true type: TEXT groupName: color advanced: true - default: purple description: CSS color name or hex value (#xxxxxx) for the grid label: Grid color name: color_grid required: true type: TEXT groupName: color advanced: true - default: deepskyblue description: CSS color name or hex value (#xxxxxx) for the house label: House color name: color_house required: true type: TEXT groupName: color advanced: true - default: royalblue description: CSS color name or hex value (#xxxxxx) for the electric vehicle label: EV color name: color_ev required: true type: TEXT groupName: color advanced: true - default: darkorange description: CSS color name or hex value (#xxxxxx) for the heat pump label: Heat pump color name: color_heatpump required: true type: TEXT groupName: color advanced: true - default: brown description: CSS color name or hex value (#xxxxxx) for the laundry label: Laundry color name: color_laundry required: true type: TEXT groupName: color advanced: true - context: item description: Solar plant actual power in watts. label: Solar power name: power_solar required: true type: TEXT groupName: data_sources_solar - context: item description: Solar plant popup item, e.g. a group that contains all relevant solar plant data. label: Solar plant popup item name: popup_solar required: false type: TEXT groupName: data_sources_solar - context: item description: Inverter actual power. label: Inverter power name: power_inverter required: true type: TEXT groupName: data_sources_inverter - context: item description: Inverter popup item, e.g. a group that contains all relevant inverter data. label: Inverter popup item name: popup_inverter required: false type: TEXT groupName: data_sources_inverter - default: "10000" description: Inverter maximum power. label: Inverter maximum power name: power_solar_max required: true type: INTEGER min: 800 groupName: data_sources_inverter - context: item description: Grid actual power delivery/consumption. label: Grid power name: power_grid required: true type: TEXT groupName: data_sources_grid - context: item description: Grid popup item, e.g. a group that contains all relevant grid data. label: Grid popup name: popup_grid required: false type: TEXT groupName: data_sources_grid - default: "22000" description: Grid maximum power delivery/consumption. Usually the same as house maximum power. label: Grid maximum power name: power_grid_max required: true type: INTEGER min: 3840 groupName: data_sources_grid advanced: true - context: item description: House actual power consumption. label: House power name: power_house required: true type: TEXT groupName: data_sources_house - context: item description: House popup item, e.g. a group that contains all relevant house data. label: House popup item name: popup_house required: false type: TEXT groupName: data_sources_house - default: "22000" description: House maximum power consumption. Typically, this relates to your primary fuse amperage. label: House maximum power name: power_house_max required: true type: INTEGER min: 3840 groupName: data_sources_house advanced: true - context: item description: Solar battery actual power delivery/consumption. label: Battery power name: power_battery required: true type: TEXT groupName: data_sources_battery - context: item description: Solar battery popup item, e.g. a a group that contains all relevant solar battery data. label: Solar battery popup item name: popup_battery required: false type: TEXT groupName: data_sources_battery - context: item description: State of charge of the solar battery. label: Battery SOC name: soc_battery required: true type: TEXT groupName: data_sources_battery - default: "10200" description: Solar battery energy capacity in Wh. label: Battery capacity name: energy_battery required: true type: INTEGER min: 1000 groupName: data_sources_battery advanced: true - context: item description: Power the heat pump consumes for heating and drinking water. If you don't select an item for this value, the heat pump will not be visible in the widget. label: Heat pump power name: power_heatpump required: false type: TEXT groupName: data_sources_heatpump - context: item description: Current operating state of the heatpump (Standby, heating and so on) label: Heat pump state name: state_heatpump required: false type: TEXT groupName: data_sources_heatpump - context: item description: Heat pump popup item, e.g. a a group that contains all relevant heatpump data. label: Heat pump popup item name: popup_heatpump required: false type: TEXT groupName: data_sources_heatpump - default: "5000" description: Maximum power the heatpump can consume. Can be found in your pump's technical specifications. label: Heatpump maximum power name: power_heatpump_max required: false type: INTEGER min: 1000 groupName: data_sources_heatpump advanced: true - context: item description: EV battery charging power. If you don't select an item for this value, the EV will not be visible in the widget. label: EV battery power name: power_ev required: false type: TEXT groupName: data_sources_ev - context: item description: EV car popup item, e.g. a a group that contains all relevant EV car data. label: EV car popup item name: popup_ev required: false type: TEXT groupName: data_sources_ev - context: item description: State of charge of the EV battery. If you don't select an item for this value, the EV will not be visible in the widget. label: EV battery SOC name: soc_ev required: false type: TEXT groupName: data_sources_ev - context: item description: Current charging state of the EV label: EV charging state name: chargestate_ev required: false type: TEXT groupName: data_sources_ev - context: item description: Current power consumption of the laundry room. If you don't select an item for this value, the laundry will not be visible in the widget. label: Laundry power name: power_laundry required: false type: TEXT groupName: data_sources_laundry - context: item description: Laundry popup item, e.g. a a group that contains all relevant laundry data. label: Laundry - popup item name: popup_laundry required: false type: TEXT groupName: data_sources_laundry - default: "2000" description: Maximum power the laundry can consume. Used to calculate percent background. label: Laundry maximum power name: power_laundry_max required: false type: INTEGER min: 1000 groupName: data_sources_laundry advanced: true parameterGroups: - name: design label: Design elements - name: colors label: Color elements - name: data_sources_solar label: Data sources (solar plant) - name: data_sources_battery label: Data sources (solar battery) - name: data_sources_inverter label: Data sources (inverter) - name: data_sources_grid label: Data sources (grid) - name: data_sources_house label: Data sources (house) - name: data_sources_ev label: Data sources (electric vehicle) - name: data_sources_heatpump label: Data sources (heating system) - name: data_sources_laundry label: Data sources (laundry room) timestamp: May 17, 2026, 11:20:09 AM component: f7-card config: comment: This component determines the size of the widget. outline: true title: =props.title slots: default: - component: oh-context config: comment: "'arc_flag' determines which arc should be drawn (short or long). 'resize_dot' adjusts the size of the energy flow dots in relation to the highest value in the system. The value correlates to the area of the dot, not its radius to give a better visual feedback. 'scale_to_deg' makes sure the input value does not exceed power_xxxx_max and scales everything to 270°. 'switch_color' handles power less than props.power_min and sets the color dependent on the data_source, based on the dictionary in the function. 'switch_magnitude' switches between W an kW depending on the input value. 'to_cartesian' converts degree to cartesian coordinates to be used by arc." functions: arc_flag: "=degree => degree < 180 ? 0 : 1" resize_dot: "=value => Math.abs(value) < props.power_min ? 0 : `${Math.pow(Math.max(Math.abs(value) / Math.max( (Math.abs(#props.power_house) + (#props.power_grid > 0 ? #props.power_grid : 0)), Math.abs(#props.power_grid), Math.abs(#props.power_solar), Math.abs(#props.power_battery)), 0.05), 0.5) * 6}px`" scale_to_deg: =(value, max) => Math.pow(Math.min(Math.abs(value), max) * (270 / max), props.exponent) * (270 / Math.pow(270, props.exponent)) switch_color: '=(value, type) => (Math.abs(value) >= props.power_min) ? {"solar": props.color_solar, "grid": props.color_grid, "inverter": props.color_inverter, "house": props.color_house, "battery": props.color_battery, "ev": props.color_ev, "laundry": props.color_laundry, "heatpump": props.color_heatpump}[type] : "grey"' switch_magnitude: "=value => Math.abs(value) > 999 ? `${(Math.abs(value) / 1000).toFixed(Math.abs(value) > 9999 ? 1 : 2)} kW` : `${Math.round(Math.abs(value)) | 0} W`" to_cartesian: =degree => (50 + Math.sin(degree * Math.PI / 180) * 41) + " " + (50 - Math.cos(degree * Math.PI / 180) * 41) fan_speed: =(curr, max) => Math.max(0.5, 3 - 3 * Math.min(curr, max) / max) constants: dot_gradient_start: "0.35" dot_gradient_stop: "0.8" slots: default: - component: f7-block config: style: content-justify: center display: flex height: 100% padding: 5% width: 100% slots: default: - component: svg config: comment: The component scales freely to the size of its parent. height: 100% viewBox: 0 0 500 300 width: 100% slots: default: - component: defs slots: default: - component: symbol config: id: few_segment_line slots: default: - component: line config: comment: Separator line for the dial. style: stroke: white stroke-width: 1px x1: 50px x2: 50px y1: 2px y2: 16px - component: symbol config: comment: "Draws the background of each dial: Outer ring, scale backdrop, inner Ring." id: few_rings slots: default: - component: circle config: comment: Outer ring. The stroke color uses the base color with less opacity. cx: 50px cy: 50px fill: white r: 49.5px style: stroke-opacity: 0.4 stroke-width: 1px - component: circle config: comment: Inner ring. The stroke color uses the base color with less opacity. cx: 50px cy: 50px fill: none r: 32.5px style: stroke-opacity: 0.4 stroke-width: 1px - component: path config: comment: Background of the dial. The stroke color uses the base color with less opacity. cx: 50px cy: 50px d: M50,9A41,41,0,1,1,9,50 fill: none r: 41px style: stroke-opacity: 0.4 stroke-width: 14px - component: path config: comment: Path for numerical display of value. d: M9,50A41,41,0,0,1,50,9 fill: none id: few_text_path stroke-width: 0px - component: g config: comment: Solar panel id: few_solarpanel slots: default: - component: g config: comment: Solar to inverter flow visualisation id: few_solar_inverter_flow slots: default: - component: defs slots: default: - component: linearGradient config: comment: Gradient for solar to inverter flow id: gradient_solar_inverter_flow x1: 0 x2: 1 y1: 0 y2: 1 slots: default: - component: stop config: offset: 0 stop-color: = props.color_solar - component: stop config: offset: =const.dot_gradient_start stop-color: = props.color_solar - component: stop config: offset: =const.dot_gradient_stop stop-color: "= props.use_dot_gradient ? props.color_inverter : props.color_solar" - component: stop config: offset: 1 stop-color: "= props.use_dot_gradient ? props.color_inverter : props.color_solar" - component: path config: comment: Energy flow visualization solar to inverter. d: M80,80L120,120 id: few_solar_inverter_path style: stroke: darkgray stroke-width: 1px - component: oh-repeater config: comment: Sets up the circles, indicating the energy flow. for: offset fragment: true rangeStart: 0 rangeStep: 1 rangeStop: 2 sourceType: range slots: default: - component: circle config: fill: url(#gradient_solar_inverter_flow) r: "=fn.resize_dot(#props.power_solar + (#props.power_battery < 0 ? #props.power_battery : 0))" slots: default: - component: animateMotion config: begin: =`${loop.offset}s` calcMode: linear dur: 3s repeatCount: indefinite slots: default: - component: mpath config: xlink:href: "#few_solar_inverter_path" - component: g config: comment: Solar to battery flow visualisation id: few_solar_battery_flow slots: default: - component: defs slots: default: - component: linearGradient config: comment: Gradient for solar to battery flow id: gradient_solar_battery_flow x1: 0 x2: 0 y1: 0 y2: 1 slots: default: - component: stop config: offset: 0 stop-color: = props.color_solar - component: stop config: offset: =const.dot_gradient_start stop-color: = props.color_solar - component: stop config: offset: =const.dot_gradient_stop stop-color: "= props.use_dot_gradient ? props.color_battery : props.color_solar" - component: stop config: offset: 1 stop-color: "= props.use_dot_gradient ? props.color_battery : props.color_solar" - component: path config: comment: Energy flow visualization solar to battery. d: M50,100L50,200 id: few_solar_battery_path style: stroke: darkgray stroke-width: 1px - component: oh-repeater config: comment: Sets up the circles, indicating the energy flow. for: offset fragment: true rangeStart: 0 rangeStep: 1 rangeStop: 2 sourceType: range slots: default: - component: circle config: fill: url(#gradient_solar_battery_flow) r: "=fn.resize_dot(#props.power_battery < 0 ? #props.power_battery:0)" slots: default: - component: animateMotion config: begin: =`${loop.offset}s` calcMode: linear dur: 3s repeatCount: indefinite slots: default: - component: mpath config: xlink:href: "#few_solar_battery_path" - component: use config: comment: Solar dial. style: stroke: =fn.switch_color(#props.power_solar, "solar") x: 0px xlink:href: "#few_rings" y: 0px - component: path config: comment: Dial, using an exponential scale. If the value exceeds power_solar_max, the color dial turns red. d: =`M50,9A41,41,0,${fn.arc_flag(fn.scale_to_deg(#props.power_solar, props.power_solar_max))},1, ${fn.to_cartesian(fn.scale_to_deg(#props.power_solar, props.power_solar_max))}` fill: none style: stroke: =(#props.power_solar < props.power_solar_max) ? fn.switch_color(#props.power_solar, "solar"):"red" stroke-width: 14px - component: text config: style: dominant-baseline: central fill: dimgray font-family: sans-serif font-size: 11px font-weight: bold letter-spacing: 1px text-anchor: middle translate: 0px 0px slots: default: - component: textPath config: content: =fn.switch_magnitude(#props.power_solar) startOffset: 50% xlink:href: "#few_text_path" - component: svg config: comment: solar icon area height: 44px width: 44px x: 28px y: 28px slots: default: - component: oh-link config: action: group actionGroupPopupItem: =props.popup_solar slots: default: - component: svg config: comment: solar icon height: 100% stroke-miterlimit: 10 stroke-width: 0.3px viewBox: 0 0 24 24 width: 100% slots: default: - component: defs slots: default: - component: linearGradient config: comment: Gradient for solar plant power. y1 = 100% means "start at bottom" gradientUnits: userSpaceOnUse id: gradient_solar x1: 0 x2: 0 y1: 2 y2: 24 slots: default: - component: stop config: offset: 0 stop-color: =fn.switch_color(#props.power_solar, "solar") - component: stop config: offset: =(#props.power_solar / props.power_solar_max) stop-color: =fn.switch_color(#props.power_solar, "solar") - component: stop config: offset: 1 stop-color: =fn.switch_color(0, "solar") - component: rect config: comment: invisible rectangle to provide a clickable area for oh-link height: 100% opacity: 0 width: 100% - component: path config: d: M12,8a4,4,0,1,0,4,4A4,4,0,0,0,12,8Z fill: url(#gradient_solar) stroke: url(#gradient_solar) - component: rect config: fill: url(#gradient_solar) height: 4 rx: 0.75 stroke: url(#gradient_solar) width: 1.5 x: 11.25 y: 2 - component: rect config: fill: url(#gradient_solar) height: 4 rx: 0.75 stroke: url(#gradient_solar) width: 1.5 x: 11.25 y: 18 - component: rect config: fill: url(#gradient_solar) height: 4 rx: 0.75 stroke: url(#gradient_solar) transform: translate(32 -8) rotate(90) width: 1.5 x: 19.25 y: 10 - component: rect config: fill: url(#gradient_solar) height: 4 rx: 0.75 stroke: url(#gradient_solar) transform: translate(16 8) rotate(90) width: 1.5 x: 3.25 y: 10 - component: rect config: fill: url(#gradient_solar) height: 4 rx: 0.75 stroke: url(#gradient_solar) transform: translate(42.63 17.66) rotate(135) width: 1.5 x: 16.91 y: 15.66 - component: rect config: fill: url(#gradient_solar) height: 4 rx: 0.75 stroke: url(#gradient_solar) transform: translate(15.31 6.34) rotate(135) width: 1.5 x: 5.59 y: 4.34 - component: rect config: fill: url(#gradient_solar) height: 4 rx: 0.75 stroke: url(#gradient_solar) transform: translate(-1.66 34.63) rotate(-135) width: 1.5 x: 5.59 y: 15.66 - component: rect config: fill: url(#gradient_solar) height: 4 rx: 0.75 stroke: url(#gradient_solar) transform: translate(25.66 23.31) rotate(-135) width: 1.5 x: 16.91 y: 4.34 - component: g config: comment: Grid id: few_grid slots: default: - component: g config: comment: Inverter to grid energy flow visualisation id: few_inverter_grid_flow slots: default: - component: defs slots: default: - component: linearGradient config: comment: Gradient for inverter to grid flow id: gradient_inverter_grid_flow x1: 0 x2: 1 y1: 1 y2: 0 slots: default: - component: stop config: offset: 0 stop-color: "= props.use_dot_gradient ? props.color_inverter : props.color_grid" - component: stop config: offset: =const.dot_gradient_start stop-color: "= props.use_dot_gradient ? props.color_inverter : props.color_grid" - component: stop config: offset: =const.dot_gradient_stop stop-color: = props.color_grid - component: stop config: offset: 1 stop-color: = props.color_grid - component: path config: comment: Inverter to grid energy flow visualization. d: M180,120L220,80 id: few_inverter_grid_path style: stroke: darkgray stroke-width: 1px - component: oh-repeater config: comment: Sets up the circles, indicating the energy flow. for: offset fragment: true rangeStart: 0 rangeStep: 1 rangeStop: 2 sourceType: range slots: default: - component: circle config: fill: url(#gradient_inverter_grid_flow) r: "=fn.resize_dot(#props.power_grid < 0 ? #props.power_grid : 0)" slots: default: - component: animateMotion config: begin: =`${loop.offset}s` calcMode: linear dur: 3s repeatCount: indefinite slots: default: - component: mpath config: xlink:href: "#few_inverter_grid_path" - component: g config: comment: Grid to house energy flow visualisation. id: few_grid_house_flow slots: default: - component: defs slots: default: - component: linearGradient config: comment: Gradient for grid to house flow id: gradient_grid_house_flow x1: 0 x2: 1 y1: 0 y2: 1 slots: default: - component: stop config: offset: 0 stop-color: "= props.use_dot_gradient ? props.color_grid : props.color_house" - component: stop config: offset: =const.dot_gradient_start stop-color: "= props.use_dot_gradient ? props.color_grid : props.color_house" - component: stop config: offset: =const.dot_gradient_stop stop-color: =props.color_house - component: stop config: offset: 1 stop-color: =props.color_house - component: path config: comment: Energy flow visualization grid. d: M280,80L320,120 id: few_grid_house_path style: stroke: darkgray stroke-width: 1px - component: oh-repeater config: comment: Sets up the circles, indicating the energy flow. for: offset fragment: true rangeStart: 0 rangeStep: 1 rangeStop: 2 sourceType: range slots: default: - component: circle config: fill: url(#gradient_grid_house_flow) r: "=fn.resize_dot(#props.power_grid > 0 ? #props.power_grid : 0)" slots: default: - component: animateMotion config: begin: =`${loop.offset}s` calcMode: linear dur: 3s repeatCount: indefinite slots: default: - component: mpath config: xlink:href: "#few_grid_house_path" - component: use config: comment: Grid dial. style: stroke: =fn.switch_color(#props.power_grid, "grid") x: 200px xlink:href: "#few_rings" y: 0px - component: path config: comment: Dial, using a exponential scale. d: =`M50,9A41,41,0 ${fn.arc_flag(fn.scale_to_deg(#props.power_grid, props.power_grid_max))},1, ${fn.to_cartesian(fn.scale_to_deg(#props.power_grid, props.power_grid_max))}` fill: rgba(0, 0, 0, 0) style: stroke: =fn.switch_color(#props.power_grid, "grid") stroke-width: 14px translate: 200px 0px - component: text config: style: dominant-baseline: central fill: dimgray font-family: sans-serif font-size: 11px font-weight: bold letter-spacing: 1px text-anchor: middle translate: 200px 0px slots: default: - component: textPath config: content: =fn.switch_magnitude(#props.power_grid) startOffset: 50% xlink:href: "#few_text_path" - component: svg config: comment: grid icon height: 44px width: 44px x: 228px y: 28px slots: default: - component: oh-link config: action: group actionGroupPopupItem: =props.popup_grid slots: default: - component: svg config: comment: grid icon fill: =fn.switch_color(#props.power_grid, "grid") height: 100% viewBox: 0 0 24 24 width: 100% slots: default: - component: rect config: comment: invisible rectangle to provide a clickable area for oh-link height: 100% opacity: 0 width: 100% - component: path config: d: M13.38,8.54V6.63H18.3V8.06h.95V5.7l-6.35-1L12,2l-1,2.8-6.25.9V8.07H5.6V6.63h4.84V8.54l-7.59,1.9v2.84H3.8V11.76H9.87L6.93,22H9.11l.57-2.46h4.59L14.8,22h2.27L14.13,11.76H20.2v1.52h.95V10.44Zm-3.32,8.81L12,11.11l1.91,6.24Z - component: g config: comment: Battery id: few_battery slots: default: - component: g config: comment: Energy flow visualisation id: few_battery_inverter_flow slots: default: - component: defs slots: default: - component: linearGradient config: comment: Gradient for battery to inverter flow id: gradient_battery_inverter_flow x1: 0 x2: 1 y1: 1 y2: 0 slots: default: - component: stop config: offset: 0 stop-color: = props.color_battery - component: stop config: offset: =const.dot_gradient_start stop-color: = props.color_battery - component: stop config: offset: 0.65 stop-color: "= props.use_dot_gradient ? props.color_inverter : props.color_battery" - component: stop config: offset: 1 stop-color: "= props.use_dot_gradient ? props.color_inverter : props.color_battery" - component: path config: comment: Energy flow visualization battery. d: '=#props.power_battery >= 0 ? "M80,220L120,180" : "M120,180L80,220"' id: few_battery_inverter_path style: stroke: darkgray stroke-width: 1px - component: oh-repeater config: comment: Sets up the circles, indicating the energy flow. for: offset fragment: true rangeStart: 0 rangeStep: 1 rangeStop: 2 sourceType: range slots: default: - component: circle config: fill: url(#gradient_battery_inverter_flow) r: "=fn.resize_dot(#props.power_battery > 0 ? #props.power_battery : 0)" slots: default: - component: animateMotion config: begin: =`${loop.offset}s` calcMode: linear dur: 3s repeatCount: indefinite slots: default: - component: mpath config: xlink:href: "#few_battery_inverter_path" - component: use config: comment: Battery dial. style: stroke: "=(#props.soc_battery < 0.07 ? fn.switch_color(#props.power_battery, 'battery') : props.color_battery)" x: 0px xlink:href: "#few_rings" y: 200px - component: path config: comment: Dial, using a exponential scale. d: =`M50,9A41,41,0,${fn.arc_flag(fn.scale_to_deg(#props.power_battery, props.energy_battery))},1, ${fn.to_cartesian(fn.scale_to_deg(#props.power_battery, props.energy_battery))}` fill: rgba(0, 0, 0, 0) style: stroke: "=(#props.soc_battery < 0.07 ? fn.switch_color(#props.power_battery, 'battery') : props.color_battery )" stroke-width: 14px translate: 0px 200px - component: text config: style: dominant-baseline: central fill: dimgray font-family: sans-serif font-size: 11px font-weight: bold letter-spacing: 1px text-anchor: middle translate: 0px 200px slots: default: - component: textPath config: content: =fn.switch_magnitude(#props.power_battery) startOffset: 50% xlink:href: "#few_text_path" - component: svg config: comment: solar battery icon area height: 44px width: 44px x: 28px y: 228px slots: default: - component: oh-link config: action: group actionGroupPopupItem: =props.popup_battery slots: default: - component: svg config: comment: solar battery icon fill: =(#props.soc_battery > 0.07 ? props.color_battery:fn.switch_color(#props.power_battery, "battery")) height: 100%> viewBox: 0 0 24 24 width: 100% slots: default: - component: defs slots: default: - component: linearGradient config: comment: Gradient for solar battery SOC. y1 = 100% means "start at bottom" gradientUnits: userSpaceOnUse id: gradient_battery x1: 0 x2: 0 y1: 20.5 y2: 6 slots: default: - component: stop config: offset: 0 stop-color: =(#props.soc_battery > 0.07 ? props.color_battery:fn.switch_color(#props.power_battery, "battery")) - component: stop config: offset: =#props.soc_battery stop-color: =(#props.soc_battery > 0.07 ? props.color_battery:fn.switch_color(#props.power_battery, "battery")) - component: stop config: offset: =#props.soc_battery stop-color: white - component: stop config: offset: 1 stop-color: white - component: linearGradient config: comment: Gradient for solar battery charging flash. y1 = 100% means "start at bottom" gradientUnits: userSpaceOnUse id: gradient_charge x1: 0 x2: 0 y1: 20.5 y2: 6 slots: default: - component: stop config: offset: 0 stop-color: white - component: stop config: offset: =#props.soc_battery stop-color: white - component: stop config: offset: =#props.soc_battery stop-color: =(#props.soc_battery > 0.07 ? props.color_battery:fn.switch_color(#props.power_battery, "battery")) - component: stop config: offset: 1 stop-color: =(#props.soc_battery > 0.07 ? props.color_battery:fn.switch_color(#props.power_battery, "battery")) - component: linearGradient config: comment: Gradient for solar battery charging flash. y1 = 100% means "start at bottom" gradientUnits: userSpaceOnUse id: gradient_soc x1: 6 x2: 19 y1: 0 y2: 0 slots: default: - component: stop config: offset: 0 stop-color: white - component: stop config: offset: =#props.soc_battery stop-color: white - component: stop config: offset: =#props.soc_battery stop-color: =(#props.soc_battery > 0.07 ? props.color_battery:fn.switch_color(#props.power_battery, "battery")) - component: stop config: offset: 1 stop-color: =(#props.soc_battery > 0.07 ? props.color_battery:fn.switch_color(#props.power_battery, "battery")) - component: rect config: comment: invisible rectangle to provide a clickable area for oh-link height: 100% opacity: 0 width: 100% - component: rect config: comment: positive pole of battery icon height: 1.5 rx: 0.5 ry: 0.5 width: 5.5 x: 9.25 y: 3 - component: rect config: comment: outer frame of battery icon fill: url(#gradient_battery) height: 16 rx: 1 ry: 1 stroke: =(#props.soc_battery > 0.07 ? props.color_battery:fn.switch_color(#props.power_battery, "battery")) stroke-width: 1 width: 10 x: 7 y: 5.5 - component: polygon config: comment: flash icon when charging fill: url(#gradient_charge) points: 12.55,11.9 12.55,8 9.8,13.6 11.45,13.6 11.45,17.2 14.14,11.9 stroke: white stroke-linejoint: miter stroke-miterlimit: 5 stroke-width: 0.2 visible: =(#props.power_battery < (-1 * props.power_min)) - component: text config: comment: state of charge when full or discharging content: =@props.soc_battery fill: url(#gradient_soc) font-size: 4.5px font-weight: bold stroke: =props.color_battery stroke-width: 0.1 transform: rotate(270 12,13.5) visible: =(#props.power_battery > (props.power_min) && (#props.soc_battery) < 0.98) x: 5 y: 14.8 - component: g config: comment: Inverter id: few_inverter slots: default: - component: g config: comment: Inverter to house energy flow visualisation id: few_inverter_house_flow slots: default: - component: defs slots: default: - component: linearGradient config: comment: Gradient for inverter to house flow id: gradient_inverter_house_flow x1: 0 x2: 1 y1: 0 y2: 0 slots: default: - component: stop config: offset: 0 stop-color: "= props.use_dot_gradient ? props.color_inverter : props.color_house" - component: stop config: offset: =const.dot_gradient_start stop-color: "= props.use_dot_gradient ? props.color_inverter : props.color_house" - component: stop config: offset: =const.dot_gradient_stop stop-color: =props.color_house - component: stop config: offset: 1 stop-color: =props.color_house - component: path config: comment: House energy flow visualization. d: M190,150L310,150 id: few_inverter_house_path style: stroke: darkgray stroke-width: 1px - component: oh-repeater config: comment: Sets up the circles, indicating the energy flow. for: offset fragment: true rangeStart: 0 rangeStep: 1 rangeStop: 4 sourceType: range slots: default: - component: circle config: comment: Power to house has 2 sources - grid and inverter. If power is coming from grid, we need math to adjust energy flow from inverter. power_house is always negative. If power comes from grid, it is positive, so we simply "add it" to subtract it from the power flow. fill: url(#gradient_inverter_house_flow) r: "=fn.resize_dot(#props.power_house + (#props.power_grid > 0 ? #props.power_grid : 0))" slots: default: - component: animateMotion config: begin: =`${loop.offset}s` calcMode: linear dur: 5s repeatCount: indefinite slots: default: - component: mpath config: xlink:href: "#few_inverter_house_path" - component: use config: comment: Inverter dial. style: stroke: =fn.switch_color(#props.power_inverter, "inverter") x: 100px xlink:href: "#few_rings" y: 100px - component: path config: comment: Dial, using an exponential scale. If the value exceeds max_solar_power, the color dial turns red. d: =`M50,9A41,41,0,${fn.arc_flag(fn.scale_to_deg(#props.power_inverter, props.power_solar_max))},1, ${fn.to_cartesian(fn.scale_to_deg(#props.power_inverter, props.power_solar_max))}` fill: none style: stroke: '=(#props.power_inverter < props.max_solar_power) ? fn.switch_color(#props.power_inverter, "inverter") : "red"' stroke-width: 14px translate: 100px 100px - component: text config: style: dominant-baseline: central fill: dimgray font-family: sans-serif font-size: 11px font-weight: bold letter-spacing: 1px text-anchor: middle translate: 100px 100px slots: default: - component: textPath config: content: =fn.switch_magnitude(#props.power_inverter) startOffset: 50% xlink:href: "#few_text_path" - component: svg config: comment: inverter icon area height: 44px width: 44px x: 128px y: 128px slots: default: - component: oh-link config: action: group actionGroupPopupItem: =props.popup_inverter slots: default: - component: svg config: comment: inverter icon height: 100% stroke: dimgray stroke-miterlimit: 10 viewBox: 0 0 70 70 width: 100% slots: default: - component: rect config: comment: invisible rectangle to provide a clickable area for oh-link height: 100% opacity: 0 width: 100% - component: rect config: comment: main inverter outline fill: linen height: 64 rx: 6.8 stroke-width: 2px width: 58.7 x: 5.65 y: 3 stroke: =fn.switch_color(#props.power_inverter, "inverter") - component: rect config: comment: inverter lower area y: 53.08 x: 5.65 width: 58.7 height: 13.02 fill: =fn.switch_color(#props.power_inverter, "inverter") fill-opacity: 0.3 rx: 6.8 - component: circle config: comment: fan intake cx: 35.03 cy: 29.61 fill: =fn.switch_color(#props.power_inverter, "inverter") fill-opacity: 0.7 r: 11 - component: circle config: comment: main power switch cx: 15 cy: 40 fill: =fn.switch_color(#props.power_inverter, "inverter") fill-opacity: 1 r: 4 - component: path config: comment: status LED and touch button area d: M40.19,52H36.73a2,2,0,0,0-3.46,0H29.81a1.08,1.08,0,1,0,0,2.15h3.46a2,2,0,0,0,3.46,0h3.46a1.08,1.08,0,1,0,0-2.15Z fill: lime - component: path config: comment: fronius decal in lower area d: M34.89,61.87c-3.24,0-5.87-.73-5.87-1.62s2.63-1.64,5.87-1.64,5.87.74,5.87,1.64S38.13,61.87,34.89,61.87Z fill: white - component: line config: comment: line from status area to the left fill: none x1: 5.07 x2: 28.73 y1: 53.08 y2: 53.08 - component: line config: comment: line from status area to the right fill: none x1: 41.27 x2: 64.93 y1: 53.08 y2: 53.08 - component: g config: comment: EV battery id: few_ev visible: =((props.power_ev && props.soc_ev) ? true:false) slots: default: - component: g config: comment: House to EV energy flow visualisation id: few_house_ev_flow slots: default: - component: defs slots: default: - component: linearGradient config: comment: Gradient for house to EV flow id: gradient_house_ev_flow x1: 0 x2: 1 y1: 1 y2: 0 slots: default: - component: stop config: offset: 0 stop-color: "= props.use_dot_gradient ? props.color_house : props.color_ev" - component: stop config: offset: =const.dot_gradient_start stop-color: "= props.use_dot_gradient ? props.color_house : props.color_ev" - component: stop config: offset: =const.dot_gradient_stop stop-color: =props.color_ev - component: stop config: offset: 1 stop-color: =props.color_ev - component: path config: comment: EV energy flow visualization load. d: M380,120L420,80 id: few_house_ev_path style: stroke: darkgray stroke-width: 1px - component: oh-repeater config: comment: Sets up the circles, indicating the energy flow. for: offset fragment: true rangeStart: 0 rangeStep: 1 rangeStop: 2 sourceType: range slots: default: - component: circle config: fill: url(#gradient_house_ev_flow) r: =fn.resize_dot(#props.power_ev) slots: default: - component: animateMotion config: begin: =`${loop.offset}s` calcMode: linear dur: 3s repeatCount: indefinite slots: default: - component: mpath config: xlink:href: "#few_house_ev_path" - component: use config: comment: EV battery dial. style: stroke: =fn.switch_color(#props.power_ev, "ev") x: 400px xlink:href: "#few_rings" y: 0px - component: path config: comment: Dial, using a linear scale. d: =`M50,9A41,41,0,${fn.arc_flag(#props.soc_ev / 100 * 270)},1, ${fn.to_cartesian(#props.soc_ev / 100 * 270)}` fill: none style: stroke: =fn.switch_color(#props.power_ev, "ev") stroke-width: 14px translate: 400px 0px - component: text config: style: dominant-baseline: central fill: dimgray font-family: sans-serif font-size: =(#props.power_ev > 0 ? "11px":"10px") font-weight: bold letter-spacing: =(#props.power_ev > 0 ? "1px" ) text-anchor: middle translate: 400px 0px slots: default: - component: textPath config: content: =(#props.power_ev > 0 ? fn.switch_magnitude(#props.power_ev):@props.chargestate_ev) startOffset: 50% xlink:href: "#few_text_path" - component: svg config: comment: car icon area height: 44px width: 44px x: 428px y: 28px slots: default: - component: oh-link config: action: group actionGroupPopupItem: =props.popup_ev slots: default: - component: svg config: comment: car icon height: 100% viewBox: 0 0 24 24 width: 100% slots: default: - component: rect config: comment: invisible rectangle to provide a clickable area for oh-link height: 100% opacity: 0 width: 100% - component: path config: d: M3,8L5.72187,10.2682C5.90158,10.418,6.12811,10.5,6.36205,10.5H17.6379C17.8719,10.5,18.0984,10.418,18.2781,10.2682L21,8M6.5,14H6.51M17.5,14H17.51M8.16065,4.5H15.8394C16.5571,4.5,17.2198,4.88457,17.5758,5.50772L20.473,10.5777C20.8183,11.1821,21,11.8661,21,12.5623V18.5C21,19.0523,20.5523,19.5,20,19.5H19C18.4477,19.5,18,19.0523,18,18.5V17.5H6V18.5C6,19.0523,5.55228,19.5,5,19.5H4C3.44772,19.5,3,19.0523,3,18.5V12.5623C3,11.8661,3.18166,11.1821,3.52703,10.5777L6.42416,5.50772C6.78024,4.88457,7.44293,4.5,8.16065,4.5ZM7,14C7,14.2761,6.77614,14.5,6.5,14.5C6.22386,14.5,6,14.2761,6,14C6,13.7239,6.22386,13.5,6.5,13.5C6.77614,13.5,7,13.7239,7,14ZM18,14C18,14.2761,17.7761,14.5,17.5,14.5C17.2239,14.5,17,14.2761,17,14C17,13.7239,17.2239,13.5,17.5,13.5C17.7761,13.5,18,13.7239,18,14Z fill: none stroke: =fn.switch_color(#props.power_ev, "ev") stroke-linecap: round stroke-linejoin: round stroke-width: 2 - component: g config: comment: Laundry id: few_laundry visible: =(props.power_laundry ? true:false) slots: default: - component: g config: comment: House to laundry energy flow visualisation id: few_house_laundry_flow slots: default: - component: defs slots: default: - component: linearGradient config: comment: Gradient for house to laundry flow id: gradient_house_laundry_flow x1: 1 x2: 0 y1: 0 y2: 1 slots: default: - component: stop config: offset: 0 stop-color: "= props.use_dot_gradient ? props.color_house : props.color_laundry" - component: stop config: offset: =const.dot_gradient_start stop-color: "= props.use_dot_gradient ? props.color_house : props.color_laundry" - component: stop config: offset: =const.dot_gradient_stop stop-color: =props.color_laundry - component: stop config: offset: 1 stop-color: =props.color_laundry - component: path config: comment: Energy flow visualization load. d: M320,180L280,220 id: few_house_laundry_path style: stroke: darkgray stroke-width: 1px - component: oh-repeater config: comment: Sets up the circles, indicating the energy flow. for: offset fragment: true rangeStart: 0 rangeStep: 1 rangeStop: 2 sourceType: range slots: default: - component: circle config: fill: url(#gradient_house_laundry_flow) r: =fn.resize_dot(#props.power_laundry) slots: default: - component: animateMotion config: begin: =`${loop.offset}s` calcMode: linear dur: 3s repeatCount: indefinite slots: default: - component: mpath config: xlink:href: "#few_house_laundry_path" - component: use config: comment: Laundry power dial style: stroke: =fn.switch_color(#props.power_laundry, "laundry") x: 200px xlink:href: "#few_rings" y: 200px - component: path config: comment: Dial, using an exponential scale scale. d: =`M50,9A41,41,0,${fn.arc_flag(fn.scale_to_deg(#props.power_laundry, props.power_laundry_max))},1, ${fn.to_cartesian(fn.scale_to_deg(#props.power_laundry, props.power_laundry_max))}` fill: none style: stroke: =fn.switch_color(#props.power_laundry, "laundry") stroke-width: 14px translate: 200px 200px - component: text config: style: dominant-baseline: central fill: dimgray font-family: sans-serif font-size: 11px font-weight: bold letter-spacing: 1px text-anchor: middle translate: 200px 200px slots: default: - component: textPath config: content: =fn.switch_magnitude(#props.power_laundry) startOffset: 50% xlink:href: "#few_text_path" - component: svg config: comment: laundry icon area height: 44px width: 44px x: 228px y: 228px slots: default: - component: oh-link config: action: group actionGroupPopupItem: =props.popup_laundry slots: default: - component: svg config: comment: laundry icon fill: =fn.switch_color(#props.power_laundry, "laundry") height: 100% viewBox: 0 0 1024 1024 width: 100% slots: default: - component: rect config: comment: invisible rectangle to provide a clickable area for oh-link height: 100% opacity: 0 width: 100% - component: path config: d: M214.25,133.12h600v790a30,30,0,0,1-30,30h-540a30,30,0,0,1-30-30v-790z opacity: 0.5 - component: path config: d: M784.25,960.62h-540a37.54,37.54,0,0,1-37.5-37.5v-790a7.5,7.5,0,0,1,7.5-7.5h600a7.5,7.5,0,0,1,7.5 7.5v790a37.54,37.54,0,0,1-37.5,37.5z m-562.5-820v782.5a22.53,22.53,0,0,0,22.5,22.5h540a22.53,22.53,0,0,0,22.5-22.5v-782.5z - component: path config: d: M244.25,72.5h540a30,30,0,0,1,30,30v170h-600v-170a30,30,0,0,1,30-30z fill: white - component: path config: d: M814.25,280h-600a7.5,7.5,0,0,1-7.5-7.5v-170a37.54,37.54,0,0,1,37.5-37.5h540a37.54,37.54,0,0,1,37.5,37.5v170a7.5,7.5,0,0,1-7.5,7.5z m-592.5-15h585V102.5a22.53,22.53,0,0,0-22.5-22.5h-540a22.53,22.53,0,0,0-22.5,22.5z - component: path config: d: M514.25,569.19m-200,0a200,200,0,1,0,400,0,200,200,0,1,0-400,0Z fill: white - component: path config: d: M514.25,776.69c-114.42,0,-207.5,-93.08,-207.5,-207.5s93.08,-207.5,207.5,-207.5,207.5,93.08,207.5,207.5,-93.08,207.5,-207.5,207.5z m0,-400c-106.15,0,-192.5,86.36,-192.5,192.5s86.35,192.5,192.5,192.5,192.5,-86.36,192.5,-192.5,-86.35,-192.5,-192.5,-192.5z opacity: 0.5 - component: path config: d: M514.25 569.19m-150 0a150 150 0 1 0 300 0 150 150 0 1 0-300 0Z - component: path config: d: M514.34,721.69h-0.09a153.69,153.69,0,0,1,-29.65,-2.88,2.5,2.5,0,0,1,1,-4.91,148.59,148.59,0,0,0,28.69,2.79,2.54,2.54,0,0,1,2.54,2.5,2.46,2.46,0,0,1,-2.49,2.5z m29.25,-2.87a2.5,2.5,0,0,1,-0.48,-5,146.81,146.81,0,0,0,27.66,-8.39,2.5,2.5,0,1,1,1.92,4.62,151.72,151.72,0,0,1,-28.6,8.68,2.54,2.54,0,0,1,-0.5,0.09z m-86.65,-8.47a2.5,2.5,0,0,1,-1,-0.19,152.37,152.37,0,0,1,-26.36,-14.09,2.5,2.5,0,1,1,2.78,-4.16,147.3,147.3,0,0,0,25.5,13.63,2.5,2.5,0,0,1,-1,4.81z m140.7,-14a2.5,2.5,0,0,1,-1.39,-4.58,148.45,148.45,0,0,0,22.33,-18.36,2.5,2.5,0,1,1,3.54,3.54A153.46,153.46,0,0,1,599,696a2.49,2.49,0,0,1,-1.36,0.39z m-189.36,-18.51a2.49,2.49,0,0,1,-1.77,-0.73,153.56,153.56,0,0,1,-19,-23.08,2.5,2.5,0,0,1,4.15,-2.79A148.55,148.55,0,0,0,410,673.57a2.5,2.5,0,0,1,-1.77,4.27z M639,655a2.5,2.5,0,0,1,-2.08,-3.89,147.51,147.51,0,0,0,13.64,-25.49,2.5,2.5,0,1,1,4.62,1.91,152.57,152.57,0,0,1,-14.11,26.36A2.5,2.5,0,0,1,639,655z m-263.31,-25.76a2.5,2.5,0,0,1,-2.31,-1.54,151.76,151.76,0,0,1,-8.7,-28.6,2.5,2.5,0,1,1,4.9,-1,146.7,146.7,0,0,0,8.42,27.68,2.5,2.5,0,0,1,-2.31,3.46z m285.71,-28.3a2.45,2.45,0,0,1,-0.49,0,2.5,2.5,0,0,1,-2,-2.94,148.67,148.67,0,0,0,2.8,-28.77v-0.34a2.5,2.5,0,0,1,2.49,-2.51,2.5,2.5,0,0,1,2.5,2.49v0.36a153.71,153.71,0,0,1,-2.9,29.74,2.5,2.5,0,0,1,-2.4,1.97z m-297.15-29.08a2.5,2.5,0,0,1-2.5-2.5v-0.17a153.75,153.75,0,0,1,2.86-29.57,2.5,2.5,0,1,1,4.91,1,148.75,148.75,0,0,0-2.77,28.61v0.17a2.5,2.5,0,0,1-2.5,2.46z m297.08-29.77a2.5,2.5,0,0,1-2.45-2,146.75,146.75,0,0,0-8.44-27.64,2.5,2.5,0,1,1,4.61-1.93,151.75,151.75,0,0,1,8.73,28.59,2.5,2.5,0,0,1-2.45,3z m-285.77-27.63a2.5,2.5,0,0,1-2.31-3.46,152.4,152.4,0,0,1,14.08-26.37,2.5,2.5,0,0,1,4.16,2.78,147.45,147.45,0,0,0-13.61,25.5,2.5,2.5,0,0,1-2.32,1.55z m263.26-26.37a2.5,2.5,0,0,1-2.08-1.1,148.53,148.53,0,0,0-18.4-22.3,2.5,2.5,0,1,1,3.53-3.54,153.67,153.67,0,0,1,19,23.05,2.5,2.5,0,0,1-2.07,3.9z M408,465.77a2.5,2.5,0,0,1-1.77-4.27,153.58,153.58,0,0,1,23.07-19,2.5,2.5,0,0,1,2.79,4.15A148.56,148.56,0,0,0,409.8,465a2.49,2.49,0,0,1-1.8,0.77z m189.31-19a2.49,2.49,0,0,1-1.38-0.42,147.46,147.46,0,0,0-25.51-13.6,2.5,2.5,0,0,1,1.91-4.62,152.53,152.53,0,0,1,26.38,14.06,2.5,2.5,0,0,1-1.39,4.58z m-140.69-13.61a2.5,2.5,0,0,1-1-4.81,151.77,151.77,0,0,1,28.59-8.71,2.5,2.5,0,1,1,1,4.9,146.85,146.85,0,0,0-27.63,8.46,2.5,2.5,0,0,1-0.96,0.16z m86.64-8.67a2.48,2.48,0,0,1-0.48,0,148.75,148.75,0,0,0-28.52-2.75H514a2.5,2.5,0,1,1,0-5h0.23a153.78,153.78,0,0,1,29.51,2.85,2.5,2.5,0,0,1-0.48,5z opacity: 0.5 - component: path config: d: M284.25 147.5h50v50h-50z - component: path config: d: M334.25,205h-50a7.5,7.5,0,0,1-7.5-7.5v-50a7.5,7.5,0,0,1,7.5-7.5h50a7.5,7.5,0,0,1,7.5,7.5v50a7.5,7.5,0,0,1-7.5,7.5z m-42.5-15h35v-35h-35z opacity: 0.5 - component: path config: d: M367.24,147.5h50v50h-50z - component: path config: d: M417.24,205h-50a7.5,7.5,0,0,1-7.5-7.5v-50a7.5,7.5,0,0,1,7.5-7.5h50a7.5,7.5,0,0,1,7.5,7.5v50a7.5,7.5,0,0,1-7.5,7.5z m-42.5-15h35v-35h-35z opacity: 0.5 - component: path config: d: M450.22,147.5h50v50h-50z - component: path config: d: M500.22,205h-50a7.5,7.5,0,0,1-7.5-7.5v-50a7.5,7.5,0,0,1 7.5-7.5h50a7.5,7.5,0,0,1,7.5,7.5v50a7.5,7.5,0,0,1-7.5,7.5z m-42.5-15h35v-35h-35z opacity: 0.5 - component: path config: d: M708.44,172.5 m-30,0a30,30,0,1,0,60,0,30,30,0,1,0-60,0Z - component: path config: d: M708.44,210a37.5,37.5,0,1,1,37.5-37.5,37.54,37.54,0,0,1-37.5,37.5z m0-60a22.5,22.5,0,1,0,22.5,22.5,22.53,22.53,0,0,0-22.5-22.5z opacity: 0.5 - component: g config: comment: Heatpump id: few_heatpump visible: =(props.power_heatpump ? true:false) slots: default: - component: g config: comment: House to heatpump energy flow visualisation id: few_house_heatpump_flow slots: default: - component: defs slots: default: - component: linearGradient config: comment: Gradient for house to heatpump flow id: gradient_house_heatpump_flow x1: 0 x2: 1 y1: 0 y2: 1 slots: default: - component: stop config: offset: 0 stop-color: "= props.use_dot_gradient ? props.color_house : props.color_heatpump" - component: stop config: offset: =const.dot_gradient_start stop-color: "= props.use_dot_gradient ? props.color_house : props.color_heatpump" - component: stop config: offset: =const.dot_gradient_stop stop-color: =props.color_heatpump - component: stop config: offset: 1 stop-color: =props.color_heatpump - component: path config: comment: Energy flow visualization load. d: M380,180L420,220 id: few_house_heatpump_path style: stroke: darkgray stroke-width: 1px - component: oh-repeater config: comment: Sets up the circles, indicating the energy flow. for: offset fragment: true rangeStart: 0 rangeStep: 1 rangeStop: 2 sourceType: range slots: default: - component: circle config: fill: url(#gradient_house_heatpump_flow) r: =fn.resize_dot(#props.power_heatpump) slots: default: - component: animateMotion config: begin: =`${loop.offset}s` calcMode: linear dur: 3s repeatCount: indefinite slots: default: - component: mpath config: xlink:href: "#few_house_heatpump_path" - component: use config: comment: Heatpump power dial style: stroke: =fn.switch_color(#props.power_heatpump, "heatpump") x: 400px xlink:href: "#few_rings" y: 200px - component: path config: comment: Dial, using an exponential scale. d: =`M50,9A41,41,0,${fn.arc_flag(fn.scale_to_deg(#props.power_heatpump, props.power_heatpump_max))},1, ${fn.to_cartesian(fn.scale_to_deg(#props.power_heatpump, props.power_heatpump_max))}` fill: none style: stroke: =fn.switch_color(#props.power_heatpump, "heatpump") stroke-width: 14px translate: 400px 200px - component: text config: style: dominant-baseline: central fill: dimgray font-family: sans-serif font-size: 10px font-weight: bold letter-spacing: 1px text-anchor: middle translate: 400px 200px slots: default: - component: textPath config: content: =@props.state_heatpump startOffset: 50% xlink:href: "#few_text_path" - component: svg config: comment: heatpump icon area height: 44px width: 44px x: 428px y: 228px slots: default: - component: oh-link config: action: group actionGroupPopupItem: =props.popup_heatpump slots: default: - component: svg config: comment: heatpump icon fill: =fn.switch_color(#props.power_heatpump, "heatpump") height: 100% viewBox: 0 0 490 490 width: 100% slots: default: - component: rect config: comment: invisible rectangle to provide a clickable area for oh-link height: 100% opacity: 0 width: 100% - component: path config: d: M244.99,211.903c-7.128,0-12.907,5.774-12.907,12.902c0,7.134,5.779,12.915,12.907,12.915 c7.127,0,12.912-5.781,12.912-12.915C257.901,217.677,252.116,211.903,244.99,211.903z - component: path config: d: M244.99,78.408c-80.727,0-146.404,65.679-146.404,146.397c0,80.733,65.677,146.405,146.404,146.405 c80.728,0,146.402-65.671,146.402-146.405C391.392,144.086,325.718,78.408,244.99,78.408z M300.173,315.748 c-8.996-8.483,4.043-23.155-5.973-40.782c-7.188-12.658-21.424-18.632-27.838-20.779c-6,4.374-13.381,6.959-21.373,6.959 c-7.381,0-14.243-2.207-19.976-5.984c-1.653,20.043-9.808,46.091-26.765,55.882c-54.185,31.282-78.859-78.148-59.61-83.909 c11.851-3.553,18.033,15.074,38.312,15.224c14.548,0.095,26.838-9.237,31.9-13.724c-0.13-1.255-0.196-2.536-0.196-3.829 c0-14.2,8.157-26.494,20.038-32.468c-16.538-11.46-35.012-31.54-35.012-51.118c0-62.566,107.103-29.225,102.474-9.671 c-2.852,12.036-22.078,8.077-32.34,25.572c-7.363,12.549-5.424,27.857-4.068,34.49c12.713,5.66,21.578,18.386,21.578,33.196 c0,0.723-0.023,1.424-0.068,2.128c18.19-8.592,44.824-14.552,61.775-4.763C397.22,253.453,314.792,329.536,300.173,315.748z slots: default: - component: animateTransform config: attributeName: transform begin: 0s comment: "=Math.max(0.5, (5 - (5 * #props.power_heatpump/props.power_heatpump_ma\ x)))" dur: =fn.fan_speed(#props.power_heatpump, props.power_heatpump_max) from: 0 245 226 repeatCount: indefinite to: 360 245 226 type: rotate visible: =(#props.power_heatpump > props.power_min) - component: path config: d: M418.913,482.596c0,4.084-3.316,7.404-7.408,7.404h-35.199c-4.092,0-7.41-3.319-7.41-7.404v-14.824 c0-4.091,3.318-7.411,7.41-7.411h35.199c4.092,0,7.408,3.32,7.408,7.411V482.596z - component: path config: d: M120.866,482.596c0,4.084-3.321,7.404-7.411,7.404H78.256c-4.092,0-7.411-3.319-7.411-7.404v-14.824 c0-4.091,3.319-7.411,7.411-7.411h35.199c4.09,0,7.411,3.32,7.411,7.411V482.596z - component: path config: d: M435.134,0H54.87C39.663,0,27.292,12.375,27.292,27.573v394.471c0,15.205,12.371,27.574,27.578,27.574h380.264 c15.201,0,27.574-12.369,27.574-27.574V27.573C462.708,12.375,450.335,0,435.134,0z M418.913,58.016 c0,10.944-7.297,20.169-17.289,23.105V34.915C411.616,37.852,418.913,47.09,418.913,58.016z M388.042,34.915v46.206 c-9.988-2.936-17.289-12.162-17.289-23.105C370.753,47.09,378.054,37.852,388.042,34.915z M419.112,233.639 c0,4.857-3.939,8.798-8.801,8.798c-0.465,0-0.92-0.045-1.365-0.119c-4.01,37.268-20.457,71.796-47.338,98.68 c-26.893,26.896-61.441,43.344-98.733,47.333c0.121,0.586,0.182,1.181,0.182,1.79c0,4.857-3.941,8.799-8.797,8.799h-18.522 c-4.857,0-8.797-3.941-8.797-8.799c0-0.608,0.062-1.204,0.179-1.776c-37.295-3.997-71.85-20.451-98.751-47.347 c-26.883-26.878-43.329-61.412-47.333-98.674c-0.443,0.068-0.889,0.113-1.35,0.113c-4.861,0-8.799-3.941-8.799-8.798v-17.718 c0-4.864,3.938-8.805,8.799-8.805c0.461,0,0.907,0.052,1.35,0.12c4.005-37.27,20.451-72.599,47.333-99.475 c26.862-26.866,61.365-43.313,98.603-47.336c-0.031-0.3-0.05-0.607-0.05-0.929c0-4.856,3.939-8.797,8.799-8.797h18.516 c4.859,0,8.805,3.94,8.805,8.797c0,0.316-0.022,0.629-0.053,0.929c37.246,4.023,71.754,20.465,98.619,47.336 c26.881,26.876,43.328,62.251,47.338,99.521c0.445-0.068,0.9-0.12,1.365-0.12c4.861,0,8.801,3.941,8.801,8.805V233.639z - component: g config: comment: House id: few_few_house slots: default: - component: use config: comment: Load dial style: stroke: =fn.switch_color(#props.power_house, "house") x: 300px xlink:href: "#few_rings" y: 100px - component: path config: comment: Dial, using a exponential scale. d: =`M50 9 A41 41 0 ${fn.arc_flag(fn.scale_to_deg(#props.power_house, props.power_grid_max))} 1 ${fn.to_cartesian(fn.scale_to_deg(#props.power_house, props.power_grid_max))}` fill: none style: stroke: =fn.switch_color(#props.power_house, "house") stroke-width: 14px translate: 300px 100px - component: text config: style: dominant-baseline: central fill: dimgray font-family: sans-serif font-size: 11px font-weight: bold letter-spacing: 1px text-anchor: middle translate: 300px 100px slots: default: - component: textPath config: content: =fn.switch_magnitude(#props.power_house) startOffset: 50% xlink:href: "#few_text_path" - component: svg config: comment: house icon area height: 44px width: 44px x: 328px y: 128px slots: default: - component: oh-link config: action: group actionGroupPopupItem: =props.popup_house slots: default: - component: svg config: comment: house icon (power plug) fill: =fn.switch_color(#props.power_house, "house") height: 100% viewBox: 0 0 24 24 width: 100% slots: default: - component: rect config: comment: invisible rectangle to provide a clickable area for oh-link height: 100% opacity: 0 width: 100% - component: path config: d: M15.21,6.73V2.63A.72.72,0,0,0,14.4,2h0a.71.71,0,0,0-.75.66V6.73Z - component: path config: d: M10.39,6.73V2.62A.7.7,0,0,0,9.6,2h0a.73.73,0,0,0-.78.66V6.73Z - component: path config: d: M6.71,7.23C6.37,7.22,6,8,6,8.8V10c0,2.48.57,4.62,1.63,5.28S9,16,10.35,16.77V22h3.3V16.77c1.38-.8,1.66-.85,2.72-1.51S18,12.46,18,10V8.8c0-.78-.37-1.58-.71-1.57Z - component: oh-repeater config: comment: Draws the segments of the dials, using linear or exponential scales. for: degree fragment: true rangeStart: 0 rangeStep: 13.5 rangeStop: 270 sourceType: range slots: default: - component: use config: comment: Solar dial segments style: transform: =`rotate(${(Math.pow(loop.degree, props.exponent) * 270 / Math.pow(270, props.exponent))}deg)` transform-origin: 50px 50px x: 0px xlink:href: "#few_segment_line" y: 0px - component: use config: comment: Grid dial segments. style: transform: =`rotate(${(Math.pow(loop.degree, props.exponent) * 270 / Math.pow(270, props.exponent))}deg)` transform-origin: 250px 50px x: 200px xlink:href: "#few_segment_line" y: 0px - component: use config: comment: EV dial segments style: transform: =`rotate(${loop.degree}deg)` transform-origin: 450px 50px visible: =((props.power_ev && props.soc_ev ) ? true:false) x: 400px xlink:href: "#few_segment_line" y: 0px - component: use config: comment: Inverter dial segments style: transform: =`rotate(${(Math.pow(loop.degree, props.exponent) * 270 / Math.pow(270, props.exponent))}deg)` transform-origin: 150px 150px x: 100px xlink:href: "#few_segment_line" y: 100px - component: use config: comment: House dial segments style: transform: =`rotate(${(Math.pow(loop.degree, props.exponent) * 270 / Math.pow(270, props.exponent))}deg)` transform-origin: 350px 150px x: 300px xlink:href: "#few_segment_line" y: 100px - component: use config: comment: Battery dial segments style: transform: =`rotate(${(Math.pow(loop.degree, props.exponent) * 270 / Math.pow(270, props.exponent))}deg)` transform-origin: 50px 250px x: 0px xlink:href: "#few_segment_line" y: 200px - component: use config: comment: laundry dial segments style: transform: =`rotate(${(Math.pow(loop.degree, props.exponent) * 270 / Math.pow(270, props.exponent))}deg)` transform-origin: 250px 250px visible: =(props.power_laundry ? true:false) x: 200px xlink:href: "#few_segment_line" y: 200px - component: use config: comment: heatpump dial segments style: transform: =`rotate(${(Math.pow(loop.degree, props.exponent) * 270 / Math.pow(270, props.exponent))}deg)` transform-origin: 450px 250px visible: =(props.power_heatpump ? true:false) x: 400px xlink:href: "#few_segment_line" y: 200px