Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

window_state does not change, configuration issue? #181

Closed
maia opened this issue Nov 9, 2023 · 39 comments
Closed

window_state does not change, configuration issue? #181

maia opened this issue Nov 9, 2023 · 39 comments
Labels
developed When development is done and tested enhancement New feature or request P1 Priority 1

Comments

@maia
Copy link

maia commented Nov 9, 2023

VTherm is not changing the window_state to "open" when the slope drops below the configured value:

I've configured all VTherm entities using the option "window detection" with the suggested value for temperature slope of 0.05 (yaml see below):
Bildschirmfoto 2023-11-09 um 08 16 01

Unfortunately while there are changes in the slope, the window_state does not change to open (on):
Bildschirmfoto 2023-11-09 um 08 28 57

By the way, in the configuration you ask for a "decrease" with the info: "Recommended value: between 0.05 and 0.1. Leave empty if automatic window open detection is not use". So I assume one needs to put a positive value in there, because a negative value of a decrease would be an increase in temperature? Otherwise, if the configuration requires a negative value, you shouldn't ask for a decrease but for a change and also change the recommended value to negative value.

PS: Why does the slope jump around so much, if the room temperature is usually pretty stable? I don't understand the slope when comparing it with the room temperature in the screenshot.

Here is the configuration:

hvac_modes:
  - "off"
  - heat
min_temp: 16
max_temp: 26
preset_modes:
  - none
  - eco
  - comfort
  - boost
current_temperature: 19.4
temperature: 21
hvac_action: heating
preset_mode: comfort
hvac_mode: heat
type: null
eco_temp: 20
boost_temp: 22
comfort_temp: 21
eco_away_temp: 19
boost_away_temp: 21
comfort_away_temp: 20
power_temp: null
ext_current_temperature: 2.40000009536743
ac_mode: false
current_power: null
current_power_max: null
saved_preset_mode: comfort
saved_target_temp: 21
saved_hvac_mode: null
window_state: null
motion_state: null
overpowering_state: null
presence_state: "on"
window_auto_state: false
window_bypass_state: false
security_delay_min: 60
security_min_on_percent: 0.5
security_default_on_percent: 0.1
last_temperature_datetime: "2023-11-09T08:16:59.625031+01:00"
last_ext_temperature_datetime: "2023-11-09T08:16:31.993989+01:00"
security_state: false
minimal_activation_delay_sec: 10
device_power: 1
mean_cycle_power: null
total_energy: 380.69
last_update_datetime: "2023-11-09T08:16:59.637219+01:00"
timezone: 
window_sensor_entity_id: null
window_delay_sec: 30
window_auto_open_threshold: 0.05
window_auto_close_threshold: 0
window_auto_max_duration: 30
motion_sensor_entity_id: null
presence_sensor_entity_id: input_boolean.presence_someone
power_sensor_entity_id: null
max_power_sensor_entity_id: null
is_over_climate: true
start_hvac_action_date: "2023-11-08T16:00:40.167541+01:00"
underlying_climate_0: climate.schlafzimmer_eve_trv
underlying_climate_1: null
underlying_climate_2: null
underlying_climate_3: null
regulated_target_temperature: 22
regulation_accumulated_error: 0
friendly_name: Schlafzimmer Heizung
supported_features: 17
@maia
Copy link
Author

maia commented Nov 9, 2023

Same issue here in a different room: no open window state and a slope jumping around wildly:

@maia
Copy link
Author

maia commented Nov 9, 2023

And in a different room the slope is at zero for many hours, even though the temperature changes:

@jmcollin78
Copy link
Owner

Hello @maia ,

It works on my side with exactly the same configuration. So you need positive value and the slope should be under 0.05 during 30 sec for the detection to be effective.

Here is a test I just do and it works:

Capture d’écran 2023-11-10 à 23 43 16

The configuration is:
Capture d’écran 2023-11-10 à 23 44 22

The only difference is that I'm in over_switch VTherm type but it should not have an impact.

@jmcollin78
Copy link
Owner

Ok, I just made a test (in dev environment) with a over_climate VTherm and you are right, it seems not working at all.

Thank for the head up !

@jmcollin78 jmcollin78 added bug Something isn't working P1 Priority 1 labels Nov 10, 2023
@maia
Copy link
Author

maia commented Nov 11, 2023

Thanks. I hope the temperature slope issue is a part of the problem. In case it's not related at all, let me know so we can create a separate issue. Good luck on bughunting!

@jmcollin78 jmcollin78 added the developed When development is done and tested label Nov 11, 2023
@jmcollin78
Copy link
Owner

It was simply not implemented for over_climate VTherm or a regression due to an ancien issue.

@maia
Copy link
Author

maia commented Nov 11, 2023

Thanks. Should this also fix the slope calculations, as reported in the screenshots above?

@jmcollin78
Copy link
Owner

Non there is no need to fix something on slope calculation. There is a temporal filter to avoid mini-slope deviation due to precision +/- 0.1 gap.

It should works fine event if the curve seems a little agitated.

@maia
Copy link
Author

maia commented Nov 11, 2023

It should works fine event if the curve seems a little agitated.

It does not work for me. I might need to create a new issue, as this one is closed.

@jmcollin78
Copy link
Owner

No, we will continue here.
You have installed 4.0.2 Vtherm and VTherm UI Card 0.3.1 ?

@maia
Copy link
Author

maia commented Nov 11, 2023

Please see the image here:
Bildschirmfoto 2023-11-11 um 18 09 19
I'm still running 3.8.0, as I've been testing the 4 timeframe EMA algo, so I couldn't restart HA without resetting everything. But I don't think anything changed regarding the slope calculation? And I'm not using VTherm UI Card.

@jmcollin78
Copy link
Owner

jmcollin78 commented Nov 11, 2023

Mine:

Capture d’écran 2023-11-11 à 18 38 56

I know this will not help you, but this works fine with 4.0.2 in my context.

To have more information, you will to turn the debug level in logs and check those logs:

_LOGGER.debug(
            "delta_t=%.3f delta_temp=%.3f new_slope=%.3f last_slope=%s slope=%.3f",
            delta_t,
            delta_temp,
            new_slope,
            lspe,
            self._last_slope,
        )

previous logs gives all the details.

Be careful in debug log level, the log will growth rapidly. So just turn it on, take the log and set the level to info back.

The algo is based is forgetting abnormal values (too quick or too high) to avoid some thermometer high jump (there is one in my screenshot which is ignored).

EDIT: i agree with you, your graph shows it don't works

@maia
Copy link
Author

maia commented Nov 11, 2023

Unfortunately the log lines do not contain the name of the entity, so they might mix in the log. But anyways, here's a chart plus the debug log file using grep 'open_window':

