import json 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) """ from smartcard.CardType import AnyCardType, ATRCardType 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): from smartcard.CardRequest import CardRequest from smartcard.Exceptions import NoCardException, CardConnectionException from smartcard.util import toHexString 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: