forked from arti/doors
		
	Import card reader code from upgrid
Also has a simple sync with server
This commit is contained in:
		
							
								
								
									
										165
									
								
								kdoorpi/kdoorpi/wiegand.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										165
									
								
								kdoorpi/kdoorpi/wiegand.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,165 @@ | ||||
| #!/bin/python | ||||
| import logging | ||||
| from smartcard.util import toHexString | ||||
| #import settings | ||||
|  | ||||
| try: | ||||
|     import pigpio | ||||
| except Exception: | ||||
|     pigpio = False | ||||
|  | ||||
| class Decoder: | ||||
|     """ | ||||
|    A class to read Wiegand codes of an arbitrary length. | ||||
|    """ | ||||
|  | ||||
|     def __init__(self, callback, bit_timeout=5): | ||||
|  | ||||
|         """ | ||||
|         Instantiate with the pi, gpio for 0 (green wire), the gpio for 1 | ||||
|         (white wire), the callback function, and the bit timeout in | ||||
|         milliseconds which indicates the end of a code. | ||||
|  | ||||
|         The callback is passed the code length in bits and the hex value. | ||||
|         """ | ||||
|         if pigpio: | ||||
|             self.pi = pigpio.pi() | ||||
|         else: | ||||
|             self.pi = False | ||||
|  | ||||
|         self.gpio_0 = 17 #settings.WIEGAND[0] | ||||
|         self.gpio_1 = 18 #settings.WIEGAND[1] | ||||
|  | ||||
|         self.callback = callback | ||||
|  | ||||
|         self.bit_timeout = bit_timeout | ||||
|         self.items = [] | ||||
|         self.in_code = False | ||||
|  | ||||
|         if self.pi: | ||||
|             self.pi.set_mode(self.gpio_0, pigpio.INPUT) | ||||
|             self.pi.set_mode(self.gpio_1, pigpio.INPUT) | ||||
|  | ||||
|             self.pi.set_pull_up_down(self.gpio_0, pigpio.PUD_UP) | ||||
|             self.pi.set_pull_up_down(self.gpio_1, pigpio.PUD_UP) | ||||
|  | ||||
|             self.cb_0 = self.pi.callback(self.gpio_0, pigpio.FALLING_EDGE, self._cb) | ||||
|             self.cb_1 = self.pi.callback(self.gpio_1, pigpio.FALLING_EDGE, self._cb) | ||||
|  | ||||
|     def cut_empty(self, item): | ||||
|         if item[0:8] == "00000000": | ||||
|             return self.cut_empty(item[8:]) | ||||
|         else: | ||||
|             return item | ||||
|  | ||||
|  | ||||
|     def get_hex(self): | ||||
|         try: | ||||
|             items = self.items | ||||
|             if len(self.items) == 26: | ||||
|                 items = self.items[1:-1] | ||||
|             elif len(self.items) == 64: | ||||
|                 items = self.cut_empty(self.items) | ||||
|  | ||||
|             bits = [] | ||||
|             for i in range(len(items), 0, -8): | ||||
|                 bits.append(int(items[i - 8:i], 2)) | ||||
|             return toHexString(bits) | ||||
|  | ||||
|         except ValueError: | ||||
|             logging.error("Wiegand convert error: bin to hex convertion ended with ValeError. raw: " + str(self.items)) | ||||
|             return False | ||||
|  | ||||
|         except Exception as e: | ||||
|             logging.error("Wiegand convert error: (raw: " + str(self.items) + ") "  + str(e)) | ||||
|             return False | ||||
|  | ||||
|     def _cb(self, gpio_pin, level, tick): | ||||
|  | ||||
|         """ | ||||
|         Accumulate bits until both gpios 0 and 1 timeout. | ||||
|         """ | ||||
|  | ||||
|         try: | ||||
|             if level < pigpio.TIMEOUT: | ||||
|  | ||||
|                 if self.in_code: | ||||
|                     self.bits += 1 | ||||
|                 else: | ||||
|                     logging.debug("Wiegand data transfer start") | ||||
|                     self.bits = 1 | ||||
|                     self.items = "" | ||||
|                     self.in_code = True | ||||
|                     self.code_timeout = 0 | ||||
|                     self.pi.set_watchdog(self.gpio_0, self.bit_timeout) | ||||
|                     self.pi.set_watchdog(self.gpio_1, self.bit_timeout) | ||||
|  | ||||
|                 if gpio_pin == self.gpio_0: | ||||
|                     self.code_timeout &= 2  # clear gpio 0 timeout | ||||
|                     self.items += "1" | ||||
|                 else: | ||||
|                     self.code_timeout &= 1  # clear gpio 1 timeout | ||||
|                     self.items += "0" | ||||
|  | ||||
|             else: | ||||
|  | ||||
|                 if self.in_code: | ||||
|  | ||||
|                     if gpio_pin == self.gpio_0: | ||||
|                         self.code_timeout |= 1  # timeout gpio 0 | ||||
|                     else: | ||||
|                         self.code_timeout |= 2  # timeout gpio 1 | ||||
|  | ||||
|                     if self.code_timeout == 3:  # both gpios timed out | ||||
|                         self.pi.set_watchdog(self.gpio_0, 0) | ||||
|                         self.pi.set_watchdog(self.gpio_1, 0) | ||||
|                         self.in_code = False | ||||
|  | ||||
|                         if self.bits >= 26: | ||||
|                             hex = self.get_hex() | ||||
|                             if hex: | ||||
|                                 self.callback(self.bits, hex) | ||||
|                         else: | ||||
|                             logging.error("Wiegand receive error: Expected at least 26 got %i bits. raw: %s" %(self.bits, self.items)) | ||||
|  | ||||
|         except Exception as e: | ||||
|             logging.error("Wiegand callback error: " + str(e)) | ||||
|  | ||||
|     def cancel(self): | ||||
|  | ||||
|         """ | ||||
|         Cancel the Wiegand decoder. | ||||
|         """ | ||||
|  | ||||
|         self.cb_0.cancel() | ||||
|         self.cb_1.cancel() | ||||
|         self.pi.stop() | ||||
|  | ||||
|  | ||||
|  | ||||
|  | ||||
| if __name__ == "__main__": | ||||
|     from urllib.request import urlopen | ||||
|     import json | ||||
|  | ||||
|     print("downloading users list") | ||||
|     r = urlopen("http://127.0.0.1:8080/api/v1/cards") | ||||
|     users = json.loads(r.read().decode())["keycards"] | ||||
|     cards = {} | ||||
|     for user in users: | ||||
|         cards[user["card_uid"].strip()] = user | ||||
|  | ||||
|     def wiegand_callback(bits, value): | ||||
|         print("bits", bits) | ||||
|         print("value", value) | ||||
|         print("user", cards.get(value)) | ||||
|  | ||||
|     logging.basicConfig(level=logging.DEBUG) | ||||
|  | ||||
|     print("Running") | ||||
|     w = Decoder(wiegand_callback) | ||||
|     from time import sleep | ||||
|     while 1: | ||||
|         sleep(1) | ||||
|  | ||||
|  | ||||
		Reference in New Issue
	
	Block a user