pydiagral 1.5.1b1__tar.gz → 1.6.0__tar.gz

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.
Files changed (42) hide show
  1. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/.github/workflows/labeler.yml +1 -1
  2. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/CHANGELOG.md +28 -0
  3. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/PKG-INFO +1 -1
  4. pydiagral-1.6.0/docs/how-to-find-diagral-serial.png +0 -0
  5. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/example_code.py +7 -7
  6. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/src/pydiagral/api.py +12 -10
  7. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/src/pydiagral/models.py +20 -23
  8. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/tests/data/configuration_sample.json +3 -3
  9. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/tests/test_pydiagral_api.py +1 -1
  10. pydiagral-1.5.1b1/docs/how-to-find-diagral-serial.png +0 -0
  11. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/.devcontainer/Dockerfile.dev +0 -0
  12. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/.devcontainer/devcontainer.json +0 -0
  13. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/.github/FUNDING.yml +0 -0
  14. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
  15. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
  16. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/.github/copilot-commit-message-instructions.md +0 -0
  17. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/.github/dependabot.yml +0 -0
  18. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/.github/labels.yml +0 -0
  19. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/.github/workflows/lint.yaml +0 -0
  20. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/.github/workflows/lock.yml +0 -0
  21. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/.github/workflows/pytest.yaml +0 -0
  22. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/.github/workflows/release_and_doc.yaml +0 -0
  23. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/.github/workflows/semantic-prs.yml +0 -0
  24. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/.gitignore +0 -0
  25. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/.releaserc +0 -0
  26. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/.vscode/extensions.json +0 -0
  27. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/.vscode/settings.json +0 -0
  28. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/LICENSE +0 -0
  29. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/README.md +0 -0
  30. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/docs/api.md +0 -0
  31. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/docs/exceptions.md +0 -0
  32. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/docs/index.md +0 -0
  33. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/docs/models.md +0 -0
  34. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/docs/pydiagral-Logo.png +0 -0
  35. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/mkdocs.yml +0 -0
  36. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/pyproject.toml +0 -0
  37. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/src/pydiagral/__init__.py +0 -0
  38. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/src/pydiagral/constants.py +0 -0
  39. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/src/pydiagral/exceptions.py +0 -0
  40. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/src/pydiagral/utils.py +0 -0
  41. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/tests/__init__.py +0 -0
  42. {pydiagral-1.5.1b1 → pydiagral-1.6.0}/tests/data/system_details_sample.json +0 -0
@@ -16,6 +16,6 @@ jobs:
16
16
  uses: actions/checkout@v4
17
17
 
18
18
  - name: Run Labeler
19
- uses: crazy-max/ghaction-github-labeler@v5.2.0
19
+ uses: crazy-max/ghaction-github-labeler@v5.3.0
20
20
  with:
21
21
  skip-delete: true
