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.