I’m on OpenHAB 3.4.3 installed on Debian 11. I just went to the market place in installed this addon from the UI page. This is how is shows up. There are others who have posted same issue here (few posts before my post).
I’ve just upgraded to OH 3.4.4-2, and this problem still occurs.
Ok so I found your widget code in that discussion you posted about (somewhere at the bottom of the conversation):
I copied and pasted that and created a widget locally, and it worked. So I believe the problem is the marketplace, or how/what is being downloaded. I don’t know if you can at least check that the widget in the marketplace is not corrupt or something?
I have installed other marketplace widgets, all successfully. So this hopefully points you in the right direction.
Thank you for troubleshooting…
I will make a note in the first post suggesting this workaround until the issue with the marketplace is fixed.
This looks stellar Rob!
Any chance you’ll share the yaml for it?
I love this.
Hi @maxmaximax thanks for sharing your work!
[UPDATE] [SOLVED]: from the in-depth post on this subject:
So far, this is really close to being 100% in OH4.01 except for one minor irritance: the frame shows the full dashboard controls.
I made sure to copy the link only to the panel, but in my widget, it continually gives me the dashboard controls.
Any idea what I might be doing incorrectly?
Thanks again, great stuff!
Glad you like the widget
Worth noting that I have not yet upgraded to OH4 - and will not upgrade any time soon due lack of time.
Have you tried this?
Hope this works for you.
Thanks @maxmaximax
I should have updated my post. I was using an external link instead of ‘share embed’, which is what was causing the controls issue.
After using the proper link, it works fine (I do have to log back into grafana via the widget from time to time, as I could not find a way for it to store cookies, but that’s a different issue).
Works great, thanks, and I do, I really like it!
I haven’t used grafana for over a year but does this still work?
Yes, it works. At least on OH 3.4.4.
On 4.0.1 is doesn’t work, same hex code in the widget library, but when adding it, nothing happens
For others it works on OH 4.01.
Maybe try creating the widget manually by copying the YAML from the first post?
Okay so i just spent 2 hours sorting through this and finally found out what my problem was. I’m posting this here to hopefully save someone else the trouble.
When editing grafana.ini you need to remove the “;” from the beginning of each line that you change. Else the change WILL NOT apply. also dont forget to restart the Grafana service.
That’s why I like using vim editor as both the # and ; in the grafana.ini would have been blue coloured text meaning they are comments. If they are not comments then they are white text.
It makes it easier to look for un-commented statements.
I would like to share the following extension:
In addition to different time ranges, different grafana pages can be selected as well:
Code:
uid: Grafana_charts_with_timeranges_MikeTheTux
tags: []
props:
parameters:
- description: Title of the chart
label: Title
name: title
required: false
type: TEXT
- description: Grafana URL with "{period}" and "{panel}" placeholder. Example: "http://nas:3000/d-solo/VCS_VtN4k/openhab?orgId=1&{period}&panelId={panel}"
label: Grafana source URL
name: URL
required: true
type: TEXT
- default: from=now-6h&to=now,6h;from=now-12h&to=now,12h;from=now-1d&to=now,24h;from=now/d&to=now/d,Day;from=now-3d&to=now,Last 3 Days;from=now-7d&to=now,Last 7 Days;from=now-14d&to=now,Last 14 Days
description: List of time ranges (separated with semicolon). Example: "from=now-6h&to=now,-6h;from=now-1d/d&to=now-1d/d,yesterday" for past "6h" and "yesterday". First entry is default.
label: Grafana time range options
name: timerange
required: true
type: TEXT
- default: 27,PV Status;22,PV Forecast
description: List of panels (separated with semicolon). Example: "27,PV Status;22,PV Forecast" for two panels with ID "27" and "22". First entry is default.
label: Grafana Panel IDs
name: panel
required: true
type: TEXT
- description: Height of the Frame (empty = default)
label: Height
name: height
required: false
type: TEXT
parameterGroups: []
timestamp: Oct 29, 2023, 9:59:50 AM
component: f7-card
config:
title: =props.title
outline: true
style:
--f7-card-margin-horizontal: 10px
--f7-card-margin-vertical: 3px
--f7-card-padding-horizontal: 10px
--f7-card-padding-vertical: 100px
margin-top: 10px
margin-bottom: 10px
noShadow: false
border-radius: var(--f7-card-expandable-border-radius)
box-shadow: 5px 5px 10px 1px rgba(0,0,0,0.3)
slots:
default:
- component: oh-webframe-card
config:
borders: false
noBorder: false
noShadow: true
height: =props.height
src: =props.URL.replace('{period}', vars.selectedPeriod || [props.timerange.split(';')[0].split(',')[0]]).replace('{panel}', vars.selectedPanel || [props.panel.split(';')[0].split(',')[0]])
class:
- display-block
- component: f7-segmented
config:
round: false
outline: false
class:
- padding-bottom-half
style:
margin-left: 10px
margin-right: 10px
--f7-button-font-size: 14px
--f7-button-text-color: "=themeOptions.dark === 'light' ? 'black' : 'white'"
--f7-button-text-transform: none
--f7-button-border-radius: 4px
--f7-button-outline-border-width: 1px
--f7-button-font-weight: 300
--f7-button-padding-vertical: 0px
--f7-button-padding-horizontal: 0px
slots:
default:
- component: oh-repeater
config:
sourceType: range
for: size
fragment: true
slots:
default:
- component: oh-repeater
config:
fragment: true
for: period
in: =[props.timerange.split(";")[loop.size].split(",")[1]]
slots:
default:
- component: oh-button
config:
text: =loop.period
fill: "=(([props.timerange.split(';')[loop.size].split(',')[0]] == vars.selectedPeriod) || (props.timerange.split(';')[0].split(',')[1] === loop.period) && !vars.selectedPeriod) ? true : false"
round: false
outline: true
style:
--f7-button-border-color: var(--f7-card-outline-border-color)
action: variable
actionVariable: selectedPeriod
actionVariableValue: =props.timerange.split(";")[loop.size].split(",")[0]
- component: f7-segmented
config:
round: false
outline: false
class:
- padding-bottom-half
style:
margin-left: 10px
margin-right: 10px
--f7-button-font-size: 14px
--f7-button-text-color: "=themeOptions.dark === 'light' ? 'black' : 'white'"
--f7-button-text-transform: none
--f7-button-border-radius: 4px
--f7-button-outline-border-width: 1px
--f7-button-font-weight: 300
--f7-button-padding-vertical: 0px
--f7-button-padding-horizontal: 0px
slots:
default:
- component: oh-repeater
config:
sourceType: range
for: size
fragment: true
slots:
default:
- component: oh-repeater
config:
fragment: true
for: panel
in: =[props.panel.split(";")[loop.size].split(",")[1]]
slots:
default:
- component: oh-button
config:
text: =loop.panel
fill: "=(([props.panel.split(';')[loop.size].split(',')[0]] == vars.selectedPanel) || (props.panel.split(';')[0].split(',')[1] === loop.panel) && !vars.selectedPanel) ? true : false"
round: false
outline: true
style:
--f7-button-border-color: var(--f7-card-outline-border-color)
action: variable
actionVariable: selectedPanel
actionVariableValue: =props.panel.split(";")[loop.size].split(",")[0]
Have fun!
I have also made my own adjustments to this widget by adding another row of buttons that allows going back several days/hours… but not changing the overall duration of the displayed range.
There are some additional tweaks to the styling for better visual integration in block layouts.
uid: vas_grafana_picker
tags: []
props:
parameters:
- description: Title of the chart
label: Title
name: title
required: false
type: TEXT
- description: URL to show in the frame
label: Source URL
name: URL
required: true
type: TEXT
- default: from=now-{fcount}h&to=now-{tcount}h;6h;6,from=now-{fcount}h&to=now-{tcount}h;12h;12,from=now-{fcount}h&to=now-{tcount}h;24h;24,from=now-{tcount}d/d&to=now-{tcount}d/d;Day;1,from=now-{fcount}d&to=now-{tcount}d;Last 3 Days;3,from=now-{fcount}d&to=now-{tcount}d;Last 7 Days;7,from=now-{fcount}d&to=now-{tcount}d;Last 14 Days;14
description: Comma-separated List of options. Example "from=now-6h&to=now;-6h,from=now-1d/d&to=now-1d/d;yesterday" for past "6h" and "yesterday". First entry is default.
label: Time range options
name: timerange
required: true
type: TEXT
- default: Previous,Now,Next
description: Labels for previous, now and next buttons as comma separated list
label: Second line buttons labels
name: prevNowNext
required: false
type: TEXT
- default: "0"
description: Index of default time range
label: Time range default
name: rangeDefault
required: false
- description: Height of the Frame (empty = default)
label: Height
name: height
required: false
type: TEXT
parameterGroups: []
timestamp: Nov 30, 2023, 12:20:38 AM
component: f7-card
config:
title: =props.title
outline: false
style:
--f7-card-margin-horizontal: 10px
--f7-card-margin-vertical: 10px
--f7-card-padding-horizontal: 10px
--f7-card-padding-vertical: 100px
margin-top: 10px
margin-bottom: 10px
padding-top: 1px
box-shadow: var(--f7-card-box-shadow)
slots:
default:
- component: oh-webframe-card
config:
borders: false
noBorder: false
noShadow: true
height: =props.height
src: = props.URL.replace('{period}', (vars.sP?.period || props.timerange.split(',')[props.rangeDefault].split(';')[0]) .replaceAll('{fcount}', (vars.sP?.count || props.timerange.split(',')[props.rangeDefault].split(';')[2])*((vars.pIdx||0)+1)) .replaceAll('{tcount}', (vars.sP?.count || props.timerange.split(',')[props.rangeDefault].split(';')[2])*(vars.pIdx||0)))
class:
- display-block
- component: f7-segmented
config:
round: false
outline: false
class:
- padding-bottom-half
style:
margin-left: 10px
margin-right: 10px
--f7-button-font-size: 14px
--f7-button-text-color: "=themeOptions.dark === 'light' ? 'black' : 'white'"
--f7-button-text-transform: none
--f7-button-border-radius: 4px
--f7-button-outline-border-width: 1px
--f7-button-font-weight: 300
--f7-button-padding-vertical: 0px
--f7-button-padding-horizontal: 0px
slots:
default:
- component: oh-button
config:
text: =props.prevNowNext.split(',')[0]
round: false
outline: true
style:
--f7-button-border-color: var(--f7-card-outline-border-color)
action: variable
actionVariable: pIdx
actionVariableValue: =(vars.pIdx || 0)+1
- component: oh-button
config:
text: =props.prevNowNext.split(',')[1]
fill: = (vars.pIdx == undefined || vars.pIdx == 0 )
round: false
outline: true
style:
--f7-button-border-color: var(--f7-card-outline-border-color)
action: variable
actionVariable: pIdx
actionVariableValue: 0
- component: oh-button
config:
text: =props.prevNowNext.split(',')[2]
round: false
outline: true
disabled: = (vars.pIdx == undefined || vars.pIdx == 0 )
style:
--f7-button-border-color: var(--f7-card-outline-border-color)
action: variable
actionVariable: pIdx
actionVariableValue: =(vars.pIdx || 0)-1
- component: f7-segmented
config:
round: false
outline: false
class:
- padding-bottom-half
style:
margin-left: 10px
margin-right: 10px
--f7-button-font-size: 14px
--f7-button-text-color: "=themeOptions.dark === 'light' ? 'black' : 'white'"
--f7-button-text-transform: none
--f7-button-border-radius: 4px
--f7-button-outline-border-width: 1px
--f7-button-font-weight: 300
--f7-button-padding-vertical: 0px
--f7-button-padding-horizontal: 0px
slots:
default:
- component: oh-repeater
config:
sourceType: range
for: size
fragment: true
slots:
default:
- component: oh-repeater
config:
fragment: true
for: period
in: =[props.timerange.split(",")[loop.size].split(";")[1]]
slots:
default:
- component: oh-button
config:
text: =loop.period
fill: "=((loop.size == vars.sP?.index) || loop.size == (props.rangeDefault || 0) && !vars.sP) ? true : false"
round: false
outline: true
style:
--f7-button-border-color: var(--f7-card-outline-border-color)
action: variable
actionVariable: sP
actionVariableValue: "= {'period': props.timerange.split(',')[loop.size].split(';')[0], 'count': props.timerange.split(',')[loop.size].split(';')[2], index: loop.size }"
Here’s what it looks like in context:
Hi @tarag
I’m working on the same widget with a similar concept, only I’m trying to use arrows to go forwards/backwards in time.
I’m trying to use your code as a startingpoint, but I’m struggling to understand 2 things:
-
What is the purpose of “rangeDefault” and its use?
-
When generating the URL, how is this line read:
vars.sP?.count || props.timerange.split(',')[props.rangeDefault].split(';')[2])
in particular what do the OR in this mean, is it bit-wise, or in case sP?.count is not specified then do the split thing?
Also how is the code on the right side of the OR statement read? I dont understand
[props.rangeDefault].split(';')[2])
when rangeDefault is set to “0” in the props
Thank you
Sorry I did not explain much. The computation of the url for the web card is a 2 step process.
- Computing the
from
andto
query string parameters using{fcount}
and/or{tcount}
tags in the selected timerange prop by multiplying thecount
parameter (3rd of each timerange), by the current position (0 upon display) - Replacing the
{period}
tag in the URL prop by the computed timerange in the previous step.
The rangeDefault
prop, should rather be called defaultRange. It is the 0-starting index of the default selected range among all timerange
prop values. I did not want it to be 0 as in the topic widget version (bu the default value of rangeDefaut in 0…). This is written in the prop description
vars.sP
is the selected period, an object with period
and count
properties, when initialised. But since one can’t initialise vars in widgets, I have to take this case into account.
So the vars.sP?.count || props.timerange.split(',')[props.rangeDefault].split(';')[2])
means:
if vars.sP?.count
is defined (when at least one of the range buttons has been selected by the user), use it, else use the count value from the timerange
property, by taking the field at the third position (index 2) of the range at the rangeDefault
index.
This line is buggy if count is 0, but there is no point in having count at 0 so I left it this way. Not being able to initialise vars in widgets is a real pain…
And it does work!
…with some nice query btw to get historical values one year before current ones
Awesome - thanks for your explanation, that was really helpful!
I’ve finished my widget with the help of your inputs, if I want to share the functioning of my widget, with a nice animation like yours, how can I do this, as it explains much better than trying to describe in words.