Pada tutorial kali ini, kami akan berbagi langkah-langkah praktis untuk mengatur UHF Reader agar dapat langsung mengirimkan data tag ke Server (Remote IP) melalui protokol TCP/IP. Dengan cara ini, kita tidak lagi memerlukan microcontroller sebagai perantara ke router, sehingga proses menjadi lebih sederhana dan efisien.
Topologi §
Server bisa berupa server lokal atau server cloud (dengan IP publik). Dalam tutorial ini, kami menggunakan server lokal yang masih dalam satu subnet.
Reader akan berjalan dalam Active Mode dan TCP Work Mode: Client , sehingga setiap kali ada tag terdeteksi, data akan langsung dikirim ke server.
Konfigurasi reader §
Tutorial ini kami menggunakan Electron HW-VX6330K konfirgurasi yang digunakan seperti berikut:
Reader parameter §
TCPIP Config §
Buka program demo, pergi ke tab “TCPIP Config”
Search reader (klik Search / Specific Search button)
Pada tab “Network”, atur seperti berikut
Protocol: TCP
Work Mode: Client
Remote IP: 192.168.1.10
, IP Server/tujuan
Remote Port: 2077
, Port Server/tujuan
Gateway IP: 192.168.1.1
, IP Router
Mask: 255.255.255.0
, Subnet mask IP Router
Advance option:
Connection mode: Immediately
Connection timeout: 0
Percobaan §
Pada sisi server membutuhkan program server yang berjalan pada port 2077
untuk menerima data yang dikirim oleh reader.
Tutorial kali ini kami mencoba menggunakan bahasa pemrograman python, adapun alternatif bisa menggunakan tools lain untuk listen ke port 2077
seperti: netcat atau Hercules SETUP utility .
main.py
§
import socket
from datetime import datetime
class Frame :
def __init__ (self, frame_bytes: bytes ):
self .length = frame_bytes[ 0 ]
self .reader_address = frame_bytes[ 1 ]
self .command = frame_bytes[ 2 ]
self .status = frame_bytes[ 3 ]
self .data = frame_bytes[ 4 : - 2 ]
self .checksum = frame_bytes[ - 2 :]
def __str__ (self) -> str :
return (
f "RESPONSE >> { hex_readable( self .length) } { hex_readable( self .reader_address) } "
f " { hex_readable( self .command) } { hex_readable( self .status) } { hex_readable( self .data) } "
f " { hex_readable( self .checksum) }\n "
f "READER ADDRESS >> { hex_readable( self .reader_address) }\n "
f "COMMAND >> { hex_readable( self .command) }\n "
f "STATUS >> { hex_readable( self .status) }\n "
f "DATA >> { hex_readable( self .data) }\n "
f "CHECKSUM >> { hex_readable( self .checksum) }\n "
)
class Response :
def __init__ (self, response_bytes: bytes ):
self .frames = self ._parse_frames(response_bytes)
def _parse_frames (self, response_bytes: bytes ):
frames = []
index = 0
while index < len (response_bytes):
length = response_bytes[index]
frame_end = index + length + 1 # +1 to include the length byte itself
frame_bytes = response_bytes[index:frame_end]
if len (frame_bytes) < length + 1 :
raise ValueError ( "Incomplete frame data" )
frames.append(Frame(frame_bytes))
index = frame_end
return frames
def __str__ (self) -> str :
now = datetime.now()
return_value = f '>>> { now } - START RESPONSE ================================ \n '
for index, frame in enumerate ( self .frames):
return_value += f ">>> FRAME [ { index } ] === \n "
return_value += str (frame)
return_value = return_value + f ' \n >>> { now } - END RESPONSE ================================ \n\n '
return_value += return_value
return return_value.strip()
def hex_readable (data: bytes | int , bytes_separator: str = " " ) -> str :
if isinstance (data, int ):
return " { :02X } " .format(data)
return bytes_separator.join( " { :02X } " .format(x) for x in data)
def start_server (host: str , port: int ) -> None :
server_socket = socket.socket(socket. AF_INET , socket. SOCK_STREAM )
server_socket.bind((host, port))
server_socket.listen( 1 )
print ( f "Server listening on { host } : { port } " )
while True :
client_socket, addr = server_socket.accept()
print ( f "Connection from { addr } " )
try :
raw_response: bytes = client_socket.recv( 1024 )
while raw_response:
response: Response = Response(raw_response)
# print(response)
for frame in response.frames:
print ( f "Tag: { hex_readable(frame.data) } " ) # Tag
raw_response = client_socket.recv( 1024 )
except Exception as e:
print ( f "Error: { e } " )
finally :
client_socket.close()
print ( f "Connection closed for { addr } " )
if __name__ == "__main__" :
start_server( host = '0.0.0.0' , port = 2077 )
Output (terminal) §
(venv) PS D:\Electron\TCP Server > python main.py
Server listening on 0.0.0.0 : 2077
Connection from ( '192.168.1.192', 10038)
Tag: 12 00 00 00 00 00 00 00 00 00 00 01
Tag: E2 80 11 70 00 00 02 0E 26 D0 7A A4
Tag: E2 83 23 A1 CC 31 24 08 18 50 99 AB
Tag: E2 80 11 70 00 00 02 0E 26 D0 7A A4
Penutup §
Beberapa poin penting:
Jika koneksi reader terputus, data tag yang terdeteksi selama putus tidak akan dikirim ulang.
Inventory work mode hanya berjalan di mode Active Mode.
Untuk yang menggunakan server cloud (IP Public), jangan lupa untuk mengatur firewall dan membuka port agar reader dapat mengirim data.
Berikut tutorial bagaimana cara menerima data tag tanpa menggunakan microcontroller.