wizata-dsapi 2.0.0.dev5__tar.gz → 2.0.0.dev7__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.dev5/wizata_dsapi.egg-info → wizata_dsapi-2.0.0.dev7}/PKG-INFO +1 -1
  2. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/__init__.py +3 -2
  3. wizata_dsapi-2.0.0.dev7/wizata_dsapi/mobile_asset.py +220 -0
  4. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/notification.py +50 -1
  5. wizata_dsapi-2.0.0.dev7/wizata_dsapi/version.py +1 -0
  6. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/wizata_dsapi_client.py +120 -3
  7. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7/wizata_dsapi.egg-info}/PKG-INFO +1 -1
  8. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi.egg-info/SOURCES.txt +1 -0
  9. wizata_dsapi-2.0.0.dev5/wizata_dsapi/version.py +0 -1
  10. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/LICENSE.txt +0 -0
  11. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/README.rst +0 -0
  12. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/setup.cfg +0 -0
  13. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/setup.py +0 -0
  14. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/api_config.py +0 -0
  15. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/api_dto.py +0 -0
  16. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/api_interface.py +0 -0
  17. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/bucket.py +0 -0
  18. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/business_label.py +0 -0
  19. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/context.py +0 -0
  20. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/dashboard.py +0 -0
  21. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/dataframe_toolkit.py +0 -0
  22. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/datapoint.py +0 -0
  23. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/datastore.py +0 -0
  24. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/ds_dataframe.py +0 -0
  25. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/dsapi_json_encoder.py +0 -0
  26. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/edge_device.py +0 -0
  27. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/evaluation.py +0 -0
  28. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/execution.py +0 -0
  29. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/execution_log.py +0 -0
  30. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/experiment.py +0 -0
  31. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/group_system.py +0 -0
  32. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/ilogger.py +0 -0
  33. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/insight.py +0 -0
  34. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/mlmodel.py +0 -0
  35. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/model_toolkit.py +0 -0
  36. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/models/__init__.py +0 -0
  37. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/models/common.py +0 -0
  38. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/paged_query_result.py +0 -0
  39. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/pipeline.py +0 -0
  40. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/pipeline_image.py +0 -0
  41. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/plot.py +0 -0
  42. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/plots/__init__.py +0 -0
  43. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/plots/common.py +0 -0
  44. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/request.py +0 -0
  45. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/script.py +0 -0
  46. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/scripts/__init__.py +0 -0
  47. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/scripts/common.py +0 -0
  48. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/search.py +0 -0
  49. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/solution_component.py +0 -0
  50. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/streamlit_utils.py +0 -0
  51. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/template.py +0 -0
  52. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/trigger.py +0 -0
  53. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/twin.py +0 -0
  54. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/twinregistration.py +0 -0
  55. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/wizard_function.py +0 -0
  56. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/wizard_request.py +0 -0
  57. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi/words.py +0 -0
  58. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi.egg-info/dependency_links.txt +0 -0
  59. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/wizata_dsapi.egg-info/requires.txt +0 -0
  60. {wizata_dsapi-2.0.0.dev5 → wizata_dsapi-2.0.0.dev7}/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.dev5
3
+ Version: 2.0.0.dev7
4
4
  Summary: Wizata Data Science Toolkit
5
5
  Author: Wizata S.A.
6
6
  Author-email: info@wizata.com
@@ -50,6 +50,7 @@ from .streamlit_utils import (get_streamlit_token, get_streamlit_domain, get_str
50
50
  get_streamlit_twin_id)
51
51
 
52
52
  from .search import FilterOperator, SearchQuery, SortOption, GroupSearchQuery
53
- from .notification import NotificationScope, DeviceToken, AlertRule, AlertActive
53
+ from .notification import NotificationScope, DeviceToken, AlertRule, AlertActive, MonitoredDatapoint
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
+ )
@@ -297,4 +297,53 @@ class AlertActive:
297
297
  return (
298
298
  f"AlertActive(rule={self.alert_rule_id!r}, twin={self.twin_id!r}, "
299
299
  f"count={self.occurrence_count}, severity={self.severity})"
300
- )
300
+ )
301
+
302
+
303
+ class MonitoredDatapoint:
304
+ """
305
+ Registry entry for a datapoint flagged for monitoring.
306
+
307
+ Stored in PostgreSQL ``"MonitoredDatapoint"`` table.
308
+ PK is ``hardware_id`` (one row per datapoint).
309
+
310
+ The datapoint_monitor job reads this table and creates independent
311
+ AlertRule/AlertActive entries per event type (disconnected, out_of_range,
312
+ misconfigured).
313
+ """
314
+
315
+ def __init__(self, hardware_id: str = None):
316
+ self.hardware_id: Optional[str] = hardware_id
317
+ self.created_at: Optional[datetime] = None
318
+
319
+ def to_dict(self) -> dict:
320
+ obj = {}
321
+ if self.hardware_id is not None:
322
+ obj["hardwareId"] = self.hardware_id
323
+ if self.created_at is not None:
324
+ obj["createdAt"] = int(self.created_at.timestamp() * 1000)
325
+ return obj
326
+
327
+ @classmethod
328
+ def from_dict(cls, data: dict) -> "MonitoredDatapoint":
329
+ obj = cls()
330
+ obj.hardware_id = data.get("hardwareId") or data.get("hardware_id")
331
+ raw = data.get("createdAt") or data.get("created_at")
332
+ if raw is not None:
333
+ if isinstance(raw, (int, float)):
334
+ obj.created_at = datetime.fromtimestamp(raw / 1000, tz=timezone.utc)
335
+ elif isinstance(raw, datetime):
336
+ obj.created_at = raw
337
+ return obj
338
+
339
+ def api_id(self) -> str:
340
+ return self.hardware_id
341
+
342
+ def api_key(self) -> str:
343
+ return self.hardware_id
344
+
345
+ def set_id(self, value):
346
+ self.hardware_id = str(value)
347
+
348
+ def __repr__(self) -> str:
349
+ return f"MonitoredDatapoint(hardware_id={self.hardware_id!r})"
@@ -0,0 +1 @@
1
+ __version__ = "2.0.0.dev7"
@@ -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.
@@ -2079,6 +2080,122 @@ class WizataDSAPIClient(ApiInterface, ApiDtoInterface):
2079
2080
  self.__raise_error(response)
2080
2081
 
2081
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
+
2082
2199
  def api() -> WizataDSAPIClient:
2083
2200
  """
2084
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.dev5
3
+ Version: 2.0.0.dev7
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.dev5"