smartx-rfid 1.6.0__tar.gz → 1.7.4__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 (40) hide show
  1. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/PKG-INFO +1 -1
  2. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/pyproject.toml +1 -1
  3. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/utils/tag_list.py +24 -8
  4. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/webhook/__init__.py +1 -1
  5. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/webhook/_main.py +66 -1
  6. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/webhook/xtrack.py +6 -1
  7. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/LICENSE +0 -0
  8. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/README.md +0 -0
  9. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/__init__.py +0 -0
  10. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/clients/rchlo.py +0 -0
  11. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/db/__init__.py +0 -0
  12. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/db/_main.py +0 -0
  13. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/devices/RFID/R700_IOT/_main.py +0 -0
  14. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/devices/RFID/R700_IOT/on_event.py +0 -0
  15. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/devices/RFID/R700_IOT/reader_config_example.py +0 -0
  16. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/devices/RFID/R700_IOT/reader_helpers.py +0 -0
  17. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/devices/RFID/R700_IOT/write_commands.py +0 -0
  18. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/devices/RFID/X714/_main.py +0 -0
  19. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/devices/RFID/X714/ble_protocol.py +0 -0
  20. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/devices/RFID/X714/on_receive.py +0 -0
  21. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/devices/RFID/X714/rfid.py +0 -0
  22. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/devices/RFID/X714/serial_protocol.py +0 -0
  23. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/devices/RFID/X714/tcp_protocol.py +0 -0
  24. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/devices/RFID/X714/write_commands.py +0 -0
  25. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/devices/__init__.py +0 -0
  26. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/devices/generic/SERIAL/_main.py +0 -0
  27. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/devices/generic/TCP/_main.py +0 -0
  28. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/devices/generic/TCP/helpers.py +0 -0
  29. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/parser/__init__.py +0 -0
  30. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/parser/main.py +0 -0
  31. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/parser/rfid_tag_parser/__init__.py +0 -0
  32. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/parser/rfid_tag_parser/exceptions.py +0 -0
  33. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/parser/rfid_tag_parser/tag_tid_parser.py +0 -0
  34. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/schemas/events.py +0 -0
  35. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/schemas/tag.py +0 -0
  36. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/utils/__init__.py +1 -1
  37. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/utils/event.py +0 -0
  38. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/utils/logger_manager.py +0 -0
  39. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/utils/path.py +0 -0
  40. {smartx_rfid-1.6.0 → smartx_rfid-1.7.4}/src/smartx_rfid/utils/regex.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: smartx-rfid
3
- Version: 1.6.0
3
+ Version: 1.7.4
4
4
  Summary: SmartX RFID library
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "smartx-rfid"
3
- version = "1.6.0"
3
+ version = "1.7.4"
4
4
  description = "SmartX RFID library"
5
5
  authors = ["Gabriel Henrique Pascon <gh.pascon@gmail.com>"]
6
6
  license = "MIT"
@@ -3,7 +3,7 @@ from datetime import datetime
3
3
  from threading import Lock
4
4
  import logging
5
5
  from pyepc import SGTIN
6
-
6
+ from smartx_rfid.schemas.tag import TagSchema
7
7
 
8
8
  class TagList:
9
9
  """
@@ -13,7 +13,7 @@ class TagList:
13
13
  Each tag is uniquely identified by either EPC or TID.
14
14
  """
15
15
 
16
- def __init__(self, unique_identifier: Literal["epc", "tid"] = "epc"):
16
+ def __init__(self, unique_identifier: Literal["epc", "tid"] = "epc", prefix: str | list | None = None):
17
17
  """
18
18
  Initialize the tag list.
19
19
 
@@ -27,6 +27,10 @@ class TagList:
27
27
  self._tags: Dict[str, Dict[str, Any]] = {}
28
28
  self._lock = Lock()
29
29
 
30
+ if isinstance(prefix, str):
31
+ prefix = [prefix]
32
+ self.prefix: list | None = prefix
33
+
30
34
  def __len__(self) -> int:
31
35
  """
32
36
  Return the number of stored tags.
@@ -55,20 +59,30 @@ class TagList:
55
59
  (False, None) if an error occurs;
56
60
  """
57
61
  try:
62
+ # Validate Tag
63
+ TagSchema.model_validate(tag)
64
+
58
65
  identifier_value = tag.get(self.unique_identifier)
59
66
  if not identifier_value:
60
67
  raise ValueError(f"Tag missing '{self.unique_identifier}'")
61
68
 
69
+ # Check Prefix
70
+ if self.prefix is not None:
71
+ epc = tag.get("epc")
72
+ if epc is None or not any(epc.startswith(p) for p in self.prefix):
73
+ return False, None
74
+
75
+ # handle tag
62
76
  with self._lock:
63
77
  if identifier_value not in self._tags:
64
78
  stored = self._new_tag(tag, device)
65
79
  return True, stored
66
80
  else:
67
- stored = self._existing_tag(tag)
81
+ stored = self._existing_tag(tag, device)
68
82
  return False, stored
69
83
 
70
84
  except Exception as e:
71
- logging.warning(f"[ TAG ERROR ] {e}")
85
+ logging.error(f"[ TAG ERROR ] {e}")
72
86
  return False, None
73
87
 
74
88
  def _new_tag(self, tag: Dict[str, Any], device: str) -> Dict[str, Any]:
@@ -90,18 +104,18 @@ class TagList:
90
104
  gtin = None
91
105
 
92
106
  stored_tag = {
93
- **tag,
94
- "device": device,
95
107
  "timestamp": now,
96
- "count": 1,
108
+ "device": device,
109
+ **tag,
97
110
  "gtin": gtin,
111
+ "count": 1,
98
112
  }
99
113
 
100
114
  self._tags[tag[self.unique_identifier]] = stored_tag
101
115
 
102
116
  return stored_tag
103
117
 
104
- def _existing_tag(self, tag: Dict[str, Any]) -> Dict[str, Any]:
118
+ def _existing_tag(self, tag: Dict[str, Any], device: str) -> Dict[str, Any]:
105
119
  """
106
120
  Update an existing tag.
107
121
 
@@ -122,6 +136,8 @@ class TagList:
122
136
  if old_rssi is None or abs(new_rssi) < abs(old_rssi):
123
137
  current["rssi"] = new_rssi
124
138
  current["ant"] = tag.get("ant")
139
+ current['device'] = device
140
+
125
141
 
126
142
  return current
127
143
 
@@ -1,2 +1,2 @@
1
1
  from ._main import WebhookManager
2
- from .xtrack import WebhookXtrack
2
+ from .xtrack import WebhookXtrack
@@ -1,6 +1,8 @@
1
1
  import asyncio
2
2
  import logging
3
3
  from typing import Optional, Dict, Any
4
+ from datetime import datetime, date
5
+ from decimal import Decimal
4
6
 
5
7
  import httpx
6
8
 
@@ -18,6 +20,66 @@ class WebhookManager:
18
20
 
19
21
  self.default_headers = {"Content-Type": "application/json", "User-Agent": "SmartX-Connector/1.0"}
20
22
 
23
+ def _make_serializable(self, obj: Any) -> Any:
24
+ """
25
+ Converts objects to JSON-serializable format.
26
+
27
+ Handles:
28
+ - datetime/date objects -> ISO format strings
29
+ - Decimal -> float
30
+ - Classes with __dict__ -> dict
31
+ - Sets -> lists
32
+ - Bytes -> string (decoded)
33
+ - Iterables -> lists
34
+
35
+ Args:
36
+ obj: Object to convert
37
+
38
+ Returns:
39
+ JSON-serializable version of the object
40
+ """
41
+ # Handle None
42
+ if obj is None:
43
+ return None
44
+
45
+ # Handle datetime and date
46
+ if isinstance(obj, (datetime, date)):
47
+ return obj.isoformat()
48
+
49
+ # Handle Decimal
50
+ if isinstance(obj, Decimal):
51
+ return float(obj)
52
+
53
+ # Handle bytes
54
+ if isinstance(obj, bytes):
55
+ try:
56
+ return obj.decode("utf-8")
57
+ except Exception:
58
+ return str(obj)
59
+
60
+ # Handle sets
61
+ if isinstance(obj, set):
62
+ return list(obj)
63
+
64
+ # Handle dictionaries (recursively)
65
+ if isinstance(obj, dict):
66
+ return {key: self._make_serializable(value) for key, value in obj.items()}
67
+
68
+ # Handle lists and tuples (recursively)
69
+ if isinstance(obj, (list, tuple)):
70
+ return [self._make_serializable(item) for item in obj]
71
+
72
+ # Handle objects with __dict__ (custom classes)
73
+ if hasattr(obj, "__dict__"):
74
+ return self._make_serializable(obj.__dict__)
75
+
76
+ # Handle primitive types (str, int, float, bool)
77
+ if isinstance(obj, (str, int, float, bool)):
78
+ return obj
79
+
80
+ # Last resort: convert to string
81
+ return str(obj)
82
+
21
83
  async def post(
22
84
  self, device: str, event_type: str, event_data: Any = None, headers: Optional[Dict[str, str]] = None
23
85
  ) -> bool:
@@ -38,7 +100,10 @@ class WebhookManager:
38
100
  logging.warning("⚠️ WEBHOOK_URL not configured in settings")
39
101
  return False
40
102
 
41
- payload = {"device": device, "event_type": event_type, "event_data": event_data}
103
+ # Convert event_data to JSON-serializable format
104
+ serializable_event_data = self._make_serializable(event_data)
105
+
106
+ payload = {"device": device, "event_type": event_type, "event_data": serializable_event_data}
42
107
 
43
108
  # Merge with custom headers if provided
44
109
  if headers:
@@ -9,9 +9,14 @@ class WebhookXtrack:
9
9
 
10
10
  async def post(self, tag: dict):
11
11
  try:
12
+ device = tag.get("device", "unknown")
13
+ ant = tag.get("ant", "1")
14
+ epc = tag.get("epc", None)
15
+ if epc is None:
16
+ raise Exception("EPC is required")
12
17
  payload = f"""<msg>
13
18
  <command>ReportRead</command>
14
- <data>EVENT=|DEVICENAME={tag.get("device", "")}|ANTENNANAME={tag.get("ant", "")}|TAGID={tag.get("epc", "")}|</data>
19
+ <data>EVENT=|DEVICENAME={device}|ANTENNANAME={ant}|TAGID={epc}|</data>
15
20
  <cmpl>STATE=|DATA1=|DATA2=|DATA3=|DATA4=|DATA5=|</cmpl>
16
21
  </msg>"""
17
22
  async with httpx.AsyncClient() as client:
File without changes
File without changes
@@ -1,3 +1,3 @@
1
+ from .regex import regex_hex
1
2
  from .tag_list import TagList
2
3
  from .logger_manager import LoggerManager
3
- from .regex import regex_hex