@@ -1,3 +1,31 @@
1
+ # [1.6.0](https://github.com/mguyard/pydiagral/compare/v1.5.2...v1.6.0) (2025-05-02)
2
+
3
+
4
+ ### Features
5
+
6
+ * **api:** ✨ Change `pincode` type from `int` to `str` in `DiagralAPI` ([d5e8afe](https://github.com/mguyard/pydiagral/commit/d5e8afe47c727202b91b9dbd24ac3b60762cfa16))
7
+
8
+ # [1.6.0-beta.1](https://github.com/mguyard/pydiagral/compare/v1.5.2...v1.6.0-beta.1) (2025-04-01)
9
+
10
+
11
+ ### Features
12
+
13
+ * **api:** ✨ Change `pincode` type from `int` to `str` in `DiagralAPI` ([d5e8afe](https://github.com/mguyard/pydiagral/commit/d5e8afe47c727202b91b9dbd24ac3b60762cfa16))
14
+
15
+ ## [1.5.2](https://github.com/mguyard/pydiagral/compare/v1.5.1...v1.5.2) (2025-03-22)
16
+
17
+
18
+ ### Bug Fixes
19
+
20
+ * **models:** ✨ Rename fields in `AlarmConfiguration` following Diagral changes ([3a56923](https://github.com/mguyard/pydiagral/commit/3a56923c553d5d4d31508e64c55ada64c3126ba0))
21
+
22
+ ## [1.5.1](https://github.com/mguyard/pydiagral/compare/v1.5.0...v1.5.1) (2025-03-09)
23
+
24
+
25
+ ### Bug Fixes
26
+
27
+ * **models:** 🐛 Allow `username` and `user_type` to be optional ([d0f173c](https://github.com/mguyard/pydiagral/commit/d0f173cae4377cded21a7f4a6bc9ca0d13035df5))
28
+
1
29
  ## [1.5.1-beta.1](https://github.com/mguyard/pydiagral/compare/v1.5.0...v1.5.1-beta.1) (2025-03-09)
2
30
 
3
31
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pydiagral
3
- Version: 1.5.1b1
3
+ Version: 1.6.0
4
4
  Summary: A Python library for interacting with Diagral systems
5
5
  Project-URL: Homepage, https://github.com/mguyard/pydiagral
6
6
  Project-URL: Documentation, https://github.com/mguyard/pydiagral
@@ -35,12 +35,12 @@ _LOGGER: logging.Logger = logging.getLogger(__name__)
35
35
  # PIN_CODE=your_pin_code
36
36
  # WEBHOOK_URL=your_webhook_url
37
37
  # LOG_LEVEL=INFO
38
- USERNAME: str | None = os.getenv("USERNAME")
39
- PASSWORD: str | None = os.getenv("PASSWORD")
40
- SERIAL_ID: str | None = os.getenv("SERIAL_ID")
38
+ USERNAME: str = os.getenv("USERNAME")
39
+ PASSWORD: str = os.getenv("PASSWORD")
40
+ SERIAL_ID: str = os.getenv("SERIAL_ID")
41
41
  API_KEY: str | None = os.getenv("API_KEY") # Optional
42
42
  SECRET_KEY: str | None = os.getenv("SECRET_KEY") # Optional
43
- PIN_CODE = int(os.getenv("PIN_CODE")) # Optional
43
+ PIN_CODE: str | None = str(os.getenv("PIN_CODE")) # Optional
44
44
  WEBHOOK_URL: str | None = os.getenv("WEBHOOK_URL") # Optional
45
45
 
46
46
  ######################################## CUSTOMIZE THE TESTS ########################################
@@ -50,9 +50,9 @@ TRY_CONNECTION_WITH_KEYS = False
50
50
  TRY_CONNECTION_WITHOUT_KEYS = False
51
51
  TRY_CONNECTION_WITH_KEYS_EPHEMERAL = False
52
52
  TRY_CONNECTION_WITHOUT_KEYS_EPHEMERAL = False
53
- APIKEY_CREATION = False
54
- APIKEY_DELETION = False
55
- LIST_GROUPS = False
53
+ APIKEY_CREATION = True
54
+ APIKEY_DELETION = True
55
+ LIST_GROUPS = True
56
56
  LIST_SYSTEM_DETAILS = False
57
57
  LIST_SYSTEM_STATUS = False
58
58
  LIST_SYSTEM_CONFIGURATION = False
@@ -63,7 +63,7 @@ class DiagralAPI:
63
63
  serial_id: str,
64
64
  apikey: str | None = None,
65
65
  secret_key: str | None = None,
66
- pincode: int | None = None,
66
+ pincode: str | None = None,
67
67
  ) -> None:
68
68
  """Initialize the DiagralAPI instance.
69
69
 
@@ -73,7 +73,7 @@ class DiagralAPI:
73
73
  serial_id (str): The serial ID of the Diagral system.
74
74
  apikey (str | None, optional): The API key for additional authentication. Defaults to None.
75
75
  secret_key (str | None, optional): The secret key for additional authentication. Defaults to None.
76
- pincode (int | None, optional): The PIN code for the Diagral system. Defaults to None.
76
+ pincode (str | None, optional): The PIN code for the Diagral system. Defaults to None.
77
77
 
78
78
  Raises:
79
79
  ConfigurationError: If any required field is empty or invalid.
@@ -104,9 +104,11 @@ class DiagralAPI:
104
104
 
105
105
  # Validate pincode
106
106
  if pincode is not None:
107
- if not isinstance(pincode, int):
108
- raise ConfigurationError("pincode must be an integer")
109
- self.__pincode: int | None = pincode
107
+ if not isinstance(pincode, str) or (
108
+ isinstance(pincode, str) and not pincode.isdigit()
109
+ ):
110
+ raise ConfigurationError("pincode must be an string of digits")
111
+ self.__pincode: str | None = pincode
110
112
 
111
113
  # Initialize session and access_token
112
114
  self.session: aiohttp.ClientSession | None = None
@@ -597,7 +599,7 @@ class DiagralAPI:
597
599
  )
598
600
 
599
601
  _HEADERS: dict[str, str] = {
600
- "X-PIN-CODE": str(self.__pincode),
602
+ "X-PIN-CODE": self.__pincode,
601
603
  "X-HMAC": _HMAC,
602
604
  "X-TIMESTAMP": _TIMESTAMP,
603
605
  "X-APIKEY": self.__apikey,
@@ -640,7 +642,7 @@ class DiagralAPI:
640
642
  )
641
643
 
642
644
  _HEADERS: dict[str, str] = {
643
- "X-PIN-CODE": str(self.__pincode),
645
+ "X-PIN-CODE": self.__pincode,
644
646
  "X-HMAC": _HMAC,
645
647
  "X-TIMESTAMP": _TIMESTAMP,
646
648
  "X-APIKEY": self.__apikey,
@@ -694,7 +696,7 @@ class DiagralAPI:
694
696
  )
695
697
 
696
698
  _HEADERS: dict[str, str] = {
697
- "X-PIN-CODE": str(self.__pincode),
699
+ "X-PIN-CODE": self.__pincode,
698
700
  "X-HMAC": _HMAC,
699
701
  "X-TIMESTAMP": _TIMESTAMP,
700
702
  "X-APIKEY": self.__apikey,
@@ -829,7 +831,7 @@ class DiagralAPI:
829
831
  )
830
832
 
831
833
  _HEADERS: dict[str, str] = {
832
- "X-PIN-CODE": str(self.__pincode),
834
+ "X-PIN-CODE": self.__pincode,
833
835
  "X-HMAC": _HMAC,
834
836
  "X-TIMESTAMP": _TIMESTAMP,
835
837
  "X-APIKEY": self.__apikey,
@@ -936,7 +938,7 @@ class DiagralAPI:
936
938
  )
937
939
 
938
940
  _HEADERS: dict[str, str] = {
939
- "X-PIN-CODE": str(self.__pincode),
941
+ "X-PIN-CODE": self.__pincode,
940
942
  "X-HMAC": _HMAC,
941
943
  "X-TIMESTAMP": _TIMESTAMP,
942
944
  "X-APIKEY": self.__apikey,
@@ -13,7 +13,7 @@ from datetime import datetime, timezone
13
13
  import logging
14
14
  import re
15
15
  import types
16
- from typing import TypeVar, Union, get_args, get_origin, get_type_hints
16
+ from typing import Self, Union, get_args, get_origin, get_type_hints
17
17
 
18
18
  logger: logging.Logger = logging.getLogger(__name__)
19
19
 
@@ -54,9 +54,6 @@ class CamelCaseModel:
54
54
 
55
55
  """
56
56
 
57
- # Type variable for the class itself
58
- T = TypeVar("T", bound="CamelCaseModel")
59
-
60
57
  def to_dict(self) -> dict:
61
58
  """Convert the instance attributes to a dictionary, transforming attribute names.
62
59
 
@@ -90,7 +87,7 @@ class CamelCaseModel:
90
87
  return result
91
88
 
92
89
  @classmethod
93
- def _from_dict_recursive(cls: type[T], data: dict, target_cls: type[T]) -> T:
90
+ def _from_dict_recursive(cls, data: dict, target_cls: type[Self]) -> Self:
94
91
  """Recursively converts a dictionary to an instance of the specified target class.
95
92
 
96
93
  This method handles nested dictionaries and lists, converting them to the appropriate
@@ -98,12 +95,12 @@ class CamelCaseModel:
98
95
  by handling `Union` types and removing `None` from the type hints.
99
96
 
100
97
  Args:
101
- cls (type[T]): The class that this method is a part of.
98
+ cls (type[Self]): The class that this method is a part of.
102
99
  data (dict): The dictionary to convert.
103
- target_cls (type[T]): The target class to convert the dictionary to.
100
+ target_cls (type[Self]): The target class to convert the dictionary to.
104
101
 
105
102
  Returns:
106
- T: An instance of the target class populated with the data from the dictionary.
103
+ An instance of the target class populated with the data from the dictionary.
107
104
 
108
105
  Raises:
109
106
  TypeError: If the target class cannot be instantiated with the provided data.
@@ -187,15 +184,15 @@ class CamelCaseModel:
187
184
  return target_cls(**init_values)
188
185
 
189
186
  @classmethod
190
- def from_dict(cls: type[T], data: dict) -> T:
187
+ def from_dict(cls, data: dict) -> Self:
191
188
  """Create an instance of the class from a dictionary.
192
189
 
193
190
  Args:
194
- cls (type[T]): The class type to instantiate.
191
+ cls (type[Self]): The class type to instantiate.
195
192
  data (dict): The dictionary containing the data to populate the instance.
196
193
 
197
194
  Returns:
198
- T: An instance of the class populated with the data from the dictionary.
195
+ An instance of the class populated with the data from the dictionary.
199
196
 
200
197
  Example:
201
198
  >>> data = {"diagral_id": 123, "user_id": 456, "access_token": "abc123"}
@@ -830,11 +827,11 @@ class AlarmConfiguration(CamelCaseModel):
830
827
  reading_date (datetime | None): The date when the configuration was read, aliased as "readingDate".
831
828
  transceivers (list[TransceiverModel] | None): A list of transceiver models.
832
829
  transmitters (list[TransmitterModel] | None): A list of transmitter models.
833
- grp_marche_presence (list[int] | None): A list of group marche presence, aliased as "grpMarchePresence".
830
+ presence_group (list[int] | None): A list of group marche presence, aliased as "presenceGroup".
834
831
  installation_state (int | None): The state of the installation, aliased as "installationState".
835
832
  central_information (CentralInformation | None): Information about the central unit, aliased as "centralInformation".
836
- grp_marche_partielle1 (list[int] | None): A list of group marche partielle 1, aliased as "grpMarchePartielle1".
837
- grp_marche_partielle2 (list[int] | None): A list of group marche partielle 2, aliased as "grpMarchePartielle2".
833
+ partial_group1 (list[int] | None): A list of group marche partielle 1, aliased as "partialGroup1".
834
+ partial_group2 (list[int] | None): A list of group marche partielle 2, aliased as "partialGroup2".
838
835
 
839
836
  Example:
840
837
  >>> alarm_config = AlarmConfiguration(
@@ -847,11 +844,11 @@ class AlarmConfiguration(CamelCaseModel):
847
844
  ... reading_date=datetime(2023, 10, 1),
848
845
  ... transceivers=[TransceiverModel(uid="11223", type=5)],
849
846
  ... transmitters=[TransmitterModel(uid="44556", type=6)],
850
- ... grp_marche_presence=[1, 2, 3],
847
+ ... presence_group=[1, 2, 3],
851
848
  ... installation_state=1,
852
849
  ... central_information=CentralInformation(has_plug=True),
853
- ... grp_marche_partielle1=[4, 5, 6],
854
- ... grp_marche_partielle2=[7, 8, 9]
850
+ ... partial_group1=[4, 5, 6],
851
+ ... partial_group2=[7, 8, 9]
855
852
  ... )
856
853
  >>> print(alarm_config.alarm.name)
857
854
  Home Alarm
@@ -870,8 +867,8 @@ class AlarmConfiguration(CamelCaseModel):
870
867
  )
871
868
  transceivers: list[TransceiverModel] | None = None
872
869
  transmitters: list[TransmitterModel] | None = None
873
- grp_marche_presence: list[int] | None = field(
874
- default=None, metadata={"alias": "grpMarchePresence"}
870
+ presence_group: list[int] | None = field(
871
+ default=None, metadata={"alias": "presenceGroup"}
875
872
  )
876
873
  installation_state: int | None = field(
877
874
  default=None, metadata={"alias": "installationState"}
@@ -879,11 +876,11 @@ class AlarmConfiguration(CamelCaseModel):
879
876
  central_information: CentralInformation | None = field(
880
877
  default=None, metadata={"alias": "centralInformation"}
881
878
  )
882
- grp_marche_partielle1: list[int] | None = field(
883
- default=None, metadata={"alias": "grpMarchePartielle1"}
879
+ partial_group1: list[int] | None = field(
880
+ default=None, metadata={"alias": "partialGroup1"}
884
881
  )
885
- grp_marche_partielle2: list[int] | None = field(
886
- default=None, metadata={"alias": "grpMarchePartielle2"}
882
+ partial_group2: list[int] | None = field(
883
+ default=None, metadata={"alias": "partialGroup2"}
887
884
  )
888
885
 
889
886
 
@@ -323,7 +323,7 @@
323
323
  "canInhibit": false
324
324
  }
325
325
  ],
326
- "grpMarchePresence": [
326
+ "presenceGroup": [
327
327
  1,
328
328
  2,
329
329
  4
@@ -345,10 +345,10 @@
345
345
  "canInhibit": false,
346
346
  "parameterGsmSaved": false
347
347
  },
348
- "grpMarchePartielle1": [
348
+ "partialGroup1": [
349
349
  1
350
350
  ],
351
- "grpMarchePartielle2": [
351
+ "partialGroup2": [
352
352
  2
353
353
  ]
354
354
  }
@@ -45,7 +45,7 @@ PASSWORD = "test_password"
45
45
  SERIAL_ID = "test_serial_id"
46
46
  API_KEY = "test_api_key"
47
47
  SECRET_KEY = "test_secret_key"
48
- PIN_CODE = 1234
48
+ PIN_CODE = "1234"
49
49
  FAKE_TOKEN = "test_fake_token"
50
50
  WEBHOOK_URL = "https://hook.example.com/webhook"
51
51
 
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes