A simple scanning application.
Well there are a lot of scanning applications out there. I am sure they are fine, but I needed something both simpler and more flexible.
I am currently working on a project managing endurance races. At this time, it is not meant to handle timing, but time will tell right?
So what we need is handling driver changes, and keeping track of how long each driver spend on track. To that effect, we generate a card for each driver that has a QR code.
The QR code needs to be scanned when a team sends a driver for a driver change, and when a driver exits the kart to indicate the end of her/his session and the start of the session of the other driver.
So the scanning application simply reads the QR code and sends the content to an API endpoint.
EasyScan works like this:
- Login with a username, password, and the URL of the API login endpoint.
- If login is successful, an authorisation token and a URL are returned.
- Scans send the payload to the URL that was received.
While not strictly necessary, we want to distinguish between driver queue scanning (drivers waiting for a change, there can be more than there are pitlanes available.) and the scan for the actual driver change.
Well it works for the go-kart race project. It could also be used to quickly add scanning stations or temporarily replace disabled scanning stations. The API is easy to implement.
By embedding a dictionary with 2 keys, info and data, in the QR code, you could setup 2 step scanning. First the QR code is scanned and the value of the info key is displayed. The operator can select Cancel or Ok. If Ok, the full content of the QR code is sent.
EasyScan can work with any API that implements the following endpoints and data format:
Create a login endpoint that accepts POST requests with JSON data:
Request Format:
{
"username": "scanner_username",
"password": "scanner_password"
}Success Response (HTTP 200):
{
"status": "ok",
"token": "your_authentication_token",
"url": "https://yourdomain.com/scan_endpoint/"
}Error Response (HTTP 401):
{
"status": "error",
"message": "Invalid credentials"
}The URL returned by the authentication endpoint should accept POST requests with:
Headers:
Authorization: Token your_authentication_token
Request Format:
{
"data": "encrypted_or_encoded_scan_data"
}Response Format:
{
"status": "ok",
"message": "Processing successful"
}Important: EasyScan only reads QR codes and transmits their content as-is. All data encoding/decoding happens on the server side.
- QR Code Generation: Your server must encode the data when creating QR codes
- Data Processing: Your server must decode the data when receiving scans from EasyScan
- EasyScan Role: Simply reads QR codes and sends the raw content to your endpoint
For secure QR codes, implement encoding/decoding on your server:
# Server-side encoding (when generating QR codes)
from cryptography.fernet import Fernet
from base64 import b64encode, b64decode
def encode_scan_data(encryption_key, data):
"""Encode data before putting it in QR code"""
cipher = Fernet(encryption_key)
return b64encode(cipher.encrypt(str(data).encode())).decode("ascii")
def decode_scan_data(encryption_key, encoded_data):
"""Decode data received from EasyScan"""
cipher = Fernet(encryption_key)
return int(cipher.decrypt(b64decode(encoded_data.encode())))
# Workflow:
# 1. Server creates QR code containing: encode_scan_data(key, user_id)
# 2. EasyScan reads QR code and sends raw content to your endpoint
# 3. Server receives scan and calls: decode_scan_data(key, received_data)For confirmation dialogs, your server should embed a JSON object when creating the QR code:
{
"info": "Driver: John Doe - Team 42",
"data": "your_encoded_data_here"
}EasyScan will:
- Display the
infovalue to the operator - Wait for OK/Cancel confirmation
- Send the complete JSON object (as-is) to your endpoint if OK is pressed
Your server receives the entire JSON and can extract the data field for processing.
Here's a minimal Flask example:
from flask import Flask, request, jsonify
from functools import wraps
app = Flask(__name__)
def require_token(f):
@wraps(f)
def decorated_function(*args, **kwargs):
token = request.headers.get('Authorization', '').replace('Token ', '')
if not validate_token(token): # Implement your token validation
return jsonify({"status": "error", "message": "Invalid token"}), 401
return f(*args, **kwargs)
return decorated_function
@app.route('/agent_login', methods=['POST'])
def login():
data = request.get_json()
username = data.get('username')
password = data.get('password')
if authenticate_user(username, password): # Implement your auth logic
token = generate_token(username) # Implement token generation
return jsonify({
"status": "ok",
"token": token,
"url": request.url_root + "scan_endpoint/"
})
else:
return jsonify({
"status": "error",
"message": "Invalid credentials"
}), 401
@app.route('/scan_endpoint/', methods=['POST'])
@require_token
def handle_scan():
data = request.get_json()
scan_data = data.get('data')
# Process your scan data here
# decode_scan_data(encryption_key, scan_data) if using encryption
return jsonify({
"status": "ok",
"message": "Scan processed successfully"
})This allows you to quickly add scanning functionality to any application while maintaining compatibility with EasyScan.
This project is my first phone application. To write it, I used Gemini and Claude AI.
I used VS code for handling code, compilation Android debugging etc.
This is a Flutter application, here are some Flutter resources:
For help getting started with Flutter development, view the online documentation, which offers tutorials, samples, guidance on mobile development, and a full API reference.
The scanner is a nice Flutter library, mobile_scanner