Host Interfaces Network UDP Server JSON
April 13, 2023 at 2:39 AMJSON over UDP
When the SpringCore device is configured for Smart Reader mode + JSON over UDP, it sends READER EVENT Messages to a remote UDP server, and opens a local UDP port to accept READER COMMAND Messages.
The JSON META and STATUS Messages are not implemented over the UDP channel.
Configuration checklist
- Define the IPv4 configuration of the device in register 0280. Leave this register empty to get the configuration from DHCP.
- Set register 02C0 to
44
(UDP server, Smart Reader operation) - Set register 02A0 to
00xxxx02xx
(JSON format over the Network link) - Insert the name or the address of the host into register 0294. Leave empty or set to 255.255.255.255 for broadcast.
- (Optionaly) define the options in register 0295. Check that the $SCCMD Message comes from the expected source to increase the security of the system.
- (Optionaly) define the Port for UDP and TCP servers in register 0285. Default port is 4000. Host and device must use the same port.
Sample host software
Use the following Python scripts as a reference for using the Smart Reader with configuration JSON over UDP.
Listener
The Listener script is an UDP server, running on the host, that receives and shows any text message coming on port 4000.
NB: since this sample script doesn’t do any processing of the message but only displays it, it is suitable for both $SCRDR and JSON formats.
# libraries import
from threading import Thread, Event
import logging
import socket
import getopt
import sys
import os
# helpers import
from helpers.ctrlccatcher import CtrlCCatcher
# display_help function
def display_help( script_name ):
print( script_name )
print( "[--port=<port>] UDP port to listen to (default: 4000)" )
sys.exit()
# main function
def main( script_name, argv ):
# default settings
port = 4000
# options parsing
try:
opts, _ = getopt.getopt(argv,"h",[ "help", "port=" ])
except getopt.GetoptError as e:
print(e)
display_help( script_name )
for opt, arg in opts:
if opt in ( "-h", "--help"):
display_help( script_name )
elif opt == "--port":
try:
port = int(arg)
except ValueError:
print( "Port must be an integer number!" )
sys.exit()
# set logging options
logging.basicConfig(level=logging.DEBUG)
# CTRL+C catcher thread (this could be useful on some Windows platforms)
ctrlccatch = CtrlCCatcher()
ctrlccatch.start()
# Create an UDP listening socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setblocking(0)
sock.settimeout(0.5)
# Bind the socket to the port
server_address = ("0.0.0.0", port)
logging.info( f"starting up on {server_address} port {port}" )
sock.bind(server_address)
# Messages are read from the socket using recvfrom(), which returns the data as well as the address of the client from which it was sent.
logging.info( "waiting for messages" )
while ctrlccatch.wait():
try:
data, address = sock.recvfrom(4096)
if data:
data = data.decode( "ascii" )
logging.info( data )
except socket.timeout:
pass
# stop all process and exit
logging.info( "Cleaning..." )
ctrlccatch.terminate()
ctrlccatch.join()
logging.info( "Done." )
# entry point
if __name__ == "__main__":
# add "this script" folder to the library search path
# could be useful on Windows platform
sys.path.append( os.path.dirname( os.path.realpath( __file__ ) ) )
# start our application
main( os.path.basename( __file__ ), sys.argv[1:] )
# EOF
Sender
The Sender script is an UDP client, running on the host, that sends a JSON READER COMMAND Message to a target device, or broadcasts the Message.
For demonstration purpose, we send the { "Sequence":"0E" }
message to play the Wink sequence.
Change message to { "Sequence":"60" }
for the Access Granted sequence or { "Sequence":"61" }
for Access Denied. For a complete list of sequences, refer to the PLAY SEQUENCE instruction.
NB: on the command line, the "
must be escaped using the \
characters, as follow: python script.py --message="{ \"Sequence\":\"0E\" }"
```python
# libraries import
from threading import Thread, Event
import socket
import getopt
import sys
import os
# helpers import
from helpers.ctrlccatcher import CtrlCCatcher
# display_help function
def display_help( script_name ):
print( script_name )
print( "[--addr=<addr>] Address of the target device (default: broadcast)" )
print( "[--port=<port>] UDP port on the target device (default: 4000)" )
print( "[--message=\"<message>\"] Message to send to the device (default: WINK Sequence)" )
sys.exit()
# main function
def main( script_name, argv ):
# default settings
message = b"{ \"Sequence\":\"0E\" }"
addr = '<broadcast>'
port = 4000
# options parsing
try:
opts, _ = getopt.getopt(argv,"h",[ "help", "addr=", "port=", "message=" ])
except getopt.GetoptError as e:
print(e)
display_help( script_name )
for opt, arg in opts:
if opt in ( "-h", "--help"):
display_help( script_name )
elif opt == "--message":
message = bytearray(arg.encode())
elif opt == "--addr":
addr = str(arg)
elif opt == "--port":
try:
port = int(arg)
except ValueError:
print( "Port must be an integer number!" )
sys.exit()
# Create an UDP socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
# Enable broadcasting mode
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
# Send the message to the target address and port
sock.sendto(message, (addr, port))
# entry point
if __name__ == "__main__":
# add "this script" folder to the library search path
# could be useful on Windows platform
sys.path.append( os.path.dirname( os.path.realpath( __file__ ) ) )
# start our application
main( os.path.basename( __file__ ), sys.argv[1:] )
# EOF