History Stats and Statistics Graph Issue

I’ve been using a history_stats sensor to track sleep hours for several years. In the past two weeks I have slept in our guest bedroom on two occasions due to lingering cold and not wanting to keep my spouse awake. On the first occasion I saw that my graph showed I slept in my primary bed, when in fact I did not. I thought it was a fluke until today (or more specifically, last night). I again slept in the guest room. The statistics graph again showed I slept in my own bed, displaying about 8 hours of sleep. When I checked sleep_hours sensor it showed 0 (zero) hours slept in my bed. Since it’s a smart bed (SleepNumber) I checked that sensor as well. No sleep data for last night. All the raw data supports that I did not sleep in my bed, yet the statistics graph says I did.
See images below:


This is the sleep number bed sensor. You can see that I did not record any data last night.

Next is the history stats sensor. Again no data for Tuesday (flat line)

And finally the raw sensor, showing 0 (zero) hours.

Now for the problem:


My data is blue, wife’s is yellow/orange. Since I did not sleep in my bed WHY do I get data showing I did?

Here is my configuration for the history sensor

- platform: history_stats
  name: Art Sleep Hours
  unique_id: art_sleep_hours
  entity_id: binary_sensor.art_in_bed
  state: "on"
  type: time
  start: "{{ as_timestamp( now().replace(hour=18).replace(minute=0).replace(second=0) ) - 86400 }}"
  end: "{{ as_timestamp( now().replace(hour=18).replace(minute=0).replace(second=0) ) }}"
#

It sets the time from 6pm of start day to 6pm of end day.
Lastly, here is the config of the history stats graph:

type: statistics-graph
chart_type: bar
period: day
entities:
  - sensor.art_sleep_hours
  - sensor.steff_sleep_hours
stat_types:
  - max
hide_legend: true
fit_y_data: false
days_to_show: 7

I’m stumped as to why this is happening. Can anyone explain?

Thanks

Your card is displaying the max from midnight to midnight and picking up the previous day’s value (history stats only updates once a minute at some random point during the minute so could cross the midnight boundary). This wouldn’t normally be a problem except your history stats sensor is not resetting at the correct time.

This is measuring from midnight to midnight instead of 6pm to 6pm:

Notice when it starts counting and when it resets?

That is not 6pm to 6pm.

See this example:

https://www.home-assistant.io/integrations/history_stats/#examples

So instead of:

  start: "{{ as_timestamp( now().replace(hour=18).replace(minute=0).replace(second=0) ) - 86400 }}"
  end: "{{ as_timestamp( now().replace(hour=18).replace(minute=0).replace(second=0) ) }}"

you want:

  end: "{{ (now() + timedelta(hours=6)).replace(hour=18, minute=0, second=0, microsecond=0) }}"
  duration:
      hours: 24

If your desired goal is to have a daily statistics graph, with each day’s value showing the number of hours slept the night before, I think you want something different.

Really you don’t want anything that has a value crossing the midnight boudary, as that is going to influence the incorrect day in either direction. So what I think you could want is a history stats that is always 0, except for maybe at 12:00 noon, calculate the number of hours slept the night before, and then go back to zero. So this will probably look pretty unusual but maybe:

start: {% if now().hour == 12 %}
         {{ today_at("12:00") - timedelta(days=1) }}
       {% else %}
         0
       {% endif %}

end: {% if now().hour == 12 %}
         {{ today_at("12:00") }}
     {% else %}
         0
     {% endif %}

(this assumes you’re always out of bed by noon :joy:)

So I think this will generate a sensor which is always 0, except from 12pm to 1pm, when it will have a stable value of the number of hours slept the night before.

Then the daily “max” of this value is what you wanted.

1 Like

OK, interesting. So this only becomes evident if I miss a night in bed? It’s been running like this for several years and I never really paid too much attention to the exact duration per night. I can see how your explanation makes sense, but really surprised it took a me so long to spot this. We’ve had weekends away, vacations and my wife in the guest room way more frequently than I, and Ive never noticed this behavior. Of course, that’s all on me but I will give your suggestion a try tomorrow. I suspect I may end up with 1 lost day in the history, but that’s really not an issue.
Thanks for the quick response AND a solution worth trying. I’ll add the solution tag once confirmed.

Not only that, but notice how in your graph you often tend to have 2 consecutive days with the same bar height. This is because the max for each day is incorrectly showing you the max of the amount you slept yesterday or today.

So if you sleep 8H on monday, 7H on tuesday, and 6H on wednesday it will show 8H for monday, 8H for tuesday, and 7H for wednesday.

This should work as it resets well before midnight (6pm):

Ok, but lets say it’s Sunday evening and you don’t go to bed at all. The sensor will stay 0 all night sunday and through most of monday. At 6pm on monday it “resets” for the next day, and it is still 0.

Then you go to bed at 9pm on monday and it starts counting up, 1, 2, 3 hours. By midnight the sensor has a value of 3.

Therefore with your sensor “3” will be the “max” value for monday. If you want to know how much you slept the previous night on monday, you would expect the value to be zero. So for that reason I thought it was the wrong approach.

1 Like

Ah I see. Thanks for the explanation.