HW-VX63 mode TCP Client (Remote IP) tanpa Microcontroller

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

Set Reader Address (00-FE), jika kamu memiliki beberapa reader, guna untuk mengetahui tag diterima oleh reader yang mana.

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 / Connect-with-data
        • Immediately: Langsung terconnect ke server tanpa ada tag
        • Connect-with-data: Menunggu ada tag, kemudian connect ke server
      • 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 seperti: netcat atau Hercules SETUP utility.

Kode python di bawah sudah dapat menghandle lebih dari 1 reader. Dapat di set pada method server_socket.listen(5) (contoh: max 5 koneksi).

main.py
import socket
from datetime import datetime
import threading
 
 
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 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 handle_client(client_socket: socket.socket, addr):
    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"Reader: {hex_readable(frame.reader_address)} -> 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}")
 
 
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(5)  # Set max 5 connections
    print(f"Server listening on {host}:{port}")
 
    try:
        while True:
            client_socket, addr = server_socket.accept()
            client_thread = threading.Thread(target=handle_client, args=(client_socket, addr))
            client_thread.start()
 
    except KeyboardInterrupt:
        print("Shutting down the server...")
    finally:
        server_socket.close()
 
 
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)
Reader: 01 -> Tag: 12 00 00 00 00 00 00 00 00 00 00 01
Reader: 00 -> Tag: E2 80 11 70 00 00 02 0E 26 D0 7A A4
Reader: 01 -> Tag: E2 83 23 A1 CC 31 24 08 18 50 99 AB
Reader: 00 -> 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.