Bildschirmfoto 2023-11-11 um 22 35 01
2023-11-11 22:11:16.910 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] We are already initialized slope=0.1503892289760363 last_temp=22.30
2023-11-11 22:11:16.910 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] delta_t=27.977 delta_temp=-0.100 new_slope=-0.004 last_slope=0.1503892289760363 slope=0.073
2023-11-11 22:11:16.913 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] We are already initialized slope=0.1503892289760363 last_temp=22.30
2023-11-11 22:11:16.914 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] delta_t=27.977 delta_temp=-0.100 new_slope=-0.004 last_slope=0.1503892289760363 slope=0.073
2023-11-11 22:11:33.085 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] We are already initialized slope=0.07340745304406945 last_temp=22.20
2023-11-11 22:11:33.085 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] delta_t=0.269 delta_temp=0.100 new_slope=0.371 last_slope=0.07340745304406945 slope=0.222
2023-11-11 22:11:33.089 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] We are already initialized slope=0.07340745304406945 last_temp=22.20
2023-11-11 22:11:33.089 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] delta_t=0.269 delta_temp=0.100 new_slope=0.371 last_slope=0.07340745304406945 slope=0.222
2023-11-11 22:12:46.258 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] We are already initialized slope=0.1789714345330802 last_temp=21.00
2023-11-11 22:12:46.258 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] delta_t=11.727 delta_temp=-0.100 new_slope=-0.009 last_slope=0.1789714345330802 slope=0.085
2023-11-11 22:13:27.325 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] We are already initialized slope=0.22226000134869384 last_temp=22.30
2023-11-11 22:13:27.325 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] delta_t=1.904 delta_temp=-0.100 new_slope=-0.053 last_slope=0.22226000134869384 slope=0.085
2023-11-11 22:13:27.333 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] We are already initialized slope=0.22226000134869384 last_temp=22.30
2023-11-11 22:13:27.334 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] delta_t=1.904 delta_temp=-0.100 new_slope=-0.053 last_slope=0.22226000134869384 slope=0.085
2023-11-11 22:14:07.744 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] We are already initialized slope=0.08522197032888035 last_temp=20.90
2023-11-11 22:14:07.744 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] delta_t=1.359 delta_temp=-0.100 new_slope=-0.074 last_slope=0.08522197032888035 slope=0.006
2023-11-11 22:14:30.112 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] We are already initialized slope=0.0058060030850321034 last_temp=20.80
2023-11-11 22:14:30.113 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] delta_t=0.373 delta_temp=-0.100 new_slope=-0.268 last_slope=0.0058060030850321034 slope=-0.131
2023-11-11 22:15:19.077 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] We are already initialized slope=-0.1312410387507784 last_temp=20.70
2023-11-11 22:15:19.077 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] delta_t=0.816 delta_temp=-0.100 new_slope=-0.123 last_slope=-0.1312410387507784 slope=-0.127
2023-11-11 22:16:14.082 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] We are already initialized slope=-0.12688470211027125 last_temp=20.60
2023-11-11 22:16:14.082 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] delta_t=0.917 delta_temp=-0.100 new_slope=-0.109 last_slope=-0.12688470211027125 slope=-0.118
2023-11-11 22:16:41.102 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] We are already initialized slope=0.08487637173366919 last_temp=22.20
2023-11-11 22:16:41.102 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] delta_t=3.229 delta_temp=0.100 new_slope=0.031 last_slope=0.08487637173366919 slope=0.058
2023-11-11 22:16:41.105 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] We are already initialized slope=0.08487637173366919 last_temp=22.20
2023-11-11 22:16:41.105 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] delta_t=3.229 delta_temp=0.100 new_slope=0.031 last_slope=0.08487637173366919 slope=0.058
2023-11-11 22:17:19.546 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] We are already initialized slope=0.09670345866316588 last_temp=20.60
2023-11-11 22:17:19.547 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] delta_t=8.856 delta_temp=0.100 new_slope=0.011 last_slope=0.09670345866316588 slope=0.054
2023-11-11 22:17:30.028 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] We are already initialized slope=0.057922510695122296 last_temp=22.30
2023-11-11 22:17:30.028 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] delta_t=0.816 delta_temp=-0.100 new_slope=-0.123 last_slope=0.057922510695122296 slope=-0.032
2023-11-11 22:17:30.033 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] We are already initialized slope=0.057922510695122296 last_temp=22.30
2023-11-11 22:17:30.033 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] delta_t=0.816 delta_temp=-0.100 new_slope=-0.123 last_slope=0.057922510695122296 slope=-0.032
2023-11-11 22:17:33.618 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] We are already initialized slope=0.053997488636818386 last_temp=20.70
2023-11-11 22:17:33.619 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] delta_t=0.235 delta_temp=-0.100 new_slope=-0.426 last_slope=0.053997488636818386 slope=-0.186
2023-11-11 22:18:06.279 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] We are already initialized slope=-0.11798875569978456 last_temp=20.50
2023-11-11 22:18:06.279 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] delta_t=1.870 delta_temp=-0.100 new_slope=-0.053 last_slope=-0.11798875569978456 slope=-0.086
2023-11-11 22:19:28.199 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] We are already initialized slope=-0.08573164277920156 last_temp=20.40
2023-11-11 22:19:28.199 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] delta_t=1.365 delta_temp=-0.100 new_slope=-0.073 last_slope=-0.08573164277920156 slope=-0.079
2023-11-11 22:20:00.769 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] We are already initialized slope=-0.07948850486448325 last_temp=20.30
2023-11-11 22:20:00.769 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] delta_t=0.543 delta_temp=0.100 new_slope=0.184 last_slope=-0.07948850486448325 slope=0.052
2023-11-11 22:20:16.964 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] We are already initialized slope=0.05235392360942899 last_temp=20.40
2023-11-11 22:20:16.964 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] delta_t=0.270 delta_temp=-0.100 new_slope=-0.370 last_slope=0.05235392360942899 slope=-0.159
2023-11-11 22:21:28.299 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] We are already initialized slope=-0.15905688728551168 last_temp=20.30
2023-11-11 22:21:28.299 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] delta_t=1.189 delta_temp=0.100 new_slope=0.084 last_slope=-0.15905688728551168 slope=-0.037
2023-11-11 22:22:51.298 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] We are already initialized slope=-0.18585105481523084 last_temp=20.60
2023-11-11 22:22:51.298 DEBUG (MainThread) [custom_components.versatile_thermostat.open_window_algorithm] delta_t=5.294 delta_temp=0.100 new_slope=0.019 last_slope=-0.18585105481523084 slope=-0.083
``

@maia
Copy link
Author

maia commented Nov 12, 2023

@jmcollin78 Can the problem with the cycle calculation that you attempt to fix in 4.0.3 cause the issues with slope calculation?

@jmcollin78
Copy link
Owner

Normally not. The slope is time based : Delta Temp / Delta time.

@maia
Copy link
Author

maia commented Nov 12, 2023

Normally not. The slope is time based : Delta Temp / Delta time.

Well, if delta time is zero or just a few seconds, it might mess up the slope?

I havn't looked into the slope calculation, but it would be great if the slope is usable to predict the room temperature in the next cycle (in 5 minutes). But maybe that would need two slopes, one short term and one medium term. The "medium term" slope would be something like a regression based on all measurements of the past 30 minutes used to predict the temperature in 5 minutes.

Having an algorithm deal with a predicted temperature in 5 minutes might increase its performance and reduce over/undershooting: "If the status quo continues, will the temperature rise or fall in the next 5 minutes and will we need additional heating or not?"

By the way, the slope is also an aspect of different room physics. To me it feels like it would be great to have one place in the config where one defines the physics (from "slow to heat, slow to cool down" to "rapidly changes to heating and open windows") and that single setting defines some (user hidden) variables that influence slope calculation, self regulation etc.

@jmcollin78
Copy link
Owner

jmcollin78 commented Nov 12, 2023

Yes that's is why I have a minimal delay (10 sec) between 2 measurements.

The algorithm don't like the noise giving +0.1 and -0.1° sometime many times per minutes.
Of we take this one:

delta_t=0.269 delta_temp=0.100 new_slope=0.371 last_slope=0.07340745304406945 slope=0.222

delta_t is very short (16 sec) and 0.1° in 16 sec means a big gap which produce some bad slope measurement.

My temperature curve are mostly smooth and that's why don't experience your problem.

I guess my magic value of 10 sec in not accurate for your case. Maybe we should adapt it to 30 sec in your case.

If you can have a try it is located in open_window_algorithm.py line 15.

The difficulty here is to remove some aberrant point (see my temperature graph). So I have temporal filter, aberrant point removal based on threshold, and low pass filter with mobile mean ( val(N) = mes(N) x 0.5 + mes(N-1) x 0.5)

@maia
Copy link
Author

maia commented Nov 12, 2023

I will try that before I have to reboot HA the next time. Rebooting is always as issue as the entire thread mesh network needs to recreate itself and that takes a while and sometimes some devices don't join.

But in general I think this part of the code could be drastically improved by using more than the last 2 temperature measurements and the time inbetween, this will always be inexact. I don't have a pseudo-code solution yet though.

@jmcollin78
Copy link
Owner

@maia
Copy link
Author

maia commented Nov 12, 2023

The slope now has less wild swings. Unfortunately it's not able to detect open windows:
Bildschirmfoto 2023-11-12 um 21 06 55
This is a 2 hour period where nothing happened at home. No people moving, no electrical devices, no open windows, no sunlight, no cooking. Any slope in the range of -0,05 to +0,05 is basically noise.

And when I opened the window, the slope in that room didn't change more than when the window was closed:
Bildschirmfoto 2023-11-12 um 21 07 49

From all I've read about unsupervised time series forecasting today (e.g. see this link) I believe the biggest improvement is to use an exponential smoothing for the temperature: Take the temperature for the past 10 minutes (one measurement per minute, if not available then calculate from the available data points), calculate a EMA for the past few minutes and use the difference between the last two smoothed points as slope.

@jmcollin78
Copy link
Owner

jmcollin78 commented Nov 14, 2023

I do an exponential mobile average calculation but not on the temperature itself but on the slope (which is not suppose to change on a wide range too fast).
This is done by the formula I gave above: slope(N) = mes(N) x 0.5 + slope(N-1) x 0.5
But you are right, in your case, because your measured temperature is very noisy (at the difference of mine typically and others thats uses this algorithm without problem) I should filter the temperature itself and no only the slope.

I will have a look at this. Maybe something like:

temp(N) = temp_measurement (N) x 0,60 + temp(N-1) x 0,40.

This will largely smooth the temperature curve but not too much which will introduce too much latency in detection. I have to make some simulation with your measurements.

@jmcollin78 jmcollin78 reopened this Nov 14, 2023
@jmcollin78 jmcollin78 added enhancement New feature or request and removed bug Something isn't working developed When development is done and tested labels Nov 14, 2023
@maia
Copy link
Author

maia commented Nov 14, 2023

Jean-Marc, I have a couple of suggestions:

  1. As a statistician I would say that smoothing of the slope is wrong, you should smooth the input that is used for calculations instead.

  2. Create a central place in the code for calculation of EMA (exponential smoothing) and/or other algorithms, instead of having it in multiple places (e.g. slope calculation, regulated temperature,…). Especially the regulated temperature algorithm can be improved when knowing the current slope. Or maybe even better: two slopes: one long term (the past 60 minutes), one short term (the past 10 minutes)

  3. The alpha (or: multiplier, smoothing factor,…) of EMA is frequently defined by the number of periods that should be used for the EMA calculation. The alpha is 0.66 at 2 periods, 0.5 at 3 periods, 0.4 at 4 periods, 0.33 at 5 periods: alpha = 2 / (num_periods + 1). I find it easier to understand when using the number of periods as input over a factor like the 0.6 you're suggesting.

  4. You could use something like:

def calculate_ema(previous_ema, current_measurement, num_periods):
    if previous_ema is None or previous_ema == 0:
        return current_measurement
    
    alpha = 2 / (num_periods + 1)
    smoothed_value = alpha * current_measurement + (1 - alpha) * previous_ema
    return smoothed_value

(I'm just starting to learn python, so I hope that's valid)

  1. Is the slope calculation run every 5 minutes or is it run each time the measured temperature changes? It should really be based on a fixed cycle, because some temperature sensors update their measurement every second or every 10 seconds. We cannot use a proper smoothing if we don't know if the last 3 measurements are from the last 10 minutes or last 10 seconds.

  2. We should have a cycle of 1-2 minutes for dealing with temperature measurements. A cycle of 5 minutes only gives you a maximum of 3 measurements in 10 minutes, which is not really enough for a proper smoothing of measurements. Especially as many sensors have a tolerance of +/- 0.2°C and only few have +/- 0.1°C. So when using less than 5 measurements you'll end up with noise only.

  3. When calculating a slow (1 hour) and a fast (10 minutes) EMA we could use the distance between these for window open detection.

