smartx-rfid 1.1.1__py3-none-any.whl → 1.5.4__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.
@@ -1,6 +1,6 @@
1
- import re
2
1
  from typing import Optional
3
2
  from pydantic import BaseModel, Field, field_validator
3
+ from smartx_rfid.utils import regex_hex
4
4
 
5
5
 
6
6
  class TagSchema(BaseModel):
@@ -15,7 +15,7 @@ class TagSchema(BaseModel):
15
15
  return v
16
16
  if len(v) != 24:
17
17
  raise ValueError(f"{field} must have exactly 24 characters")
18
- if not re.fullmatch(r"[0-9a-fA-F]{24}", v):
18
+ if not regex_hex(v, 24):
19
19
  raise ValueError(f"{field} must contain only hexadecimal characters (0-9, a-f)")
20
20
  return v.lower()
21
21
 
@@ -42,7 +42,7 @@ class WriteTagValidator(BaseModel):
42
42
 
43
43
  if len(v) != 24:
44
44
  raise ValueError(f"{field} must have exactly 24 characters")
45
- if not re.fullmatch(r"[0-9a-fA-F]{24}", v):
45
+ if not regex_hex(v, 24):
46
46
  raise ValueError(f"{field} must contain only hexadecimal characters (0-9, a-f)")
47
47
  return v.lower()
48
48
 
@@ -50,6 +50,6 @@ class WriteTagValidator(BaseModel):
50
50
  def validate_password_length_and_hex(cls, v, field):
51
51
  if len(v) != 8:
52
52
  raise ValueError(f"{field} must have exactly 8 characters")
53
- if not re.fullmatch(r"[0-9a-fA-F]{8}", v):
53
+ if not regex_hex(v, 8):
54
54
  raise ValueError(f"{field} must contain only hexadecimal characters (0-9, a-f)")
55
55
  return v.lower()
@@ -1,2 +1,3 @@
1
1
  from .tag_list import TagList
2
2
  from .logger_manager import LoggerManager
3
+ from .regex import regex_hex
smartx_rfid/utils/path.py CHANGED
@@ -84,10 +84,10 @@ def include_all_routers(current_path: str, app) -> None:
84
84
  logging.info(f"✅ Route loaded: {relative_path}")
85
85
 
86
86
  else:
87
- logging.warning(f"⚠️ File {current_path} does not define a 'router'")
87
+ logging.warning(f"⚠️ File {current_path}/{file_path.name} does not define a 'router'")
88
88
 
89
89
  except Exception as e:
90
- logging.error(f"❌ Error loading {current_path}: {e}", exc_info=True)
90
+ logging.error(f"❌ Error loading {current_path}/{file_path.name}: {e}", exc_info=True)
91
91
 
92
92
 
93
93
  def load_file(file_path: str | Path) -> str:
@@ -0,0 +1,9 @@
1
+ import re
2
+
3
+
4
+ def regex_hex(value: str, length: int = 24) -> bool:
5
+ """
6
+ Validate if the given value is a valid EPC (24 hexadecimal characters).
7
+ """
8
+ pattern = rf"^[0-9A-Fa-f]{{{length}}}$"
9
+ return bool(re.match(pattern, value))
@@ -27,6 +27,24 @@ class TagList:
27
27
  self._tags: Dict[str, Dict[str, Any]] = {}
28
28
  self._lock = Lock()
29
29
 
30
+ def __len__(self) -> int:
31
+ """
32
+ Return the number of stored tags.
33
+ """
34
+ return len(self._tags)
35
+
36
+ def __contains__(self, identifier: str) -> bool:
37
+ """
38
+ Check if a tag identifier exists in the list.
39
+ """
40
+ return identifier in self._tags
41
+
42
+ def __repr__(self) -> str:
43
+ """
44
+ Return a string representation of the stored tags.
45
+ """
46
+ return repr(self.get_all())
47
+
30
48
  def add(self, tag: Dict[str, Any], device: str = "Unknown") -> Tuple[bool, Optional[Dict[str, Any]]]:
31
49
  """
32
50
  Add or update a tag.
@@ -117,18 +135,26 @@ class TagList:
117
135
  with self._lock:
118
136
  return list(self._tags.values())
119
137
 
120
- def get_by_identifier(self, identifier: str) -> Optional[Dict[str, Any]]:
138
+ def get_by_identifier(self, identifier_value: str, identifier_type: str = "epc") -> Optional[Dict[str, Any]]:
121
139
  """
122
- Retrieve a tag by its unique identifier.
123
-
140
+ Retrieve a tag by its identifier.
124
141
  Args:
125
- identifier: EPC or TID value.
126
-
142
+ identifier_value: The value of the identifier (EPC or TID).
143
+ identifier_type: The type of identifier ("epc" or "tid").
127
144
  Returns:
128
145
  The tag dictionary if found, otherwise None.
129
146
  """
130
- with self._lock:
131
- return self._tags.get(identifier)
147
+ if identifier_type not in ("epc", "tid"):
148
+ identifier_type = "epc"
149
+
150
+ if self.unique_identifier == identifier_type:
151
+ return self._tags.get(identifier_value)
152
+
153
+ for tag in self._tags.values():
154
+ if tag.get(identifier_type) == identifier_value:
155
+ return tag
156
+
157
+ return None
132
158
 
133
159
  def clear(self) -> None:
134
160
  """
@@ -173,20 +199,29 @@ class TagList:
173
199
  return tag.get("tid")
174
200
  return None
175
201
 
176
- def __len__(self) -> int:
177
- """
178
- Return the number of stored tags.
202
+ def get_epcs(self) -> list[str]:
179
203
  """
180
- return len(self._tags)
204
+ Retrieve a list of all stored EPCs.
181
205
 
182
- def __contains__(self, identifier: str) -> bool:
183
- """
184
- Check if a tag identifier exists in the list.
206
+ Returns:
207
+ A list of EPC strings.
185
208
  """
186
- return identifier in self._tags
209
+ with self._lock:
210
+ return [tag["epc"] for tag in self._tags.values() if "epc" in tag]
187
211
 
188
- def __repr__(self) -> str:
212
+ def get_gtin_counts(self) -> Dict[str, int]:
189
213
  """
190
- Return a string representation of the stored tags.
214
+ Retrieve counts of tags grouped by GTIN.
215
+
216
+ Returns:
217
+ A dictionary mapping GTINs to their respective counts.
191
218
  """
