python-terminusgps 1.5.6__py3-none-any.whl → 1.5.8__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 python-terminusgps might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: python-terminusgps
3
- Version: 1.5.6
3
+ Version: 1.5.8
4
4
  Summary: Provides abstractions/utilities for working with Wialon API, Authorize.NET API, AWS API, and more.
5
5
  Project-URL: Documentation, https://app.terminusgps.com/docs/apps/python-terminusgps/index.html
6
6
  Project-URL: Repository, https://github.com/terminusgps/python-terminusgps
@@ -15,5 +15,5 @@ Requires-Python: >=3.12
15
15
  Requires-Dist: argparse>=1.4.0
16
16
  Requires-Dist: authorizenet>=1.1.5
17
17
  Requires-Dist: boto3>=1.34.144
18
- Requires-Dist: django>=5.1.4
18
+ Requires-Dist: django>=5.1.5
19
19
  Requires-Dist: python-wialon>=1.2.4
@@ -4,21 +4,28 @@ terminusgps/authorizenet/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
4
4
  terminusgps/authorizenet/auth.py,sha256=zITSQMH8F-3vw-lDQRbuR2s9AVlGqbOyyFo0zqU00qU,870
5
5
  terminusgps/aws/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
6
  terminusgps/aws/secrets.py,sha256=kgRA77rs0mD4berWRLkPtJLOe4Grf--o5f8NzwQqXCk,360
7
+ terminusgps/openstreetmap/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
+ terminusgps/openstreetmap/polyline.py,sha256=GHle6UWiHt-HQJ9CXxKG9Z1lr7yXCq_09dHc8IAYP6Y,104
9
+ terminusgps/openstreetmap/renderer.py,sha256=vYvWfdBJAo4vUJlzHzjAaKwISz492-ADKgcZ4Gbabbs,76
10
+ terminusgps/openstreetmap/session.py,sha256=GqDzrA_DkNN0UYcZgRFE4EQ78S6PEbdTkBSB0hyJt3A,1697
7
11
  terminusgps/wialon/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
12
  terminusgps/wialon/constants.py,sha256=dsQaNt3TIjIZbr_m94KmBGFdrqe6HER2r6lol3X8QpU,2802
9
- terminusgps/wialon/errors.py,sha256=RbHwHuhW8P9L7i3jaPzcMO8ZHxX3Z3V970ypEtqnavw,1236
13
+ terminusgps/wialon/errors.py,sha256=SV9pVwU6FZ_zGlGP6zJN6aLE2auF4TfHFISQLiPMKrI,1758
10
14
  terminusgps/wialon/flags.py,sha256=-OoH-eZM54yjRqxsAXL8VImdQu_7C0OAxCrFqaCEuko,13510
11
- terminusgps/wialon/session.py,sha256=yEoOxRqL3dLIAAFAAgYu9K866QZzFiCDApZBQ8f0LTI,8740
12
- terminusgps/wialon/utils.py,sha256=J8V2F-QDMsLD5x2OhCYI2lnZZdgqKboMve5XJD7Qt30,1877
15
+ terminusgps/wialon/session.py,sha256=x5aXxqLcBe4e0Zj3enUvWd1_Ufmd_MxXInC_d_GMn3E,9446
16
+ terminusgps/wialon/utils.py,sha256=PMtEaRB9RjdDgWWzHPRnw3Gnrv-DgjywutTCIw1S7_c,2127
13
17
  terminusgps/wialon/items/__init__.py,sha256=3BVthghekMvhMQSzQgBMlD_phxmKSmp3Zvmo-z0O8Bs,211
14
18
  terminusgps/wialon/items/base.py,sha256=MN4FG6U1nWkYAjNfXQJRVrWJoiW4Y64tyqxUO0mhv_w,6593
15
19
  terminusgps/wialon/items/resource.py,sha256=ADjGsQaCqD6Y3_AaD8vLgYzGaMK69MpxCZojnylS4GE,815
16
- terminusgps/wialon/items/retranslator.py,sha256=HkL_asa_4VTRDvl7e6I9rtUhF0PBV3HRmecgesneHUM,839
20
+ terminusgps/wialon/items/retranslator.py,sha256=zsQXqOhH1zFe5_e8DROPu60z3v6xPWOEPyMCi2IqJAo,3861
17
21
  terminusgps/wialon/items/route.py,sha256=qOHPN_rejwiGqvwWzlwmUIAIyc3lKavCalf8ki66rx0,760
18
22
  terminusgps/wialon/items/unit.py,sha256=tLAWPfHUUS6_Feh1aYBMFPgyuGlSiAnfumJJmGt3bKw,4662
19
23
  terminusgps/wialon/items/unit_group.py,sha256=1yc7ldPIgGbtiTj0djRDWmt6Q9K_VT9sxOaioasbbLY,5212
20
24
  terminusgps/wialon/items/user.py,sha256=bkcMw_YiocaMuhP_pBfB7apjAZwnsOzGScnGkn8Ybbw,6107
21
- python_terminusgps-1.5.6.dist-info/METADATA,sha256=-ydcnkpNZo3XBwK4pe9MCouyUryZqstT0lJa76zuuvY,882
22
- python_terminusgps-1.5.6.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
23
- python_terminusgps-1.5.6.dist-info/licenses/COPYING,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
24
- python_terminusgps-1.5.6.dist-info/RECORD,,
25
+ terminusgps/wialon/maps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
26
+ terminusgps/wialon/maps/layers.py,sha256=K_uxQjRG5Y7WRCpSL5RbYKJFyE87zgYuP9MdoBqgHEU,1763
27
+ terminusgps/wialon/maps/renderer.py,sha256=AusrPT7KXG2yn6E3Ls4DOAJEPANdL7548ZnjHFSmP9Y,5334
28
+ python_terminusgps-1.5.8.dist-info/METADATA,sha256=UDfapsi2DCVaBF5ToB-IXuuE4IG6VEvf74Y11Qkln-k,882
29
+ python_terminusgps-1.5.8.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
30
+ python_terminusgps-1.5.8.dist-info/licenses/COPYING,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
31
+ python_terminusgps-1.5.8.dist-info/RECORD,,
File without changes
@@ -0,0 +1,7 @@
1
+ from dataclasses import dataclass
2
+
3
+
4
+ @dataclass
5
+ class OpenStreetMapPolyline:
6
+ key: str
7
+ value: str
@@ -0,0 +1,3 @@
1
+ class OpenStreetMapRenderer:
2
+ def __init__(self) -> None:
3
+ return
@@ -0,0 +1,54 @@
1
+ import os
2
+ import requests
3
+ from urllib.parse import urlencode
4
+
5
+
6
+ class OpenStreetMapSession:
7
+ def __init__(self, client_id: str, redirect_uri: str, scopes: list[str]) -> None:
8
+ self.client_id = client_id
9
+ self.redirect_uri = redirect_uri
10
+ self.scopes = scopes
11
+ self.base_token_url = "https://master.apis.dev.openstreetmap.org/oauth2/token?"
12
+ self.base_auth_url = (
13
+ "https://master.apis.dev.openstreetmap.org/oauth2/authorize?"
14
+ )
15
+
16
+ def generate_auth_url(self) -> str:
17
+ params = urlencode(
18
+ {
19
+ "response_type": "code",
20
+ "client_id": self.client_id,
21
+ "redirect_uri": self.redirect_uri,
22
+ "scope": "%20".join(self.scopes),
23
+ }
24
+ )
25
+ return self.base_auth_url + params
26
+
27
+ def get_token(self, auth_code: str, client_secret: str) -> str | None:
28
+ params = urlencode(
29
+ {
30
+ "grant_type": "authorization_code",
31
+ "code": auth_code,
32
+ "redirect_uri": self.redirect_uri,
33
+ "client_id": self.client_id,
34
+ "client_secret": client_secret,
35
+ }
36
+ )
37
+ response = requests.post(self.base_token_url + params).json()
38
+ self.scopes = [response.get("scope").split(" ")]
39
+ return response.get("access_token")
40
+
41
+
42
+ def main() -> None:
43
+ scopes = os.getenv("OSM_SCOPES").split(" ")
44
+ session = OpenStreetMapSession(
45
+ client_id=os.getenv("OSM_CLIENT_ID"),
46
+ redirect_uri=os.getenv("OSM_REDIRECT_URI"),
47
+ scopes=scopes,
48
+ )
49
+ print(f"{session.generate_auth_url() = }")
50
+ return
51
+
52
+
53
+ if __name__ == "__main__":
54
+ main()
@@ -2,34 +2,52 @@ from wialon.api import WialonError
2
2
 
3
3
 
4
4
  class WialonBaseError(Exception):
5
- def __init__(self, message: str, wialon_err: WialonError | None = None) -> None:
5
+ def __init__(
6
+ self, message: str, wialon_err: WialonError | AssertionError | None = None
7
+ ) -> None:
6
8
  self.wialon_err = wialon_err
7
- super().__init__(message)
9
+ return super().__init__(message)
8
10
 
9
11
 
10
12
  class WialonLoginError(WialonBaseError):
11
13
  def __init__(
12
- self, token: str | None, wialon_err: WialonError | None = None
14
+ self, token: str | None, wialon_err: WialonError | AssertionError | None = None
13
15
  ) -> None:
14
16
  message = f"Failed to login to the Wialon API using token: '{token}'\n"
15
17
  if wialon_err:
16
18
  message += str(wialon_err)
17
- super().__init__(message, wialon_err)
19
+ return super().__init__(message, wialon_err)
18
20
 
19
21
 
20
22
  class WialonSessionDuplicationError(WialonBaseError):
21
23
  def __init__(
22
- self, session_id: str | None, wialon_err: WialonError | None = None
24
+ self,
25
+ session_id: str | None,
26
+ wialon_err: WialonError | AssertionError | None = None,
23
27
  ) -> None:
24
28
  message = f"Failed to duplicate the Wialon session: '#{session_id}'\n"
25
29
  if wialon_err:
26
30
  message += str(wialon_err)
27
- super().__init__(message, wialon_err)
31
+ return super().__init__(message, wialon_err)
28
32
 
29
33
 
30
34
  class WialonLogoutError(WialonBaseError):
31
- def __init__(self, session_id: str, wialon_err: WialonError | None = None) -> None:
35
+ def __init__(
36
+ self, session_id: str, wialon_err: WialonError | AssertionError | None = None
37
+ ) -> None:
32
38
  message = f"Failed to logout of the Wialon API session: '{session_id}'\n"
33
39
  if wialon_err:
34
40
  message += str(wialon_err)
35
- super().__init__(message, wialon_err)
41
+ return super().__init__(message, wialon_err)
42
+
43
+
44
+ class WialonSessionInvalidError(WialonBaseError):
45
+ def __init__(
46
+ self,
47
+ session_id: str | None,
48
+ wialon_err: WialonError | AssertionError | None = None,
49
+ ) -> None:
50
+ message = f"The session was invalid/expired: '{session_id}'\n"
51
+ if wialon_err:
52
+ message += str(wialon_err)
53
+ return super().__init__(message, wialon_err)
@@ -4,6 +4,21 @@ from terminusgps.wialon.items.base import WialonBase
4
4
 
5
5
  class WialonRetranslator(WialonBase):
6
6
  def create(self, **kwargs) -> int | None:
7
+ """
8
+ Creates a Wialon retranslator.
9
+
10
+ :param creator_id: A Wialon user that will create the retranslator.
11
+ :type creator_id: :py:obj:`str`
12
+ :param name: A name for the new retranslator.
13
+ :type name: :py:obj:`str`
14
+ :param config: A Wialon retranslator configuration object.
15
+ :type config: :py:obj:`dict`
16
+ :raises ValueError: If a required parameter was not provided.
17
+ :raises WialonError: If something went wrong with Wialon.
18
+ :returns: Nothing.
19
+ :rtype: :py:obj:`None`
20
+
21
+ """
7
22
  if not kwargs.get("creator_id"):
8
23
  raise ValueError("'creator_id' is required on creation.")
9
24
  if not kwargs.get("name"):
@@ -20,3 +35,83 @@ class WialonRetranslator(WialonBase):
20
35
  }
21
36
  )
22
37
  return response.get("item", {}).get("id")
38
+
39
+ def update_config(self, new_config: dict) -> None:
40
+ """
41
+ Updates the retranslator config to the new config.
42
+
43
+ :param new_config: A Wialon retranslator configuration.
44
+ :type units: :py:obj:`dict`
45
+ :raises WialonError: If something went wrong with Wialon.
46
+ :returns: Nothing.
47
+ :rtype: :py:obj:`None`
48
+
49
+ """
50
+ self.session.wialon_api.retranslator_update_config(
51
+ **{"itemId": self.id, "config": new_config}
52
+ )
53
+
54
+ def add_units(self, units: list[WialonBase]) -> None:
55
+ """
56
+ Adds a list of units to the Wialon retranslator.
57
+
58
+ :param units: A list of Wialon unit objects.
59
+ :type units: :py:obj:`list`
60
+ :raises WialonError: If something went wrong with Wialon.
61
+ :returns: Nothing.
62
+ :rtype: :py:obj:`None`
63
+
64
+ """
65
+ self.session.wialon_api.retranslator_update_units(
66
+ **{
67
+ "itemId": self.id,
68
+ "units": [{"a": unit.id, "i": unit.hw_type} for unit in units],
69
+ "callMode": "add",
70
+ }
71
+ )
72
+
73
+ def rm_units(self, units: list[WialonBase]) -> None:
74
+ """
75
+
76
+ Naively removes a list of units from the Wialon retranslator.
77
+
78
+ :param units: A list of Wialon unit objects.
79
+ :type units: :py:obj:`list`
80
+ :raises WialonError: If something went wrong with Wialon.
81
+ :returns: Nothing.
82
+ :rtype: :py:obj:`None`
83
+
84
+ """
85
+ self.session.wialon_api.retranslator_update_units(
86
+ **{
87
+ "itemId": self.id,
88
+ "units": [{"a": unit.id, "i": unit.hw_type} for unit in units],
89
+ "callMode": "remove",
90
+ }
91
+ )
92
+
93
+ def start(self, stop: int | None = None) -> None:
94
+ """
95
+ Starts the Wialon retranslator.
96
+
97
+ :raises WialonError: If something went wrong with Wialon.
98
+ :returns: Nothing.
99
+ :rtype: :py:obj:`None`
100
+
101
+ """
102
+ self.session.wialon_api.retranslator_update_operating(
103
+ **{"itemId": self.id, "operate": int(True), "stopTime": stop}
104
+ )
105
+
106
+ def stop(self) -> None:
107
+ """
108
+ Stops the Wialon retranslator.
109
+
110
+ :raises WialonError: If something went wrong with Wialon.
111
+ :returns: Nothing.
112
+ :rtype: :py:obj:`None`
113
+
114
+ """
115
+ self.session.wialon_api.retranslator_update_operating(
116
+ **{"itemId": self.id, "operate": int(False)}
117
+ )
File without changes
@@ -0,0 +1,49 @@
1
+ from terminusgps.wialon.maps.renderer import WialonMapRenderer
2
+
3
+
4
+ class WialonMapLayerBase:
5
+ def __init__(self, renderer: WialonMapRenderer, name: str) -> None:
6
+ self.renderer = renderer
7
+ self.name = name
8
+ self.bounds = dict()
9
+
10
+ def __str__(self) -> str:
11
+ return self.name
12
+
13
+ def delete_layer(self) -> None:
14
+ self.renderer.session.wialon_api.render_remove_layer(**{"layerName": self.name})
15
+
16
+ def create_layer(self, data: list[dict], flags: int = 0x1) -> None:
17
+ raise NotImplementedError("Subclasses must implement this method")
18
+
19
+
20
+ class WialonMapLayerGeofence(WialonMapLayerBase):
21
+ def create_layer(self, data: list[dict], flags: int = 0x1) -> None:
22
+ response = self.renderer.session.wialon_api.render_create_zones_layer(
23
+ **{"layerName": self.name, "flags": flags, "zones": data}
24
+ )
25
+ self.bounds = {
26
+ "min_lat": response.get("bounds")[0],
27
+ "min_lon": response.get("bounds")[1],
28
+ "max_lat": response.get("bounds")[2],
29
+ "max_lon": response.get("bounds")[3],
30
+ }
31
+
32
+
33
+ class WialonMapLayerPoi(WialonMapLayerBase):
34
+ def create_layer(self, data: list[dict], flags: int = 0x1) -> None:
35
+ response = self.renderer.session.wialon_api.render_create_poi_layer(
36
+ **{"layerName": self.name, "flags": flags, "pois": data}
37
+ )
38
+ self.bounds = {
39
+ "min_lat": response.get("bounds")[0],
40
+ "min_lon": response.get("bounds")[1],
41
+ "max_lat": response.get("bounds")[2],
42
+ "max_lon": response.get("bounds")[3],
43
+ }
44
+
45
+
46
+ class WialonMapLayerTrack(WialonMapLayerBase):
47
+ def __init__(self, **kwargs) -> None:
48
+ self.units = []
49
+ return super().__init__(**kwargs)
@@ -0,0 +1,110 @@
1
+ from django.conf import ImproperlyConfigured, settings
2
+
3
+ from terminusgps.wialon.session import WialonSession
4
+
5
+
6
+ class WialonMapRenderer:
7
+ def __init__(
8
+ self, sid: str | None = None, gis_host: str = "hst-api.wialon.com"
9
+ ) -> None:
10
+ if not hasattr(settings, "WIALON_TOKEN"):
11
+ raise ImproperlyConfigured("'WIALON_TOKEN' setting is required.")
12
+
13
+ self.host = gis_host
14
+ self.layers = []
15
+ self.session = WialonSession(sid=sid)
16
+
17
+ @property
18
+ def total_layers(self) -> int:
19
+ return len(self.layers)
20
+
21
+ def get_events(self):
22
+ return self.session.wialon_api.avl_evts()
23
+
24
+ def toggle_layer(self, name: str, enabled: bool = True) -> None:
25
+ self.session.wialon_api.render_enable_layer(
26
+ **{"layerName": name, "enable": enabled}
27
+ )
28
+
29
+ def delete_all_layers(self) -> None:
30
+ self.session.wialon_api.render_remove_all_layers({})
31
+ self.layers = []
32
+
33
+ def get_tiles_url(self, x: int, y: int, z: int) -> str:
34
+ MIN_ZOOM, MAX_ZOOM = 2, 17
35
+ z = min(max(z, MIN_ZOOM), MAX_ZOOM)
36
+ return f"http://{self.host}/avl_render/{x}_{y}_{z}/{self.session.id}.png"
37
+
38
+ def update_locale(
39
+ self,
40
+ tz: int,
41
+ lang: str = "en",
42
+ flags: int = 1,
43
+ date_fmt: str = "%m-%E-%Y %H:%M:%S",
44
+ density: int = 256 * 256,
45
+ ) -> None:
46
+ """
47
+ Updates the renderer locale.
48
+
49
+
50
+ Date Format:
51
+
52
+ +-----------+------------------------------------------------------------------------+
53
+ | Parameter | Description |
54
+ +===========+========================================================================+
55
+ | ``%H`` | The hour of the day with leading zero if required ("00" to "23") |
56
+ +-----------+------------------------------------------------------------------------+
57
+ | ``%B`` | The full month name ("January" to "December") |
58
+ +-----------+------------------------------------------------------------------------+
59
+ | ``%b`` | Abbreviated month name ("Jan" to "Dec") |
60
+ +-----------+------------------------------------------------------------------------+
61
+ | ``%m`` | The month of the year with leading zero if required ("01" to "12") |
62
+ +-----------+------------------------------------------------------------------------+
63
+ | ``%l`` | The month of the year between 1-12 ("1" to "12") |
64
+ +-----------+------------------------------------------------------------------------+
65
+ | ``%P`` | Format Persian calendar ("01 Farvardin 1392 00:00:00") |
66
+ +-----------+------------------------------------------------------------------------+
67
+ | ``%A`` | The full day name ("Monday" to "Sunday") |
68
+ +-----------+------------------------------------------------------------------------+
69
+ | ``%a`` | Abbreviated day name ("Mon" to "Sun") |
70
+ +-----------+------------------------------------------------------------------------+
71
+ | ``%E`` | The day of the month with a leading zero if required ("01" to "31") |
72
+ +-----------+------------------------------------------------------------------------+
73
+ | ``%e`` | The day of the month between 1 and 31 ("1" to "31") |
74
+ +-----------+------------------------------------------------------------------------+
75
+ | ``%I`` | The hour of the day with leading zero if required ("01" to "12") |
76
+ +-----------+------------------------------------------------------------------------+
77
+ | ``%M`` | The minute of the hour with leading zero if required ("00" to "59") |
78
+ +-----------+------------------------------------------------------------------------+
79
+ | ``%S`` | The seconds of the minute with leading zero if required ("00" to "59") |
80
+ +-----------+------------------------------------------------------------------------+
81
+ | ``%p`` | Displays the A.M./P.M. designator ("AM" or "PM") |
82
+ +-----------+------------------------------------------------------------------------+
83
+ | ``%Y`` | The full four digit year ("1999" or "2000") |
84
+ +-----------+------------------------------------------------------------------------+
85
+ | ``%y`` | The year as a two digit number ("99" or "00") |
86
+ +-----------+------------------------------------------------------------------------+
87
+
88
+ """
89
+ self.session.wialon_api.render_set_locale(
90
+ **{
91
+ "tzOffset": tz,
92
+ "language": lang,
93
+ "flags": flags,
94
+ "formatDate": date_fmt,
95
+ "density": density,
96
+ }
97
+ )
98
+
99
+
100
+ def main() -> None:
101
+ from terminusgps.wialon.maps.layers import WialonMapLayerPoi
102
+
103
+ with WialonSession() as session:
104
+ renderer = WialonMapRenderer(session.id)
105
+ layer = WialonMapLayerPoi(renderer, "terminusgps_office")
106
+ return
107
+
108
+
109
+ if __name__ == "__main__":
110
+ main()
@@ -2,7 +2,12 @@ from wialon.api import Wialon, WialonError
2
2
  from django.conf import settings
3
3
  from django.core.exceptions import ImproperlyConfigured
4
4
 
5
- from .errors import WialonLogoutError, WialonLoginError, WialonSessionDuplicationError
5
+ from .errors import (
6
+ WialonLogoutError,
7
+ WialonLoginError,
8
+ WialonSessionDuplicationError,
9
+ WialonSessionInvalidError,
10
+ )
6
11
 
7
12
 
8
13
  class WialonSession:
@@ -32,7 +37,6 @@ class WialonSession:
32
37
  raise ImproperlyConfigured("'WIALON_ADMIN_ID' setting is required.")
33
38
 
34
39
  self.wialon_api = Wialon(scheme=scheme, host=host, port=port, sid=sid)
35
- self.active = bool(sid)
36
40
  self.token = token
37
41
  self._username = None
38
42
  self._gis_sid = None
@@ -48,6 +52,24 @@ class WialonSession:
48
52
  def __exit__(self, *args, **kwargs) -> None:
49
53
  self.logout()
50
54
 
55
+ @property
56
+ def active(self) -> bool:
57
+ """
58
+ Whether or not the Wialon session is currently active.
59
+
60
+ :type: :py:obj:`bool`
61
+ :value: :py:obj:`False`
62
+ """
63
+ is_active = False
64
+
65
+ try:
66
+ response = self.wialon_api.core_duplicate(**{"restore": 1})
67
+ is_active = bool(response)
68
+ except WialonError as e:
69
+ raise WialonSessionInvalidError(self.id, e)
70
+ finally:
71
+ return is_active
72
+
51
73
  @property
52
74
  def gis_geocode(self) -> str | None:
53
75
  """
@@ -198,32 +220,31 @@ class WialonSession:
198
220
  def token(self, value: str | None = None) -> None:
199
221
  self._token = value if value else settings.WIALON_TOKEN
200
222
 
201
- def duplicate(
202
- self, user_id: str | None = None, continue_session: bool = False
203
- ) -> None:
223
+ def duplicate(self, username: str | None = None, continued: bool = False) -> str:
204
224
  """
205
225
  Duplicates the active Wialon API session.
206
226
 
207
- :param user_id: A Wialon user to operate as in the session.
208
- :type user_id: :py:obj:`str` | :py:obj:`None`
227
+ :param username: A Wialon user to operate as in the session.
228
+ :type username: :py:obj:`str` | :py:obj:`None`
209
229
  :param continue_session: Whether or not the original session id should be valid after duplication.
210
230
  :type continue_session: :py:obj:`bool`
211
231
  :raises WialonSessionDuplicationError: If the Wialon session was not duplicated.
212
- :returns: Nothing.
213
- :rtype: :py:obj:`None`
232
+ :raises AssertionError: If the session was already active.
233
+ :returns: The new session id.
234
+ :rtype: :py:obj:`str`
214
235
 
215
236
  """
216
237
  try:
217
- login_response = self.wialon_api.core_duplicate(
218
- **{"operateAs": user_id, "continueCurrentSession": continue_session}
238
+ assert self.active, "Cannot duplicate an inactive session."
239
+ response = self.wialon_api.core_duplicate(
240
+ **{"operateAs": username, "continueCurrentSession": continued}
219
241
  )
220
- except WialonError as e:
242
+ self._set_login_response(response)
243
+ return response.get("eid")
244
+ except (WialonError, AssertionError) as e:
221
245
  raise WialonSessionDuplicationError(self.id, e)
222
- else:
223
- self._set_login_response(login_response)
224
- self.active = True
225
246
 
226
- def login(self, token: str, flags: int = sum([0x1, 0x2, 0x20])) -> None:
247
+ def login(self, token: str, flags: int = sum([0x1, 0x2, 0x20])) -> str:
227
248
  """
228
249
  Logs into the Wialon API and starts a new session.
229
250
 
@@ -235,18 +256,17 @@ class WialonSession:
235
256
  :type flags: :py:obj:`int`
236
257
  :raises WialonLoginError: If the login fails.
237
258
  :raises AssertionError: If the session was already active.
238
- :returns: Nothing.
239
- :rtype: :py:obj:`None`
259
+ :returns: The new session id.
260
+ :rtype: :py:obj:`str`
240
261
 
241
262
  """
242
- assert not self.active, "Cannot login to an active session."
243
263
  try:
264
+ assert not self.active, "Cannot login to an active session."
244
265
  response = self.wialon_api.token_login(**{"token": token, "fl": flags})
245
- except WialonError as e:
246
- raise WialonLoginError(token, e)
247
- else:
248
266
  self._set_login_response(response)
249
- self.active = True
267
+ return response.get("eid")
268
+ except (WialonError, AssertionError) as e:
269
+ raise WialonLoginError(token, e)
250
270
 
251
271
  def logout(self) -> None:
252
272
  """
@@ -265,7 +285,7 @@ class WialonSession:
265
285
  """
266
286
  Sets the Wialon API session's attributes based on a login response.
267
287
 
268
- :param login_response: A Wialon API response to :py:meth:`login`.
288
+ :param login_response: A response returned from :py:meth:`login` or :py:meth:`duplicate`.
269
289
  :type login_response: :py:obj:`dict`
270
290
  :returns: Nothing.
271
291
  :rtype: :py:obj:`None`
@@ -289,8 +309,8 @@ class WialonSession:
289
309
 
290
310
  def main() -> None:
291
311
  session = WialonSession()
292
- session.login(settings.WIALON_TOKEN)
293
- session.duplicate(user_id="28944309")
312
+ session.login(token=settings.WIALON_TOKEN)
313
+ session.duplicate(username="chrissyron@gmail.com", continued=False)
294
314
  session.logout()
295
315
  return
296
316
 
@@ -38,10 +38,10 @@ def get_id_from_iccid(iccid: str, session: WialonSession) -> str | None:
38
38
  **{
39
39
  "spec": {
40
40
  "itemsType": "avl_unit",
41
- "propName": "sys_unique_id",
42
- "propValueMask": f"={iccid}",
43
- "sortType": "sys_unique_id",
44
- "propType": "property",
41
+ "propName": "rel_admin_field_value",
42
+ "propValueMask": str(iccid),
43
+ "sortType": "admin_fields",
44
+ "propType": "adminfield",
45
45
  "or_logic": 0,
46
46
  },
47
47
  "force": 0,
@@ -50,6 +50,18 @@ def get_id_from_iccid(iccid: str, session: WialonSession) -> str | None:
50
50
  "to": 0,
51
51
  }
52
52
  )
53
+ print(f"{response = }")
53
54
  if response.get("totalItemsCount", 0) != 1:
54
55
  return None
55
56
  return response["items"][0].get("id")
57
+
58
+
59
+ def main() -> None:
60
+ with WialonSession() as session:
61
+ wialon_id = get_id_from_iccid("89015809000307608963", session)
62
+ print(f"{wialon_id = }")
63
+ return
64
+
65
+
66
+ if __name__ == "__main__":
67
+ main()