@jmcollin78
Copy link
Owner

jmcollin78 commented Nov 14, 2023

  1. As a statistician I would say that smoothing of the slope is wrong, you should smooth the input that is used for calculations instead.

Agree.

Create a central place in the code for calculation of EMA

Yes

The alpha..

yes. I always use 0.5 myself to get a relatively dynamic curve, but this can be variabilized for sure. Thank you for your suggestion.

Is the slope calculation run every 5 minutes or is it run each time the measured temperature changes?

each time the temperature change. So We must integrate the delta time to be correct. That's why I ignore to frequent measurement. I cannot have another cycle for this calculation and having it calculated at cycle only will be not suitable for long cycle. I have to find a formula for which we can take into account the dt factor. I think that's why I smooth the slope (which dtemp / dt) and not smooth the temp only.

EDIT: are you really a statistician or like me just a sunday stastistician user ?

@maia
Copy link
Author

maia commented Nov 14, 2023

I agree, it's a goal to have a place in code where measurements can reported the moment they happen and are processed, to be available for slope calculation, regulation etc. – and this must take the timestamps of the measurements into account, by e.g. creating a 1 minute timeframe and if multiple measurements are taken in that single minute then we use the average and if there's no measurement over a few minutes then we calculate the sliding average between the available measurements.

EDIT: are you really a statistician or like me just a sunday stastistician user ?

I don't have academic training in statistics but statistics have been a rather large part of my profession over the past 20 years, from classical surveying to predictive analytics, financial markets and language models - and anything inbetween.

@maia
Copy link
Author

maia commented Nov 14, 2023

I've seen that it's common to use EMA for irregular time series. In that case the input is a list of tuples containing the timestamp and corresponding measured temperature value. The timestamps should be in ascending order.

The EMA is calculated by using the distance between two measurements to calculate the alpha. See this explanation, scroll down to "Irregular Intervals". Also see this pdf paper (page 9).

EDIT: The decay/half-life (denominator G) in the first example is the one point where one can define if the EMA should only look at very recent data (e.g. 10 minute) or longer time frames.

@jmcollin78
Copy link
Owner

See this explanation, scroll down to "Irregular Intervals"

This seems very easy to implement. I will try this maybe this week-end.

@maia
Copy link
Author

maia commented Nov 14, 2023

This seems very easy to implement. I will try this maybe this week-end.

I agree, it is promising. I also found this alpha calculation, it probably is the better choice and maybe you want to consider it instead (in C++ and Ruby, isn't there any AI translation service into Python?):

double alpha = 1 - std::exp(std::log(0.5) * time_decay / halflife);
double ewma  = alpha * measurement + (1 - alpha) * previous_ewma;
alpha = 1 - Math::E ** (Math.log(0.5) * time_decay / halflife )
ewma  = alpha * measurement + (1 - alpha) * previous_ewma

As for using the data: You could calculate the EMA and keep all calculated EMA values of the past 60 minutes in memory (or only keep a maximum of one per minute, it is smoothed anyway). This would allow to calculate a slow and a fast slope (e.g. 60 minutes and 10 minutes). And having this in a central place even allows to use the EMA values for a regression calculation to calculate the slope at some point in the future. It will allow predicting the temperature in the future (in 5 minutes) and this value could be used in the regulation algorithm.

As for the EMA calculation of irregular time series, I've seen that it might be useful to have an upper limit for alpha in case the last measurement was too long ago. For example when using a half life of 10 minutes a measurement that is 60 minutes ago (if there's nothing inbetween) would contribute to the smoothed value with 1,5%, giving the current measurement 98,5% relevance. It could be wise to limit the alpha to e.g. 4x the half life (=0.9375).

@jmcollin78
Copy link
Owner

Planned for 4.2.0 (next release). Maybe next week or this week if i have got enough time.

@jmcollin78
Copy link
Owner

jmcollin78 commented Nov 18, 2023

