Henry Argos SDK is a helper project to handle communication with Henry Argos access control fingerprint/card reader. All communication happens through TCP/IP sockets, where the reader is the server and this SDK plays the client role.
The protocol should be compatible with other Henry products, but many features were tailored down to Argos use, since this is the main goal of the project. Given it time, the goal is to remain compatible and feature balanced with other products as well. All development, use and automated testing were conducted using Argos firmware versions 1.0.1.3b and 1.0.0.24.
You can install it from pip like:
pip install ArgosSDK
It has the following dependencies:
In the basic usage you only need to import the SDK and the exceptions for error handling:
from argos import SDK, exceptions
from datetime import datetime, timedelta
import daiquiri, logging
daiquiri.setup(level=logging.INFO)
logger = daiquiri.getLogger()
ip = "192.168.0.200"
fingerprints = [
"021474747414",
"021474747414"
]
now = datetime.today()
d = now - timedelta(days=1)
try:
with SDK(ip) as s:
s.set_timestamp(timestamp=now)
s.get_timestamp()
s.get_cards(count=14, start_index=0)
s.get_quantity(typec=SDK.QT_CARDS)
s.send_cards(card_number="TEST")
s.capture_fingerprint(card_number="47854785", timeout=30)
s.get_fingerprints(card_number="47854785")
s.send_fingerprints("47854785", fingerprints)
s.delete_fingerprints(card_number="47854785")
s.send_cards(card_number="47854785", mode=SDK.SEND_DELETE)
s.get_events(start_date=d)
except (
exceptions.ConnectTimeout,
exceptions.SendCommandTimeout,
exceptions.TooManyCardsRequested,
exceptions.GenericErrorResponse,
) as e:
logger.warning(e)
Besides the IP, you can also specify the following parameters to the SDK:
port
(default 3000)timeout
, meaning the default time the socket should hang while expecting a response. Valid to the connection procedure. (default 3s)max_tries
specifies how many times the command should be resend before it gives up. (default 5 times)sleep_between_tries
meaning how much the SDK should wait before sending again the command. (default .5s)
Every command can receive the following **connection_params
:
timeout
overrides the SDK configuration on how much the socket should hang while expecting a response.tries
overrides the SDK configuration on how many times the command should be resend before it gives up.
Commands always return a Response
object. If you want to access the returned data, you can simply use it as a dict:
with SDK(ip) as s:
response = s.set_timestamp(timestamp=now)
print(response) # print the response dict repr()
print(response.data) # the actual dict with the response data
print(response['payload']) # the payload of the response, already parsed
If the return code is greater than 10, it means something went wrong. A GenericErrorResponse
or one of its children will be raised containing more information.
Get the current timestamp setted on the equipment.
Expects: None
Returns: datetime object
Set the current timestamp setted on the equipment.
Expects: Datime object. If none, datetime.now()
will be used instead.
Returns: No payload.
Retrieve the cards registered, between [start_index, start_index+count]
.
The protocol here limitates the response into 30 cards. If you try to get more than
that, a TooManyCardsRequested
will be raised.
Expects:
count
: how many cardsstart_index
: from index. These parameters work like SQL's LIMIT and OFFSET
Returns: payload containing count
cards on a list
Get the count of a given entry type.
Expects: Type. The options are:
- SDK.QT_USERS = "U"
- SDK.QT_CARDS = "C"
- SDK.QT_FINGERPRINTS = "D"
- SDK.QT_MAX_FINGERPRINTS = "TD"
Returns: a String containing a numeric value.
Get the current timestamp setted on the equipment.
Expects:
card_number
MAX 20master
the card type, being:
- SDK.NORMAL_MODE ('1') without master access (default)
- SDK.MASTER_MODE ('6') master access
verify_fingerprint
whether the fingerprint is required to validate access (default True)send_mode
the way the command should be send, being:
- SEND_INSERT = "I" (default)
- SEND_UPDATE = "A"
- SEND_DELETE = "E" (complete wipe out, be careful)
Returns: No payload
Ask to the reader to collect a new fingerprint. The user will have about 15 seconds to put his finger on the reader. The system will ask the user to put the finger twice to confirm and save it into memory.
Expects:
card_number
MAX 20 (must be registered already)
Returns: No payload
Get all fingerprints of a card from the equipment.
Expects:
card_number
MAX 20 (must be registered already)
Returns: List of hex strings representing the fingerprint.
Send a list of fingerprints to the reader.
Expects:
card_number
MAX 20 (must be registered already)fingerprints
a list of fingerprints as hex strings.
Returns: No payload
Clear fingerprints of a card.
Expects:
card_number
MAX 20 (must be registered already)
Returns: No payload
Get the current timestamp setted on the equipment.
Expects:
start_date
datetime objectend_date
datetime object,default datetime.now()
Returns: A list of events.
Usually the protocol follows this format:
{START:1}{PAYLOAD_SIZE:2}{MESSAGE:8|10}{PAYLOAD:??}{CHECKSUM:1}{END:1}
START
: Initial byte - 0x02PAYLOAD_SIZE
: 2 bytes where the most significant byte is most right. Like 421 = A5 01 (not 01 A5)MESSAGE
: that can be 8 byte like "00+RH+00" or 10 byte like "00+ECAR+00". The first two bytes indicate the version, and the last two bytes whether there was an error.CHECKSUM
: resut of a bitwise xor of each byte fromPAYLOAD_SIZE
to the end of thePAYLOAD
.END
: End byte - 0x03
You can extend this project creating your own command and sending it to the SDK. It would be something like this:
from argos import SDK, Command, Response
class AnotherResponse(Response):
response_mapping = {"payload": (12, 29, False)}
def parse_payload(self, bytes):
string = bytes.decode()
return self.dosomething(string)
class AnotherCommand(Command):
response = AnotherResponse
def payload(self):
return "01+??+00"
with SDK(ip) as s:
response = s.send_command(AnotherCommand(params), timeout=30)
print(response['payload'])
- Use checksum byte in order to verify package integrity. Today it only verifies the start/end bytes.
- Send more than one card at time.
You can use docker to build and run the test suit, like:
docker build . -t argos-sdk
docker run -eEQUIPMENT_IP=x.x.x.x -it argos-sdk
# build and upload it to PyPi
docker run -eTWINE_PASSWORD=pass -eTWINE_USERNAME=user -eARGOS_SDK_VERSION=3.0 argos-sdk sh ./build_script
This project came from a demand at Universidade Federal de Juiz de Fora (UFJF), more specifically the Departamento de Energia Eletrica (DENE) at Faculdade de Engenharia. We needed a better system to access control of our labs and classrooms, so we decided to ship this communication layer as a opensource project.