def __init__(self, light_data): """Inits ButtonHandler by starting up a FlicClient to listen for button presses. Also creates a dictionary mapping click types to functions to handle them. Args: light_data: light information retrieved from the lightservice. """ self.client = fliclib.FlicClient("localhost") self.data = light_data self.click_functions = { 'ClickType.ButtonSingleClick': self._on_single_click, 'ClickType.ButtonDoubleClick': self._on_double_click, 'ClickType.ButtonHold': self._on_hold } self.buttons = {} self.actions = {} self.states = {} self.light_service = None
#!/usr/bin/env python3 # Scan Wizard application. # # This program starts scanning of new Flic buttons that have not previously been verified by the server. # Once it finds a button that is in private mode, it shows a message that the user should hold it down for 7 seconds to make it public. # Once it finds a button that is in public mode, it attempts to connect to it. # If it could be successfully connected and verified, the bluetooth address is printed and the program exits. # If it could not be verified within 30 seconds, the scan is restarted. import fliclib client = fliclib.FlicClient("localhost") def on_found_private_button(scan_wizard): print( "Found a private button. Please hold it down for 7 seconds to make it public." ) def on_found_public_button(scan_wizard, bd_addr, name): print("Found public button " + bd_addr + " (" + name + "), now connecting...") def on_button_connected(scan_wizard, bd_addr, name): print("The button was connected, now verifying...") def on_completed(scan_wizard, result, bd_addr, name):
# input('press key...') # onFlicButtonClickOrHold( # fliclib.ButtonConnectionChannel(BLACK_BUTTON_ADDRESS), # fliclib.ClickType.ButtonClick, # False, # 0 # ) # while True: # pass try: logger.info('Setting up Flic client...') flicButtonConnectionChannels = [] flicClient = fliclib.FlicClient('localhost') flicClient.get_info(onFlicGetInfo) flicClient.on_new_verified_button = onFlicNewVerifiedButton flicClient.on_bluetooth_controller_state_change = \ onFlicBluetoothControllerStateChange except Exception as e: logger.error('Failed to start Flic client: {}'.format(e)) exit(1, forceQuitCaster=True) else: caster.setup(logLevel=logger.level, errorHandler=onCasterError) logger.info('Ready - waiting for button clicks...\n---') # note that this method is blocking! flicClient.handle_events()
def reset_client_and_scan(): client = fliclib.FlicClient("localhost") scan_for_button(client)
def run(): # set up logging logger = logging.getLogger(__name__) try: logging_level = sys.argv[1].upper() except IndexError: logging_level = 'INFO' logging.basicConfig( filename=config.LOG_FILENAME, level=logging_level, format='%(asctime)-12s | %(levelname)-8s | %(name)s | %(message)s', datefmt='%d/%m/%y, %H:%M:%S') print("Starting light controller, press [Ctrl+C] to exit.") logger.info("Starting light controller...") # signal handler to exit gracefully on Ctrl+C def exit_handler(signal, frame): print('Exiting...', end='') logger.info('Exiting...') presence_sensor.stop() flic_client.close() flic_thread.join() print(' OK') logger.info(' OK') sys.exit(0) signal.signal(signal.SIGINT, exit_handler) # these lights always come on when one of us gets home welcome_lights = ['Hall 1', 'Hall 2', 'Dining table', 'Kitchen cupboard'] # these functions are called by the PresenceSensor on last-one-out or first-one-in events def welcome_home(beacon_owner): logger.info('Welcome home %s!' % (beacon_owner)) if daylight_sensor.query(): bridge.light_on(welcome_lights) else: bridge.light_on([]) def bye(): logger.info("There's no-one home, turning lights off...") bridge.light_off([]) # these functions are called by the Flic client when a button is pressed, a new button is found etc. def click_handler(channel, click_type, was_queued, time_diff): logger.info(channel.bd_addr + " " + str(click_type)) if str(click_type) == 'ClickType.ButtonSingleClick': if channel.bd_addr in groups.keys(): logger.info("Switching on lights associated with button " + channel.bd_addr) bridge.light_on(groups[channel.bd_addr]['group']) else: logger.debug('%s Button not registered with any lights' % (channel.bd_addr)) elif str(click_type) == 'ClickType.ButtonHold': # turn off all lights logger.info("Turning off all lights...") bridge.light_off([]) elif str(click_type) == 'ClickType.ButtonDoubleClick': # not used pass return def got_button(bd_addr): cc = fliclib.ButtonConnectionChannel(bd_addr) # Assign function to call when a button is clicked cc.on_button_single_or_double_click_or_hold = click_handler cc.on_connection_status_changed = \ lambda channel, connection_status, disconnect_reason: \ logger.info(channel.bd_addr + " " + str(connection_status) + (" " + str(disconnect_reason) if connection_status == fliclib.ConnectionStatus.Disconnected else "")) flic_client.add_connection_channel(cc) print(' OK') logger.info(bd_addr + ' OK') def got_info(items): print('Connecting Flic buttons') for bd_addr in items["bd_addr_of_verified_buttons"]: print(bd_addr, end=' ...') got_button(bd_addr) # initialise lights bridge bridge = lights.Bridge(hue_uname=config.HUE_USERNAME, lightify=True) # load flic button groups from file with open(config.FLIC_BUTTONS) as f: json_data = f.read() groups = json.loads(json_data) # create flic client and start in new thread flic_client = fliclib.FlicClient("localhost") logger.info('Connecting Flic buttons...') flic_client.get_info(got_info) flic_client.on_new_verified_button = got_button flic_thread = threading.Thread(target=flic_client.handle_events) flic_thread.start() # initialise daylight sensor (daylight times from sunrise-sunset.org API) daylight_sensor = lights.DaylightSensor(lat=config.LATITUDE, lon=config.LONGITUDE) print('Sunrise and sunset times... OK') # initialise presence sensor and register beacons print('Starting presence sensor...', end='') logger.info('Starting presence sensor...') presence_sensor = presence.PresenceSensor(welcome_callback=welcome_home, last_one_out_callback=bye) beacon1 = { "UUID": "FDA50693-A4E2-4FB1-AFCF-C6EB07647825", "Major": "10004", "Minor": "54480" } beacon2 = { "UUID": "FDA50693-A4E2-4FB1-AFCF-C6EB07647825", "Major": "10004", "Minor": "54481" } logger.info((presence_sensor.register_beacon(beacon1, "Richard"))) logger.info((presence_sensor.register_beacon(beacon2, "Michelle"))) presence_sensor.start() # starts looping in a new thread print(' OK') # initialise lights controller (triggers timed actions) print('Starting light controller...', end='') controller = lights.Controller(bridge, config.RULES, daylight_sensor, presence_sensor) print(' OK') while True: # loop controller to check if any actions should be triggered controller.loop_once() time.sleep(1)
import traceback from logging import handlers from eventhelper import EventHelper # @UnresolvedImport FLIC_LIB_PATH = "/home/pi/fliclib-linux-hci/clientlib/python/" sys.path.append(FLIC_LIB_PATH) import fliclib # @UnresolvedImport FLIC_HOST = "localhost" LOGPATH = os.path.dirname( os.path.dirname(os.path.dirname(os.path.realpath(__file__)))) FILELOGLEVEL = logging.INFO CONSOLELOGLEVEL = logging.WARN flicClient = fliclib.FlicClient(FLIC_HOST) eventhelper = EventHelper() def initLogger(loggerName, logPath, fileLogLevel, consoleLogLevel): logger = logging.getLogger(loggerName) loggerLevel = min(fileLogLevel, consoleLogLevel) logger.setLevel(loggerLevel) logFormatter = logging.Formatter( "%(asctime)s [%(threadName)-12.12s] [%(levelname)-5.5s] %(message)s") fileHandler = handlers.TimedRotatingFileHandler(logPath, when='D', backupCount=7) fileHandler.setFormatter(logFormatter) fileHandler.setLevel(fileLogLevel)
def new_scan_wizard_thread(): msg = ("New scan wizard thread..") print(msg) socketio.emit('scan wizard', msg) wizard_client = fliclib.FlicClient(host) # db_sw_deamon = sqlite3.connect('../bin/armv6l/flicd.sqlite.db') # db_sw_flicpi = sqlite3.connect('flicpi.db') def on_found_private_button(scan_wizard): msg = ("Found a private button. Please hold it down for 7 seconds to make it public.") print(msg) socketio.emit('scan wizard', msg) def on_found_public_button(scan_wizard, bd_addr, name): msg = ("Found public button " + bd_addr + " (" + name + "), now connecting...") print(msg) socketio.emit('scan wizard', msg) def on_button_connected(scan_wizard, bd_addr, name): msg = ("The button was connected, now verifying...") print(msg) socketio.emit('scan wizard', msg) def on_completed(scan_wizard, result, bd_addr, name): msg = ("Scan wizard completed with result " + str(result) + ".") print(msg) socketio.emit('scan wizard', msg) if result == fliclib.ScanWizardResult.WizardSuccess: db_flicpi.execute("INSERT INTO users VALUES (?, ?, ?, ?)", (datetime.now(), bd_addr, None, None)).commit() msg = ("Your button is now ready. The bd addr is " + bd_addr + ".") print(msg) socketio.emit('scan wizard', msg) color = db_flicdeamon.execute("SELECT color FROM buttons WHERE bdAddr = ?", (bd_addr, )).fetchone() data = { 'bdAddr': bd_addr, 'color': color } socketio.emit('scan wizard succes', data) wizard_client.close() wizard = fliclib.ScanWizard() wizard.on_found_private_button = on_found_private_button wizard.on_found_public_button = on_found_public_button wizard.on_button_connected = on_button_connected wizard.on_completed = on_completed wizard_client.add_scan_wizard(wizard) msg = ("Welcome to Scan Wizard. Please press your Flic button.") print(msg) socketio.emit('scan wizard', msg) wizard_client.handle_events()
def background_thread(): print("Running T...") client = fliclib.FlicClient(host) # db = sqlite3.connect('flicpi.db') def got_button(bd_addr): cc = fliclib.ButtonConnectionChannel(bd_addr) cc.on_button_single_or_double_click_or_hold = \ lambda channel, click_type, was_queued, time_diff: \ handle_click_type(channel.bd_addr, click_type) cc.on_connection_status_changed = \ lambda channel, connection_status, disconnect_reason: \ print(channel.bd_addr + " " + str(connection_status) + (" " + str(disconnect_reason) if connection_status == fliclib.ConnectionStatus.Disconnected else "")) client.add_connection_channel(cc) def got_info(items): print(items) for bd_addr in items["bd_addr_of_verified_buttons"]: got_button(bd_addr) def handle_click_type(bdAddr, click_type): if click_type is fliclib.ClickType.ButtonSingleClick: handle_single_click(bdAddr) else: print("No process to handle click type:", str(fliclib.ClickType)) def handle_single_click(bdAddr): timestamp, status = get_last(bdAddr) if status: session_length = (datetime.now() - timestamp).total_seconds() print(bdAddr + " session lasted: " + str(session_length) + '.') user = db_flicpi.execute("SELECT user FROM users WHERE bdAddr = ? ORDER BY ROWID DESC LIMIT 1", (bdAddr,)).fetchone() if user is not None: user = user[0] new_entry = { 'timestamp': str(timestamp), 'bdAddr': bdAddr, 'user': user, 'session_length': session_length, } cur = db_flicpi.cursor() cur.execute("INSERT INTO sessions (timestamp, bdADdr, user, session_length) VALUES (?, ?, ?, ?)", (new_entry['timestamp'], new_entry['bdAddr'], new_entry['user'], new_entry['session_length'])) new_entry['key'] = cur.execute("SELECT key FROM sessions ORDER BY ROWID DESC LIMIT 1").fetchone()[0] db_flicpi.commit() new_entry['session_length_rendered'] = secs_to_string(session_length) socketio.emit('new session', new_entry) get_graph_history() else: print(bdAddr, "session starting...") db_flicpi.execute("INSERT INTO events (timestamp, bdAddr, status) VALUES (?, ?, ?)", (datetime.now(), bdAddr, not status, )) db_flicpi.commit() update_state_tabe() def get_last(bdAddr): """ Get the last entry of this bdAddr in event_log. Return the status and the time of log. If does not exist return False and datetime.now(). """ row = db_flicpi.execute("SELECT timestamp, status FROM events WHERE bdAddr=? ORDER BY timestamp DESC LIMIT 1", (bdAddr, )).fetchone() if row is not None: return dateutil.parser.parse(row[0]), bool(row[1]) return (datetime.now(), False) client.get_info(got_info) client.on_new_verified_button = got_button client.handle_events()
def __init__(self): """Inits ConfigButtonHandler by starting up a FlicClient to listen for button presses. """ self.client = fliclib.FlicClient("localhost")