Finally, I succeed to implement the EMA algorithm, add a ema_temp new attribute which is the smoothed temperature value and I use it into the automatic window detection algorithm.
I will publish a beta release with that. Feel free to test it in parallel of myself.

https://github.com/jmcollin78/versatile_thermostat/releases/tag/4.2.0.alpha1

I create a Discussion announcement if we want to discuss more about this.

EDIT:
This time is it the good one. I also remove the smoothing of slope which in doublon with the ema of temperature.

@jmcollin78
Copy link
Owner

Hello @maia ,

I have publish a alpha8 pre-release which fixes all slope artifacts. Can you have a try with these release ?

The other think I have discovered this integration which is really helpfull to display graphs with zoom and much more.

type: custom:plotly-graph
entities:
  - entity: sensor.thermostat_chambre_ema_temperature
    yaxis: y1
    name: Ema
  - entity: climate.thermostat_chambre
    attribute: temperature
    yaxis: y1
    name: Consigne
  - entity: climate.thermostat_chambre
    attribute: current_temperature
    yaxis: y1
    name: T°
  - entity: sensor.thermostat_chambre_temperature_slope
    name: Slope
    fill: tozeroy
    yaxis: y9
    fillcolor: rgba(100, 100, 100, 0.3)
    line:
      color: rgba(100, 100, 100, 0.9)
hours_to_show: 4
refresh_interval: 10
height: 800
config:
  scrollZoom: true
layout:
  margin:
    r: 50
  legend:
    x: 0
    'y': 1.2
    groupclick: togglegroup
    title:
      side: top right
  yaxis:
    visible: true
    position: 0
  yaxis9:
    visible: true
    fixedrange: false
    range:
      - -0.15
      - 0.15
    position: 1
  xaxis:
    rangeselector:
      'y': 1.1
      x: 0.7
      buttons:
        - count: 1
          step: hour
        - count: 12
          step: hour
        - count: 1
          step: day
        - count: 7
          step: day

I have beautiful analysis graph now:

Capture d’écran 2023-11-29 à 08 57 51

@jmcollin78
Copy link
Owner

jmcollin78 commented Nov 29, 2023

Maybe I have a precision issue. When the temperature is slowly decreasing I should have a small negative value and not 0 which is case here. Maybe the unit °C/min is not accurate and a unit as °C/hour would be better.
Do you have an opinion about this ?

My room is loosing 1° in 3 hours. This make 0,33 °C/hours = 0,005 °C/min -> slope is 0.

@jmcollin78
Copy link
Owner

Another room:

Capture d’écran 2023-11-29 à 10 24 35

@maia
Copy link
Author

maia commented Nov 29, 2023

I agree, a slope measured in °C/hour is better interpretable for humans. And anything users configure themselves should be as understandable as possible.

Regarding alpha8, which I installed yesterday, the calculated slopes unfortunately still cause false positives when the temperature changes by only 0,1°C and looking at these charts I couldn't say which threshold I would want to use. (I opened the windows in all three rooms at the same time and for the same duration, with 0°C outside)

Unfortunately I'm currently rather busy and don't have time to investigate possible solutions for a better calculation of the smoothed temperature. But as this smoothing is partly relevant also for an improved regulated temperature, I'm hoping that someone can come up with a solution. Because otherwise I'd want to suggest to change the default cycle from 5 minutes to 1 minute (for everything, not just the slope), I'm not yet aware of any downside to having shorter cycles.

Bildschirmfoto 2023-11-29 um 10 13 03 Bildschirmfoto 2023-11-29 um 10 14 16 Bildschirmfoto 2023-11-29 um 10 13 32

@jmcollin78
Copy link
Owner

Because you have a very volatile thermometer you certainly need to "smooth" more the EMA. I will expose the possibility to change the parameters of EMA calculation (in the configuration.yaml to avoid adding more configuration parameters in the UI). I think this is the solution for your case. You will then have more "latency" and detection will be delayed but we cannot have both : slow latency and heavy smoothing.

@maia
Copy link
Author

maia commented Nov 29, 2023

I will expose the possibility to change the parameters of EMA calculation

