aiohomematic 2025.10.1__py3-none-any.whl → 2025.10.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of aiohomematic might be problematic. Click here for more details.

Files changed (56) hide show
  1. aiohomematic/async_support.py +7 -7
  2. aiohomematic/caches/dynamic.py +31 -26
  3. aiohomematic/caches/persistent.py +34 -32
  4. aiohomematic/caches/visibility.py +19 -7
  5. aiohomematic/central/__init__.py +87 -74
  6. aiohomematic/central/decorators.py +2 -2
  7. aiohomematic/central/xml_rpc_server.py +27 -24
  8. aiohomematic/client/__init__.py +72 -56
  9. aiohomematic/client/_rpc_errors.py +3 -3
  10. aiohomematic/client/json_rpc.py +33 -25
  11. aiohomematic/client/xml_rpc.py +14 -9
  12. aiohomematic/const.py +2 -1
  13. aiohomematic/converter.py +19 -19
  14. aiohomematic/exceptions.py +2 -1
  15. aiohomematic/model/__init__.py +4 -3
  16. aiohomematic/model/calculated/__init__.py +1 -1
  17. aiohomematic/model/calculated/climate.py +9 -9
  18. aiohomematic/model/calculated/data_point.py +13 -7
  19. aiohomematic/model/calculated/operating_voltage_level.py +2 -2
  20. aiohomematic/model/calculated/support.py +7 -7
  21. aiohomematic/model/custom/__init__.py +3 -3
  22. aiohomematic/model/custom/climate.py +57 -34
  23. aiohomematic/model/custom/cover.py +32 -18
  24. aiohomematic/model/custom/data_point.py +9 -7
  25. aiohomematic/model/custom/definition.py +23 -17
  26. aiohomematic/model/custom/light.py +52 -23
  27. aiohomematic/model/custom/lock.py +16 -12
  28. aiohomematic/model/custom/siren.py +6 -3
  29. aiohomematic/model/custom/switch.py +3 -2
  30. aiohomematic/model/custom/valve.py +3 -2
  31. aiohomematic/model/data_point.py +62 -49
  32. aiohomematic/model/device.py +48 -42
  33. aiohomematic/model/event.py +6 -5
  34. aiohomematic/model/generic/__init__.py +6 -4
  35. aiohomematic/model/generic/action.py +1 -1
  36. aiohomematic/model/generic/data_point.py +7 -5
  37. aiohomematic/model/generic/number.py +3 -3
  38. aiohomematic/model/generic/select.py +1 -1
  39. aiohomematic/model/generic/sensor.py +2 -2
  40. aiohomematic/model/generic/switch.py +3 -3
  41. aiohomematic/model/hub/__init__.py +17 -16
  42. aiohomematic/model/hub/data_point.py +12 -7
  43. aiohomematic/model/hub/number.py +3 -3
  44. aiohomematic/model/hub/select.py +3 -3
  45. aiohomematic/model/hub/text.py +2 -2
  46. aiohomematic/model/support.py +8 -7
  47. aiohomematic/model/update.py +6 -6
  48. aiohomematic/support.py +44 -38
  49. aiohomematic/validator.py +6 -6
  50. {aiohomematic-2025.10.1.dist-info → aiohomematic-2025.10.2.dist-info}/METADATA +1 -1
  51. aiohomematic-2025.10.2.dist-info/RECORD +78 -0
  52. aiohomematic_support/client_local.py +19 -12
  53. aiohomematic-2025.10.1.dist-info/RECORD +0 -78
  54. {aiohomematic-2025.10.1.dist-info → aiohomematic-2025.10.2.dist-info}/WHEEL +0 -0
  55. {aiohomematic-2025.10.1.dist-info → aiohomematic-2025.10.2.dist-info}/licenses/LICENSE +0 -0
  56. {aiohomematic-2025.10.1.dist-info → aiohomematic-2025.10.2.dist-info}/top_level.txt +0 -0
@@ -19,7 +19,7 @@ from aiohomematic.support import extract_exc_args
19
19
  _LOGGER: Final = logging.getLogger(__name__)
20
20
 
21
21
 