192
- return repr(self.get_all())
219
+ gtin_counts: Dict[str, int] = {}
220
+ with self._lock:
221
+ for tag in self._tags.values():
222
+ gtin = tag.get("gtin")
223
+ if gtin is None:
224
+ gtin = "UNKNOWN"
225
+ gtin_counts[gtin] = gtin_counts.get(gtin, 0) + 1
226
+
227
+ return gtin_counts
@@ -0,0 +1 @@
1
+ from ._main import WebhookManager
@@ -0,0 +1,88 @@
1
+ import asyncio
2
+ import logging
3
+ from typing import Optional, Dict, Any
4
+
5
+ import httpx
6
+
7
+
8
+ class WebhookManager:
9
+ def __init__(
10
+ self,
11
+ url: str,
12
+ timeout: float = 5.0,
13
+ max_retries: int = 2,
14
+ ):
15
+ self.url = url
16
+ self.timeout = timeout
17
+ self.max_retries = max_retries
18
+
19
+ self.default_headers = {"Content-Type": "application/json", "User-Agent": "SmartX-Connector/1.0"}
20
+
21
+ async def post(
22
+ self, device: str, event_type: str, event_data: Any = None, headers: Optional[Dict[str, str]] = None
23
+ ) -> bool:
24
+ """
25
+ Sends data via POST to the configured webhook URL.
26
+
27
+ Args:
28
+ device: Name of the device sending the webhook
29
+ event_type: Type of event being sent
30
+ event_data: Data to be sent (will be converted to JSON)
31
+ headers: Optional headers for the request
32
+
33
+ Returns:
34
+ bool: True if sent successfully, False otherwise
35
+ """
36
+
37
+ if not self.url:
38
+ logging.warning("⚠️ WEBHOOK_URL not configured in settings")
39
+ return False
40
+
41
+ payload = {"device": device, "event_type": event_type, "event_data": event_data}
42
+
43
+ # Merge with custom headers if provided
44
+ if headers:
45
+ self.default_headers.update(headers)
46
+
47
+ retries = 0
48
+ last_error = None
49
+
50
+ while retries < self.max_retries:
51
+ try:
52
+ async with httpx.AsyncClient(timeout=self.timeout) as client:
53
+ response = await client.post(self.url, json=payload, headers=self.default_headers)
54
+
55
+ # Consider success if status 2xx
56
+ if response.status_code < 300:
57
+ logging.info(f"✅ Webhook sent successfully to {self.url} - Status: {response.status_code}")
58
+ return True
59
+ else:
60
+ logging.warning(
61
+ f"⚠️ Webhook failed - Status: {response.status_code} - Response: {response.text[:200]}"
62
+ )
63
+ return False
64
+
65
+ except httpx.TimeoutException:
66
+ last_error = f"Timeout after {self.timeout}s"
67
+ retries += 1
68
+ logging.warning(f"⏰ Webhook timeout (attempt {retries}/{self.max_retries})")
69
+
70
+ except httpx.ConnectError:
71
+ last_error = "Connection error"
72
+ retries += 1
73
+ logging.warning(f"🔌 Webhook connection error (attempt {retries}/{self.max_retries})")
74
+
75
+ except Exception as e:
76
+ last_error = str(e)
77
+ retries += 1
78
+ logging.error(f"❌ Webhook error (attempt {retries}/{self.max_retries}): {e}")
79
+
80
+ # Wait before retrying (exponential backoff)
81
+ if retries < self.max_retries:
82
+ wait_time = 2**retries # 2s, 4s, 8s...
83
+ logging.info(f"🔁 Retrying webhook in {wait_time}s...")
84
+ await asyncio.sleep(wait_time)
85
+
86
+ # If we reached here, all attempts failed
87
+ logging.error(f"❌ Webhook failed after {self.max_retries} attempts. Last error: {last_error}")
88
+ return False
@@ -0,0 +1,344 @@
1
+ Metadata-Version: 2.4
2
+ Name: smartx-rfid
3
+ Version: 1.5.4
4
+ Summary: SmartX RFID library
5
+ License: MIT
6
+ License-File: LICENSE
7
+ Keywords: python,library,RFID,smartx,packaging
8
+ Author: Gabriel Henrique Pascon
9
+ Author-email: gh.pascon@gmail.com
10
+ Requires-Python: >=3.11,<4.0
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
20
+ Requires-Dist: bleak (>=1.1.1,<2.0.0)
21
+ Requires-Dist: httpx (==0.28.1)
22
+ Requires-Dist: psycopg2 (>=2.9.11,<3.0.0)
23
+ Requires-Dist: pydantic (>=2.12.5,<3.0.0)
24
+ Requires-Dist: pyepc (==0.5.0)
25
+ Requires-Dist: pymysql (==1.1.1)
26
+ Requires-Dist: pyserial (==3.5)
27
+ Requires-Dist: pyserial-asyncio (==0.6)
28
+ Requires-Dist: sqlalchemy (==2.0.29)
29
+ Project-URL: Documentation, https://github.com/ghpascon/smartx_rfid#readme
30
+ Project-URL: Homepage, https://github.com/ghpascon/smartx_rfid
31
+ Project-URL: Repository, https://github.com/ghpascon/smartx_rfid
32
+ Description-Content-Type: text/markdown
33
+
34
+ # SmartX RFID
35
+
36
+ ![Python Version](https://img.shields.io/badge/python-3.11+-blue.svg)
37
+ ![Version](https://img.shields.io/badge/version-1.5.0-green.svg)
38
+ ![License](https://img.shields.io/badge/license-MIT-blue.svg)
39
+
40
+ Python library for RFID device integration and data management.
41
+
42
+ ## Installation
43
+
44
+ ```bash
45
+ pip install smartx-rfid
46
+ ```
47
+
48
+ ## Quick Start
49
+
50
+ ```python
51
+ from smartx_rfid.devices import X714
52
+ import asyncio
53
+
54
+ async def on_tag_read(name: str, tag_data: dict):
55
+ print(f"Tag: {tag_data['epc']} | RSSI: {tag_data['rssi']}dBm")
56
+
57
+ async def main():
58
+ reader = X714(name="RFID Reader", start_reading=True)
59
+ reader.on_event = lambda name, event_type, data: (
60
+ asyncio.create_task(on_tag_read(name, data))
61
+ if event_type == "tag" else None
62
+ )
63
+
64
+ await reader.connect()
65
+
66
+ while True:
67
+ await asyncio.sleep(1)
68
+
69
+ asyncio.run(main())
70
+ ```
71
+
72
+ ## Features
73
+
74
+ ### Supported Devices
75
+ - **X714 RFID Reader** - Serial, TCP, Bluetooth LE connections
76
+ - **R700 IOT** - HTTP REST API integration
77
+ - **Generic Serial/TCP** - Custom protocol support
78
+
79
+ ### Core Components
80
+ - **Device Management** - Async communication with auto-reconnection
81
+ - **Database Integration** - SQLAlchemy with multiple database support
82
+ - **Webhook System** - HTTP notifications with retry logic
83
+ - **Tag Management** - Thread-safe tag list with deduplication
84
+
85
+ ## Device Examples
86
+
87
+ ### X714 RFID Reader
88
+
89
+ ```python
90
+ from smartx_rfid.devices import X714
91
+
92
+ # Serial connection (auto-detect)
93
+ reader = X714(name="X714-Serial")
94
+
95
+ # TCP connection
96
+ reader = X714(
97
+ name="X714-TCP",
98
+ connection_type="TCP",
99
+ ip="192.168.1.100"
100
+ )
101
+
102
+ # Bluetooth LE
103
+ reader = X714(
104
+ name="X714-BLE",
105
+ connection_type="BLE"
106
+ )
107
+
108
+ def on_event(name: str, event_type: str, data: dict):
109
+ if event_type == "tag":
110
+ print(f"EPC: {data['epc']}, Antenna: {data['ant']}")
111
+
112
+ reader.on_event = on_event
113
+ await reader.connect()
114
+ ```
115
+
116
+ ### R700 IOT Reader
117
+
118
+ ```python
119
+ from smartx_rfid.devices import R700_IOT, R700_IOT_config_example
120
+
121
+ reader = R700_IOT(
122
+ name="R700-Reader",
123
+ ip="192.168.1.200",
124
+ config=R700_IOT_config_example
125
+ )
126
+
127
+ reader.on_event = on_event
128
+ await reader.connect()
129
+ ```
130
+
131
+ ## Database Integration
132
+
133
+ ```python
134
+ from smartx_rfid.db import DatabaseManager
135
+ from sqlalchemy import Column, String, Float, Integer, DateTime
136
+ from sqlalchemy.orm import DeclarativeBase
137
+ from datetime import datetime
138
+
139
+ class Base(DeclarativeBase):
140
+ pass
141
+
142
+ class TagModel(Base):
143
+ __tablename__ = 'rfid_tags'
144
+
145
+ id = Column(Integer, primary_key=True)
146
+ epc = Column(String(50), unique=True, nullable=False)
147
+ tid = Column(String(50))
148
+ ant = Column(Integer)
149
+ rssi = Column(Float)
150
+ created_at = Column(DateTime, default=datetime.utcnow)
151
+
152
+ # Initialize database
153
+ db = DatabaseManager("sqlite:///rfid_tags.db")
154
+ db.register_models(TagModel)
155
+ db.create_tables()
156
+
157
+ # Use with sessions
158
+ with db.get_session() as session:
159
+ tag = TagModel(epc="E200001175000001", ant=1, rssi=-45.2)
160
+ session.add(tag)
161
+
162
+ # Raw SQL queries
163
+ results = db.execute_query_fetchall(
164
+ "SELECT * FROM rfid_tags WHERE rssi > :threshold",
165
+ params={"threshold": -50}
166
+ )
167
+ ```
168
+
169
+ ### Supported Databases
170
+ - PostgreSQL: `postgresql://user:pass@localhost/db`
171
+ - MySQL: `mysql+pymysql://user:pass@localhost/db`
172
+ - SQLite: `sqlite:///path/to/database.db`
173
+
174
+ ## Webhook Integration
175
+
176
+ ```python
177
+ from smartx_rfid.webhook import WebhookManager
178
+
179
+ webhook = WebhookManager("https://api.example.com/rfid-events")
180
+
181
+ # Send tag data
182
+ success = await webhook.post("device_01", "tag_read", {
183
+ "epc": "E200001175000001",
184
+ "rssi": -45.2,
185
+ "antenna": 1,
186
+ "timestamp": "2026-01-15T10:30:00Z"
187
+ })
188
+
189
+ if success:
190
+ print("Webhook sent successfully")
191
+ ```
192
+
193
+ ## Tag Management
194
+
195
+ ```python
196
+ from smartx_rfid.utils import TagList
197
+
198
+ # Create thread-safe tag list
199
+ tags = TagList(unique_identifier="epc")
200
+
201
+ def on_tag(device: str, tag_data: dict):
202
+ new_tag, tag = tags.add(tag_data, device=device)
203
+
204
+ if new_tag:
205
+ print(f"New tag: {tag['epc']}")
206
+ # Add custom data
207
+ tag['product_name'] = "Widget ABC"
208
+ else:
209
+ print(f"Existing tag: {tag['epc']}")
210
+
211
+ # Use with device events
212
+ reader.on_event = lambda name, event_type, data: (
213
+ on_tag(name, data) if event_type == "tag" else None
214
+ )
215
+ ```
216
+
217
+ ## Complete Integration Example
218
+
219
+ ```python
220
+ import asyncio
221
+ from smartx_rfid.devices import X714
222
+ from smartx_rfid.db import DatabaseManager
223
+ from smartx_rfid.webhook import WebhookManager
224
+ from smartx_rfid.utils import TagList
225
+
226
+ async def rfid_system():
227
+ # Initialize components
228
+ reader = X714(name="Production-Scanner", start_reading=True)
229
+ db = DatabaseManager("postgresql://localhost/rfid_production")
230
+ webhook = WebhookManager("https://api.internal.com/rfid")
231
+ tags = TagList()
232
+
233
+ async def process_tag(name: str, tag_data: dict):
234
+ # Check if new tag
235
+ new_tag, tag = tags.add(tag_data, device=name)
236
+
237
+ if new_tag:
238
+ # Save to database
239
+ with db.get_session() as session:
240
+ session.add(TagModel(**tag_data))
241
+
242
+ # Send notification
243
+ await webhook.post(name, "new_tag", tag_data)
244
+ print(f"New tag processed: {tag_data['epc']}")
245
+
246
+ reader.on_event = lambda n, t, d: (
247
+ asyncio.create_task(process_tag(n, d)) if t == "tag" else None
248
+ )
249
+
250
+ await reader.connect()
251
+
252
+ asyncio.run(rfid_system())
253
+ ```
254
+
255
+ ## Configuration
256
+
257
+ ### Device Configuration
258
+ ```python
259
+ # High-performance settings
260
+ reader = X714(
261
+ name="FastScanner",
262
+ read_power=30, # Max power
263
+ session=2, # Session config
264
+ read_interval=100 # Fast scanning
265
+ )
266
+
267
+ # Database with connection pooling
268
+ db = DatabaseManager(
269
+ database_url="postgresql://user:pass@localhost/db",
270
+ pool_size=10,
271
+ max_overflow=20,
272
+ echo=True # Enable SQL logging
273
+ )
274
+ ```
275
+
276
+ ### Logging Setup
277
+ ```python
278
+ import logging
279
+
280
+ logging.basicConfig(
281
+ level=logging.INFO,
282
+ format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
283
+ )
284
+ ```
285
+
286
+ ## API Reference
287
+
288
+ ### Core Modules
289
+ - `smartx_rfid.devices` - Device communication classes
290
+ - `smartx_rfid.db` - Database management
291
+ - `smartx_rfid.webhook` - HTTP notification system
292
+ - `smartx_rfid.utils` - Utility classes and helpers
293
+
294
+ ### Event System
295
+ All devices use a consistent event callback system:
296
+
297
+ ```python
298
+ def on_event(device_name: str, event_type: str, event_data: dict):
299
+ """
300
+ Event types:
301
+ - "connected": Device connected successfully
302
+ - "disconnected": Device disconnected
303
+ - "tag": RFID tag detected
304
+ - "error": Error occurred
305
+ """
306
+ pass
307
+
308
+ device.on_event = on_event
309
+ ```
310
+
311
+ ## Examples
312
+
313
+ The `examples/` directory contains working examples for all supported devices and features:
314
+
315
+ ```
316
+ examples/
317
+ ├── devices/
318
+ │ ├── RFID/ # X714, R700_IOT examples
319
+ │ └── generic/ # Serial, TCP examples
320
+ ├── db/ # Database integration examples
321
+ └── utils/ # Tag management examples
322
+ ```
323
+
324
+ Run examples:
325
+ ```bash
326
+ python examples/devices/RFID/X714_SERIAL.py
327
+ python examples/db/showcase.py
328
+ ```
329
+
330
+ ## Requirements
331
+
332
+ - Python 3.11+
333
+ - Dependencies automatically installed with pip
334
+
335
+ ## License
336
+
337
+ MIT License
338
+
339
+ ## Support
340
+
341
+ - **Repository**: [https://github.com/ghpascon/smartx_rfid](https://github.com/ghpascon/smartx_rfid)
342
+ - **Issues**: [GitHub Issues](https://github.com/ghpascon/smartx_rfid/issues)
343
+ - **Email**: [gh.pascon@gmail.com](mailto:gh.pascon@gmail.com)
344
+
@@ -1,4 +1,7 @@
1
1
  smartx_rfid/__init__.py,sha256=XCdKdP8o5LT3VjJtWOuFHJzztc0FXt3Ms89qsx0p6sM,282
2
+ smartx_rfid/clients/rchlo.py,sha256=z2xT9YnNEwkbHSeHsJD9BZvSJZ5QtnHZ9R7SpQ21Jxk,221
3
+ smartx_rfid/db/__init__.py,sha256=P8rsrVgc_5NDMH_p4FDs5OBLe3ohaQNR_sadVaeNvxA,35
4
+ smartx_rfid/db/_main.py,sha256=pKzJnkTb6VVSbKd8E34us4SAAKxyTGsE_diE_AxJShY,15450
2
5
  smartx_rfid/devices/RFID/R700_IOT/_main.py,sha256=VL2yDBCXp8Avb3PXKZyBNwtBRhwlLQb5TSs3aTUeC6w,7458
3
6
  smartx_rfid/devices/RFID/R700_IOT/on_event.py,sha256=bG_33gY2ZHXquUbezXyMN0dyHO9SBwc36DPTc8iXc1U,799
4
7
  smartx_rfid/devices/RFID/R700_IOT/reader_config_example.py,sha256=oi4vg3_zjYFDUeq1Y_d5InUx_Rq5M2CB5RDVkK3WCgU,2264
@@ -6,7 +9,7 @@ smartx_rfid/devices/RFID/R700_IOT/reader_helpers.py,sha256=8CvvYeKGplWqceVH5mEMN
6
9
  smartx_rfid/devices/RFID/R700_IOT/write_commands.py,sha256=GMROeq_daTScj4NZygF45UM9t0Pr3E6ugmrb7OlF73w,2284
7
10
  smartx_rfid/devices/RFID/X714/_main.py,sha256=LP1X_w6Sy9m5kHLvbaRUNZbzQJU37fS8OIEWvOfrk7M,6371
8
11
  smartx_rfid/devices/RFID/X714/ble_protocol.py,sha256=M3Cs66WX6oa_EPdMTLEjD-IRxAjpfrKzGj4hn1vxlxQ,6951
9
- smartx_rfid/devices/RFID/X714/on_receive.py,sha256=Tr8KISrblB4fsLCgGTIi7TltXlyxMS8YMXLRhM9SVTg,2194
12
+ smartx_rfid/devices/RFID/X714/on_receive.py,sha256=frrZIwSSDrsOjLO2GHdShVhoC-2VvHtr_AkJU91VDIo,2133
10
13
  smartx_rfid/devices/RFID/X714/rfid.py,sha256=XgHl2evlN3tGB6hhCUYzpEy_jw2dyplxUcDYsuPec2Q,2285
11
14
  smartx_rfid/devices/RFID/X714/serial_protocol.py,sha256=eOGM5sK35SxXfS9KjB8JQzYhR1qs4H3vw3-n3oPOjQQ,3681
12
15
  smartx_rfid/devices/RFID/X714/tcp_protocol.py,sha256=GthynyN6YMl6R16nrAnlrDK61QnuZAOhYhPqycBCwJA,4804
@@ -15,13 +18,22 @@ smartx_rfid/devices/__init__.py,sha256=EVhtb-IBLpits8dr-I1ZYYuWHw9ddqiu-98myg-iy
15
18
  smartx_rfid/devices/generic/SERIAL/_main.py,sha256=7rEgviwxfd4uWpWjVXsV0qnOAET-MxJux9PcTKiE8G8,8562
16
19
  smartx_rfid/devices/generic/TCP/_main.py,sha256=DY9c9m2ZchvUJ9n2TtPENL2GqCYS4hvdjkCAe6yGXxM,2770
17
20
  smartx_rfid/devices/generic/TCP/helpers.py,sha256=GQ_yIvmSlx_yZci6pVvZfdo1wyKcS5gtZh-VDwt3pGs,1552
18
- smartx_rfid/schemas/tag.py,sha256=iSQkWI4MhSSVEzWhezX6UG4KJJ-FUahrfj0Hnz-H_u0,2269
19
- smartx_rfid/utils/__init__.py,sha256=lJA0KqFIFVDtietXGH9WwnklKkiTNvhIG6YJdDd11vk,72
21
+ smartx_rfid/parser/__init__.py,sha256=KByVPGCuGVvil8XtF0hUeLyQfyqcuKvHJwv2au2I8Zg,38
22
+ smartx_rfid/parser/main.py,sha256=66RPYIWMy7m3ir6yTprlk1Br5iBCvNHyYNAEeVsuFR8,601
23
+ smartx_rfid/parser/rfid_tag_parser/__init__.py,sha256=_voIeFw0Y3_ooEqwOEhakJyP_PRxsKWKK0K2s1c4g_E,506
24
+ smartx_rfid/parser/rfid_tag_parser/exceptions.py,sha256=QsiXv0IHGYsLhYGgx2D-yE0jjTHgw9IFaH59J1QQc-g,282
25
+ smartx_rfid/parser/rfid_tag_parser/tag_tid_parser.py,sha256=uw-h7sYrH4Tfum_E9FyCRQKQMBlr5Igtjab99sJwxvA,23396
26
+ smartx_rfid/schemas/events.py,sha256=1iX0iSGirMqDbUAi2ir1CDhtVp8ROg-KZ6tY5nppWek,243
27
+ smartx_rfid/schemas/tag.py,sha256=haMvu_ALhkba8AIL-DrQN0egkRqeP3Wr8AyzyOnWH4Q,2242
28
+ smartx_rfid/utils/__init__.py,sha256=TllHEfkXJjmBwdwjPJqzbPn4hfCeqmTNOw6vHgzC-wU,101
20
29
  smartx_rfid/utils/event.py,sha256=7QOdiSfiMscoAaTq4U3E3asYGSVnolr9OD3FSYGh6bg,469
21
30
  smartx_rfid/utils/logger_manager.py,sha256=61HJ40wgX0hVwG4xW66IQ2jdJp8CFM_S0eoGzx8-FwU,5653
22
- smartx_rfid/utils/path.py,sha256=7U619vOw4BXGAKbSVdA6ZIhpCN0f-dccVax9LCclbNc,3758
23
- smartx_rfid/utils/tag_list.py,sha256=JDWJa63LA9xpEBmsjAe129WTn4UjZsSCs7OabhFYZn8,5368
24
- smartx_rfid-1.1.1.dist-info/METADATA,sha256=9waOGm6Aui10ybdDM4xM-XRVHfVi45EBQPs_eLzITE4,2636
25
- smartx_rfid-1.1.1.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
26
- smartx_rfid-1.1.1.dist-info/licenses/LICENSE,sha256=npGJO3HuHM3JdFNEXv1jRmP_wRYq9-ujkqJPmLxrtEw,1080
27
- smartx_rfid-1.1.1.dist-info/RECORD,,
31
+ smartx_rfid/utils/path.py,sha256=eRxXKNzzDELna3USfGPNG1EPP2EkLlFxHmf21BMWAgA,3792
32
+ smartx_rfid/utils/regex.py,sha256=vxMR0PbZ6JxRHk2AAA9L3z98uZgrsVqslDFLcxC7P9Q,243
33
+ smartx_rfid/utils/tag_list.py,sha256=_AP0ITue9JHTaDBGC2VYjXfr6qcJZQdEHm0Yp2sC_-8,6550
34
+ smartx_rfid/webhook/__init__.py,sha256=IO_xPVNOfY8nsE60yajjbXqyqVR66BIFuQoNMuKY_j4,34
35
+ smartx_rfid/webhook/_main.py,sha256=FyP5-jFnT9_27_3Sa3ltpeQ4FkC9vlajzzrObXQmmzY,3213
36
+ smartx_rfid-1.5.4.dist-info/METADATA,sha256=QH-nnV_HQyWUhDq1uHeLbJM0fBZe0cnzatbNykHOJZM,8705
37
+ smartx_rfid-1.5.4.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
38
+ smartx_rfid-1.5.4.dist-info/licenses/LICENSE,sha256=npGJO3HuHM3JdFNEXv1jRmP_wRYq9-ujkqJPmLxrtEw,1080
39
+ smartx_rfid-1.5.4.dist-info/RECORD,,