Didn’t do anything special.
It’s shown automatically for me with graph_span: 2d
Thanks for this, worked a treat, been looking for a way to do this for ages, also used it to changed the Now colour based on a state.
now:
show: true
label: >-
${states['climate.immersion_heater_thermostat'].attributes.current_temperature + '°'}
color: >-
${states['binary_sensor.immersion_heater_heating'].state === 'on' ? 'red' : 'cyan'}
trying to figure out the data_generator
, but need some help, please…
if this is my sensor and attributes list:
how would I need to change this config, so it actually renders anything…?
- type: custom:apexcharts-card
graph_span: 48h
update_interval: 1h
header:
show: true
title: Solar Forecast
span:
start: day
now:
show: true
label: Now
yaxis:
- id: power
decimals: 0
apex_config:
plotOptions:
bar:
columnWidth: 100%
stroke:
width: 2
series:
- entity: sensor.solar_forecast_estimate_watts
name: Solar power
yaxis_id: power
data_generator: |
return entity.attributes.watts.map((entry) => {
return [new Date(entry).getTime(), entry];
});
type: column
show:
extremas: true
opacity: 1
float_precision: 3
I’ve copied the above form some other sensor attributes for price, but they contain an actual named KVP like
and use:
series:
- entity: sensor.energyzero_today_energy_average_price
name: Price this hour
yaxis_id: price
data_generator: |
return entity.attributes.today.map((entry) => {
return [new Date(entry.timestamp).getTime(), entry.price];
});
that wont work now obviously,
but I fail to see how I should change to fix it.
please have a look? thanks!
How does this look like, if you paste the sensor in Dev-tools/state ?
Assuming that is white space before the value, you could try this.
data_generator: |
return entity.attributes.watts.map((entry) => {
const myArray = Watts.split(" ");
return [new Date(myArray[0]).getTime(), myArray[1]];
});
thanks for your reply, unfortunately that throws an error:
Error: TypeError: entity.attributes.watts.map is not a function in 'return entity.attributes.watts.map((entry) => {
const myArray = Watts.split(" ");
return [new Da...'
is there a way to test these data generators? given the fact its JS I cant get my head around any online tool with this, we need the frontend info?
to be precise, the output of:
{{state_attr('sensor.solar_forecast_estimate_watts','watts')}}
is:
{'2023-03-24T06:34:00+01:00': 0, '2023-03-24T07:00:00+01:00': 145, '2023-03-24T08:00:00+01:00': 222, '2023-03-24T09:00:00+01:00': 329, '2023-03-24T10:00:00+01:00': 414, '2023-03-24T11:00:00+01:00': 473, '2023-03-24T12:00:00+01:00': 515, '2023-03-24T13:00:00+01:00': 577, '2023-03-24T14:00:00+01:00': 1175, '2023-03-24T15:00:00+01:00': 1395, '2023-03-24T16:00:00+01:00': 1054, '2023-03-24T17:00:00+01:00': 627, '2023-03-24T18:00:00+01:00': 258, '2023-03-24T19:00:00+01:00': 70, '2023-03-24T19:02:00+01:00': 0, '2023-03-25T06:31:00+01:00': 0, '2023-03-25T07:00:00+01:00': 187, '2023-03-25T08:00:00+01:00': 329, '2023-03-25T09:00:00+01:00': 413, '2023-03-25T10:00:00+01:00': 480, '2023-03-25T11:00:00+01:00': 594, '2023-03-25T12:00:00+01:00': 689, '2023-03-25T13:00:00+01:00': 1207, '2023-03-25T14:00:00+01:00': 2140, '2023-03-25T15:00:00+01:00': 2188, '2023-03-25T16:00:00+01:00': 1808, '2023-03-25T17:00:00+01:00': 969, '2023-03-25T18:00:00+01:00': 360, '2023-03-25T19:00:00+01:00': 108, '2023-03-25T19:04:00+01:00': 0}
maybe I need the .items()
here too, like in the jinja templates for template-entity-row I use:
{% if states[config.entity] is not none %}
{% set attr =
state_attr(config.entity,'watts').items()
|sort(attribute='1',reverse=True) %}
{% set peak = (attr|first| default(('Unknown',0))) %}
{{peak[1]}} W op {{as_datetime(peak[0]).strftime('%-d-%m')}} om {{as_datetime(peak[0]).strftime('%-H')}} uur
{% else %} Initializing
{% endif %}
or is that what the .map((entry)
does in the data_generator?
maybe its no a float? figured it is, because of no quotes in the KVP
checking the objects doc on W3, doesnt help me a lot…
I have reached a similar solution a while back (lots of searching)
- entity: sensor.solar_forecast
show:
in_header: false
legend_value: false
name: today
yaxis_id: value
color: '#ffa600'
opacity: 1
stroke_width: 1
float_precision: 1
unit: kWh
offset: '-1h'
data_generator: >
let res = []; for (const [key, value] of
Object.entries(entity.attributes.forecast.result)) {
res.push([new Date(key).getTime(), value/1000]);
} return res
in my graph (this is a combined card obviously)
EDIT:
vingerha already replied, this is the explination why.
The map function only works on ‘lists’, like arrays, you can recognize them by the square brackets [].
“entity.attributes.watts” is a dict, like objects, recognized by the curly brackets.
To convert an dict to a list, you could indeed use the items() function in jinja templates. But the data_gerenator is uses javascript. So then you use the function Object.entries().
Can you test the data_generator like this:
data_generator: |
return Object.entries(entity.attributes.watts).map((entry) => {
...
thanks! I figured that to be the case, but fail to fix the generator…
data_generator: |
return Object.entries(entity.attributes.watts).map((entry) => {
const myArray = Watts.split(" ");
return [new Date(myArray[0]).getTime(), myArray[1]];
});
should I completely do away with the const myArray, and use the .push construction?
because I did test:
data_generator: |
let res = []; for (const [key, value] of
Object.entries(entity.attributes.watts).map((entry) => {
res.push([new Date(key).getTime(), value]);
} return res;
and still it does not render
wait, there more to change:
data_generator: |
let res = []; for (const [key, value] of
Object.entries(entity.attributes.watts)) {
res.push([new Date(key).getTime(), value]);
} return res;
now shows!
yeas!!. Now time for some formatting maybe even color_thresholds…
cool, thx @studioIngrid and @vingerha , much appreciated!
so, full config now:
Why is there a 0 in the legend…?
- type: custom:apexcharts-card
graph_span: 48h
update_interval: 1h
header:
show: true
title: Solar Forecast
experimental:
color_threshold: true
span:
start: day
now:
show: true
label: Now
yaxis:
- id: estimate
- id: actueel
show: false
apex_config:
plotOptions:
bar:
columnWidth: 100%
series:
- entity: sensor.solar_forecast_estimate_watts
name: Solar power
yaxis_id: estimate
data_generator: |
let res = []; for (const [key, value] of
Object.entries(entity.attributes.watts)) {
res.push([new Date(key).getTime(), value]);
} return res;
color_threshold:
- value: 0
color: cornsilk
- value: 500
color: papayawhip
- value: 1000
color: yellow
- value: 1500
color: gold
- value: 2000
color: orange
- value: 2500
color: darkorange
- value: 3000
color: tomato
- value: 3500
color: sandybrown
- value: 4000
color: peru
- value: 4500
color: orangered
- value: 5000
color: maroon
- value: 5500
color: purple
- value: 6000
color: darkred
type: column
show:
extremas: true
opacity: 1
float_precision: 0
stroke_width: 5
- entity: sensor.zp_actuele_opbrengst
yaxis_id: actueel
# transform: return x /1000;
# unit: kW
type: line
name: Actueel
stroke_width: 2
extend_to: false
color: grey
group_by:
func: min
duration: 60m
show:
legend_value: true
float_precision: 0
aside form the colors threshold colors (the lower colors are too light), id love to have those bars we wider, and leave less whitespace. Is there some default config setting for that, or do I simply need to set the stroke_width to a higher number.
figured the columnWidth: 100% should be doing that, but apparently not.
I can set the
stroke:
width:
global option, because then it also makes the secondary line fat and I want that to be a thinner line. like in
more like this, whihc I copied at first, but still showed very thin bars…
Try with:
group_by:
func: last ( or raw )
maybe also “duration: 1month” beneath “func”
Try this “Global”(by this you can control columWidth), and then you can stil add on a individual line-serie “stroke_width: 5”
all_series_config:
stroke_width: 1
group_by:
func: min
duration: 1h
PS: No need for “stroke_width” on/inside column-serie
thanks, that works beautifully. And not needing an individual stroke_width
now:
type: custom:apexcharts-card
graph_span: 48h
update_interval: 1h
header:
show: true
title: Solar Forecast
experimental:
color_threshold: true
all_series_config:
stroke_width: 1
group_by:
func: min
duration: 1h
span:
start: day
now:
show: true
label: Now
yaxis:
- id: estimate
decimals: 0
- id: actueel
decimals: 0
show: false
apex_config:
plotOptions:
bar:
columnWidth: 100%
series:
- entity: sensor.solar_forecast_estimate_watts
name: Solar power
yaxis_id: estimate
data_generator: |
let res = []; for (const [key,value] of
Object.entries(entity.attributes.watts)) {
res.push([new Date(key).getTime(),value]);
} return res;
color_threshold:
- value: 0
color: moccasin
- value: 500
color: khaki
- value: 1000
color: yellow
- value: 1500
color: gold
- value: 2000
color: orange
- value: 2500
color: darkorange
- value: 3000
color: tomato
- value: 3500
color: sandybrown
- value: 4000
color: peru
- value: 4500
color: orangered
- value: 5000
color: maroon
- value: 5500
color: purple
- value: 6000
color: darkred
type: column
show:
extremas: true
# legend_value: true
# opacity: 1
# float_precision: 0
# stroke_width: 8
- entity: sensor.zp_actuele_opbrengst
yaxis_id: actueel
# transform: return x /1000;
# unit: kW
type: line
name: Actueel
# stroke_width: 1
extend_to: false
color: grey
shows as:
still dont get the legend to be 0 on Solar power though. does this not find the value in the data object maybe?
btw, can we set the left Y-axis scale to use the same numbers as I set in the color_thresholds, this is a bit random somehow…
If you are interested:
Did not work, because the variable “Watts” was never defined.
This is a little more complicated. The map function is essentially shorthand for the “for” function. So here you try to do a double “for”.
Good luck with your next coding adventure.
yeah, the second of your post above I get
and I had already seen and changed that into:
data_generator: |
let res = []; for (const [key,value] of
Object.entries(entity.attributes.watts)) {
res.push([new Date(key).getTime(),value]);
} return res;
however, on your first remark on the variable not being defined in
data_generator: |
return Object.entries(entity.attributes.watts).map((entry) => {
const myArray = Watts.split(" ");
return [new Date(myArray[0]).getTime(), myArray[1]];
});
how could I fix that (so define Watts)? simply by adding
let Watts = [];
?
cant test right now, because forecast solar is out for the moment
Hi Marius,
The line const myArray = Watts.split(" ");
. means, take the string (it only works on strings) from Watts and split in into a list on every space.
You are correct let Watts
would define the variable, and let Watts = []
would fill that variable with an empty list. But there isn’t any actual data there, only an empty list. So you would need a function to fill the variable Watts with a string of data.
The function list.map(x)=>{}, it is the same as a for loop: for x in list. Within the {} you can use the value x.
We know the value x will consist of two fields: a time and a value. Thats what the const [key, value]
means. It says to not return the values as one variable x, but as two separate variables a key and a value.
Is there anything you would still like to accomplice?
I’ve got a ApexChart working fine for most devices:
type: custom:apexcharts-card
graph_span: 24h
span:
start: day
now:
show: true
label: Nu
header:
show: true
title: Stroomprijs vandaag (€/kWh)
series:
- entity: sensor.nextenergy_average_electricity_price_today
stroke_width: 2
float_precision: 3
type: column
opacity: 1
color: ''
data_generator: |
return entity.attributes.prices.map((record, index) => {
return [record.time, record.price];
});
yaxis:
- id: Prijs
decimals: 2
min: 0
For some reason this one stays completely empty on my wallmount iPad Air 2 (ios maxed at 15.7.3). Other ApexCharts do show. Is this known or is there something wrong in my code?
For reference, the chart does show on iphone devices with ios 16 and Windows / MacOS devices.
well first of all, thanks.
I guess I would like to use the simplest, of, rephrase, most economical of generators. If any difference at all.
since I can only get the
data_generator: |
let res = []; for (const [key,value] of
Object.entries(entity.attributes.watts)) {
res.push([new Date(key).getTime(),value]);
} return res;
to do what is required, I seem to have no choice, but, you might yet see a better way of converting those KVP and feeding them to the apex-chart.
If that were the case, Id be very interested.
one other detail:
my data refreshes each hour, but the secondary (now) entity is a life updating entity. Updating the apex-chart per hour as I do, might require some further customizing of the handling of that entity in the chart?
always check the repo for issues: Graph not displayed on iPad/ iPhone companion app or Safari IOS · Issue #434 · RomRider/apexcharts-card · GitHub
seems identical?
Sure looks like the same issue. I’ll add my experiences to this issue. thanks.
The issue has been marked closed because of inactivity. So I won’t get my hopes up.