2727 mock_restore_cache_with_extra_data ,
2828)
2929
30-
31- async def test_state (hass : HomeAssistant ) -> None :
30+ A1 = {"attr" : "value1" }
31+ A2 = {"attr" : "value2" }
32+
33+
34+ @pytest .mark .parametrize ("force_update" , [False , True ])
35+ @pytest .mark .parametrize (
36+ "attributes" ,
37+ [
38+ # Same attributes, fires state report
39+ [A1 , A1 ],
40+ # Changing attributes, fires state change with bumped last_updated
41+ [A1 , A2 ],
42+ ],
43+ )
44+ async def test_state (
45+ hass : HomeAssistant ,
46+ force_update : bool ,
47+ attributes : list [dict [str , Any ]],
48+ ) -> None :
3249 """Test derivative sensor state."""
3350 config = {
3451 "sensor" : {
@@ -45,12 +62,13 @@ async def test_state(hass: HomeAssistant) -> None:
4562 entity_id = config ["sensor" ]["source" ]
4663 base = dt_util .utcnow ()
4764 with freeze_time (base ) as freezer :
48- hass .states .async_set (entity_id , 1 , {})
49- await hass .async_block_till_done ()
65+ for extra_attributes in attributes :
66+ hass .states .async_set (
67+ entity_id , 1 , extra_attributes , force_update = force_update
68+ )
69+ await hass .async_block_till_done ()
5070
51- freezer .move_to (dt_util .utcnow () + timedelta (seconds = 3600 ))
52- hass .states .async_set (entity_id , 1 , {})
53- await hass .async_block_till_done ()
71+ freezer .move_to (dt_util .utcnow () + timedelta (seconds = 3600 ))
5472
5573 state = hass .states .get ("sensor.derivative" )
5674 assert state is not None
@@ -61,7 +79,24 @@ async def test_state(hass: HomeAssistant) -> None:
6179 assert state .attributes .get ("unit_of_measurement" ) == "kW"
6280
6381
64- async def test_no_change (hass : HomeAssistant ) -> None :
82+ # Test unchanged states work both with and without max_sub_interval
83+ @pytest .mark .parametrize ("extra_config" , [{}, {"max_sub_interval" : {"minutes" : 9999 }}])
84+ @pytest .mark .parametrize ("force_update" , [False , True ])
85+ @pytest .mark .parametrize (
86+ "attributes" ,
87+ [
88+ # Same attributes, fires state report
89+ [A1 , A1 , A1 , A1 ],
90+ # Changing attributes, fires state change with bumped last_updated
91+ [A1 , A2 , A1 , A2 ],
92+ ],
93+ )
94+ async def test_no_change (
95+ hass : HomeAssistant ,
96+ extra_config : dict [str , Any ],
97+ force_update : bool ,
98+ attributes : list [dict [str , Any ]],
99+ ) -> None :
65100 """Test derivative sensor state updated when source sensor doesn't change."""
66101 config = {
67102 "sensor" : {
@@ -71,27 +106,21 @@ async def test_no_change(hass: HomeAssistant) -> None:
71106 "unit" : "kW" ,
72107 "round" : 2 ,
73108 }
109+ | extra_config
74110 }
75111
76112 assert await async_setup_component (hass , "sensor" , config )
77113
78114 entity_id = config ["sensor" ]["source" ]
79115 base = dt_util .utcnow ()
80116 with freeze_time (base ) as freezer :
81- hass .states .async_set (entity_id , 0 , {})
82- await hass .async_block_till_done ()
83-
84- freezer .move_to (dt_util .utcnow () + timedelta (seconds = 3600 ))
85- hass .states .async_set (entity_id , 1 , {})
86- await hass .async_block_till_done ()
87-
88- freezer .move_to (dt_util .utcnow () + timedelta (seconds = 3600 ))
89- hass .states .async_set (entity_id , 1 , {})
90- await hass .async_block_till_done ()
117+ for value , extra_attributes in zip ([0 , 1 , 1 , 1 ], attributes , strict = True ):
118+ hass .states .async_set (
119+ entity_id , value , extra_attributes , force_update = force_update
120+ )
121+ await hass .async_block_till_done ()
91122
92- freezer .move_to (dt_util .utcnow () + timedelta (seconds = 3600 ))
93- hass .states .async_set (entity_id , 1 , {})
94- await hass .async_block_till_done ()
123+ freezer .move_to (dt_util .utcnow () + timedelta (seconds = 3600 ))
95124
96125 state = hass .states .get ("sensor.derivative" )
97126 assert state is not None
@@ -138,7 +167,7 @@ async def setup_tests(
138167 # Testing a energy sensor with non-monotonic intervals and values
139168 base = dt_util .utcnow ()
140169 with freeze_time (base ) as freezer :
141- for time , value in zip (times , values , strict = False ):
170+ for time , value in zip (times , values , strict = True ):
142171 freezer .move_to (base + timedelta (seconds = time ))
143172 hass .states .async_set (entity_id , value , {})
144173 await hass .async_block_till_done ()
@@ -213,7 +242,24 @@ async def test_dataSet6(hass: HomeAssistant) -> None:
213242 await setup_tests (hass , {}, times = [0 , 60 ], values = [0 , 1 / 60 ], expected_state = 1 )
214243
215244
216- async def test_data_moving_average_with_zeroes (hass : HomeAssistant ) -> None :
245+ # Test unchanged states work both with and without max_sub_interval
246+ @pytest .mark .parametrize ("extra_config" , [{}, {"max_sub_interval" : {"minutes" : 9999 }}])
247+ @pytest .mark .parametrize ("force_update" , [False , True ])
248+ @pytest .mark .parametrize (
249+ "attributes" ,
250+ [
251+ # Same attributes, fires state report
252+ [A1 , A1 ] * 10 + [A1 ],
253+ # Changing attributes, fires state change with bumped last_updated
254+ [A1 , A2 ] * 10 + [A1 ],
255+ ],
256+ )
257+ async def test_data_moving_average_with_zeroes (
258+ hass : HomeAssistant ,
259+ extra_config : dict [str , Any ],
260+ force_update : bool ,
261+ attributes : list [dict [str , Any ]],
262+ ) -> None :
217263 """Test that zeroes are properly handled within the time window."""
218264 # We simulate the following situation:
219265 # The temperature rises 1 °C per minute for 10 minutes long. Then, it
@@ -235,16 +281,21 @@ async def test_data_moving_average_with_zeroes(hass: HomeAssistant) -> None:
235281 "time_window" : {"seconds" : time_window },
236282 "unit_time" : UnitOfTime .MINUTES ,
237283 "round" : 1 ,
238- },
284+ }
285+ | extra_config ,
239286 )
240287
241288 base = dt_util .utcnow ()
242289 with freeze_time (base ) as freezer :
243290 last_derivative = 0
244- for time , value in zip (times , temperature_values , strict = True ):
291+ for time , value , extra_attributes in zip (
292+ times , temperature_values , attributes , strict = True
293+ ):
245294 now = base + timedelta (seconds = time )
246295 freezer .move_to (now )
247- hass .states .async_set (entity_id , value , {})
296+ hass .states .async_set (
297+ entity_id , value , extra_attributes , force_update = force_update
298+ )
248299 await hass .async_block_till_done ()
249300
250301 state = hass .states .get ("sensor.power" )
@@ -273,7 +324,7 @@ async def test_data_moving_average_for_discrete_sensor(hass: HomeAssistant) -> N
273324 for temperature in range (30 ):
274325 temperature_values += [temperature ] * 2 # two values per minute
275326 time_window = 600
276- times = list (range (0 , 1800 + 30 , 30 ))
327+ times = list (range (0 , 1800 , 30 ))
277328
278329 config , entity_id = await _setup_sensor (
279330 hass ,
@@ -286,7 +337,7 @@ async def test_data_moving_average_for_discrete_sensor(hass: HomeAssistant) -> N
286337
287338 base = dt_util .utcnow ()
288339 with freeze_time (base ) as freezer :
289- for time , value in zip (times , temperature_values , strict = False ):
340+ for time , value in zip (times , temperature_values , strict = True ):
290341 now = base + timedelta (seconds = time )
291342 freezer .move_to (now )
292343 hass .states .async_set (entity_id , value , {})
@@ -330,7 +381,7 @@ def temp_function(time):
330381
331382 base = dt_util .utcnow ()
332383 with freeze_time (base ) as freezer :
333- for time , value in zip (times , temperature_values , strict = False ):
384+ for time , value in zip (times , temperature_values , strict = True ):
334385 now = base + timedelta (seconds = time )
335386 freezer .move_to (now )
336387 hass .states .async_set (entity_id , value , {})
@@ -368,7 +419,7 @@ async def test_double_signal_after_delay(hass: HomeAssistant) -> None:
368419 base = dt_util .utcnow ()
369420 previous = 0
370421 with freeze_time (base ) as freezer :
371- for time , value in zip (times , temperature_values , strict = False ):
422+ for time , value in zip (times , temperature_values , strict = True ):
372423 now = base + timedelta (seconds = time )
373424 freezer .move_to (now )
374425 hass .states .async_set (entity_id , value , {})
@@ -506,7 +557,7 @@ async def test_sub_intervals_with_time_window(hass: HomeAssistant) -> None:
506557 base = dt_util .utcnow ()
507558 with freeze_time (base ) as freezer :
508559 last_state_change = None
509- for time , value in zip (times , values , strict = False ):
560+ for time , value in zip (times , values , strict = True ):
510561 now = base + timedelta (seconds = time )
511562 freezer .move_to (now )
512563 hass .states .async_set (entity_id , value , {}, force_update = True )
@@ -636,7 +687,7 @@ async def test_total_increasing_reset(hass: HomeAssistant) -> None:
636687 actual_times = []
637688 actual_values = []
638689 with freeze_time (base_time ) as freezer :
639- for time , value in zip (times , values , strict = False ):
690+ for time , value in zip (times , values , strict = True ):
640691 current_time = base_time + timedelta (seconds = time )
641692 freezer .move_to (current_time )
642693 hass .states .async_set (
@@ -724,7 +775,7 @@ async def test_unavailable(
724775 # Testing a energy sensor with non-monotonic intervals and values
725776 base = dt_util .utcnow ()
726777 with freeze_time (base ) as freezer :
727- for time , value , expect in zip (times , values , expected_state , strict = False ):
778+ for time , value , expect in zip (times , values , expected_state , strict = True ):
728779 freezer .move_to (base + timedelta (seconds = time ))
729780 hass .states .async_set (entity_id , value , {})
730781 await hass .async_block_till_done ()
@@ -759,7 +810,7 @@ async def test_unavailable_2(
759810
760811 base = dt_util .utcnow ()
761812 with freeze_time (base ) as freezer :
762- for time , value in zip (times , values , strict = False ):
813+ for time , value in zip (times , values , strict = True ):
763814 freezer .move_to (base + timedelta (seconds = time ))
764815 hass .states .async_set (entity_id , value , {})
765816 await hass .async_block_till_done ()
0 commit comments