The recent screenshots show different temperature sensors, one of them is from Aqara and as far as I know, it's a pretty frequently used sensor. Ideally 90% of the users do not need to change parameters, neither in yaml nor the UI. It should work out of the box.

I think you personally don't see these issues as your rooms change temperature very, very rapidly, so any 0,1°C change the sensor reports is only a blip in your charts.

@maia
Copy link
Author

maia commented Nov 29, 2023

An additional info to alpha8: I'm still seeing strong spikes in the calculated slope:
Bildschirmfoto 2023-11-29 um 13 32 25
Here's the measured temperature data:

12:20:14,20.6
12:20:22,20.5
12:20:57,20.6
12:21:21,20.5
12:21:35,20.6
12:21:56,20.5
12:22:24,20.6
12:22:29,20.5
12:22:51,20.6
12:22:59,20.5
12:23:26,20.6
12:23:36,20.5
12:23:44,20.6
12:24:00,20.5
12:24:02,20.6
12:24:17,20.5
12:25:08,20.6
12:28:14,20.7
12:28:24,20.6
12:29:37,20.7
12:54:40,20.6
12:54:50,20.7
12:56:55,20.6
12:57:07,20.7
12:57:35,20.6
12:57:50,20.7
12:58:20,20.6
12:58:31,20.7
12:58:51,20.6
12:59:03,20.7
12:59:11,20.6
13:00:47,20.7
13:00:57,20.6
13:05:08,20.5
13:05:20,20.6
13:05:29,20.5
13:05:39,20.6
13:05:51,20.5
13:06:11,20.6
13:06:32,20.5
13:06:46,20.6
13:06:56,20.5
13:07:04,20.6
13:07:17,20.5
13:08:01,20.6
13:08:02,20.5
13:08:04,20.6
13:08:21,20.5
13:13:28,20.4
13:13:32,20.5
13:16:31,20.4
13:16:42,20.5
13:17:37,20.4
13:17:47,20.5
13:18:09,20.4
13:18:17,20.5
13:18:48,20.4
13:18:56,20.5
13:19:09,20.4
13:19:21,20.5
13:19:44,20.4
13:19:47,20.5
13:19:51,20.4
13:20:10,20.5
13:20:28,20.4
13:20:34,20.5
13:21:07,20.4
13:21:13,20.5
13:21:19,20.4
13:21:50,20.5
13:21:56,20.4
13:22:30,20.5
13:22:39,20.4
13:23:44,20.5
13:23:54,20.4
13:25:40,20.5
13:25:50,20.4
13:26:41,20.5
13:26:49,20.4
13:27:57,20.5
13:28:03,20.4

@jmcollin78
Copy link
Owner

jmcollin78 commented Nov 29, 2023

Thank I will try to reproduce with the value.
May I have the value of the EMA temperature ? and maybe a zoom around 13h15.
The window detection is based on the EMA which should be "smooth".

I wonder how long will your battery support this behavior.

EDIT:
I hope you agree with me, that the behavior of your temperature sensor is very weird. 5 temperature per minutes is really not expected and I can't rely on this to build an algorithm. I'm not sure, you won't need a special configuration to handle that.

@maia
Copy link
Author

maia commented Nov 29, 2023

Here's a zoom. Not sure how to export the ema values, the lovelace card I usually use only allows to export entities, not attributes. Will look into it. Also I'll try a 1min average smoothing of the raw temperature as input for vtherm.

The batteries (2xAAA) hold for 1-2 years. While powering a display. BLE is very efficient it seems.
Bildschirmfoto 2023-11-29 um 13 55 22

@jmcollin78 jmcollin78 added the developed When development is done and tested label Dec 1, 2023
@jmcollin78
Copy link
Owner

I have released the 4.2.0 with the capbility to use your own parameters for EMA calculation.
So I close the issue, but the discussion can continue if needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
developed When development is done and tested enhancement New feature or request P1 Priority 1
Projects
None yet
Development

No branches or pull requests

2 participants