@@ -4062,33 +4062,130 @@ async def test_compile_hourly_statistics_equivalent_units_2(
40624062@pytest .mark .parametrize (
40634063 (
40644064 "device_class" ,
4065- "state_unit" ,
4066- "statistic_unit" ,
4067- "unit_class" ,
4065+ "unit_1" ,
4066+ "unit_2" ,
4067+ "unit_3" ,
4068+ "unit_class_1" ,
4069+ "unit_class_2" ,
4070+ "factor_2" ,
4071+ "factor_3" ,
40684072 "mean1" ,
40694073 "mean2" ,
40704074 "min" ,
40714075 "max" ,
40724076 ),
40734077 [
4074- ("power" , "kW" , "kW" , "power" , 13.050847 , 13.333333 , - 10 , 30 ),
4078+ (
4079+ "power" ,
4080+ "kW" ,
4081+ "kW" ,
4082+ "kW" ,
4083+ "power" ,
4084+ "power" ,
4085+ 1 ,
4086+ 1 ,
4087+ 13.050847 ,
4088+ 13.333333 ,
4089+ - 10 ,
4090+ 30 ,
4091+ ),
4092+ (
4093+ "carbon_monoxide" ,
4094+ "ppm" ,
4095+ "ppm" ,
4096+ "ppm" ,
4097+ "unitless" ,
4098+ "carbon_monoxide" ,
4099+ 1 ,
4100+ 1 ,
4101+ 13.050847 ,
4102+ 13.333333 ,
4103+ - 10 ,
4104+ 30 ,
4105+ ),
4106+ # Valid change of unit class from unitless to carbon_monoxide
4107+ (
4108+ "carbon_monoxide" ,
4109+ "ppm" ,
4110+ "ppm" ,
4111+ "mg/m³" ,
4112+ "unitless" ,
4113+ "carbon_monoxide" ,
4114+ 1 ,
4115+ 1.164409 ,
4116+ 13.050847 ,
4117+ 13.333333 ,
4118+ - 10 ,
4119+ 30 ,
4120+ ),
4121+ # Valid change of unit class from unitless to carbon_monoxide
4122+ (
4123+ "carbon_monoxide" ,
4124+ "ppm" ,
4125+ "mg/m³" ,
4126+ "mg/m³" ,
4127+ "unitless" ,
4128+ "carbon_monoxide" ,
4129+ 1.164409 ,
4130+ 1.164409 ,
4131+ 13.050847 ,
4132+ 13.333333 ,
4133+ - 10 ,
4134+ 30 ,
4135+ ),
4136+ # Valid change of unit class from concentration to carbon_monoxide
4137+ (
4138+ "carbon_monoxide" ,
4139+ "mg/m³" ,
4140+ "mg/m³" ,
4141+ "ppm" ,
4142+ "concentration" ,
4143+ "carbon_monoxide" ,
4144+ 1 ,
4145+ 1 / 1.164409 ,
4146+ 13.050847 ,
4147+ 13.333333 ,
4148+ - 10 ,
4149+ 30 ,
4150+ ),
4151+ # Valid change of unit class from concentration to carbon_monoxide
4152+ (
4153+ "carbon_monoxide" ,
4154+ "mg/m³" ,
4155+ "ppm" ,
4156+ "ppm" ,
4157+ "concentration" ,
4158+ "carbon_monoxide" ,
4159+ 1 / 1.164409 ,
4160+ 1 / 1.164409 ,
4161+ 13.050847 ,
4162+ 13.333333 ,
4163+ - 10 ,
4164+ 30 ,
4165+ ),
40754166 ],
40764167)
40774168async def test_compile_hourly_statistics_changing_device_class_1 (
40784169 hass : HomeAssistant ,
40794170 caplog : pytest .LogCaptureFixture ,
40804171 device_class ,
4081- state_unit ,
4082- statistic_unit ,
4083- unit_class ,
4172+ unit_1 ,
4173+ unit_2 ,
4174+ unit_3 ,
4175+ unit_class_1 ,
4176+ unit_class_2 ,
4177+ factor_2 ,
4178+ factor_3 ,
40844179 mean1 ,
40854180 mean2 ,
40864181 min ,
40874182 max ,
40884183) -> None :
40894184 """Test compiling hourly statistics where device class changes from one hour to the next.
40904185
4091- Device class is ignored, meaning changing device class should not influence the statistics.
4186+ In this test, the device class is first None, then set to a specific device class.
4187+
4188+ Changing device class may influence the unit class.
40924189 """
40934190 zero = get_start_time (dt_util .utcnow ())
40944191 await async_setup_component (hass , "sensor" , {})
@@ -4098,7 +4195,7 @@ async def test_compile_hourly_statistics_changing_device_class_1(
40984195 # Record some states for an initial period, the entity has no device class
40994196 attributes = {
41004197 "state_class" : "measurement" ,
4101- "unit_of_measurement" : state_unit ,
4198+ "unit_of_measurement" : unit_1 ,
41024199 }
41034200 with freeze_time (zero ) as freezer :
41044201 four , states = await async_record_states (
@@ -4113,14 +4210,14 @@ async def test_compile_hourly_statistics_changing_device_class_1(
41134210 assert statistic_ids == [
41144211 {
41154212 "statistic_id" : "sensor.test1" ,
4116- "display_unit_of_measurement" : state_unit ,
4213+ "display_unit_of_measurement" : unit_1 ,
41174214 "has_mean" : True ,
41184215 "mean_type" : StatisticMeanType .ARITHMETIC ,
41194216 "has_sum" : False ,
41204217 "name" : None ,
41214218 "source" : "recorder" ,
4122- "statistics_unit_of_measurement" : state_unit ,
4123- "unit_class" : unit_class ,
4219+ "statistics_unit_of_measurement" : unit_1 ,
4220+ "unit_class" : unit_class_1 ,
41244221 },
41254222 ]
41264223 stats = statistics_during_period (hass , zero , period = "5minute" )
@@ -4139,15 +4236,17 @@ async def test_compile_hourly_statistics_changing_device_class_1(
41394236 ]
41404237 }
41414238
4142- # Update device class and record additional states in the original UoM
4239+ # Update device class and record additional states in a different UoM
41434240 attributes ["device_class" ] = device_class
4241+ attributes ["unit_of_measurement" ] = unit_2
4242+ seq = [x * factor_2 for x in (- 10 , 15 , 30 )]
41444243 with freeze_time (zero ) as freezer :
41454244 four , _states = await async_record_states (
4146- hass , freezer , zero + timedelta (minutes = 5 ), "sensor.test1" , attributes
4245+ hass , freezer , zero + timedelta (minutes = 5 ), "sensor.test1" , attributes , seq
41474246 )
41484247 states ["sensor.test1" ] += _states ["sensor.test1" ]
41494248 four , _states = await async_record_states (
4150- hass , freezer , zero + timedelta (minutes = 10 ), "sensor.test1" , attributes
4249+ hass , freezer , zero + timedelta (minutes = 10 ), "sensor.test1" , attributes , seq
41514250 )
41524251 await async_wait_recording_done (hass )
41534252 states ["sensor.test1" ] += _states ["sensor.test1" ]
@@ -4163,14 +4262,14 @@ async def test_compile_hourly_statistics_changing_device_class_1(
41634262 assert statistic_ids == [
41644263 {
41654264 "statistic_id" : "sensor.test1" ,
4166- "display_unit_of_measurement" : state_unit ,
4265+ "display_unit_of_measurement" : unit_2 ,
41674266 "has_mean" : True ,
41684267 "mean_type" : StatisticMeanType .ARITHMETIC ,
41694268 "has_sum" : False ,
41704269 "name" : None ,
41714270 "source" : "recorder" ,
4172- "statistics_unit_of_measurement" : state_unit ,
4173- "unit_class" : unit_class ,
4271+ "statistics_unit_of_measurement" : unit_1 ,
4272+ "unit_class" : unit_class_2 ,
41744273 },
41754274 ]
41764275 stats = statistics_during_period (hass , zero , period = "5minute" )
@@ -4179,19 +4278,19 @@ async def test_compile_hourly_statistics_changing_device_class_1(
41794278 {
41804279 "start" : process_timestamp (zero ).timestamp (),
41814280 "end" : process_timestamp (zero + timedelta (minutes = 5 )).timestamp (),
4182- "mean" : pytest .approx (mean1 ),
4183- "min" : pytest .approx (min ),
4184- "max" : pytest .approx (max ),
4281+ "mean" : pytest .approx (mean1 * factor_2 ),
4282+ "min" : pytest .approx (min * factor_2 ),
4283+ "max" : pytest .approx (max * factor_2 ),
41854284 "last_reset" : None ,
41864285 "state" : None ,
41874286 "sum" : None ,
41884287 },
41894288 {
41904289 "start" : process_timestamp (zero + timedelta (minutes = 10 )).timestamp (),
41914290 "end" : process_timestamp (zero + timedelta (minutes = 15 )).timestamp (),
4192- "mean" : pytest .approx (mean2 ),
4193- "min" : pytest .approx (min ),
4194- "max" : pytest .approx (max ),
4291+ "mean" : pytest .approx (mean2 * factor_2 ),
4292+ "min" : pytest .approx (min * factor_2 ),
4293+ "max" : pytest .approx (max * factor_2 ),
41954294 "last_reset" : None ,
41964295 "state" : None ,
41974296 "sum" : None ,
@@ -4200,14 +4299,15 @@ async def test_compile_hourly_statistics_changing_device_class_1(
42004299 }
42014300
42024301 # Update device class and record additional states in a different UoM
4203- attributes ["unit_of_measurement" ] = statistic_unit
4302+ attributes ["unit_of_measurement" ] = unit_3
4303+ seq = [x * factor_3 for x in (- 10 , 15 , 30 )]
42044304 with freeze_time (zero ) as freezer :
42054305 four , _states = await async_record_states (
4206- hass , freezer , zero + timedelta (minutes = 15 ), "sensor.test1" , attributes
4306+ hass , freezer , zero + timedelta (minutes = 15 ), "sensor.test1" , attributes , seq
42074307 )
42084308 states ["sensor.test1" ] += _states ["sensor.test1" ]
42094309 four , _states = await async_record_states (
4210- hass , freezer , zero + timedelta (minutes = 20 ), "sensor.test1" , attributes
4310+ hass , freezer , zero + timedelta (minutes = 20 ), "sensor.test1" , attributes , seq
42114311 )
42124312 await async_wait_recording_done (hass )
42134313 states ["sensor.test1" ] += _states ["sensor.test1" ]
@@ -4223,14 +4323,14 @@ async def test_compile_hourly_statistics_changing_device_class_1(
42234323 assert statistic_ids == [
42244324 {
42254325 "statistic_id" : "sensor.test1" ,
4226- "display_unit_of_measurement" : state_unit ,
4326+ "display_unit_of_measurement" : unit_3 ,
42274327 "has_mean" : True ,
42284328 "mean_type" : StatisticMeanType .ARITHMETIC ,
42294329 "has_sum" : False ,
42304330 "name" : None ,
42314331 "source" : "recorder" ,
4232- "statistics_unit_of_measurement" : state_unit ,
4233- "unit_class" : unit_class ,
4332+ "statistics_unit_of_measurement" : unit_1 ,
4333+ "unit_class" : unit_class_2 ,
42344334 },
42354335 ]
42364336 stats = statistics_during_period (hass , zero , period = "5minute" )
@@ -4239,29 +4339,29 @@ async def test_compile_hourly_statistics_changing_device_class_1(
42394339 {
42404340 "start" : process_timestamp (zero ).timestamp (),
42414341 "end" : process_timestamp (zero + timedelta (minutes = 5 )).timestamp (),
4242- "mean" : pytest .approx (mean1 ),
4243- "min" : pytest .approx (min ),
4244- "max" : pytest .approx (max ),
4342+ "mean" : pytest .approx (mean1 * factor_3 ),
4343+ "min" : pytest .approx (min * factor_3 ),
4344+ "max" : pytest .approx (max * factor_3 ),
42454345 "last_reset" : None ,
42464346 "state" : None ,
42474347 "sum" : None ,
42484348 },
42494349 {
42504350 "start" : process_timestamp (zero + timedelta (minutes = 10 )).timestamp (),
42514351 "end" : process_timestamp (zero + timedelta (minutes = 15 )).timestamp (),
4252- "mean" : pytest .approx (mean2 ),
4253- "min" : pytest .approx (min ),
4254- "max" : pytest .approx (max ),
4352+ "mean" : pytest .approx (mean2 * factor_3 ),
4353+ "min" : pytest .approx (min * factor_3 ),
4354+ "max" : pytest .approx (max * factor_3 ),
42554355 "last_reset" : None ,
42564356 "state" : None ,
42574357 "sum" : None ,
42584358 },
42594359 {
42604360 "start" : process_timestamp (zero + timedelta (minutes = 20 )).timestamp (),
42614361 "end" : process_timestamp (zero + timedelta (minutes = 25 )).timestamp (),
4262- "mean" : pytest .approx (mean2 ),
4263- "min" : pytest .approx (min ),
4264- "max" : pytest .approx (max ),
4362+ "mean" : pytest .approx (mean2 * factor_3 ),
4363+ "min" : pytest .approx (min * factor_3 ),
4364+ "max" : pytest .approx (max * factor_3 ),
42654365 "last_reset" : None ,
42664366 "state" : None ,
42674367 "sum" : None ,
@@ -4302,7 +4402,7 @@ async def test_compile_hourly_statistics_changing_device_class_2(
43024402) -> None :
43034403 """Test compiling hourly statistics where device class changes from one hour to the next.
43044404
4305- Device class is ignored, meaning changing device class should not influence the statistics .
4405+ In this test, the device class is first set to a specific device class, then set to None .
43064406 """
43074407 zero = get_start_time (dt_util .utcnow ())
43084408 await async_setup_component (hass , "sensor" , {})
0 commit comments