wizata-dsapi 2.0.0.dev4__tar.gz → 2.0.0.dev6__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 (60) hide show
  1. {wizata_dsapi-2.0.0.dev4/wizata_dsapi.egg-info → wizata_dsapi-2.0.0.dev6}/PKG-INFO +1 -1
  2. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/__init__.py +2 -1
  3. wizata_dsapi-2.0.0.dev6/wizata_dsapi/mobile_asset.py +220 -0
  4. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/twin.py +26 -7
  5. wizata_dsapi-2.0.0.dev6/wizata_dsapi/version.py +1 -0
  6. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/wizata_dsapi_client.py +137 -61
  7. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6/wizata_dsapi.egg-info}/PKG-INFO +1 -1
  8. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi.egg-info/SOURCES.txt +1 -0
  9. wizata_dsapi-2.0.0.dev4/wizata_dsapi/version.py +0 -1
  10. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/LICENSE.txt +0 -0
  11. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/README.rst +0 -0
  12. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/setup.cfg +0 -0
  13. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/setup.py +0 -0
  14. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/api_config.py +0 -0
  15. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/api_dto.py +0 -0
  16. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/api_interface.py +0 -0
  17. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/bucket.py +0 -0
  18. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/business_label.py +0 -0
  19. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/context.py +0 -0
  20. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/dashboard.py +0 -0
  21. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/dataframe_toolkit.py +0 -0
  22. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/datapoint.py +0 -0
  23. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/datastore.py +0 -0
  24. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/ds_dataframe.py +0 -0
  25. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/dsapi_json_encoder.py +0 -0
  26. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/edge_device.py +0 -0
  27. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/evaluation.py +0 -0
  28. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/execution.py +0 -0
  29. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/execution_log.py +0 -0
  30. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/experiment.py +0 -0
  31. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/group_system.py +0 -0
  32. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/ilogger.py +0 -0
  33. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/insight.py +0 -0
  34. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/mlmodel.py +0 -0
  35. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/model_toolkit.py +0 -0
  36. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/models/__init__.py +0 -0
  37. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/models/common.py +0 -0
  38. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/notification.py +0 -0
  39. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/paged_query_result.py +0 -0
  40. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/pipeline.py +0 -0
  41. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/pipeline_image.py +0 -0
  42. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/plot.py +0 -0
  43. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/plots/__init__.py +0 -0
  44. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/plots/common.py +0 -0
  45. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/request.py +0 -0
  46. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/script.py +0 -0
  47. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/scripts/__init__.py +0 -0
  48. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/scripts/common.py +0 -0
  49. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/search.py +0 -0
  50. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/solution_component.py +0 -0
  51. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/streamlit_utils.py +0 -0
  52. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/template.py +0 -0
  53. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/trigger.py +0 -0
  54. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/twinregistration.py +0 -0
  55. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/wizard_function.py +0 -0
  56. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/wizard_request.py +0 -0
  57. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi/words.py +0 -0
  58. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi.egg-info/dependency_links.txt +0 -0
  59. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi.egg-info/requires.txt +0 -0
  60. {wizata_dsapi-2.0.0.dev4 → wizata_dsapi-2.0.0.dev6}/wizata_dsapi.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wizata_dsapi
3
- Version: 2.0.0.dev4
3
+ Version: 2.0.0.dev6
4
4
  Summary: Wizata Data Science Toolkit
5
5
  Author: Wizata S.A.
6
6
  Author-email: info@wizata.com
@@ -52,4 +52,5 @@ from .streamlit_utils import (get_streamlit_token, get_streamlit_domain, get_str
52
52
  from .search import FilterOperator, SearchQuery, SortOption, GroupSearchQuery
53
53
  from .notification import NotificationScope, DeviceToken, AlertRule, AlertActive
54
54
  from .edge_device import EdgeDevice, EdgeDeviceStatus, EdgeDeviceType
55
- from .dashboard import Dashboard, DashboardType
55
+ from .dashboard import Dashboard, DashboardType
56
+ from .mobile_asset import MobileAssetTile, MobileAssetTileType, MobileAssetConfig
@@ -0,0 +1,220 @@
1
+ """
2
+ Mobile asset DTOs for tile and config persistence.
3
+
4
+ MobileAssetTileType — tile visualization type:
5
+ - SENSOR: single datapoint live value
6
+ - CHART: time-series chart
7
+ - TABLE: tabular data view
8
+ - POLAR: polar/radar chart
9
+ - EVENT: event timeline
10
+
11
+ MobileAssetTile — individual tile configuration scoped to a template
12
+ or a specific twin.
13
+
14
+ MobileAssetConfig — per-asset or per-template display preferences
15
+ (hero metrics, anomaly ref, pinned twins).
16
+ """
17
+
18
+ import json
19
+ from datetime import datetime, timezone
20
+ from enum import Enum
21
+ from typing import Optional
22
+
23
+
24
+ class MobileAssetTileType(str, Enum):
25
+ SENSOR = "sensor"
26
+ CHART = "chart"
27
+ TABLE = "table"
28
+ POLAR = "polar"
29
+ EVENT = "event"
30
+
31
+
32
+ class MobileAssetTile:
33
+ """
34
+ Tile entity stored in PostgreSQL ``"MobileAssetTile"`` table.
35
+
36
+ PK is ``id`` (UUID, server-generated).
37
+
38
+ - ``template_id``: template scope (empty GUID for non-templated assets).
39
+ - ``twin_id``: NULL = template-scoped, set = twin-scoped override.
40
+ - ``type``: tile visualization type (sensor, chart, table, polar, event).
41
+ - ``label``: display label.
42
+ - ``sort_order``: sort position (0-based).
43
+ - ``config``: free-form JSON with type-specific settings.
44
+ """
45
+
46
+ def __init__(self):
47
+ self.id: Optional[str] = None
48
+ self.template_id: Optional[str] = None
49
+ self.twin_id: Optional[str] = None
50
+ self.type: Optional[MobileAssetTileType] = None
51
+ self.label: Optional[str] = None
52
+ self.sort_order: int = 0
53
+ self.config: Optional[dict] = None
54
+ self.created_by: Optional[str] = None
55
+ self.updated_at: Optional[datetime] = None
56
+
57
+ # ------------------------------------------------------------------
58
+ # Serialisation
59
+ # ------------------------------------------------------------------
60
+
61
+ def to_dict(self) -> dict:
62
+ obj = {}
63
+ if self.id is not None:
64
+ obj["id"] = str(self.id)
65
+ if self.template_id is not None:
66
+ obj["templateId"] = str(self.template_id)
67
+ if self.twin_id is not None:
68
+ obj["twinId"] = str(self.twin_id)
69
+ if self.type is not None:
70
+ obj["type"] = (
71
+ self.type.value
72
+ if isinstance(self.type, MobileAssetTileType)
73
+ else self.type
74
+ )
75
+ if self.label is not None:
76
+ obj["label"] = self.label
77
+ obj["sortOrder"] = self.sort_order
78
+ if self.config is not None:
79
+ obj["config"] = self.config
80
+ if self.created_by is not None:
81
+ obj["createdBy"] = self.created_by
82
+ if self.updated_at is not None:
83
+ obj["updatedAt"] = int(self.updated_at.timestamp() * 1000)
84
+ return obj
85
+
86
+ @classmethod
87
+ def from_dict(cls, data: dict) -> "MobileAssetTile":
88
+ obj = cls()
89
+ obj.id = data.get("id")
90
+ obj.template_id = data.get("templateId") or data.get("template_id")
91
+ obj.twin_id = data.get("twinId") or data.get("twin_id")
92
+
93
+ raw_type = data.get("type")
94
+ if raw_type is not None:
95
+ obj.type = MobileAssetTileType(raw_type.lower())
96
+
97
+ obj.label = data.get("label")
98
+ obj.sort_order = data.get("sortOrder", data.get("sort_order", 0))
99
+
100
+ raw_config = data.get("config")
101
+ if isinstance(raw_config, dict):
102
+ obj.config = raw_config
103
+ elif isinstance(raw_config, str) and raw_config:
104
+ try:
105
+ parsed = json.loads(raw_config)
106
+ obj.config = parsed if isinstance(parsed, dict) else None
107
+ except (json.JSONDecodeError, ValueError):
108
+ obj.config = None
109
+
110
+ obj.created_by = data.get("createdBy") or data.get("created_by")
111
+
112
+ updated_raw = data.get("updatedAt") or data.get("updated_at")
113
+ if updated_raw is not None:
114
+ if isinstance(updated_raw, (int, float)):
115
+ obj.updated_at = datetime.fromtimestamp(updated_raw / 1000, tz=timezone.utc)
116
+ elif isinstance(updated_raw, datetime):
117
+ obj.updated_at = updated_raw
118
+ return obj
119
+
120
+ # ------------------------------------------------------------------
121
+ # API identity helpers
122
+ # ------------------------------------------------------------------
123
+
124
+ def api_id(self) -> str:
125
+ return str(self.id) if self.id else None
126
+
127
+ def api_key(self) -> str:
128
+ return str(self.id) if self.id else None
129
+
130
+ def set_id(self, value):
131
+ self.id = str(value)
132
+
133
+ def __repr__(self) -> str:
134
+ return (
135
+ f"MobileAssetTile(id={self.id!r}, label={self.label!r}, "
136
+ f"type={self.type!r}, template_id={self.template_id!r}, "
137
+ f"twin_id={self.twin_id!r})"
138
+ )
139
+
140
+
141
+ class MobileAssetConfig:
142
+ """
143
+ Asset config entity stored in PostgreSQL ``"MobileAssetConfig"`` table.
144
+
145
+ PK is ``id`` (UUID, server-generated).
146
+
147
+ - ``template_id``: template scope.
148
+ - ``twin_id``: NULL = template default, set = twin override.
149
+ - ``config``: free-form JSON (heroMetricRefs, anomalyDatapointRef, pinnedTwinIds, etc.).
150
+ """
151
+
152
+ def __init__(self):
153
+ self.id: Optional[str] = None
154
+ self.template_id: Optional[str] = None
155
+ self.twin_id: Optional[str] = None
156
+ self.config: Optional[dict] = None
157
+ self.updated_at: Optional[datetime] = None
158
+
159
+ # ------------------------------------------------------------------
160
+ # Serialisation
161
+ # ------------------------------------------------------------------
162
+
163
+ def to_dict(self) -> dict:
164
+ obj = {}
165
+ if self.id is not None:
166
+ obj["id"] = str(self.id)
167
+ if self.template_id is not None:
168
+ obj["templateId"] = str(self.template_id)
169
+ if self.twin_id is not None:
170
+ obj["twinId"] = str(self.twin_id)
171
+ if self.config is not None:
172
+ obj["config"] = self.config
173
+ if self.updated_at is not None:
174
+ obj["updatedAt"] = int(self.updated_at.timestamp() * 1000)
175
+ return obj
176
+
177
+ @classmethod
178
+ def from_dict(cls, data: dict) -> "MobileAssetConfig":
179
+ obj = cls()
180
+ obj.id = data.get("id")
181
+ obj.template_id = data.get("templateId") or data.get("template_id")
182
+ obj.twin_id = data.get("twinId") or data.get("twin_id")
183
+
184
+ raw_config = data.get("config")
185
+ if isinstance(raw_config, dict):
186
+ obj.config = raw_config
187
+ elif isinstance(raw_config, str) and raw_config:
188
+ try:
189
+ parsed = json.loads(raw_config)
190
+ obj.config = parsed if isinstance(parsed, dict) else None
191
+ except (json.JSONDecodeError, ValueError):
192
+ obj.config = None
193
+
194
+ updated_raw = data.get("updatedAt") or data.get("updated_at")
195
+ if updated_raw is not None:
196
+ if isinstance(updated_raw, (int, float)):
197
+ obj.updated_at = datetime.fromtimestamp(updated_raw / 1000, tz=timezone.utc)
198
+ elif isinstance(updated_raw, datetime):
199
+ obj.updated_at = updated_raw
200
+ return obj
201
+
202
+ # ------------------------------------------------------------------
203
+ # API identity helpers
204
+ # ------------------------------------------------------------------
205
+
206
+ def api_id(self) -> str:
207
+ return str(self.id) if self.id else None
208
+
209
+ def api_key(self) -> str:
210
+ return str(self.id) if self.id else None
211
+
212
+ def set_id(self, value):
213
+ self.id = str(value)
214
+
215
+ def __repr__(self) -> str:
216
+ return (
217
+ f"MobileAssetConfig(id={self.id!r}, "
218
+ f"template_id={self.template_id!r}, "
219
+ f"twin_id={self.twin_id!r})"
220
+ )
@@ -131,6 +131,8 @@ class Twin(ApiDto):
131
131
  :ivar uuid.UUID longitude_id: technical id of a datapoint specifying dynamic longitude of twin.
132
132
  :ivar str color: hexadecimal code of the color to associate with this twin item.
133
133
  :ivar str icon: logical id of the icon or svg schema to associate with this twin item.
134
+ :ivar bool is_asset: whether this twin represents an asset.
135
+ :ivar str image: image identifier or path associated with this twin.
134
136
  :ivar uuid.UUID createdById: unique identifier of creating user.
135
137
  :ivar int createdDate: timestamp of created date.
136
138
  :ivar uuid.UUID updatedById: unique identifier of updating user.
@@ -161,7 +163,9 @@ class Twin(ApiDto):
161
163
  latitude: float = None,
162
164
  longitude: float = None,
163
165
  extra_properties: dict = None,
164
- description: str = None):
166
+ description: str = None,
167
+ is_asset: bool = None,
168
+ image: str = None):
165
169
  if twin_id is None:
166
170
  self.twin_id = uuid.uuid4()
167
171
  else:
@@ -186,6 +190,8 @@ class Twin(ApiDto):
186
190
  self.color = color
187
191
  self.icon = icon
188
192
  self.extra_properties = extra_properties
193
+ self.is_asset = is_asset
194
+ self.image = image
189
195
  self.createdById = None
190
196
  self.createdDate = None
191
197
  self.updatedById = None
@@ -231,11 +237,22 @@ class Twin(ApiDto):
231
237
  self.description = str(obj["description"])
232
238
  if "type" in obj.keys():
233
239
  self.type = TwinBlockType(str(obj["type"]))
240
+ if "isAsset" in obj.keys() and obj["isAsset"] is not None:
241
+ self.is_asset = bool(obj["isAsset"])
242
+ if "image" in obj.keys() and obj["image"] is not None:
243
+ self.image = str(obj["image"])
234
244
  if "extraProperties" in obj.keys():
235
- if isinstance(obj["extraProperties"], str):
236
- self.extra_properties = json.loads(obj["extraProperties"])
245
+ raw = obj["extraProperties"]
246
+ if isinstance(raw, dict):
247
+ self.extra_properties = raw
248
+ elif isinstance(raw, str) and raw:
249
+ try:
250
+ parsed = json.loads(raw)
251
+ self.extra_properties = parsed if isinstance(parsed, dict) else None
252
+ except (json.JSONDecodeError, ValueError):
253
+ self.extra_properties = None
237
254
  else:
238
- self.extra_properties = obj["extraProperties"]
255
+ self.extra_properties = None
239
256
  if "createdById" in obj.keys() and obj["createdById"] is not None:
240
257
  self.createdById = obj["createdById"]
241
258
  if "createdDate" in obj.keys() and obj["createdDate"] is not None:
@@ -275,9 +292,11 @@ class Twin(ApiDto):
275
292
  obj["longitudeSensorId"] = str(self.longitude_id)
276
293
  if self.icon is not None:
277
294
  obj["icon"] = str(self.icon)
278
- if self.extra_properties is not None:
279
- if not isinstance(self.extra_properties, dict):
280
- raise ValueError('on twin extra properties must be None or a JSON serializable dict')
295
+ if self.is_asset is not None:
296
+ obj["isAsset"] = self.is_asset
297
+ if self.image is not None:
298
+ obj["image"] = str(self.image)
299
+ if self.extra_properties is not None and isinstance(self.extra_properties, dict):
281
300
  obj["extraProperties"] = json.dumps(self.extra_properties)
282
301
  if self.createdById is not None:
283
302
  obj["createdById"] = str(self.createdById)
@@ -0,0 +1 @@
1
+ __version__ = "2.0.0.dev6"
@@ -50,6 +50,7 @@ from .pipeline_image import PipelineImage
50
50
  from .solution_component import SolutionComponent, SolutionType
51
51
  from .paged_query_result import PagedQueryResult
52
52
  from .api_interface import ApiInterface
53
+ from .mobile_asset import MobileAssetTile, MobileAssetConfig
53
54
  from .version import __version__
54
55
  import ast
55
56
  from .api_config import _registry
@@ -1015,14 +1016,14 @@ class WizataDSAPIClient(ApiInterface, ApiDtoInterface):
1015
1016
 
1016
1017
  - existing models are used for simulation and prediction.
1017
1018
  - caution this might affect data inside platform or trigger automation.
1018
- - if your pipeline is templated please provide a twin.
1019
+ - if your pipeline is templated please provide a twin hardware ID.
1019
1020
  - please provide all variables and parameters required through properties.
1020
1021
  - return an execution
1021
1022
  - check status with "wizata_dsapi.api().get(execution).status"
1022
1023
  - check results in platform (dashboard/explorer) or perform queries.
1023
1024
 
1024
- :param pipeline: pipeline identified by its id (uuid or wizata_dsapi.Pipeline) or key (str).
1025
- :param twin: twin identified by its id (uuid or wizata_dsapi.Twin) or hardware ID (str).
1025
+ :param pipeline: pipeline identified by key (str) .
1026
+ :param twin: twin identified by hardware ID (str)(optional).
1026
1027
  :param properties: dictionary containing override for variables or additional parameters for your script.
1027
1028
  :param train: train machine learning model on model steps.
1028
1029
  :param image: pipeline image id to use.
@@ -1695,68 +1696,27 @@ class WizataDSAPIClient(ApiInterface, ApiDtoInterface):
1695
1696
  else:
1696
1697
  raise self.__raise_error(response)
1697
1698
 
1698
- def search_twins(self,
1699
- page: int = 1,
1700
- size: int = 20,
1701
- sort: str = "id",
1702
- direction: str = "asc",
1703
- hardware_id: str = None,
1704
- name: str = None,
1705
- parents: list = None) -> PagedQueryResult:
1699
+ def search_twins(self, search_query=None) -> PagedQueryResult:
1706
1700
  """
1707
- get twins with a paged query.
1708
- :param page: numero of the page - default 1.
1709
- :param size: quantity per page - default 20 max 100.
1710
- :param sort: column to sort results - default id.
1711
- :param direction: sorting direction by default asc, accept also desc.
1712
- :param hardware_id: filter on a specific hardware ID name or partial name.
1713
- :param name: name or part of twin name.
1714
- :param parents: list of all possible parents (Twin, UUID, or str UUID).
1715
- :return: PagedQueryResults, check total for number of potential results and results for the list of entity.
1716
- """
1717
- query = PagedQueryResult(
1718
- page=page,
1719
- size=size,
1720
- sort=sort,
1721
- direction=direction
1722
- )
1701
+ Search twins using filters, sorting and pagination via POST.
1723
1702
 
