Building a Smart Card Transit Ticketing System with Redis and Raspberry Pi

These messages should contain details about the time or number of trips remaining on the pass.To check if a pass exists for a given card I could use the Redis EXISTS command… but as I know I want to get all the values in the hash stored in Redis for that card I figured HGETALL was a better choice, saving a second call to the database in the case that the key does exist:def getPassForCard(cardSerialNumber): return r.hgetall(cardSerialNumber)If a single use pass was presented, I simply need to remove that hash from the database by deleting its key with the DEL command which is delete in the Python client:r.delete(cardSerialNumber)If a two hour pass was presented then the action taken depends on whether the pass is being used for the first time or not…TWO_HOURS = 60 * 60 * 2passTtl = r.ttl(cardSerialNumber)if (not passTtl): r.expire(cardSerialNumber, TWO_HOURS)else: print('Two hour pass has ' + str(round((passTtl / 60), 1)) + ' minutes remaining.')Here I check if the key in Redis has an expiry time set already using the TTL command..If it does (value returned was non-negative), then I log the time remaining..If there’s no TTL set, we start the two hour expiry period for this pass using the EXPIRE command..Two hour passes never get explicitly deleted using the DEL command as EXPIRE takes care of that.In the case of the ten trip pass some logic is required to determine what to do:tripsRemaining = cardPass.get('tripsRemaining') # Note tripsRemaining comes back as a String if (tripsRemaining == '1'): # Final trip for this pass, so delete this key r.delete(cardSerialNumber)else: # Remove one trip from this pass r.hincrby(cardSerialNumber, 'tripsRemaining', -1)If the field tripsRemaining is set to 1, then this pass is being used for the final time so it gets deleted from Redis..Note that Redis stores values as strings, hence the comparison with the string '1' rather than numeric 1.If this pass has more than one trip remaining, the value of the tripsRemaining field in the Redis hash used to store the pass is reduced by one..Redis doesn’t have a decrement command so instead I use the HINCRBY command to increment the value by -1 which is the same as incrementing it.The entry gate also publishes messages to different channels for each event that happens..It uses the same mechanism to do this as the sales terminal does.System MonitorThe system monitor’s role is to subscribe to the pub/sub topics that the other components publish messages on and to display those as sort of a central systemwide status..I didn’t build any hardware for this component and chose to use Node.js over Python.The system monitor is very simple and uses a couple of modules from npm:node-redis-pubsub: Makes connecting to Redis and subscribing to pub/sub topics simple.chalk: A module to display text in different colors in the terminal..I used this to display exception cases such as attempts to enter the transit system without a valid pass stand out from normal business events such as adding a pass to a card.When running it looks like this:The System Monitor component runningThe code is very simple, in the example below r is an instance of node-redis-pubsub that has been configured to connect to my cloud Redis instance..I have one event handler defined to output one message for pass-used messages, unless the pass was a ten trip pass in which case the other handler fires:const PASS_TYPE_TEN_TRIP = 'TEN_TRIP'…r.on('pass-used:*', (msg) => { // some type of pass used console.log(chalk.blue(`Card ${msg.cardSerialNumber} started a journey.`))})r.on(`pass-used:${PASS_TYPE_TEN_TRIP}`, (msg) => { console.log(chalk.yellow(`Card ${msg.cardSerialNumber} has ${msg.remainingTrips} of 10 trips remaining.`))})…The full source code consists of these plus a few more event handlers for different message topics.This component doesn’t interact with Redis as a database at all, it only uses the message broker functionality.Hopefully you found this an interesting read..It was an enjoyable project to make!.I could have played around with Redis without all of the additional hardware but where’s the fun in that!. More details

Leave a Reply