22
- def _calculate_heat_index(temperature: float, humidity: int) -> float:
22
+ def _calculate_heat_index(*, temperature: float, humidity: int) -> float:
23
23
  """
24
24
  Calculate the Heat Index (feels like temperature) based on the NOAA equation.
25
25
 
@@ -68,7 +68,7 @@ def _calculate_heat_index(temperature: float, humidity: int) -> float:
68
68
  return heat_index_celsius
69
69
 
70
70
 
71
- def _calculate_wind_chill(temperature: float, wind_speed: float) -> float | None:
71
+ def _calculate_wind_chill(*, temperature: float, wind_speed: float) -> float | None:
72
72
  """
73
73
  Calculate the Wind Chill (feels like temperature) based on NOAA.
74
74
 
@@ -84,7 +84,7 @@ def _calculate_wind_chill(temperature: float, wind_speed: float) -> float | None
84
84
  return float(13.12 + (0.6215 * temperature) - 11.37 * wind_speed**0.16 + 0.3965 * temperature * wind_speed**0.16)
85
85
 
86
86
 
87
- def calculate_vapor_concentration(temperature: float, humidity: int) -> float | None:
87
+ def calculate_vapor_concentration(*, temperature: float, humidity: int) -> float | None:
88
88
  """Calculate the vapor concentration."""
89
89
  try:
90
90
  abs_temperature = temperature + 273.15
@@ -105,7 +105,7 @@ def calculate_vapor_concentration(temperature: float, humidity: int) -> float |
105
105
  return None
106
106
 
107
107
 
108
- def calculate_apparent_temperature(temperature: float, humidity: int, wind_speed: float) -> float | None:
108
+ def calculate_apparent_temperature(*, temperature: float, humidity: int, wind_speed: float) -> float | None:
109
109
  """Calculate the apparent temperature based on NOAA."""
110
110
  try:
111
111
  if temperature <= 10 and wind_speed > 4.8:
@@ -130,7 +130,7 @@ def calculate_apparent_temperature(temperature: float, humidity: int, wind_speed
130
130
  return None
131
131
 
132
132
 
133
- def calculate_dew_point(temperature: float, humidity: int) -> float | None:
133
+ def calculate_dew_point(*, temperature: float, humidity: int) -> float | None:
134
134
  """Calculate the dew point."""
135
135
  try:
136
136
  a0 = 373.15 / (273.15 + temperature)
@@ -155,7 +155,7 @@ def calculate_dew_point(temperature: float, humidity: int) -> float | None:
155
155
  return None
156
156
 
157
157
 
158
- def calculate_frost_point(temperature: float, humidity: int) -> float | None:
158
+ def calculate_frost_point(*, temperature: float, humidity: int) -> float | None:
159
159
  """Calculate the frost point."""
160
160
  try:
161
161
  if (dewpoint := calculate_dew_point(temperature=temperature, humidity=humidity)) is None:
@@ -177,7 +177,7 @@ def calculate_frost_point(temperature: float, humidity: int) -> float | None:
177
177
 
178
178
 
179
179
  def calculate_operating_voltage_level(
180
- operating_voltage: float | None, low_bat_limit: float | None, voltage_max: float | None
180
+ *, operating_voltage: float | None, low_bat_limit: float | None, voltage_max: float | None
181
181
  ) -> float | None:
182
182
  """Return the operating voltage level."""
183
183
  if operating_voltage is None or low_bat_limit is None or voltage_max is None:
@@ -152,7 +152,7 @@ _LOGGER: Final = logging.getLogger(__name__)
152
152
 
153
153
 
154
154
  @inspector
155
- def create_custom_data_points(device: hmd.Device) -> None:
155
+ def create_custom_data_points(*, device: hmd.Device) -> None:
156
156
  """Decides which data point category should be used, and creates the required data points."""
157
157
 
158
158
  if device.ignore_for_custom_data_point:
@@ -163,7 +163,7 @@ def create_custom_data_points(device: hmd.Device) -> None:
163
163
  device.model,
164
164
  )
165
165
  return
166
- if data_point_definition_exists(device.model):
166
+ if data_point_definition_exists(model=device.model):
167
167
  _LOGGER.debug(
168
168
  "CREATE_CUSTOM_DATA_POINTS: Handling custom data point integration: %s, %s, %s",
169
169
  device.interface_id,
@@ -174,4 +174,4 @@ def create_custom_data_points(device: hmd.Device) -> None:
174
174
  # Call the custom creation function.
175
175
  for custom_config in get_custom_configs(model=device.model):
176
176
  for channel in device.channels.values():
177
- custom_config.make_ce_func(channel, custom_config)
177
+ custom_config.make_ce_func(channel=channel, custom_config=custom_config)
@@ -191,6 +191,7 @@ class BaseCustomDpClimate(CustomDataPoint):
191
191
 
192
192
  def __init__(
193
193
  self,
194
+ *,
194
195
  channel: hmd.Channel,
195
196
  unique_id: str,
196
197
  device_profile: DeviceProfile,
@@ -236,7 +237,7 @@ class BaseCustomDpClimate(CustomDataPoint):
236
237
  )
237
238
 
238
239
  @abstractmethod
239
- def _manu_temp_changed(self, data_point: GenericDataPoint) -> None:
240
+ def _manu_temp_changed(self, *, data_point: GenericDataPoint | None = None, **kwargs: Any) -> None:
240
241
  """Handle device state changes."""
241
242
 
242
243
  @state_property
@@ -354,6 +355,7 @@ class BaseCustomDpClimate(CustomDataPoint):
354
355
  @bind_collector()
355
356
  async def set_temperature(
356
357
  self,
358
+ *,
357
359
  temperature: float,
358
360
  collector: CallParameterCollector | None = None,
359
361
  do_validate: bool = True,
@@ -370,19 +372,19 @@ class BaseCustomDpClimate(CustomDataPoint):
370
372
  await self._dp_setpoint.send_value(value=temperature, collector=collector, do_validate=do_validate)
371
373
 
372
374
  @bind_collector()
373
- async def set_mode(self, mode: ClimateMode, collector: CallParameterCollector | None = None) -> None:
375
+ async def set_mode(self, *, mode: ClimateMode, collector: CallParameterCollector | None = None) -> None:
374
376
  """Set new target mode."""
375
377
 
376
378
  @bind_collector()
377
- async def set_profile(self, profile: ClimateProfile, collector: CallParameterCollector | None = None) -> None:
379
+ async def set_profile(self, *, profile: ClimateProfile, collector: CallParameterCollector | None = None) -> None:
378
380
  """Set new profile."""
379
381
 
380
382
  @inspector
381
- async def enable_away_mode_by_calendar(self, start: datetime, end: datetime, away_temperature: float) -> None:
383
+ async def enable_away_mode_by_calendar(self, *, start: datetime, end: datetime, away_temperature: float) -> None:
382
384
  """Enable the away mode by calendar on thermostat."""
383
385
 
384
386
  @inspector
385
- async def enable_away_mode_by_duration(self, hours: int, away_temperature: float) -> None:
387
+ async def enable_away_mode_by_duration(self, *, hours: int, away_temperature: float) -> None:
386
388
  """Enable the away mode by duration on thermostat."""
387
389
 
388
390
  @inspector
@@ -402,7 +404,7 @@ class BaseCustomDpClimate(CustomDataPoint):
402
404
  return super().is_state_change(**kwargs)
403
405
 
404
406
  @inspector
405
- async def copy_schedule(self, target_climate_data_point: BaseCustomDpClimate) -> None:
407
+ async def copy_schedule(self, *, target_climate_data_point: BaseCustomDpClimate) -> None:
406
408
  """Copy schedule to target device."""
407
409
 
408
410
  if self.schedule_profile_nos != target_climate_data_point.schedule_profile_nos:
@@ -417,6 +419,7 @@ class BaseCustomDpClimate(CustomDataPoint):
417
419
  @inspector
418
420
  async def copy_schedule_profile(
419
421
  self,
422
+ *,
420
423
  source_profile: ScheduleProfile,
421
424
  target_profile: ScheduleProfile,
422
425
  target_climate_data_point: BaseCustomDpClimate | None = None,
@@ -445,7 +448,7 @@ class BaseCustomDpClimate(CustomDataPoint):
445
448
  )
446
449
 
447
450
  @inspector
448
- async def get_schedule_profile(self, profile: ScheduleProfile) -> PROFILE_DICT:
451
+ async def get_schedule_profile(self, *, profile: ScheduleProfile) -> PROFILE_DICT:
449
452
  """Return a schedule by climate profile."""
450
453
  if not self._supports_schedule:
451
454
  raise ValidationException(f"Schedule is not supported by device {self._device.name}")
@@ -453,7 +456,7 @@ class BaseCustomDpClimate(CustomDataPoint):
453
456
  return schedule_data.get(profile, {})
454
457
 
455
458
  @inspector
456
- async def get_schedule_profile_weekday(self, profile: ScheduleProfile, weekday: ScheduleWeekday) -> WEEKDAY_DICT:
459
+ async def get_schedule_profile_weekday(self, *, profile: ScheduleProfile, weekday: ScheduleWeekday) -> WEEKDAY_DICT:
457
460
  """Return a schedule by climate profile."""
458
461
  if not self._supports_schedule:
459
462
  raise ValidationException(f"Schedule is not supported by device {self._device.name}")
@@ -474,7 +477,7 @@ class BaseCustomDpClimate(CustomDataPoint):
474
477
  return raw_schedule
475
478
 
476
479
  async def _get_schedule_profile(
477
- self, profile: ScheduleProfile | None = None, weekday: ScheduleWeekday | None = None
480
+ self, *, profile: ScheduleProfile | None = None, weekday: ScheduleWeekday | None = None
478
481
  ) -> _SCHEDULE_DICT:
479
482
  """Get the schedule."""
480
483
  schedule_data: _SCHEDULE_DICT = {}
@@ -506,7 +509,7 @@ class BaseCustomDpClimate(CustomDataPoint):
506
509
 
507
510
  @inspector
508
511
  async def set_schedule_profile(
509
- self, profile: ScheduleProfile, profile_data: PROFILE_DICT, do_validate: bool = True
512
+ self, *, profile: ScheduleProfile, profile_data: PROFILE_DICT, do_validate: bool = True
510
513
  ) -> None:
511
514
  """Set a profile to device."""
512
515
  await self._set_schedule_profile(
@@ -518,6 +521,7 @@ class BaseCustomDpClimate(CustomDataPoint):
518
521
 
519
522
  async def _set_schedule_profile(
520
523
  self,
524
+ *,
521
525
  target_channel_address: str,
522
526
  profile: ScheduleProfile,
523
527
  profile_data: PROFILE_DICT,
@@ -547,6 +551,7 @@ class BaseCustomDpClimate(CustomDataPoint):
547
551
  @inspector
548
552
  async def set_simple_schedule_profile(
549
553
  self,
554
+ *,
550
555
  profile: ScheduleProfile,
551
556
  base_temperature: float,
552
557
  simple_profile_data: SIMPLE_PROFILE_DICT,
@@ -560,6 +565,7 @@ class BaseCustomDpClimate(CustomDataPoint):
560
565
  @inspector
561
566
  async def set_schedule_profile_weekday(
562
567
  self,
568
+ *,
563
569
  profile: ScheduleProfile,
564
570
  weekday: ScheduleWeekday,
565
571
  weekday_data: WEEKDAY_DICT,
@@ -588,6 +594,7 @@ class BaseCustomDpClimate(CustomDataPoint):
588
594
  @inspector
589
595
  async def set_simple_schedule_profile_weekday(
590
596
  self,
597
+ *,
591
598
  profile: ScheduleProfile,
592
599
  weekday: ScheduleWeekday,
593
600
  base_temperature: float,
@@ -600,7 +607,7 @@ class BaseCustomDpClimate(CustomDataPoint):
600
607
  await self.set_schedule_profile_weekday(profile=profile, weekday=weekday, weekday_data=weekday_data)
601
608
 
602
609
  def _validate_and_convert_simple_to_profile(
603
- self, base_temperature: float, simple_profile_data: SIMPLE_PROFILE_DICT
610
+ self, *, base_temperature: float, simple_profile_data: SIMPLE_PROFILE_DICT
604
611
  ) -> PROFILE_DICT:
605
612
  """Convert simple profile dict to profile dict."""
606
613
  profile_dict: PROFILE_DICT = {}
@@ -611,7 +618,7 @@ class BaseCustomDpClimate(CustomDataPoint):
611
618
  return profile_dict
612
619
 
613
620
  def _validate_and_convert_simple_to_profile_weekday(
614
- self, base_temperature: float, simple_weekday_list: SIMPLE_WEEKDAY_LIST
621
+ self, *, base_temperature: float, simple_weekday_list: SIMPLE_WEEKDAY_LIST
615
622
  ) -> WEEKDAY_DICT:
616
623
  """Convert simple weekday list to weekday dict."""
617
624
  if not self.min_temp <= base_temperature <= self.max_temp:
@@ -632,12 +639,16 @@ class BaseCustomDpClimate(CustomDataPoint):
632
639
  if (temperature := slot.get(ScheduleSlotType.TEMPERATURE)) is None:
633
640
  raise ValidationException("VALIDATE_PROFILE: TEMPERATURE is missing.")
634
641
 
635
- if _convert_time_str_to_minutes(str(starttime)) >= _convert_time_str_to_minutes(str(endtime)):
642
+ if _convert_time_str_to_minutes(time_str=str(starttime)) >= _convert_time_str_to_minutes(
643
+ time_str=str(endtime)
644
+ ):
636
645
  raise ValidationException(
637
646
  f"VALIDATE_PROFILE: Start time {starttime} must lower than end time {endtime}"
638
647
  )
639
648
 
640
- if _convert_time_str_to_minutes(str(starttime)) < _convert_time_str_to_minutes(previous_endtime):
649
+ if _convert_time_str_to_minutes(time_str=str(starttime)) < _convert_time_str_to_minutes(
650
+ time_str=previous_endtime
651
+ ):
641
652
  raise ValidationException(
642
653
  f"VALIDATE_PROFILE: Timespans are overlapping with a previous slot for start time: {starttime} / end time: {endtime}"
643
654
  )
@@ -648,7 +659,9 @@ class BaseCustomDpClimate(CustomDataPoint):
648
659
  f"max: {self.max_temp}) for start time: {starttime} / end time: {endtime}"
649
660
  )
650
661
 
651
- if _convert_time_str_to_minutes(str(starttime)) > _convert_time_str_to_minutes(previous_endtime):
662
+ if _convert_time_str_to_minutes(time_str=str(starttime)) > _convert_time_str_to_minutes(
663
+ time_str=previous_endtime
664
+ ):
652
665
  weekday_data[slot_no] = {
653
666
  ScheduleSlotType.ENDTIME: starttime,
654
667
  ScheduleSlotType.TEMPERATURE: base_temperature,
@@ -664,13 +677,14 @@ class BaseCustomDpClimate(CustomDataPoint):
664
677
 
665
678
  return _fillup_weekday_data(base_temperature=base_temperature, weekday_data=weekday_data)
666
679
 
667
- def _validate_schedule_profile(self, profile: ScheduleProfile, profile_data: PROFILE_DICT) -> None:
680
+ def _validate_schedule_profile(self, *, profile: ScheduleProfile, profile_data: PROFILE_DICT) -> None:
668
681
  """Validate the profile."""
669
682
  for weekday, weekday_data in profile_data.items():
670
683
  self._validate_schedule_profile_weekday(profile=profile, weekday=weekday, weekday_data=weekday_data)
671
684
 
672
685
  def _validate_schedule_profile_weekday(
673
686
  self,
687
+ *,
674
688
  profile: ScheduleProfile,
675
689
  weekday: ScheduleWeekday,
676
690
  weekday_data: WEEKDAY_DICT,
@@ -720,7 +734,7 @@ class CustomDpSimpleRfThermostat(BaseCustomDpClimate):
720
734
 
721
735
  __slots__ = ()
722
736
 
723
- def _manu_temp_changed(self, data_point: GenericDataPoint) -> None:
737
+ def _manu_temp_changed(self, *, data_point: GenericDataPoint | None = None, **kwargs: Any) -> None:
724
738
  """Handle device state changes."""
725
739
 
726
740
 
@@ -741,6 +755,7 @@ class CustomDpRfThermostat(BaseCustomDpClimate):
741
755
 
742
756
  def __init__(
743
757
  self,
758
+ *,
744
759
  channel: hmd.Channel,
745
760
  unique_id: str,
746
761
  device_profile: DeviceProfile,
@@ -788,7 +803,7 @@ class CustomDpRfThermostat(BaseCustomDpClimate):
788
803
  )
789
804
  )
790
805
 
791
- def _manu_temp_changed(self, data_point: GenericDataPoint) -> None:
806
+ def _manu_temp_changed(self, *, data_point: GenericDataPoint | None = None, **kwargs: Any) -> None:
792
807
  """Handle device state changes."""
793
808
  if (
794
809
  data_point == self._dp_control_mode
@@ -861,7 +876,7 @@ class CustomDpRfThermostat(BaseCustomDpClimate):
861
876
  return self._dp_temperature_offset.value
862
877
 
863
878
  @bind_collector()
864
- async def set_mode(self, mode: ClimateMode, collector: CallParameterCollector | None = None) -> None:
879
+ async def set_mode(self, *, mode: ClimateMode, collector: CallParameterCollector | None = None) -> None:
865
880
  """Set new mode."""
866
881
  if not self.is_state_change(mode=mode):
867
882
  return
@@ -876,7 +891,7 @@ class CustomDpRfThermostat(BaseCustomDpClimate):
876
891
  await self.set_temperature(temperature=_OFF_TEMPERATURE, collector=collector, do_validate=False)
877
892
 
878
893
  @bind_collector()
879
- async def set_profile(self, profile: ClimateProfile, collector: CallParameterCollector | None = None) -> None:
894
+ async def set_profile(self, *, profile: ClimateProfile, collector: CallParameterCollector | None = None) -> None:
880
895
  """Set new profile."""
881
896
  if not self.is_state_change(profile=profile):
882
897
  return
@@ -896,7 +911,7 @@ class CustomDpRfThermostat(BaseCustomDpClimate):
896
911
  )
897
912
 
898
913
  @inspector
899
- async def enable_away_mode_by_calendar(self, start: datetime, end: datetime, away_temperature: float) -> None:
914
+ async def enable_away_mode_by_calendar(self, *, start: datetime, end: datetime, away_temperature: float) -> None:
900
915
  """Enable the away mode by calendar on thermostat."""
901
916
  await self._client.set_value(
902
917
  channel_address=self._channel.address,
@@ -906,7 +921,7 @@ class CustomDpRfThermostat(BaseCustomDpClimate):
906
921
  )
907
922
 
908
923
  @inspector
909
- async def enable_away_mode_by_duration(self, hours: int, away_temperature: float) -> None:
924
+ async def enable_away_mode_by_duration(self, *, hours: int, away_temperature: float) -> None:
910
925
  """Enable the away mode by duration on thermostat."""
911
926
  start = datetime.now() - timedelta(minutes=10)
912
927
  end = datetime.now() + timedelta(hours=hours)
@@ -954,7 +969,7 @@ class CustomDpRfThermostat(BaseCustomDpClimate):
954
969
  return profiles
955
970
 
956
971
 
957
- def _party_mode_code(start: datetime, end: datetime, away_temperature: float) -> str:
972
+ def _party_mode_code(*, start: datetime, end: datetime, away_temperature: float) -> str:
958
973
  """
959
974
  Create the party mode code.
960
975
 
@@ -983,6 +998,7 @@ class CustomDpIpThermostat(BaseCustomDpClimate):
983
998
 
984
999
  def __init__(
985
1000
  self,
1001
+ *,
986
1002
  channel: hmd.Channel,
987
1003
  unique_id: str,
988
1004
  device_profile: DeviceProfile,
@@ -1032,7 +1048,7 @@ class CustomDpIpThermostat(BaseCustomDpClimate):
1032
1048
  )
1033
1049
  )
1034
1050
 
1035
- def _manu_temp_changed(self, data_point: GenericDataPoint) -> None:
1051
+ def _manu_temp_changed(self, *, data_point: GenericDataPoint | None = None, **kwargs: Any) -> None:
1036
1052
  """Handle device state changes."""
1037
1053
  if (
1038
1054
  data_point == self._dp_set_point_mode
@@ -1135,7 +1151,7 @@ class CustomDpIpThermostat(BaseCustomDpClimate):
1135
1151
  return self._dp_temperature_offset.value
1136
1152
 
1137
1153
  @bind_collector()
1138
- async def set_mode(self, mode: ClimateMode, collector: CallParameterCollector | None = None) -> None:
1154
+ async def set_mode(self, *, mode: ClimateMode, collector: CallParameterCollector | None = None) -> None:
1139
1155
  """Set new target mode."""
1140
1156
  if not self.is_state_change(mode=mode):
1141
1157
  return
@@ -1153,7 +1169,7 @@ class CustomDpIpThermostat(BaseCustomDpClimate):
1153
1169
  await self.set_temperature(temperature=_OFF_TEMPERATURE, collector=collector, do_validate=False)
1154
1170
 
1155
1171
  @bind_collector()
1156
- async def set_profile(self, profile: ClimateProfile, collector: CallParameterCollector | None = None) -> None:
1172
+ async def set_profile(self, *, profile: ClimateProfile, collector: CallParameterCollector | None = None) -> None:
1157
1173
  """Set new control mode."""
1158
1174
  if not self.is_state_change(profile=profile):
1159
1175
  return
@@ -1169,7 +1185,7 @@ class CustomDpIpThermostat(BaseCustomDpClimate):
1169
1185
  await self._dp_active_profile.send_value(value=profile_idx, collector=collector)
1170
1186
 
1171
1187
  @inspector
1172
- async def enable_away_mode_by_calendar(self, start: datetime, end: datetime, away_temperature: float) -> None:
1188
+ async def enable_away_mode_by_calendar(self, *, start: datetime, end: datetime, away_temperature: float) -> None:
1173
1189
  """Enable the away mode by calendar on thermostat."""
1174
1190
  await self._client.put_paramset(
1175
1191
  channel_address=self._channel.address,
@@ -1183,7 +1199,7 @@ class CustomDpIpThermostat(BaseCustomDpClimate):
1183
1199
  )
1184
1200
 
1185
1201
  @inspector
1186
- async def enable_away_mode_by_duration(self, hours: int, away_temperature: float) -> None:
1202
+ async def enable_away_mode_by_duration(self, *, hours: int, away_temperature: float) -> None:
1187
1203
  """Enable the away mode by duration on thermostat."""
1188
1204
  start = datetime.now() - timedelta(minutes=10)
1189
1205
  end = datetime.now() + timedelta(hours=hours)
@@ -1243,7 +1259,7 @@ def _convert_minutes_to_time_str(minutes: Any) -> str:
1243
1259
  return time_str
1244
1260
 
1245
1261
 
1246
- def _convert_time_str_to_minutes(time_str: str) -> int:
1262
+ def _convert_time_str_to_minutes(*, time_str: str) -> int:
1247
1263
  """Convert minutes to a time string."""
1248
1264
  if SCHEDULER_TIME_PATTERN.match(time_str) is None:
1249
1265
  raise ValidationException(
@@ -1256,17 +1272,18 @@ def _convert_time_str_to_minutes(time_str: str) -> int:
1256
1272
  raise ValidationException(f"Failed to convert time {time_str}. Format must be hh:mm.") from exc
1257
1273
 
1258
1274
 
1259
- def _sort_simple_weekday_list(simple_weekday_list: SIMPLE_WEEKDAY_LIST) -> SIMPLE_WEEKDAY_LIST:
1275
+ def _sort_simple_weekday_list(*, simple_weekday_list: SIMPLE_WEEKDAY_LIST) -> SIMPLE_WEEKDAY_LIST:
1260
1276
  """Sort simple weekday list."""
1261
1277
  simple_weekday_dict = sorted(
1262
1278
  {
1263
- _convert_time_str_to_minutes(str(slot[ScheduleSlotType.STARTTIME])): slot for slot in simple_weekday_list
1279
+ _convert_time_str_to_minutes(time_str=str(slot[ScheduleSlotType.STARTTIME])): slot
1280
+ for slot in simple_weekday_list
1264
1281
  }.items()
1265
1282
  )
1266
1283
  return [slot[1] for slot in simple_weekday_dict]
1267
1284
 
1268
1285
 
1269
- def _fillup_weekday_data(base_temperature: float, weekday_data: WEEKDAY_DICT) -> WEEKDAY_DICT:
1286
+ def _fillup_weekday_data(*, base_temperature: float, weekday_data: WEEKDAY_DICT) -> WEEKDAY_DICT:
1270
1287
  """Fillup weekday data."""
1271
1288
  for slot_no in SCHEDULE_SLOT_IN_RANGE:
1272
1289
  if slot_no not in weekday_data:
@@ -1278,7 +1295,7 @@ def _fillup_weekday_data(base_temperature: float, weekday_data: WEEKDAY_DICT) ->
1278
1295
  return weekday_data
1279
1296
 
1280
1297
 
1281
- def _get_raw_schedule_paramset(schedule_data: _SCHEDULE_DICT) -> _RAW_SCHEDULE_DICT:
1298
+ def _get_raw_schedule_paramset(*, schedule_data: _SCHEDULE_DICT) -> _RAW_SCHEDULE_DICT:
1282
1299
  """Return the raw paramset."""
1283
1300
  raw_paramset: _RAW_SCHEDULE_DICT = {}
1284
1301
  for profile, profile_data in schedule_data.items():
@@ -1290,12 +1307,13 @@ def _get_raw_schedule_paramset(schedule_data: _SCHEDULE_DICT) -> _RAW_SCHEDULE_D
1290
1307
  raise ValidationException(f"Not a valid profile name: {raw_profile_name}")
1291
1308
  raw_value: float | int = cast(float | int, slot_value)
1292
1309
  if slot_type == ScheduleSlotType.ENDTIME and isinstance(slot_value, str):
1293
- raw_value = _convert_time_str_to_minutes(slot_value)
1310
+ raw_value = _convert_time_str_to_minutes(time_str=slot_value)
1294
1311
  raw_paramset[raw_profile_name] = raw_value
1295
1312
  return raw_paramset
1296
1313
 
1297
1314
 
1298
1315
  def _add_to_schedule_data(
1316
+ *,
1299
1317
  schedule_data: _SCHEDULE_DICT,
1300
1318
  profile: ScheduleProfile,
1301
1319
  weekday: ScheduleWeekday,
@@ -1317,6 +1335,7 @@ def _add_to_schedule_data(
1317
1335
 
1318
1336
 
1319
1337
  def make_simple_thermostat(
1338
+ *,
1320
1339
  channel: hmd.Channel,
1321
1340
  custom_config: CustomConfig,
1322
1341
  ) -> None:
@@ -1330,6 +1349,7 @@ def make_simple_thermostat(
1330
1349
 
1331
1350
 
1332
1351
  def make_thermostat(
1352
+ *,
1333
1353
  channel: hmd.Channel,
1334
1354
  custom_config: CustomConfig,
1335
1355
  ) -> None:
@@ -1343,6 +1363,7 @@ def make_thermostat(
1343
1363
 
1344
1364
 
1345
1365
  def make_thermostat_group(
1366
+ *,
1346
1367
  channel: hmd.Channel,
1347
1368
  custom_config: CustomConfig,
1348
1369
  ) -> None:
@@ -1356,6 +1377,7 @@ def make_thermostat_group(
1356
1377
 
1357
1378
 
1358
1379
  def make_ip_thermostat(
1380
+ *,
1359
1381
  channel: hmd.Channel,
1360
1382
  custom_config: CustomConfig,
1361
1383
  ) -> None:
@@ -1369,6 +1391,7 @@ def make_ip_thermostat(
1369
1391
 
1370
1392
 
1371
1393
  def make_ip_thermostat_group(
1394
+ *,
1372
1395
  channel: hmd.Channel,
1373
1396
  custom_config: CustomConfig,
1374
1397
  ) -> None: