smartx-rfid 1.1.6__py3-none-any.whl → 1.8.0__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.
@@ -0,0 +1,674 @@
1
+ """
2
+ RFID Tag TID Parser
3
+ Módulo para parsing e análise de TID (Tag Identifier) de tags RFID.
4
+
5
+ Este módulo fornece funcionalidades para converter TID hexadecimal em informações
6
+ estruturadas sobre tags RFID, incluindo fabricante, modelo, número serial e outras
7
+ características técnicas.
8
+
9
+ Baseado na implementação original em C# TagTidParser.cs
10
+
11
+ Autor: Conversão de C# para Python
12
+ Data: 2025-07-04
13
+ Versão: 1.0.0
14
+ """
15
+
16
+ from typing import Dict, Union
17
+ from .exceptions import TagTidParserError, InvalidTidError
18
+
19
+
20
+ class TagTidParser:
21
+ """
22
+ Parser para TID (Tag Identifier) de tags RFID.
23
+
24
+ Esta classe permite extrair informações detalhadas de tags RFID a partir
25
+ do TID (Tag Identifier) de 96 bits, incluindo:
26
+
27
+ - Número serial de 40 bits (hexadecimal e decimal)
28
+ - Identificação do fabricante
29
+ - Modelo da tag
30
+ - Número do modelo (TMN - Tag Model Number)
31
+ - ID da série Monza (para tags Impinj)
32
+ - Detecção automática do algoritmo de extração
33
+
34
+ Suporte para fabricantes:
35
+ - Impinj (Monza R6, M700, M800, Monza 4/5 Series)
36
+ - NXP (UCODE 7, 8, 9)
37
+ - Fallback universal para fabricantes desconhecidos
38
+
39
+ Exemplo:
40
+ >>> parser = TagTidParser("E2801190000000000000000A")
41
+ >>> print(parser.get_vendor_from_tid())
42
+ 'Impinj Monza R6'
43
+ >>> print(parser.get_tag_model_name())
44
+ 'Impinj M750'
45
+ >>> print(parser.get_40bit_serial_hex())
46
+ '000000000A'
47
+ """
48
+
49
+ # Prefixos conhecidos de TID mapeados para fabricantes
50
+ # Baseado nos primeiros 4 bytes (32 bits) do TID
51
+ KNOWN_TID_PREFIXES: Dict[str, str] = {
52
+ # Impinj Monza R6 Series
53
+ "E2801190": "Impinj Monza R6",
54
+ # Impinj M700 Series
55
+ "E2801191": "Impinj M730",
56
+ "E28011A0": "Impinj M770",
57
+ # Impinj M800 Series
58
+ "E28011B0": "Impinj M830/M850",
59
+ # NXP UCODE 9 Series
60
+ "E2806915": "NXP UCODE 9",
61
+ "E2806995": "NXP UCODE 9",
62
+ # Adicione mais conforme necessário
63
+ # Formato: "XXXXXXXX": "Fabricante Modelo"
64
+ }
65
+
66
+ # Mapeamento de TMN (Tag Model Number) para nomes de modelos
67
+ # TMN é extraído dos bits 11-0 dos bytes 2-3 do TID
68
+ TAG_MODEL_MAP: Dict[int, str] = {
69
+ # Impinj M700 Series
70
+ 0x190: "Impinj M750", # TMN 0x190 = Impinj M750
71
+ 0x191: "Impinj M730", # TMN 0x191 = Impinj M730
72
+ 0x1A0: "Impinj M770", # TMN 0x1A0 = Impinj M770
73
+ # Impinj M800 Series
74
+ 0x1B0: "Impinj M830/M850", # TMN 0x1B0 = Impinj M830/M850
75
+ # Impinj Monza R6 Family
76
+ 0x120: "Impinj Monza R6", # TMN 0x120 = Impinj Monza R6
77
+ 0x121: "Impinj Monza R6-A", # TMN 0x121 = Impinj Monza R6-A
78
+ 0x122: "Impinj Monza R6-P", # TMN 0x122 = Impinj Monza R6-P
79
+ # Impinj Monza 4 Series
80
+ 0x0B2: "Impinj Monza 4D", # TMN 0x0B2 = Impinj Monza 4D
81
+ 0x0B3: "Impinj Monza 4E", # TMN 0x0B3 = Impinj Monza 4E
82
+ 0x0B4: "Impinj Monza 4U", # TMN 0x0B4 = Impinj Monza 4U
83
+ 0x0B5: "Impinj Monza 4QT", # TMN 0x0B5 = Impinj Monza 4QT
84
+ # Impinj Monza 5 Series
85
+ 0x0C0: "Impinj Monza 5", # TMN 0x0C0 = Impinj Monza 5
86
+ # NXP UCODE 9 Series
87
+ 0x915: "NXP UCODE 9", # TMN 0x915 = NXP UCODE 9 (variante 1)
88
+ 0x995: "NXP UCODE 9", # TMN 0x995 = NXP UCODE 9 (variante 2)
89
+ # NXP UCODE 8 Series (prefixos estimados)
90
+ 0x910: "NXP UCODE 8", # TMN 0x910 = NXP UCODE 8
91
+ 0x990: "NXP UCODE 8", # TMN 0x990 = NXP UCODE 8
92
+ # NXP UCODE 7 Series (valor comum)
93
+ 0x970: "NXP UCODE 7", # TMN 0x970 = NXP UCODE 7
94
+ # Adicione mais modelos conforme necessário
95
+ # Formato: 0xXXX: "Fabricante Modelo Específico"
96
+ }
97
+
98
+ def __init__(self, tid_hex: str):
99
+ """
100
+ Inicializa o parser com um TID em formato hexadecimal.
101
+
102
+ Args:
103
+ tid_hex (str): TID em formato hexadecimal. Deve ter exatamente 24
104
+ caracteres (96 bits). Espaços e hífens são automaticamente
105
+ removidos. Case insensitive.
106
+
107
+ Raises:
108
+ InvalidTidError: Se o TID for None, vazio ou apenas espaços
109
+ ValueError: Se o TID não tiver 24 caracteres hexadecimais ou
110
+ contiver caracteres inválidos
111
+
112
+ Examples:
113
+ >>> parser = TagTidParser("E2801190000000000000000A")
114
+ >>> parser = TagTidParser("E2-80-11-90-00-00-00-00-00-00-00-0A")
115
+ >>> parser = TagTidParser("e2 80 11 90 00 00 00 00 00 00 00 0a")
116
+ """
117
+ if tid_hex is None or not str(tid_hex).strip():
118
+ raise InvalidTidError("TID não pode ser vazio ou nulo")
119
+
120
+ # Normalizar TID: remover espaços, hífens e converter para maiúscula
121
+ tid_hex = str(tid_hex).replace(" ", "").replace("-", "").upper().strip()
122
+
123
+ if len(tid_hex) != 24:
124
+ raise ValueError("TID deve ter 24 caracteres hexadecimais (96 bits)")
125
+
126
+ try:
127
+ # Converter para bytes e validar caracteres hexadecimais
128
+ self._tid = bytes.fromhex(tid_hex)
129
+ except ValueError:
130
+ raise ValueError("TID contém caracteres hexadecimais inválidos")
131
+
132
+ # Armazenar TID original normalizado para referência
133
+ self._tid_hex = tid_hex
134
+ # Flag para indicar se o objeto foi "descartado"
135
+ self._disposed = False
136
+
137
+ def get_40bit_serial_hex(self) -> str:
138
+ """
139
+ Extrai o número serial de 40 bits em formato hexadecimal.
140
+
141
+ O algoritmo de extração varia baseado no fabricante detectado:
142
+ - NXP UCODE 9: Extrai dos bytes 7-11 (posições específicas)
143
+ - Impinj: Extrai dos bytes 6-10 (padrão Impinj)
144
+ - Fallback: Extrai dos últimos 5 bytes (para fabricantes desconhecidos)
145
+
146
+ Returns:
147
+ str: Número serial de 40 bits em formato hexadecimal maiúsculo
148
+ (exatamente 10 caracteres)
149
+
150
+ Examples:
151
+ >>> parser = TagTidParser("E2801190000000000000000A")
152
+ >>> parser.get_40bit_serial_hex()
153
+ '000000000A'
154
+ """
155
+ if self._disposed:
156
+ raise TagTidParserError("Objeto TagTidParser já foi descartado")
157
+
158
+ if self._is_impinj_tid():
159
+ serial = 0
160
+ if self._is_m700_series() or self._is_m800_series():
161
+ serial = (
162
+ ((self._tid[6] & 0x3F) << 32)
163
+ | (self._tid[7] << 24)
164
+ | (self._tid[8] << 16)
165
+ | (self._tid[9] << 8)
166
+ | self._tid[10]
167
+ )
168
+ elif self._is_r6_series():
169
+ serial = self._get_r6_series_38bit_serial()
170
+ return f"{serial:010X}"
171
+
172
+ if self._is_nxp_ucode9_tid():
173
+ serial = 0
174
+ for i in range(7, 12):
175
+ serial = (serial << 8) | self._tid[i]
176
+ return f"{serial:010X}"
177
+
178
+ # Algoritmo fallback para fabricantes desconhecidos
179
+ # Extrai dos últimos 5 bytes
180
+ return self._get_fallback_serial_hex()
181
+
182
+ def get_40bit_serial_decimal(self) -> int:
183
+ """
184
+ Extrai o número serial de 40 bits em formato decimal.
185
+
186
+ Returns:
187
+ int: Número serial de 40 bits como inteiro decimal (0 a 1099511627775)
188
+
189
+ Examples:
190
+ >>> parser = TagTidParser("E2801190000000000000000A")
191
+ >>> parser.get_40bit_serial_decimal()
192
+ 10
193
+ """
194
+ hex_serial = self.get_40bit_serial_hex()
195
+ return int(hex_serial, 16)
196
+
197
+ def _get_fallback_serial_hex(self) -> str:
198
+ """
199
+ Método fallback para extrair serial dos últimos 5 bytes.
200
+
201
+ Usado quando o fabricante não é reconhecido ou não tem algoritmo específico.
202
+
203
+ Returns:
204
+ str: Serial em formato hexadecimal maiúsculo (10 caracteres)
205
+ """
206
+ # Extrair últimos 5 bytes (índices 7, 8, 9, 10, 11)
207
+ return self._tid[-5:].hex().upper()
208
+
209
+ def _is_r6_series(self) -> bool:
210
+ """Verifica se o TMN corresponde a um chip da família Monza R6."""
211
+ tmn = ((self._tid[2] & 0x0F) << 8) | self._tid[3]
212
+ return tmn in {0x120, 0x121, 0x122, 0x170}
213
+
214
+ def _is_m700_series(self) -> bool:
215
+ """Verifica se o TMN corresponde a um chip da série M700."""
216
+ tmn = ((self._tid[2] & 0x0F) << 8) | self._tid[3]
217
+ return tmn in {0x190, 0x191, 0x1A0, 0x1A2}
218
+
219
+ def _is_m800_series(self) -> bool:
220
+ """Verifica se o TMN corresponde a um chip da série M800."""
221
+ tmn = ((self._tid[2] & 0x0F) << 8) | self._tid[3]
222
+ return tmn == 0x1B0
223
+
224
+ def _get_r6_series_38bit_serial(self) -> int:
225
+ """Obtém o serial de 38 bits para tags Monza R6."""
226
+ if not self._is_r6_series():
227
+ raise TagTidParserError("Tag não é da família Monza R6")
228
+ return (
229
+ ((self._tid[6] & 0x3F) << 32)
230
+ | (self._tid[7] << 24)
231
+ | (self._tid[8] << 16)
232
+ | (self._tid[9] << 8)
233
+ | self._tid[10]
234
+ )
235
+
236
+ def _is_impinj_tid(self) -> bool:
237
+ """
238
+ Verifica se o TID pertence a uma tag Impinj.
239
+
240
+ Critério de identificação Impinj:
241
+ - Byte 0: 0xE2 (ISO/IEC 18000-6C)
242
+ - Byte 1: 0x80 (Allocation Class)
243
+ - Byte 2: 0x1X (bits 7-4 = 0x1, bits 3-0 = qualquer)
244
+
245
+ Returns:
246
+ bool: True se for uma tag Impinj, False caso contrário
247
+ """
248
+ return self._tid[0] == 0xE2 and self._tid[1] == 0x80 and (self._tid[2] >> 4) == 0x1
249
+
250
+ def _is_nxp_ucode9_tid(self) -> bool:
251
+ """
252
+ Verifica se o TID pertence a uma tag NXP UCODE 9.
253
+
254
+ Critério de identificação NXP UCODE 9:
255
+ - Byte 0: 0xE2 (ISO/IEC 18000-6C)
256
+ - Byte 1: 0x80 (Allocation Class)
257
+ - Byte 2: 0x69 (identificador UCODE 9)
258
+ - Byte 3: 0x15 ou 0x95 (variantes conhecidas)
259
+
260
+ Returns:
261
+ bool: True se for uma tag NXP UCODE 9, False caso contrário
262
+ """
263
+ return (
264
+ self._tid[0] == 0xE2
265
+ and self._tid[1] == 0x80
266
+ and self._tid[2] == 0x69
267
+ and (self._tid[3] == 0x15 or self._tid[3] == 0x95)
268
+ )
269
+
270
+ def get_monza_series_id(self) -> int:
271
+ """
272
+ Extrai o ID da série Monza (específico para tags Impinj).
273
+
274
+ O ID da série é codificado nos bits 7-6 do byte 10 (índice 10).
275
+ Valores possíveis: 0, 1, 2, 3
276
+
277
+ Returns:
278
+ int: ID da série Monza (0-3)
279
+
280
+ Note:
281
+ Este método só é relevante para tags Impinj. Para outras tags,
282
+ o valor pode não ter significado específico.
283
+
284
+ Examples:
285
+ >>> parser = TagTidParser("E2801190000000000000000040") # série 1
286
+ >>> parser.get_monza_series_id()
287
+ 1
288
+ """
289
+ # Extrair bits 7-6 do byte 10
290
+ return (self._tid[10] >> 6) & 0b11
291
+
292
+ def get_tag_model_number(self) -> str:
293
+ """
294
+ Extrai o número do modelo da tag (TMN - Tag Model Number).
295
+
296
+ O TMN é codificado nos bits 11-0 dos bytes 2-3:
297
+ - Bits 3-0 do byte 2 (nibble baixo)
298
+ - Bits 7-0 do byte 3 (byte completo)
299
+
300
+ Returns:
301
+ str: Número do modelo em formato hexadecimal maiúsculo (3 caracteres)
302
+
303
+ Examples:
304
+ >>> parser = TagTidParser("E2801190000000000000000A")
305
+ >>> parser.get_tag_model_number()
306
+ '190'
307
+ """
308
+ # Combinar bits 3-0 do byte 2 com byte 3 completo
309
+ # (byte2 & 0x0F) << 8 | byte3
310
+ tmn = ((self._tid[2] & 0x0F) << 8) | self._tid[3]
311
+ return f"{tmn:03X}"
312
+
313
+ def get_tag_model_name(self) -> str:
314
+ """
315
+ Obtém o nome descritivo do modelo da tag.
316
+
317
+ Consulta o dicionário TAG_MODEL_MAP usando o TMN extraído.
318
+ Se o modelo não for reconhecido, retorna uma string descritiva
319
+ com o TMN em hexadecimal.
320
+
321
+ Returns:
322
+ str: Nome do modelo ou "Desconhecido (TMN 0xXXX)" se não encontrado
323
+
324
+ Examples:
325
+ >>> parser = TagTidParser("E2801190000000000000000A")
326
+ >>> parser.get_tag_model_name()
327
+ 'Impinj M750'
328
+ >>> parser = TagTidParser("E280FF00000000000000000A") # TMN desconhecido
329
+ >>> parser.get_tag_model_name()
330
+ 'Desconhecido (TMN 0xF00)'
331
+ """
332
+ # Extrair TMN
333
+ tmn = ((self._tid[2] & 0x0F) << 8) | self._tid[3]
334
+
335
+ # Buscar no mapeamento ou retornar desconhecido
336
+ return self.TAG_MODEL_MAP.get(tmn, f"Desconhecido (TMN 0x{tmn:03X})")
337
+
338
+ def get_vendor_from_tid(self) -> str:
339
+ """
340
+ Identifica o fabricante baseado no prefixo do TID.
341
+
342
+ Utiliza os primeiros 4 bytes (32 bits) do TID para identificar
343
+ o fabricante consultando o dicionário KNOWN_TID_PREFIXES.
344
+
345
+ Returns:
346
+ str: Nome do fabricante ou "Desconhecido" se não encontrado
347
+
348
+ Examples:
349
+ >>> parser = TagTidParser("E2801190000000000000000A")
350
+ >>> parser.get_vendor_from_tid()
351
+ 'Impinj Monza R6'
352
+ >>> parser = TagTidParser("FF00AA00000000000000000A") # Prefixo desconhecido
353
+ >>> parser.get_vendor_from_tid()
354
+ 'Desconhecido'
355
+ """
356
+ # Extrair primeiros 4 bytes como string hexadecimal
357
+ prefix = self._tid[:4].hex().upper()
358
+
359
+ # Buscar no dicionário de prefixos conhecidos
360
+ return self.KNOWN_TID_PREFIXES.get(prefix, "Desconhecido")
361
+
362
+ def get_tid_info(self) -> Dict[str, Union[str, int, bool, None]]:
363
+ """
364
+ Retorna todas as informações extraídas do TID em um dicionário estruturado.
365
+
366
+ Este método combina todos os outros métodos da classe para fornecer
367
+ uma visão completa das informações da tag em um formato conveniente.
368
+
369
+ Returns:
370
+ dict: Dicionário com todas as informações da tag contendo:
371
+ - tid (str): TID original em hexadecimal maiúsculo
372
+ - vendor (str): Nome do fabricante
373
+ - model_name (str): Nome do modelo
374
+ - model_number (str): Número do modelo (TMN) em hex
375
+ - serial_hex (str): Serial de 40 bits em hexadecimal
376
+ - serial_decimal (int): Serial de 40 bits em decimal
377
+ - monza_series_id (int|None): ID da série Monza (apenas Impinj)
378
+ - is_impinj (bool): True se for tag Impinj
379
+ - is_nxp_ucode9 (bool): True se for NXP UCODE 9
380
+
381
+ Examples:
382
+ >>> parser = TagTidParser("E2801190000000000000000A")
383
+ >>> info = parser.get_tid_info()
384
+ >>> print(info['vendor'])
385
+ 'Impinj Monza R6'
386
+ >>> print(info['serial_decimal'])
387
+ 10
388
+ """
389
+ # Determinar se é Impinj para incluir Monza Series ID
390
+ is_impinj = self._is_impinj_tid()
391
+ monza_series_id = self.get_monza_series_id() if is_impinj else None
392
+
393
+ return {
394
+ "tid": self._tid_hex,
395
+ "vendor": self.get_vendor_from_tid(),
396
+ "model_name": self.get_tag_model_name(),
397
+ "model_number": self.get_tag_model_number(),
398
+ "serial_hex": self.get_40bit_serial_hex(),
399
+ "serial_decimal": self.get_40bit_serial_decimal(),
400
+ "monza_series_id": monza_series_id,
401
+ "is_impinj": is_impinj,
402
+ "is_nxp_ucode9": self._is_nxp_ucode9_tid(),
403
+ }
404
+
405
+ def __str__(self) -> str:
406
+ """
407
+ Representação string do parser.
408
+
409
+ Returns:
410
+ str: String descritiva com TID, fabricante e modelo
411
+ """
412
+ vendor = self.get_vendor_from_tid()
413
+ model = self.get_tag_model_name()
414
+ return f"TagTidParser(TID={self._tid_hex}, Vendor={vendor}, Model={model})"
415
+
416
+ def __repr__(self) -> str:
417
+ """
418
+ Representação para debug do parser.
419
+
420
+ Returns:
421
+ str: String de representação para debug
422
+ """
423
+ return f"TagTidParser('{self._tid_hex}')"
424
+
425
+ def __eq__(self, other) -> bool:
426
+ """
427
+ Compara dois parsers pela igualdade do TID.
428
+
429
+ Args:
430
+ other: Outro objeto TagTidParser para comparação
431
+
432
+ Returns:
433
+ bool: True se os TIDs forem iguais
434
+ """
435
+ if not isinstance(other, TagTidParser):
436
+ return False
437
+ return self._tid_hex == other._tid_hex
438
+
439
+ def __hash__(self) -> int:
440
+ """
441
+ Hash baseado no TID para uso em sets e dicts.
442
+
443
+ Returns:
444
+ int: Hash do TID
445
+ """
446
+ return hash(self._tid_hex)
447
+
448
+ def dispose(self) -> None:
449
+ """Descarta o objeto limpando os dados do TID."""
450
+ if not self._disposed:
451
+ self._tid = b""
452
+ self._disposed = True
453
+
454
+
455
+ # ============================================================================
456
+ # FUNÇÕES DE CONVENIÊNCIA PARA USO DIRETO
457
+ # ============================================================================
458
+
459
+
460
+ def parse_tid(tid_hex: str) -> Dict[str, Union[str, int, bool, None]]:
461
+ """
462
+ Função de conveniência para parsing rápido de TID.
463
+
464
+ Esta função cria um TagTidParser temporário e retorna todas as
465
+ informações extraídas em um dicionário.
466
+
467
+ Args:
468
+ tid_hex (str): TID em formato hexadecimal (24 caracteres)
469
+
470
+ Returns:
471
+ dict: Dicionário com todas as informações da tag
472
+ (mesmo formato que TagTidParser.get_tid_info())
473
+
474
+ Raises:
475
+ InvalidTidError: Se o TID for inválido
476
+ ValueError: Se o TID tiver formato incorreto
477
+
478
+ Examples:
479
+ >>> info = parse_tid("E2801190000000000000000A")
480
+ >>> print(info['model_name'])
481
+ 'Impinj M750'
482
+ >>> print(info['serial_hex'])
483
+ '000000000A'
484
+ """
485
+ parser = TagTidParser(tid_hex)
486
+ return parser.get_tid_info()
487
+
488
+
489
+ def get_serial_from_tid(tid_hex: str, format_type: str = "hex") -> Union[str, int]:
490
+ """
491
+ Extrai apenas o número serial do TID no formato especificado.
492
+
493
+ Função de conveniência para quando apenas o serial é necessário,
494
+ evitando criar o parser completo.
495
+
496
+ Args:
497
+ tid_hex (str): TID em formato hexadecimal (24 caracteres)
498
+ format_type (str): Formato do retorno - "hex" ou "decimal"
499
+
500
+ Returns:
501
+ str: Serial em hexadecimal se format_type="hex"
502
+ int: Serial em decimal se format_type="decimal"
503
+
504
+ Raises:
505
+ InvalidTidError: Se o TID for inválido
506
+ ValueError: Se o TID tiver formato incorreto ou format_type inválido
507
+
508
+ Examples:
509
+ >>> get_serial_from_tid("E2801190000000000000000A", "hex")
510
+ '000000000A'
511
+ >>> get_serial_from_tid("E2801190000000000000000A", "decimal")
512
+ 10
513
+ """
514
+ parser = TagTidParser(tid_hex)
515
+
516
+ if format_type.lower() == "decimal":
517
+ return parser.get_40bit_serial_decimal()
518
+ elif format_type.lower() == "hex":
519
+ return parser.get_40bit_serial_hex()
520
+ else:
521
+ raise ValueError(f"format_type deve ser 'hex' ou 'decimal', recebido: '{format_type}'")
522
+
523
+
524
+ def validate_tid(tid_hex: str) -> bool:
525
+ """
526
+ Valida se um TID tem formato válido sem fazer o parsing completo.
527
+
528
+ Args:
529
+ tid_hex (str): TID para validar
530
+
531
+ Returns:
532
+ bool: True se o TID for válido, False caso contrário
533
+
534
+ Examples:
535
+ >>> validate_tid("E2801190000000000000000A")
536
+ True
537
+ >>> validate_tid("INVALID")
538
+ False
539
+ """
540
+ try:
541
+ TagTidParser(tid_hex)
542
+ return True
543
+ except (InvalidTidError, ValueError):
544
+ return False
545
+
546
+
547
+ def get_vendor_from_tid(tid_hex: str) -> str:
548
+ """
549
+ Extrai apenas o fabricante do TID.
550
+
551
+ Função de conveniência para identificação rápida do fabricante.
552
+
553
+ Args:
554
+ tid_hex (str): TID em formato hexadecimal
555
+
556
+ Returns:
557
+ str: Nome do fabricante ou "Desconhecido"
558
+
559
+ Examples:
560
+ >>> get_vendor_from_tid("E2801190000000000000000A")
561
+ 'Impinj Monza R6'
562
+ """
563
+ parser = TagTidParser(tid_hex)
564
+ return parser.get_vendor_from_tid()
565
+
566
+
567
+ def get_model_from_tid(tid_hex: str) -> str:
568
+ """
569
+ Extrai apenas o modelo do TID.
570
+
571
+ Função de conveniência para identificação rápida do modelo.
572
+
573
+ Args:
574
+ tid_hex (str): TID em formato hexadecimal
575
+
576
+ Returns:
577
+ str: Nome do modelo
578
+
579
+ Examples:
580
+ >>> get_model_from_tid("E2801190000000000000000A")
581
+ 'Impinj M750'
582
+ """
583
+ parser = TagTidParser(tid_hex)
584
+ return parser.get_tag_model_name()
585
+
586
+
587
+ # ============================================================================
588
+ # CÓDIGO DE EXEMPLO E DEMONSTRAÇÃO
589
+ # ============================================================================
590
+
591
+ if __name__ == "__main__":
592
+ """
593
+ Código de exemplo que demonstra o uso da biblioteca.
594
+
595
+ Execute este arquivo diretamente para ver exemplos de uso:
596
+ python rfid_tag_parser/tag_tid_parser.py
597
+ """
598
+
599
+ print("=" * 80)
600
+ print("🏷️ RFID TAG TID PARSER - DEMONSTRAÇÃO")
601
+ print("=" * 80)
602
+
603
+ # TIDs de exemplo para demonstração
604
+ example_tids = [
605
+ "E2801190000000000000000A", # Impinj Monza R6
606
+ "E2801191000000000000000B", # Impinj M730
607
+ "E28011A0000000000000000C", # Impinj M770
608
+ "E2806915000000000000000E", # NXP UCODE 9
609
+ "FF00AA00000000000000002A", # Fabricante desconhecido
610
+ ]
611
+
612
+ print("\n📋 Exemplos de Parsing de TID:")
613
+ print("-" * 80)
614
+
615
+ for i, tid in enumerate(example_tids, 1):
616
+ try:
617
+ print(f"\n{i}. TID: {tid}")
618
+
619
+ # Usar a classe TagTidParser
620
+ parser = TagTidParser(tid)
621
+
622
+ print(f" Fabricante: {parser.get_vendor_from_tid()}")
623
+ print(f" Modelo: {parser.get_tag_model_name()}")
624
+ print(f" Número do modelo: {parser.get_tag_model_number()}")
625
+ print(f" Serial (Hex): {parser.get_40bit_serial_hex()}")
626
+ print(f" Serial (Decimal): {parser.get_40bit_serial_decimal()}")
627
+ print(f" É Impinj: {parser._is_impinj_tid()}")
628
+ print(f" É NXP UCODE9: {parser._is_nxp_ucode9_tid()}")
629
+
630
+ if parser._is_impinj_tid():
631
+ print(f" Monza Series ID: {parser.get_monza_series_id()}")
632
+
633
+ except Exception as e:
634
+ print(f" ❌ Erro: {e}")
635
+
636
+ print("\n" + "=" * 80)
637
+ print("🚀 Exemplos de Funções de Conveniência:")
638
+ print("=" * 80)
639
+
640
+ # Demonstrar funções de conveniência
641
+ test_tid = "E2801190123456789ABCDEF0"
642
+
643
+ print(f"\nTID de teste: {test_tid}")
644
+ print("-" * 50)
645
+
646
+ try:
647
+ # Parsing completo
648
+ info = parse_tid(test_tid)
649
+ print("✓ Parsing completo:")
650
+ for key, value in info.items():
651
+ print(f" {key}: {value}")
652
+
653
+ # Extração específica
654
+ print("\n✓ Extração específica:")
655
+ print(f" Serial (hex): {get_serial_from_tid(test_tid, 'hex')}")
656
+ print(f" Serial (decimal): {get_serial_from_tid(test_tid, 'decimal')}")
657
+ print(f" Fabricante: {get_vendor_from_tid(test_tid)}")
658
+ print(f" Modelo: {get_model_from_tid(test_tid)}")
659
+
660
+ # Validação
661
+ print("\n✓ Validação:")
662
+ print(f" TID válido: {validate_tid(test_tid)}")
663
+ print(f" TID inválido: {validate_tid('INVALID')}")
664
+
665
+ except Exception as e:
666
+ print(f"❌ Erro na demonstração: {e}")
667
+
668
+ print("\n" + "=" * 80)
669
+ print("📚 Para mais exemplos, consulte:")
670
+ print(" - examples/basic_usage.py")
671
+ print(" - examples/batch_processing.py")
672
+ print(" - examples/integration_example.py")
673
+ print(" - docs/API.md")
674
+ print("=" * 80)
@@ -1,6 +1,7 @@
1
1
  from pydantic import BaseModel, Field
2
+ from typing import Any
2
3
 
3
4
 
4
5
  class EventSchema(BaseModel):
5
6
  event_type: str = Field("event", description="Type of the event")
6
- event_data = Field(None, description="Associated data with the event")
7
+ event_data: Any = Field(None, description="Associated data with the event")