1724
- if sort not in ["id", "hardwareId", "createdDate", "createdById", "updatedDate", "updatedById",
1725
- "name", "description"]:
1726
- raise ValueError("invalid sort column")
1727
-
1728
- parameter_str = "?page=" + str(page) + "&size=" + str(size) + "&sort=" + str(sort) + "&direction=" + str(direction)
1729
- if hardware_id is not None:
1730
- parameter_str += "&hardwareId=" + sanitize_url_parameter(hardware_id)
1731
- if parents is not None and len(parents) > 0:
1732
- list_str = []
1733
- for parent in parents:
1734
- if isinstance(parent, uuid.UUID):
1735
- list_str.append(str(parent))
1736
- elif isinstance(parent, str):
1737
- list_str.append(parent)
1738
- elif isinstance(parent, Twin):
1739
- list_str.append(str(parent.twin_id))
1740
- else:
1741
- raise ValueError('parent must be a Twin or a str')
1742
- parameter_str += "&parentIds=" + sanitize_url_parameter(",".join(list_str))
1743
-
1744
- if name is not None:
1745
- parameter_str += "&name=" + sanitize_url_parameter(name)
1703
+ Supported filter fields:
1704
+ hardwareId, name, description, parentId, twinTypeId, type, isAsset, _search.
1746
1705
 
