smartx-rfid 1.0.0__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 (27) hide show
  1. smartx_rfid-1.0.0/LICENSE +21 -0
  2. smartx_rfid-1.0.0/PKG-INFO +83 -0
  3. smartx_rfid-1.0.0/README.md +52 -0
  4. smartx_rfid-1.0.0/pyproject.toml +67 -0
  5. smartx_rfid-1.0.0/src/smartx_rfid/__init__.py +9 -0
  6. smartx_rfid-1.0.0/src/smartx_rfid/devices/RFID/R700_IOT/_main.py +202 -0
  7. smartx_rfid-1.0.0/src/smartx_rfid/devices/RFID/R700_IOT/on_event.py +26 -0
  8. smartx_rfid-1.0.0/src/smartx_rfid/devices/RFID/R700_IOT/reader_config_example.py +69 -0
  9. smartx_rfid-1.0.0/src/smartx_rfid/devices/RFID/R700_IOT/reader_helpers.py +146 -0
  10. smartx_rfid-1.0.0/src/smartx_rfid/devices/RFID/R700_IOT/write_commands.py +70 -0
  11. smartx_rfid-1.0.0/src/smartx_rfid/devices/RFID/X714/_main.py +186 -0
  12. smartx_rfid-1.0.0/src/smartx_rfid/devices/RFID/X714/ble_protocol.py +159 -0
  13. smartx_rfid-1.0.0/src/smartx_rfid/devices/RFID/X714/on_receive.py +74 -0
  14. smartx_rfid-1.0.0/src/smartx_rfid/devices/RFID/X714/rfid.py +79 -0
  15. smartx_rfid-1.0.0/src/smartx_rfid/devices/RFID/X714/serial_protocol.py +89 -0
  16. smartx_rfid-1.0.0/src/smartx_rfid/devices/RFID/X714/tcp_protocol.py +127 -0
  17. smartx_rfid-1.0.0/src/smartx_rfid/devices/RFID/X714/write_commands.py +35 -0
  18. smartx_rfid-1.0.0/src/smartx_rfid/devices/__init__.py +8 -0
  19. smartx_rfid-1.0.0/src/smartx_rfid/devices/generic/SERIAL/_main.py +246 -0
  20. smartx_rfid-1.0.0/src/smartx_rfid/devices/generic/TCP/_main.py +90 -0
  21. smartx_rfid-1.0.0/src/smartx_rfid/devices/generic/TCP/helpers.py +45 -0
  22. smartx_rfid-1.0.0/src/smartx_rfid/schemas/tag.py +55 -0
  23. smartx_rfid-1.0.0/src/smartx_rfid/utils/__init__.py +2 -0
  24. smartx_rfid-1.0.0/src/smartx_rfid/utils/event.py +15 -0
  25. smartx_rfid-1.0.0/src/smartx_rfid/utils/logger_manager.py +167 -0
  26. smartx_rfid-1.0.0/src/smartx_rfid/utils/path.py +110 -0
  27. smartx_rfid-1.0.0/src/smartx_rfid/utils/tag_list.py +192 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Gabriel Henrique Pascon
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,83 @@
1
+ Metadata-Version: 2.4
2
+ Name: smartx-rfid
3
+ Version: 1.0.0
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: pydantic (>=2.12.5,<3.0.0)
23
+ Requires-Dist: pyepc (==0.5.0)
24
+ Requires-Dist: pyserial (==3.5)
25
+ Requires-Dist: pyserial-asyncio (==0.6)
26
+ Project-URL: Documentation, https://github.com/ghpascon/smartx_rfid#readme
27
+ Project-URL: Homepage, https://github.com/ghpascon/smartx_rfid
28
+ Project-URL: Repository, https://github.com/ghpascon/smartx_rfid
29
+ Description-Content-Type: text/markdown
30
+
31
+ # SmartX RFID
32
+
33
+ The official SmartX RFID Python library for seamless integration with RFID systems and devices.
34
+
35
+ ## Overview
36
+
37
+ SmartX RFID is a comprehensive Python package designed to provide easy-to-use interfaces for RFID operations and device management. This library serves as the foundation for building robust RFID applications.
38
+
39
+ ## Features (Current & Planned)
40
+
41
+ - **Device Communication**: Asynchronous serial communication with RFID devices
42
+ - **Auto-Detection**: Automatic port detection for USB devices by VID/PID
43
+ - **Connection Management**: Automatic reconnection and error handling
44
+ - **External Device Support**: Interface with various RFID readers and writers *(coming soon)*
45
+ - **Tag Operations**: Read, write, and manage RFID tags *(coming soon)*
46
+ - **Protocol Support**: Multiple RFID protocols and standards *(coming soon)*
47
+
48
+ ## Installation
49
+
50
+ ```bash
51
+ pip install smartx-rfid
52
+ ```
53
+
54
+ ## Quick Start
55
+
56
+ ```python
57
+ from smartx_rfid.devices import SERIAL
58
+ import asyncio
59
+
60
+ async def main():
61
+ device = SERIAL(name="MyRFIDDevice")
62
+ await device.connect()
63
+
64
+ asyncio.run(main())
65
+ ```
66
+
67
+ ## Development Status
68
+
69
+ This library is actively under development. Current focus areas include:
70
+
71
+ - Core device communication protocols
72
+ - External device integration
73
+ - Enhanced error handling
74
+ - Comprehensive documentation
75
+
76
+ ## License
77
+
78
+ MIT License
79
+
80
+ ## Support
81
+
82
+ For issues and support, please visit our [GitHub repository](https://github.com/ghpascon/smartx_rfid).
83
+
@@ -0,0 +1,52 @@
1
+ # SmartX RFID
2
+
3
+ The official SmartX RFID Python library for seamless integration with RFID systems and devices.
4
+
5
+ ## Overview
6
+
7
+ SmartX RFID is a comprehensive Python package designed to provide easy-to-use interfaces for RFID operations and device management. This library serves as the foundation for building robust RFID applications.
8
+
9
+ ## Features (Current & Planned)
10
+
11
+ - **Device Communication**: Asynchronous serial communication with RFID devices
12
+ - **Auto-Detection**: Automatic port detection for USB devices by VID/PID
13
+ - **Connection Management**: Automatic reconnection and error handling
14
+ - **External Device Support**: Interface with various RFID readers and writers *(coming soon)*
15
+ - **Tag Operations**: Read, write, and manage RFID tags *(coming soon)*
16
+ - **Protocol Support**: Multiple RFID protocols and standards *(coming soon)*
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ pip install smartx-rfid
22
+ ```
23
+
24
+ ## Quick Start
25
+
26
+ ```python
27
+ from smartx_rfid.devices import SERIAL
28
+ import asyncio
29
+
30
+ async def main():
31
+ device = SERIAL(name="MyRFIDDevice")
32
+ await device.connect()
33
+
34
+ asyncio.run(main())
35
+ ```
36
+
37
+ ## Development Status
38
+
39
+ This library is actively under development. Current focus areas include:
40
+
41
+ - Core device communication protocols
42
+ - External device integration
43
+ - Enhanced error handling
44
+ - Comprehensive documentation
45
+
46
+ ## License
47
+
48
+ MIT License
49
+
50
+ ## Support
51
+
52
+ For issues and support, please visit our [GitHub repository](https://github.com/ghpascon/smartx_rfid).
@@ -0,0 +1,67 @@
1
+ [tool.poetry]
2
+ name = "smartx-rfid"
3
+ version = "1.0.0"
4
+ description = "SmartX RFID library"
5
+ authors = ["Gabriel Henrique Pascon <gh.pascon@gmail.com>"]
6
+ license = "MIT"
7
+ readme = "README.md"
8
+ homepage = "https://github.com/ghpascon/smartx_rfid"
9
+ repository = "https://github.com/ghpascon/smartx_rfid"
10
+ documentation = "https://github.com/ghpascon/smartx_rfid#readme"
11
+ keywords = ["python", "library", "RFID", "smartx", "packaging"]
12
+ classifiers = [
13
+ "Intended Audience :: Developers",
14
+ "Operating System :: OS Independent",
15
+ "Programming Language :: Python :: 3",
16
+ "Programming Language :: Python :: 3.11",
17
+ "Topic :: Software Development :: Libraries :: Python Modules",
18
+ ]
19
+ packages = [{include = "smartx_rfid", from = "src"}]
20
+
21
+ [tool.poetry.dependencies]
22
+ python = "^3.11"
23
+ pyserial-asyncio = "0.6"
24
+ pyserial = "3.5"
25
+ pyepc = "0.5.0"
26
+ httpx = "0.28.1"
27
+ bleak = "^1.1.1"
28
+ pydantic = "^2.12.5"
29
+
30
+ [tool.poetry.group.dev.dependencies]
31
+ pytest = "^7.4.0"
32
+ pytest-cov = "^4.1.0"
33
+ pytest-asyncio = "^0.21.0"
34
+ twine = "^4.0.0"
35
+ ruff = "^0.14.11"
36
+
37
+ [tool.poetry.group.build.dependencies]
38
+ build = "^1.0.0"
39
+
40
+ [build-system]
41
+ requires = ["poetry-core>=1.0.0"]
42
+ build-backend = "poetry.core.masonry.api"
43
+
44
+ [tool.ruff]
45
+ line-length = 120
46
+ target-version = "py311"
47
+ exclude = ["build", "dist", ".venv", "__pycache__"] # pastas a ignorar
48
+
49
+ # Por arquivo
50
+ [tool.ruff.lint.per-file-ignores]
51
+ "__init__.py" = ["F401"] # permite imports não usados em __init__.py para re-exportações
52
+
53
+ [tool.pytest.ini_options]
54
+ testpaths = ["tests"]
55
+ python_files = ["test_*.py", "*_test.py"]
56
+ python_classes = ["Test*"]
57
+ python_functions = ["test_*"]
58
+ addopts = [
59
+ "--strict-markers",
60
+ "--strict-config",
61
+ "--verbose",
62
+ ]
63
+ markers = [
64
+ "slow: marks tests as slow (deselect with '-m \"not slow\"')",
65
+ "integration: marks tests as integration tests",
66
+ "asyncio: marks tests as asyncio tests",
67
+ ]
@@ -0,0 +1,9 @@
1
+ """publish_lib_ghp - A simple Python library demonstrating how to publish packages to PyPI."""
2
+
3
+ from importlib.metadata import version
4
+
5
+ try:
6
+ __version__ = version("publish-lib-example")
7
+ except Exception:
8
+ # Fallback for development environments
9
+ __version__ = "0.0.0-dev"
@@ -0,0 +1,202 @@
1
+ import asyncio
2
+ import logging
3
+
4
+ import httpx
5
+
6
+ from smartx_rfid.schemas.tag import WriteTagValidator
7
+ from smartx_rfid.utils.event import on_event
8
+
9
+ from .on_event import OnEvent
10
+ from .reader_helpers import ReaderHelpers
11
+ from .write_commands import WriteCommands
12
+ from .reader_config_example import R700_IOT_config_example
13
+
14
+
15
+ class R700_IOT(OnEvent, ReaderHelpers, WriteCommands):
16
+ """Impinj R700 RFID reader using HTTP REST API."""
17
+
18
+ def __init__(
19
+ self,
20
+ # READER CONFIG
21
+ reading_config: dict,
22
+ name: str = "R700",
23
+ # CONNECTION
24
+ ip: str = "192.168.1.101", # Example hotsname: impinj-14-46-36
25
+ username: str = "root",
26
+ password: str = "impinj",
27
+ start_reading: bool = False,
28
+ # Firmware Version
29
+ firmware_version: str = "8.4.1",
30
+ ):
31
+ """
32
+ Create R700 RFID reader.
33
+
34
+ Args:
35
+ reading_config: Configuration for tag reading
36
+ name: Device name
37
+ ip: IP address of reader
38
+ username: Login username
39
+ password: Login password
40
+ start_reading: Start reading tags automatically
41
+ firmware_version: Expected firmware version
42
+ """
43
+ self.name = name
44
+ self.device_type = "rfid"
45
+
46
+ self.ip = ip
47
+ self.username = username
48
+ self.password = password
49
+
50
+ self.start_reading = start_reading
51
+
52
+ # URL AND ENDPOINTS
53
+ self.urlBase = f"https://{self.ip}/api/v1"
54
+ self.endpoint_interface = f"{self.urlBase}/system/rfid/interface"
55
+ self.check_version_endpoint = f"{self.urlBase}/system/image"
56
+ self.endpoint_start = f"{self.urlBase}/profiles/inventory/start"
57
+ self.endpoint_stop = f"{self.urlBase}/profiles/stop"
58
+ self.endpointDataStream = f"{self.urlBase}/data/stream"
59
+ self.endpoint_gpo = f"{self.urlBase}/device/gpos"
60
+ self.endpoint_write = f"{self.urlBase}/profiles/inventory/tag-access"
61
+
62
+ self.interface_config = {"rfidInterface": "rest"}
63
+ self.auth = httpx.BasicAuth(self.username, self.password)
64
+
65
+ self.tags_to_write = {}
66
+
67
+ self.is_connected = False
68
+ self.is_reading = False
69
+ self._stop_connection = False
70
+
71
+ self.firmware_version = firmware_version
72
+
73
+ self.reading_config = reading_config
74
+ self.config_example = R700_IOT_config_example
75
+
76
+ self.on_event = on_event
77
+
78
+ async def disconnect(self):
79
+ """Safely disconnect from reader and stop reading."""
80
+ """Desconecta o reader de forma segura."""
81
+ logging.info(f"{self.name} 🔌 Disconnecting reader")
82
+ self._stop_connection = True
83
+
84
+ if self.is_reading:
85
+ try:
86
+ async with httpx.AsyncClient(auth=self.auth, verify=False, timeout=5.0) as session:
87
+ await self.stop_inventory(session)
88
+ except Exception as e:
89
+ logging.warning(f"{self.name} ⚠️ Error stopping inventory during disconnect: {e}")
90
+
91
+ self.is_connected = False
92
+ self.is_reading = False
93
+ self.on_event(self.name, "reading", False)
94
+ self.on_event(self.name, "connection", False)
95
+
96
+ async def connect(self):
97
+ """Connect to R700 reader and start tag reading."""
98
+ self._stop_connection = False
99
+ while not self._stop_connection:
100
+ async with httpx.AsyncClient(auth=self.auth, verify=False, timeout=10.0) as session:
101
+ if self.is_connected:
102
+ self.on_event(self.name, "connection", False)
103
+
104
+ self.is_connected = False
105
+ self.is_reading = False
106
+
107
+ # Configure interface
108
+ success = await self.configure_interface(session)
109
+ if not success:
110
+ logging.warning(f"{self.name} - Failed to configure interface")
111
+ await asyncio.sleep(1)
112
+ continue
113
+
114
+ # Check firmware version
115
+ success = await self.check_firmware_version(session)
116
+ if not success:
117
+ logging.warning(
118
+ f"{self.name} - Incompatible firmware version. Update R700 firmware to {self.firmware_version}."
119
+ )
120
+ await asyncio.sleep(5)
121
+ continue
122
+
123
+ # Stop any ongoing profiles
124
+ success = await self.stop_inventory(session)
125
+ if not success:
126
+ logging.warning(f"{self.name} - Failed to stop profiles")
127
+ await asyncio.sleep(1)
128
+ continue
129
+
130
+ if self.start_reading or self.reading_config.get("startTriggers"):
131
+ success = await self.start_inventory(session)
132
+ if not success:
133
+ logging.warning(f"{self.name} - Failed to start inventory")
134
+ await asyncio.sleep(1)
135
+ continue
136
+ if self.start_reading:
137
+ self.is_reading = True
138
+ self.on_event(self.name, "reading", True)
139
+
140
+ # Clear GPO states
141
+ for i in range(1, 4):
142
+ asyncio.create_task(self.write_gpo(pin=i, state=False))
143
+
144
+ self.is_connected = True
145
+ self.on_event(self.name, "connection", True)
146
+ await self.get_tag_list(session)
147
+
148
+ async def clear_tags(self):
149
+ """Clear all stored tags from memory."""
150
+ self.tags = {}
151
+
152
+ async def write_gpo(
153
+ self,
154
+ pin: int = 1,
155
+ state: bool | str = True,
156
+ control: str = "static",
157
+ time: int = 1000,
158
+ *args,
159
+ **kwargs,
160
+ ):
161
+ """
162
+ Control GPO (output) pins on reader.
163
+
164
+ Args:
165
+ pin: GPO pin number
166
+ state: Turn pin on (True) or off (False)
167
+ control: Control type (static or pulse)
168
+ time: Pulse duration in milliseconds
169
+ """
170
+ gpo_command = await self.get_gpo_command(pin=pin, state=state, control=control, time=time)
171
+ try:
172
+ async with httpx.AsyncClient(auth=self.auth, verify=False, timeout=10.0) as session:
173
+ await self.post_to_reader(session, self.endpoint_gpo, payload=gpo_command, method="put")
174
+ except Exception as e:
175
+ logging.warning(f"{self.name} - Failed to set GPO: {e}")
176
+
177
+ def write_epc(self, target_identifier: str | None, target_value: str | None, new_epc: str, password: str):
178
+ """
179
+ Write new EPC code to RFID tag.
180
+
181
+ Args:
182
+ target_identifier: How to find tag (epc, tid, user)
183
+ target_value: Current tag value to match
184
+ new_epc: New EPC code to write
185
+ password: Tag access password
186
+ """
187
+ """
188
+ Writes a new EPC (Electronic Product Code) to RFID tags.
189
+ """
190
+ try:
191
+ validated_tag = WriteTagValidator(
192
+ target_identifier=target_identifier,
193
+ target_value=target_value,
194
+ new_epc=new_epc,
195
+ password=password,
196
+ )
197
+ logging.info(
198
+ f"{self.name} - Writing EPC: {validated_tag.new_epc} (Current: {validated_tag.target_identifier}={validated_tag.target_value})"
199
+ )
200
+ asyncio.create_task(self.send_write_command(validated_tag.model_dump()))
201
+ except Exception as e:
202
+ logging.warning(f"{self.name} - Write validation error: {e}")
@@ -0,0 +1,26 @@
1
+ class OnEvent:
2
+ """Handle R700 reader events."""
3
+
4
+ async def on_start(self):
5
+ """Called when reader starts reading tags."""
6
+ self.is_reading = True
7
+ self.on_event(self.name, "reading", True)
8
+
9
+ async def on_stop(self):
10
+ """Called when reader stops reading tags."""
11
+ self.is_reading = False
12
+ self.on_event(self.name, "reading", False)
13
+
14
+ async def on_tag(self, tag):
15
+ """Process detected RFID tag data.
16
+
17
+ Args:
18
+ tag: Raw tag data from reader API
19
+ """
20
+ current_tag = {
21
+ "epc": tag.get("epcHex"),
22
+ "tid": tag.get("tidHex"),
23
+ "ant": tag.get("antennaPort"),
24
+ "rssi": int(tag.get("peakRssiCdbm", 0) / 100),
25
+ }
26
+ self.on_event(self.name, "tag", current_tag)
@@ -0,0 +1,69 @@
1
+ R700_IOT_config_example = {
2
+ "antennaConfigs": [
3
+ {
4
+ "antennaPort": 1,
5
+ "estimatedTagPopulation": 16,
6
+ "fastId": "enabled",
7
+ "inventorySearchMode": "dual-target",
8
+ "inventorySession": 1,
9
+ "receiveSensitivityDbm": -80,
10
+ "rfMode": 4,
11
+ "transmitPowerCdbm": 3300,
12
+ },
13
+ {
14
+ "antennaPort": 2,
15
+ "estimatedTagPopulation": 16,
16
+ "fastId": "enabled",
17
+ "inventorySearchMode": "dual-target",
18
+ "inventorySession": 1,
19
+ "receiveSensitivityDbm": -80,
20
+ "rfMode": 4,
21
+ "transmitPowerCdbm": 3300,
22
+ },
23
+ {
24
+ "antennaPort": 3,
25
+ "estimatedTagPopulation": 16,
26
+ "fastId": "enabled",
27
+ "inventorySearchMode": "dual-target",
28
+ "inventorySession": 1,
29
+ "receiveSensitivityDbm": -80,
30
+ "rfMode": 4,
31
+ "transmitPowerCdbm": 3300,
32
+ },
33
+ {
34
+ "antennaPort": 4,
35
+ "estimatedTagPopulation": 16,
36
+ "fastId": "enabled",
37
+ "inventorySearchMode": "dual-target",
38
+ "inventorySession": 1,
39
+ "receiveSensitivityDbm": -80,
40
+ "rfMode": 4,
41
+ "transmitPowerCdbm": 3300,
42
+ },
43
+ ],
44
+ "startTriggers": [{"gpiTransitionEvent": {"gpi": 1, "transition": "high-to-low"}}],
45
+ "stopTriggers": [{"gpiTransitionEvent": {"gpi": 1, "transition": "low-to-high"}}],
46
+ "eventConfig": {
47
+ "common": {"hostname": "disabled"},
48
+ "tagInventory": {
49
+ "epc": "disabled",
50
+ "epcHex": "enabled",
51
+ "xpcHex": "disabled",
52
+ "tid": "disabled",
53
+ "tidHex": "enabled",
54
+ "antennaPort": "enabled",
55
+ "transmitPowerCdbm": "disabled",
56
+ "peakRssiCdbm": "enabled",
57
+ "frequency": "disabled",
58
+ "pc": "disabled",
59
+ "lastSeenTime": "disabled",
60
+ "phaseAngle": "disabled",
61
+ "tagReporting": {
62
+ "reportingIntervalSeconds": 1,
63
+ "tagCacheSize": 2048,
64
+ "antennaIdentifier": "antennaPort",
65
+ "tagIdentifier": "epc",
66
+ },
67
+ },
68
+ },
69
+ }
@@ -0,0 +1,146 @@
1
+ import asyncio
2
+ import json
3
+ import logging
4
+
5
+ import httpx
6
+
7
+
8
+ class ReaderHelpers:
9
+ """Helper methods for R700 reader management."""
10
+
11
+ async def check_firmware_version(self, session: httpx.AsyncClient | None = None):
12
+ """Check if reader firmware version is compatible.
13
+
14
+ Args:
15
+ session: HTTP session to use
16
+
17
+ Returns:
18
+ bool: True if firmware is compatible
19
+ """
20
+ endpoint = self.check_version_endpoint
21
+
22
+ try:
23
+ if session is None:
24
+ async with httpx.AsyncClient(auth=self.auth, verify=False, timeout=5.0) as client:
25
+ response = await client.get(endpoint)
26
+ else:
27
+ response = await session.get(endpoint)
28
+
29
+ if response.status_code != 200:
30
+ logging.warning(f"{self.name} - Failed to get firmware version: {response.status_code}")
31
+ return False
32
+
33
+ version_info = response.json()
34
+ firmware_version = version_info.get("primaryFirmware", "Unknown")
35
+ return firmware_version.startswith(self.firmware_version)
36
+
37
+ except Exception as e:
38
+ logging.warning(f"{self.name} - Error GET {endpoint}: {e}")
39
+ return False
40
+
41
+ async def configure_interface(self, session):
42
+ return await self.post_to_reader(
43
+ session,
44
+ self.endpoint_interface,
45
+ payload=self.interface_config,
46
+ method="put",
47
+ )
48
+
49
+ async def stop_inventory(self, session=None):
50
+ return await self.post_to_reader(session, self.endpoint_stop)
51
+
52
+ async def start_inventory(self, session=None):
53
+ return await self.post_to_reader(session, self.endpoint_start, payload=self.reading_config)
54
+
55
+ async def post_to_reader(self, session, endpoint, payload=None, method="post", timeout=3):
56
+ try:
57
+ if session is None:
58
+ async with httpx.AsyncClient(auth=self.auth, verify=False, timeout=timeout) as client:
59
+ return await self.post_to_reader(client, endpoint, payload, method, timeout)
60
+
61
+ if method == "post":
62
+ response = await session.post(endpoint, json=payload, timeout=timeout)
63
+ if response.status_code != 204:
64
+ logging.warning(f"{self.name} - POST {endpoint} failed: {response.status_code}")
65
+
66
+ elif method == "put":
67
+ response = await session.put(endpoint, json=payload, timeout=timeout)
68
+ if response.status_code != 204:
69
+ logging.warning(f"{self.name} - PUT {endpoint} failed: {response.status_code}")
70
+
71
+ return response.status_code == 204
72
+
73
+ except Exception as e:
74
+ logging.warning(f"{self.name} - Error posting to {endpoint}: {e}")
75
+ return False
76
+
77
+ async def get_tag_list(self, session):
78
+ try:
79
+ async with session.stream("GET", self.endpointDataStream, timeout=None) as response:
80
+ if response.status_code != 200:
81
+ logging.warning(f"{self.name} - Failed to connect to data stream: {response.status_code}")
82
+ return
83
+
84
+ logging.info(f"{self.name} - Connected to data stream.")
85
+
86
+ async for line in response.aiter_lines():
87
+ try:
88
+ string = line.strip()
89
+ if not string:
90
+ continue
91
+ jsonEvent = json.loads(string)
92
+
93
+ if "inventoryStatusEvent" in jsonEvent:
94
+ status = jsonEvent["inventoryStatusEvent"]["inventoryStatus"]
95
+ if status == "running":
96
+ asyncio.create_task(self.on_start())
97
+ else:
98
+ asyncio.create_task(self.on_stop())
99
+ elif "tagInventoryEvent" in jsonEvent:
100
+ tagEvent = jsonEvent["tagInventoryEvent"]
101
+ asyncio.create_task(self.on_tag(tagEvent))
102
+
103
+ except (json.JSONDecodeError, UnicodeDecodeError) as parse_error:
104
+ logging.warning(f"{self.name} - Failed to parse event: {parse_error}")
105
+ except Exception as e:
106
+ logging.warning(f"{self.name} - Unexpected error: {e}")
107
+
108
+ async def get_gpo_command(
109
+ self, pin: int = 1, state: bool | str = True, control: str = "static", time: int = 1000
110
+ ) -> dict:
111
+ """
112
+ Gera o payload de configuração de GPO para o leitor RFID.
113
+
114
+ Args:
115
+ pin (int): Número do pino GPO a ser configurado. Default é 1.
116
+ state (bool | str): Estado do pino. Pode ser:
117
+ - True ou "high" → alto
118
+ - False ou "low" → baixo
119
+ control ("static" | "pulsed"): Tipo de controle do pino.
120
+ - "static": mantém o estado
121
+ - "pulsed": envia pulso por tempo definido
122
+ time (int): Duração do pulso em milissegundos. Apenas usado se control="pulsed". Default 1000ms.
123
+
124
+ Returns:
125
+ dict: Payload compatível com a API do leitor RFID para configurar GPO.
126
+
127
+ Example:
128
+ gpo_cmd = await self.get_gpo_command(pin=2, state=True, control="pulsed", time=500)
129
+ """
130
+ # Normaliza o estado
131
+ state = "high" if state is True else "low" if state is False else str(state)
132
+
133
+ if control == "static":
134
+ gpo_command = {"gpoConfigurations": [{"gpo": pin, "state": state, "control": control}]}
135
+ elif control == "pulsed":
136
+ gpo_command = {
137
+ "gpoConfigurations": [
138
+ {
139
+ "gpo": pin,
140
+ "state": state,
141
+ "pulseDurationMilliseconds": time,
142
+ "control": control,
143
+ }
144
+ ]
145
+ }
146
+ return gpo_command