import json from smartcard.CardType import AnyCardType, ATRCardType from smartcard.CardRequest import CardRequest from smartcard.Exceptions import NoCardException, CardConnectionException from smartcard.util import toHexString from platypush.backend import Backend from platypush.message.event.scard import SmartCardDetectedEvent, SmartCardRemovedEvent class ScardBackend(Backend): """ Generic backend to read smart cards and NFC tags and trigger an event whenever a device is detected. Extend this backend to implement more advanced communication with custom smart cards. Triggers: * :class:`platypush.message.event.scard.SmartCardDetectedEvent` when a smart card is detected * :class:`platypush.message.event.scard.SmartCardRemovedEvent` when a smart card is removed Requires: * **pyscard** (``pip install pyscard``) """ def __init__(self, atr=None, *args, **kwargs): """ :param atr: If set, the backend will trigger events only for card(s) with the specified ATR(s). It can be either an ATR string (space-separated hex octects) or a list of ATR strings. Default: none (any card will be detected) """ super().__init__(*args, **kwargs) self.ATRs = [] if atr: if isinstance(atr, str): self.ATRs = [atr] elif isinstance(atr, list): self.ATRs = atr else: raise RuntimeError("Unsupported ATR: \"{}\" - type: {}, " + "supported types: string, list".format( atr, type(atr))) self.cardtype = ATRCardType( *[toBytes(atr) for atr in self.ATRs] ) else: self.cardtype = AnyCardType() def run(self): super().run() self.logger.info('Initialized smart card reader backend - ATR filter: {}'. format(self.ATRs)) prev_atr = None reader = None while not self.should_stop(): try: cardrequest = CardRequest(timeout=None, cardType=self.cardtype) cardservice = cardrequest.waitforcard() cardservice.connection.connect() reader = cardservice.connection.getReader() atr = toHexString(cardservice.connection.getATR()) if atr != prev_atr: self.logger.info('Smart card detected on reader {}, ATR: {}'. format(reader, atr)) self.bus.post(SmartCardDetectedEvent(atr=atr, reader=reader)) prev_atr = atr except Exception as e: if isinstance(e, NoCardException) or isinstance(e, CardConnectionException): self.bus.post(SmartCardRemovedEvent(atr=prev_atr, reader=reader)) else: self.logger.exception(e) prev_atr = None # vim:sw=4:ts=4:et: