def open(self): """ Open an input event device for reading Tries to open the device path given to the constructor or search for all available input event devices. """ device_paths = [] if len(self.__inputDevicePath): device_paths = ["{0}".format(self.__inputDevicePath)] else: device_paths = glob.glob( '/dev/input/event*') # search all available devices for path in device_paths: try: self.close() self.__inputDevice = InputDevice(path) self.__deviceOpenRetries = 0 self.__inputDevicePath = path logger.debug('Opened RFID reader device \'{0}\''.format(path)) time.sleep(1.0) # prevent timing issues return except: if self.__deviceOpenRetries < 1: logger.error( 'Unable to open USB RFID reader \'{0}\'!'.format(path)) self.__inputDevice = None self.__deviceOpenRetries += 1
def _exec_queries(self, sqlQueries=[]): """ Execute given SQL statements Return results as one extended array """ results = [] sql = "" if self._dbfile is None: logger.error('Cannot execute SQL query! ' 'Database filename "{0}" invalid!'.format( self._dbfile)) return results try: with sqlite3.connect(self._dbfile) as connection: cursor = connection.cursor() for query in sqlQueries: sql = query for row in cursor.execute(sql): results.append(row) if 0: logger.debug('added query "{0}" results "{1}" ' 'to return value'.format(sql, row)) logger.debug('executed query "{0}"'.format(sql)) except sqlite3.OperationalError as err: logger.error('{0}! query: {1}'.format(err, sql)) return None return results
def readline(self): """ Try reading a code from the input device and return it as string """ if self.__inputDevice is None: self.open() if self.__inputDevice is None: return None line = '' try: while True: event = self.__inputDevice.read_one() if event is None and line == '': # There are blank events in between characters, so we don't want # to break if we've started reading them break # start a new read. if event is None or event.type != ecodes.EV_KEY: continue data = categorize(event) # catch only keyup, and not Enter if data.keystate == 0 and data.scancode != 42: if data.scancode == 28: # looking return key to be pressed if len(line) < self.__minCodeLength: logger.warning( 'ignoring to small code: {0}'.format(line)) break else: logger.debug('code read: \'{0}\''.format(line)) return line else: line += self.__scancodes[data.scancode] except: logger.error('Parsing input stream failed!') self.close() return None
def test_read(self): self.assertIsNotNone(self.reader, 'reader object cannot be initialized!') code = None try: logger.debug('reading code...') code = self.reader.readline() except: self.fail('error during reading code!')
def close(self): """ Close the input device and wait 1 second """ try: if self.__inputDevice is not None: self.__inputDevice.close() self.__inputDevice = None logger.debug('RFID input device closed') time.sleep(1.0) # prevent timing issues except: logger.warning('Error while closing RFID input device!')
def start(self): """ Init timers, reader and display user message """ self.__running = True Thread.start(self) try: logger.debug('starting shower control...') time.sleep(1.0) except Exception as error: logger.error( 'Error during starting main control! {0}'.format(error))
def writeEntry(self, tableName, primaryKey, values={}): """ Insert or update a table entry with given values tableName - name of target table for insert/update of entry primaryKey - name of table primary key or selector column values - dictionary with field:value pairs of entry to write Return True on success, False on any error """ if tableName is None: logger.error('Invalid table name given!') return False if primaryKey is None: logger.error('Invalid table entry primary key given!') return False if values is False or primaryKey not in values: logger.error('Invalid table entry primary key given!') return False id = values[primaryKey] if self.tableExists(tableName) is False: logger.warning('Entry cannot be written! ' 'Table does not exist!'.format(tableName)) return False sqls = [ 'SELECT * FROM {0} WHERE {1} ' '= \'{2}\''.format(tableName, primaryKey, id) ] retval = self._exec_queries(sqls) if len(retval) and retval[0] is not None: logger.debug('Updating entry {0}="{1}"'.format(primaryKey, id)) sqls = [ 'UPDATE {0} SET {1} WHERE {2} = \'{3}\''.format( tableName, ', '.join("%s='%s'" % (k, v) for k, v in values.items()), primaryKey, id) ] else: logger.debug('Inserting new entry {0}="{1}"'.format( primaryKey, id)) sqls = [ 'INSERT INTO {0} ({1}) VALUES ({2})'.format( tableName, ', '.join("{0}".format(k) for k in values.keys()), ', '.join("'{0}'".format(values[k]) for k in values.keys())) ] retval = self._exec_queries(sqls) return True if retval is not None else False
def stop(self): """ Stop the timer thread """ if self._timer: if self._timer.is_alive(): self._timer.cancel() self._timer.join() logger.debug('cancelled timer') self._timer = None if self.timeoutEvent.is_set(): self.timeoutEvent.clear() self._finished = False logger.info('timer stopped')
def __init__(self, outports=[], inverted=True): """ Init GPIO interface """ self.invertedLevels = inverted if not inverted: self._state_on, self._state_off = self._state_off, self._state_on self._states = {self._state_on: 'ON', self._state_off: 'OFF'} GPIO.setmode(GPIO.BCM) # BCM-numbering (GPIO 17) instead of pin (11) for port in outports: GPIO.setup(port, GPIO.OUT, initial=self._state_off) self._registered_outs.append(port) logger.debug('init GPIO {} as output'.format(port)) time.sleep(0.5)
def test_handle_timeout(self): control2 = timer.IOControlTimer(8) event = control2.timeoutEvent logger.debug('restarting timer for event test...') control2.reset() time.sleep(0.5) logger.debug('restarted timer for event test') self.assertTrue(control2.is_active(), 'starting timer failed') self.assertFalse(event.wait(1.0), 'timeout event failed for too small timeout') self.assertTrue(event.wait(9.0), 'timeout event failed within timeout') self.assertTrue(event.is_set(), 'timeout event state is invalid')
def __update_sensors(self): """ Check for 1wire drivers and read available sensors """ try: # open 1-wire slaves list to read sensor ids file = open('/sys/devices/w1_bus_master1/w1_master_slaves') w1_slaves = file.read().splitlines() file.close() self.__sensors = w1_slaves if w1_slaves[0] is None: logger.warning('no 1-wire sensors found!') else: for s in w1_slaves: logger.debug('sensor found: {}'.format(s)) except: logger.error('Unable to read 1-wire device list!')
def test_show(self): self.assertIsNotNone(self.display, 'display object cannot be initialized!') try: logger.debug('displaying text...') self.display.clear() self.display.show('Hello World! #1', 1) self.display.show('Hello World! #2', 2) self.display.backlight(False) time.sleep(1) self.display.backlight() except: self.fail('error during showing text!')
def toggle_output(self, port, value=-1): if port not in self._registered_outs: logger.warning('Cannot toggle unregistered GPIO {0}!'.format(port)) return if value is -1: value = GPIO.input(port) logger.debug('toggle GPIO {0} from {1} to {2}'.format( port, self._states[value], self._states[not value])) value = not value elif self.invertedLevels: value = not value state = GPIO.HIGH if value > 0 else GPIO.LOW GPIO.output(port, state) logger.debug('set GPIO {0} to {1}'.format(port, self._states[state])) time.sleep(0.01)
def __init__(self, shower_id=1, shower_seconds=420): """ Init card reader, display and I/O controls """ Thread.__init__(self) try: if shower_seconds < 30: logger.error('invalid shower time given! time must be > 30s') raise AttributeError() self.shower_id = shower_id self.shower_time = shower_seconds self._cardReader = UsbRfidReader() self._showerTimer = IOControlTimer(self.shower_time) self._relays = RelayControl( [self._gpio_cold_water, self._gpio_warm_water]) self._display = LcdControl() self.__running = False time.sleep(1.0) logger.debug('shower control ready') except Exception as error: logger.error( 'Error during init of main control! {0}'.format(error))
if self._display: self._display.show('Duschzeit {0:3d}min'.format(shower_time), 1) self._display.show('>>> Karte OK <<<', 2) def show_message_error(self): if self._display: self._display.show('Dusche {0} AUS'.format(self.shower_id), 1) self._display.show('>>> STOERUNG <<<', 2) def show_message_stop(self): if self._display: self._display.show('Dusche {0} BELEGT'.format(self.shower_id), 1) self._display.show('>>> GESPERRT <<<', 2) # exec tests if __name__ == "__main__": try: main = PiShowerMain(1, 40) main.start() while main.is_alive(): time.sleep(0.2) except KeyboardInterrupt: logger.debug('Key pressed - finishing now...') except Exception as error: logger.error('Error in main control! {0}'.format(error)) finally: main.stop()
def __init__(self, seconds=420): """ Init the timer """ self.timeoutSeconds = seconds self._finished = False logger.debug('timer init for {} seconds'.format(seconds))
def _handle_timeout(self): """ Worker method to set the timeoutEvent and execute commands on timeout """ self.timeoutEvent.set() self._finished = True logger.debug('timeout reached!')
if len(line) < self.__minCodeLength: logger.warning( 'ignoring to small code: {0}'.format(line)) break else: logger.debug('code read: \'{0}\''.format(line)) return line else: line += self.__scancodes[data.scancode] except: logger.error('Parsing input stream failed!') self.close() return None # command line execution if __name__ == '__main__': rfidReader = UsbRfidReader('/dev/input/event2', 10) while True: try: code = rfidReader.readline() if code is not None: logger.debug('found a code: \'{0}\''.format(code)) time.sleep(0.5) except KeyboardInterrupt: logger.debug('Key pressed - finishing now...') break except: logger.error('Unknown error received. Reading aborted!') break
return float(temperature) except: pass # failed reading sensor return float(temperature) if temperature is not None else -0.0 def current_fahrenheit(self): # type: () -> float """ Return current sensor value in Fahrenheit degrees """ temperature = self.current_celsius() return float(temperature) * 9.0 / 5.0 + 32.0 # command line execution if __name__ == '__main__': sensor = DS18B20() logger.debug('sensors found: {0}'.format(sensor.available_sensors())) while True: try: logger.debug('Temperature : {0} {1}\r' \ .format(sensor.current_celsius_str(), sensor.current_fahrenheit_str())) sys.stdout.flush() time.sleep(2.0) except KeyboardInterrupt: logger.debug('Key pressed - finishing now...') break except: logger.error('Unknown error received. Reading aborted!') break
state = GPIO.HIGH if value > 0 else GPIO.LOW GPIO.output(port, state) logger.debug('set GPIO {0} to {1}'.format(port, self._states[state])) time.sleep(0.01) # command line execution if __name__ == '__main__': relay1 = 17 # GPIO 17 / Pin 11 auf Ausgang setzen relay2 = 27 # GPIO 27 / Pin 13 auf Ausgang setzen try: control = RelayControl([relay1, relay2]) time.sleep(2.0) logger.debug('Testing invalid port...') control.toggle_output(4, True) logger.debug('Switching relais to ON...') control.toggle_output(relay1, True) control.toggle_output(relay2, True) time.sleep(2.0) logger.debug('Toggling relais...') control.toggle_output(relay1) time.sleep(2.0) control.toggle_output(relay2) time.sleep(2.0) logger.debug('Switching relais2 to OFF...') control.toggle_output(relay2, False)
def run(self): """ Handle card reader events and logic for shower control """ if self._cardReader is None: logger.error('No card reader available! Aborting!') self.stop() return if self._relays is None: logger.error('No I/O control for relays available! Aborting!') self.stop() return try: logger.debug('running main control loop...') self.show_message_ready() shower_active = False start_time = None while self.__running: code = self._cardReader.readline( ) # codes must be read to be cleared from buffer if shower_active: # a shower process was started code = None minutes_left = 0 # TODO: add minutes left calc here if self._showerTimer is None: logger.warning( 'No timer found! Stopped shower process!') shower_active = False self.show_message_ready() else: if not self._showerTimer.is_finished(): self.show_message_processing(minutes_left) else: logger.debug('stopped shower process on timeout') shower_active = False self.show_message_stop() if self._relays: self._relays.toggle_output( self._gpio_cold_water, False) self._relays.toggle_output( self._gpio_warm_water, False) time.sleep(6.0) self.show_message_ready() elif code is not None: # wait for request to start new shower process logger.debug('found a code: \'{0}\''.format( code)) # TODO: add validator here self.show_message_processing(self.shower_time // 60) shower_active = True if self._relays: self._relays.toggle_output(self._gpio_cold_water, True) self._relays.toggle_output(self._gpio_warm_water, True) if self._showerTimer: self._showerTimer.start() time.sleep(0.2) logger.debug('stopping main control loop...') except Exception as error: logger.error('Error in main control loop! {0}'.format(error))