-
-
Save nateevans/f7ce31eb2479a68c892215c81459c169 to your computer and use it in GitHub Desktop.
Revisions
-
Tom Hensel revised this gist
Jul 16, 2017 . 1 changed file with 7 additions and 7 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -14,13 +14,13 @@ import ufr_constants, ufr_errors # oh i love argparse parser = argparse.ArgumentParser(description='query, read, encode (using amiitool), write and lock NTAG215 (using uFR Nano hardware) for the purpose of researching Nintendo\'s Amiibo infrastructure') parser.add_argument('-f', '--filename', dest='filename', help='name of the file containing binary data') parser.add_argument('-r', '--read', dest='read', action='store_true', help='read data from tag') parser.add_argument('-e', '--encode', dest='encode', action='store_true', help='encode data (calls "encode.sh" when uid is known)') parser.add_argument('-w', '--write', dest='write', action='store_true', help='write data to tag') parser.add_argument('-x', '--lock', dest='lock', action='store_true', help='set dynamic and static lock bytes (!)') parser.add_argument('-l', '--loop', dest='loop', action='store_true', help='do not exit on completion but loop (useful for batch jobs)') args = parser.parse_args() class NanoAmii(threading.Thread): -
Tom Hensel revised this gist
Jul 16, 2017 . 1 changed file with 7 additions and 7 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -9,18 +9,18 @@ import argparse import os, threading, time, sys import pyperclip import subprocess import traceback import ufr_constants, ufr_errors # oh i love argparse parser = argparse.ArgumentParser(description='query, read, encode (using amiitool), write and lock NTAG215 (using uFR Nano hardware) for the purpose of researching Nintendo''s Amiibo infrastructure Raw') parser.add_argument('--filename', dest='filename', help='name of the file containing binary data') parser.add_argument('--read', dest='read', action='store_true', help='read data from tag') parser.add_argument('--encode', dest='encode', action='store_true', help='encode data (calls ''encode.sh'' when uid is known)') parser.add_argument('--write', dest='write', action='store_true', help='write data to tag') parser.add_argument('--lock', dest='lock', action='store_true', help='set dynamic and static lock bytes (!)') parser.add_argument('--loop', dest='loop', action='store_true', help='do not exit on completion but loop') args = parser.parse_args() class NanoAmii(threading.Thread): @@ -53,7 +53,7 @@ def __init__(self): #print('__init__') threading.Thread().__init__() print(sys.argv[0], args) self.block_len = 0 self.blocks_num = 0 self.card_size_linear = c_uint8() @@ -107,7 +107,7 @@ def encode(self, filename : str, uid) -> int: output = subprocess.check_output(['bash', 'encode.sh', filename, uid]) args.filename = output.decode('utf-8').strip() except subprocess.CalledProcessError as e: self.abort('error on subprocess: %s' % e.output) print(' filename', args.filename) self.load_blob(args.filename) -
Tom Hensel revised this gist
Jul 16, 2017 . No changes.There are no files selected for viewing
-
Tom Hensel revised this gist
Jul 16, 2017 . 3 changed files with 34 additions and 17 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,16 +1,13 @@ #!/bin/bash # This is a companion script to https://github.com/konstantin-kelemen/arduino-amiibo-tools # The original post this was crafted for was https://games.kel.mn/en/create-amiibo-clones-with-arduino/ # For more info go to https://games.kel.mn/en/companion-script-to-simplify-amiibo-cloning-with-arduino/ #requirements: #sha1sum (part of coreutils) #xxd (part of vim) #hexdump #amiitool (https://github.com/socram8888/amiitool) hash xxd 2>/dev/null || { echo >&2 "require xxd but it's not installed. Aborting."; exit 1; } hash sha1sum 2>/dev/null || { echo >&2 "require sha1sum but it's not installed. Aborting."; exit 1; } @@ -75,7 +72,7 @@ pw4="$(printf '%02X\n' $(( 0x55 ^ 0x$taguid4 ^ 0x$taguid6 )))" #decrypt the dump #echo Using Amiibo Tool to decrypt ${2%%.*} ./amiitool -d -k "$1" -i "$2" -o ${base}_dec.bin || exit 2 #modify the uid record echo "01D4: $uid" | xxd -r - ${base}_dec.bin @@ -89,12 +86,16 @@ echo "0208: 000000" | xxd -r - ${base}_dec.bin echo "0000: $BCC1" | xxd -r - ${base}_dec.bin echo "0002: 0000" | xxd -r - ${base}_dec.bin enc_file="${base}_${uid}.bin" #reencrypt the uid modified dump #echo Using Amiibo Tool to encrypt ${2%%.*} ./amiitool -e -k "$1" -i ${base}_dec.bin -o ${enc_file} || exit 3 rm ${base}_dec.bin echo "${enc_file}" # echo "**** START OF HEXDUMP ****" # hexdump -v -e " 4/1 \"0x%02X, \" \"\n\"" "enc.bin" > hexdump # truncate -s -2 hexdump This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -3,11 +3,11 @@ if [ $# -ne 2 ] then echo "usage: $0 amiibo.bin uuid" exit 1 fi KEY='retail_key.bin' FILE=$1 UUID=$2 ./amiibo.sh ${KEY} ${FILE} ${UUID} This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -11,13 +11,15 @@ import pyperclip import traceback import ufr_constants, ufr_errors import subprocess # oh i love argparse parser = argparse.ArgumentParser(description='read and write binary blob to nfc read_tag') parser.add_argument('--filename', dest='filename', help='name of the file containing binary data') parser.add_argument('--loop', dest='loop', action='store_true', help='do not exit on completion but loop') parser.add_argument('--write', dest='write', action='store_true', help='write data to tag') parser.add_argument('--read', dest='read', action='store_true', help='read data from tag') parser.add_argument('--encode', dest='encode', action='store_true', help='encode data') parser.add_argument('--lock', dest='lock', action='store_true', help='set dynamic and static lock bytes (!)') args = parser.parse_args() @@ -28,7 +30,7 @@ def load_blob(self, filename : str) -> bytearray: # TODO: fail gracefully if argument missing/file nonexistant self.filename = filename # read file as binary print('LOAD', self.filename) with open(self.filename, 'rb') as binary: self.data = bytearray(binary.read()) # store length @@ -51,6 +53,7 @@ def __init__(self): #print('__init__') threading.Thread().__init__() print(args) self.block_len = 0 self.blocks_num = 0 self.card_size_linear = c_uint8() @@ -98,6 +101,16 @@ def open(self) -> int: self.connected = False return call_result def encode(self, filename : str, uid) -> int: print('ENCODE', filename, uid) try: output = subprocess.check_output(['bash', 'encode.sh', filename, uid]) args.filename = output.decode('utf-8').strip() except subprocess.CalledProcessError as e: self.abort('subprocess: %s' % e.output) print(' filename', args.filename) self.load_blob(args.filename) def close(self) -> int: # reset self.card_size_linear = c_uint8() @@ -231,7 +244,6 @@ def query(self) -> bool: return True def contact(self): errors = 0 tag = self.query() @@ -250,10 +262,14 @@ def contact(self): filename = self.card_uid + '.bin' self.save_blob(filename, read_data) if(args.encode): if(args.filename): self.encode(args.filename, self.card_uid) else: self.abort('filename required') if(args.write): self.load_blob(args.filename) errors = self.write_tag() if(errors > 0): self.abort('error on write') -
Tom Hensel revised this gist
Jun 23, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,6 +1,6 @@ #!/bin/bash # # https://gist.github.com/gretel/dd80c854e22c2afd20f5aebc62015096#file-amiibo-sh # # This is a companion script to https://github.com/konstantin-kelemen/arduino-amiibo-tools # The original post this was crafted for was https://games.kel.mn/en/create-amiibo-clones-with-arduino/ -
Tom Hensel revised this gist
Jun 23, 2017 . 2 changed files with 116 additions and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,103 @@ #!/bin/bash # # edited by github@jitter.eu # # This is a companion script to https://github.com/konstantin-kelemen/arduino-amiibo-tools # The original post this was crafted for was https://games.kel.mn/en/create-amiibo-clones-with-arduino/ # For more info go to https://games.kel.mn/en/companion-script-to-simplify-amiibo-cloning-with-arduino/ # requirements: # sha1sum (part of coreutils) # xxd (part of vim) # hexdump # amiitool (https://github.com/socram8888/amiitool) hash xxd 2>/dev/null || { echo >&2 "require xxd but it's not installed. Aborting."; exit 1; } hash sha1sum 2>/dev/null || { echo >&2 "require sha1sum but it's not installed. Aborting."; exit 1; } hash hexdump 2>/dev/null || { echo >&2 "require hexdump but it's not installed. Aborting."; exit 1; } hash ./amiitool 2>/dev/null || { echo >&2 "require amiitool but it's not installed or in the currect directory. Aborting."; exit 1; } if [ $# -ne 3 ] then echo "usage: $0 key_file encrypted_dump_file blank_tagid" exit fi if [ "$(sha1sum "$1" |cut -d' ' -f1)" != "bbdbb49a917d14f7a997d327ba40d40c39e606ce" ] then echo "key_file not sane" exit fi base=${2%%.*} #get the empty tag uid: taguid=$3 taguid0="$(echo "$taguid" | cut -b1,2)" # Byte 0 (should bx 0x04) taguid1="$(echo "$taguid" | cut -b3,4)" # Byte 1 (we count from 0) taguid2="$(echo "$taguid" | cut -b5,6)" # Byte 2 if [ ${#3} -eq 18 ]; then # Check if user provided a long taguid taguid3="$(echo "$taguid" | cut -b9,10)" # Byte 4 taguid4="$(echo "$taguid" | cut -b11,12)" # Byte 5 taguid5="$(echo "$taguid" | cut -b13,14)" # Byte 6 taguid6="$(echo "$taguid" | cut -b15,16)" # Byte 7 uid="$(echo "$taguid" | cut -b1-16)" BCC1="$(echo "$taguid" | cut -b17,18)" # Pull out the BCC1 for use later elif [ ${#3} -eq 14 ]; then # Check if user provided a short taguid taguid3="$(echo "$taguid" | cut -b7,8)" # Byte 3 taguid4="$(echo "$taguid" | cut -b9,10)" # Byte 4 taguid5="$(echo "$taguid" | cut -b11,12)" # Byte 5 taguid6="$(echo "$taguid" | cut -b13,14)" # Byte 6 # Convert 7byte to 9byte for script BCC0="$(printf '%02X\n' $(( 0x88 ^ 0x$taguid0 ^ 0x$taguid1 ^ 0x$taguid2 )))" # Calculate the BCC0 BCC1="$(printf '%02X\n' $(( 0x$taguid3 ^ 0x$taguid4 ^ 0x$taguid5 ^ 0x$taguid6 )))" # Calculate the BCC1 uid="$taguid0$taguid1$taguid2$BCC0$taguid3$taguid4$taguid5$taguid6" fi if [ ${#uid} -ne 16 ]; then echo "please pick a valid 7 or 9 byte uid" exit fi # Generate the password from the tag pw1="$(printf '%02X\n' $(( 0xAA ^ 0x$taguid1 ^ 0x$taguid3 )))" pw2="$(printf '%02X\n' $(( 0x55 ^ 0x$taguid2 ^ 0x$taguid4 )))" pw3="$(printf '%02X\n' $(( 0xAA ^ 0x$taguid3 ^ 0x$taguid5 )))" pw4="$(printf '%02X\n' $(( 0x55 ^ 0x$taguid4 ^ 0x$taguid6 )))" #decrypt the dump #echo Using Amiibo Tool to decrypt ${2%%.*} ./amiitool -d -k "$1" -i "$2" -o ${base}_dec.bin #modify the uid record echo "01D4: $uid" | xxd -r - ${base}_dec.bin #add password echo "0214: $pw1$pw2$pw3$pw4" | xxd -r - ${base}_dec.bin #pw echo "0218: 8080" | xxd -r - ${base}_dec.bin #set the default values echo "0208: 000000" | xxd -r - ${base}_dec.bin echo "0000: $BCC1" | xxd -r - ${base}_dec.bin echo "0002: 0000" | xxd -r - ${base}_dec.bin #reencrypt the uid modified dump #echo Using Amiibo Tool to encrypt ${2%%.*} ./amiitool -e -k "$1" -i ${base}_dec.bin -o ${base}_enc.bin rm ${base}_dec.bin # echo "**** START OF HEXDUMP ****" # hexdump -v -e " 4/1 \"0x%02X, \" \"\n\"" "enc.bin" > hexdump # truncate -s -2 hexdump # echo "" >> hexdump # echo "" >> hexdump # cat hexdump This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,13 @@ #!/bin/sh if [ $# -ne 2 ] then echo "usage: $0 amiibo.bin uuid" exit fi KEY='retail_key.bin' FILE=$1 UUID=$2 ./amiibo.sh ${KEY} ${FILE} ${UUID} -
Tom Hensel revised this gist
Jun 23, 2017 . No changes.There are no files selected for viewing
-
Tom Hensel revised this gist
Jun 18, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # # https://gist.github.com/gretel/dd80c854e22c2afd20f5aebc62015096 # https://www.d-logic.net/nfc-rfid-reader-sdk/products/nano-nfc-rfid-reader/ # https://code.d-logic.net/nfc-rfid-reader-sdk/ufr-lib # -
Tom Hensel created this gist
Jun 18, 2017 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,304 @@ #!/usr/bin/env python3 # # https://gist.github.com/ # https://www.d-logic.net/nfc-rfid-reader-sdk/products/nano-nfc-rfid-reader/ # https://code.d-logic.net/nfc-rfid-reader-sdk/ufr-lib # from ctypes import * import argparse import os, threading, time, sys import pyperclip import traceback import ufr_constants, ufr_errors # oh i love argparse parser = argparse.ArgumentParser(description='read and write binary blob to nfc read_tag') parser.add_argument('--filename', dest='filename', help='name of the file containing binary data') parser.add_argument('--loop', dest='loop', action='store_true', help='do not exit on completion but loop') parser.add_argument('--write', dest='write', action='store_true', help='write data to tag') parser.add_argument('--read', dest='read', action='store_true', help='read data from tag') parser.add_argument('--lock', dest='lock', action='store_true', help='set dynamic and static lock bytes (!)') args = parser.parse_args() class NanoAmii(threading.Thread): def load_blob(self, filename : str) -> bytearray: # first argument (required) # TODO: fail gracefully if argument missing/file nonexistant self.filename = filename # read file as binary print('FILE', self.filename) with open(self.filename, 'rb') as binary: self.data = bytearray(binary.read()) # store length self.data_len = len(self.data) # TODO: check for min/max length print(' read', self.data_len, self.data) def save_blob(self, filename : str, data : bytes, mode : str = 'wb'): print('SAVE', repr(filename)) with open(filename, mode) as binary: binary.write(data) binary.close() def main_thread(self): # loop while self.run: self.loop() def __init__(self): #print('__init__') threading.Thread().__init__() self.block_len = 0 self.blocks_num = 0 self.card_size_linear = c_uint8() self.card_size_raw = c_uint8() self.card_type = None self.card_uid = (c_ubyte * 10)() self.connected = False self.run = True # TODO: abstraction self.ufr = cdll.LoadLibrary(os.getcwd() + '/ufr-lib/osx/x86_64/libuFCoder.dylib') self.ufr.ReaderSoftRestart() self.data = bytearray() self.data_len = 0 if(args.write and args.filename == None): self.abort('filename required') # start thread threading.Thread(target = self.main_thread).start() def open(self) -> int: reader_fw_bld = c_uint32() reader_fw_maj = c_uint32() reader_fw_min = c_uint32() reader_type = c_uint32() print('OPEN') # open device call_result = self.ufr.ReaderOpen() if call_result == ufr_constants.DL_OK: self.ufr.GetReaderType(byref(reader_type)) print(' type', reader_type.value) self.ufr.GetReaderFirmwareVersion(byref(reader_fw_min), byref(reader_fw_maj)) self.ufr.GetBuildNumber(byref(reader_fw_bld)) print(' firmware %s.%s.%s' % (reader_fw_min.value, reader_fw_maj.value, reader_fw_bld.value)) #self.ufr.ReaderUISignal(ufr_constants.FUNCT_LIGHT_OK, ufr_constants.FUNCT_SOUND_OK) self.ufr.AutoSleepSet(10) self.connected = True else: print(' error', ufr_errors.UFCODER_ERROR_CODES[call_result]) self.connected = False return call_result def close(self) -> int: # reset self.card_size_linear = c_uint8() self.card_size_raw = c_uint8() self.card_type = c_uint8() self.connected = False self.card_uid = (c_ubyte * 10)() # close device call_result = self.ufr.ReaderClose() print('CLOSE', hex(call_result)) return call_result def read_tag(self) -> bytearray: block = (c_uint8 * self.block_len)() block_pos = 0 errors = 0 result = bytearray() print('READ', self.blocks_num, self.block_len) for r in range(0, self.blocks_num): block_pos = r call_result = self.ufr.BlockRead(byref(block), block_pos, ufr_constants.MIFARE_AUTHENT1A, 0) if(call_result == ufr_constants.DL_OK): print(' R', block_pos, ufr_errors.UFCODER_ERROR_CODES[call_result], repr(bytes(block))) for b in range(0, self.block_len): result.append(block[b]) else: errors += 1 print(' !R', block_pos, ufr_errors.UFCODER_ERROR_CODES[call_result]) return errors, result def write_tag(self) -> int: block = bytes() block_pos = c_uint8() call_result = c_uint8() data_pos = 0 errors = 0 print('WRITE', self.blocks_num, self.block_len) for block_pos in range(0, self.blocks_num): if(block_pos < 3 or block_pos == 130): # skip lock bytes print(' -W', block_pos) else: block = bytes(self.data[data_pos:data_pos + self.block_len]) call_result = self.ufr.BlockWrite(block, block_pos, ufr_constants.MIFARE_AUTHENT1A, 0) if call_result == ufr_constants.DL_OK: print(' W', block_pos, ufr_errors.UFCODER_ERROR_CODES[call_result], repr(block)) else: errors = 1 print(' !W', block_pos, ufr_errors.UFCODER_ERROR_CODES[call_result], repr(block)) break data_pos += 4 return errors def write_dynlock(self) -> int: b = 0x01, 0x00, 0x0F, 0xBD block = bytes(b) block_pos = 130 call_result = c_uint8() errors = 0 print('DYNLOCK', block_pos, block) call_result = self.ufr.BlockWrite(block, block_pos, ufr_constants.MIFARE_AUTHENT1A, 0) if call_result == ufr_constants.DL_OK: print(' DL', block_pos, ufr_errors.UFCODER_ERROR_CODES[call_result], repr(block)) else: errors = 1 print(' !DL', block_pos, ufr_errors.UFCODER_ERROR_CODES[call_result], repr(block)) return errors def write_statlock(self) -> int: b = 0x0F, 0xE0, 0x0F, 0xE0 block = bytes(b) block_pos = 2 call_result = c_uint8() errors = 0 print('STATLOCK', block_pos, block) call_result = self.ufr.BlockWrite(block, block_pos, ufr_constants.MIFARE_AUTHENT1A, 0) if call_result == ufr_constants.DL_OK: print(' SL', block_pos, ufr_errors.UFCODER_ERROR_CODES[call_result], repr(block)) else: errors = 1 print(' !SL', block_pos, ufr_errors.UFCODER_ERROR_CODES[call_result], repr(block)) return errors def query(self) -> bool: card_size_linear = c_uint8() card_size_raw = c_uint8() card_type = c_uint8() card_uidsize = c_uint8() card_uid = (c_ubyte * 10)() # get tag type call_result = self.ufr.GetDlogicCardType(byref(card_type)) if call_result == ufr_constants.DL_OK: print('QUERY', ufr_errors.UFCODER_ERROR_CODES[call_result]) print(' type', card_type.value, 'name', ufr_constants.CardName(card_type.value)) self.card_type = card_type.value else: return False # size of memory, length of block self.blocks_num = ufr_constants.MaxBlock(self.card_type) self.block_len = ufr_constants.BlockLength(self.card_type) # get tag identifier (uid) call_result = self.ufr.GetCardIdEx(byref(card_type), card_uid, byref(card_uidsize)) if call_result == ufr_constants.DL_OK: # compose uid c = '' for n in range(card_uidsize.value): c = c + format(card_uid[n], '02x') print(' uid', c) self.card_uid = c else: self.abort('error getting uid of tag') # copy to clipboard pyperclip.copy(c) #self.save_blob('/tmp/nanoamii.last_uid', c, 'w') call_result = self.ufr.GetCardSize(byref(card_size_linear), byref(card_size_raw)) if call_result == ufr_constants.DL_OK: self.card_size_raw = card_size_raw.value self.card_size_linear = card_size_linear.value print(' size linear', card_size_linear.value, 'raw', card_size_raw.value) else: self.abort('error getting memory sizes of tag') return True def contact(self): call_result = c_uint8() errors = 0 tag = self.query() if(tag != True): return if(args.read): read_data = '' errors, read_data = self.read_tag() if(errors > 0): self.abort('error on read') # TODO error handling if(args.filename != None): filename = args.filename else: filename = self.card_uid + '.bin' self.save_blob(filename, read_data) if(args.write): # write if(args.write): self.load_blob(args.filename) errors = self.write_tag() if(errors > 0): self.abort('error on write') if(args.lock): errors = self.write_dynlock() if(errors > 0): self.abort('error on writing dynamic lock bytes') else: errors = self.write_statlock() if(errors > 0): self.abort('error on writing static lock bytes') self.ufr.ReaderUISignal(ufr_constants.FUNCT_LIGHT_OK, ufr_constants.FUNCT_SOUND_OK) if(args.loop != True): self.run = False else: time.sleep(1.5) def loop(self): try: if self.connected != True: # open self.open() elif self.connected: # connected result = self.contact() if result == 0xa4: # happens on usb disconnection - allow reconnection self.close() else: # ensure self.close() except: # catch exceptions print('\nEXCEPTION', traceback.format_exc()) sys.exit(1) finally: # dont run wild time.sleep(0.5) def abort(self, reason): self.ufr.ReaderUISignal(ufr_constants.FUNCT_LIGHT_ERROR, ufr_constants.FUNCT_SOUND_ERROR) raise SystemExit(reason) if __name__ == '__main__': #print('__main__') nanoamii = NanoAmii()