1747
- response = requests.request("GET",
1748
- self.__url() + "twins/filter" + parameter_str,
1749
- headers=self.__header()
1750
- )
1706
+ :param search_query: SearchQuery instance or dict with filters, sort, page, size.
1707
+ :return: PagedQueryResult with Twin results.
1708
+ """
1709
+ if search_query is None:
1710
+ search_query = SearchQuery()
1711
+ elif isinstance(search_query, dict):
1712
+ search_query = SearchQuery.from_dict(search_query)
1713
+ response = requests.post(
1714
+ self.__url() + "twins/search",
1715
+ headers=self.__header(),
1716
+ data=json.dumps(search_query.to_dict())
1717
+ )
1751
1718
  if response.status_code == 200:
1752
- response_obj = response.json()
1753
- query.total = int(response_obj["total"])
1754
- query.results = []
1755
- for obj in response_obj["results"]:
1756
- twin = Twin()
1757
- twin.from_json(obj)
1758
- query.results.append(twin)
1759
- return query
1719
+ return PagedQueryResult.from_dict(response.json(), dto_class=Twin)
1760
1720
  else:
1761
1721
  raise self.__raise_error(response)
1762
1722
 
@@ -2120,6 +2080,122 @@ class WizataDSAPIClient(ApiInterface, ApiDtoInterface):
2120
2080
  self.__raise_error(response)
2121
2081
 
2122
2082
 
2083
+ # ------------------------------------------------------------------
2084
+ # Mobile Asset Tiles & Config
2085
+ # ------------------------------------------------------------------
2086
+
2087
+ def get_mobile_tiles(self, template_id: str, twin_id: str = None) -> list:
2088
+ """
2089
+ Get merged tiles for an asset (template + twin overrides).
2090
+
2091
+ :param template_id: template UUID.
2092
+ :param twin_id: optional twin UUID for twin-scoped overrides.
2093
+ :return: list of MobileAssetTile.
2094
+ """
2095
+ params = {"templateId": str(template_id)}
2096
+ if twin_id is not None:
2097
+ params["twinId"] = str(twin_id)
2098
+ response = requests.get(
2099
+ self.__url() + "mobile/tiles",
2100
+ headers=self.__header(),
2101
+ params=params,
2102
+ )
2103
+ if response.status_code == 200:
2104
+ return [MobileAssetTile.from_dict(t) for t in response.json()]
2105
+ else:
2106
+ raise self.__raise_error(response)
2107
+
2108
+ def create_mobile_tile(self, tile: MobileAssetTile) -> MobileAssetTile:
2109
+ """
2110
+ Create a mobile asset tile.
2111
+
2112
+ :param tile: MobileAssetTile to create.
2113
+ :return: created MobileAssetTile with server-generated id.
2114
+ """
2115
+ response = requests.post(
2116
+ self.__url() + "mobile/tiles",
2117
+ headers=self.__header(),
2118
+ data=json.dumps(tile.to_dict()),
2119
+ )
2120
+ if response.status_code in (200, 201):
2121
+ return MobileAssetTile.from_dict(response.json())
2122
+ else:
2123
+ raise self.__raise_error(response)
2124
+
2125
+ def update_mobile_tile(self, tile: MobileAssetTile) -> MobileAssetTile:
2126
+ """
2127
+ Update an existing mobile asset tile.
2128
+
2129
+ :param tile: MobileAssetTile with id set.
2130
+ :return: updated MobileAssetTile.
2131
+ """
2132
+ response = requests.put(
2133
+ self.__url() + "mobile/tiles/" + str(tile.id),
2134
+ headers=self.__header(),
2135
+ data=json.dumps(tile.to_dict()),
2136
+ )
2137
+ if response.status_code == 200:
2138
+ return MobileAssetTile.from_dict(response.json())
2139
+ else:
2140
+ raise self.__raise_error(response)
2141
+
2142
+ def delete_mobile_tile(self, tile_id: str):
2143
+ """
2144
+ Delete a mobile asset tile.
2145
+
2146
+ :param tile_id: tile UUID.
2147
+ """
2148
+ response = requests.delete(
2149
+ self.__url() + "mobile/tiles/" + str(tile_id),
2150
+ headers=self.__header(),
2151
+ )
2152
+ if response.status_code not in (200, 204):
2153
+ raise self.__raise_error(response)
2154
+
2155
+ def get_mobile_config(self, template_id: str, twin_id: str = None) -> MobileAssetConfig:
2156
+ """
2157
+ Get resolved config for an asset (twin overrides template).
2158
+
2159
+ :param template_id: template UUID.
2160
+ :param twin_id: optional twin UUID.
2161
+ :return: MobileAssetConfig or None.
2162
+ """
2163
+ params = {"templateId": str(template_id)}
2164
+ if twin_id is not None:
2165
+ params["twinId"] = str(twin_id)
2166
+ response = requests.get(
2167
+ self.__url() + "mobile/config",
2168
+ headers=self.__header(),
2169
+ params=params,
2170
+ )
2171
+ if response.status_code == 200:
2172
+ data = response.json()
2173
+ if data is None:
2174
+ return None
2175
+ return MobileAssetConfig.from_dict(data)
2176
+ elif response.status_code in (400, 404):
2177
+ return None
2178
+ else:
2179
+ raise self.__raise_error(response)
2180
+
2181
+ def upsert_mobile_config(self, config: MobileAssetConfig) -> MobileAssetConfig:
2182
+ """
2183
+ Upsert mobile asset config by (templateId, twinId).
2184
+
2185
+ :param config: MobileAssetConfig to upsert.
2186
+ :return: upserted MobileAssetConfig.
2187
+ """
2188
+ response = requests.put(
2189
+ self.__url() + "mobile/config",
2190
+ headers=self.__header(),
2191
+ data=json.dumps(config.to_dict()),
2192
+ )
2193
+ if response.status_code in (200, 201):
2194
+ return MobileAssetConfig.from_dict(response.json())
2195
+ else:
2196
+ raise self.__raise_error(response)
2197
+
2198
+
2123
2199
  def api() -> WizataDSAPIClient:
2124
2200
  """
2125
2201
  Create a WizataDSAPIClient from environment variables.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wizata_dsapi
3
- Version: 2.0.0.dev4
3
+ Version: 2.0.0.dev6
4
4
  Summary: Wizata Data Science Toolkit
5
5
  Author: Wizata S.A.
6
6
  Author-email: info@wizata.com
@@ -23,6 +23,7 @@ wizata_dsapi/group_system.py
23
23
  wizata_dsapi/ilogger.py
24
24
  wizata_dsapi/insight.py
25
25
  wizata_dsapi/mlmodel.py
26
+ wizata_dsapi/mobile_asset.py
26
27
  wizata_dsapi/model_toolkit.py
27
28
  wizata_dsapi/notification.py
28
29
  wizata_dsapi/paged_query_result.py
@@ -1 +0,0 @@
1
- __version__ = "2.0.0.dev4"